Merge branch 'master' of git://git.infradead.org/users/linville/wireless into for...
authorJohn W. Linville <linville@tuxdriver.com>
Thu, 15 Sep 2011 19:37:02 +0000 (15:37 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 15 Sep 2011 19:37:02 +0000 (15:37 -0400)
2369 files changed:
CREDITS
Documentation/00-INDEX
Documentation/ABI/testing/pstore
Documentation/ABI/testing/sysfs-platform-ideapad-laptop
Documentation/CodingStyle
Documentation/DocBook/.gitignore
Documentation/DocBook/Makefile
Documentation/DocBook/dvb/dvbproperty.xml [deleted file]
Documentation/DocBook/dvb/dvbstb.png [deleted file]
Documentation/DocBook/dvb/frontend.h.xml [deleted file]
Documentation/DocBook/media-entities.tmpl [deleted file]
Documentation/DocBook/media-indices.tmpl [deleted file]
Documentation/DocBook/media/Makefile [new file with mode: 0644]
Documentation/DocBook/media/bayer.png.b64 [new file with mode: 0644]
Documentation/DocBook/media/crop.gif.b64 [new file with mode: 0644]
Documentation/DocBook/media/dvb/.gitignore [moved from Documentation/DocBook/dvb/.gitignore with 100% similarity]
Documentation/DocBook/media/dvb/audio.xml [moved from Documentation/DocBook/dvb/audio.xml with 79% similarity]
Documentation/DocBook/media/dvb/ca.xml [moved from Documentation/DocBook/dvb/ca.xml with 67% similarity]
Documentation/DocBook/media/dvb/demux.xml [moved from Documentation/DocBook/dvb/demux.xml with 84% similarity]
Documentation/DocBook/media/dvb/dvbapi.xml [moved from Documentation/DocBook/dvb/dvbapi.xml with 85% similarity]
Documentation/DocBook/media/dvb/dvbproperty.xml [new file with mode: 0644]
Documentation/DocBook/media/dvb/dvbstb.pdf [moved from Documentation/DocBook/dvb/dvbstb.pdf with 100% similarity]
Documentation/DocBook/media/dvb/examples.xml [moved from Documentation/DocBook/dvb/examples.xml with 100% similarity]
Documentation/DocBook/media/dvb/frontend.xml [moved from Documentation/DocBook/dvb/frontend.xml with 75% similarity]
Documentation/DocBook/media/dvb/intro.xml [moved from Documentation/DocBook/dvb/intro.xml with 92% similarity]
Documentation/DocBook/media/dvb/kdapi.xml [moved from Documentation/DocBook/dvb/kdapi.xml with 100% similarity]
Documentation/DocBook/media/dvb/net.xml [moved from Documentation/DocBook/dvb/net.xml with 57% similarity]
Documentation/DocBook/media/dvb/video.xml [moved from Documentation/DocBook/dvb/video.xml with 81% similarity]
Documentation/DocBook/media/dvbstb.png.b64 [new file with mode: 0644]
Documentation/DocBook/media/fieldseq_bt.gif.b64 [new file with mode: 0644]
Documentation/DocBook/media/fieldseq_tb.gif.b64 [new file with mode: 0644]
Documentation/DocBook/media/nv12mt.gif.b64 [new file with mode: 0644]
Documentation/DocBook/media/nv12mt_example.gif.b64 [new file with mode: 0644]
Documentation/DocBook/media/pipeline.png.b64 [new file with mode: 0644]
Documentation/DocBook/media/v4l/.gitignore [moved from Documentation/DocBook/v4l/.gitignore with 100% similarity]
Documentation/DocBook/media/v4l/biblio.xml [moved from Documentation/DocBook/v4l/biblio.xml with 100% similarity]
Documentation/DocBook/media/v4l/capture.c.xml [moved from Documentation/DocBook/v4l/capture.c.xml with 100% similarity]
Documentation/DocBook/media/v4l/common.xml [moved from Documentation/DocBook/v4l/common.xml with 99% similarity]
Documentation/DocBook/media/v4l/compat.xml [moved from Documentation/DocBook/v4l/compat.xml with 99% similarity]
Documentation/DocBook/media/v4l/controls.xml [moved from Documentation/DocBook/v4l/controls.xml with 62% similarity]
Documentation/DocBook/media/v4l/crop.pdf [moved from Documentation/DocBook/v4l/crop.pdf with 100% similarity]
Documentation/DocBook/media/v4l/dev-capture.xml [moved from Documentation/DocBook/v4l/dev-capture.xml with 100% similarity]
Documentation/DocBook/media/v4l/dev-codec.xml [moved from Documentation/DocBook/v4l/dev-codec.xml with 100% similarity]
Documentation/DocBook/media/v4l/dev-effect.xml [moved from Documentation/DocBook/v4l/dev-effect.xml with 100% similarity]
Documentation/DocBook/media/v4l/dev-event.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/dev-osd.xml [moved from Documentation/DocBook/v4l/dev-osd.xml with 100% similarity]
Documentation/DocBook/media/v4l/dev-output.xml [moved from Documentation/DocBook/v4l/dev-output.xml with 100% similarity]
Documentation/DocBook/media/v4l/dev-overlay.xml [moved from Documentation/DocBook/v4l/dev-overlay.xml with 100% similarity]
Documentation/DocBook/media/v4l/dev-radio.xml [moved from Documentation/DocBook/v4l/dev-radio.xml with 100% similarity]
Documentation/DocBook/media/v4l/dev-raw-vbi.xml [moved from Documentation/DocBook/v4l/dev-raw-vbi.xml with 100% similarity]
Documentation/DocBook/media/v4l/dev-rds.xml [moved from Documentation/DocBook/v4l/dev-rds.xml with 100% similarity]
Documentation/DocBook/media/v4l/dev-sliced-vbi.xml [moved from Documentation/DocBook/v4l/dev-sliced-vbi.xml with 100% similarity]
Documentation/DocBook/media/v4l/dev-subdev.xml [moved from Documentation/DocBook/v4l/dev-subdev.xml with 100% similarity]
Documentation/DocBook/media/v4l/dev-teletext.xml [moved from Documentation/DocBook/v4l/dev-teletext.xml with 100% similarity]
Documentation/DocBook/media/v4l/driver.xml [moved from Documentation/DocBook/v4l/driver.xml with 100% similarity]
Documentation/DocBook/media/v4l/fdl-appendix.xml [moved from Documentation/DocBook/v4l/fdl-appendix.xml with 100% similarity]
Documentation/DocBook/media/v4l/fieldseq_bt.pdf [moved from Documentation/DocBook/v4l/fieldseq_bt.pdf with 100% similarity]
Documentation/DocBook/media/v4l/fieldseq_tb.pdf [moved from Documentation/DocBook/v4l/fieldseq_tb.pdf with 100% similarity]
Documentation/DocBook/media/v4l/func-close.xml [moved from Documentation/DocBook/v4l/func-close.xml with 100% similarity]
Documentation/DocBook/media/v4l/func-ioctl.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/func-mmap.xml [moved from Documentation/DocBook/v4l/func-mmap.xml with 100% similarity]
Documentation/DocBook/media/v4l/func-munmap.xml [moved from Documentation/DocBook/v4l/func-munmap.xml with 100% similarity]
Documentation/DocBook/media/v4l/func-open.xml [moved from Documentation/DocBook/v4l/func-open.xml with 100% similarity]
Documentation/DocBook/media/v4l/func-poll.xml [moved from Documentation/DocBook/v4l/func-poll.xml with 100% similarity]
Documentation/DocBook/media/v4l/func-read.xml [moved from Documentation/DocBook/v4l/func-read.xml with 100% similarity]
Documentation/DocBook/media/v4l/func-select.xml [moved from Documentation/DocBook/v4l/func-select.xml with 100% similarity]
Documentation/DocBook/media/v4l/func-write.xml [moved from Documentation/DocBook/v4l/func-write.xml with 100% similarity]
Documentation/DocBook/media/v4l/gen-errors.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/io.xml [moved from Documentation/DocBook/v4l/io.xml with 100% similarity]
Documentation/DocBook/media/v4l/keytable.c.xml [moved from Documentation/DocBook/v4l/keytable.c.xml with 100% similarity]
Documentation/DocBook/media/v4l/libv4l.xml [moved from Documentation/DocBook/v4l/libv4l.xml with 100% similarity]
Documentation/DocBook/media/v4l/lirc_device_interface.xml [moved from Documentation/DocBook/v4l/lirc_device_interface.xml with 99% similarity]
Documentation/DocBook/media/v4l/media-controller.xml [moved from Documentation/DocBook/v4l/media-controller.xml with 100% similarity]
Documentation/DocBook/media/v4l/media-func-close.xml [moved from Documentation/DocBook/v4l/media-func-close.xml with 100% similarity]
Documentation/DocBook/media/v4l/media-func-ioctl.xml [moved from Documentation/DocBook/v4l/media-func-ioctl.xml with 59% similarity]
Documentation/DocBook/media/v4l/media-func-open.xml [moved from Documentation/DocBook/v4l/media-func-open.xml with 100% similarity]
Documentation/DocBook/media/v4l/media-ioc-device-info.xml [moved from Documentation/DocBook/v4l/media-ioc-device-info.xml with 97% similarity]
Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml [moved from Documentation/DocBook/v4l/media-ioc-enum-entities.xml with 100% similarity]
Documentation/DocBook/media/v4l/media-ioc-enum-links.xml [moved from Documentation/DocBook/v4l/media-ioc-enum-links.xml with 98% similarity]
Documentation/DocBook/media/v4l/media-ioc-setup-link.xml [moved from Documentation/DocBook/v4l/media-ioc-setup-link.xml with 87% similarity]
Documentation/DocBook/media/v4l/pipeline.pdf [moved from Documentation/DocBook/v4l/pipeline.pdf with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-grey.xml [moved from Documentation/DocBook/v4l/pixfmt-grey.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-m420.xml [moved from Documentation/DocBook/v4l/pixfmt-m420.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-nv12.xml [moved from Documentation/DocBook/v4l/pixfmt-nv12.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-nv12m.xml [moved from Documentation/DocBook/v4l/pixfmt-nv12m.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-nv12mt.xml [moved from Documentation/DocBook/v4l/pixfmt-nv12mt.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-nv16.xml [moved from Documentation/DocBook/v4l/pixfmt-nv16.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml [moved from Documentation/DocBook/v4l/pixfmt-packed-rgb.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-packed-yuv.xml [moved from Documentation/DocBook/v4l/pixfmt-packed-yuv.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-sbggr16.xml [moved from Documentation/DocBook/v4l/pixfmt-sbggr16.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-sbggr8.xml [moved from Documentation/DocBook/v4l/pixfmt-sbggr8.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-sgbrg8.xml [moved from Documentation/DocBook/v4l/pixfmt-sgbrg8.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-sgrbg8.xml [moved from Documentation/DocBook/v4l/pixfmt-sgrbg8.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-srggb10.xml [moved from Documentation/DocBook/v4l/pixfmt-srggb10.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-srggb12.xml [moved from Documentation/DocBook/v4l/pixfmt-srggb12.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-srggb8.xml [moved from Documentation/DocBook/v4l/pixfmt-srggb8.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-uyvy.xml [moved from Documentation/DocBook/v4l/pixfmt-uyvy.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-vyuy.xml [moved from Documentation/DocBook/v4l/pixfmt-vyuy.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-y10.xml [moved from Documentation/DocBook/v4l/pixfmt-y10.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-y10b.xml [moved from Documentation/DocBook/v4l/pixfmt-y10b.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-y12.xml [moved from Documentation/DocBook/v4l/pixfmt-y12.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-y16.xml [moved from Documentation/DocBook/v4l/pixfmt-y16.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-y41p.xml [moved from Documentation/DocBook/v4l/pixfmt-y41p.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-yuv410.xml [moved from Documentation/DocBook/v4l/pixfmt-yuv410.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-yuv411p.xml [moved from Documentation/DocBook/v4l/pixfmt-yuv411p.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-yuv420.xml [moved from Documentation/DocBook/v4l/pixfmt-yuv420.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-yuv420m.xml [moved from Documentation/DocBook/v4l/pixfmt-yuv420m.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-yuv422p.xml [moved from Documentation/DocBook/v4l/pixfmt-yuv422p.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-yuyv.xml [moved from Documentation/DocBook/v4l/pixfmt-yuyv.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt-yvyu.xml [moved from Documentation/DocBook/v4l/pixfmt-yvyu.xml with 100% similarity]
Documentation/DocBook/media/v4l/pixfmt.xml [moved from Documentation/DocBook/v4l/pixfmt.xml with 94% similarity]
Documentation/DocBook/media/v4l/planar-apis.xml [moved from Documentation/DocBook/v4l/planar-apis.xml with 100% similarity]
Documentation/DocBook/media/v4l/remote_controllers.xml [moved from Documentation/DocBook/v4l/remote_controllers.xml with 100% similarity]
Documentation/DocBook/media/v4l/subdev-formats.xml [moved from Documentation/DocBook/v4l/subdev-formats.xml with 99% similarity]
Documentation/DocBook/media/v4l/v4l2.xml [moved from Documentation/DocBook/v4l/v4l2.xml with 97% similarity]
Documentation/DocBook/media/v4l/v4l2grab.c.xml [moved from Documentation/DocBook/v4l/v4l2grab.c.xml with 100% similarity]
Documentation/DocBook/media/v4l/vbi_525.pdf [moved from Documentation/DocBook/v4l/vbi_525.pdf with 100% similarity]
Documentation/DocBook/media/v4l/vbi_625.pdf [moved from Documentation/DocBook/v4l/vbi_625.pdf with 100% similarity]
Documentation/DocBook/media/v4l/vbi_hsync.pdf [moved from Documentation/DocBook/v4l/vbi_hsync.pdf with 100% similarity]
Documentation/DocBook/media/v4l/vidioc-cropcap.xml [moved from Documentation/DocBook/v4l/vidioc-cropcap.xml with 95% similarity]
Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-ident.xml [moved from Documentation/DocBook/v4l/vidioc-dbg-g-chip-ident.xml with 97% similarity]
Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml [moved from Documentation/DocBook/v4l/vidioc-dbg-g-register.xml with 94% similarity]
Documentation/DocBook/media/v4l/vidioc-dqevent.xml [moved from Documentation/DocBook/v4l/vidioc-dqevent.xml with 84% similarity]
Documentation/DocBook/media/v4l/vidioc-encoder-cmd.xml [moved from Documentation/DocBook/v4l/vidioc-encoder-cmd.xml with 96% similarity]
Documentation/DocBook/media/v4l/vidioc-enum-dv-presets.xml [moved from Documentation/DocBook/v4l/vidioc-enum-dv-presets.xml with 100% similarity]
Documentation/DocBook/media/v4l/vidioc-enum-fmt.xml [moved from Documentation/DocBook/v4l/vidioc-enum-fmt.xml with 100% similarity]
Documentation/DocBook/media/v4l/vidioc-enum-frameintervals.xml [moved from Documentation/DocBook/v4l/vidioc-enum-frameintervals.xml with 97% similarity]
Documentation/DocBook/media/v4l/vidioc-enum-framesizes.xml [moved from Documentation/DocBook/v4l/vidioc-enum-framesizes.xml with 97% similarity]
Documentation/DocBook/media/v4l/vidioc-enumaudio.xml [moved from Documentation/DocBook/v4l/vidioc-enumaudio.xml with 89% similarity]
Documentation/DocBook/media/v4l/vidioc-enumaudioout.xml [moved from Documentation/DocBook/v4l/vidioc-enumaudioout.xml with 90% similarity]
Documentation/DocBook/media/v4l/vidioc-enuminput.xml [moved from Documentation/DocBook/v4l/vidioc-enuminput.xml with 100% similarity]
Documentation/DocBook/media/v4l/vidioc-enumoutput.xml [moved from Documentation/DocBook/v4l/vidioc-enumoutput.xml with 100% similarity]
Documentation/DocBook/media/v4l/vidioc-enumstd.xml [moved from Documentation/DocBook/v4l/vidioc-enumstd.xml with 100% similarity]
Documentation/DocBook/media/v4l/vidioc-g-audio.xml [moved from Documentation/DocBook/v4l/vidioc-g-audio.xml with 93% similarity]
Documentation/DocBook/media/v4l/vidioc-g-audioout.xml [moved from Documentation/DocBook/v4l/vidioc-g-audioout.xml with 92% similarity]
Documentation/DocBook/media/v4l/vidioc-g-crop.xml [moved from Documentation/DocBook/v4l/vidioc-g-crop.xml with 93% similarity]
Documentation/DocBook/media/v4l/vidioc-g-ctrl.xml [moved from Documentation/DocBook/v4l/vidioc-g-ctrl.xml with 94% similarity]
Documentation/DocBook/media/v4l/vidioc-g-dv-preset.xml [moved from Documentation/DocBook/v4l/vidioc-g-dv-preset.xml with 96% similarity]
Documentation/DocBook/media/v4l/vidioc-g-dv-timings.xml [moved from Documentation/DocBook/v4l/vidioc-g-dv-timings.xml with 98% similarity]
Documentation/DocBook/media/v4l/vidioc-g-enc-index.xml [moved from Documentation/DocBook/v4l/vidioc-g-enc-index.xml with 95% similarity]
Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml [moved from Documentation/DocBook/v4l/vidioc-g-ext-ctrls.xml with 95% similarity]
Documentation/DocBook/media/v4l/vidioc-g-fbuf.xml [moved from Documentation/DocBook/v4l/vidioc-g-fbuf.xml with 97% similarity]
Documentation/DocBook/media/v4l/vidioc-g-fmt.xml [moved from Documentation/DocBook/v4l/vidioc-g-fmt.xml with 93% similarity]
Documentation/DocBook/media/v4l/vidioc-g-frequency.xml [moved from Documentation/DocBook/v4l/vidioc-g-frequency.xml with 100% similarity]
Documentation/DocBook/media/v4l/vidioc-g-input.xml [moved from Documentation/DocBook/v4l/vidioc-g-input.xml with 85% similarity]
Documentation/DocBook/media/v4l/vidioc-g-jpegcomp.xml [moved from Documentation/DocBook/v4l/vidioc-g-jpegcomp.xml with 93% similarity]
Documentation/DocBook/media/v4l/vidioc-g-modulator.xml [moved from Documentation/DocBook/v4l/vidioc-g-modulator.xml with 100% similarity]
Documentation/DocBook/media/v4l/vidioc-g-output.xml [moved from Documentation/DocBook/v4l/vidioc-g-output.xml with 87% similarity]
Documentation/DocBook/media/v4l/vidioc-g-parm.xml [moved from Documentation/DocBook/v4l/vidioc-g-parm.xml with 97% similarity]
Documentation/DocBook/media/v4l/vidioc-g-priority.xml [moved from Documentation/DocBook/v4l/vidioc-g-priority.xml with 97% similarity]
Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml [moved from Documentation/DocBook/v4l/vidioc-g-sliced-vbi-cap.xml with 97% similarity]
Documentation/DocBook/media/v4l/vidioc-g-std.xml [moved from Documentation/DocBook/v4l/vidioc-g-std.xml with 90% similarity]
Documentation/DocBook/media/v4l/vidioc-g-tuner.xml [moved from Documentation/DocBook/v4l/vidioc-g-tuner.xml with 100% similarity]
Documentation/DocBook/media/v4l/vidioc-log-status.xml [moved from Documentation/DocBook/v4l/vidioc-log-status.xml with 80% similarity]
Documentation/DocBook/media/v4l/vidioc-overlay.xml [moved from Documentation/DocBook/v4l/vidioc-overlay.xml with 90% similarity]
Documentation/DocBook/media/v4l/vidioc-qbuf.xml [moved from Documentation/DocBook/v4l/vidioc-qbuf.xml with 95% similarity]
Documentation/DocBook/media/v4l/vidioc-query-dv-preset.xml [moved from Documentation/DocBook/v4l/vidioc-query-dv-preset.xml with 79% similarity]
Documentation/DocBook/media/v4l/vidioc-querybuf.xml [moved from Documentation/DocBook/v4l/vidioc-querybuf.xml with 100% similarity]
Documentation/DocBook/media/v4l/vidioc-querycap.xml [moved from Documentation/DocBook/v4l/vidioc-querycap.xml with 93% similarity]
Documentation/DocBook/media/v4l/vidioc-queryctrl.xml [moved from Documentation/DocBook/v4l/vidioc-queryctrl.xml with 97% similarity]
Documentation/DocBook/media/v4l/vidioc-querystd.xml [moved from Documentation/DocBook/v4l/vidioc-querystd.xml with 78% similarity]
Documentation/DocBook/media/v4l/vidioc-reqbufs.xml [moved from Documentation/DocBook/v4l/vidioc-reqbufs.xml with 92% similarity]
Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml [moved from Documentation/DocBook/v4l/vidioc-s-hw-freq-seek.xml with 100% similarity]
Documentation/DocBook/media/v4l/vidioc-streamon.xml [moved from Documentation/DocBook/v4l/vidioc-streamon.xml with 92% similarity]
Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-interval.xml [moved from Documentation/DocBook/v4l/vidioc-subdev-enum-frame-interval.xml with 100% similarity]
Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-size.xml [moved from Documentation/DocBook/v4l/vidioc-subdev-enum-frame-size.xml with 100% similarity]
Documentation/DocBook/media/v4l/vidioc-subdev-enum-mbus-code.xml [moved from Documentation/DocBook/v4l/vidioc-subdev-enum-mbus-code.xml with 100% similarity]
Documentation/DocBook/media/v4l/vidioc-subdev-g-crop.xml [moved from Documentation/DocBook/v4l/vidioc-subdev-g-crop.xml with 100% similarity]
Documentation/DocBook/media/v4l/vidioc-subdev-g-fmt.xml [moved from Documentation/DocBook/v4l/vidioc-subdev-g-fmt.xml with 99% similarity]
Documentation/DocBook/media/v4l/vidioc-subdev-g-frame-interval.xml [moved from Documentation/DocBook/v4l/vidioc-subdev-g-frame-interval.xml with 100% similarity]
Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml [new file with mode: 0644]
Documentation/DocBook/media/vbi_525.gif.b64 [new file with mode: 0644]
Documentation/DocBook/media/vbi_625.gif.b64 [new file with mode: 0644]
Documentation/DocBook/media/vbi_hsync.gif.b64 [new file with mode: 0644]
Documentation/DocBook/media_api.tmpl [moved from Documentation/DocBook/media.tmpl with 89% similarity]
Documentation/DocBook/v4l/bayer.pdf [deleted file]
Documentation/DocBook/v4l/bayer.png [deleted file]
Documentation/DocBook/v4l/crop.gif [deleted file]
Documentation/DocBook/v4l/dev-event.xml [deleted file]
Documentation/DocBook/v4l/fieldseq_bt.gif [deleted file]
Documentation/DocBook/v4l/fieldseq_tb.gif [deleted file]
Documentation/DocBook/v4l/func-ioctl.xml [deleted file]
Documentation/DocBook/v4l/nv12mt.gif [deleted file]
Documentation/DocBook/v4l/nv12mt_example.gif [deleted file]
Documentation/DocBook/v4l/pipeline.png [deleted file]
Documentation/DocBook/v4l/vbi_525.gif [deleted file]
Documentation/DocBook/v4l/vbi_625.gif [deleted file]
Documentation/DocBook/v4l/vbi_hsync.gif [deleted file]
Documentation/DocBook/v4l/videodev2.h.xml [deleted file]
Documentation/DocBook/v4l/vidioc-subscribe-event.xml [deleted file]
Documentation/PCI/MSI-HOWTO.txt
Documentation/SubmittingDrivers
Documentation/SubmittingPatches
Documentation/acpi/apei/einj.txt
Documentation/block/cfq-iosched.txt
Documentation/device-mapper/dm-crypt.txt
Documentation/device-mapper/dm-flakey.txt
Documentation/device-mapper/dm-raid.txt
Documentation/devicetree/bindings/arm/arm-boards [new file with mode: 0644]
Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/gpio_keys.txt
Documentation/devicetree/bindings/i2c/arm-versatile.txt [new file with mode: 0644]
Documentation/devicetree/bindings/input/fsl-mma8450.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/arm-versatile.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/fsl-fec.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/smsc-lan91c111.txt [new file with mode: 0644]
Documentation/devicetree/bindings/tty/serial/fsl-imx-uart.txt [new file with mode: 0644]
Documentation/devicetree/bindings/watchdog/fsl-imx-wdt.txt [new file with mode: 0644]
Documentation/devicetree/bindings/watchdog/samsung-wdt.txt [new file with mode: 0644]
Documentation/dmaengine.txt
Documentation/dvb/get_dvb_firmware [changed mode: 0644->0755]
Documentation/email-clients.txt
Documentation/fault-injection/fault-injection.txt
Documentation/feature-removal-schedule.txt
Documentation/filesystems/befs.txt
Documentation/frv/booting.txt
Documentation/hwmon/adm1275
Documentation/hwmon/coretemp
Documentation/hwmon/lm25066 [new file with mode: 0644]
Documentation/hwmon/lm90
Documentation/hwmon/lm95245 [new file with mode: 0644]
Documentation/hwmon/max16064
Documentation/hwmon/max1668 [new file with mode: 0644]
Documentation/hwmon/max34440
Documentation/hwmon/max8688
Documentation/hwmon/ntc_thermistor [new file with mode: 0644]
Documentation/hwmon/pmbus
Documentation/hwmon/sysfs-interface
Documentation/ioctl/ioctl-number.txt
Documentation/kernel-docs.txt
Documentation/kernel-parameters.txt
Documentation/m68k/kernel-options.txt
Documentation/media-framework.txt
Documentation/networking/00-INDEX
Documentation/networking/bonding.txt
Documentation/networking/dmfe.txt
Documentation/networking/ip-sysctl.txt
Documentation/networking/scaling.txt [new file with mode: 0644]
Documentation/power/runtime_pm.txt
Documentation/ramoops.txt [new file with mode: 0644]
Documentation/scsi/ChangeLog.megaraid_sas
Documentation/video4linux/API.html
Documentation/video4linux/CARDLIST.cx23885
Documentation/video4linux/CARDLIST.cx88
Documentation/video4linux/CARDLIST.em28xx
Documentation/video4linux/CARDLIST.saa7134
Documentation/video4linux/CARDLIST.tuner
Documentation/video4linux/CARDLIST.usbvision
Documentation/video4linux/README.davinci-vpbe [new file with mode: 0644]
Documentation/video4linux/v4l2-controls.txt
Documentation/video4linux/v4l2-framework.txt
Documentation/virtual/00-INDEX
Documentation/virtual/lguest/lguest.c
Documentation/virtual/virtio-spec.txt [new file with mode: 0644]
Documentation/watchdog/00-INDEX
Documentation/watchdog/watchdog-kernel-api.txt [new file with mode: 0644]
MAINTAINERS
Makefile
arch/Kconfig
arch/alpha/Kconfig
arch/alpha/kernel/sys_alcor.c
arch/alpha/kernel/sys_cabriolet.c
arch/alpha/kernel/sys_dp264.c
arch/alpha/kernel/sys_eb64p.c
arch/alpha/kernel/sys_eiger.c
arch/alpha/kernel/sys_marvel.c
arch/alpha/kernel/sys_miata.c
arch/alpha/kernel/sys_mikasa.c
arch/alpha/kernel/sys_nautilus.c
arch/alpha/kernel/sys_noritake.c
arch/alpha/kernel/sys_rawhide.c
arch/alpha/kernel/sys_ruffian.c
arch/alpha/kernel/sys_rx164.c
arch/alpha/kernel/sys_sable.c
arch/alpha/kernel/sys_sio.c
arch/alpha/kernel/sys_sx164.c
arch/alpha/kernel/sys_takara.c
arch/alpha/kernel/sys_titan.c
arch/alpha/kernel/sys_wildfire.c
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/boot/Makefile
arch/arm/boot/dts/skeleton.dtsi [new file with mode: 0644]
arch/arm/boot/dts/tegra-harmony.dts [new file with mode: 0644]
arch/arm/boot/dts/tegra-seaboard.dts [new file with mode: 0644]
arch/arm/boot/dts/tegra20.dtsi [new file with mode: 0644]
arch/arm/boot/dts/versatile-ab.dts [new file with mode: 0644]
arch/arm/boot/dts/versatile-pb.dts [new file with mode: 0644]
arch/arm/common/it8152.c
arch/arm/include/asm/hardware/it8152.h
arch/arm/include/asm/mach/arch.h
arch/arm/include/asm/mach/pci.h
arch/arm/include/asm/prom.h
arch/arm/kernel/armksyms.c
arch/arm/kernel/bios32.c
arch/arm/kernel/devtree.c
arch/arm/kernel/iwmmxt.S
arch/arm/kernel/module.c
arch/arm/kernel/process.c
arch/arm/lib/Makefile
arch/arm/lib/sha1.S [deleted file]
arch/arm/mach-at91/Makefile
arch/arm/mach-at91/at91cap9.c
arch/arm/mach-at91/at91rm9200.c
arch/arm/mach-at91/at91sam9260.c
arch/arm/mach-at91/at91sam9261.c
arch/arm/mach-at91/at91sam9263.c
arch/arm/mach-at91/at91sam9g45.c
arch/arm/mach-at91/at91sam9rl.c
arch/arm/mach-at91/board-1arm.c
arch/arm/mach-at91/board-afeb-9260v1.c
arch/arm/mach-at91/board-cam60.c
arch/arm/mach-at91/board-cap9adk.c
arch/arm/mach-at91/board-carmeva.c
arch/arm/mach-at91/board-cpu9krea.c
arch/arm/mach-at91/board-cpuat91.c
arch/arm/mach-at91/board-csb337.c
arch/arm/mach-at91/board-csb637.c
arch/arm/mach-at91/board-eb9200.c
arch/arm/mach-at91/board-ecbat91.c
arch/arm/mach-at91/board-eco920.c
arch/arm/mach-at91/board-flexibity.c
arch/arm/mach-at91/board-foxg20.c
arch/arm/mach-at91/board-gsia18s.c
arch/arm/mach-at91/board-kafa.c
arch/arm/mach-at91/board-kb9202.c
arch/arm/mach-at91/board-neocore926.c
arch/arm/mach-at91/board-pcontrol-g20.c
arch/arm/mach-at91/board-picotux200.c
arch/arm/mach-at91/board-qil-a9260.c
arch/arm/mach-at91/board-rm9200dk.c
arch/arm/mach-at91/board-rm9200ek.c
arch/arm/mach-at91/board-sam9-l9260.c
arch/arm/mach-at91/board-sam9260ek.c
arch/arm/mach-at91/board-sam9261ek.c
arch/arm/mach-at91/board-sam9263ek.c
arch/arm/mach-at91/board-sam9g20ek.c
arch/arm/mach-at91/board-sam9m10g45ek.c
arch/arm/mach-at91/board-sam9rlek.c
arch/arm/mach-at91/board-snapper9260.c
arch/arm/mach-at91/board-stamp9g20.c
arch/arm/mach-at91/board-usb-a9260.c
arch/arm/mach-at91/board-usb-a9263.c
arch/arm/mach-at91/board-yl-9200.c
arch/arm/mach-at91/generic.h
arch/arm/mach-at91/include/mach/at91_dbgu.h
arch/arm/mach-at91/include/mach/at91cap9.h
arch/arm/mach-at91/include/mach/at91rm9200.h
arch/arm/mach-at91/include/mach/at91sam9260.h
arch/arm/mach-at91/include/mach/at91sam9261.h
arch/arm/mach-at91/include/mach/at91sam9263.h
arch/arm/mach-at91/include/mach/at91sam9g45.h
arch/arm/mach-at91/include/mach/at91sam9rl.h
arch/arm/mach-at91/include/mach/cpu.h
arch/arm/mach-at91/include/mach/debug-macro.S
arch/arm/mach-at91/include/mach/hardware.h
arch/arm/mach-at91/include/mach/io.h
arch/arm/mach-at91/setup.c [new file with mode: 0644]
arch/arm/mach-at91/soc.h [new file with mode: 0644]
arch/arm/mach-cns3xxx/pcie.c
arch/arm/mach-dove/pcie.c
arch/arm/mach-footbridge/cats-pci.c
arch/arm/mach-footbridge/ebsa285-pci.c
arch/arm/mach-footbridge/netwinder-pci.c
arch/arm/mach-footbridge/personal-pci.c
arch/arm/mach-imx/clock-imx1.c
arch/arm/mach-imx/clock-imx21.c
arch/arm/mach-imx/clock-imx25.c
arch/arm/mach-imx/clock-imx27.c
arch/arm/mach-imx/clock-imx31.c
arch/arm/mach-imx/clock-imx35.c
arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c
arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c
arch/arm/mach-imx/mach-imx27_visstrim_m10.c
arch/arm/mach-imx/mach-mx25_3ds.c
arch/arm/mach-imx/mach-mx31ads.c
arch/arm/mach-imx/mach-mx31lilly.c
arch/arm/mach-imx/mach-pcm043.c
arch/arm/mach-imx/mm-imx25.c
arch/arm/mach-imx/mm-imx31.c
arch/arm/mach-imx/mm-imx35.c
arch/arm/mach-integrator/pci.c
arch/arm/mach-iop13xx/iq81340mc.c
arch/arm/mach-iop13xx/pci.c
arch/arm/mach-iop32x/em7210.c
arch/arm/mach-iop32x/glantank.c
arch/arm/mach-iop32x/iq31244.c
arch/arm/mach-iop32x/iq80321.c
arch/arm/mach-iop32x/n2100.c
arch/arm/mach-iop33x/iq80331.c
arch/arm/mach-iop33x/iq80332.c
arch/arm/mach-ixp2000/enp2611.c
arch/arm/mach-ixp2000/ixdp2400.c
arch/arm/mach-ixp2000/ixdp2800.c
arch/arm/mach-ixp2000/ixdp2x01.c
arch/arm/mach-ixp23xx/ixdp2351.c
arch/arm/mach-ixp23xx/roadrunner.c
arch/arm/mach-ixp4xx/avila-pci.c
arch/arm/mach-ixp4xx/coyote-pci.c
arch/arm/mach-ixp4xx/dsmg600-pci.c
arch/arm/mach-ixp4xx/fsg-pci.c
arch/arm/mach-ixp4xx/gateway7001-pci.c
arch/arm/mach-ixp4xx/goramo_mlr.c
arch/arm/mach-ixp4xx/gtwx5715-pci.c
arch/arm/mach-ixp4xx/ixdp425-pci.c
arch/arm/mach-ixp4xx/ixdpg425-pci.c
arch/arm/mach-ixp4xx/nas100d-pci.c
arch/arm/mach-ixp4xx/nslu2-pci.c
arch/arm/mach-ixp4xx/vulcan-pci.c
arch/arm/mach-ixp4xx/wg302v2-pci.c
arch/arm/mach-kirkwood/pcie.c
arch/arm/mach-ks8695/board-dsm320.c
arch/arm/mach-ks8695/board-micrel.c
arch/arm/mach-ks8695/include/mach/devices.h
arch/arm/mach-mmp/gplugd.c
arch/arm/mach-mmp/include/mach/mfp-gplugd.h [deleted file]
arch/arm/mach-mmp/include/mach/mfp-pxa168.h
arch/arm/mach-mmp/time.c
arch/arm/mach-msm/Kconfig
arch/arm/mach-msm/Makefile
arch/arm/mach-msm/gpio.c [deleted file]
arch/arm/mach-msm/gpio_hw.h [deleted file]
arch/arm/mach-msm/gpiomux.h
arch/arm/mach-msm/include/mach/msm_gpiomux.h [new file with mode: 0644]
arch/arm/mach-msm/include/mach/msm_iomap-7x00.h
arch/arm/mach-msm/include/mach/msm_iomap-7x30.h
arch/arm/mach-msm/include/mach/msm_iomap-8x50.h
arch/arm/mach-msm/include/mach/msm_iomap.h
arch/arm/mach-msm/io.c
arch/arm/mach-mv78xx0/pcie.c
arch/arm/mach-mx5/board-cpuimx51.c
arch/arm/mach-mx5/board-mx51_babbage.c
arch/arm/mach-mx5/board-mx51_efikamx.c
arch/arm/mach-mx5/board-mx51_efikasb.c
arch/arm/mach-mx5/board-mx53_loco.c
arch/arm/mach-mx5/clock-mx51-mx53.c
arch/arm/mach-mx5/mm.c
arch/arm/mach-mx5/mx51_efika.c
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/board-am3517crane.c
arch/arm/mach-omap2/board-omap3beagle.c
arch/arm/mach-omap2/board-rx51-peripherals.c
arch/arm/mach-omap2/cminst44xx.h
arch/arm/mach-omap2/display.c
arch/arm/mach-omap2/mux.c
arch/arm/mach-omap2/smartreflex.c
arch/arm/mach-omap2/timer.c
arch/arm/mach-omap2/twl-common.c
arch/arm/mach-orion5x/common.h
arch/arm/mach-orion5x/db88f5281-setup.c
arch/arm/mach-orion5x/dns323-setup.c
arch/arm/mach-orion5x/kurobox_pro-setup.c
arch/arm/mach-orion5x/mss2-setup.c
arch/arm/mach-orion5x/pci.c
arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
arch/arm/mach-orion5x/rd88f5182-setup.c
arch/arm/mach-orion5x/terastation_pro2-setup.c
arch/arm/mach-orion5x/ts209-setup.c
arch/arm/mach-orion5x/ts409-setup.c
arch/arm/mach-orion5x/wnr854t-setup.c
arch/arm/mach-orion5x/wrt350n-v2-setup.c
arch/arm/mach-pxa/cm-x2xx-pci.c
arch/arm/mach-s3c64xx/mach-crag6410.c
arch/arm/mach-sa1100/pci-nanoengine.c
arch/arm/mach-shark/pci.c
arch/arm/mach-shmobile/board-ap4evb.c
arch/arm/mach-shmobile/board-mackerel.c
arch/arm/mach-shmobile/clock-sh7367.c
arch/arm/mach-shmobile/clock-sh7372.c
arch/arm/mach-shmobile/clock-sh7377.c
arch/arm/mach-shmobile/clock-sh73a0.c
arch/arm/mach-tegra/Kconfig
arch/arm/mach-tegra/Makefile
arch/arm/mach-tegra/Makefile.boot
arch/arm/mach-tegra/board-dt.c [new file with mode: 0644]
arch/arm/mach-tegra/pcie.c
arch/arm/mach-versatile/Kconfig
arch/arm/mach-versatile/Makefile
arch/arm/mach-versatile/core.c
arch/arm/mach-versatile/core.h
arch/arm/mach-versatile/pci.c
arch/arm/mach-versatile/versatile_dt.c [new file with mode: 0644]
arch/arm/mach-zynq/Makefile
arch/arm/mach-zynq/board_dt.c [deleted file]
arch/arm/mm/alignment.c
arch/arm/mm/init.c
arch/arm/mm/proc-arm946.S
arch/arm/plat-mxc/devices/platform-fec.c
arch/arm/plat-mxc/devices/platform-imx-dma.c
arch/arm/plat-mxc/devices/platform-imx-uart.c
arch/arm/plat-mxc/devices/platform-sdhci-esdhc-imx.c
arch/arm/plat-mxc/include/mach/debug-macro.S
arch/arm/plat-mxc/include/mach/devices-common.h
arch/arm/plat-mxc/include/mach/dma.h
arch/arm/plat-mxc/include/mach/esdhc.h
arch/arm/plat-mxc/include/mach/iomux-mx53.h
arch/arm/plat-mxc/include/mach/sdma.h
arch/arm/plat-omap/Kconfig
arch/arm/plat-omap/include/plat/dma.h
arch/arm/plat-omap/include/plat/irqs.h
arch/arm/plat-omap/include/plat/serial.h
arch/arm/plat-omap/iovmm.c
arch/arm/tools/mach-types
arch/avr32/Kconfig
arch/cris/arch-v10/drivers/sync_serial.c
arch/cris/arch-v10/kernel/irq.c
arch/cris/include/asm/thread_info.h
arch/frv/Kconfig
arch/frv/mm/pgalloc.c
arch/ia64/Kconfig
arch/ia64/configs/generic_defconfig
arch/ia64/include/asm/gpio.h [new file with mode: 0644]
arch/ia64/kernel/efi.c
arch/m68k/Kconfig
arch/m68k/Kconfig.mmu
arch/m68k/amiga/chipram.c
arch/m68k/atari/stram.c
arch/m68k/include/asm/atari_stram.h
arch/m68k/include/asm/atarihw.h
arch/m68k/include/asm/page_mm.h
arch/m68k/kernel/setup_mm.c
arch/m68k/math-emu/fp_log.c
arch/m68k/math-emu/multi_arith.h
arch/m68k/mm/init_mm.c
arch/parisc/Kconfig
arch/parisc/include/asm/atomic.h
arch/parisc/include/asm/futex.h
arch/parisc/include/asm/unistd.h
arch/parisc/kernel/syscall_table.S
arch/powerpc/Kconfig
arch/powerpc/include/asm/jump_label.h
arch/powerpc/include/asm/kdump.h
arch/powerpc/include/asm/reg.h
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/iomap.c
arch/powerpc/kernel/machine_kexec.c
arch/powerpc/kernel/perf_callchain.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/platforms/Kconfig
arch/powerpc/platforms/pseries/dtl.c
arch/powerpc/platforms/pseries/hotplug-cpu.c
arch/powerpc/platforms/pseries/io_event_irq.c
arch/powerpc/platforms/pseries/kexec.c
arch/powerpc/platforms/pseries/lpar.c
arch/powerpc/platforms/pseries/plpar_wrappers.h
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/sysdev/ppc4xx_pci.c
arch/s390/Kconfig
arch/s390/include/asm/ipl.h
arch/s390/include/asm/lowcore.h
arch/s390/include/asm/processor.h
arch/s390/include/asm/system.h
arch/s390/kernel/asm-offsets.c
arch/s390/kernel/base.S
arch/s390/kernel/compat_signal.c
arch/s390/kernel/entry.S
arch/s390/kernel/entry64.S
arch/s390/kernel/ipl.c
arch/s390/kernel/reipl64.S
arch/s390/kernel/setup.c
arch/s390/kernel/signal.c
arch/s390/kernel/smp.c
arch/s390/mm/maccess.c
arch/s390/mm/pgtable.c
arch/sh/Kconfig
arch/sh/Makefile
arch/sh/boards/board-apsh4a3a.c
arch/sh/boards/board-apsh4ad0a.c
arch/sh/boards/board-sh7785lcr.c
arch/sh/boards/board-urquell.c
arch/sh/boards/mach-ap325rxa/setup.c
arch/sh/boards/mach-highlander/setup.c
arch/sh/boards/mach-sdk7786/setup.c
arch/sh/drivers/pci/fixups-cayman.c
arch/sh/drivers/pci/fixups-dreamcast.c
arch/sh/drivers/pci/fixups-landisk.c
arch/sh/drivers/pci/fixups-r7780rp.c
arch/sh/drivers/pci/fixups-rts7751r2d.c
arch/sh/drivers/pci/fixups-sdk7780.c
arch/sh/drivers/pci/fixups-se7751.c
arch/sh/drivers/pci/fixups-sh03.c
arch/sh/drivers/pci/fixups-snapgear.c
arch/sh/drivers/pci/fixups-titan.c
arch/sh/drivers/pci/pcie-sh7786.c
arch/sh/include/asm/pci.h
arch/sh/include/cpu-sh3/cpu/serial.h [new file with mode: 0644]
arch/sh/include/cpu-sh4a/cpu/serial.h [new file with mode: 0644]
arch/sh/kernel/cpu/clock-cpg.c
arch/sh/kernel/cpu/sh3/Makefile
arch/sh/kernel/cpu/sh3/serial-sh770x.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh3/serial-sh7710.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh3/serial-sh7720.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh3/setup-sh7705.c
arch/sh/kernel/cpu/sh3/setup-sh770x.c
arch/sh/kernel/cpu/sh3/setup-sh7720.c
arch/sh/kernel/cpu/sh4/clock-sh4-202.c
arch/sh/kernel/cpu/sh4/setup-sh7750.c
arch/sh/kernel/cpu/sh4/setup-sh7760.c
arch/sh/kernel/cpu/sh4a/Makefile
arch/sh/kernel/cpu/sh4a/clock-sh7343.c
arch/sh/kernel/cpu/sh4a/clock-sh7366.c
arch/sh/kernel/cpu/sh4a/clock-sh7722.c
arch/sh/kernel/cpu/sh4a/clock-sh7723.c
arch/sh/kernel/cpu/sh4a/clock-sh7724.c
arch/sh/kernel/cpu/sh4a/clock-sh7757.c
arch/sh/kernel/cpu/sh4a/clock-sh7763.c
arch/sh/kernel/cpu/sh4a/clock-sh7780.c
arch/sh/kernel/cpu/sh4a/clock-sh7785.c
arch/sh/kernel/cpu/sh4a/clock-sh7786.c
arch/sh/kernel/cpu/sh4a/clock-shx3.c
arch/sh/kernel/cpu/sh4a/serial-sh7722.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh4a/setup-sh7366.c
arch/sh/kernel/cpu/sh4a/setup-sh7722.c
arch/sh/kernel/cpu/sh4a/setup-sh7723.c
arch/sh/kernel/cpu/sh4a/setup-sh7724.c
arch/sh/kernel/cpu/sh4a/setup-sh7763.c
arch/sh/kernel/cpu/sh4a/setup-sh7780.c
arch/sh/kernel/cpu/sh4a/setup-sh7785.c
arch/sh/kernel/cpu/sh4a/setup-sh7786.c
arch/sh/kernel/idle.c
arch/sparc/Kconfig
arch/sparc/include/asm/Kbuild
arch/sparc/include/asm/bitops_64.h
arch/sparc/include/asm/div64.h [deleted file]
arch/sparc/include/asm/elf_64.h
arch/sparc/include/asm/hypervisor.h
arch/sparc/include/asm/irq_regs.h [deleted file]
arch/sparc/include/asm/leon_pci.h
arch/sparc/include/asm/local.h [deleted file]
arch/sparc/include/asm/local64.h [deleted file]
arch/sparc/include/asm/sigcontext.h
arch/sparc/include/asm/spinlock_32.h
arch/sparc/include/asm/spinlock_64.h
arch/sparc/include/asm/spitfire.h
arch/sparc/include/asm/tsb.h
arch/sparc/include/asm/xor_64.h
arch/sparc/kernel/Makefile
arch/sparc/kernel/cpu.c
arch/sparc/kernel/cpumap.c
arch/sparc/kernel/ds.c
arch/sparc/kernel/entry.h
arch/sparc/kernel/head_64.S
arch/sparc/kernel/hvapi.c
arch/sparc/kernel/hvcalls.S
arch/sparc/kernel/ioport.c
arch/sparc/kernel/kernel.h
arch/sparc/kernel/ktlb.S
arch/sparc/kernel/leon_pci_grpci2.c
arch/sparc/kernel/mdesc.c
arch/sparc/kernel/pcic.c
arch/sparc/kernel/pcr.c
arch/sparc/kernel/perf_event.c
arch/sparc/kernel/setup_64.c
arch/sparc/kernel/signal32.c
arch/sparc/kernel/signal_32.c
arch/sparc/kernel/signal_64.c
arch/sparc/kernel/sigutil.h [new file with mode: 0644]
arch/sparc/kernel/sigutil_32.c [new file with mode: 0644]
arch/sparc/kernel/sigutil_64.c [new file with mode: 0644]
arch/sparc/kernel/sparc_ksyms_64.c
arch/sparc/kernel/sstate.c
arch/sparc/kernel/unaligned_64.c
arch/sparc/kernel/vmlinux.lds.S
arch/sparc/lib/Makefile
arch/sparc/lib/NG2page.S [deleted file]
arch/sparc/lib/NGpage.S
arch/sparc/lib/atomic32.c
arch/sparc/lib/ffs.S [new file with mode: 0644]
arch/sparc/lib/hweight.S [new file with mode: 0644]
arch/sparc/mm/init_64.c
arch/tile/Kconfig
arch/tile/include/asm/Kbuild
arch/tile/include/asm/bug.h [deleted file]
arch/tile/include/asm/bugs.h [deleted file]
arch/tile/include/asm/cputime.h [deleted file]
arch/tile/include/asm/device.h [deleted file]
arch/tile/include/asm/div64.h [deleted file]
arch/tile/include/asm/emergency-restart.h [deleted file]
arch/tile/include/asm/errno.h [deleted file]
arch/tile/include/asm/fb.h [deleted file]
arch/tile/include/asm/fcntl.h [deleted file]
arch/tile/include/asm/fixmap.h
arch/tile/include/asm/ioctl.h [deleted file]
arch/tile/include/asm/ioctls.h [deleted file]
arch/tile/include/asm/ipc.h [deleted file]
arch/tile/include/asm/ipcbuf.h [deleted file]
arch/tile/include/asm/irq_regs.h [deleted file]
arch/tile/include/asm/kdebug.h [deleted file]
arch/tile/include/asm/local.h [deleted file]
arch/tile/include/asm/module.h [deleted file]
arch/tile/include/asm/msgbuf.h [deleted file]
arch/tile/include/asm/mutex.h [deleted file]
arch/tile/include/asm/param.h [deleted file]
arch/tile/include/asm/parport.h [deleted file]
arch/tile/include/asm/poll.h [deleted file]
arch/tile/include/asm/posix_types.h [deleted file]
arch/tile/include/asm/resource.h [deleted file]
arch/tile/include/asm/scatterlist.h [deleted file]
arch/tile/include/asm/sembuf.h [deleted file]
arch/tile/include/asm/serial.h [deleted file]
arch/tile/include/asm/shmbuf.h [deleted file]
arch/tile/include/asm/shmparam.h [deleted file]
arch/tile/include/asm/socket.h [deleted file]
arch/tile/include/asm/sockios.h [deleted file]
arch/tile/include/asm/statfs.h [deleted file]
arch/tile/include/asm/termbits.h [deleted file]
arch/tile/include/asm/termios.h [deleted file]
arch/tile/include/asm/types.h [deleted file]
arch/tile/include/asm/ucontext.h [deleted file]
arch/tile/include/asm/xor.h [deleted file]
arch/tile/include/hv/drv_srom_intf.h [new file with mode: 0644]
arch/tile/kernel/pci.c
arch/tile/kernel/time.c
arch/tile/mm/init.c
arch/unicore32/kernel/pci.c
arch/x86/Kconfig
arch/x86/include/asm/desc.h
arch/x86/include/asm/io.h
arch/x86/include/asm/irq_vectors.h
arch/x86/include/asm/paravirt_types.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/ptrace.h
arch/x86/include/asm/traps.h
arch/x86/include/asm/unistd_64.h
arch/x86/include/asm/vsyscall.h
arch/x86/include/asm/xen/page.h
arch/x86/kernel/Makefile
arch/x86/kernel/acpi/cstate.c
arch/x86/kernel/apic/x2apic_uv_x.c
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/entry_64.S
arch/x86/kernel/paravirt.c
arch/x86/kernel/process.c
arch/x86/kernel/process_32.c
arch/x86/kernel/process_64.c
arch/x86/kernel/step.c
arch/x86/kernel/traps.c
arch/x86/kernel/vmlinux.lds.S
arch/x86/kernel/vsyscall_64.c
arch/x86/kernel/vsyscall_emu_64.S
arch/x86/kernel/vsyscall_trace.h [new file with mode: 0644]
arch/x86/kvm/Kconfig
arch/x86/mm/fault.c
arch/x86/pci/acpi.c
arch/x86/pci/ce4100.c
arch/x86/pci/common.c
arch/x86/pci/direct.c
arch/x86/pci/numaq_32.c
arch/x86/pci/olpc.c
arch/x86/pci/pcbios.c
arch/x86/pci/visws.c
arch/x86/platform/mrst/Makefile
arch/x86/platform/mrst/pmu.c [new file with mode: 0644]
arch/x86/platform/mrst/pmu.h [new file with mode: 0644]
arch/x86/platform/olpc/olpc.c
arch/x86/vdso/vdso.S
arch/x86/vdso/vdso32/sysenter.S
arch/x86/xen/Makefile
arch/x86/xen/enlighten.c
arch/x86/xen/mmu.c
arch/x86/xen/setup.c
arch/x86/xen/smp.c
arch/x86/xen/trace.c
block/Kconfig
block/Makefile
block/blk-core.c
block/blk-flush.c
block/blk-softirq.c
block/blk-throttle.c
block/blk-timeout.c
block/blk.h
block/bsg-lib.c [new file with mode: 0644]
block/cfq-iosched.c
block/genhd.c
crypto/md5.c
drivers/acpi/acpica/acglobal.h
drivers/acpi/acpica/aclocal.h
drivers/acpi/acpica/acpredef.h
drivers/acpi/acpica/nspredef.c
drivers/acpi/acpica/nsrepair2.c
drivers/acpi/acpica/tbinstal.c
drivers/acpi/apei/Kconfig
drivers/acpi/apei/apei-base.c
drivers/acpi/apei/apei-internal.h
drivers/acpi/apei/einj.c
drivers/acpi/apei/erst-dbg.c
drivers/acpi/apei/erst.c
drivers/acpi/apei/ghes.c
drivers/acpi/apei/hest.c
drivers/acpi/battery.c
drivers/acpi/bus.c
drivers/acpi/dock.c
drivers/acpi/ec_sys.c
drivers/acpi/fan.c
drivers/acpi/osl.c
drivers/acpi/pci_irq.c
drivers/acpi/pci_root.c
drivers/acpi/processor_thermal.c
drivers/acpi/sbs.c
drivers/acpi/sleep.c
drivers/acpi/sysfs.c
drivers/acpi/thermal.c
drivers/acpi/video.c
drivers/ata/Kconfig
drivers/ata/Makefile
drivers/ata/libata-acpi.c
drivers/ata/pata_imx.c [new file with mode: 0644]
drivers/ata/pata_via.c
drivers/ata/sata_dwc_460ex.c
drivers/ata/sata_sil.c
drivers/base/devtmpfs.c
drivers/base/power/domain.c
drivers/base/power/runtime.c
drivers/base/regmap/regmap-i2c.c
drivers/base/regmap/regmap-spi.c
drivers/base/regmap/regmap.c
drivers/block/Kconfig
drivers/block/drbd/drbd_nl.c
drivers/block/loop.c
drivers/block/swim3.c
drivers/block/xen-blkfront.c
drivers/cdrom/cdrom.c
drivers/char/Kconfig
drivers/char/Makefile
drivers/char/hw_random/n2-drv.c
drivers/char/hw_random/n2rng.h
drivers/char/ramoops.c
drivers/char/random.c
drivers/char/tile-srom.c [new file with mode: 0644]
drivers/char/tpm/tpm_tis.c
drivers/connector/cn_proc.c
drivers/cpuidle/cpuidle.c
drivers/cpuidle/cpuidle.h
drivers/cpuidle/driver.c
drivers/cpuidle/governor.c
drivers/crypto/n2_core.c
drivers/dma/TODO
drivers/dma/amba-pl08x.c
drivers/dma/at_hdmac.c
drivers/dma/coh901318.c
drivers/dma/dmaengine.c
drivers/dma/ep93xx_dma.c
drivers/dma/imx-sdma.c
drivers/dma/intel_mid_dma.c
drivers/dma/ioat/dma_v3.c
drivers/dma/ioat/pci.c
drivers/dma/ipu/ipu_idmac.c
drivers/dma/mv_xor.c
drivers/dma/mxs-dma.c
drivers/dma/pch_dma.c
drivers/dma/pl330.c
drivers/dma/shdma.c
drivers/dma/shdma.h
drivers/dma/ste_dma40.c
drivers/dma/ste_dma40_ll.h
drivers/edac/i7core_edac.c
drivers/eisa/pci_eisa.c
drivers/firewire/core-cdev.c
drivers/firewire/core-device.c
drivers/firewire/ohci.c
drivers/firmware/efivars.c
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-ab8500.c
drivers/gpio/gpio-msm-v1.c [new file with mode: 0644]
drivers/gpio/gpio-msm-v2.c [moved from arch/arm/mach-msm/gpio-v2.c with 99% similarity]
drivers/gpio/gpio-tps65912.c [new file with mode: 0644]
drivers/gpu/drm/drm_debugfs.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_suspend.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_opregion.c
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/radeon/Makefile
drivers/gpu/drm/radeon/atom.c
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreen_cs.c
drivers/gpu/drm/radeon/r600_cs.c
drivers/gpu/drm/radeon/radeon_combios.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_encoders.c
drivers/gpu/drm/radeon/radeon_i2c.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/radeon_test.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/ttm/ttm_bo_util.c
drivers/hid/Kconfig
drivers/hid/hid-apple.c
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-wiimote.c
drivers/hid/usbhid/hid-quirks.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/coretemp.c
drivers/hwmon/ibmaem.c
drivers/hwmon/lm90.c
drivers/hwmon/lm95241.c
drivers/hwmon/lm95245.c [new file with mode: 0644]
drivers/hwmon/max1668.c [new file with mode: 0644]
drivers/hwmon/ntc_thermistor.c [new file with mode: 0644]
drivers/hwmon/pmbus/Kconfig [new file with mode: 0644]
drivers/hwmon/pmbus/Makefile [new file with mode: 0644]
drivers/hwmon/pmbus/adm1275.c [moved from drivers/hwmon/adm1275.c with 67% similarity]
drivers/hwmon/pmbus/lm25066.c [new file with mode: 0644]
drivers/hwmon/pmbus/max16064.c [moved from drivers/hwmon/max16064.c with 66% similarity]
drivers/hwmon/pmbus/max34440.c [moved from drivers/hwmon/max34440.c with 76% similarity]
drivers/hwmon/pmbus/max8688.c [moved from drivers/hwmon/max8688.c with 72% similarity]
drivers/hwmon/pmbus/pmbus.c [moved from drivers/hwmon/pmbus.c with 89% similarity]
drivers/hwmon/pmbus/pmbus.h [moved from drivers/hwmon/pmbus.h with 79% similarity]
drivers/hwmon/pmbus/pmbus_core.c [moved from drivers/hwmon/pmbus_core.c with 83% similarity]
drivers/hwmon/pmbus/ucd9000.c [moved from drivers/hwmon/ucd9000.c with 100% similarity]
drivers/hwmon/pmbus/ucd9200.c [moved from drivers/hwmon/ucd9200.c with 100% similarity]
drivers/ide/cy82c693.c
drivers/ide/ide_platform.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/iser/iscsi_iser.c
drivers/infiniband/ulp/iser/iscsi_iser.h
drivers/infiniband/ulp/iser/iser_initiator.c
drivers/input/joystick/analog.c
drivers/input/keyboard/ep93xx_keypad.c
drivers/input/keyboard/gpio_keys.c
drivers/input/keyboard/lm8323.c
drivers/input/keyboard/tegra-kbc.c
drivers/input/misc/ad714x-i2c.c
drivers/input/misc/ad714x-spi.c
drivers/input/misc/ad714x.c
drivers/input/misc/ad714x.h
drivers/input/misc/kxtj9.c
drivers/input/misc/mma8450.c
drivers/input/misc/mpu3050.c
drivers/input/mouse/bcm5974.c
drivers/input/mouse/hgpk.c
drivers/input/serio/xilinx_ps2.c
drivers/input/tablet/wacom_sys.c
drivers/input/tablet/wacom_wac.c
drivers/input/touchscreen/ad7879.c
drivers/input/touchscreen/atmel_mxt_ts.c
drivers/input/touchscreen/max11801_ts.c
drivers/input/touchscreen/tnetv107x-ts.c
drivers/md/Kconfig
drivers/md/dm-crypt.c
drivers/md/dm-flakey.c
drivers/md/dm-io.c
drivers/md/dm-ioctl.c
drivers/md/dm-kcopyd.c
drivers/md/dm-log-userspace-base.c
drivers/md/dm-log.c
drivers/md/dm-mpath.c
drivers/md/dm-raid.c
drivers/md/dm-snap-persistent.c
drivers/md/dm-snap.c
drivers/md/dm-table.c
drivers/md/dm.c
drivers/md/dm.h
drivers/media/Kconfig
drivers/media/common/tuners/Kconfig
drivers/media/common/tuners/Makefile
drivers/media/common/tuners/tuner-types.c
drivers/media/common/tuners/xc4000.c [new file with mode: 0644]
drivers/media/common/tuners/xc4000.h [new file with mode: 0644]
drivers/media/dvb/Kconfig
drivers/media/dvb/Makefile
drivers/media/dvb/bt8xx/dvb-bt8xx.c
drivers/media/dvb/ddbridge/Kconfig [new file with mode: 0644]
drivers/media/dvb/ddbridge/Makefile [new file with mode: 0644]
drivers/media/dvb/ddbridge/ddbridge-core.c [new file with mode: 0644]
drivers/media/dvb/ddbridge/ddbridge-regs.h [new file with mode: 0644]
drivers/media/dvb/ddbridge/ddbridge.h [new file with mode: 0644]
drivers/media/dvb/dvb-core/Makefile
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-core/dvb_net.h
drivers/media/dvb/dvb-usb/Kconfig
drivers/media/dvb/dvb-usb/af9015.c
drivers/media/dvb/dvb-usb/af9015.h
drivers/media/dvb/dvb-usb/anysee.c
drivers/media/dvb/dvb-usb/anysee.h
drivers/media/dvb/dvb-usb/dib0700_devices.c
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/dvb-usb/dvb-usb.h
drivers/media/dvb/dvb-usb/gp8psk.h
drivers/media/dvb/dvb-usb/technisat-usb2.c
drivers/media/dvb/dvb-usb/vp7045.h
drivers/media/dvb/firewire/firedtv-avc.c
drivers/media/dvb/firewire/firedtv-ci.c
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/au8522_decoder.c
drivers/media/dvb/frontends/cx24113.c
drivers/media/dvb/frontends/cx24116.c
drivers/media/dvb/frontends/cxd2820r.h
drivers/media/dvb/frontends/cxd2820r_core.c
drivers/media/dvb/frontends/cxd2820r_priv.h
drivers/media/dvb/frontends/dib7000p.c
drivers/media/dvb/frontends/drxd_hard.c
drivers/media/dvb/frontends/drxk.h [new file with mode: 0644]
drivers/media/dvb/frontends/drxk_hard.c [new file with mode: 0644]
drivers/media/dvb/frontends/drxk_hard.h [new file with mode: 0644]
drivers/media/dvb/frontends/drxk_map.h [new file with mode: 0644]
drivers/media/dvb/frontends/itd1000.c
drivers/media/dvb/frontends/nxt6000.c
drivers/media/dvb/frontends/s5h1420.c
drivers/media/dvb/frontends/tda18271c2dd.c [new file with mode: 0644]
drivers/media/dvb/frontends/tda18271c2dd.h [new file with mode: 0644]
drivers/media/dvb/frontends/tda18271c2dd_maps.h [new file with mode: 0644]
drivers/media/dvb/ngene/Kconfig
drivers/media/dvb/ngene/ngene-cards.c
drivers/media/dvb/ngene/ngene-core.c
drivers/media/dvb/ngene/ngene-dvb.c
drivers/media/dvb/ngene/ngene.h
drivers/media/dvb/siano/smscoreapi.c
drivers/media/dvb/siano/smscoreapi.h
drivers/media/radio/dsbr100.c
drivers/media/radio/radio-aimslab.c
drivers/media/radio/radio-aztech.c
drivers/media/radio/radio-cadet.c
drivers/media/radio/radio-gemtek.c
drivers/media/radio/radio-maxiradio.c
drivers/media/radio/radio-mr800.c
drivers/media/radio/radio-rtrack2.c
drivers/media/radio/radio-sf16fmi.c
drivers/media/radio/radio-sf16fmr2.c
drivers/media/radio/radio-tea5764.c
drivers/media/radio/radio-terratec.c
drivers/media/radio/radio-timb.c
drivers/media/radio/radio-trust.c
drivers/media/radio/radio-typhoon.c
drivers/media/radio/radio-wl1273.c
drivers/media/radio/radio-zoltrix.c
drivers/media/radio/si470x/radio-si470x-i2c.c
drivers/media/radio/si470x/radio-si470x-usb.c
drivers/media/radio/si470x/radio-si470x.h
drivers/media/radio/wl128x/fmdrv.h
drivers/media/radio/wl128x/fmdrv_v4l2.c
drivers/media/rc/Kconfig
drivers/media/rc/Makefile
drivers/media/rc/ene_ir.c
drivers/media/rc/ene_ir.h
drivers/media/rc/ir-lirc-codec.c
drivers/media/rc/ir-mce_kbd-decoder.c [new file with mode: 0644]
drivers/media/rc/ir-raw.c
drivers/media/rc/ite-cir.c
drivers/media/rc/keymaps/rc-rc6-mce.c
drivers/media/rc/mceusb.c
drivers/media/rc/nuvoton-cir.c
drivers/media/rc/rc-core-priv.h
drivers/media/rc/rc-loopback.c
drivers/media/rc/rc-main.c
drivers/media/rc/redrat3.c
drivers/media/rc/winbond-cir.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/adp1653.c [new file with mode: 0644]
drivers/media/video/arv.c
drivers/media/video/atmel-isi.c [new file with mode: 0644]
drivers/media/video/au0828/au0828-core.c
drivers/media/video/au0828/au0828-video.c
drivers/media/video/bt8xx/bttv-cards.c
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/bt8xx/bttvp.h
drivers/media/video/bw-qcam.c
drivers/media/video/c-qcam.c
drivers/media/video/cafe_ccic-regs.h [deleted file]
drivers/media/video/cafe_ccic.c [deleted file]
drivers/media/video/cpia2/cpia2.h
drivers/media/video/cpia2/cpia2_v4l.c
drivers/media/video/cx18/cx18-alsa-main.c
drivers/media/video/cx18/cx18-driver.h
drivers/media/video/cx18/cx18-ioctl.c
drivers/media/video/cx18/cx18-version.h
drivers/media/video/cx231xx/cx231xx-avcore.c
drivers/media/video/cx231xx/cx231xx-cards.c
drivers/media/video/cx231xx/cx231xx-core.c
drivers/media/video/cx231xx/cx231xx-video.c
drivers/media/video/cx231xx/cx231xx.h
drivers/media/video/cx23885/altera-ci.c
drivers/media/video/cx23885/cx23885-417.c
drivers/media/video/cx23885/cx23885-cards.c
drivers/media/video/cx23885/cx23885-core.c
drivers/media/video/cx23885/cx23885-dvb.c
drivers/media/video/cx23885/cx23885-input.c
drivers/media/video/cx23885/cx23885-video.c
drivers/media/video/cx23885/cx23885.h
drivers/media/video/cx88/cx88-alsa.c
drivers/media/video/cx88/cx88-blackbird.c
drivers/media/video/cx88/cx88-cards.c
drivers/media/video/cx88/cx88-core.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-input.c
drivers/media/video/cx88/cx88-mpeg.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/cx88/cx88.h
drivers/media/video/davinci/Kconfig
drivers/media/video/davinci/Makefile
drivers/media/video/davinci/vpbe.c [new file with mode: 0644]
drivers/media/video/davinci/vpbe_display.c [new file with mode: 0644]
drivers/media/video/davinci/vpbe_osd.c [new file with mode: 0644]
drivers/media/video/davinci/vpbe_osd_regs.h [new file with mode: 0644]
drivers/media/video/davinci/vpbe_venc.c [new file with mode: 0644]
drivers/media/video/davinci/vpbe_venc_regs.h [new file with mode: 0644]
drivers/media/video/davinci/vpif_capture.c
drivers/media/video/davinci/vpif_capture.h
drivers/media/video/davinci/vpif_display.c
drivers/media/video/davinci/vpif_display.h
drivers/media/video/em28xx/Kconfig
drivers/media/video/em28xx/Makefile
drivers/media/video/em28xx/em28xx-audio.c
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-core.c
drivers/media/video/em28xx/em28xx-dvb.c
drivers/media/video/em28xx/em28xx-i2c.c
drivers/media/video/em28xx/em28xx-input.c
drivers/media/video/em28xx/em28xx-reg.h
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/em28xx/em28xx.h
drivers/media/video/et61x251/et61x251.h
drivers/media/video/et61x251/et61x251_core.c
drivers/media/video/fsl-viu.c
drivers/media/video/gspca/Kconfig
drivers/media/video/gspca/Makefile
drivers/media/video/gspca/gl860/gl860.h
drivers/media/video/gspca/gspca.c
drivers/media/video/gspca/ov519.c
drivers/media/video/gspca/se401.c [new file with mode: 0644]
drivers/media/video/gspca/se401.h [new file with mode: 0644]
drivers/media/video/gspca/sunplus.c
drivers/media/video/gspca/t613.c
drivers/media/video/hdpvr/hdpvr-core.c
drivers/media/video/hdpvr/hdpvr-video.c
drivers/media/video/hdpvr/hdpvr.h
drivers/media/video/ivtv/ivtv-driver.h
drivers/media/video/ivtv/ivtv-fileops.c
drivers/media/video/ivtv/ivtv-ioctl.c
drivers/media/video/ivtv/ivtv-version.h
drivers/media/video/m5mols/m5mols_capture.c
drivers/media/video/m5mols/m5mols_core.c
drivers/media/video/marvell-ccic/Kconfig [new file with mode: 0644]
drivers/media/video/marvell-ccic/Makefile [new file with mode: 0644]
drivers/media/video/marvell-ccic/cafe-driver.c [new file with mode: 0644]
drivers/media/video/marvell-ccic/mcam-core.c [new file with mode: 0644]
drivers/media/video/marvell-ccic/mcam-core.h [new file with mode: 0644]
drivers/media/video/marvell-ccic/mmp-driver.c [new file with mode: 0644]
drivers/media/video/mem2mem_testdev.c
drivers/media/video/mt9m001.c
drivers/media/video/mt9m111.c
drivers/media/video/mt9t031.c
drivers/media/video/mt9t112.c
drivers/media/video/mt9v011.c
drivers/media/video/mt9v022.c
drivers/media/video/mt9v032.c
drivers/media/video/mx1_camera.c
drivers/media/video/mx2_camera.c
drivers/media/video/mx3_camera.c
drivers/media/video/omap/Kconfig
drivers/media/video/omap/Makefile
drivers/media/video/omap/omap_vout.c
drivers/media/video/omap/omap_vout_vrfb.c [new file with mode: 0644]
drivers/media/video/omap/omap_vout_vrfb.h [new file with mode: 0644]
drivers/media/video/omap/omap_voutdef.h
drivers/media/video/omap/omap_voutlib.c
drivers/media/video/omap/omap_voutlib.h
drivers/media/video/omap1_camera.c
drivers/media/video/omap24xxcam.c
drivers/media/video/omap3isp/isp.c
drivers/media/video/omap3isp/isp.h
drivers/media/video/omap3isp/ispccdc.c
drivers/media/video/omap3isp/ispccp2.c
drivers/media/video/omap3isp/ispccp2.h
drivers/media/video/omap3isp/ispstat.c
drivers/media/video/omap3isp/ispvideo.c
drivers/media/video/omap3isp/ispvideo.h
drivers/media/video/ov2640.c
drivers/media/video/ov5642.c [new file with mode: 0644]
drivers/media/video/ov7670.c
drivers/media/video/ov772x.c
drivers/media/video/ov9640.c
drivers/media/video/ov9740.c
drivers/media/video/pms.c
drivers/media/video/pvrusb2/pvrusb2-main.c
drivers/media/video/pvrusb2/pvrusb2-v4l2.c
drivers/media/video/pwc/Kconfig
drivers/media/video/pwc/pwc-ctrl.c
drivers/media/video/pwc/pwc-dec1.c
drivers/media/video/pwc/pwc-dec1.h
drivers/media/video/pwc/pwc-dec23.c
drivers/media/video/pwc/pwc-dec23.h
drivers/media/video/pwc/pwc-if.c
drivers/media/video/pwc/pwc-ioctl.h [deleted file]
drivers/media/video/pwc/pwc-kiara.c
drivers/media/video/pwc/pwc-misc.c
drivers/media/video/pwc/pwc-uncompress.c
drivers/media/video/pwc/pwc-uncompress.h [deleted file]
drivers/media/video/pwc/pwc-v4l.c
drivers/media/video/pwc/pwc.h
drivers/media/video/pxa_camera.c
drivers/media/video/rj54n1cb0c.c
drivers/media/video/s2255drv.c
drivers/media/video/s5p-fimc/fimc-capture.c
drivers/media/video/s5p-fimc/fimc-core.c
drivers/media/video/s5p-mfc/Makefile [new file with mode: 0644]
drivers/media/video/s5p-mfc/regs-mfc.h [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc.c [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_cmd.c [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_cmd.h [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_common.h [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_ctrl.h [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_debug.h [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_dec.c [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_dec.h [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_enc.c [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_enc.h [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_intr.c [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_intr.h [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_opr.c [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_opr.h [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_pm.c [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_pm.h [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_shm.c [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_shm.h [new file with mode: 0644]
drivers/media/video/s5p-tv/Kconfig [new file with mode: 0644]
drivers/media/video/s5p-tv/Makefile [new file with mode: 0644]
drivers/media/video/s5p-tv/hdmi_drv.c [new file with mode: 0644]
drivers/media/video/s5p-tv/hdmiphy_drv.c [new file with mode: 0644]
drivers/media/video/s5p-tv/mixer.h [new file with mode: 0644]
drivers/media/video/s5p-tv/mixer_drv.c [new file with mode: 0644]
drivers/media/video/s5p-tv/mixer_grp_layer.c [new file with mode: 0644]
drivers/media/video/s5p-tv/mixer_reg.c [new file with mode: 0644]
drivers/media/video/s5p-tv/mixer_video.c [new file with mode: 0644]
drivers/media/video/s5p-tv/mixer_vp_layer.c [new file with mode: 0644]
drivers/media/video/s5p-tv/regs-hdmi.h [new file with mode: 0644]
drivers/media/video/s5p-tv/regs-mixer.h [new file with mode: 0644]
drivers/media/video/s5p-tv/regs-sdo.h [new file with mode: 0644]
drivers/media/video/s5p-tv/regs-vp.h [new file with mode: 0644]
drivers/media/video/s5p-tv/sdo_drv.c [new file with mode: 0644]
drivers/media/video/saa7115.c
drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-core.c
drivers/media/video/saa7134/saa7134-dvb.c
drivers/media/video/saa7134/saa7134-empress.c
drivers/media/video/saa7134/saa7134-video.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/saa7164/saa7164-encoder.c
drivers/media/video/saa7164/saa7164-vbi.c
drivers/media/video/saa7164/saa7164.h
drivers/media/video/sh_mobile_ceu_camera.c
drivers/media/video/sh_mobile_csi2.c
drivers/media/video/sh_vou.c
drivers/media/video/sn9c102/sn9c102.h
drivers/media/video/sn9c102/sn9c102_core.c
drivers/media/video/soc_camera.c
drivers/media/video/soc_camera_platform.c
drivers/media/video/sr030pc30.c
drivers/media/video/tda7432.c
drivers/media/video/timblogiw.c
drivers/media/video/tlg2300/pd-common.h
drivers/media/video/tlg2300/pd-main.c
drivers/media/video/tlg2300/pd-radio.c
drivers/media/video/tuner-core.c
drivers/media/video/tw9910.c
drivers/media/video/usbvision/usbvision-video.c
drivers/media/video/uvc/uvc_ctrl.c
drivers/media/video/uvc/uvc_driver.c
drivers/media/video/uvc/uvc_v4l2.c
drivers/media/video/uvc/uvcvideo.h
drivers/media/video/v4l2-common.c
drivers/media/video/v4l2-compat-ioctl32.c
drivers/media/video/v4l2-ctrls.c
drivers/media/video/v4l2-device.c
drivers/media/video/v4l2-event.c
drivers/media/video/v4l2-fh.c
drivers/media/video/v4l2-ioctl.c
drivers/media/video/v4l2-subdev.c
drivers/media/video/videobuf-dma-sg.c
drivers/media/video/videobuf2-dma-sg.c
drivers/media/video/videobuf2-memops.c
drivers/media/video/vino.c
drivers/media/video/vivi.c
drivers/media/video/w9966.c
drivers/media/video/zoran/zoran.h
drivers/media/video/zoran/zoran_card.c
drivers/media/video/zoran/zoran_driver.c
drivers/media/video/zr364xx.c
drivers/message/fusion/mptscsih.c
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/aat2870-core.c [new file with mode: 0644]
drivers/mfd/ab3550-core.c
drivers/mfd/ab8500-core.c
drivers/mfd/ab8500-debugfs.c
drivers/mfd/jz4740-adc.c
drivers/mfd/lpc_sch.c
drivers/mfd/max8997-irq.c
drivers/mfd/max8998.c
drivers/mfd/omap-usb-host.c
drivers/mfd/stmpe.c
drivers/mfd/stmpe.h
drivers/mfd/timberdale.c
drivers/mfd/tps65910.c
drivers/mfd/tps65911-comparator.c
drivers/mfd/tps65912-core.c [new file with mode: 0644]
drivers/mfd/tps65912-i2c.c [new file with mode: 0644]
drivers/mfd/tps65912-irq.c [new file with mode: 0644]
drivers/mfd/tps65912-spi.c [new file with mode: 0644]
drivers/mfd/twl-core.c
drivers/mfd/twl4030-madc.c
drivers/mfd/twl6030-pwm.c
drivers/mfd/wm831x-auxadc.c [new file with mode: 0644]
drivers/mfd/wm831x-core.c
drivers/mfd/wm831x-irq.c
drivers/mfd/wm8350-irq.c
drivers/mfd/wm8994-core.c
drivers/mfd/wm8994-irq.c
drivers/misc/cb710/core.c
drivers/mmc/card/mmc_test.c
drivers/mmc/core/core.c
drivers/mmc/core/mmc.c
drivers/mmc/core/mmc_ops.c
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sdhci-pltfm.c
drivers/mmc/host/sdhci-pxav3.c
drivers/mmc/host/sdhci-s3c.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/tmio_mmc.c
drivers/net/bnx2x/bnx2x.h
drivers/net/bnx2x/bnx2x_cmn.c
drivers/net/bnx2x/bnx2x_dcb.c
drivers/net/bnx2x/bnx2x_ethtool.c
drivers/net/bnx2x/bnx2x_hsi.h
drivers/net/bnx2x/bnx2x_link.c
drivers/net/bnx2x/bnx2x_link.h
drivers/net/bnx2x/bnx2x_main.c
drivers/net/bnx2x/bnx2x_reg.h
drivers/net/bnx2x/bnx2x_stats.c
drivers/net/bonding/bond_main.c
drivers/net/can/sja1000/plx_pci.c
drivers/net/can/slcan.c
drivers/net/can/ti_hecc.c
drivers/net/cassini.c
drivers/net/e1000/e1000_ethtool.c
drivers/net/e1000/e1000_hw.c
drivers/net/e1000e/82571.c
drivers/net/e1000e/e1000.h
drivers/net/e1000e/es2lan.c
drivers/net/e1000e/ethtool.c
drivers/net/e1000e/ich8lan.c
drivers/net/e1000e/lib.c
drivers/net/e1000e/netdev.c
drivers/net/e1000e/phy.c
drivers/net/fec.c
drivers/net/forcedeth.c
drivers/net/gianfar.c
drivers/net/gianfar_ethtool.c
drivers/net/gianfar_ptp.c
drivers/net/ibm_newemac/core.c
drivers/net/ibm_newemac/emac.h
drivers/net/ibm_newemac/phy.c
drivers/net/ibmveth.c
drivers/net/igb/e1000_nvm.c
drivers/net/igb/igb_ethtool.c
drivers/net/igb/igb_main.c
drivers/net/igbvf/netdev.c
drivers/net/irda/sh_irda.c
drivers/net/irda/sh_sir.c
drivers/net/irda/smsc-ircc2.c
drivers/net/ixgb/ixgb_ee.c
drivers/net/ixgb/ixgb_hw.c
drivers/net/ixgbe/ixgbe_82599.c
drivers/net/ixgbe/ixgbe_common.c
drivers/net/ixgbe/ixgbe_ethtool.c
drivers/net/ixgbe/ixgbe_main.c
drivers/net/ixgbe/ixgbe_phy.c
drivers/net/ixgbe/ixgbe_x540.c
drivers/net/macb.c
drivers/net/mlx4/en_port.c
drivers/net/mlx4/main.c
drivers/net/mlx4/port.c
drivers/net/niu.c
drivers/net/pcmcia/smc91c92_cs.c
drivers/net/pcnet32.c
drivers/net/phy/dp83640.c
drivers/net/phy/national.c
drivers/net/r8169.c
drivers/net/sh_eth.c
drivers/net/sis190.c
drivers/net/slip.c
drivers/net/sungem.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/ipheth.c
drivers/net/usb/rtl8150.c
drivers/net/via-velocity.c
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/wireless/hostap/hostap_cs.c
drivers/net/wireless/orinoco/orinoco_cs.c
drivers/of/address.c
drivers/of/base.c
drivers/of/gpio.c
drivers/of/of_net.c
drivers/pci/hotplug/acpi_pcihp.c
drivers/pci/hotplug/acpiphp_glue.c
drivers/pci/hotplug/cpqphp_core.c
drivers/pci/hotplug/pciehp_ctrl.c
drivers/pci/hotplug/pciehp_hpc.c
drivers/pci/hotplug/pcihp_slot.c
drivers/pci/of.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/aer/aerdrv_core.c
drivers/pci/pcie/aer/aerdrv_errprint.c
drivers/pci/probe.c
drivers/pci/setup-bus.c
drivers/pci/setup-irq.c
drivers/pci/setup-res.c
drivers/pcmcia/pxa2xx_balloon3.c
drivers/pcmcia/pxa2xx_cm_x255.c
drivers/pcmcia/pxa2xx_cm_x270.c
drivers/pcmcia/pxa2xx_colibri.c
drivers/pcmcia/pxa2xx_mainstone.c
drivers/pcmcia/pxa2xx_palmld.c
drivers/pcmcia/pxa2xx_palmtc.c
drivers/pcmcia/pxa2xx_palmtx.c
drivers/pcmcia/pxa2xx_stargate2.c
drivers/pcmcia/pxa2xx_viper.c
drivers/pcmcia/soc_common.c
drivers/platform/x86/Kconfig
drivers/platform/x86/Makefile
drivers/platform/x86/acer-wmi.c
drivers/platform/x86/acerhdf.c
drivers/platform/x86/asus-laptop.c
drivers/platform/x86/asus-nb-wmi.c
drivers/platform/x86/asus-wmi.c
drivers/platform/x86/asus-wmi.h
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/dell-wmi.c
drivers/platform/x86/eeepc-wmi.c
drivers/platform/x86/ideapad-laptop.c
drivers/platform/x86/intel_ips.c
drivers/platform/x86/intel_menlow.c
drivers/platform/x86/intel_mid_thermal.c
drivers/platform/x86/intel_rar_register.c
drivers/platform/x86/intel_scu_ipc.c
drivers/platform/x86/msi-laptop.c
drivers/platform/x86/msi-wmi.c
drivers/platform/x86/samsung-laptop.c
drivers/platform/x86/samsung-q10.c [new file with mode: 0644]
drivers/platform/x86/thinkpad_acpi.c
drivers/power/Kconfig
drivers/power/Makefile
drivers/power/apm_power.c
drivers/power/bq20z75.c
drivers/power/gpio-charger.c
drivers/power/max17042_battery.c
drivers/power/max8903_charger.c
drivers/power/max8997_charger.c [new file with mode: 0644]
drivers/power/max8998_charger.c [new file with mode: 0644]
drivers/power/s3c_adc_battery.c
drivers/power/twl4030_charger.c
drivers/power/wm831x_backup.c
drivers/power/wm831x_power.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/aat2870-regulator.c [new file with mode: 0644]
drivers/regulator/core.c
drivers/regulator/dummy.c
drivers/regulator/tps65910-regulator.c
drivers/regulator/tps65912-regulator.c [new file with mode: 0644]
drivers/regulator/twl-regulator.c
drivers/regulator/wm831x-dcdc.c
drivers/regulator/wm831x-ldo.c
drivers/regulator/wm8994-regulator.c
drivers/rtc/interface.c
drivers/rtc/rtc-omap.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_proc.c
drivers/s390/char/sclp_async.c
drivers/s390/cio/qdio.h
drivers/s390/cio/qdio_debug.c
drivers/s390/cio/qdio_main.c
drivers/scsi/bfa/bfa.h
drivers/scsi/bfa/bfa_core.c
drivers/scsi/bfa/bfa_defs.h
drivers/scsi/bfa/bfa_defs_svc.h
drivers/scsi/bfa/bfa_fc.h
drivers/scsi/bfa/bfa_fcpim.c
drivers/scsi/bfa/bfa_fcpim.h
drivers/scsi/bfa/bfa_fcs.c
drivers/scsi/bfa/bfa_fcs.h
drivers/scsi/bfa/bfa_fcs_fcpim.c
drivers/scsi/bfa/bfa_fcs_lport.c
drivers/scsi/bfa/bfa_fcs_rport.c
drivers/scsi/bfa/bfa_hw_cb.c
drivers/scsi/bfa/bfa_hw_ct.c
drivers/scsi/bfa/bfa_ioc.c
drivers/scsi/bfa/bfa_ioc.h
drivers/scsi/bfa/bfa_modules.h
drivers/scsi/bfa/bfa_svc.c
drivers/scsi/bfa/bfa_svc.h
drivers/scsi/bfa/bfad.c
drivers/scsi/bfa/bfad_bsg.c
drivers/scsi/bfa/bfad_bsg.h
drivers/scsi/bfa/bfad_drv.h
drivers/scsi/bfa/bfad_im.c
drivers/scsi/bfa/bfad_im.h
drivers/scsi/bfa/bfi.h
drivers/scsi/bnx2fc/bnx2fc.h
drivers/scsi/bnx2fc/bnx2fc_debug.h
drivers/scsi/bnx2fc/bnx2fc_els.c
drivers/scsi/bnx2fc/bnx2fc_fcoe.c
drivers/scsi/bnx2fc/bnx2fc_hwi.c
drivers/scsi/bnx2fc/bnx2fc_io.c
drivers/scsi/bnx2fc/bnx2fc_tgt.c
drivers/scsi/device_handler/scsi_dh_rdac.c
drivers/scsi/fcoe/fcoe.c
drivers/scsi/hpsa.c
drivers/scsi/hpsa.h
drivers/scsi/ipr.c
drivers/scsi/libfc/fc_exch.c
drivers/scsi/libfc/fc_fcp.c
drivers/scsi/libfc/fc_lport.c
drivers/scsi/libsas/sas_expander.c
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_bsg.c
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_debugfs.c
drivers/scsi/lpfc/lpfc_debugfs.h
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_hw.h
drivers/scsi/lpfc/lpfc_hw4.h
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_mbox.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_sli4.h
drivers/scsi/lpfc/lpfc_version.h
drivers/scsi/megaraid/megaraid_sas.h
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/megaraid/megaraid_sas_fp.c
drivers/scsi/mpt2sas/mpt2sas_scsih.c
drivers/scsi/mvsas/Kconfig
drivers/scsi/mvsas/mv_64xx.c
drivers/scsi/mvsas/mv_94xx.c
drivers/scsi/mvsas/mv_94xx.h
drivers/scsi/mvsas/mv_chips.h
drivers/scsi/mvsas/mv_defs.h
drivers/scsi/mvsas/mv_init.c
drivers/scsi/mvsas/mv_sas.c
drivers/scsi/mvsas/mv_sas.h
drivers/scsi/pmcraid.c
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_bsg.c
drivers/scsi/qla2xxx/qla_dbg.c
drivers/scsi/qla2xxx/qla_dbg.h
drivers/scsi/qla2xxx/qla_dfs.c
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_gs.c
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_inline.h
drivers/scsi/qla2xxx/qla_iocb.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_mid.c
drivers/scsi/qla2xxx/qla_nx.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_sup.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_transport_spi.c
drivers/sh/clk/core.c
drivers/spi/spi-pl022.c
drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.c
drivers/staging/cxd2099/Kconfig
drivers/staging/cxd2099/cxd2099.c
drivers/staging/cxd2099/cxd2099.h
drivers/staging/dt3155v4l/dt3155v4l.c
drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c
drivers/staging/gma500/gem_glue.c
drivers/staging/gma500/gem_glue.h
drivers/staging/gma500/mdfld_dsi_dbi.c
drivers/staging/gma500/mdfld_dsi_dbi.h
drivers/staging/gma500/mdfld_dsi_dpi.c
drivers/staging/gma500/mdfld_dsi_output.c
drivers/staging/gma500/medfield.h
drivers/staging/gma500/psb_drv.h
drivers/staging/hv/blkvsc_drv.c
drivers/staging/iio/accel/adis16203_core.c
drivers/staging/iio/accel/adis16204_core.c
drivers/staging/iio/accel/adis16209_core.c
drivers/staging/iio/accel/adis16240_core.c
drivers/staging/iio/gyro/adis16260_core.c
drivers/staging/nvec/TODO
drivers/staging/rtl8192u/r819xU_firmware.c
drivers/staging/rts_pstor/rtsx.c
drivers/staging/rts_pstor/rtsx.h
drivers/staging/solo6x10/core.c
drivers/staging/solo6x10/enc.c
drivers/staging/solo6x10/g723.c
drivers/staging/solo6x10/p2m.c
drivers/staging/solo6x10/solo6x10.h
drivers/staging/speakup/devsynth.c
drivers/staging/tm6000/tm6000-alsa.c
drivers/staging/zcache/Makefile
drivers/staging/zcache/zcache-main.c [moved from drivers/staging/zcache/zcache.c with 99% similarity]
drivers/target/iscsi/Kconfig
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_configfs.c
drivers/target/iscsi/iscsi_target_nego.c
drivers/target/target_core_transport.c
drivers/target/tcm_fc/tcm_fc.h
drivers/target/tcm_fc/tfc_cmd.c
drivers/target/tcm_fc/tfc_io.c
drivers/thermal/Kconfig
drivers/thermal/thermal_sys.c
drivers/tty/serial/Kconfig
drivers/tty/serial/imx.c
drivers/tty/serial/sh-sci.c
drivers/tty/serial/sh-sci.h
drivers/usb/class/usbtmc.c
drivers/usb/core/config.c
drivers/usb/gadget/Kconfig
drivers/usb/gadget/at91_udc.c
drivers/usb/gadget/composite.c
drivers/usb/gadget/f_hid.c
drivers/usb/gadget/fusb300_udc.c
drivers/usb/gadget/net2272.c
drivers/usb/gadget/s3c2410_udc.c
drivers/usb/gadget/uvc_v4l2.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/ehci-mxc.c
drivers/usb/host/ehci-omap.c
drivers/usb/host/isp1760-hcd.c
drivers/usb/host/pci-quirks.c
drivers/usb/host/xhci.c
drivers/usb/musb/Kconfig
drivers/usb/musb/musb_gadget.c
drivers/usb/musb/tusb6010_omap.c
drivers/usb/renesas_usbhs/mod_gadget.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/option.c
drivers/usb/serial/qcserial.c
drivers/usb/storage/unusual_devs.h
drivers/video/backlight/Kconfig
drivers/video/backlight/Makefile
drivers/video/backlight/aat2870_bl.c [new file with mode: 0644]
drivers/video/omap2/displays/panel-taal.c
drivers/video/omap2/dss/Kconfig
drivers/video/omap2/dss/core.c
drivers/video/omap2/dss/dispc.c
drivers/video/omap2/dss/display.c
drivers/video/omap2/dss/dpi.c
drivers/video/omap2/dss/dsi.c
drivers/video/omap2/dss/dss.c
drivers/video/omap2/dss/dss.h
drivers/video/omap2/dss/dss_features.c
drivers/video/omap2/dss/dss_features.h
drivers/video/omap2/dss/hdmi.c
drivers/video/omap2/dss/manager.c
drivers/video/omap2/dss/overlay.c
drivers/video/omap2/dss/rfbi.c
drivers/video/omap2/dss/sdi.c
drivers/video/omap2/dss/venc.c
drivers/video/omap2/omapfb/omapfb-ioctl.c
drivers/video/omap2/omapfb/omapfb-main.c
drivers/video/omap2/omapfb/omapfb-sysfs.c
drivers/video/omap2/omapfb/omapfb.h
drivers/video/savage/savagefb.h
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/at91sam9_wdt.c
drivers/watchdog/at91sam9_wdt.h [moved from arch/arm/mach-at91/include/mach/at91_wdt.h with 96% similarity]
drivers/watchdog/dw_wdt.c [new file with mode: 0644]
drivers/watchdog/hpwdt.c
drivers/watchdog/iTCO_wdt.c
drivers/watchdog/imx2_wdt.c
drivers/watchdog/it8712f_wdt.c
drivers/watchdog/it87_wdt.c
drivers/watchdog/mpcore_wdt.c
drivers/watchdog/mtx-1_wdt.c
drivers/watchdog/nv_tco.c
drivers/watchdog/of_xilinx_wdt.c [new file with mode: 0644]
drivers/watchdog/pc87413_wdt.c
drivers/watchdog/s3c2410_wdt.c
drivers/watchdog/sch311x_wdt.c
drivers/watchdog/shwdt.c
drivers/watchdog/sp805_wdt.c
drivers/watchdog/watchdog_core.c [new file with mode: 0644]
drivers/watchdog/watchdog_dev.c [new file with mode: 0644]
drivers/watchdog/watchdog_dev.h [new file with mode: 0644]
drivers/xen/Kconfig
drivers/xen/grant-table.c
drivers/xen/xen-pciback/xenbus.c
drivers/xen/xen-selfballoon.c
fs/9p/acl.c
fs/9p/acl.h
fs/9p/vfs_inode_dotl.c
fs/Kconfig
fs/autofs4/autofs_i.h
fs/autofs4/waitq.c
fs/befs/linuxvfs.c
fs/block_dev.c
fs/btrfs/Makefile
fs/btrfs/acl.c
fs/btrfs/compression.c
fs/btrfs/ctree.h
fs/btrfs/dir-item.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/extent_map.c
fs/btrfs/file-item.c
fs/btrfs/file.c
fs/btrfs/free-space-cache.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/ref-cache.c [deleted file]
fs/btrfs/ref-cache.h [deleted file]
fs/btrfs/root-tree.c
fs/btrfs/transaction.c
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/btrfs/volumes.h
fs/cifs/cifs_debug.c
fs/cifs/cifs_dfs_ref.c
fs/cifs/cifsacl.c
fs/cifs/cifsencrypt.c
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/cifsglob.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/dns_resolve.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/misc.c
fs/cifs/transport.c
fs/compat_ioctl.c
fs/dcache.c
fs/ecryptfs/Kconfig
fs/ecryptfs/inode.c
fs/ecryptfs/keystore.c
fs/ecryptfs/main.c
fs/ecryptfs/read_write.c
fs/exec.c
fs/exofs/Kbuild
fs/exofs/Kconfig
fs/exofs/exofs.h
fs/exofs/inode.c
fs/exofs/ore.c [moved from fs/exofs/ios.c with 61% similarity]
fs/exofs/pnfs.h [deleted file]
fs/exofs/super.c
fs/ext2/acl.c
fs/ext2/acl.h
fs/ext3/acl.c
fs/ext3/namei.c
fs/ext4/Makefile
fs/ext4/acl.c
fs/ext4/balloc.c
fs/ext4/block_validity.c
fs/ext4/ext4.h
fs/ext4/ext4_jbd2.h
fs/ext4/extents.c
fs/ext4/fsync.c
fs/ext4/ialloc.c
fs/ext4/indirect.c [new file with mode: 0644]
fs/ext4/inode.c
fs/ext4/ioctl.c
fs/ext4/mballoc.c
fs/ext4/mballoc.h
fs/ext4/namei.c
fs/ext4/page-io.c
fs/ext4/resize.c
fs/ext4/super.c
fs/ext4/truncate.h [new file with mode: 0644]
fs/fat/dir.c
fs/fat/inode.c
fs/fs-writeback.c
fs/fuse/dev.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/fuse/inode.c
fs/generic_acl.c
fs/gfs2/acl.c
fs/hppfs/hppfs.c
fs/inode.c
fs/jbd2/checkpoint.c
fs/jbd2/journal.c
fs/jffs2/acl.c
fs/jffs2/acl.h
fs/jffs2/fs.c
fs/jffs2/os-linux.h
fs/jfs/acl.c
fs/jfs/jfs_umount.c
fs/jfs/xattr.c
fs/namei.c
fs/nfs/Kconfig
fs/nfs/Makefile
fs/nfs/blocklayout/Makefile [new file with mode: 0644]
fs/nfs/blocklayout/blocklayout.c [new file with mode: 0644]
fs/nfs/blocklayout/blocklayout.h [new file with mode: 0644]
fs/nfs/blocklayout/blocklayoutdev.c [new file with mode: 0644]
fs/nfs/blocklayout/blocklayoutdm.c [new file with mode: 0644]
fs/nfs/blocklayout/extents.c [new file with mode: 0644]
fs/nfs/callback.h
fs/nfs/callback_proc.c
fs/nfs/callback_xdr.c
fs/nfs/client.c
fs/nfs/dir.c
fs/nfs/nfs3acl.c
fs/nfs/nfs3proc.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4filelayout.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4xdr.c
fs/nfs/objlayout/objio_osd.c
fs/nfs/objlayout/pnfs_osd_xdr_cli.c
fs/nfs/pnfs.c
fs/nfs/pnfs.h
fs/ocfs2/acl.c
fs/posix_acl.c
fs/proc/base.c
fs/pstore/inode.c
fs/pstore/internal.h
fs/pstore/platform.c
fs/reiserfs/xattr_acl.c
fs/stack.c
fs/stat.c
fs/xfs/Makefile
fs/xfs/kmem.c [moved from fs/xfs/linux-2.6/kmem.c with 100% similarity]
fs/xfs/kmem.h [moved from fs/xfs/linux-2.6/kmem.h with 100% similarity]
fs/xfs/mrlock.h [moved from fs/xfs/linux-2.6/mrlock.h with 100% similarity]
fs/xfs/time.h [moved from fs/xfs/linux-2.6/time.h with 100% similarity]
fs/xfs/uuid.c [moved from fs/xfs/support/uuid.c with 100% similarity]
fs/xfs/uuid.h [moved from fs/xfs/support/uuid.h with 100% similarity]
fs/xfs/xfs.h
fs/xfs/xfs_acl.c [moved from fs/xfs/linux-2.6/xfs_acl.c with 98% similarity]
fs/xfs/xfs_acl.h
fs/xfs/xfs_ag.h
fs/xfs/xfs_alloc.c
fs/xfs/xfs_aops.c [moved from fs/xfs/linux-2.6/xfs_aops.c with 100% similarity]
fs/xfs/xfs_aops.h [moved from fs/xfs/linux-2.6/xfs_aops.h with 100% similarity]
fs/xfs/xfs_attr.c
fs/xfs/xfs_bmap.c
fs/xfs/xfs_btree.c
fs/xfs/xfs_btree.h
fs/xfs/xfs_buf.c [moved from fs/xfs/linux-2.6/xfs_buf.c with 99% similarity]
fs/xfs/xfs_buf.h [moved from fs/xfs/linux-2.6/xfs_buf.h with 92% similarity]
fs/xfs/xfs_buf_item.c
fs/xfs/xfs_da_btree.c
fs/xfs/xfs_dinode.h
fs/xfs/xfs_discard.c [moved from fs/xfs/linux-2.6/xfs_discard.c with 100% similarity]
fs/xfs/xfs_discard.h [moved from fs/xfs/linux-2.6/xfs_discard.h with 100% similarity]
fs/xfs/xfs_dquot.c [moved from fs/xfs/quota/xfs_dquot.c with 98% similarity]
fs/xfs/xfs_dquot.h [moved from fs/xfs/quota/xfs_dquot.h with 100% similarity]
fs/xfs/xfs_dquot_item.c [moved from fs/xfs/quota/xfs_dquot_item.c with 100% similarity]
fs/xfs/xfs_dquot_item.h [moved from fs/xfs/quota/xfs_dquot_item.h with 100% similarity]
fs/xfs/xfs_export.c [moved from fs/xfs/linux-2.6/xfs_export.c with 100% similarity]
fs/xfs/xfs_export.h [moved from fs/xfs/linux-2.6/xfs_export.h with 100% similarity]
fs/xfs/xfs_file.c [moved from fs/xfs/linux-2.6/xfs_file.c with 100% similarity]
fs/xfs/xfs_fs_subr.c [moved from fs/xfs/linux-2.6/xfs_fs_subr.c with 100% similarity]
fs/xfs/xfs_globals.c [moved from fs/xfs/linux-2.6/xfs_globals.c with 100% similarity]
fs/xfs/xfs_ialloc.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_ioctl.c [moved from fs/xfs/linux-2.6/xfs_ioctl.c with 100% similarity]
fs/xfs/xfs_ioctl.h [moved from fs/xfs/linux-2.6/xfs_ioctl.h with 100% similarity]
fs/xfs/xfs_ioctl32.c [moved from fs/xfs/linux-2.6/xfs_ioctl32.c with 100% similarity]
fs/xfs/xfs_ioctl32.h [moved from fs/xfs/linux-2.6/xfs_ioctl32.h with 100% similarity]
fs/xfs/xfs_iops.c [moved from fs/xfs/linux-2.6/xfs_iops.c with 100% similarity]
fs/xfs/xfs_iops.h [moved from fs/xfs/linux-2.6/xfs_iops.h with 100% similarity]
fs/xfs/xfs_linux.h [moved from fs/xfs/linux-2.6/xfs_linux.h with 96% similarity]
fs/xfs/xfs_log.c
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_message.c [moved from fs/xfs/linux-2.6/xfs_message.c with 100% similarity]
fs/xfs/xfs_message.h [moved from fs/xfs/linux-2.6/xfs_message.h with 100% similarity]
fs/xfs/xfs_mount.c
fs/xfs/xfs_qm.c [moved from fs/xfs/quota/xfs_qm.c with 99% similarity]
fs/xfs/xfs_qm.h [moved from fs/xfs/quota/xfs_qm.h with 100% similarity]
fs/xfs/xfs_qm_bhv.c [moved from fs/xfs/quota/xfs_qm_bhv.c with 100% similarity]
fs/xfs/xfs_qm_stats.c [moved from fs/xfs/quota/xfs_qm_stats.c with 100% similarity]
fs/xfs/xfs_qm_stats.h [moved from fs/xfs/quota/xfs_qm_stats.h with 100% similarity]
fs/xfs/xfs_qm_syscalls.c [moved from fs/xfs/quota/xfs_qm_syscalls.c with 100% similarity]
fs/xfs/xfs_quota_priv.h [moved from fs/xfs/quota/xfs_quota_priv.h with 100% similarity]
fs/xfs/xfs_quotaops.c [moved from fs/xfs/linux-2.6/xfs_quotaops.c with 99% similarity]
fs/xfs/xfs_rtalloc.c
fs/xfs/xfs_rtalloc.h
fs/xfs/xfs_rw.c
fs/xfs/xfs_sb.h
fs/xfs/xfs_stats.c [moved from fs/xfs/linux-2.6/xfs_stats.c with 100% similarity]
fs/xfs/xfs_stats.h [moved from fs/xfs/linux-2.6/xfs_stats.h with 100% similarity]
fs/xfs/xfs_super.c [moved from fs/xfs/linux-2.6/xfs_super.c with 100% similarity]
fs/xfs/xfs_super.h [moved from fs/xfs/linux-2.6/xfs_super.h with 100% similarity]
fs/xfs/xfs_sync.c [moved from fs/xfs/linux-2.6/xfs_sync.c with 99% similarity]
fs/xfs/xfs_sync.h [moved from fs/xfs/linux-2.6/xfs_sync.h with 100% similarity]
fs/xfs/xfs_sysctl.c [moved from fs/xfs/linux-2.6/xfs_sysctl.c with 100% similarity]
fs/xfs/xfs_sysctl.h [moved from fs/xfs/linux-2.6/xfs_sysctl.h with 100% similarity]
fs/xfs/xfs_trace.c [moved from fs/xfs/linux-2.6/xfs_trace.c with 96% similarity]
fs/xfs/xfs_trace.h [moved from fs/xfs/linux-2.6/xfs_trace.h with 100% similarity]
fs/xfs/xfs_trans_ail.c
fs/xfs/xfs_trans_buf.c
fs/xfs/xfs_trans_dquot.c [moved from fs/xfs/quota/xfs_trans_dquot.c with 100% similarity]
fs/xfs/xfs_vnode.h [moved from fs/xfs/linux-2.6/xfs_vnode.h with 100% similarity]
fs/xfs/xfs_vnodeops.c
fs/xfs/xfs_xattr.c [moved from fs/xfs/linux-2.6/xfs_xattr.c with 100% similarity]
include/acpi/acpi_drivers.h
include/acpi/acpixf.h
include/acpi/apei.h
include/acpi/processor.h
include/asm-generic/memory_model.h
include/drm/drm_crtc.h
include/drm/i915_drm.h
include/linux/acpi.h
include/linux/aer.h
include/linux/amba/pl08x.h
include/linux/bitmap.h
include/linux/blk_types.h
include/linux/blkdev.h
include/linux/blktrace_api.h
include/linux/bsg-lib.h [new file with mode: 0644]
include/linux/cpuidle.h
include/linux/cred.h
include/linux/cryptohash.h
include/linux/dcache.h
include/linux/device-mapper.h
include/linux/dm-ioctl.h
include/linux/dm-kcopyd.h
include/linux/dvb/audio.h
include/linux/efi.h
include/linux/fault-inject.h
include/linux/fs.h
include/linux/fuse.h
include/linux/genalloc.h
include/linux/gfp.h
include/linux/hash.h
include/linux/idr.h
include/linux/input.h
include/linux/ioport.h
include/linux/irq.h
include/linux/irqdesc.h
include/linux/irqdomain.h [new file with mode: 0644]
include/linux/jbd2.h
include/linux/kconfig.h [new file with mode: 0644]
include/linux/llist.h [new file with mode: 0644]
include/linux/loop.h
include/linux/memcontrol.h
include/linux/mfd/aat2870.h [new file with mode: 0644]
include/linux/mfd/ab8500.h
include/linux/mfd/max8997.h
include/linux/mfd/max8998.h
include/linux/mfd/stmpe.h
include/linux/mfd/tps65910.h
include/linux/mfd/tps65912.h [new file with mode: 0644]
include/linux/mfd/wm831x/core.h
include/linux/mfd/wm831x/pdata.h
include/linux/miscdevice.h
include/linux/mm.h
include/linux/mm_types.h
include/linux/mmc/host.h
include/linux/netlink.h
include/linux/nfs.h
include/linux/nfs4.h
include/linux/nfs_fs.h
include/linux/nfs_fs_sb.h
include/linux/nfs_xdr.h
include/linux/of.h
include/linux/of_gpio.h
include/linux/of_irq.h
include/linux/of_net.h
include/linux/page-flags.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/phy.h
include/linux/platform_data/ntc_thermistor.h [new file with mode: 0644]
include/linux/pm_domain.h
include/linux/posix_acl.h
include/linux/power/bq20z75.h
include/linux/power/max17042_battery.h
include/linux/pstore.h
include/linux/radix-tree.h
include/linux/random.h
include/linux/regulator/consumer.h
include/linux/regulator/driver.h
include/linux/rtc.h
include/linux/sched.h
include/linux/serial_sci.h
include/linux/sh_clk.h
include/linux/sh_dma.h
include/linux/shm.h
include/linux/shmem_fs.h
include/linux/skbuff.h
include/linux/slub_def.h
include/linux/snmp.h
include/linux/socket.h
include/linux/swapops.h
include/linux/thermal.h
include/linux/videodev2.h
include/linux/watchdog.h
include/media/adp1653.h [new file with mode: 0644]
include/media/atmel-isi.h [new file with mode: 0644]
include/media/davinci/vpbe.h [new file with mode: 0644]
include/media/davinci/vpbe_display.h [new file with mode: 0644]
include/media/davinci/vpbe_osd.h [new file with mode: 0644]
include/media/davinci/vpbe_types.h [new file with mode: 0644]
include/media/davinci/vpbe_venc.h [new file with mode: 0644]
include/media/mmp-camera.h [new file with mode: 0644]
include/media/ov7670.h [moved from drivers/media/video/ov7670.h with 100% similarity]
include/media/rc-core.h
include/media/rc-map.h
include/media/sh_mobile_ceu.h
include/media/sh_mobile_csi2.h
include/media/soc_camera.h
include/media/soc_camera_platform.h
include/media/timb_radio.h
include/media/tuner.h
include/media/v4l2-chip-ident.h
include/media/v4l2-ctrls.h
include/media/v4l2-event.h
include/media/v4l2-fh.h
include/media/v4l2-mediabus.h
include/media/v4l2-subdev.h
include/net/cipso_ipv4.h
include/net/dst.h
include/net/inet_sock.h
include/net/netlabel.h
include/net/request_sock.h
include/net/secure_seq.h [new file with mode: 0644]
include/net/tcp.h
include/pcmcia/device_id.h
include/scsi/fc_frame.h
include/scsi/osd_ore.h [new file with mode: 0644]
include/sound/tea575x-tuner.h
include/sound/tlv320aic3x.h
include/sound/wm8996.h [moved from include/sound/wm8915.h with 63% similarity]
include/trace/events/block.h
include/trace/events/ext4.h
include/trace/events/jbd2.h
include/trace/events/xen.h
include/video/omapdss.h
init/main.c
ipc/shm.c
kernel/Makefile
kernel/compat.c
kernel/cred.c
kernel/debug/gdbstub.c
kernel/debug/kdb/kdb_bt.c
kernel/debug/kdb/kdb_cmds
kernel/debug/kdb/kdb_debugger.c
kernel/debug/kdb/kdb_io.c
kernel/debug/kdb/kdb_main.c
kernel/debug/kdb/kdb_private.h
kernel/fork.c
kernel/futex.c
kernel/irq/Kconfig
kernel/irq/Makefile
kernel/irq/generic-chip.c
kernel/irq/irqdesc.c
kernel/irq/irqdomain.c [new file with mode: 0644]
kernel/irq/manage.c
kernel/kmod.c
kernel/lockdep.c
kernel/power/Kconfig
kernel/printk.c
kernel/resource.c
kernel/sys.c
kernel/sysctl_binary.c
kernel/sysctl_check.c
kernel/taskstats.c
kernel/trace/Kconfig
kernel/trace/blktrace.c
lib/Kconfig
lib/Makefile
lib/bitmap.c
lib/fault-inject.c
lib/genalloc.c
lib/idr.c
lib/llist.c [new file with mode: 0644]
lib/md5.c [new file with mode: 0644]
lib/radix-tree.c
lib/sha1.c
mm/failslab.c
mm/filemap.c
mm/highmem.c
mm/memcontrol.c
mm/memory-failure.c
mm/mincore.c
mm/oom_kill.c
mm/page_alloc.c
mm/shmem.c
mm/slab.c
mm/slub.c
mm/swapfile.c
mm/truncate.c
mm/vmalloc.c
net/8021q/vlan_core.c
net/atm/br2684.c
net/bridge/br_if.c
net/bridge/br_multicast.c
net/bridge/br_notify.c
net/bridge/netfilter/ebtables.c
net/can/af_can.c
net/core/Makefile
net/core/dev.c
net/core/flow.c
net/core/neighbour.c
net/core/netpoll.c
net/core/scm.c
net/core/secure_seq.c [new file with mode: 0644]
net/core/skbuff.c
net/dccp/ipv4.c
net/dccp/ipv6.c
net/ethernet/eth.c
net/ipv4/igmp.c
net/ipv4/inet_hashtables.c
net/ipv4/inetpeer.c
net/ipv4/ip_output.c
net/ipv4/ip_sockglue.c
net/ipv4/netfilter.c
net/ipv4/netfilter/nf_nat_proto_common.c
net/ipv4/proc.c
net/ipv4/raw.c
net/ipv4/route.c
net/ipv4/syncookies.c
net/ipv4/tcp_ipv4.c
net/ipv6/addrconf.c
net/ipv6/datagram.c
net/ipv6/inet6_hashtables.c
net/ipv6/ip6_fib.c
net/ipv6/ip6_output.c
net/ipv6/ipv6_sockglue.c
net/ipv6/mcast.c
net/ipv6/route.c
net/ipv6/sit.c
net/ipv6/syncookies.c
net/ipv6/tcp_ipv6.c
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/nf_queue.c
net/netlabel/Makefile
net/netlabel/netlabel_addrlist.c
net/netlabel/netlabel_addrlist.h
net/netlabel/netlabel_cipso_v4.c
net/netlabel/netlabel_cipso_v4.h
net/netlabel/netlabel_domainhash.c
net/netlabel/netlabel_domainhash.h
net/netlabel/netlabel_kapi.c
net/netlabel/netlabel_mgmt.c
net/netlabel/netlabel_mgmt.h
net/netlabel/netlabel_unlabeled.c
net/netlabel/netlabel_unlabeled.h
net/netlabel/netlabel_user.c
net/netlabel/netlabel_user.h
net/sched/act_mirred.c
net/sched/cls_rsvp.h
net/sched/sch_prio.c
net/sched/sch_sfq.c
net/socket.c
net/sunrpc/xprt.c
net/xfrm/xfrm_algo.c
scripts/kconfig/Makefile
scripts/kconfig/conf.c
scripts/kconfig/confdata.c
scripts/kconfig/expr.c
scripts/kconfig/expr.h
scripts/kconfig/gconf.c
scripts/kconfig/kconfig_load.c [deleted file]
scripts/kconfig/kxgettext.c
scripts/kconfig/lkc.h
scripts/kconfig/lkc_proto.h
scripts/kconfig/mconf.c
scripts/kconfig/menu.c
scripts/kconfig/nconf.c
scripts/kconfig/qconf.cc
scripts/kconfig/qconf.h
scripts/kconfig/symbol.c
scripts/kconfig/util.c
scripts/kconfig/zconf.l
scripts/kconfig/zconf.lex.c_shipped
scripts/kconfig/zconf.tab.c_shipped
scripts/kconfig/zconf.y
security/selinux/hooks.c
security/selinux/include/netif.h
security/selinux/include/netlabel.h
security/selinux/include/netnode.h
security/selinux/include/netport.h
security/selinux/netif.c
security/selinux/netlabel.c
security/selinux/netnode.c
security/selinux/netport.c
security/selinux/selinuxfs.c
security/selinux/ss/ebitmap.c
security/selinux/ss/mls.c
security/selinux/ss/mls.h
security/selinux/ss/policydb.c
security/selinux/ss/services.c
security/smack/smack_lsm.c
security/tomoyo/common.c
sound/aoa/fabrics/layout.c
sound/core/pcm_compat.c
sound/core/rtctimer.c
sound/core/timer.c
sound/i2c/other/tea575x-tuner.c
sound/oss/pas2_pcm.c
sound/oss/pss.c
sound/pci/Kconfig
sound/pci/ac97/ac97_patch.c
sound/pci/asihpi/hpicmn.c
sound/pci/asihpi/hpidspcd.c
sound/pci/asihpi/hpioctl.c
sound/pci/azt3328.c
sound/pci/hda/alc268_quirks.c
sound/pci/hda/alc269_quirks.c
sound/pci/hda/hda_eld.c
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/pci/rme9652/hdspm.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/wm8750.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8915.c [deleted file]
sound/soc/codecs/wm8915.h [deleted file]
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8996.c [new file with mode: 0644]
sound/soc/codecs/wm8996.h [new file with mode: 0644]
sound/soc/codecs/wm_hubs.c
sound/soc/omap/n810.c
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/omap-mcbsp.h
sound/soc/omap/omap-pcm.c
sound/soc/omap/omap-pcm.h
sound/soc/omap/rx51.c
sound/soc/samsung/Kconfig
sound/soc/samsung/Makefile
sound/soc/samsung/idma.c [new file with mode: 0644]
sound/soc/samsung/idma.h [new file with mode: 0644]
sound/soc/samsung/jive_wm8750.c
sound/soc/samsung/speyside.c
sound/soc/samsung/speyside_wm8962.c
sound/soc/tegra/tegra_pcm.c
sound/soc/tegra/tegra_wm8903.c
sound/soc/txx9/txx9aclc.c
sound/usb/caiaq/audio.c
sound/usb/caiaq/device.h
sound/usb/caiaq/input.c
sound/usb/endpoint.c
sound/usb/mixer.c
sound/usb/mixer.h
sound/usb/quirks-table.h
sound/usb/quirks.c
tools/perf/Makefile
tools/perf/builtin-lock.c
tools/perf/builtin-probe.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-sched.c
tools/perf/builtin-stat.c
tools/perf/util/config.c
tools/perf/util/dwarf-aux.c
tools/perf/util/dwarf-aux.h
tools/perf/util/evlist.c
tools/perf/util/evlist.h
tools/perf/util/header.c
tools/perf/util/include/linux/compiler.h
tools/perf/util/parse-events.c
tools/perf/util/probe-event.c
tools/perf/util/probe-finder.c
tools/perf/util/probe-finder.h
tools/perf/util/python.c
tools/perf/util/setup.py
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/ui/browsers/top.c
tools/power/cpupower/.gitignore [new file with mode: 0644]
tools/power/cpupower/Makefile [new file with mode: 0644]
tools/power/cpupower/README [new file with mode: 0644]
tools/power/cpupower/ToDo [new file with mode: 0644]
tools/power/cpupower/bench/Makefile [new file with mode: 0644]
tools/power/cpupower/bench/README-BENCH [new file with mode: 0644]
tools/power/cpupower/bench/benchmark.c [new file with mode: 0644]
tools/power/cpupower/bench/benchmark.h [new file with mode: 0644]
tools/power/cpupower/bench/config.h [new file with mode: 0644]
tools/power/cpupower/bench/cpufreq-bench_plot.sh [new file with mode: 0644]
tools/power/cpupower/bench/cpufreq-bench_script.sh [new file with mode: 0644]
tools/power/cpupower/bench/example.cfg [new file with mode: 0644]
tools/power/cpupower/bench/main.c [new file with mode: 0644]
tools/power/cpupower/bench/parse.c [new file with mode: 0644]
tools/power/cpupower/bench/parse.h [new file with mode: 0644]
tools/power/cpupower/bench/system.c [new file with mode: 0644]
tools/power/cpupower/bench/system.h [new file with mode: 0644]
tools/power/cpupower/debug/i386/Makefile [new file with mode: 0644]
tools/power/cpupower/debug/i386/centrino-decode.c [new file with mode: 0644]
tools/power/cpupower/debug/i386/dump_psb.c [new file with mode: 0644]
tools/power/cpupower/debug/i386/intel_gsic.c [new file with mode: 0644]
tools/power/cpupower/debug/i386/powernow-k8-decode.c [new file with mode: 0644]
tools/power/cpupower/debug/kernel/Makefile [new file with mode: 0644]
tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c [new file with mode: 0644]
tools/power/cpupower/debug/x86_64/Makefile [new file with mode: 0644]
tools/power/cpupower/debug/x86_64/centrino-decode.c [new symlink]
tools/power/cpupower/debug/x86_64/powernow-k8-decode.c [new symlink]
tools/power/cpupower/lib/cpufreq.c [new file with mode: 0644]
tools/power/cpupower/lib/cpufreq.h [new file with mode: 0644]
tools/power/cpupower/lib/sysfs.c [new file with mode: 0644]
tools/power/cpupower/lib/sysfs.h [new file with mode: 0644]
tools/power/cpupower/man/cpupower-frequency-info.1 [new file with mode: 0644]
tools/power/cpupower/man/cpupower-frequency-set.1 [new file with mode: 0644]
tools/power/cpupower/man/cpupower-info.1 [new file with mode: 0644]
tools/power/cpupower/man/cpupower-monitor.1 [new file with mode: 0644]
tools/power/cpupower/man/cpupower-set.1 [new file with mode: 0644]
tools/power/cpupower/man/cpupower.1 [new file with mode: 0644]
tools/power/cpupower/po/cs.po [new file with mode: 0644]
tools/power/cpupower/po/de.po [new file with mode: 0644]
tools/power/cpupower/po/fr.po [new file with mode: 0644]
tools/power/cpupower/po/it.po [new file with mode: 0644]
tools/power/cpupower/po/pt.po [new file with mode: 0644]
tools/power/cpupower/utils/builtin.h [new file with mode: 0644]
tools/power/cpupower/utils/cpufreq-info.c [new file with mode: 0644]
tools/power/cpupower/utils/cpufreq-set.c [new file with mode: 0644]
tools/power/cpupower/utils/cpuidle-info.c [new file with mode: 0644]
tools/power/cpupower/utils/cpupower-info.c [new file with mode: 0644]
tools/power/cpupower/utils/cpupower-set.c [new file with mode: 0644]
tools/power/cpupower/utils/cpupower.c [new file with mode: 0644]
tools/power/cpupower/utils/helpers/amd.c [new file with mode: 0644]
tools/power/cpupower/utils/helpers/bitmask.c [new file with mode: 0644]
tools/power/cpupower/utils/helpers/bitmask.h [new file with mode: 0644]
tools/power/cpupower/utils/helpers/cpuid.c [new file with mode: 0644]
tools/power/cpupower/utils/helpers/helpers.h [new file with mode: 0644]
tools/power/cpupower/utils/helpers/misc.c [new file with mode: 0644]
tools/power/cpupower/utils/helpers/msr.c [new file with mode: 0644]
tools/power/cpupower/utils/helpers/pci.c [new file with mode: 0644]
tools/power/cpupower/utils/helpers/sysfs.c [new file with mode: 0644]
tools/power/cpupower/utils/helpers/sysfs.h [new file with mode: 0644]
tools/power/cpupower/utils/helpers/topology.c [new file with mode: 0644]
tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c [new file with mode: 0644]
tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c [new file with mode: 0644]
tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c [new file with mode: 0644]
tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h [new file with mode: 0644]
tools/power/cpupower/utils/idle_monitor/idle_monitors.def [new file with mode: 0644]
tools/power/cpupower/utils/idle_monitor/idle_monitors.h [new file with mode: 0644]
tools/power/cpupower/utils/idle_monitor/mperf_monitor.c [new file with mode: 0644]
tools/power/cpupower/utils/idle_monitor/nhm_idle.c [new file with mode: 0644]
tools/power/cpupower/utils/idle_monitor/snb_idle.c [new file with mode: 0644]
tools/power/cpupower/utils/version-gen.sh [new file with mode: 0755]
tools/power/x86/turbostat/turbostat.c
tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c
tools/slub/slabinfo.c

diff --git a/CREDITS b/CREDITS
index 1deb331..07e32a8 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -504,7 +504,7 @@ N: Dominik Brodowski
 E: linux@brodo.de
 W: http://www.brodo.de/
 P: 1024D/725B37C6  190F 3E77 9C89 3B6D BECD  46EE 67C3 0308 725B 37C6
-D: parts of CPUFreq code, ACPI bugfixes
+D: parts of CPUFreq code, ACPI bugfixes, PCMCIA rewrite, cpufrequtils
 S: Tuebingen, Germany
 
 N: Andries Brouwer
@@ -857,6 +857,10 @@ S: One Dell Way
 S: Round Rock, TX  78682
 S: USA
 
+N: Mattia Dongili
+E: malattia@gmail.com
+D: cpufrequtils (precursor to cpupowerutils)
+
 N: Ben Dooks
 E: ben-linux@fluff.org
 E: ben@simtec.co.uk
@@ -1883,6 +1887,11 @@ S: Kruislaan 419
 S: 1098 VA Amsterdam 
 S: The Netherlands
 
+N: Goran Koruga
+E: korugag@siol.net
+D: cpufrequtils (precursor to cpupowerutils)
+S: Slovenia
+
 N: Jiri Kosina
 E: jikos@jikos.cz
 E: jkosina@suse.cz
@@ -2916,6 +2925,12 @@ S: Schlossbergring 9
 S: 79098 Freiburg
 S: Germany
 
+N: Thomas Renninger
+E: trenn@suse.de
+D: cpupowerutils
+S: SUSE Linux GmbH
+S: Germany
+
 N: Joerg Reuter
 E: jreuter@yaina.de
 W: http://yaina.de/jreuter/
index 1f89424..65bbd26 100644 (file)
@@ -272,6 +272,8 @@ printk-formats.txt
        - how to get printk format specifiers right
 prio_tree.txt
        - info on radix-priority-search-tree use for indexing vmas.
+ramoops.txt
+       - documentation of the ramoops oops/panic logging module.
 rbtree.txt
        - info on what red-black trees are and what they are for.
 robust-futex-ABI.txt
index ddf451e..ff1df4e 100644 (file)
@@ -39,3 +39,9 @@ Description:  Generic interface to platform dependent persistent storage.
                multiple) files based on the record size of the underlying
                persistent storage until at least this amount is reached.
                Default is 10 Kbytes.
+
+               Pstore only supports one backend at a time. If multiple
+               backends are available, the preferred backend may be
+               set by passing the pstore.backend= argument to the kernel at
+               boot time.
+
index 807fca2..ff53183 100644 (file)
@@ -4,3 +4,20 @@ KernelVersion: 2.6.37
 Contact:       "Ike Panhc <ike.pan@canonical.com>"
 Description:
                Control the power of camera module. 1 means on, 0 means off.
+
+What:          /sys/devices/platform/ideapad/cfg
+Date:          Jun 2011
+KernelVersion: 3.1
+Contact:       "Ike Panhc <ike.pan@canonical.com>"
+Description:
+               Ideapad capability bits.
+               Bit 8-10: 1 - Intel graphic only
+                         2 - ATI graphic only
+                         3 - Nvidia graphic only
+                         4 - Intel and ATI graphic
+                         5 - Intel and Nvidia graphic
+               Bit 16: Bluetooth exist (1 for exist)
+               Bit 17: 3G exist (1 for exist)
+               Bit 18: Wifi exist (1 for exist)
+               Bit 19: Camera exist (1 for exist)
+
index fa6e25b..c940239 100644 (file)
@@ -80,22 +80,13 @@ available tools.
 The limit on the length of lines is 80 columns and this is a strongly
 preferred limit.
 
-Statements longer than 80 columns will be broken into sensible chunks.
-Descendants are always substantially shorter than the parent and are placed
-substantially to the right. The same applies to function headers with a long
-argument list. Long strings are as well broken into shorter strings. The
-only exception to this is where exceeding 80 columns significantly increases
-readability and does not hide information.
-
-void fun(int a, int b, int c)
-{
-       if (condition)
-               printk(KERN_WARNING "Warning this is a long printk with "
-                                               "3 parameters a: %u b: %u "
-                                               "c: %u \n", a, b, c);
-       else
-               next_statement;
-}
+Statements longer than 80 columns will be broken into sensible chunks, unless
+exceeding 80 columns significantly increases readability and does not hide
+information. Descendants are always substantially shorter than the parent and
+are placed substantially to the right. The same applies to function headers
+with a long argument list. However, never break user-visible strings such as
+printk messages, because that breaks the ability to grep for them.
+
 
                Chapter 3: Placing Braces and Spaces
 
index 679034c..720f245 100644 (file)
@@ -8,4 +8,7 @@
 *.dvi
 *.log
 *.out
-media/
+*.png
+*.gif
+media-indices.tmpl
+media-entities.tmpl
index 3cebfa0..66725a3 100644 (file)
@@ -14,7 +14,9 @@ DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \
            genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
            80211.xml debugobjects.xml sh.xml regulator.xml \
            alsa-driver-api.xml writing-an-alsa-driver.xml \
-           tracepoint.xml media.xml drm.xml
+           tracepoint.xml drm.xml media_api.xml
+
+include $(srctree)/Documentation/DocBook/media/Makefile
 
 ###
 # The build process is as follows (targets):
@@ -32,7 +34,7 @@ PS_METHOD     = $(prefer-db2x)
 
 ###
 # The targets that may be used.
-PHONY += xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs cleandocs xmldoclinks
+PHONY += xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs cleandocs
 
 BOOKS := $(addprefix $(obj)/,$(DOCBOOKS))
 xmldocs: $(BOOKS)
@@ -45,27 +47,14 @@ PDF := $(patsubst %.xml, %.pdf, $(BOOKS))
 pdfdocs: $(PDF)
 
 HTML := $(sort $(patsubst %.xml, %.html, $(BOOKS)))
-htmldocs: $(HTML) xmldoclinks
+htmldocs: $(HTML)
        $(call build_main_index)
        $(call build_images)
+       $(call install_media_images)
 
 MAN := $(patsubst %.xml, %.9, $(BOOKS))
 mandocs: $(MAN)
 
-build_images = mkdir -p $(objtree)/Documentation/DocBook/media/ && \
-              cp $(srctree)/Documentation/DocBook/dvb/*.png \
-                 $(srctree)/Documentation/DocBook/v4l/*.gif \
-                 $(objtree)/Documentation/DocBook/media/
-
-xmldoclinks:
-ifneq ($(objtree),$(srctree))
-       for dep in dvb media-entities.tmpl media-indices.tmpl v4l; do \
-               rm -f $(objtree)/Documentation/DocBook/$$dep \
-               && ln -s $(srctree)/Documentation/DocBook/$$dep $(objtree)/Documentation/DocBook/ \
-               || exit; \
-       done
-endif
-
 installmandocs: mandocs
        mkdir -p /usr/local/man/man9/
        install Documentation/DocBook/man/*.9.gz /usr/local/man/man9/
@@ -97,11 +86,11 @@ define rule_docproc
         ) > $(dir $@).$(notdir $@).cmd
 endef
 
-%.xml: %.tmpl xmldoclinks FORCE
+%.xml: %.tmpl FORCE
        $(call if_changed_rule,docproc)
 
 ###
-#Read in all saved dependency files 
+#Read in all saved dependency files
 cmd_files := $(wildcard $(foreach f,$(BOOKS),$(dir $(f)).$(notdir $(f)).cmd))
 
 ifneq ($(cmd_files),)
@@ -150,7 +139,7 @@ quiet_cmd_db2pdf = PDF     $@
 
 index = index.html
 main_idx = Documentation/DocBook/$(index)
-build_main_index = rm -rf $(main_idx) && \
+build_main_index = rm -rf $(main_idx); \
                   echo '<h1>Linux Kernel HTML Documentation</h1>' >> $(main_idx) && \
                   echo '<h2>Kernel Version: $(KERNELVERSION)</h2>' >> $(main_idx) && \
                   cat $(HTML) >> $(main_idx)
@@ -242,7 +231,7 @@ clean-files := $(DOCBOOKS) \
 
 clean-dirs := $(patsubst %.xml,%,$(DOCBOOKS)) man
 
-cleandocs:
+cleandocs: cleanmediadocs
        $(Q)rm -f $(call objectify, $(clean-files))
        $(Q)rm -rf $(call objectify, $(clean-dirs))
 
diff --git a/Documentation/DocBook/dvb/dvbproperty.xml b/Documentation/DocBook/dvb/dvbproperty.xml
deleted file mode 100644 (file)
index b5365f6..0000000
+++ /dev/null
@@ -1,590 +0,0 @@
-<section id="FE_GET_SET_PROPERTY">
-<title>FE_GET_PROPERTY/FE_SET_PROPERTY</title>
-
-<programlisting>
-/* Reserved fields should be set to 0 */
-struct dtv_property {
-       __u32 cmd;
-       union {
-               __u32 data;
-               struct {
-                       __u8 data[32];
-                       __u32 len;
-                       __u32 reserved1[3];
-                       void *reserved2;
-               } buffer;
-       } u;
-       int result;
-} __attribute__ ((packed));
-
-/* num of properties cannot exceed DTV_IOCTL_MAX_MSGS per ioctl */
-#define DTV_IOCTL_MAX_MSGS 64
-
-struct dtv_properties {
-       __u32 num;
-       struct dtv_property *props;
-};
-</programlisting>
-
-<section id="FE_GET_PROPERTY">
-<title>FE_GET_PROPERTY</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns one or more frontend properties. This call only
- requires read-only access to the device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link>,
- dtv_properties &#x22C6;props);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int num</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct dtv_property *props</para>
-</entry><entry
- align="char">
-<para>Points to the location where the front-end property commands are stored.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS</para>
-<informaltable><tgroup cols="2"><tbody><row>
-  <entry align="char"><para>EINVAL</para></entry>
-  <entry align="char"><para>Invalid parameter(s) received or number of parameters out of the range.</para></entry>
- </row><row>
-  <entry align="char"><para>ENOMEM</para></entry>
-  <entry align="char"><para>Out of memory.</para></entry>
- </row><row>
-  <entry align="char"><para>EFAULT</para></entry>
-  <entry align="char"><para>Failure while copying data from/to userspace.</para></entry>
- </row><row>
-  <entry align="char"><para>EOPNOTSUPP</para></entry>
-  <entry align="char"><para>Property type not supported.</para></entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="FE_SET_PROPERTY">
-<title>FE_SET_PROPERTY</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call sets one or more frontend properties. This call only
- requires read-only access to the device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = <link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link>,
- dtv_properties &#x22C6;props);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int num</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct dtv_property *props</para>
-</entry><entry
- align="char">
-<para>Points to the location where the front-end property commands are stored.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row>
-  <entry align="char"><para>EINVAL</para></entry>
-  <entry align="char"><para>Invalid parameter(s) received or number of parameters out of the range.</para></entry>
- </row><row>
-  <entry align="char"><para>ENOMEM</para></entry>
-  <entry align="char"><para>Out of memory.</para></entry>
- </row><row>
-  <entry align="char"><para>EFAULT</para></entry>
-  <entry align="char"><para>Failure while copying data from/to userspace.</para></entry>
- </row><row>
-  <entry align="char"><para>EOPNOTSUPP</para></entry>
-  <entry align="char"><para>Property type not supported.</para></entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section>
-       <title>Property types</title>
-<para>
-On <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link>/<link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link>,
-the actual action is determined by the dtv_property cmd/data pairs. With one single ioctl, is possible to
-get/set up to 64 properties. The actual meaning of each property is described on the next sections.
-</para>
-
-<para>The available frontend property types are:</para>
-<programlisting>
-#define DTV_UNDEFINED          0
-#define DTV_TUNE               1
-#define DTV_CLEAR              2
-#define DTV_FREQUENCY          3
-#define DTV_MODULATION         4
-#define DTV_BANDWIDTH_HZ       5
-#define DTV_INVERSION          6
-#define DTV_DISEQC_MASTER      7
-#define DTV_SYMBOL_RATE                8
-#define DTV_INNER_FEC          9
-#define DTV_VOLTAGE            10
-#define DTV_TONE               11
-#define DTV_PILOT              12
-#define DTV_ROLLOFF            13
-#define DTV_DISEQC_SLAVE_REPLY 14
-#define DTV_FE_CAPABILITY_COUNT        15
-#define DTV_FE_CAPABILITY      16
-#define DTV_DELIVERY_SYSTEM    17
-#define DTV_ISDBT_PARTIAL_RECEPTION    18
-#define DTV_ISDBT_SOUND_BROADCASTING   19
-#define DTV_ISDBT_SB_SUBCHANNEL_ID     20
-#define DTV_ISDBT_SB_SEGMENT_IDX       21
-#define DTV_ISDBT_SB_SEGMENT_COUNT     22
-#define DTV_ISDBT_LAYERA_FEC                   23
-#define DTV_ISDBT_LAYERA_MODULATION            24
-#define DTV_ISDBT_LAYERA_SEGMENT_COUNT         25
-#define DTV_ISDBT_LAYERA_TIME_INTERLEAVING     26
-#define DTV_ISDBT_LAYERB_FEC                   27
-#define DTV_ISDBT_LAYERB_MODULATION            28
-#define DTV_ISDBT_LAYERB_SEGMENT_COUNT         29
-#define DTV_ISDBT_LAYERB_TIME_INTERLEAVING     30
-#define DTV_ISDBT_LAYERC_FEC                   31
-#define DTV_ISDBT_LAYERC_MODULATION            32
-#define DTV_ISDBT_LAYERC_SEGMENT_COUNT         33
-#define DTV_ISDBT_LAYERC_TIME_INTERLEAVING     34
-#define DTV_API_VERSION                35
-#define DTV_CODE_RATE_HP       36
-#define DTV_CODE_RATE_LP       37
-#define DTV_GUARD_INTERVAL     38
-#define DTV_TRANSMISSION_MODE  39
-#define DTV_HIERARCHY          40
-#define DTV_ISDBT_LAYER_ENABLED        41
-#define DTV_ISDBS_TS_ID                42
-</programlisting>
-</section>
-
-<section id="fe_property_common">
-       <title>Parameters that are common to all Digital TV standards</title>
-       <section id="DTV_FREQUENCY">
-               <title><constant>DTV_FREQUENCY</constant></title>
-
-               <para>Central frequency of the channel, in HZ.</para>
-
-               <para>Notes:</para>
-               <para>1)For ISDB-T, the channels are usually transmitted with an offset of 143kHz.
-                       E.g. a valid frequncy could be 474143 kHz. The stepping is bound to the bandwidth of
-                       the channel which is 6MHz.</para>
-
-               <para>2)As in ISDB-Tsb the channel consists of only one or three segments the
-                       frequency step is 429kHz, 3*429 respectively. As for ISDB-T the
-                       central frequency of the channel is expected.</para>
-       </section>
-
-       <section id="DTV_BANDWIDTH_HZ">
-               <title><constant>DTV_BANDWIDTH_HZ</constant></title>
-
-               <para>Bandwidth for the channel, in HZ.</para>
-
-               <para>Possible values:
-                       <constant>1712000</constant>,
-                       <constant>5000000</constant>,
-                       <constant>6000000</constant>,
-                       <constant>7000000</constant>,
-                       <constant>8000000</constant>,
-                       <constant>10000000</constant>.
-               </para>
-
-               <para>Notes:</para>
-
-               <para>1) For ISDB-T it should be always 6000000Hz (6MHz)</para>
-               <para>2) For ISDB-Tsb it can vary depending on the number of connected segments</para>
-               <para>3) Bandwidth doesn't apply for DVB-C transmissions, as the bandwidth
-                        for DVB-C depends on the symbol rate</para>
-               <para>4) Bandwidth in ISDB-T is fixed (6MHz) or can be easily derived from
-                       other parameters (DTV_ISDBT_SB_SEGMENT_IDX,
-                       DTV_ISDBT_SB_SEGMENT_COUNT).</para>
-               <para>5) DVB-T supports 6, 7 and 8MHz.</para>
-               <para>6) In addition, DVB-T2 supports 1.172, 5 and 10MHz.</para>
-       </section>
-
-       <section id="DTV_DELIVERY_SYSTEM">
-               <title><constant>DTV_DELIVERY_SYSTEM</constant></title>
-
-               <para>Specifies the type of Delivery system</para>
-
-               <para>Possible values: </para>
-<programlisting>
-typedef enum fe_delivery_system {
-       SYS_UNDEFINED,
-       SYS_DVBC_ANNEX_AC,
-       SYS_DVBC_ANNEX_B,
-       SYS_DVBT,
-       SYS_DSS,
-       SYS_DVBS,
-       SYS_DVBS2,
-       SYS_DVBH,
-       SYS_ISDBT,
-       SYS_ISDBS,
-       SYS_ISDBC,
-       SYS_ATSC,
-       SYS_ATSCMH,
-       SYS_DMBTH,
-       SYS_CMMB,
-       SYS_DAB,
-       SYS_DVBT2,
-} fe_delivery_system_t;
-</programlisting>
-
-       </section>
-
-       <section id="DTV_TRANSMISSION_MODE">
-               <title><constant>DTV_TRANSMISSION_MODE</constant></title>
-
-               <para>Specifies the number of carriers used by the standard</para>
-
-               <para>Possible values are:</para>
-<programlisting>
-typedef enum fe_transmit_mode {
-       TRANSMISSION_MODE_2K,
-       TRANSMISSION_MODE_8K,
-       TRANSMISSION_MODE_AUTO,
-       TRANSMISSION_MODE_4K,
-       TRANSMISSION_MODE_1K,
-       TRANSMISSION_MODE_16K,
-       TRANSMISSION_MODE_32K,
-} fe_transmit_mode_t;
-</programlisting>
-
-               <para>Notes:</para>
-               <para>1) ISDB-T supports three carrier/symbol-size: 8K, 4K, 2K. It is called
-                       'mode' in the standard: Mode 1 is 2K, mode 2 is 4K, mode 3 is 8K</para>
-
-               <para>2) If <constant>DTV_TRANSMISSION_MODE</constant> is set the <constant>TRANSMISSION_MODE_AUTO</constant> the
-                       hardware will try to find the correct FFT-size (if capable) and will
-                       use TMCC to fill in the missing parameters.</para>
-               <para>3) DVB-T specifies 2K and 8K as valid sizes.</para>
-               <para>4) DVB-T2 specifies 1K, 2K, 4K, 8K, 16K and 32K.</para>
-       </section>
-
-       <section id="DTV_GUARD_INTERVAL">
-               <title><constant>DTV_GUARD_INTERVAL</constant></title>
-
-               <para>Possible values are:</para>
-<programlisting>
-typedef enum fe_guard_interval {
-       GUARD_INTERVAL_1_32,
-       GUARD_INTERVAL_1_16,
-       GUARD_INTERVAL_1_8,
-       GUARD_INTERVAL_1_4,
-       GUARD_INTERVAL_AUTO,
-       GUARD_INTERVAL_1_128,
-       GUARD_INTERVAL_19_128,
-       GUARD_INTERVAL_19_256,
-} fe_guard_interval_t;
-</programlisting>
-
-               <para>Notes:</para>
-               <para>1) If <constant>DTV_GUARD_INTERVAL</constant> is set the <constant>GUARD_INTERVAL_AUTO</constant> the hardware will
-                       try to find the correct guard interval (if capable) and will use TMCC to fill
-                       in the missing parameters.</para>
-               <para>2) Intervals 1/128, 19/128 and 19/256 are used only for DVB-T2 at present</para>
-       </section>
-</section>
-
-<section id="isdbt">
-       <title>ISDB-T frontend</title>
-       <para>This section describes shortly what are the possible parameters in the Linux
-               DVB-API called "S2API" and now DVB API 5 in order to tune an ISDB-T/ISDB-Tsb
-               demodulator:</para>
-
-       <para>This ISDB-T/ISDB-Tsb API extension should reflect all information
-               needed to tune any ISDB-T/ISDB-Tsb hardware. Of course it is possible
-               that some very sophisticated devices won't need certain parameters to
-               tune.</para>
-
-       <para>The information given here should help application writers to know how
-               to handle ISDB-T and ISDB-Tsb hardware using the Linux DVB-API.</para>
-
-       <para>The details given here about ISDB-T and ISDB-Tsb are just enough to
-               basically show the dependencies between the needed parameter values,
-               but surely some information is left out. For more detailed information
-               see the following documents:</para>
-
-       <para>ARIB STD-B31 - "Transmission System for Digital Terrestrial
-               Television Broadcasting" and</para>
-       <para>ARIB TR-B14 - "Operational Guidelines for Digital Terrestrial
-               Television Broadcasting".</para>
-
-       <para>In order to read this document one has to have some knowledge the
-               channel structure in ISDB-T and ISDB-Tsb. I.e. it has to be known to
-               the reader that an ISDB-T channel consists of 13 segments, that it can
-               have up to 3 layer sharing those segments, and things like that.</para>
-
-       <para>Parameters used by ISDB-T and ISDB-Tsb.</para>
-
-       <section id="isdbt-new-parms">
-               <title>ISDB-T only parameters</title>
-
-               <section id="isdbt-part-rec">
-                       <title><constant>DTV_ISDBT_PARTIAL_RECEPTION</constant></title>
-
-                       <para><constant>If DTV_ISDBT_SOUND_BROADCASTING</constant> is '0' this bit-field represents whether
-                               the channel is in partial reception mode or not.</para>
-
-                       <para>If '1' <constant>DTV_ISDBT_LAYERA_*</constant> values are assigned to the center segment and
-                               <constant>DTV_ISDBT_LAYERA_SEGMENT_COUNT</constant> has to be '1'.</para>
-
-                       <para>If in addition <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> is '1'
-                               <constant>DTV_ISDBT_PARTIAL_RECEPTION</constant> represents whether this ISDB-Tsb channel
-                               is consisting of one segment and layer or three segments and two layers.</para>
-
-                       <para>Possible values: 0, 1, -1 (AUTO)</para>
-               </section>
-
-               <section id="isdbt-sound-bcast">
-                       <title><constant>DTV_ISDBT_SOUND_BROADCASTING</constant></title>
-
-                       <para>This field represents whether the other DTV_ISDBT_*-parameters are
-                               referring to an ISDB-T and an ISDB-Tsb channel. (See also
-                               <constant>DTV_ISDBT_PARTIAL_RECEPTION</constant>).</para>
-
-                       <para>Possible values: 0, 1, -1 (AUTO)</para>
-               </section>
-
-               <section id="isdbt-sb-ch-id">
-                       <title><constant>DTV_ISDBT_SB_SUBCHANNEL_ID</constant></title>
-
-                       <para>This field only applies if <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> is '1'.</para>
-
-                       <para>(Note of the author: This might not be the correct description of the
-                               <constant>SUBCHANNEL-ID</constant> in all details, but it is my understanding of the technical
-                               background needed to program a device)</para>
-
-                       <para>An ISDB-Tsb channel (1 or 3 segments) can be broadcasted alone or in a
-                               set of connected ISDB-Tsb channels. In this set of channels every
-                               channel can be received independently. The number of connected
-                               ISDB-Tsb segment can vary, e.g. depending on the frequency spectrum
-                               bandwidth available.</para>
-
-                       <para>Example: Assume 8 ISDB-Tsb connected segments are broadcasted. The
-                               broadcaster has several possibilities to put those channels in the
-                               air: Assuming a normal 13-segment ISDB-T spectrum he can align the 8
-                               segments from position 1-8 to 5-13 or anything in between.</para>
-
-                       <para>The underlying layer of segments are subchannels: each segment is
-                               consisting of several subchannels with a predefined IDs. A sub-channel
-                               is used to help the demodulator to synchronize on the channel.</para>
-
-                       <para>An ISDB-T channel is always centered over all sub-channels. As for
-                               the example above, in ISDB-Tsb it is no longer as simple as that.</para>
-
-                       <para><constant>The DTV_ISDBT_SB_SUBCHANNEL_ID</constant> parameter is used to give the
-                               sub-channel ID of the segment to be demodulated.</para>
-
-                       <para>Possible values: 0 .. 41, -1 (AUTO)</para>
-               </section>
-
-               <section id="isdbt-sb-seg-idx">
-
-                       <title><constant>DTV_ISDBT_SB_SEGMENT_IDX</constant></title>
-
-                       <para>This field only applies if <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> is '1'.</para>
-
-                       <para><constant>DTV_ISDBT_SB_SEGMENT_IDX</constant> gives the index of the segment to be
-                               demodulated for an ISDB-Tsb channel where several of them are
-                               transmitted in the connected manner.</para>
-
-                       <para>Possible values: 0 .. <constant>DTV_ISDBT_SB_SEGMENT_COUNT</constant> - 1</para>
-
-                       <para>Note: This value cannot be determined by an automatic channel search.</para>
-               </section>
-
-               <section id="isdbt-sb-seg-cnt">
-                       <title><constant>DTV_ISDBT_SB_SEGMENT_COUNT</constant></title>
-
-                       <para>This field only applies if <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> is '1'.</para>
-
-                       <para><constant>DTV_ISDBT_SB_SEGMENT_COUNT</constant> gives the total count of connected ISDB-Tsb
-                               channels.</para>
-
-                       <para>Possible values: 1 .. 13</para>
-
-                       <para>Note: This value cannot be determined by an automatic channel search.</para>
-               </section>
-
-               <section id="isdb-hierq-layers">
-                       <title>Hierarchical layers</title>
-
-                       <para>ISDB-T channels can be coded hierarchically. As opposed to DVB-T in
-                               ISDB-T hierarchical layers can be decoded simultaneously. For that
-                               reason a ISDB-T demodulator has 3 viterbi and 3 reed-solomon-decoders.</para>
-
-                       <para>ISDB-T has 3 hierarchical layers which each can use a part of the
-                               available segments. The total number of segments over all layers has
-                               to 13 in ISDB-T.</para>
-
-                       <section id="isdbt-layer-ena">
-                               <title><constant>DTV_ISDBT_LAYER_ENABLED</constant></title>
-
-                               <para>Hierarchical reception in ISDB-T is achieved by enabling or disabling
-                                       layers in the decoding process. Setting all bits of
-                                       <constant>DTV_ISDBT_LAYER_ENABLED</constant> to '1' forces all layers (if applicable) to be
-                                       demodulated. This is the default.</para>
-
-                               <para>If the channel is in the partial reception mode
-                                       (<constant>DTV_ISDBT_PARTIAL_RECEPTION</constant> = 1) the central segment can be decoded
-                                       independently of the other 12 segments. In that mode layer A has to
-                                       have a <constant>SEGMENT_COUNT</constant> of 1.</para>
-
-                               <para>In ISDB-Tsb only layer A is used, it can be 1 or 3 in ISDB-Tsb
-                                       according to <constant>DTV_ISDBT_PARTIAL_RECEPTION</constant>. <constant>SEGMENT_COUNT</constant> must be filled
-                                       accordingly.</para>
-
-                               <para>Possible values: 0x1, 0x2, 0x4 (|-able)</para>
-
-                               <para><constant>DTV_ISDBT_LAYER_ENABLED[0:0]</constant> - layer A</para>
-                               <para><constant>DTV_ISDBT_LAYER_ENABLED[1:1]</constant> - layer B</para>
-                               <para><constant>DTV_ISDBT_LAYER_ENABLED[2:2]</constant> - layer C</para>
-                               <para><constant>DTV_ISDBT_LAYER_ENABLED[31:3]</constant> unused</para>
-                       </section>
-
-                       <section id="isdbt-layer-fec">
-                               <title><constant>DTV_ISDBT_LAYER*_FEC</constant></title>
-
-                               <para>Possible values: <constant>FEC_AUTO</constant>, <constant>FEC_1_2</constant>, <constant>FEC_2_3</constant>, <constant>FEC_3_4</constant>, <constant>FEC_5_6</constant>, <constant>FEC_7_8</constant></para>
-                       </section>
-
-                       <section id="isdbt-layer-mod">
-                               <title><constant>DTV_ISDBT_LAYER*_MODULATION</constant></title>
-
-                               <para>Possible values: <constant>QAM_AUTO</constant>, QP<constant>SK, QAM_16</constant>, <constant>QAM_64</constant>, <constant>DQPSK</constant></para>
-
-                               <para>Note: If layer C is <constant>DQPSK</constant> layer B has to be <constant>DQPSK</constant>. If layer B is <constant>DQPSK</constant>
-                                       and <constant>DTV_ISDBT_PARTIAL_RECEPTION</constant>=0 layer has to be <constant>DQPSK</constant>.</para>
-                       </section>
-
-                       <section id="isdbt-layer-seg-cnt">
-                               <title><constant>DTV_ISDBT_LAYER*_SEGMENT_COUNT</constant></title>
-
-                               <para>Possible values: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, -1 (AUTO)</para>
-
-                               <para>Note: Truth table for <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> and
-                                       <constant>DTV_ISDBT_PARTIAL_RECEPTION</constant> and <constant>LAYER</constant>*_SEGMENT_COUNT</para>
-
-                               <informaltable id="isdbt-layer_seg-cnt-table">
-                                       <tgroup cols="6">
-
-                                               <tbody>
-                                                       <row>
-                                                               <entry>PR</entry>
-                                                               <entry>SB</entry>
-                                                               <entry>Layer A width</entry>
-                                                               <entry>Layer B width</entry>
-                                                               <entry>Layer C width</entry>
-                                                               <entry>total width</entry>
-                                                       </row>
-
-                                                       <row>
-                                                               <entry>0</entry>
-                                                               <entry>0</entry>
-                                                               <entry>1 .. 13</entry>
-                                                               <entry>1 .. 13</entry>
-                                                               <entry>1 .. 13</entry>
-                                                               <entry>13</entry>
-                                                       </row>
-
-                                                       <row>
-                                                               <entry>1</entry>
-                                                               <entry>0</entry>
-                                                               <entry>1</entry>
-                                                               <entry>1 .. 13</entry>
-                                                               <entry>1 .. 13</entry>
-                                                               <entry>13</entry>
-                                                       </row>
-
-                                                       <row>
-                                                               <entry>0</entry>
-                                                               <entry>1</entry>
-                                                               <entry>1</entry>
-                                                               <entry>0</entry>
-                                                               <entry>0</entry>
-                                                               <entry>1</entry>
-                                                       </row>
-
-                                                       <row>
-                                                               <entry>1</entry>
-                                                               <entry>1</entry>
-                                                               <entry>1</entry>
-                                                               <entry>2</entry>
-                                                               <entry>0</entry>
-                                                               <entry>13</entry>
-                                                       </row>
-                                               </tbody>
-
-                                       </tgroup>
-                               </informaltable>
-
-                       </section>
-
-                       <section id="isdbt_layer_t_interl">
-                               <title><constant>DTV_ISDBT_LAYER*_TIME_INTERLEAVING</constant></title>
-
-                               <para>Possible values: 0, 1, 2, 3, -1 (AUTO)</para>
-
-                               <para>Note: The real inter-leaver depth-names depend on the mode (fft-size); the values
-                                       here are referring to what can be found in the TMCC-structure -
-                                       independent of the mode.</para>
-                       </section>
-               </section>
-       </section>
-       <section id="dvbt2-params">
-               <title>DVB-T2 parameters</title>
-               
-               <para>This section covers parameters that apply only to the DVB-T2 delivery method. DVB-T2
-                       support is currently in the early stages development so expect this section to grow
-                       and become more detailed with time.</para>
-
-               <section id="dvbt2-plp-id">
-                       <title><constant>DTV_DVBT2_PLP_ID</constant></title>
-
-                       <para>DVB-T2 supports Physical Layer Pipes (PLP) to allow transmission of
-                               many data types via a single multiplex. The API will soon support this
-                               at which point this section will be expanded.</para>
-               </section>
-       </section>
-</section>
-</section>
diff --git a/Documentation/DocBook/dvb/dvbstb.png b/Documentation/DocBook/dvb/dvbstb.png
deleted file mode 100644 (file)
index 9b8f372..0000000
Binary files a/Documentation/DocBook/dvb/dvbstb.png and /dev/null differ
diff --git a/Documentation/DocBook/dvb/frontend.h.xml b/Documentation/DocBook/dvb/frontend.h.xml
deleted file mode 100644 (file)
index d792f78..0000000
+++ /dev/null
@@ -1,428 +0,0 @@
-<programlisting>
-/*
- * frontend.h
- *
- * Copyright (C) 2000 Marcus Metzler &lt;marcus@convergence.de&gt;
- *                  Ralph  Metzler &lt;ralph@convergence.de&gt;
- *                  Holger Waechtler &lt;holger@convergence.de&gt;
- *                  Andre Draszik &lt;ad@convergence.de&gt;
- *                  for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * 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 Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- *
- */
-
-#ifndef _DVBFRONTEND_H_
-#define _DVBFRONTEND_H_
-
-#include &lt;linux/types.h&gt;
-
-typedef enum fe_type {
-        FE_QPSK,
-        FE_QAM,
-        FE_OFDM,
-        FE_ATSC
-} fe_type_t;
-
-
-typedef enum fe_caps {
-        FE_IS_STUPID                    = 0,
-        FE_CAN_INVERSION_AUTO           = 0x1,
-        FE_CAN_FEC_1_2                  = 0x2,
-        FE_CAN_FEC_2_3                  = 0x4,
-        FE_CAN_FEC_3_4                  = 0x8,
-        FE_CAN_FEC_4_5                  = 0x10,
-        FE_CAN_FEC_5_6                  = 0x20,
-        FE_CAN_FEC_6_7                  = 0x40,
-        FE_CAN_FEC_7_8                  = 0x80,
-        FE_CAN_FEC_8_9                  = 0x100,
-        FE_CAN_FEC_AUTO                 = 0x200,
-        FE_CAN_QPSK                     = 0x400,
-        FE_CAN_QAM_16                   = 0x800,
-        FE_CAN_QAM_32                   = 0x1000,
-        FE_CAN_QAM_64                   = 0x2000,
-        FE_CAN_QAM_128                  = 0x4000,
-        FE_CAN_QAM_256                  = 0x8000,
-        FE_CAN_QAM_AUTO                 = 0x10000,
-        FE_CAN_TRANSMISSION_MODE_AUTO   = 0x20000,
-        FE_CAN_BANDWIDTH_AUTO           = 0x40000,
-        FE_CAN_GUARD_INTERVAL_AUTO      = 0x80000,
-        FE_CAN_HIERARCHY_AUTO           = 0x100000,
-        FE_CAN_8VSB                     = 0x200000,
-        FE_CAN_16VSB                    = 0x400000,
-        FE_HAS_EXTENDED_CAPS            = 0x800000,   /* We need more bitspace for newer APIs, indicate this. */
-        FE_CAN_TURBO_FEC                = 0x8000000,  /* frontend supports "turbo fec modulation" */
-        FE_CAN_2G_MODULATION            = 0x10000000, /* frontend supports "2nd generation modulation" (DVB-S2) */
-        FE_NEEDS_BENDING                = 0x20000000, /* not supported anymore, don't use (frontend requires frequency bending) */
-        FE_CAN_RECOVER                  = 0x40000000, /* frontend can recover from a cable unplug automatically */
-        FE_CAN_MUTE_TS                  = 0x80000000  /* frontend can stop spurious TS data output */
-} fe_caps_t;
-
-
-struct dvb_frontend_info {
-        char       name[128];
-        fe_type_t  type;
-        __u32      frequency_min;
-        __u32      frequency_max;
-        __u32      frequency_stepsize;
-        __u32      frequency_tolerance;
-        __u32      symbol_rate_min;
-        __u32      symbol_rate_max;
-        __u32      symbol_rate_tolerance;       /* ppm */
-        __u32      notifier_delay;              /* DEPRECATED */
-        fe_caps_t  caps;
-};
-
-
-/**
- *  Check out the DiSEqC bus spec available on http://www.eutelsat.org/ for
- *  the meaning of this struct...
- */
-struct dvb_diseqc_master_cmd {
-        __u8 msg [6];   /*  { framing, address, command, data [3] } */
-        __u8 msg_len;   /*  valid values are 3...6  */
-};
-
-
-struct dvb_diseqc_slave_reply {
-        __u8 msg [4];   /*  { framing, data [3] } */
-        __u8 msg_len;   /*  valid values are 0...4, 0 means no msg  */
-        int  timeout;   /*  return from ioctl after timeout ms with */
-};                      /*  errorcode when no message was received  */
-
-
-typedef enum fe_sec_voltage {
-        SEC_VOLTAGE_13,
-        SEC_VOLTAGE_18,
-        SEC_VOLTAGE_OFF
-} fe_sec_voltage_t;
-
-
-typedef enum fe_sec_tone_mode {
-        SEC_TONE_ON,
-        SEC_TONE_OFF
-} fe_sec_tone_mode_t;
-
-
-typedef enum fe_sec_mini_cmd {
-        SEC_MINI_A,
-        SEC_MINI_B
-} fe_sec_mini_cmd_t;
-
-
-typedef enum fe_status {
-        FE_HAS_SIGNAL   = 0x01,   /* found something above the noise level */
-        FE_HAS_CARRIER  = 0x02,   /* found a DVB signal  */
-        FE_HAS_VITERBI  = 0x04,   /* FEC is stable  */
-        FE_HAS_SYNC     = 0x08,   /* found sync bytes  */
-        FE_HAS_LOCK     = 0x10,   /* everything's working... */
-        FE_TIMEDOUT     = 0x20,   /* no lock within the last ~2 seconds */
-        FE_REINIT       = 0x40    /* frontend was reinitialized,  */
-} fe_status_t;                    /* application is recommended to reset */
-                                  /* DiSEqC, tone and parameters */
-
-typedef enum fe_spectral_inversion {
-        INVERSION_OFF,
-        INVERSION_ON,
-        INVERSION_AUTO
-} fe_spectral_inversion_t;
-
-
-typedef enum fe_code_rate {
-        FEC_NONE = 0,
-        FEC_1_2,
-        FEC_2_3,
-        FEC_3_4,
-        FEC_4_5,
-        FEC_5_6,
-        FEC_6_7,
-        FEC_7_8,
-        FEC_8_9,
-        FEC_AUTO,
-        FEC_3_5,
-        FEC_9_10,
-} fe_code_rate_t;
-
-
-typedef enum fe_modulation {
-        QPSK,
-        QAM_16,
-        QAM_32,
-        QAM_64,
-        QAM_128,
-        QAM_256,
-        QAM_AUTO,
-        VSB_8,
-        VSB_16,
-        PSK_8,
-        APSK_16,
-        APSK_32,
-        DQPSK,
-} fe_modulation_t;
-
-typedef enum fe_transmit_mode {
-        TRANSMISSION_MODE_2K,
-        TRANSMISSION_MODE_8K,
-        TRANSMISSION_MODE_AUTO,
-        TRANSMISSION_MODE_4K,
-        TRANSMISSION_MODE_1K,
-        TRANSMISSION_MODE_16K,
-        TRANSMISSION_MODE_32K,
-} fe_transmit_mode_t;
-
-typedef enum fe_bandwidth {
-        BANDWIDTH_8_MHZ,
-        BANDWIDTH_7_MHZ,
-        BANDWIDTH_6_MHZ,
-        BANDWIDTH_AUTO,
-        BANDWIDTH_5_MHZ,
-        BANDWIDTH_10_MHZ,
-        BANDWIDTH_1_712_MHZ,
-} fe_bandwidth_t;
-
-
-typedef enum fe_guard_interval {
-        GUARD_INTERVAL_1_32,
-        GUARD_INTERVAL_1_16,
-        GUARD_INTERVAL_1_8,
-        GUARD_INTERVAL_1_4,
-        GUARD_INTERVAL_AUTO,
-        GUARD_INTERVAL_1_128,
-        GUARD_INTERVAL_19_128,
-        GUARD_INTERVAL_19_256,
-} fe_guard_interval_t;
-
-
-typedef enum fe_hierarchy {
-        HIERARCHY_NONE,
-        HIERARCHY_1,
-        HIERARCHY_2,
-        HIERARCHY_4,
-        HIERARCHY_AUTO
-} fe_hierarchy_t;
-
-
-struct dvb_qpsk_parameters {
-        __u32           symbol_rate;  /* symbol rate in Symbols per second */
-        fe_code_rate_t  fec_inner;    /* forward error correction (see above) */
-};
-
-struct dvb_qam_parameters {
-        __u32           symbol_rate; /* symbol rate in Symbols per second */
-        fe_code_rate_t  fec_inner;   /* forward error correction (see above) */
-        fe_modulation_t modulation;  /* modulation type (see above) */
-};
-
-struct dvb_vsb_parameters {
-        fe_modulation_t modulation;  /* modulation type (see above) */
-};
-
-struct dvb_ofdm_parameters {
-        fe_bandwidth_t      bandwidth;
-        fe_code_rate_t      code_rate_HP;  /* high priority stream code rate */
-        fe_code_rate_t      code_rate_LP;  /* low priority stream code rate */
-        fe_modulation_t     constellation; /* modulation type (see above) */
-        fe_transmit_mode_t  transmission_mode;
-        fe_guard_interval_t guard_interval;
-        fe_hierarchy_t      hierarchy_information;
-};
-
-
-struct dvb_frontend_parameters {
-        __u32 frequency;     /* (absolute) frequency in Hz for QAM/OFDM/ATSC */
-                             /* intermediate frequency in kHz for QPSK */
-        fe_spectral_inversion_t inversion;
-        union {
-                struct dvb_qpsk_parameters qpsk;
-                struct dvb_qam_parameters  qam;
-                struct dvb_ofdm_parameters ofdm;
-                struct dvb_vsb_parameters vsb;
-        } u;
-};
-
-
-struct dvb_frontend_event {
-        fe_status_t status;
-        struct dvb_frontend_parameters parameters;
-};
-
-/* S2API Commands */
-#define DTV_UNDEFINED           0
-#define DTV_TUNE                1
-#define DTV_CLEAR               2
-#define DTV_FREQUENCY           3
-#define DTV_MODULATION          4
-#define DTV_BANDWIDTH_HZ        5
-#define DTV_INVERSION           6
-#define DTV_DISEQC_MASTER       7
-#define DTV_SYMBOL_RATE         8
-#define DTV_INNER_FEC           9
-#define DTV_VOLTAGE             10
-#define DTV_TONE                11
-#define DTV_PILOT               12
-#define DTV_ROLLOFF             13
-#define DTV_DISEQC_SLAVE_REPLY  14
-
-/* Basic enumeration set for querying unlimited capabilities */
-#define DTV_FE_CAPABILITY_COUNT 15
-#define DTV_FE_CAPABILITY       16
-#define DTV_DELIVERY_SYSTEM     17
-
-/* ISDB-T and ISDB-Tsb */
-#define DTV_ISDBT_PARTIAL_RECEPTION     18
-#define DTV_ISDBT_SOUND_BROADCASTING    19
-
-#define DTV_ISDBT_SB_SUBCHANNEL_ID      20
-#define DTV_ISDBT_SB_SEGMENT_IDX        21
-#define DTV_ISDBT_SB_SEGMENT_COUNT      22
-
-#define DTV_ISDBT_LAYERA_FEC                    23
-#define DTV_ISDBT_LAYERA_MODULATION             24
-#define DTV_ISDBT_LAYERA_SEGMENT_COUNT          25
-#define DTV_ISDBT_LAYERA_TIME_INTERLEAVING      26
-
-#define DTV_ISDBT_LAYERB_FEC                    27
-#define DTV_ISDBT_LAYERB_MODULATION             28
-#define DTV_ISDBT_LAYERB_SEGMENT_COUNT          29
-#define DTV_ISDBT_LAYERB_TIME_INTERLEAVING      30
-
-#define DTV_ISDBT_LAYERC_FEC                    31
-#define DTV_ISDBT_LAYERC_MODULATION             32
-#define DTV_ISDBT_LAYERC_SEGMENT_COUNT          33
-#define DTV_ISDBT_LAYERC_TIME_INTERLEAVING      34
-
-#define DTV_API_VERSION         35
-
-#define DTV_CODE_RATE_HP        36
-#define DTV_CODE_RATE_LP        37
-#define DTV_GUARD_INTERVAL      38
-#define DTV_TRANSMISSION_MODE   39
-#define DTV_HIERARCHY           40
-
-#define DTV_ISDBT_LAYER_ENABLED 41
-
-#define DTV_ISDBS_TS_ID         42
-
-#define DTV_DVBT2_PLP_ID       43
-
-#define DTV_MAX_COMMAND                         DTV_DVBT2_PLP_ID
-
-typedef enum fe_pilot {
-        PILOT_ON,
-        PILOT_OFF,
-        PILOT_AUTO,
-} fe_pilot_t;
-
-typedef enum fe_rolloff {
-        ROLLOFF_35, /* Implied value in DVB-S, default for DVB-S2 */
-        ROLLOFF_20,
-        ROLLOFF_25,
-        ROLLOFF_AUTO,
-} fe_rolloff_t;
-
-typedef enum fe_delivery_system {
-        SYS_UNDEFINED,
-        SYS_DVBC_ANNEX_AC,
-        SYS_DVBC_ANNEX_B,
-        SYS_DVBT,
-        SYS_DSS,
-        SYS_DVBS,
-        SYS_DVBS2,
-        SYS_DVBH,
-        SYS_ISDBT,
-        SYS_ISDBS,
-        SYS_ISDBC,
-        SYS_ATSC,
-        SYS_ATSCMH,
-        SYS_DMBTH,
-        SYS_CMMB,
-        SYS_DAB,
-        SYS_DVBT2,
-} fe_delivery_system_t;
-
-struct dtv_cmds_h {
-        char    *name;          /* A display name for debugging purposes */
-
-        __u32   cmd;            /* A unique ID */
-
-        /* Flags */
-        __u32   set:1;          /* Either a set or get property */
-        __u32   buffer:1;       /* Does this property use the buffer? */
-        __u32   reserved:30;    /* Align */
-};
-
-struct dtv_property {
-        __u32 cmd;
-        __u32 reserved[3];
-        union {
-                __u32 data;
-                struct {
-                        __u8 data[32];
-                        __u32 len;
-                        __u32 reserved1[3];
-                        void *reserved2;
-                } buffer;
-        } u;
-        int result;
-} __attribute__ ((packed));
-
-/* num of properties cannot exceed DTV_IOCTL_MAX_MSGS per ioctl */
-#define DTV_IOCTL_MAX_MSGS 64
-
-struct dtv_properties {
-        __u32 num;
-        struct dtv_property *props;
-};
-
-#define <link linkend="FE_GET_PROPERTY">FE_SET_PROPERTY</link>            _IOW('o', 82, struct dtv_properties)
-#define <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link>            _IOR('o', 83, struct dtv_properties)
-
-
-/**
- * When set, this flag will disable any zigzagging or other "normal" tuning
- * behaviour. Additionally, there will be no automatic monitoring of the lock
- * status, and hence no frontend events will be generated. If a frontend device
- * is closed, this flag will be automatically turned off when the device is
- * reopened read-write.
- */
-#define FE_TUNE_MODE_ONESHOT 0x01
-
-
-#define <link linkend="FE_GET_INFO">FE_GET_INFO</link>                _IOR('o', 61, struct dvb_frontend_info)
-
-#define <link linkend="FE_DISEQC_RESET_OVERLOAD">FE_DISEQC_RESET_OVERLOAD</link>   _IO('o', 62)
-#define <link linkend="FE_DISEQC_SEND_MASTER_CMD">FE_DISEQC_SEND_MASTER_CMD</link>  _IOW('o', 63, struct dvb_diseqc_master_cmd)
-#define <link linkend="FE_DISEQC_RECV_SLAVE_REPLY">FE_DISEQC_RECV_SLAVE_REPLY</link> _IOR('o', 64, struct dvb_diseqc_slave_reply)
-#define <link linkend="FE_DISEQC_SEND_BURST">FE_DISEQC_SEND_BURST</link>       _IO('o', 65)  /* fe_sec_mini_cmd_t */
-
-#define <link linkend="FE_SET_TONE">FE_SET_TONE</link>                _IO('o', 66)  /* fe_sec_tone_mode_t */
-#define <link linkend="FE_SET_VOLTAGE">FE_SET_VOLTAGE</link>             _IO('o', 67)  /* fe_sec_voltage_t */
-#define <link linkend="FE_ENABLE_HIGH_LNB_VOLTAGE">FE_ENABLE_HIGH_LNB_VOLTAGE</link> _IO('o', 68)  /* int */
-
-#define <link linkend="FE_READ_STATUS">FE_READ_STATUS</link>             _IOR('o', 69, fe_status_t)
-#define <link linkend="FE_READ_BER">FE_READ_BER</link>                _IOR('o', 70, __u32)
-#define <link linkend="FE_READ_SIGNAL_STRENGTH">FE_READ_SIGNAL_STRENGTH</link>    _IOR('o', 71, __u16)
-#define <link linkend="FE_READ_SNR">FE_READ_SNR</link>                _IOR('o', 72, __u16)
-#define <link linkend="FE_READ_UNCORRECTED_BLOCKS">FE_READ_UNCORRECTED_BLOCKS</link> _IOR('o', 73, __u32)
-
-#define <link linkend="FE_SET_FRONTEND">FE_SET_FRONTEND</link>            _IOW('o', 76, struct dvb_frontend_parameters)
-#define <link linkend="FE_GET_FRONTEND">FE_GET_FRONTEND</link>            _IOR('o', 77, struct dvb_frontend_parameters)
-#define <link linkend="FE_SET_FRONTEND_TUNE_MODE">FE_SET_FRONTEND_TUNE_MODE</link>  _IO('o', 81) /* unsigned int */
-#define <link linkend="FE_GET_EVENT">FE_GET_EVENT</link>               _IOR('o', 78, struct dvb_frontend_event)
-
-#define <link linkend="FE_DISHNETWORK_SEND_LEGACY_CMD">FE_DISHNETWORK_SEND_LEGACY_CMD</link> _IO('o', 80) /* unsigned int */
-
-#endif /*_DVBFRONTEND_H_*/
-</programlisting>
diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
deleted file mode 100644 (file)
index e5fe094..0000000
+++ /dev/null
@@ -1,464 +0,0 @@
-<!-- Generated file! Do not edit. -->
-
-<!-- Functions -->
-<!ENTITY func-close "<link linkend='func-close'><function>close()</function></link>">
-<!ENTITY func-ioctl "<link linkend='func-ioctl'><function>ioctl()</function></link>">
-<!ENTITY func-mmap "<link linkend='func-mmap'><function>mmap()</function></link>">
-<!ENTITY func-munmap "<link linkend='func-munmap'><function>munmap()</function></link>">
-<!ENTITY func-open "<link linkend='func-open'><function>open()</function></link>">
-<!ENTITY func-poll "<link linkend='func-poll'><function>poll()</function></link>">
-<!ENTITY func-read "<link linkend='func-read'><function>read()</function></link>">
-<!ENTITY func-select "<link linkend='func-select'><function>select()</function></link>">
-<!ENTITY func-write "<link linkend='func-write'><function>write()</function></link>">
-
-<!ENTITY media-func-close "<link linkend='media-func-close'><function>close()</function></link>">
-<!ENTITY media-func-ioctl "<link linkend='media-func-ioctl'><function>ioctl()</function></link>">
-<!ENTITY media-func-open "<link linkend='media-func-open'><function>open()</function></link>">
-
-<!-- Ioctls -->
-<!ENTITY VIDIOC-CROPCAP "<link linkend='vidioc-cropcap'><constant>VIDIOC_CROPCAP</constant></link>">
-<!ENTITY VIDIOC-DBG-G-CHIP-IDENT "<link linkend='vidioc-dbg-g-chip-ident'><constant>VIDIOC_DBG_G_CHIP_IDENT</constant></link>">
-<!ENTITY VIDIOC-DBG-G-REGISTER "<link linkend='vidioc-dbg-g-register'><constant>VIDIOC_DBG_G_REGISTER</constant></link>">
-<!ENTITY VIDIOC-DBG-S-REGISTER "<link linkend='vidioc-dbg-g-register'><constant>VIDIOC_DBG_S_REGISTER</constant></link>">
-<!ENTITY VIDIOC-DQBUF "<link linkend='vidioc-qbuf'><constant>VIDIOC_DQBUF</constant></link>">
-<!ENTITY VIDIOC-DQEVENT "<link linkend='vidioc-dqevent'><constant>VIDIOC_DQEVENT</constant></link>">
-<!ENTITY VIDIOC-ENCODER-CMD "<link linkend='vidioc-encoder-cmd'><constant>VIDIOC_ENCODER_CMD</constant></link>">
-<!ENTITY VIDIOC-ENUMAUDIO "<link linkend='vidioc-enumaudio'><constant>VIDIOC_ENUMAUDIO</constant></link>">
-<!ENTITY VIDIOC-ENUMAUDOUT "<link linkend='vidioc-enumaudioout'><constant>VIDIOC_ENUMAUDOUT</constant></link>">
-<!ENTITY VIDIOC-ENUMINPUT "<link linkend='vidioc-enuminput'><constant>VIDIOC_ENUMINPUT</constant></link>">
-<!ENTITY VIDIOC-ENUMOUTPUT "<link linkend='vidioc-enumoutput'><constant>VIDIOC_ENUMOUTPUT</constant></link>">
-<!ENTITY VIDIOC-ENUMSTD "<link linkend='vidioc-enumstd'><constant>VIDIOC_ENUMSTD</constant></link>">
-<!ENTITY VIDIOC-ENUM-DV-PRESETS "<link linkend='vidioc-enum-dv-presets'><constant>VIDIOC_ENUM_DV_PRESETS</constant></link>">
-<!ENTITY VIDIOC-ENUM-FMT "<link linkend='vidioc-enum-fmt'><constant>VIDIOC_ENUM_FMT</constant></link>">
-<!ENTITY VIDIOC-ENUM-FRAMEINTERVALS "<link linkend='vidioc-enum-frameintervals'><constant>VIDIOC_ENUM_FRAMEINTERVALS</constant></link>">
-<!ENTITY VIDIOC-ENUM-FRAMESIZES "<link linkend='vidioc-enum-framesizes'><constant>VIDIOC_ENUM_FRAMESIZES</constant></link>">
-<!ENTITY VIDIOC-G-AUDIO "<link linkend='vidioc-g-audio'><constant>VIDIOC_G_AUDIO</constant></link>">
-<!ENTITY VIDIOC-G-AUDOUT "<link linkend='vidioc-g-audioout'><constant>VIDIOC_G_AUDOUT</constant></link>">
-<!ENTITY VIDIOC-G-CROP "<link linkend='vidioc-g-crop'><constant>VIDIOC_G_CROP</constant></link>">
-<!ENTITY VIDIOC-G-CTRL "<link linkend='vidioc-g-ctrl'><constant>VIDIOC_G_CTRL</constant></link>">
-<!ENTITY VIDIOC-G-DV-PRESET "<link linkend='vidioc-g-dv-preset'><constant>VIDIOC_G_DV_PRESET</constant></link>">
-<!ENTITY VIDIOC-G-DV-TIMINGS "<link linkend='vidioc-g-dv-timings'><constant>VIDIOC_G_DV_TIMINGS</constant></link>">
-<!ENTITY VIDIOC-G-ENC-INDEX "<link linkend='vidioc-g-enc-index'><constant>VIDIOC_G_ENC_INDEX</constant></link>">
-<!ENTITY VIDIOC-G-EXT-CTRLS "<link linkend='vidioc-g-ext-ctrls'><constant>VIDIOC_G_EXT_CTRLS</constant></link>">
-<!ENTITY VIDIOC-G-FBUF "<link linkend='vidioc-g-fbuf'><constant>VIDIOC_G_FBUF</constant></link>">
-<!ENTITY VIDIOC-G-FMT "<link linkend='vidioc-g-fmt'><constant>VIDIOC_G_FMT</constant></link>">
-<!ENTITY VIDIOC-G-FREQUENCY "<link linkend='vidioc-g-frequency'><constant>VIDIOC_G_FREQUENCY</constant></link>">
-<!ENTITY VIDIOC-G-INPUT "<link linkend='vidioc-g-input'><constant>VIDIOC_G_INPUT</constant></link>">
-<!ENTITY VIDIOC-G-JPEGCOMP "<link linkend='vidioc-g-jpegcomp'><constant>VIDIOC_G_JPEGCOMP</constant></link>">
-<!ENTITY VIDIOC-G-MPEGCOMP "<link linkend=''><constant>VIDIOC_G_MPEGCOMP</constant></link>">
-<!ENTITY VIDIOC-G-MODULATOR "<link linkend='vidioc-g-modulator'><constant>VIDIOC_G_MODULATOR</constant></link>">
-<!ENTITY VIDIOC-G-OUTPUT "<link linkend='vidioc-g-output'><constant>VIDIOC_G_OUTPUT</constant></link>">
-<!ENTITY VIDIOC-G-PARM "<link linkend='vidioc-g-parm'><constant>VIDIOC_G_PARM</constant></link>">
-<!ENTITY VIDIOC-G-PRIORITY "<link linkend='vidioc-g-priority'><constant>VIDIOC_G_PRIORITY</constant></link>">
-<!ENTITY VIDIOC-G-SLICED-VBI-CAP "<link linkend='vidioc-g-sliced-vbi-cap'><constant>VIDIOC_G_SLICED_VBI_CAP</constant></link>">
-<!ENTITY VIDIOC-G-STD "<link linkend='vidioc-g-std'><constant>VIDIOC_G_STD</constant></link>">
-<!ENTITY VIDIOC-G-TUNER "<link linkend='vidioc-g-tuner'><constant>VIDIOC_G_TUNER</constant></link>">
-<!ENTITY VIDIOC-LOG-STATUS "<link linkend='vidioc-log-status'><constant>VIDIOC_LOG_STATUS</constant></link>">
-<!ENTITY VIDIOC-OVERLAY "<link linkend='vidioc-overlay'><constant>VIDIOC_OVERLAY</constant></link>">
-<!ENTITY VIDIOC-QBUF "<link linkend='vidioc-qbuf'><constant>VIDIOC_QBUF</constant></link>">
-<!ENTITY VIDIOC-QUERYBUF "<link linkend='vidioc-querybuf'><constant>VIDIOC_QUERYBUF</constant></link>">
-<!ENTITY VIDIOC-QUERYCAP "<link linkend='vidioc-querycap'><constant>VIDIOC_QUERYCAP</constant></link>">
-<!ENTITY VIDIOC-QUERYCTRL "<link linkend='vidioc-queryctrl'><constant>VIDIOC_QUERYCTRL</constant></link>">
-<!ENTITY VIDIOC-QUERYMENU "<link linkend='vidioc-queryctrl'><constant>VIDIOC_QUERYMENU</constant></link>">
-<!ENTITY VIDIOC-QUERYSTD "<link linkend='vidioc-querystd'><constant>VIDIOC_QUERYSTD</constant></link>">
-<!ENTITY VIDIOC-QUERY-DV-PRESET "<link linkend='vidioc-query-dv-preset'><constant>VIDIOC_QUERY_DV_PRESET</constant></link>">
-<!ENTITY VIDIOC-REQBUFS "<link linkend='vidioc-reqbufs'><constant>VIDIOC_REQBUFS</constant></link>">
-<!ENTITY VIDIOC-STREAMOFF "<link linkend='vidioc-streamon'><constant>VIDIOC_STREAMOFF</constant></link>">
-<!ENTITY VIDIOC-STREAMON "<link linkend='vidioc-streamon'><constant>VIDIOC_STREAMON</constant></link>">
-<!ENTITY VIDIOC-SUBSCRIBE-EVENT "<link linkend='vidioc-subscribe-event'><constant>VIDIOC_SUBSCRIBE_EVENT</constant></link>">
-<!ENTITY VIDIOC-S-AUDIO "<link linkend='vidioc-g-audio'><constant>VIDIOC_S_AUDIO</constant></link>">
-<!ENTITY VIDIOC-S-AUDOUT "<link linkend='vidioc-g-audioout'><constant>VIDIOC_S_AUDOUT</constant></link>">
-<!ENTITY VIDIOC-S-CROP "<link linkend='vidioc-g-crop'><constant>VIDIOC_S_CROP</constant></link>">
-<!ENTITY VIDIOC-S-CTRL "<link linkend='vidioc-g-ctrl'><constant>VIDIOC_S_CTRL</constant></link>">
-<!ENTITY VIDIOC-S-DV-PRESET "<link linkend='vidioc-g-dv-preset'><constant>VIDIOC_S_DV_PRESET</constant></link>">
-<!ENTITY VIDIOC-S-DV-TIMINGS "<link linkend='vidioc-g-dv-timings'><constant>VIDIOC_S_DV_TIMINGS</constant></link>">
-<!ENTITY VIDIOC-S-EXT-CTRLS "<link linkend='vidioc-g-ext-ctrls'><constant>VIDIOC_S_EXT_CTRLS</constant></link>">
-<!ENTITY VIDIOC-S-FBUF "<link linkend='vidioc-g-fbuf'><constant>VIDIOC_S_FBUF</constant></link>">
-<!ENTITY VIDIOC-S-FMT "<link linkend='vidioc-g-fmt'><constant>VIDIOC_S_FMT</constant></link>">
-<!ENTITY VIDIOC-S-FREQUENCY "<link linkend='vidioc-g-frequency'><constant>VIDIOC_S_FREQUENCY</constant></link>">
-<!ENTITY VIDIOC-S-HW-FREQ-SEEK "<link linkend='vidioc-s-hw-freq-seek'><constant>VIDIOC_S_HW_FREQ_SEEK</constant></link>">
-<!ENTITY VIDIOC-S-INPUT "<link linkend='vidioc-g-input'><constant>VIDIOC_S_INPUT</constant></link>">
-<!ENTITY VIDIOC-S-JPEGCOMP "<link linkend='vidioc-g-jpegcomp'><constant>VIDIOC_S_JPEGCOMP</constant></link>">
-<!ENTITY VIDIOC-S-MPEGCOMP "<link linkend=''><constant>VIDIOC_S_MPEGCOMP</constant></link>">
-<!ENTITY VIDIOC-S-MODULATOR "<link linkend='vidioc-g-modulator'><constant>VIDIOC_S_MODULATOR</constant></link>">
-<!ENTITY VIDIOC-S-OUTPUT "<link linkend='vidioc-g-output'><constant>VIDIOC_S_OUTPUT</constant></link>">
-<!ENTITY VIDIOC-S-PARM "<link linkend='vidioc-g-parm'><constant>VIDIOC_S_PARM</constant></link>">
-<!ENTITY VIDIOC-S-PRIORITY "<link linkend='vidioc-g-priority'><constant>VIDIOC_S_PRIORITY</constant></link>">
-<!ENTITY VIDIOC-S-STD "<link linkend='vidioc-g-std'><constant>VIDIOC_S_STD</constant></link>">
-<!ENTITY VIDIOC-S-TUNER "<link linkend='vidioc-g-tuner'><constant>VIDIOC_S_TUNER</constant></link>">
-<!ENTITY VIDIOC-SUBDEV-ENUM-FRAME-SIZE "<link linkend='vidioc-subdev-enum-frame-size'><constant>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</constant></link>">
-<!ENTITY VIDIOC-SUBDEV-ENUM-MBUS-CODE "<link linkend='vidioc-subdev-enum-mbus-code'><constant>VIDIOC_SUBDEV_ENUM_MBUS_CODE</constant></link>">
-<!ENTITY VIDIOC-SUBDEV-G-CROP "<link linkend='vidioc-subdev-g-crop'><constant>VIDIOC_SUBDEV_G_CROP</constant></link>">
-<!ENTITY VIDIOC-SUBDEV-G-FMT "<link linkend='vidioc-subdev-g-fmt'><constant>VIDIOC_SUBDEV_G_FMT</constant></link>">
-<!ENTITY VIDIOC-SUBDEV-G-FRAME-INTERVAL "<link linkend='vidioc-subdev-g-frame-interval'><constant>VIDIOC_SUBDEV_G_FRAME_INTERVAL</constant></link>">
-<!ENTITY VIDIOC-SUBDEV-S-CROP "<link linkend='vidioc-subdev-g-crop'><constant>VIDIOC_SUBDEV_S_CROP</constant></link>">
-<!ENTITY VIDIOC-SUBDEV-S-FMT "<link linkend='vidioc-subdev-g-fmt'><constant>VIDIOC_SUBDEV_S_FMT</constant></link>">
-<!ENTITY VIDIOC-SUBDEV-S-FRAME-INTERVAL "<link linkend='vidioc-subdev-g-frame-interval'><constant>VIDIOC_SUBDEV_S_FRAME_INTERVAL</constant></link>">
-<!ENTITY VIDIOC-TRY-ENCODER-CMD "<link linkend='vidioc-encoder-cmd'><constant>VIDIOC_TRY_ENCODER_CMD</constant></link>">
-<!ENTITY VIDIOC-TRY-EXT-CTRLS "<link linkend='vidioc-g-ext-ctrls'><constant>VIDIOC_TRY_EXT_CTRLS</constant></link>">
-<!ENTITY VIDIOC-TRY-FMT "<link linkend='vidioc-g-fmt'><constant>VIDIOC_TRY_FMT</constant></link>">
-<!ENTITY VIDIOC-UNSUBSCRIBE-EVENT "<link linkend='vidioc-subscribe-event'><constant>VIDIOC_UNSUBSCRIBE_EVENT</constant></link>">
-
-<!ENTITY MEDIA-IOC-DEVICE-INFO "<link linkend='media-ioc-device-info'><constant>MEDIA_IOC_DEVICE_INFO</constant></link>">
-<!ENTITY MEDIA-IOC-ENUM-ENTITIES "<link linkend='media-ioc-enum-entities'><constant>MEDIA_IOC_ENUM_ENTITIES</constant></link>">
-<!ENTITY MEDIA-IOC-ENUM-LINKS "<link linkend='media-ioc-enum-links'><constant>MEDIA_IOC_ENUM_LINKS</constant></link>">
-<!ENTITY MEDIA-IOC-SETUP-LINK "<link linkend='media-ioc-setup-link'><constant>MEDIA_IOC_SETUP_LINK</constant></link>">
-
-<!-- Types -->
-<!ENTITY v4l2-std-id "<link linkend='v4l2-std-id'>v4l2_std_id</link>">
-
-<!-- Enums -->
-<!ENTITY v4l2-buf-type "enum&nbsp;<link linkend='v4l2-buf-type'>v4l2_buf_type</link>">
-<!ENTITY v4l2-colorspace "enum&nbsp;<link linkend='v4l2-colorspace'>v4l2_colorspace</link>">
-<!ENTITY v4l2-ctrl-type "enum&nbsp;<link linkend='v4l2-ctrl-type'>v4l2_ctrl_type</link>">
-<!ENTITY v4l2-exposure-auto-type "enum&nbsp;<link linkend='v4l2-exposure-auto-type'>v4l2_exposure_auto_type</link>">
-<!ENTITY v4l2-field "enum&nbsp;<link linkend='v4l2-field'>v4l2_field</link>">
-<!ENTITY v4l2-frmivaltypes "enum&nbsp;<link linkend='v4l2-frmivaltypes'>v4l2_frmivaltypes</link>">
-<!ENTITY v4l2-frmsizetypes "enum&nbsp;<link linkend='v4l2-frmsizetypes'>v4l2_frmsizetypes</link>">
-<!ENTITY v4l2-mbus-pixelcode "enum&nbsp;<link linkend='v4l2-mbus-pixelcode'>v4l2_mbus_pixelcode</link>">
-<!ENTITY v4l2-memory "enum&nbsp;<link linkend='v4l2-memory'>v4l2_memory</link>">
-<!ENTITY v4l2-mpeg-audio-ac3-bitrate "enum&nbsp;<link linkend='v4l2-mpeg-audio-ac3-bitrate'>v4l2_mpeg_audio_ac3_bitrate</link>">
-<!ENTITY v4l2-mpeg-audio-crc "enum&nbsp;<link linkend='v4l2-mpeg-audio-crc'>v4l2_mpeg_audio_crc</link>">
-<!ENTITY v4l2-mpeg-audio-emphasis "enum&nbsp;<link linkend='v4l2-mpeg-audio-emphasis'>v4l2_mpeg_audio_emphasis</link>">
-<!ENTITY v4l2-mpeg-audio-encoding "enum&nbsp;<link linkend='v4l2-mpeg-audio-encoding'>v4l2_mpeg_audio_encoding</link>">
-<!ENTITY v4l2-mpeg-audio-l1-bitrate "enum&nbsp;<link linkend='v4l2-mpeg-audio-l1-bitrate'>v4l2_mpeg_audio_l1_bitrate</link>">
-<!ENTITY v4l2-mpeg-audio-l2-bitrate "enum&nbsp;<link linkend='v4l2-mpeg-audio-l2-bitrate'>v4l2_mpeg_audio_l2_bitrate</link>">
-<!ENTITY v4l2-mpeg-audio-l3-bitrate "enum&nbsp;<link linkend='v4l2-mpeg-audio-l3-bitrate'>v4l2_mpeg_audio_l3_bitrate</link>">
-<!ENTITY v4l2-mpeg-audio-mode "enum&nbsp;<link linkend='v4l2-mpeg-audio-mode'>v4l2_mpeg_audio_mode</link>">
-<!ENTITY v4l2-mpeg-audio-mode-extension "enum&nbsp;<link linkend='v4l2-mpeg-audio-mode-extension'>v4l2_mpeg_audio_mode_extension</link>">
-<!ENTITY v4l2-mpeg-audio-sampling-freq "enum&nbsp;<link linkend='v4l2-mpeg-audio-sampling-freq'>v4l2_mpeg_audio_sampling_freq</link>">
-<!ENTITY chroma-spatial-filter-type "enum&nbsp;<link linkend='chroma-spatial-filter-type'>v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type</link>">
-<!ENTITY luma-spatial-filter-type "enum&nbsp;<link linkend='luma-spatial-filter-type'>v4l2_mpeg_cx2341x_video_luma_spatial_filter_type</link>">
-<!ENTITY v4l2-mpeg-cx2341x-video-median-filter-type "enum&nbsp;<link linkend='v4l2-mpeg-cx2341x-video-median-filter-type'>v4l2_mpeg_cx2341x_video_median_filter_type</link>">
-<!ENTITY v4l2-mpeg-cx2341x-video-spatial-filter-mode "enum&nbsp;<link linkend='v4l2-mpeg-cx2341x-video-spatial-filter-mode'>v4l2_mpeg_cx2341x_video_spatial_filter_mode</link>">
-<!ENTITY v4l2-mpeg-cx2341x-video-temporal-filter-mode "enum&nbsp;<link linkend='v4l2-mpeg-cx2341x-video-temporal-filter-mode'>v4l2_mpeg_cx2341x_video_temporal_filter_mode</link>">
-<!ENTITY v4l2-mpeg-stream-type "enum&nbsp;<link linkend='v4l2-mpeg-stream-type'>v4l2_mpeg_stream_type</link>">
-<!ENTITY v4l2-mpeg-stream-vbi-fmt "enum&nbsp;<link linkend='v4l2-mpeg-stream-vbi-fmt'>v4l2_mpeg_stream_vbi_fmt</link>">
-<!ENTITY v4l2-mpeg-video-aspect "enum&nbsp;<link linkend='v4l2-mpeg-video-aspect'>v4l2_mpeg_video_aspect</link>">
-<!ENTITY v4l2-mpeg-video-bitrate-mode "enum&nbsp;<link linkend='v4l2-mpeg-video-bitrate-mode'>v4l2_mpeg_video_bitrate_mode</link>">
-<!ENTITY v4l2-mpeg-video-encoding "enum&nbsp;<link linkend='v4l2-mpeg-video-encoding'>v4l2_mpeg_video_encoding</link>">
-<!ENTITY v4l2-power-line-frequency "enum&nbsp;<link linkend='v4l2-power-line-frequency'>v4l2_power_line_frequency</link>">
-<!ENTITY v4l2-priority "enum&nbsp;<link linkend='v4l2-priority'>v4l2_priority</link>">
-<!ENTITY v4l2-subdev-format-whence "enum&nbsp;<link linkend='v4l2-subdev-format-whence'>v4l2_subdev_format_whence</link>">
-<!ENTITY v4l2-tuner-type "enum&nbsp;<link linkend='v4l2-tuner-type'>v4l2_tuner_type</link>">
-<!ENTITY v4l2-preemphasis "enum&nbsp;<link linkend='v4l2-preemphasis'>v4l2_preemphasis</link>">
-
-<!-- Structures -->
-<!ENTITY v4l2-audio "struct&nbsp;<link linkend='v4l2-audio'>v4l2_audio</link>">
-<!ENTITY v4l2-audioout "struct&nbsp;<link linkend='v4l2-audioout'>v4l2_audioout</link>">
-<!ENTITY v4l2-bt-timings "struct&nbsp;<link linkend='v4l2-bt-timings'>v4l2_bt_timings</link>">
-<!ENTITY v4l2-buffer "struct&nbsp;<link linkend='v4l2-buffer'>v4l2_buffer</link>">
-<!ENTITY v4l2-plane "struct&nbsp;<link linkend='v4l2-plane'>v4l2_plane</link>">
-<!ENTITY v4l2-capability "struct&nbsp;<link linkend='v4l2-capability'>v4l2_capability</link>">
-<!ENTITY v4l2-captureparm "struct&nbsp;<link linkend='v4l2-captureparm'>v4l2_captureparm</link>">
-<!ENTITY v4l2-clip "struct&nbsp;<link linkend='v4l2-clip'>v4l2_clip</link>">
-<!ENTITY v4l2-control "struct&nbsp;<link linkend='v4l2-control'>v4l2_control</link>">
-<!ENTITY v4l2-crop "struct&nbsp;<link linkend='v4l2-crop'>v4l2_crop</link>">
-<!ENTITY v4l2-cropcap "struct&nbsp;<link linkend='v4l2-cropcap'>v4l2_cropcap</link>">
-<!ENTITY v4l2-dbg-chip-ident "struct&nbsp;<link linkend='v4l2-dbg-chip-ident'>v4l2_dbg_chip_ident</link>">
-<!ENTITY v4l2-dbg-match "struct&nbsp;<link linkend='v4l2-dbg-match'>v4l2_dbg_match</link>">
-<!ENTITY v4l2-dbg-register "struct&nbsp;<link linkend='v4l2-dbg-register'>v4l2_dbg_register</link>">
-<!ENTITY v4l2-dv-enum-preset "struct&nbsp;<link linkend='v4l2-dv-enum-preset'>v4l2_dv_enum_preset</link>">
-<!ENTITY v4l2-dv-preset "struct&nbsp;<link linkend='v4l2-dv-preset'>v4l2_dv_preset</link>">
-<!ENTITY v4l2-dv-timings "struct&nbsp;<link linkend='v4l2-dv-timings'>v4l2_dv_timings</link>">
-<!ENTITY v4l2-enc-idx "struct&nbsp;<link linkend='v4l2-enc-idx'>v4l2_enc_idx</link>">
-<!ENTITY v4l2-enc-idx-entry "struct&nbsp;<link linkend='v4l2-enc-idx-entry'>v4l2_enc_idx_entry</link>">
-<!ENTITY v4l2-encoder-cmd "struct&nbsp;<link linkend='v4l2-encoder-cmd'>v4l2_encoder_cmd</link>">
-<!ENTITY v4l2-event "struct&nbsp;<link linkend='v4l2-event'>v4l2_event</link>">
-<!ENTITY v4l2-event-subscription "struct&nbsp;<link linkend='v4l2-event-subscription'>v4l2_event_subscription</link>">
-<!ENTITY v4l2-event-vsync "struct&nbsp;<link linkend='v4l2-event-vsync'>v4l2_event_vsync</link>">
-<!ENTITY v4l2-ext-control "struct&nbsp;<link linkend='v4l2-ext-control'>v4l2_ext_control</link>">
-<!ENTITY v4l2-ext-controls "struct&nbsp;<link linkend='v4l2-ext-controls'>v4l2_ext_controls</link>">
-<!ENTITY v4l2-fmtdesc "struct&nbsp;<link linkend='v4l2-fmtdesc'>v4l2_fmtdesc</link>">
-<!ENTITY v4l2-format "struct&nbsp;<link linkend='v4l2-format'>v4l2_format</link>">
-<!ENTITY v4l2-fract "struct&nbsp;<link linkend='v4l2-fract'>v4l2_fract</link>">
-<!ENTITY v4l2-framebuffer "struct&nbsp;<link linkend='v4l2-framebuffer'>v4l2_framebuffer</link>">
-<!ENTITY v4l2-frequency "struct&nbsp;<link linkend='v4l2-frequency'>v4l2_frequency</link>">
-<!ENTITY v4l2-frmival-stepwise "struct&nbsp;<link linkend='v4l2-frmival-stepwise'>v4l2_frmival_stepwise</link>">
-<!ENTITY v4l2-frmivalenum "struct&nbsp;<link linkend='v4l2-frmivalenum'>v4l2_frmivalenum</link>">
-<!ENTITY v4l2-frmsize-discrete "struct&nbsp;<link linkend='v4l2-frmsize-discrete'>v4l2_frmsize_discrete</link>">
-<!ENTITY v4l2-frmsize-stepwise "struct&nbsp;<link linkend='v4l2-frmsize-stepwise'>v4l2_frmsize_stepwise</link>">
-<!ENTITY v4l2-frmsizeenum "struct&nbsp;<link linkend='v4l2-frmsizeenum'>v4l2_frmsizeenum</link>">
-<!ENTITY v4l2-hw-freq-seek "struct&nbsp;<link linkend='v4l2-hw-freq-seek'>v4l2_hw_freq_seek</link>">
-<!ENTITY v4l2-input "struct&nbsp;<link linkend='v4l2-input'>v4l2_input</link>">
-<!ENTITY v4l2-jpegcompression "struct&nbsp;<link linkend='v4l2-jpegcompression'>v4l2_jpegcompression</link>">
-<!ENTITY v4l2-mbus-framefmt "struct&nbsp;<link linkend='v4l2-mbus-framefmt'>v4l2_mbus_framefmt</link>">
-<!ENTITY v4l2-modulator "struct&nbsp;<link linkend='v4l2-modulator'>v4l2_modulator</link>">
-<!ENTITY v4l2-mpeg-vbi-fmt-ivtv "struct&nbsp;<link linkend='v4l2-mpeg-vbi-fmt-ivtv'>v4l2_mpeg_vbi_fmt_ivtv</link>">
-<!ENTITY v4l2-output "struct&nbsp;<link linkend='v4l2-output'>v4l2_output</link>">
-<!ENTITY v4l2-outputparm "struct&nbsp;<link linkend='v4l2-outputparm'>v4l2_outputparm</link>">
-<!ENTITY v4l2-pix-format "struct&nbsp;<link linkend='v4l2-pix-format'>v4l2_pix_format</link>">
-<!ENTITY v4l2-pix-format-mplane "struct&nbsp;<link linkend='v4l2-pix-format-mplane'>v4l2_pix_format_mplane</link>">
-<!ENTITY v4l2-plane-pix-format "struct&nbsp;<link linkend='v4l2-plane-pix-format'>v4l2_plane_pix_format</link>">
-<!ENTITY v4l2-queryctrl "struct&nbsp;<link linkend='v4l2-queryctrl'>v4l2_queryctrl</link>">
-<!ENTITY v4l2-querymenu "struct&nbsp;<link linkend='v4l2-querymenu'>v4l2_querymenu</link>">
-<!ENTITY v4l2-rect "struct&nbsp;<link linkend='v4l2-rect'>v4l2_rect</link>">
-<!ENTITY v4l2-requestbuffers "struct&nbsp;<link linkend='v4l2-requestbuffers'>v4l2_requestbuffers</link>">
-<!ENTITY v4l2-sliced-vbi-cap "struct&nbsp;<link linkend='v4l2-sliced-vbi-cap'>v4l2_sliced_vbi_cap</link>">
-<!ENTITY v4l2-sliced-vbi-data "struct&nbsp;<link linkend='v4l2-sliced-vbi-data'>v4l2_sliced_vbi_data</link>">
-<!ENTITY v4l2-sliced-vbi-format "struct&nbsp;<link linkend='v4l2-sliced-vbi-format'>v4l2_sliced_vbi_format</link>">
-<!ENTITY v4l2-subdev-frame-interval "struct&nbsp;<link linkend='v4l2-subdev-frame-interval'>v4l2_subdev_frame_interval</link>">
-<!ENTITY v4l2-subdev-frame-interval-enum "struct&nbsp;<link linkend='v4l2-subdev-frame-interval-enum'>v4l2_subdev_frame_interval_enum</link>">
-<!ENTITY v4l2-subdev-frame-size-enum "struct&nbsp;<link linkend='v4l2-subdev-frame-size-enum'>v4l2_subdev_frame_size_enum</link>">
-<!ENTITY v4l2-subdev-crop "struct&nbsp;<link linkend='v4l2-subdev-crop'>v4l2_subdev_crop</link>">
-<!ENTITY v4l2-subdev-format "struct&nbsp;<link linkend='v4l2-subdev-format'>v4l2_subdev_format</link>">
-<!ENTITY v4l2-subdev-mbus-code-enum "struct&nbsp;<link linkend='v4l2-subdev-mbus-code-enum'>v4l2_subdev_mbus_code_enum</link>">
-<!ENTITY v4l2-standard "struct&nbsp;<link linkend='v4l2-standard'>v4l2_standard</link>">
-<!ENTITY v4l2-streamparm "struct&nbsp;<link linkend='v4l2-streamparm'>v4l2_streamparm</link>">
-<!ENTITY v4l2-timecode "struct&nbsp;<link linkend='v4l2-timecode'>v4l2_timecode</link>">
-<!ENTITY v4l2-tuner "struct&nbsp;<link linkend='v4l2-tuner'>v4l2_tuner</link>">
-<!ENTITY v4l2-vbi-format "struct&nbsp;<link linkend='v4l2-vbi-format'>v4l2_vbi_format</link>">
-<!ENTITY v4l2-window "struct&nbsp;<link linkend='v4l2-window'>v4l2_window</link>">
-
-<!ENTITY media-device-info "struct&nbsp;<link linkend='media-device-info'>media_device_info</link>">
-<!ENTITY media-entity-desc "struct&nbsp;<link linkend='media-entity-desc'>media_entity_desc</link>">
-<!ENTITY media-links-enum "struct&nbsp;<link linkend='media-links-enum'>media_links_enum</link>">
-<!ENTITY media-pad-desc "struct&nbsp;<link linkend='media-pad-desc'>media_pad_desc</link>">
-<!ENTITY media-link-desc "struct&nbsp;<link linkend='media-link-desc'>media_link_desc</link>">
-
-<!-- Error Codes -->
-<!ENTITY EACCES "<errorcode>EACCES</errorcode> error code">
-<!ENTITY EAGAIN "<errorcode>EAGAIN</errorcode> error code">
-<!ENTITY EBADF "<errorcode>EBADF</errorcode> error code">
-<!ENTITY EBUSY "<errorcode>EBUSY</errorcode> error code">
-<!ENTITY EFAULT "<errorcode>EFAULT</errorcode> error code">
-<!ENTITY EIO "<errorcode>EIO</errorcode> error code">
-<!ENTITY EINTR "<errorcode>EINTR</errorcode> error code">
-<!ENTITY EINVAL "<errorcode>EINVAL</errorcode> error code">
-<!ENTITY ENFILE "<errorcode>ENFILE</errorcode> error code">
-<!ENTITY ENOMEM "<errorcode>ENOMEM</errorcode> error code">
-<!ENTITY ENOSPC "<errorcode>ENOSPC</errorcode> error code">
-<!ENTITY ENOTTY "<errorcode>ENOTTY</errorcode> error code">
-<!ENTITY ENXIO "<errorcode>ENXIO</errorcode> error code">
-<!ENTITY EMFILE "<errorcode>EMFILE</errorcode> error code">
-<!ENTITY EPERM "<errorcode>EPERM</errorcode> error code">
-<!ENTITY EPIPE "<errorcode>EPIPE</errorcode> error code">
-<!ENTITY ERANGE "<errorcode>ERANGE</errorcode> error code">
-
-<!-- Subsections -->
-<!ENTITY sub-biblio SYSTEM "v4l/biblio.xml">
-<!ENTITY sub-common SYSTEM "v4l/common.xml">
-<!ENTITY sub-planar-apis SYSTEM "v4l/planar-apis.xml">
-<!ENTITY sub-compat SYSTEM "v4l/compat.xml">
-<!ENTITY sub-controls SYSTEM "v4l/controls.xml">
-<!ENTITY sub-dev-capture SYSTEM "v4l/dev-capture.xml">
-<!ENTITY sub-dev-codec SYSTEM "v4l/dev-codec.xml">
-<!ENTITY sub-dev-event SYSTEM "v4l/dev-event.xml">
-<!ENTITY sub-dev-effect SYSTEM "v4l/dev-effect.xml">
-<!ENTITY sub-dev-osd SYSTEM "v4l/dev-osd.xml">
-<!ENTITY sub-dev-output SYSTEM "v4l/dev-output.xml">
-<!ENTITY sub-dev-overlay SYSTEM "v4l/dev-overlay.xml">
-<!ENTITY sub-dev-radio SYSTEM "v4l/dev-radio.xml">
-<!ENTITY sub-dev-raw-vbi SYSTEM "v4l/dev-raw-vbi.xml">
-<!ENTITY sub-dev-rds SYSTEM "v4l/dev-rds.xml">
-<!ENTITY sub-dev-sliced-vbi SYSTEM "v4l/dev-sliced-vbi.xml">
-<!ENTITY sub-dev-subdev SYSTEM "v4l/dev-subdev.xml">
-<!ENTITY sub-dev-teletext SYSTEM "v4l/dev-teletext.xml">
-<!ENTITY sub-driver SYSTEM "v4l/driver.xml">
-<!ENTITY sub-libv4l SYSTEM "v4l/libv4l.xml">
-<!ENTITY sub-lirc_device_interface SYSTEM "v4l/lirc_device_interface.xml">
-<!ENTITY sub-remote_controllers SYSTEM "v4l/remote_controllers.xml">
-<!ENTITY sub-fdl-appendix SYSTEM "v4l/fdl-appendix.xml">
-<!ENTITY sub-close SYSTEM "v4l/func-close.xml">
-<!ENTITY sub-ioctl SYSTEM "v4l/func-ioctl.xml">
-<!ENTITY sub-mmap SYSTEM "v4l/func-mmap.xml">
-<!ENTITY sub-munmap SYSTEM "v4l/func-munmap.xml">
-<!ENTITY sub-open SYSTEM "v4l/func-open.xml">
-<!ENTITY sub-poll SYSTEM "v4l/func-poll.xml">
-<!ENTITY sub-read SYSTEM "v4l/func-read.xml">
-<!ENTITY sub-select SYSTEM "v4l/func-select.xml">
-<!ENTITY sub-write SYSTEM "v4l/func-write.xml">
-<!ENTITY sub-io SYSTEM "v4l/io.xml">
-<!ENTITY sub-grey SYSTEM "v4l/pixfmt-grey.xml">
-<!ENTITY sub-m420 SYSTEM "v4l/pixfmt-m420.xml">
-<!ENTITY sub-nv12 SYSTEM "v4l/pixfmt-nv12.xml">
-<!ENTITY sub-nv12m SYSTEM "v4l/pixfmt-nv12m.xml">
-<!ENTITY sub-nv12mt SYSTEM "v4l/pixfmt-nv12mt.xml">
-<!ENTITY sub-nv16 SYSTEM "v4l/pixfmt-nv16.xml">
-<!ENTITY sub-packed-rgb SYSTEM "v4l/pixfmt-packed-rgb.xml">
-<!ENTITY sub-packed-yuv SYSTEM "v4l/pixfmt-packed-yuv.xml">
-<!ENTITY sub-sbggr16 SYSTEM "v4l/pixfmt-sbggr16.xml">
-<!ENTITY sub-sbggr8 SYSTEM "v4l/pixfmt-sbggr8.xml">
-<!ENTITY sub-sgbrg8 SYSTEM "v4l/pixfmt-sgbrg8.xml">
-<!ENTITY sub-sgrbg8 SYSTEM "v4l/pixfmt-sgrbg8.xml">
-<!ENTITY sub-uyvy SYSTEM "v4l/pixfmt-uyvy.xml">
-<!ENTITY sub-vyuy SYSTEM "v4l/pixfmt-vyuy.xml">
-<!ENTITY sub-y16 SYSTEM "v4l/pixfmt-y16.xml">
-<!ENTITY sub-y41p SYSTEM "v4l/pixfmt-y41p.xml">
-<!ENTITY sub-yuv410 SYSTEM "v4l/pixfmt-yuv410.xml">
-<!ENTITY sub-yuv411p SYSTEM "v4l/pixfmt-yuv411p.xml">
-<!ENTITY sub-yuv420 SYSTEM "v4l/pixfmt-yuv420.xml">
-<!ENTITY sub-yuv420m SYSTEM "v4l/pixfmt-yuv420m.xml">
-<!ENTITY sub-yuv422p SYSTEM "v4l/pixfmt-yuv422p.xml">
-<!ENTITY sub-yuyv SYSTEM "v4l/pixfmt-yuyv.xml">
-<!ENTITY sub-yvyu SYSTEM "v4l/pixfmt-yvyu.xml">
-<!ENTITY sub-srggb10 SYSTEM "v4l/pixfmt-srggb10.xml">
-<!ENTITY sub-srggb12 SYSTEM "v4l/pixfmt-srggb12.xml">
-<!ENTITY sub-srggb8 SYSTEM "v4l/pixfmt-srggb8.xml">
-<!ENTITY sub-y10 SYSTEM "v4l/pixfmt-y10.xml">
-<!ENTITY sub-y12 SYSTEM "v4l/pixfmt-y12.xml">
-<!ENTITY sub-y10b SYSTEM "v4l/pixfmt-y10b.xml">
-<!ENTITY sub-pixfmt SYSTEM "v4l/pixfmt.xml">
-<!ENTITY sub-cropcap SYSTEM "v4l/vidioc-cropcap.xml">
-<!ENTITY sub-dbg-g-register SYSTEM "v4l/vidioc-dbg-g-register.xml">
-<!ENTITY sub-encoder-cmd SYSTEM "v4l/vidioc-encoder-cmd.xml">
-<!ENTITY sub-enum-fmt SYSTEM "v4l/vidioc-enum-fmt.xml">
-<!ENTITY sub-enum-frameintervals SYSTEM "v4l/vidioc-enum-frameintervals.xml">
-<!ENTITY sub-enum-framesizes SYSTEM "v4l/vidioc-enum-framesizes.xml">
-<!ENTITY sub-enumaudio SYSTEM "v4l/vidioc-enumaudio.xml">
-<!ENTITY sub-enumaudioout SYSTEM "v4l/vidioc-enumaudioout.xml">
-<!ENTITY sub-enuminput SYSTEM "v4l/vidioc-enuminput.xml">
-<!ENTITY sub-enumoutput SYSTEM "v4l/vidioc-enumoutput.xml">
-<!ENTITY sub-enum-dv-presets SYSTEM "v4l/vidioc-enum-dv-presets.xml">
-<!ENTITY sub-g-dv-preset SYSTEM "v4l/vidioc-g-dv-preset.xml">
-<!ENTITY sub-query-dv-preset SYSTEM "v4l/vidioc-query-dv-preset.xml">
-<!ENTITY sub-g-dv-timings SYSTEM "v4l/vidioc-g-dv-timings.xml">
-<!ENTITY sub-enumstd SYSTEM "v4l/vidioc-enumstd.xml">
-<!ENTITY sub-g-audio SYSTEM "v4l/vidioc-g-audio.xml">
-<!ENTITY sub-g-audioout SYSTEM "v4l/vidioc-g-audioout.xml">
-<!ENTITY sub-dbg-g-chip-ident SYSTEM "v4l/vidioc-dbg-g-chip-ident.xml">
-<!ENTITY sub-g-crop SYSTEM "v4l/vidioc-g-crop.xml">
-<!ENTITY sub-g-ctrl SYSTEM "v4l/vidioc-g-ctrl.xml">
-<!ENTITY sub-g-enc-index SYSTEM "v4l/vidioc-g-enc-index.xml">
-<!ENTITY sub-g-ext-ctrls SYSTEM "v4l/vidioc-g-ext-ctrls.xml">
-<!ENTITY sub-g-fbuf SYSTEM "v4l/vidioc-g-fbuf.xml">
-<!ENTITY sub-g-fmt SYSTEM "v4l/vidioc-g-fmt.xml">
-<!ENTITY sub-g-frequency SYSTEM "v4l/vidioc-g-frequency.xml">
-<!ENTITY sub-g-input SYSTEM "v4l/vidioc-g-input.xml">
-<!ENTITY sub-g-jpegcomp SYSTEM "v4l/vidioc-g-jpegcomp.xml">
-<!ENTITY sub-g-modulator SYSTEM "v4l/vidioc-g-modulator.xml">
-<!ENTITY sub-g-output SYSTEM "v4l/vidioc-g-output.xml">
-<!ENTITY sub-g-parm SYSTEM "v4l/vidioc-g-parm.xml">
-<!ENTITY sub-g-priority SYSTEM "v4l/vidioc-g-priority.xml">
-<!ENTITY sub-g-sliced-vbi-cap SYSTEM "v4l/vidioc-g-sliced-vbi-cap.xml">
-<!ENTITY sub-g-std SYSTEM "v4l/vidioc-g-std.xml">
-<!ENTITY sub-g-tuner SYSTEM "v4l/vidioc-g-tuner.xml">
-<!ENTITY sub-log-status SYSTEM "v4l/vidioc-log-status.xml">
-<!ENTITY sub-overlay SYSTEM "v4l/vidioc-overlay.xml">
-<!ENTITY sub-qbuf SYSTEM "v4l/vidioc-qbuf.xml">
-<!ENTITY sub-querybuf SYSTEM "v4l/vidioc-querybuf.xml">
-<!ENTITY sub-querycap SYSTEM "v4l/vidioc-querycap.xml">
-<!ENTITY sub-queryctrl SYSTEM "v4l/vidioc-queryctrl.xml">
-<!ENTITY sub-querystd SYSTEM "v4l/vidioc-querystd.xml">
-<!ENTITY sub-reqbufs SYSTEM "v4l/vidioc-reqbufs.xml">
-<!ENTITY sub-s-hw-freq-seek SYSTEM "v4l/vidioc-s-hw-freq-seek.xml">
-<!ENTITY sub-streamon SYSTEM "v4l/vidioc-streamon.xml">
-<!ENTITY sub-subdev-enum-frame-interval SYSTEM "v4l/vidioc-subdev-enum-frame-interval.xml">
-<!ENTITY sub-subdev-enum-frame-size SYSTEM "v4l/vidioc-subdev-enum-frame-size.xml">
-<!ENTITY sub-subdev-enum-mbus-code SYSTEM "v4l/vidioc-subdev-enum-mbus-code.xml">
-<!ENTITY sub-subdev-formats SYSTEM "v4l/subdev-formats.xml">
-<!ENTITY sub-subdev-g-crop SYSTEM "v4l/vidioc-subdev-g-crop.xml">
-<!ENTITY sub-subdev-g-fmt SYSTEM "v4l/vidioc-subdev-g-fmt.xml">
-<!ENTITY sub-subdev-g-frame-interval SYSTEM "v4l/vidioc-subdev-g-frame-interval.xml">
-<!ENTITY sub-capture-c SYSTEM "v4l/capture.c.xml">
-<!ENTITY sub-keytable-c SYSTEM "v4l/keytable.c.xml">
-<!ENTITY sub-v4l2grab-c SYSTEM "v4l/v4l2grab.c.xml">
-<!ENTITY sub-videodev2-h SYSTEM "v4l/videodev2.h.xml">
-<!ENTITY sub-v4l2 SYSTEM "v4l/v4l2.xml">
-<!ENTITY sub-dqevent SYSTEM "v4l/vidioc-dqevent.xml">
-<!ENTITY sub-subscribe-event SYSTEM "v4l/vidioc-subscribe-event.xml">
-<!ENTITY sub-intro SYSTEM "dvb/intro.xml">
-<!ENTITY sub-frontend SYSTEM "dvb/frontend.xml">
-<!ENTITY sub-dvbproperty SYSTEM "dvb/dvbproperty.xml">
-<!ENTITY sub-demux SYSTEM "dvb/demux.xml">
-<!ENTITY sub-video SYSTEM "dvb/video.xml">
-<!ENTITY sub-audio SYSTEM "dvb/audio.xml">
-<!ENTITY sub-ca SYSTEM "dvb/ca.xml">
-<!ENTITY sub-net SYSTEM "dvb/net.xml">
-<!ENTITY sub-kdapi SYSTEM "dvb/kdapi.xml">
-<!ENTITY sub-examples SYSTEM "dvb/examples.xml">
-<!ENTITY sub-frontend-h SYSTEM "dvb/frontend.h.xml">
-<!ENTITY sub-dvbapi SYSTEM "dvb/dvbapi.xml">
-<!ENTITY sub-media SYSTEM "media.xml">
-<!ENTITY sub-media-entities SYSTEM "media-entities.tmpl">
-<!ENTITY sub-media-indices SYSTEM "media-indices.tmpl">
-
-<!ENTITY sub-media-controller SYSTEM "v4l/media-controller.xml">
-<!ENTITY sub-media-func-open SYSTEM "v4l/media-func-open.xml">
-<!ENTITY sub-media-func-close SYSTEM "v4l/media-func-close.xml">
-<!ENTITY sub-media-func-ioctl SYSTEM "v4l/media-func-ioctl.xml">
-<!ENTITY sub-media-ioc-device-info SYSTEM "v4l/media-ioc-device-info.xml">
-<!ENTITY sub-media-ioc-enum-entities SYSTEM "v4l/media-ioc-enum-entities.xml">
-<!ENTITY sub-media-ioc-enum-links SYSTEM "v4l/media-ioc-enum-links.xml">
-<!ENTITY sub-media-ioc-setup-link SYSTEM "v4l/media-ioc-setup-link.xml">
-
-<!-- Function Reference -->
-<!ENTITY close SYSTEM "v4l/func-close.xml">
-<!ENTITY ioctl SYSTEM "v4l/func-ioctl.xml">
-<!ENTITY mmap SYSTEM "v4l/func-mmap.xml">
-<!ENTITY munmap SYSTEM "v4l/func-munmap.xml">
-<!ENTITY open SYSTEM "v4l/func-open.xml">
-<!ENTITY poll SYSTEM "v4l/func-poll.xml">
-<!ENTITY read SYSTEM "v4l/func-read.xml">
-<!ENTITY select SYSTEM "v4l/func-select.xml">
-<!ENTITY write SYSTEM "v4l/func-write.xml">
-<!ENTITY grey SYSTEM "v4l/pixfmt-grey.xml">
-<!ENTITY nv12 SYSTEM "v4l/pixfmt-nv12.xml">
-<!ENTITY nv12m SYSTEM "v4l/pixfmt-nv12m.xml">
-<!ENTITY nv16 SYSTEM "v4l/pixfmt-nv16.xml">
-<!ENTITY packed-rgb SYSTEM "v4l/pixfmt-packed-rgb.xml">
-<!ENTITY packed-yuv SYSTEM "v4l/pixfmt-packed-yuv.xml">
-<!ENTITY sbggr16 SYSTEM "v4l/pixfmt-sbggr16.xml">
-<!ENTITY sbggr8 SYSTEM "v4l/pixfmt-sbggr8.xml">
-<!ENTITY sgbrg8 SYSTEM "v4l/pixfmt-sgbrg8.xml">
-<!ENTITY sgrbg8 SYSTEM "v4l/pixfmt-sgrbg8.xml">
-<!ENTITY uyvy SYSTEM "v4l/pixfmt-uyvy.xml">
-<!ENTITY vyuy SYSTEM "v4l/pixfmt-vyuy.xml">
-<!ENTITY y16 SYSTEM "v4l/pixfmt-y16.xml">
-<!ENTITY y41p SYSTEM "v4l/pixfmt-y41p.xml">
-<!ENTITY yuv410 SYSTEM "v4l/pixfmt-yuv410.xml">
-<!ENTITY yuv411p SYSTEM "v4l/pixfmt-yuv411p.xml">
-<!ENTITY yuv420 SYSTEM "v4l/pixfmt-yuv420.xml">
-<!ENTITY yuv420m SYSTEM "v4l/pixfmt-yuv420m.xml">
-<!ENTITY yuv422p SYSTEM "v4l/pixfmt-yuv422p.xml">
-<!ENTITY yuyv SYSTEM "v4l/pixfmt-yuyv.xml">
-<!ENTITY yvyu SYSTEM "v4l/pixfmt-yvyu.xml">
-<!ENTITY srggb10 SYSTEM "v4l/pixfmt-srggb10.xml">
-<!ENTITY srggb8 SYSTEM "v4l/pixfmt-srggb8.xml">
-<!ENTITY y10 SYSTEM "v4l/pixfmt-y10.xml">
-<!ENTITY cropcap SYSTEM "v4l/vidioc-cropcap.xml">
-<!ENTITY dbg-g-register SYSTEM "v4l/vidioc-dbg-g-register.xml">
-<!ENTITY encoder-cmd SYSTEM "v4l/vidioc-encoder-cmd.xml">
-<!ENTITY enum-fmt SYSTEM "v4l/vidioc-enum-fmt.xml">
-<!ENTITY enum-frameintervals SYSTEM "v4l/vidioc-enum-frameintervals.xml">
-<!ENTITY enum-framesizes SYSTEM "v4l/vidioc-enum-framesizes.xml">
-<!ENTITY enumaudio SYSTEM "v4l/vidioc-enumaudio.xml">
-<!ENTITY enumaudioout SYSTEM "v4l/vidioc-enumaudioout.xml">
-<!ENTITY enuminput SYSTEM "v4l/vidioc-enuminput.xml">
-<!ENTITY enumoutput SYSTEM "v4l/vidioc-enumoutput.xml">
-<!ENTITY enum-dv-presets SYSTEM "v4l/vidioc-enum-dv-presets.xml">
-<!ENTITY g-dv-preset SYSTEM "v4l/vidioc-g-dv-preset.xml">
-<!ENTITY query-dv-preset SYSTEM "v4l/vidioc-query-dv-preset.xml">
-<!ENTITY g-dv-timings SYSTEM "v4l/vidioc-g-dv-timings.xml">
-<!ENTITY enumstd SYSTEM "v4l/vidioc-enumstd.xml">
-<!ENTITY g-audio SYSTEM "v4l/vidioc-g-audio.xml">
-<!ENTITY g-audioout SYSTEM "v4l/vidioc-g-audioout.xml">
-<!ENTITY dbg-g-chip-ident SYSTEM "v4l/vidioc-dbg-g-chip-ident.xml">
-<!ENTITY g-crop SYSTEM "v4l/vidioc-g-crop.xml">
-<!ENTITY g-ctrl SYSTEM "v4l/vidioc-g-ctrl.xml">
-<!ENTITY g-enc-index SYSTEM "v4l/vidioc-g-enc-index.xml">
-<!ENTITY g-ext-ctrls SYSTEM "v4l/vidioc-g-ext-ctrls.xml">
-<!ENTITY g-fbuf SYSTEM "v4l/vidioc-g-fbuf.xml">
-<!ENTITY g-fmt SYSTEM "v4l/vidioc-g-fmt.xml">
-<!ENTITY g-frequency SYSTEM "v4l/vidioc-g-frequency.xml">
-<!ENTITY g-input SYSTEM "v4l/vidioc-g-input.xml">
-<!ENTITY g-jpegcomp SYSTEM "v4l/vidioc-g-jpegcomp.xml">
-<!ENTITY g-modulator SYSTEM "v4l/vidioc-g-modulator.xml">
-<!ENTITY g-output SYSTEM "v4l/vidioc-g-output.xml">
-<!ENTITY g-parm SYSTEM "v4l/vidioc-g-parm.xml">
-<!ENTITY g-priority SYSTEM "v4l/vidioc-g-priority.xml">
-<!ENTITY g-sliced-vbi-cap SYSTEM "v4l/vidioc-g-sliced-vbi-cap.xml">
-<!ENTITY g-std SYSTEM "v4l/vidioc-g-std.xml">
-<!ENTITY g-tuner SYSTEM "v4l/vidioc-g-tuner.xml">
-<!ENTITY log-status SYSTEM "v4l/vidioc-log-status.xml">
-<!ENTITY overlay SYSTEM "v4l/vidioc-overlay.xml">
-<!ENTITY qbuf SYSTEM "v4l/vidioc-qbuf.xml">
-<!ENTITY querybuf SYSTEM "v4l/vidioc-querybuf.xml">
-<!ENTITY querycap SYSTEM "v4l/vidioc-querycap.xml">
-<!ENTITY queryctrl SYSTEM "v4l/vidioc-queryctrl.xml">
-<!ENTITY querystd SYSTEM "v4l/vidioc-querystd.xml">
-<!ENTITY reqbufs SYSTEM "v4l/vidioc-reqbufs.xml">
-<!ENTITY s-hw-freq-seek SYSTEM "v4l/vidioc-s-hw-freq-seek.xml">
-<!ENTITY streamon SYSTEM "v4l/vidioc-streamon.xml">
-<!ENTITY dqevent SYSTEM "v4l/vidioc-dqevent.xml">
-<!ENTITY subscribe_event SYSTEM "v4l/vidioc-subscribe-event.xml">
diff --git a/Documentation/DocBook/media-indices.tmpl b/Documentation/DocBook/media-indices.tmpl
deleted file mode 100644 (file)
index 78d6031..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-<!-- Generated file! Do not edit. -->
-
-<index><title>List of Types</title>
-<indexentry><primaryie><link linkend='v4l2-std-id'>v4l2_std_id</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-buf-type'>v4l2_buf_type</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-colorspace'>v4l2_colorspace</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-ctrl-type'>v4l2_ctrl_type</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-exposure-auto-type'>v4l2_exposure_auto_type</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-field'>v4l2_field</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-frmivaltypes'>v4l2_frmivaltypes</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-frmsizetypes'>v4l2_frmsizetypes</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-memory'>v4l2_memory</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-audio-ac3-bitrate'>v4l2_mpeg_audio_ac3_bitrate</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-audio-crc'>v4l2_mpeg_audio_crc</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-audio-emphasis'>v4l2_mpeg_audio_emphasis</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-audio-encoding'>v4l2_mpeg_audio_encoding</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-audio-l1-bitrate'>v4l2_mpeg_audio_l1_bitrate</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-audio-l2-bitrate'>v4l2_mpeg_audio_l2_bitrate</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-audio-l3-bitrate'>v4l2_mpeg_audio_l3_bitrate</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-audio-mode'>v4l2_mpeg_audio_mode</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-audio-mode-extension'>v4l2_mpeg_audio_mode_extension</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-audio-sampling-freq'>v4l2_mpeg_audio_sampling_freq</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='chroma-spatial-filter-type'>v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='luma-spatial-filter-type'>v4l2_mpeg_cx2341x_video_luma_spatial_filter_type</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-cx2341x-video-median-filter-type'>v4l2_mpeg_cx2341x_video_median_filter_type</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-cx2341x-video-spatial-filter-mode'>v4l2_mpeg_cx2341x_video_spatial_filter_mode</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-cx2341x-video-temporal-filter-mode'>v4l2_mpeg_cx2341x_video_temporal_filter_mode</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-stream-type'>v4l2_mpeg_stream_type</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-stream-vbi-fmt'>v4l2_mpeg_stream_vbi_fmt</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-video-aspect'>v4l2_mpeg_video_aspect</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-video-bitrate-mode'>v4l2_mpeg_video_bitrate_mode</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-video-encoding'>v4l2_mpeg_video_encoding</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-power-line-frequency'>v4l2_power_line_frequency</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-priority'>v4l2_priority</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-tuner-type'>v4l2_tuner_type</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-preemphasis'>v4l2_preemphasis</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-audio'>v4l2_audio</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-audioout'>v4l2_audioout</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-bt-timings'>v4l2_bt_timings</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-buffer'>v4l2_buffer</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-capability'>v4l2_capability</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-captureparm'>v4l2_captureparm</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-clip'>v4l2_clip</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-control'>v4l2_control</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-crop'>v4l2_crop</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-cropcap'>v4l2_cropcap</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-dbg-chip-ident'>v4l2_dbg_chip_ident</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-dbg-match'>v4l2_dbg_match</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-dbg-register'>v4l2_dbg_register</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-dv-enum-preset'>v4l2_dv_enum_preset</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-dv-preset'>v4l2_dv_preset</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-dv-timings'>v4l2_dv_timings</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-enc-idx'>v4l2_enc_idx</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-enc-idx-entry'>v4l2_enc_idx_entry</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-encoder-cmd'>v4l2_encoder_cmd</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-ext-control'>v4l2_ext_control</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-ext-controls'>v4l2_ext_controls</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-fmtdesc'>v4l2_fmtdesc</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-format'>v4l2_format</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-fract'>v4l2_fract</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-framebuffer'>v4l2_framebuffer</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-frequency'>v4l2_frequency</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-frmival-stepwise'>v4l2_frmival_stepwise</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-frmivalenum'>v4l2_frmivalenum</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-frmsize-discrete'>v4l2_frmsize_discrete</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-frmsize-stepwise'>v4l2_frmsize_stepwise</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-frmsizeenum'>v4l2_frmsizeenum</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-hw-freq-seek'>v4l2_hw_freq_seek</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-input'>v4l2_input</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-jpegcompression'>v4l2_jpegcompression</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-modulator'>v4l2_modulator</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-mpeg-vbi-fmt-ivtv'>v4l2_mpeg_vbi_fmt_ivtv</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-output'>v4l2_output</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-outputparm'>v4l2_outputparm</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-pix-format'>v4l2_pix_format</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-queryctrl'>v4l2_queryctrl</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-querymenu'>v4l2_querymenu</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-rect'>v4l2_rect</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-requestbuffers'>v4l2_requestbuffers</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-sliced-vbi-cap'>v4l2_sliced_vbi_cap</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-sliced-vbi-data'>v4l2_sliced_vbi_data</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-sliced-vbi-format'>v4l2_sliced_vbi_format</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-standard'>v4l2_standard</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-streamparm'>v4l2_streamparm</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-timecode'>v4l2_timecode</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-tuner'>v4l2_tuner</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-vbi-format'>v4l2_vbi_format</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-window'>v4l2_window</link></primaryie></indexentry>
-</index>
diff --git a/Documentation/DocBook/media/Makefile b/Documentation/DocBook/media/Makefile
new file mode 100644 (file)
index 0000000..6628b4b
--- /dev/null
@@ -0,0 +1,386 @@
+###
+# Media build rules - Auto-generates media contents/indexes and *.h xml's
+#
+
+SHELL=/bin/bash
+
+MEDIA_OBJ_DIR=$(objtree)/Documentation/DocBook/
+MEDIA_SRC_DIR=$(srctree)/Documentation/DocBook/media
+
+MEDIA_TEMP =  media-entities.tmpl \
+             media-indices.tmpl \
+             videodev2.h.xml \
+             v4l2.xml \
+             audio.h.xml \
+             ca.h.xml \
+             dmx.h.xml \
+             frontend.h.xml \
+             net.h.xml \
+             video.h.xml \
+
+IMGFILES := $(patsubst %.b64,%, $(notdir $(shell ls $(MEDIA_SRC_DIR)/*.b64)))
+OBJIMGFILES := $(addprefix $(MEDIA_OBJ_DIR)/, $(IMGFILES))
+GENFILES := $(addprefix $(MEDIA_OBJ_DIR)/, $(MEDIA_TEMP))
+
+PHONY += cleanmediadocs
+
+cleanmediadocs:
+       -@rm `find $(MEDIA_OBJ_DIR) -type l` $(GENFILES) $(OBJIMGFILES) 2>/dev/null
+
+$(obj)/media_api.xml: $(GENFILES) FORCE
+
+#$(MEDIA_OBJ_DIR)/media_api.html: $(MEDIA_OBJ_DIR)/media_api.xml
+#$(MEDIA_OBJ_DIR)/media_api.pdf: $(MEDIA_OBJ_DIR)/media_api.xml
+#$(MEDIA_OBJ_DIR)/media_api.ps: $(MEDIA_OBJ_DIR)/media_api.xml
+
+V4L_SGMLS = \
+       $(shell ls $(MEDIA_SRC_DIR)/v4l/*.xml|perl -ne 'print "$$1 " if (m,.*/(.*)\n,)') \
+       capture.c.xml \
+       keytable.c.xml \
+       v4l2grab.c.xml
+
+DVB_SGMLS = \
+       $(shell ls $(MEDIA_SRC_DIR)/dvb/*.xml|perl -ne 'print "$$1 " if (m,.*/(.*)\n,)')
+
+MEDIA_SGMLS =  $(addprefix ./,$(V4L_SGMLS)) $(addprefix ./,$(DVB_SGMLS)) $(addprefix ./,$(MEDIA_TEMP))
+
+FUNCS = \
+       close \
+       ioctl \
+       mmap \
+       munmap \
+       open \
+       poll \
+       read \
+       select \
+       write \
+
+IOCTLS = \
+       $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/linux/videodev2.h) \
+       $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/linux/dvb/audio.h) \
+       $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/linux/dvb/ca.h) \
+       $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/linux/dvb/dmx.h) \
+       $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/linux/dvb/frontend.h) \
+       $(shell perl -ne 'print "$$1 " if /\#define\s+([A-Z][^\s]+)\s+_IO/' $(srctree)/include/linux/dvb/net.h) \
+       $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/linux/dvb/video.h) \
+       $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/linux/media.h) \
+       $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/linux/v4l2-subdev.h) \
+       VIDIOC_SUBDEV_G_FRAME_INTERVAL \
+       VIDIOC_SUBDEV_S_FRAME_INTERVAL \
+       VIDIOC_SUBDEV_ENUM_MBUS_CODE \
+       VIDIOC_SUBDEV_ENUM_FRAME_SIZE \
+       VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL \
+
+TYPES = \
+       $(shell perl -ne 'print "$$1 " if /^typedef\s+[^\s]+\s+([^\s]+)\;/' $(srctree)/include/linux/videodev2.h) \
+       $(shell perl -ne 'print "$$1 " if /^}\s+([a-z0-9_]+_t)/' $(srctree)/include/linux/dvb/frontend.h)
+
+ENUMS = \
+       $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/videodev2.h) \
+       $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/dvb/audio.h) \
+       $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/dvb/ca.h) \
+       $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/dvb/dmx.h) \
+       $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/dvb/frontend.h) \
+       $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/dvb/net.h) \
+       $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/dvb/video.h) \
+       $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/media.h) \
+       $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/v4l2-mediabus.h) \
+       $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/v4l2-subdev.h)
+
+STRUCTS = \
+       $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/linux/videodev2.h) \
+       $(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s\{]+)\s*/)' $(srctree)/include/linux/dvb/audio.h) \
+       $(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s]+)\s+/)' $(srctree)/include/linux/dvb/ca.h) \
+       $(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s]+)\s+/)' $(srctree)/include/linux/dvb/dmx.h) \
+       $(shell perl -ne 'print "$$1 " if (!/dtv\_cmds\_h/ && /^struct\s+([^\s]+)\s+/)' $(srctree)/include/linux/dvb/frontend.h) \
+       $(shell perl -ne 'print "$$1 " if (/^struct\s+([A-Z][^\s]+)\s+/)' $(srctree)/include/linux/dvb/net.h) \
+       $(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s]+)\s+/)' $(srctree)/include/linux/dvb/video.h) \
+       $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/linux/media.h) \
+       $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/linux/v4l2-subdev.h) \
+       $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/linux/v4l2-mediabus.h)
+
+ERRORS = \
+       E2BIG \
+       EACCES \
+       EAGAIN \
+       EBADF \
+       EBADFD \
+       EBADR \
+       EBADRQC \
+       EBUSY \
+       ECHILD \
+       ECONNRESET \
+       EDEADLK \
+       EDOM \
+       EEXIST \
+       EFAULT \
+       EFBIG \
+       EILSEQ \
+       EINIT \
+       EINPROGRESS \
+       EINTR \
+       EINVAL \
+       EIO \
+       EMFILE \
+       ENFILE \
+       ENOBUFS \
+       ENODATA \
+       ENODEV \
+       ENOENT \
+       ENOIOCTLCMD \
+       ENOMEM \
+       ENOSPC \
+       ENOSR \
+       ENOSYS \
+       ENOTSUP \
+       ENOTSUPP \
+       ENOTTY \
+       ENXIO \
+       EOPNOTSUPP \
+       EOVERFLOW \
+       EPERM \
+       EPIPE \
+       EPROTO \
+       ERANGE \
+       EREMOTE \
+       EREMOTEIO \
+       ERESTART \
+       ERESTARTSYS \
+       ESHUTDOWN \
+       ESPIPE \
+       ETIME \
+       ETIMEDOUT \
+       EUSERS \
+       EWOULDBLOCK \
+       EXDEV \
+
+ESCAPE = \
+       -e "s/&/\\&amp;/g" \
+       -e "s/</\\&lt;/g" \
+       -e "s/>/\\&gt;/g"
+
+FILENAME = \
+       -e s,"^[^\/]*/",, \
+       -e s/"\\.xml"// \
+       -e s/"\\.tmpl"// \
+       -e s/\\\./-/g \
+       -e s/"^func-"// \
+       -e s/"^pixfmt-"// \
+       -e s/"^vidioc-"//
+
+# Generate references to these structs in videodev2.h.xml.
+DOCUMENTED = \
+       -e "s/\(enum *\)v4l2_mpeg_cx2341x_video_\([a-z]*_spatial_filter_type\)/\1<link linkend=\"\2\">v4l2_mpeg_cx2341x_video_\2<\/link>/g" \
+       -e "s/\(\(enum\|struct\) *\)\(v4l2_[a-zA-Z0-9_]*\)/\1<link linkend=\"\3\">\3<\/link>/g" \
+       -e "s/\(V4L2_PIX_FMT_[A-Z0-9_]\+\) /<link linkend=\"\1\">\1<\/link> /g" \
+       -e ":a;s/\(linkend=\".*\)_\(.*\">\)/\1-\2/;ta" \
+       -e "s/v4l2\-mpeg\-vbi\-ITV0/v4l2-mpeg-vbi-itv0-1/g"
+
+DVB_DOCUMENTED = \
+       -e "s/\(linkend\=\"\)FE_SET_PROPERTY/\1FE_GET_PROPERTY/g" \
+       -e "s,\(struct\s\+\)\([a-z0-9_]\+\)\(\s\+{\),\1\<link linkend=\"\2\">\2\<\/link\>\3,g" \
+       -e "s,\(}\s\+\)\([a-z0-9_]\+_t\+\),\1\<link linkend=\"\2\">\2\<\/link\>,g" \
+       -e "s,\(define\s\+\)\(DTV_[A-Z0-9_]\+\)\(\s\+[0-9]\+\),\1\<link linkend=\"\2\">\2\<\/link\>\3,g" \
+       -e "s,<link\s\+linkend=\".*\">\(DTV_IOCTL_MAX_MSGS\|dtv_cmds_h\|__.*_old\)<\/link>,\1,g" \
+       -e ":a;s/\(linkend=\".*\)_\(.*\">\)/\1-\2/;ta" \
+       -e "s,\(audio-mixer\|audio-karaoke\|audio-status\|ca-slot-info\|ca-descr-info\|ca-caps\|ca-msg\|ca-descr\|ca-pid\|dmx-filter\|dmx-caps\|video-system\|video-highlight\|video-spu\|video-spu-palette\|video-navi-pack\)-t,\1,g" \
+       -e "s,DTV-ISDBT-LAYER[A-C],DTV-ISDBT-LAYER,g" \
+       -e "s,\(define\s\+\)\([A-Z0-9_]\+\)\(\s\+_IO\),\1\<link linkend=\"\2\">\2\<\/link\>\3,g" \
+       -e "s,<link\s\+linkend=\".*\">\(__.*_OLD\)<\/link>,\1,g" \
+
+#
+# Media targets and dependencies
+#
+
+install_media_images = \
+       $(Q)cp $(OBJIMGFILES) $(MEDIA_OBJ_DIR)/media_api
+
+$(MEDIA_OBJ_DIR)/%: $(MEDIA_SRC_DIR)/%.b64
+       $(Q)base64 -d $< >$@
+
+$(MEDIA_OBJ_DIR)/v4l2.xml: $(OBJIMGFILES)
+       @$($(quiet)gen_xml)
+       @(ln -sf $(MEDIA_SRC_DIR)/v4l/*xml $(MEDIA_OBJ_DIR)/)
+       @(ln -sf $(MEDIA_SRC_DIR)/dvb/*xml $(MEDIA_OBJ_DIR)/)
+
+$(MEDIA_OBJ_DIR)/videodev2.h.xml: $(srctree)/include/linux/videodev2.h $(MEDIA_OBJ_DIR)/v4l2.xml
+       @$($(quiet)gen_xml)
+       @(                                      \
+       echo "<programlisting>") > $@
+       @(                                      \
+       expand --tabs=8 < $< |                  \
+         sed $(ESCAPE) $(DOCUMENTED) |         \
+         sed 's/i\.e\./&ie;/') >> $@
+       @(                                      \
+       echo "</programlisting>") >> $@
+
+$(MEDIA_OBJ_DIR)/audio.h.xml: $(srctree)/include/linux/dvb/audio.h $(MEDIA_OBJ_DIR)/v4l2.xml
+       @$($(quiet)gen_xml)
+       @(                                      \
+       echo "<programlisting>") > $@
+       @(                                      \
+       expand --tabs=8 < $< |                  \
+         sed $(ESCAPE) $(DVB_DOCUMENTED) |     \
+         sed 's/i\.e\./&ie;/') >> $@
+       @(                                      \
+       echo "</programlisting>") >> $@
+
+$(MEDIA_OBJ_DIR)/ca.h.xml: $(srctree)/include/linux/dvb/ca.h $(MEDIA_OBJ_DIR)/v4l2.xml
+       @$($(quiet)gen_xml)
+       @(                                      \
+       echo "<programlisting>") > $@
+       @(                                      \
+       expand --tabs=8 < $< |                  \
+         sed $(ESCAPE) $(DVB_DOCUMENTED) |     \
+         sed 's/i\.e\./&ie;/') >> $@
+       @(                                      \
+       echo "</programlisting>") >> $@
+
+$(MEDIA_OBJ_DIR)/dmx.h.xml: $(srctree)/include/linux/dvb/dmx.h $(MEDIA_OBJ_DIR)/v4l2.xml
+       @$($(quiet)gen_xml)
+       @(                                      \
+       echo "<programlisting>") > $@
+       @(                                      \
+       expand --tabs=8 < $< |                  \
+         sed $(ESCAPE) $(DVB_DOCUMENTED) |     \
+         sed 's/i\.e\./&ie;/') >> $@
+       @(                                      \
+       echo "</programlisting>") >> $@
+
+$(MEDIA_OBJ_DIR)/frontend.h.xml: $(srctree)/include/linux/dvb/frontend.h $(MEDIA_OBJ_DIR)/v4l2.xml
+       @$($(quiet)gen_xml)
+       @(                                      \
+       echo "<programlisting>") > $@
+       @(                                      \
+       expand --tabs=8 < $< |                  \
+         sed $(ESCAPE) $(DVB_DOCUMENTED) |     \
+         sed 's/i\.e\./&ie;/') >> $@
+       @(                                      \
+       echo "</programlisting>") >> $@
+
+$(MEDIA_OBJ_DIR)/net.h.xml: $(srctree)/include/linux/dvb/net.h $(MEDIA_OBJ_DIR)/v4l2.xml
+       @$($(quiet)gen_xml)
+       @(                                      \
+       echo "<programlisting>") > $@
+       @(                                      \
+       expand --tabs=8 < $< |                  \
+         sed $(ESCAPE) $(DVB_DOCUMENTED) |     \
+         sed 's/i\.e\./&ie;/') >> $@
+       @(                                      \
+       echo "</programlisting>") >> $@
+
+$(MEDIA_OBJ_DIR)/video.h.xml: $(srctree)/include/linux/dvb/video.h $(MEDIA_OBJ_DIR)/v4l2.xml
+       @$($(quiet)gen_xml)
+       @(                                      \
+       echo "<programlisting>") > $@
+       @(                                      \
+       expand --tabs=8 < $< |                  \
+         sed $(ESCAPE) $(DVB_DOCUMENTED) |     \
+         sed 's/i\.e\./&ie;/') >> $@
+       @(                                      \
+       echo "</programlisting>") >> $@
+
+$(MEDIA_OBJ_DIR)/media-entities.tmpl: $(MEDIA_OBJ_DIR)/v4l2.xml
+       @$($(quiet)gen_xml)
+       @(                                                              \
+       echo "<!-- Generated file! Do not edit. -->") >$@
+       @(                                                              \
+       echo -e "\n<!-- Functions -->") >>$@
+       @(                                                              \
+       for ident in $(FUNCS) ; do                                      \
+         entity=`echo $$ident | tr _ -` ;                              \
+         echo "<!ENTITY func-$$entity \"<link"                         \
+           "linkend='func-$$entity'><function>$$ident()</function></link>\">" \
+         >>$@ ;                                                        \
+       done)
+       @(                                                              \
+       echo -e "\n<!-- Ioctls -->") >>$@
+       @(                                                              \
+       for ident in $(IOCTLS) ; do                                     \
+         entity=`echo $$ident | tr _ -` ;                              \
+         id=`grep "<refname>$$ident" $(MEDIA_OBJ_DIR)/vidioc-*.xml | sed -r s,"^.*/(.*).xml.*","\1",` ; \
+         echo "<!ENTITY $$entity \"<link"                              \
+           "linkend='$$id'><constant>$$ident</constant></link>\">"     \
+         >>$@ ;                                                        \
+       done)
+       @(                                                              \
+       echo -e "\n<!-- Types -->") >>$@
+       @(                                                              \
+       for ident in $(TYPES) ; do                                      \
+         entity=`echo $$ident | tr _ -` ;                              \
+         echo "<!ENTITY $$entity \"<link"                              \
+           "linkend='$$entity'>$$ident</link>\">" >>$@ ;               \
+       done)
+       @(                                                              \
+       echo -e "\n<!-- Enums -->") >>$@
+       @(                                                              \
+       for ident in $(ENUMS) ; do                                      \
+         entity=`echo $$ident | sed -e "s/v4l2_mpeg_cx2341x_video_\([a-z]*_spatial_filter_type\)/\1/" | tr _ -` ; \
+         echo "<!ENTITY $$entity \"enum&nbsp;<link"                    \
+           "linkend='$$entity'>$$ident</link>\">" >>$@ ;               \
+       done)
+       @(                                                              \
+       echo -e "\n<!-- Structures -->") >>$@
+       @(                                                              \
+       for ident in $(STRUCTS) ; do                                    \
+         entity=`echo $$ident | tr _ - | sed s/v4l2-mpeg-vbi-ITV0/v4l2-mpeg-vbi-itv0-1/g` ; \
+         echo "<!ENTITY $$entity \"struct&nbsp;<link"                  \
+           "linkend='$$entity'>$$ident</link>\">" >>$@ ;               \
+       done)
+       @(                                                              \
+       echo -e "\n<!-- Error Codes -->") >>$@
+       @(                                                              \
+       for ident in $(ERRORS) ; do                                     \
+         echo "<!ENTITY $$ident \"<errorcode>$$ident</errorcode>"      \
+           "error code\">" >>$@ ;                                      \
+       done)
+       @(                                                              \
+       echo -e "\n<!-- Subsections -->") >>$@
+       @(                                                              \
+       for file in $(MEDIA_SGMLS) ; do                                 \
+         entity=`echo "$$file" | sed $(FILENAME) -e s/"^([^-]*)"/sub\1/` ; \
+         if ! echo "$$file" |                                          \
+           grep -q -E -e '^(func|vidioc|pixfmt)-' ; then               \
+           echo "<!ENTITY sub-$$entity SYSTEM \"$$file\">" >>$@ ;      \
+         fi ;                                                          \
+       done)
+       @(                                                              \
+       echo -e "\n<!-- Function Reference -->") >>$@
+       @(                                                              \
+       for file in $(MEDIA_SGMLS) ; do                                 \
+         if echo "$$file" |                                            \
+           grep -q -E -e '(func|vidioc|pixfmt)-' ; then                \
+           entity=`echo "$$file" |sed $(FILENAME)` ;                   \
+           echo "<!ENTITY $$entity SYSTEM \"$$file\">" >>$@ ;  \
+         fi ;                                                          \
+       done)
+
+# Jade can auto-generate a list-of-tables, which includes all structs,
+# but we only want data types, all types, and sorted please.
+$(MEDIA_OBJ_DIR)/media-indices.tmpl: $(MEDIA_OBJ_DIR)/v4l2.xml
+       @$($(quiet)gen_xml)
+       @(                                                              \
+       echo "<!-- Generated file! Do not edit. -->") >$@
+       @(                                                              \
+       echo -e "\n<index><title>List of Types</title>") >>$@
+       @(                                                              \
+       for ident in $(TYPES) ; do                                      \
+         id=`echo $$ident | tr _ -` ;                                  \
+         echo "<indexentry><primaryie><link"                           \
+           "linkend='$$id'>$$ident</link></primaryie></indexentry>" >>$@ ; \
+       done)
+       @(                                                              \
+       for ident in $(ENUMS) ; do                                      \
+         id=`echo $$ident | sed -e "s/v4l2_mpeg_cx2341x_video_\([a-z]*_spatial_filter_type\)/\1/" | tr _ -`; \
+         echo "<indexentry><primaryie>enum&nbsp;<link"                 \
+           "linkend='$$id'>$$ident</link></primaryie></indexentry>" >>$@ ; \
+       done)
+       @(                                                              \
+       for ident in $(STRUCTS) ; do                                    \
+         id=`echo $$ident | tr _ - | sed s/v4l2-mpeg-vbi-ITV0/v4l2-mpeg-vbi-itv0-1/g` ; \
+         echo "<indexentry><primaryie>struct&nbsp;<link"               \
+           "linkend='$$id'>$$ident</link></primaryie></indexentry>" >>$@ ; \
+       done)
+       @(                                                              \
+       echo "</index>") >>$@
+
diff --git a/Documentation/DocBook/media/bayer.png.b64 b/Documentation/DocBook/media/bayer.png.b64
new file mode 100644 (file)
index 0000000..ccdf2bc
--- /dev/null
@@ -0,0 +1,171 @@
+iVBORw0KGgoAAAANSUhEUgAAAlgAAACqCAMAAABGfcHVAAAAAXNSR0IArs4c6QAAAwBQTFRFAAIA
+CAICAAQVEQEBAgsAJgECAAogAwsTAQopHQYBNAEAAAxNARQAERIQAhoDABwAABZEHRQKGRYKQw0F
+ACMBACUAERwpHR4cVRAFBR5rZhADACR2JiIhBDAGAiWGgQ4AcxQABDYACSeQMSYlJykmESxYlQ4A
+PSYZIS05OSsJHS5JOC8kAEMDUC8SADXLNDUzADbEAEsAADX/2RABCFIAAD/qxB0AAD//BFgAK0Vp
+WT4r3hwA3RsTRERAAEf/5CIA2iYCCUv+WUgz7iIAOk5g3CgVSU5SiD8uB2sABm8AE1X/U1RQOFyL
+4jkfIlz/RV98M1j+G2H/fVk23jtD4T0pXl9ieFtGcV894UIiYWJfAIwA50gOV2p+4kssO2j+dGZx
+bG1qVmj/OHH/aHJzfnBX5lQ7B50AZnahdXd0AKUG5V1ARnz/6mErCqgAAKsAent46GBIW4GhAK0A
+AK8B42FtALIOin9/ALUAiIOBALkAVIf/6WxWg4eBi4SKJrEAmoVtdY2geoP/rYVXhoyOqYVuJbUh
+IrgWX5D/jo6J7nszP7gAsI9S63xnN70zZqO/fZzCOb4+cZr+64dy8otYnJ6b7ImDRcM56IqcWMEo
+oJb/N8ZoTMRL7Y9/QchcsaOTo6eohaj/7ZqKXspXj6v9xal+oK+7d7vTUM+Afco5r7CumLTVStKV
+bs9ukbb/9qx/9q9l8queoLv/e9R66beG7rDImNRhi9aDwsPAs8bWzcK2cd67jtqP5MWUodyB8b+1
+tMr/z8L/j9+kbOXWnN2ZstD7yc7Rzs7Ly9xb183UwdD/+si/qeOmvuKIx9fj4tPCtuWiqOrL+tS2
+y9v++NPK2dvZt+m0ueq80+Wo3OeSwuy/yezG+d7f/eS/z/DS3uf/6Ono4PC71O39xPb02vPZ/+nR
++Ori6e399+vt+PGz+ur65fL55/Xb4vbh7ffX/PPY8vP9+vLy6Pf36fjr/PfM8vjr//f+/vn48P36
+9vv+/vzf+fv4/fvu//z7+v7//P/7/v/8//QpxAAAAAFiS0dEAIgFHUgAAAAJcEhZcwAAFY8AABWW
+AQ2TT8cAAAAHdElNRQfaCRQXGSltwbPRAAAgAElEQVR42u2dDXwU1bXAZwEJtEaNH1nbh68fpoWK
+iE1ao2Bgo9RqIrEg+BIFmqLYLOlMcHHlU6DiQmrJM2jKo0QIBHgUjD5ETcQIlKq0gKDmA+UjiRAT
+BCOBkGzC5re/++6987Ezszszdzc7s9jfPa2wO+zMPefc/5575t67Z5hB/0Ek/W668xckcmVmQZ5S
+CvLmgshl4QCiZu+8ntCOgWlzVfrl5ZZFrl6T/VYSv9x5K3Pj9wnkh9fFFxQE6VcVqXY+8PjgH5K0
++/0bBxDaYcsN0i+vLlTbzH9kjEknkEF3zptjLPPmXL2VwGC/nxysm+YRyc+/S2bHNYUgmtJkf5RI
+vScH3HEvifz05mhqB8G68d6xJO3ecSWhHXYfYdvM99LHGEv6mEF3zmFJ5Gr49e9qVUh7O/wP/w/9
+gf4EXnKwbpjNGQs779bvktlxzULg7TCQzvDAItBvzqMD7hjrMJaxPx0Cv3OdBvqFBRZJs46xCCwi
+O+xNwNfSclom6F2L4j1A/UsG1hgI1jyWUzLEKf/gX0CwevIzsvSlJoyh8IY5LmPhEFhEhsCI9b7L
+oy/uI2GBRaDfPATWaGO596dDADhioJ+7PKyI5SBoF4NFZAcEa6ZjvL7MOg9MAWtPxv4aHdlfM315
+TMHy7Gg4pifN5cUxBMsPisub9dRrqHc1xBCsC7vHH6jVlQOO3eGBhccc9B+rGIWkP/ALBNYEA3uX
+xxasooMGbVaWxhSs0kr9Njs8zbEE60C2UbOTTAOrR6/ZHjB/ZWzBet+gzR0xBmuHfpttsQbLIEP2
+ZpsGVrsBWMspWBQsGrEoWFEAK1UUDbBkQEkJu+Ko+WDxDRmApWmH+WCF0u/bCFYIMyIHK30CL1kZ
+Y1J17wo51snhW1/4d9BdoZlgcZx7mcezzM1yemBp22E2WBzL66fsExVYjmxBxsNed1gHVra8XX2w
+WBc2A/4dDbCSp4v/2PrGb1L1hkKnZ8sRNFH39cel6K1lQyFbvLcZXf3YrmWsNlg6dpgMFltc3dAN
+j3+zazWrCVbKBun8ltcfS3FYBpb0D721L+uCxXoqxO5VfEMiBmsa6BL/+UxWqhZYMFytPSVd5yMU
+qKxJ3jlub7f4D5f+xmqDpW2HuWCxr0r69b7N6oAV6JsTj6VYBpaciP9L0QaLVXQv13ewUqeBdjyS
+ZM0/Cf6uBRbkak03uLSraBHnWfsJAJ/LEi2TIxZs7bPyZS6XZwu0XEaWCiwdO0wFi3sXgC/K4QDi
+qfhEoV8QWNtT8FLK+L90gddHWwjWjNGw1dG/mgW7/jFNsFjYvd/sKnK73Kh7P4oSWHw3JOcDkJGq
+BVbxBfD5IidKqpzOV/3gb05rwGJfRXEAfYM41nMKfMXpgaVhh5lgsVsAeJvj9YOMXVrE6YAlvHwa
+XJSFLJPBOg8m8W2lpLwFQ5YjNFgc6t45OFCx0OVgNRu1iIVEByznu+ArIUixnPMfKGRZARaCSRpf
+ENx/4wwiVgg7TASLc52CA4f4BiobCFmaYDlSusBUC8GaGgC6VgssFnavS3QtC7uXiyJYMP09o5m8
+O2GfOsW8il1TudoisF4FX8hGvy3lc1yGYAXZYSZYa+RBitvy9hyXIVij744RWP+jDRb8ygaCFLdm
+x7KoJO/tyWj2Jz3/JPhjssY8lnNL91cvsNL8KOtk1fNY5iTv3D/AP2UJMaubvGvZYSJY8Jv+T04+
+8eAyBCsFdvBXVg6F2UK7k85oDoUs7N5FsiwjSsk7v5cKkqHsD3nEcm4BnznxHINTENaaCVJpcBGn
+zXQilpYdZoL1iThSB+kXBNbu8VOhzFhwAICXrUzeF2RPnTpp6qy/nAG9YzWSd5gpfqZhRl/AkpjY
+P0HrrtBZDQ468ZuKHVgqXdYk793Ag4zkllXyDZfq5FhadpgJVjMoxZ3g3sHrV84ZzmMB8LpjdCym
+G3r/oDXdwFaD97EZHG9FxQ53VHKsadOh5K8/q51jYbDwC/FSiywFixX7/Sirk2Np2GEmWA2gHOvn
+Efe3aCfvXiTA27J9lpVLOl7cLvyH2g2PaU6QSmCx4mXcXDTASkaSmpxxEvw1VXsofBLPt79/9AgU
+2DJr5VDIFh2rh9IM6vXA0rDDgqGQW4b1awAN+neFvzoDvpTPjlqVvD8Nw+ToFG2wxKGQO3gUmnEk
+GmAlS/M/Y5KXg5pkLbD45F3IsdhgsExO3vHS5JMV2mDp2GFJ8o71KzYCK+VhSJYjxXKw4A0DeF0P
+LDF5xxOVXLQiltg384PAktaanxSmG+D9AkrtEFhWLEKzr4Jv+FsUNOizO/QjloYd5k439C6SVIID
+doPRPNbTXeA96yPW6JS3AFCkWMrpBg/qXmmYcEcbLO2IxTrfBRdfcAqYOZ1WDYVozvGf0s2vkxAs
+6yIWGqs/l9ZsnWtBsxFYKHa8bOEitDiPBQfhc49prhWyqHuliWhX1HIsvI1JL8eCMJ0CF1ezeBxk
+iz+xLMdCSyYfzRZugbd0gCO6OVZoO0xd0lnTDT57QdiktqYDtBnOvMPYcc7CRWhpghSmWW9qgoVW
+EC6u5uMGh7s3KmBNQzJ9+UnQpTnzzjmLTwHwRUVxcemWBnjnusuqRWi0ctX5cXlR8dq9HQB8s1pv
+SUfDDlMjFkxPQO/H5auKy/e2of0XhmuFKQ93gTctHwpHO1ColA+GqkVovntXFQndG5WZd0m6fqe9
+bYZzej6RPvjZ6qAJUtP2vLNrpP0c53bNYXVm3rXsMHnbzFrJL727XtCbIA0srYA/pVg33SAu6dx9
+BpyQ3Teot80oujc6E6TtWBpr1mfobPRDUrzlSEfH10d3FcEbBws3+rnX7m3o6Pjm43K9jX46dpi8
+0Y9zFe891tHZ/HHFMo5zEawV/uo4+HKsVWCdli1C+2F2p7nRj+OK+O7dUeRio7vnPdVoazIr3/Ru
+4dZkce2bI9vznmr51mRh2wd72e95T9HdmhzKDEt+paP4MQX9+Rf9lU60wKI//6JgUbAoWJczWMRF
+QehQSMEyJWJNM7B3eYwj1re8KEhnjMGaZNSsaUVB0tcrZaPqbVaMyxiVVlcqRP22KLZljEqLlApV
+q97uiG0ZowOOVzboyitmlTECK6fly2V6fr7qfXtMwTpaVKyUUtX74uYYggVAs1o9lX5F1SCGYDWB
+l2bMVMos5dsZL4HwwTIQFwYrmmICWNEUM8CKnpgDFpmEAVZQM263+shsl1ZxWz/6H/oD/ukPC6x5
+s42L6s4mrEFqClgkRX8hWPeONRYzwBpN0i4Ci8iOkGB5Q7xjbP2CZGDwoX62K29Qy/U33RB8bEDS
+SLUkpfUlYjE3EMmVIewIJTZ7sH4FfQHrqhuuV8tNQUduuJrpTyQ228hg/UoiByuXsN3+A64OtiPE
+kauYEP0bslw4c9MD9xPIA9d/5wc/JJH+uWUlaunL6Di3P1GzPxhMaMfV920N0q8qcvVO27/34/80
+lh9/b8D9D5DIz+3B7ivZFzlYv73+AaKG7x9AaEd8YbB+IUdH5hdkddR/9H2iOuX3XrE1ujnW3O+Q
+tXsdqR3PRnko/GUGQXX5jNsYjki9B5JIWvWSg3UrmVtY5jYSO9J/SV7n/efzOJKsDYI1mkSugOGp
+7ai+HAsLrLEE2afj3uvI7JhzEwTrgJGEA9ZtRPXlbx/wJMlNCA/WfgNpB/4wwCJyy5PM7UQ56u0w
+x2o7YtC/bSaB1eZx6xcqd9XHFKyXpLpnGuLYQBwTog+WF7wmlo3TkIzp7SB2YJ027F63p80csOoX
+dXR3aksHKC2PKVjZG8BpPQEvzYgpWPkrhd1koaWnJqMmhmCdqXd3dOpJd4e73hywjngM7C2viClY
+M7YbtPnKrFiDpSutWY0xBcuoe4HHNLC6KVgmgtUYa7AM8ncfBYuCRcGiYH3rwRJ+UKYLVookVoLl
+0Gw3FFgh7TAZrNRkQVKNwVKXCLIIrNBuUYKlZUZfwOJYd3FpeemqZawOWI4VCwSZ6bAyYk0V2501
+VVnzIBgsDTvMBSt1+vL5WPKVtZNCgMW6iqB6pcs41lKwtNyiACt1gmjGNHWZ/IjBYj17+T0jX+9a
+xGqCNT5wlZbXrQMrJUBEb+0f5D9NDwJLyw5zwUreLx4/80Z6qg5YrGvLMeykznplPXiTwZLc8o3K
+LQqwkqX9cl5VdbGIwWLXXIDGNjc0dwBwSfFLRWXEAoB/NN3xLgBetw6sDeC00C5UT/5LXjVYmnaY
+DNYe0IoeydgIe75GBywO/SC0t62hARXpV5S7NhcsdouWW9RgdfFm+EGXskx+hGCxW/yoTjnHch6o
+wsUXdMDi053Rk94CQFFewmSwtgsp1oIz4M2xmmBp22E6WCtxapK+shv8MVUTLM8p0LurCFVRXauq
+B28qWKj2hcwti3TAqklORRlWvrpMfoRgeU6Cz4VfvqLyDB+x2mA5UCV62OV3v6V8xoHpYOHC+6ic
+9CUZ0CqwtO0wHaz1yWPSUfb7GngjWQss9l0UL4QSVKgevEVgofrtvFtw9Y1drA5YqenIjuT5UqGx
+voCFCnzPFltzvgo+l1XADwZL6Oy/SHUIrAFLfH0azNACS8cOK8DCr1aCPVpgscXdgSjFek71yoqH
+mAkWrt+u4ZbgiKWuYNcXsIrlNe9dntJlLpcxWG8pC+JYBdbDivroSrB07LAALFw9acwH2kMh7ODP
+ZflN6arZ1kQsPbeEAAvbsTIaQyG79pQ8HXEpCnyHzrFSUHGJP8Ugx4Ij8InHNHIsPTtMB2vjmIyM
+jKzpe5QdohwK/6GsB29R8q7rliCwxmRBM6at7z7zm2iABb7RLPCtBmsFlld2A/CplXeFtQtwuxvO
+AHmxFDVY2naYDpbU+2O0wTolPPmBcwbVgzcVLB23aEw3gK7fJfd9uoEtB8f4Osw7ULnc+vpjHlYL
+rIDjP1UW/jUZrIC8PFoTLB07LAML7E/XBMsnlBUv4tU7uoO1BKwK0S2VQrsezhAs0Pi71KiB5XaK
+v6srZnXnsbygd/tMVWFnk8FqOYAnsb58KVt75l3PDvNzrFS0E3nCym7FWKgEqxsUadSrNxUsyS1t
+wW4JcVcIBT2VrysKEWut/yIfossr0SMJOsEqVjfHelo9O2pRjvUW+FJZ9Fc9FGrbYdFdYWry/G4g
+G0XUQyFOojkPUq/iiKxIr7lDodotRazBXWFqctZJ8NfkKCTvwnQsXw65Qw8sNI/FFwxPsRYs9BzH
+46D3MZ2IpWOHVdMNY1JrwHwNsHTq1ZsJFgfd8oLCLYZgwZfrFfNxkc5jfSKfS2QNwBIKhv/J4oiF
+XkxCFTS1F6F17LAMrGRtsFhUDz6g7A6LwFK5hbMQLG4NWl/gxJKMHXo5Ft+vdx9XFQy3BCx+ENZe
+hNaxwyqwUtNPakcszyk0A87x6jmrZWXFzQULAh1wC8z0VhmClZr6RjTAQlN34O1l+HET7jUNQIa0
+BlgpDwNFOWmrJkhhqOzVWYTWtsOatcLk5DGvgTOy/Q2qJZ21F8AXq92ouoq7aK8ffMxatFao7ZZg
+sPj9WMv9QHFbGCFYnAs23ftxZcWOgx3oOezGM+9BT8+waOYdDoafai9Ca9thOlh7lq+Esr4GKJJe
+1SI03nzxBVSvGpW9/uwFa5Z0VG659LbOPFYjNmPlHgD+nhyV/VicVEi996NlrM5+LLG3YQ9flG+6
+Mxms3YFnGsufIBm0H0vLDqv2YwGwUXc/VvFe8XNflLo4y/ZjabpFcx5rf3qUdpCyruLqg0cOVpe7
+We2Nfo7aA9Ja4YLa2plWgbXi+EvSIvT22t1jdXaQathhMljra/BPlfe8sVK5jSloBynLeir2HqlH
+5eBZ6/ZjSW6pVLtFCVa+YMaejdNTo73nnTXY8x76tfl73h2ybfcke97Z2Ox5Tybd887FZs87S7bn
+PWjTu9m/0nE4ZC8dlu15d2i1e9n8SkeonfFt/5VOuoYd9Odf9OdffQKL/q6QgkXBomBRsPoKlo+C
+9e8MllGzZoFV7+4EPm3pBqWxBSt7A/DqyWVQxqirpwv+H/6BRfybF9AY4zJGHt3u9YFOs8BqVlfi
+KlIXXjsYU7BWOCYpC61NUr6f5NhArJ4ZYK1Pn6astKZ6mzWtNYZgnf7aYyjNPFizSeowQ7DGkgiq
+QdpWf0QhR5Vv64+CcMAiaheBRWZHqFKRu1UCog7WbQOcROWucanID5RSs3+PUlrDKhVJ5BYnQ2iH
+vQl8repetdTj/ZXMreyTBML+6EbHHSRyRYmv6fQZlYDI5ZnvELU7+joyO5w3PXO+6YJKuiNXr8l+
++5hfGkv67cyjThI3329vamrqVYu61TCK2/6IzC2PwohFYAeMWB8Gd29IdZgBVwbJVVcFHxtgG0wk
+tiH2IBnZB7BKCNu9NpQdwYeuZOKD1IvP7QNYSf0GBsmg4EP9mBC6XB3iWLB69viIn3ngA8+GajeU
+MKR2BOtnD13nPbNuH4HUjcwl+ty+pMLgz9X1BayRZPpl9sGOPujXNKSs7kNjqSuzV5HoV1eYFOJo
+U+Rg5RK6pcreBztCTgIwhF/XtKVkn0siqfPeRe6bQsLHWuROJrRjIYimNNnJqKyznyf63NakaGrn
+Azk5ZJ/sIraDpM67VwCrcf1GXVnfDjtkLgANldX6gsAqA2C//vXWv0acJPBgvW/QbmUbADkQrI0b
+CewoAJ1GZlSHAxYcB+r1L1gJ7773oWfQbDd4HNsBASwD7SobwgLLf3yDgWzn7TDqXtGOAxsM7fBi
+sHqmTcifriP5WfkYrA6P+nlsKnFVYLBqMqZN15X0jWFFrGqXfrPFniIfAmtlhq4Zgh3PglJ3qbEd
+YYBVb6Sfqx53yAbHzBm64qiFYPlAhUtfvyJPWzhgeWdkz9JtdqZjA7TjX4bdy9txoXb8jBmGdmCw
+2rMMJtzemIDBanYbGFRZjMHak2VgbziP7oVgVRg98PSYuwOBZTRjzdvxLPAYPmG1OCywqosMPlRU
+jcFascDgc9m7MVhGj+7tcDeEA9bp8bUGH1uwAoH1tbuDxI4LB7KBsR08WBP2AP6Rb/5QAjtkGg+W
+0SNj0bOUk/hnQoe8EN9GTwRg6Q/sxzydAlh+YzuejfIzoavA+0ZgreLBemmBfgrgJQQrnGdCQ7DO
+Zx8wSIh4sNoMA+EqASyyZ0IjsPYbfNPDBSuKT7EnilgSWAR2ULAoWBQsChYFi4JFwaJgfVvBajcA
+azkFi4JFIxYFi4JFwaJgUbAoWBQsChZN3ilYNGJRsChYFCwKVphg5RCCVUAG1pCS6A6Fc0eSgNUB
+cu4jBKsgumDFE4IVTwZWmT3KYGWC00RgxROCFU8MViEZWLklZGDlVEU3YpXlkkWswgIysKAdUQUr
+s44IrLpMMrCqMkFUwVo4lzBiZf7raxKw6jK7ScECRGChaxGBBSWqYEEhAgsKCVjQDm80wUJCAhYS
+ErCQRA8sLERg4e5tI7Jjd1TBQjuiiMDygegOhfCCZGD1kEUsnzeqEQvZSwSWjxAsX5TB8hGC5SME
+yxdtsC77iOUnAwsKjViXU8QKC6xoRiwKFgWLRiwKFgWLgkXBomBRsChYFCwKFgWL3hVSsChYNGJR
+sChYFCwKFgWLgkXBomBhsGoIwTIoR1IpgmWg4PIwk/dygw80IMUgWOsJwTKsNhNlsIolsPRlkgBW
+pf7HOsIFy6jazIoVRN0r2LHbsNrMJBGsjNcaa3SkcT1fl6jBVd/coCNtFXz5nz0ZNcrrqa7emB8m
+WMVtDbrtHnR1oC9e/nxdMyQ7PJUG16soDku/ao+uWxqaPTwpK2Ycr9WV8TxYxeW6+jUfcTWEo97p
+8dv12z0+cwXfvUeI7Ng9vraWwA4IFliZkaWQaRMUbydk8KHAV+7WL+8t1G9vn66+nvJtFnEBfGGk
+W2RQVhwXSvNDoLN0RbSj0uUhsoNUDOvaCxGmdrxKpirfOma04M/VG+jnLveFpd8Kh7Kd7Gy1IgeI
+ulewo2WG6nrjs0PZwaCa4Y2tja2tjY3wL/g3fo3+j9/gF9LorpQO1Xt+jPaDdnxuo3AJ8bKyNkjr
+lIuxv81AhM81tirsaNWyo43wepHqp37fKeQyLcdb9OT4eSEHazO4XpjqAf1moVZ8uz4jt3TyZpw3
+uh62gyFSzQ8uf/H/m9jxbyIMdQEVChYVChYVChYVKhQsKhQsKhQsKlQoWFQoWFQoWCD0g0V8fvUL
+2SdDbKDwmqqu1xtQQd1SqCNBp/WYrKDkpR5/kEt9BKf5zFscUDTfE/zSq+llXwTdq4hYWwvmIlla
+8o786M6SwmeXbj6ruOjhrYVzl5YdEo41FSycK5z5odnfhJadJagZ6XG7hULLSBm0ZFNXoDgiSi86
+benmdtO/qYGGsGuqeJfOXbi0rJVfUtonOHnp5h6VlxeqvRxlrsokXTa3KjpzHWq6Sd408vKzopel
+M5eWHIpsKExjBIkfd1LEc93wBHxo2JRuiebD9wyxoWOJ4w7hz9QxktinmNp3LYtvxi3HD1si+EFs
+2JY4hf9yyHXhu9ILehcPF0/zmxey4IV7BXfFDVvSjRvKlanzIj5SKB0Y9g7Q8rIpYKUxoZremZYg
+eOuk6JqAlzerzhTACBesTGZkDpTJsKlbeANbHoH43Dc5J3M4w9wiXvP5BCYOHUuzMQO3ocel1jHx
+OVgyYf89ZOJ37vBQ6JP7YDsJjO0hXsN4JlNs+SkcIhi7qAsDj3Sh074cJZ3G3GVaz6H9C7Ahu+Cu
+u86iYwVMkqBOAtNvG3JNCX9kMjww6JD8tEzey2dN857QvTk5sH8HviN00xM2Ji5tMvZfIj7mlbyc
+hrzs589ME8Eg9Z8KrBL+xbqh/V7EcX0iE7fkEPrWt6yTrvmcjZnyYQ+Ol6OYQTU4YsVLEaV/3Aem
+9dyXI5jEzdjxdYttzO9xOLIzTfwQ9Hx/rEsVIz7bvOURW2KNeNqSJv60BHiaecPgKNjQId4PCcyD
+PFjis5EPj7Jh1kqYTOHACPgRv+RlIHj5Qb95YJWIugy1Pci/eo6JEzpz3XAhdEB3DdvcJHr5KcWZ
+6wbzYIQNlvjA9CeY3yKbN6GQJMh7gxkcGE8k2J4Sj50bxUzhwRLzu97/Mq/n4LWlqAnxjsOv7cw+
+4V+HM1sxWElisnnpZ7YXkRXPMbdIucEm4bToC24oUcpON/W3HVKABb66FkeoEiYNKojo2cQMA7yX
+A6dBL79jHliFUjPMNThlec8WJ4FyYiizJNjLiScVSCIwIgfLDxZiPHqHMjI+JyIdusAjzDi/6Enw
+pu2hs3Kw/HJPRrvjDg+OCzj93IjEDySwvH6o2HDbZgVYXYI9h69gtgXgHJG4zaxtWS3XMbJrTxy4
+TeUO/jvAg4XzdeYWrNJ1zIuB9GFi3IsWgNXL2M6jUW8UzFykf3+OeQpqj73slcYI6OUAWH6QRxo3
+QkescyP6ob54b8A1rYF/PXcIJiz+iz/jUwW+oUsfnvdaFrH+zPwk0AG9hw95gWwohN91/EWTR6x7
+bEuE0wLSiawwR95kftKtcpccrBPX9jskHwrBRD4rhNHjrPo08yPWoPNYpUEBiADsTOyuu4CkQm8n
+9LIsYn05ot8HEYGVu68KyrpRcLSDt3+/tj0l3HBCEW6Ot18x7JR0DM+6+GU5Vi/MsfaY1XG/Zv4X
+KNThc6wSrPPihMRtQJFj9T5iG/gBPu2/g08zI3VXNCT0TagcKw0rvPUe20N4UgJ62a/2sgU5Fmpz
+Q/9xFwKdqeVldGYeD8bQuCWE92YqsEQZ181rsjTohHXMfUGXhmAVYMk19a5wKBNiGiU+XtSZn26o
+YobMRark5eK7Qi867R1ggfjguLI56GgBM5JXJwfeSgt3haLGiYcwj6G8bBJYabwu8IZ0IJ4oeoZ5
+POj7EexlnwqMSMCyJyEZYkP5G5q+4BH3jeQlTYjkXlxCPAkfS6rDYEkTHQ+1muYaO1OHo03VEL7l
+PB6sJEFnfGsMwZJ0ieMjwRCmisdfUDgH+MzpuJH47gGAJqGhTHisIDB3lMinEBAsXuEEG8zZ/TIv
+JwW8bBJY4pyfeLeQJ8bTNEFlH/DFq7xcgM+UgxF5jtWybiiDponE75JPpAb75T4erCTh4D4MVi6U
+oTbhZtskuVn4LolzoJkibcJEBx6Jqhg7VCUnIT5xyVnxtHeEWMZLmllgpQkRS5wvTsJgjczLzc0c
+HD9MnPUXcyzv4XuYRMXXV+ZlsyIWdE1mf2bcZiHuSBFLRA7mqwlBXg4Moi3rbmYe8kcOFkzuEq75
+AA23S7AGvq1QqgqZIfD17sHj+ByrCh3cahfAQkc+HYxaNW+x60Zh9G/C6uSIYO0Tb/ZtP+mRcqxN
+trglqtSMPy3XLLACORbvLogUBiuXny5KFO9MA3eFJ0b0ezHotELIo6k5Vu9E5hYxY39ezLFwZ5bF
+I7DUXs5RpP0QjJo+gNUDhjNl6DZHfldYh8E68bNB2xTD077AXeGmBHT3ahpZf2YelC2eFirAQvdT
+TL/zgbvC51CGhXVR3hVuNQss3JDM9io5WLA3+21TgyVMCilvJveZCVYh8si5UWjePYBJICXGEes5
+6OUumZdz5Gm/X5gtjBSsLhif4fmXZPNYfvAhAgvNYz0kW65UgAWet9leNAsrPzjcP64m8G6pGqxe
+xtYjm26YaBO6Ep4mZu9ePygzD6xzV0jzWLChrXKwwLkRaNxTgCVOcp2TzbMhL5sLFpozGMrccoEP
+sqOYpwJN92CwdvZPVHhZAVaXlEhGOBQKcUk+lQzvB6/FlPfv91RgkeVaOVj+XvhlOGkWWTiIB67+
+hHoofNP23XYZWOew+/zq0xabB5Ziih+6Sw4WzhOE5F1U4NJE2+9BsJeHmD6Ptckm8iRfWgGH8awp
+dNddSi+LYHl5MPZHApYAZssjDB58YSOJwlrhzidsaAUCyNYKfXWLb7bZ6gJgecGJwba7zNs+EFjF
+atl5j42ZrJggPTwUeyswQWjMGXEAAAJqSURBVPpef366gV8rPCuddp9pYPGLkry7HrEx4+RgoTUo
+YbohU5zzs/FBLMjLfpPBgtFcXISeKK4Vnt+3OMEWh159qvTy44oJ0ntIJxxUYKUVoNu7nOEMjs5e
+YXcDOmJjmHHC1/F5G9rdkItWv6EKfsXM+3MMs80srsR1d3hnAxWMm9LKg5WTh3TOTGDUM++PMGgM
+9PrA4VH8adiKKa3m6Ye2UUjuwhMvAbBganNLK45YSdjJuXg/hh97+Z4QXjYTLDgY3iXQ/QQT6Mxx
+7wS8PFn08ln+fhI7OedmJo5wUjD0fixmmLRss244nhey2ccJW3jwfqwEfr/OyCU9wv21CNalEcwg
+8wZDaacQY59yiE/NmcBWITznt5Wxi2DBACJsQhH3Y/GnmSi968SGkLu8aD9WjrSM0h9veAjsx7Lz
+82z8Nq74wGlmgZXGzBW/AZsYKbkS92PF4xiBs4qWxUPkXvaFBCMcsEpy87Aod1ruLJlbwG/HlO0w
+hMcKln4oZDdNuXmBT+dONm8XKcqYdhbCljdLq2sFvMoFS/mOBHU5c6UAsi53ssiR+jTzBDaUt7Ss
+SbwJzSmTdH8+93GYX1TlCE4uUygDvZyn9nKUwSrJqZLePZO7tNsrtHUYdTDuTG9IL/tkYBAvORnu
+eff6Zb0qSo/OcADM3Pfu1VHWq3fAr2djlNlXudQXdCTYjV4L6uCodfEG97RwSL7nXa2zPwKwqFCJ
+mlCwqFCwqFCwqFCwqFChYFGhYFGhYFGhQsGiQsGiQsGiQoWCRYWCRYWCRYUKBYsKBYsKBYsKFQoW
+FQoWFQoWFSoULCqXq/w/gbudjI6bMwYAAAAASUVORK5CYII=
diff --git a/Documentation/DocBook/media/crop.gif.b64 b/Documentation/DocBook/media/crop.gif.b64
new file mode 100644 (file)
index 0000000..11d936a
--- /dev/null
@@ -0,0 +1,105 @@
+R0lGODlhuQJGAeMAAAAAAH9/fwCvAP8AANEA0dEAAK8Ar////wCOAAAA0QAA////////////////
+/////ywAAAAAuQJGAQAE/vDISau9OOvNu/9gKI5kaZ5oqq5s675wLM90bd94ru987//AoHBILBqP
+yKRyyWw6n9CodEqtWq/YrHbL7Xq/4LB4TC6bz+i0es1uu9/wuHxOr9vv+Lx+z+/7/4CBgoOEhYaH
+iImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6gQC9vr/A
+wcLDxMXGx8jJysvMzc7P0NHS09TV1tfYxbth2d3e3+DRAePk5ebn6Onl4ezt7u3q8fLqANtg7/j5
++s/z/f4B+wIKHAjsn8F09ex5IciwobuDEM1Bi0ixosWLGDNqrJhQIZdk/htDihxJsiTJiSZTqlzJ
+MmNHj1q+tRznsKbNmzhzDoz3EiYWmTN7+vQJgOfQmN5mAjzKtCg9pj+TBoU61ClCqlaAthSKVZdV
+dFy7NtHKMqxYW1/PmT2bhOzKtWxlpZUYF4pblXDrvpq7Tq+Tu+UGCB5MuLDhw4gTK17MuLHjx5Aj
+S55MubLly5gza95MmVxev0EAkxsg8jNoVXNJ0zy9RPQ41RtNsz6V2vPstlLTwdYo+zap2qt9G3Ed
+YLdL4bGAL0VOhLhxjL2Zf1IeXboM56Wtt6KuPXRudM8vVu+eiTt5H9hDjj9vyfyIXrTW80gfO4OC
++/jz69/Pv7///wAG/ijggAQWaOCBCCao4IIMNujggRe4J4IwBxBg4YUYZqjhhhx26OGHIIYo4ogk
+loihMBbi1k084VlklgLsWQKjBRJqgIwEBJRyY4UqZsNidhjMGOMkQlLgnjERwkdBjuVpk2QFTB5B
+H2/2DUlJkRNYhWQKUTKyJQpdFjHlcUFaSaQxo9nGQph/fCkDm0OMCV2VZh7iZpbnwCYfBnDKcecO
+fXq3ojotckRnnXr8SQGWEtQIphuKEhEoEHKKdygHCUiQ6QEJdDrEphWA2oGo3UXaAaMHOHrCpFmY
+2gSr6H2XJ5AXoHqBp5xyuimpPfCa6we+6uWqCaiqagKsTAxrBbLz/slqTqEUvWgBqLviSqqvnXpq
+rbbZTpDtt9ziSsG3unKraabkltutWMq+UOyswa3A7A/tfjGvDpW6eKm3v+a667i38vvvuQLzW7Cm
+AJ878L/W9ouuR/Xi8O6zasorRMRo3JtDvoaWOe2v4IIc7LUIE4zwtd1Sm7C6KZ8MLsmzYBzExIFV
+rILGJsgcB843cBztvgqHWnKwup5s8rroVivwwEc3DHLR/jKcis5K0JxmvDezQLUePNvgc0TSBix0
+1OuG6nS56nob7ssqp132wuIi7cnWU1j9ms1chkD3IF3X8DVEYe9AtNi37M2F3cXh/WgFhjPSNw1/
+HxS4CS97MPjH/ts5uQfieqbQuCWPzxC5QZPncPnYoXz+BueKY+Bm6J3AHsPo/5TOmup5sB5vxLJv
+0vsLtPtjO1W4D0Kz6r9nknwLwfczvFeam6IAmndjnfcsy2vtbM3qAT2KkhkULwj4SRITIbzLWYx9
+j9j82L3HvyljivzeG1tC9qCzf4379cEPigACCAYAB0jAAhrwgAhMoAIXyMAGOvCBEIygAVMVDBLo
+Ln1ZWx8SmjeP521CAEYiXypAGML1XHBPF8BfJVToue1drX+1GgUJZTHDFJywBSycRA5PwEF5eFAT
+NYRFEE9wwzXRYoc5c2H1YGgBW32QFkMk1vkoZr3FyQKJJeih/lH894kotsKLFpwi9zB4vSvqzxr8
+oxIXPQHGVbRRBEVUnxk3qMTEvS+GonjjBBCwxwMg4I+d0CMI4pjBOUqpjtACm/c4IUhASuCPfPQj
+I1lAyDLGAosk0OJT1hhIC0RSkpDsoyg9GUpAhtKPp6QAJD9pB0F+oJJWvOQZq5FGMuExFFHkYyR1
+OUpWqrKPvHykJIXZyzy40gOwXNURZ0mNWs6Jk5P0JChXKUxHXsCXwQTlKIe5h2OeSowvRKEFMOkI
+ck4IkbRqogyvaU1uZpOd1URlNXepSnriwZscSOaxlknHQekmnRVwIhAxgM09rtKXBrXnKalJzFTe
+AZ8b0Of9/vh5SH+CB6CLWicPEAoIiGpAoiQwp+OYOQ1nWgqaT0TBQTl6TUN4tH7oEyeUKDocdN5R
+nXnsAUv98FJO2i+kNBWTTZkYUI3SkJLgXKJMlxTU5gxVjbf8HxSRSqOY4rCpcXqqLXGKy6muAKQj
+EOkixPoBTV4FpQOdRU+jiicqkjGWsCCrB8wKlkWm9KhfTaod36pMDVbUR4TC6AQEmom1spGqjLOq
+Ef1aU4uiD6pclapaEWskxcpRlv0E7D9vWtScTjavVXXrUicgV0SUlgN0VYtd04pXFYBVBKc1RGxt
+pNVnsvWwn3WtXju3WEM2VrMX5WxGPdtaG+62dftkrFAd/utWyHa2q7k1bmjHOFocYfVitT3pbTsZ
+XRS8NgSzJUR4XZddfaG1sF7V7XTDeVXlOpW5Y3TucKFbXO8et4p99e1ygfvYrT5XsvUl4n35mlz9
+vpe/zfXvfAEcC8P+t63Uba+BswrfF8p3sEZtMGUhzN7eYvav7QuscDFMXA2DNrGilfCHfxvizRJ1
+wV1Mr3RRHGEPx5Wk0jCpebcbzQBLcb1KVfGNM9vi4L6YxPQ1sXpp3OHLDhnE+xPxkSVAWEw4uMcz
+rmyKbfyK8ZYPwfFVMJIZLMQNN8qyhVzxfovcX9tGNsbdFTCQ91pdHrmXwmC2sJipnOEyn1jLNXZy
+l3Es/g4pX5jPJfbzkgHd5DQ/mcVRdvGhD1DlS1z5rlnmcJC57Aov06i8HeMxphWd6TNvWdCdJjRK
+JL1nSvf5FZdGNJM3jepWeJpxoP7Zea0sY/vOmbe1ZsWtS5jnJU660paINXr/rGk6C3nQRI60kY/9
+alco+7sgGLYftN2oXCty15butZxn7WxO21rV/DB0q5FdCWXzmtmmDrSjoQ1lNKrbzQ/GrY9LgO0P
+cJsP/04tXcCdbHH/mNzAnneqo21vVuMbxvpWcqlThWZLPnrN0m6zdt8ccVL7GuHIneidsVthY6+7
+2l80M8VPrfBzM5yW9954vrm77zD+OuRAHbmgir1X/monGtYq/2lYr7tzNif44WOGc81H0G8P/HsP
+Afc24Fa77KXDccB1fjrX0O0MHYea4zSX+McZTeuWC5vrzfC6rkXNWrGPm+zlDvYqol7ynp/859YO
+esXhSm9IN3zad0+yx9/e7IRbvO8Y/7vGdwx2LA/+4HA3PN8XXm+YO1zmEA/74/mN9WdT3u+WBzzS
+ZU1moMN75fI+/OcTH/rFf33mjjf9oguP86HrnFJSlxzV3231EDS9A1rPA915nsipE7zdBuf8zfFb
+YDUf2OhhHr2r8Z7y0wsdtkTHfd2Lr/vjU8Ld4bb+3vPrfDxDX8/SZ/f3k29zkDNf5BMmOfEFS3ql
+/rsd8rR/f87jX/SMHx3zSddxsjdx1wde2UcvuUc6uxd+vTdInWduZ/dyzRRzjAd7ozaAY5d/BAZ/
+5Sd/52dy6YdyrHBtDyh3qjB8H2h3IUh9I6h3LKd6Lld5E3h5FZh5sZd34veCkxeDoDeDogeA9SeA
+ODh78dZoMBiBMlhSFPh6NniBQ0iA49d8F/d8/hd9QDh9goeBhFeEZXeEc4d2zKB238Z2VXd/yud+
+G7h/Hdh/ivd/NRiAmqeF+MeFcWd2XyiBSkiDTAiHN1h9RIh6RriDSNiDefiDbxiEcfiEGUiHkkd+
+U2h+VYh+V6h+kyBBlniJmJiJmriJluiCqSeI/neYhDm2hGvXeJzgCzEjQkxXgnZ4gmC4DGJofGS4
+CcAAC7XYfpFXe9h3ewi4ffSHhfGjiqvwC2eYi/pne/ynffM3YoiYOqhoi894dcuXhsi4hsqYgtyn
+gN5XHt1mi93oe6zoha6Ih6Ooh6VogTpSZ+3RG7/HAcGHBygYiSA4idCYisgUjqA4jqJYaOY4hqY4
+NepYCcI4cwWYbQcYK77IjMBYj3KxFu24Ae94B/HYhlZ4iAuZHAFJCQP5kBoQkXYwka3nhnvYjAyJ
+kWBXkP52kD0gcH2xjQBpj3CIkk6nks2SkFN2kWiRkZOgJByZAR5ZByDpg653jk1YCwM5jADQ/pN8
+QpM7wJIhR4l7oZOSoIoyCXxMiS8JWDsLaJRS+QgwQj5V6Y5XuTFZKTxbmZOvICRKEpYQOZY44JTv
+B5Xx0ZWKgCW+EIUc+IgeKI8qSI9YcZSiUCxp0YhSiHhUSJGSaJFyWTh0WQjv0guB6IiGCYmIOY+K
+GReA2QnHUxSEmZeTuZeV2ZeXWReZqQl2A5nHuIvJ2IvLeJOLuQ2leQmcA5lZ55Y9U5bOc5ZHEZtX
+cl+8mZK8iJCt6XO305h6cEK/KZbBuZK42UG6STzGeQdFlJw+aZte05w+9Jx/GZ10QEjUOU7W6TfY
+uUWzKCzcGQew9J2kFZ6QM56bVJ5+oZ6E/qBP6vmTdBCUhTiU/oiOtyGfgQBS1Gmfc4Cf5WiII4mT
+0uGffvBavymgckCg/GigRMmH1qGgm4OP5GWVy1mTwxl4Q2KheNB0memgO/OKyhCL3QefzAGiddCO
+R0micAChqyah+1mU58GicsCRwgijbyCj6daPsviPMYKjq4OhZdUTPOoGPtp1pFijFGomRMoGSvmN
+draawomNv/iaCXqeh2Ok51Sl1siaWKqQWlqhXJoFU4pr7Ck67nlWKgqlZ2oFaQolUZo/5Bih+hmk
+/IkoIfQHc8pUFKSXbBiSFXmgZcoedQoGf7qeWRKngrCkadekemqjfPokx+mlakilqQCp/mEoqSkq
+pJWaoSGKqdXYp5tqoiDhqdr4pqFqqi1KqqppqabAqbCoqlrpkq3aqK86jbW5AYlqWqiKDCi6qqCa
+q7Q1B4tqXR3wq4VAqydqq2aJq8bqqm6QrGCKWo4KlMF6DMN6q6w6rbIqpbBqgHqTrQ+6rdQDpJ+6
+p+C6rObqA9baNcy6behaDN0ard/arqKaBvGaRJzgrKmqrsTKrvo6V++aA/3KQwebBgArrNCam9Ja
+sPtKBgmLAvMqkfVKDPcKsfkqscdKseNqkCtwsfeZscOwsc4ZsR4bPgsbAxU7si0bBg3LrQ+bsh27
+sr4asy3wstojCTObrjQ6qU+Ks/7q/gU8yzw6uwU/a681m50qS7Q52wVH6wIkuwZLq7FNS57FCrVZ
+lLTFqIG92p4jdaczmqfrSqlcq7BoGrLAeZ2KcLUnm7XvubVpW7RVMLVsCqxk+6NBe7ZDW7cqULUu
+y7Yz2ZRe+wRwKwwo67Q3C7jlWjeEq6HNIl4mq7hy66Z067gWe7gwpYOSiZWPWrnBsLhaS7CaG7ic
+e5J4manMCQiJO7qXW1dPe7pfygR4O7l98LoFEbuqNbu0W7tJcLutC3Wiu7sC662Z+7swG7yRq5w1
+tXV7y6THi6/Jq7zLawTCi3vwWLy/QLpza7rWS7U6m73e8ZHce5e8O3CNG76bOwTk/otdJRu9kTq9
+HFu97Iu0M9O8bfkEgvsq54ua9Guz9nu/+Auv+tuRUtC/SqC73Zu+Lbm+BIy6PfC+h6Sk/8sXiWmo
+EQy/OkDBdMQGDIy+Acy4A7zBwHOeHowbahDCANy3A4u2JnybN5DCSqDAQcDCGGyZGhzDTlUDNNwa
+qQuB18iX2Yi84MvDbisDP5wsQSyOV0rEWYrEFQwDSzwWTVyYlEmoGTyhJCnFCOguB1yd3HDFpXqY
+WqzDXIygXly+nhiZWNwFNmwDOOy9mHvEa0yWOfiJn/sFcTwDc+zAT3nHQAyFnvvG90DGzkuIBWq2
+L/y3gqy9cwiIXZiPfIzIYryP/mUrkml8qI8snl/LiLpIrmrQx0IsplBMpp38F+NRxUhBBX88wqUL
+w6nMxq8Uxkv5BqS8x4MqlJrspF08y897j7zqeWuQy6ybxbxcqJsMzFEQm6xcyU7wyi5sxLLMzFkV
+UbacQnZgzG2ryHjay0L7y9b8wT61umXsJ6krzYxMzY48zlNMkOYcq9t8uOoMzn4rzu6swpnHlgi8
+B9x8y5jMt+tMvXaczz2MiPx8yf4cs/WszL6sxgatyjiZ0ADdB//MqAEtvdNM0NUc0eSMhmHbJu/a
+0Fv80Jzs0T8wPT1B0do8CNxM0mhs0ih9BTMCPiwNnoWQyzAtmjs801RQJPBx/tMzZSdcutNFzNHt
+7NNHwCgtPMm6zAvcadRRrNSQ+2lf0ZnHnNPGKdWoTNVSMDGoidXnTNQ0wNWu6dVfDU69INbyvAgX
+a9bEidZOgDioGdKOwKxw7aFybbvHFY2tmAiJmtcruNdNgJyl7NbVJdh+Sdh8Pcw4yiwGMAGRbQCU
+jQGRnQKXvQWPfcF0LLsQzNg+XIIgiiyVLQGUfdmZTQGpbQKr3cpPbcqhedT1W9CgjbDhqKBsktmT
+XdoHkNqtXdqnLdm7fdqVTdy7PcaGPMSxPdW1zbzD/GnHPNmm3duSXd0XIN3TTd3ajdoVwN1iIJ+K
+PZrNjQQS9Z1wIt3GPd28/m0B2L3d2e3dxJ3dY2DenA3IcTnezg3SUdvNwu3b1d3aqt3b8P3e6m3d
+AH7IIpvR87vRs93R+D3D48qbfbLaup3e7G3avD3g1G3c7W0GEl7fsPy9Dv7gof3c7prIolCa4d3T
+JO6+kQuYssPhgL0WK77MLU4ED7mWQ40KOg6oCt6pIV7HI37jg2vi50Q+SVoGxIjR3pzJDh3OEE3k
+tm3kR94RSa7k0VjjMi3l+Uvl5fqMV04GFaTlUH7SXL6FklyH/hrmZ+ALZH7PUX7mJa7fa2Iidn7n
+eJ7ner7nJgLiDC7AtC3neezG9wuXG2jmgr6KXh7Bhv5DiT4D1qqvja6d/o/+h0K9spPuu5UujXTO
+w5n+2ZsOjotOwJ9ewqGOi2ArxaUe6Keu6J0ew6s+5K3u6sZIjdYb60k962h+6R6L6/is64uY5myt
+vL4e58Ae7LwuscWO6Me+XclesMve7EqczUQb7dJOxdSOs9Z+7S4Q6e267dzexk5N6m3q2aYe7uVc
+yIVe7r0L6ugek/FM7OyuvudurAUgAfd+AAWw7z+Q7yfg79806utuk3F9uvyu7/qe7wCvAwtPAg3/
+UdmO6fP+wPVuJf5+7/uu8BXw8BmP8QrP7x0/AR0/8gl/8CKf8fhu8hpf8h4P8iHfuXpM7gAw8wBQ
+8zZ/8zif8zrf2e1e/vEWj/AIv/L4fgEXD/QXX/RFL/JAv/RLr/JDb/Qpr/QmD/ECz746f/VYj/U8
+T++sjigYz/Jfn/AYsPBC7/Rkj/JJ//Ri//Qr//FKz/JU/+omnPV0X/dbT/FdXyco//ZCbwEHH/Z/
+//drb/Z9H/htz/Ypr/Fp7+zx/rt1//hXf/eB7LhkP/Qk7/eCn/hwr/kjf/lBv/d7v/mKj/ahn+4x
+P/CQn/o5zNM2jtIPnwGvvwPeDq6qX/uSf99I3PkeEPtE7+JVH761r/q3f+g+zft+7/tyv8HBn/rD
+7+jvLurJz+jL//jNT+nPb/qEbvXTb/f2fegP8v3gH/7iP/7kX/7m/n/+6D/707r93K8bnPH+8B//
+8j//9F//9n//+E//oez47J/1SmHJEHDkpNVenPXm3X8wFEeyNM8RCFa2BVA4lme6tm8g13e+9/lW
+UDgkFgOvW1K5ZDadT6hSVURGrVdsdvnjdntGcHhY1ZbNZ3Ra3ZkSyWt4XF7z1rtivNi+5/f9f8BA
+wUHCQsNDxETFHaO3uUfISDa7vErLS8xMzU3OTr1Az1DRUdJS0yBHSdXVyL3TV9hY2dmjRdtb3NxB
+2iNW3985XeFh4mLjY+Rk5WUeYOdn6Gjpaepq62vsbO1t7m7vb/Bw8XHycvNz9HT1dfZ293f4ePl5
++nr7e/x8/X3+G37/f4ABBQ4kWNDgQYQJFS5k2NDhQ4gRJdKLAAA7
similarity index 79%
rename from Documentation/DocBook/dvb/audio.xml
rename to Documentation/DocBook/media/dvb/audio.xml
index eeb96b8..d643862 100644 (file)
@@ -14,17 +14,17 @@ the omission of the audio and video device.
 audio device.
 </para>
 
-<section id="audio_stream_source_t">
+<section id="audio-stream-source-t">
 <title>audio_stream_source_t</title>
 <para>The audio stream source is set through the AUDIO_SELECT_SOURCE call and can take
 the following values, depending on whether we are replaying from an internal (demux) or
 external (user write) source.
 </para>
 <programlisting>
- typedef enum {
-        AUDIO_SOURCE_DEMUX,
-        AUDIO_SOURCE_MEMORY
- } audio_stream_source_t;
+typedef enum {
+       AUDIO_SOURCE_DEMUX,
+       AUDIO_SOURCE_MEMORY
+} audio_stream_source_t;
 </programlisting>
 <para>AUDIO_SOURCE_DEMUX selects the demultiplexer (fed either by the frontend or the
 DVR device) as the source of the video stream. If AUDIO_SOURCE_MEMORY
@@ -33,61 +33,64 @@ call.
 </para>
 
 </section>
-<section id="audio_play_state_t">
+<section id="audio-play-state-t">
 <title>audio_play_state_t</title>
 <para>The following values can be returned by the AUDIO_GET_STATUS call representing the
 state of audio playback.
 </para>
 <programlisting>
- typedef enum {
-        AUDIO_STOPPED,
-        AUDIO_PLAYING,
-        AUDIO_PAUSED
- } audio_play_state_t;
+typedef enum {
+       AUDIO_STOPPED,
+       AUDIO_PLAYING,
+       AUDIO_PAUSED
+} audio_play_state_t;
 </programlisting>
 
 </section>
-<section id="audio_channel_select_t">
+<section id="audio-channel-select-t">
 <title>audio_channel_select_t</title>
 <para>The audio channel selected via AUDIO_CHANNEL_SELECT is determined by the
 following values.
 </para>
 <programlisting>
- typedef enum {
-        AUDIO_STEREO,
-        AUDIO_MONO_LEFT,
-        AUDIO_MONO_RIGHT,
- } audio_channel_select_t;
+typedef enum {
+       AUDIO_STEREO,
+       AUDIO_MONO_LEFT,
+       AUDIO_MONO_RIGHT,
+       AUDIO_MONO,
+       AUDIO_STEREO_SWAPPED
+} audio_channel_select_t;
 </programlisting>
 
 </section>
-<section id="struct_audio_status">
+<section id="audio-status">
 <title>struct audio_status</title>
 <para>The AUDIO_GET_STATUS call returns the following structure informing about various
 states of the playback operation.
 </para>
 <programlisting>
- typedef struct audio_status {
-        boolean AV_sync_state;
-        boolean mute_state;
-        audio_play_state_t play_state;
-        audio_stream_source_t stream_source;
-        audio_channel_select_t channel_select;
-        boolean bypass_mode;
- } audio_status_t;
+typedef struct audio_status {
+       boolean AV_sync_state;
+       boolean mute_state;
+       audio_play_state_t play_state;
+       audio_stream_source_t stream_source;
+       audio_channel_select_t channel_select;
+       boolean bypass_mode;
+       audio_mixer_t mixer_state;
+} audio_status_t;
 </programlisting>
 
 </section>
-<section id="struct_audio_mixer">
+<section id="audio-mixer">
 <title>struct audio_mixer</title>
 <para>The following structure is used by the AUDIO_SET_MIXER call to set the audio
 volume.
 </para>
 <programlisting>
- typedef struct audio_mixer {
-        unsigned int volume_left;
-        unsigned int volume_right;
- } audio_mixer_t;
+typedef struct audio_mixer {
+       unsigned int volume_left;
+       unsigned int volume_right;
+} audio_mixer_t;
 </programlisting>
 
 </section>
@@ -109,17 +112,17 @@ bits set according to the hardwares capabilities.
 </programlisting>
 
 </section>
-<section id="struct_audio_karaoke">
+<section id="audio-karaoke">
 <title>struct audio_karaoke</title>
 <para>The ioctl AUDIO_SET_KARAOKE uses the following format:
 </para>
 <programlisting>
- typedef
- struct audio_karaoke{
-        int vocal1;
-        int vocal2;
-        int melody;
- } audio_karaoke_t;
+typedef
+struct audio_karaoke {
+       int vocal1;
+       int vocal2;
+       int melody;
+} audio_karaoke_t;
 </programlisting>
 <para>If Vocal1 or Vocal2 are non-zero, they get mixed into left and right t at 70% each. If both,
 Vocal1 and Vocal2 are non-zero, Vocal1 gets mixed into the left channel and Vocal2 into the
@@ -128,7 +131,7 @@ and right.
 </para>
 
 </section>
-<section id="audio_attributes">
+<section id="audio-attributes-t">
 <title>audio attributes</title>
 <para>The following attributes can be set by a call to AUDIO_SET_ATTRIBUTES:
 </para>
@@ -217,21 +220,13 @@ and right.
 <para>(blocking mode is the default)</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+<para>RETURN VALUE</para>
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
 <para>ENODEV</para>
 </entry><entry
  align="char">
 <para>Device driver not loaded/available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
 </entry>
  </row><row><entry
  align="char">
@@ -276,8 +271,7 @@ and right.
 <para>File descriptor returned by a previous call to open().</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+<para>RETURN VALUE</para>
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
 <para>EBADF</para>
@@ -332,8 +326,7 @@ and right.
 <para>Size of buf.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+<para>RETURN VALUE</para>
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
 <para>EPERM</para>
@@ -358,7 +351,7 @@ and right.
 </entry>
  </row></tbody></tgroup></informaltable>
 
-</section><section
+</section><section id="AUDIO_STOP"
 role="subsection"><title>AUDIO_STOP</title>
 <para>DESCRIPTION
 </para>
@@ -391,25 +384,9 @@ role="subsection"><title>AUDIO_STOP</title>
 <para>Equals AUDIO_STOP for this command.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 
-</section><section
+</section><section id="AUDIO_PLAY"
 role="subsection"><title>AUDIO_PLAY</title>
 <para>DESCRIPTION
 </para>
@@ -443,25 +420,9 @@ role="subsection"><title>AUDIO_PLAY</title>
 <para>Equals AUDIO_PLAY for this command.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 
-</section><section
+</section><section id="AUDIO_PAUSE"
 role="subsection"><title>AUDIO_PAUSE</title>
 <para>DESCRIPTION
 </para>
@@ -503,25 +464,49 @@ role="subsection"><title>AUDIO_PAUSE</title>
 <para>Equals AUDIO_PAUSE for this command.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
+&return-value-dvb;
+
+</section><section id="AUDIO_CONTINUE"
+role="subsection"><title>AUDIO_CONTINUE</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl restarts the decoding and playing process previously paused
+with AUDIO_PAUSE command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>It only works if the stream were previously stopped with AUDIO_PAUSE</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = AUDIO_CONTINUE);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
 </para>
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
-<para>EBADF</para>
+<para>int fd</para>
 </entry><entry
  align="char">
-<para>fd is not a valid open file descriptor.</para>
+<para>File descriptor returned by a previous call to open().</para>
 </entry>
  </row><row><entry
  align="char">
-<para>EINTERNAL</para>
+<para>int request</para>
 </entry><entry
  align="char">
-<para>Internal error.</para>
+<para>Equals AUDIO_CONTINUE for this command.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 
-</section><section
+</section><section id="AUDIO_SELECT_SOURCE"
 role="subsection"><title>AUDIO_SELECT_SOURCE</title>
 <para>DESCRIPTION
 </para>
@@ -567,32 +552,9 @@ role="subsection"><title>AUDIO_SELECT_SOURCE</title>
  stream.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Illegal input parameter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 
-</section><section
+</section><section id="AUDIO_SET_MUTE"
 role="subsection"><title>AUDIO_SET_MUTE</title>
 <para>DESCRIPTION
 </para>
@@ -646,32 +608,9 @@ role="subsection"><title>AUDIO_SET_MUTE</title>
 <para>FALSE Audio Un-mute</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Illegal input parameter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 
-</section><section
+</section><section id="AUDIO_SET_AV_SYNC"
 role="subsection"><title>AUDIO_SET_AV_SYNC</title>
 <para>DESCRIPTION
 </para>
@@ -725,32 +664,9 @@ role="subsection"><title>AUDIO_SET_AV_SYNC</title>
 <para>FALSE AV-sync OFF</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Illegal input parameter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 
-</section><section
+</section><section id="AUDIO_SET_BYPASS_MODE"
 role="subsection"><title>AUDIO_SET_BYPASS_MODE</title>
 <para>DESCRIPTION
 </para>
@@ -808,32 +724,9 @@ role="subsection"><title>AUDIO_SET_BYPASS_MODE</title>
 <para>FALSE Bypass is enabled</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Illegal input parameter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 
-</section><section
+</section><section id="AUDIO_CHANNEL_SELECT"
 role="subsection"><title>AUDIO_CHANNEL_SELECT</title>
 <para>DESCRIPTION
 </para>
@@ -877,32 +770,9 @@ role="subsection"><title>AUDIO_CHANNEL_SELECT</title>
  stereo).</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Illegal input parameter ch.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 
-</section><section
+</section><section id="AUDIO_GET_STATUS"
 role="subsection"><title>AUDIO_GET_STATUS</title>
 <para>DESCRIPTION
 </para>
@@ -945,32 +815,9 @@ role="subsection"><title>AUDIO_GET_STATUS</title>
 <para>Returns the current state of Audio Device.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>status points to invalid address.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 
-</section><section
+</section><section id="AUDIO_GET_CAPABILITIES"
 role="subsection"><title>AUDIO_GET_CAPABILITIES</title>
 <para>DESCRIPTION
 </para>
@@ -1013,32 +860,9 @@ role="subsection"><title>AUDIO_GET_CAPABILITIES</title>
 <para>Returns a bit array of supported sound formats.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>cap points to an invalid address.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 
-</section><section
+</section><section id="AUDIO_CLEAR_BUFFER"
 role="subsection"><title>AUDIO_CLEAR_BUFFER</title>
 <para>DESCRIPTION
 </para>
@@ -1072,25 +896,9 @@ role="subsection"><title>AUDIO_CLEAR_BUFFER</title>
 <para>Equals AUDIO_CLEAR_BUFFER for this command.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 
-</section><section
+</section><section id="AUDIO_SET_ID"
 role="subsection"><title>AUDIO_SET_ID</title>
 <para>DESCRIPTION
 </para>
@@ -1136,32 +944,9 @@ role="subsection"><title>AUDIO_SET_ID</title>
 <para>audio sub-stream id</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid sub-stream id.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 
-</section><section
+</section><section id="AUDIO_SET_MIXER"
 role="subsection"><title>AUDIO_SET_MIXER</title>
 <para>DESCRIPTION
 </para>
@@ -1202,32 +987,9 @@ role="subsection"><title>AUDIO_SET_MIXER</title>
 <para>mixer settings.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>mix points to an invalid address.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 
-</section><section
+</section><section id="AUDIO_SET_STREAMTYPE"
 role="subsection"><title>AUDIO_SET_STREAMTYPE</title>
 <para>DESCRIPTION
 </para>
@@ -1270,17 +1032,9 @@ role="subsection"><title>AUDIO_SET_STREAMTYPE</title>
 <para>stream type</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+&return-value-dvb;
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
 <para>EINVAL</para>
 </entry><entry
  align="char">
@@ -1288,7 +1042,7 @@ role="subsection"><title>AUDIO_SET_STREAMTYPE</title>
 </entry>
  </row></tbody></tgroup></informaltable>
 
-</section><section
+</section><section id="AUDIO_SET_EXT_ID"
 role="subsection"><title>AUDIO_SET_EXT_ID</title>
 <para>DESCRIPTION
 </para>
@@ -1330,17 +1084,9 @@ role="subsection"><title>AUDIO_SET_EXT_ID</title>
 <para>audio sub_stream_id</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+&return-value-dvb;
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
 <para>EINVAL</para>
 </entry><entry
  align="char">
@@ -1348,7 +1094,7 @@ role="subsection"><title>AUDIO_SET_EXT_ID</title>
 </entry>
  </row></tbody></tgroup></informaltable>
 
-</section><section
+</section><section id="AUDIO_SET_ATTRIBUTES"
 role="subsection"><title>AUDIO_SET_ATTRIBUTES</title>
 <para>DESCRIPTION
 </para>
@@ -1391,17 +1137,9 @@ role="subsection"><title>AUDIO_SET_ATTRIBUTES</title>
 <para>audio attributes according to section ??</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+&return-value-dvb;
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
 <para>EINVAL</para>
 </entry><entry
  align="char">
@@ -1409,7 +1147,7 @@ role="subsection"><title>AUDIO_SET_ATTRIBUTES</title>
 </entry>
  </row></tbody></tgroup></informaltable>
 
-</section><section
+</section><section id="AUDIO_SET_KARAOKE"
 role="subsection"><title>AUDIO_SET_KARAOKE</title>
 <para>DESCRIPTION
 </para>
@@ -1422,7 +1160,7 @@ role="subsection"><title>AUDIO_SET_KARAOKE</title>
 </para>
 <informaltable><tgroup cols="1"><tbody><row><entry
  align="char">
-<para>int ioctl(fd, int request = AUDIO_SET_STREAMTYPE,
+<para>int ioctl(fd, int request = AUDIO_SET_KARAOKE,
  audio_karaoke_t &#x22C6;karaoke);</para>
 </entry>
  </row></tbody></tgroup></informaltable>
@@ -1440,7 +1178,7 @@ role="subsection"><title>AUDIO_SET_KARAOKE</title>
 <para>int request</para>
 </entry><entry
  align="char">
-<para>Equals AUDIO_SET_STREAMTYPE for this
+<para>Equals AUDIO_SET_KARAOKE for this
  command.</para>
 </entry>
  </row><row><entry
@@ -1452,17 +1190,9 @@ role="subsection"><title>AUDIO_SET_KARAOKE</title>
 <para>karaoke settings according to section ??.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+&return-value-dvb;
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
 <para>EINVAL</para>
 </entry><entry
  align="char">
similarity index 67%
rename from Documentation/DocBook/dvb/ca.xml
rename to Documentation/DocBook/media/dvb/ca.xml
index b1f1d2f..5c4adb4 100644 (file)
@@ -8,75 +8,85 @@ including <emphasis role="tt">linux/dvb/ca.h</emphasis> in your application.
 <title>CA Data Types</title>
 
 
-<section id="ca_slot_info_t">
+<section id="ca-slot-info">
 <title>ca_slot_info_t</title>
  <programlisting>
- /&#x22C6; slot interface types and info &#x22C6;/
+typedef struct ca_slot_info {
+       int num;               /&#x22C6; slot number &#x22C6;/
 
- typedef struct ca_slot_info_s {
-        int num;               /&#x22C6; slot number &#x22C6;/
+       int type;              /&#x22C6; CA interface this slot supports &#x22C6;/
+#define CA_CI            1     /&#x22C6; CI high level interface &#x22C6;/
+#define CA_CI_LINK       2     /&#x22C6; CI link layer level interface &#x22C6;/
+#define CA_CI_PHYS       4     /&#x22C6; CI physical layer level interface &#x22C6;/
+#define CA_DESCR         8     /&#x22C6; built-in descrambler &#x22C6;/
+#define CA_SC          128     /&#x22C6; simple smart card interface &#x22C6;/
 
-        int type;           /&#x22C6; CA interface this slot supports &#x22C6;/
- #define CA_CI            1  /&#x22C6; CI high level interface &#x22C6;/
- #define CA_CI_LINK       2  /&#x22C6; CI link layer level interface &#x22C6;/
- #define CA_CI_PHYS       4  /&#x22C6; CI physical layer level interface &#x22C6;/
- #define CA_SC          128  /&#x22C6; simple smart card interface &#x22C6;/
-
-        unsigned int flags;
- #define CA_CI_MODULE_PRESENT 1 /&#x22C6; module (or card) inserted &#x22C6;/
- #define CA_CI_MODULE_READY   2
- } ca_slot_info_t;
+       unsigned int flags;
+#define CA_CI_MODULE_PRESENT 1 /&#x22C6; module (or card) inserted &#x22C6;/
+#define CA_CI_MODULE_READY   2
+} ca_slot_info_t;
 </programlisting>
 
 </section>
-<section id="ca_descr_info_t">
+<section id="ca-descr-info">
 <title>ca_descr_info_t</title>
- <programlisting>
- typedef struct ca_descr_info_s {
-        unsigned int num;  /&#x22C6; number of available descramblers (keys) &#x22C6;/
-        unsigned int type; /&#x22C6; type of supported scrambling system &#x22C6;/
- #define CA_ECD           1
- #define CA_NDS           2
- #define CA_DSS           4
- } ca_descr_info_t;
+<programlisting>
+typedef struct ca_descr_info {
+       unsigned int num;  /&#x22C6; number of available descramblers (keys) &#x22C6;/
+       unsigned int type; /&#x22C6; type of supported scrambling system &#x22C6;/
+#define CA_ECD           1
+#define CA_NDS           2
+#define CA_DSS           4
+} ca_descr_info_t;
 </programlisting>
 
 </section>
-<section id="ca_cap_t">
-<title>ca_cap_t</title>
- <programlisting>
- typedef struct ca_cap_s {
-        unsigned int slot_num;  /&#x22C6; total number of CA card and module slots &#x22C6;/
-        unsigned int slot_type; /&#x22C6; OR of all supported types &#x22C6;/
-        unsigned int descr_num; /&#x22C6; total number of descrambler slots (keys) &#x22C6;/
-        unsigned int descr_type;/&#x22C6; OR of all supported types &#x22C6;/
+<section id="ca-caps">
+<title>ca_caps_t</title>
+<programlisting>
+typedef struct ca_caps {
+       unsigned int slot_num;  /&#x22C6; total number of CA card and module slots &#x22C6;/
+       unsigned int slot_type; /&#x22C6; OR of all supported types &#x22C6;/
+       unsigned int descr_num; /&#x22C6; total number of descrambler slots (keys) &#x22C6;/
+       unsigned int descr_type;/&#x22C6; OR of all supported types &#x22C6;/
  } ca_cap_t;
 </programlisting>
 
 </section>
-<section id="ca_msg_t">
+<section id="ca-msg">
 <title>ca_msg_t</title>
- <programlisting>
- /&#x22C6; a message to/from a CI-CAM &#x22C6;/
- typedef struct ca_msg_s {
-        unsigned int index;
-        unsigned int type;
-        unsigned int length;
-        unsigned char msg[256];
- } ca_msg_t;
+<programlisting>
+/&#x22C6; a message to/from a CI-CAM &#x22C6;/
+typedef struct ca_msg {
+       unsigned int index;
+       unsigned int type;
+       unsigned int length;
+       unsigned char msg[256];
+} ca_msg_t;
 </programlisting>
 
 </section>
-<section id="ca_descr_t">
+<section id="ca-descr">
 <title>ca_descr_t</title>
- <programlisting>
- typedef struct ca_descr_s {
-        unsigned int index;
-        unsigned int parity;
-        unsigned char cw[8];
- } ca_descr_t;
+<programlisting>
+typedef struct ca_descr {
+       unsigned int index;
+       unsigned int parity;
+       unsigned char cw[8];
+} ca_descr_t;
 </programlisting>
- </section></section>
+</section>
+
+<section id="ca-pid">
+<title>ca-pid</title>
+<programlisting>
+typedef struct ca_pid {
+       unsigned int pid;
+       int index;              /&#x22C6; -1 == disable&#x22C6;/
+} ca_pid_t;
+</programlisting>
+</section></section>
+
 <section id="ca_function_calls">
 <title>CA Function Calls</title>
 
@@ -148,8 +158,7 @@ including <emphasis role="tt">linux/dvb/ca.h</emphasis> in your application.
 <para>(blocking mode is the default)</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+<para>RETURN VALUE</para>
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
 <para>ENODEV</para>
@@ -207,8 +216,7 @@ including <emphasis role="tt">linux/dvb/ca.h</emphasis> in your application.
 <para>File descriptor returned by a previous call to open().</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+<para>RETURN VALUE</para>
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
 <para>EBADF</para>
similarity index 84%
rename from Documentation/DocBook/dvb/demux.xml
rename to Documentation/DocBook/media/dvb/demux.xml
index 1b8c4e9..37c1790 100644 (file)
@@ -7,15 +7,19 @@ accessed by including <emphasis role="tt">linux/dvb/dmx.h</emphasis> in your app
 <section id="dmx_types">
 <title>Demux Data Types</title>
 
-<section id="dmx_output_t">
+<section id="dmx-output-t">
 <title>dmx_output_t</title>
- <programlisting>
- typedef enum
- {
-        DMX_OUT_DECODER,
-        DMX_OUT_TAP,
-        DMX_OUT_TS_TAP
- } dmx_output_t;
+<programlisting>
+typedef enum
+{
+       DMX_OUT_DECODER, /&#x22C6; Streaming directly to decoder. &#x22C6;/
+       DMX_OUT_TAP,     /&#x22C6; Output going to a memory buffer &#x22C6;/
+                        /&#x22C6; (to be retrieved via the read command).&#x22C6;/
+       DMX_OUT_TS_TAP,  /&#x22C6; Output multiplexed into a new TS  &#x22C6;/
+                        /&#x22C6; (to be retrieved by reading from the &#x22C6;/
+                        /&#x22C6; logical DVR device).                 &#x22C6;/
+       DMX_OUT_TSDEMUX_TAP /&#x22C6; Like TS_TAP but retrieved from the DMX device &#x22C6;/
+} dmx_output_t;
 </programlisting>
 <para><emphasis role="tt">DMX_OUT_TAP</emphasis> delivers the stream output to the demux device on which the ioctl is
 called.
@@ -26,96 +30,95 @@ specified.
 </para>
 </section>
 
-<section id="dmx_input_t">
+<section id="dmx-input-t">
 <title>dmx_input_t</title>
- <programlisting>
- typedef enum
- {
-        DMX_IN_FRONTEND,
-        DMX_IN_DVR
- } dmx_input_t;
+<programlisting>
+typedef enum
+{
+       DMX_IN_FRONTEND, /&#x22C6; Input from a front-end device.  &#x22C6;/
+       DMX_IN_DVR       /&#x22C6; Input from the logical DVR device.  &#x22C6;/
+} dmx_input_t;
 </programlisting>
 </section>
 
-<section id="dmx_pes_type_t">
+<section id="dmx-pes-type-t">
 <title>dmx_pes_type_t</title>
- <programlisting>
- typedef enum
- {
-        DMX_PES_AUDIO,
-        DMX_PES_VIDEO,
-        DMX_PES_TELETEXT,
-        DMX_PES_SUBTITLE,
-        DMX_PES_PCR,
-        DMX_PES_OTHER
- } dmx_pes_type_t;
-</programlisting>
-</section>
+<programlisting>
+typedef enum
+{
+       DMX_PES_AUDIO0,
+       DMX_PES_VIDEO0,
+       DMX_PES_TELETEXT0,
+       DMX_PES_SUBTITLE0,
+       DMX_PES_PCR0,
 
-<section id="dmx_event_t">
-<title>dmx_event_t</title>
- <programlisting>
- typedef enum
- {
-        DMX_SCRAMBLING_EV,
-        DMX_FRONTEND_EV
- } dmx_event_t;
-</programlisting>
-</section>
+       DMX_PES_AUDIO1,
+       DMX_PES_VIDEO1,
+       DMX_PES_TELETEXT1,
+       DMX_PES_SUBTITLE1,
+       DMX_PES_PCR1,
 
-<section id="dmx_scrambling_status_t">
-<title>dmx_scrambling_status_t</title>
- <programlisting>
- typedef enum
- {
-        DMX_SCRAMBLING_OFF,
-        DMX_SCRAMBLING_ON
- } dmx_scrambling_status_t;
+       DMX_PES_AUDIO2,
+       DMX_PES_VIDEO2,
+       DMX_PES_TELETEXT2,
+       DMX_PES_SUBTITLE2,
+       DMX_PES_PCR2,
+
+       DMX_PES_AUDIO3,
+       DMX_PES_VIDEO3,
+       DMX_PES_TELETEXT3,
+       DMX_PES_SUBTITLE3,
+       DMX_PES_PCR3,
+
+       DMX_PES_OTHER
+} dmx_pes_type_t;
 </programlisting>
 </section>
 
-<section id="dmx_filter">
+<section id="dmx-filter">
 <title>struct dmx_filter</title>
  <programlisting>
  typedef struct dmx_filter
- {
-        uint8_t         filter[DMX_FILTER_SIZE];
-        uint8_t         mask[DMX_FILTER_SIZE];
- } dmx_filter_t;
+{
+       __u8  filter[DMX_FILTER_SIZE];
+       __u8  mask[DMX_FILTER_SIZE];
+       __u8  mode[DMX_FILTER_SIZE];
+} dmx_filter_t;
 </programlisting>
 </section>
 
-<section id="dmx_sct_filter_params">
+<section id="dmx-sct-filter-params">
 <title>struct dmx_sct_filter_params</title>
- <programlisting>
- struct dmx_sct_filter_params
- {
-        uint16_t            pid;
-        dmx_filter_t        filter;
-        uint32_t            timeout;
-        uint32_t            flags;
- #define DMX_CHECK_CRC       1
- #define DMX_ONESHOT         2
- #define DMX_IMMEDIATE_START 4
- };
+<programlisting>
+struct dmx_sct_filter_params
+{
+       __u16          pid;
+       dmx_filter_t   filter;
+       __u32          timeout;
+       __u32          flags;
+#define DMX_CHECK_CRC       1
+#define DMX_ONESHOT         2
+#define DMX_IMMEDIATE_START 4
+#define DMX_KERNEL_CLIENT   0x8000
+};
 </programlisting>
 </section>
 
-<section id="dmx_pes_filter_params">
+<section id="dmx-pes-filter-params">
 <title>struct dmx_pes_filter_params</title>
- <programlisting>
- struct dmx_pes_filter_params
- {
-        uint16_t            pid;
-        dmx_input_t         input;
-        dmx_output_t        output;
-        dmx_pes_type_t      pes_type;
-        uint32_t            flags;
- };
+<programlisting>
+struct dmx_pes_filter_params
+{
+       __u16          pid;
+       dmx_input_t    input;
+       dmx_output_t   output;
+       dmx_pes_type_t pes_type;
+       __u32          flags;
+};
 </programlisting>
 </section>
 
-<section id="dmx_event">
+<section id="dmx-event">
 <title>struct dmx_event</title>
  <programlisting>
  struct dmx_event
@@ -130,19 +133,44 @@ specified.
 </programlisting>
 </section>
 
-<section id="dmx_stc">
+<section id="dmx-stc">
 <title>struct dmx_stc</title>
- <programlisting>
- struct dmx_stc {
-        unsigned int num;       /&#x22C6; input : which STC? 0..N &#x22C6;/
-        unsigned int base;      /&#x22C6; output: divisor for stc to get 90 kHz clock &#x22C6;/
-        uint64_t stc;           /&#x22C6; output: stc in 'base'&#x22C6;90 kHz units &#x22C6;/
- };
+<programlisting>
+struct dmx_stc {
+       unsigned int num;       /&#x22C6; input : which STC? 0..N &#x22C6;/
+       unsigned int base;      /&#x22C6; output: divisor for stc to get 90 kHz clock &#x22C6;/
+       __u64 stc;              /&#x22C6; output: stc in 'base'&#x22C6;90 kHz units &#x22C6;/
+};
 </programlisting>
- </section>
+</section>
 
+<section id="dmx-caps">
+<title>struct dmx_caps</title>
+<programlisting>
+ typedef struct dmx_caps {
+       __u32 caps;
+       int num_decoders;
+} dmx_caps_t;
+</programlisting>
+</section>
+
+<section id="dmx-source-t">
+<title>enum dmx_source_t</title>
+<programlisting>
+typedef enum {
+       DMX_SOURCE_FRONT0 = 0,
+       DMX_SOURCE_FRONT1,
+       DMX_SOURCE_FRONT2,
+       DMX_SOURCE_FRONT3,
+       DMX_SOURCE_DVR0   = 16,
+       DMX_SOURCE_DVR1,
+       DMX_SOURCE_DVR2,
+       DMX_SOURCE_DVR3
+} dmx_source_t;
+</programlisting>
 </section>
 
+</section>
 <section id="dmx_fcalls">
 <title>Demux Function Calls</title>
 
@@ -211,8 +239,7 @@ specified.
 <para>(blocking mode is the default)</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+<para>RETURN VALUE</para>
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
 <para>ENODEV</para>
@@ -271,8 +298,7 @@ specified.
 <para>File descriptor returned by a previous call to open().</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+<para>RETURN VALUE</para>
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
 <para>EBADF</para>
@@ -353,8 +379,7 @@ specified.
 <para>Size of buf.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+<para>RETURN VALUE</para>
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
 <para>EWOULDBLOCK</para>
@@ -457,8 +482,7 @@ specified.
 <para>Size of buf.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+<para>RETURN VALUE</para>
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
 <para>EWOULDBLOCK</para>
@@ -491,7 +515,7 @@ specified.
  </row></tbody></tgroup></informaltable>
 </section>
 
-<section id="dmx_start">
+<section id="DMX_START">
 <title>DMX_START</title>
 <para>DESCRIPTION
 </para>
@@ -525,17 +549,9 @@ specified.
 <para>Equals DMX_START for this command.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+&return-value-dvb;
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
 <para>EINVAL</para>
 </entry><entry
  align="char">
@@ -556,7 +572,7 @@ specified.
  </row></tbody></tgroup></informaltable>
 </section>
 
-<section id="dmx_stop">
+<section id="DMX_STOP">
 <title>DMX_STOP</title>
 <para>DESCRIPTION
 </para>
@@ -591,19 +607,10 @@ specified.
 <para>Equals DMX_STOP for this command.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid file descriptor.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 </section>
 
-<section id="dmx_set_filter">
+<section id="DMX_SET_FILTER">
 <title>DMX_SET_FILTER</title>
 <para>DESCRIPTION
 </para>
@@ -654,26 +661,10 @@ specified.
 <para>Pointer to structure containing filter parameters.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid argument.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 </section>
 
-<section id="dmx_set_pes_filter">
+<section id="DMX_SET_PES_FILTER">
 <title>DMX_SET_PES_FILTER</title>
 <para>DESCRIPTION
 </para>
@@ -727,24 +718,9 @@ specified.
 <para>Pointer to structure containing filter parameters.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+&return-value-dvb;
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid argument.</para>
-</entry>
- </row><row><entry
- align="char">
 <para>EBUSY</para>
 </entry><entry
  align="char">
@@ -756,7 +732,7 @@ specified.
  </row></tbody></tgroup></informaltable>
 </section>
 
-<section id="dms_set_buffer_size">
+<section id="DMX_SET_BUFFER_SIZE">
 <title>DMX_SET_BUFFER_SIZE</title>
 <para>DESCRIPTION
 </para>
@@ -799,27 +775,10 @@ specified.
 <para>Size of circular buffer.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ENOMEM</para>
-</entry><entry
- align="char">
-<para>The driver was not able to allocate a buffer of the
- requested size.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 </section>
 
-<section id="dmx_get_event">
+<section id="DMX_GET_EVENT">
 <title>DMX_GET_EVENT</title>
 <para>DESCRIPTION
 </para>
@@ -872,24 +831,9 @@ specified.
 <para>Pointer to the location where the event is to be stored.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+&return-value-dvb;
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>ev points to an invalid address.</para>
-</entry>
- </row><row><entry
- align="char">
 <para>EWOULDBLOCK</para>
 </entry><entry
  align="char">
@@ -899,7 +843,7 @@ specified.
  </row></tbody></tgroup></informaltable>
 </section>
 
-<section id="dmx_get_stc">
+<section id="DMX_GET_STC">
 <title>DMX_GET_STC</title>
 <para>DESCRIPTION
 </para>
@@ -946,24 +890,9 @@ specified.
 <para>Pointer to the location where the stc is to be stored.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+&return-value-dvb;
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>stc points to an invalid address.</para>
-</entry>
- </row><row><entry
- align="char">
 <para>EINVAL</para>
 </entry><entry
  align="char">
similarity index 85%
rename from Documentation/DocBook/dvb/dvbapi.xml
rename to Documentation/DocBook/media/dvb/dvbapi.xml
index 9fad86c..2ab6ddc 100644 (file)
@@ -114,8 +114,28 @@ Added ISDB-T test originally written by Patrick Boettcher
     &sub-examples;
   </chapter>
 <!-- END OF CHAPTERS -->
+  <appendix id="audio_h">
+    <title>DVB Audio Header File</title>
+    &sub-audio-h;
+  </appendix>
+  <appendix id="ca_h">
+    <title>DVB Conditional Access Header File</title>
+    &sub-ca-h;
+  </appendix>
+  <appendix id="dmx_h">
+    <title>DVB Demux Header File</title>
+    &sub-dmx-h;
+  </appendix>
   <appendix id="frontend_h">
     <title>DVB Frontend Header File</title>
     &sub-frontend-h;
   </appendix>
+  <appendix id="net_h">
+    <title>DVB Network Header File</title>
+    &sub-net-h;
+  </appendix>
+  <appendix id="video_h">
+    <title>DVB Video Header File</title>
+    &sub-video-h;
+  </appendix>
 
diff --git a/Documentation/DocBook/media/dvb/dvbproperty.xml b/Documentation/DocBook/media/dvb/dvbproperty.xml
new file mode 100644 (file)
index 0000000..207e1a5
--- /dev/null
@@ -0,0 +1,859 @@
+<section id="FE_GET_SET_PROPERTY">
+<title><constant>FE_GET_PROPERTY/FE_SET_PROPERTY</constant></title>
+<para>This section describes the DVB version 5 extention of the DVB-API, also
+called "S2API", as this API were added to provide support for DVB-S2. It was
+designed to be able to replace the old frontend API. Yet, the DISEQC and
+the capability ioctls weren't implemented yet via the new way.</para>
+<para>The typical usage for the <constant>FE_GET_PROPERTY/FE_SET_PROPERTY</constant>
+API is to replace the ioctl's were the <link linkend="dvb-frontend-parameters">
+struct <constant>dvb_frontend_parameters</constant></link> were used.</para>
+<section id="dtv-property">
+<title>DTV property type</title>
+<programlisting>
+/* Reserved fields should be set to 0 */
+struct dtv_property {
+       __u32 cmd;
+       union {
+               __u32 data;
+               struct {
+                       __u8 data[32];
+                       __u32 len;
+                       __u32 reserved1[3];
+                       void *reserved2;
+               } buffer;
+       } u;
+       int result;
+} __attribute__ ((packed));
+
+/* num of properties cannot exceed DTV_IOCTL_MAX_MSGS per ioctl */
+#define DTV_IOCTL_MAX_MSGS 64
+</programlisting>
+</section>
+<section id="dtv-properties">
+<title>DTV properties type</title>
+<programlisting>
+struct dtv_properties {
+       __u32 num;
+       struct dtv_property *props;
+};
+</programlisting>
+</section>
+
+<section id="FE_GET_PROPERTY">
+<title>FE_GET_PROPERTY</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call returns one or more frontend properties. This call only
+ requires read-only access to the device.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link>,
+ dtv_properties &#x22C6;props);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int num</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link> for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct dtv_property *props</para>
+</entry><entry
+ align="char">
+<para>Points to the location where the front-end property commands are stored.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row>
+  <entry align="char"><para>EOPNOTSUPP</para></entry>
+  <entry align="char"><para>Property type not supported.</para></entry>
+ </row></tbody></tgroup></informaltable>
+</section>
+
+<section id="FE_SET_PROPERTY">
+<title>FE_SET_PROPERTY</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call sets one or more frontend properties. This call only
+ requires read-only access to the device.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = <link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link>,
+ dtv_properties &#x22C6;props);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int num</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link> for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct dtv_property *props</para>
+</entry><entry
+ align="char">
+<para>Points to the location where the front-end property commands are stored.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row>
+  <entry align="char"><para>EOPNOTSUPP</para></entry>
+  <entry align="char"><para>Property type not supported.</para></entry>
+ </row></tbody></tgroup></informaltable>
+</section>
+
+<section>
+       <title>Property types</title>
+<para>
+On <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link>/<link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link>,
+the actual action is determined by the dtv_property cmd/data pairs. With one single ioctl, is possible to
+get/set up to 64 properties. The actual meaning of each property is described on the next sections.
+</para>
+
+<para>The available frontend property types are shown on the next section.</para>
+</section>
+
+<section id="fe_property_parameters">
+       <title>Digital TV property parameters</title>
+       <section id="DTV-UNDEFINED">
+       <title><constant>DTV_UNDEFINED</constant></title>
+       <para>Used internally. A GET/SET operation for it won't change or return anything.</para>
+       </section>
+       <section id="DTV-TUNE">
+       <title><constant>DTV_TUNE</constant></title>
+       <para>Interpret the cache of data, build either a traditional frontend tunerequest so we can pass validation in the <constant>FE_SET_FRONTEND</constant> ioctl.</para>
+       </section>
+       <section id="DTV-CLEAR">
+       <title><constant>DTV_CLEAR</constant></title>
+       <para>Reset a cache of data specific to the frontend here. This does not effect hardware.</para>
+       </section>
+       <section id="DTV-FREQUENCY">
+               <title><constant>DTV_FREQUENCY</constant></title>
+
+               <para>Central frequency of the channel, in HZ.</para>
+
+               <para>Notes:</para>
+               <para>1)For ISDB-T, the channels are usually transmitted with an offset of 143kHz.
+                       E.g. a valid frequncy could be 474143 kHz. The stepping is bound to the bandwidth of
+                       the channel which is 6MHz.</para>
+
+               <para>2)As in ISDB-Tsb the channel consists of only one or three segments the
+                       frequency step is 429kHz, 3*429 respectively. As for ISDB-T the
+                       central frequency of the channel is expected.</para>
+       </section>
+       <section id="DTV-MODULATION">
+       <title><constant>DTV_MODULATION</constant></title>
+<para>Specifies the frontend modulation type for cable and satellite types. The modulation can be one of the types bellow:</para>
+<programlisting>
+ typedef enum fe_modulation {
+       QPSK,
+       QAM_16,
+       QAM_32,
+       QAM_64,
+       QAM_128,
+       QAM_256,
+       QAM_AUTO,
+       VSB_8,
+       VSB_16,
+       PSK_8,
+       APSK_16,
+       APSK_32,
+       DQPSK,
+ } fe_modulation_t;
+</programlisting>
+       </section>
+       <section id="DTV-BANDWIDTH-HZ">
+               <title><constant>DTV_BANDWIDTH_HZ</constant></title>
+
+               <para>Bandwidth for the channel, in HZ.</para>
+
+               <para>Possible values:
+                       <constant>1712000</constant>,
+                       <constant>5000000</constant>,
+                       <constant>6000000</constant>,
+                       <constant>7000000</constant>,
+                       <constant>8000000</constant>,
+                       <constant>10000000</constant>.
+               </para>
+
+               <para>Notes:</para>
+
+               <para>1) For ISDB-T it should be always 6000000Hz (6MHz)</para>
+               <para>2) For ISDB-Tsb it can vary depending on the number of connected segments</para>
+               <para>3) Bandwidth doesn't apply for DVB-C transmissions, as the bandwidth
+                        for DVB-C depends on the symbol rate</para>
+               <para>4) Bandwidth in ISDB-T is fixed (6MHz) or can be easily derived from
+                       other parameters (DTV_ISDBT_SB_SEGMENT_IDX,
+                       DTV_ISDBT_SB_SEGMENT_COUNT).</para>
+               <para>5) DVB-T supports 6, 7 and 8MHz.</para>
+               <para>6) In addition, DVB-T2 supports 1.172, 5 and 10MHz.</para>
+       </section>
+       <section id="DTV-INVERSION">
+       <title><constant>DTV_INVERSION</constant></title>
+       <para>The Inversion field can take one of these values:
+       </para>
+       <programlisting>
+       typedef enum fe_spectral_inversion {
+               INVERSION_OFF,
+               INVERSION_ON,
+               INVERSION_AUTO
+       } fe_spectral_inversion_t;
+       </programlisting>
+       <para>It indicates if spectral inversion should be presumed or not. In the automatic setting
+       (<constant>INVERSION_AUTO</constant>) the hardware will try to figure out the correct setting by
+       itself.
+       </para>
+       </section>
+       <section id="DTV-DISEQC-MASTER">
+       <title><constant>DTV_DISEQC_MASTER</constant></title>
+       <para>Currently not implemented.</para>
+       </section>
+       <section id="DTV-SYMBOL-RATE">
+       <title><constant>DTV_SYMBOL_RATE</constant></title>
+       <para>Digital TV symbol rate, in bauds (symbols/second). Used on cable standards.</para>
+       </section>
+       <section id="DTV-INNER-FEC">
+       <title><constant>DTV_INNER_FEC</constant></title>
+       <para>Used cable/satellite transmissions. The acceptable values are:
+       </para>
+       <programlisting>
+typedef enum fe_code_rate {
+       FEC_NONE = 0,
+       FEC_1_2,
+       FEC_2_3,
+       FEC_3_4,
+       FEC_4_5,
+       FEC_5_6,
+       FEC_6_7,
+       FEC_7_8,
+       FEC_8_9,
+       FEC_AUTO,
+       FEC_3_5,
+       FEC_9_10,
+} fe_code_rate_t;
+       </programlisting>
+       <para>which correspond to error correction rates of 1/2, 2/3, etc.,
+       no error correction or auto detection.</para>
+       </section>
+       <section id="DTV-VOLTAGE">
+       <title><constant>DTV_VOLTAGE</constant></title>
+       <para>The voltage is usually used with non-DiSEqC capable LNBs to switch
+       the polarzation (horizontal/vertical). When using DiSEqC epuipment this
+       voltage has to be switched consistently to the DiSEqC commands as
+       described in the DiSEqC spec.</para>
+       <programlisting>
+               typedef enum fe_sec_voltage {
+               SEC_VOLTAGE_13,
+               SEC_VOLTAGE_18
+               } fe_sec_voltage_t;
+       </programlisting>
+       </section>
+       <section id="DTV-TONE">
+       <title><constant>DTV_TONE</constant></title>
+       <para>Currently not used.</para>
+       </section>
+       <section id="DTV-PILOT">
+       <title><constant>DTV_PILOT</constant></title>
+       <para>Sets DVB-S2 pilot</para>
+       <section id="fe-pilot-t">
+               <title>fe_pilot type</title>
+               <programlisting>
+typedef enum fe_pilot {
+       PILOT_ON,
+       PILOT_OFF,
+       PILOT_AUTO,
+} fe_pilot_t;
+               </programlisting>
+               </section>
+       </section>
+       <section id="DTV-ROLLOFF">
+       <title><constant>DTV_ROLLOFF</constant></title>
+               <para>Sets DVB-S2 rolloff</para>
+
+       <section id="fe-rolloff-t">
+               <title>fe_rolloff type</title>
+               <programlisting>
+typedef enum fe_rolloff {
+       ROLLOFF_35, /* Implied value in DVB-S, default for DVB-S2 */
+       ROLLOFF_20,
+       ROLLOFF_25,
+       ROLLOFF_AUTO,
+} fe_rolloff_t;
+               </programlisting>
+               </section>
+       </section>
+       <section id="DTV-DISEQC-SLAVE-REPLY">
+       <title><constant>DTV_DISEQC_SLAVE_REPLY</constant></title>
+       <para>Currently not implemented.</para>
+       </section>
+       <section id="DTV-FE-CAPABILITY-COUNT">
+       <title><constant>DTV_FE_CAPABILITY_COUNT</constant></title>
+       <para>Currently not implemented.</para>
+       </section>
+       <section id="DTV-FE-CAPABILITY">
+       <title><constant>DTV_FE_CAPABILITY</constant></title>
+       <para>Currently not implemented.</para>
+       </section>
+       <section id="DTV-DELIVERY-SYSTEM">
+               <title><constant>DTV_DELIVERY_SYSTEM</constant></title>
+               <para>Specifies the type of Delivery system</para>
+               <section id="fe-delivery-system-t">
+               <title>fe_delivery_system type</title>
+               <para>Possible values: </para>
+<programlisting>
+typedef enum fe_delivery_system {
+       SYS_UNDEFINED,
+       SYS_DVBC_ANNEX_AC,
+       SYS_DVBC_ANNEX_B,
+       SYS_DVBT,
+       SYS_DSS,
+       SYS_DVBS,
+       SYS_DVBS2,
+       SYS_DVBH,
+       SYS_ISDBT,
+       SYS_ISDBS,
+       SYS_ISDBC,
+       SYS_ATSC,
+       SYS_ATSCMH,
+       SYS_DMBTH,
+       SYS_CMMB,
+       SYS_DAB,
+       SYS_DVBT2,
+} fe_delivery_system_t;
+</programlisting>
+               </section>
+       </section>
+       <section id="DTV-ISDBT-PARTIAL-RECEPTION">
+               <title><constant>DTV_ISDBT_PARTIAL_RECEPTION</constant></title>
+
+               <para>If <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> is '0' this bit-field represents whether
+                       the channel is in partial reception mode or not.</para>
+
+               <para>If '1' <constant>DTV_ISDBT_LAYERA_*</constant> values are assigned to the center segment and
+                       <constant>DTV_ISDBT_LAYERA_SEGMENT_COUNT</constant> has to be '1'.</para>
+
+               <para>If in addition <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> is '1'
+                       <constant>DTV_ISDBT_PARTIAL_RECEPTION</constant> represents whether this ISDB-Tsb channel
+                       is consisting of one segment and layer or three segments and two layers.</para>
+
+               <para>Possible values: 0, 1, -1 (AUTO)</para>
+       </section>
+       <section id="DTV-ISDBT-SOUND-BROADCASTING">
+               <title><constant>DTV_ISDBT_SOUND_BROADCASTING</constant></title>
+
+               <para>This field represents whether the other DTV_ISDBT_*-parameters are
+                       referring to an ISDB-T and an ISDB-Tsb channel. (See also
+                       <constant>DTV_ISDBT_PARTIAL_RECEPTION</constant>).</para>
+
+               <para>Possible values: 0, 1, -1 (AUTO)</para>
+       </section>
+       <section id="DTV-ISDBT-SB-SUBCHANNEL-ID">
+               <title><constant>DTV_ISDBT_SB_SUBCHANNEL_ID</constant></title>
+
+               <para>This field only applies if <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> is '1'.</para>
+
+               <para>(Note of the author: This might not be the correct description of the
+                       <constant>SUBCHANNEL-ID</constant> in all details, but it is my understanding of the technical
+                       background needed to program a device)</para>
+
+               <para>An ISDB-Tsb channel (1 or 3 segments) can be broadcasted alone or in a
+                       set of connected ISDB-Tsb channels. In this set of channels every
+                       channel can be received independently. The number of connected
+                       ISDB-Tsb segment can vary, e.g. depending on the frequency spectrum
+                       bandwidth available.</para>
+
+               <para>Example: Assume 8 ISDB-Tsb connected segments are broadcasted. The
+                       broadcaster has several possibilities to put those channels in the
+                       air: Assuming a normal 13-segment ISDB-T spectrum he can align the 8
+                       segments from position 1-8 to 5-13 or anything in between.</para>
+
+               <para>The underlying layer of segments are subchannels: each segment is
+                       consisting of several subchannels with a predefined IDs. A sub-channel
+                       is used to help the demodulator to synchronize on the channel.</para>
+
+               <para>An ISDB-T channel is always centered over all sub-channels. As for
+                       the example above, in ISDB-Tsb it is no longer as simple as that.</para>
+
+               <para><constant>The DTV_ISDBT_SB_SUBCHANNEL_ID</constant> parameter is used to give the
+                       sub-channel ID of the segment to be demodulated.</para>
+
+               <para>Possible values: 0 .. 41, -1 (AUTO)</para>
+       </section>
+       <section id="DTV-ISDBT-SB-SEGMENT-IDX">
+               <title><constant>DTV_ISDBT_SB_SEGMENT_IDX</constant></title>
+               <para>This field only applies if <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> is '1'.</para>
+               <para><constant>DTV_ISDBT_SB_SEGMENT_IDX</constant> gives the index of the segment to be
+                       demodulated for an ISDB-Tsb channel where several of them are
+                       transmitted in the connected manner.</para>
+               <para>Possible values: 0 .. <constant>DTV_ISDBT_SB_SEGMENT_COUNT</constant> - 1</para>
+               <para>Note: This value cannot be determined by an automatic channel search.</para>
+       </section>
+       <section id="DTV-ISDBT-SB-SEGMENT-COUNT">
+               <title><constant>DTV_ISDBT_SB_SEGMENT_COUNT</constant></title>
+               <para>This field only applies if <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> is '1'.</para>
+               <para><constant>DTV_ISDBT_SB_SEGMENT_COUNT</constant> gives the total count of connected ISDB-Tsb
+                       channels.</para>
+               <para>Possible values: 1 .. 13</para>
+               <para>Note: This value cannot be determined by an automatic channel search.</para>
+       </section>
+       <section id="isdb-hierq-layers">
+               <title><constant>DTV-ISDBT-LAYER*</constant> parameters</title>
+               <para>ISDB-T channels can be coded hierarchically. As opposed to DVB-T in
+                       ISDB-T hierarchical layers can be decoded simultaneously. For that
+                       reason a ISDB-T demodulator has 3 viterbi and 3 reed-solomon-decoders.</para>
+               <para>ISDB-T has 3 hierarchical layers which each can use a part of the
+                       available segments. The total number of segments over all layers has
+                       to 13 in ISDB-T.</para>
+               <para>There are 3 parameter sets, for Layers A, B and C.</para>
+               <section id="DTV-ISDBT-LAYER-ENABLED">
+                       <title><constant>DTV_ISDBT_LAYER_ENABLED</constant></title>
+                       <para>Hierarchical reception in ISDB-T is achieved by enabling or disabling
+                               layers in the decoding process. Setting all bits of
+                               <constant>DTV_ISDBT_LAYER_ENABLED</constant> to '1' forces all layers (if applicable) to be
+                               demodulated. This is the default.</para>
+                       <para>If the channel is in the partial reception mode
+                               (<constant>DTV_ISDBT_PARTIAL_RECEPTION</constant> = 1) the central segment can be decoded
+                               independently of the other 12 segments. In that mode layer A has to
+                               have a <constant>SEGMENT_COUNT</constant> of 1.</para>
+                       <para>In ISDB-Tsb only layer A is used, it can be 1 or 3 in ISDB-Tsb
+                               according to <constant>DTV_ISDBT_PARTIAL_RECEPTION</constant>. <constant>SEGMENT_COUNT</constant> must be filled
+                               accordingly.</para>
+                       <para>Possible values: 0x1, 0x2, 0x4 (|-able)</para>
+                       <para><constant>DTV_ISDBT_LAYER_ENABLED[0:0]</constant> - layer A</para>
+                       <para><constant>DTV_ISDBT_LAYER_ENABLED[1:1]</constant> - layer B</para>
+                       <para><constant>DTV_ISDBT_LAYER_ENABLED[2:2]</constant> - layer C</para>
+                       <para><constant>DTV_ISDBT_LAYER_ENABLED[31:3]</constant> unused</para>
+               </section>
+               <section id="DTV-ISDBT-LAYER-FEC">
+                       <title><constant>DTV_ISDBT_LAYER*_FEC</constant></title>
+                       <para>Possible values: <constant>FEC_AUTO</constant>, <constant>FEC_1_2</constant>, <constant>FEC_2_3</constant>, <constant>FEC_3_4</constant>, <constant>FEC_5_6</constant>, <constant>FEC_7_8</constant></para>
+               </section>
+               <section id="DTV-ISDBT-LAYER-MODULATION">
+                       <title><constant>DTV_ISDBT_LAYER*_MODULATION</constant></title>
+                       <para>Possible values: <constant>QAM_AUTO</constant>, QP<constant>SK, QAM_16</constant>, <constant>QAM_64</constant>, <constant>DQPSK</constant></para>
+                       <para>Note: If layer C is <constant>DQPSK</constant> layer B has to be <constant>DQPSK</constant>. If layer B is <constant>DQPSK</constant>
+                               and <constant>DTV_ISDBT_PARTIAL_RECEPTION</constant>=0 layer has to be <constant>DQPSK</constant>.</para>
+               </section>
+               <section id="DTV-ISDBT-LAYER-SEGMENT-COUNT">
+                       <title><constant>DTV_ISDBT_LAYER*_SEGMENT_COUNT</constant></title>
+                       <para>Possible values: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, -1 (AUTO)</para>
+                       <para>Note: Truth table for <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> and
+                               <constant>DTV_ISDBT_PARTIAL_RECEPTION</constant> and <constant>LAYER</constant>*_SEGMENT_COUNT</para>
+                       <informaltable id="isdbt-layer_seg-cnt-table">
+                               <tgroup cols="6">
+                                       <tbody>
+                                               <row>
+                                                       <entry>PR</entry>
+                                                       <entry>SB</entry>
+                                                       <entry>Layer A width</entry>
+                                                       <entry>Layer B width</entry>
+                                                       <entry>Layer C width</entry>
+                                                       <entry>total width</entry>
+                                               </row>
+                                               <row>
+                                                       <entry>0</entry>
+                                                       <entry>0</entry>
+                                                       <entry>1 .. 13</entry>
+                                                       <entry>1 .. 13</entry>
+                                                       <entry>1 .. 13</entry>
+                                                       <entry>13</entry>
+                                               </row>
+                                               <row>
+                                                       <entry>1</entry>
+                                                       <entry>0</entry>
+                                                       <entry>1</entry>
+                                                       <entry>1 .. 13</entry>
+                                                       <entry>1 .. 13</entry>
+                                                       <entry>13</entry>
+                                               </row>
+                                               <row>
+                                                       <entry>0</entry>
+                                                       <entry>1</entry>
+                                                       <entry>1</entry>
+                                                       <entry>0</entry>
+                                                       <entry>0</entry>
+                                                       <entry>1</entry>
+                                               </row>
+                                               <row>
+                                                       <entry>1</entry>
+                                                       <entry>1</entry>
+                                                       <entry>1</entry>
+                                                       <entry>2</entry>
+                                                       <entry>0</entry>
+                                                       <entry>13</entry>
+                                               </row>
+                                       </tbody>
+                               </tgroup>
+                       </informaltable>
+               </section>
+               <section id="DTV-ISDBT-LAYER-TIME-INTERLEAVING">
+                       <title><constant>DTV_ISDBT_LAYER*_TIME_INTERLEAVING</constant></title>
+                       <para>Possible values: 0, 1, 2, 3, -1 (AUTO)</para>
+                       <para>Note: The real inter-leaver depth-names depend on the mode (fft-size); the values
+                               here are referring to what can be found in the TMCC-structure -
+                               independent of the mode.</para>
+               </section>
+       </section>
+       <section id="DTV-API-VERSION">
+       <title><constant>DTV_API_VERSION</constant></title>
+       <para>Returns the major/minor version of the DVB API</para>
+       </section>
+       <section id="DTV-CODE-RATE-HP">
+       <title><constant>DTV_CODE_RATE_HP</constant></title>
+       <para>Used on terrestrial transmissions. The acceptable values are:
+       </para>
+       <programlisting>
+typedef enum fe_code_rate {
+       FEC_NONE = 0,
+       FEC_1_2,
+       FEC_2_3,
+       FEC_3_4,
+       FEC_4_5,
+       FEC_5_6,
+       FEC_6_7,
+       FEC_7_8,
+       FEC_8_9,
+       FEC_AUTO,
+       FEC_3_5,
+       FEC_9_10,
+} fe_code_rate_t;
+       </programlisting>
+       </section>
+       <section id="DTV-CODE-RATE-LP">
+       <title><constant>DTV_CODE_RATE_LP</constant></title>
+       <para>Used on terrestrial transmissions. The acceptable values are:
+       </para>
+       <programlisting>
+typedef enum fe_code_rate {
+       FEC_NONE = 0,
+       FEC_1_2,
+       FEC_2_3,
+       FEC_3_4,
+       FEC_4_5,
+       FEC_5_6,
+       FEC_6_7,
+       FEC_7_8,
+       FEC_8_9,
+       FEC_AUTO,
+       FEC_3_5,
+       FEC_9_10,
+} fe_code_rate_t;
+       </programlisting>
+       </section>
+       <section id="DTV-GUARD-INTERVAL">
+               <title><constant>DTV_GUARD_INTERVAL</constant></title>
+
+               <para>Possible values are:</para>
+<programlisting>
+typedef enum fe_guard_interval {
+       GUARD_INTERVAL_1_32,
+       GUARD_INTERVAL_1_16,
+       GUARD_INTERVAL_1_8,
+       GUARD_INTERVAL_1_4,
+       GUARD_INTERVAL_AUTO,
+       GUARD_INTERVAL_1_128,
+       GUARD_INTERVAL_19_128,
+       GUARD_INTERVAL_19_256,
+} fe_guard_interval_t;
+</programlisting>
+
+               <para>Notes:</para>
+               <para>1) If <constant>DTV_GUARD_INTERVAL</constant> is set the <constant>GUARD_INTERVAL_AUTO</constant> the hardware will
+                       try to find the correct guard interval (if capable) and will use TMCC to fill
+                       in the missing parameters.</para>
+               <para>2) Intervals 1/128, 19/128 and 19/256 are used only for DVB-T2 at present</para>
+       </section>
+       <section id="DTV-TRANSMISSION-MODE">
+               <title><constant>DTV_TRANSMISSION_MODE</constant></title>
+
+               <para>Specifies the number of carriers used by the standard</para>
+
+               <para>Possible values are:</para>
+<programlisting>
+typedef enum fe_transmit_mode {
+       TRANSMISSION_MODE_2K,
+       TRANSMISSION_MODE_8K,
+       TRANSMISSION_MODE_AUTO,
+       TRANSMISSION_MODE_4K,
+       TRANSMISSION_MODE_1K,
+       TRANSMISSION_MODE_16K,
+       TRANSMISSION_MODE_32K,
+} fe_transmit_mode_t;
+</programlisting>
+               <para>Notes:</para>
+               <para>1) ISDB-T supports three carrier/symbol-size: 8K, 4K, 2K. It is called
+                       'mode' in the standard: Mode 1 is 2K, mode 2 is 4K, mode 3 is 8K</para>
+
+               <para>2) If <constant>DTV_TRANSMISSION_MODE</constant> is set the <constant>TRANSMISSION_MODE_AUTO</constant> the
+                       hardware will try to find the correct FFT-size (if capable) and will
+                       use TMCC to fill in the missing parameters.</para>
+               <para>3) DVB-T specifies 2K and 8K as valid sizes.</para>
+               <para>4) DVB-T2 specifies 1K, 2K, 4K, 8K, 16K and 32K.</para>
+       </section>
+       <section id="DTV-HIERARCHY">
+       <title><constant>DTV_HIERARCHY</constant></title>
+       <para>Frontend hierarchy</para>
+       <programlisting>
+typedef enum fe_hierarchy {
+        HIERARCHY_NONE,
+        HIERARCHY_1,
+        HIERARCHY_2,
+        HIERARCHY_4,
+        HIERARCHY_AUTO
+ } fe_hierarchy_t;
+       </programlisting>
+       </section>
+       <section id="DTV-ISDBS-TS-ID">
+       <title><constant>DTV_ISDBS_TS_ID</constant></title>
+       <para>Currently unused.</para>
+       </section>
+       <section id="DTV-DVBT2-PLP-ID">
+               <title><constant>DTV_DVBT2_PLP_ID</constant></title>
+               <para>DVB-T2 supports Physical Layer Pipes (PLP) to allow transmission of
+                       many data types via a single multiplex. The API will soon support this
+                       at which point this section will be expanded.</para>
+       </section>
+</section>
+       <section id="frontend-property-terrestrial-systems">
+       <title>Properties used on terrestrial delivery systems</title>
+               <section id="dvbt-params">
+                       <title>DVB-T delivery system</title>
+                       <para>The following parameters are valid for DVB-T:</para>
+                       <itemizedlist mark='opencircle'>
+                               <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-BANDWIDTH-HZ"><constant>DTV_BANDWIDTH_HZ</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-CODE-RATE-HP"><constant>DTV_CODE_RATE_HP</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-CODE-RATE-LP"><constant>DTV_CODE_RATE_LP</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-GUARD-INTERVAL"><constant>DTV_GUARD_INTERVAL</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-TRANSMISSION-MODE"><constant>DTV_TRANSMISSION_MODE</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-HIERARCHY"><constant>DTV_HIERARCHY</constant></link></para></listitem>
+                       </itemizedlist>
+               </section>
+               <section id="dvbt2-params">
+                       <title>DVB-T2 delivery system</title>
+                       <para>DVB-T2 support is currently in the early stages
+                       of development, so expect that this section maygrow and become
+                       more detailed with time.</para>
+               <para>The following parameters are valid for DVB-T2:</para>
+               <itemizedlist mark='opencircle'>
+                       <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-BANDWIDTH-HZ"><constant>DTV_BANDWIDTH_HZ</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-CODE-RATE-HP"><constant>DTV_CODE_RATE_HP</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-CODE-RATE-LP"><constant>DTV_CODE_RATE_LP</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-GUARD-INTERVAL"><constant>DTV_GUARD_INTERVAL</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-TRANSMISSION-MODE"><constant>DTV_TRANSMISSION_MODE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-HIERARCHY"><constant>DTV_HIERARCHY</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-DVBT2-PLP-ID"><constant>DTV_DVBT2_PLP_ID</constant></link></para></listitem>
+               </itemizedlist>
+               </section>
+               <section id="isdbt">
+               <title>ISDB-T delivery system</title>
+               <para>This ISDB-T/ISDB-Tsb API extension should reflect all information
+                       needed to tune any ISDB-T/ISDB-Tsb hardware. Of course it is possible
+                       that some very sophisticated devices won't need certain parameters to
+                       tune.</para>
+               <para>The information given here should help application writers to know how
+                       to handle ISDB-T and ISDB-Tsb hardware using the Linux DVB-API.</para>
+               <para>The details given here about ISDB-T and ISDB-Tsb are just enough to
+                       basically show the dependencies between the needed parameter values,
+                       but surely some information is left out. For more detailed information
+                       see the following documents:</para>
+               <para>ARIB STD-B31 - "Transmission System for Digital Terrestrial
+                       Television Broadcasting" and</para>
+               <para>ARIB TR-B14 - "Operational Guidelines for Digital Terrestrial
+                       Television Broadcasting".</para>
+               <para>In order to understand the ISDB specific parameters,
+                       one has to have some knowledge the channel structure in
+                       ISDB-T and ISDB-Tsb. I.e. it has to be known to
+                       the reader that an ISDB-T channel consists of 13 segments,
+                       that it can have up to 3 layer sharing those segments,
+                       and things like that.</para>
+               <para>The following parameters are valid for ISDB-T:</para>
+               <itemizedlist mark='opencircle'>
+                       <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-BANDWIDTH-HZ"><constant>DTV_BANDWIDTH_HZ</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-CODE-RATE-HP"><constant>DTV_CODE_RATE_HP</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-CODE-RATE-LP"><constant>DTV_CODE_RATE_LP</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-GUARD-INTERVAL"><constant>DTV_GUARD_INTERVAL</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-TRANSMISSION-MODE"><constant>DTV_TRANSMISSION_MODE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-HIERARCHY"><constant>DTV_HIERARCHY</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-LAYER-ENABLED"><constant>DTV_ISDBT_LAYER_ENABLED</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-PARTIAL-RECEPTION"><constant>DTV_ISDBT_PARTIAL_RECEPTION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-SOUND-BROADCASTING"><constant>DTV_ISDBT_SOUND_BROADCASTING</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-SB-SUBCHANNEL-ID"><constant>DTV_ISDBT_SB_SUBCHANNEL_ID</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-SB-SEGMENT-IDX"><constant>DTV_ISDBT_SB_SEGMENT_IDX</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-SB-SEGMENT-COUNT"><constant>DTV_ISDBT_SB_SEGMENT_COUNT</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-LAYER-FEC"><constant>DTV_ISDBT_LAYERA_FEC</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-LAYER-MODULATION"><constant>DTV_ISDBT_LAYERA_MODULATION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-LAYER-SEGMENT-COUNT"><constant>DTV_ISDBT_LAYERA_SEGMENT_COUNT</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-LAYER-TIME-INTERLEAVING"><constant>DTV_ISDBT_LAYERA_TIME_INTERLEAVING</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-LAYER-FEC"><constant>DTV_ISDBT_LAYERB_FEC</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-LAYER-MODULATION"><constant>DTV_ISDBT_LAYERB_MODULATION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-LAYER-SEGMENT-COUNT"><constant>DTV_ISDBT_LAYERB_SEGMENT_COUNT</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-LAYER-TIME-INTERLEAVING"><constant>DTV_ISDBT_LAYERB_TIME_INTERLEAVING</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-LAYER-FEC"><constant>DTV_ISDBT_LAYERC_FEC</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-LAYER-MODULATION"><constant>DTV_ISDBT_LAYERC_MODULATION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-LAYER-SEGMENT-COUNT"><constant>DTV_ISDBT_LAYERC_SEGMENT_COUNT</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-LAYER-TIME-INTERLEAVING"><constant>DTV_ISDBT_LAYERC_TIME_INTERLEAVING</constant></link></para></listitem>
+               </itemizedlist>
+               </section>
+               <section id="atsc-params">
+                       <title>ATSC delivery system</title>
+                       <para>The following parameters are valid for ATSC:</para>
+                       <itemizedlist mark='opencircle'>
+                               <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-BANDWIDTH-HZ"><constant>DTV_BANDWIDTH_HZ</constant></link></para></listitem>
+                       </itemizedlist>
+               </section>
+       </section>
+       <section id="frontend-property-cable-systems">
+       <title>Properties used on cable delivery systems</title>
+       <section id="dvbc-params">
+               <title>DVB-C delivery system</title>
+               <para>The DVB-C Annex-A/C is the widely used cable standard. Transmission uses QAM modulation.</para>
+               <para>The following parameters are valid for DVB-C Annex A/C:</para>
+               <itemizedlist mark='opencircle'>
+                       <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-SYMBOL-RATE"><constant>DTV_SYMBOL_RATE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-INNER-FEC"><constant>DTV_INNER_FEC</constant></link></para></listitem>
+               </itemizedlist>
+       </section>
+       <section id="dvbc-annex-b-params">
+               <title>DVB-C Annex B delivery system</title>
+               <para>The DVB-C Annex-B is only used on a few Countries like the United States.</para>
+               <para>The following parameters are valid for DVB-C Annex B:</para>
+               <itemizedlist mark='opencircle'>
+                       <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
+               </itemizedlist>
+       </section>
+       </section>
+       <section id="frontend-property-satellital-systems">
+       <title>Properties used on satellital delivery systems</title>
+       <section id="dvbs-params">
+               <title>DVB-S delivery system</title>
+               <para>The following parameters are valid for DVB-S:</para>
+               <itemizedlist mark='opencircle'>
+                       <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-SYMBOL-RATE"><constant>DTV_SYMBOL_RATE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-INNER-FEC"><constant>DTV_INNER_FEC</constant></link></para></listitem>
+               </itemizedlist>
+               <para>Future implementations might add those two missing parameters:</para>
+               <itemizedlist mark='opencircle'>
+                       <listitem><para><link linkend="DTV-DISEQC-MASTER"><constant>DTV_DISEQC_MASTER</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-DISEQC-SLAVE-REPLY"><constant>DTV_DISEQC_SLAVE_REPLY</constant></link></para></listitem>
+               </itemizedlist>
+       </section>
+       <section id="dvbs2-params">
+               <title>DVB-S2 delivery system</title>
+               <para>The following parameters are valid for DVB-S2:</para>
+               <itemizedlist mark='opencircle'>
+                       <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-SYMBOL-RATE"><constant>DTV_SYMBOL_RATE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-INNER-FEC"><constant>DTV_INNER_FEC</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-VOLTAGE"><constant>DTV_VOLTAGE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-TONE"><constant>DTV_TONE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-PILOT"><constant>DTV_PILOT</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ROLLOFF"><constant>DTV_ROLLOFF</constant></link></para></listitem>
+               </itemizedlist>
+               <para>Future implementations might add those two missing parameters:</para>
+               <itemizedlist mark='opencircle'>
+                       <listitem><para><link linkend="DTV-DISEQC-MASTER"><constant>DTV_DISEQC_MASTER</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-DISEQC-SLAVE-REPLY"><constant>DTV_DISEQC_SLAVE_REPLY</constant></link></para></listitem>
+               </itemizedlist>
+       </section>
+       <section id="isdbs-params">
+               <title>ISDB-S delivery system</title>
+               <para>The following parameters are valid for ISDB-S:</para>
+               <itemizedlist mark='opencircle'>
+                       <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-SYMBOL-RATE"><constant>DTV_SYMBOL_RATE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-INNER-FEC"><constant>DTV_INNER_FEC</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-VOLTAGE"><constant>DTV_VOLTAGE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBS-TS-ID"><constant>DTV_ISDBS_TS_ID</constant></link></para></listitem>
+               </itemizedlist>
+       </section>
+       </section>
+</section>
similarity index 75%
rename from Documentation/DocBook/dvb/frontend.xml
rename to Documentation/DocBook/media/dvb/frontend.xml
index 60c6976..61407ea 100644 (file)
@@ -20,22 +20,52 @@ cards, in which case there exists no frontend device.</para>
 <section id="frontend_types">
 <title>Frontend Data Types</title>
 
-<section id="frontend_type">
-<title>frontend type</title>
-
-<para>For historical reasons frontend types are named after the type of modulation used in
-transmission.</para>
-<programlisting>
-       typedef enum fe_type {
-       FE_QPSK,   /&#x22C6; DVB-S &#x22C6;/
-       FE_QAM,    /&#x22C6; DVB-C &#x22C6;/
-       FE_OFDM    /&#x22C6; DVB-T &#x22C6;/
-       } fe_type_t;
-</programlisting>
-
+<section id="fe-type-t">
+<title>Frontend type</title>
+
+<para>For historical reasons, frontend types are named by the type of modulation used in
+transmission. The fontend types are given by fe_type_t type, defined as:</para>
+
+<table pgwide="1" frame="none" id="fe-type">
+<title>Frontend types</title>
+<tgroup cols="3">
+   &cs-def;
+   <thead>
+     <row>
+       <entry>fe_type</entry>
+       <entry>Description</entry>
+       <entry><link linkend="DTV-DELIVERY-SYSTEM">DTV_DELIVERY_SYSTEM</link> equivalent type</entry>
+     </row>
+  </thead>
+  <tbody valign="top">
+  <row>
+     <entry id="FE_QPSK"><constant>FE_QPSK</constant></entry>
+     <entry>For DVB-S standard</entry>
+     <entry><constant>SYS_DVBS</constant></entry>
+  </row>
+  <row>
+     <entry id="FE_QAM"><constant>FE_QAM</constant></entry>
+     <entry>For DVB-C annex A/C standard</entry>
+     <entry><constant>SYS_DVBC_ANNEX_AC</constant></entry>
+  </row>
+  <row>
+     <entry id="FE_OFDM"><constant>FE_OFDM</constant></entry>
+     <entry>For DVB-T standard</entry>
+     <entry><constant>SYS_DVBT</constant></entry>
+  </row>
+  <row>
+     <entry id="FE_ATSC"><constant>FE_ATSC</constant></entry>
+     <entry>For ATSC standard (terrestrial) or for DVB-C Annex B (cable) used in US.</entry>
+     <entry><constant>SYS_ATSC</constant> (terrestrial) or <constant>SYS_DVBC_ANNEX_B</constant> (cable)</entry>
+  </row>
+</tbody></tgroup></table>
+
+<para>Newer formats like DVB-S2, ISDB-T, ISDB-S and DVB-T2 are not described at the above, as they're
+supported via the new <link linkend="FE_GET_SET_PROPERTY">FE_GET_PROPERTY/FE_GET_SET_PROPERTY</link> ioctl's, using the <link linkend="DTV-DELIVERY-SYSTEM">DTV_DELIVERY_SYSTEM</link> parameter.
+</para>
 </section>
 
-<section id="frontend_caps">
+<section id="fe-caps-t">
 <title>frontend capabilities</title>
 
 <para>Capabilities describe what a frontend can do. Some capabilities can only be supported for
@@ -76,7 +106,7 @@ a specific frontend type.</para>
 </programlisting>
 </section>
 
-<section id="frontend_info">
+<section id="dvb-frontend-info">
 <title>frontend information</title>
 
 <para>Information about the frontend ca be queried with
@@ -99,7 +129,7 @@ a specific frontend type.</para>
 </programlisting>
 </section>
 
-<section id="frontend_diseqc">
+<section id="dvb-diseqc-master-cmd">
 <title>diseqc master command</title>
 
 <para>A message sent from the frontend to DiSEqC capable equipment.</para>
@@ -110,7 +140,7 @@ a specific frontend type.</para>
        };
 </programlisting>
 </section>
-<section role="subsection">
+<section role="subsection" id="dvb-diseqc-slave-reply">
 <title>diseqc slave reply</title>
 
 <para>A reply to the frontend from DiSEqC 2.0 capable equipment.</para>
@@ -123,7 +153,7 @@ a specific frontend type.</para>
 </programlisting>
 </section>
 
-<section id="frontend_diseqc_slave_reply">
+<section id="fe-sec-voltage-t">
 <title>diseqc slave reply</title>
 <para>The voltage is usually used with non-DiSEqC capable LNBs to switch the polarzation
 (horizontal/vertical). When using DiSEqC epuipment this voltage has to be switched
@@ -136,7 +166,7 @@ consistently to the DiSEqC commands as described in the DiSEqC spec.</para>
 </programlisting>
 </section>
 
-<section id="frontend_sec_tone">
+<section id="fe-sec-tone-mode-t">
 <title>SEC continuous tone</title>
 
 <para>The continuous 22KHz tone is usually used with non-DiSEqC capable LNBs to switch the
@@ -151,7 +181,7 @@ spec.</para>
 </programlisting>
 </section>
 
-<section id="frontend_sec_burst">
+<section id="fe-sec-mini-cmd-t">
 <title>SEC tone burst</title>
 
 <para>The 22KHz tone burst is usually used with non-DiSEqC capable switches to select
@@ -168,7 +198,7 @@ spec.</para>
 <para></para>
 </section>
 
-<section id="frontend_status">
+<section id="fe-status-t">
 <title>frontend status</title>
 <para>Several functions of the frontend device use the fe_status data type defined
 by</para>
@@ -188,31 +218,54 @@ by</para>
 
 </section>
 
-<section id="frontend_params">
+<section id="dvb-frontend-parameters">
 <title>frontend parameters</title>
 <para>The kind of parameters passed to the frontend device for tuning depend on
-the kind of hardware you are using. All kinds of parameters are combined as an
-union in the FrontendParameters structure:</para>
+the kind of hardware you are using.</para>
+<para>The struct <constant>dvb_frontend_parameters</constant> uses an
+union with specific per-system parameters. However, as newer delivery systems
+required more data, the structure size weren't enough to fit, and just
+extending its size would break the existing applications. So, those parameters
+were replaced by the usage of <link linkend="FE_GET_SET_PROPERTY">
+<constant>FE_GET_PROPERTY/FE_SET_PROPERTY</constant></link> ioctl's. The
+new API is flexible enough to add new parameters to existing delivery systems,
+and to add newer delivery systems.</para>
+<para>So, newer applications should use <link linkend="FE_GET_SET_PROPERTY">
+<constant>FE_GET_PROPERTY/FE_SET_PROPERTY</constant></link> instead, in
+order to be able to support the newer System Delivery like  DVB-S2, DVB-T2,
+DVB-C2, ISDB, etc.</para>
+<para>All kinds of parameters are combined as an union in the FrontendParameters structure:</para>
 <programlisting>
- struct dvb_frontend_parameters {
-        uint32_t frequency;       /&#x22C6; (absolute) frequency in Hz for QAM/OFDM &#x22C6;/
-                                  /&#x22C6; intermediate frequency in kHz for QPSK &#x22C6;/
-        fe_spectral_inversion_t inversion;
-        union {
-                struct dvb_qpsk_parameters qpsk;
-                struct dvb_qam_parameters  qam;
-                struct dvb_ofdm_parameters ofdm;
-        } u;
- };
+struct dvb_frontend_parameters {
+       uint32_t frequency;     /&#x22C6; (absolute) frequency in Hz for QAM/OFDM &#x22C6;/
+                               /&#x22C6; intermediate frequency in kHz for QPSK &#x22C6;/
+       fe_spectral_inversion_t inversion;
+       union {
+               struct dvb_qpsk_parameters qpsk;
+               struct dvb_qam_parameters  qam;
+               struct dvb_ofdm_parameters ofdm;
+               struct dvb_vsb_parameters  vsb;
+       } u;
+};
 </programlisting>
-<para>For satellite QPSK frontends you have to use the <constant>QPSKParameters</constant> member defined by</para>
+<para>In the case of QPSK frontends the <constant>frequency</constant> field specifies the intermediate
+frequency, i.e. the offset which is effectively added to the local oscillator frequency (LOF) of
+the LNB. The intermediate frequency has to be specified in units of kHz. For QAM and
+OFDM frontends the <constant>frequency</constant> specifies the absolute frequency and is given in Hz.
+</para>
+<section id="dvb-qpsk-parameters">
+<title>QPSK parameters</title>
+<para>For satellite QPSK frontends you have to use the <constant>dvb_qpsk_parameters</constant> structure:</para>
 <programlisting>
  struct dvb_qpsk_parameters {
         uint32_t        symbol_rate;  /&#x22C6; symbol rate in Symbols per second &#x22C6;/
         fe_code_rate_t  fec_inner;    /&#x22C6; forward error correction (see above) &#x22C6;/
  };
 </programlisting>
-<para>for cable QAM frontend you use the <constant>QAMParameters</constant> structure</para>
+</section>
+<section id="dvb-qam-parameters">
+<title>QAM parameters</title>
+<para>for cable QAM frontend you use the <constant>dvb_qam_parameters</constant> structure:</para>
 <programlisting>
  struct dvb_qam_parameters {
         uint32_t         symbol_rate; /&#x22C6; symbol rate in Symbols per second &#x22C6;/
@@ -220,8 +273,19 @@ union in the FrontendParameters structure:</para>
         fe_modulation_t  modulation;  /&#x22C6; modulation type (see above) &#x22C6;/
  };
 </programlisting>
-<para>DVB-T frontends are supported by the <constant>OFDMParamters</constant> structure
-</para>
+</section>
+<section id="dvb-vsb-parameters">
+<title>VSB parameters</title>
+<para>ATSC frontends are supported by the <constant>dvb_vsb_parameters</constant> structure:</para>
+<programlisting>
+struct dvb_vsb_parameters {
+       fe_modulation_t modulation;     /&#x22C6; modulation type (see above) &#x22C6;/
+};
+</programlisting>
+</section>
+<section id="dvb-ofdm-parameters">
+<title>OFDM parameters</title>
+<para>DVB-T frontends are supported by the <constant>dvb_ofdm_parameters</constant> structure:</para>
 <programlisting>
  struct dvb_ofdm_parameters {
         fe_bandwidth_t      bandwidth;
@@ -233,86 +297,124 @@ union in the FrontendParameters structure:</para>
         fe_hierarchy_t      hierarchy_information;
  };
 </programlisting>
-<para>In the case of QPSK frontends the <constant>Frequency</constant> field specifies the intermediate
-frequency, i.e. the offset which is effectively added to the local oscillator frequency (LOF) of
-the LNB. The intermediate frequency has to be specified in units of kHz. For QAM and
-OFDM frontends the Frequency specifies the absolute frequency and is given in
-Hz.
-</para>
+</section>
+<section id="fe-spectral-inversion-t">
+<title>frontend spectral inversion</title>
 <para>The Inversion field can take one of these values:
 </para>
 <programlisting>
- typedef enum fe_spectral_inversion {
-        INVERSION_OFF,
-        INVERSION_ON,
-        INVERSION_AUTO
- } fe_spectral_inversion_t;
+typedef enum fe_spectral_inversion {
+       INVERSION_OFF,
+       INVERSION_ON,
+       INVERSION_AUTO
+} fe_spectral_inversion_t;
 </programlisting>
 <para>It indicates if spectral inversion should be presumed or not. In the automatic setting
 (<constant>INVERSION_AUTO</constant>) the hardware will try to figure out the correct setting by
 itself.
 </para>
-<para>The possible values for the <constant>FEC_inner</constant> field are
+</section>
+<section id="fe-code-rate-t">
+<title>frontend code rate</title>
+<para>The possible values for the <constant>fec_inner</constant> field used on
+<link refend="dvb-qpsk-parameters"><constant>struct dvb_qpsk_parameters</constant></link> and
+<link refend="dvb-qam-parameters"><constant>struct dvb_qam_parameters</constant></link> are:
 </para>
 <programlisting>
- typedef enum fe_code_rate {
-        FEC_NONE = 0,
-        FEC_1_2,
-        FEC_2_3,
-        FEC_3_4,
-        FEC_4_5,
-        FEC_5_6,
-        FEC_6_7,
-        FEC_7_8,
-        FEC_8_9,
-        FEC_AUTO
- } fe_code_rate_t;
+typedef enum fe_code_rate {
+       FEC_NONE = 0,
+       FEC_1_2,
+       FEC_2_3,
+       FEC_3_4,
+       FEC_4_5,
+       FEC_5_6,
+       FEC_6_7,
+       FEC_7_8,
+       FEC_8_9,
+       FEC_AUTO,
+       FEC_3_5,
+       FEC_9_10,
+} fe_code_rate_t;
 </programlisting>
 <para>which correspond to error correction rates of 1/2, 2/3, etc., no error correction or auto
 detection.
 </para>
-<para>For cable and terrestrial frontends (QAM and OFDM) one also has to specify the quadrature
-modulation mode which can be one of the following:
+</section>
+<section id="fe-modulation-t">
+<title>frontend modulation type for QAM, OFDM and VSB</title>
+<para>For cable and terrestrial frontends, e. g. for
+<link refend="dvb-qam-parameters"><constant>struct dvb_qpsk_parameters</constant></link>,
+<link refend="dvb-ofdm-parameters"><constant>struct dvb_qam_parameters</constant></link> and
+<link refend="dvb-vsb-parameters"><constant>struct dvb_qam_parameters</constant></link>,
+it needs to specify the quadrature modulation mode which can be one of the following:
 </para>
 <programlisting>
  typedef enum fe_modulation {
- QPSK,
-        QAM_16,
-        QAM_32,
-        QAM_64,
-        QAM_128,
-        QAM_256,
-        QAM_AUTO
+       QPSK,
+       QAM_16,
+       QAM_32,
+       QAM_64,
+       QAM_128,
+       QAM_256,
+       QAM_AUTO,
+       VSB_8,
+       VSB_16,
+       PSK_8,
+       APSK_16,
+       APSK_32,
+       DQPSK,
  } fe_modulation_t;
 </programlisting>
+</section>
 <para>Finally, there are several more parameters for OFDM:
 </para>
+<section id="fe-transmit-mode-t">
+<title>Number of carriers per channel</title>
 <programlisting>
- typedef enum fe_transmit_mode {
-        TRANSMISSION_MODE_2K,
-        TRANSMISSION_MODE_8K,
-        TRANSMISSION_MODE_AUTO
+typedef enum fe_transmit_mode {
+       TRANSMISSION_MODE_2K,
+       TRANSMISSION_MODE_8K,
+       TRANSMISSION_MODE_AUTO,
+       TRANSMISSION_MODE_4K,
+       TRANSMISSION_MODE_1K,
+       TRANSMISSION_MODE_16K,
+       TRANSMISSION_MODE_32K,
  } fe_transmit_mode_t;
 </programlisting>
- <programlisting>
- typedef enum fe_bandwidth {
-        BANDWIDTH_8_MHZ,
-        BANDWIDTH_7_MHZ,
-        BANDWIDTH_6_MHZ,
-        BANDWIDTH_AUTO
- } fe_bandwidth_t;
+</section>
+<section id="fe-bandwidth-t">
+<title>frontend bandwidth</title>
+<programlisting>
+typedef enum fe_bandwidth {
+       BANDWIDTH_8_MHZ,
+       BANDWIDTH_7_MHZ,
+       BANDWIDTH_6_MHZ,
+       BANDWIDTH_AUTO,
+       BANDWIDTH_5_MHZ,
+       BANDWIDTH_10_MHZ,
+       BANDWIDTH_1_712_MHZ,
+} fe_bandwidth_t;
 </programlisting>
- <programlisting>
- typedef enum fe_guard_interval {
-        GUARD_INTERVAL_1_32,
-        GUARD_INTERVAL_1_16,
-        GUARD_INTERVAL_1_8,
-        GUARD_INTERVAL_1_4,
-        GUARD_INTERVAL_AUTO
- } fe_guard_interval_t;
+</section>
+<section id="fe-guard-interval-t">
+<title>frontend guard inverval</title>
+<programlisting>
+typedef enum fe_guard_interval {
+       GUARD_INTERVAL_1_32,
+       GUARD_INTERVAL_1_16,
+       GUARD_INTERVAL_1_8,
+       GUARD_INTERVAL_1_4,
+       GUARD_INTERVAL_AUTO,
+       GUARD_INTERVAL_1_128,
+       GUARD_INTERVAL_19_128,
+       GUARD_INTERVAL_19_256,
+} fe_guard_interval_t;
 </programlisting>
- <programlisting>
- typedef enum fe_hierarchy {
+</section>
+<section id="fe-hierarchy-t">
+<title>frontend hierarchy</title>
+<programlisting>
+typedef enum fe_hierarchy {
         HIERARCHY_NONE,
         HIERARCHY_1,
         HIERARCHY_2,
@@ -320,10 +422,11 @@ modulation mode which can be one of the following:
         HIERARCHY_AUTO
  } fe_hierarchy_t;
 </programlisting>
+</section>
 
 </section>
 
-<section id="frontend_events">
+<section id="dvb-frontend-event">
 <title>frontend events</title>
  <programlisting>
  struct dvb_frontend_event {
@@ -412,8 +515,7 @@ modulation mode which can be one of the following:
 <para>(blocking mode is the default)</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+<para>RETURN VALUE</para>
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
 <para>ENODEV</para>
@@ -473,8 +575,7 @@ modulation mode which can be one of the following:
 <para>File descriptor returned by a previous call to open().</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+<para>RETURN VALUE</para>
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
 <para>EBADF</para>
@@ -530,8 +631,7 @@ modulation mode which can be one of the following:
  to be stored.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+<para>RETURN VALUE</para>
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
 <para>EBADF</para>
@@ -592,38 +692,8 @@ modulation mode which can be one of the following:
 <para>The bit error rate is stored into *ber.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>ber points to invalid address.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ENOSIGNAL</para>
-</entry><entry
- align="char">
-<para>There is no signal, thus no meaningful bit error rate. Also
- returned if the front-end is not turned on.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ENOSYS</para>
-</entry><entry
- align="char">
-<para>Function not available for this device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+
+&return-value-dvb;
 </section>
 
 <section id="FE_READ_SNR">
@@ -670,38 +740,7 @@ modulation mode which can be one of the following:
 </entry>
  </row></tbody></tgroup></informaltable>
 
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>snr points to invalid address.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ENOSIGNAL</para>
-</entry><entry
- align="char">
-<para>There is no signal, thus no meaningful signal strength
- value. Also returned if front-end is not turned on.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ENOSYS</para>
-</entry><entry
- align="char">
-<para>Function not available for this device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 </section>
 
 <section id="FE_READ_SIGNAL_STRENGTH">
@@ -748,38 +787,8 @@ modulation mode which can be one of the following:
 <para>The signal strength value is stored into *strength.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>status points to invalid address.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ENOSIGNAL</para>
-</entry><entry
- align="char">
-<para>There is no signal, thus no meaningful signal strength
- value. Also returned if front-end is not turned on.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ENOSYS</para>
-</entry><entry
- align="char">
-<para>Function not available for this device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+
+&return-value-dvb;
 </section>
 
 <section id="FE_READ_UNCORRECTED_BLOCKS">
@@ -833,30 +842,8 @@ modulation mode which can be one of the following:
  so far.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>ublocks points to invalid address.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ENOSYS</para>
-</entry><entry
- align="char">
-<para>Function not available for this device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+
+&return-value-dvb;
 </section>
 
 <section id="FE_SET_FRONTEND">
@@ -909,24 +896,10 @@ modulation mode which can be one of the following:
 <para>Points to parameters for tuning operation.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+
+&return-value-dvb;
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>p points to invalid address.</para>
-</entry>
- </row><row><entry
- align="char">
 <para>EINVAL</para>
 </entry><entry
  align="char">
@@ -982,25 +955,9 @@ modulation mode which can be one of the following:
 </entry>
  </row></tbody></tgroup></informaltable>
 
-<para>ERRORS
-</para>
-
+&return-value-dvb;
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>p points to invalid address.</para>
-</entry>
- </row><row><entry
- align="char">
 <para>EINVAL</para>
 </entry><entry
  align="char">
@@ -1084,24 +1041,9 @@ modulation mode which can be one of the following:
 </entry>
  </row></tbody></tgroup></informaltable>
 
-<para>ERRORS
-</para>
+&return-value-dvb;
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>ev points to invalid address.</para>
-</entry>
- </row><row><entry
- align="char">
 <para>EWOULDBLOCK</para>
 </entry><entry
  align="char">
@@ -1111,11 +1053,6 @@ modulation mode which can be one of the following:
  </row><row><entry
  align="char">
 <para>EOVERFLOW</para>
-</entry><entry
- align="char">
-</entry>
- </row><row><entry
- align="char">
 </entry><entry
  align="char">
 <para>Overflow in event queue - one or more events were lost.</para>
@@ -1170,23 +1107,7 @@ modulation mode which can be one of the following:
  to be stored.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>info points to invalid address.</para>
-</entry>
-</row></tbody></tgroup></informaltable>
+&return-value-dvb;
 </section>
 
 <section id="FE_DISEQC_RESET_OVERLOAD">
@@ -1229,30 +1150,7 @@ modulation mode which can be one of the following:
 </entry>
  </row></tbody></tgroup></informaltable>
 
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EPERM</para>
-</entry><entry
- align="char">
-<para>Permission denied (needs read/write access).</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error in the device driver.</para>
-</entry>
-</row></tbody></tgroup></informaltable>
+&return-value-dvb;
 </section>
 
 <section id="FE_DISEQC_SEND_MASTER_CMD">
@@ -1302,45 +1200,7 @@ modulation mode which can be one of the following:
 </entry>
  </row></tbody></tgroup></informaltable>
 
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>Seq points to an invalid address.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>The data structure referred to by seq is invalid in some
- way.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EPERM</para>
-</entry><entry
- align="char">
-<para>Permission denied (needs read/write access).</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error in the device driver.</para>
-</entry>
-</row></tbody></tgroup></informaltable>
+&return-value-dvb;
 </section>
 
 <section id="FE_DISEQC_RECV_SLAVE_REPLY">
@@ -1390,45 +1250,7 @@ modulation mode which can be one of the following:
 <para>Pointer to the command to be received.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>Seq points to an invalid address.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>The data structure referred to by seq is invalid in some
- way.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EPERM</para>
-</entry><entry
- align="char">
-<para>Permission denied (needs read/write access).</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error in the device driver.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 </section>
 
 <section id="FE_DISEQC_SEND_BURST">
@@ -1476,45 +1298,7 @@ modulation mode which can be one of the following:
 </entry>
  </row></tbody></tgroup></informaltable>
 
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>Seq points to an invalid address.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>The data structure referred to by seq is invalid in some
- way.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EPERM</para>
-</entry><entry
- align="char">
-<para>Permission denied (needs read/write access).</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error in the device driver.</para>
-</entry>
-</row></tbody></tgroup></informaltable>
+&return-value-dvb;
 </section>
 
 <section id="FE_SET_TONE">
@@ -1560,44 +1344,7 @@ modulation mode which can be one of the following:
 <para>The requested tone generation mode (on/off).</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>ENODEV</para>
-</entry><entry
- align="char">
-<para>Device driver not loaded/available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBUSY</para>
-</entry><entry
- align="char">
-<para>Device or resource busy.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid argument.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EPERM</para>
-</entry><entry
- align="char">
-<para>File not opened with read permissions.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error in the device driver.</para>
-</entry>
-</row></tbody></tgroup></informaltable>
+&return-value-dvb;
 </section>
 
 <section id="FE_SET_VOLTAGE">
@@ -1645,44 +1392,7 @@ modulation mode which can be one of the following:
 </entry>
  </row></tbody></tgroup></informaltable>
 
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>ENODEV</para>
-</entry><entry
- align="char">
-<para>Device driver not loaded/available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBUSY</para>
-</entry><entry
- align="char">
-<para>Device or resource busy.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid argument.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EPERM</para>
-</entry><entry
- align="char">
-<para>File not opened with read permissions.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error in the device driver.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 </section>
 
 <section id="FE_ENABLE_HIGH_LNB_VOLTAGE">
@@ -1731,44 +1441,7 @@ modulation mode which can be one of the following:
 </entry>
  </row></tbody></tgroup></informaltable>
 
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>ENODEV</para>
-</entry><entry
- align="char">
-<para>Device driver not loaded/available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBUSY</para>
-</entry><entry
- align="char">
-<para>Device or resource busy.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid argument.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EPERM</para>
-</entry><entry
- align="char">
-<para>File not opened with read permissions.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error in the device driver.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 </section>
 
 <section id="FE_SET_FRONTEND_TUNE_MODE">
@@ -1800,11 +1473,7 @@ FE_TUNE_MODE_ONESHOT When set, this flag will disable any zigzagging or other "n
 </entry>
  </row></tbody></tgroup></informaltable>
 
-<para>ERRORS</para>
-<informaltable><tgroup cols="2"><tbody><row>
-<entry align="char"><para>EINVAL</para></entry>
-<entry align="char"><para>Invalid argument.</para></entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 </section>
 
 <section id="FE_DISHNETWORK_SEND_LEGACY_CMD">
@@ -1838,12 +1507,7 @@ sends the specified raw cmd to the dish via DISEqC.
 </entry>
  </row></tbody></tgroup></informaltable>
 
-<para>ERRORS</para>
-<informaltable><tgroup cols="1"><tbody><row>
-<entry align="char">
-       <para>There are no errors in use for this call</para>
-</entry>
-</row></tbody></tgroup></informaltable>
+&return-value-dvb;
 </section>
 
 </section>
similarity index 92%
rename from Documentation/DocBook/dvb/intro.xml
rename to Documentation/DocBook/media/dvb/intro.xml
index 0dc83f6..c75dc7c 100644 (file)
@@ -154,6 +154,10 @@ are called:</para>
 </listitem>
  <listitem>
 
+<para><emphasis role="tt">/dev/dvb/adapterN/dvrM</emphasis>,</para>
+</listitem>
+ <listitem>
+
 <para><emphasis role="tt">/dev/dvb/adapterN/caM</emphasis>,</para></listitem></itemizedlist>
 
 <para>where N enumerates the DVB PCI cards in a system starting
@@ -175,10 +179,27 @@ the devices are described in the following chapters.</para>
 The DVB API include files should be included in application sources with
 a partial path like:</para>
 
-
+<programlisting>
+       #include &#x003C;linux/dvb/audio.h&#x003E;
+</programlisting>
+<programlisting>
+       #include &#x003C;linux/dvb/ca.h&#x003E;
+</programlisting>
+<programlisting>
+       #include &#x003C;linux/dvb/dmx.h&#x003E;
+</programlisting>
 <programlisting>
        #include &#x003C;linux/dvb/frontend.h&#x003E;
 </programlisting>
+<programlisting>
+       #include &#x003C;linux/dvb/net.h&#x003E;
+</programlisting>
+<programlisting>
+       #include &#x003C;linux/dvb/osd.h&#x003E;
+</programlisting>
+<programlisting>
+       #include &#x003C;linux/dvb/video.h&#x003E;
+</programlisting>
 
 <para>To enable applications to support different API version, an
 additional include file <emphasis
similarity index 57%
rename from Documentation/DocBook/dvb/net.xml
rename to Documentation/DocBook/media/dvb/net.xml
index 94e388d..67d37e5 100644 (file)
@@ -7,6 +7,23 @@ application.
 </para>
 <section id="dvb_net_types">
 <title>DVB Net Data Types</title>
+
+<section id="dvb-net-if">
+<title>struct dvb_net_if</title>
+<programlisting>
+struct dvb_net_if {
+       __u16 pid;
+       __u16 if_num;
+       __u8  feedtype;
+#define DVB_NET_FEEDTYPE_MPE 0 /&#x22C6; multi protocol encapsulation &#x22C6;/
+#define DVB_NET_FEEDTYPE_ULE 1 /&#x22C6; ultra lightweight encapsulation &#x22C6;/
+};
+</programlisting>
+</section>
+
+</section>
+<section id="net_fcalls">
+<title>DVB net Function Calls</title>
 <para>To be written&#x2026;
 </para>
 </section>
similarity index 81%
rename from Documentation/DocBook/dvb/video.xml
rename to Documentation/DocBook/media/dvb/video.xml
index 7bb287e..25fb823 100644 (file)
@@ -18,15 +18,16 @@ supported on some MPEG decoders made for DVD playback.
 <section id="video_types">
 <title>Video Data Types</title>
 
-<section id="video_format_t">
+<section id="video-format-t">
 <title>video_format_t</title>
 <para>The <emphasis role="tt">video_format_t</emphasis> data type defined by
 </para>
 <programlisting>
- typedef enum {
-        VIDEO_FORMAT_4_3,
-        VIDEO_FORMAT_16_9
- } video_format_t;
+typedef enum {
+       VIDEO_FORMAT_4_3,     /&#x22C6; Select 4:3 format &#x22C6;/
+       VIDEO_FORMAT_16_9,    /&#x22C6; Select 16:9 format. &#x22C6;/
+       VIDEO_FORMAT_221_1    /&#x22C6; 2.21:1 &#x22C6;/
+} video_format_t;
 </programlisting>
 <para>is used in the VIDEO_SET_FORMAT function (??) to tell the driver which aspect ratio
 the output hardware (e.g. TV) has. It is also used in the data structures video_status
@@ -36,34 +37,36 @@ stream.
 </para>
 </section>
 
-<section id="video_display_format_t">
-<title>video_display_format_t</title>
+<section id="video-displayformat-t">
+<title>video_displayformat_t</title>
 <para>In case the display format of the video stream and of the display hardware differ the
 application has to specify how to handle the cropping of the picture. This can be done using
 the VIDEO_SET_DISPLAY_FORMAT call (??) which accepts
 </para>
 <programlisting>
- typedef enum {
-        VIDEO_PAN_SCAN,
-        VIDEO_LETTER_BOX,
-        VIDEO_CENTER_CUT_OUT
- } video_display_format_t;
+typedef enum {
+       VIDEO_PAN_SCAN,       /&#x22C6; use pan and scan format &#x22C6;/
+       VIDEO_LETTER_BOX,     /&#x22C6; use letterbox format &#x22C6;/
+       VIDEO_CENTER_CUT_OUT  /&#x22C6; use center cut out format &#x22C6;/
+} video_displayformat_t;
 </programlisting>
 <para>as argument.
 </para>
 </section>
 
-<section id="video_stream_source">
+<section id="video-stream-source-t">
 <title>video stream source</title>
 <para>The video stream source is set through the VIDEO_SELECT_SOURCE call and can take
 the following values, depending on whether we are replaying from an internal (demuxer) or
 external (user write) source.
 </para>
 <programlisting>
- typedef enum {
-        VIDEO_SOURCE_DEMUX,
-        VIDEO_SOURCE_MEMORY
- } video_stream_source_t;
+typedef enum {
+       VIDEO_SOURCE_DEMUX, /&#x22C6; Select the demux as the main source &#x22C6;/
+       VIDEO_SOURCE_MEMORY /&#x22C6; If this source is selected, the stream
+                              comes from the user through the write
+                              system call &#x22C6;/
+} video_stream_source_t;
 </programlisting>
 <para>VIDEO_SOURCE_DEMUX selects the demultiplexer (fed either by the frontend or the
 DVR device) as the source of the video stream. If VIDEO_SOURCE_MEMORY
@@ -72,49 +75,98 @@ call.
 </para>
 </section>
 
-<section id="video_play_state">
+<section id="video-play-state-t">
 <title>video play state</title>
 <para>The following values can be returned by the VIDEO_GET_STATUS call representing the
 state of video playback.
 </para>
 <programlisting>
- typedef enum {
-        VIDEO_STOPPED,
-        VIDEO_PLAYING,
-        VIDEO_FREEZED
- } video_play_state_t;
+typedef enum {
+       VIDEO_STOPPED, /&#x22C6; Video is stopped &#x22C6;/
+       VIDEO_PLAYING, /&#x22C6; Video is currently playing &#x22C6;/
+       VIDEO_FREEZED  /&#x22C6; Video is freezed &#x22C6;/
+} video_play_state_t;
 </programlisting>
 </section>
 
-<section id="video_event">
+<section id="video-command">
+<para>The structure must be zeroed before use by the application
+This ensures it can be extended safely in the future.</para>
+<title>struct video-command</title>
+<programlisting>
+struct video_command {
+       __u32 cmd;
+       __u32 flags;
+       union {
+               struct {
+                       __u64 pts;
+               } stop;
+
+               struct {
+                       /&#x22C6; 0 or 1000 specifies normal speed,
+                          1 specifies forward single stepping,
+                          -1 specifies backward single stepping,
+                          &gt;>1: playback at speed/1000 of the normal speed,
+                          &lt;-1: reverse playback at (-speed/1000) of the normal speed. &#x22C6;/
+                       __s32 speed;
+                       __u32 format;
+               } play;
+
+               struct {
+                       __u32 data[16];
+               } raw;
+       };
+};
+</programlisting>
+</section>
+
+<section id="video-size-t">
+<title>struct video_size-t</title>
+<programlisting>
+typedef struct {
+       int w;
+       int h;
+       video_format_t aspect_ratio;
+} video_size_t;
+</programlisting>
+</section>
+
+
+<section id="video-event">
 <title>struct video_event</title>
 <para>The following is the structure of a video event as it is returned by the VIDEO_GET_EVENT
 call.
 </para>
 <programlisting>
- struct video_event {
-        int32_t type;
-        time_t timestamp;
-        union {
-                video_format_t video_format;
-        } u;
- };
+struct video_event {
+       __s32 type;
+#define VIDEO_EVENT_SIZE_CHANGED       1
+#define VIDEO_EVENT_FRAME_RATE_CHANGED 2
+#define VIDEO_EVENT_DECODER_STOPPED    3
+#define VIDEO_EVENT_VSYNC              4
+       __kernel_time_t timestamp;
+       union {
+               video_size_t size;
+               unsigned int frame_rate;        /&#x22C6; in frames per 1000sec &#x22C6;/
+               unsigned char vsync_field;      /&#x22C6; unknown/odd/even/progressive &#x22C6;/
+       } u;
+};
 </programlisting>
 </section>
 
-<section id="video_status">
+<section id="video-status">
 <title>struct video_status</title>
 <para>The VIDEO_GET_STATUS call returns the following structure informing about various
 states of the playback operation.
 </para>
 <programlisting>
- struct video_status {
-        boolean video_blank;
-        video_play_state_t play_state;
-        video_stream_source_t stream_source;
-        video_format_t video_format;
-        video_displayformat_t display_format;
- };
+struct video_status {
+       int                   video_blank;   /&#x22C6; blank video on freeze? &#x22C6;/
+       video_play_state_t    play_state;    /&#x22C6; current state of playback &#x22C6;/
+       video_stream_source_t stream_source; /&#x22C6; current source (demux/memory) &#x22C6;/
+       video_format_t        video_format;  /&#x22C6; current aspect ratio of stream &#x22C6;/
+       video_displayformat_t display_format;/&#x22C6; selected cropping mode &#x22C6;/
+};
 </programlisting>
 <para>If video_blank is set video will be blanked out if the channel is changed or if playback is
 stopped. Otherwise, the last picture will be displayed. play_state indicates if the video is
@@ -127,17 +179,17 @@ device.
 </para>
 </section>
 
-<section id="video_still_picture">
+<section id="video-still-picture">
 <title>struct video_still_picture</title>
 <para>An I-frame displayed via the VIDEO_STILLPICTURE call is passed on within the
 following structure.
 </para>
 <programlisting>
- /&#x22C6; pointer to and size of a single iframe in memory &#x22C6;/
- struct video_still_picture {
-        char &#x22C6;iFrame;
-        int32_t size;
- };
+/&#x22C6; pointer to and size of a single iframe in memory &#x22C6;/
+struct video_still_picture {
+       char &#x22C6;iFrame;        /&#x22C6; pointer to a single iframe in memory &#x22C6;/
+       int32_t size;
+};
 </programlisting>
 </section>
 
@@ -164,26 +216,26 @@ bits set according to the hardwares capabilities.
 </programlisting>
 </section>
 
-<section id="video_system">
+<section id="video-system">
 <title>video system</title>
 <para>A call to VIDEO_SET_SYSTEM sets the desired video system for TV output. The
 following system types can be set:
 </para>
 <programlisting>
- typedef enum {
-         VIDEO_SYSTEM_PAL,
-         VIDEO_SYSTEM_NTSC,
-         VIDEO_SYSTEM_PALN,
-         VIDEO_SYSTEM_PALNc,
-         VIDEO_SYSTEM_PALM,
-         VIDEO_SYSTEM_NTSC60,
-         VIDEO_SYSTEM_PAL60,
-         VIDEO_SYSTEM_PALM60
- } video_system_t;
+typedef enum {
+        VIDEO_SYSTEM_PAL,
+        VIDEO_SYSTEM_NTSC,
+        VIDEO_SYSTEM_PALN,
+        VIDEO_SYSTEM_PALNc,
+        VIDEO_SYSTEM_PALM,
+        VIDEO_SYSTEM_NTSC60,
+        VIDEO_SYSTEM_PAL60,
+        VIDEO_SYSTEM_PALM60
+} video_system_t;
 </programlisting>
 </section>
 
-<section id="video_highlight">
+<section id="video-highlight">
 <title>struct video_highlight</title>
 <para>Calling the ioctl VIDEO_SET_HIGHLIGHTS posts the SPU highlight information. The
 call expects the following format for that information:
@@ -210,7 +262,7 @@ call expects the following format for that information:
 </programlisting>
 
 </section>
-<section id="video_spu">
+<section id="video-spu">
 <title>video SPU</title>
 <para>Calling VIDEO_SET_SPU deactivates or activates SPU decoding, according to the
 following format:
@@ -224,7 +276,7 @@ following format:
 </programlisting>
 
 </section>
-<section id="video_spu_palette">
+<section id="video-spu-palette">
 <title>video SPU palette</title>
 <para>The following structure is used to set the SPU palette by calling VIDEO_SPU_PALETTE:
 </para>
@@ -237,7 +289,7 @@ following format:
 </programlisting>
 
 </section>
-<section id="video_navi_pack">
+<section id="video-navi-pack">
 <title>video NAVI pack</title>
 <para>In order to get the navigational data the following structure has to be passed to the ioctl
 VIDEO_GET_NAVI:
@@ -252,7 +304,7 @@ VIDEO_GET_NAVI:
 </section>
 
 
-<section id="video_attributes">
+<section id="video-attributes-t">
 <title>video attributes</title>
 <para>The following attributes can be set by a call to VIDEO_SET_ATTRIBUTES:
 </para>
@@ -347,8 +399,7 @@ VIDEO_GET_NAVI:
 <para>(blocking mode is the default)</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+<para>RETURN VALUE</para>
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
 <para>ENODEV</para>
@@ -406,8 +457,7 @@ VIDEO_GET_NAVI:
 <para>File descriptor returned by a previous call to open().</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+<para>RETURN VALUE</para>
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
 <para>EBADF</para>
@@ -462,8 +512,7 @@ VIDEO_GET_NAVI:
 <para>Size of buf.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+<para>RETURN VALUE</para>
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
 <para>EPERM</para>
@@ -488,7 +537,7 @@ VIDEO_GET_NAVI:
 </entry>
  </row></tbody></tgroup></informaltable>
 
-</section><section
+</section><section id="VIDEO_STOP"
 role="subsection"><title>VIDEO_STOP</title>
 <para>DESCRIPTION
 </para>
@@ -543,26 +592,9 @@ role="subsection"><title>VIDEO_STOP</title>
 <para>FALSE: Show last decoded frame.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error, possibly in the communication with the
- DVB subsystem.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 
-</section><section
+</section><section id="VIDEO_PLAY"
 role="subsection"><title>VIDEO_PLAY</title>
 <para>DESCRIPTION
 </para>
@@ -596,26 +628,9 @@ role="subsection"><title>VIDEO_PLAY</title>
 <para>Equals VIDEO_PLAY for this command.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error, possibly in the communication with the
- DVB subsystem.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 
-</section><section
+</section><section id="VIDEO_FREEZE"
 role="subsection"><title>VIDEO_FREEZE</title>
 <para>DESCRIPTION
 </para>
@@ -653,26 +668,9 @@ role="subsection"><title>VIDEO_FREEZE</title>
 <para>Equals VIDEO_FREEZE for this command.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error, possibly in the communication with the
- DVB subsystem.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 
-</section><section
+</section><section id="VIDEO_CONTINUE"
 role="subsection"><title>VIDEO_CONTINUE</title>
 <para>DESCRIPTION
 </para>
@@ -706,26 +704,9 @@ role="subsection"><title>VIDEO_CONTINUE</title>
 <para>Equals VIDEO_CONTINUE for this command.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error, possibly in the communication with the
- DVB subsystem.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 
-</section><section
+</section><section id="VIDEO_SELECT_SOURCE"
 role="subsection"><title>VIDEO_SELECT_SOURCE</title>
 <para>DESCRIPTION
 </para>
@@ -769,26 +750,9 @@ role="subsection"><title>VIDEO_SELECT_SOURCE</title>
 <para>Indicates which source shall be used for the Video stream.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error, possibly in the communication with the
- DVB subsystem.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 
-</section><section
+</section><section id="VIDEO_SET_BLANK"
 role="subsection"><title>VIDEO_SET_BLANK</title>
 <para>DESCRIPTION
 </para>
@@ -835,33 +799,9 @@ role="subsection"><title>VIDEO_SET_BLANK</title>
 <para>FALSE: Show last decoded frame.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error, possibly in the communication with the
- DVB subsystem.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Illegal input parameter</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 
-</section><section
+</section><section id="VIDEO_GET_STATUS"
 role="subsection"><title>VIDEO_GET_STATUS</title>
 <para>DESCRIPTION
 </para>
@@ -903,33 +843,9 @@ role="subsection"><title>VIDEO_GET_STATUS</title>
 <para>Returns the current status of the Video Device.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error, possibly in the communication with the
- DVB subsystem.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>status points to invalid address</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 
-</section><section
+</section><section id="VIDEO_GET_EVENT"
 role="subsection"><title>VIDEO_GET_EVENT</title>
 <para>DESCRIPTION
 </para>
@@ -980,24 +896,9 @@ role="subsection"><title>VIDEO_GET_EVENT</title>
  stored.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+&return-value-dvb;
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>ev points to invalid address</para>
-</entry>
- </row><row><entry
- align="char">
 <para>EWOULDBLOCK</para>
 </entry><entry
  align="char">
@@ -1007,18 +908,13 @@ role="subsection"><title>VIDEO_GET_EVENT</title>
  </row><row><entry
  align="char">
 <para>EOVERFLOW</para>
-</entry><entry
- align="char">
-</entry>
- </row><row><entry
- align="char">
 </entry><entry
  align="char">
 <para>Overflow in event queue - one or more events were lost.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
 
-</section><section
+</section><section id="VIDEO_SET_DISPLAY_FORMAT"
 role="subsection"><title>VIDEO_SET_DISPLAY_FORMAT</title>
 <para>DESCRIPTION
 </para>
@@ -1063,32 +959,9 @@ role="subsection"><title>VIDEO_SET_DISPLAY_FORMAT</title>
 <para>Selects the video format to be used.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Illegal parameter format.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 
-</section><section
+</section><section id="VIDEO_STILLPICTURE"
 role="subsection"><title>VIDEO_STILLPICTURE</title>
 <para>DESCRIPTION
 </para>
@@ -1133,32 +1006,9 @@ role="subsection"><title>VIDEO_STILLPICTURE</title>
 <para>Pointer to a location where an I-frame and size is stored.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>sp points to an invalid iframe.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 
-</section><section
+</section><section id="VIDEO_FAST_FORWARD"
 role="subsection"><title>VIDEO_FAST_FORWARD</title>
 <para>DESCRIPTION
 </para>
@@ -1200,39 +1050,17 @@ role="subsection"><title>VIDEO_FAST_FORWARD</title>
 <para>The number of frames to skip.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+&return-value-dvb;
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
 <para>EPERM</para>
 </entry><entry
  align="char">
 <para>Mode VIDEO_SOURCE_MEMORY not selected.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Illegal parameter format.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
 
-</section><section
+</section><section id="VIDEO_SLOWMOTION"
 role="subsection"><title>VIDEO_SLOWMOTION</title>
 <para>DESCRIPTION
 </para>
@@ -1274,39 +1102,17 @@ role="subsection"><title>VIDEO_SLOWMOTION</title>
 <para>The number of times to repeat each frame.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+&return-value-dvb;
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
 <para>EPERM</para>
 </entry><entry
  align="char">
 <para>Mode VIDEO_SOURCE_MEMORY not selected.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Illegal parameter format.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
 
-</section><section
+</section><section id="VIDEO_GET_CAPABILITIES"
 role="subsection"><title>VIDEO_GET_CAPABILITIES</title>
 <para>DESCRIPTION
 </para>
@@ -1350,25 +1156,9 @@ role="subsection"><title>VIDEO_GET_CAPABILITIES</title>
  information.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>cap points to an invalid iframe.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 
-</section><section
+</section><section id="VIDEO_SET_ID"
 role="subsection"><title>VIDEO_SET_ID</title>
 <para>DESCRIPTION
 </para>
@@ -1410,24 +1200,9 @@ role="subsection"><title>VIDEO_SET_ID</title>
 <para>video sub-stream id</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+&return-value-dvb;
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
 <para>EINVAL</para>
 </entry><entry
  align="char">
@@ -1435,7 +1210,7 @@ role="subsection"><title>VIDEO_SET_ID</title>
 </entry>
  </row></tbody></tgroup></informaltable>
 
-</section><section
+</section><section id="VIDEO_CLEAR_BUFFER"
 role="subsection"><title>VIDEO_CLEAR_BUFFER</title>
 <para>DESCRIPTION
 </para>
@@ -1468,18 +1243,9 @@ role="subsection"><title>VIDEO_CLEAR_BUFFER</title>
 <para>Equals VIDEO_CLEAR_BUFFER for this command.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 
-</section><section
+</section><section id="VIDEO_SET_STREAMTYPE"
 role="subsection"><title>VIDEO_SET_STREAMTYPE</title>
 <para>DESCRIPTION
 </para>
@@ -1522,25 +1288,9 @@ role="subsection"><title>VIDEO_SET_STREAMTYPE</title>
 <para>stream type</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>type is not a valid or supported stream type.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 
-</section><section
+</section><section id="VIDEO_SET_FORMAT"
 role="subsection"><title>VIDEO_SET_FORMAT</title>
 <para>DESCRIPTION
 </para>
@@ -1583,17 +1333,9 @@ role="subsection"><title>VIDEO_SET_FORMAT</title>
 <para>video format of TV as defined in section ??.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+&return-value-dvb;
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
 <para>EINVAL</para>
 </entry><entry
  align="char">
@@ -1601,7 +1343,7 @@ role="subsection"><title>VIDEO_SET_FORMAT</title>
 </entry>
  </row></tbody></tgroup></informaltable>
 
-</section><section
+</section><section id="VIDEO_SET_SYSTEM"
 role="subsection"><title>VIDEO_SET_SYSTEM</title>
 <para>DESCRIPTION
 </para>
@@ -1645,17 +1387,9 @@ role="subsection"><title>VIDEO_SET_SYSTEM</title>
 <para>video system of TV output.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+&return-value-dvb;
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
 <para>EINVAL</para>
 </entry><entry
  align="char">
@@ -1663,7 +1397,7 @@ role="subsection"><title>VIDEO_SET_SYSTEM</title>
 </entry>
  </row></tbody></tgroup></informaltable>
 
-</section><section
+</section><section id="VIDEO_SET_HIGHLIGHT"
 role="subsection"><title>VIDEO_SET_HIGHLIGHT</title>
 <para>DESCRIPTION
 </para>
@@ -1705,25 +1439,9 @@ role="subsection"><title>VIDEO_SET_HIGHLIGHT</title>
 <para>SPU Highlight information according to section ??.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>input is not a valid highlight setting.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+&return-value-dvb;
 
-</section><section
+</section><section id="VIDEO_SET_SPU"
 role="subsection"><title>VIDEO_SET_SPU</title>
 <para>DESCRIPTION
 </para>
@@ -1766,17 +1484,9 @@ role="subsection"><title>VIDEO_SET_SPU</title>
  to section ??.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+&return-value-dvb;
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
 <para>EINVAL</para>
 </entry><entry
  align="char">
@@ -1785,7 +1495,7 @@ role="subsection"><title>VIDEO_SET_SPU</title>
 </entry>
  </row></tbody></tgroup></informaltable>
 
-</section><section
+</section><section id="VIDEO_SET_SPU_PALETTE"
 role="subsection"><title>VIDEO_SET_SPU_PALETTE</title>
 <para>DESCRIPTION
 </para>
@@ -1827,17 +1537,9 @@ role="subsection"><title>VIDEO_SET_SPU_PALETTE</title>
 <para>SPU palette according to section ??.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+&return-value-dvb;
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
 <para>EINVAL</para>
 </entry><entry
  align="char">
@@ -1845,7 +1547,7 @@ role="subsection"><title>VIDEO_SET_SPU_PALETTE</title>
 </entry>
  </row></tbody></tgroup></informaltable>
 
-</section><section
+</section><section id="VIDEO_GET_NAVI"
 role="subsection"><title>VIDEO_GET_NAVI</title>
 <para>DESCRIPTION
 </para>
@@ -1889,17 +1591,9 @@ role="subsection"><title>VIDEO_GET_NAVI</title>
  ??.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+&return-value-dvb;
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
 <para>EFAULT</para>
 </entry><entry
  align="char">
@@ -1907,7 +1601,7 @@ role="subsection"><title>VIDEO_GET_NAVI</title>
 </entry>
  </row></tbody></tgroup></informaltable>
 
-</section><section
+</section><section id="VIDEO_SET_ATTRIBUTES"
 role="subsection"><title>VIDEO_SET_ATTRIBUTES</title>
 <para>DESCRIPTION
 </para>
@@ -1951,17 +1645,9 @@ role="subsection"><title>VIDEO_SET_ATTRIBUTES</title>
 <para>video attributes according to section ??.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
+&return-value-dvb;
 <informaltable><tgroup cols="2"><tbody><row><entry
  align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
 <para>EINVAL</para>
 </entry><entry
  align="char">
diff --git a/Documentation/DocBook/media/dvbstb.png.b64 b/Documentation/DocBook/media/dvbstb.png.b64
new file mode 100644 (file)
index 0000000..e8b52fd
--- /dev/null
@@ -0,0 +1,398 @@
+iVBORw0KGgoAAAANSUhEUgAAAzMAAAGaCAYAAAA7Jx25AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBI
+WXMAAA3XAAANiQFmEOuiAAAgAElEQVR42uzdd1RU18I28GdgKFZUBE0saFA0KoqFFkEhKhbAQmxJ
+bIkNNEpMEUwsMZarJMZrw4KxRExQczUqil0jRBA1GAjGQqLYC4TemdnfH76cj3HodYDntxaLmTll
+zuw57Zmz9z4yIYQAkYZzcnJCSkoKGjZsyMIgIiIiquPS09PRoEEDyBhmqCaQyWRo06YN3nvvPRYG
+ERERUR137Ngx/Pnnn5CzKKgmMDAwwKpVqxhmiIiIiAj29vZ4//33ocWiICIiIiKimohhhoiIiIiI
+GGaIiIiIiIgYZoiIiIiIiBhmiIiIiIiIYYaIiIiIiIhhhoiIiIiIiGGGiIiIiIgYZoiIiIiIiBhm
+iIiIiIiIGGaIiIiIiIgYZoiIiIiIiGGGiIiIiIiIYYaIiIiIiIhhhoiIiIiIGGaIiIiIiIgYZoiI
+iIiIiBhmiIiIiIiIYYaIiIiIiIhhhoiIiIiIqFLIWQRElSMsLAy2trZo1KgR5HJualTxEhIS8P33
+3+PDDz+sM5+5bdu2ePDgAZo2bcoVgCplm3J0dMS5c+fqzGf++uuvsWTJEm5TVClSU1ORk5ODBw8e
+oHXr1gwzRDVJbm4uAGDRokUwMDBggVCFmzlzJrKysurUZ3727BksLCzg4eHBFYAq3IIFC5CQkFCn
+PnNGRgYAYNWqVVwBqMJFRUVh48aNUCqVlfYeDDNElWzGjBkMM1QpNm7cWOc+c8uWLTFjxgzMmDGD
+KwBVuLt37yIkJKTOfW5nZ2duU1SpYaYysc0MERERERHVSAwzRERERETEMENERERERMQwQ0RERERE
+xDBDREREREQMM0RERERERAwzREREREREDDNERERERMQwQ0RERERExDBDRERERETEMENERERERMQw
+Q0REREREDDNEREREREQMM0RERERERAwzRERERETEMENERERERMQwQ0RERERExDBDREREREQMM0RE
+RERERAwzREREREREDDNEREREREQMM0RERERExDBDRERERETEMENERERERMQwQ0REREREDDNERERE
+REQMM0RERERERAwzRERERETEMENERERERMQwQ0REREREVGnkLAKimunBgwdISkoq8/SGhoZ47bXX
+WJCV6NmzZwgMDMS5c+ewd+9eFgiVSVZWFkJCQnD16lU8evQICoUChoaG6NChA2xsbNCxY0fIZDI8
+efIEp06dwuTJk0s876CgIJiYmKBLly4saKq2Y5Wuri6aNm0KQ0NDaGnxd3ZimCGqE/78808EBgbi
+p59+QkJCgsowLS0tyGQy6blSqYQQQmWcjz/+GGvXrmVBVoKtW7di+/btuHbtGoQQMDQ0ZKFQqf37
+77/w8fHBtm3bkJCQgCZNmsDS0hLGxsZ48OABtm/fjidPnsDU1BR2dnYICwtDz549SxxmlEol5s6d
+CxsbG+zZs4cFTpV2rDpx4gQOHDiAJ0+eqAzT09ODUqlETk4OAEBfXx/dunWDvb093Nzc0LdvX5Vj
+GVFBGH+JaqihQ4di06ZNOHr0qMrrly5dgkKhQG5urvSnVCqRlZWF27dvY8mSJQCA7OxsFmIlmTFj
+Bs6ePctfu6nMTp48iTfffBOrV6+Gnp4e9uzZg+fPn+PUqVPw9/fHkSNH8PDhQxw9ehRCCOzevRu3
+bt1CWlpaqd4jJiYG+/btw+PHj1noVGnHqnXr1uHcuXMqr+/fvx8ZGRnIzs5GSkoKIiIi8M0330BH
+Rwdr166Fvb09evXqhdOnT7MQiWGGqDazsrJSeV5Y1TFdXV107NgRX331FSZPniz9ElbTnDp1SuOX
+USaToXHjxujevTtXUCq1H3/8EcOGDcPz58/RtWtXREREYMKECdDR0VE9gGtpwcXFBdeuXYONjQ0A
+ID09vcTvs2HDBgBATk4OfH19WfBUqTp16gS5/P9XCDI3N5euujRs2BAWFhb46KOP8Ntvv+HIkSNo
+3rw5rl+/DicnJ3z66adQKpUsRGKYIaqNdHR0Sl3HeNy4cTXyysyBAwdq1EkX635TaV29ehVTpkyB
+UqlEw4YNcfToUbRs2bLIaZo0aYIjR47AyMioxFdm7ty5g6CgIGhrawMAtmzZgoyMDH4BVGlkMhl0
+dXVLNJ6rqyvCwsLQqlUrAMB3332Hjz/+mIVIDDNEtfkgURqOjo5YunRpjfqMd+7cwfTp0/llU62l
+VCoxY8YM6arp/Pnz0b59+xJNa2RkBC8vrxJfmfH19YWVlRUmTJgAAIiPj2cnFaRRxypTU1McOnRI
+CtwbNmzA4cOHWYjEMENUl+Xm5iIhIQH6+vowMTEpcJz8HQUIIdQ6DijoBKy0CppnUfN59uwZnJ2d
+S9V7mxCiVMtW2mWqiPckyu/EiROIiIgAAGhra8Pd3b1U00+aNAlZWVnFjpeamoqdO3di9uzZmD17
+tvT6f//732K3d6KqZGlpiRkzZkjPvby8it3HlmY/XNh+v6jtoCTHRU1RlmNSac8BGGaIqEpduXIF
+CxYsUHs9MTERfn5+sLa2xrVr15CSkoJJkyZBX18fbdq0QWRkpMrOLTAwEMOHD4epqSnat2+Pxo0b
+o3///vDz8yu0LU5ubi7Onz8PDw8PmJubS+87d+5cGBoaQi6Xw8LCQq2x5+XLl2Fra4s7d+4AAEJD
+Q+Hi4gIXFxfMnz9fZdzs7Gz4+vrC2toa+vr60NHRQdeuXeHj41PgSV5Zl+lVx44dw8CBA/Haa6+h
+Q4cO6NmzJw4cOFBn17OgoCC1XouoeD/++KP02NbWFkZGRqWa3sjICDt37ix2PH9/f8jlcowdOxaW
+lpawtrYGAERHR+Ps2bP8IjRQaGgooqKi6mTYnDNnjvT41q1buHTpkto4pdn3CyFw7do1eHt7o127
+dkhMTIQQAv7+/rCwsIBcLkfTpk3x8ccfS9Wxc3NzsXnzZvTu3Ru6urqoX78+3n33XbWeRPfv34/x
+48dLx6jFixdLw5KSkjB37lwMHz5cGp6/hkRsbCzmz58vDcv7++KLL5Cbm4vDhw9j7Nix0utz587F
+s2fPylUWZTkH0NTURqTxDAwMxN69e2vUMgcHBwsAIjExsdLfS1tbWwAQAMTdu3cLHW/hwoVi5syZ
+0vMrV66IESNGCF1dXWn63377TfTv31/o6+tLry1YsEAIIUR6eroYPXq00NPTE7t37xY5OTlCCCFu
+374t+vbtKwCIHj16iNjYWJX3PXXqlHBycpLm16JFCxEdHS06duwoHB0dhYuLi6hfv74AIHR0dMQf
+f/whTfvXX3+J06dPC2NjYwFA2NraitOnT4vTp0+L8PBwabynT5+KPn36iOnTp4vIyEjx6NEjcejQ
+IdGiRQsBQPTt21ekpaVVyDLlUSgUYvbs2UIul4stW7aI7OxsIYQQ0dHRwsLCQjRq1EgAEIaGhpXy
+vZubmwtfX1+NW/fzyrRdu3Zi5syZIiAgQDx58qRC5t22bVuN/MwVoVWrVlLZeXp6Vsp7KJVK0bVr
+V+Hl5SW95u/vL72vs7NznT7WeHt7Czs7O41brmnTpgkAwsDAQIwYMUKsX79eREZGCqVSWSGfuaq+
+9wYNGkjr2l9//VXi6dq3by9Nt3jxYpVhpdn3X7p0SYwePVrI5XKV5Rg8eLCwsrIS7u7u4u2335aG
+ff755+LJkyfirbfeEo6OjmLWrFli1KhRQktLSwAQrq6uast67949af6DBw9WGx4dHS0ds18td6VS
+KZYtWya9f+/evVWGr1y5Uujq6oqAgIACv/vSHgdLew5QFpGRkQKA2nlBRQgMDBQGBgaCYYYYZmpZ
+mDl48KAIDQ2V/i5duiTOnj0rvv76a6Grq6sSZtLS0kR2drZ0oAQgnJycxKFDh0RqaqqYOHGiaNKk
+iTh9+rRQKpVi7NixAkCBJ5MpKSmic+fOAoDo1KmTSElJURtn6NChAoDQ19cXlpaWIiIiQhr2xx9/
+SJ9jypQpatOamJgIAGLEiBFqw7Kzs0WfPn3EqFGj1Hbw+/fvlz6bt7d3hS7TokWLBACxZs0atWGP
+Hz+WDtx1Lcw0a9ZMKnMdHR3pwF4R4aa2hpnk5GSpzApbpyrC2bNnhUwmU/nRIzMzU/qxAIC4efMm
+w4yG8fDwkE6gtbS0hJ6eXoWFm5oQZkaOHClNN3r06HLv+xcsWCANs7GxUflhTKlUSu/XoEEDYWlp
+KS5cuKAy/erVq6XpY2Ji1JbX1NS00DCT/3hWULkrlUoxZMgQ6bvOK6f09HTRsWNH8d133xU4z7KU
+RWnOARhmiBhmqizMFPeXP8zk+eGHH6ThX331VYHvcezYMQFANG3aVGRlZRU4zpEjR6T5fPHFF2rD
+P/roI2n4s2fP1Ib369dPCkOlCTNbt24VAMS5c+fUhmVmZkq/MDVt2lS6mlTeZbpx44bQ1tYWhoaG
+hZbH8OHD62SYMTIyKnT9K2+4qa1h5p9//lEpp61bt1bK+4waNarAX5PzgjkAMWvWLIYZDQwz+a8m
+5P8rb7ipCWFmxowZ0nSOjo7l3vdv375dml9YWJjatPv27ZOGb9q0SW34zZs3peG7du1SG96pU6ci
+w0xe2Cms3O/fvy9d2XdychJKpVJMmzZNODg4CIVCUeA05TkOluQcQJPDjJw1UYlql5s3b6o07hdC
+IC0tDZcuXcKHH35Y4DT5718xZMiQAsfJ6xLZysqq0O41hw0bBmNjYzx//hxbt27F0qVLVe4rkNcr
+DQAYGxurTZ/XDWd8fHypPrOfnx8AIDw8HNHR0WrDmzVrhsePHyMhIQE3btxQuf9LWZdp3bp1UCgU
+GDhwYKHl0ahRI66Qr8jfpurevXvYsWMHvv/+e+Tm5qJdu3YYPHgwHB0d0b9//2K7JK7NFApFhc8z
+NjYWhw8fxvHjx9WGzZw5EytXroRCocCuXbuwfPlyNG3alCtsDZB3U+S8dhlHjx7FiRMnkJWVBQMD
+Azg4OGDAgAFwcHBAt27dSt37pSbIv8z5j1dl3ffn3+83aNCg0P1+3jxe1aJFC+nxw4cPK/zztmnT
+Bt988w3c3d1x6tQpTJo0CYcPH0ZUVFShXf6X5zhYknMATcYwQ1TL6OnpQV9fX+W1evXqYfjw4Viw
+YIHUkL4w+Xfy+Q+WFy5cAAA0b968yGn79++PAwcOID4+HtHR0ejRo0eJlz1vJy1K0cg1OTkZ165d
+g7a2dqGNzseMGaP2HuVZJiGE1EVo586dq/Uk5v79+7h27ZpGrYO5ubllDjfff/89tm/fDoVCIYWb
+3r17w9XVtVaHm1eDQ1xcXIW/x5YtW/DGG29g0KBBBZ68ubm54cCBA0hPT8f27dvx+eef18l9aFpa
+msZtUy9evChzuDly5AiCgoKQnZ2Nxo0bw9HREf369YO9vT369OlTI76Tf//9V3r8+uuvV/q+v6Dj
+oMrJc74f6Srr/kzTp0/Hvn37cP78efj7+2Pjxo2F9kJakWVR3GdnmCGqQ4QG9jrz9ttv4+7du6We
+Lj4+XroZX3Enqp06dZIeP3z4sFRhpizu3r0rdT+5Zs2aKtkRv3jxAk+fPgVQvVdfsrOzsWrVKqxa
+tarWbDf516979+5h69atUkifOnVqpVyx0ARNmjSRrmoCQExMTIXOPyMjA35+flAoFCq/yL66nefZ
+sGED5s2bp3LSVlfcuHGjxpzkl/RYlNcrV3JyMg4fPiz9GOPo6CiFA01269Yt6XHv3r2rbd9flbS0
+tODn5wdzc3NkZGTg1KlTmDVrVoFX1mp7WTDMEFWDFy9eYPny5Rq3XD179sTGjRtLPV3+E8i8k/jC
+GBoaSo+rYoeaF7KEELh//36JbzJYHvl/Nc/MzKy271NPTw/ffvttodUHq4uZmVmZryzo6ekhKysL
+enp6sLS0hJOTE/r37w8bGxvo6uoiMDCw1u437OzscPDgQQAvu+KtSAEBAUhNTYWPj0+Rv8quWLEC
+T58+xYMHD3Do0CGVX3Prip49exZYFa86ffbZZ/jhhx9KddUzj46ODpRKJZRKJTp06IChQ4fCwcEB
+ffv2hbGxMRYsWIDExESNPp5GRUVJz11cXKpt31/V0tLSpOPvkSNHsG/fPowfP14jjoMMM0S12Llz
+5zBgwABMnTq11nym5s2bQ0dHBzk5OYiOjoYQotB61/lv0PXGG29U+rLVr19fehwSElIlO3E9PT3p
+8d9//11t34tMJkP9+vU1rm1Daerk6+vrIzMzUyW8ODo6Ftk2q7YaO3asFGbu3LmDqKgo6f5H5SGE
+wIYNGzBmzBjMnTu3yHHj4+Px1VdfAXh5E826GGby7jOiSfLvc4qjq6sLhUIBpVKJjh07YsiQIXBw
+cIC9vX2R1YQ11c6dO6WaDi4uLmjXrl217furUlZWFiZMmIClS5di48aNePToEebMmYMBAwao3YOq
+tpdFcXjTTKIKolQqsXz5cgwYMAAAMHz48Fp1cM+7sV5cXBxu3LhR6Lh59XVbtWqFjh07VvqymZqa
+SifPfn5+RVbvS01NxcyZM8v9nq1bt5YaTF64cIF3TS+FvPZcenp6sLOzwxdffIHg4GAkJycjODgY
+ixYtgp2dXZ0LMgDg5uamchLy3XffVch8L168iIiICEyfPr3YcWfOnCmt25cuXUJ4eDhXWg2nq6sL
+bW1tyGQymJmZwd3dHQcOHMCLFy9w69YtrFu3DqNGjaqRQebx48dSNVpdXV2sXr26Wvf9FaUkx4yF
+CxeicePGmD9/PjZv3iwdfz09PTXiOMgwQ1TLvHjxAoMGDcKSJUsAvLxjcUE9oFTWTjH/1ZDKOrH+
+4IMPpMcBAQGFjpd38uPu7l7qXnOKWva8eeXV/c7TqFEjKWgFBwdjz549BU6fm5uLKVOmwMnJqdzL
+pKenh/79+wN4WVc5KCioyGnrWtjJq/Lwanixt7dneCmCjo4ONm3aJD3ftWsXTp8+XeLpExMT4erq
+qnZX8NWrV8PMzAz29vbFzqNly5YYPXq09Hzt2rXcwWsApVIpVTcqaXjJX+W3Jp3E50lISMDIkSOR
+kJAAANi0aRO6dOlSZfv+8sirYp2enl5gGaSkpBQ5/a+//oqNGzfCz88PWlpacHV1xbvvvgsA+Omn
+n3D06NEqPQ4yzBDVcufPn0fXrl1x8eJFKJVKaGlp4bPPPquy909PT1c5QJSlZ5X8YaiwOtmTJk2C
+paUlAGDz5s0F1rG+ffs2goODYWZmhnnz5qkNL67xdl7PVgUd8PKqfdy+fVsanp2djcePH6v8UjVt
+2jSsX79e6s0HeFllx8XFBdnZ2XBzc6uQZcr/+Tw8PNS650xMTERISAiAl41uU1NT68w2kXcAfzW8
+XLx4keGlGEOHDsWaNWuk525ubiVqJxQaGgpLS0v069dPpdvYK1euICgoCGPGjCnxjwvvvfee9PjA
+gQPVWpWS/v8JsBCixoWXV/e1+dsYFhZshBA4deoU+vTpgytXrkBXVxfbtm3DtGnT1MYt674//zGv
+LMfE4n5AzLvCevnyZdy+fVulDFasWCHtIwu6DUFycjImT56MBQsW4M0335ReX7dunfQdu7u7qx2D
+y3McLMk5AMMMUS2kVCrx9ddfY+DAgYiPj0dubi7kcjnGjx+Ptm3bVtlynDx5UuV5YVcJipK/u+bf
+f/+9wHHkcjkOHTqETp06IT4+HhMmTFD5BT4hIQETJ05EmzZtEBgYWGDf/flPivJ6bcp/QPjzzz8B
+vOxONDk5WWW4ra2tNI/58+fj4MGDeOedd/Dvv/9i3LhxGDdunBQ+PD090bx5c/To0QOmpqYwMzND
+UlIS/P391U7oyrpMw4YNg4eHBwDg/v376NWrF1asWIHAwEBs27YNjo6OMDAwkA4O3bt3r3WX9gtz
+7do1ZGVlMbyU0SeffIJ9+/ahWbNmSE1NhaurK9zc3HDy5EmVX3pTU1MRFBSEd955By4uLli2bJlK
+d8qZmZmYNWuWtP2WVF6bhLyTr3nz5hV78keVa968eYiLi6tR4eVV58+fV1mP9u3bh5iYGPz999/4
+/fffcfjwYSxatAg9evTA4MGDce/ePbi5ueH69euFVpEs674/f2+BBQWK2NhY6XFB1aofPHggPX78
++LHa8LyaDNnZ2bCzs4OXlxe8vb1hbm4OIQQcHBwAAGFhYXj//fdx7Ngx6bxi2rRpUCqV8PLyUpmn
+kZGRVPvj8ePHmDJlikrwKM9xsCTnAJqe9ok0noGBgdi7d6/GLM+TJ0+Eg4OD2h2ZZTKZiIyMFEII
+ERwcLACIxMTESlkGPz8/MWjQoALvCm1nZyc+/fTTYudx5swZ4erqKrS0tKRp9fT0xKRJk8T27dsL
+nCYpKUnMmzdPNGrUSLz++utixowZ4sMPPxQmJibC3d1dxMXFqU0TGhoqxo8fr7KMXbp0EV9++aUQ
+QoiTJ08KJycnleE9e/YU27Ztk+YRGxsrWrduLQ1//fXXxfnz56XhOTk5YsmSJdJdk/P+DAwMxMKF
+C0VGRkaFL5NCoRDffPONaNq0qcp4JiYm4ty5c+L9998XhoaGwsPDQwQHBxd65+ayMjc3F76+vnVq
+X9C2bds685nj4uLEkiVLRNu2bVX2MYaGhqJZs2YCgGjTpo1YtGiR2na3f/9+0blzZ2k6uVwuRo0a
+JY4fP17o+/31119i8uTJol27dmr7lN69e4tffvml1pe5t7e3sLOzq1PblLe3d6F3oq+oY5WTk5PQ
+1dVVW6/y/zVu3Fh06dJFjB07VmzatEk8fPiwRPMvzb7/119/FbNmzRJ6enoq+2tvb28RGxsr/v77
+bzFv3jzRvHlzabiurq7w8PAQFy5cEBkZGeLzzz8X7du3V9m23N3dRWBgoPQ+SqVSLF26VOX43KxZ
+M+n44ezsLNq3by+8vb1FaGioyM3NFcHBweLtt98WAISRkZHw8fFR+Zznzp0TDg4OKp/R1tZWZZsu
+7XGwLOcApRUZGSkAiNjY2ApftwIDA4WBgYGQCbZcpRqgSZMm8PX1Van+UJ2/Lo0ZMwYpKSkq7Tfk
+cjkcHR1x6tQpAC97FLG3t0diYqL0C31tkpWVhT/++ANxcXFo2rQpevToodKjSmVIS0tDWFiY1PNV
+QT38ZGRk4Pr160hISICRkRG6d+9eqp6AyloW169fR1xcHIyNjdGzZ0/I5XLExMTAxMRE5e7KFal7
+9+7w8PCQrhDVBSYmJvD29q5Tn1kIgdu3b+PPP/9EXFwclEoljI2N0bVrV3Tq1KlG3tFdUy1YsAAh
+ISEIDg6uU585Kiqqxnd7Xh37/uK8ePEC169fR7169dCnTx+pDeE///yDdu3alfomzjWxLKKiotC9
+e3fExsZWeK2VY8eO4f3332fXzEQlpVAosGzZMixbtky6HPzq8C+++KLOlIeenh6srKyq9D0bNGgg
+9RZXmHr16klV0qqyLPIaX+bXoUMHbjhUbjKZDJ06dVK5IS0RVf++vzhGRkYYNGiQ2uuVfdsCTSyL
+ysQwQ1QCT58+xZgxYxAWFlZg3XEtLS1YWFhI9WCJiIiIqPKxAwCiYpw5cwbdunVDeHh4kb18LFy4
+kIVFRERExDBDVP0UCgUWL14MJycnJCQkqN3fJI9MJoOJiQlGjBjBQiMiIiKqQqxmRlSAR48eYfz4
+8QgLC5P69y+MtrY2vvjii0pryEdEREREDDNEJXLq1CkMHjwYurq6Jbp5lIGBASZNmsSCIyIiIqpi
+/CmZKB8hBPbv3w8AhVYry09XVxdeXl68ISARERERwwxR9ZLJZNi+fTvWr18PLS2tYquO6ejoYMaM
+GSw4IiIiIoYZIs0wZ84cnDlzBo0aNSr0hoe6urr46KOPauUNMYmIiIgYZohqMEdHR4SGhkJbW7vA
+O2wrlUp4enqyoIiIiIgYZog0z6pVq9CsWTO4uLhAW1tbel1XVxeTJ0/Ga6+9xkIiIiIiYpgh0izr
+1q1DQEAA/ve//+Hw4cNYvnw5tLS0IJPJkJ2dDS8vLxYSEREREcMMkWa5cOECPvvsM/j6+sLGxgYy
+mQze3t4IDAyEEAI2Njbo2LEjC4qIiIioGvE+M0SvuH//PsaOHYtp06Zh6tSpKsOGDh2KW7duISsr
+iwVFRERExDBDpDnS09Ph5uYGMzMzrFu3rsBxzMzMWFBEREREDDNEmsXDwwNPnz7F1atXeSNMIiIi
+IoYZopohr8H/r7/+ipYtW7JAiIiIiBhmiDRfXoP/LVu2wMbGhgVCREREVAOwNzOq84pq8E9ERERE
+DDNEGqkkDf6JiIiISDOxmhnVaWzwT0RERFQLwsz333+P77//Hg0aNGCpUIVTKBTIycnB//73Pxgb
+G2vEMrHBPxEREVEtCTMxMTEIDQ2Fl5cXS4UqXFRUFM6fP4/MzEyNWB42+CciIiKqRWEGAJydnbFq
+1SqWClVKmDl+/LhGLAsb/BMRERHVDuwAgOoUNvgnIiIiqj3YAQDVKWzwT0RERMQwQ1TjsME/ERER
+EcMMUY3DBv9EREREtQ/bzFCtxwb/RERERAwzRDUOG/wTERER1V6sZka1Ghv8ExERETHMENU4bPBP
+RERExDBDVOOwwT8RERFR7cc2M1TrsME/EREREcMMUY3DBv9EREREdQermVGtwgb/RERERAwzRDWO
+pjb4X716NQwMDPgFUYWLioqqc5/54cOHWL16NZKTk7kCUKXsr83Nzevc5z527BhWr17NFaAYycnJ
+uH//Ptq1a4eGDRuyQDTkOMUwQ7WCJjb4b9iwIUxMTHDixAloabFGJ1W8Nm3awMjIqE59ZkdHR9y/
+fx8HDhzgCkAVrl27dujZs2ed+sytWrVCmzZtuE29QqlUIi0tTeUvJycHMpkM+vr66NKlCwupBLKz
+s2FqalqptWUYZqjG09QG/xYWFrh37x6/IKIKdObMGRYCUQX66KOP8NFHH9XpMlAoFIiOjkZ4eDgu
+X76My5cv48aNGxBCoHPnznBycoKVlRVsbGwQFRWFhQsX4urVq1x5NATDDNVobPBPREREpfHo0SMp
+tFy+fBnXrhOJlUQAACAASURBVF1DamoqWrZsCWtra4wfPx42Njbo06cPGjdurDLtjRs3WIAMM0QV
+hw3+iYiIqDCpqam4evUqwsPDERYWhvDwcDx69Aj169dH7969YWVlhdmzZ8Pa2hpt27ZlgTHMEFUd
+TW3wT0RERFWvuOpi1tbWWLhwIWxsbNCtWzfI5TwNZpghqiaa2OCfiIiIqk55qosRwwxRtdHUBv9E
+RERUOVhdjBhmqFZgg38iIqLajdXFiGGGai02+CciIqpdWF2MGGaoTjhx4gT27dvHBv9EREQ1FKuL
+EcMM1Um5ubn48ccfsXXrVjb4JyIiqgFYXYwYZojwssF/eno63n77bTb4JyIi0lCsLkYMM0SvyGvw
+r6WlhUmTJrFAiIiINACrixHDDFEJeHh44NmzZ2jQoAEvPxMREVUDVhcjhhmiMli3bh0CAgLw66+/
+YsiQISwQIiKiKlCS6mLW1tawtLRkdTFimCEqyIULF/DZZ59hy5YtbPBPRERUSVhdjBhmiCrY/fv3
+MXbsWEybNo0N/omIiCoIq4sRw0wVCAoKgomJCbp06cJvpw7Ka/BvZmaGdevWsUCIiIjKiNXFiGGm
+iimVSsydOxc2NjbYs2cPv506KK/B/5UrV6Crq8sCISIiKgFWFyOGGQ1w8uRJxMTEIDY2FqtXr8br
+r7/Ob6gOyd/gv2XLliwQIiKiAigUCty4cUPlqgurixHDjAbYsGEDACAnJwe+vr5Yvnx5lb7/qVOn
+4OTkxLWiGrDBPxERUcFYXYyoBoSZO3fuICgoCNra2lAoFNiyZQu+/PJL1KtXr0re/8CBA9i7dy/D
+TDVgg38iIqKXWF2MqIaGGV9fX1hZWeHNN9/E7t27ER8fj71792LatGlVEqSmT58OBwcHrhFVjA3+
+iYiormJ1Mc329OlThISEYPTo0UWOFxMTg3/++Yc/iNflMJOamoqdO3di/fr1UpgBgP/+97+YOnUq
+ZDJZieclhFAbX6lUQktLq8Dxnz17BmdnZyQlJZVqmYUQEEIUOt/yLFNFTfvqfACUqiyrAhv8ExFR
+XcHqYjXLzZs3MW7cOMTFxaFp06aFjrdnzx4cPXqUYaaaaGnCQvj7+0Mul2Ps2LGwtLSEtbU1ACA6
+Ohpnz54tdvrc3FycP38eHh4eMDc3BwAkJiZi7ty5MDQ0hFwuh4WFBU6fPq0y3eXLl2Fra4s7d+4A
+AEJDQ+Hi4gIXFxfMnz9f7X2ys7Ph6+sLa2tr6OvrQ0dHB127doWPjw+ysrIqZJnKO21+V69excSJ
+E2Fvb4/Bgwejbdu26N27N3bs2CGFm+qU1+D/wIEDbPBPRES1SmpqKi5cuAAfHx+4ubmhdevWaN26
+NSZOnIjQ0FD06dMHO3bsQGxsLJ48eYJffvkFX3zxBQYMGMAgoyFsbGygq6uLkJCQIse7cOECHB0d
+WWDVRfwfb29v4ezsLKqaUqkUXbt2FV5eXtJr/v7+AoAAUOwynTp1Sjg5OUnjt2jRQkRHR4uOHTsK
+R0dH4eLiIurXry8ACB0dHfHHH39I0/7111/i9OnTwtjYWAAQtra24vTp0+L06dMiPDxc5X2ePn0q
++vTpI6ZPny4iIyPFo0ePxKFDh0SLFi0EANG3b1+RlpZW7mUqz7T5bdq0SchkMuHp6SkUCoUQQoi0
+tDRhZ2cnAIgVK1ZU6fccGRkpAIjY2FghhBDnz58XcrlcbN++vUTTGxgYiL179woiIiJNk5ubKyIj
+I4Wfn5+YNm2aMDc3F9ra2kJLS0t06dJFfPDBB2Lz5s0iIiJC5OTksMBqkH79+olPPvlEer53717R
+tm1b6Xl6errQ09MTR44cYWFVscDAQGFgYCCqPcycPXtWyGQycffuXem1zMxMKWAAEDdv3ix2PkOH
+DhUAhL6+vrC0tBQRERHSsD/++ENoa2sLAGLKlClq05qYmAgAYsSIEQXOOzs7W/Tp00eMGjVKKJVK
+lWH79++XltPb27vClqk80z548EAafurUKZVhAQEBAoBo1KiRyMrKqpYwExsbK4yMjIS7u3uJp2eY
+ISIiTfHw4UPxv//9T8yfP1/0799fNGzYUAAQLVu2FCNGjBArVqwQZ86cEUlJSSysGm7x4sWiZ8+e
+hYaZ8+fPC21tbZGQkMDCqqYwU+3VzDZu3AgXFxe0a9dOek1PTw8zZ86Unq9fv77Y+ZiamgIAMjMz
+ERgYCAsLC2lY9+7d0bdvX6kqWWnt3LkTV69exZw5c9TanAwfPhz6+voAgK1btyI3N7dClqk8096+
+fRsKhQIAEBcXpzLM2NgYAJCSkoK7d+9W+fedkZHBBv9ERMTqYlQjODo64o8//kBCQkKBw8+fP4/u
+3bujSZMmLKxqUq0dAMTGxuLw4cM4fvy42rCZM2di5cqVUCgU2LVrF5YvX15k4yttbW21E/b8WrVq
+BQCIj48v9XL6+fkBAMLDwxEdHa02vFmzZnj8+DESEhJw48YNdO/evdzLVJ5p+/Xrh08//RRZWVkY
+OXKkyrD8Yay0nR5UhC+//JIN/omISCOxdzF6lY2NDXR0dBASEgJXV1e14WwvU8fDzJYtW/DGG29g
+0KBBBZ6su7m54cCBA0hPT8f27dvx+eefl/m98nr/EqVs+J6cnIxr165BW1sbT548KXCcMWPGqL1P
+ZS5TcdPK5XJ8++23Kq+lp6cjICAAO3bskF5TKpVV/p0fOXIEFy9eZIN/IiKqduxdjIqjr68Pa2tr
+XLhwQS3MZGRk4PLly/jss89YUHUxzGRkZMDPzw8KhUK6kvGq/FcdNmzYgHnz5lX5ryB3796FEAJK
+pRJr1qxRuWJSE9y7dw/r16/HrVu3MHXqVCxZsqRauw5csWIFbGxsuOUREVGV4s0oqawcHBxw9OhR
+tdcvX76M3Nxc2Nvbs5DqYpgJCAhAamoqfHx8iryasWLFCjx9+hQPHjzAoUOHVK6CVIW0tDQAL6+A
+3L9/H+3bt68RX2xaWhoWLFgAf39/+Pr6Ys2aNZDJZLhw4UK1Ltft27dx//59HiiIiKjSsLoYVSRH
+R0csX74ciYmJKq+zvUwdDjNCCGzYsAFjxozB3Llzixw3Pj4eX331FYCXN9Gs6jBTv3596XFISEiN
+CDNJSUlwdHREREQEgoKCMGTIEI1Ztl69esHExASTJk2Cn58f280QEVG5sboYVaa8djPBwcEqr7O9
+jGaolt7MLl68iIiICEyfPr3YcWfOnAkdHR0AwKVLlxAeHl6ly2pqaio1mvfz8yuyfUtqaqpKL2zV
+ZeXKlYiIiICJiYlGBRkAcHZ2BgD88MMPePPNN3HixAluhUREVGLsXYyqWv52M3ny2ss4ODiwgOpi
+mFm9ejXMzMxKVMewZcuWGD16tPR87dq1ZXrPokJIXljJzs5WG9aoUSNYW1sDAIKDg7Fnz54C55Gb
+m4spU6aUqj1KWRr+l2TavN7h9PT01Ibl5ORU+0oXFRUF4GV7JGdnZ4wcORL//PMPt0YiIlKhUCgQ
+FRWF7du3Y/r06VKVngEDBmD37t1o0qQJFi5ciIiICCQlJeHixYv49ttvMWbMGFZnpgrl4OCA8+fP
+S8/DwsLYXqauhpkrV64gKCgIY8aMUbtnS2Hee+896fGBAwfw999/F7jDK0reSXxBISCvy+fbt29L
+w7Ozs/H48WMAgKenpzTutGnTsH79emRlZUmv3blzBy4uLsjOzoabm1uFLFN5ps3rpezOnTv4888/
+pdczMzOxe/dulV8VyhuqyqJbt2745JNPYGBgAF1dXcTExKBbt2746quvpGUiIiLNdP36ddy5c6dS
+5v3o0SMcPHgQXl5ecHBwQJMmTdC9e3csWrQIL168wPjx43Hy5EkkJCQgOjoaO3bsgLu7OywsLNju
+hSpV3v1m0tPTAbysYtajRw+2l6lrYSYzMxOzZs0CgFLtdPLfUFOhUGDevHlq3QrnDzjPnz9XGSaE
+kE7qk5KSkJycrDLc1tZWmsf8+fNx8OBBvPPOO/j3338BAOPGjcO4ceOkEOHp6YnmzZujR48eMDU1
+hZmZGZKSkuDv768S0MqzTOWZNu/qkBACgwYNwsKFCzF79mz06NEDXbt2lcZbtWoVlixZgh9++KHK
+V7wlS5ZAX18fPXr0wN27dzFr1ixs3rwZXbp0waFDh7hlEhFpmN9//x0jR45Er169EBAQUO75sboY
+1SR57WZu3rwphRlWMdMQ4v94e3sLZ2dnUVn2798vOnfuLAAIAEIul4tRo0aJ48ePFzrNX3/9JSZP
+nizatWsnTZf317t3b/HLL7+I0NBQMX78eJVhXbp0EV9++aUQQoiTJ08KJycnleE9e/YU27Ztk94n
+NjZWtG7dWhr++uuvi/Pnz6ssS05OjliyZIlo1KiRyrwMDAzEwoULRUZGhjRueZapIj5PUlKScHBw
+UBnH2dlZxMTECIVCIczNzaXXR40aJdLT00Vli4yMFABEbGys9NquXbuEvr6+mDx5sqhfv744dOiQ
+mDt3rpDL5WLIkCHi1q1b0rgGBgZi7969goiIqtaVK1eEq6urkMlkwsnJSYSEhJR6Hrm5uSIyMlL4
++fmJadOmCXNzc6GtrS20tLREly5dxAcffCA2b94sIiIiRE5ODgudNFK/fv3EsGHDRJs2bYSenp44
+cuQIC6UaBQYGCgMDAyET/1fHaMGCBYiKikJgYGCdDHVpaWkICwuDnp4eLC0tC2xvArysmnX9+nUk
+JCTAyMgI3bt3L3Tcag6piIyMxJMnT/Dmm2/CxMREGpaSkoLQ0FA0b94cPXv2LHF1v/KIiopC9+7d
+ERsbK9VjFkLA3t4eTZo0QYcOHeDn54fDhw+jRYsWmDNnDkJDQ/HJJ5/gyy+/ROvWreHr66tS5ZCI
+iCpPeHg4vv76axw7dgxDhgzB4sWLpZoMxSmudzErKyv2LkY1zpIlS+Dv74/U1FTEx8cjLi6O1cyq
+0bFjx/D++++DFUz/T4MGDTBgwIBix6tXr16Jd+bVSSaToUePHujRo4fasEaNGlXrjTPzL+PGjRvR
+p08f/PLLLwCAESNG4PDhwzh//jwCAgLw6aefwt/fXyM6LiAiqgvCwsLw9ddfIygoCMOGDUNYWJjU
+EU5BeDNKqivy7jfToEEDtpfRIAwzVK0sLCwwY8YMzJs3D5GRkSqB5t1334Wrqyu+/vprfPPNN1i+
+fLlaux8iIqoYv/32G77++mucPn0azs7OCA8Ph6Wlpco4vBkl1WXW1taQy+VISUlhexmGGaL/b9my
+Zfj555/x7bffSl1v5wWagQMHwsfHB1u2bIFcLoeFhQXmzJmDxYsX8xcRIqIKEBwcjKVLl+LcuXNw
+dXXFlStX0Lt3bwBFVxezsrLizSipTqlXrx7Mzc1x7do1hhmGGaL/z9DQECtXroSnpycmT55cYKDR
+0tKCt7c39PX1MW/ePAQEBGD9+vUq9yAiIqKS+/XXX7F06VJcuHABI0eOREhICLKzs3H27FmsWLGC
+1cWICtC8eXMA4P1lGGaIVH344YfYunUrPv30Uxw4cEAt0ORxc3PD0KFDsXLlSrXuuYmIqHjnz5/H
+0qVLERwcjF69emHUqFG4c+cO+vXrx+piRMXw9vbGixcvWDuEYYZIlZaWFjZs2IC+ffvi1KlTcHJy
+Ugk0+Xtcq1evHpYtW8ZCIyIqhb1792LChAkAAG1tbSiVSsTGxsLIyAgjR47E2rVrWV2MqBjW1tYY
+PHgwC4JhhkidjY0NPvzwQ3h6eiIyMhI6OjpSoFm/fr10o9Ca4s8//8TEiRPRrFkzaGlp8QumCvf8
++XMsX74crq6udeYzv/POO3j48CFPuEshOTkZMTEx0o2ggZcN+QHgxYsXCAoKQlBQEJYtWwaZTCZd
+hcn7r6Ojo/JcLpdDJpNBW1sbLVq0gKGhYa0pq3///RdvvfUWNmzYUGfWj++//x7r16+HsbExN5YS
+ysrKwqBBg1gQJZCdnY309HQcO3as0tYxhhnSKCtXroSZmRnWrVuHzz77DDKZDGvXrsWWLVuwZs0a
+vP322xg4cGCN+CyJiYm4fv063N3dYWBgwC+XKtzq1avx8OHDOvWZDx48iMaNG8PDw4MrQCk4OjpK
+ISYnJ0f6r1QqkZ2drfZfCIGsrCzpf94JHABkZmZK/9u3b4+OHTvWqm0qOzu7Tq0bMTExiIyMhJeX
+FzcUqnBRUVG4ePGitN9gmKFaz8jICEuXLsWXX36Jd999F61atYJMJoO+vj5sbW1VOgWoKVatWsUw
+Q5Xi+PHjde4zt23bFt7e3gwzVClkMhlCQkLq3Od2dnbGqlWruAJQpYSZyj5Wse4LaZzZs2ejQ4cO
+mD9/vsrrEyZMwPTp0zFixAicOXOGBUVERERUxzHMkMbR1tbG+vXrERAQgODgYOn1vCpnDDRERERE
+BLCaGWkoe3t7zJw5E8+ePVN5PS/QAKiRVc6IiIiIiGGG6gBfX98CX2egISIiIiKGGaqxGGiIiIiI
+iGGGGGiIiIiIiGGGiIGGiIiIiBhmiBhoiIiIiIhhhhhoiIiIiIhhhoiBhoiIiIgYZogYaIiIiIiI
+YYaIgYaIiIiIYYaIgYaIiIiIGGaIGGiIiIiIiGGGiIGGiIiIiBhmiIGGiIiIiBhmiBhoiIiIiIhh
+hoiBhoiIiIgYZogYaIiIiIgYZogYaIiIiIiIYYaIgYaIiIiIGGaIGGiIiIiIGGaIGGiIiIiIiGGG
+iIGGiIiIiBhmiBhoiIiIiIhhhoiBhoiIiIhhhoiBhoiIiIiqNcxcuHABZ86cYalQhYuKimKgISIi
+IqLKCzNpaWkYNGgQS4XqPAYaIiIiohoUZv7zn//gP//5D0uEiIGGiIiIqGaFGSJioCmMEALh4eE4
+ceIEnj17BmNjY1haWuLtt99GvXr1kJiYiJ9//hnTpk2Tpnnw4AGSkpLK/J6GhoZ47bXXih0vKysL
+ISEhuHr1Kh49egSFQgFDQ0N06NABNjY26NixI2QyGZ48eYJTp05h8uTJXLGpWgUFBcHExARdunTR
+mGV69uwZAgMDce7cOezdu1dl2L179+Dh4QEDAwNs3boVBgYG/BKpytbLFy9eFDq8adOmaNWqVYHH
+rOjo6AKnad++PRo0aFBh63ZR2w4xzBAx0GiAFy9eYNKkSThx4gSaN28OW1tb3L9/H76+vsjKyoKL
+iwsePnwIuVyuEmb+/PNPBAYG4qeffkJCQoLKPLW0tCCTyaTnSqUSQgiVcT7++GOp3Avy77//wsfH
+B9u2bUNCQgKaNGkCS0tLGBsb48GDB9i+fTuePHkCU1NT2NnZISwsDD179mSYoWqlVCoxd+5c2NjY
+YM+ePdW+PFu3bsX27dtx7do1CCFgaGioNs6aNWtw4sQJAICtrS08PT35RVKV+Oeff+Dn54ddu3ap
+HCM6deqE8ePHo1+/foWGmaCgIPz22284fPgwAMDAwACzZs3CRx99JIWZ8qzbJdl2qIoIohrAwMBA
+7N27t1qXQalUCk9PT1G/fn1x+vTpYscPDg4WAERiYmKNLfeMjAxhYWEhAIjJkyeLjIwMaVh2drbY
+vHmzqFevngAgOnfuXOA8QkJCBADpLyQkpMDxsrKyxO3bt8WSJUsEADFr1qxCl+vEiRPC2NhYABAt
+W7YUe/bsEdnZ2SrjKBQKcfToUfHGG29I7+3q6lqrtgtzc3Ph6+tbp/YFbdu2rdGf+fjx4wKA0NHR
+EY8ePar25VEqlSIpKUl07dpVABCGhoZq42zbtk0AEDKZTJw9e7ZWr1/e3t7Czs6uTm1T3t7ewtnZ
+WaOX0cfHR+U48tNPP5V42i5duggA4sSJExW6bpdk2yEhIiMjBQARGxtb4fMODAwUBgYGQotxjqh0
+V2imT5+OESNG1Ime/7Zt24br16+jSZMm2Lx5M/T19aVhOjo6cHd3x5kzZ1CvXj08evSowHlYWVmp
+PC/oVzQA0NXVRceOHfHVV19h8uTJyMnJKXC8H3/8EcOGDcPz58/RtWtXREREYMKECdDR0VG7+uPi
+4oJr167BxsYGAJCens4VmarVhg0bAAA5OTnw9fXViP1a48aN0b1790LHmT59Oi5fvoyoqCi8/fbb
+/BKpys2bNw9vvvmm9DwkJKSkP9gjLi4OdnZ2GDx4cIWu2yXZdqhqMMwQMdAU6siRIwAAU1NT1KtX
+r8Bx3nrrLXzzzTdISUlBSkqK2nAdHR1oaZVuVzNu3DhkZ2ervX716lVMmTIFSqUSDRs2xNGjR9Gy
+Zcsi59WkSRMcOXIERkZGSEtL40pM1ebOnTsICgqCtrY2AGDLli3IyMjQjJOBYrZRKysrdO3alV8i
+VQu5XI7FixdLz/39/Uu0Pw8PD8fz58/x0UcfVdq6XdrjGzHMEDHQVKHHjx9LJ2FFXdWYPn06WrRo
+IY1fUJmVhqOjI5YuXarymlKpxIwZM6QrNvPnz0f79u1LND8jIyN4eXnxygxVK19fX1hZWWHChAkA
+gPj4eDYYJiqh0aNHw8TEBACQlJSEHTt2FDvN999/j+bNm2PkyJEsQIYZIqqLgaZJkyYAgOTkZCxY
+sKDQ8XR1dTFp0iT8+++/5X7PFy9eQF9fXzpo5Tlx4gQiIiIAANra2nB3dy/VfCdNmoSsrCyuvFQt
+UlNTsXPnTsyePRuzZ8+WXv/vf/+r1vlFVRBCQKlUlmm6kirL/IkKI5fL8fHHH0vP165dC4VCUej4
+KSkp+PHHHzF58mTo6elV2Lpd1m2nPNNyW2KYIWKgKaP8N9Fdv349Pv744wKrfwGAj48PbG1ty/V+
+SqWy0J7ifvzxR+mxra0tjIyMSjVvIyMj7Ny5kysuVQt/f3/I5XKMHTsWlpaWsLa2BgBER0fj7Nmz
+RU67f/9+jB8/Hi4uLnBxcVGpbpOUlIS5c+di+PDh0vBXr2rmd+zYMQwcOBCvvfYaOnTogJ49e+LA
+gQNFvn9KSgp++OEHDB48GOvWrSvyRC0wMBDDhw+Hqakp2rdvj8aNG6N///7w8/MrtB0cUUlNnTpV
+6j757t27Uk9lhR0z0tLSMH369HKv22XddgAgOzsbvr6+sLa2hr6+PnR0dNC1a1f4+PgU+gMbt6XS
+p0Qi9mZWCb2c1YbezOLi4sRrr72m0ouMhYWFCA8PL9V8tLW1penv3r1b6HghISHCxMSkwGGtWrWS
+5uHp6cmNgr2Z1RhKpVJ07dpVeHl5Sa/5+/tL63NJepK6d++ekMvlAoAYPHiw2vDo6GhpOytofgqF
+QsyePVvI5XKxZcsWqfe/6OhoYWFhIRo1aqTWI1N0dLQYO3as0NfXl5b1m2++KXD50tPTxejRo4We
+np7YvXu3yMnJEUIIcfv2bdG3b18BQPTo0aNSejRib2a1vzez/D7//HNpfezbt2+h21zPnj1Fv379
+ChxemnW7LNtOnqdPn4o+ffqI6dOni8jISPHo0SNx6NAh0aJFC2n509LSauW2VJW9mTHMEMNMJQWa
+2hBmhBDi999/F82bN1cJNADExIkTxcOHD0sdZg4ePChCQ0NV/n799VexZcsW0a5duwLDTHJyssp7
+r1mzhhsFw0yNcfbsWSGTyVSCfGZmptS9OABx8+bNYudjampaaJgRQggTE5NCw8yiRYsK3XYeP34s
+GjRooHZClpqaKjIzM8Xu3buLPOFTKpVi7NixAkCB301KSoro3LmzACA6deokUlJSGGYYZsrswYMH
+UrAHIMLCwtTGuXLligAg/P39C5xHSdftsm47Qry8fUGfPn3EqFGjhFKpVBm2f/9+6X29vb1r5bZU
+lWGG1cyIWOWsSD179sS1a9fUuq3cs2cPOnfujG3btpWqHr2bmxtsbW1V/vr37w93d3fcu3evwGni
+4uJUnjds2JArHdUYGzduhIuLC9q1aye9pqenh5kzZ6pU4yyOXC4v0/C//voLK1euhKGhYYG9Or32
+2msYMGCA2usNGjSAnp4e7O3ti3zfoKAg7N+/H02bNsXUqVPVhjds2BA+Pj4AgFu3buE///kPVwoq
+s9atW2PcuHHS8++++05tnK1bt6Jp06Z45513CpxHSdftsm47ALBz505cvXoVc+bMUesEZ/jw4dKt
+DrZu3Yrc3FxuS+XAMENUSYHm6tWrteaztW3bFmfOnMG+ffvwxhtvSK+npqZi5syZRd4X5lU3b95E
+RkaG9Jeeno6kpCRcvXoVffv2LdE8imr0SaRJYmNjcfjwYZVG/3lmzpwpddO8a9cuJCQkVMoyrFu3
+DgqFAgMHDoSurm6B4zRq1KjQ6V+9h9Or8u6XY2VlVej8hw0bBmNjY7WTN6Ky+OSTT6THP//8M2Jj
+Y6XnycnJ+OmnnzBx4kSVe6OVZd0uz7bj5+cH4GX30Bs3blT58/PzQ7NmzQAACQkJuHHjBrclhhki
+zQs0RfX+VVM/29ixY3Hjxg0sXbpU5VfgPXv2YPLkySW6QqOnpwd9fX3pr169emjcuDF69+6NzZs3
+FzhN06ZNVZ6/eqWGSFNt2bIFb7zxhkpnGnlatWoFNzc3AC9v6Lp9+/YKf38hhNRIunPnzhU+f6VS
+iQsXLgAAmjdvXuh42tra6N+/P4CXXVJHR0dz5aAy69WrFxwcHKR1MP+VzZI0/K/sbSc5ORnXrl2D
+trY2njx5gpiYGLW/MWPGwNPTE56entDS0uK2VA5ybhJElRNoHj9+XKKeTmoaPT09LF68GEOGDMGI
+ESPw9OlTAMBPP/2EUaNGYcyYMWWed7du3dCqVSu115s0aQJjY2M8f/4cABATE8MVjTReRkYG/Pz8
+oFAoCr1LeHx8vPR4w4YNmDdvXrHVyUrjxYsX0jZa1NWXsoqPj5duXljcL8SdOnWSHj98+BA9evTg
+SkJl9umnn0on/35+fliyZAkaNWqErVu3wtbWFt26dau2befu3btSN8xr1qyRrsAW937clhhmiDQq
+0MyZM6dGh5nU1FQ0aNCg0BteWllZITg4GLa2ttKVEl9f33KFGZlMht9++63AYXZ2djh48CAAIDQ0
+lCsZDE9QJwAAGAdJREFUabyAgACkpqbCx8enyLuEr1ixAk+fPsWDBw9w6NChcm1Dr8p/FTMzM7PC
+P2P+Kp95J36FMTQ0lB6X5OSOqCjDhg1Dp06dcOvWLaSkpGD79u2wt7fH9evXK6Qb/vJsO3mhRAiB
++/fvl+gGz9yWGGaINDLQ1GTu7u6YNWsW3nrrrULH6dChA3x8fPDhhx8CAP74448KXYaHDx/CyMgI
+enp6GDt2rBRm7ty5g6ioKJibm3NFI40khMCGDRswZswYzJ07t8hx4+Pj8dVXXwF4eRPNigwz+W8W
++Pfff1f452zevDl0dHSQk5OD6OhoCCEK3fflv/Ff/rZ3RGWhpaWFTz75ROpIY926dYiMjETjxo0r
+ZBsqz7ZTv3596XFISEiJwgy3pXKsC9wciKiwoLJ8+fJix8t/o8yS3GW5pJKSkmBpaSldbndzc1M5
+IBTUgw2Rprh48SIiIiJKVG9/5syZUkPkS5cuITw8vMwB6lWtW7eW5n3hwoVS9TxYEnK5XLoBaFxc
+nNSQuSBPnjwB8LKtUMeOHbmSULlNnDhRal9y//597N69GxMmTECDBg3KPe/ybDumpqZSEPHz8yty
+2ryOdLgtMcwQUSWEmaCgoCLvsAy8bBeQx8bGpsQnWcVZtGgROnfuLB2UdHR0sGnTJmn4rl27cPr0
+6RLPLzExEa6urnj27Bm/XKp0q1evhpmZWbFdvwJAy5YtMXr0aOn52rVrCxwvrzpJenp6gdtYSkqK
+2ut6enpSY+G7d+8iKCioyG20oG21uO33gw8+kB4HBAQUOl5eSHN3d6/xV65JM9SrVw+zZs1Sea00
+Df+LWrfLs+00atRICibBwcHYs2dPgdPm5uZiypQpcHJy4rbEMENElRFm8nauRf1ClL9dUP7uMvNk
+ZmaqXBIv7sQor3rOhg0b1HqAGjp0KNasWSM9d3NzQ2BgYLGfJTQ0FJaWlujXrx9atGjBL5cq1ZUr
+VxAUFIQxY8aU+ETjvffeU9mmCqrWkndl8vLly7h9+7b0ukKhwIoVK6SQk79TAQCYN2+e9NjDwwMP
+Hz5UC/ohISEAXvbClJqaqjI8f7frBTVMnjRpEiwtLQEAmzdvRmJioto4t2/fRnBwMMzMzFSWh6i8
+Zs2aJdUK6NOnDywsLEo8bXHrdnm2HU9PT+nxtGnTsH79emRlZUmv3blzBy4uLsjOzpZ6NeS2xDBD
+RJUQZhISEmBnZ4effvpJpYGiUqnEjh07pBt4LV++vMBfoV8NGzt27EBYWBhiYmJw79493L17Fzdv
+3sTFixexadMm2NvbS20MBg4cqDa/Tz75BPv27UOzZs2QmpoKV1dXuLm54eTJkyq/WKempiIoKAjv
+vPMOXFxcsGzZMnz++ef8YqlSZWZmSr8Ul6ZXsvw31FQoFJg3b57KjwB5PywAQHZ2Nuzs7ODl5QVv
+b2+Ym5tDCCF1VRsWFob3338fx44dA/CyobSHhweAl1VxevXqhRUrViAwMBDbtm2Do6MjDAwMpBO6
+7t27q9zQM/+PGbdu3VJbdrlcjkOHDqFTp06Ij4/HhAkTpAbQefuQiRMnok2bNggMDKyQKkBEeVq0
+aIGJEycCAGbMmFGqaYtbt8uz7YwbN066uWdOTg48PT3RvHlz9OjRA6ampjAzM0NSUhL8/f2lHz24
+LZWRIKoBDAwMxN69e2vUMgcHBwsAIjExsUaWuVKpFAYGBmLJkiXCy8tLmJmZiRYtWoghQ4YIV1dX
+0bZtWwFAmJqaip9//lltej8/PzFgwAChra0tAJT6z8DAQOTm5ha6fHFxcWLJkiXScgAQMplMGBoa
+imbNmgkAok2bNmLRokUiLi6uVm4X5ubmwtfXt07tC9q2bauxn3n//v2ic+fO0vool8vFqFGjxPHj
+xwud5q+//hKTJ08W7dq1U9sGevfuLX755ReVbXLp0qVCLpdL4zRr1kxs27ZNCCGEs7OzaN++vfD2
+9hahoaEq249CoRDffPONaNq0qcp7mJiYiHPnzon33/9/7d1/dNV1/cDxF9vdxgZzTn4VET/q2DIC
+A9EgEaxOBxI9kOmRUA6dOqEQET+UMDrQOXKC6mQHS4qAlHM8mgdPHTMMzBN4GHFU1CUJyVkonFJ+
+jDMYsrGN7dMfftnXxa8pG9y7PR5/7W73fnbv+3Mv7LnPfX12e9KtW7dk2rRpyebNm5OGhoZk06ZN
+yYwZM5Lu3bs3e41NnDgxeeyxx055LEeOHElmz56dFBYWJr17906mTp2afOMb30j69euX3HXXXRnx
+Opw/f34ycuTIDvWamj9/fjJu3LiMfgw7duxICgsLk6qqqhZd//08tz/Ia+ek+vr6ZNGiRUlhYeEp
+/7/94Ac/SGpqak57/9rDa+mkV199NYmIZM+ePa2+7T/96U9JUVFR0ilp7WlAaAOXXnppLF++vNlb
+MdJdaWlpXHfddXH48OGm39xkmqeffjpuuOGGk7/4iF27dkVZWVkcOnQo8vPzY9CgQTF06NCznnb2
+AvxCJnbt2hX/+Mc/oqKiIhobG6Nnz54xcODAKCkpadfvJx48eHBMmzat6TeHHUG/fv1i/vz5Heox
+/6+DBw9GWVlZ5Ofnx7Bhw5r+yvnu3bujf//+Z3091tbWRllZWVRUVETPnj1jyJAhkUqlory8PPr1
+63fOv4jeErW1tfH3v/89Kioqori4OK688spmZ3dKZ/fee2+UlpbG5s2bO8zz6d57743t27e36C27
+6ezll1+OoUOHttn2z+e1U1NTE2VlZVFZWRk9evSIwYMHt+iEOZn8Wjpp+/btMXjw4NizZ0/07du3
+Vbe9bt26uP32252aGTizkyET8e6ppktKSpr9sa50kK73C9pKjx49Tpkni2jZKVrz8vKaBpPf6+Tb
+SltDXl5eXHPNNXYUF1Rbhsz5vnby8/ObnfnTa6l1mZkBAADEDAAAgJgBAAAQMwAAgJgBAAAQMwAA
+AGIGAAAQMwAAAGIGAABAzAAAAIgZAABAzAAAAIgZAAAAMQMAAIgZAAAAMQMAACBmAAAAMQMAACBm
+AAAAxAwAAICYAQAAxAwAAICYAQAAEDMAAICYAQAAEDMAAABiBgAAEDMAAABiBgAAQMwAAACIGQAA
+QMwAAACIGQAAADEDAACIGQAAgDSTsgTQttauXRtFRUUWgla3ffv2DveYKyoqYu3atdG9e/cO85gb
+Ghri+PHj0aVLF096/163iXXr1sXatWs9AVqguro68vPzo1OnThYjTf6fEjPQVi+u1Lsvr9mzZ0dO
+To4FoU3k5eV1qMdbVFQUGzdujLKysg7zmOvq6qK6ujry8vKic+fOfohqQ5WVlTF69OgO9Zjz8/Mj
+IuLOO+/0BDiH2traqKmpiYKCgsjNzbUgLXDkyJGIiMjKars3g4kZaCPDhw+PJEksBLSit956q8M9
+5rq6uli1alUsXbo0qqqqYubMmTFr1qwoLi72hOC8LVy4MBYuXGghzmL9+vUxd+7c2Lt3b9x3330x
+Z86cpgjk4jMzAwBpLDc3N6ZPnx7l5eXxox/9KB566KEYMGBALFq0KCorKy0QtJHy8vIYP358jBs3
+LoYPHx67du2KBQsWCBkxAwCIGkhPhw8fjrvvvjsGDhwYVVVVsW3btli9enV8+MMftjhiBgAQNZB+
+Tpw4EcuXL4/LL7881q5dG2vWrImNGzfGkCFDLI6YAQBEDaSn9evXx5VXXhnf+973YtasWfHPf/4z
+Jk6caGHEDAAgaiA9mYsRMwCAqIGMYi5GzAAAogYyirkYMQMAiBrIOOZixAwAIGogo5iLETMAQDuN
+moULF4oa2iVzMWIGAGjnUfPwww+LGtoVczFiBgAQNZBxzMWIGQBA1IgaMkp5eXlMmDDBXIyYAQBE
+jaghM7x3LubIkSPmYsQMACBqRA3pzVwMYgYAEDVkHHMxiBkAQNSQUczFIGYAAFFDRjEXg5gBAFo9
+apYsWSJqaDPmYhAzAECbRc20adNEDW3CXAwt1SlJksQykPZP1E6dYvDgwTFp0iSLAZCGGhoa4sUX
+X4yNGzdGbW1tXHvttTFy5EjzDLwvhw4dinXr1sXOnTvjqquuijFjxkRhYaGF4RTr1q2LzZs3ixky
+wzXXXBNVVVXRtWtXiwGQxpIkiYqKiti3b180NDREz549o1evXpGdnW1xOGsMv/3223HgwIHo2rVr
+9OnTJwoKCiwMZ1RdXR1du3YVMwBA66urq4vVq1fHkiVLoqqqKmbOnBmzZ8+O4uJii0OTEydOxG9+
+85tYtGhRFBQUxI9//GNvJ+N9ETMAgKjhglu/fn3MnTs39u7dG/Pnz485c+Z4WyJiBgAQNaSv8vLy
+uPvuu+Opp56Kr3/967F48WKnWeYDczYzAKDNOfsZ/l4MbcGRGQDggnOkpuMwF4OYAQBEDRnHXAxi
+BgAQNWQUczFcKGZmAICLzkxN+2AuhgvNkRkAIO04UpNZzMUgZgAARE3GMReDmAEAEDUZxVwM6cDM
+DACQ9szUpA9zMaQTR2YAgIzjSM2FZy4GMQMAIGoyjrkYxAwAgKjJKOZiSHdmZgCAjGempnWZiyFT
+ODIDALQ7jtR8MP87F7N06dL42te+ZmEQMwAAoiZ9mYtBzAAAiJqMYi6GTGZmBgBo98zUnMpcDO2B
+IzMAQIfTHo/UvPnmm/Hmm2/G9ddff9brmYtBzAAAdPCoOXbsWDz77LMxfvz4i/44du3aFSUlJU2P
+KScn57TXMxdDe+NtZgBAh3U+bz/75S9/GRMmTIilS5de1Mewc+fOuPbaayM7OzuysrLigQceOOU6
+5eXlMWHChBg3blwMHz48du3aFQsWLBAyZDxHZgAA/k9Lj9QcO3YsPvrRj0ZlZWVkZ2fHlClTYsWK
+FZFKpS7o/S0rK4svfOELcfTo0Thx4kRERHTp0iXeeOON6NGjRxw+fDgWL14cv/jFL+Jzn/tc3H//
+/TFkyBA7GjEDANBRo+anP/1pLFiwIOrr6yMiIicnJ0aOHBl/+MMfoqio6ILcx5deeik+//nPR3V1
+dTQ0NDR9Pjc3NyZNmhRXX321uRjEDACAqPn/qLnzzjtj0KBBp7wNLTc3NwYMGBDPPPNM9O3bt03v
+15YtW2LMmDFx/PjxZiHzXgUFBfH973/fXAxiBgBA1LwbNQcPHoz6+vrTRkROTk5ccsklsWHDhrjq
+qqva5L5s2rQpvvzlL0ddXV00Njae9jpZWVkxZMiQ2LZtm52HmAEAIKKysjL69OkT1dXVZ7xOdnZ2
+pFKpePzxx1v9TGcbNmyI8ePHR319/RlD5r1B87vf/S5uvfVWO452y9nMAABaaNWqVU1zMmfS0NAQ
+dXV1cfPNN8eyZcta7Xs/9dRTceONN571iMx7JUkS3/3ud+P48eN2HGIGAKAjO3bsWCxZsuScMXMy
+JBobG2POnDnx7W9/+4xzLS31xBNPxM033xwnTpyIlr6pJkmSePvtty/6qaNBzAAAXGTLli2Lo0eP
+vq/bNDY2xsqVK+Omm26Kd9555wN930ceeSRuu+229xVEeXl50alTp4iIeO2118JUAe2VmRkAgHOo
+qamJgoKCiHj3rGV1dXXv6/a5ubnxiU98IjZs2BC9e/du8e1Wr14dU6dObdF8TCqVirq6uhgwYEBM
+mDAhxo4dG6NGjYrOnTvbgYgZAICObN++fbF169bYunVrPPfcc1FWVhZ1dXWRl5fXooH8nJycKC4u
+jmeffTYGDRp0zu/34IMPxne+850zHlXJy8uLurq6yM3NjS9+8Ytx0003xdixY6N///52FmIGAIAz
+q6+vj5dffjmef/75+Nvf/habNm2K/fv3RyqViuzs7KitrT3lNllZWZGXlxe///3vY+zYsWfc9s9+
+9rOYN29es0By9AXEDABAm/nPf/4TL7zwQmzZsiU2bdoUr776atTX10fnzp2jtra22VGWX/3qV3HX
+XXedso377rsvFi5cGBHvnua5sbHR0RcQMwAAF1ZdXV288sorsXXr1ti8eXOUlpbGgQMHmr7+pS99
+KdavXx9ZWe+ek2natGnx61//OiIi+vfvH1/5ylccfQExAwBcKPv27Ys//vGPFuIMDh8+HP/617/i
+6aefjoaGhujbt2/ccccdsX79+vj3v/8dH/rQh2L06NHRrVs3i3UWI0eOjE996lMWQsyIGQCg9ZSW
+lsZ1110XvXr1ii5duliQczj5N2mysrKaTqfM2e3evTuWL18e06ZNsxgdXMoSAABt4fXXX4+ioiIL
+QasbPHiwRSAi/NFMAABAzAAAAIgZAAAAMQMAAIgZAAAAMQMAACBmAAAAMQMAACBmAAAAxAwAAICY
+AQAAxAwAAICYAQAAEDMAAICYAQAAEDMAAABiBgAAEDMAAABiBgAAQMwAAACIGQAAQMwAAACIGQAA
+ADEDAACIGQAAADEDAAAgZgAAADEDAAAgZgAAAMQMAACAmAEAANqBlCUAADh/VVVVsXfv3vP7wSyV
+ik9+8pOxf//+OHjw4BmvV1xcHB/5yEdO+XySJPHaa6+d9jYDBgyILl262FGIGQAAmvvLX/4St9xy
+y3lto2fPnrF///7YvXt3rFy5Mh5++OFIkqTp6yUlJTFx4sQYNWrUGWPmz3/+c2zZsiWefPLJiIgo
+KiqK6dOnx4wZM8QMYgYAgFPV1NRERETv3r1jwYIF8dnPfjYuu+yySKVSUVpaGpMmTYqIiI997GPx
+3HPPRZIkcfz48XjrrbfiySefjGXLljVtY8SIETFixIi44oorYt68eU3f44c//GFMnDjxjPchKysr
+7rnnnrjnnnti4MCBsWPHjnj88cdjzJgxdhBiBgCA06uuro6cnJz461//GiUlJc2+1qNHj6aPc3Jy
+ok+fPk2XL7/88hg9enRceumlsXjx4ma3mz17djz00EOxc+fOiIgoLS09a8yclCRJVFRUxMiRI4UM
+7ZoTAAAAtIKampoYP378KSHTUjNmzIjGxsZoaGho+lwqlYqFCxc2XX7kkUfi2LFj59zWCy+8EAcO
+HIgZM2bYMYgZAADOHTPjxo37wLe/7LLLYtiwYXH8+PFmn7/llluiX79+ERFx5MiR+O1vf3vOba1e
+vTq6d+8eEyZMsGMQMwAAnN28efNiypQp57WNLVu2REFBQbPPpVKpmDVrVtPln//8582O3vyvo0eP
+xqOPPhpTpkyJvLw8OwYxAwDAOX6oysqKTp06ndc2srOzT7uNb37zm1FUVBQREW+88UbTmcpO59FH
+H41jx47Ft771LTsFMQMAwMVVWFgYU6dObbp8//33n/Z6SZLEihUrYtSoUR94dgfEDAAArWrmzJmR
+Sr17ItotW7bE888/f8p1XnrppXjllVeahQ+IGQAALqo+ffrEbbfd1nT5dEdnVqxYEcXFxfHVr37V
+giFmAABIH3PmzGn6+Iknnog9e/Y0Xa6qqorHHnssJk+eHJ07d7ZYiBkAANLH0KFD4/rrr4+IiMbG
+xnjggQeavmbwHzEDAEBamzt3btPHK1eujKqqqqbB/xEjRsSnP/1pi4SYAQAg/dxwww1NZyo7evRo
+rFq1KrZt2xZlZWUG/xEzAACk8Q9vWVnNZmeWLVsWDz74YFxyySVx6623WiDEDAAA6Wvy5MnRvXv3
+iIjYu3dvrFmzJu64447o0qWLxUHMAADQehobG1t1e/n5+TF9+vRmnzP4j5gBAKDVvfPOO00f19TU
+tMo2p0+fHnl5eRERMWzYsPjMZz5joREzAAC0rmeeeabp471798aOHTvOe5u9evWKyZMnR0QY/EfM
+AADQeg4dOhRTpkyJIUOGxIoVK5p97eqrr44bb7wxfvKTn5zX95gzZ04UFhbGxIkTLTgdUsoSAAC0
+vm7dusWaNWva9HtcccUVsWnTpigsLLTgdEiOzAAAZLChQ4daBMQMAACAmAEAABAzAAAAYgYAABAz
+AAAAYgYAAEDMAAAAYgYAAEDMAAAAiBkAAEDMAAAAiBkAAAAxAwAAIGYAAAAxAwAAIGYAAADEDAAA
+IGYAAADEDAAAgJgBAADEjCUAAADEDAAAgJgBAAAQMwAAgJgBAAAQMwAAAGIGAAAQMwAAAGIGAABA
+zAAAAIgZAABAzAAAAIgZAAAAMQMAAIgZAACA9JCyBABAW+jVq1cUFBRYCFpdZWWlRSAiIjolSZJY
+BgCgtVRUVMTGjRstBG1q6NCh8fGPf9xCiBkxAwAAZB4zMwAAQEZKvb79xaYLJYOutiIAAEBGcGQG
+AADISP8FpxZnWS0U37cAAAAASUVORK5CYII=
diff --git a/Documentation/DocBook/media/fieldseq_bt.gif.b64 b/Documentation/DocBook/media/fieldseq_bt.gif.b64
new file mode 100644 (file)
index 0000000..b5b557b
--- /dev/null
@@ -0,0 +1,447 @@
+R0lGODlhcwKfAucAAAAAAElJDK+vr0gSElYMDC8kDV5bEBcHOwYGSEQODmEaGgoKOBkTVC0tVyAg
+aDcJC6Ojoys8DAAYGqSkxV9fFFtdEJmZmUA4EF0wMAAAcAoTHTZHJ0gYGAcMTwcSO29ISFUHB2AV
+FXd3YAcHMRUVQiIAGg4HT3t7eywOJ3d3dwcHSEEgABMuDnd3OGpkSQAAYlZGBzEEBGJlDCstCxwc
+WQcHSzkRGWBtYC0AACA3ABAKNhAQTTMwDA0VQD4AAEYVFVVVVSQMJQULOB8fQScnYBgYRD5VPmZm
+DEZRB2ZiDAoKSgAAVAwQOH5+lBwcS+7u7hoaST4+X3d3WACPADMzMyBRIDgAAGBgc0JCEHEAAEwN
+DRkwDAoKOR8kPZR7eyA1IABpABgNQBA9EABVAAsLRww/DAwMPgBNAENDCgc9B8zMzAUFQQBDAD4M
+DAwOKgAAcQA5AEtLFYqKAA0NTC8HBxEREQgfCAArAAApACIqMkkGBhoqKnwAAAsGQ6qqqkoKCg4O
+MlkcHAoZJCcrW6SkpFQAAAAAOBAOSwAVGh0ROgMPHWZmB00QEGUAAFQaGjEyC2w4OLe3n4qKioiI
+iBAVMC4uXhkZUGIAAHJYWHd3AAAAPhAQUQUGL0BAIGggIBgAGkIVFV9fEAwcJR8KJA8MU9EAAAcH
+VRoaYWhoaDcAALu7AGZmZnAAAGRkZGQVFVhqWD4KCgwOUzMzDAAAmgklBzEHBzExClhYWBMTPAYJ
+Qy8fCFpaB///////ACISRExUDUQrDAwMVhISSEYYGHd3IDhcOERERElJAAkPNTsHF1hYckgGBj05
+CFYAADg4OCAVO0hCDDAwMLu7ilpaDR8qCDg+EBxGHN3d3REGNjo9CDQ8DBwYRGZmHFMAABQ+FBE+
+ESIiIhs+BxU0FWVeBw04DYqKsxAsEB8hQAwuDAc2BwwqDAoqCgcIL1dMDQAA0Q0iDQwiDAckBxAQ
+EDwAAAAAU0JCDAkJPru7u5oAADg4bAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAALwALAAAAABzAp8C
+AAj+AHkJHEiwoMGDCBMqXMiwocOHECNKnEixosWLGDNq3Mixo8ePIEOKHEmypMmTKFOqXMmypcuX
+MGPKnEmzps2bOHPq3Mkz5z0AQIMCSNHyZ0WjE5GqNAZAqcGmT+8VZMoL6k6rEp0KfEJl489VBcEB
+GGjBwk8LBJsyFQqU15MUdQDUWfVk4JNVccER5ZXCT8+/gAN/xFp0LEWtDxEfRKo44s8n1/YeJCyQ
+8GO+1xhSbvwxRWaklBEiXoVW4886BNW0FQjkyem6laUKdLqKSuZrQIxtpbLqc51JbsHBFkw8pYUT
+w4uHDK2SM0PnCqHPNiz9uWGFoS1fb7h5u0nQshf+ar2G2isAKn4FpqByHQivn8YkY3WK9RoANXx1
+kwUncBVw5QCSdAsA8jiDXIAeEQYXAMbgp0YKKQAFYVxEPbjgXm/FBURmD1pQxz1qsDfUdAVlCMCG
+vFg4lhpMgbOKYX6IBY5fHX642FBx0cULbnKlUFdQkgS1IxA91mWMBWJRYQF7dZQ2HVBIsdhjbG4R
+WUeE4f3UFlQN6hUiUK1puV1Q93Sp24LglNYlAGmmKGJrvBxJ4YWxiUkmLzGymZ6ULnqXAlgC5Tmj
+QRE2qd+NkwDKCziTwAjcT6rhV1WW28013D11UfHfVrItieCnHw0YVIEHgnoRVutllgJ/X+F54hP+
+fjT1FWR68WXbXV3dU4cxmBoDnGpSaZUqru/NJRUVrV3DXrHBAnCNrrwmN9Cs17jIC2+QUUEUY4Zh
+qyxR52X2IlFwFWSUUU/8tmObXBrzxBNEhveeYVCd5wd5RD1Ra3eVzajGPeCoSq8x4qJ2ZXDghvlq
+rFJBBR6z82aGbLbe+TqbjT9lNtCq4npHUMblqQEOUr3Nmx+VJJIVl7aSToqQan/ZydbMNNds8804
+56zzzjzXbGpFWA0q0IdKWSWrswIhyUuTAtn3L9IE2ddsQUzveF/GKUJtwVirSAZECliLpnUdqmns
+ockml500agCkx625YxnlqUCT6NaU2lbL+zD+AKXNpTHK09Lr5MaCk+h3WrIZ3fDULnc90Nd4b12Q
+VY6zJtmiTnoc+LV+QYiUfuiyS6lB96wHAKDMAa5TZBC27vrrsMcu++y012777bjDHg3N4Dgj7c8P
+YTXzPUUnTvx1Rgl/PFlUgBMv2gMp/zaJawUFtuabT6fUudTFjfxYVk2/uVERCmX38tHrTe/iTa8C
+Th1A4MevyykCsStV9Bt1jfvwy288lQ5bX5zYcr3spU8g1ZMQ4gbCH7HxIlGLetp7/sOYOjxhPthz
+FX40VRDPqA54IISIqAhkoN+F0CFBkxf0FBe2s1XNaVG6D5W08sKrGcY+ZuPa5aB3I7OBI3L+qHkb
+EPPXPbiZzAKHSh8Om6YdAKowQ/TLnlUOhrbwbQeKinNiFaVSuYEskReSI4iNeNFFg1StKgnRH9lY
+NZYUSEopX8NgWpIDlVURJFawSd0J92iQW5DKhHzkTnhS9UALFq9Op6MVuW5VG7RF6oFt46GtrkEs
+pRgjWcvSVbCIhrwdUqtW3tLWvOqClFCCSzbiIxG61PUtlxnDXfBqosusAgQ42TGSHwPAj2TDSqbs
+kkS1rMst/zdLxjkMYza6JMWmshdNQqx0fAkYGanjyW6J0iiHUkq65DiQV2aGWMFB0T1EmbVAmjMh
+lDwnRRS0MvwcclI/WZCOTAQnpSwoPgD+mIRW6EnK6zyBKYZKmozQYk/vqIiKPEKoWNRAHtQkdC9W
+TNn4DPMlKkIllldyYy61mKK1UAE/AI3aQq2CJDbBhW2oXJFH/YeyekmlodeSYUnb5BaAIrEgk3CP
+QNlUmgi55UVNMoxPNwpJd95HMk5p1Ojsghe5lGwrTa1V0nSqzqpadSXVmckOr7rHdAEyNbDRVU+A
+MDiumvWsHclqTO6xKbSeMAVlPcgqWgMvReWkWm7Nq14tota9+vUjb2FILF/FE7P89bCITaxiF8vY
+xjr2sZCNrGQnS9nKWvaymM2sZjfL2c569rOgDa1oR1uSfxHvtKhNrWpXy9rWuva1sI3+7WkBaVrZ
+2va2uM0tbNOo29769re7FQ1wh0vc3/K2uMhNbnAN4hrlOve5p21ZQvIxi+pa97rYza52t8vd7nr3
+u+CtbgZUOBBP4OO86E2vetfL3va6973wja98z1uIhHBDFfjNr373y9/++ve/AA6wgAeMX24kxBpg
+SLCCF8zgBjv4wRCOsIQnTOEEWyMhSwivhjfM4Q6DlwaiYcV8R0ziEptYvp5gSD7cweIWu/jFMI6x
+jGdM4xrb+MYsngV5BeKJUvj4x0AOspCHTOQiG/nISE6yjy+REGL04slQjrKUp0zlKlv5yljOspaf
+TIyEVGEKYA6zmMdM5jKb+cxoTrP+mtcM5iok5AU4jrOc50znGztANPhQsp73zOc+JznFC1lxnQdN
+6ELTWMcI6bGfF83oRhuZyQhx8pYnTelKWzrLXUbIl9nM6U57+tNqdjNC4GzoUpt60HdeTJ4dzepW
+LxrQChH0qWdN60PvmBeKdrWud/3oJl/618AONpYzfZBNg/rYyE72mUV9EFLX+tnQdkeqSbdqXlv7
+2qWAdULOYYZue/vb4A63uMdN7nKb+9zo7jYXIIAQDhDg3fCOt7znTe962/ve+M63vt9di4TI4ggA
+D7jAB07wghv84AhPuMIXDnBZJOQd6Ii4xCdO8Ypb/OIYz7jGN87xiL8jIexIt8j+R07ykqPbDQiB
+wB/2zfKWu/zl+uaAiqNNc1oj+iC5xrbOWw3pg0ha2EAP+qWJbRBjK/voSP80sw3i7Jo7ndDTNle1
+d051RmsbIbJ+utbnfHOD5LzqYN9zzw3yc6Gb/exWJnpBjJ70trvdzEsvSNO3TncbR/1jUw+73pF8
+9YNkve6Al3HXC/L1vRt+yGMvSNnRznjGq50gbH+75N8ed4LMPfCYb/Hdp5X3w3v+x303yN8zn/nB
+E6Twn/d84gmy+Ma7PuiPH0jkJ0/7o1d+IJcnfeA3P5vOp/7woS/IEOZA/OIb//jIT77yl8/85jv/
++cUnBEJ+oIXqW//62M++9rf+z/3ue//74K8+LBKChWmY//zoT7/618/+9rv//fCPv/mxkBBzkOP+
++M+//vfP//77//8AGIACeH/mkBD2AH0ImIAKuIDPxwQIQQjhF4ESOIEUGH4/MHO6p3umV16/14Gr
+NxCt93oi+GuxJxCzV3soCGq3JxC5l4F0x3vv4XsdqHfBRxCj54J0t4E8NoOp94ECEYIjGISTVoK8
+cIIpeIRstoK80II4+HQweA8yyINVV4MDcYNN+HQ6iGtSqHq+JoReWGlEaIRIOIbL9mZXuHt4toXA
+h4FnmIO3hnpquHM+yAtA+IV2OGVhSIZ6mIRm2IYvmIZxSIMMAQUvUIiGeIj+iJiIiriIjNiIjviI
+kFiIS8BuB5EA83CJmJiJmriJnNiJnviJoBiKoniJOJAQ2ZAJqJiKqriKrNiKrviKsBiLsjiLqJgN
+CREPbJCLuriLvNiLvviLwBiMwjiMxJiL8ZAQhhCJyriMzNiMkDgCKZcKoziN1FiN1iiKCcCGfoiF
+bxiIejeHdXiH4tgLebiH5liGo7aNW/eEUeiNvEaFAmGF6lhrWQiH7shr4DiO+oiHXnaO/khmSsiE
+8zhr7HiPU6iNAwlt9WiQVJeP+/iQ5NiP/ziRUxCQCVlzBcmQOgePvEAEHvaRIBmS3pUBAoAQrsAH
+KJmSKrmSLNmSLvmSMBn+kzI5kyjZDAkRCgSWkzq5kzw5YKGQEGJQYUI5lERZlBQmBhgmkkq5lCC5
+CQghAI1Ak1I5lVRZlTPpCgzRAG+wlVzZlV75lWAZlmI5lmRZlma5lfRQkgehACfWlm75lvBVXwgR
+B3JQl3Z5l3iZl3q5l3zZl375l4BZl3GQEOJwBoZ5mIiZmIq5mIzZmI75mJAZmYYpDgmhCWd5mZiZ
+mZppliTwlCIGl6AZmm2pAAh5kTbXjRqJbQ4JkfpYjhTpjxZpmtCWkalpbRwpj7JZaAtZm9a2mqwp
+jq75muYYm7lJa7TJm7p2m8VJj6iJnLrmm79ph8EpnHpInMtpasfpnKz+xpFOUAPe+Z3gGZ7iOZ7k
+WZ7meZ7omZ7eqQKUaBADAALwGZ/yOZ/0WZ/2eZ/4mZ/6uZ/wGQMJgQa7EKACOqAEWqAGeqAImqAK
+uqAMGqBokBDrkA4SOqEUWqEWeqEYmqEauqEc2qESug4JsQbqOaIkWqImmp4LkHJ6wJ8s2qIu+qL7
+OQCleZ2EtpvayXNdGJ13OJ3UOYbWSaOFlp03anUzCqR0ZqND2mjQqaNCyKM9eoQ/aqR1JqRJ2mfK
+KaW62ZxVumhLyqQj6KRPioJRiqVyRqVbqmdXSqZ1hqRnymdd6qWvB6ZhSntjqqZ2BohtaqUM0Z0n
+2qd++qfmyZ4I8Z7+MFqohnqo+OmfCAGgDdqojvqokLqgD4oQEeqhlnqpmJqpHAqiCCGigPqpoNqn
+KXoQELCiiHqqqFqoMhpodrqmWpqnevamcNp4cjqnklenrUpjZgqrRpamuYpjbMqrSCars4p2tWqr
+boervxpjuyqsQ+ary1pjweqsRUasxWp2x4qsSaes0epizUqtQMaRWrmZ5Fqu5jqWaYkQbCma7Nqu
+cZkQdBmY8jqv9FqvfzmYCFGYkrmv/Nqv/gqZlIkQlnmuBFuw5NqZByEAn+muDNuw+ECaC+GRTDmx
+FDuSamkQJ2mVGruxHAuTNokQONmTIjuyJAtgP4kQQWmUKruyLBv+YUiJEBlWsTI7s9XllAkblR2b
+szqrsVjJqt1qY9MKrkJmrdcKexKprWLahz+rq3gqtEUGrUsLY0HrtD9GtEUrbNmKtMrGrUv7rU4L
+tVHrYlNLtaVgtVcLbFmrtcjGtT/rtULLkVHgAHI7t3Rbt3Z7t3ibt3q7t3zbt3JLA7eGAZ4wuIRb
+uIZ7uIibuIq7uIzbuI47uKCQEJ1ADJRbuZZ7uZibuZq7uZzbuZ77uZTbCQnxBVVQuqZ7uqibuqq7
+uqzbuq77urBbul+QELjgt7Z7u7ibu317DqIRCI/7u8AbvMLruBhAWsZ7vMibvMq7vMzbvM77vNAb
+vdI7vdRbvdb+e73Ym73au73c273e+73gG77iO77kW77me77om77qy1VnBEblsRXNlEGawRa6ARr0
+K0nzEhRCcxDlwxZScRdxYSnRIxRwsr4GfMAPkQJUxQtAYFdDhRhqQCSEhRCh8TBGdMHumx5ptB3k
+gSK4UQcaYxXKssAIXMImPBCqARsXpMF+EBcSxUB0wRVJNDnkZcFEdcPRJB7bcUkFUUuAEysnHMRB
+TFMt7EVpUkRTEVYZVMEChMEGZDV/cyN2IUOpoUtRBMRCnMUHrMD9IRm+kkqE0kCTUcNNjMMvHEVS
+fMYcNcJa3Mbqm8JLIylcDMZ2ARe3VhVskTIzsy0eoxV6BD3+ilEv5vNVblzI3qskMXIx/aTGhUQw
+2EHGH4S/TvFFDrQVVIzCVvzHhrzJ3ptTldO/ZIIYq3LHB3TBTEw622FH0bHDJOzDaMzJsAy+9vFD
+qHzGFyRdCXHKryzJ1+EhGlzJTQM/t2E/IUzKsXzM19s8aSwzvDIzuQzJeJzHzJy/QLG/G1wiTXU4
+kYzM3NzN3vzN4BzO4jzOZpUCr3TOr4TLH4FE6PxKcUXO8BzP8jzP9FzP9nzP+JzP+rzP/NzP/vzP
+AP1YuTPQBF3QBn3QUexXrHPQDN3QDk3QCb1XpfPQFF3RFg0hjtUzGr3RHN3RPGPMZiUzHj3SJF3S
+NwPSXAX+yia90ixN0hm9VXr1Eyh9VTKdWDWNWEOF0/K7VyOCWDd9WD/9V0HtVzl9WEWtWD0N1Joc
+0kvNVUO9V0dN1DutV0ntBZhw1Vid1Vq91Vzd1V791WAd1mKN1YEz01b10zfwCmq91mzd1m791nAd
+13I913Rd12p9A2WdWDl9DWPd137914A91l5AOC/NgWRLZD331DGNFWKotlub1zrNeYdNZLAW1YiV
+1PZItond1DTN2I5Np5Bt1MjTjlRb2VOdV5g92YgX2kLt2Z99q6wt1ZKt2kFm2oW9g7QNZJtt1lX1
+04392ioY21A92rkdroTdWEnNCKm63Mytn8sg3IsdHur+oKnUXd3WvaHqAN15ldOE0Nze/d3yyQjH
+zVipXdxLpt1u5dvATXnojVY5DYXm7WO2jdySkdlUu9s27drrva3tfVbvTdpfO96LVd7mjd8+rd/7
+bXv9Xc7EHd/zTd71Hd9lu+BOjeAJnmzMptjb3eDm/eADLhmECt4inqqKOi+8rU4/XanXveIsrqmc
+auJ6fR2lOuI0fqqryhen7VYEXtwGrtTh8dsXvmYZztlW9d8S7uFIHeHx3eOt/eNBruDaE+Oz3eEC
+nuSGXeAU3tlO/uQYnuVFzuHFjeSJldTr6rBmLppyCeMHHh76+q9u/uZw3pgBq+aiPRAKe+Z4DpoQ
+i+P+t80LjpAFgB7ogj7ohF7ohn7oiJ7oir7ogO4DXt7bWOENLTvplL6y3vDo6pTTAtANjN7pnv7p
+oL7ojlDlY67kWB7lay57XN7lqF7nvXfkpH7Zps7jmH5O6r3qxzbkJ35ORu7gsX5YO57bTO5Xt47r
+Slfr5tTrVK4eOY5WST0MbRDt0j7t1F7t1n7t2J7t2r7t3B7tdIDsgfTT8FAG5F7u5n7u6J7u6r7u
+7N7u7v7u5A4P4M5HOQ0BD9Dt+J7v+r7v3D4Mv/5XwU7bwy7RFm7sfNjqf6XsYf7vfhXwqj3w0a3q
+Bu9pui7lr+7rzN7n9u20EJ9XxT7xB0/nCQ/muS3+5rJ+5bSO8MRe8CCPZhUf2Re/7HxO3wNBfRV4
+8zif8903fipP8OFhfwMY9EI/9EQfgAXY83rF3Tq/9Eyf8xeY8TSP26cu8iu/5S0v5PO+Rwpf8gzP
+07Mu7Fl/Qh9/9S4f9iG09bRt8sD+9QJv9iA09mQPd24PPGiv2moP8Gz/8HP/M3Af9wC596ZS95N9
+9w0vGe4Gc4if+Ip/b/2G9B6PFRDXcZI/+ZRf+Rv3cY7vVvW+covf+Z6P+DIH9RCO8mCf+WjV934v
+Zi/v6jEI66L/4aTf9qZ/Vqif+m0G+KAi+IdN+F4f+3o/+0xt9bb/98Cf0iSf9l1P1ZIRAnne/G3+
+meYant5Y8Q1jUP3Wf/3Yn/3av/3c3/3e//3gX/3fgPufoukL6/zoL18hkPyoLRl/HurwH//yj+iO
+XvxaPhCSXun6v/8Sdun2/+UAwUuggG5ZDB5EmFDhQoYNHT6EGNGgI4G8UgComFHjRo4dPX4EGVLk
+yIwAUlT0VErlSpYtXb6EGVPmTJo1VV6qeA/APZI9ff4E2lMnT4FVphxFmlTpUqZNnT6FGlXq0So5
+dwbFmlUryYs58dkEG1bs2JqeKnbdmlbt2oomUZKFG1fuTJwCh7LFm3fk3aJT/f4FHFhqVbtX9R5G
+nBEtr3tf5z6GDNeswMWJLSd2KzBlZM6d6Vr+JXpZtFq+vIwKRp1a9VPCjA2Php11cWPPtW2vnGwR
+Y2zeWzPzwuBJ+HDixY0fR55c+XLmzYWDAt1butDXX6pcx55d+3bu3b1/Bx9e/PUv0aefBzk7kHP2
+7d2/b47h7G709UH+tp/fdWj99kv3r+8/AM+rbEAC6TMwP/wS7E1ABmNz8MHRIpTwsgIrHO1CDGNb
+cEPLKPRQLxBDxGtEEtfS8MS8UlTxMABWuSdGGWeksUYbb8QxRx135DHHSV5rUUQAJumxSCOPRDLJ
+GH/kL0i8LlIySimnNHIVBJ1EDAAtt+SySy+/BDNMMccks0wzm8SSNDPXZLNNN9/0Es00t7r+CE47
+78TTzTkTo7JPP/+U8Yk92XoCUEMPRVLQQdW6BlFHH8VxUUknpbRSSy/FNFNNN+W0U08/BTVUUUcl
+tVRTT0U1VVVXZbVVV1+FNVZZZ6W1VltvxTVXXXfltdfD6rAgIwvqyOiJk1zDyktjkOVFWWYz0mlL
+cPz4qEsqQrtmlToAACcFQaPt8pYvj7WACi2pCFYgbjWyUk5f34V31xSAyAiIVRTbTaeN1ABCSyAU
+5QjIwtRFU1+NDOZlWGo7MuwJbQW9po5VruFFDSqo0EjgZvlbhYqF/aDi3mYBUCOjbd2NN2WVY1UD
+AEWfAGBhXvzYdmCNwFnliSeoWJbhgnf+0xhhqxQDx6PXYObJGHoreqLbktB8zQJwAOblCWCbpeLY
+mc1FeWWvv0YVnHRprugasfO9khdjFBU6458J3qjtZ3m5BgCKAw7Nap1J1mgSjNuCOjQqJtkoBYyH
+LFqgVZgEu3HHUZ1Xca2NIRLtj1JIHO+4gX774Cs1hrvqVaiVW2iNXwsao53AKZmXOuru+nHZZ6+0
+ZUHraD1yg+UWyNg6UPbSZi9PKv1zd50t/umNUH97pxROAnlj2qen/lJ0/Uj8njq+tXyjSeow5m6f
+Nw8d2rSFrlt8tyv6UQ2YW2f/7/IBr2hw7w+/R42iF5e+ev//T9Mk7HWsOnEpRmnDXOz++me++dmM
+gWfJ3PL4cxWlFctp9FufQIZFNasF6yqse90CAThCEmKobqwj39yqxreQpK6BKnyWwowWmu8JJGIT
+q9jFMqi8inTsYyGDm+H+BroSFtGI9qFCBIfmGi4ZA1xbmmEKv8TELS3ridOqFpeoAL9sbatbVBNh
+A8t1LsLBrWVlJOIR1bhGNrbRjW+EYxzlOMdQpcAYd8SjMeCHGAvkEY/pomMgBTlIQhbSkIdEZCIV
+uUhGNtKRj4RkJCU5SUpW0pKXxGR98rRJTnZyS1pD1RM9OUpSnmlVoixlKlXJJVgBwBjPg2UsZTlL
+WtbSlrfEZS51mcsOlUonq9hlMIX+OUxiFvN57Trli4y5TGY2M5jGSJuqelmqaY7KRKC65qey6SkW
+naqao/pmqLbZqXFyqpyb6qapwhmqdWozjaI6p6bimal0UlNryshHPvW5T37205//BGhABTpQguoT
+fu30VGlc0AKGNtShD4VoRCU6UYpW1KIXZagLzJOq0lSioB8FaUhFStAozKeVWsuHO1S6Upa21KUv
+hWlMZTpTmtZUpbMIDULJ+Rpi9MKnPwVqUIU6VKIW1ahHRWpSfUqMjYbyNS+waVSlOlWq1tQBJn3V
+b1JaVa521asyxWlbQHmq0vRUqWdFa1rVilSmFkaB7gwNVL86V7py9aqUiWaqtFr+V772laZhVddY
+TVXWtRbWsIc9alv3k8y4+tWxj13pXXVz0opsFbKXrStgmyVYX/IUsZ8FrWEVO09MlUaumEWtVyVb
+T1L9BgovgG1sZTtb2tbWtrfFbW51u1vYLgECYmVsRWxxDOIW17jHRW5ylbtc5jbXuc8lri2aStbX
+GIK318VudrW72xFg1VV7TW14q6pZnZrTs6FFb3oTO93BPlW875XqavOKKvDC175gzSlnSUVY9fbX
+v0tlb2cbe18Cv1S+lBWIZQu8YHeQV7/WPO9/JRza0b5TnO5lMIMPnFWtEWEWHwZxiEU8YhKX2MQn
+RnGKVfzhDAgAuKoqTShUMWP+GtfYxjfGcY51vGMe99jHMw5FgPf7miWs2MhHRnKSVbwJ77bqNw14
+Q5SlPGUqV9nKV8ZylrW8ZS5HmR4uDmxwBRIHOZTZzGdGc5rVvGY2t9nNb4ZzmeMgZAiHRhNdxnOe
+9bxnLpOgyayqb4YJ7GAx88KsE0b0YSv81oRiWNAE3vB3UfroAhMaxhFOdKbTuuhCn5bS8I20kyf9
+aftamqOY1nSq2UpneDqa1OINNaC15oQa1NrWt8Z1rnW9a1732te/BnatVfDbMF86NGjYRbKVvWxm
+N9vZz4Z2tKU9bWonGw2svnBo1hBsbnfb298G9gL+vKpAvzq1pnZqaA6tanb+F5XTxq6Ip82N2liT
+e9TzPnd+C73udvcbqO8+9YDxTe9xS/PeA78suqmrbn83/N/YxqarEf7Yehu8shPHrMLby3CHOxzg
+6Y43xi9bcb3OGtwnR3nKfT3sFwe8IsiudsxlPnOaT/vabi30tlW+c56fXNx4RTAvFCzyvmpcwBXh
+d8fZ/fGFh5zojiU5fQ/+9MzqG94CSbrSU830jTud6nyNujen/vWvGn3IHNd6u7l+dIHIm+yqLXjJ
+KwJlPtfd7nfP8pdbDvIxx9nvfwd84OE8Z5xfnRd3xnviFV93PwOdwxXxsJIlP3nKn7jFe2+6QGT8
+Y8533vOf73GQC+9ygRT+ufKnR73kmex4SV/87XQ1e52RnvZ+r/3sXn893Fkvatfn3quxbzXaab91
+iMMV976vatjVOXbkSxX42Z798FVte9m3vfldVb49KzKEYHTf+98Hf/jFP37yl9/850d/95VA7M0W
+WhZHgH/85T9/+tff/vfHf/71v3/4y6L4jQ6NEUi/ASTAAjRA9HODuJO63ru+qXq+iBM+6Us06gu+
+42tAm8q+1mK+C5ypBzQ+rJNA4hs9vuMFt+PAmcpAcNrAE4QpDwTA6AvBCfy/nRI4FqSpFBSVcrPB
+mHJBGoTBGJwwCoQ+69vBG1RAsdu+OVDCJWTCJnTCJ4TCKJTCKaTCKlz+QkLAvK4TCCyYhi70wi8E
+wzAUwzEkwzI0wzNEwy7Eghk0r9CwByuEwziUwzmsQiY4wuVjwCJsQasjPUMDQhkcwcwrQT1EwTvU
+vgQjRPzKQrbzwz8MQjbcFNNKxJjCQXZawUTswTb8QUfsLyGEQAucRJWqRFDRwVBsMD4kwazjRAqD
+RHmSOFN0h1H8lN9oAmWwxVvExVzUxV3kxV70xV8ExmC8RfEpr0h8DRGQgmRUxmVkxmZ0xmeExmiU
+xmmkxmQUgVbMlNIQxm3kxm70RmG8AkPUQFkrNBI0x1NhLRUkR8M7Ry1MlXTMwQdTR3YUxHYsFXhk
+J3Dwo33kx370x3/+BMiAFMiB5MdidEWeIciEVMiFZEiC5JpkQsiGlMiJpEiBBIf5OpWK1MiN5Mg/
+WhU16MiQFMmF3KNTAcmRRMmU7MdMYsmWdMmXhMmYlMmZpMmatMmbxMmc1Mmd5Mme9MmfBMqgFMqh
+JMrzuJqKGJZiORbeGQnkAZousaLz4RIsAomWWZr5QSWTQCXisZaFcaUHEoh+OShncZaiNEv0iJyK
+sBd8caCK4Bd/ASMeeiAX8hykrAOZ6Yg6ARgieg3eEZoU2J6RKaNngZkOARILO8vEFA3b6Z2YqQia
+6Z6MwBmd4ZkoqsswgqG/VKKNAJajxMzy8UvjaRZjCMxnmQRwOE3+CZJLxWTN3hAbgSAbGzqbthSI
+taHN1RSezgFLurEbj/ADl1mFq+TL0AjNjKGYnaCCpUGYrKmbkjxMRmvN6ESRpQGmiqCc3cFIzLHM
+udTNJcIgjgjOmXGZFwLNaPpLNMofxzSY5uSFrNmhz5TO+MwLxsQdyqAX7OwI3wGeLhGeLuHKFPpO
+zlyYOkDP8SmMLuEJUTrKqwDMQtkNvxGIGlrN4ZHPCsWL68mewMRP7wEf9VHNy6TL3UyfjvhNLSLP
+BSrOHkocwwgZgzEXLsHL57TQGc0LAapO3UBQuUmgFuqcEPVOi9jMHhIZ8TzO4yFO80QQgzGMlumK
+ERUIIApQxKT+0SkdiRMqSWZpm/cRCbr0UQeSIY6wGrwkUPjsSyTlzvnACMPJCAmdHyml0jf9iCTi
+COxsIlTaziWaIlGKSmnBS41IyozomJFhpe9EpajMiLqhFiAxF15AzUN1zDYNHjiV1Eml1Eq11Ev1
+HzvaxyvNiz7aR0DC1FAV1VEl1VI11VNF1VRV1VVl1VZ1VQNxpliV1Vl9Hme4BVrF1VzdJVRwBlTQ
+1V8FVlniVV8N1mLV1WE11mSl1VtwBmV11llVl1WS1mml1mq11mvF1mzV1m3l1m711m8Nk2KTJmdY
+FUkAAEko13NNV3RVFWfASFFBC4PUFAAgV1UxV3ZNlXtd11X+cVdWiVd5zMF6zVd1tVeCHVh8RZV+
+XZV/dUtIcdg+2UuBVYOHpdgoqQh9tYuK1dgjuViD3diP7ZGOxVeQJdkcqQiFrZqSVVkagR+GTbDU
+g9mYTbEMyCmB9QR8wNmc1dmd5dme9dmfBdqgFdqhxdlCENmK4AbQU9qlZVoe44ajFQhrAIOppdqq
+tdqrxdqs1dqt5dqu9dqptQao5QXTk9myNdtZoIGTpY97YAWiddu3hdu4HdrccFmhg8WWIi+bvY29
+7Yy64AWMbcRV7ESxPY3VMNzDFYzWAFwTDEXJQlna4NvInQu6BZpLJMS8fQvJ1Vyy8FvAVUXBRSzF
+AtzCRdz+0jVdp1Bcg2XcSXTctXWMzYVdm6BccR06WMRczYjd3KWJzjXYzwVd0SLc0xXe4UWK1MXX
+1U3E1vUK3WVemJjd9hOIczCD6aXe6rXe68Xe7NXe7eXe7vXe6eUC9qPXiuAAAjDf80Xf9FXf9WXf
+9nXf94Xf+DXfWhDb9+O/+8Xf/NVf/fM/gQDcd0CHABbgASbgAjbgA0bgBFbgBWbgAH4HsWWH75Xg
+CabgCvbeBBQIlIWAP5DfDvbgDwbh+OUArCrFULxdXtiM5lXhmxBb3/3dtRJdgyVd4qVhwzVeUGxc
+tV3eFV7h5y3hSTzhFOZh5uVdfHXhF9604K3hJV6NGyb+wrsVRR22i9cdYt31YcvVwyCu4uYt4k1E
+YkVTYiYW48Bw4kGE4ijOYNfdYua94jy03ZrN3DWO3S4GwS8GrRjG1xke4z2GijJGXkJU3imW49xt
+Y4EYAjpE5ERWZCrEQnUR2B/QgkiW5Emm5Eq25EvG5EzW5E3m5EiGBbHlwjQU5VEm5VI+wzX0X4M1
+B3Jg5VZ25VeG5ViW5Vmm5Vq25VtmZXMQ2zdc5F72ZUS2wzSuCELo5GI25mNG5k7+ARLG4iLU4kGG
+XToOXDsG41TOYz7G5qjw4zNGY154XCqG5sgtZLvl5mcOZ8mV5iOm5lWz5orQ42yGZ6oQ2z/Ww0Bm
+DHD+PufbGOfaNUVzzue9Ted1Dt0wjueCnoJt5mZ7htx/3tt95uZTbAu9ZWiAbmGBrua/lWGD1miE
+PmOFxueJ5oxx5r4DJOmSNunyW7+IrohhaIOWdumXhumYlumZpumatumbxumWpoP63d+e9umfzr/+
+xWh8hYcyMOqjRuqkVuqlZuqmduqnhuqoNmp4EFsBPOmrxmqSxmBvpg8IeICcBuuwFuuxxulhYGY3
+7mc4xl2Qto2AtujCwmN31miD5mgo9mi2tg2HLme1RmG8rg23fmu1iuu+mOt4ruu7vWu/7gy9PmN/
+VuzHAOzARqvBNo3CNux5fujEfmzIGOfIO9vPTr3+y3PkinAFPjDt00bt1Fbt1Wbt1nbt14bt2Dbt
+ZhDbzWva28Zt0BO9oa4IMfja3wbu4BZurxUDsSVb0EbuyVs9rq4IAWgE2Ybu6Jbu6Y5tVzhrgaC7
+xdPu7c47MGsWgVUAuRXv8SbvoDXadu47wVPv9WbvNiM83hYIcTiD+abv+rbv+8bv/Nbv/ebv/vbv
++RYHsUU87ibwAn+DxmPugWjb8mbwBhdvBbhucm5svhbizZaLyJZspaLsd7ZsJj5sWNRsC5cLxoZi
+xxZxzq3oDJ9sgu7wMf5wUwzxEycLEr9bE5fxsMBwFV8v9K7sFufjF89hYRbkG5eMCKe1nkPyJF/+
+OfEV2AEAgSeH8iiX8imn8iq38ivH8izX8iePAbGFuZoD8zAXc2i7OfjmhXVIhzRX8zVn8zZ38zeH
+8ziX8zmn8zRfB7HVOSXX8z2vgZ9LcF6AAD3Y8kEn9EI3dC0fgAjnZxOmcCKHixzXcXdjcR9fYiBn
+XSm+Z0efcUV/aBvX9M/gcXWO9F7YcErfY0tPXkxf6E+XXU7fa5Vea1a3CUgfdaEqdVMXY1QHZFX/
+aFl3XlefcFjva1+vCVqv9YfjcQ7H9dPV9XrmdWIviwgvAj6ndiVv5O+uCEY49G3n9m7H8mUQ23oY
+83En9zCvB7FVhzpX93Vn93anc3XA82qX953+83OUJQRvx/d873ZGAPYSb3RoB3UzF/VIv/Vlr+Fm
+L8IYB3iXoPE3FvYKX/iWMPZjB7BkN/hKx+yEfvaI/3XH+2FM/HeOd4mJp/iCv/jhRfgdVHiRL4Vx
+zm4Dh3nF07vRFojwdvCbx3nzFlsya++e93n1fm/Ale//JvqiN/qj7+8A5/EBj/mmtzsER1kBWPCc
+p/qqxwcI9/gOS+6tlzzRxnaBKG3qFvuxJ3vXpm0et+3cVvu117HdBlzfHu64l/u539ri5vHj5vq8
+T7HljvrnLvu/B3yxt+6sR2tGf3iWH/kUp3iiMvmTZ/aM7+iNR3zc6PcaD/nJLwWSP/bGd/z+0k15
+G1x5kW/4tD58zGfhUF98Sbf4zhfez2fB0Of4ca6E7aL92rf93FoCvg6ES+D93vf93wf+4Bf+4Sf+
+4jf+4+d9KwDlTGD+5nf+54f+6Jf+6af+6rf+62d+VDZzFmCD7vf+7wf/8Bf/8Sf/8jf/80f/7mcB
+sbWu23f/96d9XFD1QkD++rf/+8f/4w+ECNcrgUUVwAUIXgIHEixo8CDChAoXMmx4UBIASQ4nUqxo
+8aJAiBIxcuzo0aEzAB9HkiyZQiQvAClKsmxpEYAzlzJnItRI8+ZNmzh3ttTJ8+fHkECHejwpUCXR
+pBdhKm3q0KfTqA8jSq1qEKrVqkKzcjX+mnLVvbBix5Ita/Ys2rRq17JVCyBa27hy59KtG7YVgFZ2
+9/LtGxevXr+CBwsGTPgw4rnRACRu7BjtKpQAJlOubPky5syaN3Pu7Pkz6NCiR5Mubfo06tSqV7Nu
+7fo17NiyZ78W+Pg27rCSIOTufViAJAG+h/sFLpw48rrGkzOXC0FS8+hxuVKvbv069uzat3Pv7v07
++PDix5Mvb/48+vTq17Nv7/49/Pjy59Ovb/8+/vz69/Pv7/8/gAEKOCCBBRp4IIIJKrgggw06+CCE
+EUo4IYUVWnghhhlq2N0TFvBizEIgJmSMMSlQoUaIaohI0IofbvgijDGilwKIIF5DhTH+JxbUokE1
+NsTjQC0CKSORRRqp1CQe+rHSkj5a4Acv1/BYIonXuPjhNeCkoOU1JuqYQgoe8rJll7xYQAUVHoLo
+B47gCDTkkXHKOadH1wDByyrXPOFji0vueA8v96xyJZ+8qHHnjR+iGKSLVDzBCzh78uLoE3XQeSmm
+mVrkIxBW+mgoECvtyKiIhVpQolFTYqnllvd8Cqemscp66SSrqEliHacGusqjPQIq6KSGFqrGSh1e
+SeqVkzT6RKWzOvssndcA0OubLq6CY4kFgUnio9eC6aKIXkJZarUgnknFSmvieOex0Lr7Lrzxyjsv
+vQx1CSaYVta7L7/9+vsvwAELPDD+wQUbfDDCCSu8MMMNO/wwxBFLPHF1VOhrgbK8GNuuQiSSqOaH
+HqfLIonoHlRHyYt6uZKKxqBM5ctK4kjFuIMKtAqsCIUpkJ0DiZkzySSOzMvLxqhYUNHUBukyiSiu
+/GbJYlL0hJs3L2os0AQVjWKNIrfrsckGvazjmGiudCrT28ZcdtjG2Ixn1tqK2bNAPzvkcbZde/x1
+yaIS1PLLvLCZI5Qh57jo1FXjuWjhcQu0tYhFgzxQ0ifnKOrgNJuJK5VMG822qG4PhHNFFtedsZnV
+/ugxyHh/CvXlBqGNMpMzFz424hdNknGnAtGoepQz5w58uaMyerPUx0u6s5l+Czn+0D1APPoEEK4q
+Do7jAx0qUJK2odSil8kTTyiLxgN70IrMWzB0sBYBsSgVA/3e4o2H9ziqqsfjKf6Vy4u5vv6Opb50
+XS97AtkeL7o3JnINBAho4p+q8gc8WyFERNGbXvWuRLeKvE8g8TPU9whyD+Hd73gSvNL5jBe/C2os
+g8RL3/8IOBDsVWR3AundAoFXP7KVr3wnXBEF0Wcb6bUQUCLa4EUSRTWBNAl4T4oSkCJoPB2yq4dP
+YN+xnnczfUUJZ6uAkh9IV5FITcpK1GPgzTxYQhP2UH9wWtHzVvTBigAwjEycH0GeKKU1Fq+Nx0Ki
+6q74tQDC0YdfFJwYKUJG0xH+C43EEojiAgiuKf6xisbL00CuMagjWnIidbSZGMGHIkAOkmNa5Jjq
+QIRJnr3tlHE8ZBgNGDyNVa2RToTSHik5ST+uiJSqW2UXNdhJi1jMT5JC40D8tKO9gYt1pRwf0XBl
+xDa6cplqGBRYZDkmCzzhgyk4GioltcymXaloppSkG30YtYssMQVQOiYqBec3ygmtXM48JSpfVodp
+prOf5bomnlxlkTB184biBBIp8cY1w+WNlxUcn97AMTyHtBNKk/ADMpM5z8fVM3IeW6g/tZYjcOQy
+pIUkFUCzScxrKFN6GZVnj5ipt4YS8qHnxJ1HdrcKFPUOmYfaKETPqb+ECqT+oNXUHzA1CaL4xU+b
+h8JYoIbWoiumQGlBfSbw3lhTbRrkfR/sKcd+KkQfUrKXwxSRUampVmQxNZ4LeaqyUsDPqa6CV3zc
+ZU15NsxfclGTbqWIV1tIPhGuAqil/CE6r3SopLZyrcVrqzZ16rS5/i1UY0WWQ/VqU8b+1SJ2+qDH
+cnUsQVlVkq974eggyKgB5jVQRKSeQFNQ2M4mhAq9m91pO3jZVPoRhW+bImu5WhAL1BV2uWoRaW2K
+2dYGUa2sRa3vYugi2WJxIra1Eo1cxr49cVGXp31mc8332gwKN4/FBZzRWgRA5Q42rym0YvXGCyjo
+brNuI6MubQ/yWd/hin3+yd0tXukb3h6yELb5BexGPUqia9XTuwxNF+vAZljJ+c5smWWi7VwkLU/p
+bo6qK5oAzOngaDYNbyup3G6fdmCG1KFwpBIZg7PlYBOTOL19s9zHKhw2+oKuWhtecUEm4eFyeuwE
+2CPRXWc60+zGTrmZa9xIWtxDEx9Zxpml8NZQjLSPCi7Dre2xhgHAYfclmKMLxhZQI4g3hqKtyZd9
+MjQpJuc5y+he+OouR/AFpvmqZ3344t9F/AwmQGfFzvn6iKFTgOfz6FmuIxE0865zj0aPJNGLNk+j
++dyRTNO5057+NKhDLepRk7rUpj41qlOt6lWzutWufjWsY91q0frMUgP+EWSgULIUy4DoHpLhda4N
+4mvKgMPFB/F1rpPHmGFbZiWX6bVlNJcSTWvN1rdeRR0AUIeqHuUy3aYMDvkIhN9KK3d+YwxGmE2Z
+YKfE29MuiLqLrRBkpwS5IsEMiDDz7cnIm91dBcDwXDUZ3ap7Mr+qTL8REm1AneQy1JZ1VFJgyXET
+xCv0ruzASzsQdMNbMg+/OPR0bQEpIwTZvq4DtTh+FE2rPOQVR/m7DeKHybi4m71Tg21XfhCOPwHb
+pX1kMq2dwEh6JebXzjYPha1rlxudIC3398iN3fFuow7kLX+6zn0Hc5DfejLzVAMAlHXFrS+d6WYi
++c7n23OYew/i1gH+e6+eAAAX+yHbbS8IOHjVTVhhnd59L7u/xxTJqfvayldn+cfLjm6s82LcFPdd
+JMFuJca33MoDmQS10b7je9g966Mznc9LDni/P7zpgd9SQvzusl5ZHfFpd/rBDzIJcMyeRfNMU+DN
+LviEqFzufOa6260CDjHVPZPDRwnwjcF6wG888Z7X/d15JmbR5xrsizo87JVekOljXe5+GPlAqIA6
+2zyK8pq2wOBRWVyNAbyotNf10x39fBGO3uOvpz9Bfnxsj+c88Ng3yNWhCPBNiqK1H/vljhpYyQCC
+nP4BIJ9VCrUMYPBFHLvM1ptgHvIxn/ykX/Npn+nlXu4xXrAh2+/+NN3/4Z/8ZAzWgZ/3zV8HOiAK
+ZtJvMZGtnYn8yBX8lZ73XBoIkt79QZ8Ikh7YQUnrZR8M+o7NAF+5EWD0TZ0HvuAR9pyxSeAENgXc
+EY3K3Am9SeDY6WC7VcbdXcZKAB/XBaFIIBvVeMgJfiFljKFl0BrWWVbjsYsIPtvzcd1FnQyUAEHG
+jJC/ieDIjV/HVUbsseFkiMjTlaEO+mAKoFwRbhywGSJSgKCQcY+tSWDBZeD26aAdQl8VSkWa+EHV
+cN6jbCHzTQLK8KAL+qATxmCUTN/+sRspruHfEcQqVM3TyZ1lPIr4DRegmF8eDd5ejQmvTF+lFOIH
+3gM4gIMX9qD+/R2h7jWgE3IcFYDF0q0hFFrA9AEfFVgGLhmgbXjIAi6dNBphAoEjFX5iUkzCuIlK
+wxEi8LUKQ9RiMtZfxXFg211cqNCi8zHd06Ff13kI6nUdlABjkMwT9SCEGuTKB2Wis1Eb5wliLE5j
+6SXi0g3kRHIc2BWdCVak63FdA1bjm8yTZY3jPfKe6zWhOkaFtEiUB3Kd3E3UD/pjP8Zg1KXeGepa
+pfDjE7Lb01keENyJzVnJjXyQQa6d0lgAoUEK7T3h0/UiQ5DhM25iK94k9Rldw5njB3Zk7pkIQaCi
+90zCo6CiAjLfxVnlD4KlJ65kU1ABB5piZRhDJqKkB+pbwUH+G7FJHeEt3STQorcx4NxJIgSAo5lM
+i8Zgm7bZlSQuXmWEm0ElxEks2sV5m8NdJQpixi9aRq7l5bxN5aRcI8tVZstpyWa2YVNmUmAGSjcC
+AMGJYWkCQMLtXGUkXTqypW3eJm7mpm7uZp65DjnhRJvhzVJSSHA6E060jOsYFnsUZ47xpnM+J3RG
+p3ROJ3VWp3VeJ3Zmp3Zu54D4pnd+J3iGp3iOJ3mWp3nKpH8gp3muJ3u2p3uyJ3r2B3O+J33Wp32S
+p4LA5n3uJ3/yZzc24374Grb0J4EWqHn+Z4GchIEuKIOCJzhooIBM4oD4GoDqB4UWyIUSCEcKyIYW
+iIQKSIb+TqgI9keIciiE9keHEsiHBkiJsuiI8keLAkiK/seMRqjfeAEm5KiO7iiP9qiP/iiQBqmQ
+DimR6mjIVWh+hOgNvAKTNqmTPimURqmUTimVVqmVXimT3sCRJqiuXUORfimYhqmYFqkXyM+JAoiE
+ekIprCmbtqmbvimcxqmczimd1qmdruklbCmBhGgVTIGf/imgBqqgDiqhFqqhHiqiJqqfVoGeDkjR
+3QM+3KmkTiqlVqqdeoKZ5qffqKmldqqnfuqc5qn3ICl+8KminiqqpqqqJiqjjiqXQk+kgqqszmqn
+YqrvnOl/pCmt7iqv1qmo5hqp3oepriqxFquxGmqrAuv+q9pGrPaqsz5rKdjqmOCqf+gqtF7rrv5q
+jP7HsB6rt37rqibrtvrHozYrtp6rp0prjQaIhNpAMrwrvMarvM4rvdarvd4rvuarvr7rAzQqiKrc
+FoSDwA4swRaswR4swiaswi4swzaswG6BvwZI0RHCvlasxV4sxu6rDWRqgkioA7gDyIasyI4syZas
+yZ4syqasyq4syL5AxAJIiBJDL8wszdaszd4szuaszu4sz/asz84sMbwsjeraPcwCyx4t0iat0q6s
+A3Asgnjs0kat1E5tyrqsq+6pysnsz24t13at1/Zs0F6toxKt0VKt2Z5t1DbtrWrqQHws2r4t3Fat
+0Pr+R8x+rd3eLd7ybNgqq4aSbdz+LeCGrNpOK9sKhNsGLuKirdXyrYjymdbmLeRG7tfu7biiqN8m
+LuZS7eCuK5r6DQqUAOiGruiOLumWrumeLuqmruquLuh+wtySqMrRAhvMLu3Wru3eLu7mru7uLu/2
+ru/OLi28Ln8UHQSwrvEeL/ImL+uigNMeiLWiK/RWqra+aICqXJ+CK/Zm76GKK/XqR7lGL/hOqrpS
+a388b/ier5xOb7DaR7dqr/u+L/eub318L/rWL5yOb+HyAqfaL//iqfBWL59d7/sOcPbG77IGirn2
+b/3ib8d6rvI+MARHcOq6rtj+K59RQw5ksAZvMAf+d7AHfzAIh7AIjzAJZzA1/K/36lrxSjALtzAE
+M+/aNnDbZi4NR+3iVi6MZq3k7jAPgy0K58ejlm0NDzHLbi758gfUErESy20Fu6jj9jAURzHNUm73
+AvHlLjEWk6wR5+/hZrEXu8MNV3Gp6rAUl/EOU7H80kcQfzEbb7EMGy4bf3EYp/F81K0Z33HeovEB
+F20ce7EbP63fhIEJDDIhF7IhHzIiJ7IiLzIjN7IjD3If/PAY81nAOqwlXzImZzLDQmwTy6iuEcIj
+h7IojzIpP3IYNK+BmK8Co6/6Yqj1EjAsg6sB9y2srjL/MjAgD8T+2vL5tjLWBnAsB7OxzvLY1jL+
+L6MvLjvvph4zK0uysL6yMEdzqhKziRozM4NvMqfyMl8z+Ppy4w6EAEuzOG+vM9sH/XIz9Gazh/rN
+NpCCO78zPMezPM8zPdezPd8zPuezO7NDOddHiD6CDAS0QA80QRe0QR80Qie0Qi80Qwf0I/SzGqsw
+GegzRVe0RV90Pm8DKq/zDPcxFs+xKz8xHo/05EL0fKyxRy/xHytzR6c0EYP0Lw/E45I0TfusHtOy
+bQixS9fwSmtzS+80DcP0NwvETNe0UefsTRdzTgP1EPc0RwvEKcyCVE81VVe1VV81Vme1Vm81V3e1
+VC+BSctHiFKAKpS1WZ81Wqe1Wq81W7e1W7/+NVyXNQWEdXwUnQBkgFfntV7vNV939SlstIr6jSNk
+AWEXtmEfNmIntmIvNmM3tmM/NmH7AF3DR4iKwxlcNmZntmZvNmd3tmd/NmiHtmhftjhM9nvYdTdA
+tmqvNmu39mM7AmAPiCqj87V6swWD8zjnNrKatnucM21jqzoHti7/NrrathPjtm4nd6BSs8QSbQIT
+t7MGt2xvM3RDq3HDLDQrt3Yztydbc3VHd2zb6ECgQBCUt3mfN3qnt3qvN3u3t3u/N3yXNwUz7m0L
+xAxEAH7nt37vN3/3t3//N4AHuIAPOH7PAG+3B/GOQnwvOIM3uIPDNwwT7hvzQhczdeIKdX3+80JR
+HzWHT/GBswdKWzjmOrVww7GIYy6GHzdRdziL12xSV/NSn3jikvh0/7SM/22KY7dItziLv3hzQ49O
+33jc0rh4m7iQ4/iHr4cd83iH+3h3x/iRD3l4s6vfPEMYXDmWZ7mWbzmXd7mXfzmYh7mYX7kOJLl6
+hGg1/IKarzmbt7mbvzmcx7mczzmd17maV4OZp8fEjjmf97mf//mYP8OUd+5wf/ezXje3Zrd2Jzd3
+D613G/quSneR6y+kOyui062iL3puNzq5Onel96qkU3mhfzqtXjrsArOmM3qez4inkzqthjqhC8Qu
+u/qnmnoOo3qqb/qqM1qr0zqownqusjP+Rg87sRf7PfNzJyc6nwF0Qze7sz87tC/0Qyd7pw8EBEy0
+sWe7tg+7RsdwLht5lL9tjiu7TDN5j+86pl1xuKMtkYs6uK+72Y47pu+4uRu1kzs6lMO72bZ7rFO4
+visuupfHktd7Td97tef7v0stvwf7QER1Xz88xEe8VoM1tZ/6QFRAXGe8xm88x8N1BQQ8edg1Xks8
+yZf8w/+1t7O0QAy2a7e8y788Y0t2xd/6QFj2aN88zue8zod2ac/8fqA2zAe90Ls8bKe8T8u6r8uq
+rQMwcuf6OHO65T560lcqsFcrdU+9pS69hWa60wsz1A9vr2M91Q86wyO92Gc9yI9H+3b+vdenvXj4
+9tlLatWXr9/4wgHcPd7nvd7vPd/3vd//PeAHvuDfPTa4fXiEaDYggeIvPuM3vuM/PuRHvuRPPuVX
+vuJng+GDB/EOPud3vud//uD7AtlbvY0n/NLKu8WvOMHbe+Z/R4ibftqOPt2XPuwjLerTvOqvPk0b
+fNQjfO0j7cKT/rv//tHePtPnvu6PNO+DPZAT/9IG/+wPv/OrrPFvPb0n/x0v/8+r+/Qzrewjsd8k
+AuiPP/mXP+AXvs9b/0Bog+W3v/u/P/xXvja0vndMrPnfP/6XfyJ8/37Mdtz7KkDwEngPwD2BBxEm
+VLiQYUOHDyFGfEjQoMAqUzBm1Lj+kWNHjx9BhhQ5EmOVgxQlplS5kmVLgSkAnMRXimZNmzdx5tS5
+k2dPnz9pejoI02VRo0ddAkhx0BNQp0+hRv156WRBpFexYkVpkWRXr1/BjjQ50GpWs2dVEh04U2pb
+t295Cn0ZE21duxCVMoW7l69bqmQr3hVsdyuvi2ERJ1YMciyvwoMhZ1XrmG1fy5fjDqUbmfPZvAId
+ZRE9mnRp06dRp1a9mnVr0T6qBu48u2VhcWdw59a9m3dv37+BBxc+HLe42LSRs5wsoJtr58+hR2/t
+SHNy6y0/8zo1i3t379/Bhxc/nnx58+e5Lzl+nX3DwhVUxZc/n359+/fx59e/n3/+/Arr2wsQoeUy
+QM/AAxFM8LxTqhPQQYWyc8CdCSms0MILMcxQww057NDDCV8A8MH2CiOmlxNRTFHFFVls0cUXYYxR
+xhOJEXHE6ya7Z5YPeezRxx89dKDBGx+MEMgjkUySwxABI5LEsngxccYpqazSyhhrbNJJHDfTUckv
+wURSyLm2dNDIMNFMc0kby+ysxCvhjFNOGLN0DMo2Z8txRzX57HPCMXmZDE/rsjvkhUMRTVTRRRlt
+1NFHIY1U0kMNYXPQwQrLJpNNOe3U009BDVXUUUkt1dRNs7H00rsmg2CJSWGNVdZZJT1kyFVpy64p
+zHjtlaa/7JQNV8EKO2yxY5H+Dauxx4ZltcvKfI2WL7kC3axZznSVVtu9gGX2WrSKTVbccUVa9s5v
+0coR2m3ZfYpaQdEVLNt26XWq23PjzSpccvnttyRV8z1K3XoJ9uldawOua96CGcbpXmETRmpffylO
+1lyIIzZq4IY5rungjO3K7pkwSC7Z5JNRTlnllVlu2eWXSdYBYJBXKqyaX3DOWeedee7Z55+BDlro
+oXGuZmaaU5qMEJiZbtrpp2F+5lakrzrTz6vDZDJYqo96c86vwYazTm+5TqvLPbFOO0lA4S27KKvV
+jttHrcl2OyKvw85b7xfHxtfuiPSUW/Ae2Ub4b5bgHlzxDOn2+3CH8N5b8sn++8b48YYCX1xzDAu/
+PKmlBJJw89EpbNxyzxWKfPLVw64cdcDPJl32zl9XKbsmlMld9915793334EPXvjhidf96NoLE0GK
+5Zlv3vnnoY9e+umpr9765UU4/vXJrine++/BD7/4Jqau/aHszF+o7vS3Zl99x9lv230y53cI/frb
+x19L/fPXX/75/6e/+9VvfekroPkOWLsAxs9w/OMFAMBhDAlOkIIVtOAFMZhBDW6Qgx3UIBXgZ0AA
+UMGDJTThCVGYQgmC8HTpg4kKYRhDGZoQHA3k3wxxmEMdTlANDuSFGnYYRCGisIcOtMAQkZjEDPqQ
+iU104hOhGEUpTpGKVbT+4hWxmEUtbpGLXfTiF8EYRjGOkYxlNOMZ0ZhGNa6RjW104xvhGEc5zpGO
+dbTjHfGYRz3ukY999OMfARlIQQ6SkIU05CERyQsgrAIh1wBAEV9ykBBCDgCVtKSdBGJJTWZSWASx
+JDj8QMlMGgMhBHmgJitJSlRWMpOaBCVZGAKERybkHsaoJBCK6ElNGkSXEAwlQ2Cyynv08pUKUQMj
+z9fChFhlkispyBOM8YRETvMufqgDQiYBjgFt5lxPWEUdRgjJ1BnOlA/E2LnKyQsL1OGX72vlJKqC
+kDv5DUopqIM004mQJ1QSdAJRAwDg+QR74rOB6VxnOxmSz3TCRJoJMYb+OIF5jZRYJQUSzYpVLIBM
+am7ULOw8CBX6eQ9wSlJYq6CCRL/Z0HGu1JwLQae1UqDNhNIFAMa4JyxJKs9zysYq+TxINrOJEGP0
+kxdUsAAmWfoSmbrHWvk8lxqWelFlJsUgT6iDRTma1aOsApn7LOITwDEJbgorBYFxnE+RSs9OWsuR
+WKUlTe9BBSDglJM6dSlPe4jWolZ0lrzwKkLUIFG95rOtooynJN0aKNAZwwI1NCoI63BUq6gBsqCj
+LD/rapUnyDKypFRDCuz5GW9WchXSHG0dYFKRVcBTq611iTUFYgEqDKWsY2VqYg9bSrje9a3LtFw5
+C/LPUDqVpzsdCjL+0erIHoKUrr1Nal2ZqlvaKsQYrB0hSvNiz5ailhfXqINBqvtDZhrEKsYAwhOe
+AELH1IGRfpilMUq7WUbG9BqjrcgkSOla/a7Eo0BgbVyR2tKFrJO179tlWlGZ35f6dqZ1HShx5Zng
+VmoSdGidxGx5MYlrBvitqGyugBtcFVQe1a4P/GU5TWkV9uK2u+M1Z2ExSZCGFsSRDf0nLyIrEEdW
+RK/79fFCUlBaAEjUqry0LS3BAY4WohW4xpXuQWDM0rJQYRUQzimEAmOBIXNYICDUZCiVW8qjDpat
+W45ubr254SuXBcUxsco1VgGOOuBSnVQAhyzJm+d0OjLABeklK6H+xGYb/pjQ/owshv+cF3TWocBn
+frJanavUM5fln4Kap5Pr6tMoU1kgQ0UIEJZC5gFF1Z255XJZBA3LOwm0Dv8soouDa2ZTppPGhgMH
+iXc8EDUXmtcISXKj6XouKgA7xI/GNF0POunABLPE0GVwTn2aAgwLRMNkmYQ0NSzYgm4m2Yalqzfn
+KlTr8pguKTYIdwMFDldnGAChdLF50ateWoM3vqsgJX3t+5L89prf1cItrT0szGIfdpXM9DAxESpl
+2aj3yhM+8J3AEWpUxrTRjjyxl+lsp4lrvJLF9DbHb6nSlyAz1Zi0ih8w3sPQDhWgLoYmBFcRk3n7
+VZYAOO9clJL+giL6t98997lDrkHqutyjoSJFilVF/nOl/7zKg4k4zTVaFNAuneorOaIFSSwYIFqQ
+qFy7egWz3pJrdB0tQCRt0lsS9aqvne1td/vb4R53uc+d7nW3+93xnne9F1KJffd72PG3db8PXogQ
+rZ/gCZ94HEIRgop3PAwHOD+CkPDxlS8hC304ectvnoM1ZDzZ6xd59yXwdaRHnek9t8DQg35+omcf
+6i8H+8fJ/nCqbz3r3ed6EU619M3sPe9RZ/vc91MSrzD+8ZGffOUvn/nNd/7zoR/942NV9wiEEiaw
+n33tb5/73ff+98EffvGPX/vaOz2UpJ9+9a+f/dK/QfkcmJ3+YlSM/scCg1lxv3u9dKxj1KL93wqD
+DepvABGjMYSPfeSPABXQK+5PkvLP+gJjV/ivYfzP984vMARwATUwJAxw0PAnATcwBDuiATPpAZEH
+SiRwAgumAoHPcwJQBGFQIzrw8w5i/mIwBknwgUzw9/ZPBVfQ/FwQSjLwBkVwBp8oO7qgB5RwCZmw
+CZ3wCaEwCqVwCqmwCpeQEBww86DkAtqhC73wC8EwDMVwDMmwDM3wDNGwCy8ACGMPSpDBCuEwDuVw
+DquQEuCPf7IjH2SHdGYB/7QwMKSEdQTxa1zHgQrjBfZwdGjHifIwETenD7PQEKEkEAexEq+kEPnn
+EB1Rcxb+sYkacRMVBxJL8A8PghIt8RRnBBP1RxNBcXA6kYk+sRXlRhR1kBQFwhRRMRddRBXxhxVl
+MW5e0YeyIw9EoRiN8RiRMRmVcRmZsRmd8RmhsRgFAQIiMROhpACAIRu1cRu5sRu98RvBMRzFcRzJ
+MRsLgA1nD0o0IBrZsR3d8R2hUQPuUID6yQaJMARzsPpOMAJ9kGFY0BZ5YQjvUQONkBHrcSDx0Q8l
+kR/7kWD+cSEPQiARkgAL0hMPciIXMB938AJ7sCHb5SGtEQMxcgErEhb7aQOIIyVVciVZcjjgQACq
+cRWhBBSkoyZt8iZXAxTQ8XAK4w5a8ieBMiiDwzjoxyD+D6ISFCQplXIpyyMDYHIUIVIgKKA/qLIq
+rfIq+YMCdhIAoWQJmPIrwVIpGWAeP7Cf9PAX44YW9ZEHb1EX3ZJvttJufBEtsSYY488s6VJt1HIj
+gxAQ3/IvV4QXCQhKEDEv65IsV+8gztIw/WQvARIXAdMtBVPyCJMxr8Yu8bCfuqADOLMzPfMzQTM0
+RXM0SbM0TfM0OTMXqBEqQ/IgeGAcYDM2ZXM2abM2bfM2cTM3dXM3YZMH4tJtCoMTUHM4ibM4jfM0
+3QAxb68GR1IBNRIgU9AjtwUkZVIkm3MAS1IYL/I66e85o5IXolM6pYU6e1EIubP+svMumfM8K8Y7
+W1P+IMJTPH2FPAfTOtnTX9IzM9fzPvvFPauzI+UzWuiTMu2TP8klP+nxIIbgOBm0QR3UNLGQNf9T
+IKCBNy30QjE0Q3cTGn6zbAojFx40REW0QZlAOYdPMS2zMRXyPaMkMl10MkevMlOUTzAzQQViMWcU
+TRzzOyHTRVERRl9PRnMUTWq0LFF0SHV0RSe0RX30L4FU/wSiMJEUTIo0MW90SsNkR1m0R5u0Ep8U
+Ag9CSrF0bUwUAftpDyQgTdV0Tdm0Td30TeE0TuV0Tuk0TRFhNWvxO3VhBfi0T/30TwE1UAV1UAm1
+UA31UPlUFzqUawpDEer0USE1UiWVTuWxKC1yPw3+dFz8szwZMkDHc1Gp5gUz9UDLNH1AcFTFZVPr
+E0A9lVcGNEYLFFWPBUGNVCDsUVbtT0k5lVVb9TJeNUhjFVcTg1atlBfQdFKRNVmVNU7vNCZ3VSD2
+FFGldVqptVoNVVH3Z0kddVm5tVuRtVKrhQavdEyVREuXlEu7VBC/dB/DlFyVpEqXc1zd9UjM9VmZ
+NF1zcV3ZkhfEdF59BF5PVF791UfqdVXbEl/zFVSRZi4HlkcA1kyPtGF7pGAJtBQRNmGz1V77VWI7
+5GFNtZ8WdERFdmQh1FkNlhcqVENVdmVZFjc5NGNPFkRJdmZpljNL1FJNElOFNTFUtWLhs1cFVGH+
+aUZUd1YxiDVeeeFWizYsehZWeRVop0VoQYZol1ZZStV8TrVqwaJpgfVpoRYufhVKA1JrC/Bqaydr
+ybYruFZs4/NrwVZqM4Zq05YkjjZgeeEcYiFv9XZv+bZv/fZvATdwBXdwCTdvyQBP15IjBYIHkqBx
+HfdxITdyJXdyKbdyLfdyMbdxfRNmfZYX2KFwQTd0RXd0CTc5cVY7I5ZjPYRinfZgL9YS9VVx+VV1
+HdZsXycWaZdDWLdrXfd1BzF2+7Jdc7djbRd1cHd4M2R3xRZdfTdvgLcNA2NjkddCPBZr+wkpwzJ7
+tbcpnzJPWXQqsTJ8xXd880MrObd1ecErt3f+fdmXO8bydNVTIFBSKOm3fn/yJU22c2kSJ/m3f2tS
+J8+Xd3nBJ+23gA14KIvXc9B2bkVibcH0Z93WV+E2YuSWgTkwgS9ngS34IxyYXSE4gvsibB94bDdY
+LDD4cTS4hDmig/e1bUFYKkTYg0lYhRnjhA9nGOExh3V4h51xGvMXfbGxHIV4iIm4iMfxHANYbNeR
+h5m4iXMYXA/wY1N3ei9EeUeYeZsXbJ43HaOXijWkes8WL70YQ6xYhrE4i+dki3lSSMe4QsD4dsW4
+jSukjPf1jNE4TtSYK7tYjt3Yhv/meOWYjmXXju/4Eic4YRhWjt/YeDWTDh35kSGZCiPUe5f+lAvT
+8JIxOZM1+QzXMIlH+A0jOZRF2ZHtEH7101ZpOCRYWHZd+IWhIob3VSJTeSPqFmJReZY9YpWD94Nd
++S1gWXZlGZf/xZRtNGmFeQR19WRbuZeB4pd3eYaPOSNqWYpvOZozQpeh12uZuZkPOWAq+Jin2XoP
+Am9Jt5zN+ZwD93B/WIAZN3Pd+Z3hOZ4vd3P7x14/F53xOZ/L2XTD9QjjmI/dQZCfmZALuUryWC7Z
+mI8XWYH/mY8FOpt7t6Cdt5vzJZHbeKEzuKEDOZk7l6AlOhUpOl4seowxGoX7aRDaN6W11ynXWWwN
+gHxhOqbF1wBCGl0KQ31VOqeXcgf82G7+smN+DziohfoM8FdC7XV//TeplVo1ALieT5aAhzqq7Zco
++9koq9mapwCbuVibt9lgavpbvlmYwzmMdTaatXqNO7Wro8KZIRqarXms4bisj/ms9Zir1Xon2Hqr
+BSKYxbqn3QYJPSCwBXuwCbuwDfuwETuxFXuxGVuwEZcv25oZYGCyKbuyLfuyMTuzNXuzObuzPXuy
+meGrr6UwhKCxTfu0UTu1GRsQ/LpsALmNH1qv7/WjW0e0m2Wkvbikb1ijYZuj0dejaZtObHtYcJuK
+dfuPeXuMYxutLTa4a9uTZVh6Sbq1uea1ldu3BRi4nbtFDho4E1qRqZtqskMZ8qG8zfv+vNE7vdV7
+vdm7vd37veHbvCEpcZ/ZBVrgvvE7v/V7v/m7v/37vwE8wAX8vl1guHGlMCohvhV8wRm8weE7CsIb
+aeiboQFySS0cf6JYnFH3Oy/8ZP3HA4v1lFm0wzv3wxkvgjgvxTFowtOR8lT8xVfIAoPQxWFcxT3v
+iWo8xyUI8A5Px3Pc8OYH8Xw8xfeuyI38yJE8yZV8yZm8yZ38yaE8yqV8yqm8yq38yrE8y7V8y7m8
+y738y8E8zMV8zMm8zM38zNEcInLsINZJnyoMxO1HwoBLzsnJlRIuIVgNANhrxlYJyr4JglIA7UTM
+koDgGhKNxdP8y1Mg3ARikbbpw37+qOZujiHwpcmeC9k8iiFMSqKuAQgUDGO8axUkirKmLamugYSa
+LdFVHbAAoKH2qZ2sqdxsLb5QndIhxtIjzdRiqiGgJMz8xrz0KawGzr1SfdWN/dYEArZ07NZknbqK
+btAqfbdyvbmiLCH2/CSkCV/+CptK/cmSfd9AzNiNfdEFYhX6qbrazCF23dYV7tJPzXLWaYR0ruFM
+DdLpauxETsbFHcz/SZpa7SXmKt0XgtVOp88RjMK47N0hR9oAgOTo3N3JYsSKfd8T3aj8QKZEiqDs
+XcOMgcXoHaei/bmqvSHcq4e0va9+Sui+7ZsmnuLRfBIWCXSCaZfQKqamKuTDHdL+82ndXSrf82wh
+gL3T7uHpSq259N3lu9yR1I2lfGrbk6ndpz3Aug3oO96vTMrZGmnF2O2mih7cWh7pzdzOSu3PjCHR
+eP3WaarPyR7kPG7g/1zrTwmVKgLOwKmmkN3ACN3nwX7v9UcNiI3vAT/wBf+OUuCCgPwsvo6CeLwo
+MGjwHf/xIT/yJX/yKb/yLf/yMT/zNZ8zQKvzPf/zQT/0RX/0Sb/0Tf/0Ub+ifGjsUr/1Xf/1YR/2
+Pf71Yr/2bf/2YZ/xCm73eb/3ff/3gT/4hV/utXD4jf/4kT/5g78FL2fmlf/5oT/6f19cR9xeSdx9
+Mrz54dxur1+Au9+Ftn97wp/+mqvfw60fw8c/9dKfrAViAsrh/eE//uV//um//u3//vE///Uf/g18
+VQojEgBCmsCBBAsaPIgwocKFDBsKjMQr4j0A9yJavIgxo8aNHDt6/AjSYwoAFp+UO4kypcqVLFu6
+fAkzpkyUEyyODIkzp86dPDUCSGHRwayhRIsaPYo0qdKlTJs6HbrE4sSKPatavRpyqkVuqrp6/Qo2
+rNixZMuaPYu2KzepFLG6ffv2psQMT+vavYvXqQObJOH6/Vv1Z1B3hAsbPow4seLFjBs7fkz4BVuq
+gCtbzqg1IrFenDt7/gw6tOjRpEubPs2Z2OTLrFnL5XVvFuTZtGvbfrw34uv+1rwtC47o4Lbw4cQb
+S5bYtrdyt5l5bUYNPbr06aZVI6e8PDvP17GLe/8+PDev3drL8/zNKzj49eyNrzYPH2Tz59Tr278/
+2jrs5PH7b+QuW3sCDkiYeOT5h2BG6O1gSoMOPghhhBJOSGGFFl6IYYMIvJdgh83Vs0uIIo5IYokm
+nohiiiquyGKI9XDYIYKvEZJhjTbeiGOGO/AVY48WoacegUKCd9x+2PkI33z4Lcmkffo1hyR8AA5J
+pXcG9hVlgkBWyaVwRUKZpXZKNklmmaU9yV+Y2k3ZZZuzXakmglu6Sad718VZ3phm7slnL2geiSdv
+bNZJKGJwBgrfnIUuGhn+jIi2pmefkjL556PKDcpooYdamh16wuQIaqiiWsiJo5xW1pwsi6zKaquu
+vgprrLLOSmuttq4qi6mn/vUaBAiMCmywoQrD467KKZopoV+maexfkU4KbX2VNlsZpsnSuSm1lyF7
+rZvLAqotVs9GSy5004YLl7Xddpktun9xuy6X37oL17jl3kvaufRepW68VLa7r1vonZJXwQYfzFRU
+dwZ8VXNxyAFxxBJPTHHFFl+MccYabwxxHLoynNNrAtCFcMkmF3xKsSALDFRElrwBc8wyz0xzzTbf
+jHPOOu8MsyYfrywffxSkRXTRRh+NFgU/Ay0SlgLQw3PUUk9N9c6WqMz+dGAtp+evt0tnvZG9+I79
+mb5gg9Rv1wQCfDZO8KpN4LxtZ8UffWTfXfbXc6vcHdxVsr23R2/73Z7cgXckNt5jm314RmkTvh7g
+jfu0dRFmXI555ppvznnnnn8OeuiiX86O3oE390gAqq/Oeuuuvw577LLPTnvtqj9i+t69cjF6777/
+DrzoRWA9eUeDQ05k7nMnrvi9jBevG5Z9Iz+g5ND/uHWQ1BeufNvMN0/u89A/vj1x1l/Py/HlD2c4
++gs7B37z4hdP/vq3nX+9+vbb1r7738c/qflNrn77ow3+oIceEsxhgQxsoAMfCMEISnCCFKygBRdo
+j+6drTlYmIYHPwj+whCKcIQkLKEJT4jCFHoQCxoE24wuCMMYynCGFyQB8dx3Ef0VcDb9Q9//ANgn
+ATaOgDvEzQ1xGBEdFtExPbzeD4G4JyEejohLZMwBi6fEKi6midB7IhTLJMXAUVGLibni5LJIRsRw
+sXhe/GKTwqg76QUojbUxY+PQA4Vg6HGPfOyjH/8IyEAKcpCELKQeR9DCrKXqCIxspCMfCclISnKS
+lKykJS/JyFy9D4e9UoIhPwnKUIqykFA4IhLRSMfCrHFybXTjkuA4tzGmskCmxCEqZ7nKxrXSlfeB
+ZdtkOUs7Hu6Wqczl4XbJS2klkmnATKUwAzewk0lzmk1RmJGQ+L7+h3Fsm9zspjc15rFNuk9kJKOm
+Oc85i5RFD5sK2trLqgbPeMoTZz4Tpw+FhrR86nOfZlGaPa8nMqjNc6AEhefV1snOHGZvlrQx5unq
+lszwLRNozaTjM/dGTDo6dG/IjKh0fHm2iqbxonPLaBo3ujyIejSAE12ZSMlI0rahJxEmqKlNb4rT
+nOp0pzztqU9/CtSaluqfXeQPC8KB1KQqdalMbapTnwrVqEp1qkhlQUtB1qs+BHWrXO2qV4GaiFq6
+Dz2eKIVZz4rWtKp1rWxtq1vfCte4mvUSV2VYc6owhbzqda987atf/wrYwAp2sITNaxXqGjDu4EOu
+jG2sYx8bV0/+iBV9ZIWsZS+L2bfSlahs5A9eCwva0Ip2tIM9LGcHKL3FZna1rLWsZBGa0CRurayt
+ra1tNYvYfd2VtLztrW8Fa9prYlOxty2ucc/62vFgKbaVPa5za7tZ4SJxt7+trnV5G1wwoY+4z+1u
+ZpN7IGyihxEgKK95z4ve9Kp3vextr3vfC9/yLiO39GqOOtKB3/zqd7/87a9//wvgAAt4wPhVB33d
+NaP4KnjBDG5wfBkx2fzN1rsUtmx0tetEz153wxwu7YHRxd0Ki1iu4F1uQps74hS79cLMuidlPtvh
+GMt4CtltMUBTq+Ics7XEscWeRWir4yDP9cPhou6Mj3zdGoP+a3w4FrKQedzj9E3YyUFm8ZI7+2Ik
+a7m6SmZniKmsYij3GD0JmIeZz4zmNKt5zWxus5vfDOc4mxkHRNZWc+yAhzzrec987rOf/wzoQAt6
+0ITOsx3qTK1epULOjG60ox8d5wREGIFTBrOKrcxOI29506Lt8nCbbOkUi5m5lQ61iDGNTU1zetUe
+Pu0QQW3qCo/6xKWOtXdRPV0Ns3rXwEV0s75s6+7Omp1khrSxj43sN9PZ1cfkTzzYAO1oS3va1K62
+ta+N7Wxre9vQjoevjaXoZIt73MeWNGxJ/eNgVxjXOFQ1r9+tV08jEdjqPu6wxVvrehuX3f7TNbz/
+bdhv74r+3vq+7b1Pme+C25bfLrYIjAEOb3lzEtYKN/iksZjwirOW4RnOMsT/LfFxUlzjrT24LbdG
+XgerfOUsb+98mf1QyqAjDTSvuc1vjvOc63znPO+5z39Oc3QI/FQJbrnRj75yCJ+b1ukm+W05XlSP
+f/zdId/uyJ3+3YufMeNYt/DQOeXuqXO66jeWimq7zlqTj5XraHcs1LHscLFT/euWInjbH6t2yrL9
+7nJ9Oyv9LfdVk53JZud71pdO7K1xgACMb7zjHw/5yEt+8pSvvOUvz/ha0P1RzXkHOj4P+tCLfvSk
+L73pT4/61Kv+8+/YPKJ69QfMy372tK/95Tmg9Tvu3fD+uIU5RwEf+E0Pnn5X5z2Jcz/M3RufrX7X
+JfCDr+Xho7bwy8c78qGp/OqntfnNljr0tyz9V1Nf+4zNu4QtogB8qH/97G+/+98P//jLf/70r7/6
+C+H6QDXHG2Dov///D4ABKIADSIAFaIAHiID95w35hyciwwr2B4ERKIETWH8KcH0YtTWOkAUbyIEd
+6IEfCIIhKIIjSIIlaIIb6AMMGCfNIQ5n4IIvCIMxKIMzSIM1aIM3iIM56ILioIJqIjLdcIJBKIRD
+SIQm6AgXWFLZR35D5nsp5X3fh2ThN0XFt4RrZX6U1nRVCFfcF3NxB4Xg14NhYndamFZXiHFZSIZt
+xYX+v/eEXyhjUihGVJiGZmWGW2cRw9AGeaiHe8iHfeiHfwiIgSiIg0iIeUgHYZglzQEPZcCIjeiI
+jwiJkSiJk0iJlWiJl8iI8ICIUdIrD1CInwiKoSiKhDgMSChTSriEa+iEXuiGRwaHcTR+c2iFpng2
+KCaLaqWK3vN8rchhrxhLcjiHdah7aHiLaJWLG7SLvJhkm4gkYyiLwph8xFiMTChd7ZaMyshlzOgj
+zhiMtAg26PEBkCCO40iO5WiO54iO6aiO68iO7SiOGKCNPdIcRlAM9WiP94iP+aiP+8iP/eiP/wiQ
+9WgE8Rgjr6EG7oiQCamQC+mOH+CNWYMe1nhlfzeTkc5XkVOYUOGFcJlmY1HHkRcZhxlpYon3kSWZ
+ah1JfCIZZeljDCngki8JkzEpkzNJkzVpkzeJkzlpk6uAkn+3CjoJlEEplENJlC7JkyAZR0WplEvJ
+lEFpDCMpXgAglVNJlVVplVeJlVmplVvJlV3ZlUiZUl4plmNJlmVpllUJlr90lmvJlm1plisJl3Ep
+l3O5NwEBADs=
diff --git a/Documentation/DocBook/media/fieldseq_tb.gif.b64 b/Documentation/DocBook/media/fieldseq_tb.gif.b64
new file mode 100644 (file)
index 0000000..7b4c176
--- /dev/null
@@ -0,0 +1,445 @@
+R0lGODlhdQKaAucAAAAAAElJDK+vr1YMDBUVZC8kDQAAVkYQEBcHOwYGSCEJHSAgaKOjoys8DDMz
+CgAYGp+fn19fFJmZmQoKO10wMA0VIAAAcDsICCsMDAcMT1MMD2ZmAAcSO29ISFUHByIAGoiIAA4H
+T0pKDJaFhXd3d0EgABoaVGYyAC4AKXd3ODs7BwAAN1MAKQAAYlZGB2JlDBwcWWBtYCA3ABAQTQAA
+ZQ0VQD4AAFVVVUhjSCQMJQAAfBMHMkQgIEtLSzAyDD5VPmZmDEZRB2FhEWZiDFo2ETkdCwAAVEUt
+Gu7u7js7Ozc3N3d3WACPADU1NTMzMyBRIDgAAEJCEHEAAEwNDZeXAABpAEQFBSMjIxgNQDooCBA9
+EEhIbwBVAAw/DAwMPgBNAENDCgc9B8zMzABDAD4MDAwOKjwKCkQWKUscHAAAcUtLFRMTEwohCoqK
+AA0NTBEREQgfCBUqIgApADIAAA4ULzg+DEEfH3wAAAcHSaqqqlkcHDgMDKSkpFQAABUVRjEwCGZm
+B00QEDAwXSUMJGUAAJaWlhQUUnx8jVQaGgcGLggSGy8GBmw4OGNAL4qKioiIiGIAAEsHB3JYWHd3
+AAAAPlctLYQyAGggIBgAGkIVFQwcJRgYSA8MU9EAAAcHVQAALRoaYbu7AEY1H2ZmZlxdEHAAAD82
+DlhqWExGHgwOUzMzDAAAmgA5KTEHB2ZmPlpaB///////ACISRExUDTJPJUQrDAwMVhISSEhISHd3
+IC4xCjhcOA4ORERERBkVXElJAG5gYFhYcnt1ZkgGBlYAAAUFMTg4ODo3BTJrAFESEmZmMF5jBwoG
+Q1paDUkKChxGHN3d3RwYRGZmHCgoKFMAACYmJi4YLhQ+FCIiIhU0FT0AKR4eHmVeBw04DRAsEAwu
+DAc2BwoqCgAAPFdMDQAA0WAqKgwiDEgZGRkQRAckBxsTPDEwDBAQEDwAAEJGDAAAU0FBQEJCDLu7
+u2IYGJoAABgYRjg4bAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAALAALAAAAAB1ApoC
+AAj+AGEJHEiwoMGDCBMqXMiwocOHECNKnEixosWLGDNq3Mixo8ePIEOKHEmypMmTKFOqXMmypcuX
+MGOelAegpk0AJFrSrLhTpYQ3AHoeDFpQqMCfQQHIXEh0olGBYkZtpGkTW56B0EYBfTMKCUEJEqja
+7DpQDIAbBJsOJHF1qdu3cOOqVKtTKcWnEOnmlQALWk6Eep8C4Ou3YWC7JUlAg9VUL0K8vcRMRUwC
+gFdoXBdD6+WE4A0kQqE5kSqwsuWBepFg8yq3tevXsPPKg4n3YW2HjnHPZrp7oODehoHDui2ysfDH
+iKFi42iU6A20A5G84SsQrdE8iKdPR3181KPY4MP+NySBC4L4lHRJAI0MSwwJ0++B5nSvHqdAJPVv
+LHb/U54YJzX99RR+QOnX3ntKidELANiMYlce2DB4FX9vHMdYTfIQeNZ+8dlHkFg9QSihQEQpyKCD
+H9q0E4X+AfhGTir6ZhMskWGTU33Y8EWffFC5OB+CONX3V1BixVgfe7DgWFlB7621nmRMAjBdLwk1
+Bw0SAEBZ1mKw5PHddQ9aNgp0jB0nQWfnpanmDTVNU56aI6lFghOLkbAcTVJh9xl28uCJBDQ2Jkkn
+EqN0Js8bvWTYy3dmzfbUnFcWOhxXsznxmWhKHeooANAcmihrBhEFKaGGAtAVoH9xN1ymFa66GFH+
+lv4JYEFE7eRphi/21ephJDqRR6fY1MlqnlnCkitmfZra5VlI8Fnms89CmuRy6jkKVEGLlkbntEwG
+CwuKyK2VE3HfLhaapQKNuSxrjpkF50Sg9SnvvPTWa++9+Oar77789lsvPDcBsE0Tqb67kVpWDVSh
+UMbRxKUEy23XV5YOFwRNrckZS93FYlRs1sNKjZLqDSRUnBBREnNsMsS0bvrtyDD6x+lRGWPsqkCZ
+pSVcT4MZtCRN7M6Ws0AM70bU0UbPljDO8uQ4kAQ177a0scA5TWKVAQ8mVJECUbnqTZ/h3NYb30Hb
+ssEQFZn12my37fbbcMct99xxo62RWlknq2r+mVsrhbfeRzmBDZsu68xdT33TGHDJGYc629+JG77T
+gjfFHLmqtiKWFTZv3CAZr9CKcQOiC66q6uadd4yYcc+ynrdav5EYMHAIYx2dVljunGnZtWF3E5q5
+5Wb3QfH6a/zxyCev/LwAB3xFEoUMnxHCuu9N5Myw/KSxQCrbZRaUNhOUMsV2XQzyy0U1fvb4qj/8
+xtk7iey4+TTDn2njBJpNtF1N5Wp60QQhEABb97ikwQIbwrFa9qImEAQmRGKMsZ2MaESmdCmFBFCq
+zShIs6xXWUh40gthStgEAHZYSksitIictvWIN4BmdUnzE6oEFalSQaVYjwDAVR41KEkJpRf+l5qV
+piYFuOEUjESzGZUPTfWnQEmOVdYqIAVlxcDMKewvdtKf6aBFtr4s6IWq8p+dBog0xrRFVCx0YbWG
+EyFslU1aLfRKyaa1GHDNMUW3QwtmDOSXa3ltiwF8Q1tw9p12qS+FiCxJoTyXyOkBpz5OkAwZk1Uf
+smgobEI5UmUeMaD8eEUoSFjQlI4SIadlsnEAEsMlP4kToJDliaRkEHWIEkopSeCPSPwfYvIAoLNI
+JpUEwcz7mgIxBqmnQjDsUi89N8lniRIWwIQklKSJyyRxUJokygmhbMm/I6otbH3RijFp5J4JFkR7
+BJFU3rJXwUa6UySgemddxHPEhZBLnij+AVRDVEm097XmBtTBp0AHOrx7ukUeZXOIQQk6klFYqCBj
+QgISbsBBuOiToRjNaHgWCieOarQjhVnIRGsCzriE5aMoTalKV8rSlrr0pTCNqUxnStOa2vSmOM2p
+TnfK05769KdADapQh0rUohr1qEhNqlKXipARSOKpUI2qVKdK1apa9apYzapWocolgxwiGGANq1jH
+StaymvWsaE2rWtca1oTE4BRwjatc50rXutr1rnjNq173CtcYJEQYSwisYAdL2MIa9rCITaxiF8vY
+wAojIVuNrGQnS9mtAgMh0GCrZjfL2c6y9RAOYUQnRkva0pr2tKhNrWpXy9rWuna09Hj+6ALIQdva
+2va2uM2tbnfL29769re0bUFCnsCE4hr3uMhNrnKXy9zmOve50C3uExKSi1hY97rYza52t8vd7nr3
+u+ANr3VzkRBIvPa86E2vel17icesArjwja985/vbBYR2vfjNr35ZG1uEzJa+AA6wgHkrXIQQN7oI
+TrCCF/zc6SKkuuKNsIQnTGHwkhch5t2vhjeM3/YeRB7vHbCIRwxg+zZEtBxOsYr5K1sSu/jFvi3w
+QQ7M4Brb+MbMdfBBIFzhHvv4x9298EEyvOIiG7kTHjYIiGHM5CbX1sQMQfGRp8zh/h7kv07OMoll
+bBAa4/jLYF6wjg3CYyCb+cwUFrL+QYhM5TbnN8lFCbGW5yxgKC/EDlPIs573zOc++/nPgA60oAdN
+aD3zASF+cIOiF83oRjv60ZCOtKQnTelKK9oLCfFGNzbN6U57+tOgDrWoR03qUpt6095ISBSawepW
+u/rVsI61rGdN61rb+tasjkJCzFDoXvv618Am9B4QwgdLG/vYyE62pf1wXzc7e71WNgiW6Uxt+XK5
+IF4Os7a3vdwxF6TMaA63uLmr5oKw+dnobi2cPyTnaru7vs1Ot7xXG+2CTPvd+NbttQmSbW77m9ve
+Jgi4x03wcZebIOeet8JJu27ftDvfELetnRUi5YVbvBP1Jsi9Ix7xfQ+k3/8O+Zf+Az6QgRf85GY+
++EASfnF5N5xoD+c4xCeekIq3fN4ZH8jGZY5vjwsE5CIPOoNJLhCTo/zoFVa5QFh+82e/fDgx5/m7
+aY4QHgzg6ljPuta3zvWue/3rYA+72K/uDAYgpB5eSLva1872trv97XCPu9znTve0JyIh5uiC3vfO
+9777/e+AD7zgB0/4wuvdHAlRBRAWz/jGO/7xkI+85CdP+cpbfvGqSEgrxs75znv+82LHAEIYMIG6
+m/70qE893esR76bLO+cC2bnUq+1zWABd6LiPLtFhYXSk+168SocF013f5qcvefYzbz3xnw17WMge
++XOu/e1zT/0cU/f32E9zeZf+73L3Qj/fVD+Izbnf5uY///tOln7116/762f//eEN/vDJX2TjRx39
+WQ6/QcpBj/77//8AGIACOIAEWIAGeIAI2H+lIAAIYQJp8IAQGIESOIEUWIEWeIEYmIEa+ICUkBDZ
+8AUgGIIiOIIkWIImeIIomIIquIIgmA0JoQZtEIMyOIM0WIM2eIM4mIM6uIM8GINqkBB9kIBCOIRE
+WIQImAwIIQDvsIFM2IRO+IQaaAIOUQlSUIVWeIVYmIVauIVc2IVe+IVgWIXUwIAHAQqrcIZomIZq
+uIZs2IZu+IZwGIdyeIZGkBDXUAV4mId6uId82Id++IeAGIiCOIh4eA0JEQH+oZCIiriIjNiIjviI
+kBiJkjiJlJiIEZAQNhCGmriJnNiJYJgJSWgBcziKpFiKpiiHoKB89Ddl5od/7qZ+7BeL1vdg8FeL
+3iV/q+hs9ueK1aZ/BTF+uVhkrciLdAaLsniMx7V7vWeL8IeLwUhlu0iMc+aLBAGMz5hiwyiNWWaM
+yIiMysiM4IhdzniNRhaN2uhk1DgQaBAJ7NiO7viO8BiP8jiP9FiP9niP7DgMZncQt+AJ/viPABmQ
+AjmQBFmQBnmQCJmQ/lgMCREO4PCQEBmREjmRFFmRFnmRGJmRGvmQ4ZAQYPAKIBmSIjmSJFmSJnmS
+KJmSKrmSIAkGCWEF+Bj+kzI5kzR5j8N2EAyQAAq5kzzZkz6ZkLegiuRYZS12juk3XN2YlN8YjuE4
+jkOpYuZolDCWjgJhjU+pX9kolS/GjUkZi0vJlMzolFe5YVGplSRGlbBglWMJbUVpli7GlV25fl8J
+lrUolmupX2XplgOGlmp5l+iVlXo5YHAZl9Q3l3T5fnbpl+uVl4FZYg6RCTUZmZI5mfZ4aAcxAz+Z
+mZq5mQeZAAnxDWEQmqI5mqRZmqZ5mqiZmqq5mqwZmt+QECIACLI5m7RZm7Z5m7iZm7q5m7zZm7Ip
+AglxAZQ5nMQpmTdpEHzAmcq5nJs5A0KpmOkFmI0JYINJmLhnmIeJfYn+CZ3oxZjTKV98yZ1Y2Zbf
+SZ1IaZ3sh53Z6XvbKZ7s5X3lGWDh6Z5s6V/xGWDViZ4ip57reXTtSZ+r5Z336VvzCaB/SZ4DCl/5
+qZ//xp/9eXL/aaCoJaAJultoeQ6QkKEauqEc2qEe+qEgGqIiOqIkmqF9sI8GwQvisKIs2qIu+qIw
+GqMyOqM0WqM2uqKfkBDpMAY82qM++qNAGqRCOqREWqRGeqQ8mg4JoQKT0KRO+qRQGqVSOqVUWqVW
+eqVY2qQqkBBQUKJe+qVgGqYk2gqjtwI3eqZomqZqaqO88JwSmlrSWaG9taAMCnDu96C/F6FvWloU
+Kqe4VaB7ymL26af+wEWndaptDoqnBrd9gapu8EmoBOqmjUpacQqpuGWohwpmiaqo4aanjdqnlkoO
+FyqmpFqqpiqiJ4oQKrqmrNqqrjqjOYoQcCAHtFqrtnqruJqrurqrvNqrvvqrtAoHCfEHv1Csxnqs
+yJqsyrqszNqszvqs0Fqsf8Clp1qt1lqqZIqTZvqq3NqtrNqmJzapgnploTqn55mpQbepnHpmnhqo
+oGqpgCqup1Wp5Rpc54quIaeu6wpk7bqn7wqp8SqvpUWv9Yqp+Gpj+rqvPtavb/qvhBqwAgtbCFqv
+tmWwBzt0d6qwBMewEuqwfoqWHXAJIjuyJFuyJnuyKJuyKruyLNv+siOLQgRhDwswszRbszZ7szib
+szq7szzbsz47szCQELTwBERbtEZ7tEibtEq7tEzbtE77tERLCwmhDLlQtVZ7tVibtVq7tVzbtV77
+tWBbtcqQEHrgsmZ7tmibti1LAQghBj/7tnAbt3L7s/bAVHZ7t3ibt3q7t3zbt377t4AbuII7uIRb
+uIZ7uIibuIq7uIzbuI77uJAbuZI7uZRbuZb7UhCUPf50HwJySIYRMFTCM6ALSDJSFYPkM2szG4Sy
+Fa90ITZRUpcbu7KLESRQQRRFEEtCulBBQrB7NumTS78bvJp7uh+WHHukGaPDJU0hGu00u877vPt0
+GrCAJYOUB9f+orsH1BVI4ATVZDjB6xh4YRRZpBBGAUQF8RzAuyzQu77sqxBWY71YkSN2ARmsQRzg
+yz/HEb7Giz3hch/FQhBm4RVqgR3tW8AGnCTQIT9dw0nz67ncAhj5i79K1jixI0HYS0Dcgy4HvMHP
+G8DGMk3W0cAIIUAnEzD7IzuVg70V3L8XfDQ30QvxxMEybLlOIAEQ0k+sdMIG0UK90FVDEcHpa054
+hBX8W7zR8b9lcRogNMNMLLmPQFFYlDd4MUYMcb9BrMNDXBrLQb7JYb6eAR1L3MRi3LgXgw0wu0UD
+gsQKYcVapMKI8RPEO8HB1DnI+wbK+1BjnMeMKzhG/DU2kSj+WXMyQOy6N+HHNRG6NzE1Fnwf4jQ0
+bazHkBzJkjzJlFzJlnzJNEUCvbDJnIwkInFLnbzJAYXJpFzKpnzKqJzKqrzKrNzKrvzKsBzLsjzL
+tFzLtnzLGhHKurzLvNzLvvzLwBzMwuzLo8xSCjLMyJzMyrzMy3zGKnXMzBzN0jzNyXxTDELN2JzN
+2uwhLkUT3KvN4BzOyAwgePxR3izO6JzOvNxGNsXNLuXOLEUT5axR8gxT9fxSuVtT8MxS+6xS99zN
+YZxR/9xS+UxT/axSB41SAx3PAY1RC71SBT1T3CwMjFDRFn3RGJ3RGr3RHN3RHv3RIG3RXZXQ5qwW
+OLALKJ3+0iq90izd0i790jAd0zI90yiNAzIyzwKtFiG90zzd0z4d0h2wFg7cUtzcl5MabSRNz2ox
+fRd7Yzr20P6sFvMnrkkW0TJV1BGLWkhdT1HdG0zd1DX21A3NUP881ZNa1UPNz6li1I261fa81GDt
+b2KN0w4t1Vl9WmhtzWt916bl1i/1z18d1wo212/dG2b9qUKt1+pYnIzd2Paoj6jB1Sn1z2zQmpZ9
+2Zid2azJBjdd2AMBk44d2qLNjsdp1TGF1XxNqb2R1Dnt1YK9bYT913ad2qOV1+2817SNcast2QoN
+168dZrEN0Iad20iW2Lc9EGwdqH4t3B/328Dd2bI93Ln+bdv6nCpU6InYnd3a3YVjGNmeLRAfyILi
+Pd7kXd4q6IL7Q9dkrRaZuN3u/d7YDYqlkdYrxc38Z4T4nd/6XYAL6N3RPRBaQIgCPuAEXuCDqAXQ
+zdwCEYT73eAOjt9ION+KXZXEvdwtBdjOrakJfuGzTdvUbdC4TdsWztCuneE4FtwcLt0ebtzVjdwV
+vtvfbXsmfuIbTuIrR9wfLtGpgqHX2uM+jqooytp13RuzCqxGfuRInuS+KqzpHeNd+uNQHuUZmq1J
+Qt8IHeKpPeIrheEzjrA1vuUdnto5ftVYztda3tXN3eVh/eVovnQ4zuIg7uK5feaT7dtqLmZsXucq
+Lub+cK7jci7iMP7fP3fnGNvkgi58by7hxy0QeBZsjv7okC5olskYvF3SvaFpp5bpmr7pnF5qqWbo
+Cg4LvBbppF7qjl7aVp5SqA3o/h3qgU3oyIXiNu7m093nZP7nWR7org7rg53nvb3nfD3mp13md03n
+v57mvN5+oJ7iN17rit7iFD7nus7sg57syr4q6k1QZZ3oVT7hsMADZBDu4j7u5F7u5n7u6J7u6r7u
+7B7uZhDkla7UvZF3hlfv9n7v+E54iLfssw4Li9DuAB/wAj/w7C56zx7n0c7q2RTjr27tsg7mwH7X
+wg5Tq57rrU7tMm7t0PXwbY7ozt7ti56WL37x/d7+8MnO8Xre7Ct+8H4uENcN3zAf89xNhpQe4+Ft
+3jif8zp/guiN7THe3jIf9EIvBfIN8tAOC/f94Eq/9PxN80K+3r1xhwY+9VRf9YBoiPwO8QPB4Ezf
+9V5PDxFu9Agv8tJO8lpf7RrvXCh/7LS+8mLf8mSv8DV/6CbP62tv6SrP5yx/6wlv8QtP92nfYL6O
+922v92/P998Oeoq/+IwPdmVn9h1vDt8w+ZRf+ZZ/+Zif+Zq/+Zzf+Z4/+fvu84e+eY1f+qav+AZ/
++MOO62Y+7SUf+Go/+PKe98Fu66vf960P+SmP9rCvXHc/+4Vf+3t/+3Hv93O/673fbbLf2rQv8bb+
+T/HEntXGTvgZn/zJ9fvMH/zOP/zQPxCS8NPgH/7i/9Fa8vTarhY/QNPqv/7s3/4z/QPLP+QDQQHj
+X//2L/7P/1LmT1D7L1BQvfsAAUvgQIIFDR5EmFDhQoYNEcoDIM/hRIoVLV4USAIARo4dPXYEQOLj
+SJIlQ5ZEmbIiRIkqXb48yBLmzJkyad5MqRHnTpgnef4EKRLo0JURiR51aBPp0odGmT4tqBPqVIQA
+epHAmlXrVq5dvX4FG1bs2LA+qT6FOIrsWrZt3b7FOsrpWaZp4d7Fm3dtr410/QIAHFjwYMKFDR9G
+nFjxYsZC/SKFyFjyZMqVLQ9u+fho5MudPX/+pqxZ9GjSpU2fRp1a9WrWrV2/hh1b9mzatW3fxp1b
+927evX3/Bh5c+HDixY0fR55c+XLmzZ0/hx5d+nTq1a1fx55d+3buFN9IICjhDUEkQiFyJNwL1nlY
+6df3JcgZALY8Cgc7yQxt1Jv5JJC8J+yGwoSSwAnAnABPoPkKkiuz7h6EMEKKSLiBoBtGIUgq9ggS
+Q0AAbvivKgcFYm+ugTY8ET7x6hNRICT2+w+aN0aBBhYxnHCiIBMVdHAUJ1jMwwkM2wNADIL4G1FC
+JZdUUgwAQkQCABZhyYM/EuEbCJtRkEDCCfVaLKjEJFG8MkNsEporSol6qXAgJLBxrL0k55L+AJsQ
+XfyuPSccC3JHJv8EVDtsEqxyIGgG7YtMWHoJUdGB/BTTIEVRhAaAGg9K8w0uiyzokRwfnTMzJx4x
+iIQcAXjkTIFGecTPQF+FFToKV3Wsl0fYc3QgElTFdMy+IMWyTIJcldPFUeqbFEs/5wJWTmyMhOWN
+SpOMtVprj3PyvzegnRXXYN0k4Q1qFRxMWMJESlbHcd1LF1SDmPVVTqyoPHXca+/FtzcE81BVHk3f
+E7bTN3q5FMz4fo03TCwrLVjdgVoVI0poH/6Ux3dFJbXTesU4k9Vi8wU55N0euVAojTBTdFd73VXY
+4pZfzojXi4dds00X4aR5ZoHEuxMWJPL+NOpZaT8WuWijY6v0WUkTDVbihpolOsWlB1oRzcweGQ8W
+GWm0EUeHv171R4GCHNIoUz8l9mi11x7NCZmlBjCwXuQDzOqpiSyXbvXko88+wZyYWD/+4Ow5apep
+NhCAUd11MuO02YY8csknp7xyyy/HPPNYSeilc897mRgmCT73PEHNT0c9ddVXZ71111+HPXbZZ6e9
+dttvxz133XeHXB7ffwc+eOGHJ754449HPnnlC08OCeWfhz566acXnnnkoKE+e+23n7460L4HP/zA
+ViaObvHPR38x8oc7OX333y/M+1G4p7/++ltdXziIbrW/f/+hx59zNPI/AhaweHLxXpz+lKOU5TBw
+gY8jjlSaI0HpmKWBEByOA5OjQeRQcDkehI4FH5i/4HDwOCY0DgiTo0LnmEUQC4BhDGU4QxrW0IY3
+xGEOdbhDGNYgRSQEjlJQkQsiFtGIR0RiEpW4RCY20YlPJCIqfihA+MgDBjzEYha1uMUdCkJX33qO
+WRZADjKW0YxnRGMa1bhGNrbRjW8kYwum2Byl5CIWd8RjHvW4Rz720Y9/BGQgBXnHXMyRORKUxyrg
+uEhGNtKRb1zAFxM4kDE+0pKXxCQb5XglIP6mjoMEZShFOUpBFpKTVDyRIjO5SlZaMpIZAWMLHVPJ
+VtbSlpo05AUzY0dS9tKXv/yjKd/+00nfIFKVt0RmMsnxSliwsDlmMUEapDlNalbTmtfEZja1uU1u
+dlOalMjlCAeihjaU05znRGc61blOdrbTne+EZznVEM4VwkcA7/BmPvW5T3520wSSpI5ZQLEKghbU
+oAdFaEIVulCGNtShDyWoEeiJHKVEIBQXxWhGNbpRjnbUox8FaUhFetEITPQ4EhSABSC6Upa21KUP
+BQVApyNGZdbUlpscpnM+CUye9rSXwkRhcYxpU6KukpnOZA5Ni7rUR+I0qOWbCy99OlWqBtOkKazi
+MZm6VUjKtIKz5GpY3ehUDOovqlVFa1rxCNSyBmeoYoVrGo8ay2c65haewGte9br+V7721a9/BWxg
+BTtYvBbjqsVRChhesVjGNtaxj4VsZCU7WcpW1rKLBcNhIwgfBiSAsJ8FbWhFO9hbeDU6So1rauOo
+2QyeVa2vnSpbidmbt6o2tXOdpEBoaVu4knW2vNkpbIX7S9mikkRa5W1YcRtQsCa3t6w16y6HO92f
+QtetWXUuXJc70+Zml6u+1alrqTveQRZ3gtj1Lle3+9WBzGC074VvfAObAOsGcS4iAER+9btf/vbX
+v/8FcIAFPGAC51cE9f2NBPkgXwY3OL4zMG0Iu5vepYKXjuIlb4b9aN5DopfCS13vaSf8YZtamDnB
+1XCK9cjhD3qYxDYNsYQp+eL+oppYlwORqop1HAsWK6e2NFZmjMM4YiDf0sbiFEiOd5ziHtczlUWu
+qZBlORBeiMPKV8ZylrW8ZS532ctfBnOYrfwJBPtGKSqYRJrVvGY2t9nNb4ZznOU8ZzqnWQVlpi1n
+VyBmPvfZz38OMy8iPOQZQzmZR94ghpes4SZ30MWGrqWU61poSN8Uz8BV9KLJ2+iTPrrSRh30lHX7
+aUuf8sLS1TSTL72bH5M6k5JOqmOqDGha19rWXiazqU88lz/8wte/BnawhT1sYhfb2MdGdrJ9/YdV
+60aCDNjzraU9bVoLGpa5hcVuXY1JRFM006meLqex+uRtg/razKV0uS/Z7RP+fhvcwhW3UD2t7kbC
+ejmopXdTm50bFL873PvGTavzzUh7KwffA2cku43Tb3/DG+C3ETjCu3pu7rbXwRfHuGDpq+sbCyQe
+lwV5yEU+csvG4+G2UXDGVb5yvUKY4uwdtcQbqXDEurvhaY33Zskt80UWPDkH53kbaQ5VVN98uDln
+37yDrkafIwfoS1fj0FtbdKPDFunCiTjU0dj04zxd62eUenRxXPWjn7w2Wf96GbluHLNswhZvh3vc
+5T53utfd7nfHe971/nbDchzJsFAFEAQ/eMIX3vCHR3ziFb94xjde8KowO22ejYe9V97yl8e83jcR
+6knHPO1Rj/xsGE72ql7+/bo7//zWOR/rdKfejGEvoc1J31PTAwftn197cbyeetjbl+qzL33oZXP7
+tOeeOGJ8afKVv/yGStTvic6MNEY6fepX3/oilYbwY4NIlTLf+99PvvGHYxYxGND89tM+bJRyfvZz
+L/2vkaDz2j9/6U0MqfdWIPTD+9vdPDXpz7k/g8s/b+M/3fA/sTsvAKQr1ju1/XPABDSumYKfCZzA
+AuQ3CsRA97HAgMvADhSf6tCLEBTBEcyKhlEOaCDBFFRBtzDBDVrBF4TBr+CdGaTBGrTBG8TBHNTB
+HeTBHvTBHwTCIBTCISTCIjTCI0TCJFTCJeSOPKGarHER81jAhWCXXxn+jL35Fr6ZkoRwEpuJGvMJ
+CfNBl/tgEas4GAvhFHK5QryRGyZ0Q9OYlYG4kAxhGoPoEMAAEbt5Gag5w515gy08iJO5E2KZC0dB
+kXD5D8DIGIBxEcDIPxNpqzeUxKfIlkackiqpw4LQEi7xEj3sQz6Em5hZiO9wQsNhGUaEGYuxin9B
+xVRJFZ05nEmURc0YlLGBwkORgEwkCEYJGFiEG1DsRYZJiDx4klGwGULMDEMMFkuREydokw3Zk0oJ
+naiJxFm0xp+IQ7UYCFvxFoXYFU/8xYTpw1M0CGOkkieJxZzpxVBsJseRBydBlr6QRljYE7AxxWvE
+R6SoxG3JiArpxoP+KA9xQZNyYcRzQUV2vEeB+EOFdEeDMR+JoBsnNBtNYQ9PEQissUeDzMeNHIp9
+6Zd/+UeBIRj7SBhgPEhhPAhi/Jt0PEVlJIhRUBWnEBL2SJzA2EJI3ECO1EmOIBltbCbC8J1vURmG
+gBqTPMS3eckhOccaQUaE7MVIsZGQ2AiUpEelpMac3MmspIikmUZGJBOnIcqSFMdQrBqAXMiBeANS
+acp1fEqE+aKNMBWCwEhyrEattEuOcJuYYBrBmBvCAEdz8Uu9iZv5AMTwgMKwYcO6ackqJIhKqQ8T
+MRBYwIZF1BopoUu/vMvM1MzN5MzO9Ewe5BzSAZ2bGB3RNJ3PRM3+1FTN1WTN1nTN14TN2JTN2aTN
+2jwd0cTN3NTN3eTN3vTN3/zNNZgG4CTO4jTO4yROJVgDJUDO5nTO5wRO5WRO6KTO6qRO6bTO7NTO
+4pyGNdjO7wRP3hwWbAjP8jRPAGAH81TP7awGAKiG9YTP6mzP94zP+mzO+bTP/DROdrAK/fTP38QG
+ZRlApzMG53AEAHAEA0VQBU3Q5jCGKdS5RxnQrivQ5jjQBmWOC2VQ53hQBRyWCWW7Cs3QBbVQEh1R
+DF2ODo3A9nCMEZCEF4XRGJXRGaXRGrXRG8XRHNVRGC0YABDRQwiGIBXSISXSIjXSI0XSJFXSJWVS
+IR0IDRWIGDj+hSml0iq10ivF0izV0i3l0i710imNgSc1UWFYgjI10zNF0zRV0zVl0zZ10zeF0zIV
+BjHF0B210zvF0zzdUWAYCBXVmiYF1EAV1EFt0kPwKrNghE5Q1EVl1EZ11EeF1EiV1Eml1EpVVHrI
+DB9tPddbLYGAUlh4AiYQ1VEl1VI11VNF1VRV1VVl1VYV1Seg07EDPpyLVYGABEvF1VzV1V2t1Evo
+U6VLvfVCVF4l1mI11knF1EcRUW3jVHLAqU8NVVeV1mml1mplVVj1VBNVsln1KWH61Fs91nAVV2L1
+VYHw00Rq1jMSVsdI1HF113dF1kxd1nR9vVoFVWvF13zV11X+xVZY+NRt5Vae8lYTBVd4NdiD7YRy
+hYVzRa5mXdeBaFeEldhxTVYFmVd67VR/NdFo3deO9Vhr7dd/Ddjgy1YMLdiJRdliVViGxVgyeliB
+sIMpkNmZpdmatdmbxdmc1dmd5dmenVk+UNaB8AM3INqiNdqjRdqkVdqlZdqmddqnJVovsFdv6Iaq
+tdqrxdqs1dqt5dqu9dqvBduq9QZ7jYJmMNuzRdu0Vdu1Zdu2ddu3hdu4NdsosFcz8Nm7xdu81due
+3YNfHQg+gNrAFdzBJVyo9YNDZdeUVVxirdj2uFiMfdaN/djJpdxrtVeAHVlfGliTXdzOzdWVBVbc
+Q1yI9dz+0qXUxtVUz6PXyMVQjq3c14XdkNXWzI0tez1Z08VdRgVd1EvXl4WFiM3d4O0E1H3c1bVX
+14Xd5P1Y2cVQzKXdUdrcgbhd4TXd3T2ull2m0RUI4KVe0yXeTeVU1h0I5FXe8s1X5pXV5wWm6LXV
+7g1e612PhuVU3+WBAbDf+8Xf/NXf/eXf/vXf/wXgALZfZ2CAoBWIevCCBFbgBWbgBnbgB4bgCJbg
+CabgBE4EezWHLtDgDebgDvbgDwbhEBbhESbhEtZgc7DXwHO8FWbhFnZhxoO8kh2IVhDgGrbhG8bh
+AMYAvxUIBpiACgbiIBbiIabgetDe33Xf3P1e1U1X8RX+CPI13yieVvRNMvUVWNtNYtyFX3RtWd/l
+3ixW3CXONux14nuV4jOmViqGBee14vLCYjD23C2WX9fzYjj2XDFm1vA9XjTmY1dVYzZu40BiX1iY
+XjuWWDnGXt8tB3pg5EZ25EeG5EiW5Emm5Eq25Etm5FIQAAOGhWjqp08G5VDWJnCSYYHIhi9A5VRW
+5VVm5VZ25VeG5ViW5VlG5WywV3KKp1zW5V3m5Xeap1KGhT7A5GEm5mI25ktOBh6GhXsS5WZ2ZlD+
+p5czi0qQgmq25mvG5mzW5m3m5m725m8G52qmhk222IEYKPBD53RuPnu9hipw53eG53iW53mm53q2
+53v+xud8dudrsFeLur5/BuiA/qiSAmYbCOeDRuiEVmhwzgRlTil1huiILqiYkubENeQwllfwdb0y
+huI+9uhR/eNA1tw3vmiUReQuPuIvLmmDxWMy3uOPhulSDWmRJqVBLuSVfteTxtg6xmmJbemW5eiY
+FupXvVyarmmS7mmD1Wl6pV8ycOqnhuqoluqppuqqtuqrxuqsdmozKOByFgi3y7ywFuuxvru+01gM
+NYdvUOu1Zuu2duu3huu4luu5puu6VmsUBuZ1CIC95uu+9uu/BuzAFuzBJuzCNuy9Xgd7XQStZuzG
+duzHzuodNlfOojyytuzLDuvNq2jSTeqD/WnIfen+oYbpmTbqULLpzj7Ype7dlEZtls5oJm7WoBbt
+0S7q0jZtpG5tcVVth2Xt3HbXzzZeYO7o2Y5i0rbtUsJt3zbW3Z7f3lbucAXuJg5t4uZj4z5uQDrt
+5w5X5qbjI86ESADv8Bbv8Sbv8jbv80bv9Fbv9Q5voPVqWHAvlpPvi9u4sx6IbwiD/Nbv/ebv/vbv
+/wbwABfwASfw/P4Ge8WvAlPwBWfwBh+wAwPmC2DvCafwCrfw9e7byf7b+ebwBnO5n/xQztZuY43u
+2J5u6j5j677uDUvuEddV7g5W53ZxXi1xPRZuFO9jFV9xPsruGedVGBfdzd5eH2fc1x5joD5xHDf+
+Xx3f8RVrcSKnVCAvPhmHckut8Y1OciVXXiZv8rV68iqPVCn/Ot89B0gw8zNH8zRX8zVn8zZ38zeH
+8zg38z7oaselMmrD8zwHs1yzb4FIhzEA9EAX9EEn9EI39ENH9ERX9EUH9HSwVzSrs0iX9Emn9Dm7
+M2CGAjnX9E3n9E6P81ZQZmjT81En9SuzNhCXUBEH80q9ct7Lci2P3dru8j7q8VWPcmXm4p2mcluP
+1Fb/PNmG9SWX9Vnfo1rn9TDH9TmOcSFH4mOPV07OYyy/8WAXdmAG5CY3dmd3VDHXOkU+5m8H93Cv
+ZE3mZALQgXNH93RX93Vn93Z393eH93iX93P+NwB71QIuwPd81/d95/d+9/d/B/iAF/iBx3ctsFch
+oIKEV/iFZ/iGd/iHh/iIl/iJp/iEFwJ7FWZx1/iN//Zk1nCBEAAamPeRJ/mSN3l5J4AjpuaFZvmW
+d/luHmdOPmeJpnnwc74+h4V21ued5/me93l85mdg9meBJvqivz6CxnmDfvmlZ3qWb+iPX+buq/mp
+Xz6KRnUFsWhth1RfTztgp/bk5fJZz3atX1RuhzqeJntH5fqv8/qvf92w7/KxT3uzXzq0T3tGXXut
+a3u3p1y4x/Yv13q6Dzrf7YBLMPzDR/zEV/zFZ/zGd/zHh/zIP/yJSV1YsAcuwvzM1/wcggH+e6WF
+JwD90Bf90Sf90jf900f91Ff91Qd9WrBXZYCi2Jf92af9J1IGe9UDydf93ef93o98ClBmMdj84Sd+
+zbeHI04qEV2OT11+E21+FFUOP+2wEG8h5VcO5r9+589+6E8O6W8x6n8m608O7B9/7S9/7kcO7/cx
+ZbmKGHT/F+yP95f/EewBAOiB+cd/vaj/+8///n+L/QcIEgIHEixo8CDChAoXMmyoEBsAhxInUqxo
+cWAvALA2wgLg8SPIkCJHkixp8iTKlCpXsmzp8iXMmDJn0qxp8ybOnDp38uzpUyfHoEKHEi1q9CjS
+pEqXMm3q9CnUqFKnUq1q9SrWrFq3cu3+6vUr2LBix5Ita/Ys2rRq17Jt6/Yt3Lhy59Kta/cu3rx6
+9/Lt6/cv4MCCBxMubPgw4sSKFzNu7Pgx5MiSJ1OubPky5syaN3Pu7Pkz6NCiR5Mubfo06tSqV7Nu
+7fo17NiyyyKRAKsXUtxGe/Ui4URMbjG6gw6/Pfs48uSbSeDGDc1Jr99Ciw9trpQ6x+LYlXPv7t3v
+I9t5SMAab11CHljQqPfmDc34bWjYSMyH5lu6QNuw6NuHJcGJE7bhlgd02Gy03XcJKrigWtDcAMso
+0CBhXXHjTScPLPKMAh+FsIjx4HO3AZedcU4gAQs2E8JiIhJvMPgijDGWZd0N71nn4Q3+5E1Hom4d
+StAbCRqxF9989MlzI4IyKrkkk009MoqAvL3xY4ajnFgdhhqu6GGHYpBXG3w8wvdIiUi02CSaaapZ
+FDQAXHmgcaNA15tQAvF2opwCGafbfen1CCdu/zlB3oDQPRjmmokquiijjTr6aFn2EfQepJVaeimm
+mWq6KaedevopqKGKOiqppZp6KqqpqspWHhtu5ARH+iU51Bu83Vgrb8AVh2svb2bXC67A3aejrQFC
+5QSlEpAJC5izTmergLfZSihxvA1KFK7S7QcgecIByxtzuIoHnRN+ugqhs0ORoJ+DscJ53bTw8Spc
+tdHpGJS3uG407IHWjtgUEgZuNMr+iOkhitS8Pca7q62+clTrtfty65+UQH7bi2383nbuKOnWye6h
+/r2blK0Y71kyosXey1G+vJVHrsHF/stUqxzBulHMTPEqL7SI8urwRhDrSGB06f34LXMXCzvxxhx1
+TJXAYrgqj0aI3qffjiQerN1GWhI13LobSUDtq1A9smyN+9640XPRzTwyoFmPDGV1G6kYtn/3ct31
+DSciccORAqPoMb6Hhtd11cXdACDWWmu999yNE8cR3mPD1+5TN4x4sxiJByUPuW+nDPfoVX5d9n76
+WQ432KoTKjg2hLNsuH7Mwb24sXLHPbnjdJ+eYd/MAn55yE1F7WrncIPudt2P667+m9dZwypP8H9j
+yDrlrt8Gu+xFjZJe2H//6TTqz5MOOYLDcT3czU6FGDDOtheHnnrYDTmk45jzjgTZI0MeIUeg0bHv
+ledpTknRit4jvpF5aSOCc9y7IBcm/cltfWwrHlMsVzN0wY0EwKEg9rbGu4NFMISlG10vCNiq7jnw
+RMjykO3C1EAUNU9MI5wgBrUGQLZtSDcgXAoB8WbA4nhQPTncG/789zvc7FA950Lf5FKYnhVSpWYm
+2g+9SKgiWvEmWrDY2QnTB8HmWEtyTEGWhVS0tqBY6FkuO1kXT0hCXL0BQ1B0HHt6ITUIHekp60LC
+zTw4vqD8sGS6Cpqt5ChG7Nn+ChuiUwr8SJCeR+RhkGxcGSLppLA43lEoEMOGjUbYyT3tcRR9dMof
+b9Y3S16wOomEoyZvuMj78caRULHiiSjJyvhx0WS6mVcYsRUdUCZxlM0p5SmnAsoHyYNsxeEfCYBW
+uiSGaZEorMrZCAaLtK0RR5g8nwjzd0S7wcqYTqOUE3EDq3I+5UPKypAzg4KEUViphiUcYwBzqEQb
+TkVzsPobh4SioW9O03yke9eHgonHKG6JnU5xJ5lIYEe4zbOeutuTQY1YFN00UYAkfMoyhRfQz42C
+oEjM6HZ086GOPlGUDF3nR51CT9scrVaI0txueEdN6J1LbpXrn1QcdDNbTan+OBqSpgh36jQzqi91
+YtPbCKnnN8DhhgQljSlSnJC2mq5tQui8qCX/Z8aR/RSrGaQnl76Vxafm1Hmy7FpPtQbQspqwrFW9
+KgtflbakvaF/Xt3ojpQ6sLHCR6rCmyhVZprWWq01b229Jz5N1zzrVW94ddXeXYEalc75apO9eAQY
+DQrMnf0MsJRjWl6JkqPATktO4LInLAkFLZUJM47bipgJX1Y047QplE95RPvexSv6vPKGPMtVyZJm
+r8fellhWeYPBIjit2L3WoMn9oq3EUNpe6lFiuJWjxpwDAN86BbhZ45UEqGs/1iYyubQ1rW7LddB2
+ukmn0FLvN/eGXuy6bLv+nsxufKMLXtSqZ7xmXRWCE5ymsQ2EsE5pJkHsIqmBfDUqExZIhQnD4PxY
+ZcN4o8uFSZDhp4R4xIIpyPWogmK7QHggVmmxnhQs4xnTuMY2vjGOc6zjHfO4xz7+MZCDLOQhE7nI
+Rj4yp6YUFAm4iCP8Q5xURIIbqm1Eyhmq2udAgg0BD4XKVGscAORBNZGQx8pj/oh8O5JiTzbZyaN4
+AwD6eqWRVBkkafvdRm7Q0zbN7F5hjsqZP3LlOoekymu+8ke2fBQqd8SoGhkJbujcES0bjNFDuQEA
+3nYkj+AU0SDJEqWNEiSRiDnUSMYLCYqn56AECcpC+RCnkarmLlftzwL+xTJHLM1kLmf5ym94k60N
+HZRg5xrXJPj1rIeSB49EF5BpE4NWhT0UW88T2a9eWR7aDItHPLDV0nYznLVFFEsX+9vDPrSuoWsU
+RntkWYPmCLGJDe8UH/tE5HayR1bWOTLxD9n3drV/1L1oXFs6SLI+tVs4azcARDfbVfs3NqwEyCTJ
++90V/ze56bNujVCNTuaO96HfPe9kC0XPq97XAzv3noqT/DbffMShBb6ie8kDziMPipze82akYrzW
+IW+5yPfzwFtXGVhXIjfIiZL0f28bG9wmzsqMxfSMD53Wvb45wuuCDf1kO4BbfziuD3T0sJ/b6kAP
+OsALbGIvZzrTH1/+88XDbuCKI4HhTLaZu7t2IpYTO72whZCr6j6igD0Cy/KWKNaJrni+oxvXvS0K
+u0F3KKTD/efxBg7TB8Xnhc9MDO+ZuuMNvPGrV9nEWXdLqgemN5iD/SgaL0rczZ322bN80FSOYdIT
+n3YSLKvid6+7wWrPeNLzUNlN/g/lJGr4nyNu7WSPvNIbL5TaR75z6aF82adN76mRffMRYzraac/8
+tBecoKd/i8LfMKLUMxr8/R6/SFxN5vDfm/oc10jAbJN7Qn+EPIGOs35U3Gpt06EIX0joBrHdGyVh
+S3rcwLKAjsjVHpPl3a19msUdoOzVH/NBX71hH7xh4KSBhI78m3n+bVuTgd//tV72QR7BiYSDnR9b
+BEgeCEzN2ZsKCgVo9YLpnR30KR7xPd643V/X/Nr+8SCujYLAyFvdhYQLUaAEYMjwxcrQ6dN+WImB
+tQio6V6GYAM2jB/9+Vz0+aDasaC0OYEp4VoRYp0EGNi/OUFIpMfm5ZptgB4hiR4ZlpvdvBkM0sUj
+6JmOjNqn/ZuRJEXsGaHZodzoWVqOFGEhyt+h+d3CZcwDAd/ZtZzH2Q0VahfyeVr/AV3NUWAQml0U
+4iEi3qGtdY63vV0Yjty9AeGKuMolbpP/kV3Qvd7okWL47WFbtIktKd69CZ5SFGIjkuKuJSKWtQgj
+hhy59WB2rMz+DTyIs73Hc9xMFFabr0iAg3EhKFqavDkBKIbi4lme9ImNzIkivXnEClbi0oWdbwQF
+aCHOI+TSG3weLaYbr4mhpc0TFeriWjhB1b3b//VCChqFMMZfQHKiohmjOzKiQYZeeogEA7hdrNRX
+tcWZRY0EFNpZhQVPUQRJhnFjoZHaHV4dRoagoAVaQprimrlhOpYksc0HJ0aE09VhpbkhAHRaCs5i
+ot0jPoYER/IjUAalUA4lURYlYCiXIYXF0ZSMyXTHUpbMC16FtzCl+SHGU/aMUWalVm4lV3alV34l
+WIalWI4lWZalWZ4lWqalcvwEW/qEF2JGCralXNLEW14GIM7+JV7ORGoAAJBchF/+JWA2xCjUnmZQ
+TUkFJmImJmIOZl1aRpAoJmRGZkVkxF5WZWZQTWNWBmaKxmaGRiqCxmeWRkRwJmFeZmnC5WnaJS1y
+RmiSxmiGRmeCRmx+xmx6Rmt2xm2KxmvCQgcwgm/+JnAGp3AOJ3EWp3EeJ3Imp29SQLFlJmXE5g/s
+gnROJ3VWp3VeJ3Zmp3ZuJ3d2p3T+QHOKRiqKgXKWp3meJ3oqZwdQzmqGxm5eQifEp3zOJ33Wp33e
+J37mp37uJ3/GJySEJ2wG2xMwAYEWqIEeKIImqIIuKIM2qIM+KIE+AYCCJpbJAz30J4ZmqIZuKH9e
+AntWJkf+wCeHjiiJlmh+/ifiOOdkxOaAQqiLviiMxqiDSmiKimeFXqiJ5qiOjqiH7kt7gsZ77qiQ
+Dul+ouiVqahksKiMLimTNmmD0uiR2miu4SiRVqmVdkKP7sePfkaQXqmXCqmR1mZnKKmTlqmZLimU
+iilr3uiXtmmOZmluuue9WMMg1Kmd3ime5qme7imf9qmf/img1qkCTChtBpsPvACiJqqiLiqjNqqj
+PiqkRqqkTiqi+gCh2iaWMYACBCqndqqnfiqgWsOHosZuLgA5nCqqpqqqriqrtqqrviqsxqqsnmoL
+XOqYBlsuxIKu7iqv9qqv/iqwBquwDiuxFquu5oKtrmn+rq3CrDarsz4rtMrqAozqaZRqtF4rtmYr
+rNZqjQZoiuWqsYaruI4ruRIrsnYrhS6rtq4ru2LrtPooiG6EqbYrvdbrtibrZsQmuJYrv/arvwbr
+uUapZ1Yos9qrwR7sqb6rlsYrLPjCKjwsxEasxE4sxVasxV4sxmasxj6sEeBrYQYbKYSCyI4syZas
+yZ4syqasyq4sy7asyJKCx2ZGKgqABWyszd4szuasxvoCtZrGbiKCFASt0A4t0Rat0R4t0iat0i4t
+0watDcQsaqZYNnwB1Vat1V4t1mat1m4t13at134t1WYD1KomRwgANTQt2qat2q4t0yJCz4rmvYio
+m87+7YaGaWpaBpmeqd7uLYOm6d1WRipaKN0ObobC6ZZ6RpcSruKe6NjirYDyLeRGboH6LZJGRuBS
+6eJmLn0aLsPKreZ+bifYbeVCRt5KrumaKeVKaddgLuhmLueS6r3IAgLMLu3Wru3eLu7mru7uLu/2
+ru/O7gQ0rmYGWx0EgfEeL/Imr/IuL/M2r/M+L/RGr/HWgfBSRioywO9mr/ZuL/f+riy8rWvey7wi
+LPm2K7cKrGzi6r+uL/v2a8Cq6XIQbPnO77oqbJwCqfjSr/5e6/nC78d+a/sGsACba/VORuAW7P4m
+8Kza7+F2hrUqMATfK7oWKgAPsAVf8LEWsGQccAT+d3CrMjDDjq8HjzA59O/fPqf6YrAKB/D7nrAB
+yy8JkzAIwy5HyG733jAO5/DuBu8Ee0ZsFq/0BrEQDzERQy/19jBuZqoOLzET5/D3wisNb4Tntu7i
+ii5ppliLnq4WN2nqDuyUUvHnvm61xi0Ya64VeytHZPEWrzGMdnG6rm4Zuy74jkbixvHgnnH6YjEb
+7/GLuvFnXK4dK64Y++y9AC3bHjIiJ3LSPi0Sc0ZsTi3YRrIkTzIle63YNnL8lu3ZKjInd/Ihuy0U
+jzFHOKzOlrIpn/LFdiwm/y9HhKzLvjIsx7IssyzMrrLMYhnNorIu77Ip82woEzJHiHAMR7AJj+7+
+Y+jrCifz+rawMTsGBw+zB8+wKMsrNHtwMV8xR+yrMm/zuDKz6mYIAlezAkszMFOzOEPwNaPxRmgz
+N7czAdsyZjzzOScwOcMtR0QDJ+SzPu8zP/ezP/8zQAe0QA80QedzImhwZMTmoVIqQze0Qz+0pFoq
+PJPtRjAALxQ0Rme0Rm80QUfDHOsmGQfyHSM06T4uH5/0k5L0YwCySNPtINuzFLc03eIxBacxSt+0
+gvoxpn6xTLvpS4dviPa0m9K0D5s0Th91hKq0M7OpUH/pT9NxSDf1lRL1reoxUiO1TicxT0u1lT41
+SHOEOmCBWI81WZe1WZ81Wqe1Wq81W7e1WO/+gFI3xg/PAl3XtV3fNV7ntV7vNV/3tV//NV0fMfr+
+MZbxgVsfNmIntmK7tTp8tJwG8zwrcDrncTa7s2W/82DvdNeEc2TPbz0DtTl3Nv1Odk2v82WfNrB6
+sxdvtmjr72dDNWS39vySdlFXMGrfdgZPtGPCsGyT72t/dWj39sHSdlVXNm7jtmq/MTgLt287Nv5y
+hDXkgHRPN3VXt3VfN3Znt3ZvN3d3t3RjQlwzRmzqQgOUt3mfN3qnt3qvN3u3t3u/N3yXty6E92Jc
+r3ffN37nt357t6j+MkzDwhRzNZjSt2KU7lWjdFYrKxwLeJV69WPHNIMTKVU7slEfOIITeGL+sHSE
+C6mDPzeEb/iOTni+VriF83GCZ/KCg7iOdjiXFrInvziMLy0jZ3ZxbwQkVzKO57iOb+0l07iCw4LZ
+xriQD7nQgvLCRjEsgAIvLzmTZ6wq+/iIp1gEzDKVV7mVr2wEYDhizGzNNrmXf/nDgoJzt3hsM7fB
+EjeF2/Zxn3ZyE7a6mrnB/vaDw4Iwwzm7onmUG/eas7mWH4Y823m7yrmH0zmg1yues7Jp7zmf6zbg
+8nah1++YI+694DNHV7qlX3pAHzSjo3CKLTREfzqoh/qjSjSUa8b1XjSmp7qqV7pH+zdoA7iKh3if
+G4aBlzgbn7ipM3WsmyiLS3pQ77qJijj+osOCGtv6rc96YWg4sPNopDtwVC87hwq7aVq1se8xrt/y
+VkP7hva6s/+6ttctshNGrVf76V57POv6txdus3PGbqJDCLw7vMe7vM87vde7vd87vue7vr87M4T7
+YMSmOyyDwA88wRe8wR88wie8wi88wze8wLuDv59YYe87xVe8xV/8vqPDum/GAz/6uh76tOu5ortz
+m2v2cns8pLs6bAc3yvNvxAcGMo+8ZZe8VrN2y2eroJM5y9/8s4J81Iq8zG8zzf+4PHA2zztrzvv6
+zh/9rPr8ZcR80HPz0KP4yTP9syZ9t2/EIHwA13e913892Ie92I892Ze92Z8914P3pq/+aLDJgNu/
+PdzHvdzPPd3Xvd3fPd7nPdy//FFmKtr/PeAHvuCj/SBsvGbUcbr3p7T//EYUO7mXO9//hbInfoca
+fmYgPuXr5+I/PYk/vumaO0VnCOtmfn5yO7s/O+kz7tonaed7fuSC/m5ne+rjp+lz/L2cAQvkvu7v
+Pu/3vu//PvAHv/APP/HnPgpEvl8APDIsP/M3v/M/P/RHv/RPP/VXv/UvP8SvvuXisjYUv/d/P/iH
+P/GfgeVjxm4qOZin/5I/uf+G/EZM+ZXHv/xTeZZrP2Rwufrnvy6LucoDN6FbPUCQEziQYEGBLWAl
+lAdAXkKHDyFGlDiRYkWLFzFaXNj+MGGuWB9BhhQ5kmRJkydRplT5MZfDjRlhxpQ5k2ZCEgBcrjK4
+k2dPnz+BBhU6cIHDmzWRJlWaFAAJhwuGRpU6lSpPhAoZLtW6devLjivBhhU7VmVLrBy5plUL86hC
+nVXhxpVrsKhNnGvx5s3Y9Olcv3+nXoXlVW/hvIQ9klW8mPFJs4OzGpastu3gt4AxZ95ZF1blyZ/X
+8k2ILkRp06dRp1a9mnVr169hl2bmMjJo2zUJu1u2m3dv37+BBxc+nHhx47vd0UZ7mznbu7D4xJY+
+nXr12OiMPm++faZoWJc6hRc/nnx58+fRp1e/nn14SMq5x69I+AkT+/fx59e/n3/+f///AQzQvifg
+k89AiCqTh572GGzQwQfZuyS7AymkyDvwIMxQww3Te++sCimkT8ARSSzRxAAJ/BBEAxNckMMXYcxQ
+QrtWrBGWC2PMUcf1PIRsORuZE/HEIYks0r8UfQSSuxZ3bNJJ8WbsTDsl5cPxyStz7JEwKm0T0sgv
+wTwRyS25/IxJLNHkMErPytzOO3Wsi1POOV1LpMA2PyNMl+P47NPPP43T5U48JauMAWboTFRROdWZ
+kFA3nUoIKs0opVQwMh89rLbEGuvUU7IewzTTtRK8rNJT/eKMzVEn825SVGGN69LaWMULsU9xzTWl
+UGmtlbLn5DE11mGjUnVKXwv+c5XYZaOa9Udku9pU12mpBYnXZ6FdqlRmuQXK2Gwlc3WVcckt19xz
+0U1X3XXZbdfdcY0YFNylCJMmlHvxzVffffnt199/AQ5Y4HulkXfepBK04N2FGW7YYXe/PTgv78SQ
+x+KLMc5Y44057tjjj0EO+WKDJaaJMJFRTlnllVEmuWSZKkOC5ZlprhlkMRx9OS3vdDa5155jEhVo
+jIQe2qJVjcYI6aRl4pnpi4p+OqKopX6I6qppxPqipbWuyOmuIboaa7GrJltqrsGWMm2YAGjb7bfh
+jlvuuemu2+678c4b27UXytvvvwEPXHC49077psERT1zxwNfOiITHIY9c8sn+Ka/c8ssxz1zzzaFp
+PCJoNg9d9NFJL33yzj232vTVWW+99NRhj1322Wmv3fbbcc9d9915793334EPXvjhiS/e+OORT175
+5Zlv3vnnoY9e+umpr97667HvXQwAUE9olBseygP1hZCK26ms+n7bKfIhgvuG7iVCHwAJHmLocMLT
+d7uh/AHoBecbsbU98D0ECaN4AwCwEakbwa0XCXEf/ML2QP61TYFGgeDUjkUR8rEvWrB4X/ZAmDQn
+POIhb6BfQrbHEQ46JA9OaNsokGChZ8lPIit0IEcK+IYYTkR+OnRIbVZoQ6w4BAk3aCAAJXK4HcIC
+CU4YRefk8QYSIjEikcn+4RIj6BBoOOGIN5zIFi8COpiQT4xc2WAXQ5jGkj3CCSwEwBJ7ERkbQkOK
+sNgiGts3w/1lUIi06kUF8wiZP/4QLUHko3bY9zNYmNCERkGjBLDhxSouZ5A11E4etKPIzgCSXhns
+ZEKw8T81jhJc0OCeTQbYmUfIcUpi6KIQCTlJyFhSlg6BpAwhs73/ARGRh7RaJKkYvjd+zyEjJCBH
+FEmrW9KShWjUJDYaIobHUZAEB1zfXaqJwP9lExv02+BdHoENBOahgf4TZzcTkodz5gGFccTGKO4y
+Ck6Skp6jMiYssMFOWIghkqysCAmAGT89zhKDtRwiD/fYmSPy0mq+TEj+AZH5LGJicoeaTOZyYElQ
+O5IAi4pEwikXMgpYYPIGSMCkxXCSQlg8ooHywEbnjvLNlb50pW27US86Z8DBvGGPnXNCSbcITjzW
+k6iEYuM+31DMhvhTIjkUZRXfttA9Ek6jsaQNLsmHBHQylDZww8rbQinJEuqzjsFsH9wiRauMTvCE
+Ym3oQanIEPJt7xFYnJBM0ZkQF97ohOSTp0NuQILtoU4Cd8loURELpI+CTqSdGSBTEfSGJ3ptoLDs
+43KWKVCCRvGjhewlM5l4g8b2CpNvayMs7mlBs1o1IZnN4kN1ytq3ajQycr0LOQHgBHaK4QZv6EUc
+Z0m+2sCTiuSLo/r+OMi+wyaWuSC6QTj1edy3VTUhN3DCUxEqS8sey4/z9CIHA8tVuM7WJlKFyCga
+O9JTAlSYMbzoQypZ0KvKdr4crC1KIYJJMbwhUjIlX15hAVx//vUhpiSsYT3ZXAUfCJJJraUN8+DD
+i/yMhvKtHw4NaNcLaxQJB/QseUFMAvMS8Q36TEgdtfpBeTghrdiyYoYnwsECpnK1P8SZfSNKvnBC
+kXt1hEYcZYYT8gG0c6vEiT+juD+eBhioe13pUBccZfl8NL0bhoz67uc2XAZygi1F6wLd9kGsameV
+H+6q+qoaxc7FTQIOdsgoTptDBCpQbg58m5gteeeO7k23tM0xTgr+2DZ0QnLOb+CpkLEpThYfWYV3
+IXRekRBHEx5xFFOU8qUxbbRHeJcrYuhem5fyhgtmmtSlRlYTDUNkO7JYKRKosqlhjaffznrWkxEx
+rX+L3ZfhutZJecSouYKEbPJXwzArdqyRnWxlL5vZzXb2s6EdbWlPm9rVtva1sZ1tbfOa29329rfB
+HW5xj5vcbYWdK8mdbnWvm93s1nXj0N1uec+b3urWHQLrnW997/trjVsIF/cdcIGn24WFA9u/B55w
+hXdbnPfmdNr6zTdNps1sT6s409AGu4ivbeMHn7jHDd61iyct46nrONhOrrWRG23lQ2s50EruOe+M
+QBI1t/nNcZ7+c53vnOc99/nPgW7z7qV8bLWJwSmQnnSlL53pTXf606EedalPHekxcBnFaxN0rW+d
+610POjBydjvvMCJNZc8QPdBC9LLVpj5hcvvb/zOmj4u8NpAw+90btKYEx27sePf7etD+w4fTHS1t
+h/vhEc8EuYdc5XX/++PPo3eHO4TskLe8eALvwME3vvCJ9/zbFz87wtj98peXfO76XnrLZ/5Gmy96
+5z8feyOFXnajV73lT48774jCBb33/e+BH3zhD5/4xTf+8ZHvez4IXvS1oQMHoB996U+f+tW3/vWx
+n33tbx/6dLg6yB0ChuSPn/zlNz/yTRF223knBdVyf65CkXb+168dLa/q1v0LwpmX94wwk3j//zvl
+MWKucdgPAA1QMeKP+WqvNuwP/xxQ/+aO8xzC/w6wAsFCAPdO4xSo/SywA1EiATWv+erPAUlQICCQ
+8V5vAj1wBUsCAycvITiQBWXwI0Cw9USwL0rwAb+P8FRwBmfQBVFPgUShFoiwCI3wCJEwCZVwCZmw
+CZ3wCYuQARQwdgijAjThCrEwC7VwC7mwC73wC8EwDMXwCitgByUwIbIACtVwDdmwDZ+wANSvdlLv
+9v6O9dROarxE9vSwRGiPCh2PDv8u98ROgSoPEPHODucPD9luDxmRRPoQdmzPEPFOENePECXxEOXv
+BhPC8Br+sRP74xFTJxIvsewoUQ4VqBKkIBVVcRVZsRVd8RVhMRZlcRZpMRWpQQCmEBJrIxu+oBd9
+8ReBMRiFcRiJsRiN8RiRsRezwQxTMCFsoBahMRqlcRppMRPikHa8QxkGZhu5sRu9UWBAABdDcAHR
+whAe5hzRMR3ZxRCYkf4cYgO+MR7lcR4BJgKucXYK0AdlsAbv0OIYMAd1UEX8EC0oUB9XEAh1bwMN
+kgX5MRH9cQQB8v5OUBNhoSAX0gIRchAdIgYvsgIbkiIbMCKJZSLJsQc7sgIzshIdAhWGoCVd8iVh
+MiZlciZpsiZt8iZxsiVfQQrHcSAdogxSISiFciiJsij+jfIokTIplXIpmTIoy6AdFREtjiEnqbIq
+rfIqcXId7lF25nAU0QQRKZITPXEs8QMUPUcUvRJLShEbLTEtvzITS3ITyXIuyxIqH9IhSM8tr2Qt
+8bEt9fJJwDIuYUEs6dITzdLf/vAvnYQvudIvFXNHAtMn5bIw5/IwJQ4t8vIxdYQx+U4Ix+EzQTM0
+RXM0SbM0TfM0UTM1VRM0l68ndREt6KAGZHM2abM2bfM2cTM3dXM3ebM3ZdP7BPI1w281ibM4jfM4
+VTP9siYhN/IkLfAjBTMkRTJWSFIyK9I5UXIrO7M5sdMAodM6pXM6UaU6hTMhLLI73S8lTZE70fP9
+vrP+PGEhPMWzUsgzFGvjPNtzWtSTLdkzP6nlPe0TIudzWOrzLO/TP9NTOzXQIY6gBBz0QSE0QiV0
+Qim0Qi30QjE0Qx+UJ21QMBXhAUA0REV0REm0RE30RFE0RVV0RUFUEeySaQijCDR0Rmm0Rm00Q+Fw
+OTUyIQpRM3MkMuGTMCmTES0T6zDTR3eEMxeUR5FUR4A0QB1CSIdUD4sU/BIiM5tUTRTU5BwzSzfk
+SQ0U9qa0E6uUB6/US2FESbnUIRrBEtz0TeE0TuV0Tum0Tu30TvE0T930BMSxQ60zDlghUAV1UAm1
+UA31UBE1URV1URk1UOPgRZOGME5ATym1Ui31UvP+lAi2VOYUSBvp8VNBNR7DMRehNCHMUR1RNVXP
+kR2Ds1RhAR5DNVZltR43lQAVEkH/Ey7Bc0BHElJZ7kBxVT9rleNuNVjhT1fhUz55FTMKFDEJ0lh1
+ZT/7sj+htVMANExxcFnH01ddDlir1VOktTFXkhvItVzN9VzRNV3VdV3ZtV3d9V3JdRw4tB9htDbK
+IAPwNV/1dV/5tV/99V8BNmAFdmDx9SlbFVsT4hjgdWEZtmEd9l3/YFghrkvRFELA1FmjdEwNk1uB
+Bi0rFkLUlFMp72O/FFldVUo11vPK9AxhAUtJNu8kFuUo9mXb42IvM2NTlkg5lv8Sk2ZhVkdVkkn+
+fdZBbNZIcTZnqXRndcZjh3Y9QtZWx/VhpXZqqZZd5ZVUERYW7pVgubZrvfZrBdZgk0QwFbZqzfZs
+pTZigXY9YfBbP+VaMVZStBVWmvVmzdNtwTVmuyYf8ZYx4NZu43Nut/Vg4/Y6+5YxwnU72/ZwF+Nv
+jVZuBZc+lfZl+o9xFyNxlxQWPHVWObdzQ2FUXdNVT1VVSbd014VVx9Y6YdVzWTdU7XFt+TMh2hRT
+abd2bddO+RRrCxdQG7V3ffd3gXdRH5VwAXdSb/d4kZd2NRV2p1Vom7ZmTTZrURZp4W5lm7Fln5dB
+npZYRzZ72aNorXQwqTdpifdxsdd7nVZvtab+K9H3PMDXTMV3fGPPet3xTNs3PbZ3Yh1iCN2wf/33
+f5twXh2yXtHCCsfwgBE4gRU4DMuwfMM3DQE4giW4f3NUbYKQWi0XLBw3fJU1cuOibs0XPzO4LNQX
+a/h2hDU4egu3gz24KkA4fEUYhR2jhKvmhGU4JTYYflm4hafiheE3hm+YJDB3TRc3iHFYhQF3h3m4
+WCa3ZCrXiHeFhqVm95Cziq34ilOzNf0UPmPTN734i8E4jHkTOFMXPsEAi9E4ja1YOS2YOZ33fs3j
+fVl2euUXTOg3KvESjtEjf2W2e/W4POT4eum4jmeviSWGaf+4E/h4b2f2jwO5fuOXkBHvju/+0n4T
+eTwWeX0bWY8fGY8nU5IPj5IJOI8vGZOl+Gm8gyWxcpVZuZVrcid1F3CBsilpuZZt+ZaXUmz3b2lr
+Yypd+ZeBeZW1knnFtYih2CRymGWVeImFwodZFoiPmSVOmWlsOJpFIpmvd5mZ2VsM+WCe2JqFeJqT
+pprBmQaR2Hy1eZt9wpmvF5qjeYhFNiE2t3XpWR5Bd4tF13T1eZ/JBXV3mXJrY3XreaC78XXbeEdh
+ARWpcaEZuqFj8RZj2Xx5MRkpuqIt+qKPcRkdGH6f0aE9+qMX2hqJWXFhoUdLuZMrOZJBGfS6eV4Q
++Y8z2YQ3GY5RepQ/eaXdTpQjtWdLOab+a3im77emd1pMcTpMdPpXj7SUoUScjWb3JvipofoJBZgi
+DXiBrfqqsdoLG7iMXRWCo/qrwboWKngAudeYyxkksBmS01mdeYKdIdmdjxmeodaszzoW0tqTA5et
+5cKt8RquoViuyxoWOLKu7fqcOViv97qlweWbCTsWAFt/6fqs7zql1xqxCYKvU9qvjfix+zghliAF
+QDu0RXu0Sbu0Tfu0UTu1VXu1Q1uU6HWoHcIeZHu2abu2bfu2cTu3dXu3ebu3aVuxs4UwlIG1ibu4
+jfu4V9sVmHpoXnucBxi2BRM+YYesIbuYrVO6XXW6M5CIrRu7s9a7G4e6Ue6PXKe8zdv+vJu7W+Xp
+vNm7vUUHnlBw7dbbvem7vicHuFBvcfR7v/mbgpqvvwE8wAEnvhVRwA38wOdG2xR8wRm8wR38wSE8
+wiV8wim8wi38wjE8wzV8wzm8wz38w0E8xEV8xEm8xE38xFE8xVV8xVm8xV38xWE8sRrJltyMifpr
+uy2EgQgqbrwMg9wmnypC2A5IsioqbrTIgObs2MAsqvgHz2L8yZmDBGhMtB6iLYSIt9qmpLZstn5G
+iDiozUwsIuCsc6DBiNxKiySrc8TACU6LsuZr1aAMyuW8MLZnhz7KxCIMwSLinZCgieK8xhLpWbxc
+O9gruxLClHBGkXqBxrTK0gy9qjD+ac4l/TPyKsK0qJv0HCJ6YYcOq8vvwtMtzI5OSSKI3CXc61k+
+CruOys3Hi5wm/dULQ8q9R4F64RGUa+8KXbNeC9Rfi75oPLcEy9cH3SLEC3SUHNaRHSnqfJG2CXxu
+fSKEvHCMfMe/bNitLMZIwIVGS8etfcvZKtnBnSucQALUSSF86Nkj4hF8C9jOfMcF/VhWyMAwQr9q
+LNUhIpyI3cyYKLbCvd+R4hFEK1KyrG3wC0GgacLevd27vTMCqor2rMaYzCF6waUGT7yoy98xPiNM
+Kaxey4bsHeHli9fJC8wp4rc6p4BOS5HoaLJWScK8/TlmLONlPiacoOHri4EmaMv+56vO+MfLfjzM
+I0LO0tzOqMqOkLx/AOzRm/zYZ77pdUcMHN3ppX7qqR7Cbw3X3k0tJIDbzE0puq3qwT7sxX7syb7s
+zf7s0T7t1X7t2f7B7fvt4R5y2B1sQCfu7Z6+517k7n7v2fveEPzv/57A/RHwCV/ABR/jCj/x+/sF
+rzu7Hd9zxBvxGR+8AZfyDQfHsSbyNZkiLT98tZt2NF+mHaJibKb0TZ9mgBtaTub0Wb/1Qyb1kSVm
+XH/2aR9jRCn0f9ohLoEeeL/3ff/3gT/4hX/4ib/4jf/4eb8PYN9XCOMZquD5oT/6pX/6qb/6rf/6
+sT/7tf/5n2H5ayVBSgH5xX/+/Mm//I/fp6dYgTBEqTtBSyJQkIuapTdaa86E/dEfldWf/d3D+1kl
+D+O/kAECFix5AOQJPIgwocKFDBs6fAgx4kMSAA7Ko9cpo8aNHDt6/AgypMiRJDNeOkhRosqVLFu6
+bAiAxMFLJWvavImTJCSLBV/6/AlUJUGDAp8wOYo0qdKlTJs6fQo1qtSjT3gSDYo1a9CUAi/m/Ao2
+rMiTArlqPYv2Z8yDBzy4fQs3rty5dOvavYs3r9tFVtP6/ctw6MFw4AobPow4seLFjBs7fgy5cLi+
+gCsDNstgmN7NnDt7znsAZUXLpEmvFUhTrOrVX3d27Vk6NlbBRafavo07t9T+qq+vyv7t0qxX1sSL
+jxUNPDnW07BSG38OvZPrgbCVW4dIG5ZR3dy7e3/Km7rv6+QVCscYPT1xsrDMln/vkLlz9fTBTs8O
+H3727d/7+9cdHn75lXdefQZ+xZ57Ay4Ii3wHPmjTfdUxeN1+/12IYVQBTkihcgVCCOJxZY3W4YDM
+BfJZiiqueNcwlJWoXHbfhEFjjTbeiGOOOu7IY48+/kjjNy/CCJxZfLCIZJIrBoIckfA5GGKUHkk4
+npOlWZhhllpSNaSVpX0oZZgmNenldVCKGSaVZcqG5ZZu/rdhlWv+BSaaUSZI4pzAnWlniGrqaVmb
+bw7aXZyAWlZnnxDieej+njIJNA89kk5KaaWWXopppppuymmnkvbRZaNnZZfNF6aeimqqqq7Kaquu
+vgprrKZmE6qoWZklQCme7sprr752Og+ZtlrG3Dx3HItsssouy2yzzj4LbbTSHktMrcMClZ0WVWzL
+bbfefgtuuOKOS2655m6rhbXX+oQrIdO+C2+88kob7IjrEvtoc4pG+ee9s1XHH6EC42aov1gluq+B
+jBrsF58JG9gvwz4JOnDFGqorsUQIP6zewhlr5TDH6kX8MUsUW4wyUwWX3NLGIkPnMctAMXdAOzbf
+jHPOOu/Mc88+/wx00DbPgbHMgVUHhxxKL810004/DXXUUk9NddVKw1H+tNHmkcgAFEJ/DXbYYgcd
+mr1aq5XvfC+nR/LZDp2cctxc9ua2xiQOt3bHwta9Ush5G9c23wrBLXfKKwvOkMt/sxYz4hH5vThr
+gTtOd22FX87E4ZQjpHjkYjW+OUxpew7d5JQTjvnAmofe3t3okV4c6KwrdKKStt+Ol4uVz747YZH9
+Dnzwwj822e68G4l78srDxaTZvDMEOez2Zc036qkTunronUuPk+zPCxQ99ziZ7rj117+Z/ebbi1+T
+99+Hz35N5CNu/vlbpk/5+vGP5P7z8O8/kvkJrn72yxL+HKc/AIKkf7xjzjkGAMEISnCCFKygBS+I
+wQxqcIMQbAX16pb+HXN0YYQkLKEJT4jCFKpwhSxsoQtHaI4Pug0zzuCgDW+Iwxxu8Bx7+95B/qdA
+kAiwegArIMoOiLgEBrEjDJwdEJfYkSGCsIhGrBgSBadEKGqkiax7ohY1IkW3EbCKcJLh2bL4RS6G
+rli/aqMb37gpUBlvdqSSlR3viMc8xopWc2QdrnQFx0AKso31ap0PF8IcREhhkYxspCMfCclISnKS
+lKykJRdpAzNqLTvXOJcnPwnKUJrrGpo0Gq6occlUqnKVrLQkInp4SC9+UTqllNkYydifK/INjVpU
+4+Zk+cUwnu2WuPSOLuvGSyj6knLA1KIwN0nFYqKvlixL5hKX6Tj+B2pgm9zspje/Cc5winOc5Cyn
+ObfpwT6GLju6aIA73wnPeMpznvSspz3vic98ulMX1CwZDc8J0IAKdKDm5KHzDvnDfC2AHAxtqEMf
+CtGISnSiFK2oRS/K0Bb082PZyUUsPgrSkIp0pCQtqUlPitKUqvSjudhoxoSzCozKdKY0relFFwBL
+HzJnoTbtqU9/SlGNqnNzHV2pUY+K1KSqtKVDzd/dYgrUqEq1pzg9KEIbpNCpanWrFhWqeHxYVKWK
+daxkPSlTv/o9mHJ1rWxtaFUNedWEHoSnba3rVL0qINaFtax87atSz5pX7T3VroSN6lsVhFDm+MEN
+jG2sYx8L2cj+SnaylK2sZS/LWC+4VGLZiUIzPgva0Ip2tKQtrWlPi9rUqvazUdgsw4yE2djKdra0
+xawfcvq+rBZ2tzbFK4f0Wh2P+nW4xEUpYH8rWItAlbfMxehh83TVnTZ3ul11rcH2Wtzsave4clLf
+YKkL3og+N65yFQhdw4tecvi2u6cLrnbfm13u+lCt6U3veMmL1bnWN73rBat74Qvgvso3rd/dL3jv
+S17m8EIcDG6wgx8M4QhLeMIUrrCFL8zgT1jXX9lRwSQ+DOIQi3jEJC6xiU+M4hSr+MMq2PC9MLMC
+DMt4xjSu8YV5gVv/6dbA1O3v97Ab4CAndcDPoy+Pp4vguEr+98jT9fHzgCzkKC/VxesyMpN5m+To
+7vjKu3Uy76As5TCXlMjHKzCXC5vlxOaLADpos5vfDOc4y3nOdK6zne+M5zYbgMrXyo4QqADoQAt6
+0IQutKEPjehEK3rRgBYCn4eFKxrkedKUrrSl8UyAHDcwX6BYhac/DepQi3rUpC61qU+N6lR72giP
+tlV2IhCKWMt61rSuta1vjetc63rXvI51BFotKlxZQNXELraxj51qUGjaiVs+s129TMf/innaYwZ2
+o6zs7LqmOZbNzjZboQ3cqwiX2uQOKZlnh21vr3XbOu22urcK7nVKu9zlPrcfzfxurrI7twe5hSf+
+DfCAC3z+4AQvuMEPjvCEK/zfxbD2obIDhldIfOIUr7jFL47xjGt84xzvuMTB4HBAYSYBCy+5yU+O
+coXfYtlddHe+pRpvos6b3tS2d3K7styXb3XfOtavzrka8/aKm+b0trl3lftzfbN8jS5Pek+DXr6Z
+Ez3MRncq0p0+VZ5v2udYjyrU6Sf1qUe56gjEd9epuvRf5svfKW+7299+8IY3NepXcQAg7o73vOt9
+73zvu9//DvjAC/7uDgi5nkYO98Qr3u0rt6qauX52n359gGEXe5DJnkSzR56mWmc25Ddf08kTceiW
+FzPmsah50Ds37cxsuuorKvopkr70Uj79LlP/+op2vuX+B+k0sn8P/OCbmtVzB/tV1NCG5Ct/+cxv
+vvOfD/3oS3/61E++Ggw/J2ELf/vcB76yHc/tg7D50uQvv/nrvOfiU/4qQui1+98P//jz2tHqv/1B
+BCDp8+t//+TPNPjb/Xm5d1GxJ0aVR3vvZXvIhHsCKFG7x3QByIBBhX1rAmYHiIATWCbpFoET5YBq
+B4EbGFEEOEwGaIHFlYAztIAg6Fasl035Ug9eAIMxKIMzSIM1aIM3iIM5qIM7CIOJgIFekh3rEABD
+SIRFaIRHiIRJqIRLyIRN6IRDuA4/aCWYMQE8aIVXiIVZuIP1wIKIs2QqKIH1J3sHMW4lCGAneEYp
+CIb+Hdh6HwiGDSWC0DR7ZghfaKg1GviGK/h//GZeeThRcWg0FUiHw2WHpqSGKsiGLeiGeQiItkSC
+g8hXhSgzeOiHieiF+bIF9qCJm8iJneiJnwiKoSiKo0iKpaiJgiCFTpIdrpACreiKrwiLsSiLs0iL
+tWiLt4iLregKqUgkZiEGpgiMwSiMw2iKW9CFgsMcX4ZcMsdedDdf0IVu0Bh+P7aMQudfzZh5h4RY
+0/hk1eiM1IiNqKeN0qhTvUAC54iO6aiO68iO7eiO7wiP8SiP7zgK3gh2ozCP+aiP+8iP/XiO9RiO
+t+ePA0mQBamPvUCO7wMAC8mQDemQDwmRESmRE0kokRVpkRYZkFN0kRvJkR3pkR/pkBmJgiBJkiVp
+kh6JXympkivJkm4TEAA7
diff --git a/Documentation/DocBook/media/nv12mt.gif.b64 b/Documentation/DocBook/media/nv12mt.gif.b64
new file mode 100644 (file)
index 0000000..083a7c8
--- /dev/null
@@ -0,0 +1,37 @@
+R0lGODlhFgFnAMZnAAAAAAYCAgAASAwFBQAAdEgAACQODkgASCoQEEgAdHQAADATEjUVFHQASDsX
+F3QAdE0eHVMhIABISABInEhIAIM0Mok2NI84Nk9PT5o9O5xIAHRInFlZWaxEQbhJRgB0v75LSLhQ
+TbRTUcBRTrBXVatcWsJWVKdfXW9vb6VhX0h0v8RcWZhpaJJubpBwb8ZiX8ZiYI5zc4t1dYd4eMhn
+Zb90AIN8fH9/f8pracpta8ttasxzcM51dM52dM53dc94dkic39F+fNOEgpmZmdWJh9ePjdiTkt+c
+SNuamd2gnt6lo3S//5y/nOCqqeKwr+S1tOa7uv+/dOjBwOrGxuzKye3KyuzMy5zf/7/fnO/S0fHX
+1//fnPPd3fTe3vXj4vfo6Pnu7r////v09N////35+f//v///3///////////////////////////
+/////////////////////////////////////////////////////////////////////////yH+
+FE5WMTJNVCBtZW1vcnkgbGF5b3V0ACwAAAAAFgFnAAAH/oBngoOEhYaHiImKi4yNjo+QkZKTlJWW
+l5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGmkM3ysvMzc7P
+0NHS0CjT1tfY19XZ3N3Y297h4sxDlQDj6OLn6ezZ6+3w0u/x9M0A5r/3vvq9/Lz+kQDqEpiLIC6D
+txAyUliLIS2HsyDKkniIIiyLrzC60tiKoyCPq0CqEpmKJCqQJk+lNLWyVEtSKPPJ3Ddz0stRN0Xl
+DLUTVEyaQPvVlNTzU1FPRzsl5fRTaNB/QwNGHTi1IL6nu5Zu0qqpKVSsVME+4pqJLCazl9Ba8oqp
+jAIA/gTCIOXkVsAVo52OAABgV6kmMxr2Cgbil9LLGh/OIJ6r6QgBLAfuMm48YYzPT1siF7a5qUyD
+u1HibtaUWfLoS55NT+a0+DSklqXPxK5EJkuhm7NdV8pMYW9i3YJsT8q99Wqm2MQn/cihZRBuzasv
+RenrdgnwM8uFQzpSOfrrTcihW5KyogiYM89VF9cUWq7i3+sRTVlB5Lyj6ngNd/58pn0mMUmY4ER6
++R2nGWCEMbUIGQE2QUYj3Fnm3VibIPgeJ178kEFz4Imn4F8aEJbcWY18EcQLViziVoITOvLSFgXA
+5R4iVvxg44045oijByAU0QMIQAYppJAwPHhIFILx/qUeieDFCIB1igjBg45U4nhBlVSaAEIQYiTi
+2IzXLbTKF1mUaeaZaJr5RAc5aKeIFStw0RErVehARZp4mrlAnmlCscILU8yp3y5iILECBI7AKaeg
+q3DxQ5cuMgLgCg5uZBwuTpiAhBgQKZqRK45CKqYiftZ30aW1WEFDEF58xIinn4L6aCMIabHDDhye
+OqgtYgSRonOLwBqrrKImglAQUjyEalg0xjlRLKEuotayFIoliLC6whKtsVVFai222Wo7KyLT7kpU
+VeCGK26xhJTLmblZGZKuuutW1C2tUc1Lb7233TuqU9c6m9At2wJrLb68JEEGP/rG4u4iBaPnr7S8
+/ohhgsRnNOxwLgU/LJVh9YR8Qwsl3HCOCyHIIDI986yMjgwkzKBMyy63g1LN8JzAgskoq4wzOzT/
+3E0MIIiQggM2CG0ztbW88MUZDAgc7y5aFlHBCDsk4ebA8NryxQsZd7DoV7oIQcQKBpyhRRM/jOCE
+VV3X8kQRcKYtCBnsNsQLFHSLPQjecL+bi9lxApCFEjuM0ASzuXwNtdSMf5yLlkQEAcIOSmzN9S5O
+A6Dxs3HPogUIOSBhRQATy1LEE/d8vq+3t5BhhH0YA6zLFELo47qlocNChhC/unowLRYzDLnevbvy
+e/DC265LEqgPsntITCsPvCEef4fV9CVVz8ry/vYOjzwh3KvkvSrgh+985AGPDbrgvl9PbuoRNev+
+6wjHzzz29L8v7/G8g18r0sct8SkrEeXTyfkigaS9sIgRBCwge/bSlzBNAjAV/BACAXgIGAmmOxo8
+lybK8AC5TGdJh4igBAuhOUaUYQOWqQEIMVGb2jVGAh6iRA0N9iYOFmJE8RFhJ/CzIPn9qxDZoYR/
+NLEcBNClAUzIISWWw6FO+XAQQOzKAocjxUKoUBEImY+pIAEY+GhCCh0wT2OAkEVJkMc8EtGYB/cC
+pRBKjjVmTKER85fCBhlpEQ2c4SYGEKC3XWILCQhDGyUBIBNE4BG7O0IGtZg8SkRIEV+k2CJM/oSi
+R0gShWs5Q4aYY4kaiKiLlvDCBUjZCNcRMYh3zMSXFuEDHGAJS1e65Y20xKVGvPJNurTSjUbQox8N
+6ZhAosEf3ZIkADxQXsHU0QWI6SNkIrNIKlJAHSkpwEvIUEKK6AKfxrmncZbJT4BSxBZUIIgTlsic
+ZyrnE1bQJkws8gxkgieaIEDPFkaiBlCapR21dxwn7UWQTErEpCqlCMBQEJRrKdQKnkAaVFKiUB2g
+aEEPCk5YEpRshygV7VwRAU3lbRaZQsIA+qc+kBLCVriKhaos0CpcqIpVNpxaNwNXCGTJoldWyJ5C
+fcVDl35Up0blKVJjyT6lNvUgW/TfUp+6jzkhJhWqBqxfJQ+4Pqd6FXZXrepUv8rHsWK1q2e1qlnF
+SlVbsKWt4wurW6O6saxKFa5gZCn+5mrXiijNZn8FWmDTEbTBuqMSHDDsODCgWHEwtrHeeCxkucGB
+Y1j2spjNrGY3y9nOevazoA2taEdL2tKa9rSoTa1qV8va1rr2tbCNrWxnS9va2va2uM3tLQIBADs=
diff --git a/Documentation/DocBook/media/nv12mt_example.gif.b64 b/Documentation/DocBook/media/nv12mt_example.gif.b64
new file mode 100644 (file)
index 0000000..a512078
--- /dev/null
@@ -0,0 +1,121 @@
+R0lGODlhoAHkAOe1AAAAAAAASAAAdEgAAEgASEgAdBgYGHQAABoaGnQASHQAdC0eHigoKEIlJEYm
+JS4uLlssKzY2NgBISFIyMQBInEBAQEhBQUhIAFBBQVhCQkhISF5DQ2NDQmdDQ3NEQ05OToNGRHhJ
+SJxIAItHRY9HRXRInJdIRlpaWppLSaJJRqpJR7BIRa5KR2NfX7JKR2BgYGxdXWleXmZfX31ZWXJc
+XHpaWQB0v29dXLZKSHhbWolXVpVUU5JVU55SUJhUUqdQTrpLSK9OTKRRT6FSULRNS7hMSrVNSr5L
+SL9MSr1OS7xQTsBRTrtTUL5WU7lYVsJWVEh0v7deW4pqab5dW8RcWbdgXrZjYcZgXnd3d8ZiX8Zi
+YL9lY7RoZshnZb90ALJubLFwb8prabBzccpta79wbsttaqx6ecxzcKt8e4aGhr93dc10cs51dM52
+dImJib97ec53dc94dqiEhKeHhkic39F+fKeKiaWPj9OEgqSSkb6PjtWJh5qamqGamqCcnNePjZ+f
+n9iTkr6amtiUktmVk9+cSL6enduamb+jo92gnr+pqd6lo7Ozs7+wsHS//7W1tZy/nOCqqbm5ub+4
+uOKwr+S1tL+/v9+/dOa7uv+/dOjBwOrGxuzKye3KyuzMy5zf/7/fnO/S0d/fnPHX1+Dg4P/fnPPd
+3fTe3vXj4vfo6L//v+/v7/nu7r///9//v/v09N//39////35+f//v///3///////////////////
+////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////yH+EUNyZWF0ZWQgd2l0aCBH
+SU1QACwAAAAAoAHkAAAI/gBrCRxIsKDBgwgTKlzIsKHDhxAjSpxIsaLFixgzatzIsaPHjyBDihxJ
+sqTJkyhTqlzJsqXLlzBjypxJs6bNmzhz6tzJs6fPn0CDCh1KtKjRo0iTKl3KtKnTp1CjSp1KtapV
+h6QkWdrKtavXr2DDih0rlpFWsmjTqkVrdq3bt27bwp1L16vcunjn3s3LNy2jVRU/MKhAuLDhw4gT
+K17MeDGCwY0jS54c+THly5gvW87MufPhzZ5DcwYturRkBGkqvgAEdPVP169Z+4Q9W3ZP2hJx89St
+k3dv27uBB4+tWvhO3ziRJzeeU/lN5zWhK5ROk7pM69eZL2+t/Xl3hthj/oZ/OZ789+jn0ROnWN5l
+e5bv4aefGX9l/ZTx7+Ofn537+tr/5cZffwAGeNyA4iFoXnH+FejgcAb+xmCEzSm44IMQ3mbhQPqh
+1KFJH4K4oXwNajghhhJSuJ2K3p1oIoopvgjjihOFWJKNI+GY44j28dgji+D5qJKOIRFZpJAeIpkk
+kAvZOMsBAAjQykdOHhDAJ1QqSVAhAABwpUcf0iJCl2TS0ZGNmZDpSJYcpekllmfyaKMXNtRCZ0av
+jEJQiIUIAAoBcMbJUSEUxHJkQa+wglEpgGKUJ4da1vLkmn1OiZEsoUC6USkDrJmJlIKyF+ksCWD5
+qaUWydJFHagIhCOj/oFyFCKpsYIp3CZPRCKLRXdeumqrs5Zay6kaxTGGniESS2uoNUYKay3PZhQJ
+FYnI8mqjtm5KwAVd1pltQangkYUnFEUrLbUtRGqnAKocsOZGmlDxRwyRZvLlpMwKqC2W5mLEyh5U
+zKAutNjme5G9WOJr8ECerJqKRIQautG/RsjRkRcAFNrRK4kUYQZHGHt5wbsb5edso/1mFEoQVrS6
+L5saEWunt7J+N221DyncUQ5OsJrRk2Z6AWpHN1RxbEc6a2TyRsvKjJAncUQt9dRUT/3DEUgcofXW
+XHc9CEMpK30ylmKaaRAebFSt9to/VLG21F0cQYUmDkXMENRvs13F/hFLXNH131wvgpCy7t6dt9pt
+L3HEH20ADrgWuyrktNguXlT2zAulEsrmnHfueec6KNEFuQt5QoUpYBdc80aXh11LJ2Vw8vnss+dg
+B+2cH3IEHg8zBHRDmuNOew5mPDE6RggTXOtBwQvveQ5oUDFGpnefvtCTNJcsp7qcRomqRq8Q4nFD
+pqMuOZlvLmxR9wCQbJApcbzSbEKoGEt9Q5V+9IoPSlCyEZddch/4dsCESjikfAl5UrdgNj+eUOIJ
+h5BBehB4oZTAT34R8c0rDvEEA8bkgTvog09AKELyWa8lS9NJw3wGHQpW0ILxy6BxHngIDL5khagw
+EkdwSB0XkkhU/jpBxRhIVwvn+NA9A4PIBSGiG0z4LCZCJJ0OwVcHKU7whEis3IEScsQstmSJDpmi
++ipUOix6sYEz6uIZWQLGIDFJPVw04xplWCKCqHGOK2njdJJ4KBbd8UdAjNAfUchHiegRIWJcnYoG
+OaTt1bEWjPwhTA5pkERq75ECieR+tBgjSMqRPoWcCCX3FMpvoUiTmwykg1AJSJmM0lWlHCONMvnJ
+BHHyJtWCDStb6coYHsSSlPsJD/xgx1raUpU6ecUTisiaXfKylzYk5Rtn8ooi2MaZS0JmTjaBB2Zi
+s5E3McUaeifNGd1kE0OQzTdPEp8TYKEv8ByLGvRgCQ1IoQmK/oinPr+igXfuE56IOMIU3iCISWyl
+n/9M6EH9qdB9qiEE7zQEPhsKTw3woSIagIxpNqoYFmCgAg5YQQY4StLEGECjJTUNDo5AAhMAIQUg
+aABKU1rSk9L0pixYAAM44IKR3pSjBkiNNm+SiixA0gh3mCZL8AAw1I0iEj9Igv9ktJOivmAOxoQj
+GnNSiT+YjgaykUU0W4QTTHj1hC/ww1jJ2JOu1oAJ5quFWNm6VZww9XQvsMMizrCESGwRJ0X1JOqA
+mRHCXoSpSK1FKPbaV7rqaydPOMIe6nCEKCzifp20SRYeVj7DXsSzFYlsD6xwhDNc9q91tckojjCG
+Q3giXUpl/skfPPjVWCpyJ6sdww7mELkMPRYnsgiEomAZ25Vwk2GJNedMgqso0N6yIc51iCzwQERm
+FlclyiTIW+OKWuBSl7jKbZJtKTLd6lo3vDDBmauwyl3H2qS8mkJvQqK7EPgWhL6/1dA6s3kT+4KX
+qnSsiX/LCeAt7ldE3jUvfgOc2pcMmMC+hdCBSbJghDz4vAV+SIUJcuH4ZpiuExbJhgvS4RFD15Ey
+6bCHI9zdEIPExAJRMYzF+9yUqHjF3Y2wi00ZkxvPeI81PsmNcZzZHAvWJiYe8o/ni+KYlekhQyay
+QBIlETd9CXzIGpiYrkyRR1WSOc5kX8YkdkmMPInLChxa/n2/C2SEYPZ6VgrUmZcX5Db/TAFTSh5D
+oizlWuBKVzkrgaG8oLGMqKoONxhYISSgOokc2mV93qXrgmmRPv0pUHfqlUL4rBz7McTS2AI1nYeq
+YT4mzcJsPnFCwjWuKqtZWkYQQ2/NnABINHoiN+utclg56cJqKVpNe7VB+Izhg2yCCnsYrkL61ev8
+MpgjzZZrqlWtkBWSkyFiyp5GYsAFKmxCI4WgQ7Qd8i9v//cgqBSzAH2tkWg9q9fELvZBZJGIXM3a
+IMy+dZ2Z/BFNo9q8bmRIrhfipkLXLBS/ukgpCtCKcT8E4axqYVYRUgguU1rh2Hq3vqUNcH4zJBV1
+aDVC/vI96gaHMYl2UwgcwnA4xLmt5XGI29zwZ/GnwVxqbYsa1hwHOMEZxAtmmjTebj41vhGB53/z
+uUNOjZEPuRtlG1850eOQ85tHtg5rVR5BHH7yfUMkfws5hfOGd7uxh0J3vGsI0w3SPLPbLhQPPB5F
+FIg+s4HL7J+Lew1MXbjbYhxOwf4eQcSO98293eyYoEIWvn0QkpfZ5BQhNJl5jJD6TW8hpYCCQPRc
+sj4Q4glTzQjXGRI+0MubV+8C++P/LpDL+fuz6eEYFQA9ctWNPuCQl4iYxyzLWmywgw0RU5dqnpHQ
+1RDaG48IDTEYIvYZfPUUcdPw+TUA70HfIIlPdkKk/v8m7hM/9zRm0fJh0jAh5AEnOISwkYs8kFGc
+4Qx6Oib4tVoQJ0LaJVFcchS/fN0XFqQOdANKXkcgHzZL6+de7Nd1/UdImISACUhW81cd43VxLOaA
+FgiBznaAGFiBBqiBSNZkBfiBDdiBDyiCpHaBJihfBBiC9PdsHLiBHtiCMSiBAyh/LwiDKJiCNxh+
+KmiDO0iDCyhJGViCMkiEQNiDMJFCSOh/MyiAQfhMTDSBFGiER/iDVdiECOFOFPVPCLWF8dSFXlhR
+DBWGeQGGZFiGY3iGdGFRGDVTP7VRNvWGJBWHcghUbliHnkGHeFgaeriHeShUEeiELFiEJJiDVxiF
+/iOIg4YoiIPIiC6IhT4IiUkohey2hOoniUxIhStohZuIiE8ITp+YSpbIgCdYiIpoijrIiZFYaomY
+ipiIR5q4igo4ikKoipPYioRIbbQIhbF4i6HIX0O4iJ3Yi5kojLKoi404jMboi7sIioGojKcYjbko
+jYfIir/ITpTYdNloEUvmccn4S9vIjeFYitToiK9Iis94jK5IjLC4jMWIjLb4juUIjfOojjxoEXM2
+ENJnd9r4M3Gmj9M3hRORj5unJtc3kP9YkOlTiQfzZJICJcImjhmxjwJBkAwZjF/nJ9gyC3g2LN+X
+jhSnkYAnaHbyfDUYkpdWkYWjerCHEaImEJzi/ikRCZIHwZF59iWZpm0SeRE26ZGf8JICOYusVxBr
+R5O1tzyTc5IJAWzCkpRKeZSbByrL0o9M4y6BF5Rz13e3d4+PWC63tpXeOJQDkW1YGRHmIjTtsm5P
+2XjYkjxF2ZUVASsaV3Jw6ZVwApZhWZdmeWuvBxFedm7rUzAFN3k7uSiqgzEmWZhTpmwQcZbDNzJd
+Fn+nxyt1MpcVgSl9Fnk0g5eIBIKBWSspNxGPBphxeWsVR5fWaJiAdwBBM5N19Wf3ljrL85b1lXB8
+ojGWWRHGkmX/Y3CcCY5riW+qw5IUkWtOd2u0mZpDSThqmVqs1nFLeWtOCRE3A1sZAXZXaRHx/jIv
+WsKSv8l/5NiYBSN5GlFuAtNuGad5PnmRn7l5X/Kdl5hJDuMQKYM9/rIHFZMR5Nl6IhA0OjkRHDM+
+GLGfAwGf8SmU0Yc+V7J7iSkRK9MyDUkmVyJ8C0mVFuF9WAJA7XOQAzFw26egn0B3/0kRPPNE5VJ9
+ZFIo3eOaE1E0RxOXKNolFHAJIMqenqgSQzd1V5M1SMc1X4OOJoE2U0c1Vfc2MheAG5GjN9c2fOM3
+Pbo1SocRStpyibM4jfOkRwA5vIigJ9F2hRc6cldtE0dh2Qg7slN4nXN4uIN215YRXup2xROmKPGm
+zgM90vNmTzOmfWSUKxE+AlpG7eWMJ/FK/lxJEJaHp33KP6G3E69AQB5UPYGKjcGJEjQkQZDKjChB
+qHk5ZRz0qC9BQiP0BCF0QHoqYp5pE+kncZEqqJnqS8opEONHfr/SjXY0q/OxY8FJq7Wwf6RZTKvK
+qq2adXlpfzLBq7rqe1XUqwWBq7k6jqXIrC35Ra6Ke/Eoj0eGqXq5jtdKjyWhqQdaj+oIrc3agOIa
+rS7hrcoKrtjqq+b4qkZWruZ6rtPamdcoqehWqvbKp7UIr/Eqr8KamdpKgvwannZGVQOrmC+hqcf6
+rTB4sPq6sATmsJPqEYQKsem6gRKLkdSqE7mkTvhai5M0rwA7jTYxTOyqrgxLTcvkGhk7/rEfMUoW
+O5k4UU3X9LHA+hBaqIZ0IQhkUE9YIFH5pLNwYYZCKxaKsAWNwE9pWLRrQbRMqxaCgAL+BLRPmxZs
+SBEZ5YehQQIeUAEGMAE9pbV5eIdiqxgbcAQqMAIdYAGE0Ydlexlu+7aTQQIQMBg85VNyKxlB5bIl
+sVm1sF3NOBKR9Qd4sARnkAg54KwaWxNZAAOA0LLjWlVG5QnJ9Y0qcVdOBVVSFbhdmgVXZbNAmq0x
+0VW1FWP/yq0uYVYUlFanW4034VZwNRBzhYqFahOYm1eM5Vfs2LlHFrMWi1hJtVh8pbsoO7IxEVmT
+VVmnVa0o4bedpbiiKxOiRVqmhaiu/guPqsVarmWdlqsSs0VLYFWvI5FbuxWbtFuw7yVcxtuuM3Fc
+mVS5zGtj6uu7p7pc00a/ybRMAwG43asS9oW/BMsSDwbAOaFeRcRe/YsS/kXAiyvA03axJIsekBvA
+DlxdDBy9NvbAEHy9LTLBDVzB9wW9N/rBCqzBG8y+K+LBI2y/AHfBK+xgJnzCqHuEKsylMFFiIuyu
+OgzCm+qOL1TDG3vDMezCO+y/Mby+M+yIQIy+MAydMlu8MjwSnJbDNoyAS0yvKXbETxywQYyQFrdl
+qElsyEFlS5eQYtagD/EoHWKRtQBAH5kQfxmfrJSPFOqQ/ZqgXWI2FLlnWvzE1nsQ/ntsZahZxF0c
+EUApEIuWfBxXxbD5aSIJk4oMEYeWaC75yIiMxnuWcAeqSYdcoJFcxRDRkwgjym8cY338xJ52PR05
+yiRJoAj7wnY5EKRiayUXb0/8nA3xdINMnbFmvrq3kcJiER76xOnGlyNKwmXsPrQpxt9xbNqndn0X
+lYJHwcApegUTbpNmy1sMSfO5bBkXo80pEdxmbkPJKNwCAMfMEOXGeEZUqiljoFGcy7aXfPEGHfRm
+b7I5liKQzrAMynt5lwznOtq8zQIxzMK5PKfpaxB3f78MJ24ZzROx0Kqaz1uCyRjsEK/Xl7J7yusL
+ciKXEL0ymGVZuxMRLUCndQYh/nVDWqSHc6RQSZQQbUc6+nI7h6VHEKWQ7NBDo2lTenNGZ9M3jXmq
+k5z9PBGh2caYrNJL+nIwd3XCetRtXMqETNIN/ZDoAwD8KBCEh6ahoKbOw6YvTRBFSae483Zx58QU
+/SyXIxBk7Tx692vDadEXvRAsSZwFsdV459XCk3iLF5LTTNTYO9UP8c6fLNiH6s1w4gWpx6JM5Hmm
+15610DqFjRCl5z/HKWes6XcV4cqubKMGIXu093O+qZ6c98qCzRAY6sm77M+/56kGgaHOR5gVYXyt
+S3A1yj7hzBCxqh+pbdembZYxmjGiENxy7c+1kH2MWRAMCgtjUqF3fNooHKsu/lF+53cT6YfE9piL
+7gd/SVzNM0KsMJF/VFwQvJqyHBywAHjeTLy7IMveW3q+KFzI8N3d2R3fXBzBPezDoXuO7a3f/R3Y
+/v3eUCzg963e+T3f9W3fBq7gDI7FnJuvCfzfA36zxo3f9L2uAU7gC+7dEa7hG47hGS6KyJzgJF7i
+1mrhJm7eH37iK96OCA7iAP7iLN7gKe7iBX7gEy7i8evhNA7j8p3jwLjjFC7jNr4QOVu1buG0SD4W
+Sr7kYtHkTq60Ua4WUD7lXHG1E5G1eZsZcbvljNHlXr4YYB7miDHmZH4YZn7mbQuII+7jKF7jEn7j
+F67iPT7jc77f7j3kPy7n/nAe5y1e5H8ez24e6H5e53Y+6DjO54hu6Hge4kFe1EAO4UKu4/zN4xw+
+6Y+e55Su6Zle4YSu54p+6Ive5zFL0Ize6JEu6e5d6kTs6KrO6a/u6adu6X0O6m8u6nR+54U+67b+
+6Zsu67pO66M+7MQO6Il+68bO679O5Ki+58je7KGe7MHe6w5+E3F8rF62ZHGM3dglmab+Etk+3s5+
+7A2xx5EtAlK9aZrcIRR5xrINZbY6kXbsxqstu5rM7R+ax3Wcx6K57koSyAaZKvGOPA4pyCO93hFB
+ynCSyPWOEMaJJAoPzwVNBSbLk6v8JVAdEcOsHwq/dZN9EA9vZhcfoivJ/tgOMS0Vj48jH5PDYvLA
+Dp4agS+z/PEJYZ7qMikSLxCs0ANMwHj+6AhTaRHrLOhw5j4aDRE2zxGTkp0XsfM9X5WOoCzB/Nwv
+n8/YTPMK8aAM/ZnqpjR2cO9cvy0LZBESzT0FA89a/zJoGdPc+PUm+pkPndvQfekXcScL13D61tNU
+WtNYitM/p20JbRB6/zY516RA7fcCcSdxzzBDKjU/bdOI//cVLduDnzdX0zeHrxCahpjvnkkr7TaG
+D/kI0SshEwCQaaFtrhB2c9Ku09bCA6Zo/RBQvXauXzt2cNYXYTcyo2m1Tztv3ZtkRvtcvTmwf50a
+8ztCM81szdW2g/uV/maSgD3u1V5pUgkldeco4vMx1xmR0b8QMvAFj039lqLW/VkRlf3tjvw9GQ+g
+2Q9uQ8OcGvH94V8Rdj2dqY/vo5+YBlqpSkKgio3IACGgVS2CBQ0eRFiQUhEwrxI+hOiFQqyCtETQ
+qVWKwCeIHWtRenLIYa0XgDyeJCiRYsFZBzCi9AjykAyTMDuqLJgpAEeNHG1CXNjw50OcB1vaGAqx
+ZNKCS5kaLDUAwFQAEwn2fErQU5c6qEjWzJpRKlUKosZaDbu1zg2wWaNSrRrrLQBHTNV6bdr26dyp
+EwsJDFvr7tfAYuH6pVo3sFq2hflWdXVgKtLCBJ0yvVxZs0FUYzzl/t0cmrNnwqIrd/58MLPpwKhB
+sw7tejVszbNt2qZdGHfurLt5P/X9e2hw4T+JF0d5/KFy5B6ZN1+uF3rS59NVS7d+G3v2k9UNeude
+Orz28cO3l08Inrt66+zZtz+P/rp8mO+h278fn75l/R3xN/+vuAAF7I++AYU7kDf3CjSQQfQSVNDB
+8iDMjULYFtyvOwnHs/DCDcPrkLUQRcMwQ/8+XA/FFE1USsXsRgytRBbTc3E6GGOsMb8Zo9sRIRl7
+fA1I/oT8LkcAjTySyCGBQxK5G2trkkAlxSPyycp+FNJK3aJEkMsIp6QSSCzF9LLCMs2cUsst03RR
+zcDc7O1M2uBksRJMOjFz8QQsLOGzTz//BDRQQQcldFAN9iw0UUUXTfRQRh+F9FFHI6W00j8ntTRT
+SjHVtFNFNeAjKzciqKBUU09FNVVVV2W1VVYfINVVWWelVVZYa8U1V1xv1bVXX1Hl9Vdhew12WGNn
+feARMJdltllnn4U2WmmnpbZaa6/FNlttt+W2W2+/BTdcccclt1xzz0U3XXXXZbddd9+FN15556W3
+XnvvxTdfffflt19//+03IAA7
diff --git a/Documentation/DocBook/media/pipeline.png.b64 b/Documentation/DocBook/media/pipeline.png.b64
new file mode 100644 (file)
index 0000000..97d9ac0
--- /dev/null
@@ -0,0 +1,213 @@
+iVBORw0KGgoAAAANSUhEUgAAAlgAAAEcCAMAAAAsmToJAAAAAXNSR0IArs4c6QAAAwBQTFRFAAEA
+EAEBAwUBCgMBCAUKAgkMHQIDCwYXFQYDBgkVDwgFCAsHChASJwkDFA4NEg4TDhANHgwHDg8aExAG
+DBEjBBUZERMQCBNRDxU0ExcZFRgVFRcgCRkzHBcUDRdCNRELIxYTAx4mLBUMEBwcEhsiDxwhExsu
+Dh8XJRkQByAtDCMUHx4bACk0DSsiGScsFCRcJSUiGSZCDiwqGCg1LyQbIycpVhsPDy0wNyQVECxA
+PSIfCS84ADJCEStWRiIULSwpADdHCDkgEy1/BjorEjhADDhXCzZvITNPUysQDzs8MjIvCj04BT1O
+PDEoQjEhMDU3LzY9KTdFTTMYNzk2GD6PAEpfEUVjBExFCEpPB1ArK0FjKEVZYTscdDYXG0d5SkA5
+FEiJQUNAOURPAFhCA1RpP0ZJVEMvYUAyBFtRWkYnDlR+QEleAF1jkTojHlV1AGB4PlN5YU87cUws
+SVRXAGaBWVJKUlRRRVZlAG1PWFNSBGt5AmqVAG+NAHNpK17BWl9ifFs9KWmnSGZ0YGFfp1IuCnWj
+AHuKbWBXoVNAdGBPDniWAHujTWmLk14rAH+ch19XX2aRX2t8AIeLiWgvAIeeAIaqa21rOnehdW1m
+AImspWJYj2tLW3C0AIyvWXaNAo6xb3Z5dXZzent4WIKiQojAen+CkX1pcoSWcYDOoH9fp4E+Y4ur
+hoWCXIvGb4mut3xpqYNYnYdUO5rDyXxdjY6LYJqk0IRGb5azXZnMjJGUgJWqpJB8l5aUyJN4kKK1
+rZ6IYqzge6Xho6GdnaWpgqy6yZ9zvaR0hqzMk6rN5Jxxw6mF26lbq7C2pLTGwrCbs7Owvb+8zcGc
+8rp42L2xsMbY3L+jtMfsz8W2nM/yx8jH0MfA7MWU78h/3crIyNTo4NLD6dK1z9bc1dbT3NXOv9vr
+/OKSwur8++Gw4uTh0ef78uPU+OPL3Ojz++bGyfH36evo/+3b6vT88vPw/feu1/v+//bb//nK/PnW
+5f/+//ro+fv49/7///37//71//3//v/8sZeTnQAAAAFiS0dEAIgFHUgAAAAJcEhZcwAAFY4AABWO
+AUTUBDsAAAAHdElNRQfaCRQPAiJBEFMLAAAgAElEQVR42u2dD3wU5bX300nWws50shA4lyTGikRE
+Qy0aUChKvJZqTQGBFNurVo0FWq2VqhAq0hc0t1rAxtLLpu61cUl6gWtNe3vb7Z9IKm+Xqn2tkFih
+GmwFA9Xwpw1s/UOyCc97zvPM7L/sbjabXTLZPL/PhzA7O7M7s893zjnPmec5k8WkpNKgLPkTSEmw
+pCRYVlSjp5n/3+3xGGsONHt2vx1t04PNTbtP8aUujxAuHvN6XjHe721pbmqLsp/H021+crP5wce8
+Ta8Evi+wKMHKHKkwjf/vA+D/77SrAKDeeTRiO3/vcnzDoTzXgy/+CEKMbVdw5dh9tMGubAfuuMjf
+E7HnfgAf/X9yJn6Aupqv206fNfYdXHr/Aloc944EK7PBWg9QurVxlQ3s70Vs+FmAdQ0LAP6By1cA
+KCT2AsBqXKme7mEfajBr25MaTIjkSjPA0mHsVnz/G8jgzyBna4MGH/UzdgHYt9ZrMNovwcpksN4E
+eJpeHbLB5PDtelT4L/wP4Fr+95NirQa34d85cB1jX3eAsGVhiPRuR644WPjOafxgHXw9uD8axL/k
+3+gj3P4vLgJ0SrAyGaxzoFCsfpObJh8aJVMtzUSMA3JZTw/Ab8RKYcD+Rvu2ehsJJIBu9llFwdW3
+0l8N1B0CrDlgpz1K4OfIkRqgT4cOjNkkWBkLFiM4ejT4nXjVrcH/wb9G4BUUwOcZ+xCgtkh74Ci9
+9Iu1Jig/BjhDhmzCGUTzccaKNx9lAqwSUAVY17Kvw7U7S2wLn6fXRXCzn90P2dIVZhxYIlxSiCE0
+W+8F1l+GYDU0hG99P9/gVxiEKxiGvYPMoCMjT2a8fxyRQkQw9HpJg3EBGAmsr4PDz8Eaxz4F+UBf
++DjtMZ0WJ/9ZBu8ZDlZwfX7fjTG0x9ibPTF93D52UEdELgD9LXYw19zteA7onMwLAHuI74SB9QGG
+b372DKAvLQF4xN/7FPlR/17gjD3H/BKszHWFYRbr6siEA7sL4Jbga4zG2Yd2sCuqaoC1H63YS3wJ
+nSW3RyFgsQ0coQLsNn4KdD/3gtcauG0HOCItVgYH78EYq4fHWOFaDLA6tMNHe3St0m0L3+Ixln+/
+BqP3ib0xGue2LRQstmu+vXjz13mMZYRbubhoFw7yXyRYmdwrHMN7hR/fgVGSdrovVzvEUpuXYPhn
+wG9+wJcOaTDZ3GcOpU/fiACLmb3CP5o0ncemCcamQY4EK+PzWD3zYayNYvcwYUj0UiCldTf+9yXQ
+2RNlKl+6Aw2YLRCtU/D+uBZgxQDr9iIkrauIeo067OOu8Cfs38Fxgi9+XoKVyWCx+wBKG5t1tDfU
+9ME81hlybtki3U59w9XNuOVL/r+IJbu/58yXwOgGdPd0aXAuwXU384eAdT7YtzXqPPO+HuybPRdA
+9hnW5YDR2zz41ntnJFiZDBbbbnfQvUI7OBaF5bF+ZdwehALCj+4n2n9qLDkK/8zxMdSNjlA/3UP4
+vRFqsf4+xhG4V8h3G0sB+/4ptJjzB5luyDDV1otUVXd9vbGmpXFr09td96mXha5kT9Yb4psfbKxv
+EgMdDjZuE2MTzPfru/9eX/8HsabWeMcY3eBtaHrL+LiDjVt3B75v224/k2CNFL3+D/kbSLCkJFhS
+EiwpKQmWlARLSoIlJSXBkpJgSUmwpKQkWFISLCkJlpSUBEtKgiUlwZKSkmBJSbCkJFhSUhIsKQmW
+leRP28f50/H5EizLSlHEDC9jCuGxJ6crtoU7TkVjxJxkuGu+XVvNp9t0bS9SFu4Ra1+/PTt/c+R+
+uFLbfMJYtNvMbRk7nq34JFiZrPB5hYdsoKqqA9Sjfbm61ZhkOAdwG1D3IVd2WhJFGp4CB+6Xw8Iq
+kD6j0QbZR3D3F/he8CPjHT1s3r0EK8PB6rHBLARmby7kRm538i4QYP2Jag4dmwkOKkU69gjbqcEb
+rOddgD1sL8DDofu8D/C4/9gCyPHTrNVZp3oXixpZjCCVYI0gsHy8Tihjf1Rt+Le7pSWw2U4bjBZg
+faUEkRJ1QETZte8ShefDT3CxtukV1tXSQm6yBXf+d7Nc0T9o2/d4SUjCyf8iTJZgjTCwng2+FVKG
+janqMn9o3UgDLOKmy1g83NrKQ6zzwc493+/YFFFKpoAqIuk03/5dmoCP1g/00xKsjAerpIWLYzMK
+oDTw9ACfqgY2w7A8rCDpHEETzZb+kPgCeIpqAz7HOD0PI2yXMfYpUcS2gGosLwf7bq8G1zNuwn7D
+JFgZD1ZAFBWdTxVBcjZHezJFKFhPAfyQwLqDu0LOGCysmi8qHS0G+Dg6wR4qJHKCVy4ajWtn0lec
+SzvfDzczCVbmg1VQxWVgs2E6oaY/HgcsP3FVKvB6pGUDCLCu53aMB+eE0E9E3y9ntxet4Gh6a/QD
+q3Qi62UYyyRYIyzdwPt/O2/Xg+X4+oJF1bNhEV/k1YgWCVdIXvGfIupCS6Xz9/8+xQGQOwddoXh8
+ABqv/8JNf9/a2goQ0jWQYGU2WH7W0cbJ6dL6lLYNsVi3AnzNWHfwyXV7WDCOZyI4p7ptRvW/XdVb
+T8/B4P1TZtnRccFCWqoEa6RYrCvUfHPt5JhgfTeQ5uxobz1DVd7HElH0rIq/cb5wAx3yCLTDbf4z
+It1gxPElMAE7mCQqFS/BGilgIRiXdeDyTkoWsO7W1ihgvYkheCuJPz7nBDumUTbrV5D3NvOdT2VI
+j2O8hRudxz/8YT97EXL9fnSFz/nZq4FnpbA+z7yQYGVyjLXcAXb+MIFFEXmsIFi5gU6kv0tFs6OK
+eGsBf1iF9g9yhLnMz0vh+u/npd3VN/j7/EEBpWcCYMngPaOlqCWhSatd84tUteDGHZF5LAKLv+xR
+TeGLQ/N1dcZm8faGEjV/4VF0hCoHaaaqnOIrtYXivuP2MlBnBOvEq6oESyq+QobC9ER7vydyq5Eq
+CZaUBEtKgiUlwZJKnyqmlXRLsKRSrhJlBI5KlmClX+USLKl0qFKCJZUO1UqwpNKhZkVtl2BJpVzt
+qtIswZJKvRSlUoIllQ6wFAmWVOqlKkq3BEsq5apWyzokWFIpV4eiVEiwpNISZHVLsKRSrlpFaZBg
+SaVeoCidEiyplKthZGYcJFhpV4FSPgIHZUmw0q8KtFkdEiypVKsbwVIafBIsqVSrhNCq7ZBgSaU8
+gie2ytq6JVhSqVWVSlZLbeiUYEmlVp4ChexWebsESyq16qzgZmtahwRLKg1mSylvlGBJpVotQLGW
+T4IllXKrpYyAjKkEaygEmU+WBGtINE3J9AmHEqwhIwskWFKpV4mi1EuwpFIvJbMHAEqwhkrNme0M
++4Dl6+w4++rs7EnT+Q3R6SRysxm7hu3D5HQGC1Z3x7Kc8RNnX2XIds1VadXU8ebS7Ik2W+pHlfja
+Z+RMnBg4CVt6z+YqW+CHmzrRNr6x39PpUJQBPQjF10anY37HNek+nYkXm42Dp6N5O5MHy9eQs8Lt
+CqpufOirNGjtNaGv3POyWlOJVWeVbW3YCUysS+/pTHWGnc5VOYf7OcKCgSSzOm8cXxN6Au7x6T0b
+15IVoSy4LtYOJwlWs80Z/slnGSxaYUuZ1equ7XP0Zxcs1NJ+TqdNUaoSPZ2qyKM/u2DxCz/flwRY
+3fkrIz/57IPlqrumKjVcdUReJUMBlqtuam3co0y4sENn39M562DRV3oHDFZ7Tl+IhgAsl6smPxWD
+LFuiQXT2wXK5NtrinU5VGbQlcjreiX0/eQjAQhtcNUCwWi+OwtCQgOVy2gbPlWdetK8bCrBc7nh3
+broVpTyB09m6xGURsFxrywcE1oGov/nQgOVyOgadIVrisgxYSFb3IH1h41KXZcBybawcAFi+0VEJ
+GiKwXM6iwXHVNs9lIbCQrNiHWpFA9r09+q80RGC5VtYmDlZBdICGCizX2nWDSjPE+sWHCCyXszrm
+sbYqiqe/89FclgLLNa8lUbDqV7qsBZZr9mACeJvbYmC55nbEuWFY0s/pFNVYDCy3LUGwfBe7rAaW
+syR5rg6sdFkNLFdsZ+io6KesQ3uM5h06sFw1tYmB9aDTcmC5ViQ9Rao7x2U9sNYeiHW40/ob76e7
+LAeW62JfQmDFMlhDCZZzWrJgHV5pQbBim6zGfu7qdC+1IFg1iUwyyvKstCBYrquSBSvfZUWwlsS6
+xtv7id5vrLEgWHUTEwGr3G1FsNY2JTmgYbwlwaqrjToEprMdu4UFFQWxx89oLguC5Zp3IAGwprqs
+CFZNeXJgdaywJFiurOiDkwOKZdGWWBKstZ4EwFpiSbBcSSZJm93WBCvaLcP2ELBi5bnWWhIs94PD
+F6z85MCqqrMmWBdGM0mOAFexplU0bLQmWAn4k6yl1gRrYnJgLbMoWHN90buEhmL1DGstCtalIw6s
+iuEEFus3xFpnUbAulGBZGqwyg6uY4zkkWBKsZMDqNMDySLAkWKkEixcHiTdxVYIlwUoKrGYBVrcE
+S4KVUrBE+B77xqgES4KVHFj00ArFK8GSYKUYLF/cEEuCJcFKEiwevndLsCRYqQbLqyhx5r1IsCRY
+SYKF4XurBEuClXqwKuONTZZgSbCSBYvFe/yqBEuClTRYtRIsCVY6wGISLAmWBEuCJcGSYEmwMhGs
+JRIslFM3phzrOsQ54keHCViz9VFiI11fGe901kiLlW6wwOBJh/zYW10EwwUs0A2wIA5Yn4AVEixL
+gAUZBRa+KcE662A5UeZ7xrITN3I6hydYEafD/yewnBKsswqW8xOA0jfRms/RItxM9oo0HMF6lB95
+qVO4c+PM5vKVKyRYaQeLWyYOVo0uIIK7Xa5vGosPDTew6GwEWF8Vp6MjTuKK4WRJsM4SWKYQrEkA
+ZKwuIYwESxcu2TS8YqyAVrrcAJNx3RaACUZc9f1S8oEyxjrbYNUA3GEE658nyAqXOodd8B4C1hf0
+vG/Tyq/i/25yiStl8D40MVbIi0K60Emzhm+vcK7xoo5e3CA84b0SrKEBy2m8GId/vxgIroY3WFt4
+wPXo5fxs7pVgnX2wTFdYQ66Qa+MlwxgsdIWbTFco3l5TALl11gJr49xJ+Zfem+nphgIRvF9EXUWA
+q3HxWwZYzmEIVmjwjl1BKrl1OYyzFliXGB3Xh1IOVs0NULppoGD54oK1ZlL+TcmBZYby+sO8a8g1
+ziUyWYmCNQlqBgpWd1ywHr08/xpnUnksI91AOQZ3gVii1RTI5z2UIFg3wNI0gvUFgM9sqrkHD6wu
+xWBR5kindhwQWNOUKl9MsP7VyB0klXkX6Z6QBOksc22CYH0ZBg4WKNXdMcH6ajBlO/AEKcdpFh3f
+lot0I8Ry8UB+ZWJg3aOnE6y6POCPqXlUh9tSDNZFUOz8NBS6BwoWKoytIFiI6t14oNclBlYqFAoW
+IZgEWKgwtoJgoXn5TE0BfDIxsFKhULC+gDSmEyxdXLimq9ENr1in67xTXhxYC6V1Bueom/iuOl5y
+t8UC69FR8DDyqn87CbDC2AqC9W90OP8Gk4YELPScyYIVxlYQrG9SBP5lXXcOAVho9wrTChZ6F714
+ZRhXSNbdBJzQVdyaBVzHp43VpS6xSaQDDYK1ln6xLaH2ZUBgBdkKgnURXEgxd27dkIB1t2sQYAXZ
+CoJ1Azm37+uwaUjA+ow7ra6Qmp74mOcMmq8vQK4bF9H5110CY92uFaDjXl+dh32PFWi9hdm6jbbW
+H6qJ6QrX8r1CDeLEhgQU0hIGW0GwdAKrJhTmszuCNBys2fUJnI4adjrEVhCsKwks/BU3DokrdKUZ
+LIxkddMerRFm+fuj4A4836uIIKIDadJu4ZcVgja5Tti5c4m90jgxlgnW7CAFSjKq6gMWWAOsS5M6
+neogWJcSWO7MBQvbiiei5xFBhm5Caua6XIaxKuC92eJNLmMtIiiM2uwEwJo1OLCmtVvVYiUFVmXn
+yLFYwiNehE5vBeUHuOaGgeW6h/dt9W8PEKw+MVZ3vwqNsYgq68RYfcCa60vgdCCcKtbHFQ5RjJV2
+sJaCkWnCBfeaYA8lHCye7dRhXogrnFwXoCxGr1AfVK/QoCpar7DYZRGwBhS8V3b27RXqQ9Yr7B+s
+jsGB9X262y9uDlxWh/ZlFrbUo6VLnSFg1WFHG/faMgrj9jV83GUgeI8Hlisv+TxWkKrwPBbEymPp
+ISOv+tOWgn43ASMZmTKwKjti5rH08/rJY9WJzO7Fse8uzU00uz0QsMpaB515N8YifttMUgHkhoIV
+SEKQC7oE9JB0Q1ywRJbiNtfAwZrW3h098/7pWJl33XTi/YPljH/bmSs/pWBVdsTIvFOO0ribHBus
+uov4uYWl6Psm5VMPVr3SOLgYy8CmeFPwRbEz3BWKtYWbAglS/SZX/2Ald69wWjhVCd4r1EOzpmkD
+S9cHDJajsiPuvUK4qr97hV8QRIVb6tSApccDq7Vv+biBBu/OkPkewQkf5n9ha8OWnVHmtwx6dEN3
+UqMbQsCqyZ90zyTRFf3ipPzZnGy0clvmTip9iC+izSO79uiVBcaYjnxw3TPpwltMdC9cEgusCAd0
+dkY3mPcIL9dzuSOnkxK3mddcWZA/9aEgWFvmFly4xEDm0UmznP3dhA7/7gv7lo9THN0jfTxWKFim
+uzScfDF/W7y42ozGzFvSfMyMGZ/R3gVmZGAZsG7g8z8CSUdxeDRmRozug3NNsIzzXcvBmgR5mwYJ
+VjkFh+0SrFCw9E/y4VaFaylDV8xpKtxIMR+a2Ro+k/DLGDg715iDSOGmGgzfruW4Xc9XWwesOqLl
+QmO83Fd1KN1Y8zli7Vu6fq9z4yQaJcPBwrdmbdp4ER9IQxHZeXWDBKuWdzuaRzpYgU4hgkPjBWqM
+7u73aaSMDvS83G9yjJwGTNfxZbrhLpb58CyA8wSb1gHLmEEIGh6p8xJ+fM4r521y1XzxXpcxNpnA
+cn6Cj17EUP9eAuu8/mOs/sBqNe58jHSwzE5hjRhz5TSGXrnoRxYjsraEgeUU/bxP0p9NZorB2MlS
+YGEwdZHRwXZHDrZaczkYYLmN+YRz4bw6BOvewYNlPiGvRLpC0xWGdf4IKmMudBhYhgpNyAywnBYE
+ixz4F3XI+3ZY3Qa6HUJpCAOsQCpvVF3MAcoDA8t8Ql7gaQgSrOgWKxwspyFzPoVVLdaauWvNVPZa
+d8g0588BxlhiXrRpscwzShFYtYG7Bi0SrABYGGNNDomx+oJ1XUjeMwSsqy0GlrsAxvKFbyFYGGNN
+EIHUBMMrfisQY10iDt1IfaYCrNbgXc5aCZYJFvX7Jm+iXmGhKxKsux+l0fPXO7d8EfKvDgPrX83O
+oqXSDYUr+QCUUS7R9auhwArByuWnhwwFe4Wue4KT7gcNFgu5f14uwTLBMge7FrrCweKBvlGhxZyo
+E7RSYvVtVoqxPgGBCTmBPNb15tLkAozTRR7LeCt3U8rAKguC1T5SwQreJKwxK0TiVT5J55lpfJvW
+GbUjt1yuz+aZd9BmG+8Gt3GtmaSXbnLpVgret+B55M9+SBzKlhsgV9xOoCNd6/qEPoGqSNaJt/RL
+HxKZ95SAVRvuCeVM6NRpZBe3NYMsn5xiL8FKJVgs1A9KsCRYKQMLg6xpXkWpl2BJsFIKVi09H09R
+CiRYEqyUgtVBw2YqFaVj2IJVKcFyWfXJFM2K4hmuYHWoEizLguUz0qPDEawyRYJlWbBoGkL38ASr
+Q1HaJFiWBavBvAs97MAqD/ZoJVjWA6tNUaqHJVgdNONLgmXdx8opijoswaJR+yDBsi5YZsJhmIHV
+wW8bSLCsC5bHmFMxzMCqCBv+KsGyHljtxpSK4QWWMFhh04wkWNYCywyyhhdYFUbZDAmWdcEygqxh
+BVZnn0lGEizLgYVBlne4gWUYLEWVYFkXrHaRyRpOYHUGRlVLsKwLFgZZZRYGa3x0722oNdZJLbMo
+WLMzC6wZ/VQtI7CWWBOs/HgGyxyw31cPuq0J1vjkwGq0KFjl8Q66mo9PzppnTbCmxzNYsW/qtFnU
+YuUkN26xc601waqPd9Beng/Kml1nRbBqlvWtsuapClTYj3lTp3OpNcGakRxY7BpLgrXCy/qN3rNi
+O4+hBGtljKExtXjQVY7Y0Xu3zZpgtSQJlm5JsK7qZPGj9woEy7vUimCNj8GN6BF2x45YKtxWBGui
+L0mwqjZaECx3fvyDBsoHZbHxddYDa2NF9ENuDYx8jTkOcK4FwaorYMlqqgXBWtEc/5gr6erPYo0r
+rAfW1JhGVunv2tfc1gNrbmfSYE2rsRxYbls/x1xL3cIsxmLxM3RgbVwW02CV9NuRutJyYLnLWfKa
+aDmwlnr7OeRmuqmDYLXMsxpYWuwIq/9rv95pNbBs3YMAq3ajxcByl/V3yHj9NxBYrHqltcC6qj2G
+7y5XKhJoCsVtLbDmtrPBSK+xFFju/i8Tnm/I4jOqaqwE1opt0Y+3Je6g5JC5bTluK4G1opENTjZL
+gTW1td8D7qZ8AweL5TutA9bKZTGvg3gTv0J7hqPd1gFrRfUguWL+8RYC65rdifgMDIUFWKxko1XA
+WrouNleJtlFnVG84JGDNa2CDls9mFbDcF7+SyAFTIivLzMQtsQRYdeO9MQNCpXIATbHWEmC5x7ey
+FMinbbQEWHVKYuFiuaIEwGItORYAa60tRpqqakBcoZr6HvzZB2tFTgdLjWonuoccLPe8GxPs3lYq
+SndW8LJYN945pGDVrc2KYa7aoCDOUJkY7vDGqe4hBcu9IquNpUydkyJGC5xtsNxLshLu3aIZ6MwK
+Pfgm29SN7qDG/9ydVm28JuTFivHj26JfEB0l2B1UBu5TOmpzZteEfMPE9J6Ne6or5MXS8eMPs5Sq
+Y5ntGudZPJ0lK4LLdUtslw4gaVKtKB1ZEUd/eOvCS01pl6ZZ+ebC3GVN7TFSn94CGidTltxd3I7D
+62688mydTsjnL/O2d7LUq+PAA5eetdaZdKG5dOMDLe0DyvHSPZ0sZmV5y8IrpkoNC9VbGqz2anSB
+NLSvoE021fBSg6K0WROs1uoCY6xoWUOHbCgJVirUVlUgLBWG7M2SquEoC8ZYLWXGuPYSpT4t8a/U
+WVCUXuHQqkpV+FOrobHdJ5tnWIPVaSGwqvjseaVaQjXchS3pswxYbdwH1sugKgNUEXqvcIjlAap7
+JW1VRqjEOmB5MFwvl1hliGiqujXAokExHtkgmQNWpTXA6lQKlGbZHpmijsCYdwsEe9WyPTJGLYrS
+aAmwOhKcJSE1PNRIjz2xAlhV5YpXNkfmqIrK21oALF/ch5hIDTuBqN1ghS6hjLAySD5RxmjoD6Q2
+8LhXqUyQl2J3K4BVEO/hOFLDTtV8YvHQg9WtqOWyNTJIojje0IPV2W8xNanhpLYy/pSmoQfLfFyU
+VMZ4whargFUrmyPTPKEFwGqjMl1SGdQnrLYGWL7WVpltyByVG7NAs+RPIZVa/yNuo0iwpFKpShG6
+JwCWP4FPC27TM9AD6Ym+m182UUp0tn9HNFhGTftIsDyqkQZXVPEknu3zdVWbsbnvIR+7vUjVFu4j
+Jj7MUkm054YiNX/ZUbFnma6WrO6740Gb+IpD+MkzdoiVG0rU/DtPibWAn3B6xCNRFmwIUbniNfy9
+HTOWnYqGz1Pmxo9NdzhmPE1LO8t0rWQ1geXfH/JDB/puqiGyLxum68Ze2BB2beGJnqSP2jRYfcEC
+83yA+mpd04FmOQAUHo3Y8KAOqmID/Q90zhqQVNY7Exy4tUYb36/hnhpcH/ndvVOAPyH1VTtk4/tf
+o1XT+WcVcupwUaPFkR4Emw3hAA7WBgf+MPjL5L7Ul6tDYGy8gFoL4BvM/4wDf13gv/5+vuj4Qdg+
+KhhCDhabezF2K7afTbRfMmpWppkDVfoBaw7kPO9jPXtzYHLEht+FcSeYbw5chsu7wNbWimIvQu4R
+5ltM53PcBt/zs72a43fh++2fAhysro/Aom6210bv/xhmdLL9NvWHjH0JinFRgx9KsMLAegbgEew8
+Hz4f7H3syU4wwPp/GjzP2FOQd5RdADf72c+0vLcYmwn3+tkL2qi3Qvdp5VoOE/zsTQ2ew720vD/j
+Vnl7mG8B3JZkBz+kMFB8sF7TdHGBYFP/lEKzqsDQ9NunP0BZC8jhkF0mVl4BtPLvNvt77ECFfhoN
+cRasY69WVf2ZsWMPVG1lbL4KYzlYf9X0dxgxtYx15ehv0Lm+3clYNizjX75MghUG1vlGY6O9vxr/
+q68KFs6cDo5csfH2+dl+P+tVoY3RP8b//tNGdCFev2QfPFBFrbihqlLEXm/qo470sGa+F277CrsL
+rsPVv9Wy30s21RAYABUfrP+A85iJzE18ZUSS/H9hHP49Bx7Y+WATIyyqxb7/bYTk7+fA91jvR8je
+fRZGY3ygaM+3cbBahUNshQlo3EazXdVbT9DrL0EpWjObtFjhYP0JHCeE2/sOjMKlSgiOCFFK9wVf
+4m/+Tw3eRouFru9Nsli/EJgsh2sZ+wrkveV/hlsoxmF7OriXDfagg/olo0U0XkmoUVEcLDZYjuoq
+VLWDwPo4PBIgaAKdQ8SQvJOj4BbGPrBxb134FvsYt1hdWfC4scHPwP4Gt3dPvyhsXpvfQOqvoNP5
+vgpj0XgVLnAAOOgsj+fAwqrpUCxjLHBU8YYAAus7kG108Dg2vC6xqbfDOUN6sk+xF2z6sgd53PSE
+2HUVNWDXGDj3Q53bPGGZToXu9Q4bA1TGvZeM18DVGlYhry9YATWQBdpqrBc+L0IY2tuPoMO0QfHu
+XWSW/gPGYn/uZQ0M/l6wwSLGY8J8HS41D4CDhTHYN/hFo7EDALk7WpaDg8h7ir46SoQ68sAKCFur
+IkiOg8CKzB6FgLUe4EcijgcYi+A8KN6rogb0v4DRP2QbUdocvqHQUxpZL7sgKimwOsLnhvYFS21t
+QbUqkWCN7vNRJ6eA/izFbIep8uwhjNNP5kBh1e06YGBF9vUZJI5fEyfRpuW+EwYWGjO0TWXAwdJ/
+YnrB+0Hb0XKfpv9UgmU0BJbt7hUAAAvPSURBVAfr9gTB6mH3YVfQTxfs2N0tMyHnRBhYgrdfi23f
+tI06Yu613gGz/ATW7mTBosA9dJRK/BjrioAr/HEg2gro2BSw/zokjZAFm9mhMQ5wzLoCAys8WrwK
+ik+ZfUhhukLAIuwge7M2Dl2h6udeMZcds+m/YRTbTZZghcZYQVf4N97TiwFWD4ZScIuf+of2oxyj
+O4KukDfgnzQ0WGKn++BfTK7uEnsZrrCLwq2BclUWMayuv+D9XAqH9jGMnh6J5KoIcvaF5dyA0qgH
+WtrYKP13wrpeb/wax5AhnvEKBYsda209cQBmoVfkYB1AsA6I9w6AJsEKBetvGFmh/3qeneERVEyL
+tRx0Ho+vMs2UzQze74LPi3hdJKy4J/ylsTty9XjIqn/mDDh471SVaeGPkowP1n4bueHP2m/ZzoPw
+sPhqCow10J9TcgsPmvTfdXqf9NNSDv7FaP0b5hUxEwp1yPf7Q8HyNnq4Kfsa682B33CjeC6F9PQ9
+f8SQXoIVmm6YQhmdX6jFe3X4AYsJ1nrIEx2+JwR+y9FMYdeKTNwF8HsRwY4FnduDDwJ9P1z5U9OI
+kVn7Hy17gLeC2qgGY/cAwMIj1Vef6L0PIz5+U6eq2hsSIy6sRlVRj1HfwY4tQPd1yIbo49LX0Bzl
+QC69X+2hcEr/DfYMbw6zWN+F/CNsly33HT++n7+H4U/2DdaVQ51LXFwowQoD600NFu5hL4MOY6nR
+G6qrooCFG43lv3n7u7nwtVNsu07x1AIoPYHNRR7wXR1uRotAeR/yliLqfTPX2KsNwy7HDnZwSqBT
+n3DCXVGmRVSC7wcsdp8GqupA+5m/2R+ax3rfZnRZcPNetK+qCqOPUOxNS6V+sj+GqsgRLqLrwnCG
+Aiw/kqerDpVHaYtpEQr93EbS92knJFjht3RetuMPw2/E3HkkIr8QeLnA/M3bKIClrSkWOa7TIv+h
+MZo/RVc/XeL/CdmnTUcYuLuznpobxp0a0KFWRnvQUVbfJJcBliJuQr/+WJGiPdAyBfLeCM1jeRVT
+9GpXmZK/mTqxPTunKzOa6Jo6x3y/qmuMMprWzFFs7xn5DhFi3We33WkEorumK8U7uP099mQRLp4a
+6VyxacGGEMmhY9vLsm0Ln7/LQb6wPHzKXIV4+RHzN8de+sFVevaM53lO9dgG3XYnub/1ikJ5nKcU
+Bd3ig+ZHBPYib7R3fnb+5u6B3IRudSjRxgAnPGxm552Jf5c/ua3kWJlE9PpMS111vHJslEc8yIF+
+UoNQgwLoBqOVYpRgSSWtRipIDC1R35NgSSWn7lpR5zpG5VgJllQyaq0UPbOYTw+RYEkNWG314sE0
+1XHm7UmwpAYkX3MlUkUpBk/c8ukSLKmE1d5YaT7ur7q/h0hKsKT6V2erp7qiIJATr27t/0m+Eiyp
+aGrxNjd7GmurqyrLSxziOX9Clc2JPUdZgiUVTaBECFeU17Yk/nBuCZZUNBWEMFVQUe1paRvgY0kl
+WFJRXSEfFt3W3pHsY24lWFJpkQRLSoIlJcGSkmBJSUmwpCRYUhIsKak0g9Vab0zwqq3nQ057vQ1b
+m96OuuvL9XySoZ+1NG7b7RcTO7z1TebErdcbt/WtAHAwuPJg49am4LQA39Z62RgRqq8X2UmP0SYH
+Guu3RS+q8O5WsQW2RQNuwtuCWiV2U9TWG2o3WlDs5e/11jeeSAdYEfMKt9tpTqFaGuW7juXwSYb+
+Y9NVAIe2B49rfx5ubeNzvHuX22i/8FqiYmXhW+Yi2AKVMReb8+6lAnKAGEgnSs3sn0KzCtXRf4iy
+5QLRav69OpWDKj7Rw96fSa0yms95vs/GV4btEVIq0r+3iO91BFvwNWpB5fG0g/WyBouamh+zw8V9
+djw5EzhYvRdA/jbPdBj9Hk1MLW3aYHM820OgFDY9aaPqWSFaD7lbPTMh30+Tox2rmxeICfWMV0KU
+YMUF630dxm1tbiwC+9tnIjdcr4lWw20ubmoEGOdH1OybPUU0PxV/dftWXDw3bHaduAuoQd4+KpqF
+exXBuNO0iC2oOX6fbrCuAF71+GUtL6KSKNuZBwKs12xU1eGkDb7HvstrxPyWivy9puHJsf+dsSh0
+n+M2eBZJ/Bh87wz7GE2O7rIZ5R0O2SRY/YD1HbATGb1TqDJfmF6badYg/Y5qP2HU8RtFk+vf1ahg
+5Bh4iTO3L5qlQ+P0Pzaaa/+uLW8PewJoavEGXmQvrWBlGzVmmprbOOWBQpFesD+icrA6W71i82qE
+ZR1dNlRR9Me8tB93f3OU0afRrimj/X8FlVzji8TUOXyDLF40mfk+kvusBCs+WBVGISNvM9XkDJ0J
+rUDpjaLV2luahZtrYzq0MlGN9C/aqKN+ciE/YF15Ctqt9/lf0lNU25YdNveiGqQPMdbzF9uod9IM
+1q2Qu/lEyBkEAuzdq98KK0iKJucniOE6sdkP0dT98LEi28I96PePU6mAn4H+UmjZUVxRfITt0kQN
+m8Xw+AEJVhSwOoNg/QrgzmAEHlq7YeHz4aUcXgC0WAvgslOiEsh/CiKpGhYV9HuWikKKNv1wlB60
+Yi9Q1eSP8zJGH+bk/SENYBlDvHipyIPZ6KJmrDNOyNPcGuamg2D1ziS/fgUPqdArbkbzS1Xewf4c
+vy7053gditc0HlL9GHLxstgAdkXTnhMBVilrk2BFActsCsJmOjaFtszoSHubPaFbhoJ1vIjs0MkF
+oCowDsF5DLJp9SpeknEBZG/XzKJF60OK6Z2cQnvpyVf0GxhY7OAC6rw5tOei7BoEqxej8F9TKObY
+wU4uB/SK2aA/z3z3UUjPus7BjyhGJ9h7Dsw4wfbmIEPYl8TvUeFOvx+tXf5pCVa/YPVu4D05ZXWU
+EhchYCFXo45QTw93duAl7g+UiqSm/ruOH2E4wt4xwcJ9yNWofURUiwBrd7rTDeiBPbdnO0B9Lg5Y
+vpmgPm3UKcSzKcLTGWUaLyqrvV8Dx0uUJTmETClU8IhgW3SKvf4R3OzkmFw8pXYJVnxXSL+z97E8
+ozRRTLAO6ZCNsfoHOmz2U52xl9BiKUGLRUXW7EdEzvG3WraZDTpWJKp+ptVihYPFj2Hv+dH6CSZY
+vinC5VFfcboyY88V8N/oFY2C7xR1vaoB/Jp/0LFVDu2BV7QJ9PiAf/A4fhzaKsgm4wVKhWQpTh5L
+6PBiyDsRGyzkitfvNAKr5RhYhcRYIq+jG2DdBXeYNOZBDjdeIsb6IMk674mDdWDVFNE92AW2mGCh
+FdVCe7JdOXazV9ibRVVuu8ag+R0d7Ge8CnMpjqezfR00AstQpWQpNliPlf1cOLB4VZOP6/QgGhao
+wb0Kctifgr1CwxUaddXGmHYJvee4I0aamnqFf7LZ09wrxL7encYXxrZYiyHXeKbPX8vz3qFIazLF
+6WOPUoVu9Q1ebnKHqPf+lRL6Owc7kGixqMb4rTCZdXhI9eBo9kqWYoM1nUprM+pOx7FYRfBR4Sd/
+oelHeMD/eQLo14E8lgjeeWb9bwG7NF2Un2QskMc6L915rPsBCmsbn5wOKsVIEU8F52Cd2asZ4X41
+FRDN3/aY3f4Sz7xrW58cBbPQQFEW9Ble1f5F0Fc3zOePnVhMi7drjh8ZaWQZvPcD1ssOyFm3rWG5
+g9d5jKjoJ8A6Qw9fEBX9eqfg1g0XYBx/hjLv6xpE5v1n1CP8iqhua1RTZmeeMffyknOZsW2VI/2Z
+994N2fxeofZ8RB4raLG+ZDoyDKr2Z9P9Px5v9S7HqEmddYr6HsXcNo0+KlbaZ5GB66EbWJD9tPlh
+Eqz+YqxdOvUKHaJXGL0G6cxgDdJj/F5hDm+39XRfgyruoyO8mSfvP3oq8CgU8iDB24YH6bah8jRL
+PVhtnkax0OjhSavelmZPc1vYKlONnhb+1xC96PV6dpsjFl5vbqL9Xvd46Kazr8lDHY4DYiXpIG4b
+NOroECVJkRe5R/QKvUabHPB6ml45FbbKkPHSbApPB/+pPa8YHu5gcxMfvOD1eGj31zweDNNagi1t
+iM9GbfE0p2V0g5QUk2BJSbCkJFhSUoPW/wfr5tj8wgE+HwAAAABJRU5ErkJggg==
similarity index 99%
rename from Documentation/DocBook/v4l/common.xml
rename to Documentation/DocBook/media/v4l/common.xml
index 9028721..a86f7a0 100644 (file)
@@ -236,7 +236,15 @@ important parts of the API.</para>
     <para>The &VIDIOC-QUERYCAP; ioctl is available to check if the kernel
 device is compatible with this specification, and to query the <link
 linkend="devices">functions</link> and <link linkend="io">I/O
-methods</link> supported by the device. Other features can be queried
+methods</link> supported by the device.</para>
+
+    <para>Starting with kernel version 3.1, VIDIOC-QUERYCAP will return the
+V4L2 API version used by the driver, with generally matches the Kernel version.
+There's no need of using &VIDIOC-QUERYCAP; to check if an specific ioctl is
+supported, the V4L2 core now returns ENOIOCTLCMD if a driver doesn't provide
+support for an ioctl.</para>
+
+    <para>Other features can be queried
 by calling the respective ioctl, for example &VIDIOC-ENUMINPUT;
 to learn about the number, types and names of video connectors on the
 device. Although abstraction is a major objective of this API, the
similarity index 99%
rename from Documentation/DocBook/v4l/compat.xml
rename to Documentation/DocBook/media/v4l/compat.xml
index 9f7cd4f..ce1004a 100644 (file)
@@ -10,12 +10,10 @@ driver writers to port or update their code.</para>
     <para>The Video For Linux API was first introduced in Linux 2.1 to
 unify and replace various TV and radio device related interfaces,
 developed independently by driver writers in prior years. Starting
-with Linux 2.5 the much improved V4L2 API replaces the V4L API,
-although existing drivers will continue to support V4L applications in
-the future, either directly or through the V4L2 compatibility layer in
-the <filename>videodev</filename> kernel module translating ioctls on
-the fly. For a transition period not all drivers will support the V4L2
-API.</para>
+with Linux 2.5 the much improved V4L2 API replaces the V4L API.
+The support for the old V4L calls were removed from Kernel, but the
+library <xref linkend="libv4l" /> supports the conversion of a V4L
+API system call into a V4L2 one.</para>
 
     <section>
       <title>Opening and Closing Devices</title>
@@ -84,12 +82,7 @@ not compatible with V4L or V4L2.</para> </footnote>,
 device file. V4L2 drivers <emphasis>may</emphasis> support multiple
 opens, see <xref linkend="open" /> for details and consequences.</para>
 
-      <para>V4L drivers respond to V4L2 ioctls with an &EINVAL;. The
-compatibility layer in the V4L2 <filename>videodev</filename> module
-can translate V4L ioctl requests to their V4L2 counterpart, however a
-V4L2 driver usually needs more preparation to become fully V4L
-compatible. This is covered in more detail in <xref
-         linkend="driver" />.</para>
+      <para>V4L drivers respond to V4L2 ioctls with an &EINVAL;.</para>
     </section>
 
     <section>
@@ -2367,6 +2360,16 @@ that used it. It was originally scheduled for removal in 2.6.35.
         </listitem>
       </orderedlist>
     </section>
+    <section>
+      <title>V4L2 in Linux 3.1</title>
+      <orderedlist>
+        <listitem>
+         <para>VIDIOC_QUERYCAP now returns a per-subsystem version instead of a per-driver one.</para>
+         <para>Standardize an error code for invalid ioctl.</para>
+          <para>Added V4L2_CTRL_TYPE_BITMASK.</para>
+        </listitem>
+      </orderedlist>
+    </section>
 
     <section id="other">
       <title>Relation of V4L2 to other Linux multimedia APIs</title>
@@ -2472,6 +2475,9 @@ ioctls.</para>
         <listitem>
          <para>&VIDIOC-DBG-G-CHIP-IDENT; ioctl.</para>
         </listitem>
+        <listitem>
+         <para>Flash API. <xref linkend="flash-controls" /></para>
+        </listitem>
       </itemizedlist>
     </section>
 
similarity index 62%
rename from Documentation/DocBook/v4l/controls.xml
rename to Documentation/DocBook/media/v4l/controls.xml
index a920ee8..8516401 100644 (file)
@@ -51,6 +51,10 @@ readability until any ioctl (querying the properties) is
 called.</para>
       </footnote></para>
 
+    <para>
+      All controls use machine endianness.
+    </para>
+
     <table pgwide="1" frame="none" id="control-id">
       <title>Control IDs</title>
       <tgroup cols="3">
@@ -323,6 +327,22 @@ minimum value disables backlight compensation.</entry>
            <entry></entry>
            <entry>End of the predefined control IDs (currently
 <constant>V4L2_CID_ILLUMINATORS_2</constant> + 1).</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_MIN_BUFFERS_FOR_CAPTURE</constant></entry>
+           <entry>integer</entry>
+           <entry>This is a read-only control that can be read by the application
+and used as a hint to determine the number of CAPTURE buffers to pass to REQBUFS.
+The value is the minimum number of CAPTURE buffers that is necessary for hardware
+to work.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_MIN_BUFFERS_FOR_OUTPUT</constant></entry>
+           <entry>integer</entry>
+           <entry>This is a read-only control that can be read by the application
+and used as a hint to determine the number of OUTPUT buffers to pass to REQBUFS.
+The value is the minimum number of OUTPUT buffers that is necessary for hardware
+to work.</entry>
          </row>
          <row>
            <entry><constant>V4L2_CID_PRIVATE_BASE</constant></entry>
@@ -545,6 +565,10 @@ may not be supported (<constant>VIDIOC_QUERYMENU</constant> will
 return an error). A good example is the list of supported MPEG audio
 bitrates. Some drivers only support one or two bitrates, others
 support a wider range.</para>
+
+      <para>
+       All controls use machine endianness.
+      </para>
     </section>
 
     <section>
@@ -670,7 +694,8 @@ caption of a Tab page in a GUI, for example.</entry>
              </row><row><entry spanname="descr">The MPEG-1, -2 or -4
 output stream type. One cannot assume anything here. Each hardware
 MPEG encoder tends to support different subsets of the available MPEG
-stream types. The currently defined stream types are:</entry>
+stream types. This control is specific to multiplexed MPEG streams.
+The currently defined stream types are:</entry>
              </row>
              <row>
                <entrytbl spanname="descr" cols="2">
@@ -800,6 +825,7 @@ frequency. Possible values are:</entry>
                <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_ENCODING</constant>&nbsp;</entry>
                <entry>enum&nbsp;v4l2_mpeg_audio_encoding</entry>
              </row><row><entry spanname="descr">MPEG Audio encoding.
+This control is specific to multiplexed MPEG streams.
 Possible values are:</entry>
              </row>
              <row>
@@ -1250,7 +1276,8 @@ and reproducible audio bitstream. 0 = unmuted, 1 = muted.</entry>
                <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_ENCODING</constant>&nbsp;</entry>
                <entry>enum&nbsp;v4l2_mpeg_video_encoding</entry>
              </row><row><entry spanname="descr">MPEG Video encoding
-method. Possible values are:</entry>
+method. This control is specific to multiplexed MPEG streams.
+Possible values are:</entry>
              </row>
              <row>
                <entrytbl spanname="descr" cols="2">
@@ -1406,225 +1433,1178 @@ of the video. The supplied 32-bit integer is interpreted as follows (bit
                  </tbody>
                </entrytbl>
              </row>
-           </tbody>
-         </tgroup>
-       </table>
-      </section>
 
-      <section>
-       <title>CX2341x MPEG Controls</title>
 
-       <para>The following MPEG class controls deal with MPEG
-encoding settings that are specific to the Conexant CX23415 and
-CX23416 MPEG encoding chips.</para>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row>
+             <row><entry spanname="descr">If enabled the decoder expects to receive a single slice per buffer, otherwise
+the decoder expects a single frame in per buffer. Applicable to the decoder, all codecs.
+</entry>
+             </row>
 
-       <table pgwide="1" frame="none" id="cx2341x-control-id">
-         <title>CX2341x Control IDs</title>
-         <tgroup cols="4">
-           <colspec colname="c1" colwidth="1*" />
-           <colspec colname="c2" colwidth="6*" />
-           <colspec colname="c3" colwidth="2*" />
-           <colspec colname="c4" colwidth="6*" />
-           <spanspec namest="c1" nameend="c2" spanname="id" />
-           <spanspec namest="c2" nameend="c4" spanname="descr" />
-           <thead>
+             <row><entry></entry></row>
              <row>
-               <entry spanname="id" align="left">ID</entry>
-               <entry align="left">Type</entry>
-             </row><row><entry spanname="descr" align="left">Description</entry>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE</constant>&nbsp;</entry>
+               <entry>boolean</entry>
              </row>
-           </thead>
-           <tbody valign="top">
+             <row><entry spanname="descr">Enable writing sample aspect ratio in the Video Usability Information.
+Applicable to the H264 encoder.</entry>
+             </row>
+
              <row><entry></entry></row>
-             <row id="v4l2-mpeg-cx2341x-video-spatial-filter-mode">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_cx2341x_video_spatial_filter_mode</entry>
-             </row><row><entry spanname="descr">Sets the Spatial
-Filter mode (default <constant>MANUAL</constant>). Possible values
-are:</entry>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_video_h264_vui_sar_idc</entry>
+             </row>
+             <row><entry spanname="descr">VUI sample aspect ratio indicator for H.264 encoding. The value
+is defined in the table E-1 in the standard. Applicable to the H264 encoder.</entry>
              </row>
              <row>
                <entrytbl spanname="descr" cols="2">
                  <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL</constant>&nbsp;</entry>
-                     <entry>Choose the filter manually</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO</constant>&nbsp;</entry>
-                     <entry>Choose the filter automatically</entry>
-                   </row>
+
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED</constant>&nbsp;</entry>
+                         <entry>Unspecified</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1</constant>&nbsp;</entry>
+                         <entry>1x1</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_12x11</constant>&nbsp;</entry>
+                         <entry>12x11</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_10x11</constant>&nbsp;</entry>
+                         <entry>10x11</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_16x11</constant>&nbsp;</entry>
+                         <entry>16x11</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_40x33</constant>&nbsp;</entry>
+                         <entry>40x33</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_24x11</constant>&nbsp;</entry>
+                         <entry>24x11</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_20x11</constant>&nbsp;</entry>
+                         <entry>20x11</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_32x11</constant>&nbsp;</entry>
+                         <entry>32x11</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_80x33</constant>&nbsp;</entry>
+                         <entry>80x33</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_18x11</constant>&nbsp;</entry>
+                         <entry>18x11</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_15x11</constant>&nbsp;</entry>
+                         <entry>15x11</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_64x33</constant>&nbsp;</entry>
+                         <entry>64x33</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_160x99</constant>&nbsp;</entry>
+                         <entry>160x99</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_4x3</constant>&nbsp;</entry>
+                         <entry>4x3</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_3x2</constant>&nbsp;</entry>
+                         <entry>3x2</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1</constant>&nbsp;</entry>
+                         <entry>2x1</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED</constant>&nbsp;</entry>
+                         <entry>Extended SAR</entry>
+                       </row>
                  </tbody>
                </entrytbl>
              </row>
+
              <row><entry></entry></row>
              <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER</constant>&nbsp;</entry>
-               <entry>integer&nbsp;(0-15)</entry>
-             </row><row><entry spanname="descr">The setting for the
-Spatial Filter. 0 = off, 15 = maximum. (Default is 0.)</entry>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH</constant>&nbsp;</entry>
+               <entry>integer</entry>
              </row>
+             <row><entry spanname="descr">Extended sample aspect ratio width for H.264 VUI encoding.
+Applicable to the H264 encoder.</entry>
+             </row>
+
              <row><entry></entry></row>
-             <row id="luma-spatial-filter-type">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_cx2341x_video_luma_spatial_filter_type</entry>
-             </row><row><entry spanname="descr">Select the algorithm
-to use for the Luma Spatial Filter (default
-<constant>1D_HOR</constant>). Possible values:</entry>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Extended sample aspect ratio height for H.264 VUI encoding.
+Applicable to the H264 encoder.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_LEVEL</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_video_h264_level</entry>
+             </row>
+             <row><entry spanname="descr">The level information for the H264 video elementary stream.
+Applicable to the H264 encoder.
+Possible values are:</entry>
              </row>
              <row>
                <entrytbl spanname="descr" cols="2">
                  <tbody valign="top">
                    <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF</constant>&nbsp;</entry>
-                     <entry>No filter</entry>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_1_0</constant>&nbsp;</entry>
+                     <entry>Level 1.0</entry>
                    </row>
                    <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR</constant>&nbsp;</entry>
-                     <entry>One-dimensional horizontal</entry>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_1B</constant>&nbsp;</entry>
+                     <entry>Level 1B</entry>
                    </row>
                    <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_VERT</constant>&nbsp;</entry>
-                     <entry>One-dimensional vertical</entry>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_1_1</constant>&nbsp;</entry>
+                     <entry>Level 1.1</entry>
                    </row>
                    <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_HV_SEPARABLE</constant>&nbsp;</entry>
-                     <entry>Two-dimensional separable</entry>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_1_2</constant>&nbsp;</entry>
+                     <entry>Level 1.2</entry>
                    </row>
                    <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE</constant>&nbsp;</entry>
-                     <entry>Two-dimensional symmetrical
-non-separable</entry>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_1_3</constant>&nbsp;</entry>
+                     <entry>Level 1.3</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_2_0</constant>&nbsp;</entry>
+                     <entry>Level 2.0</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_2_1</constant>&nbsp;</entry>
+                     <entry>Level 2.1</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_2_2</constant>&nbsp;</entry>
+                     <entry>Level 2.2</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_3_0</constant>&nbsp;</entry>
+                     <entry>Level 3.0</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_3_1</constant>&nbsp;</entry>
+                     <entry>Level 3.1</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_3_2</constant>&nbsp;</entry>
+                     <entry>Level 3.2</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_4_0</constant>&nbsp;</entry>
+                     <entry>Level 4.0</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_4_1</constant>&nbsp;</entry>
+                     <entry>Level 4.1</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_4_2</constant>&nbsp;</entry>
+                     <entry>Level 4.2</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_5_0</constant>&nbsp;</entry>
+                     <entry>Level 5.0</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_5_1</constant>&nbsp;</entry>
+                     <entry>Level 5.1</entry>
                    </row>
                  </tbody>
                </entrytbl>
              </row>
+
              <row><entry></entry></row>
-             <row id="chroma-spatial-filter-type">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type</entry>
-             </row><row><entry spanname="descr">Select the algorithm
-for the Chroma Spatial Filter (default <constant>1D_HOR</constant>).
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_video_mpeg4_level</entry>
+             </row>
+             <row><entry spanname="descr">The level information for the MPEG4 elementary stream.
+Applicable to the MPEG4 encoder.
 Possible values are:</entry>
              </row>
              <row>
                <entrytbl spanname="descr" cols="2">
                  <tbody valign="top">
                    <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF</constant>&nbsp;</entry>
-                     <entry>No filter</entry>
+                     <entry><constant>V4L2_MPEG_VIDEO_LEVEL_0</constant>&nbsp;</entry>
+                     <entry>Level 0</entry>
                    </row>
                    <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR</constant>&nbsp;</entry>
-                     <entry>One-dimensional horizontal</entry>
+                     <entry><constant>V4L2_MPEG_VIDEO_LEVEL_0B</constant>&nbsp;</entry>
+                     <entry>Level 0b</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_LEVEL_1</constant>&nbsp;</entry>
+                     <entry>Level 1</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_LEVEL_2</constant>&nbsp;</entry>
+                     <entry>Level 2</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_LEVEL_3</constant>&nbsp;</entry>
+                     <entry>Level 3</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_LEVEL_3B</constant>&nbsp;</entry>
+                     <entry>Level 3b</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_LEVEL_4</constant>&nbsp;</entry>
+                     <entry>Level 4</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_LEVEL_5</constant>&nbsp;</entry>
+                     <entry>Level 5</entry>
                    </row>
                  </tbody>
                </entrytbl>
              </row>
+
              <row><entry></entry></row>
-             <row id="v4l2-mpeg-cx2341x-video-temporal-filter-mode">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_cx2341x_video_temporal_filter_mode</entry>
-             </row><row><entry spanname="descr">Sets the Temporal
-Filter mode (default <constant>MANUAL</constant>). Possible values
-are:</entry>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_PROFILE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_h264_profile</entry>
+             </row>
+             <row><entry spanname="descr">The profile information for H264.
+Applicable to the H264 encoder.
+Possible values are:</entry>
              </row>
              <row>
                <entrytbl spanname="descr" cols="2">
                  <tbody valign="top">
                    <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL</constant>&nbsp;</entry>
-                     <entry>Choose the filter manually</entry>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE</constant>&nbsp;</entry>
+                     <entry>Baseline profile</entry>
                    </row>
                    <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO</constant>&nbsp;</entry>
-                     <entry>Choose the filter automatically</entry>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE</constant>&nbsp;</entry>
+                     <entry>Constrained Baseline profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_MAIN</constant>&nbsp;</entry>
+                     <entry>Main profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED</constant>&nbsp;</entry>
+                     <entry>Extended profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH</constant>&nbsp;</entry>
+                     <entry>High profile</entry>
                    </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10</constant>&nbsp;</entry>
+                     <entry>High 10 profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422</constant>&nbsp;</entry>
+                     <entry>High 422 profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE</constant>&nbsp;</entry>
+                     <entry>High 444 Predictive profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10_INTRA</constant>&nbsp;</entry>
+                     <entry>High 10 Intra profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA</constant>&nbsp;</entry>
+                     <entry>High 422 Intra profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_INTRA</constant>&nbsp;</entry>
+                     <entry>High 444 Intra profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_CAVLC_444_INTRA</constant>&nbsp;</entry>
+                     <entry>CAVLC 444 Intra profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE</constant>&nbsp;</entry>
+                     <entry>Scalable Baseline profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH</constant>&nbsp;</entry>
+                     <entry>Scalable High profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA</constant>&nbsp;</entry>
+                     <entry>Scalable High Intra profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH</constant>&nbsp;</entry>
+                     <entry>Stereo High profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH</constant>&nbsp;</entry>
+                     <entry>Multiview High profile</entry>
+                   </row>
+
                  </tbody>
                </entrytbl>
              </row>
+
              <row><entry></entry></row>
              <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER</constant>&nbsp;</entry>
-               <entry>integer&nbsp;(0-31)</entry>
-             </row><row><entry spanname="descr">The setting for the
-Temporal Filter. 0 = off, 31 = maximum. (Default is 8 for full-scale
-capturing and 0 for scaled capturing.)</entry>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_mpeg4_profile</entry>
              </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-cx2341x-video-median-filter-type">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_cx2341x_video_median_filter_type</entry>
-             </row><row><entry spanname="descr">Median Filter Type
-(default <constant>OFF</constant>). Possible values are:</entry>
+             <row><entry spanname="descr">The profile information for MPEG4.
+Applicable to the MPEG4 encoder.
+Possible values are:</entry>
              </row>
              <row>
                <entrytbl spanname="descr" cols="2">
                  <tbody valign="top">
                    <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF</constant>&nbsp;</entry>
-                     <entry>No filter</entry>
+                     <entry><constant>V4L2_MPEG_VIDEO_PROFILE_SIMPLE</constant>&nbsp;</entry>
+                     <entry>Simple profile</entry>
                    </row>
                    <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR</constant>&nbsp;</entry>
-                     <entry>Horizontal filter</entry>
+                     <entry><constant>V4L2_MPEG_VIDEO_PROFILE_ADVANCED_SIMPLE</constant>&nbsp;</entry>
+                     <entry>Advanced Simple profile</entry>
                    </row>
                    <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_VERT</constant>&nbsp;</entry>
-                     <entry>Vertical filter</entry>
+                     <entry><constant>V4L2_MPEG_VIDEO_PROFILE_CORE</constant>&nbsp;</entry>
+                     <entry>Core profile</entry>
                    </row>
                    <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR_VERT</constant>&nbsp;</entry>
-                     <entry>Horizontal and vertical filter</entry>
+                     <entry><constant>V4L2_MPEG_VIDEO_PROFILE_SIMPLE_SCALABLE</constant>&nbsp;</entry>
+                     <entry>Simple Scalable profile</entry>
                    </row>
                    <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG</constant>&nbsp;</entry>
-                     <entry>Diagonal filter</entry>
+                     <entry><constant>V4L2_MPEG_VIDEO_PROFILE_ADVANCED_CODING_EFFICIENCY</constant>&nbsp;</entry>
+                     <entry></entry>
                    </row>
                  </tbody>
                </entrytbl>
              </row>
+
              <row><entry></entry></row>
              <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM</constant>&nbsp;</entry>
-               <entry>integer&nbsp;(0-255)</entry>
-             </row><row><entry spanname="descr">Threshold above which
-the luminance median filter is enabled (default 0)</entry>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MAX_REF_PIC</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">The maximum number of reference pictures used for encoding.
+Applicable to the encoder.
+</entry>
              </row>
+
              <row><entry></entry></row>
              <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP</constant>&nbsp;</entry>
-               <entry>integer&nbsp;(0-255)</entry>
-             </row><row><entry spanname="descr">Threshold below which
-the luminance median filter is enabled (default 255)</entry>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_multi_slice_mode</entry>
+             </row>
+             <row><entry spanname="descr">Determines how the encoder should handle division of frame into slices.
+Applicable to the encoder.
+Possible values are:</entry>
              </row>
-             <row><entry></entry></row>
              <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM</constant>&nbsp;</entry>
-               <entry>integer&nbsp;(0-255)</entry>
-             </row><row><entry spanname="descr">Threshold above which
-the chroma median filter is enabled (default 0)</entry>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE</constant>&nbsp;</entry>
+                     <entry>Single slice per frame.</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB</constant>&nbsp;</entry>
+                     <entry>Multiple slices with set maximum number of macroblocks per slice.</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES</constant>&nbsp;</entry>
+                     <entry>Multiple slice with set maximum size in bytes per slice.</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
              </row>
+
              <row><entry></entry></row>
              <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP</constant>&nbsp;</entry>
-               <entry>integer&nbsp;(0-255)</entry>
-             </row><row><entry spanname="descr">Threshold below which
-the chroma median filter is enabled (default 255)</entry>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB</constant>&nbsp;</entry>
+               <entry>integer</entry>
              </row>
+             <row><entry spanname="descr">The maximum number of macroblocks in a slice. Used when
+<constant>V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE</constant> is set to <constant>V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB</constant>.
+Applicable to the encoder.</entry>
+             </row>
+
              <row><entry></entry></row>
              <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS</constant>&nbsp;</entry>
-               <entry>boolean</entry>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES</constant>&nbsp;</entry>
+               <entry>integer</entry>
              </row>
-             <row><entry spanname="descr">The CX2341X MPEG encoder
-can insert one empty MPEG-2 PES packet into the stream between every
-four video frames. The packet size is 2048 bytes, including the
-packet_start_code_prefix and stream_id fields. The stream_id is 0xBF
-(private stream 2). The payload consists of 0x00 bytes, to be filled
-in by the application. 0 = do not insert, 1 = insert packets.</entry>
+             <row><entry spanname="descr">The maximum size of a slice in bytes. Used when
+<constant>V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE</constant> is set to <constant>V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES</constant>.
+Applicable to the encoder.</entry>
              </row>
-           </tbody>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_h264_loop_filter_mode</entry>
+             </row>
+             <row><entry spanname="descr">Loop filter mode for H264 encoder.
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED</constant>&nbsp;</entry>
+                     <entry>Loop filter is enabled.</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED</constant>&nbsp;</entry>
+                     <entry>Loop filter is disabled.</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY</constant>&nbsp;</entry>
+                     <entry>Loop filter is disabled at the slice boundary.</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Loop filter alpha coefficient, defined in the H264 standard.
+Applicable to the H264 encoder.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Loop filter beta coefficient, defined in the H264 standard.
+Applicable to the H264 encoder.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_h264_symbol_mode</entry>
+             </row>
+             <row><entry spanname="descr">Entropy coding mode for H264 - CABAC/CAVALC.
+Applicable to the H264 encoder.
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC</constant>&nbsp;</entry>
+                     <entry>Use CAVLC entropy coding.</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC</constant>&nbsp;</entry>
+                     <entry>Use CABAC entropy coding.</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row>
+             <row><entry spanname="descr">Enable 8X8 transform for H264. Applicable to the H264 encoder.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Cyclic intra macroblock refresh. This is the number of continuous macroblocks
+refreshed every frame. Each frame a succesive set of macroblocks is refreshed until the cycle completes and starts from the
+top of the frame. Applicable to H264, H263 and MPEG4 encoder.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row>
+             <row><entry spanname="descr">Frame level rate control enable.
+If this control is disabled then the quantization parameter for each frame type is constant and set with appropriate controls
+(e.g. <constant>V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP</constant>).
+If frame rate control is enabled then quantization parameter is adjusted to meet the chosen bitrate. Minimum and maximum value
+for the quantization parameter can be set with appropriate controls (e.g. <constant>V4L2_CID_MPEG_VIDEO_H263_MIN_QP</constant>).
+Applicable to encoders.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row>
+             <row><entry spanname="descr">Macroblock level rate control enable.
+Applicable to the MPEG4 and H264 encoders.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_QPEL</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row>
+             <row><entry spanname="descr">Quarter pixel motion estimation for MPEG4. Applicable to the MPEG4 encoder.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Quantization parameter for an I frame for H263. Valid range: from 1 to 31.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H263_MIN_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Minimum quantization parameter for H263. Valid range: from 1 to 31.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H263_MAX_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Maximum quantization parameter for H263. Valid range: from 1 to 31.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Quantization parameter for an P frame for H263. Valid range: from 1 to 31.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Quantization parameter for an B frame for H263. Valid range: from 1 to 31.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Quantization parameter for an I frame for H264. Valid range: from 0 to 51.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_MIN_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Minimum quantization parameter for H264. Valid range: from 0 to 51.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_MAX_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Maximum quantization parameter for H264. Valid range: from 0 to 51.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Quantization parameter for an P frame for H264. Valid range: from 0 to 51.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Quantization parameter for an B frame for H264. Valid range: from 0 to 51.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Quantization parameter for an I frame for MPEG4. Valid range: from 1 to 31.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Minimum quantization parameter for MPEG4. Valid range: from 1 to 31.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Maximum quantization parameter for MPEG4. Valid range: from 1 to 31.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Quantization parameter for an P frame for MPEG4. Valid range: from 1 to 31.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Quantization parameter for an B frame for MPEG4. Valid range: from 1 to 31.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VBV_SIZE</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">The Video Buffer Verifier size in kilobytes, it is used as a limitation of frame skip.
+The VBV is defined in the standard as a mean to verify that the produced stream will be succesfully decoded.
+The standard describes it as "Part of a hypothetical decoder that is conceptually connected to the
+output of the encoder. Its purpose is to provide a constraint on the variability of the data rate that an
+encoder or editing process may produce.".
+Applicable to the MPEG1, MPEG2, MPEG4 encoders.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">The Coded Picture Buffer size in kilobytes, it is used as a limitation of frame skip.
+The CPB is defined in the H264 standard as a mean to verify that the produced stream will be succesfully decoded.
+Applicable to the H264 encoder.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_I_PERIOD</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Period between I-frames in the open GOP for H264. In case of an open GOP
+this is the period between two I-frames. The period between IDR (Instantaneous Decoding Refresh) frames is taken from the GOP_SIZE control.
+An IDR frame, which stands for Instantaneous Decoding Refresh is an I-frame after which no prior frames are
+referenced. This means that a stream can be restarted from an IDR frame without the need to store or decode any
+previous frames. Applicable to the H264 encoder.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_HEADER_MODE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_header_mode</entry>
+             </row>
+             <row><entry spanname="descr">Determines whether the header is returned as the first buffer or is
+it returned together with the first frame. Applicable to encoders.
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE</constant>&nbsp;</entry>
+                     <entry>The stream header is returned separately in the first buffer.</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME</constant>&nbsp;</entry>
+                     <entry>The stream header is returned together with the first encoded frame.</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row><row><entry spanname="descr">Enabled the deblocking post processing filter for MPEG4 decoder.
+Applicable to the MPEG4 decoder.</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_VOP_TIME_RES</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">vop_time_increment_resolution value for MPEG4. Applicable to the MPEG4 encoder.</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_VOP_TIME_INC</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">vop_time_increment value for MPEG4. Applicable to the MPEG4 encoder.</entry>
+             </row>
+
+           </tbody>
+         </tgroup>
+       </table>
+      </section>
+
+      <section>
+       <title>MFC 5.1 MPEG Controls</title>
+
+       <para>The following MPEG class controls deal with MPEG
+decoding and encoding settings that are specific to the Multi Format Codec 5.1 device present
+in the S5P family of SoCs by Samsung.
+</para>
+
+       <table pgwide="1" frame="none" id="mfc51-control-id">
+         <title>MFC 5.1 Control IDs</title>
+         <tgroup cols="4">
+           <colspec colname="c1" colwidth="1*" />
+           <colspec colname="c2" colwidth="6*" />
+           <colspec colname="c3" colwidth="2*" />
+           <colspec colname="c4" colwidth="6*" />
+           <spanspec namest="c1" nameend="c2" spanname="id" />
+           <spanspec namest="c2" nameend="c4" spanname="descr" />
+           <thead>
+             <row>
+               <entry spanname="id" align="left">ID</entry>
+               <entry align="left">Type</entry>
+             </row><row><entry spanname="descr" align="left">Description</entry>
+             </row>
+           </thead>
+           <tbody valign="top">
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">If the display delay is enabled then the decoder has to return a
+CAPTURE buffer after processing a certain number of OUTPUT buffers. If this number is low, then it may result in
+buffers not being dequeued in display order. In addition hardware may still use those buffers as reference, thus
+application should not write to those buffers. This feature can be used for example for generating thumbnails of videos.
+Applicable to the H264 decoder.
+             </entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">Display delay value for H264 decoder.
+The decoder is forced to return a decoded frame after the set 'display delay' number of frames. If this number is
+low it may result in frames returned out of dispaly order, in addition the hardware may still be using the returned buffer
+as a reference picture for subsequent frames.
+</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">The number of reference pictures used for encoding a P picture.
+Applicable to the H264 encoder.</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_PADDING</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row><row><entry spanname="descr">Padding enable in the encoder - use a color instead of repeating border pixels.
+Applicable to encoders.</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">Padding color in the encoder. Applicable to encoders. The supplied 32-bit integer is interpreted as follows (bit
+0 = least significant bit):</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry>Bit 0:7</entry>
+                     <entry>V chrominance information</entry>
+                   </row>
+                   <row>
+                     <entry>Bit 8:15</entry>
+                     <entry>U chrominance information</entry>
+                   </row>
+                   <row>
+                     <entry>Bit 16:23</entry>
+                     <entry>Y luminance information</entry>
+                   </row>
+                   <row>
+                     <entry>Bit 24:31</entry>
+                     <entry>Must be zero.</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">Reaction coefficient for MFC rate control. Applicable to encoders.
+<para>Note 1: Valid only when the frame level RC is enabled.</para>
+<para>Note 2: For tight CBR, this field must be small (ex. 2 ~ 10).
+For VBR, this field must be large (ex. 100 ~ 1000).</para>
+<para>Note 3: It is not recommended to use the greater number than FRAME_RATE * (10^9 / BIT_RATE).</para>
+</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row><row><entry spanname="descr">Adaptive rate control for dark region.
+Valid only when H.264 and macroblock level RC is enabled (<constant>V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE</constant>).
+Applicable to the H264 encoder.</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row><row><entry spanname="descr">Adaptive rate control for smooth region.
+Valid only when H.264 and macroblock level RC is enabled (<constant>V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE</constant>).
+Applicable to the H264 encoder.</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row><row><entry spanname="descr">Adaptive rate control for static region.
+Valid only when H.264 and macroblock level RC is enabled (<constant>V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE</constant>).
+Applicable to the H264 encoder.</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row><row><entry spanname="descr">Adaptive rate control for activity region.
+Valid only when H.264 and macroblock level RC is enabled (<constant>V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE</constant>).
+Applicable to the H264 encoder.</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_mfc51_frame_skip_mode</entry>
+             </row>
+             <row><entry spanname="descr">
+Indicates in what conditions the encoder should skip frames. If encoding a frame would cause the encoded stream to be larger then
+a chosen data limit then the frame will be skipped.
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_MFC51_FRAME_SKIP_MODE_DISABLED</constant>&nbsp;</entry>
+                     <entry>Frame skip mode is disabled.</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_MFC51_FRAME_SKIP_MODE_LEVEL_LIMIT</constant>&nbsp;</entry>
+                     <entry>Frame skip mode enabled and buffer limit is set by the chosen level and is defined by the standard.</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_MFC51_FRAME_SKIP_MODE_BUF_LIMIT</constant>&nbsp;</entry>
+                     <entry>Frame skip mode enabled and buffer limit is set by the VBV (MPEG1/2/4) or CPB (H264) buffer size control.</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">Enable rate-control with fixed target bit.
+If this setting is enabled, then the rate control logic of the encoder will calculate the average bitrate
+for a GOP and keep it below or equal the set bitrate target. Otherwise the rate control logic calculates the
+overall average bitrate for the stream and keeps it below or equal to the set bitrate. In the first case
+the average bitrate for the whole stream will be smaller then the set bitrate. This is caused because the
+average is calculated for smaller number of frames, on the other hand enabling this setting will ensure that
+the stream will meet tight bandwidth contraints. Applicable to encoders.
+</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_mfc51_force_frame_type</entry>
+             </row>
+             <row><entry spanname="descr">Force a frame type for the next queued buffer. Applicable to encoders.
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_MFC51_FORCE_FRAME_TYPE_DISABLED</constant>&nbsp;</entry>
+                     <entry>Forcing a specific frame type disabled.</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_MFC51_FORCE_FRAME_TYPE_I_FRAME</constant>&nbsp;</entry>
+                     <entry>Force an I-frame.</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_MFC51_FORCE_FRAME_TYPE_NOT_CODED</constant>&nbsp;</entry>
+                     <entry>Force a non-coded frame.</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+           </tbody>
+         </tgroup>
+       </table>
+      </section>
+
+      <section>
+       <title>CX2341x MPEG Controls</title>
+
+       <para>The following MPEG class controls deal with MPEG
+encoding settings that are specific to the Conexant CX23415 and
+CX23416 MPEG encoding chips.</para>
+
+       <table pgwide="1" frame="none" id="cx2341x-control-id">
+         <title>CX2341x Control IDs</title>
+         <tgroup cols="4">
+           <colspec colname="c1" colwidth="1*" />
+           <colspec colname="c2" colwidth="6*" />
+           <colspec colname="c3" colwidth="2*" />
+           <colspec colname="c4" colwidth="6*" />
+           <spanspec namest="c1" nameend="c2" spanname="id" />
+           <spanspec namest="c2" nameend="c4" spanname="descr" />
+           <thead>
+             <row>
+               <entry spanname="id" align="left">ID</entry>
+               <entry align="left">Type</entry>
+             </row><row><entry spanname="descr" align="left">Description</entry>
+             </row>
+           </thead>
+           <tbody valign="top">
+             <row><entry></entry></row>
+             <row id="v4l2-mpeg-cx2341x-video-spatial-filter-mode">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_cx2341x_video_spatial_filter_mode</entry>
+             </row><row><entry spanname="descr">Sets the Spatial
+Filter mode (default <constant>MANUAL</constant>). Possible values
+are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL</constant>&nbsp;</entry>
+                     <entry>Choose the filter manually</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO</constant>&nbsp;</entry>
+                     <entry>Choose the filter automatically</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER</constant>&nbsp;</entry>
+               <entry>integer&nbsp;(0-15)</entry>
+             </row><row><entry spanname="descr">The setting for the
+Spatial Filter. 0 = off, 15 = maximum. (Default is 0.)</entry>
+             </row>
+             <row><entry></entry></row>
+             <row id="luma-spatial-filter-type">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_cx2341x_video_luma_spatial_filter_type</entry>
+             </row><row><entry spanname="descr">Select the algorithm
+to use for the Luma Spatial Filter (default
+<constant>1D_HOR</constant>). Possible values:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF</constant>&nbsp;</entry>
+                     <entry>No filter</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR</constant>&nbsp;</entry>
+                     <entry>One-dimensional horizontal</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_VERT</constant>&nbsp;</entry>
+                     <entry>One-dimensional vertical</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_HV_SEPARABLE</constant>&nbsp;</entry>
+                     <entry>Two-dimensional separable</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE</constant>&nbsp;</entry>
+                     <entry>Two-dimensional symmetrical
+non-separable</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row id="chroma-spatial-filter-type">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type</entry>
+             </row><row><entry spanname="descr">Select the algorithm
+for the Chroma Spatial Filter (default <constant>1D_HOR</constant>).
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF</constant>&nbsp;</entry>
+                     <entry>No filter</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR</constant>&nbsp;</entry>
+                     <entry>One-dimensional horizontal</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row id="v4l2-mpeg-cx2341x-video-temporal-filter-mode">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_cx2341x_video_temporal_filter_mode</entry>
+             </row><row><entry spanname="descr">Sets the Temporal
+Filter mode (default <constant>MANUAL</constant>). Possible values
+are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL</constant>&nbsp;</entry>
+                     <entry>Choose the filter manually</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO</constant>&nbsp;</entry>
+                     <entry>Choose the filter automatically</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER</constant>&nbsp;</entry>
+               <entry>integer&nbsp;(0-31)</entry>
+             </row><row><entry spanname="descr">The setting for the
+Temporal Filter. 0 = off, 31 = maximum. (Default is 8 for full-scale
+capturing and 0 for scaled capturing.)</entry>
+             </row>
+             <row><entry></entry></row>
+             <row id="v4l2-mpeg-cx2341x-video-median-filter-type">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_cx2341x_video_median_filter_type</entry>
+             </row><row><entry spanname="descr">Median Filter Type
+(default <constant>OFF</constant>). Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF</constant>&nbsp;</entry>
+                     <entry>No filter</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR</constant>&nbsp;</entry>
+                     <entry>Horizontal filter</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_VERT</constant>&nbsp;</entry>
+                     <entry>Vertical filter</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR_VERT</constant>&nbsp;</entry>
+                     <entry>Horizontal and vertical filter</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG</constant>&nbsp;</entry>
+                     <entry>Diagonal filter</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM</constant>&nbsp;</entry>
+               <entry>integer&nbsp;(0-255)</entry>
+             </row><row><entry spanname="descr">Threshold above which
+the luminance median filter is enabled (default 0)</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP</constant>&nbsp;</entry>
+               <entry>integer&nbsp;(0-255)</entry>
+             </row><row><entry spanname="descr">Threshold below which
+the luminance median filter is enabled (default 255)</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM</constant>&nbsp;</entry>
+               <entry>integer&nbsp;(0-255)</entry>
+             </row><row><entry spanname="descr">Threshold above which
+the chroma median filter is enabled (default 0)</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP</constant>&nbsp;</entry>
+               <entry>integer&nbsp;(0-255)</entry>
+             </row><row><entry spanname="descr">Threshold below which
+the chroma median filter is enabled (default 255)</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row>
+             <row><entry spanname="descr">The CX2341X MPEG encoder
+can insert one empty MPEG-2 PES packet into the stream between every
+four video frames. The packet size is 2048 bytes, including the
+packet_start_code_prefix and stream_id fields. The stream_id is 0xBF
+(private stream 2). The payload consists of 0x00 bytes, to be filled
+in by the application. 0 = do not insert, 1 = insert packets.</entry>
+             </row>
+           </tbody>
          </tgroup>
        </table>
       </section>
@@ -2092,6 +3072,289 @@ manually or automatically if set to zero. Unit, range and step are driver-specif
 <para>For more details about RDS specification, refer to
 <xref linkend="en50067" /> document, from CENELEC.</para>
     </section>
+
+    <section id="flash-controls">
+      <title>Flash Control Reference</title>
+
+      <note>
+       <title>Experimental</title>
+
+       <para>This is an <link linkend="experimental">experimental</link>
+interface and may change in the future.</para>
+      </note>
+
+      <para>
+       The V4L2 flash controls are intended to provide generic access
+       to flash controller devices. Flash controller devices are
+       typically used in digital cameras.
+      </para>
+
+      <para>
+       The interface can support both LED and xenon flash devices. As
+       of writing this, there is no xenon flash driver using this
+       interface.
+      </para>
+
+      <section id="flash-controls-use-cases">
+       <title>Supported use cases</title>
+
+       <section>
+         <title>Unsynchronised LED flash (software strobe)</title>
+
+         <para>
+           Unsynchronised LED flash is controlled directly by the
+           host as the sensor. The flash must be enabled by the host
+           before the exposure of the image starts and disabled once
+           it ends. The host is fully responsible for the timing of
+           the flash.
+         </para>
+
+         <para>Example of such device: Nokia N900.</para>
+       </section>
+
+       <section>
+         <title>Synchronised LED flash (hardware strobe)</title>
+
+         <para>
+           The synchronised LED flash is pre-programmed by the host
+           (power and timeout) but controlled by the sensor through a
+           strobe signal from the sensor to the flash.
+         </para>
+
+         <para>
+           The sensor controls the flash duration and timing. This
+           information typically must be made available to the
+           sensor.
+         </para>
+
+       </section>
+
+       <section>
+         <title>LED flash as torch</title>
+
+         <para>
+           LED flash may be used as torch in conjunction with another
+           use case involving camera or individually.
+         </para>
+
+       </section>
+
+      </section>
+
+      <table pgwide="1" frame="none" id="flash-control-id">
+      <title>Flash Control IDs</title>
+
+      <tgroup cols="4">
+       <colspec colname="c1" colwidth="1*" />
+       <colspec colname="c2" colwidth="6*" />
+       <colspec colname="c3" colwidth="2*" />
+       <colspec colname="c4" colwidth="6*" />
+       <spanspec namest="c1" nameend="c2" spanname="id" />
+       <spanspec namest="c2" nameend="c4" spanname="descr" />
+       <thead>
+         <row>
+           <entry spanname="id" align="left">ID</entry>
+           <entry align="left">Type</entry>
+         </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
+         </row>
+       </thead>
+       <tbody valign="top">
+         <row><entry></entry></row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FLASH_CLASS</constant></entry>
+           <entry>class</entry>
+         </row>
+         <row>
+           <entry spanname="descr">The FLASH class descriptor.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FLASH_LED_MODE</constant></entry>
+           <entry>menu</entry>
+         </row>
+         <row id="v4l2-flash-led-mode">
+           <entry spanname="descr">Defines the mode of the flash LED,
+           the high-power white LED attached to the flash controller.
+           Setting this control may not be possible in presence of
+           some faults. See V4L2_CID_FLASH_FAULT.</entry>
+         </row>
+         <row>
+           <entrytbl spanname="descr" cols="2">
+             <tbody valign="top">
+               <row>
+                 <entry><constant>V4L2_FLASH_LED_MODE_NONE</constant></entry>
+                 <entry>Off.</entry>
+               </row>
+               <row>
+                 <entry><constant>V4L2_FLASH_LED_MODE_FLASH</constant></entry>
+                 <entry>Flash mode.</entry>
+               </row>
+               <row>
+                 <entry><constant>V4L2_FLASH_LED_MODE_TORCH</constant></entry>
+                 <entry>Torch mode. See V4L2_CID_FLASH_TORCH_INTENSITY.</entry>
+               </row>
+             </tbody>
+           </entrytbl>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE_SOURCE</constant></entry>
+           <entry>menu</entry>
+         </row>
+         <row id="v4l2-flash-strobe-source"><entry
+         spanname="descr">Defines the source of the flash LED
+         strobe.</entry>
+         </row>
+         <row>
+           <entrytbl spanname="descr" cols="2">
+             <tbody valign="top">
+               <row>
+                 <entry><constant>V4L2_FLASH_STROBE_SOURCE_SOFTWARE</constant></entry>
+                 <entry>The flash strobe is triggered by using
+                 the V4L2_CID_FLASH_STROBE control.</entry>
+               </row>
+               <row>
+                 <entry><constant>V4L2_FLASH_STROBE_SOURCE_EXTERNAL</constant></entry>
+                 <entry>The flash strobe is triggered by an
+                 external source. Typically this is a sensor,
+                 which makes it possible to synchronises the
+                 flash strobe start to exposure start.</entry>
+               </row>
+             </tbody>
+           </entrytbl>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE</constant></entry>
+           <entry>button</entry>
+         </row>
+         <row>
+           <entry spanname="descr">Strobe flash. Valid when
+           V4L2_CID_FLASH_LED_MODE is set to
+           V4L2_FLASH_LED_MODE_FLASH and V4L2_CID_FLASH_STROBE_SOURCE
+           is set to V4L2_FLASH_STROBE_SOURCE_SOFTWARE. Setting this
+           control may not be possible in presence of some faults.
+           See V4L2_CID_FLASH_FAULT.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE_STOP</constant></entry>
+           <entry>button</entry>
+         </row>
+         <row><entry spanname="descr">Stop flash strobe immediately.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE_STATUS</constant></entry>
+           <entry>boolean</entry>
+         </row>
+         <row>
+           <entry spanname="descr">Strobe status: whether the flash
+           is strobing at the moment or not. This is a read-only
+           control.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FLASH_TIMEOUT</constant></entry>
+           <entry>integer</entry>
+         </row>
+         <row>
+           <entry spanname="descr">Hardware timeout for flash. The
+           flash strobe is stopped after this period of time has
+           passed from the start of the strobe.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FLASH_INTENSITY</constant></entry>
+           <entry>integer</entry>
+         </row>
+         <row>
+           <entry spanname="descr">Intensity of the flash strobe when
+           the flash LED is in flash mode
+           (V4L2_FLASH_LED_MODE_FLASH). The unit should be milliamps
+           (mA) if possible.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FLASH_TORCH_INTENSITY</constant></entry>
+           <entry>integer</entry>
+         </row>
+         <row>
+           <entry spanname="descr">Intensity of the flash LED in
+           torch mode (V4L2_FLASH_LED_MODE_TORCH). The unit should be
+           milliamps (mA) if possible. Setting this control may not
+           be possible in presence of some faults. See
+           V4L2_CID_FLASH_FAULT.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FLASH_INDICATOR_INTENSITY</constant></entry>
+           <entry>integer</entry>
+         </row>
+         <row>
+           <entry spanname="descr">Intensity of the indicator LED.
+           The indicator LED may be fully independent of the flash
+           LED. The unit should be microamps (uA) if possible.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FLASH_FAULT</constant></entry>
+           <entry>bitmask</entry>
+         </row>
+         <row>
+           <entry spanname="descr">Faults related to the flash. The
+           faults tell about specific problems in the flash chip
+           itself or the LEDs attached to it. Faults may prevent
+           further use of some of the flash controls. In particular,
+           V4L2_CID_FLASH_LED_MODE is set to V4L2_FLASH_LED_MODE_NONE
+           if the fault affects the flash LED. Exactly which faults
+           have such an effect is chip dependent. Reading the faults
+           resets the control and returns the chip to a usable state
+           if possible.</entry>
+         </row>
+         <row>
+           <entrytbl spanname="descr" cols="2">
+             <tbody valign="top">
+               <row>
+                 <entry><constant>V4L2_FLASH_FAULT_OVER_VOLTAGE</constant></entry>
+                 <entry>Flash controller voltage to the flash LED
+                 has exceeded the limit specific to the flash
+                 controller.</entry>
+               </row>
+               <row>
+                 <entry><constant>V4L2_FLASH_FAULT_TIMEOUT</constant></entry>
+                 <entry>The flash strobe was still on when
+                 the timeout set by the user ---
+                 V4L2_CID_FLASH_TIMEOUT control --- has expired.
+                 Not all flash controllers may set this in all
+                 such conditions.</entry>
+               </row>
+               <row>
+                 <entry><constant>V4L2_FLASH_FAULT_OVER_TEMPERATURE</constant></entry>
+                 <entry>The flash controller has overheated.</entry>
+               </row>
+               <row>
+                 <entry><constant>V4L2_FLASH_FAULT_SHORT_CIRCUIT</constant></entry>
+                 <entry>The short circuit protection of the flash
+                 controller has been triggered.</entry>
+               </row>
+             </tbody>
+           </entrytbl>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FLASH_CHARGE</constant></entry>
+           <entry>boolean</entry>
+         </row>
+         <row><entry spanname="descr">Enable or disable charging of the xenon
+         flash capacitor.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FLASH_READY</constant></entry>
+           <entry>boolean</entry>
+         </row>
+         <row>
+           <entry spanname="descr">Is the flash ready to strobe?
+           Xenon flashes require their capacitors charged before
+           strobing. LED flashes often require a cooldown period
+           after strobe during which another strobe will not be
+           possible. This is a read-only control.</entry>
+         </row>
+         <row><entry></entry></row>
+       </tbody>
+      </tgroup>
+      </table>
+
+    </section>
 </section>
 
   <!--
diff --git a/Documentation/DocBook/media/v4l/dev-event.xml b/Documentation/DocBook/media/v4l/dev-event.xml
new file mode 100644 (file)
index 0000000..f14ae3f
--- /dev/null
@@ -0,0 +1,51 @@
+  <title>Event Interface</title>
+
+  <para>The V4L2 event interface provides a means for a user to get
+  immediately notified on certain conditions taking place on a device.
+  This might include start of frame or loss of signal events, for
+  example. Changes in the value or state of a V4L2 control can also be
+  reported through events.
+  </para>
+
+  <para>To receive events, the events the user is interested in first must
+  be subscribed using the &VIDIOC-SUBSCRIBE-EVENT; ioctl. Once an event is
+  subscribed, the events of subscribed types are dequeueable using the
+  &VIDIOC-DQEVENT; ioctl. Events may be unsubscribed using
+  VIDIOC_UNSUBSCRIBE_EVENT ioctl. The special event type V4L2_EVENT_ALL may
+  be used to unsubscribe all the events the driver supports.</para>
+
+  <para>The event subscriptions and event queues are specific to file
+  handles. Subscribing an event on one file handle does not affect
+  other file handles.</para>
+
+  <para>The information on dequeueable events is obtained by using select or
+  poll system calls on video devices. The V4L2 events use POLLPRI events on
+  poll system call and exceptions on select system call.</para>
+
+  <para>Starting with kernel 3.1 certain guarantees can be given with
+  regards to events:<orderedlist>
+       <listitem>
+         <para>Each subscribed event has its own internal dedicated event queue.
+This means that flooding of one event type will not interfere with other
+event types.</para>
+       </listitem>
+       <listitem>
+         <para>If the internal event queue for a particular subscribed event
+becomes full, then the oldest event in that queue will be dropped.</para>
+       </listitem>
+       <listitem>
+         <para>Where applicable, certain event types can ensure that the payload
+of the oldest event that is about to be dropped will be merged with the payload
+of the next oldest event. Thus ensuring that no information is lost, but only an
+intermediate step leading up to that information. See the documentation for the
+event you want to subscribe to whether this is applicable for that event or not.</para>
+       </listitem>
+      </orderedlist></para>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/func-ioctl.xml b/Documentation/DocBook/media/v4l/func-ioctl.xml
new file mode 100644 (file)
index 0000000..2de64be
--- /dev/null
@@ -0,0 +1,79 @@
+<refentry id="func-ioctl">
+  <refmeta>
+    <refentrytitle>V4L2 ioctl()</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>v4l2-ioctl</refname>
+    <refpurpose>Program a V4L2 device</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>#include &lt;sys/ioctl.h&gt;</funcsynopsisinfo>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>void *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>V4L2 ioctl request code as defined in the <filename>videodev2.h</filename> header file, for example
+VIDIOC_QUERYCAP.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para>Pointer to a function parameter, usually a structure.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>The <function>ioctl()</function> function is used to program
+V4L2 devices. The argument <parameter>fd</parameter> must be an open
+file descriptor. An ioctl <parameter>request</parameter> has encoded
+in it whether the argument is an input, output or read/write
+parameter, and the size of the argument <parameter>argp</parameter> in
+bytes. Macros and defines specifying V4L2 ioctl requests are located
+in the <filename>videodev2.h</filename> header file.
+Applications should use their own copy, not include the version in the
+kernel sources on the system they compile on. All V4L2 ioctl requests,
+their respective function and parameters are specified in <xref
+       linkend="user-func" />.</para>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+    <para>When an ioctl that takes an output or read/write parameter fails,
+    the parameter remains unmodified.</para>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/gen-errors.xml b/Documentation/DocBook/media/v4l/gen-errors.xml
new file mode 100644 (file)
index 0000000..5bbf3ce
--- /dev/null
@@ -0,0 +1,78 @@
+<title>Generic Error Codes</title>
+
+<table frame="none" pgwide="1" id="gen-errors">
+  <title>Generic error codes</title>
+  <tgroup cols="2">
+    &cs-str;
+    <tbody valign="top">
+       <!-- Keep it ordered alphabetically -->
+      <row>
+       <entry>EBADF</entry>
+       <entry>The file descriptor is not a valid.</entry>
+      </row>
+      <row>
+       <entry>EBUSY</entry>
+       <entry>The ioctl can't be handled because the device is busy. This is
+              typically return while device is streaming, and an ioctl tried to
+              change something that would affect the stream, or would require the
+              usage of a hardware resource that was already allocated. The ioctl
+              must not be retried without performing another action to fix the
+              problem first (typically: stop the stream before retrying).</entry>
+      </row>
+      <row>
+       <entry>EFAULT</entry>
+       <entry>There was a failure while copying data from/to userspace,
+              probably caused by an invalid pointer reference.</entry>
+      </row>
+      <row>
+       <entry>EINVAL</entry>
+       <entry>One or more of the ioctl parameters are invalid or out of the
+              allowed range. This is a widely used error code. See the individual
+              ioctl requests for specific causes.</entry>
+      </row>
+      <row>
+        <entry>ENODEV</entry>
+       <entry>Device not found or was removed.</entry>
+      </row>
+      <row>
+       <entry>ENOMEM</entry>
+       <entry>There's not enough memory to handle the desired operation.</entry>
+      </row>
+      <row>
+       <entry>ENOTTY</entry>
+       <entry>The ioctl is not supported by the driver, actually meaning that
+              the required functionality is not available, or the file
+              descriptor is not for a media device.</entry>
+      </row>
+      <row>
+       <entry>ENOSPC</entry>
+       <entry>On USB devices, the stream ioctl's can return this error, meaning
+              that this request would overcommit the usb bandwidth reserved
+              for periodic transfers (up to 80% of the USB bandwidth).</entry>
+      </row>
+      <row>
+       <entry>ENOSYS or EOPNOTSUPP</entry>
+       <entry>Function not available for this device (dvb API only. Will likely
+              be replaced anytime soon by ENOTTY).</entry>
+      </row>
+      <row>
+       <entry>EPERM</entry>
+       <entry>Permission denied. Can be returned if the device needs write
+               permission, or some special capabilities is needed
+               (e. g. root)</entry>
+      </row>
+      <row>
+       <entry>EWOULDBLOCK</entry>
+       <entry>Operation would block. Used when the ioctl would need to wait
+              for an event, but the device was opened in non-blocking mode.</entry>
+      </row>
+    </tbody>
+  </tgroup>
+</table>
+
+<para>Note 1: ioctls may return other error codes. Since errors may have side
+effects such as a driver reset, applications should abort on unexpected errors.
+</para>
+
+<para>Note 2: Request-specific error codes are listed in the individual
+requests descriptions.</para>
@@ -246,6 +246,8 @@ on working with the default settings initially.</para>
     </listitem>
   </varlistentry>
 </variablelist>
-
+<section id="lirc_dev_errors">
+  &return-value;
+</section>
 </section>
 </section>
   </refsect1>
 
   <refsect1>
-    <title>Return Value</title>
+    &return-value;
 
-    <para><function>ioctl()</function> returns <returnvalue>0</returnvalue> on
-    success. On failure, <returnvalue>-1</returnvalue> is returned, and the
-    <varname>errno</varname> variable is set appropriately. Generic error codes
-    are listed below, and request-specific error codes are listed in the
+    <para>Request-specific error codes are listed in the
     individual requests descriptions.</para>
     <para>When an ioctl that takes an output or read/write parameter fails,
     the parameter remains unmodified.</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBADF</errorcode></term>
-       <listitem>
-         <para><parameter>fd</parameter> is not a valid open file descriptor.
-         </para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EFAULT</errorcode></term>
-       <listitem>
-         <para><parameter>argp</parameter> references an inaccessible memory
-         area.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The <parameter>request</parameter> or the data pointed to by
-         <parameter>argp</parameter> is not valid. This is a very common error
-         code, see the individual ioctl requests listed in
-         <xref linkend="media-user-func" /> for actual causes.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENOMEM</errorcode></term>
-       <listitem>
-         <para>Insufficient kernel memory was available to complete the
-         request.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENOTTY</errorcode></term>
-       <listitem>
-         <para><parameter>fd</parameter> is  not  associated  with  a character
-         special device.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
   </refsect1>
 </refentry>
   </refsect1>
 
   <refsect1>
-    <title>Return value</title>
-    <para>This function doesn't return specific error codes.</para>
+    &return-value;
   </refsect1>
 </refentry>
     </table>
 
     <table pgwide="1" frame="none" id="media-link-desc">
-      <title>struct <structname>media_links_desc</structname></title>
+      <title>struct <structname>media_link_desc</structname></title>
       <tgroup cols="3">
         &cs-str;
        <tbody valign="top">
     &return-value;
 
     <variablelist>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The link properties can't be changed because the link is
-         currently busy. This can be caused, for instance, by an active media
-         stream (audio or video) on the link. The ioctl shouldn't be retried if
-         no other action is performed before to fix the problem.</para>
-       </listitem>
-      </varlistentry>
       <varlistentry>
        <term><errorcode>EINVAL</errorcode></term>
        <listitem>
similarity index 94%
rename from Documentation/DocBook/v4l/pixfmt.xml
rename to Documentation/DocBook/media/v4l/pixfmt.xml
index deb6602..2ff6b77 100644 (file)
@@ -121,7 +121,7 @@ set this field to zero.</entry>
     an array of <structname>v4l2_plane_pix_format</structname> structures,
     describing all planes of that format.</para>
   <table pgwide="1" frame="none" id="v4l2-plane-pix-format">
-    <title>struct <structname>vl42_plane_pix_format</structname></title>
+    <title>struct <structname>v4l2_plane_pix_format</structname></title>
     <tgroup cols="3">
       &cs-str;
       <tbody valign="top">
@@ -741,10 +741,55 @@ information.</para>
          <row id="V4L2-PIX-FMT-MPEG">
            <entry><constant>V4L2_PIX_FMT_MPEG</constant></entry>
            <entry>'MPEG'</entry>
-           <entry>MPEG stream. The actual format is determined by
+           <entry>MPEG multiplexed stream. The actual format is determined by
 extended control <constant>V4L2_CID_MPEG_STREAM_TYPE</constant>, see
 <xref linkend="mpeg-control-id" />.</entry>
          </row>
+         <row id="V4L2-PIX-FMT-H264">
+               <entry><constant>V4L2_PIX_FMT_H264</constant></entry>
+               <entry>'H264'</entry>
+               <entry>H264 video elementary stream with start codes.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-H264-NO-SC">
+               <entry><constant>V4L2_PIX_FMT_H264_NO_SC</constant></entry>
+               <entry>'AVC1'</entry>
+               <entry>H264 video elementary stream without start codes.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-H263">
+               <entry><constant>V4L2_PIX_FMT_H263</constant></entry>
+               <entry>'H263'</entry>
+               <entry>H263 video elementary stream.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-MPEG1">
+               <entry><constant>V4L2_PIX_FMT_MPEG1</constant></entry>
+               <entry>'MPG1'</entry>
+               <entry>MPEG1 video elementary stream.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-MPEG2">
+               <entry><constant>V4L2_PIX_FMT_MPEG2</constant></entry>
+               <entry>'MPG2'</entry>
+               <entry>MPEG2 video elementary stream.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-MPEG4">
+               <entry><constant>V4L2_PIX_FMT_MPEG4</constant></entry>
+               <entry>'MPG4'</entry>
+               <entry>MPEG4 video elementary stream.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-XVID">
+               <entry><constant>V4L2_PIX_FMT_XVID</constant></entry>
+               <entry>'XVID'</entry>
+               <entry>Xvid video elementary stream.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-VC1-ANNEX-G">
+               <entry><constant>V4L2_PIX_FMT_VC1_ANNEX_G</constant></entry>
+               <entry>'VC1G'</entry>
+               <entry>VC1, SMPTE 421M Annex G compliant stream.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-VC1-ANNEX-L">
+               <entry><constant>V4L2_PIX_FMT_VC1_ANNEX_L</constant></entry>
+               <entry>'VC1L'</entry>
+               <entry>VC1, SMPTE 421M Annex L compliant stream.</entry>
+         </row>
        </tbody>
       </tgroup>
     </table>
@@ -804,6 +849,12 @@ kernel sources in the file <filename>Documentation/video4linux/cx2341x/README.hm
            <entry>'CPIA'</entry>
            <entry>YUV format used by the gspca cpia1 driver.</entry>
          </row>
+         <row id="V4L2-PIX-FMT-JPGL">
+           <entry><constant>V4L2_PIX_FMT_JPGL</constant></entry>
+           <entry>'JPGL'</entry>
+           <entry>JPEG-Light format (Pegasus Lossless JPEG)
+                       used in Divio webcams NW 80x.</entry>
+         </row>
          <row id="V4L2-PIX-FMT-SPCA501">
            <entry><constant>V4L2_PIX_FMT_SPCA501</constant></entry>
            <entry>'S501'</entry>
@@ -854,6 +905,11 @@ kernel sources in the file <filename>Documentation/video4linux/cx2341x/README.hm
            <entry>'PJPG'</entry>
            <entry>Pixart 73xx JPEG format used by the gspca driver.</entry>
          </row>
+         <row id="V4L2-PIX-FMT-SE401">
+           <entry><constant>V4L2_PIX_FMT_SE401</constant></entry>
+           <entry>'S401'</entry>
+           <entry>Compressed RGB format used by the gspca se401 driver</entry>
+         </row>
          <row id="V4L2-PIX-FMT-SQ905C">
            <entry><constant>V4L2_PIX_FMT_SQ905C</constant></entry>
            <entry>'905C'</entry>
       <figure id="bayer-patterns">
        <title>Bayer Patterns</title>
        <mediaobject>
-         <imageobject>
-           <imagedata fileref="bayer.pdf" format="PS" />
-         </imageobject>
          <imageobject>
            <imagedata fileref="bayer.png" format="PNG" />
          </imageobject>
 
       <para>Those data formats consist of an ordered sequence of 8-bit bytes
        obtained from JPEG compression process. Additionally to the
-       <constant>_JPEG</constant> prefix the format code is made of
+       <constant>_JPEG</constant> postfix the format code is made of
        the following information.
        <itemizedlist>
          <listitem><para>The number of bus samples per entropy encoded byte.</para></listitem>
similarity index 97%
rename from Documentation/DocBook/v4l/v4l2.xml
rename to Documentation/DocBook/media/v4l/v4l2.xml
index a7fd76d..0d05e87 100644 (file)
@@ -87,7 +87,7 @@ Remote Controller chapter.</contrib>
       </author>
 
       <author>
-       <firstname>Pawel</firstname>
+       <firstname>Pawel</firstname>
        <surname>Osciak</surname>
        <contrib>Designed and documented the multi-planar API.</contrib>
        <affiliation>
@@ -127,6 +127,15 @@ structs, ioctls) must be noted in more detail in the history chapter
 (compat.xml), along with the possible impact on existing drivers and
 applications. -->
 
+      <revision>
+       <revnumber>3.1</revnumber>
+       <date>2011-06-27</date>
+       <authorinitials>mcc, po, hv</authorinitials>
+       <revremark>Documented that VIDIOC_QUERYCAP now returns a per-subsystem version instead of a per-driver one.
+                  Standardize an error code for invalid ioctl.
+                  Added V4L2_CTRL_TYPE_BITMASK.</revremark>
+      </revision>
+
       <revision>
        <revnumber>2.6.39</revnumber>
        <date>2011-03-01</date>
@@ -401,7 +410,7 @@ and discussions on the V4L mailing list.</revremark>
 </partinfo>
 
 <title>Video for Linux Two API Specification</title>
- <subtitle>Revision 2.6.39</subtitle>
+ <subtitle>Revision 3.1</subtitle>
 
   <chapter id="common">
     &sub-common;
@@ -156,19 +156,10 @@ on 22 Oct 2002 subject "Re:[V4L][patches!] Re:v4l2/kernel-2.5" -->
        <term><errorcode>EINVAL</errorcode></term>
        <listitem>
          <para>The &v4l2-cropcap; <structfield>type</structfield> is
-invalid or the ioctl is not supported. This is not permitted for
-video capture, output and overlay devices, which must support
-<constant>VIDIOC_CROPCAP</constant>.</para>
+invalid. This is not permitted for video capture, output and overlay devices,
+which must support <constant>VIDIOC_CROPCAP</constant>.</para>
        </listitem>
       </varlistentry>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
@@ -258,18 +258,9 @@ could not identify it.</entry>
       <varlistentry>
        <term><errorcode>EINVAL</errorcode></term>
        <listitem>
-         <para>The driver does not support this ioctl, or the
-<structfield>match_type</structfield> is invalid.</para>
+         <para>The <structfield>match_type</structfield> is invalid.</para>
        </listitem>
       </varlistentry>
      </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
@@ -246,15 +246,6 @@ register.</entry>
     &return-value;
 
     <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The driver does not support this ioctl, or the kernel
-was not compiled with the <constant>CONFIG_VIDEO_ADV_DEBUG</constant>
-option, or the <structfield>match_type</structfield> is invalid, or the
-selected chip or register does not exist.</para>
-       </listitem>
-      </varlistentry>
       <varlistentry>
        <term><errorcode>EPERM</errorcode></term>
        <listitem>
@@ -265,11 +256,3 @@ to execute these ioctls.</para>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
            <entry>Event data for event V4L2_EVENT_VSYNC.
             </entry>
          </row>
+         <row>
+           <entry></entry>
+           <entry>&v4l2-event-ctrl;</entry>
+            <entry><structfield>ctrl</structfield></entry>
+           <entry>Event data for event V4L2_EVENT_CTRL.
+            </entry>
+         </row>
          <row>
            <entry></entry>
            <entry>__u8</entry>
             <entry></entry>
            <entry>Event timestamp.</entry>
          </row>
+         <row>
+           <entry>u32</entry>
+           <entry><structfield>id</structfield></entry>
+            <entry></entry>
+           <entry>The ID associated with the event source. If the event does not
+               have an associated ID (this depends on the event type), then this
+               is 0.</entry>
+         </row>
          <row>
            <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[9]</entry>
+           <entry><structfield>reserved</structfield>[8]</entry>
             <entry></entry>
            <entry>Reserved for future extensions. Drivers must set
            the array to zero.</entry>
     </table>
 
   </refsect1>
+  <refsect1>
+    &return-value;
+  </refsect1>
 </refentry>
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
@@ -180,8 +180,7 @@ Pictures</wordasword>, rather than immediately.</entry>
       <varlistentry>
        <term><errorcode>EINVAL</errorcode></term>
        <listitem>
-         <para>The driver does not support this ioctl, or the
-<structfield>cmd</structfield> field is invalid.</para>
+         <para>The <structfield>cmd</structfield> field is invalid.</para>
        </listitem>
       </varlistentry>
       <varlistentry>
@@ -194,11 +193,3 @@ the encoder was not running.</para>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
@@ -254,17 +254,6 @@ enumerated.</entry>
 
   <refsect1>
     &return-value;
-
-    <para>See the description section above for a list of return
-values that <varname>errno</varname> can have.</para>
   </refsect1>
 
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
@@ -267,16 +267,5 @@ application should zero out all members except for the
 
   <refsect1>
     &return-value;
-
-    <para>See the description section above for a list of return
-values that <varname>errno</varname> can have.</para>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
@@ -68,19 +68,9 @@ until the driver returns <errorcode>EINVAL</errorcode>.</para>
       <varlistentry>
        <term><errorcode>EINVAL</errorcode></term>
        <listitem>
-         <para>The number of the audio input is out of bounds, or
-there are no audio inputs at all and this ioctl is not
-supported.</para>
+         <para>The number of the audio input is out of bounds.</para>
        </listitem>
       </varlistentry>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
@@ -71,19 +71,9 @@ signal to a sound card are not audio outputs in this sense.</para>
       <varlistentry>
        <term><errorcode>EINVAL</errorcode></term>
        <listitem>
-         <para>The number of the audio output is out of bounds, or
-there are no audio outputs at all and this ioctl is not
-supported.</para>
+         <para>The number of the audio output is out of bounds.</para>
        </listitem>
       </varlistentry>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
@@ -164,25 +164,9 @@ tuner.</entry>
        <listitem>
          <para>No audio inputs combine with the current video input,
 or the number of the selected audio input is out of bounds or it does
-not combine, or there are no audio inputs at all and the ioctl is not
-supported.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>I/O is in progress, the input cannot be
-switched.</para>
+not combine.</para>
        </listitem>
       </varlistentry>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
@@ -130,25 +130,9 @@ applications must set the array to zero.</entry>
        <listitem>
          <para>No audio outputs combine with the current video
 output, or the number of the selected audio output is out of bounds or
-it does not combine, or there are no audio outputs at all and the
-ioctl is not supported.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>I/O is in progress, the output cannot be
-switched.</para>
+it does not combine.</para>
        </listitem>
       </varlistentry>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
@@ -122,22 +122,5 @@ for &v4l2-cropcap; <structfield>bounds</structfield> is used.</entry>
 
   <refsect1>
     &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>Cropping is not supported.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
@@ -117,6 +117,13 @@ because another applications took over control of the device function
 this control belongs to.</para>
        </listitem>
       </varlistentry>
+      <varlistentry>
+       <term><errorcode>EACCES</errorcode></term>
+       <listitem>
+         <para>Attempt to set a read-only control or to get a
+         write-only control.</para>
+       </listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 </refentry>
@@ -97,14 +97,8 @@ If the preset is not supported, it returns an &EINVAL; </para>
        </tbody>
       </tgroup>
     </table>
-
+  </refsect1>
+  <refsect1>
+    &return-value;
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
@@ -212,12 +212,7 @@ bit 0 (V4L2_DV_VSYNC_POS_POL) is for vertical sync polarity and bit 1 (V4L2_DV_H
       </tgroup>
     </table>
   </refsect1>
+  <refsect1>
+    &return-value;
+  </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
@@ -192,22 +192,5 @@ this mask to obtain the picture coding type.</entry>
 
   <refsect1>
     &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The driver does not support this ioctl.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
@@ -250,6 +250,13 @@ These controls are described in <xref
 These controls are described in <xref
                linkend="fm-tx-controls" />.</entry>
          </row>
+         <row>
+           <entry><constant>V4L2_CTRL_CLASS_FLASH</constant></entry>
+           <entry>0x9c0000</entry>
+           <entry>The class containing flash device controls.
+These controls are described in <xref
+               linkend="flash-controls" />.</entry>
+         </row>
        </tbody>
       </tgroup>
     </table>
@@ -294,6 +301,13 @@ The field <structfield>size</structfield> is set to a value that is enough
 to store the payload and this error code is returned.</para>
        </listitem>
       </varlistentry>
+      <varlistentry>
+       <term><errorcode>EACCES</errorcode></term>
+       <listitem>
+         <para>Attempt to try or set a read-only control or to get a
+         write-only control.</para>
+       </listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 </refentry>
@@ -445,29 +445,12 @@ by a privileged user to negotiate the parameters for a destructive
 overlay.</para>
        </listitem>
       </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The framebuffer parameters cannot be changed at this
-time because overlay is already enabled, or capturing is enabled
-and the hardware cannot capture and overlay simultaneously.</para>
-       </listitem>
-      </varlistentry>
       <varlistentry>
        <term><errorcode>EINVAL</errorcode></term>
        <listitem>
-         <para>The ioctl is not supported or the
-<constant>VIDIOC_S_FBUF</constant> parameters are unsuitable.</para>
+         <para>The <constant>VIDIOC_S_FBUF</constant> parameters are unsuitable.</para>
        </listitem>
       </varlistentry>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
@@ -183,30 +183,14 @@ capture and output devices.</entry>
     &return-value;
 
     <variablelist>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The data format cannot be changed at this
-time, for example because I/O is already in progress.</para>
-       </listitem>
-      </varlistentry>
       <varlistentry>
        <term><errorcode>EINVAL</errorcode></term>
        <listitem>
          <para>The &v4l2-format; <structfield>type</structfield>
-field is invalid, the requested buffer type not supported, or
-<constant>VIDIOC_TRY_FMT</constant> was called and is not
-supported with this buffer type.</para>
+field is invalid, the requested buffer type not supported, or the
+format is not supported with this buffer type.</para>
        </listitem>
       </varlistentry>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
@@ -75,26 +75,9 @@ querying or negotiating any other parameters.</para>
       <varlistentry>
        <term><errorcode>EINVAL</errorcode></term>
        <listitem>
-         <para>The number of the video input is out of bounds, or
-there are no video inputs at all and this ioctl is not
-supported.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>I/O is in progress, the input cannot be
-switched.</para>
+         <para>The number of the video input is out of bounds.</para>
        </listitem>
       </varlistentry>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
@@ -159,22 +159,5 @@ to add them.</para>
 
   <refsect1>
     &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>This ioctl is not supported.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
@@ -76,25 +76,9 @@ negotiating any other parameters.</para>
        <term><errorcode>EINVAL</errorcode></term>
        <listitem>
          <para>The number of the video output is out of bounds, or
-there are no video outputs at all and this ioctl is not
-supported.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>I/O is in progress, the output cannot be
-switched.</para>
+there are no video outputs at all.</para>
        </listitem>
       </varlistentry>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
@@ -311,22 +311,5 @@ excessive motion blur. </para>
 
   <refsect1>
     &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>This ioctl is not supported.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
@@ -120,8 +120,7 @@ recording.</entry>
       <varlistentry>
        <term><errorcode>EINVAL</errorcode></term>
        <listitem>
-         <para>The requested priority value is invalid, or the
-driver does not support access priorities.</para>
+         <para>The requested priority value is invalid.</para>
        </listitem>
       </varlistentry>
       <varlistentry>
@@ -246,19 +246,10 @@ line systems.</entry>
       <varlistentry>
        <term><errorcode>EINVAL</errorcode></term>
        <listitem>
-         <para>The device does not support sliced VBI capturing or
-output, or the value in the <structfield>type</structfield> field is
+         <para>The value in the <structfield>type</structfield> field is
 wrong.</para>
        </listitem>
       </varlistentry>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
@@ -82,14 +82,7 @@ standards.</para>
       <varlistentry>
        <term><errorcode>EINVAL</errorcode></term>
        <listitem>
-         <para>This ioctl is not supported, or the
-<constant>VIDIOC_S_STD</constant> parameter was unsuitable.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The device is busy and therefore can not change the standard</para>
+         <para>The <constant>VIDIOC_S_STD</constant> parameter was unsuitable.</para>
        </listitem>
       </varlistentry>
     </variablelist>
@@ -37,22 +37,5 @@ was introduced in Linux 2.6.15.</para>
 
   <refsect1>
     &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The driver does not support this ioctl.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
       <varlistentry>
        <term><errorcode>EINVAL</errorcode></term>
        <listitem>
-         <para>Video overlay is not supported, or the
-parameters have not been set up. See <xref
+         <para>The overlay parameters have not been set up. See <xref
 linkend="overlay" /> for the necessary steps.</para>
        </listitem>
       </varlistentry>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
similarity index 95%
rename from Documentation/DocBook/v4l/vidioc-qbuf.xml
rename to Documentation/DocBook/media/v4l/vidioc-qbuf.xml
index f2b11f8..9caa49a 100644 (file)
@@ -158,15 +158,6 @@ or no buffers have been allocated yet, or the
 <structfield>userptr</structfield> or
 <structfield>length</structfield> are invalid.</para>
        </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENOMEM</errorcode></term>
-       <listitem>
-         <para>Not enough physical or virtual memory was available to
-enqueue a user pointer buffer.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
        <term><errorcode>EIO</errorcode></term>
        <listitem>
          <para><constant>VIDIOC_DQBUF</constant> failed due to an
@@ -184,11 +175,3 @@ continue streaming.
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
@@ -61,27 +61,5 @@ returned.</para>
 
   <refsect1>
     &return-value;
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>This ioctl is not supported.</para>
-       </listitem>
-    </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The device is busy and therefore can not sense the preset</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
@@ -67,9 +67,8 @@ driver is not compatible with this specification the ioctl returns an
            <entry><para>Name of the driver, a unique NUL-terminated
 ASCII string. For example: "bttv". Driver specific applications can
 use this information to verify the driver identity. It is also useful
-to work around known bugs, or to identify drivers in error reports.
-The driver version is stored in the <structfield>version</structfield>
-field.</para><para>Storing strings in fixed sized arrays is bad
+to work around known bugs, or to identify drivers in error reports.</para>
+<para>Storing strings in fixed sized arrays is bad
 practice but unavoidable here. Drivers and applications should take
 precautions to never read or write beyond the end of the array and to
 make sure the strings are properly NUL-terminated.</para></entry>
@@ -100,9 +99,13 @@ empty string (<structfield>bus_info</structfield>[0] = 0).<!-- XXX pci_dev->slot
          <row>
            <entry>__u32</entry>
            <entry><structfield>version</structfield></entry>
-           <entry><para>Version number of the driver. Together with
-the <structfield>driver</structfield> field this identifies a
-particular driver. The version number is formatted using the
+           <entry><para>Version number of the driver.</para>
+<para>Starting on kernel 3.1, the version reported is provided per
+V4L2 subsystem, following the same Kernel numberation scheme. However, it
+should not always return the same version as the kernel, if, for example,
+an stable or distribution-modified kernel uses the V4L2 stack from a
+newer kernel.</para>
+<para>The version number is formatted using the
 <constant>KERNEL_VERSION()</constant> macro:</para></entry>
          </row>
          <row>
@@ -280,24 +283,5 @@ linkend="mmap">streaming</link> I/O method.</entry>
 
   <refsect1>
     &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The device is not compatible with this
-specification.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
-
@@ -156,7 +156,8 @@ signed value.</entry>
            <entry>Maximum value, inclusive. This field gives an upper
 bound for <constant>V4L2_CTRL_TYPE_INTEGER</constant> controls and the
 highest valid index for <constant>V4L2_CTRL_TYPE_MENU</constant>
-controls.
+controls. For <constant>V4L2_CTRL_TYPE_BITMASK</constant> controls it is the
+set of usable bits.
 For <constant>V4L2_CTRL_TYPE_STRING</constant> controls the maximum value
 gives the maximum length of the string. This length <emphasis>does not include the terminating
 zero</emphasis>. It may not be valid for any other type of control, including
@@ -289,6 +290,15 @@ values which are actually different on the hardware.</entry>
            <entry>The control has a menu of N choices. The names of
 the menu items can be enumerated with the
 <constant>VIDIOC_QUERYMENU</constant> ioctl.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CTRL_TYPE_BITMASK</constant></entry>
+           <entry>0</entry>
+           <entry>n/a</entry>
+           <entry>any</entry>
+           <entry>A bitmask field. The maximum value is the set of bits that can
+be used, all other bits are to be 0. The maximum value is interpreted as a __u32,
+allowing the use of bit 31 in the bitmask.</entry>
          </row>
          <row>
            <entry><constant>V4L2_CTRL_TYPE_BUTTON</constant></entry>
@@ -62,28 +62,5 @@ current video input or output.</para>
 
   <refsect1>
     &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>This ioctl is not supported.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The device is busy and therefore can not detect the standard</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
@@ -121,14 +121,6 @@ higher. This array should be zeroed by applications.</entry>
     &return-value;
 
     <variablelist>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The driver supports multiple opens and I/O is already
-in progress, or reallocation of buffers was attempted although one or
-more are still mapped.</para>
-       </listitem>
-      </varlistentry>
       <varlistentry>
        <term><errorcode>EINVAL</errorcode></term>
        <listitem>
@@ -140,11 +132,3 @@ supported.</para>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
@@ -88,9 +88,9 @@ synchronize with other events.</para>
       <varlistentry>
        <term><errorcode>EINVAL</errorcode></term>
        <listitem>
-         <para>Streaming I/O is not supported, the buffer
-<structfield>type</structfield> is not supported, or no buffers have
-been allocated (memory mapping) or enqueued (output) yet.</para>
+         <para>The buffer<structfield>type</structfield> is not supported,
+         or no buffers have been allocated (memory mapping) or enqueued
+         (output) yet.</para>
        </listitem>
       </varlistentry>
       <varlistentry>
@@ -105,11 +105,3 @@ been allocated (memory mapping) or enqueued (output) yet.</para>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
       </varlistentry>
     </variablelist>
   </refsect1>
+  <refsect1>
+    &return-value;
+  </refsect1>
 </refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml
new file mode 100644 (file)
index 0000000..69c0d8a
--- /dev/null
@@ -0,0 +1,297 @@
+<refentry id="vidioc-subscribe-event">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT</refname>
+    <refpurpose>Subscribe or unsubscribe event</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_event_subscription
+*<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>Subscribe or unsubscribe V4L2 event. Subscribed events are
+    dequeued by using the &VIDIOC-DQEVENT; ioctl.</para>
+
+    <table frame="none" pgwide="1" id="v4l2-event-subscription">
+      <title>struct <structname>v4l2_event_subscription</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry>Type of the event.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>id</structfield></entry>
+           <entry>ID of the event source. If there is no ID associated with
+               the event source, then set this to 0. Whether or not an event
+               needs an ID depends on the event type.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>flags</structfield></entry>
+           <entry>Event flags, see <xref linkend="event-flags" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[5]</entry>
+           <entry>Reserved for future extensions. Drivers and applications
+           must set the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="event-type">
+      <title>Event Types</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_EVENT_ALL</constant></entry>
+           <entry>0</entry>
+           <entry>All events. V4L2_EVENT_ALL is valid only for
+           VIDIOC_UNSUBSCRIBE_EVENT for unsubscribing all events at once.
+           </entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_EVENT_VSYNC</constant></entry>
+           <entry>1</entry>
+           <entry>This event is triggered on the vertical sync.
+           This event has a &v4l2-event-vsync; associated with it.
+           </entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_EVENT_EOS</constant></entry>
+           <entry>2</entry>
+           <entry>This event is triggered when the end of a stream is reached.
+           This is typically used with MPEG decoders to report to the application
+           when the last of the MPEG stream has been decoded.
+           </entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_EVENT_CTRL</constant></entry>
+           <entry>3</entry>
+           <entry><para>This event requires that the <structfield>id</structfield>
+               matches the control ID from which you want to receive events.
+               This event is triggered if the control's value changes, if a
+               button control is pressed or if the control's flags change.
+               This event has a &v4l2-event-ctrl; associated with it. This struct
+               contains much of the same information as &v4l2-queryctrl; and
+               &v4l2-control;.</para>
+
+               <para>If the event is generated due to a call to &VIDIOC-S-CTRL; or
+               &VIDIOC-S-EXT-CTRLS;, then the event will <emphasis>not</emphasis> be sent to
+               the file handle that called the ioctl function. This prevents
+               nasty feedback loops. If you <emphasis>do</emphasis> want to get the
+               event, then set the <constant>V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK</constant>
+               flag.
+               </para>
+
+               <para>This event type will ensure that no information is lost when
+               more events are raised than there is room internally. In that
+               case the &v4l2-event-ctrl; of the second-oldest event is kept,
+               but the <structfield>changes</structfield> field of the
+               second-oldest event is ORed with the <structfield>changes</structfield>
+               field of the oldest event.</para>
+           </entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_EVENT_PRIVATE_START</constant></entry>
+           <entry>0x08000000</entry>
+           <entry>Base event number for driver-private events.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="event-flags">
+      <title>Event Flags</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_EVENT_SUB_FL_SEND_INITIAL</constant></entry>
+           <entry>0x0001</entry>
+           <entry>When this event is subscribed an initial event will be sent
+               containing the current status. This only makes sense for events
+               that are triggered by a status change such as <constant>V4L2_EVENT_CTRL</constant>.
+               Other events will ignore this flag.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK</constant></entry>
+           <entry>0x0002</entry>
+           <entry><para>If set, then events directly caused by an ioctl will also be sent to
+               the filehandle that called that ioctl. For example, changing a control using
+               &VIDIOC-S-CTRL; will cause a V4L2_EVENT_CTRL to be sent back to that same
+               filehandle. Normally such events are suppressed to prevent feedback loops
+               where an application changes a control to a one value and then another, and
+               then receives an event telling it that that control has changed to the first
+               value.</para>
+
+               <para>Since it can't tell whether that event was caused by another application
+               or by the &VIDIOC-S-CTRL; call it is hard to decide whether to set the
+               control to the value in the event, or ignore it.</para>
+
+               <para>Think carefully when you set this flag so you won't get into situations
+               like that.</para>
+           </entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="v4l2-event-vsync">
+      <title>struct <structname>v4l2_event_vsync</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u8</entry>
+           <entry><structfield>field</structfield></entry>
+           <entry>The upcoming field. See &v4l2-field;.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="v4l2-event-ctrl">
+      <title>struct <structname>v4l2_event_ctrl</structname></title>
+      <tgroup cols="4">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>changes</structfield></entry>
+           <entry></entry>
+           <entry>A bitmask that tells what has changed. See <xref linkend="changes-flags" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry></entry>
+           <entry>The type of the control. See &v4l2-ctrl-type;.</entry>
+         </row>
+         <row>
+           <entry>union (anonymous)</entry>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__s32</entry>
+           <entry><structfield>value</structfield></entry>
+           <entry>The 32-bit value of the control for 32-bit control types.
+               This is 0 for string controls since the value of a string
+               cannot be passed using &VIDIOC-DQEVENT;.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__s64</entry>
+           <entry><structfield>value64</structfield></entry>
+           <entry>The 64-bit value of the control for 64-bit control types.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>flags</structfield></entry>
+           <entry></entry>
+           <entry>The control flags. See <xref linkend="control-flags" />.</entry>
+         </row>
+         <row>
+           <entry>__s32</entry>
+           <entry><structfield>minimum</structfield></entry>
+           <entry></entry>
+           <entry>The minimum value of the control. See &v4l2-queryctrl;.</entry>
+         </row>
+         <row>
+           <entry>__s32</entry>
+           <entry><structfield>maximum</structfield></entry>
+           <entry></entry>
+           <entry>The maximum value of the control. See &v4l2-queryctrl;.</entry>
+         </row>
+         <row>
+           <entry>__s32</entry>
+           <entry><structfield>step</structfield></entry>
+           <entry></entry>
+           <entry>The step value of the control. See &v4l2-queryctrl;.</entry>
+         </row>
+         <row>
+           <entry>__s32</entry>
+           <entry><structfield>default_value</structfield></entry>
+           <entry></entry>
+           <entry>The default value value of the control. See &v4l2-queryctrl;.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="changes-flags">
+      <title>Changes</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_EVENT_CTRL_CH_VALUE</constant></entry>
+           <entry>0x0001</entry>
+           <entry>This control event was triggered because the value of the control
+               changed. Special case: if a button control is pressed, then this
+               event is sent as well, even though there is not explicit value
+               associated with a button control.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_EVENT_CTRL_CH_FLAGS</constant></entry>
+           <entry>0x0002</entry>
+           <entry>This control event was triggered because the control flags
+               changed.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+  <refsect1>
+    &return-value;
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/vbi_525.gif.b64 b/Documentation/DocBook/media/vbi_525.gif.b64
new file mode 100644 (file)
index 0000000..d5dcf06
--- /dev/null
@@ -0,0 +1,84 @@
+R0lGODlhKgPIAIAAAAAAAP///yH5BAEAAAEALAAAAAAqA8gAAAL+jI+py+0Po5y02ouz3rz7D4bi
+SJbmiabqWgJs475LLCt0fdy4oeN9/QPuEEFZkXVcJZXDXNP5pC0TgGrMSrRMidhA1/uNbB9j2CZ8
+Kc+qHDXDTT2jK3BuPau13vFpdmc/p6Uh5SeYoXMHyFNomEeYiNEVKCFFx8Wz2Eh56YWp2bfnGXk1
+OEhaKnem2rYa6vp3KIqaBhULmsk4Ufc1KTbq4rfbhxkcOQx22limZ4P8STYH3PsGu8pqe439aw36
+eji9qT1rGCpraf5MkQynyJeuG0c73imvLYzuUAwF/P6WTK8vHDdj2Qia8hYL4bF2o/CpmydOXa6I
+uqQNPFepny/+d+cM0qsH8qNGCI8M3gvG7KG8iSJJVoNIp1w5h/C+gSPjgWE9hR0Lqmzp0RFPjLV+
+hoRki2XNPJyCVmy2U6KnHm6WnboRcOPFkS59xqQpEKZRpkDHfi1rdqlXgTMVKVVL7h/cnmi1rtxq
+t27Yn1n5xrySUi81iYAlvR2MN23Fm/nkyHzp9G9iSof3Ps1pE3PmyV2dhaSL1Jiee3/ZjI5Mkhlj
+xDPXGnkClgns1pxV0K6d4rbYF7pRv44CW7Dtojt6f/YxO7hxrrmVJ3/eZDnd4tCjVw+OPbv27dy7
+e/8OPrz48eTLmz+PPr369ezbu38PP778+fTr27+PP7/+/fz++/v/D2CAAg5IYIEGHohgggouSNFv
+1l2HHIRCACehgw9eOIR0001I4YVq8MJIVZItUpJiG564GG75VJaXb5aVthtljwnV1mauyXijVqtB
+FVRoK7Foxi0kNphaYdhYNRUxQMZDWZKd9IXTQTmmFluUDQln5TcqBrnlYEOhaGJXNZrUpR24sLPN
+kC6uaBGWMywERpWISeUZacIE5iZH8OApJ3FrtvhnY5AdR1iZVOw4p1BTZhljlGNG1aijfgIKl4+f
+kNZjoIL2ySOacX4kYlyyfDgooWBSWmikOH15mU5ksfqiqUVqNsySXN7FqZ5jWdoTr7sSqaOtTH6Y
+EajMNZX+kbC53qopDDMuymhprgLbGaTUbgrtm8smCqOqQRYbZrV58vijtzZgNW2TTHZEag7rHFuU
+Pp4aSq6sc9EJa7jinpVuq/Ruy+xSj9KibL0YyRXrXr7WlC+242qrDMJsEYYSVvAiUzGJwg7c7BqI
+GjyiuQ5f7PG/7j57VqkpqryyyJ0WDDBxC29ymr3+YFEzyRpLE5qG91qYYYVAR4hh0B0WTbTRR1Mn
+NBKTDs0h0lErTTXTSyddNdZabw311ET7nLDTTct2tddmn82bc2V3zbbYazMId9xyz0133XbfjXfe
+eu/Nd99+/w144IIPTnjhhh+OeOKKczcR2CYvDnnkkgf+XoTF2eUCs9uTb85554MrVUjmJGDuuMue
+n4566gKyxM+T2L37cNqqz0577QG2/ikpVxEie7LflW578MIPL1vroVdifOy3outkscD/THz00k+v
+ne46ApQT70o2ZWz1RT5Pffji2w4YWcqLkrzvMhNT/Wjuvy/6+PLPL/w/854vr+t58gP+vufySb8A
+CnB8phEBmo7nhDHwz3vQGKADH0jAT4UgVGZQILjeBsEManB6GqKgP+h0vtFtcIQk5KAJpqAa/znL
+Xc4CXv9KCMP2fMyA8fvDDCdYwzbg7IQbwZ0IqeHCGArRbj4UwgvxgDJSHXEfIUQVEpuIqiLycIhU
+jJv+FNO2RCeJQ4kPuuIHUMi+Kb4piFUso4K8yIQsYm8cIlKj9VrQQyiqUH9mrOPm0DgcN8YsXoLQ
+Ix1HAMY/ArKCdiyk5PDYHD+6qo1dlOPItIXIG0XSkJT02yR5qEg2EqyRHYyjzyrnyEqK8oyhTEgj
+7bFJo13SI2EwzCdDhDP4yXKWtKxYLWWJsVu+L5e6rFkv4bezX9pSmDd0XzdgZkwa7SJnFDMNMX35
+TFdGM5jE5GU1o4kn1WDzmXbg2TaFaSZrgvNks+ymOL9Jy3DesGUiSd5wmEhGt5SiHUipp+naCZL7
+6ZOV+WyixMJhT1MKlJ+CFCP2nmexf9plCZZbJWT+3Cm7MJIxSfGcp0WTglGC9CtL+9RERz3aT3pm
+FFeiuShBHcqNN75ToqjkaBhXqr8XJnSPIC0oHP2JU5FqdKQ2g5jyLNerfgo1qDolKTlMmsqTlrJa
+Km1OAmOGCKa+1KkstRBEUdDQpUpqoEk1KlF2ei2fftQoYyVrSFERUK9aQp4tRakmbXrTqtbUpXD9
+oVw1d9UTZLWiXO0jWnn61Y7xca5mJWxhifpXsKr1IWxV6kQPitc1GnZOTcVqFhRq0Lxmdqp6palb
+L5vYxQL0nkA9rGnVgql9FvWoiu2qX9uqVWxVtrNP/em6lsdZ2t6VbE9ap1B9y9qS9jWwwS2uzvD+
+OdmFDjWoIF0tcZ+7VqTWFLjMpS5Ri6krsaoJpt6M2hFLK7bGuha6DAPsqSi7XNSmV73NDa1xVSLe
+1xLUqlaLbViWCF7vJu27ns2pe8k72rCSq6z3XW+B22ve8rZWvuM9LW/xm13LPo2q9mUufScU3+gm
+OMCiDRtukytVEIcYsRuO44I1LNz5RrTCytXvfo/G3wnTNsOM/S98S+zED1vYwS0WsWxxGkLMbjXF
+DWbvhV185CS/GMm9ky6KOywmHM/xxz7WMY97bFbn3vjENR7ulSVM05QumcljXnGMabwnGysYylO2
+spG/TOUqo1fLa35vl4ksZ7uyeMRmrq8akav+5OI5+c5sFlRaezpgA/P5zXDGLZ05bOc0e5nRD/Zz
+mfscHWYiQdNKAK6n4wfAxSTi09wk5zipqctunvqct1T1L8P5i1GLLtTsdMRBrBvrHNoE18fEL6dH
+CexgC3vYxC62sY+N7GQre9nMbraznw3taEt72tSutrWvje1sa3vb3O62t78N7nCLe9zkLre5z43u
+dKt73exut7vfDe94y3ve9K63ve9t7SBkNdH47re/9Qq6CAP63wQvuGZ2mYneFoPWBm+4w8VUWiMB
+5IIPr7jFX2a/YCZ8zxfvuLnf1VB5QcnjJDd4YTKucN3xuuQsb7nLXw7zmMt85jSvuc1vjvP+nOt8
+5zzvuc9/DvSgC33oRC+60Y+O9KQrfelMb7rTnw71qEt96lSvutWvjvWsa33rXO+6178O9rCLfexk
+L7vZz472scG0vllD24rZzrW28bbtcl873N2uObUfqkQzJFaJPAO9Fm53W34/mcbO+7/t9j1ksfzY
+MiUO+DaXDPCLT9VpKr8yZnpQDM50JcmkyTOdNT5Enx8mxhAPaxApq/CULxjFV9S8kT9yhWts0zL4
+JVnX44uigl1481Cf8KsI3Kf+Er6biMXS18/+gy2JJfBzFw/Mc35U0NcXJxAh+4A1ENC69xdoER38
+34Mf+sZvF/5OP3yQ+QKAt8+14Z9/2dH+H3dnh4d/Als5f1MzMcdsCoj5SfwwqXVb/Mca6qd9WBaA
+R/J+1qddDHeAUZZy85c+mOcp/ndc5QMqGyMawrd5ACVx/8dYKrcsFQg7DAhEu6NAG7g9q3cU3RN4
+zBJV9jdwsXM/GQiCRuZWNWh7Msh3QmaAhoYSIyhja1ALbQJ/obM+L0iExvJry8d8LpiAuPdSN7h9
+3VOD3kdHW1AVsOOAxEclTySEIIQOHViF7XSFZQgUVFiGj8CCYpiGR+g8Axgt24c8Q9gpvTJbHjZg
+IjguFJQVZChbH2h/2rODJjgqxieDGTiFevgyFKWGAYOBj8gtVPF564IpLRKJgziAgAj+ieFniNxX
+fUo4LPcXhn2YEqMnif+TMYNHgKoWeTTYTGoifZzXeAsoivpXJ2f4PaHHik7oMZ1ni4yIi8fDib+I
+gen3g6pohE34gMa4cbO4ixJkh8m4d0HYi5Lniq1XjMqojcqgd2AmNXVnd3g3juRIYXT3dnGXjuZ4
+jl/zjboVjuvIjvB4d/NoUOiYd+qYj/Z4j+6IQXNXj/IojuAYkAK5j/yoZwV5kAa5kA2Zdg8JkREp
+kRNJkRVpkT73ZxwnjASpjwCJkIP0jv3Yke34kSAZjww5kPQ4kiSZkipZkhOkNifpkOWIkjQ5kzZJ
+NqyXi9uYeIrXho8TZtTlCjnEMfn+Z07jN3n3hIuC1ZNKeY2JiD6Zs0gC5iWzliav+Inv51vKx3wo
+WIrTV3uh2IqC9zjZN5ZL2DBgSZW+iI2GBpTT2IwmtpajqJSGIY232JRbuQ1myZZoKZZZmTt8ySV3
+ggapWEHRAJjU2JaL6YVMKYepMpe/GJlH6ZTI2Jdu6ZRcuZGQBJePqTCTmYRG2XyO6Q52Ui5QuJn7
+sA4amC2XOYeJCWukWVugeX2y+ZeiGZSO0ZrncpdGWYKwOZq2mV94SXwzEyymCULIo4u0h5rt95ZD
+uZuuyS2xSJuNeZZ3WJlhBmRQBAhCGVrLmRfGCXF1yTyg2ThkQlZ5eJ3lWYipOZ3+UKmd/uSDrwmf
+ciSY76kuacmY+Hk9lWmEwumJ8BmDSBl9/zKgpEmI6CkjGcOM/MmN3QicnRmX0OBpuvmW3GlD4jkr
+QEmUFuqfHXokUjkPGtoYDSqd+meiE+qMehmf0ZmQComTHtmScSWTMWqjHPmSMPmPMhpRGemjMYmP
+N4mjM0qjMHqjLkmkL5qjIPCjLXqhLqqkSWqSQXqkSFqTLHmlVpqlIrmkF+mlXwqmYSqmY7puiEim
+Zzogj4GEaMqmAIIQmtmmcTofbyqhcqp0GSlD1gCndvpvuqYldSU3dOqkfJpun/VFt1md5sFQjOKn
+hFpu+dObKVMXUnSMx5AfDBX+agfqqH0qQQtkCrMZf81gqBvnmemBTZtacuCyp98yFbyAD/NJSLiD
+p4dKoSuHqu62qJHqlpTYJ5AgcvKBqbfqclroUOUZBynoFP/pHrMqrI8KL2CErB1YQPHBrM06bjwJ
+lxsDJCkkqgD3WNZ6Ro16lT5gq0JCnBPGrfs5SerJcaOKm+BaH+4KC5kkZoR2nTTBrixToKCESTwK
+r2mqkatySi1lr/uJr7nFpJ6kooMWpf8KsHpErwQraed6sIAKLez6SQHrsHAjr6wQsSpGMzzIqp0U
+ZfwKR9W6sfzRsarwsXnWrYDJryurohjbWSibsvohs5MmaBI7se45qQhLq5L+YrIiZLM3ix85i2e/
+oRMHJLJesmfoArVPyWqldnivNrW1hGqvhk5Xi7VcW05ei0u9JrbKNLbS8nioyE1bC7bAtLYIt7Xo
+BLfmBLdWW7Vz20vq9E2mFrZ1u2qihrcdRHq19Vj5CoaFVqIMC2kAdq/U57KWqGh0hWBJu2WG67Q6
+y11AO6WEq6O71WjIhbRSBaubG1OVZrH7R7lAhLhyGWmLO4MHtmOUhoDqhWaJO7mru34YorlBC1mV
+Frr8RmWf61K9q7uaRaO5K1m26xKzq7qKa7CM+7qu27nadVaWC4GnCxXKS2HG+1CYm7nHG717FVnC
+Syuje7mlq0XIK7DUO2T+6Luwvhu97gu7iya7qVu97Fu5khtZ5ju+2ru94uu8v6ux1Oe/BUG8ema8
+A+y9T8Zg9suZCGqZjtu4pfm4wUu/68u8FqzAFwa8H7bBjgZVyAi+vDuo8xvAIVy/F5y++Eu7dZaI
+wym/sQvDL6xc2IvBLFy7C6zBJfxECPV9BIZe+ru/CZy96DfEWHm/DDxGFYyZ1luqcfa+EPy8MQy6
+SsyqXLbCPeti5fq74gq62JWtSMTFwavFUgyPFShlKVxkV7y8ienCkPvEEhzBEkzDS4zEBaq+ZXxp
++RtopEs1MQYwCIzAQJzEZ1zFBPq/8evGiOzEWUbFR4zChZzG5bvHkoz+aWRmyZRsw5mMxRl8w51M
+sYcMvYrsZqFMwiq8xpp8yptcyavMynw8yXrcyqksy7d7x5D8yA46ymScyzKcyKUcySfsyWpMy5Z2
+yZjsyrGMzOBoxlYcsrXsyMHMum28yKSsyz8cub9cw8Kczc1MzK+szHl8zMX8zXVcuNh8uIT8zJ/c
+utUsvVHMyxTszA3MxOWMw8mMx+BcxOIczsY8y9s8zOZsy9DcvOv8zrvcy+zcgI0sz+RsugBdvPic
+z/Z8zxmSoqNT0aq4a1JiI92Q0bm2aqeqt3cb0qk20q1W0iYttbR4ax3N0RsNBBdNQ114QjCNQzLd
+AjRttDmt0zvN0z1u7dM/DdRBLdRDTdRFbdRHjdRJrdRLzdRN7dRPDdVRLdVTTdVVbdVXjdVfVBkx
++APSnNU5bZaaCsVfPdQnR8TkJwlnTdZAnSwXJIidutZBHbhrqpqnuKpx/a9c3RdvndZ43dO+pCSY
+E9gqF8bNWgAAOw==
diff --git a/Documentation/DocBook/media/vbi_625.gif.b64 b/Documentation/DocBook/media/vbi_625.gif.b64
new file mode 100644 (file)
index 0000000..831f49a
--- /dev/null
@@ -0,0 +1,90 @@
+R0lGODlhKgPIAIAAAAAAAP///yH5BAEAAAEALAAAAAAqA8gAAAL+jI+py+0Po5y02ouz3rz7D4bi
+SJbmiabqWgJs475LLCt0fdy4oeN9/QPuEEFZkXVcJZXDXNP5pC0TgGrOCqVMidhAVdqVbLmx73Wc
+FXfNabGFzfbG3Rz0bDO/2G1hzJ7o8ceT56dB+Gb4JciD16fnh3VI97bmOCE4tyhVUSbHKOlg1xnp
+6aWFKDfaecrqQlrK2vqK2bjImPFaiLuKuxvY+2HLq1tniHcLzFmWy6mnitxMeWs5iaZo0xZhTahj
+rdzXHa3m6Eod+h1+LW7MXpx83P7962y+ju4O//5oGr8PHUvs36VjoCBsujTsxp5t0MIB1MZLYb07
+CBt+QlWRHz/+Zto62NLYD+Ouj7Q+ZlMj0J80kCr1iaSHT6WmeAXPAXOVzNs0hw8fHAwzkeLATz9E
+xVo2qCa2o7AA9Wz5cmXIgFAhKu2Yb2q1rFSrDmUZFeUgrQaLdhWriFZKGKt6LNTSlopXthevrIUB
+d9rSp6FGcbnLwCRYe2ELo+VK+CxEwF9XkoypeCtZn05dTiqlNupMxnyWxXkL17OVtHz7loMTdO+4
+pGsMsz0dKbVcyK7LXsWbyKSweTA95qatDHho4T7TqqsdWN1toaFbExNMHMkTzimgR2cSZfpgI9qt
+T8aePbz4IQebeLcsZDz56ecjv2g/9z37+fTNd6+vPb/+/fz++/v/D2CAAg5IYIEGHohgggouyGCD
+Dj4IYYQSTkhhhRZeiGGGGm7IYYcefghiiCKOSGKJJp6IYooqrsjidyrAh9yL+K2nng/31WgjjtzN
+mKOO8lFHxhlJxRjkkEY2tloWy51k2mxAVoaQQkImRiRuIyEmD5ZIomeVYMLIZhMkS6rWm4vJecZl
+cWBsRomUz+Vlymg4bWflYnGWo5FOGZ02FphPYmbkmHQmRxRSgzJXpntl/UlmcIca5ItvilJJx2OS
+TkrZo5k6CgemfBDFKJPF7ZRTIZsMgxUip4qKKFN5UropSKD54xasW9p6a65VBiYmb/dc2qZuwMaH
+laXvZEb+FbKPCKpkm68KutBoTshZWpN6MRqtm6H+8ZmTulabqplhXikuNtBhgqqnM6SLa7jE2nZd
+rGzK5CeUqMxJq6l2YavvTn6yGVG7zGn77aZgvOvuruvGexnCndXLq5YCC2Vsmg2LUzGcTSm8r7fg
+0pUKxMgwdOdY/O4JaMkFf/pqyiv/Jau9CY/asqatOlwnzuM6JvHMOsPsZaQZ/3zzV0NfdnS4HL3c
+KsBZpnIk01NCHbXP1o4MsSjgyAzp0xsddzHRHqOz2289d83wmb46e/aibauZNhXGMWuz3KjNG6Vz
++fooHY/p8Q0ejYDL6PeO9hX+4+DVsRr4DjByPMLjE5v+ILnUJ1Qe9t+Cb855j4d/jrnVfSuOQuii
+N+5555qrbjjrrTt+Y4uyz0577bbfjnvuuu/Oe+++/w588MIPT3zxxh+PfPLKL8+87rWGYLqI0TdP
+ffWwM249oXKDgC/y02cPfvgkkPJ97t137075HKovfvvuQ1KXh9zKJ6V37A7P/vv6739Oa0BFnoRK
+QG9+2PlJMLDnu/zxb4EMxJPJ/DLA/sXvF0EogsgG5hQDkupeCOydAhkIwvcdAYJeqYdfymOMCvLK
+Swe7yKqgkLU4dZB3AaRbCG8YwhrOEGazUaHJNuKboqjQaRBMSDrqBkOu4W9uTAQbDp8IRSV2jFtm
+2Y7+thwIDyzi64VIBKIMvQip+/Gwit5Tkw2jiMbsGcVRPfyhBTdGq7gY6ovoG1UL6ximJSwtVLjT
+YRr/mMZZFctJRZSgLswiR73gMWcsqw0Jx0a8DwJyksAj4CCjRr7T2aSCiQTiIiMGsvg8UorBkyQl
+T7k7S3aNXQJEm2lWxcl9bRGFnWFM2TAIyuOZEpUpOqNHLhgMX9ahXqq02xZTQrCdRQyWdpolq+Yk
+uTdqMoG8BOEnZSSsHYLRRmukFAnFGKOA2ayVsBjhNkUgTVcab5fVNNE1F5fNk33wnY2y2iOBWbQ2
+8rFj9axLNBmZy3W2c4H0vFwXcTmUeXaxmBmUlf3+LkmSdJprn5kb50AvWruCUu6g3gKNQrtZmns+
+dJUU/WE/6bjRgAIUoyx1J0e599I0eNQ+INXVPaEH0ZTeAZzE2QI7WwrU7Hw0KzNdT00rOkqckjSm
+9jynUvMJyaBKVX5MDSJN9jHUj+UzqTCdGtWcOECJyAmf8CqSbWDTxLSiVa1MZA1b5+bWt5ImZHI1
+Dj2YZddgiSyvel1rXc3w17bSNbCiIWxhDUsGwyoWbNdYrGITO1jCJjatRXIsYs/gV7betbJkhZtM
+ndqChkaPJ6fYTdk2g9pyQUmVrJVJQDS6Qnak9pBX1RxXxyfa2o4LmoG7LW6nVdJjgfa3imzc/Ez+
+K9ubKNdiuWytSJz7XKbCliKzxapuE+fJ3k5wHVOoX3AB4tvIAYKnxEUp4Yp7Xj5Od6LLtS5tmYtQ
+8Lo2uq5Fbns5+N7Xei68T82ufl3J2/Tyt78Bxm6BS5fb9HJ0vXI57X2jcUv50pe7842uffOLX/f+
+t3UDPmAS59Xd8X63MR32sD9tO1zxfti4y0phcjEMYdV+dsISpnB9XfzgVuS4xgberk79S+Pdphid
+CRbwkEML3KpKmMH6OC6OYaxjKGtVNdDlMYn1e2ENZ3jLQdbuFxe34grL68hdRa+RyaviQo02g51F
+kpN74WApV0rGFumy0sQs3yxzOcpatjOY/eX+Zbols06wCXSbrwzWPyt5w9hdsHQfHVM0L5POMfPz
+mC09Zj3HWM6XZPToFo3nT7Nv0F7e3KhJ+WNHa5rPe04opUkN4FDf+cZwfnGfWY3pH59am2UGda51
+PZ5dj7glb+4Xp5d66yl3VNax/nVzHx3nZM9ZuCiutrV7vN9gZ3t1xW7xjqct7YoK2dlUZnasV+3q
+Y2cqwsL2tY2vLerrDfu68ea2t40dbmS32nIzfreVkYblJ+d73d8GOLxLzeFtHzzhC1e0qgW+705H
+fJrlJveyLb5sdIN74gSnNsM/DvJ6N1zk2H5dt1Vla45v8tWofjbG+01hjUt80wO/dMgRXvL+nOsc
+CHM1Qs/fw9fhkEtMmrBhovMW2Mn+Vel1Zbpcnf50r7KN6CMpOj6DjoSfZ/3o1dG6Erz+da5Pdexk
+L7vZz472tKt97Wxvu9vfDve4y33udK+73e+O97zrfe9877vf/w74wAt+8IQvvOEPj/jEK37xjG+8
+4x8P+chLfvKUr7zlL4/5zGt+85zvvOfx7sNrXfzzpC89gyQB6zqbfvWsL9Bh7xgyNbd+9rT3zxwr
+3aly1n73vAcdMw7rxt4Lf/iE4+LX2rJH4it/+bLNvSI7JXbmS3/61K++9a+P/exrf/vc7773vw/+
+8It//OQvv/nPj/70q3/97G+/+98P//j+y3/+9K+//e+P//zrf//877///w+AASiAA0iABWiAB4iA
+CaiAC8iADeiADwiBtoc4n+Y6FChvFYg6qaOBG/g6HNiBq3OBE7gua1I1FCd1JKhsXkVa4jaCPRRD
+XoOCKUg1MMeCtVQZ0RdVZQVD/+I1dzImWsMT0AKDUmeCR3I3HHOELXdSahMoP/g0n/GCUdKETvgn
+5MMnJ3MYX4VFRQgoUChIboMmybdSIHOFYqhSfQFoJlWDQGOEYjMLs2A5b7iC6kQzaCJ6ayhLX6VN
+JONAgHVUdSiHu2KFPoaHD5QykrZDsYEq3VQSUzQ5qzUyMniDOTiGNoeFGPE8/DZjQjj+XzhIiXfm
+ibymegeFLBqkiZFYM4XoMXqjiqNHiskSikqIKIX2iDA3K9mSJ9QiiZmAiq3YhrIIjCoYjOrFilQo
+dGamibzoMlxoViozBrhIg8yojDOYjM6hi9XoXZcohf/whVaBWYi4LZXQh7WYhNsiil9Gi6eIe4lY
+KsP4Um6yV+04jKVIV7U4ilVIVKkYKzXGUAZHS3QoGbEniRv0j/tYWpmojqT1h+5yTANZaY5Whc8g
+Q8QEJ/AIjlrTi+aIMkn0M7lgKAupPQTTjWiIexfpDBZhhp+4PQ/Zj2TYUNpYh81CkRsJezKYSUt4
+hi6piDBJkuOYkji5ks5nSUA4JZz+uI1KMpPHyBIjeTVqBpKvcYNRmCTRCJBNmYtPaZV22Ip5cHv8
+xpVEWJVQiZRMKZakYZRS+HNkyYRaqJYtaIRS6Y0zGI/zRmlEJoIKFoIeaIF6mYEg6Jcf+JeNlpd/
+Y0qFGTsY2JeCGZiKCZiNuZeO+ZiMCZnnZZikg2CWaVCYiWSaWV6I6XB8mZiRKZmiGYGlaZqniZqp
+qZqryZqt2WuDOZl4uZikKZux+ZmzGZq5WZu2mZmc2ZueeZm+aZfC2V+wyZupZpy0eZu4uZzHuZlE
+OYUK85UlaJA6uJTSuTXU6IvTeJbwpUw9CDluKTZAWZ3N8TZiWZdulZ7UaY9s6Z3+NqidDjmNmFiR
+ntAtKRiI9qknh+GFgoh842iTqvCR7QmWDmmI79mT6hJKCgpVBkpm5RmewQWODRqSP5mTMWmhFLow
+XyOPzdBCC/VfBVmJBqOS5BlfIPomJeqOGvqd40mX71gL53km8RQscdOi6siRCHqiOMqNDGouwCSi
+TUKCSXmUYLSfRzmHYYmeD3mK98meI+qLKgqhUbqWBEqIDpqhUOqS63mOXfqkPJp6SgpgF+RgTnNv
+6Uil8MiOKcpr9AhHzNgsUjpiSZMRXGqidzqCV7c2ERqkVLqicroXdEozb5qQZNSeikimiSiROEGk
+YMhm+FifPTo5v7dPGNkyWTr+pzJ6oQ6ahy76p16KqSy6oYLqp6DqpTB6qqU4oeeIkBjzhDv5iNMZ
+n1NapUlKq/DplOT4P1+6qTwqXbEoqp7lqakao5qKqz66klwqTFQkWJAzV0Z3V31KosT5msmpm7up
+nMH5OcCprdaKrdn6m9yqU5W5reK6meUKms05mteqruwart7aru46rncZr99qr/farelar/mqr+/K
+nPvqr//qmgNLsAVrsAeLsAl7O8ansNP3U9ZjKaHasID0sNxTsc3Dbi86sfxzaPzRsZOUse62sR9y
+Ho8BI+RUp1KhhlMVshc7sgMSG8N0pUGZi8HET2KRYUxGSS37sh60jMuCZgD+Sqgn6U+xtLLTJqIS
+5bInEkD7+LE9qyASQShBCBX3g0j66KHFZbRDS3CkhkfQtLQu9UqGKrJQmyD+s1O1MpciRrYn9opm
+xkrPMkO0VEVqe7QNdFlm2yIFpoxusap1ezO8lTWdFJVu25U3qjKpeDBhWyI1BKx6CyJJJWltyahW
+dCrRgowf9kKH26s3qXrSAkV+BLm086EvKaYNirIZpyqlK2Lsxbmiij5xG7qjKzwh9oxA8k8eCmtf
+m10+pTFXyrgkEry0GyDd5Q2ykbtmtE1DtFN2YUGY2ranyjzDq3ePi05PO3U+IEzF6rsV8byg25mT
+BpJS+0aryqnTe33mC1P+WUVv+iYE6otUMzss4utNpuu6yGlN6auxWWtUMbFGWZW8S6Gza1hiXHJg
+w4lD1Jt38EtBNOW/NMdN+ysqBYwwFDwXB1ycxCsgDGxV/du+7ssdHAyhFtwuJFy/Ioy4GuyxEjwQ
+7OtpMxfCLEwnJvwyNGxTD6qjKkwjLvy++QjBPVy2UmTD0zTETYXCWqrD9MHDMexxuMbEAdxGAZwJ
+sNoCQOGH2MtZjhVZSWdZr7d0W9x00cqseAV2Z7VXz2pZYNx0XRxXSafGXRzGUwjHbwVZcxzHscfG
+39hEWWzHalXH2/saYsWrxYqSMnxxA6xyhoRviTxpyMqkV/Zy9+iPEMf+v+q2cqaGw8BSxEsGaZyR
+jWsWZmdmyM92xLOGyD9cyfdWc7iBN5Dsb678b6ZMyaWVcqjcY6XcbKfMySAGiqO8iUFMaJncaxh8
+rpucboucyoxMXTksybP2ygZnYzIXRrXsxLfsy3Wmy5A8wGH6Wbh8admMaNesusCMS+AMw7RcawUH
+wgm5otzscs8sy+mMzNW8cSjmzeNmzrkcaUr4yYFGzhh0z738z4c80PaLcvK8yo08nu68o84cy/qM
+0Adtyay8rcRcXsY8yW56buKsptPTzwkX0C6Xzx03zy1MzcccngxdcfDcbNE8yyatziSdbSFdzgX9
+yxqdaRxdZIpm0b/+iaY+PcgeJs2UEW3KjKeQGMmPDM2cHNHJbMv1DNKAbMpYLNKJ2kH1I9W5TNWk
+nNWwTHJ9M9SKnNDL7Mgq7YpevdTa/NJuUNRPjXNvbWQKt3NwPdc8nSNhjRdtTc9wqtQOjdZ+PclN
+jc4TrdBy/dV0bdcjp62SZNYEdtdr3RF6jdKH2s6VLYqN/cuCDdOETdYX2G6f7dmGfdg3F9c7gtex
+FdOXvNCWrV6sDZF3KNGqbNT6FNqKDWyiXdqkXdeL/diazdYnDdXsfNmuXWVq7duRDdznPNqJrdvM
+vdu8XdG4DWan3bypTdFlTdzmNm4ufdzTbN2FbdvFLN3OvdzkHd7RF93bJf3b393ZKZ3dSY3Z2AzZ
+3s3ZAhzd551mNv3Ozw3U5lHGpfPfl3NGA351Rmfgj6XHd7xYUKdZCR51rGE2vVJ1E04eAU45Fl7F
+1htMGv5LHN7hXZ3EIS7iI07iJW7iJ47iKa7iK87iLe7iLw7jMS7jM07jNW7jN47jOa7jO87jPe7j
+Pw7kQV68E+EQhqrAQs6aZmirzYzkQC4aAmmIygHlTS7kP0G3gRJ8VB7kAGCRbQB8uqflTu6Ci4jl
+ehjmPs7laf58XB7Fau6DR56aBQAAOw==
diff --git a/Documentation/DocBook/media/vbi_hsync.gif.b64 b/Documentation/DocBook/media/vbi_hsync.gif.b64
new file mode 100644 (file)
index 0000000..cdafabe
--- /dev/null
@@ -0,0 +1,43 @@
+R0lGODlhBwHJAOcAAAAAAAEBAQICAgMDAwQEBAUFBQYGBgcHBwgICAkJCQoKCgsLCwwMDA0NDQ4O
+Dg8PDxAQEBERERISEhMTExQUFBUVFRYWFhcXFxgYGBkZGRoaGhsbGxwcHB0dHR4eHh8fHyAgICEh
+ISIiIiMjIyQkJCUlJSYmJicnJygoKCkpKSoqKisrKywsLC0tLS4uLi8vLzAwMDExMTIyMjMzMzQ0
+NDU1NTY2Njc3Nzg4ODk5OTo6Ojs7Ozw8PD09PT4+Pj8/P0BAQEFBQUJCQkNDQ0REREVFRUZGRkdH
+R0hISElJSUpKSktLS0xMTE1NTU5OTk9PT1BQUFFRUVJSUlNTU1RUVFVVVVZWVldXV1hYWFlZWVpa
+WltbW1xcXF1dXV5eXl9fX2BgYGFhYWJiYmNjY2RkZGVlZWZmZmdnZ2hoaGlpaWpqamtra2xsbG1t
+bW5ubm9vb3BwcHFxcXJycnNzc3R0dHV1dXZ2dnd3d3h4eHl5eXp6ent7e3x8fH19fX5+fn9/f4CA
+gIGBgYKCgoODg4SEhIWFhYaGhoeHh4iIiImJiYqKiouLi4yMjI2NjY6Ojo+Pj5CQkJGRkZKSkpOT
+k5SUlJWVlZaWlpeXl5iYmJmZmZqampubm5ycnJ2dnZ6enp+fn6CgoKGhoaKioqOjo6SkpKWlpaam
+pqenp6ioqKmpqaqqqqurq6ysrK2tra6urq+vr7CwsLGxsbKysrOzs7S0tLW1tba2tre3t7i4uLm5
+ubq6uru7u7y8vL29vb6+vr+/v8DAwMHBwcLCwsPDw8TExMXFxcbGxsfHx8jIyMnJycrKysvLy8zM
+zM3Nzc7Ozs/Pz9DQ0NHR0dLS0tPT09TU1NXV1dbW1tfX19jY2NnZ2dra2tvb29zc3N3d3d7e3t/f
+3+Dg4OHh4eLi4uPj4+Tk5OXl5ebm5ufn5+jo6Onp6erq6uvr6+zs7O3t7e7u7u/v7/Dw8PHx8fLy
+8vPz8/T09PX19fb29vf39/j4+Pn5+fr6+vv7+/z8/P39/f7+/v///ywAAAAABwHJAAAI/gD/CRxI
+sKDBgwgTKlzIsKHDhxAjSpxIsaLFixgzatzIsaPHjyBDihxJsqTJkyhTqlzJsqXLlzBjypxJs6bN
+mzhz6tzJs6fPn0CDCh1KtKjRo0iTKl3KtKnTp1CjSp1KtarVqyQBYN1aVSvXr1C9gh2rVOxCsV4B
+mE2b0GxDt2TjtnWo9l9du2rrar2bl+BavQL3ApZLeC5du3j77g2MF/FAtIv1AoZb+Gfey5gza97M
+ua/ByJ4XI8b8+PHl0ZkrE6XsuCDr1xD5ip7d2m9pv6IZqxYK+zPC3g/T0mabGLdk4YEH7wYK3PZB
+yqyXSw/++3l139OzS4R+Hbtr7eCp/nv/bp18+PMKuZcfj7792fXm47ufz/52fd308zu/X3u/fv3N
++Sfgf/MFaJ98BLpnIH4IJojegv0d6GB7EEI4oXYVdnfhgxoOyOCG4WXIH4jTidggiSV2KOGHKGa3
+oIUtqvaiijEuNyN8NUp344g5EqYef9H1KNePJwYpJFlEehjhkT7iuCKLTMZl4olRgjWlklV+deWT
+WWpJ45JgdrnVllCKOeaXMJrZFZpfqmkVmWG6SRWcRsoZFZl12hkWmzxemCdXeAr555lOgjnof4de
+tSOVG0KWaFl3GVponH52ZumlmGaq6aaY0pjmhJppmRqQbTaKm6gewgnio2uSOumq/jpO+qmDrE5F
+p6AtSZZeSrf2WOtEoZEmm2C/Astnn6CapKtjbClWZki95lhsbLcRtxmlHkVb47TBWcuYcGvxeiyj
+fp7kGbOJEZscStrGyK1T7bb4blPxojgvU4Hiulu+vto4Lpck3rvUoljCuq+npZp6cKGz0uovwwmX
+u3CRESc7sZINJyhwWbJW7PDFXGZM4MZI1WsvyCF7rDHKZYqMKMuSvmqwS5yOypHJAcP0K8k4z5xr
+RTz/C7DPLO2crdDPEr2S0R31rDDNQB/dMbISQ01R0FOT+/TPV0vtqtZVc21s0wjLLONFJG8XNdkQ
+y5z2UNy+TW3XbN8Ho9xBxa3z/to3lz0i3nljBPhbfG+UZMoqG5db2+KJ9O7gDDHd99dUstpscsgR
+x6CzqC0O0uN70z05xVlHdNpwgvUHGWrFef5RppGHPjawNddue3nB5nYufsKmu/vrhL/3kuRqq1Tr
+6pd/G+6HymGLdvC7Dl+46cYD7aywoSleXGOtj5RnnZALP3vx7Bb2J/iyk6++subTZanz2ZJ2te2R
+st8+9NaFHx/x1Jff5GFz0Z9/+Dc3c9EnSK4ryfLG1z89GaY6AjwQARvnQLfBr24XpFrizGSk+tlv
+aOJbXwULxj3/gTB6DBwhCD2oQLBtkIR66mAEVTe9AqqQhCzMigvNhsIbrnCG/m6ZIAB9+MPqwfCB
+IryhDI14QiQ2kIiUyqH3dqhBHtoJfSZs4gu16CYsGpCKYDyinLz4QS5W8YwcjF0WkxbCJxKRjC0M
+oxnlmCU46tA19BPiCO04xZjM8IBq/GL63hjIMloNitiS4uv+aMUxRk5/ihQXIhMJSUaiUUzgq6RM
+LEmhR5qLk2LsoieVBco5YnKUCiwlG2OIyqyoMoNpPIsm/TjJRMKya698JYZiB7kELq2W6OvlLT8H
+TF62MJfM+R3+lnnIAB5zk8zBHOZks7/BqEuXwXwmLS1DzestDnmNud5MsqlDZPKGWMkzT+9CBc33
+5PGd8IynPOfJwkilLp37/gniN8dZyDgOcienCadudnc6anavnT30p/SKokvH9fOO/+RmqxIK0YUi
+EosBNVz2tnnRR9KzUxyFYjAzqpHehZSQbdxYEBEqUhcVM0WTbGhNZBor+7xNj8SMaT7TJc1Tgcug
+Bf2LNZnlKODp1KYCbR64ujcZ0OBxe5FR3jAfqsSdNiujucMnPnl3uaxiraNI3ep3hro8161uNLbB
+G00fNk3abG+aAiXqcKqlGG8Oy6hgLang+HnUjERyiBFV4VpZitKa5rWEgKJjldgpKs5d9KOQjeym
+XkrSMdnzpYatpWY3y1l6NXGB3RlsZ9eDzp7ydKmnW1dAlTnaQ94zruEkS2tUnfra1iIUdRvlHueu
+iS7N2daic1VncEEz3N/6MbVyNU1TV0tUdL3VuF6aKnQhJdrpWve62M2udrfL3e5697vgDa94x0ve
+8lIkIAA7
similarity index 89%
rename from Documentation/DocBook/media.tmpl
rename to Documentation/DocBook/media_api.tmpl
index 88f2cc6..4e8e898 100644 (file)
@@ -8,7 +8,8 @@
 <!ENTITY ie                     "i.&nbsp;e.">
 <!ENTITY fd                     "File descriptor returned by <link linkend='func-open'><function>open()</function></link>.">
 <!ENTITY i2c                    "I<superscript>2</superscript>C">
-<!ENTITY return-value          "<title>Return Value</title><para>On success <returnvalue>0</returnvalue> is returned, on error <returnvalue>-1</returnvalue> and the <varname>errno</varname> variable is set appropriately:</para>">
+<!ENTITY return-value          "<title>Return Value</title><para>On success <returnvalue>0</returnvalue> is returned, on error <returnvalue>-1</returnvalue> and the <varname>errno</varname> variable is set appropriately. The generic error codes are described at the <link linkend='gen-errors'>Generic Error Codes</link> chapter.</para>">
+<!ENTITY return-value-dvb      "<para>RETURN VALUE</para><para>On success <returnvalue>0</returnvalue> is returned, on error <returnvalue>-1</returnvalue> and the <varname>errno</varname> variable is set appropriately. The generic error codes are described at the <link linkend='gen-errors'>Generic Error Codes</link> chapter.</para>">
 <!ENTITY manvol                 "<manvolnum>2</manvolnum>">
 
 <!-- Table templates: structs, structs w/union, defines. -->
@@ -110,6 +111,11 @@ Foundation. A copy of the license is included in the chapter entitled
 &sub-media-controller;
 </part>
 
+<chapter id="gen_errors">
+&sub-gen-errors;
+</chapter>
+
+
 &sub-fdl-appendix;
 
 </book>
diff --git a/Documentation/DocBook/v4l/bayer.pdf b/Documentation/DocBook/v4l/bayer.pdf
deleted file mode 100644 (file)
index 905e60e..0000000
Binary files a/Documentation/DocBook/v4l/bayer.pdf and /dev/null differ
diff --git a/Documentation/DocBook/v4l/bayer.png b/Documentation/DocBook/v4l/bayer.png
deleted file mode 100644 (file)
index 9b15fb2..0000000
Binary files a/Documentation/DocBook/v4l/bayer.png and /dev/null differ
diff --git a/Documentation/DocBook/v4l/crop.gif b/Documentation/DocBook/v4l/crop.gif
deleted file mode 100644 (file)
index 3b9e7d8..0000000
Binary files a/Documentation/DocBook/v4l/crop.gif and /dev/null differ
diff --git a/Documentation/DocBook/v4l/dev-event.xml b/Documentation/DocBook/v4l/dev-event.xml
deleted file mode 100644 (file)
index be5a98f..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-  <title>Event Interface</title>
-
-  <para>The V4L2 event interface provides means for user to get
-  immediately notified on certain conditions taking place on a device.
-  This might include start of frame or loss of signal events, for
-  example.
-  </para>
-
-  <para>To receive events, the events the user is interested in first must
-  be subscribed using the &VIDIOC-SUBSCRIBE-EVENT; ioctl. Once an event is
-  subscribed, the events of subscribed types are dequeueable using the
-  &VIDIOC-DQEVENT; ioctl. Events may be unsubscribed using
-  VIDIOC_UNSUBSCRIBE_EVENT ioctl. The special event type V4L2_EVENT_ALL may
-  be used to unsubscribe all the events the driver supports.</para>
-
-  <para>The event subscriptions and event queues are specific to file
-  handles. Subscribing an event on one file handle does not affect
-  other file handles.
-  </para>
-
-  <para>The information on dequeueable events is obtained by using select or
-  poll system calls on video devices. The V4L2 events use POLLPRI events on
-  poll system call and exceptions on select system call.  </para>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/fieldseq_bt.gif b/Documentation/DocBook/v4l/fieldseq_bt.gif
deleted file mode 100644 (file)
index 60e8569..0000000
Binary files a/Documentation/DocBook/v4l/fieldseq_bt.gif and /dev/null differ
diff --git a/Documentation/DocBook/v4l/fieldseq_tb.gif b/Documentation/DocBook/v4l/fieldseq_tb.gif
deleted file mode 100644 (file)
index 718492f..0000000
Binary files a/Documentation/DocBook/v4l/fieldseq_tb.gif and /dev/null differ
diff --git a/Documentation/DocBook/v4l/func-ioctl.xml b/Documentation/DocBook/v4l/func-ioctl.xml
deleted file mode 100644 (file)
index b60fd37..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-<refentry id="func-ioctl">
-  <refmeta>
-    <refentrytitle>V4L2 ioctl()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>v4l2-ioctl</refname>
-    <refpurpose>Program a V4L2 device</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>#include &lt;sys/ioctl.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>void *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>V4L2 ioctl request code as defined in the <filename>videodev2.h</filename> header file, for example
-VIDIOC_QUERYCAP.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para>Pointer to a function parameter, usually a structure.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>The <function>ioctl()</function> function is used to program
-V4L2 devices. The argument <parameter>fd</parameter> must be an open
-file descriptor. An ioctl <parameter>request</parameter> has encoded
-in it whether the argument is an input, output or read/write
-parameter, and the size of the argument <parameter>argp</parameter> in
-bytes. Macros and defines specifying V4L2 ioctl requests are located
-in the <filename>videodev2.h</filename> header file.
-Applications should use their own copy, not include the version in the
-kernel sources on the system they compile on. All V4L2 ioctl requests,
-their respective function and parameters are specified in <xref
-       linkend="user-func" />.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>Return Value</title>
-
-    <para>On success the <function>ioctl()</function> function returns
-<returnvalue>0</returnvalue> and does not reset the
-<varname>errno</varname> variable. On failure
-<returnvalue>-1</returnvalue> is returned, when the ioctl takes an
-output or read/write parameter it remains unmodified, and the
-<varname>errno</varname> variable is set appropriately. See below for
-possible error codes. Generic errors like <errorcode>EBADF</errorcode>
-or <errorcode>EFAULT</errorcode> are not listed in the sections
-discussing individual ioctl requests.</para>
-    <para>Note ioctls may return undefined error codes. Since errors
-may have side effects such as a driver reset applications should
-abort on unexpected errors.</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBADF</errorcode></term>
-       <listitem>
-         <para><parameter>fd</parameter> is not a valid open file
-descriptor.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The property cannot be changed right now. Typically
-this error code is returned when I/O is in progress or the driver
-supports multiple opens and another process locked the property.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EFAULT</errorcode></term>
-       <listitem>
-         <para><parameter>argp</parameter> references an inaccessible
-memory area.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENOTTY</errorcode></term>
-       <listitem>
-         <para><parameter>fd</parameter> is  not  associated  with  a
-character special device.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The <parameter>request</parameter> or the data pointed
-to by <parameter>argp</parameter> is not valid. This is a very common
-error code, see the individual ioctl requests listed in <xref
-             linkend="user-func" /> for actual causes.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENOMEM</errorcode></term>
-       <listitem>
-         <para>Not enough physical or virtual memory was available to
-complete the request.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ERANGE</errorcode></term>
-       <listitem>
-         <para>The application attempted to set a control with the
-&VIDIOC-S-CTRL; ioctl to a value which is out of bounds.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/nv12mt.gif b/Documentation/DocBook/v4l/nv12mt.gif
deleted file mode 100644 (file)
index ef2d4cf..0000000
Binary files a/Documentation/DocBook/v4l/nv12mt.gif and /dev/null differ
diff --git a/Documentation/DocBook/v4l/nv12mt_example.gif b/Documentation/DocBook/v4l/nv12mt_example.gif
deleted file mode 100644 (file)
index df81d68..0000000
Binary files a/Documentation/DocBook/v4l/nv12mt_example.gif and /dev/null differ
diff --git a/Documentation/DocBook/v4l/pipeline.png b/Documentation/DocBook/v4l/pipeline.png
deleted file mode 100644 (file)
index f19b86c..0000000
Binary files a/Documentation/DocBook/v4l/pipeline.png and /dev/null differ
diff --git a/Documentation/DocBook/v4l/vbi_525.gif b/Documentation/DocBook/v4l/vbi_525.gif
deleted file mode 100644 (file)
index 5580b69..0000000
Binary files a/Documentation/DocBook/v4l/vbi_525.gif and /dev/null differ
diff --git a/Documentation/DocBook/v4l/vbi_625.gif b/Documentation/DocBook/v4l/vbi_625.gif
deleted file mode 100644 (file)
index 34e3251..0000000
Binary files a/Documentation/DocBook/v4l/vbi_625.gif and /dev/null differ
diff --git a/Documentation/DocBook/v4l/vbi_hsync.gif b/Documentation/DocBook/v4l/vbi_hsync.gif
deleted file mode 100644 (file)
index b02434d..0000000
Binary files a/Documentation/DocBook/v4l/vbi_hsync.gif and /dev/null differ
diff --git a/Documentation/DocBook/v4l/videodev2.h.xml b/Documentation/DocBook/v4l/videodev2.h.xml
deleted file mode 100644 (file)
index c50536a..0000000
+++ /dev/null
@@ -1,1946 +0,0 @@
-<programlisting>
-/*
- *  Video for Linux Two header file
- *
- *  Copyright (C) 1999-2007 the contributors
- *
- *  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.
- *
- *  Alternatively you can redistribute this file under the terms of the
- *  BSD license as stated below:
- *
- *  Redistribution and use in source and binary forms, with or without
- *  modification, are permitted provided that the following conditions
- *  are met:
- *  1. Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- *  2. Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in
- *     the documentation and/or other materials provided with the
- *     distribution.
- *  3. The names of its contributors may not 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.
- *
- *      Header file for v4l or V4L2 drivers and applications
- * with public API.
- * All kernel-specific stuff were moved to media/v4l2-dev.h, so
- * no #if __KERNEL tests are allowed here
- *
- *      See http://linuxtv.org for more info
- *
- *      Author: Bill Dirks &lt;bill@thedirks.org&gt;
- *              Justin Schoeman
- *              Hans Verkuil &lt;hverkuil@xs4all.nl&gt;
- *              et al.
- */
-#ifndef __LINUX_VIDEODEV2_H
-#define __LINUX_VIDEODEV2_H
-
-#ifdef __KERNEL__
-#include &lt;linux/time.h&gt;     /* need struct timeval */
-#else
-#include &lt;sys/time.h&gt;
-#endif
-#include &lt;linux/compiler.h&gt;
-#include &lt;linux/ioctl.h&gt;
-#include &lt;linux/types.h&gt;
-
-/*
- * Common stuff for both V4L1 and V4L2
- * Moved from videodev.h
- */
-#define VIDEO_MAX_FRAME               32
-#define VIDEO_MAX_PLANES               8
-
-#ifndef __KERNEL__
-
-/* These defines are V4L1 specific and should not be used with the V4L2 API!
-   They will be removed from this header in the future. */
-
-#define VID_TYPE_CAPTURE        1       /* Can capture */
-#define VID_TYPE_TUNER          2       /* Can tune */
-#define VID_TYPE_TELETEXT       4       /* Does teletext */
-#define VID_TYPE_OVERLAY        8       /* Overlay onto frame buffer */
-#define VID_TYPE_CHROMAKEY      16      /* Overlay by chromakey */
-#define VID_TYPE_CLIPPING       32      /* Can clip */
-#define VID_TYPE_FRAMERAM       64      /* Uses the frame buffer memory */
-#define VID_TYPE_SCALES         128     /* Scalable */
-#define VID_TYPE_MONOCHROME     256     /* Monochrome only */
-#define VID_TYPE_SUBCAPTURE     512     /* Can capture subareas of the image */
-#define VID_TYPE_MPEG_DECODER   1024    /* Can decode MPEG streams */
-#define VID_TYPE_MPEG_ENCODER   2048    /* Can encode MPEG streams */
-#define VID_TYPE_MJPEG_DECODER  4096    /* Can decode MJPEG streams */
-#define VID_TYPE_MJPEG_ENCODER  8192    /* Can encode MJPEG streams */
-#endif
-
-/*
- *      M I S C E L L A N E O U S
- */
-
-/*  Four-character-code (FOURCC) */
-#define v4l2_fourcc(a, b, c, d)\
-        ((__u32)(a) | ((__u32)(b) &lt;&lt; 8) | ((__u32)(c) &lt;&lt; 16) | ((__u32)(d) &lt;&lt; 24))
-
-/*
- *      E N U M S
- */
-enum <link linkend="v4l2-field">v4l2_field</link> {
-        V4L2_FIELD_ANY           = 0, /* driver can choose from none,
-                                         top, bottom, interlaced
-                                         depending on whatever it thinks
-                                         is approximate ... */
-        V4L2_FIELD_NONE          = 1, /* this device has no fields ... */
-        V4L2_FIELD_TOP           = 2, /* top field only */
-        V4L2_FIELD_BOTTOM        = 3, /* bottom field only */
-        V4L2_FIELD_INTERLACED    = 4, /* both fields interlaced */
-        V4L2_FIELD_SEQ_TB        = 5, /* both fields sequential into one
-                                         buffer, top-bottom order */
-        V4L2_FIELD_SEQ_BT        = 6, /* same as above + bottom-top order */
-        V4L2_FIELD_ALTERNATE     = 7, /* both fields alternating into
-                                         separate buffers */
-        V4L2_FIELD_INTERLACED_TB = 8, /* both fields interlaced, top field
-                                         first and the top field is
-                                         transmitted first */
-        V4L2_FIELD_INTERLACED_BT = 9, /* both fields interlaced, top field
-                                         first and the bottom field is
-                                         transmitted first */
-};
-#define V4L2_FIELD_HAS_TOP(field)       \
-        ((field) == V4L2_FIELD_TOP      ||\
-         (field) == V4L2_FIELD_INTERLACED ||\
-         (field) == V4L2_FIELD_INTERLACED_TB ||\
-         (field) == V4L2_FIELD_INTERLACED_BT ||\
-         (field) == V4L2_FIELD_SEQ_TB   ||\
-         (field) == V4L2_FIELD_SEQ_BT)
-#define V4L2_FIELD_HAS_BOTTOM(field)    \
-        ((field) == V4L2_FIELD_BOTTOM   ||\
-         (field) == V4L2_FIELD_INTERLACED ||\
-         (field) == V4L2_FIELD_INTERLACED_TB ||\
-         (field) == V4L2_FIELD_INTERLACED_BT ||\
-         (field) == V4L2_FIELD_SEQ_TB   ||\
-         (field) == V4L2_FIELD_SEQ_BT)
-#define V4L2_FIELD_HAS_BOTH(field)      \
-        ((field) == V4L2_FIELD_INTERLACED ||\
-         (field) == V4L2_FIELD_INTERLACED_TB ||\
-         (field) == V4L2_FIELD_INTERLACED_BT ||\
-         (field) == V4L2_FIELD_SEQ_TB ||\
-         (field) == V4L2_FIELD_SEQ_BT)
-
-enum <link linkend="v4l2-buf-type">v4l2_buf_type</link> {
-        V4L2_BUF_TYPE_VIDEO_CAPTURE        = 1,
-        V4L2_BUF_TYPE_VIDEO_OUTPUT         = 2,
-        V4L2_BUF_TYPE_VIDEO_OVERLAY        = 3,
-        V4L2_BUF_TYPE_VBI_CAPTURE          = 4,
-        V4L2_BUF_TYPE_VBI_OUTPUT           = 5,
-        V4L2_BUF_TYPE_SLICED_VBI_CAPTURE   = 6,
-        V4L2_BUF_TYPE_SLICED_VBI_OUTPUT    = 7,
-#if 1
-        /* Experimental */
-        V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8,
-#endif
-        V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE = 9,
-        V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE  = 10,
-        V4L2_BUF_TYPE_PRIVATE              = 0x80,
-};
-
-#define V4L2_TYPE_IS_MULTIPLANAR(type)                  \
-        ((type) == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE   \
-         || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
-
-#define V4L2_TYPE_IS_OUTPUT(type)                               \
-        ((type) == V4L2_BUF_TYPE_VIDEO_OUTPUT                   \
-         || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE         \
-         || (type) == V4L2_BUF_TYPE_VIDEO_OVERLAY               \
-         || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY        \
-         || (type) == V4L2_BUF_TYPE_VBI_OUTPUT                  \
-         || (type) == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT)
-
-enum <link linkend="v4l2-tuner-type">v4l2_tuner_type</link> {
-        V4L2_TUNER_RADIO             = 1,
-        V4L2_TUNER_ANALOG_TV         = 2,
-        V4L2_TUNER_DIGITAL_TV        = 3,
-};
-
-enum <link linkend="v4l2-memory">v4l2_memory</link> {
-        V4L2_MEMORY_MMAP             = 1,
-        V4L2_MEMORY_USERPTR          = 2,
-        V4L2_MEMORY_OVERLAY          = 3,
-};
-
-/* see also http://vektor.theorem.ca/graphics/ycbcr/ */
-enum <link linkend="v4l2-colorspace">v4l2_colorspace</link> {
-        /* ITU-R 601 -- broadcast NTSC/PAL */
-        V4L2_COLORSPACE_SMPTE170M     = 1,
-
-        /* 1125-Line (US) HDTV */
-        V4L2_COLORSPACE_SMPTE240M     = 2,
-
-        /* HD and modern captures. */
-        V4L2_COLORSPACE_REC709        = 3,
-
-        /* broken BT878 extents (601, luma range 16-253 instead of 16-235) */
-        V4L2_COLORSPACE_BT878         = 4,
-
-        /* These should be useful.  Assume 601 extents. */
-        V4L2_COLORSPACE_470_SYSTEM_M  = 5,
-        V4L2_COLORSPACE_470_SYSTEM_BG = 6,
-
-        /* I know there will be cameras that send this.  So, this is
-         * unspecified chromaticities and full 0-255 on each of the
-         * Y'CbCr components
-         */
-        V4L2_COLORSPACE_JPEG          = 7,
-
-        /* For RGB colourspaces, this is probably a good start. */
-        V4L2_COLORSPACE_SRGB          = 8,
-};
-
-enum <link linkend="v4l2-priority">v4l2_priority</link> {
-        V4L2_PRIORITY_UNSET       = 0,  /* not initialized */
-        V4L2_PRIORITY_BACKGROUND  = 1,
-        V4L2_PRIORITY_INTERACTIVE = 2,
-        V4L2_PRIORITY_RECORD      = 3,
-        V4L2_PRIORITY_DEFAULT     = V4L2_PRIORITY_INTERACTIVE,
-};
-
-struct <link linkend="v4l2-rect">v4l2_rect</link> {
-        __s32   left;
-        __s32   top;
-        __s32   width;
-        __s32   height;
-};
-
-struct <link linkend="v4l2-fract">v4l2_fract</link> {
-        __u32   numerator;
-        __u32   denominator;
-};
-
-/*
- *      D R I V E R   C A P A B I L I T I E S
- */
-struct <link linkend="v4l2-capability">v4l2_capability</link> {
-        __u8    driver[16];     /* i.e.ie; "bttv" */
-        __u8    card[32];       /* i.e.ie; "Hauppauge WinTV" */
-        __u8    bus_info[32];   /* "PCI:" + pci_name(pci_dev) */
-        __u32   version;        /* should use KERNEL_VERSION() */
-        __u32   capabilities;   /* Device capabilities */
-        __u32   reserved[4];
-};
-
-/* Values for 'capabilities' field */
-#define V4L2_CAP_VIDEO_CAPTURE          0x00000001  /* Is a video capture device */
-#define V4L2_CAP_VIDEO_OUTPUT           0x00000002  /* Is a video output device */
-#define V4L2_CAP_VIDEO_OVERLAY          0x00000004  /* Can do video overlay */
-#define V4L2_CAP_VBI_CAPTURE            0x00000010  /* Is a raw VBI capture device */
-#define V4L2_CAP_VBI_OUTPUT             0x00000020  /* Is a raw VBI output device */
-#define V4L2_CAP_SLICED_VBI_CAPTURE     0x00000040  /* Is a sliced VBI capture device */
-#define V4L2_CAP_SLICED_VBI_OUTPUT      0x00000080  /* Is a sliced VBI output device */
-#define V4L2_CAP_RDS_CAPTURE            0x00000100  /* RDS data capture */
-#define V4L2_CAP_VIDEO_OUTPUT_OVERLAY   0x00000200  /* Can do video output overlay */
-#define V4L2_CAP_HW_FREQ_SEEK           0x00000400  /* Can do hardware frequency seek  */
-#define V4L2_CAP_RDS_OUTPUT             0x00000800  /* Is an RDS encoder */
-
-/* Is a video capture device that supports multiplanar formats */
-#define V4L2_CAP_VIDEO_CAPTURE_MPLANE   0x00001000
-/* Is a video output device that supports multiplanar formats */
-#define V4L2_CAP_VIDEO_OUTPUT_MPLANE    0x00002000
-
-#define V4L2_CAP_TUNER                  0x00010000  /* has a tuner */
-#define V4L2_CAP_AUDIO                  0x00020000  /* has audio support */
-#define V4L2_CAP_RADIO                  0x00040000  /* is a radio device */
-#define V4L2_CAP_MODULATOR              0x00080000  /* has a modulator */
-
-#define V4L2_CAP_READWRITE              0x01000000  /* read/write systemcalls */
-#define V4L2_CAP_ASYNCIO                0x02000000  /* async I/O */
-#define V4L2_CAP_STREAMING              0x04000000  /* streaming I/O ioctls */
-
-/*
- *      V I D E O   I M A G E   F O R M A T
- */
-struct <link linkend="v4l2-pix-format">v4l2_pix_format</link> {
-        __u32                   width;
-        __u32                   height;
-        __u32                   pixelformat;
-        enum <link linkend="v4l2-field">v4l2_field</link>         field;
-        __u32                   bytesperline;   /* for padding, zero if unused */
-        __u32                   sizeimage;
-        enum <link linkend="v4l2-colorspace">v4l2_colorspace</link>    colorspace;
-        __u32                   priv;           /* private data, depends on pixelformat */
-};
-
-/*      Pixel format         FOURCC                          depth  Description  */
-
-/* RGB formats */
-#define <link linkend="V4L2-PIX-FMT-RGB332">V4L2_PIX_FMT_RGB332</link>  v4l2_fourcc('R', 'G', 'B', '1') /*  8  RGB-3-3-2     */
-#define <link linkend="V4L2-PIX-FMT-RGB444">V4L2_PIX_FMT_RGB444</link>  v4l2_fourcc('R', '4', '4', '4') /* 16  xxxxrrrr ggggbbbb */
-#define <link linkend="V4L2-PIX-FMT-RGB555">V4L2_PIX_FMT_RGB555</link>  v4l2_fourcc('R', 'G', 'B', 'O') /* 16  RGB-5-5-5     */
-#define <link linkend="V4L2-PIX-FMT-RGB565">V4L2_PIX_FMT_RGB565</link>  v4l2_fourcc('R', 'G', 'B', 'P') /* 16  RGB-5-6-5     */
-#define <link linkend="V4L2-PIX-FMT-RGB555X">V4L2_PIX_FMT_RGB555X</link> v4l2_fourcc('R', 'G', 'B', 'Q') /* 16  RGB-5-5-5 BE  */
-#define <link linkend="V4L2-PIX-FMT-RGB565X">V4L2_PIX_FMT_RGB565X</link> v4l2_fourcc('R', 'G', 'B', 'R') /* 16  RGB-5-6-5 BE  */
-#define <link linkend="V4L2-PIX-FMT-BGR666">V4L2_PIX_FMT_BGR666</link>  v4l2_fourcc('B', 'G', 'R', 'H') /* 18  BGR-6-6-6     */
-#define <link linkend="V4L2-PIX-FMT-BGR24">V4L2_PIX_FMT_BGR24</link>   v4l2_fourcc('B', 'G', 'R', '3') /* 24  BGR-8-8-8     */
-#define <link linkend="V4L2-PIX-FMT-RGB24">V4L2_PIX_FMT_RGB24</link>   v4l2_fourcc('R', 'G', 'B', '3') /* 24  RGB-8-8-8     */
-#define <link linkend="V4L2-PIX-FMT-BGR32">V4L2_PIX_FMT_BGR32</link>   v4l2_fourcc('B', 'G', 'R', '4') /* 32  BGR-8-8-8-8   */
-#define <link linkend="V4L2-PIX-FMT-RGB32">V4L2_PIX_FMT_RGB32</link>   v4l2_fourcc('R', 'G', 'B', '4') /* 32  RGB-8-8-8-8   */
-
-/* Grey formats */
-#define <link linkend="V4L2-PIX-FMT-GREY">V4L2_PIX_FMT_GREY</link>    v4l2_fourcc('G', 'R', 'E', 'Y') /*  8  Greyscale     */
-#define <link linkend="V4L2-PIX-FMT-Y4">V4L2_PIX_FMT_Y4</link>      v4l2_fourcc('Y', '0', '4', ' ') /*  4  Greyscale     */
-#define <link linkend="V4L2-PIX-FMT-Y6">V4L2_PIX_FMT_Y6</link>      v4l2_fourcc('Y', '0', '6', ' ') /*  6  Greyscale     */
-#define <link linkend="V4L2-PIX-FMT-Y10">V4L2_PIX_FMT_Y10</link>     v4l2_fourcc('Y', '1', '0', ' ') /* 10  Greyscale     */
-#define <link linkend="V4L2-PIX-FMT-Y16">V4L2_PIX_FMT_Y16</link>     v4l2_fourcc('Y', '1', '6', ' ') /* 16  Greyscale     */
-
-/* Grey bit-packed formats */
-#define <link linkend="V4L2-PIX-FMT-Y10BPACK">V4L2_PIX_FMT_Y10BPACK</link>    v4l2_fourcc('Y', '1', '0', 'B') /* 10  Greyscale bit-packed */
-
-/* Palette formats */
-#define <link linkend="V4L2-PIX-FMT-PAL8">V4L2_PIX_FMT_PAL8</link>    v4l2_fourcc('P', 'A', 'L', '8') /*  8  8-bit palette */
-
-/* Luminance+Chrominance formats */
-#define <link linkend="V4L2-PIX-FMT-YVU410">V4L2_PIX_FMT_YVU410</link>  v4l2_fourcc('Y', 'V', 'U', '9') /*  9  YVU 4:1:0     */
-#define <link linkend="V4L2-PIX-FMT-YVU420">V4L2_PIX_FMT_YVU420</link>  v4l2_fourcc('Y', 'V', '1', '2') /* 12  YVU 4:2:0     */
-#define <link linkend="V4L2-PIX-FMT-YUYV">V4L2_PIX_FMT_YUYV</link>    v4l2_fourcc('Y', 'U', 'Y', 'V') /* 16  YUV 4:2:2     */
-#define <link linkend="V4L2-PIX-FMT-YYUV">V4L2_PIX_FMT_YYUV</link>    v4l2_fourcc('Y', 'Y', 'U', 'V') /* 16  YUV 4:2:2     */
-#define <link linkend="V4L2-PIX-FMT-YVYU">V4L2_PIX_FMT_YVYU</link>    v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16 YVU 4:2:2 */
-#define <link linkend="V4L2-PIX-FMT-UYVY">V4L2_PIX_FMT_UYVY</link>    v4l2_fourcc('U', 'Y', 'V', 'Y') /* 16  YUV 4:2:2     */
-#define <link linkend="V4L2-PIX-FMT-VYUY">V4L2_PIX_FMT_VYUY</link>    v4l2_fourcc('V', 'Y', 'U', 'Y') /* 16  YUV 4:2:2     */
-#define <link linkend="V4L2-PIX-FMT-YUV422P">V4L2_PIX_FMT_YUV422P</link> v4l2_fourcc('4', '2', '2', 'P') /* 16  YVU422 planar */
-#define <link linkend="V4L2-PIX-FMT-YUV411P">V4L2_PIX_FMT_YUV411P</link> v4l2_fourcc('4', '1', '1', 'P') /* 16  YVU411 planar */
-#define <link linkend="V4L2-PIX-FMT-Y41P">V4L2_PIX_FMT_Y41P</link>    v4l2_fourcc('Y', '4', '1', 'P') /* 12  YUV 4:1:1     */
-#define <link linkend="V4L2-PIX-FMT-YUV444">V4L2_PIX_FMT_YUV444</link>  v4l2_fourcc('Y', '4', '4', '4') /* 16  xxxxyyyy uuuuvvvv */
-#define <link linkend="V4L2-PIX-FMT-YUV555">V4L2_PIX_FMT_YUV555</link>  v4l2_fourcc('Y', 'U', 'V', 'O') /* 16  YUV-5-5-5     */
-#define <link linkend="V4L2-PIX-FMT-YUV565">V4L2_PIX_FMT_YUV565</link>  v4l2_fourcc('Y', 'U', 'V', 'P') /* 16  YUV-5-6-5     */
-#define <link linkend="V4L2-PIX-FMT-YUV32">V4L2_PIX_FMT_YUV32</link>   v4l2_fourcc('Y', 'U', 'V', '4') /* 32  YUV-8-8-8-8   */
-#define <link linkend="V4L2-PIX-FMT-YUV410">V4L2_PIX_FMT_YUV410</link>  v4l2_fourcc('Y', 'U', 'V', '9') /*  9  YUV 4:1:0     */
-#define <link linkend="V4L2-PIX-FMT-YUV420">V4L2_PIX_FMT_YUV420</link>  v4l2_fourcc('Y', 'U', '1', '2') /* 12  YUV 4:2:0     */
-#define <link linkend="V4L2-PIX-FMT-HI240">V4L2_PIX_FMT_HI240</link>   v4l2_fourcc('H', 'I', '2', '4') /*  8  8-bit color   */
-#define <link linkend="V4L2-PIX-FMT-HM12">V4L2_PIX_FMT_HM12</link>    v4l2_fourcc('H', 'M', '1', '2') /*  8  YUV 4:2:0 16x16 macroblocks */
-#define <link linkend="V4L2-PIX-FMT-M420">V4L2_PIX_FMT_M420</link>    v4l2_fourcc('M', '4', '2', '0') /* 12  YUV 4:2:0 2 lines y, 1 line uv interleaved */
-
-/* two planes -- one Y, one Cr + Cb interleaved  */
-#define <link linkend="V4L2-PIX-FMT-NV12">V4L2_PIX_FMT_NV12</link>    v4l2_fourcc('N', 'V', '1', '2') /* 12  Y/CbCr 4:2:0  */
-#define <link linkend="V4L2-PIX-FMT-NV21">V4L2_PIX_FMT_NV21</link>    v4l2_fourcc('N', 'V', '2', '1') /* 12  Y/CrCb 4:2:0  */
-#define <link linkend="V4L2-PIX-FMT-NV16">V4L2_PIX_FMT_NV16</link>    v4l2_fourcc('N', 'V', '1', '6') /* 16  Y/CbCr 4:2:2  */
-#define <link linkend="V4L2-PIX-FMT-NV61">V4L2_PIX_FMT_NV61</link>    v4l2_fourcc('N', 'V', '6', '1') /* 16  Y/CrCb 4:2:2  */
-
-/* two non contiguous planes - one Y, one Cr + Cb interleaved  */
-#define <link linkend="V4L2-PIX-FMT-NV12M">V4L2_PIX_FMT_NV12M</link>   v4l2_fourcc('N', 'M', '1', '2') /* 12  Y/CbCr 4:2:0  */
-#define <link linkend="V4L2-PIX-FMT-NV12MT">V4L2_PIX_FMT_NV12MT</link>  v4l2_fourcc('T', 'M', '1', '2') /* 12  Y/CbCr 4:2:0 64x32 macroblocks */
-
-/* three non contiguous planes - Y, Cb, Cr */
-#define <link linkend="V4L2-PIX-FMT-YUV420M">V4L2_PIX_FMT_YUV420M</link> v4l2_fourcc('Y', 'M', '1', '2') /* 12  YUV420 planar */
-
-/* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */
-#define <link linkend="V4L2-PIX-FMT-SBGGR8">V4L2_PIX_FMT_SBGGR8</link>  v4l2_fourcc('B', 'A', '8', '1') /*  8  BGBG.. GRGR.. */
-#define <link linkend="V4L2-PIX-FMT-SGBRG8">V4L2_PIX_FMT_SGBRG8</link>  v4l2_fourcc('G', 'B', 'R', 'G') /*  8  GBGB.. RGRG.. */
-#define <link linkend="V4L2-PIX-FMT-SGRBG8">V4L2_PIX_FMT_SGRBG8</link>  v4l2_fourcc('G', 'R', 'B', 'G') /*  8  GRGR.. BGBG.. */
-#define <link linkend="V4L2-PIX-FMT-SRGGB8">V4L2_PIX_FMT_SRGGB8</link>  v4l2_fourcc('R', 'G', 'G', 'B') /*  8  RGRG.. GBGB.. */
-#define <link linkend="V4L2-PIX-FMT-SBGGR10">V4L2_PIX_FMT_SBGGR10</link> v4l2_fourcc('B', 'G', '1', '0') /* 10  BGBG.. GRGR.. */
-#define <link linkend="V4L2-PIX-FMT-SGBRG10">V4L2_PIX_FMT_SGBRG10</link> v4l2_fourcc('G', 'B', '1', '0') /* 10  GBGB.. RGRG.. */
-#define <link linkend="V4L2-PIX-FMT-SGRBG10">V4L2_PIX_FMT_SGRBG10</link> v4l2_fourcc('B', 'A', '1', '0') /* 10  GRGR.. BGBG.. */
-#define <link linkend="V4L2-PIX-FMT-SRGGB10">V4L2_PIX_FMT_SRGGB10</link> v4l2_fourcc('R', 'G', '1', '0') /* 10  RGRG.. GBGB.. */
-        /* 10bit raw bayer DPCM compressed to 8 bits */
-#define <link linkend="V4L2-PIX-FMT-SGRBG10DPCM8">V4L2_PIX_FMT_SGRBG10DPCM8</link> v4l2_fourcc('B', 'D', '1', '0')
-        /*
-         * 10bit raw bayer, expanded to 16 bits
-         * xxxxrrrrrrrrrrxxxxgggggggggg xxxxggggggggggxxxxbbbbbbbbbb...
-         */
-#define <link linkend="V4L2-PIX-FMT-SBGGR16">V4L2_PIX_FMT_SBGGR16</link> v4l2_fourcc('B', 'Y', 'R', '2') /* 16  BGBG.. GRGR.. */
-
-/* compressed formats */
-#define <link linkend="V4L2-PIX-FMT-MJPEG">V4L2_PIX_FMT_MJPEG</link>    v4l2_fourcc('M', 'J', 'P', 'G') /* Motion-JPEG   */
-#define <link linkend="V4L2-PIX-FMT-JPEG">V4L2_PIX_FMT_JPEG</link>     v4l2_fourcc('J', 'P', 'E', 'G') /* JFIF JPEG     */
-#define <link linkend="V4L2-PIX-FMT-DV">V4L2_PIX_FMT_DV</link>       v4l2_fourcc('d', 'v', 's', 'd') /* 1394          */
-#define <link linkend="V4L2-PIX-FMT-MPEG">V4L2_PIX_FMT_MPEG</link>     v4l2_fourcc('M', 'P', 'E', 'G') /* MPEG-1/2/4    */
-
-/*  Vendor-specific formats   */
-#define <link linkend="V4L2-PIX-FMT-CPIA1">V4L2_PIX_FMT_CPIA1</link>    v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */
-#define <link linkend="V4L2-PIX-FMT-WNVA">V4L2_PIX_FMT_WNVA</link>     v4l2_fourcc('W', 'N', 'V', 'A') /* Winnov hw compress */
-#define <link linkend="V4L2-PIX-FMT-SN9C10X">V4L2_PIX_FMT_SN9C10X</link>  v4l2_fourcc('S', '9', '1', '0') /* SN9C10x compression */
-#define <link linkend="V4L2-PIX-FMT-SN9C20X-I420">V4L2_PIX_FMT_SN9C20X_I420</link> v4l2_fourcc('S', '9', '2', '0') /* SN9C20x YUV 4:2:0 */
-#define <link linkend="V4L2-PIX-FMT-PWC1">V4L2_PIX_FMT_PWC1</link>     v4l2_fourcc('P', 'W', 'C', '1') /* pwc older webcam */
-#define <link linkend="V4L2-PIX-FMT-PWC2">V4L2_PIX_FMT_PWC2</link>     v4l2_fourcc('P', 'W', 'C', '2') /* pwc newer webcam */
-#define <link linkend="V4L2-PIX-FMT-ET61X251">V4L2_PIX_FMT_ET61X251</link> v4l2_fourcc('E', '6', '2', '5') /* ET61X251 compression */
-#define <link linkend="V4L2-PIX-FMT-SPCA501">V4L2_PIX_FMT_SPCA501</link>  v4l2_fourcc('S', '5', '0', '1') /* YUYV per line */
-#define <link linkend="V4L2-PIX-FMT-SPCA505">V4L2_PIX_FMT_SPCA505</link>  v4l2_fourcc('S', '5', '0', '5') /* YYUV per line */
-#define <link linkend="V4L2-PIX-FMT-SPCA508">V4L2_PIX_FMT_SPCA508</link>  v4l2_fourcc('S', '5', '0', '8') /* YUVY per line */
-#define <link linkend="V4L2-PIX-FMT-SPCA561">V4L2_PIX_FMT_SPCA561</link>  v4l2_fourcc('S', '5', '6', '1') /* compressed GBRG bayer */
-#define <link linkend="V4L2-PIX-FMT-PAC207">V4L2_PIX_FMT_PAC207</link>   v4l2_fourcc('P', '2', '0', '7') /* compressed BGGR bayer */
-#define <link linkend="V4L2-PIX-FMT-MR97310A">V4L2_PIX_FMT_MR97310A</link> v4l2_fourcc('M', '3', '1', '0') /* compressed BGGR bayer */
-#define <link linkend="V4L2-PIX-FMT-SN9C2028">V4L2_PIX_FMT_SN9C2028</link> v4l2_fourcc('S', 'O', 'N', 'X') /* compressed GBRG bayer */
-#define <link linkend="V4L2-PIX-FMT-SQ905C">V4L2_PIX_FMT_SQ905C</link>   v4l2_fourcc('9', '0', '5', 'C') /* compressed RGGB bayer */
-#define <link linkend="V4L2-PIX-FMT-PJPG">V4L2_PIX_FMT_PJPG</link>     v4l2_fourcc('P', 'J', 'P', 'G') /* Pixart 73xx JPEG */
-#define <link linkend="V4L2-PIX-FMT-OV511">V4L2_PIX_FMT_OV511</link>    v4l2_fourcc('O', '5', '1', '1') /* ov511 JPEG */
-#define <link linkend="V4L2-PIX-FMT-OV518">V4L2_PIX_FMT_OV518</link>    v4l2_fourcc('O', '5', '1', '8') /* ov518 JPEG */
-#define <link linkend="V4L2-PIX-FMT-STV0680">V4L2_PIX_FMT_STV0680</link>  v4l2_fourcc('S', '6', '8', '0') /* stv0680 bayer */
-#define <link linkend="V4L2-PIX-FMT-TM6000">V4L2_PIX_FMT_TM6000</link>   v4l2_fourcc('T', 'M', '6', '0') /* tm5600/tm60x0 */
-#define <link linkend="V4L2-PIX-FMT-CIT-YYVYUY">V4L2_PIX_FMT_CIT_YYVYUY</link> v4l2_fourcc('C', 'I', 'T', 'V') /* one line of Y then 1 line of VYUY */
-#define <link linkend="V4L2-PIX-FMT-KONICA420">V4L2_PIX_FMT_KONICA420</link>  v4l2_fourcc('K', 'O', 'N', 'I') /* YUV420 planar in blocks of 256 pixels */
-
-/*
- *      F O R M A T   E N U M E R A T I O N
- */
-struct <link linkend="v4l2-fmtdesc">v4l2_fmtdesc</link> {
-        __u32               index;             /* Format number      */
-        enum <link linkend="v4l2-buf-type">v4l2_buf_type</link>  type;              /* buffer type        */
-        __u32               flags;
-        __u8                description[32];   /* Description string */
-        __u32               pixelformat;       /* Format fourcc      */
-        __u32               reserved[4];
-};
-
-#define V4L2_FMT_FLAG_COMPRESSED 0x0001
-#define V4L2_FMT_FLAG_EMULATED   0x0002
-
-#if 1
-        /* Experimental Frame Size and frame rate enumeration */
-/*
- *      F R A M E   S I Z E   E N U M E R A T I O N
- */
-enum <link linkend="v4l2-frmsizetypes">v4l2_frmsizetypes</link> {
-        V4L2_FRMSIZE_TYPE_DISCRETE      = 1,
-        V4L2_FRMSIZE_TYPE_CONTINUOUS    = 2,
-        V4L2_FRMSIZE_TYPE_STEPWISE      = 3,
-};
-
-struct <link linkend="v4l2-frmsize-discrete">v4l2_frmsize_discrete</link> {
-        __u32                   width;          /* Frame width [pixel] */
-        __u32                   height;         /* Frame height [pixel] */
-};
-
-struct <link linkend="v4l2-frmsize-stepwise">v4l2_frmsize_stepwise</link> {
-        __u32                   min_width;      /* Minimum frame width [pixel] */
-        __u32                   max_width;      /* Maximum frame width [pixel] */
-        __u32                   step_width;     /* Frame width step size [pixel] */
-        __u32                   min_height;     /* Minimum frame height [pixel] */
-        __u32                   max_height;     /* Maximum frame height [pixel] */
-        __u32                   step_height;    /* Frame height step size [pixel] */
-};
-
-struct <link linkend="v4l2-frmsizeenum">v4l2_frmsizeenum</link> {
-        __u32                   index;          /* Frame size number */
-        __u32                   pixel_format;   /* Pixel format */
-        __u32                   type;           /* Frame size type the device supports. */
-
-        union {                                 /* Frame size */
-                struct <link linkend="v4l2-frmsize-discrete">v4l2_frmsize_discrete</link>    discrete;
-                struct <link linkend="v4l2-frmsize-stepwise">v4l2_frmsize_stepwise</link>    stepwise;
-        };
-
-        __u32   reserved[2];                    /* Reserved space for future use */
-};
-
-/*
- *      F R A M E   R A T E   E N U M E R A T I O N
- */
-enum <link linkend="v4l2-frmivaltypes">v4l2_frmivaltypes</link> {
-        V4L2_FRMIVAL_TYPE_DISCRETE      = 1,
-        V4L2_FRMIVAL_TYPE_CONTINUOUS    = 2,
-        V4L2_FRMIVAL_TYPE_STEPWISE      = 3,
-};
-
-struct <link linkend="v4l2-frmival-stepwise">v4l2_frmival_stepwise</link> {
-        struct <link linkend="v4l2-fract">v4l2_fract</link>       min;            /* Minimum frame interval [s] */
-        struct <link linkend="v4l2-fract">v4l2_fract</link>       max;            /* Maximum frame interval [s] */
-        struct <link linkend="v4l2-fract">v4l2_fract</link>       step;           /* Frame interval step size [s] */
-};
-
-struct <link linkend="v4l2-frmivalenum">v4l2_frmivalenum</link> {
-        __u32                   index;          /* Frame format index */
-        __u32                   pixel_format;   /* Pixel format */
-        __u32                   width;          /* Frame width */
-        __u32                   height;         /* Frame height */
-        __u32                   type;           /* Frame interval type the device supports. */
-
-        union {                                 /* Frame interval */
-                struct <link linkend="v4l2-fract">v4l2_fract</link>               discrete;
-                struct <link linkend="v4l2-frmival-stepwise">v4l2_frmival_stepwise</link>    stepwise;
-        };
-
-        __u32   reserved[2];                    /* Reserved space for future use */
-};
-#endif
-
-/*
- *      T I M E C O D E
- */
-struct <link linkend="v4l2-timecode">v4l2_timecode</link> {
-        __u32   type;
-        __u32   flags;
-        __u8    frames;
-        __u8    seconds;
-        __u8    minutes;
-        __u8    hours;
-        __u8    userbits[4];
-};
-
-/*  Type  */
-#define V4L2_TC_TYPE_24FPS              1
-#define V4L2_TC_TYPE_25FPS              2
-#define V4L2_TC_TYPE_30FPS              3
-#define V4L2_TC_TYPE_50FPS              4
-#define V4L2_TC_TYPE_60FPS              5
-
-/*  Flags  */
-#define V4L2_TC_FLAG_DROPFRAME          0x0001 /* "drop-frame" mode */
-#define V4L2_TC_FLAG_COLORFRAME         0x0002
-#define V4L2_TC_USERBITS_field          0x000C
-#define V4L2_TC_USERBITS_USERDEFINED    0x0000
-#define V4L2_TC_USERBITS_8BITCHARS      0x0008
-/* The above is based on SMPTE timecodes */
-
-struct <link linkend="v4l2-jpegcompression">v4l2_jpegcompression</link> {
-        int quality;
-
-        int  APPn;              /* Number of APP segment to be written,
-                                 * must be 0..15 */
-        int  APP_len;           /* Length of data in JPEG APPn segment */
-        char APP_data[60];      /* Data in the JPEG APPn segment. */
-
-        int  COM_len;           /* Length of data in JPEG COM segment */
-        char COM_data[60];      /* Data in JPEG COM segment */
-
-        __u32 jpeg_markers;     /* Which markers should go into the JPEG
-                                 * output. Unless you exactly know what
-                                 * you do, leave them untouched.
-                                 * Inluding less markers will make the
-                                 * resulting code smaller, but there will
-                                 * be fewer applications which can read it.
-                                 * The presence of the APP and COM marker
-                                 * is influenced by APP_len and COM_len
-                                 * ONLY, not by this property! */
-
-#define V4L2_JPEG_MARKER_DHT (1&lt;&lt;3)    /* Define Huffman Tables */
-#define V4L2_JPEG_MARKER_DQT (1&lt;&lt;4)    /* Define Quantization Tables */
-#define V4L2_JPEG_MARKER_DRI (1&lt;&lt;5)    /* Define Restart Interval */
-#define V4L2_JPEG_MARKER_COM (1&lt;&lt;6)    /* Comment segment */
-#define V4L2_JPEG_MARKER_APP (1&lt;&lt;7)    /* App segment, driver will
-                                        * allways use APP0 */
-};
-
-/*
- *      M E M O R Y - M A P P I N G   B U F F E R S
- */
-struct <link linkend="v4l2-requestbuffers">v4l2_requestbuffers</link> {
-        __u32                   count;
-        enum <link linkend="v4l2-buf-type">v4l2_buf_type</link>      type;
-        enum <link linkend="v4l2-memory">v4l2_memory</link>        memory;
-        __u32                   reserved[2];
-};
-
-/**
- * struct <link linkend="v4l2-plane">v4l2_plane</link> - plane info for multi-planar buffers
- * @bytesused:          number of bytes occupied by data in the plane (payload)
- * @length:             size of this plane (NOT the payload) in bytes
- * @mem_offset:         when memory in the associated struct <link linkend="v4l2-buffer">v4l2_buffer</link> is
- *                      V4L2_MEMORY_MMAP, equals the offset from the start of
- *                      the device memory for this plane (or is a "cookie" that
- *                      should be passed to mmap() called on the video node)
- * @userptr:            when memory is V4L2_MEMORY_USERPTR, a userspace pointer
- *                      pointing to this plane
- * @data_offset:        offset in the plane to the start of data; usually 0,
- *                      unless there is a header in front of the data
- *
- * Multi-planar buffers consist of one or more planes, e.g. an YCbCr buffer
- * with two planes can have one plane for Y, and another for interleaved CbCr
- * components. Each plane can reside in a separate memory buffer, or even in
- * a completely separate memory node (e.g. in embedded devices).
- */
-struct <link linkend="v4l2-plane">v4l2_plane</link> {
-        __u32                   bytesused;
-        __u32                   length;
-        union {
-                __u32           mem_offset;
-                unsigned long   userptr;
-        } m;
-        __u32                   data_offset;
-        __u32                   reserved[11];
-};
-
-/**
- * struct <link linkend="v4l2-buffer">v4l2_buffer</link> - video buffer info
- * @index:      id number of the buffer
- * @type:       buffer type (type == *_MPLANE for multiplanar buffers)
- * @bytesused:  number of bytes occupied by data in the buffer (payload);
- *              unused (set to 0) for multiplanar buffers
- * @flags:      buffer informational flags
- * @field:      field order of the image in the buffer
- * @timestamp:  frame timestamp
- * @timecode:   frame timecode
- * @sequence:   sequence count of this frame
- * @memory:     the method, in which the actual video data is passed
- * @offset:     for non-multiplanar buffers with memory == V4L2_MEMORY_MMAP;
- *              offset from the start of the device memory for this plane,
- *              (or a "cookie" that should be passed to mmap() as offset)
- * @userptr:    for non-multiplanar buffers with memory == V4L2_MEMORY_USERPTR;
- *              a userspace pointer pointing to this buffer
- * @planes:     for multiplanar buffers; userspace pointer to the array of plane
- *              info structs for this buffer
- * @length:     size in bytes of the buffer (NOT its payload) for single-plane
- *              buffers (when type != *_MPLANE); number of elements in the
- *              planes array for multi-plane buffers
- * @input:      input number from which the video data has has been captured
- *
- * Contains data exchanged by application and driver using one of the Streaming
- * I/O methods.
- */
-struct <link linkend="v4l2-buffer">v4l2_buffer</link> {
-        __u32                   index;
-        enum <link linkend="v4l2-buf-type">v4l2_buf_type</link>      type;
-        __u32                   bytesused;
-        __u32                   flags;
-        enum <link linkend="v4l2-field">v4l2_field</link>         field;
-        struct timeval          timestamp;
-        struct <link linkend="v4l2-timecode">v4l2_timecode</link>    timecode;
-        __u32                   sequence;
-
-        /* memory location */
-        enum <link linkend="v4l2-memory">v4l2_memory</link>        memory;
-        union {
-                __u32           offset;
-                unsigned long   userptr;
-                struct <link linkend="v4l2-plane">v4l2_plane</link> *planes;
-        } m;
-        __u32                   length;
-        __u32                   input;
-        __u32                   reserved;
-};
-
-/*  Flags for 'flags' field */
-#define V4L2_BUF_FLAG_MAPPED    0x0001  /* Buffer is mapped (flag) */
-#define V4L2_BUF_FLAG_QUEUED    0x0002  /* Buffer is queued for processing */
-#define V4L2_BUF_FLAG_DONE      0x0004  /* Buffer is ready */
-#define V4L2_BUF_FLAG_KEYFRAME  0x0008  /* Image is a keyframe (I-frame) */
-#define V4L2_BUF_FLAG_PFRAME    0x0010  /* Image is a P-frame */
-#define V4L2_BUF_FLAG_BFRAME    0x0020  /* Image is a B-frame */
-/* Buffer is ready, but the data contained within is corrupted. */
-#define V4L2_BUF_FLAG_ERROR     0x0040
-#define V4L2_BUF_FLAG_TIMECODE  0x0100  /* timecode field is valid */
-#define V4L2_BUF_FLAG_INPUT     0x0200  /* input field is valid */
-
-/*
- *      O V E R L A Y   P R E V I E W
- */
-struct <link linkend="v4l2-framebuffer">v4l2_framebuffer</link> {
-        __u32                   capability;
-        __u32                   flags;
-/* FIXME: in theory we should pass something like PCI device + memory
- * region + offset instead of some physical address */
-        void                    *base;
-        struct <link linkend="v4l2-pix-format">v4l2_pix_format</link>  fmt;
-};
-/*  Flags for the 'capability' field. Read only */
-#define V4L2_FBUF_CAP_EXTERNOVERLAY     0x0001
-#define V4L2_FBUF_CAP_CHROMAKEY         0x0002
-#define V4L2_FBUF_CAP_LIST_CLIPPING     0x0004
-#define V4L2_FBUF_CAP_BITMAP_CLIPPING   0x0008
-#define V4L2_FBUF_CAP_LOCAL_ALPHA       0x0010
-#define V4L2_FBUF_CAP_GLOBAL_ALPHA      0x0020
-#define V4L2_FBUF_CAP_LOCAL_INV_ALPHA   0x0040
-#define V4L2_FBUF_CAP_SRC_CHROMAKEY     0x0080
-/*  Flags for the 'flags' field. */
-#define V4L2_FBUF_FLAG_PRIMARY          0x0001
-#define V4L2_FBUF_FLAG_OVERLAY          0x0002
-#define V4L2_FBUF_FLAG_CHROMAKEY        0x0004
-#define V4L2_FBUF_FLAG_LOCAL_ALPHA      0x0008
-#define V4L2_FBUF_FLAG_GLOBAL_ALPHA     0x0010
-#define V4L2_FBUF_FLAG_LOCAL_INV_ALPHA  0x0020
-#define V4L2_FBUF_FLAG_SRC_CHROMAKEY    0x0040
-
-struct <link linkend="v4l2-clip">v4l2_clip</link> {
-        struct <link linkend="v4l2-rect">v4l2_rect</link>        c;
-        struct <link linkend="v4l2-clip">v4l2_clip</link>        __user *next;
-};
-
-struct <link linkend="v4l2-window">v4l2_window</link> {
-        struct <link linkend="v4l2-rect">v4l2_rect</link>        w;
-        enum <link linkend="v4l2-field">v4l2_field</link>         field;
-        __u32                   chromakey;
-        struct <link linkend="v4l2-clip">v4l2_clip</link>        __user *clips;
-        __u32                   clipcount;
-        void                    __user *bitmap;
-        __u8                    global_alpha;
-};
-
-/*
- *      C A P T U R E   P A R A M E T E R S
- */
-struct <link linkend="v4l2-captureparm">v4l2_captureparm</link> {
-        __u32              capability;    /*  Supported modes */
-        __u32              capturemode;   /*  Current mode */
-        struct <link linkend="v4l2-fract">v4l2_fract</link>  timeperframe;  /*  Time per frame in .1us units */
-        __u32              extendedmode;  /*  Driver-specific extensions */
-        __u32              readbuffers;   /*  # of buffers for read */
-        __u32              reserved[4];
-};
-
-/*  Flags for 'capability' and 'capturemode' fields */
-#define V4L2_MODE_HIGHQUALITY   0x0001  /*  High quality imaging mode */
-#define V4L2_CAP_TIMEPERFRAME   0x1000  /*  timeperframe field is supported */
-
-struct <link linkend="v4l2-outputparm">v4l2_outputparm</link> {
-        __u32              capability;   /*  Supported modes */
-        __u32              outputmode;   /*  Current mode */
-        struct <link linkend="v4l2-fract">v4l2_fract</link>  timeperframe; /*  Time per frame in seconds */
-        __u32              extendedmode; /*  Driver-specific extensions */
-        __u32              writebuffers; /*  # of buffers for write */
-        __u32              reserved[4];
-};
-
-/*
- *      I N P U T   I M A G E   C R O P P I N G
- */
-struct <link linkend="v4l2-cropcap">v4l2_cropcap</link> {
-        enum <link linkend="v4l2-buf-type">v4l2_buf_type</link>      type;
-        struct <link linkend="v4l2-rect">v4l2_rect</link>        bounds;
-        struct <link linkend="v4l2-rect">v4l2_rect</link>        defrect;
-        struct <link linkend="v4l2-fract">v4l2_fract</link>       pixelaspect;
-};
-
-struct <link linkend="v4l2-crop">v4l2_crop</link> {
-        enum <link linkend="v4l2-buf-type">v4l2_buf_type</link>      type;
-        struct <link linkend="v4l2-rect">v4l2_rect</link>        c;
-};
-
-/*
- *      A N A L O G   V I D E O   S T A N D A R D
- */
-
-typedef __u64 v4l2_std_id;
-
-/* one bit for each */
-#define V4L2_STD_PAL_B          ((v4l2_std_id)0x00000001)
-#define V4L2_STD_PAL_B1         ((v4l2_std_id)0x00000002)
-#define V4L2_STD_PAL_G          ((v4l2_std_id)0x00000004)
-#define V4L2_STD_PAL_H          ((v4l2_std_id)0x00000008)
-#define V4L2_STD_PAL_I          ((v4l2_std_id)0x00000010)
-#define V4L2_STD_PAL_D          ((v4l2_std_id)0x00000020)
-#define V4L2_STD_PAL_D1         ((v4l2_std_id)0x00000040)
-#define V4L2_STD_PAL_K          ((v4l2_std_id)0x00000080)
-
-#define V4L2_STD_PAL_M          ((v4l2_std_id)0x00000100)
-#define V4L2_STD_PAL_N          ((v4l2_std_id)0x00000200)
-#define V4L2_STD_PAL_Nc         ((v4l2_std_id)0x00000400)
-#define V4L2_STD_PAL_60         ((v4l2_std_id)0x00000800)
-
-#define V4L2_STD_NTSC_M         ((v4l2_std_id)0x00001000)
-#define V4L2_STD_NTSC_M_JP      ((v4l2_std_id)0x00002000)
-#define V4L2_STD_NTSC_443       ((v4l2_std_id)0x00004000)
-#define V4L2_STD_NTSC_M_KR      ((v4l2_std_id)0x00008000)
-
-#define V4L2_STD_SECAM_B        ((v4l2_std_id)0x00010000)
-#define V4L2_STD_SECAM_D        ((v4l2_std_id)0x00020000)
-#define V4L2_STD_SECAM_G        ((v4l2_std_id)0x00040000)
-#define V4L2_STD_SECAM_H        ((v4l2_std_id)0x00080000)
-#define V4L2_STD_SECAM_K        ((v4l2_std_id)0x00100000)
-#define V4L2_STD_SECAM_K1       ((v4l2_std_id)0x00200000)
-#define V4L2_STD_SECAM_L        ((v4l2_std_id)0x00400000)
-#define V4L2_STD_SECAM_LC       ((v4l2_std_id)0x00800000)
-
-/* ATSC/HDTV */
-#define V4L2_STD_ATSC_8_VSB     ((v4l2_std_id)0x01000000)
-#define V4L2_STD_ATSC_16_VSB    ((v4l2_std_id)0x02000000)
-
-/* FIXME:
-   Although std_id is 64 bits, there is an issue on PPC32 architecture that
-   makes switch(__u64) to break. So, there's a hack on v4l2-common.c rounding
-   this value to 32 bits.
-   As, currently, the max value is for V4L2_STD_ATSC_16_VSB (30 bits wide),
-   it should work fine. However, if needed to add more than two standards,
-   v4l2-common.c should be fixed.
- */
-
-/* some merged standards */
-#define V4L2_STD_MN     (V4L2_STD_PAL_M|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|V4L2_STD_NTSC)
-#define V4L2_STD_B      (V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_SECAM_B)
-#define V4L2_STD_GH     (V4L2_STD_PAL_G|V4L2_STD_PAL_H|V4L2_STD_SECAM_G|V4L2_STD_SECAM_H)
-#define V4L2_STD_DK     (V4L2_STD_PAL_DK|V4L2_STD_SECAM_DK)
-
-/* some common needed stuff */
-#define V4L2_STD_PAL_BG         (V4L2_STD_PAL_B         |\
-                                 V4L2_STD_PAL_B1        |\
-                                 V4L2_STD_PAL_G)
-#define V4L2_STD_PAL_DK         (V4L2_STD_PAL_D         |\
-                                 V4L2_STD_PAL_D1        |\
-                                 V4L2_STD_PAL_K)
-#define V4L2_STD_PAL            (V4L2_STD_PAL_BG        |\
-                                 V4L2_STD_PAL_DK        |\
-                                 V4L2_STD_PAL_H         |\
-                                 V4L2_STD_PAL_I)
-#define V4L2_STD_NTSC           (V4L2_STD_NTSC_M        |\
-                                 V4L2_STD_NTSC_M_JP     |\
-                                 V4L2_STD_NTSC_M_KR)
-#define V4L2_STD_SECAM_DK       (V4L2_STD_SECAM_D       |\
-                                 V4L2_STD_SECAM_K       |\
-                                 V4L2_STD_SECAM_K1)
-#define V4L2_STD_SECAM          (V4L2_STD_SECAM_B       |\
-                                 V4L2_STD_SECAM_G       |\
-                                 V4L2_STD_SECAM_H       |\
-                                 V4L2_STD_SECAM_DK      |\
-                                 V4L2_STD_SECAM_L       |\
-                                 V4L2_STD_SECAM_LC)
-
-#define V4L2_STD_525_60         (V4L2_STD_PAL_M         |\
-                                 V4L2_STD_PAL_60        |\
-                                 V4L2_STD_NTSC          |\
-                                 V4L2_STD_NTSC_443)
-#define V4L2_STD_625_50         (V4L2_STD_PAL           |\
-                                 V4L2_STD_PAL_N         |\
-                                 V4L2_STD_PAL_Nc        |\
-                                 V4L2_STD_SECAM)
-#define V4L2_STD_ATSC           (V4L2_STD_ATSC_8_VSB    |\
-                                 V4L2_STD_ATSC_16_VSB)
-
-#define V4L2_STD_UNKNOWN        0
-#define V4L2_STD_ALL            (V4L2_STD_525_60        |\
-                                 V4L2_STD_625_50)
-
-struct <link linkend="v4l2-standard">v4l2_standard</link> {
-        __u32                index;
-        v4l2_std_id          id;
-        __u8                 name[24];
-        struct <link linkend="v4l2-fract">v4l2_fract</link>    frameperiod; /* Frames, not fields */
-        __u32                framelines;
-        __u32                reserved[4];
-};
-
-/*
- *      V I D E O       T I M I N G S   D V     P R E S E T
- */
-struct <link linkend="v4l2-dv-preset">v4l2_dv_preset</link> {
-        __u32   preset;
-        __u32   reserved[4];
-};
-
-/*
- *      D V     P R E S E T S   E N U M E R A T I O N
- */
-struct <link linkend="v4l2-dv-enum-preset">v4l2_dv_enum_preset</link> {
-        __u32   index;
-        __u32   preset;
-        __u8    name[32]; /* Name of the preset timing */
-        __u32   width;
-        __u32   height;
-        __u32   reserved[4];
-};
-
-/*
- *      D V     P R E S E T     V A L U E S
- */
-#define         V4L2_DV_INVALID         0
-#define         V4L2_DV_480P59_94       1 /* BT.1362 */
-#define         V4L2_DV_576P50          2 /* BT.1362 */
-#define         V4L2_DV_720P24          3 /* SMPTE 296M */
-#define         V4L2_DV_720P25          4 /* SMPTE 296M */
-#define         V4L2_DV_720P30          5 /* SMPTE 296M */
-#define         V4L2_DV_720P50          6 /* SMPTE 296M */
-#define         V4L2_DV_720P59_94       7 /* SMPTE 274M */
-#define         V4L2_DV_720P60          8 /* SMPTE 274M/296M */
-#define         V4L2_DV_1080I29_97      9 /* BT.1120/ SMPTE 274M */
-#define         V4L2_DV_1080I30         10 /* BT.1120/ SMPTE 274M */
-#define         V4L2_DV_1080I25         11 /* BT.1120 */
-#define         V4L2_DV_1080I50         12 /* SMPTE 296M */
-#define         V4L2_DV_1080I60         13 /* SMPTE 296M */
-#define         V4L2_DV_1080P24         14 /* SMPTE 296M */
-#define         V4L2_DV_1080P25         15 /* SMPTE 296M */
-#define         V4L2_DV_1080P30         16 /* SMPTE 296M */
-#define         V4L2_DV_1080P50         17 /* BT.1120 */
-#define         V4L2_DV_1080P60         18 /* BT.1120 */
-
-/*
- *      D V     B T     T I M I N G S
- */
-
-/* BT.656/BT.1120 timing data */
-struct <link linkend="v4l2-bt-timings">v4l2_bt_timings</link> {
-        __u32   width;          /* width in pixels */
-        __u32   height;         /* height in lines */
-        __u32   interlaced;     /* Interlaced or progressive */
-        __u32   polarities;     /* Positive or negative polarity */
-        __u64   pixelclock;     /* Pixel clock in HZ. Ex. 74.25MHz-&gt;74250000 */
-        __u32   hfrontporch;    /* Horizpontal front porch in pixels */
-        __u32   hsync;          /* Horizontal Sync length in pixels */
-        __u32   hbackporch;     /* Horizontal back porch in pixels */
-        __u32   vfrontporch;    /* Vertical front porch in pixels */
-        __u32   vsync;          /* Vertical Sync length in lines */
-        __u32   vbackporch;     /* Vertical back porch in lines */
-        __u32   il_vfrontporch; /* Vertical front porch for bottom field of
-                                 * interlaced field formats
-                                 */
-        __u32   il_vsync;       /* Vertical sync length for bottom field of
-                                 * interlaced field formats
-                                 */
-        __u32   il_vbackporch;  /* Vertical back porch for bottom field of
-                                 * interlaced field formats
-                                 */
-        __u32   reserved[16];
-} __attribute__ ((packed));
-
-/* Interlaced or progressive format */
-#define V4L2_DV_PROGRESSIVE     0
-#define V4L2_DV_INTERLACED      1
-
-/* Polarities. If bit is not set, it is assumed to be negative polarity */
-#define V4L2_DV_VSYNC_POS_POL   0x00000001
-#define V4L2_DV_HSYNC_POS_POL   0x00000002
-
-
-/* DV timings */
-struct <link linkend="v4l2-dv-timings">v4l2_dv_timings</link> {
-        __u32 type;
-        union {
-                struct <link linkend="v4l2-bt-timings">v4l2_bt_timings</link>  bt;
-                __u32   reserved[32];
-        };
-} __attribute__ ((packed));
-
-/* Values for the type field */
-#define V4L2_DV_BT_656_1120     0       /* BT.656/1120 timing type */
-
-/*
- *      V I D E O   I N P U T S
- */
-struct <link linkend="v4l2-input">v4l2_input</link> {
-        __u32        index;             /*  Which input */
-        __u8         name[32];          /*  Label */
-        __u32        type;              /*  Type of input */
-        __u32        audioset;          /*  Associated audios (bitfield) */
-        __u32        tuner;             /*  Associated tuner */
-        v4l2_std_id  std;
-        __u32        status;
-        __u32        capabilities;
-        __u32        reserved[3];
-};
-
-/*  Values for the 'type' field */
-#define V4L2_INPUT_TYPE_TUNER           1
-#define V4L2_INPUT_TYPE_CAMERA          2
-
-/* field 'status' - general */
-#define V4L2_IN_ST_NO_POWER    0x00000001  /* Attached device is off */
-#define V4L2_IN_ST_NO_SIGNAL   0x00000002
-#define V4L2_IN_ST_NO_COLOR    0x00000004
-
-/* field 'status' - sensor orientation */
-/* If sensor is mounted upside down set both bits */
-#define V4L2_IN_ST_HFLIP       0x00000010 /* Frames are flipped horizontally */
-#define V4L2_IN_ST_VFLIP       0x00000020 /* Frames are flipped vertically */
-
-/* field 'status' - analog */
-#define V4L2_IN_ST_NO_H_LOCK   0x00000100  /* No horizontal sync lock */
-#define V4L2_IN_ST_COLOR_KILL  0x00000200  /* Color killer is active */
-
-/* field 'status' - digital */
-#define V4L2_IN_ST_NO_SYNC     0x00010000  /* No synchronization lock */
-#define V4L2_IN_ST_NO_EQU      0x00020000  /* No equalizer lock */
-#define V4L2_IN_ST_NO_CARRIER  0x00040000  /* Carrier recovery failed */
-
-/* field 'status' - VCR and set-top box */
-#define V4L2_IN_ST_MACROVISION 0x01000000  /* Macrovision detected */
-#define V4L2_IN_ST_NO_ACCESS   0x02000000  /* Conditional access denied */
-#define V4L2_IN_ST_VTR         0x04000000  /* VTR time constant */
-
-/* capabilities flags */
-#define V4L2_IN_CAP_PRESETS             0x00000001 /* Supports S_DV_PRESET */
-#define V4L2_IN_CAP_CUSTOM_TIMINGS      0x00000002 /* Supports S_DV_TIMINGS */
-#define V4L2_IN_CAP_STD                 0x00000004 /* Supports S_STD */
-
-/*
- *      V I D E O   O U T P U T S
- */
-struct <link linkend="v4l2-output">v4l2_output</link> {
-        __u32        index;             /*  Which output */
-        __u8         name[32];          /*  Label */
-        __u32        type;              /*  Type of output */
-        __u32        audioset;          /*  Associated audios (bitfield) */
-        __u32        modulator;         /*  Associated modulator */
-        v4l2_std_id  std;
-        __u32        capabilities;
-        __u32        reserved[3];
-};
-/*  Values for the 'type' field */
-#define V4L2_OUTPUT_TYPE_MODULATOR              1
-#define V4L2_OUTPUT_TYPE_ANALOG                 2
-#define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY       3
-
-/* capabilities flags */
-#define V4L2_OUT_CAP_PRESETS            0x00000001 /* Supports S_DV_PRESET */
-#define V4L2_OUT_CAP_CUSTOM_TIMINGS     0x00000002 /* Supports S_DV_TIMINGS */
-#define V4L2_OUT_CAP_STD                0x00000004 /* Supports S_STD */
-
-/*
- *      C O N T R O L S
- */
-struct <link linkend="v4l2-control">v4l2_control</link> {
-        __u32                id;
-        __s32                value;
-};
-
-struct <link linkend="v4l2-ext-control">v4l2_ext_control</link> {
-        __u32 id;
-        __u32 size;
-        __u32 reserved2[1];
-        union {
-                __s32 value;
-                __s64 value64;
-                char *string;
-        };
-} __attribute__ ((packed));
-
-struct <link linkend="v4l2-ext-controls">v4l2_ext_controls</link> {
-        __u32 ctrl_class;
-        __u32 count;
-        __u32 error_idx;
-        __u32 reserved[2];
-        struct <link linkend="v4l2-ext-control">v4l2_ext_control</link> *controls;
-};
-
-/*  Values for ctrl_class field */
-#define V4L2_CTRL_CLASS_USER 0x00980000 /* Old-style 'user' controls */
-#define V4L2_CTRL_CLASS_MPEG 0x00990000 /* MPEG-compression controls */
-#define V4L2_CTRL_CLASS_CAMERA 0x009a0000       /* Camera class controls */
-#define V4L2_CTRL_CLASS_FM_TX 0x009b0000        /* FM Modulator control class */
-
-#define V4L2_CTRL_ID_MASK         (0x0fffffff)
-#define V4L2_CTRL_ID2CLASS(id)    ((id) &amp; 0x0fff0000UL)
-#define V4L2_CTRL_DRIVER_PRIV(id) (((id) &amp; 0xffff) &gt;= 0x1000)
-
-enum <link linkend="v4l2-ctrl-type">v4l2_ctrl_type</link> {
-        V4L2_CTRL_TYPE_INTEGER       = 1,
-        V4L2_CTRL_TYPE_BOOLEAN       = 2,
-        V4L2_CTRL_TYPE_MENU          = 3,
-        V4L2_CTRL_TYPE_BUTTON        = 4,
-        V4L2_CTRL_TYPE_INTEGER64     = 5,
-        V4L2_CTRL_TYPE_CTRL_CLASS    = 6,
-        V4L2_CTRL_TYPE_STRING        = 7,
-};
-
-/*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
-struct <link linkend="v4l2-queryctrl">v4l2_queryctrl</link> {
-        __u32                id;
-        enum <link linkend="v4l2-ctrl-type">v4l2_ctrl_type</link>  type;
-        __u8                 name[32];  /* Whatever */
-        __s32                minimum;   /* Note signedness */
-        __s32                maximum;
-        __s32                step;
-        __s32                default_value;
-        __u32                flags;
-        __u32                reserved[2];
-};
-
-/*  Used in the VIDIOC_QUERYMENU ioctl for querying menu items */
-struct <link linkend="v4l2-querymenu">v4l2_querymenu</link> {
-        __u32           id;
-        __u32           index;
-        __u8            name[32];       /* Whatever */
-        __u32           reserved;
-};
-
-/*  Control flags  */
-#define V4L2_CTRL_FLAG_DISABLED         0x0001
-#define V4L2_CTRL_FLAG_GRABBED          0x0002
-#define V4L2_CTRL_FLAG_READ_ONLY        0x0004
-#define V4L2_CTRL_FLAG_UPDATE           0x0008
-#define V4L2_CTRL_FLAG_INACTIVE         0x0010
-#define V4L2_CTRL_FLAG_SLIDER           0x0020
-#define V4L2_CTRL_FLAG_WRITE_ONLY       0x0040
-
-/*  Query flag, to be ORed with the control ID */
-#define V4L2_CTRL_FLAG_NEXT_CTRL        0x80000000
-
-/*  User-class control IDs defined by V4L2 */
-#define V4L2_CID_BASE                   (V4L2_CTRL_CLASS_USER | 0x900)
-#define V4L2_CID_USER_BASE              V4L2_CID_BASE
-/*  IDs reserved for driver specific controls */
-#define V4L2_CID_PRIVATE_BASE           0x08000000
-
-#define V4L2_CID_USER_CLASS             (V4L2_CTRL_CLASS_USER | 1)
-#define V4L2_CID_BRIGHTNESS             (V4L2_CID_BASE+0)
-#define V4L2_CID_CONTRAST               (V4L2_CID_BASE+1)
-#define V4L2_CID_SATURATION             (V4L2_CID_BASE+2)
-#define V4L2_CID_HUE                    (V4L2_CID_BASE+3)
-#define V4L2_CID_AUDIO_VOLUME           (V4L2_CID_BASE+5)
-#define V4L2_CID_AUDIO_BALANCE          (V4L2_CID_BASE+6)
-#define V4L2_CID_AUDIO_BASS             (V4L2_CID_BASE+7)
-#define V4L2_CID_AUDIO_TREBLE           (V4L2_CID_BASE+8)
-#define V4L2_CID_AUDIO_MUTE             (V4L2_CID_BASE+9)
-#define V4L2_CID_AUDIO_LOUDNESS         (V4L2_CID_BASE+10)
-#define V4L2_CID_BLACK_LEVEL            (V4L2_CID_BASE+11) /* Deprecated */
-#define V4L2_CID_AUTO_WHITE_BALANCE     (V4L2_CID_BASE+12)
-#define V4L2_CID_DO_WHITE_BALANCE       (V4L2_CID_BASE+13)
-#define V4L2_CID_RED_BALANCE            (V4L2_CID_BASE+14)
-#define V4L2_CID_BLUE_BALANCE           (V4L2_CID_BASE+15)
-#define V4L2_CID_GAMMA                  (V4L2_CID_BASE+16)
-#define V4L2_CID_WHITENESS              (V4L2_CID_GAMMA) /* Deprecated */
-#define V4L2_CID_EXPOSURE               (V4L2_CID_BASE+17)
-#define V4L2_CID_AUTOGAIN               (V4L2_CID_BASE+18)
-#define V4L2_CID_GAIN                   (V4L2_CID_BASE+19)
-#define V4L2_CID_HFLIP                  (V4L2_CID_BASE+20)
-#define V4L2_CID_VFLIP                  (V4L2_CID_BASE+21)
-
-/* Deprecated; use V4L2_CID_PAN_RESET and V4L2_CID_TILT_RESET */
-#define V4L2_CID_HCENTER                (V4L2_CID_BASE+22)
-#define V4L2_CID_VCENTER                (V4L2_CID_BASE+23)
-
-#define V4L2_CID_POWER_LINE_FREQUENCY   (V4L2_CID_BASE+24)
-enum <link linkend="v4l2-power-line-frequency">v4l2_power_line_frequency</link> {
-        V4L2_CID_POWER_LINE_FREQUENCY_DISABLED  = 0,
-        V4L2_CID_POWER_LINE_FREQUENCY_50HZ      = 1,
-        V4L2_CID_POWER_LINE_FREQUENCY_60HZ      = 2,
-};
-#define V4L2_CID_HUE_AUTO                       (V4L2_CID_BASE+25)
-#define V4L2_CID_WHITE_BALANCE_TEMPERATURE      (V4L2_CID_BASE+26)
-#define V4L2_CID_SHARPNESS                      (V4L2_CID_BASE+27)
-#define V4L2_CID_BACKLIGHT_COMPENSATION         (V4L2_CID_BASE+28)
-#define V4L2_CID_CHROMA_AGC                     (V4L2_CID_BASE+29)
-#define V4L2_CID_COLOR_KILLER                   (V4L2_CID_BASE+30)
-#define V4L2_CID_COLORFX                        (V4L2_CID_BASE+31)
-enum <link linkend="v4l2-colorfx">v4l2_colorfx</link> {
-        V4L2_COLORFX_NONE       = 0,
-        V4L2_COLORFX_BW         = 1,
-        V4L2_COLORFX_SEPIA      = 2,
-        V4L2_COLORFX_NEGATIVE = 3,
-        V4L2_COLORFX_EMBOSS = 4,
-        V4L2_COLORFX_SKETCH = 5,
-        V4L2_COLORFX_SKY_BLUE = 6,
-        V4L2_COLORFX_GRASS_GREEN = 7,
-        V4L2_COLORFX_SKIN_WHITEN = 8,
-        V4L2_COLORFX_VIVID = 9,
-};
-#define V4L2_CID_AUTOBRIGHTNESS                 (V4L2_CID_BASE+32)
-#define V4L2_CID_BAND_STOP_FILTER               (V4L2_CID_BASE+33)
-
-#define V4L2_CID_ROTATE                         (V4L2_CID_BASE+34)
-#define V4L2_CID_BG_COLOR                       (V4L2_CID_BASE+35)
-
-#define V4L2_CID_CHROMA_GAIN                    (V4L2_CID_BASE+36)
-
-#define V4L2_CID_ILLUMINATORS_1                 (V4L2_CID_BASE+37)
-#define V4L2_CID_ILLUMINATORS_2                 (V4L2_CID_BASE+38)
-
-/* last CID + 1 */
-#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+39)
-
-/*  MPEG-class control IDs defined by V4L2 */
-#define V4L2_CID_MPEG_BASE                      (V4L2_CTRL_CLASS_MPEG | 0x900)
-#define V4L2_CID_MPEG_CLASS                     (V4L2_CTRL_CLASS_MPEG | 1)
-
-/*  MPEG streams */
-#define V4L2_CID_MPEG_STREAM_TYPE               (V4L2_CID_MPEG_BASE+0)
-enum <link linkend="v4l2-mpeg-stream-type">v4l2_mpeg_stream_type</link> {
-        V4L2_MPEG_STREAM_TYPE_MPEG2_PS   = 0, /* MPEG-2 program stream */
-        V4L2_MPEG_STREAM_TYPE_MPEG2_TS   = 1, /* MPEG-2 transport stream */
-        V4L2_MPEG_STREAM_TYPE_MPEG1_SS   = 2, /* MPEG-1 system stream */
-        V4L2_MPEG_STREAM_TYPE_MPEG2_DVD  = 3, /* MPEG-2 DVD-compatible stream */
-        V4L2_MPEG_STREAM_TYPE_MPEG1_VCD  = 4, /* MPEG-1 VCD-compatible stream */
-        V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD = 5, /* MPEG-2 SVCD-compatible stream */
-};
-#define V4L2_CID_MPEG_STREAM_PID_PMT            (V4L2_CID_MPEG_BASE+1)
-#define V4L2_CID_MPEG_STREAM_PID_AUDIO          (V4L2_CID_MPEG_BASE+2)
-#define V4L2_CID_MPEG_STREAM_PID_VIDEO          (V4L2_CID_MPEG_BASE+3)
-#define V4L2_CID_MPEG_STREAM_PID_PCR            (V4L2_CID_MPEG_BASE+4)
-#define V4L2_CID_MPEG_STREAM_PES_ID_AUDIO       (V4L2_CID_MPEG_BASE+5)
-#define V4L2_CID_MPEG_STREAM_PES_ID_VIDEO       (V4L2_CID_MPEG_BASE+6)
-#define V4L2_CID_MPEG_STREAM_VBI_FMT            (V4L2_CID_MPEG_BASE+7)
-enum <link linkend="v4l2-mpeg-stream-vbi-fmt">v4l2_mpeg_stream_vbi_fmt</link> {
-        V4L2_MPEG_STREAM_VBI_FMT_NONE = 0,  /* No VBI in the MPEG stream */
-        V4L2_MPEG_STREAM_VBI_FMT_IVTV = 1,  /* VBI in private packets, IVTV format */
-};
-
-/*  MPEG audio */
-#define V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ       (V4L2_CID_MPEG_BASE+100)
-enum <link linkend="v4l2-mpeg-audio-sampling-freq">v4l2_mpeg_audio_sampling_freq</link> {
-        V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100 = 0,
-        V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000 = 1,
-        V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000 = 2,
-};
-#define V4L2_CID_MPEG_AUDIO_ENCODING            (V4L2_CID_MPEG_BASE+101)
-enum <link linkend="v4l2-mpeg-audio-encoding">v4l2_mpeg_audio_encoding</link> {
-        V4L2_MPEG_AUDIO_ENCODING_LAYER_1 = 0,
-        V4L2_MPEG_AUDIO_ENCODING_LAYER_2 = 1,
-        V4L2_MPEG_AUDIO_ENCODING_LAYER_3 = 2,
-        V4L2_MPEG_AUDIO_ENCODING_AAC     = 3,
-        V4L2_MPEG_AUDIO_ENCODING_AC3     = 4,
-};
-#define V4L2_CID_MPEG_AUDIO_L1_BITRATE          (V4L2_CID_MPEG_BASE+102)
-enum <link linkend="v4l2-mpeg-audio-l1-bitrate">v4l2_mpeg_audio_l1_bitrate</link> {
-        V4L2_MPEG_AUDIO_L1_BITRATE_32K  = 0,
-        V4L2_MPEG_AUDIO_L1_BITRATE_64K  = 1,
-        V4L2_MPEG_AUDIO_L1_BITRATE_96K  = 2,
-        V4L2_MPEG_AUDIO_L1_BITRATE_128K = 3,
-        V4L2_MPEG_AUDIO_L1_BITRATE_160K = 4,
-        V4L2_MPEG_AUDIO_L1_BITRATE_192K = 5,
-        V4L2_MPEG_AUDIO_L1_BITRATE_224K = 6,
-        V4L2_MPEG_AUDIO_L1_BITRATE_256K = 7,
-        V4L2_MPEG_AUDIO_L1_BITRATE_288K = 8,
-        V4L2_MPEG_AUDIO_L1_BITRATE_320K = 9,
-        V4L2_MPEG_AUDIO_L1_BITRATE_352K = 10,
-        V4L2_MPEG_AUDIO_L1_BITRATE_384K = 11,
-        V4L2_MPEG_AUDIO_L1_BITRATE_416K = 12,
-        V4L2_MPEG_AUDIO_L1_BITRATE_448K = 13,
-};
-#define V4L2_CID_MPEG_AUDIO_L2_BITRATE          (V4L2_CID_MPEG_BASE+103)
-enum <link linkend="v4l2-mpeg-audio-l2-bitrate">v4l2_mpeg_audio_l2_bitrate</link> {
-        V4L2_MPEG_AUDIO_L2_BITRATE_32K  = 0,
-        V4L2_MPEG_AUDIO_L2_BITRATE_48K  = 1,
-        V4L2_MPEG_AUDIO_L2_BITRATE_56K  = 2,
-        V4L2_MPEG_AUDIO_L2_BITRATE_64K  = 3,
-        V4L2_MPEG_AUDIO_L2_BITRATE_80K  = 4,
-        V4L2_MPEG_AUDIO_L2_BITRATE_96K  = 5,
-        V4L2_MPEG_AUDIO_L2_BITRATE_112K = 6,
-        V4L2_MPEG_AUDIO_L2_BITRATE_128K = 7,
-        V4L2_MPEG_AUDIO_L2_BITRATE_160K = 8,
-        V4L2_MPEG_AUDIO_L2_BITRATE_192K = 9,
-        V4L2_MPEG_AUDIO_L2_BITRATE_224K = 10,
-        V4L2_MPEG_AUDIO_L2_BITRATE_256K = 11,
-        V4L2_MPEG_AUDIO_L2_BITRATE_320K = 12,
-        V4L2_MPEG_AUDIO_L2_BITRATE_384K = 13,
-};
-#define V4L2_CID_MPEG_AUDIO_L3_BITRATE          (V4L2_CID_MPEG_BASE+104)
-enum <link linkend="v4l2-mpeg-audio-l3-bitrate">v4l2_mpeg_audio_l3_bitrate</link> {
-        V4L2_MPEG_AUDIO_L3_BITRATE_32K  = 0,
-        V4L2_MPEG_AUDIO_L3_BITRATE_40K  = 1,
-        V4L2_MPEG_AUDIO_L3_BITRATE_48K  = 2,
-        V4L2_MPEG_AUDIO_L3_BITRATE_56K  = 3,
-        V4L2_MPEG_AUDIO_L3_BITRATE_64K  = 4,
-        V4L2_MPEG_AUDIO_L3_BITRATE_80K  = 5,
-        V4L2_MPEG_AUDIO_L3_BITRATE_96K  = 6,
-        V4L2_MPEG_AUDIO_L3_BITRATE_112K = 7,
-        V4L2_MPEG_AUDIO_L3_BITRATE_128K = 8,
-        V4L2_MPEG_AUDIO_L3_BITRATE_160K = 9,
-        V4L2_MPEG_AUDIO_L3_BITRATE_192K = 10,
-        V4L2_MPEG_AUDIO_L3_BITRATE_224K = 11,
-        V4L2_MPEG_AUDIO_L3_BITRATE_256K = 12,
-        V4L2_MPEG_AUDIO_L3_BITRATE_320K = 13,
-};
-#define V4L2_CID_MPEG_AUDIO_MODE                (V4L2_CID_MPEG_BASE+105)
-enum <link linkend="v4l2-mpeg-audio-mode">v4l2_mpeg_audio_mode</link> {
-        V4L2_MPEG_AUDIO_MODE_STEREO       = 0,
-        V4L2_MPEG_AUDIO_MODE_JOINT_STEREO = 1,
-        V4L2_MPEG_AUDIO_MODE_DUAL         = 2,
-        V4L2_MPEG_AUDIO_MODE_MONO         = 3,
-};
-#define V4L2_CID_MPEG_AUDIO_MODE_EXTENSION      (V4L2_CID_MPEG_BASE+106)
-enum <link linkend="v4l2-mpeg-audio-mode-extension">v4l2_mpeg_audio_mode_extension</link> {
-        V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4  = 0,
-        V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_8  = 1,
-        V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_12 = 2,
-        V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16 = 3,
-};
-#define V4L2_CID_MPEG_AUDIO_EMPHASIS            (V4L2_CID_MPEG_BASE+107)
-enum <link linkend="v4l2-mpeg-audio-emphasis">v4l2_mpeg_audio_emphasis</link> {
-        V4L2_MPEG_AUDIO_EMPHASIS_NONE         = 0,
-        V4L2_MPEG_AUDIO_EMPHASIS_50_DIV_15_uS = 1,
-        V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17    = 2,
-};
-#define V4L2_CID_MPEG_AUDIO_CRC                 (V4L2_CID_MPEG_BASE+108)
-enum <link linkend="v4l2-mpeg-audio-crc">v4l2_mpeg_audio_crc</link> {
-        V4L2_MPEG_AUDIO_CRC_NONE  = 0,
-        V4L2_MPEG_AUDIO_CRC_CRC16 = 1,
-};
-#define V4L2_CID_MPEG_AUDIO_MUTE                (V4L2_CID_MPEG_BASE+109)
-#define V4L2_CID_MPEG_AUDIO_AAC_BITRATE         (V4L2_CID_MPEG_BASE+110)
-#define V4L2_CID_MPEG_AUDIO_AC3_BITRATE         (V4L2_CID_MPEG_BASE+111)
-enum <link linkend="v4l2-mpeg-audio-ac3-bitrate">v4l2_mpeg_audio_ac3_bitrate</link> {
-        V4L2_MPEG_AUDIO_AC3_BITRATE_32K  = 0,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_40K  = 1,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_48K  = 2,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_56K  = 3,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_64K  = 4,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_80K  = 5,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_96K  = 6,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_112K = 7,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_128K = 8,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_160K = 9,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_192K = 10,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_224K = 11,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_256K = 12,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_320K = 13,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_384K = 14,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_448K = 15,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_512K = 16,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_576K = 17,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_640K = 18,
-};
-
-/*  MPEG video */
-#define V4L2_CID_MPEG_VIDEO_ENCODING            (V4L2_CID_MPEG_BASE+200)
-enum <link linkend="v4l2-mpeg-video-encoding">v4l2_mpeg_video_encoding</link> {
-        V4L2_MPEG_VIDEO_ENCODING_MPEG_1     = 0,
-        V4L2_MPEG_VIDEO_ENCODING_MPEG_2     = 1,
-        V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC = 2,
-};
-#define V4L2_CID_MPEG_VIDEO_ASPECT              (V4L2_CID_MPEG_BASE+201)
-enum <link linkend="v4l2-mpeg-video-aspect">v4l2_mpeg_video_aspect</link> {
-        V4L2_MPEG_VIDEO_ASPECT_1x1     = 0,
-        V4L2_MPEG_VIDEO_ASPECT_4x3     = 1,
-        V4L2_MPEG_VIDEO_ASPECT_16x9    = 2,
-        V4L2_MPEG_VIDEO_ASPECT_221x100 = 3,
-};
-#define V4L2_CID_MPEG_VIDEO_B_FRAMES            (V4L2_CID_MPEG_BASE+202)
-#define V4L2_CID_MPEG_VIDEO_GOP_SIZE            (V4L2_CID_MPEG_BASE+203)
-#define V4L2_CID_MPEG_VIDEO_GOP_CLOSURE         (V4L2_CID_MPEG_BASE+204)
-#define V4L2_CID_MPEG_VIDEO_PULLDOWN            (V4L2_CID_MPEG_BASE+205)
-#define V4L2_CID_MPEG_VIDEO_BITRATE_MODE        (V4L2_CID_MPEG_BASE+206)
-enum <link linkend="v4l2-mpeg-video-bitrate-mode">v4l2_mpeg_video_bitrate_mode</link> {
-        V4L2_MPEG_VIDEO_BITRATE_MODE_VBR = 0,
-        V4L2_MPEG_VIDEO_BITRATE_MODE_CBR = 1,
-};
-#define V4L2_CID_MPEG_VIDEO_BITRATE             (V4L2_CID_MPEG_BASE+207)
-#define V4L2_CID_MPEG_VIDEO_BITRATE_PEAK        (V4L2_CID_MPEG_BASE+208)
-#define V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION (V4L2_CID_MPEG_BASE+209)
-#define V4L2_CID_MPEG_VIDEO_MUTE                (V4L2_CID_MPEG_BASE+210)
-#define V4L2_CID_MPEG_VIDEO_MUTE_YUV            (V4L2_CID_MPEG_BASE+211)
-
-/*  MPEG-class control IDs specific to the CX2341x driver as defined by V4L2 */
-#define V4L2_CID_MPEG_CX2341X_BASE                              (V4L2_CTRL_CLASS_MPEG | 0x1000)
-#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE         (V4L2_CID_MPEG_CX2341X_BASE+0)
-enum <link linkend="v4l2-mpeg-cx2341x-video-spatial-filter-mode">v4l2_mpeg_cx2341x_video_spatial_filter_mode</link> {
-        V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL = 0,
-        V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO   = 1,
-};
-#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER              (V4L2_CID_MPEG_CX2341X_BASE+1)
-#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE    (V4L2_CID_MPEG_CX2341X_BASE+2)
-enum <link linkend="luma-spatial-filter-type">v4l2_mpeg_cx2341x_video_luma_spatial_filter_type</link> {
-        V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF                  = 0,
-        V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR               = 1,
-        V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_VERT              = 2,
-        V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_HV_SEPARABLE      = 3,
-        V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE = 4,
-};
-#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE  (V4L2_CID_MPEG_CX2341X_BASE+3)
-enum <link linkend="chroma-spatial-filter-type">v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type</link> {
-        V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF    = 0,
-        V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR = 1,
-};
-#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE        (V4L2_CID_MPEG_CX2341X_BASE+4)
-enum <link linkend="v4l2-mpeg-cx2341x-video-temporal-filter-mode">v4l2_mpeg_cx2341x_video_temporal_filter_mode</link> {
-        V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL = 0,
-        V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO   = 1,
-};
-#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER             (V4L2_CID_MPEG_CX2341X_BASE+5)
-#define V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE          (V4L2_CID_MPEG_CX2341X_BASE+6)
-enum <link linkend="v4l2-mpeg-cx2341x-video-median-filter-type">v4l2_mpeg_cx2341x_video_median_filter_type</link> {
-        V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF      = 0,
-        V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR      = 1,
-        V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_VERT     = 2,
-        V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR_VERT = 3,
-        V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG     = 4,
-};
-#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM   (V4L2_CID_MPEG_CX2341X_BASE+7)
-#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP      (V4L2_CID_MPEG_CX2341X_BASE+8)
-#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM (V4L2_CID_MPEG_CX2341X_BASE+9)
-#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP    (V4L2_CID_MPEG_CX2341X_BASE+10)
-#define V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS         (V4L2_CID_MPEG_CX2341X_BASE+11)
-
-/*  Camera class control IDs */
-#define V4L2_CID_CAMERA_CLASS_BASE      (V4L2_CTRL_CLASS_CAMERA | 0x900)
-#define V4L2_CID_CAMERA_CLASS           (V4L2_CTRL_CLASS_CAMERA | 1)
-
-#define V4L2_CID_EXPOSURE_AUTO                  (V4L2_CID_CAMERA_CLASS_BASE+1)
-enum  <link linkend="v4l2-exposure-auto-type">v4l2_exposure_auto_type</link> {
-        V4L2_EXPOSURE_AUTO = 0,
-        V4L2_EXPOSURE_MANUAL = 1,
-        V4L2_EXPOSURE_SHUTTER_PRIORITY = 2,
-        V4L2_EXPOSURE_APERTURE_PRIORITY = 3
-};
-#define V4L2_CID_EXPOSURE_ABSOLUTE              (V4L2_CID_CAMERA_CLASS_BASE+2)
-#define V4L2_CID_EXPOSURE_AUTO_PRIORITY         (V4L2_CID_CAMERA_CLASS_BASE+3)
-
-#define V4L2_CID_PAN_RELATIVE                   (V4L2_CID_CAMERA_CLASS_BASE+4)
-#define V4L2_CID_TILT_RELATIVE                  (V4L2_CID_CAMERA_CLASS_BASE+5)
-#define V4L2_CID_PAN_RESET                      (V4L2_CID_CAMERA_CLASS_BASE+6)
-#define V4L2_CID_TILT_RESET                     (V4L2_CID_CAMERA_CLASS_BASE+7)
-
-#define V4L2_CID_PAN_ABSOLUTE                   (V4L2_CID_CAMERA_CLASS_BASE+8)
-#define V4L2_CID_TILT_ABSOLUTE                  (V4L2_CID_CAMERA_CLASS_BASE+9)
-
-#define V4L2_CID_FOCUS_ABSOLUTE                 (V4L2_CID_CAMERA_CLASS_BASE+10)
-#define V4L2_CID_FOCUS_RELATIVE                 (V4L2_CID_CAMERA_CLASS_BASE+11)
-#define V4L2_CID_FOCUS_AUTO                     (V4L2_CID_CAMERA_CLASS_BASE+12)
-
-#define V4L2_CID_ZOOM_ABSOLUTE                  (V4L2_CID_CAMERA_CLASS_BASE+13)
-#define V4L2_CID_ZOOM_RELATIVE                  (V4L2_CID_CAMERA_CLASS_BASE+14)
-#define V4L2_CID_ZOOM_CONTINUOUS                (V4L2_CID_CAMERA_CLASS_BASE+15)
-
-#define V4L2_CID_PRIVACY                        (V4L2_CID_CAMERA_CLASS_BASE+16)
-
-#define V4L2_CID_IRIS_ABSOLUTE                  (V4L2_CID_CAMERA_CLASS_BASE+17)
-#define V4L2_CID_IRIS_RELATIVE                  (V4L2_CID_CAMERA_CLASS_BASE+18)
-
-/* FM Modulator class control IDs */
-#define V4L2_CID_FM_TX_CLASS_BASE               (V4L2_CTRL_CLASS_FM_TX | 0x900)
-#define V4L2_CID_FM_TX_CLASS                    (V4L2_CTRL_CLASS_FM_TX | 1)
-
-#define V4L2_CID_RDS_TX_DEVIATION               (V4L2_CID_FM_TX_CLASS_BASE + 1)
-#define V4L2_CID_RDS_TX_PI                      (V4L2_CID_FM_TX_CLASS_BASE + 2)
-#define V4L2_CID_RDS_TX_PTY                     (V4L2_CID_FM_TX_CLASS_BASE + 3)
-#define V4L2_CID_RDS_TX_PS_NAME                 (V4L2_CID_FM_TX_CLASS_BASE + 5)
-#define V4L2_CID_RDS_TX_RADIO_TEXT              (V4L2_CID_FM_TX_CLASS_BASE + 6)
-
-#define V4L2_CID_AUDIO_LIMITER_ENABLED          (V4L2_CID_FM_TX_CLASS_BASE + 64)
-#define V4L2_CID_AUDIO_LIMITER_RELEASE_TIME     (V4L2_CID_FM_TX_CLASS_BASE + 65)
-#define V4L2_CID_AUDIO_LIMITER_DEVIATION        (V4L2_CID_FM_TX_CLASS_BASE + 66)
-
-#define V4L2_CID_AUDIO_COMPRESSION_ENABLED      (V4L2_CID_FM_TX_CLASS_BASE + 80)
-#define V4L2_CID_AUDIO_COMPRESSION_GAIN         (V4L2_CID_FM_TX_CLASS_BASE + 81)
-#define V4L2_CID_AUDIO_COMPRESSION_THRESHOLD    (V4L2_CID_FM_TX_CLASS_BASE + 82)
-#define V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME  (V4L2_CID_FM_TX_CLASS_BASE + 83)
-#define V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME (V4L2_CID_FM_TX_CLASS_BASE + 84)
-
-#define V4L2_CID_PILOT_TONE_ENABLED             (V4L2_CID_FM_TX_CLASS_BASE + 96)
-#define V4L2_CID_PILOT_TONE_DEVIATION           (V4L2_CID_FM_TX_CLASS_BASE + 97)
-#define V4L2_CID_PILOT_TONE_FREQUENCY           (V4L2_CID_FM_TX_CLASS_BASE + 98)
-
-#define V4L2_CID_TUNE_PREEMPHASIS               (V4L2_CID_FM_TX_CLASS_BASE + 112)
-enum <link linkend="v4l2-preemphasis">v4l2_preemphasis</link> {
-        V4L2_PREEMPHASIS_DISABLED       = 0,
-        V4L2_PREEMPHASIS_50_uS          = 1,
-        V4L2_PREEMPHASIS_75_uS          = 2,
-};
-#define V4L2_CID_TUNE_POWER_LEVEL               (V4L2_CID_FM_TX_CLASS_BASE + 113)
-#define V4L2_CID_TUNE_ANTENNA_CAPACITOR         (V4L2_CID_FM_TX_CLASS_BASE + 114)
-
-/*
- *      T U N I N G
- */
-struct <link linkend="v4l2-tuner">v4l2_tuner</link> {
-        __u32                   index;
-        __u8                    name[32];
-        enum <link linkend="v4l2-tuner-type">v4l2_tuner_type</link>    type;
-        __u32                   capability;
-        __u32                   rangelow;
-        __u32                   rangehigh;
-        __u32                   rxsubchans;
-        __u32                   audmode;
-        __s32                   signal;
-        __s32                   afc;
-        __u32                   reserved[4];
-};
-
-struct <link linkend="v4l2-modulator">v4l2_modulator</link> {
-        __u32                   index;
-        __u8                    name[32];
-        __u32                   capability;
-        __u32                   rangelow;
-        __u32                   rangehigh;
-        __u32                   txsubchans;
-        __u32                   reserved[4];
-};
-
-/*  Flags for the 'capability' field */
-#define V4L2_TUNER_CAP_LOW              0x0001
-#define V4L2_TUNER_CAP_NORM             0x0002
-#define V4L2_TUNER_CAP_STEREO           0x0010
-#define V4L2_TUNER_CAP_LANG2            0x0020
-#define V4L2_TUNER_CAP_SAP              0x0020
-#define V4L2_TUNER_CAP_LANG1            0x0040
-#define V4L2_TUNER_CAP_RDS              0x0080
-#define V4L2_TUNER_CAP_RDS_BLOCK_IO     0x0100
-#define V4L2_TUNER_CAP_RDS_CONTROLS     0x0200
-
-/*  Flags for the 'rxsubchans' field */
-#define V4L2_TUNER_SUB_MONO             0x0001
-#define V4L2_TUNER_SUB_STEREO           0x0002
-#define V4L2_TUNER_SUB_LANG2            0x0004
-#define V4L2_TUNER_SUB_SAP              0x0004
-#define V4L2_TUNER_SUB_LANG1            0x0008
-#define V4L2_TUNER_SUB_RDS              0x0010
-
-/*  Values for the 'audmode' field */
-#define V4L2_TUNER_MODE_MONO            0x0000
-#define V4L2_TUNER_MODE_STEREO          0x0001
-#define V4L2_TUNER_MODE_LANG2           0x0002
-#define V4L2_TUNER_MODE_SAP             0x0002
-#define V4L2_TUNER_MODE_LANG1           0x0003
-#define V4L2_TUNER_MODE_LANG1_LANG2     0x0004
-
-struct <link linkend="v4l2-frequency">v4l2_frequency</link> {
-        __u32                 tuner;
-        enum <link linkend="v4l2-tuner-type">v4l2_tuner_type</link>  type;
-        __u32                 frequency;
-        __u32                 reserved[8];
-};
-
-struct <link linkend="v4l2-hw-freq-seek">v4l2_hw_freq_seek</link> {
-        __u32                 tuner;
-        enum <link linkend="v4l2-tuner-type">v4l2_tuner_type</link>  type;
-        __u32                 seek_upward;
-        __u32                 wrap_around;
-        __u32                 spacing;
-        __u32                 reserved[7];
-};
-
-/*
- *      R D S
- */
-
-struct <link linkend="v4l2-rds-data">v4l2_rds_data</link> {
-        __u8    lsb;
-        __u8    msb;
-        __u8    block;
-} __attribute__ ((packed));
-
-#define V4L2_RDS_BLOCK_MSK       0x7
-#define V4L2_RDS_BLOCK_A         0
-#define V4L2_RDS_BLOCK_B         1
-#define V4L2_RDS_BLOCK_C         2
-#define V4L2_RDS_BLOCK_D         3
-#define V4L2_RDS_BLOCK_C_ALT     4
-#define V4L2_RDS_BLOCK_INVALID   7
-
-#define V4L2_RDS_BLOCK_CORRECTED 0x40
-#define V4L2_RDS_BLOCK_ERROR     0x80
-
-/*
- *      A U D I O
- */
-struct <link linkend="v4l2-audio">v4l2_audio</link> {
-        __u32   index;
-        __u8    name[32];
-        __u32   capability;
-        __u32   mode;
-        __u32   reserved[2];
-};
-
-/*  Flags for the 'capability' field */
-#define V4L2_AUDCAP_STEREO              0x00001
-#define V4L2_AUDCAP_AVL                 0x00002
-
-/*  Flags for the 'mode' field */
-#define V4L2_AUDMODE_AVL                0x00001
-
-struct <link linkend="v4l2-audioout">v4l2_audioout</link> {
-        __u32   index;
-        __u8    name[32];
-        __u32   capability;
-        __u32   mode;
-        __u32   reserved[2];
-};
-
-/*
- *      M P E G   S E R V I C E S
- *
- *      NOTE: EXPERIMENTAL API
- */
-#if 1
-#define V4L2_ENC_IDX_FRAME_I    (0)
-#define V4L2_ENC_IDX_FRAME_P    (1)
-#define V4L2_ENC_IDX_FRAME_B    (2)
-#define V4L2_ENC_IDX_FRAME_MASK (0xf)
-
-struct <link linkend="v4l2-enc-idx-entry">v4l2_enc_idx_entry</link> {
-        __u64 offset;
-        __u64 pts;
-        __u32 length;
-        __u32 flags;
-        __u32 reserved[2];
-};
-
-#define V4L2_ENC_IDX_ENTRIES (64)
-struct <link linkend="v4l2-enc-idx">v4l2_enc_idx</link> {
-        __u32 entries;
-        __u32 entries_cap;
-        __u32 reserved[4];
-        struct <link linkend="v4l2-enc-idx-entry">v4l2_enc_idx_entry</link> entry[V4L2_ENC_IDX_ENTRIES];
-};
-
-
-#define V4L2_ENC_CMD_START      (0)
-#define V4L2_ENC_CMD_STOP       (1)
-#define V4L2_ENC_CMD_PAUSE      (2)
-#define V4L2_ENC_CMD_RESUME     (3)
-
-/* Flags for V4L2_ENC_CMD_STOP */
-#define V4L2_ENC_CMD_STOP_AT_GOP_END    (1 &lt;&lt; 0)
-
-struct <link linkend="v4l2-encoder-cmd">v4l2_encoder_cmd</link> {
-        __u32 cmd;
-        __u32 flags;
-        union {
-                struct {
-                        __u32 data[8];
-                } raw;
-        };
-};
-
-#endif
-
-
-/*
- *      D A T A   S E R V I C E S   ( V B I )
- *
- *      Data services API by Michael Schimek
- */
-
-/* Raw VBI */
-struct <link linkend="v4l2-vbi-format">v4l2_vbi_format</link> {
-        __u32   sampling_rate;          /* in 1 Hz */
-        __u32   offset;
-        __u32   samples_per_line;
-        __u32   sample_format;          /* V4L2_PIX_FMT_* */
-        __s32   start[2];
-        __u32   count[2];
-        __u32   flags;                  /* V4L2_VBI_* */
-        __u32   reserved[2];            /* must be zero */
-};
-
-/*  VBI flags  */
-#define V4L2_VBI_UNSYNC         (1 &lt;&lt; 0)
-#define V4L2_VBI_INTERLACED     (1 &lt;&lt; 1)
-
-/* Sliced VBI
- *
- *    This implements is a proposal V4L2 API to allow SLICED VBI
- * required for some hardware encoders. It should change without
- * notice in the definitive implementation.
- */
-
-struct <link linkend="v4l2-sliced-vbi-format">v4l2_sliced_vbi_format</link> {
-        __u16   service_set;
-        /* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field
-           service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field
-                                 (equals frame lines 313-336 for 625 line video
-                                  standards, 263-286 for 525 line standards) */
-        __u16   service_lines[2][24];
-        __u32   io_size;
-        __u32   reserved[2];            /* must be zero */
-};
-
-/* Teletext World System Teletext
-   (WST), defined on ITU-R BT.653-2 */
-#define V4L2_SLICED_TELETEXT_B          (0x0001)
-/* Video Program System, defined on ETS 300 231*/
-#define V4L2_SLICED_VPS                 (0x0400)
-/* Closed Caption, defined on EIA-608 */
-#define V4L2_SLICED_CAPTION_525         (0x1000)
-/* Wide Screen System, defined on ITU-R BT1119.1 */
-#define V4L2_SLICED_WSS_625             (0x4000)
-
-#define V4L2_SLICED_VBI_525             (V4L2_SLICED_CAPTION_525)
-#define V4L2_SLICED_VBI_625             (V4L2_SLICED_TELETEXT_B | V4L2_SLICED_VPS | V4L2_SLICED_WSS_625)
-
-struct <link linkend="v4l2-sliced-vbi-cap">v4l2_sliced_vbi_cap</link> {
-        __u16   service_set;
-        /* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field
-           service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field
-                                 (equals frame lines 313-336 for 625 line video
-                                  standards, 263-286 for 525 line standards) */
-        __u16   service_lines[2][24];
-        enum <link linkend="v4l2-buf-type">v4l2_buf_type</link> type;
-        __u32   reserved[3];    /* must be 0 */
-};
-
-struct <link linkend="v4l2-sliced-vbi-data">v4l2_sliced_vbi_data</link> {
-        __u32   id;
-        __u32   field;          /* 0: first field, 1: second field */
-        __u32   line;           /* 1-23 */
-        __u32   reserved;       /* must be 0 */
-        __u8    data[48];
-};
-
-/*
- * Sliced VBI data inserted into MPEG Streams
- */
-
-/*
- * V4L2_MPEG_STREAM_VBI_FMT_IVTV:
- *
- * Structure of payload contained in an MPEG 2 Private Stream 1 PES Packet in an
- * MPEG-2 Program Pack that contains V4L2_MPEG_STREAM_VBI_FMT_IVTV Sliced VBI
- * data
- *
- * Note, the MPEG-2 Program Pack and Private Stream 1 PES packet header
- * definitions are not included here.  See the MPEG-2 specifications for details
- * on these headers.
- */
-
-/* Line type IDs */
-#define V4L2_MPEG_VBI_IVTV_TELETEXT_B     (1)
-#define V4L2_MPEG_VBI_IVTV_CAPTION_525    (4)
-#define V4L2_MPEG_VBI_IVTV_WSS_625        (5)
-#define V4L2_MPEG_VBI_IVTV_VPS            (7)
-
-struct <link linkend="v4l2-mpeg-vbi-itv0-line">v4l2_mpeg_vbi_itv0_line</link> {
-        __u8 id;        /* One of V4L2_MPEG_VBI_IVTV_* above */
-        __u8 data[42];  /* Sliced VBI data for the line */
-} __attribute__ ((packed));
-
-struct <link linkend="v4l2-mpeg-vbi-itv0">v4l2_mpeg_vbi_itv0</link> {
-        __le32 linemask[2]; /* Bitmasks of VBI service lines present */
-        struct <link linkend="v4l2-mpeg-vbi-itv0-line">v4l2_mpeg_vbi_itv0_line</link> line[35];
-} __attribute__ ((packed));
-
-struct <link linkend="v4l2-mpeg-vbi-itv0-1">v4l2_mpeg_vbi_ITV0</link> {
-        struct <link linkend="v4l2-mpeg-vbi-itv0-line">v4l2_mpeg_vbi_itv0_line</link> line[36];
-} __attribute__ ((packed));
-
-#define V4L2_MPEG_VBI_IVTV_MAGIC0       "itv0"
-#define V4L2_MPEG_VBI_IVTV_MAGIC1       "ITV0"
-
-struct <link linkend="v4l2-mpeg-vbi-fmt-ivtv">v4l2_mpeg_vbi_fmt_ivtv</link> {
-        __u8 magic[4];
-        union {
-                struct <link linkend="v4l2-mpeg-vbi-itv0">v4l2_mpeg_vbi_itv0</link> itv0;
-                struct <link linkend="v4l2-mpeg-vbi-itv0-1">v4l2_mpeg_vbi_ITV0</link> ITV0;
-        };
-} __attribute__ ((packed));
-
-/*
- *      A G G R E G A T E   S T R U C T U R E S
- */
-
-/**
- * struct <link linkend="v4l2-plane-pix-format">v4l2_plane_pix_format</link> - additional, per-plane format definition
- * @sizeimage:          maximum size in bytes required for data, for which
- *                      this plane will be used
- * @bytesperline:       distance in bytes between the leftmost pixels in two
- *                      adjacent lines
- */
-struct <link linkend="v4l2-plane-pix-format">v4l2_plane_pix_format</link> {
-        __u32           sizeimage;
-        __u16           bytesperline;
-        __u16           reserved[7];
-} __attribute__ ((packed));
-
-/**
- * struct <link linkend="v4l2-pix-format-mplane">v4l2_pix_format_mplane</link> - multiplanar format definition
- * @width:              image width in pixels
- * @height:             image height in pixels
- * @pixelformat:        little endian four character code (fourcc)
- * @field:              field order (for interlaced video)
- * @colorspace:         supplemental to pixelformat
- * @plane_fmt:          per-plane information
- * @num_planes:         number of planes for this format
- */
-struct <link linkend="v4l2-pix-format-mplane">v4l2_pix_format_mplane</link> {
-        __u32                           width;
-        __u32                           height;
-        __u32                           pixelformat;
-        enum <link linkend="v4l2-field">v4l2_field</link>                 field;
-        enum <link linkend="v4l2-colorspace">v4l2_colorspace</link>            colorspace;
-
-        struct <link linkend="v4l2-plane-pix-format">v4l2_plane_pix_format</link>    plane_fmt[VIDEO_MAX_PLANES];
-        __u8                            num_planes;
-        __u8                            reserved[11];
-} __attribute__ ((packed));
-
-/**
- * struct <link linkend="v4l2-format">v4l2_format</link> - stream data format
- * @type:       type of the data stream
- * @pix:        definition of an image format
- * @pix_mp:     definition of a multiplanar image format
- * @win:        definition of an overlaid image
- * @vbi:        raw VBI capture or output parameters
- * @sliced:     sliced VBI capture or output parameters
- * @raw_data:   placeholder for future extensions and custom formats
- */
-struct <link linkend="v4l2-format">v4l2_format</link> {
-        enum <link linkend="v4l2-buf-type">v4l2_buf_type</link> type;
-        union {
-                struct <link linkend="v4l2-pix-format">v4l2_pix_format</link>          pix;     /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
-                struct <link linkend="v4l2-pix-format-mplane">v4l2_pix_format_mplane</link>   pix_mp;  /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
-                struct <link linkend="v4l2-window">v4l2_window</link>              win;     /* V4L2_BUF_TYPE_VIDEO_OVERLAY */
-                struct <link linkend="v4l2-vbi-format">v4l2_vbi_format</link>          vbi;     /* V4L2_BUF_TYPE_VBI_CAPTURE */
-                struct <link linkend="v4l2-sliced-vbi-format">v4l2_sliced_vbi_format</link>   sliced;  /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */
-                __u8    raw_data[200];                   /* user-defined */
-        } fmt;
-};
-
-/*      Stream type-dependent parameters
- */
-struct <link linkend="v4l2-streamparm">v4l2_streamparm</link> {
-        enum <link linkend="v4l2-buf-type">v4l2_buf_type</link> type;
-        union {
-                struct <link linkend="v4l2-captureparm">v4l2_captureparm</link> capture;
-                struct <link linkend="v4l2-outputparm">v4l2_outputparm</link>  output;
-                __u8    raw_data[200];  /* user-defined */
-        } parm;
-};
-
-/*
- *      E V E N T S
- */
-
-#define V4L2_EVENT_ALL                          0
-#define V4L2_EVENT_VSYNC                        1
-#define V4L2_EVENT_EOS                          2
-#define V4L2_EVENT_PRIVATE_START                0x08000000
-
-/* Payload for V4L2_EVENT_VSYNC */
-struct <link linkend="v4l2-event-vsync">v4l2_event_vsync</link> {
-        /* Can be V4L2_FIELD_ANY, _NONE, _TOP or _BOTTOM */
-        __u8 field;
-} __attribute__ ((packed));
-
-struct <link linkend="v4l2-event">v4l2_event</link> {
-        __u32                           type;
-        union {
-                struct <link linkend="v4l2-event-vsync">v4l2_event_vsync</link> vsync;
-                __u8                    data[64];
-        } u;
-        __u32                           pending;
-        __u32                           sequence;
-        struct timespec                 timestamp;
-        __u32                           reserved[9];
-};
-
-struct <link linkend="v4l2-event-subscription">v4l2_event_subscription</link> {
-        __u32                           type;
-        __u32                           reserved[7];
-};
-
-/*
- *      A D V A N C E D   D E B U G G I N G
- *
- *      NOTE: EXPERIMENTAL API, NEVER RELY ON THIS IN APPLICATIONS!
- *      FOR DEBUGGING, TESTING AND INTERNAL USE ONLY!
- */
-
-/* VIDIOC_DBG_G_REGISTER and VIDIOC_DBG_S_REGISTER */
-
-#define V4L2_CHIP_MATCH_HOST       0  /* Match against chip ID on host (0 for the host) */
-#define V4L2_CHIP_MATCH_I2C_DRIVER 1  /* Match against I2C driver name */
-#define V4L2_CHIP_MATCH_I2C_ADDR   2  /* Match against I2C 7-bit address */
-#define V4L2_CHIP_MATCH_AC97       3  /* Match against anciliary AC97 chip */
-
-struct <link linkend="v4l2-dbg-match">v4l2_dbg_match</link> {
-        __u32 type; /* Match type */
-        union {     /* Match this chip, meaning determined by type */
-                __u32 addr;
-                char name[32];
-        };
-} __attribute__ ((packed));
-
-struct <link linkend="v4l2-dbg-register">v4l2_dbg_register</link> {
-        struct <link linkend="v4l2-dbg-match">v4l2_dbg_match</link> match;
-        __u32 size;     /* register size in bytes */
-        __u64 reg;
-        __u64 val;
-} __attribute__ ((packed));
-
-/* VIDIOC_DBG_G_CHIP_IDENT */
-struct <link linkend="v4l2-dbg-chip-ident">v4l2_dbg_chip_ident</link> {
-        struct <link linkend="v4l2-dbg-match">v4l2_dbg_match</link> match;
-        __u32 ident;       /* chip identifier as specified in &lt;media/v4l2-chip-ident.h&gt; */
-        __u32 revision;    /* chip revision, chip specific */
-} __attribute__ ((packed));
-
-/*
- *      I O C T L   C O D E S   F O R   V I D E O   D E V I C E S
- *
- */
-#define VIDIOC_QUERYCAP          _IOR('V',  0, struct <link linkend="v4l2-capability">v4l2_capability</link>)
-#define VIDIOC_RESERVED           _IO('V',  1)
-#define VIDIOC_ENUM_FMT         _IOWR('V',  2, struct <link linkend="v4l2-fmtdesc">v4l2_fmtdesc</link>)
-#define VIDIOC_G_FMT            _IOWR('V',  4, struct <link linkend="v4l2-format">v4l2_format</link>)
-#define VIDIOC_S_FMT            _IOWR('V',  5, struct <link linkend="v4l2-format">v4l2_format</link>)
-#define VIDIOC_REQBUFS          _IOWR('V',  8, struct <link linkend="v4l2-requestbuffers">v4l2_requestbuffers</link>)
-#define VIDIOC_QUERYBUF         _IOWR('V',  9, struct <link linkend="v4l2-buffer">v4l2_buffer</link>)
-#define VIDIOC_G_FBUF            _IOR('V', 10, struct <link linkend="v4l2-framebuffer">v4l2_framebuffer</link>)
-#define VIDIOC_S_FBUF            _IOW('V', 11, struct <link linkend="v4l2-framebuffer">v4l2_framebuffer</link>)
-#define VIDIOC_OVERLAY           _IOW('V', 14, int)
-#define VIDIOC_QBUF             _IOWR('V', 15, struct <link linkend="v4l2-buffer">v4l2_buffer</link>)
-#define VIDIOC_DQBUF            _IOWR('V', 17, struct <link linkend="v4l2-buffer">v4l2_buffer</link>)
-#define VIDIOC_STREAMON          _IOW('V', 18, int)
-#define VIDIOC_STREAMOFF         _IOW('V', 19, int)
-#define VIDIOC_G_PARM           _IOWR('V', 21, struct <link linkend="v4l2-streamparm">v4l2_streamparm</link>)
-#define VIDIOC_S_PARM           _IOWR('V', 22, struct <link linkend="v4l2-streamparm">v4l2_streamparm</link>)
-#define VIDIOC_G_STD             _IOR('V', 23, v4l2_std_id)
-#define VIDIOC_S_STD             _IOW('V', 24, v4l2_std_id)
-#define VIDIOC_ENUMSTD          _IOWR('V', 25, struct <link linkend="v4l2-standard">v4l2_standard</link>)
-#define VIDIOC_ENUMINPUT        _IOWR('V', 26, struct <link linkend="v4l2-input">v4l2_input</link>)
-#define VIDIOC_G_CTRL           _IOWR('V', 27, struct <link linkend="v4l2-control">v4l2_control</link>)
-#define VIDIOC_S_CTRL           _IOWR('V', 28, struct <link linkend="v4l2-control">v4l2_control</link>)
-#define VIDIOC_G_TUNER          _IOWR('V', 29, struct <link linkend="v4l2-tuner">v4l2_tuner</link>)
-#define VIDIOC_S_TUNER           _IOW('V', 30, struct <link linkend="v4l2-tuner">v4l2_tuner</link>)
-#define VIDIOC_G_AUDIO           _IOR('V', 33, struct <link linkend="v4l2-audio">v4l2_audio</link>)
-#define VIDIOC_S_AUDIO           _IOW('V', 34, struct <link linkend="v4l2-audio">v4l2_audio</link>)
-#define VIDIOC_QUERYCTRL        _IOWR('V', 36, struct <link linkend="v4l2-queryctrl">v4l2_queryctrl</link>)
-#define VIDIOC_QUERYMENU        _IOWR('V', 37, struct <link linkend="v4l2-querymenu">v4l2_querymenu</link>)
-#define VIDIOC_G_INPUT           _IOR('V', 38, int)
-#define VIDIOC_S_INPUT          _IOWR('V', 39, int)
-#define VIDIOC_G_OUTPUT          _IOR('V', 46, int)
-#define VIDIOC_S_OUTPUT         _IOWR('V', 47, int)
-#define VIDIOC_ENUMOUTPUT       _IOWR('V', 48, struct <link linkend="v4l2-output">v4l2_output</link>)
-#define VIDIOC_G_AUDOUT          _IOR('V', 49, struct <link linkend="v4l2-audioout">v4l2_audioout</link>)
-#define VIDIOC_S_AUDOUT          _IOW('V', 50, struct <link linkend="v4l2-audioout">v4l2_audioout</link>)
-#define VIDIOC_G_MODULATOR      _IOWR('V', 54, struct <link linkend="v4l2-modulator">v4l2_modulator</link>)
-#define VIDIOC_S_MODULATOR       _IOW('V', 55, struct <link linkend="v4l2-modulator">v4l2_modulator</link>)
-#define VIDIOC_G_FREQUENCY      _IOWR('V', 56, struct <link linkend="v4l2-frequency">v4l2_frequency</link>)
-#define VIDIOC_S_FREQUENCY       _IOW('V', 57, struct <link linkend="v4l2-frequency">v4l2_frequency</link>)
-#define VIDIOC_CROPCAP          _IOWR('V', 58, struct <link linkend="v4l2-cropcap">v4l2_cropcap</link>)
-#define VIDIOC_G_CROP           _IOWR('V', 59, struct <link linkend="v4l2-crop">v4l2_crop</link>)
-#define VIDIOC_S_CROP            _IOW('V', 60, struct <link linkend="v4l2-crop">v4l2_crop</link>)
-#define VIDIOC_G_JPEGCOMP        _IOR('V', 61, struct <link linkend="v4l2-jpegcompression">v4l2_jpegcompression</link>)
-#define VIDIOC_S_JPEGCOMP        _IOW('V', 62, struct <link linkend="v4l2-jpegcompression">v4l2_jpegcompression</link>)
-#define VIDIOC_QUERYSTD          _IOR('V', 63, v4l2_std_id)
-#define VIDIOC_TRY_FMT          _IOWR('V', 64, struct <link linkend="v4l2-format">v4l2_format</link>)
-#define VIDIOC_ENUMAUDIO        _IOWR('V', 65, struct <link linkend="v4l2-audio">v4l2_audio</link>)
-#define VIDIOC_ENUMAUDOUT       _IOWR('V', 66, struct <link linkend="v4l2-audioout">v4l2_audioout</link>)
-#define VIDIOC_G_PRIORITY        _IOR('V', 67, enum <link linkend="v4l2-priority">v4l2_priority</link>)
-#define VIDIOC_S_PRIORITY        _IOW('V', 68, enum <link linkend="v4l2-priority">v4l2_priority</link>)
-#define VIDIOC_G_SLICED_VBI_CAP _IOWR('V', 69, struct <link linkend="v4l2-sliced-vbi-cap">v4l2_sliced_vbi_cap</link>)
-#define VIDIOC_LOG_STATUS         _IO('V', 70)
-#define VIDIOC_G_EXT_CTRLS      _IOWR('V', 71, struct <link linkend="v4l2-ext-controls">v4l2_ext_controls</link>)
-#define VIDIOC_S_EXT_CTRLS      _IOWR('V', 72, struct <link linkend="v4l2-ext-controls">v4l2_ext_controls</link>)
-#define VIDIOC_TRY_EXT_CTRLS    _IOWR('V', 73, struct <link linkend="v4l2-ext-controls">v4l2_ext_controls</link>)
-#if 1
-#define VIDIOC_ENUM_FRAMESIZES  _IOWR('V', 74, struct <link linkend="v4l2-frmsizeenum">v4l2_frmsizeenum</link>)
-#define VIDIOC_ENUM_FRAMEINTERVALS _IOWR('V', 75, struct <link linkend="v4l2-frmivalenum">v4l2_frmivalenum</link>)
-#define VIDIOC_G_ENC_INDEX       _IOR('V', 76, struct <link linkend="v4l2-enc-idx">v4l2_enc_idx</link>)
-#define VIDIOC_ENCODER_CMD      _IOWR('V', 77, struct <link linkend="v4l2-encoder-cmd">v4l2_encoder_cmd</link>)
-#define VIDIOC_TRY_ENCODER_CMD  _IOWR('V', 78, struct <link linkend="v4l2-encoder-cmd">v4l2_encoder_cmd</link>)
-#endif
-
-#if 1
-/* Experimental, meant for debugging, testing and internal use.
-   Only implemented if CONFIG_VIDEO_ADV_DEBUG is defined.
-   You must be root to use these ioctls. Never use these in applications! */
-#define VIDIOC_DBG_S_REGISTER    _IOW('V', 79, struct <link linkend="v4l2-dbg-register">v4l2_dbg_register</link>)
-#define VIDIOC_DBG_G_REGISTER   _IOWR('V', 80, struct <link linkend="v4l2-dbg-register">v4l2_dbg_register</link>)
-
-/* Experimental, meant for debugging, testing and internal use.
-   Never use this ioctl in applications! */
-#define VIDIOC_DBG_G_CHIP_IDENT _IOWR('V', 81, struct <link linkend="v4l2-dbg-chip-ident">v4l2_dbg_chip_ident</link>)
-#endif
-
-#define VIDIOC_S_HW_FREQ_SEEK    _IOW('V', 82, struct <link linkend="v4l2-hw-freq-seek">v4l2_hw_freq_seek</link>)
-#define VIDIOC_ENUM_DV_PRESETS  _IOWR('V', 83, struct <link linkend="v4l2-dv-enum-preset">v4l2_dv_enum_preset</link>)
-#define VIDIOC_S_DV_PRESET      _IOWR('V', 84, struct <link linkend="v4l2-dv-preset">v4l2_dv_preset</link>)
-#define VIDIOC_G_DV_PRESET      _IOWR('V', 85, struct <link linkend="v4l2-dv-preset">v4l2_dv_preset</link>)
-#define VIDIOC_QUERY_DV_PRESET  _IOR('V',  86, struct <link linkend="v4l2-dv-preset">v4l2_dv_preset</link>)
-#define VIDIOC_S_DV_TIMINGS     _IOWR('V', 87, struct <link linkend="v4l2-dv-timings">v4l2_dv_timings</link>)
-#define VIDIOC_G_DV_TIMINGS     _IOWR('V', 88, struct <link linkend="v4l2-dv-timings">v4l2_dv_timings</link>)
-#define VIDIOC_DQEVENT           _IOR('V', 89, struct <link linkend="v4l2-event">v4l2_event</link>)
-#define VIDIOC_SUBSCRIBE_EVENT   _IOW('V', 90, struct <link linkend="v4l2-event-subscription">v4l2_event_subscription</link>)
-#define VIDIOC_UNSUBSCRIBE_EVENT _IOW('V', 91, struct <link linkend="v4l2-event-subscription">v4l2_event_subscription</link>)
-
-/* Reminder: when adding new ioctls please add support for them to
-   drivers/media/video/v4l2-compat-ioctl32.c as well! */
-
-#define BASE_VIDIOC_PRIVATE     192             /* 192-255 are private */
-
-#endif /* __LINUX_VIDEODEV2_H */
-</programlisting>
diff --git a/Documentation/DocBook/v4l/vidioc-subscribe-event.xml b/Documentation/DocBook/v4l/vidioc-subscribe-event.xml
deleted file mode 100644 (file)
index 8b50179..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-<refentry id="vidioc-subscribe-event">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT</refname>
-    <refpurpose>Subscribe or unsubscribe event</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_event_subscription
-*<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>Subscribe or unsubscribe V4L2 event. Subscribed events are
-    dequeued by using the &VIDIOC-DQEVENT; ioctl.</para>
-
-    <table frame="none" pgwide="1" id="v4l2-event-subscription">
-      <title>struct <structname>v4l2_event_subscription</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>Type of the event.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[7]</entry>
-           <entry>Reserved for future extensions. Drivers and applications
-           must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="event-type">
-      <title>Event Types</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_EVENT_ALL</constant></entry>
-           <entry>0</entry>
-           <entry>All events. V4L2_EVENT_ALL is valid only for
-           VIDIOC_UNSUBSCRIBE_EVENT for unsubscribing all events at once.
-           </entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_EVENT_VSYNC</constant></entry>
-           <entry>1</entry>
-           <entry>This event is triggered on the vertical sync.
-           This event has &v4l2-event-vsync; associated with it.
-           </entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_EVENT_EOS</constant></entry>
-           <entry>2</entry>
-           <entry>This event is triggered when the end of a stream is reached.
-           This is typically used with MPEG decoders to report to the application
-           when the last of the MPEG stream has been decoded.
-           </entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_EVENT_PRIVATE_START</constant></entry>
-           <entry>0x08000000</entry>
-           <entry>Base event number for driver-private events.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="v4l2-event-vsync">
-      <title>struct <structname>v4l2_event_vsync</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>field</structfield></entry>
-           <entry>The upcoming field. See &v4l2-field;.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-  </refsect1>
-</refentry>
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
index 3f5e0b0..53e6fca 100644 (file)
@@ -45,7 +45,7 @@ arrived in memory (this becomes more likely with devices behind PCI-PCI
 bridges).  In order to ensure that all the data has arrived in memory,
 the interrupt handler must read a register on the device which raised
 the interrupt.  PCI transaction ordering rules require that all the data
-arrives in memory before the value can be returned from the register.
+arrive in memory before the value may be returned from the register.
 Using MSIs avoids this problem as the interrupt-generating write cannot
 pass the data writes, so by the time the interrupt is raised, the driver
 knows that all the data has arrived in memory.
@@ -86,13 +86,13 @@ device.
 
 int pci_enable_msi(struct pci_dev *dev)
 
-A successful call will allocate ONE interrupt to the device, regardless
-of how many MSIs the device supports.  The device will be switched from
+A successful call allocates ONE interrupt to the device, regardless
+of how many MSIs the device supports.  The device is switched from
 pin-based interrupt mode to MSI mode.  The dev->irq number is changed
-to a new number which represents the message signaled interrupt.
-This function should be called before the driver calls request_irq()
-since enabling MSIs disables the pin-based IRQ and the driver will not
-receive interrupts on the old interrupt.
+to a new number which represents the message signaled interrupt;
+consequently, this function should be called before the driver calls
+request_irq(), because an MSI is delivered via a vector that is
+different from the vector of a pin-based interrupt.
 
 4.2.2 pci_enable_msi_block
 
@@ -111,20 +111,20 @@ the device are in the range dev->irq to dev->irq + count - 1.
 
 If this function returns a negative number, it indicates an error and
 the driver should not attempt to request any more MSI interrupts for
-this device.  If this function returns a positive number, it will be
-less than 'count' and indicate the number of interrupts that could have
-been allocated.  In neither case will the irq value have been
-updated, nor will the device have been switched into MSI mode.
+this device.  If this function returns a positive number, it is
+less than 'count' and indicates the number of interrupts that could have
+been allocated.  In neither case is the irq value updated or the device
+switched into MSI mode.
 
 The device driver must decide what action to take if
-pci_enable_msi_block() returns a value less than the number asked for.
-Some devices can make use of fewer interrupts than the maximum they
-request; in this case the driver should call pci_enable_msi_block()
+pci_enable_msi_block() returns a value less than the number requested.
+For instance, the driver could still make use of fewer interrupts;
+in this case the driver should call pci_enable_msi_block()
 again.  Note that it is not guaranteed to succeed, even when the
 'count' has been reduced to the value returned from a previous call to
 pci_enable_msi_block().  This is because there are multiple constraints
 on the number of vectors that can be allocated; pci_enable_msi_block()
-will return as soon as it finds any constraint that doesn't allow the
+returns as soon as it finds any constraint that doesn't allow the
 call to succeed.
 
 4.2.3 pci_disable_msi
@@ -137,10 +137,10 @@ interrupt number and frees the previously allocated message signaled
 interrupt(s).  The interrupt may subsequently be assigned to another
 device, so drivers should not cache the value of dev->irq.
 
-A device driver must always call free_irq() on the interrupt(s)
-for which it has called request_irq() before calling this function.
-Failure to do so will result in a BUG_ON(), the device will be left with
-MSI enabled and will leak its vector.
+Before calling this function, a device driver must always call free_irq()
+on any interrupt for which it previously called request_irq().
+Failure to do so results in a BUG_ON(), leaving the device with
+MSI enabled and thus leaking its vector.
 
 4.3 Using MSI-X
 
@@ -155,10 +155,10 @@ struct msix_entry {
 };
 
 This allows for the device to use these interrupts in a sparse fashion;
-for example it could use interrupts 3 and 1027 and allocate only a
+for example, it could use interrupts 3 and 1027 and yet allocate only a
 two-element array.  The driver is expected to fill in the 'entry' value
-in each element of the array to indicate which entries it wants the kernel
-to assign interrupts for.  It is invalid to fill in two entries with the
+in each element of the array to indicate for which entries the kernel
+should assign interrupts; it is invalid to fill in two entries with the
 same number.
 
 4.3.1 pci_enable_msix
@@ -168,10 +168,11 @@ int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec)
 Calling this function asks the PCI subsystem to allocate 'nvec' MSIs.
 The 'entries' argument is a pointer to an array of msix_entry structs
 which should be at least 'nvec' entries in size.  On success, the
-function will return 0 and the device will have been switched into
-MSI-X interrupt mode.  The 'vector' elements in each entry will have
-been filled in with the interrupt number.  The driver should then call
-request_irq() for each 'vector' that it decides to use.
+device is switched into MSI-X mode and the function returns 0.
+The 'vector' member in each entry is populated with the interrupt number;
+the driver should then call request_irq() for each 'vector' that it
+decides to use.  The device driver is responsible for keeping track of the
+interrupts assigned to the MSI-X vectors so it can free them again later.
 
 If this function returns a negative number, it indicates an error and
 the driver should not attempt to allocate any more MSI-X interrupts for
@@ -181,16 +182,14 @@ below.
 
 This function, in contrast with pci_enable_msi(), does not adjust
 dev->irq.  The device will not generate interrupts for this interrupt
-number once MSI-X is enabled.  The device driver is responsible for
-keeping track of the interrupts assigned to the MSI-X vectors so it can
-free them again later.
+number once MSI-X is enabled.
 
 Device drivers should normally call this function once per device
 during the initialization phase.
 
-It is ideal if drivers can cope with a variable number of MSI-X interrupts,
+It is ideal if drivers can cope with a variable number of MSI-X interrupts;
 there are many reasons why the platform may not be able to provide the
-exact number a driver asks for.
+exact number that a driver asks for.
 
 A request loop to achieve that might look like:
 
@@ -212,15 +211,15 @@ static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
 
 void pci_disable_msix(struct pci_dev *dev)
 
-This API should be used to undo the effect of pci_enable_msix().  It frees
+This function should be used to undo the effect of pci_enable_msix().  It frees
 the previously allocated message signaled interrupts.  The interrupts may
 subsequently be assigned to another device, so drivers should not cache
 the value of the 'vector' elements over a call to pci_disable_msix().
 
-A device driver must always call free_irq() on the interrupt(s)
-for which it has called request_irq() before calling this function.
-Failure to do so will result in a BUG_ON(), the device will be left with
-MSI enabled and will leak its vector.
+Before calling this function, a device driver must always call free_irq()
+on any interrupt for which it previously called request_irq().
+Failure to do so results in a BUG_ON(), leaving the device with
+MSI-X enabled and thus leaking its vector.
 
 4.3.3 The MSI-X Table
 
@@ -232,10 +231,10 @@ mask or unmask an interrupt, it should call disable_irq() / enable_irq().
 4.4 Handling devices implementing both MSI and MSI-X capabilities
 
 If a device implements both MSI and MSI-X capabilities, it can
-run in either MSI mode or MSI-X mode but not both simultaneously.
+run in either MSI mode or MSI-X mode, but not both simultaneously.
 This is a requirement of the PCI spec, and it is enforced by the
 PCI layer.  Calling pci_enable_msi() when MSI-X is already enabled or
-pci_enable_msix() when MSI is already enabled will result in an error.
+pci_enable_msix() when MSI is already enabled results in an error.
 If a device driver wishes to switch between MSI and MSI-X at runtime,
 it must first quiesce the device, then switch it back to pin-interrupt
 mode, before calling pci_enable_msi() or pci_enable_msix() and resuming
@@ -251,7 +250,7 @@ the MSI-X facilities in preference to the MSI facilities.  As mentioned
 above, MSI-X supports any number of interrupts between 1 and 2048.
 In constrast, MSI is restricted to a maximum of 32 interrupts (and
 must be a power of two).  In addition, the MSI interrupt vectors must
-be allocated consecutively, so the system may not be able to allocate
+be allocated consecutively, so the system might not be able to allocate
 as many vectors for MSI as it could for MSI-X.  On some platforms, MSI
 interrupts must all be targeted at the same set of CPUs whereas MSI-X
 interrupts can all be targeted at different CPUs.
@@ -281,7 +280,7 @@ disabled to enabled and back again.
 
 Using 'lspci -v' (as root) may show some devices with "MSI", "Message
 Signalled Interrupts" or "MSI-X" capabilities.  Each of these capabilities
-has an 'Enable' flag which will be followed with either "+" (enabled)
+has an 'Enable' flag which is followed with either "+" (enabled)
 or "-" (disabled).
 
 
@@ -298,7 +297,7 @@ The PCI stack provides three ways to disable MSIs:
 
 Some host chipsets simply don't support MSIs properly.  If we're
 lucky, the manufacturer knows this and has indicated it in the ACPI
-FADT table.  In this case, Linux will automatically disable MSIs.
+FADT table.  In this case, Linux automatically disables MSIs.
 Some boards don't include this information in the table and so we have
 to detect them ourselves.  The complete list of these is found near the
 quirk_disable_all_msi() function in drivers/pci/quirks.c.
@@ -317,7 +316,7 @@ Some bridges allow you to enable MSIs by changing some bits in their
 PCI configuration space (especially the Hypertransport chipsets such
 as the nVidia nForce and Serverworks HT2000).  As with host chipsets,
 Linux mostly knows about them and automatically enables MSIs if it can.
-If you have a bridge which Linux doesn't yet know about, you can enable
+If you have a bridge unknown to Linux, you can enable
 MSIs in configuration space using whatever method you know works, then
 enable MSIs on that bridge by doing:
 
@@ -327,7 +326,7 @@ where $bridge is the PCI address of the bridge you've enabled (eg
 0000:00:0e.0).
 
 To disable MSIs, echo 0 instead of 1.  Changing this value should be
-done with caution as it can break interrupt handling for all devices
+done with caution as it could break interrupt handling for all devices
 below this bridge.
 
 Again, please notify linux-pci@vger.kernel.org of any bridges that need
@@ -336,7 +335,7 @@ special handling.
 5.3. Disabling MSIs on a single device
 
 Some devices are known to have faulty MSI implementations.  Usually this
-is handled in the individual device driver but occasionally it's necessary
+is handled in the individual device driver, but occasionally it's necessary
 to handle this with a quirk.  Some drivers have an option to disable use
 of MSI.  While this is a convenient workaround for the driver author,
 it is not good practise, and should not be emulated.
@@ -350,7 +349,7 @@ for your machine.  You should also check your .config to be sure you
 have enabled CONFIG_PCI_MSI.
 
 Then, 'lspci -t' gives the list of bridges above a device.  Reading
-/sys/bus/pci/devices/*/msi_bus will tell you whether MSI are enabled (1)
+/sys/bus/pci/devices/*/msi_bus will tell you whether MSIs are enabled (1)
 or disabled (0).  If 0 is found in any of the msi_bus files belonging
 to bridges between the PCI root and the device, MSIs are disabled.
 
index 319baa8..36d16bb 100644 (file)
@@ -130,7 +130,7 @@ Linux kernel master tree:
        ftp.??.kernel.org:/pub/linux/kernel/...
        ?? == your country code, such as "us", "uk", "fr", etc.
 
-       http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git
+       http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git
 
 Linux kernel mailing list:
        linux-kernel@vger.kernel.org
index 569f353..4468ce2 100644 (file)
@@ -303,7 +303,7 @@ patches that are being emailed around.
 
 The sign-off is a simple line at the end of the explanation for the
 patch, which certifies that you wrote it or otherwise have the right to
-pass it on as a open-source patch.  The rules are pretty simple: if you
+pass it on as an open-source patch.  The rules are pretty simple: if you
 can certify the below:
 
         Developer's Certificate of Origin 1.1
index dfab718..5cc699b 100644 (file)
@@ -48,12 +48,19 @@ directory apei/einj. The following files are provided.
 - param1
   This file is used to set the first error parameter value. Effect of
   parameter depends on error_type specified. For memory error, this is
-  physical memory address.
+  physical memory address.  Only available if param_extension module
+  parameter is specified.
 
 - param2
   This file is used to set the second error parameter value. Effect of
   parameter depends on error_type specified. For memory error, this is
-  physical memory address mask.
+  physical memory address mask.  Only available if param_extension
+  module parameter is specified.
+
+Injecting parameter support is a BIOS version specific extension, that
+is, it only works on some BIOS version.  If you want to use it, please
+make sure your BIOS version has the proper support and specify
+"param_extension=y" in module parameter.
 
 For more information about EINJ, please refer to ACPI specification
 version 4.0, section 17.5.
index e578fee..6d670f5 100644 (file)
@@ -43,3 +43,74 @@ If one sets slice_idle=0 and if storage supports NCQ, CFQ internally switches
 to IOPS mode and starts providing fairness in terms of number of requests
 dispatched. Note that this mode switching takes effect only for group
 scheduling. For non-cgroup users nothing should change.
+
+CFQ IO scheduler Idling Theory
+===============================
+Idling on a queue is primarily about waiting for the next request to come
+on same queue after completion of a request. In this process CFQ will not
+dispatch requests from other cfq queues even if requests are pending there.
+
+The rationale behind idling is that it can cut down on number of seeks
+on rotational media. For example, if a process is doing dependent
+sequential reads (next read will come on only after completion of previous
+one), then not dispatching request from other queue should help as we
+did not move the disk head and kept on dispatching sequential IO from
+one queue.
+
+CFQ has following service trees and various queues are put on these trees.
+
+       sync-idle       sync-noidle     async
+
+All cfq queues doing synchronous sequential IO go on to sync-idle tree.
+On this tree we idle on each queue individually.
+
+All synchronous non-sequential queues go on sync-noidle tree. Also any
+request which are marked with REQ_NOIDLE go on this service tree. On this
+tree we do not idle on individual queues instead idle on the whole group
+of queues or the tree. So if there are 4 queues waiting for IO to dispatch
+we will idle only once last queue has dispatched the IO and there is
+no more IO on this service tree.
+
+All async writes go on async service tree. There is no idling on async
+queues.
+
+CFQ has some optimizations for SSDs and if it detects a non-rotational
+media which can support higher queue depth (multiple requests at in
+flight at a time), then it cuts down on idling of individual queues and
+all the queues move to sync-noidle tree and only tree idle remains. This
+tree idling provides isolation with buffered write queues on async tree.
+
+FAQ
+===
+Q1. Why to idle at all on queues marked with REQ_NOIDLE.
+
+A1. We only do tree idle (all queues on sync-noidle tree) on queues marked
+    with REQ_NOIDLE. This helps in providing isolation with all the sync-idle
+    queues. Otherwise in presence of many sequential readers, other
+    synchronous IO might not get fair share of disk.
+
+    For example, if there are 10 sequential readers doing IO and they get
+    100ms each. If a REQ_NOIDLE request comes in, it will be scheduled
+    roughly after 1 second. If after completion of REQ_NOIDLE request we
+    do not idle, and after a couple of milli seconds a another REQ_NOIDLE
+    request comes in, again it will be scheduled after 1second. Repeat it
+    and notice how a workload can lose its disk share and suffer due to
+    multiple sequential readers.
+
+    fsync can generate dependent IO where bunch of data is written in the
+    context of fsync, and later some journaling data is written. Journaling
+    data comes in only after fsync has finished its IO (atleast for ext4
+    that seemed to be the case). Now if one decides not to idle on fsync
+    thread due to REQ_NOIDLE, then next journaling write will not get
+    scheduled for another second. A process doing small fsync, will suffer
+    badly in presence of multiple sequential readers.
+
+    Hence doing tree idling on threads using REQ_NOIDLE flag on requests
+    provides isolation from multiple sequential readers and at the same
+    time we do not idle on individual threads.
+
+Q2. When to specify REQ_NOIDLE
+A2. I would think whenever one is doing synchronous write and not expecting
+    more writes to be dispatched from same context soon, should be able
+    to specify REQ_NOIDLE on writes and that probably should work well for
+    most of the cases.
index 6b5c42d..2c656ae 100644 (file)
@@ -4,7 +4,8 @@ dm-crypt
 Device-Mapper's "crypt" target provides transparent encryption of block devices
 using the kernel crypto API.
 
-Parameters: <cipher> <key> <iv_offset> <device path> <offset>
+Parameters: <cipher> <key> <iv_offset> <device path> \
+             <offset> [<#opt_params> <opt_params>]
 
 <cipher>
     Encryption cipher and an optional IV generation mode.
@@ -37,6 +38,24 @@ Parameters: <cipher> <key> <iv_offset> <device path> <offset>
 <offset>
     Starting sector within the device where the encrypted data begins.
 
+<#opt_params>
+    Number of optional parameters. If there are no optional parameters,
+    the optional paramaters section can be skipped or #opt_params can be zero.
+    Otherwise #opt_params is the number of following arguments.
+
+    Example of optional parameters section:
+        1 allow_discards
+
+allow_discards
+    Block discard requests (a.k.a. TRIM) are passed through the crypt device.
+    The default is to ignore discard requests.
+
+    WARNING: Assess the specific security risks carefully before enabling this
+    option.  For example, allowing discards on encrypted devices may lead to
+    the leak of information about the ciphertext device (filesystem type,
+    used space etc.) if the discarded blocks can be located easily on the
+    device later.
+
 Example scripts
 ===============
 LUKS (Linux Unified Key Setup) is now the preferred way to set up disk
index c8efdfd..6ff5c23 100644 (file)
@@ -1,17 +1,53 @@
 dm-flakey
 =========
 
-This target is the same as the linear target except that it returns I/O
-errors periodically.  It's been found useful in simulating failing
-devices for testing purposes.
+This target is the same as the linear target except that it exhibits
+unreliable behaviour periodically.  It's been found useful in simulating
+failing devices for testing purposes.
 
 Starting from the time the table is loaded, the device is available for
-<up interval> seconds, then returns errors for <down interval> seconds,
-and then this cycle repeats.
+<up interval> seconds, then exhibits unreliable behaviour for <down
+interval> seconds, and then this cycle repeats.
 
-Parameters: <dev path> <offset> <up interval> <down interval>
+Also, consider using this in combination with the dm-delay target too,
+which can delay reads and writes and/or send them to different
+underlying devices.
+
+Table parameters
+----------------
+  <dev path> <offset> <up interval> <down interval> \
+    [<num_features> [<feature arguments>]]
+
+Mandatory parameters:
     <dev path>: Full pathname to the underlying block-device, or a
                 "major:minor" device-number.
     <offset>: Starting sector within the device.
     <up interval>: Number of seconds device is available.
     <down interval>: Number of seconds device returns errors.
+
+Optional feature parameters:
+  If no feature parameters are present, during the periods of
+  unreliability, all I/O returns errors.
+
+  drop_writes:
+       All write I/O is silently ignored.
+       Read I/O is handled correctly.
+
+  corrupt_bio_byte <Nth_byte> <direction> <value> <flags>:
+       During <down interval>, replace <Nth_byte> of the data of
+       each matching bio with <value>.
+
+    <Nth_byte>: The offset of the byte to replace.
+               Counting starts at 1, to replace the first byte.
+    <direction>: Either 'r' to corrupt reads or 'w' to corrupt writes.
+                'w' is incompatible with drop_writes.
+    <value>: The value (from 0-255) to write.
+    <flags>: Perform the replacement only if bio->bi_rw has all the
+            selected flags set.
+
+Examples:
+  corrupt_bio_byte 32 r 1 0
+       - replaces the 32nd byte of READ bios with the value 1
+
+  corrupt_bio_byte 224 w 0 32
+       - replaces the 224th byte of REQ_META (=32) bios with the value 0
index 33b6b70..2a8c113 100644 (file)
-Device-mapper RAID (dm-raid) is a bridge from DM to MD.  It
-provides a way to use device-mapper interfaces to access the MD RAID
-drivers.
+dm-raid
+-------
 
-As with all device-mapper targets, the nominal public interfaces are the
-constructor (CTR) tables and the status outputs (both STATUSTYPE_INFO
-and STATUSTYPE_TABLE).  The CTR table looks like the following:
+The device-mapper RAID (dm-raid) target provides a bridge from DM to MD.
+It allows the MD RAID drivers to be accessed using a device-mapper
+interface.
 
-1: <s> <l> raid \
-2:      <raid_type> <#raid_params> <raid_params> \
-3:      <#raid_devs> <meta_dev1> <dev1> .. <meta_devN> <devN>
-
-Line 1 contains the standard first three arguments to any device-mapper
-target - the start, length, and target type fields.  The target type in
-this case is "raid".
-
-Line 2 contains the arguments that define the particular raid
-type/personality/level, the required arguments for that raid type, and
-any optional arguments.  Possible raid types include: raid4, raid5_la,
-raid5_ls, raid5_rs, raid6_zr, raid6_nr, and raid6_nc.  (raid1 is
-planned for the future.)  The list of required and optional parameters
-is the same for all the current raid types.  The required parameters are
-positional, while the optional parameters are given as key/value pairs.
-The possible parameters are as follows:
- <chunk_size>           Chunk size in sectors.
- [[no]sync]             Force/Prevent RAID initialization
- [rebuild <idx>]        Rebuild the drive indicated by the index
- [daemon_sleep <ms>]    Time between bitmap daemon work to clear bits
- [min_recovery_rate <kB/sec/disk>]      Throttle RAID initialization
- [max_recovery_rate <kB/sec/disk>]      Throttle RAID initialization
- [max_write_behind <sectors>]           See '-write-behind=' (man mdadm)
- [stripe_cache <sectors>]               Stripe cache size for higher RAIDs
-
-Line 3 contains the list of devices that compose the array in
-metadata/data device pairs.  If the metadata is stored separately, a '-'
-is given for the metadata device position.  If a drive has failed or is
-missing at creation time, a '-' can be given for both the metadata and
-data drives for a given position.
-
-NB. Currently all metadata devices must be specified as '-'.
-
-Examples:
-# RAID4 - 4 data drives, 1 parity
+The target is named "raid" and it accepts the following parameters:
+
+  <raid_type> <#raid_params> <raid_params> \
+    <#raid_devs> <metadata_dev0> <dev0> [.. <metadata_devN> <devN>]
+
+<raid_type>:
+  raid1                RAID1 mirroring
+  raid4                RAID4 dedicated parity disk
+  raid5_la     RAID5 left asymmetric
+               - rotating parity 0 with data continuation
+  raid5_ra     RAID5 right asymmetric
+               - rotating parity N with data continuation
+  raid5_ls     RAID5 left symmetric
+               - rotating parity 0 with data restart
+  raid5_rs     RAID5 right symmetric
+               - rotating parity N with data restart
+  raid6_zr     RAID6 zero restart
+               - rotating parity zero (left-to-right) with data restart
+  raid6_nr     RAID6 N restart
+               - rotating parity N (right-to-left) with data restart
+  raid6_nc     RAID6 N continue
+               - rotating parity N (right-to-left) with data continuation
+
+  Refererence: Chapter 4 of
+  http://www.snia.org/sites/default/files/SNIA_DDF_Technical_Position_v2.0.pdf
+
+<#raid_params>: The number of parameters that follow.
+
+<raid_params> consists of
+    Mandatory parameters:
+        <chunk_size>: Chunk size in sectors.  This parameter is often known as
+                     "stripe size".  It is the only mandatory parameter and
+                     is placed first.
+
+    followed by optional parameters (in any order):
+       [sync|nosync]   Force or prevent RAID initialization.
+
+       [rebuild <idx>] Rebuild drive number idx (first drive is 0).
+
+       [daemon_sleep <ms>]
+               Interval between runs of the bitmap daemon that
+               clear bits.  A longer interval means less bitmap I/O but
+               resyncing after a failure is likely to take longer.
+
+       [min_recovery_rate <kB/sec/disk>]  Throttle RAID initialization
+       [max_recovery_rate <kB/sec/disk>]  Throttle RAID initialization
+       [write_mostly <idx>]               Drive index is write-mostly
+       [max_write_behind <sectors>]       See '-write-behind=' (man mdadm)
+       [stripe_cache <sectors>]           Stripe cache size (higher RAIDs only)
+       [region_size <sectors>]
+               The region_size multiplied by the number of regions is the
+               logical size of the array.  The bitmap records the device
+               synchronisation state for each region.
+
+<#raid_devs>: The number of devices composing the array.
+       Each device consists of two entries.  The first is the device
+       containing the metadata (if any); the second is the one containing the
+       data.
+
+       If a drive has failed or is missing at creation time, a '-' can be
+       given for both the metadata and data drives for a given position.
+
+
+Example tables
+--------------
+# RAID4 - 4 data drives, 1 parity (no metadata devices)
 # No metadata devices specified to hold superblock/bitmap info
 # Chunk size of 1MiB
 # (Lines separated for easy reading)
+
 0 1960893648 raid \
         raid4 1 2048 \
         5 - 8:17 - 8:33 - 8:49 - 8:65 - 8:81
 
-# RAID4 - 4 data drives, 1 parity (no metadata devices)
+# RAID4 - 4 data drives, 1 parity (with metadata devices)
 # Chunk size of 1MiB, force RAID initialization,
 #       min recovery rate at 20 kiB/sec/disk
+
 0 1960893648 raid \
-        raid4 4 2048 min_recovery_rate 20 sync\
-        5 - 8:17 - 8:33 - 8:49 - 8:65 - 8:81
+        raid4 4 2048 sync min_recovery_rate 20 \
+        5 8:17 8:18 8:33 8:34 8:49 8:50 8:65 8:66 8:81 8:82
 
-Performing a 'dmsetup table' should display the CTR table used to
-construct the mapping (with possible reordering of optional
-parameters).
+'dmsetup table' displays the table used to construct the mapping.
+The optional parameters are always printed in the order listed
+above with "sync" or "nosync" always output ahead of the other
+arguments, regardless of the order used when originally loading the table.
+Arguments that can be repeated are ordered by value.
 
-Performing a 'dmsetup status' will yield information on the state and
-health of the array.  The output is as follows:
+'dmsetup status' yields information on the state and health of the
+array.
+The output is as follows:
 1: <s> <l> raid \
 2:      <raid_type> <#devices> <1 health char for each dev> <resync_ratio>
 
-Line 1 is standard DM output.  Line 2 is best shown by example:
+Line 1 is the standard output produced by device-mapper.
+Line 2 is produced by the raid target, and best explained by example:
         0 1960893648 raid raid4 5 AAAAA 2/490221568
 Here we can see the RAID type is raid4, there are 5 devices - all of
 which are 'A'live, and the array is 2/490221568 complete with recovery.
+Faulty or missing devices are marked 'D'.  Devices that are out-of-sync
+are marked 'a'.
diff --git a/Documentation/devicetree/bindings/arm/arm-boards b/Documentation/devicetree/bindings/arm/arm-boards
new file mode 100644 (file)
index 0000000..91f2614
--- /dev/null
@@ -0,0 +1,20 @@
+ARM Versatile Application and Platform Baseboards
+-------------------------------------------------
+ARM's development hardware platform with connectors for customizable
+core tiles.  The hardware configuration of the Versatile boards is
+highly customizable.
+
+Required properties (in root node):
+       compatible = "arm,versatile-ab";  /* Application baseboard */
+       compatible = "arm,versatile-pb";  /* Platform baseboard */
+
+Interrupt controllers:
+- VIC required properties:
+       compatible = "arm,versatile-vic";
+       interrupt-controller;
+       #interrupt-cells = <1>;
+
+- SIC required properties:
+       compatible = "arm,versatile-sic";
+       interrupt-controller;
+       #interrupt-cells = <1>;
diff --git a/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt b/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt
new file mode 100644 (file)
index 0000000..d1e3f44
--- /dev/null
@@ -0,0 +1,17 @@
+* Freescale Smart Direct Memory Access (SDMA) Controller for i.MX
+
+Required properties:
+- compatible : Should be "fsl,<chip>-sdma"
+- reg : Should contain SDMA registers location and length
+- interrupts : Should contain SDMA interrupt
+- fsl,sdma-ram-script-name : Should contain the full path of SDMA RAM
+  scripts firmware
+
+Examples:
+
+sdma@83fb0000 {
+       compatible = "fsl,imx51-sdma", "fsl,imx35-sdma";
+       reg = <0x83fb0000 0x4000>;
+       interrupts = <6>;
+       fsl,sdma-ram-script-name = "sdma-imx51.bin";
+};
index 7190c99..5c2c021 100644 (file)
@@ -10,7 +10,7 @@ Optional properties:
 Each button (key) is represented as a sub-node of "gpio-keys":
 Subnode properties:
 
-       - gpios: OF devcie-tree gpio specificatin.
+       - gpios: OF device-tree gpio specification.
        - label: Descriptive name of the key.
        - linux,code: Keycode to emit.
 
diff --git a/Documentation/devicetree/bindings/i2c/arm-versatile.txt b/Documentation/devicetree/bindings/i2c/arm-versatile.txt
new file mode 100644 (file)
index 0000000..361d31c
--- /dev/null
@@ -0,0 +1,10 @@
+i2c Controller on ARM Versatile platform:
+
+Required properties:
+- compatible : Must be "arm,versatile-i2c";
+- reg
+- #address-cells = <1>;
+- #size-cells = <0>;
+
+Optional properties:
+- Child nodes conforming to i2c bus binding
diff --git a/Documentation/devicetree/bindings/input/fsl-mma8450.txt b/Documentation/devicetree/bindings/input/fsl-mma8450.txt
new file mode 100644 (file)
index 0000000..a00c94c
--- /dev/null
@@ -0,0 +1,11 @@
+* Freescale MMA8450 3-Axis Accelerometer
+
+Required properties:
+- compatible : "fsl,mma8450".
+
+Example:
+
+accelerometer: mma8450@1c {
+       compatible = "fsl,mma8450";
+       reg = <0x1c>;
+};
diff --git a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
new file mode 100644 (file)
index 0000000..ab22fe6
--- /dev/null
@@ -0,0 +1,34 @@
+* Freescale Enhanced Secure Digital Host Controller (eSDHC) for i.MX
+
+The Enhanced Secure Digital Host Controller on Freescale i.MX family
+provides an interface for MMC, SD, and SDIO types of memory cards.
+
+Required properties:
+- compatible : Should be "fsl,<chip>-esdhc"
+- reg : Should contain eSDHC registers location and length
+- interrupts : Should contain eSDHC interrupt
+
+Optional properties:
+- fsl,card-wired : Indicate the card is wired to host permanently
+- fsl,cd-internal : Indicate to use controller internal card detection
+- fsl,wp-internal : Indicate to use controller internal write protection
+- cd-gpios : Specify GPIOs for card detection
+- wp-gpios : Specify GPIOs for write protection
+
+Examples:
+
+esdhc@70004000 {
+       compatible = "fsl,imx51-esdhc";
+       reg = <0x70004000 0x4000>;
+       interrupts = <1>;
+       fsl,cd-internal;
+       fsl,wp-internal;
+};
+
+esdhc@70008000 {
+       compatible = "fsl,imx51-esdhc";
+       reg = <0x70008000 0x4000>;
+       interrupts = <2>;
+       cd-gpios = <&gpio0 6 0>; /* GPIO1_6 */
+       wp-gpios = <&gpio0 5 0>; /* GPIO1_5 */
+};
diff --git a/Documentation/devicetree/bindings/mtd/arm-versatile.txt b/Documentation/devicetree/bindings/mtd/arm-versatile.txt
new file mode 100644 (file)
index 0000000..476845d
--- /dev/null
@@ -0,0 +1,8 @@
+Flash device on ARM Versatile board
+
+Required properties:
+- compatible : must be "arm,versatile-flash";
+- bank-width : width in bytes of flash interface.
+
+Optional properties:
+- Subnode partition map from mtd flash binding
diff --git a/Documentation/devicetree/bindings/net/fsl-fec.txt b/Documentation/devicetree/bindings/net/fsl-fec.txt
new file mode 100644 (file)
index 0000000..de43951
--- /dev/null
@@ -0,0 +1,24 @@
+* Freescale Fast Ethernet Controller (FEC)
+
+Required properties:
+- compatible : Should be "fsl,<soc>-fec"
+- reg : Address and length of the register set for the device
+- interrupts : Should contain fec interrupt
+- phy-mode : String, operation mode of the PHY interface.
+  Supported values are: "mii", "gmii", "sgmii", "tbi", "rmii",
+  "rgmii", "rgmii-id", "rgmii-rxid", "rgmii-txid", "rtbi", "smii".
+- phy-reset-gpios : Should specify the gpio for phy reset
+
+Optional properties:
+- local-mac-address : 6 bytes, mac address
+
+Example:
+
+fec@83fec000 {
+       compatible = "fsl,imx51-fec", "fsl,imx27-fec";
+       reg = <0x83fec000 0x4000>;
+       interrupts = <87>;
+       phy-mode = "mii";
+       phy-reset-gpios = <&gpio1 14 0>; /* GPIO2_14 */
+       local-mac-address = [00 04 9F 01 1B B9];
+};
diff --git a/Documentation/devicetree/bindings/net/smsc-lan91c111.txt b/Documentation/devicetree/bindings/net/smsc-lan91c111.txt
new file mode 100644 (file)
index 0000000..953049b
--- /dev/null
@@ -0,0 +1,10 @@
+SMSC LAN91c111 Ethernet mac
+
+Required properties:
+- compatible = "smsc,lan91c111";
+- reg : physical address and size of registers
+- interrupts : interrupt connection
+
+Optional properties:
+- phy-device : phandle to Ethernet phy
+- local-mac-address : Ethernet mac address to use
diff --git a/Documentation/devicetree/bindings/tty/serial/fsl-imx-uart.txt b/Documentation/devicetree/bindings/tty/serial/fsl-imx-uart.txt
new file mode 100644 (file)
index 0000000..a9c0406
--- /dev/null
@@ -0,0 +1,19 @@
+* Freescale i.MX Universal Asynchronous Receiver/Transmitter (UART)
+
+Required properties:
+- compatible : Should be "fsl,<soc>-uart"
+- reg : Address and length of the register set for the device
+- interrupts : Should contain uart interrupt
+
+Optional properties:
+- fsl,uart-has-rtscts : Indicate the uart has rts and cts
+- fsl,irda-mode : Indicate the uart supports irda mode
+
+Example:
+
+uart@73fbc000 {
+       compatible = "fsl,imx51-uart", "fsl,imx21-uart";
+       reg = <0x73fbc000 0x4000>;
+       interrupts = <31>;
+       fsl,uart-has-rtscts;
+};
diff --git a/Documentation/devicetree/bindings/watchdog/fsl-imx-wdt.txt b/Documentation/devicetree/bindings/watchdog/fsl-imx-wdt.txt
new file mode 100644 (file)
index 0000000..2144af1
--- /dev/null
@@ -0,0 +1,14 @@
+* Freescale i.MX Watchdog Timer (WDT) Controller
+
+Required properties:
+- compatible : Should be "fsl,<soc>-wdt"
+- reg : Should contain WDT registers location and length
+- interrupts : Should contain WDT interrupt
+
+Examples:
+
+wdt@73f98000 {
+       compatible = "fsl,imx51-wdt", "fsl,imx21-wdt";
+       reg = <0x73f98000 0x4000>;
+       interrupts = <58>;
+};
diff --git a/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt b/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt
new file mode 100644 (file)
index 0000000..79ead82
--- /dev/null
@@ -0,0 +1,11 @@
+* Samsung's Watchdog Timer Controller
+
+The Samsung's Watchdog controller is used for resuming system operation
+after a preset amount of time during which the WDT reset event has not
+occured.
+
+Required properties:
+- compatible : should be "samsung,s3c2410-wdt"
+- reg : base physical address of the controller and length of memory mapped
+       region.
+- interrupts : interrupt number to the cpu.
index 5a0cb1e..94b7e0f 100644 (file)
@@ -10,87 +10,181 @@ NOTE: For DMA Engine usage in async_tx please see:
 Below is a guide to device driver writers on how to use the Slave-DMA API of the
 DMA Engine. This is applicable only for slave DMA usage only.
 
-The slave DMA usage consists of following steps
+The slave DMA usage consists of following steps:
 1. Allocate a DMA slave channel
 2. Set slave and controller specific parameters
 3. Get a descriptor for transaction
-4. Submit the transaction and wait for callback notification
+4. Submit the transaction
+5. Issue pending requests and wait for callback notification
 
 1. Allocate a DMA slave channel
-Channel allocation is slightly different in the slave DMA context, client
-drivers typically need a channel from a particular DMA controller only and even
-in some cases a specific channel is desired. To request a channel
-dma_request_channel() API is used.
-
-Interface:
-struct dma_chan *dma_request_channel(dma_cap_mask_t mask,
-               dma_filter_fn filter_fn,
-               void *filter_param);
-where dma_filter_fn is defined as:
-typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param);
-
-When the optional 'filter_fn' parameter is set to NULL dma_request_channel
-simply returns the first channel that satisfies the capability mask.  Otherwise,
-when the mask parameter is insufficient for specifying the necessary channel,
-the filter_fn routine can be used to disposition the available channels in the
-system. The filter_fn routine is called once for each free channel in the
-system.  Upon seeing a suitable channel filter_fn returns DMA_ACK which flags
-that channel to be the return value from dma_request_channel.  A channel
-allocated via this interface is exclusive to the caller, until
-dma_release_channel() is called.
+
+   Channel allocation is slightly different in the slave DMA context,
+   client drivers typically need a channel from a particular DMA
+   controller only and even in some cases a specific channel is desired.
+   To request a channel dma_request_channel() API is used.
+
+   Interface:
+       struct dma_chan *dma_request_channel(dma_cap_mask_t mask,
+                       dma_filter_fn filter_fn,
+                       void *filter_param);
+   where dma_filter_fn is defined as:
+       typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param);
+
+   The 'filter_fn' parameter is optional, but highly recommended for
+   slave and cyclic channels as they typically need to obtain a specific
+   DMA channel.
+
+   When the optional 'filter_fn' parameter is NULL, dma_request_channel()
+   simply returns the first channel that satisfies the capability mask.
+
+   Otherwise, the 'filter_fn' routine will be called once for each free
+   channel which has a capability in 'mask'.  'filter_fn' is expected to
+   return 'true' when the desired DMA channel is found.
+
+   A channel allocated via this interface is exclusive to the caller,
+   until dma_release_channel() is called.
 
 2. Set slave and controller specific parameters
-Next step is always to pass some specific information to the DMA driver. Most of
-the generic information which a slave DMA can use is in struct dma_slave_config.
-It allows the clients to specify DMA direction, DMA addresses, bus widths, DMA
-burst lengths etc. If some DMA controllers have more parameters to be sent then
-they should try to embed struct dma_slave_config in their controller specific
-structure. That gives flexibility to client to pass more parameters, if
-required.
-
-Interface:
-int dmaengine_slave_config(struct dma_chan *chan,
-                                         struct dma_slave_config *config)
+
+   Next step is always to pass some specific information to the DMA
+   driver.  Most of the generic information which a slave DMA can use
+   is in struct dma_slave_config.  This allows the clients to specify
+   DMA direction, DMA addresses, bus widths, DMA burst lengths etc
+   for the peripheral.
+
+   If some DMA controllers have more parameters to be sent then they
+   should try to embed struct dma_slave_config in their controller
+   specific structure. That gives flexibility to client to pass more
+   parameters, if required.
+
+   Interface:
+       int dmaengine_slave_config(struct dma_chan *chan,
+                                 struct dma_slave_config *config)
+
+   Please see the dma_slave_config structure definition in dmaengine.h
+   for a detailed explaination of the struct members.  Please note
+   that the 'direction' member will be going away as it duplicates the
+   direction given in the prepare call.
 
 3. Get a descriptor for transaction
-For slave usage the various modes of slave transfers supported by the
-DMA-engine are:
-slave_sg       - DMA a list of scatter gather buffers from/to a peripheral
-dma_cyclic     - Perform a cyclic DMA operation from/to a peripheral till the
+
+   For slave usage the various modes of slave transfers supported by the
+   DMA-engine are:
+
+   slave_sg    - DMA a list of scatter gather buffers from/to a peripheral
+   dma_cyclic  - Perform a cyclic DMA operation from/to a peripheral till the
                  operation is explicitly stopped.
-The non NULL return of this transfer API represents a "descriptor" for the given
-transaction.
-
-Interface:
-struct dma_async_tx_descriptor *(*chan->device->device_prep_dma_sg)(
-               struct dma_chan *chan,
-               struct scatterlist *dst_sg, unsigned int dst_nents,
-               struct scatterlist *src_sg, unsigned int src_nents,
+
+   A non-NULL return of this transfer API represents a "descriptor" for
+   the given transaction.
+
+   Interface:
+       struct dma_async_tx_descriptor *(*chan->device->device_prep_slave_sg)(
+               struct dma_chan *chan, struct scatterlist *sgl,
+               unsigned int sg_len, enum dma_data_direction direction,
                unsigned long flags);
-struct dma_async_tx_descriptor *(*chan->device->device_prep_dma_cyclic)(
+
+       struct dma_async_tx_descriptor *(*chan->device->device_prep_dma_cyclic)(
                struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
                size_t period_len, enum dma_data_direction direction);
 
-4. Submit the transaction and wait for callback notification
-To schedule the transaction to be scheduled by dma device, the "descriptor"
-returned in above (3) needs to be submitted.
-To tell the dma driver that a transaction is ready to be serviced, the
-descriptor->submit() callback needs to be invoked. This chains the descriptor to
-the pending queue.
-The transactions in the pending queue can be activated by calling the
-issue_pending API. If channel is idle then the first transaction in queue is
-started and subsequent ones queued up.
-On completion of the DMA operation the next in queue is submitted and a tasklet
-triggered. The tasklet would then call the client driver completion callback
-routine for notification, if set.
-Interface:
-void dma_async_issue_pending(struct dma_chan *chan);
-
-==============================================================================
-
-Additional usage notes for dma driver writers
-1/ Although DMA engine specifies that completion callback routines cannot submit
-any new operations, but typically for slave DMA subsequent transaction may not
-be available for submit prior to callback routine being called. This requirement
-is not a requirement for DMA-slave devices. But they should take care to drop
-the spin-lock they might be holding before calling the callback routine
+   The peripheral driver is expected to have mapped the scatterlist for
+   the DMA operation prior to calling device_prep_slave_sg, and must
+   keep the scatterlist mapped until the DMA operation has completed.
+   The scatterlist must be mapped using the DMA struct device.  So,
+   normal setup should look like this:
+
+       nr_sg = dma_map_sg(chan->device->dev, sgl, sg_len);
+       if (nr_sg == 0)
+               /* error */
+
+       desc = chan->device->device_prep_slave_sg(chan, sgl, nr_sg,
+                       direction, flags);
+
+   Once a descriptor has been obtained, the callback information can be
+   added and the descriptor must then be submitted.  Some DMA engine
+   drivers may hold a spinlock between a successful preparation and
+   submission so it is important that these two operations are closely
+   paired.
+
+   Note:
+       Although the async_tx API specifies that completion callback
+       routines cannot submit any new operations, this is not the
+       case for slave/cyclic DMA.
+
+       For slave DMA, the subsequent transaction may not be available
+       for submission prior to callback function being invoked, so
+       slave DMA callbacks are permitted to prepare and submit a new
+       transaction.
+
+       For cyclic DMA, a callback function may wish to terminate the
+       DMA via dmaengine_terminate_all().
+
+       Therefore, it is important that DMA engine drivers drop any
+       locks before calling the callback function which may cause a
+       deadlock.
+
+       Note that callbacks will always be invoked from the DMA
+       engines tasklet, never from interrupt context.
+
+4. Submit the transaction
+
+   Once the descriptor has been prepared and the callback information
+   added, it must be placed on the DMA engine drivers pending queue.
+
+   Interface:
+       dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc)
+
+   This returns a cookie can be used to check the progress of DMA engine
+   activity via other DMA engine calls not covered in this document.
+
+   dmaengine_submit() will not start the DMA operation, it merely adds
+   it to the pending queue.  For this, see step 5, dma_async_issue_pending.
+
+5. Issue pending DMA requests and wait for callback notification
+
+   The transactions in the pending queue can be activated by calling the
+   issue_pending API. If channel is idle then the first transaction in
+   queue is started and subsequent ones queued up.
+
+   On completion of each DMA operation, the next in queue is started and
+   a tasklet triggered. The tasklet will then call the client driver
+   completion callback routine for notification, if set.
+
+   Interface:
+       void dma_async_issue_pending(struct dma_chan *chan);
+
+Further APIs:
+
+1. int dmaengine_terminate_all(struct dma_chan *chan)
+
+   This causes all activity for the DMA channel to be stopped, and may
+   discard data in the DMA FIFO which hasn't been fully transferred.
+   No callback functions will be called for any incomplete transfers.
+
+2. int dmaengine_pause(struct dma_chan *chan)
+
+   This pauses activity on the DMA channel without data loss.
+
+3. int dmaengine_resume(struct dma_chan *chan)
+
+   Resume a previously paused DMA channel.  It is invalid to resume a
+   channel which is not currently paused.
+
+4. enum dma_status dma_async_is_tx_complete(struct dma_chan *chan,
+        dma_cookie_t cookie, dma_cookie_t *last, dma_cookie_t *used)
+
+   This can be used to check the status of the channel.  Please see
+   the documentation in include/linux/dmaengine.h for a more complete
+   description of this API.
+
+   This can be used in conjunction with dma_async_is_complete() and
+   the cookie returned from 'descriptor->submit()' to check for
+   completion of a specific DMA transaction.
+
+   Note:
+       Not all DMA engine drivers can return reliable information for
+       a running DMA channel.  It is recommended that DMA engine users
+       pause or stop (via dmaengine_terminate_all) the channel before
+       using this API.
old mode 100644 (file)
new mode 100755 (executable)
index 3348d31..c466f58
@@ -27,7 +27,7 @@ use IO::Handle;
                "or51211", "or51132_qam", "or51132_vsb", "bluebird",
                "opera1", "cx231xx", "cx18", "cx23885", "pvrusb2", "mpc718",
                "af9015", "ngene", "az6027", "lme2510_lg", "lme2510c_s7395",
-               "lme2510c_s7395_old");
+               "lme2510c_s7395_old", "drxk", "drxk_terratec_h5");
 
 # Check args
 syntax() if (scalar(@ARGV) != 1);
@@ -634,6 +634,37 @@ sub lme2510c_s7395_old {
     $outfile;
 }
 
+sub drxk {
+    my $url = "http://l4m-daten.de/files/";
+    my $zipfile = "DDTuner.zip";
+    my $hash = "f5a37b9a20a3534997997c0b1382a3e5";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+    my $drvfile = "DDTuner.sys";
+    my $fwfile = "drxk_a3.mc";
+
+    checkstandard();
+
+    wgetfile($zipfile, $url . $zipfile);
+    verify($zipfile, $hash);
+    unzip($zipfile, $tmpdir);
+    extract("$tmpdir/$drvfile", 0x14dd8, 15634, "$fwfile");
+
+    "$fwfile"
+}
+
+sub drxk_terratec_h5 {
+    my $url = "http://www.linuxtv.org/downloads/firmware/";
+    my $hash = "19000dada8e2741162ccc50cc91fa7f1";
+    my $fwfile = "dvb-usb-terratec-h5-drxk.fw";
+
+    checkstandard();
+
+    wgetfile($fwfile, $url . $fwfile);
+    verify($fwfile, $hash);
+
+    "$fwfile"
+}
+
 # ---------------------------------------------------------------
 # Utilities
 
index a0b58e2..860c29a 100644 (file)
@@ -199,18 +199,16 @@ to coerce it into behaving.
 
 To beat some sense out of the internal editor, do this:
 
-- Under account settings, composition and addressing, uncheck "Compose
-  messages in HTML format".
-
 - Edit your Thunderbird config settings so that it won't use format=flowed.
   Go to "edit->preferences->advanced->config editor" to bring up the
   thunderbird's registry editor, and set "mailnews.send_plaintext_flowed" to
   "false".
 
-- Enable "preformat" mode: Shft-click on the Write icon to bring up the HTML
-  composer, select "Preformat" from the drop-down box just under the subject
-  line, then close the message without saving.  (This setting also applies to
-  the text composer, but the only control for it is in the HTML composer.)
+- Disable HTML Format: Set "mail.identity.id1.compose_html" to "false".
+
+- Enable "preformat" mode: Set "editor.quotesPreformatted" to "true".
+
+- Enable UTF8: Set "prefs.converted-to-utf8" to "true".
 
 - Install the "toggle wordwrap" extension.  Download the file from:
     https://addons.mozilla.org/thunderbird/addon/2351/
index 7be15e4..82a5d25 100644 (file)
@@ -143,8 +143,7 @@ o provide a way to configure fault attributes
   failslab, fail_page_alloc, and fail_make_request use this way.
   Helper functions:
 
-       init_fault_attr_dentries(entries, attr, name);
-       void cleanup_fault_attr_dentries(entries);
+       fault_create_debugfs_attr(name, parent, attr);
 
 - module parameters
 
index dfd6a9f..c4a6e14 100644 (file)
@@ -296,15 +296,6 @@ Who:       Ravikiran Thirumalai <kiran@scalex86.org>
 
 ---------------------------
 
-What:  CONFIG_THERMAL_HWMON
-When:  January 2009
-Why:   This option was introduced just to allow older lm-sensors userspace
-       to keep working over the upgrade to 2.6.26. At the scheduled time of
-       removal fixed lm-sensors (2.x or 3.x) should be readily available.
-Who:   Rene Herman <rene.herman@gmail.com>
-
----------------------------
-
 What:  Code that is now under CONFIG_WIRELESS_EXT_SYSFS
        (in net/core/net-sysfs.c)
 When:  After the only user (hal) has seen a release with the patches
@@ -527,6 +518,41 @@ Who:       Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 
 ----------------------------
 
+What:  Support for driver specific ioctls in the pwc driver (everything
+       defined in media/pwc-ioctl.h)
+When:  3.3
+Why:   This stems from the v4l1 era, with v4l2 everything can be done with
+       standardized v4l2 API calls
+Who:   Hans de Goede <hdegoede@redhat.com>
+
+----------------------------
+
+What:  Driver specific sysfs API in the pwc driver
+When:  3.3
+Why:   Setting pan/tilt should be done with v4l2 controls, like with other
+       cams. The button is available as a standard input device
+Who:   Hans de Goede <hdegoede@redhat.com>
+
+----------------------------
+
+What:  Driver specific use of pixfmt.priv in the pwc driver
+When:  3.3
+Why:   The .priv field never was intended for this, setting a framerate is
+       support using the standardized S_PARM ioctl
+Who:   Hans de Goede <hdegoede@redhat.com>
+
+----------------------------
+
+What:  Software emulation of arbritary resolutions in the pwc driver
+When:  3.3
+Why:   The pwc driver claims to support any resolution between 160x120
+       and 640x480, but emulates this by simply drawing a black border
+       around the image. Userspace can draw its own black border if it
+       really wants one.
+Who:   Hans de Goede <hdegoede@redhat.com>
+
+----------------------------
+
 What:  For VIDIOC_S_FREQUENCY the type field must match the device node's type.
        If not, return -EINVAL.
 When:  3.2
@@ -555,3 +581,14 @@ Why:       This driver has been superseded by g_mass_storage.
 Who:   Alan Stern <stern@rowland.harvard.edu>
 
 ----------------------------
+
+What:   threeg and interface sysfs files in /sys/devices/platform/acer-wmi
+When:   2012
+Why:    In 3.0, we can now autodetect internal 3G device and already have
+       the threeg rfkill device. So, we plan to remove threeg sysfs support
+       for it's no longer necessary.
+
+       We also plan to remove interface sysfs file that exposed which ACPI-WMI
+       interface that was used by acer-wmi driver. It will replaced by
+       information log when acer-wmi initial.
+Who:    Lee, Chun-Yi <jlee@novell.com>
index 6e49c36..da45e6c 100644 (file)
@@ -27,7 +27,7 @@ His original code can still be found at:
 Does anyone know of a more current email address for Makoto? He doesn't
 respond to the address given above...
 
-Current maintainer: Sergey S. Kostyliov <rathamahata@php4.ru>
+This filesystem doesn't have a maintainer.
 
 WHAT IS THIS DRIVER?
 ==================
index ace200b..37c4d84 100644 (file)
@@ -106,13 +106,20 @@ separated by spaces:
       To use the first on-chip serial port at baud rate 115200, no parity, 8
       bits, and no flow control.
 
-  (*) root=/dev/<xxxx>
+  (*) root=<xxxx>
 
-      This specifies the device upon which the root filesystem resides. For
-      example:
+      This specifies the device upon which the root filesystem resides. It
+      may be specified by major and minor number, device path, or even
+      partition uuid, if supported.  For example:
 
        /dev/nfs        NFS root filesystem
        /dev/mtdblock3  Fourth RedBoot partition on the System Flash
+       PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF/PARTNROFF=1
+               first partition after the partition with the given UUID
+       253:0           Device with major 253 and minor 0
+
+      Authoritative information can be found in
+      "Documentation/kernel-parameters.txt".
 
   (*) rw
 
index 6a3a647..097b3cc 100644 (file)
@@ -43,8 +43,8 @@ Documentation/hwmon/pmbus for details.
 Sysfs entries
 -------------
 
-The following attributes are supported. Limits are read-write; all other
-attributes are read-only.
+The following attributes are supported. Limits are read-write, history reset
+attributes are write-only, all other attributes are read-only.
 
 in1_label              "vin1" or "vout1" depending on chip variant and
                        configuration.
@@ -53,8 +53,12 @@ in1_min                      Minumum Voltage. From VOUT_UV_WARN_LIMIT register.
 in1_max                        Maximum voltage. From VOUT_OV_WARN_LIMIT register.
 in1_min_alarm          Voltage low alarm. From VOLTAGE_UV_WARNING status.
 in1_max_alarm          Voltage high alarm. From VOLTAGE_OV_WARNING status.
+in1_highest            Historical maximum voltage.
+in1_reset_history      Write any value to reset history.
 
 curr1_label            "iout1"
 curr1_input            Measured current. From READ_IOUT register.
 curr1_max              Maximum current. From IOUT_OC_WARN_LIMIT register.
 curr1_max_alarm                Current high alarm. From IOUT_OC_WARN_LIMIT register.
+curr1_highest          Historical maximum current.
+curr1_reset_history    Write any value to reset history.
index f85e913..fa8776a 100644 (file)
@@ -35,6 +35,13 @@ the Out-Of-Spec bit. Following table summarizes the exported sysfs files:
 All Sysfs entries are named with their core_id (represented here by 'X').
 tempX_input     - Core temperature (in millidegrees Celsius).
 tempX_max       - All cooling devices should be turned on (on Core2).
+                  Initialized with IA32_THERM_INTERRUPT. When the CPU
+                  temperature reaches this temperature, an interrupt is
+                  generated and tempX_max_alarm is set.
+tempX_max_hyst   - If the CPU temperature falls below than temperature,
+                  an interrupt is generated and tempX_max_alarm is reset.
+tempX_max_alarm  - Set if the temperature reaches or exceeds tempX_max.
+                  Reset if the temperature drops to or below tempX_max_hyst.
 tempX_crit      - Maximum junction temperature (in millidegrees Celsius).
 tempX_crit_alarm - Set when Out-of-spec bit is set, never clears.
                   Correct CPU operation is no longer guaranteed.
diff --git a/Documentation/hwmon/lm25066 b/Documentation/hwmon/lm25066
new file mode 100644 (file)
index 0000000..a21db81
--- /dev/null
@@ -0,0 +1,90 @@
+Kernel driver max8688
+=====================
+
+Supported chips:
+  * National Semiconductor LM25066
+    Prefix: 'lm25066'
+    Addresses scanned: -
+    Datasheets:
+       http://www.national.com/pf/LM/LM25066.html
+       http://www.national.com/pf/LM/LM25066A.html
+  * National Semiconductor LM5064
+    Prefix: 'lm5064'
+    Addresses scanned: -
+    Datasheet:
+       http://www.national.com/pf/LM/LM5064.html
+  * National Semiconductor LM5066
+    Prefix: 'lm5066'
+    Addresses scanned: -
+    Datasheet:
+       http://www.national.com/pf/LM/LM5066.html
+
+Author: Guenter Roeck <guenter.roeck@ericsson.com>
+
+
+Description
+-----------
+
+This driver supports hardware montoring for National Semiconductor LM25066,
+LM5064, and LM5064 Power Management, Monitoring, Control, and Protection ICs.
+
+The driver is a client driver to the core PMBus driver. Please see
+Documentation/hwmon/pmbus for details on PMBus client drivers.
+
+
+Usage Notes
+-----------
+
+This driver does not auto-detect devices. You will have to instantiate the
+devices explicitly. Please see Documentation/i2c/instantiating-devices for
+details.
+
+
+Platform data support
+---------------------
+
+The driver supports standard PMBus driver platform data.
+
+
+Sysfs entries
+-------------
+
+The following attributes are supported. Limits are read-write; all other
+attributes are read-only.
+
+in1_label              "vin"
+in1_input              Measured input voltage.
+in1_average            Average measured input voltage.
+in1_min                        Minimum input voltage.
+in1_max                        Maximum input voltage.
+in1_min_alarm          Input voltage low alarm.
+in1_max_alarm          Input voltage high alarm.
+
+in2_label              "vout1"
+in2_input              Measured output voltage.
+in2_average            Average measured output voltage.
+in2_min                        Minimum output voltage.
+in2_min_alarm          Output voltage low alarm.
+
+in3_label              "vout2"
+in3_input              Measured voltage on vaux pin
+
+curr1_label            "iin"
+curr1_input            Measured input current.
+curr1_average          Average measured input current.
+curr1_max              Maximum input current.
+curr1_max_alarm                Input current high alarm.
+
+power1_label           "pin"
+power1_input           Measured input power.
+power1_average         Average measured input power.
+power1_max             Maximum input power limit.
+power1_alarm           Input power alarm
+power1_input_highest   Historical maximum power.
+power1_reset_history   Write any value to reset maximum power history.
+
+temp1_input            Measured temperature.
+temp1_max              Maximum temperature.
+temp1_crit             Critical high temperature.
+temp1_max_alarm                Chip temperature high alarm.
+temp1_crit_alarm       Chip temperature critical high alarm.
index f3efd18..9cd14cf 100644 (file)
@@ -113,7 +113,11 @@ Supported chips:
     Prefix: 'w83l771'
     Addresses scanned: I2C 0x4c
     Datasheet: Not publicly available, can be requested from Nuvoton
-
+  * Philips/NXP SA56004X
+    Prefix: 'sa56004'
+    Addresses scanned: I2C 0x48 through 0x4F
+    Datasheet: Publicly available at NXP website
+               http://ics.nxp.com/products/interface/datasheet/sa56004x.pdf
 
 Author: Jean Delvare <khali@linux-fr.org>
 
@@ -193,6 +197,9 @@ W83L771AWG/ASG
   * The AWG and ASG variants only differ in package format.
   * Diode ideality factor configuration (remote sensor) at 0xE3
 
+SA56004X:
+  * Better local resolution
+
 All temperature values are given in degrees Celsius. Resolution
 is 1.0 degree for the local temperature, 0.125 degree for the remote
 temperature, except for the MAX6657, MAX6658 and MAX6659 which have a
diff --git a/Documentation/hwmon/lm95245 b/Documentation/hwmon/lm95245
new file mode 100644 (file)
index 0000000..cbd8aea
--- /dev/null
@@ -0,0 +1,33 @@
+Kernel driver lm95245
+==================
+
+Supported chips:
+  * National Semiconductor LM95245
+    Addresses scanned: I2C 0x18, 0x19, 0x29, 0x4c, 0x4d
+    Datasheet: Publicly available at the National Semiconductor website
+               http://www.national.com/mpf/LM/LM95245.html
+
+
+Author: Alexander Stein <alexander.stein@systec-electronic.com>
+
+Description
+-----------
+
+The LM95245 is an 11-bit digital temperature sensor with a 2-wire System
+Management Bus (SMBus) interface and TruTherm technology that can monitor
+the temperature of a remote diode as well as its own temperature.
+The LM95245 can be used to very accurately monitor the temperature of
+external devices such as microprocessors.
+
+All temperature values are given in millidegrees Celsius. Local temperature
+is given within a range of -127 to +127.875 degrees. Remote temperatures are
+given within a range of -127 to +255 degrees. Resolution depends on
+temperature input and range.
+
+Each sensor has its own critical limit, but the hysteresis is common to all
+two channels.
+
+The lm95245 driver can change its update interval to a fixed set of values.
+It will round up to the next selectable interval. See the datasheet for exact
+values. Reading sensor values more often will do no harm, but will return
+'old' values.
index 4172899..f6e8bcb 100644 (file)
@@ -50,6 +50,8 @@ in[1-4]_min_alarm     Voltage low alarm. From VOLTAGE_UV_WARNING status.
 in[1-4]_max_alarm      Voltage high alarm. From VOLTAGE_OV_WARNING status.
 in[1-4]_lcrit_alarm    Voltage critical low alarm. From VOLTAGE_UV_FAULT status.
 in[1-4]_crit_alarm     Voltage critical high alarm. From VOLTAGE_OV_FAULT status.
+in[1-4]_highest                Historical maximum voltage.
+in[1-4]_reset_history  Write any value to reset history.
 
 temp1_input            Measured temperature. From READ_TEMPERATURE_1 register.
 temp1_max              Maximum temperature. From OT_WARN_LIMIT register.
@@ -60,3 +62,5 @@ temp1_max_alarm               Chip temperature high alarm. Set by comparing
 temp1_crit_alarm       Chip temperature critical high alarm. Set by comparing
                        READ_TEMPERATURE_1 with OT_FAULT_LIMIT if TEMP_OT_FAULT
                        status is set.
+temp1_highest          Historical maximum temperature.
+temp1_reset_history    Write any value to reset history.
diff --git a/Documentation/hwmon/max1668 b/Documentation/hwmon/max1668
new file mode 100644 (file)
index 0000000..0616ed9
--- /dev/null
@@ -0,0 +1,60 @@
+Kernel driver max1668
+=====================
+
+Supported chips:
+  * Maxim MAX1668, MAX1805 and MAX1989
+    Prefix: 'max1668'
+    Addresses scanned: I2C 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e
+    Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX1668-MAX1989.pdf
+
+Author:
+    David George <david.george@ska.ac.za>
+
+Description
+-----------
+
+This driver implements support for the Maxim MAX1668, MAX1805 and MAX1989
+chips.
+
+The three devices are very similar, but the MAX1805 has a reduced feature
+set; only two remote temperature inputs vs the four avaible on the other
+two ICs.
+
+The driver is able to distinguish between the devices and creates sysfs
+entries as follows:
+
+MAX1805, MAX1668 and MAX1989:
+
+temp1_input     ro local (ambient) temperature
+temp1_max       rw local temperature maximum threshold for alarm
+temp1_max_alarm ro local temperature maximum threshold alarm
+temp1_min       rw local temperature minimum threshold for alarm
+temp1_min_alarm ro local temperature minimum threshold alarm
+temp2_input     ro remote temperature 1
+temp2_max       rw remote temperature 1 maximum threshold for alarm
+temp2_max_alarm ro remote temperature 1 maximum threshold alarm
+temp2_min       rw remote temperature 1 minimum threshold for alarm
+temp2_min_alarm ro remote temperature 1 minimum threshold alarm
+temp3_input     ro remote temperature 2
+temp3_max       rw remote temperature 2 maximum threshold for alarm
+temp3_max_alarm ro remote temperature 2 maximum threshold alarm
+temp3_min       rw remote temperature 2 minimum threshold for alarm
+temp3_min_alarm ro remote temperature 2 minimum threshold alarm
+
+MAX1668 and MAX1989 only:
+temp4_input     ro remote temperature 3
+temp4_max       rw remote temperature 3 maximum threshold for alarm
+temp4_max_alarm ro remote temperature 3 maximum threshold alarm
+temp4_min       rw remote temperature 3 minimum threshold for alarm
+temp4_min_alarm ro remote temperature 3 minimum threshold alarm
+temp5_input     ro remote temperature 4
+temp5_max       rw remote temperature 4 maximum threshold for alarm
+temp5_max_alarm ro remote temperature 4 maximum threshold alarm
+temp5_min       rw remote temperature 4 minimum threshold for alarm
+temp5_min_alarm ro remote temperature 4 minimum threshold alarm
+
+Module Parameters
+-----------------
+
+* read_only: int
+  Set to non-zero if you wish to prevent write access to alarm thresholds.
index 6c525dd..8ab5153 100644 (file)
@@ -56,6 +56,8 @@ in[1-6]_min_alarm     Voltage low alarm. From VOLTAGE_UV_WARNING status.
 in[1-6]_max_alarm      Voltage high alarm. From VOLTAGE_OV_WARNING status.
 in[1-6]_lcrit_alarm    Voltage critical low alarm. From VOLTAGE_UV_FAULT status.
 in[1-6]_crit_alarm     Voltage critical high alarm. From VOLTAGE_OV_FAULT status.
+in[1-6]_highest                Historical maximum voltage.
+in[1-6]_reset_history  Write any value to reset history.
 
 curr[1-6]_label                "iout[1-6]".
 curr[1-6]_input                Measured current. From READ_IOUT register.
@@ -63,6 +65,8 @@ curr[1-6]_max         Maximum current. From IOUT_OC_WARN_LIMIT register.
 curr[1-6]_crit         Critical maximum current. From IOUT_OC_FAULT_LIMIT register.
 curr[1-6]_max_alarm    Current high alarm. From IOUT_OC_WARNING status.
 curr[1-6]_crit_alarm   Current critical high alarm. From IOUT_OC_FAULT status.
+curr[1-6]_highest      Historical maximum current.
+curr[1-6]_reset_history        Write any value to reset history.
 
                        in6 and curr6 attributes only exist for MAX34440.
 
@@ -75,5 +79,7 @@ temp[1-8]_max         Maximum temperature. From OT_WARN_LIMIT register.
 temp[1-8]_crit         Critical high temperature. From OT_FAULT_LIMIT register.
 temp[1-8]_max_alarm    Temperature high alarm.
 temp[1-8]_crit_alarm   Temperature critical high alarm.
+temp[1-8]_highest      Historical maximum temperature.
+temp[1-8]_reset_history        Write any value to reset history.
 
                        temp7 and temp8 attributes only exist for MAX34440.
index 0ddd3a4..71ed10a 100644 (file)
@@ -50,6 +50,8 @@ in1_min_alarm         Voltage low alarm. From VOLTAGE_UV_WARNING status.
 in1_max_alarm          Voltage high alarm. From VOLTAGE_OV_WARNING status.
 in1_lcrit_alarm                Voltage critical low alarm. From VOLTAGE_UV_FAULT status.
 in1_crit_alarm         Voltage critical high alarm. From VOLTAGE_OV_FAULT status.
+in1_highest            Historical maximum voltage.
+in1_reset_history      Write any value to reset history.
 
 curr1_label            "iout1"
 curr1_input            Measured current. From READ_IOUT register.
@@ -57,6 +59,8 @@ curr1_max             Maximum current. From IOUT_OC_WARN_LIMIT register.
 curr1_crit             Critical maximum current. From IOUT_OC_FAULT_LIMIT register.
 curr1_max_alarm                Current high alarm. From IOUT_OC_WARN_LIMIT register.
 curr1_crit_alarm       Current critical high alarm. From IOUT_OC_FAULT status.
+curr1_highest          Historical maximum current.
+curr1_reset_history    Write any value to reset history.
 
 temp1_input            Measured temperature. From READ_TEMPERATURE_1 register.
 temp1_max              Maximum temperature. From OT_WARN_LIMIT register.
@@ -67,3 +71,5 @@ temp1_max_alarm               Chip temperature high alarm. Set by comparing
 temp1_crit_alarm       Chip temperature critical high alarm. Set by comparing
                        READ_TEMPERATURE_1 with OT_FAULT_LIMIT if TEMP_OT_FAULT
                        status is set.
+temp1_highest          Historical maximum temperature.
+temp1_reset_history    Write any value to reset history.
diff --git a/Documentation/hwmon/ntc_thermistor b/Documentation/hwmon/ntc_thermistor
new file mode 100644 (file)
index 0000000..3bfda94
--- /dev/null
@@ -0,0 +1,93 @@
+Kernel driver ntc_thermistor
+=================
+
+Supported thermistors:
+* Murata NTC Thermistors NCP15WB473, NCP18WB473, NCP21WB473, NCP03WB473, NCP15WL333
+  Prefixes: 'ncp15wb473', 'ncp18wb473', 'ncp21wb473', 'ncp03wb473', 'ncp15wl333'
+  Datasheet: Publicly available at Murata
+
+Other NTC thermistors can be supported simply by adding compensation
+tables; e.g., NCP15WL333 support is added by the table ncpXXwl333.
+
+Authors:
+       MyungJoo Ham <myungjoo.ham@samsung.com>
+
+Description
+-----------
+
+The NTC thermistor is a simple thermistor that requires users to provide the
+resistance and lookup the corresponding compensation table to get the
+temperature input.
+
+The NTC driver provides lookup tables with a linear approximation function
+and four circuit models with an option not to use any of the four models.
+
+The four circuit models provided are:
+
+       $: resister, [TH]: the thermistor
+
+ 1. connect = NTC_CONNECTED_POSITIVE, pullup_ohm > 0
+
+   [pullup_uV]
+       |    |
+      [TH]  $ (pullup_ohm)
+       |    |
+       +----+-----------------------[read_uV]
+       |
+       $ (pulldown_ohm)
+       |
+      --- (ground)
+
+ 2. connect = NTC_CONNECTED_POSITIVE, pullup_ohm = 0 (not-connected)
+
+   [pullup_uV]
+       |
+      [TH]
+       |
+       +----------------------------[read_uV]
+       |
+       $ (pulldown_ohm)
+       |
+      --- (ground)
+
+ 3. connect = NTC_CONNECTED_GROUND, pulldown_ohm > 0
+
+   [pullup_uV]
+       |
+       $ (pullup_ohm)
+       |
+       +----+-----------------------[read_uV]
+       |    |
+      [TH]  $ (pulldown_ohm)
+       |    |
+      -------- (ground)
+
+ 4. connect = NTC_CONNECTED_GROUND, pulldown_ohm = 0 (not-connected)
+
+   [pullup_uV]
+       |
+       $ (pullup_ohm)
+       |
+       +----------------------------[read_uV]
+       |
+      [TH]
+       |
+      --- (ground)
+
+When one of the four circuit models is used, read_uV, pullup_uV, pullup_ohm,
+pulldown_ohm, and connect should be provided. When none of the four models
+are suitable or the user can get the resistance directly, the user should
+provide read_ohm and _not_ provide the others.
+
+Sysfs Interface
+---------------
+name           the mandatory global attribute, the thermistor name.
+
+temp1_type     always 4 (thermistor)
+               RO
+
+temp1_input    measure the temperature and provide the measured value.
+               (reading this file initiates the reading procedure.)
+               RO
+
+Note that each NTC thermistor has only _one_ thermistor; thus, only temp1 exists.
index 5e462fc..c36c1c1 100644 (file)
@@ -13,6 +13,13 @@ Supported chips:
     Prefix: 'ltc2978'
     Addresses scanned: -
     Datasheet: http://cds.linear.com/docs/Datasheet/2978fa.pdf
+  * ON Semiconductor ADP4000, NCP4200, NCP4208
+    Prefixes: 'adp4000', 'ncp4200', 'ncp4208'
+    Addresses scanned: -
+    Datasheets:
+       http://www.onsemi.com/pub_link/Collateral/ADP4000-D.PDF
+       http://www.onsemi.com/pub_link/Collateral/NCP4200-D.PDF
+       http://www.onsemi.com/pub_link/Collateral/JUNE%202009-%20REV.%200.PDF
   * Generic PMBus devices
     Prefix: 'pmbus'
     Addresses scanned: -
index 8f63c24..a4aa8f6 100644 (file)
@@ -139,6 +139,29 @@ in[0-*]_input      Voltage input value.
                thumb: drivers should report the voltage values at the
                "pins" of the chip.
 
+in[0-*]_average
+               Average voltage
+               Unit: millivolt
+               RO
+
+in[0-*]_lowest
+               Historical minimum voltage
+               Unit: millivolt
+               RO
+
+in[0-*]_highest
+               Historical maximum voltage
+               Unit: millivolt
+               RO
+
+in[0-*]_reset_history
+               Reset inX_lowest and inX_highest
+               WO
+
+in_reset_history
+               Reset inX_lowest and inX_highest for all sensors
+               WO
+
 in[0-*]_label  Suggested voltage channel label.
                Text string
                Should only be created if the driver has hints about what
@@ -407,6 +430,29 @@ curr[1-*]_input    Current input value
                Unit: milliampere
                RO
 
+curr[1-*]_average
+               Average current use
+               Unit: milliampere
+               RO
+
+curr[1-*]_lowest
+               Historical minimum current
+               Unit: milliampere
+               RO
+
+curr[1-*]_highest
+               Historical maximum current
+               Unit: milliampere
+               RO
+
+curr[1-*]_reset_history
+               Reset currX_lowest and currX_highest
+               WO
+
+curr_reset_history
+               Reset currX_lowest and currX_highest for all sensors
+               WO
+
 Also see the Alarms section for status flags associated with currents.
 
 *********
index 72ba8d5..845a191 100644 (file)
@@ -292,6 +292,7 @@ Code  Seq#(hex)     Include File            Comments
                                        <mailto:buk@buks.ipn.de>
 0xA0   all     linux/sdp/sdp.h         Industrial Device Project
                                        <mailto:kenji@bitgate.com>
+0xA2   00-0F   arch/tile/include/asm/hardwall.h
 0xA3   80-8F   Port ACL                in development:
                                        <mailto:tlewis@mindspring.com>
 0xA3   90-9F   linux/dtlk.h
index 9a86746..0e0734b 100644 (file)
        (including this document itself) have been moved there, and might
        be more up to date than the web version.
 
-     * Name: "Linux Source Driver"
-       URL: http://lsd.linux.cz
-       Keywords: Browsing source code.
-       Description: "Linux Source Driver (LSD) is an application, which
-       can make browsing source codes of Linux kernel easier than you can
-       imagine. You can select between multiple versions of kernel (e.g.
-       0.01, 1.0.0, 2.0.33, 2.0.34pre13, 2.0.0, 2.1.101 etc.). With LSD
-       you can search Linux kernel (fulltext, macros, types, functions
-       and variables) and LSD can generate patches for you on the fly
-       (files, directories or kernel)".
-
      * Name: "Linux Kernel Source Reference"
        Author: Thomas Graichen.
        URL: http://marc.info/?l=linux-kernel&m=96446640102205&w=4
index 4ca9389..614d038 100644 (file)
@@ -40,6 +40,7 @@ parameter is applicable:
        ALSA    ALSA sound support is enabled.
        APIC    APIC support is enabled.
        APM     Advanced Power Management support is enabled.
+       ARM     ARM architecture is enabled.
        AVR32   AVR32 architecture is enabled.
        AX25    Appropriate AX.25 support is enabled.
        BLACKFIN Blackfin architecture is enabled.
@@ -49,6 +50,7 @@ parameter is applicable:
        EFI     EFI Partitioning (GPT) is enabled
        EIDE    EIDE/ATAPI support is enabled.
        FB      The frame buffer device is enabled.
+       FTRACE  Function tracing enabled.
        GCOV    GCOV profiling is enabled.
        HW      Appropriate hardware is enabled.
        IA-64   IA-64 architecture is enabled.
@@ -69,6 +71,7 @@ parameter is applicable:
                        Documentation/m68k/kernel-options.txt.
        MCA     MCA bus support is enabled.
        MDA     MDA console support is enabled.
+       MIPS    MIPS architecture is enabled.
        MOUSE   Appropriate mouse support is enabled.
        MSI     Message Signaled Interrupts (PCI).
        MTD     MTD (Memory Technology Device) support is enabled.
@@ -100,7 +103,6 @@ parameter is applicable:
        SPARC   Sparc architecture is enabled.
        SWSUSP  Software suspend (hibernation) is enabled.
        SUSPEND System suspend states are enabled.
-       FTRACE  Function tracing enabled.
        TPM     TPM drivers are enabled.
        TS      Appropriate touchscreen support is enabled.
        UMS     USB Mass Storage support is enabled.
@@ -115,7 +117,7 @@ parameter is applicable:
        X86-64  X86-64 architecture is enabled.
                        More X86-64 boot options can be found in
                        Documentation/x86/x86_64/boot-options.txt .
-       X86     Either 32bit or 64bit x86 (same as X86-32+X86-64)
+       X86     Either 32-bit or 64-bit x86 (same as X86-32+X86-64)
        XEN     Xen support is enabled
 
 In addition, the following text indicates that the option:
@@ -163,6 +165,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 
                        See also Documentation/power/pm.txt, pci=noacpi
 
+       acpi_rsdp=      [ACPI,EFI,KEXEC]
+                       Pass the RSDP address to the kernel, mostly used
+                       on machines running EFI runtime service to boot the
+                       second kernel for kdump.
+
        acpi_apic_instance=     [ACPI, IOAPIC]
                        Format: <int>
                        2: use 2nd APIC table, if available
@@ -371,7 +378,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
        atkbd.softrepeat= [HW]
                        Use software keyboard repeat
 
-       autotest        [IA64]
+       autotest        [IA-64]
 
        baycom_epp=     [HW,AX25]
                        Format: <io>,<mode>
@@ -546,6 +553,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        /proc/<pid>/coredump_filter.
                        See also Documentation/filesystems/proc.txt.
 
+       cpuidle.off=1   [CPU_IDLE]
+                       disable the cpuidle sub-system
+
        cpcihp_generic= [HW,PCI] Generic port I/O CompactPCI driver
                        Format:
                        <first_slot>,<last_slot>,<port>,<enum_bit>[,<debug>]
@@ -673,8 +683,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                uart[8250],mmio32,<addr>[,options]
                        Start an early, polled-mode console on the 8250/16550
                        UART at the specified I/O port or MMIO address.
-                       MMIO inter-register address stride is either 8bit (mmio)
-                        or 32bit (mmio32).
+                       MMIO inter-register address stride is either 8-bit
+                       (mmio) or 32-bit (mmio32).
                        The options are the same as for ttyS, above.
 
        earlyprintk=    [X86,SH,BLACKFIN]
@@ -717,7 +727,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        See Documentation/block/as-iosched.txt and
                        Documentation/block/deadline-iosched.txt for details.
 
-       elfcorehdr=     [IA64,PPC,SH,X86]
+       elfcorehdr=     [IA-64,PPC,SH,X86]
                        Specifies physical address of start of kernel core
                        image elf header. Generally kexec loader will
                        pass this option to capture kernel.
@@ -783,7 +793,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        tracer at boot up. function-list is a comma separated
                        list of functions. This list can be changed at run
                        time by the set_ftrace_filter file in the debugfs
-                       tracing directory. 
+                       tracing directory.
 
        ftrace_notrace=[function-list]
                        [FTRACE] Do not trace the functions specified in
@@ -821,7 +831,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 
        hashdist=       [KNL,NUMA] Large hashes allocated during boot
                        are distributed across NUMA nodes.  Defaults on
-                       for 64bit NUMA, off otherwise.
+                       for 64-bit NUMA, off otherwise.
                        Format: 0 | 1 (for off | on)
 
        hcl=            [IA-64] SGI's Hardware Graph compatibility layer
@@ -990,10 +1000,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        DMA.
                forcedac [x86_64]
                        With this option iommu will not optimize to look
-                       for io virtual address below 32 bit forcing dual
+                       for io virtual address below 32-bit forcing dual
                        address cycle on pci bus for cards supporting greater
-                       than 32 bit addressing. The default is to look
-                       for translation below 32 bit and if not available
+                       than 32-bit addressing. The default is to look
+                       for translation below 32-bit and if not available
                        then look in the higher range.
                strict [Default Off]
                        With this option on every unmap_single operation will
@@ -1009,7 +1019,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        off     disable Interrupt Remapping
                        nosid   disable Source ID checking
 
-       inttest=        [IA64]
+       inttest=        [IA-64]
 
        iomem=          Disable strict checking of access to MMIO memory
                strict  regions from userspace.
@@ -1026,7 +1036,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                nomerge
                forcesac
                soft
-               pt      [x86, IA64]
+               pt      [x86, IA-64]
 
        io7=            [HW] IO7 for Marvel based alpha systems
                        See comment before marvel_specify_io7 in
@@ -1157,7 +1167,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 
        kvm-amd.npt=    [KVM,AMD] Disable nested paging (virtualized MMU)
                        for all guests.
-                       Default is 1 (enabled) if in 64bit or 32bit-PAE mode
+                       Default is 1 (enabled) if in 64-bit or 32-bit PAE mode.
 
        kvm-intel.ept=  [KVM,Intel] Disable extended page tables
                        (virtualized MMU) support on capable Intel chips.
@@ -1194,10 +1204,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        libata.dma=0      Disable all PATA and SATA DMA
                        libata.dma=1      PATA and SATA Disk DMA only
                        libata.dma=2      ATAPI (CDROM) DMA only
-                       libata.dma=4      Compact Flash DMA only 
+                       libata.dma=4      Compact Flash DMA only
                        Combinations also work, so libata.dma=3 enables DMA
                        for disks and CDROMs, but not CFs.
-       
+
        libata.ignore_hpa=      [LIBATA] Ignore HPA limit
                        libata.ignore_hpa=0       keep BIOS limits (default)
                        libata.ignore_hpa=1       ignore limits, using full disk
@@ -1323,7 +1333,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
        ltpc=           [NET]
                        Format: <io>,<irq>,<dma>
 
-       machvec=        [IA64] Force the use of a particular machine-vector
+       machvec=        [IA-64] Force the use of a particular machine-vector
                        (machvec) in a generic kernel.
                        Example: machvec=hpzx1_swiotlb
 
@@ -1340,9 +1350,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        it is equivalent to "nosmp", which also disables
                        the IO APIC.
 
-       max_loop=       [LOOP] Maximum number of loopback devices that can
-                       be mounted
-                       Format: <1-256>
+       max_loop=       [LOOP] The number of loop block devices that get
+       (loop.max_loop) unconditionally pre-created at init time. The default
+                       number is configured by BLK_DEV_LOOP_MIN_COUNT. Instead
+                       of statically allocating a predefined number, loop
+                       devices can be requested on-demand with the
+                       /dev/loop-control interface.
 
        mcatest=        [IA-64]
 
@@ -1726,7 +1739,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 
        nointroute      [IA-64]
 
-       nojitter        [IA64] Disables jitter checking for ITC timers.
+       nojitter        [IA-64] Disables jitter checking for ITC timers.
 
        no-kvmclock     [X86,KVM] Disable paravirtualized KVM clock driver
 
@@ -1792,7 +1805,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 
        nox2apic        [X86-64,APIC] Do not enable x2APIC mode.
 
-       nptcg=          [IA64] Override max number of concurrent global TLB
+       nptcg=          [IA-64] Override max number of concurrent global TLB
                        purges which is reported from either PAL_VM_SUMMARY or
                        SAL PALO.
 
@@ -2069,7 +2082,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        Format: { parport<nr> | timid | 0 }
                        See also Documentation/parport.txt.
 
-       pmtmr=          [X86] Manual setup of pmtmr I/O Port. 
+       pmtmr=          [X86] Manual setup of pmtmr I/O Port.
                        Override pmtimer IOPort with a hex value.
                        e.g. pmtmr=0x508
 
@@ -2153,6 +2166,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        [HW,MOUSE] Controls Logitech smartscroll autorepeat.
                        0 = disabled, 1 = enabled (default).
 
+       pstore.backend= Specify the name of the pstore backend to use
+
        pt.             [PARIDE]
                        See Documentation/blockdev/paride.txt.
 
@@ -2238,6 +2253,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
        ro              [KNL] Mount root device read-only on boot
 
        root=           [KNL] Root filesystem
+                       See name_to_dev_t comment in init/do_mounts.c.
 
        rootdelay=      [KNL] Delay (in seconds) to pause before attempting to
                        mount the root filesystem
@@ -2624,6 +2640,16 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                                        medium is write-protected).
                        Example: quirks=0419:aaf5:rl,0421:0433:rc
 
+       user_debug=     [KNL,ARM]
+                       Format: <int>
+                       See arch/arm/Kconfig.debug help text.
+                                1 - undefined instruction events
+                                2 - system calls
+                                4 - invalid data aborts
+                                8 - SIGSEGV faults
+                               16 - SIGBUS faults
+                       Example: user_debug=31
+
        userpte=
                        [X86] Flags controlling user PTE allocations.
 
@@ -2669,6 +2695,27 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
        vmpoff=         [KNL,S390] Perform z/VM CP command after power off.
                        Format: <command>
 
+       vsyscall=       [X86-64]
+                       Controls the behavior of vsyscalls (i.e. calls to
+                       fixed addresses of 0xffffffffff600x00 from legacy
+                       code).  Most statically-linked binaries and older
+                       versions of glibc use these calls.  Because these
+                       functions are at fixed addresses, they make nice
+                       targets for exploits that can control RIP.
+
+                       emulate     [default] Vsyscalls turn into traps and are
+                                   emulated reasonably safely.
+
+                       native      Vsyscalls are native syscall instructions.
+                                   This is a little bit faster than trapping
+                                   and makes a few dynamic recompilers work
+                                   better than they would in emulation mode.
+                                   It also makes exploits much easier to write.
+
+                       none        Vsyscalls don't work at all.  This makes
+                                   them quite hard to use for exploits but
+                                   might break your system.
+
        vt.cur_default= [VT] Default cursor shape.
                        Format: 0xCCBBAA, where AA, BB, and CC are the same as
                        the parameters of the <Esc>[?A;B;Cc escape sequence;
index c93bed6..97d45f2 100644 (file)
@@ -129,6 +129,20 @@ decimal 11 is the major of SCSI CD-ROMs, and the minor 0 stands for
 the first of these. You can find out all valid major numbers by
 looking into include/linux/major.h.
 
+In addition to major and minor numbers, if the device containing your
+root partition uses a partition table format with unique partition
+identifiers, then you may use them.  For instance,
+"root=PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF".  It is also
+possible to reference another partition on the same device using a
+known partition UUID as the starting point.  For example,
+if partition 5 of the device has the UUID of
+00112233-4455-6677-8899-AABBCCDDEEFF then partition 3 may be found as
+follows:
+  PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF/PARTNROFF=-2
+
+Authoritative information can be found in
+"Documentation/kernel-parameters.txt".
+
 
 2.2) ro, rw
 -----------
index 76a2087..669b5fb 100644 (file)
@@ -310,7 +310,7 @@ is non-immutable. The operation must either configure the hardware or store
 the configuration information to be applied later.
 
 Link configuration must not have any side effect on other links. If an enabled
-link at a sink pad prevents another link at the same pad from being disabled,
+link at a sink pad prevents another link at the same pad from being enabled,
 the link_setup operation must return -EBUSY and can't implicitly disable the
 first enabled link.
 
index 4edd78d..bbce121 100644 (file)
@@ -1,13 +1,21 @@
 00-INDEX
        - this file
+3c359.txt
+       - information on the 3Com TokenLink Velocity XL (3c5359) driver.
 3c505.txt
        - information on the 3Com EtherLink Plus (3c505) driver.
+3c509.txt
+       - information on the 3Com Etherlink III Series Ethernet cards.
 6pack.txt
        - info on the 6pack protocol, an alternative to KISS for AX.25
 DLINK.txt
        - info on the D-Link DE-600/DE-620 parallel port pocket adapters
 PLIP.txt
        - PLIP: The Parallel Line Internet Protocol device driver
+README.ipw2100
+       - README for the Intel PRO/Wireless 2100 driver.
+README.ipw2200
+       - README for the Intel PRO/Wireless 2915ABG and 2200BG driver.
 README.sb1000
        - info on General Instrument/NextLevel SURFboard1000 cable modem.
 alias.txt
@@ -20,8 +28,12 @@ atm.txt
        - info on where to get ATM programs and support for Linux.
 ax25.txt
        - info on using AX.25 and NET/ROM code for Linux
+batman-adv.txt
+       - B.A.T.M.A.N routing protocol on top of layer 2 Ethernet Frames.
 baycom.txt
        - info on the driver for Baycom style amateur radio modems
+bonding.txt
+       - Linux Ethernet Bonding Driver HOWTO: link aggregation in Linux.
 bridge.txt
        - where to get user space programs for ethernet bridging with Linux.
 can.txt
@@ -34,32 +46,60 @@ cxacru.txt
        - Conexant AccessRunner USB ADSL Modem
 cxacru-cf.py
        - Conexant AccessRunner USB ADSL Modem configuration file parser
+cxgb.txt
+       - Release Notes for the Chelsio N210 Linux device driver.
+dccp.txt
+       - the Datagram Congestion Control Protocol (DCCP) (RFC 4340..42).
 de4x5.txt
        - the Digital EtherWORKS DE4?? and DE5?? PCI Ethernet driver
 decnet.txt
        - info on using the DECnet networking layer in Linux.
 depca.txt
        - the Digital DEPCA/EtherWORKS DE1?? and DE2?? LANCE Ethernet driver
+dl2k.txt
+       - README for D-Link DL2000-based Gigabit Ethernet Adapters (dl2k.ko).
+dm9000.txt
+       - README for the Simtec DM9000 Network driver.
 dmfe.txt
        - info on the Davicom DM9102(A)/DM9132/DM9801 fast ethernet driver.
+dns_resolver.txt
+       - The DNS resolver module allows kernel servies to make DNS queries.
+driver.txt
+       - Softnet driver issues.
 e100.txt
        - info on Intel's EtherExpress PRO/100 line of 10/100 boards
 e1000.txt
        - info on Intel's E1000 line of gigabit ethernet boards
+e1000e.txt
+       - README for the Intel Gigabit Ethernet Driver (e1000e).
 eql.txt
        - serial IP load balancing
 ewrk3.txt
        - the Digital EtherWORKS 3 DE203/4/5 Ethernet driver
+fib_trie.txt
+       - Level Compressed Trie (LC-trie) notes: a structure for routing.
 filter.txt
        - Linux Socket Filtering
 fore200e.txt
        - FORE Systems PCA-200E/SBA-200E ATM NIC driver info.
 framerelay.txt
        - info on using Frame Relay/Data Link Connection Identifier (DLCI).
+gen_stats.txt
+       - Generic networking statistics for netlink users.
+generic_hdlc.txt
+       - The generic High Level Data Link Control (HDLC) layer.
 generic_netlink.txt
        - info on Generic Netlink
+gianfar.txt
+       - Gianfar Ethernet Driver.
 ieee802154.txt
        - Linux IEEE 802.15.4 implementation, API and drivers
+ifenslave.c
+       - Configure network interfaces for parallel routing (bonding).
+igb.txt
+       - README for the Intel Gigabit Ethernet Driver (igb).
+igbvf.txt
+       - README for the Intel Gigabit Ethernet Driver (igbvf).
 ip-sysctl.txt
        - /proc/sys/net/ipv4/* variables
 ip_dynaddr.txt
@@ -68,41 +108,117 @@ ipddp.txt
        - AppleTalk-IP Decapsulation and AppleTalk-IP Encapsulation
 iphase.txt
        - Interphase PCI ATM (i)Chip IA Linux driver info.
+ipv6.txt
+       - Options to the ipv6 kernel module.
+ipvs-sysctl.txt
+       - Per-inode explanation of the /proc/sys/net/ipv4/vs interface.
 irda.txt
        - where to get IrDA (infrared) utilities and info for Linux.
+ixgb.txt
+       - README for the Intel 10 Gigabit Ethernet Driver (ixgb).
+ixgbe.txt
+       - README for the Intel 10 Gigabit Ethernet Driver (ixgbe).
+ixgbevf.txt
+       - README for the Intel Virtual Function (VF) Driver (ixgbevf).
+l2tp.txt
+       - User guide to the L2TP tunnel protocol.
 lapb-module.txt
        - programming information of the LAPB module.
 ltpc.txt
        - the Apple or Farallon LocalTalk PC card driver
+mac80211-injection.txt
+       - HOWTO use packet injection with mac80211
 multicast.txt
        - Behaviour of cards under Multicast
+multiqueue.txt
+       - HOWTO for multiqueue network device support.
+netconsole.txt
+       - The network console module netconsole.ko: configuration and notes.
+netdev-features.txt
+       - Network interface features API description.
 netdevices.txt
        - info on network device driver functions exported to the kernel.
+netif-msg.txt
+       - Design of the network interface message level setting (NETIF_MSG_*).
+nfc.txt
+       - The Linux Near Field Communication (NFS) subsystem.
 olympic.txt
        - IBM PCI Pit/Pit-Phy/Olympic Token Ring driver info.
+operstates.txt
+       - Overview of network interface operational states.
+packet_mmap.txt
+       - User guide to memory mapped packet socket rings (PACKET_[RT]X_RING).
+phonet.txt
+       - The Phonet packet protocol used in Nokia cellular modems.
+phy.txt
+       - The PHY abstraction layer.
+pktgen.txt
+       - User guide to the kernel packet generator (pktgen.ko).
 policy-routing.txt
        - IP policy-based routing
+ppp_generic.txt
+       - Information about the generic PPP driver.
+proc_net_tcp.txt
+       - Per inode overview of the /proc/net/tcp and /proc/net/tcp6 interfaces.
+radiotap-headers.txt
+       - Background on radiotap headers.
 ray_cs.txt
        - Raylink Wireless LAN card driver info.
+rds.txt
+       - Background on the reliable, ordered datagram delivery method RDS.
+regulatory.txt
+       - Overview of the Linux wireless regulatory infrastructure.
+rxrpc.txt
+       - Guide to the RxRPC protocol.
+s2io.txt
+       - Release notes for Neterion Xframe I/II 10GbE driver.
+scaling.txt
+       - Explanation of network scaling techniques: RSS, RPS, RFS, aRFS, XPS.
+sctp.txt
+       - Notes on the Linux kernel implementation of the SCTP protocol.
+secid.txt
+       - Explanation of the secid member in flow structures.
 skfp.txt
        - SysKonnect FDDI (SK-5xxx, Compaq Netelligent) driver info.
 smc9.txt
        - the driver for SMC's 9000 series of Ethernet cards
 smctr.txt
        - SMC TokenCard TokenRing Linux driver info.
+spider-net.txt
+       - README for the Spidernet Driver (as found in PS3 / Cell BE).
+stmmac.txt
+       - README for the STMicro Synopsys Ethernet driver.
+tc-actions-env-rules.txt
+       - rules for traffic control (tc) actions.
+timestamping.txt
+       - overview of network packet timestamping variants.
 tcp.txt
        - short blurb on how TCP output takes place.
+tcp-thin.txt
+       - kernel tuning options for low rate 'thin' TCP streams.
 tlan.txt
        - ThunderLAN (Compaq Netelligent 10/100, Olicom OC-2xxx) driver info.
 tms380tr.txt
        - SysKonnect Token Ring ISA/PCI adapter driver info.
+tproxy.txt
+       - Transparent proxy support user guide.
 tuntap.txt
        - TUN/TAP device driver, allowing user space Rx/Tx of packets.
+udplite.txt
+       - UDP-Lite protocol (RFC 3828) introduction.
 vortex.txt
        - info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) Ethernet cards.
+vxge.txt
+       - README for the Neterion X3100 PCIe Server Adapter.
 x25.txt
        - general info on X.25 development.
 x25-iface.txt
        - description of the X.25 Packet Layer to LAPB device interface.
+xfrm_proc.txt
+       - description of the statistics package for XFRM.
+xfrm_sync.txt
+       - sync patches for XFRM enable migration of an SA between hosts.
+xfrm_sysctl.txt
+       - description of the XFRM configuration options.
 z8530drv.txt
        - info about Linux driver for Z8530 based HDLC cards for AX.25
index 675612f..91df678 100644 (file)
@@ -238,6 +238,18 @@ ad_select
 
        This option was added in bonding version 3.4.0.
 
+all_slaves_active
+
+       Specifies that duplicate frames (received on inactive ports) should be
+       dropped (0) or delivered (1).
+
+       Normally, bonding will drop duplicate frames (received on inactive
+       ports), which is desirable for most users. But there are some times
+       it is nice to allow duplicate frames to be delivered.
+
+       The default value is 0 (drop duplicate frames received on inactive
+       ports).
+
 arp_interval
 
        Specifies the ARP link monitoring frequency in milliseconds.
@@ -433,6 +445,23 @@ miimon
        determined.  See the High Availability section for additional
        information.  The default value is 0.
 
+min_links
+
+       Specifies the minimum number of links that must be active before
+       asserting carrier. It is similar to the Cisco EtherChannel min-links
+       feature. This allows setting the minimum number of member ports that
+       must be up (link-up state) before marking the bond device as up
+       (carrier on). This is useful for situations where higher level services
+       such as clustering want to ensure a minimum number of low bandwidth
+       links are active before switchover. This option only affect 802.3ad
+       mode.
+
+       The default value is 0. This will cause carrier to be asserted (for
+       802.3ad mode) whenever there is an active aggregator, regardless of the
+       number of available links in that aggregator. Note that, because an
+       aggregator cannot be active without at least one available link,
+       setting this option to 0 or to 1 has the exact same effect.
+
 mode
 
        Specifies one of the bonding policies. The default is
@@ -599,7 +628,7 @@ num_unsol_na
        affect only the active-backup mode.  These options were added for
        bonding versions 3.3.0 and 3.4.0 respectively.
 
-       From Linux 2.6.40 and bonding version 3.7.1, these notifications
+       From Linux 3.0 and bonding version 3.7.1, these notifications
        are generated by the ipv4 and ipv6 code and the numbers of
        repetitions cannot be set independently.
 
index 8006c22..25320bf 100644 (file)
@@ -1,3 +1,5 @@
+Note: This driver doesn't have a maintainer.
+
 Davicom DM9102(A)/DM9132/DM9801 fast ethernet driver for Linux.
 
 This program is free software; you can redistribute it and/or
@@ -55,7 +57,6 @@ Test and make sure PCI latency is now correct for all cases.
 Authors:
 
 Sten Wang <sten_wang@davicom.com.tw >   : Original Author
-Tobias Ringstrom <tori@unhappy.mine.nu> : Current Maintainer
 
 Contributors:
 
index db2a406..8154699 100644 (file)
@@ -992,7 +992,7 @@ bindv6only - BOOLEAN
                TRUE: disable IPv4-mapped address feature
                FALSE: enable IPv4-mapped address feature
 
-       Default: FALSE (as specified in RFC2553bis)
+       Default: FALSE (as specified in RFC3493)
 
 IPv6 Fragmentation:
 
diff --git a/Documentation/networking/scaling.txt b/Documentation/networking/scaling.txt
new file mode 100644 (file)
index 0000000..58fd741
--- /dev/null
@@ -0,0 +1,378 @@
+Scaling in the Linux Networking Stack
+
+
+Introduction
+============
+
+This document describes a set of complementary techniques in the Linux
+networking stack to increase parallelism and improve performance for
+multi-processor systems.
+
+The following technologies are described:
+
+  RSS: Receive Side Scaling
+  RPS: Receive Packet Steering
+  RFS: Receive Flow Steering
+  Accelerated Receive Flow Steering
+  XPS: Transmit Packet Steering
+
+
+RSS: Receive Side Scaling
+=========================
+
+Contemporary NICs support multiple receive and transmit descriptor queues
+(multi-queue). On reception, a NIC can send different packets to different
+queues to distribute processing among CPUs. The NIC distributes packets by
+applying a filter to each packet that assigns it to one of a small number
+of logical flows. Packets for each flow are steered to a separate receive
+queue, which in turn can be processed by separate CPUs. This mechanism is
+generally known as “Receive-side Scaling” (RSS). The goal of RSS and
+the other scaling techniques to increase performance uniformly.
+Multi-queue distribution can also be used for traffic prioritization, but
+that is not the focus of these techniques.
+
+The filter used in RSS is typically a hash function over the network
+and/or transport layer headers-- for example, a 4-tuple hash over
+IP addresses and TCP ports of a packet. The most common hardware
+implementation of RSS uses a 128-entry indirection table where each entry
+stores a queue number. The receive queue for a packet is determined
+by masking out the low order seven bits of the computed hash for the
+packet (usually a Toeplitz hash), taking this number as a key into the
+indirection table and reading the corresponding value.
+
+Some advanced NICs allow steering packets to queues based on
+programmable filters. For example, webserver bound TCP port 80 packets
+can be directed to their own receive queue. Such “n-tuple” filters can
+be configured from ethtool (--config-ntuple).
+
+==== RSS Configuration
+
+The driver for a multi-queue capable NIC typically provides a kernel
+module parameter for specifying the number of hardware queues to
+configure. In the bnx2x driver, for instance, this parameter is called
+num_queues. A typical RSS configuration would be to have one receive queue
+for each CPU if the device supports enough queues, or otherwise at least
+one for each memory domain, where a memory domain is a set of CPUs that
+share a particular memory level (L1, L2, NUMA node, etc.).
+
+The indirection table of an RSS device, which resolves a queue by masked
+hash, is usually programmed by the driver at initialization. The
+default mapping is to distribute the queues evenly in the table, but the
+indirection table can be retrieved and modified at runtime using ethtool
+commands (--show-rxfh-indir and --set-rxfh-indir). Modifying the
+indirection table could be done to give different queues different
+relative weights.
+
+== RSS IRQ Configuration
+
+Each receive queue has a separate IRQ associated with it. The NIC triggers
+this to notify a CPU when new packets arrive on the given queue. The
+signaling path for PCIe devices uses message signaled interrupts (MSI-X),
+that can route each interrupt to a particular CPU. The active mapping
+of queues to IRQs can be determined from /proc/interrupts. By default,
+an IRQ may be handled on any CPU. Because a non-negligible part of packet
+processing takes place in receive interrupt handling, it is advantageous
+to spread receive interrupts between CPUs. To manually adjust the IRQ
+affinity of each interrupt see Documentation/IRQ-affinity. Some systems
+will be running irqbalance, a daemon that dynamically optimizes IRQ
+assignments and as a result may override any manual settings.
+
+== Suggested Configuration
+
+RSS should be enabled when latency is a concern or whenever receive
+interrupt processing forms a bottleneck. Spreading load between CPUs
+decreases queue length. For low latency networking, the optimal setting
+is to allocate as many queues as there are CPUs in the system (or the
+NIC maximum, if lower). The most efficient high-rate configuration
+is likely the one with the smallest number of receive queues where no
+receive queue overflows due to a saturated CPU, because in default
+mode with interrupt coalescing enabled, the aggregate number of
+interrupts (and thus work) grows with each additional queue.
+
+Per-cpu load can be observed using the mpstat utility, but note that on
+processors with hyperthreading (HT), each hyperthread is represented as
+a separate CPU. For interrupt handling, HT has shown no benefit in
+initial tests, so limit the number of queues to the number of CPU cores
+in the system.
+
+
+RPS: Receive Packet Steering
+============================
+
+Receive Packet Steering (RPS) is logically a software implementation of
+RSS. Being in software, it is necessarily called later in the datapath.
+Whereas RSS selects the queue and hence CPU that will run the hardware
+interrupt handler, RPS selects the CPU to perform protocol processing
+above the interrupt handler. This is accomplished by placing the packet
+on the desired CPU’s backlog queue and waking up the CPU for processing.
+RPS has some advantages over RSS: 1) it can be used with any NIC,
+2) software filters can easily be added to hash over new protocols,
+3) it does not increase hardware device interrupt rate (although it does
+introduce inter-processor interrupts (IPIs)).
+
+RPS is called during bottom half of the receive interrupt handler, when
+a driver sends a packet up the network stack with netif_rx() or
+netif_receive_skb(). These call the get_rps_cpu() function, which
+selects the queue that should process a packet.
+
+The first step in determining the target CPU for RPS is to calculate a
+flow hash over the packet’s addresses or ports (2-tuple or 4-tuple hash
+depending on the protocol). This serves as a consistent hash of the
+associated flow of the packet. The hash is either provided by hardware
+or will be computed in the stack. Capable hardware can pass the hash in
+the receive descriptor for the packet; this would usually be the same
+hash used for RSS (e.g. computed Toeplitz hash). The hash is saved in
+skb->rx_hash and can be used elsewhere in the stack as a hash of the
+packet’s flow.
+
+Each receive hardware queue has an associated list of CPUs to which
+RPS may enqueue packets for processing. For each received packet,
+an index into the list is computed from the flow hash modulo the size
+of the list. The indexed CPU is the target for processing the packet,
+and the packet is queued to the tail of that CPU’s backlog queue. At
+the end of the bottom half routine, IPIs are sent to any CPUs for which
+packets have been queued to their backlog queue. The IPI wakes backlog
+processing on the remote CPU, and any queued packets are then processed
+up the networking stack.
+
+==== RPS Configuration
+
+RPS requires a kernel compiled with the CONFIG_RPS kconfig symbol (on
+by default for SMP). Even when compiled in, RPS remains disabled until
+explicitly configured. The list of CPUs to which RPS may forward traffic
+can be configured for each receive queue using a sysfs file entry:
+
+ /sys/class/net/<dev>/queues/rx-<n>/rps_cpus
+
+This file implements a bitmap of CPUs. RPS is disabled when it is zero
+(the default), in which case packets are processed on the interrupting
+CPU. Documentation/IRQ-affinity.txt explains how CPUs are assigned to
+the bitmap.
+
+== Suggested Configuration
+
+For a single queue device, a typical RPS configuration would be to set
+the rps_cpus to the CPUs in the same memory domain of the interrupting
+CPU. If NUMA locality is not an issue, this could also be all CPUs in
+the system. At high interrupt rate, it might be wise to exclude the
+interrupting CPU from the map since that already performs much work.
+
+For a multi-queue system, if RSS is configured so that a hardware
+receive queue is mapped to each CPU, then RPS is probably redundant
+and unnecessary. If there are fewer hardware queues than CPUs, then
+RPS might be beneficial if the rps_cpus for each queue are the ones that
+share the same memory domain as the interrupting CPU for that queue.
+
+
+RFS: Receive Flow Steering
+==========================
+
+While RPS steers packets solely based on hash, and thus generally
+provides good load distribution, it does not take into account
+application locality. This is accomplished by Receive Flow Steering
+(RFS). The goal of RFS is to increase datacache hitrate by steering
+kernel processing of packets to the CPU where the application thread
+consuming the packet is running. RFS relies on the same RPS mechanisms
+to enqueue packets onto the backlog of another CPU and to wake up that
+CPU.
+
+In RFS, packets are not forwarded directly by the value of their hash,
+but the hash is used as index into a flow lookup table. This table maps
+flows to the CPUs where those flows are being processed. The flow hash
+(see RPS section above) is used to calculate the index into this table.
+The CPU recorded in each entry is the one which last processed the flow.
+If an entry does not hold a valid CPU, then packets mapped to that entry
+are steered using plain RPS. Multiple table entries may point to the
+same CPU. Indeed, with many flows and few CPUs, it is very likely that
+a single application thread handles flows with many different flow hashes.
+
+rps_sock_table is a global flow table that contains the *desired* CPU for
+flows: the CPU that is currently processing the flow in userspace. Each
+table value is a CPU index that is updated during calls to recvmsg and
+sendmsg (specifically, inet_recvmsg(), inet_sendmsg(), inet_sendpage()
+and tcp_splice_read()).
+
+When the scheduler moves a thread to a new CPU while it has outstanding
+receive packets on the old CPU, packets may arrive out of order. To
+avoid this, RFS uses a second flow table to track outstanding packets
+for each flow: rps_dev_flow_table is a table specific to each hardware
+receive queue of each device. Each table value stores a CPU index and a
+counter. The CPU index represents the *current* CPU onto which packets
+for this flow are enqueued for further kernel processing. Ideally, kernel
+and userspace processing occur on the same CPU, and hence the CPU index
+in both tables is identical. This is likely false if the scheduler has
+recently migrated a userspace thread while the kernel still has packets
+enqueued for kernel processing on the old CPU.
+
+The counter in rps_dev_flow_table values records the length of the current
+CPU's backlog when a packet in this flow was last enqueued. Each backlog
+queue has a head counter that is incremented on dequeue. A tail counter
+is computed as head counter + queue length. In other words, the counter
+in rps_dev_flow_table[i] records the last element in flow i that has
+been enqueued onto the currently designated CPU for flow i (of course,
+entry i is actually selected by hash and multiple flows may hash to the
+same entry i).
+
+And now the trick for avoiding out of order packets: when selecting the
+CPU for packet processing (from get_rps_cpu()) the rps_sock_flow table
+and the rps_dev_flow table of the queue that the packet was received on
+are compared. If the desired CPU for the flow (found in the
+rps_sock_flow table) matches the current CPU (found in the rps_dev_flow
+table), the packet is enqueued onto that CPU’s backlog. If they differ,
+the current CPU is updated to match the desired CPU if one of the
+following is true:
+
+- The current CPU's queue head counter >= the recorded tail counter
+  value in rps_dev_flow[i]
+- The current CPU is unset (equal to NR_CPUS)
+- The current CPU is offline
+
+After this check, the packet is sent to the (possibly updated) current
+CPU. These rules aim to ensure that a flow only moves to a new CPU when
+there are no packets outstanding on the old CPU, as the outstanding
+packets could arrive later than those about to be processed on the new
+CPU.
+
+==== RFS Configuration
+
+RFS is only available if the kconfig symbol CONFIG_RFS is enabled (on
+by default for SMP). The functionality remains disabled until explicitly
+configured. The number of entries in the global flow table is set through:
+
+ /proc/sys/net/core/rps_sock_flow_entries
+
+The number of entries in the per-queue flow table are set through:
+
+ /sys/class/net/<dev>/queues/tx-<n>/rps_flow_cnt
+
+== Suggested Configuration
+
+Both of these need to be set before RFS is enabled for a receive queue.
+Values for both are rounded up to the nearest power of two. The
+suggested flow count depends on the expected number of active connections
+at any given time, which may be significantly less than the number of open
+connections. We have found that a value of 32768 for rps_sock_flow_entries
+works fairly well on a moderately loaded server.
+
+For a single queue device, the rps_flow_cnt value for the single queue
+would normally be configured to the same value as rps_sock_flow_entries.
+For a multi-queue device, the rps_flow_cnt for each queue might be
+configured as rps_sock_flow_entries / N, where N is the number of
+queues. So for instance, if rps_flow_entries is set to 32768 and there
+are 16 configured receive queues, rps_flow_cnt for each queue might be
+configured as 2048.
+
+
+Accelerated RFS
+===============
+
+Accelerated RFS is to RFS what RSS is to RPS: a hardware-accelerated load
+balancing mechanism that uses soft state to steer flows based on where
+the application thread consuming the packets of each flow is running.
+Accelerated RFS should perform better than RFS since packets are sent
+directly to a CPU local to the thread consuming the data. The target CPU
+will either be the same CPU where the application runs, or at least a CPU
+which is local to the application thread’s CPU in the cache hierarchy.
+
+To enable accelerated RFS, the networking stack calls the
+ndo_rx_flow_steer driver function to communicate the desired hardware
+queue for packets matching a particular flow. The network stack
+automatically calls this function every time a flow entry in
+rps_dev_flow_table is updated. The driver in turn uses a device specific
+method to program the NIC to steer the packets.
+
+The hardware queue for a flow is derived from the CPU recorded in
+rps_dev_flow_table. The stack consults a CPU to hardware queue map which
+is maintained by the NIC driver. This is an auto-generated reverse map of
+the IRQ affinity table shown by /proc/interrupts. Drivers can use
+functions in the cpu_rmap (“CPU affinity reverse map”) kernel library
+to populate the map. For each CPU, the corresponding queue in the map is
+set to be one whose processing CPU is closest in cache locality.
+
+==== Accelerated RFS Configuration
+
+Accelerated RFS is only available if the kernel is compiled with
+CONFIG_RFS_ACCEL and support is provided by the NIC device and driver.
+It also requires that ntuple filtering is enabled via ethtool. The map
+of CPU to queues is automatically deduced from the IRQ affinities
+configured for each receive queue by the driver, so no additional
+configuration should be necessary.
+
+== Suggested Configuration
+
+This technique should be enabled whenever one wants to use RFS and the
+NIC supports hardware acceleration.
+
+XPS: Transmit Packet Steering
+=============================
+
+Transmit Packet Steering is a mechanism for intelligently selecting
+which transmit queue to use when transmitting a packet on a multi-queue
+device. To accomplish this, a mapping from CPU to hardware queue(s) is
+recorded. The goal of this mapping is usually to assign queues
+exclusively to a subset of CPUs, where the transmit completions for
+these queues are processed on a CPU within this set. This choice
+provides two benefits. First, contention on the device queue lock is
+significantly reduced since fewer CPUs contend for the same queue
+(contention can be eliminated completely if each CPU has its own
+transmit queue). Secondly, cache miss rate on transmit completion is
+reduced, in particular for data cache lines that hold the sk_buff
+structures.
+
+XPS is configured per transmit queue by setting a bitmap of CPUs that
+may use that queue to transmit. The reverse mapping, from CPUs to
+transmit queues, is computed and maintained for each network device.
+When transmitting the first packet in a flow, the function
+get_xps_queue() is called to select a queue. This function uses the ID
+of the running CPU as a key into the CPU-to-queue lookup table. If the
+ID matches a single queue, that is used for transmission. If multiple
+queues match, one is selected by using the flow hash to compute an index
+into the set.
+
+The queue chosen for transmitting a particular flow is saved in the
+corresponding socket structure for the flow (e.g. a TCP connection).
+This transmit queue is used for subsequent packets sent on the flow to
+prevent out of order (ooo) packets. The choice also amortizes the cost
+of calling get_xps_queues() over all packets in the flow. To avoid
+ooo packets, the queue for a flow can subsequently only be changed if
+skb->ooo_okay is set for a packet in the flow. This flag indicates that
+there are no outstanding packets in the flow, so the transmit queue can
+change without the risk of generating out of order packets. The
+transport layer is responsible for setting ooo_okay appropriately. TCP,
+for instance, sets the flag when all data for a connection has been
+acknowledged.
+
+==== XPS Configuration
+
+XPS is only available if the kconfig symbol CONFIG_XPS is enabled (on by
+default for SMP). The functionality remains disabled until explicitly
+configured. To enable XPS, the bitmap of CPUs that may use a transmit
+queue is configured using the sysfs file entry:
+
+/sys/class/net/<dev>/queues/tx-<n>/xps_cpus
+
+== Suggested Configuration
+
+For a network device with a single transmission queue, XPS configuration
+has no effect, since there is no choice in this case. In a multi-queue
+system, XPS is preferably configured so that each CPU maps onto one queue.
+If there are as many queues as there are CPUs in the system, then each
+queue can also map onto one CPU, resulting in exclusive pairings that
+experience no contention. If there are fewer queues than CPUs, then the
+best CPUs to share a given queue are probably those that share the cache
+with the CPU that processes transmit completions for that queue
+(transmit interrupts).
+
+
+Further Information
+===================
+RPS and RFS were introduced in kernel 2.6.35. XPS was incorporated into
+2.6.38. Original patches were submitted by Tom Herbert
+(therbert@google.com)
+
+Accelerated RFS was introduced in 2.6.35. Original patches were
+submitted by Ben Hutchings (bhutchings@solarflare.com)
+
+Authors:
+Tom Herbert (therbert@google.com)
+Willem de Bruijn (willemb@google.com)
index 14dd3c6..4ce5450 100644 (file)
@@ -54,11 +54,10 @@ referred to as subsystem-level callbacks in what follows.
 By default, the callbacks are always invoked in process context with interrupts
 enabled.  However, subsystems can use the pm_runtime_irq_safe() helper function
 to tell the PM core that a device's ->runtime_suspend() and ->runtime_resume()
-callbacks should be invoked in atomic context with interrupts disabled
-(->runtime_idle() is still invoked the default way).  This implies that these
-callback routines must not block or sleep, but it also means that the
-synchronous helper functions listed at the end of Section 4 can be used within
-an interrupt handler or in an atomic context.
+callbacks should be invoked in atomic context with interrupts disabled.
+This implies that these callback routines must not block or sleep, but it also
+means that the synchronous helper functions listed at the end of Section 4 can
+be used within an interrupt handler or in an atomic context.
 
 The subsystem-level suspend callback is _entirely_ _responsible_ for handling
 the suspend of the device as appropriate, which may, but need not include
@@ -483,6 +482,7 @@ pm_runtime_suspend()
 pm_runtime_autosuspend()
 pm_runtime_resume()
 pm_runtime_get_sync()
+pm_runtime_put_sync()
 pm_runtime_put_sync_suspend()
 
 5. Runtime PM Initialization, Device Probing and Removal
diff --git a/Documentation/ramoops.txt b/Documentation/ramoops.txt
new file mode 100644 (file)
index 0000000..8fb1ba7
--- /dev/null
@@ -0,0 +1,76 @@
+Ramoops oops/panic logger
+=========================
+
+Sergiu Iordache <sergiu@chromium.org>
+
+Updated: 8 August 2011
+
+0. Introduction
+
+Ramoops is an oops/panic logger that writes its logs to RAM before the system
+crashes. It works by logging oopses and panics in a circular buffer. Ramoops
+needs a system with persistent RAM so that the content of that area can
+survive after a restart.
+
+1. Ramoops concepts
+
+Ramoops uses a predefined memory area to store the dump. The start and size of
+the memory area are set using two variables:
+  * "mem_address" for the start
+  * "mem_size" for the size. The memory size will be rounded down to a
+  power of two.
+
+The memory area is divided into "record_size" chunks (also rounded down to
+power of two) and each oops/panic writes a "record_size" chunk of
+information.
+
+Dumping both oopses and panics can be done by setting 1 in the "dump_oops"
+variable while setting 0 in that variable dumps only the panics.
+
+The module uses a counter to record multiple dumps but the counter gets reset
+on restart (i.e. new dumps after the restart will overwrite old ones).
+
+2. Setting the parameters
+
+Setting the ramoops parameters can be done in 2 different manners:
+ 1. Use the module parameters (which have the names of the variables described
+ as before).
+ 2. Use a platform device and set the platform data. The parameters can then
+ be set through that platform data. An example of doing that is:
+
+#include <linux/ramoops.h>
+[...]
+
+static struct ramoops_platform_data ramoops_data = {
+        .mem_size               = <...>,
+        .mem_address            = <...>,
+        .record_size            = <...>,
+        .dump_oops              = <...>,
+};
+
+static struct platform_device ramoops_dev = {
+        .name = "ramoops",
+        .dev = {
+                .platform_data = &ramoops_data,
+        },
+};
+
+[... inside a function ...]
+int ret;
+
+ret = platform_device_register(&ramoops_dev);
+if (ret) {
+       printk(KERN_ERR "unable to register platform device\n");
+       return ret;
+}
+
+3. Dump format
+
+The data dump begins with a header, currently defined as "====" followed by a
+timestamp and a new line. The dump then continues with the actual data.
+
+4. Reading the data
+
+The dump data can be read from memory (through /dev/mem or other means).
+Getting the module parameters, which are needed in order to parse the data, can
+be done through /sys/module/ramoops/parameters/* .
index 9ed1d9d..1b6e27d 100644 (file)
@@ -1,3 +1,11 @@
+Release Date    : Tue. Jul 26, 2011 17:00:00 PST 2010 -
+                       (emaild-id:megaraidlinux@lsi.com)
+                       Adam Radford
+Current Version : 00.00.05.40-rc1
+Old Version     : 00.00.05.38-rc1
+    1. Fix FastPath I/O to work with degraded RAID 1.
+    2. Add .change_queue_depth support.
+-------------------------------------------------------------------------------
 Release Date    : Wed. May 11, 2011 17:00:00 PST 2010 -
                        (emaild-id:megaraidlinux@lsi.com)
                        Adam Radford
index d72fd2a..256f8ef 100644 (file)
@@ -9,7 +9,7 @@
   <table border="0">
    <tr>
     <td>
-     <a href="http://www.linuxtv.org/downloads/video4linux/API/V4L1_API.html">V4L original API</a>
+     <a href="http://linuxtv.org/downloads/legacy/video4linux/API/V4L1_API.html">V4L original API</a>
     </td>
     <td>
      Obsoleted by V4L2 API
index 87c4634..8910449 100644 (file)
@@ -27,3 +27,5 @@
  26 -> Hauppauge WinTV-HVR1290                             [0070:8551]
  27 -> Mygica X8558 PRO DMB-TH                             [14f1:8578]
  28 -> LEADTEK WinFast PxTV1200                            [107d:6f22]
+ 29 -> GoTView X5 3D Hybrid                                [5654:2390]
+ 30 -> NetUP Dual DVB-T/C-CI RF                            [1b55:e2e4]
index 42517d9..d9c0f11 100644 (file)
@@ -84,3 +84,4 @@
  83 -> Prof 7301 DVB-S/S2                                  [b034:3034]
  84 -> Samsung SMT 7020 DVB-S                              [18ac:dc00,18ac:dccd]
  85 -> Twinhan VP-1027 DVB-S                               [1822:0023]
+ 86 -> TeVii S464 DVB-S/S2                                 [d464:9022]
index 9aae449..4a7b3df 100644 (file)
@@ -74,3 +74,5 @@
  74 -> Actionmaster/LinXcel/Digitus VC211A      (em2800)
  75 -> Dikom DK300                              (em2882)
  76 -> KWorld PlusTV 340U or UB435-Q (ATSC)     (em2870)        [1b80:a340]
+ 77 -> EM2874 Leadership ISDBT                  (em2874)
+ 78 -> PCTV nanoStick T2 290e                   (em28174)
index 6b4c72d..7efae9b 100644 (file)
 181 -> TechoTrend TT-budget T-3000              [13c2:2804]
 182 -> Kworld PCI SBTVD/ISDB-T Full-Seg Hybrid  [17de:b136]
 183 -> Compro VideoMate Vista M1F               [185b:c900]
+184 -> Encore ENLTV-FM 3                        [1a7f:2108]
+185 -> MagicPro ProHDTV Pro2 DMB-TH/Hybrid      [17de:d136]
+186 -> Beholder BeholdTV 501                    [5ace:5010]
+187 -> Beholder BeholdTV 503 FM                 [5ace:5030]
index e67c1db..6323b7a 100644 (file)
@@ -78,8 +78,10 @@ tuner=77 - TCL tuner MF02GIP-5N-E
 tuner=78 - Philips FMD1216MEX MK3 Hybrid Tuner
 tuner=79 - Philips PAL/SECAM multi (FM1216 MK5)
 tuner=80 - Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough
+tuner=81 - Xceive 4000 tuner
 tuner=81 - Partsnic (Daewoo) PTI-5NF05
 tuner=82 - Philips CU1216L
 tuner=83 - NXP TDA18271
 tuner=84 - Sony BTF-Pxn01Z
 tuner=85 - Philips FQ1236 MK5
+tuner=86 - Tena TNF5337 MFD
index 0b72d3f..6fd1af3 100644 (file)
@@ -63,3 +63,5 @@
  62 -> Pinnacle PCTV Bungee USB (PAL) FM                        [2304:0419]
  63 -> Hauppauge WinTv-USB                                      [2400:4200]
  64 -> Pinnacle Studio PCTV USB (NTSC) FM V3                    [2304:0113]
+ 65 -> Nogatech USB MicroCam NTSC (NV3000N)                     [0573:3000]
+ 66 -> Nogatech USB MicroCam PAL (NV3001P)                      [0573:3001]
diff --git a/Documentation/video4linux/README.davinci-vpbe b/Documentation/video4linux/README.davinci-vpbe
new file mode 100644 (file)
index 0000000..7a460b0
--- /dev/null
@@ -0,0 +1,93 @@
+
+                VPBE V4L2 driver design
+ ======================================================================
+
+ File partitioning
+ -----------------
+ V4L2 display device driver
+         drivers/media/video/davinci/vpbe_display.c
+         drivers/media/video/davinci/vpbe_display.h
+
+ VPBE display controller
+         drivers/media/video/davinci/vpbe.c
+         drivers/media/video/davinci/vpbe.h
+
+ VPBE venc sub device driver
+         drivers/media/video/davinci/vpbe_venc.c
+         drivers/media/video/davinci/vpbe_venc.h
+         drivers/media/video/davinci/vpbe_venc_regs.h
+
+ VPBE osd driver
+         drivers/media/video/davinci/vpbe_osd.c
+         drivers/media/video/davinci/vpbe_osd.h
+         drivers/media/video/davinci/vpbe_osd_regs.h
+
+ Functional partitioning
+ -----------------------
+
+ Consists of the following (in the same order as the list under file
+ partitioning):-
+
+ 1. V4L2 display driver
+    Implements creation of video2 and video3 device nodes and
+    provides v4l2 device interface to manage VID0 and VID1 layers.
+
+ 2. Display controller
+    Loads up VENC, OSD and external encoders such as ths8200. It provides
+    a set of API calls to V4L2 drivers to set the output/standards
+    in the VENC or external sub devices. It also provides
+    a device object to access the services from OSD subdevice
+    using sub device ops. The connection of external encoders to VENC LCD
+    controller port is done at init time based on default output and standard
+    selection or at run time when application change the output through
+    V4L2 IOCTLs.
+
+    When connected to an external encoder, vpbe controller is also responsible
+    for setting up the interface between VENC and external encoders based on
+    board specific settings (specified in board-xxx-evm.c). This allows
+    interfacing external encoders such as ths8200. The setup_if_config()
+    is implemented for this as well as configure_venc() (part of the next patch)
+    API to set timings in VENC for a specific display resolution. As of this
+    patch series, the interconnection and enabling and setting of the external
+    encoders is not present, and would be a part of the next patch series.
+
+ 3. VENC subdevice module
+    Responsible for setting outputs provided through internal DACs and also
+    setting timings at LCD controller port when external encoders are connected
+    at the port or LCD panel timings required. When external encoder/LCD panel
+    is connected, the timings for a specific standard/preset is retrieved from
+    the board specific table and the values are used to set the timings in
+    venc using non-standard timing mode.
+
+    Support LCD Panel displays using the VENC. For example to support a Logic
+    PD display, it requires setting up the LCD controller port with a set of
+    timings for the resolution supported and setting the dot clock. So we could
+    add the available outputs as a board specific entry (i.e add the "LogicPD"
+    output name to board-xxx-evm.c). A table of timings for various LCDs
+    supported can be maintained in the board specific setup file to support
+    various LCD displays.As of this patch a basic driver is present, and this
+    support for external encoders and displays forms a part of the next
+    patch series.
+
+ 4. OSD module
+    OSD module implements all OSD layer management and hardware specific
+    features. The VPBE module interacts with the OSD for enabling and
+    disabling appropriate features of the OSD.
+
+ Current status:-
+
+ A fully functional working version of the V4L2 driver is available. This
+ driver has been tested with NTSC and PAL standards and buffer streaming.
+
+ Following are TBDs.
+
+ vpbe display controller
+    - Add support for external encoders.
+    - add support for selecting external encoder as default at probe time.
+
+ vpbe venc sub device
+    - add timings for supporting ths8200
+    - add support for LogicPD LCD.
+
+ FB drivers
+    - Add support for fbdev drivers.- Ready and part of subsequent patches.
index 881e7f4..9346fc8 100644 (file)
@@ -277,16 +277,13 @@ implement g_volatile_ctrl like this:
        {
                switch (ctrl->id) {
                case V4L2_CID_BRIGHTNESS:
-                       ctrl->cur.val = read_reg(0x123);
+                       ctrl->val = read_reg(0x123);
                        break;
                }
        }
 
-The 'new value' union is not used in g_volatile_ctrl. In general controls
-that need to implement g_volatile_ctrl are read-only controls.
-
-Note that if one or more controls in a control cluster are marked as volatile,
-then all the controls in the cluster are seen as volatile.
+Note that you use the 'new value' union as well in g_volatile_ctrl. In general
+controls that need to implement g_volatile_ctrl are read-only controls.
 
 To mark a control as volatile you have to set the is_volatile flag:
 
@@ -453,6 +450,25 @@ In the example above the following are equivalent for the VOLUME case:
        ctrl == ctrl->cluster[AUDIO_CL_VOLUME] == state->audio_cluster[AUDIO_CL_VOLUME]
        ctrl->cluster[AUDIO_CL_MUTE] == state->audio_cluster[AUDIO_CL_MUTE]
 
+In practice using cluster arrays like this becomes very tiresome. So instead
+the following equivalent method is used:
+
+       struct {
+               /* audio cluster */
+               struct v4l2_ctrl *volume;
+               struct v4l2_ctrl *mute;
+       };
+
+The anonymous struct is used to clearly 'cluster' these two control pointers,
+but it serves no other purpose. The effect is the same as creating an
+array with two control pointers. So you can just do:
+
+       state->volume = v4l2_ctrl_new_std(&state->ctrl_handler, ...);
+       state->mute = v4l2_ctrl_new_std(&state->ctrl_handler, ...);
+       v4l2_ctrl_cluster(2, &state->volume);
+
+And in foo_s_ctrl you can use these pointers directly: state->mute->val.
+
 Note that controls in a cluster may be NULL. For example, if for some
 reason mute was never added (because the hardware doesn't support that
 particular feature), then mute will be NULL. So in that case we have a
@@ -475,6 +491,43 @@ controls, then the 'is_new' flag would be 1 for both controls.
 The 'is_new' flag is always 1 when called from v4l2_ctrl_handler_setup().
 
 
+Handling autogain/gain-type Controls with Auto Clusters
+=======================================================
+
+A common type of control cluster is one that handles 'auto-foo/foo'-type
+controls. Typical examples are autogain/gain, autoexposure/exposure,
+autowhitebalance/red balance/blue balance. In all cases you have one controls
+that determines whether another control is handled automatically by the hardware,
+or whether it is under manual control from the user.
+
+If the cluster is in automatic mode, then the manual controls should be
+marked inactive. When the volatile controls are read the g_volatile_ctrl
+operation should return the value that the hardware's automatic mode set up
+automatically.
+
+If the cluster is put in manual mode, then the manual controls should become
+active again and the is_volatile flag should be ignored (so g_volatile_ctrl is
+no longer called while in manual mode).
+
+Finally the V4L2_CTRL_FLAG_UPDATE should be set for the auto control since
+changing that control affects the control flags of the manual controls.
+
+In order to simplify this a special variation of v4l2_ctrl_cluster was
+introduced:
+
+void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls,
+                       u8 manual_val, bool set_volatile);
+
+The first two arguments are identical to v4l2_ctrl_cluster. The third argument
+tells the framework which value switches the cluster into manual mode. The
+last argument will optionally set the is_volatile flag for the non-auto controls.
+
+The first control of the cluster is assumed to be the 'auto' control.
+
+Using this function will ensure that you don't need to handle all the complex
+flag and volatile handling.
+
+
 VIDIOC_LOG_STATUS Support
 =========================
 
@@ -636,9 +689,7 @@ button controls are write-only controls.
 -EINVAL as the spec says.
 
 5) The spec does not mention what should happen when you try to set/get a
-control class controls. ivtv currently returns -EINVAL (indicating that the
-control ID does not exist) while the framework will return -EACCES, which
-makes more sense.
+control class controls. The framework will return -EACCES.
 
 
 Proposals for Extensions
index cf21f7a..f8dcabf 100644 (file)
@@ -817,11 +817,7 @@ int my_open(struct file *file)
 
        ...
 
-       ret = v4l2_fh_init(&my_fh->fh, vfd);
-       if (ret) {
-               kfree(my_fh);
-               return ret;
-       }
+       v4l2_fh_init(&my_fh->fh, vfd);
 
        ...
 
@@ -844,7 +840,7 @@ int my_release(struct file *file)
 
 Below is a short description of the v4l2_fh functions used:
 
-int v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev)
+void v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev)
 
   Initialise the file handle. This *MUST* be performed in the driver's
   v4l2_file_operations->open() handler.
@@ -901,14 +897,38 @@ V4L2 events
 The V4L2 events provide a generic way to pass events to user space.
 The driver must use v4l2_fh to be able to support V4L2 events.
 
-Useful functions:
+Events are defined by a type and an optional ID. The ID may refer to a V4L2
+object such as a control ID. If unused, then the ID is 0.
+
+When the user subscribes to an event the driver will allocate a number of
+kevent structs for that event. So every (type, ID) event tuple will have
+its own set of kevent structs. This guarantees that if a driver is generating
+lots of events of one type in a short time, then that will not overwrite
+events of another type.
+
+But if you get more events of one type than the number of kevents that were
+reserved, then the oldest event will be dropped and the new one added.
+
+Furthermore, the internal struct v4l2_subscribed_event has merge() and
+replace() callbacks which drivers can set. These callbacks are called when
+a new event is raised and there is no more room. The replace() callback
+allows you to replace the payload of the old event with that of the new event,
+merging any relevant data from the old payload into the new payload that
+replaces it. It is called when this event type has only one kevent struct
+allocated. The merge() callback allows you to merge the oldest event payload
+into that of the second-oldest event payload. It is called when there are two
+or more kevent structs allocated.
 
-- v4l2_event_alloc()
+This way no status information is lost, just the intermediate steps leading
+up to that state.
 
-  To use events, the driver must allocate events for the file handle. By
-  calling the function more than once, the driver may assure that at least n
-  events in total have been allocated. The function may not be called in
-  atomic context.
+A good example of these replace/merge callbacks is in v4l2-event.c:
+ctrls_replace() and ctrls_merge() callbacks for the control event.
+
+Note: these callbacks can be called from interrupt context, so they must be
+fast.
+
+Useful functions:
 
 - v4l2_event_queue()
 
@@ -920,7 +940,9 @@ Useful functions:
 
   The video_device->ioctl_ops->vidioc_subscribe_event must check the driver
   is able to produce events with specified event id. Then it calls
-  v4l2_event_subscribe() to subscribe the event.
+  v4l2_event_subscribe() to subscribe the event. The last argument is the
+  size of the event queue for this event. If it is 0, then the framework
+  will fill in a default value (this depends on the event type).
 
 - v4l2_event_unsubscribe()
 
@@ -935,14 +957,8 @@ Useful functions:
 
   Returns the number of pending events. Useful when implementing poll.
 
-Drivers do not initialise events directly. The events are initialised
-through v4l2_fh_init() if video_device->ioctl_ops->vidioc_subscribe_event is
-non-NULL. This *MUST* be performed in the driver's
-v4l2_file_operations->open() handler.
-
 Events are delivered to user space through the poll system call. The driver
-can use v4l2_fh->events->wait wait_queue_head_t as the argument for
-poll_wait().
+can use v4l2_fh->wait (a wait_queue_head_t) as the argument for poll_wait().
 
 There are standard and private events. New standard events must use the
 smallest available event type. The drivers must allocate their events from
@@ -952,5 +968,4 @@ The first event type in the class is reserved for future use, so the first
 available event type is 'class base + 1'.
 
 An example on how the V4L2 events may be used can be found in the OMAP
-3 ISP driver available at <URL:http://gitorious.org/omap3camera> as of
-writing this.
+3 ISP driver (drivers/media/video/omap3isp).
index fe0251c..8e60199 100644 (file)
@@ -8,3 +8,6 @@ lguest/
        - Extremely simple hypervisor for experimental/educational use.
 uml/
        - User Mode Linux, builds/runs Linux kernel as a userspace program.
+virtio.txt
+       - Text version of draft virtio spec.
+          See http://ozlabs.org/~rusty/virtio-spec
index 043bd7d..d928c13 100644 (file)
@@ -1996,6 +1996,9 @@ int main(int argc, char *argv[])
        /* We use a simple helper to copy the arguments separated by spaces. */
        concat((char *)(boot + 1), argv+optind+2);
 
+       /* Set kernel alignment to 16M (CONFIG_PHYSICAL_ALIGN) */
+       boot->hdr.kernel_alignment = 0x1000000;
+
        /* Boot protocol version: 2.07 supports the fields for lguest. */
        boot->hdr.version = 0x207;
 
diff --git a/Documentation/virtual/virtio-spec.txt b/Documentation/virtual/virtio-spec.txt
new file mode 100644 (file)
index 0000000..a350ae1
--- /dev/null
@@ -0,0 +1,2200 @@
+[Generated file: see http://ozlabs.org/~rusty/virtio-spec/]
+Virtio PCI Card Specification
+v0.9.1 DRAFT
+-
+
+Rusty Russell <rusty@rustcorp.com.au>IBM Corporation (Editor)
+
+2011 August 1.
+
+Purpose and Description
+
+This document describes the specifications of the “virtio” family
+of PCI[LaTeX Command: nomenclature] devices. These are devices
+are found in virtual environments[LaTeX Command: nomenclature],
+yet by design they are not all that different from physical PCI
+devices, and this document treats them as such. This allows the
+guest to use standard PCI drivers and discovery mechanisms.
+
+The purpose of virtio and this specification is that virtual
+environments and guests should have a straightforward, efficient,
+standard and extensible mechanism for virtual devices, rather
+than boutique per-environment or per-OS mechanisms.
+
+  Straightforward: Virtio PCI devices use normal PCI mechanisms
+  of interrupts and DMA which should be familiar to any device
+  driver author. There is no exotic page-flipping or COW
+  mechanism: it's just a PCI device.[footnote:
+This lack of page-sharing implies that the implementation of the
+device (e.g. the hypervisor or host) needs full access to the
+guest memory. Communication with untrusted parties (i.e.
+inter-guest communication) requires copying.
+]
+
+  Efficient: Virtio PCI devices consist of rings of descriptors
+  for input and output, which are neatly separated to avoid cache
+  effects from both guest and device writing to the same cache
+  lines.
+
+  Standard: Virtio PCI makes no assumptions about the environment
+  in which it operates, beyond supporting PCI. In fact the virtio
+  devices specified in the appendices do not require PCI at all:
+  they have been implemented on non-PCI buses.[footnote:
+The Linux implementation further separates the PCI virtio code
+from the specific virtio drivers: these drivers are shared with
+the non-PCI implementations (currently lguest and S/390).
+]
+
+  Extensible: Virtio PCI devices contain feature bits which are
+  acknowledged by the guest operating system during device setup.
+  This allows forwards and backwards compatibility: the device
+  offers all the features it knows about, and the driver
+  acknowledges those it understands and wishes to use.
+
+  Virtqueues
+
+The mechanism for bulk data transport on virtio PCI devices is
+pretentiously called a virtqueue. Each device can have zero or
+more virtqueues: for example, the network device has one for
+transmit and one for receive.
+
+Each virtqueue occupies two or more physically-contiguous pages
+(defined, for the purposes of this specification, as 4096 bytes),
+and consists of three parts:
+
+
++-------------------+-----------------------------------+-----------+
+| Descriptor Table  |   Available Ring     (padding)    | Used Ring |
++-------------------+-----------------------------------+-----------+
+
+
+When the driver wants to send buffers to the device, it puts them
+in one or more slots in the descriptor table, and writes the
+descriptor indices into the available ring. It then notifies the
+device. When the device has finished with the buffers, it writes
+the descriptors into the used ring, and sends an interrupt.
+
+Specification
+
+  PCI Discovery
+
+Any PCI device with Vendor ID 0x1AF4, and Device ID 0x1000
+through 0x103F inclusive is a virtio device[footnote:
+The actual value within this range is ignored
+]. The device must also have a Revision ID of 0 to match this
+specification.
+
+The Subsystem Device ID indicates which virtio device is
+supported by the device. The Subsystem Vendor ID should reflect
+the PCI Vendor ID of the environment (it's currently only used
+for informational purposes by the guest).
+
+
++----------------------+--------------------+---------------+
+| Subsystem Device ID  |   Virtio Device    | Specification |
++----------------------+--------------------+---------------+
++----------------------+--------------------+---------------+
+|          1           |   network card     |  Appendix C   |
++----------------------+--------------------+---------------+
+|          2           |   block device     |  Appendix D   |
++----------------------+--------------------+---------------+
+|          3           |      console       |  Appendix E   |
++----------------------+--------------------+---------------+
+|          4           |  entropy source    |  Appendix F   |
++----------------------+--------------------+---------------+
+|          5           | memory ballooning  |  Appendix G   |
++----------------------+--------------------+---------------+
+|          6           |     ioMemory       |       -       |
++----------------------+--------------------+---------------+
+|          9           |   9P transport     |       -       |
++----------------------+--------------------+---------------+
+
+
+  Device Configuration
+
+To configure the device, we use the first I/O region of the PCI
+device. This contains a virtio header followed by a
+device-specific region.
+
+There may be different widths of accesses to the I/O region; the “
+natural” access method for each field in the virtio header must
+be used (i.e. 32-bit accesses for 32-bit fields, etc), but the
+device-specific region can be accessed using any width accesses,
+and should obtain the same results.
+
+Note that this is possible because while the virtio header is PCI
+(i.e. little) endian, the device-specific region is encoded in
+the native endian of the guest (where such distinction is
+applicable).
+
+  Device Initialization Sequence
+
+We start with an overview of device initialization, then expand
+on the details of the device and how each step is preformed.
+
+  Reset the device. This is not required on initial start up.
+
+  The ACKNOWLEDGE status bit is set: we have noticed the device.
+
+  The DRIVER status bit is set: we know how to drive the device.
+
+  Device-specific setup, including reading the Device Feature
+  Bits, discovery of virtqueues for the device, optional MSI-X
+  setup, and reading and possibly writing the virtio
+  configuration space.
+
+  The subset of Device Feature Bits understood by the driver is
+  written to the device.
+
+  The DRIVER_OK status bit is set.
+
+  The device can now be used (ie. buffers added to the
+  virtqueues)[footnote:
+Historically, drivers have used the device before steps 5 and 6.
+This is only allowed if the driver does not use any features
+which would alter this early use of the device.
+]
+
+If any of these steps go irrecoverably wrong, the guest should
+set the FAILED status bit to indicate that it has given up on the
+device (it can reset the device later to restart if desired).
+
+We now cover the fields required for general setup in detail.
+
+  Virtio Header
+
+The virtio header looks as follows:
+
+
++------------++---------------------+---------------------+----------+--------+---------+---------+---------+--------+
+| Bits       || 32                  | 32                  | 32       | 16     | 16      | 16      | 8       | 8      |
++------------++---------------------+---------------------+----------+--------+---------+---------+---------+--------+
+| Read/Write || R                   | R+W                 | R+W      | R      | R+W     | R+W     | R+W     | R      |
++------------++---------------------+---------------------+----------+--------+---------+---------+---------+--------+
+| Purpose    || Device              | Guest               | Queue    | Queue  | Queue   | Queue   | Device  | ISR    |
+|            || Features bits 0:31  | Features bits 0:31  | Address  | Size   | Select  | Notify  | Status  | Status |
++------------++---------------------+---------------------+----------+--------+---------+---------+---------+--------+
+
+
+If MSI-X is enabled for the device, two additional fields
+immediately follow this header:
+
+
++------------++----------------+--------+
+| Bits       || 16             | 16     |
+              +----------------+--------+
++------------++----------------+--------+
+| Read/Write || R+W            | R+W    |
++------------++----------------+--------+
+| Purpose    || Configuration  | Queue  |
+| (MSI-X)    || Vector         | Vector |
++------------++----------------+--------+
+
+
+Finally, if feature bits (VIRTIO_F_FEATURES_HI) this is
+immediately followed by two additional fields:
+
+
++------------++----------------------+----------------------
+| Bits       || 32                   | 32
++------------++----------------------+----------------------
+| Read/Write || R                    | R+W
++------------++----------------------+----------------------
+| Purpose    || Device               | Guest
+|            || Features bits 32:63  | Features bits 32:63
++------------++----------------------+----------------------
+
+
+Immediately following these general headers, there may be
+device-specific headers:
+
+
++------------++--------------------+
+| Bits       || Device Specific    |
+              +--------------------+
++------------++--------------------+
+| Read/Write || Device Specific    |
++------------++--------------------+
+| Purpose    || Device Specific... |
+|            ||                    |
++------------++--------------------+
+
+
+  Device Status
+
+The Device Status field is updated by the guest to indicate its
+progress. This provides a simple low-level diagnostic: it's most
+useful to imagine them hooked up to traffic lights on the console
+indicating the status of each device.
+
+The device can be reset by writing a 0 to this field, otherwise
+at least one bit should be set:
+
+  ACKNOWLEDGE (1) Indicates that the guest OS has found the
+  device and recognized it as a valid virtio device.
+
+  DRIVER (2) Indicates that the guest OS knows how to drive the
+  device. Under Linux, drivers can be loadable modules so there
+  may be a significant (or infinite) delay before setting this
+  bit.
+
+  DRIVER_OK (3) Indicates that the driver is set up and ready to
+  drive the device.
+
+  FAILED (8) Indicates that something went wrong in the guest,
+  and it has given up on the device. This could be an internal
+  error, or the driver didn't like the device for some reason, or
+  even a fatal error during device operation. The device must be
+  reset before attempting to re-initialize.
+
+  Feature Bits
+
+The least significant 31 bits of the first configuration field
+indicates the features that the device supports (the high bit is
+reserved, and will be used to indicate the presence of future
+feature bits elsewhere). If more than 31 feature bits are
+supported, the device indicates so by setting feature bit 31 (see
+[cha:Reserved-Feature-Bits]). The bits are allocated as follows:
+
+  0 to 23 Feature bits for the specific device type
+
+  24 to 40 Feature bits reserved for extensions to the queue and
+  feature negotiation mechanisms
+
+  41 to 63 Feature bits reserved for future extensions
+
+For example, feature bit 0 for a network device (i.e. Subsystem
+Device ID 1) indicates that the device supports checksumming of
+packets.
+
+The feature bits are negotiated: the device lists all the
+features it understands in the Device Features field, and the
+guest writes the subset that it understands into the Guest
+Features field. The only way to renegotiate is to reset the
+device.
+
+In particular, new fields in the device configuration header are
+indicated by offering a feature bit, so the guest can check
+before accessing that part of the configuration space.
+
+This allows for forwards and backwards compatibility: if the
+device is enhanced with a new feature bit, older guests will not
+write that feature bit back to the Guest Features field and it
+can go into backwards compatibility mode. Similarly, if a guest
+is enhanced with a feature that the device doesn't support, it
+will not see that feature bit in the Device Features field and
+can go into backwards compatibility mode (or, for poor
+implementations, set the FAILED Device Status bit).
+
+Access to feature bits 32 to 63 is enabled by Guest by setting
+feature bit 31. If this bit is unset, Device must assume that all
+feature bits > 31 are unset.
+
+  Configuration/Queue Vectors
+
+When MSI-X capability is present and enabled in the device
+(through standard PCI configuration space) 4 bytes at byte offset
+20 are used to map configuration change and queue interrupts to
+MSI-X vectors. In this case, the ISR Status field is unused, and
+device specific configuration starts at byte offset 24 in virtio
+header structure. When MSI-X capability is not enabled, device
+specific configuration starts at byte offset 20 in virtio header.
+
+Writing a valid MSI-X Table entry number, 0 to 0x7FF, to one of
+Configuration/Queue Vector registers, maps interrupts triggered
+by the configuration change/selected queue events respectively to
+the corresponding MSI-X vector. To disable interrupts for a
+specific event type, unmap it by writing a special NO_VECTOR
+value:
+
+/* Vector value used to disable MSI for queue */
+
+#define VIRTIO_MSI_NO_VECTOR            0xffff
+
+Reading these registers returns vector mapped to a given event,
+or NO_VECTOR if unmapped. All queue and configuration change
+events are unmapped by default.
+
+Note that mapping an event to vector might require allocating
+internal device resources, and might fail. Devices report such
+failures by returning the NO_VECTOR value when the relevant
+Vector field is read. After mapping an event to vector, the
+driver must verify success by reading the Vector field value: on
+success, the previously written value is returned, and on
+failure, NO_VECTOR is returned. If a mapping failure is detected,
+the driver can retry mapping with fewervectors, or disable MSI-X.
+
+  Virtqueue Configuration
+
+As a device can have zero or more virtqueues for bulk data
+transport (for example, the network driver has two), the driver
+needs to configure them as part of the device-specific
+configuration.
+
+This is done as follows, for each virtqueue a device has:
+
+  Write the virtqueue index (first queue is 0) to the Queue
+  Select field.
+
+  Read the virtqueue size from the Queue Size field, which is
+  always a power of 2. This controls how big the virtqueue is
+  (see below). If this field is 0, the virtqueue does not exist.
+
+  Allocate and zero virtqueue in contiguous physical memory, on a
+  4096 byte alignment. Write the physical address, divided by
+  4096 to the Queue Address field.[footnote:
+The 4096 is based on the x86 page size, but it's also large
+enough to ensure that the separate parts of the virtqueue are on
+separate cache lines.
+]
+
+  Optionally, if MSI-X capability is present and enabled on the
+  device, select a vector to use to request interrupts triggered
+  by virtqueue events. Write the MSI-X Table entry number
+  corresponding to this vector in Queue Vector field. Read the
+  Queue Vector field: on success, previously written value is
+  returned; on failure, NO_VECTOR value is returned.
+
+The Queue Size field controls the total number of bytes required
+for the virtqueue according to the following formula:
+
+#define ALIGN(x) (((x) + 4095) & ~4095)
+
+static inline unsigned vring_size(unsigned int qsz)
+
+{
+
+     return ALIGN(sizeof(struct vring_desc)*qsz + sizeof(u16)*(2
++ qsz))
+
+          + ALIGN(sizeof(struct vring_used_elem)*qsz);
+
+}
+
+This currently wastes some space with padding, but also allows
+future extensions. The virtqueue layout structure looks like this
+(qsz is the Queue Size field, which is a variable, so this code
+won't compile):
+
+struct vring {
+
+    /* The actual descriptors (16 bytes each) */
+
+    struct vring_desc desc[qsz];
+
+
+
+    /* A ring of available descriptor heads with free-running
+index. */
+
+    struct vring_avail avail;
+
+
+
+    // Padding to the next 4096 boundary.
+
+    char pad[];
+
+
+
+    // A ring of used descriptor heads with free-running index.
+
+    struct vring_used used;
+
+};
+
+  A Note on Virtqueue Endianness
+
+Note that the endian of these fields and everything else in the
+virtqueue is the native endian of the guest, not little-endian as
+PCI normally is. This makes for simpler guest code, and it is
+assumed that the host already has to be deeply aware of the guest
+endian so such an “endian-aware” device is not a significant
+issue.
+
+  Descriptor Table
+
+The descriptor table refers to the buffers the guest is using for
+the device. The addresses are physical addresses, and the buffers
+can be chained via the next field. Each descriptor describes a
+buffer which is read-only or write-only, but a chain of
+descriptors can contain both read-only and write-only buffers.
+
+No descriptor chain may be more than 2^32 bytes long in total.struct vring_desc {
+
+    /* Address (guest-physical). */
+
+    u64 addr;
+
+    /* Length. */
+
+    u32 len;
+
+/* This marks a buffer as continuing via the next field. */
+
+#define VRING_DESC_F_NEXT   1
+
+/* This marks a buffer as write-only (otherwise read-only). */
+
+#define VRING_DESC_F_WRITE     2
+
+/* This means the buffer contains a list of buffer descriptors.
+*/
+
+#define VRING_DESC_F_INDIRECT   4
+
+    /* The flags as indicated above. */
+
+    u16 flags;
+
+    /* Next field if flags & NEXT */
+
+    u16 next;
+
+};
+
+The number of descriptors in the table is specified by the Queue
+Size field for this virtqueue.
+
+  <sub:Indirect-Descriptors>Indirect Descriptors
+
+Some devices benefit by concurrently dispatching a large number
+of large requests. The VIRTIO_RING_F_INDIRECT_DESC feature can be
+used to allow this (see [cha:Reserved-Feature-Bits]). To increase
+ring capacity it is possible to store a table of indirect
+descriptors anywhere in memory, and insert a descriptor in main
+virtqueue (with flags&INDIRECT on) that refers to memory buffer
+containing this indirect descriptor table; fields addr and len
+refer to the indirect table address and length in bytes,
+respectively. The indirect table layout structure looks like this
+(len is the length of the descriptor that refers to this table,
+which is a variable, so this code won't compile):
+
+struct indirect_descriptor_table {
+
+    /* The actual descriptors (16 bytes each) */
+
+    struct vring_desc desc[len / 16];
+
+};
+
+The first indirect descriptor is located at start of the indirect
+descriptor table (index 0), additional indirect descriptors are
+chained by next field. An indirect descriptor without next field
+(with flags&NEXT off) signals the end of the indirect descriptor
+table, and transfers control back to the main virtqueue. An
+indirect descriptor can not refer to another indirect descriptor
+table (flags&INDIRECT must be off). A single indirect descriptor
+table can include both read-only and write-only descriptors;
+write-only flag (flags&WRITE) in the descriptor that refers to it
+is ignored.
+
+  Available Ring
+
+The available ring refers to what descriptors we are offering the
+device: it refers to the head of a descriptor chain. The “flags”
+field is currently 0 or 1: 1 indicating that we do not need an
+interrupt when the device consumes a descriptor from the
+available ring. Alternatively, the guest can ask the device to
+delay interrupts until an entry with an index specified by the “
+used_event” field is written in the used ring (equivalently,
+until the idx field in the used ring will reach the value
+used_event + 1). The method employed by the device is controlled
+by the VIRTIO_RING_F_EVENT_IDX feature bit (see [cha:Reserved-Feature-Bits]
+). This interrupt suppression is merely an optimization; it may
+not suppress interrupts entirely.
+
+The “idx” field indicates where we would put the next descriptor
+entry (modulo the ring size). This starts at 0, and increases.
+
+struct vring_avail {
+
+#define VRING_AVAIL_F_NO_INTERRUPT      1
+
+   u16 flags;
+
+   u16 idx;
+
+   u16 ring[qsz]; /* qsz is the Queue Size field read from device
+*/
+
+   u16 used_event;
+
+};
+
+  Used Ring
+
+The used ring is where the device returns buffers once it is done
+with them. The flags field can be used by the device to hint that
+no notification is necessary when the guest adds to the available
+ring. Alternatively, the “avail_event” field can be used by the
+device to hint that no notification is necessary until an entry
+with an index specified by the “avail_event” is written in the
+available ring (equivalently, until the idx field in the
+available ring will reach the value avail_event + 1). The method
+employed by the device is controlled by the guest through the
+VIRTIO_RING_F_EVENT_IDX feature bit (see [cha:Reserved-Feature-Bits]
+). [footnote:
+These fields are kept here because this is the only part of the
+virtqueue written by the device
+].
+
+Each entry in the ring is a pair: the head entry of the
+descriptor chain describing the buffer (this matches an entry
+placed in the available ring by the guest earlier), and the total
+of bytes written into the buffer. The latter is extremely useful
+for guests using untrusted buffers: if you do not know exactly
+how much has been written by the device, you usually have to zero
+the buffer to ensure no data leakage occurs.
+
+/* u32 is used here for ids for padding reasons. */
+
+struct vring_used_elem {
+
+    /* Index of start of used descriptor chain. */
+
+    u32 id;
+
+    /* Total length of the descriptor chain which was used
+(written to) */
+
+    u32 len;
+
+};
+
+
+
+struct vring_used {
+
+#define VRING_USED_F_NO_NOTIFY  1
+
+    u16 flags;
+
+    u16 idx;
+
+    struct vring_used_elem ring[qsz];
+
+    u16 avail_event;
+
+};
+
+  Helpers for Managing Virtqueues
+
+The Linux Kernel Source code contains the definitions above and
+helper routines in a more usable form, in
+include/linux/virtio_ring.h. This was explicitly licensed by IBM
+and Red Hat under the (3-clause) BSD license so that it can be
+freely used by all other projects, and is reproduced (with slight
+variation to remove Linux assumptions) in Appendix A.
+
+  Device Operation
+
+There are two parts to device operation: supplying new buffers to
+the device, and processing used buffers from the device. As an
+example, the virtio network device has two virtqueues: the
+transmit virtqueue and the receive virtqueue. The driver adds
+outgoing (read-only) packets to the transmit virtqueue, and then
+frees them after they are used. Similarly, incoming (write-only)
+buffers are added to the receive virtqueue, and processed after
+they are used.
+
+  Supplying Buffers to The Device
+
+Actual transfer of buffers from the guest OS to the device
+operates as follows:
+
+  Place the buffer(s) into free descriptor(s).
+
+  If there are no free descriptors, the guest may choose to
+    notify the device even if notifications are suppressed (to
+    reduce latency).[footnote:
+The Linux drivers do this only for read-only buffers: for
+write-only buffers, it is assumed that the driver is merely
+trying to keep the receive buffer ring full, and no notification
+of this expected condition is necessary.
+]
+
+  Place the id of the buffer in the next ring entry of the
+  available ring.
+
+  The steps (1) and (2) may be performed repeatedly if batching
+  is possible.
+
+  A memory barrier should be executed to ensure the device sees
+  the updated descriptor table and available ring before the next
+  step.
+
+  The available “idx” field should be increased by the number of
+  entries added to the available ring.
+
+  A memory barrier should be executed to ensure that we update
+  the idx field before checking for notification suppression.
+
+  If notifications are not suppressed, the device should be
+  notified of the new buffers.
+
+Note that the above code does not take precautions against the
+available ring buffer wrapping around: this is not possible since
+the ring buffer is the same size as the descriptor table, so step
+(1) will prevent such a condition.
+
+In addition, the maximum queue size is 32768 (it must be a power
+of 2 which fits in 16 bits), so the 16-bit “idx” value can always
+distinguish between a full and empty buffer.
+
+Here is a description of each stage in more detail.
+
+  Placing Buffers Into The Descriptor Table
+
+A buffer consists of zero or more read-only physically-contiguous
+elements followed by zero or more physically-contiguous
+write-only elements (it must have at least one element). This
+algorithm maps it into the descriptor table:
+
+  for each buffer element, b:
+
+  Get the next free descriptor table entry, d
+
+  Set d.addr to the physical address of the start of b
+
+  Set d.len to the length of b.
+
+  If b is write-only, set d.flags to VRING_DESC_F_WRITE,
+    otherwise 0.
+
+  If there is a buffer element after this:
+
+    Set d.next to the index of the next free descriptor element.
+
+    Set the VRING_DESC_F_NEXT bit in d.flags.
+
+In practice, the d.next fields are usually used to chain free
+descriptors, and a separate count kept to check there are enough
+free descriptors before beginning the mappings.
+
+  Updating The Available Ring
+
+The head of the buffer we mapped is the first d in the algorithm
+above. A naive implementation would do the following:
+
+avail->ring[avail->idx % qsz] = head;
+
+However, in general we can add many descriptors before we update
+the “idx” field (at which point they become visible to the
+device), so we keep a counter of how many we've added:
+
+avail->ring[(avail->idx + added++) % qsz] = head;
+
+  Updating The Index Field
+
+Once the idx field of the virtqueue is updated, the device will
+be able to access the descriptor entries we've created and the
+memory they refer to. This is why a memory barrier is generally
+used before the idx update, to ensure it sees the most up-to-date
+copy.
+
+The idx field always increments, and we let it wrap naturally at
+65536:
+
+avail->idx += added;
+
+  <sub:Notifying-The-Device>Notifying The Device
+
+Device notification occurs by writing the 16-bit virtqueue index
+of this virtqueue to the Queue Notify field of the virtio header
+in the first I/O region of the PCI device. This can be expensive,
+however, so the device can suppress such notifications if it
+doesn't need them. We have to be careful to expose the new idx
+value before checking the suppression flag: it's OK to notify
+gratuitously, but not to omit a required notification. So again,
+we use a memory barrier here before reading the flags or the
+avail_event field.
+
+If the VIRTIO_F_RING_EVENT_IDX feature is not negotiated, and if
+the VRING_USED_F_NOTIFY flag is not set, we go ahead and write to
+the PCI configuration space.
+
+If the VIRTIO_F_RING_EVENT_IDX feature is negotiated, we read the
+avail_event field in the available ring structure. If the
+available index crossed_the avail_event field value since the
+last notification, we go ahead and write to the PCI configuration
+space. The avail_event field wraps naturally at 65536 as well:
+
+(u16)(new_idx - avail_event - 1) < (u16)(new_idx - old_idx)
+
+  <sub:Receiving-Used-Buffers>Receiving Used Buffers From The
+  Device
+
+Once the device has used a buffer (read from or written to it, or
+parts of both, depending on the nature of the virtqueue and the
+device), it sends an interrupt, following an algorithm very
+similar to the algorithm used for the driver to send the device a
+buffer:
+
+  Write the head descriptor number to the next field in the used
+  ring.
+
+  Update the used ring idx.
+
+  Determine whether an interrupt is necessary:
+
+  If the VIRTIO_F_RING_EVENT_IDX feature is not negotiated: check
+    if f the VRING_AVAIL_F_NO_INTERRUPT flag is not set in avail-
+    >flags
+
+  If the VIRTIO_F_RING_EVENT_IDX feature is negotiated: check
+    whether the used index crossed the used_event field value
+    since the last update. The used_event field wraps naturally
+    at 65536 as well:(u16)(new_idx - used_event - 1) < (u16)(new_idx - old_idx)
+
+  If an interrupt is necessary:
+
+  If MSI-X capability is disabled:
+
+    Set the lower bit of the ISR Status field for the device.
+
+    Send the appropriate PCI interrupt for the device.
+
+  If MSI-X capability is enabled:
+
+    Request the appropriate MSI-X interrupt message for the
+      device, Queue Vector field sets the MSI-X Table entry
+      number.
+
+    If Queue Vector field value is NO_VECTOR, no interrupt
+      message is requested for this event.
+
+The guest interrupt handler should:
+
+  If MSI-X capability is disabled: read the ISR Status field,
+  which will reset it to zero. If the lower bit is zero, the
+  interrupt was not for this device. Otherwise, the guest driver
+  should look through the used rings of each virtqueue for the
+  device, to see if any progress has been made by the device
+  which requires servicing.
+
+  If MSI-X capability is enabled: look through the used rings of
+  each virtqueue mapped to the specific MSI-X vector for the
+  device, to see if any progress has been made by the device
+  which requires servicing.
+
+For each ring, guest should then disable interrupts by writing
+VRING_AVAIL_F_NO_INTERRUPT flag in avail structure, if required.
+It can then process used ring entries finally enabling interrupts
+by clearing the VRING_AVAIL_F_NO_INTERRUPT flag or updating the
+EVENT_IDX field in the available structure, Guest should then
+execute a memory barrier, and then recheck the ring empty
+condition. This is necessary to handle the case where, after the
+last check and before enabling interrupts, an interrupt has been
+suppressed by the device:
+
+vring_disable_interrupts(vq);
+
+for (;;) {
+
+    if (vq->last_seen_used != vring->used.idx) {
+
+               vring_enable_interrupts(vq);
+
+               mb();
+
+               if (vq->last_seen_used != vring->used.idx)
+
+                       break;
+
+    }
+
+    struct vring_used_elem *e =
+vring.used->ring[vq->last_seen_used%vsz];
+
+    process_buffer(e);
+
+    vq->last_seen_used++;
+
+}
+
+  Dealing With Configuration Changes
+
+Some virtio PCI devices can change the device configuration
+state, as reflected in the virtio header in the PCI configuration
+space. In this case:
+
+  If MSI-X capability is disabled: an interrupt is delivered and
+  the second highest bit is set in the ISR Status field to
+  indicate that the driver should re-examine the configuration
+  space.Note that a single interrupt can indicate both that one
+  or more virtqueue has been used and that the configuration
+  space has changed: even if the config bit is set, virtqueues
+  must be scanned.
+
+  If MSI-X capability is enabled: an interrupt message is
+  requested. The Configuration Vector field sets the MSI-X Table
+  entry number to use. If Configuration Vector field value is
+  NO_VECTOR, no interrupt message is requested for this event.
+
+Creating New Device Types
+
+Various considerations are necessary when creating a new device
+type:
+
+  How Many Virtqueues?
+
+It is possible that a very simple device will operate entirely
+through its configuration space, but most will need at least one
+virtqueue in which it will place requests. A device with both
+input and output (eg. console and network devices described here)
+need two queues: one which the driver fills with buffers to
+receive input, and one which the driver places buffers to
+transmit output.
+
+  What Configuration Space Layout?
+
+Configuration space is generally used for rarely-changing or
+initialization-time parameters. But it is a limited resource, so
+it might be better to use a virtqueue to update configuration
+information (the network device does this for filtering,
+otherwise the table in the config space could potentially be very
+large).
+
+Note that this space is generally the guest's native endian,
+rather than PCI's little-endian.
+
+  What Device Number?
+
+Currently device numbers are assigned quite freely: a simple
+request mail to the author of this document or the Linux
+virtualization mailing list[footnote:
+
+https://lists.linux-foundation.org/mailman/listinfo/virtualization
+] will be sufficient to secure a unique one.
+
+Meanwhile for experimental drivers, use 65535 and work backwards.
+
+  How many MSI-X vectors?
+
+Using the optional MSI-X capability devices can speed up
+interrupt processing by removing the need to read ISR Status
+register by guest driver (which might be an expensive operation),
+reducing interrupt sharing between devices and queues within the
+device, and handling interrupts from multiple CPUs. However, some
+systems impose a limit (which might be as low as 256) on the
+total number of MSI-X vectors that can be allocated to all
+devices. Devices and/or device drivers should take this into
+account, limiting the number of vectors used unless the device is
+expected to cause a high volume of interrupts. Devices can
+control the number of vectors used by limiting the MSI-X Table
+Size or not presenting MSI-X capability in PCI configuration
+space. Drivers can control this by mapping events to as small
+number of vectors as possible, or disabling MSI-X capability
+altogether.
+
+  Message Framing
+
+The descriptors used for a buffer should not effect the semantics
+of the message, except for the total length of the buffer. For
+example, a network buffer consists of a 10 byte header followed
+by the network packet. Whether this is presented in the ring
+descriptor chain as (say) a 10 byte buffer and a 1514 byte
+buffer, or a single 1524 byte buffer, or even three buffers,
+should have no effect.
+
+In particular, no implementation should use the descriptor
+boundaries to determine the size of any header in a request.[footnote:
+The current qemu device implementations mistakenly insist that
+the first descriptor cover the header in these cases exactly, so
+a cautious driver should arrange it so.
+]
+
+  Device Improvements
+
+Any change to configuration space, or new virtqueues, or
+behavioural changes, should be indicated by negotiation of a new
+feature bit. This establishes clarity[footnote:
+Even if it does mean documenting design or implementation
+mistakes!
+] and avoids future expansion problems.
+
+Clusters of functionality which are always implemented together
+can use a single bit, but if one feature makes sense without the
+others they should not be gratuitously grouped together to
+conserve feature bits. We can always extend the spec when the
+first person needs more than 24 feature bits for their device.
+
+[LaTeX Command: printnomenclature]
+
+Appendix A: virtio_ring.h
+
+#ifndef VIRTIO_RING_H
+
+#define VIRTIO_RING_H
+
+/* An interface for efficient virtio implementation.
+
+ *
+
+ * This header is BSD licensed so anyone can use the definitions
+
+ * to implement compatible drivers/servers.
+
+ *
+
+ * Copyright 2007, 2009, IBM Corporation
+
+ * Copyright 2011, Red Hat, Inc
+
+ * All rights reserved.
+
+ *
+
+ * Redistribution and use in source and binary forms, with or
+without
+
+ * modification, are permitted provided that the following
+conditions
+
+ * are met:
+
+ * 1. Redistributions of source code must retain the above
+copyright
+
+ *    notice, this list of conditions and the following
+disclaimer.
+
+ * 2. Redistributions in binary form must reproduce the above
+copyright
+
+ *    notice, this list of conditions and the following
+disclaimer in the
+
+ *    documentation and/or other materials provided with the
+distribution.
+
+ * 3. Neither the name of IBM 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 IBM 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.
+
+ */
+
+
+
+/* This marks a buffer as continuing via the next field. */
+
+#define VRING_DESC_F_NEXT       1
+
+/* This marks a buffer as write-only (otherwise read-only). */
+
+#define VRING_DESC_F_WRITE      2
+
+
+
+/* The Host uses this in used->flags to advise the Guest: don't
+kick me
+
+ * when you add a buffer.  It's unreliable, so it's simply an
+
+ * optimization.  Guest will still kick if it's out of buffers.
+*/
+
+#define VRING_USED_F_NO_NOTIFY  1
+
+/* The Guest uses this in avail->flags to advise the Host: don't
+
+ * interrupt me when you consume a buffer.  It's unreliable, so
+it's
+
+ * simply an optimization.  */
+
+#define VRING_AVAIL_F_NO_INTERRUPT      1
+
+
+
+/* Virtio ring descriptors: 16 bytes.
+
+ * These can chain together via "next". */
+
+struct vring_desc {
+
+        /* Address (guest-physical). */
+
+        uint64_t addr;
+
+        /* Length. */
+
+        uint32_t len;
+
+        /* The flags as indicated above. */
+
+        uint16_t flags;
+
+        /* We chain unused descriptors via this, too */
+
+        uint16_t next;
+
+};
+
+
+
+struct vring_avail {
+
+        uint16_t flags;
+
+        uint16_t idx;
+
+        uint16_t ring[];
+
+        uint16_t used_event;
+
+};
+
+
+
+/* u32 is used here for ids for padding reasons. */
+
+struct vring_used_elem {
+
+        /* Index of start of used descriptor chain. */
+
+        uint32_t id;
+
+        /* Total length of the descriptor chain which was written
+to. */
+
+        uint32_t len;
+
+};
+
+
+
+struct vring_used {
+
+        uint16_t flags;
+
+        uint16_t idx;
+
+        struct vring_used_elem ring[];
+
+        uint16_t avail_event;
+
+};
+
+
+
+struct vring {
+
+        unsigned int num;
+
+
+
+        struct vring_desc *desc;
+
+        struct vring_avail *avail;
+
+        struct vring_used *used;
+
+};
+
+
+
+/* The standard layout for the ring is a continuous chunk of
+memory which
+
+ * looks like this.  We assume num is a power of 2.
+
+ *
+
+ * struct vring {
+
+ *      // The actual descriptors (16 bytes each)
+
+ *      struct vring_desc desc[num];
+
+ *
+
+ *      // A ring of available descriptor heads with free-running
+index.
+
+ *      __u16 avail_flags;
+
+ *      __u16 avail_idx;
+
+ *      __u16 available[num];
+
+ *
+
+ *      // Padding to the next align boundary.
+
+ *      char pad[];
+
+ *
+
+ *      // A ring of used descriptor heads with free-running
+index.
+
+ *      __u16 used_flags;
+
+ *      __u16 EVENT_IDX;
+
+ *      struct vring_used_elem used[num];
+
+ * };
+
+ * Note: for virtio PCI, align is 4096.
+
+ */
+
+static inline void vring_init(struct vring *vr, unsigned int num,
+void *p,
+
+                              unsigned long align)
+
+{
+
+        vr->num = num;
+
+        vr->desc = p;
+
+        vr->avail = p + num*sizeof(struct vring_desc);
+
+        vr->used = (void *)(((unsigned long)&vr->avail->ring[num]
+
+                              + align-1)
+
+                            & ~(align - 1));
+
+}
+
+
+
+static inline unsigned vring_size(unsigned int num, unsigned long
+align)
+
+{
+
+        return ((sizeof(struct vring_desc)*num +
+sizeof(uint16_t)*(2+num)
+
+                 + align - 1) & ~(align - 1))
+
+                + sizeof(uint16_t)*3 + sizeof(struct
+vring_used_elem)*num;
+
+}
+
+
+
+static inline int vring_need_event(uint16_t event_idx, uint16_t
+new_idx, uint16_t old_idx)
+
+{
+
+         return (uint16_t)(new_idx - event_idx - 1) <
+(uint16_t)(new_idx - old_idx);
+
+}
+
+#endif /* VIRTIO_RING_H */
+
+<cha:Reserved-Feature-Bits>Appendix B: Reserved Feature Bits
+
+Currently there are five device-independent feature bits defined:
+
+  VIRTIO_F_NOTIFY_ON_EMPTY (24) Negotiating this feature
+  indicates that the driver wants an interrupt if the device runs
+  out of available descriptors on a virtqueue, even though
+  interrupts are suppressed using the VRING_AVAIL_F_NO_INTERRUPT
+  flag or the used_event field. An example of this is the
+  networking driver: it doesn't need to know every time a packet
+  is transmitted, but it does need to free the transmitted
+  packets a finite time after they are transmitted. It can avoid
+  using a timer if the device interrupts it when all the packets
+  are transmitted.
+
+  VIRTIO_F_RING_INDIRECT_DESC (28) Negotiating this feature
+  indicates that the driver can use descriptors with the
+  VRING_DESC_F_INDIRECT flag set, as described in [sub:Indirect-Descriptors]
+  .
+
+  VIRTIO_F_RING_EVENT_IDX(29) This feature enables the used_event
+  and the avail_event fields. If set, it indicates that the
+  device should ignore the flags field in the available ring
+  structure. Instead, the used_event field in this structure is
+  used by guest to suppress device interrupts. Further, the
+  driver should ignore the flags field in the used ring
+  structure. Instead, the avail_event field in this structure is
+  used by the device to suppress notifications. If unset, the
+  driver should ignore the used_event field; the device should
+  ignore the avail_event field; the flags field is used
+
+  VIRTIO_F_BAD_FEATURE(30) This feature should never be
+  negotiated by the guest; doing so is an indication that the
+  guest is faulty[footnote:
+An experimental virtio PCI driver contained in Linux version
+2.6.25 had this problem, and this feature bit can be used to
+detect it.
+]
+
+  VIRTIO_F_FEATURES_HIGH(31) This feature indicates that the
+  device supports feature bits 32:63. If unset, feature bits
+  32:63 are unset.
+
+Appendix C: Network Device
+
+The virtio network device is a virtual ethernet card, and is the
+most complex of the devices supported so far by virtio. It has
+enhanced rapidly and demonstrates clearly how support for new
+features should be added to an existing device. Empty buffers are
+placed in one virtqueue for receiving packets, and outgoing
+packets are enqueued into another for transmission in that order.
+A third command queue is used to control advanced filtering
+features.
+
+  Configuration
+
+  Subsystem Device ID 1
+
+  Virtqueues 0:receiveq. 1:transmitq. 2:controlq[footnote:
+Only if VIRTIO_NET_F_CTRL_VQ set
+]
+
+  Feature bits
+
+  VIRTIO_NET_F_CSUM (0) Device handles packets with partial
+    checksum
+
+  VIRTIO_NET_F_GUEST_CSUM (1) Guest handles packets with partial
+    checksum
+
+  VIRTIO_NET_F_MAC (5) Device has given MAC address.
+
+  VIRTIO_NET_F_GSO (6) (Deprecated) device handles packets with
+    any GSO type.[footnote:
+It was supposed to indicate segmentation offload support, but
+upon further investigation it became clear that multiple bits
+were required.
+]
+
+  VIRTIO_NET_F_GUEST_TSO4 (7) Guest can receive TSOv4.
+
+  VIRTIO_NET_F_GUEST_TSO6 (8) Guest can receive TSOv6.
+
+  VIRTIO_NET_F_GUEST_ECN (9) Guest can receive TSO with ECN.
+
+  VIRTIO_NET_F_GUEST_UFO (10) Guest can receive UFO.
+
+  VIRTIO_NET_F_HOST_TSO4 (11) Device can receive TSOv4.
+
+  VIRTIO_NET_F_HOST_TSO6 (12) Device can receive TSOv6.
+
+  VIRTIO_NET_F_HOST_ECN (13) Device can receive TSO with ECN.
+
+  VIRTIO_NET_F_HOST_UFO (14) Device can receive UFO.
+
+  VIRTIO_NET_F_MRG_RXBUF (15) Guest can merge receive buffers.
+
+  VIRTIO_NET_F_STATUS (16) Configuration status field is
+    available.
+
+  VIRTIO_NET_F_CTRL_VQ (17) Control channel is available.
+
+  VIRTIO_NET_F_CTRL_RX (18) Control channel RX mode support.
+
+  VIRTIO_NET_F_CTRL_VLAN (19) Control channel VLAN filtering.
+
+  Device configuration layout Two configuration fields are
+  currently defined. The mac address field always exists (though
+  is only valid if VIRTIO_NET_F_MAC is set), and the status field
+  only exists if VIRTIO_NET_F_STATUS is set. Only one bit is
+  currently defined for the status field: VIRTIO_NET_S_LINK_UP. #define VIRTIO_NET_S_LINK_UP   1
+
+
+
+struct virtio_net_config {
+
+    u8 mac[6];
+
+    u16 status;
+
+};
+
+  Device Initialization
+
+  The initialization routine should identify the receive and
+  transmission virtqueues.
+
+  If the VIRTIO_NET_F_MAC feature bit is set, the configuration
+  space “mac” entry indicates the “physical” address of the the
+  network card, otherwise a private MAC address should be
+  assigned. All guests are expected to negotiate this feature if
+  it is set.
+
+  If the VIRTIO_NET_F_CTRL_VQ feature bit is negotiated, identify
+  the control virtqueue.
+
+  If the VIRTIO_NET_F_STATUS feature bit is negotiated, the link
+  status can be read from the bottom bit of the “status” config
+  field. Otherwise, the link should be assumed active.
+
+  The receive virtqueue should be filled with receive buffers.
+  This is described in detail below in “Setting Up Receive
+  Buffers”.
+
+  A driver can indicate that it will generate checksumless
+  packets by negotating the VIRTIO_NET_F_CSUM feature. This “
+  checksum offload” is a common feature on modern network cards.
+
+  If that feature is negotiated, a driver can use TCP or UDP
+  segmentation offload by negotiating the VIRTIO_NET_F_HOST_TSO4
+  (IPv4 TCP), VIRTIO_NET_F_HOST_TSO6 (IPv6 TCP) and
+  VIRTIO_NET_F_HOST_UFO (UDP fragmentation) features. It should
+  not send TCP packets requiring segmentation offload which have
+  the Explicit Congestion Notification bit set, unless the
+  VIRTIO_NET_F_HOST_ECN feature is negotiated.[footnote:
+This is a common restriction in real, older network cards.
+]
+
+  The converse features are also available: a driver can save the
+  virtual device some work by negotiating these features.[footnote:
+For example, a network packet transported between two guests on
+the same system may not require checksumming at all, nor
+segmentation, if both guests are amenable.
+] The VIRTIO_NET_F_GUEST_CSUM feature indicates that partially
+  checksummed packets can be received, and if it can do that then
+  the VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6,
+  VIRTIO_NET_F_GUEST_UFO and VIRTIO_NET_F_GUEST_ECN are the input
+  equivalents of the features described above. See “Receiving
+  Packets” below.
+
+  Device Operation
+
+Packets are transmitted by placing them in the transmitq, and
+buffers for incoming packets are placed in the receiveq. In each
+case, the packet itself is preceeded by a header:
+
+struct virtio_net_hdr {
+
+#define VIRTIO_NET_HDR_F_NEEDS_CSUM    1
+
+       u8 flags;
+
+#define VIRTIO_NET_HDR_GSO_NONE        0
+
+#define VIRTIO_NET_HDR_GSO_TCPV4       1
+
+#define VIRTIO_NET_HDR_GSO_UDP          3
+
+#define VIRTIO_NET_HDR_GSO_TCPV6       4
+
+#define VIRTIO_NET_HDR_GSO_ECN      0x80
+
+       u8 gso_type;
+
+       u16 hdr_len;
+
+       u16 gso_size;
+
+       u16 csum_start;
+
+       u16 csum_offset;
+
+/* Only if VIRTIO_NET_F_MRG_RXBUF: */
+
+       u16 num_buffers
+
+};
+
+The controlq is used to control device features such as
+filtering.
+
+  Packet Transmission
+
+Transmitting a single packet is simple, but varies depending on
+the different features the driver negotiated.
+
+  If the driver negotiated VIRTIO_NET_F_CSUM, and the packet has
+  not been fully checksummed, then the virtio_net_hdr's fields
+  are set as follows. Otherwise, the packet must be fully
+  checksummed, and flags is zero.
+
+  flags has the VIRTIO_NET_HDR_F_NEEDS_CSUM set,
+
+  <ite:csum_start-is-set>csum_start is set to the offset within
+    the packet to begin checksumming, and
+
+  csum_offset indicates how many bytes after the csum_start the
+    new (16 bit ones' complement) checksum should be placed.[footnote:
+For example, consider a partially checksummed TCP (IPv4) packet.
+It will have a 14 byte ethernet header and 20 byte IP header
+followed by the TCP header (with the TCP checksum field 16 bytes
+into that header). csum_start will be 14+20 = 34 (the TCP
+checksum includes the header), and csum_offset will be 16. The
+value in the TCP checksum field will be the sum of the TCP pseudo
+header, so that replacing it by the ones' complement checksum of
+the TCP header and body will give the correct result.
+]
+
+  <enu:If-the-driver>If the driver negotiated
+  VIRTIO_NET_F_HOST_TSO4, TSO6 or UFO, and the packet requires
+  TCP segmentation or UDP fragmentation, then the “gso_type”
+  field is set to VIRTIO_NET_HDR_GSO_TCPV4, TCPV6 or UDP.
+  (Otherwise, it is set to VIRTIO_NET_HDR_GSO_NONE). In this
+  case, packets larger than 1514 bytes can be transmitted: the
+  metadata indicates how to replicate the packet header to cut it
+  into smaller packets. The other gso fields are set:
+
+  hdr_len is a hint to the device as to how much of the header
+    needs to be kept to copy into each packet, usually set to the
+    length of the headers, including the transport header.[footnote:
+Due to various bugs in implementations, this field is not useful
+as a guarantee of the transport header size.
+]
+
+  gso_size is the size of the packet beyond that header (ie.
+    MSS).
+
+  If the driver negotiated the VIRTIO_NET_F_HOST_ECN feature, the
+    VIRTIO_NET_HDR_GSO_ECN bit may be set in “gso_type” as well,
+    indicating that the TCP packet has the ECN bit set.[footnote:
+This case is not handled by some older hardware, so is called out
+specifically in the protocol.
+]
+
+  If the driver negotiated the VIRTIO_NET_F_MRG_RXBUF feature,
+  the num_buffers field is set to zero.
+
+  The header and packet are added as one output buffer to the
+  transmitq, and the device is notified of the new entry (see [sub:Notifying-The-Device]
+  ).[footnote:
+Note that the header will be two bytes longer for the
+VIRTIO_NET_F_MRG_RXBUF case.
+]
+
+  Packet Transmission Interrupt
+
+Often a driver will suppress transmission interrupts using the
+VRING_AVAIL_F_NO_INTERRUPT flag (see [sub:Receiving-Used-Buffers]
+) and check for used packets in the transmit path of following
+packets. However, it will still receive interrupts if the
+VIRTIO_F_NOTIFY_ON_EMPTY feature is negotiated, indicating that
+the transmission queue is completely emptied.
+
+The normal behavior in this interrupt handler is to retrieve and
+new descriptors from the used ring and free the corresponding
+headers and packets.
+
+  Setting Up Receive Buffers
+
+It is generally a good idea to keep the receive virtqueue as
+fully populated as possible: if it runs out, network performance
+will suffer.
+
+If the VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6 or
+VIRTIO_NET_F_GUEST_UFO features are used, the Guest will need to
+accept packets of up to 65550 bytes long (the maximum size of a
+TCP or UDP packet, plus the 14 byte ethernet header), otherwise
+1514 bytes. So unless VIRTIO_NET_F_MRG_RXBUF is negotiated, every
+buffer in the receive queue needs to be at least this length [footnote:
+Obviously each one can be split across multiple descriptor
+elements.
+].
+
+If VIRTIO_NET_F_MRG_RXBUF is negotiated, each buffer must be at
+least the size of the struct virtio_net_hdr.
+
+  Packet Receive Interrupt
+
+When a packet is copied into a buffer in the receiveq, the
+optimal path is to disable further interrupts for the receiveq
+(see [sub:Receiving-Used-Buffers]) and process packets until no
+more are found, then re-enable them.
+
+Processing packet involves:
+
+  If the driver negotiated the VIRTIO_NET_F_MRG_RXBUF feature,
+  then the “num_buffers” field indicates how many descriptors
+  this packet is spread over (including this one). This allows
+  receipt of large packets without having to allocate large
+  buffers. In this case, there will be at least “num_buffers” in
+  the used ring, and they should be chained together to form a
+  single packet. The other buffers will not begin with a struct
+  virtio_net_hdr.
+
+  If the VIRTIO_NET_F_MRG_RXBUF feature was not negotiated, or
+  the “num_buffers” field is one, then the entire packet will be
+  contained within this buffer, immediately following the struct
+  virtio_net_hdr.
+
+  If the VIRTIO_NET_F_GUEST_CSUM feature was negotiated, the
+  VIRTIO_NET_HDR_F_NEEDS_CSUM bit in the “flags” field may be
+  set: if so, the checksum on the packet is incomplete and the “
+  csum_start” and “csum_offset” fields indicate how to calculate
+  it (see [ite:csum_start-is-set]).
+
+  If the VIRTIO_NET_F_GUEST_TSO4, TSO6 or UFO options were
+  negotiated, then the “gso_type” may be something other than
+  VIRTIO_NET_HDR_GSO_NONE, and the “gso_size” field indicates the
+  desired MSS (see [enu:If-the-driver]).Control Virtqueue
+
+The driver uses the control virtqueue (if VIRTIO_NET_F_VTRL_VQ is
+negotiated) to send commands to manipulate various features of
+the device which would not easily map into the configuration
+space.
+
+All commands are of the following form:
+
+struct virtio_net_ctrl {
+
+       u8 class;
+
+       u8 command;
+
+       u8 command-specific-data[];
+
+       u8 ack;
+
+};
+
+
+
+/* ack values */
+
+#define VIRTIO_NET_OK     0
+
+#define VIRTIO_NET_ERR    1
+
+The class, command and command-specific-data are set by the
+driver, and the device sets the ack byte. There is little it can
+do except issue a diagnostic if the ack byte is not
+VIRTIO_NET_OK.
+
+  Packet Receive Filtering
+
+If the VIRTIO_NET_F_CTRL_RX feature is negotiated, the driver can
+send control commands for promiscuous mode, multicast receiving,
+and filtering of MAC addresses.
+
+Note that in general, these commands are best-effort: unwanted
+packets may still arrive.
+
+  Setting Promiscuous Mode
+
+#define VIRTIO_NET_CTRL_RX    0
+
+ #define VIRTIO_NET_CTRL_RX_PROMISC      0
+
+ #define VIRTIO_NET_CTRL_RX_ALLMULTI     1
+
+The class VIRTIO_NET_CTRL_RX has two commands:
+VIRTIO_NET_CTRL_RX_PROMISC turns promiscuous mode on and off, and
+VIRTIO_NET_CTRL_RX_ALLMULTI turns all-multicast receive on and
+off. The command-specific-data is one byte containing 0 (off) or
+1 (on).
+
+  Setting MAC Address Filtering
+
+struct virtio_net_ctrl_mac {
+
+       u32 entries;
+
+       u8 macs[entries][ETH_ALEN];
+
+};
+
+
+
+#define VIRTIO_NET_CTRL_MAC    1
+
+ #define VIRTIO_NET_CTRL_MAC_TABLE_SET        0
+
+The device can filter incoming packets by any number of
+destination MAC addresses.[footnote:
+Since there are no guarentees, it can use a hash filter
+orsilently switch to allmulti or promiscuous mode if it is given
+too many addresses.
+] This table is set using the class VIRTIO_NET_CTRL_MAC and the
+command VIRTIO_NET_CTRL_MAC_TABLE_SET. The command-specific-data
+is two variable length tables of 6-byte MAC addresses. The first
+table contains unicast addresses, and the second contains
+multicast addresses.
+
+  VLAN Filtering
+
+If the driver negotiates the VIRTION_NET_F_CTRL_VLAN feature, it
+can control a VLAN filter table in the device.
+
+#define VIRTIO_NET_CTRL_VLAN       2
+
+ #define VIRTIO_NET_CTRL_VLAN_ADD             0
+
+ #define VIRTIO_NET_CTRL_VLAN_DEL             1
+
+Both the VIRTIO_NET_CTRL_VLAN_ADD and VIRTIO_NET_CTRL_VLAN_DEL
+command take a 16-bit VLAN id as the command-specific-data.
+
+Appendix D: Block Device
+
+The virtio block device is a simple virtual block device (ie.
+disk). Read and write requests (and other exotic requests) are
+placed in the queue, and serviced (probably out of order) by the
+device except where noted.
+
+  Configuration
+
+  Subsystem Device ID 2
+
+  Virtqueues 0:requestq.
+
+  Feature bits
+
+  VIRTIO_BLK_F_BARRIER (0) Host supports request barriers.
+
+  VIRTIO_BLK_F_SIZE_MAX (1) Maximum size of any single segment is
+    in “size_max”.
+
+  VIRTIO_BLK_F_SEG_MAX (2) Maximum number of segments in a
+    request is in “seg_max”.
+
+  VIRTIO_BLK_F_GEOMETRY (4) Disk-style geometry specified in “
+    geometry”.
+
+  VIRTIO_BLK_F_RO (5) Device is read-only.
+
+  VIRTIO_BLK_F_BLK_SIZE (6) Block size of disk is in “blk_size”.
+
+  VIRTIO_BLK_F_SCSI (7) Device supports scsi packet commands.
+
+  VIRTIO_BLK_F_FLUSH (9) Cache flush command support.
+
+
+
+  Device configuration layout The capacity of the device
+  (expressed in 512-byte sectors) is always present. The
+  availability of the others all depend on various feature bits
+  as indicated above. struct virtio_blk_config {
+
+       u64 capacity;
+
+       u32 size_max;
+
+       u32 seg_max;
+
+       struct virtio_blk_geometry {
+
+               u16 cylinders;
+
+               u8 heads;
+
+               u8 sectors;
+
+       } geometry;
+
+       u32 blk_size;
+
+
+
+};
+
+  Device Initialization
+
+  The device size should be read from the “capacity”
+  configuration field. No requests should be submitted which goes
+  beyond this limit.
+
+  If the VIRTIO_BLK_F_BLK_SIZE feature is negotiated, the
+  blk_size field can be read to determine the optimal sector size
+  for the driver to use. This does not effect the units used in
+  the protocol (always 512 bytes), but awareness of the correct
+  value can effect performance.
+
+  If the VIRTIO_BLK_F_RO feature is set by the device, any write
+  requests will fail.
+
+
+
+  Device Operation
+
+The driver queues requests to the virtqueue, and they are used by
+the device (not necessarily in order). Each request is of form:
+
+struct virtio_blk_req {
+
+
+
+       u32 type;
+
+       u32 ioprio;
+
+       u64 sector;
+
+       char data[][512];
+
+       u8 status;
+
+};
+
+If the device has VIRTIO_BLK_F_SCSI feature, it can also support
+scsi packet command requests, each of these requests is of form:struct virtio_scsi_pc_req {
+
+       u32 type;
+
+       u32 ioprio;
+
+       u64 sector;
+
+    char cmd[];
+
+       char data[][512];
+
+#define SCSI_SENSE_BUFFERSIZE   96
+
+    u8 sense[SCSI_SENSE_BUFFERSIZE];
+
+    u32 errors;
+
+    u32 data_len;
+
+    u32 sense_len;
+
+    u32 residual;
+
+       u8 status;
+
+};
+
+The type of the request is either a read (VIRTIO_BLK_T_IN), a
+write (VIRTIO_BLK_T_OUT), a scsi packet command
+(VIRTIO_BLK_T_SCSI_CMD or VIRTIO_BLK_T_SCSI_CMD_OUT[footnote:
+the SCSI_CMD and SCSI_CMD_OUT types are equivalent, the device
+does not distinguish between them
+]) or a flush (VIRTIO_BLK_T_FLUSH or VIRTIO_BLK_T_FLUSH_OUT[footnote:
+the FLUSH and FLUSH_OUT types are equivalent, the device does not
+distinguish between them
+]). If the device has VIRTIO_BLK_F_BARRIER feature the high bit
+(VIRTIO_BLK_T_BARRIER) indicates that this request acts as a
+barrier and that all preceeding requests must be complete before
+this one, and all following requests must not be started until
+this is complete. Note that a barrier does not flush caches in
+the underlying backend device in host, and thus does not serve as
+data consistency guarantee. Driver must use FLUSH request to
+flush the host cache.
+
+#define VIRTIO_BLK_T_IN           0
+
+#define VIRTIO_BLK_T_OUT          1
+
+#define VIRTIO_BLK_T_SCSI_CMD     2
+
+#define VIRTIO_BLK_T_SCSI_CMD_OUT 3
+
+#define VIRTIO_BLK_T_FLUSH        4
+
+#define VIRTIO_BLK_T_FLUSH_OUT    5
+
+#define VIRTIO_BLK_T_BARRIER    0x80000000
+
+The ioprio field is a hint about the relative priorities of
+requests to the device: higher numbers indicate more important
+requests.
+
+The sector number indicates the offset (multiplied by 512) where
+the read or write is to occur. This field is unused and set to 0
+for scsi packet commands and for flush commands.
+
+The cmd field is only present for scsi packet command requests,
+and indicates the command to perform. This field must reside in a
+single, separate read-only buffer; command length can be derived
+from the length of this buffer.
+
+Note that these first three (four for scsi packet commands)
+fields are always read-only: the data field is either read-only
+or write-only, depending on the request. The size of the read or
+write can be derived from the total size of the request buffers.
+
+The sense field is only present for scsi packet command requests,
+and indicates the buffer for scsi sense data.
+
+The data_len field is only present for scsi packet command
+requests, this field is deprecated, and should be ignored by the
+driver. Historically, devices copied data length there.
+
+The sense_len field is only present for scsi packet command
+requests and indicates the number of bytes actually written to
+the sense buffer.
+
+The residual field is only present for scsi packet command
+requests and indicates the residual size, calculated as data
+length - number of bytes actually transferred.
+
+The final status byte is written by the device: either
+VIRTIO_BLK_S_OK for success, VIRTIO_BLK_S_IOERR for host or guest
+error or VIRTIO_BLK_S_UNSUPP for a request unsupported by host:#define VIRTIO_BLK_S_OK        0
+
+#define VIRTIO_BLK_S_IOERR     1
+
+#define VIRTIO_BLK_S_UNSUPP    2
+
+Historically, devices assumed that the fields type, ioprio and
+sector reside in a single, separate read-only buffer; the fields
+errors, data_len, sense_len and residual reside in a single,
+separate write-only buffer; the sense field in a separate
+write-only buffer of size 96 bytes, by itself; the fields errors,
+data_len, sense_len and residual in a single write-only buffer;
+and the status field is a separate read-only buffer of size 1
+byte, by itself.
+
+Appendix E: Console Device
+
+The virtio console device is a simple device for data input and
+output. A device may have one or more ports. Each port has a pair
+of input and output virtqueues. Moreover, a device has a pair of
+control IO virtqueues. The control virtqueues are used to
+communicate information between the device and the driver about
+ports being opened and closed on either side of the connection,
+indication from the host about whether a particular port is a
+console port, adding new ports, port hot-plug/unplug, etc., and
+indication from the guest about whether a port or a device was
+successfully added, port open/close, etc.. For data IO, one or
+more empty buffers are placed in the receive queue for incoming
+data and outgoing characters are placed in the transmit queue.
+
+  Configuration
+
+  Subsystem Device ID 3
+
+  Virtqueues 0:receiveq(port0). 1:transmitq(port0), 2:control
+  receiveq[footnote:
+Ports 2 onwards only if VIRTIO_CONSOLE_F_MULTIPORT is set
+], 3:control transmitq, 4:receiveq(port1), 5:transmitq(port1),
+  ...
+
+  Feature bits
+
+  VIRTIO_CONSOLE_F_SIZE (0) Configuration cols and rows fields
+    are valid.
+
+  VIRTIO_CONSOLE_F_MULTIPORT(1) Device has support for multiple
+    ports; configuration fields nr_ports and max_nr_ports are
+    valid and control virtqueues will be used.
+
+  Device configuration layout The size of the console is supplied
+  in the configuration space if the VIRTIO_CONSOLE_F_SIZE feature
+  is set. Furthermore, if the VIRTIO_CONSOLE_F_MULTIPORT feature
+  is set, the maximum number of ports supported by the device can
+  be fetched.struct virtio_console_config {
+
+       u16 cols;
+
+       u16 rows;
+
+
+
+       u32 max_nr_ports;
+
+};
+
+  Device Initialization
+
+  If the VIRTIO_CONSOLE_F_SIZE feature is negotiated, the driver
+  can read the console dimensions from the configuration fields.
+
+  If the VIRTIO_CONSOLE_F_MULTIPORT feature is negotiated, the
+  driver can spawn multiple ports, not all of which may be
+  attached to a console. Some could be generic ports. In this
+  case, the control virtqueues are enabled and according to the
+  max_nr_ports configuration-space value, the appropriate number
+  of virtqueues are created. A control message indicating the
+  driver is ready is sent to the host. The host can then send
+  control messages for adding new ports to the device. After
+  creating and initializing each port, a
+  VIRTIO_CONSOLE_PORT_READY control message is sent to the host
+  for that port so the host can let us know of any additional
+  configuration options set for that port.
+
+  The receiveq for each port is populated with one or more
+  receive buffers.
+
+  Device Operation
+
+  For output, a buffer containing the characters is placed in the
+  port's transmitq.[footnote:
+Because this is high importance and low bandwidth, the current
+Linux implementation polls for the buffer to be used, rather than
+waiting for an interrupt, simplifying the implementation
+significantly. However, for generic serial ports with the
+O_NONBLOCK flag set, the polling limitation is relaxed and the
+consumed buffers are freed upon the next write or poll call or
+when a port is closed or hot-unplugged.
+]
+
+  When a buffer is used in the receiveq (signalled by an
+  interrupt), the contents is the input to the port associated
+  with the virtqueue for which the notification was received.
+
+  If the driver negotiated the VIRTIO_CONSOLE_F_SIZE feature, a
+  configuration change interrupt may occur. The updated size can
+  be read from the configuration fields.
+
+  If the driver negotiated the VIRTIO_CONSOLE_F_MULTIPORT
+  feature, active ports are announced by the host using the
+  VIRTIO_CONSOLE_PORT_ADD control message. The same message is
+  used for port hot-plug as well.
+
+  If the host specified a port `name', a sysfs attribute is
+  created with the name filled in, so that udev rules can be
+  written that can create a symlink from the port's name to the
+  char device for port discovery by applications in the guest.
+
+  Changes to ports' state are effected by control messages.
+  Appropriate action is taken on the port indicated in the
+  control message. The layout of the structure of the control
+  buffer and the events associated are:struct virtio_console_control {
+
+       uint32_t id;    /* Port number */
+
+       uint16_t event; /* The kind of control event */
+
+       uint16_t value; /* Extra information for the event */
+
+};
+
+
+
+/* Some events for the internal messages (control packets) */
+
+
+
+#define VIRTIO_CONSOLE_DEVICE_READY     0
+
+#define VIRTIO_CONSOLE_PORT_ADD         1
+
+#define VIRTIO_CONSOLE_PORT_REMOVE      2
+
+#define VIRTIO_CONSOLE_PORT_READY       3
+
+#define VIRTIO_CONSOLE_CONSOLE_PORT     4
+
+#define VIRTIO_CONSOLE_RESIZE           5
+
+#define VIRTIO_CONSOLE_PORT_OPEN        6
+
+#define VIRTIO_CONSOLE_PORT_NAME        7
+
+Appendix F: Entropy Device
+
+The virtio entropy device supplies high-quality randomness for
+guest use.
+
+  Configuration
+
+  Subsystem Device ID 4
+
+  Virtqueues 0:requestq.
+
+  Feature bits None currently defined
+
+  Device configuration layout None currently defined.
+
+  Device Initialization
+
+  The virtqueue is initialized
+
+  Device Operation
+
+When the driver requires random bytes, it places the descriptor
+of one or more buffers in the queue. It will be completely filled
+by random data by the device.
+
+Appendix G: Memory Balloon Device
+
+The virtio memory balloon device is a primitive device for
+managing guest memory: the device asks for a certain amount of
+memory, and the guest supplies it (or withdraws it, if the device
+has more than it asks for). This allows the guest to adapt to
+changes in allowance of underlying physical memory. If the
+feature is negotiated, the device can also be used to communicate
+guest memory statistics to the host.
+
+  Configuration
+
+  Subsystem Device ID 5
+
+  Virtqueues 0:inflateq. 1:deflateq. 2:statsq.[footnote:
+Only if VIRTIO_BALLON_F_STATS_VQ set
+]
+
+  Feature bits
+
+  VIRTIO_BALLOON_F_MUST_TELL_HOST (0) Host must be told before
+    pages from the balloon are used.
+
+  VIRTIO_BALLOON_F_STATS_VQ (1) A virtqueue for reporting guest
+    memory statistics is present.
+
+  Device configuration layout Both fields of this configuration
+  are always available. Note that they are little endian, despite
+  convention that device fields are guest endian:struct virtio_balloon_config {
+
+       u32 num_pages;
+
+       u32 actual;
+
+};
+
+  Device Initialization
+
+  The inflate and deflate virtqueues are identified.
+
+  If the VIRTIO_BALLOON_F_STATS_VQ feature bit is negotiated:
+
+  Identify the stats virtqueue.
+
+  Add one empty buffer to the stats virtqueue and notify the
+    host.
+
+Device operation begins immediately.
+
+  Device Operation
+
+  Memory Ballooning The device is driven by the receipt of a
+  configuration change interrupt.
+
+  The “num_pages” configuration field is examined. If this is
+  greater than the “actual” number of pages, memory must be given
+  to the balloon. If it is less than the “actual” number of
+  pages, memory may be taken back from the balloon for general
+  use.
+
+  To supply memory to the balloon (aka. inflate):
+
+  The driver constructs an array of addresses of unused memory
+    pages. These addresses are divided by 4096[footnote:
+This is historical, and independent of the guest page size
+] and the descriptor describing the resulting 32-bit array is
+    added to the inflateq.
+
+  To remove memory from the balloon (aka. deflate):
+
+  The driver constructs an array of addresses of memory pages it
+    has previously given to the balloon, as described above. This
+    descriptor is added to the deflateq.
+
+  If the VIRTIO_BALLOON_F_MUST_TELL_HOST feature is set, the
+    guest may not use these requested pages until that descriptor
+    in the deflateq has been used by the device.
+
+  Otherwise, the guest may begin to re-use pages previously given
+    to the balloon before the device has acknowledged their
+    withdrawl. [footnote:
+In this case, deflation advice is merely a courtesy
+]
+
+  In either case, once the device has completed the inflation or
+  deflation, the “actual” field of the configuration should be
+  updated to reflect the new number of pages in the balloon.[footnote:
+As updates to configuration space are not atomic, this field
+isn't particularly reliable, but can be used to diagnose buggy
+guests.
+]
+
+  Memory Statistics
+
+The stats virtqueue is atypical because communication is driven
+by the device (not the driver). The channel becomes active at
+driver initialization time when the driver adds an empty buffer
+and notifies the device. A request for memory statistics proceeds
+as follows:
+
+  The device pushes the buffer onto the used ring and sends an
+  interrupt.
+
+  The driver pops the used buffer and discards it.
+
+  The driver collects memory statistics and writes them into a
+  new buffer.
+
+  The driver adds the buffer to the virtqueue and notifies the
+  device.
+
+  The device pops the buffer (retaining it to initiate a
+  subsequent request) and consumes the statistics.
+
+  Memory Statistics Format Each statistic consists of a 16 bit
+  tag and a 64 bit value. Both quantities are represented in the
+  native endian of the guest. All statistics are optional and the
+  driver may choose which ones to supply. To guarantee backwards
+  compatibility, unsupported statistics should be omitted.
+
+  struct virtio_balloon_stat {
+
+#define VIRTIO_BALLOON_S_SWAP_IN  0
+
+#define VIRTIO_BALLOON_S_SWAP_OUT 1
+
+#define VIRTIO_BALLOON_S_MAJFLT   2
+
+#define VIRTIO_BALLOON_S_MINFLT   3
+
+#define VIRTIO_BALLOON_S_MEMFREE  4
+
+#define VIRTIO_BALLOON_S_MEMTOT   5
+
+       u16 tag;
+
+       u64 val;
+
+} __attribute__((packed));
+
+  Tags
+
+  VIRTIO_BALLOON_S_SWAP_IN The amount of memory that has been
+  swapped in (in bytes).
+
+  VIRTIO_BALLOON_S_SWAP_OUT The amount of memory that has been
+  swapped out to disk (in bytes).
+
+  VIRTIO_BALLOON_S_MAJFLT The number of major page faults that
+  have occurred.
+
+  VIRTIO_BALLOON_S_MINFLT The number of minor page faults that
+  have occurred.
+
+  VIRTIO_BALLOON_S_MEMFREE The amount of memory not being used
+  for any purpose (in bytes).
+
+  VIRTIO_BALLOON_S_MEMTOT The total amount of memory available
+  (in bytes).
+
index ee99451..fc51128 100644 (file)
@@ -8,6 +8,8 @@ src/
        - directory holding watchdog related example programs.
 watchdog-api.txt
        - description of the Linux Watchdog driver API.
+watchdog-kernel-api.txt
+       - description of the Linux WatchDog Timer Driver Core kernel API.
 watchdog-parameters.txt
        - information on driver parameters (for drivers other than
          the ones that have driver-specific files here)
diff --git a/Documentation/watchdog/watchdog-kernel-api.txt b/Documentation/watchdog/watchdog-kernel-api.txt
new file mode 100644 (file)
index 0000000..4f7c894
--- /dev/null
@@ -0,0 +1,162 @@
+The Linux WatchDog Timer Driver Core kernel API.
+===============================================
+Last reviewed: 22-Jul-2011
+
+Wim Van Sebroeck <wim@iguana.be>
+
+Introduction
+------------
+This document does not describe what a WatchDog Timer (WDT) Driver or Device is.
+It also does not describe the API which can be used by user space to communicate
+with a WatchDog Timer. If you want to know this then please read the following
+file: Documentation/watchdog/watchdog-api.txt .
+
+So what does this document describe? It describes the API that can be used by
+WatchDog Timer Drivers that want to use the WatchDog Timer Driver Core
+Framework. This framework provides all interfacing towards user space so that
+the same code does not have to be reproduced each time. This also means that
+a watchdog timer driver then only needs to provide the different routines
+(operations) that control the watchdog timer (WDT).
+
+The API
+-------
+Each watchdog timer driver that wants to use the WatchDog Timer Driver Core
+must #include <linux/watchdog.h> (you would have to do this anyway when
+writing a watchdog device driver). This include file contains following
+register/unregister routines:
+
+extern int watchdog_register_device(struct watchdog_device *);
+extern void watchdog_unregister_device(struct watchdog_device *);
+
+The watchdog_register_device routine registers a watchdog timer device.
+The parameter of this routine is a pointer to a watchdog_device structure.
+This routine returns zero on success and a negative errno code for failure.
+
+The watchdog_unregister_device routine deregisters a registered watchdog timer
+device. The parameter of this routine is the pointer to the registered
+watchdog_device structure.
+
+The watchdog device structure looks like this:
+
+struct watchdog_device {
+       const struct watchdog_info *info;
+       const struct watchdog_ops *ops;
+       unsigned int bootstatus;
+       unsigned int timeout;
+       unsigned int min_timeout;
+       unsigned int max_timeout;
+       void *driver_data;
+       unsigned long status;
+};
+
+It contains following fields:
+* info: a pointer to a watchdog_info structure. This structure gives some
+  additional information about the watchdog timer itself. (Like it's unique name)
+* ops: a pointer to the list of watchdog operations that the watchdog supports.
+* timeout: the watchdog timer's timeout value (in seconds).
+* min_timeout: the watchdog timer's minimum timeout value (in seconds).
+* max_timeout: the watchdog timer's maximum timeout value (in seconds).
+* bootstatus: status of the device after booting (reported with watchdog
+  WDIOF_* status bits).
+* driver_data: a pointer to the drivers private data of a watchdog device.
+  This data should only be accessed via the watchdog_set_drvadata and
+  watchdog_get_drvdata routines.
+* status: this field contains a number of status bits that give extra
+  information about the status of the device (Like: is the watchdog timer
+  running/active, is the nowayout bit set, is the device opened via
+  the /dev/watchdog interface or not, ...).
+
+The list of watchdog operations is defined as:
+
+struct watchdog_ops {
+       struct module *owner;
+       /* mandatory operations */
+       int (*start)(struct watchdog_device *);
+       int (*stop)(struct watchdog_device *);
+       /* optional operations */
+       int (*ping)(struct watchdog_device *);
+       unsigned int (*status)(struct watchdog_device *);
+       int (*set_timeout)(struct watchdog_device *, unsigned int);
+       long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
+};
+
+It is important that you first define the module owner of the watchdog timer
+driver's operations. This module owner will be used to lock the module when
+the watchdog is active. (This to avoid a system crash when you unload the
+module and /dev/watchdog is still open).
+Some operations are mandatory and some are optional. The mandatory operations
+are:
+* start: this is a pointer to the routine that starts the watchdog timer
+  device.
+  The routine needs a pointer to the watchdog timer device structure as a
+  parameter. It returns zero on success or a negative errno code for failure.
+* stop: with this routine the watchdog timer device is being stopped.
+  The routine needs a pointer to the watchdog timer device structure as a
+  parameter. It returns zero on success or a negative errno code for failure.
+  Some watchdog timer hardware can only be started and not be stopped. The
+  driver supporting this hardware needs to make sure that a start and stop
+  routine is being provided. This can be done by using a timer in the driver
+  that regularly sends a keepalive ping to the watchdog timer hardware.
+
+Not all watchdog timer hardware supports the same functionality. That's why
+all other routines/operations are optional. They only need to be provided if
+they are supported. These optional routines/operations are:
+* ping: this is the routine that sends a keepalive ping to the watchdog timer
+  hardware.
+  The routine needs a pointer to the watchdog timer device structure as a
+  parameter. It returns zero on success or a negative errno code for failure.
+  Most hardware that does not support this as a separate function uses the
+  start function to restart the watchdog timer hardware. And that's also what
+  the watchdog timer driver core does: to send a keepalive ping to the watchdog
+  timer hardware it will either use the ping operation (when available) or the
+  start operation (when the ping operation is not available).
+  (Note: the WDIOC_KEEPALIVE ioctl call will only be active when the
+  WDIOF_KEEPALIVEPING bit has been set in the option field on the watchdog's
+  info structure).
+* status: this routine checks the status of the watchdog timer device. The
+  status of the device is reported with watchdog WDIOF_* status flags/bits.
+* set_timeout: this routine checks and changes the timeout of the watchdog
+  timer device. It returns 0 on success, -EINVAL for "parameter out of range"
+  and -EIO for "could not write value to the watchdog". On success the timeout
+  value of the watchdog_device will be changed to the value that was just used
+  to re-program the watchdog timer device.
+  (Note: the WDIOF_SETTIMEOUT needs to be set in the options field of the
+  watchdog's info structure).
+* ioctl: if this routine is present then it will be called first before we do
+  our own internal ioctl call handling. This routine should return -ENOIOCTLCMD
+  if a command is not supported. The parameters that are passed to the ioctl
+  call are: watchdog_device, cmd and arg.
+
+The status bits should (preferably) be set with the set_bit and clear_bit alike
+bit-operations. The status bits that are defined are:
+* WDOG_ACTIVE: this status bit indicates whether or not a watchdog timer device
+  is active or not. When the watchdog is active after booting, then you should
+  set this status bit (Note: when you register the watchdog timer device with
+  this bit set, then opening /dev/watchdog will skip the start operation)
+* WDOG_DEV_OPEN: this status bit shows whether or not the watchdog device
+  was opened via /dev/watchdog.
+  (This bit should only be used by the WatchDog Timer Driver Core).
+* WDOG_ALLOW_RELEASE: this bit stores whether or not the magic close character
+  has been sent (so that we can support the magic close feature).
+  (This bit should only be used by the WatchDog Timer Driver Core).
+* WDOG_NO_WAY_OUT: this bit stores the nowayout setting for the watchdog.
+  If this bit is set then the watchdog timer will not be able to stop.
+
+Note: The WatchDog Timer Driver Core supports the magic close feature and
+the nowayout feature. To use the magic close feature you must set the
+WDIOF_MAGICCLOSE bit in the options field of the watchdog's info structure.
+The nowayout feature will overrule the magic close feature.
+
+To get or set driver specific data the following two helper functions should be
+used:
+
+static inline void watchdog_set_drvdata(struct watchdog_device *wdd, void *data)
+static inline void *watchdog_get_drvdata(struct watchdog_device *wdd)
+
+The watchdog_set_drvdata function allows you to add driver specific data. The
+arguments of this function are the watchdog device where you want to add the
+driver specific data to and a pointer to the data itself.
+
+The watchdog_get_drvdata function allows you to retrieve driver specific data.
+The argument of this function is the watchdog device where you want to retrieve
+data from. The function retruns the pointer to the driver specific data.
index 1d2e79d..c94a898 100644 (file)
@@ -1925,6 +1925,12 @@ S:       Maintained
 F:     arch/x86/kernel/cpuid.c
 F:     arch/x86/kernel/msr.c
 
+CPU POWER MONITORING SUBSYSTEM
+M:     Dominik Brodowski <linux@dominikbrodowski.net>
+M:     Thomas Renninger <trenn@suse.de>
+S:     Maintained
+F:     tools/power/cpupower
+
 CPUSETS
 M:     Paul Menage <menage@google.com>
 W:     http://www.bullopensource.org/cpuset/
@@ -2637,9 +2643,8 @@ S:        Maintained
 F:     arch/x86/math-emu/
 
 FRAME RELAY DLCI/FRAD (Sangoma drivers too)
-M:     Mike McLagan <mike.mclagan@linux.org>
 L:     netdev@vger.kernel.org
-S:     Maintained
+S:     Orphan
 F:     drivers/net/wan/dlci.c
 F:     drivers/net/wan/sdla.c
 
@@ -3361,6 +3366,12 @@ F:       drivers/net/ixgb/
 F:     drivers/net/ixgbe/
 F:     drivers/net/ixgbevf/
 
+INTEL MRST PMU DRIVER
+M:     Len Brown <len.brown@intel.com>
+L:     linux-pm@lists.linux-foundation.org
+S:     Supported
+F:     arch/x86/platform/mrst/pmu.*
+
 INTEL PRO/WIRELESS 2100 NETWORK CONNECTION SUPPORT
 L:     linux-wireless@vger.kernel.org
 S:     Orphan
@@ -3894,9 +3905,9 @@ F:        arch/powerpc/platforms/powermac/
 F:     drivers/macintosh/
 
 LINUX FOR POWERPC EMBEDDED MPC5XXX
-M:     Grant Likely <grant.likely@secretlab.ca>
+M:     Anatolij Gustschin <agust@denx.de>
 L:     linuxppc-dev@lists.ozlabs.org
-T:     git git://git.secretlab.ca/git/linux-2.6.git
+T:     git git://git.denx.de/linux-2.6-agust.git
 S:     Maintained
 F:     arch/powerpc/platforms/512x/
 F:     arch/powerpc/platforms/52xx/
@@ -4150,6 +4161,13 @@ S:       Orphan
 F:     drivers/video/matrox/matroxfb_*
 F:     include/linux/matroxfb.h
 
+MAX1668 TEMPERATURE SENSOR DRIVER
+M:     "David George" <david.george@ska.ac.za>
+L:     lm-sensors@lm-sensors.org
+S:     Maintained
+F:     Documentation/hwmon/max1668
+F:     drivers/hwmon/max1668.c
+
 MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER
 M:     "Hans J. Koch" <hjk@hansjkoch.de>
 L:     lm-sensors@lm-sensors.org
@@ -4396,10 +4414,10 @@ F:      net/*/netfilter/
 F:     net/netfilter/
 
 NETLABEL
-M:     Paul Moore <paul.moore@hp.com>
+M:     Paul Moore <paul@paul-moore.com>
 W:     http://netlabel.sf.net
 L:     netdev@vger.kernel.org
-S:     Supported
+S:     Maintained
 F:     Documentation/netlabel/
 F:     include/net/netlabel.h
 F:     net/netlabel/
@@ -4432,8 +4450,8 @@ M:        "David S. Miller" <davem@davemloft.net>
 L:     netdev@vger.kernel.org
 W:     http://www.linuxfoundation.org/en/Net
 W:     http://patchwork.ozlabs.org/project/netdev/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6.git
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git
 S:     Maintained
 F:     net/
 F:     include/net/
@@ -4444,7 +4462,6 @@ F:        include/linux/netdevice.h
 NETWORKING [IPv4/IPv6]
 M:     "David S. Miller" <davem@davemloft.net>
 M:     Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
-M:     "Pekka Savola (ipv6)" <pekkas@netcore.fi>
 M:     James Morris <jmorris@namei.org>
 M:     Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
 M:     Patrick McHardy <kaber@trash.net>
@@ -4457,7 +4474,7 @@ F:        include/net/ip*
 F:     arch/x86/net/*
 
 NETWORKING [LABELED] (NetLabel, CIPSO, Labeled IPsec, SECMARK)
-M:     Paul Moore <paul.moore@hp.com>
+M:     Paul Moore <paul@paul-moore.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
 
@@ -4587,7 +4604,7 @@ F:        arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
 F:     arch/arm/mach-omap2/clockdomain44xx.c
 
 OMAP AUDIO SUPPORT
-M:     Jarkko Nikula <jhnikula@gmail.com>
+M:     Jarkko Nikula <jarkko.nikula@bitmer.com>
 L:     alsa-devel@alsa-project.org (subscribers-only)
 L:     linux-omap@vger.kernel.org
 S:     Maintained
@@ -4709,6 +4726,7 @@ S:        Maintained
 F:     drivers/of
 F:     include/linux/of*.h
 K:     of_get_property
+K:     of_match_table
 
 OPENRISC ARCHITECTURE
 M:     Jonas Bonn <jonas@southpole.se>
@@ -4953,7 +4971,7 @@ M:        Paul Mackerras <paulus@samba.org>
 M:     Ingo Molnar <mingo@elte.hu>
 M:     Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
 S:     Supported
-F:     kernel/perf_event*.c
+F:     kernel/events/*
 F:     include/linux/perf_event.h
 F:     arch/*/kernel/perf_event*.c
 F:     arch/*/kernel/*/perf_event*.c
@@ -4999,6 +5017,17 @@ F:       drivers/i2c/busses/i2c-puv3.c
 F:     drivers/video/fb-puv3.c
 F:     drivers/rtc/rtc-puv3.c
 
+PMBUS HARDWARE MONITORING DRIVERS
+M:     Guenter Roeck <guenter.roeck@ericsson.com>
+L:     lm-sensors@lm-sensors.org
+W:     http://www.lm-sensors.org/
+W:     http://www.roeck-us.net/linux/drivers/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git
+S:     Maintained
+F:     Documentation/hwmon/pmbus
+F:     drivers/hwmon/pmbus/
+F:     include/linux/i2c/pmbus.h
+
 PMC SIERRA MaxRAID DRIVER
 M:     Anil Ravindranath <anil_ravindranath@pmc-sierra.com>
 L:     linux-scsi@vger.kernel.org
@@ -6294,6 +6323,7 @@ F:        include/linux/sysv_fs.h
 TARGET SUBSYSTEM
 M:     Nicholas A. Bellinger <nab@linux-iscsi.org>
 L:     linux-scsi@vger.kernel.org
+L:     target-devel@vger.kernel.org
 L:     http://groups.google.com/group/linux-iscsi-target-dev
 W:     http://www.linux-iscsi.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/nab/lio-core-2.6.git master
@@ -7327,7 +7357,7 @@ THE REST
 M:     Linus Torvalds <torvalds@linux-foundation.org>
 L:     linux-kernel@vger.kernel.org
 Q:     http://patchwork.kernel.org/project/LKML/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
 S:     Buried alive in reporters
 F:     *
 F:     */
index d018956..788511f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
 VERSION = 3
-PATCHLEVEL = 0
+PATCHLEVEL = 1
 SUBLEVEL = 0
-EXTRAVERSION =
-NAME = Sneaky Weasel
+EXTRAVERSION = -rc3
+NAME = "Divemaster Edition"
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
@@ -360,7 +360,7 @@ CFLAGS_GCOV = -fprofile-arcs -ftest-coverage
 LINUXINCLUDE    := -I$(srctree)/arch/$(hdr-arch)/include \
                    -Iarch/$(hdr-arch)/include/generated -Iinclude \
                    $(if $(KBUILD_SRC), -I$(srctree)/include) \
-                   -include include/generated/autoconf.h
+                   -include $(srctree)/include/linux/kconfig.h
 
 KBUILD_CPPFLAGS := -D__KERNEL__
 
index 26b0e23..4b0669c 100644 (file)
@@ -178,4 +178,7 @@ config HAVE_ARCH_MUTEX_CPU_RELAX
 config HAVE_RCU_TABLE_FREE
        bool
 
+config ARCH_HAVE_NMI_SAFE_CMPXCHG
+       bool
+
 source "kernel/gcov/Kconfig"
index ca2da8d..60cde53 100644 (file)
@@ -14,6 +14,7 @@ config ALPHA
        select AUTO_IRQ_AFFINITY if SMP
        select GENERIC_IRQ_SHOW
        select ARCH_WANT_OPTIONAL_GPIOLIB
+       select ARCH_HAVE_NMI_SAFE_CMPXCHG
        help
          The Alpha is a 64-bit general-purpose processor designed and
          marketed by the Digital Equipment Corporation of blessed memory,
index 0e14399..8606d77 100644 (file)
@@ -183,7 +183,7 @@ alcor_init_irq(void)
  */
 
 static int __init
-alcor_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+alcor_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[7][5] __initdata = {
                /*INT    INTA   INTB   INTC   INTD */
index c8c112d..1029619 100644 (file)
@@ -175,7 +175,7 @@ pc164_init_irq(void)
  */
 
 static inline int __init
-eb66p_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+eb66p_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[5][5] __initdata = {
                /*INT  INTA  INTB  INTC   INTD */
@@ -205,7 +205,7 @@ eb66p_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
  */
 
 static inline int __init
-cabriolet_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+cabriolet_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[5][5] __initdata = {
                /*INT   INTA  INTB  INTC   INTD */
@@ -289,7 +289,7 @@ cia_cab_init_pci(void)
  */
 
 static inline int __init
-alphapc164_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+alphapc164_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[7][5] __initdata = {
                /*INT   INTA  INTB   INTC   INTD */
index f885682..bb7f0c7 100644 (file)
@@ -382,7 +382,7 @@ isa_irq_fixup(struct pci_dev *dev, int irq)
 }
 
 static int __init
-dp264_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+dp264_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[6][5] __initdata = {
                /*INT    INTA   INTB   INTC   INTD */
@@ -404,7 +404,7 @@ dp264_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 }
 
 static int __init
-monet_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+monet_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[13][5] __initdata = {
                /*INT    INTA   INTB   INTC   INTD */
@@ -466,7 +466,7 @@ monet_swizzle(struct pci_dev *dev, u8 *pinp)
 }
 
 static int __init
-webbrick_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+webbrick_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[13][5] __initdata = {
                /*INT    INTA   INTB   INTC   INTD */
@@ -488,7 +488,7 @@ webbrick_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 }
 
 static int __init
-clipper_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+clipper_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[7][5] __initdata = {
                /*INT    INTA   INTB   INTC   INTD */
index a7a23b4..3c6c13c 100644 (file)
@@ -169,7 +169,7 @@ eb64p_init_irq(void)
  */
 
 static int __init
-eb64p_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+eb64p_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[5][5] __initdata = {
                /*INT  INTA  INTB  INTC   INTD */
index a60cd5b..35f480d 100644 (file)
@@ -144,7 +144,7 @@ eiger_init_irq(void)
 }
 
 static int __init
-eiger_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+eiger_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        u8 irq_orig;
 
index 388b99d..95cfc83 100644 (file)
@@ -318,7 +318,7 @@ marvel_init_irq(void)
 }
 
 static int 
-marvel_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+marvel_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        struct pci_controller *hose = dev->sysdata;
        struct io7_port *io7_port = hose->sysdata;
index 61ccd95..258da68 100644 (file)
@@ -151,7 +151,7 @@ miata_init_irq(void)
  */
 
 static int __init
-miata_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+miata_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
         static char irq_tab[18][5] __initdata = {
                /*INT    INTA   INTB   INTC   INTD */
index 0e6e469..c0fd728 100644 (file)
@@ -146,7 +146,7 @@ mikasa_init_irq(void)
  */
 
 static int __init
-mikasa_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+mikasa_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[8][5] __initdata = {
                /*INT    INTA   INTB   INTC   INTD */
index 99c0f46..4112200 100644 (file)
@@ -65,7 +65,7 @@ nautilus_init_irq(void)
 }
 
 static int __init
-nautilus_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+nautilus_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        /* Preserve the IRQ set up by the console.  */
 
index a00ac70..2172528 100644 (file)
@@ -194,7 +194,7 @@ noritake_init_irq(void)
  */
 
 static int __init
-noritake_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+noritake_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[15][5] __initdata = {
                /*INT    INTA   INTB   INTC   INTD */
index 7f52161..a125d6b 100644 (file)
@@ -223,7 +223,7 @@ rawhide_init_irq(void)
  */
 
 static int __init
-rawhide_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+rawhide_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[5][5] __initdata = {
                /*INT    INTA   INTB   INTC   INTD */
index f33648e..2581cbe 100644 (file)
@@ -119,7 +119,7 @@ ruffian_kill_arch (int mode)
  */
 
 static int __init
-ruffian_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+ruffian_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
         static char irq_tab[11][5] __initdata = {
              /*INT  INTA INTB INTC INTD */
index 216d94d..b172b27 100644 (file)
@@ -144,7 +144,7 @@ rx164_init_irq(void)
  */
 
 static int __init
-rx164_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+rx164_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
 #if 0
        static char irq_tab_pass1[6][5] __initdata = {
index da714e4..98d1dbf 100644 (file)
@@ -194,7 +194,7 @@ sable_init_irq(void)
  */
 
 static int __init
-sable_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+sable_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[9][5] __initdata = {
                /*INT    INTA   INTB   INTC   INTD */
@@ -376,7 +376,7 @@ lynx_init_irq(void)
  */
 
 static int __init
-lynx_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+lynx_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[19][5] __initdata = {
                /*INT    INTA   INTB   INTC   INTD */
index 85b4aea..47bec1e 100644 (file)
@@ -146,7 +146,7 @@ sio_fixup_irq_levels(unsigned int level_bits)
 }
 
 static inline int __init
-noname_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+noname_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        /*
         * The Noname board has 5 PCI slots with each of the 4
@@ -185,7 +185,7 @@ noname_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 }
 
 static inline int __init
-p2k_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+p2k_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[][5] __initdata = {
                /*INT A   B   C   D */
index 41d4ad4..73e1c31 100644 (file)
@@ -95,7 +95,7 @@ sx164_init_irq(void)
  */
 
 static int __init
-sx164_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+sx164_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[5][5] __initdata = {
                /*INT    INTA   INTB   INTC   INTD */
index a31f8cd..2ae99ad 100644 (file)
@@ -157,7 +157,7 @@ takara_init_irq(void)
  */
 
 static int __init
-takara_map_irq_srm(struct pci_dev *dev, u8 slot, u8 pin)
+takara_map_irq_srm(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[15][5] __initdata = {
                { 16+3, 16+3, 16+3, 16+3, 16+3},   /* slot  6 == device 3 */
@@ -188,7 +188,7 @@ takara_map_irq_srm(struct pci_dev *dev, u8 slot, u8 pin)
 }
 
 static int __init
-takara_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+takara_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[15][5] __initdata = {
                { 16+3, 16+3, 16+3, 16+3, 16+3},   /* slot  6 == device 3 */
index 6994407..f47b30a 100644 (file)
@@ -305,7 +305,7 @@ titan_late_init(void)
 }
 
 static int __devinit
-titan_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+titan_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        u8 intline;
        int irq;
index d92cdc7..17c85a6 100644 (file)
@@ -290,7 +290,7 @@ wildfire_device_interrupt(unsigned long vector)
  */
 
 static int __init
-wildfire_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+wildfire_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[8][5] __initdata = {
                /*INT    INTA   INTB   INTC   INTD */
index 09ebf0b..5ebc5d9 100644 (file)
@@ -195,8 +195,7 @@ config VECTORS_BASE
          The base address of exception vectors.
 
 config ARM_PATCH_PHYS_VIRT
-       bool "Patch physical to virtual translations at runtime (EXPERIMENTAL)"
-       depends on EXPERIMENTAL
+       bool "Patch physical to virtual translations at runtime"
        depends on !XIP_KERNEL && MMU
        depends on !ARCH_REALVIEW || !SPARSEMEM
        help
@@ -1716,6 +1715,7 @@ config USE_OF
        bool "Flattened Device Tree support"
        select OF
        select OF_EARLY_FLATTREE
+       select IRQ_DOMAIN
        help
          Include support for flattened device tree machine descriptions.
 
index 3a4a04b..70c424e 100644 (file)
@@ -282,6 +282,12 @@ zImage Image xipImage bootpImage uImage: vmlinux
 zinstall uinstall install: vmlinux
        $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@
 
+%.dtb:
+       $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
+
+dtbs:
+       $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
+
 # We use MRPROPER_FILES and CLEAN_FILES now
 archclean:
        $(Q)$(MAKE) $(clean)=$(boot)
@@ -298,6 +304,7 @@ define archhelp
   echo  '  uImage        - U-Boot wrapped zImage'
   echo  '  bootpImage    - Combined zImage and initial RAM disk' 
   echo  '                  (supply initrd image via make variable INITRD=<path>)'
+  echo  '  dtbs          - Build device tree blobs for enabled boards'
   echo  '  install       - Install uncompressed kernel'
   echo  '  zinstall      - Install compressed kernel'
   echo  '  uinstall      - Install U-Boot wrapped compressed kernel'
index 9128fdd..a1edfd5 100644 (file)
@@ -59,6 +59,12 @@ $(obj)/zImage:       $(obj)/compressed/vmlinux FORCE
 
 endif
 
+# Rule to build device tree blobs
+$(obj)/%.dtb: $(src)/dts/%.dts
+       $(call cmd,dtc)
+
+$(obj)/dtbs: $(addprefix $(obj)/, $(dtb-y))
+
 quiet_cmd_uimage = UIMAGE  $@
       cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A arm -O linux -T kernel \
                   -C none -a $(LOADADDR) -e $(STARTADDR) \
diff --git a/arch/arm/boot/dts/skeleton.dtsi b/arch/arm/boot/dts/skeleton.dtsi
new file mode 100644 (file)
index 0000000..b41d241
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Skeleton device tree; the bare minimum needed to boot; just include and
+ * add a compatible value.  The bootloader will typically populate the memory
+ * node.
+ */
+
+/ {
+       #address-cells = <1>;
+       #size-cells = <1>;
+       chosen { };
+       aliases { };
+       memory { device_type = "memory"; reg = <0 0>; };
+};
diff --git a/arch/arm/boot/dts/tegra-harmony.dts b/arch/arm/boot/dts/tegra-harmony.dts
new file mode 100644 (file)
index 0000000..4c05334
--- /dev/null
@@ -0,0 +1,70 @@
+/dts-v1/;
+
+/memreserve/ 0x1c000000 0x04000000;
+/include/ "tegra20.dtsi"
+
+/ {
+       model = "NVIDIA Tegra2 Harmony evaluation board";
+       compatible = "nvidia,harmony", "nvidia,tegra20";
+
+       chosen {
+               bootargs = "vmalloc=192M video=tegrafb console=ttyS0,115200n8 root=/dev/mmcblk0p2 rw rootwait";
+       };
+
+       memory@0 {
+               reg = < 0x00000000 0x40000000 >;
+       };
+
+       i2c@7000c000 {
+               clock-frequency = <400000>;
+
+               codec: wm8903@1a {
+                       compatible = "wlf,wm8903";
+                       reg = <0x1a>;
+                       interrupts = < 347 >;
+
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       /* 0x8000 = Not configured */
+                       gpio-cfg = < 0x8000 0x8000 0 0x8000 0x8000 >;
+               };
+       };
+
+       i2c@7000c400 {
+               clock-frequency = <400000>;
+       };
+
+       i2c@7000c500 {
+               clock-frequency = <400000>;
+       };
+
+       i2c@7000d000 {
+               clock-frequency = <400000>;
+       };
+
+       sound {
+               compatible = "nvidia,harmony-sound", "nvidia,tegra-wm8903";
+
+               spkr-en-gpios = <&codec 2 0>;
+               hp-det-gpios = <&gpio 178 0>;
+               int-mic-en-gpios = <&gpio 184 0>;
+               ext-mic-en-gpios = <&gpio 185 0>;
+       };
+
+       serial@70006300 {
+               clock-frequency = < 216000000 >;
+       };
+
+       sdhci@c8000200 {
+               gpios = <&gpio 69 0>, /* cd, gpio PI5 */
+                       <&gpio 57 0>, /* wp, gpio PH1 */
+                       <&gpio 155 0>; /* power, gpio PT3 */
+       };
+
+       sdhci@c8000600 {
+               gpios = <&gpio 58 0>, /* cd, gpio PH2 */
+                       <&gpio 59 0>, /* wp, gpio PH3 */
+                       <&gpio 70 0>; /* power, gpio PI6 */
+       };
+};
diff --git a/arch/arm/boot/dts/tegra-seaboard.dts b/arch/arm/boot/dts/tegra-seaboard.dts
new file mode 100644 (file)
index 0000000..1940cae
--- /dev/null
@@ -0,0 +1,28 @@
+/dts-v1/;
+
+/memreserve/ 0x1c000000 0x04000000;
+/include/ "tegra20.dtsi"
+
+/ {
+       model = "NVIDIA Seaboard";
+       compatible = "nvidia,seaboard", "nvidia,tegra20";
+
+       chosen {
+               bootargs = "vmalloc=192M video=tegrafb console=ttyS0,115200n8 root=/dev/mmcblk1p3 rw rootwait";
+       };
+
+       memory {
+               device_type = "memory";
+               reg = < 0x00000000 0x40000000 >;
+       };
+
+       serial@70006300 {
+               clock-frequency = < 216000000 >;
+       };
+
+       sdhci@c8000400 {
+               gpios = <&gpio 69 0>, /* cd, gpio PI5 */
+                       <&gpio 57 0>, /* wp, gpio PH1 */
+                       <&gpio 70 0>; /* power, gpio PI6 */
+       };
+};
diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
new file mode 100644 (file)
index 0000000..5727595
--- /dev/null
@@ -0,0 +1,139 @@
+/include/ "skeleton.dtsi"
+
+/ {
+       compatible = "nvidia,tegra20";
+       interrupt-parent = <&intc>;
+
+       intc: interrupt-controller@50041000 {
+               compatible = "nvidia,tegra20-gic";
+               interrupt-controller;
+               #interrupt-cells = <1>;
+               reg = < 0x50041000 0x1000 >,
+                     < 0x50040100 0x0100 >;
+       };
+
+       i2c@7000c000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "nvidia,tegra20-i2c";
+               reg = <0x7000C000 0x100>;
+               interrupts = < 70 >;
+       };
+
+       i2c@7000c400 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "nvidia,tegra20-i2c";
+               reg = <0x7000C400 0x100>;
+               interrupts = < 116 >;
+       };
+
+       i2c@7000c500 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "nvidia,tegra20-i2c";
+               reg = <0x7000C500 0x100>;
+               interrupts = < 124 >;
+       };
+
+       i2c@7000d000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "nvidia,tegra20-i2c";
+               reg = <0x7000D000 0x200>;
+               interrupts = < 85 >;
+       };
+
+       i2s@70002800 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "nvidia,tegra20-i2s";
+               reg = <0x70002800 0x200>;
+               interrupts = < 45 >;
+               dma-channel = < 2 >;
+       };
+
+       i2s@70002a00 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "nvidia,tegra20-i2s";
+               reg = <0x70002a00 0x200>;
+               interrupts = < 35 >;
+               dma-channel = < 1 >;
+       };
+
+       das@70000c00 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "nvidia,tegra20-das";
+               reg = <0x70000c00 0x80>;
+       };
+
+       gpio: gpio@6000d000 {
+               compatible = "nvidia,tegra20-gpio";
+               reg = < 0x6000d000 0x1000 >;
+               interrupts = < 64 65 66 67 87 119 121 >;
+               #gpio-cells = <2>;
+               gpio-controller;
+       };
+
+       serial@70006000 {
+               compatible = "nvidia,tegra20-uart";
+               reg = <0x70006000 0x40>;
+               reg-shift = <2>;
+               interrupts = < 68 >;
+       };
+
+       serial@70006040 {
+               compatible = "nvidia,tegra20-uart";
+               reg = <0x70006040 0x40>;
+               reg-shift = <2>;
+               interrupts = < 69 >;
+       };
+
+       serial@70006200 {
+               compatible = "nvidia,tegra20-uart";
+               reg = <0x70006200 0x100>;
+               reg-shift = <2>;
+               interrupts = < 78 >;
+       };
+
+       serial@70006300 {
+               compatible = "nvidia,tegra20-uart";
+               reg = <0x70006300 0x100>;
+               reg-shift = <2>;
+               interrupts = < 122 >;
+       };
+
+       serial@70006400 {
+               compatible = "nvidia,tegra20-uart";
+               reg = <0x70006400 0x100>;
+               reg-shift = <2>;
+               interrupts = < 123 >;
+       };
+
+       sdhci@c8000000 {
+               compatible = "nvidia,tegra20-sdhci";
+               reg = <0xc8000000 0x200>;
+               interrupts = < 46 >;
+       };
+
+       sdhci@c8000200 {
+               compatible = "nvidia,tegra20-sdhci";
+               reg = <0xc8000200 0x200>;
+               interrupts = < 47 >;
+       };
+
+       sdhci@c8000400 {
+               compatible = "nvidia,tegra20-sdhci";
+               reg = <0xc8000400 0x200>;
+               interrupts = < 51 >;
+       };
+
+       sdhci@c8000600 {
+               compatible = "nvidia,tegra20-sdhci";
+               reg = <0xc8000600 0x200>;
+               interrupts = < 63 >;
+       };
+};
+
diff --git a/arch/arm/boot/dts/versatile-ab.dts b/arch/arm/boot/dts/versatile-ab.dts
new file mode 100644 (file)
index 0000000..0b32925
--- /dev/null
@@ -0,0 +1,192 @@
+/dts-v1/;
+/include/ "skeleton.dtsi"
+
+/ {
+       model = "ARM Versatile AB";
+       compatible = "arm,versatile-ab";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       interrupt-parent = <&vic>;
+
+       aliases {
+               serial0 = &uart0;
+               serial1 = &uart1;
+               serial2 = &uart2;
+               i2c0 = &i2c0;
+       };
+
+       memory {
+               reg = <0x0 0x08000000>;
+       };
+
+       flash@34000000 {
+               compatible = "arm,versatile-flash";
+               reg = <0x34000000 0x4000000>;
+               bank-width = <4>;
+       };
+
+       i2c0: i2c@10002000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "arm,versatile-i2c";
+               reg = <0x10002000 0x1000>;
+
+               rtc@68 {
+                       compatible = "dallas,ds1338";
+                       reg = <0x68>;
+               };
+       };
+
+       net@10010000 {
+               compatible = "smsc,lan91c111";
+               reg = <0x10010000 0x10000>;
+               interrupts = <25>;
+       };
+
+       lcd@10008000 {
+               compatible = "arm,versatile-lcd";
+               reg = <0x10008000 0x1000>;
+       };
+
+       amba {
+               compatible = "arm,amba-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               vic: intc@10140000 {
+                       compatible = "arm,versatile-vic";
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+                       reg = <0x10140000 0x1000>;
+               };
+
+               sic: intc@10003000 {
+                       compatible = "arm,versatile-sic";
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+                       reg = <0x10003000 0x1000>;
+                       interrupt-parent = <&vic>;
+                       interrupts = <31>; /* Cascaded to vic */
+               };
+
+               dma@10130000 {
+                       compatible = "arm,pl081", "arm,primecell";
+                       reg = <0x10130000 0x1000>;
+                       interrupts = <17>;
+               };
+
+               uart0: uart@101f1000 {
+                       compatible = "arm,pl011", "arm,primecell";
+                       reg = <0x101f1000 0x1000>;
+                       interrupts = <12>;
+               };
+
+               uart1: uart@101f2000 {
+                       compatible = "arm,pl011", "arm,primecell";
+                       reg = <0x101f2000 0x1000>;
+                       interrupts = <13>;
+               };
+
+               uart2: uart@101f3000 {
+                       compatible = "arm,pl011", "arm,primecell";
+                       reg = <0x101f3000 0x1000>;
+                       interrupts = <14>;
+               };
+
+               smc@10100000 {
+                       compatible = "arm,primecell";
+                       reg = <0x10100000 0x1000>;
+               };
+
+               mpmc@10110000 {
+                       compatible = "arm,primecell";
+                       reg = <0x10110000 0x1000>;
+               };
+
+               display@10120000 {
+                       compatible = "arm,pl110", "arm,primecell";
+                       reg = <0x10120000 0x1000>;
+                       interrupts = <16>;
+               };
+
+               sctl@101e0000 {
+                       compatible = "arm,primecell";
+                       reg = <0x101e0000 0x1000>;
+               };
+
+               watchdog@101e1000 {
+                       compatible = "arm,primecell";
+                       reg = <0x101e1000 0x1000>;
+                       interrupts = <0>;
+               };
+
+               gpio0: gpio@101e4000 {
+                       compatible = "arm,pl061", "arm,primecell";
+                       reg = <0x101e4000 0x1000>;
+                       gpio-controller;
+                       interrupts = <6>;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpio1: gpio@101e5000 {
+                       compatible = "arm,pl061", "arm,primecell";
+                       reg = <0x101e5000 0x1000>;
+                       interrupts = <7>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               rtc@101e8000 {
+                       compatible = "arm,pl030", "arm,primecell";
+                       reg = <0x101e8000 0x1000>;
+                       interrupts = <10>;
+               };
+
+               sci@101f0000 {
+                       compatible = "arm,primecell";
+                       reg = <0x101f0000 0x1000>;
+                       interrupts = <15>;
+               };
+
+               ssp@101f4000 {
+                       compatible = "arm,pl022", "arm,primecell";
+                       reg = <0x101f4000 0x1000>;
+                       interrupts = <11>;
+               };
+
+               fpga {
+                       compatible = "arm,versatile-fpga", "simple-bus";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0 0x10000000 0x10000>;
+
+                       aaci@4000 {
+                               compatible = "arm,primecell";
+                               reg = <0x4000 0x1000>;
+                               interrupts = <24>;
+                       };
+                       mmc@5000 {
+                               compatible = "arm,primecell";
+                               reg = < 0x5000 0x1000>;
+                               interrupts = <22>;
+                       };
+                       kmi@6000 {
+                               compatible = "arm,pl050", "arm,primecell";
+                               reg = <0x6000 0x1000>;
+                               interrupt-parent = <&sic>;
+                               interrupts = <3>;
+                       };
+                       kmi@7000 {
+                               compatible = "arm,pl050", "arm,primecell";
+                               reg = <0x7000 0x1000>;
+                               interrupt-parent = <&sic>;
+                               interrupts = <4>;
+                       };
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/versatile-pb.dts b/arch/arm/boot/dts/versatile-pb.dts
new file mode 100644 (file)
index 0000000..8a614e3
--- /dev/null
@@ -0,0 +1,48 @@
+/include/ "versatile-ab.dts"
+
+/ {
+       model = "ARM Versatile PB";
+       compatible = "arm,versatile-pb";
+
+       amba {
+               gpio2: gpio@101e6000 {
+                       compatible = "arm,pl061", "arm,primecell";
+                       reg = <0x101e6000 0x1000>;
+                       interrupts = <8>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpio3: gpio@101e7000 {
+                       compatible = "arm,pl061", "arm,primecell";
+                       reg = <0x101e7000 0x1000>;
+                       interrupts = <9>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               fpga {
+                       uart@9000 {
+                               compatible = "arm,pl011", "arm,primecell";
+                               reg = <0x9000 0x1000>;
+                               interrupt-parent = <&sic>;
+                               interrupts = <6>;
+                       };
+                       sci@a000 {
+                               compatible = "arm,primecell";
+                               reg = <0xa000 0x1000>;
+                               interrupt-parent = <&sic>;
+                               interrupts = <5>;
+                       };
+                       mmc@b000 {
+                               compatible = "arm,primecell";
+                               reg = <0xb000 0x1000>;
+                               interrupts = <23>;
+                       };
+               };
+       };
+};
index 14ad62e..a7934ba 100644 (file)
@@ -144,7 +144,7 @@ void it8152_irq_demux(unsigned int irq, struct irq_desc *desc)
 }
 
 /* mapping for on-chip devices */
-int __init it8152_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+int __init it8152_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        if ((dev->vendor == PCI_VENDOR_ID_ITE) &&
            (dev->device == PCI_DEVICE_ID_ITE_8152)) {
index b2f95c7..b3fea38 100644 (file)
@@ -105,7 +105,7 @@ struct pci_sys_data;
 
 extern void it8152_irq_demux(unsigned int irq, struct irq_desc *desc);
 extern void it8152_init_irq(void);
-extern int it8152_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin);
+extern int it8152_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin);
 extern int it8152_pci_setup(int nr, struct pci_sys_data *sys);
 extern struct pci_bus *it8152_pci_scan_bus(int nr, struct pci_sys_data *sys);
 
index 3281fb4..217aa19 100644 (file)
@@ -74,4 +74,11 @@ static const struct machine_desc __mach_desc_##_type \
 #define MACHINE_END                            \
 };
 
+#define DT_MACHINE_START(_name, _namestr)              \
+static const struct machine_desc __mach_desc_##_name   \
+ __used                                                        \
+ __attribute__((__section__(".arch.info.init"))) = {   \
+       .nr             = ~0,                           \
+       .name           = _namestr,
+
 #endif
index 16330bd..186efd4 100644 (file)
@@ -25,7 +25,7 @@ struct hw_pci {
        void            (*preinit)(void);
        void            (*postinit)(void);
        u8              (*swizzle)(struct pci_dev *dev, u8 *pin);
-       int             (*map_irq)(struct pci_dev *dev, u8 slot, u8 pin);
+       int             (*map_irq)(const struct pci_dev *dev, u8 slot, u8 pin);
 };
 
 /*
@@ -44,7 +44,7 @@ struct pci_sys_data {
                                        /* Bridge swizzling                     */
        u8              (*swizzle)(struct pci_dev *, u8 *);
                                        /* IRQ mapping                          */
-       int             (*map_irq)(struct pci_dev *, u8, u8);
+       int             (*map_irq)(const struct pci_dev *, u8, u8);
        struct hw_pci   *hw;
        void            *private_data;  /* platform controller private data     */
 };
index 11b8708..6f65ca8 100644 (file)
 #include <asm/setup.h>
 #include <asm/irq.h>
 
-static inline void irq_dispose_mapping(unsigned int virq)
-{
-       return;
-}
-
 extern struct machine_desc *setup_machine_fdt(unsigned int dt_phys);
 extern void arm_dt_memblock_reserve(void);
 
index acca35a..aeef960 100644 (file)
@@ -112,9 +112,6 @@ EXPORT_SYMBOL(__put_user_4);
 EXPORT_SYMBOL(__put_user_8);
 #endif
 
-       /* crypto hash */
-EXPORT_SYMBOL(sha_transform);
-
        /* gcc lib functions */
 EXPORT_SYMBOL(__ashldi3);
 EXPORT_SYMBOL(__ashrdi3);
index e4ee050..d6df359 100644 (file)
@@ -476,7 +476,7 @@ static u8 __devinit pcibios_swizzle(struct pci_dev *dev, u8 *pin)
 /*
  * Map a slot/pin to an IRQ.
  */
-static int pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        struct pci_sys_data *sys = dev->sysdata;
        int irq = -1;
index 0cdd7b4..1a33e9d 100644 (file)
@@ -132,17 +132,3 @@ struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
 
        return mdesc_best;
 }
-
-/**
- * irq_create_of_mapping - Hook to resolve OF irq specifier into a Linux irq#
- *
- * Currently the mapping mechanism is trivial; simple flat hwirq numbers are
- * mapped 1:1 onto Linux irq numbers.  Cascaded irq controllers are not
- * supported.
- */
-unsigned int irq_create_of_mapping(struct device_node *controller,
-                                  const u32 *intspec, unsigned int intsize)
-{
-       return intspec[0];
-}
-EXPORT_SYMBOL_GPL(irq_create_of_mapping);
index 7fa3bb0..a087838 100644 (file)
@@ -195,10 +195,10 @@ ENTRY(iwmmxt_task_disable)
 
        @ enable access to CP0 and CP1
        XSC(mrc p15, 0, r4, c15, c1, 0)
-       XSC(orr r4, r4, #0xf)
+       XSC(orr r4, r4, #0x3)
        XSC(mcr p15, 0, r4, c15, c1, 0)
        PJ4(mrc p15, 0, r4, c1, c0, 2)
-       PJ4(orr r4, r4, #0x3)
+       PJ4(orr r4, r4, #0xf)
        PJ4(mcr p15, 0, r4, c1, c0, 2)
 
        mov     r0, #0                          @ nothing to load
@@ -313,7 +313,7 @@ ENTRY(iwmmxt_task_switch)
        teq     r2, r3                          @ next task owns it?
        movne   pc, lr                          @ no: leave Concan disabled
 
-1:     @ flip Conan access
+1:     @ flip Concan access
        XSC(eor r1, r1, #0x3)
        XSC(mcr p15, 0, r1, c15, c1, 0)
        PJ4(eor r1, r1, #0xf)
index 05b3776..cc2020c 100644 (file)
@@ -323,7 +323,11 @@ int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
 #endif
        s = find_mod_section(hdr, sechdrs, ".alt.smp.init");
        if (s && !is_smp())
+#ifdef CONFIG_SMP_ON_UP
                fixup_smp((void *)s->sh_addr, s->sh_size);
+#else
+               return -EINVAL;
+#endif
        return 0;
 }
 
index 5e1e541..1a347f4 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/uaccess.h>
 #include <linux/random.h>
 #include <linux/hw_breakpoint.h>
+#include <linux/cpuidle.h>
 
 #include <asm/cacheflush.h>
 #include <asm/leds.h>
@@ -196,7 +197,8 @@ void cpu_idle(void)
                                cpu_relax();
                        } else {
                                stop_critical_timings();
-                               pm_idle();
+                               if (cpuidle_idle_call())
+                                       pm_idle();
                                start_critical_timings();
                                /*
                                 * This will eventually be removed - pm_idle
index 59ff42d..cf73a7f 100644 (file)
@@ -12,7 +12,7 @@ lib-y         := backtrace.o changebit.o csumipv6.o csumpartial.o   \
                   strchr.o strrchr.o                                 \
                   testchangebit.o testclearbit.o testsetbit.o        \
                   ashldi3.o ashrdi3.o lshrdi3.o muldi3.o             \
-                  ucmpdi2.o lib1funcs.o div64.o sha1.o               \
+                  ucmpdi2.o lib1funcs.o div64.o                      \
                   io-readsb.o io-writesb.o io-readsl.o io-writesl.o
 
 mmu-y  := clear_user.o copy_page.o getuser.o putuser.o
diff --git a/arch/arm/lib/sha1.S b/arch/arm/lib/sha1.S
deleted file mode 100644 (file)
index eb0edb8..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- *  linux/arch/arm/lib/sha1.S
- *
- *  SHA transform optimized for ARM
- *
- *  Copyright: (C) 2005 by Nicolas Pitre <nico@fluxnic.net>
- *  Created:   September 17, 2005
- *
- *  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 reference implementation for this code is linux/lib/sha1.c
- */
-
-#include <linux/linkage.h>
-
-       .text
-
-
-/*
- * void sha_transform(__u32 *digest, const char *in, __u32 *W)
- *
- * Note: the "in" ptr may be unaligned.
- */
-
-ENTRY(sha_transform)
-
-       stmfd   sp!, {r4 - r8, lr}
-
-       @ for (i = 0; i < 16; i++)
-       @         W[i] = be32_to_cpu(in[i]);
-
-#ifdef __ARMEB__
-       mov     r4, r0
-       mov     r0, r2
-       mov     r2, #64
-       bl      memcpy
-       mov     r2, r0
-       mov     r0, r4
-#else
-       mov     r3, r2
-       mov     lr, #16
-1:     ldrb    r4, [r1], #1
-       ldrb    r5, [r1], #1
-       ldrb    r6, [r1], #1
-       ldrb    r7, [r1], #1
-       subs    lr, lr, #1
-       orr     r5, r5, r4, lsl #8
-       orr     r6, r6, r5, lsl #8
-       orr     r7, r7, r6, lsl #8
-       str     r7, [r3], #4
-       bne     1b
-#endif
-
-       @ for (i = 0; i < 64; i++)
-       @         W[i+16] = ror(W[i+13] ^ W[i+8] ^ W[i+2] ^ W[i], 31);
-
-       sub     r3, r2, #4
-       mov     lr, #64
-2:     ldr     r4, [r3, #4]!
-       subs    lr, lr, #1
-       ldr     r5, [r3, #8]
-       ldr     r6, [r3, #32]
-       ldr     r7, [r3, #52]
-       eor     r4, r4, r5
-       eor     r4, r4, r6
-       eor     r4, r4, r7
-       mov     r4, r4, ror #31
-       str     r4, [r3, #64]
-       bne     2b
-
-       /*
-        * The SHA functions are:
-        *
-        * f1(B,C,D) = (D ^ (B & (C ^ D)))
-        * f2(B,C,D) = (B ^ C ^ D)
-        * f3(B,C,D) = ((B & C) | (D & (B | C)))
-        *
-        * Then the sub-blocks are processed as follows:
-        *
-        * A' = ror(A, 27) + f(B,C,D) + E + K + *W++
-        * B' = A
-        * C' = ror(B, 2)
-        * D' = C
-        * E' = D
-        *
-        * We therefore unroll each loop 5 times to avoid register shuffling.
-        * Also the ror for C (and also D and E which are successivelyderived
-        * from it) is applied in place to cut on an additional mov insn for
-        * each round.
-        */
-
-       .macro  sha_f1, A, B, C, D, E
-       ldr     r3, [r2], #4
-       eor     ip, \C, \D
-       add     \E, r1, \E, ror #2
-       and     ip, \B, ip, ror #2
-       add     \E, \E, \A, ror #27
-       eor     ip, ip, \D, ror #2
-       add     \E, \E, r3
-       add     \E, \E, ip
-       .endm
-
-       .macro  sha_f2, A, B, C, D, E
-       ldr     r3, [r2], #4
-       add     \E, r1, \E, ror #2
-       eor     ip, \B, \C, ror #2
-       add     \E, \E, \A, ror #27
-       eor     ip, ip, \D, ror #2
-       add     \E, \E, r3
-       add     \E, \E, ip
-       .endm
-
-       .macro  sha_f3, A, B, C, D, E
-       ldr     r3, [r2], #4
-       add     \E, r1, \E, ror #2
-       orr     ip, \B, \C, ror #2
-       add     \E, \E, \A, ror #27
-       and     ip, ip, \D, ror #2
-       add     \E, \E, r3
-       and     r3, \B, \C, ror #2
-       orr     ip, ip, r3
-       add     \E, \E, ip
-       .endm
-
-       ldmia   r0, {r4 - r8}
-
-       mov     lr, #4
-       ldr     r1, .L_sha_K + 0
-
-       /* adjust initial values */
-       mov     r6, r6, ror #30
-       mov     r7, r7, ror #30
-       mov     r8, r8, ror #30
-
-3:     subs    lr, lr, #1
-       sha_f1  r4, r5, r6, r7, r8
-       sha_f1  r8, r4, r5, r6, r7
-       sha_f1  r7, r8, r4, r5, r6
-       sha_f1  r6, r7, r8, r4, r5
-       sha_f1  r5, r6, r7, r8, r4
-       bne     3b
-
-       ldr     r1, .L_sha_K + 4
-       mov     lr, #4
-
-4:     subs    lr, lr, #1
-       sha_f2  r4, r5, r6, r7, r8
-       sha_f2  r8, r4, r5, r6, r7
-       sha_f2  r7, r8, r4, r5, r6
-       sha_f2  r6, r7, r8, r4, r5
-       sha_f2  r5, r6, r7, r8, r4
-       bne     4b
-
-       ldr     r1, .L_sha_K + 8
-       mov     lr, #4
-
-5:     subs    lr, lr, #1
-       sha_f3  r4, r5, r6, r7, r8
-       sha_f3  r8, r4, r5, r6, r7
-       sha_f3  r7, r8, r4, r5, r6
-       sha_f3  r6, r7, r8, r4, r5
-       sha_f3  r5, r6, r7, r8, r4
-       bne     5b
-
-       ldr     r1, .L_sha_K + 12
-       mov     lr, #4
-
-6:     subs    lr, lr, #1
-       sha_f2  r4, r5, r6, r7, r8
-       sha_f2  r8, r4, r5, r6, r7
-       sha_f2  r7, r8, r4, r5, r6
-       sha_f2  r6, r7, r8, r4, r5
-       sha_f2  r5, r6, r7, r8, r4
-       bne     6b
-
-       ldmia   r0, {r1, r2, r3, ip, lr}
-       add     r4, r1, r4
-       add     r5, r2, r5
-       add     r6, r3, r6, ror #2
-       add     r7, ip, r7, ror #2
-       add     r8, lr, r8, ror #2
-       stmia   r0, {r4 - r8}
-
-       ldmfd   sp!, {r4 - r8, pc}
-
-ENDPROC(sha_transform)
-
-       .align  2
-.L_sha_K:
-       .word   0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6
-
-
-/*
- * void sha_init(__u32 *buf)
- */
-
-       .align  2
-.L_sha_initial_digest:
-       .word   0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0
-
-ENTRY(sha_init)
-
-       str     lr, [sp, #-4]!
-       adr     r1, .L_sha_initial_digest
-       ldmia   r1, {r1, r2, r3, ip, lr}
-       stmia   r0, {r1, r2, r3, ip, lr}
-       ldr     pc, [sp], #4
-
-ENDPROC(sha_init)
index 9696623..bf57e8b 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the linux kernel.
 #
 
-obj-y          := irq.o gpio.o
+obj-y          := irq.o gpio.o setup.o
 obj-m          :=
 obj-n          :=
 obj-           :=
index f1013d0..bfc6844 100644 (file)
 #include <mach/at91_rstc.h>
 #include <mach/at91_shdwc.h>
 
+#include "soc.h"
 #include "generic.h"
 #include "clock.h"
 
-static struct map_desc at91cap9_io_desc[] __initdata = {
-       {
-               .virtual        = AT91_VA_BASE_SYS,
-               .pfn            = __phys_to_pfn(AT91_BASE_SYS),
-               .length         = SZ_16K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = AT91_IO_VIRT_BASE - AT91CAP9_SRAM_SIZE,
-               .pfn            = __phys_to_pfn(AT91CAP9_SRAM_BASE),
-               .length         = AT91CAP9_SRAM_SIZE,
-               .type           = MT_DEVICE,
-       },
-};
-
 /* --------------------------------------------------------------------
  *  Clocks
  * -------------------------------------------------------------------- */
@@ -339,24 +326,17 @@ static void at91cap9_poweroff(void)
  *  AT91CAP9 processor initialization
  * -------------------------------------------------------------------- */
 
-void __init at91cap9_map_io(void)
+static void __init at91cap9_map_io(void)
 {
-       /* Map peripherals */
-       iotable_init(at91cap9_io_desc, ARRAY_SIZE(at91cap9_io_desc));
+       at91_init_sram(0, AT91CAP9_SRAM_BASE, AT91CAP9_SRAM_SIZE);
 }
 
-void __init at91cap9_initialize(unsigned long main_clock)
+static void __init at91cap9_initialize(void)
 {
        at91_arch_reset = at91cap9_reset;
        pm_power_off = at91cap9_poweroff;
        at91_extern_irq = (1 << AT91CAP9_ID_IRQ0) | (1 << AT91CAP9_ID_IRQ1);
 
-       /* Init clock subsystem */
-       at91_clock_init(main_clock);
-
-       /* Register the processor-specific clocks */
-       at91cap9_register_clocks();
-
        /* Register GPIO subsystem */
        at91_gpio_init(at91cap9_gpio, 4);
 
@@ -409,14 +389,9 @@ static unsigned int at91cap9_default_irq_priority[NR_AIC_IRQS] __initdata = {
        0,      /* Advanced Interrupt Controller (IRQ1) */
 };
 
-void __init at91cap9_init_interrupts(unsigned int priority[NR_AIC_IRQS])
-{
-       if (!priority)
-               priority = at91cap9_default_irq_priority;
-
-       /* Initialize the AIC interrupt controller */
-       at91_aic_init(priority);
-
-       /* Enable GPIO interrupts */
-       at91_gpio_irq_setup();
-}
+struct at91_init_soc __initdata at91cap9_soc = {
+       .map_io = at91cap9_map_io,
+       .default_irq_priority = at91cap9_default_irq_priority,
+       .register_clocks = at91cap9_register_clocks,
+       .init = at91cap9_initialize,
+};
index 83a1a3f..f73302d 100644 (file)
 #include <mach/at91_st.h>
 #include <mach/cpu.h>
 
+#include "soc.h"
 #include "generic.h"
 #include "clock.h"
 
 static struct map_desc at91rm9200_io_desc[] __initdata = {
        {
-               .virtual        = AT91_VA_BASE_SYS,
-               .pfn            = __phys_to_pfn(AT91_BASE_SYS),
-               .length         = SZ_4K,
-               .type           = MT_DEVICE,
-       }, {
                .virtual        = AT91_VA_BASE_EMAC,
                .pfn            = __phys_to_pfn(AT91RM9200_BASE_EMAC),
                .length         = SZ_16K,
                .type           = MT_DEVICE,
-       }, {
-               .virtual        = AT91_IO_VIRT_BASE - AT91RM9200_SRAM_SIZE,
-               .pfn            = __phys_to_pfn(AT91RM9200_SRAM_BASE),
-               .length         = AT91RM9200_SRAM_SIZE,
-               .type           = MT_DEVICE,
        },
 };
 
@@ -304,24 +295,17 @@ static void at91rm9200_reset(void)
        at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
 }
 
-int rm9200_type;
-EXPORT_SYMBOL(rm9200_type);
-
-void __init at91rm9200_set_type(int type)
-{
-       rm9200_type = type;
-}
-
 /* --------------------------------------------------------------------
  *  AT91RM9200 processor initialization
  * -------------------------------------------------------------------- */
-void __init at91rm9200_map_io(void)
+static void __init at91rm9200_map_io(void)
 {
        /* Map peripherals */
+       at91_init_sram(0, AT91RM9200_SRAM_BASE, AT91RM9200_SRAM_SIZE);
        iotable_init(at91rm9200_io_desc, ARRAY_SIZE(at91rm9200_io_desc));
 }
 
-void __init at91rm9200_initialize(unsigned long main_clock)
+static void __init at91rm9200_initialize(void)
 {
        at91_arch_reset = at91rm9200_reset;
        at91_extern_irq = (1 << AT91RM9200_ID_IRQ0) | (1 << AT91RM9200_ID_IRQ1)
@@ -329,12 +313,6 @@ void __init at91rm9200_initialize(unsigned long main_clock)
                        | (1 << AT91RM9200_ID_IRQ4) | (1 << AT91RM9200_ID_IRQ5)
                        | (1 << AT91RM9200_ID_IRQ6);
 
-       /* Init clock subsystem */
-       at91_clock_init(main_clock);
-
-       /* Register the processor-specific clocks */
-       at91rm9200_register_clocks();
-
        /* Initialize GPIO subsystem */
        at91_gpio_init(at91rm9200_gpio,
                cpu_is_at91rm9200_bga() ? AT91RM9200_BGA : AT91RM9200_PQFP);
@@ -383,14 +361,9 @@ static unsigned int at91rm9200_default_irq_priority[NR_AIC_IRQS] __initdata = {
        0       /* Advanced Interrupt Controller (IRQ6) */
 };
 
-void __init at91rm9200_init_interrupts(unsigned int priority[NR_AIC_IRQS])
-{
-       if (!priority)
-               priority = at91rm9200_default_irq_priority;
-
-       /* Initialize the AIC interrupt controller */
-       at91_aic_init(priority);
-
-       /* Enable GPIO interrupts */
-       at91_gpio_irq_setup();
-}
+struct at91_init_soc __initdata at91rm9200_soc = {
+       .map_io = at91rm9200_map_io,
+       .default_irq_priority = at91rm9200_default_irq_priority,
+       .register_clocks = at91rm9200_register_clocks,
+       .init = at91rm9200_initialize,
+};
index 7d606b0..cb397be 100644 (file)
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <mach/cpu.h>
+#include <mach/at91_dbgu.h>
 #include <mach/at91sam9260.h>
 #include <mach/at91_pmc.h>
 #include <mach/at91_rstc.h>
 #include <mach/at91_shdwc.h>
 
+#include "soc.h"
 #include "generic.h"
 #include "clock.h"
 
-static struct map_desc at91sam9260_io_desc[] __initdata = {
-       {
-               .virtual        = AT91_VA_BASE_SYS,
-               .pfn            = __phys_to_pfn(AT91_BASE_SYS),
-               .length         = SZ_16K,
-               .type           = MT_DEVICE,
-       }
-};
-
-static struct map_desc at91sam9260_sram_desc[] __initdata = {
-       {
-               .virtual        = AT91_IO_VIRT_BASE - AT91SAM9260_SRAM0_SIZE,
-               .pfn            = __phys_to_pfn(AT91SAM9260_SRAM0_BASE),
-               .length         = AT91SAM9260_SRAM0_SIZE,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = AT91_IO_VIRT_BASE - AT91SAM9260_SRAM0_SIZE - AT91SAM9260_SRAM1_SIZE,
-               .pfn            = __phys_to_pfn(AT91SAM9260_SRAM1_BASE),
-               .length         = AT91SAM9260_SRAM1_SIZE,
-               .type           = MT_DEVICE,
-       }
-};
-
-static struct map_desc at91sam9g20_sram_desc[] __initdata = {
-       {
-               .virtual        = AT91_IO_VIRT_BASE - AT91SAM9G20_SRAM0_SIZE,
-               .pfn            = __phys_to_pfn(AT91SAM9G20_SRAM0_BASE),
-               .length         = AT91SAM9G20_SRAM0_SIZE,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = AT91_IO_VIRT_BASE - AT91SAM9G20_SRAM0_SIZE - AT91SAM9G20_SRAM1_SIZE,
-               .pfn            = __phys_to_pfn(AT91SAM9G20_SRAM1_BASE),
-               .length         = AT91SAM9G20_SRAM1_SIZE,
-               .type           = MT_DEVICE,
-       }
-};
-
-static struct map_desc at91sam9xe_sram_desc[] __initdata = {
-       {
-               .pfn            = __phys_to_pfn(AT91SAM9XE_SRAM_BASE),
-               .type           = MT_DEVICE,
-       }
-};
-
 /* --------------------------------------------------------------------
  *  Clocks
  * -------------------------------------------------------------------- */
@@ -330,11 +288,9 @@ static void at91sam9260_poweroff(void)
 
 static void __init at91sam9xe_map_io(void)
 {
-       unsigned long cidr, sram_size;
-
-       cidr = at91_sys_read(AT91_DBGU_CIDR);
+       unsigned long sram_size;
 
-       switch (cidr & AT91_CIDR_SRAMSIZ) {
+       switch (at91_soc_initdata.cidr & AT91_CIDR_SRAMSIZ) {
                case AT91_CIDR_SRAMSIZ_32K:
                        sram_size = 2 * SZ_16K;
                        break;
@@ -343,38 +299,29 @@ static void __init at91sam9xe_map_io(void)
                        sram_size = SZ_16K;
        }
 
-       at91sam9xe_sram_desc->virtual = AT91_IO_VIRT_BASE - sram_size;
-       at91sam9xe_sram_desc->length = sram_size;
-
-       iotable_init(at91sam9xe_sram_desc, ARRAY_SIZE(at91sam9xe_sram_desc));
+       at91_init_sram(0, AT91SAM9XE_SRAM_BASE, sram_size);
 }
 
-void __init at91sam9260_map_io(void)
+static void __init at91sam9260_map_io(void)
 {
-       /* Map peripherals */
-       iotable_init(at91sam9260_io_desc, ARRAY_SIZE(at91sam9260_io_desc));
-
-       if (cpu_is_at91sam9xe())
+       if (cpu_is_at91sam9xe()) {
                at91sam9xe_map_io();
-       else if (cpu_is_at91sam9g20())
-               iotable_init(at91sam9g20_sram_desc, ARRAY_SIZE(at91sam9g20_sram_desc));
-       else
-               iotable_init(at91sam9260_sram_desc, ARRAY_SIZE(at91sam9260_sram_desc));
+       } else if (cpu_is_at91sam9g20()) {
+               at91_init_sram(0, AT91SAM9G20_SRAM0_BASE, AT91SAM9G20_SRAM0_SIZE);
+               at91_init_sram(1, AT91SAM9G20_SRAM1_BASE, AT91SAM9G20_SRAM1_SIZE);
+       } else {
+               at91_init_sram(0, AT91SAM9260_SRAM0_BASE, AT91SAM9260_SRAM0_SIZE);
+               at91_init_sram(1, AT91SAM9260_SRAM1_BASE, AT91SAM9260_SRAM1_SIZE);
+       }
 }
 
-void __init at91sam9260_initialize(unsigned long main_clock)
+static void __init at91sam9260_initialize(void)
 {
        at91_arch_reset = at91sam9_alt_reset;
        pm_power_off = at91sam9260_poweroff;
        at91_extern_irq = (1 << AT91SAM9260_ID_IRQ0) | (1 << AT91SAM9260_ID_IRQ1)
                        | (1 << AT91SAM9260_ID_IRQ2);
 
-       /* Init clock subsystem */
-       at91_clock_init(main_clock);
-
-       /* Register the processor-specific clocks */
-       at91sam9260_register_clocks();
-
        /* Register GPIO subsystem */
        at91_gpio_init(at91sam9260_gpio, 3);
 }
@@ -421,14 +368,9 @@ static unsigned int at91sam9260_default_irq_priority[NR_AIC_IRQS] __initdata = {
        0,      /* Advanced Interrupt Controller */
 };
 
-void __init at91sam9260_init_interrupts(unsigned int priority[NR_AIC_IRQS])
-{
-       if (!priority)
-               priority = at91sam9260_default_irq_priority;
-
-       /* Initialize the AIC interrupt controller */
-       at91_aic_init(priority);
-
-       /* Enable GPIO interrupts */
-       at91_gpio_irq_setup();
-}
+struct at91_init_soc __initdata at91sam9260_soc = {
+       .map_io = at91sam9260_map_io,
+       .default_irq_priority = at91sam9260_default_irq_priority,
+       .register_clocks = at91sam9260_register_clocks,
+       .init = at91sam9260_initialize,
+};
index c148316..d522b47 100644 (file)
 #include <mach/at91_rstc.h>
 #include <mach/at91_shdwc.h>
 
+#include "soc.h"
 #include "generic.h"
 #include "clock.h"
 
-static struct map_desc at91sam9261_io_desc[] __initdata = {
-       {
-               .virtual        = AT91_VA_BASE_SYS,
-               .pfn            = __phys_to_pfn(AT91_BASE_SYS),
-               .length         = SZ_16K,
-               .type           = MT_DEVICE,
-       },
-};
-
-static struct map_desc at91sam9261_sram_desc[] __initdata = {
-       {
-               .virtual        = AT91_IO_VIRT_BASE - AT91SAM9261_SRAM_SIZE,
-               .pfn            = __phys_to_pfn(AT91SAM9261_SRAM_BASE),
-               .length         = AT91SAM9261_SRAM_SIZE,
-               .type           = MT_DEVICE,
-       },
-};
-
-static struct map_desc at91sam9g10_sram_desc[] __initdata = {
-       {
-               .virtual        = AT91_IO_VIRT_BASE - AT91SAM9G10_SRAM_SIZE,
-               .pfn            = __phys_to_pfn(AT91SAM9G10_SRAM_BASE),
-               .length         = AT91SAM9G10_SRAM_SIZE,
-               .type           = MT_DEVICE,
-       },
-};
-
 /* --------------------------------------------------------------------
  *  Clocks
  * -------------------------------------------------------------------- */
@@ -302,30 +276,21 @@ static void at91sam9261_poweroff(void)
  *  AT91SAM9261 processor initialization
  * -------------------------------------------------------------------- */
 
-void __init at91sam9261_map_io(void)
+static void __init at91sam9261_map_io(void)
 {
-       /* Map peripherals */
-       iotable_init(at91sam9261_io_desc, ARRAY_SIZE(at91sam9261_io_desc));
-
        if (cpu_is_at91sam9g10())
-               iotable_init(at91sam9g10_sram_desc, ARRAY_SIZE(at91sam9g10_sram_desc));
+               at91_init_sram(0, AT91SAM9G10_SRAM_BASE, AT91SAM9G10_SRAM_SIZE);
        else
-               iotable_init(at91sam9261_sram_desc, ARRAY_SIZE(at91sam9261_sram_desc));
+               at91_init_sram(0, AT91SAM9261_SRAM_BASE, AT91SAM9261_SRAM_SIZE);
 }
 
-void __init at91sam9261_initialize(unsigned long main_clock)
+static void __init at91sam9261_initialize(void)
 {
        at91_arch_reset = at91sam9_alt_reset;
        pm_power_off = at91sam9261_poweroff;
        at91_extern_irq = (1 << AT91SAM9261_ID_IRQ0) | (1 << AT91SAM9261_ID_IRQ1)
                        | (1 << AT91SAM9261_ID_IRQ2);
 
-       /* Init clock subsystem */
-       at91_clock_init(main_clock);
-
-       /* Register the processor-specific clocks */
-       at91sam9261_register_clocks();
-
        /* Register GPIO subsystem */
        at91_gpio_init(at91sam9261_gpio, 3);
 }
@@ -372,14 +337,9 @@ static unsigned int at91sam9261_default_irq_priority[NR_AIC_IRQS] __initdata = {
        0,      /* Advanced Interrupt Controller */
 };
 
-void __init at91sam9261_init_interrupts(unsigned int priority[NR_AIC_IRQS])
-{
-       if (!priority)
-               priority = at91sam9261_default_irq_priority;
-
-       /* Initialize the AIC interrupt controller */
-       at91_aic_init(priority);
-
-       /* Enable GPIO interrupts */
-       at91_gpio_irq_setup();
-}
+struct at91_init_soc __initdata at91sam9261_soc = {
+       .map_io = at91sam9261_map_io,
+       .default_irq_priority = at91sam9261_default_irq_priority,
+       .register_clocks = at91sam9261_register_clocks,
+       .init = at91sam9261_initialize,
+};
index dc28477..044f3c9 100644 (file)
 #include <mach/at91_rstc.h>
 #include <mach/at91_shdwc.h>
 
+#include "soc.h"
 #include "generic.h"
 #include "clock.h"
 
-static struct map_desc at91sam9263_io_desc[] __initdata = {
-       {
-               .virtual        = AT91_VA_BASE_SYS,
-               .pfn            = __phys_to_pfn(AT91_BASE_SYS),
-               .length         = SZ_16K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = AT91_IO_VIRT_BASE - AT91SAM9263_SRAM0_SIZE,
-               .pfn            = __phys_to_pfn(AT91SAM9263_SRAM0_BASE),
-               .length         = AT91SAM9263_SRAM0_SIZE,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = AT91_IO_VIRT_BASE - AT91SAM9263_SRAM0_SIZE - AT91SAM9263_SRAM1_SIZE,
-               .pfn            = __phys_to_pfn(AT91SAM9263_SRAM1_BASE),
-               .length         = AT91SAM9263_SRAM1_SIZE,
-               .type           = MT_DEVICE,
-       },
-};
-
 /* --------------------------------------------------------------------
  *  Clocks
  * -------------------------------------------------------------------- */
@@ -313,24 +295,18 @@ static void at91sam9263_poweroff(void)
  *  AT91SAM9263 processor initialization
  * -------------------------------------------------------------------- */
 
-void __init at91sam9263_map_io(void)
+static void __init at91sam9263_map_io(void)
 {
-       /* Map peripherals */
-       iotable_init(at91sam9263_io_desc, ARRAY_SIZE(at91sam9263_io_desc));
+       at91_init_sram(0, AT91SAM9263_SRAM0_BASE, AT91SAM9263_SRAM0_SIZE);
+       at91_init_sram(1, AT91SAM9263_SRAM1_BASE, AT91SAM9263_SRAM1_SIZE);
 }
 
-void __init at91sam9263_initialize(unsigned long main_clock)
+static void __init at91sam9263_initialize(void)
 {
        at91_arch_reset = at91sam9_alt_reset;
        pm_power_off = at91sam9263_poweroff;
        at91_extern_irq = (1 << AT91SAM9263_ID_IRQ0) | (1 << AT91SAM9263_ID_IRQ1);
 
-       /* Init clock subsystem */
-       at91_clock_init(main_clock);
-
-       /* Register the processor-specific clocks */
-       at91sam9263_register_clocks();
-
        /* Register GPIO subsystem */
        at91_gpio_init(at91sam9263_gpio, 5);
 }
@@ -377,14 +353,9 @@ static unsigned int at91sam9263_default_irq_priority[NR_AIC_IRQS] __initdata = {
        0,      /* Advanced Interrupt Controller (IRQ1) */
 };
 
-void __init at91sam9263_init_interrupts(unsigned int priority[NR_AIC_IRQS])
-{
-       if (!priority)
-               priority = at91sam9263_default_irq_priority;
-
-       /* Initialize the AIC interrupt controller */
-       at91_aic_init(priority);
-
-       /* Enable GPIO interrupts */
-       at91_gpio_irq_setup();
-}
+struct at91_init_soc __initdata at91sam9263_soc = {
+       .map_io = at91sam9263_map_io,
+       .default_irq_priority = at91sam9263_default_irq_priority,
+       .register_clocks = at91sam9263_register_clocks,
+       .init = at91sam9263_initialize,
+};
index 11e2141..e04c5fb 100644 (file)
 #include <mach/at91_shdwc.h>
 #include <mach/cpu.h>
 
+#include "soc.h"
 #include "generic.h"
 #include "clock.h"
 
-static struct map_desc at91sam9g45_io_desc[] __initdata = {
-       {
-               .virtual        = AT91_VA_BASE_SYS,
-               .pfn            = __phys_to_pfn(AT91_BASE_SYS),
-               .length         = SZ_16K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = AT91_IO_VIRT_BASE - AT91SAM9G45_SRAM_SIZE,
-               .pfn            = __phys_to_pfn(AT91SAM9G45_SRAM_BASE),
-               .length         = AT91SAM9G45_SRAM_SIZE,
-               .type           = MT_DEVICE,
-       }
-};
-
 /* --------------------------------------------------------------------
  *  Clocks
  * -------------------------------------------------------------------- */
@@ -329,24 +316,17 @@ static void at91sam9g45_poweroff(void)
  *  AT91SAM9G45 processor initialization
  * -------------------------------------------------------------------- */
 
-void __init at91sam9g45_map_io(void)
+static void __init at91sam9g45_map_io(void)
 {
-       /* Map peripherals */
-       iotable_init(at91sam9g45_io_desc, ARRAY_SIZE(at91sam9g45_io_desc));
+       at91_init_sram(0, AT91SAM9G45_SRAM_BASE, AT91SAM9G45_SRAM_SIZE);
 }
 
-void __init at91sam9g45_initialize(unsigned long main_clock)
+static void __init at91sam9g45_initialize(void)
 {
        at91_arch_reset = at91sam9g45_reset;
        pm_power_off = at91sam9g45_poweroff;
        at91_extern_irq = (1 << AT91SAM9G45_ID_IRQ0);
 
-       /* Init clock subsystem */
-       at91_clock_init(main_clock);
-
-       /* Register the processor-specific clocks */
-       at91sam9g45_register_clocks();
-
        /* Register GPIO subsystem */
        at91_gpio_init(at91sam9g45_gpio, 5);
 }
@@ -393,14 +373,9 @@ static unsigned int at91sam9g45_default_irq_priority[NR_AIC_IRQS] __initdata = {
        0,      /* Advanced Interrupt Controller (IRQ0) */
 };
 
-void __init at91sam9g45_init_interrupts(unsigned int priority[NR_AIC_IRQS])
-{
-       if (!priority)
-               priority = at91sam9g45_default_irq_priority;
-
-       /* Initialize the AIC interrupt controller */
-       at91_aic_init(priority);
-
-       /* Enable GPIO interrupts */
-       at91_gpio_irq_setup();
-}
+struct at91_init_soc __initdata at91sam9g45_soc = {
+       .map_io = at91sam9g45_map_io,
+       .default_irq_priority = at91sam9g45_default_irq_priority,
+       .register_clocks = at91sam9g45_register_clocks,
+       .init = at91sam9g45_initialize,
+};
index 29dff18..a238105 100644 (file)
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <mach/cpu.h>
+#include <mach/at91_dbgu.h>
 #include <mach/at91sam9rl.h>
 #include <mach/at91_pmc.h>
 #include <mach/at91_rstc.h>
 #include <mach/at91_shdwc.h>
 
+#include "soc.h"
 #include "generic.h"
 #include "clock.h"
 
-static struct map_desc at91sam9rl_io_desc[] __initdata = {
-       {
-               .virtual        = AT91_VA_BASE_SYS,
-               .pfn            = __phys_to_pfn(AT91_BASE_SYS),
-               .length         = SZ_16K,
-               .type           = MT_DEVICE,
-       },
-};
-
-static struct map_desc at91sam9rl_sram_desc[] __initdata = {
-       {
-               .pfn            = __phys_to_pfn(AT91SAM9RL_SRAM_BASE),
-               .type           = MT_DEVICE,
-       }
-};
-
 /* --------------------------------------------------------------------
  *  Clocks
  * -------------------------------------------------------------------- */
@@ -287,16 +273,11 @@ static void at91sam9rl_poweroff(void)
  *  AT91SAM9RL processor initialization
  * -------------------------------------------------------------------- */
 
-void __init at91sam9rl_map_io(void)
+static void __init at91sam9rl_map_io(void)
 {
-       unsigned long cidr, sram_size;
-
-       /* Map peripherals */
-       iotable_init(at91sam9rl_io_desc, ARRAY_SIZE(at91sam9rl_io_desc));
-
-       cidr = at91_sys_read(AT91_DBGU_CIDR);
+       unsigned long sram_size;
 
-       switch (cidr & AT91_CIDR_SRAMSIZ) {
+       switch (at91_soc_initdata.cidr & AT91_CIDR_SRAMSIZ) {
                case AT91_CIDR_SRAMSIZ_32K:
                        sram_size = 2 * SZ_16K;
                        break;
@@ -305,25 +286,16 @@ void __init at91sam9rl_map_io(void)
                        sram_size = SZ_16K;
        }
 
-       at91sam9rl_sram_desc->virtual = AT91_IO_VIRT_BASE - sram_size;
-       at91sam9rl_sram_desc->length = sram_size;
-
        /* Map SRAM */
-       iotable_init(at91sam9rl_sram_desc, ARRAY_SIZE(at91sam9rl_sram_desc));
+       at91_init_sram(0, AT91SAM9RL_SRAM_BASE, sram_size);
 }
 
-void __init at91sam9rl_initialize(unsigned long main_clock)
+static void __init at91sam9rl_initialize(void)
 {
        at91_arch_reset = at91sam9_alt_reset;
        pm_power_off = at91sam9rl_poweroff;
        at91_extern_irq = (1 << AT91SAM9RL_ID_IRQ0);
 
-       /* Init clock subsystem */
-       at91_clock_init(main_clock);
-
-       /* Register the processor-specific clocks */
-       at91sam9rl_register_clocks();
-
        /* Register GPIO subsystem */
        at91_gpio_init(at91sam9rl_gpio, 4);
 }
@@ -370,14 +342,9 @@ static unsigned int at91sam9rl_default_irq_priority[NR_AIC_IRQS] __initdata = {
        0,      /* Advanced Interrupt Controller */
 };
 
-void __init at91sam9rl_init_interrupts(unsigned int priority[NR_AIC_IRQS])
-{
-       if (!priority)
-               priority = at91sam9rl_default_irq_priority;
-
-       /* Initialize the AIC interrupt controller */
-       at91_aic_init(priority);
-
-       /* Enable GPIO interrupts */
-       at91_gpio_irq_setup();
-}
+struct at91_init_soc __initdata at91sam9rl_soc = {
+       .map_io = at91sam9rl_map_io,
+       .default_irq_priority = at91sam9rl_default_irq_priority,
+       .register_clocks = at91sam9rl_register_clocks,
+       .init = at91sam9rl_initialize,
+};
index ab1d463..5aa5885 100644 (file)
@@ -46,7 +46,7 @@ static void __init onearm_init_early(void)
        at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
 
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000);
+       at91_initialize(18432000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -63,11 +63,6 @@ static void __init onearm_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init onearm_init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
 static struct at91_eth_data __initdata onearm_eth_data = {
        .phy_irq_pin    = AT91_PIN_PC4,
        .is_rmii        = 1,
@@ -97,8 +92,8 @@ static void __init onearm_board_init(void)
 MACHINE_START(ONEARM, "Ajeco 1ARM single board computer")
        /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = onearm_init_early,
-       .init_irq       = onearm_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = onearm_board_init,
 MACHINE_END
index a4924de..b0c796d 100644 (file)
@@ -51,7 +51,7 @@
 static void __init afeb9260_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91sam9260_initialize(18432000);
+       at91_initialize(18432000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -70,12 +70,6 @@ static void __init afeb9260_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init afeb9260_init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
-
 /*
  * USB Host port
  */
@@ -219,9 +213,9 @@ static void __init afeb9260_board_init(void)
 MACHINE_START(AFEB9260, "Custom afeb9260 board")
        /* Maintainer: Sergey Lapin <slapin@ossfans.org> */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = afeb9260_init_early,
-       .init_irq       = afeb9260_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = afeb9260_board_init,
 MACHINE_END
 
index 148fccb..d1abd58 100644 (file)
@@ -48,7 +48,7 @@
 static void __init cam60_init_early(void)
 {
        /* Initialize processor: 10 MHz crystal */
-       at91sam9260_initialize(10000000);
+       at91_initialize(10000000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -57,12 +57,6 @@ static void __init cam60_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init cam60_init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
-
 /*
  * USB Host
  */
@@ -199,8 +193,8 @@ static void __init cam60_board_init(void)
 MACHINE_START(CAM60, "KwikByte CAM60")
        /* Maintainer: KwikByte */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = cam60_init_early,
-       .init_irq       = cam60_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = cam60_board_init,
 MACHINE_END
index cdb65d4..679b0b7 100644 (file)
@@ -53,7 +53,7 @@
 static void __init cap9adk_init_early(void)
 {
        /* Initialize processor: 12 MHz crystal */
-       at91cap9_initialize(12000000);
+       at91_initialize(12000000);
 
        /* Setup the LEDs: USER1 and USER2 LED for cpu/timer... */
        at91_init_leds(AT91_PIN_PA10, AT91_PIN_PA11);
@@ -65,12 +65,6 @@ static void __init cap9adk_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init cap9adk_init_irq(void)
-{
-       at91cap9_init_interrupts(NULL);
-}
-
-
 /*
  * USB Host port
  */
@@ -397,8 +391,8 @@ static void __init cap9adk_board_init(void)
 MACHINE_START(AT91CAP9ADK, "Atmel AT91CAP9A-DK")
        /* Maintainer: Stelian Pop <stelian.pop@leadtechdesign.com> */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91cap9_map_io,
+       .map_io         = at91_map_io,
        .init_early     = cap9adk_init_early,
-       .init_irq       = cap9adk_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = cap9adk_board_init,
 MACHINE_END
index f36b186..c578c5d 100644 (file)
@@ -43,7 +43,7 @@
 static void __init carmeva_init_early(void)
 {
        /* Initialize processor: 20.000 MHz crystal */
-       at91rm9200_initialize(20000000);
+       at91_initialize(20000000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -57,11 +57,6 @@ static void __init carmeva_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init carmeva_init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
 static struct at91_eth_data __initdata carmeva_eth_data = {
        .phy_irq_pin    = AT91_PIN_PC4,
        .is_rmii        = 1,
@@ -163,8 +158,8 @@ static void __init carmeva_board_init(void)
 MACHINE_START(CARMEVA, "Carmeva")
        /* Maintainer: Conitec Datasystems */
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = carmeva_init_early,
-       .init_irq       = carmeva_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = carmeva_board_init,
 MACHINE_END
index 9805110..f4da8a1 100644 (file)
@@ -50,7 +50,7 @@
 static void __init cpu9krea_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91sam9260_initialize(18432000);
+       at91_initialize(18432000);
 
        /* DGBU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -81,11 +81,6 @@ static void __init cpu9krea_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init cpu9krea_init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
 /*
  * USB Host port
  */
@@ -376,8 +371,8 @@ MACHINE_START(CPUAT9G20, "Eukrea CPU9G20")
 #endif
        /* Maintainer: Eric Benard - EUKREA Electromatique */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = cpu9krea_init_early,
-       .init_irq       = cpu9krea_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = cpu9krea_board_init,
 MACHINE_END
index 6daabe3..2d919f5 100644 (file)
@@ -57,7 +57,7 @@ static void __init cpuat91_init_early(void)
        at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
 
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000);
+       at91_initialize(18432000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -82,11 +82,6 @@ static void __init cpuat91_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init cpuat91_init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
 static struct at91_eth_data __initdata cpuat91_eth_data = {
        .is_rmii        = 1,
 };
@@ -180,8 +175,8 @@ static void __init cpuat91_board_init(void)
 MACHINE_START(CPUAT91, "Eukrea")
        /* Maintainer: Eric Benard - EUKREA Electromatique */
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = cpuat91_init_early,
-       .init_irq       = cpuat91_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = cpuat91_board_init,
 MACHINE_END
index d98bcec..17654d5 100644 (file)
@@ -46,7 +46,7 @@
 static void __init csb337_init_early(void)
 {
        /* Initialize processor: 3.6864 MHz crystal */
-       at91rm9200_initialize(3686400);
+       at91_initialize(3686400);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
@@ -58,11 +58,6 @@ static void __init csb337_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init csb337_init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
 static struct at91_eth_data __initdata csb337_eth_data = {
        .phy_irq_pin    = AT91_PIN_PC2,
        .is_rmii        = 0,
@@ -258,8 +253,8 @@ static void __init csb337_board_init(void)
 MACHINE_START(CSB337, "Cogent CSB337")
        /* Maintainer: Bill Gatliff */
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = csb337_init_early,
-       .init_irq       = csb337_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = csb337_board_init,
 MACHINE_END
index 019aab4..72b5567 100644 (file)
@@ -43,7 +43,7 @@
 static void __init csb637_init_early(void)
 {
        /* Initialize processor: 3.6864 MHz crystal */
-       at91rm9200_initialize(3686400);
+       at91_initialize(3686400);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -52,11 +52,6 @@ static void __init csb637_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init csb637_init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
 static struct at91_eth_data __initdata csb637_eth_data = {
        .phy_irq_pin    = AT91_PIN_PC0,
        .is_rmii        = 0,
@@ -139,8 +134,8 @@ static void __init csb637_board_init(void)
 MACHINE_START(CSB637, "Cogent CSB637")
        /* Maintainer: Bill Gatliff */
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = csb637_init_early,
-       .init_irq       = csb637_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = csb637_board_init,
 MACHINE_END
index e948453..01170a2 100644 (file)
@@ -43,7 +43,7 @@
 static void __init eb9200_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000);
+       at91_initialize(18432000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -60,11 +60,6 @@ static void __init eb9200_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init eb9200_init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
 static struct at91_eth_data __initdata eb9200_eth_data = {
        .phy_irq_pin    = AT91_PIN_PC4,
        .is_rmii        = 1,
@@ -121,8 +116,8 @@ static void __init eb9200_board_init(void)
 
 MACHINE_START(ATEB9200, "Embest ATEB9200")
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = eb9200_init_early,
-       .init_irq       = eb9200_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = eb9200_board_init,
 MACHINE_END
index a6f57fa..7c0313c 100644 (file)
@@ -49,7 +49,7 @@ static void __init ecb_at91init_early(void)
        at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
 
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000);
+       at91_initialize(18432000);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PC7, AT91_PIN_PC7);
@@ -64,11 +64,6 @@ static void __init ecb_at91init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init ecb_at91init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
 static struct at91_eth_data __initdata ecb_at91eth_data = {
        .phy_irq_pin    = AT91_PIN_PC4,
        .is_rmii        = 0,
@@ -173,8 +168,8 @@ static void __init ecb_at91board_init(void)
 MACHINE_START(ECBAT91, "emQbit's ECB_AT91")
        /* Maintainer: emQbit.com */
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = ecb_at91init_early,
-       .init_irq       = ecb_at91init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = ecb_at91board_init,
 MACHINE_END
index bfc0062..8252c72 100644 (file)
@@ -35,7 +35,7 @@ static void __init eco920_init_early(void)
        /* Set cpu type: PQFP */
        at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
 
-       at91rm9200_initialize(18432000);
+       at91_initialize(18432000);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
@@ -47,11 +47,6 @@ static void __init eco920_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init eco920_init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
 static struct at91_eth_data __initdata eco920_eth_data = {
        .phy_irq_pin    = AT91_PIN_PC2,
        .is_rmii        = 1,
@@ -135,8 +130,8 @@ static void __init eco920_board_init(void)
 MACHINE_START(ECO920, "eco920")
        /* Maintainer: Sascha Hauer */
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = eco920_init_early,
-       .init_irq       = eco920_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = eco920_board_init,
 MACHINE_END
index 466c063..4c3f65d 100644 (file)
@@ -40,7 +40,7 @@
 static void __init flexibity_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91sam9260_initialize(18432000);
+       at91_initialize(18432000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -49,11 +49,6 @@ static void __init flexibity_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init flexibity_init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
 /* USB Host port */
 static struct at91_usbh_data __initdata flexibity_usbh_data = {
        .ports          = 2,
@@ -155,8 +150,8 @@ static void __init flexibity_board_init(void)
 MACHINE_START(FLEXIBITY, "Flexibity Connect")
        /* Maintainer: Maxim Osipov */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = flexibity_init_early,
-       .init_irq       = flexibity_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = flexibity_board_init,
 MACHINE_END
index e2d1dc9..f27d1a7 100644 (file)
@@ -60,7 +60,7 @@
 static void __init foxg20_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91sam9260_initialize(18432000);
+       at91_initialize(18432000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -101,12 +101,6 @@ static void __init foxg20_init_early(void)
 
 }
 
-static void __init foxg20_init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
-
 /*
  * USB Host port
  */
@@ -267,8 +261,8 @@ static void __init foxg20_board_init(void)
 MACHINE_START(ACMENETUSFOXG20, "Acme Systems srl FOX Board G20")
        /* Maintainer: Sergio Tanzilli */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = foxg20_init_early,
-       .init_irq       = foxg20_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = foxg20_board_init,
 MACHINE_END
index 1d4f36b..2e95949 100644 (file)
@@ -75,11 +75,6 @@ static void __init gsia18s_init_early(void)
        at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
 }
 
-static void __init init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
 /*
  * Two USB Host ports
  */
@@ -577,8 +572,8 @@ static void __init gsia18s_board_init(void)
 
 MACHINE_START(GSIA18S, "GS_IA18_S")
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = gsia18s_init_early,
-       .init_irq       = init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = gsia18s_board_init,
 MACHINE_END
index 9b003ff..4a17089 100644 (file)
@@ -46,7 +46,7 @@ static void __init kafa_init_early(void)
        at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
 
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000);
+       at91_initialize(18432000);
 
        /* Set up the LEDs */
        at91_init_leds(AT91_PIN_PB4, AT91_PIN_PB4);
@@ -61,11 +61,6 @@ static void __init kafa_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init kafa_init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
 static struct at91_eth_data __initdata kafa_eth_data = {
        .phy_irq_pin    = AT91_PIN_PC4,
        .is_rmii        = 0,
@@ -99,8 +94,8 @@ static void __init kafa_board_init(void)
 MACHINE_START(KAFA, "Sperry-Sun KAFA")
        /* Maintainer: Sergei Sharonov */
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = kafa_init_early,
-       .init_irq       = kafa_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = kafa_board_init,
 MACHINE_END
index a813a74..9dc8d49 100644 (file)
@@ -48,7 +48,7 @@ static void __init kb9202_init_early(void)
        at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
 
        /* Initialize processor: 10 MHz crystal */
-       at91rm9200_initialize(10000000);
+       at91_initialize(10000000);
 
        /* Set up the LEDs */
        at91_init_leds(AT91_PIN_PC19, AT91_PIN_PC18);
@@ -69,11 +69,6 @@ static void __init kb9202_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init kb9202_init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
 static struct at91_eth_data __initdata kb9202_eth_data = {
        .phy_irq_pin    = AT91_PIN_PB29,
        .is_rmii        = 0,
@@ -140,8 +135,8 @@ static void __init kb9202_board_init(void)
 MACHINE_START(KB9200, "KB920x")
        /* Maintainer: KwikByte, Inc. */
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = kb9202_init_early,
-       .init_irq       = kb9202_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = kb9202_board_init,
 MACHINE_END
index 961e805..9bc6ab3 100644 (file)
@@ -54,7 +54,7 @@
 static void __init neocore926_init_early(void)
 {
        /* Initialize processor: 20 MHz crystal */
-       at91sam9263_initialize(20000000);
+       at91_initialize(20000000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -66,12 +66,6 @@ static void __init neocore926_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init neocore926_init_irq(void)
-{
-       at91sam9263_init_interrupts(NULL);
-}
-
-
 /*
  * USB Host port
  */
@@ -388,8 +382,8 @@ static void __init neocore926_board_init(void)
 MACHINE_START(NEOCORE926, "ADENEO NEOCORE 926")
        /* Maintainer: ADENEO */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9263_map_io,
+       .map_io         = at91_map_io,
        .init_early     = neocore926_init_early,
-       .init_irq       = neocore926_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = neocore926_board_init,
 MACHINE_END
index 21a21af..49e3f69 100644 (file)
@@ -53,13 +53,6 @@ static void __init pcontrol_g20_init_early(void)
        at91_register_uart(AT91SAM9260_ID_US4, 3, 0);
 }
 
-
-static void __init init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
-
 static struct sam9_smc_config __initdata pcontrol_smc_config[2] = { {
        .ncs_read_setup         = 16,
        .nrd_setup              = 18,
@@ -223,8 +216,8 @@ static void __init pcontrol_g20_board_init(void)
 MACHINE_START(PCONTROL_G20, "PControl G20")
        /* Maintainer: pgsellmann@portner-elektronik.at */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = pcontrol_g20_init_early,
-       .init_irq       = init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = pcontrol_g20_board_init,
 MACHINE_END
index 756cc2a..b7b8390 100644 (file)
@@ -46,7 +46,7 @@
 static void __init picotux200_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000);
+       at91_initialize(18432000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -60,11 +60,6 @@ static void __init picotux200_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init picotux200_init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
 static struct at91_eth_data __initdata picotux200_eth_data = {
        .phy_irq_pin    = AT91_PIN_PC4,
        .is_rmii        = 1,
@@ -124,8 +119,8 @@ static void __init picotux200_board_init(void)
 MACHINE_START(PICOTUX2XX, "picotux 200")
        /* Maintainer: Kleinhenz Elektronik GmbH */
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = picotux200_init_early,
-       .init_irq       = picotux200_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = picotux200_board_init,
 MACHINE_END
index d1a6001..81f9110 100644 (file)
@@ -51,7 +51,7 @@
 static void __init ek_init_early(void)
 {
        /* Initialize processor: 12.000 MHz crystal */
-       at91sam9260_initialize(12000000);
+       at91_initialize(12000000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -72,12 +72,6 @@ static void __init ek_init_early(void)
 
 }
 
-static void __init ek_init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
-
 /*
  * USB Host port
  */
@@ -269,8 +263,8 @@ static void __init ek_board_init(void)
 MACHINE_START(QIL_A9260, "CALAO QIL_A9260")
        /* Maintainer: calao-systems */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = ek_init_early,
-       .init_irq       = ek_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
 MACHINE_END
index aef9627..6f08faa 100644 (file)
@@ -48,7 +48,7 @@
 static void __init dk_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000);
+       at91_initialize(18432000);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2);
@@ -65,11 +65,6 @@ static void __init dk_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init dk_init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
 static struct at91_eth_data __initdata dk_eth_data = {
        .phy_irq_pin    = AT91_PIN_PC4,
        .is_rmii        = 1,
@@ -228,8 +223,8 @@ static void __init dk_board_init(void)
 MACHINE_START(AT91RM9200DK, "Atmel AT91RM9200-DK")
        /* Maintainer: SAN People/Atmel */
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = dk_init_early,
-       .init_irq       = dk_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = dk_board_init,
 MACHINE_END
index 015a021..85bcccd 100644 (file)
@@ -48,7 +48,7 @@
 static void __init ek_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000);
+       at91_initialize(18432000);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2);
@@ -65,11 +65,6 @@ static void __init ek_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init ek_init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
 static struct at91_eth_data __initdata ek_eth_data = {
        .phy_irq_pin    = AT91_PIN_PC4,
        .is_rmii        = 1,
@@ -194,8 +189,8 @@ static void __init ek_board_init(void)
 MACHINE_START(AT91RM9200EK, "Atmel AT91RM9200-EK")
        /* Maintainer: SAN People/Atmel */
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = ek_init_early,
-       .init_irq       = ek_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
 MACHINE_END
index aaf1bf0..4d3a02f 100644 (file)
@@ -47,7 +47,7 @@
 static void __init ek_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91sam9260_initialize(18432000);
+       at91_initialize(18432000);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PA9, AT91_PIN_PA6);
@@ -67,12 +67,6 @@ static void __init ek_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init ek_init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
-
 /*
  * USB Host port
  */
@@ -213,8 +207,8 @@ static void __init ek_board_init(void)
 MACHINE_START(SAM9_L9260, "Olimex SAM9-L9260")
        /* Maintainer: Olimex */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = ek_init_early,
-       .init_irq       = ek_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
 MACHINE_END
index 5c24074..8a50c3e 100644 (file)
@@ -53,7 +53,7 @@
 static void __init ek_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91sam9260_initialize(18432000);
+       at91_initialize(18432000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -70,12 +70,6 @@ static void __init ek_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init ek_init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
-
 /*
  * USB Host port
  */
@@ -354,8 +348,8 @@ static void __init ek_board_init(void)
 MACHINE_START(AT91SAM9260EK, "Atmel AT91SAM9260-EK")
        /* Maintainer: Atmel */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = ek_init_early,
-       .init_irq       = ek_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
 MACHINE_END
index b60c22b..5096a0e 100644 (file)
@@ -57,7 +57,7 @@
 static void __init ek_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91sam9261_initialize(18432000);
+       at91_initialize(18432000);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PA13, AT91_PIN_PA14);
@@ -69,12 +69,6 @@ static void __init ek_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init ek_init_irq(void)
-{
-       at91sam9261_init_interrupts(NULL);
-}
-
-
 /*
  * DM9000 ethernet device
  */
@@ -621,8 +615,8 @@ MACHINE_START(AT91SAM9G10EK, "Atmel AT91SAM9G10-EK")
 #endif
        /* Maintainer: Atmel */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9261_map_io,
+       .map_io         = at91_map_io,
        .init_early     = ek_init_early,
-       .init_irq       = ek_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
 MACHINE_END
index 9bbdc92..ea8f185 100644 (file)
@@ -56,7 +56,7 @@
 static void __init ek_init_early(void)
 {
        /* Initialize processor: 16.367 MHz crystal */
-       at91sam9263_initialize(16367660);
+       at91_initialize(16367660);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -68,12 +68,6 @@ static void __init ek_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init ek_init_irq(void)
-{
-       at91sam9263_init_interrupts(NULL);
-}
-
-
 /*
  * USB Host port
  */
@@ -452,8 +446,8 @@ static void __init ek_board_init(void)
 MACHINE_START(AT91SAM9263EK, "Atmel AT91SAM9263-EK")
        /* Maintainer: Atmel */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9263_map_io,
+       .map_io         = at91_map_io,
        .init_early     = ek_init_early,
-       .init_irq       = ek_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
 MACHINE_END
index 1325a50..817f59d 100644 (file)
@@ -64,7 +64,7 @@ static int inline ek_have_2mmc(void)
 static void __init ek_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91sam9260_initialize(18432000);
+       at91_initialize(18432000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -81,12 +81,6 @@ static void __init ek_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init ek_init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
-
 /*
  * USB Host port
  */
@@ -404,17 +398,17 @@ static void __init ek_board_init(void)
 MACHINE_START(AT91SAM9G20EK, "Atmel AT91SAM9G20-EK")
        /* Maintainer: Atmel */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = ek_init_early,
-       .init_irq       = ek_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
 MACHINE_END
 
 MACHINE_START(AT91SAM9G20EK_2MMC, "Atmel AT91SAM9G20-EK 2 MMC Slot Mod")
        /* Maintainer: Atmel */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = ek_init_early,
-       .init_irq       = ek_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
 MACHINE_END
index 33eaa13..ad234cc 100644 (file)
@@ -50,7 +50,7 @@
 static void __init ek_init_early(void)
 {
        /* Initialize processor: 12.000 MHz crystal */
-       at91sam9g45_initialize(12000000);
+       at91_initialize(12000000);
 
        /* DGBU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -63,12 +63,6 @@ static void __init ek_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init ek_init_irq(void)
-{
-       at91sam9g45_init_interrupts(NULL);
-}
-
-
 /*
  * USB HS Host port (common to OHCI & EHCI)
  */
@@ -422,8 +416,8 @@ static void __init ek_board_init(void)
 MACHINE_START(AT91SAM9M10G45EK, "Atmel AT91SAM9M10G45-EK")
        /* Maintainer: Atmel */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9g45_map_io,
+       .map_io         = at91_map_io,
        .init_early     = ek_init_early,
-       .init_irq       = ek_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
 MACHINE_END
index effb399..4f14b54 100644 (file)
@@ -41,7 +41,7 @@
 static void __init ek_init_early(void)
 {
        /* Initialize processor: 12.000 MHz crystal */
-       at91sam9rl_initialize(12000000);
+       at91_initialize(12000000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -53,12 +53,6 @@ static void __init ek_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init ek_init_irq(void)
-{
-       at91sam9rl_init_interrupts(NULL);
-}
-
-
 /*
  * USB HS Device port
  */
@@ -330,8 +324,8 @@ static void __init ek_board_init(void)
 MACHINE_START(AT91SAM9RLEK, "Atmel AT91SAM9RL-EK")
        /* Maintainer: Atmel */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9rl_map_io,
+       .map_io         = at91_map_io,
        .init_early     = ek_init_early,
-       .init_irq       = ek_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
 MACHINE_END
index 6010ce1..c73d25e 100644 (file)
@@ -42,7 +42,7 @@
 
 static void __init snapper9260_init_early(void)
 {
-       at91sam9260_initialize(18432000);
+       at91_initialize(18432000);
 
        /* Debug on ttyS0 */
        at91_register_uart(0, 0, 0);
@@ -55,11 +55,6 @@ static void __init snapper9260_init_early(void)
        at91_register_uart(AT91SAM9260_ID_US2, 3, 0);
 }
 
-static void __init snapper9260_init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
 static struct at91_usbh_data __initdata snapper9260_usbh_data = {
        .ports          = 2,
 };
@@ -179,9 +174,9 @@ static void __init snapper9260_board_init(void)
 
 MACHINE_START(SNAPPER_9260, "Bluewater Systems Snapper 9260/9G20 module")
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = snapper9260_init_early,
-       .init_irq       = snapper9260_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = snapper9260_board_init,
 MACHINE_END
 
index 5e5c856..936e5fd 100644 (file)
@@ -35,7 +35,7 @@
 void __init stamp9g20_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91sam9260_initialize(18432000);
+       at91_initialize(18432000);
 
        /* DGBU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -76,12 +76,6 @@ static void __init portuxg20_init_early(void)
        at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
 }
 
-static void __init init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
-
 /*
  * NAND flash
  */
@@ -299,17 +293,17 @@ static void __init stamp9g20evb_board_init(void)
 MACHINE_START(PORTUXG20, "taskit PortuxG20")
        /* Maintainer: taskit GmbH */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = portuxg20_init_early,
-       .init_irq       = init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = portuxg20_board_init,
 MACHINE_END
 
 MACHINE_START(STAMP9G20, "taskit Stamp9G20")
        /* Maintainer: taskit GmbH */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = stamp9g20evb_init_early,
-       .init_irq       = init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = stamp9g20evb_board_init,
 MACHINE_END
index 0e784e6..8c4c1a0 100644 (file)
@@ -51,7 +51,7 @@
 static void __init ek_init_early(void)
 {
        /* Initialize processor: 12.000 MHz crystal */
-       at91sam9260_initialize(12000000);
+       at91_initialize(12000000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -60,12 +60,6 @@ static void __init ek_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init ek_init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
-
 /*
  * USB Host port
  */
@@ -229,8 +223,8 @@ static void __init ek_board_init(void)
 MACHINE_START(USB_A9260, "CALAO USB_A9260")
        /* Maintainer: calao-systems */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = ek_init_early,
-       .init_irq       = ek_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
 MACHINE_END
index cf626dd..25e7937 100644 (file)
@@ -50,7 +50,7 @@
 static void __init ek_init_early(void)
 {
        /* Initialize processor: 12.00 MHz crystal */
-       at91sam9263_initialize(12000000);
+       at91_initialize(12000000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -59,12 +59,6 @@ static void __init ek_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init ek_init_irq(void)
-{
-       at91sam9263_init_interrupts(NULL);
-}
-
-
 /*
  * USB Host port
  */
@@ -245,8 +239,8 @@ static void __init ek_board_init(void)
 MACHINE_START(USB_A9263, "CALAO USB_A9263")
        /* Maintainer: calao-systems */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9263_map_io,
+       .map_io         = at91_map_io,
        .init_early     = ek_init_early,
-       .init_irq       = ek_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
 MACHINE_END
index c208cc3..95edcbd 100644 (file)
@@ -56,7 +56,7 @@ static void __init yl9200_init_early(void)
        at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
 
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000);
+       at91_initialize(18432000);
 
        /* Setup the LEDs D2=PB17 (timer), D3=PB16 (cpu) */
        at91_init_leds(AT91_PIN_PB16, AT91_PIN_PB17);
@@ -79,12 +79,6 @@ static void __init yl9200_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init yl9200_init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
-
 /*
  * LEDs
  */
@@ -599,8 +593,8 @@ static void __init yl9200_board_init(void)
 MACHINE_START(YL9200, "uCdragon YL-9200")
        /* Maintainer: S.Birtles */
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = yl9200_init_early,
-       .init_irq       = yl9200_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = yl9200_board_init,
 MACHINE_END
index 8ff3418..938b34f 100644 (file)
 #include <linux/clkdev.h>
 
  /* Map io */
-extern void __init at91rm9200_map_io(void);
-extern void __init at91sam9260_map_io(void);
-extern void __init at91sam9261_map_io(void);
-extern void __init at91sam9263_map_io(void);
-extern void __init at91sam9rl_map_io(void);
-extern void __init at91sam9g45_map_io(void);
-extern void __init at91x40_map_io(void);
-extern void __init at91cap9_map_io(void);
+extern void __init at91_map_io(void);
+extern void __init at91_init_sram(int bank, unsigned long base,
+                                 unsigned int length);
 
  /* Processors */
 extern void __init at91rm9200_set_type(int type);
-extern void __init at91rm9200_initialize(unsigned long main_clock);
-extern void __init at91sam9260_initialize(unsigned long main_clock);
-extern void __init at91sam9261_initialize(unsigned long main_clock);
-extern void __init at91sam9263_initialize(unsigned long main_clock);
-extern void __init at91sam9rl_initialize(unsigned long main_clock);
-extern void __init at91sam9g45_initialize(unsigned long main_clock);
+extern void __init at91_initialize(unsigned long main_clock);
 extern void __init at91x40_initialize(unsigned long main_clock);
-extern void __init at91cap9_initialize(unsigned long main_clock);
 
  /* Interrupts */
-extern void __init at91rm9200_init_interrupts(unsigned int priority[]);
-extern void __init at91sam9260_init_interrupts(unsigned int priority[]);
-extern void __init at91sam9261_init_interrupts(unsigned int priority[]);
-extern void __init at91sam9263_init_interrupts(unsigned int priority[]);
-extern void __init at91sam9rl_init_interrupts(unsigned int priority[]);
-extern void __init at91sam9g45_init_interrupts(unsigned int priority[]);
+extern void __init at91_init_irq_default(void);
+extern void __init at91_init_interrupts(unsigned int priority[]);
 extern void __init at91x40_init_interrupts(unsigned int priority[]);
-extern void __init at91cap9_init_interrupts(unsigned int priority[]);
 extern void __init at91_aic_init(unsigned int priority[]);
 
  /* Timer */
@@ -49,7 +33,6 @@ extern struct sys_timer at91sam926x_timer;
 extern struct sys_timer at91x40_timer;
 
  /* Clocks */
-extern int __init at91_clock_init(unsigned long main_clock);
 /*
  * function to specify the clock of the default console. As we do not
  * use the device/driver bus, the dev_name is not intialize. So we need
@@ -62,6 +45,11 @@ extern void __init at91sam9263_set_console_clock(int id);
 extern void __init at91sam9rl_set_console_clock(int id);
 extern void __init at91sam9g45_set_console_clock(int id);
 extern void __init at91cap9_set_console_clock(int id);
+#ifdef CONFIG_AT91_PMC_UNIT
+extern int __init at91_clock_init(unsigned long main_clock);
+#else
+static int inline at91_clock_init(unsigned long main_clock) { return 0; }
+#endif
 struct device;
 
  /* Power Management */
index 6dcaa77..dbfe455 100644 (file)
 #ifndef AT91_DBGU_H
 #define AT91_DBGU_H
 
+#define dbgu_readl(dbgu, field) \
+       __raw_readl(AT91_VA_BASE_SYS + dbgu + AT91_DBGU_ ## field)
+
 #ifdef AT91_DBGU
-#define AT91_DBGU_CR           (AT91_DBGU + 0x00)      /* Control Register */
-#define AT91_DBGU_MR           (AT91_DBGU + 0x04)      /* Mode Register */
-#define AT91_DBGU_IER          (AT91_DBGU + 0x08)      /* Interrupt Enable Register */
+#define AT91_DBGU_CR           (0x00)  /* Control Register */
+#define AT91_DBGU_MR           (0x04)  /* Mode Register */
+#define AT91_DBGU_IER          (0x08)  /* Interrupt Enable Register */
 #define                AT91_DBGU_TXRDY         (1 << 1)                /* Transmitter Ready */
 #define                AT91_DBGU_TXEMPTY       (1 << 9)                /* Transmitter Empty */
-#define AT91_DBGU_IDR          (AT91_DBGU + 0x0c)      /* Interrupt Disable Register */
-#define AT91_DBGU_IMR          (AT91_DBGU + 0x10)      /* Interrupt Mask Register */
-#define AT91_DBGU_SR           (AT91_DBGU + 0x14)      /* Status Register */
-#define AT91_DBGU_RHR          (AT91_DBGU + 0x18)      /* Receiver Holding Register */
-#define AT91_DBGU_THR          (AT91_DBGU + 0x1c)      /* Transmitter Holding Register */
-#define AT91_DBGU_BRGR         (AT91_DBGU + 0x20)      /* Baud Rate Generator Register */
+#define AT91_DBGU_IDR          (0x0c)  /* Interrupt Disable Register */
+#define AT91_DBGU_IMR          (0x10)  /* Interrupt Mask Register */
+#define AT91_DBGU_SR           (0x14)  /* Status Register */
+#define AT91_DBGU_RHR          (0x18)  /* Receiver Holding Register */
+#define AT91_DBGU_THR          (0x1c)  /* Transmitter Holding Register */
+#define AT91_DBGU_BRGR         (0x20)  /* Baud Rate Generator Register */
 
-#define AT91_DBGU_CIDR         (AT91_DBGU + 0x40)      /* Chip ID Register */
-#define AT91_DBGU_EXID         (AT91_DBGU + 0x44)      /* Chip ID Extension Register */
-#define AT91_DBGU_FNR          (AT91_DBGU + 0x48)      /* Force NTRST Register [SAM9 only] */
+#define AT91_DBGU_CIDR         (0x40)  /* Chip ID Register */
+#define AT91_DBGU_EXID         (0x44)  /* Chip ID Extension Register */
+#define AT91_DBGU_FNR          (0x48)  /* Force NTRST Register [SAM9 only] */
 #define                AT91_DBGU_FNTRST        (1 << 0)                /* Force NTRST */
 
 #endif /* AT91_DBGU */
index 6659938..c5df1e8 100644 (file)
@@ -75,7 +75,6 @@
 #define AT91CAP9_BASE_EMAC             0xfffbc000
 #define AT91CAP9_BASE_ADC              0xfffc0000
 #define AT91CAP9_BASE_ISI              0xfffc4000
-#define AT91_BASE_SYS                  0xffffe200
 
 /*
  * System Peripherals (offset from AT91_BASE_SYS)
index 99e0f8d..e4037b5 100644 (file)
@@ -74,7 +74,6 @@
 #define AT91RM9200_BASE_SSC1   0xfffd4000
 #define AT91RM9200_BASE_SSC2   0xfffd8000
 #define AT91RM9200_BASE_SPI    0xfffe0000
-#define AT91_BASE_SYS          0xfffff000
 
 
 /*
index 8b6bf83..9a79116 100644 (file)
@@ -76,7 +76,6 @@
 #define AT91SAM9260_BASE_TC4           0xfffdc040
 #define AT91SAM9260_BASE_TC5           0xfffdc080
 #define AT91SAM9260_BASE_ADC           0xfffe0000
-#define AT91_BASE_SYS                  0xffffe800
 
 /*
  * System Peripherals (offset from AT91_BASE_SYS)
index eafbdda..ce59620 100644 (file)
@@ -60,7 +60,6 @@
 #define AT91SAM9261_BASE_SSC2          0xfffc4000
 #define AT91SAM9261_BASE_SPI0          0xfffc8000
 #define AT91SAM9261_BASE_SPI1          0xfffcc000
-#define AT91_BASE_SYS                  0xffffea00
 
 
 /*
index e2d3482..f1b9296 100644 (file)
@@ -70,7 +70,6 @@
 #define AT91SAM9263_BASE_EMAC          0xfffbc000
 #define AT91SAM9263_BASE_ISI           0xfffc4000
 #define AT91SAM9263_BASE_2DGE          0xfffc8000
-#define AT91_BASE_SYS                  0xffffe000
 
 /*
  * System Peripherals (offset from AT91_BASE_SYS)
index 659304a..2c611b9 100644 (file)
@@ -82,7 +82,6 @@
 #define AT91SAM9G45_BASE_TC3           0xfffd4000
 #define AT91SAM9G45_BASE_TC4           0xfffd4040
 #define AT91SAM9G45_BASE_TC5           0xfffd4080
-#define AT91_BASE_SYS                  0xffffe200
 
 /*
  * System Peripherals (offset from AT91_BASE_SYS)
index 41dbbe6..1aabacd 100644 (file)
@@ -64,7 +64,6 @@
 #define AT91SAM9RL_BASE_TSC    0xfffd0000
 #define AT91SAM9RL_BASE_UDPHS  0xfffd4000
 #define AT91SAM9RL_BASE_AC97C  0xfffd8000
-#define AT91_BASE_SYS          0xffffc000
 
 
 /*
index df966c2..f6ce936 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * arch/arm/mach-at91/include/mach/cpu.h
  *
- *  Copyright (C) 2006 SAN People
+ * Copyright (C) 2006 SAN People
+ * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.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
  *
  */
 
-#ifndef __ASM_ARCH_CPU_H
-#define __ASM_ARCH_CPU_H
-
-#include <mach/hardware.h>
-#include <mach/at91_dbgu.h>
-
+#ifndef __MACH_CPU_H__
+#define __MACH_CPU_H__
 
 #define ARCH_ID_AT91RM9200     0x09290780
 #define ARCH_ID_AT91SAM9260    0x019803a0
 #define ARCH_ID_AT91M40807     0x14080745
 #define ARCH_ID_AT91R40008     0x44000840
 
-static inline unsigned long at91_cpu_identify(void)
-{
-       return (at91_sys_read(AT91_DBGU_CIDR) & ~AT91_CIDR_VERSION);
-}
-
-static inline unsigned long at91_cpu_fully_identify(void)
-{
-       return at91_sys_read(AT91_DBGU_CIDR);
-}
-
 #define ARCH_EXID_AT91SAM9M11  0x00000001
 #define ARCH_EXID_AT91SAM9M10  0x00000002
 #define ARCH_EXID_AT91SAM9G46  0x00000003
@@ -60,40 +47,80 @@ static inline unsigned long at91_cpu_fully_identify(void)
 #define ARCH_EXID_AT91SAM9G25  0x00000003
 #define ARCH_EXID_AT91SAM9X25  0x00000004
 
-static inline unsigned long at91_exid_identify(void)
-{
-       return at91_sys_read(AT91_DBGU_EXID);
-}
-
-
 #define ARCH_FAMILY_AT91X92    0x09200000
 #define ARCH_FAMILY_AT91SAM9   0x01900000
 #define ARCH_FAMILY_AT91SAM9XE 0x02900000
 
-static inline unsigned long at91_arch_identify(void)
-{
-       return (at91_sys_read(AT91_DBGU_CIDR) & AT91_CIDR_ARCH);
-}
-
-#ifdef CONFIG_ARCH_AT91CAP9
-#include <mach/at91_pmc.h>
-
+/* PMC revision */
 #define ARCH_REVISION_CAP9_B   0x399
 #define ARCH_REVISION_CAP9_C   0x601
 
-static inline unsigned long at91cap9_rev_identify(void)
+/* RM9200 type */
+#define ARCH_REVISON_9200_BGA  (0 << 0)
+#define ARCH_REVISON_9200_PQFP (1 << 0)
+
+enum at91_soc_type {
+       /* 920T */
+       AT91_SOC_RM9200,
+
+       /* CAP */
+       AT91_SOC_CAP9,
+
+       /* SAM92xx */
+       AT91_SOC_SAM9260, AT91_SOC_SAM9261, AT91_SOC_SAM9263,
+
+       /* SAM9Gxx */
+       AT91_SOC_SAM9G10, AT91_SOC_SAM9G20, AT91_SOC_SAM9G45,
+
+       /* SAM9RL */
+       AT91_SOC_SAM9RL,
+
+       /* SAM9X5 */
+       AT91_SOC_SAM9X5,
+
+       /* Unknown type */
+       AT91_SOC_NONE
+};
+
+enum at91_soc_subtype {
+       /* RM9200 */
+       AT91_SOC_RM9200_BGA, AT91_SOC_RM9200_PQFP,
+
+       /* CAP9 */
+       AT91_SOC_CAP9_REV_B, AT91_SOC_CAP9_REV_C,
+
+       /* SAM9260 */
+       AT91_SOC_SAM9XE,
+
+       /* SAM9G45 */
+       AT91_SOC_SAM9G45ES, AT91_SOC_SAM9M10, AT91_SOC_SAM9G46, AT91_SOC_SAM9M11,
+
+       /* SAM9X5 */
+       AT91_SOC_SAM9G15, AT91_SOC_SAM9G35, AT91_SOC_SAM9X35,
+       AT91_SOC_SAM9G25, AT91_SOC_SAM9X25,
+
+       /* Unknown subtype */
+       AT91_SOC_SUBTYPE_NONE
+};
+
+struct at91_socinfo {
+       unsigned int type, subtype;
+       unsigned int cidr, exid;
+};
+
+extern struct at91_socinfo at91_soc_initdata;
+const char *at91_get_soc_type(struct at91_socinfo *c);
+const char *at91_get_soc_subtype(struct at91_socinfo *c);
+
+static inline int at91_soc_is_detected(void)
 {
-       return (at91_sys_read(AT91_PMC_VER));
+       return at91_soc_initdata.type != AT91_SOC_NONE;
 }
-#endif
 
 #ifdef CONFIG_ARCH_AT91RM9200
-extern int rm9200_type;
-#define ARCH_REVISON_9200_BGA  (0 << 0)
-#define ARCH_REVISON_9200_PQFP (1 << 0)
-#define cpu_is_at91rm9200()    (at91_cpu_identify() == ARCH_ID_AT91RM9200)
-#define cpu_is_at91rm9200_bga()        (!cpu_is_at91rm9200_pqfp())
-#define cpu_is_at91rm9200_pqfp() (cpu_is_at91rm9200() && rm9200_type & ARCH_REVISON_9200_PQFP)
+#define cpu_is_at91rm9200()    (at91_soc_initdata.type == AT91_SOC_RM9200)
+#define cpu_is_at91rm9200_bga()        (at91_soc_initdata.subtype == AT91_SOC_RM9200_BGA)
+#define cpu_is_at91rm9200_pqfp() (at91_soc_initdata.subtype == AT91_SOC_RM9200_PQFP)
 #else
 #define cpu_is_at91rm9200()    (0)
 #define cpu_is_at91rm9200_bga()        (0)
@@ -101,52 +128,49 @@ extern int rm9200_type;
 #endif
 
 #ifdef CONFIG_ARCH_AT91SAM9260
-#define cpu_is_at91sam9xe()    (at91_arch_identify() == ARCH_FAMILY_AT91SAM9XE)
-#define cpu_is_at91sam9260()   ((at91_cpu_identify() == ARCH_ID_AT91SAM9260) || cpu_is_at91sam9xe())
+#define cpu_is_at91sam9xe()    (at91_soc_initdata.subtype == AT91_SOC_SAM9XE)
+#define cpu_is_at91sam9260()   (at91_soc_initdata.type == AT91_SOC_SAM9260)
 #else
 #define cpu_is_at91sam9xe()    (0)
 #define cpu_is_at91sam9260()   (0)
 #endif
 
 #ifdef CONFIG_ARCH_AT91SAM9G20
-#define cpu_is_at91sam9g20()   (at91_cpu_identify() == ARCH_ID_AT91SAM9G20)
+#define cpu_is_at91sam9g20()   (at91_soc_initdata.type == AT91_SOC_SAM9G20)
 #else
 #define cpu_is_at91sam9g20()   (0)
 #endif
 
 #ifdef CONFIG_ARCH_AT91SAM9261
-#define cpu_is_at91sam9261()   (at91_cpu_identify() == ARCH_ID_AT91SAM9261)
+#define cpu_is_at91sam9261()   (at91_soc_initdata.type == AT91_SOC_SAM9261)
 #else
 #define cpu_is_at91sam9261()   (0)
 #endif
 
 #ifdef CONFIG_ARCH_AT91SAM9G10
-#define cpu_is_at91sam9g10()   ((at91_cpu_identify() & ~AT91_CIDR_EXT) == ARCH_ID_AT91SAM9G10)
+#define cpu_is_at91sam9g10()   (at91_soc_initdata.type == AT91_SOC_SAM9G10)
 #else
 #define cpu_is_at91sam9g10()   (0)
 #endif
 
 #ifdef CONFIG_ARCH_AT91SAM9263
-#define cpu_is_at91sam9263()   (at91_cpu_identify() == ARCH_ID_AT91SAM9263)
+#define cpu_is_at91sam9263()   (at91_soc_initdata.type == AT91_SOC_SAM9263)
 #else
 #define cpu_is_at91sam9263()   (0)
 #endif
 
 #ifdef CONFIG_ARCH_AT91SAM9RL
-#define cpu_is_at91sam9rl()    (at91_cpu_identify() == ARCH_ID_AT91SAM9RL64)
+#define cpu_is_at91sam9rl()    (at91_soc_initdata.type == AT91_SOC_SAM9RL)
 #else
 #define cpu_is_at91sam9rl()    (0)
 #endif
 
 #ifdef CONFIG_ARCH_AT91SAM9G45
-#define cpu_is_at91sam9g45()   (at91_cpu_identify() == ARCH_ID_AT91SAM9G45)
-#define cpu_is_at91sam9g45es() (at91_cpu_fully_identify() == ARCH_ID_AT91SAM9G45ES)
-#define cpu_is_at91sam9m10()    (cpu_is_at91sam9g45() && \
-                                (at91_exid_identify() == ARCH_EXID_AT91SAM9M10))
-#define cpu_is_at91sam9m46()    (cpu_is_at91sam9g45() && \
-                                (at91_exid_identify() == ARCH_EXID_AT91SAM9G46))
-#define cpu_is_at91sam9m11()    (cpu_is_at91sam9g45() && \
-                                (at91_exid_identify() == ARCH_EXID_AT91SAM9M11))
+#define cpu_is_at91sam9g45()   (at91_soc_initdata.type == AT91_SOC_SAM9G45)
+#define cpu_is_at91sam9g45es() (at91_soc_initdata.subtype == AT91_SOC_SAM9G45ES)
+#define cpu_is_at91sam9m10()   (at91_soc_initdata.subtype == AT91_SOC_SAM9M10)
+#define cpu_is_at91sam9g46()   (at91_soc_initdata.subtype == AT91_SOC_SAM9G46)
+#define cpu_is_at91sam9m11()   (at91_soc_initdata.subtype == AT91_SOC_SAM9M11)
 #else
 #define cpu_is_at91sam9g45()   (0)
 #define cpu_is_at91sam9g45es() (0)
@@ -156,17 +180,12 @@ extern int rm9200_type;
 #endif
 
 #ifdef CONFIG_ARCH_AT91SAM9X5
-#define cpu_is_at91sam9x5()    (at91_cpu_identify() == ARCH_ID_AT91SAM9X5)
-#define cpu_is_at91sam9g15()   (cpu_is_at91sam9x5() && \
-                               (at91_exid_identify() == ARCH_EXID_AT91SAM9G15))
-#define cpu_is_at91sam9g35()   (cpu_is_at91sam9x5() && \
-                               (at91_exid_identify() == ARCH_EXID_AT91SAM9G35))
-#define cpu_is_at91sam9x35()   (cpu_is_at91sam9x5() && \
-                               (at91_exid_identify() == ARCH_EXID_AT91SAM9X35))
-#define cpu_is_at91sam9g25()   (cpu_is_at91sam9x5() && \
-                               (at91_exid_identify() == ARCH_EXID_AT91SAM9G25))
-#define cpu_is_at91sam9x25()   (cpu_is_at91sam9x5() && \
-                               (at91_exid_identify() == ARCH_EXID_AT91SAM9X25))
+#define cpu_is_at91sam9x5()    (at91_soc_initdata.type == AT91_SOC_SAM9X5)
+#define cpu_is_at91sam9g15()   (at91_soc_initdata.subtype == AT91_SOC_SAM9G15)
+#define cpu_is_at91sam9g35()   (at91_soc_initdata.subtype == AT91_SOC_SAM9G35)
+#define cpu_is_at91sam9x35()   (at91_soc_initdata.subtype == AT91_SOC_SAM9X35)
+#define cpu_is_at91sam9g25()   (at91_soc_initdata.subtype == AT91_SOC_SAM9G25)
+#define cpu_is_at91sam9x25()   (at91_soc_initdata.subtype == AT91_SOC_SAM9X25)
 #else
 #define cpu_is_at91sam9x5()    (0)
 #define cpu_is_at91sam9g15()   (0)
@@ -177,9 +196,9 @@ extern int rm9200_type;
 #endif
 
 #ifdef CONFIG_ARCH_AT91CAP9
-#define cpu_is_at91cap9()      (at91_cpu_identify() == ARCH_ID_AT91CAP9)
-#define cpu_is_at91cap9_revB() (at91cap9_rev_identify() == ARCH_REVISION_CAP9_B)
-#define cpu_is_at91cap9_revC() (at91cap9_rev_identify() == ARCH_REVISION_CAP9_C)
+#define cpu_is_at91cap9()      (at91_soc_initdata.type == AT91_SOC_CAP9)
+#define cpu_is_at91cap9_revB() (at91_soc_initdata.subtype == AT91_SOC_CAP9_REV_B)
+#define cpu_is_at91cap9_revC() (at91_soc_initdata.subtype == AT91_SOC_CAP9_REV_C)
 #else
 #define cpu_is_at91cap9()      (0)
 #define cpu_is_at91cap9_revB() (0)
@@ -192,4 +211,4 @@ extern int rm9200_type;
  */
 #define cpu_is_at32ap7000()    (0)
 
-#endif
+#endif /* __MACH_CPU_H__ */
index 0f959fa..bc1e0b2 100644 (file)
 #include <mach/at91_dbgu.h>
 
        .macro  addruart, rp, rv
-       ldr     \rp, =(AT91_BASE_SYS + AT91_DBGU)               @ System peripherals (phys address)
-       ldr     \rv, =(AT91_VA_BASE_SYS + AT91_DBGU)            @ System peripherals (virt address)
+       ldr     \rp, =(AT91_BASE_SYS + AT91_DBGU)       @ System peripherals (phys address)
+       ldr     \rv, =(AT91_VA_BASE_SYS + AT91_DBGU)    @ System peripherals (virt address)
        .endm
 
        .macro  senduart,rd,rx
-       strb    \rd, [\rx, #(AT91_DBGU_THR - AT91_DBGU)]        @ Write to Transmitter Holding Register
+       strb    \rd, [\rx, #(AT91_DBGU_THR)]            @ Write to Transmitter Holding Register
        .endm
 
        .macro  waituart,rd,rx
-1001:  ldr     \rd, [\rx, #(AT91_DBGU_SR - AT91_DBGU)]         @ Read Status Register
-       tst     \rd, #AT91_DBGU_TXRDY                           @ DBGU_TXRDY = 1 when ready to transmit
+1001:  ldr     \rd, [\rx, #(AT91_DBGU_SR)]             @ Read Status Register
+       tst     \rd, #AT91_DBGU_TXRDY                   @ DBGU_TXRDY = 1 when ready to transmit
        beq     1001b
        .endm
 
        .macro  busyuart,rd,rx
-1001:  ldr     \rd, [\rx, #(AT91_DBGU_SR - AT91_DBGU)]         @ Read Status Register
-       tst     \rd, #AT91_DBGU_TXEMPTY                         @ DBGU_TXEMPTY = 1 when transmission complete
+1001:  ldr     \rd, [\rx, #(AT91_DBGU_SR)]             @ Read Status Register
+       tst     \rd, #AT91_DBGU_TXEMPTY                 @ DBGU_TXEMPTY = 1 when transmission complete
        beq     1001b
        .endm
 
index 1008b9f..483478d 100644 (file)
 #error "Unsupported AT91 processor"
 #endif
 
+#if !defined(CONFIG_ARCH_AT91X40)
+/*
+ * On all at91 except rm9200 and x40 have the System Controller starts
+ * at address 0xffffc000 and has a size of 16KiB.
+ *
+ * On rm9200 it's start at 0xfffe4000 of 111KiB with non reserved data starting
+ * at 0xfffff000
+ *
+ * Removes the individual definitions of AT91_BASE_SYS and
+ * replaces them with a common version at base 0xfffffc000 and size 16KiB
+ * and map the same memory space
+ */
+#define AT91_BASE_SYS  0xffffc000
+#endif
 
 /*
  * Peripheral identifiers/interrupts.
index 0b0cccc..4298e78 100644 (file)
 #ifndef __ASM_ARCH_IO_H
 #define __ASM_ARCH_IO_H
 
+#include <mach/hardware.h>
+
 #define IO_SPACE_LIMIT         0xFFFFFFFF
 
 #define __io(a)                __typesafe_io(a)
 #define __mem_pci(a)   (a)
 
-
 #ifndef __ASSEMBLY__
 
+#ifndef CONFIG_ARCH_AT91X40
+#define __arch_ioremap at91_ioremap
+#define __arch_iounmap at91_iounmap
+#endif
+
+void __iomem *at91_ioremap(unsigned long phys, size_t size, unsigned int type);
+void at91_iounmap(volatile void __iomem *addr);
+
 static inline unsigned int at91_sys_read(unsigned int reg_offset)
 {
        void __iomem *addr = (void __iomem *)AT91_VA_BASE_SYS;
diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
new file mode 100644 (file)
index 0000000..aa64294
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2007 Atmel Corporation.
+ * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Under GPLv2
+ */
+
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+
+#include <asm/mach/map.h>
+
+#include <mach/hardware.h>
+#include <mach/cpu.h>
+#include <mach/at91_dbgu.h>
+#include <mach/at91_pmc.h>
+
+#include "soc.h"
+#include "generic.h"
+
+struct at91_init_soc __initdata at91_boot_soc;
+
+struct at91_socinfo at91_soc_initdata;
+EXPORT_SYMBOL(at91_soc_initdata);
+
+void __init at91rm9200_set_type(int type)
+{
+       if (type == ARCH_REVISON_9200_PQFP)
+               at91_soc_initdata.subtype = AT91_SOC_RM9200_BGA;
+       else
+               at91_soc_initdata.subtype = AT91_SOC_RM9200_PQFP;
+}
+
+void __init at91_init_irq_default(void)
+{
+       at91_init_interrupts(at91_boot_soc.default_irq_priority);
+}
+
+void __init at91_init_interrupts(unsigned int *priority)
+{
+       /* Initialize the AIC interrupt controller */
+       at91_aic_init(priority);
+
+       /* Enable GPIO interrupts */
+       at91_gpio_irq_setup();
+}
+
+static struct map_desc sram_desc[2] __initdata;
+
+void __init at91_init_sram(int bank, unsigned long base, unsigned int length)
+{
+       struct map_desc *desc = &sram_desc[bank];
+
+       desc->virtual = AT91_IO_VIRT_BASE - length;
+       if (bank > 0)
+               desc->virtual -= sram_desc[bank - 1].length;
+
+       desc->pfn = __phys_to_pfn(base);
+       desc->length = length;
+       desc->type = MT_DEVICE;
+
+       pr_info("AT91: sram at 0x%lx of 0x%x mapped at 0x%lx\n",
+               base, length, desc->virtual);
+
+       iotable_init(desc, 1);
+}
+
+static struct map_desc at91_io_desc __initdata = {
+       .virtual        = AT91_VA_BASE_SYS,
+       .pfn            = __phys_to_pfn(AT91_BASE_SYS),
+       .length         = SZ_16K,
+       .type           = MT_DEVICE,
+};
+
+void __iomem *at91_ioremap(unsigned long p, size_t size, unsigned int type)
+{
+       if (p >= AT91_BASE_SYS && p <= (AT91_BASE_SYS + SZ_16K - 1))
+               return (void __iomem *)AT91_IO_P2V(p);
+
+       return __arm_ioremap_caller(p, size, type, __builtin_return_address(0));
+}
+EXPORT_SYMBOL(at91_ioremap);
+
+void at91_iounmap(volatile void __iomem *addr)
+{
+       unsigned long virt = (unsigned long)addr;
+
+       if (virt >= VMALLOC_START && virt < VMALLOC_END)
+               __iounmap(addr);
+}
+EXPORT_SYMBOL(at91_iounmap);
+
+#define AT91_DBGU0     0xfffff200
+#define AT91_DBGU1     0xffffee00
+
+static void __init soc_detect(u32 dbgu_base)
+{
+       u32 cidr, socid;
+
+       cidr = __raw_readl(AT91_IO_P2V(dbgu_base) + AT91_DBGU_CIDR);
+       socid = cidr & ~AT91_CIDR_VERSION;
+
+       switch (socid) {
+       case ARCH_ID_AT91CAP9: {
+#ifdef CONFIG_AT91_PMC_UNIT
+               u32 pmc_ver = at91_sys_read(AT91_PMC_VER);
+
+               if (pmc_ver == ARCH_REVISION_CAP9_B)
+                       at91_soc_initdata.subtype = AT91_SOC_CAP9_REV_B;
+               else if (pmc_ver == ARCH_REVISION_CAP9_C)
+                       at91_soc_initdata.subtype = AT91_SOC_CAP9_REV_C;
+#endif
+               at91_soc_initdata.type = AT91_SOC_CAP9;
+               at91_boot_soc = at91cap9_soc;
+               break;
+       }
+
+       case ARCH_ID_AT91RM9200:
+               at91_soc_initdata.type = AT91_SOC_RM9200;
+               at91_boot_soc = at91rm9200_soc;
+               break;
+
+       case ARCH_ID_AT91SAM9260:
+               at91_soc_initdata.type = AT91_SOC_SAM9260;
+               at91_boot_soc = at91sam9260_soc;
+               break;
+
+       case ARCH_ID_AT91SAM9261:
+               at91_soc_initdata.type = AT91_SOC_SAM9261;
+               at91_boot_soc = at91sam9261_soc;
+               break;
+
+       case ARCH_ID_AT91SAM9263:
+               at91_soc_initdata.type = AT91_SOC_SAM9263;
+               at91_boot_soc = at91sam9263_soc;
+               break;
+
+       case ARCH_ID_AT91SAM9G20:
+               at91_soc_initdata.type = AT91_SOC_SAM9G20;
+               at91_boot_soc = at91sam9260_soc;
+               break;
+
+       case ARCH_ID_AT91SAM9G45:
+               at91_soc_initdata.type = AT91_SOC_SAM9G45;
+               if (cidr == ARCH_ID_AT91SAM9G45ES)
+                       at91_soc_initdata.subtype = AT91_SOC_SAM9G45ES;
+               at91_boot_soc = at91sam9g45_soc;
+               break;
+
+       case ARCH_ID_AT91SAM9RL64:
+               at91_soc_initdata.type = AT91_SOC_SAM9RL;
+               at91_boot_soc = at91sam9rl_soc;
+               break;
+
+       case ARCH_ID_AT91SAM9X5:
+               at91_soc_initdata.type = AT91_SOC_SAM9X5;
+               at91_boot_soc = at91sam9x5_soc;
+               break;
+       }
+
+       /* at91sam9g10 */
+       if ((cidr & ~AT91_CIDR_EXT) == ARCH_ID_AT91SAM9G10) {
+               at91_soc_initdata.type = AT91_SOC_SAM9G10;
+               at91_boot_soc = at91sam9261_soc;
+       }
+       /* at91sam9xe */
+       else if ((cidr & AT91_CIDR_ARCH) == ARCH_FAMILY_AT91SAM9XE) {
+               at91_soc_initdata.type = AT91_SOC_SAM9260;
+               at91_soc_initdata.subtype = AT91_SOC_SAM9XE;
+               at91_boot_soc = at91sam9260_soc;
+       }
+
+       if (!at91_soc_is_detected())
+               return;
+
+       at91_soc_initdata.cidr = cidr;
+
+       /* sub version of soc */
+       at91_soc_initdata.exid = __raw_readl(AT91_IO_P2V(dbgu_base) + AT91_DBGU_EXID);
+
+       if (at91_soc_initdata.type == AT91_SOC_SAM9G45) {
+               switch (at91_soc_initdata.exid) {
+               case ARCH_EXID_AT91SAM9M10:
+                       at91_soc_initdata.subtype = AT91_SOC_SAM9M10;
+                       break;
+               case ARCH_EXID_AT91SAM9G46:
+                       at91_soc_initdata.subtype = AT91_SOC_SAM9G46;
+                       break;
+               case ARCH_EXID_AT91SAM9M11:
+                       at91_soc_initdata.subtype = AT91_SOC_SAM9M11;
+                       break;
+               }
+       }
+
+       if (at91_soc_initdata.type == AT91_SOC_SAM9X5) {
+               switch (at91_soc_initdata.exid) {
+               case ARCH_EXID_AT91SAM9G15:
+                       at91_soc_initdata.subtype = AT91_SOC_SAM9G15;
+                       break;
+               case ARCH_EXID_AT91SAM9G35:
+                       at91_soc_initdata.subtype = AT91_SOC_SAM9G35;
+                       break;
+               case ARCH_EXID_AT91SAM9X35:
+                       at91_soc_initdata.subtype = AT91_SOC_SAM9X35;
+                       break;
+               case ARCH_EXID_AT91SAM9G25:
+                       at91_soc_initdata.subtype = AT91_SOC_SAM9G25;
+                       break;
+               case ARCH_EXID_AT91SAM9X25:
+                       at91_soc_initdata.subtype = AT91_SOC_SAM9X25;
+                       break;
+               }
+       }
+}
+
+static const char *soc_name[] = {
+       [AT91_SOC_RM9200]       = "at91rm9200",
+       [AT91_SOC_CAP9]         = "at91cap9",
+       [AT91_SOC_SAM9260]      = "at91sam9260",
+       [AT91_SOC_SAM9261]      = "at91sam9261",
+       [AT91_SOC_SAM9263]      = "at91sam9263",
+       [AT91_SOC_SAM9G10]      = "at91sam9g10",
+       [AT91_SOC_SAM9G20]      = "at91sam9g20",
+       [AT91_SOC_SAM9G45]      = "at91sam9g45",
+       [AT91_SOC_SAM9RL]       = "at91sam9rl",
+       [AT91_SOC_SAM9X5]       = "at91sam9x5",
+       [AT91_SOC_NONE]         = "Unknown"
+};
+
+const char *at91_get_soc_type(struct at91_socinfo *c)
+{
+       return soc_name[c->type];
+}
+EXPORT_SYMBOL(at91_get_soc_type);
+
+static const char *soc_subtype_name[] = {
+       [AT91_SOC_RM9200_BGA]   = "at91rm9200 BGA",
+       [AT91_SOC_RM9200_PQFP]  = "at91rm9200 PQFP",
+       [AT91_SOC_CAP9_REV_B]   = "at91cap9 revB",
+       [AT91_SOC_CAP9_REV_C]   = "at91cap9 revC",
+       [AT91_SOC_SAM9XE]       = "at91sam9xe",
+       [AT91_SOC_SAM9G45ES]    = "at91sam9g45es",
+       [AT91_SOC_SAM9M10]      = "at91sam9m10",
+       [AT91_SOC_SAM9G46]      = "at91sam9g46",
+       [AT91_SOC_SAM9M11]      = "at91sam9m11",
+       [AT91_SOC_SAM9G15]      = "at91sam9g15",
+       [AT91_SOC_SAM9G35]      = "at91sam9g35",
+       [AT91_SOC_SAM9X35]      = "at91sam9x35",
+       [AT91_SOC_SAM9G25]      = "at91sam9g25",
+       [AT91_SOC_SAM9X25]      = "at91sam9x25",
+       [AT91_SOC_SUBTYPE_NONE] = "Unknown"
+};
+
+const char *at91_get_soc_subtype(struct at91_socinfo *c)
+{
+       return soc_subtype_name[c->subtype];
+}
+EXPORT_SYMBOL(at91_get_soc_subtype);
+
+void __init at91_map_io(void)
+{
+       /* Map peripherals */
+       iotable_init(&at91_io_desc, 1);
+
+       at91_soc_initdata.type = AT91_SOC_NONE;
+       at91_soc_initdata.subtype = AT91_SOC_SUBTYPE_NONE;
+
+       soc_detect(AT91_DBGU0);
+       if (!at91_soc_is_detected())
+               soc_detect(AT91_DBGU1);
+
+       if (!at91_soc_is_detected())
+               panic("AT91: Impossible to detect the SOC type");
+
+       pr_info("AT91: Detected soc type: %s\n",
+               at91_get_soc_type(&at91_soc_initdata));
+       pr_info("AT91: Detected soc subtype: %s\n",
+               at91_get_soc_subtype(&at91_soc_initdata));
+
+       if (!at91_soc_is_enabled())
+               panic("AT91: Soc not enabled");
+
+       if (at91_boot_soc.map_io)
+               at91_boot_soc.map_io();
+}
+
+void __init at91_initialize(unsigned long main_clock)
+{
+       /* Init clock subsystem */
+       at91_clock_init(main_clock);
+
+       /* Register the processor-specific clocks */
+       at91_boot_soc.register_clocks();
+
+       at91_boot_soc.init();
+}
diff --git a/arch/arm/mach-at91/soc.h b/arch/arm/mach-at91/soc.h
new file mode 100644 (file)
index 0000000..21ed881
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Under GPLv2
+ */
+
+struct at91_init_soc {
+       unsigned int *default_irq_priority;
+       void (*map_io)(void);
+       void (*register_clocks)(void);
+       void (*init)(void);
+};
+
+extern struct at91_init_soc at91_boot_soc;
+extern struct at91_init_soc at91cap9_soc;
+extern struct at91_init_soc at91rm9200_soc;
+extern struct at91_init_soc at91sam9260_soc;
+extern struct at91_init_soc at91sam9261_soc;
+extern struct at91_init_soc at91sam9263_soc;
+extern struct at91_init_soc at91sam9g45_soc;
+extern struct at91_init_soc at91sam9rl_soc;
+extern struct at91_init_soc at91sam9x5_soc;
+
+static inline int at91_soc_is_enabled(void)
+{
+       return at91_boot_soc.init != NULL;
+}
+
+#if !defined(CONFIG_ARCH_AT91CAP9)
+#define at91cap9_soc   at91_boot_soc
+#endif
+
+#if !defined(CONFIG_ARCH_AT91RM9200)
+#define at91rm9200_soc at91_boot_soc
+#endif
+
+#if !(defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20))
+#define at91sam9260_soc        at91_boot_soc
+#endif
+
+#if !(defined(CONFIG_ARCH_AT91SAM9261) || defined(CONFIG_ARCH_AT91SAM9G10))
+#define at91sam9261_soc        at91_boot_soc
+#endif
+
+#if !defined(CONFIG_ARCH_AT91SAM9263)
+#define at91sam9263_soc        at91_boot_soc
+#endif
+
+#if !defined(CONFIG_ARCH_AT91SAM9G45)
+#define at91sam9g45_soc        at91_boot_soc
+#endif
+
+#if !defined(CONFIG_ARCH_AT91SAM9RL)
+#define at91sam9rl_soc at91_boot_soc
+#endif
+
+#if !defined(CONFIG_ARCH_AT91SAM9X5)
+#define at91sam9x5_soc at91_boot_soc
+#endif
index a4ec080..06fd25d 100644 (file)
@@ -172,7 +172,7 @@ static struct pci_bus *cns3xxx_pci_scan_bus(int nr, struct pci_sys_data *sys)
        return pci_scan_bus(sys->busnr, &cns3xxx_pcie_ops, sys);
 }
 
-static int cns3xxx_pcie_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int cns3xxx_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        struct cns3xxx_pcie *cnspci = pdev_to_cnspci(dev);
        int irq = cnspci->irqs[slot];
index c2f1c47..aa2b3a0 100644 (file)
@@ -193,7 +193,7 @@ dove_pcie_scan_bus(int nr, struct pci_sys_data *sys)
        return bus;
 }
 
-static int __init dove_pcie_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init dove_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        struct pcie_port *pp = bus_to_port(dev->bus->number);
 
index ae3e1c8..32321f6 100644 (file)
@@ -16,7 +16,7 @@
 /* cats host-specific stuff */
 static int irqmap_cats[] __initdata = { IRQ_PCI, IRQ_IN0, IRQ_IN1, IRQ_IN3 };
 
-static int __init cats_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init cats_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        if (dev->irq >= 255)
                return -1;      /* not a valid interrupt. */
index e5ab5bd..511c673 100644 (file)
@@ -15,7 +15,7 @@
 
 static int irqmap_ebsa285[] __initdata = { IRQ_IN3, IRQ_IN1, IRQ_IN0, IRQ_PCI };
 
-static int __init ebsa285_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init ebsa285_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        if (dev->vendor == PCI_VENDOR_ID_CONTAQ &&
            dev->device == PCI_DEVICE_ID_CONTAQ_82C693)
index e263d6d..6218761 100644 (file)
@@ -17,7 +17,7 @@
  * We now use the slot ID instead of the device identifiers to select
  * which interrupt is routed where.
  */
-static int __init netwinder_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init netwinder_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        switch (slot) {
        case 0:  /* host bridge */
index d5fca95..aeb651d 100644 (file)
@@ -18,7 +18,8 @@ static int irqmap_personal_server[] __initdata = {
        IRQ_DOORBELLHOST, IRQ_DMA1, IRQ_DMA2, IRQ_PCI
 };
 
-static int __init personal_server_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init personal_server_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        unsigned char line;
 
index dcc4172..4aabeb2 100644 (file)
@@ -587,9 +587,9 @@ static struct clk_lookup lookups[] __initdata = {
        _REGISTER_CLOCK(NULL, "mma", mma_clk)
        _REGISTER_CLOCK("imx_udc.0", NULL, usbd_clk)
        _REGISTER_CLOCK(NULL, "gpt", gpt_clk)
-       _REGISTER_CLOCK("imx-uart.0", NULL, uart_clk)
-       _REGISTER_CLOCK("imx-uart.1", NULL, uart_clk)
-       _REGISTER_CLOCK("imx-uart.2", NULL, uart_clk)
+       _REGISTER_CLOCK("imx1-uart.0", NULL, uart_clk)
+       _REGISTER_CLOCK("imx1-uart.1", NULL, uart_clk)
+       _REGISTER_CLOCK("imx1-uart.2", NULL, uart_clk)
        _REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk)
        _REGISTER_CLOCK("imx1-cspi.0", NULL, spi_clk)
        _REGISTER_CLOCK("imx1-cspi.1", NULL, spi_clk)
index bf30a8c..ee15d8c 100644 (file)
@@ -1162,10 +1162,10 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK(NULL, "perclk3", per_clk[2])
        _REGISTER_CLOCK(NULL, "perclk4", per_clk[3])
        _REGISTER_CLOCK(NULL, "clko", clko_clk)
-       _REGISTER_CLOCK("imx-uart.0", NULL, uart_clk[0])
-       _REGISTER_CLOCK("imx-uart.1", NULL, uart_clk[1])
-       _REGISTER_CLOCK("imx-uart.2", NULL, uart_clk[2])
-       _REGISTER_CLOCK("imx-uart.3", NULL, uart_clk[3])
+       _REGISTER_CLOCK("imx21-uart.0", NULL, uart_clk[0])
+       _REGISTER_CLOCK("imx21-uart.1", NULL, uart_clk[1])
+       _REGISTER_CLOCK("imx21-uart.2", NULL, uart_clk[2])
+       _REGISTER_CLOCK("imx21-uart.3", NULL, uart_clk[3])
        _REGISTER_CLOCK(NULL, "gpt1", gpt_clk[0])
        _REGISTER_CLOCK(NULL, "gpt1", gpt_clk[1])
        _REGISTER_CLOCK(NULL, "gpt1", gpt_clk[2])
index af1c580..e63e235 100644 (file)
@@ -272,11 +272,12 @@ DEFINE_CLOCK(can2_clk,     1, CCM_CGCR1,  3, get_rate_ipg, NULL, NULL);
        },
 
 static struct clk_lookup lookups[] = {
-       _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk)
-       _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk)
-       _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk)
-       _REGISTER_CLOCK("imx-uart.3", NULL, uart4_clk)
-       _REGISTER_CLOCK("imx-uart.4", NULL, uart5_clk)
+       /* i.mx25 has the i.mx21 type uart */
+       _REGISTER_CLOCK("imx21-uart.0", NULL, uart1_clk)
+       _REGISTER_CLOCK("imx21-uart.1", NULL, uart2_clk)
+       _REGISTER_CLOCK("imx21-uart.2", NULL, uart3_clk)
+       _REGISTER_CLOCK("imx21-uart.3", NULL, uart4_clk)
+       _REGISTER_CLOCK("imx21-uart.4", NULL, uart5_clk)
        _REGISTER_CLOCK("mxc-ehci.0", "usb", usbotg_clk)
        _REGISTER_CLOCK("mxc-ehci.1", "usb", usbotg_clk)
        _REGISTER_CLOCK("mxc-ehci.2", "usb", usbotg_clk)
@@ -295,19 +296,20 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk)
        _REGISTER_CLOCK("imx-i2c.1", NULL, i2c_clk)
        _REGISTER_CLOCK("imx-i2c.2", NULL, i2c_clk)
-       _REGISTER_CLOCK("fec.0", NULL, fec_clk)
+       _REGISTER_CLOCK("imx25-fec.0", NULL, fec_clk)
        _REGISTER_CLOCK("imxdi_rtc.0", NULL, dryice_clk)
        _REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk)
        _REGISTER_CLOCK("imx2-wdt.0", NULL, wdt_clk)
        _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk)
        _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk)
-       _REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk)
-       _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx25.0", NULL, esdhc1_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx25.1", NULL, esdhc2_clk)
        _REGISTER_CLOCK("mx2-camera.0", NULL, csi_clk)
        _REGISTER_CLOCK(NULL, "audmux", audmux_clk)
        _REGISTER_CLOCK("flexcan.0", NULL, can1_clk)
        _REGISTER_CLOCK("flexcan.1", NULL, can2_clk)
-       _REGISTER_CLOCK("imx-sdma", NULL, sdma_clk)
+       /* i.mx25 has the i.mx35 type sdma */
+       _REGISTER_CLOCK("imx35-sdma", NULL, sdma_clk)
 };
 
 int __init mx25_clocks_init(void)
@@ -329,6 +331,9 @@ int __init mx25_clocks_init(void)
        __raw_writel(__raw_readl(CRM_BASE+0x64) | (1 << 7) | (1 << 0),
                        CRM_BASE + 0x64);
 
+       /* Clock source for gpt is ahb_div */
+       __raw_writel(__raw_readl(CRM_BASE+0x64) & ~(1 << 5), CRM_BASE + 0x64);
+
        mxc_timer_init(&gpt_clk, MX25_IO_ADDRESS(MX25_GPT1_BASE_ADDR), 54);
 
        return 0;
index 583f251..6912b82 100644 (file)
@@ -624,12 +624,13 @@ DEFINE_CLOCK1(csi_clk,     0, NULL,   0, parent, &csi_clk1, &per4_clk);
        },
 
 static struct clk_lookup lookups[] = {
-       _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk)
-       _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk)
-       _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk)
-       _REGISTER_CLOCK("imx-uart.3", NULL, uart4_clk)
-       _REGISTER_CLOCK("imx-uart.4", NULL, uart5_clk)
-       _REGISTER_CLOCK("imx-uart.5", NULL, uart6_clk)
+       /* i.mx27 has the i.mx21 type uart */
+       _REGISTER_CLOCK("imx21-uart.0", NULL, uart1_clk)
+       _REGISTER_CLOCK("imx21-uart.1", NULL, uart2_clk)
+       _REGISTER_CLOCK("imx21-uart.2", NULL, uart3_clk)
+       _REGISTER_CLOCK("imx21-uart.3", NULL, uart4_clk)
+       _REGISTER_CLOCK("imx21-uart.4", NULL, uart5_clk)
+       _REGISTER_CLOCK("imx21-uart.5", NULL, uart6_clk)
        _REGISTER_CLOCK(NULL, "gpt1", gpt1_clk)
        _REGISTER_CLOCK(NULL, "gpt2", gpt2_clk)
        _REGISTER_CLOCK(NULL, "gpt3", gpt3_clk)
@@ -662,7 +663,7 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK(NULL, "brom", brom_clk)
        _REGISTER_CLOCK(NULL, "emma", emma_clk)
        _REGISTER_CLOCK(NULL, "slcdc", slcdc_clk)
-       _REGISTER_CLOCK("fec.0", NULL, fec_clk)
+       _REGISTER_CLOCK("imx27-fec.0", NULL, fec_clk)
        _REGISTER_CLOCK(NULL, "emi", emi_clk)
        _REGISTER_CLOCK(NULL, "sahara2", sahara2_clk)
        _REGISTER_CLOCK(NULL, "ata", ata_clk)
index 25f343f..d973770 100644 (file)
@@ -547,11 +547,12 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK("fsl-usb2-udc", "usb", usb_clk1)
        _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", usb_clk2)
        _REGISTER_CLOCK("mx3-camera.0", NULL, csi_clk)
-       _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk)
-       _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk)
-       _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk)
-       _REGISTER_CLOCK("imx-uart.3", NULL, uart4_clk)
-       _REGISTER_CLOCK("imx-uart.4", NULL, uart5_clk)
+       /* i.mx31 has the i.mx21 type uart */
+       _REGISTER_CLOCK("imx21-uart.0", NULL, uart1_clk)
+       _REGISTER_CLOCK("imx21-uart.1", NULL, uart2_clk)
+       _REGISTER_CLOCK("imx21-uart.2", NULL, uart3_clk)
+       _REGISTER_CLOCK("imx21-uart.3", NULL, uart4_clk)
+       _REGISTER_CLOCK("imx21-uart.4", NULL, uart5_clk)
        _REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk)
        _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk)
        _REGISTER_CLOCK("imx-i2c.2", NULL, i2c3_clk)
@@ -564,7 +565,7 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK(NULL, "ata", ata_clk)
        _REGISTER_CLOCK(NULL, "rtic", rtic_clk)
        _REGISTER_CLOCK(NULL, "rng", rng_clk)
-       _REGISTER_CLOCK("imx-sdma", NULL, sdma_clk1)
+       _REGISTER_CLOCK("imx31-sdma", NULL, sdma_clk1)
        _REGISTER_CLOCK(NULL, "sdma_ipg", sdma_clk2)
        _REGISTER_CLOCK(NULL, "mstick", mstick1_clk)
        _REGISTER_CLOCK(NULL, "mstick", mstick2_clk)
index 5a4cc1e..88b62a0 100644 (file)
@@ -458,10 +458,11 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK("imx-epit.0", NULL, epit1_clk)
        _REGISTER_CLOCK("imx-epit.1", NULL, epit2_clk)
        _REGISTER_CLOCK(NULL, "esai", esai_clk)
-       _REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk)
-       _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_clk)
-       _REGISTER_CLOCK("sdhci-esdhc-imx.2", NULL, esdhc3_clk)
-       _REGISTER_CLOCK("fec.0", NULL, fec_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx35.0", NULL, esdhc1_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx35.1", NULL, esdhc2_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx35.2", NULL, esdhc3_clk)
+       /* i.mx35 has the i.mx27 type fec */
+       _REGISTER_CLOCK("imx27-fec.0", NULL, fec_clk)
        _REGISTER_CLOCK(NULL, "gpio", gpio1_clk)
        _REGISTER_CLOCK(NULL, "gpio", gpio2_clk)
        _REGISTER_CLOCK(NULL, "gpio", gpio3_clk)
@@ -481,14 +482,15 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK(NULL, "rtc", rtc_clk)
        _REGISTER_CLOCK(NULL, "rtic", rtic_clk)
        _REGISTER_CLOCK(NULL, "scc", scc_clk)
-       _REGISTER_CLOCK("imx-sdma", NULL, sdma_clk)
+       _REGISTER_CLOCK("imx35-sdma", NULL, sdma_clk)
        _REGISTER_CLOCK(NULL, "spba", spba_clk)
        _REGISTER_CLOCK(NULL, "spdif", spdif_clk)
        _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk)
        _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk)
-       _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk)
-       _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk)
-       _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk)
+       /* i.mx35 has the i.mx21 type uart */
+       _REGISTER_CLOCK("imx21-uart.0", NULL, uart1_clk)
+       _REGISTER_CLOCK("imx21-uart.1", NULL, uart2_clk)
+       _REGISTER_CLOCK("imx21-uart.2", NULL, uart3_clk)
        _REGISTER_CLOCK("mxc-ehci.0", "usb", usbotg_clk)
        _REGISTER_CLOCK("mxc-ehci.1", "usb", usbotg_clk)
        _REGISTER_CLOCK("mxc-ehci.2", "usb", usbotg_clk)
index 01ebcb3..66e8726 100644 (file)
@@ -225,7 +225,8 @@ struct imx_ssi_platform_data eukrea_mbimxsd_ssi_pdata __initconst = {
 
 static struct esdhc_platform_data sd1_pdata = {
        .cd_gpio = GPIO_SD1CD,
-       .wp_gpio = -EINVAL,
+       .cd_type = ESDHC_CD_GPIO,
+       .wp_type = ESDHC_WP_NONE,
 };
 
 /*
index 558eb52..0f0af02 100644 (file)
@@ -236,7 +236,8 @@ struct imx_ssi_platform_data eukrea_mbimxsd_ssi_pdata __initconst = {
 
 static struct esdhc_platform_data sd1_pdata = {
        .cd_gpio = GPIO_SD1CD,
-       .wp_gpio = -EINVAL,
+       .cd_type = ESDHC_CD_GPIO,
+       .wp_type = ESDHC_WP_NONE,
 };
 
 /*
index 6707de0..6778f81 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/input.h>
 #include <linux/gpio.h>
 #include <linux/delay.h>
+#include <sound/tlv320aic32x4.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
@@ -196,6 +197,17 @@ static struct pca953x_platform_data visstrim_m10_pca9555_pdata = {
        .invert = 0,
 };
 
+static struct aic32x4_pdata visstrim_m10_aic32x4_pdata = {
+       .power_cfg = AIC32X4_PWR_MICBIAS_2075_LDOIN |
+                    AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE |
+                    AIC32X4_PWR_AIC32X4_LDO_ENABLE |
+                    AIC32X4_PWR_CMMODE_LDOIN_RANGE_18_36 |
+                    AIC32X4_PWR_CMMODE_HP_LDOIN_POWERED,
+       .micpga_routing = AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K |
+                        AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K,
+       .swapdacs = false,
+};
+
 static struct i2c_board_info visstrim_m10_i2c_devices[] = {
        {
                I2C_BOARD_INFO("pca9555", 0x20),
@@ -203,6 +215,7 @@ static struct i2c_board_info visstrim_m10_i2c_devices[] = {
        },
        {
                I2C_BOARD_INFO("tlv320aic32x4", 0x18),
+               .platform_data = &visstrim_m10_aic32x4_pdata,
        }
 };
 
index 01534bb..7f66a91 100644 (file)
@@ -215,6 +215,8 @@ static const struct imxi2c_platform_data mx25_3ds_i2c0_data __initconst = {
 static const struct esdhc_platform_data mx25pdk_esdhc_pdata __initconst = {
        .wp_gpio = SD1_GPIO_WP,
        .cd_gpio = SD1_GPIO_CD,
+       .wp_type = ESDHC_WP_GPIO,
+       .cd_type = ESDHC_CD_GPIO,
 };
 
 static void __init mx25pdk_init(void)
index 0ce4947..29ca890 100644 (file)
@@ -468,7 +468,7 @@ static struct i2c_board_info __initdata mx31ads_i2c1_devices[] = {
 #endif
 };
 
-static void mxc_init_i2c(void)
+static void __init mxc_init_i2c(void)
 {
        i2c_register_board_info(1, mx31ads_i2c1_devices,
                                ARRAY_SIZE(mx31ads_i2c1_devices));
@@ -486,7 +486,7 @@ static unsigned int ssi_pins[] = {
        MX31_PIN_STXD5__STXD5,
 };
 
-static void mxc_init_audio(void)
+static void __init mxc_init_audio(void)
 {
        imx31_add_imx_ssi(0, NULL);
        mxc_iomux_setup_multiple_pins(ssi_pins, ARRAY_SIZE(ssi_pins), "ssi");
index 750368d..126913a 100644 (file)
@@ -192,7 +192,7 @@ static struct mxc_usbh_platform_data usbh2_pdata __initdata = {
        .portsc = MXC_EHCI_MODE_ULPI | MXC_EHCI_UTMI_8BIT,
 };
 
-static void lilly1131_usb_init(void)
+static void __init lilly1131_usb_init(void)
 {
        imx31_add_mxc_ehci_hs(1, &usbh1_pdata);
 
index 163cc31..660ec3e 100644 (file)
@@ -349,6 +349,8 @@ __setup("otg_mode=", pcm043_otg_mode);
 static struct esdhc_platform_data sd1_pdata = {
        .wp_gpio = SD1_GPIO_WP,
        .cd_gpio = SD1_GPIO_CD,
+       .wp_type = ESDHC_WP_GPIO,
+       .cd_type = ESDHC_CD_GPIO,
 };
 
 /*
index 8bf0291..cc4d152 100644 (file)
@@ -79,7 +79,6 @@ static struct sdma_script_start_addrs imx25_sdma_script __initdata = {
 };
 
 static struct sdma_platform_data imx25_sdma_pdata __initdata = {
-       .sdma_version = 2,
        .fw_name = "sdma-imx25.bin",
        .script_addrs = &imx25_sdma_script,
 };
@@ -92,5 +91,6 @@ void __init imx25_soc_init(void)
        mxc_register_gpio("imx31-gpio", 2, MX25_GPIO3_BASE_ADDR, SZ_16K, MX25_INT_GPIO3, 0);
        mxc_register_gpio("imx31-gpio", 3, MX25_GPIO4_BASE_ADDR, SZ_16K, MX25_INT_GPIO4, 0);
 
-       imx_add_imx_sdma(MX25_SDMA_BASE_ADDR, MX25_INT_SDMA, &imx25_sdma_pdata);
+       /* i.mx25 has the i.mx35 type sdma */
+       imx_add_imx_sdma("imx35-sdma", MX25_SDMA_BASE_ADDR, MX25_INT_SDMA, &imx25_sdma_pdata);
 }
index 61bff38..b7c55e7 100644 (file)
@@ -69,7 +69,6 @@ static struct sdma_script_start_addrs imx31_to2_sdma_script __initdata = {
 };
 
 static struct sdma_platform_data imx31_sdma_pdata __initdata = {
-       .sdma_version = 1,
        .fw_name = "sdma-imx31-to2.bin",
        .script_addrs = &imx31_to2_sdma_script,
 };
@@ -88,5 +87,5 @@ void __init imx31_soc_init(void)
                imx31_sdma_pdata.script_addrs = &imx31_to1_sdma_script;
        }
 
-       imx_add_imx_sdma(MX31_SDMA_BASE_ADDR, MX31_INT_SDMA, &imx31_sdma_pdata);
+       imx_add_imx_sdma("imx31-sdma", MX31_SDMA_BASE_ADDR, MX31_INT_SDMA, &imx31_sdma_pdata);
 }
index 98769ae..f49bac7 100644 (file)
@@ -86,7 +86,6 @@ static struct sdma_script_start_addrs imx35_to2_sdma_script __initdata = {
 };
 
 static struct sdma_platform_data imx35_sdma_pdata __initdata = {
-       .sdma_version = 2,
        .fw_name = "sdma-imx35-to2.bin",
        .script_addrs = &imx35_to2_sdma_script,
 };
@@ -106,5 +105,5 @@ void __init imx35_soc_init(void)
                imx35_sdma_pdata.script_addrs = &imx35_to1_sdma_script;
        }
 
-       imx_add_imx_sdma(MX35_SDMA_BASE_ADDR, MX35_INT_SDMA, &imx35_sdma_pdata);
+       imx_add_imx_sdma("imx35-sdma", MX35_SDMA_BASE_ADDR, MX35_INT_SDMA, &imx35_sdma_pdata);
 }
index 2fdb954..520b6bf 100644 (file)
@@ -95,7 +95,7 @@ static int irq_tab[4] __initdata = {
  * map the specified device/slot/pin to an IRQ.  This works out such
  * that slot 9 pin 1 is INT0, pin 2 is INT1, and slot 10 pin 1 is INT1.
  */
-static int __init integrator_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init integrator_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int intnr = ((slot - 9) + (pin - 1)) & 3;
 
index 9b5a63f..23dfaff 100644 (file)
@@ -30,7 +30,7 @@
 extern int init_atu; /* Flag to select which ATU(s) to initialize / disable */
 
 static int __init
-iq81340mc_pcix_map_irq(struct pci_dev *dev, u8 idsel, u8 pin)
+iq81340mc_pcix_map_irq(const struct pci_dev *dev, u8 idsel, u8 pin)
 {
        switch (idsel) {
        case 1:
index 0690b1d..251c408 100644 (file)
@@ -388,7 +388,7 @@ static int iop13xx_atue_pci_status(int clear)
 }
 
 static int
-iop13xx_pcie_map_irq(struct pci_dev *dev, u8 idsel, u8 pin)
+iop13xx_pcie_map_irq(const struct pci_dev *dev, u8 idsel, u8 pin)
 {
        WARN_ON(idsel != 0);
 
index 779f924..6cbffbf 100644 (file)
@@ -81,7 +81,7 @@ void __init em7210_map_io(void)
 #define INTD   IRQ_IOP32X_XINT3
 
 static int __init
-em7210_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+em7210_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static int pci_irq_table[][4] = {
                /*
index c6b6f9c..ceef5d4 100644 (file)
@@ -77,7 +77,7 @@ void __init glantank_map_io(void)
 #define INTD   IRQ_IOP32X_XINT3
 
 static int __init
-glantank_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+glantank_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static int pci_irq_table[][4] = {
                /*
index fde962c..3a62514 100644 (file)
@@ -103,7 +103,7 @@ void __init iq31244_map_io(void)
  * EP80219/IQ31244 PCI.
  */
 static int __init
-ep80219_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+ep80219_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
 
@@ -139,7 +139,7 @@ static struct hw_pci ep80219_pci __initdata = {
 };
 
 static int __init
-iq31244_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+iq31244_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
 
index 3a95950..35b7e69 100644 (file)
@@ -71,7 +71,7 @@ void __init iq80321_map_io(void)
  * IQ80321 PCI.
  */
 static int __init
-iq80321_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+iq80321_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
 
index 626aa37..1a374ea 100644 (file)
@@ -78,7 +78,7 @@ void __init n2100_map_io(void)
  * N2100 PCI.
  */
 static int __init
-n2100_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+n2100_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
 
index c565f8d..637c027 100644 (file)
@@ -54,7 +54,7 @@ static struct sys_timer iq80331_timer = {
  * IQ80331 PCI.
  */
 static int __init
-iq80331_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+iq80331_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
 
index 36a9efb..90a0436 100644 (file)
@@ -54,7 +54,7 @@ static struct sys_timer iq80332_timer = {
  * IQ80332 PCI.
  */
 static int __init
-iq80332_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+iq80332_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
 
index 88663ab..62c60ad 100644 (file)
@@ -148,7 +148,8 @@ static struct pci_bus * __init enp2611_pci_scan_bus(int nr,
        return pci_scan_bus(sys->busnr, &enp2611_pci_ops, sys);
 }
 
-static int __init enp2611_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init enp2611_pci_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        int irq;
 
index dfffc1e..5bad1a8 100644 (file)
@@ -78,7 +78,8 @@ int ixdp2400_pci_setup(int nr, struct pci_sys_data *sys)
        return 1;
 }
 
-static int __init ixdp2400_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init ixdp2400_pci_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        if (ixdp2x00_master_npu()) {
 
index cd4c9bc..3d3cef8 100644 (file)
@@ -161,7 +161,8 @@ static int __init ixdp2800_pci_setup(int nr, struct pci_sys_data *sys)
        return 1;
 }
 
-static int __init ixdp2800_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init ixdp2800_pci_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        if (ixdp2x00_master_npu()) {
 
index 84835b2..be2a254 100644 (file)
@@ -252,7 +252,8 @@ void __init ixdp2x01_pci_preinit(void)
 
 #define DEVPIN(dev, pin) ((pin) | ((dev) << 3))
 
-static int __init ixdp2x01_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init ixdp2x01_pci_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        u8 bus = dev->bus->number;
        u32 devpin = DEVPIN(PCI_SLOT(dev->devfn), pin);
index 8dcba17..ec028e3 100644 (file)
@@ -168,7 +168,7 @@ void __init ixdp2351_init_irq(void)
  */
 #define DEVPIN(dev, pin) ((pin) | ((dev) << 3))
 
-static int __init ixdp2351_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init ixdp2351_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        u8 bus = dev->bus->number;
        u32 devpin = DEVPIN(PCI_SLOT(dev->devfn), pin);
index 8fe0c62..844551d 100644 (file)
@@ -56,7 +56,8 @@
 #define INTC_PIN       IXP23XX_GPIO_PIN_11
 #define INTD_PIN       IXP23XX_GPIO_PIN_12
 
-static int __init roadrunner_map_irq(struct pci_dev *dev, u8 idsel, u8 pin)
+static int __init roadrunner_map_irq(const struct pci_dev *dev, u8 idsel,
+       u8 pin)
 {
        static int pci_card_slot_irq[] = {INTB, INTC, INTD, INTA};
        static int pmc_card_slot_irq[] = {INTA, INTB, INTC, INTD};
index 162043f..8fea0a3 100644 (file)
@@ -46,7 +46,7 @@ void __init avila_pci_preinit(void)
        ixp4xx_pci_preinit();
 }
 
-static int __init avila_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init avila_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static int pci_irq_table[IRQ_LINES] = {
                IXP4XX_GPIO_IRQ(INTA),
index 37fda7d..71f5c9c 100644 (file)
@@ -37,7 +37,7 @@ void __init coyote_pci_preinit(void)
        ixp4xx_pci_preinit();
 }
 
-static int __init coyote_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init coyote_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        if (slot == SLOT0_DEVID)
                return IXP4XX_GPIO_IRQ(SLOT0_INTA);
index c761201..0532510 100644 (file)
@@ -44,7 +44,7 @@ void __init dsmg600_pci_preinit(void)
        ixp4xx_pci_preinit();
 }
 
-static int __init dsmg600_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init dsmg600_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static int pci_irq_table[MAX_DEV][IRQ_LINES] = {
                { IXP4XX_GPIO_IRQ(INTE), -1, -1 },
index 44ccde9..d2ac803 100644 (file)
@@ -38,7 +38,7 @@ void __init fsg_pci_preinit(void)
        ixp4xx_pci_preinit();
 }
 
-static int __init fsg_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init fsg_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static int pci_irq_table[IRQ_LINES] = {
                IXP4XX_GPIO_IRQ(INTC),
index fc11241..76581fb 100644 (file)
@@ -35,7 +35,8 @@ void __init gateway7001_pci_preinit(void)
        ixp4xx_pci_preinit();
 }
 
-static int __init gateway7001_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init gateway7001_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        if (slot == 1)
                return IRQ_IXP4XX_GPIO11;
index 5f00ad2..7548d9a 100644 (file)
@@ -462,7 +462,7 @@ static void __init gmlr_pci_postinit(void)
        }
 }
 
-static int __init gmlr_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init gmlr_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        switch(slot) {
        case SLOT_ETHA: return IXP4XX_GPIO_IRQ(GPIO_IRQ_ETHA);
index 38cc072..d68fc06 100644 (file)
@@ -49,7 +49,7 @@ void __init gtwx5715_pci_preinit(void)
 }
 
 
-static int __init gtwx5715_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init gtwx5715_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int rc = -1;
 
index 58f4004..fffd8c5 100644 (file)
@@ -43,7 +43,7 @@ void __init ixdp425_pci_preinit(void)
        ixp4xx_pci_preinit();
 }
 
-static int __init ixdp425_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init ixdp425_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static int pci_irq_table[IRQ_LINES] = {
                IXP4XX_GPIO_IRQ(INTA),
index e64f6d0..34efe75 100644 (file)
@@ -31,7 +31,7 @@ void __init ixdpg425_pci_preinit(void)
        ixp4xx_pci_preinit();
 }
 
-static int __init ixdpg425_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init ixdpg425_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        if (slot == 12 || slot == 13)
                return IRQ_IXP4XX_GPIO7;
index 428d120..5434ccf 100644 (file)
@@ -41,7 +41,7 @@ void __init nas100d_pci_preinit(void)
        ixp4xx_pci_preinit();
 }
 
-static int __init nas100d_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init nas100d_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static int pci_irq_table[MAX_DEV][IRQ_LINES] = {
                { IXP4XX_GPIO_IRQ(INTA), -1, -1 },
index 2e85f76..b571605 100644 (file)
@@ -38,7 +38,7 @@ void __init nslu2_pci_preinit(void)
        ixp4xx_pci_preinit();
 }
 
-static int __init nslu2_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init nslu2_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static int pci_irq_table[IRQ_LINES] = {
                IXP4XX_GPIO_IRQ(INTA),
index 03bdec5..0bc3f34 100644 (file)
@@ -43,7 +43,7 @@ void __init vulcan_pci_preinit(void)
        ixp4xx_pci_preinit();
 }
 
-static int __init vulcan_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init vulcan_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        if (slot == 1)
                return IXP4XX_GPIO_IRQ(INTA);
index 17f3cf5..f27dfcf 100644 (file)
@@ -35,7 +35,7 @@ void __init wg302v2_pci_preinit(void)
        ixp4xx_pci_preinit();
 }
 
-static int __init wg302v2_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init wg302v2_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        if (slot == 1)
                return IRQ_IXP4XX_GPIO8;
index bfeb9c9..74b992d 100644 (file)
@@ -245,7 +245,8 @@ kirkwood_pcie_scan_bus(int nr, struct pci_sys_data *sys)
        return bus;
 }
 
-static int __init kirkwood_pcie_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init kirkwood_pcie_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        struct pcie_port *pp = bus_to_port(dev->bus);
 
index ada92b6..1338cb3 100644 (file)
@@ -34,7 +34,7 @@
 #include "generic.h"
 
 #ifdef CONFIG_PCI
-static int dsm320_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int dsm320_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        switch (slot) {
        case 0:
index c7ad09b..e2e3cba 100644 (file)
@@ -24,7 +24,7 @@
 #include "generic.h"
 
 #ifdef CONFIG_PCI
-static int micrel_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int micrel_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        return KS8695_IRQ_EXTERN0;
 }
index 2744fec..85a3c9a 100644 (file)
@@ -30,7 +30,7 @@ extern void __init ks8695_init_leds(u8 cpu_led, u8 timer_led);
 
 struct ks8695_pci_cfg {
        short mode;
-       int (*map_irq)(struct pci_dev *, u8, u8);
+       int (*map_irq)(const struct pci_dev *, u8, u8);
 };
 extern __init void ks8695_init_pci(struct ks8695_pci_cfg *);
 
index c070c24..98e25d9 100644 (file)
 #include <mach/gpio.h>
 #include <mach/pxa168.h>
 #include <mach/mfp-pxa168.h>
-#include <mach/mfp-gplugd.h>
 
 #include "common.h"
 
 static unsigned long gplugd_pin_config[] __initdata = {
        /* UART3 */
-       GPIO8_UART3_SOUT,
-       GPIO9_UART3_SIN,
-       GPI1O_UART3_CTS,
-       GPI11_UART3_RTS,
+       GPIO8_UART3_TXD,
+       GPIO9_UART3_RXD,
+       GPIO1O_UART3_CTS,
+       GPIO11_UART3_RTS,
+
+       /* USB OTG PEN */
+       GPIO18_GPIO,
 
        /* MMC2 */
        GPIO28_MMC2_CMD,
@@ -109,6 +111,12 @@ static unsigned long gplugd_pin_config[] __initdata = {
        GPIO105_CI2C_SDA,
        GPIO106_CI2C_SCL,
 
+       /* SPI NOR Flash on SSP2 */
+       GPIO107_SSP2_RXD,
+       GPIO108_SSP2_TXD,
+       GPIO110_GPIO,     /* SPI_CSn */
+       GPIO111_SSP2_CLK,
+
        /* Select JTAG */
        GPIO109_GPIO,
 
@@ -154,7 +162,7 @@ static void __init select_disp_freq(void)
                                "frequency\n");
        } else {
                gpio_direction_output(35, 1);
-               gpio_free(104);
+               gpio_free(35);
        }
 
        if (unlikely(gpio_request(85, "DISP_FREQ_SEL_2"))) {
@@ -162,7 +170,7 @@ static void __init select_disp_freq(void)
                                "frequency\n");
        } else {
                gpio_direction_output(85, 0);
-               gpio_free(104);
+               gpio_free(85);
        }
 }
 
diff --git a/arch/arm/mach-mmp/include/mach/mfp-gplugd.h b/arch/arm/mach-mmp/include/mach/mfp-gplugd.h
deleted file mode 100644 (file)
index b8cf38d..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * linux/arch/arm/mach-mmp/include/mach/mfp-gplugd.h
- *
- *   MFP definitions used in gplugD
- *
- * 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 __MACH_MFP_GPLUGD_H
-#define __MACH_MFP_GPLUGD_H
-
-#include <plat/mfp.h>
-#include <mach/mfp.h>
-
-/* UART3 */
-#define GPIO8_UART3_SOUT       MFP_CFG(GPIO8, AF2)
-#define GPIO9_UART3_SIN        MFP_CFG(GPIO9, AF2)
-#define GPI1O_UART3_CTS        MFP_CFG(GPIO10, AF2)
-#define GPI11_UART3_RTS        MFP_CFG(GPIO11, AF2)
-
-/* MMC2 */
-#define        GPIO28_MMC2_CMD         MFP_CFG_DRV(GPIO28, AF6, FAST)
-#define        GPIO29_MMC2_CLK         MFP_CFG_DRV(GPIO29, AF6, FAST)
-#define        GPIO30_MMC2_DAT0        MFP_CFG_DRV(GPIO30, AF6, FAST)
-#define        GPIO31_MMC2_DAT1        MFP_CFG_DRV(GPIO31, AF6, FAST)
-#define        GPIO32_MMC2_DAT2        MFP_CFG_DRV(GPIO32, AF6, FAST)
-#define        GPIO33_MMC2_DAT3        MFP_CFG_DRV(GPIO33, AF6, FAST)
-
-/* I2S */
-#undef GPIO114_I2S_FRM
-#undef GPIO115_I2S_BCLK
-
-#define GPIO114_I2S_FRM                MFP_CFG_DRV(GPIO114, AF1, FAST)
-#define GPIO115_I2S_BCLK        MFP_CFG_DRV(GPIO115, AF1, FAST)
-#define GPIO116_I2S_TXD         MFP_CFG_DRV(GPIO116, AF1, FAST)
-
-/* MMC4 */
-#define GPIO125_MMC4_DAT3       MFP_CFG_DRV(GPIO125, AF7, FAST)
-#define GPIO126_MMC4_DAT2       MFP_CFG_DRV(GPIO126, AF7, FAST)
-#define GPIO127_MMC4_DAT1       MFP_CFG_DRV(GPIO127, AF7, FAST)
-#define GPIO0_2_MMC4_DAT0       MFP_CFG_DRV(GPIO0_2, AF7, FAST)
-#define GPIO1_2_MMC4_CMD        MFP_CFG_DRV(GPIO1_2, AF7, FAST)
-#define GPIO2_2_MMC4_CLK        MFP_CFG_DRV(GPIO2_2, AF7, FAST)
-
-/* OTG GPIO */
-#define GPIO_USB_OTG_PEN        18
-#define GPIO_USB_OIDIR          20
-
-/* Other GPIOs are 35, 84, 85 */
-#endif /* __MACH_MFP_GPLUGD_H */
index 8c78232..92aaa3c 100644 (file)
 #define GPIO33_CF_nCD2         MFP_CFG(GPIO33, AF3)
 
 /* UART */
+#define GPIO8_UART3_TXD                MFP_CFG(GPIO8, AF2)
+#define GPIO9_UART3_RXD                MFP_CFG(GPIO9, AF2)
+#define GPIO1O_UART3_CTS       MFP_CFG(GPIO10, AF2)
+#define GPIO11_UART3_RTS       MFP_CFG(GPIO11, AF2)
 #define GPIO88_UART2_TXD       MFP_CFG(GPIO88, AF2)
 #define GPIO89_UART2_RXD       MFP_CFG(GPIO89, AF2)
 #define GPIO107_UART1_TXD      MFP_CFG_DRV(GPIO107, AF1, FAST)
 #define GPIO53_MMC1_CD         MFP_CFG(GPIO53, AF1)
 #define GPIO46_MMC1_WP         MFP_CFG(GPIO46, AF1)
 
+/* MMC2 */
+#define        GPIO28_MMC2_CMD         MFP_CFG_DRV(GPIO28, AF6, FAST)
+#define        GPIO29_MMC2_CLK         MFP_CFG_DRV(GPIO29, AF6, FAST)
+#define        GPIO30_MMC2_DAT0        MFP_CFG_DRV(GPIO30, AF6, FAST)
+#define        GPIO31_MMC2_DAT1        MFP_CFG_DRV(GPIO31, AF6, FAST)
+#define        GPIO32_MMC2_DAT2        MFP_CFG_DRV(GPIO32, AF6, FAST)
+#define        GPIO33_MMC2_DAT3        MFP_CFG_DRV(GPIO33, AF6, FAST)
+
+/* MMC4 */
+#define GPIO125_MMC4_DAT3       MFP_CFG_DRV(GPIO125, AF7, FAST)
+#define GPIO126_MMC4_DAT2       MFP_CFG_DRV(GPIO126, AF7, FAST)
+#define GPIO127_MMC4_DAT1       MFP_CFG_DRV(GPIO127, AF7, FAST)
+#define GPIO0_2_MMC4_DAT0       MFP_CFG_DRV(GPIO0_2, AF7, FAST)
+#define GPIO1_2_MMC4_CMD        MFP_CFG_DRV(GPIO1_2, AF7, FAST)
+#define GPIO2_2_MMC4_CLK        MFP_CFG_DRV(GPIO2_2, AF7, FAST)
+
 /* LCD */
 #define GPIO84_LCD_CS          MFP_CFG(GPIO84, AF1)
 #define GPIO60_LCD_DD0         MFP_CFG(GPIO60, AF1)
 #define GPIO106_CI2C_SCL       MFP_CFG(GPIO106, AF1)
 
 /* I2S */
-#define GPIO113_I2S_MCLK       MFP_CFG(GPIO113,AF6)
-#define GPIO114_I2S_FRM                MFP_CFG(GPIO114,AF1)
-#define GPIO115_I2S_BCLK       MFP_CFG(GPIO115,AF1)
-#define GPIO116_I2S_RXD                MFP_CFG(GPIO116,AF2)
-#define GPIO117_I2S_TXD                MFP_CFG(GPIO117,AF2)
+#define GPIO113_I2S_MCLK       MFP_CFG(GPIO113, AF6)
+#define GPIO114_I2S_FRM                MFP_CFG(GPIO114, AF1)
+#define GPIO115_I2S_BCLK       MFP_CFG(GPIO115, AF1)
+#define GPIO116_I2S_RXD                MFP_CFG(GPIO116, AF2)
+#define GPIO116_I2S_TXD         MFP_CFG(GPIO116, AF1)
+#define GPIO117_I2S_TXD                MFP_CFG(GPIO117, AF2)
 
 /* PWM */
 #define GPIO96_PWM3_OUT                MFP_CFG(GPIO96, AF1)
 #define GPIO101_MII_MDIO       MFP_CFG(GPIO101, AF5)
 #define GPIO103_RX_DV          MFP_CFG(GPIO103, AF5)
 
+/* SSP2 */
+#define GPIO107_SSP2_RXD       MFP_CFG(GPIO107, AF4)
+#define GPIO108_SSP2_TXD       MFP_CFG(GPIO108, AF4)
+#define GPIO111_SSP2_CLK       MFP_CFG(GPIO111, AF4)
+#define GPIO112_SSP2_FRM       MFP_CFG(GPIO112, AF4)
+
 #endif /* __ASM_MACH_MFP_PXA168_H */
index 99833b9..4e91ee6 100644 (file)
@@ -51,12 +51,12 @@ static inline uint32_t timer_read(void)
 {
        int delay = 100;
 
-       __raw_writel(1, TIMERS_VIRT_BASE + TMR_CVWR(0));
+       __raw_writel(1, TIMERS_VIRT_BASE + TMR_CVWR(1));
 
        while (delay--)
                cpu_relax();
 
-       return __raw_readl(TIMERS_VIRT_BASE + TMR_CVWR(0));
+       return __raw_readl(TIMERS_VIRT_BASE + TMR_CVWR(1));
 }
 
 unsigned long long notrace sched_clock(void)
@@ -75,28 +75,51 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
 {
        struct clock_event_device *c = dev_id;
 
-       /* disable and clear pending interrupt status */
-       __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_IER(0));
-       __raw_writel(0x1, TIMERS_VIRT_BASE + TMR_ICR(0));
+       /*
+        * Clear pending interrupt status.
+        */
+       __raw_writel(0x01, TIMERS_VIRT_BASE + TMR_ICR(0));
+
+       /*
+        * Disable timer 0.
+        */
+       __raw_writel(0x02, TIMERS_VIRT_BASE + TMR_CER);
+
        c->event_handler(c);
+
        return IRQ_HANDLED;
 }
 
 static int timer_set_next_event(unsigned long delta,
                                struct clock_event_device *dev)
 {
-       unsigned long flags, next;
+       unsigned long flags;
 
        local_irq_save(flags);
 
-       /* clear pending interrupt status and enable */
+       /*
+        * Disable timer 0.
+        */
+       __raw_writel(0x02, TIMERS_VIRT_BASE + TMR_CER);
+
+       /*
+        * Clear and enable timer match 0 interrupt.
+        */
        __raw_writel(0x01, TIMERS_VIRT_BASE + TMR_ICR(0));
        __raw_writel(0x01, TIMERS_VIRT_BASE + TMR_IER(0));
 
-       next = timer_read() + delta;
-       __raw_writel(next, TIMERS_VIRT_BASE + TMR_TN_MM(0, 0));
+       /*
+        * Setup new clockevent timer value.
+        */
+       __raw_writel(delta - 1, TIMERS_VIRT_BASE + TMR_TN_MM(0, 0));
+
+       /*
+        * Enable timer 0.
+        */
+       __raw_writel(0x03, TIMERS_VIRT_BASE + TMR_CER);
 
        local_irq_restore(flags);
+
        return 0;
 }
 
@@ -145,23 +168,26 @@ static struct clocksource cksrc = {
 static void __init timer_config(void)
 {
        uint32_t ccr = __raw_readl(TIMERS_VIRT_BASE + TMR_CCR);
-       uint32_t cer = __raw_readl(TIMERS_VIRT_BASE + TMR_CER);
-       uint32_t cmr = __raw_readl(TIMERS_VIRT_BASE + TMR_CMR);
 
-       __raw_writel(cer & ~0x1, TIMERS_VIRT_BASE + TMR_CER); /* disable */
+       __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_CER); /* disable */
 
-       ccr &= (cpu_is_mmp2()) ? TMR_CCR_CS_0(0) : TMR_CCR_CS_0(3);
+       ccr &= (cpu_is_mmp2()) ? (TMR_CCR_CS_0(0) | TMR_CCR_CS_1(0)) :
+               (TMR_CCR_CS_0(3) | TMR_CCR_CS_1(3));
        __raw_writel(ccr, TIMERS_VIRT_BASE + TMR_CCR);
 
-       /* free-running mode */
-       __raw_writel(cmr | 0x01, TIMERS_VIRT_BASE + TMR_CMR);
+       /* set timer 0 to periodic mode, and timer 1 to free-running mode */
+       __raw_writel(0x2, TIMERS_VIRT_BASE + TMR_CMR);
 
-       __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_PLCR(0)); /* free-running */
+       __raw_writel(0x1, TIMERS_VIRT_BASE + TMR_PLCR(0)); /* periodic */
        __raw_writel(0x7, TIMERS_VIRT_BASE + TMR_ICR(0));  /* clear status */
        __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_IER(0));
 
-       /* enable timer counter */
-       __raw_writel(cer | 0x01, TIMERS_VIRT_BASE + TMR_CER);
+       __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_PLCR(1)); /* free-running */
+       __raw_writel(0x7, TIMERS_VIRT_BASE + TMR_ICR(1));  /* clear status */
+       __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_IER(1));
+
+       /* enable timer 1 counter */
+       __raw_writel(0x2, TIMERS_VIRT_BASE + TMR_CER);
 }
 
 static struct irqaction timer_irq = {
index 888e925..ebde97f 100644 (file)
@@ -11,6 +11,7 @@ config ARCH_MSM7X00A
        select MSM_SMD
        select MSM_SMD_PKG3
        select CPU_V6
+       select GPIO_MSM_V1
        select MSM_PROC_COMM
        select HAS_MSM_DEBUG_UART_PHYS
 
@@ -22,6 +23,7 @@ config ARCH_MSM7X30
        select MSM_VIC
        select CPU_V7
        select MSM_GPIOMUX
+       select GPIO_MSM_V1
        select MSM_PROC_COMM
        select HAS_MSM_DEBUG_UART_PHYS
 
@@ -33,6 +35,7 @@ config ARCH_QSD8X50
        select MSM_VIC
        select CPU_V7
        select MSM_GPIOMUX
+       select GPIO_MSM_V1
        select MSM_PROC_COMM
        select HAS_MSM_DEBUG_UART_PHYS
 
@@ -44,6 +47,7 @@ config ARCH_MSM8X60
        select ARM_GIC
        select CPU_V7
        select MSM_V2_TLMM
+       select GPIO_MSM_V2
        select MSM_GPIOMUX
        select MSM_SCM if SMP
 
index b70658c..4285dfd 100644 (file)
@@ -29,11 +29,3 @@ obj-$(CONFIG_ARCH_MSM8960) += board-msm8960.o devices-msm8960.o
 obj-$(CONFIG_ARCH_MSM7X30) += gpiomux-v1.o gpiomux.o
 obj-$(CONFIG_ARCH_QSD8X50) += gpiomux-8x50.o gpiomux-v1.o gpiomux.o
 obj-$(CONFIG_ARCH_MSM8X60) += gpiomux-8x60.o gpiomux-v2.o gpiomux.o
-ifdef CONFIG_MSM_V2_TLMM
-ifndef CONFIG_ARCH_MSM8960
-# TODO: TLMM Mapping issues need to be resolved
-obj-y  += gpio-v2.o
-endif
-else
-obj-y  += gpio.o
-endif
diff --git a/arch/arm/mach-msm/gpio.c b/arch/arm/mach-msm/gpio.c
deleted file mode 100644 (file)
index 5ea273b..0000000
+++ /dev/null
@@ -1,376 +0,0 @@
-/* linux/arch/arm/mach-msm/gpio.c
- *
- * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2010, Code Aurora Forum. 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/bitops.h>
-#include <linux/gpio.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/module.h>
-#include "gpio_hw.h"
-#include "gpiomux.h"
-
-#define FIRST_GPIO_IRQ MSM_GPIO_TO_INT(0)
-
-#define MSM_GPIO_BANK(bank, first, last)                               \
-       {                                                               \
-               .regs = {                                               \
-                       .out =         MSM_GPIO_OUT_##bank,             \
-                       .in =          MSM_GPIO_IN_##bank,              \
-                       .int_status =  MSM_GPIO_INT_STATUS_##bank,      \
-                       .int_clear =   MSM_GPIO_INT_CLEAR_##bank,       \
-                       .int_en =      MSM_GPIO_INT_EN_##bank,          \
-                       .int_edge =    MSM_GPIO_INT_EDGE_##bank,        \
-                       .int_pos =     MSM_GPIO_INT_POS_##bank,         \
-                       .oe =          MSM_GPIO_OE_##bank,              \
-               },                                                      \
-               .chip = {                                               \
-                       .base = (first),                                \
-                       .ngpio = (last) - (first) + 1,                  \
-                       .get = msm_gpio_get,                            \
-                       .set = msm_gpio_set,                            \
-                       .direction_input = msm_gpio_direction_input,    \
-                       .direction_output = msm_gpio_direction_output,  \
-                       .to_irq = msm_gpio_to_irq,                      \
-                       .request = msm_gpio_request,                    \
-                       .free = msm_gpio_free,                          \
-               }                                                       \
-       }
-
-#define MSM_GPIO_BROKEN_INT_CLEAR 1
-
-struct msm_gpio_regs {
-       void __iomem *out;
-       void __iomem *in;
-       void __iomem *int_status;
-       void __iomem *int_clear;
-       void __iomem *int_en;
-       void __iomem *int_edge;
-       void __iomem *int_pos;
-       void __iomem *oe;
-};
-
-struct msm_gpio_chip {
-       spinlock_t              lock;
-       struct gpio_chip        chip;
-       struct msm_gpio_regs    regs;
-#if MSM_GPIO_BROKEN_INT_CLEAR
-       unsigned                int_status_copy;
-#endif
-       unsigned int            both_edge_detect;
-       unsigned int            int_enable[2]; /* 0: awake, 1: sleep */
-};
-
-static int msm_gpio_write(struct msm_gpio_chip *msm_chip,
-                         unsigned offset, unsigned on)
-{
-       unsigned mask = BIT(offset);
-       unsigned val;
-
-       val = readl(msm_chip->regs.out);
-       if (on)
-               writel(val | mask, msm_chip->regs.out);
-       else
-               writel(val & ~mask, msm_chip->regs.out);
-       return 0;
-}
-
-static void msm_gpio_update_both_edge_detect(struct msm_gpio_chip *msm_chip)
-{
-       int loop_limit = 100;
-       unsigned pol, val, val2, intstat;
-       do {
-               val = readl(msm_chip->regs.in);
-               pol = readl(msm_chip->regs.int_pos);
-               pol = (pol & ~msm_chip->both_edge_detect) |
-                     (~val & msm_chip->both_edge_detect);
-               writel(pol, msm_chip->regs.int_pos);
-               intstat = readl(msm_chip->regs.int_status);
-               val2 = readl(msm_chip->regs.in);
-               if (((val ^ val2) & msm_chip->both_edge_detect & ~intstat) == 0)
-                       return;
-       } while (loop_limit-- > 0);
-       printk(KERN_ERR "msm_gpio_update_both_edge_detect, "
-              "failed to reach stable state %x != %x\n", val, val2);
-}
-
-static int msm_gpio_clear_detect_status(struct msm_gpio_chip *msm_chip,
-                                       unsigned offset)
-{
-       unsigned bit = BIT(offset);
-
-#if MSM_GPIO_BROKEN_INT_CLEAR
-       /* Save interrupts that already triggered before we loose them. */
-       /* Any interrupt that triggers between the read of int_status */
-       /* and the write to int_clear will still be lost though. */
-       msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
-       msm_chip->int_status_copy &= ~bit;
-#endif
-       writel(bit, msm_chip->regs.int_clear);
-       msm_gpio_update_both_edge_detect(msm_chip);
-       return 0;
-}
-
-static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
-{
-       struct msm_gpio_chip *msm_chip;
-       unsigned long irq_flags;
-
-       msm_chip = container_of(chip, struct msm_gpio_chip, chip);
-       spin_lock_irqsave(&msm_chip->lock, irq_flags);
-       writel(readl(msm_chip->regs.oe) & ~BIT(offset), msm_chip->regs.oe);
-       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
-       return 0;
-}
-
-static int
-msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value)
-{
-       struct msm_gpio_chip *msm_chip;
-       unsigned long irq_flags;
-
-       msm_chip = container_of(chip, struct msm_gpio_chip, chip);
-       spin_lock_irqsave(&msm_chip->lock, irq_flags);
-       msm_gpio_write(msm_chip, offset, value);
-       writel(readl(msm_chip->regs.oe) | BIT(offset), msm_chip->regs.oe);
-       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
-       return 0;
-}
-
-static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
-       struct msm_gpio_chip *msm_chip;
-
-       msm_chip = container_of(chip, struct msm_gpio_chip, chip);
-       return (readl(msm_chip->regs.in) & (1U << offset)) ? 1 : 0;
-}
-
-static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
-{
-       struct msm_gpio_chip *msm_chip;
-       unsigned long irq_flags;
-
-       msm_chip = container_of(chip, struct msm_gpio_chip, chip);
-       spin_lock_irqsave(&msm_chip->lock, irq_flags);
-       msm_gpio_write(msm_chip, offset, value);
-       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
-}
-
-static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
-       return MSM_GPIO_TO_INT(chip->base + offset);
-}
-
-#ifdef CONFIG_MSM_GPIOMUX
-static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)
-{
-       return msm_gpiomux_get(chip->base + offset);
-}
-
-static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
-{
-       msm_gpiomux_put(chip->base + offset);
-}
-#else
-#define msm_gpio_request NULL
-#define msm_gpio_free NULL
-#endif
-
-struct msm_gpio_chip msm_gpio_chips[] = {
-#if defined(CONFIG_ARCH_MSM7X00A)
-       MSM_GPIO_BANK(0,   0,  15),
-       MSM_GPIO_BANK(1,  16,  42),
-       MSM_GPIO_BANK(2,  43,  67),
-       MSM_GPIO_BANK(3,  68,  94),
-       MSM_GPIO_BANK(4,  95, 106),
-       MSM_GPIO_BANK(5, 107, 121),
-#elif defined(CONFIG_ARCH_MSM7X25) || defined(CONFIG_ARCH_MSM7X27)
-       MSM_GPIO_BANK(0,   0,  15),
-       MSM_GPIO_BANK(1,  16,  42),
-       MSM_GPIO_BANK(2,  43,  67),
-       MSM_GPIO_BANK(3,  68,  94),
-       MSM_GPIO_BANK(4,  95, 106),
-       MSM_GPIO_BANK(5, 107, 132),
-#elif defined(CONFIG_ARCH_MSM7X30)
-       MSM_GPIO_BANK(0,   0,  15),
-       MSM_GPIO_BANK(1,  16,  43),
-       MSM_GPIO_BANK(2,  44,  67),
-       MSM_GPIO_BANK(3,  68,  94),
-       MSM_GPIO_BANK(4,  95, 106),
-       MSM_GPIO_BANK(5, 107, 133),
-       MSM_GPIO_BANK(6, 134, 150),
-       MSM_GPIO_BANK(7, 151, 181),
-#elif defined(CONFIG_ARCH_QSD8X50)
-       MSM_GPIO_BANK(0,   0,  15),
-       MSM_GPIO_BANK(1,  16,  42),
-       MSM_GPIO_BANK(2,  43,  67),
-       MSM_GPIO_BANK(3,  68,  94),
-       MSM_GPIO_BANK(4,  95, 103),
-       MSM_GPIO_BANK(5, 104, 121),
-       MSM_GPIO_BANK(6, 122, 152),
-       MSM_GPIO_BANK(7, 153, 164),
-#endif
-};
-
-static void msm_gpio_irq_ack(struct irq_data *d)
-{
-       unsigned long irq_flags;
-       struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
-       spin_lock_irqsave(&msm_chip->lock, irq_flags);
-       msm_gpio_clear_detect_status(msm_chip,
-                                    d->irq - gpio_to_irq(msm_chip->chip.base));
-       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
-}
-
-static void msm_gpio_irq_mask(struct irq_data *d)
-{
-       unsigned long irq_flags;
-       struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
-       unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
-
-       spin_lock_irqsave(&msm_chip->lock, irq_flags);
-       /* level triggered interrupts are also latched */
-       if (!(readl(msm_chip->regs.int_edge) & BIT(offset)))
-               msm_gpio_clear_detect_status(msm_chip, offset);
-       msm_chip->int_enable[0] &= ~BIT(offset);
-       writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
-       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
-}
-
-static void msm_gpio_irq_unmask(struct irq_data *d)
-{
-       unsigned long irq_flags;
-       struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
-       unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
-
-       spin_lock_irqsave(&msm_chip->lock, irq_flags);
-       /* level triggered interrupts are also latched */
-       if (!(readl(msm_chip->regs.int_edge) & BIT(offset)))
-               msm_gpio_clear_detect_status(msm_chip, offset);
-       msm_chip->int_enable[0] |= BIT(offset);
-       writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
-       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
-}
-
-static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
-{
-       unsigned long irq_flags;
-       struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
-       unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
-
-       spin_lock_irqsave(&msm_chip->lock, irq_flags);
-
-       if (on)
-               msm_chip->int_enable[1] |= BIT(offset);
-       else
-               msm_chip->int_enable[1] &= ~BIT(offset);
-
-       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
-       return 0;
-}
-
-static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
-{
-       unsigned long irq_flags;
-       struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
-       unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
-       unsigned val, mask = BIT(offset);
-
-       spin_lock_irqsave(&msm_chip->lock, irq_flags);
-       val = readl(msm_chip->regs.int_edge);
-       if (flow_type & IRQ_TYPE_EDGE_BOTH) {
-               writel(val | mask, msm_chip->regs.int_edge);
-               __irq_set_handler_locked(d->irq, handle_edge_irq);
-       } else {
-               writel(val & ~mask, msm_chip->regs.int_edge);
-               __irq_set_handler_locked(d->irq, handle_level_irq);
-       }
-       if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
-               msm_chip->both_edge_detect |= mask;
-               msm_gpio_update_both_edge_detect(msm_chip);
-       } else {
-               msm_chip->both_edge_detect &= ~mask;
-               val = readl(msm_chip->regs.int_pos);
-               if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH))
-                       writel(val | mask, msm_chip->regs.int_pos);
-               else
-                       writel(val & ~mask, msm_chip->regs.int_pos);
-       }
-       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
-       return 0;
-}
-
-static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
-{
-       int i, j, mask;
-       unsigned val;
-
-       for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
-               struct msm_gpio_chip *msm_chip = &msm_gpio_chips[i];
-               val = readl(msm_chip->regs.int_status);
-               val &= msm_chip->int_enable[0];
-               while (val) {
-                       mask = val & -val;
-                       j = fls(mask) - 1;
-                       /* printk("%s %08x %08x bit %d gpio %d irq %d\n",
-                               __func__, v, m, j, msm_chip->chip.start + j,
-                               FIRST_GPIO_IRQ + msm_chip->chip.start + j); */
-                       val &= ~mask;
-                       generic_handle_irq(FIRST_GPIO_IRQ +
-                                          msm_chip->chip.base + j);
-               }
-       }
-       desc->irq_data.chip->irq_ack(&desc->irq_data);
-}
-
-static struct irq_chip msm_gpio_irq_chip = {
-       .name          = "msmgpio",
-       .irq_ack       = msm_gpio_irq_ack,
-       .irq_mask      = msm_gpio_irq_mask,
-       .irq_unmask    = msm_gpio_irq_unmask,
-       .irq_set_wake  = msm_gpio_irq_set_wake,
-       .irq_set_type  = msm_gpio_irq_set_type,
-};
-
-static int __init msm_init_gpio(void)
-{
-       int i, j = 0;
-
-       for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) {
-               if (i - FIRST_GPIO_IRQ >=
-                       msm_gpio_chips[j].chip.base +
-                       msm_gpio_chips[j].chip.ngpio)
-                       j++;
-               irq_set_chip_data(i, &msm_gpio_chips[j]);
-               irq_set_chip_and_handler(i, &msm_gpio_irq_chip,
-                                        handle_edge_irq);
-               set_irq_flags(i, IRQF_VALID);
-       }
-
-       for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
-               spin_lock_init(&msm_gpio_chips[i].lock);
-               writel(0, msm_gpio_chips[i].regs.int_en);
-               gpiochip_add(&msm_gpio_chips[i].chip);
-       }
-
-       irq_set_chained_handler(INT_GPIO_GROUP1, msm_gpio_irq_handler);
-       irq_set_chained_handler(INT_GPIO_GROUP2, msm_gpio_irq_handler);
-       irq_set_irq_wake(INT_GPIO_GROUP1, 1);
-       irq_set_irq_wake(INT_GPIO_GROUP2, 2);
-       return 0;
-}
-
-postcore_initcall(msm_init_gpio);
diff --git a/arch/arm/mach-msm/gpio_hw.h b/arch/arm/mach-msm/gpio_hw.h
deleted file mode 100644 (file)
index 6b50660..0000000
+++ /dev/null
@@ -1,278 +0,0 @@
-/* arch/arm/mach-msm/gpio_hw.h
- *
- * Copyright (C) 2007 Google, Inc.
- * Author: Brian Swetland <swetland@google.com>
- * Copyright (c) 2008-2010, Code Aurora Forum. 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 __ARCH_ARM_MACH_MSM_GPIO_HW_H
-#define __ARCH_ARM_MACH_MSM_GPIO_HW_H
-
-#include <mach/msm_iomap.h>
-
-/* see 80-VA736-2 Rev C pp 695-751
-**
-** These are actually the *shadow* gpio registers, since the
-** real ones (which allow full access) are only available to the
-** ARM9 side of the world.
-**
-** Since the _BASE need to be page-aligned when we're mapping them
-** to virtual addresses, adjust for the additional offset in these
-** macros.
-*/
-
-#if defined(CONFIG_ARCH_MSM7X30)
-#define MSM_GPIO1_REG(off) (MSM_GPIO1_BASE + (off))
-#define MSM_GPIO2_REG(off) (MSM_GPIO2_BASE + 0x400 + (off))
-#else
-#define MSM_GPIO1_REG(off) (MSM_GPIO1_BASE + 0x800 + (off))
-#define MSM_GPIO2_REG(off) (MSM_GPIO2_BASE + 0xC00 + (off))
-#endif
-
-#if defined(CONFIG_ARCH_MSM7X00A) || defined(CONFIG_ARCH_MSM7X25) ||\
-    defined(CONFIG_ARCH_MSM7X27)
-
-/* output value */
-#define MSM_GPIO_OUT_0         MSM_GPIO1_REG(0x00)  /* gpio  15-0  */
-#define MSM_GPIO_OUT_1         MSM_GPIO2_REG(0x00)  /* gpio  42-16 */
-#define MSM_GPIO_OUT_2         MSM_GPIO1_REG(0x04)  /* gpio  67-43 */
-#define MSM_GPIO_OUT_3         MSM_GPIO1_REG(0x08)  /* gpio  94-68 */
-#define MSM_GPIO_OUT_4         MSM_GPIO1_REG(0x0C)  /* gpio 106-95 */
-#define MSM_GPIO_OUT_5         MSM_GPIO1_REG(0x50)  /* gpio 107-121 */
-
-/* same pin map as above, output enable */
-#define MSM_GPIO_OE_0          MSM_GPIO1_REG(0x10)
-#define MSM_GPIO_OE_1          MSM_GPIO2_REG(0x08)
-#define MSM_GPIO_OE_2          MSM_GPIO1_REG(0x14)
-#define MSM_GPIO_OE_3          MSM_GPIO1_REG(0x18)
-#define MSM_GPIO_OE_4          MSM_GPIO1_REG(0x1C)
-#define MSM_GPIO_OE_5          MSM_GPIO1_REG(0x54)
-
-/* same pin map as above, input read */
-#define MSM_GPIO_IN_0          MSM_GPIO1_REG(0x34)
-#define MSM_GPIO_IN_1          MSM_GPIO2_REG(0x20)
-#define MSM_GPIO_IN_2          MSM_GPIO1_REG(0x38)
-#define MSM_GPIO_IN_3          MSM_GPIO1_REG(0x3C)
-#define MSM_GPIO_IN_4          MSM_GPIO1_REG(0x40)
-#define MSM_GPIO_IN_5          MSM_GPIO1_REG(0x44)
-
-/* same pin map as above, 1=edge 0=level interrup */
-#define MSM_GPIO_INT_EDGE_0    MSM_GPIO1_REG(0x60)
-#define MSM_GPIO_INT_EDGE_1    MSM_GPIO2_REG(0x50)
-#define MSM_GPIO_INT_EDGE_2    MSM_GPIO1_REG(0x64)
-#define MSM_GPIO_INT_EDGE_3    MSM_GPIO1_REG(0x68)
-#define MSM_GPIO_INT_EDGE_4    MSM_GPIO1_REG(0x6C)
-#define MSM_GPIO_INT_EDGE_5    MSM_GPIO1_REG(0xC0)
-
-/* same pin map as above, 1=positive 0=negative */
-#define MSM_GPIO_INT_POS_0     MSM_GPIO1_REG(0x70)
-#define MSM_GPIO_INT_POS_1     MSM_GPIO2_REG(0x58)
-#define MSM_GPIO_INT_POS_2     MSM_GPIO1_REG(0x74)
-#define MSM_GPIO_INT_POS_3     MSM_GPIO1_REG(0x78)
-#define MSM_GPIO_INT_POS_4     MSM_GPIO1_REG(0x7C)
-#define MSM_GPIO_INT_POS_5     MSM_GPIO1_REG(0xBC)
-
-/* same pin map as above, interrupt enable */
-#define MSM_GPIO_INT_EN_0      MSM_GPIO1_REG(0x80)
-#define MSM_GPIO_INT_EN_1      MSM_GPIO2_REG(0x60)
-#define MSM_GPIO_INT_EN_2      MSM_GPIO1_REG(0x84)
-#define MSM_GPIO_INT_EN_3      MSM_GPIO1_REG(0x88)
-#define MSM_GPIO_INT_EN_4      MSM_GPIO1_REG(0x8C)
-#define MSM_GPIO_INT_EN_5      MSM_GPIO1_REG(0xB8)
-
-/* same pin map as above, write 1 to clear interrupt */
-#define MSM_GPIO_INT_CLEAR_0   MSM_GPIO1_REG(0x90)
-#define MSM_GPIO_INT_CLEAR_1   MSM_GPIO2_REG(0x68)
-#define MSM_GPIO_INT_CLEAR_2   MSM_GPIO1_REG(0x94)
-#define MSM_GPIO_INT_CLEAR_3   MSM_GPIO1_REG(0x98)
-#define MSM_GPIO_INT_CLEAR_4   MSM_GPIO1_REG(0x9C)
-#define MSM_GPIO_INT_CLEAR_5   MSM_GPIO1_REG(0xB4)
-
-/* same pin map as above, 1=interrupt pending */
-#define MSM_GPIO_INT_STATUS_0  MSM_GPIO1_REG(0xA0)
-#define MSM_GPIO_INT_STATUS_1  MSM_GPIO2_REG(0x70)
-#define MSM_GPIO_INT_STATUS_2  MSM_GPIO1_REG(0xA4)
-#define MSM_GPIO_INT_STATUS_3  MSM_GPIO1_REG(0xA8)
-#define MSM_GPIO_INT_STATUS_4  MSM_GPIO1_REG(0xAC)
-#define MSM_GPIO_INT_STATUS_5  MSM_GPIO1_REG(0xB0)
-
-#endif
-
-#if defined(CONFIG_ARCH_QSD8X50)
-/* output value */
-#define MSM_GPIO_OUT_0         MSM_GPIO1_REG(0x00)  /* gpio  15-0   */
-#define MSM_GPIO_OUT_1         MSM_GPIO2_REG(0x00)  /* gpio  42-16  */
-#define MSM_GPIO_OUT_2         MSM_GPIO1_REG(0x04)  /* gpio  67-43  */
-#define MSM_GPIO_OUT_3         MSM_GPIO1_REG(0x08)  /* gpio  94-68  */
-#define MSM_GPIO_OUT_4         MSM_GPIO1_REG(0x0C)  /* gpio 103-95  */
-#define MSM_GPIO_OUT_5         MSM_GPIO1_REG(0x10)  /* gpio 121-104 */
-#define MSM_GPIO_OUT_6         MSM_GPIO1_REG(0x14)  /* gpio 152-122 */
-#define MSM_GPIO_OUT_7         MSM_GPIO1_REG(0x18)  /* gpio 164-153 */
-
-/* same pin map as above, output enable */
-#define MSM_GPIO_OE_0          MSM_GPIO1_REG(0x20)
-#define MSM_GPIO_OE_1          MSM_GPIO2_REG(0x08)
-#define MSM_GPIO_OE_2          MSM_GPIO1_REG(0x24)
-#define MSM_GPIO_OE_3          MSM_GPIO1_REG(0x28)
-#define MSM_GPIO_OE_4          MSM_GPIO1_REG(0x2C)
-#define MSM_GPIO_OE_5          MSM_GPIO1_REG(0x30)
-#define MSM_GPIO_OE_6          MSM_GPIO1_REG(0x34)
-#define MSM_GPIO_OE_7          MSM_GPIO1_REG(0x38)
-
-/* same pin map as above, input read */
-#define MSM_GPIO_IN_0          MSM_GPIO1_REG(0x50)
-#define MSM_GPIO_IN_1          MSM_GPIO2_REG(0x20)
-#define MSM_GPIO_IN_2          MSM_GPIO1_REG(0x54)
-#define MSM_GPIO_IN_3          MSM_GPIO1_REG(0x58)
-#define MSM_GPIO_IN_4          MSM_GPIO1_REG(0x5C)
-#define MSM_GPIO_IN_5          MSM_GPIO1_REG(0x60)
-#define MSM_GPIO_IN_6          MSM_GPIO1_REG(0x64)
-#define MSM_GPIO_IN_7          MSM_GPIO1_REG(0x68)
-
-/* same pin map as above, 1=edge 0=level interrup */
-#define MSM_GPIO_INT_EDGE_0    MSM_GPIO1_REG(0x70)
-#define MSM_GPIO_INT_EDGE_1    MSM_GPIO2_REG(0x50)
-#define MSM_GPIO_INT_EDGE_2    MSM_GPIO1_REG(0x74)
-#define MSM_GPIO_INT_EDGE_3    MSM_GPIO1_REG(0x78)
-#define MSM_GPIO_INT_EDGE_4    MSM_GPIO1_REG(0x7C)
-#define MSM_GPIO_INT_EDGE_5    MSM_GPIO1_REG(0x80)
-#define MSM_GPIO_INT_EDGE_6    MSM_GPIO1_REG(0x84)
-#define MSM_GPIO_INT_EDGE_7    MSM_GPIO1_REG(0x88)
-
-/* same pin map as above, 1=positive 0=negative */
-#define MSM_GPIO_INT_POS_0     MSM_GPIO1_REG(0x90)
-#define MSM_GPIO_INT_POS_1     MSM_GPIO2_REG(0x58)
-#define MSM_GPIO_INT_POS_2     MSM_GPIO1_REG(0x94)
-#define MSM_GPIO_INT_POS_3     MSM_GPIO1_REG(0x98)
-#define MSM_GPIO_INT_POS_4     MSM_GPIO1_REG(0x9C)
-#define MSM_GPIO_INT_POS_5     MSM_GPIO1_REG(0xA0)
-#define MSM_GPIO_INT_POS_6     MSM_GPIO1_REG(0xA4)
-#define MSM_GPIO_INT_POS_7     MSM_GPIO1_REG(0xA8)
-
-/* same pin map as above, interrupt enable */
-#define MSM_GPIO_INT_EN_0      MSM_GPIO1_REG(0xB0)
-#define MSM_GPIO_INT_EN_1      MSM_GPIO2_REG(0x60)
-#define MSM_GPIO_INT_EN_2      MSM_GPIO1_REG(0xB4)
-#define MSM_GPIO_INT_EN_3      MSM_GPIO1_REG(0xB8)
-#define MSM_GPIO_INT_EN_4      MSM_GPIO1_REG(0xBC)
-#define MSM_GPIO_INT_EN_5      MSM_GPIO1_REG(0xC0)
-#define MSM_GPIO_INT_EN_6      MSM_GPIO1_REG(0xC4)
-#define MSM_GPIO_INT_EN_7      MSM_GPIO1_REG(0xC8)
-
-/* same pin map as above, write 1 to clear interrupt */
-#define MSM_GPIO_INT_CLEAR_0   MSM_GPIO1_REG(0xD0)
-#define MSM_GPIO_INT_CLEAR_1   MSM_GPIO2_REG(0x68)
-#define MSM_GPIO_INT_CLEAR_2   MSM_GPIO1_REG(0xD4)
-#define MSM_GPIO_INT_CLEAR_3   MSM_GPIO1_REG(0xD8)
-#define MSM_GPIO_INT_CLEAR_4   MSM_GPIO1_REG(0xDC)
-#define MSM_GPIO_INT_CLEAR_5   MSM_GPIO1_REG(0xE0)
-#define MSM_GPIO_INT_CLEAR_6   MSM_GPIO1_REG(0xE4)
-#define MSM_GPIO_INT_CLEAR_7   MSM_GPIO1_REG(0xE8)
-
-/* same pin map as above, 1=interrupt pending */
-#define MSM_GPIO_INT_STATUS_0  MSM_GPIO1_REG(0xF0)
-#define MSM_GPIO_INT_STATUS_1  MSM_GPIO2_REG(0x70)
-#define MSM_GPIO_INT_STATUS_2  MSM_GPIO1_REG(0xF4)
-#define MSM_GPIO_INT_STATUS_3  MSM_GPIO1_REG(0xF8)
-#define MSM_GPIO_INT_STATUS_4  MSM_GPIO1_REG(0xFC)
-#define MSM_GPIO_INT_STATUS_5  MSM_GPIO1_REG(0x100)
-#define MSM_GPIO_INT_STATUS_6  MSM_GPIO1_REG(0x104)
-#define MSM_GPIO_INT_STATUS_7  MSM_GPIO1_REG(0x108)
-
-#endif
-
-#if defined(CONFIG_ARCH_MSM7X30)
-
-/* output value */
-#define MSM_GPIO_OUT_0         MSM_GPIO1_REG(0x00)   /* gpio  15-0   */
-#define MSM_GPIO_OUT_1         MSM_GPIO2_REG(0x00)   /* gpio  43-16  */
-#define MSM_GPIO_OUT_2         MSM_GPIO1_REG(0x04)   /* gpio  67-44  */
-#define MSM_GPIO_OUT_3         MSM_GPIO1_REG(0x08)   /* gpio  94-68  */
-#define MSM_GPIO_OUT_4         MSM_GPIO1_REG(0x0C)   /* gpio 106-95  */
-#define MSM_GPIO_OUT_5         MSM_GPIO1_REG(0x50)   /* gpio 133-107 */
-#define MSM_GPIO_OUT_6         MSM_GPIO1_REG(0xC4)   /* gpio 150-134 */
-#define MSM_GPIO_OUT_7         MSM_GPIO1_REG(0x214)  /* gpio 181-151 */
-
-/* same pin map as above, output enable */
-#define MSM_GPIO_OE_0          MSM_GPIO1_REG(0x10)
-#define MSM_GPIO_OE_1          MSM_GPIO2_REG(0x08)
-#define MSM_GPIO_OE_2          MSM_GPIO1_REG(0x14)
-#define MSM_GPIO_OE_3          MSM_GPIO1_REG(0x18)
-#define MSM_GPIO_OE_4          MSM_GPIO1_REG(0x1C)
-#define MSM_GPIO_OE_5          MSM_GPIO1_REG(0x54)
-#define MSM_GPIO_OE_6          MSM_GPIO1_REG(0xC8)
-#define MSM_GPIO_OE_7          MSM_GPIO1_REG(0x218)
-
-/* same pin map as above, input read */
-#define MSM_GPIO_IN_0          MSM_GPIO1_REG(0x34)
-#define MSM_GPIO_IN_1          MSM_GPIO2_REG(0x20)
-#define MSM_GPIO_IN_2          MSM_GPIO1_REG(0x38)
-#define MSM_GPIO_IN_3          MSM_GPIO1_REG(0x3C)
-#define MSM_GPIO_IN_4          MSM_GPIO1_REG(0x40)
-#define MSM_GPIO_IN_5          MSM_GPIO1_REG(0x44)
-#define MSM_GPIO_IN_6          MSM_GPIO1_REG(0xCC)
-#define MSM_GPIO_IN_7          MSM_GPIO1_REG(0x21C)
-
-/* same pin map as above, 1=edge 0=level interrup */
-#define MSM_GPIO_INT_EDGE_0    MSM_GPIO1_REG(0x60)
-#define MSM_GPIO_INT_EDGE_1    MSM_GPIO2_REG(0x50)
-#define MSM_GPIO_INT_EDGE_2    MSM_GPIO1_REG(0x64)
-#define MSM_GPIO_INT_EDGE_3    MSM_GPIO1_REG(0x68)
-#define MSM_GPIO_INT_EDGE_4    MSM_GPIO1_REG(0x6C)
-#define MSM_GPIO_INT_EDGE_5    MSM_GPIO1_REG(0xC0)
-#define MSM_GPIO_INT_EDGE_6    MSM_GPIO1_REG(0xD0)
-#define MSM_GPIO_INT_EDGE_7    MSM_GPIO1_REG(0x240)
-
-/* same pin map as above, 1=positive 0=negative */
-#define MSM_GPIO_INT_POS_0     MSM_GPIO1_REG(0x70)
-#define MSM_GPIO_INT_POS_1     MSM_GPIO2_REG(0x58)
-#define MSM_GPIO_INT_POS_2     MSM_GPIO1_REG(0x74)
-#define MSM_GPIO_INT_POS_3     MSM_GPIO1_REG(0x78)
-#define MSM_GPIO_INT_POS_4     MSM_GPIO1_REG(0x7C)
-#define MSM_GPIO_INT_POS_5     MSM_GPIO1_REG(0xBC)
-#define MSM_GPIO_INT_POS_6     MSM_GPIO1_REG(0xD4)
-#define MSM_GPIO_INT_POS_7     MSM_GPIO1_REG(0x228)
-
-/* same pin map as above, interrupt enable */
-#define MSM_GPIO_INT_EN_0      MSM_GPIO1_REG(0x80)
-#define MSM_GPIO_INT_EN_1      MSM_GPIO2_REG(0x60)
-#define MSM_GPIO_INT_EN_2      MSM_GPIO1_REG(0x84)
-#define MSM_GPIO_INT_EN_3      MSM_GPIO1_REG(0x88)
-#define MSM_GPIO_INT_EN_4      MSM_GPIO1_REG(0x8C)
-#define MSM_GPIO_INT_EN_5      MSM_GPIO1_REG(0xB8)
-#define MSM_GPIO_INT_EN_6      MSM_GPIO1_REG(0xD8)
-#define MSM_GPIO_INT_EN_7      MSM_GPIO1_REG(0x22C)
-
-/* same pin map as above, write 1 to clear interrupt */
-#define MSM_GPIO_INT_CLEAR_0   MSM_GPIO1_REG(0x90)
-#define MSM_GPIO_INT_CLEAR_1   MSM_GPIO2_REG(0x68)
-#define MSM_GPIO_INT_CLEAR_2   MSM_GPIO1_REG(0x94)
-#define MSM_GPIO_INT_CLEAR_3   MSM_GPIO1_REG(0x98)
-#define MSM_GPIO_INT_CLEAR_4   MSM_GPIO1_REG(0x9C)
-#define MSM_GPIO_INT_CLEAR_5   MSM_GPIO1_REG(0xB4)
-#define MSM_GPIO_INT_CLEAR_6   MSM_GPIO1_REG(0xDC)
-#define MSM_GPIO_INT_CLEAR_7   MSM_GPIO1_REG(0x230)
-
-/* same pin map as above, 1=interrupt pending */
-#define MSM_GPIO_INT_STATUS_0  MSM_GPIO1_REG(0xA0)
-#define MSM_GPIO_INT_STATUS_1  MSM_GPIO2_REG(0x70)
-#define MSM_GPIO_INT_STATUS_2  MSM_GPIO1_REG(0xA4)
-#define MSM_GPIO_INT_STATUS_3  MSM_GPIO1_REG(0xA8)
-#define MSM_GPIO_INT_STATUS_4  MSM_GPIO1_REG(0xAC)
-#define MSM_GPIO_INT_STATUS_5  MSM_GPIO1_REG(0xB0)
-#define MSM_GPIO_INT_STATUS_6  MSM_GPIO1_REG(0xE0)
-#define MSM_GPIO_INT_STATUS_7  MSM_GPIO1_REG(0x234)
-
-#endif
-
-#endif
index b178d9c..00459f6 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <linux/bitops.h>
 #include <linux/errno.h>
+#include <mach/msm_gpiomux.h>
 
 #if defined(CONFIG_MSM_V2_TLMM)
 #include "gpiomux-v2.h"
@@ -71,12 +72,6 @@ enum {
  */
 extern struct msm_gpiomux_config msm_gpiomux_configs[GPIOMUX_NGPIOS];
 
-/* Increment a gpio's reference count, possibly activating the line. */
-int __must_check msm_gpiomux_get(unsigned gpio);
-
-/* Decrement a gpio's reference count, possibly suspending the line. */
-int msm_gpiomux_put(unsigned gpio);
-
 /* Install a new configuration to the gpio line.  To avoid overwriting
  * a configuration, leave the VALID bit out.
  */
@@ -94,16 +89,6 @@ int msm_gpiomux_write(unsigned gpio,
  */
 void __msm_gpiomux_write(unsigned gpio, gpiomux_config_t val);
 #else
-static inline int __must_check msm_gpiomux_get(unsigned gpio)
-{
-       return -ENOSYS;
-}
-
-static inline int msm_gpiomux_put(unsigned gpio)
-{
-       return -ENOSYS;
-}
-
 static inline int msm_gpiomux_write(unsigned gpio,
                                    gpiomux_config_t active,
                                    gpiomux_config_t suspended)
diff --git a/arch/arm/mach-msm/include/mach/msm_gpiomux.h b/arch/arm/mach-msm/include/mach/msm_gpiomux.h
new file mode 100644 (file)
index 0000000..0c7d393
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (c) 2011, Code Aurora Forum. 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 and
+ * only 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.
+ */
+
+#ifndef _LINUX_MSM_GPIOMUX_H
+#define _LINUX_MSM_GPIOMUX_H
+
+#ifdef CONFIG_MSM_GPIOMUX
+
+/* Increment a gpio's reference count, possibly activating the line. */
+int __must_check msm_gpiomux_get(unsigned gpio);
+
+/* Decrement a gpio's reference count, possibly suspending the line. */
+int msm_gpiomux_put(unsigned gpio);
+
+#else
+
+static inline int __must_check msm_gpiomux_get(unsigned gpio)
+{
+       return -ENOSYS;
+}
+
+static inline int msm_gpiomux_put(unsigned gpio)
+{
+       return -ENOSYS;
+}
+
+#endif
+
+#endif /* _LINUX_MSM_GPIOMUX_H */
index 8f99d97..94fe9fe 100644 (file)
 #define MSM_DMOV_PHYS         0xA9700000
 #define MSM_DMOV_SIZE         SZ_4K
 
-#define MSM_GPIO1_BASE        IOMEM(0xE0003000)
-#define MSM_GPIO1_PHYS        0xA9200000
-#define MSM_GPIO1_SIZE        SZ_4K
+#define MSM7X00_GPIO1_PHYS        0xA9200000
+#define MSM7X00_GPIO1_SIZE        SZ_4K
 
-#define MSM_GPIO2_BASE        IOMEM(0xE0004000)
-#define MSM_GPIO2_PHYS        0xA9300000
-#define MSM_GPIO2_SIZE        SZ_4K
+#define MSM7X00_GPIO2_PHYS        0xA9300000
+#define MSM7X00_GPIO2_SIZE        SZ_4K
 
 #define MSM_CLK_CTL_BASE      IOMEM(0xE0005000)
 #define MSM_CLK_CTL_PHYS      0xA8600000
index 4d84be1..3769444 100644 (file)
 #define MSM_DMOV_PHYS         0xAC400000
 #define MSM_DMOV_SIZE         SZ_4K
 
-#define MSM_GPIO1_BASE        IOMEM(0xE0003000)
-#define MSM_GPIO1_PHYS        0xAC001000
-#define MSM_GPIO1_SIZE        SZ_4K
+#define MSM7X30_GPIO1_PHYS        0xAC001000
+#define MSM7X30_GPIO1_SIZE        SZ_4K
 
-#define MSM_GPIO2_BASE        IOMEM(0xE0004000)
-#define MSM_GPIO2_PHYS        0xAC101000
-#define MSM_GPIO2_SIZE        SZ_4K
+#define MSM7X30_GPIO2_PHYS        0xAC101000
+#define MSM7X30_GPIO2_SIZE        SZ_4K
 
 #define MSM_CLK_CTL_BASE      IOMEM(0xE0005000)
 #define MSM_CLK_CTL_PHYS      0xAB800000
index d414320..d67cd73 100644 (file)
 #define MSM_DMOV_PHYS         0xA9700000
 #define MSM_DMOV_SIZE         SZ_4K
 
-#define MSM_GPIO1_BASE        IOMEM(0xE0003000)
-#define MSM_GPIO1_PHYS        0xA9000000
-#define MSM_GPIO1_SIZE        SZ_4K
+#define QSD8X50_GPIO1_PHYS        0xA9000000
+#define QSD8X50_GPIO1_SIZE        SZ_4K
 
-#define MSM_GPIO2_BASE        IOMEM(0xE0004000)
-#define MSM_GPIO2_PHYS        0xA9100000
-#define MSM_GPIO2_SIZE        SZ_4K
+#define QSD8X50_GPIO2_PHYS        0xA9100000
+#define QSD8X50_GPIO2_SIZE        SZ_4K
 
 #define MSM_CLK_CTL_BASE      IOMEM(0xE0005000)
 #define MSM_CLK_CTL_PHYS      0xA8600000
index 2f494b6..4ded152 100644 (file)
@@ -61,5 +61,7 @@
 #define MSM_QGIC_CPU_BASE      IOMEM(0xF0001000)
 #define MSM_TMR_BASE           IOMEM(0xF0200000)
 #define MSM_TMR0_BASE          IOMEM(0xF0201000)
+#define MSM_GPIO1_BASE         IOMEM(0xE0003000)
+#define MSM_GPIO2_BASE         IOMEM(0xE0004000)
 
 #endif
index cec6ed1..140ddbb 100644 (file)
@@ -43,8 +43,8 @@ static struct map_desc msm_io_desc[] __initdata = {
        MSM_DEVICE(VIC),
        MSM_CHIP_DEVICE(CSR, MSM7X00),
        MSM_DEVICE(DMOV),
-       MSM_DEVICE(GPIO1),
-       MSM_DEVICE(GPIO2),
+       MSM_CHIP_DEVICE(GPIO1, MSM7X00),
+       MSM_CHIP_DEVICE(GPIO2, MSM7X00),
        MSM_DEVICE(CLK_CTL),
 #ifdef CONFIG_MSM_DEBUG_UART
        MSM_DEVICE(DEBUG_UART),
@@ -76,8 +76,8 @@ static struct map_desc qsd8x50_io_desc[] __initdata = {
        MSM_DEVICE(VIC),
        MSM_CHIP_DEVICE(CSR, QSD8X50),
        MSM_DEVICE(DMOV),
-       MSM_DEVICE(GPIO1),
-       MSM_DEVICE(GPIO2),
+       MSM_CHIP_DEVICE(GPIO1, QSD8X50),
+       MSM_CHIP_DEVICE(GPIO2, QSD8X50),
        MSM_DEVICE(CLK_CTL),
        MSM_DEVICE(SIRC),
        MSM_DEVICE(SCPLL),
@@ -135,8 +135,8 @@ static struct map_desc msm7x30_io_desc[] __initdata = {
        MSM_DEVICE(VIC),
        MSM_CHIP_DEVICE(CSR, MSM7X30),
        MSM_DEVICE(DMOV),
-       MSM_DEVICE(GPIO1),
-       MSM_DEVICE(GPIO2),
+       MSM_CHIP_DEVICE(GPIO1, MSM7X30),
+       MSM_CHIP_DEVICE(GPIO2, MSM7X30),
        MSM_DEVICE(CLK_CTL),
        MSM_DEVICE(CLK_CTL_SH2),
        MSM_DEVICE(AD5),
index d6336af..c51af1c 100644 (file)
@@ -260,7 +260,8 @@ mv78xx0_pcie_scan_bus(int nr, struct pci_sys_data *sys)
        return bus;
 }
 
-static int __init mv78xx0_pcie_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init mv78xx0_pcie_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        struct pcie_port *pp = bus_to_port(dev->bus->number);
 
index 7c893fa..68934ea 100644 (file)
@@ -81,7 +81,7 @@ static struct plat_serial8250_port serial_platform_data[] = {
                .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP,
        }, {
                .mapbase = (unsigned long)(MX51_CS1_BASE_ADDR + 0x2000000),
-               .irq = irq_to_gpio(CPUIMX51_QUARTD_GPIO),
+               .irq = gpio_to_irq(CPUIMX51_QUARTD_GPIO),
                .irqflags = IRQF_TRIGGER_HIGH,
                .uartclk = CPUIMX51_QUART_XTAL,
                .regshift = CPUIMX51_QUART_REGSHIFT,
index 15c6000..11b0ff6 100644 (file)
@@ -41,8 +41,6 @@
 #define BABBAGE_POWER_KEY      IMX_GPIO_NR(2, 21)
 #define BABBAGE_ECSPI1_CS0     IMX_GPIO_NR(4, 24)
 #define BABBAGE_ECSPI1_CS1     IMX_GPIO_NR(4, 25)
-#define BABBAGE_SD1_CD         IMX_GPIO_NR(1, 0)
-#define BABBAGE_SD1_WP         IMX_GPIO_NR(1, 1)
 #define BABBAGE_SD2_CD         IMX_GPIO_NR(1, 6)
 #define BABBAGE_SD2_WP         IMX_GPIO_NR(1, 5)
 
@@ -146,8 +144,9 @@ static iomux_v3_cfg_t mx51babbage_pads[] = {
        MX51_PAD_SD1_DATA1__SD1_DATA1,
        MX51_PAD_SD1_DATA2__SD1_DATA2,
        MX51_PAD_SD1_DATA3__SD1_DATA3,
-       MX51_PAD_GPIO1_0__GPIO1_0,
-       MX51_PAD_GPIO1_1__GPIO1_1,
+       /* CD/WP from controller */
+       MX51_PAD_GPIO1_0__SD1_CD,
+       MX51_PAD_GPIO1_1__SD1_WP,
 
        /* SD 2 */
        MX51_PAD_SD2_CMD__SD2_CMD,
@@ -156,6 +155,7 @@ static iomux_v3_cfg_t mx51babbage_pads[] = {
        MX51_PAD_SD2_DATA1__SD2_DATA1,
        MX51_PAD_SD2_DATA2__SD2_DATA2,
        MX51_PAD_SD2_DATA3__SD2_DATA3,
+       /* CD/WP gpio */
        MX51_PAD_GPIO1_6__GPIO1_6,
        MX51_PAD_GPIO1_5__GPIO1_5,
 
@@ -340,13 +340,15 @@ static const struct spi_imx_master mx51_babbage_spi_pdata __initconst = {
 };
 
 static const struct esdhc_platform_data mx51_babbage_sd1_data __initconst = {
-       .cd_gpio = BABBAGE_SD1_CD,
-       .wp_gpio = BABBAGE_SD1_WP,
+       .cd_type = ESDHC_CD_CONTROLLER,
+       .wp_type = ESDHC_WP_CONTROLLER,
 };
 
 static const struct esdhc_platform_data mx51_babbage_sd2_data __initconst = {
        .cd_gpio = BABBAGE_SD2_CD,
        .wp_gpio = BABBAGE_SD2_WP,
+       .cd_type = ESDHC_CD_GPIO,
+       .wp_type = ESDHC_WP_GPIO,
 };
 
 /*
@@ -367,7 +369,7 @@ static void __init mx51_babbage_init(void)
                                        ARRAY_SIZE(mx51babbage_pads));
 
        imx51_add_imx_uart(0, &uart_pdata);
-       imx51_add_imx_uart(1, &uart_pdata);
+       imx51_add_imx_uart(1, NULL);
        imx51_add_imx_uart(2, &uart_pdata);
 
        babbage_fec_reset();
index f70700d..551daf8 100644 (file)
@@ -108,9 +108,9 @@ static void __init mx51_efikamx_board_id(void)
        gpio_request(EFIKAMX_PCBID2, "pcbid2");
        gpio_direction_input(EFIKAMX_PCBID2);
 
-       id = gpio_get_value(EFIKAMX_PCBID0);
-       id |= gpio_get_value(EFIKAMX_PCBID1) << 1;
-       id |= gpio_get_value(EFIKAMX_PCBID2) << 2;
+       id = gpio_get_value(EFIKAMX_PCBID0) ? 1 : 0;
+       id |= (gpio_get_value(EFIKAMX_PCBID1) ? 1 : 0) << 1;
+       id |= (gpio_get_value(EFIKAMX_PCBID2) ? 1 : 0) << 2;
 
        switch (id) {
        case 7:
index 2e4d9d3..8a9bca2 100644 (file)
@@ -156,23 +156,24 @@ static struct gpio_keys_button mx51_efikasb_keys[] = {
        {
                .code = KEY_POWER,
                .gpio = EFIKASB_PWRKEY,
-               .type = EV_PWR,
+               .type = EV_KEY,
                .desc = "Power Button",
                .wakeup = 1,
-               .debounce_interval = 10, /* ms */
+               .active_low = 1,
        },
        {
                .code = SW_LID,
                .gpio = EFIKASB_LID,
                .type = EV_SW,
                .desc = "Lid Switch",
+               .active_low = 1,
        },
        {
-               /* SW_RFKILLALL vs KEY_RFKILL ? */
-               .code = SW_RFKILL_ALL,
+               .code = KEY_RFKILL,
                .gpio = EFIKASB_RFKILL,
-               .type = EV_SW,
+               .type = EV_KEY,
                .desc = "rfkill",
+               .active_low = 1,
        },
 };
 
@@ -224,8 +225,8 @@ static void __init mx51_efikasb_board_id(void)
        gpio_request(EFIKASB_PCBID1, "pcb id1");
        gpio_direction_input(EFIKASB_PCBID1);
 
-       id = gpio_get_value(EFIKASB_PCBID0);
-       id |= gpio_get_value(EFIKASB_PCBID1) << 1;
+       id = gpio_get_value(EFIKASB_PCBID0) ? 1 : 0;
+       id |= (gpio_get_value(EFIKASB_PCBID1) ? 1 : 0) << 1;
 
        switch (id) {
        default:
index 54be525..4e1d51d 100644 (file)
@@ -210,11 +210,15 @@ static const struct gpio_keys_platform_data loco_button_data __initconst = {
 
 static const struct esdhc_platform_data mx53_loco_sd1_data __initconst = {
        .cd_gpio = LOCO_SD1_CD,
+       .cd_type = ESDHC_CD_GPIO,
+       .wp_type = ESDHC_WP_NONE,
 };
 
 static const struct esdhc_platform_data mx53_loco_sd3_data __initconst = {
        .cd_gpio = LOCO_SD3_CD,
        .wp_gpio = LOCO_SD3_WP,
+       .cd_type = ESDHC_CD_GPIO,
+       .wp_type = ESDHC_WP_GPIO,
 };
 
 static inline void mx53_loco_fec_reset(void)
index 23cd809..f7bf996 100644 (file)
@@ -271,7 +271,11 @@ static int _clk_pll_enable(struct clk *clk)
        int i = 0;
 
        pllbase = _get_pll_base(clk);
-       reg = __raw_readl(pllbase + MXC_PLL_DP_CTL) | MXC_PLL_DP_CTL_UPEN;
+       reg = __raw_readl(pllbase + MXC_PLL_DP_CTL);
+       if (reg & MXC_PLL_DP_CTL_UPEN)
+               return 0;
+
+       reg |= MXC_PLL_DP_CTL_UPEN;
        __raw_writel(reg, pllbase + MXC_PLL_DP_CTL);
 
        /* Wait for lock */
@@ -1422,11 +1426,13 @@ DEFINE_CLOCK(ipu_di1_clk, 0, MXC_CCM_CCGR6, MXC_CCM_CCGRx_CG6_OFFSET,
        },
 
 static struct clk_lookup mx51_lookups[] = {
-       _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk)
-       _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk)
-       _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk)
+       /* i.mx51 has the i.mx21 type uart */
+       _REGISTER_CLOCK("imx21-uart.0", NULL, uart1_clk)
+       _REGISTER_CLOCK("imx21-uart.1", NULL, uart2_clk)
+       _REGISTER_CLOCK("imx21-uart.2", NULL, uart3_clk)
        _REGISTER_CLOCK(NULL, "gpt", gpt_clk)
-       _REGISTER_CLOCK("fec.0", NULL, fec_clk)
+       /* i.mx51 has the i.mx27 type fec */
+       _REGISTER_CLOCK("imx27-fec.0", NULL, fec_clk)
        _REGISTER_CLOCK("mxc_pwm.0", "pwm", pwm1_clk)
        _REGISTER_CLOCK("mxc_pwm.1", "pwm", pwm2_clk)
        _REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk)
@@ -1446,7 +1452,8 @@ static struct clk_lookup mx51_lookups[] = {
        _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk)
        _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk)
        _REGISTER_CLOCK("imx-ssi.2", NULL, ssi3_clk)
-       _REGISTER_CLOCK("imx-sdma", NULL, sdma_clk)
+       /* i.mx51 has the i.mx35 type sdma */
+       _REGISTER_CLOCK("imx35-sdma", NULL, sdma_clk)
        _REGISTER_CLOCK(NULL, "ckih", ckih_clk)
        _REGISTER_CLOCK(NULL, "ckih2", ckih2_clk)
        _REGISTER_CLOCK(NULL, "gpt_32k", gpt_32k_clk)
@@ -1454,10 +1461,10 @@ static struct clk_lookup mx51_lookups[] = {
        _REGISTER_CLOCK("imx51-ecspi.1", NULL, ecspi2_clk)
        /* i.mx51 has the i.mx35 type cspi */
        _REGISTER_CLOCK("imx35-cspi.0", NULL, cspi_clk)
-       _REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk)
-       _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_clk)
-       _REGISTER_CLOCK("sdhci-esdhc-imx.2", NULL, esdhc3_clk)
-       _REGISTER_CLOCK("sdhci-esdhc-imx.3", NULL, esdhc4_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx51.0", NULL, esdhc1_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx51.1", NULL, esdhc2_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx51.2", NULL, esdhc3_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx51.3", NULL, esdhc4_clk)
        _REGISTER_CLOCK(NULL, "cpu_clk", cpu_clk)
        _REGISTER_CLOCK(NULL, "iim_clk", iim_clk)
        _REGISTER_CLOCK("imx2-wdt.0", NULL, dummy_clk)
@@ -1470,29 +1477,32 @@ static struct clk_lookup mx51_lookups[] = {
 };
 
 static struct clk_lookup mx53_lookups[] = {
-       _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk)
-       _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk)
-       _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk)
-       _REGISTER_CLOCK("imx-uart.3", NULL, uart4_clk)
-       _REGISTER_CLOCK("imx-uart.4", NULL, uart5_clk)
+       /* i.mx53 has the i.mx21 type uart */
+       _REGISTER_CLOCK("imx21-uart.0", NULL, uart1_clk)
+       _REGISTER_CLOCK("imx21-uart.1", NULL, uart2_clk)
+       _REGISTER_CLOCK("imx21-uart.2", NULL, uart3_clk)
+       _REGISTER_CLOCK("imx21-uart.3", NULL, uart4_clk)
+       _REGISTER_CLOCK("imx21-uart.4", NULL, uart5_clk)
        _REGISTER_CLOCK(NULL, "gpt", gpt_clk)
-       _REGISTER_CLOCK("fec.0", NULL, fec_clk)
+       /* i.mx53 has the i.mx25 type fec */
+       _REGISTER_CLOCK("imx25-fec.0", NULL, fec_clk)
        _REGISTER_CLOCK(NULL, "iim_clk", iim_clk)
        _REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk)
        _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk)
        _REGISTER_CLOCK("imx-i2c.2", NULL, i2c3_mx53_clk)
-       _REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk)
-       _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_mx53_clk)
-       _REGISTER_CLOCK("sdhci-esdhc-imx.2", NULL, esdhc3_mx53_clk)
-       _REGISTER_CLOCK("sdhci-esdhc-imx.3", NULL, esdhc4_mx53_clk)
        /* i.mx53 has the i.mx51 type ecspi */
        _REGISTER_CLOCK("imx51-ecspi.0", NULL, ecspi1_clk)
        _REGISTER_CLOCK("imx51-ecspi.1", NULL, ecspi2_clk)
        /* i.mx53 has the i.mx25 type cspi */
        _REGISTER_CLOCK("imx35-cspi.0", NULL, cspi_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx53.0", NULL, esdhc1_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx53.1", NULL, esdhc2_mx53_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx53.2", NULL, esdhc3_mx53_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx53.3", NULL, esdhc4_mx53_clk)
        _REGISTER_CLOCK("imx2-wdt.0", NULL, dummy_clk)
        _REGISTER_CLOCK("imx2-wdt.1", NULL, dummy_clk)
-       _REGISTER_CLOCK("imx-sdma", NULL, sdma_clk)
+       /* i.mx53 has the i.mx35 type sdma */
+       _REGISTER_CLOCK("imx35-sdma", NULL, sdma_clk)
        _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk)
        _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk)
        _REGISTER_CLOCK("imx-ssi.2", NULL, ssi3_clk)
index ef8aec9..baea6e5 100644 (file)
@@ -115,7 +115,6 @@ static struct sdma_script_start_addrs imx51_sdma_script __initdata = {
 };
 
 static struct sdma_platform_data imx51_sdma_pdata __initdata = {
-       .sdma_version = 2,
        .fw_name = "sdma-imx51.bin",
        .script_addrs = &imx51_sdma_script,
 };
@@ -135,7 +134,6 @@ static struct sdma_script_start_addrs imx53_sdma_script __initdata = {
 };
 
 static struct sdma_platform_data imx53_sdma_pdata __initdata = {
-       .sdma_version = 2,
        .fw_name = "sdma-imx53.bin",
        .script_addrs = &imx53_sdma_script,
 };
@@ -148,7 +146,8 @@ void __init imx51_soc_init(void)
        mxc_register_gpio("imx31-gpio", 2, MX51_GPIO3_BASE_ADDR, SZ_16K, MX51_MXC_INT_GPIO3_LOW, MX51_MXC_INT_GPIO3_HIGH);
        mxc_register_gpio("imx31-gpio", 3, MX51_GPIO4_BASE_ADDR, SZ_16K, MX51_MXC_INT_GPIO4_LOW, MX51_MXC_INT_GPIO4_HIGH);
 
-       imx_add_imx_sdma(MX51_SDMA_BASE_ADDR, MX51_INT_SDMA, &imx51_sdma_pdata);
+       /* i.mx51 has the i.mx35 type sdma */
+       imx_add_imx_sdma("imx35-sdma", MX51_SDMA_BASE_ADDR, MX51_INT_SDMA, &imx51_sdma_pdata);
 }
 
 void __init imx53_soc_init(void)
@@ -162,5 +161,6 @@ void __init imx53_soc_init(void)
        mxc_register_gpio("imx31-gpio", 5, MX53_GPIO6_BASE_ADDR, SZ_16K, MX53_INT_GPIO6_LOW, MX53_INT_GPIO6_HIGH);
        mxc_register_gpio("imx31-gpio", 6, MX53_GPIO7_BASE_ADDR, SZ_16K, MX53_INT_GPIO7_LOW, MX53_INT_GPIO7_HIGH);
 
-       imx_add_imx_sdma(MX53_SDMA_BASE_ADDR, MX53_INT_SDMA, &imx53_sdma_pdata);
+       /* i.mx53 has the i.mx35 type sdma */
+       imx_add_imx_sdma("imx35-sdma", MX53_SDMA_BASE_ADDR, MX53_INT_SDMA, &imx53_sdma_pdata);
 }
index 56739c2..c920945 100644 (file)
@@ -186,7 +186,7 @@ static int initialize_usbh1_port(struct platform_device *pdev)
 
        mdelay(10);
 
-       return mx51_initialize_usb_hw(0, MXC_EHCI_ITC_NO_THRESHOLD);
+       return mx51_initialize_usb_hw(pdev->id, MXC_EHCI_ITC_NO_THRESHOLD);
 }
 
 static struct mxc_usbh_platform_data usbh1_config = {
@@ -260,8 +260,8 @@ static struct regulator_consumer_supply vvideo_consumers[] = {
 };
 
 static struct regulator_consumer_supply vsd_consumers[] = {
-       REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.0"),
-       REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.1"),
+       REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx51.0"),
+       REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx51.1"),
 };
 
 static struct regulator_consumer_supply pwgt1_consumer[] = {
index 4ae6257..57b66d5 100644 (file)
@@ -7,7 +7,6 @@ config ARCH_OMAP2PLUS_TYPICAL
        default y
        select AEABI
        select REGULATOR
-       select PM
        select PM_RUNTIME
        select VFP
        select NEON if ARCH_OMAP3 || ARCH_OMAP4
index 5f2b55f..933e935 100644 (file)
@@ -45,8 +45,6 @@ static struct omap_board_config_kernel am3517_crane_config[] __initdata = {
 static struct omap_board_mux board_mux[] __initdata = {
        { .reg_offset = OMAP_MUX_TERMINATOR },
 };
-#else
-#define board_mux      NULL
 #endif
 
 static void __init am3517_crane_init_early(void)
index 32f5f89..3ae16b4 100644 (file)
@@ -491,23 +491,22 @@ static void __init beagle_opp_init(void)
 
        /* Custom OPP enabled for all xM versions */
        if (cpu_is_omap3630()) {
-               struct omap_hwmod *mh = omap_hwmod_lookup("mpu");
-               struct omap_hwmod *dh = omap_hwmod_lookup("iva");
-               struct device *dev;
+               struct device *mpu_dev, *iva_dev;
 
-               if (!mh || !dh) {
+               mpu_dev = omap2_get_mpuss_device();
+               iva_dev = omap2_get_iva_device();
+
+               if (!mpu_dev || !iva_dev) {
                        pr_err("%s: Aiee.. no mpu/dsp devices? %p %p\n",
-                               __func__, mh, dh);
+                               __func__, mpu_dev, iva_dev);
                        return;
                }
                /* Enable MPU 1GHz and lower opps */
-               dev = &mh->od->pdev.dev;
-               r = opp_enable(dev, 800000000);
+               r = opp_enable(mpu_dev, 800000000);
                /* TODO: MPU 1GHz needs SR and ABB */
 
                /* Enable IVA 800MHz and lower opps */
-               dev = &dh->od->pdev.dev;
-               r |= opp_enable(dev, 660000000);
+               r |= opp_enable(iva_dev, 660000000);
                /* TODO: DSP 800MHz needs SR and ABB */
                if (r) {
                        pr_err("%s: failed to enable higher opp %d\n",
@@ -516,10 +515,8 @@ static void __init beagle_opp_init(void)
                         * Cleanup - disable the higher freqs - we dont care
                         * about the results
                         */
-                       dev = &mh->od->pdev.dev;
-                       opp_disable(dev, 800000000);
-                       dev = &dh->od->pdev.dev;
-                       opp_disable(dev, 660000000);
+                       opp_disable(mpu_dev, 800000000);
+                       opp_disable(iva_dev, 660000000);
                }
        }
        return;
index cc503aa..5a886cd 100644 (file)
@@ -418,6 +418,10 @@ static struct regulator_consumer_supply rx51_vmmc1_supply[] = {
        REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"),
 };
 
+static struct regulator_consumer_supply rx51_vaux2_supply[] = {
+       REGULATOR_SUPPLY("vdds_csib", "omap3isp"),
+};
+
 static struct regulator_consumer_supply rx51_vaux3_supply[] = {
        REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1"),
 };
@@ -479,6 +483,8 @@ static struct regulator_init_data rx51_vaux2 = {
                .valid_ops_mask         = REGULATOR_CHANGE_MODE
                                        | REGULATOR_CHANGE_STATUS,
        },
+       .num_consumer_supplies  = ARRAY_SIZE(rx51_vaux2_supply),
+       .consumer_supplies      = rx51_vaux2_supply,
 };
 
 /* VAUX3 - adds more power to VIO_18 rail */
index f2ea645..a018a73 100644 (file)
@@ -18,13 +18,36 @@ extern void omap4_cminst_clkdm_force_sleep(u8 part, s16 inst, u16 cdoffs);
 extern void omap4_cminst_clkdm_force_wakeup(u8 part, s16 inst, u16 cdoffs);
 
 extern int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs);
-extern int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs);
+
+# ifdef CONFIG_ARCH_OMAP4
+extern int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs,
+                                        u16 clkctrl_offs);
 
 extern void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, s16 cdoffs,
                                       u16 clkctrl_offs);
 extern void omap4_cminst_module_disable(u8 part, u16 inst, s16 cdoffs,
                                        u16 clkctrl_offs);
 
+# else
+
+static inline int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs,
+                                       u16 clkctrl_offs)
+{
+       return 0;
+}
+
+static inline void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst,
+                               s16 cdoffs, u16 clkctrl_offs)
+{
+}
+
+static inline void omap4_cminst_module_disable(u8 part, u16 inst, s16 cdoffs,
+                                u16 clkctrl_offs)
+{
+}
+
+# endif
+
 /*
  * In an ideal world, we would not export these low-level functions,
  * but this will probably take some time to fix properly
index 543fcb8..a5b7a23 100644 (file)
@@ -25,6 +25,7 @@
 #include <video/omapdss.h>
 #include <plat/omap_hwmod.h>
 #include <plat/omap_device.h>
+#include <plat/omap-pm.h>
 
 static struct platform_device omap_display_device = {
        .name          = "omapdss",
@@ -42,20 +43,6 @@ static struct omap_device_pm_latency omap_dss_latency[] = {
        },
 };
 
-/* oh_core is used for getting opt-clocks */
-static struct omap_hwmod       *oh_core;
-
-static bool opt_clock_available(const char *clk_role)
-{
-       int i;
-
-       for (i = 0; i < oh_core->opt_clks_cnt; i++) {
-               if (!strcmp(oh_core->opt_clks[i].role, clk_role))
-                       return true;
-       }
-       return false;
-}
-
 struct omap_dss_hwmod_data {
        const char *oh_name;
        const char *dev_name;
@@ -109,16 +96,9 @@ int __init omap_display_init(struct omap_dss_board_info *board_data)
                oh_count = ARRAY_SIZE(omap4_dss_hwmod_data);
        }
 
-       /* opt_clks are always associated with dss hwmod */
-       oh_core = omap_hwmod_lookup("dss_core");
-       if (!oh_core) {
-               pr_err("Could not look up dss_core.\n");
-               return -ENODEV;
-       }
-
        pdata.board_data = board_data;
-       pdata.board_data->get_last_off_on_transaction_id = NULL;
-       pdata.opt_clock_available = opt_clock_available;
+       pdata.board_data->get_context_loss_count =
+               omap_pm_get_dev_context_loss_count;
 
        for (i = 0; i < oh_count; i++) {
                oh = omap_hwmod_lookup(curr_dss_hwmod[i].oh_name);
index c7fb22a..655e948 100644 (file)
@@ -821,11 +821,10 @@ static void __init omap_mux_set_cmdline_signals(void)
        if (!omap_mux_options)
                return;
 
-       options = kmalloc(strlen(omap_mux_options) + 1, GFP_KERNEL);
+       options = kstrdup(omap_mux_options, GFP_KERNEL);
        if (!options)
                return;
 
-       strcpy(options, omap_mux_options);
        next_opt = options;
 
        while ((token = strsep(&next_opt, ",")) != NULL) {
@@ -855,24 +854,19 @@ static int __init omap_mux_copy_names(struct omap_mux *src,
 
        for (i = 0; i < OMAP_MUX_NR_MODES; i++) {
                if (src->muxnames[i]) {
-                       dst->muxnames[i] =
-                               kmalloc(strlen(src->muxnames[i]) + 1,
-                                       GFP_KERNEL);
+                       dst->muxnames[i] = kstrdup(src->muxnames[i],
+                                                  GFP_KERNEL);
                        if (!dst->muxnames[i])
                                goto free;
-                       strcpy(dst->muxnames[i], src->muxnames[i]);
                }
        }
 
 #ifdef CONFIG_DEBUG_FS
        for (i = 0; i < OMAP_MUX_NR_SIDES; i++) {
                if (src->balls[i]) {
-                       dst->balls[i] =
-                               kmalloc(strlen(src->balls[i]) + 1,
-                                       GFP_KERNEL);
+                       dst->balls[i] = kstrdup(src->balls[i], GFP_KERNEL);
                        if (!dst->balls[i])
                                goto free;
-                       strcpy(dst->balls[i], src->balls[i]);
                }
        }
 #endif
index 2ce2fb7..34c01a7 100644 (file)
@@ -621,7 +621,7 @@ void sr_disable(struct voltagedomain *voltdm)
                        sr_v2_disable(sr);
        }
 
-       pm_runtime_put_sync(&sr->pdev->dev);
+       pm_runtime_put_sync_suspend(&sr->pdev->dev);
 }
 
 /**
@@ -860,6 +860,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
        irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 
        pm_runtime_enable(&pdev->dev);
+       pm_runtime_irq_safe(&pdev->dev);
 
        sr_info->pdev = pdev;
        sr_info->srid = pdev->id;
index e964072..cf1de7d 100644 (file)
@@ -293,7 +293,8 @@ static void __init omap2_gp_clocksource_init(int gptimer_id,
        pr_info("OMAP clocksource: GPTIMER%d at %lu Hz\n",
                gptimer_id, clksrc.rate);
 
-       __omap_dm_timer_load_start(clksrc.io_base, OMAP_TIMER_CTRL_ST, 0, 1);
+       __omap_dm_timer_load_start(clksrc.io_base,
+                       OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1);
        init_sched_clock(&cd, dmtimer_update_sched_clock, 32, clksrc.rate);
 
        if (clocksource_register_hz(&clocksource_gpt, clksrc.rate))
index 2543342..daa056e 100644 (file)
@@ -48,14 +48,7 @@ void __init omap_pmic_init(int bus, u32 clkrate,
        omap_register_i2c_bus(bus, clkrate, &pmic_i2c_board_info, 1);
 }
 
-static struct twl4030_usb_data omap4_usb_pdata = {
-       .phy_init       = omap4430_phy_init,
-       .phy_exit       = omap4430_phy_exit,
-       .phy_power      = omap4430_phy_power,
-       .phy_set_clock  = omap4430_phy_set_clk,
-       .phy_suspend    = omap4430_phy_suspend,
-};
-
+#if defined(CONFIG_ARCH_OMAP3)
 static struct twl4030_usb_data omap3_usb_pdata = {
        .usb_mode       = T2_USB_MODE_ULPI,
 };
@@ -122,6 +115,45 @@ static struct regulator_init_data omap3_vpll2_idata = {
        .consumer_supplies              = omap3_vpll2_supplies,
 };
 
+void __init omap3_pmic_get_config(struct twl4030_platform_data *pmic_data,
+                                 u32 pdata_flags, u32 regulators_flags)
+{
+       if (!pmic_data->irq_base)
+               pmic_data->irq_base = TWL4030_IRQ_BASE;
+       if (!pmic_data->irq_end)
+               pmic_data->irq_end = TWL4030_IRQ_END;
+
+       /* Common platform data configurations */
+       if (pdata_flags & TWL_COMMON_PDATA_USB && !pmic_data->usb)
+               pmic_data->usb = &omap3_usb_pdata;
+
+       if (pdata_flags & TWL_COMMON_PDATA_BCI && !pmic_data->bci)
+               pmic_data->bci = &omap3_bci_pdata;
+
+       if (pdata_flags & TWL_COMMON_PDATA_MADC && !pmic_data->madc)
+               pmic_data->madc = &omap3_madc_pdata;
+
+       if (pdata_flags & TWL_COMMON_PDATA_AUDIO && !pmic_data->audio)
+               pmic_data->audio = &omap3_audio_pdata;
+
+       /* Common regulator configurations */
+       if (regulators_flags & TWL_COMMON_REGULATOR_VDAC && !pmic_data->vdac)
+               pmic_data->vdac = &omap3_vdac_idata;
+
+       if (regulators_flags & TWL_COMMON_REGULATOR_VPLL2 && !pmic_data->vpll2)
+               pmic_data->vpll2 = &omap3_vpll2_idata;
+}
+#endif /* CONFIG_ARCH_OMAP3 */
+
+#if defined(CONFIG_ARCH_OMAP4)
+static struct twl4030_usb_data omap4_usb_pdata = {
+       .phy_init       = omap4430_phy_init,
+       .phy_exit       = omap4430_phy_exit,
+       .phy_power      = omap4430_phy_power,
+       .phy_set_clock  = omap4430_phy_set_clk,
+       .phy_suspend    = omap4430_phy_suspend,
+};
+
 static struct regulator_init_data omap4_vdac_idata = {
        .constraints = {
                .min_uV                 = 1800000,
@@ -273,32 +305,4 @@ void __init omap4_pmic_get_config(struct twl4030_platform_data *pmic_data,
            !pmic_data->clk32kg)
                pmic_data->clk32kg = &omap4_clk32kg_idata;
 }
-
-void __init omap3_pmic_get_config(struct twl4030_platform_data *pmic_data,
-                                 u32 pdata_flags, u32 regulators_flags)
-{
-       if (!pmic_data->irq_base)
-               pmic_data->irq_base = TWL4030_IRQ_BASE;
-       if (!pmic_data->irq_end)
-               pmic_data->irq_end = TWL4030_IRQ_END;
-
-       /* Common platform data configurations */
-       if (pdata_flags & TWL_COMMON_PDATA_USB && !pmic_data->usb)
-               pmic_data->usb = &omap3_usb_pdata;
-
-       if (pdata_flags & TWL_COMMON_PDATA_BCI && !pmic_data->bci)
-               pmic_data->bci = &omap3_bci_pdata;
-
-       if (pdata_flags & TWL_COMMON_PDATA_MADC && !pmic_data->madc)
-               pmic_data->madc = &omap3_madc_pdata;
-
-       if (pdata_flags & TWL_COMMON_PDATA_AUDIO && !pmic_data->audio)
-               pmic_data->audio = &omap3_audio_pdata;
-
-       /* Common regulator configurations */
-       if (regulators_flags & TWL_COMMON_REGULATOR_VDAC && !pmic_data->vdac)
-               pmic_data->vdac = &omap3_vdac_idata;
-
-       if (regulators_flags & TWL_COMMON_REGULATOR_VPLL2 && !pmic_data->vpll2)
-               pmic_data->vpll2 = &omap3_vpll2_idata;
-}
+#endif /* CONFIG_ARCH_OMAP4 */
index f2b2b35..3e5499d 100644 (file)
@@ -51,7 +51,7 @@ void orion5x_pci_disable(void);
 void orion5x_pci_set_cardbus_mode(void);
 int orion5x_pci_sys_setup(int nr, struct pci_sys_data *sys);
 struct pci_bus *orion5x_pci_sys_scan_bus(int nr, struct pci_sys_data *sys);
-int orion5x_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin);
+int orion5x_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin);
 
 struct machine_desc;
 struct meminfo;
index f95d3cb..a3e3e9e 100644 (file)
@@ -237,7 +237,8 @@ void __init db88f5281_pci_preinit(void)
        }
 }
 
-static int __init db88f5281_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init db88f5281_pci_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        int irq;
 
index 855e0e7..a6eddae 100644 (file)
@@ -70,14 +70,14 @@ enum {
  * PCI setup
  */
 
-static int __init dns323_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init dns323_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
 
        /*
         * Check for devices with hard-wired IRQs.
         */
-       irq = orion5x_pci_map_irq(dev, slot, pin);
+       irq = orion5x_pci_map_irq(const dev, slot, pin);
        if (irq != -1)
                return irq;
 
index c0eb646..0038124 100644 (file)
@@ -119,7 +119,8 @@ static struct platform_device kurobox_pro_nor_flash = {
  * PCI
  ****************************************************************************/
 
-static int __init kurobox_pro_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init kurobox_pro_pci_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        int irq;
 
index 59263b7..ef3bb8e 100644 (file)
@@ -73,7 +73,7 @@ static struct platform_device mss2_nor_flash = {
 /****************************************************************************
  * PCI setup
  ****************************************************************************/
-static int __init mss2_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init mss2_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
 
index f64965d..28b8760 100644 (file)
@@ -589,7 +589,7 @@ struct pci_bus __init *orion5x_pci_sys_scan_bus(int nr, struct pci_sys_data *sys
        return bus;
 }
 
-int __init orion5x_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+int __init orion5x_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int bus = dev->bus->number;
 
index 9eec7c2..291d22b 100644 (file)
@@ -131,7 +131,7 @@ static void __init rd88f5181l_fxo_init(void)
 }
 
 static int __init
-rd88f5181l_fxo_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+rd88f5181l_fxo_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
 
index 0cc90bb..3f02362 100644 (file)
@@ -140,7 +140,7 @@ static void __init rd88f5181l_ge_init(void)
 }
 
 static int __init
-rd88f5181l_ge_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+rd88f5181l_ge_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
 
index 48da39b..27fd38e 100644 (file)
@@ -172,7 +172,8 @@ void __init rd88f5182_pci_preinit(void)
        }
 }
 
-static int __init rd88f5182_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init rd88f5182_pci_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        int irq;
 
index 29ce826..a34e4fa 100644 (file)
@@ -100,7 +100,7 @@ void __init tsp2_pci_preinit(void)
        }
 }
 
-static int __init tsp2_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init tsp2_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
 
index 47162fd..c983161 100644 (file)
@@ -143,7 +143,8 @@ void __init qnap_ts209_pci_preinit(void)
        }
 }
 
-static int __init qnap_ts209_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init qnap_ts209_pci_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        int irq;
 
index 5aacc7a..cc33b22 100644 (file)
@@ -121,7 +121,8 @@ static struct platform_device qnap_ts409_nor_flash = {
  * PCI
  ****************************************************************************/
 
-static int __init qnap_ts409_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init qnap_ts409_pci_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        int irq;
 
index 444a1c7..2653595 100644 (file)
@@ -133,7 +133,8 @@ static void __init wnr854t_init(void)
        platform_device_register(&wnr854t_nor_flash);
 }
 
-static int __init wnr854t_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init wnr854t_pci_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        int irq;
 
index d1952be..251ef15 100644 (file)
@@ -221,7 +221,8 @@ static void __init wrt350n_v2_init(void)
        platform_device_register(&wrt350n_v2_button_device);
 }
 
-static int __init wrt350n_v2_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init wrt350n_v2_pci_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        int irq;
 
index 4eb7660..6bf479d 100644 (file)
@@ -77,7 +77,7 @@ void cmx2xx_pci_resume(void) {}
 #endif
 
 /* PCI IRQ mapping*/
-static int __init cmx2xx_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init cmx2xx_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
 
index 9026249..af0c2fe 100644 (file)
@@ -65,7 +65,7 @@
 #include <plat/iic.h>
 #include <plat/pm.h>
 
-#include <sound/wm8915.h>
+#include <sound/wm8996.h>
 #include <sound/wm8962.h>
 #include <sound/wm9081.h>
 
@@ -614,7 +614,7 @@ static struct wm831x_pdata glenfarclas_pmic_pdata __initdata = {
        .disable_touch = true,
 };
 
-static struct wm8915_retune_mobile_config wm8915_retune[] = {
+static struct wm8996_retune_mobile_config wm8996_retune[] = {
        {
                .name = "Sub LPF",
                .rate = 48000,
@@ -635,12 +635,12 @@ static struct wm8915_retune_mobile_config wm8915_retune[] = {
        },
 };
 
-static struct wm8915_pdata wm8915_pdata __initdata = {
+static struct wm8996_pdata wm8996_pdata __initdata = {
        .ldo_ena = S3C64XX_GPN(7),
        .gpio_base = CODEC_GPIO_BASE,
        .micdet_def = 1,
-       .inl_mode = WM8915_DIFFERRENTIAL_1,
-       .inr_mode = WM8915_DIFFERRENTIAL_1,
+       .inl_mode = WM8996_DIFFERRENTIAL_1,
+       .inr_mode = WM8996_DIFFERRENTIAL_1,
 
        .irq_flags = IRQF_TRIGGER_RISING,
 
@@ -652,8 +652,8 @@ static struct wm8915_pdata wm8915_pdata __initdata = {
                0x020e, /* GPIO5 == CLKOUT */
        },
 
-       .retune_mobile_cfgs = wm8915_retune,
-       .num_retune_mobile_cfgs = ARRAY_SIZE(wm8915_retune),
+       .retune_mobile_cfgs = wm8996_retune,
+       .num_retune_mobile_cfgs = ARRAY_SIZE(wm8996_retune),
 };
 
 static struct wm8962_pdata wm8962_pdata __initdata = {
@@ -679,8 +679,8 @@ static struct i2c_board_info i2c_devs1[] __initdata = {
          .platform_data = &glenfarclas_pmic_pdata },
 
        { I2C_BOARD_INFO("wm1250-ev1", 0x27) },
-       { I2C_BOARD_INFO("wm8915", 0x1a),
-         .platform_data = &wm8915_pdata,
+       { I2C_BOARD_INFO("wm8996", 0x1a),
+         .platform_data = &wm8996_pdata,
          .irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2,
        },
        { I2C_BOARD_INFO("wm9081", 0x6c),
index 5fc074f..dd39fee 100644 (file)
@@ -28,6 +28,7 @@
 #include <asm/mach-types.h>
 
 #include <mach/nanoengine.h>
+#include <mach/hardware.h>
 
 static DEFINE_SPINLOCK(nano_lock);
 
@@ -122,7 +123,8 @@ static struct pci_ops pci_nano_ops = {
        .write  = nanoengine_write_config,
 };
 
-static int __init pci_nanoengine_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init pci_nanoengine_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        return NANOENGINE_IRQ_GPIO_PCI;
 }
index 92d7227..7cb79a0 100644 (file)
@@ -14,7 +14,7 @@
 #include <asm/mach/pci.h>
 #include <asm/mach-types.h>
 
-static int __init shark_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init shark_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        if (dev->bus->number == 0)
                if (dev->devfn == 0)
index 837138e..9e0856b 100644 (file)
@@ -957,19 +957,16 @@ static struct resource csi2_resources[] = {
        },
 };
 
-static struct platform_device csi2_device = {
-       .name   = "sh-mobile-csi2",
-       .id     = 0,
+static struct sh_mobile_ceu_companion csi2 = {
+       .id             = 0,
        .num_resources  = ARRAY_SIZE(csi2_resources),
        .resource       = csi2_resources,
-       .dev    = {
-               .platform_data = &csi2_info,
-       },
+       .platform_data  = &csi2_info,
 };
 
 static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
        .flags = SH_CEU_FLAG_USE_8BIT_BUS,
-       .csi2_dev = &csi2_device.dev,
+       .csi2 = &csi2,
 };
 
 static struct resource ceu_resources[] = {
@@ -1013,7 +1010,6 @@ static struct platform_device *ap4evb_devices[] __initdata = {
        &lcdc1_device,
        &lcdc_device,
        &hdmi_device,
-       &csi2_device,
        &ceu_device,
        &ap4evb_camera,
        &meram_device,
index 5b36b6c..d41c01f 100644 (file)
@@ -1192,8 +1192,8 @@ static struct platform_device sh_mmcif_device = {
 };
 
 
-static int mackerel_camera_add(struct soc_camera_link *icl, struct device *dev);
-static void mackerel_camera_del(struct soc_camera_link *icl);
+static int mackerel_camera_add(struct soc_camera_device *icd);
+static void mackerel_camera_del(struct soc_camera_device *icd);
 
 static int camera_set_capture(struct soc_camera_platform_info *info,
                              int enable)
@@ -1232,16 +1232,15 @@ static void mackerel_camera_release(struct device *dev)
        soc_camera_platform_release(&camera_device);
 }
 
-static int mackerel_camera_add(struct soc_camera_link *icl,
-                              struct device *dev)
+static int mackerel_camera_add(struct soc_camera_device *icd)
 {
-       return soc_camera_platform_add(icl, dev, &camera_device, &camera_link,
+       return soc_camera_platform_add(icd, &camera_device, &camera_link,
                                       mackerel_camera_release, 0);
 }
 
-static void mackerel_camera_del(struct soc_camera_link *icl)
+static void mackerel_camera_del(struct soc_camera_device *icd)
 {
-       soc_camera_platform_del(icl, camera_device, &camera_link);
+       soc_camera_platform_del(icd, camera_device, &camera_link);
 }
 
 static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
index 6b186ae..5218c34 100644 (file)
@@ -259,9 +259,6 @@ static struct clk mstp_clks[MSTP_NR] = {
        [CMMSTP003] = MSTP(&r_clk, CMMSTPCR0, 3, 0), /* KEYSC */
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-#define CLKDEV_DEV_ID(_id, _clk) { .dev_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("r_clk", &r_clk),
index 91f5779..6b1619a 100644 (file)
@@ -561,10 +561,6 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP403] = MSTP(&r_clk, SMSTPCR4, 3, 0), /* KEYSC */
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-#define CLKDEV_DEV_ID(_id, _clk) { .dev_id = _id, .clk = _clk }
-#define CLKDEV_ICK_ID(_cid, _did, _clk) { .con_id = _cid, .dev_id = _did, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("dv_clki_div2_clk", &sh7372_dv_clki_div2_clk),
index 9594246..8cee7b1 100644 (file)
@@ -267,9 +267,6 @@ static struct clk mstp_clks[] = {
        [MSTP403] = MSTP(&r_clk, SMSTPCR4, 3, 0), /* KEYSC */
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-#define CLKDEV_DEV_ID(_id, _clk) { .dev_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("r_clk", &r_clk),
index bcacb1e..6db2cca 100644 (file)
@@ -306,10 +306,6 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP403] = MSTP(&r_clk, SMSTPCR4, 3, 0), /* KEYSC */
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-#define CLKDEV_DEV_ID(_id, _clk) { .dev_id = _id, .clk = _clk }
-#define CLKDEV_ICK_ID(_cid, _did, _clk) { .con_id = _cid, .dev_id = _did, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("r_clk", &r_clk),
index 5ec1846..d82ebab 100644 (file)
@@ -27,14 +27,14 @@ comment "Tegra board type"
 
 config MACH_HARMONY
        bool "Harmony board"
-       select MACH_HAS_SND_SOC_TEGRA_WM8903
+       select MACH_HAS_SND_SOC_TEGRA_WM8903 if SND_SOC
        help
          Support for nVidia Harmony development platform
 
 config MACH_KAEN
        bool "Kaen board"
        select MACH_SEABOARD
-       select MACH_HAS_SND_SOC_TEGRA_WM8903
+       select MACH_HAS_SND_SOC_TEGRA_WM8903 if SND_SOC
        help
          Support for the Kaen version of Seaboard
 
@@ -45,12 +45,18 @@ config MACH_PAZ00
 
 config MACH_SEABOARD
        bool "Seaboard board"
-       select MACH_HAS_SND_SOC_TEGRA_WM8903
+       select MACH_HAS_SND_SOC_TEGRA_WM8903 if SND_SOC
        help
          Support for nVidia Seaboard development platform. It will
         also be included for some of the derivative boards that
         have large similarities with the seaboard design.
 
+config MACH_TEGRA_DT
+       bool "Generic Tegra board (FDT support)"
+       select USE_OF
+       help
+         Support for generic nVidia Tegra boards using Flattened Device Tree
+
 config MACH_TRIMSLICE
        bool "TrimSlice board"
        select TEGRA_PCI
index ed58ef9..f11b910 100644 (file)
@@ -29,5 +29,8 @@ obj-${CONFIG_MACH_PAZ00}              += board-paz00-pinmux.o
 obj-${CONFIG_MACH_SEABOARD}             += board-seaboard.o
 obj-${CONFIG_MACH_SEABOARD}             += board-seaboard-pinmux.o
 
+obj-${CONFIG_MACH_TEGRA_DT}             += board-dt.o
+obj-${CONFIG_MACH_TEGRA_DT}             += board-harmony-pinmux.o
+
 obj-${CONFIG_MACH_TRIMSLICE}            += board-trimslice.o
 obj-${CONFIG_MACH_TRIMSLICE}            += board-trimslice-pinmux.o
index db52d61..428ad12 100644 (file)
@@ -1,3 +1,6 @@
 zreladdr-$(CONFIG_ARCH_TEGRA_2x_SOC)   := 0x00008000
 params_phys-$(CONFIG_ARCH_TEGRA_2x_SOC)        := 0x00000100
 initrd_phys-$(CONFIG_ARCH_TEGRA_2x_SOC)        := 0x00800000
+
+dtb-$(CONFIG_MACH_HARMONY) += tegra-harmony.dtb
+dtb-$(CONFIG_MACH_SEABOARD) += tegra-seaboard.dtb
diff --git a/arch/arm/mach-tegra/board-dt.c b/arch/arm/mach-tegra/board-dt.c
new file mode 100644 (file)
index 0000000..9f47e04
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * nVidia Tegra device tree board support
+ *
+ * Copyright (C) 2010 Secret Lab Technologies, Ltd.
+ * Copyright (C) 2010 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/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_fdt.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/pda_power.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/i2c-tegra.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/setup.h>
+
+#include <mach/iomap.h>
+#include <mach/irqs.h>
+
+#include "board.h"
+#include "board-harmony.h"
+#include "clock.h"
+#include "devices.h"
+
+void harmony_pinmux_init(void);
+void seaboard_pinmux_init(void);
+
+
+struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
+       OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC1_BASE, "sdhci-tegra.0", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC2_BASE, "sdhci-tegra.1", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC3_BASE, "sdhci-tegra.2", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC4_BASE, "sdhci-tegra.3", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C_BASE, "tegra-i2c.0", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C2_BASE, "tegra-i2c.1", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C3_BASE, "tegra-i2c.2", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_DVC_BASE, "tegra-i2c.3", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra-i2s.0", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra-i2s.1", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-das", TEGRA_APB_MISC_DAS_BASE, "tegra-das", NULL),
+       {}
+};
+
+static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = {
+       /* name         parent          rate            enabled */
+       { "uartd",      "pll_p",        216000000,      true },
+       { NULL,         NULL,           0,              0},
+};
+
+static struct of_device_id tegra_dt_match_table[] __initdata = {
+       { .compatible = "simple-bus", },
+       {}
+};
+
+static struct of_device_id tegra_dt_gic_match[] __initdata = {
+       { .compatible = "nvidia,tegra20-gic", },
+       {}
+};
+
+static void __init tegra_dt_init(void)
+{
+       struct device_node *node;
+
+       node = of_find_matching_node_by_address(NULL, tegra_dt_gic_match,
+                                               TEGRA_ARM_INT_DIST_BASE);
+       if (node)
+               irq_domain_add_simple(node, INT_GIC_BASE);
+
+       tegra_clk_init_from_table(tegra_dt_clk_init_table);
+
+       if (of_machine_is_compatible("nvidia,harmony"))
+               harmony_pinmux_init();
+       else if (of_machine_is_compatible("nvidia,seaboard"))
+               seaboard_pinmux_init();
+
+       /*
+        * Finished with the static registrations now; fill in the missing
+        * devices
+        */
+       of_platform_populate(NULL, tegra_dt_match_table, tegra20_auxdata_lookup, NULL);
+}
+
+static const char * tegra_dt_board_compat[] = {
+       "nvidia,harmony",
+       "nvidia,seaboard",
+       NULL
+};
+
+DT_MACHINE_START(TEGRA_DT, "nVidia Tegra (Flattened Device Tree)")
+       .map_io         = tegra_map_common_io,
+       .init_early     = tegra_init_early,
+       .init_irq       = tegra_init_irq,
+       .timer          = &tegra_timer,
+       .init_machine   = tegra_dt_init,
+       .dt_compat      = tegra_dt_board_compat,
+MACHINE_END
index 031cd0a..f1f699d 100644 (file)
@@ -449,7 +449,7 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
        return 1;
 }
 
-static int tegra_pcie_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int tegra_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        return INT_PCIE_INTR;
 }
index 9cdec5a..c1f38f6 100644 (file)
@@ -17,4 +17,12 @@ config MACH_VERSATILE_AB
          Include support for the ARM(R) Versatile Application Baseboard
          for the ARM926EJ-S.
 
+config MACH_VERSATILE_DT
+       bool "Support Versatile platform from device tree"
+       select USE_OF
+       select CPU_ARM926T
+       help
+         Include support for the ARM(R) Versatile/PB platform,
+         using the device tree for discovery
+
 endmenu
index 97cf4d8..81fa3fe 100644 (file)
@@ -5,4 +5,5 @@
 obj-y                                  := core.o
 obj-$(CONFIG_ARCH_VERSATILE_PB)                += versatile_pb.o
 obj-$(CONFIG_MACH_VERSATILE_AB)                += versatile_ab.o
+obj-$(CONFIG_MACH_VERSATILE_DT)                += versatile_dt.o
 obj-$(CONFIG_PCI)                      += pci.o
index 0c99cf0..e340a54 100644 (file)
@@ -24,6 +24,9 @@
 #include <linux/platform_device.h>
 #include <linux/sysdev.h>
 #include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
 #include <linux/amba/bus.h>
 #include <linux/amba/clcd.h>
 #include <linux/amba/pl061.h>
@@ -83,13 +86,26 @@ static struct fpga_irq_data sic_irq = {
 #define PIC_MASK       0
 #endif
 
+/* Lookup table for finding a DT node that represents the vic instance */
+static const struct of_device_id vic_of_match[] __initconst = {
+       { .compatible = "arm,versatile-vic", },
+       {}
+};
+
+static const struct of_device_id sic_of_match[] __initconst = {
+       { .compatible = "arm,versatile-sic", },
+       {}
+};
+
 void __init versatile_init_irq(void)
 {
        vic_init(VA_VIC_BASE, IRQ_VIC_START, ~0, 0);
+       irq_domain_generate_simple(vic_of_match, VERSATILE_VIC_BASE, IRQ_VIC_START);
 
        writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
 
        fpga_irq_init(IRQ_VICSOURCE31, ~PIC_MASK, &sic_irq);
+       irq_domain_generate_simple(sic_of_match, VERSATILE_SIC_BASE, IRQ_SIC_START);
 
        /*
         * Interrupts on secondary controller from 0 to 8 are routed to
@@ -646,6 +662,52 @@ static struct amba_device *amba_devs[] __initdata = {
        &kmi1_device,
 };
 
+#ifdef CONFIG_OF
+/*
+ * Lookup table for attaching a specific name and platform_data pointer to
+ * devices as they get created by of_platform_populate().  Ideally this table
+ * would not exist, but the current clock implementation depends on some devices
+ * having a specific name.
+ */
+struct of_dev_auxdata versatile_auxdata_lookup[] __initdata = {
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_MMCI0_BASE, "fpga:05", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_KMI0_BASE, "fpga:06", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_KMI1_BASE, "fpga:07", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_UART3_BASE, "fpga:09", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_MMCI1_BASE, "fpga:0b", NULL),
+
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_CLCD_BASE, "dev:20", &clcd_plat_data),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_UART0_BASE, "dev:f1", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_UART1_BASE, "dev:f2", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_UART2_BASE, "dev:f3", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_SSP_BASE, "dev:f4", NULL),
+
+#if 0
+       /*
+        * These entries are unnecessary because no clocks referencing
+        * them.  I've left them in for now as place holders in case
+        * any of them need to be added back, but they should be
+        * removed before actually committing this patch.  --gcl
+        */
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_AACI_BASE, "fpga:04", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_SCI1_BASE, "fpga:0a", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_SMC_BASE, "dev:00", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_MPMC_BASE, "dev:10", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_DMAC_BASE, "dev:30", NULL),
+
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_SCTL_BASE, "dev:e0", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_WATCHDOG_BASE, "dev:e1", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_GPIO0_BASE, "dev:e4", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_GPIO1_BASE, "dev:e5", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_GPIO2_BASE, "dev:e6", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_GPIO3_BASE, "dev:e7", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_RTC_BASE, "dev:e8", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_SCI_BASE, "dev:f0", NULL),
+#endif
+       {}
+};
+#endif
+
 #ifdef CONFIG_LEDS
 #define VA_LEDS_BASE (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_LED_OFFSET)
 
index fd6404e..e014227 100644 (file)
@@ -23,6 +23,7 @@
 #define __ASM_ARCH_VERSATILE_H
 
 #include <linux/amba/bus.h>
+#include <linux/of_platform.h>
 
 extern void __init versatile_init(void);
 extern void __init versatile_init_early(void);
@@ -30,6 +31,9 @@ extern void __init versatile_init_irq(void);
 extern void __init versatile_map_io(void);
 extern struct sys_timer versatile_timer;
 extern unsigned int mmc_status(struct device *dev);
+#ifdef CONFIG_OF
+extern struct of_dev_auxdata versatile_auxdata_lookup[];
+#endif
 
 #define AMBA_DEVICE(name,busid,base,plat)                      \
 static struct amba_device name##_device = {                    \
index 7848a17..c898deb 100644 (file)
@@ -328,7 +328,7 @@ void __init pci_versatile_preinit(void)
 /*
  * map the specified device/slot/pin to an IRQ.   Different backplanes may need to modify this.
  */
-static int __init versatile_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init versatile_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
        int devslot = PCI_SLOT(dev->devfn);
diff --git a/arch/arm/mach-versatile/versatile_dt.c b/arch/arm/mach-versatile/versatile_dt.c
new file mode 100644 (file)
index 0000000..54e037c
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Versatile board support using the device tree
+ *
+ *  Copyright (C) 2010 Secret Lab Technologies Ltd.
+ *  Copyright (C) 2009 Jeremy Kerr <jeremy.kerr@canonical.com>
+ *  Copyright (C) 2004 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/init.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include "core.h"
+
+static void __init versatile_dt_init(void)
+{
+       of_platform_populate(NULL, of_default_bus_match_table,
+                            versatile_auxdata_lookup, NULL);
+}
+
+static const char *versatile_dt_match[] __initconst = {
+       "arm,versatile-ab",
+       "arm,versatile-pb",
+       NULL,
+};
+
+DT_MACHINE_START(VERSATILE_PB, "ARM-Versatile (Device Tree Support)")
+       .map_io         = versatile_map_io,
+       .init_early     = versatile_init_early,
+       .init_irq       = versatile_init_irq,
+       .timer          = &versatile_timer,
+       .init_machine   = versatile_dt_init,
+       .dt_compat      = versatile_dt_match,
+MACHINE_END
index c550c67..397268c 100644 (file)
@@ -3,4 +3,4 @@
 #
 
 # Common support
-obj-y                          := common.o timer.o board_dt.o
+obj-y                          := common.o timer.o
diff --git a/arch/arm/mach-zynq/board_dt.c b/arch/arm/mach-zynq/board_dt.c
deleted file mode 100644 (file)
index e69de29..0000000
index be7c638..cfbcf8b 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/sched.h>
 #include <linux/uaccess.h>
 
+#include <asm/system.h>
 #include <asm/unaligned.h>
 
 #include "fault.h"
@@ -95,6 +96,33 @@ static const char *usermode_action[] = {
        "signal+warn"
 };
 
+/* Return true if and only if the ARMv6 unaligned access model is in use. */
+static bool cpu_is_v6_unaligned(void)
+{
+       return cpu_architecture() >= CPU_ARCH_ARMv6 && (cr_alignment & CR_U);
+}
+
+static int safe_usermode(int new_usermode, bool warn)
+{
+       /*
+        * ARMv6 and later CPUs can perform unaligned accesses for
+        * most single load and store instructions up to word size.
+        * LDM, STM, LDRD and STRD still need to be handled.
+        *
+        * Ignoring the alignment fault is not an option on these
+        * CPUs since we spin re-faulting the instruction without
+        * making any progress.
+        */
+       if (cpu_is_v6_unaligned() && !(new_usermode & (UM_FIXUP | UM_SIGNAL))) {
+               new_usermode |= UM_FIXUP;
+
+               if (warn)
+                       printk(KERN_WARNING "alignment: ignoring faults is unsafe on this CPU.  Defaulting to fixup mode.\n");
+       }
+
+       return new_usermode;
+}
+
 static int alignment_proc_show(struct seq_file *m, void *v)
 {
        seq_printf(m, "User:\t\t%lu\n", ai_user);
@@ -125,7 +153,7 @@ static ssize_t alignment_proc_write(struct file *file, const char __user *buffer
                if (get_user(mode, buffer))
                        return -EFAULT;
                if (mode >= '0' && mode <= '5')
-                       ai_usermode = mode - '0';
+                       ai_usermode = safe_usermode(mode - '0', true);
        }
        return count;
 }
@@ -886,9 +914,16 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
        if (ai_usermode & UM_FIXUP)
                goto fixup;
 
-       if (ai_usermode & UM_SIGNAL)
-               force_sig(SIGBUS, current);
-       else {
+       if (ai_usermode & UM_SIGNAL) {
+               siginfo_t si;
+
+               si.si_signo = SIGBUS;
+               si.si_errno = 0;
+               si.si_code = BUS_ADRALN;
+               si.si_addr = (void __user *)addr;
+
+               force_sig_info(si.si_signo, &si, current);
+       } else {
                /*
                 * We're about to disable the alignment trap and return to
                 * user space.  But if an interrupt occurs before actually
@@ -926,20 +961,11 @@ static int __init alignment_init(void)
                return -ENOMEM;
 #endif
 
-       /*
-        * ARMv6 and later CPUs can perform unaligned accesses for
-        * most single load and store instructions up to word size.
-        * LDM, STM, LDRD and STRD still need to be handled.
-        *
-        * Ignoring the alignment fault is not an option on these
-        * CPUs since we spin re-faulting the instruction without
-        * making any progress.
-        */
-       if (cpu_architecture() >= CPU_ARCH_ARMv6 && (cr_alignment & CR_U)) {
+       if (cpu_is_v6_unaligned()) {
                cr_alignment &= ~CR_A;
                cr_no_alignment &= ~CR_A;
                set_cr(cr_alignment);
-               ai_usermode = UM_FIXUP;
+               ai_usermode = safe_usermode(ai_usermode, false);
        }
 
        hook_fault_code(1, do_alignment, SIGBUS, BUS_ADRALN,
index 2fee782..91bca35 100644 (file)
@@ -441,7 +441,7 @@ static inline int free_area(unsigned long pfn, unsigned long end, char *s)
 static inline void poison_init_mem(void *s, size_t count)
 {
        u32 *p = (u32 *)s;
-       while ((count = count - 4))
+       for (; count != 0; count -= 4)
                *p++ = 0xe7fddef0;
 }
 
index f8f7ea3..683af3a 100644 (file)
@@ -410,6 +410,7 @@ __arm946_proc_info:
        .long   0x41009460
        .long   0xff00fff0
        .long   0
+       .long   0
        b       __arm946_setup
        .long   cpu_arch_name
        .long   cpu_elf_name
@@ -418,6 +419,6 @@ __arm946_proc_info:
        .long   arm946_processor_functions
        .long   0
        .long   0
-       .long   arm940_cache_fns
+       .long   arm946_cache_fns
        .size   __arm946_proc_info, . - __arm946_proc_info
 
index 4fc6ffc..0bae44e 100644 (file)
 #include <mach/hardware.h>
 #include <mach/devices-common.h>
 
-#define imx_fec_data_entry_single(soc)                                 \
+#define imx_fec_data_entry_single(soc, _devid)                         \
        {                                                               \
+               .devid = _devid,                                        \
                .iobase = soc ## _FEC_BASE_ADDR,                        \
                .irq = soc ## _INT_FEC,                                 \
        }
 
 #ifdef CONFIG_SOC_IMX25
 const struct imx_fec_data imx25_fec_data __initconst =
-       imx_fec_data_entry_single(MX25);
+       imx_fec_data_entry_single(MX25, "imx25-fec");
 #endif /* ifdef CONFIG_SOC_IMX25 */
 
 #ifdef CONFIG_SOC_IMX27
 const struct imx_fec_data imx27_fec_data __initconst =
-       imx_fec_data_entry_single(MX27);
+       imx_fec_data_entry_single(MX27, "imx27-fec");
 #endif /* ifdef CONFIG_SOC_IMX27 */
 
 #ifdef CONFIG_SOC_IMX35
+/* i.mx35 has the i.mx27 type fec */
 const struct imx_fec_data imx35_fec_data __initconst =
-       imx_fec_data_entry_single(MX35);
+       imx_fec_data_entry_single(MX35, "imx27-fec");
 #endif
 
 #ifdef CONFIG_SOC_IMX50
+/* i.mx50 has the i.mx25 type fec */
 const struct imx_fec_data imx50_fec_data __initconst =
-       imx_fec_data_entry_single(MX50);
+       imx_fec_data_entry_single(MX50, "imx25-fec");
 #endif
 
 #ifdef CONFIG_SOC_IMX51
+/* i.mx51 has the i.mx27 type fec */
 const struct imx_fec_data imx51_fec_data __initconst =
-       imx_fec_data_entry_single(MX51);
+       imx_fec_data_entry_single(MX51, "imx27-fec");
 #endif
 
 #ifdef CONFIG_SOC_IMX53
+/* i.mx53 has the i.mx25 type fec */
 const struct imx_fec_data imx53_fec_data __initconst =
-       imx_fec_data_entry_single(MX53);
+       imx_fec_data_entry_single(MX53, "imx25-fec");
 #endif
 
 struct platform_device *__init imx_add_fec(
@@ -63,7 +68,7 @@ struct platform_device *__init imx_add_fec(
                },
        };
 
-       return imx_add_platform_device_dmamask("fec", 0,
+       return imx_add_platform_device_dmamask(data->devid, 0,
                        res, ARRAY_SIZE(res),
                        pdata, sizeof(*pdata), DMA_BIT_MASK(32));
 }
index 2b0fdb2..7fa7e9c 100644 (file)
@@ -14,7 +14,7 @@ struct platform_device __init __maybe_unused *imx_add_imx_dma(void)
                        "imx-dma", -1, NULL, 0, NULL, 0);
 }
 
-struct platform_device __init __maybe_unused *imx_add_imx_sdma(
+struct platform_device __init __maybe_unused *imx_add_imx_sdma(char *name,
        resource_size_t iobase, int irq, struct sdma_platform_data *pdata)
 {
        struct resource res[] = {
@@ -29,6 +29,6 @@ struct platform_device __init __maybe_unused *imx_add_imx_sdma(
                },
        };
 
-       return platform_device_register_resndata(&mxc_ahb_bus, "imx-sdma",
+       return platform_device_register_resndata(&mxc_ahb_bus, name,
                        -1, res, ARRAY_SIZE(res), pdata, sizeof(*pdata));
 }
index cfce8c9..2020d84 100644 (file)
@@ -152,7 +152,7 @@ struct platform_device *__init imx_add_imx_uart_3irq(
                },
        };
 
-       return imx_add_platform_device("imx-uart", data->id, res,
+       return imx_add_platform_device("imx1-uart", data->id, res,
                        ARRAY_SIZE(res), pdata, sizeof(*pdata));
 }
 
@@ -172,6 +172,7 @@ struct platform_device *__init imx_add_imx_uart_1irq(
                },
        };
 
-       return imx_add_platform_device("imx-uart", data->id, res, ARRAY_SIZE(res),
-                       pdata, sizeof(*pdata));
+       /* i.mx21 type uart runs on all i.mx except i.mx1 */
+       return imx_add_platform_device("imx21-uart", data->id,
+                       res, ARRAY_SIZE(res), pdata, sizeof(*pdata));
 }
index 6b2940b..5955f5d 100644 (file)
 #include <mach/devices-common.h>
 #include <mach/esdhc.h>
 
-#define imx_sdhci_esdhc_imx_data_entry_single(soc, _id, hwid) \
+#define imx_sdhci_esdhc_imx_data_entry_single(soc, _devid, _id, hwid) \
        {                                                               \
+               .devid = _devid,                                        \
                .id = _id,                                              \
                .iobase = soc ## _ESDHC ## hwid ## _BASE_ADDR,  \
                .irq = soc ## _INT_ESDHC ## hwid,                       \
        }
 
-#define imx_sdhci_esdhc_imx_data_entry(soc, id, hwid)  \
-       [id] = imx_sdhci_esdhc_imx_data_entry_single(soc, id, hwid)
+#define imx_sdhci_esdhc_imx_data_entry(soc, devid, id, hwid)   \
+       [id] = imx_sdhci_esdhc_imx_data_entry_single(soc, devid, id, hwid)
 
 #ifdef CONFIG_SOC_IMX25
 const struct imx_sdhci_esdhc_imx_data
 imx25_sdhci_esdhc_imx_data[] __initconst = {
 #define imx25_sdhci_esdhc_imx_data_entry(_id, _hwid)                   \
-       imx_sdhci_esdhc_imx_data_entry(MX25, _id, _hwid)
+       imx_sdhci_esdhc_imx_data_entry(MX25, "sdhci-esdhc-imx25", _id, _hwid)
        imx25_sdhci_esdhc_imx_data_entry(0, 1),
        imx25_sdhci_esdhc_imx_data_entry(1, 2),
 };
@@ -34,7 +35,7 @@ imx25_sdhci_esdhc_imx_data[] __initconst = {
 const struct imx_sdhci_esdhc_imx_data
 imx35_sdhci_esdhc_imx_data[] __initconst = {
 #define imx35_sdhci_esdhc_imx_data_entry(_id, _hwid)                   \
-       imx_sdhci_esdhc_imx_data_entry(MX35, _id, _hwid)
+       imx_sdhci_esdhc_imx_data_entry(MX35, "sdhci-esdhc-imx35", _id, _hwid)
        imx35_sdhci_esdhc_imx_data_entry(0, 1),
        imx35_sdhci_esdhc_imx_data_entry(1, 2),
        imx35_sdhci_esdhc_imx_data_entry(2, 3),
@@ -45,7 +46,7 @@ imx35_sdhci_esdhc_imx_data[] __initconst = {
 const struct imx_sdhci_esdhc_imx_data
 imx51_sdhci_esdhc_imx_data[] __initconst = {
 #define imx51_sdhci_esdhc_imx_data_entry(_id, _hwid)                   \
-       imx_sdhci_esdhc_imx_data_entry(MX51, _id, _hwid)
+       imx_sdhci_esdhc_imx_data_entry(MX51, "sdhci-esdhc-imx51", _id, _hwid)
        imx51_sdhci_esdhc_imx_data_entry(0, 1),
        imx51_sdhci_esdhc_imx_data_entry(1, 2),
        imx51_sdhci_esdhc_imx_data_entry(2, 3),
@@ -57,7 +58,7 @@ imx51_sdhci_esdhc_imx_data[] __initconst = {
 const struct imx_sdhci_esdhc_imx_data
 imx53_sdhci_esdhc_imx_data[] __initconst = {
 #define imx53_sdhci_esdhc_imx_data_entry(_id, _hwid)                   \
-       imx_sdhci_esdhc_imx_data_entry(MX53, _id, _hwid)
+       imx_sdhci_esdhc_imx_data_entry(MX53, "sdhci-esdhc-imx53", _id, _hwid)
        imx53_sdhci_esdhc_imx_data_entry(0, 1),
        imx53_sdhci_esdhc_imx_data_entry(1, 2),
        imx53_sdhci_esdhc_imx_data_entry(2, 3),
@@ -65,6 +66,11 @@ imx53_sdhci_esdhc_imx_data[] __initconst = {
 };
 #endif /* ifdef CONFIG_SOC_IMX53 */
 
+static const struct esdhc_platform_data default_esdhc_pdata __initconst = {
+       .wp_type = ESDHC_WP_NONE,
+       .cd_type = ESDHC_CD_NONE,
+};
+
 struct platform_device *__init imx_add_sdhci_esdhc_imx(
                const struct imx_sdhci_esdhc_imx_data *data,
                const struct esdhc_platform_data *pdata)
@@ -81,6 +87,13 @@ struct platform_device *__init imx_add_sdhci_esdhc_imx(
                },
        };
 
-       return imx_add_platform_device("sdhci-esdhc-imx", data->id, res,
+       /*
+        * If machine does not provide pdata, use the default one
+        * which means no WP/CD support
+        */
+       if (!pdata)
+               pdata = &default_esdhc_pdata;
+
+       return imx_add_platform_device(data->devid, data->id, res,
                        ARRAY_SIZE(res), pdata, sizeof(*pdata));
 }
index 91fc7cd..e4dde91 100644 (file)
 #define UART_PADDR     MX51_UART1_BASE_ADDR
 #endif
 
+/* iMX50/53 have same addresses, but not iMX51 */
+#if defined(CONFIG_SOC_IMX50) || defined(CONFIG_SOC_IMX53)
+#ifdef UART_PADDR
+#error "CONFIG_DEBUG_LL is incompatible with multiple archs"
+#endif
+#define UART_PADDR     MX53_UART1_BASE_ADDR
+#endif
+
 #define UART_VADDR     IMX_IO_ADDRESS(UART_PADDR)
 
                .macro  addruart, rp, rv
index bf93820..524538a 100644 (file)
@@ -30,6 +30,7 @@ static inline struct platform_device *imx_add_platform_device(
 
 #include <linux/fec.h>
 struct imx_fec_data {
+       const char *devid;
        resource_size_t iobase;
        resource_size_t irq;
 };
@@ -276,6 +277,7 @@ struct platform_device *__init imx_add_mxc_w1(
 
 #include <mach/esdhc.h>
 struct imx_sdhci_esdhc_imx_data {
+       const char *devid;
        int id;
        resource_size_t iobase;
        resource_size_t irq;
@@ -297,5 +299,5 @@ struct platform_device *__init imx_add_spi_imx(
                const struct spi_imx_master *pdata);
 
 struct platform_device *imx_add_imx_dma(void);
-struct platform_device *imx_add_imx_sdma(
+struct platform_device *imx_add_imx_sdma(char *name,
        resource_size_t iobase, int irq, struct sdma_platform_data *pdata);
index ef77515..233d0a5 100644 (file)
@@ -60,7 +60,8 @@ static inline int imx_dma_is_ipu(struct dma_chan *chan)
 
 static inline int imx_dma_is_general_purpose(struct dma_chan *chan)
 {
-       return !strcmp(dev_name(chan->device->dev), "imx-sdma") ||
+       return !strcmp(dev_name(chan->device->dev), "imx31-sdma") ||
+               !strcmp(dev_name(chan->device->dev), "imx35-sdma") ||
                !strcmp(dev_name(chan->device->dev), "imx-dma");
 }
 
index 86003f4..aaf9748 100644 (file)
 #ifndef __ASM_ARCH_IMX_ESDHC_H
 #define __ASM_ARCH_IMX_ESDHC_H
 
+enum wp_types {
+       ESDHC_WP_NONE,          /* no WP, neither controller nor gpio */
+       ESDHC_WP_CONTROLLER,    /* mmc controller internal WP */
+       ESDHC_WP_GPIO,          /* external gpio pin for WP */
+};
+
+enum cd_types {
+       ESDHC_CD_NONE,          /* no CD, neither controller nor gpio */
+       ESDHC_CD_CONTROLLER,    /* mmc controller internal CD */
+       ESDHC_CD_GPIO,          /* external gpio pin for CD */
+       ESDHC_CD_PERMANENT,     /* no CD, card permanently wired to host */
+};
+
 /**
- * struct esdhc_platform_data - optional platform data for esdhc on i.MX
+ * struct esdhc_platform_data - platform data for esdhc on i.MX
  *
- * strongly recommended for i.MX25/35, not needed for other variants
+ * ESDHC_WP(CD)_CONTROLLER type is not available on i.MX25/35.
  *
- * @wp_gpio:   gpio for write_protect (-EINVAL if unused)
- * @cd_gpio:   gpio for card_detect interrupt (-EINVAL if unused)
+ * @wp_gpio:   gpio for write_protect
+ * @cd_gpio:   gpio for card_detect interrupt
+ * @wp_type:   type of write_protect method (see wp_types enum above)
+ * @cd_type:   type of card_detect method (see cd_types enum above)
  */
 
 struct esdhc_platform_data {
        unsigned int wp_gpio;
        unsigned int cd_gpio;
+       enum wp_types wp_type;
+       enum cd_types cd_type;
 };
 #endif /* __ASM_ARCH_IMX_ESDHC_H */
index 9440b9e..5408fd1 100644 (file)
@@ -30,6 +30,9 @@
 #define MX53_SDHC_PAD_CTRL     (PAD_CTL_HYS | PAD_CTL_PKE | PAD_CTL_PUE | \
                                PAD_CTL_PUS_47K_UP | PAD_CTL_DSE_HIGH | \
                                PAD_CTL_SRE_FAST)
+#define PAD_CTRL_I2C   (PAD_CTL_SRE_FAST | PAD_CTL_ODE | PAD_CTL_PKE | \
+                       PAD_CTL_PUE | PAD_CTL_DSE_HIGH | PAD_CTL_PUS_100K_UP \
+                       | PAD_CTL_HYS)
 
 #define _MX53_PAD_GPIO_19__KPP_COL_5           IOMUX_PAD(0x348, 0x20, 0, 0x840, 0, 0)
 #define _MX53_PAD_GPIO_19__GPIO4_5             IOMUX_PAD(0x348, 0x20, 1, 0x0, 0, 0)
 #define MX53_PAD_KEY_COL3__GPIO4_12            (_MX53_PAD_KEY_COL3__GPIO4_12 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_KEY_COL3__USBOH3_H2_DP                (_MX53_PAD_KEY_COL3__USBOH3_H2_DP | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_KEY_COL3__SPDIF_IN1           (_MX53_PAD_KEY_COL3__SPDIF_IN1 | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_KEY_COL3__I2C2_SCL            (_MX53_PAD_KEY_COL3__I2C2_SCL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL3__I2C2_SCL            (_MX53_PAD_KEY_COL3__I2C2_SCL | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_KEY_COL3__ECSPI1_SS3          (_MX53_PAD_KEY_COL3__ECSPI1_SS3 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_KEY_COL3__FEC_CRS             (_MX53_PAD_KEY_COL3__FEC_CRS | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_KEY_COL3__USBPHY1_SIECLOCK            (_MX53_PAD_KEY_COL3__USBPHY1_SIECLOCK | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_KEY_ROW3__GPIO4_13            (_MX53_PAD_KEY_ROW3__GPIO4_13 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_KEY_ROW3__USBOH3_H2_DM                (_MX53_PAD_KEY_ROW3__USBOH3_H2_DM | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_KEY_ROW3__CCM_ASRC_EXT_CLK            (_MX53_PAD_KEY_ROW3__CCM_ASRC_EXT_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_KEY_ROW3__I2C2_SDA            (_MX53_PAD_KEY_ROW3__I2C2_SDA | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW3__I2C2_SDA            (_MX53_PAD_KEY_ROW3__I2C2_SDA | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_KEY_ROW3__OSC32K_32K_OUT              (_MX53_PAD_KEY_ROW3__OSC32K_32K_OUT | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_KEY_ROW3__CCM_PLL4_BYP                (_MX53_PAD_KEY_ROW3__CCM_PLL4_BYP | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_KEY_ROW3__USBPHY1_LINESTATE_0         (_MX53_PAD_KEY_ROW3__USBPHY1_LINESTATE_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_CSI0_DAT8__KPP_COL_7          (_MX53_PAD_CSI0_DAT8__KPP_COL_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_CSI0_DAT8__ECSPI2_SCLK                (_MX53_PAD_CSI0_DAT8__ECSPI2_SCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_CSI0_DAT8__USBOH3_USBH3_OC            (_MX53_PAD_CSI0_DAT8__USBOH3_USBH3_OC | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_CSI0_DAT8__I2C1_SDA           (_MX53_PAD_CSI0_DAT8__I2C1_SDA | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT8__I2C1_SDA           (_MX53_PAD_CSI0_DAT8__I2C1_SDA | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_CSI0_DAT8__EMI_EMI_DEBUG_37           (_MX53_PAD_CSI0_DAT8__EMI_EMI_DEBUG_37 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_CSI0_DAT8__TPIU_TRACE_5               (_MX53_PAD_CSI0_DAT8__TPIU_TRACE_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_CSI0_DAT9__IPU_CSI0_D_9               (_MX53_PAD_CSI0_DAT9__IPU_CSI0_D_9 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_CSI0_DAT9__KPP_ROW_7          (_MX53_PAD_CSI0_DAT9__KPP_ROW_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_CSI0_DAT9__ECSPI2_MOSI                (_MX53_PAD_CSI0_DAT9__ECSPI2_MOSI | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_CSI0_DAT9__USBOH3_USBH3_PWR           (_MX53_PAD_CSI0_DAT9__USBOH3_USBH3_PWR | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_CSI0_DAT9__I2C1_SCL           (_MX53_PAD_CSI0_DAT9__I2C1_SCL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT9__I2C1_SCL           (_MX53_PAD_CSI0_DAT9__I2C1_SCL | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_CSI0_DAT9__EMI_EMI_DEBUG_38           (_MX53_PAD_CSI0_DAT9__EMI_EMI_DEBUG_38 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_CSI0_DAT9__TPIU_TRACE_6               (_MX53_PAD_CSI0_DAT9__TPIU_TRACE_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_CSI0_DAT10__IPU_CSI0_D_10             (_MX53_PAD_CSI0_DAT10__IPU_CSI0_D_10 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_EB2__CCM_DI1_EXT_CLK              (_MX53_PAD_EIM_EB2__CCM_DI1_EXT_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_EB2__IPU_SER_DISP1_CS             (_MX53_PAD_EIM_EB2__IPU_SER_DISP1_CS | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_EB2__ECSPI1_SS0           (_MX53_PAD_EIM_EB2__ECSPI1_SS0 | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_EIM_EB2__I2C2_SCL             (_MX53_PAD_EIM_EB2__I2C2_SCL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_EB2__I2C2_SCL             (_MX53_PAD_EIM_EB2__I2C2_SCL | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_EIM_D16__EMI_WEIM_D_16                (_MX53_PAD_EIM_D16__EMI_WEIM_D_16 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D16__GPIO3_16             (_MX53_PAD_EIM_D16__GPIO3_16 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D16__IPU_DI0_PIN5         (_MX53_PAD_EIM_D16__IPU_DI0_PIN5 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D16__IPU_DISPB1_SER_CLK           (_MX53_PAD_EIM_D16__IPU_DISPB1_SER_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D16__ECSPI1_SCLK          (_MX53_PAD_EIM_D16__ECSPI1_SCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_EIM_D16__I2C2_SDA             (_MX53_PAD_EIM_D16__I2C2_SDA | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D16__I2C2_SDA             (_MX53_PAD_EIM_D16__I2C2_SDA | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_EIM_D17__EMI_WEIM_D_17                (_MX53_PAD_EIM_D17__EMI_WEIM_D_17 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D17__GPIO3_17             (_MX53_PAD_EIM_D17__GPIO3_17 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D17__IPU_DI0_PIN6         (_MX53_PAD_EIM_D17__IPU_DI0_PIN6 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D17__IPU_DISPB1_SER_DIN           (_MX53_PAD_EIM_D17__IPU_DISPB1_SER_DIN | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D17__ECSPI1_MISO          (_MX53_PAD_EIM_D17__ECSPI1_MISO | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_EIM_D17__I2C3_SCL             (_MX53_PAD_EIM_D17__I2C3_SCL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D17__I2C3_SCL             (_MX53_PAD_EIM_D17__I2C3_SCL | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_EIM_D18__EMI_WEIM_D_18                (_MX53_PAD_EIM_D18__EMI_WEIM_D_18 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D18__GPIO3_18             (_MX53_PAD_EIM_D18__GPIO3_18 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D18__IPU_DI0_PIN7         (_MX53_PAD_EIM_D18__IPU_DI0_PIN7 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D18__IPU_DISPB1_SER_DIO           (_MX53_PAD_EIM_D18__IPU_DISPB1_SER_DIO | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D18__ECSPI1_MOSI          (_MX53_PAD_EIM_D18__ECSPI1_MOSI | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_EIM_D18__I2C3_SDA             (_MX53_PAD_EIM_D18__I2C3_SDA | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D18__I2C3_SDA             (_MX53_PAD_EIM_D18__I2C3_SDA | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_EIM_D18__IPU_DI1_D0_CS                (_MX53_PAD_EIM_D18__IPU_DI1_D0_CS | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D19__EMI_WEIM_D_19                (_MX53_PAD_EIM_D19__EMI_WEIM_D_19 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D19__GPIO3_19             (_MX53_PAD_EIM_D19__GPIO3_19 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D21__IPU_DI0_PIN17                (_MX53_PAD_EIM_D21__IPU_DI0_PIN17 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D21__IPU_DISPB0_SER_CLK           (_MX53_PAD_EIM_D21__IPU_DISPB0_SER_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D21__CSPI_SCLK            (_MX53_PAD_EIM_D21__CSPI_SCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_EIM_D21__I2C1_SCL             (_MX53_PAD_EIM_D21__I2C1_SCL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D21__I2C1_SCL             (_MX53_PAD_EIM_D21__I2C1_SCL | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_EIM_D21__USBOH3_USBOTG_OC             (_MX53_PAD_EIM_D21__USBOH3_USBOTG_OC | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D22__EMI_WEIM_D_22                (_MX53_PAD_EIM_D22__EMI_WEIM_D_22 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D22__GPIO3_22             (_MX53_PAD_EIM_D22__GPIO3_22 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D28__UART2_CTS            (_MX53_PAD_EIM_D28__UART2_CTS | MUX_PAD_CTRL(MX53_UART_PAD_CTRL))
 #define MX53_PAD_EIM_D28__IPU_DISPB0_SER_DIO           (_MX53_PAD_EIM_D28__IPU_DISPB0_SER_DIO | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D28__CSPI_MOSI            (_MX53_PAD_EIM_D28__CSPI_MOSI | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_EIM_D28__I2C1_SDA             (_MX53_PAD_EIM_D28__I2C1_SDA | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D28__I2C1_SDA             (_MX53_PAD_EIM_D28__I2C1_SDA | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_EIM_D28__IPU_EXT_TRIG         (_MX53_PAD_EIM_D28__IPU_EXT_TRIG | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D28__IPU_DI0_PIN13                (_MX53_PAD_EIM_D28__IPU_DI0_PIN13 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D29__EMI_WEIM_D_29                (_MX53_PAD_EIM_D29__EMI_WEIM_D_29 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_9__SCC_FAIL_STATE                (_MX53_PAD_GPIO_9__SCC_FAIL_STATE | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_3__ESAI1_HCKR            (_MX53_PAD_GPIO_3__ESAI1_HCKR | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_3__GPIO1_3               (_MX53_PAD_GPIO_3__GPIO1_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_GPIO_3__I2C3_SCL              (_MX53_PAD_GPIO_3__I2C3_SCL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_3__I2C3_SCL              (_MX53_PAD_GPIO_3__I2C3_SCL | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_GPIO_3__DPLLIP1_TOG_EN                (_MX53_PAD_GPIO_3__DPLLIP1_TOG_EN | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_3__CCM_CLKO2             (_MX53_PAD_GPIO_3__CCM_CLKO2 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_3__OBSERVE_MUX_OBSRV_INT_OUT0            (_MX53_PAD_GPIO_3__OBSERVE_MUX_OBSRV_INT_OUT0 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_3__MLB_MLBCLK            (_MX53_PAD_GPIO_3__MLB_MLBCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_6__ESAI1_SCKT            (_MX53_PAD_GPIO_6__ESAI1_SCKT | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_6__GPIO1_6               (_MX53_PAD_GPIO_6__GPIO1_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_GPIO_6__I2C3_SDA              (_MX53_PAD_GPIO_6__I2C3_SDA | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_6__I2C3_SDA              (_MX53_PAD_GPIO_6__I2C3_SDA | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_GPIO_6__CCM_CCM_OUT_0         (_MX53_PAD_GPIO_6__CCM_CCM_OUT_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_6__CSU_CSU_INT_DEB               (_MX53_PAD_GPIO_6__CSU_CSU_INT_DEB | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_6__OBSERVE_MUX_OBSRV_INT_OUT1            (_MX53_PAD_GPIO_6__OBSERVE_MUX_OBSRV_INT_OUT1 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_5__CCM_CLKO              (_MX53_PAD_GPIO_5__CCM_CLKO | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_5__CSU_CSU_ALARM_AUT_2           (_MX53_PAD_GPIO_5__CSU_CSU_ALARM_AUT_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_5__OBSERVE_MUX_OBSRV_INT_OUT4            (_MX53_PAD_GPIO_5__OBSERVE_MUX_OBSRV_INT_OUT4 | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_GPIO_5__I2C3_SCL              (_MX53_PAD_GPIO_5__I2C3_SCL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_5__I2C3_SCL              (_MX53_PAD_GPIO_5__I2C3_SCL | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_GPIO_5__CCM_PLL1_BYP          (_MX53_PAD_GPIO_5__CCM_PLL1_BYP | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_7__ESAI1_TX4_RX1         (_MX53_PAD_GPIO_7__ESAI1_TX4_RX1 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_7__GPIO1_7               (_MX53_PAD_GPIO_7__GPIO1_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_16__TZIC_PWRFAIL_INT             (_MX53_PAD_GPIO_16__TZIC_PWRFAIL_INT | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_16__RTC_CE_RTC_EXT_TRIG1         (_MX53_PAD_GPIO_16__RTC_CE_RTC_EXT_TRIG1 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_16__SPDIF_IN1            (_MX53_PAD_GPIO_16__SPDIF_IN1 | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_GPIO_16__I2C3_SDA             (_MX53_PAD_GPIO_16__I2C3_SDA | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_16__I2C3_SDA             (_MX53_PAD_GPIO_16__I2C3_SDA | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_GPIO_16__SJC_DE_B             (_MX53_PAD_GPIO_16__SJC_DE_B | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_17__ESAI1_TX0            (_MX53_PAD_GPIO_17__ESAI1_TX0 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_17__GPIO7_12             (_MX53_PAD_GPIO_17__GPIO7_12 | MUX_PAD_CTRL(NO_PAD_CTRL))
index f495c87..3a39428 100644 (file)
@@ -48,12 +48,10 @@ struct sdma_script_start_addrs {
 /**
  * struct sdma_platform_data - platform specific data for SDMA engine
  *
- * @sdma_version       The version of this SDMA engine
  * @fw_name            The firmware name
  * @script_addrs       SDMA scripts addresses in SDMA ROM
  */
 struct sdma_platform_data {
-       int sdma_version;
        char *fw_name;
        struct sdma_script_start_addrs *script_addrs;
 };
index 6e6735f..bb8f4a6 100644 (file)
@@ -13,6 +13,7 @@ config ARCH_OMAP1
        bool "TI OMAP1"
        select CLKDEV_LOOKUP
        select CLKSRC_MMIO
+       select GENERIC_IRQ_CHIP
        help
          "Systems based on omap7xx, omap15xx or omap16xx"
 
index d1c916f..dc562a5 100644 (file)
 
 #define OMAP36XX_DMA_UART4_TX          81      /* S_DMA_80 */
 #define OMAP36XX_DMA_UART4_RX          82      /* S_DMA_81 */
+
+/* Only for AM35xx */
+#define AM35XX_DMA_UART4_TX            54
+#define AM35XX_DMA_UART4_RX            55
+
 /*----------------------------------------------------------------------------*/
 
 #define OMAP1_DMA_TOUT_IRQ             (1 << 0)
index 926d25c..30e1071 100644 (file)
 #define INT_35XX_EMAC_C0_TX_PULSE_IRQ  69
 #define INT_35XX_EMAC_C0_MISC_PULSE_IRQ        70
 #define INT_35XX_USBOTG_IRQ            71
+#define INT_35XX_UART4                 84
 #define INT_35XX_CCDC_VD0_IRQ          88
 #define INT_35XX_CCDC_VD1_IRQ          92
 #define INT_35XX_CCDC_VD2_IRQ          93
index 2723f91..de3b10c 100644 (file)
@@ -56,6 +56,9 @@
 #define TI816X_UART2_BASE      0x48022000
 #define TI816X_UART3_BASE      0x48024000
 
+/* AM3505/3517 UART4 */
+#define AM35XX_UART4_BASE      0x4809E000      /* Only on AM3505/3517 */
+
 /* External port on Zoom2/3 */
 #define ZOOM_UART_BASE         0x10000000
 #define ZOOM_UART_VIRT         0xfa400000
index c60737c..79e7fed 100644 (file)
@@ -423,9 +423,6 @@ static void sgtable_fill_kmalloc(struct sg_table *sgt, u32 pa, u32 da,
 {
        unsigned int i;
        struct scatterlist *sg;
-       void *va;
-
-       va = phys_to_virt(pa);
 
        for_each_sg(sgt->sgl, sg, sgt->nents, i) {
                unsigned bytes;
index 3b3776d..fff68d0 100644 (file)
@@ -910,7 +910,7 @@ omapl138_case_a3    MACH_OMAPL138_CASE_A3   OMAPL138_CASE_A3        3280
 uemd                   MACH_UEMD               UEMD                    3281
 ccwmx51mut             MACH_CCWMX51MUT         CCWMX51MUT              3282
 rockhopper             MACH_ROCKHOPPER         ROCKHOPPER              3283
-nookcolor              MACH_NOOKCOLOR          NOOKCOLOR               3284
+encore                 MACH_ENCORE             ENCORE                  3284
 hkdkc100               MACH_HKDKC100           HKDKC100                3285
 ts42xx                 MACH_TS42XX             TS42XX                  3286
 aebl                   MACH_AEBL               AEBL                    3287
index e9d689b..197e96f 100644 (file)
@@ -10,6 +10,7 @@ config AVR32
        select GENERIC_IRQ_PROBE
        select HARDIRQS_SW_RESEND
        select GENERIC_IRQ_SHOW
+       select ARCH_HAVE_NMI_SAFE_CMPXCHG
        help
          AVR32 is a high-performance 32-bit RISC microprocessor core,
          designed for cost-sensitive embedded applications, with particular
index 8502653..466af40 100644 (file)
@@ -158,7 +158,7 @@ static int sync_serial_open(struct inode *inode, struct file *file);
 static int sync_serial_release(struct inode *inode, struct file *file);
 static unsigned int sync_serial_poll(struct file *filp, poll_table *wait);
 
-static int sync_serial_ioctl(struct file *file,
+static long sync_serial_ioctl(struct file *file,
        unsigned int cmd, unsigned long arg);
 static ssize_t sync_serial_write(struct file *file, const char *buf,
        size_t count, loff_t *ppos);
@@ -625,11 +625,11 @@ static int sync_serial_open(struct inode *inode, struct file *file)
                        *R_IRQ_MASK1_SET = 1 << port->data_avail_bit;
                DEBUG(printk(KERN_DEBUG "sser%d rec started\n", dev));
        }
-       ret = 0;
+       err = 0;
        
 out:
        mutex_unlock(&sync_serial_mutex);
-       return ret;
+       return err;
 }
 
 static int sync_serial_release(struct inode *inode, struct file *file)
index 907cfb5..ba0e596 100644 (file)
@@ -20,6 +20,9 @@
 #define crisv10_mask_irq(irq_nr) (*R_VECT_MASK_CLR = 1 << (irq_nr));
 #define crisv10_unmask_irq(irq_nr) (*R_VECT_MASK_SET = 1 << (irq_nr));
 
+extern void kgdb_init(void);
+extern void breakpoint(void);
+
 /* don't use set_int_vector, it bypasses the linux interrupt handlers. it is
  * global just so that the kernel gdb can use it.
  */
index 29b74a1..332f19c 100644 (file)
@@ -11,8 +11,6 @@
 
 #ifdef __KERNEL__
 
-#define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
-
 #ifndef __ASSEMBLY__
 #include <asm/types.h>
 #include <asm/processor.h>
@@ -67,8 +65,10 @@ struct thread_info {
 
 #define init_thread_info       (init_thread_union.thread_info)
 
+#define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
 /* thread information allocation */
-#define alloc_thread_info(tsk, node) ((struct thread_info *) __get_free_pages(GFP_KERNEL,1))
+#define alloc_thread_info_node(tsk, node)      \
+       ((struct thread_info *) __get_free_pages(GFP_KERNEL, 1))
 #define free_thread_info(ti) free_pages((unsigned long) (ti), 1)
 
 #endif /* !__ASSEMBLY__ */
index cb884e4..bad27a6 100644 (file)
@@ -7,6 +7,7 @@ config FRV
        select HAVE_PERF_EVENTS
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_SHOW
+       select ARCH_HAVE_NMI_SAFE_CMPXCHG
 
 config ZONE_DMA
        bool
index c42c83d..4fb63a3 100644 (file)
@@ -133,13 +133,7 @@ void pgd_dtor(void *pgd)
 
 pgd_t *pgd_alloc(struct mm_struct *mm)
 {
-       pgd_t *pgd;
-
-       pgd = quicklist_alloc(0, GFP_KERNEL, pgd_ctor);
-       if (!pgd)
-               return pgd;
-
-       return pgd;
+       return quicklist_alloc(0, GFP_KERNEL, pgd_ctor);
 }
 
 void pgd_free(struct mm_struct *mm, pgd_t *pgd)
index 137b277..3ff7785 100644 (file)
@@ -27,6 +27,8 @@ config IA64
        select GENERIC_PENDING_IRQ if SMP
        select IRQ_PER_CPU
        select GENERIC_IRQ_SHOW
+       select ARCH_WANT_OPTIONAL_GPIOLIB
+       select ARCH_HAVE_NMI_SAFE_CMPXCHG
        default y
        help
          The Itanium Processor Family is Intel's 64-bit successor to
@@ -89,6 +91,9 @@ config GENERIC_TIME_VSYSCALL
 config HAVE_SETUP_PER_CPU_AREA
        def_bool y
 
+config GENERIC_GPIO
+       def_bool y
+
 config DMI
        bool
        default y
@@ -157,7 +162,6 @@ config IA64_GENERIC
        select ACPI_NUMA
        select SWIOTLB
        select PCI_MSI
-       select DMAR
        help
          This selects the system type of your hardware.  A "generic" kernel
          will run on any supported IA-64 system.  However, if you configure
index 1d7bca0..0e5cd14 100644 (file)
@@ -234,3 +234,4 @@ CONFIG_CRYPTO_MD5=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRC_T10DIF=y
 CONFIG_MISC_DEVICES=y
+CONFIG_DMAR=y
diff --git a/arch/ia64/include/asm/gpio.h b/arch/ia64/include/asm/gpio.h
new file mode 100644 (file)
index 0000000..590a20d
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Generic GPIO API implementation for IA-64.
+ *
+ * A stright copy of that for PowerPC which was:
+ *
+ * Copyright (c) 2007-2008  MontaVista Software, Inc.
+ *
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _ASM_IA64_GPIO_H
+#define _ASM_IA64_GPIO_H
+
+#include <linux/errno.h>
+#include <asm-generic/gpio.h>
+
+#ifdef CONFIG_GPIOLIB
+
+/*
+ * We don't (yet) implement inlined/rapid versions for on-chip gpios.
+ * Just call gpiolib.
+ */
+static inline int gpio_get_value(unsigned int gpio)
+{
+       return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned int gpio, int value)
+{
+       __gpio_set_value(gpio, value);
+}
+
+static inline int gpio_cansleep(unsigned int gpio)
+{
+       return __gpio_cansleep(gpio);
+}
+
+static inline int gpio_to_irq(unsigned int gpio)
+{
+       return __gpio_to_irq(gpio);
+}
+
+static inline int irq_to_gpio(unsigned int irq)
+{
+       return -EINVAL;
+}
+
+#endif /* CONFIG_GPIOLIB */
+
+#endif /* _ASM_IA64_GPIO_H */
index 6fc03af..c38d22e 100644 (file)
@@ -156,7 +156,7 @@ prefix##_get_next_variable (unsigned long *name_size, efi_char16_t *name,      \
 #define STUB_SET_VARIABLE(prefix, adjust_arg)                                 \
 static efi_status_t                                                           \
 prefix##_set_variable (efi_char16_t *name, efi_guid_t *vendor,                \
-                      unsigned long attr, unsigned long data_size,            \
+                      u32 attr, unsigned long data_size,                      \
                       void *data)                                             \
 {                                                                             \
        struct ia64_fpreg fr[6];                                               \
index 284cd37..9e8ee9d 100644 (file)
@@ -6,6 +6,7 @@ config M68K
        select GENERIC_ATOMIC64 if MMU
        select HAVE_GENERIC_HARDIRQS if !MMU
        select GENERIC_IRQ_SHOW if !MMU
+       select ARCH_HAVE_NMI_SAFE_CMPXCHG if RMW_INSNS
 
 config RWSEM_GENERIC_SPINLOCK
        bool
index 16539b1..13e20bb 100644 (file)
@@ -372,12 +372,6 @@ config AMIGA_PCMCIA
          Include support in the kernel for pcmcia on Amiga 1200 and Amiga
          600. If you intend to use pcmcia cards say Y; otherwise say N.
 
-config STRAM_PROC
-       bool "ST-RAM statistics in /proc"
-       depends on ATARI
-       help
-         Say Y here to report ST-RAM usage statistics in /proc/stram.
-
 config HEARTBEAT
        bool "Use power LED as a heartbeat" if AMIGA || APOLLO || ATARI || MAC ||Q40
        default y if !AMIGA && !APOLLO && !ATARI && !MAC && !Q40 && HP300
index dd0447d..99449fb 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/string.h>
 #include <linux/module.h>
 
+#include <asm/atomic.h>
 #include <asm/page.h>
 #include <asm/amigahw.h>
 
@@ -23,111 +24,100 @@ unsigned long amiga_chip_size;
 EXPORT_SYMBOL(amiga_chip_size);
 
 static struct resource chipram_res = {
-    .name = "Chip RAM", .start = CHIP_PHYSADDR
+       .name = "Chip RAM", .start = CHIP_PHYSADDR
 };
-static unsigned long chipavail;
+static atomic_t chipavail;
 
 
 void __init amiga_chip_init(void)
 {
-    if (!AMIGAHW_PRESENT(CHIP_RAM))
-       return;
+       if (!AMIGAHW_PRESENT(CHIP_RAM))
+               return;
 
-    chipram_res.end = amiga_chip_size-1;
-    request_resource(&iomem_resource, &chipram_res);
+       chipram_res.end = CHIP_PHYSADDR + amiga_chip_size - 1;
+       request_resource(&iomem_resource, &chipram_res);
 
-    chipavail = amiga_chip_size;
+       atomic_set(&chipavail, amiga_chip_size);
 }
 
 
 void *amiga_chip_alloc(unsigned long size, const char *name)
 {
-    struct resource *res;
+       struct resource *res;
+       void *p;
 
-    /* round up */
-    size = PAGE_ALIGN(size);
+       res = kzalloc(sizeof(struct resource), GFP_KERNEL);
+       if (!res)
+               return NULL;
 
-#ifdef DEBUG
-    printk("amiga_chip_alloc: allocate %ld bytes\n", size);
-#endif
-    res = kzalloc(sizeof(struct resource), GFP_KERNEL);
-    if (!res)
-       return NULL;
-    res->name = name;
+       res->name = name;
+       p = amiga_chip_alloc_res(size, res);
+       if (!p) {
+               kfree(res);
+               return NULL;
+       }
 
-    if (allocate_resource(&chipram_res, res, size, 0, UINT_MAX, PAGE_SIZE, NULL, NULL) < 0) {
-       kfree(res);
-       return NULL;
-    }
-    chipavail -= size;
-#ifdef DEBUG
-    printk("amiga_chip_alloc: returning %lx\n", res->start);
-#endif
-    return (void *)ZTWO_VADDR(res->start);
+       return p;
 }
 EXPORT_SYMBOL(amiga_chip_alloc);
 
 
-    /*
-     *  Warning:
-     *  amiga_chip_alloc_res is meant only for drivers that need to allocate
-     *  Chip RAM before kmalloc() is functional. As a consequence, those
-      drivers must not free that Chip RAM afterwards.
-     */
+       /*
+        *  Warning:
+        *  amiga_chip_alloc_res is meant only for drivers that need to
+        *  allocate Chip RAM before kmalloc() is functional. As a consequence,
+        *  those drivers must not free that Chip RAM afterwards.
+        */
 
-void * __init amiga_chip_alloc_res(unsigned long size, struct resource *res)
+void *amiga_chip_alloc_res(unsigned long size, struct resource *res)
 {
-    unsigned long start;
-
-    /* round up */
-    size = PAGE_ALIGN(size);
-    /* dmesg into chipmem prefers memory at the safe end */
-    start = CHIP_PHYSADDR + chipavail - size;
-
-#ifdef DEBUG
-    printk("amiga_chip_alloc_res: allocate %ld bytes\n", size);
-#endif
-    if (allocate_resource(&chipram_res, res, size, start, UINT_MAX, PAGE_SIZE, NULL, NULL) < 0) {
-       printk("amiga_chip_alloc_res: first alloc failed!\n");
-       if (allocate_resource(&chipram_res, res, size, 0, UINT_MAX, PAGE_SIZE, NULL, NULL) < 0)
-           return NULL;
-    }
-    chipavail -= size;
-#ifdef DEBUG
-    printk("amiga_chip_alloc_res: returning %lx\n", res->start);
-#endif
-    return (void *)ZTWO_VADDR(res->start);
+       int error;
+
+       /* round up */
+       size = PAGE_ALIGN(size);
+
+       pr_debug("amiga_chip_alloc_res: allocate %lu bytes\n", size);
+       error = allocate_resource(&chipram_res, res, size, 0, UINT_MAX,
+                                 PAGE_SIZE, NULL, NULL);
+       if (error < 0) {
+               pr_err("amiga_chip_alloc_res: allocate_resource() failed %d!\n",
+                      error);
+               return NULL;
+       }
+
+       atomic_sub(size, &chipavail);
+       pr_debug("amiga_chip_alloc_res: returning %pR\n", res);
+       return (void *)ZTWO_VADDR(res->start);
 }
 
 void amiga_chip_free(void *ptr)
 {
-    unsigned long start = ZTWO_PADDR(ptr);
-    struct resource **p, *res;
-    unsigned long size;
-
-    for (p = &chipram_res.child; (res = *p); p = &res->sibling) {
-       if (res->start != start)
-           continue;
-       *p = res->sibling;
-       size = res->end-start;
-#ifdef DEBUG
-       printk("amiga_chip_free: free %ld bytes at %p\n", size, ptr);
-#endif
-       chipavail += size;
+       unsigned long start = ZTWO_PADDR(ptr);
+       struct resource *res;
+       unsigned long size;
+
+       res = lookup_resource(&chipram_res, start);
+       if (!res) {
+               pr_err("amiga_chip_free: trying to free nonexistent region at "
+                      "%p\n", ptr);
+               return;
+       }
+
+       size = resource_size(res);
+       pr_debug("amiga_chip_free: free %lu bytes at %p\n", size, ptr);
+       atomic_add(size, &chipavail);
+       release_resource(res);
        kfree(res);
-       return;
-    }
-    printk("amiga_chip_free: trying to free nonexistent region at %p\n", ptr);
 }
 EXPORT_SYMBOL(amiga_chip_free);
 
 
 unsigned long amiga_chip_avail(void)
 {
-#ifdef DEBUG
-       printk("amiga_chip_avail : %ld bytes\n", chipavail);
-#endif
-       return chipavail;
+       unsigned long n = atomic_read(&chipavail);
+
+       pr_debug("amiga_chip_avail : %lu bytes\n", n);
+       return n;
 }
 EXPORT_SYMBOL(amiga_chip_avail);
 
index 6ec3b7f..0810c8d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * arch/m68k/atari/stram.c: Functions for ST-RAM allocations
+ * Functions for ST-RAM allocations
  *
  * Copyright 1994-97 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
  *
 #include <asm/atari_stram.h>
 #include <asm/io.h>
 
-#undef DEBUG
-
-#ifdef DEBUG
-#define        DPRINTK(fmt,args...) printk( fmt, ##args )
-#else
-#define DPRINTK(fmt,args...)
-#endif
-
-#if defined(CONFIG_PROC_FS) && defined(CONFIG_STRAM_PROC)
-/* abbrev for the && above... */
-#define DO_PROC
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#endif
 
 /*
- * ++roman:
- *
- * New version of ST-Ram buffer allocation. Instead of using the
- * 1 MB - 4 KB that remain when the ST-Ram chunk starts at $1000
- * (1 MB granularity!), such buffers are reserved like this:
- *
- *  - If the kernel resides in ST-Ram anyway, we can take the buffer
- *    from behind the current kernel data space the normal way
- *    (incrementing start_mem).
- *
- *  - If the kernel is in TT-Ram, stram_init() initializes start and
- *    end of the available region. Buffers are allocated from there
- *    and mem_init() later marks the such used pages as reserved.
- *    Since each TT-Ram chunk is at least 4 MB in size, I hope there
- *    won't be an overrun of the ST-Ram region by normal kernel data
- *    space.
- *
- * For that, ST-Ram may only be allocated while kernel initialization
- * is going on, or exactly: before mem_init() is called. There is also
- * no provision now for freeing ST-Ram buffers. It seems that isn't
- * really needed.
- *
+ * The ST-RAM allocator allocates memory from a pool of reserved ST-RAM of
+ * configurable size, set aside on ST-RAM init.
+ * As long as this pool is not exhausted, allocation of real ST-RAM can be
+ * guaranteed.
  */
 
-/* Start and end (virtual) of ST-RAM */
-static void *stram_start, *stram_end;
-
-/* set after memory_init() executed and allocations via start_mem aren't
- * possible anymore */
-static int mem_init_done;
-
 /* set if kernel is in ST-RAM */
 static int kernel_in_stram;
 
-typedef struct stram_block {
-       struct stram_block *next;
-       void *start;
-       unsigned long size;
-       unsigned flags;
-       const char *owner;
-} BLOCK;
-
-/* values for flags field */
-#define BLOCK_FREE     0x01    /* free structure in the BLOCKs pool */
-#define BLOCK_KMALLOCED        0x02    /* structure allocated by kmalloc() */
-#define BLOCK_GFP      0x08    /* block allocated with __get_dma_pages() */
+static struct resource stram_pool = {
+       .name = "ST-RAM Pool"
+};
 
-/* list of allocated blocks */
-static BLOCK *alloc_list;
+static unsigned long pool_size = 1024*1024;
 
-/* We can't always use kmalloc() to allocate BLOCK structures, since
- * stram_alloc() can be called rather early. So we need some pool of
- * statically allocated structures. 20 of them is more than enough, so in most
- * cases we never should need to call kmalloc(). */
-#define N_STATIC_BLOCKS        20
-static BLOCK static_blocks[N_STATIC_BLOCKS];
 
-/***************************** Prototypes *****************************/
+static int __init atari_stram_setup(char *arg)
+{
+       if (!MACH_IS_ATARI)
+               return 0;
 
-static BLOCK *add_region( void *addr, unsigned long size );
-static BLOCK *find_region( void *addr );
-static int remove_region( BLOCK *block );
+       pool_size = memparse(arg, NULL);
+       return 0;
+}
 
-/************************* End of Prototypes **************************/
+early_param("stram_pool", atari_stram_setup);
 
-\f
-/* ------------------------------------------------------------------------ */
-/*                                                        Public Interface                                                             */
-/* ------------------------------------------------------------------------ */
 
 /*
  * This init function is called very early by atari/config.c
@@ -123,25 +67,23 @@ static int remove_region( BLOCK *block );
 void __init atari_stram_init(void)
 {
        int i;
+       void *stram_start;
 
-       /* initialize static blocks */
-       for( i = 0; i < N_STATIC_BLOCKS; ++i )
-               static_blocks[i].flags = BLOCK_FREE;
-
-       /* determine whether kernel code resides in ST-RAM (then ST-RAM is the
-        * first memory block at virtual 0x0) */
+       /*
+        * determine whether kernel code resides in ST-RAM
+        * (then ST-RAM is the first memory block at virtual 0x0)
+        */
        stram_start = phys_to_virt(0);
        kernel_in_stram = (stram_start == 0);
 
-       for( i = 0; i < m68k_num_memory; ++i ) {
+       for (i = 0; i < m68k_num_memory; ++i) {
                if (m68k_memory[i].addr == 0) {
-                       /* skip first 2kB or page (supervisor-only!) */
-                       stram_end = stram_start + m68k_memory[i].size;
                        return;
                }
        }
+
        /* Should never come here! (There is always ST-Ram!) */
-       panic( "atari_stram_init: no ST-RAM found!" );
+       panic("atari_stram_init: no ST-RAM found!");
 }
 
 
@@ -151,226 +93,68 @@ void __init atari_stram_init(void)
  */
 void __init atari_stram_reserve_pages(void *start_mem)
 {
-       /* always reserve first page of ST-RAM, the first 2 kB are
-        * supervisor-only! */
+       /*
+        * always reserve first page of ST-RAM, the first 2 KiB are
+        * supervisor-only!
+        */
        if (!kernel_in_stram)
                reserve_bootmem(0, PAGE_SIZE, BOOTMEM_DEFAULT);
 
-}
+       stram_pool.start = (resource_size_t)alloc_bootmem_low_pages(pool_size);
+       stram_pool.end = stram_pool.start + pool_size - 1;
+       request_resource(&iomem_resource, &stram_pool);
 
-void atari_stram_mem_init_hook (void)
-{
-       mem_init_done = 1;
+       pr_debug("atari_stram pool: size = %lu bytes, resource = %pR\n",
+                pool_size, &stram_pool);
 }
 
 
-/*
- * This is main public interface: somehow allocate a ST-RAM block
- *
- *  - If we're before mem_init(), we have to make a static allocation. The
- *    region is taken in the kernel data area (if the kernel is in ST-RAM) or
- *    from the start of ST-RAM (if the kernel is in TT-RAM) and added to the
- *    rsvd_stram_* region. The ST-RAM is somewhere in the middle of kernel
- *    address space in the latter case.
- *
- *  - If mem_init() already has been called, try with __get_dma_pages().
- *    This has the disadvantage that it's very hard to get more than 1 page,
- *    and it is likely to fail :-(
- *
- */
-void *atari_stram_alloc(long size, const char *owner)
+void *atari_stram_alloc(unsigned long size, const char *owner)
 {
-       void *addr = NULL;
-       BLOCK *block;
-       int flags;
-
-       DPRINTK("atari_stram_alloc(size=%08lx,owner=%s)\n", size, owner);
-
-       if (!mem_init_done)
-               return alloc_bootmem_low(size);
-       else {
-               /* After mem_init(): can only resort to __get_dma_pages() */
-               addr = (void *)__get_dma_pages(GFP_KERNEL, get_order(size));
-               flags = BLOCK_GFP;
-               DPRINTK( "atari_stram_alloc: after mem_init, "
-                                "get_pages=%p\n", addr );
+       struct resource *res;
+       int error;
+
+       pr_debug("atari_stram_alloc: allocate %lu bytes\n", size);
+
+       /* round up */
+       size = PAGE_ALIGN(size);
+
+       res = kzalloc(sizeof(struct resource), GFP_KERNEL);
+       if (!res)
+               return NULL;
+
+       res->name = owner;
+       error = allocate_resource(&stram_pool, res, size, 0, UINT_MAX,
+                                 PAGE_SIZE, NULL, NULL);
+       if (error < 0) {
+               pr_err("atari_stram_alloc: allocate_resource() failed %d!\n",
+                      error);
+               kfree(res);
+               return NULL;
        }
 
-       if (addr) {
-               if (!(block = add_region( addr, size ))) {
-                       /* out of memory for BLOCK structure :-( */
-                       DPRINTK( "atari_stram_alloc: out of mem for BLOCK -- "
-                                        "freeing again\n" );
-                       free_pages((unsigned long)addr, get_order(size));
-                       return( NULL );
-               }
-               block->owner = owner;
-               block->flags |= flags;
-       }
-       return( addr );
+       pr_debug("atari_stram_alloc: returning %pR\n", res);
+       return (void *)res->start;
 }
 EXPORT_SYMBOL(atari_stram_alloc);
 
-void atari_stram_free( void *addr )
 
+void atari_stram_free(void *addr)
 {
-       BLOCK *block;
-
-       DPRINTK( "atari_stram_free(addr=%p)\n", addr );
+       unsigned long start = (unsigned long)addr;
+       struct resource *res;
+       unsigned long size;
 
-       if (!(block = find_region( addr ))) {
-               printk( KERN_ERR "Attempt to free non-allocated ST-RAM block at %p "
-                               "from %p\n", addr, __builtin_return_address(0) );
+       res = lookup_resource(&stram_pool, start);
+       if (!res) {
+               pr_err("atari_stram_free: trying to free nonexistent region "
+                      "at %p\n", addr);
                return;
        }
-       DPRINTK( "atari_stram_free: found block (%p): size=%08lx, owner=%s, "
-                        "flags=%02x\n", block, block->size, block->owner, block->flags );
-
-       if (!(block->flags & BLOCK_GFP))
-               goto fail;
 
-       DPRINTK("atari_stram_free: is kmalloced, order_size=%d\n",
-               get_order(block->size));
-       free_pages((unsigned long)addr, get_order(block->size));
-       remove_region( block );
-       return;
-
-  fail:
-       printk( KERN_ERR "atari_stram_free: cannot free block at %p "
-                       "(called from %p)\n", addr, __builtin_return_address(0) );
+       size = resource_size(res);
+       pr_debug("atari_stram_free: free %lu bytes at %p\n", size, addr);
+       release_resource(res);
+       kfree(res);
 }
 EXPORT_SYMBOL(atari_stram_free);
-
-\f
-/* ------------------------------------------------------------------------ */
-/*                                                       Region Management                                                             */
-/* ------------------------------------------------------------------------ */
-
-
-/* insert a region into the alloced list (sorted) */
-static BLOCK *add_region( void *addr, unsigned long size )
-{
-       BLOCK **p, *n = NULL;
-       int i;
-
-       for( i = 0; i < N_STATIC_BLOCKS; ++i ) {
-               if (static_blocks[i].flags & BLOCK_FREE) {
-                       n = &static_blocks[i];
-                       n->flags = 0;
-                       break;
-               }
-       }
-       if (!n && mem_init_done) {
-               /* if statics block pool exhausted and we can call kmalloc() already
-                * (after mem_init()), try that */
-               n = kmalloc( sizeof(BLOCK), GFP_KERNEL );
-               if (n)
-                       n->flags = BLOCK_KMALLOCED;
-       }
-       if (!n) {
-               printk( KERN_ERR "Out of memory for ST-RAM descriptor blocks\n" );
-               return( NULL );
-       }
-       n->start = addr;
-       n->size  = size;
-
-       for( p = &alloc_list; *p; p = &((*p)->next) )
-               if ((*p)->start > addr) break;
-       n->next = *p;
-       *p = n;
-
-       return( n );
-}
-
-
-/* find a region (by start addr) in the alloced list */
-static BLOCK *find_region( void *addr )
-{
-       BLOCK *p;
-
-       for( p = alloc_list; p; p = p->next ) {
-               if (p->start == addr)
-                       return( p );
-               if (p->start > addr)
-                       break;
-       }
-       return( NULL );
-}
-
-
-/* remove a block from the alloced list */
-static int remove_region( BLOCK *block )
-{
-       BLOCK **p;
-
-       for( p = &alloc_list; *p; p = &((*p)->next) )
-               if (*p == block) break;
-       if (!*p)
-               return( 0 );
-
-       *p = block->next;
-       if (block->flags & BLOCK_KMALLOCED)
-               kfree( block );
-       else
-               block->flags |= BLOCK_FREE;
-       return( 1 );
-}
-
-
-\f
-/* ------------------------------------------------------------------------ */
-/*                                              /proc statistics file stuff                                            */
-/* ------------------------------------------------------------------------ */
-
-#ifdef DO_PROC
-
-#define        PRINT_PROC(fmt,args...) seq_printf( m, fmt, ##args )
-
-static int stram_proc_show(struct seq_file *m, void *v)
-{
-       BLOCK *p;
-
-       PRINT_PROC("Total ST-RAM:      %8u kB\n",
-                          (stram_end - stram_start) >> 10);
-       PRINT_PROC( "Allocated regions:\n" );
-       for( p = alloc_list; p; p = p->next ) {
-               PRINT_PROC("0x%08lx-0x%08lx: %s (",
-                          virt_to_phys(p->start),
-                          virt_to_phys(p->start+p->size-1),
-                          p->owner);
-               if (p->flags & BLOCK_GFP)
-                       PRINT_PROC( "page-alloced)\n" );
-               else
-                       PRINT_PROC( "??)\n" );
-       }
-
-       return 0;
-}
-
-static int stram_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, stram_proc_show, NULL);
-}
-
-static const struct file_operations stram_proc_fops = {
-       .open           = stram_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
-static int __init proc_stram_init(void)
-{
-       proc_create("stram", 0, NULL, &stram_proc_fops);
-       return 0;
-}
-module_init(proc_stram_init);
-#endif
-
-
-/*
- * Local variables:
- *  c-indent-level: 4
- *  tab-width: 4
- * End:
- */
index 7546d13..62e2759 100644 (file)
@@ -6,12 +6,11 @@
  */
 
 /* public interface */
-void *atari_stram_alloc(long size, const char *owner);
+void *atari_stram_alloc(unsigned long size, const char *owner);
 void atari_stram_free(void *);
 
 /* functions called internally by other parts of the kernel */
 void atari_stram_init(void);
 void atari_stram_reserve_pages(void *start_mem);
-void atari_stram_mem_init_hook (void);
 
 #endif /*_M68K_ATARI_STRAM_H */
index f51f709..0392b28 100644 (file)
@@ -399,8 +399,8 @@ struct CODEC
 #define CODEC_OVERFLOW_LEFT     2
   u_char unused2, unused3, unused4, unused5;
   u_char gpio_directions;
-#define GPIO_IN                 0
-#define GPIO_OUT                1
+#define CODEC_GPIO_IN           0
+#define CODEC_GPIO_OUT          1
   u_char unused6;
   u_char gpio_data;
 };
index 31d5570..89f2014 100644 (file)
@@ -162,7 +162,7 @@ static inline __attribute_const__ int __virt_to_node_shift(void)
        pgdat->node_mem_map + (__pfn - pgdat->node_start_pfn);          \
 })
 #define page_to_pfn(_page) ({                                          \
-       struct page *__p = (_page);                                     \
+       const struct page *__p = (_page);                               \
        struct pglist_data *pgdat;                                      \
        pgdat = &pg_data_map[page_to_nid(__p)];                         \
        ((__p) - pgdat->node_mem_map) + pgdat->node_start_pfn;          \
index 334d836..c3b4506 100644 (file)
@@ -216,7 +216,9 @@ static void __init m68k_parse_bootinfo(const struct bi_record *record)
 
 void __init setup_arch(char **cmdline_p)
 {
+#ifndef CONFIG_SUN3
        int i;
+#endif
 
        /* The bootinfo is located right after the kernel bss */
        m68k_parse_bootinfo((const struct bi_record *)_end);
index 367ecee..3384a52 100644 (file)
@@ -105,9 +105,6 @@ fp_fetoxm1(struct fp_ext *dest, struct fp_ext *src)
 
        fp_monadic_check(dest, src);
 
-       if (IS_ZERO(dest))
-               return dest;
-
        return dest;
 }
 
index 4ad0ca9..4b5eb3d 100644 (file)
 #ifndef MULTI_ARITH_H
 #define MULTI_ARITH_H
 
-#if 0  /* old code... */
-
-/* Unsigned only, because we don't need signs to multiply and divide. */
-typedef unsigned int int128[4];
-
-/* Word order */
-enum {
-       MSW128,
-       NMSW128,
-       NLSW128,
-       LSW128
-};
-
-/* big-endian */
-#define LO_WORD(ll) (((unsigned int *) &ll)[1])
-#define HI_WORD(ll) (((unsigned int *) &ll)[0])
-
-/* Convenience functions to stuff various integer values into int128s */
-
-static inline void zero128(int128 a)
-{
-       a[LSW128] = a[NLSW128] = a[NMSW128] = a[MSW128] = 0;
-}
-
-/* Human-readable word order in the arguments */
-static inline void set128(unsigned int i3, unsigned int i2, unsigned int i1,
-                         unsigned int i0, int128 a)
-{
-       a[LSW128] = i0;
-       a[NLSW128] = i1;
-       a[NMSW128] = i2;
-       a[MSW128] = i3;
-}
-
-/* Convenience functions (for testing as well) */
-static inline void int64_to_128(unsigned long long src, int128 dest)
-{
-       dest[LSW128] = (unsigned int) src;
-       dest[NLSW128] = src >> 32;
-       dest[NMSW128] = dest[MSW128] = 0;
-}
-
-static inline void int128_to_64(const int128 src, unsigned long long *dest)
-{
-       *dest = src[LSW128] | (long long) src[NLSW128] << 32;
-}
-
-static inline void put_i128(const int128 a)
-{
-       printk("%08x %08x %08x %08x\n", a[MSW128], a[NMSW128],
-              a[NLSW128], a[LSW128]);
-}
-
-/* Internal shifters:
-
-   Note that these are only good for 0 < count < 32.
- */
-
-static inline void _lsl128(unsigned int count, int128 a)
-{
-       a[MSW128] = (a[MSW128] << count) | (a[NMSW128] >> (32 - count));
-       a[NMSW128] = (a[NMSW128] << count) | (a[NLSW128] >> (32 - count));
-       a[NLSW128] = (a[NLSW128] << count) | (a[LSW128] >> (32 - count));
-       a[LSW128] <<= count;
-}
-
-static inline void _lsr128(unsigned int count, int128 a)
-{
-       a[LSW128] = (a[LSW128] >> count) | (a[NLSW128] << (32 - count));
-       a[NLSW128] = (a[NLSW128] >> count) | (a[NMSW128] << (32 - count));
-       a[NMSW128] = (a[NMSW128] >> count) | (a[MSW128] << (32 - count));
-       a[MSW128] >>= count;
-}
-
-/* Should be faster, one would hope */
-
-static inline void lslone128(int128 a)
-{
-       asm volatile ("lsl.l #1,%0\n"
-                     "roxl.l #1,%1\n"
-                     "roxl.l #1,%2\n"
-                     "roxl.l #1,%3\n"
-                     :
-                     "=d" (a[LSW128]),
-                     "=d"(a[NLSW128]),
-                     "=d"(a[NMSW128]),
-                     "=d"(a[MSW128])
-                     :
-                     "0"(a[LSW128]),
-                     "1"(a[NLSW128]),
-                     "2"(a[NMSW128]),
-                     "3"(a[MSW128]));
-}
-
-static inline void lsrone128(int128 a)
-{
-       asm volatile ("lsr.l #1,%0\n"
-                     "roxr.l #1,%1\n"
-                     "roxr.l #1,%2\n"
-                     "roxr.l #1,%3\n"
-                     :
-                     "=d" (a[MSW128]),
-                     "=d"(a[NMSW128]),
-                     "=d"(a[NLSW128]),
-                     "=d"(a[LSW128])
-                     :
-                     "0"(a[MSW128]),
-                     "1"(a[NMSW128]),
-                     "2"(a[NLSW128]),
-                     "3"(a[LSW128]));
-}
-
-/* Generalized 128-bit shifters:
-
-   These bit-shift to a multiple of 32, then move whole longwords.  */
-
-static inline void lsl128(unsigned int count, int128 a)
-{
-       int wordcount, i;
-
-       if (count % 32)
-               _lsl128(count % 32, a);
-
-       if (0 == (wordcount = count / 32))
-               return;
-
-       /* argh, gak, endian-sensitive */
-       for (i = 0; i < 4 - wordcount; i++) {
-               a[i] = a[i + wordcount];
-       }
-       for (i = 3; i >= 4 - wordcount; --i) {
-               a[i] = 0;
-       }
-}
-
-static inline void lsr128(unsigned int count, int128 a)
-{
-       int wordcount, i;
-
-       if (count % 32)
-               _lsr128(count % 32, a);
-
-       if (0 == (wordcount = count / 32))
-               return;
-
-       for (i = 3; i >= wordcount; --i) {
-               a[i] = a[i - wordcount];
-       }
-       for (i = 0; i < wordcount; i++) {
-               a[i] = 0;
-       }
-}
-
-static inline int orl128(int a, int128 b)
-{
-       b[LSW128] |= a;
-}
-
-static inline int btsthi128(const int128 a)
-{
-       return a[MSW128] & 0x80000000;
-}
-
-/* test bits (numbered from 0 = LSB) up to and including "top" */
-static inline int bftestlo128(int top, const int128 a)
-{
-       int r = 0;
-
-       if (top > 31)
-               r |= a[LSW128];
-       if (top > 63)
-               r |= a[NLSW128];
-       if (top > 95)
-               r |= a[NMSW128];
-
-       r |= a[3 - (top / 32)] & ((1 << (top % 32 + 1)) - 1);
-
-       return (r != 0);
-}
-
-/* Aargh.  We need these because GCC is broken */
-/* FIXME: do them in assembly, for goodness' sake! */
-static inline void mask64(int pos, unsigned long long *mask)
-{
-       *mask = 0;
-
-       if (pos < 32) {
-               LO_WORD(*mask) = (1 << pos) - 1;
-               return;
-       }
-       LO_WORD(*mask) = -1;
-       HI_WORD(*mask) = (1 << (pos - 32)) - 1;
-}
-
-static inline void bset64(int pos, unsigned long long *dest)
-{
-       /* This conditional will be optimized away.  Thanks, GCC! */
-       if (pos < 32)
-               asm volatile ("bset %1,%0":"=m"
-                             (LO_WORD(*dest)):"id"(pos));
-       else
-               asm volatile ("bset %1,%0":"=m"
-                             (HI_WORD(*dest)):"id"(pos - 32));
-}
-
-static inline int btst64(int pos, unsigned long long dest)
-{
-       if (pos < 32)
-               return (0 != (LO_WORD(dest) & (1 << pos)));
-       else
-               return (0 != (HI_WORD(dest) & (1 << (pos - 32))));
-}
-
-static inline void lsl64(int count, unsigned long long *dest)
-{
-       if (count < 32) {
-               HI_WORD(*dest) = (HI_WORD(*dest) << count)
-                   | (LO_WORD(*dest) >> count);
-               LO_WORD(*dest) <<= count;
-               return;
-       }
-       count -= 32;
-       HI_WORD(*dest) = LO_WORD(*dest) << count;
-       LO_WORD(*dest) = 0;
-}
-
-static inline void lsr64(int count, unsigned long long *dest)
-{
-       if (count < 32) {
-               LO_WORD(*dest) = (LO_WORD(*dest) >> count)
-                   | (HI_WORD(*dest) << (32 - count));
-               HI_WORD(*dest) >>= count;
-               return;
-       }
-       count -= 32;
-       LO_WORD(*dest) = HI_WORD(*dest) >> count;
-       HI_WORD(*dest) = 0;
-}
-#endif
-
 static inline void fp_denormalize(struct fp_ext *reg, unsigned int cnt)
 {
        reg->exp += cnt;
@@ -481,117 +241,6 @@ static inline void fp_dividemant(union fp_mant128 *dest, struct fp_ext *src,
        }
 }
 
-#if 0
-static inline unsigned int fp_fls128(union fp_mant128 *src)
-{
-       unsigned long data;
-       unsigned int res, off;
-
-       if ((data = src->m32[0]))
-               off = 0;
-       else if ((data = src->m32[1]))
-               off = 32;
-       else if ((data = src->m32[2]))
-               off = 64;
-       else if ((data = src->m32[3]))
-               off = 96;
-       else
-               return 128;
-
-       asm ("bfffo %1{#0,#32},%0" : "=d" (res) : "dm" (data));
-       return res + off;
-}
-
-static inline void fp_shiftmant128(union fp_mant128 *src, int shift)
-{
-       unsigned long sticky;
-
-       switch (shift) {
-       case 0:
-               return;
-       case 1:
-               asm volatile ("lsl.l #1,%0"
-                       : "=d" (src->m32[3]) : "0" (src->m32[3]));
-               asm volatile ("roxl.l #1,%0"
-                       : "=d" (src->m32[2]) : "0" (src->m32[2]));
-               asm volatile ("roxl.l #1,%0"
-                       : "=d" (src->m32[1]) : "0" (src->m32[1]));
-               asm volatile ("roxl.l #1,%0"
-                       : "=d" (src->m32[0]) : "0" (src->m32[0]));
-               return;
-       case 2 ... 31:
-               src->m32[0] = (src->m32[0] << shift) | (src->m32[1] >> (32 - shift));
-               src->m32[1] = (src->m32[1] << shift) | (src->m32[2] >> (32 - shift));
-               src->m32[2] = (src->m32[2] << shift) | (src->m32[3] >> (32 - shift));
-               src->m32[3] = (src->m32[3] << shift);
-               return;
-       case 32 ... 63:
-               shift -= 32;
-               src->m32[0] = (src->m32[1] << shift) | (src->m32[2] >> (32 - shift));
-               src->m32[1] = (src->m32[2] << shift) | (src->m32[3] >> (32 - shift));
-               src->m32[2] = (src->m32[3] << shift);
-               src->m32[3] = 0;
-               return;
-       case 64 ... 95:
-               shift -= 64;
-               src->m32[0] = (src->m32[2] << shift) | (src->m32[3] >> (32 - shift));
-               src->m32[1] = (src->m32[3] << shift);
-               src->m32[2] = src->m32[3] = 0;
-               return;
-       case 96 ... 127:
-               shift -= 96;
-               src->m32[0] = (src->m32[3] << shift);
-               src->m32[1] = src->m32[2] = src->m32[3] = 0;
-               return;
-       case -31 ... -1:
-               shift = -shift;
-               sticky = 0;
-               if (src->m32[3] << (32 - shift))
-                       sticky = 1;
-               src->m32[3] = (src->m32[3] >> shift) | (src->m32[2] << (32 - shift)) | sticky;
-               src->m32[2] = (src->m32[2] >> shift) | (src->m32[1] << (32 - shift));
-               src->m32[1] = (src->m32[1] >> shift) | (src->m32[0] << (32 - shift));
-               src->m32[0] = (src->m32[0] >> shift);
-               return;
-       case -63 ... -32:
-               shift = -shift - 32;
-               sticky = 0;
-               if ((src->m32[2] << (32 - shift)) || src->m32[3])
-                       sticky = 1;
-               src->m32[3] = (src->m32[2] >> shift) | (src->m32[1] << (32 - shift)) | sticky;
-               src->m32[2] = (src->m32[1] >> shift) | (src->m32[0] << (32 - shift));
-               src->m32[1] = (src->m32[0] >> shift);
-               src->m32[0] = 0;
-               return;
-       case -95 ... -64:
-               shift = -shift - 64;
-               sticky = 0;
-               if ((src->m32[1] << (32 - shift)) || src->m32[2] || src->m32[3])
-                       sticky = 1;
-               src->m32[3] = (src->m32[1] >> shift) | (src->m32[0] << (32 - shift)) | sticky;
-               src->m32[2] = (src->m32[0] >> shift);
-               src->m32[1] = src->m32[0] = 0;
-               return;
-       case -127 ... -96:
-               shift = -shift - 96;
-               sticky = 0;
-               if ((src->m32[0] << (32 - shift)) || src->m32[1] || src->m32[2] || src->m32[3])
-                       sticky = 1;
-               src->m32[3] = (src->m32[0] >> shift) | sticky;
-               src->m32[2] = src->m32[1] = src->m32[0] = 0;
-               return;
-       }
-
-       if (shift < 0 && (src->m32[0] || src->m32[1] || src->m32[2] || src->m32[3]))
-               src->m32[3] = 1;
-       else
-               src->m32[3] = 0;
-       src->m32[2] = 0;
-       src->m32[1] = 0;
-       src->m32[0] = 0;
-}
-#endif
-
 static inline void fp_putmant128(struct fp_ext *dest, union fp_mant128 *src,
                                 int shift)
 {
@@ -637,183 +286,4 @@ static inline void fp_putmant128(struct fp_ext *dest, union fp_mant128 *src,
        }
 }
 
-#if 0 /* old code... */
-static inline int fls(unsigned int a)
-{
-       int r;
-
-       asm volatile ("bfffo %1{#0,#32},%0"
-                     : "=d" (r) : "md" (a));
-       return r;
-}
-
-/* fls = "find last set" (cf. ffs(3)) */
-static inline int fls128(const int128 a)
-{
-       if (a[MSW128])
-               return fls(a[MSW128]);
-       if (a[NMSW128])
-               return fls(a[NMSW128]) + 32;
-       /* XXX: it probably never gets beyond this point in actual
-          use, but that's indicative of a more general problem in the
-          algorithm (i.e. as per the actual 68881 implementation, we
-          really only need at most 67 bits of precision [plus
-          overflow]) so I'm not going to fix it. */
-       if (a[NLSW128])
-               return fls(a[NLSW128]) + 64;
-       if (a[LSW128])
-               return fls(a[LSW128]) + 96;
-       else
-               return -1;
-}
-
-static inline int zerop128(const int128 a)
-{
-       return !(a[LSW128] | a[NLSW128] | a[NMSW128] | a[MSW128]);
-}
-
-static inline int nonzerop128(const int128 a)
-{
-       return (a[LSW128] | a[NLSW128] | a[NMSW128] | a[MSW128]);
-}
-
-/* Addition and subtraction */
-/* Do these in "pure" assembly, because "extended" asm is unmanageable
-   here */
-static inline void add128(const int128 a, int128 b)
-{
-       /* rotating carry flags */
-       unsigned int carry[2];
-
-       carry[0] = a[LSW128] > (0xffffffff - b[LSW128]);
-       b[LSW128] += a[LSW128];
-
-       carry[1] = a[NLSW128] > (0xffffffff - b[NLSW128] - carry[0]);
-       b[NLSW128] = a[NLSW128] + b[NLSW128] + carry[0];
-
-       carry[0] = a[NMSW128] > (0xffffffff - b[NMSW128] - carry[1]);
-       b[NMSW128] = a[NMSW128] + b[NMSW128] + carry[1];
-
-       b[MSW128] = a[MSW128] + b[MSW128] + carry[0];
-}
-
-/* Note: assembler semantics: "b -= a" */
-static inline void sub128(const int128 a, int128 b)
-{
-       /* rotating borrow flags */
-       unsigned int borrow[2];
-
-       borrow[0] = b[LSW128] < a[LSW128];
-       b[LSW128] -= a[LSW128];
-
-       borrow[1] = b[NLSW128] < a[NLSW128] + borrow[0];
-       b[NLSW128] = b[NLSW128] - a[NLSW128] - borrow[0];
-
-       borrow[0] = b[NMSW128] < a[NMSW128] + borrow[1];
-       b[NMSW128] = b[NMSW128] - a[NMSW128] - borrow[1];
-
-       b[MSW128] = b[MSW128] - a[MSW128] - borrow[0];
-}
-
-/* Poor man's 64-bit expanding multiply */
-static inline void mul64(unsigned long long a, unsigned long long b, int128 c)
-{
-       unsigned long long acc;
-       int128 acc128;
-
-       zero128(acc128);
-       zero128(c);
-
-       /* first the low words */
-       if (LO_WORD(a) && LO_WORD(b)) {
-               acc = (long long) LO_WORD(a) * LO_WORD(b);
-               c[NLSW128] = HI_WORD(acc);
-               c[LSW128] = LO_WORD(acc);
-       }
-       /* Next the high words */
-       if (HI_WORD(a) && HI_WORD(b)) {
-               acc = (long long) HI_WORD(a) * HI_WORD(b);
-               c[MSW128] = HI_WORD(acc);
-               c[NMSW128] = LO_WORD(acc);
-       }
-       /* The middle words */
-       if (LO_WORD(a) && HI_WORD(b)) {
-               acc = (long long) LO_WORD(a) * HI_WORD(b);
-               acc128[NMSW128] = HI_WORD(acc);
-               acc128[NLSW128] = LO_WORD(acc);
-               add128(acc128, c);
-       }
-       /* The first and last words */
-       if (HI_WORD(a) && LO_WORD(b)) {
-               acc = (long long) HI_WORD(a) * LO_WORD(b);
-               acc128[NMSW128] = HI_WORD(acc);
-               acc128[NLSW128] = LO_WORD(acc);
-               add128(acc128, c);
-       }
-}
-
-/* Note: unsigned */
-static inline int cmp128(int128 a, int128 b)
-{
-       if (a[MSW128] < b[MSW128])
-               return -1;
-       if (a[MSW128] > b[MSW128])
-               return 1;
-       if (a[NMSW128] < b[NMSW128])
-               return -1;
-       if (a[NMSW128] > b[NMSW128])
-               return 1;
-       if (a[NLSW128] < b[NLSW128])
-               return -1;
-       if (a[NLSW128] > b[NLSW128])
-               return 1;
-
-       return (signed) a[LSW128] - b[LSW128];
-}
-
-inline void div128(int128 a, int128 b, int128 c)
-{
-       int128 mask;
-
-       /* Algorithm:
-
-          Shift the divisor until it's at least as big as the
-          dividend, keeping track of the position to which we've
-          shifted it, i.e. the power of 2 which we've multiplied it
-          by.
-
-          Then, for this power of 2 (the mask), and every one smaller
-          than it, subtract the mask from the dividend and add it to
-          the quotient until the dividend is smaller than the raised
-          divisor.  At this point, divide the dividend and the mask
-          by 2 (i.e. shift one place to the right).  Lather, rinse,
-          and repeat, until there are no more powers of 2 left. */
-
-       /* FIXME: needless to say, there's room for improvement here too. */
-
-       /* Shift up */
-       /* XXX: since it just has to be "at least as big", we can
-          probably eliminate this horribly wasteful loop.  I will
-          have to prove this first, though */
-       set128(0, 0, 0, 1, mask);
-       while (cmp128(b, a) < 0 && !btsthi128(b)) {
-               lslone128(b);
-               lslone128(mask);
-       }
-
-       /* Shift down */
-       zero128(c);
-       do {
-               if (cmp128(a, b) >= 0) {
-                       sub128(b, a);
-                       add128(mask, c);
-               }
-               lsrone128(mask);
-               lsrone128(b);
-       } while (nonzerop128(mask));
-
-       /* The remainder is in a... */
-}
-#endif
-
 #endif /* MULTI_ARITH_H */
index 9113c2f..bbe5254 100644 (file)
@@ -83,11 +83,6 @@ void __init mem_init(void)
        int initpages = 0;
        int i;
 
-#ifdef CONFIG_ATARI
-       if (MACH_IS_ATARI)
-               atari_stram_mem_init_hook();
-#endif
-
        /* this will put all memory onto the freelists */
        totalram_pages = num_physpages = 0;
        for_each_online_pgdat(pgdat) {
index 65adc86..e077b0b 100644 (file)
@@ -15,6 +15,7 @@ config PARISC
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_PROBE
        select IRQ_PER_CPU
+       select ARCH_HAVE_NMI_SAFE_CMPXCHG
 
        help
          The PA-RISC microprocessor is designed by Hewlett-Packard and used
index b1dc71f..4054b31 100644 (file)
@@ -258,10 +258,10 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u)
 
 #define ATOMIC64_INIT(i) ((atomic64_t) { (i) })
 
-static __inline__ int
+static __inline__ s64
 __atomic64_add_return(s64 i, atomic64_t *v)
 {
-       int ret;
+       s64 ret;
        unsigned long flags;
        _atomic_spin_lock_irqsave(v, flags);
 
index 67a33cc..2388bdb 100644 (file)
@@ -5,11 +5,14 @@
 
 #include <linux/futex.h>
 #include <linux/uaccess.h>
+#include <asm/atomic.h>
 #include <asm/errno.h>
 
 static inline int
 futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
 {
+       unsigned long int flags;
+       u32 val;
        int op = (encoded_op >> 28) & 7;
        int cmp = (encoded_op >> 24) & 15;
        int oparg = (encoded_op << 8) >> 20;
@@ -18,21 +21,58 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
        if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
                oparg = 1 << oparg;
 
-       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
+       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(*uaddr)))
                return -EFAULT;
 
        pagefault_disable();
 
+       _atomic_spin_lock_irqsave(uaddr, flags);
+
        switch (op) {
        case FUTEX_OP_SET:
+               /* *(int *)UADDR2 = OPARG; */
+               ret = get_user(oldval, uaddr);
+               if (!ret)
+                       ret = put_user(oparg, uaddr);
+               break;
        case FUTEX_OP_ADD:
+               /* *(int *)UADDR2 += OPARG; */
+               ret = get_user(oldval, uaddr);
+               if (!ret) {
+                       val = oldval + oparg;
+                       ret = put_user(val, uaddr);
+               }
+               break;
        case FUTEX_OP_OR:
+               /* *(int *)UADDR2 |= OPARG; */
+               ret = get_user(oldval, uaddr);
+               if (!ret) {
+                       val = oldval | oparg;
+                       ret = put_user(val, uaddr);
+               }
+               break;
        case FUTEX_OP_ANDN:
+               /* *(int *)UADDR2 &= ~OPARG; */
+               ret = get_user(oldval, uaddr);
+               if (!ret) {
+                       val = oldval & ~oparg;
+                       ret = put_user(val, uaddr);
+               }
+               break;
        case FUTEX_OP_XOR:
+               /* *(int *)UADDR2 ^= OPARG; */
+               ret = get_user(oldval, uaddr);
+               if (!ret) {
+                       val = oldval ^ oparg;
+                       ret = put_user(val, uaddr);
+               }
+               break;
        default:
                ret = -ENOSYS;
        }
 
+       _atomic_spin_unlock_irqrestore(uaddr, flags);
+
        pagefault_enable();
 
        if (!ret) {
@@ -54,7 +94,9 @@ static inline int
 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
                              u32 oldval, u32 newval)
 {
+       int ret;
        u32 val;
+       unsigned long flags;
 
        /* futex.c wants to do a cmpxchg_inatomic on kernel NULL, which is
         * our gateway page, and causes no end of trouble...
@@ -65,12 +107,24 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
        if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
                return -EFAULT;
 
-       if (get_user(val, uaddr))
-               return -EFAULT;
-       if (val == oldval && put_user(newval, uaddr))
-               return -EFAULT;
+       /* HPPA has no cmpxchg in hardware and therefore the
+        * best we can do here is use an array of locks. The
+        * lock selected is based on a hash of the userspace
+        * address. This should scale to a couple of CPUs.
+        */
+
+       _atomic_spin_lock_irqsave(uaddr, flags);
+
+       ret = get_user(val, uaddr);
+
+       if (!ret && val == oldval)
+               ret = put_user(newval, uaddr);
+
        *uval = val;
-       return 0;
+
+       _atomic_spin_unlock_irqrestore(uaddr, flags);
+
+       return ret;
 }
 
 #endif /*__KERNEL__*/
index 3392de3..d61de64 100644 (file)
 #define __NR_open_by_handle_at (__NR_Linux + 326)
 #define __NR_syncfs            (__NR_Linux + 327)
 #define __NR_setns             (__NR_Linux + 328)
+#define __NR_sendmmsg          (__NR_Linux + 329)
 
-#define __NR_Linux_syscalls    (__NR_setns + 1)
+#define __NR_Linux_syscalls    (__NR_sendmmsg + 1)
 
 
 #define __IGNORE_select                /* newselect */
index 34a4f5a..e66366f 100644 (file)
        ENTRY_COMP(open_by_handle_at)
        ENTRY_SAME(syncfs)
        ENTRY_SAME(setns)
+       ENTRY_COMP(sendmmsg)
 
        /* Nothing yet */
 
index 374c475..6926b61 100644 (file)
@@ -136,6 +136,7 @@ config PPC
        select HAVE_SYSCALL_TRACEPOINTS
        select HAVE_BPF_JIT if (PPC64 && NET)
        select HAVE_ARCH_JUMP_LABEL
+       select ARCH_HAVE_NMI_SAFE_CMPXCHG
 
 config EARLY_PRINTK
        bool
index 1f780b9..938986e 100644 (file)
@@ -22,7 +22,6 @@ static __always_inline bool arch_static_branch(struct jump_label_key *key)
        asm goto("1:\n\t"
                 "nop\n\t"
                 ".pushsection __jump_table,  \"aw\"\n\t"
-                ".align 4\n\t"
                 JUMP_ENTRY_TYPE "1b, %l[l_yes], %c0\n\t"
                 ".popsection \n\t"
                 : :  "i" (key) : : l_yes);
@@ -41,7 +40,6 @@ struct jump_entry {
        jump_label_t code;
        jump_label_t target;
        jump_label_t key;
-       jump_label_t pad;
 };
 
 #endif /* _ASM_POWERPC_JUMP_LABEL_H */
index 6857af5..bffd062 100644 (file)
@@ -3,17 +3,7 @@
 
 #include <asm/page.h>
 
-/*
- * If CONFIG_RELOCATABLE is enabled we can place the kdump kernel anywhere.
- * To keep enough space in the RMO for the first stage kernel on 64bit, we
- * place it at 64MB. If CONFIG_RELOCATABLE is not enabled we must place
- * the second stage at 32MB.
- */
-#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_PPC64)
-#define KDUMP_KERNELBASE       0x4000000
-#else
 #define KDUMP_KERNELBASE       0x2000000
-#endif
 
 /* How many bytes to reserve at zero for kdump. The reserve limit should
  * be greater or equal to the trampoline's end address.
index e8aaf6f..559da19 100644 (file)
 #define PV_970         0x0039
 #define PV_POWER5      0x003A
 #define PV_POWER5p     0x003B
-#define PV_POWER7      0x003F
 #define PV_970FX       0x003C
 #define PV_POWER6      0x003E
 #define PV_POWER7      0x003F
 #define mtmsrd(v)      __mtmsrd((v), 0)
 #define mtmsr(v)       mtmsrd(v)
 #else
-#define mtmsr(v)       asm volatile("mtmsr %0" : : "r" (v) : "memory")
+#define mtmsr(v)       asm volatile("mtmsr %0" : \
+                                    : "r" ((unsigned long)(v)) \
+                                    : "memory")
 #endif
 
 #define mfspr(rn)      ({unsigned long rval; \
                        asm volatile("mfspr %0," __stringify(rn) \
                                : "=r" (rval)); rval;})
-#define mtspr(rn, v)   asm volatile("mtspr " __stringify(rn) ",%0" : : "r" (v)\
+#define mtspr(rn, v)   asm volatile("mtspr " __stringify(rn) ",%0" : \
+                                    : "r" ((unsigned long)(v)) \
                                     : "memory")
 
 #ifdef __powerpc64__
index 9fb9332..fa44ff5 100644 (file)
@@ -2051,7 +2051,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 
 static struct cpu_spec the_cpu_spec;
 
-static void __init setup_cpu_spec(unsigned long offset, struct cpu_spec *s)
+static struct cpu_spec * __init setup_cpu_spec(unsigned long offset,
+                                              struct cpu_spec *s)
 {
        struct cpu_spec *t = &the_cpu_spec;
        struct cpu_spec old;
@@ -2114,6 +2115,8 @@ static void __init setup_cpu_spec(unsigned long offset, struct cpu_spec *s)
                t->cpu_setup(offset, t);
        }
 #endif /* CONFIG_PPC64 || CONFIG_BOOKE */
+
+       return t;
 }
 
 struct cpu_spec * __init identify_cpu(unsigned long offset, unsigned int pvr)
@@ -2124,10 +2127,8 @@ struct cpu_spec * __init identify_cpu(unsigned long offset, unsigned int pvr)
        s = PTRRELOC(s);
 
        for (i = 0; i < ARRAY_SIZE(cpu_specs); i++,s++) {
-               if ((pvr & s->pvr_mask) == s->pvr_value) {
-                       setup_cpu_spec(offset, s);
-                       return s;
-               }
+               if ((pvr & s->pvr_mask) == s->pvr_value)
+                       return setup_cpu_spec(offset, s);
        }
 
        BUG();
index 1577434..b25f632 100644 (file)
@@ -117,6 +117,7 @@ void ioport_unmap(void __iomem *addr)
 EXPORT_SYMBOL(ioport_map);
 EXPORT_SYMBOL(ioport_unmap);
 
+#ifdef CONFIG_PCI
 void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max)
 {
        resource_size_t start = pci_resource_start(dev, bar);
@@ -146,3 +147,4 @@ void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
 
 EXPORT_SYMBOL(pci_iomap);
 EXPORT_SYMBOL(pci_iounmap);
+#endif /* CONFIG_PCI */
index 6658a15..9ce1672 100644 (file)
@@ -136,12 +136,16 @@ void __init reserve_crashkernel(void)
        crashk_res.start = KDUMP_KERNELBASE;
 #else
        if (!crashk_res.start) {
+#ifdef CONFIG_PPC64
                /*
-                * unspecified address, choose a region of specified size
-                * can overlap with initrd (ignoring corruption when retained)
-                * ppc64 requires kernel and some stacks to be in first segemnt
+                * On 64bit we split the RMO in half but cap it at half of
+                * a small SLB (128MB) since the crash kernel needs to place
+                * itself and some stacks to be in the first segment.
                 */
+               crashk_res.start = min(0x80000000ULL, (ppc64_rma_size / 2));
+#else
                crashk_res.start = KDUMP_KERNELBASE;
+#endif
        }
 
        crash_base = PAGE_ALIGN(crashk_res.start);
index d05ae42..564c1d8 100644 (file)
@@ -154,8 +154,12 @@ static int read_user_stack_64(unsigned long __user *ptr, unsigned long *ret)
            ((unsigned long)ptr & 7))
                return -EFAULT;
 
-       if (!__get_user_inatomic(*ret, ptr))
+       pagefault_disable();
+       if (!__get_user_inatomic(*ret, ptr)) {
+               pagefault_enable();
                return 0;
+       }
+       pagefault_enable();
 
        return read_user_stack_slow(ptr, ret, 8);
 }
@@ -166,8 +170,12 @@ static int read_user_stack_32(unsigned int __user *ptr, unsigned int *ret)
            ((unsigned long)ptr & 3))
                return -EFAULT;
 
-       if (!__get_user_inatomic(*ret, ptr))
+       pagefault_disable();
+       if (!__get_user_inatomic(*ret, ptr)) {
+               pagefault_enable();
                return 0;
+       }
+       pagefault_enable();
 
        return read_user_stack_slow(ptr, ret, 4);
 }
@@ -294,11 +302,17 @@ static inline int current_is_64bit(void)
  */
 static int read_user_stack_32(unsigned int __user *ptr, unsigned int *ret)
 {
+       int rc;
+
        if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned int) ||
            ((unsigned long)ptr & 3))
                return -EFAULT;
 
-       return __get_user_inatomic(*ret, ptr);
+       pagefault_disable();
+       rc = __get_user_inatomic(*ret, ptr);
+       pagefault_enable();
+
+       return rc;
 }
 
 static inline void perf_callchain_user_64(struct perf_callchain_entry *entry,
index c016033..a909f4e 100644 (file)
@@ -1020,7 +1020,7 @@ static unsigned long __init alloc_up(unsigned long size, unsigned long align)
        }
        if (addr == 0)
                return 0;
-       RELOC(alloc_bottom) = addr;
+       RELOC(alloc_bottom) = addr + size;
 
        prom_debug(" -> %x\n", addr);
        prom_debug("  alloc_bottom : %x\n", RELOC(alloc_bottom));
@@ -1830,11 +1830,13 @@ static void __init *make_room(unsigned long *mem_start, unsigned long *mem_end,
                if (room > DEVTREE_CHUNK_SIZE)
                        room = DEVTREE_CHUNK_SIZE;
                if (room < PAGE_SIZE)
-                       prom_panic("No memory for flatten_device_tree (no room)");
+                       prom_panic("No memory for flatten_device_tree "
+                                  "(no room)\n");
                chunk = alloc_up(room, 0);
                if (chunk == 0)
-                       prom_panic("No memory for flatten_device_tree (claim failed)");
-               *mem_end = RELOC(alloc_top);
+                       prom_panic("No memory for flatten_device_tree "
+                                  "(claim failed)\n");
+               *mem_end = chunk + room;
        }
 
        ret = (void *)*mem_start;
@@ -2042,7 +2044,7 @@ static void __init flatten_device_tree(void)
 
        /*
         * Check how much room we have between alloc top & bottom (+/- a
-        * few pages), crop to 4Mb, as this is our "chuck" size
+        * few pages), crop to 1MB, as this is our "chunk" size
         */
        room = RELOC(alloc_top) - RELOC(alloc_bottom) - 0x4000;
        if (room > DEVTREE_CHUNK_SIZE)
@@ -2053,7 +2055,7 @@ static void __init flatten_device_tree(void)
        mem_start = (unsigned long)alloc_up(room, PAGE_SIZE);
        if (mem_start == 0)
                prom_panic("Can't allocate initial device-tree chunk\n");
-       mem_end = RELOC(alloc_top);
+       mem_end = mem_start + room;
 
        /* Get root of tree */
        root = call_prom("peer", 1, 1, (phandle)0);
index 6dd3358..de29501 100644 (file)
@@ -1251,7 +1251,7 @@ BEGIN_FTR_SECTION
        reg = 0
        .rept   32
        li      r6,reg*16+VCPU_VSRS
-       stxvd2x reg,r6,r3
+       STXVD2X(reg,r6,r3)
        reg = reg + 1
        .endr
 FTR_SECTION_ELSE
@@ -1313,7 +1313,7 @@ BEGIN_FTR_SECTION
        reg = 0
        .rept   32
        li      r7,reg*16+VCPU_VSRS
-       lxvd2x  reg,r7,r4
+       LXVD2X(reg,r7,r4)
        reg = reg + 1
        .endr
 FTR_SECTION_ELSE
index d0af7fb..b9ba861 100644 (file)
@@ -24,7 +24,7 @@ source "arch/powerpc/platforms/wsp/Kconfig"
 
 config KVM_GUEST
        bool "KVM Guest support"
-       default y
+       default n
        ---help---
          This option enables various optimizations for running under the KVM
          hypervisor. Overhead for the kernel when not running inside KVM should
index e919007..0e86563 100644 (file)
@@ -181,7 +181,7 @@ static void dtl_stop(struct dtl *dtl)
 
        lppaca_of(dtl->cpu).dtl_enable_mask = 0x0;
 
-       unregister_dtl(hwcpu, __pa(dtl->buf));
+       unregister_dtl(hwcpu);
 }
 
 static u64 dtl_current_index(struct dtl *dtl)
index bc02885..83a3ca2 100644 (file)
@@ -135,7 +135,7 @@ static void pseries_mach_cpu_die(void)
                get_lppaca()->idle = 0;
 
                if (get_preferred_offline_state(cpu) == CPU_STATE_ONLINE) {
-                       unregister_slb_shadow(hwcpu, __pa(get_slb_shadow()));
+                       unregister_slb_shadow(hwcpu);
 
                        /*
                         * Call to start_secondary_resume() will not return.
@@ -150,7 +150,7 @@ static void pseries_mach_cpu_die(void)
        WARN_ON(get_preferred_offline_state(cpu) != CPU_STATE_OFFLINE);
 
        set_cpu_current_state(cpu, CPU_STATE_OFFLINE);
-       unregister_slb_shadow(hwcpu, __pa(get_slb_shadow()));
+       unregister_slb_shadow(hwcpu);
        rtas_stop_self();
 
        /* Should never get here... */
index c829e60..2c4dd1f 100644 (file)
@@ -212,17 +212,15 @@ static int __init ioei_init(void)
        struct device_node *np;
 
        ioei_check_exception_token = rtas_token("check-exception");
-       if (ioei_check_exception_token == RTAS_UNKNOWN_SERVICE) {
-               pr_warning("IO Event IRQ not supported on this system !\n");
+       if (ioei_check_exception_token == RTAS_UNKNOWN_SERVICE)
                return -ENODEV;
-       }
+
        np = of_find_node_by_path("/event-sources/ibm,io-events");
        if (np) {
                request_event_sources_irqs(np, ioei_interrupt, "IO_EVENT");
+               pr_info("IBM I/O event interrupts enabled\n");
                of_node_put(np);
        } else {
-               pr_err("io_event_irq: No ibm,io-events on system! "
-                      "IO Event interrupt disabled.\n");
                return -ENODEV;
        }
        return 0;
index 54cf3a4..7d94bdc 100644 (file)
@@ -25,20 +25,30 @@ static void pseries_kexec_cpu_down(int crash_shutdown, int secondary)
 {
        /* Don't risk a hypervisor call if we're crashing */
        if (firmware_has_feature(FW_FEATURE_SPLPAR) && !crash_shutdown) {
-               unsigned long addr;
+               int ret;
+               int cpu = smp_processor_id();
+               int hwcpu = hard_smp_processor_id();
 
-               addr = __pa(get_slb_shadow());
-               if (unregister_slb_shadow(hard_smp_processor_id(), addr))
-                       printk("SLB shadow buffer deregistration of "
-                              "cpu %u (hw_cpu_id %d) failed\n",
-                              smp_processor_id(),
-                              hard_smp_processor_id());
+               if (get_lppaca()->dtl_enable_mask) {
+                       ret = unregister_dtl(hwcpu);
+                       if (ret) {
+                               pr_err("WARNING: DTL deregistration for cpu "
+                                      "%d (hw %d) failed with %d\n",
+                                      cpu, hwcpu, ret);
+                       }
+               }
+
+               ret = unregister_slb_shadow(hwcpu);
+               if (ret) {
+                       pr_err("WARNING: SLB shadow buffer deregistration "
+                              "for cpu %d (hw %d) failed with %d\n",
+                              cpu, hwcpu, ret);
+               }
 
-               addr = __pa(get_lppaca());
-               if (unregister_vpa(hard_smp_processor_id(), addr)) {
-                       printk("VPA deregistration of cpu %u (hw_cpu_id %d) "
-                                       "failed\n", smp_processor_id(),
-                                       hard_smp_processor_id());
+               ret = unregister_vpa(hwcpu);
+               if (ret) {
+                       pr_err("WARNING: VPA deregistration for cpu %d "
+                              "(hw %d) failed with %d\n", cpu, hwcpu, ret);
                }
        }
 }
index f7205d3..c9a29da 100644 (file)
@@ -67,9 +67,8 @@ void vpa_init(int cpu)
        ret = register_vpa(hwcpu, addr);
 
        if (ret) {
-               printk(KERN_ERR "WARNING: vpa_init: VPA registration for "
-                               "cpu %d (hw %d) of area %lx returns %ld\n",
-                               cpu, hwcpu, addr, ret);
+               pr_err("WARNING: VPA registration for cpu %d (hw %d) of area "
+                      "%lx failed with %ld\n", cpu, hwcpu, addr, ret);
                return;
        }
        /*
@@ -80,10 +79,9 @@ void vpa_init(int cpu)
        if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
                ret = register_slb_shadow(hwcpu, addr);
                if (ret)
-                       printk(KERN_ERR
-                              "WARNING: vpa_init: SLB shadow buffer "
-                              "registration for cpu %d (hw %d) of area %lx "
-                              "returns %ld\n", cpu, hwcpu, addr, ret);
+                       pr_err("WARNING: SLB shadow buffer registration for "
+                              "cpu %d (hw %d) of area %lx failed with %ld\n",
+                              cpu, hwcpu, addr, ret);
        }
 
        /*
@@ -100,8 +98,9 @@ void vpa_init(int cpu)
                dtl->enqueue_to_dispatch_time = DISPATCH_LOG_BYTES;
                ret = register_dtl(hwcpu, __pa(dtl));
                if (ret)
-                       pr_warn("DTL registration failed for cpu %d (%ld)\n",
-                               cpu, ret);
+                       pr_err("WARNING: DTL registration of cpu %d (hw %d) "
+                              "failed with %ld\n", smp_processor_id(),
+                              hwcpu, ret);
                lppaca_of(cpu).dtl_enable_mask = 2;
        }
 }
@@ -204,7 +203,7 @@ static void pSeries_lpar_hptab_clear(void)
                unsigned long ptel;
        } ptes[4];
        long lpar_rc;
-       int i, j;
+       unsigned long i, j;
 
        /* Read in batches of 4,
         * invalidate only valid entries not in the VRMA
index 4bf2120..41c24c1 100644 (file)
@@ -53,9 +53,9 @@ static inline long vpa_call(unsigned long flags, unsigned long cpu,
        return plpar_hcall_norets(H_REGISTER_VPA, flags, cpu, vpa);
 }
 
-static inline long unregister_vpa(unsigned long cpu, unsigned long vpa)
+static inline long unregister_vpa(unsigned long cpu)
 {
-       return vpa_call(0x5, cpu, vpa);
+       return vpa_call(0x5, cpu, 0);
 }
 
 static inline long register_vpa(unsigned long cpu, unsigned long vpa)
@@ -63,9 +63,9 @@ static inline long register_vpa(unsigned long cpu, unsigned long vpa)
        return vpa_call(0x1, cpu, vpa);
 }
 
-static inline long unregister_slb_shadow(unsigned long cpu, unsigned long vpa)
+static inline long unregister_slb_shadow(unsigned long cpu)
 {
-       return vpa_call(0x7, cpu, vpa);
+       return vpa_call(0x7, cpu, 0);
 }
 
 static inline long register_slb_shadow(unsigned long cpu, unsigned long vpa)
@@ -73,9 +73,9 @@ static inline long register_slb_shadow(unsigned long cpu, unsigned long vpa)
        return vpa_call(0x3, cpu, vpa);
 }
 
-static inline long unregister_dtl(unsigned long cpu, unsigned long vpa)
+static inline long unregister_dtl(unsigned long cpu)
 {
-       return vpa_call(0x6, cpu, vpa);
+       return vpa_call(0x6, cpu, 0);
 }
 
 static inline long register_dtl(unsigned long cpu, unsigned long vpa)
index d00e529..0969fd9 100644 (file)
@@ -324,8 +324,9 @@ static int alloc_dispatch_logs(void)
        dtl->enqueue_to_dispatch_time = DISPATCH_LOG_BYTES;
        ret = register_dtl(hard_smp_processor_id(), __pa(dtl));
        if (ret)
-               pr_warn("DTL registration failed for boot cpu %d (%d)\n",
-                       smp_processor_id(), ret);
+               pr_err("WARNING: DTL registration of cpu %d (hw %d) failed "
+                      "with %d\n", smp_processor_id(),
+                      hard_smp_processor_id(), ret);
        get_paca()->lppaca_ptr->dtl_enable_mask = 2;
 
        return 0;
index a59ba96..dbfe96b 100644 (file)
@@ -655,8 +655,6 @@ struct ppc4xx_pciex_hwops
 
 static struct ppc4xx_pciex_hwops *ppc4xx_pciex_hwops;
 
-#ifdef CONFIG_44x
-
 static int __init ppc4xx_pciex_wait_on_sdr(struct ppc4xx_pciex_port *port,
                                           unsigned int sdr_offset,
                                           unsigned int mask,
@@ -688,6 +686,7 @@ static int __init ppc4xx_pciex_port_reset_sdr(struct ppc4xx_pciex_port *port)
        return 0;
 }
 
+
 static void __init ppc4xx_pciex_check_link_sdr(struct ppc4xx_pciex_port *port)
 {
        printk(KERN_INFO "PCIE%d: Checking link...\n", port->index);
@@ -718,6 +717,8 @@ static void __init ppc4xx_pciex_check_link_sdr(struct ppc4xx_pciex_port *port)
                printk(KERN_INFO "PCIE%d: No device detected.\n", port->index);
 }
 
+#ifdef CONFIG_44x
+
 /* Check various reset bits of the 440SPe PCIe core */
 static int __init ppc440spe_pciex_check_reset(struct device_node *np)
 {
index c03fef7..ed5cb5a 100644 (file)
@@ -81,6 +81,7 @@ config S390
        select INIT_ALL_POSSIBLE
        select HAVE_IRQ_WORK
        select HAVE_PERF_EVENTS
+       select ARCH_HAVE_NMI_SAFE_CMPXCHG
        select HAVE_KERNEL_GZIP
        select HAVE_KERNEL_BZIP2
        select HAVE_KERNEL_LZMA
@@ -273,11 +274,11 @@ config MARCH_Z10
          on older machines.
 
 config MARCH_Z196
-       bool "IBM zEnterprise 196"
+       bool "IBM zEnterprise 114 and 196"
        help
-         Select this to enable optimizations for IBM zEnterprise 196
-         (2817 series). The kernel will be slightly faster but will not work
-         on older machines.
+         Select this to enable optimizations for IBM zEnterprise 114 and 196
+         (2818 and 2817 series). The kernel will be slightly faster but will
+         not work on older machines.
 
 endchoice
 
index 5e95d95..97cc440 100644 (file)
@@ -167,5 +167,6 @@ enum diag308_rc {
 };
 
 extern int diag308(unsigned long subcode, void *addr);
+extern void diag308_reset(void);
 
 #endif /* _ASM_S390_IPL_H */
index f26280d..e85c911 100644 (file)
@@ -18,6 +18,7 @@ void system_call(void);
 void pgm_check_handler(void);
 void mcck_int_handler(void);
 void io_int_handler(void);
+void psw_restart_int_handler(void);
 
 #ifdef CONFIG_32BIT
 
@@ -150,7 +151,10 @@ struct _lowcore {
         */
        __u32   ipib;                           /* 0x0e00 */
        __u32   ipib_checksum;                  /* 0x0e04 */
-       __u8    pad_0x0e08[0x0f00-0x0e08];      /* 0x0e08 */
+
+       /* 64 bit save area */
+       __u64   save_area_64;                   /* 0x0e08 */
+       __u8    pad_0x0e10[0x0f00-0x0e10];      /* 0x0e10 */
 
        /* Extended facility list */
        __u64   stfle_fac_list[32];             /* 0x0f00 */
@@ -286,7 +290,10 @@ struct _lowcore {
         */
        __u64   ipib;                           /* 0x0e00 */
        __u32   ipib_checksum;                  /* 0x0e08 */
-       __u8    pad_0x0e0c[0x0f00-0x0e0c];      /* 0x0e0c */
+
+       /* 64 bit save area */
+       __u64   save_area_64;                   /* 0x0e0c */
+       __u8    pad_0x0e14[0x0f00-0x0e14];      /* 0x0e14 */
 
        /* Extended facility list */
        __u64   stfle_fac_list[32];             /* 0x0f00 */
index 55dfcc8..a4b6229 100644 (file)
@@ -119,14 +119,12 @@ struct stack_frame {
  * Do necessary setup to start up a new thread.
  */
 #define start_thread(regs, new_psw, new_stackp) do {           \
-       set_fs(USER_DS);                                        \
        regs->psw.mask  = psw_user_bits;                        \
        regs->psw.addr  = new_psw | PSW_ADDR_AMODE;             \
        regs->gprs[15]  = new_stackp;                           \
 } while (0)
 
 #define start_thread31(regs, new_psw, new_stackp) do {         \
-       set_fs(USER_DS);                                        \
        regs->psw.mask  = psw_user32_bits;                      \
        regs->psw.addr  = new_psw | PSW_ADDR_AMODE;             \
        regs->gprs[15]  = new_stackp;                           \
index d382629..6582f69 100644 (file)
@@ -113,6 +113,7 @@ extern void pfault_fini(void);
 
 extern void cmma_init(void);
 extern int memcpy_real(void *, void *, size_t);
+extern void copy_to_absolute_zero(void *dest, void *src, size_t count);
 
 #define finish_arch_switch(prev) do {                                       \
        set_fs(current->thread.mm_segment);                                  \
index 05d8f38..532fd43 100644 (file)
@@ -27,12 +27,9 @@ int main(void)
        BLANK();
        DEFINE(__TASK_pid, offsetof(struct task_struct, pid));
        BLANK();
-       DEFINE(__THREAD_per_cause,
-              offsetof(struct task_struct, thread.per_event.cause));
-       DEFINE(__THREAD_per_address,
-              offsetof(struct task_struct, thread.per_event.address));
-       DEFINE(__THREAD_per_paid,
-              offsetof(struct task_struct, thread.per_event.paid));
+       DEFINE(__THREAD_per_cause, offsetof(struct task_struct, thread.per_event.cause));
+       DEFINE(__THREAD_per_address, offsetof(struct task_struct, thread.per_event.address));
+       DEFINE(__THREAD_per_paid, offsetof(struct task_struct, thread.per_event.paid));
        BLANK();
        DEFINE(__TI_task, offsetof(struct thread_info, task));
        DEFINE(__TI_domain, offsetof(struct thread_info, exec_domain));
@@ -142,6 +139,7 @@ int main(void)
        DEFINE(__LC_FPREGS_SAVE_AREA, offsetof(struct _lowcore, floating_pt_save_area));
        DEFINE(__LC_GPREGS_SAVE_AREA, offsetof(struct _lowcore, gpregs_save_area));
        DEFINE(__LC_CREGS_SAVE_AREA, offsetof(struct _lowcore, cregs_save_area));
+       DEFINE(__LC_SAVE_AREA_64, offsetof(struct _lowcore, save_area_64));
 #ifdef CONFIG_32BIT
        DEFINE(SAVE_AREA_BASE, offsetof(struct _lowcore, extended_save_area_addr));
 #else /* CONFIG_32BIT */
index 209938c..2554356 100644 (file)
@@ -76,6 +76,42 @@ s390_base_pgm_handler_fn:
        .quad   0
        .previous
 
+#
+# Calls diag 308 subcode 1 and continues execution
+#
+# The following conditions must be ensured before calling this function:
+# * Prefix register = 0
+# * Lowcore protection is disabled
+#
+ENTRY(diag308_reset)
+       larl    %r4,.Lctlregs           # Save control registers
+       stctg   %c0,%c15,0(%r4)
+       larl    %r4,.Lrestart_psw       # Setup restart PSW at absolute 0
+       lghi    %r3,0
+       lg      %r4,0(%r4)              # Save PSW
+       sturg   %r4,%r3                 # Use sturg, because of large pages
+       lghi    %r1,1
+       diag    %r1,%r1,0x308
+.Lrestart_part2:
+       lhi     %r0,0                   # Load r0 with zero
+       lhi     %r1,2                   # Use mode 2 = ESAME (dump)
+       sigp    %r1,%r0,0x12            # Switch to ESAME mode
+       sam64                           # Switch to 64 bit addressing mode
+       larl    %r4,.Lctlregs           # Restore control registers
+       lctlg   %c0,%c15,0(%r4)
+       br      %r14
+.align 16
+.Lrestart_psw:
+       .long   0x00080000,0x80000000 + .Lrestart_part2
+
+       .section .bss
+.align 8
+.Lctlregs:
+       .rept   16
+       .quad   0
+       .endr
+       .previous
+
 #else /* CONFIG_64BIT */
 
 ENTRY(s390_base_mcck_handler)
index eee9998..a9a285b 100644 (file)
@@ -380,20 +380,13 @@ asmlinkage long sys32_sigreturn(void)
                goto badframe;
        if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE32))
                goto badframe;
-
        sigdelsetmask(&set, ~_BLOCKABLE);
-       spin_lock_irq(&current->sighand->siglock);
-       current->blocked = set;
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-
+       set_current_blocked(&set);
        if (restore_sigregs32(regs, &frame->sregs))
                goto badframe;
        if (restore_sigregs_gprs_high(regs, frame->gprs_high))
                goto badframe;
-
        return regs->gprs[2];
-
 badframe:
        force_sig(SIGSEGV, current);
        return 0;
@@ -413,31 +406,22 @@ asmlinkage long sys32_rt_sigreturn(void)
                goto badframe;
        if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
                goto badframe;
-
        sigdelsetmask(&set, ~_BLOCKABLE);
-       spin_lock_irq(&current->sighand->siglock);
-       current->blocked = set;
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-
+       set_current_blocked(&set);
        if (restore_sigregs32(regs, &frame->uc.uc_mcontext))
                goto badframe;
        if (restore_sigregs_gprs_high(regs, frame->gprs_high))
                goto badframe;
-
        err = __get_user(ss_sp, &frame->uc.uc_stack.ss_sp);
        st.ss_sp = compat_ptr(ss_sp);
        err |= __get_user(st.ss_size, &frame->uc.uc_stack.ss_size);
        err |= __get_user(st.ss_flags, &frame->uc.uc_stack.ss_flags);
        if (err)
                goto badframe; 
-
        set_fs (KERNEL_DS);
        do_sigaltstack((stack_t __force __user *)&st, NULL, regs->gprs[15]);
        set_fs (old_fs);
-
        return regs->gprs[2];
-
 badframe:
        force_sig(SIGSEGV, current);
        return 0;
@@ -605,10 +589,10 @@ give_sigsegv:
  * OK, we're invoking a handler
  */    
 
-int
-handle_signal32(unsigned long sig, struct k_sigaction *ka,
-               siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
+int handle_signal32(unsigned long sig, struct k_sigaction *ka,
+                   siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
 {
+       sigset_t blocked;
        int ret;
 
        /* Set up the stack frame */
@@ -616,15 +600,12 @@ handle_signal32(unsigned long sig, struct k_sigaction *ka,
                ret = setup_rt_frame32(sig, ka, info, oldset, regs);
        else
                ret = setup_frame32(sig, ka, oldset, regs);
-
-       if (ret == 0) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
-               if (!(ka->sa.sa_flags & SA_NODEFER))
-                       sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
-       return ret;
+       if (ret)
+               return ret;
+       sigorsets(&blocked, &current->blocked, &ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
+               sigaddset(&blocked, sig);
+       set_current_blocked(&blocked);
+       return 0;
 }
 
index 3eab7cf..02ec8fe 100644 (file)
@@ -849,6 +849,34 @@ restart_crash:
 restart_go:
 #endif
 
+#
+# PSW restart interrupt handler
+#
+ENTRY(psw_restart_int_handler)
+       st      %r15,__LC_SAVE_AREA_64(%r0)     # save r15
+       basr    %r15,0
+0:     l       %r15,.Lrestart_stack-0b(%r15)   # load restart stack
+       l       %r15,0(%r15)
+       ahi     %r15,-SP_SIZE                   # make room for pt_regs
+       stm     %r0,%r14,SP_R0(%r15)            # store gprs %r0-%r14 to stack
+       mvc     SP_R15(4,%r15),__LC_SAVE_AREA_64(%r0)# store saved %r15 to stack
+       mvc     SP_PSW(8,%r15),__LC_RST_OLD_PSW(%r0) # store restart old psw
+       xc      __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # set backchain to 0
+       basr    %r14,0
+1:     l       %r14,.Ldo_restart-1b(%r14)
+       basr    %r14,%r14
+
+       basr    %r14,0                          # load disabled wait PSW if
+2:     lpsw    restart_psw_crash-2b(%r14)      # do_restart returns
+       .align 4
+.Ldo_restart:
+       .long   do_restart
+.Lrestart_stack:
+       .long   restart_stack
+       .align 8
+restart_psw_crash:
+       .long   0x000a0000,0x00000000 + restart_psw_crash
+
        .section .kprobes.text, "ax"
 
 #ifdef CONFIG_CHECK_STACK
index 7a0fd42..5f729d6 100644 (file)
@@ -865,6 +865,26 @@ restart_crash:
 restart_go:
 #endif
 
+#
+# PSW restart interrupt handler
+#
+ENTRY(psw_restart_int_handler)
+       stg     %r15,__LC_SAVE_AREA_64(%r0)     # save r15
+       larl    %r15,restart_stack              # load restart stack
+       lg      %r15,0(%r15)
+       aghi    %r15,-SP_SIZE                   # make room for pt_regs
+       stmg    %r0,%r14,SP_R0(%r15)            # store gprs %r0-%r14 to stack
+       mvc     SP_R15(8,%r15),__LC_SAVE_AREA_64(%r0)# store saved %r15 to stack
+       mvc     SP_PSW(16,%r15),__LC_RST_OLD_PSW(%r0)# store restart old psw
+       xc      __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) # set backchain to 0
+       brasl   %r14,do_restart
+
+       larl    %r14,restart_psw_crash          # load disabled wait PSW if
+       lpswe   0(%r14)                         # do_restart returns
+       .align 8
+restart_psw_crash:
+       .quad   0x0002000080000000,0x0000000000000000 + restart_psw_crash
+
        .section .kprobes.text, "ax"
 
 #ifdef CONFIG_CHECK_STACK
index a689070..04361d5 100644 (file)
  * - halt
  * - power off
  * - reipl
+ * - restart
  */
 #define ON_PANIC_STR           "on_panic"
 #define ON_HALT_STR            "on_halt"
 #define ON_POFF_STR            "on_poff"
 #define ON_REIPL_STR           "on_reboot"
+#define ON_RESTART_STR         "on_restart"
 
 struct shutdown_action;
 struct shutdown_trigger {
@@ -1544,17 +1546,20 @@ static char vmcmd_on_reboot[128];
 static char vmcmd_on_panic[128];
 static char vmcmd_on_halt[128];
 static char vmcmd_on_poff[128];
+static char vmcmd_on_restart[128];
 
 DEFINE_IPL_ATTR_STR_RW(vmcmd, on_reboot, "%s\n", "%s\n", vmcmd_on_reboot);
 DEFINE_IPL_ATTR_STR_RW(vmcmd, on_panic, "%s\n", "%s\n", vmcmd_on_panic);
 DEFINE_IPL_ATTR_STR_RW(vmcmd, on_halt, "%s\n", "%s\n", vmcmd_on_halt);
 DEFINE_IPL_ATTR_STR_RW(vmcmd, on_poff, "%s\n", "%s\n", vmcmd_on_poff);
+DEFINE_IPL_ATTR_STR_RW(vmcmd, on_restart, "%s\n", "%s\n", vmcmd_on_restart);
 
 static struct attribute *vmcmd_attrs[] = {
        &sys_vmcmd_on_reboot_attr.attr,
        &sys_vmcmd_on_panic_attr.attr,
        &sys_vmcmd_on_halt_attr.attr,
        &sys_vmcmd_on_poff_attr.attr,
+       &sys_vmcmd_on_restart_attr.attr,
        NULL,
 };
 
@@ -1576,6 +1581,8 @@ static void vmcmd_run(struct shutdown_trigger *trigger)
                cmd = vmcmd_on_halt;
        else if (strcmp(trigger->name, ON_POFF_STR) == 0)
                cmd = vmcmd_on_poff;
+       else if (strcmp(trigger->name, ON_RESTART_STR) == 0)
+               cmd = vmcmd_on_restart;
        else
                return;
 
@@ -1707,6 +1714,34 @@ static void do_panic(void)
        stop_run(&on_panic_trigger);
 }
 
+/* on restart */
+
+static struct shutdown_trigger on_restart_trigger = {ON_RESTART_STR,
+       &reipl_action};
+
+static ssize_t on_restart_show(struct kobject *kobj,
+                              struct kobj_attribute *attr, char *page)
+{
+       return sprintf(page, "%s\n", on_restart_trigger.action->name);
+}
+
+static ssize_t on_restart_store(struct kobject *kobj,
+                               struct kobj_attribute *attr,
+                               const char *buf, size_t len)
+{
+       return set_trigger(buf, &on_restart_trigger, len);
+}
+
+static struct kobj_attribute on_restart_attr =
+       __ATTR(on_restart, 0644, on_restart_show, on_restart_store);
+
+void do_restart(void)
+{
+       smp_send_stop();
+       on_restart_trigger.action->fn(&on_restart_trigger);
+       stop_run(&on_restart_trigger);
+}
+
 /* on halt */
 
 static struct shutdown_trigger on_halt_trigger = {ON_HALT_STR, &stop_action};
@@ -1783,7 +1818,9 @@ static void __init shutdown_triggers_init(void)
        if (sysfs_create_file(&shutdown_actions_kset->kobj,
                              &on_poff_attr.attr))
                goto fail;
-
+       if (sysfs_create_file(&shutdown_actions_kset->kobj,
+                             &on_restart_attr.attr))
+               goto fail;
        return;
 fail:
        panic("shutdown_triggers_init failed\n");
@@ -1959,6 +1996,12 @@ static void do_reset_calls(void)
 {
        struct reset_call *reset;
 
+#ifdef CONFIG_64BIT
+       if (diag308_set_works) {
+               diag308_reset();
+               return;
+       }
+#endif
        list_for_each_entry(reset, &rcall, list)
                reset->fn();
 }
index 78eb7cf..e690975 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *    Copyright IBM Corp 2000,2009
+ *    Copyright IBM Corp 2000,2011
  *    Author(s): Holger Smolinski <Holger.Smolinski@de.ibm.com>,
  *              Denis Joseph Barrow,
  */
@@ -7,6 +7,64 @@
 #include <linux/linkage.h>
 #include <asm/asm-offsets.h>
 
+#
+# store_status
+#
+# Prerequisites to run this function:
+# - Prefix register is set to zero
+# - Original prefix register is stored in "dump_prefix_page"
+# - Lowcore protection is off
+#
+ENTRY(store_status)
+       /* Save register one and load save area base */
+       stg     %r1,__LC_SAVE_AREA_64(%r0)
+       lghi    %r1,SAVE_AREA_BASE
+       /* General purpose registers */
+       stmg    %r0,%r15,__LC_GPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
+       lg      %r2,__LC_SAVE_AREA_64(%r0)
+       stg     %r2,__LC_GPREGS_SAVE_AREA-SAVE_AREA_BASE+8(%r1)
+       /* Control registers */
+       stctg   %c0,%c15,__LC_CREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
+       /* Access registers */
+       stam    %a0,%a15,__LC_AREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
+       /* Floating point registers */
+       std     %f0, 0x00 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
+       std     %f1, 0x08 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
+       std     %f2, 0x10 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
+       std     %f3, 0x18 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
+       std     %f4, 0x20 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
+       std     %f5, 0x28 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
+       std     %f6, 0x30 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
+       std     %f7, 0x38 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
+       std     %f8, 0x40 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
+       std     %f9, 0x48 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
+       std     %f10,0x50 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
+       std     %f11,0x58 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
+       std     %f12,0x60 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
+       std     %f13,0x68 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
+       std     %f14,0x70 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
+       std     %f15,0x78 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
+       /* Floating point control register */
+       stfpc   __LC_FP_CREG_SAVE_AREA-SAVE_AREA_BASE(%r1)
+       /* CPU timer */
+       stpt    __LC_CPU_TIMER_SAVE_AREA-SAVE_AREA_BASE(%r1)
+       /* Saved prefix register */
+       larl    %r2,dump_prefix_page
+       mvc     __LC_PREFIX_SAVE_AREA-SAVE_AREA_BASE(4,%r1),0(%r2)
+       /* Clock comparator - seven bytes */
+       larl    %r2,.Lclkcmp
+       stckc   0(%r2)
+       mvc     __LC_CLOCK_COMP_SAVE_AREA-SAVE_AREA_BASE + 1(7,%r1),1(%r2)
+       /* Program status word */
+       epsw    %r2,%r3
+       st      %r2,__LC_PSW_SAVE_AREA-SAVE_AREA_BASE + 0(%r1)
+       st      %r3,__LC_PSW_SAVE_AREA-SAVE_AREA_BASE + 4(%r1)
+       larl    %r2,store_status
+       stg     %r2,__LC_PSW_SAVE_AREA-SAVE_AREA_BASE + 8(%r1)
+       br      %r14
+.align 8
+.Lclkcmp:      .quad   0x0000000000000000
+
 #
 # do_reipl_asm
 # Parameter: r2 = schid of reipl device
 ENTRY(do_reipl_asm)
                basr    %r13,0
 .Lpg0:         lpswe   .Lnewpsw-.Lpg0(%r13)
-.Lpg1:         # do store status of all registers
-
-               stg     %r1,.Lregsave-.Lpg0(%r13)
-               lghi    %r1,0x1000
-               stmg    %r0,%r15,__LC_GPREGS_SAVE_AREA-0x1000(%r1)
-               lg      %r0,.Lregsave-.Lpg0(%r13)
-               stg     %r0,__LC_GPREGS_SAVE_AREA-0x1000+8(%r1)
-               stctg   %c0,%c15,__LC_CREGS_SAVE_AREA-0x1000(%r1)
-               stam    %a0,%a15,__LC_AREGS_SAVE_AREA-0x1000(%r1)
-               lg      %r10,.Ldump_pfx-.Lpg0(%r13)
-               mvc     __LC_PREFIX_SAVE_AREA-0x1000(4,%r1),0(%r10)
-               stfpc   __LC_FP_CREG_SAVE_AREA-0x1000(%r1)
-               stckc   .Lclkcmp-.Lpg0(%r13)
-               mvc     __LC_CLOCK_COMP_SAVE_AREA-0x1000(7,%r1),.Lclkcmp-.Lpg0(%r13)
-               stpt    __LC_CPU_TIMER_SAVE_AREA-0x1000(%r1)
-               stg     %r13, __LC_PSW_SAVE_AREA-0x1000+8(%r1)
+.Lpg1:         brasl   %r14,store_status
 
                lctlg   %c6,%c6,.Lall-.Lpg0(%r13)
                lgr     %r1,%r2
@@ -67,10 +110,7 @@ ENTRY(do_reipl_asm)
                st      %r14,.Ldispsw+12-.Lpg0(%r13)
                lpswe   .Ldispsw-.Lpg0(%r13)
                .align  8
-.Lclkcmp:      .quad   0x0000000000000000
 .Lall:         .quad   0x00000000ff000000
-.Ldump_pfx:    .quad   dump_prefix_page
-.Lregsave:     .quad   0x0000000000000000
                .align  16
 /*
  * These addresses have to be 31 bit otherwise
index 0c35dee..7b371c3 100644 (file)
@@ -346,7 +346,7 @@ setup_lowcore(void)
        lc = __alloc_bootmem_low(LC_PAGES * PAGE_SIZE, LC_PAGES * PAGE_SIZE, 0);
        lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
        lc->restart_psw.addr =
-               PSW_ADDR_AMODE | (unsigned long) restart_int_handler;
+               PSW_ADDR_AMODE | (unsigned long) psw_restart_int_handler;
        if (user_mode != HOME_SPACE_MODE)
                lc->restart_psw.mask |= PSW_ASC_HOME;
        lc->external_new_psw.mask = psw_kernel_bits;
@@ -529,6 +529,27 @@ static void __init setup_memory_end(void)
                memory_end = memory_size;
 }
 
+void *restart_stack __attribute__((__section__(".data")));
+
+/*
+ * Setup new PSW and allocate stack for PSW restart interrupt
+ */
+static void __init setup_restart_psw(void)
+{
+       psw_t psw;
+
+       restart_stack = __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0);
+       restart_stack += ASYNC_SIZE;
+
+       /*
+        * Setup restart PSW for absolute zero lowcore. This is necesary
+        * if PSW restart is done on an offline CPU that has lowcore zero
+        */
+       psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
+       psw.addr = PSW_ADDR_AMODE | (unsigned long) psw_restart_int_handler;
+       copy_to_absolute_zero(&S390_lowcore.restart_psw, &psw, sizeof(psw));
+}
+
 static void __init
 setup_memory(void)
 {
@@ -731,6 +752,7 @@ static void __init setup_hwcaps(void)
                strcpy(elf_platform, "z10");
                break;
        case 0x2817:
+       case 0x2818:
                strcpy(elf_platform, "z196");
                break;
        }
@@ -792,6 +814,7 @@ setup_arch(char **cmdline_p)
        setup_addressing_mode();
        setup_memory();
        setup_resources();
+       setup_restart_psw();
        setup_lowcore();
 
         cpu_init();
index abbb3c3..9a40e1c 100644 (file)
@@ -57,17 +57,15 @@ typedef struct
  */
 SYSCALL_DEFINE3(sigsuspend, int, history0, int, history1, old_sigset_t, mask)
 {
-       mask &= _BLOCKABLE;
-       spin_lock_irq(&current->sighand->siglock);
-       current->saved_sigmask = current->blocked;
-       siginitset(&current->blocked, mask);
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
+       sigset_t blocked;
 
+       current->saved_sigmask = current->blocked;
+       mask &= _BLOCKABLE;
+       siginitset(&blocked, mask);
+       set_current_blocked(&blocked);
        set_current_state(TASK_INTERRUPTIBLE);
        schedule();
-       set_thread_flag(TIF_RESTORE_SIGMASK);
-
+       set_restore_sigmask();
        return -ERESTARTNOHAND;
 }
 
@@ -172,18 +170,11 @@ SYSCALL_DEFINE0(sigreturn)
                goto badframe;
        if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE))
                goto badframe;
-
        sigdelsetmask(&set, ~_BLOCKABLE);
-       spin_lock_irq(&current->sighand->siglock);
-       current->blocked = set;
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-
+       set_current_blocked(&set);
        if (restore_sigregs(regs, &frame->sregs))
                goto badframe;
-
        return regs->gprs[2];
-
 badframe:
        force_sig(SIGSEGV, current);
        return 0;
@@ -199,21 +190,14 @@ SYSCALL_DEFINE0(rt_sigreturn)
                goto badframe;
        if (__copy_from_user(&set.sig, &frame->uc.uc_sigmask, sizeof(set)))
                goto badframe;
-
        sigdelsetmask(&set, ~_BLOCKABLE);
-       spin_lock_irq(&current->sighand->siglock);
-       current->blocked = set;
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-
+       set_current_blocked(&set);
        if (restore_sigregs(regs, &frame->uc.uc_mcontext))
                goto badframe;
-
        if (do_sigaltstack(&frame->uc.uc_stack, NULL,
                           regs->gprs[15]) == -EFAULT)
                goto badframe;
        return regs->gprs[2];
-
 badframe:
        force_sig(SIGSEGV, current);
        return 0;
@@ -385,14 +369,11 @@ give_sigsegv:
        return -EFAULT;
 }
 
-/*
- * OK, we're invoking a handler
- */    
-
-static int
-handle_signal(unsigned long sig, struct k_sigaction *ka,
-             siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
+static int handle_signal(unsigned long sig, struct k_sigaction *ka,
+                        siginfo_t *info, sigset_t *oldset,
+                        struct pt_regs *regs)
 {
+       sigset_t blocked;
        int ret;
 
        /* Set up the stack frame */
@@ -400,17 +381,13 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
                ret = setup_rt_frame(sig, ka, info, oldset, regs);
        else
                ret = setup_frame(sig, ka, oldset, regs);
-
-       if (ret == 0) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
-               if (!(ka->sa.sa_flags & SA_NODEFER))
-                       sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
-
-       return ret;
+       if (ret)
+               return ret;
+       sigorsets(&blocked, &current->blocked, &ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
+               sigaddset(&blocked, sig);
+       set_current_blocked(&blocked);
+       return 0;
 }
 
 /*
index a6d85c0..6ab16ac 100644 (file)
@@ -452,23 +452,27 @@ out:
  */
 int __cpuinit start_secondary(void *cpuvoid)
 {
-       /* Setup the cpu */
        cpu_init();
        preempt_disable();
-       /* Enable TOD clock interrupts on the secondary cpu. */
        init_cpu_timer();
-       /* Enable cpu timer interrupts on the secondary cpu. */
        init_cpu_vtimer();
-       /* Enable pfault pseudo page faults on this cpu. */
        pfault_init();
 
-       /* call cpu notifiers */
        notify_cpu_starting(smp_processor_id());
-       /* Mark this cpu as online */
        ipi_call_lock();
        set_cpu_online(smp_processor_id(), true);
        ipi_call_unlock();
-       /* Switch on interrupts */
+       __ctl_clear_bit(0, 28); /* Disable lowcore protection */
+       S390_lowcore.restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
+       S390_lowcore.restart_psw.addr =
+               PSW_ADDR_AMODE | (unsigned long) psw_restart_int_handler;
+       __ctl_set_bit(0, 28); /* Enable lowcore protection */
+       /*
+        * Wait until the cpu which brought this one up marked it
+        * active before enabling interrupts.
+        */
+       while (!cpumask_test_cpu(smp_processor_id(), cpu_active_mask))
+               cpu_relax();
        local_irq_enable();
        /* cpu_idle will call schedule for us */
        cpu_idle();
@@ -507,7 +511,11 @@ static int __cpuinit smp_alloc_lowcore(int cpu)
        memset((char *)lowcore + 512, 0, sizeof(*lowcore) - 512);
        lowcore->async_stack = async_stack + ASYNC_SIZE;
        lowcore->panic_stack = panic_stack + PAGE_SIZE;
-
+       lowcore->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
+       lowcore->restart_psw.addr =
+               PSW_ADDR_AMODE | (unsigned long) restart_int_handler;
+       if (user_mode != HOME_SPACE_MODE)
+               lowcore->restart_psw.mask |= PSW_ASC_HOME;
 #ifndef CONFIG_64BIT
        if (MACHINE_HAS_IEEE) {
                unsigned long save_area;
index 51e5cd9..5dbbaa6 100644 (file)
@@ -85,3 +85,19 @@ int memcpy_real(void *dest, void *src, size_t count)
        arch_local_irq_restore(flags);
        return rc;
 }
+
+/*
+ * Copy memory to absolute zero
+ */
+void copy_to_absolute_zero(void *dest, void *src, size_t count)
+{
+       unsigned long cr0;
+
+       BUG_ON((unsigned long) dest + count >= sizeof(struct _lowcore));
+       preempt_disable();
+       __ctl_store(cr0, 0, 0);
+       __ctl_clear_bit(0, 28); /* disable lowcore protection */
+       memcpy_real(dest + store_prefix(), src, count);
+       __ctl_load(cr0, 0, 0);
+       preempt_enable();
+}
index 2adb239..4d1f2bc 100644 (file)
@@ -528,6 +528,7 @@ static inline void page_table_free_pgste(unsigned long *table)
 static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm,
                                                    unsigned long vmaddr)
 {
+       return NULL;
 }
 
 static inline void page_table_free_pgste(unsigned long *table)
index 748ff19..ff9177c 100644 (file)
@@ -11,6 +11,7 @@ config SUPERH
        select HAVE_DMA_ATTRS
        select HAVE_IRQ_WORK
        select HAVE_PERF_EVENTS
+       select ARCH_HAVE_NMI_SAFE_CMPXCHG if (GUSA_RB || CPU_SH4A)
        select PERF_USE_VMALLOC
        select HAVE_KERNEL_GZIP
        select HAVE_KERNEL_BZIP2
index e3d8170..99385d0 100644 (file)
@@ -173,6 +173,7 @@ core-$(CONFIG_HD6446X_SERIES)       += arch/sh/cchips/hd6446x/
 cpuincdir-$(CONFIG_CPU_SH2A)   += cpu-sh2a
 cpuincdir-$(CONFIG_CPU_SH2)    += cpu-sh2
 cpuincdir-$(CONFIG_CPU_SH3)    += cpu-sh3
+cpuincdir-$(CONFIG_CPU_SH4A)   += cpu-sh4a
 cpuincdir-$(CONFIG_CPU_SH4)    += cpu-sh4
 cpuincdir-$(CONFIG_CPU_SH5)    += cpu-sh5
 cpuincdir-y                    += cpu-common   # Must be last
index 8e2a270..2823619 100644 (file)
@@ -116,7 +116,7 @@ static int apsh4a3a_clk_init(void)
        int ret;
 
        clk = clk_get(NULL, "extal");
-       if (!clk || IS_ERR(clk))
+       if (IS_ERR(clk))
                return PTR_ERR(clk);
        ret = clk_set_rate(clk, 33333000);
        clk_put(clk);
index e2bd218..b4d6292 100644 (file)
@@ -94,7 +94,7 @@ static int apsh4ad0a_clk_init(void)
        int ret;
 
        clk = clk_get(NULL, "extal");
-       if (!clk || IS_ERR(clk))
+       if (IS_ERR(clk))
                return PTR_ERR(clk);
        ret = clk_set_rate(clk, 33333000);
        clk_put(clk);
index ee65ff0..d879848 100644 (file)
@@ -299,7 +299,7 @@ static int sh7785lcr_clk_init(void)
        int ret;
 
        clk = clk_get(NULL, "extal");
-       if (!clk || IS_ERR(clk))
+       if (IS_ERR(clk))
                return PTR_ERR(clk);
        ret = clk_set_rate(clk, 33333333);
        clk_put(clk);
index d81c609..24e3316 100644 (file)
@@ -190,7 +190,7 @@ static int urquell_clk_init(void)
                return -EINVAL;
 
        clk = clk_get(NULL, "extal");
-       if (!clk || IS_ERR(clk))
+       if (IS_ERR(clk))
                return PTR_ERR(clk);
        ret = clk_set_rate(clk, 33333333);
        clk_put(clk);
index 1dc924b..d362657 100644 (file)
@@ -332,8 +332,8 @@ static int camera_set_capture(struct soc_camera_platform_info *info,
        return ret;
 }
 
-static int ap325rxa_camera_add(struct soc_camera_link *icl, struct device *dev);
-static void ap325rxa_camera_del(struct soc_camera_link *icl);
+static int ap325rxa_camera_add(struct soc_camera_device *icd);
+static void ap325rxa_camera_del(struct soc_camera_device *icd);
 
 static struct soc_camera_platform_info camera_info = {
        .format_name = "UYVY",
@@ -366,24 +366,23 @@ static void ap325rxa_camera_release(struct device *dev)
        soc_camera_platform_release(&camera_device);
 }
 
-static int ap325rxa_camera_add(struct soc_camera_link *icl,
-                              struct device *dev)
+static int ap325rxa_camera_add(struct soc_camera_device *icd)
 {
-       int ret = soc_camera_platform_add(icl, dev, &camera_device, &camera_link,
+       int ret = soc_camera_platform_add(icd, &camera_device, &camera_link,
                                          ap325rxa_camera_release, 0);
        if (ret < 0)
                return ret;
 
        ret = camera_probe();
        if (ret < 0)
-               soc_camera_platform_del(icl, camera_device, &camera_link);
+               soc_camera_platform_del(icd, camera_device, &camera_link);
 
        return ret;
 }
 
-static void ap325rxa_camera_del(struct soc_camera_link *icl)
+static void ap325rxa_camera_del(struct soc_camera_device *icd)
 {
-       soc_camera_platform_del(icl, camera_device, &camera_link);
+       soc_camera_platform_del(icd, camera_device, &camera_link);
 }
 #endif /* CONFIG_I2C */
 
index 87618c9..74b8db1 100644 (file)
@@ -335,8 +335,6 @@ static struct clk *r7780rp_clocks[] = {
        &ivdr_clk,
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("ivdr_clk", &ivdr_clk),
index 1521aa7..486d1ac 100644 (file)
@@ -194,7 +194,7 @@ static int sdk7786_clk_init(void)
                return -EINVAL;
 
        clk = clk_get(NULL, "extal");
-       if (!clk || IS_ERR(clk))
+       if (IS_ERR(clk))
                return PTR_ERR(clk);
        ret = clk_set_rate(clk, 33333333);
        clk_put(clk);
index b68b61d..edc2fb7 100644 (file)
@@ -5,7 +5,7 @@
 #include <cpu/irq.h>
 #include "pci-sh5.h"
 
-int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin)
+int __init pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int result = -1;
 
index 942ef4f..edeea89 100644 (file)
@@ -64,7 +64,7 @@ static void __init gapspci_fixup_resources(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, gapspci_fixup_resources);
 
-int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin)
+int __init pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        /*
         * The interrupt routing semantics here are quite trivial.
index 95c6e2d..ecb1d10 100644 (file)
@@ -19,7 +19,7 @@
 #define PCIMCR_MRSET_OFF       0xBFFFFFFF
 #define PCIMCR_RFSH_OFF                0xFFFFFFFB
 
-int pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
 {
        /*
         * slot0: pin1-4 = irq5,6,7,8
index 08b2d86..f9370dc 100644 (file)
@@ -18,7 +18,7 @@ static char irq_tab[] __initdata = {
        65, 66, 67, 68,
 };
 
-int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
 {
        return irq_tab[slot];
 }
index e248516..eaddb56 100644 (file)
@@ -31,7 +31,7 @@ static char lboxre2_irq_tab[] __initdata = {
        IRQ_ETH0, IRQ_ETH1, IRQ_INTA, IRQ_INTD,
 };
 
-int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
 {
        if (mach_is_lboxre2())
                return lboxre2_irq_tab[slot];
index 0930f98..0b84725 100644 (file)
@@ -27,7 +27,7 @@ static char sdk7780_irq_tab[4][16] __initdata = {
        { 68, 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 };
 
-int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
 {
        return sdk7780_irq_tab[pin-1][slot];
 }
index fd3e6b0..2ec146c 100644 (file)
@@ -6,7 +6,7 @@
 #include <linux/io.h>
 #include "pci-sh4.h"
 
-int __init pcibios_map_platform_irq(struct pci_dev *, u8 slot, u8 pin)
+int __init pcibios_map_platform_irq(const struct pci_dev *, u8 slot, u8 pin)
 {
         switch (slot) {
         case 0: return 13;
index 2e8a18b..1615e59 100644 (file)
@@ -3,7 +3,7 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 
-int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin)
+int __init pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
 
index 5a39ecc..4a093c6 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/pci.h>
 #include "pci-sh4.h"
 
-int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
 {
        int irq = -1;
 
index 3a79fa8..bd1addb 100644 (file)
@@ -27,7 +27,7 @@ static char titan_irq_tab[] __initdata = {
        TITAN_IRQ_USB,
 };
 
-int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
 {
        int irq = titan_irq_tab[slot];
 
index 4418f90..4df27c4 100644 (file)
@@ -466,7 +466,7 @@ static int __init pcie_init(struct sh7786_pcie_port *port)
        return 0;
 }
 
-int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
 {
         return 71;
 }
index f0efe97..cb21e23 100644 (file)
@@ -112,7 +112,7 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
 #endif
 
 /* Board-specific fixup routines. */
-int pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin);
+int pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin);
 
 extern void pcibios_resource_to_bus(struct pci_dev *dev,
        struct pci_bus_region *region, struct resource *res);
diff --git a/arch/sh/include/cpu-sh3/cpu/serial.h b/arch/sh/include/cpu-sh3/cpu/serial.h
new file mode 100644 (file)
index 0000000..7766329
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __CPU_SH3_SERIAL_H
+#define __CPU_SH3_SERIAL_H
+
+#include <linux/serial_sci.h>
+
+extern struct plat_sci_port_ops sh770x_sci_port_ops;
+extern struct plat_sci_port_ops sh7710_sci_port_ops;
+extern struct plat_sci_port_ops sh7720_sci_port_ops;
+
+#endif /* __CPU_SH3_SERIAL_H */
diff --git a/arch/sh/include/cpu-sh4a/cpu/serial.h b/arch/sh/include/cpu-sh4a/cpu/serial.h
new file mode 100644 (file)
index 0000000..ff1bc27
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __CPU_SH4A_SERIAL_H
+#define __CPU_SH4A_SERIAL_H
+
+/* arch/sh/kernel/cpu/sh4a/serial-sh7722.c */
+extern struct plat_sci_port_ops sh7722_sci_port_ops;
+
+#endif /* __CPU_SH4A_SERIAL_H */
index 8f63a26..f59b1f3 100644 (file)
@@ -35,8 +35,6 @@ static struct clk *onchip_clocks[] = {
        &cpu_clk,
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("master_clk", &master_clk),
index ecab274..6f13f33 100644 (file)
@@ -7,15 +7,15 @@ obj-y := ex.o probe.o entry.o setup-sh3.o
 obj-$(CONFIG_HIBERNATION)              += swsusp.o
 
 # CPU subtype setup
-obj-$(CONFIG_CPU_SUBTYPE_SH7705)       += setup-sh7705.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7706)       += setup-sh770x.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7707)       += setup-sh770x.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7708)       += setup-sh770x.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7709)       += setup-sh770x.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7710)       += setup-sh7710.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7712)       += setup-sh7710.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7720)       += setup-sh7720.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7721)       += setup-sh7720.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7705)       += setup-sh7705.o serial-sh770x.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7706)       += setup-sh770x.o serial-sh770x.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7707)       += setup-sh770x.o serial-sh770x.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7708)       += setup-sh770x.o serial-sh770x.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7709)       += setup-sh770x.o serial-sh770x.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7710)       += setup-sh7710.o serial-sh7710.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7712)       += setup-sh7710.o serial-sh7710.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7720)       += setup-sh7720.o serial-sh7720.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7721)       += setup-sh7720.o serial-sh7720.o
 
 # Primary on-chip clocks (common)
 clock-$(CONFIG_CPU_SH3)                        := clock-sh3.o
diff --git a/arch/sh/kernel/cpu/sh3/serial-sh770x.c b/arch/sh/kernel/cpu/sh3/serial-sh770x.c
new file mode 100644 (file)
index 0000000..4f7242c
--- /dev/null
@@ -0,0 +1,33 @@
+#include <linux/serial_sci.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+#include <cpu/serial.h>
+
+#define SCPCR 0xA4000116
+#define SCPDR 0xA4000136
+
+static void sh770x_sci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+       unsigned short data;
+
+       /* We need to set SCPCR to enable RTS/CTS */
+       data = __raw_readw(SCPCR);
+       /* Clear out SCP7MD1,0, SCP6MD1,0, SCP4MD1,0*/
+       __raw_writew(data & 0x0fcf, SCPCR);
+
+       if (!(cflag & CRTSCTS)) {
+               /* We need to set SCPCR to enable RTS/CTS */
+               data = __raw_readw(SCPCR);
+               /* Clear out SCP7MD1,0, SCP4MD1,0,
+                  Set SCP6MD1,0 = {01} (output)  */
+               __raw_writew((data & 0x0fcf) | 0x1000, SCPCR);
+
+               data = __raw_readb(SCPDR);
+               /* Set /RTS2 (bit6) = 0 */
+               __raw_writeb(data & 0xbf, SCPDR);
+       }
+}
+
+struct plat_sci_port_ops sh770x_sci_port_ops = {
+       .init_pins      = sh770x_sci_init_pins,
+};
diff --git a/arch/sh/kernel/cpu/sh3/serial-sh7710.c b/arch/sh/kernel/cpu/sh3/serial-sh7710.c
new file mode 100644 (file)
index 0000000..42190ef
--- /dev/null
@@ -0,0 +1,20 @@
+#include <linux/serial_sci.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+#include <cpu/serial.h>
+
+#define PACR 0xa4050100
+#define PBCR 0xa4050102
+
+static void sh7710_sci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+       if (port->mapbase == 0xA4400000) {
+               __raw_writew(__raw_readw(PACR) & 0xffc0, PACR);
+               __raw_writew(__raw_readw(PBCR) & 0x0fff, PBCR);
+       } else if (port->mapbase == 0xA4410000)
+               __raw_writew(__raw_readw(PBCR) & 0xf003, PBCR);
+}
+
+struct plat_sci_port_ops sh7710_sci_port_ops = {
+       .init_pins      = sh7710_sci_init_pins,
+};
diff --git a/arch/sh/kernel/cpu/sh3/serial-sh7720.c b/arch/sh/kernel/cpu/sh3/serial-sh7720.c
new file mode 100644 (file)
index 0000000..8832c52
--- /dev/null
@@ -0,0 +1,37 @@
+#include <linux/serial_sci.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+#include <cpu/serial.h>
+#include <asm/gpio.h>
+
+static void sh7720_sci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+       unsigned short data;
+
+       if (cflag & CRTSCTS) {
+               /* enable RTS/CTS */
+               if (port->mapbase == 0xa4430000) { /* SCIF0 */
+                       /* Clear PTCR bit 9-2; enable all scif pins but sck */
+                       data = __raw_readw(PORT_PTCR);
+                       __raw_writew((data & 0xfc03), PORT_PTCR);
+               } else if (port->mapbase == 0xa4438000) { /* SCIF1 */
+                       /* Clear PVCR bit 9-2 */
+                       data = __raw_readw(PORT_PVCR);
+                       __raw_writew((data & 0xfc03), PORT_PVCR);
+               }
+       } else {
+               if (port->mapbase == 0xa4430000) { /* SCIF0 */
+                       /* Clear PTCR bit 5-2; enable only tx and rx  */
+                       data = __raw_readw(PORT_PTCR);
+                       __raw_writew((data & 0xffc3), PORT_PTCR);
+               } else if (port->mapbase == 0xa4438000) { /* SCIF1 */
+                       /* Clear PVCR bit 5-2 */
+                       data = __raw_readw(PORT_PVCR);
+                       __raw_writew((data & 0xffc3), PORT_PVCR);
+               }
+       }
+}
+
+struct plat_sci_port_ops sh7720_sci_port_ops = {
+       .init_pins      = sh7720_sci_init_pins,
+};
index cd2e702..2309618 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
 #include <asm/rtc.h>
+#include <cpu/serial.h>
 
 enum {
        UNUSED = 0,
@@ -75,6 +76,8 @@ static struct plat_sci_port scif0_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_4,
        .type           = PORT_SCIF,
        .irqs           = { 56, 56, 56 },
+       .ops            = &sh770x_sci_port_ops,
+       .regtype        = SCIx_SH7705_SCIF_REGTYPE,
 };
 
 static struct platform_device scif0_device = {
@@ -92,6 +95,8 @@ static struct plat_sci_port scif1_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_4,
        .type           = PORT_SCIF,
        .irqs           = { 52, 52, 52 },
+       .ops            = &sh770x_sci_port_ops,
+       .regtype        = SCIx_SH7705_SCIF_REGTYPE,
 };
 
 static struct platform_device scif1_device = {
index 4551ad6..3f3d5fe 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
+#include <cpu/serial.h>
 
 enum {
        UNUSED = 0,
@@ -108,11 +109,14 @@ static struct platform_device rtc_device = {
 
 static struct plat_sci_port scif0_platform_data = {
        .mapbase        = 0xfffffe80,
+       .port_reg       = 0xa4000136,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_TE | SCSCR_RE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCI,
        .irqs           = { 23, 23, 23, 0 },
+       .ops            = &sh770x_sci_port_ops,
+       .regshift       = 1,
 };
 
 static struct platform_device scif0_device = {
@@ -132,6 +136,8 @@ static struct plat_sci_port scif1_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 56, 56, 56, 56 },
+       .ops            = &sh770x_sci_port_ops,
+       .regtype        = SCIx_SH3_SCIF_REGTYPE,
 };
 
 static struct platform_device scif1_device = {
@@ -146,11 +152,14 @@ static struct platform_device scif1_device = {
     defined(CONFIG_CPU_SUBTYPE_SH7709)
 static struct plat_sci_port scif2_platform_data = {
        .mapbase        = 0xa4000140,
+       .port_reg       = SCIx_NOT_SUPPORTED,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_TE | SCSCR_RE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_IRDA,
        .irqs           = { 52, 52, 52, 52 },
+       .ops            = &sh770x_sci_port_ops,
+       .regshift       = 1,
 };
 
 static struct platform_device scif2_device = {
index 365b94a..9492034 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
 #include <asm/rtc.h>
+#include <cpu/serial.h>
 
 static struct resource rtc_resources[] = {
        [0] = {
@@ -55,6 +56,8 @@ static struct plat_sci_port scif0_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_4,
        .type           = PORT_SCIF,
        .irqs           = { 80, 80, 80, 80 },
+       .ops            = &sh7720_sci_port_ops,
+       .regtype        = SCIx_SH7705_SCIF_REGTYPE,
 };
 
 static struct platform_device scif0_device = {
@@ -72,6 +75,8 @@ static struct plat_sci_port scif1_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_4,
        .type           = PORT_SCIF,
        .irqs           = { 81, 81, 81, 81 },
+       .ops            = &sh7720_sci_port_ops,
+       .regtype        = SCIx_SH7705_SCIF_REGTYPE,
 };
 
 static struct platform_device scif1_device = {
index 3f6f8e9..f4e262a 100644 (file)
@@ -147,8 +147,6 @@ static struct clk *sh4202_onchip_clocks[] = {
        &sh4202_shoc_clk,
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("emi_clk", &sh4202_emi_clk),
index e53b4b3..98cc0c7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * SH7750/SH7751 Setup
+ * SH7091/SH7750/SH7750S/SH7750R/SH7751/SH7751R Setup
  *
  *  Copyright (C) 2006  Paul Mundt
  *  Copyright (C) 2006  Jamie Lenehan
@@ -38,11 +38,13 @@ static struct platform_device rtc_device = {
 
 static struct plat_sci_port sci_platform_data = {
        .mapbase        = 0xffe00000,
+       .port_reg       = 0xffe0001C,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_TE | SCSCR_RE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCI,
        .irqs           = { 23, 23, 23, 0 },
+       .regshift       = 2,
 };
 
 static struct platform_device sci_device = {
index 78bbf23..c0b4c77 100644 (file)
@@ -133,6 +133,7 @@ static struct plat_sci_port scif0_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 52, 53, 55, 54 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif0_device = {
@@ -150,6 +151,7 @@ static struct plat_sci_port scif1_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .irqs           = { 72, 73, 75, 74 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif1_device = {
@@ -167,6 +169,7 @@ static struct plat_sci_port scif2_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 76, 77, 79, 78 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif2_device = {
@@ -184,6 +187,7 @@ static struct plat_sci_port scif3_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCI,
        .irqs           = { 80, 81, 82, 0 },
+       .regshift       = 2,
 };
 
 static struct platform_device scif3_device = {
index cc122b1..c57fb28 100644 (file)
@@ -10,7 +10,7 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7780)      += setup-sh7780.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7785)       += setup-sh7785.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7786)       += setup-sh7786.o intc-shx3.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7343)       += setup-sh7343.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7722)       += setup-sh7722.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7722)       += setup-sh7722.o serial-sh7722.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7723)       += setup-sh7723.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7724)       += setup-sh7724.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7366)       += setup-sh7366.o
index 93c6460..70e45bd 100644 (file)
@@ -194,8 +194,6 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP200] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 0, 0),
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("rclk", &r_clk),
@@ -233,32 +231,17 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("rwdt0", &mstp_clks[MSTP013]),
        CLKDEV_CON_ID("mfi0", &mstp_clks[MSTP011]),
        CLKDEV_CON_ID("flctl0", &mstp_clks[MSTP010]),
-       {
-               /* SCIF0 */
-               .dev_id         = "sh-sci.0",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP007],
-       }, {
-               /* SCIF1 */
-               .dev_id         = "sh-sci.1",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP006],
-       }, {
-               /* SCIF2 */
-               .dev_id         = "sh-sci.2",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP005],
-       }, {
-               /* SCIF3 */
-               .dev_id         = "sh-sci.3",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP004],
-       },
+
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP007]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP006]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP005]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP004]),
+
        CLKDEV_CON_ID("sio0", &mstp_clks[MSTP003]),
        CLKDEV_CON_ID("siof0", &mstp_clks[MSTP002]),
        CLKDEV_CON_ID("siof1", &mstp_clks[MSTP001]),
-       CLKDEV_CON_ID("i2c0", &mstp_clks[MSTP109]),
-       CLKDEV_CON_ID("i2c1", &mstp_clks[MSTP108]),
+       CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP109]),
+       CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP108]),
        CLKDEV_CON_ID("tpu0", &mstp_clks[MSTP225]),
        CLKDEV_CON_ID("irda0", &mstp_clks[MSTP224]),
        CLKDEV_CON_ID("sdhi0", &mstp_clks[MSTP218]),
index 049dc06..3c31650 100644 (file)
@@ -192,8 +192,6 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP200] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 0, 0),
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("rclk", &r_clk),
@@ -231,25 +229,14 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("rwdt0", &mstp_clks[MSTP013]),
        CLKDEV_CON_ID("mfi0", &mstp_clks[MSTP011]),
        CLKDEV_CON_ID("flctl0", &mstp_clks[MSTP010]),
-       {
-               /* SCIF0 */
-               .dev_id         = "sh-sci.0",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP007],
-       }, {
-               /* SCIF1 */
-               .dev_id         = "sh-sci.1",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP006],
-       }, {
-               /* SCIF2 */
-               .dev_id         = "sh-sci.2",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP005],
-       },
+
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP007]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP006]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP005]),
+
        CLKDEV_CON_ID("msiof0", &mstp_clks[MSTP002]),
        CLKDEV_CON_ID("sbr0", &mstp_clks[MSTP001]),
-       CLKDEV_CON_ID("i2c0", &mstp_clks[MSTP109]),
+       CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP109]),
        CLKDEV_CON_ID("icb0", &mstp_clks[MSTP227]),
        CLKDEV_CON_ID("meram0", &mstp_clks[MSTP226]),
        CLKDEV_CON_ID("dacy1", &mstp_clks[MSTP224]),
index 9d23a36..c9a4808 100644 (file)
@@ -175,8 +175,6 @@ static struct clk mstp_clks[HWBLK_NR] = {
        SH_HWBLK_CLK(HWBLK_LCDC, &div4_clks[DIV4_P], 0),
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("rclk", &r_clk),
@@ -201,42 +199,20 @@ static struct clk_lookup lookups[] = {
        /* MSTP clocks */
        CLKDEV_CON_ID("uram0", &mstp_clks[HWBLK_URAM]),
        CLKDEV_CON_ID("xymem0", &mstp_clks[HWBLK_XYMEM]),
-       {
-               /* TMU0 */
-               .dev_id         = "sh_tmu.0",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[HWBLK_TMU],
-       }, {
-               /* TMU1 */
-               .dev_id         = "sh_tmu.1",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[HWBLK_TMU],
-       }, {
-               /* TMU2 */
-               .dev_id         = "sh_tmu.2",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[HWBLK_TMU],
-       },
+
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.0", &mstp_clks[HWBLK_TMU]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.1", &mstp_clks[HWBLK_TMU]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.2", &mstp_clks[HWBLK_TMU]),
+
        CLKDEV_CON_ID("cmt_fck", &mstp_clks[HWBLK_CMT]),
        CLKDEV_CON_ID("rwdt0", &mstp_clks[HWBLK_RWDT]),
        CLKDEV_CON_ID("flctl0", &mstp_clks[HWBLK_FLCTL]),
-       {
-               /* SCIF0 */
-               .dev_id         = "sh-sci.0",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[HWBLK_SCIF0],
-       }, {
-               /* SCIF1 */
-               .dev_id         = "sh-sci.1",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[HWBLK_SCIF1],
-       }, {
-               /* SCIF2 */
-               .dev_id         = "sh-sci.2",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[HWBLK_SCIF2],
-       },
-       CLKDEV_CON_ID("i2c0", &mstp_clks[HWBLK_IIC]),
+
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[HWBLK_SCIF0]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[HWBLK_SCIF1]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[HWBLK_SCIF2]),
+
+       CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[HWBLK_IIC]),
        CLKDEV_CON_ID("rtc0", &mstp_clks[HWBLK_RTC]),
        CLKDEV_CON_ID("sdhi0", &mstp_clks[HWBLK_SDHI]),
        CLKDEV_CON_ID("keysc0", &mstp_clks[HWBLK_KEYSC]),
index 55493cd..3cc3827 100644 (file)
@@ -200,8 +200,6 @@ static struct clk mstp_clks[] = {
        SH_HWBLK_CLK(HWBLK_LCDC, &div4_clks[DIV4_B], 0),
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("rclk", &r_clk),
@@ -305,7 +303,7 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("msiof0", &mstp_clks[HWBLK_MSIOF0]),
        CLKDEV_CON_ID("msiof1", &mstp_clks[HWBLK_MSIOF1]),
        CLKDEV_CON_ID("meram0", &mstp_clks[HWBLK_MERAM]),
-       CLKDEV_CON_ID("i2c0", &mstp_clks[HWBLK_IIC]),
+       CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[HWBLK_IIC]),
        CLKDEV_CON_ID("rtc0", &mstp_clks[HWBLK_RTC]),
        CLKDEV_CON_ID("atapi0", &mstp_clks[HWBLK_ATAPI]),
        CLKDEV_CON_ID("adc0", &mstp_clks[HWBLK_ADC]),
index d08fa95..8668f55 100644 (file)
@@ -252,8 +252,6 @@ static struct clk mstp_clks[HWBLK_NR] = {
        SH_HWBLK_CLK(HWBLK_LCDC, &div4_clks[DIV4_B], 0),
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("rclk", &r_clk),
@@ -289,77 +287,31 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("sh0", &mstp_clks[HWBLK_SHYWAY]),
        CLKDEV_CON_ID("hudi0", &mstp_clks[HWBLK_HUDI]),
        CLKDEV_CON_ID("ubc0", &mstp_clks[HWBLK_UBC]),
-       {
-               /* TMU0 */
-               .dev_id         = "sh_tmu.0",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[HWBLK_TMU0],
-       }, {
-               /* TMU1 */
-               .dev_id         = "sh_tmu.1",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[HWBLK_TMU0],
-       }, {
-               /* TMU2 */
-               .dev_id         = "sh_tmu.2",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[HWBLK_TMU0],
-       }, {
-               /* TMU3 */
-               .dev_id         = "sh_tmu.3",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[HWBLK_TMU1],
-       },
+
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.0", &mstp_clks[HWBLK_TMU0]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.1", &mstp_clks[HWBLK_TMU0]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.2", &mstp_clks[HWBLK_TMU0]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.3", &mstp_clks[HWBLK_TMU1]),
+
        CLKDEV_CON_ID("cmt_fck", &mstp_clks[HWBLK_CMT]),
        CLKDEV_CON_ID("rwdt0", &mstp_clks[HWBLK_RWDT]),
        CLKDEV_CON_ID("dmac1", &mstp_clks[HWBLK_DMAC1]),
-       {
-               /* TMU4 */
-               .dev_id         = "sh_tmu.4",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[HWBLK_TMU1],
-       }, {
-               /* TMU5 */
-               .dev_id         = "sh_tmu.5",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[HWBLK_TMU1],
-       }, {
-               /* SCIF0 */
-               .dev_id         = "sh-sci.0",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[HWBLK_SCIF0],
-       }, {
-               /* SCIF1 */
-               .dev_id         = "sh-sci.1",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[HWBLK_SCIF1],
-       }, {
-               /* SCIF2 */
-               .dev_id         = "sh-sci.2",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[HWBLK_SCIF2],
-       }, {
-               /* SCIF3 */
-               .dev_id         = "sh-sci.3",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[HWBLK_SCIF3],
-       }, {
-               /* SCIF4 */
-               .dev_id         = "sh-sci.4",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[HWBLK_SCIF4],
-       }, {
-               /* SCIF5 */
-               .dev_id         = "sh-sci.5",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[HWBLK_SCIF5],
-       },
+
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.4", &mstp_clks[HWBLK_TMU1]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.5", &mstp_clks[HWBLK_TMU1]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[HWBLK_SCIF0]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[HWBLK_SCIF1]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[HWBLK_SCIF2]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[HWBLK_SCIF3]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[HWBLK_SCIF4]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[HWBLK_SCIF5]),
+
        CLKDEV_CON_ID("msiof0", &mstp_clks[HWBLK_MSIOF0]),
        CLKDEV_CON_ID("msiof1", &mstp_clks[HWBLK_MSIOF1]),
        CLKDEV_CON_ID("keysc0", &mstp_clks[HWBLK_KEYSC]),
        CLKDEV_CON_ID("rtc0", &mstp_clks[HWBLK_RTC]),
-       CLKDEV_CON_ID("i2c0", &mstp_clks[HWBLK_IIC0]),
-       CLKDEV_CON_ID("i2c1", &mstp_clks[HWBLK_IIC1]),
+       CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[HWBLK_IIC0]),
+       CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[HWBLK_IIC1]),
        CLKDEV_CON_ID("mmc0", &mstp_clks[HWBLK_MMC]),
        CLKDEV_CON_ID("eth0", &mstp_clks[HWBLK_ETHER]),
        CLKDEV_CON_ID("atapi0", &mstp_clks[HWBLK_ATAPI]),
index eedddad..3b097b0 100644 (file)
@@ -101,8 +101,6 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP220] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR2, 20, 0),
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("extal", &extal_clk),
@@ -116,33 +114,13 @@ static struct clk_lookup lookups[] = {
        /* MSTP32 clocks */
        CLKDEV_CON_ID("sdhi0", &mstp_clks[MSTP004]),
        CLKDEV_CON_ID("riic", &mstp_clks[MSTP000]),
-       {
-               /* TMU0 */
-               .dev_id         = "sh_tmu.0",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP113],
-       }, {
-               /* TMU1 */
-               .dev_id         = "sh_tmu.1",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP114],
-       },
-       {
-               /* SCIF4 (But, ID is 2) */
-               .dev_id         = "sh-sci.2",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP112],
-       }, {
-               /* SCIF3 */
-               .dev_id         = "sh-sci.1",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP111],
-       }, {
-               /* SCIF2 */
-               .dev_id         = "sh-sci.0",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP110],
-       },
+
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.0", &mstp_clks[MSTP113]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.1", &mstp_clks[MSTP114]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP112]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP111]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP110]),
+
        CLKDEV_CON_ID("usb0", &mstp_clks[MSTP102]),
        CLKDEV_CON_ID("mmc0", &mstp_clks[MSTP220]),
 };
index 599630f..2d4c7fd 100644 (file)
@@ -91,8 +91,6 @@ static struct clk *sh7763_onchip_clocks[] = {
        &sh7763_shyway_clk,
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("shyway_clk", &sh7763_shyway_clk),
index 8894926..3b53348 100644 (file)
@@ -97,8 +97,6 @@ static struct clk *sh7780_onchip_clocks[] = {
        &sh7780_shyway_clk,
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("shyway_clk", &sh7780_shyway_clk),
index 2d96024..e5b420c 100644 (file)
@@ -116,8 +116,6 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP100] = SH_CLK_MSTP32(NULL, MSTPCR1, 0, 0),
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("extal", &extal_clk),
@@ -134,74 +132,27 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
 
        /* MSTP32 clocks */
-       {
-               /* SCIF5 */
-               .dev_id         = "sh-sci.5",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP029],
-       }, {
-               /* SCIF4 */
-               .dev_id         = "sh-sci.4",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP028],
-       }, {
-               /* SCIF3 */
-               .dev_id         = "sh-sci.3",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP027],
-       }, {
-               /* SCIF2 */
-               .dev_id         = "sh-sci.2",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP026],
-       }, {
-               /* SCIF1 */
-               .dev_id         = "sh-sci.1",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP025],
-       }, {
-               /* SCIF0 */
-               .dev_id         = "sh-sci.0",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP024],
-       },
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[MSTP029]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[MSTP028]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP027]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP026]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP025]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP024]),
+
        CLKDEV_CON_ID("ssi1_fck", &mstp_clks[MSTP021]),
        CLKDEV_CON_ID("ssi0_fck", &mstp_clks[MSTP020]),
        CLKDEV_CON_ID("hac1_fck", &mstp_clks[MSTP017]),
        CLKDEV_CON_ID("hac0_fck", &mstp_clks[MSTP016]),
        CLKDEV_CON_ID("mmcif_fck", &mstp_clks[MSTP013]),
        CLKDEV_CON_ID("flctl_fck", &mstp_clks[MSTP012]),
-       {
-               /* TMU0 */
-               .dev_id         = "sh_tmu.0",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP008],
-       }, {
-               /* TMU1 */
-               .dev_id         = "sh_tmu.1",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP008],
-       }, {
-               /* TMU2 */
-               .dev_id         = "sh_tmu.2",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP008],
-       }, {
-               /* TMU3 */
-               .dev_id         = "sh_tmu.3",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP009],
-       }, {
-               /* TMU4 */
-               .dev_id         = "sh_tmu.4",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP009],
-       }, {
-               /* TMU5 */
-               .dev_id         = "sh_tmu.5",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP009],
-       },
+
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.0", &mstp_clks[MSTP008]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.1", &mstp_clks[MSTP008]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.2", &mstp_clks[MSTP008]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.3", &mstp_clks[MSTP009]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.4", &mstp_clks[MSTP009]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.5", &mstp_clks[MSTP009]),
+
        CLKDEV_CON_ID("siof_fck", &mstp_clks[MSTP003]),
        CLKDEV_CON_ID("hspi_fck", &mstp_clks[MSTP002]),
        CLKDEV_CON_ID("hudi_fck", &mstp_clks[MSTP119]),
index 42e403b..f6c0c3d 100644 (file)
@@ -125,8 +125,6 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP102] = SH_CLK_MSTP32(NULL, MSTPCR1, 2, 0),
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("extal", &extal_clk),
@@ -141,37 +139,13 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
 
        /* MSTP32 clocks */
-       {
-               /* SCIF5 */
-               .dev_id         = "sh-sci.5",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP029],
-       }, {
-               /* SCIF4 */
-               .dev_id         = "sh-sci.4",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP028],
-       }, {
-               /* SCIF3 */
-               .dev_id         = "sh-sci.3",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP027],
-       }, {
-               /* SCIF2 */
-               .dev_id         = "sh-sci.2",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP026],
-       }, {
-               /* SCIF1 */
-               .dev_id         = "sh-sci.1",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP025],
-       }, {
-               /* SCIF0 */
-               .dev_id         = "sh-sci.0",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP024],
-       },
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[MSTP029]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[MSTP028]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP027]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP026]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP025]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP024]),
+
        CLKDEV_CON_ID("ssi3_fck", &mstp_clks[MSTP023]),
        CLKDEV_CON_ID("ssi2_fck", &mstp_clks[MSTP022]),
        CLKDEV_CON_ID("ssi1_fck", &mstp_clks[MSTP021]),
@@ -180,67 +154,20 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("hac0_fck", &mstp_clks[MSTP016]),
        CLKDEV_CON_ID("i2c1_fck", &mstp_clks[MSTP015]),
        CLKDEV_CON_ID("i2c0_fck", &mstp_clks[MSTP014]),
-       {
-               /* TMU0 */
-               .dev_id         = "sh_tmu.0",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP008],
-       }, {
-               /* TMU1 */
-               .dev_id         = "sh_tmu.1",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP008],
-       }, {
-               /* TMU2 */
-               .dev_id         = "sh_tmu.2",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP008],
-       }, {
-               /* TMU3 */
-               .dev_id         = "sh_tmu.3",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP009],
-       }, {
-               /* TMU4 */
-               .dev_id         = "sh_tmu.4",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP009],
-       }, {
-               /* TMU5 */
-               .dev_id         = "sh_tmu.5",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP009],
-       }, {
-               /* TMU6 */
-               .dev_id         = "sh_tmu.6",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP010],
-       }, {
-               /* TMU7 */
-               .dev_id         = "sh_tmu.7",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP010],
-       }, {
-               /* TMU8 */
-               .dev_id         = "sh_tmu.8",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP010],
-       }, {
-               /* TMU9 */
-               .dev_id         = "sh_tmu.9",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP011],
-       }, {
-               /* TMU10 */
-               .dev_id         = "sh_tmu.10",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP011],
-       }, {
-               /* TMU11 */
-               .dev_id         = "sh_tmu.11",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP011],
-       },
+
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.0", &mstp_clks[MSTP008]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.1", &mstp_clks[MSTP008]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.2", &mstp_clks[MSTP008]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.3", &mstp_clks[MSTP009]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.4", &mstp_clks[MSTP009]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.5", &mstp_clks[MSTP009]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.6", &mstp_clks[MSTP010]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.7", &mstp_clks[MSTP010]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.8", &mstp_clks[MSTP010]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.9", &mstp_clks[MSTP011]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.10", &mstp_clks[MSTP011]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.11", &mstp_clks[MSTP011]),
+
        CLKDEV_CON_ID("sdif1_fck", &mstp_clks[MSTP005]),
        CLKDEV_CON_ID("sdif0_fck", &mstp_clks[MSTP004]),
        CLKDEV_CON_ID("hspi_fck", &mstp_clks[MSTP002]),
index 1afdb93..bf2d00b 100644 (file)
@@ -100,8 +100,6 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP104] = SH_CLK_MSTP32(NULL, MSTPCR1, 4, 0),
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("extal", &extal_clk),
@@ -116,62 +114,23 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
 
        /* MSTP32 clocks */
-       {
-               /* SCIF3 */
-               .dev_id         = "sh-sci.3",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP027],
-       }, {
-               /* SCIF2 */
-               .dev_id         = "sh-sci.2",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP026],
-       }, {
-               /* SCIF1 */
-               .dev_id         = "sh-sci.1",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP025],
-       }, {
-               /* SCIF0 */
-               .dev_id         = "sh-sci.0",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP024],
-       },
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP027]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP026]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP025]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP024]),
+
        CLKDEV_CON_ID("h8ex_fck", &mstp_clks[MSTP003]),
        CLKDEV_CON_ID("csm_fck", &mstp_clks[MSTP002]),
        CLKDEV_CON_ID("fe1_fck", &mstp_clks[MSTP001]),
        CLKDEV_CON_ID("fe0_fck", &mstp_clks[MSTP000]),
-       {
-               /* TMU0 */
-               .dev_id         = "sh_tmu.0",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP008],
-       }, {
-               /* TMU1 */
-               .dev_id         = "sh_tmu.1",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP008],
-       }, {
-               /* TMU2 */
-               .dev_id         = "sh_tmu.2",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP008],
-       }, {
-               /* TMU3 */
-               .dev_id         = "sh_tmu.3",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP009],
-       }, {
-               /* TMU4 */
-               .dev_id         = "sh_tmu.4",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP009],
-       }, {
-               /* TMU5 */
-               .dev_id         = "sh_tmu.5",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP009],
-       },
+
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.0", &mstp_clks[MSTP008]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.1", &mstp_clks[MSTP008]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.2", &mstp_clks[MSTP008]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.3", &mstp_clks[MSTP009]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.4", &mstp_clks[MSTP009]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.5", &mstp_clks[MSTP009]),
+
        CLKDEV_CON_ID("hudi_fck", &mstp_clks[MSTP119]),
        CLKDEV_CON_ID("dmac_11_6_fck", &mstp_clks[MSTP105]),
        CLKDEV_CON_ID("dmac_5_0_fck", &mstp_clks[MSTP104]),
diff --git a/arch/sh/kernel/cpu/sh4a/serial-sh7722.c b/arch/sh/kernel/cpu/sh4a/serial-sh7722.c
new file mode 100644 (file)
index 0000000..59bc3a7
--- /dev/null
@@ -0,0 +1,23 @@
+#include <linux/serial_sci.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+
+#define PSCR 0xA405011E
+
+static void sh7722_sci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+       unsigned short data;
+
+       if (port->mapbase == 0xffe00000) {
+               data = __raw_readw(PSCR);
+               data &= ~0x03cf;
+               if (!(cflag & CRTSCTS))
+                       data |= 0x0340;
+
+               __raw_writew(data, PSCR);
+       }
+}
+
+struct plat_sci_port_ops sh7722_sci_port_ops = {
+       .init_pins      = sh7722_sci_init_pins,
+};
index 82616af..8777386 100644 (file)
@@ -20,6 +20,7 @@
 
 static struct plat_sci_port scif0_platform_data = {
        .mapbase        = 0xffe00000,
+       .port_reg       = 0xa405013e,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
index 5813d80..278a0e5 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <cpu/dma-register.h>
 #include <cpu/sh7722.h>
+#include <cpu/serial.h>
 
 static const struct sh_dmae_slave_config sh7722_dmae_slaves[] = {
        {
@@ -185,6 +186,8 @@ static struct plat_sci_port scif0_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 80, 80, 80, 80 },
+       .ops            = &sh7722_sci_port_ops,
+       .regtype        = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
 static struct platform_device scif0_device = {
@@ -202,6 +205,8 @@ static struct plat_sci_port scif1_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 81, 81, 81, 81 },
+       .ops            = &sh7722_sci_port_ops,
+       .regtype        = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
 static struct platform_device scif1_device = {
@@ -219,6 +224,8 @@ static struct plat_sci_port scif2_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 82, 82, 82, 82 },
+       .ops            = &sh7722_sci_port_ops,
+       .regtype        = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
 static struct platform_device scif2_device = {
index 0723822..3c2810d 100644 (file)
 /* Serial */
 static struct plat_sci_port scif0_platform_data = {
        .mapbase        = 0xffe00000,
+       .port_reg       = 0xa4050160,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 80, 80, 80, 80 },
+       .regtype        = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
 static struct platform_device scif0_device = {
@@ -40,11 +42,13 @@ static struct platform_device scif0_device = {
 
 static struct plat_sci_port scif1_platform_data = {
        .mapbase        = 0xffe10000,
+       .port_reg       = SCIx_NOT_SUPPORTED,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 81, 81, 81, 81 },
+       .regtype        = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
 static struct platform_device scif1_device = {
@@ -57,11 +61,13 @@ static struct platform_device scif1_device = {
 
 static struct plat_sci_port scif2_platform_data = {
        .mapbase        = 0xffe20000,
+       .port_reg       = SCIx_NOT_SUPPORTED,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 82, 82, 82, 82 },
+       .regtype        = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
 static struct platform_device scif2_device = {
@@ -75,6 +81,7 @@ static struct platform_device scif2_device = {
 static struct plat_sci_port scif3_platform_data = {
        .mapbase        = 0xa4e30000,
        .flags          = UPF_BOOT_AUTOCONF,
+       .port_reg       = SCIx_NOT_SUPPORTED,
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_3,
        .type           = PORT_SCIFA,
@@ -91,6 +98,7 @@ static struct platform_device scif3_device = {
 
 static struct plat_sci_port scif4_platform_data = {
        .mapbase        = 0xa4e40000,
+       .port_reg       = SCIx_NOT_SUPPORTED,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_3,
@@ -108,6 +116,7 @@ static struct platform_device scif4_device = {
 
 static struct plat_sci_port scif5_platform_data = {
        .mapbase        = 0xa4e50000,
+       .port_reg       = SCIx_NOT_SUPPORTED,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_3,
index 134a397..a37dd72 100644 (file)
@@ -296,11 +296,13 @@ static struct platform_device dma1_device = {
 /* Serial */
 static struct plat_sci_port scif0_platform_data = {
        .mapbase        = 0xffe00000,
+       .port_reg       = SCIx_NOT_SUPPORTED,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 80, 80, 80, 80 },
+       .regtype        = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
 static struct platform_device scif0_device = {
@@ -313,11 +315,13 @@ static struct platform_device scif0_device = {
 
 static struct plat_sci_port scif1_platform_data = {
        .mapbase        = 0xffe10000,
+       .port_reg       = SCIx_NOT_SUPPORTED,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 81, 81, 81, 81 },
+       .regtype        = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
 static struct platform_device scif1_device = {
@@ -330,11 +334,13 @@ static struct platform_device scif1_device = {
 
 static struct plat_sci_port scif2_platform_data = {
        .mapbase        = 0xffe20000,
+       .port_reg       = SCIx_NOT_SUPPORTED,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 82, 82, 82, 82 },
+       .regtype        = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
 static struct platform_device scif2_device = {
@@ -347,6 +353,7 @@ static struct platform_device scif2_device = {
 
 static struct plat_sci_port scif3_platform_data = {
        .mapbase        = 0xa4e30000,
+       .port_reg       = SCIx_NOT_SUPPORTED,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_3,
@@ -364,6 +371,7 @@ static struct platform_device scif3_device = {
 
 static struct plat_sci_port scif4_platform_data = {
        .mapbase        = 0xa4e40000,
+       .port_reg       = SCIx_NOT_SUPPORTED,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_3,
@@ -381,6 +389,7 @@ static struct platform_device scif4_device = {
 
 static struct plat_sci_port scif5_platform_data = {
        .mapbase        = 0xa4e50000,
+       .port_reg       = SCIx_NOT_SUPPORTED,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_3,
index 593eca6..0011351 100644 (file)
@@ -23,6 +23,7 @@ static struct plat_sci_port scif0_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 40, 40, 40, 40 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif0_device = {
@@ -40,6 +41,7 @@ static struct plat_sci_port scif1_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 76, 76, 76, 76 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif1_device = {
@@ -57,6 +59,7 @@ static struct plat_sci_port scif2_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 104, 104, 104, 104 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif2_device = {
index 08add7f..3d4d207 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/serial_sci.h>
 #include <linux/sh_dma.h>
 #include <linux/sh_timer.h>
-
 #include <cpu/dma-register.h>
 
 static struct plat_sci_port scif0_platform_data = {
@@ -24,6 +23,7 @@ static struct plat_sci_port scif0_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 40, 40, 40, 40 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif0_device = {
@@ -41,6 +41,7 @@ static struct plat_sci_port scif1_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 76, 76, 76, 76 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif1_device = {
index 18d8fc1..b29e634 100644 (file)
@@ -15,9 +15,7 @@
 #include <linux/mm.h>
 #include <linux/sh_dma.h>
 #include <linux/sh_timer.h>
-
 #include <asm/mmzone.h>
-
 #include <cpu/dma-register.h>
 
 static struct plat_sci_port scif0_platform_data = {
@@ -27,6 +25,7 @@ static struct plat_sci_port scif0_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 40, 40, 40, 40 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif0_device = {
@@ -44,6 +43,7 @@ static struct plat_sci_port scif1_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 44, 44, 44, 44 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif1_device = {
@@ -61,6 +61,7 @@ static struct plat_sci_port scif2_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 60, 60, 60, 60 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif2_device = {
@@ -78,6 +79,7 @@ static struct plat_sci_port scif3_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 61, 61, 61, 61 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif3_device = {
@@ -95,6 +97,7 @@ static struct plat_sci_port scif4_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 62, 62, 62, 62 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif4_device = {
@@ -112,6 +115,7 @@ static struct plat_sci_port scif5_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 63, 63, 63, 63 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif5_device = {
index beba32b..dd5e709 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * SH7786 Setup
  *
- * Copyright (C) 2009 - 2010  Renesas Solutions Corp.
+ * Copyright (C) 2009 - 2011  Renesas Solutions Corp.
  * Kuninori Morimoto <morimoto.kuninori@renesas.com>
  * Paul Mundt <paul.mundt@renesas.com>
  *
@@ -33,6 +33,7 @@ static struct plat_sci_port scif0_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 40, 41, 43, 42 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif0_device = {
@@ -53,6 +54,7 @@ static struct plat_sci_port scif1_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 44, 44, 44, 44 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif1_device = {
@@ -70,6 +72,7 @@ static struct plat_sci_port scif2_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 50, 50, 50, 50 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif2_device = {
@@ -87,6 +90,7 @@ static struct plat_sci_port scif3_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 51, 51, 51, 51 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif3_device = {
@@ -104,6 +108,7 @@ static struct plat_sci_port scif4_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 52, 52, 52, 52 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif4_device = {
@@ -121,6 +126,7 @@ static struct plat_sci_port scif5_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 53, 53, 53, 53 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif5_device = {
index 84db0d6..32114e0 100644 (file)
 #include <linux/thread_info.h>
 #include <linux/irqflags.h>
 #include <linux/smp.h>
+#include <linux/cpuidle.h>
 #include <asm/pgalloc.h>
 #include <asm/system.h>
 #include <linux/atomic.h>
 #include <asm/smp.h>
 
-void (*pm_idle)(void) = NULL;
+static void (*pm_idle)(void);
 
 static int hlt_counter;
 
@@ -100,7 +101,8 @@ void cpu_idle(void)
                        local_irq_disable();
                        /* Don't trace irqs off for idle */
                        stop_critical_timings();
-                       pm_idle();
+                       if (cpuidle_idle_call())
+                               pm_idle();
                        /*
                         * Sanity check to ensure that pm_idle() returns
                         * with IRQs enabled
index 1074ddd..1a6f20d 100644 (file)
@@ -54,6 +54,8 @@ config SPARC64
        select HAVE_PERF_EVENTS
        select PERF_USE_VMALLOC
        select IRQ_PREFLOW_FASTEOI
+       select ARCH_HAVE_NMI_SAFE_CMPXCHG
+       select HAVE_C_RECORDMCOUNT
 
 config ARCH_DEFCONFIG
        string
index 3c93f08..2c2e388 100644 (file)
@@ -16,3 +16,8 @@ header-y += traps.h
 header-y += uctx.h
 header-y += utrap.h
 header-y += watchdog.h
+
+generic-y += div64.h
+generic-y += local64.h
+generic-y += irq_regs.h
+generic-y += local.h
index 325e295..29011cc 100644 (file)
@@ -26,61 +26,28 @@ extern void change_bit(unsigned long nr, volatile unsigned long *addr);
 #define smp_mb__before_clear_bit()     barrier()
 #define smp_mb__after_clear_bit()      barrier()
 
-#include <asm-generic/bitops/ffz.h>
-#include <asm-generic/bitops/__ffs.h>
 #include <asm-generic/bitops/fls.h>
 #include <asm-generic/bitops/__fls.h>
 #include <asm-generic/bitops/fls64.h>
 
 #ifdef __KERNEL__
 
+extern int ffs(int x);
+extern unsigned long __ffs(unsigned long);
+
+#include <asm-generic/bitops/ffz.h>
 #include <asm-generic/bitops/sched.h>
-#include <asm-generic/bitops/ffs.h>
 
 /*
  * hweightN: returns the hamming weight (i.e. the number
  * of bits set) of a N-bit word
  */
 
-#ifdef ULTRA_HAS_POPULATION_COUNT
-
-static inline unsigned int __arch_hweight64(unsigned long w)
-{
-       unsigned int res;
-
-       __asm__ ("popc %1,%0" : "=r" (res) : "r" (w));
-       return res;
-}
-
-static inline unsigned int __arch_hweight32(unsigned int w)
-{
-       unsigned int res;
-
-       __asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xffffffff));
-       return res;
-}
+extern unsigned long __arch_hweight64(__u64 w);
+extern unsigned int __arch_hweight32(unsigned int w);
+extern unsigned int __arch_hweight16(unsigned int w);
+extern unsigned int __arch_hweight8(unsigned int w);
 
-static inline unsigned int __arch_hweight16(unsigned int w)
-{
-       unsigned int res;
-
-       __asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xffff));
-       return res;
-}
-
-static inline unsigned int __arch_hweight8(unsigned int w)
-{
-       unsigned int res;
-
-       __asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xff));
-       return res;
-}
-
-#else
-
-#include <asm-generic/bitops/arch_hweight.h>
-
-#endif
 #include <asm-generic/bitops/const_hweight.h>
 #include <asm-generic/bitops/lock.h>
 #endif /* __KERNEL__ */
diff --git a/arch/sparc/include/asm/div64.h b/arch/sparc/include/asm/div64.h
deleted file mode 100644 (file)
index 6cd978c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/div64.h>
index cfa9cd2..7df8b7f 100644 (file)
 #define R_SPARC_6              45
 
 /* Bits present in AT_HWCAP, primarily for Sparc32.  */
-
-#define HWCAP_SPARC_FLUSH       1    /* CPU supports flush instruction. */
-#define HWCAP_SPARC_STBAR       2
-#define HWCAP_SPARC_SWAP        4
-#define HWCAP_SPARC_MULDIV      8
-#define HWCAP_SPARC_V9         16
-#define HWCAP_SPARC_ULTRA3     32
-#define HWCAP_SPARC_BLKINIT    64
-#define HWCAP_SPARC_N2         128
+#define HWCAP_SPARC_FLUSH       0x00000001
+#define HWCAP_SPARC_STBAR       0x00000002
+#define HWCAP_SPARC_SWAP        0x00000004
+#define HWCAP_SPARC_MULDIV      0x00000008
+#define HWCAP_SPARC_V9         0x00000010
+#define HWCAP_SPARC_ULTRA3     0x00000020
+#define HWCAP_SPARC_BLKINIT    0x00000040
+#define HWCAP_SPARC_N2         0x00000080
+
+/* Solaris compatible AT_HWCAP bits. */
+#define AV_SPARC_MUL32         0x00000100 /* 32x32 multiply is efficient */
+#define AV_SPARC_DIV32         0x00000200 /* 32x32 divide is efficient */
+#define AV_SPARC_FSMULD                0x00000400 /* 'fsmuld' is efficient */
+#define AV_SPARC_V8PLUS                0x00000800 /* v9 insn available to 32bit */
+#define AV_SPARC_POPC          0x00001000 /* 'popc' is efficient */
+#define AV_SPARC_VIS           0x00002000 /* VIS insns available */
+#define AV_SPARC_VIS2          0x00004000 /* VIS2 insns available */
+#define AV_SPARC_ASI_BLK_INIT  0x00008000 /* block init ASIs available */
+#define AV_SPARC_FMAF          0x00010000 /* fused multiply-add */
+#define AV_SPARC_VIS3          0x00020000 /* VIS3 insns available */
+#define AV_SPARC_HPC           0x00040000 /* HPC insns available */
+#define AV_SPARC_RANDOM                0x00080000 /* 'random' insn available */
+#define AV_SPARC_TRANS         0x00100000 /* transaction insns available */
+#define AV_SPARC_FJFMAU                0x00200000 /* unfused multiply-add */
+#define AV_SPARC_IMA           0x00400000 /* integer multiply-add */
+#define AV_SPARC_ASI_CACHE_SPARING \
+                               0x00800000 /* cache sparing ASIs available */
 
 #define CORE_DUMP_USE_REGSET
 
@@ -162,31 +180,8 @@ typedef struct {
 #define ELF_ET_DYN_BASE                0x0000010000000000UL
 #define COMPAT_ELF_ET_DYN_BASE 0x0000000070000000UL
 
-
-/* This yields a mask that user programs can use to figure out what
-   instruction set this cpu supports.  */
-
-/* On Ultra, we support all of the v8 capabilities. */
-static inline unsigned int sparc64_elf_hwcap(void)
-{
-       unsigned int cap = (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR |
-                           HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV |
-                           HWCAP_SPARC_V9);
-
-       if (tlb_type == cheetah || tlb_type == cheetah_plus)
-               cap |= HWCAP_SPARC_ULTRA3;
-       else if (tlb_type == hypervisor) {
-               if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1 ||
-                   sun4v_chip_type == SUN4V_CHIP_NIAGARA2)
-                       cap |= HWCAP_SPARC_BLKINIT;
-               if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2)
-                       cap |= HWCAP_SPARC_N2;
-       }
-
-       return cap;
-}
-
-#define ELF_HWCAP      sparc64_elf_hwcap()
+extern unsigned long sparc64_elf_hwcap;
+#define ELF_HWCAP      sparc64_elf_hwcap
 
 /* This yields a string that ld.so will use to load implementation
    specific libraries for optimization.  This is more specific in
index 7568640..015a761 100644 (file)
@@ -2927,6 +2927,13 @@ extern unsigned long sun4v_ncs_request(unsigned long request,
 #define HV_FAST_FIRE_GET_PERFREG       0x120
 #define HV_FAST_FIRE_SET_PERFREG       0x121
 
+#define HV_FAST_REBOOT_DATA_SET                0x172
+
+#ifndef __ASSEMBLY__
+extern unsigned long sun4v_reboot_data_set(unsigned long ra,
+                                          unsigned long len);
+#endif
+
 /* Function numbers for HV_CORE_TRAP.  */
 #define HV_CORE_SET_VER                        0x00
 #define HV_CORE_PUTCHAR                        0x01
@@ -2940,16 +2947,23 @@ extern unsigned long sun4v_ncs_request(unsigned long request,
 #define HV_GRP_CORE                    0x0001
 #define HV_GRP_INTR                    0x0002
 #define HV_GRP_SOFT_STATE              0x0003
+#define HV_GRP_TM                      0x0080
 #define HV_GRP_PCI                     0x0100
 #define HV_GRP_LDOM                    0x0101
 #define HV_GRP_SVC_CHAN                        0x0102
 #define HV_GRP_NCS                     0x0103
 #define HV_GRP_RNG                     0x0104
+#define HV_GRP_PBOOT                   0x0105
+#define HV_GRP_TPM                     0x0107
+#define HV_GRP_SDIO                    0x0108
+#define HV_GRP_SDIO_ERR                        0x0109
+#define HV_GRP_REBOOT_DATA             0x0110
 #define HV_GRP_NIAG_PERF               0x0200
 #define HV_GRP_FIRE_PERF               0x0201
 #define HV_GRP_N2_CPU                  0x0202
 #define HV_GRP_NIU                     0x0204
 #define HV_GRP_VF_CPU                  0x0205
+#define HV_GRP_KT_CPU                  0x0209
 #define HV_GRP_DIAG                    0x0300
 
 #ifndef __ASSEMBLY__
diff --git a/arch/sparc/include/asm/irq_regs.h b/arch/sparc/include/asm/irq_regs.h
deleted file mode 100644 (file)
index 3dd9c0b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/irq_regs.h>
index 42b4b31..f48527e 100644 (file)
@@ -12,7 +12,7 @@ struct leon_pci_info {
        struct pci_ops *ops;
        struct resource io_space;
        struct resource mem_space;
-       int (*map_irq)(struct pci_dev *dev, u8 slot, u8 pin);
+       int (*map_irq)(const struct pci_dev *dev, u8 slot, u8 pin);
 };
 
 extern void leon_pci_init(struct platform_device *ofdev,
diff --git a/arch/sparc/include/asm/local.h b/arch/sparc/include/asm/local.h
deleted file mode 100644 (file)
index bc80815..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _SPARC_LOCAL_H
-#define _SPARC_LOCAL_H
-
-#include <asm-generic/local.h>
-
-#endif
diff --git a/arch/sparc/include/asm/local64.h b/arch/sparc/include/asm/local64.h
deleted file mode 100644 (file)
index 36c93b5..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/local64.h>
index a1607d1..69914d7 100644 (file)
@@ -45,6 +45,19 @@ typedef struct {
        int                     si_mask;
 } __siginfo32_t;
 
+#define __SIGC_MAXWIN  7
+
+typedef struct {
+       unsigned long locals[8];
+       unsigned long ins[8];
+} __siginfo_reg_window;
+
+typedef struct {
+       int                     wsaved;
+       __siginfo_reg_window    reg_window[__SIGC_MAXWIN];
+       unsigned long           rwbuf_stkptrs[__SIGC_MAXWIN];
+} __siginfo_rwin_t;
+
 #ifdef CONFIG_SPARC64
 typedef struct {
        unsigned   int si_float_regs [64];
@@ -73,6 +86,7 @@ struct sigcontext {
                unsigned long   ss_size;
        }                       sigc_stack;
        unsigned long           sigc_mask;
+       __siginfo_rwin_t *      sigc_rwin_save;
 };
 
 #else
index 5f5b8bf..bcc98fc 100644 (file)
@@ -131,6 +131,15 @@ static inline void arch_write_lock(arch_rwlock_t *rw)
        *(volatile __u32 *)&lp->lock = ~0U;
 }
 
+static void inline arch_write_unlock(arch_rwlock_t *lock)
+{
+       __asm__ __volatile__(
+"      st              %%g0, [%0]"
+       : /* no outputs */
+       : "r" (lock)
+       : "memory");
+}
+
 static inline int arch_write_trylock(arch_rwlock_t *rw)
 {
        unsigned int val;
@@ -175,8 +184,6 @@ static inline int __arch_read_trylock(arch_rwlock_t *rw)
        res; \
 })
 
-#define arch_write_unlock(rw)  do { (rw)->lock = 0; } while(0)
-
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 #define arch_read_lock_flags(rw, flags)   arch_read_lock(rw)
 #define arch_write_lock_flags(rw, flags)  arch_write_lock(rw)
index 073936a..9689176 100644 (file)
@@ -210,14 +210,8 @@ static int inline arch_write_trylock(arch_rwlock_t *lock)
        return result;
 }
 
-#define arch_read_lock(p)      arch_read_lock(p)
 #define arch_read_lock_flags(p, f) arch_read_lock(p)
-#define arch_read_trylock(p)   arch_read_trylock(p)
-#define arch_read_unlock(p)    arch_read_unlock(p)
-#define arch_write_lock(p)     arch_write_lock(p)
 #define arch_write_lock_flags(p, f) arch_write_lock(p)
-#define arch_write_unlock(p)   arch_write_unlock(p)
-#define arch_write_trylock(p)  arch_write_trylock(p)
 
 #define arch_read_can_lock(rw)         (!((rw)->lock & 0x80000000UL))
 #define arch_write_can_lock(rw)        (!(rw)->lock)
index f0d0c40..55a17c6 100644 (file)
@@ -42,6 +42,7 @@
 #define SUN4V_CHIP_INVALID     0x00
 #define SUN4V_CHIP_NIAGARA1    0x01
 #define SUN4V_CHIP_NIAGARA2    0x02
+#define SUN4V_CHIP_NIAGARA3    0x03
 #define SUN4V_CHIP_UNKNOWN     0xff
 
 #ifndef __ASSEMBLY__
index 83c571d..1a8afd1 100644 (file)
@@ -133,29 +133,6 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
        sub     TSB, 0x8, TSB;   \
        TSB_STORE(TSB, TAG);
 
-#define KTSB_LOAD_QUAD(TSB, REG) \
-       ldda            [TSB] ASI_NUCLEUS_QUAD_LDD, REG;
-
-#define KTSB_STORE(ADDR, VAL) \
-       stxa            VAL, [ADDR] ASI_N;
-
-#define KTSB_LOCK_TAG(TSB, REG1, REG2) \
-99:    lduwa   [TSB] ASI_N, REG1;      \
-       sethi   %hi(TSB_TAG_LOCK_HIGH), REG2;\
-       andcc   REG1, REG2, %g0;        \
-       bne,pn  %icc, 99b;              \
-        nop;                           \
-       casa    [TSB] ASI_N, REG1, REG2;\
-       cmp     REG1, REG2;             \
-       bne,pn  %icc, 99b;              \
-        nop;                           \
-
-#define KTSB_WRITE(TSB, TTE, TAG) \
-       add     TSB, 0x8, TSB;   \
-       stxa    TTE, [TSB] ASI_N;     \
-       sub     TSB, 0x8, TSB;   \
-       stxa    TAG, [TSB] ASI_N;
-
        /* Do a kernel page table walk.  Leaves physical PTE pointer in
         * REG1.  Jumps to FAIL_LABEL on early page table walk termination.
         * VADDR will not be clobbered, but REG2 will.
@@ -239,6 +216,8 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
        (KERNEL_TSB_SIZE_BYTES / 16)
 #define KERNEL_TSB4M_NENTRIES  4096
 
+#define KTSB_PHYS_SHIFT                15
+
        /* Do a kernel TSB lookup at tl>0 on VADDR+TAG, branch to OK_LABEL
         * on TSB hit.  REG1, REG2, REG3, and REG4 are used as temporaries
         * and the found TTE will be left in REG1.  REG3 and REG4 must
@@ -247,13 +226,22 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
         * VADDR and TAG will be preserved and not clobbered by this macro.
         */
 #define KERN_TSB_LOOKUP_TL1(VADDR, TAG, REG1, REG2, REG3, REG4, OK_LABEL) \
-       sethi           %hi(swapper_tsb), REG1; \
+661:   sethi           %hi(swapper_tsb), REG1;                 \
        or              REG1, %lo(swapper_tsb), REG1; \
+       .section        .swapper_tsb_phys_patch, "ax"; \
+       .word           661b; \
+       .previous; \
+661:   nop; \
+       .section        .tsb_ldquad_phys_patch, "ax"; \
+       .word           661b; \
+       sllx            REG1, KTSB_PHYS_SHIFT, REG1; \
+       sllx            REG1, KTSB_PHYS_SHIFT, REG1; \
+       .previous; \
        srlx            VADDR, PAGE_SHIFT, REG2; \
        and             REG2, (KERNEL_TSB_NENTRIES - 1), REG2; \
        sllx            REG2, 4, REG2; \
        add             REG1, REG2, REG2; \
-       KTSB_LOAD_QUAD(REG2, REG3); \
+       TSB_LOAD_QUAD(REG2, REG3); \
        cmp             REG3, TAG; \
        be,a,pt         %xcc, OK_LABEL; \
         mov            REG4, REG1;
@@ -263,12 +251,21 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
         * we can make use of that for the index computation.
         */
 #define KERN_TSB4M_LOOKUP_TL1(TAG, REG1, REG2, REG3, REG4, OK_LABEL) \
-       sethi           %hi(swapper_4m_tsb), REG1; \
+661:   sethi           %hi(swapper_4m_tsb), REG1;           \
        or              REG1, %lo(swapper_4m_tsb), REG1; \
+       .section        .swapper_4m_tsb_phys_patch, "ax"; \
+       .word           661b; \
+       .previous; \
+661:   nop; \
+       .section        .tsb_ldquad_phys_patch, "ax"; \
+       .word           661b; \
+       sllx            REG1, KTSB_PHYS_SHIFT, REG1; \
+       sllx            REG1, KTSB_PHYS_SHIFT, REG1; \
+       .previous; \
        and             TAG, (KERNEL_TSB4M_NENTRIES - 1), REG2; \
        sllx            REG2, 4, REG2; \
        add             REG1, REG2, REG2; \
-       KTSB_LOAD_QUAD(REG2, REG3); \
+       TSB_LOAD_QUAD(REG2, REG3); \
        cmp             REG3, TAG; \
        be,a,pt         %xcc, OK_LABEL; \
         mov            REG4, REG1;
index bee4bf4..9ed6ff6 100644 (file)
@@ -65,6 +65,7 @@ static struct xor_block_template xor_block_niagara = {
 #define XOR_SELECT_TEMPLATE(FASTEST) \
        ((tlb_type == hypervisor && \
          (sun4v_chip_type == SUN4V_CHIP_NIAGARA1 || \
-          sun4v_chip_type == SUN4V_CHIP_NIAGARA2)) ? \
+          sun4v_chip_type == SUN4V_CHIP_NIAGARA2 || \
+          sun4v_chip_type == SUN4V_CHIP_NIAGARA3)) ? \
         &xor_block_niagara : \
         &xor_block_VIS)
index b90b4a1..cb85458 100644 (file)
@@ -32,6 +32,7 @@ obj-$(CONFIG_SPARC32)   += sun4m_irq.o sun4c_irq.o sun4d_irq.o
 
 obj-y                   += process_$(BITS).o
 obj-y                   += signal_$(BITS).o
+obj-y                   += sigutil_$(BITS).o
 obj-$(CONFIG_SPARC32)   += ioport.o
 obj-y                   += setup_$(BITS).o
 obj-y                   += idprom.o
index 138dbbc..9810fd8 100644 (file)
@@ -396,6 +396,7 @@ static int show_cpuinfo(struct seq_file *m, void *__unused)
                   , cpu_data(0).clock_tick
 #endif
                );
+       cpucap_info(m);
 #ifdef CONFIG_SMP
        smp_bogo(m);
 #endif
@@ -474,11 +475,18 @@ static void __init sun4v_cpu_probe(void)
                sparc_pmu_type = "niagara2";
                break;
 
+       case SUN4V_CHIP_NIAGARA3:
+               sparc_cpu_type = "UltraSparc T3 (Niagara3)";
+               sparc_fpu_type = "UltraSparc T3 integrated FPU";
+               sparc_pmu_type = "niagara3";
+               break;
+
        default:
                printk(KERN_WARNING "CPU: Unknown sun4v cpu type [%s]\n",
                       prom_cpu_compatible);
                sparc_cpu_type = "Unknown SUN4V CPU";
                sparc_fpu_type = "Unknown SUN4V FPU";
+               sparc_pmu_type = "Unknown SUN4V PMU";
                break;
        }
 }
index d91fd78..4197e8d 100644 (file)
@@ -324,6 +324,7 @@ static int iterate_cpu(struct cpuinfo_tree *t, unsigned int root_index)
        switch (sun4v_chip_type) {
        case SUN4V_CHIP_NIAGARA1:
        case SUN4V_CHIP_NIAGARA2:
+       case SUN4V_CHIP_NIAGARA3:
                rover_inc_table = niagara_iterate_method;
                break;
        default:
index dd1342c..7429b47 100644 (file)
 #include <linux/reboot.h>
 #include <linux/cpu.h>
 
+#include <asm/hypervisor.h>
 #include <asm/ldc.h>
 #include <asm/vio.h>
 #include <asm/mdesc.h>
 #include <asm/head.h>
 #include <asm/irq.h>
 
+#include "kernel.h"
+
 #define DRV_MODULE_NAME                "ds"
 #define PFX DRV_MODULE_NAME    ": "
 #define DRV_MODULE_VERSION     "1.0"
@@ -828,18 +831,32 @@ void ldom_set_var(const char *var, const char *value)
        }
 }
 
+static char full_boot_str[256] __attribute__((aligned(32)));
+static int reboot_data_supported;
+
 void ldom_reboot(const char *boot_command)
 {
        /* Don't bother with any of this if the boot_command
         * is empty.
         */
        if (boot_command && strlen(boot_command)) {
-               char full_boot_str[256];
+               unsigned long len;
 
                strcpy(full_boot_str, "boot ");
                strcpy(full_boot_str + strlen("boot "), boot_command);
+               len = strlen(full_boot_str);
 
-               ldom_set_var("reboot-command", full_boot_str);
+               if (reboot_data_supported) {
+                       unsigned long ra = kimage_addr_to_ra(full_boot_str);
+                       unsigned long hv_ret;
+
+                       hv_ret = sun4v_reboot_data_set(ra, len);
+                       if (hv_ret != HV_EOK)
+                               pr_err("SUN4V: Unable to set reboot data "
+                                      "hv_ret=%lu\n", hv_ret);
+               } else {
+                       ldom_set_var("reboot-command", full_boot_str);
+               }
        }
        sun4v_mach_sir();
 }
@@ -1237,6 +1254,16 @@ static struct vio_driver ds_driver = {
 
 static int __init ds_init(void)
 {
+       unsigned long hv_ret, major, minor;
+
+       if (tlb_type == hypervisor) {
+               hv_ret = sun4v_get_version(HV_GRP_REBOOT_DATA, &major, &minor);
+               if (hv_ret == HV_EOK) {
+                       pr_info("SUN4V: Reboot data supported (maj=%lu,min=%lu).\n",
+                               major, minor);
+                       reboot_data_supported = 1;
+               }
+       }
        kthread_run(ds_thread, NULL, "kldomd");
 
        return vio_register_driver(&ds_driver);
index d1f1361..e27f8ea 100644 (file)
@@ -42,6 +42,20 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
 extern void fpload(unsigned long *fpregs, unsigned long *fsr);
 
 #else /* CONFIG_SPARC32 */
+struct popc_3insn_patch_entry {
+       unsigned int    addr;
+       unsigned int    insns[3];
+};
+extern struct popc_3insn_patch_entry __popc_3insn_patch,
+       __popc_3insn_patch_end;
+
+struct popc_6insn_patch_entry {
+       unsigned int    addr;
+       unsigned int    insns[6];
+};
+extern struct popc_6insn_patch_entry __popc_6insn_patch,
+       __popc_6insn_patch_end;
+
 extern void __init per_cpu_patch(void);
 extern void __init sun4v_patch(void);
 extern void __init boot_cpu_id_too_large(int cpu);
index aa594c7..0eac1b2 100644 (file)
@@ -132,6 +132,8 @@ prom_sun4v_name:
        .asciz  "sun4v"
 prom_niagara_prefix:
        .asciz  "SUNW,UltraSPARC-T"
+prom_sparc_prefix:
+       .asciz  "SPARC-T"
        .align  4
 prom_root_compatible:
        .skip   64
@@ -379,6 +381,22 @@ sun4v_chip_type:
        sethi   %hi(prom_niagara_prefix), %g7
        or      %g7, %lo(prom_niagara_prefix), %g7
        mov     17, %g3
+90:    ldub    [%g7], %g2
+       ldub    [%g1], %g4
+       cmp     %g2, %g4
+       bne,pn  %icc, 89f
+        add    %g7, 1, %g7
+       subcc   %g3, 1, %g3
+       bne,pt  %xcc, 90b
+        add    %g1, 1, %g1
+       ba,pt   %xcc, 91f
+        nop
+
+89:    sethi   %hi(prom_cpu_compatible), %g1
+       or      %g1, %lo(prom_cpu_compatible), %g1
+       sethi   %hi(prom_sparc_prefix), %g7
+       or      %g7, %lo(prom_sparc_prefix), %g7
+       mov     7, %g3
 90:    ldub    [%g7], %g2
        ldub    [%g1], %g4
        cmp     %g2, %g4
@@ -389,6 +407,15 @@ sun4v_chip_type:
         add    %g1, 1, %g1
 
        sethi   %hi(prom_cpu_compatible), %g1
+       or      %g1, %lo(prom_cpu_compatible), %g1
+       ldub    [%g1 + 7], %g2
+       cmp     %g2, '3'
+       be,pt   %xcc, 5f
+        mov    SUN4V_CHIP_NIAGARA3, %g4
+       ba,pt   %xcc, 4f
+        nop
+
+91:    sethi   %hi(prom_cpu_compatible), %g1
        or      %g1, %lo(prom_cpu_compatible), %g1
        ldub    [%g1 + 17], %g2
        cmp     %g2, '1'
@@ -397,6 +424,7 @@ sun4v_chip_type:
        cmp     %g2, '2'
        be,pt   %xcc, 5f
         mov    SUN4V_CHIP_NIAGARA2, %g4
+       
 4:
        mov     SUN4V_CHIP_UNKNOWN, %g4
 5:     sethi   %hi(sun4v_chip_type), %g2
@@ -514,6 +542,9 @@ niagara_tlb_fixup:
         cmp    %g1, SUN4V_CHIP_NIAGARA2
        be,pt   %xcc, niagara2_patch
         nop
+       cmp     %g1, SUN4V_CHIP_NIAGARA3
+       be,pt   %xcc, niagara2_patch
+        nop
 
        call    generic_patch_copyops
         nop
@@ -528,7 +559,7 @@ niagara2_patch:
         nop
        call    niagara_patch_bzero
         nop
-       call    niagara2_patch_pageops
+       call    niagara_patch_pageops
         nop
 
        ba,a,pt %xcc, 80f
index 7c60afb..c2d055d 100644 (file)
@@ -28,16 +28,23 @@ static struct api_info api_table[] = {
        { .group = HV_GRP_CORE,         .flags = FLAG_PRE_API   },
        { .group = HV_GRP_INTR,                                 },
        { .group = HV_GRP_SOFT_STATE,                           },
+       { .group = HV_GRP_TM,                                   },
        { .group = HV_GRP_PCI,          .flags = FLAG_PRE_API   },
        { .group = HV_GRP_LDOM,                                 },
        { .group = HV_GRP_SVC_CHAN,     .flags = FLAG_PRE_API   },
        { .group = HV_GRP_NCS,          .flags = FLAG_PRE_API   },
        { .group = HV_GRP_RNG,                                  },
+       { .group = HV_GRP_PBOOT,                                },
+       { .group = HV_GRP_TPM,                                  },
+       { .group = HV_GRP_SDIO,                                 },
+       { .group = HV_GRP_SDIO_ERR,                             },
+       { .group = HV_GRP_REBOOT_DATA,                          },
        { .group = HV_GRP_NIAG_PERF,    .flags = FLAG_PRE_API   },
        { .group = HV_GRP_FIRE_PERF,                            },
        { .group = HV_GRP_N2_CPU,                               },
        { .group = HV_GRP_NIU,                                  },
        { .group = HV_GRP_VF_CPU,                               },
+       { .group = HV_GRP_KT_CPU,                               },
        { .group = HV_GRP_DIAG,         .flags = FLAG_PRE_API   },
 };
 
index 8a5f35f..58d60de 100644 (file)
@@ -798,3 +798,10 @@ ENTRY(sun4v_niagara2_setperf)
        retl
         nop
 ENDPROC(sun4v_niagara2_setperf)
+
+ENTRY(sun4v_reboot_data_set)
+       mov     HV_FAST_REBOOT_DATA_SET, %o5
+       ta      HV_FAST_TRAP
+       retl
+        nop
+ENDPROC(sun4v_reboot_data_set)
index 6ffccd6..d0479e2 100644 (file)
@@ -65,9 +65,6 @@ static inline void dma_make_coherent(unsigned long pa, unsigned long len)
 }
 #endif
 
-static struct resource *_sparc_find_resource(struct resource *r,
-                                            unsigned long);
-
 static void __iomem *_sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz);
 static void __iomem *_sparc_alloc_io(unsigned int busno, unsigned long phys,
     unsigned long size, char *name);
@@ -143,7 +140,11 @@ void iounmap(volatile void __iomem *virtual)
        unsigned long vaddr = (unsigned long) virtual & PAGE_MASK;
        struct resource *res;
 
-       if ((res = _sparc_find_resource(&sparc_iomap, vaddr)) == NULL) {
+       /*
+        * XXX Too slow. Can have 8192 DVMA pages on sun4m in the worst case.
+        * This probably warrants some sort of hashing.
+       */
+       if ((res = lookup_resource(&sparc_iomap, vaddr)) == NULL) {
                printk("free_io/iounmap: cannot free %lx\n", vaddr);
                return;
        }
@@ -319,7 +320,7 @@ static void sbus_free_coherent(struct device *dev, size_t n, void *p,
        struct resource *res;
        struct page *pgv;
 
-       if ((res = _sparc_find_resource(&_sparc_dvma,
+       if ((res = lookup_resource(&_sparc_dvma,
            (unsigned long)p)) == NULL) {
                printk("sbus_free_consistent: cannot free %p\n", p);
                return;
@@ -492,7 +493,7 @@ static void pci32_free_coherent(struct device *dev, size_t n, void *p,
 {
        struct resource *res;
 
-       if ((res = _sparc_find_resource(&_sparc_dvma,
+       if ((res = lookup_resource(&_sparc_dvma,
            (unsigned long)p)) == NULL) {
                printk("pci_free_consistent: cannot free %p\n", p);
                return;
@@ -715,25 +716,6 @@ static const struct file_operations sparc_io_proc_fops = {
 };
 #endif /* CONFIG_PROC_FS */
 
-/*
- * This is a version of find_resource and it belongs to kernel/resource.c.
- * Until we have agreement with Linus and Martin, it lingers here.
- *
- * XXX Too slow. Can have 8192 DVMA pages on sun4m in the worst case.
- * This probably warrants some sort of hashing.
- */
-static struct resource *_sparc_find_resource(struct resource *root,
-                                            unsigned long hit)
-{
-       struct resource *tmp;
-
-       for (tmp = root->child; tmp != 0; tmp = tmp->sibling) {
-               if (tmp->start <= hit && tmp->end >= hit)
-                       return tmp;
-       }
-       return NULL;
-}
-
 static void register_proc_sparc_ioport(void)
 {
 #ifdef CONFIG_PROC_FS
index 6f6544c..fd6c36b 100644 (file)
@@ -4,12 +4,27 @@
 #include <linux/interrupt.h>
 
 #include <asm/traps.h>
+#include <asm/head.h>
+#include <asm/io.h>
 
 /* cpu.c */
 extern const char *sparc_pmu_type;
 extern unsigned int fsr_storage;
 extern int ncpus_probed;
 
+#ifdef CONFIG_SPARC64
+/* setup_64.c */
+struct seq_file;
+extern void cpucap_info(struct seq_file *);
+
+static inline unsigned long kimage_addr_to_ra(const char *p)
+{
+       unsigned long val = (unsigned long) p;
+
+       return kern_base + (val - KERNBASE);
+}
+#endif
+
 #ifdef CONFIG_SPARC32
 /* cpu.c */
 extern void cpu_probe(void);
index 1d36147..79f3103 100644 (file)
@@ -47,16 +47,16 @@ kvmap_itlb_tsb_miss:
 kvmap_itlb_vmalloc_addr:
        KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_itlb_longpath)
 
-       KTSB_LOCK_TAG(%g1, %g2, %g7)
+       TSB_LOCK_TAG(%g1, %g2, %g7)
 
        /* Load and check PTE.  */
        ldxa            [%g5] ASI_PHYS_USE_EC, %g5
        mov             1, %g7
        sllx            %g7, TSB_TAG_INVALID_BIT, %g7
        brgez,a,pn      %g5, kvmap_itlb_longpath
-        KTSB_STORE(%g1, %g7)
+        TSB_STORE(%g1, %g7)
 
-       KTSB_WRITE(%g1, %g5, %g6)
+       TSB_WRITE(%g1, %g5, %g6)
 
        /* fallthrough to TLB load */
 
@@ -102,9 +102,9 @@ kvmap_itlb_longpath:
 kvmap_itlb_obp:
        OBP_TRANS_LOOKUP(%g4, %g5, %g2, %g3, kvmap_itlb_longpath)
 
-       KTSB_LOCK_TAG(%g1, %g2, %g7)
+       TSB_LOCK_TAG(%g1, %g2, %g7)
 
-       KTSB_WRITE(%g1, %g5, %g6)
+       TSB_WRITE(%g1, %g5, %g6)
 
        ba,pt           %xcc, kvmap_itlb_load
         nop
@@ -112,17 +112,17 @@ kvmap_itlb_obp:
 kvmap_dtlb_obp:
        OBP_TRANS_LOOKUP(%g4, %g5, %g2, %g3, kvmap_dtlb_longpath)
 
-       KTSB_LOCK_TAG(%g1, %g2, %g7)
+       TSB_LOCK_TAG(%g1, %g2, %g7)
 
-       KTSB_WRITE(%g1, %g5, %g6)
+       TSB_WRITE(%g1, %g5, %g6)
 
        ba,pt           %xcc, kvmap_dtlb_load
         nop
 
        .align          32
 kvmap_dtlb_tsb4m_load:
-       KTSB_LOCK_TAG(%g1, %g2, %g7)
-       KTSB_WRITE(%g1, %g5, %g6)
+       TSB_LOCK_TAG(%g1, %g2, %g7)
+       TSB_WRITE(%g1, %g5, %g6)
        ba,pt           %xcc, kvmap_dtlb_load
         nop
 
@@ -222,16 +222,16 @@ kvmap_linear_patch:
 kvmap_dtlb_vmalloc_addr:
        KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_dtlb_longpath)
 
-       KTSB_LOCK_TAG(%g1, %g2, %g7)
+       TSB_LOCK_TAG(%g1, %g2, %g7)
 
        /* Load and check PTE.  */
        ldxa            [%g5] ASI_PHYS_USE_EC, %g5
        mov             1, %g7
        sllx            %g7, TSB_TAG_INVALID_BIT, %g7
        brgez,a,pn      %g5, kvmap_dtlb_longpath
-        KTSB_STORE(%g1, %g7)
+        TSB_STORE(%g1, %g7)
 
-       KTSB_WRITE(%g1, %g5, %g6)
+       TSB_WRITE(%g1, %g5, %g6)
 
        /* fallthrough to TLB load */
 
index 44dc093..fad1bd0 100644 (file)
@@ -215,7 +215,7 @@ struct grpci2_priv {
 DEFINE_SPINLOCK(grpci2_dev_lock);
 struct grpci2_priv *grpci2priv;
 
-int grpci2_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+int grpci2_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        struct grpci2_priv *priv = dev->bus->sysdata;
        int irq_group;
index 42f28c7..acaebb6 100644 (file)
@@ -508,6 +508,8 @@ const char *mdesc_node_name(struct mdesc_handle *hp, u64 node)
 }
 EXPORT_SYMBOL(mdesc_node_name);
 
+static u64 max_cpus = 64;
+
 static void __init report_platform_properties(void)
 {
        struct mdesc_handle *hp = mdesc_grab();
@@ -543,8 +545,10 @@ static void __init report_platform_properties(void)
        if (v)
                printk("PLATFORM: watchdog-max-timeout [%llu ms]\n", *v);
        v = mdesc_get_property(hp, pn, "max-cpus", NULL);
-       if (v)
-               printk("PLATFORM: max-cpus [%llu]\n", *v);
+       if (v) {
+               max_cpus = *v;
+               printk("PLATFORM: max-cpus [%llu]\n", max_cpus);
+       }
 
 #ifdef CONFIG_SMP
        {
@@ -715,7 +719,7 @@ static void __cpuinit set_proc_ids(struct mdesc_handle *hp)
 }
 
 static void __cpuinit get_one_mondo_bits(const u64 *p, unsigned int *mask,
-                                        unsigned char def)
+                                        unsigned long def, unsigned long max)
 {
        u64 val;
 
@@ -726,6 +730,9 @@ static void __cpuinit get_one_mondo_bits(const u64 *p, unsigned int *mask,
        if (!val || val >= 64)
                goto use_default;
 
+       if (val > max)
+               val = max;
+
        *mask = ((1U << val) * 64U) - 1U;
        return;
 
@@ -736,19 +743,28 @@ use_default:
 static void __cpuinit get_mondo_data(struct mdesc_handle *hp, u64 mp,
                                     struct trap_per_cpu *tb)
 {
+       static int printed;
        const u64 *val;
 
        val = mdesc_get_property(hp, mp, "q-cpu-mondo-#bits", NULL);
-       get_one_mondo_bits(val, &tb->cpu_mondo_qmask, 7);
+       get_one_mondo_bits(val, &tb->cpu_mondo_qmask, 7, ilog2(max_cpus * 2));
 
        val = mdesc_get_property(hp, mp, "q-dev-mondo-#bits", NULL);
-       get_one_mondo_bits(val, &tb->dev_mondo_qmask, 7);
+       get_one_mondo_bits(val, &tb->dev_mondo_qmask, 7, 8);
 
        val = mdesc_get_property(hp, mp, "q-resumable-#bits", NULL);
-       get_one_mondo_bits(val, &tb->resum_qmask, 6);
+       get_one_mondo_bits(val, &tb->resum_qmask, 6, 7);
 
        val = mdesc_get_property(hp, mp, "q-nonresumable-#bits", NULL);
-       get_one_mondo_bits(val, &tb->nonresum_qmask, 2);
+       get_one_mondo_bits(val, &tb->nonresum_qmask, 2, 2);
+       if (!printed++) {
+               pr_info("SUN4V: Mondo queue sizes "
+                       "[cpu(%u) dev(%u) r(%u) nr(%u)]\n",
+                       tb->cpu_mondo_qmask + 1,
+                       tb->dev_mondo_qmask + 1,
+                       tb->resum_qmask + 1,
+                       tb->nonresum_qmask + 1);
+       }
 }
 
 static void * __cpuinit mdesc_iterate_over_cpus(void *(*func)(struct mdesc_handle *, u64, int, void *), void *arg, cpumask_t *mask)
index a19f041..1aaf8c1 100644 (file)
@@ -352,8 +352,8 @@ int __init pcic_probe(void)
        strcpy(pbm->prom_name, namebuf);
 
        {
-               extern volatile int t_nmi[1];
-               extern int pcic_nmi_trap_patch[1];
+               extern volatile int t_nmi[4];
+               extern int pcic_nmi_trap_patch[4];
 
                t_nmi[0] = pcic_nmi_trap_patch[0];
                t_nmi[1] = pcic_nmi_trap_patch[1];
index 8ac23e6..343b0f9 100644 (file)
@@ -80,8 +80,11 @@ static void n2_pcr_write(u64 val)
 {
        unsigned long ret;
 
-       ret = sun4v_niagara2_setperf(HV_N2_PERF_SPARC_CTL, val);
-       if (ret != HV_EOK)
+       if (val & PCR_N2_HTRACE) {
+               ret = sun4v_niagara2_setperf(HV_N2_PERF_SPARC_CTL, val);
+               if (ret != HV_EOK)
+                       write_pcr(val);
+       } else
                write_pcr(val);
 }
 
@@ -106,6 +109,10 @@ static int __init register_perf_hsvc(void)
                        perf_hsvc_group = HV_GRP_N2_CPU;
                        break;
 
+               case SUN4V_CHIP_NIAGARA3:
+                       perf_hsvc_group = HV_GRP_KT_CPU;
+                       break;
+
                default:
                        return -ENODEV;
                }
index 171e8d8..614da62 100644 (file)
@@ -1343,7 +1343,8 @@ static bool __init supported_pmu(void)
                sparc_pmu = &niagara1_pmu;
                return true;
        }
-       if (!strcmp(sparc_pmu_type, "niagara2")) {
+       if (!strcmp(sparc_pmu_type, "niagara2") ||
+           !strcmp(sparc_pmu_type, "niagara3")) {
                sparc_pmu = &niagara2_pmu;
                return true;
        }
index c4dd099..3e9daea 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/interrupt.h>
 #include <linux/cpu.h>
 #include <linux/initrd.h>
+#include <linux/module.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -46,6 +47,8 @@
 #include <asm/mmu.h>
 #include <asm/ns87303.h>
 #include <asm/btext.h>
+#include <asm/elf.h>
+#include <asm/mdesc.h>
 
 #ifdef CONFIG_IP_PNP
 #include <net/ipconfig.h>
@@ -269,6 +272,40 @@ void __init sun4v_patch(void)
        sun4v_hvapi_init();
 }
 
+static void __init popc_patch(void)
+{
+       struct popc_3insn_patch_entry *p3;
+       struct popc_6insn_patch_entry *p6;
+
+       p3 = &__popc_3insn_patch;
+       while (p3 < &__popc_3insn_patch_end) {
+               unsigned long i, addr = p3->addr;
+
+               for (i = 0; i < 3; i++) {
+                       *(unsigned int *) (addr +  (i * 4)) = p3->insns[i];
+                       wmb();
+                       __asm__ __volatile__("flush     %0"
+                                            : : "r" (addr +  (i * 4)));
+               }
+
+               p3++;
+       }
+
+       p6 = &__popc_6insn_patch;
+       while (p6 < &__popc_6insn_patch_end) {
+               unsigned long i, addr = p6->addr;
+
+               for (i = 0; i < 6; i++) {
+                       *(unsigned int *) (addr +  (i * 4)) = p6->insns[i];
+                       wmb();
+                       __asm__ __volatile__("flush     %0"
+                                            : : "r" (addr +  (i * 4)));
+               }
+
+               p6++;
+       }
+}
+
 #ifdef CONFIG_SMP
 void __init boot_cpu_id_too_large(int cpu)
 {
@@ -278,6 +315,154 @@ void __init boot_cpu_id_too_large(int cpu)
 }
 #endif
 
+/* On Ultra, we support all of the v8 capabilities. */
+unsigned long sparc64_elf_hwcap = (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR |
+                                  HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV |
+                                  HWCAP_SPARC_V9);
+EXPORT_SYMBOL(sparc64_elf_hwcap);
+
+static const char *hwcaps[] = {
+       "flush", "stbar", "swap", "muldiv", "v9",
+       "ultra3", "blkinit", "n2",
+
+       /* These strings are as they appear in the machine description
+        * 'hwcap-list' property for cpu nodes.
+        */
+       "mul32", "div32", "fsmuld", "v8plus", "popc", "vis", "vis2",
+       "ASIBlkInit", "fmaf", "vis3", "hpc", "random", "trans", "fjfmau",
+       "ima", "cspare",
+};
+
+void cpucap_info(struct seq_file *m)
+{
+       unsigned long caps = sparc64_elf_hwcap;
+       int i, printed = 0;
+
+       seq_puts(m, "cpucaps\t\t: ");
+       for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
+               unsigned long bit = 1UL << i;
+               if (caps & bit) {
+                       seq_printf(m, "%s%s",
+                                  printed ? "," : "", hwcaps[i]);
+                       printed++;
+               }
+       }
+       seq_putc(m, '\n');
+}
+
+static void __init report_hwcaps(unsigned long caps)
+{
+       int i, printed = 0;
+
+       printk(KERN_INFO "CPU CAPS: [");
+       for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
+               unsigned long bit = 1UL << i;
+               if (caps & bit) {
+                       printk(KERN_CONT "%s%s",
+                              printed ? "," : "", hwcaps[i]);
+                       if (++printed == 8) {
+                               printk(KERN_CONT "]\n");
+                               printk(KERN_INFO "CPU CAPS: [");
+                               printed = 0;
+                       }
+               }
+       }
+       printk(KERN_CONT "]\n");
+}
+
+static unsigned long __init mdesc_cpu_hwcap_list(void)
+{
+       struct mdesc_handle *hp;
+       unsigned long caps = 0;
+       const char *prop;
+       int len;
+       u64 pn;
+
+       hp = mdesc_grab();
+       if (!hp)
+               return 0;
+
+       pn = mdesc_node_by_name(hp, MDESC_NODE_NULL, "cpu");
+       if (pn == MDESC_NODE_NULL)
+               goto out;
+
+       prop = mdesc_get_property(hp, pn, "hwcap-list", &len);
+       if (!prop)
+               goto out;
+
+       while (len) {
+               int i, plen;
+
+               for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
+                       unsigned long bit = 1UL << i;
+
+                       if (!strcmp(prop, hwcaps[i])) {
+                               caps |= bit;
+                               break;
+                       }
+               }
+
+               plen = strlen(prop) + 1;
+               prop += plen;
+               len -= plen;
+       }
+
+out:
+       mdesc_release(hp);
+       return caps;
+}
+
+/* This yields a mask that user programs can use to figure out what
+ * instruction set this cpu supports.
+ */
+static void __init init_sparc64_elf_hwcap(void)
+{
+       unsigned long cap = sparc64_elf_hwcap;
+       unsigned long mdesc_caps;
+
+       if (tlb_type == cheetah || tlb_type == cheetah_plus)
+               cap |= HWCAP_SPARC_ULTRA3;
+       else if (tlb_type == hypervisor) {
+               if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1 ||
+                   sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
+                   sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
+                       cap |= HWCAP_SPARC_BLKINIT;
+               if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
+                   sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
+                       cap |= HWCAP_SPARC_N2;
+       }
+
+       cap |= (AV_SPARC_MUL32 | AV_SPARC_DIV32 | AV_SPARC_V8PLUS);
+
+       mdesc_caps = mdesc_cpu_hwcap_list();
+       if (!mdesc_caps) {
+               if (tlb_type == spitfire)
+                       cap |= AV_SPARC_VIS;
+               if (tlb_type == cheetah || tlb_type == cheetah_plus)
+                       cap |= AV_SPARC_VIS | AV_SPARC_VIS2;
+               if (tlb_type == cheetah_plus)
+                       cap |= AV_SPARC_POPC;
+               if (tlb_type == hypervisor) {
+                       if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1)
+                               cap |= AV_SPARC_ASI_BLK_INIT;
+                       if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
+                           sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
+                               cap |= (AV_SPARC_VIS | AV_SPARC_VIS2 |
+                                       AV_SPARC_ASI_BLK_INIT |
+                                       AV_SPARC_POPC);
+                       if (sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
+                               cap |= (AV_SPARC_VIS3 | AV_SPARC_HPC |
+                                       AV_SPARC_FMAF);
+               }
+       }
+       sparc64_elf_hwcap = cap | mdesc_caps;
+
+       report_hwcaps(sparc64_elf_hwcap);
+
+       if (sparc64_elf_hwcap & AV_SPARC_POPC)
+               popc_patch();
+}
+
 void __init setup_arch(char **cmdline_p)
 {
        /* Initialize PROM console and command line. */
@@ -337,6 +522,7 @@ void __init setup_arch(char **cmdline_p)
        init_cur_cpu_trap(current_thread_info());
 
        paging_init();
+       init_sparc64_elf_hwcap();
 }
 
 extern int stop_a_enabled;
index 75fad42..1ba95af 100644 (file)
@@ -29,6 +29,8 @@
 #include <asm/visasm.h>
 #include <asm/compat_signal.h>
 
+#include "sigutil.h"
+
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
 /* This magic should be in g_upper[0] for all upper parts
@@ -44,14 +46,14 @@ typedef struct {
 struct signal_frame32 {
        struct sparc_stackf32   ss;
        __siginfo32_t           info;
-       /* __siginfo_fpu32_t * */ u32 fpu_save;
+       /* __siginfo_fpu_t * */ u32 fpu_save;
        unsigned int            insns[2];
        unsigned int            extramask[_COMPAT_NSIG_WORDS - 1];
        unsigned int            extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
        /* Only valid if (info.si_regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
        siginfo_extra_v8plus_t  v8plus;
-       __siginfo_fpu_t         fpu_state;
-};
+       /* __siginfo_rwin_t * */u32 rwin_save;
+} __attribute__((aligned(8)));
 
 typedef struct compat_siginfo{
        int si_signo;
@@ -110,18 +112,14 @@ struct rt_signal_frame32 {
        compat_siginfo_t        info;
        struct pt_regs32        regs;
        compat_sigset_t         mask;
-       /* __siginfo_fpu32_t * */ u32 fpu_save;
+       /* __siginfo_fpu_t * */ u32 fpu_save;
        unsigned int            insns[2];
        stack_t32               stack;
        unsigned int            extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
        /* Only valid if (regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
        siginfo_extra_v8plus_t  v8plus;
-       __siginfo_fpu_t         fpu_state;
-};
-
-/* Align macros */
-#define SF_ALIGNEDSZ  (((sizeof(struct signal_frame32) + 15) & (~15)))
-#define RT_ALIGNEDSZ  (((sizeof(struct rt_signal_frame32) + 15) & (~15)))
+       /* __siginfo_rwin_t * */u32 rwin_save;
+} __attribute__((aligned(8)));
 
 int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
 {
@@ -192,30 +190,13 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
        return 0;
 }
 
-static int restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
-{
-       unsigned long *fpregs = current_thread_info()->fpregs;
-       unsigned long fprs;
-       int err;
-       
-       err = __get_user(fprs, &fpu->si_fprs);
-       fprs_write(0);
-       regs->tstate &= ~TSTATE_PEF;
-       if (fprs & FPRS_DL)
-               err |= copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 32));
-       if (fprs & FPRS_DU)
-               err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32], (sizeof(unsigned int) * 32));
-       err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
-       err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr);
-       current_thread_info()->fpsaved[0] |= fprs;
-       return err;
-}
-
 void do_sigreturn32(struct pt_regs *regs)
 {
        struct signal_frame32 __user *sf;
+       compat_uptr_t fpu_save;
+       compat_uptr_t rwin_save;
        unsigned int psr;
-       unsigned pc, npc, fpu_save;
+       unsigned pc, npc;
        sigset_t set;
        unsigned seta[_COMPAT_NSIG_WORDS];
        int err, i;
@@ -273,8 +254,13 @@ void do_sigreturn32(struct pt_regs *regs)
        pt_regs_clear_syscall(regs);
 
        err |= __get_user(fpu_save, &sf->fpu_save);
-       if (fpu_save)
-               err |= restore_fpu_state32(regs, &sf->fpu_state);
+       if (!err && fpu_save)
+               err |= restore_fpu_state(regs, compat_ptr(fpu_save));
+       err |= __get_user(rwin_save, &sf->rwin_save);
+       if (!err && rwin_save) {
+               if (restore_rwin_state(compat_ptr(rwin_save)))
+                       goto segv;
+       }
        err |= __get_user(seta[0], &sf->info.si_mask);
        err |= copy_from_user(seta+1, &sf->extramask,
                              (_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));
@@ -300,7 +286,9 @@ segv:
 asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
 {
        struct rt_signal_frame32 __user *sf;
-       unsigned int psr, pc, npc, fpu_save, u_ss_sp;
+       unsigned int psr, pc, npc, u_ss_sp;
+       compat_uptr_t fpu_save;
+       compat_uptr_t rwin_save;
        mm_segment_t old_fs;
        sigset_t set;
        compat_sigset_t seta;
@@ -359,8 +347,8 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
        pt_regs_clear_syscall(regs);
 
        err |= __get_user(fpu_save, &sf->fpu_save);
-       if (fpu_save)
-               err |= restore_fpu_state32(regs, &sf->fpu_state);
+       if (!err && fpu_save)
+               err |= restore_fpu_state(regs, compat_ptr(fpu_save));
        err |= copy_from_user(&seta, &sf->mask, sizeof(compat_sigset_t));
        err |= __get_user(u_ss_sp, &sf->stack.ss_sp);
        st.ss_sp = compat_ptr(u_ss_sp);
@@ -376,6 +364,12 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
        do_sigaltstack((stack_t __user *) &st, NULL, (unsigned long)sf);
        set_fs(old_fs);
        
+       err |= __get_user(rwin_save, &sf->rwin_save);
+       if (!err && rwin_save) {
+               if (restore_rwin_state(compat_ptr(rwin_save)))
+                       goto segv;
+       }
+
        switch (_NSIG_WORDS) {
                case 4: set.sig[3] = seta.sig[6] + (((long)seta.sig[7]) << 32);
                case 3: set.sig[2] = seta.sig[4] + (((long)seta.sig[5]) << 32);
@@ -433,26 +427,6 @@ static void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, uns
        return (void __user *) sp;
 }
 
-static int save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
-{
-       unsigned long *fpregs = current_thread_info()->fpregs;
-       unsigned long fprs;
-       int err = 0;
-       
-       fprs = current_thread_info()->fpsaved[0];
-       if (fprs & FPRS_DL)
-               err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
-                                   (sizeof(unsigned int) * 32));
-       if (fprs & FPRS_DU)
-               err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
-                                   (sizeof(unsigned int) * 32));
-       err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
-       err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr);
-       err |= __put_user(fprs, &fpu->si_fprs);
-
-       return err;
-}
-
 /* The I-cache flush instruction only works in the primary ASI, which
  * right now is the nucleus, aka. kernel space.
  *
@@ -515,18 +489,23 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
                         int signo, sigset_t *oldset)
 {
        struct signal_frame32 __user *sf;
+       int i, err, wsaved;
+       void __user *tail;
        int sigframe_size;
        u32 psr;
-       int i, err;
        unsigned int seta[_COMPAT_NSIG_WORDS];
 
        /* 1. Make sure everything is clean */
        synchronize_user_stack();
        save_and_clear_fpu();
        
-       sigframe_size = SF_ALIGNEDSZ;
-       if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
-               sigframe_size -= sizeof(__siginfo_fpu_t);
+       wsaved = get_thread_wsaved();
+
+       sigframe_size = sizeof(*sf);
+       if (current_thread_info()->fpsaved[0] & FPRS_FEF)
+               sigframe_size += sizeof(__siginfo_fpu_t);
+       if (wsaved)
+               sigframe_size += sizeof(__siginfo_rwin_t);
 
        sf = (struct signal_frame32 __user *)
                get_sigframe(&ka->sa, regs, sigframe_size);
@@ -534,8 +513,7 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
        if (invalid_frame_pointer(sf, sigframe_size))
                goto sigill;
 
-       if (get_thread_wsaved() != 0)
-               goto sigill;
+       tail = (sf + 1);
 
        /* 2. Save the current process state */
        if (test_thread_flag(TIF_32BIT)) {
@@ -560,11 +538,22 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
                          &sf->v8plus.asi);
 
        if (psr & PSR_EF) {
-               err |= save_fpu_state32(regs, &sf->fpu_state);
-               err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
+               __siginfo_fpu_t __user *fp = tail;
+               tail += sizeof(*fp);
+               err |= save_fpu_state(regs, fp);
+               err |= __put_user((u64)fp, &sf->fpu_save);
        } else {
                err |= __put_user(0, &sf->fpu_save);
        }
+       if (wsaved) {
+               __siginfo_rwin_t __user *rwp = tail;
+               tail += sizeof(*rwp);
+               err |= save_rwin_state(wsaved, rwp);
+               err |= __put_user((u64)rwp, &sf->rwin_save);
+               set_thread_wsaved(0);
+       } else {
+               err |= __put_user(0, &sf->rwin_save);
+       }
 
        switch (_NSIG_WORDS) {
        case 4: seta[7] = (oldset->sig[3] >> 32);
@@ -580,10 +569,21 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
        err |= __copy_to_user(sf->extramask, seta + 1,
                              (_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));
 
-       err |= copy_in_user((u32 __user *)sf,
-                           (u32 __user *)(regs->u_regs[UREG_FP]),
-                           sizeof(struct reg_window32));
-       
+       if (!wsaved) {
+               err |= copy_in_user((u32 __user *)sf,
+                                   (u32 __user *)(regs->u_regs[UREG_FP]),
+                                   sizeof(struct reg_window32));
+       } else {
+               struct reg_window *rp;
+
+               rp = &current_thread_info()->reg_window[wsaved - 1];
+               for (i = 0; i < 8; i++)
+                       err |= __put_user(rp->locals[i], &sf->ss.locals[i]);
+               for (i = 0; i < 6; i++)
+                       err |= __put_user(rp->ins[i], &sf->ss.ins[i]);
+               err |= __put_user(rp->ins[6], &sf->ss.fp);
+               err |= __put_user(rp->ins[7], &sf->ss.callers_pc);
+       }       
        if (err)
                goto sigsegv;
 
@@ -613,7 +613,6 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
                err |= __put_user(0x91d02010, &sf->insns[1]); /*t 0x10*/
                if (err)
                        goto sigsegv;
-
                flush_signal_insns(address);
        }
        return 0;
@@ -632,18 +631,23 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
                            siginfo_t *info)
 {
        struct rt_signal_frame32 __user *sf;
+       int i, err, wsaved;
+       void __user *tail;
        int sigframe_size;
        u32 psr;
-       int i, err;
        compat_sigset_t seta;
 
        /* 1. Make sure everything is clean */
        synchronize_user_stack();
        save_and_clear_fpu();
        
-       sigframe_size = RT_ALIGNEDSZ;
-       if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
-               sigframe_size -= sizeof(__siginfo_fpu_t);
+       wsaved = get_thread_wsaved();
+
+       sigframe_size = sizeof(*sf);
+       if (current_thread_info()->fpsaved[0] & FPRS_FEF)
+               sigframe_size += sizeof(__siginfo_fpu_t);
+       if (wsaved)
+               sigframe_size += sizeof(__siginfo_rwin_t);
 
        sf = (struct rt_signal_frame32 __user *)
                get_sigframe(&ka->sa, regs, sigframe_size);
@@ -651,8 +655,7 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
        if (invalid_frame_pointer(sf, sigframe_size))
                goto sigill;
 
-       if (get_thread_wsaved() != 0)
-               goto sigill;
+       tail = (sf + 1);
 
        /* 2. Save the current process state */
        if (test_thread_flag(TIF_32BIT)) {
@@ -677,11 +680,22 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
                          &sf->v8plus.asi);
 
        if (psr & PSR_EF) {
-               err |= save_fpu_state32(regs, &sf->fpu_state);
-               err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
+               __siginfo_fpu_t __user *fp = tail;
+               tail += sizeof(*fp);
+               err |= save_fpu_state(regs, fp);
+               err |= __put_user((u64)fp, &sf->fpu_save);
        } else {
                err |= __put_user(0, &sf->fpu_save);
        }
+       if (wsaved) {
+               __siginfo_rwin_t __user *rwp = tail;
+               tail += sizeof(*rwp);
+               err |= save_rwin_state(wsaved, rwp);
+               err |= __put_user((u64)rwp, &sf->rwin_save);
+               set_thread_wsaved(0);
+       } else {
+               err |= __put_user(0, &sf->rwin_save);
+       }
 
        /* Update the siginfo structure.  */
        err |= copy_siginfo_to_user32(&sf->info, info);
@@ -703,9 +717,21 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
        }
        err |= __copy_to_user(&sf->mask, &seta, sizeof(compat_sigset_t));
 
-       err |= copy_in_user((u32 __user *)sf,
-                           (u32 __user *)(regs->u_regs[UREG_FP]),
-                           sizeof(struct reg_window32));
+       if (!wsaved) {
+               err |= copy_in_user((u32 __user *)sf,
+                                   (u32 __user *)(regs->u_regs[UREG_FP]),
+                                   sizeof(struct reg_window32));
+       } else {
+               struct reg_window *rp;
+
+               rp = &current_thread_info()->reg_window[wsaved - 1];
+               for (i = 0; i < 8; i++)
+                       err |= __put_user(rp->locals[i], &sf->ss.locals[i]);
+               for (i = 0; i < 6; i++)
+                       err |= __put_user(rp->ins[i], &sf->ss.ins[i]);
+               err |= __put_user(rp->ins[6], &sf->ss.fp);
+               err |= __put_user(rp->ins[7], &sf->ss.callers_pc);
+       }
        if (err)
                goto sigsegv;
        
index 5e5c5fd..04ede8f 100644 (file)
@@ -26,6 +26,8 @@
 #include <asm/pgtable.h>
 #include <asm/cacheflush.h>    /* flush_sig_insns */
 
+#include "sigutil.h"
+
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
 extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
@@ -39,8 +41,8 @@ struct signal_frame {
        unsigned long           insns[2] __attribute__ ((aligned (8)));
        unsigned int            extramask[_NSIG_WORDS - 1];
        unsigned int            extra_size; /* Should be 0 */
-       __siginfo_fpu_t         fpu_state;
-};
+       __siginfo_rwin_t __user *rwin_save;
+} __attribute__((aligned(8)));
 
 struct rt_signal_frame {
        struct sparc_stackf     ss;
@@ -51,8 +53,8 @@ struct rt_signal_frame {
        unsigned int            insns[2];
        stack_t                 stack;
        unsigned int            extra_size; /* Should be 0 */
-       __siginfo_fpu_t         fpu_state;
-};
+       __siginfo_rwin_t __user *rwin_save;
+} __attribute__((aligned(8)));
 
 /* Align macros */
 #define SF_ALIGNEDSZ  (((sizeof(struct signal_frame) + 7) & (~7)))
@@ -79,43 +81,13 @@ asmlinkage int sys_sigsuspend(old_sigset_t set)
        return _sigpause_common(set);
 }
 
-static inline int
-restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
-{
-       int err;
-#ifdef CONFIG_SMP
-       if (test_tsk_thread_flag(current, TIF_USEDFPU))
-               regs->psr &= ~PSR_EF;
-#else
-       if (current == last_task_used_math) {
-               last_task_used_math = NULL;
-               regs->psr &= ~PSR_EF;
-       }
-#endif
-       set_used_math();
-       clear_tsk_thread_flag(current, TIF_USEDFPU);
-
-       if (!access_ok(VERIFY_READ, fpu, sizeof(*fpu)))
-               return -EFAULT;
-
-       err = __copy_from_user(&current->thread.float_regs[0], &fpu->si_float_regs[0],
-                              (sizeof(unsigned long) * 32));
-       err |= __get_user(current->thread.fsr, &fpu->si_fsr);
-       err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
-       if (current->thread.fpqdepth != 0)
-               err |= __copy_from_user(&current->thread.fpqueue[0],
-                                       &fpu->si_fpqueue[0],
-                                       ((sizeof(unsigned long) +
-                                       (sizeof(unsigned long *)))*16));
-       return err;
-}
-
 asmlinkage void do_sigreturn(struct pt_regs *regs)
 {
        struct signal_frame __user *sf;
        unsigned long up_psr, pc, npc;
        sigset_t set;
        __siginfo_fpu_t __user *fpu_save;
+       __siginfo_rwin_t __user *rwin_save;
        int err;
 
        /* Always make any pending restarted system calls return -EINTR */
@@ -150,9 +122,11 @@ asmlinkage void do_sigreturn(struct pt_regs *regs)
        pt_regs_clear_syscall(regs);
 
        err |= __get_user(fpu_save, &sf->fpu_save);
-
        if (fpu_save)
                err |= restore_fpu_state(regs, fpu_save);
+       err |= __get_user(rwin_save, &sf->rwin_save);
+       if (rwin_save)
+               err |= restore_rwin_state(rwin_save);
 
        /* This is pretty much atomic, no amount locking would prevent
         * the races which exist anyways.
@@ -180,6 +154,7 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
        struct rt_signal_frame __user *sf;
        unsigned int psr, pc, npc;
        __siginfo_fpu_t __user *fpu_save;
+       __siginfo_rwin_t __user *rwin_save;
        mm_segment_t old_fs;
        sigset_t set;
        stack_t st;
@@ -207,8 +182,7 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
        pt_regs_clear_syscall(regs);
 
        err |= __get_user(fpu_save, &sf->fpu_save);
-
-       if (fpu_save)
+       if (!err && fpu_save)
                err |= restore_fpu_state(regs, fpu_save);
        err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
        
@@ -228,6 +202,12 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
        do_sigaltstack((const stack_t __user *) &st, NULL, (unsigned long)sf);
        set_fs(old_fs);
 
+       err |= __get_user(rwin_save, &sf->rwin_save);
+       if (!err && rwin_save) {
+               if (restore_rwin_state(rwin_save))
+                       goto segv;
+       }
+
        sigdelsetmask(&set, ~_BLOCKABLE);
        spin_lock_irq(&current->sighand->siglock);
        current->blocked = set;
@@ -280,53 +260,23 @@ static inline void __user *get_sigframe(struct sigaction *sa, struct pt_regs *re
        return (void __user *) sp;
 }
 
-static inline int
-save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
-{
-       int err = 0;
-#ifdef CONFIG_SMP
-       if (test_tsk_thread_flag(current, TIF_USEDFPU)) {
-               put_psr(get_psr() | PSR_EF);
-               fpsave(&current->thread.float_regs[0], &current->thread.fsr,
-                      &current->thread.fpqueue[0], &current->thread.fpqdepth);
-               regs->psr &= ~(PSR_EF);
-               clear_tsk_thread_flag(current, TIF_USEDFPU);
-       }
-#else
-       if (current == last_task_used_math) {
-               put_psr(get_psr() | PSR_EF);
-               fpsave(&current->thread.float_regs[0], &current->thread.fsr,
-                      &current->thread.fpqueue[0], &current->thread.fpqdepth);
-               last_task_used_math = NULL;
-               regs->psr &= ~(PSR_EF);
-       }
-#endif
-       err |= __copy_to_user(&fpu->si_float_regs[0],
-                             &current->thread.float_regs[0],
-                             (sizeof(unsigned long) * 32));
-       err |= __put_user(current->thread.fsr, &fpu->si_fsr);
-       err |= __put_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
-       if (current->thread.fpqdepth != 0)
-               err |= __copy_to_user(&fpu->si_fpqueue[0],
-                                     &current->thread.fpqueue[0],
-                                     ((sizeof(unsigned long) +
-                                     (sizeof(unsigned long *)))*16));
-       clear_used_math();
-       return err;
-}
-
 static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
                       int signo, sigset_t *oldset)
 {
        struct signal_frame __user *sf;
-       int sigframe_size, err;
+       int sigframe_size, err, wsaved;
+       void __user *tail;
 
        /* 1. Make sure everything is clean */
        synchronize_user_stack();
 
-       sigframe_size = SF_ALIGNEDSZ;
-       if (!used_math())
-               sigframe_size -= sizeof(__siginfo_fpu_t);
+       wsaved = current_thread_info()->w_saved;
+
+       sigframe_size = sizeof(*sf);
+       if (used_math())
+               sigframe_size += sizeof(__siginfo_fpu_t);
+       if (wsaved)
+               sigframe_size += sizeof(__siginfo_rwin_t);
 
        sf = (struct signal_frame __user *)
                get_sigframe(&ka->sa, regs, sigframe_size);
@@ -334,8 +284,7 @@ static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
        if (invalid_frame_pointer(sf, sigframe_size))
                goto sigill_and_return;
 
-       if (current_thread_info()->w_saved != 0)
-               goto sigill_and_return;
+       tail = sf + 1;
 
        /* 2. Save the current process state */
        err = __copy_to_user(&sf->info.si_regs, regs, sizeof(struct pt_regs));
@@ -343,17 +292,34 @@ static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
        err |= __put_user(0, &sf->extra_size);
 
        if (used_math()) {
-               err |= save_fpu_state(regs, &sf->fpu_state);
-               err |= __put_user(&sf->fpu_state, &sf->fpu_save);
+               __siginfo_fpu_t __user *fp = tail;
+               tail += sizeof(*fp);
+               err |= save_fpu_state(regs, fp);
+               err |= __put_user(fp, &sf->fpu_save);
        } else {
                err |= __put_user(0, &sf->fpu_save);
        }
+       if (wsaved) {
+               __siginfo_rwin_t __user *rwp = tail;
+               tail += sizeof(*rwp);
+               err |= save_rwin_state(wsaved, rwp);
+               err |= __put_user(rwp, &sf->rwin_save);
+       } else {
+               err |= __put_user(0, &sf->rwin_save);
+       }
 
        err |= __put_user(oldset->sig[0], &sf->info.si_mask);
        err |= __copy_to_user(sf->extramask, &oldset->sig[1],
                              (_NSIG_WORDS - 1) * sizeof(unsigned int));
-       err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
-                             sizeof(struct reg_window32));
+       if (!wsaved) {
+               err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
+                                     sizeof(struct reg_window32));
+       } else {
+               struct reg_window32 *rp;
+
+               rp = &current_thread_info()->reg_window[wsaved - 1];
+               err |= __copy_to_user(sf, rp, sizeof(struct reg_window32));
+       }
        if (err)
                goto sigsegv;
        
@@ -399,21 +365,24 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
                          int signo, sigset_t *oldset, siginfo_t *info)
 {
        struct rt_signal_frame __user *sf;
-       int sigframe_size;
+       int sigframe_size, wsaved;
+       void __user *tail;
        unsigned int psr;
        int err;
 
        synchronize_user_stack();
-       sigframe_size = RT_ALIGNEDSZ;
-       if (!used_math())
-               sigframe_size -= sizeof(__siginfo_fpu_t);
+       wsaved = current_thread_info()->w_saved;
+       sigframe_size = sizeof(*sf);
+       if (used_math())
+               sigframe_size += sizeof(__siginfo_fpu_t);
+       if (wsaved)
+               sigframe_size += sizeof(__siginfo_rwin_t);
        sf = (struct rt_signal_frame __user *)
                get_sigframe(&ka->sa, regs, sigframe_size);
        if (invalid_frame_pointer(sf, sigframe_size))
                goto sigill;
-       if (current_thread_info()->w_saved != 0)
-               goto sigill;
 
+       tail = sf + 1;
        err  = __put_user(regs->pc, &sf->regs.pc);
        err |= __put_user(regs->npc, &sf->regs.npc);
        err |= __put_user(regs->y, &sf->regs.y);
@@ -425,11 +394,21 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
        err |= __put_user(0, &sf->extra_size);
 
        if (psr & PSR_EF) {
-               err |= save_fpu_state(regs, &sf->fpu_state);
-               err |= __put_user(&sf->fpu_state, &sf->fpu_save);
+               __siginfo_fpu_t *fp = tail;
+               tail += sizeof(*fp);
+               err |= save_fpu_state(regs, fp);
+               err |= __put_user(fp, &sf->fpu_save);
        } else {
                err |= __put_user(0, &sf->fpu_save);
        }
+       if (wsaved) {
+               __siginfo_rwin_t *rwp = tail;
+               tail += sizeof(*rwp);
+               err |= save_rwin_state(wsaved, rwp);
+               err |= __put_user(rwp, &sf->rwin_save);
+       } else {
+               err |= __put_user(0, &sf->rwin_save);
+       }
        err |= __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t));
        
        /* Setup sigaltstack */
@@ -437,8 +416,15 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
        err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
        err |= __put_user(current->sas_ss_size, &sf->stack.ss_size);
        
-       err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
-                             sizeof(struct reg_window32));
+       if (!wsaved) {
+               err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
+                                     sizeof(struct reg_window32));
+       } else {
+               struct reg_window32 *rp;
+
+               rp = &current_thread_info()->reg_window[wsaved - 1];
+               err |= __copy_to_user(sf, rp, sizeof(struct reg_window32));
+       }
 
        err |= copy_siginfo_to_user(&sf->info, info);
 
index 006fe45..47509df 100644 (file)
@@ -34,6 +34,7 @@
 
 #include "entry.h"
 #include "systbls.h"
+#include "sigutil.h"
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
@@ -236,7 +237,7 @@ struct rt_signal_frame {
        __siginfo_fpu_t __user  *fpu_save;
        stack_t                 stack;
        sigset_t                mask;
-       __siginfo_fpu_t         fpu_state;
+       __siginfo_rwin_t        *rwin_save;
 };
 
 static long _sigpause_common(old_sigset_t set)
@@ -266,33 +267,12 @@ asmlinkage long sys_sigsuspend(old_sigset_t set)
        return _sigpause_common(set);
 }
 
-static inline int
-restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
-{
-       unsigned long *fpregs = current_thread_info()->fpregs;
-       unsigned long fprs;
-       int err;
-
-       err = __get_user(fprs, &fpu->si_fprs);
-       fprs_write(0);
-       regs->tstate &= ~TSTATE_PEF;
-       if (fprs & FPRS_DL)
-               err |= copy_from_user(fpregs, &fpu->si_float_regs[0],
-                              (sizeof(unsigned int) * 32));
-       if (fprs & FPRS_DU)
-               err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32],
-                              (sizeof(unsigned int) * 32));
-       err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
-       err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr);
-       current_thread_info()->fpsaved[0] |= fprs;
-       return err;
-}
-
 void do_rt_sigreturn(struct pt_regs *regs)
 {
        struct rt_signal_frame __user *sf;
        unsigned long tpc, tnpc, tstate;
        __siginfo_fpu_t __user *fpu_save;
+       __siginfo_rwin_t __user *rwin_save;
        sigset_t set;
        int err;
 
@@ -325,8 +305,8 @@ void do_rt_sigreturn(struct pt_regs *regs)
        regs->tstate |= (tstate & (TSTATE_ASI | TSTATE_ICC | TSTATE_XCC));
 
        err |= __get_user(fpu_save, &sf->fpu_save);
-       if (fpu_save)
-               err |= restore_fpu_state(regs, &sf->fpu_state);
+       if (!err && fpu_save)
+               err |= restore_fpu_state(regs, fpu_save);
 
        err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
        err |= do_sigaltstack(&sf->stack, NULL, (unsigned long)sf);
@@ -334,6 +314,12 @@ void do_rt_sigreturn(struct pt_regs *regs)
        if (err)
                goto segv;
 
+       err |= __get_user(rwin_save, &sf->rwin_save);
+       if (!err && rwin_save) {
+               if (restore_rwin_state(rwin_save))
+                       goto segv;
+       }
+
        regs->tpc = tpc;
        regs->tnpc = tnpc;
 
@@ -351,34 +337,13 @@ segv:
 }
 
 /* Checks if the fp is valid */
-static int invalid_frame_pointer(void __user *fp, int fplen)
+static int invalid_frame_pointer(void __user *fp)
 {
        if (((unsigned long) fp) & 15)
                return 1;
        return 0;
 }
 
-static inline int
-save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
-{
-       unsigned long *fpregs = current_thread_info()->fpregs;
-       unsigned long fprs;
-       int err = 0;
-       
-       fprs = current_thread_info()->fpsaved[0];
-       if (fprs & FPRS_DL)
-               err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
-                                   (sizeof(unsigned int) * 32));
-       if (fprs & FPRS_DU)
-               err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
-                                   (sizeof(unsigned int) * 32));
-       err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
-       err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr);
-       err |= __put_user(fprs, &fpu->si_fprs);
-
-       return err;
-}
-
 static inline void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, unsigned long framesize)
 {
        unsigned long sp = regs->u_regs[UREG_FP] + STACK_BIAS;
@@ -414,34 +379,48 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
               int signo, sigset_t *oldset, siginfo_t *info)
 {
        struct rt_signal_frame __user *sf;
-       int sigframe_size, err;
+       int wsaved, err, sf_size;
+       void __user *tail;
 
        /* 1. Make sure everything is clean */
        synchronize_user_stack();
        save_and_clear_fpu();
        
-       sigframe_size = sizeof(struct rt_signal_frame);
-       if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
-               sigframe_size -= sizeof(__siginfo_fpu_t);
+       wsaved = get_thread_wsaved();
 
+       sf_size = sizeof(struct rt_signal_frame);
+       if (current_thread_info()->fpsaved[0] & FPRS_FEF)
+               sf_size += sizeof(__siginfo_fpu_t);
+       if (wsaved)
+               sf_size += sizeof(__siginfo_rwin_t);
        sf = (struct rt_signal_frame __user *)
-               get_sigframe(ka, regs, sigframe_size);
-       
-       if (invalid_frame_pointer (sf, sigframe_size))
-               goto sigill;
+               get_sigframe(ka, regs, sf_size);
 
-       if (get_thread_wsaved() != 0)
+       if (invalid_frame_pointer (sf))
                goto sigill;
 
+       tail = (sf + 1);
+
        /* 2. Save the current process state */
        err = copy_to_user(&sf->regs, regs, sizeof (*regs));
 
        if (current_thread_info()->fpsaved[0] & FPRS_FEF) {
-               err |= save_fpu_state(regs, &sf->fpu_state);
-               err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
+               __siginfo_fpu_t __user *fpu_save = tail;
+               tail += sizeof(__siginfo_fpu_t);
+               err |= save_fpu_state(regs, fpu_save);
+               err |= __put_user((u64)fpu_save, &sf->fpu_save);
        } else {
                err |= __put_user(0, &sf->fpu_save);
        }
+       if (wsaved) {
+               __siginfo_rwin_t __user *rwin_save = tail;
+               tail += sizeof(__siginfo_rwin_t);
+               err |= save_rwin_state(wsaved, rwin_save);
+               err |= __put_user((u64)rwin_save, &sf->rwin_save);
+               set_thread_wsaved(0);
+       } else {
+               err |= __put_user(0, &sf->rwin_save);
+       }
        
        /* Setup sigaltstack */
        err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
@@ -450,10 +429,17 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
 
        err |= copy_to_user(&sf->mask, oldset, sizeof(sigset_t));
 
-       err |= copy_in_user((u64 __user *)sf,
-                           (u64 __user *)(regs->u_regs[UREG_FP]+STACK_BIAS),
-                           sizeof(struct reg_window));
+       if (!wsaved) {
+               err |= copy_in_user((u64 __user *)sf,
+                                   (u64 __user *)(regs->u_regs[UREG_FP] +
+                                                  STACK_BIAS),
+                                   sizeof(struct reg_window));
+       } else {
+               struct reg_window *rp;
 
+               rp = &current_thread_info()->reg_window[wsaved - 1];
+               err |= copy_to_user(sf, rp, sizeof(struct reg_window));
+       }
        if (info)
                err |= copy_siginfo_to_user(&sf->info, info);
        else {
diff --git a/arch/sparc/kernel/sigutil.h b/arch/sparc/kernel/sigutil.h
new file mode 100644 (file)
index 0000000..d223aa4
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _SIGUTIL_H
+#define _SIGUTIL_H
+
+int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu);
+int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu);
+int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin);
+int restore_rwin_state(__siginfo_rwin_t __user *rp);
+
+#endif /* _SIGUTIL_H */
diff --git a/arch/sparc/kernel/sigutil_32.c b/arch/sparc/kernel/sigutil_32.c
new file mode 100644 (file)
index 0000000..35c7897
--- /dev/null
@@ -0,0 +1,120 @@
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/thread_info.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+
+#include <asm/sigcontext.h>
+#include <asm/fpumacro.h>
+#include <asm/ptrace.h>
+
+#include "sigutil.h"
+
+int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
+{
+       int err = 0;
+#ifdef CONFIG_SMP
+       if (test_tsk_thread_flag(current, TIF_USEDFPU)) {
+               put_psr(get_psr() | PSR_EF);
+               fpsave(&current->thread.float_regs[0], &current->thread.fsr,
+                      &current->thread.fpqueue[0], &current->thread.fpqdepth);
+               regs->psr &= ~(PSR_EF);
+               clear_tsk_thread_flag(current, TIF_USEDFPU);
+       }
+#else
+       if (current == last_task_used_math) {
+               put_psr(get_psr() | PSR_EF);
+               fpsave(&current->thread.float_regs[0], &current->thread.fsr,
+                      &current->thread.fpqueue[0], &current->thread.fpqdepth);
+               last_task_used_math = NULL;
+               regs->psr &= ~(PSR_EF);
+       }
+#endif
+       err |= __copy_to_user(&fpu->si_float_regs[0],
+                             &current->thread.float_regs[0],
+                             (sizeof(unsigned long) * 32));
+       err |= __put_user(current->thread.fsr, &fpu->si_fsr);
+       err |= __put_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
+       if (current->thread.fpqdepth != 0)
+               err |= __copy_to_user(&fpu->si_fpqueue[0],
+                                     &current->thread.fpqueue[0],
+                                     ((sizeof(unsigned long) +
+                                     (sizeof(unsigned long *)))*16));
+       clear_used_math();
+       return err;
+}
+
+int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
+{
+       int err;
+#ifdef CONFIG_SMP
+       if (test_tsk_thread_flag(current, TIF_USEDFPU))
+               regs->psr &= ~PSR_EF;
+#else
+       if (current == last_task_used_math) {
+               last_task_used_math = NULL;
+               regs->psr &= ~PSR_EF;
+       }
+#endif
+       set_used_math();
+       clear_tsk_thread_flag(current, TIF_USEDFPU);
+
+       if (!access_ok(VERIFY_READ, fpu, sizeof(*fpu)))
+               return -EFAULT;
+
+       err = __copy_from_user(&current->thread.float_regs[0], &fpu->si_float_regs[0],
+                              (sizeof(unsigned long) * 32));
+       err |= __get_user(current->thread.fsr, &fpu->si_fsr);
+       err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
+       if (current->thread.fpqdepth != 0)
+               err |= __copy_from_user(&current->thread.fpqueue[0],
+                                       &fpu->si_fpqueue[0],
+                                       ((sizeof(unsigned long) +
+                                       (sizeof(unsigned long *)))*16));
+       return err;
+}
+
+int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin)
+{
+       int i, err = __put_user(wsaved, &rwin->wsaved);
+
+       for (i = 0; i < wsaved; i++) {
+               struct reg_window32 *rp;
+               unsigned long fp;
+
+               rp = &current_thread_info()->reg_window[i];
+               fp = current_thread_info()->rwbuf_stkptrs[i];
+               err |= copy_to_user(&rwin->reg_window[i], rp,
+                                   sizeof(struct reg_window32));
+               err |= __put_user(fp, &rwin->rwbuf_stkptrs[i]);
+       }
+       return err;
+}
+
+int restore_rwin_state(__siginfo_rwin_t __user *rp)
+{
+       struct thread_info *t = current_thread_info();
+       int i, wsaved, err;
+
+       __get_user(wsaved, &rp->wsaved);
+       if (wsaved > NSWINS)
+               return -EFAULT;
+
+       err = 0;
+       for (i = 0; i < wsaved; i++) {
+               err |= copy_from_user(&t->reg_window[i],
+                                     &rp->reg_window[i],
+                                     sizeof(struct reg_window32));
+               err |= __get_user(t->rwbuf_stkptrs[i],
+                                 &rp->rwbuf_stkptrs[i]);
+       }
+       if (err)
+               return err;
+
+       t->w_saved = wsaved;
+       synchronize_user_stack();
+       if (t->w_saved)
+               return -EFAULT;
+       return 0;
+
+}
diff --git a/arch/sparc/kernel/sigutil_64.c b/arch/sparc/kernel/sigutil_64.c
new file mode 100644 (file)
index 0000000..e7dc508
--- /dev/null
@@ -0,0 +1,93 @@
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/thread_info.h>
+#include <linux/uaccess.h>
+
+#include <asm/sigcontext.h>
+#include <asm/fpumacro.h>
+#include <asm/ptrace.h>
+
+#include "sigutil.h"
+
+int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
+{
+       unsigned long *fpregs = current_thread_info()->fpregs;
+       unsigned long fprs;
+       int err = 0;
+       
+       fprs = current_thread_info()->fpsaved[0];
+       if (fprs & FPRS_DL)
+               err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
+                                   (sizeof(unsigned int) * 32));
+       if (fprs & FPRS_DU)
+               err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
+                                   (sizeof(unsigned int) * 32));
+       err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
+       err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr);
+       err |= __put_user(fprs, &fpu->si_fprs);
+
+       return err;
+}
+
+int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
+{
+       unsigned long *fpregs = current_thread_info()->fpregs;
+       unsigned long fprs;
+       int err;
+
+       err = __get_user(fprs, &fpu->si_fprs);
+       fprs_write(0);
+       regs->tstate &= ~TSTATE_PEF;
+       if (fprs & FPRS_DL)
+               err |= copy_from_user(fpregs, &fpu->si_float_regs[0],
+                              (sizeof(unsigned int) * 32));
+       if (fprs & FPRS_DU)
+               err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32],
+                              (sizeof(unsigned int) * 32));
+       err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
+       err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr);
+       current_thread_info()->fpsaved[0] |= fprs;
+       return err;
+}
+
+int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin)
+{
+       int i, err = __put_user(wsaved, &rwin->wsaved);
+
+       for (i = 0; i < wsaved; i++) {
+               struct reg_window *rp = &current_thread_info()->reg_window[i];
+               unsigned long fp = current_thread_info()->rwbuf_stkptrs[i];
+
+               err |= copy_to_user(&rwin->reg_window[i], rp,
+                                   sizeof(struct reg_window));
+               err |= __put_user(fp, &rwin->rwbuf_stkptrs[i]);
+       }
+       return err;
+}
+
+int restore_rwin_state(__siginfo_rwin_t __user *rp)
+{
+       struct thread_info *t = current_thread_info();
+       int i, wsaved, err;
+
+       __get_user(wsaved, &rp->wsaved);
+       if (wsaved > NSWINS)
+               return -EFAULT;
+
+       err = 0;
+       for (i = 0; i < wsaved; i++) {
+               err |= copy_from_user(&t->reg_window[i],
+                                     &rp->reg_window[i],
+                                     sizeof(struct reg_window));
+               err |= __get_user(t->rwbuf_stkptrs[i],
+                                 &rp->rwbuf_stkptrs[i]);
+       }
+       if (err)
+               return err;
+
+       set_thread_wsaved(wsaved);
+       synchronize_user_stack();
+       if (get_thread_wsaved())
+               return -EFAULT;
+       return 0;
+}
index 372ad59..83b47ab 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/bitops.h>
 
 #include <asm/system.h>
 #include <asm/cpudata.h>
@@ -38,5 +39,15 @@ EXPORT_SYMBOL(sun4v_niagara_setperf);
 EXPORT_SYMBOL(sun4v_niagara2_getperf);
 EXPORT_SYMBOL(sun4v_niagara2_setperf);
 
+/* from hweight.S */
+EXPORT_SYMBOL(__arch_hweight8);
+EXPORT_SYMBOL(__arch_hweight16);
+EXPORT_SYMBOL(__arch_hweight32);
+EXPORT_SYMBOL(__arch_hweight64);
+
+/* from ffs_ffz.S */
+EXPORT_SYMBOL(ffs);
+EXPORT_SYMBOL(__ffs);
+
 /* Exporting a symbol from /init/main.c */
 EXPORT_SYMBOL(saved_command_line);
index 8cdbe59..c59af54 100644 (file)
 #include <asm/head.h>
 #include <asm/io.h>
 
-static int hv_supports_soft_state;
-
-static unsigned long kimage_addr_to_ra(const char *p)
-{
-       unsigned long val = (unsigned long) p;
+#include "kernel.h"
 
-       return kern_base + (val - KERNBASE);
-}
+static int hv_supports_soft_state;
 
 static void do_set_sstate(unsigned long state, const char *msg)
 {
index 35cff16..76e4ac1 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/bitops.h>
 #include <linux/perf_event.h>
 #include <linux/ratelimit.h>
+#include <linux/bitops.h>
 #include <asm/fpumacro.h>
 
 enum direction {
@@ -373,16 +374,11 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
        }
 }
 
-static char popc_helper[] = {
-0, 1, 1, 2, 1, 2, 2, 3,
-1, 2, 2, 3, 2, 3, 3, 4, 
-};
-
 int handle_popc(u32 insn, struct pt_regs *regs)
 {
-       u64 value;
-       int ret, i, rd = ((insn >> 25) & 0x1f);
        int from_kernel = (regs->tstate & TSTATE_PRIV) != 0;
+       int ret, rd = ((insn >> 25) & 0x1f);
+       u64 value;
                                
        perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0);
        if (insn & 0x2000) {
@@ -392,10 +388,7 @@ int handle_popc(u32 insn, struct pt_regs *regs)
                maybe_flush_windows(0, insn & 0x1f, rd, from_kernel);
                value = fetch_reg(insn & 0x1f, regs);
        }
-       for (ret = 0, i = 0; i < 16; i++) {
-               ret += popc_helper[value & 0xf];
-               value >>= 4;
-       }
+       ret = hweight64(value);
        if (rd < 16) {
                if (rd)
                        regs->u_regs[rd] = ret;
index c022075..0e16056 100644 (file)
@@ -107,7 +107,26 @@ SECTIONS
                *(.sun4v_2insn_patch)
                __sun4v_2insn_patch_end = .;
        }
-
+       .swapper_tsb_phys_patch : {
+               __swapper_tsb_phys_patch = .;
+               *(.swapper_tsb_phys_patch)
+               __swapper_tsb_phys_patch_end = .;
+       }
+       .swapper_4m_tsb_phys_patch : {
+               __swapper_4m_tsb_phys_patch = .;
+               *(.swapper_4m_tsb_phys_patch)
+               __swapper_4m_tsb_phys_patch_end = .;
+       }
+       .popc_3insn_patch : {
+               __popc_3insn_patch = .;
+               *(.popc_3insn_patch)
+               __popc_3insn_patch_end = .;
+       }
+       .popc_6insn_patch : {
+               __popc_6insn_patch = .;
+               *(.popc_6insn_patch)
+               __popc_6insn_patch_end = .;
+       }
        PERCPU_SECTION(SMP_CACHE_BYTES)
 
        . = ALIGN(PAGE_SIZE);
index 7f01b8f..a3fc437 100644 (file)
@@ -31,13 +31,13 @@ lib-$(CONFIG_SPARC64) += NGmemcpy.o NGcopy_from_user.o NGcopy_to_user.o
 lib-$(CONFIG_SPARC64) += NGpatch.o NGpage.o NGbzero.o
 
 lib-$(CONFIG_SPARC64) += NG2memcpy.o NG2copy_from_user.o NG2copy_to_user.o
-lib-$(CONFIG_SPARC64) +=  NG2patch.o NG2page.o
+lib-$(CONFIG_SPARC64) +=  NG2patch.o
 
 lib-$(CONFIG_SPARC64) += GENmemcpy.o GENcopy_from_user.o GENcopy_to_user.o
 lib-$(CONFIG_SPARC64) += GENpatch.o GENpage.o GENbzero.o
 
 lib-$(CONFIG_SPARC64) += copy_in_user.o user_fixup.o memmove.o
-lib-$(CONFIG_SPARC64) += mcount.o ipcsum.o xor.o
+lib-$(CONFIG_SPARC64) += mcount.o ipcsum.o xor.o hweight.o ffs.o
 
 obj-y                 += iomap.o
 obj-$(CONFIG_SPARC32) += atomic32.o
diff --git a/arch/sparc/lib/NG2page.S b/arch/sparc/lib/NG2page.S
deleted file mode 100644 (file)
index 73b6b7c..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/* NG2page.S: Niagara-2 optimized clear and copy page.
- *
- * Copyright (C) 2007 (davem@davemloft.net)
- */
-
-#include <asm/asi.h>
-#include <asm/page.h>
-#include <asm/visasm.h>
-
-       .text
-       .align  32
-
-       /* This is heavily simplified from the sun4u variants
-        * because Niagara-2 does not have any D-cache aliasing issues.
-        */
-NG2copy_user_page:     /* %o0=dest, %o1=src, %o2=vaddr */
-       prefetch        [%o1 + 0x00], #one_read
-       prefetch        [%o1 + 0x40], #one_read
-       VISEntryHalf
-       set             PAGE_SIZE, %g7
-       sub             %o0, %o1, %g3
-1:     stxa            %g0, [%o1 + %g3] ASI_BLK_INIT_QUAD_LDD_P
-       subcc           %g7, 64, %g7
-       ldda            [%o1] ASI_BLK_P, %f0
-       stda            %f0, [%o1 + %g3] ASI_BLK_P
-       add             %o1, 64, %o1
-       bne,pt          %xcc, 1b
-        prefetch       [%o1 + 0x40], #one_read
-       membar          #Sync
-       VISExitHalf
-       retl
-        nop
-
-#define BRANCH_ALWAYS  0x10680000
-#define NOP            0x01000000
-#define NG_DO_PATCH(OLD, NEW)  \
-       sethi   %hi(NEW), %g1; \
-       or      %g1, %lo(NEW), %g1; \
-       sethi   %hi(OLD), %g2; \
-       or      %g2, %lo(OLD), %g2; \
-       sub     %g1, %g2, %g1; \
-       sethi   %hi(BRANCH_ALWAYS), %g3; \
-       sll     %g1, 11, %g1; \
-       srl     %g1, 11 + 2, %g1; \
-       or      %g3, %lo(BRANCH_ALWAYS), %g3; \
-       or      %g3, %g1, %g3; \
-       stw     %g3, [%g2]; \
-       sethi   %hi(NOP), %g3; \
-       or      %g3, %lo(NOP), %g3; \
-       stw     %g3, [%g2 + 0x4]; \
-       flush   %g2;
-
-       .globl  niagara2_patch_pageops
-       .type   niagara2_patch_pageops,#function
-niagara2_patch_pageops:
-       NG_DO_PATCH(copy_user_page, NG2copy_user_page)
-       NG_DO_PATCH(_clear_page, NGclear_page)
-       NG_DO_PATCH(clear_user_page, NGclear_user_page)
-       retl
-        nop
-       .size   niagara2_patch_pageops,.-niagara2_patch_pageops
index 428920d..b9e790b 100644 (file)
         */
 
 NGcopy_user_page:      /* %o0=dest, %o1=src, %o2=vaddr */
-       prefetch        [%o1 + 0x00], #one_read
-       mov             8, %g1
-       mov             16, %g2
-       mov             24, %g3
+       save            %sp, -192, %sp
+       rd              %asi, %g3
+       wr              %g0, ASI_BLK_INIT_QUAD_LDD_P, %asi
        set             PAGE_SIZE, %g7
+       prefetch        [%i1 + 0x00], #one_read
+       prefetch        [%i1 + 0x40], #one_read
 
-1:     ldda            [%o1 + %g0] ASI_BLK_INIT_QUAD_LDD_P, %o2
-       ldda            [%o1 + %g2] ASI_BLK_INIT_QUAD_LDD_P, %o4
-       prefetch        [%o1 + 0x40], #one_read
-       add             %o1, 32, %o1
-       stxa            %o2, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P
-       stxa            %o3, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P
-       ldda            [%o1 + %g0] ASI_BLK_INIT_QUAD_LDD_P, %o2
-       stxa            %o4, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P
-       stxa            %o5, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P
-       ldda            [%o1 + %g2] ASI_BLK_INIT_QUAD_LDD_P, %o4
-       add             %o1, 32, %o1
-       add             %o0, 32, %o0
-       stxa            %o2, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P
-       stxa            %o3, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P
-       stxa            %o4, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P
-       stxa            %o5, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P
-       subcc           %g7, 64, %g7
+1:     prefetch        [%i1 + 0x80], #one_read
+       prefetch        [%i1 + 0xc0], #one_read
+       ldda            [%i1 + 0x00] %asi, %o2
+       ldda            [%i1 + 0x10] %asi, %o4
+       ldda            [%i1 + 0x20] %asi, %l2
+       ldda            [%i1 + 0x30] %asi, %l4
+       stxa            %o2, [%i0 + 0x00] %asi
+       stxa            %o3, [%i0 + 0x08] %asi
+       stxa            %o4, [%i0 + 0x10] %asi
+       stxa            %o5, [%i0 + 0x18] %asi
+       stxa            %l2, [%i0 + 0x20] %asi
+       stxa            %l3, [%i0 + 0x28] %asi
+       stxa            %l4, [%i0 + 0x30] %asi
+       stxa            %l5, [%i0 + 0x38] %asi
+       ldda            [%i1 + 0x40] %asi, %o2
+       ldda            [%i1 + 0x50] %asi, %o4
+       ldda            [%i1 + 0x60] %asi, %l2
+       ldda            [%i1 + 0x70] %asi, %l4
+       stxa            %o2, [%i0 + 0x40] %asi
+       stxa            %o3, [%i0 + 0x48] %asi
+       stxa            %o4, [%i0 + 0x50] %asi
+       stxa            %o5, [%i0 + 0x58] %asi
+       stxa            %l2, [%i0 + 0x60] %asi
+       stxa            %l3, [%i0 + 0x68] %asi
+       stxa            %l4, [%i0 + 0x70] %asi
+       stxa            %l5, [%i0 + 0x78] %asi
+       add             %i1, 128, %i1
+       subcc           %g7, 128, %g7
        bne,pt          %xcc, 1b
-        add            %o0, 32, %o0
+        add            %i0, 128, %i0
+       wr              %g3, 0x0, %asi
        membar          #Sync
-       retl
-        nop
+       ret
+        restore
 
-       .globl          NGclear_page, NGclear_user_page
+       .align          32
 NGclear_page:          /* %o0=dest */
 NGclear_user_page:     /* %o0=dest, %o1=vaddr */
-       mov             8, %g1
-       mov             16, %g2
-       mov             24, %g3
+       rd              %asi, %g3
+       wr              %g0, ASI_BLK_INIT_QUAD_LDD_P, %asi
        set             PAGE_SIZE, %g7
 
-1:     stxa            %g0, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P
-       stxa            %g0, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P
-       stxa            %g0, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P
-       stxa            %g0, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P
-       add             %o0, 32, %o0
-       stxa            %g0, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P
-       stxa            %g0, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P
-       stxa            %g0, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P
-       stxa            %g0, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P
-       subcc           %g7, 64, %g7
+1:     stxa            %g0, [%o0 + 0x00] %asi
+       stxa            %g0, [%o0 + 0x08] %asi
+       stxa            %g0, [%o0 + 0x10] %asi
+       stxa            %g0, [%o0 + 0x18] %asi
+       stxa            %g0, [%o0 + 0x20] %asi
+       stxa            %g0, [%o0 + 0x28] %asi
+       stxa            %g0, [%o0 + 0x30] %asi
+       stxa            %g0, [%o0 + 0x38] %asi
+       stxa            %g0, [%o0 + 0x40] %asi
+       stxa            %g0, [%o0 + 0x48] %asi
+       stxa            %g0, [%o0 + 0x50] %asi
+       stxa            %g0, [%o0 + 0x58] %asi
+       stxa            %g0, [%o0 + 0x60] %asi
+       stxa            %g0, [%o0 + 0x68] %asi
+       stxa            %g0, [%o0 + 0x70] %asi
+       stxa            %g0, [%o0 + 0x78] %asi
+       stxa            %g0, [%o0 + 0x80] %asi
+       stxa            %g0, [%o0 + 0x88] %asi
+       stxa            %g0, [%o0 + 0x90] %asi
+       stxa            %g0, [%o0 + 0x98] %asi
+       stxa            %g0, [%o0 + 0xa0] %asi
+       stxa            %g0, [%o0 + 0xa8] %asi
+       stxa            %g0, [%o0 + 0xb0] %asi
+       stxa            %g0, [%o0 + 0xb8] %asi
+       stxa            %g0, [%o0 + 0xc0] %asi
+       stxa            %g0, [%o0 + 0xc8] %asi
+       stxa            %g0, [%o0 + 0xd0] %asi
+       stxa            %g0, [%o0 + 0xd8] %asi
+       stxa            %g0, [%o0 + 0xe0] %asi
+       stxa            %g0, [%o0 + 0xe8] %asi
+       stxa            %g0, [%o0 + 0xf0] %asi
+       stxa            %g0, [%o0 + 0xf8] %asi
+       subcc           %g7, 256, %g7
        bne,pt          %xcc, 1b
-        add            %o0, 32, %o0
+        add            %o0, 256, %o0
+       wr              %g3, 0x0, %asi
        membar          #Sync
        retl
         nop
index 8600eb2..1d32b54 100644 (file)
@@ -65,7 +65,7 @@ int __atomic_add_unless(atomic_t *v, int a, int u)
        if (ret != u)
                v->counter += a;
        spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
-       return ret != u;
+       return ret;
 }
 EXPORT_SYMBOL(__atomic_add_unless);
 
diff --git a/arch/sparc/lib/ffs.S b/arch/sparc/lib/ffs.S
new file mode 100644 (file)
index 0000000..b39389f
--- /dev/null
@@ -0,0 +1,84 @@
+#include <linux/linkage.h>
+
+       .register       %g2,#scratch
+
+       .text
+       .align  32
+
+ENTRY(ffs)
+       brnz,pt %o0, 1f
+        mov    1, %o1
+       retl
+        clr    %o0
+       nop
+       nop
+ENTRY(__ffs)
+       sllx    %o0, 32, %g1            /* 1  */
+       srlx    %o0, 32, %g2
+
+       clr     %o1                     /* 2  */
+       movrz   %g1, %g2, %o0
+
+       movrz   %g1, 32, %o1            /* 3  */
+1:     clr     %o2
+
+       sllx    %o0, (64 - 16), %g1     /* 4  */
+       srlx    %o0, 16, %g2
+
+       movrz   %g1, %g2, %o0           /* 5  */
+       clr     %o3
+
+       movrz   %g1, 16, %o2            /* 6  */
+       clr     %o4
+
+       and     %o0, 0xff, %g1          /* 7  */
+       srlx    %o0, 8, %g2
+
+       movrz   %g1, %g2, %o0           /* 8  */
+       clr     %o5
+
+       movrz   %g1, 8, %o3             /* 9  */
+       add     %o2, %o1, %o2
+
+       and     %o0, 0xf, %g1           /* 10 */
+       srlx    %o0, 4, %g2
+
+       movrz   %g1, %g2, %o0           /* 11 */
+       add     %o2, %o3, %o2
+
+       movrz   %g1, 4, %o4             /* 12 */
+
+       and     %o0, 0x3, %g1           /* 13 */
+       srlx    %o0, 2, %g2
+
+       movrz   %g1, %g2, %o0           /* 14 */
+       add     %o2, %o4, %o2
+
+       movrz   %g1, 2, %o5             /* 15 */
+
+       and     %o0, 0x1, %g1           /* 16 */
+
+       add     %o2, %o5, %o2           /* 17 */
+       xor     %g1, 0x1, %g1
+
+       retl                            /* 18 */
+        add    %o2, %g1, %o0
+ENDPROC(ffs)
+ENDPROC(__ffs)
+
+       .section        .popc_6insn_patch, "ax"
+       .word           ffs
+       brz,pn  %o0, 98f
+        neg    %o0, %g1
+       xnor    %o0, %g1, %o1
+       popc    %o1, %o0
+98:    retl
+        nop
+       .word           __ffs
+       neg     %o0, %g1
+       xnor    %o0, %g1, %o1
+       popc    %o1, %o0
+       retl
+        sub    %o0, 1, %o0
+       nop
+       .previous
diff --git a/arch/sparc/lib/hweight.S b/arch/sparc/lib/hweight.S
new file mode 100644 (file)
index 0000000..95414e0
--- /dev/null
@@ -0,0 +1,51 @@
+#include <linux/linkage.h>
+
+       .text
+       .align  32
+ENTRY(__arch_hweight8)
+       ba,pt   %xcc, __sw_hweight8
+        nop
+       nop
+ENDPROC(__arch_hweight8)
+       .section        .popc_3insn_patch, "ax"
+       .word           __arch_hweight8
+       sllx            %o0, 64-8, %g1
+       retl
+        popc           %g1, %o0
+       .previous
+
+ENTRY(__arch_hweight16)
+       ba,pt   %xcc, __sw_hweight16
+        nop
+       nop
+ENDPROC(__arch_hweight16)
+       .section        .popc_3insn_patch, "ax"
+       .word           __arch_hweight16
+       sllx            %o0, 64-16, %g1
+       retl
+        popc           %g1, %o0
+       .previous
+
+ENTRY(__arch_hweight32)
+       ba,pt   %xcc, __sw_hweight32
+        nop
+       nop
+ENDPROC(__arch_hweight32)
+       .section        .popc_3insn_patch, "ax"
+       .word           __arch_hweight32
+       sllx            %o0, 64-32, %g1
+       retl
+        popc           %g1, %o0
+       .previous
+
+ENTRY(__arch_hweight64)
+       ba,pt   %xcc, __sw_hweight64
+        nop
+       nop
+ENDPROC(__arch_hweight64)
+       .section        .popc_3insn_patch, "ax"
+       .word           __arch_hweight64
+       retl
+        popc           %o0, %o0
+       nop
+       .previous
index 3fd8e18..581531d 100644 (file)
@@ -1597,6 +1597,44 @@ static void __init tsb_phys_patch(void)
 static struct hv_tsb_descr ktsb_descr[NUM_KTSB_DESCR];
 extern struct tsb swapper_tsb[KERNEL_TSB_NENTRIES];
 
+static void patch_one_ktsb_phys(unsigned int *start, unsigned int *end, unsigned long pa)
+{
+       pa >>= KTSB_PHYS_SHIFT;
+
+       while (start < end) {
+               unsigned int *ia = (unsigned int *)(unsigned long)*start;
+
+               ia[0] = (ia[0] & ~0x3fffff) | (pa >> 10);
+               __asm__ __volatile__("flush     %0" : : "r" (ia));
+
+               ia[1] = (ia[1] & ~0x3ff) | (pa & 0x3ff);
+               __asm__ __volatile__("flush     %0" : : "r" (ia + 1));
+
+               start++;
+       }
+}
+
+static void ktsb_phys_patch(void)
+{
+       extern unsigned int __swapper_tsb_phys_patch;
+       extern unsigned int __swapper_tsb_phys_patch_end;
+       unsigned long ktsb_pa;
+
+       ktsb_pa = kern_base + ((unsigned long)&swapper_tsb[0] - KERNBASE);
+       patch_one_ktsb_phys(&__swapper_tsb_phys_patch,
+                           &__swapper_tsb_phys_patch_end, ktsb_pa);
+#ifndef CONFIG_DEBUG_PAGEALLOC
+       {
+       extern unsigned int __swapper_4m_tsb_phys_patch;
+       extern unsigned int __swapper_4m_tsb_phys_patch_end;
+       ktsb_pa = (kern_base +
+                  ((unsigned long)&swapper_4m_tsb[0] - KERNBASE));
+       patch_one_ktsb_phys(&__swapper_4m_tsb_phys_patch,
+                           &__swapper_4m_tsb_phys_patch_end, ktsb_pa);
+       }
+#endif
+}
+
 static void __init sun4v_ktsb_init(void)
 {
        unsigned long ktsb_pa;
@@ -1716,8 +1754,10 @@ void __init paging_init(void)
                sun4u_pgprot_init();
 
        if (tlb_type == cheetah_plus ||
-           tlb_type == hypervisor)
+           tlb_type == hypervisor) {
                tsb_phys_patch();
+               ktsb_phys_patch();
+       }
 
        if (tlb_type == hypervisor) {
                sun4v_patch_tlb_handlers();
index 0249b8b..b30f71a 100644 (file)
@@ -12,6 +12,7 @@ config TILE
        select GENERIC_PENDING_IRQ if SMP
        select GENERIC_IRQ_SHOW
        select SYS_HYPERVISOR
+       select ARCH_HAVE_NMI_SAFE_CMPXCHG if !M386
 
 # FIXME: investigate whether we need/want these options.
 #      select HAVE_IOREMAP_PROT
index 849ab2f..aec60dc 100644 (file)
@@ -2,3 +2,41 @@ include include/asm-generic/Kbuild.asm
 
 header-y += ucontext.h
 header-y += hardwall.h
+
+generic-y += bug.h
+generic-y += bugs.h
+generic-y += cputime.h
+generic-y += device.h
+generic-y += div64.h
+generic-y += emergency-restart.h
+generic-y += errno.h
+generic-y += fb.h
+generic-y += fcntl.h
+generic-y += ioctl.h
+generic-y += ioctls.h
+generic-y += ipc.h
+generic-y += ipcbuf.h
+generic-y += irq_regs.h
+generic-y += kdebug.h
+generic-y += local.h
+generic-y += module.h
+generic-y += msgbuf.h
+generic-y += mutex.h
+generic-y += param.h
+generic-y += parport.h
+generic-y += poll.h
+generic-y += posix_types.h
+generic-y += resource.h
+generic-y += scatterlist.h
+generic-y += sembuf.h
+generic-y += serial.h
+generic-y += shmbuf.h
+generic-y += shmparam.h
+generic-y += socket.h
+generic-y += sockios.h
+generic-y += statfs.h
+generic-y += termbits.h
+generic-y += termios.h
+generic-y += types.h
+generic-y += ucontext.h
+generic-y += xor.h
diff --git a/arch/tile/include/asm/bug.h b/arch/tile/include/asm/bug.h
deleted file mode 100644 (file)
index b12fd89..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/bug.h>
diff --git a/arch/tile/include/asm/bugs.h b/arch/tile/include/asm/bugs.h
deleted file mode 100644 (file)
index 61791e1..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/bugs.h>
diff --git a/arch/tile/include/asm/cputime.h b/arch/tile/include/asm/cputime.h
deleted file mode 100644 (file)
index 6d68ad7..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/cputime.h>
diff --git a/arch/tile/include/asm/device.h b/arch/tile/include/asm/device.h
deleted file mode 100644 (file)
index f0a4c25..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/device.h>
diff --git a/arch/tile/include/asm/div64.h b/arch/tile/include/asm/div64.h
deleted file mode 100644 (file)
index 6cd978c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/div64.h>
diff --git a/arch/tile/include/asm/emergency-restart.h b/arch/tile/include/asm/emergency-restart.h
deleted file mode 100644 (file)
index 3711bd9..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/emergency-restart.h>
diff --git a/arch/tile/include/asm/errno.h b/arch/tile/include/asm/errno.h
deleted file mode 100644 (file)
index 4c82b50..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/errno.h>
diff --git a/arch/tile/include/asm/fb.h b/arch/tile/include/asm/fb.h
deleted file mode 100644 (file)
index 3a4988e..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/fb.h>
diff --git a/arch/tile/include/asm/fcntl.h b/arch/tile/include/asm/fcntl.h
deleted file mode 100644 (file)
index 46ab12d..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/fcntl.h>
index 51537ff..c66f793 100644 (file)
@@ -75,12 +75,6 @@ extern void __set_fixmap(enum fixed_addresses idx,
 
 #define set_fixmap(idx, phys) \
                __set_fixmap(idx, phys, PAGE_KERNEL)
-/*
- * Some hardware wants to get fixmapped without caching.
- */
-#define set_fixmap_nocache(idx, phys) \
-               __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE)
-
 #define clear_fixmap(idx) \
                __set_fixmap(idx, 0, __pgprot(0))
 
diff --git a/arch/tile/include/asm/ioctl.h b/arch/tile/include/asm/ioctl.h
deleted file mode 100644 (file)
index b279fe0..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/ioctl.h>
diff --git a/arch/tile/include/asm/ioctls.h b/arch/tile/include/asm/ioctls.h
deleted file mode 100644 (file)
index ec34c76..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/ioctls.h>
diff --git a/arch/tile/include/asm/ipc.h b/arch/tile/include/asm/ipc.h
deleted file mode 100644 (file)
index a46e3d9..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/ipc.h>
diff --git a/arch/tile/include/asm/ipcbuf.h b/arch/tile/include/asm/ipcbuf.h
deleted file mode 100644 (file)
index 84c7e51..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/ipcbuf.h>
diff --git a/arch/tile/include/asm/irq_regs.h b/arch/tile/include/asm/irq_regs.h
deleted file mode 100644 (file)
index 3dd9c0b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/irq_regs.h>
diff --git a/arch/tile/include/asm/kdebug.h b/arch/tile/include/asm/kdebug.h
deleted file mode 100644 (file)
index 6ece1b0..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/kdebug.h>
diff --git a/arch/tile/include/asm/local.h b/arch/tile/include/asm/local.h
deleted file mode 100644 (file)
index c11c530..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/local.h>
diff --git a/arch/tile/include/asm/module.h b/arch/tile/include/asm/module.h
deleted file mode 100644 (file)
index 1e4b79f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/module.h>
diff --git a/arch/tile/include/asm/msgbuf.h b/arch/tile/include/asm/msgbuf.h
deleted file mode 100644 (file)
index 809134c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/msgbuf.h>
diff --git a/arch/tile/include/asm/mutex.h b/arch/tile/include/asm/mutex.h
deleted file mode 100644 (file)
index ff6101a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/mutex-dec.h>
diff --git a/arch/tile/include/asm/param.h b/arch/tile/include/asm/param.h
deleted file mode 100644 (file)
index 965d454..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/param.h>
diff --git a/arch/tile/include/asm/parport.h b/arch/tile/include/asm/parport.h
deleted file mode 100644 (file)
index cf252af..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/parport.h>
diff --git a/arch/tile/include/asm/poll.h b/arch/tile/include/asm/poll.h
deleted file mode 100644 (file)
index c98509d..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/poll.h>
diff --git a/arch/tile/include/asm/posix_types.h b/arch/tile/include/asm/posix_types.h
deleted file mode 100644 (file)
index 22cae62..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/posix_types.h>
diff --git a/arch/tile/include/asm/resource.h b/arch/tile/include/asm/resource.h
deleted file mode 100644 (file)
index 04bc4db..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/resource.h>
diff --git a/arch/tile/include/asm/scatterlist.h b/arch/tile/include/asm/scatterlist.h
deleted file mode 100644 (file)
index 35d786f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/scatterlist.h>
diff --git a/arch/tile/include/asm/sembuf.h b/arch/tile/include/asm/sembuf.h
deleted file mode 100644 (file)
index 7673b83..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/sembuf.h>
diff --git a/arch/tile/include/asm/serial.h b/arch/tile/include/asm/serial.h
deleted file mode 100644 (file)
index a0cb0ca..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/serial.h>
diff --git a/arch/tile/include/asm/shmbuf.h b/arch/tile/include/asm/shmbuf.h
deleted file mode 100644 (file)
index 83c05fc..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/shmbuf.h>
diff --git a/arch/tile/include/asm/shmparam.h b/arch/tile/include/asm/shmparam.h
deleted file mode 100644 (file)
index 93f30de..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/shmparam.h>
diff --git a/arch/tile/include/asm/socket.h b/arch/tile/include/asm/socket.h
deleted file mode 100644 (file)
index 6b71384..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/socket.h>
diff --git a/arch/tile/include/asm/sockios.h b/arch/tile/include/asm/sockios.h
deleted file mode 100644 (file)
index def6d47..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/sockios.h>
diff --git a/arch/tile/include/asm/statfs.h b/arch/tile/include/asm/statfs.h
deleted file mode 100644 (file)
index 0b91fe1..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/statfs.h>
diff --git a/arch/tile/include/asm/termbits.h b/arch/tile/include/asm/termbits.h
deleted file mode 100644 (file)
index 3935b10..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/termbits.h>
diff --git a/arch/tile/include/asm/termios.h b/arch/tile/include/asm/termios.h
deleted file mode 100644 (file)
index 280d78a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/termios.h>
diff --git a/arch/tile/include/asm/types.h b/arch/tile/include/asm/types.h
deleted file mode 100644 (file)
index b9e79bc..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/types.h>
diff --git a/arch/tile/include/asm/ucontext.h b/arch/tile/include/asm/ucontext.h
deleted file mode 100644 (file)
index 9bc07b9..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/ucontext.h>
diff --git a/arch/tile/include/asm/xor.h b/arch/tile/include/asm/xor.h
deleted file mode 100644 (file)
index c82eb12..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/xor.h>
diff --git a/arch/tile/include/hv/drv_srom_intf.h b/arch/tile/include/hv/drv_srom_intf.h
new file mode 100644 (file)
index 0000000..6395faa
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2011 Tilera Corporation. 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, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/**
+ * @file drv_srom_intf.h
+ * Interface definitions for the SPI Flash ROM driver.
+ */
+
+#ifndef _SYS_HV_INCLUDE_DRV_SROM_INTF_H
+#define _SYS_HV_INCLUDE_DRV_SROM_INTF_H
+
+/** Read this offset to get the total device size. */
+#define SROM_TOTAL_SIZE_OFF   0xF0000000
+
+/** Read this offset to get the device sector size. */
+#define SROM_SECTOR_SIZE_OFF  0xF0000004
+
+/** Read this offset to get the device page size. */
+#define SROM_PAGE_SIZE_OFF    0xF0000008
+
+/** Write this offset to flush any pending writes. */
+#define SROM_FLUSH_OFF        0xF1000000
+
+/** Write this offset, plus the byte offset of the start of a sector, to
+ *  erase a sector.  Any write data is ignored, but there must be at least
+ *  one byte of write data.  Only applies when the driver is in MTD mode.
+ */
+#define SROM_ERASE_OFF        0xF2000000
+
+#endif /* _SYS_HV_INCLUDE_DRV_SROM_INTF_H */
index 6d4cb5d..2a8014c 100644 (file)
@@ -228,7 +228,7 @@ err_cont:
  * (pin - 1) converts from the PCI standard's [1:4] convention to
  * a normal [0:3] range.
  */
-static int tile_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int tile_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        struct pci_controller *controller =
                (struct pci_controller *)dev->sysdata;
index c4be58c..f6f50f2 100644 (file)
@@ -78,7 +78,6 @@ static struct clocksource cycle_counter_cs = {
        .rating = 300,
        .read = clocksource_get_cycles,
        .mask = CLOCKSOURCE_MASK(64),
-       .shift = 22,   /* typical value, e.g. x86 tsc uses this */
        .flags = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
@@ -91,8 +90,6 @@ void __init setup_clock(void)
        cycles_per_sec = hv_sysconf(HV_SYSCONF_CPU_SPEED);
        sched_clock_mult =
                clocksource_hz2mult(cycles_per_sec, SCHED_CLOCK_SHIFT);
-       cycle_counter_cs.mult =
-               clocksource_hz2mult(cycles_per_sec, cycle_counter_cs.shift);
 }
 
 void __init calibrate_delay(void)
@@ -107,7 +104,7 @@ void __init calibrate_delay(void)
 void __init time_init(void)
 {
        /* Initialize and register the clock source. */
-       clocksource_register(&cycle_counter_cs);
+       clocksource_register_hz(&cycle_counter_cs, cycles_per_sec);
 
        /* Start up the tile-timer interrupt source on the boot cpu. */
        setup_tile_timer();
index 4e10c40..7309988 100644 (file)
@@ -836,8 +836,7 @@ void __init mem_init(void)
 #endif
 
 #ifdef CONFIG_FLATMEM
-       if (!mem_map)
-               BUG();
+       BUG_ON(!mem_map);
 #endif
 
 #ifdef CONFIG_HIGHMEM
index 100eab8..4892fbb 100644 (file)
@@ -102,7 +102,7 @@ void pci_puv3_preinit(void)
        writel(readl(PCIBRI_CMD) | PCIBRI_CMD_IO | PCIBRI_CMD_MEM, PCIBRI_CMD);
 }
 
-static int __init pci_puv3_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init pci_puv3_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        if (dev->bus->number == 0) {
 #ifdef CONFIG_ARCH_FPGA /* 4 pci slots */
index 153aa6f..6a47bb2 100644 (file)
@@ -72,6 +72,7 @@ config X86
        select USE_GENERIC_SMP_HELPERS if SMP
        select HAVE_BPF_JIT if (X86_64 && NET)
        select CLKEVT_I8253
+       select ARCH_HAVE_NMI_SAFE_CMPXCHG
 
 config INSTRUCTION_DECODER
        def_bool (KPROBES || PERF_EVENTS)
@@ -1905,7 +1906,7 @@ config PCI_BIOS
 # x86-64 doesn't support PCI BIOS access from long mode so always go direct.
 config PCI_DIRECT
        def_bool y
-       depends on PCI && (X86_64 || (PCI_GODIRECT || PCI_GOANY || PCI_GOOLPC))
+       depends on PCI && (X86_64 || (PCI_GODIRECT || PCI_GOANY || PCI_GOOLPC || PCI_GOMMCONFIG))
 
 config PCI_MMCONFIG
        def_bool y
index 7b439d9..41935fa 100644 (file)
@@ -27,8 +27,8 @@ static inline void fill_ldt(struct desc_struct *desc, const struct user_desc *in
 
        desc->base2             = (info->base_addr & 0xff000000) >> 24;
        /*
-        * Don't allow setting of the lm bit. It is useless anyway
-        * because 64bit system calls require __USER_CS:
+        * Don't allow setting of the lm bit. It would confuse
+        * user_64bit_mode and would get overridden by sysret anyway.
         */
        desc->l                 = 0;
 }
index d02804d..d8e8eef 100644 (file)
@@ -40,8 +40,6 @@
 #include <linux/compiler.h>
 #include <asm/page.h>
 
-#include <xen/xen.h>
-
 #define build_mmio_read(name, size, type, reg, barrier) \
 static inline type name(const volatile void __iomem *addr) \
 { type ret; asm volatile("mov" size " %1,%0":reg (ret) \
@@ -334,6 +332,7 @@ extern void fixup_early_ioremap(void);
 extern bool is_early_ioremap_ptep(pte_t *ptep);
 
 #ifdef CONFIG_XEN
+#include <xen/xen.h>
 struct bio_vec;
 
 extern bool xen_biovec_phys_mergeable(const struct bio_vec *vec1,
index f9a3209..7e50f06 100644 (file)
@@ -17,7 +17,6 @@
  *  Vectors   0 ...  31 : system traps and exceptions - hardcoded events
  *  Vectors  32 ... 127 : device interrupts
  *  Vector  128         : legacy int80 syscall interface
- *  Vector  204         : legacy x86_64 vsyscall emulation
  *  Vectors 129 ... INVALIDATE_TLB_VECTOR_START-1 except 204 : device interrupts
  *  Vectors INVALIDATE_TLB_VECTOR_START ... 255 : special interrupts
  *
@@ -51,9 +50,6 @@
 #ifdef CONFIG_X86_32
 # define SYSCALL_VECTOR                        0x80
 #endif
-#ifdef CONFIG_X86_64
-# define VSYSCALL_EMU_VECTOR           0xcc
-#endif
 
 /*
  * Vectors 0x30-0x3f are used for ISA interrupts.
index 2c76521..8e8b9a4 100644 (file)
@@ -41,6 +41,7 @@
 
 #include <asm/desc_defs.h>
 #include <asm/kmap_types.h>
+#include <asm/pgtable_types.h>
 
 struct page;
 struct thread_struct;
@@ -63,6 +64,11 @@ struct paravirt_callee_save {
 struct pv_info {
        unsigned int kernel_rpl;
        int shared_kernel_pmd;
+
+#ifdef CONFIG_X86_64
+       u16 extra_user_64bit_cs;  /* __USER_CS if none */
+#endif
+
        int paravirt_enabled;
        const char *name;
 };
index 2193715..0d1171c 100644 (file)
@@ -751,8 +751,6 @@ static inline void __sti_mwait(unsigned long eax, unsigned long ecx)
                     :: "a" (eax), "c" (ecx));
 }
 
-extern void mwait_idle_with_hints(unsigned long eax, unsigned long ecx);
-
 extern void select_idle_routine(const struct cpuinfo_x86 *c);
 extern void init_amd_e400_c1e_mask(void);
 
index 94e7618..3566454 100644 (file)
@@ -131,6 +131,9 @@ struct pt_regs {
 #ifdef __KERNEL__
 
 #include <linux/init.h>
+#ifdef CONFIG_PARAVIRT
+#include <asm/paravirt_types.h>
+#endif
 
 struct cpuinfo_x86;
 struct task_struct;
@@ -187,6 +190,22 @@ static inline int v8086_mode(struct pt_regs *regs)
 #endif
 }
 
+#ifdef CONFIG_X86_64
+static inline bool user_64bit_mode(struct pt_regs *regs)
+{
+#ifndef CONFIG_PARAVIRT
+       /*
+        * On non-paravirt systems, this is the only long mode CPL 3
+        * selector.  We do not allow long mode selectors in the LDT.
+        */
+       return regs->cs == __USER_CS;
+#else
+       /* Headers are too twisted for this to go in paravirt.h. */
+       return regs->cs == __USER_CS || regs->cs == pv_info.extra_user_64bit_cs;
+#endif
+}
+#endif
+
 /*
  * X86_32 CPUs don't save ss and esp if the CPU is already in kernel mode
  * when it traps.  The previous stack will be directly underneath the saved
index 2bae0a5..0012d09 100644 (file)
@@ -40,7 +40,6 @@ asmlinkage void alignment_check(void);
 asmlinkage void machine_check(void);
 #endif /* CONFIG_X86_MCE */
 asmlinkage void simd_coprocessor_error(void);
-asmlinkage void emulate_vsyscall(void);
 
 dotraplinkage void do_divide_error(struct pt_regs *, long);
 dotraplinkage void do_debug(struct pt_regs *, long);
@@ -67,7 +66,6 @@ dotraplinkage void do_alignment_check(struct pt_regs *, long);
 dotraplinkage void do_machine_check(struct pt_regs *, long);
 #endif
 dotraplinkage void do_simd_coprocessor_error(struct pt_regs *, long);
-dotraplinkage void do_emulate_vsyscall(struct pt_regs *, long);
 #ifdef CONFIG_X86_32
 dotraplinkage void do_iret_error(struct pt_regs *, long);
 #endif
index 705bf13..d92641c 100644 (file)
@@ -681,6 +681,8 @@ __SYSCALL(__NR_syncfs, sys_syncfs)
 __SYSCALL(__NR_sendmmsg, sys_sendmmsg)
 #define __NR_setns                             308
 __SYSCALL(__NR_setns, sys_setns)
+#define __NR_getcpu                            309
+__SYSCALL(__NR_getcpu, sys_getcpu)
 
 #ifndef __NO_STUBS
 #define __ARCH_WANT_OLD_READDIR
index 6010707..eaea1d3 100644 (file)
@@ -27,6 +27,12 @@ extern struct timezone sys_tz;
 
 extern void map_vsyscall(void);
 
+/*
+ * Called on instruction fetch fault in vsyscall page.
+ * Returns true if handled.
+ */
+extern bool emulate_vsyscall(struct pt_regs *regs, unsigned long address);
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_X86_VSYSCALL_H */
index 64a619d..7ff4669 100644 (file)
@@ -39,7 +39,7 @@ typedef struct xpaddr {
     ((unsigned long)((u64)CONFIG_XEN_MAX_DOMAIN_MEMORY * 1024 * 1024 * 1024 / PAGE_SIZE))
 
 extern unsigned long *machine_to_phys_mapping;
-extern unsigned int   machine_to_phys_order;
+extern unsigned long  machine_to_phys_nr;
 
 extern unsigned long get_phys_to_machine(unsigned long pfn);
 extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn);
@@ -87,7 +87,7 @@ static inline unsigned long mfn_to_pfn(unsigned long mfn)
        if (xen_feature(XENFEAT_auto_translated_physmap))
                return mfn;
 
-       if (unlikely((mfn >> machine_to_phys_order) != 0)) {
+       if (unlikely(mfn >= machine_to_phys_nr)) {
                pfn = ~0;
                goto try_override;
        }
index 0410557..82f2912 100644 (file)
@@ -17,19 +17,6 @@ CFLAGS_REMOVE_ftrace.o = -pg
 CFLAGS_REMOVE_early_printk.o = -pg
 endif
 
-#
-# vsyscalls (which work on the user stack) should have
-# no stack-protector checks:
-#
-nostackp := $(call cc-option, -fno-stack-protector)
-CFLAGS_vsyscall_64.o   := $(PROFILING) -g0 $(nostackp)
-CFLAGS_hpet.o          := $(nostackp)
-CFLAGS_paravirt.o      := $(nostackp)
-GCOV_PROFILE_vsyscall_64.o     := n
-GCOV_PROFILE_hpet.o            := n
-GCOV_PROFILE_tsc.o             := n
-GCOV_PROFILE_paravirt.o                := n
-
 obj-y                  := process_$(BITS).o signal.o entry_$(BITS).o
 obj-y                  += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o
 obj-y                  += time.o ioport.o ldt.o dumpstack.o
index 5812404..f50e7fb 100644 (file)
@@ -149,6 +149,29 @@ int acpi_processor_ffh_cstate_probe(unsigned int cpu,
 }
 EXPORT_SYMBOL_GPL(acpi_processor_ffh_cstate_probe);
 
+/*
+ * This uses new MONITOR/MWAIT instructions on P4 processors with PNI,
+ * which can obviate IPI to trigger checking of need_resched.
+ * We execute MONITOR against need_resched and enter optimized wait state
+ * through MWAIT. Whenever someone changes need_resched, we would be woken
+ * up from MWAIT (without an IPI).
+ *
+ * New with Core Duo processors, MWAIT can take some hints based on CPU
+ * capability.
+ */
+void mwait_idle_with_hints(unsigned long ax, unsigned long cx)
+{
+       if (!need_resched()) {
+               if (this_cpu_has(X86_FEATURE_CLFLUSH_MONITOR))
+                       clflush((void *)&current_thread_info()->flags);
+
+               __monitor((void *)&current_thread_info()->flags, 0, 0);
+               smp_mb();
+               if (!need_resched())
+                       __mwait(ax, cx);
+       }
+}
+
 void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cx)
 {
        unsigned int cpu = smp_processor_id();
index adc66c3..34b1859 100644 (file)
@@ -207,7 +207,6 @@ static int __cpuinit uv_wakeup_secondary(int phys_apicid, unsigned long start_ri
            ((start_rip << UVH_IPI_INT_VECTOR_SHFT) >> 12) |
            APIC_DM_INIT;
        uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
-       mdelay(10);
 
        val = (1UL << UVH_IPI_INT_SEND_SHFT) |
            (phys_apicid << UVH_IPI_INT_APIC_ID_SHFT) |
index 45fbb8f..f88af2c 100644 (file)
@@ -1590,6 +1590,7 @@ static __init int intel_pmu_init(void)
                break;
 
        case 42: /* SandyBridge */
+       case 45: /* SandyBridge, "Romely-EP" */
                memcpy(hw_cache_event_ids, snb_hw_cache_event_ids,
                       sizeof(hw_cache_event_ids));
 
index e13329d..6419bb0 100644 (file)
@@ -1111,7 +1111,6 @@ zeroentry spurious_interrupt_bug do_spurious_interrupt_bug
 zeroentry coprocessor_error do_coprocessor_error
 errorentry alignment_check do_alignment_check
 zeroentry simd_coprocessor_error do_simd_coprocessor_error
-zeroentry emulate_vsyscall do_emulate_vsyscall
 
 
        /* Reload gs selector with exception handling */
index 613a793..d90272e 100644 (file)
@@ -307,6 +307,10 @@ struct pv_info pv_info = {
        .paravirt_enabled = 0,
        .kernel_rpl = 0,
        .shared_kernel_pmd = 1, /* Only used when CONFIG_X86_PAE is set */
+
+#ifdef CONFIG_X86_64
+       .extra_user_64bit_cs = __USER_CS,
+#endif
 };
 
 struct pv_init_ops pv_init_ops = {
index e1ba8cb..e7e3b01 100644 (file)
@@ -438,29 +438,6 @@ void cpu_idle_wait(void)
 }
 EXPORT_SYMBOL_GPL(cpu_idle_wait);
 
-/*
- * This uses new MONITOR/MWAIT instructions on P4 processors with PNI,
- * which can obviate IPI to trigger checking of need_resched.
- * We execute MONITOR against need_resched and enter optimized wait state
- * through MWAIT. Whenever someone changes need_resched, we would be woken
- * up from MWAIT (without an IPI).
- *
- * New with Core Duo processors, MWAIT can take some hints based on CPU
- * capability.
- */
-void mwait_idle_with_hints(unsigned long ax, unsigned long cx)
-{
-       if (!need_resched()) {
-               if (this_cpu_has(X86_FEATURE_CLFLUSH_MONITOR))
-                       clflush((void *)&current_thread_info()->flags);
-
-               __monitor((void *)&current_thread_info()->flags, 0, 0);
-               smp_mb();
-               if (!need_resched())
-                       __mwait(ax, cx);
-       }
-}
-
 /* Default MONITOR/MWAIT with no hints, used for default C1 state */
 static void mwait_idle(void)
 {
index a3d0dc5..7a3b651 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/uaccess.h>
 #include <linux/io.h>
 #include <linux/kdebug.h>
+#include <linux/cpuidle.h>
 
 #include <asm/pgtable.h>
 #include <asm/system.h>
@@ -109,7 +110,8 @@ void cpu_idle(void)
                        local_irq_disable();
                        /* Don't trace irqs off for idle */
                        stop_critical_timings();
-                       pm_idle();
+                       if (cpuidle_idle_call())
+                               pm_idle();
                        start_critical_timings();
                }
                tick_nohz_restart_sched_tick();
index ca6f7ab..f693e44 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/uaccess.h>
 #include <linux/io.h>
 #include <linux/ftrace.h>
+#include <linux/cpuidle.h>
 
 #include <asm/pgtable.h>
 #include <asm/system.h>
@@ -136,7 +137,8 @@ void cpu_idle(void)
                        enter_idle();
                        /* Don't trace irqs off for idle */
                        stop_critical_timings();
-                       pm_idle();
+                       if (cpuidle_idle_call())
+                               pm_idle();
                        start_critical_timings();
 
                        /* In many cases the interrupt that ended idle
index 7977f0c..c346d11 100644 (file)
@@ -74,7 +74,7 @@ static int is_setting_trap_flag(struct task_struct *child, struct pt_regs *regs)
 
 #ifdef CONFIG_X86_64
                case 0x40 ... 0x4f:
-                       if (regs->cs != __USER_CS)
+                       if (!user_64bit_mode(regs))
                                /* 32-bit mode: register increment */
                                return 0;
                        /* 64-bit mode: REX prefix */
index 9682ec5..6913369 100644 (file)
@@ -872,12 +872,6 @@ void __init trap_init(void)
        set_bit(SYSCALL_VECTOR, used_vectors);
 #endif
 
-#ifdef CONFIG_X86_64
-       BUG_ON(test_bit(VSYSCALL_EMU_VECTOR, used_vectors));
-       set_system_intr_gate(VSYSCALL_EMU_VECTOR, &emulate_vsyscall);
-       set_bit(VSYSCALL_EMU_VECTOR, used_vectors);
-#endif
-
        /*
         * Should be a barrier for any external CPU state:
         */
index 4aa9c54..0f703f1 100644 (file)
@@ -71,7 +71,6 @@ PHDRS {
        text PT_LOAD FLAGS(5);          /* R_E */
        data PT_LOAD FLAGS(6);          /* RW_ */
 #ifdef CONFIG_X86_64
-       user PT_LOAD FLAGS(5);          /* R_E */
 #ifdef CONFIG_SMP
        percpu PT_LOAD FLAGS(6);        /* RW_ */
 #endif
@@ -154,44 +153,16 @@ SECTIONS
 
 #ifdef CONFIG_X86_64
 
-#define VSYSCALL_ADDR (-10*1024*1024)
-
-#define VLOAD_OFFSET (VSYSCALL_ADDR - __vsyscall_0 + LOAD_OFFSET)
-#define VLOAD(x) (ADDR(x) - VLOAD_OFFSET)
-
-#define VVIRT_OFFSET (VSYSCALL_ADDR - __vsyscall_0)
-#define VVIRT(x) (ADDR(x) - VVIRT_OFFSET)
-
-       . = ALIGN(4096);
-       __vsyscall_0 = .;
-
-       . = VSYSCALL_ADDR;
-       .vsyscall : AT(VLOAD(.vsyscall)) {
-               *(.vsyscall_0)
-
-               . = 1024;
-               *(.vsyscall_1)
-
-               . = 2048;
-               *(.vsyscall_2)
-
-               . = 4096;  /* Pad the whole page. */
-       } :user =0xcc
-       . = ALIGN(__vsyscall_0 + PAGE_SIZE, PAGE_SIZE);
-
-#undef VSYSCALL_ADDR
-#undef VLOAD_OFFSET
-#undef VLOAD
-#undef VVIRT_OFFSET
-#undef VVIRT
-
+       . = ALIGN(PAGE_SIZE);
        __vvar_page = .;
 
        .vvar : AT(ADDR(.vvar) - LOAD_OFFSET) {
+               /* work around gold bug 13023 */
+               __vvar_beginning_hack = .;
 
-             /* Place all vvars at the offsets in asm/vvar.h. */
-#define EMIT_VVAR(name, offset)                \
-               . = offset;             \
+               /* Place all vvars at the offsets in asm/vvar.h. */
+#define EMIT_VVAR(name, offset)                        \
+               . = __vvar_beginning_hack + offset;     \
                *(.vvar_ ## name)
 #define __VVAR_KERNEL_LDS
 #include <asm/vvar.h>
index dda7dff..18ae83d 100644 (file)
@@ -18,9 +18,6 @@
  *  use the vDSO.
  */
 
-/* Disable profiling for userspace code: */
-#define DISABLE_BRANCH_PROFILING
-
 #include <linux/time.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <asm/vgtod.h>
 #include <asm/traps.h>
 
+#define CREATE_TRACE_POINTS
+#include "vsyscall_trace.h"
+
 DEFINE_VVAR(int, vgetcpu_mode);
 DEFINE_VVAR(struct vsyscall_gtod_data, vsyscall_gtod_data) =
 {
        .lock = __SEQLOCK_UNLOCKED(__vsyscall_gtod_data.lock),
 };
 
+static enum { EMULATE, NATIVE, NONE } vsyscall_mode = EMULATE;
+
+static int __init vsyscall_setup(char *str)
+{
+       if (str) {
+               if (!strcmp("emulate", str))
+                       vsyscall_mode = EMULATE;
+               else if (!strcmp("native", str))
+                       vsyscall_mode = NATIVE;
+               else if (!strcmp("none", str))
+                       vsyscall_mode = NONE;
+               else
+                       return -EINVAL;
+
+               return 0;
+       }
+
+       return -EINVAL;
+}
+early_param("vsyscall", vsyscall_setup);
+
 void update_vsyscall_tz(void)
 {
        unsigned long flags;
@@ -100,7 +121,7 @@ static void warn_bad_vsyscall(const char *level, struct pt_regs *regs,
 
        printk("%s%s[%d] %s ip:%lx cs:%lx sp:%lx ax:%lx si:%lx di:%lx\n",
               level, tsk->comm, task_pid_nr(tsk),
-              message, regs->ip - 2, regs->cs,
+              message, regs->ip, regs->cs,
               regs->sp, regs->ax, regs->si, regs->di);
 }
 
@@ -118,46 +139,39 @@ static int addr_to_vsyscall_nr(unsigned long addr)
        return nr;
 }
 
-void dotraplinkage do_emulate_vsyscall(struct pt_regs *regs, long error_code)
+bool emulate_vsyscall(struct pt_regs *regs, unsigned long address)
 {
        struct task_struct *tsk;
        unsigned long caller;
        int vsyscall_nr;
        long ret;
 
-       local_irq_enable();
-
        /*
-        * Real 64-bit user mode code has cs == __USER_CS.  Anything else
-        * is bogus.
+        * No point in checking CS -- the only way to get here is a user mode
+        * trap to a high address, which means that we're in 64-bit user code.
         */
-       if (regs->cs != __USER_CS) {
-               /*
-                * If we trapped from kernel mode, we might as well OOPS now
-                * instead of returning to some random address and OOPSing
-                * then.
-                */
-               BUG_ON(!user_mode(regs));
 
-               /* Compat mode and non-compat 32-bit CS should both segfault. */
-               warn_bad_vsyscall(KERN_WARNING, regs,
-                                 "illegal int 0xcc from 32-bit mode");
-               goto sigsegv;
+       WARN_ON_ONCE(address != regs->ip);
+
+       if (vsyscall_mode == NONE) {
+               warn_bad_vsyscall(KERN_INFO, regs,
+                                 "vsyscall attempted with vsyscall=none");
+               return false;
        }
 
-       /*
-        * x86-ism here: regs->ip points to the instruction after the int 0xcc,
-        * and int 0xcc is two bytes long.
-        */
-       vsyscall_nr = addr_to_vsyscall_nr(regs->ip - 2);
+       vsyscall_nr = addr_to_vsyscall_nr(address);
+
+       trace_emulate_vsyscall(vsyscall_nr);
+
        if (vsyscall_nr < 0) {
                warn_bad_vsyscall(KERN_WARNING, regs,
-                                 "illegal int 0xcc (exploit attempt?)");
+                                 "misaligned vsyscall (exploit attempt or buggy program) -- look up the vsyscall kernel parameter if you need a workaround");
                goto sigsegv;
        }
 
        if (get_user(caller, (unsigned long __user *)regs->sp) != 0) {
-               warn_bad_vsyscall(KERN_WARNING, regs, "int 0xcc with bad stack (exploit attempt?)");
+               warn_bad_vsyscall(KERN_WARNING, regs,
+                                 "vsyscall with bad stack (exploit attempt?)");
                goto sigsegv;
        }
 
@@ -202,13 +216,11 @@ void dotraplinkage do_emulate_vsyscall(struct pt_regs *regs, long error_code)
        regs->ip = caller;
        regs->sp += 8;
 
-       local_irq_disable();
-       return;
+       return true;
 
 sigsegv:
-       regs->ip -= 2;  /* The faulting instruction should be the int 0xcc. */
        force_sig(SIGSEGV, current);
-       local_irq_disable();
+       return true;
 }
 
 /*
@@ -256,15 +268,21 @@ cpu_vsyscall_notifier(struct notifier_block *n, unsigned long action, void *arg)
 
 void __init map_vsyscall(void)
 {
-       extern char __vsyscall_0;
-       unsigned long physaddr_page0 = __pa_symbol(&__vsyscall_0);
+       extern char __vsyscall_page;
+       unsigned long physaddr_vsyscall = __pa_symbol(&__vsyscall_page);
        extern char __vvar_page;
        unsigned long physaddr_vvar_page = __pa_symbol(&__vvar_page);
 
-       /* Note that VSYSCALL_MAPPED_PAGES must agree with the code below. */
-       __set_fixmap(VSYSCALL_FIRST_PAGE, physaddr_page0, PAGE_KERNEL_VSYSCALL);
+       __set_fixmap(VSYSCALL_FIRST_PAGE, physaddr_vsyscall,
+                    vsyscall_mode == NATIVE
+                    ? PAGE_KERNEL_VSYSCALL
+                    : PAGE_KERNEL_VVAR);
+       BUILD_BUG_ON((unsigned long)__fix_to_virt(VSYSCALL_FIRST_PAGE) !=
+                    (unsigned long)VSYSCALL_START);
+
        __set_fixmap(VVAR_PAGE, physaddr_vvar_page, PAGE_KERNEL_VVAR);
-       BUILD_BUG_ON((unsigned long)__fix_to_virt(VVAR_PAGE) != (unsigned long)VVAR_ADDRESS);
+       BUILD_BUG_ON((unsigned long)__fix_to_virt(VVAR_PAGE) !=
+                    (unsigned long)VVAR_ADDRESS);
 }
 
 static int __init vsyscall_init(void)
index ffa845e..c9596a9 100644 (file)
@@ -7,21 +7,31 @@
  */
 
 #include <linux/linkage.h>
+
 #include <asm/irq_vectors.h>
+#include <asm/page_types.h>
+#include <asm/unistd_64.h>
+
+__PAGE_ALIGNED_DATA
+       .globl __vsyscall_page
+       .balign PAGE_SIZE, 0xcc
+       .type __vsyscall_page, @object
+__vsyscall_page:
+
+       mov $__NR_gettimeofday, %rax
+       syscall
+       ret
 
-/* The unused parts of the page are filled with 0xcc by the linker script. */
+       .balign 1024, 0xcc
+       mov $__NR_time, %rax
+       syscall
+       ret
 
-.section .vsyscall_0, "a"
-ENTRY(vsyscall_0)
-       int $VSYSCALL_EMU_VECTOR
-END(vsyscall_0)
+       .balign 1024, 0xcc
+       mov $__NR_getcpu, %rax
+       syscall
+       ret
 
-.section .vsyscall_1, "a"
-ENTRY(vsyscall_1)
-       int $VSYSCALL_EMU_VECTOR
-END(vsyscall_1)
+       .balign 4096, 0xcc
 
-.section .vsyscall_2, "a"
-ENTRY(vsyscall_2)
-       int $VSYSCALL_EMU_VECTOR
-END(vsyscall_2)
+       .size __vsyscall_page, 4096
diff --git a/arch/x86/kernel/vsyscall_trace.h b/arch/x86/kernel/vsyscall_trace.h
new file mode 100644 (file)
index 0000000..a8b2ede
--- /dev/null
@@ -0,0 +1,29 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM vsyscall
+
+#if !defined(__VSYSCALL_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define __VSYSCALL_TRACE_H
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(emulate_vsyscall,
+
+           TP_PROTO(int nr),
+
+           TP_ARGS(nr),
+
+           TP_STRUCT__entry(__field(int, nr)),
+
+           TP_fast_assign(
+                          __entry->nr = nr;
+                          ),
+
+           TP_printk("nr = %d", __entry->nr)
+);
+
+#endif
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ../../arch/x86/kernel
+#define TRACE_INCLUDE_FILE vsyscall_trace
+#include <trace/define_trace.h>
index 988724b..ff5790d 100644 (file)
@@ -22,6 +22,8 @@ config KVM
        depends on HAVE_KVM
        # for device assignment:
        depends on PCI
+       # for TASKSTATS/TASK_DELAY_ACCT:
+       depends on NET
        select PREEMPT_NOTIFIERS
        select MMU_NOTIFIER
        select ANON_INODES
@@ -31,6 +33,7 @@ config KVM
        select KVM_ASYNC_PF
        select USER_RETURN_NOTIFIER
        select KVM_MMIO
+       select TASKSTATS
        select TASK_DELAY_ACCT
        ---help---
          Support hosting fully virtualized guest machines using hardware
index 4d09df0..0d17c8c 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm/traps.h>                 /* dotraplinkage, ...           */
 #include <asm/pgalloc.h>               /* pgd_*(), ...                 */
 #include <asm/kmemcheck.h>             /* kmemcheck_*(), ...           */
+#include <asm/vsyscall.h>
 
 /*
  * Page fault error code bits:
@@ -105,7 +106,7 @@ check_prefetch_opcode(struct pt_regs *regs, unsigned char *instr,
                 * but for now it's good enough to assume that long
                 * mode only uses well known segments or kernel.
                 */
-               return (!user_mode(regs)) || (regs->cs == __USER_CS);
+               return (!user_mode(regs) || user_64bit_mode(regs));
 #endif
        case 0x60:
                /* 0x64 thru 0x67 are valid prefixes in all modes. */
@@ -720,6 +721,18 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
                if (is_errata100(regs, address))
                        return;
 
+#ifdef CONFIG_X86_64
+               /*
+                * Instruction fetch faults in the vsyscall page might need
+                * emulation.
+                */
+               if (unlikely((error_code & PF_INSTR) &&
+                            ((address & ~0xfff) == VSYSCALL_START))) {
+                       if (emulate_vsyscall(regs, address))
+                               return;
+               }
+#endif
+
                if (unlikely(show_unhandled_signals))
                        show_signal_msg(regs, error_code, address, tsk);
 
index 68c3c13..c953302 100644 (file)
@@ -246,10 +246,9 @@ static void add_resources(struct pci_root_info *info)
 
                conflict = insert_resource_conflict(root, res);
                if (conflict)
-                       dev_err(&info->bridge->dev,
-                               "address space collision: host bridge window %pR "
-                               "conflicts with %s %pR\n",
-                               res, conflict->name, conflict);
+                       dev_info(&info->bridge->dev,
+                                "ignoring host bridge window %pR (conflicts with %s %pR)\n",
+                                res, conflict->name, conflict);
                else
                        pci_bus_add_resource(info->bus, res, 0);
        }
@@ -361,6 +360,15 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
                }
        }
 
+       /* After the PCI-E bus has been walked and all devices discovered,
+        * configure any settings of the fabric that might be necessary.
+        */
+       if (bus) {
+               struct pci_bus *child;
+               list_for_each_entry(child, &bus->children, node)
+                       pcie_bus_configure_settings(child, child->self->pcie_mpss);
+       }
+
        if (!bus)
                kfree(sd);
 
index 67858be..9917609 100644 (file)
@@ -257,6 +257,7 @@ static int ce4100_conf_read(unsigned int seg, unsigned int bus,
 {
        int i;
 
+       WARN_ON(seg);
        if (bus == 1) {
                for (i = 0; i < ARRAY_SIZE(bus1_fixups); i++) {
                        if (bus1_fixups[i].dev_func == devfn &&
@@ -282,6 +283,7 @@ static int ce4100_conf_write(unsigned int seg, unsigned int bus,
 {
        int i;
 
+       WARN_ON(seg);
        if (bus == 1) {
                for (i = 0; i < ARRAY_SIZE(bus1_fixups); i++) {
                        if (bus1_fixups[i].dev_func == devfn &&
index 5fe7502..92df322 100644 (file)
@@ -246,13 +246,6 @@ static const struct dmi_system_id __devinitconst pciprobe_dmi_table[] = {
                },
        },
 #endif         /* __i386__ */
-       {
-               .callback = find_sort_method,
-               .ident = "Dell System",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
-               },
-       },
        {
                .callback = set_bf_sort,
                .ident = "Dell PowerEdge 1950",
@@ -293,6 +286,13 @@ static const struct dmi_system_id __devinitconst pciprobe_dmi_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R900"),
                },
        },
+       {
+               .callback = find_sort_method,
+               .ident = "Dell System",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+               },
+       },
        {
                .callback = set_bf_sort,
                .ident = "HP ProLiant BL20p G3",
index e6fd847..4f2c704 100644 (file)
@@ -22,7 +22,7 @@ static int pci_conf1_read(unsigned int seg, unsigned int bus,
 {
        unsigned long flags;
 
-       if ((bus > 255) || (devfn > 255) || (reg > 4095)) {
+       if (seg || (bus > 255) || (devfn > 255) || (reg > 4095)) {
                *value = -1;
                return -EINVAL;
        }
@@ -53,7 +53,7 @@ static int pci_conf1_write(unsigned int seg, unsigned int bus,
 {
        unsigned long flags;
 
-       if ((bus > 255) || (devfn > 255) || (reg > 4095))
+       if (seg || (bus > 255) || (devfn > 255) || (reg > 4095))
                return -EINVAL;
 
        raw_spin_lock_irqsave(&pci_config_lock, flags);
@@ -97,6 +97,7 @@ static int pci_conf2_read(unsigned int seg, unsigned int bus,
        unsigned long flags;
        int dev, fn;
 
+       WARN_ON(seg);
        if ((bus > 255) || (devfn > 255) || (reg > 255)) {
                *value = -1;
                return -EINVAL;
@@ -138,6 +139,7 @@ static int pci_conf2_write(unsigned int seg, unsigned int bus,
        unsigned long flags;
        int dev, fn;
 
+       WARN_ON(seg);
        if ((bus > 255) || (devfn > 255) || (reg > 255)) 
                return -EINVAL;
 
index 5c9e245..512a88c 100644 (file)
@@ -34,6 +34,7 @@ static int pci_conf1_mq_read(unsigned int seg, unsigned int bus,
        unsigned long flags;
        void *adr __iomem = XQUAD_PORT_ADDR(0xcfc, BUS2QUAD(bus));
 
+       WARN_ON(seg);
        if (!value || (bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255))
                return -EINVAL;
 
@@ -73,6 +74,7 @@ static int pci_conf1_mq_write(unsigned int seg, unsigned int bus,
        unsigned long flags;
        void *adr __iomem = XQUAD_PORT_ADDR(0xcfc, BUS2QUAD(bus));
 
+       WARN_ON(seg);
        if ((bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255)) 
                return -EINVAL;
 
index 13700ec..5262603 100644 (file)
@@ -206,6 +206,8 @@ static int pci_olpc_read(unsigned int seg, unsigned int bus,
 {
        uint32_t *addr;
 
+       WARN_ON(seg);
+
        /* Use the hardware mechanism for non-simulated devices */
        if (!is_simulated(bus, devfn))
                return pci_direct_conf1.read(seg, bus, devfn, reg, len, value);
@@ -264,6 +266,8 @@ static int pci_olpc_read(unsigned int seg, unsigned int bus,
 static int pci_olpc_write(unsigned int seg, unsigned int bus,
                unsigned int devfn, int reg, int len, uint32_t value)
 {
+       WARN_ON(seg);
+
        /* Use the hardware mechanism for non-simulated devices */
        if (!is_simulated(bus, devfn))
                return pci_direct_conf1.write(seg, bus, devfn, reg, len, value);
index a5f7d0d..f685535 100644 (file)
@@ -181,6 +181,7 @@ static int pci_bios_read(unsigned int seg, unsigned int bus,
        unsigned long flags;
        unsigned long bx = (bus << 8) | devfn;
 
+       WARN_ON(seg);
        if (!value || (bus > 255) || (devfn > 255) || (reg > 255))
                return -EINVAL;
 
@@ -247,6 +248,7 @@ static int pci_bios_write(unsigned int seg, unsigned int bus,
        unsigned long flags;
        unsigned long bx = (bus << 8) | devfn;
 
+       WARN_ON(seg);
        if ((bus > 255) || (devfn > 255) || (reg > 255)) 
                return -EINVAL;
 
index 03008f7..6f2f8ee 100644 (file)
@@ -24,7 +24,7 @@ static void pci_visws_disable_irq(struct pci_dev *dev) { }
 
 unsigned int pci_bus0, pci_bus1;
 
-static int __init visws_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init visws_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq, bus = dev->bus->number;
 
index f61ccdd..1ea3877 100644 (file)
@@ -1,3 +1,4 @@
 obj-$(CONFIG_X86_MRST)         += mrst.o
 obj-$(CONFIG_X86_MRST)         += vrtc.o
 obj-$(CONFIG_EARLY_PRINTK_MRST)        += early_printk_mrst.o
+obj-$(CONFIG_X86_MRST)         += pmu.o
diff --git a/arch/x86/platform/mrst/pmu.c b/arch/x86/platform/mrst/pmu.c
new file mode 100644 (file)
index 0000000..9281da7
--- /dev/null
@@ -0,0 +1,817 @@
+/*
+ * mrst/pmu.c - driver for MRST Power Management Unit
+ *
+ * Copyright (c) 2011, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/cpuidle.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/seq_file.h>
+#include <linux/sfi.h>
+#include <asm/intel_scu_ipc.h>
+#include "pmu.h"
+
+#define IPCMSG_FW_REVISION     0xF4
+
+struct mrst_device {
+       u16 pci_dev_num;        /* DEBUG only */
+       u16 lss;
+       u16 latest_request;
+       unsigned int pci_state_counts[PCI_D3cold + 1]; /* DEBUG only */
+};
+
+/*
+ * comlete list of MRST PCI devices
+ */
+static struct mrst_device mrst_devs[] = {
+/*  0 */ { 0x0800, LSS_SPI0 },         /* Moorestown SPI Ctrl 0 */
+/*  1 */ { 0x0801, LSS_SPI1 },         /* Moorestown SPI Ctrl 1 */
+/*  2 */ { 0x0802, LSS_I2C0 },         /* Moorestown I2C 0 */
+/*  3 */ { 0x0803, LSS_I2C1 },         /* Moorestown I2C 1 */
+/*  4 */ { 0x0804, LSS_I2C2 },         /* Moorestown I2C 2 */
+/*  5 */ { 0x0805, LSS_KBD },          /* Moorestown Keyboard Ctrl */
+/*  6 */ { 0x0806, LSS_USB_HC },       /* Moorestown USB Ctrl */
+/*  7 */ { 0x0807, LSS_SD_HC0 },       /* Moorestown SD Host Ctrl 0 */
+/*  8 */ { 0x0808, LSS_SD_HC1 },       /* Moorestown SD Host Ctrl 1 */
+/*  9 */ { 0x0809, LSS_NAND },         /* Moorestown NAND Ctrl */
+/* 10 */ { 0x080a, LSS_AUDIO },                /* Moorestown Audio Ctrl */
+/* 11 */ { 0x080b, LSS_IMAGING },      /* Moorestown ISP */
+/* 12 */ { 0x080c, LSS_SECURITY },     /* Moorestown Security Controller */
+/* 13 */ { 0x080d, LSS_DISPLAY },      /* Moorestown External Displays */
+/* 14 */ { 0x080e, 0 },                        /* Moorestown SCU IPC */
+/* 15 */ { 0x080f, LSS_GPIO },         /* Moorestown GPIO Controller */
+/* 16 */ { 0x0810, 0 },                        /* Moorestown Power Management Unit */
+/* 17 */ { 0x0811, LSS_USB_OTG },      /* Moorestown OTG Ctrl */
+/* 18 */ { 0x0812, LSS_SPI2 },         /* Moorestown SPI Ctrl 2 */
+/* 19 */ { 0x0813, 0 },                        /* Moorestown SC DMA */
+/* 20 */ { 0x0814, LSS_AUDIO_LPE },    /* Moorestown LPE DMA */
+/* 21 */ { 0x0815, LSS_AUDIO_SSP },    /* Moorestown SSP0 */
+
+/* 22 */ { 0x084F, LSS_SD_HC2 },       /* Moorestown SD Host Ctrl 2 */
+
+/* 23 */ { 0x4102, 0 },                        /* Lincroft */
+/* 24 */ { 0x4110, 0 },                        /* Lincroft */
+};
+
+/* n.b. We ignore PCI-id 0x815 in LSS9 b/c MeeGo has no driver for it */
+static u16 mrst_lss9_pci_ids[] = {0x080a, 0x0814, 0};
+static u16 mrst_lss10_pci_ids[] = {0x0800, 0x0801, 0x0802, 0x0803,
+                                       0x0804, 0x0805, 0x080f, 0};
+
+/* handle concurrent SMP invokations of pmu_pci_set_power_state() */
+static spinlock_t mrst_pmu_power_state_lock;
+
+static unsigned int wake_counters[MRST_NUM_LSS];       /* DEBUG only */
+static unsigned int pmu_irq_stats[INT_INVALID + 1];    /* DEBUG only */
+
+static int graphics_is_off;
+static int lss_s0i3_enabled;
+static bool mrst_pmu_s0i3_enable;
+
+/*  debug counters */
+static u32 pmu_wait_ready_calls;
+static u32 pmu_wait_ready_udelays;
+static u32 pmu_wait_ready_udelays_max;
+static u32 pmu_wait_done_calls;
+static u32 pmu_wait_done_udelays;
+static u32 pmu_wait_done_udelays_max;
+static u32 pmu_set_power_state_entry;
+static u32 pmu_set_power_state_send_cmd;
+
+static struct mrst_device *pci_id_2_mrst_dev(u16 pci_dev_num)
+{
+       int index = 0;
+
+       if ((pci_dev_num >= 0x0800) && (pci_dev_num <= 0x815))
+               index = pci_dev_num - 0x800;
+       else if (pci_dev_num == 0x084F)
+               index = 22;
+       else if (pci_dev_num == 0x4102)
+               index = 23;
+       else if (pci_dev_num == 0x4110)
+               index = 24;
+
+       if (pci_dev_num != mrst_devs[index].pci_dev_num) {
+               WARN_ONCE(1, FW_BUG "Unknown PCI device 0x%04X\n", pci_dev_num);
+               return 0;
+       }
+
+       return &mrst_devs[index];
+}
+
+/**
+ * mrst_pmu_validate_cstates
+ * @dev: cpuidle_device
+ *
+ * Certain states are not appropriate for governor to pick in some cases.
+ * This function will be called as cpuidle_device's prepare callback and
+ * thus tells governor to ignore such states when selecting the next state
+ * to enter.
+ */
+
+#define IDLE_STATE4_IS_C6      4
+#define IDLE_STATE5_IS_S0I3    5
+
+int mrst_pmu_invalid_cstates(void)
+{
+       int cpu = smp_processor_id();
+
+       /*
+        * Demote to C4 if the PMU is busy.
+        * Since LSS changes leave the busy bit clear...
+        * busy means either the PMU is waiting for an ACK-C6 that
+        * isn't coming due to an MWAIT that returned immediately;
+        * or we returned from S0i3 successfully, and the PMU
+        * is not done sending us interrupts.
+        */
+       if (pmu_read_busy_status())
+               return 1 << IDLE_STATE4_IS_C6 | 1 << IDLE_STATE5_IS_S0I3;
+
+       /*
+        * Disallow S0i3 if: PMU is not initialized, or CPU1 is active,
+        * or if device LSS is insufficient, or the GPU is active,
+        * or if it has been explicitly disabled.
+        */
+       if (!pmu_reg || !cpumask_equal(cpu_online_mask, cpumask_of(cpu)) ||
+           !lss_s0i3_enabled || !graphics_is_off || !mrst_pmu_s0i3_enable)
+               return 1 << IDLE_STATE5_IS_S0I3;
+       else
+               return 0;
+}
+
+/*
+ * pmu_update_wake_counters(): read PM_WKS, update wake_counters[]
+ * DEBUG only.
+ */
+static void pmu_update_wake_counters(void)
+{
+       int lss;
+       u32 wake_status;
+
+       wake_status = pmu_read_wks();
+
+       for (lss = 0; lss < MRST_NUM_LSS; ++lss) {
+               if (wake_status & (1 << lss))
+                       wake_counters[lss]++;
+       }
+}
+
+int mrst_pmu_s0i3_entry(void)
+{
+       int status;
+
+       /* Clear any possible error conditions */
+       pmu_write_ics(0x300);
+
+       /* set wake control to current D-states */
+       pmu_write_wssc(S0I3_SSS_TARGET);
+
+       status = mrst_s0i3_entry(PM_S0I3_COMMAND, &pmu_reg->pm_cmd);
+       pmu_update_wake_counters();
+       return status;
+}
+
+/* poll for maximum of 5ms for busy bit to clear */
+static int pmu_wait_ready(void)
+{
+       int udelays;
+
+       pmu_wait_ready_calls++;
+
+       for (udelays = 0; udelays < 500; ++udelays) {
+               if (udelays > pmu_wait_ready_udelays_max)
+                       pmu_wait_ready_udelays_max = udelays;
+
+               if (pmu_read_busy_status() == 0)
+                       return 0;
+
+               udelay(10);
+               pmu_wait_ready_udelays++;
+       }
+
+       /*
+        * if this fires, observe
+        * /sys/kernel/debug/mrst_pmu_wait_ready_calls
+        * /sys/kernel/debug/mrst_pmu_wait_ready_udelays
+        */
+       WARN_ONCE(1, "SCU not ready for 5ms");
+       return -EBUSY;
+}
+/* poll for maximum of 50ms us for busy bit to clear */
+static int pmu_wait_done(void)
+{
+       int udelays;
+
+       pmu_wait_done_calls++;
+
+       for (udelays = 0; udelays < 500; ++udelays) {
+               if (udelays > pmu_wait_done_udelays_max)
+                       pmu_wait_done_udelays_max = udelays;
+
+               if (pmu_read_busy_status() == 0)
+                       return 0;
+
+               udelay(100);
+               pmu_wait_done_udelays++;
+       }
+
+       /*
+        * if this fires, observe
+        * /sys/kernel/debug/mrst_pmu_wait_done_calls
+        * /sys/kernel/debug/mrst_pmu_wait_done_udelays
+        */
+       WARN_ONCE(1, "SCU not done for 50ms");
+       return -EBUSY;
+}
+
+u32 mrst_pmu_msi_is_disabled(void)
+{
+       return pmu_msi_is_disabled();
+}
+
+void mrst_pmu_enable_msi(void)
+{
+       pmu_msi_enable();
+}
+
+/**
+ * pmu_irq - pmu driver interrupt handler
+ * Context: interrupt context
+ */
+static irqreturn_t pmu_irq(int irq, void *dummy)
+{
+       union pmu_pm_ics pmu_ics;
+
+       pmu_ics.value = pmu_read_ics();
+
+       if (!pmu_ics.bits.pending)
+               return IRQ_NONE;
+
+       switch (pmu_ics.bits.cause) {
+       case INT_SPURIOUS:
+       case INT_CMD_DONE:
+       case INT_CMD_ERR:
+       case INT_WAKE_RX:
+       case INT_SS_ERROR:
+       case INT_S0IX_MISS:
+       case INT_NO_ACKC6:
+               pmu_irq_stats[pmu_ics.bits.cause]++;
+               break;
+       default:
+               pmu_irq_stats[INT_INVALID]++;
+       }
+
+       pmu_write_ics(pmu_ics.value); /* Clear pending interrupt */
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * Translate PCI power management to MRST LSS D-states
+ */
+static int pci_2_mrst_state(int lss, pci_power_t pci_state)
+{
+       switch (pci_state) {
+       case PCI_D0:
+               if (SSMSK(D0i1, lss) & D0I1_ACG_SSS_TARGET)
+                       return D0i1;
+               else
+                       return D0;
+       case PCI_D1:
+               return D0i1;
+       case PCI_D2:
+               return D0i2;
+       case PCI_D3hot:
+       case PCI_D3cold:
+               return D0i3;
+       default:
+               WARN(1, "pci_state %d\n", pci_state);
+               return 0;
+       }
+}
+
+static int pmu_issue_command(u32 pm_ssc)
+{
+       union pmu_pm_set_cfg_cmd_t command;
+
+       if (pmu_read_busy_status()) {
+               pr_debug("pmu is busy, Operation not permitted\n");
+               return -1;
+       }
+
+       /*
+        * enable interrupts in PMU so that interrupts are
+        * propagated when ioc bit for a particular set
+        * command is set
+        */
+
+       pmu_irq_enable();
+
+       /* Configure the sub systems for pmu2 */
+
+       pmu_write_ssc(pm_ssc);
+
+       /*
+        * Send the set config command for pmu its configured
+        * for mode CM_IMMEDIATE & hence with No Trigger
+        */
+
+       command.pmu2_params.d_param.cfg_mode = CM_IMMEDIATE;
+       command.pmu2_params.d_param.cfg_delay = 0;
+       command.pmu2_params.d_param.rsvd = 0;
+
+       /* construct the command to send SET_CFG to particular PMU */
+       command.pmu2_params.d_param.cmd = SET_CFG_CMD;
+       command.pmu2_params.d_param.ioc = 0;
+       command.pmu2_params.d_param.mode_id = 0;
+       command.pmu2_params.d_param.sys_state = SYS_STATE_S0I0;
+
+       /* write the value of PM_CMD into particular PMU */
+       pr_debug("pmu command being written %x\n",
+                       command.pmu_pm_set_cfg_cmd_value);
+
+       pmu_write_cmd(command.pmu_pm_set_cfg_cmd_value);
+
+       return 0;
+}
+
+static u16 pmu_min_lss_pci_req(u16 *ids, u16 pci_state)
+{
+       u16 existing_request;
+       int i;
+
+       for (i = 0; ids[i]; ++i) {
+               struct mrst_device *mrst_dev;
+
+               mrst_dev = pci_id_2_mrst_dev(ids[i]);
+               if (unlikely(!mrst_dev))
+                       continue;
+
+               existing_request = mrst_dev->latest_request;
+               if (existing_request < pci_state)
+                       pci_state = existing_request;
+       }
+       return pci_state;
+}
+
+/**
+ * pmu_pci_set_power_state - Callback function is used by all the PCI devices
+ *                     for a platform  specific device power on/shutdown.
+ */
+
+int pmu_pci_set_power_state(struct pci_dev *pdev, pci_power_t pci_state)
+{
+       u32 old_sss, new_sss;
+       int status = 0;
+       struct mrst_device *mrst_dev;
+
+       pmu_set_power_state_entry++;
+
+       BUG_ON(pdev->vendor != PCI_VENDOR_ID_INTEL);
+       BUG_ON(pci_state < PCI_D0 || pci_state > PCI_D3cold);
+
+       mrst_dev = pci_id_2_mrst_dev(pdev->device);
+       if (unlikely(!mrst_dev))
+               return -ENODEV;
+
+       mrst_dev->pci_state_counts[pci_state]++;        /* count invocations */
+
+       /* PMU driver calls self as part of PCI initialization, ignore */
+       if (pdev->device == PCI_DEV_ID_MRST_PMU)
+               return 0;
+
+       BUG_ON(!pmu_reg); /* SW bug if called before initialized */
+
+       spin_lock(&mrst_pmu_power_state_lock);
+
+       if (pdev->d3_delay) {
+               dev_dbg(&pdev->dev, "d3_delay %d, should be 0\n",
+                       pdev->d3_delay);
+               pdev->d3_delay = 0;
+       }
+       /*
+        * If Lincroft graphics, simply remember state
+        */
+       if ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY
+               && !((pdev->class & PCI_SUB_CLASS_MASK) >> 8)) {
+               if (pci_state == PCI_D0)
+                       graphics_is_off = 0;
+               else
+                       graphics_is_off = 1;
+               goto ret;
+       }
+
+       if (!mrst_dev->lss)
+               goto ret;       /* device with no LSS */
+
+       if (mrst_dev->latest_request == pci_state)
+               goto ret;       /* no change */
+
+       mrst_dev->latest_request = pci_state;   /* record latest request */
+
+       /*
+        * LSS9 and LSS10 contain multiple PCI devices.
+        * Use the lowest numbered (highest power) state in the LSS
+        */
+       if (mrst_dev->lss == 9)
+               pci_state = pmu_min_lss_pci_req(mrst_lss9_pci_ids, pci_state);
+       else if (mrst_dev->lss == 10)
+               pci_state = pmu_min_lss_pci_req(mrst_lss10_pci_ids, pci_state);
+
+       status = pmu_wait_ready();
+       if (status)
+               goto ret;
+
+       old_sss = pmu_read_sss();
+       new_sss = old_sss & ~SSMSK(3, mrst_dev->lss);
+       new_sss |= SSMSK(pci_2_mrst_state(mrst_dev->lss, pci_state),
+                       mrst_dev->lss);
+
+       if (new_sss == old_sss)
+               goto ret;       /* nothing to do */
+
+       pmu_set_power_state_send_cmd++;
+
+       status = pmu_issue_command(new_sss);
+
+       if (unlikely(status != 0)) {
+               dev_err(&pdev->dev, "Failed to Issue a PM command\n");
+               goto ret;
+       }
+
+       if (pmu_wait_done())
+               goto ret;
+
+       lss_s0i3_enabled =
+       ((pmu_read_sss() & S0I3_SSS_TARGET) == S0I3_SSS_TARGET);
+ret:
+       spin_unlock(&mrst_pmu_power_state_lock);
+       return status;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static char *d0ix_names[] = {"D0", "D0i1", "D0i2", "D0i3"};
+
+static inline const char *d0ix_name(int state)
+{
+       return d0ix_names[(int) state];
+}
+
+static int debug_mrst_pmu_show(struct seq_file *s, void *unused)
+{
+       struct pci_dev *pdev = NULL;
+       u32 cur_pmsss;
+       int lss;
+
+       seq_printf(s, "0x%08X D0I1_ACG_SSS_TARGET\n", D0I1_ACG_SSS_TARGET);
+
+       cur_pmsss = pmu_read_sss();
+
+       seq_printf(s, "0x%08X S0I3_SSS_TARGET\n", S0I3_SSS_TARGET);
+
+       seq_printf(s, "0x%08X Current SSS ", cur_pmsss);
+       seq_printf(s, lss_s0i3_enabled ? "\n" : "[BLOCKS s0i3]\n");
+
+       if (cpumask_equal(cpu_online_mask, cpumask_of(0)))
+               seq_printf(s, "cpu0 is only cpu online\n");
+       else
+               seq_printf(s, "cpu0 is NOT only cpu online [BLOCKS S0i3]\n");
+
+       seq_printf(s, "GFX: %s\n", graphics_is_off ? "" : "[BLOCKS s0i3]");
+
+
+       for_each_pci_dev(pdev) {
+               int pos;
+               u16 pmcsr;
+               struct mrst_device *mrst_dev;
+               int i;
+
+               mrst_dev = pci_id_2_mrst_dev(pdev->device);
+
+               seq_printf(s, "%s %04x/%04X %-16.16s ",
+                       dev_name(&pdev->dev),
+                       pdev->vendor, pdev->device,
+                       dev_driver_string(&pdev->dev));
+
+               if (unlikely (!mrst_dev)) {
+                       seq_printf(s, " UNKNOWN\n");
+                       continue;
+               }
+
+               if (mrst_dev->lss)
+                       seq_printf(s, "LSS %2d %-4s ", mrst_dev->lss,
+                               d0ix_name(((cur_pmsss >>
+                                       (mrst_dev->lss * 2)) & 0x3)));
+               else
+                       seq_printf(s, "            ");
+
+               /* PCI PM config space setting */
+               pos = pci_find_capability(pdev, PCI_CAP_ID_PM);
+               if (pos != 0) {
+                       pci_read_config_word(pdev, pos + PCI_PM_CTRL, &pmcsr);
+               seq_printf(s, "PCI-%-4s",
+                       pci_power_name(pmcsr & PCI_PM_CTRL_STATE_MASK));
+               } else {
+                       seq_printf(s, "        ");
+               }
+
+               seq_printf(s, " %s ", pci_power_name(mrst_dev->latest_request));
+               for (i = 0; i <= PCI_D3cold; ++i)
+                       seq_printf(s, "%d ", mrst_dev->pci_state_counts[i]);
+
+               if (mrst_dev->lss) {
+                       unsigned int lssmask;
+
+                       lssmask = SSMSK(D0i3, mrst_dev->lss);
+
+                       if ((lssmask & S0I3_SSS_TARGET) &&
+                               ((lssmask & cur_pmsss) !=
+                                       (lssmask & S0I3_SSS_TARGET)))
+                                               seq_printf(s , "[BLOCKS s0i3]");
+               }
+
+               seq_printf(s, "\n");
+       }
+       seq_printf(s, "Wake Counters:\n");
+       for (lss = 0; lss < MRST_NUM_LSS; ++lss)
+               seq_printf(s, "LSS%d %d\n", lss, wake_counters[lss]);
+
+       seq_printf(s, "Interrupt Counters:\n");
+       seq_printf(s,
+               "INT_SPURIOUS \t%8u\n" "INT_CMD_DONE \t%8u\n"
+               "INT_CMD_ERR  \t%8u\n" "INT_WAKE_RX  \t%8u\n"
+               "INT_SS_ERROR \t%8u\n" "INT_S0IX_MISS\t%8u\n"
+               "INT_NO_ACKC6 \t%8u\n" "INT_INVALID  \t%8u\n",
+               pmu_irq_stats[INT_SPURIOUS], pmu_irq_stats[INT_CMD_DONE],
+               pmu_irq_stats[INT_CMD_ERR], pmu_irq_stats[INT_WAKE_RX],
+               pmu_irq_stats[INT_SS_ERROR], pmu_irq_stats[INT_S0IX_MISS],
+               pmu_irq_stats[INT_NO_ACKC6], pmu_irq_stats[INT_INVALID]);
+
+       seq_printf(s, "mrst_pmu_wait_ready_calls          %8d\n",
+                       pmu_wait_ready_calls);
+       seq_printf(s, "mrst_pmu_wait_ready_udelays        %8d\n",
+                       pmu_wait_ready_udelays);
+       seq_printf(s, "mrst_pmu_wait_ready_udelays_max    %8d\n",
+                       pmu_wait_ready_udelays_max);
+       seq_printf(s, "mrst_pmu_wait_done_calls           %8d\n",
+                       pmu_wait_done_calls);
+       seq_printf(s, "mrst_pmu_wait_done_udelays         %8d\n",
+                       pmu_wait_done_udelays);
+       seq_printf(s, "mrst_pmu_wait_done_udelays_max     %8d\n",
+                       pmu_wait_done_udelays_max);
+       seq_printf(s, "mrst_pmu_set_power_state_entry     %8d\n",
+                       pmu_set_power_state_entry);
+       seq_printf(s, "mrst_pmu_set_power_state_send_cmd  %8d\n",
+                       pmu_set_power_state_send_cmd);
+       seq_printf(s, "SCU busy: %d\n", pmu_read_busy_status());
+
+       return 0;
+}
+
+static int debug_mrst_pmu_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, debug_mrst_pmu_show, NULL);
+}
+
+static const struct file_operations devices_state_operations = {
+       .open           = debug_mrst_pmu_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+#endif /* DEBUG_FS */
+
+/*
+ * Validate SCU PCI shim PCI vendor capability byte
+ * against LSS hard-coded in mrst_devs[] above.
+ * DEBUG only.
+ */
+static void pmu_scu_firmware_debug(void)
+{
+       struct pci_dev *pdev = NULL;
+
+       for_each_pci_dev(pdev) {
+               struct mrst_device *mrst_dev;
+               u8 pci_config_lss;
+               int pos;
+
+               mrst_dev = pci_id_2_mrst_dev(pdev->device);
+               if (unlikely(!mrst_dev)) {
+                       printk(KERN_ERR FW_BUG "pmu: Unknown "
+                               "PCI device 0x%04X\n", pdev->device);
+                       continue;
+               }
+
+               if (mrst_dev->lss == 0)
+                       continue;        /* no LSS in our table */
+
+               pos = pci_find_capability(pdev, PCI_CAP_ID_VNDR);
+               if (!pos != 0) {
+                       printk(KERN_ERR FW_BUG "pmu: 0x%04X "
+                               "missing PCI Vendor Capability\n",
+                               pdev->device);
+                       continue;
+               }
+               pci_read_config_byte(pdev, pos + 4, &pci_config_lss);
+               if (!(pci_config_lss & PCI_VENDOR_CAP_LOG_SS_MASK)) {
+                       printk(KERN_ERR FW_BUG "pmu: 0x%04X "
+                               "invalid PCI Vendor Capability 0x%x "
+                               " expected LSS 0x%X\n",
+                               pdev->device, pci_config_lss, mrst_dev->lss);
+                       continue;
+               }
+               pci_config_lss &= PCI_VENDOR_CAP_LOG_ID_MASK;
+
+               if (mrst_dev->lss == pci_config_lss)
+                       continue;
+
+               printk(KERN_ERR FW_BUG "pmu: 0x%04X LSS = %d, expected %d\n",
+                       pdev->device, pci_config_lss, mrst_dev->lss);
+       }
+}
+
+/**
+ * pmu_probe
+ */
+static int __devinit pmu_probe(struct pci_dev *pdev,
+                                  const struct pci_device_id *pci_id)
+{
+       int ret;
+       struct mrst_pmu_reg *pmu;
+
+       /* Init the device */
+       ret = pci_enable_device(pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "Unable to Enable PCI device\n");
+               return ret;
+       }
+
+       ret = pci_request_regions(pdev, MRST_PMU_DRV_NAME);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting\n");
+               goto out_err1;
+       }
+
+       /* Map the memory of PMU reg base */
+       pmu = pci_iomap(pdev, 0, 0);
+       if (!pmu) {
+               dev_err(&pdev->dev, "Unable to map the PMU address space\n");
+               ret = -ENOMEM;
+               goto out_err2;
+       }
+
+#ifdef CONFIG_DEBUG_FS
+       /* /sys/kernel/debug/mrst_pmu */
+       (void) debugfs_create_file("mrst_pmu", S_IFREG | S_IRUGO,
+                               NULL, NULL, &devices_state_operations);
+#endif
+       pmu_reg = pmu;  /* success */
+
+       if (request_irq(pdev->irq, pmu_irq, 0, MRST_PMU_DRV_NAME, NULL)) {
+               dev_err(&pdev->dev, "Registering isr has failed\n");
+               ret = -1;
+               goto out_err3;
+       }
+
+       pmu_scu_firmware_debug();
+
+       pmu_write_wkc(S0I3_WAKE_SOURCES);       /* Enable S0i3 wakeup sources */
+
+       pmu_wait_ready();
+
+       pmu_write_ssc(D0I1_ACG_SSS_TARGET);     /* Enable Auto-Clock_Gating */
+       pmu_write_cmd(0x201);
+
+       spin_lock_init(&mrst_pmu_power_state_lock);
+
+       /* Enable the hardware interrupt */
+       pmu_irq_enable();
+       return 0;
+
+out_err3:
+       free_irq(pdev->irq, NULL);
+       pci_iounmap(pdev, pmu_reg);
+       pmu_reg = NULL;
+out_err2:
+       pci_release_region(pdev, 0);
+out_err1:
+       pci_disable_device(pdev);
+       return ret;
+}
+
+static void __devexit pmu_remove(struct pci_dev *pdev)
+{
+       dev_err(&pdev->dev, "Mid PM pmu_remove called\n");
+
+       /* Freeing up the irq */
+       free_irq(pdev->irq, NULL);
+
+       pci_iounmap(pdev, pmu_reg);
+       pmu_reg = NULL;
+
+       /* disable the current PCI device */
+       pci_release_region(pdev, 0);
+       pci_disable_device(pdev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(pmu_pci_ids) = {
+       { PCI_VDEVICE(INTEL, PCI_DEV_ID_MRST_PMU), 0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(pci, pmu_pci_ids);
+
+static struct pci_driver driver = {
+       .name = MRST_PMU_DRV_NAME,
+       .id_table = pmu_pci_ids,
+       .probe = pmu_probe,
+       .remove = __devexit_p(pmu_remove),
+};
+
+/**
+ * pmu_pci_register - register the PMU driver as PCI device
+ */
+static int __init pmu_pci_register(void)
+{
+       return pci_register_driver(&driver);
+}
+
+/* Register and probe via fs_initcall() to preceed device_initcall() */
+fs_initcall(pmu_pci_register);
+
+static void __exit mid_pci_cleanup(void)
+{
+       pci_unregister_driver(&driver);
+}
+
+static int ia_major;
+static int ia_minor;
+
+static int pmu_sfi_parse_oem(struct sfi_table_header *table)
+{
+       struct sfi_table_simple *sb;
+
+       sb = (struct sfi_table_simple *)table;
+       ia_major = (sb->pentry[1] >> 0) & 0xFFFF;
+       ia_minor = (sb->pentry[1] >> 16) & 0xFFFF;
+       printk(KERN_INFO "mrst_pmu: IA FW version v%x.%x\n",
+               ia_major, ia_minor);
+
+       return 0;
+}
+
+static int __init scu_fw_check(void)
+{
+       int ret;
+       u32 fw_version;
+
+       if (!pmu_reg)
+               return 0;       /* this driver didn't probe-out */
+
+       sfi_table_parse("OEMB", NULL, NULL, pmu_sfi_parse_oem);
+
+       if (ia_major < 0x6005 || ia_minor < 0x1525) {
+               WARN(1, "mrst_pmu: IA FW version too old\n");
+               return -1;
+       }
+
+       ret = intel_scu_ipc_command(IPCMSG_FW_REVISION, 0, NULL, 0,
+                                       &fw_version, 1);
+
+       if (ret) {
+               WARN(1, "mrst_pmu: IPC FW version? %d\n", ret);
+       } else {
+               int scu_major = (fw_version >> 8) & 0xFF;
+               int scu_minor = (fw_version >> 0) & 0xFF;
+
+               printk(KERN_INFO "mrst_pmu: firmware v%x\n", fw_version);
+
+               if ((scu_major >= 0xC0) && (scu_minor >= 0x49)) {
+                       printk(KERN_INFO "mrst_pmu: enabling S0i3\n");
+                       mrst_pmu_s0i3_enable = true;
+               } else {
+                       WARN(1, "mrst_pmu: S0i3 disabled, old firmware %X.%X",
+                                       scu_major, scu_minor);
+               }
+       }
+       return 0;
+}
+late_initcall(scu_fw_check);
+module_exit(mid_pci_cleanup);
diff --git a/arch/x86/platform/mrst/pmu.h b/arch/x86/platform/mrst/pmu.h
new file mode 100644 (file)
index 0000000..bfbfe64
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * mrst/pmu.h - private definitions for MRST Power Management Unit mrst/pmu.c
+ *
+ * Copyright (c) 2011, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _MRST_PMU_H_
+#define _MRST_PMU_H_
+
+#define PCI_DEV_ID_MRST_PMU            0x0810
+#define MRST_PMU_DRV_NAME              "mrst_pmu"
+#define        PCI_SUB_CLASS_MASK              0xFF00
+
+#define        PCI_VENDOR_CAP_LOG_ID_MASK      0x7F
+#define PCI_VENDOR_CAP_LOG_SS_MASK     0x80
+
+#define SUB_SYS_ALL_D0I1       0x01155555
+#define S0I3_WAKE_SOURCES      0x00001FFF
+
+#define PM_S0I3_COMMAND                                        \
+       ((0 << 31) |    /* Reserved */                  \
+       (0 << 30) |     /* Core must be idle */         \
+       (0xc2 << 22) |  /* ACK C6 trigger */            \
+       (3 << 19) |     /* Trigger on DMI message */    \
+       (3 << 16) |     /* Enter S0i3 */                \
+       (0 << 13) |     /* Numeric mode ID (sw) */      \
+       (3 << 9) |      /* Trigger mode */              \
+       (0 << 8) |      /* Do not interrupt */          \
+       (1 << 0))       /* Set configuration */
+
+#define        LSS_DMI         0
+#define        LSS_SD_HC0      1
+#define        LSS_SD_HC1      2
+#define        LSS_NAND        3
+#define        LSS_IMAGING     4
+#define        LSS_SECURITY    5
+#define        LSS_DISPLAY     6
+#define        LSS_USB_HC      7
+#define        LSS_USB_OTG     8
+#define        LSS_AUDIO       9
+#define        LSS_AUDIO_LPE   9
+#define        LSS_AUDIO_SSP   9
+#define        LSS_I2C0        10
+#define        LSS_I2C1        10
+#define        LSS_I2C2        10
+#define        LSS_KBD         10
+#define        LSS_SPI0        10
+#define        LSS_SPI1        10
+#define        LSS_SPI2        10
+#define        LSS_GPIO        10
+#define        LSS_SRAM        11      /* used by SCU, do not touch */
+#define        LSS_SD_HC2      12
+/* LSS hardware bits 15,14,13 are hardwired to 0, thus unusable */
+#define MRST_NUM_LSS   13
+
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+#define        SSMSK(mask, lss) ((mask) << ((lss) * 2))
+#define        D0      0
+#define        D0i1    1
+#define        D0i2    2
+#define        D0i3    3
+
+#define S0I3_SSS_TARGET        (               \
+       SSMSK(D0i1, LSS_DMI) |          \
+       SSMSK(D0i3, LSS_SD_HC0) |       \
+       SSMSK(D0i3, LSS_SD_HC1) |       \
+       SSMSK(D0i3, LSS_NAND) |         \
+       SSMSK(D0i3, LSS_SD_HC2) |       \
+       SSMSK(D0i3, LSS_IMAGING) |      \
+       SSMSK(D0i3, LSS_SECURITY) |     \
+       SSMSK(D0i3, LSS_DISPLAY) |      \
+       SSMSK(D0i3, LSS_USB_HC) |       \
+       SSMSK(D0i3, LSS_USB_OTG) |      \
+       SSMSK(D0i3, LSS_AUDIO) |        \
+       SSMSK(D0i1, LSS_I2C0))
+
+/*
+ * D0i1 on Langwell is Autonomous Clock Gating (ACG).
+ * Enable ACG on every LSS except camera and audio
+ */
+#define D0I1_ACG_SSS_TARGET     \
+       (SUB_SYS_ALL_D0I1 & ~SSMSK(D0i1, LSS_IMAGING) & ~SSMSK(D0i1, LSS_AUDIO))
+
+enum cm_mode {
+       CM_NOP,                 /* ignore the config mode value */
+       CM_IMMEDIATE,
+       CM_DELAY,
+       CM_TRIGGER,
+       CM_INVALID
+};
+
+enum sys_state {
+       SYS_STATE_S0I0,
+       SYS_STATE_S0I1,
+       SYS_STATE_S0I2,
+       SYS_STATE_S0I3,
+       SYS_STATE_S3,
+       SYS_STATE_S5
+};
+
+#define SET_CFG_CMD    1
+
+enum int_status {
+       INT_SPURIOUS = 0,
+       INT_CMD_DONE = 1,
+       INT_CMD_ERR = 2,
+       INT_WAKE_RX = 3,
+       INT_SS_ERROR = 4,
+       INT_S0IX_MISS = 5,
+       INT_NO_ACKC6 = 6,
+       INT_INVALID = 7,
+};
+
+/* PMU register interface */
+static struct mrst_pmu_reg {
+       u32 pm_sts;             /* 0x00 */
+       u32 pm_cmd;             /* 0x04 */
+       u32 pm_ics;             /* 0x08 */
+       u32 _resv1;             /* 0x0C */
+       u32 pm_wkc[2];          /* 0x10 */
+       u32 pm_wks[2];          /* 0x18 */
+       u32 pm_ssc[4];          /* 0x20 */
+       u32 pm_sss[4];          /* 0x30 */
+       u32 pm_wssc[4];         /* 0x40 */
+       u32 pm_c3c4;            /* 0x50 */
+       u32 pm_c5c6;            /* 0x54 */
+       u32 pm_msi_disable;     /* 0x58 */
+} *pmu_reg;
+
+static inline u32 pmu_read_sts(void) { return readl(&pmu_reg->pm_sts); }
+static inline u32 pmu_read_ics(void) { return readl(&pmu_reg->pm_ics); }
+static inline u32 pmu_read_wks(void) { return readl(&pmu_reg->pm_wks[0]); }
+static inline u32 pmu_read_sss(void) { return readl(&pmu_reg->pm_sss[0]); }
+
+static inline void pmu_write_cmd(u32 arg) { writel(arg, &pmu_reg->pm_cmd); }
+static inline void pmu_write_ics(u32 arg) { writel(arg, &pmu_reg->pm_ics); }
+static inline void pmu_write_wkc(u32 arg) { writel(arg, &pmu_reg->pm_wkc[0]); }
+static inline void pmu_write_ssc(u32 arg) { writel(arg, &pmu_reg->pm_ssc[0]); }
+static inline void pmu_write_wssc(u32 arg)
+                                       { writel(arg, &pmu_reg->pm_wssc[0]); }
+
+static inline void pmu_msi_enable(void) { writel(0, &pmu_reg->pm_msi_disable); }
+static inline u32 pmu_msi_is_disabled(void)
+                               { return readl(&pmu_reg->pm_msi_disable); }
+
+union pmu_pm_ics {
+       struct {
+               u32 cause:8;
+               u32 enable:1;
+               u32 pending:1;
+               u32 reserved:22;
+       } bits;
+       u32 value;
+};
+
+static inline void pmu_irq_enable(void)
+{
+       union pmu_pm_ics pmu_ics;
+
+       pmu_ics.value = pmu_read_ics();
+       pmu_ics.bits.enable = 1;
+       pmu_write_ics(pmu_ics.value);
+}
+
+union pmu_pm_status {
+       struct {
+               u32 pmu_rev:8;
+               u32 pmu_busy:1;
+               u32 mode_id:4;
+               u32 Reserved:19;
+       } pmu_status_parts;
+       u32 pmu_status_value;
+};
+
+static inline int pmu_read_busy_status(void)
+{
+       union pmu_pm_status result;
+
+       result.pmu_status_value = pmu_read_sts();
+
+       return result.pmu_status_parts.pmu_busy;
+}
+
+/* pmu set config parameters */
+struct cfg_delay_param_t {
+       u32 cmd:8;
+       u32 ioc:1;
+       u32 cfg_mode:4;
+       u32 mode_id:3;
+       u32 sys_state:3;
+       u32 cfg_delay:8;
+       u32 rsvd:5;
+};
+
+struct cfg_trig_param_t {
+       u32 cmd:8;
+       u32 ioc:1;
+       u32 cfg_mode:4;
+       u32 mode_id:3;
+       u32 sys_state:3;
+       u32 cfg_trig_type:3;
+       u32 cfg_trig_val:8;
+       u32 cmbi:1;
+       u32 rsvd1:1;
+};
+
+union pmu_pm_set_cfg_cmd_t {
+       union {
+               struct cfg_delay_param_t d_param;
+               struct cfg_trig_param_t t_param;
+       } pmu2_params;
+       u32 pmu_pm_set_cfg_cmd_value;
+};
+
+#ifdef FUTURE_PATCH
+extern int mrst_s0i3_entry(u32 regval, u32 *regaddr);
+#else
+static inline int mrst_s0i3_entry(u32 regval, u32 *regaddr) { return -1; }
+#endif
+#endif
index 8b9940e..7cce722 100644 (file)
@@ -161,13 +161,13 @@ restart:
        if (inbuf && inlen) {
                /* write data to EC */
                for (i = 0; i < inlen; i++) {
+                       pr_devel("olpc-ec:  sending cmd arg 0x%x\n", inbuf[i]);
+                       outb(inbuf[i], 0x68);
                        if (wait_on_ibf(0x6c, 0)) {
                                printk(KERN_ERR "olpc-ec:  timeout waiting for"
                                                " EC accept data!\n");
                                goto err;
                        }
-                       pr_devel("olpc-ec:  sending cmd arg 0x%x\n", inbuf[i]);
-                       outb(inbuf[i], 0x68);
                }
        }
        if (outbuf && outlen) {
index 1b979c1..01f5e3b 100644 (file)
@@ -9,6 +9,7 @@ __PAGE_ALIGNED_DATA
 vdso_start:
        .incbin "arch/x86/vdso/vdso.so"
 vdso_end:
+       .align PAGE_SIZE /* extra data here leaks to userspace. */
 
 .previous
 
index e2800af..e354bce 100644 (file)
@@ -43,7 +43,7 @@ __kernel_vsyscall:
        .space 7,0x90
 
        /* 14: System call restart point is here! (SYSENTER_RETURN-2) */
-       jmp .Lenter_kernel
+       int $0x80
        /* 16: System call normal return point is here! */
 VDSO32_SYSENTER_RETURN:        /* Symbol used by sysenter.c via vdso32-syms.h */
        pop %ebp
index ccf73b2..add2c2d 100644 (file)
@@ -13,7 +13,9 @@ CFLAGS_mmu.o                  := $(nostackp)
 obj-y          := enlighten.o setup.o multicalls.o mmu.o irq.o \
                        time.o xen-asm.o xen-asm_$(BITS).o \
                        grant-table.o suspend.o platform-pci-unplug.o \
-                       p2m.o trace.o
+                       p2m.o
+
+obj-$(CONFIG_EVENT_TRACING) += trace.o
 
 obj-$(CONFIG_SMP)              += smp.o
 obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o
index 974a528..2d69617 100644 (file)
@@ -77,8 +77,8 @@ EXPORT_SYMBOL_GPL(xen_domain_type);
 
 unsigned long *machine_to_phys_mapping = (void *)MACH2PHYS_VIRT_START;
 EXPORT_SYMBOL(machine_to_phys_mapping);
-unsigned int   machine_to_phys_order;
-EXPORT_SYMBOL(machine_to_phys_order);
+unsigned long  machine_to_phys_nr;
+EXPORT_SYMBOL(machine_to_phys_nr);
 
 struct start_info *xen_start_info;
 EXPORT_SYMBOL_GPL(xen_start_info);
@@ -951,6 +951,10 @@ static const struct pv_info xen_info __initconst = {
        .paravirt_enabled = 1,
        .shared_kernel_pmd = 0,
 
+#ifdef CONFIG_X86_64
+       .extra_user_64bit_cs = FLAT_USER_CS64,
+#endif
+
        .name = "Xen",
 };
 
index f987bde..20a6142 100644 (file)
@@ -1713,15 +1713,19 @@ static void __init xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn)
 void __init xen_setup_machphys_mapping(void)
 {
        struct xen_machphys_mapping mapping;
-       unsigned long machine_to_phys_nr_ents;
 
        if (HYPERVISOR_memory_op(XENMEM_machphys_mapping, &mapping) == 0) {
                machine_to_phys_mapping = (unsigned long *)mapping.v_start;
-               machine_to_phys_nr_ents = mapping.max_mfn + 1;
+               machine_to_phys_nr = mapping.max_mfn + 1;
        } else {
-               machine_to_phys_nr_ents = MACH2PHYS_NR_ENTRIES;
+               machine_to_phys_nr = MACH2PHYS_NR_ENTRIES;
        }
-       machine_to_phys_order = fls(machine_to_phys_nr_ents - 1);
+#ifdef CONFIG_X86_32
+       if ((machine_to_phys_mapping + machine_to_phys_nr)
+           < machine_to_phys_mapping)
+               machine_to_phys_nr = (unsigned long *)NULL
+                                    - machine_to_phys_mapping;
+#endif
 }
 
 #ifdef CONFIG_X86_64
@@ -1916,6 +1920,7 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
 # endif
 #else
        case VSYSCALL_LAST_PAGE ... VSYSCALL_FIRST_PAGE:
+       case VVAR_PAGE:
 #endif
        case FIX_TEXT_POKE0:
        case FIX_TEXT_POKE1:
@@ -1956,7 +1961,8 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
 #ifdef CONFIG_X86_64
        /* Replicate changes to map the vsyscall page into the user
           pagetable vsyscall mapping. */
-       if (idx >= VSYSCALL_LAST_PAGE && idx <= VSYSCALL_FIRST_PAGE) {
+       if ((idx >= VSYSCALL_LAST_PAGE && idx <= VSYSCALL_FIRST_PAGE) ||
+           idx == VVAR_PAGE) {
                unsigned long vaddr = __fix_to_virt(idx);
                set_pte_vaddr_pud(level3_user_vsyscall, vaddr, pte);
        }
index 60aeeb5..df118a8 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/mm.h>
 #include <linux/pm.h>
 #include <linux/memblock.h>
+#include <linux/cpuidle.h>
 
 #include <asm/elf.h>
 #include <asm/vdso.h>
@@ -92,8 +93,6 @@ static unsigned long __init xen_release_chunk(phys_addr_t start_addr,
        if (end <= start)
                return 0;
 
-       printk(KERN_INFO "xen_release_chunk: looking at area pfn %lx-%lx: ",
-              start, end);
        for(pfn = start; pfn < end; pfn++) {
                unsigned long mfn = pfn_to_mfn(pfn);
 
@@ -106,14 +105,14 @@ static unsigned long __init xen_release_chunk(phys_addr_t start_addr,
 
                ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
                                           &reservation);
-               WARN(ret != 1, "Failed to release memory %lx-%lx err=%d\n",
-                    start, end, ret);
+               WARN(ret != 1, "Failed to release pfn %lx err=%d\n", pfn, ret);
                if (ret == 1) {
                        __set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
                        len++;
                }
        }
-       printk(KERN_CONT "%ld pages freed\n", len);
+       printk(KERN_INFO "Freeing  %lx-%lx pfn range: %lu pages freed\n",
+              start, end, len);
 
        return len;
 }
@@ -139,7 +138,7 @@ static unsigned long __init xen_return_unused_memory(unsigned long max_pfn,
        if (last_end < max_addr)
                released += xen_release_chunk(last_end, max_addr);
 
-       printk(KERN_INFO "released %ld pages of unused memory\n", released);
+       printk(KERN_INFO "released %lu pages of unused memory\n", released);
        return released;
 }
 
@@ -426,7 +425,7 @@ void __init xen_arch_setup(void)
 #ifdef CONFIG_X86_32
        boot_cpu_data.hlt_works_ok = 1;
 #endif
-       pm_idle = default_idle;
+       disable_cpuidle();
        boot_option_idle_override = IDLE_HALT;
 
        fiddle_vdso();
index b4533a8..e79dbb9 100644 (file)
@@ -521,8 +521,6 @@ static void __init xen_hvm_smp_prepare_cpus(unsigned int max_cpus)
        native_smp_prepare_cpus(max_cpus);
        WARN_ON(xen_smp_intr_init(0));
 
-       if (!xen_have_vector_callback)
-               return;
        xen_init_lock_cpu(0);
        xen_init_spinlocks();
 }
@@ -546,6 +544,8 @@ static void xen_hvm_cpu_die(unsigned int cpu)
 
 void __init xen_hvm_smp_init(void)
 {
+       if (!xen_have_vector_callback)
+               return;
        smp_ops.smp_prepare_cpus = xen_hvm_smp_prepare_cpus;
        smp_ops.smp_send_reschedule = xen_smp_send_reschedule;
        smp_ops.cpu_up = xen_hvm_cpu_up;
index 734beba..520022d 100644 (file)
@@ -1,4 +1,5 @@
 #include <linux/ftrace.h>
+#include <xen/interface/xen.h>
 
 #define N(x)   [__HYPERVISOR_##x] = "("#x")"
 static const char *xen_hypercall_names[] = {
index 60be1e0..e97934e 100644 (file)
@@ -65,6 +65,16 @@ config BLK_DEV_BSG
 
          If unsure, say Y.
 
+config BLK_DEV_BSGLIB
+       bool "Block layer SG support v4 helper lib"
+       default n
+       select BLK_DEV_BSG
+       help
+         Subsystems will normally enable this if needed. Users will not
+         normally need to manually enable this.
+
+         If unsure, say N.
+
 config BLK_DEV_INTEGRITY
        bool "Block layer data integrity support"
        ---help---
index 0fec4b3..514c6e4 100644 (file)
@@ -8,6 +8,7 @@ obj-$(CONFIG_BLOCK) := elevator.o blk-core.o blk-tag.o blk-sysfs.o \
                        blk-iopoll.o blk-lib.o ioctl.o genhd.o scsi_ioctl.o
 
 obj-$(CONFIG_BLK_DEV_BSG)      += bsg.o
+obj-$(CONFIG_BLK_DEV_BSGLIB)   += bsg-lib.o
 obj-$(CONFIG_BLK_CGROUP)       += blk-cgroup.o
 obj-$(CONFIG_BLK_DEV_THROTTLING)       += blk-throttle.o
 obj-$(CONFIG_IOSCHED_NOOP)     += noop-iosched.o
index b850bed..90e1ffd 100644 (file)
@@ -1368,8 +1368,10 @@ static bool should_fail_request(struct hd_struct *part, unsigned int bytes)
 
 static int __init fail_make_request_debugfs(void)
 {
-       return init_fault_attr_dentries(&fail_make_request,
-                                       "fail_make_request");
+       struct dentry *dir = fault_create_debugfs_attr("fail_make_request",
+                                               NULL, &fail_make_request);
+
+       return IS_ERR(dir) ? PTR_ERR(dir) : 0;
 }
 
 late_initcall(fail_make_request_debugfs);
@@ -1700,6 +1702,7 @@ EXPORT_SYMBOL_GPL(blk_rq_check_limits);
 int blk_insert_cloned_request(struct request_queue *q, struct request *rq)
 {
        unsigned long flags;
+       int where = ELEVATOR_INSERT_BACK;
 
        if (blk_rq_check_limits(q, rq))
                return -EIO;
@@ -1716,7 +1719,10 @@ int blk_insert_cloned_request(struct request_queue *q, struct request *rq)
         */
        BUG_ON(blk_queued_rq(rq));
 
-       add_acct_request(q, rq, ELEVATOR_INSERT_BACK);
+       if (rq->cmd_flags & (REQ_FLUSH|REQ_FUA))
+               where = ELEVATOR_INSERT_FLUSH;
+
+       add_acct_request(q, rq, where);
        spin_unlock_irqrestore(q->queue_lock, flags);
 
        return 0;
@@ -2273,7 +2279,7 @@ static bool blk_end_bidi_request(struct request *rq, int error,
  *     %false - we are done with this request
  *     %true  - still buffers pending for this request
  **/
-static bool __blk_end_bidi_request(struct request *rq, int error,
+bool __blk_end_bidi_request(struct request *rq, int error,
                                   unsigned int nr_bytes, unsigned int bidi_bytes)
 {
        if (blk_update_bidi_request(rq, error, nr_bytes, bidi_bytes))
index bb21e4c..491eb30 100644 (file)
@@ -95,11 +95,12 @@ static unsigned int blk_flush_policy(unsigned int fflags, struct request *rq)
 {
        unsigned int policy = 0;
 
+       if (blk_rq_sectors(rq))
+               policy |= REQ_FSEQ_DATA;
+
        if (fflags & REQ_FLUSH) {
                if (rq->cmd_flags & REQ_FLUSH)
                        policy |= REQ_FSEQ_PREFLUSH;
-               if (blk_rq_sectors(rq))
-                       policy |= REQ_FSEQ_DATA;
                if (!(fflags & REQ_FUA) && (rq->cmd_flags & REQ_FUA))
                        policy |= REQ_FSEQ_POSTFLUSH;
        }
@@ -122,7 +123,7 @@ static void blk_flush_restore_request(struct request *rq)
 
        /* make @rq a normal request */
        rq->cmd_flags &= ~REQ_FLUSH_SEQ;
-       rq->end_io = NULL;
+       rq->end_io = rq->flush.saved_end_io;
 }
 
 /**
@@ -300,9 +301,6 @@ void blk_insert_flush(struct request *rq)
        unsigned int fflags = q->flush_flags;   /* may change, cache */
        unsigned int policy = blk_flush_policy(fflags, rq);
 
-       BUG_ON(rq->end_io);
-       BUG_ON(!rq->bio || rq->bio != rq->biotail);
-
        /*
         * @policy now records what operations need to be done.  Adjust
         * REQ_FLUSH and FUA for the driver.
@@ -311,6 +309,19 @@ void blk_insert_flush(struct request *rq)
        if (!(fflags & REQ_FUA))
                rq->cmd_flags &= ~REQ_FUA;
 
+       /*
+        * An empty flush handed down from a stacking driver may
+        * translate into nothing if the underlying device does not
+        * advertise a write-back cache.  In this case, simply
+        * complete the request.
+        */
+       if (!policy) {
+               __blk_end_bidi_request(rq, 0, 0, 0);
+               return;
+       }
+
+       BUG_ON(!rq->bio || rq->bio != rq->biotail);
+
        /*
         * If there's data but flush is not necessary, the request can be
         * processed directly without going through flush machinery.  Queue
@@ -319,6 +330,7 @@ void blk_insert_flush(struct request *rq)
        if ((policy & REQ_FSEQ_DATA) &&
            !(policy & (REQ_FSEQ_PREFLUSH | REQ_FSEQ_POSTFLUSH))) {
                list_add_tail(&rq->queuelist, &q->queue_head);
+               blk_run_queue_async(q);
                return;
        }
 
@@ -329,6 +341,7 @@ void blk_insert_flush(struct request *rq)
        memset(&rq->flush, 0, sizeof(rq->flush));
        INIT_LIST_HEAD(&rq->flush.list);
        rq->cmd_flags |= REQ_FLUSH_SEQ;
+       rq->flush.saved_end_io = rq->end_io; /* Usually NULL */
        rq->end_io = flush_data_end_io;
 
        blk_flush_complete_seq(rq, REQ_FSEQ_ACTIONS & ~policy, 0);
index 475fab8..58340d0 100644 (file)
@@ -124,6 +124,14 @@ void __blk_complete_request(struct request *req)
        } else
                ccpu = cpu;
 
+       /*
+        * If current CPU and requested CPU are in the same group, running
+        * softirq in current CPU. One might concern this is just like
+        * QUEUE_FLAG_SAME_FORCE, but actually not. blk_complete_request() is
+        * running in interrupt handler, and currently I/O controller doesn't
+        * support multiple interrupts, so current CPU is unique actually. This
+        * avoids IPI sending from current CPU to the first CPU of a group.
+        */
        if (ccpu == cpu || ccpu == group_cpu) {
                struct list_head *list;
 do_local:
index f6a7941..a19f58c 100644 (file)
@@ -746,7 +746,7 @@ static bool tg_may_dispatch(struct throtl_data *td, struct throtl_grp *tg,
 static void throtl_charge_bio(struct throtl_grp *tg, struct bio *bio)
 {
        bool rw = bio_data_dir(bio);
-       bool sync = bio->bi_rw & REQ_SYNC;
+       bool sync = rw_is_sync(bio->bi_rw);
 
        /* Charge the bio to the group */
        tg->bytes_disp[rw] += bio->bi_size;
@@ -1150,7 +1150,7 @@ int blk_throtl_bio(struct request_queue *q, struct bio **biop)
 
                if (tg_no_rule_group(tg, rw)) {
                        blkiocg_update_dispatch_stats(&tg->blkg, bio->bi_size,
-                                       rw, bio->bi_rw & REQ_SYNC);
+                                       rw, rw_is_sync(bio->bi_rw));
                        rcu_read_unlock();
                        return 0;
                }
index 4f0c06c..7803548 100644 (file)
@@ -28,7 +28,10 @@ int blk_should_fake_timeout(struct request_queue *q)
 
 static int __init fail_io_timeout_debugfs(void)
 {
-       return init_fault_attr_dentries(&fail_io_timeout, "fail_io_timeout");
+       struct dentry *dir = fault_create_debugfs_attr("fail_io_timeout",
+                                               NULL, &fail_io_timeout);
+
+       return IS_ERR(dir) ? PTR_ERR(dir) : 0;
 }
 
 late_initcall(fail_io_timeout_debugfs);
index d658628..20b900a 100644 (file)
@@ -17,6 +17,8 @@ int blk_rq_append_bio(struct request_queue *q, struct request *rq,
                      struct bio *bio);
 void blk_dequeue_request(struct request *rq);
 void __blk_queue_free_tags(struct request_queue *q);
+bool __blk_end_bidi_request(struct request *rq, int error,
+                           unsigned int nr_bytes, unsigned int bidi_bytes);
 
 void blk_rq_timed_out_timer(unsigned long data);
 void blk_delete_timer(struct request *);
diff --git a/block/bsg-lib.c b/block/bsg-lib.c
new file mode 100644 (file)
index 0000000..6690e6e
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ *  BSG helper library
+ *
+ *  Copyright (C) 2008   James Smart, Emulex Corporation
+ *  Copyright (C) 2011   Red Hat, Inc.  All rights reserved.
+ *  Copyright (C) 2011   Mike Christie
+ *
+ *  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/slab.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/scatterlist.h>
+#include <linux/bsg-lib.h>
+#include <linux/module.h>
+#include <scsi/scsi_cmnd.h>
+
+/**
+ * bsg_destroy_job - routine to teardown/delete a bsg job
+ * @job: bsg_job that is to be torn down
+ */
+static void bsg_destroy_job(struct bsg_job *job)
+{
+       put_device(job->dev);   /* release reference for the request */
+
+       kfree(job->request_payload.sg_list);
+       kfree(job->reply_payload.sg_list);
+       kfree(job);
+}
+
+/**
+ * bsg_job_done - completion routine for bsg requests
+ * @job: bsg_job that is complete
+ * @result: job reply result
+ * @reply_payload_rcv_len: length of payload recvd
+ *
+ * The LLD should call this when the bsg job has completed.
+ */
+void bsg_job_done(struct bsg_job *job, int result,
+                 unsigned int reply_payload_rcv_len)
+{
+       struct request *req = job->req;
+       struct request *rsp = req->next_rq;
+       int err;
+
+       err = job->req->errors = result;
+       if (err < 0)
+               /* we're only returning the result field in the reply */
+               job->req->sense_len = sizeof(u32);
+       else
+               job->req->sense_len = job->reply_len;
+       /* we assume all request payload was transferred, residual == 0 */
+       req->resid_len = 0;
+
+       if (rsp) {
+               WARN_ON(reply_payload_rcv_len > rsp->resid_len);
+
+               /* set reply (bidi) residual */
+               rsp->resid_len -= min(reply_payload_rcv_len, rsp->resid_len);
+       }
+       blk_complete_request(req);
+}
+EXPORT_SYMBOL_GPL(bsg_job_done);
+
+/**
+ * bsg_softirq_done - softirq done routine for destroying the bsg requests
+ * @rq: BSG request that holds the job to be destroyed
+ */
+static void bsg_softirq_done(struct request *rq)
+{
+       struct bsg_job *job = rq->special;
+
+       blk_end_request_all(rq, rq->errors);
+       bsg_destroy_job(job);
+}
+
+static int bsg_map_buffer(struct bsg_buffer *buf, struct request *req)
+{
+       size_t sz = (sizeof(struct scatterlist) * req->nr_phys_segments);
+
+       BUG_ON(!req->nr_phys_segments);
+
+       buf->sg_list = kzalloc(sz, GFP_KERNEL);
+       if (!buf->sg_list)
+               return -ENOMEM;
+       sg_init_table(buf->sg_list, req->nr_phys_segments);
+       buf->sg_cnt = blk_rq_map_sg(req->q, req, buf->sg_list);
+       buf->payload_len = blk_rq_bytes(req);
+       return 0;
+}
+
+/**
+ * bsg_create_job - create the bsg_job structure for the bsg request
+ * @dev: device that is being sent the bsg request
+ * @req: BSG request that needs a job structure
+ */
+static int bsg_create_job(struct device *dev, struct request *req)
+{
+       struct request *rsp = req->next_rq;
+       struct request_queue *q = req->q;
+       struct bsg_job *job;
+       int ret;
+
+       BUG_ON(req->special);
+
+       job = kzalloc(sizeof(struct bsg_job) + q->bsg_job_size, GFP_KERNEL);
+       if (!job)
+               return -ENOMEM;
+
+       req->special = job;
+       job->req = req;
+       if (q->bsg_job_size)
+               job->dd_data = (void *)&job[1];
+       job->request = req->cmd;
+       job->request_len = req->cmd_len;
+       job->reply = req->sense;
+       job->reply_len = SCSI_SENSE_BUFFERSIZE; /* Size of sense buffer
+                                                * allocated */
+       if (req->bio) {
+               ret = bsg_map_buffer(&job->request_payload, req);
+               if (ret)
+                       goto failjob_rls_job;
+       }
+       if (rsp && rsp->bio) {
+               ret = bsg_map_buffer(&job->reply_payload, rsp);
+               if (ret)
+                       goto failjob_rls_rqst_payload;
+       }
+       job->dev = dev;
+       /* take a reference for the request */
+       get_device(job->dev);
+       return 0;
+
+failjob_rls_rqst_payload:
+       kfree(job->request_payload.sg_list);
+failjob_rls_job:
+       kfree(job);
+       return -ENOMEM;
+}
+
+/*
+ * bsg_goose_queue - restart queue in case it was stopped
+ * @q: request q to be restarted
+ */
+void bsg_goose_queue(struct request_queue *q)
+{
+       if (!q)
+               return;
+
+       blk_run_queue_async(q);
+}
+EXPORT_SYMBOL_GPL(bsg_goose_queue);
+
+/**
+ * bsg_request_fn - generic handler for bsg requests
+ * @q: request queue to manage
+ *
+ * On error the create_bsg_job function should return a -Exyz error value
+ * that will be set to the req->errors.
+ *
+ * Drivers/subsys should pass this to the queue init function.
+ */
+void bsg_request_fn(struct request_queue *q)
+{
+       struct device *dev = q->queuedata;
+       struct request *req;
+       struct bsg_job *job;
+       int ret;
+
+       if (!get_device(dev))
+               return;
+
+       while (1) {
+               req = blk_fetch_request(q);
+               if (!req)
+                       break;
+               spin_unlock_irq(q->queue_lock);
+
+               ret = bsg_create_job(dev, req);
+               if (ret) {
+                       req->errors = ret;
+                       blk_end_request_all(req, ret);
+                       spin_lock_irq(q->queue_lock);
+                       continue;
+               }
+
+               job = req->special;
+               ret = q->bsg_job_fn(job);
+               spin_lock_irq(q->queue_lock);
+               if (ret)
+                       break;
+       }
+
+       spin_unlock_irq(q->queue_lock);
+       put_device(dev);
+       spin_lock_irq(q->queue_lock);
+}
+EXPORT_SYMBOL_GPL(bsg_request_fn);
+
+/**
+ * bsg_setup_queue - Create and add the bsg hooks so we can receive requests
+ * @dev: device to attach bsg device to
+ * @q: request queue setup by caller
+ * @name: device to give bsg device
+ * @job_fn: bsg job handler
+ * @dd_job_size: size of LLD data needed for each job
+ *
+ * The caller should have setup the reuqest queue with bsg_request_fn
+ * as the request_fn.
+ */
+int bsg_setup_queue(struct device *dev, struct request_queue *q,
+                   char *name, bsg_job_fn *job_fn, int dd_job_size)
+{
+       int ret;
+
+       q->queuedata = dev;
+       q->bsg_job_size = dd_job_size;
+       q->bsg_job_fn = job_fn;
+       queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q);
+       blk_queue_softirq_done(q, bsg_softirq_done);
+       blk_queue_rq_timeout(q, BLK_DEFAULT_SG_TIMEOUT);
+
+       ret = bsg_register_queue(q, dev, name, NULL);
+       if (ret) {
+               printk(KERN_ERR "%s: bsg interface failed to "
+                      "initialize - register queue\n", dev->kobj.name);
+               return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(bsg_setup_queue);
+
+/**
+ * bsg_remove_queue - Deletes the bsg dev from the q
+ * @q: the request_queue that is to be torn down.
+ *
+ * Notes:
+ *   Before unregistering the queue empty any requests that are blocked
+ */
+void bsg_remove_queue(struct request_queue *q)
+{
+       struct request *req; /* block request */
+       int counts; /* totals for request_list count and starved */
+
+       if (!q)
+               return;
+
+       /* Stop taking in new requests */
+       spin_lock_irq(q->queue_lock);
+       blk_stop_queue(q);
+
+       /* drain all requests in the queue */
+       while (1) {
+               /* need the lock to fetch a request
+                * this may fetch the same reqeust as the previous pass
+                */
+               req = blk_fetch_request(q);
+               /* save requests in use and starved */
+               counts = q->rq.count[0] + q->rq.count[1] +
+                        q->rq.starved[0] + q->rq.starved[1];
+               spin_unlock_irq(q->queue_lock);
+               /* any requests still outstanding? */
+               if (counts == 0)
+                       break;
+
+               /* This may be the same req as the previous iteration,
+                * always send the blk_end_request_all after a prefetch.
+                * It is not okay to not end the request because the
+                * prefetch started the request.
+                */
+               if (req) {
+                       /* return -ENXIO to indicate that this queue is
+                        * going away
+                        */
+                       req->errors = -ENXIO;
+                       blk_end_request_all(req, -ENXIO);
+               }
+
+               msleep(200); /* allow bsg to possibly finish */
+               spin_lock_irq(q->queue_lock);
+       }
+       bsg_unregister_queue(q);
+}
+EXPORT_SYMBOL_GPL(bsg_remove_queue);
index 1f96ad6..a33bd43 100644 (file)
@@ -130,6 +130,8 @@ struct cfq_queue {
        unsigned long slice_end;
        long slice_resid;
 
+       /* pending metadata requests */
+       int meta_pending;
        /* number of requests that are on the dispatch list or inside driver */
        int dispatched;
 
@@ -682,6 +684,9 @@ cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2,
        if (rq_is_sync(rq1) != rq_is_sync(rq2))
                return rq_is_sync(rq1) ? rq1 : rq2;
 
+       if ((rq1->cmd_flags ^ rq2->cmd_flags) & REQ_META)
+               return rq1->cmd_flags & REQ_META ? rq1 : rq2;
+
        s1 = blk_rq_pos(rq1);
        s2 = blk_rq_pos(rq2);
 
@@ -1209,6 +1214,9 @@ static void cfq_destroy_cfqg(struct cfq_data *cfqd, struct cfq_group *cfqg)
 
        hlist_del_init(&cfqg->cfqd_node);
 
+       BUG_ON(cfqd->nr_blkcg_linked_grps <= 0);
+       cfqd->nr_blkcg_linked_grps--;
+
        /*
         * Put the reference taken at the time of creation so that when all
         * queues are gone, group can be destroyed.
@@ -1604,6 +1612,10 @@ static void cfq_remove_request(struct request *rq)
        cfqq->cfqd->rq_queued--;
        cfq_blkiocg_update_io_remove_stats(&(RQ_CFQG(rq))->blkg,
                                        rq_data_dir(rq), rq_is_sync(rq));
+       if (rq->cmd_flags & REQ_META) {
+               WARN_ON(!cfqq->meta_pending);
+               cfqq->meta_pending--;
+       }
 }
 
 static int cfq_merge(struct request_queue *q, struct request **req,
@@ -3356,6 +3368,13 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
            RB_EMPTY_ROOT(&cfqq->sort_list))
                return true;
 
+       /*
+        * So both queues are sync. Let the new request get disk time if
+        * it's a metadata request and the current queue is doing regular IO.
+        */
+       if ((rq->cmd_flags & REQ_META) && !cfqq->meta_pending)
+               return true;
+
        /*
         * Allow an RT request to pre-empt an ongoing non-RT cfqq timeslice.
         */
@@ -3420,6 +3439,8 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
        struct cfq_io_context *cic = RQ_CIC(rq);
 
        cfqd->rq_queued++;
+       if (rq->cmd_flags & REQ_META)
+               cfqq->meta_pending++;
 
        cfq_update_io_thinktime(cfqd, cfqq, cic);
        cfq_update_io_seektime(cfqd, cfqq, rq);
index 5cb51c5..e2f6790 100644 (file)
@@ -1146,17 +1146,17 @@ static int diskstats_show(struct seq_file *seqf, void *v)
                cpu = part_stat_lock();
                part_round_stats(cpu, hd);
                part_stat_unlock();
-               seq_printf(seqf, "%4d %7d %s %lu %lu %llu "
-                          "%u %lu %lu %llu %u %u %u %u\n",
+               seq_printf(seqf, "%4d %7d %s %lu %lu %lu "
+                          "%u %lu %lu %lu %u %u %u %u\n",
                           MAJOR(part_devt(hd)), MINOR(part_devt(hd)),
                           disk_name(gp, hd->partno, buf),
                           part_stat_read(hd, ios[READ]),
                           part_stat_read(hd, merges[READ]),
-                          (unsigned long long)part_stat_read(hd, sectors[READ]),
+                          part_stat_read(hd, sectors[READ]),
                           jiffies_to_msecs(part_stat_read(hd, ticks[READ])),
                           part_stat_read(hd, ios[WRITE]),
                           part_stat_read(hd, merges[WRITE]),
-                          (unsigned long long)part_stat_read(hd, sectors[WRITE]),
+                          part_stat_read(hd, sectors[WRITE]),
                           jiffies_to_msecs(part_stat_read(hd, ticks[WRITE])),
                           part_in_flight(hd),
                           jiffies_to_msecs(part_stat_read(hd, io_ticks)),
index 30efc7d..7febeaa 100644 (file)
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/types.h>
+#include <linux/cryptohash.h>
 #include <asm/byteorder.h>
 
-#define F1(x, y, z)    (z ^ (x & (y ^ z)))
-#define F2(x, y, z)    F1(z, x, y)
-#define F3(x, y, z)    (x ^ y ^ z)
-#define F4(x, y, z)    (y ^ (x | ~z))
-
-#define MD5STEP(f, w, x, y, z, in, s) \
-       (w += f(x, y, z) + in, w = (w<<s | w>>(32-s)) + x)
-
-static void md5_transform(u32 *hash, u32 const *in)
-{
-       u32 a, b, c, d;
-
-       a = hash[0];
-       b = hash[1];
-       c = hash[2];
-       d = hash[3];
-
-       MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
-       MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
-       MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
-       MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
-       MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
-       MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
-       MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
-       MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
-       MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
-       MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
-       MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
-       MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
-       MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
-       MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
-       MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
-       MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
-
-       MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
-       MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
-       MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
-       MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
-       MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
-       MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
-       MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
-       MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
-       MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
-       MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
-       MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
-       MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
-       MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
-       MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
-       MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
-       MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
-
-       MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
-       MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
-       MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
-       MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
-       MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
-       MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
-       MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
-       MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
-       MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
-       MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
-       MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
-       MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
-       MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
-       MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
-       MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
-       MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
-
-       MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
-       MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
-       MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
-       MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
-       MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
-       MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
-       MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
-       MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
-       MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
-       MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
-       MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
-       MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
-       MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
-       MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
-       MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
-       MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
-
-       hash[0] += a;
-       hash[1] += b;
-       hash[2] += c;
-       hash[3] += d;
-}
-
 /* XXX: this stuff can be optimized */
 static inline void le32_to_cpu_array(u32 *buf, unsigned int words)
 {
index 73863d8..76dc02f 100644 (file)
@@ -126,6 +126,12 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_copy_dsdt_locally, FALSE);
  */
 u8 ACPI_INIT_GLOBAL(acpi_gbl_truncate_io_addresses, FALSE);
 
+/*
+ * Disable runtime checking and repair of values returned by control methods.
+ * Use only if the repair is causing a problem on a particular machine.
+ */
+u8 ACPI_INIT_GLOBAL(acpi_gbl_disable_auto_repair, FALSE);
+
 /* acpi_gbl_FADT is a local copy of the FADT, converted to a common format. */
 
 struct acpi_table_fadt acpi_gbl_FADT;
index c7f743c..5552125 100644 (file)
@@ -357,6 +357,7 @@ struct acpi_predefined_data {
        char *pathname;
        const union acpi_predefined_info *predefined;
        union acpi_operand_object *parent_package;
+       struct acpi_namespace_node *node;
        u32 flags;
        u8 node_flags;
 };
index 94e73c9..c445cca 100644 (file)
@@ -468,6 +468,7 @@ static const union acpi_predefined_info predefined_names[] =
        {{"_SWS", 0, ACPI_RTYPE_INTEGER}},
        {{"_TC1", 0, ACPI_RTYPE_INTEGER}},
        {{"_TC2", 0, ACPI_RTYPE_INTEGER}},
+       {{"_TDL", 0, ACPI_RTYPE_INTEGER}},
        {{"_TIP", 1, ACPI_RTYPE_INTEGER}},
        {{"_TIV", 1, ACPI_RTYPE_INTEGER}},
        {{"_TMP", 0, ACPI_RTYPE_INTEGER}},
index 9fb03fa..c845c80 100644 (file)
@@ -193,14 +193,20 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
        }
 
        /*
-        * 1) We have a return value, but if one wasn't expected, just exit, this is
-        * not a problem. For example, if the "Implicit Return" feature is
-        * enabled, methods will always return a value.
+        * Return value validation and possible repair.
         *
-        * 2) If the return value can be of any type, then we cannot perform any
-        * validation, exit.
+        * 1) Don't perform return value validation/repair if this feature
+        * has been disabled via a global option.
+        *
+        * 2) We have a return value, but if one wasn't expected, just exit,
+        * this is not a problem. For example, if the "Implicit Return"
+        * feature is enabled, methods will always return a value.
+        *
+        * 3) If the return value can be of any type, then we cannot perform
+        * any validation, just exit.
         */
-       if ((!predefined->info.expected_btypes) ||
+       if (acpi_gbl_disable_auto_repair ||
+           (!predefined->info.expected_btypes) ||
            (predefined->info.expected_btypes == ACPI_RTYPE_ALL)) {
                goto cleanup;
        }
@@ -212,6 +218,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
                goto cleanup;
        }
        data->predefined = predefined;
+       data->node = node;
        data->node_flags = node->flags;
        data->pathname = pathname;
 
index 973883b..024c4f2 100644 (file)
@@ -503,6 +503,21 @@ acpi_ns_repair_TSS(struct acpi_predefined_data *data,
 {
        union acpi_operand_object *return_object = *return_object_ptr;
        acpi_status status;
+       struct acpi_namespace_node *node;
+
+       /*
+        * We can only sort the _TSS return package if there is no _PSS in the
+        * same scope. This is because if _PSS is present, the ACPI specification
+        * dictates that the _TSS Power Dissipation field is to be ignored, and
+        * therefore some BIOSs leave garbage values in the _TSS Power field(s).
+        * In this case, it is best to just return the _TSS package as-is.
+        * (May, 2011)
+        */
+       status =
+           acpi_ns_get_node(data->node, "^_PSS", ACPI_NS_NO_UPSEARCH, &node);
+       if (ACPI_SUCCESS(status)) {
+               return (AE_OK);
+       }
 
        status = acpi_ns_check_sorted_list(data, return_object, 5, 1,
                                           ACPI_SORT_DESCENDING,
index 48db094..62365f6 100644 (file)
@@ -126,12 +126,29 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index)
        }
 
        /*
-        * Originally, we checked the table signature for "SSDT" or "PSDT" here.
-        * Next, we added support for OEMx tables, signature "OEM".
-        * Valid tables were encountered with a null signature, so we've just
-        * given up on validating the signature, since it seems to be a waste
-        * of code. The original code was removed (05/2008).
+        * Validate the incoming table signature.
+        *
+        * 1) Originally, we checked the table signature for "SSDT" or "PSDT".
+        * 2) We added support for OEMx tables, signature "OEM".
+        * 3) Valid tables were encountered with a null signature, so we just
+        *    gave up on validating the signature, (05/2008).
+        * 4) We encountered non-AML tables such as the MADT, which caused
+        *    interpreter errors and kernel faults. So now, we once again allow
+        *    only "SSDT", "OEMx", and now, also a null signature. (05/2011).
         */
+       if ((table_desc->pointer->signature[0] != 0x00) &&
+           (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT))
+           && (ACPI_STRNCMP(table_desc->pointer->signature, "OEM", 3))) {
+               ACPI_ERROR((AE_INFO,
+                           "Table has invalid signature [%4.4s] (0x%8.8X), must be SSDT or OEMx",
+                           acpi_ut_valid_acpi_name(*(u32 *)table_desc->
+                                                   pointer->
+                                                   signature) ? table_desc->
+                           pointer->signature : "????",
+                           *(u32 *)table_desc->pointer->signature));
+
+               return_ACPI_STATUS(AE_BAD_SIGNATURE);
+       }
 
        (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
 
index f739a70..c34aa51 100644 (file)
@@ -10,9 +10,11 @@ config ACPI_APEI
          error injection.
 
 config ACPI_APEI_GHES
-       tristate "APEI Generic Hardware Error Source"
+       bool "APEI Generic Hardware Error Source"
        depends on ACPI_APEI && X86
        select ACPI_HED
+       select LLIST
+       select GENERIC_ALLOCATOR
        help
          Generic Hardware Error Source provides a way to report
          platform hardware errors (such as that from chipset). It
@@ -30,6 +32,13 @@ config ACPI_APEI_PCIEAER
          PCIe AER errors may be reported via APEI firmware first mode.
          Turn on this option to enable the corresponding support.
 
+config ACPI_APEI_MEMORY_FAILURE
+       bool "APEI memory error recovering support"
+       depends on ACPI_APEI && MEMORY_FAILURE
+       help
+         Memory errors may be reported via APEI firmware first mode.
+         Turn on this option to enable the memory recovering support.
+
 config ACPI_APEI_EINJ
        tristate "APEI Error INJection (EINJ)"
        depends on ACPI_APEI && DEBUG_FS
index 4a904a4..8041248 100644 (file)
@@ -157,9 +157,10 @@ EXPORT_SYMBOL_GPL(apei_exec_noop);
  * Interpret the specified action. Go through whole action table,
  * execute all instructions belong to the action.
  */
-int apei_exec_run(struct apei_exec_context *ctx, u8 action)
+int __apei_exec_run(struct apei_exec_context *ctx, u8 action,
+                   bool optional)
 {
-       int rc;
+       int rc = -ENOENT;
        u32 i, ip;
        struct acpi_whea_header *entry;
        apei_exec_ins_func_t run;
@@ -198,9 +199,9 @@ rewind:
                        goto rewind;
        }
 
-       return 0;
+       return !optional && rc < 0 ? rc : 0;
 }
-EXPORT_SYMBOL_GPL(apei_exec_run);
+EXPORT_SYMBOL_GPL(__apei_exec_run);
 
 typedef int (*apei_exec_entry_func_t)(struct apei_exec_context *ctx,
                                      struct acpi_whea_header *entry,
@@ -603,3 +604,29 @@ struct dentry *apei_get_debugfs_dir(void)
        return dapei;
 }
 EXPORT_SYMBOL_GPL(apei_get_debugfs_dir);
+
+int apei_osc_setup(void)
+{
+       static u8 whea_uuid_str[] = "ed855e0c-6c90-47bf-a62a-26de0fc5ad5c";
+       acpi_handle handle;
+       u32 capbuf[3];
+       struct acpi_osc_context context = {
+               .uuid_str       = whea_uuid_str,
+               .rev            = 1,
+               .cap.length     = sizeof(capbuf),
+               .cap.pointer    = capbuf,
+       };
+
+       capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
+       capbuf[OSC_SUPPORT_TYPE] = 0;
+       capbuf[OSC_CONTROL_TYPE] = 0;
+
+       if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle))
+           || ACPI_FAILURE(acpi_run_osc(handle, &context)))
+               return -EIO;
+       else {
+               kfree(context.ret.pointer);
+               return 0;
+       }
+}
+EXPORT_SYMBOL_GPL(apei_osc_setup);
index ef0581f..f57050e 100644 (file)
@@ -50,7 +50,18 @@ static inline u64 apei_exec_ctx_get_output(struct apei_exec_context *ctx)
        return ctx->value;
 }
 
-int apei_exec_run(struct apei_exec_context *ctx, u8 action);
+int __apei_exec_run(struct apei_exec_context *ctx, u8 action, bool optional);
+
+static inline int apei_exec_run(struct apei_exec_context *ctx, u8 action)
+{
+       return __apei_exec_run(ctx, action, 0);
+}
+
+/* It is optional whether the firmware provides the action */
+static inline int apei_exec_run_optional(struct apei_exec_context *ctx, u8 action)
+{
+       return __apei_exec_run(ctx, action, 1);
+}
 
 /* Common instruction implementation */
 
@@ -113,4 +124,6 @@ void apei_estatus_print(const char *pfx,
                        const struct acpi_hest_generic_status *estatus);
 int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus);
 int apei_estatus_check(const struct acpi_hest_generic_status *estatus);
+
+int apei_osc_setup(void);
 #endif
index f74b2ea..589b96c 100644 (file)
@@ -46,7 +46,8 @@
  * Some BIOSes allow parameters to the SET_ERROR_TYPE entries in the
  * EINJ table through an unpublished extension. Use with caution as
  * most will ignore the parameter and make their own choice of address
- * for error injection.
+ * for error injection.  This extension is used only if
+ * param_extension module parameter is specified.
  */
 struct einj_parameter {
        u64 type;
@@ -65,6 +66,9 @@ struct einj_parameter {
        ((struct acpi_whea_header *)((char *)(tab) +                    \
                                    sizeof(struct acpi_table_einj)))
 
+static bool param_extension;
+module_param(param_extension, bool, 0);
+
 static struct acpi_table_einj *einj_tab;
 
 static struct apei_resources einj_resources;
@@ -285,7 +289,7 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2)
 
        einj_exec_ctx_init(&ctx);
 
-       rc = apei_exec_run(&ctx, ACPI_EINJ_BEGIN_OPERATION);
+       rc = apei_exec_run_optional(&ctx, ACPI_EINJ_BEGIN_OPERATION);
        if (rc)
                return rc;
        apei_exec_ctx_set_input(&ctx, type);
@@ -323,7 +327,7 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2)
        rc = __einj_error_trigger(trigger_paddr);
        if (rc)
                return rc;
-       rc = apei_exec_run(&ctx, ACPI_EINJ_END_OPERATION);
+       rc = apei_exec_run_optional(&ctx, ACPI_EINJ_END_OPERATION);
 
        return rc;
 }
@@ -489,14 +493,6 @@ static int __init einj_init(void)
                                     einj_debug_dir, NULL, &error_type_fops);
        if (!fentry)
                goto err_cleanup;
-       fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR,
-                                   einj_debug_dir, &error_param1);
-       if (!fentry)
-               goto err_cleanup;
-       fentry = debugfs_create_x64("param2", S_IRUSR | S_IWUSR,
-                                   einj_debug_dir, &error_param2);
-       if (!fentry)
-               goto err_cleanup;
        fentry = debugfs_create_file("error_inject", S_IWUSR,
                                     einj_debug_dir, NULL, &error_inject_fops);
        if (!fentry)
@@ -513,12 +509,23 @@ static int __init einj_init(void)
        rc = apei_exec_pre_map_gars(&ctx);
        if (rc)
                goto err_release;
-       param_paddr = einj_get_parameter_address();
-       if (param_paddr) {
-               einj_param = ioremap(param_paddr, sizeof(*einj_param));
-               rc = -ENOMEM;
-               if (!einj_param)
-                       goto err_unmap;
+       if (param_extension) {
+               param_paddr = einj_get_parameter_address();
+               if (param_paddr) {
+                       einj_param = ioremap(param_paddr, sizeof(*einj_param));
+                       rc = -ENOMEM;
+                       if (!einj_param)
+                               goto err_unmap;
+                       fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR,
+                                                   einj_debug_dir, &error_param1);
+                       if (!fentry)
+                               goto err_unmap;
+                       fentry = debugfs_create_x64("param2", S_IRUSR | S_IWUSR,
+                                                   einj_debug_dir, &error_param2);
+                       if (!fentry)
+                               goto err_unmap;
+               } else
+                       pr_warn(EINJ_PFX "Parameter extension is not supported.\n");
        }
 
        pr_info(EINJ_PFX "Error INJection is initialized.\n");
@@ -526,6 +533,8 @@ static int __init einj_init(void)
        return 0;
 
 err_unmap:
+       if (einj_param)
+               iounmap(einj_param);
        apei_exec_post_unmap_gars(&ctx);
 err_release:
        apei_resources_release(&einj_resources);
index a4cfb64..903549d 100644 (file)
@@ -33,7 +33,7 @@
 
 #define ERST_DBG_PFX                   "ERST DBG: "
 
-#define ERST_DBG_RECORD_LEN_MAX                4096
+#define ERST_DBG_RECORD_LEN_MAX                0x4000
 
 static void *erst_dbg_buf;
 static unsigned int erst_dbg_buf_len;
@@ -213,6 +213,10 @@ static struct miscdevice erst_dbg_dev = {
 
 static __init int erst_dbg_init(void)
 {
+       if (erst_disable) {
+               pr_info(ERST_DBG_PFX "ERST support is disabled.\n");
+               return -ENODEV;
+       }
        return misc_register(&erst_dbg_dev);
 }
 
index e6cef8e..2ca59dc 100644 (file)
@@ -642,7 +642,7 @@ static int __erst_write_to_storage(u64 offset)
        int rc;
 
        erst_exec_ctx_init(&ctx);
-       rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_WRITE);
+       rc = apei_exec_run_optional(&ctx, ACPI_ERST_BEGIN_WRITE);
        if (rc)
                return rc;
        apei_exec_ctx_set_input(&ctx, offset);
@@ -666,7 +666,7 @@ static int __erst_write_to_storage(u64 offset)
        if (rc)
                return rc;
        val = apei_exec_ctx_get_output(&ctx);
-       rc = apei_exec_run(&ctx, ACPI_ERST_END);
+       rc = apei_exec_run_optional(&ctx, ACPI_ERST_END);
        if (rc)
                return rc;
 
@@ -681,7 +681,7 @@ static int __erst_read_from_storage(u64 record_id, u64 offset)
        int rc;
 
        erst_exec_ctx_init(&ctx);
-       rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_READ);
+       rc = apei_exec_run_optional(&ctx, ACPI_ERST_BEGIN_READ);
        if (rc)
                return rc;
        apei_exec_ctx_set_input(&ctx, offset);
@@ -709,7 +709,7 @@ static int __erst_read_from_storage(u64 record_id, u64 offset)
        if (rc)
                return rc;
        val = apei_exec_ctx_get_output(&ctx);
-       rc = apei_exec_run(&ctx, ACPI_ERST_END);
+       rc = apei_exec_run_optional(&ctx, ACPI_ERST_END);
        if (rc)
                return rc;
 
@@ -724,7 +724,7 @@ static int __erst_clear_from_storage(u64 record_id)
        int rc;
 
        erst_exec_ctx_init(&ctx);
-       rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_CLEAR);
+       rc = apei_exec_run_optional(&ctx, ACPI_ERST_BEGIN_CLEAR);
        if (rc)
                return rc;
        apei_exec_ctx_set_input(&ctx, record_id);
@@ -748,7 +748,7 @@ static int __erst_clear_from_storage(u64 record_id)
        if (rc)
                return rc;
        val = apei_exec_ctx_get_output(&ctx);
-       rc = apei_exec_run(&ctx, ACPI_ERST_END);
+       rc = apei_exec_run_optional(&ctx, ACPI_ERST_END);
        if (rc)
                return rc;
 
@@ -932,8 +932,11 @@ static int erst_check_table(struct acpi_table_erst *erst_tab)
 static int erst_open_pstore(struct pstore_info *psi);
 static int erst_close_pstore(struct pstore_info *psi);
 static ssize_t erst_reader(u64 *id, enum pstore_type_id *type,
-                      struct timespec *time);
-static u64 erst_writer(enum pstore_type_id type, size_t size);
+                          struct timespec *time, struct pstore_info *psi);
+static u64 erst_writer(enum pstore_type_id type, unsigned int part,
+                      size_t size, struct pstore_info *psi);
+static int erst_clearer(enum pstore_type_id type, u64 id,
+                       struct pstore_info *psi);
 
 static struct pstore_info erst_info = {
        .owner          = THIS_MODULE,
@@ -942,7 +945,7 @@ static struct pstore_info erst_info = {
        .close          = erst_close_pstore,
        .read           = erst_reader,
        .write          = erst_writer,
-       .erase          = erst_clear
+       .erase          = erst_clearer
 };
 
 #define CPER_CREATOR_PSTORE                                            \
@@ -983,7 +986,7 @@ static int erst_close_pstore(struct pstore_info *psi)
 }
 
 static ssize_t erst_reader(u64 *id, enum pstore_type_id *type,
-                      struct timespec *time)
+                          struct timespec *time, struct pstore_info *psi)
 {
        int rc;
        ssize_t len = 0;
@@ -1037,7 +1040,8 @@ out:
        return (rc < 0) ? rc : (len - sizeof(*rcd));
 }
 
-static u64 erst_writer(enum pstore_type_id type, size_t size)
+static u64 erst_writer(enum pstore_type_id type, unsigned int part,
+                      size_t size, struct pstore_info *psi)
 {
        struct cper_pstore_record *rcd = (struct cper_pstore_record *)
                                        (erst_info.buf - sizeof(*rcd));
@@ -1080,6 +1084,12 @@ static u64 erst_writer(enum pstore_type_id type, size_t size)
        return rcd->hdr.record_id;
 }
 
+static int erst_clearer(enum pstore_type_id type, u64 id,
+                       struct pstore_info *psi)
+{
+       return erst_clear(id);
+}
+
 static int __init erst_init(void)
 {
        int rc = 0;
index f703b28..0784f99 100644 (file)
@@ -12,7 +12,7 @@
  * For more information about Generic Hardware Error Source, please
  * refer to ACPI Specification version 4.0, section 17.3.2.6
  *
- * Copyright 2010 Intel Corp.
+ * Copyright 2010,2011 Intel Corp.
  *   Author: Huang Ying <ying.huang@intel.com>
  *
  * This program is free software; you can redistribute it and/or
@@ -42,6 +42,9 @@
 #include <linux/mutex.h>
 #include <linux/ratelimit.h>
 #include <linux/vmalloc.h>
+#include <linux/irq_work.h>
+#include <linux/llist.h>
+#include <linux/genalloc.h>
 #include <acpi/apei.h>
 #include <acpi/atomicio.h>
 #include <acpi/hed.h>
 #define GHES_PFX       "GHES: "
 
 #define GHES_ESTATUS_MAX_SIZE          65536
+#define GHES_ESOURCE_PREALLOC_MAX_SIZE 65536
+
+#define GHES_ESTATUS_POOL_MIN_ALLOC_ORDER 3
+
+/* This is just an estimation for memory pool allocation */
+#define GHES_ESTATUS_CACHE_AVG_SIZE    512
+
+#define GHES_ESTATUS_CACHES_SIZE       4
+
+#define GHES_ESTATUS_IN_CACHE_MAX_NSEC 10000000000ULL
+/* Prevent too many caches are allocated because of RCU */
+#define GHES_ESTATUS_CACHE_ALLOCED_MAX (GHES_ESTATUS_CACHES_SIZE * 3 / 2)
+
+#define GHES_ESTATUS_CACHE_LEN(estatus_len)                    \
+       (sizeof(struct ghes_estatus_cache) + (estatus_len))
+#define GHES_ESTATUS_FROM_CACHE(estatus_cache)                 \
+       ((struct acpi_hest_generic_status *)                    \
+        ((struct ghes_estatus_cache *)(estatus_cache) + 1))
+
+#define GHES_ESTATUS_NODE_LEN(estatus_len)                     \
+       (sizeof(struct ghes_estatus_node) + (estatus_len))
+#define GHES_ESTATUS_FROM_NODE(estatus_node)                           \
+       ((struct acpi_hest_generic_status *)                            \
+        ((struct ghes_estatus_node *)(estatus_node) + 1))
 
 /*
  * One struct ghes is created for each generic hardware error source.
@@ -77,6 +104,22 @@ struct ghes {
        };
 };
 
+struct ghes_estatus_node {
+       struct llist_node llnode;
+       struct acpi_hest_generic *generic;
+};
+
+struct ghes_estatus_cache {
+       u32 estatus_len;
+       atomic_t count;
+       struct acpi_hest_generic *generic;
+       unsigned long long time_in;
+       struct rcu_head rcu;
+};
+
+int ghes_disable;
+module_param_named(disable, ghes_disable, bool, 0);
+
 static int ghes_panic_timeout  __read_mostly = 30;
 
 /*
@@ -121,6 +164,22 @@ static struct vm_struct *ghes_ioremap_area;
 static DEFINE_RAW_SPINLOCK(ghes_ioremap_lock_nmi);
 static DEFINE_SPINLOCK(ghes_ioremap_lock_irq);
 
+/*
+ * printk is not safe in NMI context.  So in NMI handler, we allocate
+ * required memory from lock-less memory allocator
+ * (ghes_estatus_pool), save estatus into it, put them into lock-less
+ * list (ghes_estatus_llist), then delay printk into IRQ context via
+ * irq_work (ghes_proc_irq_work).  ghes_estatus_size_request record
+ * required pool size by all NMI error source.
+ */
+static struct gen_pool *ghes_estatus_pool;
+static unsigned long ghes_estatus_pool_size_request;
+static struct llist_head ghes_estatus_llist;
+static struct irq_work ghes_proc_irq_work;
+
+struct ghes_estatus_cache *ghes_estatus_caches[GHES_ESTATUS_CACHES_SIZE];
+static atomic_t ghes_estatus_cache_alloced;
+
 static int ghes_ioremap_init(void)
 {
        ghes_ioremap_area = __get_vm_area(PAGE_SIZE * GHES_IOREMAP_PAGES,
@@ -180,6 +239,55 @@ static void ghes_iounmap_irq(void __iomem *vaddr_ptr)
        __flush_tlb_one(vaddr);
 }
 
+static int ghes_estatus_pool_init(void)
+{
+       ghes_estatus_pool = gen_pool_create(GHES_ESTATUS_POOL_MIN_ALLOC_ORDER, -1);
+       if (!ghes_estatus_pool)
+               return -ENOMEM;
+       return 0;
+}
+
+static void ghes_estatus_pool_free_chunk_page(struct gen_pool *pool,
+                                             struct gen_pool_chunk *chunk,
+                                             void *data)
+{
+       free_page(chunk->start_addr);
+}
+
+static void ghes_estatus_pool_exit(void)
+{
+       gen_pool_for_each_chunk(ghes_estatus_pool,
+                               ghes_estatus_pool_free_chunk_page, NULL);
+       gen_pool_destroy(ghes_estatus_pool);
+}
+
+static int ghes_estatus_pool_expand(unsigned long len)
+{
+       unsigned long i, pages, size, addr;
+       int ret;
+
+       ghes_estatus_pool_size_request += PAGE_ALIGN(len);
+       size = gen_pool_size(ghes_estatus_pool);
+       if (size >= ghes_estatus_pool_size_request)
+               return 0;
+       pages = (ghes_estatus_pool_size_request - size) / PAGE_SIZE;
+       for (i = 0; i < pages; i++) {
+               addr = __get_free_page(GFP_KERNEL);
+               if (!addr)
+                       return -ENOMEM;
+               ret = gen_pool_add(ghes_estatus_pool, addr, PAGE_SIZE, -1);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static void ghes_estatus_pool_shrink(unsigned long len)
+{
+       ghes_estatus_pool_size_request -= PAGE_ALIGN(len);
+}
+
 static struct ghes *ghes_new(struct acpi_hest_generic *generic)
 {
        struct ghes *ghes;
@@ -341,43 +449,196 @@ static void ghes_clear_estatus(struct ghes *ghes)
        ghes->flags &= ~GHES_TO_CLEAR;
 }
 
-static void ghes_do_proc(struct ghes *ghes)
+static void ghes_do_proc(const struct acpi_hest_generic_status *estatus)
 {
-       int sev, processed = 0;
+       int sev, sec_sev;
        struct acpi_hest_generic_data *gdata;
 
-       sev = ghes_severity(ghes->estatus->error_severity);
-       apei_estatus_for_each_section(ghes->estatus, gdata) {
-#ifdef CONFIG_X86_MCE
+       sev = ghes_severity(estatus->error_severity);
+       apei_estatus_for_each_section(estatus, gdata) {
+               sec_sev = ghes_severity(gdata->error_severity);
                if (!uuid_le_cmp(*(uuid_le *)gdata->section_type,
                                 CPER_SEC_PLATFORM_MEM)) {
-                       apei_mce_report_mem_error(
-                               sev == GHES_SEV_CORRECTED,
-                               (struct cper_sec_mem_err *)(gdata+1));
-                       processed = 1;
-               }
+                       struct cper_sec_mem_err *mem_err;
+                       mem_err = (struct cper_sec_mem_err *)(gdata+1);
+#ifdef CONFIG_X86_MCE
+                       apei_mce_report_mem_error(sev == GHES_SEV_CORRECTED,
+                                                 mem_err);
 #endif
+#ifdef CONFIG_ACPI_APEI_MEMORY_FAILURE
+                       if (sev == GHES_SEV_RECOVERABLE &&
+                           sec_sev == GHES_SEV_RECOVERABLE &&
+                           mem_err->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS) {
+                               unsigned long pfn;
+                               pfn = mem_err->physical_addr >> PAGE_SHIFT;
+                               memory_failure_queue(pfn, 0, 0);
+                       }
+#endif
+               }
        }
 }
 
-static void ghes_print_estatus(const char *pfx, struct ghes *ghes)
+static void __ghes_print_estatus(const char *pfx,
+                                const struct acpi_hest_generic *generic,
+                                const struct acpi_hest_generic_status *estatus)
 {
-       /* Not more than 2 messages every 5 seconds */
-       static DEFINE_RATELIMIT_STATE(ratelimit, 5*HZ, 2);
-
        if (pfx == NULL) {
-               if (ghes_severity(ghes->estatus->error_severity) <=
+               if (ghes_severity(estatus->error_severity) <=
                    GHES_SEV_CORRECTED)
                        pfx = KERN_WARNING HW_ERR;
                else
                        pfx = KERN_ERR HW_ERR;
        }
-       if (__ratelimit(&ratelimit)) {
-               printk(
-       "%s""Hardware error from APEI Generic Hardware Error Source: %d\n",
-       pfx, ghes->generic->header.source_id);
-               apei_estatus_print(pfx, ghes->estatus);
+       printk("%s""Hardware error from APEI Generic Hardware Error Source: %d\n",
+              pfx, generic->header.source_id);
+       apei_estatus_print(pfx, estatus);
+}
+
+static int ghes_print_estatus(const char *pfx,
+                             const struct acpi_hest_generic *generic,
+                             const struct acpi_hest_generic_status *estatus)
+{
+       /* Not more than 2 messages every 5 seconds */
+       static DEFINE_RATELIMIT_STATE(ratelimit_corrected, 5*HZ, 2);
+       static DEFINE_RATELIMIT_STATE(ratelimit_uncorrected, 5*HZ, 2);
+       struct ratelimit_state *ratelimit;
+
+       if (ghes_severity(estatus->error_severity) <= GHES_SEV_CORRECTED)
+               ratelimit = &ratelimit_corrected;
+       else
+               ratelimit = &ratelimit_uncorrected;
+       if (__ratelimit(ratelimit)) {
+               __ghes_print_estatus(pfx, generic, estatus);
+               return 1;
        }
+       return 0;
+}
+
+/*
+ * GHES error status reporting throttle, to report more kinds of
+ * errors, instead of just most frequently occurred errors.
+ */
+static int ghes_estatus_cached(struct acpi_hest_generic_status *estatus)
+{
+       u32 len;
+       int i, cached = 0;
+       unsigned long long now;
+       struct ghes_estatus_cache *cache;
+       struct acpi_hest_generic_status *cache_estatus;
+
+       len = apei_estatus_len(estatus);
+       rcu_read_lock();
+       for (i = 0; i < GHES_ESTATUS_CACHES_SIZE; i++) {
+               cache = rcu_dereference(ghes_estatus_caches[i]);
+               if (cache == NULL)
+                       continue;
+               if (len != cache->estatus_len)
+                       continue;
+               cache_estatus = GHES_ESTATUS_FROM_CACHE(cache);
+               if (memcmp(estatus, cache_estatus, len))
+                       continue;
+               atomic_inc(&cache->count);
+               now = sched_clock();
+               if (now - cache->time_in < GHES_ESTATUS_IN_CACHE_MAX_NSEC)
+                       cached = 1;
+               break;
+       }
+       rcu_read_unlock();
+       return cached;
+}
+
+static struct ghes_estatus_cache *ghes_estatus_cache_alloc(
+       struct acpi_hest_generic *generic,
+       struct acpi_hest_generic_status *estatus)
+{
+       int alloced;
+       u32 len, cache_len;
+       struct ghes_estatus_cache *cache;
+       struct acpi_hest_generic_status *cache_estatus;
+
+       alloced = atomic_add_return(1, &ghes_estatus_cache_alloced);
+       if (alloced > GHES_ESTATUS_CACHE_ALLOCED_MAX) {
+               atomic_dec(&ghes_estatus_cache_alloced);
+               return NULL;
+       }
+       len = apei_estatus_len(estatus);
+       cache_len = GHES_ESTATUS_CACHE_LEN(len);
+       cache = (void *)gen_pool_alloc(ghes_estatus_pool, cache_len);
+       if (!cache) {
+               atomic_dec(&ghes_estatus_cache_alloced);
+               return NULL;
+       }
+       cache_estatus = GHES_ESTATUS_FROM_CACHE(cache);
+       memcpy(cache_estatus, estatus, len);
+       cache->estatus_len = len;
+       atomic_set(&cache->count, 0);
+       cache->generic = generic;
+       cache->time_in = sched_clock();
+       return cache;
+}
+
+static void ghes_estatus_cache_free(struct ghes_estatus_cache *cache)
+{
+       u32 len;
+
+       len = apei_estatus_len(GHES_ESTATUS_FROM_CACHE(cache));
+       len = GHES_ESTATUS_CACHE_LEN(len);
+       gen_pool_free(ghes_estatus_pool, (unsigned long)cache, len);
+       atomic_dec(&ghes_estatus_cache_alloced);
+}
+
+static void ghes_estatus_cache_rcu_free(struct rcu_head *head)
+{
+       struct ghes_estatus_cache *cache;
+
+       cache = container_of(head, struct ghes_estatus_cache, rcu);
+       ghes_estatus_cache_free(cache);
+}
+
+static void ghes_estatus_cache_add(
+       struct acpi_hest_generic *generic,
+       struct acpi_hest_generic_status *estatus)
+{
+       int i, slot = -1, count;
+       unsigned long long now, duration, period, max_period = 0;
+       struct ghes_estatus_cache *cache, *slot_cache = NULL, *new_cache;
+
+       new_cache = ghes_estatus_cache_alloc(generic, estatus);
+       if (new_cache == NULL)
+               return;
+       rcu_read_lock();
+       now = sched_clock();
+       for (i = 0; i < GHES_ESTATUS_CACHES_SIZE; i++) {
+               cache = rcu_dereference(ghes_estatus_caches[i]);
+               if (cache == NULL) {
+                       slot = i;
+                       slot_cache = NULL;
+                       break;
+               }
+               duration = now - cache->time_in;
+               if (duration >= GHES_ESTATUS_IN_CACHE_MAX_NSEC) {
+                       slot = i;
+                       slot_cache = cache;
+                       break;
+               }
+               count = atomic_read(&cache->count);
+               period = duration;
+               do_div(period, (count + 1));
+               if (period > max_period) {
+                       max_period = period;
+                       slot = i;
+                       slot_cache = cache;
+               }
+       }
+       /* new_cache must be put into array after its contents are written */
+       smp_wmb();
+       if (slot != -1 && cmpxchg(ghes_estatus_caches + slot,
+                                 slot_cache, new_cache) == slot_cache) {
+               if (slot_cache)
+                       call_rcu(&slot_cache->rcu, ghes_estatus_cache_rcu_free);
+       } else
+               ghes_estatus_cache_free(new_cache);
+       rcu_read_unlock();
 }
 
 static int ghes_proc(struct ghes *ghes)
@@ -387,9 +648,11 @@ static int ghes_proc(struct ghes *ghes)
        rc = ghes_read_estatus(ghes, 0);
        if (rc)
                goto out;
-       ghes_print_estatus(NULL, ghes);
-       ghes_do_proc(ghes);
-
+       if (!ghes_estatus_cached(ghes->estatus)) {
+               if (ghes_print_estatus(NULL, ghes->generic, ghes->estatus))
+                       ghes_estatus_cache_add(ghes->generic, ghes->estatus);
+       }
+       ghes_do_proc(ghes->estatus);
 out:
        ghes_clear_estatus(ghes);
        return 0;
@@ -447,6 +710,45 @@ static int ghes_notify_sci(struct notifier_block *this,
        return ret;
 }
 
+static void ghes_proc_in_irq(struct irq_work *irq_work)
+{
+       struct llist_node *llnode, *next, *tail = NULL;
+       struct ghes_estatus_node *estatus_node;
+       struct acpi_hest_generic *generic;
+       struct acpi_hest_generic_status *estatus;
+       u32 len, node_len;
+
+       /*
+        * Because the time order of estatus in list is reversed,
+        * revert it back to proper order.
+        */
+       llnode = llist_del_all(&ghes_estatus_llist);
+       while (llnode) {
+               next = llnode->next;
+               llnode->next = tail;
+               tail = llnode;
+               llnode = next;
+       }
+       llnode = tail;
+       while (llnode) {
+               next = llnode->next;
+               estatus_node = llist_entry(llnode, struct ghes_estatus_node,
+                                          llnode);
+               estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
+               len = apei_estatus_len(estatus);
+               node_len = GHES_ESTATUS_NODE_LEN(len);
+               ghes_do_proc(estatus);
+               if (!ghes_estatus_cached(estatus)) {
+                       generic = estatus_node->generic;
+                       if (ghes_print_estatus(NULL, generic, estatus))
+                               ghes_estatus_cache_add(generic, estatus);
+               }
+               gen_pool_free(ghes_estatus_pool, (unsigned long)estatus_node,
+                             node_len);
+               llnode = next;
+       }
+}
+
 static int ghes_notify_nmi(struct notifier_block *this,
                                  unsigned long cmd, void *data)
 {
@@ -476,7 +778,8 @@ static int ghes_notify_nmi(struct notifier_block *this,
 
        if (sev_global >= GHES_SEV_PANIC) {
                oops_begin();
-               ghes_print_estatus(KERN_EMERG HW_ERR, ghes_global);
+               __ghes_print_estatus(KERN_EMERG HW_ERR, ghes_global->generic,
+                                    ghes_global->estatus);
                /* reboot to log the error! */
                if (panic_timeout == 0)
                        panic_timeout = ghes_panic_timeout;
@@ -484,12 +787,34 @@ static int ghes_notify_nmi(struct notifier_block *this,
        }
 
        list_for_each_entry_rcu(ghes, &ghes_nmi, list) {
+#ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
+               u32 len, node_len;
+               struct ghes_estatus_node *estatus_node;
+               struct acpi_hest_generic_status *estatus;
+#endif
                if (!(ghes->flags & GHES_TO_CLEAR))
                        continue;
-               /* Do not print estatus because printk is not NMI safe */
-               ghes_do_proc(ghes);
+#ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
+               if (ghes_estatus_cached(ghes->estatus))
+                       goto next;
+               /* Save estatus for further processing in IRQ context */
+               len = apei_estatus_len(ghes->estatus);
+               node_len = GHES_ESTATUS_NODE_LEN(len);
+               estatus_node = (void *)gen_pool_alloc(ghes_estatus_pool,
+                                                     node_len);
+               if (estatus_node) {
+                       estatus_node->generic = ghes->generic;
+                       estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
+                       memcpy(estatus, ghes->estatus, len);
+                       llist_add(&estatus_node->llnode, &ghes_estatus_llist);
+               }
+next:
+#endif
                ghes_clear_estatus(ghes);
        }
+#ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
+       irq_work_queue(&ghes_proc_irq_work);
+#endif
 
 out:
        raw_spin_unlock(&ghes_nmi_lock);
@@ -504,10 +829,26 @@ static struct notifier_block ghes_notifier_nmi = {
        .notifier_call = ghes_notify_nmi,
 };
 
+static unsigned long ghes_esource_prealloc_size(
+       const struct acpi_hest_generic *generic)
+{
+       unsigned long block_length, prealloc_records, prealloc_size;
+
+       block_length = min_t(unsigned long, generic->error_block_length,
+                            GHES_ESTATUS_MAX_SIZE);
+       prealloc_records = max_t(unsigned long,
+                                generic->records_to_preallocate, 1);
+       prealloc_size = min_t(unsigned long, block_length * prealloc_records,
+                             GHES_ESOURCE_PREALLOC_MAX_SIZE);
+
+       return prealloc_size;
+}
+
 static int __devinit ghes_probe(struct platform_device *ghes_dev)
 {
        struct acpi_hest_generic *generic;
        struct ghes *ghes = NULL;
+       unsigned long len;
        int rc = -EINVAL;
 
        generic = *(struct acpi_hest_generic **)ghes_dev->dev.platform_data;
@@ -573,6 +914,8 @@ static int __devinit ghes_probe(struct platform_device *ghes_dev)
                mutex_unlock(&ghes_list_mutex);
                break;
        case ACPI_HEST_NOTIFY_NMI:
+               len = ghes_esource_prealloc_size(generic);
+               ghes_estatus_pool_expand(len);
                mutex_lock(&ghes_list_mutex);
                if (list_empty(&ghes_nmi))
                        register_die_notifier(&ghes_notifier_nmi);
@@ -597,6 +940,7 @@ static int __devexit ghes_remove(struct platform_device *ghes_dev)
 {
        struct ghes *ghes;
        struct acpi_hest_generic *generic;
+       unsigned long len;
 
        ghes = platform_get_drvdata(ghes_dev);
        generic = ghes->generic;
@@ -627,6 +971,8 @@ static int __devexit ghes_remove(struct platform_device *ghes_dev)
                 * freed after NMI handler finishes.
                 */
                synchronize_rcu();
+               len = ghes_esource_prealloc_size(generic);
+               ghes_estatus_pool_shrink(len);
                break;
        default:
                BUG();
@@ -662,15 +1008,43 @@ static int __init ghes_init(void)
                return -EINVAL;
        }
 
+       if (ghes_disable) {
+               pr_info(GHES_PFX "GHES is not enabled!\n");
+               return -EINVAL;
+       }
+
+       init_irq_work(&ghes_proc_irq_work, ghes_proc_in_irq);
+
        rc = ghes_ioremap_init();
        if (rc)
                goto err;
 
-       rc = platform_driver_register(&ghes_platform_driver);
+       rc = ghes_estatus_pool_init();
        if (rc)
                goto err_ioremap_exit;
 
+       rc = ghes_estatus_pool_expand(GHES_ESTATUS_CACHE_AVG_SIZE *
+                                     GHES_ESTATUS_CACHE_ALLOCED_MAX);
+       if (rc)
+               goto err_pool_exit;
+
+       rc = platform_driver_register(&ghes_platform_driver);
+       if (rc)
+               goto err_pool_exit;
+
+       rc = apei_osc_setup();
+       if (rc == 0 && osc_sb_apei_support_acked)
+               pr_info(GHES_PFX "APEI firmware first mode is enabled by APEI bit and WHEA _OSC.\n");
+       else if (rc == 0 && !osc_sb_apei_support_acked)
+               pr_info(GHES_PFX "APEI firmware first mode is enabled by WHEA _OSC.\n");
+       else if (rc && osc_sb_apei_support_acked)
+               pr_info(GHES_PFX "APEI firmware first mode is enabled by APEI bit.\n");
+       else
+               pr_info(GHES_PFX "Failed to enable APEI firmware first mode.\n");
+
        return 0;
+err_pool_exit:
+       ghes_estatus_pool_exit();
 err_ioremap_exit:
        ghes_ioremap_exit();
 err:
@@ -680,6 +1054,7 @@ err:
 static void __exit ghes_exit(void)
 {
        platform_driver_unregister(&ghes_platform_driver);
+       ghes_estatus_pool_exit();
        ghes_ioremap_exit();
 }
 
index 181bc2f..05fee06 100644 (file)
@@ -231,16 +231,17 @@ void __init acpi_hest_init(void)
                goto err;
        }
 
-       rc = apei_hest_parse(hest_parse_ghes_count, &ghes_count);
-       if (rc)
-               goto err;
-
-       rc = hest_ghes_dev_register(ghes_count);
-       if (!rc) {
-               pr_info(HEST_PFX "Table parsing has been initialized.\n");
-               return;
+       if (!ghes_disable) {
+               rc = apei_hest_parse(hest_parse_ghes_count, &ghes_count);
+               if (rc)
+                       goto err;
+               rc = hest_ghes_dev_register(ghes_count);
+               if (rc)
+                       goto err;
        }
 
+       pr_info(HEST_PFX "Table parsing has been initialized.\n");
+       return;
 err:
        hest_disable = 1;
 }
index 2c66135..7711d94 100644 (file)
@@ -55,6 +55,9 @@
 #define ACPI_BATTERY_NOTIFY_INFO       0x81
 #define ACPI_BATTERY_NOTIFY_THRESHOLD   0x82
 
+/* Battery power unit: 0 means mW, 1 means mA */
+#define ACPI_BATTERY_POWER_UNIT_MA     1
+
 #define _COMPONENT             ACPI_BATTERY_COMPONENT
 
 ACPI_MODULE_NAME("battery");
@@ -91,16 +94,12 @@ MODULE_DEVICE_TABLE(acpi, battery_device_ids);
 enum {
        ACPI_BATTERY_ALARM_PRESENT,
        ACPI_BATTERY_XINFO_PRESENT,
-       /* For buggy DSDTs that report negative 16-bit values for either
-        * charging or discharging current and/or report 0 as 65536
-        * due to bad math.
-        */
-       ACPI_BATTERY_QUIRK_SIGNED16_CURRENT,
        ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY,
 };
 
 struct acpi_battery {
        struct mutex lock;
+       struct mutex sysfs_lock;
        struct power_supply bat;
        struct acpi_device *device;
        struct notifier_block pm_nb;
@@ -301,7 +300,8 @@ static enum power_supply_property energy_battery_props[] = {
 #ifdef CONFIG_ACPI_PROCFS_POWER
 inline char *acpi_battery_units(struct acpi_battery *battery)
 {
-       return (battery->power_unit)?"mA":"mW";
+       return (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA) ?
+               "mA" : "mW";
 }
 #endif
 
@@ -461,9 +461,17 @@ static int acpi_battery_get_state(struct acpi_battery *battery)
        battery->update_time = jiffies;
        kfree(buffer.pointer);
 
-       if (test_bit(ACPI_BATTERY_QUIRK_SIGNED16_CURRENT, &battery->flags) &&
-           battery->rate_now != -1)
+       /* For buggy DSDTs that report negative 16-bit values for either
+        * charging or discharging current and/or report 0 as 65536
+        * due to bad math.
+        */
+       if (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA &&
+               battery->rate_now != ACPI_BATTERY_VALUE_UNKNOWN &&
+               (s16)(battery->rate_now) < 0) {
                battery->rate_now = abs((s16)battery->rate_now);
+               printk_once(KERN_WARNING FW_BUG "battery: (dis)charge rate"
+                       " invalid.\n");
+       }
 
        if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags)
            && battery->capacity_now >= 0 && battery->capacity_now <= 100)
@@ -544,7 +552,7 @@ static int sysfs_add_battery(struct acpi_battery *battery)
 {
        int result;
 
-       if (battery->power_unit) {
+       if (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA) {
                battery->bat.properties = charge_battery_props;
                battery->bat.num_properties =
                        ARRAY_SIZE(charge_battery_props);
@@ -566,18 +574,16 @@ static int sysfs_add_battery(struct acpi_battery *battery)
 
 static void sysfs_remove_battery(struct acpi_battery *battery)
 {
-       if (!battery->bat.dev)
+       mutex_lock(&battery->sysfs_lock);
+       if (!battery->bat.dev) {
+               mutex_unlock(&battery->sysfs_lock);
                return;
+       }
+
        device_remove_file(battery->bat.dev, &alarm_attr);
        power_supply_unregister(&battery->bat);
        battery->bat.dev = NULL;
-}
-
-static void acpi_battery_quirks(struct acpi_battery *battery)
-{
-       if (dmi_name_in_vendors("Acer") && battery->power_unit) {
-               set_bit(ACPI_BATTERY_QUIRK_SIGNED16_CURRENT, &battery->flags);
-       }
+       mutex_unlock(&battery->sysfs_lock);
 }
 
 /*
@@ -592,7 +598,7 @@ static void acpi_battery_quirks(struct acpi_battery *battery)
  *
  * Handle this correctly so that they won't break userspace.
  */
-static void acpi_battery_quirks2(struct acpi_battery *battery)
+static void acpi_battery_quirks(struct acpi_battery *battery)
 {
        if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags))
                return ;
@@ -623,13 +629,15 @@ static int acpi_battery_update(struct acpi_battery *battery)
                result = acpi_battery_get_info(battery);
                if (result)
                        return result;
-               acpi_battery_quirks(battery);
                acpi_battery_init_alarm(battery);
        }
-       if (!battery->bat.dev)
-               sysfs_add_battery(battery);
+       if (!battery->bat.dev) {
+               result = sysfs_add_battery(battery);
+               if (result)
+                       return result;
+       }
        result = acpi_battery_get_state(battery);
-       acpi_battery_quirks2(battery);
+       acpi_battery_quirks(battery);
        return result;
 }
 
@@ -863,7 +871,7 @@ DECLARE_FILE_FUNCTIONS(alarm);
                }, \
        }
 
-static struct battery_file {
+static const struct battery_file {
        struct file_operations ops;
        mode_t mode;
        const char *name;
@@ -948,9 +956,12 @@ static int battery_notify(struct notifier_block *nb,
        struct acpi_battery *battery = container_of(nb, struct acpi_battery,
                                                    pm_nb);
        switch (mode) {
+       case PM_POST_HIBERNATION:
        case PM_POST_SUSPEND:
-               sysfs_remove_battery(battery);
-               sysfs_add_battery(battery);
+               if (battery->bat.dev) {
+                       sysfs_remove_battery(battery);
+                       sysfs_add_battery(battery);
+               }
                break;
        }
 
@@ -972,28 +983,38 @@ static int acpi_battery_add(struct acpi_device *device)
        strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
        device->driver_data = battery;
        mutex_init(&battery->lock);
+       mutex_init(&battery->sysfs_lock);
        if (ACPI_SUCCESS(acpi_get_handle(battery->device->handle,
                        "_BIX", &handle)))
                set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
-       acpi_battery_update(battery);
+       result = acpi_battery_update(battery);
+       if (result)
+               goto fail;
 #ifdef CONFIG_ACPI_PROCFS_POWER
        result = acpi_battery_add_fs(device);
 #endif
-       if (!result) {
-               printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n",
-                       ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device),
-                       device->status.battery_present ? "present" : "absent");
-       } else {
+       if (result) {
 #ifdef CONFIG_ACPI_PROCFS_POWER
                acpi_battery_remove_fs(device);
 #endif
-               kfree(battery);
+               goto fail;
        }
 
+       printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n",
+               ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device),
+               device->status.battery_present ? "present" : "absent");
+
        battery->pm_nb.notifier_call = battery_notify;
        register_pm_notifier(&battery->pm_nb);
 
        return result;
+
+fail:
+       sysfs_remove_battery(battery);
+       mutex_destroy(&battery->lock);
+       mutex_destroy(&battery->sysfs_lock);
+       kfree(battery);
+       return result;
 }
 
 static int acpi_battery_remove(struct acpi_device *device, int type)
@@ -1009,6 +1030,7 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
 #endif
        sysfs_remove_battery(battery);
        mutex_destroy(&battery->lock);
+       mutex_destroy(&battery->sysfs_lock);
        kfree(battery);
        return 0;
 }
index d1e06c1..437ddbf 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/pci.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
+#include <acpi/apei.h>
 #include <linux/dmi.h>
 #include <linux/suspend.h>
 
@@ -519,6 +520,7 @@ out_kfree:
 }
 EXPORT_SYMBOL(acpi_run_osc);
 
+bool osc_sb_apei_support_acked;
 static u8 sb_uuid_str[] = "0811B06E-4A27-44F9-8D60-3CBBC22E7B48";
 static void acpi_bus_osc_support(void)
 {
@@ -541,11 +543,19 @@ static void acpi_bus_osc_support(void)
 #if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
        capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_PPC_OST_SUPPORT;
 #endif
+
+       if (!ghes_disable)
+               capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_APEI_SUPPORT;
        if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle)))
                return;
-       if (ACPI_SUCCESS(acpi_run_osc(handle, &context)))
+       if (ACPI_SUCCESS(acpi_run_osc(handle, &context))) {
+               u32 *capbuf_ret = context.ret.pointer;
+               if (context.ret.length > OSC_SUPPORT_TYPE)
+                       osc_sb_apei_support_acked =
+                               capbuf_ret[OSC_SUPPORT_TYPE] & OSC_SB_APEI_SUPPORT;
                kfree(context.ret.pointer);
-       /* do we need to check the returned cap? Sounds no */
+       }
+       /* do we need to check other returned cap? Sounds no */
 }
 
 /* --------------------------------------------------------------------------
index 1864ad3..19a6113 100644 (file)
@@ -77,7 +77,7 @@ struct dock_dependent_device {
        struct list_head list;
        struct list_head hotplug_list;
        acpi_handle handle;
-       struct acpi_dock_ops *ops;
+       const struct acpi_dock_ops *ops;
        void *context;
 };
 
@@ -589,7 +589,7 @@ EXPORT_SYMBOL_GPL(unregister_dock_notifier);
  * the dock driver after _DCK is executed.
  */
 int
-register_hotplug_dock_device(acpi_handle handle, struct acpi_dock_ops *ops,
+register_hotplug_dock_device(acpi_handle handle, const struct acpi_dock_ops *ops,
                             void *context)
 {
        struct dock_dependent_device *dd;
index 05b4420..22f918b 100644 (file)
@@ -92,7 +92,7 @@ static ssize_t acpi_ec_write_io(struct file *f, const char __user *buf,
        return count;
 }
 
-static struct file_operations acpi_ec_io_ops = {
+static const struct file_operations acpi_ec_io_ops = {
        .owner = THIS_MODULE,
        .open  = acpi_ec_open_io,
        .read  = acpi_ec_read_io,
index 467479f..0f0356c 100644 (file)
@@ -110,7 +110,7 @@ fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
        return result;
 }
 
-static struct thermal_cooling_device_ops fan_cooling_ops = {
+static const struct thermal_cooling_device_ops fan_cooling_ops = {
        .get_max_state = fan_get_max_state,
        .get_cur_state = fan_get_cur_state,
        .set_cur_state = fan_set_cur_state,
index 372f9b7..fa32f58 100644 (file)
@@ -155,7 +155,7 @@ static u32 acpi_osi_handler(acpi_string interface, u32 supported)
 {
        if (!strcmp("Linux", interface)) {
 
-               printk(KERN_NOTICE FW_BUG PREFIX
+               printk_once(KERN_NOTICE FW_BUG PREFIX
                        "BIOS _OSI(Linux) query %s%s\n",
                        osi_linux.enable ? "honored" : "ignored",
                        osi_linux.cmdline ? " via cmdline" :
@@ -237,8 +237,23 @@ void acpi_os_vprintf(const char *fmt, va_list args)
 #endif
 }
 
+#ifdef CONFIG_KEXEC
+static unsigned long acpi_rsdp;
+static int __init setup_acpi_rsdp(char *arg)
+{
+       acpi_rsdp = simple_strtoul(arg, NULL, 16);
+       return 0;
+}
+early_param("acpi_rsdp", setup_acpi_rsdp);
+#endif
+
 acpi_physical_address __init acpi_os_get_root_pointer(void)
 {
+#ifdef CONFIG_KEXEC
+       if (acpi_rsdp)
+               return acpi_rsdp;
+#endif
+
        if (efi_enabled) {
                if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
                        return efi.acpi20;
@@ -1083,7 +1098,13 @@ struct osi_setup_entry {
        bool enable;
 };
 
-static struct osi_setup_entry __initdata osi_setup_entries[OSI_STRING_ENTRIES_MAX];
+static struct osi_setup_entry __initdata
+               osi_setup_entries[OSI_STRING_ENTRIES_MAX] = {
+       {"Module Device", true},
+       {"Processor Device", true},
+       {"3.0 _SCP Extensions", true},
+       {"Processor Aggregator Device", true},
+};
 
 void __init acpi_osi_setup(char *str)
 {
index f907cfb..7f9eba9 100644 (file)
@@ -303,6 +303,61 @@ void acpi_pci_irq_del_prt(struct pci_bus *bus)
 /* --------------------------------------------------------------------------
                           PCI Interrupt Routing Support
    -------------------------------------------------------------------------- */
+#ifdef CONFIG_X86_IO_APIC
+extern int noioapicquirk;
+extern int noioapicreroute;
+
+static int bridge_has_boot_interrupt_variant(struct pci_bus *bus)
+{
+       struct pci_bus *bus_it;
+
+       for (bus_it = bus ; bus_it ; bus_it = bus_it->parent) {
+               if (!bus_it->self)
+                       return 0;
+               if (bus_it->self->irq_reroute_variant)
+                       return bus_it->self->irq_reroute_variant;
+       }
+       return 0;
+}
+
+/*
+ * Some chipsets (e.g. Intel 6700PXH) generate a legacy INTx when the IRQ
+ * entry in the chipset's IO-APIC is masked (as, e.g. the RT kernel does
+ * during interrupt handling). When this INTx generation cannot be disabled,
+ * we reroute these interrupts to their legacy equivalent to get rid of
+ * spurious interrupts.
+ */
+static int acpi_reroute_boot_interrupt(struct pci_dev *dev,
+                                      struct acpi_prt_entry *entry)
+{
+       if (noioapicquirk || noioapicreroute) {
+               return 0;
+       } else {
+               switch (bridge_has_boot_interrupt_variant(dev->bus)) {
+               case 0:
+                       /* no rerouting necessary */
+                       return 0;
+               case INTEL_IRQ_REROUTE_VARIANT:
+                       /*
+                        * Remap according to INTx routing table in 6700PXH
+                        * specs, intel order number 302628-002, section
+                        * 2.15.2. Other chipsets (80332, ...) have the same
+                        * mapping and are handled here as well.
+                        */
+                       dev_info(&dev->dev, "PCI IRQ %d -> rerouted to legacy "
+                                "IRQ %d\n", entry->index,
+                                (entry->index % 4) + 16);
+                       entry->index = (entry->index % 4) + 16;
+                       return 1;
+               default:
+                       dev_warn(&dev->dev, "Cannot reroute IRQ %d to legacy "
+                                "IRQ: unknown mapping\n", entry->index);
+                       return -1;
+               }
+       }
+}
+#endif /* CONFIG_X86_IO_APIC */
+
 static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin)
 {
        struct acpi_prt_entry *entry;
@@ -311,6 +366,9 @@ static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin)
 
        entry = acpi_pci_irq_find_prt_entry(dev, pin);
        if (entry) {
+#ifdef CONFIG_X86_IO_APIC
+               acpi_reroute_boot_interrupt(dev, entry);
+#endif /* CONFIG_X86_IO_APIC */
                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %s[%c] _PRT entry\n",
                                  pci_name(dev), pin_name(pin)));
                return entry;
index d06078d..2672c79 100644 (file)
@@ -485,7 +485,8 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
                root->secondary.end = 0xFF;
                printk(KERN_WARNING FW_BUG PREFIX
                       "no secondary bus range in _CRS\n");
-               status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN,                                               NULL, &bus);
+               status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN,
+                                              NULL, &bus);
                if (ACPI_SUCCESS(status))
                        root->secondary.start = bus;
                else if (status == AE_NOT_FOUND)
index 79cb653..870550d 100644 (file)
@@ -244,7 +244,7 @@ processor_set_cur_state(struct thermal_cooling_device *cdev,
        return result;
 }
 
-struct thermal_cooling_device_ops processor_cooling_ops = {
+const struct thermal_cooling_device_ops processor_cooling_ops = {
        .get_max_state = processor_get_max_state,
        .get_cur_state = processor_get_cur_state,
        .set_cur_state = processor_set_cur_state,
index 50658ff..6e36d0c 100644 (file)
@@ -130,6 +130,9 @@ struct acpi_sbs {
 
 #define to_acpi_sbs(x) container_of(x, struct acpi_sbs, charger)
 
+static int acpi_sbs_remove(struct acpi_device *device, int type);
+static int acpi_battery_get_state(struct acpi_battery *battery);
+
 static inline int battery_scale(int log)
 {
        int scale = 1;
@@ -195,6 +198,8 @@ static int acpi_sbs_battery_get_property(struct power_supply *psy,
 
        if ((!battery->present) && psp != POWER_SUPPLY_PROP_PRESENT)
                return -ENODEV;
+
+       acpi_battery_get_state(battery);
        switch (psp) {
        case POWER_SUPPLY_PROP_STATUS:
                if (battery->rate_now < 0)
@@ -225,11 +230,17 @@ static int acpi_sbs_battery_get_property(struct power_supply *psy,
        case POWER_SUPPLY_PROP_POWER_NOW:
                val->intval = abs(battery->rate_now) *
                                acpi_battery_ipscale(battery) * 1000;
+               val->intval *= (acpi_battery_mode(battery)) ?
+                               (battery->voltage_now *
+                               acpi_battery_vscale(battery) / 1000) : 1;
                break;
        case POWER_SUPPLY_PROP_CURRENT_AVG:
        case POWER_SUPPLY_PROP_POWER_AVG:
                val->intval = abs(battery->rate_avg) *
                                acpi_battery_ipscale(battery) * 1000;
+               val->intval *= (acpi_battery_mode(battery)) ?
+                               (battery->voltage_now *
+                               acpi_battery_vscale(battery) / 1000) : 1;
                break;
        case POWER_SUPPLY_PROP_CAPACITY:
                val->intval = battery->state_of_charge;
@@ -903,8 +914,6 @@ static void acpi_sbs_callback(void *context)
        }
 }
 
-static int acpi_sbs_remove(struct acpi_device *device, int type);
-
 static int acpi_sbs_add(struct acpi_device *device)
 {
        struct acpi_sbs *sbs;
index 6c94960..3ed80b2 100644 (file)
@@ -428,6 +428,22 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
                DMI_MATCH(DMI_PRODUCT_NAME, "1000 Series"),
                },
        },
+       {
+       .callback = init_old_suspend_ordering,
+       .ident = "Asus A8N-SLI DELUXE",
+       .matches = {
+               DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+               DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI DELUXE"),
+               },
+       },
+       {
+       .callback = init_old_suspend_ordering,
+       .ident = "Asus A8N-SLI Premium",
+       .matches = {
+               DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+               DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI Premium"),
+               },
+       },
        {},
 };
 #endif /* CONFIG_SUSPEND */
index 77255f2..c538d0e 100644 (file)
@@ -149,12 +149,12 @@ static int param_get_debug_level(char *buffer, const struct kernel_param *kp)
        return result;
 }
 
-static struct kernel_param_ops param_ops_debug_layer = {
+static const struct kernel_param_ops param_ops_debug_layer = {
        .set = param_set_uint,
        .get = param_get_debug_layer,
 };
 
-static struct kernel_param_ops param_ops_debug_level = {
+static const struct kernel_param_ops param_ops_debug_level = {
        .set = param_set_uint,
        .get = param_get_debug_level,
 };
index 2607e17..48fbc64 100644 (file)
@@ -812,7 +812,7 @@ acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal,
                                thermal_zone_unbind_cooling_device);
 }
 
-static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
+static const struct thermal_zone_device_ops acpi_thermal_zone_ops = {
        .bind = acpi_thermal_bind_cooling_device,
        .unbind = acpi_thermal_unbind_cooling_device,
        .get_temp = thermal_get_temp,
index ada4b4d..08a44b5 100644 (file)
@@ -307,7 +307,7 @@ video_set_cur_state(struct thermal_cooling_device *cooling_dev, unsigned long st
        return acpi_video_device_lcd_set_level(video, level);
 }
 
-static struct thermal_cooling_device_ops video_cooling_ops = {
+static const struct thermal_cooling_device_ops video_cooling_ops = {
        .get_max_state = video_get_max_state,
        .get_cur_state = video_get_cur_state,
        .set_cur_state = video_set_cur_state,
index ca3e6be..5987e0b 100644 (file)
@@ -468,6 +468,15 @@ config PATA_ICSIDE
          interface card.  This is not required for ICS partition support.
          If you are unsure, say N to this.
 
+config PATA_IMX
+       tristate "PATA support for Freescale iMX"
+       depends on ARCH_MXC
+       help
+         This option enables support for the PATA host available on Freescale
+          iMX SoCs.
+
+         If unsure, say N.
+
 config PATA_IT8213
        tristate "IT8213 PATA support (Experimental)"
        depends on PCI && EXPERIMENTAL
index 8ac64e1..9550d69 100644 (file)
@@ -48,6 +48,7 @@ obj-$(CONFIG_PATA_HPT37X)     += pata_hpt37x.o
 obj-$(CONFIG_PATA_HPT3X2N)     += pata_hpt3x2n.o
 obj-$(CONFIG_PATA_HPT3X3)      += pata_hpt3x3.o
 obj-$(CONFIG_PATA_ICSIDE)      += pata_icside.o
+obj-$(CONFIG_PATA_IMX)         += pata_imx.o
 obj-$(CONFIG_PATA_IT8213)      += pata_it8213.o
 obj-$(CONFIG_PATA_IT821X)      += pata_it821x.o
 obj-$(CONFIG_PATA_JMICRON)     += pata_jmicron.o
index e0a5b55..bb7c5f1 100644 (file)
@@ -218,12 +218,12 @@ static void ata_acpi_dev_uevent(acpi_handle handle, u32 event, void *data)
        ata_acpi_uevent(dev->link->ap, dev, event);
 }
 
-static struct acpi_dock_ops ata_acpi_dev_dock_ops = {
+static const struct acpi_dock_ops ata_acpi_dev_dock_ops = {
        .handler = ata_acpi_dev_notify_dock,
        .uevent = ata_acpi_dev_uevent,
 };
 
-static struct acpi_dock_ops ata_acpi_ap_dock_ops = {
+static const struct acpi_dock_ops ata_acpi_ap_dock_ops = {
        .handler = ata_acpi_ap_notify_dock,
        .uevent = ata_acpi_ap_uevent,
 };
diff --git a/drivers/ata/pata_imx.c b/drivers/ata/pata_imx.c
new file mode 100644 (file)
index 0000000..ca9d9ca
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * Freescale iMX PATA driver
+ *
+ * Copyright (C) 2011 Arnaud Patard <arnaud.patard@rtp-net.org>
+ *
+ * Based on pata_platform - Copyright (C) 2006 - 2007  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * TODO:
+ * - dmaengine support
+ * - check if timing stuff needed
+ */
+#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/clk.h>
+
+#define DRV_NAME "pata_imx"
+
+#define PATA_IMX_ATA_CONTROL           0x24
+#define PATA_IMX_ATA_CTRL_FIFO_RST_B   (1<<7)
+#define PATA_IMX_ATA_CTRL_ATA_RST_B    (1<<6)
+#define PATA_IMX_ATA_CTRL_IORDY_EN     (1<<0)
+#define PATA_IMX_ATA_INT_EN            0x2C
+#define PATA_IMX_ATA_INTR_ATA_INTRQ2   (1<<3)
+#define PATA_IMX_DRIVE_DATA            0xA0
+#define PATA_IMX_DRIVE_CONTROL         0xD8
+
+struct pata_imx_priv {
+       struct clk *clk;
+       /* timings/interrupt/control regs */
+       u8 *host_regs;
+       u32 ata_ctl;
+};
+
+static int pata_imx_set_mode(struct ata_link *link, struct ata_device **unused)
+{
+       struct ata_device *dev;
+       struct ata_port *ap = link->ap;
+       struct pata_imx_priv *priv = ap->host->private_data;
+       u32 val;
+
+       ata_for_each_dev(dev, link, ENABLED) {
+               dev->pio_mode = dev->xfer_mode = XFER_PIO_0;
+               dev->xfer_shift = ATA_SHIFT_PIO;
+               dev->flags |= ATA_DFLAG_PIO;
+
+               val = __raw_readl(priv->host_regs + PATA_IMX_ATA_CONTROL);
+               if (ata_pio_need_iordy(dev))
+                       val |= PATA_IMX_ATA_CTRL_IORDY_EN;
+               else
+                       val &= ~PATA_IMX_ATA_CTRL_IORDY_EN;
+               __raw_writel(val, priv->host_regs + PATA_IMX_ATA_CONTROL);
+
+               ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
+       }
+       return 0;
+}
+
+static struct scsi_host_template pata_imx_sht = {
+       ATA_PIO_SHT(DRV_NAME),
+};
+
+static struct ata_port_operations pata_imx_port_ops = {
+       .inherits               = &ata_sff_port_ops,
+       .sff_data_xfer          = ata_sff_data_xfer_noirq,
+       .cable_detect           = ata_cable_unknown,
+       .set_mode               = pata_imx_set_mode,
+};
+
+static void pata_imx_setup_port(struct ata_ioports *ioaddr)
+{
+       /* Fixup the port shift for platforms that need it */
+       ioaddr->data_addr       = ioaddr->cmd_addr + (ATA_REG_DATA    << 2);
+       ioaddr->error_addr      = ioaddr->cmd_addr + (ATA_REG_ERR     << 2);
+       ioaddr->feature_addr    = ioaddr->cmd_addr + (ATA_REG_FEATURE << 2);
+       ioaddr->nsect_addr      = ioaddr->cmd_addr + (ATA_REG_NSECT   << 2);
+       ioaddr->lbal_addr       = ioaddr->cmd_addr + (ATA_REG_LBAL    << 2);
+       ioaddr->lbam_addr       = ioaddr->cmd_addr + (ATA_REG_LBAM    << 2);
+       ioaddr->lbah_addr       = ioaddr->cmd_addr + (ATA_REG_LBAH    << 2);
+       ioaddr->device_addr     = ioaddr->cmd_addr + (ATA_REG_DEVICE  << 2);
+       ioaddr->status_addr     = ioaddr->cmd_addr + (ATA_REG_STATUS  << 2);
+       ioaddr->command_addr    = ioaddr->cmd_addr + (ATA_REG_CMD     << 2);
+}
+
+static int __devinit pata_imx_probe(struct platform_device *pdev)
+{
+       struct ata_host *host;
+       struct ata_port *ap;
+       struct pata_imx_priv *priv;
+       int irq = 0;
+       struct resource *io_res;
+
+       io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (io_res == NULL)
+               return -EINVAL;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0)
+               return -EINVAL;
+
+       priv = devm_kzalloc(&pdev->dev,
+                               sizeof(struct pata_imx_priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(priv->clk)) {
+               dev_err(&pdev->dev, "Failed to get clock\n");
+               return PTR_ERR(priv->clk);
+       }
+
+       clk_enable(priv->clk);
+
+       host = ata_host_alloc(&pdev->dev, 1);
+       if (!host)
+               goto free_priv;
+
+       host->private_data = priv;
+       ap = host->ports[0];
+
+       ap->ops = &pata_imx_port_ops;
+       ap->pio_mask = ATA_PIO0;
+       ap->flags |= ATA_FLAG_SLAVE_POSS;
+
+       priv->host_regs = devm_ioremap(&pdev->dev, io_res->start,
+               resource_size(io_res));
+       if (!priv->host_regs) {
+               dev_err(&pdev->dev, "failed to map IO/CTL base\n");
+               goto free_priv;
+       }
+
+       ap->ioaddr.cmd_addr = priv->host_regs + PATA_IMX_DRIVE_DATA;
+       ap->ioaddr.ctl_addr = priv->host_regs + PATA_IMX_DRIVE_CONTROL;
+
+       ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr;
+
+       pata_imx_setup_port(&ap->ioaddr);
+
+       ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx",
+               (unsigned long long)io_res->start + PATA_IMX_DRIVE_DATA,
+               (unsigned long long)io_res->start + PATA_IMX_DRIVE_CONTROL);
+
+       /* deassert resets */
+       __raw_writel(PATA_IMX_ATA_CTRL_FIFO_RST_B |
+                       PATA_IMX_ATA_CTRL_ATA_RST_B,
+                       priv->host_regs + PATA_IMX_ATA_CONTROL);
+       /* enable interrupts */
+       __raw_writel(PATA_IMX_ATA_INTR_ATA_INTRQ2,
+                       priv->host_regs + PATA_IMX_ATA_INT_EN);
+
+       /* activate */
+       return ata_host_activate(host, irq, ata_sff_interrupt, 0,
+                               &pata_imx_sht);
+
+free_priv:
+       clk_disable(priv->clk);
+       clk_put(priv->clk);
+       return -ENOMEM;
+}
+
+static int __devexit pata_imx_remove(struct platform_device *pdev)
+{
+       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct pata_imx_priv *priv = host->private_data;
+
+       ata_host_detach(host);
+
+       __raw_writel(0, priv->host_regs + PATA_IMX_ATA_INT_EN);
+
+       clk_disable(priv->clk);
+       clk_put(priv->clk);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int pata_imx_suspend(struct device *dev)
+{
+       struct ata_host *host = dev_get_drvdata(dev);
+       struct pata_imx_priv *priv = host->private_data;
+       int ret;
+
+       ret = ata_host_suspend(host, PMSG_SUSPEND);
+       if (!ret) {
+               __raw_writel(0, priv->host_regs + PATA_IMX_ATA_INT_EN);
+               priv->ata_ctl =
+                       __raw_readl(priv->host_regs + PATA_IMX_ATA_CONTROL);
+               clk_disable(priv->clk);
+       }
+
+       return ret;
+}
+
+static int pata_imx_resume(struct device *dev)
+{
+       struct ata_host *host = dev_get_drvdata(dev);
+       struct pata_imx_priv *priv = host->private_data;
+
+       clk_enable(priv->clk);
+
+       __raw_writel(priv->ata_ctl, priv->host_regs + PATA_IMX_ATA_CONTROL);
+
+       __raw_writel(PATA_IMX_ATA_INTR_ATA_INTRQ2,
+                       priv->host_regs + PATA_IMX_ATA_INT_EN);
+
+       ata_host_resume(host);
+
+       return 0;
+}
+
+static const struct dev_pm_ops pata_imx_pm_ops = {
+       .suspend        = pata_imx_suspend,
+       .resume         = pata_imx_resume,
+};
+#endif
+
+static struct platform_driver pata_imx_driver = {
+       .probe          = pata_imx_probe,
+       .remove         = __devexit_p(pata_imx_remove),
+       .driver = {
+               .name           = DRV_NAME,
+               .owner          = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm             = &pata_imx_pm_ops,
+#endif
+       },
+};
+
+static int __init pata_imx_init(void)
+{
+       return platform_driver_register(&pata_imx_driver);
+}
+
+static void __exit pata_imx_exit(void)
+{
+       platform_driver_unregister(&pata_imx_driver);
+}
+module_init(pata_imx_init);
+module_exit(pata_imx_exit);
+
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
+MODULE_DESCRIPTION("low-level driver for iMX PATA");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
index 65e4be6..8e9f504 100644 (file)
@@ -124,6 +124,17 @@ static const struct via_isa_bridge {
        { NULL }
 };
 
+static const struct dmi_system_id no_atapi_dma_dmi_table[] = {
+       {
+               .ident = "AVERATEC 3200",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "AVERATEC"),
+                       DMI_MATCH(DMI_BOARD_NAME, "3200"),
+               },
+       },
+       { }
+};
+
 struct via_port {
        u8 cached_device;
 };
@@ -355,6 +366,13 @@ static unsigned long via_mode_filter(struct ata_device *dev, unsigned long mask)
                        mask &= ~ ATA_MASK_UDMA;
                }
        }
+
+       if (dev->class == ATA_DEV_ATAPI &&
+           dmi_check_system(no_atapi_dma_dmi_table)) {
+               ata_dev_warn(dev, "controller locks up on ATAPI DMA, forcing PIO\n");
+               mask &= ATA_MASK_PIO;
+       }
+
        return mask;
 }
 
index 0a9a774..5c42374 100644 (file)
@@ -1329,7 +1329,7 @@ static int sata_dwc_port_start(struct ata_port *ap)
                        dev_err(ap->dev, "%s: dma_alloc_coherent failed\n",
                                 __func__);
                        err = -ENOMEM;
-                       goto CLEANUP;
+                       goto CLEANUP_ALLOC;
                }
        }
 
@@ -1349,15 +1349,13 @@ static int sata_dwc_port_start(struct ata_port *ap)
        /* Clear any error bits before libata starts issuing commands */
        clear_serror();
        ap->private_data = hsdevp;
+       dev_dbg(ap->dev, "%s: done\n", __func__);
+       return 0;
 
+CLEANUP_ALLOC:
+       kfree(hsdevp);
 CLEANUP:
-       if (err) {
-               sata_dwc_port_stop(ap);
-               dev_dbg(ap->dev, "%s: fail\n", __func__);
-       } else {
-               dev_dbg(ap->dev, "%s: done\n", __func__);
-       }
-
+       dev_dbg(ap->dev, "%s: fail. ap->id = %d\n", __func__, ap->print_id);
        return err;
 }
 
index 98c1d78..9dfb40b 100644 (file)
@@ -438,7 +438,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
        u8 status;
 
        if (unlikely(bmdma2 & SIL_DMA_SATA_IRQ)) {
-               u32 serror;
+               u32 serror = 0xffffffff;
 
                /* SIEN doesn't mask SATA IRQs on some 3112s.  Those
                 * controllers continue to assert IRQ as long as
index b89fffc..33e1bed 100644 (file)
@@ -166,7 +166,7 @@ static int create_path(const char *nodepath)
 {
        char *path;
        char *s;
-       int err;
+       int err = 0;
 
        /* parent directories do not exist, create them */
        path = kstrdup(nodepath, GFP_KERNEL);
index be8714a..1c37457 100644 (file)
@@ -80,7 +80,6 @@ static void genpd_set_active(struct generic_pm_domain *genpd)
 int pm_genpd_poweron(struct generic_pm_domain *genpd)
 {
        struct generic_pm_domain *parent = genpd->parent;
-       DEFINE_WAIT(wait);
        int ret = 0;
 
  start:
@@ -112,7 +111,7 @@ int pm_genpd_poweron(struct generic_pm_domain *genpd)
        }
 
        if (genpd->power_on) {
-               int ret = genpd->power_on(genpd);
+               ret = genpd->power_on(genpd);
                if (ret)
                        goto out;
        }
@@ -461,6 +460,21 @@ static int pm_genpd_runtime_resume(struct device *dev)
        return 0;
 }
 
+/**
+ * pm_genpd_poweroff_unused - Power off all PM domains with no devices in use.
+ */
+void pm_genpd_poweroff_unused(void)
+{
+       struct generic_pm_domain *genpd;
+
+       mutex_lock(&gpd_list_lock);
+
+       list_for_each_entry(genpd, &gpd_list, gpd_list_node)
+               genpd_queue_power_off_work(genpd);
+
+       mutex_unlock(&gpd_list_lock);
+}
+
 #else
 
 static inline void genpd_power_off_work_fn(struct work_struct *work) {}
@@ -1256,18 +1270,3 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
        list_add(&genpd->gpd_list_node, &gpd_list);
        mutex_unlock(&gpd_list_lock);
 }
-
-/**
- * pm_genpd_poweroff_unused - Power off all PM domains with no devices in use.
- */
-void pm_genpd_poweroff_unused(void)
-{
-       struct generic_pm_domain *genpd;
-
-       mutex_lock(&gpd_list_lock);
-
-       list_for_each_entry(genpd, &gpd_list, gpd_list_node)
-               genpd_queue_power_off_work(genpd);
-
-       mutex_unlock(&gpd_list_lock);
-}
index 8dc247c..acb3f83 100644 (file)
@@ -226,11 +226,17 @@ static int rpm_idle(struct device *dev, int rpmflags)
                callback = NULL;
 
        if (callback) {
-               spin_unlock_irq(&dev->power.lock);
+               if (dev->power.irq_safe)
+                       spin_unlock(&dev->power.lock);
+               else
+                       spin_unlock_irq(&dev->power.lock);
 
                callback(dev);
 
-               spin_lock_irq(&dev->power.lock);
+               if (dev->power.irq_safe)
+                       spin_lock(&dev->power.lock);
+               else
+                       spin_lock_irq(&dev->power.lock);
        }
 
        dev->power.idle_notification = false;
index c2231ff..c4f7a45 100644 (file)
@@ -113,3 +113,4 @@ struct regmap *regmap_init_i2c(struct i2c_client *i2c,
 }
 EXPORT_SYMBOL_GPL(regmap_init_i2c);
 
+MODULE_LICENSE("GPL");
index 4deba06..f839694 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/regmap.h>
 #include <linux/spi/spi.h>
 #include <linux/init.h>
+#include <linux/module.h>
 
 static int regmap_spi_write(struct device *dev, const void *data, size_t count)
 {
@@ -70,3 +71,5 @@ struct regmap *regmap_init_spi(struct spi_device *spi,
        return regmap_init(&spi->dev, &regmap_spi, config);
 }
 EXPORT_SYMBOL_GPL(regmap_init_spi);
+
+MODULE_LICENSE("GPL");
index cf3565c..0eef4da 100644 (file)
@@ -317,7 +317,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
                u8[0] |= map->bus->read_flag_mask;
 
        ret = map->bus->read(map->dev, map->work_buf, map->format.reg_bytes,
-                            val, map->format.val_bytes);
+                            val, val_len);
        if (ret != 0)
                return ret;
 
index 717d6e4..6f07ec1 100644 (file)
@@ -256,6 +256,21 @@ config BLK_DEV_LOOP
 
          Most users will answer N here.
 
+config BLK_DEV_LOOP_MIN_COUNT
+       int "Number of loop devices to pre-create at init time"
+       depends on BLK_DEV_LOOP
+       default 8
+       help
+         Static number of loop devices to be unconditionally pre-created
+         at init time.
+
+         This default value can be overwritten on the kernel command
+         line or with module-parameter loop.max_loop.
+
+         The historic default is 8. If a late 2011 version of losetup(8)
+         is used, it can be set to 0, since needed loop devices can be
+         dynamically allocated with the /dev/loop-control interface.
+
 config BLK_DEV_CRYPTOLOOP
        tristate "Cryptoloop Support"
        select CRYPTO
@@ -471,7 +486,7 @@ config XEN_BLKDEV_FRONTEND
          in another domain which drives the actual block device.
 
 config XEN_BLKDEV_BACKEND
-       tristate "Block-device backend driver"
+       tristate "Xen block-device backend driver"
        depends on XEN_BACKEND
        help
          The block-device backend driver allows the kernel to export its
index 515bcd9..0feab26 100644 (file)
@@ -1829,10 +1829,10 @@ static int drbd_nl_syncer_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *n
 
        /* silently ignore cpu mask on UP kernel */
        if (nr_cpu_ids > 1 && sc.cpu_mask[0] != 0) {
-               err = __bitmap_parse(sc.cpu_mask, 32, 0,
+               err = bitmap_parse(sc.cpu_mask, 32,
                                cpumask_bits(new_cpu_mask), nr_cpu_ids);
                if (err) {
-                       dev_warn(DEV, "__bitmap_parse() failed with %d\n", err);
+                       dev_warn(DEV, "bitmap_parse() failed with %d\n", err);
                        retcode = ERR_CPU_MASK_PARSE;
                        goto fail;
                }
index 76c8da7..4720c7a 100644 (file)
 #include <linux/kthread.h>
 #include <linux/splice.h>
 #include <linux/sysfs.h>
-
+#include <linux/miscdevice.h>
 #include <asm/uaccess.h>
 
-static LIST_HEAD(loop_devices);
-static DEFINE_MUTEX(loop_devices_mutex);
+static DEFINE_IDR(loop_index_idr);
+static DEFINE_MUTEX(loop_index_mutex);
 
 static int max_part;
 static int part_shift;
@@ -722,17 +722,10 @@ static inline int is_loop_device(struct file *file)
 static ssize_t loop_attr_show(struct device *dev, char *page,
                              ssize_t (*callback)(struct loop_device *, char *))
 {
-       struct loop_device *l, *lo = NULL;
-
-       mutex_lock(&loop_devices_mutex);
-       list_for_each_entry(l, &loop_devices, lo_list)
-               if (disk_to_dev(l->lo_disk) == dev) {
-                       lo = l;
-                       break;
-               }
-       mutex_unlock(&loop_devices_mutex);
+       struct gendisk *disk = dev_to_disk(dev);
+       struct loop_device *lo = disk->private_data;
 
-       return lo ? callback(lo, page) : -EIO;
+       return callback(lo, page);
 }
 
 #define LOOP_ATTR_RO(_name)                                            \
@@ -750,10 +743,10 @@ static ssize_t loop_attr_backing_file_show(struct loop_device *lo, char *buf)
        ssize_t ret;
        char *p = NULL;
 
-       mutex_lock(&lo->lo_ctl_mutex);
+       spin_lock_irq(&lo->lo_lock);
        if (lo->lo_backing_file)
                p = d_path(&lo->lo_backing_file->f_path, buf, PAGE_SIZE - 1);
-       mutex_unlock(&lo->lo_ctl_mutex);
+       spin_unlock_irq(&lo->lo_lock);
 
        if (IS_ERR_OR_NULL(p))
                ret = PTR_ERR(p);
@@ -1007,7 +1000,9 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
 
        kthread_stop(lo->lo_thread);
 
+       spin_lock_irq(&lo->lo_lock);
        lo->lo_backing_file = NULL;
+       spin_unlock_irq(&lo->lo_lock);
 
        loop_release_xfer(lo);
        lo->transfer = NULL;
@@ -1485,13 +1480,22 @@ static int lo_compat_ioctl(struct block_device *bdev, fmode_t mode,
 
 static int lo_open(struct block_device *bdev, fmode_t mode)
 {
-       struct loop_device *lo = bdev->bd_disk->private_data;
+       struct loop_device *lo;
+       int err = 0;
+
+       mutex_lock(&loop_index_mutex);
+       lo = bdev->bd_disk->private_data;
+       if (!lo) {
+               err = -ENXIO;
+               goto out;
+       }
 
        mutex_lock(&lo->lo_ctl_mutex);
        lo->lo_refcnt++;
        mutex_unlock(&lo->lo_ctl_mutex);
-
-       return 0;
+out:
+       mutex_unlock(&loop_index_mutex);
+       return err;
 }
 
 static int lo_release(struct gendisk *disk, fmode_t mode)
@@ -1557,40 +1561,71 @@ int loop_register_transfer(struct loop_func_table *funcs)
        return 0;
 }
 
+static int unregister_transfer_cb(int id, void *ptr, void *data)
+{
+       struct loop_device *lo = ptr;
+       struct loop_func_table *xfer = data;
+
+       mutex_lock(&lo->lo_ctl_mutex);
+       if (lo->lo_encryption == xfer)
+               loop_release_xfer(lo);
+       mutex_unlock(&lo->lo_ctl_mutex);
+       return 0;
+}
+
 int loop_unregister_transfer(int number)
 {
        unsigned int n = number;
-       struct loop_device *lo;
        struct loop_func_table *xfer;
 
        if (n == 0 || n >= MAX_LO_CRYPT || (xfer = xfer_funcs[n]) == NULL)
                return -EINVAL;
 
        xfer_funcs[n] = NULL;
-
-       list_for_each_entry(lo, &loop_devices, lo_list) {
-               mutex_lock(&lo->lo_ctl_mutex);
-
-               if (lo->lo_encryption == xfer)
-                       loop_release_xfer(lo);
-
-               mutex_unlock(&lo->lo_ctl_mutex);
-       }
-
+       idr_for_each(&loop_index_idr, &unregister_transfer_cb, xfer);
        return 0;
 }
 
 EXPORT_SYMBOL(loop_register_transfer);
 EXPORT_SYMBOL(loop_unregister_transfer);
 
-static struct loop_device *loop_alloc(int i)
+static int loop_add(struct loop_device **l, int i)
 {
        struct loop_device *lo;
        struct gendisk *disk;
+       int err;
 
        lo = kzalloc(sizeof(*lo), GFP_KERNEL);
-       if (!lo)
+       if (!lo) {
+               err = -ENOMEM;
                goto out;
+       }
+
+       err = idr_pre_get(&loop_index_idr, GFP_KERNEL);
+       if (err < 0)
+               goto out_free_dev;
+
+       if (i >= 0) {
+               int m;
+
+               /* create specific i in the index */
+               err = idr_get_new_above(&loop_index_idr, lo, i, &m);
+               if (err >= 0 && i != m) {
+                       idr_remove(&loop_index_idr, m);
+                       err = -EEXIST;
+               }
+       } else if (i == -1) {
+               int m;
+
+               /* get next free nr */
+               err = idr_get_new(&loop_index_idr, lo, &m);
+               if (err >= 0)
+                       i = m;
+       } else {
+               err = -EINVAL;
+       }
+       if (err < 0)
+               goto out_free_dev;
 
        lo->lo_queue = blk_alloc_queue(GFP_KERNEL);
        if (!lo->lo_queue)
@@ -1611,81 +1646,158 @@ static struct loop_device *loop_alloc(int i)
        disk->private_data      = lo;
        disk->queue             = lo->lo_queue;
        sprintf(disk->disk_name, "loop%d", i);
-       return lo;
+       add_disk(disk);
+       *l = lo;
+       return lo->lo_number;
 
 out_free_queue:
        blk_cleanup_queue(lo->lo_queue);
 out_free_dev:
        kfree(lo);
 out:
-       return NULL;
+       return err;
 }
 
-static void loop_free(struct loop_device *lo)
+static void loop_remove(struct loop_device *lo)
 {
+       del_gendisk(lo->lo_disk);
        blk_cleanup_queue(lo->lo_queue);
        put_disk(lo->lo_disk);
-       list_del(&lo->lo_list);
        kfree(lo);
 }
 
-static struct loop_device *loop_init_one(int i)
+static int find_free_cb(int id, void *ptr, void *data)
+{
+       struct loop_device *lo = ptr;
+       struct loop_device **l = data;
+
+       if (lo->lo_state == Lo_unbound) {
+               *l = lo;
+               return 1;
+       }
+       return 0;
+}
+
+static int loop_lookup(struct loop_device **l, int i)
 {
        struct loop_device *lo;
+       int ret = -ENODEV;
 
-       list_for_each_entry(lo, &loop_devices, lo_list) {
-               if (lo->lo_number == i)
-                       return lo;
+       if (i < 0) {
+               int err;
+
+               err = idr_for_each(&loop_index_idr, &find_free_cb, &lo);
+               if (err == 1) {
+                       *l = lo;
+                       ret = lo->lo_number;
+               }
+               goto out;
        }
 
-       lo = loop_alloc(i);
+       /* lookup and return a specific i */
+       lo = idr_find(&loop_index_idr, i);
        if (lo) {
-               add_disk(lo->lo_disk);
-               list_add_tail(&lo->lo_list, &loop_devices);
+               *l = lo;
+               ret = lo->lo_number;
        }
-       return lo;
-}
-
-static void loop_del_one(struct loop_device *lo)
-{
-       del_gendisk(lo->lo_disk);
-       loop_free(lo);
+out:
+       return ret;
 }
 
 static struct kobject *loop_probe(dev_t dev, int *part, void *data)
 {
        struct loop_device *lo;
        struct kobject *kobj;
+       int err;
 
-       mutex_lock(&loop_devices_mutex);
-       lo = loop_init_one(MINOR(dev) >> part_shift);
-       kobj = lo ? get_disk(lo->lo_disk) : ERR_PTR(-ENOMEM);
-       mutex_unlock(&loop_devices_mutex);
+       mutex_lock(&loop_index_mutex);
+       err = loop_lookup(&lo, MINOR(dev) >> part_shift);
+       if (err < 0)
+               err = loop_add(&lo, MINOR(dev) >> part_shift);
+       if (err < 0)
+               kobj = ERR_PTR(err);
+       else
+               kobj = get_disk(lo->lo_disk);
+       mutex_unlock(&loop_index_mutex);
 
        *part = 0;
        return kobj;
 }
 
+static long loop_control_ioctl(struct file *file, unsigned int cmd,
+                              unsigned long parm)
+{
+       struct loop_device *lo;
+       int ret = -ENOSYS;
+
+       mutex_lock(&loop_index_mutex);
+       switch (cmd) {
+       case LOOP_CTL_ADD:
+               ret = loop_lookup(&lo, parm);
+               if (ret >= 0) {
+                       ret = -EEXIST;
+                       break;
+               }
+               ret = loop_add(&lo, parm);
+               break;
+       case LOOP_CTL_REMOVE:
+               ret = loop_lookup(&lo, parm);
+               if (ret < 0)
+                       break;
+               mutex_lock(&lo->lo_ctl_mutex);
+               if (lo->lo_state != Lo_unbound) {
+                       ret = -EBUSY;
+                       mutex_unlock(&lo->lo_ctl_mutex);
+                       break;
+               }
+               if (lo->lo_refcnt > 0) {
+                       ret = -EBUSY;
+                       mutex_unlock(&lo->lo_ctl_mutex);
+                       break;
+               }
+               lo->lo_disk->private_data = NULL;
+               mutex_unlock(&lo->lo_ctl_mutex);
+               idr_remove(&loop_index_idr, lo->lo_number);
+               loop_remove(lo);
+               break;
+       case LOOP_CTL_GET_FREE:
+               ret = loop_lookup(&lo, -1);
+               if (ret >= 0)
+                       break;
+               ret = loop_add(&lo, -1);
+       }
+       mutex_unlock(&loop_index_mutex);
+
+       return ret;
+}
+
+static const struct file_operations loop_ctl_fops = {
+       .open           = nonseekable_open,
+       .unlocked_ioctl = loop_control_ioctl,
+       .compat_ioctl   = loop_control_ioctl,
+       .owner          = THIS_MODULE,
+       .llseek         = noop_llseek,
+};
+
+static struct miscdevice loop_misc = {
+       .minor          = LOOP_CTRL_MINOR,
+       .name           = "loop-control",
+       .fops           = &loop_ctl_fops,
+};
+
+MODULE_ALIAS_MISCDEV(LOOP_CTRL_MINOR);
+MODULE_ALIAS("devname:loop-control");
+
 static int __init loop_init(void)
 {
        int i, nr;
        unsigned long range;
-       struct loop_device *lo, *next;
+       struct loop_device *lo;
+       int err;
 
-       /*
-        * loop module now has a feature to instantiate underlying device
-        * structure on-demand, provided that there is an access dev node.
-        * However, this will not work well with user space tool that doesn't
-        * know about such "feature".  In order to not break any existing
-        * tool, we do the following:
-        *
-        * (1) if max_loop is specified, create that many upfront, and this
-        *     also becomes a hard limit.
-        * (2) if max_loop is not specified, create 8 loop device on module
-        *     load, user can further extend loop device by create dev node
-        *     themselves and have kernel automatically instantiate actual
-        *     device on-demand.
-        */
+       err = misc_register(&loop_misc);
+       if (err < 0)
+               return err;
 
        part_shift = 0;
        if (max_part > 0) {
@@ -1708,57 +1820,60 @@ static int __init loop_init(void)
        if (max_loop > 1UL << (MINORBITS - part_shift))
                return -EINVAL;
 
+       /*
+        * If max_loop is specified, create that many devices upfront.
+        * This also becomes a hard limit. If max_loop is not specified,
+        * create CONFIG_BLK_DEV_LOOP_MIN_COUNT loop devices at module
+        * init time. Loop devices can be requested on-demand with the
+        * /dev/loop-control interface, or be instantiated by accessing
+        * a 'dead' device node.
+        */
        if (max_loop) {
                nr = max_loop;
                range = max_loop << part_shift;
        } else {
-               nr = 8;
+               nr = CONFIG_BLK_DEV_LOOP_MIN_COUNT;
                range = 1UL << MINORBITS;
        }
 
        if (register_blkdev(LOOP_MAJOR, "loop"))
                return -EIO;
 
-       for (i = 0; i < nr; i++) {
-               lo = loop_alloc(i);
-               if (!lo)
-                       goto Enomem;
-               list_add_tail(&lo->lo_list, &loop_devices);
-       }
-
-       /* point of no return */
-
-       list_for_each_entry(lo, &loop_devices, lo_list)
-               add_disk(lo->lo_disk);
-
        blk_register_region(MKDEV(LOOP_MAJOR, 0), range,
                                  THIS_MODULE, loop_probe, NULL, NULL);
 
+       /* pre-create number of devices given by config or max_loop */
+       mutex_lock(&loop_index_mutex);
+       for (i = 0; i < nr; i++)
+               loop_add(&lo, i);
+       mutex_unlock(&loop_index_mutex);
+
        printk(KERN_INFO "loop: module loaded\n");
        return 0;
+}
 
-Enomem:
-       printk(KERN_INFO "loop: out of memory\n");
-
-       list_for_each_entry_safe(lo, next, &loop_devices, lo_list)
-               loop_free(lo);
+static int loop_exit_cb(int id, void *ptr, void *data)
+{
+       struct loop_device *lo = ptr;
 
-       unregister_blkdev(LOOP_MAJOR, "loop");
-       return -ENOMEM;
+       loop_remove(lo);
+       return 0;
 }
 
 static void __exit loop_exit(void)
 {
        unsigned long range;
-       struct loop_device *lo, *next;
 
        range = max_loop ? max_loop << part_shift : 1UL << MINORBITS;
 
-       list_for_each_entry_safe(lo, next, &loop_devices, lo_list)
-               loop_del_one(lo);
+       idr_for_each(&loop_index_idr, &loop_exit_cb, NULL);
+       idr_remove_all(&loop_index_idr);
+       idr_destroy(&loop_index_idr);
 
        blk_unregister_region(MKDEV(LOOP_MAJOR, 0), range);
        unregister_blkdev(LOOP_MAJOR, "loop");
+
+       misc_deregister(&loop_misc);
 }
 
 module_init(loop_init);
index 773bfa7..ae3e167 100644 (file)
@@ -1184,6 +1184,7 @@ static struct of_device_id swim3_match[] =
        {
        .compatible     = "swim3"
        },
+       { /* end of list */ }
 };
 
 static struct macio_driver swim3_driver =
index b536a9c..9ea8c25 100644 (file)
@@ -123,8 +123,8 @@ static DEFINE_SPINLOCK(minor_lock);
 #define BLKIF_MINOR_EXT(dev) ((dev)&(~EXTENDED))
 #define EMULATED_HD_DISK_MINOR_OFFSET (0)
 #define EMULATED_HD_DISK_NAME_OFFSET (EMULATED_HD_DISK_MINOR_OFFSET / 256)
-#define EMULATED_SD_DISK_MINOR_OFFSET (EMULATED_HD_DISK_MINOR_OFFSET + (4 * 16))
-#define EMULATED_SD_DISK_NAME_OFFSET (EMULATED_HD_DISK_NAME_OFFSET + 4)
+#define EMULATED_SD_DISK_MINOR_OFFSET (0)
+#define EMULATED_SD_DISK_NAME_OFFSET (EMULATED_SD_DISK_MINOR_OFFSET / 256)
 
 #define DEV_NAME       "xvd"   /* name in /dev */
 
@@ -529,7 +529,7 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
                minor = BLKIF_MINOR_EXT(info->vdevice);
                nr_parts = PARTS_PER_EXT_DISK;
                offset = minor / nr_parts;
-               if (xen_hvm_domain() && offset <= EMULATED_HD_DISK_NAME_OFFSET + 4)
+               if (xen_hvm_domain() && offset < EMULATED_HD_DISK_NAME_OFFSET + 4)
                        printk(KERN_WARNING "blkfront: vdevice 0x%x might conflict with "
                                        "emulated IDE disks,\n\t choose an xvd device name"
                                        "from xvde on\n", info->vdevice);
index 75fb965..f997c27 100644 (file)
@@ -1929,11 +1929,17 @@ static int dvd_read_manufact(struct cdrom_device_info *cdi, dvd_struct *s,
                goto out;
 
        s->manufact.len = buf[0] << 8 | buf[1];
-       if (s->manufact.len < 0 || s->manufact.len > 2048) {
+       if (s->manufact.len < 0) {
                cdinfo(CD_WARNING, "Received invalid manufacture info length"
                                   " (%d)\n", s->manufact.len);
                ret = -EIO;
        } else {
+               if (s->manufact.len > 2048) {
+                       cdinfo(CD_WARNING, "Received invalid manufacture info "
+                                       "length (%d): truncating to 2048\n",
+                                       s->manufact.len);
+                       s->manufact.len = 2048;
+               }
                memcpy(s->manufact.value, &buf[4], s->manufact.len);
        }
 
index 49502bc..423fd56 100644 (file)
@@ -616,5 +616,16 @@ config MSM_SMD_PKT
          Enables userspace clients to read and write to some packet SMD
          ports via device interface for MSM chipset.
 
+config TILE_SROM
+       bool "Character-device access via hypervisor to the Tilera SPI ROM"
+       depends on TILE
+       default y
+       ---help---
+         This device provides character-level read-write access
+         to the SROM, typically via the "0", "1", and "2" devices
+         in /dev/srom/.  The Tilera hypervisor makes the flash
+         device appear much like a simple EEPROM, and knows
+         how to partition a single ROM for multiple purposes.
+
 endmenu
 
index 7a00672..32762ba 100644 (file)
@@ -63,3 +63,5 @@ obj-$(CONFIG_RAMOOPS)         += ramoops.o
 
 obj-$(CONFIG_JS_RTC)           += js-rtc.o
 js-rtc-y = rtc.o
+
+obj-$(CONFIG_TILE_SROM)                += tile-srom.o
index ac6739e..c3de70d 100644 (file)
@@ -1,6 +1,6 @@
 /* n2-drv.c: Niagara-2 RNG driver.
  *
- * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2008, 2011 David S. Miller <davem@davemloft.net>
  */
 
 #include <linux/kernel.h>
@@ -22,8 +22,8 @@
 
 #define DRV_MODULE_NAME                "n2rng"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "0.1"
-#define DRV_MODULE_RELDATE     "May 15, 2008"
+#define DRV_MODULE_VERSION     "0.2"
+#define DRV_MODULE_RELDATE     "July 27, 2011"
 
 static char version[] __devinitdata =
        DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
@@ -623,14 +623,14 @@ static const struct of_device_id n2rng_match[];
 static int __devinit n2rng_probe(struct platform_device *op)
 {
        const struct of_device_id *match;
-       int victoria_falls;
+       int multi_capable;
        int err = -ENOMEM;
        struct n2rng *np;
 
        match = of_match_device(n2rng_match, &op->dev);
        if (!match)
                return -EINVAL;
-       victoria_falls = (match->data != NULL);
+       multi_capable = (match->data != NULL);
 
        n2rng_driver_version();
        np = kzalloc(sizeof(*np), GFP_KERNEL);
@@ -640,8 +640,8 @@ static int __devinit n2rng_probe(struct platform_device *op)
 
        INIT_DELAYED_WORK(&np->work, n2rng_work);
 
-       if (victoria_falls)
-               np->flags |= N2RNG_FLAG_VF;
+       if (multi_capable)
+               np->flags |= N2RNG_FLAG_MULTI;
 
        err = -ENODEV;
        np->hvapi_major = 2;
@@ -658,10 +658,10 @@ static int __devinit n2rng_probe(struct platform_device *op)
                }
        }
 
-       if (np->flags & N2RNG_FLAG_VF) {
+       if (np->flags & N2RNG_FLAG_MULTI) {
                if (np->hvapi_major < 2) {
-                       dev_err(&op->dev, "VF RNG requires HVAPI major "
-                               "version 2 or later, got %lu\n",
+                       dev_err(&op->dev, "multi-unit-capable RNG requires "
+                               "HVAPI major version 2 or later, got %lu\n",
                                np->hvapi_major);
                        goto out_hvapi_unregister;
                }
@@ -688,8 +688,8 @@ static int __devinit n2rng_probe(struct platform_device *op)
                goto out_free_units;
 
        dev_info(&op->dev, "Found %s RNG, units: %d\n",
-                ((np->flags & N2RNG_FLAG_VF) ?
-                 "Victoria Falls" : "Niagara2"),
+                ((np->flags & N2RNG_FLAG_MULTI) ?
+                 "multi-unit-capable" : "single-unit"),
                 np->num_units);
 
        np->hwrng.name = "n2rng";
@@ -751,6 +751,11 @@ static const struct of_device_id n2rng_match[] = {
                .compatible     = "SUNW,vf-rng",
                .data           = (void *) 1,
        },
+       {
+               .name           = "random-number-generator",
+               .compatible     = "SUNW,kt-rng",
+               .data           = (void *) 1,
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, n2rng_match);
index 4bea07f..f244ac8 100644 (file)
@@ -68,7 +68,7 @@ struct n2rng {
        struct platform_device  *op;
 
        unsigned long           flags;
-#define N2RNG_FLAG_VF          0x00000001 /* Victoria Falls RNG, else N2 */
+#define N2RNG_FLAG_MULTI       0x00000001 /* Multi-unit capable RNG */
 #define N2RNG_FLAG_CONTROL     0x00000002 /* Operating in control domain */
 #define N2RNG_FLAG_READY       0x00000008 /* Ready for hw-rng layer      */
 #define N2RNG_FLAG_SHUTDOWN    0x00000010 /* Driver unregistering        */
index bd9b94b..810aff9 100644 (file)
@@ -22,6 +22,7 @@
 #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>
@@ -146,6 +147,14 @@ static int __init ramoops_probe(struct platform_device *pdev)
        cxt->phys_addr = pdata->mem_address;
        cxt->record_size = pdata->record_size;
        cxt->dump_oops = pdata->dump_oops;
+       /*
+        * 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;
 
        if (!request_mem_region(cxt->phys_addr, cxt->size, "ramoops")) {
                pr_err("request mem region failed\n");
index 7292819..c35a785 100644 (file)
@@ -1300,345 +1300,14 @@ ctl_table random_table[] = {
 };
 #endif         /* CONFIG_SYSCTL */
 
-/********************************************************************
- *
- * Random functions for networking
- *
- ********************************************************************/
-
-/*
- * TCP initial sequence number picking.  This uses the random number
- * generator to pick an initial secret value.  This value is hashed
- * along with the TCP endpoint information to provide a unique
- * starting point for each pair of TCP endpoints.  This defeats
- * attacks which rely on guessing the initial TCP sequence number.
- * This algorithm was suggested by Steve Bellovin.
- *
- * Using a very strong hash was taking an appreciable amount of the total
- * TCP connection establishment time, so this is a weaker hash,
- * compensated for by changing the secret periodically.
- */
-
-/* F, G and H are basic MD4 functions: selection, majority, parity */
-#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
-#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z)))
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-
-/*
- * The generic round function.  The application is so specific that
- * we don't bother protecting all the arguments with parens, as is generally
- * good macro practice, in favor of extra legibility.
- * Rotation is separate from addition to prevent recomputation
- */
-#define ROUND(f, a, b, c, d, x, s)     \
-       (a += f(b, c, d) + x, a = (a << s) | (a >> (32 - s)))
-#define K1 0
-#define K2 013240474631UL
-#define K3 015666365641UL
-
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-
-static __u32 twothirdsMD4Transform(__u32 const buf[4], __u32 const in[12])
-{
-       __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
-
-       /* Round 1 */
-       ROUND(F, a, b, c, d, in[ 0] + K1,  3);
-       ROUND(F, d, a, b, c, in[ 1] + K1,  7);
-       ROUND(F, c, d, a, b, in[ 2] + K1, 11);
-       ROUND(F, b, c, d, a, in[ 3] + K1, 19);
-       ROUND(F, a, b, c, d, in[ 4] + K1,  3);
-       ROUND(F, d, a, b, c, in[ 5] + K1,  7);
-       ROUND(F, c, d, a, b, in[ 6] + K1, 11);
-       ROUND(F, b, c, d, a, in[ 7] + K1, 19);
-       ROUND(F, a, b, c, d, in[ 8] + K1,  3);
-       ROUND(F, d, a, b, c, in[ 9] + K1,  7);
-       ROUND(F, c, d, a, b, in[10] + K1, 11);
-       ROUND(F, b, c, d, a, in[11] + K1, 19);
-
-       /* Round 2 */
-       ROUND(G, a, b, c, d, in[ 1] + K2,  3);
-       ROUND(G, d, a, b, c, in[ 3] + K2,  5);
-       ROUND(G, c, d, a, b, in[ 5] + K2,  9);
-       ROUND(G, b, c, d, a, in[ 7] + K2, 13);
-       ROUND(G, a, b, c, d, in[ 9] + K2,  3);
-       ROUND(G, d, a, b, c, in[11] + K2,  5);
-       ROUND(G, c, d, a, b, in[ 0] + K2,  9);
-       ROUND(G, b, c, d, a, in[ 2] + K2, 13);
-       ROUND(G, a, b, c, d, in[ 4] + K2,  3);
-       ROUND(G, d, a, b, c, in[ 6] + K2,  5);
-       ROUND(G, c, d, a, b, in[ 8] + K2,  9);
-       ROUND(G, b, c, d, a, in[10] + K2, 13);
-
-       /* Round 3 */
-       ROUND(H, a, b, c, d, in[ 3] + K3,  3);
-       ROUND(H, d, a, b, c, in[ 7] + K3,  9);
-       ROUND(H, c, d, a, b, in[11] + K3, 11);
-       ROUND(H, b, c, d, a, in[ 2] + K3, 15);
-       ROUND(H, a, b, c, d, in[ 6] + K3,  3);
-       ROUND(H, d, a, b, c, in[10] + K3,  9);
-       ROUND(H, c, d, a, b, in[ 1] + K3, 11);
-       ROUND(H, b, c, d, a, in[ 5] + K3, 15);
-       ROUND(H, a, b, c, d, in[ 9] + K3,  3);
-       ROUND(H, d, a, b, c, in[ 0] + K3,  9);
-       ROUND(H, c, d, a, b, in[ 4] + K3, 11);
-       ROUND(H, b, c, d, a, in[ 8] + K3, 15);
-
-       return buf[1] + b; /* "most hashed" word */
-       /* Alternative: return sum of all words? */
-}
-#endif
-
-#undef ROUND
-#undef F
-#undef G
-#undef H
-#undef K1
-#undef K2
-#undef K3
-
-/* This should not be decreased so low that ISNs wrap too fast. */
-#define REKEY_INTERVAL (300 * HZ)
-/*
- * Bit layout of the tcp sequence numbers (before adding current time):
- * bit 24-31: increased after every key exchange
- * bit 0-23: hash(source,dest)
- *
- * The implementation is similar to the algorithm described
- * in the Appendix of RFC 1185, except that
- * - it uses a 1 MHz clock instead of a 250 kHz clock
- * - it performs a rekey every 5 minutes, which is equivalent
- *     to a (source,dest) tulple dependent forward jump of the
- *     clock by 0..2^(HASH_BITS+1)
- *
- * Thus the average ISN wraparound time is 68 minutes instead of
- * 4.55 hours.
- *
- * SMP cleanup and lock avoidance with poor man's RCU.
- *                     Manfred Spraul <manfred@colorfullife.com>
- *
- */
-#define COUNT_BITS 8
-#define COUNT_MASK ((1 << COUNT_BITS) - 1)
-#define HASH_BITS 24
-#define HASH_MASK ((1 << HASH_BITS) - 1)
+static u32 random_int_secret[MD5_MESSAGE_BYTES / 4] ____cacheline_aligned;
 
-static struct keydata {
-       __u32 count; /* already shifted to the final position */
-       __u32 secret[12];
-} ____cacheline_aligned ip_keydata[2];
-
-static unsigned int ip_cnt;
-
-static void rekey_seq_generator(struct work_struct *work);
-
-static DECLARE_DELAYED_WORK(rekey_work, rekey_seq_generator);
-
-/*
- * Lock avoidance:
- * The ISN generation runs lockless - it's just a hash over random data.
- * State changes happen every 5 minutes when the random key is replaced.
- * Synchronization is performed by having two copies of the hash function
- * state and rekey_seq_generator always updates the inactive copy.
- * The copy is then activated by updating ip_cnt.
- * The implementation breaks down if someone blocks the thread
- * that processes SYN requests for more than 5 minutes. Should never
- * happen, and even if that happens only a not perfectly compliant
- * ISN is generated, nothing fatal.
- */
-static void rekey_seq_generator(struct work_struct *work)
+static int __init random_int_secret_init(void)
 {
-       struct keydata *keyptr = &ip_keydata[1 ^ (ip_cnt & 1)];
-
-       get_random_bytes(keyptr->secret, sizeof(keyptr->secret));
-       keyptr->count = (ip_cnt & COUNT_MASK) << HASH_BITS;
-       smp_wmb();
-       ip_cnt++;
-       schedule_delayed_work(&rekey_work,
-                             round_jiffies_relative(REKEY_INTERVAL));
-}
-
-static inline struct keydata *get_keyptr(void)
-{
-       struct keydata *keyptr = &ip_keydata[ip_cnt & 1];
-
-       smp_rmb();
-
-       return keyptr;
-}
-
-static __init int seqgen_init(void)
-{
-       rekey_seq_generator(NULL);
+       get_random_bytes(random_int_secret, sizeof(random_int_secret));
        return 0;
 }
-late_initcall(seqgen_init);
-
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-__u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr,
-                                  __be16 sport, __be16 dport)
-{
-       __u32 seq;
-       __u32 hash[12];
-       struct keydata *keyptr = get_keyptr();
-
-       /* The procedure is the same as for IPv4, but addresses are longer.
-        * Thus we must use twothirdsMD4Transform.
-        */
-
-       memcpy(hash, saddr, 16);
-       hash[4] = ((__force u16)sport << 16) + (__force u16)dport;
-       memcpy(&hash[5], keyptr->secret, sizeof(__u32) * 7);
-
-       seq = twothirdsMD4Transform((const __u32 *)daddr, hash) & HASH_MASK;
-       seq += keyptr->count;
-
-       seq += ktime_to_ns(ktime_get_real());
-
-       return seq;
-}
-EXPORT_SYMBOL(secure_tcpv6_sequence_number);
-#endif
-
-/*  The code below is shamelessly stolen from secure_tcp_sequence_number().
- *  All blames to Andrey V. Savochkin <saw@msu.ru>.
- */
-__u32 secure_ip_id(__be32 daddr)
-{
-       struct keydata *keyptr;
-       __u32 hash[4];
-
-       keyptr = get_keyptr();
-
-       /*
-        *  Pick a unique starting offset for each IP destination.
-        *  The dest ip address is placed in the starting vector,
-        *  which is then hashed with random data.
-        */
-       hash[0] = (__force __u32)daddr;
-       hash[1] = keyptr->secret[9];
-       hash[2] = keyptr->secret[10];
-       hash[3] = keyptr->secret[11];
-
-       return half_md4_transform(hash, keyptr->secret);
-}
-
-__u32 secure_ipv6_id(const __be32 daddr[4])
-{
-       const struct keydata *keyptr;
-       __u32 hash[4];
-
-       keyptr = get_keyptr();
-
-       hash[0] = (__force __u32)daddr[0];
-       hash[1] = (__force __u32)daddr[1];
-       hash[2] = (__force __u32)daddr[2];
-       hash[3] = (__force __u32)daddr[3];
-
-       return half_md4_transform(hash, keyptr->secret);
-}
-
-#ifdef CONFIG_INET
-
-__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
-                                __be16 sport, __be16 dport)
-{
-       __u32 seq;
-       __u32 hash[4];
-       struct keydata *keyptr = get_keyptr();
-
-       /*
-        *  Pick a unique starting offset for each TCP connection endpoints
-        *  (saddr, daddr, sport, dport).
-        *  Note that the words are placed into the starting vector, which is
-        *  then mixed with a partial MD4 over random data.
-        */
-       hash[0] = (__force u32)saddr;
-       hash[1] = (__force u32)daddr;
-       hash[2] = ((__force u16)sport << 16) + (__force u16)dport;
-       hash[3] = keyptr->secret[11];
-
-       seq = half_md4_transform(hash, keyptr->secret) & HASH_MASK;
-       seq += keyptr->count;
-       /*
-        *      As close as possible to RFC 793, which
-        *      suggests using a 250 kHz clock.
-        *      Further reading shows this assumes 2 Mb/s networks.
-        *      For 10 Mb/s Ethernet, a 1 MHz clock is appropriate.
-        *      For 10 Gb/s Ethernet, a 1 GHz clock should be ok, but
-        *      we also need to limit the resolution so that the u32 seq
-        *      overlaps less than one time per MSL (2 minutes).
-        *      Choosing a clock of 64 ns period is OK. (period of 274 s)
-        */
-       seq += ktime_to_ns(ktime_get_real()) >> 6;
-
-       return seq;
-}
-
-/* Generate secure starting point for ephemeral IPV4 transport port search */
-u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport)
-{
-       struct keydata *keyptr = get_keyptr();
-       u32 hash[4];
-
-       /*
-        *  Pick a unique starting offset for each ephemeral port search
-        *  (saddr, daddr, dport) and 48bits of random data.
-        */
-       hash[0] = (__force u32)saddr;
-       hash[1] = (__force u32)daddr;
-       hash[2] = (__force u32)dport ^ keyptr->secret[10];
-       hash[3] = keyptr->secret[11];
-
-       return half_md4_transform(hash, keyptr->secret);
-}
-EXPORT_SYMBOL_GPL(secure_ipv4_port_ephemeral);
-
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
-                              __be16 dport)
-{
-       struct keydata *keyptr = get_keyptr();
-       u32 hash[12];
-
-       memcpy(hash, saddr, 16);
-       hash[4] = (__force u32)dport;
-       memcpy(&hash[5], keyptr->secret, sizeof(__u32) * 7);
-
-       return twothirdsMD4Transform((const __u32 *)daddr, hash);
-}
-#endif
-
-#if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE)
-/* Similar to secure_tcp_sequence_number but generate a 48 bit value
- * bit's 32-47 increase every key exchange
- *       0-31  hash(source, dest)
- */
-u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
-                               __be16 sport, __be16 dport)
-{
-       u64 seq;
-       __u32 hash[4];
-       struct keydata *keyptr = get_keyptr();
-
-       hash[0] = (__force u32)saddr;
-       hash[1] = (__force u32)daddr;
-       hash[2] = ((__force u16)sport << 16) + (__force u16)dport;
-       hash[3] = keyptr->secret[11];
-
-       seq = half_md4_transform(hash, keyptr->secret);
-       seq |= ((u64)keyptr->count) << (32 - HASH_BITS);
-
-       seq += ktime_to_ns(ktime_get_real());
-       seq &= (1ull << 48) - 1;
-
-       return seq;
-}
-EXPORT_SYMBOL(secure_dccp_sequence_number);
-#endif
-
-#endif /* CONFIG_INET */
-
+late_initcall(random_int_secret_init);
 
 /*
  * Get a random word for internal kernel use only. Similar to urandom but
@@ -1646,17 +1315,15 @@ EXPORT_SYMBOL(secure_dccp_sequence_number);
  * value is not cryptographically secure but for several uses the cost of
  * depleting entropy is too high
  */
-DEFINE_PER_CPU(__u32 [4], get_random_int_hash);
+DEFINE_PER_CPU(__u32 [MD5_DIGEST_WORDS], get_random_int_hash);
 unsigned int get_random_int(void)
 {
-       struct keydata *keyptr;
        __u32 *hash = get_cpu_var(get_random_int_hash);
-       int ret;
+       unsigned int ret;
 
-       keyptr = get_keyptr();
        hash[0] += current->pid + jiffies + get_cycles();
-
-       ret = half_md4_transform(hash, keyptr->secret);
+       md5_transform(hash, random_int_secret);
+       ret = hash[0];
        put_cpu_var(get_random_int_hash);
 
        return ret;
diff --git a/drivers/char/tile-srom.c b/drivers/char/tile-srom.c
new file mode 100644 (file)
index 0000000..cf3ee00
--- /dev/null
@@ -0,0 +1,481 @@
+/*
+ * Copyright 2011 Tilera Corporation. 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, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ *
+ * SPI Flash ROM driver
+ *
+ * This source code is derived from code provided in "Linux Device
+ * Drivers, Third Edition", by Jonathan Corbet, Alessandro Rubini, and
+ * Greg Kroah-Hartman, published by O'Reilly Media, Inc.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/kernel.h>      /* printk() */
+#include <linux/slab.h>                /* kmalloc() */
+#include <linux/fs.h>          /* everything... */
+#include <linux/errno.h>       /* error codes */
+#include <linux/types.h>       /* size_t */
+#include <linux/proc_fs.h>
+#include <linux/fcntl.h>       /* O_ACCMODE */
+#include <linux/aio.h>
+#include <linux/pagemap.h>
+#include <linux/hugetlb.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+#include <hv/hypervisor.h>
+#include <linux/ioctl.h>
+#include <linux/cdev.h>
+#include <linux/delay.h>
+#include <hv/drv_srom_intf.h>
+
+/*
+ * Size of our hypervisor I/O requests.  We break up large transfers
+ * so that we don't spend large uninterrupted spans of time in the
+ * hypervisor.  Erasing an SROM sector takes a significant fraction of
+ * a second, so if we allowed the user to, say, do one I/O to write the
+ * entire ROM, we'd get soft lockup timeouts, or worse.
+ */
+#define SROM_CHUNK_SIZE ((size_t)4096)
+
+/*
+ * When hypervisor is busy (e.g. erasing), poll the status periodically.
+ */
+
+/*
+ * Interval to poll the state in msec
+ */
+#define SROM_WAIT_TRY_INTERVAL 20
+
+/*
+ * Maximum times to poll the state
+ */
+#define SROM_MAX_WAIT_TRY_TIMES 1000
+
+struct srom_dev {
+       int hv_devhdl;                  /* Handle for hypervisor device */
+       u32 total_size;                 /* Size of this device */
+       u32 sector_size;                /* Size of a sector */
+       u32 page_size;                  /* Size of a page */
+       struct mutex lock;              /* Allow only one accessor at a time */
+};
+
+static int srom_major;                 /* Dynamic major by default */
+module_param(srom_major, int, 0);
+MODULE_AUTHOR("Tilera Corporation");
+MODULE_LICENSE("GPL");
+
+static int srom_devs;                  /* Number of SROM partitions */
+static struct cdev srom_cdev;
+static struct class *srom_class;
+static struct srom_dev *srom_devices;
+
+/*
+ * Handle calling the hypervisor and managing EAGAIN/EBUSY.
+ */
+
+static ssize_t _srom_read(int hv_devhdl, void *buf,
+                         loff_t off, size_t count)
+{
+       int retval, retries = SROM_MAX_WAIT_TRY_TIMES;
+       for (;;) {
+               retval = hv_dev_pread(hv_devhdl, 0, (HV_VirtAddr)buf,
+                                     count, off);
+               if (retval >= 0)
+                       return retval;
+               if (retval == HV_EAGAIN)
+                       continue;
+               if (retval == HV_EBUSY && --retries > 0) {
+                       msleep(SROM_WAIT_TRY_INTERVAL);
+                       continue;
+               }
+               pr_err("_srom_read: error %d\n", retval);
+               return -EIO;
+       }
+}
+
+static ssize_t _srom_write(int hv_devhdl, const void *buf,
+                          loff_t off, size_t count)
+{
+       int retval, retries = SROM_MAX_WAIT_TRY_TIMES;
+       for (;;) {
+               retval = hv_dev_pwrite(hv_devhdl, 0, (HV_VirtAddr)buf,
+                                      count, off);
+               if (retval >= 0)
+                       return retval;
+               if (retval == HV_EAGAIN)
+                       continue;
+               if (retval == HV_EBUSY && --retries > 0) {
+                       msleep(SROM_WAIT_TRY_INTERVAL);
+                       continue;
+               }
+               pr_err("_srom_write: error %d\n", retval);
+               return -EIO;
+       }
+}
+
+/**
+ * srom_open() - Device open routine.
+ * @inode: Inode for this device.
+ * @filp: File for this specific open of the device.
+ *
+ * Returns zero, or an error code.
+ */
+static int srom_open(struct inode *inode, struct file *filp)
+{
+       filp->private_data = &srom_devices[iminor(inode)];
+       return 0;
+}
+
+
+/**
+ * srom_release() - Device release routine.
+ * @inode: Inode for this device.
+ * @filp: File for this specific open of the device.
+ *
+ * Returns zero, or an error code.
+ */
+static int srom_release(struct inode *inode, struct file *filp)
+{
+       struct srom_dev *srom = filp->private_data;
+       char dummy;
+
+       /* Make sure we've flushed anything written to the ROM. */
+       mutex_lock(&srom->lock);
+       if (srom->hv_devhdl >= 0)
+               _srom_write(srom->hv_devhdl, &dummy, SROM_FLUSH_OFF, 1);
+       mutex_unlock(&srom->lock);
+
+       filp->private_data = NULL;
+
+       return 0;
+}
+
+
+/**
+ * srom_read() - Read data from the device.
+ * @filp: File for this specific open of the device.
+ * @buf: User's data buffer.
+ * @count: Number of bytes requested.
+ * @f_pos: File position.
+ *
+ * Returns number of bytes read, or an error code.
+ */
+static ssize_t srom_read(struct file *filp, char __user *buf,
+                        size_t count, loff_t *f_pos)
+{
+       int retval = 0;
+       void *kernbuf;
+       struct srom_dev *srom = filp->private_data;
+
+       kernbuf = kmalloc(SROM_CHUNK_SIZE, GFP_KERNEL);
+       if (!kernbuf)
+               return -ENOMEM;
+
+       if (mutex_lock_interruptible(&srom->lock)) {
+               retval = -ERESTARTSYS;
+               kfree(kernbuf);
+               return retval;
+       }
+
+       while (count) {
+               int hv_retval;
+               int bytes_this_pass = min(count, SROM_CHUNK_SIZE);
+
+               hv_retval = _srom_read(srom->hv_devhdl, kernbuf,
+                                      *f_pos, bytes_this_pass);
+               if (hv_retval > 0) {
+                       if (copy_to_user(buf, kernbuf, hv_retval) != 0) {
+                               retval = -EFAULT;
+                               break;
+                       }
+               } else if (hv_retval <= 0) {
+                       if (retval == 0)
+                               retval = hv_retval;
+                       break;
+               }
+
+               retval += hv_retval;
+               *f_pos += hv_retval;
+               buf += hv_retval;
+               count -= hv_retval;
+       }
+
+       mutex_unlock(&srom->lock);
+       kfree(kernbuf);
+
+       return retval;
+}
+
+/**
+ * srom_write() - Write data to the device.
+ * @filp: File for this specific open of the device.
+ * @buf: User's data buffer.
+ * @count: Number of bytes requested.
+ * @f_pos: File position.
+ *
+ * Returns number of bytes written, or an error code.
+ */
+static ssize_t srom_write(struct file *filp, const char __user *buf,
+                         size_t count, loff_t *f_pos)
+{
+       int retval = 0;
+       void *kernbuf;
+       struct srom_dev *srom = filp->private_data;
+
+       kernbuf = kmalloc(SROM_CHUNK_SIZE, GFP_KERNEL);
+       if (!kernbuf)
+               return -ENOMEM;
+
+       if (mutex_lock_interruptible(&srom->lock)) {
+               retval = -ERESTARTSYS;
+               kfree(kernbuf);
+               return retval;
+       }
+
+       while (count) {
+               int hv_retval;
+               int bytes_this_pass = min(count, SROM_CHUNK_SIZE);
+
+               if (copy_from_user(kernbuf, buf, bytes_this_pass) != 0) {
+                       retval = -EFAULT;
+                       break;
+               }
+
+               hv_retval = _srom_write(srom->hv_devhdl, kernbuf,
+                                       *f_pos, bytes_this_pass);
+               if (hv_retval <= 0) {
+                       if (retval == 0)
+                               retval = hv_retval;
+                       break;
+               }
+
+               retval += hv_retval;
+               *f_pos += hv_retval;
+               buf += hv_retval;
+               count -= hv_retval;
+       }
+
+       mutex_unlock(&srom->lock);
+       kfree(kernbuf);
+
+       return retval;
+}
+
+/* Provide our own implementation so we can use srom->total_size. */
+loff_t srom_llseek(struct file *filp, loff_t offset, int origin)
+{
+       struct srom_dev *srom = filp->private_data;
+
+       if (mutex_lock_interruptible(&srom->lock))
+               return -ERESTARTSYS;
+
+       switch (origin) {
+       case SEEK_END:
+               offset += srom->total_size;
+               break;
+       case SEEK_CUR:
+               offset += filp->f_pos;
+               break;
+       }
+
+       if (offset < 0 || offset > srom->total_size) {
+               offset = -EINVAL;
+       } else {
+               filp->f_pos = offset;
+               filp->f_version = 0;
+       }
+
+       mutex_unlock(&srom->lock);
+
+       return offset;
+}
+
+static ssize_t total_show(struct device *dev,
+                         struct device_attribute *attr, char *buf)
+{
+       struct srom_dev *srom = dev_get_drvdata(dev);
+       return sprintf(buf, "%u\n", srom->total_size);
+}
+
+static ssize_t sector_show(struct device *dev,
+                          struct device_attribute *attr, char *buf)
+{
+       struct srom_dev *srom = dev_get_drvdata(dev);
+       return sprintf(buf, "%u\n", srom->sector_size);
+}
+
+static ssize_t page_show(struct device *dev,
+                        struct device_attribute *attr, char *buf)
+{
+       struct srom_dev *srom = dev_get_drvdata(dev);
+       return sprintf(buf, "%u\n", srom->page_size);
+}
+
+static struct device_attribute srom_dev_attrs[] = {
+       __ATTR(total_size, S_IRUGO, total_show, NULL),
+       __ATTR(sector_size, S_IRUGO, sector_show, NULL),
+       __ATTR(page_size, S_IRUGO, page_show, NULL),
+       __ATTR_NULL
+};
+
+static char *srom_devnode(struct device *dev, mode_t *mode)
+{
+       *mode = S_IRUGO | S_IWUSR;
+       return kasprintf(GFP_KERNEL, "srom/%s", dev_name(dev));
+}
+
+/*
+ * The fops
+ */
+static const struct file_operations srom_fops = {
+       .owner =     THIS_MODULE,
+       .llseek =    srom_llseek,
+       .read =      srom_read,
+       .write =     srom_write,
+       .open =      srom_open,
+       .release =   srom_release,
+};
+
+/**
+ * srom_setup_minor() - Initialize per-minor information.
+ * @srom: Per-device SROM state.
+ * @index: Device to set up.
+ */
+static int srom_setup_minor(struct srom_dev *srom, int index)
+{
+       struct device *dev;
+       int devhdl = srom->hv_devhdl;
+
+       mutex_init(&srom->lock);
+
+       if (_srom_read(devhdl, &srom->total_size,
+                      SROM_TOTAL_SIZE_OFF, sizeof(srom->total_size)) < 0)
+               return -EIO;
+       if (_srom_read(devhdl, &srom->sector_size,
+                      SROM_SECTOR_SIZE_OFF, sizeof(srom->sector_size)) < 0)
+               return -EIO;
+       if (_srom_read(devhdl, &srom->page_size,
+                      SROM_PAGE_SIZE_OFF, sizeof(srom->page_size)) < 0)
+               return -EIO;
+
+       dev = device_create(srom_class, &platform_bus,
+                           MKDEV(srom_major, index), srom, "%d", index);
+       return IS_ERR(dev) ? PTR_ERR(dev) : 0;
+}
+
+/** srom_init() - Initialize the driver's module. */
+static int srom_init(void)
+{
+       int result, i;
+       dev_t dev = MKDEV(srom_major, 0);
+
+       /*
+        * Start with a plausible number of partitions; the krealloc() call
+        * below will yield about log(srom_devs) additional allocations.
+        */
+       srom_devices = kzalloc(4 * sizeof(struct srom_dev), GFP_KERNEL);
+
+       /* Discover the number of srom partitions. */
+       for (i = 0; ; i++) {
+               int devhdl;
+               char buf[20];
+               struct srom_dev *new_srom_devices =
+                       krealloc(srom_devices, (i+1) * sizeof(struct srom_dev),
+                                GFP_KERNEL | __GFP_ZERO);
+               if (!new_srom_devices) {
+                       result = -ENOMEM;
+                       goto fail_mem;
+               }
+               srom_devices = new_srom_devices;
+               sprintf(buf, "srom/0/%d", i);
+               devhdl = hv_dev_open((HV_VirtAddr)buf, 0);
+               if (devhdl < 0) {
+                       if (devhdl != HV_ENODEV)
+                               pr_notice("srom/%d: hv_dev_open failed: %d.\n",
+                                         i, devhdl);
+                       break;
+               }
+               srom_devices[i].hv_devhdl = devhdl;
+       }
+       srom_devs = i;
+
+       /* Bail out early if we have no partitions at all. */
+       if (srom_devs == 0) {
+               result = -ENODEV;
+               goto fail_mem;
+       }
+
+       /* Register our major, and accept a dynamic number. */
+       if (srom_major)
+               result = register_chrdev_region(dev, srom_devs, "srom");
+       else {
+               result = alloc_chrdev_region(&dev, 0, srom_devs, "srom");
+               srom_major = MAJOR(dev);
+       }
+       if (result < 0)
+               goto fail_mem;
+
+       /* Register a character device. */
+       cdev_init(&srom_cdev, &srom_fops);
+       srom_cdev.owner = THIS_MODULE;
+       srom_cdev.ops = &srom_fops;
+       result = cdev_add(&srom_cdev, dev, srom_devs);
+       if (result < 0)
+               goto fail_chrdev;
+
+       /* Create a sysfs class. */
+       srom_class = class_create(THIS_MODULE, "srom");
+       if (IS_ERR(srom_class)) {
+               result = PTR_ERR(srom_class);
+               goto fail_cdev;
+       }
+       srom_class->dev_attrs = srom_dev_attrs;
+       srom_class->devnode = srom_devnode;
+
+       /* Do per-partition initialization */
+       for (i = 0; i < srom_devs; i++) {
+               result = srom_setup_minor(srom_devices + i, i);
+               if (result < 0)
+                       goto fail_class;
+       }
+
+       return 0;
+
+fail_class:
+       for (i = 0; i < srom_devs; i++)
+               device_destroy(srom_class, MKDEV(srom_major, i));
+       class_destroy(srom_class);
+fail_cdev:
+       cdev_del(&srom_cdev);
+fail_chrdev:
+       unregister_chrdev_region(dev, srom_devs);
+fail_mem:
+       kfree(srom_devices);
+       return result;
+}
+
+/** srom_cleanup() - Clean up the driver's module. */
+static void srom_cleanup(void)
+{
+       int i;
+       for (i = 0; i < srom_devs; i++)
+               device_destroy(srom_class, MKDEV(srom_major, i));
+       class_destroy(srom_class);
+       cdev_del(&srom_cdev);
+       unregister_chrdev_region(MKDEV(srom_major, 0), srom_devs);
+       kfree(srom_devices);
+}
+
+module_init(srom_init);
+module_exit(srom_cleanup);
index 7fc2f10..3f4051a 100644 (file)
@@ -80,7 +80,7 @@ enum tis_defaults {
 static LIST_HEAD(tis_chips);
 static DEFINE_SPINLOCK(tis_lock);
 
-#ifdef CONFIG_PNP
+#if defined(CONFIG_PNP) && defined(CONFIG_ACPI)
 static int is_itpm(struct pnp_dev *dev)
 {
        struct acpi_device *acpi = pnp_acpi_device(dev);
@@ -93,6 +93,11 @@ static int is_itpm(struct pnp_dev *dev)
 
        return 0;
 }
+#else
+static inline int is_itpm(struct pnp_dev *dev)
+{
+       return 0;
+}
 #endif
 
 static int check_locality(struct tpm_chip *chip, int l)
index 3ee1fdb..e55814b 100644 (file)
@@ -57,6 +57,7 @@ void proc_fork_connector(struct task_struct *task)
        struct proc_event *ev;
        __u8 buffer[CN_PROC_MSG_SIZE];
        struct timespec ts;
+       struct task_struct *parent;
 
        if (atomic_read(&proc_event_num_listeners) < 1)
                return;
@@ -67,8 +68,11 @@ void proc_fork_connector(struct task_struct *task)
        ktime_get_ts(&ts); /* get high res monotonic timestamp */
        put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
        ev->what = PROC_EVENT_FORK;
-       ev->event_data.fork.parent_pid = task->real_parent->pid;
-       ev->event_data.fork.parent_tgid = task->real_parent->tgid;
+       rcu_read_lock();
+       parent = rcu_dereference(task->real_parent);
+       ev->event_data.fork.parent_pid = parent->pid;
+       ev->event_data.fork.parent_tgid = parent->tgid;
+       rcu_read_unlock();
        ev->event_data.fork.child_pid = task->pid;
        ev->event_data.fork.child_tgid = task->tgid;
 
index bf50924..d4c5423 100644 (file)
@@ -25,9 +25,19 @@ DEFINE_PER_CPU(struct cpuidle_device *, cpuidle_devices);
 
 DEFINE_MUTEX(cpuidle_lock);
 LIST_HEAD(cpuidle_detected_devices);
-static void (*pm_idle_old)(void);
 
 static int enabled_devices;
+static int off __read_mostly;
+static int initialized __read_mostly;
+
+int cpuidle_disabled(void)
+{
+       return off;
+}
+void disable_cpuidle(void)
+{
+       off = 1;
+}
 
 #if defined(CONFIG_ARCH_HAS_CPU_IDLE_WAIT)
 static void cpuidle_kick_cpus(void)
@@ -46,25 +56,23 @@ static int __cpuidle_register_device(struct cpuidle_device *dev);
  * cpuidle_idle_call - the main idle loop
  *
  * NOTE: no locks or semaphores should be used here
+ * return non-zero on failure
  */
-static void cpuidle_idle_call(void)
+int cpuidle_idle_call(void)
 {
        struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
        struct cpuidle_state *target_state;
        int next_state;
 
+       if (off)
+               return -ENODEV;
+
+       if (!initialized)
+               return -ENODEV;
+
        /* check if the device is ready */
-       if (!dev || !dev->enabled) {
-               if (pm_idle_old)
-                       pm_idle_old();
-               else
-#if defined(CONFIG_ARCH_HAS_DEFAULT_IDLE)
-                       default_idle();
-#else
-                       local_irq_enable();
-#endif
-               return;
-       }
+       if (!dev || !dev->enabled)
+               return -EBUSY;
 
 #if 0
        /* shows regressions, re-enable for 2.6.29 */
@@ -89,7 +97,7 @@ static void cpuidle_idle_call(void)
        next_state = cpuidle_curr_governor->select(dev);
        if (need_resched()) {
                local_irq_enable();
-               return;
+               return 0;
        }
 
        target_state = &dev->states[next_state];
@@ -114,6 +122,8 @@ static void cpuidle_idle_call(void)
        /* give the governor an opportunity to reflect on the outcome */
        if (cpuidle_curr_governor->reflect)
                cpuidle_curr_governor->reflect(dev);
+
+       return 0;
 }
 
 /**
@@ -121,10 +131,10 @@ static void cpuidle_idle_call(void)
  */
 void cpuidle_install_idle_handler(void)
 {
-       if (enabled_devices && (pm_idle != cpuidle_idle_call)) {
+       if (enabled_devices) {
                /* Make sure all changes finished before we switch to new idle */
                smp_wmb();
-               pm_idle = cpuidle_idle_call;
+               initialized = 1;
        }
 }
 
@@ -133,8 +143,8 @@ void cpuidle_install_idle_handler(void)
  */
 void cpuidle_uninstall_idle_handler(void)
 {
-       if (enabled_devices && pm_idle_old && (pm_idle != pm_idle_old)) {
-               pm_idle = pm_idle_old;
+       if (enabled_devices) {
+               initialized = 0;
                cpuidle_kick_cpus();
        }
 }
@@ -427,7 +437,8 @@ static int __init cpuidle_init(void)
 {
        int ret;
 
-       pm_idle_old = pm_idle;
+       if (cpuidle_disabled())
+               return -ENODEV;
 
        ret = cpuidle_add_class_sysfs(&cpu_sysdev_class);
        if (ret)
@@ -438,4 +449,5 @@ static int __init cpuidle_init(void)
        return 0;
 }
 
+module_param(off, int, 0444);
 core_initcall(cpuidle_init);
index 33e50d5..38c3fd8 100644 (file)
@@ -13,6 +13,7 @@ extern struct list_head cpuidle_governors;
 extern struct list_head cpuidle_detected_devices;
 extern struct mutex cpuidle_lock;
 extern spinlock_t cpuidle_driver_lock;
+extern int cpuidle_disabled(void);
 
 /* idle loop */
 extern void cpuidle_install_idle_handler(void);
index fd1601e..3f7e3ce 100644 (file)
@@ -26,6 +26,9 @@ int cpuidle_register_driver(struct cpuidle_driver *drv)
        if (!drv)
                return -EINVAL;
 
+       if (cpuidle_disabled())
+               return -ENODEV;
+
        spin_lock(&cpuidle_driver_lock);
        if (cpuidle_curr_driver) {
                spin_unlock(&cpuidle_driver_lock);
index 724c164..ea2f8e7 100644 (file)
@@ -81,6 +81,9 @@ int cpuidle_register_governor(struct cpuidle_governor *gov)
        if (!gov || !gov->select)
                return -EINVAL;
 
+       if (cpuidle_disabled())
+               return -ENODEV;
+
        mutex_lock(&cpuidle_lock);
        if (__cpuidle_find_governor(gov->name) == NULL) {
                ret = 0;
index 2e5b204..d0183dd 100644 (file)
@@ -1,6 +1,6 @@
 /* n2_core.c: Niagara2 Stream Processing Unit (SPU) crypto support.
  *
- * Copyright (C) 2010 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2010, 2011 David S. Miller <davem@davemloft.net>
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -31,8 +31,8 @@
 #include "n2_core.h"
 
 #define DRV_MODULE_NAME                "n2_crypto"
-#define DRV_MODULE_VERSION     "0.1"
-#define DRV_MODULE_RELDATE     "April 29, 2010"
+#define DRV_MODULE_VERSION     "0.2"
+#define DRV_MODULE_RELDATE     "July 28, 2011"
 
 static char version[] __devinitdata =
        DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
@@ -1823,22 +1823,17 @@ static int spu_mdesc_scan(struct mdesc_handle *mdesc, struct platform_device *de
 static int __devinit get_irq_props(struct mdesc_handle *mdesc, u64 node,
                                   struct spu_mdesc_info *ip)
 {
-       const u64 *intr, *ino;
-       int intr_len, ino_len;
+       const u64 *ino;
+       int ino_len;
        int i;
 
-       intr = mdesc_get_property(mdesc, node, "intr", &intr_len);
-       if (!intr)
-               return -ENODEV;
-
        ino = mdesc_get_property(mdesc, node, "ino", &ino_len);
-       if (!ino)
+       if (!ino) {
+               printk("NO 'ino'\n");
                return -ENODEV;
+       }
 
-       if (intr_len != ino_len)
-               return -EINVAL;
-
-       ip->num_intrs = intr_len / sizeof(u64);
+       ip->num_intrs = ino_len / sizeof(u64);
        ip->ino_table = kzalloc((sizeof(struct ino_blob) *
                                 ip->num_intrs),
                                GFP_KERNEL);
@@ -1847,7 +1842,7 @@ static int __devinit get_irq_props(struct mdesc_handle *mdesc, u64 node,
 
        for (i = 0; i < ip->num_intrs; i++) {
                struct ino_blob *b = &ip->ino_table[i];
-               b->intr = intr[i];
+               b->intr = i + 1;
                b->ino = ino[i];
        }
 
@@ -2204,6 +2199,10 @@ static struct of_device_id n2_crypto_match[] = {
                .name = "n2cp",
                .compatible = "SUNW,vf-cwq",
        },
+       {
+               .name = "n2cp",
+               .compatible = "SUNW,kt-cwq",
+       },
        {},
 };
 
@@ -2228,6 +2227,10 @@ static struct of_device_id n2_mau_match[] = {
                .name = "ncp",
                .compatible = "SUNW,vf-mau",
        },
+       {
+               .name = "ncp",
+               .compatible = "SUNW,kt-mau",
+       },
        {},
 };
 
index a4af858..734ed02 100644 (file)
@@ -9,6 +9,5 @@ TODO for slave dma
        - mxs-dma.c
        - dw_dmac
        - intel_mid_dma
-       - ste_dma40
 4. Check other subsystems for dma drivers and merge/move to dmaengine
 5. Remove dma_slave_config's dma direction.
index e6d7228..be21e3f 100644 (file)
@@ -80,6 +80,7 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/dma-mapping.h>
 #include <linux/dmapool.h>
 #include <linux/dmaengine.h>
 #include <linux/amba/bus.h>
@@ -156,14 +157,10 @@ struct pl08x_driver_data {
 #define PL08X_BOUNDARY_SHIFT           (10)    /* 1KB 0x400 */
 #define PL08X_BOUNDARY_SIZE            (1 << PL08X_BOUNDARY_SHIFT)
 
-/* Minimum period between work queue runs */
-#define PL08X_WQ_PERIODMIN     20
-
 /* Size (bytes) of each LLI buffer allocated for one transfer */
 # define PL08X_LLI_TSFR_SIZE   0x2000
 
 /* Maximum times we call dma_pool_alloc on this pool without freeing */
-#define PL08X_MAX_ALLOCS       0x40
 #define MAX_NUM_TSFR_LLIS      (PL08X_LLI_TSFR_SIZE/sizeof(struct pl08x_lli))
 #define PL08X_ALIGN            8
 
@@ -495,10 +492,10 @@ static inline u32 pl08x_cctl_bits(u32 cctl, u8 srcwidth, u8 dstwidth,
 
 struct pl08x_lli_build_data {
        struct pl08x_txd *txd;
-       struct pl08x_driver_data *pl08x;
        struct pl08x_bus_data srcbus;
        struct pl08x_bus_data dstbus;
        size_t remainder;
+       u32 lli_bus;
 };
 
 /*
@@ -551,8 +548,7 @@ static void pl08x_fill_lli_for_desc(struct pl08x_lli_build_data *bd,
        llis_va[num_llis].src = bd->srcbus.addr;
        llis_va[num_llis].dst = bd->dstbus.addr;
        llis_va[num_llis].lli = llis_bus + (num_llis + 1) * sizeof(struct pl08x_lli);
-       if (bd->pl08x->lli_buses & PL08X_AHB2)
-               llis_va[num_llis].lli |= PL080_LLI_LM_AHB2;
+       llis_va[num_llis].lli |= bd->lli_bus;
 
        if (cctl & PL080_CONTROL_SRC_INCR)
                bd->srcbus.addr += len;
@@ -605,9 +601,9 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
        cctl = txd->cctl;
 
        bd.txd = txd;
-       bd.pl08x = pl08x;
        bd.srcbus.addr = txd->src_addr;
        bd.dstbus.addr = txd->dst_addr;
+       bd.lli_bus = (pl08x->lli_buses & PL08X_AHB2) ? PL080_LLI_LM_AHB2 : 0;
 
        /* Find maximum width of the source bus */
        bd.srcbus.maxwidth =
@@ -622,25 +618,15 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
        /* Set up the bus widths to the maximum */
        bd.srcbus.buswidth = bd.srcbus.maxwidth;
        bd.dstbus.buswidth = bd.dstbus.maxwidth;
-       dev_vdbg(&pl08x->adev->dev,
-                "%s source bus is %d bytes wide, dest bus is %d bytes wide\n",
-                __func__, bd.srcbus.buswidth, bd.dstbus.buswidth);
-
 
        /*
         * Bytes transferred == tsize * MIN(buswidths), not max(buswidths)
         */
        max_bytes_per_lli = min(bd.srcbus.buswidth, bd.dstbus.buswidth) *
                PL080_CONTROL_TRANSFER_SIZE_MASK;
-       dev_vdbg(&pl08x->adev->dev,
-                "%s max bytes per lli = %zu\n",
-                __func__, max_bytes_per_lli);
 
        /* We need to count this down to zero */
        bd.remainder = txd->len;
-       dev_vdbg(&pl08x->adev->dev,
-                "%s remainder = %zu\n",
-                __func__, bd.remainder);
 
        /*
         * Choose bus to align to
@@ -649,6 +635,16 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
         */
        pl08x_choose_master_bus(&bd, &mbus, &sbus, cctl);
 
+       dev_vdbg(&pl08x->adev->dev, "src=0x%08x%s/%u dst=0x%08x%s/%u len=%zu llimax=%zu\n",
+                bd.srcbus.addr, cctl & PL080_CONTROL_SRC_INCR ? "+" : "",
+                bd.srcbus.buswidth,
+                bd.dstbus.addr, cctl & PL080_CONTROL_DST_INCR ? "+" : "",
+                bd.dstbus.buswidth,
+                bd.remainder, max_bytes_per_lli);
+       dev_vdbg(&pl08x->adev->dev, "mbus=%s sbus=%s\n",
+                mbus == &bd.srcbus ? "src" : "dst",
+                sbus == &bd.srcbus ? "src" : "dst");
+
        if (txd->len < mbus->buswidth) {
                /* Less than a bus width available - send as single bytes */
                while (bd.remainder) {
@@ -840,15 +836,14 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
        {
                int i;
 
+               dev_vdbg(&pl08x->adev->dev,
+                        "%-3s %-9s  %-10s %-10s %-10s %s\n",
+                        "lli", "", "csrc", "cdst", "clli", "cctl");
                for (i = 0; i < num_llis; i++) {
                        dev_vdbg(&pl08x->adev->dev,
-                                "lli %d @%p: csrc=0x%08x, cdst=0x%08x, cctl=0x%08x, clli=0x%08x\n",
-                                i,
-                                &llis_va[i],
-                                llis_va[i].src,
-                                llis_va[i].dst,
-                                llis_va[i].cctl,
-                                llis_va[i].lli
+                                "%3d @%p: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                                i, &llis_va[i], llis_va[i].src,
+                                llis_va[i].dst, llis_va[i].lli, llis_va[i].cctl
                                );
                }
        }
@@ -1054,64 +1049,105 @@ pl08x_dma_tx_status(struct dma_chan *chan,
 
 /* PrimeCell DMA extension */
 struct burst_table {
-       int burstwords;
+       u32 burstwords;
        u32 reg;
 };
 
 static const struct burst_table burst_sizes[] = {
        {
                .burstwords = 256,
-               .reg = (PL080_BSIZE_256 << PL080_CONTROL_SB_SIZE_SHIFT) |
-                       (PL080_BSIZE_256 << PL080_CONTROL_DB_SIZE_SHIFT),
+               .reg = PL080_BSIZE_256,
        },
        {
                .burstwords = 128,
-               .reg = (PL080_BSIZE_128 << PL080_CONTROL_SB_SIZE_SHIFT) |
-                       (PL080_BSIZE_128 << PL080_CONTROL_DB_SIZE_SHIFT),
+               .reg = PL080_BSIZE_128,
        },
        {
                .burstwords = 64,
-               .reg = (PL080_BSIZE_64 << PL080_CONTROL_SB_SIZE_SHIFT) |
-                       (PL080_BSIZE_64 << PL080_CONTROL_DB_SIZE_SHIFT),
+               .reg = PL080_BSIZE_64,
        },
        {
                .burstwords = 32,
-               .reg = (PL080_BSIZE_32 << PL080_CONTROL_SB_SIZE_SHIFT) |
-                       (PL080_BSIZE_32 << PL080_CONTROL_DB_SIZE_SHIFT),
+               .reg = PL080_BSIZE_32,
        },
        {
                .burstwords = 16,
-               .reg = (PL080_BSIZE_16 << PL080_CONTROL_SB_SIZE_SHIFT) |
-                       (PL080_BSIZE_16 << PL080_CONTROL_DB_SIZE_SHIFT),
+               .reg = PL080_BSIZE_16,
        },
        {
                .burstwords = 8,
-               .reg = (PL080_BSIZE_8 << PL080_CONTROL_SB_SIZE_SHIFT) |
-                       (PL080_BSIZE_8 << PL080_CONTROL_DB_SIZE_SHIFT),
+               .reg = PL080_BSIZE_8,
        },
        {
                .burstwords = 4,
-               .reg = (PL080_BSIZE_4 << PL080_CONTROL_SB_SIZE_SHIFT) |
-                       (PL080_BSIZE_4 << PL080_CONTROL_DB_SIZE_SHIFT),
+               .reg = PL080_BSIZE_4,
        },
        {
-               .burstwords = 1,
-               .reg = (PL080_BSIZE_1 << PL080_CONTROL_SB_SIZE_SHIFT) |
-                       (PL080_BSIZE_1 << PL080_CONTROL_DB_SIZE_SHIFT),
+               .burstwords = 0,
+               .reg = PL080_BSIZE_1,
        },
 };
 
+/*
+ * Given the source and destination available bus masks, select which
+ * will be routed to each port.  We try to have source and destination
+ * on separate ports, but always respect the allowable settings.
+ */
+static u32 pl08x_select_bus(u8 src, u8 dst)
+{
+       u32 cctl = 0;
+
+       if (!(dst & PL08X_AHB1) || ((dst & PL08X_AHB2) && (src & PL08X_AHB1)))
+               cctl |= PL080_CONTROL_DST_AHB2;
+       if (!(src & PL08X_AHB1) || ((src & PL08X_AHB2) && !(dst & PL08X_AHB2)))
+               cctl |= PL080_CONTROL_SRC_AHB2;
+
+       return cctl;
+}
+
+static u32 pl08x_cctl(u32 cctl)
+{
+       cctl &= ~(PL080_CONTROL_SRC_AHB2 | PL080_CONTROL_DST_AHB2 |
+                 PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR |
+                 PL080_CONTROL_PROT_MASK);
+
+       /* Access the cell in privileged mode, non-bufferable, non-cacheable */
+       return cctl | PL080_CONTROL_PROT_SYS;
+}
+
+static u32 pl08x_width(enum dma_slave_buswidth width)
+{
+       switch (width) {
+       case DMA_SLAVE_BUSWIDTH_1_BYTE:
+               return PL080_WIDTH_8BIT;
+       case DMA_SLAVE_BUSWIDTH_2_BYTES:
+               return PL080_WIDTH_16BIT;
+       case DMA_SLAVE_BUSWIDTH_4_BYTES:
+               return PL080_WIDTH_32BIT;
+       default:
+               return ~0;
+       }
+}
+
+static u32 pl08x_burst(u32 maxburst)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(burst_sizes); i++)
+               if (burst_sizes[i].burstwords <= maxburst)
+                       break;
+
+       return burst_sizes[i].reg;
+}
+
 static int dma_set_runtime_config(struct dma_chan *chan,
                                  struct dma_slave_config *config)
 {
        struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
        struct pl08x_driver_data *pl08x = plchan->host;
-       struct pl08x_channel_data *cd = plchan->cd;
        enum dma_slave_buswidth addr_width;
-       dma_addr_t addr;
-       u32 maxburst;
+       u32 width, burst, maxburst;
        u32 cctl = 0;
-       int i;
 
        if (!plchan->slave)
                return -EINVAL;
@@ -1119,11 +1155,9 @@ static int dma_set_runtime_config(struct dma_chan *chan,
        /* Transfer direction */
        plchan->runtime_direction = config->direction;
        if (config->direction == DMA_TO_DEVICE) {
-               addr = config->dst_addr;
                addr_width = config->dst_addr_width;
                maxburst = config->dst_maxburst;
        } else if (config->direction == DMA_FROM_DEVICE) {
-               addr = config->src_addr;
                addr_width = config->src_addr_width;
                maxburst = config->src_maxburst;
        } else {
@@ -1132,46 +1166,40 @@ static int dma_set_runtime_config(struct dma_chan *chan,
                return -EINVAL;
        }
 
-       switch (addr_width) {
-       case DMA_SLAVE_BUSWIDTH_1_BYTE:
-               cctl |= (PL080_WIDTH_8BIT << PL080_CONTROL_SWIDTH_SHIFT) |
-                       (PL080_WIDTH_8BIT << PL080_CONTROL_DWIDTH_SHIFT);
-               break;
-       case DMA_SLAVE_BUSWIDTH_2_BYTES:
-               cctl |= (PL080_WIDTH_16BIT << PL080_CONTROL_SWIDTH_SHIFT) |
-                       (PL080_WIDTH_16BIT << PL080_CONTROL_DWIDTH_SHIFT);
-               break;
-       case DMA_SLAVE_BUSWIDTH_4_BYTES:
-               cctl |= (PL080_WIDTH_32BIT << PL080_CONTROL_SWIDTH_SHIFT) |
-                       (PL080_WIDTH_32BIT << PL080_CONTROL_DWIDTH_SHIFT);
-               break;
-       default:
+       width = pl08x_width(addr_width);
+       if (width == ~0) {
                dev_err(&pl08x->adev->dev,
                        "bad runtime_config: alien address width\n");
                return -EINVAL;
        }
 
+       cctl |= width << PL080_CONTROL_SWIDTH_SHIFT;
+       cctl |= width << PL080_CONTROL_DWIDTH_SHIFT;
+
        /*
-        * Now decide on a maxburst:
         * If this channel will only request single transfers, set this
         * down to ONE element.  Also select one element if no maxburst
         * is specified.
         */
-       if (plchan->cd->single || maxburst == 0) {
-               cctl |= (PL080_BSIZE_1 << PL080_CONTROL_SB_SIZE_SHIFT) |
-                       (PL080_BSIZE_1 << PL080_CONTROL_DB_SIZE_SHIFT);
+       if (plchan->cd->single)
+               maxburst = 1;
+
+       burst = pl08x_burst(maxburst);
+       cctl |= burst << PL080_CONTROL_SB_SIZE_SHIFT;
+       cctl |= burst << PL080_CONTROL_DB_SIZE_SHIFT;
+
+       if (plchan->runtime_direction == DMA_FROM_DEVICE) {
+               plchan->src_addr = config->src_addr;
+               plchan->src_cctl = pl08x_cctl(cctl) | PL080_CONTROL_DST_INCR |
+                       pl08x_select_bus(plchan->cd->periph_buses,
+                                        pl08x->mem_buses);
        } else {
-               for (i = 0; i < ARRAY_SIZE(burst_sizes); i++)
-                       if (burst_sizes[i].burstwords <= maxburst)
-                               break;
-               cctl |= burst_sizes[i].reg;
+               plchan->dst_addr = config->dst_addr;
+               plchan->dst_cctl = pl08x_cctl(cctl) | PL080_CONTROL_SRC_INCR |
+                       pl08x_select_bus(pl08x->mem_buses,
+                                        plchan->cd->periph_buses);
        }
 
-       plchan->runtime_addr = addr;
-
-       /* Modify the default channel data to fit PrimeCell request */
-       cd->cctl = cctl;
-
        dev_dbg(&pl08x->adev->dev,
                "configured channel %s (%s) for %s, data width %d, "
                "maxburst %d words, LE, CCTL=0x%08x\n",
@@ -1270,23 +1298,6 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan,
        return 0;
 }
 
-/*
- * Given the source and destination available bus masks, select which
- * will be routed to each port.  We try to have source and destination
- * on separate ports, but always respect the allowable settings.
- */
-static u32 pl08x_select_bus(struct pl08x_driver_data *pl08x, u8 src, u8 dst)
-{
-       u32 cctl = 0;
-
-       if (!(dst & PL08X_AHB1) || ((dst & PL08X_AHB2) && (src & PL08X_AHB1)))
-               cctl |= PL080_CONTROL_DST_AHB2;
-       if (!(src & PL08X_AHB1) || ((src & PL08X_AHB2) && !(dst & PL08X_AHB2)))
-               cctl |= PL080_CONTROL_SRC_AHB2;
-
-       return cctl;
-}
-
 static struct pl08x_txd *pl08x_get_txd(struct pl08x_dma_chan *plchan,
        unsigned long flags)
 {
@@ -1338,8 +1349,8 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy(
        txd->cctl |= PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR;
 
        if (pl08x->vd->dualmaster)
-               txd->cctl |= pl08x_select_bus(pl08x,
-                                       pl08x->mem_buses, pl08x->mem_buses);
+               txd->cctl |= pl08x_select_bus(pl08x->mem_buses,
+                                             pl08x->mem_buses);
 
        ret = pl08x_prep_channel_resources(plchan, txd);
        if (ret)
@@ -1356,7 +1367,6 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
        struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
        struct pl08x_driver_data *pl08x = plchan->host;
        struct pl08x_txd *txd;
-       u8 src_buses, dst_buses;
        int ret;
 
        /*
@@ -1390,42 +1400,22 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
        txd->direction = direction;
        txd->len = sgl->length;
 
-       txd->cctl = plchan->cd->cctl &
-                       ~(PL080_CONTROL_SRC_AHB2 | PL080_CONTROL_DST_AHB2 |
-                         PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR |
-                         PL080_CONTROL_PROT_MASK);
-
-       /* Access the cell in privileged mode, non-bufferable, non-cacheable */
-       txd->cctl |= PL080_CONTROL_PROT_SYS;
-
        if (direction == DMA_TO_DEVICE) {
                txd->ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT;
-               txd->cctl |= PL080_CONTROL_SRC_INCR;
+               txd->cctl = plchan->dst_cctl;
                txd->src_addr = sgl->dma_address;
-               if (plchan->runtime_addr)
-                       txd->dst_addr = plchan->runtime_addr;
-               else
-                       txd->dst_addr = plchan->cd->addr;
-               src_buses = pl08x->mem_buses;
-               dst_buses = plchan->cd->periph_buses;
+               txd->dst_addr = plchan->dst_addr;
        } else if (direction == DMA_FROM_DEVICE) {
                txd->ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT;
-               txd->cctl |= PL080_CONTROL_DST_INCR;
-               if (plchan->runtime_addr)
-                       txd->src_addr = plchan->runtime_addr;
-               else
-                       txd->src_addr = plchan->cd->addr;
+               txd->cctl = plchan->src_cctl;
+               txd->src_addr = plchan->src_addr;
                txd->dst_addr = sgl->dma_address;
-               src_buses = plchan->cd->periph_buses;
-               dst_buses = pl08x->mem_buses;
        } else {
                dev_err(&pl08x->adev->dev,
                        "%s direction unsupported\n", __func__);
                return NULL;
        }
 
-       txd->cctl |= pl08x_select_bus(pl08x, src_buses, dst_buses);
-
        ret = pl08x_prep_channel_resources(plchan, txd);
        if (ret)
                return NULL;
@@ -1676,6 +1666,20 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
        return mask ? IRQ_HANDLED : IRQ_NONE;
 }
 
+static void pl08x_dma_slave_init(struct pl08x_dma_chan *chan)
+{
+       u32 cctl = pl08x_cctl(chan->cd->cctl);
+
+       chan->slave = true;
+       chan->name = chan->cd->bus_id;
+       chan->src_addr = chan->cd->addr;
+       chan->dst_addr = chan->cd->addr;
+       chan->src_cctl = cctl | PL080_CONTROL_DST_INCR |
+               pl08x_select_bus(chan->cd->periph_buses, chan->host->mem_buses);
+       chan->dst_cctl = cctl | PL080_CONTROL_SRC_INCR |
+               pl08x_select_bus(chan->host->mem_buses, chan->cd->periph_buses);
+}
+
 /*
  * Initialise the DMAC memcpy/slave channels.
  * Make a local wrapper to hold required data
@@ -1707,9 +1711,8 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x,
                chan->state = PL08X_CHAN_IDLE;
 
                if (slave) {
-                       chan->slave = true;
-                       chan->name = pl08x->pd->slave_channels[i].bus_id;
                        chan->cd = &pl08x->pd->slave_channels[i];
+                       pl08x_dma_slave_init(chan);
                } else {
                        chan->cd = &pl08x->pd->memcpy_channel;
                        chan->name = kasprintf(GFP_KERNEL, "memcpy%d", i);
index 36144f8..6a483ea 100644 (file)
@@ -1216,7 +1216,7 @@ static int __init at_dma_probe(struct platform_device *pdev)
        atdma->dma_common.cap_mask = pdata->cap_mask;
        atdma->all_chan_mask = (1 << pdata->nr_channels) - 1;
 
-       size = io->end - io->start + 1;
+       size = resource_size(io);
        if (!request_mem_region(io->start, size, pdev->dev.driver->name)) {
                err = -EBUSY;
                goto err_kfree;
@@ -1362,7 +1362,7 @@ static int __exit at_dma_remove(struct platform_device *pdev)
        atdma->regs = NULL;
 
        io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(io->start, io->end - io->start + 1);
+       release_mem_region(io->start, resource_size(io));
 
        kfree(atdma);
 
index a92d95e..4234f41 100644 (file)
@@ -41,6 +41,8 @@ struct coh901318_desc {
        struct coh901318_lli *lli;
        enum dma_data_direction dir;
        unsigned long flags;
+       u32 head_config;
+       u32 head_ctrl;
 };
 
 struct coh901318_base {
@@ -661,6 +663,9 @@ static struct coh901318_desc *coh901318_queue_start(struct coh901318_chan *cohc)
 
                coh901318_desc_submit(cohc, cohd);
 
+               /* Program the transaction head */
+               coh901318_set_conf(cohc, cohd->head_config);
+               coh901318_set_ctrl(cohc, cohd->head_ctrl);
                coh901318_prep_linked_list(cohc, cohd->lli);
 
                /* start dma job on this channel */
@@ -1091,8 +1096,6 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
        } else
                goto err_direction;
 
-       coh901318_set_conf(cohc, config);
-
        /* The dma only supports transmitting packages up to
         * MAX_DMA_PACKET_SIZE. Calculate to total number of
         * dma elemts required to send the entire sg list
@@ -1129,16 +1132,18 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
        if (ret)
                goto err_lli_fill;
 
-       /*
-        * Set the default ctrl for the channel to the one from the lli,
-        * things may have changed due to odd buffer alignment etc.
-        */
-       coh901318_set_ctrl(cohc, lli->control);
 
        COH_DBG(coh901318_list_print(cohc, lli));
 
        /* Pick a descriptor to handle this transfer */
        cohd = coh901318_desc_get(cohc);
+       cohd->head_config = config;
+       /*
+        * Set the default head ctrl for the channel to the one from the
+        * lli, things may have changed due to odd buffer alignment
+        * etc.
+        */
+       cohd->head_ctrl = lli->control;
        cohd->dir = direction;
        cohd->flags = flags;
        cohd->desc.tx_submit = coh901318_tx_submit;
index 48694c3..b48967b 100644 (file)
@@ -62,9 +62,9 @@
 #include <linux/slab.h>
 
 static DEFINE_MUTEX(dma_list_mutex);
+static DEFINE_IDR(dma_idr);
 static LIST_HEAD(dma_device_list);
 static long dmaengine_ref_count;
-static struct idr dma_idr;
 
 /* --- sysfs implementation --- */
 
@@ -510,8 +510,8 @@ struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask, dma_filter_fn fn, v
                                         dma_chan_name(chan));
                                list_del_rcu(&device->global_node);
                        } else if (err)
-                               pr_err("dmaengine: failed to get %s: (%d)\n",
-                                      dma_chan_name(chan), err);
+                               pr_debug("dmaengine: failed to get %s: (%d)\n",
+                                        dma_chan_name(chan), err);
                        else
                                break;
                        if (--device->privatecnt == 0)
@@ -1050,8 +1050,6 @@ EXPORT_SYMBOL_GPL(dma_run_dependencies);
 
 static int __init dma_bus_init(void)
 {
-       idr_init(&dma_idr);
-       mutex_init(&dma_list_mutex);
        return class_register(&dma_devclass);
 }
 arch_initcall(dma_bus_init);
index 0766c1e..5d7a49b 100644 (file)
@@ -902,7 +902,7 @@ static void ep93xx_dma_free_chan_resources(struct dma_chan *chan)
  *
  * Returns a valid DMA descriptor or %NULL in case of failure.
  */
-struct dma_async_tx_descriptor *
+static struct dma_async_tx_descriptor *
 ep93xx_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest,
                           dma_addr_t src, size_t len, unsigned long flags)
 {
index 1ea47db..7bd7e98 100644 (file)
@@ -32,6 +32,8 @@
 #include <linux/slab.h>
 #include <linux/platform_device.h>
 #include <linux/dmaengine.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/irq.h>
 #include <mach/sdma.h>
@@ -65,8 +67,8 @@
 #define SDMA_ONCE_RTB          0x060
 #define SDMA_XTRIG_CONF1       0x070
 #define SDMA_XTRIG_CONF2       0x074
-#define SDMA_CHNENBL0_V2       0x200
-#define SDMA_CHNENBL0_V1       0x080
+#define SDMA_CHNENBL0_IMX35    0x200
+#define SDMA_CHNENBL0_IMX31    0x080
 #define SDMA_CHNPRI_0          0x100
 
 /*
@@ -299,13 +301,18 @@ struct sdma_firmware_header {
        u32     ram_code_size;
 };
 
+enum sdma_devtype {
+       IMX31_SDMA,     /* runs on i.mx31 */
+       IMX35_SDMA,     /* runs on i.mx35 and later */
+};
+
 struct sdma_engine {
        struct device                   *dev;
        struct device_dma_parameters    dma_parms;
        struct sdma_channel             channel[MAX_DMA_CHANNELS];
        struct sdma_channel_control     *channel_control;
        void __iomem                    *regs;
-       unsigned int                    version;
+       enum sdma_devtype               devtype;
        unsigned int                    num_events;
        struct sdma_context_data        *context;
        dma_addr_t                      context_phys;
@@ -314,6 +321,26 @@ struct sdma_engine {
        struct sdma_script_start_addrs  *script_addrs;
 };
 
+static struct platform_device_id sdma_devtypes[] = {
+       {
+               .name = "imx31-sdma",
+               .driver_data = IMX31_SDMA,
+       }, {
+               .name = "imx35-sdma",
+               .driver_data = IMX35_SDMA,
+       }, {
+               /* sentinel */
+       }
+};
+MODULE_DEVICE_TABLE(platform, sdma_devtypes);
+
+static const struct of_device_id sdma_dt_ids[] = {
+       { .compatible = "fsl,imx31-sdma", .data = &sdma_devtypes[IMX31_SDMA], },
+       { .compatible = "fsl,imx35-sdma", .data = &sdma_devtypes[IMX35_SDMA], },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sdma_dt_ids);
+
 #define SDMA_H_CONFIG_DSPDMA   (1 << 12) /* indicates if the DSPDMA is used */
 #define SDMA_H_CONFIG_RTD_PINS (1 << 11) /* indicates if Real-Time Debug pins are enabled */
 #define SDMA_H_CONFIG_ACR      (1 << 4)  /* indicates if AHB freq /core freq = 2 or 1 */
@@ -321,8 +348,8 @@ struct sdma_engine {
 
 static inline u32 chnenbl_ofs(struct sdma_engine *sdma, unsigned int event)
 {
-       u32 chnenbl0 = (sdma->version == 2 ? SDMA_CHNENBL0_V2 : SDMA_CHNENBL0_V1);
-
+       u32 chnenbl0 = (sdma->devtype == IMX31_SDMA ? SDMA_CHNENBL0_IMX31 :
+                                                     SDMA_CHNENBL0_IMX35);
        return chnenbl0 + event * 4;
 }
 
@@ -1108,22 +1135,14 @@ static int __init sdma_get_firmware(struct sdma_engine *sdma,
                const char *fw_name)
 {
        const struct firmware *fw;
-       char *fwname;
        const struct sdma_firmware_header *header;
        int ret;
        const struct sdma_script_start_addrs *addr;
        unsigned short *ram_code;
 
-       fwname = kasprintf(GFP_KERNEL, "%s", fw_name);
-       if (!fwname)
-               return -ENOMEM;
-
-       ret = request_firmware(&fw, fwname, sdma->dev);
-       if (ret) {
-               kfree(fwname);
+       ret = request_firmware(&fw, fw_name, sdma->dev);
+       if (ret)
                return ret;
-       }
-       kfree(fwname);
 
        if (fw->size < sizeof(*header))
                goto err_firmware;
@@ -1162,15 +1181,16 @@ static int __init sdma_init(struct sdma_engine *sdma)
        int i, ret;
        dma_addr_t ccb_phys;
 
-       switch (sdma->version) {
-       case 1:
+       switch (sdma->devtype) {
+       case IMX31_SDMA:
                sdma->num_events = 32;
                break;
-       case 2:
+       case IMX35_SDMA:
                sdma->num_events = 48;
                break;
        default:
-               dev_err(sdma->dev, "Unknown version %d. aborting\n", sdma->version);
+               dev_err(sdma->dev, "Unknown sdma type %d. aborting\n",
+                       sdma->devtype);
                return -ENODEV;
        }
 
@@ -1239,6 +1259,10 @@ err_dma_alloc:
 
 static int __init sdma_probe(struct platform_device *pdev)
 {
+       const struct of_device_id *of_id =
+                       of_match_device(sdma_dt_ids, &pdev->dev);
+       struct device_node *np = pdev->dev.of_node;
+       const char *fw_name;
        int ret;
        int irq;
        struct resource *iores;
@@ -1254,7 +1278,7 @@ static int __init sdma_probe(struct platform_device *pdev)
 
        iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        irq = platform_get_irq(pdev, 0);
-       if (!iores || irq < 0 || !pdata) {
+       if (!iores || irq < 0) {
                ret = -EINVAL;
                goto err_irq;
        }
@@ -1281,10 +1305,14 @@ static int __init sdma_probe(struct platform_device *pdev)
                goto err_request_irq;
 
        sdma->script_addrs = kzalloc(sizeof(*sdma->script_addrs), GFP_KERNEL);
-       if (!sdma->script_addrs)
+       if (!sdma->script_addrs) {
+               ret = -ENOMEM;
                goto err_alloc;
+       }
 
-       sdma->version = pdata->sdma_version;
+       if (of_id)
+               pdev->id_entry = of_id->data;
+       sdma->devtype = pdev->id_entry->driver_data;
 
        dma_cap_set(DMA_SLAVE, sdma->dma_device.cap_mask);
        dma_cap_set(DMA_CYCLIC, sdma->dma_device.cap_mask);
@@ -1314,10 +1342,30 @@ static int __init sdma_probe(struct platform_device *pdev)
        if (ret)
                goto err_init;
 
-       if (pdata->script_addrs)
+       if (pdata && pdata->script_addrs)
                sdma_add_scripts(sdma, pdata->script_addrs);
 
-       sdma_get_firmware(sdma, pdata->fw_name);
+       if (pdata) {
+               sdma_get_firmware(sdma, pdata->fw_name);
+       } else {
+               /*
+                * Because that device tree does not encode ROM script address,
+                * the RAM script in firmware is mandatory for device tree
+                * probe, otherwise it fails.
+                */
+               ret = of_property_read_string(np, "fsl,sdma-ram-script-name",
+                                             &fw_name);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to get firmware name\n");
+                       goto err_init;
+               }
+
+               ret = sdma_get_firmware(sdma, fw_name);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to get firmware\n");
+                       goto err_init;
+               }
+       }
 
        sdma->dma_device.dev = &pdev->dev;
 
@@ -1365,7 +1413,9 @@ static int __exit sdma_remove(struct platform_device *pdev)
 static struct platform_driver sdma_driver = {
        .driver         = {
                .name   = "imx-sdma",
+               .of_match_table = sdma_dt_ids,
        },
+       .id_table       = sdma_devtypes,
        .remove         = __exit_p(sdma_remove),
 };
 
index f653517..8a3fdd8 100644 (file)
@@ -1351,7 +1351,6 @@ int dma_suspend(struct pci_dev *pci, pm_message_t state)
                        return -EAGAIN;
        }
        device->state = SUSPENDED;
-       pci_set_drvdata(pci, device);
        pci_save_state(pci);
        pci_disable_device(pci);
        pci_set_power_state(pci, PCI_D3hot);
@@ -1380,7 +1379,6 @@ int dma_resume(struct pci_dev *pci)
        }
        device->state = RUNNING;
        iowrite32(REG_BIT0, device->dma_base + DMA_CFG);
-       pci_set_drvdata(pci, device);
        return 0;
 }
 
index d845dc4..f519c93 100644 (file)
 /* provide a lookup table for setting the source address in the base or
  * extended descriptor of an xor or pq descriptor
  */
-static const u8 xor_idx_to_desc __read_mostly = 0xd0;
-static const u8 xor_idx_to_field[] __read_mostly = { 1, 4, 5, 6, 7, 0, 1, 2 };
-static const u8 pq_idx_to_desc __read_mostly = 0xf8;
-static const u8 pq_idx_to_field[] __read_mostly = { 1, 4, 5, 0, 1, 2, 4, 5 };
+static const u8 xor_idx_to_desc = 0xe0;
+static const u8 xor_idx_to_field[] = { 1, 4, 5, 6, 7, 0, 1, 2 };
+static const u8 pq_idx_to_desc = 0xf8;
+static const u8 pq_idx_to_field[] = { 1, 4, 5, 0, 1, 2, 4, 5 };
 
 static dma_addr_t xor_get_src(struct ioat_raw_descriptor *descs[2], int idx)
 {
index fab37d1..5e3a40f 100644 (file)
@@ -72,6 +72,17 @@ static struct pci_device_id ioat_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_JSF8) },
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_JSF9) },
 
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB0) },
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB1) },
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB2) },
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB3) },
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB4) },
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB5) },
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB6) },
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB7) },
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB8) },
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB9) },
+
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, ioat_pci_tbl);
index fd7d2b3..6815905 100644 (file)
@@ -1706,16 +1706,14 @@ static int __init ipu_probe(struct platform_device *pdev)
                ipu_data.irq_fn, ipu_data.irq_err, ipu_data.irq_base);
 
        /* Remap IPU common registers */
-       ipu_data.reg_ipu = ioremap(mem_ipu->start,
-                                  mem_ipu->end - mem_ipu->start + 1);
+       ipu_data.reg_ipu = ioremap(mem_ipu->start, resource_size(mem_ipu));
        if (!ipu_data.reg_ipu) {
                ret = -ENOMEM;
                goto err_ioremap_ipu;
        }
 
        /* Remap Image Converter and Image DMA Controller registers */
-       ipu_data.reg_ic = ioremap(mem_ic->start,
-                                 mem_ic->end - mem_ic->start + 1);
+       ipu_data.reg_ic = ioremap(mem_ic->start, resource_size(mem_ic));
        if (!ipu_data.reg_ic) {
                ret = -ENOMEM;
                goto err_ioremap_ic;
index 06f9f27..9a353c2 100644 (file)
@@ -1304,7 +1304,8 @@ static int mv_xor_shared_probe(struct platform_device *pdev)
        if (!res)
                return -ENODEV;
 
-       msp->xor_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+       msp->xor_base = devm_ioremap(&pdev->dev, res->start,
+                                    resource_size(res));
        if (!msp->xor_base)
                return -EBUSY;
 
index 88aad4f..be641cb 100644 (file)
@@ -327,10 +327,12 @@ static int mxs_dma_alloc_chan_resources(struct dma_chan *chan)
 
        memset(mxs_chan->ccw, 0, PAGE_SIZE);
 
-       ret = request_irq(mxs_chan->chan_irq, mxs_dma_int_handler,
-                               0, "mxs-dma", mxs_dma);
-       if (ret)
-               goto err_irq;
+       if (mxs_chan->chan_irq != NO_IRQ) {
+               ret = request_irq(mxs_chan->chan_irq, mxs_dma_int_handler,
+                                       0, "mxs-dma", mxs_dma);
+               if (ret)
+                       goto err_irq;
+       }
 
        ret = clk_enable(mxs_dma->clk);
        if (ret)
@@ -535,6 +537,7 @@ static int mxs_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
        switch (cmd) {
        case DMA_TERMINATE_ALL:
                mxs_dma_disable_chan(mxs_chan);
+               mxs_dma_reset_chan(mxs_chan);
                break;
        case DMA_PAUSE:
                mxs_dma_pause_chan(mxs_chan);
@@ -707,6 +710,8 @@ static struct platform_device_id mxs_dma_type[] = {
        }, {
                .name = "mxs-dma-apbx",
                .driver_data = MXS_DMA_APBX,
+       }, {
+               /* end of list */
        }
 };
 
index ff5b38f..1ac8d4b 100644 (file)
@@ -45,7 +45,8 @@
 #define DMA_STATUS_MASK_BITS           0x3
 #define DMA_STATUS_SHIFT_BITS          16
 #define DMA_STATUS_IRQ(x)              (0x1 << (x))
-#define DMA_STATUS_ERR(x)              (0x1 << ((x) + 8))
+#define DMA_STATUS0_ERR(x)             (0x1 << ((x) + 8))
+#define DMA_STATUS2_ERR(x)             (0x1 << (x))
 
 #define DMA_DESC_WIDTH_SHIFT_BITS      12
 #define DMA_DESC_WIDTH_1_BYTE          (0x3 << DMA_DESC_WIDTH_SHIFT_BITS)
@@ -61,6 +62,9 @@
 
 #define MAX_CHAN_NR                    8
 
+#define DMA_MASK_CTL0_MODE     0x33333333
+#define DMA_MASK_CTL2_MODE     0x00003333
+
 static unsigned int init_nr_desc_per_channel = 64;
 module_param(init_nr_desc_per_channel, uint, 0644);
 MODULE_PARM_DESC(init_nr_desc_per_channel,
@@ -133,6 +137,7 @@ struct pch_dma {
 #define PCH_DMA_CTL3   0x0C
 #define PCH_DMA_STS0   0x10
 #define PCH_DMA_STS1   0x14
+#define PCH_DMA_STS2   0x18
 
 #define dma_readl(pd, name) \
        readl((pd)->membase + PCH_DMA_##name)
@@ -183,13 +188,19 @@ static void pdc_enable_irq(struct dma_chan *chan, int enable)
 {
        struct pch_dma *pd = to_pd(chan->device);
        u32 val;
+       int pos;
+
+       if (chan->chan_id < 8)
+               pos = chan->chan_id;
+       else
+               pos = chan->chan_id + 8;
 
        val = dma_readl(pd, CTL2);
 
        if (enable)
-               val |= 0x1 << chan->chan_id;
+               val |= 0x1 << pos;
        else
-               val &= ~(0x1 << chan->chan_id);
+               val &= ~(0x1 << pos);
 
        dma_writel(pd, CTL2, val);
 
@@ -202,10 +213,17 @@ static void pdc_set_dir(struct dma_chan *chan)
        struct pch_dma_chan *pd_chan = to_pd_chan(chan);
        struct pch_dma *pd = to_pd(chan->device);
        u32 val;
+       u32 mask_mode;
+       u32 mask_ctl;
 
        if (chan->chan_id < 8) {
                val = dma_readl(pd, CTL0);
 
+               mask_mode = DMA_CTL0_MODE_MASK_BITS <<
+                                       (DMA_CTL0_BITS_PER_CH * chan->chan_id);
+               mask_ctl = DMA_MASK_CTL0_MODE & ~(DMA_CTL0_MODE_MASK_BITS <<
+                                      (DMA_CTL0_BITS_PER_CH * chan->chan_id));
+               val &= mask_mode;
                if (pd_chan->dir == DMA_TO_DEVICE)
                        val |= 0x1 << (DMA_CTL0_BITS_PER_CH * chan->chan_id +
                                       DMA_CTL0_DIR_SHIFT_BITS);
@@ -213,18 +231,24 @@ static void pdc_set_dir(struct dma_chan *chan)
                        val &= ~(0x1 << (DMA_CTL0_BITS_PER_CH * chan->chan_id +
                                         DMA_CTL0_DIR_SHIFT_BITS));
 
+               val |= mask_ctl;
                dma_writel(pd, CTL0, val);
        } else {
                int ch = chan->chan_id - 8; /* ch8-->0 ch9-->1 ... ch11->3 */
                val = dma_readl(pd, CTL3);
 
+               mask_mode = DMA_CTL0_MODE_MASK_BITS <<
+                                               (DMA_CTL0_BITS_PER_CH * ch);
+               mask_ctl = DMA_MASK_CTL2_MODE & ~(DMA_CTL0_MODE_MASK_BITS <<
+                                                (DMA_CTL0_BITS_PER_CH * ch));
+               val &= mask_mode;
                if (pd_chan->dir == DMA_TO_DEVICE)
                        val |= 0x1 << (DMA_CTL0_BITS_PER_CH * ch +
                                       DMA_CTL0_DIR_SHIFT_BITS);
                else
                        val &= ~(0x1 << (DMA_CTL0_BITS_PER_CH * ch +
                                         DMA_CTL0_DIR_SHIFT_BITS));
-
+               val |= mask_ctl;
                dma_writel(pd, CTL3, val);
        }
 
@@ -236,33 +260,37 @@ static void pdc_set_mode(struct dma_chan *chan, u32 mode)
 {
        struct pch_dma *pd = to_pd(chan->device);
        u32 val;
+       u32 mask_ctl;
+       u32 mask_dir;
 
        if (chan->chan_id < 8) {
+               mask_ctl = DMA_MASK_CTL0_MODE & ~(DMA_CTL0_MODE_MASK_BITS <<
+                          (DMA_CTL0_BITS_PER_CH * chan->chan_id));
+               mask_dir = 1 << (DMA_CTL0_BITS_PER_CH * chan->chan_id +\
+                                DMA_CTL0_DIR_SHIFT_BITS);
                val = dma_readl(pd, CTL0);
-
-               val &= ~(DMA_CTL0_MODE_MASK_BITS <<
-                       (DMA_CTL0_BITS_PER_CH * chan->chan_id));
+               val &= mask_dir;
                val |= mode << (DMA_CTL0_BITS_PER_CH * chan->chan_id);
-
+               val |= mask_ctl;
                dma_writel(pd, CTL0, val);
        } else {
                int ch = chan->chan_id - 8; /* ch8-->0 ch9-->1 ... ch11->3 */
-
+               mask_ctl = DMA_MASK_CTL2_MODE & ~(DMA_CTL0_MODE_MASK_BITS <<
+                                                (DMA_CTL0_BITS_PER_CH * ch));
+               mask_dir = 1 << (DMA_CTL0_BITS_PER_CH * ch +\
+                                DMA_CTL0_DIR_SHIFT_BITS);
                val = dma_readl(pd, CTL3);
-
-               val &= ~(DMA_CTL0_MODE_MASK_BITS <<
-                       (DMA_CTL0_BITS_PER_CH * ch));
+               val &= mask_dir;
                val |= mode << (DMA_CTL0_BITS_PER_CH * ch);
-
+               val |= mask_ctl;
                dma_writel(pd, CTL3, val);
-
        }
 
        dev_dbg(chan2dev(chan), "pdc_set_mode: chan %d -> %x\n",
                chan->chan_id, val);
 }
 
-static u32 pdc_get_status(struct pch_dma_chan *pd_chan)
+static u32 pdc_get_status0(struct pch_dma_chan *pd_chan)
 {
        struct pch_dma *pd = to_pd(pd_chan->chan.device);
        u32 val;
@@ -272,9 +300,27 @@ static u32 pdc_get_status(struct pch_dma_chan *pd_chan)
                        DMA_STATUS_BITS_PER_CH * pd_chan->chan.chan_id));
 }
 
+static u32 pdc_get_status2(struct pch_dma_chan *pd_chan)
+{
+       struct pch_dma *pd = to_pd(pd_chan->chan.device);
+       u32 val;
+
+       val = dma_readl(pd, STS2);
+       return DMA_STATUS_MASK_BITS & (val >> (DMA_STATUS_SHIFT_BITS +
+                       DMA_STATUS_BITS_PER_CH * (pd_chan->chan.chan_id - 8)));
+}
+
 static bool pdc_is_idle(struct pch_dma_chan *pd_chan)
 {
-       if (pdc_get_status(pd_chan) == DMA_STATUS_IDLE)
+       u32 sts;
+
+       if (pd_chan->chan.chan_id < 8)
+               sts = pdc_get_status0(pd_chan);
+       else
+               sts = pdc_get_status2(pd_chan);
+
+
+       if (sts == DMA_STATUS_IDLE)
                return true;
        else
                return false;
@@ -495,11 +541,11 @@ static int pd_alloc_chan_resources(struct dma_chan *chan)
                list_add_tail(&desc->desc_node, &tmp_list);
        }
 
-       spin_lock_bh(&pd_chan->lock);
+       spin_lock_irq(&pd_chan->lock);
        list_splice(&tmp_list, &pd_chan->free_list);
        pd_chan->descs_allocated = i;
        pd_chan->completed_cookie = chan->cookie = 1;
-       spin_unlock_bh(&pd_chan->lock);
+       spin_unlock_irq(&pd_chan->lock);
 
        pdc_enable_irq(chan, 1);
 
@@ -517,10 +563,10 @@ static void pd_free_chan_resources(struct dma_chan *chan)
        BUG_ON(!list_empty(&pd_chan->active_list));
        BUG_ON(!list_empty(&pd_chan->queue));
 
-       spin_lock_bh(&pd_chan->lock);
+       spin_lock_irq(&pd_chan->lock);
        list_splice_init(&pd_chan->free_list, &tmp_list);
        pd_chan->descs_allocated = 0;
-       spin_unlock_bh(&pd_chan->lock);
+       spin_unlock_irq(&pd_chan->lock);
 
        list_for_each_entry_safe(desc, _d, &tmp_list, desc_node)
                pci_pool_free(pd->pool, desc, desc->txd.phys);
@@ -536,10 +582,10 @@ static enum dma_status pd_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
        dma_cookie_t last_completed;
        int ret;
 
-       spin_lock_bh(&pd_chan->lock);
+       spin_lock_irq(&pd_chan->lock);
        last_completed = pd_chan->completed_cookie;
        last_used = chan->cookie;
-       spin_unlock_bh(&pd_chan->lock);
+       spin_unlock_irq(&pd_chan->lock);
 
        ret = dma_async_is_complete(cookie, last_completed, last_used);
 
@@ -654,7 +700,7 @@ static int pd_device_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
        if (cmd != DMA_TERMINATE_ALL)
                return -ENXIO;
 
-       spin_lock_bh(&pd_chan->lock);
+       spin_lock_irq(&pd_chan->lock);
 
        pdc_set_mode(&pd_chan->chan, DMA_CTL0_DISABLE);
 
@@ -664,7 +710,7 @@ static int pd_device_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
        list_for_each_entry_safe(desc, _d, &list, desc_node)
                pdc_chain_complete(pd_chan, desc);
 
-       spin_unlock_bh(&pd_chan->lock);
+       spin_unlock_irq(&pd_chan->lock);
 
        return 0;
 }
@@ -693,30 +739,45 @@ static irqreturn_t pd_irq(int irq, void *devid)
        struct pch_dma *pd = (struct pch_dma *)devid;
        struct pch_dma_chan *pd_chan;
        u32 sts0;
+       u32 sts2;
        int i;
-       int ret = IRQ_NONE;
+       int ret0 = IRQ_NONE;
+       int ret2 = IRQ_NONE;
 
        sts0 = dma_readl(pd, STS0);
+       sts2 = dma_readl(pd, STS2);
 
        dev_dbg(pd->dma.dev, "pd_irq sts0: %x\n", sts0);
 
        for (i = 0; i < pd->dma.chancnt; i++) {
                pd_chan = &pd->channels[i];
 
-               if (sts0 & DMA_STATUS_IRQ(i)) {
-                       if (sts0 & DMA_STATUS_ERR(i))
-                               set_bit(0, &pd_chan->err_status);
+               if (i < 8) {
+                       if (sts0 & DMA_STATUS_IRQ(i)) {
+                               if (sts0 & DMA_STATUS0_ERR(i))
+                                       set_bit(0, &pd_chan->err_status);
 
-                       tasklet_schedule(&pd_chan->tasklet);
-                       ret = IRQ_HANDLED;
-               }
+                               tasklet_schedule(&pd_chan->tasklet);
+                               ret0 = IRQ_HANDLED;
+                       }
+               } else {
+                       if (sts2 & DMA_STATUS_IRQ(i - 8)) {
+                               if (sts2 & DMA_STATUS2_ERR(i))
+                                       set_bit(0, &pd_chan->err_status);
 
+                               tasklet_schedule(&pd_chan->tasklet);
+                               ret2 = IRQ_HANDLED;
+                       }
+               }
        }
 
        /* clear interrupt bits in status register */
-       dma_writel(pd, STS0, sts0);
+       if (ret0)
+               dma_writel(pd, STS0, sts0);
+       if (ret2)
+               dma_writel(pd, STS2, sts2);
 
-       return ret;
+       return ret0 | ret2;
 }
 
 #ifdef CONFIG_PM
index 6abe1ec..00eee59 100644 (file)
@@ -82,7 +82,7 @@ struct dma_pl330_dmac {
        spinlock_t pool_lock;
 
        /* Peripheral channels connected to this DMAC */
-       struct dma_pl330_chan peripherals[0]; /* keep at end */
+       struct dma_pl330_chan *peripherals; /* keep at end */
 };
 
 struct dma_pl330_desc {
@@ -451,8 +451,13 @@ static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch)
        desc->txd.cookie = 0;
        async_tx_ack(&desc->txd);
 
-       desc->req.rqtype = peri->rqtype;
-       desc->req.peri = peri->peri_id;
+       if (peri) {
+               desc->req.rqtype = peri->rqtype;
+               desc->req.peri = peri->peri_id;
+       } else {
+               desc->req.rqtype = MEMTOMEM;
+               desc->req.peri = 0;
+       }
 
        dma_async_tx_descriptor_init(&desc->txd, &pch->chan);
 
@@ -529,10 +534,10 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst,
        struct pl330_info *pi;
        int burst;
 
-       if (unlikely(!pch || !len || !peri))
+       if (unlikely(!pch || !len))
                return NULL;
 
-       if (peri->rqtype != MEMTOMEM)
+       if (peri && peri->rqtype != MEMTOMEM)
                return NULL;
 
        pi = &pch->dmac->pif;
@@ -577,7 +582,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
        int i, burst_size;
        dma_addr_t addr;
 
-       if (unlikely(!pch || !sgl || !sg_len))
+       if (unlikely(!pch || !sgl || !sg_len || !peri))
                return NULL;
 
        /* Make sure the direction is consistent */
@@ -666,17 +671,12 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
        struct dma_device *pd;
        struct resource *res;
        int i, ret, irq;
+       int num_chan;
 
        pdat = adev->dev.platform_data;
 
-       if (!pdat || !pdat->nr_valid_peri) {
-               dev_err(&adev->dev, "platform data missing\n");
-               return -ENODEV;
-       }
-
        /* Allocate a new DMAC and its Channels */
-       pdmac = kzalloc(pdat->nr_valid_peri * sizeof(*pch)
-                               + sizeof(*pdmac), GFP_KERNEL);
+       pdmac = kzalloc(sizeof(*pdmac), GFP_KERNEL);
        if (!pdmac) {
                dev_err(&adev->dev, "unable to allocate mem\n");
                return -ENOMEM;
@@ -685,7 +685,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
        pi = &pdmac->pif;
        pi->dev = &adev->dev;
        pi->pl330_data = NULL;
-       pi->mcbufsz = pdat->mcbuf_sz;
+       pi->mcbufsz = pdat ? pdat->mcbuf_sz : 0;
 
        res = &adev->res;
        request_mem_region(res->start, resource_size(res), "dma-pl330");
@@ -717,27 +717,35 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
        INIT_LIST_HEAD(&pd->channels);
 
        /* Initialize channel parameters */
-       for (i = 0; i < pdat->nr_valid_peri; i++) {
-               struct dma_pl330_peri *peri = &pdat->peri[i];
-               pch = &pdmac->peripherals[i];
+       num_chan = max(pdat ? pdat->nr_valid_peri : 0, (u8)pi->pcfg.num_chan);
+       pdmac->peripherals = kzalloc(num_chan * sizeof(*pch), GFP_KERNEL);
 
-               switch (peri->rqtype) {
-               case MEMTOMEM:
+       for (i = 0; i < num_chan; i++) {
+               pch = &pdmac->peripherals[i];
+               if (pdat) {
+                       struct dma_pl330_peri *peri = &pdat->peri[i];
+
+                       switch (peri->rqtype) {
+                       case MEMTOMEM:
+                               dma_cap_set(DMA_MEMCPY, pd->cap_mask);
+                               break;
+                       case MEMTODEV:
+                       case DEVTOMEM:
+                               dma_cap_set(DMA_SLAVE, pd->cap_mask);
+                               break;
+                       default:
+                               dev_err(&adev->dev, "DEVTODEV Not Supported\n");
+                               continue;
+                       }
+                       pch->chan.private = peri;
+               } else {
                        dma_cap_set(DMA_MEMCPY, pd->cap_mask);
-                       break;
-               case MEMTODEV:
-               case DEVTOMEM:
-                       dma_cap_set(DMA_SLAVE, pd->cap_mask);
-                       break;
-               default:
-                       dev_err(&adev->dev, "DEVTODEV Not Supported\n");
-                       continue;
+                       pch->chan.private = NULL;
                }
 
                INIT_LIST_HEAD(&pch->work_list);
                spin_lock_init(&pch->lock);
                pch->pl330_chid = NULL;
-               pch->chan.private = peri;
                pch->chan.device = pd;
                pch->chan.chan_id = i;
                pch->dmac = pdmac;
index 0283300..7f49235 100644 (file)
@@ -70,12 +70,36 @@ static u32 sh_dmae_readl(struct sh_dmae_chan *sh_dc, u32 reg)
 
 static u16 dmaor_read(struct sh_dmae_device *shdev)
 {
-       return __raw_readw(shdev->chan_reg + DMAOR / sizeof(u32));
+       u32 __iomem *addr = shdev->chan_reg + DMAOR / sizeof(u32);
+
+       if (shdev->pdata->dmaor_is_32bit)
+               return __raw_readl(addr);
+       else
+               return __raw_readw(addr);
 }
 
 static void dmaor_write(struct sh_dmae_device *shdev, u16 data)
 {
-       __raw_writew(data, shdev->chan_reg + DMAOR / sizeof(u32));
+       u32 __iomem *addr = shdev->chan_reg + DMAOR / sizeof(u32);
+
+       if (shdev->pdata->dmaor_is_32bit)
+               __raw_writel(data, addr);
+       else
+               __raw_writew(data, addr);
+}
+
+static void chcr_write(struct sh_dmae_chan *sh_dc, u32 data)
+{
+       struct sh_dmae_device *shdev = to_sh_dev(sh_dc);
+
+       __raw_writel(data, sh_dc->base + shdev->chcr_offset / sizeof(u32));
+}
+
+static u32 chcr_read(struct sh_dmae_chan *sh_dc)
+{
+       struct sh_dmae_device *shdev = to_sh_dev(sh_dc);
+
+       return __raw_readl(sh_dc->base + shdev->chcr_offset / sizeof(u32));
 }
 
 /*
@@ -120,7 +144,7 @@ static int sh_dmae_rst(struct sh_dmae_device *shdev)
 
 static bool dmae_is_busy(struct sh_dmae_chan *sh_chan)
 {
-       u32 chcr = sh_dmae_readl(sh_chan, CHCR);
+       u32 chcr = chcr_read(sh_chan);
 
        if ((chcr & (CHCR_DE | CHCR_TE)) == CHCR_DE)
                return true; /* working */
@@ -130,8 +154,7 @@ static bool dmae_is_busy(struct sh_dmae_chan *sh_chan)
 
 static unsigned int calc_xmit_shift(struct sh_dmae_chan *sh_chan, u32 chcr)
 {
-       struct sh_dmae_device *shdev = container_of(sh_chan->common.device,
-                                               struct sh_dmae_device, common);
+       struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
        struct sh_dmae_pdata *pdata = shdev->pdata;
        int cnt = ((chcr & pdata->ts_low_mask) >> pdata->ts_low_shift) |
                ((chcr & pdata->ts_high_mask) >> pdata->ts_high_shift);
@@ -144,8 +167,7 @@ static unsigned int calc_xmit_shift(struct sh_dmae_chan *sh_chan, u32 chcr)
 
 static u32 log2size_to_chcr(struct sh_dmae_chan *sh_chan, int l2size)
 {
-       struct sh_dmae_device *shdev = container_of(sh_chan->common.device,
-                                               struct sh_dmae_device, common);
+       struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
        struct sh_dmae_pdata *pdata = shdev->pdata;
        int i;
 
@@ -169,18 +191,23 @@ static void dmae_set_reg(struct sh_dmae_chan *sh_chan, struct sh_dmae_regs *hw)
 
 static void dmae_start(struct sh_dmae_chan *sh_chan)
 {
-       u32 chcr = sh_dmae_readl(sh_chan, CHCR);
+       struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
+       u32 chcr = chcr_read(sh_chan);
+
+       if (shdev->pdata->needs_tend_set)
+               sh_dmae_writel(sh_chan, 0xFFFFFFFF, TEND);
 
-       chcr |= CHCR_DE | CHCR_IE;
-       sh_dmae_writel(sh_chan, chcr & ~CHCR_TE, CHCR);
+       chcr |= CHCR_DE | shdev->chcr_ie_bit;
+       chcr_write(sh_chan, chcr & ~CHCR_TE);
 }
 
 static void dmae_halt(struct sh_dmae_chan *sh_chan)
 {
-       u32 chcr = sh_dmae_readl(sh_chan, CHCR);
+       struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
+       u32 chcr = chcr_read(sh_chan);
 
-       chcr &= ~(CHCR_DE | CHCR_TE | CHCR_IE);
-       sh_dmae_writel(sh_chan, chcr, CHCR);
+       chcr &= ~(CHCR_DE | CHCR_TE | shdev->chcr_ie_bit);
+       chcr_write(sh_chan, chcr);
 }
 
 static void dmae_init(struct sh_dmae_chan *sh_chan)
@@ -192,7 +219,7 @@ static void dmae_init(struct sh_dmae_chan *sh_chan)
        u32 chcr = DM_INC | SM_INC | 0x400 | log2size_to_chcr(sh_chan,
                                                   LOG2_DEFAULT_XFER_SIZE);
        sh_chan->xmit_shift = calc_xmit_shift(sh_chan, chcr);
-       sh_dmae_writel(sh_chan, chcr, CHCR);
+       chcr_write(sh_chan, chcr);
 }
 
 static int dmae_set_chcr(struct sh_dmae_chan *sh_chan, u32 val)
@@ -202,23 +229,25 @@ static int dmae_set_chcr(struct sh_dmae_chan *sh_chan, u32 val)
                return -EBUSY;
 
        sh_chan->xmit_shift = calc_xmit_shift(sh_chan, val);
-       sh_dmae_writel(sh_chan, val, CHCR);
+       chcr_write(sh_chan, val);
 
        return 0;
 }
 
 static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val)
 {
-       struct sh_dmae_device *shdev = container_of(sh_chan->common.device,
-                                               struct sh_dmae_device, common);
+       struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
        struct sh_dmae_pdata *pdata = shdev->pdata;
        const struct sh_dmae_channel *chan_pdata = &pdata->channel[sh_chan->id];
        u16 __iomem *addr = shdev->dmars;
-       int shift = chan_pdata->dmars_bit;
+       unsigned int shift = chan_pdata->dmars_bit;
 
        if (dmae_is_busy(sh_chan))
                return -EBUSY;
 
+       if (pdata->no_dmars)
+               return 0;
+
        /* in the case of a missing DMARS resource use first memory window */
        if (!addr)
                addr = (u16 __iomem *)shdev->chan_reg;
@@ -296,9 +325,7 @@ static struct sh_desc *sh_dmae_get_desc(struct sh_dmae_chan *sh_chan)
 static const struct sh_dmae_slave_config *sh_dmae_find_slave(
        struct sh_dmae_chan *sh_chan, struct sh_dmae_slave *param)
 {
-       struct dma_device *dma_dev = sh_chan->common.device;
-       struct sh_dmae_device *shdev = container_of(dma_dev,
-                                       struct sh_dmae_device, common);
+       struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
        struct sh_dmae_pdata *pdata = shdev->pdata;
        int i;
 
@@ -771,10 +798,8 @@ static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan)
 
        spin_lock_bh(&sh_chan->desc_lock);
        /* DMA work check */
-       if (dmae_is_busy(sh_chan)) {
-               spin_unlock_bh(&sh_chan->desc_lock);
-               return;
-       }
+       if (dmae_is_busy(sh_chan))
+               goto sh_chan_xfer_ld_queue_end;
 
        /* Find the first not transferred descriptor */
        list_for_each_entry(desc, &sh_chan->ld_queue, node)
@@ -788,6 +813,7 @@ static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan)
                        break;
                }
 
+sh_chan_xfer_ld_queue_end:
        spin_unlock_bh(&sh_chan->desc_lock);
 }
 
@@ -846,7 +872,7 @@ static irqreturn_t sh_dmae_interrupt(int irq, void *data)
 
        spin_lock(&sh_chan->desc_lock);
 
-       chcr = sh_dmae_readl(sh_chan, CHCR);
+       chcr = chcr_read(sh_chan);
 
        if (chcr & CHCR_TE) {
                /* DMA stop */
@@ -1144,6 +1170,16 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
        /* platform data */
        shdev->pdata = pdata;
 
+       if (pdata->chcr_offset)
+               shdev->chcr_offset = pdata->chcr_offset;
+       else
+               shdev->chcr_offset = CHCR;
+
+       if (pdata->chcr_ie_bit)
+               shdev->chcr_ie_bit = pdata->chcr_ie_bit;
+       else
+               shdev->chcr_ie_bit = CHCR_IE;
+
        platform_set_drvdata(pdev, shdev);
 
        pm_runtime_enable(&pdev->dev);
index 5ae9fc5..dc56576 100644 (file)
@@ -47,10 +47,14 @@ struct sh_dmae_device {
        struct list_head node;
        u32 __iomem *chan_reg;
        u16 __iomem *dmars;
+       unsigned int chcr_offset;
+       u32 chcr_ie_bit;
 };
 
 #define to_sh_chan(chan) container_of(chan, struct sh_dmae_chan, common)
 #define to_sh_desc(lh) container_of(lh, struct sh_desc, node)
 #define tx_to_sh_desc(tx) container_of(tx, struct sh_desc, async_tx)
+#define to_sh_dev(chan) container_of(chan->common.device,\
+                                    struct sh_dmae_device, common)
 
 #endif /* __DMA_SHDMA_H */
index 29d1add..cd3a7c7 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/err.h>
+#include <linux/amba/bus.h>
 
 #include <plat/ste_dma40.h>
 
@@ -45,9 +46,6 @@
 #define D40_ALLOC_PHY          (1 << 30)
 #define D40_ALLOC_LOG_FREE     0
 
-/* Hardware designer of the block */
-#define D40_HW_DESIGNER 0x8
-
 /**
  * enum 40_command - The different commands and/or statuses.
  *
@@ -186,6 +184,8 @@ struct d40_base;
  * @log_def: Default logical channel settings.
  * @lcla: Space for one dst src pair for logical channel transfers.
  * @lcpa: Pointer to dst and src lcpa settings.
+ * @runtime_addr: runtime configured address.
+ * @runtime_direction: runtime configured direction.
  *
  * This struct can either "be" a logical or a physical channel.
  */
@@ -200,6 +200,7 @@ struct d40_chan {
        struct dma_chan                  chan;
        struct tasklet_struct            tasklet;
        struct list_head                 client;
+       struct list_head                 pending_queue;
        struct list_head                 active;
        struct list_head                 queue;
        struct stedma40_chan_cfg         dma_cfg;
@@ -645,7 +646,20 @@ static struct d40_desc *d40_first_active_get(struct d40_chan *d40c)
 
 static void d40_desc_queue(struct d40_chan *d40c, struct d40_desc *desc)
 {
-       list_add_tail(&desc->node, &d40c->queue);
+       list_add_tail(&desc->node, &d40c->pending_queue);
+}
+
+static struct d40_desc *d40_first_pending(struct d40_chan *d40c)
+{
+       struct d40_desc *d;
+
+       if (list_empty(&d40c->pending_queue))
+               return NULL;
+
+       d = list_first_entry(&d40c->pending_queue,
+                            struct d40_desc,
+                            node);
+       return d;
 }
 
 static struct d40_desc *d40_first_queued(struct d40_chan *d40c)
@@ -802,6 +816,11 @@ static void d40_term_all(struct d40_chan *d40c)
                d40_desc_free(d40c, d40d);
        }
 
+       /* Release pending descriptors */
+       while ((d40d = d40_first_pending(d40c))) {
+               d40_desc_remove(d40d);
+               d40_desc_free(d40c, d40d);
+       }
 
        d40c->pending_tx = 0;
        d40c->busy = false;
@@ -2092,7 +2111,7 @@ dma40_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr,
        struct scatterlist *sg;
        int i;
 
-       sg = kcalloc(periods + 1, sizeof(struct scatterlist), GFP_KERNEL);
+       sg = kcalloc(periods + 1, sizeof(struct scatterlist), GFP_NOWAIT);
        for (i = 0; i < periods; i++) {
                sg_dma_address(&sg[i]) = dma_addr;
                sg_dma_len(&sg[i]) = period_len;
@@ -2152,24 +2171,87 @@ static void d40_issue_pending(struct dma_chan *chan)
 
        spin_lock_irqsave(&d40c->lock, flags);
 
-       /* Busy means that pending jobs are already being processed */
+       list_splice_tail_init(&d40c->pending_queue, &d40c->queue);
+
+       /* Busy means that queued jobs are already being processed */
        if (!d40c->busy)
                (void) d40_queue_start(d40c);
 
        spin_unlock_irqrestore(&d40c->lock, flags);
 }
 
+static int
+dma40_config_to_halfchannel(struct d40_chan *d40c,
+                           struct stedma40_half_channel_info *info,
+                           enum dma_slave_buswidth width,
+                           u32 maxburst)
+{
+       enum stedma40_periph_data_width addr_width;
+       int psize;
+
+       switch (width) {
+       case DMA_SLAVE_BUSWIDTH_1_BYTE:
+               addr_width = STEDMA40_BYTE_WIDTH;
+               break;
+       case DMA_SLAVE_BUSWIDTH_2_BYTES:
+               addr_width = STEDMA40_HALFWORD_WIDTH;
+               break;
+       case DMA_SLAVE_BUSWIDTH_4_BYTES:
+               addr_width = STEDMA40_WORD_WIDTH;
+               break;
+       case DMA_SLAVE_BUSWIDTH_8_BYTES:
+               addr_width = STEDMA40_DOUBLEWORD_WIDTH;
+               break;
+       default:
+               dev_err(d40c->base->dev,
+                       "illegal peripheral address width "
+                       "requested (%d)\n",
+                       width);
+               return -EINVAL;
+       }
+
+       if (chan_is_logical(d40c)) {
+               if (maxburst >= 16)
+                       psize = STEDMA40_PSIZE_LOG_16;
+               else if (maxburst >= 8)
+                       psize = STEDMA40_PSIZE_LOG_8;
+               else if (maxburst >= 4)
+                       psize = STEDMA40_PSIZE_LOG_4;
+               else
+                       psize = STEDMA40_PSIZE_LOG_1;
+       } else {
+               if (maxburst >= 16)
+                       psize = STEDMA40_PSIZE_PHY_16;
+               else if (maxburst >= 8)
+                       psize = STEDMA40_PSIZE_PHY_8;
+               else if (maxburst >= 4)
+                       psize = STEDMA40_PSIZE_PHY_4;
+               else
+                       psize = STEDMA40_PSIZE_PHY_1;
+       }
+
+       info->data_width = addr_width;
+       info->psize = psize;
+       info->flow_ctrl = STEDMA40_NO_FLOW_CTRL;
+
+       return 0;
+}
+
 /* Runtime reconfiguration extension */
-static void d40_set_runtime_config(struct dma_chan *chan,
-                              struct dma_slave_config *config)
+static int d40_set_runtime_config(struct dma_chan *chan,
+                                 struct dma_slave_config *config)
 {
        struct d40_chan *d40c = container_of(chan, struct d40_chan, chan);
        struct stedma40_chan_cfg *cfg = &d40c->dma_cfg;
-       enum dma_slave_buswidth config_addr_width;
+       enum dma_slave_buswidth src_addr_width, dst_addr_width;
        dma_addr_t config_addr;
-       u32 config_maxburst;
-       enum stedma40_periph_data_width addr_width;
-       int psize;
+       u32 src_maxburst, dst_maxburst;
+       int ret;
+
+       src_addr_width = config->src_addr_width;
+       src_maxburst = config->src_maxburst;
+       dst_addr_width = config->dst_addr_width;
+       dst_maxburst = config->dst_maxburst;
 
        if (config->direction == DMA_FROM_DEVICE) {
                dma_addr_t dev_addr_rx =
@@ -2188,8 +2270,11 @@ static void d40_set_runtime_config(struct dma_chan *chan,
                                cfg->dir);
                cfg->dir = STEDMA40_PERIPH_TO_MEM;
 
-               config_addr_width = config->src_addr_width;
-               config_maxburst = config->src_maxburst;
+               /* Configure the memory side */
+               if (dst_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
+                       dst_addr_width = src_addr_width;
+               if (dst_maxburst == 0)
+                       dst_maxburst = src_maxburst;
 
        } else if (config->direction == DMA_TO_DEVICE) {
                dma_addr_t dev_addr_tx =
@@ -2208,68 +2293,39 @@ static void d40_set_runtime_config(struct dma_chan *chan,
                                cfg->dir);
                cfg->dir = STEDMA40_MEM_TO_PERIPH;
 
-               config_addr_width = config->dst_addr_width;
-               config_maxburst = config->dst_maxburst;
-
+               /* Configure the memory side */
+               if (src_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
+                       src_addr_width = dst_addr_width;
+               if (src_maxburst == 0)
+                       src_maxburst = dst_maxburst;
        } else {
                dev_err(d40c->base->dev,
                        "unrecognized channel direction %d\n",
                        config->direction);
-               return;
+               return -EINVAL;
        }
 
-       switch (config_addr_width) {
-       case DMA_SLAVE_BUSWIDTH_1_BYTE:
-               addr_width = STEDMA40_BYTE_WIDTH;
-               break;
-       case DMA_SLAVE_BUSWIDTH_2_BYTES:
-               addr_width = STEDMA40_HALFWORD_WIDTH;
-               break;
-       case DMA_SLAVE_BUSWIDTH_4_BYTES:
-               addr_width = STEDMA40_WORD_WIDTH;
-               break;
-       case DMA_SLAVE_BUSWIDTH_8_BYTES:
-               addr_width = STEDMA40_DOUBLEWORD_WIDTH;
-               break;
-       default:
+       if (src_maxburst * src_addr_width != dst_maxburst * dst_addr_width) {
                dev_err(d40c->base->dev,
-                       "illegal peripheral address width "
-                       "requested (%d)\n",
-                       config->src_addr_width);
-               return;
+                       "src/dst width/maxburst mismatch: %d*%d != %d*%d\n",
+                       src_maxburst,
+                       src_addr_width,
+                       dst_maxburst,
+                       dst_addr_width);
+               return -EINVAL;
        }
 
-       if (chan_is_logical(d40c)) {
-               if (config_maxburst >= 16)
-                       psize = STEDMA40_PSIZE_LOG_16;
-               else if (config_maxburst >= 8)
-                       psize = STEDMA40_PSIZE_LOG_8;
-               else if (config_maxburst >= 4)
-                       psize = STEDMA40_PSIZE_LOG_4;
-               else
-                       psize = STEDMA40_PSIZE_LOG_1;
-       } else {
-               if (config_maxburst >= 16)
-                       psize = STEDMA40_PSIZE_PHY_16;
-               else if (config_maxburst >= 8)
-                       psize = STEDMA40_PSIZE_PHY_8;
-               else if (config_maxburst >= 4)
-                       psize = STEDMA40_PSIZE_PHY_4;
-               else if (config_maxburst >= 2)
-                       psize = STEDMA40_PSIZE_PHY_2;
-               else
-                       psize = STEDMA40_PSIZE_PHY_1;
-       }
+       ret = dma40_config_to_halfchannel(d40c, &cfg->src_info,
+                                         src_addr_width,
+                                         src_maxburst);
+       if (ret)
+               return ret;
 
-       /* Set up all the endpoint configs */
-       cfg->src_info.data_width = addr_width;
-       cfg->src_info.psize = psize;
-       cfg->src_info.big_endian = false;
-       cfg->src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL;
-       cfg->dst_info.data_width = addr_width;
-       cfg->dst_info.psize = psize;
-       cfg->dst_info.big_endian = false;
-       cfg->dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL;
+       ret = dma40_config_to_halfchannel(d40c, &cfg->dst_info,
+                                         dst_addr_width,
+                                         dst_maxburst);
+       if (ret)
+               return ret;
 
        /* Fill in register values */
        if (chan_is_logical(d40c))
@@ -2282,12 +2338,14 @@ static void d40_set_runtime_config(struct dma_chan *chan,
        d40c->runtime_addr = config_addr;
        d40c->runtime_direction = config->direction;
        dev_dbg(d40c->base->dev,
-               "configured channel %s for %s, data width %d, "
-               "maxburst %d bytes, LE, no flow control\n",
+               "configured channel %s for %s, data width %d/%d, "
+               "maxburst %d/%d elements, LE, no flow control\n",
                dma_chan_name(chan),
                (config->direction == DMA_FROM_DEVICE) ? "RX" : "TX",
-               config_addr_width,
-               config_maxburst);
+               src_addr_width, dst_addr_width,
+               src_maxburst, dst_maxburst);
+
+       return 0;
 }
 
 static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
@@ -2308,9 +2366,8 @@ static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
        case DMA_RESUME:
                return d40_resume(d40c);
        case DMA_SLAVE_CONFIG:
-               d40_set_runtime_config(chan,
+               return d40_set_runtime_config(chan,
                        (struct dma_slave_config *) arg);
-               return 0;
        default:
                break;
        }
@@ -2341,6 +2398,7 @@ static void __init d40_chan_init(struct d40_base *base, struct dma_device *dma,
 
                INIT_LIST_HEAD(&d40c->active);
                INIT_LIST_HEAD(&d40c->queue);
+               INIT_LIST_HEAD(&d40c->pending_queue);
                INIT_LIST_HEAD(&d40c->client);
 
                tasklet_init(&d40c->tasklet, dma_tasklet,
@@ -2502,25 +2560,6 @@ static int __init d40_phy_res_init(struct d40_base *base)
 
 static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
 {
-       static const struct d40_reg_val dma_id_regs[] = {
-               /* Peripheral Id */
-               { .reg = D40_DREG_PERIPHID0, .val = 0x0040},
-               { .reg = D40_DREG_PERIPHID1, .val = 0x0000},
-               /*
-                * D40_DREG_PERIPHID2 Depends on HW revision:
-                *  DB8500ed has 0x0008,
-                *  ? has 0x0018,
-                *  DB8500v1 has 0x0028
-                *  DB8500v2 has 0x0038
-                */
-               { .reg = D40_DREG_PERIPHID3, .val = 0x0000},
-
-               /* PCell Id */
-               { .reg = D40_DREG_CELLID0, .val = 0x000d},
-               { .reg = D40_DREG_CELLID1, .val = 0x00f0},
-               { .reg = D40_DREG_CELLID2, .val = 0x0005},
-               { .reg = D40_DREG_CELLID3, .val = 0x00b1}
-       };
        struct stedma40_platform_data *plat_data;
        struct clk *clk = NULL;
        void __iomem *virtbase = NULL;
@@ -2529,8 +2568,9 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
        int num_log_chans = 0;
        int num_phy_chans;
        int i;
-       u32 val;
-       u32 rev;
+       u32 pid;
+       u32 cid;
+       u8 rev;
 
        clk = clk_get(&pdev->dev, NULL);
 
@@ -2554,32 +2594,32 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
        if (!virtbase)
                goto failure;
 
-       /* HW version check */
-       for (i = 0; i < ARRAY_SIZE(dma_id_regs); i++) {
-               if (dma_id_regs[i].val !=
-                   readl(virtbase + dma_id_regs[i].reg)) {
-                       d40_err(&pdev->dev,
-                               "Unknown hardware! Expected 0x%x at 0x%x but got 0x%x\n",
-                               dma_id_regs[i].val,
-                               dma_id_regs[i].reg,
-                               readl(virtbase + dma_id_regs[i].reg));
-                       goto failure;
-               }
-       }
+       /* This is just a regular AMBA PrimeCell ID actually */
+       for (pid = 0, i = 0; i < 4; i++)
+               pid |= (readl(virtbase + resource_size(res) - 0x20 + 4 * i)
+                       & 255) << (i * 8);
+       for (cid = 0, i = 0; i < 4; i++)
+               cid |= (readl(virtbase + resource_size(res) - 0x10 + 4 * i)
+                       & 255) << (i * 8);
 
-       /* Get silicon revision and designer */
-       val = readl(virtbase + D40_DREG_PERIPHID2);
-
-       if ((val & D40_DREG_PERIPHID2_DESIGNER_MASK) !=
-           D40_HW_DESIGNER) {
+       if (cid != AMBA_CID) {
+               d40_err(&pdev->dev, "Unknown hardware! No PrimeCell ID\n");
+               goto failure;
+       }
+       if (AMBA_MANF_BITS(pid) != AMBA_VENDOR_ST) {
                d40_err(&pdev->dev, "Unknown designer! Got %x wanted %x\n",
-                       val & D40_DREG_PERIPHID2_DESIGNER_MASK,
-                       D40_HW_DESIGNER);
+                       AMBA_MANF_BITS(pid),
+                       AMBA_VENDOR_ST);
                goto failure;
        }
-
-       rev = (val & D40_DREG_PERIPHID2_REV_MASK) >>
-               D40_DREG_PERIPHID2_REV_POS;
+       /*
+        * HW revision:
+        * DB8500ed has revision 0
+        * ? has revision 1
+        * DB8500v1 has revision 2
+        * DB8500v2 has revision 3
+        */
+       rev = AMBA_REV_BITS(pid);
 
        /* The number of physical channels on this HW */
        num_phy_chans = 4 * (readl(virtbase + D40_DREG_ICFG) & 0x7) + 4;
index 195ee65..b44c455 100644 (file)
 #define D40_DREG_PERIPHID0     0xFE0
 #define D40_DREG_PERIPHID1     0xFE4
 #define D40_DREG_PERIPHID2     0xFE8
-#define D40_DREG_PERIPHID2_REV_POS 4
-#define D40_DREG_PERIPHID2_REV_MASK (0xf << D40_DREG_PERIPHID2_REV_POS)
-#define D40_DREG_PERIPHID2_DESIGNER_MASK 0xf
 #define D40_DREG_PERIPHID3     0xFEC
 #define D40_DREG_CELLID0       0xFF0
 #define D40_DREG_CELLID1       0xFF4
index 04f1e7c..f6cf448 100644 (file)
@@ -1670,7 +1670,7 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci,
        char *type, *optype, *err, *msg;
        unsigned long error = m->status & 0x1ff0000l;
        u32 optypenum = (m->status >> 4) & 0x07;
-       u32 core_err_cnt = (m->status >> 38) && 0x7fff;
+       u32 core_err_cnt = (m->status >> 38) & 0x7fff;
        u32 dimm = (m->misc >> 16) & 0x3;
        u32 channel = (m->misc >> 18) & 0x3;
        u32 syndrome = m->misc >> 32;
index 30da70d..cdae207 100644 (file)
@@ -45,13 +45,13 @@ static int __init pci_eisa_init(struct pci_dev *pdev,
        return 0;
 }
 
-static struct pci_device_id __initdata pci_eisa_pci_tbl[] = {
+static struct pci_device_id pci_eisa_pci_tbl[] = {
        { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
          PCI_CLASS_BRIDGE_EISA << 8, 0xffff00, 0 },
        { 0, }
 };
 
-static struct pci_driver __initdata pci_eisa_driver = {
+static struct pci_driver __refdata pci_eisa_driver = {
        .name           = "pci_eisa",
        .id_table       = pci_eisa_pci_tbl,
        .probe          = pci_eisa_init,
index e6ad3bb..4799393 100644 (file)
@@ -216,15 +216,33 @@ struct inbound_phy_packet_event {
        struct fw_cdev_event_phy_packet phy_packet;
 };
 
-static inline void __user *u64_to_uptr(__u64 value)
+#ifdef CONFIG_COMPAT
+static void __user *u64_to_uptr(u64 value)
+{
+       if (is_compat_task())
+               return compat_ptr(value);
+       else
+               return (void __user *)(unsigned long)value;
+}
+
+static u64 uptr_to_u64(void __user *ptr)
+{
+       if (is_compat_task())
+               return ptr_to_compat(ptr);
+       else
+               return (u64)(unsigned long)ptr;
+}
+#else
+static inline void __user *u64_to_uptr(u64 value)
 {
        return (void __user *)(unsigned long)value;
 }
 
-static inline __u64 uptr_to_u64(void __user *ptr)
+static inline u64 uptr_to_u64(void __user *ptr)
 {
-       return (__u64)(unsigned long)ptr;
+       return (u64)(unsigned long)ptr;
 }
+#endif /* CONFIG_COMPAT */
 
 static int fw_device_op_open(struct inode *inode, struct file *file)
 {
index 8ba7f79..f3b890d 100644 (file)
@@ -455,15 +455,20 @@ static struct device_attribute fw_device_attributes[] = {
 static int read_rom(struct fw_device *device,
                    int generation, int index, u32 *data)
 {
-       int rcode;
+       u64 offset = (CSR_REGISTER_BASE | CSR_CONFIG_ROM) + index * 4;
+       int i, rcode;
 
        /* device->node_id, accessed below, must not be older than generation */
        smp_rmb();
 
-       rcode = fw_run_transaction(device->card, TCODE_READ_QUADLET_REQUEST,
-                       device->node_id, generation, device->max_speed,
-                       (CSR_REGISTER_BASE | CSR_CONFIG_ROM) + index * 4,
-                       data, 4);
+       for (i = 10; i < 100; i += 10) {
+               rcode = fw_run_transaction(device->card,
+                               TCODE_READ_QUADLET_REQUEST, device->node_id,
+                               generation, device->max_speed, offset, data, 4);
+               if (rcode != RCODE_BUSY)
+                       break;
+               msleep(i);
+       }
        be32_to_cpus(data);
 
        return rcode;
index bcf792f..57cd3a4 100644 (file)
@@ -2179,8 +2179,13 @@ static int ohci_enable(struct fw_card *card,
                        ohci_driver_name, ohci)) {
                fw_error("Failed to allocate interrupt %d.\n", dev->irq);
                pci_disable_msi(dev);
-               dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
-                                 ohci->config_rom, ohci->config_rom_bus);
+
+               if (config_rom) {
+                       dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
+                                         ohci->next_config_rom,
+                                         ohci->next_config_rom_bus);
+                       ohci->next_config_rom = NULL;
+               }
                return -EIO;
        }
 
index 5f29aaf..eb80b54 100644 (file)
@@ -78,6 +78,7 @@
 #include <linux/kobject.h>
 #include <linux/device.h>
 #include <linux/slab.h>
+#include <linux/pstore.h>
 
 #include <asm/uaccess.h>
 
@@ -89,6 +90,8 @@ MODULE_DESCRIPTION("sysfs interface to EFI Variables");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(EFIVARS_VERSION);
 
+#define DUMP_NAME_LEN 52
+
 /*
  * The maximum size of VariableName + Data = 1024
  * Therefore, it's reasonable to save that much
@@ -119,6 +122,10 @@ struct efivar_attribute {
        ssize_t (*store)(struct efivar_entry *entry, const char *buf, size_t count);
 };
 
+#define PSTORE_EFI_ATTRIBUTES \
+       (EFI_VARIABLE_NON_VOLATILE | \
+        EFI_VARIABLE_BOOTSERVICE_ACCESS | \
+        EFI_VARIABLE_RUNTIME_ACCESS)
 
 #define EFIVAR_ATTR(_name, _mode, _show, _store) \
 struct efivar_attribute efivar_attr_##_name = { \
@@ -141,38 +148,72 @@ efivar_create_sysfs_entry(struct efivars *efivars,
 
 /* Return the number of unicode characters in data */
 static unsigned long
-utf8_strlen(efi_char16_t *data, unsigned long maxlength)
+utf16_strnlen(efi_char16_t *s, size_t maxlength)
 {
        unsigned long length = 0;
 
-       while (*data++ != 0 && length < maxlength)
+       while (*s++ != 0 && length < maxlength)
                length++;
        return length;
 }
 
+static inline unsigned long
+utf16_strlen(efi_char16_t *s)
+{
+       return utf16_strnlen(s, ~0UL);
+}
+
 /*
  * Return the number of bytes is the length of this string
  * Note: this is NOT the same as the number of unicode characters
  */
 static inline unsigned long
-utf8_strsize(efi_char16_t *data, unsigned long maxlength)
+utf16_strsize(efi_char16_t *data, unsigned long maxlength)
 {
-       return utf8_strlen(data, maxlength/sizeof(efi_char16_t)) * sizeof(efi_char16_t);
+       return utf16_strnlen(data, maxlength/sizeof(efi_char16_t)) * sizeof(efi_char16_t);
+}
+
+static inline int
+utf16_strncmp(const efi_char16_t *a, const efi_char16_t *b, size_t len)
+{
+       while (1) {
+               if (len == 0)
+                       return 0;
+               if (*a < *b)
+                       return -1;
+               if (*a > *b)
+                       return 1;
+               if (*a == 0) /* implies *b == 0 */
+                       return 0;
+               a++;
+               b++;
+               len--;
+       }
 }
 
 static efi_status_t
-get_var_data(struct efivars *efivars, struct efi_variable *var)
+get_var_data_locked(struct efivars *efivars, struct efi_variable *var)
 {
        efi_status_t status;
 
-       spin_lock(&efivars->lock);
        var->DataSize = 1024;
        status = efivars->ops->get_variable(var->VariableName,
                                            &var->VendorGuid,
                                            &var->Attributes,
                                            &var->DataSize,
                                            var->Data);
+       return status;
+}
+
+static efi_status_t
+get_var_data(struct efivars *efivars, struct efi_variable *var)
+{
+       efi_status_t status;
+
+       spin_lock(&efivars->lock);
+       status = get_var_data_locked(efivars, var);
        spin_unlock(&efivars->lock);
+
        if (status != EFI_SUCCESS) {
                printk(KERN_WARNING "efivars: get_variable() failed 0x%lx!\n",
                        status);
@@ -387,12 +428,180 @@ static struct kobj_type efivar_ktype = {
        .default_attrs = def_attrs,
 };
 
+static struct pstore_info efi_pstore_info;
+
 static inline void
 efivar_unregister(struct efivar_entry *var)
 {
        kobject_put(&var->kobj);
 }
 
+#ifdef CONFIG_PSTORE
+
+static int efi_pstore_open(struct pstore_info *psi)
+{
+       struct efivars *efivars = psi->data;
+
+       spin_lock(&efivars->lock);
+       efivars->walk_entry = list_first_entry(&efivars->list,
+                                              struct efivar_entry, list);
+       return 0;
+}
+
+static int efi_pstore_close(struct pstore_info *psi)
+{
+       struct efivars *efivars = psi->data;
+
+       spin_unlock(&efivars->lock);
+       return 0;
+}
+
+static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
+                              struct timespec *timespec, struct pstore_info *psi)
+{
+       efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
+       struct efivars *efivars = psi->data;
+       char name[DUMP_NAME_LEN];
+       int i;
+       unsigned int part, size;
+       unsigned long time;
+
+       while (&efivars->walk_entry->list != &efivars->list) {
+               if (!efi_guidcmp(efivars->walk_entry->var.VendorGuid,
+                                vendor)) {
+                       for (i = 0; i < DUMP_NAME_LEN; i++) {
+                               name[i] = efivars->walk_entry->var.VariableName[i];
+                       }
+                       if (sscanf(name, "dump-type%u-%u-%lu", type, &part, &time) == 3) {
+                               *id = part;
+                               timespec->tv_sec = time;
+                               timespec->tv_nsec = 0;
+                               get_var_data_locked(efivars, &efivars->walk_entry->var);
+                               size = efivars->walk_entry->var.DataSize;
+                               memcpy(psi->buf, efivars->walk_entry->var.Data, size);
+                               efivars->walk_entry = list_entry(efivars->walk_entry->list.next,
+                                                  struct efivar_entry, list);
+                               return size;
+                       }
+               }
+               efivars->walk_entry = list_entry(efivars->walk_entry->list.next,
+                                                struct efivar_entry, list);
+       }
+       return 0;
+}
+
+static u64 efi_pstore_write(enum pstore_type_id type, unsigned int part,
+                           size_t size, struct pstore_info *psi)
+{
+       char name[DUMP_NAME_LEN];
+       char stub_name[DUMP_NAME_LEN];
+       efi_char16_t efi_name[DUMP_NAME_LEN];
+       efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
+       struct efivars *efivars = psi->data;
+       struct efivar_entry *entry, *found = NULL;
+       int i;
+
+       sprintf(stub_name, "dump-type%u-%u-", type, part);
+       sprintf(name, "%s%lu", stub_name, get_seconds());
+
+       spin_lock(&efivars->lock);
+
+       for (i = 0; i < DUMP_NAME_LEN; i++)
+               efi_name[i] = stub_name[i];
+
+       /*
+        * Clean up any entries with the same name
+        */
+
+       list_for_each_entry(entry, &efivars->list, list) {
+               get_var_data_locked(efivars, &entry->var);
+
+               if (efi_guidcmp(entry->var.VendorGuid, vendor))
+                       continue;
+               if (utf16_strncmp(entry->var.VariableName, efi_name,
+                                 utf16_strlen(efi_name)))
+                       continue;
+               /* Needs to be a prefix */
+               if (entry->var.VariableName[utf16_strlen(efi_name)] == 0)
+                       continue;
+
+               /* found */
+               found = entry;
+               efivars->ops->set_variable(entry->var.VariableName,
+                                          &entry->var.VendorGuid,
+                                          PSTORE_EFI_ATTRIBUTES,
+                                          0, NULL);
+       }
+
+       if (found)
+               list_del(&found->list);
+
+       for (i = 0; i < DUMP_NAME_LEN; i++)
+               efi_name[i] = name[i];
+
+       efivars->ops->set_variable(efi_name, &vendor, PSTORE_EFI_ATTRIBUTES,
+                                  size, psi->buf);
+
+       spin_unlock(&efivars->lock);
+
+       if (found)
+               efivar_unregister(found);
+
+       if (size)
+               efivar_create_sysfs_entry(efivars,
+                                         utf16_strsize(efi_name,
+                                                       DUMP_NAME_LEN * 2),
+                                         efi_name, &vendor);
+
+       return part;
+};
+
+static int efi_pstore_erase(enum pstore_type_id type, u64 id,
+                           struct pstore_info *psi)
+{
+       efi_pstore_write(type, id, 0, psi);
+
+       return 0;
+}
+#else
+static int efi_pstore_open(struct pstore_info *psi)
+{
+       return 0;
+}
+
+static int efi_pstore_close(struct pstore_info *psi)
+{
+       return 0;
+}
+
+static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
+                              struct timespec *time, struct pstore_info *psi)
+{
+       return -1;
+}
+
+static u64 efi_pstore_write(enum pstore_type_id type, unsigned int part,
+                           size_t size, struct pstore_info *psi)
+{
+       return 0;
+}
+
+static int efi_pstore_erase(enum pstore_type_id type, u64 id,
+                           struct pstore_info *psi)
+{
+       return 0;
+}
+#endif
+
+static struct pstore_info efi_pstore_info = {
+       .owner          = THIS_MODULE,
+       .name           = "efi",
+       .open           = efi_pstore_open,
+       .close          = efi_pstore_close,
+       .read           = efi_pstore_read,
+       .write          = efi_pstore_write,
+       .erase          = efi_pstore_erase,
+};
 
 static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
                             struct bin_attribute *bin_attr,
@@ -414,8 +623,8 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
         * Does this variable already exist?
         */
        list_for_each_entry_safe(search_efivar, n, &efivars->list, list) {
-               strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024);
-               strsize2 = utf8_strsize(new_var->VariableName, 1024);
+               strsize1 = utf16_strsize(search_efivar->var.VariableName, 1024);
+               strsize2 = utf16_strsize(new_var->VariableName, 1024);
                if (strsize1 == strsize2 &&
                        !memcmp(&(search_efivar->var.VariableName),
                                new_var->VariableName, strsize1) &&
@@ -447,8 +656,8 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
 
        /* Create the entry in sysfs.  Locking is not required here */
        status = efivar_create_sysfs_entry(efivars,
-                                          utf8_strsize(new_var->VariableName,
-                                                       1024),
+                                          utf16_strsize(new_var->VariableName,
+                                                        1024),
                                           new_var->VariableName,
                                           &new_var->VendorGuid);
        if (status) {
@@ -477,8 +686,8 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
         * Does this variable already exist?
         */
        list_for_each_entry_safe(search_efivar, n, &efivars->list, list) {
-               strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024);
-               strsize2 = utf8_strsize(del_var->VariableName, 1024);
+               strsize1 = utf16_strsize(search_efivar->var.VariableName, 1024);
+               strsize2 = utf16_strsize(del_var->VariableName, 1024);
                if (strsize1 == strsize2 &&
                        !memcmp(&(search_efivar->var.VariableName),
                                del_var->VariableName, strsize1) &&
@@ -763,6 +972,16 @@ int register_efivars(struct efivars *efivars,
        if (error)
                unregister_efivars(efivars);
 
+       efivars->efi_pstore_info = efi_pstore_info;
+
+       efivars->efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL);
+       if (efivars->efi_pstore_info.buf) {
+               efivars->efi_pstore_info.bufsize = 1024;
+               efivars->efi_pstore_info.data = efivars;
+               mutex_init(&efivars->efi_pstore_info.buf_mutex);
+               pstore_register(&efivars->efi_pstore_info);
+       }
+
 out:
        kfree(variable_name);
 
index 3634986..d539efd 100644 (file)
@@ -103,6 +103,22 @@ config GPIO_MPC5200
        def_bool y
        depends on PPC_MPC52xx
 
+config GPIO_MSM_V1
+       tristate "Qualcomm MSM GPIO v1"
+       depends on GPIOLIB && ARCH_MSM
+       help
+         Say yes here to support the GPIO interface on ARM v6 based
+         Qualcomm MSM chips.  Most of the pins on the MSM can be
+         selected for GPIO, and are controlled by this driver.
+
+config GPIO_MSM_V2
+       tristate "Qualcomm MSM GPIO v2"
+       depends on GPIOLIB && ARCH_MSM
+       help
+         Say yes here to support the GPIO interface on ARM v7 based
+         Qualcomm MSM chips.  Most of the pins on the MSM can be
+         selected for GPIO, and are controlled by this driver.
+
 config GPIO_MXC
        def_bool y
        depends on ARCH_MXC
@@ -280,6 +296,12 @@ config GPIO_TC3589X
          This enables support for the GPIOs found on the TC3589X
          I/O Expander.
 
+config GPIO_TPS65912
+       tristate "TI TPS65912 GPIO"
+       depends on (MFD_TPS65912_I2C || MFD_TPS65912_SPI)
+       help
+         This driver supports TPS65912 gpio chip
+
 config GPIO_TWL4030
        tristate "TWL4030, TWL5030, and TPS659x0 GPIOs"
        depends on TWL4030_CORE
index 7207112..9588948 100644 (file)
@@ -27,6 +27,8 @@ obj-$(CONFIG_GPIO_MC33880)    += gpio-mc33880.o
 obj-$(CONFIG_GPIO_MCP23S08)    += gpio-mcp23s08.o
 obj-$(CONFIG_GPIO_ML_IOH)      += gpio-ml-ioh.o
 obj-$(CONFIG_GPIO_MPC5200)     += gpio-mpc5200.o
+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
@@ -48,6 +50,7 @@ obj-$(CONFIG_GPIO_TC3589X)    += gpio-tc3589x.o
 obj-$(CONFIG_ARCH_TEGRA)       += gpio-tegra.o
 obj-$(CONFIG_GPIO_TIMBERDALE)  += gpio-timberdale.o
 obj-$(CONFIG_GPIO_TPS65910)    += gpio-tps65910.o
+obj-$(CONFIG_GPIO_TPS65912)    += gpio-tps65912.o
 obj-$(CONFIG_GPIO_TWL4030)     += gpio-twl4030.o
 obj-$(CONFIG_MACH_U300)                += gpio-u300.o
 obj-$(CONFIG_GPIO_UCB1400)     += gpio-ucb1400.o
index ed795e6..050c05d 100644 (file)
@@ -516,5 +516,5 @@ module_exit(ab8500_gpio_exit);
 
 MODULE_AUTHOR("BIBEK BASU <bibek.basu@stericsson.com>");
 MODULE_DESCRIPTION("Driver allows to use AB8500 unused pins to be used as GPIO");
-MODULE_ALIAS("AB8500 GPIO driver");
+MODULE_ALIAS("platform:ab8500-gpio");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-msm-v1.c b/drivers/gpio/gpio-msm-v1.c
new file mode 100644 (file)
index 0000000..52a4d42
--- /dev/null
@@ -0,0 +1,636 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009-2011, Code Aurora Forum. 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/bitops.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <mach/cpu.h>
+#include <mach/msm_gpiomux.h>
+#include <mach/msm_iomap.h>
+
+/* see 80-VA736-2 Rev C pp 695-751
+**
+** These are actually the *shadow* gpio registers, since the
+** real ones (which allow full access) are only available to the
+** ARM9 side of the world.
+**
+** Since the _BASE need to be page-aligned when we're mapping them
+** to virtual addresses, adjust for the additional offset in these
+** macros.
+*/
+
+#define MSM_GPIO1_REG(off) (MSM_GPIO1_BASE + (off))
+#define MSM_GPIO2_REG(off) (MSM_GPIO2_BASE + 0x400 + (off))
+#define MSM_GPIO1_SHADOW_REG(off) (MSM_GPIO1_BASE + 0x800 + (off))
+#define MSM_GPIO2_SHADOW_REG(off) (MSM_GPIO2_BASE + 0xC00 + (off))
+
+/*
+ * MSM7X00 registers
+ */
+/* output value */
+#define MSM7X00_GPIO_OUT_0     MSM_GPIO1_SHADOW_REG(0x00)  /* gpio  15-0  */
+#define MSM7X00_GPIO_OUT_1     MSM_GPIO2_SHADOW_REG(0x00)  /* gpio  42-16 */
+#define MSM7X00_GPIO_OUT_2     MSM_GPIO1_SHADOW_REG(0x04)  /* gpio  67-43 */
+#define MSM7X00_GPIO_OUT_3     MSM_GPIO1_SHADOW_REG(0x08)  /* gpio  94-68 */
+#define MSM7X00_GPIO_OUT_4     MSM_GPIO1_SHADOW_REG(0x0C)  /* gpio 106-95 */
+#define MSM7X00_GPIO_OUT_5     MSM_GPIO1_SHADOW_REG(0x50)  /* gpio 107-121 */
+
+/* same pin map as above, output enable */
+#define MSM7X00_GPIO_OE_0      MSM_GPIO1_SHADOW_REG(0x10)
+#define MSM7X00_GPIO_OE_1      MSM_GPIO2_SHADOW_REG(0x08)
+#define MSM7X00_GPIO_OE_2      MSM_GPIO1_SHADOW_REG(0x14)
+#define MSM7X00_GPIO_OE_3      MSM_GPIO1_SHADOW_REG(0x18)
+#define MSM7X00_GPIO_OE_4      MSM_GPIO1_SHADOW_REG(0x1C)
+#define MSM7X00_GPIO_OE_5      MSM_GPIO1_SHADOW_REG(0x54)
+
+/* same pin map as above, input read */
+#define MSM7X00_GPIO_IN_0      MSM_GPIO1_SHADOW_REG(0x34)
+#define MSM7X00_GPIO_IN_1      MSM_GPIO2_SHADOW_REG(0x20)
+#define MSM7X00_GPIO_IN_2      MSM_GPIO1_SHADOW_REG(0x38)
+#define MSM7X00_GPIO_IN_3      MSM_GPIO1_SHADOW_REG(0x3C)
+#define MSM7X00_GPIO_IN_4      MSM_GPIO1_SHADOW_REG(0x40)
+#define MSM7X00_GPIO_IN_5      MSM_GPIO1_SHADOW_REG(0x44)
+
+/* same pin map as above, 1=edge 0=level interrup */
+#define MSM7X00_GPIO_INT_EDGE_0        MSM_GPIO1_SHADOW_REG(0x60)
+#define MSM7X00_GPIO_INT_EDGE_1        MSM_GPIO2_SHADOW_REG(0x50)
+#define MSM7X00_GPIO_INT_EDGE_2        MSM_GPIO1_SHADOW_REG(0x64)
+#define MSM7X00_GPIO_INT_EDGE_3        MSM_GPIO1_SHADOW_REG(0x68)
+#define MSM7X00_GPIO_INT_EDGE_4        MSM_GPIO1_SHADOW_REG(0x6C)
+#define MSM7X00_GPIO_INT_EDGE_5        MSM_GPIO1_SHADOW_REG(0xC0)
+
+/* same pin map as above, 1=positive 0=negative */
+#define MSM7X00_GPIO_INT_POS_0 MSM_GPIO1_SHADOW_REG(0x70)
+#define MSM7X00_GPIO_INT_POS_1 MSM_GPIO2_SHADOW_REG(0x58)
+#define MSM7X00_GPIO_INT_POS_2 MSM_GPIO1_SHADOW_REG(0x74)
+#define MSM7X00_GPIO_INT_POS_3 MSM_GPIO1_SHADOW_REG(0x78)
+#define MSM7X00_GPIO_INT_POS_4 MSM_GPIO1_SHADOW_REG(0x7C)
+#define MSM7X00_GPIO_INT_POS_5 MSM_GPIO1_SHADOW_REG(0xBC)
+
+/* same pin map as above, interrupt enable */
+#define MSM7X00_GPIO_INT_EN_0  MSM_GPIO1_SHADOW_REG(0x80)
+#define MSM7X00_GPIO_INT_EN_1  MSM_GPIO2_SHADOW_REG(0x60)
+#define MSM7X00_GPIO_INT_EN_2  MSM_GPIO1_SHADOW_REG(0x84)
+#define MSM7X00_GPIO_INT_EN_3  MSM_GPIO1_SHADOW_REG(0x88)
+#define MSM7X00_GPIO_INT_EN_4  MSM_GPIO1_SHADOW_REG(0x8C)
+#define MSM7X00_GPIO_INT_EN_5  MSM_GPIO1_SHADOW_REG(0xB8)
+
+/* same pin map as above, write 1 to clear interrupt */
+#define MSM7X00_GPIO_INT_CLEAR_0       MSM_GPIO1_SHADOW_REG(0x90)
+#define MSM7X00_GPIO_INT_CLEAR_1       MSM_GPIO2_SHADOW_REG(0x68)
+#define MSM7X00_GPIO_INT_CLEAR_2       MSM_GPIO1_SHADOW_REG(0x94)
+#define MSM7X00_GPIO_INT_CLEAR_3       MSM_GPIO1_SHADOW_REG(0x98)
+#define MSM7X00_GPIO_INT_CLEAR_4       MSM_GPIO1_SHADOW_REG(0x9C)
+#define MSM7X00_GPIO_INT_CLEAR_5       MSM_GPIO1_SHADOW_REG(0xB4)
+
+/* same pin map as above, 1=interrupt pending */
+#define MSM7X00_GPIO_INT_STATUS_0      MSM_GPIO1_SHADOW_REG(0xA0)
+#define MSM7X00_GPIO_INT_STATUS_1      MSM_GPIO2_SHADOW_REG(0x70)
+#define MSM7X00_GPIO_INT_STATUS_2      MSM_GPIO1_SHADOW_REG(0xA4)
+#define MSM7X00_GPIO_INT_STATUS_3      MSM_GPIO1_SHADOW_REG(0xA8)
+#define MSM7X00_GPIO_INT_STATUS_4      MSM_GPIO1_SHADOW_REG(0xAC)
+#define MSM7X00_GPIO_INT_STATUS_5      MSM_GPIO1_SHADOW_REG(0xB0)
+
+/*
+ * QSD8X50 registers
+ */
+/* output value */
+#define QSD8X50_GPIO_OUT_0     MSM_GPIO1_SHADOW_REG(0x00)  /* gpio  15-0   */
+#define QSD8X50_GPIO_OUT_1     MSM_GPIO2_SHADOW_REG(0x00)  /* gpio  42-16  */
+#define QSD8X50_GPIO_OUT_2     MSM_GPIO1_SHADOW_REG(0x04)  /* gpio  67-43  */
+#define QSD8X50_GPIO_OUT_3     MSM_GPIO1_SHADOW_REG(0x08)  /* gpio  94-68  */
+#define QSD8X50_GPIO_OUT_4     MSM_GPIO1_SHADOW_REG(0x0C)  /* gpio 103-95  */
+#define QSD8X50_GPIO_OUT_5     MSM_GPIO1_SHADOW_REG(0x10)  /* gpio 121-104 */
+#define QSD8X50_GPIO_OUT_6     MSM_GPIO1_SHADOW_REG(0x14)  /* gpio 152-122 */
+#define QSD8X50_GPIO_OUT_7     MSM_GPIO1_SHADOW_REG(0x18)  /* gpio 164-153 */
+
+/* same pin map as above, output enable */
+#define QSD8X50_GPIO_OE_0      MSM_GPIO1_SHADOW_REG(0x20)
+#define QSD8X50_GPIO_OE_1      MSM_GPIO2_SHADOW_REG(0x08)
+#define QSD8X50_GPIO_OE_2      MSM_GPIO1_SHADOW_REG(0x24)
+#define QSD8X50_GPIO_OE_3      MSM_GPIO1_SHADOW_REG(0x28)
+#define QSD8X50_GPIO_OE_4      MSM_GPIO1_SHADOW_REG(0x2C)
+#define QSD8X50_GPIO_OE_5      MSM_GPIO1_SHADOW_REG(0x30)
+#define QSD8X50_GPIO_OE_6      MSM_GPIO1_SHADOW_REG(0x34)
+#define QSD8X50_GPIO_OE_7      MSM_GPIO1_SHADOW_REG(0x38)
+
+/* same pin map as above, input read */
+#define QSD8X50_GPIO_IN_0      MSM_GPIO1_SHADOW_REG(0x50)
+#define QSD8X50_GPIO_IN_1      MSM_GPIO2_SHADOW_REG(0x20)
+#define QSD8X50_GPIO_IN_2      MSM_GPIO1_SHADOW_REG(0x54)
+#define QSD8X50_GPIO_IN_3      MSM_GPIO1_SHADOW_REG(0x58)
+#define QSD8X50_GPIO_IN_4      MSM_GPIO1_SHADOW_REG(0x5C)
+#define QSD8X50_GPIO_IN_5      MSM_GPIO1_SHADOW_REG(0x60)
+#define QSD8X50_GPIO_IN_6      MSM_GPIO1_SHADOW_REG(0x64)
+#define QSD8X50_GPIO_IN_7      MSM_GPIO1_SHADOW_REG(0x68)
+
+/* same pin map as above, 1=edge 0=level interrup */
+#define QSD8X50_GPIO_INT_EDGE_0        MSM_GPIO1_SHADOW_REG(0x70)
+#define QSD8X50_GPIO_INT_EDGE_1        MSM_GPIO2_SHADOW_REG(0x50)
+#define QSD8X50_GPIO_INT_EDGE_2        MSM_GPIO1_SHADOW_REG(0x74)
+#define QSD8X50_GPIO_INT_EDGE_3        MSM_GPIO1_SHADOW_REG(0x78)
+#define QSD8X50_GPIO_INT_EDGE_4        MSM_GPIO1_SHADOW_REG(0x7C)
+#define QSD8X50_GPIO_INT_EDGE_5        MSM_GPIO1_SHADOW_REG(0x80)
+#define QSD8X50_GPIO_INT_EDGE_6        MSM_GPIO1_SHADOW_REG(0x84)
+#define QSD8X50_GPIO_INT_EDGE_7        MSM_GPIO1_SHADOW_REG(0x88)
+
+/* same pin map as above, 1=positive 0=negative */
+#define QSD8X50_GPIO_INT_POS_0 MSM_GPIO1_SHADOW_REG(0x90)
+#define QSD8X50_GPIO_INT_POS_1 MSM_GPIO2_SHADOW_REG(0x58)
+#define QSD8X50_GPIO_INT_POS_2 MSM_GPIO1_SHADOW_REG(0x94)
+#define QSD8X50_GPIO_INT_POS_3 MSM_GPIO1_SHADOW_REG(0x98)
+#define QSD8X50_GPIO_INT_POS_4 MSM_GPIO1_SHADOW_REG(0x9C)
+#define QSD8X50_GPIO_INT_POS_5 MSM_GPIO1_SHADOW_REG(0xA0)
+#define QSD8X50_GPIO_INT_POS_6 MSM_GPIO1_SHADOW_REG(0xA4)
+#define QSD8X50_GPIO_INT_POS_7 MSM_GPIO1_SHADOW_REG(0xA8)
+
+/* same pin map as above, interrupt enable */
+#define QSD8X50_GPIO_INT_EN_0  MSM_GPIO1_SHADOW_REG(0xB0)
+#define QSD8X50_GPIO_INT_EN_1  MSM_GPIO2_SHADOW_REG(0x60)
+#define QSD8X50_GPIO_INT_EN_2  MSM_GPIO1_SHADOW_REG(0xB4)
+#define QSD8X50_GPIO_INT_EN_3  MSM_GPIO1_SHADOW_REG(0xB8)
+#define QSD8X50_GPIO_INT_EN_4  MSM_GPIO1_SHADOW_REG(0xBC)
+#define QSD8X50_GPIO_INT_EN_5  MSM_GPIO1_SHADOW_REG(0xC0)
+#define QSD8X50_GPIO_INT_EN_6  MSM_GPIO1_SHADOW_REG(0xC4)
+#define QSD8X50_GPIO_INT_EN_7  MSM_GPIO1_SHADOW_REG(0xC8)
+
+/* same pin map as above, write 1 to clear interrupt */
+#define QSD8X50_GPIO_INT_CLEAR_0       MSM_GPIO1_SHADOW_REG(0xD0)
+#define QSD8X50_GPIO_INT_CLEAR_1       MSM_GPIO2_SHADOW_REG(0x68)
+#define QSD8X50_GPIO_INT_CLEAR_2       MSM_GPIO1_SHADOW_REG(0xD4)
+#define QSD8X50_GPIO_INT_CLEAR_3       MSM_GPIO1_SHADOW_REG(0xD8)
+#define QSD8X50_GPIO_INT_CLEAR_4       MSM_GPIO1_SHADOW_REG(0xDC)
+#define QSD8X50_GPIO_INT_CLEAR_5       MSM_GPIO1_SHADOW_REG(0xE0)
+#define QSD8X50_GPIO_INT_CLEAR_6       MSM_GPIO1_SHADOW_REG(0xE4)
+#define QSD8X50_GPIO_INT_CLEAR_7       MSM_GPIO1_SHADOW_REG(0xE8)
+
+/* same pin map as above, 1=interrupt pending */
+#define QSD8X50_GPIO_INT_STATUS_0      MSM_GPIO1_SHADOW_REG(0xF0)
+#define QSD8X50_GPIO_INT_STATUS_1      MSM_GPIO2_SHADOW_REG(0x70)
+#define QSD8X50_GPIO_INT_STATUS_2      MSM_GPIO1_SHADOW_REG(0xF4)
+#define QSD8X50_GPIO_INT_STATUS_3      MSM_GPIO1_SHADOW_REG(0xF8)
+#define QSD8X50_GPIO_INT_STATUS_4      MSM_GPIO1_SHADOW_REG(0xFC)
+#define QSD8X50_GPIO_INT_STATUS_5      MSM_GPIO1_SHADOW_REG(0x100)
+#define QSD8X50_GPIO_INT_STATUS_6      MSM_GPIO1_SHADOW_REG(0x104)
+#define QSD8X50_GPIO_INT_STATUS_7      MSM_GPIO1_SHADOW_REG(0x108)
+
+/*
+ * MSM7X30 registers
+ */
+/* output value */
+#define MSM7X30_GPIO_OUT_0     MSM_GPIO1_REG(0x00)   /* gpio  15-0   */
+#define MSM7X30_GPIO_OUT_1     MSM_GPIO2_REG(0x00)   /* gpio  43-16  */
+#define MSM7X30_GPIO_OUT_2     MSM_GPIO1_REG(0x04)   /* gpio  67-44  */
+#define MSM7X30_GPIO_OUT_3     MSM_GPIO1_REG(0x08)   /* gpio  94-68  */
+#define MSM7X30_GPIO_OUT_4     MSM_GPIO1_REG(0x0C)   /* gpio 106-95  */
+#define MSM7X30_GPIO_OUT_5     MSM_GPIO1_REG(0x50)   /* gpio 133-107 */
+#define MSM7X30_GPIO_OUT_6     MSM_GPIO1_REG(0xC4)   /* gpio 150-134 */
+#define MSM7X30_GPIO_OUT_7     MSM_GPIO1_REG(0x214)  /* gpio 181-151 */
+
+/* same pin map as above, output enable */
+#define MSM7X30_GPIO_OE_0      MSM_GPIO1_REG(0x10)
+#define MSM7X30_GPIO_OE_1      MSM_GPIO2_REG(0x08)
+#define MSM7X30_GPIO_OE_2      MSM_GPIO1_REG(0x14)
+#define MSM7X30_GPIO_OE_3      MSM_GPIO1_REG(0x18)
+#define MSM7X30_GPIO_OE_4      MSM_GPIO1_REG(0x1C)
+#define MSM7X30_GPIO_OE_5      MSM_GPIO1_REG(0x54)
+#define MSM7X30_GPIO_OE_6      MSM_GPIO1_REG(0xC8)
+#define MSM7X30_GPIO_OE_7      MSM_GPIO1_REG(0x218)
+
+/* same pin map as above, input read */
+#define MSM7X30_GPIO_IN_0      MSM_GPIO1_REG(0x34)
+#define MSM7X30_GPIO_IN_1      MSM_GPIO2_REG(0x20)
+#define MSM7X30_GPIO_IN_2      MSM_GPIO1_REG(0x38)
+#define MSM7X30_GPIO_IN_3      MSM_GPIO1_REG(0x3C)
+#define MSM7X30_GPIO_IN_4      MSM_GPIO1_REG(0x40)
+#define MSM7X30_GPIO_IN_5      MSM_GPIO1_REG(0x44)
+#define MSM7X30_GPIO_IN_6      MSM_GPIO1_REG(0xCC)
+#define MSM7X30_GPIO_IN_7      MSM_GPIO1_REG(0x21C)
+
+/* same pin map as above, 1=edge 0=level interrup */
+#define MSM7X30_GPIO_INT_EDGE_0        MSM_GPIO1_REG(0x60)
+#define MSM7X30_GPIO_INT_EDGE_1        MSM_GPIO2_REG(0x50)
+#define MSM7X30_GPIO_INT_EDGE_2        MSM_GPIO1_REG(0x64)
+#define MSM7X30_GPIO_INT_EDGE_3        MSM_GPIO1_REG(0x68)
+#define MSM7X30_GPIO_INT_EDGE_4        MSM_GPIO1_REG(0x6C)
+#define MSM7X30_GPIO_INT_EDGE_5        MSM_GPIO1_REG(0xC0)
+#define MSM7X30_GPIO_INT_EDGE_6        MSM_GPIO1_REG(0xD0)
+#define MSM7X30_GPIO_INT_EDGE_7        MSM_GPIO1_REG(0x240)
+
+/* same pin map as above, 1=positive 0=negative */
+#define MSM7X30_GPIO_INT_POS_0 MSM_GPIO1_REG(0x70)
+#define MSM7X30_GPIO_INT_POS_1 MSM_GPIO2_REG(0x58)
+#define MSM7X30_GPIO_INT_POS_2 MSM_GPIO1_REG(0x74)
+#define MSM7X30_GPIO_INT_POS_3 MSM_GPIO1_REG(0x78)
+#define MSM7X30_GPIO_INT_POS_4 MSM_GPIO1_REG(0x7C)
+#define MSM7X30_GPIO_INT_POS_5 MSM_GPIO1_REG(0xBC)
+#define MSM7X30_GPIO_INT_POS_6 MSM_GPIO1_REG(0xD4)
+#define MSM7X30_GPIO_INT_POS_7 MSM_GPIO1_REG(0x228)
+
+/* same pin map as above, interrupt enable */
+#define MSM7X30_GPIO_INT_EN_0  MSM_GPIO1_REG(0x80)
+#define MSM7X30_GPIO_INT_EN_1  MSM_GPIO2_REG(0x60)
+#define MSM7X30_GPIO_INT_EN_2  MSM_GPIO1_REG(0x84)
+#define MSM7X30_GPIO_INT_EN_3  MSM_GPIO1_REG(0x88)
+#define MSM7X30_GPIO_INT_EN_4  MSM_GPIO1_REG(0x8C)
+#define MSM7X30_GPIO_INT_EN_5  MSM_GPIO1_REG(0xB8)
+#define MSM7X30_GPIO_INT_EN_6  MSM_GPIO1_REG(0xD8)
+#define MSM7X30_GPIO_INT_EN_7  MSM_GPIO1_REG(0x22C)
+
+/* same pin map as above, write 1 to clear interrupt */
+#define MSM7X30_GPIO_INT_CLEAR_0       MSM_GPIO1_REG(0x90)
+#define MSM7X30_GPIO_INT_CLEAR_1       MSM_GPIO2_REG(0x68)
+#define MSM7X30_GPIO_INT_CLEAR_2       MSM_GPIO1_REG(0x94)
+#define MSM7X30_GPIO_INT_CLEAR_3       MSM_GPIO1_REG(0x98)
+#define MSM7X30_GPIO_INT_CLEAR_4       MSM_GPIO1_REG(0x9C)
+#define MSM7X30_GPIO_INT_CLEAR_5       MSM_GPIO1_REG(0xB4)
+#define MSM7X30_GPIO_INT_CLEAR_6       MSM_GPIO1_REG(0xDC)
+#define MSM7X30_GPIO_INT_CLEAR_7       MSM_GPIO1_REG(0x230)
+
+/* same pin map as above, 1=interrupt pending */
+#define MSM7X30_GPIO_INT_STATUS_0      MSM_GPIO1_REG(0xA0)
+#define MSM7X30_GPIO_INT_STATUS_1      MSM_GPIO2_REG(0x70)
+#define MSM7X30_GPIO_INT_STATUS_2      MSM_GPIO1_REG(0xA4)
+#define MSM7X30_GPIO_INT_STATUS_3      MSM_GPIO1_REG(0xA8)
+#define MSM7X30_GPIO_INT_STATUS_4      MSM_GPIO1_REG(0xAC)
+#define MSM7X30_GPIO_INT_STATUS_5      MSM_GPIO1_REG(0xB0)
+#define MSM7X30_GPIO_INT_STATUS_6      MSM_GPIO1_REG(0xE0)
+#define MSM7X30_GPIO_INT_STATUS_7      MSM_GPIO1_REG(0x234)
+
+#define FIRST_GPIO_IRQ MSM_GPIO_TO_INT(0)
+
+#define MSM_GPIO_BANK(soc, bank, first, last)                          \
+       {                                                               \
+               .regs = {                                               \
+                       .out =         soc##_GPIO_OUT_##bank,           \
+                       .in =          soc##_GPIO_IN_##bank,            \
+                       .int_status =  soc##_GPIO_INT_STATUS_##bank,    \
+                       .int_clear =   soc##_GPIO_INT_CLEAR_##bank,     \
+                       .int_en =      soc##_GPIO_INT_EN_##bank,        \
+                       .int_edge =    soc##_GPIO_INT_EDGE_##bank,      \
+                       .int_pos =     soc##_GPIO_INT_POS_##bank,       \
+                       .oe =          soc##_GPIO_OE_##bank,            \
+               },                                                      \
+               .chip = {                                               \
+                       .base = (first),                                \
+                       .ngpio = (last) - (first) + 1,                  \
+                       .get = msm_gpio_get,                            \
+                       .set = msm_gpio_set,                            \
+                       .direction_input = msm_gpio_direction_input,    \
+                       .direction_output = msm_gpio_direction_output,  \
+                       .to_irq = msm_gpio_to_irq,                      \
+                       .request = msm_gpio_request,                    \
+                       .free = msm_gpio_free,                          \
+               }                                                       \
+       }
+
+#define MSM_GPIO_BROKEN_INT_CLEAR 1
+
+struct msm_gpio_regs {
+       void __iomem *out;
+       void __iomem *in;
+       void __iomem *int_status;
+       void __iomem *int_clear;
+       void __iomem *int_en;
+       void __iomem *int_edge;
+       void __iomem *int_pos;
+       void __iomem *oe;
+};
+
+struct msm_gpio_chip {
+       spinlock_t              lock;
+       struct gpio_chip        chip;
+       struct msm_gpio_regs    regs;
+#if MSM_GPIO_BROKEN_INT_CLEAR
+       unsigned                int_status_copy;
+#endif
+       unsigned int            both_edge_detect;
+       unsigned int            int_enable[2]; /* 0: awake, 1: sleep */
+};
+
+static int msm_gpio_write(struct msm_gpio_chip *msm_chip,
+                         unsigned offset, unsigned on)
+{
+       unsigned mask = BIT(offset);
+       unsigned val;
+
+       val = readl(msm_chip->regs.out);
+       if (on)
+               writel(val | mask, msm_chip->regs.out);
+       else
+               writel(val & ~mask, msm_chip->regs.out);
+       return 0;
+}
+
+static void msm_gpio_update_both_edge_detect(struct msm_gpio_chip *msm_chip)
+{
+       int loop_limit = 100;
+       unsigned pol, val, val2, intstat;
+       do {
+               val = readl(msm_chip->regs.in);
+               pol = readl(msm_chip->regs.int_pos);
+               pol = (pol & ~msm_chip->both_edge_detect) |
+                     (~val & msm_chip->both_edge_detect);
+               writel(pol, msm_chip->regs.int_pos);
+               intstat = readl(msm_chip->regs.int_status);
+               val2 = readl(msm_chip->regs.in);
+               if (((val ^ val2) & msm_chip->both_edge_detect & ~intstat) == 0)
+                       return;
+       } while (loop_limit-- > 0);
+       printk(KERN_ERR "msm_gpio_update_both_edge_detect, "
+              "failed to reach stable state %x != %x\n", val, val2);
+}
+
+static int msm_gpio_clear_detect_status(struct msm_gpio_chip *msm_chip,
+                                       unsigned offset)
+{
+       unsigned bit = BIT(offset);
+
+#if MSM_GPIO_BROKEN_INT_CLEAR
+       /* Save interrupts that already triggered before we loose them. */
+       /* Any interrupt that triggers between the read of int_status */
+       /* and the write to int_clear will still be lost though. */
+       msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
+       msm_chip->int_status_copy &= ~bit;
+#endif
+       writel(bit, msm_chip->regs.int_clear);
+       msm_gpio_update_both_edge_detect(msm_chip);
+       return 0;
+}
+
+static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+       struct msm_gpio_chip *msm_chip;
+       unsigned long irq_flags;
+
+       msm_chip = container_of(chip, struct msm_gpio_chip, chip);
+       spin_lock_irqsave(&msm_chip->lock, irq_flags);
+       writel(readl(msm_chip->regs.oe) & ~BIT(offset), msm_chip->regs.oe);
+       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+       return 0;
+}
+
+static int
+msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct msm_gpio_chip *msm_chip;
+       unsigned long irq_flags;
+
+       msm_chip = container_of(chip, struct msm_gpio_chip, chip);
+       spin_lock_irqsave(&msm_chip->lock, irq_flags);
+       msm_gpio_write(msm_chip, offset, value);
+       writel(readl(msm_chip->regs.oe) | BIT(offset), msm_chip->regs.oe);
+       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+       return 0;
+}
+
+static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       struct msm_gpio_chip *msm_chip;
+
+       msm_chip = container_of(chip, struct msm_gpio_chip, chip);
+       return (readl(msm_chip->regs.in) & (1U << offset)) ? 1 : 0;
+}
+
+static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct msm_gpio_chip *msm_chip;
+       unsigned long irq_flags;
+
+       msm_chip = container_of(chip, struct msm_gpio_chip, chip);
+       spin_lock_irqsave(&msm_chip->lock, irq_flags);
+       msm_gpio_write(msm_chip, offset, value);
+       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+}
+
+static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+       return MSM_GPIO_TO_INT(chip->base + offset);
+}
+
+#ifdef CONFIG_MSM_GPIOMUX
+static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+       return msm_gpiomux_get(chip->base + offset);
+}
+
+static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+       msm_gpiomux_put(chip->base + offset);
+}
+#else
+#define msm_gpio_request NULL
+#define msm_gpio_free NULL
+#endif
+
+static struct msm_gpio_chip *msm_gpio_chips;
+static int msm_gpio_count;
+
+static struct msm_gpio_chip msm_gpio_chips_msm7x01[] = {
+       MSM_GPIO_BANK(MSM7X00, 0,   0,  15),
+       MSM_GPIO_BANK(MSM7X00, 1,  16,  42),
+       MSM_GPIO_BANK(MSM7X00, 2,  43,  67),
+       MSM_GPIO_BANK(MSM7X00, 3,  68,  94),
+       MSM_GPIO_BANK(MSM7X00, 4,  95, 106),
+       MSM_GPIO_BANK(MSM7X00, 5, 107, 121),
+};
+
+static struct msm_gpio_chip msm_gpio_chips_msm7x30[] = {
+       MSM_GPIO_BANK(MSM7X30, 0,   0,  15),
+       MSM_GPIO_BANK(MSM7X30, 1,  16,  43),
+       MSM_GPIO_BANK(MSM7X30, 2,  44,  67),
+       MSM_GPIO_BANK(MSM7X30, 3,  68,  94),
+       MSM_GPIO_BANK(MSM7X30, 4,  95, 106),
+       MSM_GPIO_BANK(MSM7X30, 5, 107, 133),
+       MSM_GPIO_BANK(MSM7X30, 6, 134, 150),
+       MSM_GPIO_BANK(MSM7X30, 7, 151, 181),
+};
+
+static struct msm_gpio_chip msm_gpio_chips_qsd8x50[] = {
+       MSM_GPIO_BANK(QSD8X50, 0,   0,  15),
+       MSM_GPIO_BANK(QSD8X50, 1,  16,  42),
+       MSM_GPIO_BANK(QSD8X50, 2,  43,  67),
+       MSM_GPIO_BANK(QSD8X50, 3,  68,  94),
+       MSM_GPIO_BANK(QSD8X50, 4,  95, 103),
+       MSM_GPIO_BANK(QSD8X50, 5, 104, 121),
+       MSM_GPIO_BANK(QSD8X50, 6, 122, 152),
+       MSM_GPIO_BANK(QSD8X50, 7, 153, 164),
+};
+
+static void msm_gpio_irq_ack(struct irq_data *d)
+{
+       unsigned long irq_flags;
+       struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
+       spin_lock_irqsave(&msm_chip->lock, irq_flags);
+       msm_gpio_clear_detect_status(msm_chip,
+                                    d->irq - gpio_to_irq(msm_chip->chip.base));
+       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+}
+
+static void msm_gpio_irq_mask(struct irq_data *d)
+{
+       unsigned long irq_flags;
+       struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
+       unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
+
+       spin_lock_irqsave(&msm_chip->lock, irq_flags);
+       /* level triggered interrupts are also latched */
+       if (!(readl(msm_chip->regs.int_edge) & BIT(offset)))
+               msm_gpio_clear_detect_status(msm_chip, offset);
+       msm_chip->int_enable[0] &= ~BIT(offset);
+       writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
+       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+}
+
+static void msm_gpio_irq_unmask(struct irq_data *d)
+{
+       unsigned long irq_flags;
+       struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
+       unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
+
+       spin_lock_irqsave(&msm_chip->lock, irq_flags);
+       /* level triggered interrupts are also latched */
+       if (!(readl(msm_chip->regs.int_edge) & BIT(offset)))
+               msm_gpio_clear_detect_status(msm_chip, offset);
+       msm_chip->int_enable[0] |= BIT(offset);
+       writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
+       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+}
+
+static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+       unsigned long irq_flags;
+       struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
+       unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
+
+       spin_lock_irqsave(&msm_chip->lock, irq_flags);
+
+       if (on)
+               msm_chip->int_enable[1] |= BIT(offset);
+       else
+               msm_chip->int_enable[1] &= ~BIT(offset);
+
+       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+       return 0;
+}
+
+static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
+{
+       unsigned long irq_flags;
+       struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
+       unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
+       unsigned val, mask = BIT(offset);
+
+       spin_lock_irqsave(&msm_chip->lock, irq_flags);
+       val = readl(msm_chip->regs.int_edge);
+       if (flow_type & IRQ_TYPE_EDGE_BOTH) {
+               writel(val | mask, msm_chip->regs.int_edge);
+               __irq_set_handler_locked(d->irq, handle_edge_irq);
+       } else {
+               writel(val & ~mask, msm_chip->regs.int_edge);
+               __irq_set_handler_locked(d->irq, handle_level_irq);
+       }
+       if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
+               msm_chip->both_edge_detect |= mask;
+               msm_gpio_update_both_edge_detect(msm_chip);
+       } else {
+               msm_chip->both_edge_detect &= ~mask;
+               val = readl(msm_chip->regs.int_pos);
+               if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH))
+                       writel(val | mask, msm_chip->regs.int_pos);
+               else
+                       writel(val & ~mask, msm_chip->regs.int_pos);
+       }
+       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+       return 0;
+}
+
+static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+       int i, j, mask;
+       unsigned val;
+
+       for (i = 0; i < msm_gpio_count; i++) {
+               struct msm_gpio_chip *msm_chip = &msm_gpio_chips[i];
+               val = readl(msm_chip->regs.int_status);
+               val &= msm_chip->int_enable[0];
+               while (val) {
+                       mask = val & -val;
+                       j = fls(mask) - 1;
+                       /* printk("%s %08x %08x bit %d gpio %d irq %d\n",
+                               __func__, v, m, j, msm_chip->chip.start + j,
+                               FIRST_GPIO_IRQ + msm_chip->chip.start + j); */
+                       val &= ~mask;
+                       generic_handle_irq(FIRST_GPIO_IRQ +
+                                          msm_chip->chip.base + j);
+               }
+       }
+       desc->irq_data.chip->irq_ack(&desc->irq_data);
+}
+
+static struct irq_chip msm_gpio_irq_chip = {
+       .name          = "msmgpio",
+       .irq_ack       = msm_gpio_irq_ack,
+       .irq_mask      = msm_gpio_irq_mask,
+       .irq_unmask    = msm_gpio_irq_unmask,
+       .irq_set_wake  = msm_gpio_irq_set_wake,
+       .irq_set_type  = msm_gpio_irq_set_type,
+};
+
+static int __init msm_init_gpio(void)
+{
+       int i, j = 0;
+
+       if (cpu_is_msm7x01()) {
+               msm_gpio_chips = msm_gpio_chips_msm7x01;
+               msm_gpio_count = ARRAY_SIZE(msm_gpio_chips_msm7x01);
+       } else if (cpu_is_msm7x30()) {
+               msm_gpio_chips = msm_gpio_chips_msm7x30;
+               msm_gpio_count = ARRAY_SIZE(msm_gpio_chips_msm7x30);
+       } else if (cpu_is_qsd8x50()) {
+               msm_gpio_chips = msm_gpio_chips_qsd8x50;
+               msm_gpio_count = ARRAY_SIZE(msm_gpio_chips_qsd8x50);
+       } else {
+               return 0;
+       }
+
+       for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) {
+               if (i - FIRST_GPIO_IRQ >=
+                       msm_gpio_chips[j].chip.base +
+                       msm_gpio_chips[j].chip.ngpio)
+                       j++;
+               irq_set_chip_data(i, &msm_gpio_chips[j]);
+               irq_set_chip_and_handler(i, &msm_gpio_irq_chip,
+                                        handle_edge_irq);
+               set_irq_flags(i, IRQF_VALID);
+       }
+
+       for (i = 0; i < msm_gpio_count; i++) {
+               spin_lock_init(&msm_gpio_chips[i].lock);
+               writel(0, msm_gpio_chips[i].regs.int_en);
+               gpiochip_add(&msm_gpio_chips[i].chip);
+       }
+
+       irq_set_chained_handler(INT_GPIO_GROUP1, msm_gpio_irq_handler);
+       irq_set_chained_handler(INT_GPIO_GROUP2, msm_gpio_irq_handler);
+       irq_set_irq_wake(INT_GPIO_GROUP1, 1);
+       irq_set_irq_wake(INT_GPIO_GROUP2, 2);
+       return 0;
+}
+
+postcore_initcall(msm_init_gpio);
similarity index 99%
rename from arch/arm/mach-msm/gpio-v2.c
rename to drivers/gpio/gpio-msm-v2.c
index cc9c4fd..5cb1227 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2011, Code Aurora Forum. 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 and
@@ -30,8 +30,8 @@
 
 #include <asm/mach/irq.h>
 
+#include <mach/msm_gpiomux.h>
 #include <mach/msm_iomap.h>
-#include "gpiomux.h"
 
 /* Bits of interest in the GPIO_IN_OUT register.
  */
diff --git a/drivers/gpio/gpio-tps65912.c b/drivers/gpio/gpio-tps65912.c
new file mode 100644 (file)
index 0000000..79e66c0
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2011 Texas Instruments Inc.
+ *
+ * Author: Margarita Olaya <magi@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.
+ *
+ * This driver is based on wm8350 implementation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/mfd/core.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/mfd/tps65912.h>
+
+struct tps65912_gpio_data {
+       struct tps65912 *tps65912;
+       struct gpio_chip gpio_chip;
+};
+
+static int tps65912_gpio_get(struct gpio_chip *gc, unsigned offset)
+{
+       struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio);
+       int val;
+
+       val = tps65912_reg_read(tps65912, TPS65912_GPIO1 + offset);
+
+       if (val & GPIO_STS_MASK)
+               return 1;
+
+       return 0;
+}
+
+static void tps65912_gpio_set(struct gpio_chip *gc, unsigned offset,
+                             int value)
+{
+       struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio);
+
+       if (value)
+               tps65912_set_bits(tps65912, TPS65912_GPIO1 + offset,
+                                                       GPIO_SET_MASK);
+       else
+               tps65912_clear_bits(tps65912, TPS65912_GPIO1 + offset,
+                                                               GPIO_SET_MASK);
+}
+
+static int tps65912_gpio_output(struct gpio_chip *gc, unsigned offset,
+                               int value)
+{
+       struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio);
+
+       /* Set the initial value */
+       tps65912_gpio_set(gc, offset, value);
+
+       return tps65912_set_bits(tps65912, TPS65912_GPIO1 + offset,
+                                                               GPIO_CFG_MASK);
+}
+
+static int tps65912_gpio_input(struct gpio_chip *gc, unsigned offset)
+{
+       struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio);
+
+       return tps65912_clear_bits(tps65912, TPS65912_GPIO1 + offset,
+                                                               GPIO_CFG_MASK);
+
+}
+
+static struct gpio_chip template_chip = {
+       .label                  = "tps65912",
+       .owner                  = THIS_MODULE,
+       .direction_input        = tps65912_gpio_input,
+       .direction_output       = tps65912_gpio_output,
+       .get                    = tps65912_gpio_get,
+       .set                    = tps65912_gpio_set,
+       .can_sleep              = 1,
+       .ngpio                  = 5,
+       .base                   = -1,
+};
+
+static int __devinit tps65912_gpio_probe(struct platform_device *pdev)
+{
+       struct tps65912 *tps65912 = dev_get_drvdata(pdev->dev.parent);
+       struct tps65912_board *pdata = tps65912->dev->platform_data;
+       struct tps65912_gpio_data *tps65912_gpio;
+       int ret;
+
+       tps65912_gpio = kzalloc(sizeof(*tps65912_gpio), GFP_KERNEL);
+       if (tps65912_gpio == NULL)
+               return -ENOMEM;
+
+       tps65912_gpio->tps65912 = tps65912;
+       tps65912_gpio->gpio_chip = template_chip;
+       tps65912_gpio->gpio_chip.dev = &pdev->dev;
+       if (pdata && pdata->gpio_base)
+               tps65912_gpio->gpio_chip.base = pdata->gpio_base;
+
+       ret = gpiochip_add(&tps65912_gpio->gpio_chip);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to register gpiochip, %d\n", ret);
+               goto err;
+       }
+
+       platform_set_drvdata(pdev, tps65912_gpio);
+
+       return ret;
+
+err:
+       kfree(tps65912_gpio);
+       return ret;
+}
+
+static int __devexit tps65912_gpio_remove(struct platform_device *pdev)
+{
+       struct tps65912_gpio_data  *tps65912_gpio = platform_get_drvdata(pdev);
+       int ret;
+
+       ret = gpiochip_remove(&tps65912_gpio->gpio_chip);
+       if (ret == 0)
+               kfree(tps65912_gpio);
+
+       return ret;
+}
+
+static struct platform_driver tps65912_gpio_driver = {
+       .driver = {
+               .name = "tps65912-gpio",
+               .owner = THIS_MODULE,
+       },
+       .probe = tps65912_gpio_probe,
+       .remove = __devexit_p(tps65912_gpio_remove),
+};
+
+static int __init tps65912_gpio_init(void)
+{
+       return platform_driver_register(&tps65912_gpio_driver);
+}
+subsys_initcall(tps65912_gpio_init);
+
+static void __exit tps65912_gpio_exit(void)
+{
+       platform_driver_unregister(&tps65912_gpio_driver);
+}
+module_exit(tps65912_gpio_exit);
+
+MODULE_AUTHOR("Margarita Olaya Cabrera <magi@slimlogic.co.uk>");
+MODULE_DESCRIPTION("GPIO interface for TPS65912 PMICs");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:tps65912-gpio");
index 9d8c892..9d2668a 100644 (file)
@@ -90,7 +90,6 @@ int drm_debugfs_create_files(struct drm_info_list *files, int count,
        struct drm_device *dev = minor->dev;
        struct dentry *ent;
        struct drm_info_node *tmp;
-       char name[64];
        int i, ret;
 
        for (i = 0; i < count; i++) {
@@ -108,6 +107,9 @@ int drm_debugfs_create_files(struct drm_info_list *files, int count,
                ent = debugfs_create_file(files[i].name, S_IFREG | S_IRUGO,
                                          root, tmp, &drm_debugfs_fops);
                if (!ent) {
+                       char name[64];
+                       strncpy(name, root->d_name.name,
+                                               min(root->d_name.len, 64U));
                        DRM_ERROR("Cannot create /sys/kernel/debug/dri/%s/%s\n",
                                  name, files[i].name);
                        kfree(tmp);
index 756af4d..7425e5c 100644 (file)
@@ -127,6 +127,23 @@ static const u8 edid_header[] = {
        0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
 };
 
+ /*
+ * Sanity check the header of the base EDID block.  Return 8 if the header
+ * is perfect, down to 0 if it's totally wrong.
+ */
+int drm_edid_header_is_valid(const u8 *raw_edid)
+{
+       int i, score = 0;
+
+       for (i = 0; i < sizeof(edid_header); i++)
+               if (raw_edid[i] == edid_header[i])
+                       score++;
+
+       return score;
+}
+EXPORT_SYMBOL(drm_edid_header_is_valid);
+
+
 /*
  * Sanity check the EDID block (base or extension).  Return 0 if the block
  * doesn't check out, or 1 if it's valid.
@@ -139,12 +156,7 @@ drm_edid_block_valid(u8 *raw_edid)
        struct edid *edid = (struct edid *)raw_edid;
 
        if (raw_edid[0] == 0x00) {
-               int score = 0;
-
-               for (i = 0; i < sizeof(edid_header); i++)
-                       if (raw_edid[i] == edid_header[i])
-                               score++;
-
+               int score = drm_edid_header_is_valid(raw_edid);
                if (score == 8) ;
                else if (score >= 6) {
                        DRM_DEBUG("Fixing EDID header, your hardware may be failing\n");
@@ -1439,6 +1451,8 @@ EXPORT_SYMBOL(drm_detect_monitor_audio);
 static void drm_add_display_info(struct edid *edid,
                                 struct drm_display_info *info)
 {
+       u8 *edid_ext;
+
        info->width_mm = edid->width_cm * 10;
        info->height_mm = edid->height_cm * 10;
 
@@ -1483,6 +1497,13 @@ static void drm_add_display_info(struct edid *edid,
                info->color_formats = DRM_COLOR_FORMAT_YCRCB444;
        if (info->color_formats & DRM_EDID_FEATURE_RGB_YCRCB422)
                info->color_formats = DRM_COLOR_FORMAT_YCRCB422;
+
+       /* Get data from CEA blocks if present */
+       edid_ext = drm_find_cea_extension(edid);
+       if (!edid_ext)
+               return;
+
+       info->cea_rev = edid_ext[1];
 }
 
 /**
index 2022a5c..3830e9e 100644 (file)
@@ -291,11 +291,14 @@ static void drm_irq_vgaarb_nokms(void *cookie, bool state)
        if (!dev->irq_enabled)
                return;
 
-       if (state)
-               dev->driver->irq_uninstall(dev);
-       else {
-               dev->driver->irq_preinstall(dev);
-               dev->driver->irq_postinstall(dev);
+       if (state) {
+               if (dev->driver->irq_uninstall)
+                       dev->driver->irq_uninstall(dev);
+       } else {
+               if (dev->driver->irq_preinstall)
+                       dev->driver->irq_preinstall(dev);
+               if (dev->driver->irq_postinstall)
+                       dev->driver->irq_postinstall(dev);
        }
 }
 
@@ -338,7 +341,8 @@ int drm_irq_install(struct drm_device *dev)
        DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev));
 
        /* Before installing handler */
-       dev->driver->irq_preinstall(dev);
+       if (dev->driver->irq_preinstall)
+               dev->driver->irq_preinstall(dev);
 
        /* Install handler */
        if (drm_core_check_feature(dev, DRIVER_IRQ_SHARED))
@@ -363,11 +367,16 @@ int drm_irq_install(struct drm_device *dev)
                vga_client_register(dev->pdev, (void *)dev, drm_irq_vgaarb_nokms, NULL);
 
        /* After installing handler */
-       ret = dev->driver->irq_postinstall(dev);
+       if (dev->driver->irq_postinstall)
+               ret = dev->driver->irq_postinstall(dev);
+
        if (ret < 0) {
                mutex_lock(&dev->struct_mutex);
                dev->irq_enabled = 0;
                mutex_unlock(&dev->struct_mutex);
+               if (!drm_core_check_feature(dev, DRIVER_MODESET))
+                       vga_client_register(dev->pdev, NULL, NULL, NULL);
+               free_irq(drm_dev_to_irq(dev), dev);
        }
 
        return ret;
@@ -413,7 +422,8 @@ int drm_irq_uninstall(struct drm_device *dev)
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                vga_client_register(dev->pdev, NULL, NULL, NULL);
 
-       dev->driver->irq_uninstall(dev);
+       if (dev->driver->irq_uninstall)
+               dev->driver->irq_uninstall(dev);
 
        free_irq(drm_dev_to_irq(dev), dev);
 
index e266249..3c395a5 100644 (file)
@@ -499,7 +499,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
        seq_printf(m, "Interrupts received: %d\n",
                   atomic_read(&dev_priv->irq_received));
        for (i = 0; i < I915_NUM_RINGS; i++) {
-               if (IS_GEN6(dev)) {
+               if (IS_GEN6(dev) || IS_GEN7(dev)) {
                        seq_printf(m, "Graphics Interrupt mask (%s):    %08x\n",
                                   dev_priv->ring[i].name,
                                   I915_READ_IMR(&dev_priv->ring[i]));
@@ -1338,6 +1338,155 @@ static const struct file_operations i915_wedged_fops = {
        .llseek = default_llseek,
 };
 
+static int
+i915_max_freq_open(struct inode *inode,
+                  struct file *filp)
+{
+       filp->private_data = inode->i_private;
+       return 0;
+}
+
+static ssize_t
+i915_max_freq_read(struct file *filp,
+                  char __user *ubuf,
+                  size_t max,
+                  loff_t *ppos)
+{
+       struct drm_device *dev = filp->private_data;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       char buf[80];
+       int len;
+
+       len = snprintf(buf, sizeof (buf),
+                      "max freq: %d\n", dev_priv->max_delay * 50);
+
+       if (len > sizeof (buf))
+               len = sizeof (buf);
+
+       return simple_read_from_buffer(ubuf, max, ppos, buf, len);
+}
+
+static ssize_t
+i915_max_freq_write(struct file *filp,
+                 const char __user *ubuf,
+                 size_t cnt,
+                 loff_t *ppos)
+{
+       struct drm_device *dev = filp->private_data;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       char buf[20];
+       int val = 1;
+
+       if (cnt > 0) {
+               if (cnt > sizeof (buf) - 1)
+                       return -EINVAL;
+
+               if (copy_from_user(buf, ubuf, cnt))
+                       return -EFAULT;
+               buf[cnt] = 0;
+
+               val = simple_strtoul(buf, NULL, 0);
+       }
+
+       DRM_DEBUG_DRIVER("Manually setting max freq to %d\n", val);
+
+       /*
+        * Turbo will still be enabled, but won't go above the set value.
+        */
+       dev_priv->max_delay = val / 50;
+
+       gen6_set_rps(dev, val / 50);
+
+       return cnt;
+}
+
+static const struct file_operations i915_max_freq_fops = {
+       .owner = THIS_MODULE,
+       .open = i915_max_freq_open,
+       .read = i915_max_freq_read,
+       .write = i915_max_freq_write,
+       .llseek = default_llseek,
+};
+
+static int
+i915_cache_sharing_open(struct inode *inode,
+                  struct file *filp)
+{
+       filp->private_data = inode->i_private;
+       return 0;
+}
+
+static ssize_t
+i915_cache_sharing_read(struct file *filp,
+                  char __user *ubuf,
+                  size_t max,
+                  loff_t *ppos)
+{
+       struct drm_device *dev = filp->private_data;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       char buf[80];
+       u32 snpcr;
+       int len;
+
+       mutex_lock(&dev_priv->dev->struct_mutex);
+       snpcr = I915_READ(GEN6_MBCUNIT_SNPCR);
+       mutex_unlock(&dev_priv->dev->struct_mutex);
+
+       len = snprintf(buf, sizeof (buf),
+                      "%d\n", (snpcr & GEN6_MBC_SNPCR_MASK) >>
+                      GEN6_MBC_SNPCR_SHIFT);
+
+       if (len > sizeof (buf))
+               len = sizeof (buf);
+
+       return simple_read_from_buffer(ubuf, max, ppos, buf, len);
+}
+
+static ssize_t
+i915_cache_sharing_write(struct file *filp,
+                 const char __user *ubuf,
+                 size_t cnt,
+                 loff_t *ppos)
+{
+       struct drm_device *dev = filp->private_data;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       char buf[20];
+       u32 snpcr;
+       int val = 1;
+
+       if (cnt > 0) {
+               if (cnt > sizeof (buf) - 1)
+                       return -EINVAL;
+
+               if (copy_from_user(buf, ubuf, cnt))
+                       return -EFAULT;
+               buf[cnt] = 0;
+
+               val = simple_strtoul(buf, NULL, 0);
+       }
+
+       if (val < 0 || val > 3)
+               return -EINVAL;
+
+       DRM_DEBUG_DRIVER("Manually setting uncore sharing to %d\n", val);
+
+       /* Update the cache sharing policy here as well */
+       snpcr = I915_READ(GEN6_MBCUNIT_SNPCR);
+       snpcr &= ~GEN6_MBC_SNPCR_MASK;
+       snpcr |= (val << GEN6_MBC_SNPCR_SHIFT);
+       I915_WRITE(GEN6_MBCUNIT_SNPCR, snpcr);
+
+       return cnt;
+}
+
+static const struct file_operations i915_cache_sharing_fops = {
+       .owner = THIS_MODULE,
+       .open = i915_cache_sharing_open,
+       .read = i915_cache_sharing_read,
+       .write = i915_cache_sharing_write,
+       .llseek = default_llseek,
+};
+
 /* As the drm_debugfs_init() routines are called before dev->dev_private is
  * allocated we need to hook into the minor for release. */
 static int
@@ -1437,6 +1586,36 @@ static int i915_forcewake_create(struct dentry *root, struct drm_minor *minor)
        return drm_add_fake_info_node(minor, ent, &i915_forcewake_fops);
 }
 
+static int i915_max_freq_create(struct dentry *root, struct drm_minor *minor)
+{
+       struct drm_device *dev = minor->dev;
+       struct dentry *ent;
+
+       ent = debugfs_create_file("i915_max_freq",
+                                 S_IRUGO | S_IWUSR,
+                                 root, dev,
+                                 &i915_max_freq_fops);
+       if (IS_ERR(ent))
+               return PTR_ERR(ent);
+
+       return drm_add_fake_info_node(minor, ent, &i915_max_freq_fops);
+}
+
+static int i915_cache_sharing_create(struct dentry *root, struct drm_minor *minor)
+{
+       struct drm_device *dev = minor->dev;
+       struct dentry *ent;
+
+       ent = debugfs_create_file("i915_cache_sharing",
+                                 S_IRUGO | S_IWUSR,
+                                 root, dev,
+                                 &i915_cache_sharing_fops);
+       if (IS_ERR(ent))
+               return PTR_ERR(ent);
+
+       return drm_add_fake_info_node(minor, ent, &i915_cache_sharing_fops);
+}
+
 static struct drm_info_list i915_debugfs_list[] = {
        {"i915_capabilities", i915_capabilities, 0},
        {"i915_gem_objects", i915_gem_object_info, 0},
@@ -1488,6 +1667,12 @@ int i915_debugfs_init(struct drm_minor *minor)
                return ret;
 
        ret = i915_forcewake_create(minor->debugfs_root, minor);
+       if (ret)
+               return ret;
+       ret = i915_max_freq_create(minor->debugfs_root, minor);
+       if (ret)
+               return ret;
+       ret = i915_cache_sharing_create(minor->debugfs_root, minor);
        if (ret)
                return ret;
 
@@ -1504,6 +1689,10 @@ void i915_debugfs_cleanup(struct drm_minor *minor)
                                 1, minor);
        drm_debugfs_remove_files((struct drm_info_list *) &i915_wedged_fops,
                                 1, minor);
+       drm_debugfs_remove_files((struct drm_info_list *) &i915_max_freq_fops,
+                                1, minor);
+       drm_debugfs_remove_files((struct drm_info_list *) &i915_cache_sharing_fops,
+                                1, minor);
 }
 
 #endif /* CONFIG_DEBUG_FS */
index 1271282..8a3942c 100644 (file)
@@ -61,7 +61,6 @@ static void i915_write_hws_pga(struct drm_device *dev)
 static int i915_init_phys_hws(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       struct intel_ring_buffer *ring = LP_RING(dev_priv);
 
        /* Program Hardware Status Page */
        dev_priv->status_page_dmah =
@@ -71,10 +70,9 @@ static int i915_init_phys_hws(struct drm_device *dev)
                DRM_ERROR("Can not allocate hardware status page\n");
                return -ENOMEM;
        }
-       ring->status_page.page_addr =
-               (void __force __iomem *)dev_priv->status_page_dmah->vaddr;
 
-       memset_io(ring->status_page.page_addr, 0, PAGE_SIZE);
+       memset_io((void __force __iomem *)dev_priv->status_page_dmah->vaddr,
+                 0, PAGE_SIZE);
 
        i915_write_hws_pga(dev);
 
index 6867e19..7916bd9 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/io-mapping.h>
 #include <linux/i2c.h>
 #include <drm/intel-gtt.h>
+#include <linux/backlight.h>
 
 /* General customization:
  */
@@ -544,6 +545,7 @@ typedef struct drm_i915_private {
        u32 savePIPEB_LINK_M1;
        u32 savePIPEB_LINK_N1;
        u32 saveMCHBAR_RENDER_STANDBY;
+       u32 savePCH_PORT_HOTPLUG;
 
        struct {
                /** Bridge to intel-gtt-ko */
@@ -689,6 +691,7 @@ typedef struct drm_i915_private {
        int child_dev_num;
        struct child_device_config *child_dev;
        struct drm_connector *int_lvds_connector;
+       struct drm_connector *int_edp_connector;
 
        bool mchbar_need_disable;
 
@@ -722,6 +725,8 @@ typedef struct drm_i915_private {
        /* list of fbdev register on this device */
        struct intel_fbdev *fbdev;
 
+       struct backlight_device *backlight;
+
        struct drm_property *broadcast_rgb_property;
        struct drm_property *force_audio_property;
 
index d1cd8b8..a546a71 100644 (file)
@@ -3112,7 +3112,7 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
 
        if (pipelined != obj->ring) {
                ret = i915_gem_object_wait_rendering(obj);
-               if (ret)
+               if (ret == -ERESTARTSYS)
                        return ret;
        }
 
index 23d1ae6..9cbb0cd 100644 (file)
@@ -306,12 +306,15 @@ static void i915_hotplug_work_func(struct work_struct *work)
        struct drm_mode_config *mode_config = &dev->mode_config;
        struct intel_encoder *encoder;
 
+       mutex_lock(&mode_config->mutex);
        DRM_DEBUG_KMS("running encoder hotplug functions\n");
 
        list_for_each_entry(encoder, &mode_config->encoder_list, base.head)
                if (encoder->hot_plug)
                        encoder->hot_plug(encoder);
 
+       mutex_unlock(&mode_config->mutex);
+
        /* Just fire off a uevent and let userspace tell us what to do */
        drm_helper_hpd_irq_event(dev);
 }
@@ -2055,8 +2058,10 @@ void intel_irq_init(struct drm_device *dev)
                dev->driver->get_vblank_counter = gm45_get_vblank_counter;
        }
 
-
-       dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp;
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp;
+       else
+               dev->driver->get_vblank_timestamp = NULL;
        dev->driver->get_scanout_position = i915_get_crtc_scanoutpos;
 
        if (IS_IVYBRIDGE(dev)) {
index 02db299..542453f 100644 (file)
 #define  GRDOM_RENDER  (1<<2)
 #define  GRDOM_MEDIA   (3<<2)
 
+#define GEN6_MBCUNIT_SNPCR     0x900c /* for LLC config */
+#define   GEN6_MBC_SNPCR_SHIFT 21
+#define   GEN6_MBC_SNPCR_MASK  (3<<21)
+#define   GEN6_MBC_SNPCR_MAX   (0<<21)
+#define   GEN6_MBC_SNPCR_MED   (1<<21)
+#define   GEN6_MBC_SNPCR_LOW   (2<<21)
+#define   GEN6_MBC_SNPCR_MIN   (3<<21) /* only 1/16th of the cache is shared */
+
 #define GEN6_GDRST     0x941c
 #define  GEN6_GRDOM_FULL               (1 << 0)
 #define  GEN6_GRDOM_RENDER             (1 << 1)
 # define MI_FLUSH_ENABLE                               (1 << 11)
 
 #define GFX_MODE       0x02520
+#define GFX_MODE_GEN7  0x0229c
 #define   GFX_RUN_LIST_ENABLE          (1<<15)
 #define   GFX_TLB_INVALIDATE_ALWAYS    (1<<13)
 #define   GFX_SURFACE_FAULT_ENABLE     (1<<12)
 #define   GFX_PSMI_GRANULARITY         (1<<10)
 #define   GFX_PPGTT_ENABLE             (1<<9)
 
+#define GFX_MODE_ENABLE(bit) (((bit) << 16) | (bit))
+#define GFX_MODE_DISABLE(bit) (((bit) << 16) | (0))
+
 #define SCPD0          0x0209c /* 915+ only */
 #define IER            0x020a0
 #define IIR            0x020a4
 #define   ADPA_PIPE_SELECT_MASK        (1<<30)
 #define   ADPA_PIPE_A_SELECT   0
 #define   ADPA_PIPE_B_SELECT   (1<<30)
+#define   ADPA_PIPE_SELECT(pipe) ((pipe) << 30)
 #define   ADPA_USE_VGA_HVPOLARITY (1<<15)
 #define   ADPA_SETS_HVPOLARITY 0
 #define   ADPA_VSYNC_CNTL_DISABLE (1<<11)
 /* Selects pipe B for LVDS data.  Must be set on pre-965. */
 #define   LVDS_PIPEB_SELECT            (1 << 30)
 #define   LVDS_PIPE_MASK               (1 << 30)
+#define   LVDS_PIPE(pipe)              ((pipe) << 30)
 /* LVDS dithering flag on 965/g4x platform */
 #define   LVDS_ENABLE_DITHER           (1 << 25)
 /* LVDS sync polarity flags. Set to invert (i.e. negative) */
 #define   LVDS_B0B3_POWER_DOWN         (0 << 2)
 #define   LVDS_B0B3_POWER_UP           (3 << 2)
 
-#define LVDS_PIPE_ENABLED(V, P) \
-       (((V) & (LVDS_PIPE_MASK | LVDS_PORT_EN)) == ((P) << 30 | LVDS_PORT_EN))
-
 /* Video Data Island Packet control */
 #define VIDEO_DIP_DATA         0x61178
 #define VIDEO_DIP_CTL          0x61170
 #define   VIDEO_DIP_SELECT_AVI         (0 << 19)
 #define   VIDEO_DIP_SELECT_VENDOR      (1 << 19)
 #define   VIDEO_DIP_SELECT_SPD         (3 << 19)
+#define   VIDEO_DIP_SELECT_MASK                (3 << 19)
 #define   VIDEO_DIP_FREQ_ONCE          (0 << 16)
 #define   VIDEO_DIP_FREQ_VSYNC         (1 << 16)
 #define   VIDEO_DIP_FREQ_2VSYNC                (2 << 16)
 #define   DP_PIPEB_SELECT              (1 << 30)
 #define   DP_PIPE_MASK                 (1 << 30)
 
-#define DP_PIPE_ENABLED(V, P) \
-       (((V) & (DP_PIPE_MASK | DP_PORT_EN)) == ((P) << 30 | DP_PORT_EN))
-
 /* Link training mode - select a suitable mode for each stage */
 #define   DP_LINK_TRAIN_PAT_1          (0 << 28)
 #define   DP_LINK_TRAIN_PAT_2          (1 << 28)
 #define _TRANSA_DP_LINK_M2       0xe0048
 #define _TRANSA_DP_LINK_N2       0xe004c
 
+/* Per-transcoder DIP controls */
+
+#define _VIDEO_DIP_CTL_A         0xe0200
+#define _VIDEO_DIP_DATA_A        0xe0208
+#define _VIDEO_DIP_GCP_A         0xe0210
+
+#define _VIDEO_DIP_CTL_B         0xe1200
+#define _VIDEO_DIP_DATA_B        0xe1208
+#define _VIDEO_DIP_GCP_B         0xe1210
+
+#define TVIDEO_DIP_CTL(pipe) _PIPE(pipe, _VIDEO_DIP_CTL_A, _VIDEO_DIP_CTL_B)
+#define TVIDEO_DIP_DATA(pipe) _PIPE(pipe, _VIDEO_DIP_DATA_A, _VIDEO_DIP_DATA_B)
+#define TVIDEO_DIP_GCP(pipe) _PIPE(pipe, _VIDEO_DIP_GCP_A, _VIDEO_DIP_GCP_B)
+
 #define _TRANS_HTOTAL_B          0xe1000
 #define _TRANS_HBLANK_B          0xe1004
 #define _TRANS_HSYNC_B           0xe1008
 #define  TRANS_6BPC             (2<<5)
 #define  TRANS_12BPC            (3<<5)
 
+#define _TRANSA_CHICKEN2        0xf0064
+#define _TRANSB_CHICKEN2        0xf1064
+#define TRANS_CHICKEN2(pipe) _PIPE(pipe, _TRANSA_CHICKEN2, _TRANSB_CHICKEN2)
+#define   TRANS_AUTOTRAIN_GEN_STALL_DIS        (1<<31)
+
+#define SOUTH_CHICKEN1         0xc2000
+#define  FDIA_PHASE_SYNC_SHIFT_OVR     19
+#define  FDIA_PHASE_SYNC_SHIFT_EN      18
+#define FDI_PHASE_SYNC_OVR(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_OVR - ((pipe) * 2)))
+#define FDI_PHASE_SYNC_EN(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_EN - ((pipe) * 2)))
 #define SOUTH_CHICKEN2         0xc2004
 #define  DPLS_EDP_PPS_FIX_DIS  (1<<0)
 
 #define  ADPA_CRT_HOTPLUG_VOLREF_475MV  (1<<17)
 #define  ADPA_CRT_HOTPLUG_FORCE_TRIGGER (1<<16)
 
-#define ADPA_PIPE_ENABLED(V, P) \
-       (((V) & (ADPA_TRANS_SELECT_MASK | ADPA_DAC_ENABLE)) == ((P) << 30 | ADPA_DAC_ENABLE))
-
 /* or SDVOB */
 #define HDMIB   0xe1140
 #define  PORT_ENABLE    (1 << 31)
 #define  TRANSCODER_A   (0)
 #define  TRANSCODER_B   (1 << 30)
+#define  TRANSCODER(pipe)      ((pipe) << 30)
 #define  TRANSCODER_MASK   (1 << 30)
 #define  COLOR_FORMAT_8bpc      (0)
 #define  COLOR_FORMAT_12bpc     (3 << 26)
 #define  HSYNC_ACTIVE_HIGH      (1 << 3)
 #define  PORT_DETECTED          (1 << 2)
 
-#define HDMI_PIPE_ENABLED(V, P) \
-       (((V) & (TRANSCODER_MASK | PORT_ENABLE)) == ((P) << 30 | PORT_ENABLE))
-
 /* PCH SDVOB multiplex with HDMIB */
 #define PCH_SDVOB      HDMIB
 
 #define  PORT_TRANS_B_SEL_CPT  (1<<29)
 #define  PORT_TRANS_C_SEL_CPT  (2<<29)
 #define  PORT_TRANS_SEL_MASK   (3<<29)
+#define  PORT_TRANS_SEL_CPT(pipe)      ((pipe) << 29)
 
 #define TRANS_DP_CTL_A         0xe0300
 #define TRANS_DP_CTL_B         0xe1300
index 2857586..f107423 100644 (file)
@@ -812,6 +812,7 @@ int i915_save_state(struct drm_device *dev)
                dev_priv->saveFDI_RXB_IMR = I915_READ(_FDI_RXB_IMR);
                dev_priv->saveMCHBAR_RENDER_STANDBY =
                        I915_READ(RSTDBYCTL);
+               dev_priv->savePCH_PORT_HOTPLUG = I915_READ(PCH_PORT_HOTPLUG);
        } else {
                dev_priv->saveIER = I915_READ(IER);
                dev_priv->saveIMR = I915_READ(IMR);
@@ -863,13 +864,15 @@ int i915_restore_state(struct drm_device *dev)
                I915_WRITE(GTIMR, dev_priv->saveGTIMR);
                I915_WRITE(_FDI_RXA_IMR, dev_priv->saveFDI_RXA_IMR);
                I915_WRITE(_FDI_RXB_IMR, dev_priv->saveFDI_RXB_IMR);
+               I915_WRITE(PCH_PORT_HOTPLUG, dev_priv->savePCH_PORT_HOTPLUG);
        } else {
                I915_WRITE(IER, dev_priv->saveIER);
                I915_WRITE(IMR, dev_priv->saveIMR);
        }
        mutex_unlock(&dev->struct_mutex);
 
-       intel_init_clock_gating(dev);
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               intel_init_clock_gating(dev);
 
        if (IS_IRONLAKE_M(dev)) {
                ironlake_enable_drps(dev);
index 393a399..ee1d701 100644 (file)
@@ -980,11 +980,76 @@ static void assert_transcoder_disabled(struct drm_i915_private *dev_priv,
             pipe_name(pipe));
 }
 
+static bool dp_pipe_enabled(struct drm_i915_private *dev_priv,
+                           enum pipe pipe, u32 port_sel, u32 val)
+{
+       if ((val & DP_PORT_EN) == 0)
+               return false;
+
+       if (HAS_PCH_CPT(dev_priv->dev)) {
+               u32     trans_dp_ctl_reg = TRANS_DP_CTL(pipe);
+               u32     trans_dp_ctl = I915_READ(trans_dp_ctl_reg);
+               if ((trans_dp_ctl & TRANS_DP_PORT_SEL_MASK) != port_sel)
+                       return false;
+       } else {
+               if ((val & DP_PIPE_MASK) != (pipe << 30))
+                       return false;
+       }
+       return true;
+}
+
+static bool hdmi_pipe_enabled(struct drm_i915_private *dev_priv,
+                             enum pipe pipe, u32 val)
+{
+       if ((val & PORT_ENABLE) == 0)
+               return false;
+
+       if (HAS_PCH_CPT(dev_priv->dev)) {
+               if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe))
+                       return false;
+       } else {
+               if ((val & TRANSCODER_MASK) != TRANSCODER(pipe))
+                       return false;
+       }
+       return true;
+}
+
+static bool lvds_pipe_enabled(struct drm_i915_private *dev_priv,
+                             enum pipe pipe, u32 val)
+{
+       if ((val & LVDS_PORT_EN) == 0)
+               return false;
+
+       if (HAS_PCH_CPT(dev_priv->dev)) {
+               if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe))
+                       return false;
+       } else {
+               if ((val & LVDS_PIPE_MASK) != LVDS_PIPE(pipe))
+                       return false;
+       }
+       return true;
+}
+
+static bool adpa_pipe_enabled(struct drm_i915_private *dev_priv,
+                             enum pipe pipe, u32 val)
+{
+       if ((val & ADPA_DAC_ENABLE) == 0)
+               return false;
+       if (HAS_PCH_CPT(dev_priv->dev)) {
+               if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe))
+                       return false;
+       } else {
+               if ((val & ADPA_PIPE_SELECT_MASK) != ADPA_PIPE_SELECT(pipe))
+                       return false;
+       }
+       return true;
+}
+
 static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv,
-                                  enum pipe pipe, int reg)
+                                  enum pipe pipe, int reg, u32 port_sel)
 {
        u32 val = I915_READ(reg);
-       WARN(DP_PIPE_ENABLED(val, pipe),
+       WARN(dp_pipe_enabled(dev_priv, pipe, port_sel, val),
             "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",
             reg, pipe_name(pipe));
 }
@@ -993,7 +1058,7 @@ static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv,
                                     enum pipe pipe, int reg)
 {
        u32 val = I915_READ(reg);
-       WARN(HDMI_PIPE_ENABLED(val, pipe),
+       WARN(hdmi_pipe_enabled(dev_priv, val, pipe),
             "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",
             reg, pipe_name(pipe));
 }
@@ -1004,19 +1069,19 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv,
        int reg;
        u32 val;
 
-       assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_B);
-       assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_C);
-       assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_D);
+       assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_B, TRANS_DP_PORT_SEL_B);
+       assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_C, TRANS_DP_PORT_SEL_C);
+       assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_D, TRANS_DP_PORT_SEL_D);
 
        reg = PCH_ADPA;
        val = I915_READ(reg);
-       WARN(ADPA_PIPE_ENABLED(val, pipe),
+       WARN(adpa_pipe_enabled(dev_priv, val, pipe),
             "PCH VGA enabled on transcoder %c, should be disabled\n",
             pipe_name(pipe));
 
        reg = PCH_LVDS;
        val = I915_READ(reg);
-       WARN(LVDS_PIPE_ENABLED(val, pipe),
+       WARN(lvds_pipe_enabled(dev_priv, val, pipe),
             "PCH LVDS enabled on transcoder %c, should be disabled\n",
             pipe_name(pipe));
 
@@ -1276,6 +1341,17 @@ static void intel_disable_pipe(struct drm_i915_private *dev_priv,
        intel_wait_for_pipe_off(dev_priv->dev, pipe);
 }
 
+/*
+ * Plane regs are double buffered, going from enabled->disabled needs a
+ * trigger in order to latch.  The display address reg provides this.
+ */
+static void intel_flush_display_plane(struct drm_i915_private *dev_priv,
+                                     enum plane plane)
+{
+       I915_WRITE(DSPADDR(plane), I915_READ(DSPADDR(plane)));
+       I915_WRITE(DSPSURF(plane), I915_READ(DSPSURF(plane)));
+}
+
 /**
  * intel_enable_plane - enable a display plane on a given pipe
  * @dev_priv: i915 private structure
@@ -1299,20 +1375,10 @@ static void intel_enable_plane(struct drm_i915_private *dev_priv,
                return;
 
        I915_WRITE(reg, val | DISPLAY_PLANE_ENABLE);
+       intel_flush_display_plane(dev_priv, plane);
        intel_wait_for_vblank(dev_priv->dev, pipe);
 }
 
-/*
- * Plane regs are double buffered, going from enabled->disabled needs a
- * trigger in order to latch.  The display address reg provides this.
- */
-static void intel_flush_display_plane(struct drm_i915_private *dev_priv,
-                                     enum plane plane)
-{
-       u32 reg = DSPADDR(plane);
-       I915_WRITE(reg, I915_READ(reg));
-}
-
 /**
  * intel_disable_plane - disable a display plane
  * @dev_priv: i915 private structure
@@ -1338,19 +1404,24 @@ static void intel_disable_plane(struct drm_i915_private *dev_priv,
 }
 
 static void disable_pch_dp(struct drm_i915_private *dev_priv,
-                          enum pipe pipe, int reg)
+                          enum pipe pipe, int reg, u32 port_sel)
 {
        u32 val = I915_READ(reg);
-       if (DP_PIPE_ENABLED(val, pipe))
+       if (dp_pipe_enabled(dev_priv, pipe, port_sel, val)) {
+               DRM_DEBUG_KMS("Disabling pch dp %x on pipe %d\n", reg, pipe);
                I915_WRITE(reg, val & ~DP_PORT_EN);
+       }
 }
 
 static void disable_pch_hdmi(struct drm_i915_private *dev_priv,
                             enum pipe pipe, int reg)
 {
        u32 val = I915_READ(reg);
-       if (HDMI_PIPE_ENABLED(val, pipe))
+       if (hdmi_pipe_enabled(dev_priv, val, pipe)) {
+               DRM_DEBUG_KMS("Disabling pch HDMI %x on pipe %d\n",
+                             reg, pipe);
                I915_WRITE(reg, val & ~PORT_ENABLE);
+       }
 }
 
 /* Disable any ports connected to this transcoder */
@@ -1362,18 +1433,19 @@ static void intel_disable_pch_ports(struct drm_i915_private *dev_priv,
        val = I915_READ(PCH_PP_CONTROL);
        I915_WRITE(PCH_PP_CONTROL, val | PANEL_UNLOCK_REGS);
 
-       disable_pch_dp(dev_priv, pipe, PCH_DP_B);
-       disable_pch_dp(dev_priv, pipe, PCH_DP_C);
-       disable_pch_dp(dev_priv, pipe, PCH_DP_D);
+       disable_pch_dp(dev_priv, pipe, PCH_DP_B, TRANS_DP_PORT_SEL_B);
+       disable_pch_dp(dev_priv, pipe, PCH_DP_C, TRANS_DP_PORT_SEL_C);
+       disable_pch_dp(dev_priv, pipe, PCH_DP_D, TRANS_DP_PORT_SEL_D);
 
        reg = PCH_ADPA;
        val = I915_READ(reg);
-       if (ADPA_PIPE_ENABLED(val, pipe))
+       if (adpa_pipe_enabled(dev_priv, val, pipe))
                I915_WRITE(reg, val & ~ADPA_DAC_ENABLE);
 
        reg = PCH_LVDS;
        val = I915_READ(reg);
-       if (LVDS_PIPE_ENABLED(val, pipe)) {
+       if (lvds_pipe_enabled(dev_priv, val, pipe)) {
+               DRM_DEBUG_KMS("disable lvds on pipe %d val 0x%08x\n", pipe, val);
                I915_WRITE(reg, val & ~LVDS_PORT_EN);
                POSTING_READ(reg);
                udelay(100);
@@ -2096,7 +2168,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
 
        /* no fb bound */
        if (!crtc->fb) {
-               DRM_DEBUG_KMS("No FB bound\n");
+               DRM_ERROR("No FB bound\n");
                return 0;
        }
 
@@ -2105,6 +2177,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
        case 1:
                break;
        default:
+               DRM_ERROR("no plane for crtc\n");
                return -EINVAL;
        }
 
@@ -2114,6 +2187,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                                         NULL);
        if (ret != 0) {
                mutex_unlock(&dev->struct_mutex);
+               DRM_ERROR("pin & fence failed\n");
                return ret;
        }
 
@@ -2142,6 +2216,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
        if (ret) {
                i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj);
                mutex_unlock(&dev->struct_mutex);
+               DRM_ERROR("failed to update base address\n");
                return ret;
        }
 
@@ -2248,6 +2323,18 @@ static void intel_fdi_normal_train(struct drm_crtc *crtc)
                           FDI_FE_ERRC_ENABLE);
 }
 
+static void cpt_phase_pointer_enable(struct drm_device *dev, int pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 flags = I915_READ(SOUTH_CHICKEN1);
+
+       flags |= FDI_PHASE_SYNC_OVR(pipe);
+       I915_WRITE(SOUTH_CHICKEN1, flags); /* once to unlock... */
+       flags |= FDI_PHASE_SYNC_EN(pipe);
+       I915_WRITE(SOUTH_CHICKEN1, flags); /* then again to enable */
+       POSTING_READ(SOUTH_CHICKEN1);
+}
+
 /* The FDI link training functions for ILK/Ibexpeak. */
 static void ironlake_fdi_link_train(struct drm_crtc *crtc)
 {
@@ -2398,6 +2485,9 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
        POSTING_READ(reg);
        udelay(150);
 
+       if (HAS_PCH_CPT(dev))
+               cpt_phase_pointer_enable(dev, pipe);
+
        for (i = 0; i < 4; i++ ) {
                reg = FDI_TX_CTL(pipe);
                temp = I915_READ(reg);
@@ -2514,6 +2604,9 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc)
        POSTING_READ(reg);
        udelay(150);
 
+       if (HAS_PCH_CPT(dev))
+               cpt_phase_pointer_enable(dev, pipe);
+
        for (i = 0; i < 4; i++ ) {
                reg = FDI_TX_CTL(pipe);
                temp = I915_READ(reg);
@@ -2623,6 +2716,17 @@ static void ironlake_fdi_pll_enable(struct drm_crtc *crtc)
        }
 }
 
+static void cpt_phase_pointer_disable(struct drm_device *dev, int pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 flags = I915_READ(SOUTH_CHICKEN1);
+
+       flags &= ~(FDI_PHASE_SYNC_EN(pipe));
+       I915_WRITE(SOUTH_CHICKEN1, flags); /* once to disable... */
+       flags &= ~(FDI_PHASE_SYNC_OVR(pipe));
+       I915_WRITE(SOUTH_CHICKEN1, flags); /* then again to lock */
+       POSTING_READ(SOUTH_CHICKEN1);
+}
 static void ironlake_fdi_disable(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
@@ -2652,6 +2756,8 @@ static void ironlake_fdi_disable(struct drm_crtc *crtc)
                I915_WRITE(FDI_RX_CHICKEN(pipe),
                           I915_READ(FDI_RX_CHICKEN(pipe) &
                                     ~FDI_RX_PHASE_SYNC_POINTER_EN));
+       } else if (HAS_PCH_CPT(dev)) {
+               cpt_phase_pointer_disable(dev, pipe);
        }
 
        /* still set train pattern 1 */
@@ -2862,14 +2968,18 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
                I915_WRITE(PF_WIN_SZ(pipe), dev_priv->pch_pf_size);
        }
 
+       /*
+        * On ILK+ LUT must be loaded before the pipe is running but with
+        * clocks enabled
+        */
+       intel_crtc_load_lut(crtc);
+
        intel_enable_pipe(dev_priv, pipe, is_pch_port);
        intel_enable_plane(dev_priv, plane, pipe);
 
        if (is_pch_port)
                ironlake_pch_enable(crtc);
 
-       intel_crtc_load_lut(crtc);
-
        mutex_lock(&dev->struct_mutex);
        intel_update_fbc(dev);
        mutex_unlock(&dev->struct_mutex);
@@ -4538,7 +4648,9 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
                        if (connector->encoder != encoder)
                                continue;
 
-                       if (connector->display_info.bpc < display_bpc) {
+                       /* Don't use an invalid EDID bpc value */
+                       if (connector->display_info.bpc &&
+                           connector->display_info.bpc < display_bpc) {
                                DRM_DEBUG_DRIVER("clamping display bpc (was %d) to EDID reported max of %d\n", display_bpc, connector->display_info.bpc);
                                display_bpc = connector->display_info.bpc;
                        }
@@ -4985,6 +5097,81 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
        return ret;
 }
 
+static void ironlake_update_pch_refclk(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct drm_crtc *crtc;
+       struct intel_encoder *encoder;
+       struct intel_encoder *has_edp_encoder = NULL;
+       u32 temp;
+       bool has_lvds = false;
+
+       /* We need to take the global config into account */
+       list_for_each_entry(crtc, &mode_config->crtc_list, head) {
+               if (!crtc->enabled)
+                       continue;
+
+               list_for_each_entry(encoder, &mode_config->encoder_list,
+                                   base.head) {
+                       if (encoder->base.crtc != crtc)
+                               continue;
+
+                       switch (encoder->type) {
+                       case INTEL_OUTPUT_LVDS:
+                               has_lvds = true;
+                       case INTEL_OUTPUT_EDP:
+                               has_edp_encoder = encoder;
+                               break;
+                       }
+               }
+       }
+
+       /* Ironlake: try to setup display ref clock before DPLL
+        * enabling. This is only under driver's control after
+        * PCH B stepping, previous chipset stepping should be
+        * ignoring this setting.
+        */
+       temp = I915_READ(PCH_DREF_CONTROL);
+       /* Always enable nonspread source */
+       temp &= ~DREF_NONSPREAD_SOURCE_MASK;
+       temp |= DREF_NONSPREAD_SOURCE_ENABLE;
+       temp &= ~DREF_SSC_SOURCE_MASK;
+       temp |= DREF_SSC_SOURCE_ENABLE;
+       I915_WRITE(PCH_DREF_CONTROL, temp);
+
+       POSTING_READ(PCH_DREF_CONTROL);
+       udelay(200);
+
+       if (has_edp_encoder) {
+               if (intel_panel_use_ssc(dev_priv)) {
+                       temp |= DREF_SSC1_ENABLE;
+                       I915_WRITE(PCH_DREF_CONTROL, temp);
+
+                       POSTING_READ(PCH_DREF_CONTROL);
+                       udelay(200);
+               }
+               temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
+
+               /* Enable CPU source on CPU attached eDP */
+               if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
+                       if (intel_panel_use_ssc(dev_priv))
+                               temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
+                       else
+                               temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
+               } else {
+                       /* Enable SSC on PCH eDP if needed */
+                       if (intel_panel_use_ssc(dev_priv)) {
+                               DRM_ERROR("enabling SSC on PCH\n");
+                               temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
+                       }
+               }
+               I915_WRITE(PCH_DREF_CONTROL, temp);
+               POSTING_READ(PCH_DREF_CONTROL);
+               udelay(200);
+       }
+}
+
 static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
                                  struct drm_display_mode *mode,
                                  struct drm_display_mode *adjusted_mode,
@@ -5153,7 +5340,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
                temp |= PIPE_12BPC;
                break;
        default:
-               WARN(1, "intel_choose_pipe_bpp returned invalid value\n");
+               WARN(1, "intel_choose_pipe_bpp returned invalid value %d\n",
+                       pipe_bpp);
                temp |= PIPE_8BPC;
                pipe_bpp = 24;
                break;
@@ -5179,49 +5367,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
        ironlake_compute_m_n(intel_crtc->bpp, lane, target_clock, link_bw,
                             &m_n);
 
-       /* Ironlake: try to setup display ref clock before DPLL
-        * enabling. This is only under driver's control after
-        * PCH B stepping, previous chipset stepping should be
-        * ignoring this setting.
-        */
-       temp = I915_READ(PCH_DREF_CONTROL);
-       /* Always enable nonspread source */
-       temp &= ~DREF_NONSPREAD_SOURCE_MASK;
-       temp |= DREF_NONSPREAD_SOURCE_ENABLE;
-       temp &= ~DREF_SSC_SOURCE_MASK;
-       temp |= DREF_SSC_SOURCE_ENABLE;
-       I915_WRITE(PCH_DREF_CONTROL, temp);
-
-       POSTING_READ(PCH_DREF_CONTROL);
-       udelay(200);
-
-       if (has_edp_encoder) {
-               if (intel_panel_use_ssc(dev_priv)) {
-                       temp |= DREF_SSC1_ENABLE;
-                       I915_WRITE(PCH_DREF_CONTROL, temp);
-
-                       POSTING_READ(PCH_DREF_CONTROL);
-                       udelay(200);
-               }
-               temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
-
-               /* Enable CPU source on CPU attached eDP */
-               if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
-                       if (intel_panel_use_ssc(dev_priv))
-                               temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
-                       else
-                               temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
-               } else {
-                       /* Enable SSC on PCH eDP if needed */
-                       if (intel_panel_use_ssc(dev_priv)) {
-                               DRM_ERROR("enabling SSC on PCH\n");
-                               temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
-                       }
-               }
-               I915_WRITE(PCH_DREF_CONTROL, temp);
-               POSTING_READ(PCH_DREF_CONTROL);
-               udelay(200);
-       }
+       ironlake_update_pch_refclk(dev);
 
        fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
        if (has_reduced_clock)
@@ -5238,7 +5384,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
        } else if (is_sdvo && is_tv)
                factor = 20;
 
-       if (clock.m1 < factor * clock.n)
+       if (clock.m < factor * clock.n)
                fp |= FP_CB_TUNE;
 
        dpll = 0;
@@ -5516,6 +5662,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 
        drm_vblank_post_modeset(dev, pipe);
 
+       intel_crtc->dpms_mode = DRM_MODE_DPMS_ON;
+
        return ret;
 }
 
@@ -7714,10 +7862,12 @@ static void gen6_init_clock_gating(struct drm_device *dev)
                   ILK_DPARB_CLK_GATE  |
                   ILK_DPFD_CLK_GATE);
 
-       for_each_pipe(pipe)
+       for_each_pipe(pipe) {
                I915_WRITE(DSPCNTR(pipe),
                           I915_READ(DSPCNTR(pipe)) |
                           DISPPLANE_TRICKLE_FEED_DISABLE);
+               intel_flush_display_plane(dev_priv, pipe);
+       }
 }
 
 static void ivybridge_init_clock_gating(struct drm_device *dev)
@@ -7734,10 +7884,12 @@ static void ivybridge_init_clock_gating(struct drm_device *dev)
 
        I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE);
 
-       for_each_pipe(pipe)
+       for_each_pipe(pipe) {
                I915_WRITE(DSPCNTR(pipe),
                           I915_READ(DSPCNTR(pipe)) |
                           DISPPLANE_TRICKLE_FEED_DISABLE);
+               intel_flush_display_plane(dev_priv, pipe);
+       }
 }
 
 static void g4x_init_clock_gating(struct drm_device *dev)
@@ -7820,6 +7972,7 @@ static void ibx_init_clock_gating(struct drm_device *dev)
 static void cpt_init_clock_gating(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       int pipe;
 
        /*
         * On Ibex Peak and Cougar Point, we need to disable clock
@@ -7829,6 +7982,9 @@ static void cpt_init_clock_gating(struct drm_device *dev)
        I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
        I915_WRITE(SOUTH_CHICKEN2, I915_READ(SOUTH_CHICKEN2) |
                   DPLS_EDP_PPS_FIX_DIS);
+       /* Without this, mode sets may fail silently on FDI */
+       for_each_pipe(pipe)
+               I915_WRITE(TRANS_CHICKEN2(pipe), TRANS_AUTOTRAIN_GEN_STALL_DIS);
 }
 
 static void ironlake_teardown_rc6(struct drm_device *dev)
@@ -8178,6 +8334,9 @@ struct intel_quirk intel_quirks[] = {
 
        /* Lenovo U160 cannot use SSC on LVDS */
        { 0x0046, 0x17aa, 0x3920, quirk_ssc_force_disable },
+
+       /* Sony Vaio Y cannot use SSC on LVDS */
+       { 0x0046, 0x104d, 0x9076, quirk_ssc_force_disable },
 };
 
 static void intel_init_quirks(struct drm_device *dev)
index f797fb5..44fef5e 100644 (file)
@@ -50,9 +50,10 @@ struct intel_dp {
        bool has_audio;
        int force_audio;
        uint32_t color_range;
+       int dpms_mode;
        uint8_t link_bw;
        uint8_t lane_count;
-       uint8_t dpcd[4];
+       uint8_t dpcd[8];
        struct i2c_adapter adapter;
        struct i2c_algo_dp_aux_data algo;
        bool is_pch_edp;
@@ -316,9 +317,17 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
        else
                precharge = 5;
 
-       if (I915_READ(ch_ctl) & DP_AUX_CH_CTL_SEND_BUSY) {
-               DRM_ERROR("dp_aux_ch not started status 0x%08x\n",
-                         I915_READ(ch_ctl));
+       /* Try to wait for any previous AUX channel activity */
+       for (try = 0; try < 3; try++) {
+               status = I915_READ(ch_ctl);
+               if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0)
+                       break;
+               msleep(1);
+       }
+
+       if (try == 3) {
+               WARN(1, "dp_aux_ch not started status 0x%08x\n",
+                    I915_READ(ch_ctl));
                return -EBUSY;
        }
 
@@ -770,6 +779,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
        memset(intel_dp->link_configuration, 0, DP_LINK_CONFIGURATION_SIZE);
        intel_dp->link_configuration[0] = intel_dp->link_bw;
        intel_dp->link_configuration[1] = intel_dp->lane_count;
+       intel_dp->link_configuration[8] = DP_SET_ANSI_8B10B;
 
        /*
         * Check for DPCD version > 1.1 and enhanced framing support
@@ -1011,6 +1021,8 @@ static void intel_dp_commit(struct drm_encoder *encoder)
 
        if (is_edp(intel_dp))
                ironlake_edp_backlight_on(dev);
+
+       intel_dp->dpms_mode = DRM_MODE_DPMS_ON;
 }
 
 static void
@@ -1045,6 +1057,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
                if (is_edp(intel_dp))
                        ironlake_edp_backlight_on(dev);
        }
+       intel_dp->dpms_mode = mode;
 }
 
 /*
@@ -1334,10 +1347,16 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
        u32 reg;
        uint32_t DP = intel_dp->DP;
 
-       /* Enable output, wait for it to become active */
-       I915_WRITE(intel_dp->output_reg, intel_dp->DP);
-       POSTING_READ(intel_dp->output_reg);
-       intel_wait_for_vblank(dev, intel_crtc->pipe);
+       /*
+        * On CPT we have to enable the port in training pattern 1, which
+        * will happen below in intel_dp_set_link_train.  Otherwise, enable
+        * the port and wait for it to become active.
+        */
+       if (!HAS_PCH_CPT(dev)) {
+               I915_WRITE(intel_dp->output_reg, intel_dp->DP);
+               POSTING_READ(intel_dp->output_reg);
+               intel_wait_for_vblank(dev, intel_crtc->pipe);
+       }
 
        /* Write the link configuration data */
        intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET,
@@ -1370,7 +1389,8 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
                        reg = DP | DP_LINK_TRAIN_PAT_1;
 
                if (!intel_dp_set_link_train(intel_dp, reg,
-                                            DP_TRAINING_PATTERN_1))
+                                            DP_TRAINING_PATTERN_1 |
+                                            DP_LINK_SCRAMBLING_DISABLE))
                        break;
                /* Set training pattern 1 */
 
@@ -1445,7 +1465,8 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
 
                /* channel eq pattern */
                if (!intel_dp_set_link_train(intel_dp, reg,
-                                            DP_TRAINING_PATTERN_2))
+                                            DP_TRAINING_PATTERN_2 |
+                                            DP_LINK_SCRAMBLING_DISABLE))
                        break;
 
                udelay(400);
@@ -1559,6 +1580,18 @@ intel_dp_link_down(struct intel_dp *intel_dp)
        POSTING_READ(intel_dp->output_reg);
 }
 
+static bool
+intel_dp_get_dpcd(struct intel_dp *intel_dp)
+{
+       if (intel_dp_aux_native_read_retry(intel_dp, 0x000, intel_dp->dpcd,
+                                          sizeof (intel_dp->dpcd)) &&
+           (intel_dp->dpcd[DP_DPCD_REV] != 0)) {
+               return true;
+       }
+
+       return false;
+}
+
 /*
  * According to DP spec
  * 5.1.2:
@@ -1571,36 +1604,44 @@ intel_dp_link_down(struct intel_dp *intel_dp)
 static void
 intel_dp_check_link_status(struct intel_dp *intel_dp)
 {
-       int ret;
+       if (intel_dp->dpms_mode != DRM_MODE_DPMS_ON)
+               return;
 
        if (!intel_dp->base.base.crtc)
                return;
 
+       /* Try to read receiver status if the link appears to be up */
        if (!intel_dp_get_link_status(intel_dp)) {
                intel_dp_link_down(intel_dp);
                return;
        }
 
-       /* Try to read receiver status if the link appears to be up */
-       ret = intel_dp_aux_native_read(intel_dp,
-                                      0x000, intel_dp->dpcd,
-                                      sizeof (intel_dp->dpcd));
-       if (ret != sizeof(intel_dp->dpcd)) {
+       /* Now read the DPCD to see if it's actually running */
+       if (!intel_dp_get_dpcd(intel_dp)) {
                intel_dp_link_down(intel_dp);
                return;
        }
 
        if (!intel_channel_eq_ok(intel_dp)) {
+               DRM_DEBUG_KMS("%s: channel EQ not ok, retraining\n",
+                             drm_get_encoder_name(&intel_dp->base.base));
                intel_dp_start_link_train(intel_dp);
                intel_dp_complete_link_train(intel_dp);
        }
 }
 
+static enum drm_connector_status
+intel_dp_detect_dpcd(struct intel_dp *intel_dp)
+{
+       if (intel_dp_get_dpcd(intel_dp))
+               return connector_status_connected;
+       return connector_status_disconnected;
+}
+
 static enum drm_connector_status
 ironlake_dp_detect(struct intel_dp *intel_dp)
 {
        enum drm_connector_status status;
-       bool ret;
 
        /* Can't disconnect eDP, but you can close the lid... */
        if (is_edp(intel_dp)) {
@@ -1610,15 +1651,7 @@ ironlake_dp_detect(struct intel_dp *intel_dp)
                return status;
        }
 
-       status = connector_status_disconnected;
-       ret = intel_dp_aux_native_read_retry(intel_dp,
-                                            0x000, intel_dp->dpcd,
-                                            sizeof (intel_dp->dpcd));
-       if (ret && intel_dp->dpcd[DP_DPCD_REV] != 0)
-               status = connector_status_connected;
-       DRM_DEBUG_KMS("DPCD: %hx%hx%hx%hx\n", intel_dp->dpcd[0],
-                     intel_dp->dpcd[1], intel_dp->dpcd[2], intel_dp->dpcd[3]);
-       return status;
+       return intel_dp_detect_dpcd(intel_dp);
 }
 
 static enum drm_connector_status
@@ -1626,7 +1659,6 @@ g4x_dp_detect(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       enum drm_connector_status status;
        uint32_t temp, bit;
 
        switch (intel_dp->output_reg) {
@@ -1648,15 +1680,7 @@ g4x_dp_detect(struct intel_dp *intel_dp)
        if ((temp & bit) == 0)
                return connector_status_disconnected;
 
-       status = connector_status_disconnected;
-       if (intel_dp_aux_native_read(intel_dp, 0x000, intel_dp->dpcd,
-                                    sizeof (intel_dp->dpcd)) == sizeof (intel_dp->dpcd))
-       {
-               if (intel_dp->dpcd[DP_DPCD_REV] != 0)
-                       status = connector_status_connected;
-       }
-
-       return status;
+       return intel_dp_detect_dpcd(intel_dp);
 }
 
 /**
@@ -1679,6 +1703,12 @@ intel_dp_detect(struct drm_connector *connector, bool force)
                status = ironlake_dp_detect(intel_dp);
        else
                status = g4x_dp_detect(intel_dp);
+
+       DRM_DEBUG_KMS("DPCD: %02hx%02hx%02hx%02hx%02hx%02hx%02hx%02hx\n",
+                     intel_dp->dpcd[0], intel_dp->dpcd[1], intel_dp->dpcd[2],
+                     intel_dp->dpcd[3], intel_dp->dpcd[4], intel_dp->dpcd[5],
+                     intel_dp->dpcd[6], intel_dp->dpcd[7]);
+
        if (status != connector_status_connected)
                return status;
 
@@ -1811,6 +1841,11 @@ done:
 static void
 intel_dp_destroy (struct drm_connector *connector)
 {
+       struct drm_device *dev = connector->dev;
+
+       if (intel_dpd_is_edp(dev))
+               intel_panel_destroy_backlight(dev);
+
        drm_sysfs_connector_remove(connector);
        drm_connector_cleanup(connector);
        kfree(connector);
@@ -1924,6 +1959,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)
                return;
 
        intel_dp->output_reg = output_reg;
+       intel_dp->dpms_mode = -1;
 
        intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
        if (!intel_connector) {
@@ -2000,7 +2036,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)
 
        /* Cache some DPCD data in the eDP case */
        if (is_edp(intel_dp)) {
-               int ret;
+               bool ret;
                u32 pp_on, pp_div;
 
                pp_on = I915_READ(PCH_PP_ON_DELAYS);
@@ -2013,11 +2049,9 @@ intel_dp_init(struct drm_device *dev, int output_reg)
                dev_priv->panel_t12 *= 100; /* t12 in 100ms units */
 
                ironlake_edp_panel_vdd_on(intel_dp);
-               ret = intel_dp_aux_native_read(intel_dp, DP_DPCD_REV,
-                                              intel_dp->dpcd,
-                                              sizeof(intel_dp->dpcd));
+               ret = intel_dp_get_dpcd(intel_dp);
                ironlake_edp_panel_vdd_off(intel_dp);
-               if (ret == sizeof(intel_dp->dpcd)) {
+               if (ret) {
                        if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11)
                                dev_priv->no_aux_handshake =
                                        intel_dp->dpcd[DP_MAX_DOWNSPREAD] &
@@ -2043,6 +2077,8 @@ intel_dp_init(struct drm_device *dev, int output_reg)
                                        DRM_MODE_TYPE_PREFERRED;
                        }
                }
+               dev_priv->int_edp_connector = connector;
+               intel_panel_setup_backlight(dev);
        }
 
        intel_dp_add_properties(intel_dp, connector);
index 6e990f9..0b2ee9d 100644 (file)
@@ -178,10 +178,28 @@ struct intel_crtc {
 #define to_intel_encoder(x) container_of(x, struct intel_encoder, base)
 #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base)
 
+#define DIP_HEADER_SIZE        5
+
 #define DIP_TYPE_AVI    0x82
 #define DIP_VERSION_AVI 0x2
 #define DIP_LEN_AVI     13
 
+#define DIP_TYPE_SPD   0x3
+#define DIP_VERSION_SPD        0x1
+#define DIP_LEN_SPD    25
+#define DIP_SPD_UNKNOWN        0
+#define DIP_SPD_DSTB   0x1
+#define DIP_SPD_DVDP   0x2
+#define DIP_SPD_DVHS   0x3
+#define DIP_SPD_HDDVR  0x4
+#define DIP_SPD_DVC    0x5
+#define DIP_SPD_DSC    0x6
+#define DIP_SPD_VCD    0x7
+#define DIP_SPD_GAME   0x8
+#define DIP_SPD_PC     0x9
+#define DIP_SPD_BD     0xa
+#define DIP_SPD_SCD    0xb
+
 struct dip_infoframe {
        uint8_t type;           /* HB0 */
        uint8_t ver;            /* HB1 */
@@ -206,6 +224,11 @@ struct dip_infoframe {
                        uint16_t left_bar_end;
                        uint16_t right_bar_start;
                } avi;
+               struct {
+                       uint8_t vn[8];
+                       uint8_t pd[16];
+                       uint8_t sdi;
+               } spd;
                uint8_t payload[27];
        } __attribute__ ((packed)) body;
 } __attribute__((packed));
@@ -274,9 +297,10 @@ extern void intel_pch_panel_fitting(struct drm_device *dev,
 extern u32 intel_panel_get_max_backlight(struct drm_device *dev);
 extern u32 intel_panel_get_backlight(struct drm_device *dev);
 extern void intel_panel_set_backlight(struct drm_device *dev, u32 level);
-extern void intel_panel_setup_backlight(struct drm_device *dev);
+extern int intel_panel_setup_backlight(struct drm_device *dev);
 extern void intel_panel_enable_backlight(struct drm_device *dev);
 extern void intel_panel_disable_backlight(struct drm_device *dev);
+extern void intel_panel_destroy_backlight(struct drm_device *dev);
 extern enum drm_connector_status intel_panel_detect(struct drm_device *dev);
 
 extern void intel_crtc_load_lut(struct drm_crtc *crtc);
index 1ed8e69..226ba83 100644 (file)
@@ -45,6 +45,8 @@ struct intel_hdmi {
        bool has_hdmi_sink;
        bool has_audio;
        int force_audio;
+       void (*write_infoframe)(struct drm_encoder *encoder,
+                               struct dip_infoframe *frame);
 };
 
 static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder)
@@ -58,37 +60,70 @@ static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector)
                            struct intel_hdmi, base);
 }
 
-void intel_dip_infoframe_csum(struct dip_infoframe *avi_if)
+void intel_dip_infoframe_csum(struct dip_infoframe *frame)
 {
-       uint8_t *data = (uint8_t *)avi_if;
+       uint8_t *data = (uint8_t *)frame;
        uint8_t sum = 0;
        unsigned i;
 
-       avi_if->checksum = 0;
-       avi_if->ecc = 0;
+       frame->checksum = 0;
+       frame->ecc = 0;
 
-       for (i = 0; i < sizeof(*avi_if); i++)
+       /* Header isn't part of the checksum */
+       for (i = 5; i < frame->len; i++)
                sum += data[i];
 
-       avi_if->checksum = 0x100 - sum;
+       frame->checksum = 0x100 - sum;
 }
 
-static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
+static u32 intel_infoframe_index(struct dip_infoframe *frame)
 {
-       struct dip_infoframe avi_if = {
-               .type = DIP_TYPE_AVI,
-               .ver = DIP_VERSION_AVI,
-               .len = DIP_LEN_AVI,
-       };
-       uint32_t *data = (uint32_t *)&avi_if;
+       u32 flags = 0;
+
+       switch (frame->type) {
+       case DIP_TYPE_AVI:
+               flags |= VIDEO_DIP_SELECT_AVI;
+               break;
+       case DIP_TYPE_SPD:
+               flags |= VIDEO_DIP_SELECT_SPD;
+               break;
+       default:
+               DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
+               break;
+       }
+
+       return flags;
+}
+
+static u32 intel_infoframe_flags(struct dip_infoframe *frame)
+{
+       u32 flags = 0;
+
+       switch (frame->type) {
+       case DIP_TYPE_AVI:
+               flags |= VIDEO_DIP_ENABLE_AVI | VIDEO_DIP_FREQ_VSYNC;
+               break;
+       case DIP_TYPE_SPD:
+               flags |= VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_FREQ_2VSYNC;
+               break;
+       default:
+               DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
+               break;
+       }
+
+       return flags;
+}
+
+static void i9xx_write_infoframe(struct drm_encoder *encoder,
+                                struct dip_infoframe *frame)
+{
+       uint32_t *data = (uint32_t *)frame;
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
-       u32 port;
-       unsigned i;
+       u32 port, flags, val = I915_READ(VIDEO_DIP_CTL);
+       unsigned i, len = DIP_HEADER_SIZE + frame->len;
 
-       if (!intel_hdmi->has_hdmi_sink)
-               return;
 
        /* XXX first guess at handling video port, is this corrent? */
        if (intel_hdmi->sdvox_reg == SDVOB)
@@ -98,18 +133,87 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
        else
                return;
 
-       I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port |
-                  VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC);
+       flags = intel_infoframe_index(frame);
+
+       val &= ~VIDEO_DIP_SELECT_MASK;
 
-       intel_dip_infoframe_csum(&avi_if);
-       for (i = 0; i < sizeof(avi_if); i += 4) {
+       I915_WRITE(VIDEO_DIP_CTL, val | port | flags);
+
+       for (i = 0; i < len; i += 4) {
                I915_WRITE(VIDEO_DIP_DATA, *data);
                data++;
        }
 
-       I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port |
-                  VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC |
-                  VIDEO_DIP_ENABLE_AVI);
+       flags |= intel_infoframe_flags(frame);
+
+       I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | val | port | flags);
+}
+
+static void ironlake_write_infoframe(struct drm_encoder *encoder,
+                                    struct dip_infoframe *frame)
+{
+       uint32_t *data = (uint32_t *)frame;
+       struct drm_device *dev = encoder->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc = encoder->crtc;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
+       unsigned i, len = DIP_HEADER_SIZE + frame->len;
+       u32 flags, val = I915_READ(reg);
+
+       intel_wait_for_vblank(dev, intel_crtc->pipe);
+
+       flags = intel_infoframe_index(frame);
+
+       val &= ~VIDEO_DIP_SELECT_MASK;
+
+       I915_WRITE(reg, val | flags);
+
+       for (i = 0; i < len; i += 4) {
+               I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
+               data++;
+       }
+
+       flags |= intel_infoframe_flags(frame);
+
+       I915_WRITE(reg, VIDEO_DIP_ENABLE | val | flags);
+}
+static void intel_set_infoframe(struct drm_encoder *encoder,
+                               struct dip_infoframe *frame)
+{
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+
+       if (!intel_hdmi->has_hdmi_sink)
+               return;
+
+       intel_dip_infoframe_csum(frame);
+       intel_hdmi->write_infoframe(encoder, frame);
+}
+
+static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
+{
+       struct dip_infoframe avi_if = {
+               .type = DIP_TYPE_AVI,
+               .ver = DIP_VERSION_AVI,
+               .len = DIP_LEN_AVI,
+       };
+
+       intel_set_infoframe(encoder, &avi_if);
+}
+
+static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
+{
+       struct dip_infoframe spd_if;
+
+       memset(&spd_if, 0, sizeof(spd_if));
+       spd_if.type = DIP_TYPE_SPD;
+       spd_if.ver = DIP_VERSION_SPD;
+       spd_if.len = DIP_LEN_SPD;
+       strcpy(spd_if.body.spd.vn, "Intel");
+       strcpy(spd_if.body.spd.pd, "Integrated gfx");
+       spd_if.body.spd.sdi = DIP_SPD_PC;
+
+       intel_set_infoframe(encoder, &spd_if);
 }
 
 static void intel_hdmi_mode_set(struct drm_encoder *encoder,
@@ -156,6 +260,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
        POSTING_READ(intel_hdmi->sdvox_reg);
 
        intel_hdmi_set_avi_infoframe(encoder);
+       intel_hdmi_set_spd_infoframe(encoder);
 }
 
 static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
@@ -433,6 +538,11 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
 
        intel_hdmi->sdvox_reg = sdvox_reg;
 
+       if (!HAS_PCH_SPLIT(dev))
+               intel_hdmi->write_infoframe = i9xx_write_infoframe;
+       else
+               intel_hdmi->write_infoframe = ironlake_write_infoframe;
+
        drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs);
 
        intel_hdmi_add_properties(intel_hdmi, connector);
index b28f7bd..31da77f 100644 (file)
@@ -72,14 +72,16 @@ static void intel_lvds_enable(struct intel_lvds *intel_lvds)
 {
        struct drm_device *dev = intel_lvds->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 ctl_reg, lvds_reg;
+       u32 ctl_reg, lvds_reg, stat_reg;
 
        if (HAS_PCH_SPLIT(dev)) {
                ctl_reg = PCH_PP_CONTROL;
                lvds_reg = PCH_LVDS;
+               stat_reg = PCH_PP_STATUS;
        } else {
                ctl_reg = PP_CONTROL;
                lvds_reg = LVDS;
+               stat_reg = PP_STATUS;
        }
 
        I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN);
@@ -94,17 +96,16 @@ static void intel_lvds_enable(struct intel_lvds *intel_lvds)
                DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n",
                              intel_lvds->pfit_control,
                              intel_lvds->pfit_pgm_ratios);
-               if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000)) {
-                       DRM_ERROR("timed out waiting for panel to power off\n");
-               } else {
-                       I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios);
-                       I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control);
-                       intel_lvds->pfit_dirty = false;
-               }
+
+               I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios);
+               I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control);
+               intel_lvds->pfit_dirty = false;
        }
 
        I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON);
        POSTING_READ(lvds_reg);
+       if (wait_for((I915_READ(stat_reg) & PP_ON) != 0, 1000))
+               DRM_ERROR("timed out waiting for panel to power on\n");
 
        intel_panel_enable_backlight(dev);
 }
@@ -113,24 +114,25 @@ static void intel_lvds_disable(struct intel_lvds *intel_lvds)
 {
        struct drm_device *dev = intel_lvds->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 ctl_reg, lvds_reg;
+       u32 ctl_reg, lvds_reg, stat_reg;
 
        if (HAS_PCH_SPLIT(dev)) {
                ctl_reg = PCH_PP_CONTROL;
                lvds_reg = PCH_LVDS;
+               stat_reg = PCH_PP_STATUS;
        } else {
                ctl_reg = PP_CONTROL;
                lvds_reg = LVDS;
+               stat_reg = PP_STATUS;
        }
 
        intel_panel_disable_backlight(dev);
 
        I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON);
+       if (wait_for((I915_READ(stat_reg) & PP_ON) == 0, 1000))
+               DRM_ERROR("timed out waiting for panel to power off\n");
 
        if (intel_lvds->pfit_control) {
-               if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000))
-                       DRM_ERROR("timed out waiting for panel to power off\n");
-
                I915_WRITE(PFIT_CONTROL, 0);
                intel_lvds->pfit_dirty = true;
        }
@@ -398,53 +400,21 @@ out:
 
 static void intel_lvds_prepare(struct drm_encoder *encoder)
 {
-       struct drm_device *dev = encoder->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
 
-       /* We try to do the minimum that is necessary in order to unlock
-        * the registers for mode setting.
-        *
-        * On Ironlake, this is quite simple as we just set the unlock key
-        * and ignore all subtleties. (This may cause some issues...)
-        *
+       /*
         * Prior to Ironlake, we must disable the pipe if we want to adjust
         * the panel fitter. However at all other times we can just reset
         * the registers regardless.
         */
-
-       if (HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(PCH_PP_CONTROL,
-                          I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS);
-       } else if (intel_lvds->pfit_dirty) {
-               I915_WRITE(PP_CONTROL,
-                          (I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS)
-                          & ~POWER_TARGET_ON);
-       } else {
-               I915_WRITE(PP_CONTROL,
-                          I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
-       }
+       if (!HAS_PCH_SPLIT(encoder->dev) && intel_lvds->pfit_dirty)
+               intel_lvds_disable(intel_lvds);
 }
 
 static void intel_lvds_commit(struct drm_encoder *encoder)
 {
-       struct drm_device *dev = encoder->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
 
-       /* Undo any unlocking done in prepare to prevent accidental
-        * adjustment of the registers.
-        */
-       if (HAS_PCH_SPLIT(dev)) {
-               u32 val = I915_READ(PCH_PP_CONTROL);
-               if ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS)
-                       I915_WRITE(PCH_PP_CONTROL, val & 0x3);
-       } else {
-               u32 val = I915_READ(PP_CONTROL);
-               if ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS)
-                       I915_WRITE(PP_CONTROL, val & 0x3);
-       }
-
        /* Always do a full power on as we do not know what state
         * we were left in.
         */
@@ -582,6 +552,8 @@ static void intel_lvds_destroy(struct drm_connector *connector)
        struct drm_device *dev = connector->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 
+       intel_panel_destroy_backlight(dev);
+
        if (dev_priv->lid_notifier.notifier_call)
                acpi_lid_notifier_unregister(&dev_priv->lid_notifier);
        drm_sysfs_connector_remove(connector);
@@ -688,6 +660,14 @@ static const struct dmi_system_id intel_no_lvds[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "Studio Hybrid 140g"),
                },
        },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "Dell OptiPlex FX170",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex FX170"),
+               },
+       },
        {
                .callback = intel_no_lvds_dmi_callback,
                .ident = "AOpen Mini PC",
@@ -1032,6 +1012,19 @@ out:
                pwm = I915_READ(BLC_PWM_PCH_CTL1);
                pwm |= PWM_PCH_ENABLE;
                I915_WRITE(BLC_PWM_PCH_CTL1, pwm);
+               /*
+                * Unlock registers and just
+                * leave them unlocked
+                */
+               I915_WRITE(PCH_PP_CONTROL,
+                          I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS);
+       } else {
+               /*
+                * Unlock registers and just
+                * leave them unlocked
+                */
+               I915_WRITE(PP_CONTROL,
+                          I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
        }
        dev_priv->lid_notifier.notifier_call = intel_lid_notify;
        if (acpi_lid_notifier_register(&dev_priv->lid_notifier)) {
@@ -1041,6 +1034,9 @@ out:
        /* keep the LVDS connector */
        dev_priv->int_lvds_connector = connector;
        drm_sysfs_connector_add(connector);
+
+       intel_panel_setup_backlight(dev);
+
        return true;
 
 failed:
index b7c5ddb..b8e8158 100644 (file)
@@ -227,7 +227,6 @@ void intel_opregion_asle_intr(struct drm_device *dev)
        asle->aslc = asle_stat;
 }
 
-/* Only present on Ironlake+ */
 void intel_opregion_gse_intr(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
index a06ff07..a9e0c7b 100644 (file)
@@ -83,11 +83,15 @@ intel_pch_panel_fitting(struct drm_device *dev,
                        u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay;
                        if (scaled_width > scaled_height) { /* pillar */
                                width = scaled_height / mode->vdisplay;
+                               if (width & 1)
+                                       width++;
                                x = (adjusted_mode->hdisplay - width + 1) / 2;
                                y = 0;
                                height = adjusted_mode->vdisplay;
                        } else if (scaled_width < scaled_height) { /* letter */
                                height = scaled_width / mode->hdisplay;
+                               if (height & 1)
+                                   height++;
                                y = (adjusted_mode->vdisplay - height + 1) / 2;
                                x = 0;
                                width = adjusted_mode->hdisplay;
@@ -273,7 +277,7 @@ void intel_panel_enable_backlight(struct drm_device *dev)
        dev_priv->backlight_enabled = true;
 }
 
-void intel_panel_setup_backlight(struct drm_device *dev)
+static void intel_panel_init_backlight(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
@@ -305,3 +309,73 @@ intel_panel_detect(struct drm_device *dev)
 
        return connector_status_unknown;
 }
+
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+static int intel_panel_update_status(struct backlight_device *bd)
+{
+       struct drm_device *dev = bl_get_data(bd);
+       intel_panel_set_backlight(dev, bd->props.brightness);
+       return 0;
+}
+
+static int intel_panel_get_brightness(struct backlight_device *bd)
+{
+       struct drm_device *dev = bl_get_data(bd);
+       return intel_panel_get_backlight(dev);
+}
+
+static const struct backlight_ops intel_panel_bl_ops = {
+       .update_status = intel_panel_update_status,
+       .get_brightness = intel_panel_get_brightness,
+};
+
+int intel_panel_setup_backlight(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct backlight_properties props;
+       struct drm_connector *connector;
+
+       intel_panel_init_backlight(dev);
+
+       if (dev_priv->int_lvds_connector)
+               connector = dev_priv->int_lvds_connector;
+       else if (dev_priv->int_edp_connector)
+               connector = dev_priv->int_edp_connector;
+       else
+               return -ENODEV;
+
+       props.type = BACKLIGHT_RAW;
+       props.max_brightness = intel_panel_get_max_backlight(dev);
+       dev_priv->backlight =
+               backlight_device_register("intel_backlight",
+                                         &connector->kdev, dev,
+                                         &intel_panel_bl_ops, &props);
+
+       if (IS_ERR(dev_priv->backlight)) {
+               DRM_ERROR("Failed to register backlight: %ld\n",
+                         PTR_ERR(dev_priv->backlight));
+               dev_priv->backlight = NULL;
+               return -ENODEV;
+       }
+       dev_priv->backlight->props.brightness = intel_panel_get_backlight(dev);
+       return 0;
+}
+
+void intel_panel_destroy_backlight(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       if (dev_priv->backlight)
+               backlight_device_unregister(dev_priv->backlight);
+}
+#else
+int intel_panel_setup_backlight(struct drm_device *dev)
+{
+       intel_panel_init_backlight(dev);
+       return 0;
+}
+
+void intel_panel_destroy_backlight(struct drm_device *dev)
+{
+       return;
+}
+#endif
index e961568..c30626e 100644 (file)
@@ -290,6 +290,10 @@ static int init_render_ring(struct intel_ring_buffer *ring)
                if (IS_GEN6(dev) || IS_GEN7(dev))
                        mode |= MI_FLUSH_ENABLE << 16 | MI_FLUSH_ENABLE;
                I915_WRITE(MI_MODE, mode);
+               if (IS_GEN7(dev))
+                       I915_WRITE(GFX_MODE_GEN7,
+                                  GFX_MODE_DISABLE(GFX_TLB_INVALIDATE_ALWAYS) |
+                                  GFX_MODE_ENABLE(GFX_REPLAY_MODE));
        }
 
        if (INTEL_INFO(dev)->gen >= 6) {
@@ -1321,6 +1325,9 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size)
                ring->get_seqno = pc_render_get_seqno;
        }
 
+       if (!I915_NEED_GFX_HWS(dev))
+               ring->status_page.page_addr = dev_priv->status_page_dmah->vaddr;
+
        ring->dev = dev;
        INIT_LIST_HEAD(&ring->active_list);
        INIT_LIST_HEAD(&ring->request_list);
index 3896ef8..9f363e0 100644 (file)
@@ -5,6 +5,7 @@
 ccflags-y := -Iinclude/drm
 
 hostprogs-y := mkregtable
+clean-files := rn50_reg_safe.h r100_reg_safe.h r200_reg_safe.h rv515_reg_safe.h r300_reg_safe.h r420_reg_safe.h rs600_reg_safe.h r600_reg_safe.h evergreen_reg_safe.h cayman_reg_safe.h
 
 quiet_cmd_mkregtable = MKREGTABLE $@
       cmd_mkregtable = $(obj)/mkregtable $< > $@
index ebdb0fd..e88c644 100644 (file)
@@ -1245,6 +1245,9 @@ struct atom_context *atom_parse(struct card_info *card, void *bios)
        char name[512];
        int i;
 
+       if (!ctx)
+               return NULL;
+
        ctx->card = card;
        ctx->bios = bios;
 
index 645b84b..7ad43c6 100644 (file)
@@ -613,6 +613,18 @@ static bool radeon_dp_get_link_status(struct radeon_connector *radeon_connector,
        return true;
 }
 
+bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector)
+{
+       u8 link_status[DP_LINK_STATUS_SIZE];
+       struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
+
+       if (!radeon_dp_get_link_status(radeon_connector, link_status))
+               return false;
+       if (dp_channel_eq_ok(link_status, dig->dp_lane_count))
+               return false;
+       return true;
+}
+
 struct radeon_dp_link_train_info {
        struct radeon_device *rdev;
        struct drm_encoder *encoder;
index 14dce9f..fb5fa08 100644 (file)
@@ -743,7 +743,7 @@ static void evergreen_program_watermarks(struct radeon_device *rdev,
                    !evergreen_average_bandwidth_vs_available_bandwidth(&wm) ||
                    !evergreen_check_latency_hiding(&wm) ||
                    (rdev->disp_priority == 2)) {
-                       DRM_INFO("force priority to high\n");
+                       DRM_DEBUG_KMS("force priority to high\n");
                        priority_a_cnt |= PRIORITY_ALWAYS_ON;
                        priority_b_cnt |= PRIORITY_ALWAYS_ON;
                }
index 189e865..a134790 100644 (file)
@@ -428,7 +428,7 @@ static inline int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u3
                last_reg = ARRAY_SIZE(evergreen_reg_safe_bm);
 
        i = (reg >> 7);
-       if (i > last_reg) {
+       if (i >= last_reg) {
                dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx);
                return -EINVAL;
        }
index db8ef19..cf83aa0 100644 (file)
@@ -915,12 +915,11 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx
 {
        struct r600_cs_track *track = (struct r600_cs_track *)p->track;
        struct radeon_cs_reloc *reloc;
-       u32 last_reg = ARRAY_SIZE(r600_reg_safe_bm);
        u32 m, i, tmp, *ib;
        int r;
 
        i = (reg >> 7);
-       if (i > last_reg) {
+       if (i >= ARRAY_SIZE(r600_reg_safe_bm)) {
                dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx);
                return -EINVAL;
        }
index a74217c..e0138b6 100644 (file)
@@ -2557,6 +2557,7 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev)
        u16 offset, misc, misc2 = 0;
        u8 rev, blocks, tmp;
        int state_index = 0;
+       struct radeon_i2c_bus_rec i2c_bus;
 
        rdev->pm.default_power_state_index = -1;
 
@@ -2575,7 +2576,6 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev)
        offset = combios_get_table_offset(dev, COMBIOS_OVERDRIVE_INFO_TABLE);
        if (offset) {
                u8 thermal_controller = 0, gpio = 0, i2c_addr = 0, clk_bit = 0, data_bit = 0;
-               struct radeon_i2c_bus_rec i2c_bus;
 
                rev = RBIOS8(offset);
 
@@ -2617,6 +2617,25 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev)
                                i2c_new_device(&rdev->pm.i2c_bus->adapter, &info);
                        }
                }
+       } else {
+               /* boards with a thermal chip, but no overdrive table */
+
+               /* Asus 9600xt has an f75375 on the monid bus */
+               if ((dev->pdev->device == 0x4152) &&
+                   (dev->pdev->subsystem_vendor == 0x1043) &&
+                   (dev->pdev->subsystem_device == 0xc002)) {
+                       i2c_bus = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0);
+                       rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
+                       if (rdev->pm.i2c_bus) {
+                               struct i2c_board_info info = { };
+                               const char *name = "f75375";
+                               info.addr = 0x28;
+                               strlcpy(info.type, name, sizeof(info.type));
+                               i2c_new_device(&rdev->pm.i2c_bus->adapter, &info);
+                               DRM_INFO("Possible %s thermal controller at 0x%02x\n",
+                                        name, info.addr);
+                       }
+               }
        }
 
        if (rdev->flags & RADEON_IS_MOBILITY) {
index 9792d4f..4f0c1ec 100644 (file)
@@ -60,18 +60,20 @@ void radeon_connector_hotplug(struct drm_connector *connector)
 
        radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
 
-       /* powering up/down the eDP panel generates hpd events which
-        * can interfere with modesetting.
-        */
-       if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)
+       /* if the connector is already off, don't turn it back on */
+       if (connector->dpms != DRM_MODE_DPMS_ON)
                return;
 
-       /* pre-r600 did not always have the hpd pins mapped accurately to connectors */
-       if (rdev->family >= CHIP_R600) {
-               if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd))
+       /* just deal with DP (not eDP) here. */
+       if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
+               int saved_dpms = connector->dpms;
+
+               if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd) &&
+                   radeon_dp_needs_link_train(radeon_connector))
                        drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
                else
                        drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+               connector->dpms = saved_dpms;
        }
 }
 
@@ -430,16 +432,73 @@ int radeon_connector_set_property(struct drm_connector *connector, struct drm_pr
        return 0;
 }
 
+/*
+ * Some integrated ATI Radeon chipset implementations (e. g.
+ * Asus M2A-VM HDMI) may indicate the availability of a DDC,
+ * even when there's no monitor connected. For these connectors
+ * following DDC probe extension will be applied: check also for the
+ * availability of EDID with at least a correct EDID header. Only then,
+ * DDC is assumed to be available. This prevents drm_get_edid() and
+ * drm_edid_block_valid() from periodically dumping data and kernel
+ * errors into the logs and onto the terminal.
+ */
+static bool radeon_connector_needs_extended_probe(struct radeon_device *dev,
+                                    uint32_t supported_device,
+                                    int connector_type)
+{
+       /* Asus M2A-VM HDMI board sends data to i2c bus even,
+        * if HDMI add-on card is not plugged in or HDMI is disabled in
+        * BIOS. Valid DDC can only be assumed, if also a valid EDID header
+        * can be retrieved via i2c bus during DDC probe */
+       if ((dev->pdev->device == 0x791e) &&
+           (dev->pdev->subsystem_vendor == 0x1043) &&
+           (dev->pdev->subsystem_device == 0x826d)) {
+               if ((connector_type == DRM_MODE_CONNECTOR_HDMIA) &&
+                   (supported_device == ATOM_DEVICE_DFP2_SUPPORT))
+                       return true;
+       }
+       /* ECS A740GM-M with ATI RADEON 2100 sends data to i2c bus
+        * for a DVI connector that is not implemented */
+       if ((dev->pdev->device == 0x796e) &&
+           (dev->pdev->subsystem_vendor == 0x1019) &&
+           (dev->pdev->subsystem_device == 0x2615)) {
+               if ((connector_type == DRM_MODE_CONNECTOR_DVID) &&
+                   (supported_device == ATOM_DEVICE_DFP2_SUPPORT))
+                       return true;
+       }
+       /* TOSHIBA Satellite L300D with ATI Mobility Radeon x1100
+        * (RS690M) sends data to i2c bus for a HDMI connector that
+        * is not implemented */
+       if ((dev->pdev->device == 0x791f) &&
+           (dev->pdev->subsystem_vendor == 0x1179) &&
+           (dev->pdev->subsystem_device == 0xff68)) {
+               if ((connector_type == DRM_MODE_CONNECTOR_HDMIA) &&
+                   (supported_device == ATOM_DEVICE_DFP2_SUPPORT))
+                       return true;
+       }
+
+       /* Default: no EDID header probe required for DDC probing */
+       return false;
+}
+
 static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder,
                                          struct drm_connector *connector)
 {
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
+       struct drm_display_mode *t, *mode;
+
+       /* If the EDID preferred mode doesn't match the native mode, use it */
+       list_for_each_entry_safe(mode, t, &connector->probed_modes, head) {
+               if (mode->type & DRM_MODE_TYPE_PREFERRED) {
+                       if (mode->hdisplay != native_mode->hdisplay ||
+                           mode->vdisplay != native_mode->vdisplay)
+                               memcpy(native_mode, mode, sizeof(*mode));
+               }
+       }
 
        /* Try to get native mode details from EDID if necessary */
        if (!native_mode->clock) {
-               struct drm_display_mode *t, *mode;
-
                list_for_each_entry_safe(mode, t, &connector->probed_modes, head) {
                        if (mode->hdisplay == native_mode->hdisplay &&
                            mode->vdisplay == native_mode->vdisplay) {
@@ -450,6 +509,7 @@ static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder,
                        }
                }
        }
+
        if (!native_mode->clock) {
                DRM_DEBUG_KMS("No LVDS native mode details, disabling RMX\n");
                radeon_encoder->rmx_type = RMX_OFF;
@@ -661,7 +721,8 @@ radeon_vga_detect(struct drm_connector *connector, bool force)
                ret = connector_status_disconnected;
 
        if (radeon_connector->ddc_bus)
-               dret = radeon_ddc_probe(radeon_connector);
+               dret = radeon_ddc_probe(radeon_connector,
+                                       radeon_connector->requires_extended_probe);
        if (dret) {
                if (radeon_connector->edid) {
                        kfree(radeon_connector->edid);
@@ -833,7 +894,8 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
        bool dret = false;
 
        if (radeon_connector->ddc_bus)
-               dret = radeon_ddc_probe(radeon_connector);
+               dret = radeon_ddc_probe(radeon_connector,
+                                       radeon_connector->requires_extended_probe);
        if (dret) {
                if (radeon_connector->edid) {
                        kfree(radeon_connector->edid);
@@ -1251,7 +1313,8 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
                                if (radeon_dp_getdpcd(radeon_connector))
                                        ret = connector_status_connected;
                        } else {
-                               if (radeon_ddc_probe(radeon_connector))
+                               if (radeon_ddc_probe(radeon_connector,
+                                                    radeon_connector->requires_extended_probe))
                                        ret = connector_status_connected;
                        }
                }
@@ -1406,6 +1469,9 @@ radeon_add_atom_connector(struct drm_device *dev,
        radeon_connector->shared_ddc = shared_ddc;
        radeon_connector->connector_object_id = connector_object_id;
        radeon_connector->hpd = *hpd;
+       radeon_connector->requires_extended_probe =
+               radeon_connector_needs_extended_probe(rdev, supported_device,
+                                                       connector_type);
        radeon_connector->router = *router;
        if (router->ddc_valid || router->cd_valid) {
                radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info);
@@ -1752,6 +1818,9 @@ radeon_add_legacy_connector(struct drm_device *dev,
        radeon_connector->devices = supported_device;
        radeon_connector->connector_object_id = connector_object_id;
        radeon_connector->hpd = *hpd;
+       radeon_connector->requires_extended_probe =
+               radeon_connector_needs_extended_probe(rdev, supported_device,
+                                                       connector_type);
        switch (connector_type) {
        case DRM_MODE_CONNECTOR_VGA:
                drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
index 7cfaa7e..b51e157 100644 (file)
@@ -32,6 +32,7 @@
 #include <drm/radeon_drm.h>
 #include <linux/vgaarb.h>
 #include <linux/vga_switcheroo.h>
+#include <linux/efi.h>
 #include "radeon_reg.h"
 #include "radeon.h"
 #include "atom.h"
@@ -300,6 +301,8 @@ void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64
                mc->mc_vram_size = mc->aper_size;
        }
        mc->vram_end = mc->vram_start + mc->mc_vram_size - 1;
+       if (radeon_vram_limit && radeon_vram_limit < mc->real_vram_size)
+               mc->real_vram_size = radeon_vram_limit;
        dev_info(rdev->dev, "VRAM: %lluM 0x%016llX - 0x%016llX (%lluM used)\n",
                        mc->mc_vram_size >> 20, mc->vram_start,
                        mc->vram_end, mc->real_vram_size >> 20);
@@ -348,6 +351,9 @@ bool radeon_card_posted(struct radeon_device *rdev)
 {
        uint32_t reg;
 
+       if (efi_enabled && rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE)
+               return false;
+
        /* first check CRTCs */
        if (ASIC_IS_DCE41(rdev)) {
                reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) |
@@ -704,8 +710,9 @@ int radeon_device_init(struct radeon_device *rdev,
        rdev->gpu_lockup = false;
        rdev->accel_working = false;
 
-       DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X).\n",
-               radeon_family_name[rdev->family], pdev->vendor, pdev->device);
+       DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X 0x%04X:0x%04X).\n",
+               radeon_family_name[rdev->family], pdev->vendor, pdev->device,
+               pdev->subsystem_vendor, pdev->subsystem_device);
 
        /* mutex initialization are all done here so we
         * can recall function without having locking issues */
index 28f4655..1a85894 100644 (file)
@@ -751,8 +751,17 @@ static int radeon_ddc_dump(struct drm_connector *connector)
        if (!radeon_connector->ddc_bus)
                return -1;
        edid = drm_get_edid(connector, &radeon_connector->ddc_bus->adapter);
+       /* Log EDID retrieval status here. In particular with regard to
+        * connectors with requires_extended_probe flag set, that will prevent
+        * function radeon_dvi_detect() to fetch EDID on this connector,
+        * as long as there is no valid EDID header found */
        if (edid) {
+               DRM_INFO("Radeon display connector %s: Found valid EDID",
+                               drm_get_connector_name(connector));
                kfree(edid);
+       } else {
+               DRM_INFO("Radeon display connector %s: No monitor connected or invalid EDID",
+                               drm_get_connector_name(connector));
        }
        return ret;
 }
index 85f033f..e71d2ed 100644 (file)
@@ -50,8 +50,8 @@
  *   2.7.0 - fixups for r600 2D tiling support. (no external ABI change), add eg dyn gpr regs
  *   2.8.0 - pageflip support, r500 US_FORMAT regs. r500 ARGB2101010 colorbuf, r300->r500 CMASK, clock crystal query
  *   2.9.0 - r600 tiling (s3tc,rgtc) working, SET_PREDICATION packet 3 on r600 + eg, backend query
- *   2.10.0 - fusion 2D tiling, initial compute support for the CS checker
- *   2.11.0 - backend map
+ *   2.10.0 - fusion 2D tiling
+ *   2.11.0 - backend map, initial compute support for the CS checker
  */
 #define KMS_DRIVER_MAJOR       2
 #define KMS_DRIVER_MINOR       11
index b293487..319d85d 100644 (file)
@@ -2323,6 +2323,9 @@ radeon_add_atom_encoder(struct drm_device *dev,
        default:
                encoder->possible_crtcs = 0x3;
                break;
+       case 4:
+               encoder->possible_crtcs = 0xf;
+               break;
        case 6:
                encoder->possible_crtcs = 0x3f;
                break;
index 781196d..6c111c1 100644 (file)
  * radeon_ddc_probe
  *
  */
-bool radeon_ddc_probe(struct radeon_connector *radeon_connector)
+bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool requires_extended_probe)
 {
-       u8 out_buf[] = { 0x0, 0x0};
-       u8 buf[2];
+       u8 out = 0x0;
+       u8 buf[8];
        int ret;
        struct i2c_msg msgs[] = {
                {
                        .addr = 0x50,
                        .flags = 0,
                        .len = 1,
-                       .buf = out_buf,
+                       .buf = &out,
                },
                {
                        .addr = 0x50,
@@ -52,15 +52,31 @@ bool radeon_ddc_probe(struct radeon_connector *radeon_connector)
                }
        };
 
+       /* Read 8 bytes from i2c for extended probe of EDID header */
+       if (requires_extended_probe)
+               msgs[1].len = 8;
+
        /* on hw with routers, select right port */
        if (radeon_connector->router.ddc_valid)
                radeon_router_select_ddc_port(radeon_connector);
 
        ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2);
-       if (ret == 2)
-               return true;
-
-       return false;
+       if (ret != 2)
+               /* Couldn't find an accessible DDC on this connector */
+               return false;
+       if (requires_extended_probe) {
+               /* Probe also for valid EDID header
+                * EDID header starts with:
+                * 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00.
+                * Only the first 6 bytes must be valid as
+                * drm_edid_block_valid() can fix the last 2 bytes */
+               if (drm_edid_header_is_valid(buf) < 6) {
+                       /* Couldn't find an accessible EDID on this
+                        * connector */
+                       return false;
+               }
+       }
+       return true;
 }
 
 /* bit banging i2c */
index 6df4e3c..68820f5 100644 (file)
@@ -438,6 +438,9 @@ struct radeon_connector {
        struct radeon_i2c_chan *ddc_bus;
        /* some systems have an hdmi and vga port with a shared ddc line */
        bool shared_ddc;
+       /* for some Radeon chip families we apply an additional EDID header
+          check as part of the DDC probe */
+       bool requires_extended_probe;
        bool use_digital;
        /* we need to mind the EDID between detect
           and get modes due to analog/digital/tvencoder */
@@ -476,6 +479,7 @@ extern void radeon_dp_set_link_config(struct drm_connector *connector,
                                      struct drm_display_mode *mode);
 extern void radeon_dp_link_train(struct drm_encoder *encoder,
                                 struct drm_connector *connector);
+extern bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector);
 extern u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector);
 extern bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector);
 extern void atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode);
@@ -514,7 +518,8 @@ extern void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c,
                                u8 val);
 extern void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector);
 extern void radeon_router_select_cd_port(struct radeon_connector *radeon_connector);
-extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector);
+extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector,
+                       bool requires_extended_probe);
 extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector);
 
 extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector);
index dee4a0c..602fa35 100644 (file)
@@ -40,10 +40,14 @@ void radeon_test_moves(struct radeon_device *rdev)
        size = 1024 * 1024;
 
        /* Number of tests =
-        * (Total GTT - IB pool - writeback page - ring buffer) / test size
+        * (Total GTT - IB pool - writeback page - ring buffers) / test size
         */
-       n = ((u32)(rdev->mc.gtt_size - RADEON_IB_POOL_SIZE*64*1024 - RADEON_GPU_PAGE_SIZE -
-            rdev->cp.ring_size)) / size;
+       n = rdev->mc.gtt_size - RADEON_IB_POOL_SIZE*64*1024 - rdev->cp.ring_size;
+       if (rdev->wb.wb_obj)
+               n -= RADEON_GPU_PAGE_SIZE;
+       if (rdev->ih.ring_obj)
+               n -= rdev->ih.ring_size;
+       n /= size;
 
        gtt_obj = kzalloc(n * sizeof(*gtt_obj), GFP_KERNEL);
        if (!gtt_obj) {
@@ -132,9 +136,15 @@ void radeon_test_moves(struct radeon_device *rdev)
                     gtt_start++, vram_start++) {
                        if (*vram_start != gtt_start) {
                                DRM_ERROR("Incorrect GTT->VRAM copy %d: Got 0x%p, "
-                                         "expected 0x%p (GTT map 0x%p-0x%p)\n",
-                                         i, *vram_start, gtt_start, gtt_map,
-                                         gtt_end);
+                                         "expected 0x%p (GTT/VRAM offset "
+                                         "0x%16llx/0x%16llx)\n",
+                                         i, *vram_start, gtt_start,
+                                         (unsigned long long)
+                                         (gtt_addr - rdev->mc.gtt_start +
+                                          (void*)gtt_start - gtt_map),
+                                         (unsigned long long)
+                                         (vram_addr - rdev->mc.vram_start +
+                                          (void*)gtt_start - gtt_map));
                                radeon_bo_kunmap(vram_obj);
                                goto out_cleanup;
                        }
@@ -175,9 +185,15 @@ void radeon_test_moves(struct radeon_device *rdev)
                     gtt_start++, vram_start++) {
                        if (*gtt_start != vram_start) {
                                DRM_ERROR("Incorrect VRAM->GTT copy %d: Got 0x%p, "
-                                         "expected 0x%p (VRAM map 0x%p-0x%p)\n",
-                                         i, *gtt_start, vram_start, vram_map,
-                                         vram_end);
+                                         "expected 0x%p (VRAM/GTT offset "
+                                         "0x%16llx/0x%16llx)\n",
+                                         i, *gtt_start, vram_start,
+                                         (unsigned long long)
+                                         (vram_addr - rdev->mc.vram_start +
+                                          (void*)vram_start - vram_map),
+                                         (unsigned long long)
+                                         (gtt_addr - rdev->mc.gtt_start +
+                                          (void*)vram_start - vram_map));
                                radeon_bo_kunmap(gtt_obj[i]);
                                goto out_cleanup;
                        }
index 60125dd..9b86fb0 100644 (file)
@@ -450,6 +450,29 @@ static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_
                        return -EINVAL;
                mem->bus.base = rdev->mc.aper_base;
                mem->bus.is_iomem = true;
+#ifdef __alpha__
+               /*
+                * Alpha: use bus.addr to hold the ioremap() return,
+                * so we can modify bus.base below.
+                */
+               if (mem->placement & TTM_PL_FLAG_WC)
+                       mem->bus.addr =
+                               ioremap_wc(mem->bus.base + mem->bus.offset,
+                                          mem->bus.size);
+               else
+                       mem->bus.addr =
+                               ioremap_nocache(mem->bus.base + mem->bus.offset,
+                                               mem->bus.size);
+
+               /*
+                * Alpha: Use just the bus offset plus
+                * the hose/domain memory base for bus.base.
+                * It then can be used to build PTEs for VRAM
+                * access, as done in ttm_bo_vm_fault().
+                */
+               mem->bus.base = (mem->bus.base & 0x0ffffffffUL) +
+                       rdev->ddev->hose->dense_mem_base;
+#endif
                break;
        default:
                return -EINVAL;
index 56619f6..a4d38d8 100644 (file)
@@ -353,8 +353,10 @@ static int ttm_bo_add_ttm(struct ttm_buffer_object *bo, bool zero_alloc)
 
                ret = ttm_tt_set_user(bo->ttm, current,
                                      bo->buffer_start, bo->num_pages);
-               if (unlikely(ret != 0))
+               if (unlikely(ret != 0)) {
                        ttm_tt_destroy(bo->ttm);
+                       bo->ttm = NULL;
+               }
                break;
        default:
                printk(KERN_ERR TTM_PFX "Illegal buffer object type\n");
@@ -390,10 +392,12 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
         * Create and bind a ttm if required.
         */
 
-       if (!(new_man->flags & TTM_MEMTYPE_FLAG_FIXED) && (bo->ttm == NULL)) {
-               ret = ttm_bo_add_ttm(bo, false);
-               if (ret)
-                       goto out_err;
+       if (!(new_man->flags & TTM_MEMTYPE_FLAG_FIXED)) {
+               if (bo->ttm == NULL) {
+                       ret = ttm_bo_add_ttm(bo, false);
+                       if (ret)
+                               goto out_err;
+               }
 
                ret = ttm_tt_set_placement_caching(bo->ttm, mem->placement);
                if (ret)
index 77dbf40..ae3c6f5 100644 (file)
@@ -635,13 +635,13 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
                if (ret)
                        return ret;
 
-               ttm_bo_free_old_node(bo);
                if ((man->flags & TTM_MEMTYPE_FLAG_FIXED) &&
                    (bo->ttm != NULL)) {
                        ttm_tt_unbind(bo->ttm);
                        ttm_tt_destroy(bo->ttm);
                        bo->ttm = NULL;
                }
+               ttm_bo_free_old_node(bo);
        } else {
                /**
                 * This should help pipeline ordinary buffer moves.
index 306b15f..1130a89 100644 (file)
@@ -589,6 +589,7 @@ config HID_WACOM_POWER_SUPPLY
 config HID_WIIMOTE
        tristate "Nintendo Wii Remote support"
        depends on BT_HIDP
+       depends on LEDS_CLASS
        ---help---
        Support for the Nintendo Wii Remote bluetooth device.
 
index b85744f..18b3bc6 100644 (file)
@@ -444,6 +444,12 @@ static const struct hid_device_id apple_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS),
                .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
                        APPLE_RDESC_JIS },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI),
+               .driver_data = APPLE_HAS_FN },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ISO),
+               .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_JIS),
+               .driver_data = APPLE_HAS_FN },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI),
                .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO),
index 1a5cf0c..242353d 100644 (file)
@@ -1340,6 +1340,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_JIS) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
index db63ccf..7d27d2b 100644 (file)
 #define USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI   0x0245
 #define USB_DEVICE_ID_APPLE_WELLSPRING5_ISO    0x0246
 #define USB_DEVICE_ID_APPLE_WELLSPRING5_JIS    0x0247
+#define USB_DEVICE_ID_APPLE_ALU_REVB_ANSI      0x024f
+#define USB_DEVICE_ID_APPLE_ALU_REVB_ISO       0x0250
+#define USB_DEVICE_ID_APPLE_ALU_REVB_JIS       0x0251
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI  0x0239
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO   0x023a
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS   0x023b
 #define USB_DEVICE_ID_SAMSUNG_IR_REMOTE        0x0001
 #define USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE       0x0600
 
+#define USB_VENDOR_ID_SIGMA_MICRO      0x1c4f
+#define USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD     0x0002
+
 #define USB_VENDOR_ID_SKYCABLE                 0x1223
 #define        USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER       0x3F07
 
index a594383..85a02e5 100644 (file)
  * any later version.
  */
 
-#include <linux/atomic.h>
 #include <linux/device.h>
 #include <linux/hid.h>
 #include <linux/input.h>
+#include <linux/leds.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include "hid-ids.h"
@@ -33,9 +33,9 @@ struct wiimote_state {
 };
 
 struct wiimote_data {
-       atomic_t ready;
        struct hid_device *hdev;
        struct input_dev *input;
+       struct led_classdev *leds[4];
 
        spinlock_t qlock;
        __u8 head;
@@ -53,8 +53,15 @@ struct wiimote_data {
 #define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \
                                        WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4)
 
+/* return flag for led \num */
+#define WIIPROTO_FLAG_LED(num) (WIIPROTO_FLAG_LED1 << (num - 1))
+
 enum wiiproto_reqs {
+       WIIPROTO_REQ_NULL = 0x0,
        WIIPROTO_REQ_LED = 0x11,
+       WIIPROTO_REQ_DRM = 0x12,
+       WIIPROTO_REQ_STATUS = 0x20,
+       WIIPROTO_REQ_RETURN = 0x22,
        WIIPROTO_REQ_DRM_K = 0x30,
 };
 
@@ -87,9 +94,6 @@ static __u16 wiiproto_keymap[] = {
        BTN_MODE,       /* WIIPROTO_KEY_HOME */
 };
 
-#define dev_to_wii(pdev) hid_get_drvdata(container_of(pdev, struct hid_device, \
-                                                                       dev))
-
 static ssize_t wiimote_hid_send(struct hid_device *hdev, __u8 *buffer,
                                                                size_t count)
 {
@@ -192,66 +196,96 @@ static void wiiproto_req_leds(struct wiimote_data *wdata, int leds)
        wiimote_queue(wdata, cmd, sizeof(cmd));
 }
 
-#define wiifs_led_show_set(num)                                                \
-static ssize_t wiifs_led_show_##num(struct device *dev,                        \
-                       struct device_attribute *attr, char *buf)       \
-{                                                                      \
-       struct wiimote_data *wdata = dev_to_wii(dev);                   \
-       unsigned long flags;                                            \
-       int state;                                                      \
-                                                                       \
-       if (!atomic_read(&wdata->ready))                                \
-               return -EBUSY;                                          \
-                                                                       \
-       spin_lock_irqsave(&wdata->state.lock, flags);                   \
-       state = !!(wdata->state.flags & WIIPROTO_FLAG_LED##num);        \
-       spin_unlock_irqrestore(&wdata->state.lock, flags);              \
-                                                                       \
-       return sprintf(buf, "%d\n", state);                             \
-}                                                                      \
-static ssize_t wiifs_led_set_##num(struct device *dev,                 \
-       struct device_attribute *attr, const char *buf, size_t count)   \
-{                                                                      \
-       struct wiimote_data *wdata = dev_to_wii(dev);                   \
-       int tmp = simple_strtoul(buf, NULL, 10);                        \
-       unsigned long flags;                                            \
-       __u8 state;                                                     \
-                                                                       \
-       if (!atomic_read(&wdata->ready))                                \
-               return -EBUSY;                                          \
-                                                                       \
-       spin_lock_irqsave(&wdata->state.lock, flags);                   \
-                                                                       \
-       state = wdata->state.flags;                                     \
-                                                                       \
-       if (tmp)                                                        \
-               wiiproto_req_leds(wdata, state | WIIPROTO_FLAG_LED##num);\
-       else                                                            \
-               wiiproto_req_leds(wdata, state & ~WIIPROTO_FLAG_LED##num);\
-                                                                       \
-       spin_unlock_irqrestore(&wdata->state.lock, flags);              \
-                                                                       \
-       return count;                                                   \
-}                                                                      \
-static DEVICE_ATTR(led##num, S_IRUGO | S_IWUSR, wiifs_led_show_##num,  \
-                                               wiifs_led_set_##num)
-
-wiifs_led_show_set(1);
-wiifs_led_show_set(2);
-wiifs_led_show_set(3);
-wiifs_led_show_set(4);
+/*
+ * Check what peripherals of the wiimote are currently
+ * active and select a proper DRM that supports all of
+ * the requested data inputs.
+ */
+static __u8 select_drm(struct wiimote_data *wdata)
+{
+       return WIIPROTO_REQ_DRM_K;
+}
+
+static void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm)
+{
+       __u8 cmd[3];
+
+       if (drm == WIIPROTO_REQ_NULL)
+               drm = select_drm(wdata);
+
+       cmd[0] = WIIPROTO_REQ_DRM;
+       cmd[1] = 0;
+       cmd[2] = drm;
+
+       wiimote_queue(wdata, cmd, sizeof(cmd));
+}
+
+static enum led_brightness wiimote_leds_get(struct led_classdev *led_dev)
+{
+       struct wiimote_data *wdata;
+       struct device *dev = led_dev->dev->parent;
+       int i;
+       unsigned long flags;
+       bool value = false;
+
+       wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
+
+       for (i = 0; i < 4; ++i) {
+               if (wdata->leds[i] == led_dev) {
+                       spin_lock_irqsave(&wdata->state.lock, flags);
+                       value = wdata->state.flags & WIIPROTO_FLAG_LED(i + 1);
+                       spin_unlock_irqrestore(&wdata->state.lock, flags);
+                       break;
+               }
+       }
+
+       return value ? LED_FULL : LED_OFF;
+}
+
+static void wiimote_leds_set(struct led_classdev *led_dev,
+                                               enum led_brightness value)
+{
+       struct wiimote_data *wdata;
+       struct device *dev = led_dev->dev->parent;
+       int i;
+       unsigned long flags;
+       __u8 state, flag;
+
+       wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
+
+       for (i = 0; i < 4; ++i) {
+               if (wdata->leds[i] == led_dev) {
+                       flag = WIIPROTO_FLAG_LED(i + 1);
+                       spin_lock_irqsave(&wdata->state.lock, flags);
+                       state = wdata->state.flags;
+                       if (value == LED_OFF)
+                               wiiproto_req_leds(wdata, state & ~flag);
+                       else
+                               wiiproto_req_leds(wdata, state | flag);
+                       spin_unlock_irqrestore(&wdata->state.lock, flags);
+                       break;
+               }
+       }
+}
 
 static int wiimote_input_event(struct input_dev *dev, unsigned int type,
                                                unsigned int code, int value)
+{
+       return 0;
+}
+
+static int wiimote_input_open(struct input_dev *dev)
 {
        struct wiimote_data *wdata = input_get_drvdata(dev);
 
-       if (!atomic_read(&wdata->ready))
-               return -EBUSY;
-       /* smp_rmb: Make sure wdata->xy is available when wdata->ready is 1 */
-       smp_rmb();
+       return hid_hw_open(wdata->hdev);
+}
 
-       return 0;
+static void wiimote_input_close(struct input_dev *dev)
+{
+       struct wiimote_data *wdata = input_get_drvdata(dev);
+
+       hid_hw_close(wdata->hdev);
 }
 
 static void handler_keys(struct wiimote_data *wdata, const __u8 *payload)
@@ -281,6 +315,26 @@ static void handler_keys(struct wiimote_data *wdata, const __u8 *payload)
        input_sync(wdata->input);
 }
 
+static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
+{
+       handler_keys(wdata, payload);
+
+       /* on status reports the drm is reset so we need to resend the drm */
+       wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+}
+
+static void handler_return(struct wiimote_data *wdata, const __u8 *payload)
+{
+       __u8 err = payload[3];
+       __u8 cmd = payload[2];
+
+       handler_keys(wdata, payload);
+
+       if (err)
+               hid_warn(wdata->hdev, "Remote error %hhu on req %hhu\n", err,
+                                                                       cmd);
+}
+
 struct wiiproto_handler {
        __u8 id;
        size_t size;
@@ -288,6 +342,8 @@ struct wiiproto_handler {
 };
 
 static struct wiiproto_handler handlers[] = {
+       { .id = WIIPROTO_REQ_STATUS, .size = 6, .func = handler_status },
+       { .id = WIIPROTO_REQ_RETURN, .size = 4, .func = handler_return },
        { .id = WIIPROTO_REQ_DRM_K, .size = 2, .func = handler_keys },
        { .id = 0 }
 };
@@ -300,11 +356,6 @@ static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report,
        int i;
        unsigned long flags;
 
-       if (!atomic_read(&wdata->ready))
-               return -EBUSY;
-       /* smp_rmb: Make sure wdata->xy is available when wdata->ready is 1 */
-       smp_rmb();
-
        if (size < 1)
                return -EINVAL;
 
@@ -321,6 +372,58 @@ static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report,
        return 0;
 }
 
+static void wiimote_leds_destroy(struct wiimote_data *wdata)
+{
+       int i;
+       struct led_classdev *led;
+
+       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 wiimote_leds_create(struct wiimote_data *wdata)
+{
+       int i, ret;
+       struct device *dev = &wdata->hdev->dev;
+       size_t namesz = strlen(dev_name(dev)) + 9;
+       struct led_classdev *led;
+       char *name;
+
+       for (i = 0; i < 4; ++i) {
+               led = kzalloc(sizeof(struct led_classdev) + namesz, GFP_KERNEL);
+               if (!led) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+               name = (void*)&led[1];
+               snprintf(name, namesz, "%s:blue:p%d", dev_name(dev), i);
+               led->name = name;
+               led->brightness = 0;
+               led->max_brightness = 1;
+               led->brightness_get = wiimote_leds_get;
+               led->brightness_set = wiimote_leds_set;
+
+               ret = led_classdev_register(dev, led);
+               if (ret) {
+                       kfree(led);
+                       goto err;
+               }
+               wdata->leds[i] = led;
+       }
+
+       return 0;
+
+err:
+       wiimote_leds_destroy(wdata);
+       return ret;
+}
+
 static struct wiimote_data *wiimote_create(struct hid_device *hdev)
 {
        struct wiimote_data *wdata;
@@ -341,6 +444,8 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
 
        input_set_drvdata(wdata->input, wdata);
        wdata->input->event = wiimote_input_event;
+       wdata->input->open = wiimote_input_open;
+       wdata->input->close = wiimote_input_close;
        wdata->input->dev.parent = &wdata->hdev->dev;
        wdata->input->id.bustype = wdata->hdev->bus;
        wdata->input->id.vendor = wdata->hdev->vendor;
@@ -362,6 +467,12 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
 
 static void wiimote_destroy(struct wiimote_data *wdata)
 {
+       wiimote_leds_destroy(wdata);
+
+       input_unregister_device(wdata->input);
+       cancel_work_sync(&wdata->worker);
+       hid_hw_stop(wdata->hdev);
+
        kfree(wdata);
 }
 
@@ -377,19 +488,6 @@ static int wiimote_hid_probe(struct hid_device *hdev,
                return -ENOMEM;
        }
 
-       ret = device_create_file(&hdev->dev, &dev_attr_led1);
-       if (ret)
-               goto err;
-       ret = device_create_file(&hdev->dev, &dev_attr_led2);
-       if (ret)
-               goto err;
-       ret = device_create_file(&hdev->dev, &dev_attr_led3);
-       if (ret)
-               goto err;
-       ret = device_create_file(&hdev->dev, &dev_attr_led4);
-       if (ret)
-               goto err;
-
        ret = hid_parse(hdev);
        if (ret) {
                hid_err(hdev, "HID parse failed\n");
@@ -408,9 +506,10 @@ static int wiimote_hid_probe(struct hid_device *hdev,
                goto err_stop;
        }
 
-       /* smp_wmb: Write wdata->xy first before wdata->ready is set to 1 */
-       smp_wmb();
-       atomic_set(&wdata->ready, 1);
+       ret = wiimote_leds_create(wdata);
+       if (ret)
+               goto err_free;
+
        hid_info(hdev, "New device registered\n");
 
        /* by default set led1 after device initialization */
@@ -420,15 +519,15 @@ static int wiimote_hid_probe(struct hid_device *hdev,
 
        return 0;
 
+err_free:
+       wiimote_destroy(wdata);
+       return ret;
+
 err_stop:
        hid_hw_stop(hdev);
 err:
        input_free_device(wdata->input);
-       device_remove_file(&hdev->dev, &dev_attr_led1);
-       device_remove_file(&hdev->dev, &dev_attr_led2);
-       device_remove_file(&hdev->dev, &dev_attr_led3);
-       device_remove_file(&hdev->dev, &dev_attr_led4);
-       wiimote_destroy(wdata);
+       kfree(wdata);
        return ret;
 }
 
@@ -437,16 +536,6 @@ static void wiimote_hid_remove(struct hid_device *hdev)
        struct wiimote_data *wdata = hid_get_drvdata(hdev);
 
        hid_info(hdev, "Device removed\n");
-
-       device_remove_file(&hdev->dev, &dev_attr_led1);
-       device_remove_file(&hdev->dev, &dev_attr_led2);
-       device_remove_file(&hdev->dev, &dev_attr_led3);
-       device_remove_file(&hdev->dev, &dev_attr_led4);
-
-       hid_hw_stop(hdev);
-       input_unregister_device(wdata->input);
-
-       cancel_work_sync(&wdata->worker);
        wiimote_destroy(wdata);
 }
 
index 621959d..4bdb5d4 100644 (file)
@@ -89,6 +89,7 @@ static const struct hid_blacklist {
 
        { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS, HID_QUIRK_MULTI_INPUT },
+       { USB_VENDOR_ID_SIGMA_MICRO, USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD, HID_QUIRK_NO_INIT_REPORTS },
        { 0, 0 }
 };
 
index 0598cd2..0b62c3c 100644 (file)
@@ -623,7 +623,7 @@ config SENSORS_LM90
          LM86, LM89 and LM99, Analog Devices ADM1032, ADT7461, and ADT7461A,
          Maxim MAX6646, MAX6647, MAX6648, MAX6649, MAX6657, MAX6658, MAX6659,
          MAX6680, MAX6681, MAX6692, MAX6695, MAX6696, ON Semiconductor NCT1008,
-         and Winbond/Nuvoton W83L771W/G/AWG/ASG sensor chips.
+         Winbond/Nuvoton W83L771W/G/AWG/ASG and Philips SA56004 sensor chips.
 
          This driver can also be built as a module.  If so, the module
          will be called lm90.
@@ -694,14 +694,24 @@ config SENSORS_LTC4261
          be called ltc4261.
 
 config SENSORS_LM95241
-       tristate "National Semiconductor LM95241 sensor chip"
+       tristate "National Semiconductor LM95241 and compatibles"
        depends on I2C
        help
-         If you say yes here you get support for LM95241 sensor chip.
+         If you say yes here you get support for LM95231 and LM95241 sensor
+         chips.
 
          This driver can also be built as a module.  If so, the module
          will be called lm95241.
 
+config SENSORS_LM95245
+       tristate "National Semiconductor LM95245 sensor chip"
+       depends on I2C && EXPERIMENTAL
+       help
+         If you say yes here you get support for LM95245 sensor chip.
+
+         This driver can also be built as a module.  If so, the module
+         will be called lm95245.
+
 config SENSORS_MAX1111
        tristate "Maxim MAX1111 Multichannel, Serial 8-bit ADC chip"
        depends on SPI_MASTER
@@ -736,6 +746,16 @@ config SENSORS_MAX1619
          This driver can also be built as a module.  If so, the module
          will be called max1619.
 
+config SENSORS_MAX1668
+       tristate "Maxim MAX1668 and compatibles"
+       depends on I2C && EXPERIMENTAL
+       help
+         If you say yes here you get support for MAX1668, MAX1989 and
+         MAX1805 chips.
+
+         This driver can also be built as a module.  If so, the module
+         will be called max1668.
+
 config SENSORS_MAX6639
        tristate "Maxim MAX6639 sensor chip"
        depends on I2C && EXPERIMENTAL
@@ -767,6 +787,20 @@ config SENSORS_MAX6650
          This driver can also be built as a module.  If so, the module
          will be called max6650.
 
+config SENSORS_NTC_THERMISTOR
+       tristate "NTC thermistor support"
+       depends on EXPERIMENTAL
+       help
+         This driver supports NTC thermistors sensor reading and its
+         interpretation. The driver can also monitor the temperature and
+         send notifications about the temperature.
+
+         Currently, this driver supports
+         NCP15WB473, NCP18WB473, NCP21WB473, NCP03WB473, and NCP15WL333.
+
+         This driver can also be built as a module.  If so, the module
+         will be called ntc-thermistor.
+
 config SENSORS_PC87360
        tristate "National Semiconductor PC87360 family"
        select HWMON_VID
@@ -807,92 +841,7 @@ config SENSORS_PCF8591
          These devices are hard to detect and rarely found on mainstream
          hardware.  If unsure, say N.
 
-config PMBUS
-       tristate "PMBus support"
-       depends on I2C && EXPERIMENTAL
-       default n
-       help
-         Say yes here if you want to enable PMBus support.
-
-         This driver can also be built as a module. If so, the module will
-         be called pmbus_core.
-
-if PMBUS
-
-config SENSORS_PMBUS
-       tristate "Generic PMBus devices"
-       default n
-       help
-         If you say yes here you get hardware monitoring support for generic
-         PMBus devices, including but not limited to BMR450, BMR451, BMR453,
-         BMR454, and LTC2978.
-
-         This driver can also be built as a module. If so, the module will
-         be called pmbus.
-
-config SENSORS_ADM1275
-       tristate "Analog Devices ADM1275"
-       default n
-       help
-         If you say yes here you get hardware monitoring support for Analog
-         Devices ADM1275 Hot-Swap Controller and Digital Power Monitor.
-
-         This driver can also be built as a module. If so, the module will
-         be called adm1275.
-
-config SENSORS_MAX16064
-       tristate "Maxim MAX16064"
-       default n
-       help
-         If you say yes here you get hardware monitoring support for Maxim
-         MAX16064.
-
-         This driver can also be built as a module. If so, the module will
-         be called max16064.
-
-config SENSORS_MAX34440
-       tristate "Maxim MAX34440/MAX34441"
-       default n
-       help
-         If you say yes here you get hardware monitoring support for Maxim
-         MAX34440 and MAX34441.
-
-         This driver can also be built as a module. If so, the module will
-         be called max34440.
-
-config SENSORS_MAX8688
-       tristate "Maxim MAX8688"
-       default n
-       help
-         If you say yes here you get hardware monitoring support for Maxim
-         MAX8688.
-
-         This driver can also be built as a module. If so, the module will
-         be called max8688.
-
-config SENSORS_UCD9000
-       tristate "TI UCD90120, UCD90124, UCD9090, UCD90910"
-       default n
-       help
-         If you say yes here you get hardware monitoring support for TI
-         UCD90120, UCD90124, UCD9090, UCD90910 Sequencer and System Health
-         Controllers.
-
-         This driver can also be built as a module. If so, the module will
-         be called ucd9000.
-
-config SENSORS_UCD9200
-       tristate "TI UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, UCD9248"
-       default n
-       help
-         If you say yes here you get hardware monitoring support for TI
-         UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, and UCD9248
-         Digital PWM System Controllers.
-
-         This driver can also be built as a module. If so, the module will
-         be called ucd9200.
-
-endif # PMBUS
+source drivers/hwmon/pmbus/Kconfig
 
 config SENSORS_SHT15
        tristate "Sensiron humidity and temperature sensors. SHT15 and compat."
index d7995a1..3c9ccef 100644 (file)
@@ -80,6 +80,7 @@ obj-$(CONFIG_SENSORS_LM90)    += lm90.o
 obj-$(CONFIG_SENSORS_LM92)     += lm92.o
 obj-$(CONFIG_SENSORS_LM93)     += lm93.o
 obj-$(CONFIG_SENSORS_LM95241)  += lm95241.o
+obj-$(CONFIG_SENSORS_LM95245)  += lm95245.o
 obj-$(CONFIG_SENSORS_LTC4151)  += ltc4151.o
 obj-$(CONFIG_SENSORS_LTC4215)  += ltc4215.o
 obj-$(CONFIG_SENSORS_LTC4245)  += ltc4245.o
@@ -87,10 +88,12 @@ obj-$(CONFIG_SENSORS_LTC4261)       += ltc4261.o
 obj-$(CONFIG_SENSORS_MAX1111)  += max1111.o
 obj-$(CONFIG_SENSORS_MAX16065) += max16065.o
 obj-$(CONFIG_SENSORS_MAX1619)  += max1619.o
+obj-$(CONFIG_SENSORS_MAX1668)  += max1668.o
 obj-$(CONFIG_SENSORS_MAX6639)  += max6639.o
 obj-$(CONFIG_SENSORS_MAX6642)  += max6642.o
 obj-$(CONFIG_SENSORS_MAX6650)  += max6650.o
 obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
+obj-$(CONFIG_SENSORS_NTC_THERMISTOR)   += ntc_thermistor.o
 obj-$(CONFIG_SENSORS_PC87360)  += pc87360.o
 obj-$(CONFIG_SENSORS_PC87427)  += pc87427.o
 obj-$(CONFIG_SENSORS_PCF8591)  += pcf8591.o
@@ -121,15 +124,7 @@ obj-$(CONFIG_SENSORS_W83L786NG)    += w83l786ng.o
 obj-$(CONFIG_SENSORS_WM831X)   += wm831x-hwmon.o
 obj-$(CONFIG_SENSORS_WM8350)   += wm8350-hwmon.o
 
-# PMBus drivers
-obj-$(CONFIG_PMBUS)            += pmbus_core.o
-obj-$(CONFIG_SENSORS_PMBUS)    += pmbus.o
-obj-$(CONFIG_SENSORS_ADM1275)  += adm1275.o
-obj-$(CONFIG_SENSORS_MAX16064) += max16064.o
-obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
-obj-$(CONFIG_SENSORS_MAX8688)  += max8688.o
-obj-$(CONFIG_SENSORS_UCD9000)  += ucd9000.o
-obj-$(CONFIG_SENSORS_UCD9200)  += ucd9200.o
+obj-$(CONFIG_PMBUS)            += pmbus/
 
 ccflags-$(CONFIG_HWMON_DEBUG_CHIP) := -DDEBUG
 
index 0070d54..59d83e8 100644 (file)
@@ -44,7 +44,9 @@
 #define BASE_SYSFS_ATTR_NO     2       /* Sysfs Base attr no for coretemp */
 #define NUM_REAL_CORES         16      /* Number of Real cores per cpu */
 #define CORETEMP_NAME_LENGTH   17      /* String Length of attrs */
-#define MAX_ATTRS              5       /* Maximum no of per-core attrs */
+#define MAX_CORE_ATTRS         4       /* Maximum no of basic attrs */
+#define MAX_THRESH_ATTRS       3       /* Maximum no of Threshold attrs */
+#define TOTAL_ATTRS            (MAX_CORE_ATTRS + MAX_THRESH_ATTRS)
 #define MAX_CORE_DATA          (NUM_REAL_CORES + BASE_SYSFS_ATTR_NO)
 
 #ifdef CONFIG_SMP
@@ -67,6 +69,9 @@
  *             This value is passed as "id" field to rdmsr/wrmsr functions.
  * @status_reg: One of IA32_THERM_STATUS or IA32_PACKAGE_THERM_STATUS,
  *             from where the temperature values should be read.
+ * @intrpt_reg: One of IA32_THERM_INTERRUPT or IA32_PACKAGE_THERM_INTERRUPT,
+ *             from where the thresholds are read.
+ * @attr_size:  Total number of pre-core attrs displayed in the sysfs.
  * @is_pkg_data: If this is 1, the temp_data holds pkgtemp data.
  *             Otherwise, temp_data holds coretemp data.
  * @valid: If this is 1, the current temperature is valid.
 struct temp_data {
        int temp;
        int ttarget;
+       int tmin;
        int tjmax;
        unsigned long last_updated;
        unsigned int cpu;
        u32 cpu_core_id;
        u32 status_reg;
+       u32 intrpt_reg;
+       int attr_size;
        bool is_pkg_data;
        bool valid;
-       struct sensor_device_attribute sd_attrs[MAX_ATTRS];
-       char attr_name[MAX_ATTRS][CORETEMP_NAME_LENGTH];
+       struct sensor_device_attribute sd_attrs[TOTAL_ATTRS];
+       char attr_name[TOTAL_ATTRS][CORETEMP_NAME_LENGTH];
        struct mutex update_lock;
 };
 
@@ -135,6 +143,19 @@ static ssize_t show_crit_alarm(struct device *dev,
        return sprintf(buf, "%d\n", (eax >> 5) & 1);
 }
 
+static ssize_t show_max_alarm(struct device *dev,
+                               struct device_attribute *devattr, char *buf)
+{
+       u32 eax, edx;
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct platform_data *pdata = dev_get_drvdata(dev);
+       struct temp_data *tdata = pdata->core_data[attr->index];
+
+       rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx);
+
+       return sprintf(buf, "%d\n", !!(eax & THERM_STATUS_THRESHOLD1));
+}
+
 static ssize_t show_tjmax(struct device *dev,
                        struct device_attribute *devattr, char *buf)
 {
@@ -153,6 +174,83 @@ static ssize_t show_ttarget(struct device *dev,
        return sprintf(buf, "%d\n", pdata->core_data[attr->index]->ttarget);
 }
 
+static ssize_t store_ttarget(struct device *dev,
+                               struct device_attribute *devattr,
+                               const char *buf, size_t count)
+{
+       struct platform_data *pdata = dev_get_drvdata(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct temp_data *tdata = pdata->core_data[attr->index];
+       u32 eax, edx;
+       unsigned long val;
+       int diff;
+
+       if (strict_strtoul(buf, 10, &val))
+               return -EINVAL;
+
+       /*
+        * THERM_MASK_THRESHOLD1 is 7 bits wide. Values are entered in terms
+        * of milli degree celsius. Hence don't accept val > (127 * 1000)
+        */
+       if (val > tdata->tjmax || val > 127000)
+               return -EINVAL;
+
+       diff = (tdata->tjmax - val) / 1000;
+
+       mutex_lock(&tdata->update_lock);
+       rdmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, &eax, &edx);
+       eax = (eax & ~THERM_MASK_THRESHOLD1) |
+                               (diff << THERM_SHIFT_THRESHOLD1);
+       wrmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, eax, edx);
+       tdata->ttarget = val;
+       mutex_unlock(&tdata->update_lock);
+
+       return count;
+}
+
+static ssize_t show_tmin(struct device *dev,
+                       struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct platform_data *pdata = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%d\n", pdata->core_data[attr->index]->tmin);
+}
+
+static ssize_t store_tmin(struct device *dev,
+                               struct device_attribute *devattr,
+                               const char *buf, size_t count)
+{
+       struct platform_data *pdata = dev_get_drvdata(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct temp_data *tdata = pdata->core_data[attr->index];
+       u32 eax, edx;
+       unsigned long val;
+       int diff;
+
+       if (strict_strtoul(buf, 10, &val))
+               return -EINVAL;
+
+       /*
+        * THERM_MASK_THRESHOLD0 is 7 bits wide. Values are entered in terms
+        * of milli degree celsius. Hence don't accept val > (127 * 1000)
+        */
+       if (val > tdata->tjmax || val > 127000)
+               return -EINVAL;
+
+       diff = (tdata->tjmax - val) / 1000;
+
+       mutex_lock(&tdata->update_lock);
+       rdmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, &eax, &edx);
+       eax = (eax & ~THERM_MASK_THRESHOLD0) |
+                               (diff << THERM_SHIFT_THRESHOLD0);
+       wrmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, eax, edx);
+       tdata->tmin = val;
+       mutex_unlock(&tdata->update_lock);
+
+       return count;
+}
+
 static ssize_t show_temp(struct device *dev,
                        struct device_attribute *devattr, char *buf)
 {
@@ -344,23 +442,31 @@ static int create_core_attrs(struct temp_data *tdata, struct device *dev,
                                int attr_no)
 {
        int err, i;
-       static ssize_t (*rd_ptr[MAX_ATTRS]) (struct device *dev,
+       static ssize_t (*rd_ptr[TOTAL_ATTRS]) (struct device *dev,
                        struct device_attribute *devattr, char *buf) = {
-                       show_label, show_crit_alarm, show_ttarget,
-                       show_temp, show_tjmax };
-       static const char *names[MAX_ATTRS] = {
+                       show_label, show_crit_alarm, show_temp, show_tjmax,
+                       show_max_alarm, show_ttarget, show_tmin };
+       static ssize_t (*rw_ptr[TOTAL_ATTRS]) (struct device *dev,
+                       struct device_attribute *devattr, const char *buf,
+                       size_t count) = { NULL, NULL, NULL, NULL, NULL,
+                                       store_ttarget, store_tmin };
+       static const char *names[TOTAL_ATTRS] = {
                                        "temp%d_label", "temp%d_crit_alarm",
-                                       "temp%d_max", "temp%d_input",
-                                       "temp%d_crit" };
+                                       "temp%d_input", "temp%d_crit",
+                                       "temp%d_max_alarm", "temp%d_max",
+                                       "temp%d_max_hyst" };
 
-       for (i = 0; i < MAX_ATTRS; i++) {
+       for (i = 0; i < tdata->attr_size; i++) {
                snprintf(tdata->attr_name[i], CORETEMP_NAME_LENGTH, names[i],
                        attr_no);
                sysfs_attr_init(&tdata->sd_attrs[i].dev_attr.attr);
                tdata->sd_attrs[i].dev_attr.attr.name = tdata->attr_name[i];
                tdata->sd_attrs[i].dev_attr.attr.mode = S_IRUGO;
+               if (rw_ptr[i]) {
+                       tdata->sd_attrs[i].dev_attr.attr.mode |= S_IWUSR;
+                       tdata->sd_attrs[i].dev_attr.store = rw_ptr[i];
+               }
                tdata->sd_attrs[i].dev_attr.show = rd_ptr[i];
-               tdata->sd_attrs[i].dev_attr.store = NULL;
                tdata->sd_attrs[i].index = attr_no;
                err = device_create_file(dev, &tdata->sd_attrs[i].dev_attr);
                if (err)
@@ -374,38 +480,6 @@ exit_free:
        return err;
 }
 
-static void update_ttarget(__u8 cpu_model, struct temp_data *tdata,
-                               struct device *dev)
-{
-       int err;
-       u32 eax, edx;
-
-       /*
-        * Initialize ttarget value. Eventually this will be
-        * initialized with the value from MSR_IA32_THERM_INTERRUPT
-        * register. If IA32_TEMPERATURE_TARGET is supported, this
-        * value will be over written below.
-        * To Do: Patch to initialize ttarget from MSR_IA32_THERM_INTERRUPT
-        */
-       tdata->ttarget = tdata->tjmax - 20000;
-
-       /*
-        * Read the still undocumented IA32_TEMPERATURE_TARGET. It exists
-        * on older CPUs but not in this register,
-        * Atoms don't have it either.
-        */
-       if (cpu_model > 0xe && cpu_model != 0x1c) {
-               err = rdmsr_safe_on_cpu(tdata->cpu,
-                               MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
-               if (err) {
-                       dev_warn(dev,
-                       "Unable to read IA32_TEMPERATURE_TARGET MSR\n");
-               } else {
-                       tdata->ttarget = tdata->tjmax -
-                                       ((eax >> 8) & 0xff) * 1000;
-               }
-       }
-}
 
 static int __devinit chk_ucode_version(struct platform_device *pdev)
 {
@@ -464,9 +538,12 @@ static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag)
 
        tdata->status_reg = pkg_flag ? MSR_IA32_PACKAGE_THERM_STATUS :
                                                        MSR_IA32_THERM_STATUS;
+       tdata->intrpt_reg = pkg_flag ? MSR_IA32_PACKAGE_THERM_INTERRUPT :
+                                               MSR_IA32_THERM_INTERRUPT;
        tdata->is_pkg_data = pkg_flag;
        tdata->cpu = cpu;
        tdata->cpu_core_id = TO_CORE_ID(cpu);
+       tdata->attr_size = MAX_CORE_ATTRS;
        mutex_init(&tdata->update_lock);
        return tdata;
 }
@@ -516,7 +593,17 @@ static int create_core_data(struct platform_data *pdata,
        else
                tdata->tjmax = get_tjmax(c, cpu, &pdev->dev);
 
-       update_ttarget(c->x86_model, tdata, &pdev->dev);
+       /*
+        * Test if we can access the intrpt register. If so, increase the
+        * 'size' enough to have ttarget/tmin/max_alarm interfaces.
+        * Initialize ttarget with bits 16:22 of MSR_IA32_THERM_INTERRUPT
+        */
+       err = rdmsr_safe_on_cpu(cpu, tdata->intrpt_reg, &eax, &edx);
+       if (!err) {
+               tdata->attr_size += MAX_THRESH_ATTRS;
+               tdata->ttarget = tdata->tjmax - ((eax >> 16) & 0x7f) * 1000;
+       }
+
        pdata->core_data[attr_no] = tdata;
 
        /* Create sysfs interfaces */
@@ -553,7 +640,7 @@ static void coretemp_remove_core(struct platform_data *pdata,
        struct temp_data *tdata = pdata->core_data[indx];
 
        /* Remove the sysfs attributes */
-       for (i = 0; i < MAX_ATTRS; i++)
+       for (i = 0; i < tdata->attr_size; i++)
                device_remove_file(dev, &tdata->sd_attrs[i].dev_attr);
 
        kfree(pdata->core_data[indx]);
index 1a409c5..c316294 100644 (file)
@@ -432,13 +432,15 @@ static int aem_read_sensor(struct aem_data *data, u8 elt, u8 reg,
        aem_send_message(ipmi);
 
        res = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT);
-       if (!res)
-               return -ETIMEDOUT;
+       if (!res) {
+               res = -ETIMEDOUT;
+               goto out;
+       }
 
        if (ipmi->rx_result || ipmi->rx_msg_len != rs_size ||
            memcmp(&rs_resp->id, &system_x_id, sizeof(system_x_id))) {
-               kfree(rs_resp);
-               return -ENOENT;
+               res = -ENOENT;
+               goto out;
        }
 
        switch (size) {
@@ -463,8 +465,11 @@ static int aem_read_sensor(struct aem_data *data, u8 elt, u8 reg,
                break;
        }
        }
+       res = 0;
 
-       return 0;
+out:
+       kfree(rs_resp);
+       return res;
 }
 
 /* Update AEM energy registers */
index 2f94f95..90ddb87 100644 (file)
@@ -54,6 +54,9 @@
  * and extended mode. They are mostly compatible with LM90 except for a data
  * format difference for the temperature value registers.
  *
+ * This driver also supports the SA56004 from Philips. This device is
+ * pin-compatible with the LM86, the ED/EDP parts are also address-compatible.
+ *
  * Since the LM90 was the first chipset supported by this driver, most
  * comments will refer to this chipset, but are actually general and
  * concern all supported chipsets, unless mentioned otherwise.
  * MAX6659 can have address 0x4c, 0x4d or 0x4e.
  * MAX6680 and MAX6681 can have address 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b,
  * 0x4c, 0x4d or 0x4e.
+ * SA56004 can have address 0x48 through 0x4F.
  */
 
 static const unsigned short normal_i2c[] = {
-       0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e, I2C_CLIENT_END };
+       0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x48, 0x49, 0x4a, 0x4b, 0x4c,
+       0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
 
 enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
-       max6646, w83l771, max6696 };
+       max6646, w83l771, max6696, sa56004 };
 
 /*
  * The LM90 registers
@@ -152,6 +157,10 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
 #define MAX6659_REG_R_LOCAL_EMERG      0x17
 #define MAX6659_REG_W_LOCAL_EMERG      0x17
 
+/*  SA56004 registers */
+
+#define SA56004_REG_R_LOCAL_TEMPL 0x22
+
 #define LM90_DEF_CONVRATE_RVAL 6       /* Def conversion rate register value */
 #define LM90_MAX_CONVRATE_MS   16000   /* Maximum conversion rate in ms */
 
@@ -161,7 +170,6 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
 #define LM90_FLAG_ADT7461_EXT  (1 << 0) /* ADT7461 extended mode       */
 /* Device features */
 #define LM90_HAVE_OFFSET       (1 << 1) /* temperature offset register */
-#define LM90_HAVE_LOCAL_EXT    (1 << 2) /* extended local temperature  */
 #define LM90_HAVE_REM_LIMIT_EXT        (1 << 3) /* extended remote limit       */
 #define LM90_HAVE_EMERGENCY    (1 << 4) /* 3rd upper (emergency) limit */
 #define LM90_HAVE_EMERGENCY_ALARM (1 << 5)/* emergency alarm           */
@@ -192,6 +200,7 @@ static const struct i2c_device_id lm90_id[] = {
        { "max6696", max6696 },
        { "nct1008", adt7461 },
        { "w83l771", w83l771 },
+       { "sa56004", sa56004 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, lm90_id);
@@ -204,6 +213,7 @@ struct lm90_params {
        u16 alert_alarms;       /* Which alarm bits trigger ALERT# */
                                /* Upper 8 bits for max6695/96 */
        u8 max_convrate;        /* Maximum conversion rate register value */
+       u8 reg_local_ext;       /* Extended local temp register (optional) */
 };
 
 static const struct lm90_params lm90_params[] = {
@@ -235,19 +245,20 @@ static const struct lm90_params lm90_params[] = {
                .max_convrate = 9,
        },
        [max6646] = {
-               .flags = LM90_HAVE_LOCAL_EXT,
                .alert_alarms = 0x7c,
                .max_convrate = 6,
+               .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
        },
        [max6657] = {
-               .flags = LM90_HAVE_LOCAL_EXT,
                .alert_alarms = 0x7c,
                .max_convrate = 8,
+               .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
        },
        [max6659] = {
-               .flags = LM90_HAVE_LOCAL_EXT | LM90_HAVE_EMERGENCY,
+               .flags = LM90_HAVE_EMERGENCY,
                .alert_alarms = 0x7c,
                .max_convrate = 8,
+               .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
        },
        [max6680] = {
                .flags = LM90_HAVE_OFFSET,
@@ -255,16 +266,23 @@ static const struct lm90_params lm90_params[] = {
                .max_convrate = 7,
        },
        [max6696] = {
-               .flags = LM90_HAVE_LOCAL_EXT | LM90_HAVE_EMERGENCY
+               .flags = LM90_HAVE_EMERGENCY
                  | LM90_HAVE_EMERGENCY_ALARM | LM90_HAVE_TEMP3,
                .alert_alarms = 0x187c,
                .max_convrate = 6,
+               .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
        },
        [w83l771] = {
                .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
                .alert_alarms = 0x7c,
                .max_convrate = 8,
        },
+       [sa56004] = {
+               .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
+               .alert_alarms = 0x7b,
+               .max_convrate = 9,
+               .reg_local_ext = SA56004_REG_R_LOCAL_TEMPL,
+       },
 };
 
 /*
@@ -286,6 +304,7 @@ struct lm90_data {
        u16 alert_alarms;       /* Which alarm bits trigger ALERT# */
                                /* Upper 8 bits for max6695/96 */
        u8 max_convrate;        /* Maximum conversion rate */
+       u8 reg_local_ext;       /* local extension register offset */
 
        /* registers values */
        s8 temp8[8];    /* 0: local low limit
@@ -452,9 +471,9 @@ static struct lm90_data *lm90_update_device(struct device *dev)
                lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT, &data->temp8[3]);
                lm90_read_reg(client, LM90_REG_R_TCRIT_HYST, &data->temp_hyst);
 
-               if (data->flags & LM90_HAVE_LOCAL_EXT) {
+               if (data->reg_local_ext) {
                        lm90_read16(client, LM90_REG_R_LOCAL_TEMP,
-                                   MAX6657_REG_R_LOCAL_TEMPL,
+                                   data->reg_local_ext,
                                    &data->temp11[4]);
                } else {
                        if (lm90_read_reg(client, LM90_REG_R_LOCAL_TEMP,
@@ -1092,7 +1111,7 @@ static int lm90_detect(struct i2c_client *new_client,
        struct i2c_adapter *adapter = new_client->adapter;
        int address = new_client->addr;
        const char *name = NULL;
-       int man_id, chip_id, reg_config1, reg_convrate;
+       int man_id, chip_id, reg_config1, reg_config2, reg_convrate;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -ENODEV;
@@ -1108,15 +1127,16 @@ static int lm90_detect(struct i2c_client *new_client,
                                                LM90_REG_R_CONVRATE)) < 0)
                return -ENODEV;
 
-       if ((address == 0x4C || address == 0x4D)
-        && man_id == 0x01) { /* National Semiconductor */
-               int reg_config2;
-
+       if (man_id == 0x01 || man_id == 0x5C || man_id == 0x41) {
                reg_config2 = i2c_smbus_read_byte_data(new_client,
                                                LM90_REG_R_CONFIG2);
                if (reg_config2 < 0)
                        return -ENODEV;
+       } else
+               reg_config2 = 0;        /* Make compiler happy */
 
+       if ((address == 0x4C || address == 0x4D)
+        && man_id == 0x01) { /* National Semiconductor */
                if ((reg_config1 & 0x2A) == 0x00
                 && (reg_config2 & 0xF8) == 0x00
                 && reg_convrate <= 0x09) {
@@ -1245,13 +1265,6 @@ static int lm90_detect(struct i2c_client *new_client,
        } else
        if (address == 0x4C
         && man_id == 0x5C) { /* Winbond/Nuvoton */
-               int reg_config2;
-
-               reg_config2 = i2c_smbus_read_byte_data(new_client,
-                                               LM90_REG_R_CONFIG2);
-               if (reg_config2 < 0)
-                       return -ENODEV;
-
                if ((reg_config1 & 0x2A) == 0x00
                 && (reg_config2 & 0xF8) == 0x00) {
                        if (chip_id == 0x01 /* W83L771W/G */
@@ -1263,6 +1276,15 @@ static int lm90_detect(struct i2c_client *new_client,
                                name = "w83l771";
                        }
                }
+       } else
+       if (address >= 0x48 && address <= 0x4F
+        && man_id == 0xA1) { /*  NXP Semiconductor/Philips */
+               if (chip_id == 0x00
+                && (reg_config1 & 0x2A) == 0x00
+                && (reg_config2 & 0xFE) == 0x00
+                && reg_convrate <= 0x09) {
+                       name = "sa56004";
+               }
        }
 
        if (!name) { /* identification failed */
@@ -1368,6 +1390,7 @@ static int lm90_probe(struct i2c_client *new_client,
 
        /* Set chip capabilities */
        data->flags = lm90_params[data->kind].flags;
+       data->reg_local_ext = lm90_params[data->kind].reg_local_ext;
 
        /* Set maximum conversion rate */
        data->max_convrate = lm90_params[data->kind].max_convrate;
index d3b464b..513901d 100644 (file)
@@ -74,8 +74,9 @@ static const unsigned short normal_i2c[] = {
 #define TT_OFF 0
 #define TT_ON 1
 #define TT_MASK 7
-#define MANUFACTURER_ID 0x01
-#define DEFAULT_REVISION 0xA4
+#define NATSEMI_MAN_ID 0x01
+#define LM95231_CHIP_ID        0xA1
+#define LM95241_CHIP_ID        0xA4
 
 static const u8 lm95241_reg_address[] = {
        LM95241_REG_R_LOCAL_TEMPH,
@@ -338,20 +339,25 @@ static int lm95241_detect(struct i2c_client *new_client,
                          struct i2c_board_info *info)
 {
        struct i2c_adapter *adapter = new_client->adapter;
-       int address = new_client->addr;
        const char *name;
+       int mfg_id, chip_id;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -ENODEV;
 
-       if ((i2c_smbus_read_byte_data(new_client, LM95241_REG_R_MAN_ID)
-            == MANUFACTURER_ID)
-           && (i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID)
-               == DEFAULT_REVISION)) {
-               name = DEVNAME;
-       } else {
-               dev_dbg(&adapter->dev, "LM95241 detection failed at 0x%02x\n",
-                       address);
+       mfg_id = i2c_smbus_read_byte_data(new_client, LM95241_REG_R_MAN_ID);
+       if (mfg_id != NATSEMI_MAN_ID)
+               return -ENODEV;
+
+       chip_id = i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID);
+       switch (chip_id) {
+       case LM95231_CHIP_ID:
+               name = "lm95231";
+               break;
+       case LM95241_CHIP_ID:
+               name = "lm95241";
+               break;
+       default:
                return -ENODEV;
        }
 
@@ -431,7 +437,8 @@ static int lm95241_remove(struct i2c_client *client)
 
 /* Driver data (common to all clients) */
 static const struct i2c_device_id lm95241_id[] = {
-       { DEVNAME, 0 },
+       { "lm95231", 0 },
+       { "lm95241", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, lm95241_id);
diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c
new file mode 100644 (file)
index 0000000..dce9e68
--- /dev/null
@@ -0,0 +1,543 @@
+/*
+ * Copyright (C) 2011 Alexander Stein <alexander.stein@systec-electronic.com>
+ *
+ * The LM95245 is a sensor chip made by National Semiconductors.
+ * It reports up to two temperatures (its own plus an external one).
+ * Complete datasheet can be obtained from National's website at:
+ *   http://www.national.com/ds.cgi/LM/LM95245.pdf
+ *
+ * This driver is based on lm95241.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+
+#define DEVNAME "lm95245"
+
+static const unsigned short normal_i2c[] = {
+       0x18, 0x19, 0x29, 0x4c, 0x4d, I2C_CLIENT_END };
+
+/* LM95245 registers */
+/* general registers */
+#define LM95245_REG_RW_CONFIG1         0x03
+#define LM95245_REG_RW_CONVERS_RATE    0x04
+#define LM95245_REG_W_ONE_SHOT         0x0F
+
+/* diode configuration */
+#define LM95245_REG_RW_CONFIG2         0xBF
+#define LM95245_REG_RW_REMOTE_OFFH     0x11
+#define LM95245_REG_RW_REMOTE_OFFL     0x12
+
+/* status registers */
+#define LM95245_REG_R_STATUS1          0x02
+#define LM95245_REG_R_STATUS2          0x33
+
+/* limit registers */
+#define LM95245_REG_RW_REMOTE_OS_LIMIT         0x07
+#define LM95245_REG_RW_LOCAL_OS_TCRIT_LIMIT    0x20
+#define LM95245_REG_RW_REMOTE_TCRIT_LIMIT      0x19
+#define LM95245_REG_RW_COMMON_HYSTERESIS       0x21
+
+/* temperature signed */
+#define LM95245_REG_R_LOCAL_TEMPH_S    0x00
+#define LM95245_REG_R_LOCAL_TEMPL_S    0x30
+#define LM95245_REG_R_REMOTE_TEMPH_S   0x01
+#define LM95245_REG_R_REMOTE_TEMPL_S   0x10
+/* temperature unsigned */
+#define LM95245_REG_R_REMOTE_TEMPH_U   0x31
+#define LM95245_REG_R_REMOTE_TEMPL_U   0x32
+
+/* id registers */
+#define LM95245_REG_R_MAN_ID           0xFE
+#define LM95245_REG_R_CHIP_ID          0xFF
+
+/* LM95245 specific bitfields */
+#define CFG_STOP               0x40
+#define CFG_REMOTE_TCRIT_MASK  0x10
+#define CFG_REMOTE_OS_MASK     0x08
+#define CFG_LOCAL_TCRIT_MASK   0x04
+#define CFG_LOCAL_OS_MASK      0x02
+
+#define CFG2_OS_A0             0x40
+#define CFG2_DIODE_FAULT_OS    0x20
+#define CFG2_DIODE_FAULT_TCRIT 0x10
+#define CFG2_REMOTE_TT         0x08
+#define CFG2_REMOTE_FILTER_DIS 0x00
+#define CFG2_REMOTE_FILTER_EN  0x06
+
+/* conversation rate in ms */
+#define RATE_CR0063    0x00
+#define RATE_CR0364    0x01
+#define RATE_CR1000    0x02
+#define RATE_CR2500    0x03
+
+#define STATUS1_DIODE_FAULT    0x04
+#define STATUS1_RTCRIT         0x02
+#define STATUS1_LOC            0x01
+
+#define MANUFACTURER_ID                0x01
+#define DEFAULT_REVISION       0xB3
+
+static const u8 lm95245_reg_address[] = {
+       LM95245_REG_R_LOCAL_TEMPH_S,
+       LM95245_REG_R_LOCAL_TEMPL_S,
+       LM95245_REG_R_REMOTE_TEMPH_S,
+       LM95245_REG_R_REMOTE_TEMPL_S,
+       LM95245_REG_R_REMOTE_TEMPH_U,
+       LM95245_REG_R_REMOTE_TEMPL_U,
+       LM95245_REG_RW_LOCAL_OS_TCRIT_LIMIT,
+       LM95245_REG_RW_REMOTE_TCRIT_LIMIT,
+       LM95245_REG_RW_COMMON_HYSTERESIS,
+       LM95245_REG_R_STATUS1,
+};
+
+/* Client data (each client gets its own) */
+struct lm95245_data {
+       struct device *hwmon_dev;
+       struct mutex update_lock;
+       unsigned long last_updated;     /* in jiffies */
+       unsigned long interval; /* in msecs */
+       bool valid;             /* zero until following fields are valid */
+       /* registers values */
+       u8 regs[ARRAY_SIZE(lm95245_reg_address)];
+       u8 config1, config2;
+};
+
+/* Conversions */
+static int temp_from_reg_unsigned(u8 val_h, u8 val_l)
+{
+       return val_h * 1000 + val_l * 1000 / 256;
+}
+
+static int temp_from_reg_signed(u8 val_h, u8 val_l)
+{
+       if (val_h & 0x80)
+               return (val_h - 0x100) * 1000;
+       return temp_from_reg_unsigned(val_h, val_l);
+}
+
+static struct lm95245_data *lm95245_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95245_data *data = i2c_get_clientdata(client);
+
+       mutex_lock(&data->update_lock);
+
+       if (time_after(jiffies, data->last_updated
+               + msecs_to_jiffies(data->interval)) || !data->valid) {
+               int i;
+
+               dev_dbg(&client->dev, "Updating lm95245 data.\n");
+               for (i = 0; i < ARRAY_SIZE(lm95245_reg_address); i++)
+                       data->regs[i]
+                         = i2c_smbus_read_byte_data(client,
+                                                    lm95245_reg_address[i]);
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       mutex_unlock(&data->update_lock);
+
+       return data;
+}
+
+static unsigned long lm95245_read_conversion_rate(struct i2c_client *client)
+{
+       int rate;
+       unsigned long interval;
+
+       rate = i2c_smbus_read_byte_data(client, LM95245_REG_RW_CONVERS_RATE);
+
+       switch (rate) {
+       case RATE_CR0063:
+               interval = 63;
+               break;
+       case RATE_CR0364:
+               interval = 364;
+               break;
+       case RATE_CR1000:
+               interval = 1000;
+               break;
+       case RATE_CR2500:
+       default:
+               interval = 2500;
+               break;
+       }
+
+       return interval;
+}
+
+static unsigned long lm95245_set_conversion_rate(struct i2c_client *client,
+                       unsigned long interval)
+{
+       int rate;
+
+       if (interval <= 63) {
+               interval = 63;
+               rate = RATE_CR0063;
+       } else if (interval <= 364) {
+               interval = 364;
+               rate = RATE_CR0364;
+       } else if (interval <= 1000) {
+               interval = 1000;
+               rate = RATE_CR1000;
+       } else {
+               interval = 2500;
+               rate = RATE_CR2500;
+       }
+
+       i2c_smbus_write_byte_data(client, LM95245_REG_RW_CONVERS_RATE, rate);
+
+       return interval;
+}
+
+/* Sysfs stuff */
+static ssize_t show_input(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       struct lm95245_data *data = lm95245_update_device(dev);
+       int temp;
+       int index = to_sensor_dev_attr(attr)->index;
+
+       /*
+        * Index 0 (Local temp) is always signed
+        * Index 2 (Remote temp) has both signed and unsigned data
+        * use signed calculation for remote if signed bit is set
+        */
+       if (index == 0 || data->regs[index] & 0x80)
+               temp = temp_from_reg_signed(data->regs[index],
+                           data->regs[index + 1]);
+       else
+               temp = temp_from_reg_unsigned(data->regs[index + 2],
+                           data->regs[index + 3]);
+
+       return snprintf(buf, PAGE_SIZE - 1, "%d\n", temp);
+}
+
+static ssize_t show_limit(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct lm95245_data *data = lm95245_update_device(dev);
+       int index = to_sensor_dev_attr(attr)->index;
+
+       return snprintf(buf, PAGE_SIZE - 1, "%d\n",
+                       data->regs[index] * 1000);
+}
+
+static ssize_t set_limit(struct device *dev, struct device_attribute *attr,
+                       const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95245_data *data = i2c_get_clientdata(client);
+       int index = to_sensor_dev_attr(attr)->index;
+       unsigned long val;
+
+       if (strict_strtoul(buf, 10, &val) < 0)
+               return -EINVAL;
+
+       val /= 1000;
+
+       val = SENSORS_LIMIT(val, 0, (index == 6 ? 127 : 255));
+
+       mutex_lock(&data->update_lock);
+
+       data->valid = 0;
+
+       i2c_smbus_write_byte_data(client, lm95245_reg_address[index], val);
+
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t set_crit_hyst(struct device *dev, struct device_attribute *attr,
+                       const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95245_data *data = i2c_get_clientdata(client);
+       unsigned long val;
+
+       if (strict_strtoul(buf, 10, &val) < 0)
+               return -EINVAL;
+
+       val /= 1000;
+
+       val = SENSORS_LIMIT(val, 0, 31);
+
+       mutex_lock(&data->update_lock);
+
+       data->valid = 0;
+
+       /* shared crit hysteresis */
+       i2c_smbus_write_byte_data(client, LM95245_REG_RW_COMMON_HYSTERESIS,
+               val);
+
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t show_type(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95245_data *data = i2c_get_clientdata(client);
+
+       return snprintf(buf, PAGE_SIZE - 1,
+               data->config2 & CFG2_REMOTE_TT ? "1\n" : "2\n");
+}
+
+static ssize_t set_type(struct device *dev, struct device_attribute *attr,
+                       const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95245_data *data = i2c_get_clientdata(client);
+       unsigned long val;
+
+       if (strict_strtoul(buf, 10, &val) < 0)
+               return -EINVAL;
+       if (val != 1 && val != 2)
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+
+       if (val == 1)
+               data->config2 |= CFG2_REMOTE_TT;
+       else
+               data->config2 &= ~CFG2_REMOTE_TT;
+
+       data->valid = 0;
+
+       i2c_smbus_write_byte_data(client, LM95245_REG_RW_CONFIG2,
+                                 data->config2);
+
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct lm95245_data *data = lm95245_update_device(dev);
+       int index = to_sensor_dev_attr(attr)->index;
+
+       return snprintf(buf, PAGE_SIZE - 1, "%d\n",
+                       !!(data->regs[9] & index));
+}
+
+static ssize_t show_interval(struct device *dev, struct device_attribute *attr,
+                            char *buf)
+{
+       struct lm95245_data *data = lm95245_update_device(dev);
+
+       return snprintf(buf, PAGE_SIZE - 1, "%lu\n", data->interval);
+}
+
+static ssize_t set_interval(struct device *dev, struct device_attribute *attr,
+                           const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95245_data *data = i2c_get_clientdata(client);
+       unsigned long val;
+
+       if (strict_strtoul(buf, 10, &val) < 0)
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+
+       data->interval = lm95245_set_conversion_rate(client, val);
+
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_limit,
+               set_limit, 6);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_limit,
+               set_crit_hyst, 8);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL,
+               STATUS1_LOC);
+
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_input, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_limit,
+               set_limit, 7);
+static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_limit,
+               set_crit_hyst, 8);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL,
+               STATUS1_RTCRIT);
+static SENSOR_DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type,
+               set_type, 0);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL,
+               STATUS1_DIODE_FAULT);
+
+static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval,
+               set_interval);
+
+static struct attribute *lm95245_attributes[] = {
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_input.dev_attr.attr,
+       &sensor_dev_attr_temp2_crit.dev_attr.attr,
+       &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_type.dev_attr.attr,
+       &sensor_dev_attr_temp2_fault.dev_attr.attr,
+       &dev_attr_update_interval.attr,
+       NULL
+};
+
+static const struct attribute_group lm95245_group = {
+       .attrs = lm95245_attributes,
+};
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int lm95245_detect(struct i2c_client *new_client,
+                         struct i2c_board_info *info)
+{
+       struct i2c_adapter *adapter = new_client->adapter;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       if (i2c_smbus_read_byte_data(new_client, LM95245_REG_R_MAN_ID)
+                       != MANUFACTURER_ID
+               || i2c_smbus_read_byte_data(new_client, LM95245_REG_R_CHIP_ID)
+                       != DEFAULT_REVISION)
+               return -ENODEV;
+
+       strlcpy(info->type, DEVNAME, I2C_NAME_SIZE);
+       return 0;
+}
+
+static void lm95245_init_client(struct i2c_client *client)
+{
+       struct lm95245_data *data = i2c_get_clientdata(client);
+
+       data->valid = 0;
+       data->interval = lm95245_read_conversion_rate(client);
+
+       data->config1 = i2c_smbus_read_byte_data(client,
+               LM95245_REG_RW_CONFIG1);
+       data->config2 = i2c_smbus_read_byte_data(client,
+               LM95245_REG_RW_CONFIG2);
+
+       if (data->config1 & CFG_STOP) {
+               /* Clear the standby bit */
+               data->config1 &= ~CFG_STOP;
+               i2c_smbus_write_byte_data(client, LM95245_REG_RW_CONFIG1,
+                       data->config1);
+       }
+}
+
+static int lm95245_probe(struct i2c_client *new_client,
+                        const struct i2c_device_id *id)
+{
+       struct lm95245_data *data;
+       int err;
+
+       data = kzalloc(sizeof(struct lm95245_data), GFP_KERNEL);
+       if (!data) {
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       i2c_set_clientdata(new_client, data);
+       mutex_init(&data->update_lock);
+
+       /* Initialize the LM95245 chip */
+       lm95245_init_client(new_client);
+
+       /* Register sysfs hooks */
+       err = sysfs_create_group(&new_client->dev.kobj, &lm95245_group);
+       if (err)
+               goto exit_free;
+
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               goto exit_remove_files;
+       }
+
+       return 0;
+
+exit_remove_files:
+       sysfs_remove_group(&new_client->dev.kobj, &lm95245_group);
+exit_free:
+       kfree(data);
+exit:
+       return err;
+}
+
+static int lm95245_remove(struct i2c_client *client)
+{
+       struct lm95245_data *data = i2c_get_clientdata(client);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &lm95245_group);
+
+       kfree(data);
+       return 0;
+}
+
+/* Driver data (common to all clients) */
+static const struct i2c_device_id lm95245_id[] = {
+       { DEVNAME, 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, lm95245_id);
+
+static struct i2c_driver lm95245_driver = {
+       .class          = I2C_CLASS_HWMON,
+       .driver = {
+               .name   = DEVNAME,
+       },
+       .probe          = lm95245_probe,
+       .remove         = lm95245_remove,
+       .id_table       = lm95245_id,
+       .detect         = lm95245_detect,
+       .address_list   = normal_i2c,
+};
+
+static int __init sensors_lm95245_init(void)
+{
+       return i2c_add_driver(&lm95245_driver);
+}
+
+static void __exit sensors_lm95245_exit(void)
+{
+       i2c_del_driver(&lm95245_driver);
+}
+
+MODULE_AUTHOR("Alexander Stein <alexander.stein@systec-electronic.com>");
+MODULE_DESCRIPTION("LM95245 sensor driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_lm95245_init);
+module_exit(sensors_lm95245_exit);
diff --git a/drivers/hwmon/max1668.c b/drivers/hwmon/max1668.c
new file mode 100644 (file)
index 0000000..20d1b2d
--- /dev/null
@@ -0,0 +1,502 @@
+/*
+    Copyright (c) 2011 David George <david.george@ska.ac.za>
+
+    based on adm1021.c
+    some credit to Christoph Scheurer, but largely a rewrite
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+/* Addresses to scan */
+static unsigned short max1668_addr_list[] = {
+       0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e, I2C_CLIENT_END };
+
+/* max1668 registers */
+
+#define MAX1668_REG_TEMP(nr)   (nr)
+#define MAX1668_REG_STAT1      0x05
+#define MAX1668_REG_STAT2      0x06
+#define MAX1668_REG_MAN_ID     0xfe
+#define MAX1668_REG_DEV_ID     0xff
+
+/* limits */
+
+/* write high limits */
+#define MAX1668_REG_LIMH_WR(nr)        (0x13 + 2 * (nr))
+/* write low limits */
+#define MAX1668_REG_LIML_WR(nr)        (0x14 + 2 * (nr))
+/* read high limits */
+#define MAX1668_REG_LIMH_RD(nr)        (0x08 + 2 * (nr))
+/* read low limits */
+#define MAX1668_REG_LIML_RD(nr)        (0x09 + 2 * (nr))
+
+/* manufacturer and device ID Constants */
+#define MAN_ID_MAXIM           0x4d
+#define DEV_ID_MAX1668         0x3
+#define DEV_ID_MAX1805         0x5
+#define DEV_ID_MAX1989         0xb
+
+/* read only mode module parameter */
+static int read_only;
+module_param(read_only, bool, 0);
+MODULE_PARM_DESC(read_only, "Don't set any values, read only mode");
+
+enum chips { max1668, max1805, max1989 };
+
+struct max1668_data {
+       struct device *hwmon_dev;
+       enum chips type;
+
+       struct mutex update_lock;
+       char valid;             /* !=0 if following fields are valid */
+       unsigned long last_updated;     /* In jiffies */
+
+       /* 1x local and 4x remote */
+       s8 temp_max[5];
+       s8 temp_min[5];
+       s8 temp[5];
+       u16 alarms;
+};
+
+static struct max1668_data *max1668_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct max1668_data *data = i2c_get_clientdata(client);
+       struct max1668_data *ret = data;
+       s32 val;
+       int i;
+
+       mutex_lock(&data->update_lock);
+
+       if (data->valid && !time_after(jiffies,
+                       data->last_updated + HZ + HZ / 2))
+               goto abort;
+
+       for (i = 0; i < 5; i++) {
+               val = i2c_smbus_read_byte_data(client, MAX1668_REG_TEMP(i));
+               if (unlikely(val < 0)) {
+                       ret = ERR_PTR(val);
+                       goto abort;
+               }
+               data->temp[i] = (s8) val;
+
+               val = i2c_smbus_read_byte_data(client, MAX1668_REG_LIMH_RD(i));
+               if (unlikely(val < 0)) {
+                       ret = ERR_PTR(val);
+                       goto abort;
+               }
+               data->temp_max[i] = (s8) val;
+
+               val = i2c_smbus_read_byte_data(client, MAX1668_REG_LIML_RD(i));
+               if (unlikely(val < 0)) {
+                       ret = ERR_PTR(val);
+                       goto abort;
+               }
+               data->temp_min[i] = (s8) val;
+       }
+
+       val = i2c_smbus_read_byte_data(client, MAX1668_REG_STAT1);
+       if (unlikely(val < 0)) {
+               ret = ERR_PTR(val);
+               goto abort;
+       }
+       data->alarms = val << 8;
+
+       val = i2c_smbus_read_byte_data(client, MAX1668_REG_STAT2);
+       if (unlikely(val < 0)) {
+               ret = ERR_PTR(val);
+               goto abort;
+       }
+       data->alarms |= val;
+
+       data->last_updated = jiffies;
+       data->valid = 1;
+abort:
+       mutex_unlock(&data->update_lock);
+
+       return ret;
+}
+
+static ssize_t show_temp(struct device *dev,
+                        struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct max1668_data *data = max1668_update_device(dev);
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       return sprintf(buf, "%d\n", data->temp[index] * 1000);
+}
+
+static ssize_t show_temp_max(struct device *dev,
+                            struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct max1668_data *data = max1668_update_device(dev);
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       return sprintf(buf, "%d\n", data->temp_max[index] * 1000);
+}
+
+static ssize_t show_temp_min(struct device *dev,
+                            struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct max1668_data *data = max1668_update_device(dev);
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       return sprintf(buf, "%d\n", data->temp_min[index] * 1000);
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       int index = to_sensor_dev_attr(attr)->index;
+       struct max1668_data *data = max1668_update_device(dev);
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       return sprintf(buf, "%u\n", (data->alarms >> index) & 0x1);
+}
+
+static ssize_t show_fault(struct device *dev,
+                         struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct max1668_data *data = max1668_update_device(dev);
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       return sprintf(buf, "%u\n",
+                      (data->alarms & (1 << 12)) && data->temp[index] == 127);
+}
+
+static ssize_t set_temp_max(struct device *dev,
+                           struct device_attribute *devattr,
+                           const char *buf, size_t count)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct max1668_data *data = i2c_get_clientdata(client);
+       long temp;
+       int ret;
+
+       ret = kstrtol(buf, 10, &temp);
+       if (ret < 0)
+               return ret;
+
+       mutex_lock(&data->update_lock);
+       data->temp_max[index] = SENSORS_LIMIT(temp/1000, -128, 127);
+       if (i2c_smbus_write_byte_data(client,
+                                       MAX1668_REG_LIMH_WR(index),
+                                       data->temp_max[index]))
+               count = -EIO;
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t set_temp_min(struct device *dev,
+                           struct device_attribute *devattr,
+                           const char *buf, size_t count)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct max1668_data *data = i2c_get_clientdata(client);
+       long temp;
+       int ret;
+
+       ret = kstrtol(buf, 10, &temp);
+       if (ret < 0)
+               return ret;
+
+       mutex_lock(&data->update_lock);
+       data->temp_min[index] = SENSORS_LIMIT(temp/1000, -128, 127);
+       if (i2c_smbus_write_byte_data(client,
+                                       MAX1668_REG_LIML_WR(index),
+                                       data->temp_max[index]))
+               count = -EIO;
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_max,
+                               set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO, show_temp_min,
+                               set_temp_min, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO, show_temp_max,
+                               set_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO, show_temp_min,
+                               set_temp_min, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO, show_temp_max,
+                               set_temp_max, 2);
+static SENSOR_DEVICE_ATTR(temp3_min, S_IRUGO, show_temp_min,
+                               set_temp_min, 2);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp4_max, S_IRUGO, show_temp_max,
+                               set_temp_max, 3);
+static SENSOR_DEVICE_ATTR(temp4_min, S_IRUGO, show_temp_min,
+                               set_temp_min, 3);
+static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp5_max, S_IRUGO, show_temp_max,
+                               set_temp_max, 4);
+static SENSOR_DEVICE_ATTR(temp5_min, S_IRUGO, show_temp_min,
+                               set_temp_min, 4);
+
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 14);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp3_min_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp4_min_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp5_min_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp5_max_alarm, S_IRUGO, show_alarm, NULL, 0);
+
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_fault, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_fault, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_fault, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_fault, S_IRUGO, show_fault, NULL, 4);
+
+/* Attributes common to MAX1668, MAX1989 and MAX1805 */
+static struct attribute *max1668_attribute_common[] = {
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_min.dev_attr.attr,
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp2_max.dev_attr.attr,
+       &sensor_dev_attr_temp2_min.dev_attr.attr,
+       &sensor_dev_attr_temp2_input.dev_attr.attr,
+       &sensor_dev_attr_temp3_max.dev_attr.attr,
+       &sensor_dev_attr_temp3_min.dev_attr.attr,
+       &sensor_dev_attr_temp3_input.dev_attr.attr,
+
+       &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
+
+       &sensor_dev_attr_temp2_fault.dev_attr.attr,
+       &sensor_dev_attr_temp3_fault.dev_attr.attr,
+       NULL
+};
+
+/* Attributes not present on MAX1805 */
+static struct attribute *max1668_attribute_unique[] = {
+       &sensor_dev_attr_temp4_max.dev_attr.attr,
+       &sensor_dev_attr_temp4_min.dev_attr.attr,
+       &sensor_dev_attr_temp4_input.dev_attr.attr,
+       &sensor_dev_attr_temp5_max.dev_attr.attr,
+       &sensor_dev_attr_temp5_min.dev_attr.attr,
+       &sensor_dev_attr_temp5_input.dev_attr.attr,
+
+       &sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp4_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp5_min_alarm.dev_attr.attr,
+
+       &sensor_dev_attr_temp4_fault.dev_attr.attr,
+       &sensor_dev_attr_temp5_fault.dev_attr.attr,
+       NULL
+};
+
+static mode_t max1668_attribute_mode(struct kobject *kobj,
+                                    struct attribute *attr, int index)
+{
+       int ret = S_IRUGO;
+       if (read_only)
+               return ret;
+       if (attr == &sensor_dev_attr_temp1_max.dev_attr.attr ||
+           attr == &sensor_dev_attr_temp2_max.dev_attr.attr ||
+           attr == &sensor_dev_attr_temp3_max.dev_attr.attr ||
+           attr == &sensor_dev_attr_temp4_max.dev_attr.attr ||
+           attr == &sensor_dev_attr_temp5_max.dev_attr.attr ||
+           attr == &sensor_dev_attr_temp1_min.dev_attr.attr ||
+           attr == &sensor_dev_attr_temp2_min.dev_attr.attr ||
+           attr == &sensor_dev_attr_temp3_min.dev_attr.attr ||
+           attr == &sensor_dev_attr_temp4_min.dev_attr.attr ||
+           attr == &sensor_dev_attr_temp5_min.dev_attr.attr)
+               ret |= S_IWUSR;
+       return ret;
+}
+
+static const struct attribute_group max1668_group_common = {
+       .attrs = max1668_attribute_common,
+       .is_visible = max1668_attribute_mode
+};
+
+static const struct attribute_group max1668_group_unique = {
+       .attrs = max1668_attribute_unique,
+       .is_visible = max1668_attribute_mode
+};
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int max1668_detect(struct i2c_client *client,
+                         struct i2c_board_info *info)
+{
+       struct i2c_adapter *adapter = client->adapter;
+       const char *type_name;
+       int man_id, dev_id;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       /* Check for unsupported part */
+       man_id = i2c_smbus_read_byte_data(client, MAX1668_REG_MAN_ID);
+       if (man_id != MAN_ID_MAXIM)
+               return -ENODEV;
+
+       dev_id = i2c_smbus_read_byte_data(client, MAX1668_REG_DEV_ID);
+       if (dev_id < 0)
+               return -ENODEV;
+
+       type_name = NULL;
+       if (dev_id == DEV_ID_MAX1668)
+               type_name = "max1668";
+       else if (dev_id == DEV_ID_MAX1805)
+               type_name = "max1805";
+       else if (dev_id == DEV_ID_MAX1989)
+               type_name = "max1989";
+
+       if (!type_name)
+               return -ENODEV;
+
+       strlcpy(info->type, type_name, I2C_NAME_SIZE);
+
+       return 0;
+}
+
+static int max1668_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct i2c_adapter *adapter = client->adapter;
+       struct max1668_data *data;
+       int err;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       data = kzalloc(sizeof(struct max1668_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, data);
+       data->type = id->driver_data;
+       mutex_init(&data->update_lock);
+
+       /* Register sysfs hooks */
+       err = sysfs_create_group(&client->dev.kobj, &max1668_group_common);
+       if (err)
+               goto error_free;
+
+       if (data->type == max1668 || data->type == max1989) {
+               err = sysfs_create_group(&client->dev.kobj,
+                                        &max1668_group_unique);
+               if (err)
+                       goto error_sysrem0;
+       }
+
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               goto error_sysrem1;
+       }
+
+       return 0;
+
+error_sysrem1:
+       if (data->type == max1668 || data->type == max1989)
+               sysfs_remove_group(&client->dev.kobj, &max1668_group_unique);
+error_sysrem0:
+       sysfs_remove_group(&client->dev.kobj, &max1668_group_common);
+error_free:
+       kfree(data);
+       return err;
+}
+
+static int max1668_remove(struct i2c_client *client)
+{
+       struct max1668_data *data = i2c_get_clientdata(client);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       if (data->type == max1668 || data->type == max1989)
+               sysfs_remove_group(&client->dev.kobj, &max1668_group_unique);
+
+       sysfs_remove_group(&client->dev.kobj, &max1668_group_common);
+
+       kfree(data);
+       return 0;
+}
+
+static const struct i2c_device_id max1668_id[] = {
+       { "max1668", max1668 },
+       { "max1805", max1805 },
+       { "max1989", max1989 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, max1668_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver max1668_driver = {
+       .class = I2C_CLASS_HWMON,
+       .driver = {
+                 .name = "max1668",
+                 },
+       .probe = max1668_probe,
+       .remove = max1668_remove,
+       .id_table = max1668_id,
+       .detect = max1668_detect,
+       .address_list = max1668_addr_list,
+};
+
+static int __init sensors_max1668_init(void)
+{
+       return i2c_add_driver(&max1668_driver);
+}
+
+static void __exit sensors_max1668_exit(void)
+{
+       i2c_del_driver(&max1668_driver);
+}
+
+MODULE_AUTHOR("David George <david.george@ska.ac.za>");
+MODULE_DESCRIPTION("MAX1668 remote temperature sensor driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_max1668_init)
+module_exit(sensors_max1668_exit)
diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c
new file mode 100644 (file)
index 0000000..d7926f4
--- /dev/null
@@ -0,0 +1,453 @@
+/*
+ * ntc_thermistor.c - NTC Thermistors
+ *
+ *  Copyright (C) 2010 Samsung Electronics
+ *  MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/math64.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+
+#include <linux/platform_data/ntc_thermistor.h>
+
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+struct ntc_compensation {
+       int             temp_C;
+       unsigned int    ohm;
+};
+
+/*
+ * A compensation table should be sorted by the values of .ohm
+ * in descending order.
+ * The following compensation tables are from the specification of Murata NTC
+ * Thermistors Datasheet
+ */
+const struct ntc_compensation ncpXXwb473[] = {
+       { .temp_C       = -40, .ohm     = 1747920 },
+       { .temp_C       = -35, .ohm     = 1245428 },
+       { .temp_C       = -30, .ohm     = 898485 },
+       { .temp_C       = -25, .ohm     = 655802 },
+       { .temp_C       = -20, .ohm     = 483954 },
+       { .temp_C       = -15, .ohm     = 360850 },
+       { .temp_C       = -10, .ohm     = 271697 },
+       { .temp_C       = -5, .ohm      = 206463 },
+       { .temp_C       = 0, .ohm       = 158214 },
+       { .temp_C       = 5, .ohm       = 122259 },
+       { .temp_C       = 10, .ohm      = 95227 },
+       { .temp_C       = 15, .ohm      = 74730 },
+       { .temp_C       = 20, .ohm      = 59065 },
+       { .temp_C       = 25, .ohm      = 47000 },
+       { .temp_C       = 30, .ohm      = 37643 },
+       { .temp_C       = 35, .ohm      = 30334 },
+       { .temp_C       = 40, .ohm      = 24591 },
+       { .temp_C       = 45, .ohm      = 20048 },
+       { .temp_C       = 50, .ohm      = 16433 },
+       { .temp_C       = 55, .ohm      = 13539 },
+       { .temp_C       = 60, .ohm      = 11209 },
+       { .temp_C       = 65, .ohm      = 9328 },
+       { .temp_C       = 70, .ohm      = 7798 },
+       { .temp_C       = 75, .ohm      = 6544 },
+       { .temp_C       = 80, .ohm      = 5518 },
+       { .temp_C       = 85, .ohm      = 4674 },
+       { .temp_C       = 90, .ohm      = 3972 },
+       { .temp_C       = 95, .ohm      = 3388 },
+       { .temp_C       = 100, .ohm     = 2902 },
+       { .temp_C       = 105, .ohm     = 2494 },
+       { .temp_C       = 110, .ohm     = 2150 },
+       { .temp_C       = 115, .ohm     = 1860 },
+       { .temp_C       = 120, .ohm     = 1615 },
+       { .temp_C       = 125, .ohm     = 1406 },
+};
+const struct ntc_compensation ncpXXwl333[] = {
+       { .temp_C       = -40, .ohm     = 1610154 },
+       { .temp_C       = -35, .ohm     = 1130850 },
+       { .temp_C       = -30, .ohm     = 802609 },
+       { .temp_C       = -25, .ohm     = 575385 },
+       { .temp_C       = -20, .ohm     = 416464 },
+       { .temp_C       = -15, .ohm     = 304219 },
+       { .temp_C       = -10, .ohm     = 224193 },
+       { .temp_C       = -5, .ohm      = 166623 },
+       { .temp_C       = 0, .ohm       = 124850 },
+       { .temp_C       = 5, .ohm       = 94287 },
+       { .temp_C       = 10, .ohm      = 71747 },
+       { .temp_C       = 15, .ohm      = 54996 },
+       { .temp_C       = 20, .ohm      = 42455 },
+       { .temp_C       = 25, .ohm      = 33000 },
+       { .temp_C       = 30, .ohm      = 25822 },
+       { .temp_C       = 35, .ohm      = 20335 },
+       { .temp_C       = 40, .ohm      = 16115 },
+       { .temp_C       = 45, .ohm      = 12849 },
+       { .temp_C       = 50, .ohm      = 10306 },
+       { .temp_C       = 55, .ohm      = 8314 },
+       { .temp_C       = 60, .ohm      = 6746 },
+       { .temp_C       = 65, .ohm      = 5503 },
+       { .temp_C       = 70, .ohm      = 4513 },
+       { .temp_C       = 75, .ohm      = 3721 },
+       { .temp_C       = 80, .ohm      = 3084 },
+       { .temp_C       = 85, .ohm      = 2569 },
+       { .temp_C       = 90, .ohm      = 2151 },
+       { .temp_C       = 95, .ohm      = 1809 },
+       { .temp_C       = 100, .ohm     = 1529 },
+       { .temp_C       = 105, .ohm     = 1299 },
+       { .temp_C       = 110, .ohm     = 1108 },
+       { .temp_C       = 115, .ohm     = 949 },
+       { .temp_C       = 120, .ohm     = 817 },
+       { .temp_C       = 125, .ohm     = 707 },
+};
+
+struct ntc_data {
+       struct device *hwmon_dev;
+       struct ntc_thermistor_platform_data *pdata;
+       const struct ntc_compensation *comp;
+       struct device *dev;
+       int n_comp;
+       char name[PLATFORM_NAME_SIZE];
+};
+
+static inline u64 div64_u64_safe(u64 dividend, u64 divisor)
+{
+       if (divisor == 0 && dividend == 0)
+               return 0;
+       if (divisor == 0)
+               return UINT_MAX;
+       return div64_u64(dividend, divisor);
+}
+
+static unsigned int get_ohm_of_thermistor(struct ntc_data *data,
+               unsigned int uV)
+{
+       struct ntc_thermistor_platform_data *pdata = data->pdata;
+       u64 mV = uV / 1000;
+       u64 pmV = pdata->pullup_uV / 1000;
+       u64 N, puO, pdO;
+       puO = pdata->pullup_ohm;
+       pdO = pdata->pulldown_ohm;
+
+       if (mV == 0) {
+               if (pdata->connect == NTC_CONNECTED_POSITIVE)
+                       return UINT_MAX;
+               return 0;
+       }
+       if (mV >= pmV)
+               return (pdata->connect == NTC_CONNECTED_POSITIVE) ?
+                       0 : UINT_MAX;
+
+       if (pdata->connect == NTC_CONNECTED_POSITIVE && puO == 0)
+               N = div64_u64_safe(pdO * (pmV - mV), mV);
+       else if (pdata->connect == NTC_CONNECTED_GROUND && pdO == 0)
+               N = div64_u64_safe(puO * mV, pmV - mV);
+       else if (pdata->connect == NTC_CONNECTED_POSITIVE)
+               N = div64_u64_safe(pdO * puO * (pmV - mV),
+                               puO * mV - pdO * (pmV - mV));
+       else
+               N = div64_u64_safe(pdO * puO * mV, pdO * (pmV - mV) - puO * mV);
+
+       return (unsigned int) N;
+}
+
+static int lookup_comp(struct ntc_data *data,
+               unsigned int ohm, int *i_low, int *i_high)
+{
+       int start, end, mid = -1;
+
+       /* Do a binary search on compensation table */
+       start = 0;
+       end = data->n_comp;
+
+       while (end > start) {
+               mid = start + (end - start) / 2;
+               if (data->comp[mid].ohm < 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;
+               }
+       }
+
+       if (data->comp[mid].ohm <= ohm) {
+               *i_low = mid;
+               *i_high = mid - 1;
+       }
+       if (data->comp[mid].ohm > ohm) {
+               *i_low = mid + 1;
+               *i_high = mid;
+       }
+
+       return 0;
+}
+
+static int get_temp_mC(struct ntc_data *data, unsigned int ohm, int *temp)
+{
+       int low, high;
+       int ret;
+
+       ret = lookup_comp(data, ohm, &low, &high);
+       if (ret) {
+               /* 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;
+       } else {
+               *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;
+}
+
+static int ntc_thermistor_read(struct ntc_data *data, int *temp)
+{
+       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;
+       }
+
+       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 0;
+}
+
+static ssize_t ntc_show_name(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct ntc_data *data = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%s\n", data->name);
+}
+
+static ssize_t ntc_show_type(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "4\n");
+}
+
+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;
+
+       ret = ntc_thermistor_read(data, &temp);
+       if (ret)
+               return ret;
+       return sprintf(buf, "%d\n", temp);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, ntc_show_type, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ntc_show_temp, NULL, 0);
+static DEVICE_ATTR(name, S_IRUGO, ntc_show_name, NULL);
+
+static struct attribute *ntc_attributes[] = {
+       &dev_attr_name.attr,
+       &sensor_dev_attr_temp1_type.dev_attr.attr,
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group ntc_attr_group = {
+       .attrs = ntc_attributes,
+};
+
+static int __devinit ntc_thermistor_probe(struct platform_device *pdev)
+{
+       struct ntc_data *data;
+       struct ntc_thermistor_platform_data *pdata = pdev->dev.platform_data;
+       int ret = 0;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "No platform init data supplied.\n");
+               return -ENODEV;
+       }
+
+       /* 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");
+               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");
+               pdata->read_uV = NULL;
+       }
+
+       if (pdata->read_uV && (pdata->pullup_uV == 0 ||
+                               (pdata->pullup_ohm == 0 && pdata->connect ==
+                                NTC_CONNECTED_GROUND) ||
+                               (pdata->pulldown_ohm == 0 && pdata->connect ==
+                                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");
+               return -EINVAL;
+       }
+
+       data = kzalloc(sizeof(struct ntc_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->dev = &pdev->dev;
+       data->pdata = pdata;
+       strncpy(data->name, pdev->id_entry->name, PLATFORM_NAME_SIZE);
+
+       switch (pdev->id_entry->driver_data) {
+       case TYPE_NCPXXWB473:
+               data->comp = ncpXXwb473;
+               data->n_comp = ARRAY_SIZE(ncpXXwb473);
+               break;
+       case TYPE_NCPXXWL333:
+               data->comp = ncpXXwl333;
+               data->n_comp = ARRAY_SIZE(ncpXXwl333);
+               break;
+       default:
+               dev_err(&pdev->dev, "Unknown device type: %lu(%s)\n",
+                               pdev->id_entry->driver_data,
+                               pdev->id_entry->name);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       platform_set_drvdata(pdev, data);
+
+       ret = sysfs_create_group(&data->dev->kobj, &ntc_attr_group);
+       if (ret) {
+               dev_err(data->dev, "unable to create sysfs files\n");
+               goto err;
+       }
+
+       data->hwmon_dev = hwmon_device_register(data->dev);
+       if (IS_ERR_OR_NULL(data->hwmon_dev)) {
+               dev_err(data->dev, "unable to register as hwmon device.\n");
+               ret = -EINVAL;
+               goto err_after_sysfs;
+       }
+
+       dev_info(&pdev->dev, "Thermistor %s:%d (type: %s/%lu) successfully probed.\n",
+                       pdev->name, pdev->id, pdev->id_entry->name,
+                       pdev->id_entry->driver_data);
+       return 0;
+err_after_sysfs:
+       sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
+err:
+       kfree(data);
+       return ret;
+}
+
+static int __devexit ntc_thermistor_remove(struct platform_device *pdev)
+{
+       struct ntc_data *data = platform_get_drvdata(pdev);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
+       platform_set_drvdata(pdev, NULL);
+
+       kfree(data);
+
+       return 0;
+}
+
+static const struct platform_device_id ntc_thermistor_id[] = {
+       { "ncp15wb473", TYPE_NCPXXWB473 },
+       { "ncp18wb473", TYPE_NCPXXWB473 },
+       { "ncp21wb473", TYPE_NCPXXWB473 },
+       { "ncp03wb473", TYPE_NCPXXWB473 },
+       { "ncp15wl333", TYPE_NCPXXWL333 },
+       { },
+};
+
+static struct platform_driver ntc_thermistor_driver = {
+       .driver = {
+               .name = "ntc-thermistor",
+               .owner = THIS_MODULE,
+       },
+       .probe = ntc_thermistor_probe,
+       .remove = __devexit_p(ntc_thermistor_remove),
+       .id_table = ntc_thermistor_id,
+};
+
+static int __init ntc_thermistor_init(void)
+{
+       return platform_driver_register(&ntc_thermistor_driver);
+}
+
+module_init(ntc_thermistor_init);
+
+static void __exit ntc_thermistor_cleanup(void)
+{
+       platform_driver_unregister(&ntc_thermistor_driver);
+}
+
+module_exit(ntc_thermistor_cleanup);
+
+MODULE_DESCRIPTION("NTC Thermistor Driver");
+MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ntc-thermistor");
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
new file mode 100644 (file)
index 0000000..c9237b9
--- /dev/null
@@ -0,0 +1,100 @@
+#
+# PMBus chip drivers configuration
+#
+
+menuconfig PMBUS
+       tristate "PMBus support"
+       depends on I2C && EXPERIMENTAL
+       default n
+       help
+         Say yes here if you want to enable PMBus support.
+
+         This driver can also be built as a module. If so, the module will
+         be called pmbus_core.
+
+if PMBUS
+
+config SENSORS_PMBUS
+       tristate "Generic PMBus devices"
+       default y
+       help
+         If you say yes here you get hardware monitoring support for generic
+         PMBus devices, including but not limited to ADP4000, BMR450, BMR451,
+         BMR453, BMR454, LTC2978, NCP4200, and NCP4208.
+
+         This driver can also be built as a module. If so, the module will
+         be called pmbus.
+
+config SENSORS_ADM1275
+       tristate "Analog Devices ADM1275"
+       default n
+       help
+         If you say yes here you get hardware monitoring support for Analog
+         Devices ADM1275 Hot-Swap Controller and Digital Power Monitor.
+
+         This driver can also be built as a module. If so, the module will
+         be called adm1275.
+
+config SENSORS_LM25066
+       tristate "National Semiconductor LM25066 and compatibles"
+       default n
+       help
+         If you say yes here you get hardware monitoring support for National
+         Semiconductor LM25066, LM5064, and LM5066.
+
+         This driver can also be built as a module. If so, the module will
+         be called lm25066.
+
+config SENSORS_MAX16064
+       tristate "Maxim MAX16064"
+       default n
+       help
+         If you say yes here you get hardware monitoring support for Maxim
+         MAX16064.
+
+         This driver can also be built as a module. If so, the module will
+         be called max16064.
+
+config SENSORS_MAX34440
+       tristate "Maxim MAX34440/MAX34441"
+       default n
+       help
+         If you say yes here you get hardware monitoring support for Maxim
+         MAX34440 and MAX34441.
+
+         This driver can also be built as a module. If so, the module will
+         be called max34440.
+
+config SENSORS_MAX8688
+       tristate "Maxim MAX8688"
+       default n
+       help
+         If you say yes here you get hardware monitoring support for Maxim
+         MAX8688.
+
+         This driver can also be built as a module. If so, the module will
+         be called max8688.
+
+config SENSORS_UCD9000
+       tristate "TI UCD90120, UCD90124, UCD9090, UCD90910"
+       default n
+       help
+         If you say yes here you get hardware monitoring support for TI
+         UCD90120, UCD90124, UCD9090, UCD90910 Sequencer and System Health
+         Controllers.
+
+         This driver can also be built as a module. If so, the module will
+         be called ucd9000.
+
+config SENSORS_UCD9200
+       tristate "TI UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, UCD9248"
+       default n
+       help
+         If you say yes here you get hardware monitoring support for TI
+         UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, and UCD9248
+         Digital PWM System Controllers.
+
+         This driver can also be built as a module. If so, the module will
+         be called ucd9200.
+
+endif # PMBUS
diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile
new file mode 100644 (file)
index 0000000..623eedb
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# Makefile for PMBus chip drivers.
+#
+
+obj-$(CONFIG_PMBUS)            += pmbus_core.o
+obj-$(CONFIG_SENSORS_PMBUS)    += pmbus.o
+obj-$(CONFIG_SENSORS_ADM1275)  += adm1275.o
+obj-$(CONFIG_SENSORS_LM25066)  += lm25066.o
+obj-$(CONFIG_SENSORS_MAX16064) += max16064.o
+obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
+obj-$(CONFIG_SENSORS_MAX8688)  += max8688.o
+obj-$(CONFIG_SENSORS_UCD9000)  += ucd9000.o
+obj-$(CONFIG_SENSORS_UCD9200)  += ucd9200.o
similarity index 67%
rename from drivers/hwmon/adm1275.c
rename to drivers/hwmon/pmbus/adm1275.c
index 8bc1bd6..c936e27 100644 (file)
 #include <linux/i2c.h>
 #include "pmbus.h"
 
+#define ADM1275_PEAK_IOUT              0xd0
+#define ADM1275_PEAK_VIN               0xd1
+#define ADM1275_PEAK_VOUT              0xd2
 #define ADM1275_PMON_CONFIG            0xd4
 
 #define ADM1275_VIN_VOUT_SELECT                (1 << 6)
 #define ADM1275_VRANGE                 (1 << 5)
 
+static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
+{
+       int ret;
+
+       if (page)
+               return -EINVAL;
+
+       switch (reg) {
+       case PMBUS_VIRT_READ_IOUT_MAX:
+               ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_IOUT);
+               break;
+       case PMBUS_VIRT_READ_VOUT_MAX:
+               ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VOUT);
+               break;
+       case PMBUS_VIRT_READ_VIN_MAX:
+               ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VIN);
+               break;
+       case PMBUS_VIRT_RESET_IOUT_HISTORY:
+       case PMBUS_VIRT_RESET_VOUT_HISTORY:
+       case PMBUS_VIRT_RESET_VIN_HISTORY:
+               ret = 0;
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
+static int adm1275_write_word_data(struct i2c_client *client, int page, int reg,
+                                  u16 word)
+{
+       int ret;
+
+       if (page)
+               return -EINVAL;
+
+       switch (reg) {
+       case PMBUS_VIRT_RESET_IOUT_HISTORY:
+               ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_IOUT, 0);
+               break;
+       case PMBUS_VIRT_RESET_VOUT_HISTORY:
+               ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VOUT, 0);
+               break;
+       case PMBUS_VIRT_RESET_VIN_HISTORY:
+               ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VIN, 0);
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
 static int adm1275_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
@@ -50,14 +107,17 @@ static int adm1275_probe(struct i2c_client *client,
        }
 
        info->pages = 1;
-       info->direct[PSC_VOLTAGE_IN] = true;
-       info->direct[PSC_VOLTAGE_OUT] = true;
-       info->direct[PSC_CURRENT_OUT] = true;
+       info->format[PSC_VOLTAGE_IN] = direct;
+       info->format[PSC_VOLTAGE_OUT] = direct;
+       info->format[PSC_CURRENT_OUT] = direct;
        info->m[PSC_CURRENT_OUT] = 807;
        info->b[PSC_CURRENT_OUT] = 20475;
        info->R[PSC_CURRENT_OUT] = -1;
        info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
 
+       info->read_word_data = adm1275_read_word_data;
+       info->write_word_data = adm1275_write_word_data;
+
        if (config & ADM1275_VRANGE) {
                info->m[PSC_VOLTAGE_IN] = 19199;
                info->b[PSC_VOLTAGE_IN] = 0;
diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c
new file mode 100644 (file)
index 0000000..ac254fb
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * Hardware monitoring driver for LM25066 / LM5064 / LM5066
+ *
+ * Copyright (c) 2011 Ericsson 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include "pmbus.h"
+
+enum chips { lm25066, lm5064, lm5066 };
+
+#define LM25066_READ_VAUX              0xd0
+#define LM25066_MFR_READ_IIN           0xd1
+#define LM25066_MFR_READ_PIN           0xd2
+#define LM25066_MFR_IIN_OC_WARN_LIMIT  0xd3
+#define LM25066_MFR_PIN_OP_WARN_LIMIT  0xd4
+#define LM25066_READ_PIN_PEAK          0xd5
+#define LM25066_CLEAR_PIN_PEAK         0xd6
+#define LM25066_DEVICE_SETUP           0xd9
+#define LM25066_READ_AVG_VIN           0xdc
+#define LM25066_READ_AVG_VOUT          0xdd
+#define LM25066_READ_AVG_IIN           0xde
+#define LM25066_READ_AVG_PIN           0xdf
+
+#define LM25066_DEV_SETUP_CL           (1 << 4)        /* Current limit */
+
+struct lm25066_data {
+       int id;
+       struct pmbus_driver_info info;
+};
+
+#define to_lm25066_data(x)  container_of(x, struct lm25066_data, info)
+
+static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)
+{
+       const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+       const struct lm25066_data *data = to_lm25066_data(info);
+       int ret;
+
+       if (page > 1)
+               return -EINVAL;
+
+       /* Map READ_VAUX into READ_VOUT register on page 1 */
+       if (page == 1) {
+               switch (reg) {
+               case PMBUS_READ_VOUT:
+                       ret = pmbus_read_word_data(client, 0,
+                                                  LM25066_READ_VAUX);
+                       if (ret < 0)
+                               break;
+                       /* Adjust returned value to match VOUT coefficients */
+                       switch (data->id) {
+                       case lm25066:
+                               /* VOUT: 4.54 mV VAUX: 283.2 uV LSB */
+                               ret = DIV_ROUND_CLOSEST(ret * 2832, 45400);
+                               break;
+                       case lm5064:
+                               /* VOUT: 4.53 mV VAUX: 700 uV LSB */
+                               ret = DIV_ROUND_CLOSEST(ret * 70, 453);
+                               break;
+                       case lm5066:
+                               /* VOUT: 2.18 mV VAUX: 725 uV LSB */
+                               ret = DIV_ROUND_CLOSEST(ret * 725, 2180);
+                               break;
+                       }
+                       break;
+               default:
+                       /* No other valid registers on page 1 */
+                       ret = -EINVAL;
+                       break;
+               }
+               goto done;
+       }
+
+       switch (reg) {
+       case PMBUS_READ_IIN:
+               ret = pmbus_read_word_data(client, 0, LM25066_MFR_READ_IIN);
+               break;
+       case PMBUS_READ_PIN:
+               ret = pmbus_read_word_data(client, 0, LM25066_MFR_READ_PIN);
+               break;
+       case PMBUS_IIN_OC_WARN_LIMIT:
+               ret = pmbus_read_word_data(client, 0,
+                                          LM25066_MFR_IIN_OC_WARN_LIMIT);
+               break;
+       case PMBUS_PIN_OP_WARN_LIMIT:
+               ret = pmbus_read_word_data(client, 0,
+                                          LM25066_MFR_PIN_OP_WARN_LIMIT);
+               break;
+       case PMBUS_VIRT_READ_VIN_AVG:
+               ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_VIN);
+               break;
+       case PMBUS_VIRT_READ_VOUT_AVG:
+               ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_VOUT);
+               break;
+       case PMBUS_VIRT_READ_IIN_AVG:
+               ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_IIN);
+               break;
+       case PMBUS_VIRT_READ_PIN_AVG:
+               ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_PIN);
+               break;
+       case PMBUS_VIRT_READ_PIN_MAX:
+               ret = pmbus_read_word_data(client, 0, LM25066_READ_PIN_PEAK);
+               break;
+       case PMBUS_VIRT_RESET_PIN_HISTORY:
+               ret = 0;
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+done:
+       return ret;
+}
+
+static int lm25066_write_word_data(struct i2c_client *client, int page, int reg,
+                                  u16 word)
+{
+       int ret;
+
+       if (page > 1)
+               return -EINVAL;
+
+       switch (reg) {
+       case PMBUS_IIN_OC_WARN_LIMIT:
+               ret = pmbus_write_word_data(client, 0,
+                                           LM25066_MFR_IIN_OC_WARN_LIMIT,
+                                           word);
+               break;
+       case PMBUS_PIN_OP_WARN_LIMIT:
+               ret = pmbus_write_word_data(client, 0,
+                                           LM25066_MFR_PIN_OP_WARN_LIMIT,
+                                           word);
+               break;
+       case PMBUS_VIRT_RESET_PIN_HISTORY:
+               ret = pmbus_write_byte(client, 0, LM25066_CLEAR_PIN_PEAK);
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
+static int lm25066_write_byte(struct i2c_client *client, int page, u8 value)
+{
+       if (page > 1)
+               return -EINVAL;
+
+       if (page == 0)
+               return pmbus_write_byte(client, 0, value);
+
+       return 0;
+}
+
+static int lm25066_probe(struct i2c_client *client,
+                         const struct i2c_device_id *id)
+{
+       int config;
+       int ret;
+       struct lm25066_data *data;
+       struct pmbus_driver_info *info;
+
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_READ_BYTE_DATA))
+               return -ENODEV;
+
+       data = kzalloc(sizeof(struct lm25066_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       config = i2c_smbus_read_byte_data(client, LM25066_DEVICE_SETUP);
+       if (config < 0) {
+               ret = config;
+               goto err_mem;
+       }
+
+       data->id = id->driver_data;
+       info = &data->info;
+
+       info->pages = 2;
+       info->format[PSC_VOLTAGE_IN] = direct;
+       info->format[PSC_VOLTAGE_OUT] = direct;
+       info->format[PSC_CURRENT_IN] = direct;
+       info->format[PSC_TEMPERATURE] = direct;
+       info->format[PSC_POWER] = direct;
+
+       info->m[PSC_TEMPERATURE] = 16;
+       info->b[PSC_TEMPERATURE] = 0;
+       info->R[PSC_TEMPERATURE] = 0;
+
+       info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT
+         | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_PIN | PMBUS_HAVE_IIN
+         | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
+       info->func[1] = PMBUS_HAVE_VOUT;
+
+       info->read_word_data = lm25066_read_word_data;
+       info->write_word_data = lm25066_write_word_data;
+       info->write_byte = lm25066_write_byte;
+
+       switch (id->driver_data) {
+       case lm25066:
+               info->m[PSC_VOLTAGE_IN] = 22070;
+               info->b[PSC_VOLTAGE_IN] = 0;
+               info->R[PSC_VOLTAGE_IN] = -2;
+               info->m[PSC_VOLTAGE_OUT] = 22070;
+               info->b[PSC_VOLTAGE_OUT] = 0;
+               info->R[PSC_VOLTAGE_OUT] = -2;
+
+               if (config & LM25066_DEV_SETUP_CL) {
+                       info->m[PSC_CURRENT_IN] = 6852;
+                       info->b[PSC_CURRENT_IN] = 0;
+                       info->R[PSC_CURRENT_IN] = -2;
+                       info->m[PSC_POWER] = 369;
+                       info->b[PSC_POWER] = 0;
+                       info->R[PSC_POWER] = -2;
+               } else {
+                       info->m[PSC_CURRENT_IN] = 13661;
+                       info->b[PSC_CURRENT_IN] = 0;
+                       info->R[PSC_CURRENT_IN] = -2;
+                       info->m[PSC_POWER] = 736;
+                       info->b[PSC_POWER] = 0;
+                       info->R[PSC_POWER] = -2;
+               }
+               break;
+       case lm5064:
+               info->m[PSC_VOLTAGE_IN] = 22075;
+               info->b[PSC_VOLTAGE_IN] = 0;
+               info->R[PSC_VOLTAGE_IN] = -2;
+               info->m[PSC_VOLTAGE_OUT] = 22075;
+               info->b[PSC_VOLTAGE_OUT] = 0;
+               info->R[PSC_VOLTAGE_OUT] = -2;
+
+               if (config & LM25066_DEV_SETUP_CL) {
+                       info->m[PSC_CURRENT_IN] = 6713;
+                       info->b[PSC_CURRENT_IN] = 0;
+                       info->R[PSC_CURRENT_IN] = -2;
+                       info->m[PSC_POWER] = 3619;
+                       info->b[PSC_POWER] = 0;
+                       info->R[PSC_POWER] = -3;
+               } else {
+                       info->m[PSC_CURRENT_IN] = 13426;
+                       info->b[PSC_CURRENT_IN] = 0;
+                       info->R[PSC_CURRENT_IN] = -2;
+                       info->m[PSC_POWER] = 7238;
+                       info->b[PSC_POWER] = 0;
+                       info->R[PSC_POWER] = -3;
+               }
+               break;
+       case lm5066:
+               info->m[PSC_VOLTAGE_IN] = 4587;
+               info->b[PSC_VOLTAGE_IN] = 0;
+               info->R[PSC_VOLTAGE_IN] = -2;
+               info->m[PSC_VOLTAGE_OUT] = 4587;
+               info->b[PSC_VOLTAGE_OUT] = 0;
+               info->R[PSC_VOLTAGE_OUT] = -2;
+
+               if (config & LM25066_DEV_SETUP_CL) {
+                       info->m[PSC_CURRENT_IN] = 10753;
+                       info->b[PSC_CURRENT_IN] = 0;
+                       info->R[PSC_CURRENT_IN] = -2;
+                       info->m[PSC_POWER] = 1204;
+                       info->b[PSC_POWER] = 0;
+                       info->R[PSC_POWER] = -3;
+               } else {
+                       info->m[PSC_CURRENT_IN] = 5405;
+                       info->b[PSC_CURRENT_IN] = 0;
+                       info->R[PSC_CURRENT_IN] = -2;
+                       info->m[PSC_POWER] = 605;
+                       info->b[PSC_POWER] = 0;
+                       info->R[PSC_POWER] = -3;
+               }
+               break;
+       default:
+               ret = -ENODEV;
+               goto err_mem;
+       }
+
+       ret = pmbus_do_probe(client, id, info);
+       if (ret)
+               goto err_mem;
+       return 0;
+
+err_mem:
+       kfree(data);
+       return ret;
+}
+
+static int lm25066_remove(struct i2c_client *client)
+{
+       const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+       const struct lm25066_data *data = to_lm25066_data(info);
+       int ret;
+
+       ret = pmbus_do_remove(client);
+       kfree(data);
+       return ret;
+}
+
+static const struct i2c_device_id lm25066_id[] = {
+       {"lm25066", lm25066},
+       {"lm5064", lm5064},
+       {"lm5066", lm5066},
+       { }
+};
+
+MODULE_DEVICE_TABLE(i2c, lm25066_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver lm25066_driver = {
+       .driver = {
+                  .name = "lm25066",
+                  },
+       .probe = lm25066_probe,
+       .remove = lm25066_remove,
+       .id_table = lm25066_id,
+};
+
+static int __init lm25066_init(void)
+{
+       return i2c_add_driver(&lm25066_driver);
+}
+
+static void __exit lm25066_exit(void)
+{
+       i2c_del_driver(&lm25066_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for LM25066/LM5064/LM5066");
+MODULE_LICENSE("GPL");
+module_init(lm25066_init);
+module_exit(lm25066_exit);
similarity index 66%
rename from drivers/hwmon/max16064.c
rename to drivers/hwmon/pmbus/max16064.c
index 1d6d717..e50b296 100644 (file)
 #include <linux/i2c.h>
 #include "pmbus.h"
 
+#define MAX16064_MFR_VOUT_PEAK         0xd4
+#define MAX16064_MFR_TEMPERATURE_PEAK  0xd6
+
+static int max16064_read_word_data(struct i2c_client *client, int page, int reg)
+{
+       int ret;
+
+       switch (reg) {
+       case PMBUS_VIRT_READ_VOUT_MAX:
+               ret = pmbus_read_word_data(client, page,
+                                          MAX16064_MFR_VOUT_PEAK);
+               break;
+       case PMBUS_VIRT_READ_TEMP_MAX:
+               ret = pmbus_read_word_data(client, page,
+                                          MAX16064_MFR_TEMPERATURE_PEAK);
+               break;
+       case PMBUS_VIRT_RESET_VOUT_HISTORY:
+       case PMBUS_VIRT_RESET_TEMP_HISTORY:
+               ret = 0;
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
+static int max16064_write_word_data(struct i2c_client *client, int page,
+                                   int reg, u16 word)
+{
+       int ret;
+
+       switch (reg) {
+       case PMBUS_VIRT_RESET_VOUT_HISTORY:
+               ret = pmbus_write_word_data(client, page,
+                                           MAX16064_MFR_VOUT_PEAK, 0);
+               break;
+       case PMBUS_VIRT_RESET_TEMP_HISTORY:
+               ret = pmbus_write_word_data(client, page,
+                                           MAX16064_MFR_TEMPERATURE_PEAK,
+                                           0xffff);
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
 static struct pmbus_driver_info max16064_info = {
        .pages = 4,
-       .direct[PSC_VOLTAGE_IN] = true,
-       .direct[PSC_VOLTAGE_OUT] = true,
-       .direct[PSC_TEMPERATURE] = true,
+       .format[PSC_VOLTAGE_IN] = direct,
+       .format[PSC_VOLTAGE_OUT] = direct,
+       .format[PSC_TEMPERATURE] = direct,
        .m[PSC_VOLTAGE_IN] = 19995,
        .b[PSC_VOLTAGE_IN] = 0,
        .R[PSC_VOLTAGE_IN] = -1,
@@ -44,6 +93,8 @@ static struct pmbus_driver_info max16064_info = {
        .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
        .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
        .func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+       .read_word_data = max16064_read_word_data,
+       .write_word_data = max16064_write_word_data,
 };
 
 static int max16064_probe(struct i2c_client *client,
similarity index 76%
rename from drivers/hwmon/max34440.c
rename to drivers/hwmon/pmbus/max34440.c
index db11e1a..fda621d 100644 (file)
 
 enum chips { max34440, max34441 };
 
+#define MAX34440_MFR_VOUT_PEAK         0xd4
+#define MAX34440_MFR_IOUT_PEAK         0xd5
+#define MAX34440_MFR_TEMPERATURE_PEAK  0xd6
+
 #define MAX34440_STATUS_OC_WARN                (1 << 0)
 #define MAX34440_STATUS_OC_FAULT       (1 << 1)
 #define MAX34440_STATUS_OT_FAULT       (1 << 5)
 #define MAX34440_STATUS_OT_WARN                (1 << 6)
 
+static int max34440_read_word_data(struct i2c_client *client, int page, int reg)
+{
+       int ret;
+
+       switch (reg) {
+       case PMBUS_VIRT_READ_VOUT_MAX:
+               ret = pmbus_read_word_data(client, page,
+                                          MAX34440_MFR_VOUT_PEAK);
+               break;
+       case PMBUS_VIRT_READ_IOUT_MAX:
+               ret = pmbus_read_word_data(client, page,
+                                          MAX34440_MFR_IOUT_PEAK);
+               break;
+       case PMBUS_VIRT_READ_TEMP_MAX:
+               ret = pmbus_read_word_data(client, page,
+                                          MAX34440_MFR_TEMPERATURE_PEAK);
+               break;
+       case PMBUS_VIRT_RESET_VOUT_HISTORY:
+       case PMBUS_VIRT_RESET_IOUT_HISTORY:
+       case PMBUS_VIRT_RESET_TEMP_HISTORY:
+               ret = 0;
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
+static int max34440_write_word_data(struct i2c_client *client, int page,
+                                   int reg, u16 word)
+{
+       int ret;
+
+       switch (reg) {
+       case PMBUS_VIRT_RESET_VOUT_HISTORY:
+               ret = pmbus_write_word_data(client, page,
+                                           MAX34440_MFR_VOUT_PEAK, 0);
+               break;
+       case PMBUS_VIRT_RESET_IOUT_HISTORY:
+               ret = pmbus_write_word_data(client, page,
+                                           MAX34440_MFR_IOUT_PEAK, 0);
+               break;
+       case PMBUS_VIRT_RESET_TEMP_HISTORY:
+               ret = pmbus_write_word_data(client, page,
+                                           MAX34440_MFR_TEMPERATURE_PEAK,
+                                           0xffff);
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
 static int max34440_read_byte_data(struct i2c_client *client, int page, int reg)
 {
        int ret;
@@ -72,10 +131,10 @@ static int max34440_read_byte_data(struct i2c_client *client, int page, int reg)
 static struct pmbus_driver_info max34440_info[] = {
        [max34440] = {
                .pages = 14,
-               .direct[PSC_VOLTAGE_IN] = true,
-               .direct[PSC_VOLTAGE_OUT] = true,
-               .direct[PSC_TEMPERATURE] = true,
-               .direct[PSC_CURRENT_OUT] = true,
+               .format[PSC_VOLTAGE_IN] = direct,
+               .format[PSC_VOLTAGE_OUT] = direct,
+               .format[PSC_TEMPERATURE] = direct,
+               .format[PSC_CURRENT_OUT] = direct,
                .m[PSC_VOLTAGE_IN] = 1,
                .b[PSC_VOLTAGE_IN] = 0,
                .R[PSC_VOLTAGE_IN] = 3,     /* R = 0 in datasheet reflects mV */
@@ -109,14 +168,16 @@ static struct pmbus_driver_info max34440_info[] = {
                .func[12] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
                .func[13] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
                .read_byte_data = max34440_read_byte_data,
+               .read_word_data = max34440_read_word_data,
+               .write_word_data = max34440_write_word_data,
        },
        [max34441] = {
                .pages = 12,
-               .direct[PSC_VOLTAGE_IN] = true,
-               .direct[PSC_VOLTAGE_OUT] = true,
-               .direct[PSC_TEMPERATURE] = true,
-               .direct[PSC_CURRENT_OUT] = true,
-               .direct[PSC_FAN] = true,
+               .format[PSC_VOLTAGE_IN] = direct,
+               .format[PSC_VOLTAGE_OUT] = direct,
+               .format[PSC_TEMPERATURE] = direct,
+               .format[PSC_CURRENT_OUT] = direct,
+               .format[PSC_FAN] = direct,
                .m[PSC_VOLTAGE_IN] = 1,
                .b[PSC_VOLTAGE_IN] = 0,
                .R[PSC_VOLTAGE_IN] = 3,
@@ -150,6 +211,8 @@ static struct pmbus_driver_info max34440_info[] = {
                .func[10] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
                .func[11] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
                .read_byte_data = max34440_read_byte_data,
+               .read_word_data = max34440_read_word_data,
+               .write_word_data = max34440_write_word_data,
        },
 };
 
similarity index 72%
rename from drivers/hwmon/max8688.c
rename to drivers/hwmon/pmbus/max8688.c
index 7fb93f4..c3e72f1 100644 (file)
@@ -25,6 +25,9 @@
 #include <linux/i2c.h>
 #include "pmbus.h"
 
+#define MAX8688_MFR_VOUT_PEAK          0xd4
+#define MAX8688_MFR_IOUT_PEAK          0xd5
+#define MAX8688_MFR_TEMPERATURE_PEAK   0xd6
 #define MAX8688_MFG_STATUS             0xd8
 
 #define MAX8688_STATUS_OC_FAULT                (1 << 4)
 #define MAX8688_STATUS_OT_FAULT                (1 << 13)
 #define MAX8688_STATUS_OT_WARNING      (1 << 14)
 
+static int max8688_read_word_data(struct i2c_client *client, int page, int reg)
+{
+       int ret;
+
+       if (page)
+               return -EINVAL;
+
+       switch (reg) {
+       case PMBUS_VIRT_READ_VOUT_MAX:
+               ret = pmbus_read_word_data(client, 0, MAX8688_MFR_VOUT_PEAK);
+               break;
+       case PMBUS_VIRT_READ_IOUT_MAX:
+               ret = pmbus_read_word_data(client, 0, MAX8688_MFR_IOUT_PEAK);
+               break;
+       case PMBUS_VIRT_READ_TEMP_MAX:
+               ret = pmbus_read_word_data(client, 0,
+                                          MAX8688_MFR_TEMPERATURE_PEAK);
+               break;
+       case PMBUS_VIRT_RESET_VOUT_HISTORY:
+       case PMBUS_VIRT_RESET_IOUT_HISTORY:
+       case PMBUS_VIRT_RESET_TEMP_HISTORY:
+               ret = 0;
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
+static int max8688_write_word_data(struct i2c_client *client, int page, int reg,
+                                  u16 word)
+{
+       int ret;
+
+       switch (reg) {
+       case PMBUS_VIRT_RESET_VOUT_HISTORY:
+               ret = pmbus_write_word_data(client, 0, MAX8688_MFR_VOUT_PEAK,
+                                           0);
+               break;
+       case PMBUS_VIRT_RESET_IOUT_HISTORY:
+               ret = pmbus_write_word_data(client, 0, MAX8688_MFR_IOUT_PEAK,
+                                           0);
+               break;
+       case PMBUS_VIRT_RESET_TEMP_HISTORY:
+               ret = pmbus_write_word_data(client, 0,
+                                           MAX8688_MFR_TEMPERATURE_PEAK,
+                                           0xffff);
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
 static int max8688_read_byte_data(struct i2c_client *client, int page, int reg)
 {
        int ret = 0;
@@ -91,10 +150,10 @@ static int max8688_read_byte_data(struct i2c_client *client, int page, int reg)
 
 static struct pmbus_driver_info max8688_info = {
        .pages = 1,
-       .direct[PSC_VOLTAGE_IN] = true,
-       .direct[PSC_VOLTAGE_OUT] = true,
-       .direct[PSC_TEMPERATURE] = true,
-       .direct[PSC_CURRENT_OUT] = true,
+       .format[PSC_VOLTAGE_IN] = direct,
+       .format[PSC_VOLTAGE_OUT] = direct,
+       .format[PSC_TEMPERATURE] = direct,
+       .format[PSC_CURRENT_OUT] = direct,
        .m[PSC_VOLTAGE_IN] = 19995,
        .b[PSC_VOLTAGE_IN] = 0,
        .R[PSC_VOLTAGE_IN] = -1,
@@ -111,6 +170,8 @@ static struct pmbus_driver_info max8688_info = {
                | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
                | PMBUS_HAVE_STATUS_TEMP,
        .read_byte_data = max8688_read_byte_data,
+       .read_word_data = max8688_read_word_data,
+       .write_word_data = max8688_write_word_data,
 };
 
 static int max8688_probe(struct i2c_client *client,
similarity index 89%
rename from drivers/hwmon/pmbus.c
rename to drivers/hwmon/pmbus/pmbus.c
index 9b1f0c3..73de9f1 100644 (file)
@@ -96,6 +96,8 @@ static void pmbus_find_sensor_groups(struct i2c_client *client,
 static int pmbus_identify(struct i2c_client *client,
                          struct pmbus_driver_info *info)
 {
+       int ret = 0;
+
        if (!info->pages) {
                /*
                 * Check if the PAGE command is supported. If it is,
@@ -117,6 +119,27 @@ static int pmbus_identify(struct i2c_client *client,
                }
        }
 
+       if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) {
+               int vout_mode;
+
+               vout_mode = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE);
+               if (vout_mode >= 0 && vout_mode != 0xff) {
+                       switch (vout_mode >> 5) {
+                       case 0:
+                               break;
+                       case 1:
+                               info->format[PSC_VOLTAGE_OUT] = vid;
+                               break;
+                       case 2:
+                               info->format[PSC_VOLTAGE_OUT] = direct;
+                               break;
+                       default:
+                               ret = -ENODEV;
+                               goto abort;
+                       }
+               }
+       }
+
        /*
         * We should check if the COEFFICIENTS register is supported.
         * If it is, and the chip is configured for direct mode, we can read
@@ -125,13 +148,18 @@ static int pmbus_identify(struct i2c_client *client,
         *
         * To do this, we will need access to a chip which actually supports the
         * COEFFICIENTS command, since the command is too complex to implement
-        * without testing it.
+        * without testing it. Until then, abort if a chip configured for direct
+        * mode was detected.
         */
+       if (info->format[PSC_VOLTAGE_OUT] == direct) {
+               ret = -ENODEV;
+               goto abort;
+       }
 
        /* Try to find sensor groups  */
        pmbus_find_sensor_groups(client, info);
-
-       return 0;
+abort:
+       return ret;
 }
 
 static int pmbus_probe(struct i2c_client *client,
@@ -172,11 +200,14 @@ static int pmbus_remove(struct i2c_client *client)
  * Use driver_data to set the number of pages supported by the chip.
  */
 static const struct i2c_device_id pmbus_id[] = {
+       {"adp4000", 1},
        {"bmr450", 1},
        {"bmr451", 1},
        {"bmr453", 1},
        {"bmr454", 1},
        {"ltc2978", 8},
+       {"ncp4200", 1},
+       {"ncp4208", 1},
        {"pmbus", 0},
        {}
 };
similarity index 79%
rename from drivers/hwmon/pmbus.h
rename to drivers/hwmon/pmbus/pmbus.h
index 50647ab..a6ae20f 100644 (file)
 #define PMBUS_MFR_DATE                 0x9D
 #define PMBUS_MFR_SERIAL               0x9E
 
+/*
+ * Virtual registers.
+ * Useful to support attributes which are not supported by standard PMBus
+ * registers but exist as manufacturer specific registers on individual chips.
+ * Must be mapped to real registers in device specific code.
+ *
+ * Semantics:
+ * Virtual registers are all word size.
+ * READ registers are read-only; writes are either ignored or return an error.
+ * RESET registers are read/write. Reading returns zero (used for detection),
+ * writing any value causes the associated history to be reset.
+ */
+#define PMBUS_VIRT_BASE                        0x100
+#define PMBUS_VIRT_READ_TEMP_MIN       (PMBUS_VIRT_BASE + 0)
+#define PMBUS_VIRT_READ_TEMP_MAX       (PMBUS_VIRT_BASE + 1)
+#define PMBUS_VIRT_RESET_TEMP_HISTORY  (PMBUS_VIRT_BASE + 2)
+#define PMBUS_VIRT_READ_VIN_AVG                (PMBUS_VIRT_BASE + 3)
+#define PMBUS_VIRT_READ_VIN_MIN                (PMBUS_VIRT_BASE + 4)
+#define PMBUS_VIRT_READ_VIN_MAX                (PMBUS_VIRT_BASE + 5)
+#define PMBUS_VIRT_RESET_VIN_HISTORY   (PMBUS_VIRT_BASE + 6)
+#define PMBUS_VIRT_READ_IIN_AVG                (PMBUS_VIRT_BASE + 7)
+#define PMBUS_VIRT_READ_IIN_MIN                (PMBUS_VIRT_BASE + 8)
+#define PMBUS_VIRT_READ_IIN_MAX                (PMBUS_VIRT_BASE + 9)
+#define PMBUS_VIRT_RESET_IIN_HISTORY   (PMBUS_VIRT_BASE + 10)
+#define PMBUS_VIRT_READ_PIN_AVG                (PMBUS_VIRT_BASE + 11)
+#define PMBUS_VIRT_READ_PIN_MAX                (PMBUS_VIRT_BASE + 12)
+#define PMBUS_VIRT_RESET_PIN_HISTORY   (PMBUS_VIRT_BASE + 13)
+#define PMBUS_VIRT_READ_VOUT_AVG       (PMBUS_VIRT_BASE + 14)
+#define PMBUS_VIRT_READ_VOUT_MIN       (PMBUS_VIRT_BASE + 15)
+#define PMBUS_VIRT_READ_VOUT_MAX       (PMBUS_VIRT_BASE + 16)
+#define PMBUS_VIRT_RESET_VOUT_HISTORY  (PMBUS_VIRT_BASE + 17)
+#define PMBUS_VIRT_READ_IOUT_AVG       (PMBUS_VIRT_BASE + 18)
+#define PMBUS_VIRT_READ_IOUT_MIN       (PMBUS_VIRT_BASE + 19)
+#define PMBUS_VIRT_READ_IOUT_MAX       (PMBUS_VIRT_BASE + 20)
+#define PMBUS_VIRT_RESET_IOUT_HISTORY  (PMBUS_VIRT_BASE + 21)
+
 /*
  * CAPABILITY
  */
@@ -266,11 +302,11 @@ enum pmbus_sensor_classes {
 #define PMBUS_HAVE_STATUS_FAN12        (1 << 16)
 #define PMBUS_HAVE_STATUS_FAN34        (1 << 17)
 
+enum pmbus_data_format { linear = 0, direct, vid };
+
 struct pmbus_driver_info {
        int pages;              /* Total number of pages */
-       bool direct[PSC_NUM_CLASSES];
-                               /* true if device uses direct data format
-                                  for the given sensor class */
+       enum pmbus_data_format format[PSC_NUM_CLASSES];
        /*
         * Support one set of coefficients for each sensor type
         * Used for chips providing data in direct mode.
@@ -286,6 +322,10 @@ struct pmbus_driver_info {
         * necessary.
         */
        int (*read_byte_data)(struct i2c_client *client, int page, int reg);
+       int (*read_word_data)(struct i2c_client *client, int page, int reg);
+       int (*write_word_data)(struct i2c_client *client, int page, int reg,
+                              u16 word);
+       int (*write_byte)(struct i2c_client *client, int page, u8 value);
        /*
         * The identify function determines supported PMBus functionality.
         * This function is only necessary if a chip driver supports multiple
@@ -299,6 +339,9 @@ struct pmbus_driver_info {
 
 int pmbus_set_page(struct i2c_client *client, u8 page);
 int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg);
+int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg, u16 word);
+int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg);
+int pmbus_write_byte(struct i2c_client *client, int page, u8 value);
 void pmbus_clear_faults(struct i2c_client *client);
 bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg);
 bool pmbus_check_word_register(struct i2c_client *client, int page, int reg);
similarity index 83%
rename from drivers/hwmon/pmbus_core.c
rename to drivers/hwmon/pmbus/pmbus_core.c
index 8e31a8e..a561c3a 100644 (file)
 /*
  * Constants needed to determine number of sensors, booleans, and labels.
  */
-#define PMBUS_MAX_INPUT_SENSORS                11      /* 6*volt, 3*curr, 2*power */
-#define PMBUS_VOUT_SENSORS_PER_PAGE    5       /* input, min, max, lcrit,
-                                                  crit */
-#define PMBUS_IOUT_SENSORS_PER_PAGE    4       /* input, min, max, crit */
+#define PMBUS_MAX_INPUT_SENSORS                22      /* 10*volt, 7*curr, 5*power */
+#define PMBUS_VOUT_SENSORS_PER_PAGE    9       /* input, min, max, lcrit,
+                                                  crit, lowest, highest, avg,
+                                                  reset */
+#define PMBUS_IOUT_SENSORS_PER_PAGE    8       /* input, min, max, crit,
+                                                  lowest, highest, avg,
+                                                  reset */
 #define PMBUS_POUT_SENSORS_PER_PAGE    4       /* input, cap, max, crit */
 #define PMBUS_MAX_SENSORS_PER_FAN      1       /* input */
-#define PMBUS_MAX_SENSORS_PER_TEMP     5       /* input, min, max, lcrit,
-                                                  crit */
+#define PMBUS_MAX_SENSORS_PER_TEMP     8       /* input, min, max, lcrit,
+                                                  crit, lowest, highest,
+                                                  reset */
 
 #define PMBUS_MAX_INPUT_BOOLEANS       7       /* v: min_alarm, max_alarm,
                                                   lcrit_alarm, crit_alarm;
 #define PB_STATUS_INPUT_BASE   (PB_STATUS_FAN34_BASE + PMBUS_PAGES)
 #define PB_STATUS_TEMP_BASE    (PB_STATUS_INPUT_BASE + 1)
 
+#define PMBUS_NAME_SIZE                24
+
 struct pmbus_sensor {
-       char name[I2C_NAME_SIZE];       /* sysfs sensor name */
+       char name[PMBUS_NAME_SIZE];     /* sysfs sensor name */
        struct sensor_device_attribute attribute;
        u8 page;                /* page number */
-       u8 reg;                 /* register */
+       u16 reg;                /* register */
        enum pmbus_sensor_classes class;        /* sensor class */
        bool update;            /* runtime sensor update needed */
        int data;               /* Sensor data.
@@ -86,14 +92,14 @@ struct pmbus_sensor {
 };
 
 struct pmbus_boolean {
-       char name[I2C_NAME_SIZE];       /* sysfs boolean name */
+       char name[PMBUS_NAME_SIZE];     /* sysfs boolean name */
        struct sensor_device_attribute attribute;
 };
 
 struct pmbus_label {
-       char name[I2C_NAME_SIZE];       /* sysfs label name */
+       char name[PMBUS_NAME_SIZE];     /* sysfs label name */
        struct sensor_device_attribute attribute;
-       char label[I2C_NAME_SIZE];      /* label */
+       char label[PMBUS_NAME_SIZE];    /* label */
 };
 
 struct pmbus_data {
@@ -162,19 +168,39 @@ int pmbus_set_page(struct i2c_client *client, u8 page)
 }
 EXPORT_SYMBOL_GPL(pmbus_set_page);
 
-static int pmbus_write_byte(struct i2c_client *client, u8 page, u8 value)
+int pmbus_write_byte(struct i2c_client *client, int page, u8 value)
 {
        int rv;
 
-       rv = pmbus_set_page(client, page);
-       if (rv < 0)
-               return rv;
+       if (page >= 0) {
+               rv = pmbus_set_page(client, page);
+               if (rv < 0)
+                       return rv;
+       }
 
        return i2c_smbus_write_byte(client, value);
 }
+EXPORT_SYMBOL_GPL(pmbus_write_byte);
+
+/*
+ * _pmbus_write_byte() is similar to pmbus_write_byte(), but checks if
+ * a device specific mapping funcion exists and calls it if necessary.
+ */
+static int _pmbus_write_byte(struct i2c_client *client, int page, u8 value)
+{
+       struct pmbus_data *data = i2c_get_clientdata(client);
+       const struct pmbus_driver_info *info = data->info;
+       int status;
+
+       if (info->write_byte) {
+               status = info->write_byte(client, page, value);
+               if (status != -ENODATA)
+                       return status;
+       }
+       return pmbus_write_byte(client, page, value);
+}
 
-static int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg,
-                                u16 word)
+int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg, u16 word)
 {
        int rv;
 
@@ -184,6 +210,28 @@ static int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg,
 
        return i2c_smbus_write_word_data(client, reg, word);
 }
+EXPORT_SYMBOL_GPL(pmbus_write_word_data);
+
+/*
+ * _pmbus_write_word_data() is similar to pmbus_write_word_data(), but checks if
+ * a device specific mapping function exists and calls it if necessary.
+ */
+static int _pmbus_write_word_data(struct i2c_client *client, int page, int reg,
+                                 u16 word)
+{
+       struct pmbus_data *data = i2c_get_clientdata(client);
+       const struct pmbus_driver_info *info = data->info;
+       int status;
+
+       if (info->write_word_data) {
+               status = info->write_word_data(client, page, reg, word);
+               if (status != -ENODATA)
+                       return status;
+       }
+       if (reg >= PMBUS_VIRT_BASE)
+               return -EINVAL;
+       return pmbus_write_word_data(client, page, reg, word);
+}
 
 int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg)
 {
@@ -197,20 +245,61 @@ int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg)
 }
 EXPORT_SYMBOL_GPL(pmbus_read_word_data);
 
-static int pmbus_read_byte_data(struct i2c_client *client, u8 page, u8 reg)
+/*
+ * _pmbus_read_word_data() is similar to pmbus_read_word_data(), but checks if
+ * a device specific mapping function exists and calls it if necessary.
+ */
+static int _pmbus_read_word_data(struct i2c_client *client, int page, int reg)
+{
+       struct pmbus_data *data = i2c_get_clientdata(client);
+       const struct pmbus_driver_info *info = data->info;
+       int status;
+
+       if (info->read_word_data) {
+               status = info->read_word_data(client, page, reg);
+               if (status != -ENODATA)
+                       return status;
+       }
+       if (reg >= PMBUS_VIRT_BASE)
+               return -EINVAL;
+       return pmbus_read_word_data(client, page, reg);
+}
+
+int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg)
 {
        int rv;
 
-       rv = pmbus_set_page(client, page);
-       if (rv < 0)
-               return rv;
+       if (page >= 0) {
+               rv = pmbus_set_page(client, page);
+               if (rv < 0)
+                       return rv;
+       }
 
        return i2c_smbus_read_byte_data(client, reg);
 }
+EXPORT_SYMBOL_GPL(pmbus_read_byte_data);
+
+/*
+ * _pmbus_read_byte_data() is similar to pmbus_read_byte_data(), but checks if
+ * a device specific mapping function exists and calls it if necessary.
+ */
+static int _pmbus_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+       struct pmbus_data *data = i2c_get_clientdata(client);
+       const struct pmbus_driver_info *info = data->info;
+       int status;
+
+       if (info->read_byte_data) {
+               status = info->read_byte_data(client, page, reg);
+               if (status != -ENODATA)
+                       return status;
+       }
+       return pmbus_read_byte_data(client, page, reg);
+}
 
 static void pmbus_clear_fault_page(struct i2c_client *client, int page)
 {
-       pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
+       _pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
 }
 
 void pmbus_clear_faults(struct i2c_client *client)
@@ -223,13 +312,13 @@ void pmbus_clear_faults(struct i2c_client *client)
 }
 EXPORT_SYMBOL_GPL(pmbus_clear_faults);
 
-static int pmbus_check_status_cml(struct i2c_client *client, int page)
+static int pmbus_check_status_cml(struct i2c_client *client)
 {
        int status, status2;
 
-       status = pmbus_read_byte_data(client, page, PMBUS_STATUS_BYTE);
+       status = pmbus_read_byte_data(client, -1, PMBUS_STATUS_BYTE);
        if (status < 0 || (status & PB_STATUS_CML)) {
-               status2 = pmbus_read_byte_data(client, page, PMBUS_STATUS_CML);
+               status2 = pmbus_read_byte_data(client, -1, PMBUS_STATUS_CML);
                if (status2 < 0 || (status2 & PB_CML_FAULT_INVALID_COMMAND))
                        return -EINVAL;
        }
@@ -241,10 +330,10 @@ bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg)
        int rv;
        struct pmbus_data *data = i2c_get_clientdata(client);
 
-       rv = pmbus_read_byte_data(client, page, reg);
+       rv = _pmbus_read_byte_data(client, page, reg);
        if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK))
-               rv = pmbus_check_status_cml(client, page);
-       pmbus_clear_fault_page(client, page);
+               rv = pmbus_check_status_cml(client);
+       pmbus_clear_fault_page(client, -1);
        return rv >= 0;
 }
 EXPORT_SYMBOL_GPL(pmbus_check_byte_register);
@@ -254,10 +343,10 @@ bool pmbus_check_word_register(struct i2c_client *client, int page, int reg)
        int rv;
        struct pmbus_data *data = i2c_get_clientdata(client);
 
-       rv = pmbus_read_word_data(client, page, reg);
+       rv = _pmbus_read_word_data(client, page, reg);
        if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK))
-               rv = pmbus_check_status_cml(client, page);
-       pmbus_clear_fault_page(client, page);
+               rv = pmbus_check_status_cml(client);
+       pmbus_clear_fault_page(client, -1);
        return rv >= 0;
 }
 EXPORT_SYMBOL_GPL(pmbus_check_word_register);
@@ -270,24 +359,6 @@ const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client *client)
 }
 EXPORT_SYMBOL_GPL(pmbus_get_driver_info);
 
-/*
- * _pmbus_read_byte_data() is similar to pmbus_read_byte_data(), but checks if
- * a device specific mapping funcion exists and calls it if necessary.
- */
-static int _pmbus_read_byte_data(struct i2c_client *client, int page, int reg)
-{
-       struct pmbus_data *data = i2c_get_clientdata(client);
-       const struct pmbus_driver_info *info = data->info;
-       int status;
-
-       if (info->read_byte_data) {
-               status = info->read_byte_data(client, page, reg);
-               if (status != -ENODATA)
-                       return status;
-       }
-       return pmbus_read_byte_data(client, page, reg);
-}
-
 static struct pmbus_data *pmbus_update_device(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
@@ -347,8 +418,9 @@ static struct pmbus_data *pmbus_update_device(struct device *dev)
 
                        if (!data->valid || sensor->update)
                                sensor->data
-                                   = pmbus_read_word_data(client, sensor->page,
-                                                          sensor->reg);
+                                   = _pmbus_read_word_data(client,
+                                                           sensor->page,
+                                                           sensor->reg);
                }
                pmbus_clear_faults(client);
                data->last_updated = jiffies;
@@ -443,15 +515,37 @@ static long pmbus_reg2data_direct(struct pmbus_data *data,
        return (val - b) / m;
 }
 
+/*
+ * Convert VID sensor values to milli- or micro-units
+ * depending on sensor type.
+ * We currently only support VR11.
+ */
+static long pmbus_reg2data_vid(struct pmbus_data *data,
+                              struct pmbus_sensor *sensor)
+{
+       long val = sensor->data;
+
+       if (val < 0x02 || val > 0xb2)
+               return 0;
+       return DIV_ROUND_CLOSEST(160000 - (val - 2) * 625, 100);
+}
+
 static long pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor)
 {
        long val;
 
-       if (data->info->direct[sensor->class])
+       switch (data->info->format[sensor->class]) {
+       case direct:
                val = pmbus_reg2data_direct(data, sensor);
-       else
+               break;
+       case vid:
+               val = pmbus_reg2data_vid(data, sensor);
+               break;
+       case linear:
+       default:
                val = pmbus_reg2data_linear(data, sensor);
-
+               break;
+       }
        return val;
 }
 
@@ -561,16 +655,31 @@ static u16 pmbus_data2reg_direct(struct pmbus_data *data,
        return val;
 }
 
+static u16 pmbus_data2reg_vid(struct pmbus_data *data,
+                             enum pmbus_sensor_classes class, long val)
+{
+       val = SENSORS_LIMIT(val, 500, 1600);
+
+       return 2 + DIV_ROUND_CLOSEST((1600 - val) * 100, 625);
+}
+
 static u16 pmbus_data2reg(struct pmbus_data *data,
                          enum pmbus_sensor_classes class, long val)
 {
        u16 regval;
 
-       if (data->info->direct[class])
+       switch (data->info->format[class]) {
+       case direct:
                regval = pmbus_data2reg_direct(data, class, val);
-       else
+               break;
+       case vid:
+               regval = pmbus_data2reg_vid(data, class, val);
+               break;
+       case linear:
+       default:
                regval = pmbus_data2reg_linear(data, class, val);
-
+               break;
+       }
        return regval;
 }
 
@@ -682,7 +791,7 @@ static ssize_t pmbus_set_sensor(struct device *dev,
 
        mutex_lock(&data->update_lock);
        regval = pmbus_data2reg(data, sensor->class, val);
-       ret = pmbus_write_word_data(client, sensor->page, sensor->reg, regval);
+       ret = _pmbus_write_word_data(client, sensor->page, sensor->reg, regval);
        if (ret < 0)
                rv = ret;
        else
@@ -867,7 +976,8 @@ static void pmbus_find_max_attr(struct i2c_client *client,
  * and its associated alarm attribute.
  */
 struct pmbus_limit_attr {
-       u8 reg;                 /* Limit register */
+       u16 reg;                /* Limit register */
+       bool update;            /* True if register needs updates */
        const char *attr;       /* Attribute name */
        const char *alarm;      /* Alarm attribute name */
        u32 sbit;               /* Alarm attribute status bit */
@@ -912,9 +1022,10 @@ static bool pmbus_add_limit_attrs(struct i2c_client *client,
                if (pmbus_check_word_register(client, page, l->reg)) {
                        cindex = data->num_sensors;
                        pmbus_add_sensor(data, name, l->attr, index, page,
-                                        l->reg, attr->class, attr->update,
+                                        l->reg, attr->class,
+                                        attr->update || l->update,
                                         false);
-                       if (info->func[page] & attr->sfunc) {
+                       if (l->sbit && (info->func[page] & attr->sfunc)) {
                                if (attr->compare) {
                                        pmbus_add_boolean_cmp(data, name,
                                                l->alarm, index,
@@ -953,9 +1064,11 @@ static void pmbus_add_sensor_attrs_one(struct i2c_client *client,
                                                   index, page, cbase, attr);
                /*
                 * Add generic alarm attribute only if there are no individual
-                * alarm attributes, and if there is a global alarm bit.
+                * alarm attributes, if there is a global alarm bit, and if
+                * the generic status register for this page is accessible.
                 */
-               if (!have_alarm && attr->gbit)
+               if (!have_alarm && attr->gbit &&
+                   pmbus_check_byte_register(client, page, PMBUS_STATUS_BYTE))
                        pmbus_add_boolean_reg(data, name, "alarm", index,
                                              PB_STATUS_BASE + page,
                                              attr->gbit);
@@ -1008,6 +1121,21 @@ static const struct pmbus_limit_attr vin_limit_attrs[] = {
                .attr = "crit",
                .alarm = "crit_alarm",
                .sbit = PB_VOLTAGE_OV_FAULT,
+       }, {
+               .reg = PMBUS_VIRT_READ_VIN_AVG,
+               .update = true,
+               .attr = "average",
+       }, {
+               .reg = PMBUS_VIRT_READ_VIN_MIN,
+               .update = true,
+               .attr = "lowest",
+       }, {
+               .reg = PMBUS_VIRT_READ_VIN_MAX,
+               .update = true,
+               .attr = "highest",
+       }, {
+               .reg = PMBUS_VIRT_RESET_VIN_HISTORY,
+               .attr = "reset_history",
        },
 };
 
@@ -1032,6 +1160,21 @@ static const struct pmbus_limit_attr vout_limit_attrs[] = {
                .attr = "crit",
                .alarm = "crit_alarm",
                .sbit = PB_VOLTAGE_OV_FAULT,
+       }, {
+               .reg = PMBUS_VIRT_READ_VOUT_AVG,
+               .update = true,
+               .attr = "average",
+       }, {
+               .reg = PMBUS_VIRT_READ_VOUT_MIN,
+               .update = true,
+               .attr = "lowest",
+       }, {
+               .reg = PMBUS_VIRT_READ_VOUT_MAX,
+               .update = true,
+               .attr = "highest",
+       }, {
+               .reg = PMBUS_VIRT_RESET_VOUT_HISTORY,
+               .attr = "reset_history",
        }
 };
 
@@ -1078,6 +1221,21 @@ static const struct pmbus_limit_attr iin_limit_attrs[] = {
                .attr = "crit",
                .alarm = "crit_alarm",
                .sbit = PB_IIN_OC_FAULT,
+       }, {
+               .reg = PMBUS_VIRT_READ_IIN_AVG,
+               .update = true,
+               .attr = "average",
+       }, {
+               .reg = PMBUS_VIRT_READ_IIN_MIN,
+               .update = true,
+               .attr = "lowest",
+       }, {
+               .reg = PMBUS_VIRT_READ_IIN_MAX,
+               .update = true,
+               .attr = "highest",
+       }, {
+               .reg = PMBUS_VIRT_RESET_IIN_HISTORY,
+               .attr = "reset_history",
        }
 };
 
@@ -1097,6 +1255,21 @@ static const struct pmbus_limit_attr iout_limit_attrs[] = {
                .attr = "crit",
                .alarm = "crit_alarm",
                .sbit = PB_IOUT_OC_FAULT,
+       }, {
+               .reg = PMBUS_VIRT_READ_IOUT_AVG,
+               .update = true,
+               .attr = "average",
+       }, {
+               .reg = PMBUS_VIRT_READ_IOUT_MIN,
+               .update = true,
+               .attr = "lowest",
+       }, {
+               .reg = PMBUS_VIRT_READ_IOUT_MAX,
+               .update = true,
+               .attr = "highest",
+       }, {
+               .reg = PMBUS_VIRT_RESET_IOUT_HISTORY,
+               .attr = "reset_history",
        }
 };
 
@@ -1132,6 +1305,17 @@ static const struct pmbus_limit_attr pin_limit_attrs[] = {
                .attr = "max",
                .alarm = "alarm",
                .sbit = PB_PIN_OP_WARNING,
+       }, {
+               .reg = PMBUS_VIRT_READ_PIN_AVG,
+               .update = true,
+               .attr = "average",
+       }, {
+               .reg = PMBUS_VIRT_READ_PIN_MAX,
+               .update = true,
+               .attr = "input_highest",
+       }, {
+               .reg = PMBUS_VIRT_RESET_PIN_HISTORY,
+               .attr = "reset_history",
        }
 };
 
@@ -1180,6 +1364,39 @@ static const struct pmbus_sensor_attr power_attributes[] = {
 /* Temperature atributes */
 
 static const struct pmbus_limit_attr temp_limit_attrs[] = {
+       {
+               .reg = PMBUS_UT_WARN_LIMIT,
+               .attr = "min",
+               .alarm = "min_alarm",
+               .sbit = PB_TEMP_UT_WARNING,
+       }, {
+               .reg = PMBUS_UT_FAULT_LIMIT,
+               .attr = "lcrit",
+               .alarm = "lcrit_alarm",
+               .sbit = PB_TEMP_UT_FAULT,
+       }, {
+               .reg = PMBUS_OT_WARN_LIMIT,
+               .attr = "max",
+               .alarm = "max_alarm",
+               .sbit = PB_TEMP_OT_WARNING,
+       }, {
+               .reg = PMBUS_OT_FAULT_LIMIT,
+               .attr = "crit",
+               .alarm = "crit_alarm",
+               .sbit = PB_TEMP_OT_FAULT,
+       }, {
+               .reg = PMBUS_VIRT_READ_TEMP_MIN,
+               .attr = "lowest",
+       }, {
+               .reg = PMBUS_VIRT_READ_TEMP_MAX,
+               .attr = "highest",
+       }, {
+               .reg = PMBUS_VIRT_RESET_TEMP_HISTORY,
+               .attr = "reset_history",
+       }
+};
+
+static const struct pmbus_limit_attr temp_limit_attrs23[] = {
        {
                .reg = PMBUS_UT_WARN_LIMIT,
                .attr = "min",
@@ -1226,8 +1443,8 @@ static const struct pmbus_sensor_attr temp_attributes[] = {
                .sfunc = PMBUS_HAVE_STATUS_TEMP,
                .sbase = PB_STATUS_TEMP_BASE,
                .gbit = PB_STATUS_TEMPERATURE,
-               .limit = temp_limit_attrs,
-               .nlimit = ARRAY_SIZE(temp_limit_attrs),
+               .limit = temp_limit_attrs23,
+               .nlimit = ARRAY_SIZE(temp_limit_attrs23),
        }, {
                .reg = PMBUS_READ_TEMPERATURE_3,
                .class = PSC_TEMPERATURE,
@@ -1238,8 +1455,8 @@ static const struct pmbus_sensor_attr temp_attributes[] = {
                .sfunc = PMBUS_HAVE_STATUS_TEMP,
                .sbase = PB_STATUS_TEMP_BASE,
                .gbit = PB_STATUS_TEMPERATURE,
-               .limit = temp_limit_attrs,
-               .nlimit = ARRAY_SIZE(temp_limit_attrs),
+               .limit = temp_limit_attrs23,
+               .nlimit = ARRAY_SIZE(temp_limit_attrs23),
        }
 };
 
@@ -1380,7 +1597,7 @@ static int pmbus_identify_common(struct i2c_client *client,
                 */
                switch (vout_mode >> 5) {
                case 0: /* linear mode      */
-                       if (data->info->direct[PSC_VOLTAGE_OUT])
+                       if (data->info->format[PSC_VOLTAGE_OUT] != linear)
                                return -ENODEV;
 
                        exponent = vout_mode & 0x1f;
@@ -1389,8 +1606,12 @@ static int pmbus_identify_common(struct i2c_client *client,
                                exponent |= ~0x1f;
                        data->exponent = exponent;
                        break;
+               case 1: /* VID mode         */
+                       if (data->info->format[PSC_VOLTAGE_OUT] != vid)
+                               return -ENODEV;
+                       break;
                case 2: /* direct mode      */
-                       if (!data->info->direct[PSC_VOLTAGE_OUT])
+                       if (data->info->format[PSC_VOLTAGE_OUT] != direct)
                                return -ENODEV;
                        break;
                default:
@@ -1457,18 +1678,6 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
                ret = -EINVAL;
                goto out_data;
        }
-       /*
-        * Bail out if more than one page was configured, but we can not
-        * select the highest page. This is an indication that the wrong
-        * chip type was selected. Better bail out now than keep
-        * returning errors later on.
-        */
-       if (info->pages > 1 && pmbus_set_page(client, info->pages - 1) < 0) {
-               dev_err(&client->dev, "Failed to select page %d\n",
-                       info->pages - 1);
-               ret = -EINVAL;
-               goto out_data;
-       }
 
        ret = pmbus_identify_common(client, data);
        if (ret < 0) {
index 3be60da..67cbcfa 100644 (file)
@@ -141,6 +141,8 @@ static void cy82c693_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
                pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, time_16);
                pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, time_8);
        }
+       if (hwif->index > 0)
+               pci_dev_put(dev);
 }
 
 static void __devinit init_iops_cy82c693(ide_hwif_t *hwif)
index 542603b..962693b 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/ata_platform.h>
 #include <linux/platform_device.h>
+#include <linux/interrupt.h>
 #include <linux/io.h>
 
 static void __devinit plat_ide_setup_ports(struct ide_hw *hw,
@@ -95,7 +96,10 @@ static int __devinit plat_ide_probe(struct platform_device *pdev)
        plat_ide_setup_ports(&hw, base, alt_base, pdata, res_irq->start);
        hw.dev = &pdev->dev;
 
-       d.irq_flags = res_irq->flags;
+       d.irq_flags = res_irq->flags & IRQF_TRIGGER_MASK;
+       if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE)
+               d.irq_flags |= IRQF_SHARED;
+
        if (mmio)
                d.host_flags |= IDE_HFLAG_MMIO;
 
index 43f89ba..fe89c46 100644 (file)
@@ -717,11 +717,13 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct ipoib_neigh *neigh;
-       struct neighbour *n;
+       struct neighbour *n = NULL;
        unsigned long flags;
 
-       n = dst_get_neighbour(skb_dst(skb));
-       if (likely(skb_dst(skb) && n)) {
+       if (likely(skb_dst(skb)))
+               n = dst_get_neighbour(skb_dst(skb));
+
+       if (likely(n)) {
                if (unlikely(!*to_ipoib_neigh(n))) {
                        ipoib_path_lookup(skb, dev);
                        return NETDEV_TX_OK;
index 8db008d..9c61b9c 100644 (file)
@@ -101,13 +101,17 @@ iscsi_iser_recv(struct iscsi_conn *conn,
 
        /* verify PDU length */
        datalen = ntoh24(hdr->dlength);
-       if (datalen != rx_data_len) {
-               printk(KERN_ERR "iscsi_iser: datalen %d (hdr) != %d (IB) \n",
-                      datalen, rx_data_len);
+       if (datalen > rx_data_len || (datalen + 4) < rx_data_len) {
+               iser_err("wrong datalen %d (hdr), %d (IB)\n",
+                       datalen, rx_data_len);
                rc = ISCSI_ERR_DATALEN;
                goto error;
        }
 
+       if (datalen != rx_data_len)
+               iser_dbg("aligned datalen (%d) hdr, %d (IB)\n",
+                       datalen, rx_data_len);
+
        /* read AHS */
        ahslen = hdr->hlength * 4;
 
index 342cbc1..db6f3ce 100644 (file)
@@ -89,7 +89,7 @@
        } while (0)
 
 #define SHIFT_4K       12
-#define SIZE_4K        (1UL << SHIFT_4K)
+#define SIZE_4K        (1ULL << SHIFT_4K)
 #define MASK_4K        (~(SIZE_4K-1))
 
                                        /* support up to 512KB in one RDMA */
index 5745b7f..f299de6 100644 (file)
@@ -412,7 +412,7 @@ int iser_send_control(struct iscsi_conn *conn,
                memcpy(iser_conn->ib_conn->login_buf, task->data,
                                                        task->data_count);
                tx_dsg->addr    = iser_conn->ib_conn->login_dma;
-               tx_dsg->length  = data_seg_len;
+               tx_dsg->length  = task->data_count;
                tx_dsg->lkey    = device->mr->lkey;
                mdesc->num_sge = 2;
        }
index 9882971..358cd7e 100644 (file)
@@ -139,7 +139,7 @@ struct analog_port {
 #include <linux/i8253.h>
 
 #define GET_TIME(x)    do { if (cpu_has_tsc) rdtscl(x); else x = get_time_pit(); } while (0)
-#define DELTA(x,y)     (cpu_has_tsc ? ((y) - (x)) : ((x) - (y) + ((x) < (y) ? CLOCK_TICK_RATE / HZ : 0)))
+#define DELTA(x,y)     (cpu_has_tsc ? ((y) - (x)) : ((x) - (y) + ((x) < (y) ? PIT_TICK_RATE / HZ : 0)))
 #define TIME_NAME      (cpu_has_tsc?"TSC":"PIT")
 static unsigned int get_time_pit(void)
 {
index c8242dd..aa17e02 100644 (file)
@@ -20,6 +20,7 @@
  * flag.
  */
 
+#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/clk.h>
index ce281d1..67df91a 100644 (file)
@@ -483,7 +483,7 @@ static int gpio_keys_get_devtree_pdata(struct device *dev,
 
        buttons = kzalloc(pdata->nbuttons * (sizeof *buttons), GFP_KERNEL);
        if (!buttons)
-               return -ENODEV;
+               return -ENOMEM;
 
        pp = NULL;
        i = 0;
index ab0acaf..756348a 100644 (file)
@@ -754,8 +754,11 @@ fail3:
        device_remove_file(&client->dev, &dev_attr_disable_kp);
 fail2:
        while (--pwm >= 0)
-               if (lm->pwm[pwm].enabled)
+               if (lm->pwm[pwm].enabled) {
+                       device_remove_file(lm->pwm[pwm].cdev.dev,
+                                          &dev_attr_time);
                        led_classdev_unregister(&lm->pwm[pwm].cdev);
+               }
 fail1:
        input_free_device(idev);
        kfree(lm);
@@ -775,8 +778,10 @@ static int __devexit lm8323_remove(struct i2c_client *client)
        device_remove_file(&lm->client->dev, &dev_attr_disable_kp);
 
        for (i = 0; i < 3; i++)
-               if (lm->pwm[i].enabled)
+               if (lm->pwm[i].enabled) {
+                       device_remove_file(lm->pwm[i].cdev.dev, &dev_attr_time);
                        led_classdev_unregister(&lm->pwm[i].cdev);
+               }
 
        kfree(lm);
 
index da3828f..a5a7791 100644 (file)
@@ -19,6 +19,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
+#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/input.h>
 #include <linux/platform_device.h>
@@ -37,7 +38,7 @@
 #define KBC_ROW_SCAN_DLY       5
 
 /* KBC uses a 32KHz clock so a cycle = 1/32Khz */
-#define KBC_CYCLE_USEC 32
+#define KBC_CYCLE_MS   32
 
 /* KBC Registers */
 
@@ -647,7 +648,7 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
        debounce_cnt = min(pdata->debounce_cnt, KBC_MAX_DEBOUNCE_CNT);
        scan_time_rows = (KBC_ROW_SCAN_TIME + debounce_cnt) * num_rows;
        kbc->repoll_dly = KBC_ROW_SCAN_DLY + scan_time_rows + pdata->repeat_cnt;
-       kbc->repoll_dly = ((kbc->repoll_dly * KBC_CYCLE_USEC) + 999) / 1000;
+       kbc->repoll_dly = DIV_ROUND_UP(kbc->repoll_dly, KBC_CYCLE_MS);
 
        input_dev->name = pdev->name;
        input_dev->id.bustype = BUS_HOST;
@@ -701,7 +702,7 @@ err_iounmap:
 err_free_mem_region:
        release_mem_region(res->start, resource_size(res));
 err_free_mem:
-       input_free_device(kbc->idev);
+       input_free_device(input_dev);
        kfree(kbc);
 
        return err;
index e21deb1..025417d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * AD714X CapTouch Programmable Controller driver (I2C bus)
  *
- * Copyright 2009 Analog Devices Inc.
+ * Copyright 2009-2011 Analog Devices Inc.
  *
  * Licensed under the GPL-2 or later.
  */
@@ -27,54 +27,49 @@ static int ad714x_i2c_resume(struct device *dev)
 
 static SIMPLE_DEV_PM_OPS(ad714x_i2c_pm, ad714x_i2c_suspend, ad714x_i2c_resume);
 
-static int ad714x_i2c_write(struct device *dev, unsigned short reg,
-                               unsigned short data)
+static int ad714x_i2c_write(struct ad714x_chip *chip,
+                           unsigned short reg, unsigned short data)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       int ret = 0;
-       u8 *_reg = (u8 *)&reg;
-       u8 *_data = (u8 *)&data;
-
-       u8 tx[4] = {
-               _reg[1],
-               _reg[0],
-               _data[1],
-               _data[0]
-       };
-
-       ret = i2c_master_send(client, tx, 4);
-       if (ret < 0)
-               dev_err(&client->dev, "I2C write error\n");
-
-       return ret;
+       struct i2c_client *client = to_i2c_client(chip->dev);
+       int error;
+
+       chip->xfer_buf[0] = cpu_to_be16(reg);
+       chip->xfer_buf[1] = cpu_to_be16(data);
+
+       error = i2c_master_send(client, (u8 *)chip->xfer_buf,
+                               2 * sizeof(*chip->xfer_buf));
+       if (unlikely(error < 0)) {
+               dev_err(&client->dev, "I2C write error: %d\n", error);
+               return error;
+       }
+
+       return 0;
 }
 
-static int ad714x_i2c_read(struct device *dev, unsigned short reg,
-                               unsigned short *data)
+static int ad714x_i2c_read(struct ad714x_chip *chip,
+                          unsigned short reg, unsigned short *data, size_t len)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       int ret = 0;
-       u8 *_reg = (u8 *)&reg;
-       u8 *_data = (u8 *)data;
-
-       u8 tx[2] = {
-               _reg[1],
-               _reg[0]
-       };
-       u8 rx[2];
-
-       ret = i2c_master_send(client, tx, 2);
-       if (ret >= 0)
-               ret = i2c_master_recv(client, rx, 2);
-
-       if (unlikely(ret < 0)) {
-               dev_err(&client->dev, "I2C read error\n");
-       } else {
-               _data[0] = rx[1];
-               _data[1] = rx[0];
+       struct i2c_client *client = to_i2c_client(chip->dev);
+       int i;
+       int error;
+
+       chip->xfer_buf[0] = cpu_to_be16(reg);
+
+       error = i2c_master_send(client, (u8 *)chip->xfer_buf,
+                               sizeof(*chip->xfer_buf));
+       if (error >= 0)
+               error = i2c_master_recv(client, (u8 *)chip->xfer_buf,
+                                       len * sizeof(*chip->xfer_buf));
+
+       if (unlikely(error < 0)) {
+               dev_err(&client->dev, "I2C read error: %d\n", error);
+               return error;
        }
 
-       return ret;
+       for (i = 0; i < len; i++)
+               data[i] = be16_to_cpu(chip->xfer_buf[i]);
+
+       return 0;
 }
 
 static int __devinit ad714x_i2c_probe(struct i2c_client *client,
index 4120dd5..875b508 100644 (file)
@@ -1,12 +1,12 @@
 /*
  * AD714X CapTouch Programmable Controller driver (SPI bus)
  *
- * Copyright 2009 Analog Devices Inc.
+ * Copyright 2009-2011 Analog Devices Inc.
  *
  * Licensed under the GPL-2 or later.
  */
 
-#include <linux/input.h>       /* BUS_I2C */
+#include <linux/input.h>       /* BUS_SPI */
 #include <linux/module.h>
 #include <linux/spi/spi.h>
 #include <linux/pm.h>
@@ -30,30 +30,68 @@ static int ad714x_spi_resume(struct device *dev)
 
 static SIMPLE_DEV_PM_OPS(ad714x_spi_pm, ad714x_spi_suspend, ad714x_spi_resume);
 
-static int ad714x_spi_read(struct device *dev, unsigned short reg,
-               unsigned short *data)
+static int ad714x_spi_read(struct ad714x_chip *chip,
+                          unsigned short reg, unsigned short *data, size_t len)
 {
-       struct spi_device *spi = to_spi_device(dev);
-       unsigned short tx = AD714x_SPI_CMD_PREFIX | AD714x_SPI_READ | reg;
+       struct spi_device *spi = to_spi_device(chip->dev);
+       struct spi_message message;
+       struct spi_transfer xfer[2];
+       int i;
+       int error;
+
+       spi_message_init(&message);
+       memset(xfer, 0, sizeof(xfer));
+
+       chip->xfer_buf[0] = cpu_to_be16(AD714x_SPI_CMD_PREFIX |
+                                       AD714x_SPI_READ | reg);
+       xfer[0].tx_buf = &chip->xfer_buf[0];
+       xfer[0].len = sizeof(chip->xfer_buf[0]);
+       spi_message_add_tail(&xfer[0], &message);
+
+       xfer[1].rx_buf = &chip->xfer_buf[1];
+       xfer[1].len = sizeof(chip->xfer_buf[1]) * len;
+       spi_message_add_tail(&xfer[1], &message);
+
+       error = spi_sync(spi, &message);
+       if (unlikely(error)) {
+               dev_err(chip->dev, "SPI read error: %d\n", error);
+               return error;
+       }
+
+       for (i = 0; i < len; i++)
+               data[i] = be16_to_cpu(chip->xfer_buf[i + 1]);
 
-       return spi_write_then_read(spi, (u8 *)&tx, 2, (u8 *)data, 2);
+       return 0;
 }
 
-static int ad714x_spi_write(struct device *dev, unsigned short reg,
-               unsigned short data)
+static int ad714x_spi_write(struct ad714x_chip *chip,
+                           unsigned short reg, unsigned short data)
 {
-       struct spi_device *spi = to_spi_device(dev);
-       unsigned short tx[2] = {
-               AD714x_SPI_CMD_PREFIX | reg,
-               data
-       };
+       struct spi_device *spi = to_spi_device(chip->dev);
+       int error;
+
+       chip->xfer_buf[0] = cpu_to_be16(AD714x_SPI_CMD_PREFIX | reg);
+       chip->xfer_buf[1] = cpu_to_be16(data);
+
+       error = spi_write(spi, (u8 *)chip->xfer_buf,
+                         2 * sizeof(*chip->xfer_buf));
+       if (unlikely(error)) {
+               dev_err(chip->dev, "SPI write error: %d\n", error);
+               return error;
+       }
 
-       return spi_write(spi, (u8 *)tx, 4);
+       return 0;
 }
 
 static int __devinit ad714x_spi_probe(struct spi_device *spi)
 {
        struct ad714x_chip *chip;
+       int err;
+
+       spi->bits_per_word = 8;
+       err = spi_setup(spi);
+       if (err < 0)
+               return err;
 
        chip = ad714x_probe(&spi->dev, BUS_SPI, spi->irq,
                            ad714x_spi_read, ad714x_spi_write);
index c3a62c4..ca42c7d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * AD714X CapTouch Programmable Controller driver supporting AD7142/3/7/8/7A
  *
- * Copyright 2009 Analog Devices Inc.
+ * Copyright 2009-2011 Analog Devices Inc.
  *
  * Licensed under the GPL-2 or later.
  */
@@ -59,7 +59,6 @@
 #define STAGE11_AMBIENT                0x27D
 
 #define PER_STAGE_REG_NUM      36
-#define STAGE_NUM              12
 #define STAGE_CFGREG_NUM       8
 #define SYS_CFGREG_NUM         8
 
@@ -124,27 +123,6 @@ struct ad714x_driver_data {
  * information to integrate all things which will be private data
  * of spi/i2c device
  */
-struct ad714x_chip {
-       unsigned short h_state;
-       unsigned short l_state;
-       unsigned short c_state;
-       unsigned short adc_reg[STAGE_NUM];
-       unsigned short amb_reg[STAGE_NUM];
-       unsigned short sensor_val[STAGE_NUM];
-
-       struct ad714x_platform_data *hw;
-       struct ad714x_driver_data *sw;
-
-       int irq;
-       struct device *dev;
-       ad714x_read_t read;
-       ad714x_write_t write;
-
-       struct mutex mutex;
-
-       unsigned product;
-       unsigned version;
-};
 
 static void ad714x_use_com_int(struct ad714x_chip *ad714x,
                                int start_stage, int end_stage)
@@ -154,13 +132,13 @@ static void ad714x_use_com_int(struct ad714x_chip *ad714x,
 
        mask = ((1 << (end_stage + 1)) - 1) - ((1 << start_stage) - 1);
 
-       ad714x->read(ad714x->dev, STG_COM_INT_EN_REG, &data);
+       ad714x->read(ad714x, STG_COM_INT_EN_REG, &data, 1);
        data |= 1 << end_stage;
-       ad714x->write(ad714x->dev, STG_COM_INT_EN_REG, data);
+       ad714x->write(ad714x, STG_COM_INT_EN_REG, data);
 
-       ad714x->read(ad714x->dev, STG_HIGH_INT_EN_REG, &data);
+       ad714x->read(ad714x, STG_HIGH_INT_EN_REG, &data, 1);
        data &= ~mask;
-       ad714x->write(ad714x->dev, STG_HIGH_INT_EN_REG, data);
+       ad714x->write(ad714x, STG_HIGH_INT_EN_REG, data);
 }
 
 static void ad714x_use_thr_int(struct ad714x_chip *ad714x,
@@ -171,13 +149,13 @@ static void ad714x_use_thr_int(struct ad714x_chip *ad714x,
 
        mask = ((1 << (end_stage + 1)) - 1) - ((1 << start_stage) - 1);
 
-       ad714x->read(ad714x->dev, STG_COM_INT_EN_REG, &data);
+       ad714x->read(ad714x, STG_COM_INT_EN_REG, &data, 1);
        data &= ~(1 << end_stage);
-       ad714x->write(ad714x->dev, STG_COM_INT_EN_REG, data);
+       ad714x->write(ad714x, STG_COM_INT_EN_REG, data);
 
-       ad714x->read(ad714x->dev, STG_HIGH_INT_EN_REG, &data);
+       ad714x->read(ad714x, STG_HIGH_INT_EN_REG, &data, 1);
        data |= mask;
-       ad714x->write(ad714x->dev, STG_HIGH_INT_EN_REG, data);
+       ad714x->write(ad714x, STG_HIGH_INT_EN_REG, data);
 }
 
 static int ad714x_cal_highest_stage(struct ad714x_chip *ad714x,
@@ -273,15 +251,16 @@ static void ad714x_slider_cal_sensor_val(struct ad714x_chip *ad714x, int idx)
        struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
        int i;
 
+       ad714x->read(ad714x, CDC_RESULT_S0 + hw->start_stage,
+                       &ad714x->adc_reg[hw->start_stage],
+                       hw->end_stage - hw->start_stage + 1);
+
        for (i = hw->start_stage; i <= hw->end_stage; i++) {
-               ad714x->read(ad714x->dev, CDC_RESULT_S0 + i,
-                       &ad714x->adc_reg[i]);
-               ad714x->read(ad714x->dev,
-                               STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
-                               &ad714x->amb_reg[i]);
-
-               ad714x->sensor_val[i] = abs(ad714x->adc_reg[i] -
-                               ad714x->amb_reg[i]);
+               ad714x->read(ad714x, STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
+                               &ad714x->amb_reg[i], 1);
+
+               ad714x->sensor_val[i] =
+                       abs(ad714x->adc_reg[i] - ad714x->amb_reg[i]);
        }
 }
 
@@ -444,15 +423,16 @@ static void ad714x_wheel_cal_sensor_val(struct ad714x_chip *ad714x, int idx)
        struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
        int i;
 
+       ad714x->read(ad714x, CDC_RESULT_S0 + hw->start_stage,
+                       &ad714x->adc_reg[hw->start_stage],
+                       hw->end_stage - hw->start_stage + 1);
+
        for (i = hw->start_stage; i <= hw->end_stage; i++) {
-               ad714x->read(ad714x->dev, CDC_RESULT_S0 + i,
-                       &ad714x->adc_reg[i]);
-               ad714x->read(ad714x->dev,
-                               STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
-                               &ad714x->amb_reg[i]);
+               ad714x->read(ad714x, STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
+                               &ad714x->amb_reg[i], 1);
                if (ad714x->adc_reg[i] > ad714x->amb_reg[i])
-                       ad714x->sensor_val[i] = ad714x->adc_reg[i] -
-                               ad714x->amb_reg[i];
+                       ad714x->sensor_val[i] =
+                               ad714x->adc_reg[i] - ad714x->amb_reg[i];
                else
                        ad714x->sensor_val[i] = 0;
        }
@@ -597,15 +577,16 @@ static void touchpad_cal_sensor_val(struct ad714x_chip *ad714x, int idx)
        struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
        int i;
 
+       ad714x->read(ad714x, CDC_RESULT_S0 + hw->x_start_stage,
+                       &ad714x->adc_reg[hw->x_start_stage],
+                       hw->x_end_stage - hw->x_start_stage + 1);
+
        for (i = hw->x_start_stage; i <= hw->x_end_stage; i++) {
-               ad714x->read(ad714x->dev, CDC_RESULT_S0 + i,
-                               &ad714x->adc_reg[i]);
-               ad714x->read(ad714x->dev,
-                               STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
-                               &ad714x->amb_reg[i]);
+               ad714x->read(ad714x, STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
+                               &ad714x->amb_reg[i], 1);
                if (ad714x->adc_reg[i] > ad714x->amb_reg[i])
-                       ad714x->sensor_val[i] = ad714x->adc_reg[i] -
-                               ad714x->amb_reg[i];
+                       ad714x->sensor_val[i] =
+                               ad714x->adc_reg[i] - ad714x->amb_reg[i];
                else
                        ad714x->sensor_val[i] = 0;
        }
@@ -891,7 +872,7 @@ static int ad714x_hw_detect(struct ad714x_chip *ad714x)
 {
        unsigned short data;
 
-       ad714x->read(ad714x->dev, AD714X_PARTID_REG, &data);
+       ad714x->read(ad714x, AD714X_PARTID_REG, &data, 1);
        switch (data & 0xFFF0) {
        case AD7142_PARTID:
                ad714x->product = 0x7142;
@@ -940,23 +921,20 @@ static void ad714x_hw_init(struct ad714x_chip *ad714x)
        for (i = 0; i < STAGE_NUM; i++) {
                reg_base = AD714X_STAGECFG_REG + i * STAGE_CFGREG_NUM;
                for (j = 0; j < STAGE_CFGREG_NUM; j++)
-                       ad714x->write(ad714x->dev, reg_base + j,
+                       ad714x->write(ad714x, reg_base + j,
                                        ad714x->hw->stage_cfg_reg[i][j]);
        }
 
        for (i = 0; i < SYS_CFGREG_NUM; i++)
-               ad714x->write(ad714x->dev, AD714X_SYSCFG_REG + i,
+               ad714x->write(ad714x, AD714X_SYSCFG_REG + i,
                        ad714x->hw->sys_cfg_reg[i]);
        for (i = 0; i < SYS_CFGREG_NUM; i++)
-               ad714x->read(ad714x->dev, AD714X_SYSCFG_REG + i,
-                       &data);
+               ad714x->read(ad714x, AD714X_SYSCFG_REG + i, &data, 1);
 
-       ad714x->write(ad714x->dev, AD714X_STG_CAL_EN_REG, 0xFFF);
+       ad714x->write(ad714x, AD714X_STG_CAL_EN_REG, 0xFFF);
 
        /* clear all interrupts */
-       ad714x->read(ad714x->dev, STG_LOW_INT_STA_REG, &data);
-       ad714x->read(ad714x->dev, STG_HIGH_INT_STA_REG, &data);
-       ad714x->read(ad714x->dev, STG_COM_INT_STA_REG, &data);
+       ad714x->read(ad714x, STG_LOW_INT_STA_REG, &ad714x->l_state, 3);
 }
 
 static irqreturn_t ad714x_interrupt_thread(int irq, void *data)
@@ -966,9 +944,7 @@ static irqreturn_t ad714x_interrupt_thread(int irq, void *data)
 
        mutex_lock(&ad714x->mutex);
 
-       ad714x->read(ad714x->dev, STG_LOW_INT_STA_REG, &ad714x->l_state);
-       ad714x->read(ad714x->dev, STG_HIGH_INT_STA_REG, &ad714x->h_state);
-       ad714x->read(ad714x->dev, STG_COM_INT_STA_REG, &ad714x->c_state);
+       ad714x->read(ad714x, STG_LOW_INT_STA_REG, &ad714x->l_state, 3);
 
        for (i = 0; i < ad714x->hw->button_num; i++)
                ad714x_button_state_machine(ad714x, i);
@@ -1245,7 +1221,7 @@ int ad714x_disable(struct ad714x_chip *ad714x)
        mutex_lock(&ad714x->mutex);
 
        data = ad714x->hw->sys_cfg_reg[AD714X_PWR_CTRL] | 0x3;
-       ad714x->write(ad714x->dev, AD714X_PWR_CTRL, data);
+       ad714x->write(ad714x, AD714X_PWR_CTRL, data);
 
        mutex_unlock(&ad714x->mutex);
 
@@ -1255,24 +1231,20 @@ EXPORT_SYMBOL(ad714x_disable);
 
 int ad714x_enable(struct ad714x_chip *ad714x)
 {
-       unsigned short data;
-
        dev_dbg(ad714x->dev, "%s enter\n", __func__);
 
        mutex_lock(&ad714x->mutex);
 
        /* resume to non-shutdown mode */
 
-       ad714x->write(ad714x->dev, AD714X_PWR_CTRL,
+       ad714x->write(ad714x, AD714X_PWR_CTRL,
                        ad714x->hw->sys_cfg_reg[AD714X_PWR_CTRL]);
 
        /* make sure the interrupt output line is not low level after resume,
         * otherwise we will get no chance to enter falling-edge irq again
         */
 
-       ad714x->read(ad714x->dev, STG_LOW_INT_STA_REG, &data);
-       ad714x->read(ad714x->dev, STG_HIGH_INT_STA_REG, &data);
-       ad714x->read(ad714x->dev, STG_COM_INT_STA_REG, &data);
+       ad714x->read(ad714x, STG_LOW_INT_STA_REG, &ad714x->l_state, 3);
 
        mutex_unlock(&ad714x->mutex);
 
index 45c54fb..3c85455 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * AD714X CapTouch Programmable Controller driver (bus interfaces)
  *
- * Copyright 2009 Analog Devices Inc.
+ * Copyright 2009-2011 Analog Devices Inc.
  *
  * Licensed under the GPL-2 or later.
  */
 
 #include <linux/types.h>
 
+#define STAGE_NUM              12
+
 struct device;
+struct ad714x_platform_data;
+struct ad714x_driver_data;
 struct ad714x_chip;
 
-typedef int (*ad714x_read_t)(struct device *, unsigned short, unsigned short *);
-typedef int (*ad714x_write_t)(struct device *, unsigned short, unsigned short);
+typedef int (*ad714x_read_t)(struct ad714x_chip *, unsigned short, unsigned short *, size_t);
+typedef int (*ad714x_write_t)(struct ad714x_chip *, unsigned short, unsigned short);
+
+struct ad714x_chip {
+       unsigned short l_state;
+       unsigned short h_state;
+       unsigned short c_state;
+       unsigned short adc_reg[STAGE_NUM];
+       unsigned short amb_reg[STAGE_NUM];
+       unsigned short sensor_val[STAGE_NUM];
+
+       struct ad714x_platform_data *hw;
+       struct ad714x_driver_data *sw;
+
+       int irq;
+       struct device *dev;
+       ad714x_read_t read;
+       ad714x_write_t write;
+
+       struct mutex mutex;
+
+       unsigned product;
+       unsigned version;
+
+       __be16 xfer_buf[16] ____cacheline_aligned;
+
+};
 
 int ad714x_disable(struct ad714x_chip *ad714x);
 int ad714x_enable(struct ad714x_chip *ad714x);
index c456f63..783597a 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/i2c.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
+#include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/input/kxtj9.h>
 #include <linux/input-polldev.h>
index 20f8f92..0794778 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/input-polldev.h>
+#include <linux/of_device.h>
 
 #define MMA8450_DRV_NAME       "mma8450"
 
@@ -229,10 +230,17 @@ static const struct i2c_device_id mma8450_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, mma8450_id);
 
+static const struct of_device_id mma8450_dt_ids[] = {
+       { .compatible = "fsl,mma8450", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mma8450_dt_ids);
+
 static struct i2c_driver mma8450_driver = {
        .driver = {
                .name   = MMA8450_DRV_NAME,
                .owner  = THIS_MODULE,
+               .of_match_table = mma8450_dt_ids,
        },
        .probe          = mma8450_probe,
        .remove         = __devexit_p(mma8450_remove),
index b95fac1..f71dc72 100644 (file)
@@ -282,7 +282,7 @@ err_free_irq:
 err_pm_set_suspended:
        pm_runtime_set_suspended(&client->dev);
 err_free_mem:
-       input_unregister_device(idev);
+       input_free_device(idev);
        kfree(sensor);
        return error;
 }
index 3126983..da28018 100644 (file)
 #define USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI   0x0245
 #define USB_DEVICE_ID_APPLE_WELLSPRING5_ISO    0x0246
 #define USB_DEVICE_ID_APPLE_WELLSPRING5_JIS    0x0247
+/* MacbookAir4,2 (unibody, July 2011) */
+#define USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI   0x024c
+#define USB_DEVICE_ID_APPLE_WELLSPRING6_ISO    0x024d
+#define USB_DEVICE_ID_APPLE_WELLSPRING6_JIS    0x024e
+/* Macbook8,2 (unibody) */
+#define USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI  0x0252
+#define USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO   0x0253
+#define USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS   0x0254
 
 #define BCM5974_DEVICE(prod) {                                 \
        .match_flags = (USB_DEVICE_ID_MATCH_DEVICE |            \
@@ -104,6 +112,14 @@ static const struct usb_device_id bcm5974_table[] = {
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI),
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_ISO),
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_JIS),
+       /* MacbookAir4,2 */
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI),
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6_ISO),
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6_JIS),
+       /* MacbookPro8,2 */
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI),
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO),
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS),
        /* Terminating entry */
        {}
 };
@@ -294,6 +310,30 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                { DIM_X, DIM_X / SN_COORD, -4415, 5050 },
                { DIM_Y, DIM_Y / SN_COORD, -55, 6680 }
        },
+       {
+               USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI,
+               USB_DEVICE_ID_APPLE_WELLSPRING6_ISO,
+               USB_DEVICE_ID_APPLE_WELLSPRING6_JIS,
+               HAS_INTEGRATED_BUTTON,
+               0x84, sizeof(struct bt_data),
+               0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+               { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
+               { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
+               { DIM_X, DIM_X / SN_COORD, -4620, 5140 },
+               { DIM_Y, DIM_Y / SN_COORD, -150, 6600 }
+       },
+       {
+               USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI,
+               USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO,
+               USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS,
+               HAS_INTEGRATED_BUTTON,
+               0x84, sizeof(struct bt_data),
+               0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+               { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
+               { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
+               { DIM_X, DIM_X / SN_COORD, -4750, 5280 },
+               { DIM_Y, DIM_Y / SN_COORD, -150, 6730 }
+       },
        {}
 };
 
index 95577c1..4d17d9f 100644 (file)
@@ -32,6 +32,7 @@
 #define DEBUG
 #include <linux/slab.h>
 #include <linux/input.h>
+#include <linux/module.h>
 #include <linux/serio.h>
 #include <linux/libps2.h>
 #include <linux/delay.h>
index 80baa53..d64c5a4 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/io.h>
-
+#include <linux/of_address.h>
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
 
index 449c0a4..d27c9d9 100644 (file)
@@ -49,6 +49,7 @@ struct hid_descriptor {
 #define USB_REQ_GET_REPORT     0x01
 #define USB_REQ_SET_REPORT     0x09
 #define WAC_HID_FEATURE_REPORT 0x03
+#define WAC_MSG_RETRIES                5
 
 static int usb_get_report(struct usb_interface *intf, unsigned char type,
                                unsigned char id, void *buf, int size)
@@ -165,7 +166,7 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
                        report,
                        hid_desc->wDescriptorLength,
                        5000); /* 5 secs */
-       } while (result < 0 && limit++ < 5);
+       } while (result < 0 && limit++ < WAC_MSG_RETRIES);
 
        /* No need to parse the Descriptor. It isn't an error though */
        if (result < 0)
@@ -319,24 +320,26 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat
        int limit = 0, report_id = 2;
        int error = -ENOMEM;
 
-       rep_data = kmalloc(2, GFP_KERNEL);
+       rep_data = kmalloc(4, GFP_KERNEL);
        if (!rep_data)
                return error;
 
-       /* ask to report tablet data if it is 2FGT Tablet PC or
+       /* ask to report tablet data if it is MT Tablet PC or
         * not a Tablet PC */
        if (features->type == TABLETPC2FG) {
                do {
                        rep_data[0] = 3;
                        rep_data[1] = 4;
+                       rep_data[2] = 0;
+                       rep_data[3] = 0;
                        report_id = 3;
                        error = usb_set_report(intf, WAC_HID_FEATURE_REPORT,
-                               report_id, rep_data, 2);
+                               report_id, rep_data, 4);
                        if (error >= 0)
                                error = usb_get_report(intf,
                                        WAC_HID_FEATURE_REPORT, report_id,
-                                       rep_data, 3);
-               } while ((error < 0 || rep_data[1] != 4) && limit++ < 5);
+                                       rep_data, 4);
+               } while ((error < 0 || rep_data[1] != 4) && limit++ < WAC_MSG_RETRIES);
        } else if (features->type != TABLETPC) {
                do {
                        rep_data[0] = 2;
@@ -347,7 +350,7 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat
                                error = usb_get_report(intf,
                                        WAC_HID_FEATURE_REPORT, report_id,
                                        rep_data, 2);
-               } while ((error < 0 || rep_data[1] != 2) && limit++ < 5);
+               } while ((error < 0 || rep_data[1] != 2) && limit++ < WAC_MSG_RETRIES);
        }
 
        kfree(rep_data);
index 03ebcc8..c1c2f7b 100644 (file)
@@ -1460,6 +1460,9 @@ static const struct wacom_features wacom_features_0xD3 =
 static const struct wacom_features wacom_features_0xD4 =
        { "Wacom Bamboo Pen",     WACOM_PKGLEN_BBFUN,     14720,  9200, 1023,
          63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0xD5 =
+       { "Wacom Bamboo Pen 6x8",     WACOM_PKGLEN_BBFUN, 21648, 13530, 1023,
+         63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0xD6 =
        { "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN,   14720,  9200, 1023,
          63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -1564,6 +1567,7 @@ const struct usb_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0xD2) },
        { USB_DEVICE_WACOM(0xD3) },
        { USB_DEVICE_WACOM(0xD4) },
+       { USB_DEVICE_WACOM(0xD5) },
        { USB_DEVICE_WACOM(0xD6) },
        { USB_DEVICE_WACOM(0xD7) },
        { USB_DEVICE_WACOM(0xD8) },
index bc3b518..131f9d1 100644 (file)
@@ -249,12 +249,14 @@ static void __ad7879_enable(struct ad7879 *ts)
 
 static void __ad7879_disable(struct ad7879 *ts)
 {
+       u16 reg = (ts->cmd_crtl2 & ~AD7879_PM(-1)) |
+               AD7879_PM(AD7879_PM_SHUTDOWN);
        disable_irq(ts->irq);
 
        if (del_timer_sync(&ts->timer))
                ad7879_ts_event_release(ts);
 
-       ad7879_write(ts, AD7879_REG_CTRL2, AD7879_PM(AD7879_PM_SHUTDOWN));
+       ad7879_write(ts, AD7879_REG_CTRL2, reg);
 }
 
 
index ae00604..f5d6685 100644 (file)
@@ -244,6 +244,7 @@ struct mxt_finger {
        int x;
        int y;
        int area;
+       int pressure;
 };
 
 /* Each client has this additional data */
@@ -536,6 +537,8 @@ static void mxt_input_report(struct mxt_data *data, int single_id)
                                        finger[id].x);
                        input_report_abs(input_dev, ABS_MT_POSITION_Y,
                                        finger[id].y);
+                       input_report_abs(input_dev, ABS_MT_PRESSURE,
+                                       finger[id].pressure);
                } else {
                        finger[id].status = 0;
                }
@@ -546,6 +549,8 @@ static void mxt_input_report(struct mxt_data *data, int single_id)
        if (status != MXT_RELEASE) {
                input_report_abs(input_dev, ABS_X, finger[single_id].x);
                input_report_abs(input_dev, ABS_Y, finger[single_id].y);
+               input_report_abs(input_dev,
+                                ABS_PRESSURE, finger[single_id].pressure);
        }
 
        input_sync(input_dev);
@@ -560,6 +565,7 @@ static void mxt_input_touchevent(struct mxt_data *data,
        int x;
        int y;
        int area;
+       int pressure;
 
        /* Check the touch is present on the screen */
        if (!(status & MXT_DETECT)) {
@@ -584,6 +590,7 @@ static void mxt_input_touchevent(struct mxt_data *data,
                y = y >> 2;
 
        area = message->message[4];
+       pressure = message->message[5];
 
        dev_dbg(dev, "[%d] %s x: %d, y: %d, area: %d\n", id,
                status & MXT_MOVE ? "moved" : "pressed",
@@ -594,6 +601,7 @@ static void mxt_input_touchevent(struct mxt_data *data,
        finger[id].x = x;
        finger[id].y = y;
        finger[id].area = area;
+       finger[id].pressure = pressure;
 
        mxt_input_report(data, id);
 }
@@ -1116,6 +1124,8 @@ static int __devinit mxt_probe(struct i2c_client *client,
                             0, data->max_x, 0, 0);
        input_set_abs_params(input_dev, ABS_Y,
                             0, data->max_y, 0, 0);
+       input_set_abs_params(input_dev, ABS_PRESSURE,
+                            0, 255, 0, 0);
 
        /* For multi touch */
        input_mt_init_slots(input_dev, MXT_MAX_FINGER);
@@ -1125,6 +1135,8 @@ static int __devinit mxt_probe(struct i2c_client *client,
                             0, data->max_x, 0, 0);
        input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
                             0, data->max_y, 0, 0);
+       input_set_abs_params(input_dev, ABS_MT_PRESSURE,
+                            0, 255, 0, 0);
 
        input_set_drvdata(input_dev, data);
        i2c_set_clientdata(client, data);
index 4f2713d..4627fe5 100644 (file)
@@ -9,7 +9,8 @@
  *
  * 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.
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  */
 
 /*
index 089b0a0..0e8f63e 100644 (file)
@@ -13,6 +13,7 @@
  * GNU General Public License for more details.
  */
 
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/err.h>
 #include <linux/errno.h>
index 8420129..f75a66e 100644 (file)
@@ -241,12 +241,13 @@ config DM_MIRROR
          needed for live data migration tools such as 'pvmove'.
 
 config DM_RAID
-       tristate "RAID 4/5/6 target (EXPERIMENTAL)"
+       tristate "RAID 1/4/5/6 target (EXPERIMENTAL)"
        depends on BLK_DEV_DM && EXPERIMENTAL
+       select MD_RAID1
        select MD_RAID456
        select BLK_DEV_MD
        ---help---
-        A dm target that supports RAID4, RAID5 and RAID6 mappings
+        A dm target that supports RAID1, RAID4, RAID5 and RAID6 mappings
 
         A RAID-5 set of N drives with a capacity of C MB per drive provides
         the capacity of C * (N - 1) MB, and protects against a failure
index bae6c4e..49da55c 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/device-mapper.h>
 
 #define DM_MSG_PREFIX "crypt"
-#define MESG_STR(x) x, sizeof(x)
 
 /*
  * context holding the current state of a multi-part conversion
@@ -239,7 +238,7 @@ static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv,
                              struct dm_crypt_request *dmreq)
 {
        memset(iv, 0, cc->iv_size);
-       *(u32 *)iv = cpu_to_le32(dmreq->iv_sector & 0xffffffff);
+       *(__le32 *)iv = cpu_to_le32(dmreq->iv_sector & 0xffffffff);
 
        return 0;
 }
@@ -248,7 +247,7 @@ static int crypt_iv_plain64_gen(struct crypt_config *cc, u8 *iv,
                                struct dm_crypt_request *dmreq)
 {
        memset(iv, 0, cc->iv_size);
-       *(u64 *)iv = cpu_to_le64(dmreq->iv_sector);
+       *(__le64 *)iv = cpu_to_le64(dmreq->iv_sector);
 
        return 0;
 }
@@ -415,7 +414,7 @@ static int crypt_iv_essiv_gen(struct crypt_config *cc, u8 *iv,
        struct crypto_cipher *essiv_tfm = this_crypt_config(cc)->iv_private;
 
        memset(iv, 0, cc->iv_size);
-       *(u64 *)iv = cpu_to_le64(dmreq->iv_sector);
+       *(__le64 *)iv = cpu_to_le64(dmreq->iv_sector);
        crypto_cipher_encrypt_one(essiv_tfm, iv, iv);
 
        return 0;
@@ -1575,11 +1574,17 @@ bad_mem:
 static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 {
        struct crypt_config *cc;
-       unsigned int key_size;
+       unsigned int key_size, opt_params;
        unsigned long long tmpll;
        int ret;
+       struct dm_arg_set as;
+       const char *opt_string;
+
+       static struct dm_arg _args[] = {
+               {0, 1, "Invalid number of feature args"},
+       };
 
-       if (argc != 5) {
+       if (argc < 5) {
                ti->error = "Not enough arguments";
                return -EINVAL;
        }
@@ -1648,6 +1653,30 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        }
        cc->start = tmpll;
 
+       argv += 5;
+       argc -= 5;
+
+       /* Optional parameters */
+       if (argc) {
+               as.argc = argc;
+               as.argv = argv;
+
+               ret = dm_read_arg_group(_args, &as, &opt_params, &ti->error);
+               if (ret)
+                       goto bad;
+
+               opt_string = dm_shift_arg(&as);
+
+               if (opt_params == 1 && opt_string &&
+                   !strcasecmp(opt_string, "allow_discards"))
+                       ti->num_discard_requests = 1;
+               else if (opt_params) {
+                       ret = -EINVAL;
+                       ti->error = "Invalid feature arguments";
+                       goto bad;
+               }
+       }
+
        ret = -ENOMEM;
        cc->io_queue = alloc_workqueue("kcryptd_io",
                                       WQ_NON_REENTRANT|
@@ -1682,9 +1711,16 @@ static int crypt_map(struct dm_target *ti, struct bio *bio,
        struct dm_crypt_io *io;
        struct crypt_config *cc;
 
-       if (bio->bi_rw & REQ_FLUSH) {
+       /*
+        * If bio is REQ_FLUSH or REQ_DISCARD, just bypass crypt queues.
+        * - for REQ_FLUSH device-mapper core ensures that no IO is in-flight
+        * - for REQ_DISCARD caller must use flush if IO ordering matters
+        */
+       if (unlikely(bio->bi_rw & (REQ_FLUSH | REQ_DISCARD))) {
                cc = ti->private;
                bio->bi_bdev = cc->dev->bdev;
+               if (bio_sectors(bio))
+                       bio->bi_sector = cc->start + dm_target_offset(ti, bio->bi_sector);
                return DM_MAPIO_REMAPPED;
        }
 
@@ -1727,6 +1763,10 @@ static int crypt_status(struct dm_target *ti, status_type_t type,
 
                DMEMIT(" %llu %s %llu", (unsigned long long)cc->iv_offset,
                                cc->dev->name, (unsigned long long)cc->start);
+
+               if (ti->num_discard_requests)
+                       DMEMIT(" 1 allow_discards");
+
                break;
        }
        return 0;
@@ -1770,12 +1810,12 @@ static int crypt_message(struct dm_target *ti, unsigned argc, char **argv)
        if (argc < 2)
                goto error;
 
-       if (!strnicmp(argv[0], MESG_STR("key"))) {
+       if (!strcasecmp(argv[0], "key")) {
                if (!test_bit(DM_CRYPT_SUSPENDED, &cc->flags)) {
                        DMWARN("not suspended during key manipulation.");
                        return -EINVAL;
                }
-               if (argc == 3 && !strnicmp(argv[1], MESG_STR("set"))) {
+               if (argc == 3 && !strcasecmp(argv[1], "set")) {
                        ret = crypt_set_key(cc, argv[2]);
                        if (ret)
                                return ret;
@@ -1783,7 +1823,7 @@ static int crypt_message(struct dm_target *ti, unsigned argc, char **argv)
                                ret = cc->iv_gen_ops->init(cc);
                        return ret;
                }
-               if (argc == 2 && !strnicmp(argv[1], MESG_STR("wipe"))) {
+               if (argc == 2 && !strcasecmp(argv[1], "wipe")) {
                        if (cc->iv_gen_ops && cc->iv_gen_ops->wipe) {
                                ret = cc->iv_gen_ops->wipe(cc);
                                if (ret)
@@ -1823,7 +1863,7 @@ static int crypt_iterate_devices(struct dm_target *ti,
 
 static struct target_type crypt_target = {
        .name   = "crypt",
-       .version = {1, 10, 0},
+       .version = {1, 11, 0},
        .module = THIS_MODULE,
        .ctr    = crypt_ctr,
        .dtr    = crypt_dtr,
index ea79062..89f73ca 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2003 Sistina Software (UK) Limited.
- * Copyright (C) 2004, 2010 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004, 2010-2011 Red Hat, Inc. All rights reserved.
  *
  * This file is released under the GPL.
  */
@@ -15,6 +15,9 @@
 
 #define DM_MSG_PREFIX "flakey"
 
+#define all_corrupt_bio_flags_match(bio, fc)   \
+       (((bio)->bi_rw & (fc)->corrupt_bio_flags) == (fc)->corrupt_bio_flags)
+
 /*
  * Flakey: Used for testing only, simulates intermittent,
  * catastrophic device failure.
@@ -25,60 +28,189 @@ struct flakey_c {
        sector_t start;
        unsigned up_interval;
        unsigned down_interval;
+       unsigned long flags;
+       unsigned corrupt_bio_byte;
+       unsigned corrupt_bio_rw;
+       unsigned corrupt_bio_value;
+       unsigned corrupt_bio_flags;
+};
+
+enum feature_flag_bits {
+       DROP_WRITES
 };
 
+static int parse_features(struct dm_arg_set *as, struct flakey_c *fc,
+                         struct dm_target *ti)
+{
+       int r;
+       unsigned argc;
+       const char *arg_name;
+
+       static struct dm_arg _args[] = {
+               {0, 6, "Invalid number of feature args"},
+               {1, UINT_MAX, "Invalid corrupt bio byte"},
+               {0, 255, "Invalid corrupt value to write into bio byte (0-255)"},
+               {0, UINT_MAX, "Invalid corrupt bio flags mask"},
+       };
+
+       /* No feature arguments supplied. */
+       if (!as->argc)
+               return 0;
+
+       r = dm_read_arg_group(_args, as, &argc, &ti->error);
+       if (r)
+               return r;
+
+       while (argc) {
+               arg_name = dm_shift_arg(as);
+               argc--;
+
+               /*
+                * drop_writes
+                */
+               if (!strcasecmp(arg_name, "drop_writes")) {
+                       if (test_and_set_bit(DROP_WRITES, &fc->flags)) {
+                               ti->error = "Feature drop_writes duplicated";
+                               return -EINVAL;
+                       }
+
+                       continue;
+               }
+
+               /*
+                * corrupt_bio_byte <Nth_byte> <direction> <value> <bio_flags>
+                */
+               if (!strcasecmp(arg_name, "corrupt_bio_byte")) {
+                       if (!argc)
+                               ti->error = "Feature corrupt_bio_byte requires parameters";
+
+                       r = dm_read_arg(_args + 1, as, &fc->corrupt_bio_byte, &ti->error);
+                       if (r)
+                               return r;
+                       argc--;
+
+                       /*
+                        * Direction r or w?
+                        */
+                       arg_name = dm_shift_arg(as);
+                       if (!strcasecmp(arg_name, "w"))
+                               fc->corrupt_bio_rw = WRITE;
+                       else if (!strcasecmp(arg_name, "r"))
+                               fc->corrupt_bio_rw = READ;
+                       else {
+                               ti->error = "Invalid corrupt bio direction (r or w)";
+                               return -EINVAL;
+                       }
+                       argc--;
+
+                       /*
+                        * Value of byte (0-255) to write in place of correct one.
+                        */
+                       r = dm_read_arg(_args + 2, as, &fc->corrupt_bio_value, &ti->error);
+                       if (r)
+                               return r;
+                       argc--;
+
+                       /*
+                        * Only corrupt bios with these flags set.
+                        */
+                       r = dm_read_arg(_args + 3, as, &fc->corrupt_bio_flags, &ti->error);
+                       if (r)
+                               return r;
+                       argc--;
+
+                       continue;
+               }
+
+               ti->error = "Unrecognised flakey feature requested";
+               return -EINVAL;
+       }
+
+       if (test_bit(DROP_WRITES, &fc->flags) && (fc->corrupt_bio_rw == WRITE)) {
+               ti->error = "drop_writes is incompatible with corrupt_bio_byte with the WRITE flag set";
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 /*
- * Construct a flakey mapping: <dev_path> <offset> <up interval> <down interval>
+ * Construct a flakey mapping:
+ * <dev_path> <offset> <up interval> <down interval> [<#feature args> [<arg>]*]
+ *
+ *   Feature args:
+ *     [drop_writes]
+ *     [corrupt_bio_byte <Nth_byte> <direction> <value> <bio_flags>]
+ *
+ *   Nth_byte starts from 1 for the first byte.
+ *   Direction is r for READ or w for WRITE.
+ *   bio_flags is ignored if 0.
  */
 static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 {
+       static struct dm_arg _args[] = {
+               {0, UINT_MAX, "Invalid up interval"},
+               {0, UINT_MAX, "Invalid down interval"},
+       };
+
+       int r;
        struct flakey_c *fc;
-       unsigned long long tmp;
+       unsigned long long tmpll;
+       struct dm_arg_set as;
+       const char *devname;
 
-       if (argc != 4) {
-               ti->error = "dm-flakey: Invalid argument count";
+       as.argc = argc;
+       as.argv = argv;
+
+       if (argc < 4) {
+               ti->error = "Invalid argument count";
                return -EINVAL;
        }
 
-       fc = kmalloc(sizeof(*fc), GFP_KERNEL);
+       fc = kzalloc(sizeof(*fc), GFP_KERNEL);
        if (!fc) {
-               ti->error = "dm-flakey: Cannot allocate linear context";
+               ti->error = "Cannot allocate linear context";
                return -ENOMEM;
        }
        fc->start_time = jiffies;
 
-       if (sscanf(argv[1], "%llu", &tmp) != 1) {
-               ti->error = "dm-flakey: Invalid device sector";
+       devname = dm_shift_arg(&as);
+
+       if (sscanf(dm_shift_arg(&as), "%llu", &tmpll) != 1) {
+               ti->error = "Invalid device sector";
                goto bad;
        }
-       fc->start = tmp;
+       fc->start = tmpll;
 
-       if (sscanf(argv[2], "%u", &fc->up_interval) != 1) {
-               ti->error = "dm-flakey: Invalid up interval";
+       r = dm_read_arg(_args, &as, &fc->up_interval, &ti->error);
+       if (r)
                goto bad;
-       }
 
-       if (sscanf(argv[3], "%u", &fc->down_interval) != 1) {
-               ti->error = "dm-flakey: Invalid down interval";
+       r = dm_read_arg(_args, &as, &fc->down_interval, &ti->error);
+       if (r)
                goto bad;
-       }
 
        if (!(fc->up_interval + fc->down_interval)) {
-               ti->error = "dm-flakey: Total (up + down) interval is zero";
+               ti->error = "Total (up + down) interval is zero";
                goto bad;
        }
 
        if (fc->up_interval + fc->down_interval < fc->up_interval) {
-               ti->error = "dm-flakey: Interval overflow";
+               ti->error = "Interval overflow";
                goto bad;
        }
 
-       if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &fc->dev)) {
-               ti->error = "dm-flakey: Device lookup failed";
+       r = parse_features(&as, fc, ti);
+       if (r)
+               goto bad;
+
+       if (dm_get_device(ti, devname, dm_table_get_mode(ti->table), &fc->dev)) {
+               ti->error = "Device lookup failed";
                goto bad;
        }
 
        ti->num_flush_requests = 1;
+       ti->num_discard_requests = 1;
        ti->private = fc;
        return 0;
 
@@ -99,7 +231,7 @@ static sector_t flakey_map_sector(struct dm_target *ti, sector_t bi_sector)
 {
        struct flakey_c *fc = ti->private;
 
-       return fc->start + (bi_sector - ti->begin);
+       return fc->start + dm_target_offset(ti, bi_sector);
 }
 
 static void flakey_map_bio(struct dm_target *ti, struct bio *bio)
@@ -111,6 +243,25 @@ static void flakey_map_bio(struct dm_target *ti, struct bio *bio)
                bio->bi_sector = flakey_map_sector(ti, bio->bi_sector);
 }
 
+static void corrupt_bio_data(struct bio *bio, struct flakey_c *fc)
+{
+       unsigned bio_bytes = bio_cur_bytes(bio);
+       char *data = bio_data(bio);
+
+       /*
+        * Overwrite the Nth byte of the data returned.
+        */
+       if (data && bio_bytes >= fc->corrupt_bio_byte) {
+               data[fc->corrupt_bio_byte - 1] = fc->corrupt_bio_value;
+
+               DMDEBUG("Corrupting data bio=%p by writing %u to byte %u "
+                       "(rw=%c bi_rw=%lu bi_sector=%llu cur_bytes=%u)\n",
+                       bio, fc->corrupt_bio_value, fc->corrupt_bio_byte,
+                       (bio_data_dir(bio) == WRITE) ? 'w' : 'r',
+                       bio->bi_rw, (unsigned long long)bio->bi_sector, bio_bytes);
+       }
+}
+
 static int flakey_map(struct dm_target *ti, struct bio *bio,
                      union map_info *map_context)
 {
@@ -119,18 +270,71 @@ static int flakey_map(struct dm_target *ti, struct bio *bio,
 
        /* Are we alive ? */
        elapsed = (jiffies - fc->start_time) / HZ;
-       if (elapsed % (fc->up_interval + fc->down_interval) >= fc->up_interval)
+       if (elapsed % (fc->up_interval + fc->down_interval) >= fc->up_interval) {
+               /*
+                * Flag this bio as submitted while down.
+                */
+               map_context->ll = 1;
+
+               /*
+                * Map reads as normal.
+                */
+               if (bio_data_dir(bio) == READ)
+                       goto map_bio;
+
+               /*
+                * Drop writes?
+                */
+               if (test_bit(DROP_WRITES, &fc->flags)) {
+                       bio_endio(bio, 0);
+                       return DM_MAPIO_SUBMITTED;
+               }
+
+               /*
+                * Corrupt matching writes.
+                */
+               if (fc->corrupt_bio_byte && (fc->corrupt_bio_rw == WRITE)) {
+                       if (all_corrupt_bio_flags_match(bio, fc))
+                               corrupt_bio_data(bio, fc);
+                       goto map_bio;
+               }
+
+               /*
+                * By default, error all I/O.
+                */
                return -EIO;
+       }
 
+map_bio:
        flakey_map_bio(ti, bio);
 
        return DM_MAPIO_REMAPPED;
 }
 
+static int flakey_end_io(struct dm_target *ti, struct bio *bio,
+                        int error, union map_info *map_context)
+{
+       struct flakey_c *fc = ti->private;
+       unsigned bio_submitted_while_down = map_context->ll;
+
+       /*
+        * Corrupt successful READs while in down state.
+        * If flags were specified, only corrupt those that match.
+        */
+       if (!error && bio_submitted_while_down &&
+           (bio_data_dir(bio) == READ) && (fc->corrupt_bio_rw == READ) &&
+           all_corrupt_bio_flags_match(bio, fc))
+               corrupt_bio_data(bio, fc);
+
+       return error;
+}
+
 static int flakey_status(struct dm_target *ti, status_type_t type,
                         char *result, unsigned int maxlen)
 {
+       unsigned sz = 0;
        struct flakey_c *fc = ti->private;
+       unsigned drop_writes;
 
        switch (type) {
        case STATUSTYPE_INFO:
@@ -138,9 +342,22 @@ static int flakey_status(struct dm_target *ti, status_type_t type,
                break;
 
        case STATUSTYPE_TABLE:
-               snprintf(result, maxlen, "%s %llu %u %u", fc->dev->name,
-                        (unsigned long long)fc->start, fc->up_interval,
-                        fc->down_interval);
+               DMEMIT("%s %llu %u %u ", fc->dev->name,
+                      (unsigned long long)fc->start, fc->up_interval,
+                      fc->down_interval);
+
+               drop_writes = test_bit(DROP_WRITES, &fc->flags);
+               DMEMIT("%u ", drop_writes + (fc->corrupt_bio_byte > 0) * 5);
+
+               if (drop_writes)
+                       DMEMIT("drop_writes ");
+
+               if (fc->corrupt_bio_byte)
+                       DMEMIT("corrupt_bio_byte %u %c %u %u ",
+                              fc->corrupt_bio_byte,
+                              (fc->corrupt_bio_rw == WRITE) ? 'w' : 'r',
+                              fc->corrupt_bio_value, fc->corrupt_bio_flags);
+
                break;
        }
        return 0;
@@ -177,11 +394,12 @@ static int flakey_iterate_devices(struct dm_target *ti, iterate_devices_callout_
 
 static struct target_type flakey_target = {
        .name   = "flakey",
-       .version = {1, 1, 0},
+       .version = {1, 2, 0},
        .module = THIS_MODULE,
        .ctr    = flakey_ctr,
        .dtr    = flakey_dtr,
        .map    = flakey_map,
+       .end_io = flakey_end_io,
        .status = flakey_status,
        .ioctl  = flakey_ioctl,
        .merge  = flakey_merge,
index 2067288..ad2eba4 100644 (file)
@@ -38,6 +38,8 @@ struct io {
        struct dm_io_client *client;
        io_notify_fn callback;
        void *context;
+       void *vma_invalidate_address;
+       unsigned long vma_invalidate_size;
 } __attribute__((aligned(DM_IO_MAX_REGIONS)));
 
 static struct kmem_cache *_dm_io_cache;
@@ -116,6 +118,10 @@ static void dec_count(struct io *io, unsigned int region, int error)
                set_bit(region, &io->error_bits);
 
        if (atomic_dec_and_test(&io->count)) {
+               if (io->vma_invalidate_size)
+                       invalidate_kernel_vmap_range(io->vma_invalidate_address,
+                                                    io->vma_invalidate_size);
+
                if (io->sleeper)
                        wake_up_process(io->sleeper);
 
@@ -159,6 +165,9 @@ struct dpages {
 
        unsigned context_u;
        void *context_ptr;
+
+       void *vma_invalidate_address;
+       unsigned long vma_invalidate_size;
 };
 
 /*
@@ -377,6 +386,9 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions,
        io->sleeper = current;
        io->client = client;
 
+       io->vma_invalidate_address = dp->vma_invalidate_address;
+       io->vma_invalidate_size = dp->vma_invalidate_size;
+
        dispatch_io(rw, num_regions, where, dp, io, 1);
 
        while (1) {
@@ -415,13 +427,21 @@ static int async_io(struct dm_io_client *client, unsigned int num_regions,
        io->callback = fn;
        io->context = context;
 
+       io->vma_invalidate_address = dp->vma_invalidate_address;
+       io->vma_invalidate_size = dp->vma_invalidate_size;
+
        dispatch_io(rw, num_regions, where, dp, io, 0);
        return 0;
 }
 
-static int dp_init(struct dm_io_request *io_req, struct dpages *dp)
+static int dp_init(struct dm_io_request *io_req, struct dpages *dp,
+                  unsigned long size)
 {
        /* Set up dpages based on memory type */
+
+       dp->vma_invalidate_address = NULL;
+       dp->vma_invalidate_size = 0;
+
        switch (io_req->mem.type) {
        case DM_IO_PAGE_LIST:
                list_dp_init(dp, io_req->mem.ptr.pl, io_req->mem.offset);
@@ -432,6 +452,11 @@ static int dp_init(struct dm_io_request *io_req, struct dpages *dp)
                break;
 
        case DM_IO_VMA:
+               flush_kernel_vmap_range(io_req->mem.ptr.vma, size);
+               if ((io_req->bi_rw & RW_MASK) == READ) {
+                       dp->vma_invalidate_address = io_req->mem.ptr.vma;
+                       dp->vma_invalidate_size = size;
+               }
                vm_dp_init(dp, io_req->mem.ptr.vma);
                break;
 
@@ -460,7 +485,7 @@ int dm_io(struct dm_io_request *io_req, unsigned num_regions,
        int r;
        struct dpages dp;
 
-       r = dp_init(io_req, &dp);
+       r = dp_init(io_req, &dp, (unsigned long)where->count << SECTOR_SHIFT);
        if (r)
                return r;
 
index 4cacdad..2e9a3ca 100644 (file)
@@ -128,6 +128,24 @@ static struct hash_cell *__get_uuid_cell(const char *str)
        return NULL;
 }
 
+static struct hash_cell *__get_dev_cell(uint64_t dev)
+{
+       struct mapped_device *md;
+       struct hash_cell *hc;
+
+       md = dm_get_md(huge_decode_dev(dev));
+       if (!md)
+               return NULL;
+
+       hc = dm_get_mdptr(md);
+       if (!hc) {
+               dm_put(md);
+               return NULL;
+       }
+
+       return hc;
+}
+
 /*-----------------------------------------------------------------
  * Inserting, removing and renaming a device.
  *---------------------------------------------------------------*/
@@ -718,25 +736,45 @@ static int dev_create(struct dm_ioctl *param, size_t param_size)
  */
 static struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param)
 {
-       struct mapped_device *md;
-       void *mdptr = NULL;
+       struct hash_cell *hc = NULL;
 
-       if (*param->uuid)
-               return __get_uuid_cell(param->uuid);
+       if (*param->uuid) {
+               if (*param->name || param->dev)
+                       return NULL;
 
-       if (*param->name)
-               return __get_name_cell(param->name);
+               hc = __get_uuid_cell(param->uuid);
+               if (!hc)
+                       return NULL;
+       } else if (*param->name) {
+               if (param->dev)
+                       return NULL;
 
-       md = dm_get_md(huge_decode_dev(param->dev));
-       if (!md)
-               goto out;
+               hc = __get_name_cell(param->name);
+               if (!hc)
+                       return NULL;
+       } else if (param->dev) {
+               hc = __get_dev_cell(param->dev);
+               if (!hc)
+                       return NULL;
+       } else
+               return NULL;
 
-       mdptr = dm_get_mdptr(md);
-       if (!mdptr)
-               dm_put(md);
+       /*
+        * Sneakily write in both the name and the uuid
+        * while we have the cell.
+        */
+       strlcpy(param->name, hc->name, sizeof(param->name));
+       if (hc->uuid)
+               strlcpy(param->uuid, hc->uuid, sizeof(param->uuid));
+       else
+               param->uuid[0] = '\0';
 
-out:
-       return mdptr;
+       if (hc->new_map)
+               param->flags |= DM_INACTIVE_PRESENT_FLAG;
+       else
+               param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
+
+       return hc;
 }
 
 static struct mapped_device *find_device(struct dm_ioctl *param)
@@ -746,24 +784,8 @@ static struct mapped_device *find_device(struct dm_ioctl *param)
 
        down_read(&_hash_lock);
        hc = __find_device_hash_cell(param);
-       if (hc) {
+       if (hc)
                md = hc->md;
-
-               /*
-                * Sneakily write in both the name and the uuid
-                * while we have the cell.
-                */
-               strlcpy(param->name, hc->name, sizeof(param->name));
-               if (hc->uuid)
-                       strlcpy(param->uuid, hc->uuid, sizeof(param->uuid));
-               else
-                       param->uuid[0] = '\0';
-
-               if (hc->new_map)
-                       param->flags |= DM_INACTIVE_PRESENT_FLAG;
-               else
-                       param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
-       }
        up_read(&_hash_lock);
 
        return md;
@@ -1402,6 +1424,11 @@ static int target_message(struct dm_ioctl *param, size_t param_size)
                goto out;
        }
 
+       if (!argc) {
+               DMWARN("Empty message received.");
+               goto out;
+       }
+
        table = dm_get_live_table(md);
        if (!table)
                goto out_argv;
index 320401d..f821470 100644 (file)
@@ -224,8 +224,6 @@ struct kcopyd_job {
        unsigned int num_dests;
        struct dm_io_region dests[DM_KCOPYD_MAX_REGIONS];
 
-       sector_t offset;
-       unsigned int nr_pages;
        struct page_list *pages;
 
        /*
@@ -380,7 +378,7 @@ static int run_io_job(struct kcopyd_job *job)
                .bi_rw = job->rw,
                .mem.type = DM_IO_PAGE_LIST,
                .mem.ptr.pl = job->pages,
-               .mem.offset = job->offset,
+               .mem.offset = 0,
                .notify.fn = complete_io,
                .notify.context = job,
                .client = job->kc->io_client,
@@ -397,10 +395,9 @@ static int run_io_job(struct kcopyd_job *job)
 static int run_pages_job(struct kcopyd_job *job)
 {
        int r;
+       unsigned nr_pages = dm_div_up(job->dests[0].count, PAGE_SIZE >> 9);
 
-       job->nr_pages = dm_div_up(job->dests[0].count + job->offset,
-                                 PAGE_SIZE >> 9);
-       r = kcopyd_get_pages(job->kc, job->nr_pages, &job->pages);
+       r = kcopyd_get_pages(job->kc, nr_pages, &job->pages);
        if (!r) {
                /* this job is ready for io */
                push(&job->kc->io_jobs, job);
@@ -602,8 +599,6 @@ int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
        job->num_dests = num_dests;
        memcpy(&job->dests, dests, sizeof(*dests) * num_dests);
 
-       job->offset = 0;
-       job->nr_pages = 0;
        job->pages = NULL;
 
        job->fn = fn;
@@ -622,6 +617,37 @@ int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
 }
 EXPORT_SYMBOL(dm_kcopyd_copy);
 
+void *dm_kcopyd_prepare_callback(struct dm_kcopyd_client *kc,
+                                dm_kcopyd_notify_fn fn, void *context)
+{
+       struct kcopyd_job *job;
+
+       job = mempool_alloc(kc->job_pool, GFP_NOIO);
+
+       memset(job, 0, sizeof(struct kcopyd_job));
+       job->kc = kc;
+       job->fn = fn;
+       job->context = context;
+
+       atomic_inc(&kc->nr_jobs);
+
+       return job;
+}
+EXPORT_SYMBOL(dm_kcopyd_prepare_callback);
+
+void dm_kcopyd_do_callback(void *j, int read_err, unsigned long write_err)
+{
+       struct kcopyd_job *job = j;
+       struct dm_kcopyd_client *kc = job->kc;
+
+       job->read_err = read_err;
+       job->write_err = write_err;
+
+       push(&kc->complete_jobs, job);
+       wake(kc);
+}
+EXPORT_SYMBOL(dm_kcopyd_do_callback);
+
 /*
  * Cancels a kcopyd job, eg. someone might be deactivating a
  * mirror.
index aa2e0c3..1021c89 100644 (file)
@@ -394,8 +394,7 @@ static int flush_by_group(struct log_c *lc, struct list_head *flush_list)
                        group[count] = fe->region;
                        count++;
 
-                       list_del(&fe->list);
-                       list_add(&fe->list, &tmp_list);
+                       list_move(&fe->list, &tmp_list);
 
                        type = fe->type;
                        if (count >= MAX_FLUSH_GROUP_COUNT)
index 948e3f4..3b52bb7 100644 (file)
@@ -197,15 +197,21 @@ EXPORT_SYMBOL(dm_dirty_log_destroy);
 #define MIRROR_DISK_VERSION 2
 #define LOG_OFFSET 2
 
-struct log_header {
-       uint32_t magic;
+struct log_header_disk {
+       __le32 magic;
 
        /*
         * Simple, incrementing version. no backward
         * compatibility.
         */
+       __le32 version;
+       __le64 nr_regions;
+} __packed;
+
+struct log_header_core {
+       uint32_t magic;
        uint32_t version;
-       sector_t nr_regions;
+       uint64_t nr_regions;
 };
 
 struct log_c {
@@ -239,10 +245,10 @@ struct log_c {
        int log_dev_failed;
        int log_dev_flush_failed;
        struct dm_dev *log_dev;
-       struct log_header header;
+       struct log_header_core header;
 
        struct dm_io_region header_location;
-       struct log_header *disk_header;
+       struct log_header_disk *disk_header;
 };
 
 /*
@@ -251,34 +257,34 @@ struct log_c {
  */
 static inline int log_test_bit(uint32_t *bs, unsigned bit)
 {
-       return test_bit_le(bit, (unsigned long *) bs) ? 1 : 0;
+       return test_bit_le(bit, bs) ? 1 : 0;
 }
 
 static inline void log_set_bit(struct log_c *l,
                               uint32_t *bs, unsigned bit)
 {
-       __test_and_set_bit_le(bit, (unsigned long *) bs);
+       __set_bit_le(bit, bs);
        l->touched_cleaned = 1;
 }
 
 static inline void log_clear_bit(struct log_c *l,
                                 uint32_t *bs, unsigned bit)
 {
-       __test_and_clear_bit_le(bit, (unsigned long *) bs);
+       __clear_bit_le(bit, bs);
        l->touched_dirtied = 1;
 }
 
 /*----------------------------------------------------------------
  * Header IO
  *--------------------------------------------------------------*/
-static void header_to_disk(struct log_header *core, struct log_header *disk)
+static void header_to_disk(struct log_header_core *core, struct log_header_disk *disk)
 {
        disk->magic = cpu_to_le32(core->magic);
        disk->version = cpu_to_le32(core->version);
        disk->nr_regions = cpu_to_le64(core->nr_regions);
 }
 
-static void header_from_disk(struct log_header *core, struct log_header *disk)
+static void header_from_disk(struct log_header_core *core, struct log_header_disk *disk)
 {
        core->magic = le32_to_cpu(disk->magic);
        core->version = le32_to_cpu(disk->version);
@@ -486,7 +492,7 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
        memset(lc->sync_bits, (sync == NOSYNC) ? -1 : 0, bitset_size);
        lc->sync_count = (sync == NOSYNC) ? region_count : 0;
 
-       lc->recovering_bits = vmalloc(bitset_size);
+       lc->recovering_bits = vzalloc(bitset_size);
        if (!lc->recovering_bits) {
                DMWARN("couldn't allocate sync bitset");
                vfree(lc->sync_bits);
@@ -498,7 +504,6 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
                kfree(lc);
                return -ENOMEM;
        }
-       memset(lc->recovering_bits, 0, bitset_size);
        lc->sync_search = 0;
        log->context = lc;
 
@@ -739,8 +744,7 @@ static int core_get_resync_work(struct dm_dirty_log *log, region_t *region)
                return 0;
 
        do {
-               *region = find_next_zero_bit_le(
-                                            (unsigned long *) lc->sync_bits,
+               *region = find_next_zero_bit_le(lc->sync_bits,
                                             lc->region_count,
                                             lc->sync_search);
                lc->sync_search = *region + 1;
index c354701..5e0090e 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/atomic.h>
 
 #define DM_MSG_PREFIX "multipath"
-#define MESG_STR(x) x, sizeof(x)
 #define DM_PG_INIT_DELAY_MSECS 2000
 #define DM_PG_INIT_DELAY_DEFAULT ((unsigned) -1)
 
@@ -505,80 +504,29 @@ static void trigger_event(struct work_struct *work)
  *      <#paths> <#per-path selector args>
  *         [<path> [<arg>]* ]+ ]+
  *---------------------------------------------------------------*/
-struct param {
-       unsigned min;
-       unsigned max;
-       char *error;
-};
-
-static int read_param(struct param *param, char *str, unsigned *v, char **error)
-{
-       if (!str ||
-           (sscanf(str, "%u", v) != 1) ||
-           (*v < param->min) ||
-           (*v > param->max)) {
-               *error = param->error;
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-struct arg_set {
-       unsigned argc;
-       char **argv;
-};
-
-static char *shift(struct arg_set *as)
-{
-       char *r;
-
-       if (as->argc) {
-               as->argc--;
-               r = *as->argv;
-               as->argv++;
-               return r;
-       }
-
-       return NULL;
-}
-
-static void consume(struct arg_set *as, unsigned n)
-{
-       BUG_ON (as->argc < n);
-       as->argc -= n;
-       as->argv += n;
-}
-
-static int parse_path_selector(struct arg_set *as, struct priority_group *pg,
+static int parse_path_selector(struct dm_arg_set *as, struct priority_group *pg,
                               struct dm_target *ti)
 {
        int r;
        struct path_selector_type *pst;
        unsigned ps_argc;
 
-       static struct param _params[] = {
+       static struct dm_arg _args[] = {
                {0, 1024, "invalid number of path selector args"},
        };
 
-       pst = dm_get_path_selector(shift(as));
+       pst = dm_get_path_selector(dm_shift_arg(as));
        if (!pst) {
                ti->error = "unknown path selector type";
                return -EINVAL;
        }
 
-       r = read_param(_params, shift(as), &ps_argc, &ti->error);
+       r = dm_read_arg_group(_args, as, &ps_argc, &ti->error);
        if (r) {
                dm_put_path_selector(pst);
                return -EINVAL;
        }
 
-       if (ps_argc > as->argc) {
-               dm_put_path_selector(pst);
-               ti->error = "not enough arguments for path selector";
-               return -EINVAL;
-       }
-
        r = pst->create(&pg->ps, ps_argc, as->argv);
        if (r) {
                dm_put_path_selector(pst);
@@ -587,12 +535,12 @@ static int parse_path_selector(struct arg_set *as, struct priority_group *pg,
        }
 
        pg->ps.type = pst;
-       consume(as, ps_argc);
+       dm_consume_args(as, ps_argc);
 
        return 0;
 }
 
-static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps,
+static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps,
                               struct dm_target *ti)
 {
        int r;
@@ -609,7 +557,7 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps,
        if (!p)
                return ERR_PTR(-ENOMEM);
 
-       r = dm_get_device(ti, shift(as), dm_table_get_mode(ti->table),
+       r = dm_get_device(ti, dm_shift_arg(as), dm_table_get_mode(ti->table),
                          &p->path.dev);
        if (r) {
                ti->error = "error getting device";
@@ -660,16 +608,16 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps,
        return ERR_PTR(r);
 }
 
-static struct priority_group *parse_priority_group(struct arg_set *as,
+static struct priority_group *parse_priority_group(struct dm_arg_set *as,
                                                   struct multipath *m)
 {
-       static struct param _params[] = {
+       static struct dm_arg _args[] = {
                {1, 1024, "invalid number of paths"},
                {0, 1024, "invalid number of selector args"}
        };
 
        int r;
-       unsigned i, nr_selector_args, nr_params;
+       unsigned i, nr_selector_args, nr_args;
        struct priority_group *pg;
        struct dm_target *ti = m->ti;
 
@@ -693,26 +641,26 @@ static struct priority_group *parse_priority_group(struct arg_set *as,
        /*
         * read the paths
         */
-       r = read_param(_params, shift(as), &pg->nr_pgpaths, &ti->error);
+       r = dm_read_arg(_args, as, &pg->nr_pgpaths, &ti->error);
        if (r)
                goto bad;
 
-       r = read_param(_params + 1, shift(as), &nr_selector_args, &ti->error);
+       r = dm_read_arg(_args + 1, as, &nr_selector_args, &ti->error);
        if (r)
                goto bad;
 
-       nr_params = 1 + nr_selector_args;
+       nr_args = 1 + nr_selector_args;
        for (i = 0; i < pg->nr_pgpaths; i++) {
                struct pgpath *pgpath;
-               struct arg_set path_args;
+               struct dm_arg_set path_args;
 
-               if (as->argc < nr_params) {
+               if (as->argc < nr_args) {
                        ti->error = "not enough path parameters";
                        r = -EINVAL;
                        goto bad;
                }
 
-               path_args.argc = nr_params;
+               path_args.argc = nr_args;
                path_args.argv = as->argv;
 
                pgpath = parse_path(&path_args, &pg->ps, ti);
@@ -723,7 +671,7 @@ static struct priority_group *parse_priority_group(struct arg_set *as,
 
                pgpath->pg = pg;
                list_add_tail(&pgpath->list, &pg->pgpaths);
-               consume(as, nr_params);
+               dm_consume_args(as, nr_args);
        }
 
        return pg;
@@ -733,28 +681,23 @@ static struct priority_group *parse_priority_group(struct arg_set *as,
        return ERR_PTR(r);
 }
 
-static int parse_hw_handler(struct arg_set *as, struct multipath *m)
+static int parse_hw_handler(struct dm_arg_set *as, struct multipath *m)
 {
        unsigned hw_argc;
        int ret;
        struct dm_target *ti = m->ti;
 
-       static struct param _params[] = {
+       static struct dm_arg _args[] = {
                {0, 1024, "invalid number of hardware handler args"},
        };
 
-       if (read_param(_params, shift(as), &hw_argc, &ti->error))
+       if (dm_read_arg_group(_args, as, &hw_argc, &ti->error))
                return -EINVAL;
 
        if (!hw_argc)
                return 0;
 
-       if (hw_argc > as->argc) {
-               ti->error = "not enough arguments for hardware handler";
-               return -EINVAL;
-       }
-
-       m->hw_handler_name = kstrdup(shift(as), GFP_KERNEL);
+       m->hw_handler_name = kstrdup(dm_shift_arg(as), GFP_KERNEL);
        request_module("scsi_dh_%s", m->hw_handler_name);
        if (scsi_dh_handler_exist(m->hw_handler_name) == 0) {
                ti->error = "unknown hardware handler type";
@@ -778,7 +721,7 @@ static int parse_hw_handler(struct arg_set *as, struct multipath *m)
                for (i = 0, p+=j+1; i <= hw_argc - 2; i++, p+=j+1)
                        j = sprintf(p, "%s", as->argv[i]);
        }
-       consume(as, hw_argc - 1);
+       dm_consume_args(as, hw_argc - 1);
 
        return 0;
 fail:
@@ -787,20 +730,20 @@ fail:
        return ret;
 }
 
-static int parse_features(struct arg_set *as, struct multipath *m)
+static int parse_features(struct dm_arg_set *as, struct multipath *m)
 {
        int r;
        unsigned argc;
        struct dm_target *ti = m->ti;
-       const char *param_name;
+       const char *arg_name;
 
-       static struct param _params[] = {
+       static struct dm_arg _args[] = {
                {0, 5, "invalid number of feature args"},
                {1, 50, "pg_init_retries must be between 1 and 50"},
                {0, 60000, "pg_init_delay_msecs must be between 0 and 60000"},
        };
 
-       r = read_param(_params, shift(as), &argc, &ti->error);
+       r = dm_read_arg_group(_args, as, &argc, &ti->error);
        if (r)
                return -EINVAL;
 
@@ -808,26 +751,24 @@ static int parse_features(struct arg_set *as, struct multipath *m)
                return 0;
 
        do {
-               param_name = shift(as);
+               arg_name = dm_shift_arg(as);
                argc--;
 
-               if (!strnicmp(param_name, MESG_STR("queue_if_no_path"))) {
+               if (!strcasecmp(arg_name, "queue_if_no_path")) {
                        r = queue_if_no_path(m, 1, 0);
                        continue;
                }
 
-               if (!strnicmp(param_name, MESG_STR("pg_init_retries")) &&
+               if (!strcasecmp(arg_name, "pg_init_retries") &&
                    (argc >= 1)) {
-                       r = read_param(_params + 1, shift(as),
-                                      &m->pg_init_retries, &ti->error);
+                       r = dm_read_arg(_args + 1, as, &m->pg_init_retries, &ti->error);
                        argc--;
                        continue;
                }
 
-               if (!strnicmp(param_name, MESG_STR("pg_init_delay_msecs")) &&
+               if (!strcasecmp(arg_name, "pg_init_delay_msecs") &&
                    (argc >= 1)) {
-                       r = read_param(_params + 2, shift(as),
-                                      &m->pg_init_delay_msecs, &ti->error);
+                       r = dm_read_arg(_args + 2, as, &m->pg_init_delay_msecs, &ti->error);
                        argc--;
                        continue;
                }
@@ -842,15 +783,15 @@ static int parse_features(struct arg_set *as, struct multipath *m)
 static int multipath_ctr(struct dm_target *ti, unsigned int argc,
                         char **argv)
 {
-       /* target parameters */
-       static struct param _params[] = {
+       /* target arguments */
+       static struct dm_arg _args[] = {
                {0, 1024, "invalid number of priority groups"},
                {0, 1024, "invalid initial priority group number"},
        };
 
        int r;
        struct multipath *m;
-       struct arg_set as;
+       struct dm_arg_set as;
        unsigned pg_count = 0;
        unsigned next_pg_num;
 
@@ -871,11 +812,11 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc,
        if (r)
                goto bad;
 
-       r = read_param(_params, shift(&as), &m->nr_priority_groups, &ti->error);
+       r = dm_read_arg(_args, &as, &m->nr_priority_groups, &ti->error);
        if (r)
                goto bad;
 
-       r = read_param(_params + 1, shift(&as), &next_pg_num, &ti->error);
+       r = dm_read_arg(_args + 1, &as, &next_pg_num, &ti->error);
        if (r)
                goto bad;
 
@@ -1505,10 +1446,10 @@ static int multipath_message(struct dm_target *ti, unsigned argc, char **argv)
        }
 
        if (argc == 1) {
-               if (!strnicmp(argv[0], MESG_STR("queue_if_no_path"))) {
+               if (!strcasecmp(argv[0], "queue_if_no_path")) {
                        r = queue_if_no_path(m, 1, 0);
                        goto out;
-               } else if (!strnicmp(argv[0], MESG_STR("fail_if_no_path"))) {
+               } else if (!strcasecmp(argv[0], "fail_if_no_path")) {
                        r = queue_if_no_path(m, 0, 0);
                        goto out;
                }
@@ -1519,18 +1460,18 @@ static int multipath_message(struct dm_target *ti, unsigned argc, char **argv)
                goto out;
        }
 
-       if (!strnicmp(argv[0], MESG_STR("disable_group"))) {
+       if (!strcasecmp(argv[0], "disable_group")) {
                r = bypass_pg_num(m, argv[1], 1);
                goto out;
-       } else if (!strnicmp(argv[0], MESG_STR("enable_group"))) {
+       } else if (!strcasecmp(argv[0], "enable_group")) {
                r = bypass_pg_num(m, argv[1], 0);
                goto out;
-       } else if (!strnicmp(argv[0], MESG_STR("switch_group"))) {
+       } else if (!strcasecmp(argv[0], "switch_group")) {
                r = switch_pg_num(m, argv[1]);
                goto out;
-       } else if (!strnicmp(argv[0], MESG_STR("reinstate_path")))
+       } else if (!strcasecmp(argv[0], "reinstate_path"))
                action = reinstate_path;
-       else if (!strnicmp(argv[0], MESG_STR("fail_path")))
+       else if (!strcasecmp(argv[0], "fail_path"))
                action = fail_path;
        else {
                DMWARN("Unrecognised multipath message received.");
index e5d8904..a002dd8 100644 (file)
@@ -8,19 +8,19 @@
 #include <linux/slab.h>
 
 #include "md.h"
+#include "raid1.h"
 #include "raid5.h"
-#include "dm.h"
 #include "bitmap.h"
 
+#include <linux/device-mapper.h>
+
 #define DM_MSG_PREFIX "raid"
 
 /*
- * If the MD doesn't support MD_SYNC_STATE_FORCED yet, then
- * make it so the flag doesn't set anything.
+ * The following flags are used by dm-raid.c to set up the array state.
+ * They must be cleared before md_run is called.
  */
-#ifndef MD_SYNC_STATE_FORCED
-#define MD_SYNC_STATE_FORCED 0
-#endif
+#define FirstUse 10             /* rdev flag */
 
 struct raid_dev {
        /*
@@ -43,14 +43,15 @@ struct raid_dev {
 /*
  * Flags for rs->print_flags field.
  */
-#define DMPF_DAEMON_SLEEP      0x1
-#define DMPF_MAX_WRITE_BEHIND  0x2
-#define DMPF_SYNC              0x4
-#define DMPF_NOSYNC            0x8
-#define DMPF_STRIPE_CACHE      0x10
-#define DMPF_MIN_RECOVERY_RATE 0x20
-#define DMPF_MAX_RECOVERY_RATE 0x40
-
+#define DMPF_SYNC              0x1
+#define DMPF_NOSYNC            0x2
+#define DMPF_REBUILD           0x4
+#define DMPF_DAEMON_SLEEP      0x8
+#define DMPF_MIN_RECOVERY_RATE 0x10
+#define DMPF_MAX_RECOVERY_RATE 0x20
+#define DMPF_MAX_WRITE_BEHIND  0x40
+#define DMPF_STRIPE_CACHE      0x80
+#define DMPF_REGION_SIZE       0X100
 struct raid_set {
        struct dm_target *ti;
 
@@ -72,6 +73,7 @@ static struct raid_type {
        const unsigned level;           /* RAID level. */
        const unsigned algorithm;       /* RAID algorithm. */
 } raid_types[] = {
+       {"raid1",    "RAID1 (mirroring)",               0, 2, 1, 0 /* NONE */},
        {"raid4",    "RAID4 (dedicated parity disk)",   1, 2, 5, ALGORITHM_PARITY_0},
        {"raid5_la", "RAID5 (left asymmetric)",         1, 2, 5, ALGORITHM_LEFT_ASYMMETRIC},
        {"raid5_ra", "RAID5 (right asymmetric)",        1, 2, 5, ALGORITHM_RIGHT_ASYMMETRIC},
@@ -105,7 +107,8 @@ static struct raid_set *context_alloc(struct dm_target *ti, struct raid_type *ra
        }
 
        sectors_per_dev = ti->len;
-       if (sector_div(sectors_per_dev, (raid_devs - raid_type->parity_devs))) {
+       if ((raid_type->level > 1) &&
+           sector_div(sectors_per_dev, (raid_devs - raid_type->parity_devs))) {
                ti->error = "Target length not divisible by number of data devices";
                return ERR_PTR(-EINVAL);
        }
@@ -147,9 +150,16 @@ static void context_free(struct raid_set *rs)
 {
        int i;
 
-       for (i = 0; i < rs->md.raid_disks; i++)
+       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;
                if (rs->dev[i].data_dev)
                        dm_put_device(rs->ti, rs->dev[i].data_dev);
+       }
 
        kfree(rs);
 }
@@ -159,7 +169,16 @@ static void context_free(struct raid_set *rs)
  *  <meta_dev>: meta device name or '-' if missing
  *  <data_dev>: data device name or '-' if missing
  *
- * This code parses those words.
+ * The following are permitted:
+ *    - -
+ *    - <data_dev>
+ *    <meta_dev> <data_dev>
+ *
+ * The following is not allowed:
+ *    <meta_dev> -
+ *
+ * This code parses those words.  If there is a failure,
+ * the caller must use context_free to unwind the operations.
  */
 static int dev_parms(struct raid_set *rs, char **argv)
 {
@@ -182,8 +201,16 @@ static int dev_parms(struct raid_set *rs, char **argv)
                rs->dev[i].rdev.mddev = &rs->md;
 
                if (strcmp(argv[0], "-")) {
-                       rs->ti->error = "Metadata devices not supported";
-                       return -EINVAL;
+                       ret = dm_get_device(rs->ti, argv[0],
+                                           dm_table_get_mode(rs->ti->table),
+                                           &rs->dev[i].meta_dev);
+                       rs->ti->error = "RAID metadata device lookup failure";
+                       if (ret)
+                               return ret;
+
+                       rs->dev[i].rdev.sb_page = alloc_page(GFP_KERNEL);
+                       if (!rs->dev[i].rdev.sb_page)
+                               return -ENOMEM;
                }
 
                if (!strcmp(argv[1], "-")) {
@@ -193,6 +220,10 @@ static int dev_parms(struct raid_set *rs, char **argv)
                                return -EINVAL;
                        }
 
+                       rs->ti->error = "No data device supplied with metadata device";
+                       if (rs->dev[i].meta_dev)
+                               return -EINVAL;
+
                        continue;
                }
 
@@ -204,6 +235,10 @@ static int dev_parms(struct raid_set *rs, char **argv)
                        return ret;
                }
 
+               if (rs->dev[i].meta_dev) {
+                       metadata_available = 1;
+                       rs->dev[i].rdev.meta_bdev = rs->dev[i].meta_dev->bdev;
+               }
                rs->dev[i].rdev.bdev = rs->dev[i].data_dev->bdev;
                list_add(&rs->dev[i].rdev.same_set, &rs->md.disks);
                if (!test_bit(In_sync, &rs->dev[i].rdev.flags))
@@ -234,34 +269,110 @@ static int dev_parms(struct raid_set *rs, char **argv)
        return 0;
 }
 
+/*
+ * validate_region_size
+ * @rs
+ * @region_size:  region size in sectors.  If 0, pick a size (4MiB default).
+ *
+ * Set rs->md.bitmap_info.chunksize (which really refers to 'region size').
+ * Ensure that (ti->len/region_size < 2^21) - required by MD bitmap.
+ *
+ * Returns: 0 on success, -EINVAL on failure.
+ */
+static int validate_region_size(struct raid_set *rs, unsigned long region_size)
+{
+       unsigned long min_region_size = rs->ti->len / (1 << 21);
+
+       if (!region_size) {
+               /*
+                * Choose a reasonable default.  All figures in sectors.
+                */
+               if (min_region_size > (1 << 13)) {
+                       DMINFO("Choosing default region size of %lu sectors",
+                              region_size);
+                       region_size = min_region_size;
+               } else {
+                       DMINFO("Choosing default region size of 4MiB");
+                       region_size = 1 << 13; /* sectors */
+               }
+       } else {
+               /*
+                * Validate user-supplied value.
+                */
+               if (region_size > rs->ti->len) {
+                       rs->ti->error = "Supplied region size is too large";
+                       return -EINVAL;
+               }
+
+               if (region_size < min_region_size) {
+                       DMERR("Supplied region_size (%lu sectors) below minimum (%lu)",
+                             region_size, min_region_size);
+                       rs->ti->error = "Supplied region size is too small";
+                       return -EINVAL;
+               }
+
+               if (!is_power_of_2(region_size)) {
+                       rs->ti->error = "Region size is not a power of 2";
+                       return -EINVAL;
+               }
+
+               if (region_size < rs->md.chunk_sectors) {
+                       rs->ti->error = "Region size is smaller than the chunk size";
+                       return -EINVAL;
+               }
+       }
+
+       /*
+        * Convert sectors to bytes.
+        */
+       rs->md.bitmap_info.chunksize = (region_size << 9);
+
+       return 0;
+}
+
 /*
  * Possible arguments are...
- * RAID456:
  *     <chunk_size> [optional_args]
  *
- * Optional args:
- *    [[no]sync]                       Force or prevent recovery of the entire array
+ * Argument definitions
+ *    <chunk_size>                     The number of sectors per disk that
+ *                                      will form the "stripe"
+ *    [[no]sync]                       Force or prevent recovery of the
+ *                                      entire array
  *    [rebuild <idx>]                  Rebuild the drive indicated by the index
- *    [daemon_sleep <ms>]              Time between bitmap daemon work to clear bits
+ *    [daemon_sleep <ms>]              Time between bitmap daemon work to
+ *                                      clear bits
  *    [min_recovery_rate <kB/sec/disk>]        Throttle RAID initialization
  *    [max_recovery_rate <kB/sec/disk>]        Throttle RAID initialization
+ *    [write_mostly <idx>]             Indicate a write mostly drive via index
  *    [max_write_behind <sectors>]     See '-write-behind=' (man mdadm)
  *    [stripe_cache <sectors>]         Stripe cache size for higher RAIDs
+ *    [region_size <sectors>]           Defines granularity of bitmap
  */
 static int parse_raid_params(struct raid_set *rs, char **argv,
                             unsigned num_raid_params)
 {
        unsigned i, rebuild_cnt = 0;
-       unsigned long value;
+       unsigned long value, region_size = 0;
        char *key;
 
        /*
         * First, parse the in-order required arguments
+        * "chunk_size" is the only argument of this type.
         */
-       if ((strict_strtoul(argv[0], 10, &value) < 0) ||
-           !is_power_of_2(value) || (value < 8)) {
+       if ((strict_strtoul(argv[0], 10, &value) < 0)) {
                rs->ti->error = "Bad chunk size";
                return -EINVAL;
+       } else if (rs->raid_type->level == 1) {
+               if (value)
+                       DMERR("Ignoring chunk size parameter for RAID 1");
+               value = 0;
+       } else if (!is_power_of_2(value)) {
+               rs->ti->error = "Chunk size must be a power of 2";
+               return -EINVAL;
+       } else if (value < 8) {
+               rs->ti->error = "Chunk size value is too small";
+               return -EINVAL;
        }
 
        rs->md.new_chunk_sectors = rs->md.chunk_sectors = value;
@@ -269,22 +380,39 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
        num_raid_params--;
 
        /*
-        * Second, parse the unordered optional arguments
+        * We set each individual device as In_sync with a completed
+        * 'recovery_offset'.  If there has been a device failure or
+        * replacement then one of the following cases applies:
+        *
+        *   1) User specifies 'rebuild'.
+        *      - Device is reset when param is read.
+        *   2) A new device is supplied.
+        *      - No matching superblock found, resets device.
+        *   3) Device failure was transient and returns on reload.
+        *      - Failure noticed, resets device for bitmap replay.
+        *   4) Device hadn't completed recovery after previous failure.
+        *      - Superblock is read and overrides recovery_offset.
+        *
+        * What is found in the superblocks of the devices is always
+        * authoritative, unless 'rebuild' or '[no]sync' was specified.
         */
-       for (i = 0; i < rs->md.raid_disks; i++)
+       for (i = 0; i < rs->md.raid_disks; i++) {
                set_bit(In_sync, &rs->dev[i].rdev.flags);
+               rs->dev[i].rdev.recovery_offset = MaxSector;
+       }
 
+       /*
+        * Second, parse the unordered optional arguments
+        */
        for (i = 0; i < num_raid_params; i++) {
-               if (!strcmp(argv[i], "nosync")) {
+               if (!strcasecmp(argv[i], "nosync")) {
                        rs->md.recovery_cp = MaxSector;
                        rs->print_flags |= DMPF_NOSYNC;
-                       rs->md.flags |= MD_SYNC_STATE_FORCED;
                        continue;
                }
-               if (!strcmp(argv[i], "sync")) {
+               if (!strcasecmp(argv[i], "sync")) {
                        rs->md.recovery_cp = 0;
                        rs->print_flags |= DMPF_SYNC;
-                       rs->md.flags |= MD_SYNC_STATE_FORCED;
                        continue;
                }
 
@@ -300,9 +428,13 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
                        return -EINVAL;
                }
 
-               if (!strcmp(key, "rebuild")) {
-                       if (++rebuild_cnt > rs->raid_type->parity_devs) {
-                               rs->ti->error = "Too many rebuild drives given";
+               if (!strcasecmp(key, "rebuild")) {
+                       rebuild_cnt++;
+                       if (((rs->raid_type->level != 1) &&
+                            (rebuild_cnt > rs->raid_type->parity_devs)) ||
+                           ((rs->raid_type->level == 1) &&
+                            (rebuild_cnt > (rs->md.raid_disks - 1)))) {
+                               rs->ti->error = "Too many rebuild devices specified for given RAID type";
                                return -EINVAL;
                        }
                        if (value > rs->md.raid_disks) {
@@ -311,7 +443,22 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
                        }
                        clear_bit(In_sync, &rs->dev[value].rdev.flags);
                        rs->dev[value].rdev.recovery_offset = 0;
-               } else if (!strcmp(key, "max_write_behind")) {
+                       rs->print_flags |= DMPF_REBUILD;
+               } else if (!strcasecmp(key, "write_mostly")) {
+                       if (rs->raid_type->level != 1) {
+                               rs->ti->error = "write_mostly option is only valid for RAID1";
+                               return -EINVAL;
+                       }
+                       if (value > rs->md.raid_disks) {
+                               rs->ti->error = "Invalid write_mostly drive index given";
+                               return -EINVAL;
+                       }
+                       set_bit(WriteMostly, &rs->dev[value].rdev.flags);
+               } else if (!strcasecmp(key, "max_write_behind")) {
+                       if (rs->raid_type->level != 1) {
+                               rs->ti->error = "max_write_behind option is only valid for RAID1";
+                               return -EINVAL;
+                       }
                        rs->print_flags |= DMPF_MAX_WRITE_BEHIND;
 
                        /*
@@ -324,14 +471,14 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
                                return -EINVAL;
                        }
                        rs->md.bitmap_info.max_write_behind = value;
-               } else if (!strcmp(key, "daemon_sleep")) {
+               } else if (!strcasecmp(key, "daemon_sleep")) {
                        rs->print_flags |= DMPF_DAEMON_SLEEP;
                        if (!value || (value > MAX_SCHEDULE_TIMEOUT)) {
                                rs->ti->error = "daemon sleep period out of range";
                                return -EINVAL;
                        }
                        rs->md.bitmap_info.daemon_sleep = value;
-               } else if (!strcmp(key, "stripe_cache")) {
+               } else if (!strcasecmp(key, "stripe_cache")) {
                        rs->print_flags |= DMPF_STRIPE_CACHE;
 
                        /*
@@ -348,20 +495,23 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
                                rs->ti->error = "Bad stripe_cache size";
                                return -EINVAL;
                        }
-               } else if (!strcmp(key, "min_recovery_rate")) {
+               } else if (!strcasecmp(key, "min_recovery_rate")) {
                        rs->print_flags |= DMPF_MIN_RECOVERY_RATE;
                        if (value > INT_MAX) {
                                rs->ti->error = "min_recovery_rate out of range";
                                return -EINVAL;
                        }
                        rs->md.sync_speed_min = (int)value;
-               } else if (!strcmp(key, "max_recovery_rate")) {
+               } else if (!strcasecmp(key, "max_recovery_rate")) {
                        rs->print_flags |= DMPF_MAX_RECOVERY_RATE;
                        if (value > INT_MAX) {
                                rs->ti->error = "max_recovery_rate out of range";
                                return -EINVAL;
                        }
                        rs->md.sync_speed_max = (int)value;
+               } else if (!strcasecmp(key, "region_size")) {
+                       rs->print_flags |= DMPF_REGION_SIZE;
+                       region_size = value;
                } else {
                        DMERR("Unable to parse RAID parameter: %s", key);
                        rs->ti->error = "Unable to parse RAID parameters";
@@ -369,6 +519,19 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
                }
        }
 
+       if (validate_region_size(rs, region_size))
+               return -EINVAL;
+
+       if (rs->md.chunk_sectors)
+               rs->ti->split_io = rs->md.chunk_sectors;
+       else
+               rs->ti->split_io = region_size;
+
+       if (rs->md.chunk_sectors)
+               rs->ti->split_io = rs->md.chunk_sectors;
+       else
+               rs->ti->split_io = region_size;
+
        /* Assume there are no metadata devices until the drives are parsed */
        rs->md.persistent = 0;
        rs->md.external = 1;
@@ -387,17 +550,351 @@ static int raid_is_congested(struct dm_target_callbacks *cb, int bits)
 {
        struct raid_set *rs = container_of(cb, struct raid_set, callbacks);
 
+       if (rs->raid_type->level == 1)
+               return md_raid1_congested(&rs->md, bits);
+
        return md_raid5_congested(&rs->md, bits);
 }
 
+/*
+ * This structure is never routinely used by userspace, unlike md superblocks.
+ * Devices with this superblock should only ever be accessed via device-mapper.
+ */
+#define DM_RAID_MAGIC 0x64526D44
+struct dm_raid_superblock {
+       __le32 magic;           /* "DmRd" */
+       __le32 features;        /* Used to indicate possible future changes */
+
+       __le32 num_devices;     /* Number of devices in this array. (Max 64) */
+       __le32 array_position;  /* The position of this drive in the array */
+
+       __le64 events;          /* Incremented by md when superblock updated */
+       __le64 failed_devices;  /* Bit field of devices to indicate failures */
+
+       /*
+        * This offset tracks the progress of the repair or replacement of
+        * an individual drive.
+        */
+       __le64 disk_recovery_offset;
+
+       /*
+        * This offset tracks the progress of the initial array
+        * synchronisation/parity calculation.
+        */
+       __le64 array_resync_offset;
+
+       /*
+        * RAID characteristics
+        */
+       __le32 level;
+       __le32 layout;
+       __le32 stripe_sectors;
+
+       __u8 pad[452];          /* Round struct to 512 bytes. */
+                               /* Always set to 0 when writing. */
+} __packed;
+
+static int read_disk_sb(mdk_rdev_t *rdev, int size)
+{
+       BUG_ON(!rdev->sb_page);
+
+       if (rdev->sb_loaded)
+               return 0;
+
+       if (!sync_page_io(rdev, 0, size, rdev->sb_page, READ, 1)) {
+               DMERR("Failed to read device superblock");
+               return -EINVAL;
+       }
+
+       rdev->sb_loaded = 1;
+
+       return 0;
+}
+
+static void super_sync(mddev_t *mddev, mdk_rdev_t *rdev)
+{
+       mdk_rdev_t *r, *t;
+       uint64_t failed_devices;
+       struct dm_raid_superblock *sb;
+
+       sb = page_address(rdev->sb_page);
+       failed_devices = le64_to_cpu(sb->failed_devices);
+
+       rdev_for_each(r, t, mddev)
+               if ((r->raid_disk >= 0) && test_bit(Faulty, &r->flags))
+                       failed_devices |= (1ULL << r->raid_disk);
+
+       memset(sb, 0, sizeof(*sb));
+
+       sb->magic = cpu_to_le32(DM_RAID_MAGIC);
+       sb->features = cpu_to_le32(0);  /* No features yet */
+
+       sb->num_devices = cpu_to_le32(mddev->raid_disks);
+       sb->array_position = cpu_to_le32(rdev->raid_disk);
+
+       sb->events = cpu_to_le64(mddev->events);
+       sb->failed_devices = cpu_to_le64(failed_devices);
+
+       sb->disk_recovery_offset = cpu_to_le64(rdev->recovery_offset);
+       sb->array_resync_offset = cpu_to_le64(mddev->recovery_cp);
+
+       sb->level = cpu_to_le32(mddev->level);
+       sb->layout = cpu_to_le32(mddev->layout);
+       sb->stripe_sectors = cpu_to_le32(mddev->chunk_sectors);
+}
+
+/*
+ * super_load
+ *
+ * This function creates a superblock if one is not found on the device
+ * and will decide which superblock to use if there's a choice.
+ *
+ * Return: 1 if use rdev, 0 if use refdev, -Exxx otherwise
+ */
+static int super_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev)
+{
+       int ret;
+       struct dm_raid_superblock *sb;
+       struct dm_raid_superblock *refsb;
+       uint64_t events_sb, events_refsb;
+
+       rdev->sb_start = 0;
+       rdev->sb_size = sizeof(*sb);
+
+       ret = read_disk_sb(rdev, rdev->sb_size);
+       if (ret)
+               return ret;
+
+       sb = page_address(rdev->sb_page);
+       if (sb->magic != cpu_to_le32(DM_RAID_MAGIC)) {
+               super_sync(rdev->mddev, rdev);
+
+               set_bit(FirstUse, &rdev->flags);
+
+               /* Force writing of superblocks to disk */
+               set_bit(MD_CHANGE_DEVS, &rdev->mddev->flags);
+
+               /* Any superblock is better than none, choose that if given */
+               return refdev ? 0 : 1;
+       }
+
+       if (!refdev)
+               return 1;
+
+       events_sb = le64_to_cpu(sb->events);
+
+       refsb = page_address(refdev->sb_page);
+       events_refsb = le64_to_cpu(refsb->events);
+
+       return (events_sb > events_refsb) ? 1 : 0;
+}
+
+static int super_init_validation(mddev_t *mddev, mdk_rdev_t *rdev)
+{
+       int role;
+       struct raid_set *rs = container_of(mddev, struct raid_set, md);
+       uint64_t events_sb;
+       uint64_t failed_devices;
+       struct dm_raid_superblock *sb;
+       uint32_t new_devs = 0;
+       uint32_t rebuilds = 0;
+       mdk_rdev_t *r, *t;
+       struct dm_raid_superblock *sb2;
+
+       sb = page_address(rdev->sb_page);
+       events_sb = le64_to_cpu(sb->events);
+       failed_devices = le64_to_cpu(sb->failed_devices);
+
+       /*
+        * Initialise to 1 if this is a new superblock.
+        */
+       mddev->events = events_sb ? : 1;
+
+       /*
+        * Reshaping is not currently allowed
+        */
+       if ((le32_to_cpu(sb->level) != mddev->level) ||
+           (le32_to_cpu(sb->layout) != mddev->layout) ||
+           (le32_to_cpu(sb->stripe_sectors) != mddev->chunk_sectors)) {
+               DMERR("Reshaping arrays not yet supported.");
+               return -EINVAL;
+       }
+
+       /* We can only change the number of devices in RAID1 right now */
+       if ((rs->raid_type->level != 1) &&
+           (le32_to_cpu(sb->num_devices) != mddev->raid_disks)) {
+               DMERR("Reshaping arrays not yet supported.");
+               return -EINVAL;
+       }
+
+       if (!(rs->print_flags & (DMPF_SYNC | DMPF_NOSYNC)))
+               mddev->recovery_cp = le64_to_cpu(sb->array_resync_offset);
+
+       /*
+        * During load, we set FirstUse if a new superblock was written.
+        * There are two reasons we might not have a superblock:
+        * 1) The array is brand new - in which case, all of the
+        *    devices must have their In_sync bit set.  Also,
+        *    recovery_cp must be 0, unless forced.
+        * 2) This is a new device being added to an old array
+        *    and the new device needs to be rebuilt - in which
+        *    case the In_sync bit will /not/ be set and
+        *    recovery_cp must be MaxSector.
+        */
+       rdev_for_each(r, t, mddev) {
+               if (!test_bit(In_sync, &r->flags)) {
+                       if (!test_bit(FirstUse, &r->flags))
+                               DMERR("Superblock area of "
+                                     "rebuild device %d should have been "
+                                     "cleared.", r->raid_disk);
+                       set_bit(FirstUse, &r->flags);
+                       rebuilds++;
+               } else if (test_bit(FirstUse, &r->flags))
+                       new_devs++;
+       }
+
+       if (!rebuilds) {
+               if (new_devs == mddev->raid_disks) {
+                       DMINFO("Superblocks created for new array");
+                       set_bit(MD_ARRAY_FIRST_USE, &mddev->flags);
+               } else if (new_devs) {
+                       DMERR("New device injected "
+                             "into existing array without 'rebuild' "
+                             "parameter specified");
+                       return -EINVAL;
+               }
+       } else if (new_devs) {
+               DMERR("'rebuild' devices cannot be "
+                     "injected into an array with other first-time devices");
+               return -EINVAL;
+       } else if (mddev->recovery_cp != MaxSector) {
+               DMERR("'rebuild' specified while array is not in-sync");
+               return -EINVAL;
+       }
+
+       /*
+        * Now we set the Faulty bit for those devices that are
+        * recorded in the superblock as failed.
+        */
+       rdev_for_each(r, t, mddev) {
+               if (!r->sb_page)
+                       continue;
+               sb2 = page_address(r->sb_page);
+               sb2->failed_devices = 0;
+
+               /*
+                * Check for any device re-ordering.
+                */
+               if (!test_bit(FirstUse, &r->flags) && (r->raid_disk >= 0)) {
+                       role = le32_to_cpu(sb2->array_position);
+                       if (role != r->raid_disk) {
+                               if (rs->raid_type->level != 1) {
+                                       rs->ti->error = "Cannot change device "
+                                               "positions in RAID array";
+                                       return -EINVAL;
+                               }
+                               DMINFO("RAID1 device #%d now at position #%d",
+                                      role, r->raid_disk);
+                       }
+
+                       /*
+                        * Partial recovery is performed on
+                        * returning failed devices.
+                        */
+                       if (failed_devices & (1 << role))
+                               set_bit(Faulty, &r->flags);
+               }
+       }
+
+       return 0;
+}
+
+static int super_validate(mddev_t *mddev, mdk_rdev_t *rdev)
+{
+       struct dm_raid_superblock *sb = page_address(rdev->sb_page);
+
+       /*
+        * If mddev->events is not set, we know we have not yet initialized
+        * the array.
+        */
+       if (!mddev->events && super_init_validation(mddev, rdev))
+               return -EINVAL;
+
+       mddev->bitmap_info.offset = 4096 >> 9; /* Enable bitmap creation */
+       rdev->mddev->bitmap_info.default_offset = 4096 >> 9;
+       if (!test_bit(FirstUse, &rdev->flags)) {
+               rdev->recovery_offset = le64_to_cpu(sb->disk_recovery_offset);
+               if (rdev->recovery_offset != MaxSector)
+                       clear_bit(In_sync, &rdev->flags);
+       }
+
+       /*
+        * If a device comes back, set it as not In_sync and no longer faulty.
+        */
+       if (test_bit(Faulty, &rdev->flags)) {
+               clear_bit(Faulty, &rdev->flags);
+               clear_bit(In_sync, &rdev->flags);
+               rdev->saved_raid_disk = rdev->raid_disk;
+               rdev->recovery_offset = 0;
+       }
+
+       clear_bit(FirstUse, &rdev->flags);
+
+       return 0;
+}
+
+/*
+ * Analyse superblocks and select the freshest.
+ */
+static int analyse_superblocks(struct dm_target *ti, struct raid_set *rs)
+{
+       int ret;
+       mdk_rdev_t *rdev, *freshest, *tmp;
+       mddev_t *mddev = &rs->md;
+
+       freshest = NULL;
+       rdev_for_each(rdev, tmp, mddev) {
+               if (!rdev->meta_bdev)
+                       continue;
+
+               ret = super_load(rdev, freshest);
+
+               switch (ret) {
+               case 1:
+                       freshest = rdev;
+                       break;
+               case 0:
+                       break;
+               default:
+                       ti->error = "Failed to load superblock";
+                       return ret;
+               }
+       }
+
+       if (!freshest)
+               return 0;
+
+       /*
+        * Validation of the freshest device provides the source of
+        * validation for the remaining devices.
+        */
+       ti->error = "Unable to assemble array: Invalid superblocks";
+       if (super_validate(mddev, freshest))
+               return -EINVAL;
+
+       rdev_for_each(rdev, tmp, mddev)
+               if ((rdev != freshest) && super_validate(mddev, rdev))
+                       return -EINVAL;
+
+       return 0;
+}
+
 /*
  * Construct a RAID4/5/6 mapping:
  * Args:
  *     <raid_type> <#raid_params> <raid_params>                \
  *     <#raid_devs> { <meta_dev1> <dev1> .. <meta_devN> <devN> }
  *
- * ** metadata devices are not supported yet, use '-' instead **
- *
  * <raid_params> varies by <raid_type>.  See 'parse_raid_params' for
  * details on possible <raid_params>.
  */
@@ -465,8 +962,12 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
        if (ret)
                goto bad;
 
+       rs->md.sync_super = super_sync;
+       ret = analyse_superblocks(ti, rs);
+       if (ret)
+               goto bad;
+
        INIT_WORK(&rs->md.event_work, do_table_event);
-       ti->split_io = rs->md.chunk_sectors;
        ti->private = rs;
 
        mutex_lock(&rs->md.reconfig_mutex);
@@ -482,6 +983,7 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
        rs->callbacks.congested_fn = raid_is_congested;
        dm_table_add_target_callbacks(ti->table, &rs->callbacks);
 
+       mddev_suspend(&rs->md);
        return 0;
 
 bad:
@@ -546,12 +1048,17 @@ static int raid_status(struct dm_target *ti, status_type_t type,
                break;
        case STATUSTYPE_TABLE:
                /* The string you would use to construct this array */
-               for (i = 0; i < rs->md.raid_disks; i++)
-                       if (rs->dev[i].data_dev &&
+               for (i = 0; i < rs->md.raid_disks; i++) {
+                       if ((rs->print_flags & DMPF_REBUILD) &&
+                           rs->dev[i].data_dev &&
                            !test_bit(In_sync, &rs->dev[i].rdev.flags))
-                               raid_param_cnt++; /* for rebuilds */
+                               raid_param_cnt += 2; /* for rebuilds */
+                       if (rs->dev[i].data_dev &&
+                           test_bit(WriteMostly, &rs->dev[i].rdev.flags))
+                               raid_param_cnt += 2;
+               }
 
-               raid_param_cnt += (hweight64(rs->print_flags) * 2);
+               raid_param_cnt += (hweight64(rs->print_flags & ~DMPF_REBUILD) * 2);
                if (rs->print_flags & (DMPF_SYNC | DMPF_NOSYNC))
                        raid_param_cnt--;
 
@@ -565,7 +1072,8 @@ static int raid_status(struct dm_target *ti, status_type_t type,
                        DMEMIT(" nosync");
 
                for (i = 0; i < rs->md.raid_disks; i++)
-                       if (rs->dev[i].data_dev &&
+                       if ((rs->print_flags & DMPF_REBUILD) &&
+                           rs->dev[i].data_dev &&
                            !test_bit(In_sync, &rs->dev[i].rdev.flags))
                                DMEMIT(" rebuild %u", i);
 
@@ -579,6 +1087,11 @@ static int raid_status(struct dm_target *ti, status_type_t type,
                if (rs->print_flags & DMPF_MAX_RECOVERY_RATE)
                        DMEMIT(" max_recovery_rate %d", rs->md.sync_speed_max);
 
+               for (i = 0; i < rs->md.raid_disks; i++)
+                       if (rs->dev[i].data_dev &&
+                           test_bit(WriteMostly, &rs->dev[i].rdev.flags))
+                               DMEMIT(" write_mostly %u", i);
+
                if (rs->print_flags & DMPF_MAX_WRITE_BEHIND)
                        DMEMIT(" max_write_behind %lu",
                               rs->md.bitmap_info.max_write_behind);
@@ -591,9 +1104,16 @@ static int raid_status(struct dm_target *ti, status_type_t type,
                               conf ? conf->max_nr_stripes * 2 : 0);
                }
 
+               if (rs->print_flags & DMPF_REGION_SIZE)
+                       DMEMIT(" region_size %lu",
+                              rs->md.bitmap_info.chunksize >> 9);
+
                DMEMIT(" %d", rs->md.raid_disks);
                for (i = 0; i < rs->md.raid_disks; i++) {
-                       DMEMIT(" -"); /* metadata device */
+                       if (rs->dev[i].meta_dev)
+                               DMEMIT(" %s", rs->dev[i].meta_dev->name);
+                       else
+                               DMEMIT(" -");
 
                        if (rs->dev[i].data_dev)
                                DMEMIT(" %s", rs->dev[i].data_dev->name);
@@ -650,12 +1170,13 @@ static void raid_resume(struct dm_target *ti)
 {
        struct raid_set *rs = ti->private;
 
+       bitmap_load(&rs->md);
        mddev_resume(&rs->md);
 }
 
 static struct target_type raid_target = {
        .name = "raid",
-       .version = {1, 0, 0},
+       .version = {1, 1, 0},
        .module = THIS_MODULE,
        .ctr = raid_ctr,
        .dtr = raid_dtr,
index 135c2f1..d1f1d70 100644 (file)
 #define NUM_SNAPSHOT_HDR_CHUNKS 1
 
 struct disk_header {
-       uint32_t magic;
+       __le32 magic;
 
        /*
         * Is this snapshot valid.  There is no way of recovering
         * an invalid snapshot.
         */
-       uint32_t valid;
+       __le32 valid;
 
        /*
         * Simple, incrementing version. no backward
         * compatibility.
         */
-       uint32_t version;
+       __le32 version;
 
        /* In sectors */
-       uint32_t chunk_size;
-};
+       __le32 chunk_size;
+} __packed;
 
 struct disk_exception {
+       __le64 old_chunk;
+       __le64 new_chunk;
+} __packed;
+
+struct core_exception {
        uint64_t old_chunk;
        uint64_t new_chunk;
 };
@@ -169,10 +174,9 @@ static int alloc_area(struct pstore *ps)
        if (!ps->area)
                goto err_area;
 
-       ps->zero_area = vmalloc(len);
+       ps->zero_area = vzalloc(len);
        if (!ps->zero_area)
                goto err_zero_area;
-       memset(ps->zero_area, 0, len);
 
        ps->header_area = vmalloc(len);
        if (!ps->header_area)
@@ -396,32 +400,32 @@ static struct disk_exception *get_exception(struct pstore *ps, uint32_t index)
 }
 
 static void read_exception(struct pstore *ps,
-                          uint32_t index, struct disk_exception *result)
+                          uint32_t index, struct core_exception *result)
 {
-       struct disk_exception *e = get_exception(ps, index);
+       struct disk_exception *de = get_exception(ps, index);
 
        /* copy it */
-       result->old_chunk = le64_to_cpu(e->old_chunk);
-       result->new_chunk = le64_to_cpu(e->new_chunk);
+       result->old_chunk = le64_to_cpu(de->old_chunk);
+       result->new_chunk = le64_to_cpu(de->new_chunk);
 }
 
 static void write_exception(struct pstore *ps,
-                           uint32_t index, struct disk_exception *de)
+                           uint32_t index, struct core_exception *e)
 {
-       struct disk_exception *e = get_exception(ps, index);
+       struct disk_exception *de = get_exception(ps, index);
 
        /* copy it */
-       e->old_chunk = cpu_to_le64(de->old_chunk);
-       e->new_chunk = cpu_to_le64(de->new_chunk);
+       de->old_chunk = cpu_to_le64(e->old_chunk);
+       de->new_chunk = cpu_to_le64(e->new_chunk);
 }
 
 static void clear_exception(struct pstore *ps, uint32_t index)
 {
-       struct disk_exception *e = get_exception(ps, index);
+       struct disk_exception *de = get_exception(ps, index);
 
        /* clear it */
-       e->old_chunk = 0;
-       e->new_chunk = 0;
+       de->old_chunk = 0;
+       de->new_chunk = 0;
 }
 
 /*
@@ -437,13 +441,13 @@ static int insert_exceptions(struct pstore *ps,
 {
        int r;
        unsigned int i;
-       struct disk_exception de;
+       struct core_exception e;
 
        /* presume the area is full */
        *full = 1;
 
        for (i = 0; i < ps->exceptions_per_area; i++) {
-               read_exception(ps, i, &de);
+               read_exception(ps, i, &e);
 
                /*
                 * If the new_chunk is pointing at the start of
@@ -451,7 +455,7 @@ static int insert_exceptions(struct pstore *ps,
                 * is we know that we've hit the end of the
                 * exceptions.  Therefore the area is not full.
                 */
-               if (de.new_chunk == 0LL) {
+               if (e.new_chunk == 0LL) {
                        ps->current_committed = i;
                        *full = 0;
                        break;
@@ -460,13 +464,13 @@ static int insert_exceptions(struct pstore *ps,
                /*
                 * Keep track of the start of the free chunks.
                 */
-               if (ps->next_free <= de.new_chunk)
-                       ps->next_free = de.new_chunk + 1;
+               if (ps->next_free <= e.new_chunk)
+                       ps->next_free = e.new_chunk + 1;
 
                /*
                 * Otherwise we add the exception to the snapshot.
                 */
-               r = callback(callback_context, de.old_chunk, de.new_chunk);
+               r = callback(callback_context, e.old_chunk, e.new_chunk);
                if (r)
                        return r;
        }
@@ -563,7 +567,7 @@ static int persistent_read_metadata(struct dm_exception_store *store,
        ps->exceptions_per_area = (ps->store->chunk_size << SECTOR_SHIFT) /
                                  sizeof(struct disk_exception);
        ps->callbacks = dm_vcalloc(ps->exceptions_per_area,
-                       sizeof(*ps->callbacks));
+                                  sizeof(*ps->callbacks));
        if (!ps->callbacks)
                return -ENOMEM;
 
@@ -641,12 +645,12 @@ static void persistent_commit_exception(struct dm_exception_store *store,
 {
        unsigned int i;
        struct pstore *ps = get_info(store);
-       struct disk_exception de;
+       struct core_exception ce;
        struct commit_callback *cb;
 
-       de.old_chunk = e->old_chunk;
-       de.new_chunk = e->new_chunk;
-       write_exception(ps, ps->current_committed++, &de);
+       ce.old_chunk = e->old_chunk;
+       ce.new_chunk = e->new_chunk;
+       write_exception(ps, ps->current_committed++, &ce);
 
        /*
         * Add the callback to the back of the array.  This code
@@ -670,7 +674,7 @@ static void persistent_commit_exception(struct dm_exception_store *store,
         * If we completely filled the current area, then wipe the next one.
         */
        if ((ps->current_committed == ps->exceptions_per_area) &&
-            zero_disk_area(ps, ps->current_area + 1))
+           zero_disk_area(ps, ps->current_area + 1))
                ps->valid = 0;
 
        /*
@@ -701,7 +705,7 @@ static int persistent_prepare_merge(struct dm_exception_store *store,
                                    chunk_t *last_new_chunk)
 {
        struct pstore *ps = get_info(store);
-       struct disk_exception de;
+       struct core_exception ce;
        int nr_consecutive;
        int r;
 
@@ -722,9 +726,9 @@ static int persistent_prepare_merge(struct dm_exception_store *store,
                ps->current_committed = ps->exceptions_per_area;
        }
 
-       read_exception(ps, ps->current_committed - 1, &de);
-       *last_old_chunk = de.old_chunk;
-       *last_new_chunk = de.new_chunk;
+       read_exception(ps, ps->current_committed - 1, &ce);
+       *last_old_chunk = ce.old_chunk;
+       *last_new_chunk = ce.new_chunk;
 
        /*
         * Find number of consecutive chunks within the current area,
@@ -733,9 +737,9 @@ static int persistent_prepare_merge(struct dm_exception_store *store,
        for (nr_consecutive = 1; nr_consecutive < ps->current_committed;
             nr_consecutive++) {
                read_exception(ps, ps->current_committed - 1 - nr_consecutive,
-                              &de);
-               if (de.old_chunk != *last_old_chunk - nr_consecutive ||
-                   de.new_chunk != *last_new_chunk - nr_consecutive)
+                              &ce);
+               if (ce.old_chunk != *last_old_chunk - nr_consecutive ||
+                   ce.new_chunk != *last_new_chunk - nr_consecutive)
                        break;
        }
 
@@ -753,7 +757,7 @@ static int persistent_commit_merge(struct dm_exception_store *store,
        for (i = 0; i < nr_merged; i++)
                clear_exception(ps, ps->current_committed - 1 - i);
 
-       r = area_io(ps, WRITE);
+       r = area_io(ps, WRITE_FLUSH_FUA);
        if (r < 0)
                return r;
 
index 9ecff5f..6f75887 100644 (file)
@@ -29,16 +29,6 @@ static const char dm_snapshot_merge_target_name[] = "snapshot-merge";
 #define dm_target_is_snapshot_merge(ti) \
        ((ti)->type->name == dm_snapshot_merge_target_name)
 
-/*
- * The percentage increment we will wake up users at
- */
-#define WAKE_UP_PERCENT 5
-
-/*
- * kcopyd priority of snapshot operations
- */
-#define SNAPSHOT_COPY_PRIORITY 2
-
 /*
  * The size of the mempool used to track chunks in use.
  */
@@ -180,6 +170,13 @@ struct dm_snap_pending_exception {
         * kcopyd.
         */
        int started;
+
+       /*
+        * For writing a complete chunk, bypassing the copy.
+        */
+       struct bio *full_bio;
+       bio_end_io_t *full_bio_end_io;
+       void *full_bio_private;
 };
 
 /*
@@ -1055,8 +1052,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 
        s = kmalloc(sizeof(*s), GFP_KERNEL);
        if (!s) {
-               ti->error = "Cannot allocate snapshot context private "
-                   "structure";
+               ti->error = "Cannot allocate private snapshot structure";
                r = -ENOMEM;
                goto bad;
        }
@@ -1380,6 +1376,7 @@ static void pending_complete(struct dm_snap_pending_exception *pe, int success)
        struct dm_snapshot *s = pe->snap;
        struct bio *origin_bios = NULL;
        struct bio *snapshot_bios = NULL;
+       struct bio *full_bio = NULL;
        int error = 0;
 
        if (!success) {
@@ -1415,10 +1412,15 @@ static void pending_complete(struct dm_snap_pending_exception *pe, int success)
         */
        dm_insert_exception(&s->complete, e);
 
- out:
+out:
        dm_remove_exception(&pe->e);
        snapshot_bios = bio_list_get(&pe->snapshot_bios);
        origin_bios = bio_list_get(&pe->origin_bios);
+       full_bio = pe->full_bio;
+       if (full_bio) {
+               full_bio->bi_end_io = pe->full_bio_end_io;
+               full_bio->bi_private = pe->full_bio_private;
+       }
        free_pending_exception(pe);
 
        increment_pending_exceptions_done_count();
@@ -1426,10 +1428,15 @@ static void pending_complete(struct dm_snap_pending_exception *pe, int success)
        up_write(&s->lock);
 
        /* Submit any pending write bios */
-       if (error)
+       if (error) {
+               if (full_bio)
+                       bio_io_error(full_bio);
                error_bios(snapshot_bios);
-       else
+       } else {
+               if (full_bio)
+                       bio_endio(full_bio, 0);
                flush_bios(snapshot_bios);
+       }
 
        retry_origin_bios(s, origin_bios);
 }
@@ -1480,8 +1487,33 @@ static void start_copy(struct dm_snap_pending_exception *pe)
        dest.count = src.count;
 
        /* Hand over to kcopyd */
-       dm_kcopyd_copy(s->kcopyd_client,
-                   &src, 1, &dest, 0, copy_callback, pe);
+       dm_kcopyd_copy(s->kcopyd_client, &src, 1, &dest, 0, copy_callback, pe);
+}
+
+static void full_bio_end_io(struct bio *bio, int error)
+{
+       void *callback_data = bio->bi_private;
+
+       dm_kcopyd_do_callback(callback_data, 0, error ? 1 : 0);
+}
+
+static void start_full_bio(struct dm_snap_pending_exception *pe,
+                          struct bio *bio)
+{
+       struct dm_snapshot *s = pe->snap;
+       void *callback_data;
+
+       pe->full_bio = bio;
+       pe->full_bio_end_io = bio->bi_end_io;
+       pe->full_bio_private = bio->bi_private;
+
+       callback_data = dm_kcopyd_prepare_callback(s->kcopyd_client,
+                                                  copy_callback, pe);
+
+       bio->bi_end_io = full_bio_end_io;
+       bio->bi_private = callback_data;
+
+       generic_make_request(bio);
 }
 
 static struct dm_snap_pending_exception *
@@ -1519,6 +1551,7 @@ __find_pending_exception(struct dm_snapshot *s,
        bio_list_init(&pe->origin_bios);
        bio_list_init(&pe->snapshot_bios);
        pe->started = 0;
+       pe->full_bio = NULL;
 
        if (s->store->type->prepare_exception(s->store, &pe->e)) {
                free_pending_exception(pe);
@@ -1612,10 +1645,19 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio,
                }
 
                remap_exception(s, &pe->e, bio, chunk);
-               bio_list_add(&pe->snapshot_bios, bio);
 
                r = DM_MAPIO_SUBMITTED;
 
+               if (!pe->started &&
+                   bio->bi_size == (s->store->chunk_size << SECTOR_SHIFT)) {
+                       pe->started = 1;
+                       up_write(&s->lock);
+                       start_full_bio(pe, bio);
+                       goto out;
+               }
+
+               bio_list_add(&pe->snapshot_bios, bio);
+
                if (!pe->started) {
                        /* this is protected by snap->lock */
                        pe->started = 1;
@@ -1628,9 +1670,9 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio,
                map_context->ptr = track_chunk(s, chunk);
        }
 
- out_unlock:
+out_unlock:
        up_write(&s->lock);
- out:
+out:
        return r;
 }
 
@@ -1974,7 +2016,7 @@ static int __origin_write(struct list_head *snapshots, sector_t sector,
                        pe_to_start_now = pe;
                }
 
- next_snapshot:
+next_snapshot:
                up_write(&snap->lock);
 
                if (pe_to_start_now) {
index bfe9c23..986b875 100644 (file)
@@ -54,7 +54,6 @@ struct dm_table {
        sector_t *highs;
        struct dm_target *targets;
 
-       unsigned discards_supported:1;
        unsigned integrity_supported:1;
 
        /*
@@ -154,12 +153,11 @@ void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size)
                return NULL;
 
        size = nmemb * elem_size;
-       addr = vmalloc(size);
-       if (addr)
-               memset(addr, 0, size);
+       addr = vzalloc(size);
 
        return addr;
 }
+EXPORT_SYMBOL(dm_vcalloc);
 
 /*
  * highs, and targets are managed as dynamic arrays during a
@@ -209,7 +207,6 @@ int dm_table_create(struct dm_table **result, fmode_t mode,
        INIT_LIST_HEAD(&t->devices);
        INIT_LIST_HEAD(&t->target_callbacks);
        atomic_set(&t->holders, 0);
-       t->discards_supported = 1;
 
        if (!num_targets)
                num_targets = KEYS_PER_NODE;
@@ -281,6 +278,7 @@ void dm_table_get(struct dm_table *t)
 {
        atomic_inc(&t->holders);
 }
+EXPORT_SYMBOL(dm_table_get);
 
 void dm_table_put(struct dm_table *t)
 {
@@ -290,6 +288,7 @@ void dm_table_put(struct dm_table *t)
        smp_mb__before_atomic_dec();
        atomic_dec(&t->holders);
 }
+EXPORT_SYMBOL(dm_table_put);
 
 /*
  * Checks to see if we need to extend highs or targets.
@@ -455,13 +454,14 @@ static int upgrade_mode(struct dm_dev_internal *dd, fmode_t new_mode,
  * Add a device to the list, or just increment the usage count if
  * it's already present.
  */
-static int __table_get_device(struct dm_table *t, struct dm_target *ti,
-                     const char *path, fmode_t mode, struct dm_dev **result)
+int dm_get_device(struct dm_target *ti, const char *path, fmode_t mode,
+                 struct dm_dev **result)
 {
        int r;
        dev_t uninitialized_var(dev);
        struct dm_dev_internal *dd;
        unsigned int major, minor;
+       struct dm_table *t = ti->table;
 
        BUG_ON(!t);
 
@@ -509,6 +509,7 @@ static int __table_get_device(struct dm_table *t, struct dm_target *ti,
        *result = &dd->dm_dev;
        return 0;
 }
+EXPORT_SYMBOL(dm_get_device);
 
 int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev,
                         sector_t start, sector_t len, void *data)
@@ -539,23 +540,15 @@ int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev,
         * If not we'll force DM to use PAGE_SIZE or
         * smaller I/O, just to be safe.
         */
-
-       if (q->merge_bvec_fn && !ti->type->merge)
+       if (dm_queue_merge_is_compulsory(q) && !ti->type->merge)
                blk_limits_max_hw_sectors(limits,
                                          (unsigned int) (PAGE_SIZE >> 9));
        return 0;
 }
 EXPORT_SYMBOL_GPL(dm_set_device_limits);
 
-int dm_get_device(struct dm_target *ti, const char *path, fmode_t mode,
-                 struct dm_dev **result)
-{
-       return __table_get_device(ti->table, ti, path, mode, result);
-}
-
-
 /*
- * Decrement a devices use count and remove it if necessary.
+ * Decrement a device's use count and remove it if necessary.
  */
 void dm_put_device(struct dm_target *ti, struct dm_dev *d)
 {
@@ -568,6 +561,7 @@ void dm_put_device(struct dm_target *ti, struct dm_dev *d)
                kfree(dd);
        }
 }
+EXPORT_SYMBOL(dm_put_device);
 
 /*
  * Checks to see if the target joins onto the end of the table.
@@ -791,8 +785,9 @@ int dm_table_add_target(struct dm_table *t, const char *type,
 
        t->highs[t->num_targets++] = tgt->begin + tgt->len - 1;
 
-       if (!tgt->num_discard_requests)
-               t->discards_supported = 0;
+       if (!tgt->num_discard_requests && tgt->discards_supported)
+               DMWARN("%s: %s: ignoring discards_supported because num_discard_requests is zero.",
+                      dm_device_name(t->md), type);
 
        return 0;
 
@@ -802,6 +797,63 @@ int dm_table_add_target(struct dm_table *t, const char *type,
        return r;
 }
 
+/*
+ * Target argument parsing helpers.
+ */
+static int validate_next_arg(struct dm_arg *arg, struct dm_arg_set *arg_set,
+                            unsigned *value, char **error, unsigned grouped)
+{
+       const char *arg_str = dm_shift_arg(arg_set);
+
+       if (!arg_str ||
+           (sscanf(arg_str, "%u", value) != 1) ||
+           (*value < arg->min) ||
+           (*value > arg->max) ||
+           (grouped && arg_set->argc < *value)) {
+               *error = arg->error;
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int dm_read_arg(struct dm_arg *arg, struct dm_arg_set *arg_set,
+               unsigned *value, char **error)
+{
+       return validate_next_arg(arg, arg_set, value, error, 0);
+}
+EXPORT_SYMBOL(dm_read_arg);
+
+int dm_read_arg_group(struct dm_arg *arg, struct dm_arg_set *arg_set,
+                     unsigned *value, char **error)
+{
+       return validate_next_arg(arg, arg_set, value, error, 1);
+}
+EXPORT_SYMBOL(dm_read_arg_group);
+
+const char *dm_shift_arg(struct dm_arg_set *as)
+{
+       char *r;
+
+       if (as->argc) {
+               as->argc--;
+               r = *as->argv;
+               as->argv++;
+               return r;
+       }
+
+       return NULL;
+}
+EXPORT_SYMBOL(dm_shift_arg);
+
+void dm_consume_args(struct dm_arg_set *as, unsigned num_args)
+{
+       BUG_ON(as->argc < num_args);
+       as->argc -= num_args;
+       as->argv += num_args;
+}
+EXPORT_SYMBOL(dm_consume_args);
+
 static int dm_table_set_type(struct dm_table *t)
 {
        unsigned i;
@@ -1077,11 +1129,13 @@ void dm_table_event(struct dm_table *t)
                t->event_fn(t->event_context);
        mutex_unlock(&_event_lock);
 }
+EXPORT_SYMBOL(dm_table_event);
 
 sector_t dm_table_get_size(struct dm_table *t)
 {
        return t->num_targets ? (t->highs[t->num_targets - 1] + 1) : 0;
 }
+EXPORT_SYMBOL(dm_table_get_size);
 
 struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index)
 {
@@ -1194,9 +1248,45 @@ static void dm_table_set_integrity(struct dm_table *t)
                               blk_get_integrity(template_disk));
 }
 
+static int device_flush_capable(struct dm_target *ti, struct dm_dev *dev,
+                               sector_t start, sector_t len, void *data)
+{
+       unsigned flush = (*(unsigned *)data);
+       struct request_queue *q = bdev_get_queue(dev->bdev);
+
+       return q && (q->flush_flags & flush);
+}
+
+static bool dm_table_supports_flush(struct dm_table *t, unsigned flush)
+{
+       struct dm_target *ti;
+       unsigned i = 0;
+
+       /*
+        * Require at least one underlying device to support flushes.
+        * t->devices includes internal dm devices such as mirror logs
+        * so we need to use iterate_devices here, which targets
+        * supporting flushes must provide.
+        */
+       while (i < dm_table_get_num_targets(t)) {
+               ti = dm_table_get_target(t, i++);
+
+               if (!ti->num_flush_requests)
+                       continue;
+
+               if (ti->type->iterate_devices &&
+                   ti->type->iterate_devices(ti, device_flush_capable, &flush))
+                       return 1;
+       }
+
+       return 0;
+}
+
 void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
                               struct queue_limits *limits)
 {
+       unsigned flush = 0;
+
        /*
         * Copy table's limits to the DM device's request_queue
         */
@@ -1207,6 +1297,13 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
        else
                queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
 
+       if (dm_table_supports_flush(t, REQ_FLUSH)) {
+               flush |= REQ_FLUSH;
+               if (dm_table_supports_flush(t, REQ_FUA))
+                       flush |= REQ_FUA;
+       }
+       blk_queue_flush(q, flush);
+
        dm_table_set_integrity(t);
 
        /*
@@ -1237,6 +1334,7 @@ fmode_t dm_table_get_mode(struct dm_table *t)
 {
        return t->mode;
 }
+EXPORT_SYMBOL(dm_table_get_mode);
 
 static void suspend_targets(struct dm_table *t, unsigned postsuspend)
 {
@@ -1345,6 +1443,7 @@ struct mapped_device *dm_table_get_md(struct dm_table *t)
 {
        return t->md;
 }
+EXPORT_SYMBOL(dm_table_get_md);
 
 static int device_discard_capable(struct dm_target *ti, struct dm_dev *dev,
                                  sector_t start, sector_t len, void *data)
@@ -1359,19 +1458,19 @@ bool dm_table_supports_discards(struct dm_table *t)
        struct dm_target *ti;
        unsigned i = 0;
 
-       if (!t->discards_supported)
-               return 0;
-
        /*
         * Unless any target used by the table set discards_supported,
         * require at least one underlying device to support discards.
         * t->devices includes internal dm devices such as mirror logs
         * so we need to use iterate_devices here, which targets
-        * supporting discard must provide.
+        * supporting discard selectively must provide.
         */
        while (i < dm_table_get_num_targets(t)) {
                ti = dm_table_get_target(t, i++);
 
+               if (!ti->num_discard_requests)
+                       continue;
+
                if (ti->discards_supported)
                        return 1;
 
@@ -1382,13 +1481,3 @@ bool dm_table_supports_discards(struct dm_table *t)
 
        return 0;
 }
-
-EXPORT_SYMBOL(dm_vcalloc);
-EXPORT_SYMBOL(dm_get_device);
-EXPORT_SYMBOL(dm_put_device);
-EXPORT_SYMBOL(dm_table_event);
-EXPORT_SYMBOL(dm_table_get_size);
-EXPORT_SYMBOL(dm_table_get_mode);
-EXPORT_SYMBOL(dm_table_get_md);
-EXPORT_SYMBOL(dm_table_put);
-EXPORT_SYMBOL(dm_table_get);
index 0cf68b4..52b39f3 100644 (file)
@@ -37,6 +37,8 @@ static const char *_name = DM_NAME;
 static unsigned int major = 0;
 static unsigned int _major = 0;
 
+static DEFINE_IDR(_minor_idr);
+
 static DEFINE_SPINLOCK(_minor_lock);
 /*
  * For bio-based dm.
@@ -109,6 +111,7 @@ EXPORT_SYMBOL_GPL(dm_get_rq_mapinfo);
 #define DMF_FREEING 3
 #define DMF_DELETING 4
 #define DMF_NOFLUSH_SUSPENDING 5
+#define DMF_MERGE_IS_OPTIONAL 6
 
 /*
  * Work processed by per-device workqueue.
@@ -313,6 +316,12 @@ static void __exit dm_exit(void)
 
        while (i--)
                _exits[i]();
+
+       /*
+        * Should be empty by this point.
+        */
+       idr_remove_all(&_minor_idr);
+       idr_destroy(&_minor_idr);
 }
 
 /*
@@ -1171,7 +1180,8 @@ static int __clone_and_map_discard(struct clone_info *ci)
 
                /*
                 * Even though the device advertised discard support,
-                * reconfiguration might have changed that since the
+                * that does not mean every target supports it, and
+                * reconfiguration might also have changed that since the
                 * check was performed.
                 */
                if (!ti->num_discard_requests)
@@ -1705,8 +1715,6 @@ static int dm_any_congested(void *congested_data, int bdi_bits)
 /*-----------------------------------------------------------------
  * An IDR is used to keep track of allocated minor numbers.
  *---------------------------------------------------------------*/
-static DEFINE_IDR(_minor_idr);
-
 static void free_minor(int minor)
 {
        spin_lock(&_minor_lock);
@@ -1800,7 +1808,6 @@ static void dm_init_md_queue(struct mapped_device *md)
        blk_queue_make_request(md->queue, dm_request);
        blk_queue_bounce_limit(md->queue, BLK_BOUNCE_ANY);
        blk_queue_merge_bvec(md->queue, dm_merge_bvec);
-       blk_queue_flush(md->queue, REQ_FLUSH | REQ_FUA);
 }
 
 /*
@@ -1985,6 +1992,59 @@ static void __set_size(struct mapped_device *md, sector_t size)
        i_size_write(md->bdev->bd_inode, (loff_t)size << SECTOR_SHIFT);
 }
 
+/*
+ * Return 1 if the queue has a compulsory merge_bvec_fn function.
+ *
+ * If this function returns 0, then the device is either a non-dm
+ * device without a merge_bvec_fn, or it is a dm device that is
+ * able to split any bios it receives that are too big.
+ */
+int dm_queue_merge_is_compulsory(struct request_queue *q)
+{
+       struct mapped_device *dev_md;
+
+       if (!q->merge_bvec_fn)
+               return 0;
+
+       if (q->make_request_fn == dm_request) {
+               dev_md = q->queuedata;
+               if (test_bit(DMF_MERGE_IS_OPTIONAL, &dev_md->flags))
+                       return 0;
+       }
+
+       return 1;
+}
+
+static int dm_device_merge_is_compulsory(struct dm_target *ti,
+                                        struct dm_dev *dev, sector_t start,
+                                        sector_t len, void *data)
+{
+       struct block_device *bdev = dev->bdev;
+       struct request_queue *q = bdev_get_queue(bdev);
+
+       return dm_queue_merge_is_compulsory(q);
+}
+
+/*
+ * Return 1 if it is acceptable to ignore merge_bvec_fn based
+ * on the properties of the underlying devices.
+ */
+static int dm_table_merge_is_optional(struct dm_table *table)
+{
+       unsigned i = 0;
+       struct dm_target *ti;
+
+       while (i < dm_table_get_num_targets(table)) {
+               ti = dm_table_get_target(table, i++);
+
+               if (ti->type->iterate_devices &&
+                   ti->type->iterate_devices(ti, dm_device_merge_is_compulsory, NULL))
+                       return 0;
+       }
+
+       return 1;
+}
+
 /*
  * Returns old map, which caller must destroy.
  */
@@ -1995,6 +2055,7 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
        struct request_queue *q = md->queue;
        sector_t size;
        unsigned long flags;
+       int merge_is_optional;
 
        size = dm_table_get_size(t);
 
@@ -2020,10 +2081,16 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
 
        __bind_mempools(md, t);
 
+       merge_is_optional = dm_table_merge_is_optional(t);
+
        write_lock_irqsave(&md->map_lock, flags);
        old_map = md->map;
        md->map = t;
        dm_table_set_restrictions(t, q, limits);
+       if (merge_is_optional)
+               set_bit(DMF_MERGE_IS_OPTIONAL, &md->flags);
+       else
+               clear_bit(DMF_MERGE_IS_OPTIONAL, &md->flags);
        write_unlock_irqrestore(&md->map_lock, flags);
 
        return old_map;
index 1aaf167..6745dbd 100644 (file)
@@ -66,6 +66,8 @@ int dm_table_alloc_md_mempools(struct dm_table *t);
 void dm_table_free_md_mempools(struct dm_table *t);
 struct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t);
 
+int dm_queue_merge_is_compulsory(struct request_queue *q);
+
 void dm_lock_md_type(struct mapped_device *md);
 void dm_unlock_md_type(struct mapped_device *md);
 void dm_set_md_type(struct mapped_device *md, unsigned type);
index 6995940..9575db4 100644 (file)
@@ -68,7 +68,6 @@ config VIDEO_V4L2_SUBDEV_API
 
 config DVB_CORE
        tristate "DVB for Linux"
-       depends on NET && INET
        select CRC32
        help
          DVB core utility functions for device handling, software fallbacks etc.
@@ -85,6 +84,19 @@ config DVB_CORE
 
          If unsure say N.
 
+config DVB_NET
+       bool "DVB Network Support"
+       default (NET && INET)
+       depends on NET && INET && DVB_CORE
+       help
+         This option enables DVB Network Support which is a part of the DVB
+         standard. It is used, for example, by automatic firmware updates used
+         on Set-Top-Boxes. It can also be used to access the Internet via the
+         DVB card, if the network provider supports it.
+
+         You may want to disable the network support on embedded devices. If
+         unsure say Y.
+
 config VIDEO_MEDIA
        tristate
        default (DVB_CORE && (VIDEO_DEV = n)) || (VIDEO_DEV && (DVB_CORE = n)) || (DVB_CORE && VIDEO_DEV)
index 22d3ca3..996302a 100644 (file)
@@ -23,6 +23,7 @@ config MEDIA_TUNER
        depends on VIDEO_MEDIA && I2C
        select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE
@@ -152,6 +153,15 @@ config MEDIA_TUNER_XC5000
          This device is only used inside a SiP called together with a
          demodulator for now.
 
+config MEDIA_TUNER_XC4000
+       tristate "Xceive XC4000 silicon tuner"
+       depends on VIDEO_MEDIA && I2C
+       default m if MEDIA_TUNER_CUSTOMISE
+       help
+         A driver for the silicon tuner XC4000 from Xceive.
+         This device is only used inside a SiP called together with a
+         demodulator for now.
+
 config MEDIA_TUNER_MXL5005S
        tristate "MaxLinear MSL5005S silicon tuner"
        depends on VIDEO_MEDIA && I2C
index 2cb4f53..20d24fc 100644 (file)
@@ -16,6 +16,7 @@ obj-$(CONFIG_MEDIA_TUNER_TDA9887) += tda9887.o
 obj-$(CONFIG_MEDIA_TUNER_TDA827X) += tda827x.o
 obj-$(CONFIG_MEDIA_TUNER_TDA18271) += tda18271.o
 obj-$(CONFIG_MEDIA_TUNER_XC5000) += xc5000.o
+obj-$(CONFIG_MEDIA_TUNER_XC4000) += xc4000.o
 obj-$(CONFIG_MEDIA_TUNER_MT2060) += mt2060.o
 obj-$(CONFIG_MEDIA_TUNER_MT2266) += mt2266.o
 obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o
index afba6dc..94a603a 100644 (file)
@@ -1805,6 +1805,10 @@ struct tunertype tuners[] = {
                .name   = "Xceive 5000 tuner",
                /* see xc5000.c for details */
        },
+       [TUNER_XC4000] = { /* Xceive 4000 */
+               .name   = "Xceive 4000 tuner",
+               /* see xc4000.c for details */
+       },
        [TUNER_TCL_MF02GIP_5N] = { /* TCL tuner MF02GIP-5N-E */
                .name   = "TCL tuner MF02GIP-5N-E",
                .params = tuner_tcl_mf02gip_5n_params,
diff --git a/drivers/media/common/tuners/xc4000.c b/drivers/media/common/tuners/xc4000.c
new file mode 100644 (file)
index 0000000..634f4d9
--- /dev/null
@@ -0,0 +1,1691 @@
+/*
+ *  Driver for Xceive XC4000 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2007 Xceive Corporation
+ *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
+ *  Copyright (c) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
+ *  Copyright (c) 2009 Davide Ferri <d.ferri@zero11.it>
+ *  Copyright (c) 2010 Istvan Varga <istvan_v@mailbox.hu>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/videodev2.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <asm/unaligned.h>
+
+#include "dvb_frontend.h"
+
+#include "xc4000.h"
+#include "tuner-i2c.h"
+#include "tuner-xc2028-types.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debugging level (0 to 2, default: 0 (off)).");
+
+static int no_poweroff;
+module_param(no_poweroff, int, 0644);
+MODULE_PARM_DESC(no_poweroff, "Power management (1: disabled, 2: enabled, "
+       "0 (default): use device-specific default mode).");
+
+static int audio_std;
+module_param(audio_std, int, 0644);
+MODULE_PARM_DESC(audio_std, "Audio standard. XC4000 audio decoder explicitly "
+       "needs to know what audio standard is needed for some video standards "
+       "with audio A2 or NICAM. The valid settings are a sum of:\n"
+       " 1: use NICAM/B or A2/B instead of NICAM/A or A2/A\n"
+       " 2: use A2 instead of NICAM or BTSC\n"
+       " 4: use SECAM/K3 instead of K1\n"
+       " 8: use PAL-D/K audio for SECAM-D/K\n"
+       "16: use FM radio input 1 instead of input 2\n"
+       "32: use mono audio (the lower three bits are ignored)");
+
+static char firmware_name[30];
+module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0);
+MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the "
+       "default firmware name.");
+
+static DEFINE_MUTEX(xc4000_list_mutex);
+static LIST_HEAD(hybrid_tuner_instance_list);
+
+#define dprintk(level, fmt, arg...) if (debug >= level) \
+       printk(KERN_INFO "%s: " fmt, "xc4000", ## arg)
+
+/* struct for storing firmware table */
+struct firmware_description {
+       unsigned int  type;
+       v4l2_std_id   id;
+       __u16         int_freq;
+       unsigned char *ptr;
+       unsigned int  size;
+};
+
+struct firmware_properties {
+       unsigned int    type;
+       v4l2_std_id     id;
+       v4l2_std_id     std_req;
+       __u16           int_freq;
+       unsigned int    scode_table;
+       int             scode_nr;
+};
+
+struct xc4000_priv {
+       struct tuner_i2c_props i2c_props;
+       struct list_head hybrid_tuner_instance_list;
+       struct firmware_description *firm;
+       int     firm_size;
+       u32     if_khz;
+       u32     freq_hz;
+       u32     bandwidth;
+       u8      video_standard;
+       u8      rf_mode;
+       u8      default_pm;
+       u8      dvb_amplitude;
+       u8      set_smoothedcvbs;
+       u8      ignore_i2c_write_errors;
+       __u16   firm_version;
+       struct firmware_properties cur_fw;
+       __u16   hwmodel;
+       __u16   hwvers;
+       struct mutex    lock;
+};
+
+#define XC4000_AUDIO_STD_B              1
+#define XC4000_AUDIO_STD_A2             2
+#define XC4000_AUDIO_STD_K3             4
+#define XC4000_AUDIO_STD_L              8
+#define XC4000_AUDIO_STD_INPUT1                16
+#define XC4000_AUDIO_STD_MONO          32
+
+#define XC4000_DEFAULT_FIRMWARE "dvb-fe-xc4000-1.4.fw"
+
+/* Misc Defines */
+#define MAX_TV_STANDARD                        24
+#define XC_MAX_I2C_WRITE_LENGTH                64
+#define XC_POWERED_DOWN                        0x80000000U
+
+/* Signal Types */
+#define XC_RF_MODE_AIR                 0
+#define XC_RF_MODE_CABLE               1
+
+/* Product id */
+#define XC_PRODUCT_ID_FW_NOT_LOADED    0x2000
+#define XC_PRODUCT_ID_XC4000           0x0FA0
+#define XC_PRODUCT_ID_XC4100           0x1004
+
+/* Registers (Write-only) */
+#define XREG_INIT         0x00
+#define XREG_VIDEO_MODE   0x01
+#define XREG_AUDIO_MODE   0x02
+#define XREG_RF_FREQ      0x03
+#define XREG_D_CODE       0x04
+#define XREG_DIRECTSITTING_MODE 0x05
+#define XREG_SEEK_MODE    0x06
+#define XREG_POWER_DOWN   0x08
+#define XREG_SIGNALSOURCE 0x0A
+#define XREG_SMOOTHEDCVBS 0x0E
+#define XREG_AMPLITUDE    0x10
+
+/* Registers (Read-only) */
+#define XREG_ADC_ENV      0x00
+#define XREG_QUALITY      0x01
+#define XREG_FRAME_LINES  0x02
+#define XREG_HSYNC_FREQ   0x03
+#define XREG_LOCK         0x04
+#define XREG_FREQ_ERROR   0x05
+#define XREG_SNR          0x06
+#define XREG_VERSION      0x07
+#define XREG_PRODUCT_ID   0x08
+
+/*
+   Basic firmware description. This will remain with
+   the driver for documentation purposes.
+
+   This represents an I2C firmware file encoded as a
+   string of unsigned char. Format is as follows:
+
+   char[0  ]=len0_MSB  -> len = len_MSB * 256 + len_LSB
+   char[1  ]=len0_LSB  -> length of first write transaction
+   char[2  ]=data0 -> first byte to be sent
+   char[3  ]=data1
+   char[4  ]=data2
+   char[   ]=...
+   char[M  ]=dataN  -> last byte to be sent
+   char[M+1]=len1_MSB  -> len = len_MSB * 256 + len_LSB
+   char[M+2]=len1_LSB  -> length of second write transaction
+   char[M+3]=data0
+   char[M+4]=data1
+   ...
+   etc.
+
+   The [len] value should be interpreted as follows:
+
+   len= len_MSB _ len_LSB
+   len=1111_1111_1111_1111   : End of I2C_SEQUENCE
+   len=0000_0000_0000_0000   : Reset command: Do hardware reset
+   len=0NNN_NNNN_NNNN_NNNN   : Normal transaction: number of bytes = {1:32767)
+   len=1WWW_WWWW_WWWW_WWWW   : Wait command: wait for {1:32767} ms
+
+   For the RESET and WAIT commands, the two following bytes will contain
+   immediately the length of the following transaction.
+*/
+
+struct XC_TV_STANDARD {
+       const char  *Name;
+       u16         audio_mode;
+       u16         video_mode;
+       u16         int_freq;
+};
+
+/* Tuner standards */
+#define XC4000_MN_NTSC_PAL_BTSC                0
+#define XC4000_MN_NTSC_PAL_A2          1
+#define XC4000_MN_NTSC_PAL_EIAJ                2
+#define XC4000_MN_NTSC_PAL_Mono                3
+#define XC4000_BG_PAL_A2               4
+#define XC4000_BG_PAL_NICAM            5
+#define XC4000_BG_PAL_MONO             6
+#define XC4000_I_PAL_NICAM             7
+#define XC4000_I_PAL_NICAM_MONO                8
+#define XC4000_DK_PAL_A2               9
+#define XC4000_DK_PAL_NICAM            10
+#define XC4000_DK_PAL_MONO             11
+#define XC4000_DK_SECAM_A2DK1          12
+#define XC4000_DK_SECAM_A2LDK3         13
+#define XC4000_DK_SECAM_A2MONO         14
+#define XC4000_DK_SECAM_NICAM          15
+#define XC4000_L_SECAM_NICAM           16
+#define XC4000_LC_SECAM_NICAM          17
+#define XC4000_DTV6                    18
+#define XC4000_DTV8                    19
+#define XC4000_DTV7_8                  20
+#define XC4000_DTV7                    21
+#define XC4000_FM_Radio_INPUT2         22
+#define XC4000_FM_Radio_INPUT1         23
+
+static struct XC_TV_STANDARD xc4000_standard[MAX_TV_STANDARD] = {
+       {"M/N-NTSC/PAL-BTSC",   0x0000, 0x80A0, 4500},
+       {"M/N-NTSC/PAL-A2",     0x0000, 0x80A0, 4600},
+       {"M/N-NTSC/PAL-EIAJ",   0x0040, 0x80A0, 4500},
+       {"M/N-NTSC/PAL-Mono",   0x0078, 0x80A0, 4500},
+       {"B/G-PAL-A2",          0x0000, 0x8159, 5640},
+       {"B/G-PAL-NICAM",       0x0004, 0x8159, 5740},
+       {"B/G-PAL-MONO",        0x0078, 0x8159, 5500},
+       {"I-PAL-NICAM",         0x0080, 0x8049, 6240},
+       {"I-PAL-NICAM-MONO",    0x0078, 0x8049, 6000},
+       {"D/K-PAL-A2",          0x0000, 0x8049, 6380},
+       {"D/K-PAL-NICAM",       0x0080, 0x8049, 6200},
+       {"D/K-PAL-MONO",        0x0078, 0x8049, 6500},
+       {"D/K-SECAM-A2 DK1",    0x0000, 0x8049, 6340},
+       {"D/K-SECAM-A2 L/DK3",  0x0000, 0x8049, 6000},
+       {"D/K-SECAM-A2 MONO",   0x0078, 0x8049, 6500},
+       {"D/K-SECAM-NICAM",     0x0080, 0x8049, 6200},
+       {"L-SECAM-NICAM",       0x8080, 0x0009, 6200},
+       {"L'-SECAM-NICAM",      0x8080, 0x4009, 6200},
+       {"DTV6",                0x00C0, 0x8002,    0},
+       {"DTV8",                0x00C0, 0x800B,    0},
+       {"DTV7/8",              0x00C0, 0x801B,    0},
+       {"DTV7",                0x00C0, 0x8007,    0},
+       {"FM Radio-INPUT2",     0x0008, 0x9800, 10700},
+       {"FM Radio-INPUT1",     0x0008, 0x9000, 10700}
+};
+
+static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val);
+static int xc4000_tuner_reset(struct dvb_frontend *fe);
+static void xc_debug_dump(struct xc4000_priv *priv);
+
+static int xc_send_i2c_data(struct xc4000_priv *priv, u8 *buf, int len)
+{
+       struct i2c_msg msg = { .addr = priv->i2c_props.addr,
+                              .flags = 0, .buf = buf, .len = len };
+       if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
+               if (priv->ignore_i2c_write_errors == 0) {
+                       printk(KERN_ERR "xc4000: I2C write failed (len=%i)\n",
+                              len);
+                       if (len == 4) {
+                               printk(KERN_ERR "bytes %02x %02x %02x %02x\n", buf[0],
+                                      buf[1], buf[2], buf[3]);
+                       }
+                       return -EREMOTEIO;
+               }
+       }
+       return 0;
+}
+
+static int xc4000_tuner_reset(struct dvb_frontend *fe)
+{
+       struct xc4000_priv *priv = fe->tuner_priv;
+       int ret;
+
+       dprintk(1, "%s()\n", __func__);
+
+       if (fe->callback) {
+               ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
+                                          fe->dvb->priv :
+                                          priv->i2c_props.adap->algo_data,
+                                          DVB_FRONTEND_COMPONENT_TUNER,
+                                          XC4000_TUNER_RESET, 0);
+               if (ret) {
+                       printk(KERN_ERR "xc4000: reset failed\n");
+                       return -EREMOTEIO;
+               }
+       } else {
+               printk(KERN_ERR "xc4000: no tuner reset callback function, "
+                               "fatal\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int xc_write_reg(struct xc4000_priv *priv, u16 regAddr, u16 i2cData)
+{
+       u8 buf[4];
+       int result;
+
+       buf[0] = (regAddr >> 8) & 0xFF;
+       buf[1] = regAddr & 0xFF;
+       buf[2] = (i2cData >> 8) & 0xFF;
+       buf[3] = i2cData & 0xFF;
+       result = xc_send_i2c_data(priv, buf, 4);
+
+       return result;
+}
+
+static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
+{
+       struct xc4000_priv *priv = fe->tuner_priv;
+
+       int i, nbytes_to_send, result;
+       unsigned int len, pos, index;
+       u8 buf[XC_MAX_I2C_WRITE_LENGTH];
+
+       index = 0;
+       while ((i2c_sequence[index] != 0xFF) ||
+               (i2c_sequence[index + 1] != 0xFF)) {
+               len = i2c_sequence[index] * 256 + i2c_sequence[index+1];
+               if (len == 0x0000) {
+                       /* RESET command */
+                       /* NOTE: this is ignored, as the reset callback was */
+                       /* already called by check_firmware() */
+                       index += 2;
+               } else if (len & 0x8000) {
+                       /* WAIT command */
+                       msleep(len & 0x7FFF);
+                       index += 2;
+               } else {
+                       /* Send i2c data whilst ensuring individual transactions
+                        * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes.
+                        */
+                       index += 2;
+                       buf[0] = i2c_sequence[index];
+                       buf[1] = i2c_sequence[index + 1];
+                       pos = 2;
+                       while (pos < len) {
+                               if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2)
+                                       nbytes_to_send =
+                                               XC_MAX_I2C_WRITE_LENGTH;
+                               else
+                                       nbytes_to_send = (len - pos + 2);
+                               for (i = 2; i < nbytes_to_send; i++) {
+                                       buf[i] = i2c_sequence[index + pos +
+                                               i - 2];
+                               }
+                               result = xc_send_i2c_data(priv, buf,
+                                       nbytes_to_send);
+
+                               if (result != 0)
+                                       return result;
+
+                               pos += nbytes_to_send - 2;
+                       }
+                       index += len;
+               }
+       }
+       return 0;
+}
+
+static int xc_set_tv_standard(struct xc4000_priv *priv,
+       u16 video_mode, u16 audio_mode)
+{
+       int ret;
+       dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, video_mode, audio_mode);
+       dprintk(1, "%s() Standard = %s\n",
+               __func__,
+               xc4000_standard[priv->video_standard].Name);
+
+       /* Don't complain when the request fails because of i2c stretching */
+       priv->ignore_i2c_write_errors = 1;
+
+       ret = xc_write_reg(priv, XREG_VIDEO_MODE, video_mode);
+       if (ret == 0)
+               ret = xc_write_reg(priv, XREG_AUDIO_MODE, audio_mode);
+
+       priv->ignore_i2c_write_errors = 0;
+
+       return ret;
+}
+
+static int xc_set_signal_source(struct xc4000_priv *priv, u16 rf_mode)
+{
+       dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode,
+               rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE");
+
+       if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) {
+               rf_mode = XC_RF_MODE_CABLE;
+               printk(KERN_ERR
+                       "%s(), Invalid mode, defaulting to CABLE",
+                       __func__);
+       }
+       return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode);
+}
+
+static const struct dvb_tuner_ops xc4000_tuner_ops;
+
+static int xc_set_rf_frequency(struct xc4000_priv *priv, u32 freq_hz)
+{
+       u16 freq_code;
+
+       dprintk(1, "%s(%u)\n", __func__, freq_hz);
+
+       if ((freq_hz > xc4000_tuner_ops.info.frequency_max) ||
+           (freq_hz < xc4000_tuner_ops.info.frequency_min))
+               return -EINVAL;
+
+       freq_code = (u16)(freq_hz / 15625);
+
+       /* WAS: Starting in firmware version 1.1.44, Xceive recommends using the
+          FINERFREQ for all normal tuning (the doc indicates reg 0x03 should
+          only be used for fast scanning for channel lock) */
+       /* WAS: XREG_FINERFREQ */
+       return xc_write_reg(priv, XREG_RF_FREQ, freq_code);
+}
+
+static int xc_get_adc_envelope(struct xc4000_priv *priv, u16 *adc_envelope)
+{
+       return xc4000_readreg(priv, XREG_ADC_ENV, adc_envelope);
+}
+
+static int xc_get_frequency_error(struct xc4000_priv *priv, u32 *freq_error_hz)
+{
+       int result;
+       u16 regData;
+       u32 tmp;
+
+       result = xc4000_readreg(priv, XREG_FREQ_ERROR, &regData);
+       if (result != 0)
+               return result;
+
+       tmp = (u32)regData & 0xFFFFU;
+       tmp = (tmp < 0x8000U ? tmp : 0x10000U - tmp);
+       (*freq_error_hz) = tmp * 15625;
+       return result;
+}
+
+static int xc_get_lock_status(struct xc4000_priv *priv, u16 *lock_status)
+{
+       return xc4000_readreg(priv, XREG_LOCK, lock_status);
+}
+
+static int xc_get_version(struct xc4000_priv *priv,
+       u8 *hw_majorversion, u8 *hw_minorversion,
+       u8 *fw_majorversion, u8 *fw_minorversion)
+{
+       u16 data;
+       int result;
+
+       result = xc4000_readreg(priv, XREG_VERSION, &data);
+       if (result != 0)
+               return result;
+
+       (*hw_majorversion) = (data >> 12) & 0x0F;
+       (*hw_minorversion) = (data >>  8) & 0x0F;
+       (*fw_majorversion) = (data >>  4) & 0x0F;
+       (*fw_minorversion) = data & 0x0F;
+
+       return 0;
+}
+
+static int xc_get_hsync_freq(struct xc4000_priv *priv, u32 *hsync_freq_hz)
+{
+       u16 regData;
+       int result;
+
+       result = xc4000_readreg(priv, XREG_HSYNC_FREQ, &regData);
+       if (result != 0)
+               return result;
+
+       (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100;
+       return result;
+}
+
+static int xc_get_frame_lines(struct xc4000_priv *priv, u16 *frame_lines)
+{
+       return xc4000_readreg(priv, XREG_FRAME_LINES, frame_lines);
+}
+
+static int xc_get_quality(struct xc4000_priv *priv, u16 *quality)
+{
+       return xc4000_readreg(priv, XREG_QUALITY, quality);
+}
+
+static u16 xc_wait_for_lock(struct xc4000_priv *priv)
+{
+       u16     lock_state = 0;
+       int     watchdog_count = 40;
+
+       while ((lock_state == 0) && (watchdog_count > 0)) {
+               xc_get_lock_status(priv, &lock_state);
+               if (lock_state != 1) {
+                       msleep(5);
+                       watchdog_count--;
+               }
+       }
+       return lock_state;
+}
+
+static int xc_tune_channel(struct xc4000_priv *priv, u32 freq_hz)
+{
+       int     found = 1;
+       int     result;
+
+       dprintk(1, "%s(%u)\n", __func__, freq_hz);
+
+       /* Don't complain when the request fails because of i2c stretching */
+       priv->ignore_i2c_write_errors = 1;
+       result = xc_set_rf_frequency(priv, freq_hz);
+       priv->ignore_i2c_write_errors = 0;
+
+       if (result != 0)
+               return 0;
+
+       /* wait for lock only in analog TV mode */
+       if ((priv->cur_fw.type & (FM | DTV6 | DTV7 | DTV78 | DTV8)) == 0) {
+               if (xc_wait_for_lock(priv) != 1)
+                       found = 0;
+       }
+
+       /* Wait for stats to stabilize.
+        * Frame Lines needs two frame times after initial lock
+        * before it is valid.
+        */
+       msleep(debug ? 100 : 10);
+
+       if (debug)
+               xc_debug_dump(priv);
+
+       return found;
+}
+
+static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val)
+{
+       u8 buf[2] = { reg >> 8, reg & 0xff };
+       u8 bval[2] = { 0, 0 };
+       struct i2c_msg msg[2] = {
+               { .addr = priv->i2c_props.addr,
+                       .flags = 0, .buf = &buf[0], .len = 2 },
+               { .addr = priv->i2c_props.addr,
+                       .flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
+       };
+
+       if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
+               printk(KERN_ERR "xc4000: I2C read failed\n");
+               return -EREMOTEIO;
+       }
+
+       *val = (bval[0] << 8) | bval[1];
+       return 0;
+}
+
+#define dump_firm_type(t)      dump_firm_type_and_int_freq(t, 0)
+static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
+{
+        if (type & BASE)
+               printk(KERN_CONT "BASE ");
+        if (type & INIT1)
+               printk(KERN_CONT "INIT1 ");
+        if (type & F8MHZ)
+               printk(KERN_CONT "F8MHZ ");
+        if (type & MTS)
+               printk(KERN_CONT "MTS ");
+        if (type & D2620)
+               printk(KERN_CONT "D2620 ");
+        if (type & D2633)
+               printk(KERN_CONT "D2633 ");
+        if (type & DTV6)
+               printk(KERN_CONT "DTV6 ");
+        if (type & QAM)
+               printk(KERN_CONT "QAM ");
+        if (type & DTV7)
+               printk(KERN_CONT "DTV7 ");
+        if (type & DTV78)
+               printk(KERN_CONT "DTV78 ");
+        if (type & DTV8)
+               printk(KERN_CONT "DTV8 ");
+        if (type & FM)
+               printk(KERN_CONT "FM ");
+        if (type & INPUT1)
+               printk(KERN_CONT "INPUT1 ");
+        if (type & LCD)
+               printk(KERN_CONT "LCD ");
+        if (type & NOGD)
+               printk(KERN_CONT "NOGD ");
+        if (type & MONO)
+               printk(KERN_CONT "MONO ");
+        if (type & ATSC)
+               printk(KERN_CONT "ATSC ");
+        if (type & IF)
+               printk(KERN_CONT "IF ");
+        if (type & LG60)
+               printk(KERN_CONT "LG60 ");
+        if (type & ATI638)
+               printk(KERN_CONT "ATI638 ");
+        if (type & OREN538)
+               printk(KERN_CONT "OREN538 ");
+        if (type & OREN36)
+               printk(KERN_CONT "OREN36 ");
+        if (type & TOYOTA388)
+               printk(KERN_CONT "TOYOTA388 ");
+        if (type & TOYOTA794)
+               printk(KERN_CONT "TOYOTA794 ");
+        if (type & DIBCOM52)
+               printk(KERN_CONT "DIBCOM52 ");
+        if (type & ZARLINK456)
+               printk(KERN_CONT "ZARLINK456 ");
+        if (type & CHINA)
+               printk(KERN_CONT "CHINA ");
+        if (type & F6MHZ)
+               printk(KERN_CONT "F6MHZ ");
+        if (type & INPUT2)
+               printk(KERN_CONT "INPUT2 ");
+        if (type & SCODE)
+               printk(KERN_CONT "SCODE ");
+        if (type & HAS_IF)
+               printk(KERN_CONT "HAS_IF_%d ", int_freq);
+}
+
+static int seek_firmware(struct dvb_frontend *fe, unsigned int type,
+                        v4l2_std_id *id)
+{
+       struct xc4000_priv *priv = fe->tuner_priv;
+       int             i, best_i = -1;
+       unsigned int    best_nr_diffs = 255U;
+
+       if (!priv->firm) {
+               printk(KERN_ERR "Error! firmware not loaded\n");
+               return -EINVAL;
+       }
+
+       if (((type & ~SCODE) == 0) && (*id == 0))
+               *id = V4L2_STD_PAL;
+
+       /* Seek for generic video standard match */
+       for (i = 0; i < priv->firm_size; i++) {
+               v4l2_std_id     id_diff_mask =
+                       (priv->firm[i].id ^ (*id)) & (*id);
+               unsigned int    type_diff_mask =
+                       (priv->firm[i].type ^ type)
+                       & (BASE_TYPES | DTV_TYPES | LCD | NOGD | MONO | SCODE);
+               unsigned int    nr_diffs;
+
+               if (type_diff_mask
+                   & (BASE | INIT1 | FM | DTV6 | DTV7 | DTV78 | DTV8 | SCODE))
+                       continue;
+
+               nr_diffs = hweight64(id_diff_mask) + hweight32(type_diff_mask);
+               if (!nr_diffs)  /* Supports all the requested standards */
+                       goto found;
+
+               if (nr_diffs < best_nr_diffs) {
+                       best_nr_diffs = nr_diffs;
+                       best_i = i;
+               }
+       }
+
+       /* FIXME: Would make sense to seek for type "hint" match ? */
+       if (best_i < 0) {
+               i = -ENOENT;
+               goto ret;
+       }
+
+       if (best_nr_diffs > 0U) {
+               printk(KERN_WARNING
+                      "Selecting best matching firmware (%u bits differ) for "
+                      "type=(%x), id %016llx:\n",
+                      best_nr_diffs, type, (unsigned long long)*id);
+               i = best_i;
+       }
+
+found:
+       *id = priv->firm[i].id;
+
+ret:
+       if (debug) {
+               printk(KERN_DEBUG "%s firmware for type=",
+                      (i < 0) ? "Can't find" : "Found");
+               dump_firm_type(type);
+               printk(KERN_DEBUG "(%x), id %016llx.\n", type, (unsigned long long)*id);
+       }
+       return i;
+}
+
+static int load_firmware(struct dvb_frontend *fe, unsigned int type,
+                        v4l2_std_id *id)
+{
+       struct xc4000_priv *priv = fe->tuner_priv;
+       int                pos, rc;
+       unsigned char      *p;
+
+       pos = seek_firmware(fe, type, id);
+       if (pos < 0)
+               return pos;
+
+       p = priv->firm[pos].ptr;
+
+       /* Don't complain when the request fails because of i2c stretching */
+       priv->ignore_i2c_write_errors = 1;
+
+       rc = xc_load_i2c_sequence(fe, p);
+
+       priv->ignore_i2c_write_errors = 0;
+
+       return rc;
+}
+
+static int xc4000_fwupload(struct dvb_frontend *fe)
+{
+       struct xc4000_priv *priv = fe->tuner_priv;
+       const struct firmware *fw   = NULL;
+       const unsigned char   *p, *endp;
+       int                   rc = 0;
+       int                   n, n_array;
+       char                  name[33];
+       const char            *fname;
+
+       if (firmware_name[0] != '\0')
+               fname = firmware_name;
+       else
+               fname = XC4000_DEFAULT_FIRMWARE;
+
+       dprintk(1, "Reading firmware %s\n", fname);
+       rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent);
+       if (rc < 0) {
+               if (rc == -ENOENT)
+                       printk(KERN_ERR "Error: firmware %s not found.\n", fname);
+               else
+                       printk(KERN_ERR "Error %d while requesting firmware %s\n",
+                              rc, fname);
+
+               return rc;
+       }
+       p = fw->data;
+       endp = p + fw->size;
+
+       if (fw->size < sizeof(name) - 1 + 2 + 2) {
+               printk(KERN_ERR "Error: firmware file %s has invalid size!\n",
+                      fname);
+               goto corrupt;
+       }
+
+       memcpy(name, p, sizeof(name) - 1);
+       name[sizeof(name) - 1] = '\0';
+       p += sizeof(name) - 1;
+
+       priv->firm_version = get_unaligned_le16(p);
+       p += 2;
+
+       n_array = get_unaligned_le16(p);
+       p += 2;
+
+       dprintk(1, "Loading %d firmware images from %s, type: %s, ver %d.%d\n",
+               n_array, fname, name,
+               priv->firm_version >> 8, priv->firm_version & 0xff);
+
+       priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL);
+       if (priv->firm == NULL) {
+               printk(KERN_ERR "Not enough memory to load firmware file.\n");
+               rc = -ENOMEM;
+               goto done;
+       }
+       priv->firm_size = n_array;
+
+       n = -1;
+       while (p < endp) {
+               __u32 type, size;
+               v4l2_std_id id;
+               __u16 int_freq = 0;
+
+               n++;
+               if (n >= n_array) {
+                       printk(KERN_ERR "More firmware images in file than "
+                              "were expected!\n");
+                       goto corrupt;
+               }
+
+               /* Checks if there's enough bytes to read */
+               if (endp - p < sizeof(type) + sizeof(id) + sizeof(size))
+                       goto header;
+
+               type = get_unaligned_le32(p);
+               p += sizeof(type);
+
+               id = get_unaligned_le64(p);
+               p += sizeof(id);
+
+               if (type & HAS_IF) {
+                       int_freq = get_unaligned_le16(p);
+                       p += sizeof(int_freq);
+                       if (endp - p < sizeof(size))
+                               goto header;
+               }
+
+               size = get_unaligned_le32(p);
+               p += sizeof(size);
+
+               if (!size || size > endp - p) {
+                       printk(KERN_ERR "Firmware type (%x), id %llx is corrupted (size=%d, expected %d)\n",
+                              type, (unsigned long long)id,
+                              (unsigned)(endp - p), size);
+                       goto corrupt;
+               }
+
+               priv->firm[n].ptr = kzalloc(size, GFP_KERNEL);
+               if (priv->firm[n].ptr == NULL) {
+                       printk(KERN_ERR "Not enough memory to load firmware file.\n");
+                       rc = -ENOMEM;
+                       goto done;
+               }
+
+               if (debug) {
+                       printk(KERN_DEBUG "Reading firmware type ");
+                       dump_firm_type_and_int_freq(type, int_freq);
+                       printk(KERN_DEBUG "(%x), id %llx, size=%d.\n",
+                              type, (unsigned long long)id, size);
+               }
+
+               memcpy(priv->firm[n].ptr, p, size);
+               priv->firm[n].type = type;
+               priv->firm[n].id   = id;
+               priv->firm[n].size = size;
+               priv->firm[n].int_freq = int_freq;
+
+               p += size;
+       }
+
+       if (n + 1 != priv->firm_size) {
+               printk(KERN_ERR "Firmware file is incomplete!\n");
+               goto corrupt;
+       }
+
+       goto done;
+
+header:
+       printk(KERN_ERR "Firmware header is incomplete!\n");
+corrupt:
+       rc = -EINVAL;
+       printk(KERN_ERR "Error: firmware file is corrupted!\n");
+
+done:
+       release_firmware(fw);
+       if (rc == 0)
+               dprintk(1, "Firmware files loaded.\n");
+
+       return rc;
+}
+
+static int load_scode(struct dvb_frontend *fe, unsigned int type,
+                        v4l2_std_id *id, __u16 int_freq, int scode)
+{
+       struct xc4000_priv *priv = fe->tuner_priv;
+       int             pos, rc;
+       unsigned char   *p;
+       u8              scode_buf[13];
+       u8              indirect_mode[5];
+
+       dprintk(1, "%s called int_freq=%d\n", __func__, int_freq);
+
+       if (!int_freq) {
+               pos = seek_firmware(fe, type, id);
+               if (pos < 0)
+                       return pos;
+       } else {
+               for (pos = 0; pos < priv->firm_size; pos++) {
+                       if ((priv->firm[pos].int_freq == int_freq) &&
+                           (priv->firm[pos].type & HAS_IF))
+                               break;
+               }
+               if (pos == priv->firm_size)
+                       return -ENOENT;
+       }
+
+       p = priv->firm[pos].ptr;
+
+       if (priv->firm[pos].size != 12 * 16 || scode >= 16)
+               return -EINVAL;
+       p += 12 * scode;
+
+       if (debug) {
+               tuner_info("Loading SCODE for type=");
+               dump_firm_type_and_int_freq(priv->firm[pos].type,
+                                           priv->firm[pos].int_freq);
+               printk(KERN_CONT "(%x), id %016llx.\n", priv->firm[pos].type,
+                      (unsigned long long)*id);
+       }
+
+       scode_buf[0] = 0x00;
+       memcpy(&scode_buf[1], p, 12);
+
+       /* Enter direct-mode */
+       rc = xc_write_reg(priv, XREG_DIRECTSITTING_MODE, 0);
+       if (rc < 0) {
+               printk(KERN_ERR "failed to put device into direct mode!\n");
+               return -EIO;
+       }
+
+       rc = xc_send_i2c_data(priv, scode_buf, 13);
+       if (rc != 0) {
+               /* Even if the send failed, make sure we set back to indirect
+                  mode */
+               printk(KERN_ERR "Failed to set scode %d\n", rc);
+       }
+
+       /* Switch back to indirect-mode */
+       memset(indirect_mode, 0, sizeof(indirect_mode));
+       indirect_mode[4] = 0x88;
+       xc_send_i2c_data(priv, indirect_mode, sizeof(indirect_mode));
+       msleep(10);
+
+       return 0;
+}
+
+static int check_firmware(struct dvb_frontend *fe, unsigned int type,
+                         v4l2_std_id std, __u16 int_freq)
+{
+       struct xc4000_priv         *priv = fe->tuner_priv;
+       struct firmware_properties new_fw;
+       int                        rc = 0, is_retry = 0;
+       u16                        hwmodel;
+       v4l2_std_id                std0;
+       u8                         hw_major, hw_minor, fw_major, fw_minor;
+
+       dprintk(1, "%s called\n", __func__);
+
+       if (!priv->firm) {
+               rc = xc4000_fwupload(fe);
+               if (rc < 0)
+                       return rc;
+       }
+
+retry:
+       new_fw.type = type;
+       new_fw.id = std;
+       new_fw.std_req = std;
+       new_fw.scode_table = SCODE;
+       new_fw.scode_nr = 0;
+       new_fw.int_freq = int_freq;
+
+       dprintk(1, "checking firmware, user requested type=");
+       if (debug) {
+               dump_firm_type(new_fw.type);
+               printk(KERN_CONT "(%x), id %016llx, ", new_fw.type,
+                      (unsigned long long)new_fw.std_req);
+               if (!int_freq)
+                       printk(KERN_CONT "scode_tbl ");
+               else
+                       printk(KERN_CONT "int_freq %d, ", new_fw.int_freq);
+               printk(KERN_CONT "scode_nr %d\n", new_fw.scode_nr);
+       }
+
+       /* No need to reload base firmware if it matches */
+       if (priv->cur_fw.type & BASE) {
+               dprintk(1, "BASE firmware not changed.\n");
+               goto skip_base;
+       }
+
+       /* Updating BASE - forget about all currently loaded firmware */
+       memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
+
+       /* Reset is needed before loading firmware */
+       rc = xc4000_tuner_reset(fe);
+       if (rc < 0)
+               goto fail;
+
+       /* BASE firmwares are all std0 */
+       std0 = 0;
+       rc = load_firmware(fe, BASE, &std0);
+       if (rc < 0) {
+               printk(KERN_ERR "Error %d while loading base firmware\n", rc);
+               goto fail;
+       }
+
+       /* Load INIT1, if needed */
+       dprintk(1, "Load init1 firmware, if exists\n");
+
+       rc = load_firmware(fe, BASE | INIT1, &std0);
+       if (rc == -ENOENT)
+               rc = load_firmware(fe, BASE | INIT1, &std0);
+       if (rc < 0 && rc != -ENOENT) {
+               tuner_err("Error %d while loading init1 firmware\n",
+                         rc);
+               goto fail;
+       }
+
+skip_base:
+       /*
+        * No need to reload standard specific firmware if base firmware
+        * was not reloaded and requested video standards have not changed.
+        */
+       if (priv->cur_fw.type == (BASE | new_fw.type) &&
+           priv->cur_fw.std_req == std) {
+               dprintk(1, "Std-specific firmware already loaded.\n");
+               goto skip_std_specific;
+       }
+
+       /* Reloading std-specific firmware forces a SCODE update */
+       priv->cur_fw.scode_table = 0;
+
+       /* Load the standard firmware */
+       rc = load_firmware(fe, new_fw.type, &new_fw.id);
+
+       if (rc < 0)
+               goto fail;
+
+skip_std_specific:
+       if (priv->cur_fw.scode_table == new_fw.scode_table &&
+           priv->cur_fw.scode_nr == new_fw.scode_nr) {
+               dprintk(1, "SCODE firmware already loaded.\n");
+               goto check_device;
+       }
+
+       /* Load SCODE firmware, if exists */
+       rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id,
+                       new_fw.int_freq, new_fw.scode_nr);
+       if (rc != 0)
+               dprintk(1, "load scode failed %d\n", rc);
+
+check_device:
+       rc = xc4000_readreg(priv, XREG_PRODUCT_ID, &hwmodel);
+
+       if (xc_get_version(priv, &hw_major, &hw_minor, &fw_major,
+                          &fw_minor) != 0) {
+               printk(KERN_ERR "Unable to read tuner registers.\n");
+               goto fail;
+       }
+
+       dprintk(1, "Device is Xceive %d version %d.%d, "
+               "firmware version %d.%d\n",
+               hwmodel, hw_major, hw_minor, fw_major, fw_minor);
+
+       /* Check firmware version against what we downloaded. */
+       if (priv->firm_version != ((fw_major << 8) | fw_minor)) {
+               printk(KERN_WARNING
+                      "Incorrect readback of firmware version %d.%d.\n",
+                      fw_major, fw_minor);
+               goto fail;
+       }
+
+       /* Check that the tuner hardware model remains consistent over time. */
+       if (priv->hwmodel == 0 &&
+           (hwmodel == XC_PRODUCT_ID_XC4000 ||
+            hwmodel == XC_PRODUCT_ID_XC4100)) {
+               priv->hwmodel = hwmodel;
+               priv->hwvers = (hw_major << 8) | hw_minor;
+       } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel ||
+                  priv->hwvers != ((hw_major << 8) | hw_minor)) {
+               printk(KERN_WARNING
+                      "Read invalid device hardware information - tuner "
+                      "hung?\n");
+               goto fail;
+       }
+
+       memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw));
+
+       /*
+        * By setting BASE in cur_fw.type only after successfully loading all
+        * firmwares, we can:
+        * 1. Identify that BASE firmware with type=0 has been loaded;
+        * 2. Tell whether BASE firmware was just changed the next time through.
+        */
+       priv->cur_fw.type |= BASE;
+
+       return 0;
+
+fail:
+       memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
+       if (!is_retry) {
+               msleep(50);
+               is_retry = 1;
+               dprintk(1, "Retrying firmware load\n");
+               goto retry;
+       }
+
+       if (rc == -ENOENT)
+               rc = -EINVAL;
+       return rc;
+}
+
+static void xc_debug_dump(struct xc4000_priv *priv)
+{
+       u16     adc_envelope;
+       u32     freq_error_hz = 0;
+       u16     lock_status;
+       u32     hsync_freq_hz = 0;
+       u16     frame_lines;
+       u16     quality;
+       u8      hw_majorversion = 0, hw_minorversion = 0;
+       u8      fw_majorversion = 0, fw_minorversion = 0;
+
+       xc_get_adc_envelope(priv, &adc_envelope);
+       dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope);
+
+       xc_get_frequency_error(priv, &freq_error_hz);
+       dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz);
+
+       xc_get_lock_status(priv, &lock_status);
+       dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n",
+               lock_status);
+
+       xc_get_version(priv, &hw_majorversion, &hw_minorversion,
+                      &fw_majorversion, &fw_minorversion);
+       dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n",
+               hw_majorversion, hw_minorversion,
+               fw_majorversion, fw_minorversion);
+
+       if (priv->video_standard < XC4000_DTV6) {
+               xc_get_hsync_freq(priv, &hsync_freq_hz);
+               dprintk(1, "*** Horizontal sync frequency = %d Hz\n",
+                       hsync_freq_hz);
+
+               xc_get_frame_lines(priv, &frame_lines);
+               dprintk(1, "*** Frame lines = %d\n", frame_lines);
+       }
+
+       xc_get_quality(priv, &quality);
+       dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality);
+}
+
+static int xc4000_set_params(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *params)
+{
+       struct xc4000_priv *priv = fe->tuner_priv;
+       unsigned int type;
+       int     ret = -EREMOTEIO;
+
+       dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency);
+
+       mutex_lock(&priv->lock);
+
+       if (fe->ops.info.type == FE_ATSC) {
+               dprintk(1, "%s() ATSC\n", __func__);
+               switch (params->u.vsb.modulation) {
+               case VSB_8:
+               case VSB_16:
+                       dprintk(1, "%s() VSB modulation\n", __func__);
+                       priv->rf_mode = XC_RF_MODE_AIR;
+                       priv->freq_hz = params->frequency - 1750000;
+                       priv->bandwidth = BANDWIDTH_6_MHZ;
+                       priv->video_standard = XC4000_DTV6;
+                       type = DTV6;
+                       break;
+               case QAM_64:
+               case QAM_256:
+               case QAM_AUTO:
+                       dprintk(1, "%s() QAM modulation\n", __func__);
+                       priv->rf_mode = XC_RF_MODE_CABLE;
+                       priv->freq_hz = params->frequency - 1750000;
+                       priv->bandwidth = BANDWIDTH_6_MHZ;
+                       priv->video_standard = XC4000_DTV6;
+                       type = DTV6;
+                       break;
+               default:
+                       ret = -EINVAL;
+                       goto fail;
+               }
+       } else if (fe->ops.info.type == FE_OFDM) {
+               dprintk(1, "%s() OFDM\n", __func__);
+               switch (params->u.ofdm.bandwidth) {
+               case BANDWIDTH_6_MHZ:
+                       priv->bandwidth = BANDWIDTH_6_MHZ;
+                       priv->video_standard = XC4000_DTV6;
+                       priv->freq_hz = params->frequency - 1750000;
+                       type = DTV6;
+                       break;
+               case BANDWIDTH_7_MHZ:
+                       priv->bandwidth = BANDWIDTH_7_MHZ;
+                       priv->video_standard = XC4000_DTV7;
+                       priv->freq_hz = params->frequency - 2250000;
+                       type = DTV7;
+                       break;
+               case BANDWIDTH_8_MHZ:
+                       priv->bandwidth = BANDWIDTH_8_MHZ;
+                       priv->video_standard = XC4000_DTV8;
+                       priv->freq_hz = params->frequency - 2750000;
+                       type = DTV8;
+                       break;
+               case BANDWIDTH_AUTO:
+                       if (params->frequency < 400000000) {
+                               priv->bandwidth = BANDWIDTH_7_MHZ;
+                               priv->freq_hz = params->frequency - 2250000;
+                       } else {
+                               priv->bandwidth = BANDWIDTH_8_MHZ;
+                               priv->freq_hz = params->frequency - 2750000;
+                       }
+                       priv->video_standard = XC4000_DTV7_8;
+                       type = DTV78;
+                       break;
+               default:
+                       printk(KERN_ERR "xc4000 bandwidth not set!\n");
+                       ret = -EINVAL;
+                       goto fail;
+               }
+               priv->rf_mode = XC_RF_MODE_AIR;
+       } else {
+               printk(KERN_ERR "xc4000 modulation type not supported!\n");
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       dprintk(1, "%s() frequency=%d (compensated)\n",
+               __func__, priv->freq_hz);
+
+       /* Make sure the correct firmware type is loaded */
+       if (check_firmware(fe, type, 0, priv->if_khz) != 0)
+               goto fail;
+
+       ret = xc_set_signal_source(priv, priv->rf_mode);
+       if (ret != 0) {
+               printk(KERN_ERR "xc4000: xc_set_signal_source(%d) failed\n",
+                      priv->rf_mode);
+               goto fail;
+       } else {
+               u16     video_mode, audio_mode;
+               video_mode = xc4000_standard[priv->video_standard].video_mode;
+               audio_mode = xc4000_standard[priv->video_standard].audio_mode;
+               if (type == DTV6 && priv->firm_version != 0x0102)
+                       video_mode |= 0x0001;
+               ret = xc_set_tv_standard(priv, video_mode, audio_mode);
+               if (ret != 0) {
+                       printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n");
+                       /* DJH - do not return when it fails... */
+                       /* goto fail; */
+               }
+       }
+
+       if (xc_write_reg(priv, XREG_D_CODE, 0) == 0)
+               ret = 0;
+       if (priv->dvb_amplitude != 0) {
+               if (xc_write_reg(priv, XREG_AMPLITUDE,
+                                (priv->firm_version != 0x0102 ||
+                                 priv->dvb_amplitude != 134 ?
+                                 priv->dvb_amplitude : 132)) != 0)
+                       ret = -EREMOTEIO;
+       }
+       if (priv->set_smoothedcvbs != 0) {
+               if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0)
+                       ret = -EREMOTEIO;
+       }
+       if (ret != 0) {
+               printk(KERN_ERR "xc4000: setting registers failed\n");
+               /* goto fail; */
+       }
+
+       xc_tune_channel(priv, priv->freq_hz);
+
+       ret = 0;
+
+fail:
+       mutex_unlock(&priv->lock);
+
+       return ret;
+}
+
+static int xc4000_set_analog_params(struct dvb_frontend *fe,
+       struct analog_parameters *params)
+{
+       struct xc4000_priv *priv = fe->tuner_priv;
+       unsigned int type = 0;
+       int     ret = -EREMOTEIO;
+
+       if (params->mode == V4L2_TUNER_RADIO) {
+               dprintk(1, "%s() frequency=%d (in units of 62.5Hz)\n",
+                       __func__, params->frequency);
+
+               mutex_lock(&priv->lock);
+
+               params->std = 0;
+               priv->freq_hz = params->frequency * 125L / 2;
+
+               if (audio_std & XC4000_AUDIO_STD_INPUT1) {
+                       priv->video_standard = XC4000_FM_Radio_INPUT1;
+                       type = FM | INPUT1;
+               } else {
+                       priv->video_standard = XC4000_FM_Radio_INPUT2;
+                       type = FM | INPUT2;
+               }
+
+               goto tune_channel;
+       }
+
+       dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
+               __func__, params->frequency);
+
+       mutex_lock(&priv->lock);
+
+       /* params->frequency is in units of 62.5khz */
+       priv->freq_hz = params->frequency * 62500;
+
+       params->std &= V4L2_STD_ALL;
+       /* if std is not defined, choose one */
+       if (!params->std)
+               params->std = V4L2_STD_PAL_BG;
+
+       if (audio_std & XC4000_AUDIO_STD_MONO)
+               type = MONO;
+
+       if (params->std & V4L2_STD_MN) {
+               params->std = V4L2_STD_MN;
+               if (audio_std & XC4000_AUDIO_STD_MONO) {
+                       priv->video_standard = XC4000_MN_NTSC_PAL_Mono;
+               } else if (audio_std & XC4000_AUDIO_STD_A2) {
+                       params->std |= V4L2_STD_A2;
+                       priv->video_standard = XC4000_MN_NTSC_PAL_A2;
+               } else {
+                       params->std |= V4L2_STD_BTSC;
+                       priv->video_standard = XC4000_MN_NTSC_PAL_BTSC;
+               }
+               goto tune_channel;
+       }
+
+       if (params->std & V4L2_STD_PAL_BG) {
+               params->std = V4L2_STD_PAL_BG;
+               if (audio_std & XC4000_AUDIO_STD_MONO) {
+                       priv->video_standard = XC4000_BG_PAL_MONO;
+               } else if (!(audio_std & XC4000_AUDIO_STD_A2)) {
+                       if (!(audio_std & XC4000_AUDIO_STD_B)) {
+                               params->std |= V4L2_STD_NICAM_A;
+                               priv->video_standard = XC4000_BG_PAL_NICAM;
+                       } else {
+                               params->std |= V4L2_STD_NICAM_B;
+                               priv->video_standard = XC4000_BG_PAL_NICAM;
+                       }
+               } else {
+                       if (!(audio_std & XC4000_AUDIO_STD_B)) {
+                               params->std |= V4L2_STD_A2_A;
+                               priv->video_standard = XC4000_BG_PAL_A2;
+                       } else {
+                               params->std |= V4L2_STD_A2_B;
+                               priv->video_standard = XC4000_BG_PAL_A2;
+                       }
+               }
+               goto tune_channel;
+       }
+
+       if (params->std & V4L2_STD_PAL_I) {
+               /* default to NICAM audio standard */
+               params->std = V4L2_STD_PAL_I | V4L2_STD_NICAM;
+               if (audio_std & XC4000_AUDIO_STD_MONO)
+                       priv->video_standard = XC4000_I_PAL_NICAM_MONO;
+               else
+                       priv->video_standard = XC4000_I_PAL_NICAM;
+               goto tune_channel;
+       }
+
+       if (params->std & V4L2_STD_PAL_DK) {
+               params->std = V4L2_STD_PAL_DK;
+               if (audio_std & XC4000_AUDIO_STD_MONO) {
+                       priv->video_standard = XC4000_DK_PAL_MONO;
+               } else if (audio_std & XC4000_AUDIO_STD_A2) {
+                       params->std |= V4L2_STD_A2;
+                       priv->video_standard = XC4000_DK_PAL_A2;
+               } else {
+                       params->std |= V4L2_STD_NICAM;
+                       priv->video_standard = XC4000_DK_PAL_NICAM;
+               }
+               goto tune_channel;
+       }
+
+       if (params->std & V4L2_STD_SECAM_DK) {
+               /* default to A2 audio standard */
+               params->std = V4L2_STD_SECAM_DK | V4L2_STD_A2;
+               if (audio_std & XC4000_AUDIO_STD_L) {
+                       type = 0;
+                       priv->video_standard = XC4000_DK_SECAM_NICAM;
+               } else if (audio_std & XC4000_AUDIO_STD_MONO) {
+                       priv->video_standard = XC4000_DK_SECAM_A2MONO;
+               } else if (audio_std & XC4000_AUDIO_STD_K3) {
+                       params->std |= V4L2_STD_SECAM_K3;
+                       priv->video_standard = XC4000_DK_SECAM_A2LDK3;
+               } else {
+                       priv->video_standard = XC4000_DK_SECAM_A2DK1;
+               }
+               goto tune_channel;
+       }
+
+       if (params->std & V4L2_STD_SECAM_L) {
+               /* default to NICAM audio standard */
+               type = 0;
+               params->std = V4L2_STD_SECAM_L | V4L2_STD_NICAM;
+               priv->video_standard = XC4000_L_SECAM_NICAM;
+               goto tune_channel;
+       }
+
+       if (params->std & V4L2_STD_SECAM_LC) {
+               /* default to NICAM audio standard */
+               type = 0;
+               params->std = V4L2_STD_SECAM_LC | V4L2_STD_NICAM;
+               priv->video_standard = XC4000_LC_SECAM_NICAM;
+               goto tune_channel;
+       }
+
+tune_channel:
+       /* FIXME: it could be air. */
+       priv->rf_mode = XC_RF_MODE_CABLE;
+
+       if (check_firmware(fe, type, params->std,
+                          xc4000_standard[priv->video_standard].int_freq) != 0)
+               goto fail;
+
+       ret = xc_set_signal_source(priv, priv->rf_mode);
+       if (ret != 0) {
+               printk(KERN_ERR
+                      "xc4000: xc_set_signal_source(%d) failed\n",
+                      priv->rf_mode);
+               goto fail;
+       } else {
+               u16     video_mode, audio_mode;
+               video_mode = xc4000_standard[priv->video_standard].video_mode;
+               audio_mode = xc4000_standard[priv->video_standard].audio_mode;
+               if (priv->video_standard < XC4000_BG_PAL_A2) {
+                       if (type & NOGD)
+                               video_mode &= 0xFF7F;
+               } else if (priv->video_standard < XC4000_I_PAL_NICAM) {
+                       if (priv->firm_version == 0x0102)
+                               video_mode &= 0xFEFF;
+                       if (audio_std & XC4000_AUDIO_STD_B)
+                               video_mode |= 0x0080;
+               }
+               ret = xc_set_tv_standard(priv, video_mode, audio_mode);
+               if (ret != 0) {
+                       printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n");
+                       goto fail;
+               }
+       }
+
+       if (xc_write_reg(priv, XREG_D_CODE, 0) == 0)
+               ret = 0;
+       if (xc_write_reg(priv, XREG_AMPLITUDE, 1) != 0)
+               ret = -EREMOTEIO;
+       if (priv->set_smoothedcvbs != 0) {
+               if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0)
+                       ret = -EREMOTEIO;
+       }
+       if (ret != 0) {
+               printk(KERN_ERR "xc4000: setting registers failed\n");
+               goto fail;
+       }
+
+       xc_tune_channel(priv, priv->freq_hz);
+
+       ret = 0;
+
+fail:
+       mutex_unlock(&priv->lock);
+
+       return ret;
+}
+
+static int xc4000_get_frequency(struct dvb_frontend *fe, u32 *freq)
+{
+       struct xc4000_priv *priv = fe->tuner_priv;
+
+       *freq = priv->freq_hz;
+
+       if (debug) {
+               mutex_lock(&priv->lock);
+               if ((priv->cur_fw.type
+                    & (BASE | FM | DTV6 | DTV7 | DTV78 | DTV8)) == BASE) {
+                       u16     snr = 0;
+                       if (xc4000_readreg(priv, XREG_SNR, &snr) == 0) {
+                               mutex_unlock(&priv->lock);
+                               dprintk(1, "%s() freq = %u, SNR = %d\n",
+                                       __func__, *freq, snr);
+                               return 0;
+                       }
+               }
+               mutex_unlock(&priv->lock);
+       }
+
+       dprintk(1, "%s()\n", __func__);
+
+       return 0;
+}
+
+static int xc4000_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
+{
+       struct xc4000_priv *priv = fe->tuner_priv;
+       dprintk(1, "%s()\n", __func__);
+
+       *bw = priv->bandwidth;
+       return 0;
+}
+
+static int xc4000_get_status(struct dvb_frontend *fe, u32 *status)
+{
+       struct xc4000_priv *priv = fe->tuner_priv;
+       u16     lock_status = 0;
+
+       mutex_lock(&priv->lock);
+
+       if (priv->cur_fw.type & BASE)
+               xc_get_lock_status(priv, &lock_status);
+
+       *status = (lock_status == 1 ?
+                  TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO : 0);
+       if (priv->cur_fw.type & (DTV6 | DTV7 | DTV78 | DTV8))
+               *status &= (~TUNER_STATUS_STEREO);
+
+       mutex_unlock(&priv->lock);
+
+       dprintk(2, "%s() lock_status = %d\n", __func__, lock_status);
+
+       return 0;
+}
+
+static int xc4000_sleep(struct dvb_frontend *fe)
+{
+       struct xc4000_priv *priv = fe->tuner_priv;
+       int     ret = 0;
+
+       dprintk(1, "%s()\n", __func__);
+
+       mutex_lock(&priv->lock);
+
+       /* Avoid firmware reload on slow devices */
+       if ((no_poweroff == 2 ||
+            (no_poweroff == 0 && priv->default_pm != 0)) &&
+           (priv->cur_fw.type & BASE) != 0) {
+               /* force reset and firmware reload */
+               priv->cur_fw.type = XC_POWERED_DOWN;
+
+               if (xc_write_reg(priv, XREG_POWER_DOWN, 0) != 0) {
+                       printk(KERN_ERR
+                              "xc4000: %s() unable to shutdown tuner\n",
+                              __func__);
+                       ret = -EREMOTEIO;
+               }
+               msleep(20);
+       }
+
+       mutex_unlock(&priv->lock);
+
+       return ret;
+}
+
+static int xc4000_init(struct dvb_frontend *fe)
+{
+       dprintk(1, "%s()\n", __func__);
+
+       return 0;
+}
+
+static int xc4000_release(struct dvb_frontend *fe)
+{
+       struct xc4000_priv *priv = fe->tuner_priv;
+
+       dprintk(1, "%s()\n", __func__);
+
+       mutex_lock(&xc4000_list_mutex);
+
+       if (priv)
+               hybrid_tuner_release_state(priv);
+
+       mutex_unlock(&xc4000_list_mutex);
+
+       fe->tuner_priv = NULL;
+
+       return 0;
+}
+
+static const struct dvb_tuner_ops xc4000_tuner_ops = {
+       .info = {
+               .name           = "Xceive XC4000",
+               .frequency_min  =    1000000,
+               .frequency_max  = 1023000000,
+               .frequency_step =      50000,
+       },
+
+       .release           = xc4000_release,
+       .init              = xc4000_init,
+       .sleep             = xc4000_sleep,
+
+       .set_params        = xc4000_set_params,
+       .set_analog_params = xc4000_set_analog_params,
+       .get_frequency     = xc4000_get_frequency,
+       .get_bandwidth     = xc4000_get_bandwidth,
+       .get_status        = xc4000_get_status
+};
+
+struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe,
+                                  struct i2c_adapter *i2c,
+                                  struct xc4000_config *cfg)
+{
+       struct xc4000_priv *priv = NULL;
+       int     instance;
+       u16     id = 0;
+
+       dprintk(1, "%s(%d-%04x)\n", __func__,
+               i2c ? i2c_adapter_id(i2c) : -1,
+               cfg ? cfg->i2c_address : -1);
+
+       mutex_lock(&xc4000_list_mutex);
+
+       instance = hybrid_tuner_request_state(struct xc4000_priv, priv,
+                                             hybrid_tuner_instance_list,
+                                             i2c, cfg->i2c_address, "xc4000");
+       switch (instance) {
+       case 0:
+               goto fail;
+               break;
+       case 1:
+               /* new tuner instance */
+               priv->bandwidth = BANDWIDTH_6_MHZ;
+               /* set default configuration */
+               priv->if_khz = 4560;
+               priv->default_pm = 0;
+               priv->dvb_amplitude = 134;
+               priv->set_smoothedcvbs = 1;
+               mutex_init(&priv->lock);
+               fe->tuner_priv = priv;
+               break;
+       default:
+               /* existing tuner instance */
+               fe->tuner_priv = priv;
+               break;
+       }
+
+       if (cfg->if_khz != 0) {
+               /* copy configuration if provided by the caller */
+               priv->if_khz = cfg->if_khz;
+               priv->default_pm = cfg->default_pm;
+               priv->dvb_amplitude = cfg->dvb_amplitude;
+               priv->set_smoothedcvbs = cfg->set_smoothedcvbs;
+       }
+
+       /* Check if firmware has been loaded. It is possible that another
+          instance of the driver has loaded the firmware.
+        */
+
+       if (instance == 1) {
+               if (xc4000_readreg(priv, XREG_PRODUCT_ID, &id) != 0)
+                       goto fail;
+       } else {
+               id = ((priv->cur_fw.type & BASE) != 0 ?
+                     priv->hwmodel : XC_PRODUCT_ID_FW_NOT_LOADED);
+       }
+
+       switch (id) {
+       case XC_PRODUCT_ID_XC4000:
+       case XC_PRODUCT_ID_XC4100:
+               printk(KERN_INFO
+                       "xc4000: Successfully identified at address 0x%02x\n",
+                       cfg->i2c_address);
+               printk(KERN_INFO
+                       "xc4000: Firmware has been loaded previously\n");
+               break;
+       case XC_PRODUCT_ID_FW_NOT_LOADED:
+               printk(KERN_INFO
+                       "xc4000: Successfully identified at address 0x%02x\n",
+                       cfg->i2c_address);
+               printk(KERN_INFO
+                       "xc4000: Firmware has not been loaded previously\n");
+               break;
+       default:
+               printk(KERN_ERR
+                       "xc4000: Device not found at addr 0x%02x (0x%x)\n",
+                       cfg->i2c_address, id);
+               goto fail;
+       }
+
+       mutex_unlock(&xc4000_list_mutex);
+
+       memcpy(&fe->ops.tuner_ops, &xc4000_tuner_ops,
+               sizeof(struct dvb_tuner_ops));
+
+       if (instance == 1) {
+               int     ret;
+               mutex_lock(&priv->lock);
+               ret = xc4000_fwupload(fe);
+               mutex_unlock(&priv->lock);
+               if (ret != 0)
+                       goto fail2;
+       }
+
+       return fe;
+fail:
+       mutex_unlock(&xc4000_list_mutex);
+fail2:
+       xc4000_release(fe);
+       return NULL;
+}
+EXPORT_SYMBOL(xc4000_attach);
+
+MODULE_AUTHOR("Steven Toth, Davide Ferri");
+MODULE_DESCRIPTION("Xceive xc4000 silicon tuner driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/xc4000.h b/drivers/media/common/tuners/xc4000.h
new file mode 100644 (file)
index 0000000..e6a44d1
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ *  Driver for Xceive XC4000 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __XC4000_H__
+#define __XC4000_H__
+
+#include <linux/firmware.h>
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct xc4000_config {
+       u8      i2c_address;
+       /* if non-zero, power management is enabled by default */
+       u8      default_pm;
+       /* value to be written to XREG_AMPLITUDE in DVB-T mode (0: no write) */
+       u8      dvb_amplitude;
+       /* if non-zero, register 0x0E is set to filter analog TV video output */
+       u8      set_smoothedcvbs;
+       /* IF for DVB-T */
+       u32     if_khz;
+};
+
+/* xc4000 callback command */
+#define XC4000_TUNER_RESET             0
+
+/* For each bridge framework, when it attaches either analog or digital,
+ * it has to store a reference back to its _core equivalent structure,
+ * so that it can service the hardware by steering gpio's etc.
+ * Each bridge implementation is different so cast devptr accordingly.
+ * The xc4000 driver cares not for this value, other than ensuring
+ * it's passed back to a bridge during tuner_callback().
+ */
+
+#if defined(CONFIG_MEDIA_TUNER_XC4000) || (defined(CONFIG_MEDIA_TUNER_XC4000_MODULE) && defined(MODULE))
+extern struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe,
+                                         struct i2c_adapter *i2c,
+                                         struct xc4000_config *cfg);
+#else
+static inline struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe,
+                                                struct i2c_adapter *i2c,
+                                                struct xc4000_config *cfg)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif
+
+#endif
index ee214c3..f6e40b3 100644 (file)
@@ -80,6 +80,10 @@ comment "Supported nGene Adapters"
        depends on DVB_CORE && PCI && I2C
        source "drivers/media/dvb/ngene/Kconfig"
 
+comment "Supported ddbridge ('Octopus') Adapters"
+       depends on DVB_CORE && PCI && I2C
+       source "drivers/media/dvb/ddbridge/Kconfig"
+
 comment "Supported DVB Frontends"
        depends on DVB_CORE
 source "drivers/media/dvb/frontends/Kconfig"
index a1a0875..b2cefe6 100644 (file)
@@ -15,6 +15,7 @@ obj-y        := dvb-core/     \
                dm1105/         \
                pt1/            \
                mantis/         \
-               ngene/
+               ngene/          \
+               ddbridge/
 
 obj-$(CONFIG_DVB_FIREDTV)      += firewire/
index 1e1106d..521d691 100644 (file)
@@ -892,7 +892,7 @@ static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub)
        if (!(bttv_pci_dev = bttv_get_pcidev(card->bttv_nr))) {
                printk("dvb_bt8xx: no pci device for card %d\n", card->bttv_nr);
                kfree(card);
-               return -EFAULT;
+               return -ENODEV;
        }
 
        if (!(card->bt = dvb_bt8xx_878_match(card->bttv_nr, bttv_pci_dev))) {
@@ -902,7 +902,7 @@ static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub)
                       "installed, try removing it.\n");
 
                kfree(card);
-               return -EFAULT;
+               return -ENODEV;
        }
 
        mutex_init(&card->bt->gpio_lock);
diff --git a/drivers/media/dvb/ddbridge/Kconfig b/drivers/media/dvb/ddbridge/Kconfig
new file mode 100644 (file)
index 0000000..d099e1a
--- /dev/null
@@ -0,0 +1,18 @@
+config DVB_DDBRIDGE
+       tristate "Digital Devices bridge support"
+       depends on DVB_CORE && PCI && I2C
+       select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+       select DVB_STV6110x if !DVB_FE_CUSTOMISE
+       select DVB_STV090x if !DVB_FE_CUSTOMISE
+       select DVB_DRXK if !DVB_FE_CUSTOMISE
+       select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE
+       ---help---
+         Support for cards with the Digital Devices PCI express bridge:
+         - Octopus PCIe Bridge
+         - Octopus mini PCIe Bridge
+         - Octopus LE
+         - DuoFlex S2 Octopus
+         - DuoFlex CT Octopus
+         - cineS2(v6)
+
+         Say Y if you own such a card and want to use it.
diff --git a/drivers/media/dvb/ddbridge/Makefile b/drivers/media/dvb/ddbridge/Makefile
new file mode 100644 (file)
index 0000000..de4fe19
--- /dev/null
@@ -0,0 +1,14 @@
+#
+# Makefile for the ddbridge device driver
+#
+
+ddbridge-objs := ddbridge-core.o
+
+obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends/
+EXTRA_CFLAGS += -Idrivers/media/common/tuners/
+
+# For the staging CI driver cxd2099
+EXTRA_CFLAGS += -Idrivers/staging/cxd2099/
diff --git a/drivers/media/dvb/ddbridge/ddbridge-core.c b/drivers/media/dvb/ddbridge/ddbridge-core.c
new file mode 100644 (file)
index 0000000..573d540
--- /dev/null
@@ -0,0 +1,1719 @@
+/*
+ * ddbridge.c: Digital Devices PCIe bridge driver
+ *
+ * Copyright (C) 2010-2011 Digital Devices GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/io.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/timer.h>
+#include <linux/version.h>
+#include <linux/i2c.h>
+#include <linux/swab.h>
+#include <linux/vmalloc.h>
+#include "ddbridge.h"
+
+#include "ddbridge-regs.h"
+
+#include "tda18271c2dd.h"
+#include "stv6110x.h"
+#include "stv090x.h"
+#include "lnbh24.h"
+#include "drxk.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+/* MSI had problems with lost interrupts, fixed but needs testing */
+#undef CONFIG_PCI_MSI
+
+/******************************************************************************/
+
+static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val)
+{
+       struct i2c_msg msgs[1] = {{.addr = adr,  .flags = I2C_M_RD,
+                                  .buf  = val,  .len   = 1 } };
+       return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1;
+}
+
+static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, u8 reg, u8 *val)
+{
+       struct i2c_msg msgs[2] = {{.addr = adr,  .flags = 0,
+                                  .buf  = &reg, .len   = 1 },
+                                 {.addr = adr,  .flags = I2C_M_RD,
+                                  .buf  = val,  .len   = 1 } };
+       return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
+}
+
+static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr,
+                         u16 reg, u8 *val)
+{
+       u8 msg[2] = {reg>>8, reg&0xff};
+       struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
+                                  .buf  = msg, .len   = 2},
+                                 {.addr = adr, .flags = I2C_M_RD,
+                                  .buf  = val, .len   = 1} };
+       return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
+}
+
+static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd)
+{
+       struct ddb *dev = i2c->dev;
+       int stat;
+       u32 val;
+
+       i2c->done = 0;
+       ddbwritel((adr << 9) | cmd, i2c->regs + I2C_COMMAND);
+       stat = wait_event_timeout(i2c->wq, i2c->done == 1, HZ);
+       if (stat <= 0) {
+               printk(KERN_ERR "I2C timeout\n");
+               { /* MSI debugging*/
+                       u32 istat = ddbreadl(INTERRUPT_STATUS);
+                       printk(KERN_ERR "IRS %08x\n", istat);
+                       ddbwritel(istat, INTERRUPT_ACK);
+               }
+               return -EIO;
+       }
+       val = ddbreadl(i2c->regs+I2C_COMMAND);
+       if (val & 0x70000)
+               return -EIO;
+       return 0;
+}
+
+static int ddb_i2c_master_xfer(struct i2c_adapter *adapter,
+                              struct i2c_msg msg[], int num)
+{
+       struct ddb_i2c *i2c = (struct ddb_i2c *)i2c_get_adapdata(adapter);
+       struct ddb *dev = i2c->dev;
+       u8 addr = 0;
+
+       if (num)
+               addr = msg[0].addr;
+
+       if (num == 2 && msg[1].flags & I2C_M_RD &&
+           !(msg[0].flags & I2C_M_RD)) {
+               memcpy_toio(dev->regs + I2C_TASKMEM_BASE + i2c->wbuf,
+                           msg[0].buf, msg[0].len);
+               ddbwritel(msg[0].len|(msg[1].len << 16),
+                         i2c->regs+I2C_TASKLENGTH);
+               if (!ddb_i2c_cmd(i2c, addr, 1)) {
+                       memcpy_fromio(msg[1].buf,
+                                     dev->regs + I2C_TASKMEM_BASE + i2c->rbuf,
+                                     msg[1].len);
+                       return num;
+               }
+       }
+
+       if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
+               ddbcpyto(I2C_TASKMEM_BASE + i2c->wbuf, msg[0].buf, msg[0].len);
+               ddbwritel(msg[0].len, i2c->regs + I2C_TASKLENGTH);
+               if (!ddb_i2c_cmd(i2c, addr, 2))
+                       return num;
+       }
+       if (num == 1 && (msg[0].flags & I2C_M_RD)) {
+               ddbwritel(msg[0].len << 16, i2c->regs + I2C_TASKLENGTH);
+               if (!ddb_i2c_cmd(i2c, addr, 3)) {
+                       ddbcpyfrom(msg[0].buf,
+                                  I2C_TASKMEM_BASE + i2c->rbuf, msg[0].len);
+                       return num;
+               }
+       }
+       return -EIO;
+}
+
+
+static u32 ddb_i2c_functionality(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_SMBUS_EMUL;
+}
+
+struct i2c_algorithm ddb_i2c_algo = {
+       .master_xfer   = ddb_i2c_master_xfer,
+       .functionality = ddb_i2c_functionality,
+};
+
+static void ddb_i2c_release(struct ddb *dev)
+{
+       int i;
+       struct ddb_i2c *i2c;
+       struct i2c_adapter *adap;
+
+       for (i = 0; i < dev->info->port_num; i++) {
+               i2c = &dev->i2c[i];
+               adap = &i2c->adap;
+               i2c_del_adapter(adap);
+       }
+}
+
+static int ddb_i2c_init(struct ddb *dev)
+{
+       int i, j, stat = 0;
+       struct ddb_i2c *i2c;
+       struct i2c_adapter *adap;
+
+       for (i = 0; i < dev->info->port_num; i++) {
+               i2c = &dev->i2c[i];
+               i2c->dev = dev;
+               i2c->nr = i;
+               i2c->wbuf = i * (I2C_TASKMEM_SIZE / 4);
+               i2c->rbuf = i2c->wbuf + (I2C_TASKMEM_SIZE / 8);
+               i2c->regs = 0x80 + i * 0x20;
+               ddbwritel(I2C_SPEED_100, i2c->regs + I2C_TIMING);
+               ddbwritel((i2c->rbuf << 16) | i2c->wbuf,
+                         i2c->regs + I2C_TASKADDRESS);
+               init_waitqueue_head(&i2c->wq);
+
+               adap = &i2c->adap;
+               i2c_set_adapdata(adap, i2c);
+#ifdef I2C_ADAP_CLASS_TV_DIGITAL
+               adap->class = I2C_ADAP_CLASS_TV_DIGITAL|I2C_CLASS_TV_ANALOG;
+#else
+#ifdef I2C_CLASS_TV_ANALOG
+               adap->class = I2C_CLASS_TV_ANALOG;
+#endif
+#endif
+               strcpy(adap->name, "ddbridge");
+               adap->algo = &ddb_i2c_algo;
+               adap->algo_data = (void *)i2c;
+               adap->dev.parent = &dev->pdev->dev;
+               stat = i2c_add_adapter(adap);
+               if (stat)
+                       break;
+       }
+       if (stat)
+               for (j = 0; j < i; j++) {
+                       i2c = &dev->i2c[j];
+                       adap = &i2c->adap;
+                       i2c_del_adapter(adap);
+               }
+       return stat;
+}
+
+
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+
+#if 0
+static void set_table(struct ddb *dev, u32 off,
+                     dma_addr_t *pbuf, u32 num)
+{
+       u32 i, base;
+       u64 mem;
+
+       base = DMA_BASE_ADDRESS_TABLE + off;
+       for (i = 0; i < num; i++) {
+               mem = pbuf[i];
+               ddbwritel(mem & 0xffffffff, base + i * 8);
+               ddbwritel(mem >> 32, base + i * 8 + 4);
+       }
+}
+#endif
+
+static void ddb_address_table(struct ddb *dev)
+{
+       u32 i, j, base;
+       u64 mem;
+       dma_addr_t *pbuf;
+
+       for (i = 0; i < dev->info->port_num * 2; i++) {
+               base = DMA_BASE_ADDRESS_TABLE + i * 0x100;
+               pbuf = dev->input[i].pbuf;
+               for (j = 0; j < dev->input[i].dma_buf_num; j++) {
+                       mem = pbuf[j];
+                       ddbwritel(mem & 0xffffffff, base + j * 8);
+                       ddbwritel(mem >> 32, base + j * 8 + 4);
+               }
+       }
+       for (i = 0; i < dev->info->port_num; i++) {
+               base = DMA_BASE_ADDRESS_TABLE + 0x800 + i * 0x100;
+               pbuf = dev->output[i].pbuf;
+               for (j = 0; j < dev->output[i].dma_buf_num; j++) {
+                       mem = pbuf[j];
+                       ddbwritel(mem & 0xffffffff, base + j * 8);
+                       ddbwritel(mem >> 32, base + j * 8 + 4);
+               }
+       }
+}
+
+static void io_free(struct pci_dev *pdev, u8 **vbuf,
+                   dma_addr_t *pbuf, u32 size, int num)
+{
+       int i;
+
+       for (i = 0; i < num; i++) {
+               if (vbuf[i]) {
+                       pci_free_consistent(pdev, size, vbuf[i], pbuf[i]);
+                       vbuf[i] = 0;
+               }
+       }
+}
+
+static int io_alloc(struct pci_dev *pdev, u8 **vbuf,
+                   dma_addr_t *pbuf, u32 size, int num)
+{
+       int i;
+
+       for (i = 0; i < num; i++) {
+               vbuf[i] = pci_alloc_consistent(pdev, size, &pbuf[i]);
+               if (!vbuf[i])
+                       return -ENOMEM;
+       }
+       return 0;
+}
+
+static int ddb_buffers_alloc(struct ddb *dev)
+{
+       int i;
+       struct ddb_port *port;
+
+       for (i = 0; i < dev->info->port_num; i++) {
+               port = &dev->port[i];
+               switch (port->class) {
+               case DDB_PORT_TUNER:
+                       if (io_alloc(dev->pdev, port->input[0]->vbuf,
+                                    port->input[0]->pbuf,
+                                    port->input[0]->dma_buf_size,
+                                    port->input[0]->dma_buf_num) < 0)
+                               return -1;
+                       if (io_alloc(dev->pdev, port->input[1]->vbuf,
+                                    port->input[1]->pbuf,
+                                    port->input[1]->dma_buf_size,
+                                    port->input[1]->dma_buf_num) < 0)
+                               return -1;
+                       break;
+               case DDB_PORT_CI:
+                       if (io_alloc(dev->pdev, port->input[0]->vbuf,
+                                    port->input[0]->pbuf,
+                                    port->input[0]->dma_buf_size,
+                                    port->input[0]->dma_buf_num) < 0)
+                               return -1;
+                       if (io_alloc(dev->pdev, port->output->vbuf,
+                                    port->output->pbuf,
+                                    port->output->dma_buf_size,
+                                    port->output->dma_buf_num) < 0)
+                               return -1;
+                       break;
+               default:
+                       break;
+               }
+       }
+       ddb_address_table(dev);
+       return 0;
+}
+
+static void ddb_buffers_free(struct ddb *dev)
+{
+       int i;
+       struct ddb_port *port;
+
+       for (i = 0; i < dev->info->port_num; i++) {
+               port = &dev->port[i];
+               io_free(dev->pdev, port->input[0]->vbuf,
+                       port->input[0]->pbuf,
+                       port->input[0]->dma_buf_size,
+                       port->input[0]->dma_buf_num);
+               io_free(dev->pdev, port->input[1]->vbuf,
+                       port->input[1]->pbuf,
+                       port->input[1]->dma_buf_size,
+                       port->input[1]->dma_buf_num);
+               io_free(dev->pdev, port->output->vbuf,
+                       port->output->pbuf,
+                       port->output->dma_buf_size,
+                       port->output->dma_buf_num);
+       }
+}
+
+static void ddb_input_start(struct ddb_input *input)
+{
+       struct ddb *dev = input->port->dev;
+
+       spin_lock_irq(&input->lock);
+       input->cbuf = 0;
+       input->coff = 0;
+
+       /* reset */
+       ddbwritel(0, TS_INPUT_CONTROL(input->nr));
+       ddbwritel(2, TS_INPUT_CONTROL(input->nr));
+       ddbwritel(0, TS_INPUT_CONTROL(input->nr));
+
+       ddbwritel((1 << 16) |
+                 (input->dma_buf_num << 11) |
+                 (input->dma_buf_size >> 7),
+                 DMA_BUFFER_SIZE(input->nr));
+       ddbwritel(0, DMA_BUFFER_ACK(input->nr));
+
+       ddbwritel(1, DMA_BASE_WRITE);
+       ddbwritel(3, DMA_BUFFER_CONTROL(input->nr));
+       ddbwritel(9, TS_INPUT_CONTROL(input->nr));
+       input->running = 1;
+       spin_unlock_irq(&input->lock);
+}
+
+static void ddb_input_stop(struct ddb_input *input)
+{
+       struct ddb *dev = input->port->dev;
+
+       spin_lock_irq(&input->lock);
+       ddbwritel(0, TS_INPUT_CONTROL(input->nr));
+       ddbwritel(0, DMA_BUFFER_CONTROL(input->nr));
+       input->running = 0;
+       spin_unlock_irq(&input->lock);
+}
+
+static void ddb_output_start(struct ddb_output *output)
+{
+       struct ddb *dev = output->port->dev;
+
+       spin_lock_irq(&output->lock);
+       output->cbuf = 0;
+       output->coff = 0;
+       ddbwritel(0, TS_OUTPUT_CONTROL(output->nr));
+       ddbwritel(2, TS_OUTPUT_CONTROL(output->nr));
+       ddbwritel(0, TS_OUTPUT_CONTROL(output->nr));
+       ddbwritel(0x3c, TS_OUTPUT_CONTROL(output->nr));
+       ddbwritel((1 << 16) |
+                 (output->dma_buf_num << 11) |
+                 (output->dma_buf_size >> 7),
+                 DMA_BUFFER_SIZE(output->nr + 8));
+       ddbwritel(0, DMA_BUFFER_ACK(output->nr + 8));
+
+       ddbwritel(1, DMA_BASE_READ);
+       ddbwritel(3, DMA_BUFFER_CONTROL(output->nr + 8));
+       /* ddbwritel(0xbd, TS_OUTPUT_CONTROL(output->nr)); */
+       ddbwritel(0x1d, TS_OUTPUT_CONTROL(output->nr));
+       output->running = 1;
+       spin_unlock_irq(&output->lock);
+}
+
+static void ddb_output_stop(struct ddb_output *output)
+{
+       struct ddb *dev = output->port->dev;
+
+       spin_lock_irq(&output->lock);
+       ddbwritel(0, TS_OUTPUT_CONTROL(output->nr));
+       ddbwritel(0, DMA_BUFFER_CONTROL(output->nr + 8));
+       output->running = 0;
+       spin_unlock_irq(&output->lock);
+}
+
+static u32 ddb_output_free(struct ddb_output *output)
+{
+       u32 idx, off, stat = output->stat;
+       s32 diff;
+
+       idx = (stat >> 11) & 0x1f;
+       off = (stat & 0x7ff) << 7;
+
+       if (output->cbuf != idx) {
+               if ((((output->cbuf + 1) % output->dma_buf_num) == idx) &&
+                   (output->dma_buf_size - output->coff <= 188))
+                       return 0;
+               return 188;
+       }
+       diff = off - output->coff;
+       if (diff <= 0 || diff > 188)
+               return 188;
+       return 0;
+}
+
+static ssize_t ddb_output_write(struct ddb_output *output,
+                               const u8 *buf, size_t count)
+{
+       struct ddb *dev = output->port->dev;
+       u32 idx, off, stat = output->stat;
+       u32 left = count, len;
+
+       idx = (stat >> 11) & 0x1f;
+       off = (stat & 0x7ff) << 7;
+
+       while (left) {
+               len = output->dma_buf_size - output->coff;
+               if ((((output->cbuf + 1) % output->dma_buf_num) == idx) &&
+                   (off == 0)) {
+                       if (len <= 188)
+                               break;
+                       len -= 188;
+               }
+               if (output->cbuf == idx) {
+                       if (off > output->coff) {
+#if 1
+                               len = off - output->coff;
+                               len -= (len % 188);
+                               if (len <= 188)
+
+#endif
+                                       break;
+                               len -= 188;
+                       }
+               }
+               if (len > left)
+                       len = left;
+               if (copy_from_user(output->vbuf[output->cbuf] + output->coff,
+                                  buf, len))
+                       return -EIO;
+               left -= len;
+               buf += len;
+               output->coff += len;
+               if (output->coff == output->dma_buf_size) {
+                       output->coff = 0;
+                       output->cbuf = ((output->cbuf + 1) % output->dma_buf_num);
+               }
+               ddbwritel((output->cbuf << 11) | (output->coff >> 7),
+                         DMA_BUFFER_ACK(output->nr + 8));
+       }
+       return count - left;
+}
+
+static u32 ddb_input_avail(struct ddb_input *input)
+{
+       struct ddb *dev = input->port->dev;
+       u32 idx, off, stat = input->stat;
+       u32 ctrl = ddbreadl(DMA_BUFFER_CONTROL(input->nr));
+
+       idx = (stat >> 11) & 0x1f;
+       off = (stat & 0x7ff) << 7;
+
+       if (ctrl & 4) {
+               printk(KERN_ERR "IA %d %d %08x\n", idx, off, ctrl);
+               ddbwritel(input->stat, DMA_BUFFER_ACK(input->nr));
+               return 0;
+       }
+       if (input->cbuf != idx)
+               return 188;
+       return 0;
+}
+
+static size_t ddb_input_read(struct ddb_input *input, u8 *buf, size_t count)
+{
+       struct ddb *dev = input->port->dev;
+       u32 left = count;
+       u32 idx, off, free, stat = input->stat;
+       int ret;
+
+       idx = (stat >> 11) & 0x1f;
+       off = (stat & 0x7ff) << 7;
+
+       while (left) {
+               if (input->cbuf == idx)
+                       return count - left;
+               free = input->dma_buf_size - input->coff;
+               if (free > left)
+                       free = left;
+               ret = copy_to_user(buf, input->vbuf[input->cbuf] +
+                                  input->coff, free);
+               input->coff += free;
+               if (input->coff == input->dma_buf_size) {
+                       input->coff = 0;
+                       input->cbuf = (input->cbuf+1) % input->dma_buf_num;
+               }
+               left -= free;
+               ddbwritel((input->cbuf << 11) | (input->coff >> 7),
+                         DMA_BUFFER_ACK(input->nr));
+       }
+       return count;
+}
+
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+
+#if 0
+static struct ddb_input *fe2input(struct ddb *dev, struct dvb_frontend *fe)
+{
+       int i;
+
+       for (i = 0; i < dev->info->port_num * 2; i++) {
+               if (dev->input[i].fe == fe)
+                       return &dev->input[i];
+       }
+       return NULL;
+}
+#endif
+
+static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       struct ddb_input *input = fe->sec_priv;
+       struct ddb_port *port = input->port;
+       int status;
+
+       if (enable) {
+               mutex_lock(&port->i2c_gate_lock);
+               status = input->gate_ctrl(fe, 1);
+       } else {
+               status = input->gate_ctrl(fe, 0);
+               mutex_unlock(&port->i2c_gate_lock);
+       }
+       return status;
+}
+
+static int demod_attach_drxk(struct ddb_input *input)
+{
+       struct i2c_adapter *i2c = &input->port->i2c->adap;
+       struct dvb_frontend *fe;
+       struct drxk_config config;
+
+       memset(&config, 0, sizeof(config));
+       config.adr = 0x29 + (input->nr & 1);
+
+       fe = input->fe = dvb_attach(drxk_attach, &config, i2c, &input->fe2);
+       if (!input->fe) {
+               printk(KERN_ERR "No DRXK found!\n");
+               return -ENODEV;
+       }
+       fe->sec_priv = input;
+       input->gate_ctrl = fe->ops.i2c_gate_ctrl;
+       fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
+       return 0;
+}
+
+static int tuner_attach_tda18271(struct ddb_input *input)
+{
+       struct i2c_adapter *i2c = &input->port->i2c->adap;
+       struct dvb_frontend *fe;
+
+       if (input->fe->ops.i2c_gate_ctrl)
+               input->fe->ops.i2c_gate_ctrl(input->fe, 1);
+       fe = dvb_attach(tda18271c2dd_attach, input->fe, i2c, 0x60);
+       if (!fe) {
+               printk(KERN_ERR "No TDA18271 found!\n");
+               return -ENODEV;
+       }
+       if (input->fe->ops.i2c_gate_ctrl)
+               input->fe->ops.i2c_gate_ctrl(input->fe, 0);
+       return 0;
+}
+
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+
+static struct stv090x_config stv0900 = {
+       .device         = STV0900,
+       .demod_mode     = STV090x_DUAL,
+       .clk_mode       = STV090x_CLK_EXT,
+
+       .xtal           = 27000000,
+       .address        = 0x69,
+
+       .ts1_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
+       .ts2_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
+
+       .repeater_level = STV090x_RPTLEVEL_16,
+
+       .adc1_range     = STV090x_ADC_1Vpp,
+       .adc2_range     = STV090x_ADC_1Vpp,
+
+       .diseqc_envelope_mode = true,
+};
+
+static struct stv090x_config stv0900_aa = {
+       .device         = STV0900,
+       .demod_mode     = STV090x_DUAL,
+       .clk_mode       = STV090x_CLK_EXT,
+
+       .xtal           = 27000000,
+       .address        = 0x68,
+
+       .ts1_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
+       .ts2_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
+
+       .repeater_level = STV090x_RPTLEVEL_16,
+
+       .adc1_range     = STV090x_ADC_1Vpp,
+       .adc2_range     = STV090x_ADC_1Vpp,
+
+       .diseqc_envelope_mode = true,
+};
+
+static struct stv6110x_config stv6110a = {
+       .addr    = 0x60,
+       .refclk  = 27000000,
+       .clk_div = 1,
+};
+
+static struct stv6110x_config stv6110b = {
+       .addr    = 0x63,
+       .refclk  = 27000000,
+       .clk_div = 1,
+};
+
+static int demod_attach_stv0900(struct ddb_input *input, int type)
+{
+       struct i2c_adapter *i2c = &input->port->i2c->adap;
+       struct stv090x_config *feconf = type ? &stv0900_aa : &stv0900;
+
+       input->fe = dvb_attach(stv090x_attach, feconf, i2c,
+                              (input->nr & 1) ? STV090x_DEMODULATOR_1
+                              : STV090x_DEMODULATOR_0);
+       if (!input->fe) {
+               printk(KERN_ERR "No STV0900 found!\n");
+               return -ENODEV;
+       }
+       if (!dvb_attach(lnbh24_attach, input->fe, i2c, 0,
+                       0, (input->nr & 1) ?
+                       (0x09 - type) : (0x0b - type))) {
+               printk(KERN_ERR "No LNBH24 found!\n");
+               return -ENODEV;
+       }
+       return 0;
+}
+
+static int tuner_attach_stv6110(struct ddb_input *input, int type)
+{
+       struct i2c_adapter *i2c = &input->port->i2c->adap;
+       struct stv090x_config *feconf = type ? &stv0900_aa : &stv0900;
+       struct stv6110x_config *tunerconf = (input->nr & 1) ?
+               &stv6110b : &stv6110a;
+       struct stv6110x_devctl *ctl;
+
+       ctl = dvb_attach(stv6110x_attach, input->fe, tunerconf, i2c);
+       if (!ctl) {
+               printk(KERN_ERR "No STV6110X found!\n");
+               return -ENODEV;
+       }
+       printk(KERN_INFO "attach tuner input %d adr %02x\n",
+                        input->nr, tunerconf->addr);
+
+       feconf->tuner_init          = ctl->tuner_init;
+       feconf->tuner_sleep         = ctl->tuner_sleep;
+       feconf->tuner_set_mode      = ctl->tuner_set_mode;
+       feconf->tuner_set_frequency = ctl->tuner_set_frequency;
+       feconf->tuner_get_frequency = ctl->tuner_get_frequency;
+       feconf->tuner_set_bandwidth = ctl->tuner_set_bandwidth;
+       feconf->tuner_get_bandwidth = ctl->tuner_get_bandwidth;
+       feconf->tuner_set_bbgain    = ctl->tuner_set_bbgain;
+       feconf->tuner_get_bbgain    = ctl->tuner_get_bbgain;
+       feconf->tuner_set_refclk    = ctl->tuner_set_refclk;
+       feconf->tuner_get_status    = ctl->tuner_get_status;
+
+       return 0;
+}
+
+static int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id,
+                           int (*start_feed)(struct dvb_demux_feed *),
+                           int (*stop_feed)(struct dvb_demux_feed *),
+                           void *priv)
+{
+       dvbdemux->priv = priv;
+
+       dvbdemux->filternum = 256;
+       dvbdemux->feednum = 256;
+       dvbdemux->start_feed = start_feed;
+       dvbdemux->stop_feed = stop_feed;
+       dvbdemux->write_to_decoder = NULL;
+       dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
+                                     DMX_SECTION_FILTERING |
+                                     DMX_MEMORY_BASED_FILTERING);
+       return dvb_dmx_init(dvbdemux);
+}
+
+static int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev,
+                              struct dvb_demux *dvbdemux,
+                              struct dmx_frontend *hw_frontend,
+                              struct dmx_frontend *mem_frontend,
+                              struct dvb_adapter *dvb_adapter)
+{
+       int ret;
+
+       dmxdev->filternum = 256;
+       dmxdev->demux = &dvbdemux->dmx;
+       dmxdev->capabilities = 0;
+       ret = dvb_dmxdev_init(dmxdev, dvb_adapter);
+       if (ret < 0)
+               return ret;
+
+       hw_frontend->source = DMX_FRONTEND_0;
+       dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend);
+       mem_frontend->source = DMX_MEMORY_FE;
+       dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend);
+       return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend);
+}
+
+static int start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+       struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+       struct ddb_input *input = dvbdmx->priv;
+
+       if (!input->users)
+               ddb_input_start(input);
+
+       return ++input->users;
+}
+
+static int stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+       struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+       struct ddb_input *input = dvbdmx->priv;
+
+       if (--input->users)
+               return input->users;
+
+       ddb_input_stop(input);
+       return 0;
+}
+
+
+static void dvb_input_detach(struct ddb_input *input)
+{
+       struct dvb_adapter *adap = &input->adap;
+       struct dvb_demux *dvbdemux = &input->demux;
+
+       switch (input->attached) {
+       case 5:
+               if (input->fe2)
+                       dvb_unregister_frontend(input->fe2);
+               if (input->fe) {
+                       dvb_unregister_frontend(input->fe);
+                       dvb_frontend_detach(input->fe);
+                       input->fe = NULL;
+               }
+       case 4:
+               dvb_net_release(&input->dvbnet);
+
+       case 3:
+               dvbdemux->dmx.close(&dvbdemux->dmx);
+               dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
+                                             &input->hw_frontend);
+               dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
+                                             &input->mem_frontend);
+               dvb_dmxdev_release(&input->dmxdev);
+
+       case 2:
+               dvb_dmx_release(&input->demux);
+
+       case 1:
+               dvb_unregister_adapter(adap);
+       }
+       input->attached = 0;
+}
+
+static int dvb_input_attach(struct ddb_input *input)
+{
+       int ret;
+       struct ddb_port *port = input->port;
+       struct dvb_adapter *adap = &input->adap;
+       struct dvb_demux *dvbdemux = &input->demux;
+
+       ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE,
+                                  &input->port->dev->pdev->dev,
+                                  adapter_nr);
+       if (ret < 0) {
+               printk(KERN_ERR "ddbridge: Could not register adapter."
+                      "Check if you enabled enough adapters in dvb-core!\n");
+               return ret;
+       }
+       input->attached = 1;
+
+       ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux",
+                                     start_feed,
+                                     stop_feed, input);
+       if (ret < 0)
+               return ret;
+       input->attached = 2;
+
+       ret = my_dvb_dmxdev_ts_card_init(&input->dmxdev, &input->demux,
+                                        &input->hw_frontend,
+                                        &input->mem_frontend, adap);
+       if (ret < 0)
+               return ret;
+       input->attached = 3;
+
+       ret = dvb_net_init(adap, &input->dvbnet, input->dmxdev.demux);
+       if (ret < 0)
+               return ret;
+       input->attached = 4;
+
+       input->fe = 0;
+       switch (port->type) {
+       case DDB_TUNER_DVBS_ST:
+               if (demod_attach_stv0900(input, 0) < 0)
+                       return -ENODEV;
+               if (tuner_attach_stv6110(input, 0) < 0)
+                       return -ENODEV;
+               if (input->fe) {
+                       if (dvb_register_frontend(adap, input->fe) < 0)
+                               return -ENODEV;
+               }
+               break;
+       case DDB_TUNER_DVBS_ST_AA:
+               if (demod_attach_stv0900(input, 1) < 0)
+                       return -ENODEV;
+               if (tuner_attach_stv6110(input, 1) < 0)
+                       return -ENODEV;
+               if (input->fe) {
+                       if (dvb_register_frontend(adap, input->fe) < 0)
+                               return -ENODEV;
+               }
+               break;
+       case DDB_TUNER_DVBCT_TR:
+               if (demod_attach_drxk(input) < 0)
+                       return -ENODEV;
+               if (tuner_attach_tda18271(input) < 0)
+                       return -ENODEV;
+               if (input->fe) {
+                       if (dvb_register_frontend(adap, input->fe) < 0)
+                               return -ENODEV;
+               }
+               if (input->fe2) {
+                       if (dvb_register_frontend(adap, input->fe2) < 0)
+                               return -ENODEV;
+                       input->fe2->tuner_priv = input->fe->tuner_priv;
+                       memcpy(&input->fe2->ops.tuner_ops,
+                              &input->fe->ops.tuner_ops,
+                              sizeof(struct dvb_tuner_ops));
+               }
+               break;
+       }
+       input->attached = 5;
+       return 0;
+}
+
+/****************************************************************************/
+/****************************************************************************/
+
+static ssize_t ts_write(struct file *file, const char *buf,
+                       size_t count, loff_t *ppos)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct ddb_output *output = dvbdev->priv;
+       size_t left = count;
+       int stat;
+
+       while (left) {
+               if (ddb_output_free(output) < 188) {
+                       if (file->f_flags & O_NONBLOCK)
+                               break;
+                       if (wait_event_interruptible(
+                                   output->wq, ddb_output_free(output) >= 188) < 0)
+                               break;
+               }
+               stat = ddb_output_write(output, buf, left);
+               if (stat < 0)
+                       break;
+               buf += stat;
+               left -= stat;
+       }
+       return (left == count) ? -EAGAIN : (count - left);
+}
+
+static ssize_t ts_read(struct file *file, char *buf,
+                      size_t count, loff_t *ppos)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct ddb_output *output = dvbdev->priv;
+       struct ddb_input *input = output->port->input[0];
+       int left, read;
+
+       count -= count % 188;
+       left = count;
+       while (left) {
+               if (ddb_input_avail(input) < 188) {
+                       if (file->f_flags & O_NONBLOCK)
+                               break;
+                       if (wait_event_interruptible(
+                                   input->wq, ddb_input_avail(input) >= 188) < 0)
+                               break;
+               }
+               read = ddb_input_read(input, buf, left);
+               left -= read;
+               buf += read;
+       }
+       return (left == count) ? -EAGAIN : (count - left);
+}
+
+static unsigned int ts_poll(struct file *file, poll_table *wait)
+{
+       /*
+       struct dvb_device *dvbdev = file->private_data;
+       struct ddb_output *output = dvbdev->priv;
+       struct ddb_input *input = output->port->input[0];
+       */
+       unsigned int mask = 0;
+
+#if 0
+       if (data_avail_to_read)
+               mask |= POLLIN | POLLRDNORM;
+       if (data_avail_to_write)
+               mask |= POLLOUT | POLLWRNORM;
+
+       poll_wait(file, &read_queue, wait);
+       poll_wait(file, &write_queue, wait);
+#endif
+       return mask;
+}
+
+static const struct file_operations ci_fops = {
+       .owner   = THIS_MODULE,
+       .read    = ts_read,
+       .write   = ts_write,
+       .open    = dvb_generic_open,
+       .release = dvb_generic_release,
+       .poll    = ts_poll,
+       .mmap    = 0,
+};
+
+static struct dvb_device dvbdev_ci = {
+       .priv    = 0,
+       .readers = -1,
+       .writers = -1,
+       .users   = -1,
+       .fops    = &ci_fops,
+};
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+static void input_tasklet(unsigned long data)
+{
+       struct ddb_input *input = (struct ddb_input *) data;
+       struct ddb *dev = input->port->dev;
+
+       spin_lock(&input->lock);
+       if (!input->running) {
+               spin_unlock(&input->lock);
+               return;
+       }
+       input->stat = ddbreadl(DMA_BUFFER_CURRENT(input->nr));
+
+       if (input->port->class == DDB_PORT_TUNER) {
+               if (4&ddbreadl(DMA_BUFFER_CONTROL(input->nr)))
+                       printk(KERN_ERR "Overflow input %d\n", input->nr);
+               while (input->cbuf != ((input->stat >> 11) & 0x1f)
+                      || (4&ddbreadl(DMA_BUFFER_CONTROL(input->nr)))) {
+                       dvb_dmx_swfilter_packets(&input->demux,
+                                                input->vbuf[input->cbuf],
+                                                input->dma_buf_size / 188);
+
+                       input->cbuf = (input->cbuf + 1) % input->dma_buf_num;
+                       ddbwritel((input->cbuf << 11),
+                                 DMA_BUFFER_ACK(input->nr));
+                       input->stat = ddbreadl(DMA_BUFFER_CURRENT(input->nr));
+                      }
+       }
+       if (input->port->class == DDB_PORT_CI)
+               wake_up(&input->wq);
+       spin_unlock(&input->lock);
+}
+
+static void output_tasklet(unsigned long data)
+{
+       struct ddb_output *output = (struct ddb_output *) data;
+       struct ddb *dev = output->port->dev;
+
+       spin_lock(&output->lock);
+       if (!output->running) {
+               spin_unlock(&output->lock);
+               return;
+       }
+       output->stat = ddbreadl(DMA_BUFFER_CURRENT(output->nr + 8));
+       wake_up(&output->wq);
+       spin_unlock(&output->lock);
+}
+
+
+struct cxd2099_cfg cxd_cfg = {
+       .bitrate =  62000,
+       .adr     =  0x40,
+       .polarity = 1,
+       .clock_mode = 1,
+};
+
+static int ddb_ci_attach(struct ddb_port *port)
+{
+       int ret;
+
+       ret = dvb_register_adapter(&port->output->adap,
+                                  "DDBridge",
+                                  THIS_MODULE,
+                                  &port->dev->pdev->dev,
+                                  adapter_nr);
+       if (ret < 0)
+               return ret;
+       port->en = cxd2099_attach(&cxd_cfg, port, &port->i2c->adap);
+       if (!port->en) {
+               dvb_unregister_adapter(&port->output->adap);
+               return -ENODEV;
+       }
+       ddb_input_start(port->input[0]);
+       ddb_output_start(port->output);
+       dvb_ca_en50221_init(&port->output->adap,
+                           port->en, 0, 1);
+       ret = dvb_register_device(&port->output->adap, &port->output->dev,
+                                 &dvbdev_ci, (void *) port->output,
+                                 DVB_DEVICE_SEC);
+       return ret;
+}
+
+static int ddb_port_attach(struct ddb_port *port)
+{
+       int ret = 0;
+
+       switch (port->class) {
+       case DDB_PORT_TUNER:
+               ret = dvb_input_attach(port->input[0]);
+               if (ret < 0)
+                       break;
+               ret = dvb_input_attach(port->input[1]);
+               break;
+       case DDB_PORT_CI:
+               ret = ddb_ci_attach(port);
+               break;
+       default:
+               break;
+       }
+       if (ret < 0)
+               printk(KERN_ERR "port_attach on port %d failed\n", port->nr);
+       return ret;
+}
+
+static int ddb_ports_attach(struct ddb *dev)
+{
+       int i, ret = 0;
+       struct ddb_port *port;
+
+       for (i = 0; i < dev->info->port_num; i++) {
+               port = &dev->port[i];
+               ret = ddb_port_attach(port);
+               if (ret < 0)
+                       break;
+       }
+       return ret;
+}
+
+static void ddb_ports_detach(struct ddb *dev)
+{
+       int i;
+       struct ddb_port *port;
+
+       for (i = 0; i < dev->info->port_num; i++) {
+               port = &dev->port[i];
+               switch (port->class) {
+               case DDB_PORT_TUNER:
+                       dvb_input_detach(port->input[0]);
+                       dvb_input_detach(port->input[1]);
+                       break;
+               case DDB_PORT_CI:
+                       if (port->output->dev)
+                               dvb_unregister_device(port->output->dev);
+                       if (port->en) {
+                               ddb_input_stop(port->input[0]);
+                               ddb_output_stop(port->output);
+                               dvb_ca_en50221_release(port->en);
+                               kfree(port->en);
+                               port->en = 0;
+                               dvb_unregister_adapter(&port->output->adap);
+                       }
+                       break;
+               }
+       }
+}
+
+/****************************************************************************/
+/****************************************************************************/
+
+static int port_has_ci(struct ddb_port *port)
+{
+       u8 val;
+       return i2c_read_reg(&port->i2c->adap, 0x40, 0, &val) ? 0 : 1;
+}
+
+static int port_has_stv0900(struct ddb_port *port)
+{
+       u8 val;
+       if (i2c_read_reg16(&port->i2c->adap, 0x69, 0xf100, &val) < 0)
+               return 0;
+       return 1;
+}
+
+static int port_has_stv0900_aa(struct ddb_port *port)
+{
+       u8 val;
+       if (i2c_read_reg16(&port->i2c->adap, 0x68, 0xf100, &val) < 0)
+               return 0;
+       return 1;
+}
+
+static int port_has_drxks(struct ddb_port *port)
+{
+       u8 val;
+       if (i2c_read(&port->i2c->adap, 0x29, &val) < 0)
+               return 0;
+       if (i2c_read(&port->i2c->adap, 0x2a, &val) < 0)
+               return 0;
+       return 1;
+}
+
+static void ddb_port_probe(struct ddb_port *port)
+{
+       struct ddb *dev = port->dev;
+       char *modname = "NO MODULE";
+
+       port->class = DDB_PORT_NONE;
+
+       if (port_has_ci(port)) {
+               modname = "CI";
+               port->class = DDB_PORT_CI;
+               ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING);
+       } else if (port_has_stv0900(port)) {
+               modname = "DUAL DVB-S2";
+               port->class = DDB_PORT_TUNER;
+               port->type = DDB_TUNER_DVBS_ST;
+               ddbwritel(I2C_SPEED_100, port->i2c->regs + I2C_TIMING);
+       } else if (port_has_stv0900_aa(port)) {
+               modname = "DUAL DVB-S2";
+               port->class = DDB_PORT_TUNER;
+               port->type = DDB_TUNER_DVBS_ST_AA;
+               ddbwritel(I2C_SPEED_100, port->i2c->regs + I2C_TIMING);
+       } else if (port_has_drxks(port)) {
+               modname = "DUAL DVB-C/T";
+               port->class = DDB_PORT_TUNER;
+               port->type = DDB_TUNER_DVBCT_TR;
+               ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING);
+       }
+       printk(KERN_INFO "Port %d (TAB %d): %s\n",
+                        port->nr, port->nr+1, modname);
+}
+
+static void ddb_input_init(struct ddb_port *port, int nr)
+{
+       struct ddb *dev = port->dev;
+       struct ddb_input *input = &dev->input[nr];
+
+       input->nr = nr;
+       input->port = port;
+       input->dma_buf_num = INPUT_DMA_BUFS;
+       input->dma_buf_size = INPUT_DMA_SIZE;
+       ddbwritel(0, TS_INPUT_CONTROL(nr));
+       ddbwritel(2, TS_INPUT_CONTROL(nr));
+       ddbwritel(0, TS_INPUT_CONTROL(nr));
+       ddbwritel(0, DMA_BUFFER_ACK(nr));
+       tasklet_init(&input->tasklet, input_tasklet, (unsigned long) input);
+       spin_lock_init(&input->lock);
+       init_waitqueue_head(&input->wq);
+}
+
+static void ddb_output_init(struct ddb_port *port, int nr)
+{
+       struct ddb *dev = port->dev;
+       struct ddb_output *output = &dev->output[nr];
+       output->nr = nr;
+       output->port = port;
+       output->dma_buf_num = OUTPUT_DMA_BUFS;
+       output->dma_buf_size = OUTPUT_DMA_SIZE;
+
+       ddbwritel(0, TS_OUTPUT_CONTROL(nr));
+       ddbwritel(2, TS_OUTPUT_CONTROL(nr));
+       ddbwritel(0, TS_OUTPUT_CONTROL(nr));
+       tasklet_init(&output->tasklet, output_tasklet, (unsigned long) output);
+       init_waitqueue_head(&output->wq);
+}
+
+static void ddb_ports_init(struct ddb *dev)
+{
+       int i;
+       struct ddb_port *port;
+
+       for (i = 0; i < dev->info->port_num; i++) {
+               port = &dev->port[i];
+               port->dev = dev;
+               port->nr = i;
+               port->i2c = &dev->i2c[i];
+               port->input[0] = &dev->input[2 * i];
+               port->input[1] = &dev->input[2 * i + 1];
+               port->output = &dev->output[i];
+
+               mutex_init(&port->i2c_gate_lock);
+               ddb_port_probe(port);
+               ddb_input_init(port, 2 * i);
+               ddb_input_init(port, 2 * i + 1);
+               ddb_output_init(port, i);
+       }
+}
+
+static void ddb_ports_release(struct ddb *dev)
+{
+       int i;
+       struct ddb_port *port;
+
+       for (i = 0; i < dev->info->port_num; i++) {
+               port = &dev->port[i];
+               port->dev = dev;
+               tasklet_kill(&port->input[0]->tasklet);
+               tasklet_kill(&port->input[1]->tasklet);
+               tasklet_kill(&port->output->tasklet);
+       }
+}
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+static void irq_handle_i2c(struct ddb *dev, int n)
+{
+       struct ddb_i2c *i2c = &dev->i2c[n];
+
+       i2c->done = 1;
+       wake_up(&i2c->wq);
+}
+
+static irqreturn_t irq_handler(int irq, void *dev_id)
+{
+       struct ddb *dev = (struct ddb *) dev_id;
+       u32 s = ddbreadl(INTERRUPT_STATUS);
+
+       if (!s)
+               return IRQ_NONE;
+
+       do {
+               ddbwritel(s, INTERRUPT_ACK);
+
+               if (s & 0x00000001)
+                       irq_handle_i2c(dev, 0);
+               if (s & 0x00000002)
+                       irq_handle_i2c(dev, 1);
+               if (s & 0x00000004)
+                       irq_handle_i2c(dev, 2);
+               if (s & 0x00000008)
+                       irq_handle_i2c(dev, 3);
+
+               if (s & 0x00000100)
+                       tasklet_schedule(&dev->input[0].tasklet);
+               if (s & 0x00000200)
+                       tasklet_schedule(&dev->input[1].tasklet);
+               if (s & 0x00000400)
+                       tasklet_schedule(&dev->input[2].tasklet);
+               if (s & 0x00000800)
+                       tasklet_schedule(&dev->input[3].tasklet);
+               if (s & 0x00001000)
+                       tasklet_schedule(&dev->input[4].tasklet);
+               if (s & 0x00002000)
+                       tasklet_schedule(&dev->input[5].tasklet);
+               if (s & 0x00004000)
+                       tasklet_schedule(&dev->input[6].tasklet);
+               if (s & 0x00008000)
+                       tasklet_schedule(&dev->input[7].tasklet);
+
+               if (s & 0x00010000)
+                       tasklet_schedule(&dev->output[0].tasklet);
+               if (s & 0x00020000)
+                       tasklet_schedule(&dev->output[1].tasklet);
+               if (s & 0x00040000)
+                       tasklet_schedule(&dev->output[2].tasklet);
+               if (s & 0x00080000)
+                       tasklet_schedule(&dev->output[3].tasklet);
+
+               /* if (s & 0x000f0000)  printk(KERN_DEBUG "%08x\n", istat); */
+       } while ((s = ddbreadl(INTERRUPT_STATUS)));
+
+       return IRQ_HANDLED;
+}
+
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+
+static int flashio(struct ddb *dev, u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen)
+{
+       u32 data, shift;
+
+       if (wlen > 4)
+               ddbwritel(1, SPI_CONTROL);
+       while (wlen > 4) {
+               /* FIXME: check for big-endian */
+               data = swab32(*(u32 *)wbuf);
+               wbuf += 4;
+               wlen -= 4;
+               ddbwritel(data, SPI_DATA);
+               while (ddbreadl(SPI_CONTROL) & 0x0004)
+                       ;
+       }
+
+       if (rlen)
+               ddbwritel(0x0001 | ((wlen << (8 + 3)) & 0x1f00), SPI_CONTROL);
+       else
+               ddbwritel(0x0003 | ((wlen << (8 + 3)) & 0x1f00), SPI_CONTROL);
+
+       data = 0;
+       shift = ((4 - wlen) * 8);
+       while (wlen) {
+               data <<= 8;
+               data |= *wbuf;
+               wlen--;
+               wbuf++;
+       }
+       if (shift)
+               data <<= shift;
+       ddbwritel(data, SPI_DATA);
+       while (ddbreadl(SPI_CONTROL) & 0x0004)
+               ;
+
+       if (!rlen) {
+               ddbwritel(0, SPI_CONTROL);
+               return 0;
+       }
+       if (rlen > 4)
+               ddbwritel(1, SPI_CONTROL);
+
+       while (rlen > 4) {
+               ddbwritel(0xffffffff, SPI_DATA);
+               while (ddbreadl(SPI_CONTROL) & 0x0004)
+                       ;
+               data = ddbreadl(SPI_DATA);
+               *(u32 *) rbuf = swab32(data);
+               rbuf += 4;
+               rlen -= 4;
+       }
+       ddbwritel(0x0003 | ((rlen << (8 + 3)) & 0x1F00), SPI_CONTROL);
+       ddbwritel(0xffffffff, SPI_DATA);
+       while (ddbreadl(SPI_CONTROL) & 0x0004)
+               ;
+
+       data = ddbreadl(SPI_DATA);
+       ddbwritel(0, SPI_CONTROL);
+
+       if (rlen < 4)
+               data <<= ((4 - rlen) * 8);
+
+       while (rlen > 0) {
+               *rbuf = ((data >> 24) & 0xff);
+               data <<= 8;
+               rbuf++;
+               rlen--;
+       }
+       return 0;
+}
+
+#define DDB_MAGIC 'd'
+
+struct ddb_flashio {
+       __u8 *write_buf;
+       __u32 write_len;
+       __u8 *read_buf;
+       __u32 read_len;
+};
+
+#define IOCTL_DDB_FLASHIO  _IOWR(DDB_MAGIC, 0x00, struct ddb_flashio)
+
+#define DDB_NAME "ddbridge"
+
+static u32 ddb_num;
+static struct ddb *ddbs[32];
+static struct class *ddb_class;
+static int ddb_major;
+
+static int ddb_open(struct inode *inode, struct file *file)
+{
+       struct ddb *dev = ddbs[iminor(inode)];
+
+       file->private_data = dev;
+       return 0;
+}
+
+static long ddb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct ddb *dev = file->private_data;
+       void *parg = (void *)arg;
+       int res = -EFAULT;
+
+       switch (cmd) {
+       case IOCTL_DDB_FLASHIO:
+       {
+               struct ddb_flashio fio;
+               u8 *rbuf, *wbuf;
+
+               if (copy_from_user(&fio, parg, sizeof(fio)))
+                       break;
+               if (fio.write_len + fio.read_len > 1028) {
+                       printk(KERN_ERR "IOBUF too small\n");
+                       return -ENOMEM;
+               }
+               wbuf = &dev->iobuf[0];
+               if (!wbuf)
+                       return -ENOMEM;
+               rbuf = wbuf + fio.write_len;
+               if (copy_from_user(wbuf, fio.write_buf, fio.write_len)) {
+                       vfree(wbuf);
+                       break;
+               }
+               res = flashio(dev, wbuf, fio.write_len,
+                             rbuf, fio.read_len);
+               if (copy_to_user(fio.read_buf, rbuf, fio.read_len))
+                       res = -EFAULT;
+               break;
+       }
+       default:
+               break;
+       }
+       return res;
+}
+
+static const struct file_operations ddb_fops = {
+       .unlocked_ioctl = ddb_ioctl,
+       .open           = ddb_open,
+};
+
+static char *ddb_devnode(struct device *device, mode_t *mode)
+{
+       struct ddb *dev = dev_get_drvdata(device);
+
+       return kasprintf(GFP_KERNEL, "ddbridge/card%d", dev->nr);
+}
+
+static int ddb_class_create(void)
+{
+       ddb_major = register_chrdev(0, DDB_NAME, &ddb_fops);
+       if (ddb_major < 0)
+               return ddb_major;
+
+       ddb_class = class_create(THIS_MODULE, DDB_NAME);
+       if (IS_ERR(ddb_class)) {
+               unregister_chrdev(ddb_major, DDB_NAME);
+               return -1;
+       }
+       ddb_class->devnode = ddb_devnode;
+       return 0;
+}
+
+static void ddb_class_destroy(void)
+{
+       class_destroy(ddb_class);
+       unregister_chrdev(ddb_major, DDB_NAME);
+}
+
+static int ddb_device_create(struct ddb *dev)
+{
+       dev->nr = ddb_num++;
+       dev->ddb_dev = device_create(ddb_class, NULL,
+                                    MKDEV(ddb_major, dev->nr),
+                                    dev, "ddbridge%d", dev->nr);
+       ddbs[dev->nr] = dev;
+       if (IS_ERR(dev->ddb_dev))
+               return -1;
+       return 0;
+}
+
+static void ddb_device_destroy(struct ddb *dev)
+{
+       ddb_num--;
+       if (IS_ERR(dev->ddb_dev))
+               return;
+       device_destroy(ddb_class, MKDEV(ddb_major, 0));
+}
+
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+static void ddb_unmap(struct ddb *dev)
+{
+       if (dev->regs)
+               iounmap(dev->regs);
+       vfree(dev);
+}
+
+
+static void __devexit ddb_remove(struct pci_dev *pdev)
+{
+       struct ddb *dev = (struct ddb *) pci_get_drvdata(pdev);
+
+       ddb_ports_detach(dev);
+       ddb_i2c_release(dev);
+
+       ddbwritel(0, INTERRUPT_ENABLE);
+       free_irq(dev->pdev->irq, dev);
+#ifdef CONFIG_PCI_MSI
+       if (dev->msi)
+               pci_disable_msi(dev->pdev);
+#endif
+       ddb_ports_release(dev);
+       ddb_buffers_free(dev);
+       ddb_device_destroy(dev);
+
+       ddb_unmap(dev);
+       pci_set_drvdata(pdev, 0);
+       pci_disable_device(pdev);
+}
+
+
+static int __devinit ddb_probe(struct pci_dev *pdev,
+                              const struct pci_device_id *id)
+{
+       struct ddb *dev;
+       int stat = 0;
+       int irq_flag = IRQF_SHARED;
+
+       if (pci_enable_device(pdev) < 0)
+               return -ENODEV;
+
+       dev = vmalloc(sizeof(struct ddb));
+       if (dev == NULL)
+               return -ENOMEM;
+       memset(dev, 0, sizeof(struct ddb));
+
+       dev->pdev = pdev;
+       pci_set_drvdata(pdev, dev);
+       dev->info = (struct ddb_info *) id->driver_data;
+       printk(KERN_INFO "DDBridge driver detected: %s\n", dev->info->name);
+
+       dev->regs = ioremap(pci_resource_start(dev->pdev, 0),
+                           pci_resource_len(dev->pdev, 0));
+       if (!dev->regs) {
+               stat = -ENOMEM;
+               goto fail;
+       }
+       printk(KERN_INFO "HW %08x FW %08x\n", ddbreadl(0), ddbreadl(4));
+
+#ifdef CONFIG_PCI_MSI
+       if (pci_msi_enabled())
+               stat = pci_enable_msi(dev->pdev);
+       if (stat) {
+               printk(KERN_INFO ": MSI not available.\n");
+       } else {
+               irq_flag = 0;
+               dev->msi = 1;
+       }
+#endif
+       stat = request_irq(dev->pdev->irq, irq_handler,
+                          irq_flag, "DDBridge", (void *) dev);
+       if (stat < 0)
+               goto fail1;
+       ddbwritel(0, DMA_BASE_WRITE);
+       ddbwritel(0, DMA_BASE_READ);
+       ddbwritel(0xffffffff, INTERRUPT_ACK);
+       ddbwritel(0xfff0f, INTERRUPT_ENABLE);
+       ddbwritel(0, MSI1_ENABLE);
+
+       if (ddb_i2c_init(dev) < 0)
+               goto fail1;
+       ddb_ports_init(dev);
+       if (ddb_buffers_alloc(dev) < 0) {
+               printk(KERN_INFO ": Could not allocate buffer memory\n");
+               goto fail2;
+       }
+       if (ddb_ports_attach(dev) < 0)
+               goto fail3;
+       ddb_device_create(dev);
+       return 0;
+
+fail3:
+       ddb_ports_detach(dev);
+       printk(KERN_ERR "fail3\n");
+       ddb_ports_release(dev);
+fail2:
+       printk(KERN_ERR "fail2\n");
+       ddb_buffers_free(dev);
+fail1:
+       printk(KERN_ERR "fail1\n");
+       if (dev->msi)
+               pci_disable_msi(dev->pdev);
+       free_irq(dev->pdev->irq, dev);
+fail:
+       printk(KERN_ERR "fail\n");
+       ddb_unmap(dev);
+       pci_set_drvdata(pdev, 0);
+       pci_disable_device(pdev);
+       return -1;
+}
+
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+
+static struct ddb_info ddb_none = {
+       .type     = DDB_NONE,
+       .name     = "Digital Devices PCIe bridge",
+};
+
+static struct ddb_info ddb_octopus = {
+       .type     = DDB_OCTOPUS,
+       .name     = "Digital Devices Octopus DVB adapter",
+       .port_num = 4,
+};
+
+static struct ddb_info ddb_octopus_le = {
+       .type     = DDB_OCTOPUS,
+       .name     = "Digital Devices Octopus LE DVB adapter",
+       .port_num = 2,
+};
+
+static struct ddb_info ddb_v6 = {
+       .type     = DDB_OCTOPUS,
+       .name     = "Digital Devices Cine S2 V6 DVB adapter",
+       .port_num = 3,
+};
+
+#define DDVID 0xdd01 /* Digital Devices Vendor ID */
+
+#define DDB_ID(_vend, _dev, _subvend, _subdev, _driverdata) {  \
+       .vendor      = _vend,    .device    = _dev, \
+       .subvendor   = _subvend, .subdevice = _subdev, \
+       .driver_data = (unsigned long)&_driverdata }
+
+static const struct pci_device_id ddb_id_tbl[] __devinitdata = {
+       DDB_ID(DDVID, 0x0002, DDVID, 0x0001, ddb_octopus),
+       DDB_ID(DDVID, 0x0003, DDVID, 0x0001, ddb_octopus),
+       DDB_ID(DDVID, 0x0003, DDVID, 0x0002, ddb_octopus_le),
+       DDB_ID(DDVID, 0x0003, DDVID, 0x0010, ddb_octopus),
+       DDB_ID(DDVID, 0x0003, DDVID, 0x0020, ddb_v6),
+       /* in case sub-ids got deleted in flash */
+       DDB_ID(DDVID, 0x0003, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
+       {0}
+};
+MODULE_DEVICE_TABLE(pci, ddb_id_tbl);
+
+
+static struct pci_driver ddb_pci_driver = {
+       .name        = "DDBridge",
+       .id_table    = ddb_id_tbl,
+       .probe       = ddb_probe,
+       .remove      = ddb_remove,
+};
+
+static __init int module_init_ddbridge(void)
+{
+       printk(KERN_INFO "Digital Devices PCIE bridge driver, "
+              "Copyright (C) 2010-11 Digital Devices GmbH\n");
+       if (ddb_class_create())
+               return -1;
+       return pci_register_driver(&ddb_pci_driver);
+}
+
+static __exit void module_exit_ddbridge(void)
+{
+       pci_unregister_driver(&ddb_pci_driver);
+       ddb_class_destroy();
+}
+
+module_init(module_init_ddbridge);
+module_exit(module_exit_ddbridge);
+
+MODULE_DESCRIPTION("Digital Devices PCIe Bridge");
+MODULE_AUTHOR("Ralph Metzler");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.5");
diff --git a/drivers/media/dvb/ddbridge/ddbridge-regs.h b/drivers/media/dvb/ddbridge/ddbridge-regs.h
new file mode 100644 (file)
index 0000000..a3ccb31
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * ddbridge-regs.h: Digital Devices PCIe bridge driver
+ *
+ * Copyright (C) 2010-2011 Digital Devices GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+/* DD-DVBBridgeV1.h 273 2010-09-17 05:03:16Z manfred */
+
+/* Register Definitions */
+
+#define CUR_REGISTERMAP_VERSION 0x10000
+
+#define HARDWARE_VERSION       0x00
+#define REGISTERMAP_VERSION    0x04
+
+/* ------------------------------------------------------------------------- */
+/* SPI Controller */
+
+#define SPI_CONTROL     0x10
+#define SPI_DATA        0x14
+
+/* ------------------------------------------------------------------------- */
+
+/* Interrupt controller                                     */
+/* How many MSI's are available depends on HW (Min 2 max 8) */
+/* How many are usable also depends on Host platform        */
+
+#define INTERRUPT_BASE   (0x40)
+
+#define INTERRUPT_ENABLE (INTERRUPT_BASE + 0x00)
+#define MSI0_ENABLE      (INTERRUPT_BASE + 0x00)
+#define MSI1_ENABLE      (INTERRUPT_BASE + 0x04)
+#define MSI2_ENABLE      (INTERRUPT_BASE + 0x08)
+#define MSI3_ENABLE      (INTERRUPT_BASE + 0x0C)
+#define MSI4_ENABLE      (INTERRUPT_BASE + 0x10)
+#define MSI5_ENABLE      (INTERRUPT_BASE + 0x14)
+#define MSI6_ENABLE      (INTERRUPT_BASE + 0x18)
+#define MSI7_ENABLE      (INTERRUPT_BASE + 0x1C)
+
+#define INTERRUPT_STATUS (INTERRUPT_BASE + 0x20)
+#define INTERRUPT_ACK    (INTERRUPT_BASE + 0x20)
+
+#define INTMASK_I2C1        (0x00000001)
+#define INTMASK_I2C2        (0x00000002)
+#define INTMASK_I2C3        (0x00000004)
+#define INTMASK_I2C4        (0x00000008)
+
+#define INTMASK_CIRQ1       (0x00000010)
+#define INTMASK_CIRQ2       (0x00000020)
+#define INTMASK_CIRQ3       (0x00000040)
+#define INTMASK_CIRQ4       (0x00000080)
+
+#define INTMASK_TSINPUT1    (0x00000100)
+#define INTMASK_TSINPUT2    (0x00000200)
+#define INTMASK_TSINPUT3    (0x00000400)
+#define INTMASK_TSINPUT4    (0x00000800)
+#define INTMASK_TSINPUT5    (0x00001000)
+#define INTMASK_TSINPUT6    (0x00002000)
+#define INTMASK_TSINPUT7    (0x00004000)
+#define INTMASK_TSINPUT8    (0x00008000)
+
+#define INTMASK_TSOUTPUT1   (0x00010000)
+#define INTMASK_TSOUTPUT2   (0x00020000)
+#define INTMASK_TSOUTPUT3   (0x00040000)
+#define INTMASK_TSOUTPUT4   (0x00080000)
+
+/* ------------------------------------------------------------------------- */
+/* I2C Master Controller */
+
+#define I2C_BASE        (0x80)  /* Byte offset */
+
+#define I2C_COMMAND     (0x00)
+#define I2C_TIMING      (0x04)
+#define I2C_TASKLENGTH  (0x08)     /* High read, low write */
+#define I2C_TASKADDRESS (0x0C)     /* High read, low write */
+
+#define I2C_MONITOR     (0x1C)
+
+#define I2C_BASE_1      (I2C_BASE + 0x00)
+#define I2C_BASE_2      (I2C_BASE + 0x20)
+#define I2C_BASE_3      (I2C_BASE + 0x40)
+#define I2C_BASE_4      (I2C_BASE + 0x60)
+
+#define I2C_BASE_N(i)   (I2C_BASE + (i) * 0x20)
+
+#define I2C_TASKMEM_BASE    (0x1000)    /* Byte offset */
+#define I2C_TASKMEM_SIZE    (0x1000)
+
+#define I2C_SPEED_400   (0x04030404)
+#define I2C_SPEED_200   (0x09080909)
+#define I2C_SPEED_154   (0x0C0B0C0C)
+#define I2C_SPEED_100   (0x13121313)
+#define I2C_SPEED_77    (0x19181919)
+#define I2C_SPEED_50    (0x27262727)
+
+
+/* ------------------------------------------------------------------------- */
+/* DMA  Controller */
+
+#define DMA_BASE_WRITE        (0x100)
+#define DMA_BASE_READ         (0x140)
+
+#define DMA_CONTROL     (0x00)                  /* 64 */
+#define DMA_ERROR       (0x04)                  /* 65 ( only read instance ) */
+
+#define DMA_DIAG_CONTROL                (0x1C)  /* 71 */
+#define DMA_DIAG_PACKETCOUNTER_LOW      (0x20)  /* 72 */
+#define DMA_DIAG_PACKETCOUNTER_HIGH     (0x24)  /* 73 */
+#define DMA_DIAG_TIMECOUNTER_LOW        (0x28)  /* 74 */
+#define DMA_DIAG_TIMECOUNTER_HIGH       (0x2C)  /* 75 */
+#define DMA_DIAG_RECHECKCOUNTER         (0x30)  /* 76  ( Split completions on read ) */
+#define DMA_DIAG_WAITTIMEOUTINIT        (0x34)  /* 77 */
+#define DMA_DIAG_WAITOVERFLOWCOUNTER    (0x38)  /* 78 */
+#define DMA_DIAG_WAITCOUNTER            (0x3C)  /* 79 */
+
+/* ------------------------------------------------------------------------- */
+/* DMA  Buffer */
+
+#define TS_INPUT_BASE       (0x200)
+#define TS_INPUT_CONTROL(i)         (TS_INPUT_BASE + (i) * 16 + 0x00)
+
+#define TS_OUTPUT_BASE       (0x280)
+#define TS_OUTPUT_CONTROL(i)         (TS_OUTPUT_BASE + (i) * 16 + 0x00)
+
+#define DMA_BUFFER_BASE     (0x300)
+
+#define DMA_BUFFER_CONTROL(i)       (DMA_BUFFER_BASE + (i) * 16 + 0x00)
+#define DMA_BUFFER_ACK(i)           (DMA_BUFFER_BASE + (i) * 16 + 0x04)
+#define DMA_BUFFER_CURRENT(i)       (DMA_BUFFER_BASE + (i) * 16 + 0x08)
+#define DMA_BUFFER_SIZE(i)          (DMA_BUFFER_BASE + (i) * 16 + 0x0c)
+
+#define DMA_BASE_ADDRESS_TABLE  (0x2000)
+#define DMA_BASE_ADDRESS_TABLE_ENTRIES (512)
+
diff --git a/drivers/media/dvb/ddbridge/ddbridge.h b/drivers/media/dvb/ddbridge/ddbridge.h
new file mode 100644 (file)
index 0000000..6d14893
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * ddbridge.h: Digital Devices PCIe bridge driver
+ *
+ * Copyright (C) 2010-2011 Digital Devices GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef _DDBRIDGE_H_
+#define _DDBRIDGE_H_
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <asm/dma.h>
+#include <linux/dvb/frontend.h>
+#include <linux/dvb/ca.h>
+#include <linux/dvb/video.h>
+#include <linux/dvb/audio.h>
+#include <linux/socket.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_ringbuffer.h"
+#include "dvb_ca_en50221.h"
+#include "dvb_net.h"
+#include "cxd2099.h"
+
+#define DDB_MAX_I2C     4
+#define DDB_MAX_PORT    4
+#define DDB_MAX_INPUT   8
+#define DDB_MAX_OUTPUT  4
+
+struct ddb_info {
+       int   type;
+#define DDB_NONE         0
+#define DDB_OCTOPUS      1
+       char *name;
+       int   port_num;
+       u32   port_type[DDB_MAX_PORT];
+};
+
+/* DMA_SIZE MUST be divisible by 188 and 128 !!! */
+
+#define INPUT_DMA_MAX_BUFS 32      /* hardware table limit */
+#define INPUT_DMA_BUFS 8
+#define INPUT_DMA_SIZE (128*47*21)
+
+#define OUTPUT_DMA_MAX_BUFS 32
+#define OUTPUT_DMA_BUFS 8
+#define OUTPUT_DMA_SIZE (128*47*21)
+
+struct ddb;
+struct ddb_port;
+
+struct ddb_input {
+       struct ddb_port       *port;
+       u32                    nr;
+       int                    attached;
+
+       dma_addr_t             pbuf[INPUT_DMA_MAX_BUFS];
+       u8                    *vbuf[INPUT_DMA_MAX_BUFS];
+       u32                    dma_buf_num;
+       u32                    dma_buf_size;
+
+       struct tasklet_struct  tasklet;
+       spinlock_t             lock;
+       wait_queue_head_t      wq;
+       int                    running;
+       u32                    stat;
+       u32                    cbuf;
+       u32                    coff;
+
+       struct dvb_adapter     adap;
+       struct dvb_device     *dev;
+       struct dvb_frontend   *fe;
+       struct dvb_frontend   *fe2;
+       struct dmxdev          dmxdev;
+       struct dvb_demux       demux;
+       struct dvb_net         dvbnet;
+       struct dmx_frontend    hw_frontend;
+       struct dmx_frontend    mem_frontend;
+       int                    users;
+       int (*gate_ctrl)(struct dvb_frontend *, int);
+};
+
+struct ddb_output {
+       struct ddb_port       *port;
+       u32                    nr;
+       dma_addr_t             pbuf[OUTPUT_DMA_MAX_BUFS];
+       u8                    *vbuf[OUTPUT_DMA_MAX_BUFS];
+       u32                    dma_buf_num;
+       u32                    dma_buf_size;
+       struct tasklet_struct  tasklet;
+       spinlock_t             lock;
+       wait_queue_head_t      wq;
+       int                    running;
+       u32                    stat;
+       u32                    cbuf;
+       u32                    coff;
+
+       struct dvb_adapter     adap;
+       struct dvb_device     *dev;
+};
+
+struct ddb_i2c {
+       struct ddb            *dev;
+       u32                    nr;
+       struct i2c_adapter     adap;
+       struct i2c_adapter     adap2;
+       u32                    regs;
+       u32                    rbuf;
+       u32                    wbuf;
+       int                    done;
+       wait_queue_head_t      wq;
+};
+
+struct ddb_port {
+       struct ddb            *dev;
+       u32                    nr;
+       struct ddb_i2c        *i2c;
+       struct mutex           i2c_gate_lock;
+       u32                    class;
+#define DDB_PORT_NONE           0
+#define DDB_PORT_CI             1
+#define DDB_PORT_TUNER          2
+       u32                    type;
+#define DDB_TUNER_NONE          0
+#define DDB_TUNER_DVBS_ST       1
+#define DDB_TUNER_DVBS_ST_AA    2
+#define DDB_TUNER_DVBCT_TR     16
+#define DDB_TUNER_DVBCT_ST     17
+       u32                    adr;
+
+       struct ddb_input      *input[2];
+       struct ddb_output     *output;
+       struct dvb_ca_en50221 *en;
+};
+
+struct ddb {
+       struct pci_dev        *pdev;
+       unsigned char         *regs;
+       struct ddb_port        port[DDB_MAX_PORT];
+       struct ddb_i2c         i2c[DDB_MAX_I2C];
+       struct ddb_input       input[DDB_MAX_INPUT];
+       struct ddb_output      output[DDB_MAX_OUTPUT];
+
+       struct device         *ddb_dev;
+       int                    nr;
+       u8                     iobuf[1028];
+
+       struct ddb_info       *info;
+       int                    msi;
+};
+
+/****************************************************************************/
+
+#define ddbwritel(_val, _adr)        writel((_val), \
+                                    (char *) (dev->regs+(_adr)))
+#define ddbreadl(_adr)               readl((char *) (dev->regs+(_adr)))
+#define ddbcpyto(_adr, _src, _count) memcpy_toio((char *)      \
+                                    (dev->regs+(_adr)), (_src), (_count))
+#define ddbcpyfrom(_dst, _adr, _count) memcpy_fromio((_dst), (char *) \
+                                      (dev->regs+(_adr)), (_count))
+
+/****************************************************************************/
+
+#endif
index 0b51828..8f22bcd 100644 (file)
@@ -2,8 +2,10 @@
 # Makefile for the kernel DVB device drivers.
 #
 
+dvb-net-$(CONFIG_DVB_NET) := dvb_net.o
+
 dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o    \
                 dvb_ca_en50221.o dvb_frontend.o                \
-                dvb_net.o dvb_ringbuffer.o dvb_math.o
+                $(dvb-net-y) dvb_ringbuffer.o dvb_math.o
 
 obj-$(CONFIG_DVB_CORE) += dvb-core.o
index 5b6b451..efe9c30 100644 (file)
@@ -904,7 +904,7 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
        .buffer = b \
 }
 
-static struct dtv_cmds_h dtv_cmds[] = {
+static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
        _DTV_CMD(DTV_TUNE, 1, 0),
        _DTV_CMD(DTV_CLEAR, 1, 0),
 
@@ -966,6 +966,7 @@ static struct dtv_cmds_h dtv_cmds[] = {
        _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 0, 0),
 
        _DTV_CMD(DTV_ISDBS_TS_ID, 1, 0),
+       _DTV_CMD(DTV_DVBT2_PLP_ID, 1, 0),
 
        /* Get */
        _DTV_CMD(DTV_DISEQC_SLAVE_REPLY, 0, 1),
index 3a3126c..1e53acd 100644 (file)
@@ -32,6 +32,8 @@
 
 #define DVB_NET_DEVICES_MAX 10
 
+#ifdef CONFIG_DVB_NET
+
 struct dvb_net {
        struct dvb_device *dvbdev;
        struct net_device *device[DVB_NET_DEVICES_MAX];
@@ -40,8 +42,25 @@ struct dvb_net {
        struct dmx_demux *demux;
 };
 
-
 void dvb_net_release(struct dvb_net *);
 int  dvb_net_init(struct dvb_adapter *, struct dvb_net *, struct dmx_demux *);
 
+#else
+
+struct dvb_net {
+       struct dvb_device *dvbdev;
+};
+
+static inline void dvb_net_release(struct dvb_net *dvbnet)
+{
+}
+
+static inline int dvb_net_init(struct dvb_adapter *adap,
+                              struct dvb_net *dvbnet, struct dmx_demux *dmx)
+{
+       return 0;
+}
+
+#endif /* ifdef CONFIG_DVB_NET */
+
 #endif
index e85304c..5d73dec 100644 (file)
@@ -81,6 +81,7 @@ config DVB_USB_DIB0700
        select MEDIA_TUNER_MT2266 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
        help
          Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
index 100ebc3..d7ad05f 100644 (file)
@@ -91,7 +91,6 @@ static int af9015_rw_udev(struct usb_device *udev, struct req_t *req)
        case GET_CONFIG:
        case READ_MEMORY:
        case RECONNECT_USB:
-       case GET_IR_CODE:
                write = 0;
                break;
        case READ_I2C:
@@ -164,13 +163,6 @@ static int af9015_rw_udev(struct usb_device *udev, struct req_t *req)
        deb_xfer("<<< ");
        debug_dump(buf, act_len, deb_xfer);
 
-       /* remote controller query status is 1 if remote code is not received */
-       if (req->cmd == GET_IR_CODE && buf[1] == 1) {
-               buf[1] = 0; /* clear command "error" status */
-               memset(&buf[2], 0, req->data_len);
-               buf[3] = 1; /* no remote code received mark */
-       }
-
        /* check status */
        if (buf[1]) {
                err("command failed:%d", buf[1]);
@@ -292,6 +284,10 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate.
                }
 
                if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
+                       if (msg[i].len > 3 || msg[i+1].len > 61) {
+                               ret = -EOPNOTSUPP;
+                               goto error;
+                       }
                        if (msg[i].addr ==
                                af9015_af9013_config[0].demod_address)
                                req.cmd = READ_MEMORY;
@@ -306,12 +302,16 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate.
                        ret = af9015_ctrl_msg(d, &req);
                        i += 2;
                } else if (msg[i].flags & I2C_M_RD) {
-                       ret = -EINVAL;
+                       if (msg[i].len > 61) {
+                               ret = -EOPNOTSUPP;
+                               goto error;
+                       }
                        if (msg[i].addr ==
-                               af9015_af9013_config[0].demod_address)
+                               af9015_af9013_config[0].demod_address) {
+                               ret = -EINVAL;
                                goto error;
-                       else
-                               req.cmd = READ_I2C;
+                       }
+                       req.cmd = READ_I2C;
                        req.i2c_addr = msg[i].addr;
                        req.addr = addr;
                        req.mbox = mbox;
@@ -321,6 +321,10 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate.
                        ret = af9015_ctrl_msg(d, &req);
                        i += 1;
                } else {
+                       if (msg[i].len > 21) {
+                               ret = -EOPNOTSUPP;
+                               goto error;
+                       }
                        if (msg[i].addr ==
                                af9015_af9013_config[0].demod_address)
                                req.cmd = WRITE_MEMORY;
@@ -735,6 +739,7 @@ static const struct af9015_rc_setup af9015_rc_setup_hashes[] = {
        { 0xb8feb708, RC_MAP_MSI_DIGIVOX_II },
        { 0xa3703d00, RC_MAP_ALINK_DTU_M },
        { 0x9b7dc64e, RC_MAP_TOTAL_MEDIA_IN_HAND }, /* MYGICTV U718 */
+       { 0x5d49e3db, RC_MAP_DIGITTRADE }, /* LC-Power LC-USB-DVBT */
        { }
 };
 
@@ -749,6 +754,8 @@ static const struct af9015_rc_setup af9015_rc_setup_usbids[] = {
                RC_MAP_AZUREWAVE_AD_TU700 },
        { (USB_VID_MSI_2 << 16) + USB_PID_MSI_DIGI_VOX_MINI_III,
                RC_MAP_MSI_DIGIVOX_III },
+       { (USB_VID_MSI_2 << 16) + USB_PID_MSI_DIGIVOX_DUO,
+               RC_MAP_MSI_DIGIVOX_III },
        { (USB_VID_LEADTEK << 16) + USB_PID_WINFAST_DTV_DONGLE_GOLD,
                RC_MAP_LEADTEK_Y04G0051 },
        { (USB_VID_AVERMEDIA << 16) + USB_PID_AVERMEDIA_VOLAR_X,
@@ -759,6 +766,8 @@ static const struct af9015_rc_setup af9015_rc_setup_usbids[] = {
                RC_MAP_DIGITALNOW_TINYTWIN },
        { (USB_VID_GTEK << 16) + USB_PID_TINYTWIN_3,
                RC_MAP_DIGITALNOW_TINYTWIN },
+       { (USB_VID_KWORLD_2 << 16) + USB_PID_SVEON_STV22,
+               RC_MAP_MSI_DIGIVOX_III },
        { }
 };
 
@@ -1082,44 +1091,11 @@ error:
        return ret;
 }
 
-/* init 2nd I2C adapter */
-static int af9015_i2c_init(struct dvb_usb_device *d)
-{
-       int ret;
-       struct af9015_state *state = d->priv;
-       deb_info("%s:\n", __func__);
-
-       strncpy(state->i2c_adap.name, d->desc->name,
-               sizeof(state->i2c_adap.name));
-       state->i2c_adap.algo      = d->props.i2c_algo;
-       state->i2c_adap.algo_data = NULL;
-       state->i2c_adap.dev.parent = &d->udev->dev;
-
-       i2c_set_adapdata(&state->i2c_adap, d);
-
-       ret = i2c_add_adapter(&state->i2c_adap);
-       if (ret < 0)
-               err("could not add i2c adapter");
-
-       return ret;
-}
-
 static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
 {
        int ret;
-       struct af9015_state *state = adap->dev->priv;
-       struct i2c_adapter *i2c_adap;
-
-       if (adap->id == 0) {
-               /* select I2C adapter */
-               i2c_adap = &adap->dev->i2c_adap;
-
-               deb_info("%s: init I2C\n", __func__);
-               ret = af9015_i2c_init(adap->dev);
-       } else {
-               /* select I2C adapter */
-               i2c_adap = &state->i2c_adap;
 
+       if (adap->id == 1) {
                /* copy firmware to 2nd demodulator */
                if (af9015_config.dual_mode) {
                        ret = af9015_copy_firmware(adap->dev);
@@ -1136,7 +1112,7 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
 
        /* attach demodulator */
        adap->fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id],
-               i2c_adap);
+               &adap->dev->i2c_adap);
 
        return adap->fe == NULL ? -ENODEV : 0;
 }
@@ -1206,57 +1182,56 @@ static struct mxl5007t_config af9015_mxl5007t_config = {
 
 static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       struct af9015_state *state = adap->dev->priv;
-       struct i2c_adapter *i2c_adap;
        int ret;
        deb_info("%s:\n", __func__);
 
-       /* select I2C adapter */
-       if (adap->id == 0)
-               i2c_adap = &adap->dev->i2c_adap;
-       else
-               i2c_adap = &state->i2c_adap;
-
        switch (af9015_af9013_config[adap->id].tuner) {
        case AF9013_TUNER_MT2060:
        case AF9013_TUNER_MT2060_2:
-               ret = dvb_attach(mt2060_attach, adap->fe, i2c_adap,
+               ret = dvb_attach(mt2060_attach, adap->fe, &adap->dev->i2c_adap,
                        &af9015_mt2060_config,
                        af9015_config.mt2060_if1[adap->id])
                        == NULL ? -ENODEV : 0;
                break;
        case AF9013_TUNER_QT1010:
        case AF9013_TUNER_QT1010A:
-               ret = dvb_attach(qt1010_attach, adap->fe, i2c_adap,
+               ret = dvb_attach(qt1010_attach, adap->fe, &adap->dev->i2c_adap,
                        &af9015_qt1010_config) == NULL ? -ENODEV : 0;
                break;
        case AF9013_TUNER_TDA18271:
-               ret = dvb_attach(tda18271_attach, adap->fe, 0xc0, i2c_adap,
+               ret = dvb_attach(tda18271_attach, adap->fe, 0xc0,
+                       &adap->dev->i2c_adap,
                        &af9015_tda18271_config) == NULL ? -ENODEV : 0;
                break;
        case AF9013_TUNER_TDA18218:
-               ret = dvb_attach(tda18218_attach, adap->fe, i2c_adap,
+               ret = dvb_attach(tda18218_attach, adap->fe,
+                       &adap->dev->i2c_adap,
                        &af9015_tda18218_config) == NULL ? -ENODEV : 0;
                break;
        case AF9013_TUNER_MXL5003D:
-               ret = dvb_attach(mxl5005s_attach, adap->fe, i2c_adap,
+               ret = dvb_attach(mxl5005s_attach, adap->fe,
+                       &adap->dev->i2c_adap,
                        &af9015_mxl5003_config) == NULL ? -ENODEV : 0;
                break;
        case AF9013_TUNER_MXL5005D:
        case AF9013_TUNER_MXL5005R:
-               ret = dvb_attach(mxl5005s_attach, adap->fe, i2c_adap,
+               ret = dvb_attach(mxl5005s_attach, adap->fe,
+                       &adap->dev->i2c_adap,
                        &af9015_mxl5005_config) == NULL ? -ENODEV : 0;
                break;
        case AF9013_TUNER_ENV77H11D5:
-               ret = dvb_attach(dvb_pll_attach, adap->fe, 0xc0, i2c_adap,
+               ret = dvb_attach(dvb_pll_attach, adap->fe, 0xc0,
+                       &adap->dev->i2c_adap,
                        DVB_PLL_TDA665X) == NULL ? -ENODEV : 0;
                break;
        case AF9013_TUNER_MC44S803:
-               ret = dvb_attach(mc44s803_attach, adap->fe, i2c_adap,
+               ret = dvb_attach(mc44s803_attach, adap->fe,
+                       &adap->dev->i2c_adap,
                        &af9015_mc44s803_config) == NULL ? -ENODEV : 0;
                break;
        case AF9013_TUNER_MXL5007T:
-               ret = dvb_attach(mxl5007t_attach, adap->fe, i2c_adap,
+               ret = dvb_attach(mxl5007t_attach, adap->fe,
+                       &adap->dev->i2c_adap,
                        0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0;
                break;
        case AF9013_TUNER_UNKNOWN:
@@ -1309,6 +1284,7 @@ static struct usb_device_id af9015_usb_table[] = {
                USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC)},
 /* 35 */{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T)},
        {USB_DEVICE(USB_VID_GTEK,      USB_PID_TINYTWIN_3)},
+       {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_SVEON_STV22)},
        {0},
 };
 MODULE_DEVICE_TABLE(usb, af9015_usb_table);
@@ -1502,7 +1478,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
 
                .i2c_algo = &af9015_i2c_algo,
 
-               .num_device_descs = 9, /* check max from dvb-usb.h */
+               .num_device_descs = 10, /* check max from dvb-usb.h */
                .devices = {
                        {
                                .name = "Xtensions XD-380",
@@ -1554,6 +1530,11 @@ static struct dvb_usb_device_properties af9015_properties[] = {
                                .cold_ids = {&af9015_usb_table[20], NULL},
                                .warm_ids = {NULL},
                        },
+                       {
+                               .name = "Sveon STV22 Dual USB DVB-T Tuner HDTV",
+                               .cold_ids = {&af9015_usb_table[37], NULL},
+                               .warm_ids = {NULL},
+                       },
                }
        }, {
                .caps = DVB_USB_IS_AN_I2C_ADAPTER,
@@ -1704,33 +1685,11 @@ static int af9015_usb_probe(struct usb_interface *intf,
        return ret;
 }
 
-static void af9015_i2c_exit(struct dvb_usb_device *d)
-{
-       struct af9015_state *state = d->priv;
-       deb_info("%s:\n", __func__);
-
-       /* remove 2nd I2C adapter */
-       if (d->state & DVB_USB_STATE_I2C)
-               i2c_del_adapter(&state->i2c_adap);
-}
-
-static void af9015_usb_device_exit(struct usb_interface *intf)
-{
-       struct dvb_usb_device *d = usb_get_intfdata(intf);
-       deb_info("%s:\n", __func__);
-
-       /* remove 2nd I2C adapter */
-       if (d != NULL && d->desc != NULL)
-               af9015_i2c_exit(d);
-
-       dvb_usb_device_exit(intf);
-}
-
 /* usb specific object needed to register this driver with the usb subsystem */
 static struct usb_driver af9015_usb_driver = {
        .name = "dvb_usb_af9015",
        .probe = af9015_usb_probe,
-       .disconnect = af9015_usb_device_exit,
+       .disconnect = dvb_usb_device_exit,
        .id_table = af9015_usb_table,
 };
 
index beb3004..6252ea6 100644 (file)
@@ -99,7 +99,6 @@ enum af9015_ir_mode {
 };
 
 struct af9015_state {
-       struct i2c_adapter i2c_adap; /* I2C adapter for 2nd FE */
        u8 rc_repeat;
        u32 rc_keycode;
        u8 rc_last[4];
index 7c327b5..2cbf19a 100644 (file)
@@ -347,15 +347,17 @@ static struct isl6423_config anysee_isl6423_config = {
  * PCB: ?
  * parts: DNOS404ZH102A(MT352, DTT7579(?))
  *
- * E30 VID=04b4 PID=861f HW=2 FW=2.1 Product=????????
- * PCB: ?
+ * E30 VID=04b4 PID=861f HW=2 FW=2.1 "anysee-T(LP)"
+ * PCB: PCB 507T (rev1.61)
  * parts: DNOS404ZH103A(ZL10353, DTT7579(?))
+ * OEA=0a OEB=00 OEC=00 OED=ff OEE=00
+ * IOA=45 IOB=ff IOC=00 IOD=ff IOE=00
  *
  * E30 Plus VID=04b4 PID=861f HW=6 FW=1.0 "anysee"
  * PCB: 507CD (rev1.1)
  * parts: DNOS404ZH103A(ZL10353, DTT7579(?)), CST56I01
- * OEA=80 OEB=00 OEC=00 OED=ff OEF=fe
- * IOA=4f IOB=ff IOC=00 IOD=06 IOF=01
+ * OEA=80 OEB=00 OEC=00 OED=ff OEE=fe
+ * IOA=4f IOB=ff IOC=00 IOD=06 IOE=01
  * IOD[0] ZL10353 1=enabled
  * IOA[7] TS 0=enabled
  * tuner is not behind ZL10353 I2C-gate (no care if gate disabled or not)
@@ -363,30 +365,30 @@ static struct isl6423_config anysee_isl6423_config = {
  * E30 C Plus VID=04b4 PID=861f HW=10 FW=1.0 "anysee-DC(LP)"
  * PCB: 507DC (rev0.2)
  * parts: TDA10023, DTOS403IH102B TM, CST56I01
- * OEA=80 OEB=00 OEC=00 OED=ff OEF=fe
- * IOA=4f IOB=ff IOC=00 IOD=26 IOF=01
+ * OEA=80 OEB=00 OEC=00 OED=ff OEE=fe
+ * IOA=4f IOB=ff IOC=00 IOD=26 IOE=01
  * IOD[0] TDA10023 1=enabled
  *
  * E30 S2 Plus VID=04b4 PID=861f HW=11 FW=0.1 "anysee-S2(LP)"
  * PCB: 507SI (rev2.1)
  * parts: BS2N10WCC01(CX24116, CX24118), ISL6423, TDA8024
- * OEA=80 OEB=00 OEC=ff OED=ff OEF=fe
- * IOA=4d IOB=ff IOC=00 IOD=26 IOF=01
+ * OEA=80 OEB=00 OEC=ff OED=ff OEE=fe
+ * IOA=4d IOB=ff IOC=00 IOD=26 IOE=01
  * IOD[0] CX24116 1=enabled
  *
  * E30 C Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)"
  * PCB: 507FA (rev0.4)
  * parts: TDA10023, DTOS403IH102B TM, TDA8024
- * OEA=80 OEB=00 OEC=ff OED=ff OEF=ff
- * IOA=4d IOB=ff IOC=00 IOD=00 IOF=c0
+ * OEA=80 OEB=00 OEC=ff OED=ff OEE=ff
+ * IOA=4d IOB=ff IOC=00 IOD=00 IOE=c0
  * IOD[5] TDA10023 1=enabled
  * IOE[0] tuner 1=enabled
  *
  * E30 Combo Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)"
  * PCB: 507FA (rev1.1)
  * parts: ZL10353, TDA10023, DTOS403IH102B TM, TDA8024
- * OEA=80 OEB=00 OEC=ff OED=ff OEF=ff
- * IOA=4d IOB=ff IOC=00 IOD=00 IOF=c0
+ * OEA=80 OEB=00 OEC=ff OED=ff OEE=ff
+ * IOA=4d IOB=ff IOC=00 IOD=00 IOE=c0
  * DVB-C:
  * IOD[5] TDA10023 1=enabled
  * IOE[0] tuner 1=enabled
@@ -398,8 +400,8 @@ static struct isl6423_config anysee_isl6423_config = {
  * E7 TC VID=1c73 PID=861f HW=18 FW=0.7 AMTCI=0.5 "anysee-E7TC(LP)"
  * PCB: 508TC (rev0.6)
  * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212)
- * OEA=80 OEB=00 OEC=03 OED=f7 OEF=ff
- * IOA=4d IOB=00 IOC=cc IOD=48 IOF=e4
+ * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff
+ * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4
  * IOA[7] TS 1=enabled
  * IOE[4] TDA18212 1=enabled
  * DVB-C:
@@ -414,11 +416,34 @@ static struct isl6423_config anysee_isl6423_config = {
  * E7 S2 VID=1c73 PID=861f HW=19 FW=0.4 AMTCI=0.5 "anysee-E7S2(LP)"
  * PCB: 508S2 (rev0.7)
  * parts: DNBU10512IST(STV0903, STV6110), ISL6423
- * OEA=80 OEB=00 OEC=03 OED=f7 OEF=ff
- * IOA=4d IOB=00 IOC=c4 IOD=08 IOF=e4
+ * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff
+ * IOA=4d IOB=00 IOC=c4 IOD=08 IOE=e4
  * IOA[7] TS 1=enabled
  * IOE[5] STV0903 1=enabled
  *
+ * E7 PTC VID=1c73 PID=861f HW=21 FW=0.1 AMTCI=?? "anysee-E7PTC(LP)"
+ * PCB: 508PTC (rev0.5)
+ * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212)
+ * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff
+ * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4
+ * IOA[7] TS 1=enabled
+ * IOE[4] TDA18212 1=enabled
+ * DVB-C:
+ * IOD[6] ZL10353 0=disabled
+ * IOD[5] TDA10023 1=enabled
+ * IOE[0] IF 1=enabled
+ * DVB-T:
+ * IOD[5] TDA10023 0=disabled
+ * IOD[6] ZL10353 1=enabled
+ * IOE[0] IF 0=enabled
+ *
+ * E7 S2 VID=1c73 PID=861f HW=22 FW=0.1 AMTCI=?? "anysee-E7PS2(LP)"
+ * PCB: 508PS2 (rev0.4)
+ * parts: DNBU10512IST(STV0903, STV6110), ISL6423
+ * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff
+ * IOA=4d IOB=00 IOC=c4 IOD=08 IOE=e4
+ * IOA[7] TS 1=enabled
+ * IOE[5] STV0903 1=enabled
  */
 
 static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
@@ -459,7 +484,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
        state->hw = hw_info[0];
 
        switch (state->hw) {
-       case ANYSEE_HW_02: /* 2 */
+       case ANYSEE_HW_507T: /* 2 */
                /* E30 */
 
                /* attach demod */
@@ -593,7 +618,9 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
 
                break;
        case ANYSEE_HW_508TC: /* 18 */
+       case ANYSEE_HW_508PTC: /* 21 */
                /* E7 TC */
+               /* E7 PTC */
 
                /* enable transport stream on IOA[7] */
                ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80);
@@ -650,7 +677,9 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
 
                break;
        case ANYSEE_HW_508S2: /* 19 */
+       case ANYSEE_HW_508PS2: /* 22 */
                /* E7 S2 */
+               /* E7 PS2 */
 
                /* enable transport stream on IOA[7] */
                ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80);
@@ -687,7 +716,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
        deb_info("%s:\n", __func__);
 
        switch (state->hw) {
-       case ANYSEE_HW_02: /* 2 */
+       case ANYSEE_HW_507T: /* 2 */
                /* E30 */
 
                /* attach tuner */
@@ -762,7 +791,9 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
 
                break;
        case ANYSEE_HW_508TC: /* 18 */
+       case ANYSEE_HW_508PTC: /* 21 */
                /* E7 TC */
+               /* E7 PTC */
 
                /* enable tuner on IOE[4] */
                ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10);
@@ -775,7 +806,9 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
 
                break;
        case ANYSEE_HW_508S2: /* 19 */
+       case ANYSEE_HW_508PS2: /* 22 */
                /* E7 S2 */
+               /* E7 PS2 */
 
                /* attach tuner */
                fe = dvb_attach(stv6110_attach, adap->fe,
index a7673aa..ad6ccd1 100644 (file)
@@ -61,13 +61,15 @@ struct anysee_state {
        u8 seq;
 };
 
-#define ANYSEE_HW_02     2 /* E30 */
-#define ANYSEE_HW_507CD  6 /* E30 Plus */
-#define ANYSEE_HW_507DC 10 /* E30 C Plus */
-#define ANYSEE_HW_507SI 11 /* E30 S2 Plus */
-#define ANYSEE_HW_507FA 15 /* E30 Combo Plus / E30 C Plus */
-#define ANYSEE_HW_508TC 18 /* E7 TC */
-#define ANYSEE_HW_508S2 19 /* E7 S2 */
+#define ANYSEE_HW_507T    2 /* E30 */
+#define ANYSEE_HW_507CD   6 /* E30 Plus */
+#define ANYSEE_HW_507DC  10 /* E30 C Plus */
+#define ANYSEE_HW_507SI  11 /* E30 S2 Plus */
+#define ANYSEE_HW_507FA  15 /* E30 Combo Plus / E30 C Plus */
+#define ANYSEE_HW_508TC  18 /* E7 TC */
+#define ANYSEE_HW_508S2  19 /* E7 S2 */
+#define ANYSEE_HW_508PTC 21 /* E7 PTC Plus */
+#define ANYSEE_HW_508PS2 22 /* E7 PS2 Plus */
 
 #define REG_IOA       0x80 /* Port A (bit addressable) */
 #define REG_IOB       0x90 /* Port B (bit addressable) */
index c519ad5..d0ea5b6 100644 (file)
@@ -17,6 +17,7 @@
 #include "mt2266.h"
 #include "tuner-xc2028.h"
 #include "xc5000.h"
+#include "xc4000.h"
 #include "s5h1411.h"
 #include "dib0070.h"
 #include "dib0090.h"
@@ -2655,6 +2656,156 @@ static int xc5000_tuner_attach(struct dvb_usb_adapter *adap)
                == NULL ? -ENODEV : 0;
 }
 
+static int dib0700_xc4000_tuner_callback(void *priv, int component,
+                                        int command, int arg)
+{
+       struct dvb_usb_adapter *adap = priv;
+
+       if (command == XC4000_TUNER_RESET) {
+               /* Reset the tuner */
+               dib7000p_set_gpio(adap->fe, 8, 0, 0);
+               msleep(10);
+               dib7000p_set_gpio(adap->fe, 8, 0, 1);
+       } else {
+               err("xc4000: unknown tuner callback command: %d\n", command);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct dibx000_agc_config stk7700p_7000p_xc4000_agc_config = {
+       .band_caps = BAND_UHF | BAND_VHF,
+       .setup = 0x64,
+       .inv_gain = 0x02c8,
+       .time_stabiliz = 0x15,
+       .alpha_level = 0x00,
+       .thlock = 0x76,
+       .wbd_inv = 0x01,
+       .wbd_ref = 0x0b33,
+       .wbd_sel = 0x00,
+       .wbd_alpha = 0x02,
+       .agc1_max = 0x00,
+       .agc1_min = 0x00,
+       .agc2_max = 0x9b26,
+       .agc2_min = 0x26ca,
+       .agc1_pt1 = 0x00,
+       .agc1_pt2 = 0x00,
+       .agc1_pt3 = 0x00,
+       .agc1_slope1 = 0x00,
+       .agc1_slope2 = 0x00,
+       .agc2_pt1 = 0x00,
+       .agc2_pt2 = 0x80,
+       .agc2_slope1 = 0x1d,
+       .agc2_slope2 = 0x1d,
+       .alpha_mant = 0x11,
+       .alpha_exp = 0x1b,
+       .beta_mant = 0x17,
+       .beta_exp = 0x33,
+       .perform_agc_softsplit = 0x00,
+};
+
+static struct dibx000_bandwidth_config stk7700p_xc4000_pll_config = {
+       60000, 30000,   /* internal, sampling */
+       1, 8, 3, 1, 0,  /* pll_cfg: prediv, ratio, range, reset, bypass */
+       0, 0, 1, 1, 0,  /* misc: refdiv, bypclk_div, IO_CLK_en_core, */
+                       /* ADClkSrc, modulo */
+       (3 << 14) | (1 << 12) | 524,    /* sad_cfg: refsel, sel, freq_15k */
+       39370534,       /* ifreq */
+       20452225,       /* timf */
+       30000000        /* xtal */
+};
+
+/* FIXME: none of these inputs are validated yet */
+static struct dib7000p_config pctv_340e_config = {
+       .output_mpeg2_in_188_bytes = 1,
+
+       .agc_config_count = 1,
+       .agc = &stk7700p_7000p_xc4000_agc_config,
+       .bw  = &stk7700p_xc4000_pll_config,
+
+       .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS,
+       .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES,
+       .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS,
+};
+
+/* PCTV 340e GPIOs map:
+   dib0700:
+   GPIO2  - CX25843 sleep
+   GPIO3  - CS5340 reset
+   GPIO5  - IRD
+   GPIO6  - Power Supply
+   GPIO8  - LNA (1=off 0=on)
+   GPIO10 - CX25843 reset
+   dib7000:
+   GPIO8  - xc4000 reset
+ */
+static int pctv340e_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       struct dib0700_state *st = adap->dev->priv;
+
+       /* Power Supply on */
+       dib0700_set_gpio(adap->dev, GPIO6,  GPIO_OUT, 0);
+       msleep(50);
+       dib0700_set_gpio(adap->dev, GPIO6,  GPIO_OUT, 1);
+       msleep(100); /* Allow power supply to settle before probing */
+
+       /* cx25843 reset */
+       dib0700_set_gpio(adap->dev, GPIO10,  GPIO_OUT, 0);
+       msleep(1); /* cx25843 datasheet say 350us required */
+       dib0700_set_gpio(adap->dev, GPIO10,  GPIO_OUT, 1);
+
+       /* LNA off for now */
+       dib0700_set_gpio(adap->dev, GPIO8,  GPIO_OUT, 1);
+
+       /* Put the CX25843 to sleep for now since we're in digital mode */
+       dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 1);
+
+       /* FIXME: not verified yet */
+       dib0700_ctrl_clock(adap->dev, 72, 1);
+
+       msleep(500);
+
+       if (dib7000pc_detection(&adap->dev->i2c_adap) == 0) {
+               /* Demodulator not found for some reason? */
+               return -ENODEV;
+       }
+
+       adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x12,
+                             &pctv_340e_config);
+       st->is_dib7000pc = 1;
+
+       return adap->fe == NULL ? -ENODEV : 0;
+}
+
+static struct xc4000_config dib7000p_xc4000_tunerconfig = {
+       .i2c_address      = 0x61,
+       .default_pm       = 1,
+       .dvb_amplitude    = 0,
+       .set_smoothedcvbs = 0,
+       .if_khz           = 5400
+};
+
+static int xc4000_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       struct i2c_adapter *tun_i2c;
+
+       /* The xc4000 is not on the main i2c bus */
+       tun_i2c = dib7000p_get_i2c_master(adap->fe,
+                                         DIBX000_I2C_INTERFACE_TUNER, 1);
+       if (tun_i2c == NULL) {
+               printk(KERN_ERR "Could not reach tuner i2c bus\n");
+               return 0;
+       }
+
+       /* Setup the reset callback */
+       adap->fe->callback = dib0700_xc4000_tuner_callback;
+
+       return dvb_attach(xc4000_attach, adap->fe, tun_i2c,
+                         &dib7000p_xc4000_tunerconfig)
+               == NULL ? -ENODEV : 0;
+}
+
 static struct lgdt3305_config hcw_lgdt3305_config = {
        .i2c_addr           = 0x0e,
        .mpeg_mode          = LGDT3305_MPEG_PARALLEL,
@@ -2802,6 +2953,8 @@ struct usb_device_id dib0700_usb_id_table[] = {
        { USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_TFE7090PVR) },
        { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2) },
 /* 75 */{ USB_DEVICE(USB_VID_MEDION,    USB_PID_CREATIX_CTX1921) },
+       { USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV340E) },
+       { USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV340E_SE) },
        { 0 }           /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -3762,6 +3915,41 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        },
                },
 
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+                       .module_name      = "dib0700",
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .allowed_protos   = RC_TYPE_RC5 |
+                                           RC_TYPE_RC6 |
+                                           RC_TYPE_NEC,
+                       .change_protocol  = dib0700_change_protocol,
+               },
+       }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+               .num_adapters = 1,
+               .adapter = {
+                       {
+                               .frontend_attach  = pctv340e_frontend_attach,
+                               .tuner_attach     = xc4000_tuner_attach,
+
+                               DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+                               .size_of_priv = sizeof(struct
+                                               dib0700_adapter_state),
+                       },
+               },
+
+               .num_device_descs = 2,
+               .devices = {
+                       {   "Pinnacle PCTV 340e HD Pro USB Stick",
+                               { &dib0700_usb_id_table[76], NULL },
+                               { NULL },
+                       },
+                       {   "Pinnacle PCTV Hybrid Stick Solo",
+                               { &dib0700_usb_id_table[77], NULL },
+                               { NULL },
+                       },
+               },
                .rc.core = {
                        .rc_interval      = DEFAULT_RC_INTERVAL,
                        .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
index 21b1549..2a79b8f 100644 (file)
 #define USB_PID_PINNACLE_PCTV310E                      0x3211
 #define USB_PID_PINNACLE_PCTV801E                      0x023a
 #define USB_PID_PINNACLE_PCTV801E_SE                   0x023b
+#define USB_PID_PINNACLE_PCTV340E                      0x023d
+#define USB_PID_PINNACLE_PCTV340E_SE                   0x023e
 #define USB_PID_PINNACLE_PCTV73A                       0x0243
 #define USB_PID_PINNACLE_PCTV73ESE                     0x0245
 #define USB_PID_PINNACLE_PCTV74E                       0x0246
 #define USB_PID_FRIIO_WHITE                            0x0001
 #define USB_PID_TVWAY_PLUS                             0x0002
 #define USB_PID_SVEON_STV20                            0xe39d
+#define USB_PID_SVEON_STV22                            0xe401
 #define USB_PID_AZUREWAVE_AZ6027                       0x3275
 #define USB_PID_TERRATEC_DVBS2CI_V1                    0x10a4
 #define USB_PID_TERRATEC_DVBS2CI_V2                    0x10ac
index 76a8096..7d35d07 100644 (file)
@@ -85,7 +85,7 @@ static inline u8 rc5_data(struct rc_map_table *key)
        return key->scancode & 0xff;
 }
 
-static inline u8 rc5_scan(struct rc_map_table *key)
+static inline u16 rc5_scan(struct rc_map_table *key)
 {
        return key->scancode & 0xffff;
 }
index 831749a..ed32b9d 100644 (file)
@@ -78,9 +78,6 @@ extern int dvb_usb_gp8psk_debug;
 #define ADV_MOD_DVB_BPSK 9     /* DVB-S BPSK */
 
 #define GET_USB_SPEED                     0x07
- #define USB_SPEED_LOW                    0
- #define USB_SPEED_FULL                   1
- #define USB_SPEED_HIGH                   2
 
 #define RESET_FX2                         0x13
 
index 08f8842..473b95e 100644 (file)
@@ -765,10 +765,8 @@ static void technisat_usb2_disconnect(struct usb_interface *intf)
        /* work and stuff was only created when the device is is hot-state */
        if (dev != NULL) {
                struct technisat_usb2_state *state = dev->priv;
-               if (state != NULL) {
+               if (state != NULL)
                        cancel_delayed_work_sync(&state->green_led_work);
-                       flush_scheduled_work();
-               }
        }
 
        dvb_usb_device_exit(intf);
index 969688f..cf5ec46 100644 (file)
@@ -36,9 +36,6 @@
  #define Tuner_Power_OFF                  0
 
 #define GET_USB_SPEED                     0x07
- #define USB_SPEED_LOW                    0
- #define USB_SPEED_FULL                   1
- #define USB_SPEED_HIGH                   2
 
 #define LOCK_TUNER_COMMAND                0x09
 
index 21c52e3..489ae82 100644 (file)
@@ -1208,7 +1208,7 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
        if (r->response != AVC_RESPONSE_ACCEPTED) {
                dev_err(fdtv->device,
                        "CA PMT failed with response 0x%x\n", r->response);
-               ret = -EFAULT;
+               ret = -EACCES;
        }
 out:
        mutex_unlock(&fdtv->avc_mutex);
index 8ffb565..e5ebdbf 100644 (file)
@@ -45,11 +45,6 @@ static int fdtv_get_ca_flags(struct firedtv_tuner_status *stat)
        return flags;
 }
 
-static int fdtv_ca_reset(struct firedtv *fdtv)
-{
-       return avc_ca_reset(fdtv) ? -EFAULT : 0;
-}
-
 static int fdtv_ca_get_caps(void *arg)
 {
        struct ca_caps *cap = arg;
@@ -65,12 +60,14 @@ static int fdtv_ca_get_slot_info(struct firedtv *fdtv, void *arg)
 {
        struct firedtv_tuner_status stat;
        struct ca_slot_info *slot = arg;
+       int err;
 
-       if (avc_tuner_status(fdtv, &stat))
-               return -EFAULT;
+       err = avc_tuner_status(fdtv, &stat);
+       if (err)
+               return err;
 
        if (slot->num != 0)
-               return -EFAULT;
+               return -EACCES;
 
        slot->type = CA_CI;
        slot->flags = fdtv_get_ca_flags(&stat);
@@ -81,21 +78,21 @@ static int fdtv_ca_app_info(struct firedtv *fdtv, void *arg)
 {
        struct ca_msg *reply = arg;
 
-       return avc_ca_app_info(fdtv, reply->msg, &reply->length) ? -EFAULT : 0;
+       return avc_ca_app_info(fdtv, reply->msg, &reply->length);
 }
 
 static int fdtv_ca_info(struct firedtv *fdtv, void *arg)
 {
        struct ca_msg *reply = arg;
 
-       return avc_ca_info(fdtv, reply->msg, &reply->length) ? -EFAULT : 0;
+       return avc_ca_info(fdtv, reply->msg, &reply->length);
 }
 
 static int fdtv_ca_get_mmi(struct firedtv *fdtv, void *arg)
 {
        struct ca_msg *reply = arg;
 
-       return avc_ca_get_mmi(fdtv, reply->msg, &reply->length) ? -EFAULT : 0;
+       return avc_ca_get_mmi(fdtv, reply->msg, &reply->length);
 }
 
 static int fdtv_ca_get_msg(struct firedtv *fdtv, void *arg)
@@ -111,14 +108,15 @@ static int fdtv_ca_get_msg(struct firedtv *fdtv, void *arg)
                err = fdtv_ca_info(fdtv, arg);
                break;
        default:
-               if (avc_tuner_status(fdtv, &stat))
-                       err = -EFAULT;
-               else if (stat.ca_mmi == 1)
+               err = avc_tuner_status(fdtv, &stat);
+               if (err)
+                       break;
+               if (stat.ca_mmi == 1)
                        err = fdtv_ca_get_mmi(fdtv, arg);
                else {
                        dev_info(fdtv->device, "unhandled CA message 0x%08x\n",
                                 fdtv->ca_last_command);
-                       err = -EFAULT;
+                       err = -EACCES;
                }
        }
        fdtv->ca_last_command = 0;
@@ -141,7 +139,7 @@ static int fdtv_ca_pmt(struct firedtv *fdtv, void *arg)
                data_length = msg->msg[3];
        }
 
-       return avc_ca_pmt(fdtv, &msg->msg[data_pos], data_length) ? -EFAULT : 0;
+       return avc_ca_pmt(fdtv, &msg->msg[data_pos], data_length);
 }
 
 static int fdtv_ca_send_msg(struct firedtv *fdtv, void *arg)
@@ -170,7 +168,7 @@ static int fdtv_ca_send_msg(struct firedtv *fdtv, void *arg)
        default:
                dev_err(fdtv->device, "unhandled CA message 0x%08x\n",
                        fdtv->ca_last_command);
-               err = -EFAULT;
+               err = -EACCES;
        }
        return err;
 }
@@ -184,7 +182,7 @@ static int fdtv_ca_ioctl(struct file *file, unsigned int cmd, void *arg)
 
        switch (cmd) {
        case CA_RESET:
-               err = fdtv_ca_reset(fdtv);
+               err = avc_ca_reset(fdtv);
                break;
        case CA_GET_CAP:
                err = fdtv_ca_get_caps(arg);
index 44b816f..32e08e3 100644 (file)
@@ -49,6 +49,27 @@ config DVB_STV6110x
        help
          A Silicon tuner that supports DVB-S and DVB-S2 modes
 
+comment "Multistandard (cable + terrestrial) frontends"
+       depends on DVB_CORE
+
+config DVB_DRXK
+       tristate "Micronas DRXK based"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         Micronas DRX-K DVB-C/T demodulator.
+
+         Say Y when you want to support this frontend.
+
+config DVB_TDA18271C2DD
+       tristate "NXP TDA18271C2 silicon tuner"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         NXP TDA18271 silicon tuner.
+
+         Say Y when you want to support this tuner.
+
 comment "DVB-S (satellite) frontends"
        depends on DVB_CORE
 
index 2f3a6f7..6a6ba05 100644 (file)
@@ -10,6 +10,7 @@ stv0900-objs = stv0900_core.o stv0900_sw.o
 au8522-objs = au8522_dig.o au8522_decoder.o
 drxd-objs = drxd_firm.o drxd_hard.o
 cxd2820r-objs = cxd2820r_core.o cxd2820r_c.o cxd2820r_t.o cxd2820r_t2.o
+drxk-objs := drxk_hard.o
 
 obj-$(CONFIG_DVB_PLL) += dvb-pll.o
 obj-$(CONFIG_DVB_STV0299) += stv0299.o
@@ -88,4 +89,6 @@ obj-$(CONFIG_DVB_MB86A20S) += mb86a20s.o
 obj-$(CONFIG_DVB_IX2505V) += ix2505v.o
 obj-$(CONFIG_DVB_STV0367) += stv0367.o
 obj-$(CONFIG_DVB_CXD2820R) += cxd2820r.o
+obj-$(CONFIG_DVB_DRXK) += drxk.o
+obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o
 
index b537891..2b248c1 100644 (file)
@@ -692,7 +692,7 @@ static int au8522_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
        /* Interrogate the decoder to see if we are getting a real signal */
        lock_status = au8522_readreg(state, 0x00);
        if (lock_status == 0xa2)
-               vt->signal = 0x01;
+               vt->signal = 0xffff;
        else
                vt->signal = 0x00;
 
index e9ee555..c341d57 100644 (file)
@@ -31,8 +31,8 @@
 
 static int debug;
 
-#define info(args...) do { printk(KERN_INFO "CX24113: " args); } while (0)
-#define err(args...)  do { printk(KERN_ERR  "CX24113: " args); } while (0)
+#define cx_info(args...) do { printk(KERN_INFO "CX24113: " args); } while (0)
+#define cx_err(args...)  do { printk(KERN_ERR  "CX24113: " args); } while (0)
 
 #define dprintk(args...) \
        do { \
@@ -341,7 +341,7 @@ static void cx24113_calc_pll_nf(struct cx24113_state *state, u16 *n, s32 *f)
        } while (N < 6 && R < 3);
 
        if (N < 6) {
-               err("strange frequency: N < 6\n");
+               cx_err("strange frequency: N < 6\n");
                return;
        }
        F = freq_hz;
@@ -563,7 +563,7 @@ struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
                kzalloc(sizeof(struct cx24113_state), GFP_KERNEL);
        int rc;
        if (state == NULL) {
-               err("Unable to kzalloc\n");
+               cx_err("Unable to kzalloc\n");
                goto error;
        }
 
@@ -571,7 +571,7 @@ struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
        state->config = config;
        state->i2c = i2c;
 
-       info("trying to detect myself\n");
+       cx_info("trying to detect myself\n");
 
        /* making a dummy read, because of some expected troubles
         * after power on */
@@ -579,24 +579,24 @@ struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
 
        rc = cx24113_readreg(state, 0x00);
        if (rc < 0) {
-               info("CX24113 not found.\n");
+               cx_info("CX24113 not found.\n");
                goto error;
        }
        state->rev = rc;
 
        switch (rc) {
        case 0x43:
-               info("detected CX24113 variant\n");
+               cx_info("detected CX24113 variant\n");
                break;
        case REV_CX24113:
-               info("successfully detected\n");
+               cx_info("successfully detected\n");
                break;
        default:
-               err("unsupported device id: %x\n", state->rev);
+               cx_err("unsupported device id: %x\n", state->rev);
                goto error;
        }
        state->ver = cx24113_readreg(state, 0x01);
-       info("version: %x\n", state->ver);
+       cx_info("version: %x\n", state->ver);
 
        /* create dvb_frontend */
        memcpy(&fe->ops.tuner_ops, &cx24113_tuner_ops,
index 95c6465..ccd0525 100644 (file)
@@ -1452,11 +1452,7 @@ tuned:  /* Set/Reset B/W */
        cmd.args[0x00] = CMD_BANDWIDTH;
        cmd.args[0x01] = 0x00;
        cmd.len = 0x02;
-       ret = cx24116_cmd_execute(fe, &cmd);
-       if (ret != 0)
-               return ret;
-
-       return ret;
+       return cx24116_cmd_execute(fe, &cmd);
 }
 
 static int cx24116_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *params,
index ad17845..2906582 100644 (file)
@@ -55,13 +55,13 @@ struct cxd2820r_config {
         * Default: 0
         * Values: 0, 1
         */
-       int if_agc_polarity:1;
+       bool if_agc_polarity;
 
        /* Spectrum inversion.
         * Default: 0
         * Values: 0, 1
         */
-       int spec_inv:1;
+       bool spec_inv;
 
        /* IFs for all used modes.
         * Default: none, must set
index 0779f69..d416e85 100644 (file)
@@ -314,6 +314,8 @@ static int cxd2820r_set_frontend(struct dvb_frontend *fe,
                        } else if (c->delivery_system == SYS_DVBT2) {
                                /* DVB-T => DVB-T2 */
                                ret = cxd2820r_sleep_t(fe);
+                               if (ret)
+                                       break;
                                ret = cxd2820r_set_frontend_t2(fe, p);
                        }
                        break;
@@ -324,6 +326,8 @@ static int cxd2820r_set_frontend(struct dvb_frontend *fe,
                        } else if (c->delivery_system == SYS_DVBT) {
                                /* DVB-T2 => DVB-T */
                                ret = cxd2820r_sleep_t2(fe);
+                               if (ret)
+                                       break;
                                ret = cxd2820r_set_frontend_t(fe, p);
                        }
                        break;
@@ -740,12 +744,13 @@ static int cxd2820r_tuner_i2c_xfer(struct i2c_adapter *i2c_adap,
        struct i2c_msg msg[], int num)
 {
        struct cxd2820r_priv *priv = i2c_get_adapdata(i2c_adap);
-       u8 obuf[msg[0].len + 2];
+       int ret;
+       u8 *obuf = kmalloc(msg[0].len + 2, GFP_KERNEL);
        struct i2c_msg msg2[2] = {
                {
                        .addr = priv->cfg.i2c_address,
                        .flags = 0,
-                       .len = sizeof(obuf),
+                       .len = msg[0].len + 2,
                        .buf = obuf,
                }, {
                        .addr = priv->cfg.i2c_address,
@@ -755,15 +760,24 @@ static int cxd2820r_tuner_i2c_xfer(struct i2c_adapter *i2c_adap,
                }
        };
 
+       if (!obuf)
+               return -ENOMEM;
+
        obuf[0] = 0x09;
        obuf[1] = (msg[0].addr << 1);
        if (num == 2) { /* I2C read */
                obuf[1] = (msg[0].addr << 1) | I2C_M_RD; /* I2C RD flag */
-               msg2[0].len = sizeof(obuf) - 1; /* maybe HW bug ? */
+               msg2[0].len = msg[0].len + 2 - 1; /* '-1' maybe HW bug ? */
        }
        memcpy(&obuf[2], msg[0].buf, msg[0].len);
 
-       return i2c_transfer(priv->i2c, msg2, num);
+       ret = i2c_transfer(priv->i2c, msg2, num);
+       if (ret < 0)
+               warn("tuner i2c failed ret:%d", ret);
+
+       kfree(obuf);
+
+       return ret;
 }
 
 static struct i2c_algorithm cxd2820r_tuner_i2c_algo = {
index 25adbee..0c0ebc9 100644 (file)
@@ -55,13 +55,13 @@ struct cxd2820r_priv {
        struct mutex fe_lock; /* FE lock */
        int active_fe:2; /* FE lock, -1=NONE, 0=DVB-T/T2, 1=DVB-C */
 
-       int ber_running:1;
+       bool ber_running;
 
        u8 bank[2];
        u8 gpio[3];
 
        fe_delivery_system_t delivery_system;
-       int last_tune_failed:1; /* for switch between T and T2 tune */
+       bool last_tune_failed; /* for switch between T and T2 tune */
 };
 
 /* cxd2820r_core.c */
index 0c9f40c..a64a538 100644 (file)
@@ -2336,6 +2336,11 @@ struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
                request_firmware() will hit an OOPS (this should be moved somewhere
                more common) */
 
+       /* FIXME: make sure the dev.parent field is initialized, or else
+          request_firmware() will hit an OOPS (this should be moved somewhere
+          more common) */
+       st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
+
        dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
 
        /* init 7090 tuner adapter */
index ea4c1c3..2238bf0 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/delay.h>
 #include <linux/firmware.h>
 #include <linux/i2c.h>
-#include <linux/version.h>
 #include <asm/div64.h>
 
 #include "dvb_frontend.h"
@@ -233,7 +232,7 @@ static int i2c_read(struct i2c_adapter *adap,
        return 0;
 }
 
-inline u32 MulDiv32(u32 a, u32 b, u32 c)
+static inline u32 MulDiv32(u32 a, u32 b, u32 c)
 {
        u64 tmp64;
 
@@ -910,14 +909,16 @@ static int load_firmware(struct drxd_state *state, const char *fw_name)
                return -EIO;
        }
 
-       state->microcode = kzalloc(fw->size, GFP_KERNEL);
+       state->microcode = kmalloc(fw->size, GFP_KERNEL);
        if (state->microcode == NULL) {
-               printk(KERN_ERR "drxd: firmware load failure: nomemory\n");
+               release_firmware(fw);
+               printk(KERN_ERR "drxd: firmware load failure: no memory\n");
                return -ENOMEM;
        }
 
        memcpy(state->microcode, fw->data, fw->size);
        state->microcode_length = fw->size;
+       release_firmware(fw);
        return 0;
 }
 
diff --git a/drivers/media/dvb/frontends/drxk.h b/drivers/media/dvb/frontends/drxk.h
new file mode 100644 (file)
index 0000000..58baf41
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef _DRXK_H_
+#define _DRXK_H_
+
+#include <linux/types.h>
+#include <linux/i2c.h>
+
+/**
+ * struct drxk_config - Configure the initial parameters for DRX-K
+ *
+ * adr:                        I2C Address of the DRX-K
+ * single_master:      Device is on the single master mode
+ * no_i2c_bridge:      Don't switch the I2C bridge to talk with tuner
+ * antenna_gpio:       GPIO bit used to control the antenna
+ * antenna_dvbt:       GPIO bit for changing antenna to DVB-C. A value of 1
+ *                     means that 1=DVBC, 0 = DVBT. Zero means the opposite.
+ * microcode_name:     Name of the firmware file with the microcode
+ *
+ * On the *_gpio vars, bit 0 is UIO-1, bit 1 is UIO-2 and bit 2 is
+ * UIO-3.
+ */
+struct drxk_config {
+       u8      adr;
+       bool    single_master;
+       bool    no_i2c_bridge;
+
+       bool    antenna_dvbt;
+       u16     antenna_gpio;
+
+       const char *microcode_name;
+};
+
+#if defined(CONFIG_DVB_DRXK) || (defined(CONFIG_DVB_DRXK_MODULE) \
+        && defined(MODULE))
+extern struct dvb_frontend *drxk_attach(const struct drxk_config *config,
+                                       struct i2c_adapter *i2c,
+                                       struct dvb_frontend **fe_t);
+#else
+static inline struct dvb_frontend *drxk_attach(const struct drxk_config *config,
+                                       struct i2c_adapter *i2c,
+                                       struct dvb_frontend **fe_t)
+{
+        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+        return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/dvb/frontends/drxk_hard.c b/drivers/media/dvb/frontends/drxk_hard.c
new file mode 100644 (file)
index 0000000..41b0838
--- /dev/null
@@ -0,0 +1,6454 @@
+/*
+ * drxk_hard: DRX-K DVB-C/T demodulator driver
+ *
+ * Copyright (C) 2010-2011 Digital Devices GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/version.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "drxk.h"
+#include "drxk_hard.h"
+
+static int PowerDownDVBT(struct drxk_state *state, bool setPowerMode);
+static int PowerDownQAM(struct drxk_state *state);
+static int SetDVBTStandard(struct drxk_state *state,
+                          enum OperationMode oMode);
+static int SetQAMStandard(struct drxk_state *state,
+                         enum OperationMode oMode);
+static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
+                 s32 tunerFreqOffset);
+static int SetDVBTStandard(struct drxk_state *state,
+                          enum OperationMode oMode);
+static int DVBTStart(struct drxk_state *state);
+static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
+                  s32 tunerFreqOffset);
+static int GetQAMLockStatus(struct drxk_state *state, u32 *pLockStatus);
+static int GetDVBTLockStatus(struct drxk_state *state, u32 *pLockStatus);
+static int SwitchAntennaToQAM(struct drxk_state *state);
+static int SwitchAntennaToDVBT(struct drxk_state *state);
+
+static bool IsDVBT(struct drxk_state *state)
+{
+       return state->m_OperationMode == OM_DVBT;
+}
+
+static bool IsQAM(struct drxk_state *state)
+{
+       return state->m_OperationMode == OM_QAM_ITU_A ||
+           state->m_OperationMode == OM_QAM_ITU_B ||
+           state->m_OperationMode == OM_QAM_ITU_C;
+}
+
+bool IsA1WithPatchCode(struct drxk_state *state)
+{
+       return state->m_DRXK_A1_PATCH_CODE;
+}
+
+bool IsA1WithRomCode(struct drxk_state *state)
+{
+       return state->m_DRXK_A1_ROM_CODE;
+}
+
+#define NOA1ROM 0
+
+#define DRXDAP_FASI_SHORT_FORMAT(addr) (((addr) & 0xFC30FF80) == 0)
+#define DRXDAP_FASI_LONG_FORMAT(addr)  (((addr) & 0xFC30FF80) != 0)
+
+#define DEFAULT_MER_83  165
+#define DEFAULT_MER_93  250
+
+#ifndef DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH
+#define DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH (0x02)
+#endif
+
+#ifndef DRXK_MPEG_PARALLEL_OUTPUT_PIN_DRIVE_STRENGTH
+#define DRXK_MPEG_PARALLEL_OUTPUT_PIN_DRIVE_STRENGTH (0x03)
+#endif
+
+#ifndef DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH
+#define DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH (0x06)
+#endif
+
+#define DEFAULT_DRXK_MPEG_LOCK_TIMEOUT 700
+#define DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT 500
+
+#ifndef DRXK_KI_RAGC_ATV
+#define DRXK_KI_RAGC_ATV   4
+#endif
+#ifndef DRXK_KI_IAGC_ATV
+#define DRXK_KI_IAGC_ATV   6
+#endif
+#ifndef DRXK_KI_DAGC_ATV
+#define DRXK_KI_DAGC_ATV   7
+#endif
+
+#ifndef DRXK_KI_RAGC_QAM
+#define DRXK_KI_RAGC_QAM   3
+#endif
+#ifndef DRXK_KI_IAGC_QAM
+#define DRXK_KI_IAGC_QAM   4
+#endif
+#ifndef DRXK_KI_DAGC_QAM
+#define DRXK_KI_DAGC_QAM   7
+#endif
+#ifndef DRXK_KI_RAGC_DVBT
+#define DRXK_KI_RAGC_DVBT  (IsA1WithPatchCode(state) ? 3 : 2)
+#endif
+#ifndef DRXK_KI_IAGC_DVBT
+#define DRXK_KI_IAGC_DVBT  (IsA1WithPatchCode(state) ? 4 : 2)
+#endif
+#ifndef DRXK_KI_DAGC_DVBT
+#define DRXK_KI_DAGC_DVBT  (IsA1WithPatchCode(state) ? 10 : 7)
+#endif
+
+#ifndef DRXK_AGC_DAC_OFFSET
+#define DRXK_AGC_DAC_OFFSET (0x800)
+#endif
+
+#ifndef DRXK_BANDWIDTH_8MHZ_IN_HZ
+#define DRXK_BANDWIDTH_8MHZ_IN_HZ  (0x8B8249L)
+#endif
+
+#ifndef DRXK_BANDWIDTH_7MHZ_IN_HZ
+#define DRXK_BANDWIDTH_7MHZ_IN_HZ  (0x7A1200L)
+#endif
+
+#ifndef DRXK_BANDWIDTH_6MHZ_IN_HZ
+#define DRXK_BANDWIDTH_6MHZ_IN_HZ  (0x68A1B6L)
+#endif
+
+#ifndef DRXK_QAM_SYMBOLRATE_MAX
+#define DRXK_QAM_SYMBOLRATE_MAX         (7233000)
+#endif
+
+#define DRXK_BL_ROM_OFFSET_TAPS_DVBT    56
+#define DRXK_BL_ROM_OFFSET_TAPS_ITU_A   64
+#define DRXK_BL_ROM_OFFSET_TAPS_ITU_C   0x5FE0
+#define DRXK_BL_ROM_OFFSET_TAPS_BG      24
+#define DRXK_BL_ROM_OFFSET_TAPS_DKILLP  32
+#define DRXK_BL_ROM_OFFSET_TAPS_NTSC    40
+#define DRXK_BL_ROM_OFFSET_TAPS_FM      48
+#define DRXK_BL_ROM_OFFSET_UCODE        0
+
+#define DRXK_BLC_TIMEOUT                100
+
+#define DRXK_BLCC_NR_ELEMENTS_TAPS      2
+#define DRXK_BLCC_NR_ELEMENTS_UCODE     6
+
+#define DRXK_BLDC_NR_ELEMENTS_TAPS      28
+
+#ifndef DRXK_OFDM_NE_NOTCH_WIDTH
+#define DRXK_OFDM_NE_NOTCH_WIDTH             (4)
+#endif
+
+#define DRXK_QAM_SL_SIG_POWER_QAM16       (40960)
+#define DRXK_QAM_SL_SIG_POWER_QAM32       (20480)
+#define DRXK_QAM_SL_SIG_POWER_QAM64       (43008)
+#define DRXK_QAM_SL_SIG_POWER_QAM128      (20992)
+#define DRXK_QAM_SL_SIG_POWER_QAM256      (43520)
+
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages");
+
+#define dprintk(level, fmt, arg...) do {                       \
+if (debug >= level)                                            \
+       printk(KERN_DEBUG "drxk: %s" fmt, __func__, ## arg);    \
+} while (0)
+
+
+static inline u32 MulDiv32(u32 a, u32 b, u32 c)
+{
+       u64 tmp64;
+
+       tmp64 = (u64) a * (u64) b;
+       do_div(tmp64, c);
+
+       return (u32) tmp64;
+}
+
+inline u32 Frac28a(u32 a, u32 c)
+{
+       int i = 0;
+       u32 Q1 = 0;
+       u32 R0 = 0;
+
+       R0 = (a % c) << 4;      /* 32-28 == 4 shifts possible at max */
+       Q1 = a / c;             /* integer part, only the 4 least significant bits
+                                  will be visible in the result */
+
+       /* division using radix 16, 7 nibbles in the result */
+       for (i = 0; i < 7; i++) {
+               Q1 = (Q1 << 4) | (R0 / c);
+               R0 = (R0 % c) << 4;
+       }
+       /* rounding */
+       if ((R0 >> 3) >= c)
+               Q1++;
+
+       return Q1;
+}
+
+static u32 Log10Times100(u32 x)
+{
+       static const u8 scale = 15;
+       static const u8 indexWidth = 5;
+       u8 i = 0;
+       u32 y = 0;
+       u32 d = 0;
+       u32 k = 0;
+       u32 r = 0;
+       /*
+          log2lut[n] = (1<<scale) * 200 * log2(1.0 + ((1.0/(1<<INDEXWIDTH)) * n))
+          0 <= n < ((1<<INDEXWIDTH)+1)
+        */
+
+       static const u32 log2lut[] = {
+               0,              /* 0.000000 */
+               290941,         /* 290941.300628 */
+               573196,         /* 573196.476418 */
+               847269,         /* 847269.179851 */
+               1113620,        /* 1113620.489452 */
+               1372674,        /* 1372673.576986 */
+               1624818,        /* 1624817.752104 */
+               1870412,        /* 1870411.981536 */
+               2109788,        /* 2109787.962654 */
+               2343253,        /* 2343252.817465 */
+               2571091,        /* 2571091.461923 */
+               2793569,        /* 2793568.696416 */
+               3010931,        /* 3010931.055901 */
+               3223408,        /* 3223408.452106 */
+               3431216,        /* 3431215.635215 */
+               3634553,        /* 3634553.498355 */
+               3833610,        /* 3833610.244726 */
+               4028562,        /* 4028562.434393 */
+               4219576,        /* 4219575.925308 */
+               4406807,        /* 4406806.721144 */
+               4590402,        /* 4590401.736809 */
+               4770499,        /* 4770499.491025 */
+               4947231,        /* 4947230.734179 */
+               5120719,        /* 5120719.018555 */
+               5291081,        /* 5291081.217197 */
+               5458428,        /* 5458427.996830 */
+               5622864,        /* 5622864.249668 */
+               5784489,        /* 5784489.488298 */
+               5943398,        /* 5943398.207380 */
+               6099680,        /* 6099680.215452 */
+               6253421,        /* 6253420.939751 */
+               6404702,        /* 6404701.706649 */
+               6553600,        /* 6553600.000000 */
+       };
+
+
+       if (x == 0)
+               return 0;
+
+       /* Scale x (normalize) */
+       /* computing y in log(x/y) = log(x) - log(y) */
+       if ((x & ((0xffffffff) << (scale + 1))) == 0) {
+               for (k = scale; k > 0; k--) {
+                       if (x & (((u32) 1) << scale))
+                               break;
+                       x <<= 1;
+               }
+       } else {
+               for (k = scale; k < 31; k++) {
+                       if ((x & (((u32) (-1)) << (scale + 1))) == 0)
+                               break;
+                       x >>= 1;
+               }
+       }
+       /*
+          Now x has binary point between bit[scale] and bit[scale-1]
+          and 1.0 <= x < 2.0 */
+
+       /* correction for divison: log(x) = log(x/y)+log(y) */
+       y = k * ((((u32) 1) << scale) * 200);
+
+       /* remove integer part */
+       x &= ((((u32) 1) << scale) - 1);
+       /* get index */
+       i = (u8) (x >> (scale - indexWidth));
+       /* compute delta (x - a) */
+       d = x & ((((u32) 1) << (scale - indexWidth)) - 1);
+       /* compute log, multiplication (d* (..)) must be within range ! */
+       y += log2lut[i] +
+           ((d * (log2lut[i + 1] - log2lut[i])) >> (scale - indexWidth));
+       /* Conver to log10() */
+       y /= 108853;            /* (log2(10) << scale) */
+       r = (y >> 1);
+       /* rounding */
+       if (y & ((u32) 1))
+               r++;
+       return r;
+}
+
+/****************************************************************************/
+/* I2C **********************************************************************/
+/****************************************************************************/
+
+static int i2c_read1(struct i2c_adapter *adapter, u8 adr, u8 *val)
+{
+       struct i2c_msg msgs[1] = { {.addr = adr, .flags = I2C_M_RD,
+                                   .buf = val, .len = 1}
+       };
+
+       return i2c_transfer(adapter, msgs, 1);
+}
+
+static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len)
+{
+       int status;
+       struct i2c_msg msg = {
+           .addr = adr, .flags = 0, .buf = data, .len = len };
+
+       dprintk(3, ":");
+       if (debug > 2) {
+               int i;
+               for (i = 0; i < len; i++)
+                       printk(KERN_CONT " %02x", data[i]);
+               printk(KERN_CONT "\n");
+       }
+       status = i2c_transfer(adap, &msg, 1);
+       if (status >= 0 && status != 1)
+               status = -EIO;
+
+       if (status < 0)
+               printk(KERN_ERR "drxk: i2c write error at addr 0x%02x\n", adr);
+
+       return status;
+}
+
+static int i2c_read(struct i2c_adapter *adap,
+                   u8 adr, u8 *msg, int len, u8 *answ, int alen)
+{
+       int status;
+       struct i2c_msg msgs[2] = {
+               {.addr = adr, .flags = 0,
+                                   .buf = msg, .len = len},
+               {.addr = adr, .flags = I2C_M_RD,
+                .buf = answ, .len = alen}
+       };
+
+       status = i2c_transfer(adap, msgs, 2);
+       if (status != 2) {
+               if (debug > 2)
+                       printk(KERN_CONT ": ERROR!\n");
+               if (status >= 0)
+                       status = -EIO;
+
+               printk(KERN_ERR "drxk: i2c read error at addr 0x%02x\n", adr);
+               return status;
+       }
+       if (debug > 2) {
+               int i;
+               dprintk(2, ": read from ");
+               for (i = 0; i < len; i++)
+                       printk(KERN_CONT " %02x", msg[i]);
+               printk(KERN_CONT "Value = ");
+               for (i = 0; i < alen; i++)
+                       printk(KERN_CONT " %02x", answ[i]);
+               printk(KERN_CONT "\n");
+       }
+       return 0;
+}
+
+static int read16_flags(struct drxk_state *state, u32 reg, u16 *data, u8 flags)
+{
+       int status;
+       u8 adr = state->demod_address, mm1[4], mm2[2], len;
+
+       if (state->single_master)
+               flags |= 0xC0;
+
+       if (DRXDAP_FASI_LONG_FORMAT(reg) || (flags != 0)) {
+               mm1[0] = (((reg << 1) & 0xFF) | 0x01);
+               mm1[1] = ((reg >> 16) & 0xFF);
+               mm1[2] = ((reg >> 24) & 0xFF) | flags;
+               mm1[3] = ((reg >> 7) & 0xFF);
+               len = 4;
+       } else {
+               mm1[0] = ((reg << 1) & 0xFF);
+               mm1[1] = (((reg >> 16) & 0x0F) | ((reg >> 18) & 0xF0));
+               len = 2;
+       }
+       dprintk(2, "(0x%08x, 0x%02x)\n", reg, flags);
+       status = i2c_read(state->i2c, adr, mm1, len, mm2, 2);
+       if (status < 0)
+               return status;
+       if (data)
+               *data = mm2[0] | (mm2[1] << 8);
+
+       return 0;
+}
+
+static int read16(struct drxk_state *state, u32 reg, u16 *data)
+{
+       return read16_flags(state, reg, data, 0);
+}
+
+static int read32_flags(struct drxk_state *state, u32 reg, u32 *data, u8 flags)
+{
+       int status;
+       u8 adr = state->demod_address, mm1[4], mm2[4], len;
+
+       if (state->single_master)
+               flags |= 0xC0;
+
+       if (DRXDAP_FASI_LONG_FORMAT(reg) || (flags != 0)) {
+               mm1[0] = (((reg << 1) & 0xFF) | 0x01);
+               mm1[1] = ((reg >> 16) & 0xFF);
+               mm1[2] = ((reg >> 24) & 0xFF) | flags;
+               mm1[3] = ((reg >> 7) & 0xFF);
+               len = 4;
+       } else {
+               mm1[0] = ((reg << 1) & 0xFF);
+               mm1[1] = (((reg >> 16) & 0x0F) | ((reg >> 18) & 0xF0));
+               len = 2;
+       }
+       dprintk(2, "(0x%08x, 0x%02x)\n", reg, flags);
+       status = i2c_read(state->i2c, adr, mm1, len, mm2, 4);
+       if (status < 0)
+               return status;
+       if (data)
+               *data = mm2[0] | (mm2[1] << 8) |
+                   (mm2[2] << 16) | (mm2[3] << 24);
+
+       return 0;
+}
+
+static int read32(struct drxk_state *state, u32 reg, u32 *data)
+{
+       return read32_flags(state, reg, data, 0);
+}
+
+static int write16_flags(struct drxk_state *state, u32 reg, u16 data, u8 flags)
+{
+       u8 adr = state->demod_address, mm[6], len;
+
+       if (state->single_master)
+               flags |= 0xC0;
+       if (DRXDAP_FASI_LONG_FORMAT(reg) || (flags != 0)) {
+               mm[0] = (((reg << 1) & 0xFF) | 0x01);
+               mm[1] = ((reg >> 16) & 0xFF);
+               mm[2] = ((reg >> 24) & 0xFF) | flags;
+               mm[3] = ((reg >> 7) & 0xFF);
+               len = 4;
+       } else {
+               mm[0] = ((reg << 1) & 0xFF);
+               mm[1] = (((reg >> 16) & 0x0F) | ((reg >> 18) & 0xF0));
+               len = 2;
+       }
+       mm[len] = data & 0xff;
+       mm[len + 1] = (data >> 8) & 0xff;
+
+       dprintk(2, "(0x%08x, 0x%04x, 0x%02x)\n", reg, data, flags);
+       return i2c_write(state->i2c, adr, mm, len + 2);
+}
+
+static int write16(struct drxk_state *state, u32 reg, u16 data)
+{
+       return write16_flags(state, reg, data, 0);
+}
+
+static int write32_flags(struct drxk_state *state, u32 reg, u32 data, u8 flags)
+{
+       u8 adr = state->demod_address, mm[8], len;
+
+       if (state->single_master)
+               flags |= 0xC0;
+       if (DRXDAP_FASI_LONG_FORMAT(reg) || (flags != 0)) {
+               mm[0] = (((reg << 1) & 0xFF) | 0x01);
+               mm[1] = ((reg >> 16) & 0xFF);
+               mm[2] = ((reg >> 24) & 0xFF) | flags;
+               mm[3] = ((reg >> 7) & 0xFF);
+               len = 4;
+       } else {
+               mm[0] = ((reg << 1) & 0xFF);
+               mm[1] = (((reg >> 16) & 0x0F) | ((reg >> 18) & 0xF0));
+               len = 2;
+       }
+       mm[len] = data & 0xff;
+       mm[len + 1] = (data >> 8) & 0xff;
+       mm[len + 2] = (data >> 16) & 0xff;
+       mm[len + 3] = (data >> 24) & 0xff;
+       dprintk(2, "(0x%08x, 0x%08x, 0x%02x)\n", reg, data, flags);
+
+       return i2c_write(state->i2c, adr, mm, len + 4);
+}
+
+static int write32(struct drxk_state *state, u32 reg, u32 data)
+{
+       return write32_flags(state, reg, data, 0);
+}
+
+static int write_block(struct drxk_state *state, u32 Address,
+                     const int BlockSize, const u8 pBlock[])
+{
+       int status = 0, BlkSize = BlockSize;
+       u8 Flags = 0;
+
+       if (state->single_master)
+               Flags |= 0xC0;
+
+       while (BlkSize > 0) {
+               int Chunk = BlkSize > state->m_ChunkSize ?
+                   state->m_ChunkSize : BlkSize;
+               u8 *AdrBuf = &state->Chunk[0];
+               u32 AdrLength = 0;
+
+               if (DRXDAP_FASI_LONG_FORMAT(Address) || (Flags != 0)) {
+                       AdrBuf[0] = (((Address << 1) & 0xFF) | 0x01);
+                       AdrBuf[1] = ((Address >> 16) & 0xFF);
+                       AdrBuf[2] = ((Address >> 24) & 0xFF);
+                       AdrBuf[3] = ((Address >> 7) & 0xFF);
+                       AdrBuf[2] |= Flags;
+                       AdrLength = 4;
+                       if (Chunk == state->m_ChunkSize)
+                               Chunk -= 2;
+               } else {
+                       AdrBuf[0] = ((Address << 1) & 0xFF);
+                       AdrBuf[1] = (((Address >> 16) & 0x0F) |
+                                    ((Address >> 18) & 0xF0));
+                       AdrLength = 2;
+               }
+               memcpy(&state->Chunk[AdrLength], pBlock, Chunk);
+               dprintk(2, "(0x%08x, 0x%02x)\n", Address, Flags);
+               if (debug > 1) {
+                       int i;
+                       if (pBlock)
+                               for (i = 0; i < Chunk; i++)
+                                       printk(KERN_CONT " %02x", pBlock[i]);
+                       printk(KERN_CONT "\n");
+               }
+               status = i2c_write(state->i2c, state->demod_address,
+                                  &state->Chunk[0], Chunk + AdrLength);
+               if (status < 0) {
+                       printk(KERN_ERR "drxk: %s: i2c write error at addr 0x%02x\n",
+                              __func__, Address);
+                       break;
+               }
+               pBlock += Chunk;
+               Address += (Chunk >> 1);
+               BlkSize -= Chunk;
+       }
+       return status;
+}
+
+#ifndef DRXK_MAX_RETRIES_POWERUP
+#define DRXK_MAX_RETRIES_POWERUP 20
+#endif
+
+int PowerUpDevice(struct drxk_state *state)
+{
+       int status;
+       u8 data = 0;
+       u16 retryCount = 0;
+
+       dprintk(1, "\n");
+
+       status = i2c_read1(state->i2c, state->demod_address, &data);
+       if (status < 0) {
+               do {
+                       data = 0;
+                       status = i2c_write(state->i2c, state->demod_address,
+                                          &data, 1);
+                       msleep(10);
+                       retryCount++;
+                       if (status < 0)
+                               continue;
+                       status = i2c_read1(state->i2c, state->demod_address,
+                                          &data);
+               } while (status < 0 &&
+                        (retryCount < DRXK_MAX_RETRIES_POWERUP));
+               if (status < 0 && retryCount >= DRXK_MAX_RETRIES_POWERUP)
+                       goto error;
+       }
+
+       /* Make sure all clk domains are active */
+       status = write16(state, SIO_CC_PWD_MODE__A, SIO_CC_PWD_MODE_LEVEL_NONE);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY);
+       if (status < 0)
+               goto error;
+       /* Enable pll lock tests */
+       status = write16(state, SIO_CC_PLL_LOCK__A, 1);
+       if (status < 0)
+               goto error;
+
+       state->m_currentPowerMode = DRX_POWER_UP;
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+
+static int init_state(struct drxk_state *state)
+{
+       /*
+        * FIXME: most (all?) of the values bellow should be moved into
+        * struct drxk_config, as they are probably board-specific
+        */
+       u32 ulVSBIfAgcMode = DRXK_AGC_CTRL_AUTO;
+       u32 ulVSBIfAgcOutputLevel = 0;
+       u32 ulVSBIfAgcMinLevel = 0;
+       u32 ulVSBIfAgcMaxLevel = 0x7FFF;
+       u32 ulVSBIfAgcSpeed = 3;
+
+       u32 ulVSBRfAgcMode = DRXK_AGC_CTRL_AUTO;
+       u32 ulVSBRfAgcOutputLevel = 0;
+       u32 ulVSBRfAgcMinLevel = 0;
+       u32 ulVSBRfAgcMaxLevel = 0x7FFF;
+       u32 ulVSBRfAgcSpeed = 3;
+       u32 ulVSBRfAgcTop = 9500;
+       u32 ulVSBRfAgcCutOffCurrent = 4000;
+
+       u32 ulATVIfAgcMode = DRXK_AGC_CTRL_AUTO;
+       u32 ulATVIfAgcOutputLevel = 0;
+       u32 ulATVIfAgcMinLevel = 0;
+       u32 ulATVIfAgcMaxLevel = 0;
+       u32 ulATVIfAgcSpeed = 3;
+
+       u32 ulATVRfAgcMode = DRXK_AGC_CTRL_OFF;
+       u32 ulATVRfAgcOutputLevel = 0;
+       u32 ulATVRfAgcMinLevel = 0;
+       u32 ulATVRfAgcMaxLevel = 0;
+       u32 ulATVRfAgcTop = 9500;
+       u32 ulATVRfAgcCutOffCurrent = 4000;
+       u32 ulATVRfAgcSpeed = 3;
+
+       u32 ulQual83 = DEFAULT_MER_83;
+       u32 ulQual93 = DEFAULT_MER_93;
+
+       u32 ulDVBTStaticTSClock = 1;
+       u32 ulDVBCStaticTSClock = 1;
+
+       u32 ulMpegLockTimeOut = DEFAULT_DRXK_MPEG_LOCK_TIMEOUT;
+       u32 ulDemodLockTimeOut = DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT;
+
+       /* io_pad_cfg register (8 bit reg.) MSB bit is 1 (default value) */
+       /* io_pad_cfg_mode output mode is drive always */
+       /* io_pad_cfg_drive is set to power 2 (23 mA) */
+       u32 ulGPIOCfg = 0x0113;
+       u32 ulSerialMode = 1;
+       u32 ulInvertTSClock = 0;
+       u32 ulTSDataStrength = DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH;
+       u32 ulTSClockkStrength = DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH;
+       u32 ulDVBTBitrate = 50000000;
+       u32 ulDVBCBitrate = DRXK_QAM_SYMBOLRATE_MAX * 8;
+
+       u32 ulInsertRSByte = 0;
+
+       u32 ulRfMirror = 1;
+       u32 ulPowerDown = 0;
+
+       dprintk(1, "\n");
+
+       state->m_hasLNA = false;
+       state->m_hasDVBT = false;
+       state->m_hasDVBC = false;
+       state->m_hasATV = false;
+       state->m_hasOOB = false;
+       state->m_hasAudio = false;
+
+       state->m_ChunkSize = 124;
+
+       state->m_oscClockFreq = 0;
+       state->m_smartAntInverted = false;
+       state->m_bPDownOpenBridge = false;
+
+       /* real system clock frequency in kHz */
+       state->m_sysClockFreq = 151875;
+       /* Timing div, 250ns/Psys */
+       /* Timing div, = (delay (nano seconds) * sysclk (kHz))/ 1000 */
+       state->m_HICfgTimingDiv = ((state->m_sysClockFreq / 1000) *
+                                  HI_I2C_DELAY) / 1000;
+       /* Clipping */
+       if (state->m_HICfgTimingDiv > SIO_HI_RA_RAM_PAR_2_CFG_DIV__M)
+               state->m_HICfgTimingDiv = SIO_HI_RA_RAM_PAR_2_CFG_DIV__M;
+       state->m_HICfgWakeUpKey = (state->demod_address << 1);
+       /* port/bridge/power down ctrl */
+       state->m_HICfgCtrl = SIO_HI_RA_RAM_PAR_5_CFG_SLV0_SLAVE;
+
+       state->m_bPowerDown = (ulPowerDown != 0);
+
+       state->m_DRXK_A1_PATCH_CODE = false;
+       state->m_DRXK_A1_ROM_CODE = false;
+       state->m_DRXK_A2_ROM_CODE = false;
+       state->m_DRXK_A3_ROM_CODE = false;
+       state->m_DRXK_A2_PATCH_CODE = false;
+       state->m_DRXK_A3_PATCH_CODE = false;
+
+       /* Init AGC and PGA parameters */
+       /* VSB IF */
+       state->m_vsbIfAgcCfg.ctrlMode = (ulVSBIfAgcMode);
+       state->m_vsbIfAgcCfg.outputLevel = (ulVSBIfAgcOutputLevel);
+       state->m_vsbIfAgcCfg.minOutputLevel = (ulVSBIfAgcMinLevel);
+       state->m_vsbIfAgcCfg.maxOutputLevel = (ulVSBIfAgcMaxLevel);
+       state->m_vsbIfAgcCfg.speed = (ulVSBIfAgcSpeed);
+       state->m_vsbPgaCfg = 140;
+
+       /* VSB RF */
+       state->m_vsbRfAgcCfg.ctrlMode = (ulVSBRfAgcMode);
+       state->m_vsbRfAgcCfg.outputLevel = (ulVSBRfAgcOutputLevel);
+       state->m_vsbRfAgcCfg.minOutputLevel = (ulVSBRfAgcMinLevel);
+       state->m_vsbRfAgcCfg.maxOutputLevel = (ulVSBRfAgcMaxLevel);
+       state->m_vsbRfAgcCfg.speed = (ulVSBRfAgcSpeed);
+       state->m_vsbRfAgcCfg.top = (ulVSBRfAgcTop);
+       state->m_vsbRfAgcCfg.cutOffCurrent = (ulVSBRfAgcCutOffCurrent);
+       state->m_vsbPreSawCfg.reference = 0x07;
+       state->m_vsbPreSawCfg.usePreSaw = true;
+
+       state->m_Quality83percent = DEFAULT_MER_83;
+       state->m_Quality93percent = DEFAULT_MER_93;
+       if (ulQual93 <= 500 && ulQual83 < ulQual93) {
+               state->m_Quality83percent = ulQual83;
+               state->m_Quality93percent = ulQual93;
+       }
+
+       /* ATV IF */
+       state->m_atvIfAgcCfg.ctrlMode = (ulATVIfAgcMode);
+       state->m_atvIfAgcCfg.outputLevel = (ulATVIfAgcOutputLevel);
+       state->m_atvIfAgcCfg.minOutputLevel = (ulATVIfAgcMinLevel);
+       state->m_atvIfAgcCfg.maxOutputLevel = (ulATVIfAgcMaxLevel);
+       state->m_atvIfAgcCfg.speed = (ulATVIfAgcSpeed);
+
+       /* ATV RF */
+       state->m_atvRfAgcCfg.ctrlMode = (ulATVRfAgcMode);
+       state->m_atvRfAgcCfg.outputLevel = (ulATVRfAgcOutputLevel);
+       state->m_atvRfAgcCfg.minOutputLevel = (ulATVRfAgcMinLevel);
+       state->m_atvRfAgcCfg.maxOutputLevel = (ulATVRfAgcMaxLevel);
+       state->m_atvRfAgcCfg.speed = (ulATVRfAgcSpeed);
+       state->m_atvRfAgcCfg.top = (ulATVRfAgcTop);
+       state->m_atvRfAgcCfg.cutOffCurrent = (ulATVRfAgcCutOffCurrent);
+       state->m_atvPreSawCfg.reference = 0x04;
+       state->m_atvPreSawCfg.usePreSaw = true;
+
+
+       /* DVBT RF */
+       state->m_dvbtRfAgcCfg.ctrlMode = DRXK_AGC_CTRL_OFF;
+       state->m_dvbtRfAgcCfg.outputLevel = 0;
+       state->m_dvbtRfAgcCfg.minOutputLevel = 0;
+       state->m_dvbtRfAgcCfg.maxOutputLevel = 0xFFFF;
+       state->m_dvbtRfAgcCfg.top = 0x2100;
+       state->m_dvbtRfAgcCfg.cutOffCurrent = 4000;
+       state->m_dvbtRfAgcCfg.speed = 1;
+
+
+       /* DVBT IF */
+       state->m_dvbtIfAgcCfg.ctrlMode = DRXK_AGC_CTRL_AUTO;
+       state->m_dvbtIfAgcCfg.outputLevel = 0;
+       state->m_dvbtIfAgcCfg.minOutputLevel = 0;
+       state->m_dvbtIfAgcCfg.maxOutputLevel = 9000;
+       state->m_dvbtIfAgcCfg.top = 13424;
+       state->m_dvbtIfAgcCfg.cutOffCurrent = 0;
+       state->m_dvbtIfAgcCfg.speed = 3;
+       state->m_dvbtIfAgcCfg.FastClipCtrlDelay = 30;
+       state->m_dvbtIfAgcCfg.IngainTgtMax = 30000;
+       /* state->m_dvbtPgaCfg = 140; */
+
+       state->m_dvbtPreSawCfg.reference = 4;
+       state->m_dvbtPreSawCfg.usePreSaw = false;
+
+       /* QAM RF */
+       state->m_qamRfAgcCfg.ctrlMode = DRXK_AGC_CTRL_OFF;
+       state->m_qamRfAgcCfg.outputLevel = 0;
+       state->m_qamRfAgcCfg.minOutputLevel = 6023;
+       state->m_qamRfAgcCfg.maxOutputLevel = 27000;
+       state->m_qamRfAgcCfg.top = 0x2380;
+       state->m_qamRfAgcCfg.cutOffCurrent = 4000;
+       state->m_qamRfAgcCfg.speed = 3;
+
+       /* QAM IF */
+       state->m_qamIfAgcCfg.ctrlMode = DRXK_AGC_CTRL_AUTO;
+       state->m_qamIfAgcCfg.outputLevel = 0;
+       state->m_qamIfAgcCfg.minOutputLevel = 0;
+       state->m_qamIfAgcCfg.maxOutputLevel = 9000;
+       state->m_qamIfAgcCfg.top = 0x0511;
+       state->m_qamIfAgcCfg.cutOffCurrent = 0;
+       state->m_qamIfAgcCfg.speed = 3;
+       state->m_qamIfAgcCfg.IngainTgtMax = 5119;
+       state->m_qamIfAgcCfg.FastClipCtrlDelay = 50;
+
+       state->m_qamPgaCfg = 140;
+       state->m_qamPreSawCfg.reference = 4;
+       state->m_qamPreSawCfg.usePreSaw = false;
+
+       state->m_OperationMode = OM_NONE;
+       state->m_DrxkState = DRXK_UNINITIALIZED;
+
+       /* MPEG output configuration */
+       state->m_enableMPEGOutput = true;       /* If TRUE; enable MPEG ouput */
+       state->m_insertRSByte = false;  /* If TRUE; insert RS byte */
+       state->m_enableParallel = true; /* If TRUE;
+                                          parallel out otherwise serial */
+       state->m_invertDATA = false;    /* If TRUE; invert DATA signals */
+       state->m_invertERR = false;     /* If TRUE; invert ERR signal */
+       state->m_invertSTR = false;     /* If TRUE; invert STR signals */
+       state->m_invertVAL = false;     /* If TRUE; invert VAL signals */
+       state->m_invertCLK = (ulInvertTSClock != 0);    /* If TRUE; invert CLK signals */
+       state->m_DVBTStaticCLK = (ulDVBTStaticTSClock != 0);
+       state->m_DVBCStaticCLK = (ulDVBCStaticTSClock != 0);
+       /* If TRUE; static MPEG clockrate will be used;
+          otherwise clockrate will adapt to the bitrate of the TS */
+
+       state->m_DVBTBitrate = ulDVBTBitrate;
+       state->m_DVBCBitrate = ulDVBCBitrate;
+
+       state->m_TSDataStrength = (ulTSDataStrength & 0x07);
+       state->m_TSClockkStrength = (ulTSClockkStrength & 0x07);
+
+       /* Maximum bitrate in b/s in case static clockrate is selected */
+       state->m_mpegTsStaticBitrate = 19392658;
+       state->m_disableTEIhandling = false;
+
+       if (ulInsertRSByte)
+               state->m_insertRSByte = true;
+
+       state->m_MpegLockTimeOut = DEFAULT_DRXK_MPEG_LOCK_TIMEOUT;
+       if (ulMpegLockTimeOut < 10000)
+               state->m_MpegLockTimeOut = ulMpegLockTimeOut;
+       state->m_DemodLockTimeOut = DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT;
+       if (ulDemodLockTimeOut < 10000)
+               state->m_DemodLockTimeOut = ulDemodLockTimeOut;
+
+       /* QAM defaults */
+       state->m_Constellation = DRX_CONSTELLATION_AUTO;
+       state->m_qamInterleaveMode = DRXK_QAM_I12_J17;
+       state->m_fecRsPlen = 204 * 8;   /* fecRsPlen  annex A */
+       state->m_fecRsPrescale = 1;
+
+       state->m_sqiSpeed = DRXK_DVBT_SQI_SPEED_MEDIUM;
+       state->m_agcFastClipCtrlDelay = 0;
+
+       state->m_GPIOCfg = (ulGPIOCfg);
+
+       state->m_bPowerDown = false;
+       state->m_currentPowerMode = DRX_POWER_DOWN;
+
+       state->m_enableParallel = (ulSerialMode == 0);
+
+       state->m_rfmirror = (ulRfMirror == 0);
+       state->m_IfAgcPol = false;
+       return 0;
+}
+
+static int DRXX_Open(struct drxk_state *state)
+{
+       int status = 0;
+       u32 jtag = 0;
+       u16 bid = 0;
+       u16 key = 0;
+
+       dprintk(1, "\n");
+       /* stop lock indicator process */
+       status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+       if (status < 0)
+               goto error;
+       /* Check device id */
+       status = read16(state, SIO_TOP_COMM_KEY__A, &key);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY_KEY);
+       if (status < 0)
+               goto error;
+       status = read32(state, SIO_TOP_JTAGID_LO__A, &jtag);
+       if (status < 0)
+               goto error;
+       status = read16(state, SIO_PDR_UIO_IN_HI__A, &bid);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_TOP_COMM_KEY__A, key);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int GetDeviceCapabilities(struct drxk_state *state)
+{
+       u16 sioPdrOhwCfg = 0;
+       u32 sioTopJtagidLo = 0;
+       int status;
+       const char *spin = "";
+
+       dprintk(1, "\n");
+
+       /* driver 0.9.0 */
+       /* stop lock indicator process */
+       status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_TOP_COMM_KEY__A, 0xFABA);
+       if (status < 0)
+               goto error;
+       status = read16(state, SIO_PDR_OHW_CFG__A, &sioPdrOhwCfg);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_TOP_COMM_KEY__A, 0x0000);
+       if (status < 0)
+               goto error;
+
+       switch ((sioPdrOhwCfg & SIO_PDR_OHW_CFG_FREF_SEL__M)) {
+       case 0:
+               /* ignore (bypass ?) */
+               break;
+       case 1:
+               /* 27 MHz */
+               state->m_oscClockFreq = 27000;
+               break;
+       case 2:
+               /* 20.25 MHz */
+               state->m_oscClockFreq = 20250;
+               break;
+       case 3:
+               /* 4 MHz */
+               state->m_oscClockFreq = 20250;
+               break;
+       default:
+               printk(KERN_ERR "drxk: Clock Frequency is unkonwn\n");
+               return -EINVAL;
+       }
+       /*
+               Determine device capabilities
+               Based on pinning v14
+               */
+       status = read32(state, SIO_TOP_JTAGID_LO__A, &sioTopJtagidLo);
+       if (status < 0)
+               goto error;
+       /* driver 0.9.0 */
+       switch ((sioTopJtagidLo >> 29) & 0xF) {
+       case 0:
+               state->m_deviceSpin = DRXK_SPIN_A1;
+               spin = "A1";
+               break;
+       case 2:
+               state->m_deviceSpin = DRXK_SPIN_A2;
+               spin = "A2";
+               break;
+       case 3:
+               state->m_deviceSpin = DRXK_SPIN_A3;
+               spin = "A3";
+               break;
+       default:
+               state->m_deviceSpin = DRXK_SPIN_UNKNOWN;
+               status = -EINVAL;
+               printk(KERN_ERR "drxk: Spin unknown\n");
+               goto error2;
+       }
+       switch ((sioTopJtagidLo >> 12) & 0xFF) {
+       case 0x13:
+               /* typeId = DRX3913K_TYPE_ID */
+               state->m_hasLNA = false;
+               state->m_hasOOB = false;
+               state->m_hasATV = false;
+               state->m_hasAudio = false;
+               state->m_hasDVBT = true;
+               state->m_hasDVBC = true;
+               state->m_hasSAWSW = true;
+               state->m_hasGPIO2 = false;
+               state->m_hasGPIO1 = false;
+               state->m_hasIRQN = false;
+               break;
+       case 0x15:
+               /* typeId = DRX3915K_TYPE_ID */
+               state->m_hasLNA = false;
+               state->m_hasOOB = false;
+               state->m_hasATV = true;
+               state->m_hasAudio = false;
+               state->m_hasDVBT = true;
+               state->m_hasDVBC = false;
+               state->m_hasSAWSW = true;
+               state->m_hasGPIO2 = true;
+               state->m_hasGPIO1 = true;
+               state->m_hasIRQN = false;
+               break;
+       case 0x16:
+               /* typeId = DRX3916K_TYPE_ID */
+               state->m_hasLNA = false;
+               state->m_hasOOB = false;
+               state->m_hasATV = true;
+               state->m_hasAudio = false;
+               state->m_hasDVBT = true;
+               state->m_hasDVBC = false;
+               state->m_hasSAWSW = true;
+               state->m_hasGPIO2 = true;
+               state->m_hasGPIO1 = true;
+               state->m_hasIRQN = false;
+               break;
+       case 0x18:
+               /* typeId = DRX3918K_TYPE_ID */
+               state->m_hasLNA = false;
+               state->m_hasOOB = false;
+               state->m_hasATV = true;
+               state->m_hasAudio = true;
+               state->m_hasDVBT = true;
+               state->m_hasDVBC = false;
+               state->m_hasSAWSW = true;
+               state->m_hasGPIO2 = true;
+               state->m_hasGPIO1 = true;
+               state->m_hasIRQN = false;
+               break;
+       case 0x21:
+               /* typeId = DRX3921K_TYPE_ID */
+               state->m_hasLNA = false;
+               state->m_hasOOB = false;
+               state->m_hasATV = true;
+               state->m_hasAudio = true;
+               state->m_hasDVBT = true;
+               state->m_hasDVBC = true;
+               state->m_hasSAWSW = true;
+               state->m_hasGPIO2 = true;
+               state->m_hasGPIO1 = true;
+               state->m_hasIRQN = false;
+               break;
+       case 0x23:
+               /* typeId = DRX3923K_TYPE_ID */
+               state->m_hasLNA = false;
+               state->m_hasOOB = false;
+               state->m_hasATV = true;
+               state->m_hasAudio = true;
+               state->m_hasDVBT = true;
+               state->m_hasDVBC = true;
+               state->m_hasSAWSW = true;
+               state->m_hasGPIO2 = true;
+               state->m_hasGPIO1 = true;
+               state->m_hasIRQN = false;
+               break;
+       case 0x25:
+               /* typeId = DRX3925K_TYPE_ID */
+               state->m_hasLNA = false;
+               state->m_hasOOB = false;
+               state->m_hasATV = true;
+               state->m_hasAudio = true;
+               state->m_hasDVBT = true;
+               state->m_hasDVBC = true;
+               state->m_hasSAWSW = true;
+               state->m_hasGPIO2 = true;
+               state->m_hasGPIO1 = true;
+               state->m_hasIRQN = false;
+               break;
+       case 0x26:
+               /* typeId = DRX3926K_TYPE_ID */
+               state->m_hasLNA = false;
+               state->m_hasOOB = false;
+               state->m_hasATV = true;
+               state->m_hasAudio = false;
+               state->m_hasDVBT = true;
+               state->m_hasDVBC = true;
+               state->m_hasSAWSW = true;
+               state->m_hasGPIO2 = true;
+               state->m_hasGPIO1 = true;
+               state->m_hasIRQN = false;
+               break;
+       default:
+               printk(KERN_ERR "drxk: DeviceID 0x%02x not supported\n",
+                       ((sioTopJtagidLo >> 12) & 0xFF));
+               status = -EINVAL;
+               goto error2;
+       }
+
+       printk(KERN_INFO
+              "drxk: detected a drx-39%02xk, spin %s, xtal %d.%03d MHz\n",
+              ((sioTopJtagidLo >> 12) & 0xFF), spin,
+              state->m_oscClockFreq / 1000,
+              state->m_oscClockFreq % 1000);
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+error2:
+       return status;
+}
+
+static int HI_Command(struct drxk_state *state, u16 cmd, u16 *pResult)
+{
+       int status;
+       bool powerdown_cmd;
+
+       dprintk(1, "\n");
+
+       /* Write command */
+       status = write16(state, SIO_HI_RA_RAM_CMD__A, cmd);
+       if (status < 0)
+               goto error;
+       if (cmd == SIO_HI_RA_RAM_CMD_RESET)
+               msleep(1);
+
+       powerdown_cmd =
+           (bool) ((cmd == SIO_HI_RA_RAM_CMD_CONFIG) &&
+                   ((state->m_HICfgCtrl) &
+                    SIO_HI_RA_RAM_PAR_5_CFG_SLEEP__M) ==
+                   SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ);
+       if (powerdown_cmd == false) {
+               /* Wait until command rdy */
+               u32 retryCount = 0;
+               u16 waitCmd;
+
+               do {
+                       msleep(1);
+                       retryCount += 1;
+                       status = read16(state, SIO_HI_RA_RAM_CMD__A,
+                                         &waitCmd);
+               } while ((status < 0) && (retryCount < DRXK_MAX_RETRIES)
+                        && (waitCmd != 0));
+               if (status < 0)
+                       goto error;
+               status = read16(state, SIO_HI_RA_RAM_RES__A, pResult);
+       }
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+static int HI_CfgCommand(struct drxk_state *state)
+{
+       int status;
+
+       dprintk(1, "\n");
+
+       mutex_lock(&state->mutex);
+
+       status = write16(state, SIO_HI_RA_RAM_PAR_6__A, state->m_HICfgTimeout);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_HI_RA_RAM_PAR_5__A, state->m_HICfgCtrl);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_HI_RA_RAM_PAR_4__A, state->m_HICfgWakeUpKey);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_HI_RA_RAM_PAR_3__A, state->m_HICfgBridgeDelay);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_HI_RA_RAM_PAR_2__A, state->m_HICfgTimingDiv);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_HI_RA_RAM_PAR_1__A, SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY);
+       if (status < 0)
+               goto error;
+       status = HI_Command(state, SIO_HI_RA_RAM_CMD_CONFIG, 0);
+       if (status < 0)
+               goto error;
+
+       state->m_HICfgCtrl &= ~SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ;
+error:
+       mutex_unlock(&state->mutex);
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int InitHI(struct drxk_state *state)
+{
+       dprintk(1, "\n");
+
+       state->m_HICfgWakeUpKey = (state->demod_address << 1);
+       state->m_HICfgTimeout = 0x96FF;
+       /* port/bridge/power down ctrl */
+       state->m_HICfgCtrl = SIO_HI_RA_RAM_PAR_5_CFG_SLV0_SLAVE;
+
+       return HI_CfgCommand(state);
+}
+
+static int MPEGTSConfigurePins(struct drxk_state *state, bool mpegEnable)
+{
+       int status = -1;
+       u16 sioPdrMclkCfg = 0;
+       u16 sioPdrMdxCfg = 0;
+
+       dprintk(1, "\n");
+
+       /* stop lock indicator process */
+       status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+       if (status < 0)
+               goto error;
+
+       /*  MPEG TS pad configuration */
+       status = write16(state, SIO_TOP_COMM_KEY__A, 0xFABA);
+       if (status < 0)
+               goto error;
+
+       if (mpegEnable == false) {
+               /*  Set MPEG TS pads to inputmode */
+               status = write16(state, SIO_PDR_MSTRT_CFG__A, 0x0000);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MERR_CFG__A, 0x0000);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MCLK_CFG__A, 0x0000);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MVAL_CFG__A, 0x0000);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MD0_CFG__A, 0x0000);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MD1_CFG__A, 0x0000);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MD2_CFG__A, 0x0000);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MD3_CFG__A, 0x0000);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MD4_CFG__A, 0x0000);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MD5_CFG__A, 0x0000);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MD6_CFG__A, 0x0000);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MD7_CFG__A, 0x0000);
+               if (status < 0)
+                       goto error;
+       } else {
+               /* Enable MPEG output */
+               sioPdrMdxCfg =
+                       ((state->m_TSDataStrength <<
+                       SIO_PDR_MD0_CFG_DRIVE__B) | 0x0003);
+               sioPdrMclkCfg = ((state->m_TSClockkStrength <<
+                                       SIO_PDR_MCLK_CFG_DRIVE__B) |
+                                       0x0003);
+
+               status = write16(state, SIO_PDR_MSTRT_CFG__A, sioPdrMdxCfg);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MERR_CFG__A, 0x0000);   /* Disable */
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MVAL_CFG__A, 0x0000);   /* Disable */
+               if (status < 0)
+                       goto error;
+               if (state->m_enableParallel == true) {
+                       /* paralel -> enable MD1 to MD7 */
+                       status = write16(state, SIO_PDR_MD1_CFG__A, sioPdrMdxCfg);
+                       if (status < 0)
+                               goto error;
+                       status = write16(state, SIO_PDR_MD2_CFG__A, sioPdrMdxCfg);
+                       if (status < 0)
+                               goto error;
+                       status = write16(state, SIO_PDR_MD3_CFG__A, sioPdrMdxCfg);
+                       if (status < 0)
+                               goto error;
+                       status = write16(state, SIO_PDR_MD4_CFG__A, sioPdrMdxCfg);
+                       if (status < 0)
+                               goto error;
+                       status = write16(state, SIO_PDR_MD5_CFG__A, sioPdrMdxCfg);
+                       if (status < 0)
+                               goto error;
+                       status = write16(state, SIO_PDR_MD6_CFG__A, sioPdrMdxCfg);
+                       if (status < 0)
+                               goto error;
+                       status = write16(state, SIO_PDR_MD7_CFG__A, sioPdrMdxCfg);
+                       if (status < 0)
+                               goto error;
+               } else {
+                       sioPdrMdxCfg = ((state->m_TSDataStrength <<
+                                               SIO_PDR_MD0_CFG_DRIVE__B)
+                                       | 0x0003);
+                       /* serial -> disable MD1 to MD7 */
+                       status = write16(state, SIO_PDR_MD1_CFG__A, 0x0000);
+                       if (status < 0)
+                               goto error;
+                       status = write16(state, SIO_PDR_MD2_CFG__A, 0x0000);
+                       if (status < 0)
+                               goto error;
+                       status = write16(state, SIO_PDR_MD3_CFG__A, 0x0000);
+                       if (status < 0)
+                               goto error;
+                       status = write16(state, SIO_PDR_MD4_CFG__A, 0x0000);
+                       if (status < 0)
+                               goto error;
+                       status = write16(state, SIO_PDR_MD5_CFG__A, 0x0000);
+                       if (status < 0)
+                               goto error;
+                       status = write16(state, SIO_PDR_MD6_CFG__A, 0x0000);
+                       if (status < 0)
+                               goto error;
+                       status = write16(state, SIO_PDR_MD7_CFG__A, 0x0000);
+                       if (status < 0)
+                               goto error;
+               }
+               status = write16(state, SIO_PDR_MCLK_CFG__A, sioPdrMclkCfg);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MD0_CFG__A, sioPdrMdxCfg);
+               if (status < 0)
+                       goto error;
+       }
+       /*  Enable MB output over MPEG pads and ctl input */
+       status = write16(state, SIO_PDR_MON_CFG__A, 0x0000);
+       if (status < 0)
+               goto error;
+       /*  Write nomagic word to enable pdr reg write */
+       status = write16(state, SIO_TOP_COMM_KEY__A, 0x0000);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int MPEGTSDisable(struct drxk_state *state)
+{
+       dprintk(1, "\n");
+
+       return MPEGTSConfigurePins(state, false);
+}
+
+static int BLChainCmd(struct drxk_state *state,
+                     u16 romOffset, u16 nrOfElements, u32 timeOut)
+{
+       u16 blStatus = 0;
+       int status;
+       unsigned long end;
+
+       dprintk(1, "\n");
+       mutex_lock(&state->mutex);
+       status = write16(state, SIO_BL_MODE__A, SIO_BL_MODE_CHAIN);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_BL_CHAIN_ADDR__A, romOffset);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_BL_CHAIN_LEN__A, nrOfElements);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_BL_ENABLE__A, SIO_BL_ENABLE_ON);
+       if (status < 0)
+               goto error;
+
+       end = jiffies + msecs_to_jiffies(timeOut);
+       do {
+               msleep(1);
+               status = read16(state, SIO_BL_STATUS__A, &blStatus);
+               if (status < 0)
+                       goto error;
+       } while ((blStatus == 0x1) &&
+                       ((time_is_after_jiffies(end))));
+
+       if (blStatus == 0x1) {
+               printk(KERN_ERR "drxk: SIO not ready\n");
+               status = -EINVAL;
+               goto error2;
+       }
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+error2:
+       mutex_unlock(&state->mutex);
+       return status;
+}
+
+
+static int DownloadMicrocode(struct drxk_state *state,
+                            const u8 pMCImage[], u32 Length)
+{
+       const u8 *pSrc = pMCImage;
+       u16 Flags;
+       u16 Drain;
+       u32 Address;
+       u16 nBlocks;
+       u16 BlockSize;
+       u16 BlockCRC;
+       u32 offset = 0;
+       u32 i;
+       int status = 0;
+
+       dprintk(1, "\n");
+
+       /* down the drain (we don care about MAGIC_WORD) */
+       Drain = (pSrc[0] << 8) | pSrc[1];
+       pSrc += sizeof(u16);
+       offset += sizeof(u16);
+       nBlocks = (pSrc[0] << 8) | pSrc[1];
+       pSrc += sizeof(u16);
+       offset += sizeof(u16);
+
+       for (i = 0; i < nBlocks; i += 1) {
+               Address = (pSrc[0] << 24) | (pSrc[1] << 16) |
+                   (pSrc[2] << 8) | pSrc[3];
+               pSrc += sizeof(u32);
+               offset += sizeof(u32);
+
+               BlockSize = ((pSrc[0] << 8) | pSrc[1]) * sizeof(u16);
+               pSrc += sizeof(u16);
+               offset += sizeof(u16);
+
+               Flags = (pSrc[0] << 8) | pSrc[1];
+               pSrc += sizeof(u16);
+               offset += sizeof(u16);
+
+               BlockCRC = (pSrc[0] << 8) | pSrc[1];
+               pSrc += sizeof(u16);
+               offset += sizeof(u16);
+
+               if (offset + BlockSize > Length) {
+                       printk(KERN_ERR "drxk: Firmware is corrupted.\n");
+                       return -EINVAL;
+               }
+
+               status = write_block(state, Address, BlockSize, pSrc);
+               if (status < 0) {
+                       printk(KERN_ERR "drxk: Error %d while loading firmware\n", status);
+                       break;
+               }
+               pSrc += BlockSize;
+               offset += BlockSize;
+       }
+       return status;
+}
+
+static int DVBTEnableOFDMTokenRing(struct drxk_state *state, bool enable)
+{
+       int status;
+       u16 data = 0;
+       u16 desiredCtrl = SIO_OFDM_SH_OFDM_RING_ENABLE_ON;
+       u16 desiredStatus = SIO_OFDM_SH_OFDM_RING_STATUS_ENABLED;
+       unsigned long end;
+
+       dprintk(1, "\n");
+
+       if (enable == false) {
+               desiredCtrl = SIO_OFDM_SH_OFDM_RING_ENABLE_OFF;
+               desiredStatus = SIO_OFDM_SH_OFDM_RING_STATUS_DOWN;
+       }
+
+       status = read16(state, SIO_OFDM_SH_OFDM_RING_STATUS__A, &data);
+       if (status >= 0 && data == desiredStatus) {
+               /* tokenring already has correct status */
+               return status;
+       }
+       /* Disable/enable dvbt tokenring bridge   */
+       status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, desiredCtrl);
+
+       end = jiffies + msecs_to_jiffies(DRXK_OFDM_TR_SHUTDOWN_TIMEOUT);
+       do {
+               status = read16(state, SIO_OFDM_SH_OFDM_RING_STATUS__A, &data);
+               if ((status >= 0 && data == desiredStatus) || time_is_after_jiffies(end))
+                       break;
+               msleep(1);
+       } while (1);
+       if (data != desiredStatus) {
+               printk(KERN_ERR "drxk: SIO not ready\n");
+               return -EINVAL;
+       }
+       return status;
+}
+
+static int MPEGTSStop(struct drxk_state *state)
+{
+       int status = 0;
+       u16 fecOcSncMode = 0;
+       u16 fecOcIprMode = 0;
+
+       dprintk(1, "\n");
+
+       /* Gracefull shutdown (byte boundaries) */
+       status = read16(state, FEC_OC_SNC_MODE__A, &fecOcSncMode);
+       if (status < 0)
+               goto error;
+       fecOcSncMode |= FEC_OC_SNC_MODE_SHUTDOWN__M;
+       status = write16(state, FEC_OC_SNC_MODE__A, fecOcSncMode);
+       if (status < 0)
+               goto error;
+
+       /* Suppress MCLK during absence of data */
+       status = read16(state, FEC_OC_IPR_MODE__A, &fecOcIprMode);
+       if (status < 0)
+               goto error;
+       fecOcIprMode |= FEC_OC_IPR_MODE_MCLK_DIS_DAT_ABS__M;
+       status = write16(state, FEC_OC_IPR_MODE__A, fecOcIprMode);
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+static int scu_command(struct drxk_state *state,
+                      u16 cmd, u8 parameterLen,
+                      u16 *parameter, u8 resultLen, u16 *result)
+{
+#if (SCU_RAM_PARAM_0__A - SCU_RAM_PARAM_15__A) != 15
+#error DRXK register mapping no longer compatible with this routine!
+#endif
+       u16 curCmd = 0;
+       int status = -EINVAL;
+       unsigned long end;
+       u8 buffer[34];
+       int cnt = 0, ii;
+       const char *p;
+       char errname[30];
+
+       dprintk(1, "\n");
+
+       if ((cmd == 0) || ((parameterLen > 0) && (parameter == NULL)) ||
+           ((resultLen > 0) && (result == NULL)))
+               goto error;
+
+       mutex_lock(&state->mutex);
+
+       /* assume that the command register is ready
+               since it is checked afterwards */
+       for (ii = parameterLen - 1; ii >= 0; ii -= 1) {
+               buffer[cnt++] = (parameter[ii] & 0xFF);
+               buffer[cnt++] = ((parameter[ii] >> 8) & 0xFF);
+       }
+       buffer[cnt++] = (cmd & 0xFF);
+       buffer[cnt++] = ((cmd >> 8) & 0xFF);
+
+       write_block(state, SCU_RAM_PARAM_0__A -
+                       (parameterLen - 1), cnt, buffer);
+       /* Wait until SCU has processed command */
+       end = jiffies + msecs_to_jiffies(DRXK_MAX_WAITTIME);
+       do {
+               msleep(1);
+               status = read16(state, SCU_RAM_COMMAND__A, &curCmd);
+               if (status < 0)
+                       goto error;
+       } while (!(curCmd == DRX_SCU_READY) && (time_is_after_jiffies(end)));
+       if (curCmd != DRX_SCU_READY) {
+               printk(KERN_ERR "drxk: SCU not ready\n");
+               status = -EIO;
+               goto error2;
+       }
+       /* read results */
+       if ((resultLen > 0) && (result != NULL)) {
+               s16 err;
+               int ii;
+
+               for (ii = resultLen - 1; ii >= 0; ii -= 1) {
+                       status = read16(state, SCU_RAM_PARAM_0__A - ii, &result[ii]);
+                       if (status < 0)
+                               goto error;
+               }
+
+               /* Check if an error was reported by SCU */
+               err = (s16)result[0];
+               if (err >= 0)
+                       goto error;
+
+               /* check for the known error codes */
+               switch (err) {
+               case SCU_RESULT_UNKCMD:
+                       p = "SCU_RESULT_UNKCMD";
+                       break;
+               case SCU_RESULT_UNKSTD:
+                       p = "SCU_RESULT_UNKSTD";
+                       break;
+               case SCU_RESULT_SIZE:
+                       p = "SCU_RESULT_SIZE";
+                       break;
+               case SCU_RESULT_INVPAR:
+                       p = "SCU_RESULT_INVPAR";
+                       break;
+               default: /* Other negative values are errors */
+                       sprintf(errname, "ERROR: %d\n", err);
+                       p = errname;
+               }
+               printk(KERN_ERR "drxk: %s while sending cmd 0x%04x with params:", p, cmd);
+               print_hex_dump_bytes("drxk: ", DUMP_PREFIX_NONE, buffer, cnt);
+               status = -EINVAL;
+               goto error2;
+       }
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+error2:
+       mutex_unlock(&state->mutex);
+       return status;
+}
+
+static int SetIqmAf(struct drxk_state *state, bool active)
+{
+       u16 data = 0;
+       int status;
+
+       dprintk(1, "\n");
+
+       /* Configure IQM */
+       status = read16(state, IQM_AF_STDBY__A, &data);
+       if (status < 0)
+               goto error;
+
+       if (!active) {
+               data |= (IQM_AF_STDBY_STDBY_ADC_STANDBY
+                               | IQM_AF_STDBY_STDBY_AMP_STANDBY
+                               | IQM_AF_STDBY_STDBY_PD_STANDBY
+                               | IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY
+                               | IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY);
+       } else {
+               data &= ((~IQM_AF_STDBY_STDBY_ADC_STANDBY)
+                               & (~IQM_AF_STDBY_STDBY_AMP_STANDBY)
+                               & (~IQM_AF_STDBY_STDBY_PD_STANDBY)
+                               & (~IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY)
+                               & (~IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY)
+                       );
+       }
+       status = write16(state, IQM_AF_STDBY__A, data);
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int CtrlPowerMode(struct drxk_state *state, enum DRXPowerMode *mode)
+{
+       int status = 0;
+       u16 sioCcPwdMode = 0;
+
+       dprintk(1, "\n");
+
+       /* Check arguments */
+       if (mode == NULL)
+               return -EINVAL;
+
+       switch (*mode) {
+       case DRX_POWER_UP:
+               sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_NONE;
+               break;
+       case DRXK_POWER_DOWN_OFDM:
+               sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_OFDM;
+               break;
+       case DRXK_POWER_DOWN_CORE:
+               sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_CLOCK;
+               break;
+       case DRXK_POWER_DOWN_PLL:
+               sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_PLL;
+               break;
+       case DRX_POWER_DOWN:
+               sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_OSC;
+               break;
+       default:
+               /* Unknow sleep mode */
+               return -EINVAL;
+       }
+
+       /* If already in requested power mode, do nothing */
+       if (state->m_currentPowerMode == *mode)
+               return 0;
+
+       /* For next steps make sure to start from DRX_POWER_UP mode */
+       if (state->m_currentPowerMode != DRX_POWER_UP) {
+               status = PowerUpDevice(state);
+               if (status < 0)
+                       goto error;
+               status = DVBTEnableOFDMTokenRing(state, true);
+               if (status < 0)
+                       goto error;
+       }
+
+       if (*mode == DRX_POWER_UP) {
+               /* Restore analog & pin configuartion */
+       } else {
+               /* Power down to requested mode */
+               /* Backup some register settings */
+               /* Set pins with possible pull-ups connected
+                  to them in input mode */
+               /* Analog power down */
+               /* ADC power down */
+               /* Power down device */
+               /* stop all comm_exec */
+               /* Stop and power down previous standard */
+               switch (state->m_OperationMode) {
+               case OM_DVBT:
+                       status = MPEGTSStop(state);
+                       if (status < 0)
+                               goto error;
+                       status = PowerDownDVBT(state, false);
+                       if (status < 0)
+                               goto error;
+                       break;
+               case OM_QAM_ITU_A:
+               case OM_QAM_ITU_C:
+                       status = MPEGTSStop(state);
+                       if (status < 0)
+                               goto error;
+                       status = PowerDownQAM(state);
+                       if (status < 0)
+                               goto error;
+                       break;
+               default:
+                       break;
+               }
+               status = DVBTEnableOFDMTokenRing(state, false);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_CC_PWD_MODE__A, sioCcPwdMode);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY);
+               if (status < 0)
+                       goto error;
+
+               if (*mode != DRXK_POWER_DOWN_OFDM) {
+                       state->m_HICfgCtrl |=
+                               SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ;
+                       status = HI_CfgCommand(state);
+                       if (status < 0)
+                               goto error;
+               }
+       }
+       state->m_currentPowerMode = *mode;
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+static int PowerDownDVBT(struct drxk_state *state, bool setPowerMode)
+{
+       enum DRXPowerMode powerMode = DRXK_POWER_DOWN_OFDM;
+       u16 cmdResult = 0;
+       u16 data = 0;
+       int status;
+
+       dprintk(1, "\n");
+
+       status = read16(state, SCU_COMM_EXEC__A, &data);
+       if (status < 0)
+               goto error;
+       if (data == SCU_COMM_EXEC_ACTIVE) {
+               /* Send OFDM stop command */
+               status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_STOP, 0, NULL, 1, &cmdResult);
+               if (status < 0)
+                       goto error;
+               /* Send OFDM reset command */
+               status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_RESET, 0, NULL, 1, &cmdResult);
+               if (status < 0)
+                       goto error;
+       }
+
+       /* Reset datapath for OFDM, processors first */
+       status = write16(state, OFDM_SC_COMM_EXEC__A, OFDM_SC_COMM_EXEC_STOP);
+       if (status < 0)
+               goto error;
+       status = write16(state, OFDM_LC_COMM_EXEC__A, OFDM_LC_COMM_EXEC_STOP);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_COMM_EXEC__A, IQM_COMM_EXEC_B_STOP);
+       if (status < 0)
+               goto error;
+
+       /* powerdown AFE                   */
+       status = SetIqmAf(state, false);
+       if (status < 0)
+               goto error;
+
+       /* powerdown to OFDM mode          */
+       if (setPowerMode) {
+               status = CtrlPowerMode(state, &powerMode);
+               if (status < 0)
+                       goto error;
+       }
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int SetOperationMode(struct drxk_state *state,
+                           enum OperationMode oMode)
+{
+       int status = 0;
+
+       dprintk(1, "\n");
+       /*
+          Stop and power down previous standard
+          TODO investigate total power down instead of partial
+          power down depending on "previous" standard.
+        */
+
+       /* disable HW lock indicator */
+       status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+       if (status < 0)
+               goto error;
+
+       /* Device is already at the required mode */
+       if (state->m_OperationMode == oMode)
+               return 0;
+
+       switch (state->m_OperationMode) {
+               /* OM_NONE was added for start up */
+       case OM_NONE:
+               break;
+       case OM_DVBT:
+               status = MPEGTSStop(state);
+               if (status < 0)
+                       goto error;
+               status = PowerDownDVBT(state, true);
+               if (status < 0)
+                       goto error;
+               state->m_OperationMode = OM_NONE;
+               break;
+       case OM_QAM_ITU_A:      /* fallthrough */
+       case OM_QAM_ITU_C:
+               status = MPEGTSStop(state);
+               if (status < 0)
+                       goto error;
+               status = PowerDownQAM(state);
+               if (status < 0)
+                       goto error;
+               state->m_OperationMode = OM_NONE;
+               break;
+       case OM_QAM_ITU_B:
+       default:
+               status = -EINVAL;
+               goto error;
+       }
+
+       /*
+               Power up new standard
+               */
+       switch (oMode) {
+       case OM_DVBT:
+               state->m_OperationMode = oMode;
+               status = SetDVBTStandard(state, oMode);
+               if (status < 0)
+                       goto error;
+               break;
+       case OM_QAM_ITU_A:      /* fallthrough */
+       case OM_QAM_ITU_C:
+               state->m_OperationMode = oMode;
+               status = SetQAMStandard(state, oMode);
+               if (status < 0)
+                       goto error;
+               break;
+       case OM_QAM_ITU_B:
+       default:
+               status = -EINVAL;
+       }
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int Start(struct drxk_state *state, s32 offsetFreq,
+                s32 IntermediateFrequency)
+{
+       int status = -EINVAL;
+
+       u16 IFreqkHz;
+       s32 OffsetkHz = offsetFreq / 1000;
+
+       dprintk(1, "\n");
+       if (state->m_DrxkState != DRXK_STOPPED &&
+               state->m_DrxkState != DRXK_DTV_STARTED)
+               goto error;
+
+       state->m_bMirrorFreqSpect = (state->param.inversion == INVERSION_ON);
+
+       if (IntermediateFrequency < 0) {
+               state->m_bMirrorFreqSpect = !state->m_bMirrorFreqSpect;
+               IntermediateFrequency = -IntermediateFrequency;
+       }
+
+       switch (state->m_OperationMode) {
+       case OM_QAM_ITU_A:
+       case OM_QAM_ITU_C:
+               IFreqkHz = (IntermediateFrequency / 1000);
+               status = SetQAM(state, IFreqkHz, OffsetkHz);
+               if (status < 0)
+                       goto error;
+               state->m_DrxkState = DRXK_DTV_STARTED;
+               break;
+       case OM_DVBT:
+               IFreqkHz = (IntermediateFrequency / 1000);
+               status = MPEGTSStop(state);
+               if (status < 0)
+                       goto error;
+               status = SetDVBT(state, IFreqkHz, OffsetkHz);
+               if (status < 0)
+                       goto error;
+               status = DVBTStart(state);
+               if (status < 0)
+                       goto error;
+               state->m_DrxkState = DRXK_DTV_STARTED;
+               break;
+       default:
+               break;
+       }
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int ShutDown(struct drxk_state *state)
+{
+       dprintk(1, "\n");
+
+       MPEGTSStop(state);
+       return 0;
+}
+
+static int GetLockStatus(struct drxk_state *state, u32 *pLockStatus,
+                        u32 Time)
+{
+       int status = -EINVAL;
+
+       dprintk(1, "\n");
+
+       if (pLockStatus == NULL)
+               goto error;
+
+       *pLockStatus = NOT_LOCKED;
+
+       /* define the SCU command code */
+       switch (state->m_OperationMode) {
+       case OM_QAM_ITU_A:
+       case OM_QAM_ITU_B:
+       case OM_QAM_ITU_C:
+               status = GetQAMLockStatus(state, pLockStatus);
+               break;
+       case OM_DVBT:
+               status = GetDVBTLockStatus(state, pLockStatus);
+               break;
+       default:
+               break;
+       }
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int MPEGTSStart(struct drxk_state *state)
+{
+       int status;
+
+       u16 fecOcSncMode = 0;
+
+       /* Allow OC to sync again */
+       status = read16(state, FEC_OC_SNC_MODE__A, &fecOcSncMode);
+       if (status < 0)
+               goto error;
+       fecOcSncMode &= ~FEC_OC_SNC_MODE_SHUTDOWN__M;
+       status = write16(state, FEC_OC_SNC_MODE__A, fecOcSncMode);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_SNC_UNLOCK__A, 1);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int MPEGTSDtoInit(struct drxk_state *state)
+{
+       int status;
+
+       dprintk(1, "\n");
+
+       /* Rate integration settings */
+       status = write16(state, FEC_OC_RCN_CTL_STEP_LO__A, 0x0000);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_RCN_CTL_STEP_HI__A, 0x000C);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_RCN_GAIN__A, 0x000A);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_AVR_PARM_A__A, 0x0008);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_AVR_PARM_B__A, 0x0006);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_TMD_HI_MARGIN__A, 0x0680);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_TMD_LO_MARGIN__A, 0x0080);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_TMD_COUNT__A, 0x03F4);
+       if (status < 0)
+               goto error;
+
+       /* Additional configuration */
+       status = write16(state, FEC_OC_OCR_INVERT__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_SNC_LWM__A, 2);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_SNC_HWM__A, 12);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+static int MPEGTSDtoSetup(struct drxk_state *state,
+                         enum OperationMode oMode)
+{
+       int status;
+
+       u16 fecOcRegMode = 0;   /* FEC_OC_MODE       register value */
+       u16 fecOcRegIprMode = 0;        /* FEC_OC_IPR_MODE   register value */
+       u16 fecOcDtoMode = 0;   /* FEC_OC_IPR_INVERT register value */
+       u16 fecOcFctMode = 0;   /* FEC_OC_IPR_INVERT register value */
+       u16 fecOcDtoPeriod = 2; /* FEC_OC_IPR_INVERT register value */
+       u16 fecOcDtoBurstLen = 188;     /* FEC_OC_IPR_INVERT register value */
+       u32 fecOcRcnCtlRate = 0;        /* FEC_OC_IPR_INVERT register value */
+       u16 fecOcTmdMode = 0;
+       u16 fecOcTmdIntUpdRate = 0;
+       u32 maxBitRate = 0;
+       bool staticCLK = false;
+
+       dprintk(1, "\n");
+
+       /* Check insertion of the Reed-Solomon parity bytes */
+       status = read16(state, FEC_OC_MODE__A, &fecOcRegMode);
+       if (status < 0)
+               goto error;
+       status = read16(state, FEC_OC_IPR_MODE__A, &fecOcRegIprMode);
+       if (status < 0)
+               goto error;
+       fecOcRegMode &= (~FEC_OC_MODE_PARITY__M);
+       fecOcRegIprMode &= (~FEC_OC_IPR_MODE_MVAL_DIS_PAR__M);
+       if (state->m_insertRSByte == true) {
+               /* enable parity symbol forward */
+               fecOcRegMode |= FEC_OC_MODE_PARITY__M;
+               /* MVAL disable during parity bytes */
+               fecOcRegIprMode |= FEC_OC_IPR_MODE_MVAL_DIS_PAR__M;
+               /* TS burst length to 204 */
+               fecOcDtoBurstLen = 204;
+       }
+
+       /* Check serial or parrallel output */
+       fecOcRegIprMode &= (~(FEC_OC_IPR_MODE_SERIAL__M));
+       if (state->m_enableParallel == false) {
+               /* MPEG data output is serial -> set ipr_mode[0] */
+               fecOcRegIprMode |= FEC_OC_IPR_MODE_SERIAL__M;
+       }
+
+       switch (oMode) {
+       case OM_DVBT:
+               maxBitRate = state->m_DVBTBitrate;
+               fecOcTmdMode = 3;
+               fecOcRcnCtlRate = 0xC00000;
+               staticCLK = state->m_DVBTStaticCLK;
+               break;
+       case OM_QAM_ITU_A:      /* fallthrough */
+       case OM_QAM_ITU_C:
+               fecOcTmdMode = 0x0004;
+               fecOcRcnCtlRate = 0xD2B4EE;     /* good for >63 Mb/s */
+               maxBitRate = state->m_DVBCBitrate;
+               staticCLK = state->m_DVBCStaticCLK;
+               break;
+       default:
+               status = -EINVAL;
+       }               /* switch (standard) */
+       if (status < 0)
+               goto error;
+
+       /* Configure DTO's */
+       if (staticCLK) {
+               u32 bitRate = 0;
+
+               /* Rational DTO for MCLK source (static MCLK rate),
+                       Dynamic DTO for optimal grouping
+                       (avoid intra-packet gaps),
+                       DTO offset enable to sync TS burst with MSTRT */
+               fecOcDtoMode = (FEC_OC_DTO_MODE_DYNAMIC__M |
+                               FEC_OC_DTO_MODE_OFFSET_ENABLE__M);
+               fecOcFctMode = (FEC_OC_FCT_MODE_RAT_ENA__M |
+                               FEC_OC_FCT_MODE_VIRT_ENA__M);
+
+               /* Check user defined bitrate */
+               bitRate = maxBitRate;
+               if (bitRate > 75900000UL) {     /* max is 75.9 Mb/s */
+                       bitRate = 75900000UL;
+               }
+               /* Rational DTO period:
+                       dto_period = (Fsys / bitrate) - 2
+
+                       Result should be floored,
+                       to make sure >= requested bitrate
+                       */
+               fecOcDtoPeriod = (u16) (((state->m_sysClockFreq)
+                                               * 1000) / bitRate);
+               if (fecOcDtoPeriod <= 2)
+                       fecOcDtoPeriod = 0;
+               else
+                       fecOcDtoPeriod -= 2;
+               fecOcTmdIntUpdRate = 8;
+       } else {
+               /* (commonAttr->staticCLK == false) => dynamic mode */
+               fecOcDtoMode = FEC_OC_DTO_MODE_DYNAMIC__M;
+               fecOcFctMode = FEC_OC_FCT_MODE__PRE;
+               fecOcTmdIntUpdRate = 5;
+       }
+
+       /* Write appropriate registers with requested configuration */
+       status = write16(state, FEC_OC_DTO_BURST_LEN__A, fecOcDtoBurstLen);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_DTO_PERIOD__A, fecOcDtoPeriod);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_DTO_MODE__A, fecOcDtoMode);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_FCT_MODE__A, fecOcFctMode);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_MODE__A, fecOcRegMode);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_IPR_MODE__A, fecOcRegIprMode);
+       if (status < 0)
+               goto error;
+
+       /* Rate integration settings */
+       status = write32(state, FEC_OC_RCN_CTL_RATE_LO__A, fecOcRcnCtlRate);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_TMD_INT_UPD_RATE__A, fecOcTmdIntUpdRate);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_TMD_MODE__A, fecOcTmdMode);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int MPEGTSConfigurePolarity(struct drxk_state *state)
+{
+       u16 fecOcRegIprInvert = 0;
+
+       /* Data mask for the output data byte */
+       u16 InvertDataMask =
+           FEC_OC_IPR_INVERT_MD7__M | FEC_OC_IPR_INVERT_MD6__M |
+           FEC_OC_IPR_INVERT_MD5__M | FEC_OC_IPR_INVERT_MD4__M |
+           FEC_OC_IPR_INVERT_MD3__M | FEC_OC_IPR_INVERT_MD2__M |
+           FEC_OC_IPR_INVERT_MD1__M | FEC_OC_IPR_INVERT_MD0__M;
+
+       dprintk(1, "\n");
+
+       /* Control selective inversion of output bits */
+       fecOcRegIprInvert &= (~(InvertDataMask));
+       if (state->m_invertDATA == true)
+               fecOcRegIprInvert |= InvertDataMask;
+       fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MERR__M));
+       if (state->m_invertERR == true)
+               fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MERR__M;
+       fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MSTRT__M));
+       if (state->m_invertSTR == true)
+               fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MSTRT__M;
+       fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MVAL__M));
+       if (state->m_invertVAL == true)
+               fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MVAL__M;
+       fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MCLK__M));
+       if (state->m_invertCLK == true)
+               fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MCLK__M;
+
+       return write16(state, FEC_OC_IPR_INVERT__A, fecOcRegIprInvert);
+}
+
+#define   SCU_RAM_AGC_KI_INV_RF_POL__M 0x4000
+
+static int SetAgcRf(struct drxk_state *state,
+                   struct SCfgAgc *pAgcCfg, bool isDTV)
+{
+       int status = -EINVAL;
+       u16 data = 0;
+       struct SCfgAgc *pIfAgcSettings;
+
+       dprintk(1, "\n");
+
+       if (pAgcCfg == NULL)
+               goto error;
+
+       switch (pAgcCfg->ctrlMode) {
+       case DRXK_AGC_CTRL_AUTO:
+               /* Enable RF AGC DAC */
+               status = read16(state, IQM_AF_STDBY__A, &data);
+               if (status < 0)
+                       goto error;
+               data &= ~IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY;
+               status = write16(state, IQM_AF_STDBY__A, data);
+               if (status < 0)
+                       goto error;
+               status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
+               if (status < 0)
+                       goto error;
+
+               /* Enable SCU RF AGC loop */
+               data &= ~SCU_RAM_AGC_CONFIG_DISABLE_RF_AGC__M;
+
+               /* Polarity */
+               if (state->m_RfAgcPol)
+                       data |= SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
+               else
+                       data &= ~SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
+               status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
+               if (status < 0)
+                       goto error;
+
+               /* Set speed (using complementary reduction value) */
+               status = read16(state, SCU_RAM_AGC_KI_RED__A, &data);
+               if (status < 0)
+                       goto error;
+
+               data &= ~SCU_RAM_AGC_KI_RED_RAGC_RED__M;
+               data |= (~(pAgcCfg->speed <<
+                               SCU_RAM_AGC_KI_RED_RAGC_RED__B)
+                               & SCU_RAM_AGC_KI_RED_RAGC_RED__M);
+
+               status = write16(state, SCU_RAM_AGC_KI_RED__A, data);
+               if (status < 0)
+                       goto error;
+
+               if (IsDVBT(state))
+                       pIfAgcSettings = &state->m_dvbtIfAgcCfg;
+               else if (IsQAM(state))
+                       pIfAgcSettings = &state->m_qamIfAgcCfg;
+               else
+                       pIfAgcSettings = &state->m_atvIfAgcCfg;
+               if (pIfAgcSettings == NULL) {
+                       status = -EINVAL;
+                       goto error;
+               }
+
+               /* Set TOP, only if IF-AGC is in AUTO mode */
+               if (pIfAgcSettings->ctrlMode == DRXK_AGC_CTRL_AUTO)
+                       status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, pAgcCfg->top);
+                       if (status < 0)
+                               goto error;
+
+               /* Cut-Off current */
+               status = write16(state, SCU_RAM_AGC_RF_IACCU_HI_CO__A, pAgcCfg->cutOffCurrent);
+               if (status < 0)
+                       goto error;
+
+               /* Max. output level */
+               status = write16(state, SCU_RAM_AGC_RF_MAX__A, pAgcCfg->maxOutputLevel);
+               if (status < 0)
+                       goto error;
+
+               break;
+
+       case DRXK_AGC_CTRL_USER:
+               /* Enable RF AGC DAC */
+               status = read16(state, IQM_AF_STDBY__A, &data);
+               if (status < 0)
+                       goto error;
+               data &= ~IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY;
+               status = write16(state, IQM_AF_STDBY__A, data);
+               if (status < 0)
+                       goto error;
+
+               /* Disable SCU RF AGC loop */
+               status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
+               if (status < 0)
+                       goto error;
+               data |= SCU_RAM_AGC_CONFIG_DISABLE_RF_AGC__M;
+               if (state->m_RfAgcPol)
+                       data |= SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
+               else
+                       data &= ~SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
+               status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
+               if (status < 0)
+                       goto error;
+
+               /* SCU c.o.c. to 0, enabling full control range */
+               status = write16(state, SCU_RAM_AGC_RF_IACCU_HI_CO__A, 0);
+               if (status < 0)
+                       goto error;
+
+               /* Write value to output pin */
+               status = write16(state, SCU_RAM_AGC_RF_IACCU_HI__A, pAgcCfg->outputLevel);
+               if (status < 0)
+                       goto error;
+               break;
+
+       case DRXK_AGC_CTRL_OFF:
+               /* Disable RF AGC DAC */
+               status = read16(state, IQM_AF_STDBY__A, &data);
+               if (status < 0)
+                       goto error;
+               data |= IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY;
+               status = write16(state, IQM_AF_STDBY__A, data);
+               if (status < 0)
+                       goto error;
+
+               /* Disable SCU RF AGC loop */
+               status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
+               if (status < 0)
+                       goto error;
+               data |= SCU_RAM_AGC_CONFIG_DISABLE_RF_AGC__M;
+               status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
+               if (status < 0)
+                       goto error;
+               break;
+
+       default:
+               status = -EINVAL;
+
+       }
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+#define SCU_RAM_AGC_KI_INV_IF_POL__M 0x2000
+
+static int SetAgcIf(struct drxk_state *state,
+                   struct SCfgAgc *pAgcCfg, bool isDTV)
+{
+       u16 data = 0;
+       int status = 0;
+       struct SCfgAgc *pRfAgcSettings;
+
+       dprintk(1, "\n");
+
+       switch (pAgcCfg->ctrlMode) {
+       case DRXK_AGC_CTRL_AUTO:
+
+               /* Enable IF AGC DAC */
+               status = read16(state, IQM_AF_STDBY__A, &data);
+               if (status < 0)
+                       goto error;
+               data &= ~IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY;
+               status = write16(state, IQM_AF_STDBY__A, data);
+               if (status < 0)
+                       goto error;
+
+               status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
+               if (status < 0)
+                       goto error;
+
+               /* Enable SCU IF AGC loop */
+               data &= ~SCU_RAM_AGC_CONFIG_DISABLE_IF_AGC__M;
+
+               /* Polarity */
+               if (state->m_IfAgcPol)
+                       data |= SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
+               else
+                       data &= ~SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
+               status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
+               if (status < 0)
+                       goto error;
+
+               /* Set speed (using complementary reduction value) */
+               status = read16(state, SCU_RAM_AGC_KI_RED__A, &data);
+               if (status < 0)
+                       goto error;
+               data &= ~SCU_RAM_AGC_KI_RED_IAGC_RED__M;
+               data |= (~(pAgcCfg->speed <<
+                               SCU_RAM_AGC_KI_RED_IAGC_RED__B)
+                               & SCU_RAM_AGC_KI_RED_IAGC_RED__M);
+
+               status = write16(state, SCU_RAM_AGC_KI_RED__A, data);
+               if (status < 0)
+                       goto error;
+
+               if (IsQAM(state))
+                       pRfAgcSettings = &state->m_qamRfAgcCfg;
+               else
+                       pRfAgcSettings = &state->m_atvRfAgcCfg;
+               if (pRfAgcSettings == NULL)
+                       return -1;
+               /* Restore TOP */
+               status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, pRfAgcSettings->top);
+               if (status < 0)
+                       goto error;
+               break;
+
+       case DRXK_AGC_CTRL_USER:
+
+               /* Enable IF AGC DAC */
+               status = read16(state, IQM_AF_STDBY__A, &data);
+               if (status < 0)
+                       goto error;
+               data &= ~IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY;
+               status = write16(state, IQM_AF_STDBY__A, data);
+               if (status < 0)
+                       goto error;
+
+               status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
+               if (status < 0)
+                       goto error;
+
+               /* Disable SCU IF AGC loop */
+               data |= SCU_RAM_AGC_CONFIG_DISABLE_IF_AGC__M;
+
+               /* Polarity */
+               if (state->m_IfAgcPol)
+                       data |= SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
+               else
+                       data &= ~SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
+               status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
+               if (status < 0)
+                       goto error;
+
+               /* Write value to output pin */
+               status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, pAgcCfg->outputLevel);
+               if (status < 0)
+                       goto error;
+               break;
+
+       case DRXK_AGC_CTRL_OFF:
+
+               /* Disable If AGC DAC */
+               status = read16(state, IQM_AF_STDBY__A, &data);
+               if (status < 0)
+                       goto error;
+               data |= IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY;
+               status = write16(state, IQM_AF_STDBY__A, data);
+               if (status < 0)
+                       goto error;
+
+               /* Disable SCU IF AGC loop */
+               status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
+               if (status < 0)
+                       goto error;
+               data |= SCU_RAM_AGC_CONFIG_DISABLE_IF_AGC__M;
+               status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
+               if (status < 0)
+                       goto error;
+               break;
+       }               /* switch (agcSettingsIf->ctrlMode) */
+
+       /* always set the top to support
+               configurations without if-loop */
+       status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MIN__A, pAgcCfg->top);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int ReadIFAgc(struct drxk_state *state, u32 *pValue)
+{
+       u16 agcDacLvl;
+       int status;
+       u16 Level = 0;
+
+       dprintk(1, "\n");
+
+       status = read16(state, IQM_AF_AGC_IF__A, &agcDacLvl);
+       if (status < 0) {
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               return status;
+       }
+
+       *pValue = 0;
+
+       if (agcDacLvl > DRXK_AGC_DAC_OFFSET)
+               Level = agcDacLvl - DRXK_AGC_DAC_OFFSET;
+       if (Level < 14000)
+               *pValue = (14000 - Level) / 4;
+       else
+               *pValue = 0;
+
+       return status;
+}
+
+static int GetQAMSignalToNoise(struct drxk_state *state,
+                              s32 *pSignalToNoise)
+{
+       int status = 0;
+       u16 qamSlErrPower = 0;  /* accum. error between
+                                       raw and sliced symbols */
+       u32 qamSlSigPower = 0;  /* used for MER, depends of
+                                       QAM constellation */
+       u32 qamSlMer = 0;       /* QAM MER */
+
+       dprintk(1, "\n");
+
+       /* MER calculation */
+
+       /* get the register value needed for MER */
+       status = read16(state, QAM_SL_ERR_POWER__A, &qamSlErrPower);
+       if (status < 0) {
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               return -EINVAL;
+       }
+
+       switch (state->param.u.qam.modulation) {
+       case QAM_16:
+               qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM16 << 2;
+               break;
+       case QAM_32:
+               qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM32 << 2;
+               break;
+       case QAM_64:
+               qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM64 << 2;
+               break;
+       case QAM_128:
+               qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM128 << 2;
+               break;
+       default:
+       case QAM_256:
+               qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM256 << 2;
+               break;
+       }
+
+       if (qamSlErrPower > 0) {
+               qamSlMer = Log10Times100(qamSlSigPower) -
+                       Log10Times100((u32) qamSlErrPower);
+       }
+       *pSignalToNoise = qamSlMer;
+
+       return status;
+}
+
+static int GetDVBTSignalToNoise(struct drxk_state *state,
+                               s32 *pSignalToNoise)
+{
+       int status;
+       u16 regData = 0;
+       u32 EqRegTdSqrErrI = 0;
+       u32 EqRegTdSqrErrQ = 0;
+       u16 EqRegTdSqrErrExp = 0;
+       u16 EqRegTdTpsPwrOfs = 0;
+       u16 EqRegTdReqSmbCnt = 0;
+       u32 tpsCnt = 0;
+       u32 SqrErrIQ = 0;
+       u32 a = 0;
+       u32 b = 0;
+       u32 c = 0;
+       u32 iMER = 0;
+       u16 transmissionParams = 0;
+
+       dprintk(1, "\n");
+
+       status = read16(state, OFDM_EQ_TOP_TD_TPS_PWR_OFS__A, &EqRegTdTpsPwrOfs);
+       if (status < 0)
+               goto error;
+       status = read16(state, OFDM_EQ_TOP_TD_REQ_SMB_CNT__A, &EqRegTdReqSmbCnt);
+       if (status < 0)
+               goto error;
+       status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_EXP__A, &EqRegTdSqrErrExp);
+       if (status < 0)
+               goto error;
+       status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_I__A, &regData);
+       if (status < 0)
+               goto error;
+       /* Extend SQR_ERR_I operational range */
+       EqRegTdSqrErrI = (u32) regData;
+       if ((EqRegTdSqrErrExp > 11) &&
+               (EqRegTdSqrErrI < 0x00000FFFUL)) {
+               EqRegTdSqrErrI += 0x00010000UL;
+       }
+       status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_Q__A, &regData);
+       if (status < 0)
+               goto error;
+       /* Extend SQR_ERR_Q operational range */
+       EqRegTdSqrErrQ = (u32) regData;
+       if ((EqRegTdSqrErrExp > 11) &&
+               (EqRegTdSqrErrQ < 0x00000FFFUL))
+               EqRegTdSqrErrQ += 0x00010000UL;
+
+       status = read16(state, OFDM_SC_RA_RAM_OP_PARAM__A, &transmissionParams);
+       if (status < 0)
+               goto error;
+
+       /* Check input data for MER */
+
+       /* MER calculation (in 0.1 dB) without math.h */
+       if ((EqRegTdTpsPwrOfs == 0) || (EqRegTdReqSmbCnt == 0))
+               iMER = 0;
+       else if ((EqRegTdSqrErrI + EqRegTdSqrErrQ) == 0) {
+               /* No error at all, this must be the HW reset value
+                       * Apparently no first measurement yet
+                       * Set MER to 0.0 */
+               iMER = 0;
+       } else {
+               SqrErrIQ = (EqRegTdSqrErrI + EqRegTdSqrErrQ) <<
+                       EqRegTdSqrErrExp;
+               if ((transmissionParams &
+                       OFDM_SC_RA_RAM_OP_PARAM_MODE__M)
+                       == OFDM_SC_RA_RAM_OP_PARAM_MODE_2K)
+                       tpsCnt = 17;
+               else
+                       tpsCnt = 68;
+
+               /* IMER = 100 * log10 (x)
+                       where x = (EqRegTdTpsPwrOfs^2 *
+                       EqRegTdReqSmbCnt * tpsCnt)/SqrErrIQ
+
+                       => IMER = a + b -c
+                       where a = 100 * log10 (EqRegTdTpsPwrOfs^2)
+                       b = 100 * log10 (EqRegTdReqSmbCnt * tpsCnt)
+                       c = 100 * log10 (SqrErrIQ)
+                       */
+
+               /* log(x) x = 9bits * 9bits->18 bits  */
+               a = Log10Times100(EqRegTdTpsPwrOfs *
+                                       EqRegTdTpsPwrOfs);
+               /* log(x) x = 16bits * 7bits->23 bits  */
+               b = Log10Times100(EqRegTdReqSmbCnt * tpsCnt);
+               /* log(x) x = (16bits + 16bits) << 15 ->32 bits  */
+               c = Log10Times100(SqrErrIQ);
+
+               iMER = a + b;
+               /* No negative MER, clip to zero */
+               if (iMER > c)
+                       iMER -= c;
+               else
+                       iMER = 0;
+       }
+       *pSignalToNoise = iMER;
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int GetSignalToNoise(struct drxk_state *state, s32 *pSignalToNoise)
+{
+       dprintk(1, "\n");
+
+       *pSignalToNoise = 0;
+       switch (state->m_OperationMode) {
+       case OM_DVBT:
+               return GetDVBTSignalToNoise(state, pSignalToNoise);
+       case OM_QAM_ITU_A:
+       case OM_QAM_ITU_C:
+               return GetQAMSignalToNoise(state, pSignalToNoise);
+       default:
+               break;
+       }
+       return 0;
+}
+
+#if 0
+static int GetDVBTQuality(struct drxk_state *state, s32 *pQuality)
+{
+       /* SNR Values for quasi errorfree reception rom Nordig 2.2 */
+       int status = 0;
+
+       dprintk(1, "\n");
+
+       static s32 QE_SN[] = {
+               51,             /* QPSK 1/2 */
+               69,             /* QPSK 2/3 */
+               79,             /* QPSK 3/4 */
+               89,             /* QPSK 5/6 */
+               97,             /* QPSK 7/8 */
+               108,            /* 16-QAM 1/2 */
+               131,            /* 16-QAM 2/3 */
+               146,            /* 16-QAM 3/4 */
+               156,            /* 16-QAM 5/6 */
+               160,            /* 16-QAM 7/8 */
+               165,            /* 64-QAM 1/2 */
+               187,            /* 64-QAM 2/3 */
+               202,            /* 64-QAM 3/4 */
+               216,            /* 64-QAM 5/6 */
+               225,            /* 64-QAM 7/8 */
+       };
+
+       *pQuality = 0;
+
+       do {
+               s32 SignalToNoise = 0;
+               u16 Constellation = 0;
+               u16 CodeRate = 0;
+               u32 SignalToNoiseRel;
+               u32 BERQuality;
+
+               status = GetDVBTSignalToNoise(state, &SignalToNoise);
+               if (status < 0)
+                       break;
+               status = read16(state, OFDM_EQ_TOP_TD_TPS_CONST__A, &Constellation);
+               if (status < 0)
+                       break;
+               Constellation &= OFDM_EQ_TOP_TD_TPS_CONST__M;
+
+               status = read16(state, OFDM_EQ_TOP_TD_TPS_CODE_HP__A, &CodeRate);
+               if (status < 0)
+                       break;
+               CodeRate &= OFDM_EQ_TOP_TD_TPS_CODE_HP__M;
+
+               if (Constellation > OFDM_EQ_TOP_TD_TPS_CONST_64QAM ||
+                   CodeRate > OFDM_EQ_TOP_TD_TPS_CODE_LP_7_8)
+                       break;
+               SignalToNoiseRel = SignalToNoise -
+                   QE_SN[Constellation * 5 + CodeRate];
+               BERQuality = 100;
+
+               if (SignalToNoiseRel < -70)
+                       *pQuality = 0;
+               else if (SignalToNoiseRel < 30)
+                       *pQuality = ((SignalToNoiseRel + 70) *
+                                    BERQuality) / 100;
+               else
+                       *pQuality = BERQuality;
+       } while (0);
+       return 0;
+};
+
+static int GetDVBCQuality(struct drxk_state *state, s32 *pQuality)
+{
+       int status = 0;
+       *pQuality = 0;
+
+       dprintk(1, "\n");
+
+       do {
+               u32 SignalToNoise = 0;
+               u32 BERQuality = 100;
+               u32 SignalToNoiseRel = 0;
+
+               status = GetQAMSignalToNoise(state, &SignalToNoise);
+               if (status < 0)
+                       break;
+
+               switch (state->param.u.qam.modulation) {
+               case QAM_16:
+                       SignalToNoiseRel = SignalToNoise - 200;
+                       break;
+               case QAM_32:
+                       SignalToNoiseRel = SignalToNoise - 230;
+                       break;  /* Not in NorDig */
+               case QAM_64:
+                       SignalToNoiseRel = SignalToNoise - 260;
+                       break;
+               case QAM_128:
+                       SignalToNoiseRel = SignalToNoise - 290;
+                       break;
+               default:
+               case QAM_256:
+                       SignalToNoiseRel = SignalToNoise - 320;
+                       break;
+               }
+
+               if (SignalToNoiseRel < -70)
+                       *pQuality = 0;
+               else if (SignalToNoiseRel < 30)
+                       *pQuality = ((SignalToNoiseRel + 70) *
+                                    BERQuality) / 100;
+               else
+                       *pQuality = BERQuality;
+       } while (0);
+
+       return status;
+}
+
+static int GetQuality(struct drxk_state *state, s32 *pQuality)
+{
+       dprintk(1, "\n");
+
+       switch (state->m_OperationMode) {
+       case OM_DVBT:
+               return GetDVBTQuality(state, pQuality);
+       case OM_QAM_ITU_A:
+               return GetDVBCQuality(state, pQuality);
+       default:
+               break;
+       }
+
+       return 0;
+}
+#endif
+
+/* Free data ram in SIO HI */
+#define SIO_HI_RA_RAM_USR_BEGIN__A 0x420040
+#define SIO_HI_RA_RAM_USR_END__A   0x420060
+
+#define DRXK_HI_ATOMIC_BUF_START (SIO_HI_RA_RAM_USR_BEGIN__A)
+#define DRXK_HI_ATOMIC_BUF_END   (SIO_HI_RA_RAM_USR_BEGIN__A + 7)
+#define DRXK_HI_ATOMIC_READ      SIO_HI_RA_RAM_PAR_3_ACP_RW_READ
+#define DRXK_HI_ATOMIC_WRITE     SIO_HI_RA_RAM_PAR_3_ACP_RW_WRITE
+
+#define DRXDAP_FASI_ADDR2BLOCK(addr)  (((addr) >> 22) & 0x3F)
+#define DRXDAP_FASI_ADDR2BANK(addr)   (((addr) >> 16) & 0x3F)
+#define DRXDAP_FASI_ADDR2OFFSET(addr) ((addr) & 0x7FFF)
+
+static int ConfigureI2CBridge(struct drxk_state *state, bool bEnableBridge)
+{
+       int status = -EINVAL;
+
+       dprintk(1, "\n");
+
+       if (state->m_DrxkState == DRXK_UNINITIALIZED)
+               goto error;
+       if (state->m_DrxkState == DRXK_POWERED_DOWN)
+               goto error;
+
+       if (state->no_i2c_bridge)
+               return 0;
+
+       status = write16(state, SIO_HI_RA_RAM_PAR_1__A, SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY);
+       if (status < 0)
+               goto error;
+       if (bEnableBridge) {
+               status = write16(state, SIO_HI_RA_RAM_PAR_2__A, SIO_HI_RA_RAM_PAR_2_BRD_CFG_CLOSED);
+               if (status < 0)
+                       goto error;
+       } else {
+               status = write16(state, SIO_HI_RA_RAM_PAR_2__A, SIO_HI_RA_RAM_PAR_2_BRD_CFG_OPEN);
+               if (status < 0)
+                       goto error;
+       }
+
+       status = HI_Command(state, SIO_HI_RA_RAM_CMD_BRDCTRL, 0);
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int SetPreSaw(struct drxk_state *state,
+                    struct SCfgPreSaw *pPreSawCfg)
+{
+       int status = -EINVAL;
+
+       dprintk(1, "\n");
+
+       if ((pPreSawCfg == NULL)
+           || (pPreSawCfg->reference > IQM_AF_PDREF__M))
+               goto error;
+
+       status = write16(state, IQM_AF_PDREF__A, pPreSawCfg->reference);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int BLDirectCmd(struct drxk_state *state, u32 targetAddr,
+                      u16 romOffset, u16 nrOfElements, u32 timeOut)
+{
+       u16 blStatus = 0;
+       u16 offset = (u16) ((targetAddr >> 0) & 0x00FFFF);
+       u16 blockbank = (u16) ((targetAddr >> 16) & 0x000FFF);
+       int status;
+       unsigned long end;
+
+       dprintk(1, "\n");
+
+       mutex_lock(&state->mutex);
+       status = write16(state, SIO_BL_MODE__A, SIO_BL_MODE_DIRECT);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_BL_TGT_HDR__A, blockbank);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_BL_TGT_ADDR__A, offset);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_BL_SRC_ADDR__A, romOffset);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_BL_SRC_LEN__A, nrOfElements);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_BL_ENABLE__A, SIO_BL_ENABLE_ON);
+       if (status < 0)
+               goto error;
+
+       end = jiffies + msecs_to_jiffies(timeOut);
+       do {
+               status = read16(state, SIO_BL_STATUS__A, &blStatus);
+               if (status < 0)
+                       goto error;
+       } while ((blStatus == 0x1) && time_is_after_jiffies(end));
+       if (blStatus == 0x1) {
+               printk(KERN_ERR "drxk: SIO not ready\n");
+               status = -EINVAL;
+               goto error2;
+       }
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+error2:
+       mutex_unlock(&state->mutex);
+       return status;
+
+}
+
+static int ADCSyncMeasurement(struct drxk_state *state, u16 *count)
+{
+       u16 data = 0;
+       int status;
+
+       dprintk(1, "\n");
+
+       /* Start measurement */
+       status = write16(state, IQM_AF_COMM_EXEC__A, IQM_AF_COMM_EXEC_ACTIVE);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_AF_START_LOCK__A, 1);
+       if (status < 0)
+               goto error;
+
+       *count = 0;
+       status = read16(state, IQM_AF_PHASE0__A, &data);
+       if (status < 0)
+               goto error;
+       if (data == 127)
+               *count = *count + 1;
+       status = read16(state, IQM_AF_PHASE1__A, &data);
+       if (status < 0)
+               goto error;
+       if (data == 127)
+               *count = *count + 1;
+       status = read16(state, IQM_AF_PHASE2__A, &data);
+       if (status < 0)
+               goto error;
+       if (data == 127)
+               *count = *count + 1;
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int ADCSynchronization(struct drxk_state *state)
+{
+       u16 count = 0;
+       int status;
+
+       dprintk(1, "\n");
+
+       status = ADCSyncMeasurement(state, &count);
+       if (status < 0)
+               goto error;
+
+       if (count == 1) {
+               /* Try sampling on a diffrent edge */
+               u16 clkNeg = 0;
+
+               status = read16(state, IQM_AF_CLKNEG__A, &clkNeg);
+               if (status < 0)
+                       goto error;
+               if ((clkNeg | IQM_AF_CLKNEG_CLKNEGDATA__M) ==
+                       IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_POS) {
+                       clkNeg &= (~(IQM_AF_CLKNEG_CLKNEGDATA__M));
+                       clkNeg |=
+                               IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_NEG;
+               } else {
+                       clkNeg &= (~(IQM_AF_CLKNEG_CLKNEGDATA__M));
+                       clkNeg |=
+                               IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_POS;
+               }
+               status = write16(state, IQM_AF_CLKNEG__A, clkNeg);
+               if (status < 0)
+                       goto error;
+               status = ADCSyncMeasurement(state, &count);
+               if (status < 0)
+                       goto error;
+       }
+
+       if (count < 2)
+               status = -EINVAL;
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int SetFrequencyShifter(struct drxk_state *state,
+                              u16 intermediateFreqkHz,
+                              s32 tunerFreqOffset, bool isDTV)
+{
+       bool selectPosImage = false;
+       u32 rfFreqResidual = tunerFreqOffset;
+       u32 fmFrequencyShift = 0;
+       bool tunerMirror = !state->m_bMirrorFreqSpect;
+       u32 adcFreq;
+       bool adcFlip;
+       int status;
+       u32 ifFreqActual;
+       u32 samplingFrequency = (u32) (state->m_sysClockFreq / 3);
+       u32 frequencyShift;
+       bool imageToSelect;
+
+       dprintk(1, "\n");
+
+       /*
+          Program frequency shifter
+          No need to account for mirroring on RF
+        */
+       if (isDTV) {
+               if ((state->m_OperationMode == OM_QAM_ITU_A) ||
+                   (state->m_OperationMode == OM_QAM_ITU_C) ||
+                   (state->m_OperationMode == OM_DVBT))
+                       selectPosImage = true;
+               else
+                       selectPosImage = false;
+       }
+       if (tunerMirror)
+               /* tuner doesn't mirror */
+               ifFreqActual = intermediateFreqkHz +
+                   rfFreqResidual + fmFrequencyShift;
+       else
+               /* tuner mirrors */
+               ifFreqActual = intermediateFreqkHz -
+                   rfFreqResidual - fmFrequencyShift;
+       if (ifFreqActual > samplingFrequency / 2) {
+               /* adc mirrors */
+               adcFreq = samplingFrequency - ifFreqActual;
+               adcFlip = true;
+       } else {
+               /* adc doesn't mirror */
+               adcFreq = ifFreqActual;
+               adcFlip = false;
+       }
+
+       frequencyShift = adcFreq;
+       imageToSelect = state->m_rfmirror ^ tunerMirror ^
+           adcFlip ^ selectPosImage;
+       state->m_IqmFsRateOfs =
+           Frac28a((frequencyShift), samplingFrequency);
+
+       if (imageToSelect)
+               state->m_IqmFsRateOfs = ~state->m_IqmFsRateOfs + 1;
+
+       /* Program frequency shifter with tuner offset compensation */
+       /* frequencyShift += tunerFreqOffset; TODO */
+       status = write32(state, IQM_FS_RATE_OFS_LO__A,
+                        state->m_IqmFsRateOfs);
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int InitAGC(struct drxk_state *state, bool isDTV)
+{
+       u16 ingainTgt = 0;
+       u16 ingainTgtMin = 0;
+       u16 ingainTgtMax = 0;
+       u16 clpCyclen = 0;
+       u16 clpSumMin = 0;
+       u16 clpDirTo = 0;
+       u16 snsSumMin = 0;
+       u16 snsSumMax = 0;
+       u16 clpSumMax = 0;
+       u16 snsDirTo = 0;
+       u16 kiInnergainMin = 0;
+       u16 ifIaccuHiTgt = 0;
+       u16 ifIaccuHiTgtMin = 0;
+       u16 ifIaccuHiTgtMax = 0;
+       u16 data = 0;
+       u16 fastClpCtrlDelay = 0;
+       u16 clpCtrlMode = 0;
+       int status = 0;
+
+       dprintk(1, "\n");
+
+       /* Common settings */
+       snsSumMax = 1023;
+       ifIaccuHiTgtMin = 2047;
+       clpCyclen = 500;
+       clpSumMax = 1023;
+
+       /* AGCInit() not available for DVBT; init done in microcode */
+       if (!IsQAM(state)) {
+               printk(KERN_ERR "drxk: %s: mode %d is not DVB-C\n", __func__, state->m_OperationMode);
+               return -EINVAL;
+       }
+
+       /* FIXME: Analog TV AGC require different settings */
+
+       /* Standard specific settings */
+       clpSumMin = 8;
+       clpDirTo = (u16) -9;
+       clpCtrlMode = 0;
+       snsSumMin = 8;
+       snsDirTo = (u16) -9;
+       kiInnergainMin = (u16) -1030;
+       ifIaccuHiTgtMax = 0x2380;
+       ifIaccuHiTgt = 0x2380;
+       ingainTgtMin = 0x0511;
+       ingainTgt = 0x0511;
+       ingainTgtMax = 5119;
+       fastClpCtrlDelay = state->m_qamIfAgcCfg.FastClipCtrlDelay;
+
+       status = write16(state, SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__A, fastClpCtrlDelay);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_AGC_CLP_CTRL_MODE__A, clpCtrlMode);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_INGAIN_TGT__A, ingainTgt);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MIN__A, ingainTgtMin);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MAX__A, ingainTgtMax);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MIN__A, ifIaccuHiTgtMin);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, ifIaccuHiTgtMax);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_IF_IACCU_HI__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_IF_IACCU_LO__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_RF_IACCU_HI__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_RF_IACCU_LO__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_CLP_SUM_MAX__A, clpSumMax);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_SNS_SUM_MAX__A, snsSumMax);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_AGC_KI_INNERGAIN_MIN__A, kiInnergainMin);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT__A, ifIaccuHiTgt);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_CLP_CYCLEN__A, clpCyclen);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_AGC_RF_SNS_DEV_MAX__A, 1023);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_RF_SNS_DEV_MIN__A, (u16) -1023);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_FAST_SNS_CTRL_DELAY__A, 50);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_AGC_KI_MAXMINGAIN_TH__A, 20);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_CLP_SUM_MIN__A, clpSumMin);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_SNS_SUM_MIN__A, snsSumMin);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_CLP_DIR_TO__A, clpDirTo);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_SNS_DIR_TO__A, snsDirTo);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_KI_MINGAIN__A, 0x7fff);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_KI_MAXGAIN__A, 0x0);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_KI_MIN__A, 0x0117);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_KI_MAX__A, 0x0657);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_CLP_SUM__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_CLP_CYCCNT__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_CLP_DIR_WD__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_CLP_DIR_STP__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_SNS_SUM__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_SNS_CYCCNT__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_SNS_DIR_WD__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_SNS_DIR_STP__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_SNS_CYCLEN__A, 500);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_KI_CYCLEN__A, 500);
+       if (status < 0)
+               goto error;
+
+       /* Initialize inner-loop KI gain factors */
+       status = read16(state, SCU_RAM_AGC_KI__A, &data);
+       if (status < 0)
+               goto error;
+
+       data = 0x0657;
+       data &= ~SCU_RAM_AGC_KI_RF__M;
+       data |= (DRXK_KI_RAGC_QAM << SCU_RAM_AGC_KI_RF__B);
+       data &= ~SCU_RAM_AGC_KI_IF__M;
+       data |= (DRXK_KI_IAGC_QAM << SCU_RAM_AGC_KI_IF__B);
+
+       status = write16(state, SCU_RAM_AGC_KI__A, data);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int DVBTQAMGetAccPktErr(struct drxk_state *state, u16 *packetErr)
+{
+       int status;
+
+       dprintk(1, "\n");
+       if (packetErr == NULL)
+               status = write16(state, SCU_RAM_FEC_ACCUM_PKT_FAILURES__A, 0);
+       else
+               status = read16(state, SCU_RAM_FEC_ACCUM_PKT_FAILURES__A, packetErr);
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int DVBTScCommand(struct drxk_state *state,
+                        u16 cmd, u16 subcmd,
+                        u16 param0, u16 param1, u16 param2,
+                        u16 param3, u16 param4)
+{
+       u16 curCmd = 0;
+       u16 errCode = 0;
+       u16 retryCnt = 0;
+       u16 scExec = 0;
+       int status;
+
+       dprintk(1, "\n");
+       status = read16(state, OFDM_SC_COMM_EXEC__A, &scExec);
+       if (scExec != 1) {
+               /* SC is not running */
+               status = -EINVAL;
+       }
+       if (status < 0)
+               goto error;
+
+       /* Wait until sc is ready to receive command */
+       retryCnt = 0;
+       do {
+               msleep(1);
+               status = read16(state, OFDM_SC_RA_RAM_CMD__A, &curCmd);
+               retryCnt++;
+       } while ((curCmd != 0) && (retryCnt < DRXK_MAX_RETRIES));
+       if (retryCnt >= DRXK_MAX_RETRIES && (status < 0))
+               goto error;
+
+       /* Write sub-command */
+       switch (cmd) {
+               /* All commands using sub-cmd */
+       case OFDM_SC_RA_RAM_CMD_PROC_START:
+       case OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM:
+       case OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM:
+               status = write16(state, OFDM_SC_RA_RAM_CMD_ADDR__A, subcmd);
+               if (status < 0)
+                       goto error;
+               break;
+       default:
+               /* Do nothing */
+               break;
+       }
+
+       /* Write needed parameters and the command */
+       switch (cmd) {
+               /* All commands using 5 parameters */
+               /* All commands using 4 parameters */
+               /* All commands using 3 parameters */
+               /* All commands using 2 parameters */
+       case OFDM_SC_RA_RAM_CMD_PROC_START:
+       case OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM:
+       case OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM:
+               status = write16(state, OFDM_SC_RA_RAM_PARAM1__A, param1);
+               /* All commands using 1 parameters */
+       case OFDM_SC_RA_RAM_CMD_SET_ECHO_TIMING:
+       case OFDM_SC_RA_RAM_CMD_USER_IO:
+               status = write16(state, OFDM_SC_RA_RAM_PARAM0__A, param0);
+               /* All commands using 0 parameters */
+       case OFDM_SC_RA_RAM_CMD_GET_OP_PARAM:
+       case OFDM_SC_RA_RAM_CMD_NULL:
+               /* Write command */
+               status = write16(state, OFDM_SC_RA_RAM_CMD__A, cmd);
+               break;
+       default:
+               /* Unknown command */
+               status = -EINVAL;
+       }
+       if (status < 0)
+               goto error;
+
+       /* Wait until sc is ready processing command */
+       retryCnt = 0;
+       do {
+               msleep(1);
+               status = read16(state, OFDM_SC_RA_RAM_CMD__A, &curCmd);
+               retryCnt++;
+       } while ((curCmd != 0) && (retryCnt < DRXK_MAX_RETRIES));
+       if (retryCnt >= DRXK_MAX_RETRIES && (status < 0))
+               goto error;
+
+       /* Check for illegal cmd */
+       status = read16(state, OFDM_SC_RA_RAM_CMD_ADDR__A, &errCode);
+       if (errCode == 0xFFFF) {
+               /* illegal command */
+               status = -EINVAL;
+       }
+       if (status < 0)
+               goto error;
+
+       /* Retreive results parameters from SC */
+       switch (cmd) {
+               /* All commands yielding 5 results */
+               /* All commands yielding 4 results */
+               /* All commands yielding 3 results */
+               /* All commands yielding 2 results */
+               /* All commands yielding 1 result */
+       case OFDM_SC_RA_RAM_CMD_USER_IO:
+       case OFDM_SC_RA_RAM_CMD_GET_OP_PARAM:
+               status = read16(state, OFDM_SC_RA_RAM_PARAM0__A, &(param0));
+               /* All commands yielding 0 results */
+       case OFDM_SC_RA_RAM_CMD_SET_ECHO_TIMING:
+       case OFDM_SC_RA_RAM_CMD_SET_TIMER:
+       case OFDM_SC_RA_RAM_CMD_PROC_START:
+       case OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM:
+       case OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM:
+       case OFDM_SC_RA_RAM_CMD_NULL:
+               break;
+       default:
+               /* Unknown command */
+               status = -EINVAL;
+               break;
+       }                       /* switch (cmd->cmd) */
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int PowerUpDVBT(struct drxk_state *state)
+{
+       enum DRXPowerMode powerMode = DRX_POWER_UP;
+       int status;
+
+       dprintk(1, "\n");
+       status = CtrlPowerMode(state, &powerMode);
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int DVBTCtrlSetIncEnable(struct drxk_state *state, bool *enabled)
+{
+       int status;
+
+       dprintk(1, "\n");
+       if (*enabled == true)
+               status = write16(state, IQM_CF_BYPASSDET__A, 0);
+       else
+               status = write16(state, IQM_CF_BYPASSDET__A, 1);
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+#define DEFAULT_FR_THRES_8K     4000
+static int DVBTCtrlSetFrEnable(struct drxk_state *state, bool *enabled)
+{
+
+       int status;
+
+       dprintk(1, "\n");
+       if (*enabled == true) {
+               /* write mask to 1 */
+               status = write16(state, OFDM_SC_RA_RAM_FR_THRES_8K__A,
+                                  DEFAULT_FR_THRES_8K);
+       } else {
+               /* write mask to 0 */
+               status = write16(state, OFDM_SC_RA_RAM_FR_THRES_8K__A, 0);
+       }
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+static int DVBTCtrlSetEchoThreshold(struct drxk_state *state,
+                                   struct DRXKCfgDvbtEchoThres_t *echoThres)
+{
+       u16 data = 0;
+       int status;
+
+       dprintk(1, "\n");
+       status = read16(state, OFDM_SC_RA_RAM_ECHO_THRES__A, &data);
+       if (status < 0)
+               goto error;
+
+       switch (echoThres->fftMode) {
+       case DRX_FFTMODE_2K:
+               data &= ~OFDM_SC_RA_RAM_ECHO_THRES_2K__M;
+               data |= ((echoThres->threshold <<
+                       OFDM_SC_RA_RAM_ECHO_THRES_2K__B)
+                       & (OFDM_SC_RA_RAM_ECHO_THRES_2K__M));
+               break;
+       case DRX_FFTMODE_8K:
+               data &= ~OFDM_SC_RA_RAM_ECHO_THRES_8K__M;
+               data |= ((echoThres->threshold <<
+                       OFDM_SC_RA_RAM_ECHO_THRES_8K__B)
+                       & (OFDM_SC_RA_RAM_ECHO_THRES_8K__M));
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       status = write16(state, OFDM_SC_RA_RAM_ECHO_THRES__A, data);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int DVBTCtrlSetSqiSpeed(struct drxk_state *state,
+                              enum DRXKCfgDvbtSqiSpeed *speed)
+{
+       int status = -EINVAL;
+
+       dprintk(1, "\n");
+
+       switch (*speed) {
+       case DRXK_DVBT_SQI_SPEED_FAST:
+       case DRXK_DVBT_SQI_SPEED_MEDIUM:
+       case DRXK_DVBT_SQI_SPEED_SLOW:
+               break;
+       default:
+               goto error;
+       }
+       status = write16(state, SCU_RAM_FEC_PRE_RS_BER_FILTER_SH__A,
+                          (u16) *speed);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+/*============================================================================*/
+
+/**
+* \brief Activate DVBT specific presets
+* \param demod instance of demodulator.
+* \return DRXStatus_t.
+*
+* Called in DVBTSetStandard
+*
+*/
+static int DVBTActivatePresets(struct drxk_state *state)
+{
+       int status;
+       bool setincenable = false;
+       bool setfrenable = true;
+
+       struct DRXKCfgDvbtEchoThres_t echoThres2k = { 0, DRX_FFTMODE_2K };
+       struct DRXKCfgDvbtEchoThres_t echoThres8k = { 0, DRX_FFTMODE_8K };
+
+       dprintk(1, "\n");
+       status = DVBTCtrlSetIncEnable(state, &setincenable);
+       if (status < 0)
+               goto error;
+       status = DVBTCtrlSetFrEnable(state, &setfrenable);
+       if (status < 0)
+               goto error;
+       status = DVBTCtrlSetEchoThreshold(state, &echoThres2k);
+       if (status < 0)
+               goto error;
+       status = DVBTCtrlSetEchoThreshold(state, &echoThres8k);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MAX__A, state->m_dvbtIfAgcCfg.IngainTgtMax);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+/*============================================================================*/
+
+/**
+* \brief Initialize channelswitch-independent settings for DVBT.
+* \param demod instance of demodulator.
+* \return DRXStatus_t.
+*
+* For ROM code channel filter taps are loaded from the bootloader. For microcode
+* the DVB-T taps from the drxk_filters.h are used.
+*/
+static int SetDVBTStandard(struct drxk_state *state,
+                          enum OperationMode oMode)
+{
+       u16 cmdResult = 0;
+       u16 data = 0;
+       int status;
+
+       dprintk(1, "\n");
+
+       PowerUpDVBT(state);
+       /* added antenna switch */
+       SwitchAntennaToDVBT(state);
+       /* send OFDM reset command */
+       status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_RESET, 0, NULL, 1, &cmdResult);
+       if (status < 0)
+               goto error;
+
+       /* send OFDM setenv command */
+       status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV, 0, NULL, 1, &cmdResult);
+       if (status < 0)
+               goto error;
+
+       /* reset datapath for OFDM, processors first */
+       status = write16(state, OFDM_SC_COMM_EXEC__A, OFDM_SC_COMM_EXEC_STOP);
+       if (status < 0)
+               goto error;
+       status = write16(state, OFDM_LC_COMM_EXEC__A, OFDM_LC_COMM_EXEC_STOP);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_COMM_EXEC__A, IQM_COMM_EXEC_B_STOP);
+       if (status < 0)
+               goto error;
+
+       /* IQM setup */
+       /* synchronize on ofdstate->m_festart */
+       status = write16(state, IQM_AF_UPD_SEL__A, 1);
+       if (status < 0)
+               goto error;
+       /* window size for clipping ADC detection */
+       status = write16(state, IQM_AF_CLP_LEN__A, 0);
+       if (status < 0)
+               goto error;
+       /* window size for for sense pre-SAW detection */
+       status = write16(state, IQM_AF_SNS_LEN__A, 0);
+       if (status < 0)
+               goto error;
+       /* sense threshold for sense pre-SAW detection */
+       status = write16(state, IQM_AF_AMUX__A, IQM_AF_AMUX_SIGNAL2ADC);
+       if (status < 0)
+               goto error;
+       status = SetIqmAf(state, true);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, IQM_AF_AGC_RF__A, 0);
+       if (status < 0)
+               goto error;
+
+       /* Impulse noise cruncher setup */
+       status = write16(state, IQM_AF_INC_LCT__A, 0);  /* crunch in IQM_CF */
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_DET_LCT__A, 0);  /* detect in IQM_CF */
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_WND_LEN__A, 3);  /* peak detector window length */
+       if (status < 0)
+               goto error;
+
+       status = write16(state, IQM_RC_STRETCH__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_OUT_ENA__A, 0x4);        /* enable output 2 */
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_DS_ENA__A, 0x4); /* decimate output 2 */
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_SCALE__A, 1600);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_SCALE_SH__A, 0);
+       if (status < 0)
+               goto error;
+
+       /* virtual clipping threshold for clipping ADC detection */
+       status = write16(state, IQM_AF_CLP_TH__A, 448);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_DATATH__A, 495); /* crunching threshold */
+       if (status < 0)
+               goto error;
+
+       status = BLChainCmd(state, DRXK_BL_ROM_OFFSET_TAPS_DVBT, DRXK_BLCC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, IQM_CF_PKDTH__A, 2);    /* peak detector threshold */
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_POW_MEAS_LEN__A, 2);
+       if (status < 0)
+               goto error;
+       /* enable power measurement interrupt */
+       status = write16(state, IQM_CF_COMM_INT_MSK__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_COMM_EXEC__A, IQM_COMM_EXEC_B_ACTIVE);
+       if (status < 0)
+               goto error;
+
+       /* IQM will not be reset from here, sync ADC and update/init AGC */
+       status = ADCSynchronization(state);
+       if (status < 0)
+               goto error;
+       status = SetPreSaw(state, &state->m_dvbtPreSawCfg);
+       if (status < 0)
+               goto error;
+
+       /* Halt SCU to enable safe non-atomic accesses */
+       status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_HOLD);
+       if (status < 0)
+               goto error;
+
+       status = SetAgcRf(state, &state->m_dvbtRfAgcCfg, true);
+       if (status < 0)
+               goto error;
+       status = SetAgcIf(state, &state->m_dvbtIfAgcCfg, true);
+       if (status < 0)
+               goto error;
+
+       /* Set Noise Estimation notch width and enable DC fix */
+       status = read16(state, OFDM_SC_RA_RAM_CONFIG__A, &data);
+       if (status < 0)
+               goto error;
+       data |= OFDM_SC_RA_RAM_CONFIG_NE_FIX_ENABLE__M;
+       status = write16(state, OFDM_SC_RA_RAM_CONFIG__A, data);
+       if (status < 0)
+               goto error;
+
+       /* Activate SCU to enable SCU commands */
+       status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE);
+       if (status < 0)
+               goto error;
+
+       if (!state->m_DRXK_A3_ROM_CODE) {
+               /* AGCInit() is not done for DVBT, so set agcFastClipCtrlDelay  */
+               status = write16(state, SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__A, state->m_dvbtIfAgcCfg.FastClipCtrlDelay);
+               if (status < 0)
+                       goto error;
+       }
+
+       /* OFDM_SC setup */
+#ifdef COMPILE_FOR_NONRT
+       status = write16(state, OFDM_SC_RA_RAM_BE_OPT_DELAY__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, OFDM_SC_RA_RAM_BE_OPT_INIT_DELAY__A, 2);
+       if (status < 0)
+               goto error;
+#endif
+
+       /* FEC setup */
+       status = write16(state, FEC_DI_INPUT_CTL__A, 1);        /* OFDM input */
+       if (status < 0)
+               goto error;
+
+
+#ifdef COMPILE_FOR_NONRT
+       status = write16(state, FEC_RS_MEASUREMENT_PERIOD__A, 0x400);
+       if (status < 0)
+               goto error;
+#else
+       status = write16(state, FEC_RS_MEASUREMENT_PERIOD__A, 0x1000);
+       if (status < 0)
+               goto error;
+#endif
+       status = write16(state, FEC_RS_MEASUREMENT_PRESCALE__A, 0x0001);
+       if (status < 0)
+               goto error;
+
+       /* Setup MPEG bus */
+       status = MPEGTSDtoSetup(state, OM_DVBT);
+       if (status < 0)
+               goto error;
+       /* Set DVBT Presets */
+       status = DVBTActivatePresets(state);
+       if (status < 0)
+               goto error;
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+/*============================================================================*/
+/**
+* \brief Start dvbt demodulating for channel.
+* \param demod instance of demodulator.
+* \return DRXStatus_t.
+*/
+static int DVBTStart(struct drxk_state *state)
+{
+       u16 param1;
+       int status;
+       /* DRXKOfdmScCmd_t scCmd; */
+
+       dprintk(1, "\n");
+       /* Start correct processes to get in lock */
+       /* DRXK: OFDM_SC_RA_RAM_PROC_LOCKTRACK is no longer in mapfile! */
+       param1 = OFDM_SC_RA_RAM_LOCKTRACK_MIN;
+       status = DVBTScCommand(state, OFDM_SC_RA_RAM_CMD_PROC_START, 0, OFDM_SC_RA_RAM_SW_EVENT_RUN_NMASK__M, param1, 0, 0, 0);
+       if (status < 0)
+               goto error;
+       /* Start FEC OC */
+       status = MPEGTSStart(state);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_COMM_EXEC__A, FEC_COMM_EXEC_ACTIVE);
+       if (status < 0)
+               goto error;
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+
+/*============================================================================*/
+
+/**
+* \brief Set up dvbt demodulator for channel.
+* \param demod instance of demodulator.
+* \return DRXStatus_t.
+* // original DVBTSetChannel()
+*/
+static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
+                  s32 tunerFreqOffset)
+{
+       u16 cmdResult = 0;
+       u16 transmissionParams = 0;
+       u16 operationMode = 0;
+       u32 iqmRcRateOfs = 0;
+       u32 bandwidth = 0;
+       u16 param1;
+       int status;
+
+       dprintk(1, "IF =%d, TFO = %d\n", IntermediateFreqkHz, tunerFreqOffset);
+
+       status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_STOP, 0, NULL, 1, &cmdResult);
+       if (status < 0)
+               goto error;
+
+       /* Halt SCU to enable safe non-atomic accesses */
+       status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_HOLD);
+       if (status < 0)
+               goto error;
+
+       /* Stop processors */
+       status = write16(state, OFDM_SC_COMM_EXEC__A, OFDM_SC_COMM_EXEC_STOP);
+       if (status < 0)
+               goto error;
+       status = write16(state, OFDM_LC_COMM_EXEC__A, OFDM_LC_COMM_EXEC_STOP);
+       if (status < 0)
+               goto error;
+
+       /* Mandatory fix, always stop CP, required to set spl offset back to
+               hardware default (is set to 0 by ucode during pilot detection */
+       status = write16(state, OFDM_CP_COMM_EXEC__A, OFDM_CP_COMM_EXEC_STOP);
+       if (status < 0)
+               goto error;
+
+       /*== Write channel settings to device =====================================*/
+
+       /* mode */
+       switch (state->param.u.ofdm.transmission_mode) {
+       case TRANSMISSION_MODE_AUTO:
+       default:
+               operationMode |= OFDM_SC_RA_RAM_OP_AUTO_MODE__M;
+               /* fall through , try first guess DRX_FFTMODE_8K */
+       case TRANSMISSION_MODE_8K:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_MODE_8K;
+               break;
+       case TRANSMISSION_MODE_2K:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_MODE_2K;
+               break;
+       }
+
+       /* guard */
+       switch (state->param.u.ofdm.guard_interval) {
+       default:
+       case GUARD_INTERVAL_AUTO:
+               operationMode |= OFDM_SC_RA_RAM_OP_AUTO_GUARD__M;
+               /* fall through , try first guess DRX_GUARD_1DIV4 */
+       case GUARD_INTERVAL_1_4:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_4;
+               break;
+       case GUARD_INTERVAL_1_32:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_32;
+               break;
+       case GUARD_INTERVAL_1_16:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_16;
+               break;
+       case GUARD_INTERVAL_1_8:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_8;
+               break;
+       }
+
+       /* hierarchy */
+       switch (state->param.u.ofdm.hierarchy_information) {
+       case HIERARCHY_AUTO:
+       case HIERARCHY_NONE:
+       default:
+               operationMode |= OFDM_SC_RA_RAM_OP_AUTO_HIER__M;
+               /* fall through , try first guess SC_RA_RAM_OP_PARAM_HIER_NO */
+               /* transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_NO; */
+               /* break; */
+       case HIERARCHY_1:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A1;
+               break;
+       case HIERARCHY_2:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A2;
+               break;
+       case HIERARCHY_4:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A4;
+               break;
+       }
+
+
+       /* constellation */
+       switch (state->param.u.ofdm.constellation) {
+       case QAM_AUTO:
+       default:
+               operationMode |= OFDM_SC_RA_RAM_OP_AUTO_CONST__M;
+               /* fall through , try first guess DRX_CONSTELLATION_QAM64 */
+       case QAM_64:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM64;
+               break;
+       case QPSK:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QPSK;
+               break;
+       case QAM_16:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM16;
+               break;
+       }
+#if 0
+       /* No hierachical channels support in BDA */
+       /* Priority (only for hierarchical channels) */
+       switch (channel->priority) {
+       case DRX_PRIORITY_LOW:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_LO;
+               WR16(devAddr, OFDM_EC_SB_PRIOR__A,
+                       OFDM_EC_SB_PRIOR_LO);
+               break;
+       case DRX_PRIORITY_HIGH:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_HI;
+               WR16(devAddr, OFDM_EC_SB_PRIOR__A,
+                       OFDM_EC_SB_PRIOR_HI));
+               break;
+       case DRX_PRIORITY_UNKNOWN:      /* fall through */
+       default:
+               status = -EINVAL;
+               goto error;
+       }
+#else
+       /* Set Priorty high */
+       transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_HI;
+       status = write16(state, OFDM_EC_SB_PRIOR__A, OFDM_EC_SB_PRIOR_HI);
+       if (status < 0)
+               goto error;
+#endif
+
+       /* coderate */
+       switch (state->param.u.ofdm.code_rate_HP) {
+       case FEC_AUTO:
+       default:
+               operationMode |= OFDM_SC_RA_RAM_OP_AUTO_RATE__M;
+               /* fall through , try first guess DRX_CODERATE_2DIV3 */
+       case FEC_2_3:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_2_3;
+               break;
+       case FEC_1_2:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_1_2;
+               break;
+       case FEC_3_4:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_3_4;
+               break;
+       case FEC_5_6:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_5_6;
+               break;
+       case FEC_7_8:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_7_8;
+               break;
+       }
+
+       /* SAW filter selection: normaly not necesarry, but if wanted
+               the application can select a SAW filter via the driver by using UIOs */
+       /* First determine real bandwidth (Hz) */
+       /* Also set delay for impulse noise cruncher */
+       /* Also set parameters for EC_OC fix, note EC_OC_REG_TMD_HIL_MAR is changed
+               by SC for fix for some 8K,1/8 guard but is restored by InitEC and ResetEC
+               functions */
+       switch (state->param.u.ofdm.bandwidth) {
+       case BANDWIDTH_AUTO:
+       case BANDWIDTH_8_MHZ:
+               bandwidth = DRXK_BANDWIDTH_8MHZ_IN_HZ;
+               status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 3052);
+               if (status < 0)
+                       goto error;
+               /* cochannel protection for PAL 8 MHz */
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A, 7);
+               if (status < 0)
+                       goto error;
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A, 7);
+               if (status < 0)
+                       goto error;
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A, 7);
+               if (status < 0)
+                       goto error;
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A, 1);
+               if (status < 0)
+                       goto error;
+               break;
+       case BANDWIDTH_7_MHZ:
+               bandwidth = DRXK_BANDWIDTH_7MHZ_IN_HZ;
+               status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 3491);
+               if (status < 0)
+                       goto error;
+               /* cochannel protection for PAL 7 MHz */
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A, 8);
+               if (status < 0)
+                       goto error;
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A, 8);
+               if (status < 0)
+                       goto error;
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A, 4);
+               if (status < 0)
+                       goto error;
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A, 1);
+               if (status < 0)
+                       goto error;
+               break;
+       case BANDWIDTH_6_MHZ:
+               bandwidth = DRXK_BANDWIDTH_6MHZ_IN_HZ;
+               status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 4073);
+               if (status < 0)
+                       goto error;
+               /* cochannel protection for NTSC 6 MHz */
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A, 19);
+               if (status < 0)
+                       goto error;
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A, 19);
+               if (status < 0)
+                       goto error;
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A, 14);
+               if (status < 0)
+                       goto error;
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A, 1);
+               if (status < 0)
+                       goto error;
+               break;
+       default:
+               status = -EINVAL;
+               goto error;
+       }
+
+       if (iqmRcRateOfs == 0) {
+               /* Now compute IQM_RC_RATE_OFS
+                       (((SysFreq/BandWidth)/2)/2) -1) * 2^23)
+                       =>
+                       ((SysFreq / BandWidth) * (2^21)) - (2^23)
+                       */
+               /* (SysFreq / BandWidth) * (2^28)  */
+               /* assert (MAX(sysClk)/MIN(bandwidth) < 16)
+                       => assert(MAX(sysClk) < 16*MIN(bandwidth))
+                       => assert(109714272 > 48000000) = true so Frac 28 can be used  */
+               iqmRcRateOfs = Frac28a((u32)
+                                       ((state->m_sysClockFreq *
+                                               1000) / 3), bandwidth);
+               /* (SysFreq / BandWidth) * (2^21), rounding before truncating  */
+               if ((iqmRcRateOfs & 0x7fL) >= 0x40)
+                       iqmRcRateOfs += 0x80L;
+               iqmRcRateOfs = iqmRcRateOfs >> 7;
+               /* ((SysFreq / BandWidth) * (2^21)) - (2^23)  */
+               iqmRcRateOfs = iqmRcRateOfs - (1 << 23);
+       }
+
+       iqmRcRateOfs &=
+               ((((u32) IQM_RC_RATE_OFS_HI__M) <<
+               IQM_RC_RATE_OFS_LO__W) | IQM_RC_RATE_OFS_LO__M);
+       status = write32(state, IQM_RC_RATE_OFS_LO__A, iqmRcRateOfs);
+       if (status < 0)
+               goto error;
+
+       /* Bandwidth setting done */
+
+#if 0
+       status = DVBTSetFrequencyShift(demod, channel, tunerOffset);
+       if (status < 0)
+               goto error;
+#endif
+       status = SetFrequencyShifter(state, IntermediateFreqkHz, tunerFreqOffset, true);
+       if (status < 0)
+               goto error;
+
+       /*== Start SC, write channel settings to SC ===============================*/
+
+       /* Activate SCU to enable SCU commands */
+       status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE);
+       if (status < 0)
+               goto error;
+
+       /* Enable SC after setting all other parameters */
+       status = write16(state, OFDM_SC_COMM_STATE__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, OFDM_SC_COMM_EXEC__A, 1);
+       if (status < 0)
+               goto error;
+
+
+       status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_START, 0, NULL, 1, &cmdResult);
+       if (status < 0)
+               goto error;
+
+       /* Write SC parameter registers, set all AUTO flags in operation mode */
+       param1 = (OFDM_SC_RA_RAM_OP_AUTO_MODE__M |
+                       OFDM_SC_RA_RAM_OP_AUTO_GUARD__M |
+                       OFDM_SC_RA_RAM_OP_AUTO_CONST__M |
+                       OFDM_SC_RA_RAM_OP_AUTO_HIER__M |
+                       OFDM_SC_RA_RAM_OP_AUTO_RATE__M);
+       status = DVBTScCommand(state, OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM,
+                               0, transmissionParams, param1, 0, 0, 0);
+       if (status < 0)
+               goto error;
+
+       if (!state->m_DRXK_A3_ROM_CODE)
+               status = DVBTCtrlSetSqiSpeed(state, &state->m_sqiSpeed);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+
+/*============================================================================*/
+
+/**
+* \brief Retreive lock status .
+* \param demod    Pointer to demodulator instance.
+* \param lockStat Pointer to lock status structure.
+* \return DRXStatus_t.
+*
+*/
+static int GetDVBTLockStatus(struct drxk_state *state, u32 *pLockStatus)
+{
+       int status;
+       const u16 mpeg_lock_mask = (OFDM_SC_RA_RAM_LOCK_MPEG__M |
+                                   OFDM_SC_RA_RAM_LOCK_FEC__M);
+       const u16 fec_lock_mask = (OFDM_SC_RA_RAM_LOCK_FEC__M);
+       const u16 demod_lock_mask = OFDM_SC_RA_RAM_LOCK_DEMOD__M;
+
+       u16 ScRaRamLock = 0;
+       u16 ScCommExec = 0;
+
+       dprintk(1, "\n");
+
+       *pLockStatus = NOT_LOCKED;
+       /* driver 0.9.0 */
+       /* Check if SC is running */
+       status = read16(state, OFDM_SC_COMM_EXEC__A, &ScCommExec);
+       if (status < 0)
+               goto end;
+       if (ScCommExec == OFDM_SC_COMM_EXEC_STOP)
+               goto end;
+
+       status = read16(state, OFDM_SC_RA_RAM_LOCK__A, &ScRaRamLock);
+       if (status < 0)
+               goto end;
+
+       if ((ScRaRamLock & mpeg_lock_mask) == mpeg_lock_mask)
+               *pLockStatus = MPEG_LOCK;
+       else if ((ScRaRamLock & fec_lock_mask) == fec_lock_mask)
+               *pLockStatus = FEC_LOCK;
+       else if ((ScRaRamLock & demod_lock_mask) == demod_lock_mask)
+               *pLockStatus = DEMOD_LOCK;
+       else if (ScRaRamLock & OFDM_SC_RA_RAM_LOCK_NODVBT__M)
+               *pLockStatus = NEVER_LOCK;
+end:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+static int PowerUpQAM(struct drxk_state *state)
+{
+       enum DRXPowerMode powerMode = DRXK_POWER_DOWN_OFDM;
+       int status;
+
+       dprintk(1, "\n");
+       status = CtrlPowerMode(state, &powerMode);
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+
+/** Power Down QAM */
+static int PowerDownQAM(struct drxk_state *state)
+{
+       u16 data = 0;
+       u16 cmdResult;
+       int status = 0;
+
+       dprintk(1, "\n");
+       status = read16(state, SCU_COMM_EXEC__A, &data);
+       if (status < 0)
+               goto error;
+       if (data == SCU_COMM_EXEC_ACTIVE) {
+               /*
+                       STOP demodulator
+                       QAM and HW blocks
+                       */
+               /* stop all comstate->m_exec */
+               status = write16(state, QAM_COMM_EXEC__A, QAM_COMM_EXEC_STOP);
+               if (status < 0)
+                       goto error;
+               status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_STOP, 0, NULL, 1, &cmdResult);
+               if (status < 0)
+                       goto error;
+       }
+       /* powerdown AFE                   */
+       status = SetIqmAf(state, false);
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+/*============================================================================*/
+
+/**
+* \brief Setup of the QAM Measurement intervals for signal quality
+* \param demod instance of demod.
+* \param constellation current constellation.
+* \return DRXStatus_t.
+*
+*  NOTE:
+*  Take into account that for certain settings the errorcounters can overflow.
+*  The implementation does not check this.
+*
+*/
+static int SetQAMMeasurement(struct drxk_state *state,
+                            enum EDrxkConstellation constellation,
+                            u32 symbolRate)
+{
+       u32 fecBitsDesired = 0; /* BER accounting period */
+       u32 fecRsPeriodTotal = 0;       /* Total period */
+       u16 fecRsPrescale = 0;  /* ReedSolomon Measurement Prescale */
+       u16 fecRsPeriod = 0;    /* Value for corresponding I2C register */
+       int status = 0;
+
+       dprintk(1, "\n");
+
+       fecRsPrescale = 1;
+       /* fecBitsDesired = symbolRate [kHz] *
+               FrameLenght [ms] *
+               (constellation + 1) *
+               SyncLoss (== 1) *
+               ViterbiLoss (==1)
+               */
+       switch (constellation) {
+       case DRX_CONSTELLATION_QAM16:
+               fecBitsDesired = 4 * symbolRate;
+               break;
+       case DRX_CONSTELLATION_QAM32:
+               fecBitsDesired = 5 * symbolRate;
+               break;
+       case DRX_CONSTELLATION_QAM64:
+               fecBitsDesired = 6 * symbolRate;
+               break;
+       case DRX_CONSTELLATION_QAM128:
+               fecBitsDesired = 7 * symbolRate;
+               break;
+       case DRX_CONSTELLATION_QAM256:
+               fecBitsDesired = 8 * symbolRate;
+               break;
+       default:
+               status = -EINVAL;
+       }
+       if (status < 0)
+               goto error;
+
+       fecBitsDesired /= 1000; /* symbolRate [Hz] -> symbolRate [kHz]  */
+       fecBitsDesired *= 500;  /* meas. period [ms] */
+
+       /* Annex A/C: bits/RsPeriod = 204 * 8 = 1632 */
+       /* fecRsPeriodTotal = fecBitsDesired / 1632 */
+       fecRsPeriodTotal = (fecBitsDesired / 1632UL) + 1;       /* roughly ceil */
+
+       /* fecRsPeriodTotal =  fecRsPrescale * fecRsPeriod  */
+       fecRsPrescale = 1 + (u16) (fecRsPeriodTotal >> 16);
+       if (fecRsPrescale == 0) {
+               /* Divide by zero (though impossible) */
+               status = -EINVAL;
+               if (status < 0)
+                       goto error;
+       }
+       fecRsPeriod =
+               ((u16) fecRsPeriodTotal +
+               (fecRsPrescale >> 1)) / fecRsPrescale;
+
+       /* write corresponding registers */
+       status = write16(state, FEC_RS_MEASUREMENT_PERIOD__A, fecRsPeriod);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_RS_MEASUREMENT_PRESCALE__A, fecRsPrescale);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_SNC_FAIL_PERIOD__A, fecRsPeriod);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int SetQAM16(struct drxk_state *state)
+{
+       int status = 0;
+
+       dprintk(1, "\n");
+       /* QAM Equalizer Setup */
+       /* Equalizer */
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD0__A, 13517);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD1__A, 13517);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD2__A, 13517);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD3__A, 13517);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD4__A, 13517);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD5__A, 13517);
+       if (status < 0)
+               goto error;
+       /* Decision Feedback Equalizer */
+       status = write16(state, QAM_DQ_QUAL_FUN0__A, 2);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN1__A, 2);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN2__A, 2);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN3__A, 2);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN4__A, 2);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN5__A, 0);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, QAM_SY_SYNC_HWM__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_SY_SYNC_AWM__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_SY_SYNC_LWM__A, 3);
+       if (status < 0)
+               goto error;
+
+       /* QAM Slicer Settings */
+       status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM16);
+       if (status < 0)
+               goto error;
+
+       /* QAM Loop Controller Coeficients */
+       status = write16(state, SCU_RAM_QAM_LC_CA_FINE__A, 15);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CA_COARSE__A, 40);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_FINE__A, 12);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_COARSE__A, 24);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_FINE__A, 12);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_COARSE__A, 16);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_QAM_LC_CP_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CP_MEDIUM__A, 20);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CP_COARSE__A, 80);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_MEDIUM__A, 20);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_COARSE__A, 50);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_FINE__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_MEDIUM__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_COARSE__A, 32);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 10);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_COARSE__A, 10);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM State Machine (FSM) Thresholds */
+
+       status = write16(state, SCU_RAM_QAM_FSM_RTH__A, 140);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_FTH__A, 50);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_CTH__A, 95);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_PTH__A, 120);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_QTH__A, 230);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_MTH__A, 105);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_QAM_FSM_RATE_LIM__A, 40);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_COUNT_LIM__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_FREQ_LIM__A, 24);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM FSM Tracking Parameters */
+
+       status = write16(state, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, (u16) 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, (u16) 220);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, (u16) 25);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, (u16) 6);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16) -24);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16) -65);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -127);
+       if (status < 0)
+               goto error;
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+/*============================================================================*/
+
+/**
+* \brief QAM32 specific setup
+* \param demod instance of demod.
+* \return DRXStatus_t.
+*/
+static int SetQAM32(struct drxk_state *state)
+{
+       int status = 0;
+
+       dprintk(1, "\n");
+
+       /* QAM Equalizer Setup */
+       /* Equalizer */
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD0__A, 6707);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD1__A, 6707);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD2__A, 6707);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD3__A, 6707);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD4__A, 6707);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD5__A, 6707);
+       if (status < 0)
+               goto error;
+
+       /* Decision Feedback Equalizer */
+       status = write16(state, QAM_DQ_QUAL_FUN0__A, 3);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN1__A, 3);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN2__A, 3);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN3__A, 3);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN4__A, 3);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN5__A, 0);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, QAM_SY_SYNC_HWM__A, 6);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_SY_SYNC_AWM__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_SY_SYNC_LWM__A, 3);
+       if (status < 0)
+               goto error;
+
+       /* QAM Slicer Settings */
+
+       status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM32);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM Loop Controller Coeficients */
+
+       status = write16(state, SCU_RAM_QAM_LC_CA_FINE__A, 15);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CA_COARSE__A, 40);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_FINE__A, 12);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_COARSE__A, 24);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_FINE__A, 12);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_COARSE__A, 16);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_QAM_LC_CP_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CP_MEDIUM__A, 20);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CP_COARSE__A, 80);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_MEDIUM__A, 20);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_COARSE__A, 50);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_FINE__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_MEDIUM__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_COARSE__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 10);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_COARSE__A, 0);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM State Machine (FSM) Thresholds */
+
+       status = write16(state, SCU_RAM_QAM_FSM_RTH__A, 90);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_FTH__A, 50);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_CTH__A, 80);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_PTH__A, 100);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_QTH__A, 170);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_MTH__A, 100);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_QAM_FSM_RATE_LIM__A, 40);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_COUNT_LIM__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_FREQ_LIM__A, 10);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM FSM Tracking Parameters */
+
+       status = write16(state, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, (u16) 12);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, (u16) 140);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, (u16) -8);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, (u16) -16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16) -26);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16) -56);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -86);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+/*============================================================================*/
+
+/**
+* \brief QAM64 specific setup
+* \param demod instance of demod.
+* \return DRXStatus_t.
+*/
+static int SetQAM64(struct drxk_state *state)
+{
+       int status = 0;
+
+       dprintk(1, "\n");
+       /* QAM Equalizer Setup */
+       /* Equalizer */
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD0__A, 13336);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD1__A, 12618);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD2__A, 11988);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD3__A, 13809);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD4__A, 13809);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD5__A, 15609);
+       if (status < 0)
+               goto error;
+
+       /* Decision Feedback Equalizer */
+       status = write16(state, QAM_DQ_QUAL_FUN0__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN1__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN2__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN3__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN4__A, 3);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN5__A, 0);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, QAM_SY_SYNC_HWM__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_SY_SYNC_AWM__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_SY_SYNC_LWM__A, 3);
+       if (status < 0)
+               goto error;
+
+       /* QAM Slicer Settings */
+       status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM64);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM Loop Controller Coeficients */
+
+       status = write16(state, SCU_RAM_QAM_LC_CA_FINE__A, 15);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CA_COARSE__A, 40);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_FINE__A, 12);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_COARSE__A, 24);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_FINE__A, 12);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_COARSE__A, 16);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_QAM_LC_CP_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CP_MEDIUM__A, 30);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CP_COARSE__A, 100);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_MEDIUM__A, 30);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_COARSE__A, 50);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_FINE__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_MEDIUM__A, 25);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_COARSE__A, 48);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 10);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_COARSE__A, 10);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM State Machine (FSM) Thresholds */
+
+       status = write16(state, SCU_RAM_QAM_FSM_RTH__A, 100);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_FTH__A, 60);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_CTH__A, 80);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_PTH__A, 110);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_QTH__A, 200);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_MTH__A, 95);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_QAM_FSM_RATE_LIM__A, 40);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_COUNT_LIM__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_FREQ_LIM__A, 15);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM FSM Tracking Parameters */
+
+       status = write16(state, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, (u16) 12);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, (u16) 141);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, (u16) 7);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, (u16) 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16) -15);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16) -45);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -80);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+/*============================================================================*/
+
+/**
+* \brief QAM128 specific setup
+* \param demod: instance of demod.
+* \return DRXStatus_t.
+*/
+static int SetQAM128(struct drxk_state *state)
+{
+       int status = 0;
+
+       dprintk(1, "\n");
+       /* QAM Equalizer Setup */
+       /* Equalizer */
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD0__A, 6564);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD1__A, 6598);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD2__A, 6394);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD3__A, 6409);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD4__A, 6656);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD5__A, 7238);
+       if (status < 0)
+               goto error;
+
+       /* Decision Feedback Equalizer */
+       status = write16(state, QAM_DQ_QUAL_FUN0__A, 6);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN1__A, 6);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN2__A, 6);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN3__A, 6);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN4__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN5__A, 0);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, QAM_SY_SYNC_HWM__A, 6);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_SY_SYNC_AWM__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_SY_SYNC_LWM__A, 3);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM Slicer Settings */
+
+       status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM128);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM Loop Controller Coeficients */
+
+       status = write16(state, SCU_RAM_QAM_LC_CA_FINE__A, 15);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CA_COARSE__A, 40);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_FINE__A, 12);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_COARSE__A, 24);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_FINE__A, 12);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_COARSE__A, 16);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_QAM_LC_CP_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CP_MEDIUM__A, 40);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CP_COARSE__A, 120);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_MEDIUM__A, 40);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_COARSE__A, 60);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_FINE__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_MEDIUM__A, 25);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_COARSE__A, 64);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 10);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_COARSE__A, 0);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM State Machine (FSM) Thresholds */
+
+       status = write16(state, SCU_RAM_QAM_FSM_RTH__A, 50);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_FTH__A, 60);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_CTH__A, 80);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_PTH__A, 100);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_QTH__A, 140);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_MTH__A, 100);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_QAM_FSM_RATE_LIM__A, 40);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_COUNT_LIM__A, 5);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_QAM_FSM_FREQ_LIM__A, 12);
+       if (status < 0)
+               goto error;
+
+       /* QAM FSM Tracking Parameters */
+
+       status = write16(state, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, (u16) 8);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, (u16) 65);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, (u16) 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, (u16) 3);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16) -1);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16) -12);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -23);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+/*============================================================================*/
+
+/**
+* \brief QAM256 specific setup
+* \param demod: instance of demod.
+* \return DRXStatus_t.
+*/
+static int SetQAM256(struct drxk_state *state)
+{
+       int status = 0;
+
+       dprintk(1, "\n");
+       /* QAM Equalizer Setup */
+       /* Equalizer */
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD0__A, 11502);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD1__A, 12084);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD2__A, 12543);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD3__A, 12931);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD4__A, 13629);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD5__A, 15385);
+       if (status < 0)
+               goto error;
+
+       /* Decision Feedback Equalizer */
+       status = write16(state, QAM_DQ_QUAL_FUN0__A, 8);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN1__A, 8);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN2__A, 8);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN3__A, 8);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN4__A, 6);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN5__A, 0);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, QAM_SY_SYNC_HWM__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_SY_SYNC_AWM__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_SY_SYNC_LWM__A, 3);
+       if (status < 0)
+               goto error;
+
+       /* QAM Slicer Settings */
+
+       status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM256);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM Loop Controller Coeficients */
+
+       status = write16(state, SCU_RAM_QAM_LC_CA_FINE__A, 15);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CA_COARSE__A, 40);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_FINE__A, 12);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_COARSE__A, 24);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_FINE__A, 12);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_COARSE__A, 16);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_QAM_LC_CP_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CP_MEDIUM__A, 50);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CP_COARSE__A, 250);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_MEDIUM__A, 50);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_COARSE__A, 125);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_FINE__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_MEDIUM__A, 25);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_COARSE__A, 48);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 10);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_COARSE__A, 10);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM State Machine (FSM) Thresholds */
+
+       status = write16(state, SCU_RAM_QAM_FSM_RTH__A, 50);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_FTH__A, 60);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_CTH__A, 80);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_PTH__A, 100);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_QTH__A, 150);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_MTH__A, 110);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_QAM_FSM_RATE_LIM__A, 40);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_COUNT_LIM__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_FREQ_LIM__A, 12);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM FSM Tracking Parameters */
+
+       status = write16(state, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, (u16) 8);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, (u16) 74);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, (u16) 18);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, (u16) 13);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16) 7);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16) 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -8);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+
+/*============================================================================*/
+/**
+* \brief Reset QAM block.
+* \param demod:   instance of demod.
+* \param channel: pointer to channel data.
+* \return DRXStatus_t.
+*/
+static int QAMResetQAM(struct drxk_state *state)
+{
+       int status;
+       u16 cmdResult;
+
+       dprintk(1, "\n");
+       /* Stop QAM comstate->m_exec */
+       status = write16(state, QAM_COMM_EXEC__A, QAM_COMM_EXEC_STOP);
+       if (status < 0)
+               goto error;
+
+       status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_RESET, 0, NULL, 1, &cmdResult);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+/*============================================================================*/
+
+/**
+* \brief Set QAM symbolrate.
+* \param demod:   instance of demod.
+* \param channel: pointer to channel data.
+* \return DRXStatus_t.
+*/
+static int QAMSetSymbolrate(struct drxk_state *state)
+{
+       u32 adcFrequency = 0;
+       u32 symbFreq = 0;
+       u32 iqmRcRate = 0;
+       u16 ratesel = 0;
+       u32 lcSymbRate = 0;
+       int status;
+
+       dprintk(1, "\n");
+       /* Select & calculate correct IQM rate */
+       adcFrequency = (state->m_sysClockFreq * 1000) / 3;
+       ratesel = 0;
+       /* printk(KERN_DEBUG "drxk: SR %d\n", state->param.u.qam.symbol_rate); */
+       if (state->param.u.qam.symbol_rate <= 1188750)
+               ratesel = 3;
+       else if (state->param.u.qam.symbol_rate <= 2377500)
+               ratesel = 2;
+       else if (state->param.u.qam.symbol_rate <= 4755000)
+               ratesel = 1;
+       status = write16(state, IQM_FD_RATESEL__A, ratesel);
+       if (status < 0)
+               goto error;
+
+       /*
+               IqmRcRate = ((Fadc / (symbolrate * (4<<ratesel))) - 1) * (1<<23)
+               */
+       symbFreq = state->param.u.qam.symbol_rate * (1 << ratesel);
+       if (symbFreq == 0) {
+               /* Divide by zero */
+               status = -EINVAL;
+               goto error;
+       }
+       iqmRcRate = (adcFrequency / symbFreq) * (1 << 21) +
+               (Frac28a((adcFrequency % symbFreq), symbFreq) >> 7) -
+               (1 << 23);
+       status = write32(state, IQM_RC_RATE_OFS_LO__A, iqmRcRate);
+       if (status < 0)
+               goto error;
+       state->m_iqmRcRate = iqmRcRate;
+       /*
+               LcSymbFreq = round (.125 *  symbolrate / adcFreq * (1<<15))
+               */
+       symbFreq = state->param.u.qam.symbol_rate;
+       if (adcFrequency == 0) {
+               /* Divide by zero */
+               status = -EINVAL;
+               goto error;
+       }
+       lcSymbRate = (symbFreq / adcFrequency) * (1 << 12) +
+               (Frac28a((symbFreq % adcFrequency), adcFrequency) >>
+               16);
+       if (lcSymbRate > 511)
+               lcSymbRate = 511;
+       status = write16(state, QAM_LC_SYMBOL_FREQ__A, (u16) lcSymbRate);
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+/*============================================================================*/
+
+/**
+* \brief Get QAM lock status.
+* \param demod:   instance of demod.
+* \param channel: pointer to channel data.
+* \return DRXStatus_t.
+*/
+
+static int GetQAMLockStatus(struct drxk_state *state, u32 *pLockStatus)
+{
+       int status;
+       u16 Result[2] = { 0, 0 };
+
+       dprintk(1, "\n");
+       *pLockStatus = NOT_LOCKED;
+       status = scu_command(state,
+                       SCU_RAM_COMMAND_STANDARD_QAM |
+                       SCU_RAM_COMMAND_CMD_DEMOD_GET_LOCK, 0, NULL, 2,
+                       Result);
+       if (status < 0)
+               printk(KERN_ERR "drxk: %s status = %08x\n", __func__, status);
+
+       if (Result[1] < SCU_RAM_QAM_LOCKED_LOCKED_DEMOD_LOCKED) {
+               /* 0x0000 NOT LOCKED */
+       } else if (Result[1] < SCU_RAM_QAM_LOCKED_LOCKED_LOCKED) {
+               /* 0x4000 DEMOD LOCKED */
+               *pLockStatus = DEMOD_LOCK;
+       } else if (Result[1] < SCU_RAM_QAM_LOCKED_LOCKED_NEVER_LOCK) {
+               /* 0x8000 DEMOD + FEC LOCKED (system lock) */
+               *pLockStatus = MPEG_LOCK;
+       } else {
+               /* 0xC000 NEVER LOCKED */
+               /* (system will never be able to lock to the signal) */
+               /* TODO: check this, intermediate & standard specific lock states are not
+                  taken into account here */
+               *pLockStatus = NEVER_LOCK;
+       }
+       return status;
+}
+
+#define QAM_MIRROR__M         0x03
+#define QAM_MIRROR_NORMAL     0x00
+#define QAM_MIRRORED          0x01
+#define QAM_MIRROR_AUTO_ON    0x02
+#define QAM_LOCKRANGE__M      0x10
+#define QAM_LOCKRANGE_NORMAL  0x10
+
+static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
+                 s32 tunerFreqOffset)
+{
+       int status;
+       u16 setParamParameters[4] = { 0, 0, 0, 0 };
+       u16 cmdResult;
+
+       dprintk(1, "\n");
+       /*
+        * STEP 1: reset demodulator
+        *      resets FEC DI and FEC RS
+        *      resets QAM block
+        *      resets SCU variables
+        */
+       status = write16(state, FEC_DI_COMM_EXEC__A, FEC_DI_COMM_EXEC_STOP);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_RS_COMM_EXEC__A, FEC_RS_COMM_EXEC_STOP);
+       if (status < 0)
+               goto error;
+       status = QAMResetQAM(state);
+       if (status < 0)
+               goto error;
+
+       /*
+        * STEP 2: configure demodulator
+        *      -set params; resets IQM,QAM,FEC HW; initializes some
+        *       SCU variables
+        */
+       status = QAMSetSymbolrate(state);
+       if (status < 0)
+               goto error;
+
+       /* Set params */
+       switch (state->param.u.qam.modulation) {
+       case QAM_256:
+               state->m_Constellation = DRX_CONSTELLATION_QAM256;
+               break;
+       case QAM_AUTO:
+       case QAM_64:
+               state->m_Constellation = DRX_CONSTELLATION_QAM64;
+               break;
+       case QAM_16:
+               state->m_Constellation = DRX_CONSTELLATION_QAM16;
+               break;
+       case QAM_32:
+               state->m_Constellation = DRX_CONSTELLATION_QAM32;
+               break;
+       case QAM_128:
+               state->m_Constellation = DRX_CONSTELLATION_QAM128;
+               break;
+       default:
+               status = -EINVAL;
+               break;
+       }
+       if (status < 0)
+               goto error;
+       setParamParameters[0] = state->m_Constellation; /* constellation     */
+       setParamParameters[1] = DRXK_QAM_I12_J17;       /* interleave mode   */
+       if (state->m_OperationMode == OM_QAM_ITU_C)
+               setParamParameters[2] = QAM_TOP_ANNEX_C;
+       else
+               setParamParameters[2] = QAM_TOP_ANNEX_A;
+       setParamParameters[3] |= (QAM_MIRROR_AUTO_ON);
+       /* Env parameters */
+       /* check for LOCKRANGE Extented */
+       /* setParamParameters[3] |= QAM_LOCKRANGE_NORMAL; */
+
+       status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM, 4, setParamParameters, 1, &cmdResult);
+       if (status < 0) {
+               /* Fall-back to the simpler call */
+               if (state->m_OperationMode == OM_QAM_ITU_C)
+                       setParamParameters[0] = QAM_TOP_ANNEX_C;
+               else
+                       setParamParameters[0] = QAM_TOP_ANNEX_A;
+               status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV, 1, setParamParameters, 1, &cmdResult);
+               if (status < 0)
+                       goto error;
+
+               setParamParameters[0] = state->m_Constellation; /* constellation     */
+               setParamParameters[1] = DRXK_QAM_I12_J17;       /* interleave mode   */
+               status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM, 2, setParamParameters, 1, &cmdResult);
+       }
+       if (status < 0)
+               goto error;
+
+       /*
+        * STEP 3: enable the system in a mode where the ADC provides valid
+        * signal setup constellation independent registers
+        */
+#if 0
+       status = SetFrequency(channel, tunerFreqOffset));
+       if (status < 0)
+               goto error;
+#endif
+       status = SetFrequencyShifter(state, IntermediateFreqkHz, tunerFreqOffset, true);
+       if (status < 0)
+               goto error;
+
+       /* Setup BER measurement */
+       status = SetQAMMeasurement(state, state->m_Constellation, state->param.u. qam.symbol_rate);
+       if (status < 0)
+               goto error;
+
+       /* Reset default values */
+       status = write16(state, IQM_CF_SCALE_SH__A, IQM_CF_SCALE_SH__PRE);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_SY_TIMEOUT__A, QAM_SY_TIMEOUT__PRE);
+       if (status < 0)
+               goto error;
+
+       /* Reset default LC values */
+       status = write16(state, QAM_LC_RATE_LIMIT__A, 3);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_LPF_FACTORP__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_LPF_FACTORI__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_MODE__A, 7);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, QAM_LC_QUAL_TAB0__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB1__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB2__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB3__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB4__A, 2);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB5__A, 2);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB6__A, 2);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB8__A, 2);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB9__A, 2);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB10__A, 2);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB12__A, 2);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB15__A, 3);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB16__A, 3);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB20__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB25__A, 4);
+       if (status < 0)
+               goto error;
+
+       /* Mirroring, QAM-block starting point not inverted */
+       status = write16(state, QAM_SY_SP_INV__A, QAM_SY_SP_INV_SPECTRUM_INV_DIS);
+       if (status < 0)
+               goto error;
+
+       /* Halt SCU to enable safe non-atomic accesses */
+       status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_HOLD);
+       if (status < 0)
+               goto error;
+
+       /* STEP 4: constellation specific setup */
+       switch (state->param.u.qam.modulation) {
+       case QAM_16:
+               status = SetQAM16(state);
+               break;
+       case QAM_32:
+               status = SetQAM32(state);
+               break;
+       case QAM_AUTO:
+       case QAM_64:
+               status = SetQAM64(state);
+               break;
+       case QAM_128:
+               status = SetQAM128(state);
+               break;
+       case QAM_256:
+               status = SetQAM256(state);
+               break;
+       default:
+               status = -EINVAL;
+               break;
+       }
+       if (status < 0)
+               goto error;
+
+       /* Activate SCU to enable SCU commands */
+       status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE);
+       if (status < 0)
+               goto error;
+
+       /* Re-configure MPEG output, requires knowledge of channel bitrate */
+       /* extAttr->currentChannel.constellation = channel->constellation; */
+       /* extAttr->currentChannel.symbolrate    = channel->symbolrate; */
+       status = MPEGTSDtoSetup(state, state->m_OperationMode);
+       if (status < 0)
+               goto error;
+
+       /* Start processes */
+       status = MPEGTSStart(state);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_COMM_EXEC__A, FEC_COMM_EXEC_ACTIVE);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_COMM_EXEC__A, QAM_COMM_EXEC_ACTIVE);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_COMM_EXEC__A, IQM_COMM_EXEC_B_ACTIVE);
+       if (status < 0)
+               goto error;
+
+       /* STEP 5: start QAM demodulator (starts FEC, QAM and IQM HW) */
+       status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_START, 0, NULL, 1, &cmdResult);
+       if (status < 0)
+               goto error;
+
+       /* update global DRXK data container */
+/*?     extAttr->qamInterleaveMode = DRXK_QAM_I12_J17; */
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int SetQAMStandard(struct drxk_state *state,
+                         enum OperationMode oMode)
+{
+       int status;
+#ifdef DRXK_QAM_TAPS
+#define DRXK_QAMA_TAPS_SELECT
+#include "drxk_filters.h"
+#undef DRXK_QAMA_TAPS_SELECT
+#endif
+
+       dprintk(1, "\n");
+
+       /* added antenna switch */
+       SwitchAntennaToQAM(state);
+
+       /* Ensure correct power-up mode */
+       status = PowerUpQAM(state);
+       if (status < 0)
+               goto error;
+       /* Reset QAM block */
+       status = QAMResetQAM(state);
+       if (status < 0)
+               goto error;
+
+       /* Setup IQM */
+
+       status = write16(state, IQM_COMM_EXEC__A, IQM_COMM_EXEC_B_STOP);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_AF_AMUX__A, IQM_AF_AMUX_SIGNAL2ADC);
+       if (status < 0)
+               goto error;
+
+       /* Upload IQM Channel Filter settings by
+               boot loader from ROM table */
+       switch (oMode) {
+       case OM_QAM_ITU_A:
+               status = BLChainCmd(state, DRXK_BL_ROM_OFFSET_TAPS_ITU_A, DRXK_BLCC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT);
+               break;
+       case OM_QAM_ITU_C:
+               status = BLDirectCmd(state, IQM_CF_TAP_RE0__A, DRXK_BL_ROM_OFFSET_TAPS_ITU_C, DRXK_BLDC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT);
+               if (status < 0)
+                       goto error;
+               status = BLDirectCmd(state, IQM_CF_TAP_IM0__A, DRXK_BL_ROM_OFFSET_TAPS_ITU_C, DRXK_BLDC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT);
+               break;
+       default:
+               status = -EINVAL;
+       }
+       if (status < 0)
+               goto error;
+
+       status = write16(state, IQM_CF_OUT_ENA__A, (1 << IQM_CF_OUT_ENA_QAM__B));
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_SYMMETRIC__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_MIDTAP__A, ((1 << IQM_CF_MIDTAP_RE__B) | (1 << IQM_CF_MIDTAP_IM__B)));
+       if (status < 0)
+               goto error;
+
+       status = write16(state, IQM_RC_STRETCH__A, 21);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_AF_CLP_LEN__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_AF_CLP_TH__A, 448);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_AF_SNS_LEN__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_POW_MEAS_LEN__A, 0);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, IQM_FS_ADJ_SEL__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_RC_ADJ_SEL__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_ADJ_SEL__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_AF_UPD_SEL__A, 0);
+       if (status < 0)
+               goto error;
+
+       /* IQM Impulse Noise Processing Unit */
+       status = write16(state, IQM_CF_CLP_VAL__A, 500);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_DATATH__A, 1000);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_BYPASSDET__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_DET_LCT__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_WND_LEN__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_PKDTH__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_AF_INC_BYPASS__A, 1);
+       if (status < 0)
+               goto error;
+
+       /* turn on IQMAF. Must be done before setAgc**() */
+       status = SetIqmAf(state, true);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_AF_START_LOCK__A, 0x01);
+       if (status < 0)
+               goto error;
+
+       /* IQM will not be reset from here, sync ADC and update/init AGC */
+       status = ADCSynchronization(state);
+       if (status < 0)
+               goto error;
+
+       /* Set the FSM step period */
+       status = write16(state, SCU_RAM_QAM_FSM_STEP_PERIOD__A, 2000);
+       if (status < 0)
+               goto error;
+
+       /* Halt SCU to enable safe non-atomic accesses */
+       status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_HOLD);
+       if (status < 0)
+               goto error;
+
+       /* No more resets of the IQM, current standard correctly set =>
+               now AGCs can be configured. */
+
+       status = InitAGC(state, true);
+       if (status < 0)
+               goto error;
+       status = SetPreSaw(state, &(state->m_qamPreSawCfg));
+       if (status < 0)
+               goto error;
+
+       /* Configure AGC's */
+       status = SetAgcRf(state, &(state->m_qamRfAgcCfg), true);
+       if (status < 0)
+               goto error;
+       status = SetAgcIf(state, &(state->m_qamIfAgcCfg), true);
+       if (status < 0)
+               goto error;
+
+       /* Activate SCU to enable SCU commands */
+       status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int WriteGPIO(struct drxk_state *state)
+{
+       int status;
+       u16 value = 0;
+
+       dprintk(1, "\n");
+       /* stop lock indicator process */
+       status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+       if (status < 0)
+               goto error;
+
+       /*  Write magic word to enable pdr reg write               */
+       status = write16(state, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY_KEY);
+       if (status < 0)
+               goto error;
+
+       if (state->m_hasSAWSW) {
+               if (state->UIO_mask & 0x0001) { /* UIO-1 */
+                       /* write to io pad configuration register - output mode */
+                       status = write16(state, SIO_PDR_SMA_TX_CFG__A, state->m_GPIOCfg);
+                       if (status < 0)
+                               goto error;
+
+                       /* use corresponding bit in io data output registar */
+                       status = read16(state, SIO_PDR_UIO_OUT_LO__A, &value);
+                       if (status < 0)
+                               goto error;
+                       if ((state->m_GPIO & 0x0001) == 0)
+                               value &= 0x7FFF;        /* write zero to 15th bit - 1st UIO */
+                       else
+                               value |= 0x8000;        /* write one to 15th bit - 1st UIO */
+                       /* write back to io data output register */
+                       status = write16(state, SIO_PDR_UIO_OUT_LO__A, value);
+                       if (status < 0)
+                               goto error;
+               }
+               if (state->UIO_mask & 0x0002) { /* UIO-2 */
+                       /* write to io pad configuration register - output mode */
+                       status = write16(state, SIO_PDR_SMA_TX_CFG__A, state->m_GPIOCfg);
+                       if (status < 0)
+                               goto error;
+
+                       /* use corresponding bit in io data output registar */
+                       status = read16(state, SIO_PDR_UIO_OUT_LO__A, &value);
+                       if (status < 0)
+                               goto error;
+                       if ((state->m_GPIO & 0x0002) == 0)
+                               value &= 0xBFFF;        /* write zero to 14th bit - 2st UIO */
+                       else
+                               value |= 0x4000;        /* write one to 14th bit - 2st UIO */
+                       /* write back to io data output register */
+                       status = write16(state, SIO_PDR_UIO_OUT_LO__A, value);
+                       if (status < 0)
+                               goto error;
+               }
+               if (state->UIO_mask & 0x0004) { /* UIO-3 */
+                       /* write to io pad configuration register - output mode */
+                       status = write16(state, SIO_PDR_SMA_TX_CFG__A, state->m_GPIOCfg);
+                       if (status < 0)
+                               goto error;
+
+                       /* use corresponding bit in io data output registar */
+                       status = read16(state, SIO_PDR_UIO_OUT_LO__A, &value);
+                       if (status < 0)
+                               goto error;
+                       if ((state->m_GPIO & 0x0004) == 0)
+                               value &= 0xFFFB;            /* write zero to 2nd bit - 3rd UIO */
+                       else
+                               value |= 0x0004;            /* write one to 2nd bit - 3rd UIO */
+                       /* write back to io data output register */
+                       status = write16(state, SIO_PDR_UIO_OUT_LO__A, value);
+                       if (status < 0)
+                               goto error;
+               }
+       }
+       /*  Write magic word to disable pdr reg write               */
+       status = write16(state, SIO_TOP_COMM_KEY__A, 0x0000);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int SwitchAntennaToQAM(struct drxk_state *state)
+{
+       int status = 0;
+       bool gpio_state;
+
+       dprintk(1, "\n");
+
+       if (!state->antenna_gpio)
+               return 0;
+
+       gpio_state = state->m_GPIO & state->antenna_gpio;
+
+       if (state->antenna_dvbt ^ gpio_state) {
+               /* Antenna is on DVB-T mode. Switch */
+               if (state->antenna_dvbt)
+                       state->m_GPIO &= ~state->antenna_gpio;
+               else
+                       state->m_GPIO |= state->antenna_gpio;
+               status = WriteGPIO(state);
+       }
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int SwitchAntennaToDVBT(struct drxk_state *state)
+{
+       int status = 0;
+       bool gpio_state;
+
+       dprintk(1, "\n");
+
+       if (!state->antenna_gpio)
+               return 0;
+
+       gpio_state = state->m_GPIO & state->antenna_gpio;
+
+       if (!(state->antenna_dvbt ^ gpio_state)) {
+               /* Antenna is on DVB-C mode. Switch */
+               if (state->antenna_dvbt)
+                       state->m_GPIO |= state->antenna_gpio;
+               else
+                       state->m_GPIO &= ~state->antenna_gpio;
+               status = WriteGPIO(state);
+       }
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+
+static int PowerDownDevice(struct drxk_state *state)
+{
+       /* Power down to requested mode */
+       /* Backup some register settings */
+       /* Set pins with possible pull-ups connected to them in input mode */
+       /* Analog power down */
+       /* ADC power down */
+       /* Power down device */
+       int status;
+
+       dprintk(1, "\n");
+       if (state->m_bPDownOpenBridge) {
+               /* Open I2C bridge before power down of DRXK */
+               status = ConfigureI2CBridge(state, true);
+               if (status < 0)
+                       goto error;
+       }
+       /* driver 0.9.0 */
+       status = DVBTEnableOFDMTokenRing(state, false);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SIO_CC_PWD_MODE__A, SIO_CC_PWD_MODE_LEVEL_CLOCK);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY);
+       if (status < 0)
+               goto error;
+       state->m_HICfgCtrl |= SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ;
+       status = HI_CfgCommand(state);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+static int load_microcode(struct drxk_state *state, const char *mc_name)
+{
+       const struct firmware *fw = NULL;
+       int err = 0;
+
+       dprintk(1, "\n");
+
+       err = request_firmware(&fw, mc_name, state->i2c->dev.parent);
+       if (err < 0) {
+               printk(KERN_ERR
+                      "drxk: Could not load firmware file %s.\n", mc_name);
+               printk(KERN_INFO
+                      "drxk: Copy %s to your hotplug directory!\n", mc_name);
+               return err;
+       }
+       err = DownloadMicrocode(state, fw->data, fw->size);
+       release_firmware(fw);
+       return err;
+}
+
+static int init_drxk(struct drxk_state *state)
+{
+       int status = 0;
+       enum DRXPowerMode powerMode = DRXK_POWER_DOWN_OFDM;
+       u16 driverVersion;
+
+       dprintk(1, "\n");
+       if ((state->m_DrxkState == DRXK_UNINITIALIZED)) {
+               status = PowerUpDevice(state);
+               if (status < 0)
+                       goto error;
+               status = DRXX_Open(state);
+               if (status < 0)
+                       goto error;
+               /* Soft reset of OFDM-, sys- and osc-clockdomain */
+               status = write16(state, SIO_CC_SOFT_RST__A, SIO_CC_SOFT_RST_OFDM__M | SIO_CC_SOFT_RST_SYS__M | SIO_CC_SOFT_RST_OSC__M);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY);
+               if (status < 0)
+                       goto error;
+               /* TODO is this needed, if yes how much delay in worst case scenario */
+               msleep(1);
+               state->m_DRXK_A3_PATCH_CODE = true;
+               status = GetDeviceCapabilities(state);
+               if (status < 0)
+                       goto error;
+
+               /* Bridge delay, uses oscilator clock */
+               /* Delay = (delay (nano seconds) * oscclk (kHz))/ 1000 */
+               /* SDA brdige delay */
+               state->m_HICfgBridgeDelay =
+                       (u16) ((state->m_oscClockFreq / 1000) *
+                               HI_I2C_BRIDGE_DELAY) / 1000;
+               /* Clipping */
+               if (state->m_HICfgBridgeDelay >
+                       SIO_HI_RA_RAM_PAR_3_CFG_DBL_SDA__M) {
+                       state->m_HICfgBridgeDelay =
+                               SIO_HI_RA_RAM_PAR_3_CFG_DBL_SDA__M;
+               }
+               /* SCL bridge delay, same as SDA for now */
+               state->m_HICfgBridgeDelay +=
+                       state->m_HICfgBridgeDelay <<
+                       SIO_HI_RA_RAM_PAR_3_CFG_DBL_SCL__B;
+
+               status = InitHI(state);
+               if (status < 0)
+                       goto error;
+               /* disable various processes */
+#if NOA1ROM
+               if (!(state->m_DRXK_A1_ROM_CODE)
+                       && !(state->m_DRXK_A2_ROM_CODE))
+#endif
+               {
+                       status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+                       if (status < 0)
+                               goto error;
+               }
+
+               /* disable MPEG port */
+               status = MPEGTSDisable(state);
+               if (status < 0)
+                       goto error;
+
+               /* Stop AUD and SCU */
+               status = write16(state, AUD_COMM_EXEC__A, AUD_COMM_EXEC_STOP);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_STOP);
+               if (status < 0)
+                       goto error;
+
+               /* enable token-ring bus through OFDM block for possible ucode upload */
+               status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, SIO_OFDM_SH_OFDM_RING_ENABLE_ON);
+               if (status < 0)
+                       goto error;
+
+               /* include boot loader section */
+               status = write16(state, SIO_BL_COMM_EXEC__A, SIO_BL_COMM_EXEC_ACTIVE);
+               if (status < 0)
+                       goto error;
+               status = BLChainCmd(state, 0, 6, 100);
+               if (status < 0)
+                       goto error;
+
+               if (!state->microcode_name)
+                       load_microcode(state, "drxk_a3.mc");
+               else
+                       load_microcode(state, state->microcode_name);
+
+               /* disable token-ring bus through OFDM block for possible ucode upload */
+               status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, SIO_OFDM_SH_OFDM_RING_ENABLE_OFF);
+               if (status < 0)
+                       goto error;
+
+               /* Run SCU for a little while to initialize microcode version numbers */
+               status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE);
+               if (status < 0)
+                       goto error;
+               status = DRXX_Open(state);
+               if (status < 0)
+                       goto error;
+               /* added for test */
+               msleep(30);
+
+               powerMode = DRXK_POWER_DOWN_OFDM;
+               status = CtrlPowerMode(state, &powerMode);
+               if (status < 0)
+                       goto error;
+
+               /* Stamp driver version number in SCU data RAM in BCD code
+                       Done to enable field application engineers to retreive drxdriver version
+                       via I2C from SCU RAM.
+                       Not using SCU command interface for SCU register access since no
+                       microcode may be present.
+                       */
+               driverVersion =
+                       (((DRXK_VERSION_MAJOR / 100) % 10) << 12) +
+                       (((DRXK_VERSION_MAJOR / 10) % 10) << 8) +
+                       ((DRXK_VERSION_MAJOR % 10) << 4) +
+                       (DRXK_VERSION_MINOR % 10);
+               status = write16(state, SCU_RAM_DRIVER_VER_HI__A, driverVersion);
+               if (status < 0)
+                       goto error;
+               driverVersion =
+                       (((DRXK_VERSION_PATCH / 1000) % 10) << 12) +
+                       (((DRXK_VERSION_PATCH / 100) % 10) << 8) +
+                       (((DRXK_VERSION_PATCH / 10) % 10) << 4) +
+                       (DRXK_VERSION_PATCH % 10);
+               status = write16(state, SCU_RAM_DRIVER_VER_LO__A, driverVersion);
+               if (status < 0)
+                       goto error;
+
+               printk(KERN_INFO "DRXK driver version %d.%d.%d\n",
+                       DRXK_VERSION_MAJOR, DRXK_VERSION_MINOR,
+                       DRXK_VERSION_PATCH);
+
+               /* Dirty fix of default values for ROM/PATCH microcode
+                       Dirty because this fix makes it impossible to setup suitable values
+                       before calling DRX_Open. This solution requires changes to RF AGC speed
+                       to be done via the CTRL function after calling DRX_Open */
+
+               /* m_dvbtRfAgcCfg.speed = 3; */
+
+               /* Reset driver debug flags to 0 */
+               status = write16(state, SCU_RAM_DRIVER_DEBUG__A, 0);
+               if (status < 0)
+                       goto error;
+               /* driver 0.9.0 */
+               /* Setup FEC OC:
+                       NOTE: No more full FEC resets allowed afterwards!! */
+               status = write16(state, FEC_COMM_EXEC__A, FEC_COMM_EXEC_STOP);
+               if (status < 0)
+                       goto error;
+               /* MPEGTS functions are still the same */
+               status = MPEGTSDtoInit(state);
+               if (status < 0)
+                       goto error;
+               status = MPEGTSStop(state);
+               if (status < 0)
+                       goto error;
+               status = MPEGTSConfigurePolarity(state);
+               if (status < 0)
+                       goto error;
+               status = MPEGTSConfigurePins(state, state->m_enableMPEGOutput);
+               if (status < 0)
+                       goto error;
+               /* added: configure GPIO */
+               status = WriteGPIO(state);
+               if (status < 0)
+                       goto error;
+
+               state->m_DrxkState = DRXK_STOPPED;
+
+               if (state->m_bPowerDown) {
+                       status = PowerDownDevice(state);
+                       if (status < 0)
+                               goto error;
+                       state->m_DrxkState = DRXK_POWERED_DOWN;
+               } else
+                       state->m_DrxkState = DRXK_STOPPED;
+       }
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+static void drxk_c_release(struct dvb_frontend *fe)
+{
+       struct drxk_state *state = fe->demodulator_priv;
+
+       dprintk(1, "\n");
+       kfree(state);
+}
+
+static int drxk_c_init(struct dvb_frontend *fe)
+{
+       struct drxk_state *state = fe->demodulator_priv;
+
+       dprintk(1, "\n");
+       if (mutex_trylock(&state->ctlock) == 0)
+               return -EBUSY;
+       SetOperationMode(state, OM_QAM_ITU_A);
+       return 0;
+}
+
+static int drxk_c_sleep(struct dvb_frontend *fe)
+{
+       struct drxk_state *state = fe->demodulator_priv;
+
+       dprintk(1, "\n");
+       ShutDown(state);
+       mutex_unlock(&state->ctlock);
+       return 0;
+}
+
+static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       struct drxk_state *state = fe->demodulator_priv;
+
+       dprintk(1, "%s\n", enable ? "enable" : "disable");
+       return ConfigureI2CBridge(state, enable ? true : false);
+}
+
+static int drxk_set_parameters(struct dvb_frontend *fe,
+                              struct dvb_frontend_parameters *p)
+{
+       struct drxk_state *state = fe->demodulator_priv;
+       u32 IF;
+
+       dprintk(1, "\n");
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+       if (fe->ops.tuner_ops.set_params)
+               fe->ops.tuner_ops.set_params(fe, p);
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0);
+       state->param = *p;
+       fe->ops.tuner_ops.get_frequency(fe, &IF);
+       Start(state, 0, IF);
+
+       /* printk(KERN_DEBUG "drxk: %s IF=%d done\n", __func__, IF); */
+
+       return 0;
+}
+
+static int drxk_c_get_frontend(struct dvb_frontend *fe,
+                              struct dvb_frontend_parameters *p)
+{
+       dprintk(1, "\n");
+       return 0;
+}
+
+static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct drxk_state *state = fe->demodulator_priv;
+       u32 stat;
+
+       dprintk(1, "\n");
+       *status = 0;
+       GetLockStatus(state, &stat, 0);
+       if (stat == MPEG_LOCK)
+               *status |= 0x1f;
+       if (stat == FEC_LOCK)
+               *status |= 0x0f;
+       if (stat == DEMOD_LOCK)
+               *status |= 0x07;
+       return 0;
+}
+
+static int drxk_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       dprintk(1, "\n");
+
+       *ber = 0;
+       return 0;
+}
+
+static int drxk_read_signal_strength(struct dvb_frontend *fe,
+                                    u16 *strength)
+{
+       struct drxk_state *state = fe->demodulator_priv;
+       u32 val = 0;
+
+       dprintk(1, "\n");
+       ReadIFAgc(state, &val);
+       *strength = val & 0xffff;
+       return 0;
+}
+
+static int drxk_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       struct drxk_state *state = fe->demodulator_priv;
+       s32 snr2;
+
+       dprintk(1, "\n");
+       GetSignalToNoise(state, &snr2);
+       *snr = snr2 & 0xffff;
+       return 0;
+}
+
+static int drxk_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       struct drxk_state *state = fe->demodulator_priv;
+       u16 err;
+
+       dprintk(1, "\n");
+       DVBTQAMGetAccPktErr(state, &err);
+       *ucblocks = (u32) err;
+       return 0;
+}
+
+static int drxk_c_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings
+                                   *sets)
+{
+       dprintk(1, "\n");
+       sets->min_delay_ms = 3000;
+       sets->max_drift = 0;
+       sets->step_size = 0;
+       return 0;
+}
+
+static void drxk_t_release(struct dvb_frontend *fe)
+{
+       /*
+        * There's nothing to release here, as the state struct
+        * is already freed by drxk_c_release.
+        */
+}
+
+static int drxk_t_init(struct dvb_frontend *fe)
+{
+       struct drxk_state *state = fe->demodulator_priv;
+
+       dprintk(1, "\n");
+       if (mutex_trylock(&state->ctlock) == 0)
+               return -EBUSY;
+       SetOperationMode(state, OM_DVBT);
+       return 0;
+}
+
+static int drxk_t_sleep(struct dvb_frontend *fe)
+{
+       struct drxk_state *state = fe->demodulator_priv;
+
+       dprintk(1, "\n");
+       mutex_unlock(&state->ctlock);
+       return 0;
+}
+
+static int drxk_t_get_frontend(struct dvb_frontend *fe,
+                              struct dvb_frontend_parameters *p)
+{
+       dprintk(1, "\n");
+
+       return 0;
+}
+
+static struct dvb_frontend_ops drxk_c_ops = {
+       .info = {
+                .name = "DRXK DVB-C",
+                .type = FE_QAM,
+                .frequency_stepsize = 62500,
+                .frequency_min = 47000000,
+                .frequency_max = 862000000,
+                .symbol_rate_min = 870000,
+                .symbol_rate_max = 11700000,
+                .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
+                FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_FEC_AUTO},
+       .release = drxk_c_release,
+       .init = drxk_c_init,
+       .sleep = drxk_c_sleep,
+       .i2c_gate_ctrl = drxk_gate_ctrl,
+
+       .set_frontend = drxk_set_parameters,
+       .get_frontend = drxk_c_get_frontend,
+       .get_tune_settings = drxk_c_get_tune_settings,
+
+       .read_status = drxk_read_status,
+       .read_ber = drxk_read_ber,
+       .read_signal_strength = drxk_read_signal_strength,
+       .read_snr = drxk_read_snr,
+       .read_ucblocks = drxk_read_ucblocks,
+};
+
+static struct dvb_frontend_ops drxk_t_ops = {
+       .info = {
+                .name = "DRXK DVB-T",
+                .type = FE_OFDM,
+                .frequency_min = 47125000,
+                .frequency_max = 865000000,
+                .frequency_stepsize = 166667,
+                .frequency_tolerance = 0,
+                .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+                FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+                FE_CAN_FEC_AUTO |
+                FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+                FE_CAN_QAM_AUTO |
+                FE_CAN_TRANSMISSION_MODE_AUTO |
+                FE_CAN_GUARD_INTERVAL_AUTO |
+                FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | FE_CAN_MUTE_TS},
+       .release = drxk_t_release,
+       .init = drxk_t_init,
+       .sleep = drxk_t_sleep,
+       .i2c_gate_ctrl = drxk_gate_ctrl,
+
+       .set_frontend = drxk_set_parameters,
+       .get_frontend = drxk_t_get_frontend,
+
+       .read_status = drxk_read_status,
+       .read_ber = drxk_read_ber,
+       .read_signal_strength = drxk_read_signal_strength,
+       .read_snr = drxk_read_snr,
+       .read_ucblocks = drxk_read_ucblocks,
+};
+
+struct dvb_frontend *drxk_attach(const struct drxk_config *config,
+                                struct i2c_adapter *i2c,
+                                struct dvb_frontend **fe_t)
+{
+       struct drxk_state *state = NULL;
+       u8 adr = config->adr;
+
+       dprintk(1, "\n");
+       state = kzalloc(sizeof(struct drxk_state), GFP_KERNEL);
+       if (!state)
+               return NULL;
+
+       state->i2c = i2c;
+       state->demod_address = adr;
+       state->single_master = config->single_master;
+       state->microcode_name = config->microcode_name;
+       state->no_i2c_bridge = config->no_i2c_bridge;
+       state->antenna_gpio = config->antenna_gpio;
+       state->antenna_dvbt = config->antenna_dvbt;
+
+       /* NOTE: as more UIO bits will be used, add them to the mask */
+       state->UIO_mask = config->antenna_gpio;
+
+       /* Default gpio to DVB-C */
+       if (!state->antenna_dvbt && state->antenna_gpio)
+               state->m_GPIO |= state->antenna_gpio;
+       else
+               state->m_GPIO &= ~state->antenna_gpio;
+
+       mutex_init(&state->mutex);
+       mutex_init(&state->ctlock);
+
+       memcpy(&state->c_frontend.ops, &drxk_c_ops,
+              sizeof(struct dvb_frontend_ops));
+       memcpy(&state->t_frontend.ops, &drxk_t_ops,
+              sizeof(struct dvb_frontend_ops));
+       state->c_frontend.demodulator_priv = state;
+       state->t_frontend.demodulator_priv = state;
+
+       init_state(state);
+       if (init_drxk(state) < 0)
+               goto error;
+       *fe_t = &state->t_frontend;
+
+       return &state->c_frontend;
+
+error:
+       printk(KERN_ERR "drxk: not found\n");
+       kfree(state);
+       return NULL;
+}
+EXPORT_SYMBOL(drxk_attach);
+
+MODULE_DESCRIPTION("DRX-K driver");
+MODULE_AUTHOR("Ralph Metzler");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/drxk_hard.h b/drivers/media/dvb/frontends/drxk_hard.h
new file mode 100644 (file)
index 0000000..a05c32e
--- /dev/null
@@ -0,0 +1,348 @@
+#include "drxk_map.h"
+
+#define DRXK_VERSION_MAJOR 0
+#define DRXK_VERSION_MINOR 9
+#define DRXK_VERSION_PATCH 4300
+
+#define HI_I2C_DELAY        42
+#define HI_I2C_BRIDGE_DELAY 350
+#define DRXK_MAX_RETRIES    100
+
+#define DRIVER_4400 1
+
+#define DRXX_JTAGID   0x039210D9
+#define DRXX_J_JTAGID 0x239310D9
+#define DRXX_K_JTAGID 0x039210D9
+
+#define DRX_UNKNOWN     254
+#define DRX_AUTO        255
+
+#define DRX_SCU_READY   0
+#define DRXK_MAX_WAITTIME (200)
+#define SCU_RESULT_OK      0
+#define SCU_RESULT_SIZE   -4
+#define SCU_RESULT_INVPAR -3
+#define SCU_RESULT_UNKSTD -2
+#define SCU_RESULT_UNKCMD -1
+
+#ifndef DRXK_OFDM_TR_SHUTDOWN_TIMEOUT
+#define DRXK_OFDM_TR_SHUTDOWN_TIMEOUT (200)
+#endif
+
+#define DRXK_8VSB_MPEG_BIT_RATE     19392658UL  /*bps*/
+#define DRXK_DVBT_MPEG_BIT_RATE     32000000UL  /*bps*/
+#define DRXK_QAM16_MPEG_BIT_RATE    27000000UL  /*bps*/
+#define DRXK_QAM32_MPEG_BIT_RATE    33000000UL  /*bps*/
+#define DRXK_QAM64_MPEG_BIT_RATE    40000000UL  /*bps*/
+#define DRXK_QAM128_MPEG_BIT_RATE   46000000UL  /*bps*/
+#define DRXK_QAM256_MPEG_BIT_RATE   52000000UL  /*bps*/
+#define DRXK_MAX_MPEG_BIT_RATE      52000000UL  /*bps*/
+
+#define   IQM_CF_OUT_ENA_OFDM__M                                            0x4
+#define     IQM_FS_ADJ_SEL_B_QAM                                            0x1
+#define     IQM_FS_ADJ_SEL_B_OFF                                            0x0
+#define     IQM_FS_ADJ_SEL_B_VSB                                            0x2
+#define     IQM_RC_ADJ_SEL_B_OFF                                            0x0
+#define     IQM_RC_ADJ_SEL_B_QAM                                            0x1
+#define     IQM_RC_ADJ_SEL_B_VSB                                            0x2
+
+enum OperationMode {
+       OM_NONE,
+       OM_QAM_ITU_A,
+       OM_QAM_ITU_B,
+       OM_QAM_ITU_C,
+       OM_DVBT
+};
+
+enum DRXPowerMode {
+       DRX_POWER_UP = 0,
+       DRX_POWER_MODE_1,
+       DRX_POWER_MODE_2,
+       DRX_POWER_MODE_3,
+       DRX_POWER_MODE_4,
+       DRX_POWER_MODE_5,
+       DRX_POWER_MODE_6,
+       DRX_POWER_MODE_7,
+       DRX_POWER_MODE_8,
+
+       DRX_POWER_MODE_9,
+       DRX_POWER_MODE_10,
+       DRX_POWER_MODE_11,
+       DRX_POWER_MODE_12,
+       DRX_POWER_MODE_13,
+       DRX_POWER_MODE_14,
+       DRX_POWER_MODE_15,
+       DRX_POWER_MODE_16,
+       DRX_POWER_DOWN = 255
+};
+
+
+/** /brief Intermediate power mode for DRXK, power down OFDM clock domain */
+#ifndef DRXK_POWER_DOWN_OFDM
+#define DRXK_POWER_DOWN_OFDM        DRX_POWER_MODE_1
+#endif
+
+/** /brief Intermediate power mode for DRXK, power down core (sysclk) */
+#ifndef DRXK_POWER_DOWN_CORE
+#define DRXK_POWER_DOWN_CORE        DRX_POWER_MODE_9
+#endif
+
+/** /brief Intermediate power mode for DRXK, power down pll (only osc runs) */
+#ifndef DRXK_POWER_DOWN_PLL
+#define DRXK_POWER_DOWN_PLL         DRX_POWER_MODE_10
+#endif
+
+
+enum AGC_CTRL_MODE { DRXK_AGC_CTRL_AUTO = 0, DRXK_AGC_CTRL_USER, DRXK_AGC_CTRL_OFF };
+enum EDrxkState { DRXK_UNINITIALIZED = 0, DRXK_STOPPED, DRXK_DTV_STARTED, DRXK_ATV_STARTED, DRXK_POWERED_DOWN };
+enum EDrxkCoefArrayIndex {
+       DRXK_COEF_IDX_MN = 0,
+       DRXK_COEF_IDX_FM    ,
+       DRXK_COEF_IDX_L     ,
+       DRXK_COEF_IDX_LP    ,
+       DRXK_COEF_IDX_BG    ,
+       DRXK_COEF_IDX_DK    ,
+       DRXK_COEF_IDX_I     ,
+       DRXK_COEF_IDX_MAX
+};
+enum EDrxkSifAttenuation {
+       DRXK_SIF_ATTENUATION_0DB,
+       DRXK_SIF_ATTENUATION_3DB,
+       DRXK_SIF_ATTENUATION_6DB,
+       DRXK_SIF_ATTENUATION_9DB
+};
+enum EDrxkConstellation {
+       DRX_CONSTELLATION_BPSK = 0,
+       DRX_CONSTELLATION_QPSK,
+       DRX_CONSTELLATION_PSK8,
+       DRX_CONSTELLATION_QAM16,
+       DRX_CONSTELLATION_QAM32,
+       DRX_CONSTELLATION_QAM64,
+       DRX_CONSTELLATION_QAM128,
+       DRX_CONSTELLATION_QAM256,
+       DRX_CONSTELLATION_QAM512,
+       DRX_CONSTELLATION_QAM1024,
+       DRX_CONSTELLATION_UNKNOWN = DRX_UNKNOWN,
+       DRX_CONSTELLATION_AUTO    = DRX_AUTO
+};
+enum EDrxkInterleaveMode {
+       DRXK_QAM_I12_J17    = 16,
+       DRXK_QAM_I_UNKNOWN  = DRX_UNKNOWN
+};
+enum {
+       DRXK_SPIN_A1 = 0,
+       DRXK_SPIN_A2,
+       DRXK_SPIN_A3,
+       DRXK_SPIN_UNKNOWN
+};
+
+enum DRXKCfgDvbtSqiSpeed {
+       DRXK_DVBT_SQI_SPEED_FAST = 0,
+       DRXK_DVBT_SQI_SPEED_MEDIUM,
+       DRXK_DVBT_SQI_SPEED_SLOW,
+       DRXK_DVBT_SQI_SPEED_UNKNOWN = DRX_UNKNOWN
+} ;
+
+enum DRXFftmode_t {
+       DRX_FFTMODE_2K = 0,
+       DRX_FFTMODE_4K,
+       DRX_FFTMODE_8K,
+       DRX_FFTMODE_UNKNOWN = DRX_UNKNOWN,
+       DRX_FFTMODE_AUTO    = DRX_AUTO
+};
+
+enum DRXMPEGStrWidth_t {
+       DRX_MPEG_STR_WIDTH_1,
+       DRX_MPEG_STR_WIDTH_8
+};
+
+enum DRXQamLockRange_t {
+       DRX_QAM_LOCKRANGE_NORMAL,
+       DRX_QAM_LOCKRANGE_EXTENDED
+};
+
+struct DRXKCfgDvbtEchoThres_t {
+       u16             threshold;
+       enum DRXFftmode_t      fftMode;
+} ;
+
+struct SCfgAgc {
+       enum AGC_CTRL_MODE     ctrlMode;        /* off, user, auto */
+       u16            outputLevel;     /* range dependent on AGC */
+       u16            minOutputLevel;  /* range dependent on AGC */
+       u16            maxOutputLevel;  /* range dependent on AGC */
+       u16            speed;           /* range dependent on AGC */
+       u16            top;             /* rf-agc take over point */
+       u16            cutOffCurrent;   /* rf-agc is accelerated if output current
+                                          is below cut-off current */
+       u16            IngainTgtMax;
+       u16            FastClipCtrlDelay;
+};
+
+struct SCfgPreSaw {
+       u16        reference; /* pre SAW reference value, range 0 .. 31 */
+       bool          usePreSaw; /* TRUE algorithms must use pre SAW sense */
+};
+
+struct DRXKOfdmScCmd_t {
+       u16 cmd;        /**< Command number */
+       u16 subcmd;     /**< Sub-command parameter*/
+       u16 param0;     /**< General purpous param */
+       u16 param1;     /**< General purpous param */
+       u16 param2;     /**< General purpous param */
+       u16 param3;     /**< General purpous param */
+       u16 param4;     /**< General purpous param */
+};
+
+struct drxk_state {
+       struct dvb_frontend c_frontend;
+       struct dvb_frontend t_frontend;
+       struct dvb_frontend_parameters param;
+       struct device *dev;
+
+       struct i2c_adapter *i2c;
+       u8     demod_address;
+       void  *priv;
+
+       struct mutex mutex;
+       struct mutex ctlock;
+
+       u32    m_Instance;           /**< Channel 1,2,3 or 4 */
+
+       int    m_ChunkSize;
+       u8 Chunk[256];
+
+       bool   m_hasLNA;
+       bool   m_hasDVBT;
+       bool   m_hasDVBC;
+       bool   m_hasAudio;
+       bool   m_hasATV;
+       bool   m_hasOOB;
+       bool   m_hasSAWSW;         /**< TRUE if mat_tx is available */
+       bool   m_hasGPIO1;         /**< TRUE if mat_rx is available */
+       bool   m_hasGPIO2;         /**< TRUE if GPIO is available */
+       bool   m_hasIRQN;          /**< TRUE if IRQN is available */
+       u16    m_oscClockFreq;
+       u16    m_HICfgTimingDiv;
+       u16    m_HICfgBridgeDelay;
+       u16    m_HICfgWakeUpKey;
+       u16    m_HICfgTimeout;
+       u16    m_HICfgCtrl;
+       s32    m_sysClockFreq;      /**< system clock frequency in kHz */
+
+       enum EDrxkState    m_DrxkState;      /**< State of Drxk (init,stopped,started) */
+       enum OperationMode m_OperationMode;  /**< digital standards */
+       struct SCfgAgc     m_vsbRfAgcCfg;    /**< settings for VSB RF-AGC */
+       struct SCfgAgc     m_vsbIfAgcCfg;    /**< settings for VSB IF-AGC */
+       u16                m_vsbPgaCfg;      /**< settings for VSB PGA */
+       struct SCfgPreSaw  m_vsbPreSawCfg;   /**< settings for pre SAW sense */
+       s32    m_Quality83percent;  /**< MER level (*0.1 dB) for 83% quality indication */
+       s32    m_Quality93percent;  /**< MER level (*0.1 dB) for 93% quality indication */
+       bool   m_smartAntInverted;
+       bool   m_bDebugEnableBridge;
+       bool   m_bPDownOpenBridge;  /**< only open DRXK bridge before power-down once it has been accessed */
+       bool   m_bPowerDown;        /**< Power down when not used */
+
+       u32    m_IqmFsRateOfs;      /**< frequency shift as written to DRXK register (28bit fixpoint) */
+
+       bool   m_enableMPEGOutput;  /**< If TRUE, enable MPEG output */
+       bool   m_insertRSByte;      /**< If TRUE, insert RS byte */
+       bool   m_enableParallel;    /**< If TRUE, parallel out otherwise serial */
+       bool   m_invertDATA;        /**< If TRUE, invert DATA signals */
+       bool   m_invertERR;         /**< If TRUE, invert ERR signal */
+       bool   m_invertSTR;         /**< If TRUE, invert STR signals */
+       bool   m_invertVAL;         /**< If TRUE, invert VAL signals */
+       bool   m_invertCLK;         /**< If TRUE, invert CLK signals */
+       bool   m_DVBCStaticCLK;
+       bool   m_DVBTStaticCLK;     /**< If TRUE, static MPEG clockrate will
+                                        be used, otherwise clockrate will
+                                        adapt to the bitrate of the TS */
+       u32    m_DVBTBitrate;
+       u32    m_DVBCBitrate;
+
+       u8     m_TSDataStrength;
+       u8     m_TSClockkStrength;
+
+       enum DRXMPEGStrWidth_t  m_widthSTR;    /**< MPEG start width */
+       u32    m_mpegTsStaticBitrate;          /**< Maximum bitrate in b/s in case
+                                                   static clockrate is selected */
+
+       /* LARGE_INTEGER   m_StartTime; */     /**< Contains the time of the last demod start */
+       s32    m_MpegLockTimeOut;      /**< WaitForLockStatus Timeout (counts from start time) */
+       s32    m_DemodLockTimeOut;     /**< WaitForLockStatus Timeout (counts from start time) */
+
+       bool   m_disableTEIhandling;
+
+       bool   m_RfAgcPol;
+       bool   m_IfAgcPol;
+
+       struct SCfgAgc    m_atvRfAgcCfg;  /**< settings for ATV RF-AGC */
+       struct SCfgAgc    m_atvIfAgcCfg;  /**< settings for ATV IF-AGC */
+       struct SCfgPreSaw m_atvPreSawCfg; /**< settings for ATV pre SAW sense */
+       bool              m_phaseCorrectionBypass;
+       s16               m_atvTopVidPeak;
+       u16               m_atvTopNoiseTh;
+       enum EDrxkSifAttenuation m_sifAttenuation;
+       bool              m_enableCVBSOutput;
+       bool              m_enableSIFOutput;
+       bool              m_bMirrorFreqSpect;
+       enum EDrxkConstellation  m_Constellation; /**< Constellation type of the channel */
+       u32               m_CurrSymbolRate;       /**< Current QAM symbol rate */
+       struct SCfgAgc    m_qamRfAgcCfg;          /**< settings for QAM RF-AGC */
+       struct SCfgAgc    m_qamIfAgcCfg;          /**< settings for QAM IF-AGC */
+       u16               m_qamPgaCfg;            /**< settings for QAM PGA */
+       struct SCfgPreSaw m_qamPreSawCfg;         /**< settings for QAM pre SAW sense */
+       enum EDrxkInterleaveMode m_qamInterleaveMode; /**< QAM Interleave mode */
+       u16               m_fecRsPlen;
+       u16               m_fecRsPrescale;
+
+       enum DRXKCfgDvbtSqiSpeed m_sqiSpeed;
+
+       u16               m_GPIO;
+       u16               m_GPIOCfg;
+
+       struct SCfgAgc    m_dvbtRfAgcCfg;     /**< settings for QAM RF-AGC */
+       struct SCfgAgc    m_dvbtIfAgcCfg;     /**< settings for QAM IF-AGC */
+       struct SCfgPreSaw m_dvbtPreSawCfg;    /**< settings for QAM pre SAW sense */
+
+       u16               m_agcFastClipCtrlDelay;
+       bool              m_adcCompPassed;
+       u16               m_adcCompCoef[64];
+       u16               m_adcState;
+
+       u8               *m_microcode;
+       int               m_microcode_length;
+       bool              m_DRXK_A1_PATCH_CODE;
+       bool              m_DRXK_A1_ROM_CODE;
+       bool              m_DRXK_A2_ROM_CODE;
+       bool              m_DRXK_A3_ROM_CODE;
+       bool              m_DRXK_A2_PATCH_CODE;
+       bool              m_DRXK_A3_PATCH_CODE;
+
+       bool              m_rfmirror;
+       u8                m_deviceSpin;
+       u32               m_iqmRcRate;
+
+       enum DRXPowerMode m_currentPowerMode;
+
+       /*
+        * Configurable parameters at the driver. They stores the values found
+        * at struct drxk_config.
+        */
+
+       u16     UIO_mask;       /* Bits used by UIO */
+
+       bool    single_master;
+       bool    no_i2c_bridge;
+       bool    antenna_dvbt;
+       u16     antenna_gpio;
+
+       const char *microcode_name;
+};
+
+#define NEVER_LOCK 0
+#define NOT_LOCKED 1
+#define DEMOD_LOCK 2
+#define FEC_LOCK   3
+#define MPEG_LOCK  4
+
diff --git a/drivers/media/dvb/frontends/drxk_map.h b/drivers/media/dvb/frontends/drxk_map.h
new file mode 100644 (file)
index 0000000..9b11a83
--- /dev/null
@@ -0,0 +1,449 @@
+#define  AUD_COMM_EXEC__A                                                  0x1000000
+#define    AUD_COMM_EXEC_STOP                                              0x0
+#define  FEC_COMM_EXEC__A                                                  0x1C00000
+#define    FEC_COMM_EXEC_STOP                                              0x0
+#define    FEC_COMM_EXEC_ACTIVE                                            0x1
+#define  FEC_DI_COMM_EXEC__A                                               0x1C20000
+#define    FEC_DI_COMM_EXEC_STOP                                           0x0
+#define  FEC_DI_INPUT_CTL__A                                               0x1C20016
+#define  FEC_RS_COMM_EXEC__A                                               0x1C30000
+#define    FEC_RS_COMM_EXEC_STOP                                           0x0
+#define  FEC_RS_MEASUREMENT_PERIOD__A                                      0x1C30012
+#define  FEC_RS_MEASUREMENT_PRESCALE__A                                    0x1C30013
+#define  FEC_OC_MODE__A                                                    0x1C40011
+#define    FEC_OC_MODE_PARITY__M                                           0x1
+#define  FEC_OC_DTO_MODE__A                                                0x1C40014
+#define    FEC_OC_DTO_MODE_DYNAMIC__M                                      0x1
+#define    FEC_OC_DTO_MODE_OFFSET_ENABLE__M                                0x4
+#define  FEC_OC_DTO_PERIOD__A                                              0x1C40015
+#define  FEC_OC_DTO_BURST_LEN__A                                           0x1C40018
+#define  FEC_OC_FCT_MODE__A                                                0x1C4001A
+#define  FEC_OC_FCT_MODE__PRE                                              0x0
+#define    FEC_OC_FCT_MODE_RAT_ENA__M                                      0x1
+#define    FEC_OC_FCT_MODE_VIRT_ENA__M                                     0x2
+#define  FEC_OC_TMD_MODE__A                                                0x1C4001E
+#define  FEC_OC_TMD_COUNT__A                                               0x1C4001F
+#define  FEC_OC_TMD_HI_MARGIN__A                                           0x1C40020
+#define  FEC_OC_TMD_LO_MARGIN__A                                           0x1C40021
+#define  FEC_OC_TMD_INT_UPD_RATE__A                                        0x1C40023
+#define  FEC_OC_AVR_PARM_A__A                                              0x1C40026
+#define  FEC_OC_AVR_PARM_B__A                                              0x1C40027
+#define  FEC_OC_RCN_GAIN__A                                                0x1C4002E
+#define  FEC_OC_RCN_CTL_RATE_LO__A                                         0x1C40030
+#define  FEC_OC_RCN_CTL_STEP_LO__A                                         0x1C40032
+#define  FEC_OC_RCN_CTL_STEP_HI__A                                         0x1C40033
+#define  FEC_OC_SNC_MODE__A                                                0x1C40040
+#define    FEC_OC_SNC_MODE_SHUTDOWN__M                                     0x10
+#define  FEC_OC_SNC_LWM__A                                                 0x1C40041
+#define  FEC_OC_SNC_HWM__A                                                 0x1C40042
+#define  FEC_OC_SNC_UNLOCK__A                                              0x1C40043
+#define  FEC_OC_SNC_FAIL_PERIOD__A                                         0x1C40046
+#define  FEC_OC_IPR_MODE__A                                                0x1C40048
+#define    FEC_OC_IPR_MODE_SERIAL__M                                       0x1
+#define    FEC_OC_IPR_MODE_MCLK_DIS_DAT_ABS__M                             0x4
+#define    FEC_OC_IPR_MODE_MVAL_DIS_PAR__M                                 0x10
+#define  FEC_OC_IPR_INVERT__A                                              0x1C40049
+#define    FEC_OC_IPR_INVERT_MD0__M                                        0x1
+#define    FEC_OC_IPR_INVERT_MD1__M                                        0x2
+#define    FEC_OC_IPR_INVERT_MD2__M                                        0x4
+#define    FEC_OC_IPR_INVERT_MD3__M                                        0x8
+#define    FEC_OC_IPR_INVERT_MD4__M                                        0x10
+#define    FEC_OC_IPR_INVERT_MD5__M                                        0x20
+#define    FEC_OC_IPR_INVERT_MD6__M                                        0x40
+#define    FEC_OC_IPR_INVERT_MD7__M                                        0x80
+#define    FEC_OC_IPR_INVERT_MERR__M                                       0x100
+#define    FEC_OC_IPR_INVERT_MSTRT__M                                      0x200
+#define    FEC_OC_IPR_INVERT_MVAL__M                                       0x400
+#define    FEC_OC_IPR_INVERT_MCLK__M                                       0x800
+#define  FEC_OC_OCR_INVERT__A                                              0x1C40052
+#define  IQM_COMM_EXEC__A                                                  0x1800000
+#define      IQM_COMM_EXEC_B_STOP                                          0x0
+#define      IQM_COMM_EXEC_B_ACTIVE                                        0x1
+#define  IQM_FS_RATE_OFS_LO__A                                             0x1820010
+#define  IQM_FS_ADJ_SEL__A                                                 0x1820014
+#define      IQM_FS_ADJ_SEL_B_OFF                                          0x0
+#define      IQM_FS_ADJ_SEL_B_QAM                                          0x1
+#define      IQM_FS_ADJ_SEL_B_VSB                                          0x2
+#define  IQM_FD_RATESEL__A                                                 0x1830010
+#define  IQM_RC_RATE_OFS_LO__A                                             0x1840010
+#define  IQM_RC_RATE_OFS_LO__W                                             16
+#define  IQM_RC_RATE_OFS_LO__M                                             0xFFFF
+#define  IQM_RC_RATE_OFS_HI__M                                             0xFF
+#define  IQM_RC_ADJ_SEL__A                                                 0x1840014
+#define      IQM_RC_ADJ_SEL_B_OFF                                          0x0
+#define      IQM_RC_ADJ_SEL_B_QAM                                          0x1
+#define      IQM_RC_ADJ_SEL_B_VSB                                          0x2
+#define  IQM_RC_STRETCH__A                                                 0x1840016
+#define  IQM_CF_COMM_INT_MSK__A                                            0x1860006
+#define  IQM_CF_SYMMETRIC__A                                               0x1860010
+#define  IQM_CF_MIDTAP__A                                                  0x1860011
+#define    IQM_CF_MIDTAP_RE__B                                             0
+#define    IQM_CF_MIDTAP_IM__B                                             1
+#define  IQM_CF_OUT_ENA__A                                                 0x1860012
+#define    IQM_CF_OUT_ENA_QAM__B                                           1
+#define    IQM_CF_OUT_ENA_OFDM__M                                          0x4
+#define  IQM_CF_ADJ_SEL__A                                                 0x1860013
+#define  IQM_CF_SCALE__A                                                   0x1860014
+#define  IQM_CF_SCALE_SH__A                                                0x1860015
+#define  IQM_CF_SCALE_SH__PRE                                              0x0
+#define  IQM_CF_POW_MEAS_LEN__A                                            0x1860017
+#define  IQM_CF_DS_ENA__A                                                  0x1860019
+#define  IQM_CF_TAP_RE0__A                                                 0x1860020
+#define  IQM_CF_TAP_IM0__A                                                 0x1860040
+#define  IQM_CF_CLP_VAL__A                                                 0x1860060
+#define  IQM_CF_DATATH__A                                                  0x1860061
+#define  IQM_CF_PKDTH__A                                                   0x1860062
+#define  IQM_CF_WND_LEN__A                                                 0x1860063
+#define  IQM_CF_DET_LCT__A                                                 0x1860064
+#define  IQM_CF_BYPASSDET__A                                               0x1860067
+#define  IQM_AF_COMM_EXEC__A                                               0x1870000
+#define    IQM_AF_COMM_EXEC_ACTIVE                                         0x1
+#define  IQM_AF_CLKNEG__A                                                  0x1870012
+#define    IQM_AF_CLKNEG_CLKNEGDATA__M                                     0x2
+#define      IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_POS                     0x0
+#define      IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_NEG                     0x2
+#define  IQM_AF_START_LOCK__A                                              0x187001B
+#define  IQM_AF_PHASE0__A                                                  0x187001C
+#define  IQM_AF_PHASE1__A                                                  0x187001D
+#define  IQM_AF_PHASE2__A                                                  0x187001E
+#define  IQM_AF_CLP_LEN__A                                                 0x1870023
+#define  IQM_AF_CLP_TH__A                                                  0x1870024
+#define  IQM_AF_SNS_LEN__A                                                 0x1870026
+#define  IQM_AF_AGC_IF__A                                                  0x1870028
+#define  IQM_AF_AGC_RF__A                                                  0x1870029
+#define  IQM_AF_PDREF__A                                                   0x187002B
+#define  IQM_AF_PDREF__M                                                   0x1F
+#define  IQM_AF_STDBY__A                                                   0x187002C
+#define      IQM_AF_STDBY_STDBY_ADC_STANDBY                                0x2
+#define      IQM_AF_STDBY_STDBY_AMP_STANDBY                                0x4
+#define      IQM_AF_STDBY_STDBY_PD_STANDBY                                 0x8
+#define      IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY                            0x10
+#define      IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY                            0x20
+#define  IQM_AF_AMUX__A                                                    0x187002D
+#define    IQM_AF_AMUX_SIGNAL2ADC                                          0x1
+#define  IQM_AF_UPD_SEL__A                                                 0x187002F
+#define  IQM_AF_INC_LCT__A                                                 0x1870034
+#define  IQM_AF_INC_BYPASS__A                                              0x1870036
+#define  OFDM_CP_COMM_EXEC__A                                              0x2800000
+#define    OFDM_CP_COMM_EXEC_STOP                                          0x0
+#define  OFDM_EC_SB_PRIOR__A                                               0x3410013
+#define    OFDM_EC_SB_PRIOR_HI                                             0x0
+#define    OFDM_EC_SB_PRIOR_LO                                             0x1
+#define  OFDM_EQ_TOP_TD_TPS_CONST__A                                       0x3010054
+#define  OFDM_EQ_TOP_TD_TPS_CONST__M                                       0x3
+#define    OFDM_EQ_TOP_TD_TPS_CONST_64QAM                                  0x2
+#define  OFDM_EQ_TOP_TD_TPS_CODE_HP__A                                     0x3010056
+#define  OFDM_EQ_TOP_TD_TPS_CODE_HP__M                                     0x7
+#define    OFDM_EQ_TOP_TD_TPS_CODE_LP_7_8                                  0x4
+#define  OFDM_EQ_TOP_TD_SQR_ERR_I__A                                       0x301005E
+#define  OFDM_EQ_TOP_TD_SQR_ERR_Q__A                                       0x301005F
+#define  OFDM_EQ_TOP_TD_SQR_ERR_EXP__A                                     0x3010060
+#define  OFDM_EQ_TOP_TD_REQ_SMB_CNT__A                                     0x3010061
+#define  OFDM_EQ_TOP_TD_TPS_PWR_OFS__A                                     0x3010062
+#define  OFDM_LC_COMM_EXEC__A                                              0x3800000
+#define    OFDM_LC_COMM_EXEC_STOP                                          0x0
+#define  OFDM_SC_COMM_EXEC__A                                              0x3C00000
+#define    OFDM_SC_COMM_EXEC_STOP                                          0x0
+#define  OFDM_SC_COMM_STATE__A                                             0x3C00001
+#define  OFDM_SC_RA_RAM_PARAM0__A                                          0x3C20040
+#define  OFDM_SC_RA_RAM_PARAM1__A                                          0x3C20041
+#define  OFDM_SC_RA_RAM_CMD_ADDR__A                                        0x3C20042
+#define  OFDM_SC_RA_RAM_CMD__A                                             0x3C20043
+#define    OFDM_SC_RA_RAM_CMD_NULL                                         0x0
+#define    OFDM_SC_RA_RAM_CMD_PROC_START                                   0x1
+#define    OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM                               0x3
+#define    OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM                                0x4
+#define    OFDM_SC_RA_RAM_CMD_GET_OP_PARAM                                 0x5
+#define    OFDM_SC_RA_RAM_CMD_USER_IO                                      0x6
+#define    OFDM_SC_RA_RAM_CMD_SET_TIMER                                    0x7
+#define    OFDM_SC_RA_RAM_CMD_SET_ECHO_TIMING                              0x8
+#define    OFDM_SC_RA_RAM_SW_EVENT_RUN_NMASK__M                            0x1
+#define    OFDM_SC_RA_RAM_LOCKTRACK_MIN                                    0x1
+#define  OFDM_SC_RA_RAM_OP_PARAM__A                                        0x3C20048
+#define    OFDM_SC_RA_RAM_OP_PARAM_MODE__M                                 0x3
+#define      OFDM_SC_RA_RAM_OP_PARAM_MODE_2K                               0x0
+#define      OFDM_SC_RA_RAM_OP_PARAM_MODE_8K                               0x1
+#define      OFDM_SC_RA_RAM_OP_PARAM_GUARD_32                              0x0
+#define      OFDM_SC_RA_RAM_OP_PARAM_GUARD_16                              0x4
+#define      OFDM_SC_RA_RAM_OP_PARAM_GUARD_8                               0x8
+#define      OFDM_SC_RA_RAM_OP_PARAM_GUARD_4                               0xC
+#define      OFDM_SC_RA_RAM_OP_PARAM_CONST_QPSK                            0x0
+#define      OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM16                           0x10
+#define      OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM64                           0x20
+#define      OFDM_SC_RA_RAM_OP_PARAM_HIER_NO                               0x0
+#define      OFDM_SC_RA_RAM_OP_PARAM_HIER_A1                               0x40
+#define      OFDM_SC_RA_RAM_OP_PARAM_HIER_A2                               0x80
+#define      OFDM_SC_RA_RAM_OP_PARAM_HIER_A4                               0xC0
+#define      OFDM_SC_RA_RAM_OP_PARAM_RATE_1_2                              0x0
+#define      OFDM_SC_RA_RAM_OP_PARAM_RATE_2_3                              0x200
+#define      OFDM_SC_RA_RAM_OP_PARAM_RATE_3_4                              0x400
+#define      OFDM_SC_RA_RAM_OP_PARAM_RATE_5_6                              0x600
+#define      OFDM_SC_RA_RAM_OP_PARAM_RATE_7_8                              0x800
+#define      OFDM_SC_RA_RAM_OP_PARAM_PRIO_HI                               0x0
+#define      OFDM_SC_RA_RAM_OP_PARAM_PRIO_LO                               0x1000
+#define    OFDM_SC_RA_RAM_OP_AUTO_MODE__M                                  0x1
+#define    OFDM_SC_RA_RAM_OP_AUTO_GUARD__M                                 0x2
+#define    OFDM_SC_RA_RAM_OP_AUTO_CONST__M                                 0x4
+#define    OFDM_SC_RA_RAM_OP_AUTO_HIER__M                                  0x8
+#define    OFDM_SC_RA_RAM_OP_AUTO_RATE__M                                  0x10
+#define  OFDM_SC_RA_RAM_LOCK__A                                            0x3C2004B
+#define    OFDM_SC_RA_RAM_LOCK_DEMOD__M                                    0x1
+#define    OFDM_SC_RA_RAM_LOCK_FEC__M                                      0x2
+#define    OFDM_SC_RA_RAM_LOCK_MPEG__M                                     0x4
+#define    OFDM_SC_RA_RAM_LOCK_NODVBT__M                                   0x8
+#define  OFDM_SC_RA_RAM_BE_OPT_DELAY__A                                    0x3C2004D
+#define  OFDM_SC_RA_RAM_BE_OPT_INIT_DELAY__A                               0x3C2004E
+#define  OFDM_SC_RA_RAM_ECHO_THRES__A                                      0x3C2004F
+#define    OFDM_SC_RA_RAM_ECHO_THRES_8K__B                                 0
+#define    OFDM_SC_RA_RAM_ECHO_THRES_8K__M                                 0xFF
+#define    OFDM_SC_RA_RAM_ECHO_THRES_2K__B                                 8
+#define    OFDM_SC_RA_RAM_ECHO_THRES_2K__M                                 0xFF00
+#define  OFDM_SC_RA_RAM_CONFIG__A                                          0x3C20050
+#define    OFDM_SC_RA_RAM_CONFIG_NE_FIX_ENABLE__M                          0x800
+#define  OFDM_SC_RA_RAM_FR_THRES_8K__A                                     0x3C2007D
+#define  OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A                             0x3C200E0
+#define  OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A                            0x3C200E1
+#define  OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A                             0x3C200E3
+#define  OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A                            0x3C200E4
+#define  OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A                                0x3C200F8
+#define  QAM_COMM_EXEC__A                                                  0x1400000
+#define    QAM_COMM_EXEC_STOP                                              0x0
+#define    QAM_COMM_EXEC_ACTIVE                                            0x1
+#define    QAM_TOP_ANNEX_A                                                 0x0
+#define    QAM_TOP_ANNEX_C                                                 0x2
+#define  QAM_SL_ERR_POWER__A                                               0x1430017
+#define  QAM_DQ_QUAL_FUN0__A                                               0x1440018
+#define  QAM_DQ_QUAL_FUN1__A                                               0x1440019
+#define  QAM_DQ_QUAL_FUN2__A                                               0x144001A
+#define  QAM_DQ_QUAL_FUN3__A                                               0x144001B
+#define  QAM_DQ_QUAL_FUN4__A                                               0x144001C
+#define  QAM_DQ_QUAL_FUN5__A                                               0x144001D
+#define  QAM_LC_MODE__A                                                    0x1450010
+#define  QAM_LC_QUAL_TAB0__A                                               0x1450018
+#define  QAM_LC_QUAL_TAB1__A                                               0x1450019
+#define  QAM_LC_QUAL_TAB2__A                                               0x145001A
+#define  QAM_LC_QUAL_TAB3__A                                               0x145001B
+#define  QAM_LC_QUAL_TAB4__A                                               0x145001C
+#define  QAM_LC_QUAL_TAB5__A                                               0x145001D
+#define  QAM_LC_QUAL_TAB6__A                                               0x145001E
+#define  QAM_LC_QUAL_TAB8__A                                               0x145001F
+#define  QAM_LC_QUAL_TAB9__A                                               0x1450020
+#define  QAM_LC_QUAL_TAB10__A                                              0x1450021
+#define  QAM_LC_QUAL_TAB12__A                                              0x1450022
+#define  QAM_LC_QUAL_TAB15__A                                              0x1450023
+#define  QAM_LC_QUAL_TAB16__A                                              0x1450024
+#define  QAM_LC_QUAL_TAB20__A                                              0x1450025
+#define  QAM_LC_QUAL_TAB25__A                                              0x1450026
+#define  QAM_LC_LPF_FACTORP__A                                             0x1450028
+#define  QAM_LC_LPF_FACTORI__A                                             0x1450029
+#define  QAM_LC_RATE_LIMIT__A                                              0x145002A
+#define  QAM_LC_SYMBOL_FREQ__A                                             0x145002B
+#define  QAM_SY_TIMEOUT__A                                                 0x1470011
+#define  QAM_SY_TIMEOUT__PRE                                               0x3A98
+#define  QAM_SY_SYNC_LWM__A                                                0x1470012
+#define  QAM_SY_SYNC_AWM__A                                                0x1470013
+#define  QAM_SY_SYNC_HWM__A                                                0x1470014
+#define  QAM_SY_SP_INV__A                                                  0x1470017
+#define    QAM_SY_SP_INV_SPECTRUM_INV_DIS                                  0x0
+#define  SCU_COMM_EXEC__A                                                  0x800000
+#define    SCU_COMM_EXEC_STOP                                              0x0
+#define    SCU_COMM_EXEC_ACTIVE                                            0x1
+#define    SCU_COMM_EXEC_HOLD                                              0x2
+#define  SCU_RAM_DRIVER_DEBUG__A                                           0x831EBF
+#define  SCU_RAM_QAM_FSM_STEP_PERIOD__A                                    0x831EC4
+#define  SCU_RAM_GPIO__A                                                   0x831EC7
+#define      SCU_RAM_GPIO_HW_LOCK_IND_DISABLE                              0x0
+#define  SCU_RAM_AGC_CLP_CTRL_MODE__A                                      0x831EC8
+#define  SCU_RAM_FEC_ACCUM_PKT_FAILURES__A                                 0x831ECB
+#define  SCU_RAM_FEC_PRE_RS_BER_FILTER_SH__A                               0x831F05
+#define  SCU_RAM_AGC_FAST_SNS_CTRL_DELAY__A                                0x831F15
+#define  SCU_RAM_AGC_KI_CYCLEN__A                                          0x831F17
+#define  SCU_RAM_AGC_SNS_CYCLEN__A                                         0x831F18
+#define  SCU_RAM_AGC_RF_SNS_DEV_MAX__A                                     0x831F19
+#define  SCU_RAM_AGC_RF_SNS_DEV_MIN__A                                     0x831F1A
+#define  SCU_RAM_AGC_RF_MAX__A                                             0x831F1B
+#define  SCU_RAM_AGC_CONFIG__A                                             0x831F24
+#define    SCU_RAM_AGC_CONFIG_DISABLE_RF_AGC__M                            0x1
+#define    SCU_RAM_AGC_CONFIG_DISABLE_IF_AGC__M                            0x2
+#define    SCU_RAM_AGC_CONFIG_INV_IF_POL__M                                0x100
+#define    SCU_RAM_AGC_CONFIG_INV_RF_POL__M                                0x200
+#define  SCU_RAM_AGC_KI__A                                                 0x831F25
+#define    SCU_RAM_AGC_KI_RF__B                                            4
+#define    SCU_RAM_AGC_KI_RF__M                                            0xF0
+#define    SCU_RAM_AGC_KI_IF__B                                            8
+#define    SCU_RAM_AGC_KI_IF__M                                            0xF00
+#define  SCU_RAM_AGC_KI_RED__A                                             0x831F26
+#define    SCU_RAM_AGC_KI_RED_RAGC_RED__B                                  2
+#define    SCU_RAM_AGC_KI_RED_RAGC_RED__M                                  0xC
+#define    SCU_RAM_AGC_KI_RED_IAGC_RED__B                                  4
+#define    SCU_RAM_AGC_KI_RED_IAGC_RED__M                                  0x30
+#define  SCU_RAM_AGC_KI_INNERGAIN_MIN__A                                   0x831F27
+#define  SCU_RAM_AGC_KI_MINGAIN__A                                         0x831F28
+#define  SCU_RAM_AGC_KI_MAXGAIN__A                                         0x831F29
+#define  SCU_RAM_AGC_KI_MAXMINGAIN_TH__A                                   0x831F2A
+#define  SCU_RAM_AGC_KI_MIN__A                                             0x831F2B
+#define  SCU_RAM_AGC_KI_MAX__A                                             0x831F2C
+#define  SCU_RAM_AGC_CLP_SUM__A                                            0x831F2D
+#define  SCU_RAM_AGC_CLP_SUM_MIN__A                                        0x831F2E
+#define  SCU_RAM_AGC_CLP_SUM_MAX__A                                        0x831F2F
+#define  SCU_RAM_AGC_CLP_CYCLEN__A                                         0x831F30
+#define  SCU_RAM_AGC_CLP_CYCCNT__A                                         0x831F31
+#define  SCU_RAM_AGC_CLP_DIR_TO__A                                         0x831F32
+#define  SCU_RAM_AGC_CLP_DIR_WD__A                                         0x831F33
+#define  SCU_RAM_AGC_CLP_DIR_STP__A                                        0x831F34
+#define  SCU_RAM_AGC_SNS_SUM__A                                            0x831F35
+#define  SCU_RAM_AGC_SNS_SUM_MIN__A                                        0x831F36
+#define  SCU_RAM_AGC_SNS_SUM_MAX__A                                        0x831F37
+#define  SCU_RAM_AGC_SNS_CYCCNT__A                                         0x831F38
+#define  SCU_RAM_AGC_SNS_DIR_TO__A                                         0x831F39
+#define  SCU_RAM_AGC_SNS_DIR_WD__A                                         0x831F3A
+#define  SCU_RAM_AGC_SNS_DIR_STP__A                                        0x831F3B
+#define  SCU_RAM_AGC_INGAIN_TGT__A                                         0x831F3D
+#define  SCU_RAM_AGC_INGAIN_TGT_MIN__A                                     0x831F3E
+#define  SCU_RAM_AGC_INGAIN_TGT_MAX__A                                     0x831F3F
+#define  SCU_RAM_AGC_IF_IACCU_HI__A                                        0x831F40
+#define  SCU_RAM_AGC_IF_IACCU_LO__A                                        0x831F41
+#define  SCU_RAM_AGC_IF_IACCU_HI_TGT__A                                    0x831F42
+#define  SCU_RAM_AGC_IF_IACCU_HI_TGT_MIN__A                                0x831F43
+#define  SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A                                0x831F44
+#define  SCU_RAM_AGC_RF_IACCU_HI__A                                        0x831F45
+#define  SCU_RAM_AGC_RF_IACCU_LO__A                                        0x831F46
+#define  SCU_RAM_AGC_RF_IACCU_HI_CO__A                                     0x831F47
+#define  SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A                                 0x831F84
+#define  SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A                                0x831F85
+#define  SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A                                  0x831F86
+#define  SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A                                  0x831F87
+#define  SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A                                  0x831F88
+#define  SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A                                  0x831F89
+#define  SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A                                  0x831F8A
+#define  SCU_RAM_QAM_FSM_RTH__A                                            0x831F8E
+#define  SCU_RAM_QAM_FSM_FTH__A                                            0x831F8F
+#define  SCU_RAM_QAM_FSM_PTH__A                                            0x831F90
+#define  SCU_RAM_QAM_FSM_MTH__A                                            0x831F91
+#define  SCU_RAM_QAM_FSM_CTH__A                                            0x831F92
+#define  SCU_RAM_QAM_FSM_QTH__A                                            0x831F93
+#define  SCU_RAM_QAM_FSM_RATE_LIM__A                                       0x831F94
+#define  SCU_RAM_QAM_FSM_FREQ_LIM__A                                       0x831F95
+#define  SCU_RAM_QAM_FSM_COUNT_LIM__A                                      0x831F96
+#define  SCU_RAM_QAM_LC_CA_COARSE__A                                       0x831F97
+#define  SCU_RAM_QAM_LC_CA_FINE__A                                         0x831F99
+#define  SCU_RAM_QAM_LC_CP_COARSE__A                                       0x831F9A
+#define  SCU_RAM_QAM_LC_CP_MEDIUM__A                                       0x831F9B
+#define  SCU_RAM_QAM_LC_CP_FINE__A                                         0x831F9C
+#define  SCU_RAM_QAM_LC_CI_COARSE__A                                       0x831F9D
+#define  SCU_RAM_QAM_LC_CI_MEDIUM__A                                       0x831F9E
+#define  SCU_RAM_QAM_LC_CI_FINE__A                                         0x831F9F
+#define  SCU_RAM_QAM_LC_EP_COARSE__A                                       0x831FA0
+#define  SCU_RAM_QAM_LC_EP_MEDIUM__A                                       0x831FA1
+#define  SCU_RAM_QAM_LC_EP_FINE__A                                         0x831FA2
+#define  SCU_RAM_QAM_LC_EI_COARSE__A                                       0x831FA3
+#define  SCU_RAM_QAM_LC_EI_MEDIUM__A                                       0x831FA4
+#define  SCU_RAM_QAM_LC_EI_FINE__A                                         0x831FA5
+#define  SCU_RAM_QAM_LC_CF_COARSE__A                                       0x831FA6
+#define  SCU_RAM_QAM_LC_CF_MEDIUM__A                                       0x831FA7
+#define  SCU_RAM_QAM_LC_CF_FINE__A                                         0x831FA8
+#define  SCU_RAM_QAM_LC_CF1_COARSE__A                                      0x831FA9
+#define  SCU_RAM_QAM_LC_CF1_MEDIUM__A                                      0x831FAA
+#define  SCU_RAM_QAM_LC_CF1_FINE__A                                        0x831FAB
+#define  SCU_RAM_QAM_SL_SIG_POWER__A                                       0x831FAC
+#define  SCU_RAM_QAM_EQ_CMA_RAD0__A                                        0x831FAD
+#define  SCU_RAM_QAM_EQ_CMA_RAD1__A                                        0x831FAE
+#define  SCU_RAM_QAM_EQ_CMA_RAD2__A                                        0x831FAF
+#define  SCU_RAM_QAM_EQ_CMA_RAD3__A                                        0x831FB0
+#define  SCU_RAM_QAM_EQ_CMA_RAD4__A                                        0x831FB1
+#define  SCU_RAM_QAM_EQ_CMA_RAD5__A                                        0x831FB2
+#define      SCU_RAM_QAM_LOCKED_LOCKED_DEMOD_LOCKED                        0x4000
+#define      SCU_RAM_QAM_LOCKED_LOCKED_LOCKED                              0x8000
+#define      SCU_RAM_QAM_LOCKED_LOCKED_NEVER_LOCK                          0xC000
+#define  SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__A                                0x831FEA
+#define  SCU_RAM_DRIVER_VER_HI__A                                          0x831FEB
+#define  SCU_RAM_DRIVER_VER_LO__A                                          0x831FEC
+#define  SCU_RAM_PARAM_15__A                                               0x831FED
+#define  SCU_RAM_PARAM_0__A                                                0x831FFC
+#define  SCU_RAM_COMMAND__A                                                0x831FFD
+#define    SCU_RAM_COMMAND_CMD_DEMOD_RESET                                 0x1
+#define    SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV                               0x2
+#define    SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM                             0x3
+#define    SCU_RAM_COMMAND_CMD_DEMOD_START                                 0x4
+#define    SCU_RAM_COMMAND_CMD_DEMOD_GET_LOCK                              0x5
+#define    SCU_RAM_COMMAND_CMD_DEMOD_STOP                                  0x9
+#define      SCU_RAM_COMMAND_STANDARD_QAM                                  0x200
+#define      SCU_RAM_COMMAND_STANDARD_OFDM                                 0x400
+#define  SIO_TOP_COMM_KEY__A                                               0x41000F
+#define    SIO_TOP_COMM_KEY_KEY                                            0xFABA
+#define  SIO_TOP_JTAGID_LO__A                                              0x410012
+#define  SIO_HI_RA_RAM_RES__A                                              0x420031
+#define  SIO_HI_RA_RAM_CMD__A                                              0x420032
+#define    SIO_HI_RA_RAM_CMD_RESET                                         0x2
+#define    SIO_HI_RA_RAM_CMD_CONFIG                                        0x3
+#define    SIO_HI_RA_RAM_CMD_BRDCTRL                                       0x7
+#define  SIO_HI_RA_RAM_PAR_1__A                                            0x420033
+#define      SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY                              0x3945
+#define  SIO_HI_RA_RAM_PAR_2__A                                            0x420034
+#define    SIO_HI_RA_RAM_PAR_2_CFG_DIV__M                                  0x7F
+#define      SIO_HI_RA_RAM_PAR_2_BRD_CFG_OPEN                              0x0
+#define      SIO_HI_RA_RAM_PAR_2_BRD_CFG_CLOSED                            0x4
+#define  SIO_HI_RA_RAM_PAR_3__A                                            0x420035
+#define    SIO_HI_RA_RAM_PAR_3_CFG_DBL_SDA__M                              0x7F
+#define    SIO_HI_RA_RAM_PAR_3_CFG_DBL_SCL__B                              7
+#define      SIO_HI_RA_RAM_PAR_3_ACP_RW_READ                               0x0
+#define      SIO_HI_RA_RAM_PAR_3_ACP_RW_WRITE                              0x8
+#define  SIO_HI_RA_RAM_PAR_4__A                                            0x420036
+#define  SIO_HI_RA_RAM_PAR_5__A                                            0x420037
+#define      SIO_HI_RA_RAM_PAR_5_CFG_SLV0_SLAVE                            0x1
+#define    SIO_HI_RA_RAM_PAR_5_CFG_SLEEP__M                                0x8
+#define      SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ                             0x8
+#define  SIO_HI_RA_RAM_PAR_6__A                                            0x420038
+#define  SIO_CC_PLL_LOCK__A                                                0x450012
+#define  SIO_CC_PWD_MODE__A                                                0x450015
+#define      SIO_CC_PWD_MODE_LEVEL_NONE                                    0x0
+#define      SIO_CC_PWD_MODE_LEVEL_OFDM                                    0x1
+#define      SIO_CC_PWD_MODE_LEVEL_CLOCK                                   0x2
+#define      SIO_CC_PWD_MODE_LEVEL_PLL                                     0x3
+#define      SIO_CC_PWD_MODE_LEVEL_OSC                                     0x4
+#define  SIO_CC_SOFT_RST__A                                                0x450016
+#define    SIO_CC_SOFT_RST_OFDM__M                                         0x1
+#define    SIO_CC_SOFT_RST_SYS__M                                          0x2
+#define    SIO_CC_SOFT_RST_OSC__M                                          0x4
+#define  SIO_CC_UPDATE__A                                                  0x450017
+#define    SIO_CC_UPDATE_KEY                                               0xFABA
+#define  SIO_OFDM_SH_OFDM_RING_ENABLE__A                                   0x470010
+#define    SIO_OFDM_SH_OFDM_RING_ENABLE_OFF                                0x0
+#define    SIO_OFDM_SH_OFDM_RING_ENABLE_ON                                 0x1
+#define  SIO_OFDM_SH_OFDM_RING_STATUS__A                                   0x470012
+#define    SIO_OFDM_SH_OFDM_RING_STATUS_DOWN                               0x0
+#define    SIO_OFDM_SH_OFDM_RING_STATUS_ENABLED                            0x1
+#define  SIO_BL_COMM_EXEC__A                                               0x480000
+#define    SIO_BL_COMM_EXEC_ACTIVE                                         0x1
+#define  SIO_BL_STATUS__A                                                  0x480010
+#define  SIO_BL_MODE__A                                                    0x480011
+#define    SIO_BL_MODE_DIRECT                                              0x0
+#define    SIO_BL_MODE_CHAIN                                               0x1
+#define  SIO_BL_ENABLE__A                                                  0x480012
+#define    SIO_BL_ENABLE_ON                                                0x1
+#define  SIO_BL_TGT_HDR__A                                                 0x480014
+#define  SIO_BL_TGT_ADDR__A                                                0x480015
+#define  SIO_BL_SRC_ADDR__A                                                0x480016
+#define  SIO_BL_SRC_LEN__A                                                 0x480017
+#define  SIO_BL_CHAIN_ADDR__A                                              0x480018
+#define  SIO_BL_CHAIN_LEN__A                                               0x480019
+#define  SIO_PDR_MON_CFG__A                                                0x7F0010
+#define  SIO_PDR_UIO_IN_HI__A                                              0x7F0015
+#define  SIO_PDR_UIO_OUT_LO__A                                             0x7F0016
+#define  SIO_PDR_OHW_CFG__A                                                0x7F001F
+#define    SIO_PDR_OHW_CFG_FREF_SEL__M                                     0x3
+#define  SIO_PDR_MSTRT_CFG__A                                              0x7F0025
+#define  SIO_PDR_MERR_CFG__A                                               0x7F0026
+#define  SIO_PDR_MCLK_CFG__A                                               0x7F0028
+#define    SIO_PDR_MCLK_CFG_DRIVE__B                                       3
+#define  SIO_PDR_MVAL_CFG__A                                               0x7F0029
+#define  SIO_PDR_MD0_CFG__A                                                0x7F002A
+#define    SIO_PDR_MD0_CFG_DRIVE__B                                        3
+#define  SIO_PDR_MD1_CFG__A                                                0x7F002B
+#define  SIO_PDR_MD2_CFG__A                                                0x7F002C
+#define  SIO_PDR_MD3_CFG__A                                                0x7F002D
+#define  SIO_PDR_MD4_CFG__A                                                0x7F002F
+#define  SIO_PDR_MD5_CFG__A                                                0x7F0030
+#define  SIO_PDR_MD6_CFG__A                                                0x7F0031
+#define  SIO_PDR_MD7_CFG__A                                                0x7F0032
+#define  SIO_PDR_SMA_TX_CFG__A                                             0x7F0038
index f7a40a1..aa9ccb8 100644 (file)
@@ -35,21 +35,18 @@ static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
 
-#define deb(args...)  do { \
+#define itd_dbg(args...)  do { \
        if (debug) { \
                printk(KERN_DEBUG   "ITD1000: " args);\
-               printk("\n"); \
        } \
 } while (0)
 
-#define warn(args...) do { \
+#define itd_warn(args...) do { \
        printk(KERN_WARNING "ITD1000: " args); \
-       printk("\n"); \
 } while (0)
 
-#define info(args...) do { \
+#define itd_info(args...) do { \
        printk(KERN_INFO    "ITD1000: " args); \
-       printk("\n"); \
 } while (0)
 
 /* don't write more than one byte with flexcop behind */
@@ -62,7 +59,7 @@ static int itd1000_write_regs(struct itd1000_state *state, u8 reg, u8 v[], u8 le
        buf[0] = reg;
        memcpy(&buf[1], v, len);
 
-       /* deb("wr %02x: %02x", reg, v[0]); */
+       /* itd_dbg("wr %02x: %02x\n", reg, v[0]); */
 
        if (i2c_transfer(state->i2c, &msg, 1) != 1) {
                printk(KERN_WARNING "itd1000 I2C write failed\n");
@@ -83,7 +80,7 @@ static int itd1000_read_reg(struct itd1000_state *state, u8 reg)
        itd1000_write_regs(state, (reg - 1) & 0xff, &state->shadow[(reg - 1) & 0xff], 1);
 
        if (i2c_transfer(state->i2c, msg, 2) != 2) {
-               warn("itd1000 I2C read failed");
+               itd_warn("itd1000 I2C read failed\n");
                return -EREMOTEIO;
        }
        return val;
@@ -127,14 +124,14 @@ static void itd1000_set_lpf_bw(struct itd1000_state *state, u32 symbol_rate)
        u8 bbgvmin = itd1000_read_reg(state, BBGVMIN) & 0xf0;
        u8 bw      = itd1000_read_reg(state, BW)      & 0xf0;
 
-       deb("symbol_rate = %d", symbol_rate);
+       itd_dbg("symbol_rate = %d\n", symbol_rate);
 
        /* not sure what is that ? - starting to download the table */
        itd1000_write_reg(state, CON1, con1 | (1 << 1));
 
        for (i = 0; i < ARRAY_SIZE(itd1000_lpf_pga); i++)
                if (symbol_rate < itd1000_lpf_pga[i].symbol_rate) {
-                       deb("symrate: index: %d pgaext: %x, bbgvmin: %x", i, itd1000_lpf_pga[i].pgaext, itd1000_lpf_pga[i].bbgvmin);
+                       itd_dbg("symrate: index: %d pgaext: %x, bbgvmin: %x\n", i, itd1000_lpf_pga[i].pgaext, itd1000_lpf_pga[i].bbgvmin);
                        itd1000_write_reg(state, PLLFH,   pllfh | (itd1000_lpf_pga[i].pgaext << 4));
                        itd1000_write_reg(state, BBGVMIN, bbgvmin | (itd1000_lpf_pga[i].bbgvmin));
                        itd1000_write_reg(state, BW,      bw | (i & 0x0f));
@@ -182,7 +179,7 @@ static void itd1000_set_vco(struct itd1000_state *state, u32 freq_khz)
 
                        adcout = itd1000_read_reg(state, PLLLOCK) & 0x0f;
 
-                       deb("VCO: %dkHz: %d -> ADCOUT: %d %02x", freq_khz, itd1000_vcorg[i].vcorg, adcout, vco_chp1_i2c);
+                       itd_dbg("VCO: %dkHz: %d -> ADCOUT: %d %02x\n", freq_khz, itd1000_vcorg[i].vcorg, adcout, vco_chp1_i2c);
 
                        if (adcout > 13) {
                                if (!(itd1000_vcorg[i].vcorg == 7 || itd1000_vcorg[i].vcorg == 15))
@@ -232,7 +229,7 @@ static void itd1000_set_lo(struct itd1000_state *state, u32 freq_khz)
        pllf = (u32) tmp;
 
        state->frequency = ((plln * 1000) + (pllf * 1000)/1048576) * 2*FREF;
-       deb("frequency: %dkHz (wanted) %dkHz (set), PLLF = %d, PLLN = %d", freq_khz, state->frequency, pllf, plln);
+       itd_dbg("frequency: %dkHz (wanted) %dkHz (set), PLLF = %d, PLLN = %d\n", freq_khz, state->frequency, pllf, plln);
 
        itd1000_write_reg(state, PLLNH, 0x80); /* PLLNH */;
        itd1000_write_reg(state, PLLNL, plln & 0xff);
@@ -242,7 +239,7 @@ static void itd1000_set_lo(struct itd1000_state *state, u32 freq_khz)
 
        for (i = 0; i < ARRAY_SIZE(itd1000_fre_values); i++) {
                if (freq_khz <= itd1000_fre_values[i].freq) {
-                       deb("fre_values: %d", i);
+                       itd_dbg("fre_values: %d\n", i);
                        itd1000_write_reg(state, RFTR, itd1000_fre_values[i].values[0]);
                        for (j = 0; j < 9; j++)
                                itd1000_write_reg(state, RFST1+j, itd1000_fre_values[i].values[j+1]);
@@ -382,7 +379,7 @@ struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter
                kfree(state);
                return NULL;
        }
-       info("successfully identified (ID: %d)", i);
+       itd_info("successfully identified (ID: %d)\n", i);
 
        memset(state->shadow, 0xff, sizeof(state->shadow));
        for (i = 0x65; i < 0x9c; i++)
index a763ec7..6599b8f 100644 (file)
@@ -50,7 +50,7 @@ static int nxt6000_writereg(struct nxt6000_state* state, u8 reg, u8 data)
        if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1)
                dprintk("nxt6000: nxt6000_write error (reg: 0x%02X, data: 0x%02X, ret: %d)\n", reg, data, ret);
 
-       return (ret != 1) ? -EFAULT : 0;
+       return (ret != 1) ? -EIO : 0;
 }
 
 static u8 nxt6000_readreg(struct nxt6000_state* state, u8 reg)
index 17f8cdf..3879d2e 100644 (file)
@@ -634,7 +634,7 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
        struct s5h1420_state* state = fe->demodulator_priv;
        int frequency_delta;
        struct dvb_frontend_tune_settings fesettings;
-       uint8_t clock_settting;
+       uint8_t clock_setting;
 
        dprintk("enter %s\n", __func__);
 
@@ -684,19 +684,19 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
        switch (state->fclk) {
        default:
        case 88000000:
-               clock_settting = 80;
+               clock_setting = 80;
                break;
        case 86000000:
-               clock_settting = 78;
+               clock_setting = 78;
                break;
        case 80000000:
-               clock_settting = 72;
+               clock_setting = 72;
                break;
        case 59000000:
-               clock_settting = 51;
+               clock_setting = 51;
                break;
        case 44000000:
-               clock_settting = 36;
+               clock_setting = 36;
                break;
        }
        dprintk("pll01: %d, ToneFreq: %d\n", state->fclk/1000000 - 8, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32));
diff --git a/drivers/media/dvb/frontends/tda18271c2dd.c b/drivers/media/dvb/frontends/tda18271c2dd.c
new file mode 100644 (file)
index 0000000..0384e8d
--- /dev/null
@@ -0,0 +1,1251 @@
+/*
+ * tda18271c2dd: Driver for the TDA18271C2 tuner
+ *
+ * Copyright (C) 2010 Digital Devices GmbH
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/version.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+
+struct SStandardParam {
+       s32   m_IFFrequency;
+       u32   m_BandWidth;
+       u8    m_EP3_4_0;
+       u8    m_EB22;
+};
+
+struct SMap {
+       u32   m_Frequency;
+       u8    m_Param;
+};
+
+struct SMapI {
+       u32   m_Frequency;
+       s32    m_Param;
+};
+
+struct SMap2 {
+       u32   m_Frequency;
+       u8    m_Param1;
+       u8    m_Param2;
+};
+
+struct SRFBandMap {
+       u32   m_RF_max;
+       u32   m_RF1_Default;
+       u32   m_RF2_Default;
+       u32   m_RF3_Default;
+};
+
+enum ERegister {
+       ID = 0,
+       TM,
+       PL,
+       EP1, EP2, EP3, EP4, EP5,
+       CPD, CD1, CD2, CD3,
+       MPD, MD1, MD2, MD3,
+       EB1, EB2, EB3, EB4, EB5, EB6, EB7, EB8, EB9, EB10,
+       EB11, EB12, EB13, EB14, EB15, EB16, EB17, EB18, EB19, EB20,
+       EB21, EB22, EB23,
+       NUM_REGS
+};
+
+struct tda_state {
+       struct i2c_adapter *i2c;
+       u8 adr;
+
+       u32   m_Frequency;
+       u32   IF;
+
+       u8    m_IFLevelAnalog;
+       u8    m_IFLevelDigital;
+       u8    m_IFLevelDVBC;
+       u8    m_IFLevelDVBT;
+
+       u8    m_EP4;
+       u8    m_EP3_Standby;
+
+       bool  m_bMaster;
+
+       s32   m_SettlingTime;
+
+       u8    m_Regs[NUM_REGS];
+
+       /* Tracking filter settings for band 0..6 */
+       u32   m_RF1[7];
+       s32   m_RF_A1[7];
+       s32   m_RF_B1[7];
+       u32   m_RF2[7];
+       s32   m_RF_A2[7];
+       s32   m_RF_B2[7];
+       u32   m_RF3[7];
+
+       u8    m_TMValue_RFCal;    /* Calibration temperatur */
+
+       bool  m_bFMInput;         /* true to use Pin 8 for FM Radio */
+
+};
+
+static int PowerScan(struct tda_state *state,
+                    u8 RFBand, u32 RF_in,
+                    u32 *pRF_Out, bool *pbcal);
+
+static int i2c_readn(struct i2c_adapter *adapter, u8 adr, u8 *data, int len)
+{
+       struct i2c_msg msgs[1] = {{.addr = adr,  .flags = I2C_M_RD,
+                                  .buf  = data, .len   = len} };
+       return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1;
+}
+
+static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len)
+{
+       struct i2c_msg msg = {.addr = adr, .flags = 0,
+                             .buf = data, .len = len};
+
+       if (i2c_transfer(adap, &msg, 1) != 1) {
+               printk(KERN_ERR "tda18271c2dd: i2c write error at addr %i\n", adr);
+               return -1;
+       }
+       return 0;
+}
+
+static int WriteRegs(struct tda_state *state,
+                    u8 SubAddr, u8 *Regs, u16 nRegs)
+{
+       u8 data[nRegs+1];
+
+       data[0] = SubAddr;
+       memcpy(data + 1, Regs, nRegs);
+       return i2c_write(state->i2c, state->adr, data, nRegs+1);
+}
+
+static int WriteReg(struct tda_state *state, u8 SubAddr, u8 Reg)
+{
+       u8 msg[2] = {SubAddr, Reg};
+
+       return i2c_write(state->i2c, state->adr, msg, 2);
+}
+
+static int Read(struct tda_state *state, u8 * Regs)
+{
+       return i2c_readn(state->i2c, state->adr, Regs, 16);
+}
+
+static int ReadExtented(struct tda_state *state, u8 * Regs)
+{
+       return i2c_readn(state->i2c, state->adr, Regs, NUM_REGS);
+}
+
+static int UpdateRegs(struct tda_state *state, u8 RegFrom, u8 RegTo)
+{
+       return WriteRegs(state, RegFrom,
+                        &state->m_Regs[RegFrom], RegTo-RegFrom+1);
+}
+static int UpdateReg(struct tda_state *state, u8 Reg)
+{
+       return WriteReg(state, Reg, state->m_Regs[Reg]);
+}
+
+#include "tda18271c2dd_maps.h"
+
+static void reset(struct tda_state *state)
+{
+       u32   ulIFLevelAnalog = 0;
+       u32   ulIFLevelDigital = 2;
+       u32   ulIFLevelDVBC = 7;
+       u32   ulIFLevelDVBT = 6;
+       u32   ulXTOut = 0;
+       u32   ulStandbyMode = 0x06;    /* Send in stdb, but leave osc on */
+       u32   ulSlave = 0;
+       u32   ulFMInput = 0;
+       u32   ulSettlingTime = 100;
+
+       state->m_Frequency         = 0;
+       state->m_SettlingTime = 100;
+       state->m_IFLevelAnalog = (ulIFLevelAnalog & 0x07) << 2;
+       state->m_IFLevelDigital = (ulIFLevelDigital & 0x07) << 2;
+       state->m_IFLevelDVBC = (ulIFLevelDVBC & 0x07) << 2;
+       state->m_IFLevelDVBT = (ulIFLevelDVBT & 0x07) << 2;
+
+       state->m_EP4 = 0x20;
+       if (ulXTOut != 0)
+               state->m_EP4 |= 0x40;
+
+       state->m_EP3_Standby = ((ulStandbyMode & 0x07) << 5) | 0x0F;
+       state->m_bMaster = (ulSlave == 0);
+
+       state->m_SettlingTime = ulSettlingTime;
+
+       state->m_bFMInput = (ulFMInput == 2);
+}
+
+static bool SearchMap1(struct SMap Map[],
+                      u32 Frequency, u8 *pParam)
+{
+       int i = 0;
+
+       while ((Map[i].m_Frequency != 0) && (Frequency > Map[i].m_Frequency))
+               i += 1;
+       if (Map[i].m_Frequency == 0)
+               return false;
+       *pParam = Map[i].m_Param;
+       return true;
+}
+
+static bool SearchMap2(struct SMapI Map[],
+                      u32 Frequency, s32 *pParam)
+{
+       int i = 0;
+
+       while ((Map[i].m_Frequency != 0) &&
+              (Frequency > Map[i].m_Frequency))
+               i += 1;
+       if (Map[i].m_Frequency == 0)
+               return false;
+       *pParam = Map[i].m_Param;
+       return true;
+}
+
+static bool SearchMap3(struct SMap2 Map[], u32 Frequency,
+                      u8 *pParam1, u8 *pParam2)
+{
+       int i = 0;
+
+       while ((Map[i].m_Frequency != 0) &&
+              (Frequency > Map[i].m_Frequency))
+               i += 1;
+       if (Map[i].m_Frequency == 0)
+               return false;
+       *pParam1 = Map[i].m_Param1;
+       *pParam2 = Map[i].m_Param2;
+       return true;
+}
+
+static bool SearchMap4(struct SRFBandMap Map[],
+                      u32 Frequency, u8 *pRFBand)
+{
+       int i = 0;
+
+       while (i < 7 && (Frequency > Map[i].m_RF_max))
+               i += 1;
+       if (i == 7)
+               return false;
+       *pRFBand = i;
+       return true;
+}
+
+static int ThermometerRead(struct tda_state *state, u8 *pTM_Value)
+{
+       int status = 0;
+
+       do {
+               u8 Regs[16];
+               state->m_Regs[TM] |= 0x10;
+               status = UpdateReg(state, TM);
+               if (status < 0)
+                       break;
+               status = Read(state, Regs);
+               if (status < 0)
+                       break;
+               if (((Regs[TM] & 0x0F) == 0 && (Regs[TM] & 0x20) == 0x20) ||
+                   ((Regs[TM] & 0x0F) == 8 && (Regs[TM] & 0x20) == 0x00)) {
+                       state->m_Regs[TM] ^= 0x20;
+                       status = UpdateReg(state, TM);
+                       if (status < 0)
+                               break;
+                       msleep(10);
+                       status = Read(state, Regs);
+                       if (status < 0)
+                               break;
+               }
+               *pTM_Value = (Regs[TM] & 0x20)
+                               ? m_Thermometer_Map_2[Regs[TM] & 0x0F]
+                               : m_Thermometer_Map_1[Regs[TM] & 0x0F] ;
+               state->m_Regs[TM] &= ~0x10;        /* Thermometer off */
+               status = UpdateReg(state, TM);
+               if (status < 0)
+                       break;
+               state->m_Regs[EP4] &= ~0x03;       /* CAL_mode = 0 ????????? */
+               status = UpdateReg(state, EP4);
+               if (status < 0)
+                       break;
+       } while (0);
+
+       return status;
+}
+
+static int StandBy(struct tda_state *state)
+{
+       int status = 0;
+       do {
+               state->m_Regs[EB12] &= ~0x20;  /* PD_AGC1_Det = 0 */
+               status = UpdateReg(state, EB12);
+               if (status < 0)
+                       break;
+               state->m_Regs[EB18] &= ~0x83;  /* AGC1_loop_off = 0, AGC1_Gain = 6 dB */
+               status = UpdateReg(state, EB18);
+               if (status < 0)
+                       break;
+               state->m_Regs[EB21] |= 0x03; /* AGC2_Gain = -6 dB */
+               state->m_Regs[EP3] = state->m_EP3_Standby;
+               status = UpdateReg(state, EP3);
+               if (status < 0)
+                       break;
+               state->m_Regs[EB23] &= ~0x06; /* ForceLP_Fc2_En = 0, LP_Fc[2] = 0 */
+               status = UpdateRegs(state, EB21, EB23);
+               if (status < 0)
+                       break;
+       } while (0);
+       return status;
+}
+
+static int CalcMainPLL(struct tda_state *state, u32 freq)
+{
+
+       u8  PostDiv;
+       u8  Div;
+       u64 OscFreq;
+       u32 MainDiv;
+
+       if (!SearchMap3(m_Main_PLL_Map, freq, &PostDiv, &Div))
+               return -EINVAL;
+
+       OscFreq = (u64) freq * (u64) Div;
+       OscFreq *= (u64) 16384;
+       do_div(OscFreq, (u64)16000000);
+       MainDiv = OscFreq;
+
+       state->m_Regs[MPD] = PostDiv & 0x77;
+       state->m_Regs[MD1] = ((MainDiv >> 16) & 0x7F);
+       state->m_Regs[MD2] = ((MainDiv >>  8) & 0xFF);
+       state->m_Regs[MD3] = (MainDiv & 0xFF);
+
+       return UpdateRegs(state, MPD, MD3);
+}
+
+static int CalcCalPLL(struct tda_state *state, u32 freq)
+{
+       u8 PostDiv;
+       u8 Div;
+       u64 OscFreq;
+       u32 CalDiv;
+
+       if (!SearchMap3(m_Cal_PLL_Map, freq, &PostDiv, &Div))
+               return -EINVAL;
+
+       OscFreq = (u64)freq * (u64)Div;
+       /* CalDiv = u32( OscFreq * 16384 / 16000000 ); */
+       OscFreq *= (u64)16384;
+       do_div(OscFreq, (u64)16000000);
+       CalDiv = OscFreq;
+
+       state->m_Regs[CPD] = PostDiv;
+       state->m_Regs[CD1] = ((CalDiv >> 16) & 0xFF);
+       state->m_Regs[CD2] = ((CalDiv >>  8) & 0xFF);
+       state->m_Regs[CD3] = (CalDiv & 0xFF);
+
+       return UpdateRegs(state, CPD, CD3);
+}
+
+static int CalibrateRF(struct tda_state *state,
+                      u8 RFBand, u32 freq, s32 *pCprog)
+{
+       int status = 0;
+       u8 Regs[NUM_REGS];
+       do {
+               u8 BP_Filter = 0;
+               u8 GainTaper = 0;
+               u8 RFC_K = 0;
+               u8 RFC_M = 0;
+
+               state->m_Regs[EP4] &= ~0x03; /* CAL_mode = 0 */
+               status = UpdateReg(state, EP4);
+               if (status < 0)
+                       break;
+               state->m_Regs[EB18] |= 0x03;  /* AGC1_Gain = 3 */
+               status = UpdateReg(state, EB18);
+               if (status < 0)
+                       break;
+
+               /* Switching off LT (as datasheet says) causes calibration on C1 to fail */
+               /* (Readout of Cprog is allways 255) */
+               if (state->m_Regs[ID] != 0x83)    /* C1: ID == 83, C2: ID == 84 */
+                       state->m_Regs[EP3] |= 0x40; /* SM_LT = 1 */
+
+               if (!(SearchMap1(m_BP_Filter_Map, freq, &BP_Filter) &&
+                       SearchMap1(m_GainTaper_Map, freq, &GainTaper) &&
+                       SearchMap3(m_KM_Map, freq, &RFC_K, &RFC_M)))
+                       return -EINVAL;
+
+               state->m_Regs[EP1] = (state->m_Regs[EP1] & ~0x07) | BP_Filter;
+               state->m_Regs[EP2] = (RFBand << 5) | GainTaper;
+
+               state->m_Regs[EB13] = (state->m_Regs[EB13] & ~0x7C) | (RFC_K << 4) | (RFC_M << 2);
+
+               status = UpdateRegs(state, EP1, EP3);
+               if (status < 0)
+                       break;
+               status = UpdateReg(state, EB13);
+               if (status < 0)
+                       break;
+
+               state->m_Regs[EB4] |= 0x20;    /* LO_ForceSrce = 1 */
+               status = UpdateReg(state, EB4);
+               if (status < 0)
+                       break;
+
+               state->m_Regs[EB7] |= 0x20;    /* CAL_ForceSrce = 1 */
+               status = UpdateReg(state, EB7);
+               if (status < 0)
+                       break;
+
+               state->m_Regs[EB14] = 0; /* RFC_Cprog = 0 */
+               status = UpdateReg(state, EB14);
+               if (status < 0)
+                       break;
+
+               state->m_Regs[EB20] &= ~0x20;  /* ForceLock = 0; */
+               status = UpdateReg(state, EB20);
+               if (status < 0)
+                       break;
+
+               state->m_Regs[EP4] |= 0x03;  /* CAL_Mode = 3 */
+               status = UpdateRegs(state, EP4, EP5);
+               if (status < 0)
+                       break;
+
+               status = CalcCalPLL(state, freq);
+               if (status < 0)
+                       break;
+               status = CalcMainPLL(state, freq + 1000000);
+               if (status < 0)
+                       break;
+
+               msleep(5);
+               status = UpdateReg(state, EP2);
+               if (status < 0)
+                       break;
+               status = UpdateReg(state, EP1);
+               if (status < 0)
+                       break;
+               status = UpdateReg(state, EP2);
+               if (status < 0)
+                       break;
+               status = UpdateReg(state, EP1);
+               if (status < 0)
+                       break;
+
+               state->m_Regs[EB4] &= ~0x20;    /* LO_ForceSrce = 0 */
+               status = UpdateReg(state, EB4);
+               if (status < 0)
+                       break;
+
+               state->m_Regs[EB7] &= ~0x20;    /* CAL_ForceSrce = 0 */
+               status = UpdateReg(state, EB7);
+               if (status < 0)
+                       break;
+               msleep(10);
+
+               state->m_Regs[EB20] |= 0x20;  /* ForceLock = 1; */
+               status = UpdateReg(state, EB20);
+               if (status < 0)
+                       break;
+               msleep(60);
+
+               state->m_Regs[EP4] &= ~0x03;  /* CAL_Mode = 0 */
+               state->m_Regs[EP3] &= ~0x40; /* SM_LT = 0 */
+               state->m_Regs[EB18] &= ~0x03;  /* AGC1_Gain = 0 */
+               status = UpdateReg(state, EB18);
+               if (status < 0)
+                       break;
+               status = UpdateRegs(state, EP3, EP4);
+               if (status < 0)
+                       break;
+               status = UpdateReg(state, EP1);
+               if (status < 0)
+                       break;
+
+               status = ReadExtented(state, Regs);
+               if (status < 0)
+                       break;
+
+               *pCprog = Regs[EB14];
+
+       } while (0);
+       return status;
+}
+
+static int RFTrackingFiltersInit(struct tda_state *state,
+                                u8 RFBand)
+{
+       int status = 0;
+
+       u32   RF1 = m_RF_Band_Map[RFBand].m_RF1_Default;
+       u32   RF2 = m_RF_Band_Map[RFBand].m_RF2_Default;
+       u32   RF3 = m_RF_Band_Map[RFBand].m_RF3_Default;
+       bool    bcal = false;
+
+       s32    Cprog_cal1 = 0;
+       s32    Cprog_table1 = 0;
+       s32    Cprog_cal2 = 0;
+       s32    Cprog_table2 = 0;
+       s32    Cprog_cal3 = 0;
+       s32    Cprog_table3 = 0;
+
+       state->m_RF_A1[RFBand] = 0;
+       state->m_RF_B1[RFBand] = 0;
+       state->m_RF_A2[RFBand] = 0;
+       state->m_RF_B2[RFBand] = 0;
+
+       do {
+               status = PowerScan(state, RFBand, RF1, &RF1, &bcal);
+               if (status < 0)
+                       break;
+               if (bcal) {
+                       status = CalibrateRF(state, RFBand, RF1, &Cprog_cal1);
+                       if (status < 0)
+                               break;
+               }
+               SearchMap2(m_RF_Cal_Map, RF1, &Cprog_table1);
+               if (!bcal)
+                       Cprog_cal1 = Cprog_table1;
+               state->m_RF_B1[RFBand] = Cprog_cal1 - Cprog_table1;
+               /* state->m_RF_A1[RF_Band] = ???? */
+
+               if (RF2 == 0)
+                       break;
+
+               status = PowerScan(state, RFBand, RF2, &RF2, &bcal);
+               if (status < 0)
+                       break;
+               if (bcal) {
+                       status = CalibrateRF(state, RFBand, RF2, &Cprog_cal2);
+                       if (status < 0)
+                               break;
+               }
+               SearchMap2(m_RF_Cal_Map, RF2, &Cprog_table2);
+               if (!bcal)
+                       Cprog_cal2 = Cprog_table2;
+
+               state->m_RF_A1[RFBand] =
+                       (Cprog_cal2 - Cprog_table2 - Cprog_cal1 + Cprog_table1) /
+                       ((s32)(RF2) - (s32)(RF1));
+
+               if (RF3 == 0)
+                       break;
+
+               status = PowerScan(state, RFBand, RF3, &RF3, &bcal);
+               if (status < 0)
+                       break;
+               if (bcal) {
+                       status = CalibrateRF(state, RFBand, RF3, &Cprog_cal3);
+                       if (status < 0)
+                               break;
+               }
+               SearchMap2(m_RF_Cal_Map, RF3, &Cprog_table3);
+               if (!bcal)
+                       Cprog_cal3 = Cprog_table3;
+               state->m_RF_A2[RFBand] = (Cprog_cal3 - Cprog_table3 - Cprog_cal2 + Cprog_table2) / ((s32)(RF3) - (s32)(RF2));
+               state->m_RF_B2[RFBand] = Cprog_cal2 - Cprog_table2;
+
+       } while (0);
+
+       state->m_RF1[RFBand] = RF1;
+       state->m_RF2[RFBand] = RF2;
+       state->m_RF3[RFBand] = RF3;
+
+#if 0
+       printk(KERN_ERR "tda18271c2dd: %s %d RF1 = %d A1 = %d B1 = %d RF2 = %d A2 = %d B2 = %d RF3 = %d\n", __func__,
+              RFBand, RF1, state->m_RF_A1[RFBand], state->m_RF_B1[RFBand], RF2,
+              state->m_RF_A2[RFBand], state->m_RF_B2[RFBand], RF3);
+#endif
+
+       return status;
+}
+
+static int PowerScan(struct tda_state *state,
+                    u8 RFBand, u32 RF_in, u32 *pRF_Out, bool *pbcal)
+{
+       int status = 0;
+       do {
+               u8   Gain_Taper = 0;
+               s32  RFC_Cprog = 0;
+               u8   CID_Target = 0;
+               u8   CountLimit = 0;
+               u32  freq_MainPLL;
+               u8   Regs[NUM_REGS];
+               u8   CID_Gain;
+               s32  Count = 0;
+               int  sign  = 1;
+               bool wait = false;
+
+               if (!(SearchMap2(m_RF_Cal_Map, RF_in, &RFC_Cprog) &&
+                     SearchMap1(m_GainTaper_Map, RF_in, &Gain_Taper) &&
+                     SearchMap3(m_CID_Target_Map, RF_in, &CID_Target, &CountLimit))) {
+
+                       printk(KERN_ERR "tda18271c2dd: %s Search map failed\n", __func__);
+                       return -EINVAL;
+               }
+
+               state->m_Regs[EP2] = (RFBand << 5) | Gain_Taper;
+               state->m_Regs[EB14] = (RFC_Cprog);
+               status = UpdateReg(state, EP2);
+               if (status < 0)
+                       break;
+               status = UpdateReg(state, EB14);
+               if (status < 0)
+                       break;
+
+               freq_MainPLL = RF_in + 1000000;
+               status = CalcMainPLL(state, freq_MainPLL);
+               if (status < 0)
+                       break;
+               msleep(5);
+               state->m_Regs[EP4] = (state->m_Regs[EP4] & ~0x03) | 1;    /* CAL_mode = 1 */
+               status = UpdateReg(state, EP4);
+               if (status < 0)
+                       break;
+               status = UpdateReg(state, EP2);  /* Launch power measurement */
+               if (status < 0)
+                       break;
+               status = ReadExtented(state, Regs);
+               if (status < 0)
+                       break;
+               CID_Gain = Regs[EB10] & 0x3F;
+               state->m_Regs[ID] = Regs[ID];  /* Chip version, (needed for C1 workarround in CalibrateRF) */
+
+               *pRF_Out = RF_in;
+
+               while (CID_Gain < CID_Target) {
+                       freq_MainPLL = RF_in + sign * Count + 1000000;
+                       status = CalcMainPLL(state, freq_MainPLL);
+                       if (status < 0)
+                               break;
+                       msleep(wait ? 5 : 1);
+                       wait = false;
+                       status = UpdateReg(state, EP2);  /* Launch power measurement */
+                       if (status < 0)
+                               break;
+                       status = ReadExtented(state, Regs);
+                       if (status < 0)
+                               break;
+                       CID_Gain = Regs[EB10] & 0x3F;
+                       Count += 200000;
+
+                       if (Count < CountLimit * 100000)
+                               continue;
+                       if (sign < 0)
+                               break;
+
+                       sign = -sign;
+                       Count = 200000;
+                       wait = true;
+               }
+               status = status;
+               if (status < 0)
+                       break;
+               if (CID_Gain >= CID_Target) {
+                       *pbcal = true;
+                       *pRF_Out = freq_MainPLL - 1000000;
+               } else
+                       *pbcal = false;
+       } while (0);
+
+       return status;
+}
+
+static int PowerScanInit(struct tda_state *state)
+{
+       int status = 0;
+       do {
+               state->m_Regs[EP3] = (state->m_Regs[EP3] & ~0x1F) | 0x12;
+               state->m_Regs[EP4] = (state->m_Regs[EP4] & ~0x1F); /* If level = 0, Cal mode = 0 */
+               status = UpdateRegs(state, EP3, EP4);
+               if (status < 0)
+                       break;
+               state->m_Regs[EB18] = (state->m_Regs[EB18] & ~0x03); /* AGC 1 Gain = 0 */
+               status = UpdateReg(state, EB18);
+               if (status < 0)
+                       break;
+               state->m_Regs[EB21] = (state->m_Regs[EB21] & ~0x03); /* AGC 2 Gain = 0 (Datasheet = 3) */
+               state->m_Regs[EB23] = (state->m_Regs[EB23] | 0x06); /* ForceLP_Fc2_En = 1, LPFc[2] = 1 */
+               status = UpdateRegs(state, EB21, EB23);
+               if (status < 0)
+                       break;
+       } while (0);
+       return status;
+}
+
+static int CalcRFFilterCurve(struct tda_state *state)
+{
+       int status = 0;
+       do {
+               msleep(200);      /* Temperature stabilisation */
+               status = PowerScanInit(state);
+               if (status < 0)
+                       break;
+               status = RFTrackingFiltersInit(state, 0);
+               if (status < 0)
+                       break;
+               status = RFTrackingFiltersInit(state, 1);
+               if (status < 0)
+                       break;
+               status = RFTrackingFiltersInit(state, 2);
+               if (status < 0)
+                       break;
+               status = RFTrackingFiltersInit(state, 3);
+               if (status < 0)
+                       break;
+               status = RFTrackingFiltersInit(state, 4);
+               if (status < 0)
+                       break;
+               status = RFTrackingFiltersInit(state, 5);
+               if (status < 0)
+                       break;
+               status = RFTrackingFiltersInit(state, 6);
+               if (status < 0)
+                       break;
+               status = ThermometerRead(state, &state->m_TMValue_RFCal); /* also switches off Cal mode !!! */
+               if (status < 0)
+                       break;
+       } while (0);
+
+       return status;
+}
+
+static int FixedContentsI2CUpdate(struct tda_state *state)
+{
+       static u8 InitRegs[] = {
+               0x08, 0x80, 0xC6,
+               0xDF, 0x16, 0x60, 0x80,
+               0x80, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00,
+               0xFC, 0x01, 0x84, 0x41,
+               0x01, 0x84, 0x40, 0x07,
+               0x00, 0x00, 0x96, 0x3F,
+               0xC1, 0x00, 0x8F, 0x00,
+               0x00, 0x8C, 0x00, 0x20,
+               0xB3, 0x48, 0xB0,
+       };
+       int status = 0;
+       memcpy(&state->m_Regs[TM], InitRegs, EB23 - TM + 1);
+       do {
+               status = UpdateRegs(state, TM, EB23);
+               if (status < 0)
+                       break;
+
+               /* AGC1 gain setup */
+               state->m_Regs[EB17] = 0x00;
+               status = UpdateReg(state, EB17);
+               if (status < 0)
+                       break;
+               state->m_Regs[EB17] = 0x03;
+               status = UpdateReg(state, EB17);
+               if (status < 0)
+                       break;
+               state->m_Regs[EB17] = 0x43;
+               status = UpdateReg(state, EB17);
+               if (status < 0)
+                       break;
+               state->m_Regs[EB17] = 0x4C;
+               status = UpdateReg(state, EB17);
+               if (status < 0)
+                       break;
+
+               /* IRC Cal Low band */
+               state->m_Regs[EP3] = 0x1F;
+               state->m_Regs[EP4] = 0x66;
+               state->m_Regs[EP5] = 0x81;
+               state->m_Regs[CPD] = 0xCC;
+               state->m_Regs[CD1] = 0x6C;
+               state->m_Regs[CD2] = 0x00;
+               state->m_Regs[CD3] = 0x00;
+               state->m_Regs[MPD] = 0xC5;
+               state->m_Regs[MD1] = 0x77;
+               state->m_Regs[MD2] = 0x08;
+               state->m_Regs[MD3] = 0x00;
+               status = UpdateRegs(state, EP2, MD3); /* diff between sw and datasheet (ep3-md3) */
+               if (status < 0)
+                       break;
+
+#if 0
+               state->m_Regs[EB4] = 0x61;          /* missing in sw */
+               status = UpdateReg(state, EB4);
+               if (status < 0)
+                       break;
+               msleep(1);
+               state->m_Regs[EB4] = 0x41;
+               status = UpdateReg(state, EB4);
+               if (status < 0)
+                       break;
+#endif
+
+               msleep(5);
+               status = UpdateReg(state, EP1);
+               if (status < 0)
+                       break;
+               msleep(5);
+
+               state->m_Regs[EP5] = 0x85;
+               state->m_Regs[CPD] = 0xCB;
+               state->m_Regs[CD1] = 0x66;
+               state->m_Regs[CD2] = 0x70;
+               status = UpdateRegs(state, EP3, CD3);
+               if (status < 0)
+                       break;
+               msleep(5);
+               status = UpdateReg(state, EP2);
+               if (status < 0)
+                       break;
+               msleep(30);
+
+               /* IRC Cal mid band */
+               state->m_Regs[EP5] = 0x82;
+               state->m_Regs[CPD] = 0xA8;
+               state->m_Regs[CD2] = 0x00;
+               state->m_Regs[MPD] = 0xA1; /* Datasheet = 0xA9 */
+               state->m_Regs[MD1] = 0x73;
+               state->m_Regs[MD2] = 0x1A;
+               status = UpdateRegs(state, EP3, MD3);
+               if (status < 0)
+                       break;
+
+               msleep(5);
+               status = UpdateReg(state, EP1);
+               if (status < 0)
+                       break;
+               msleep(5);
+
+               state->m_Regs[EP5] = 0x86;
+               state->m_Regs[CPD] = 0xA8;
+               state->m_Regs[CD1] = 0x66;
+               state->m_Regs[CD2] = 0xA0;
+               status = UpdateRegs(state, EP3, CD3);
+               if (status < 0)
+                       break;
+               msleep(5);
+               status = UpdateReg(state, EP2);
+               if (status < 0)
+                       break;
+               msleep(30);
+
+               /* IRC Cal high band */
+               state->m_Regs[EP5] = 0x83;
+               state->m_Regs[CPD] = 0x98;
+               state->m_Regs[CD1] = 0x65;
+               state->m_Regs[CD2] = 0x00;
+               state->m_Regs[MPD] = 0x91;  /* Datasheet = 0x91 */
+               state->m_Regs[MD1] = 0x71;
+               state->m_Regs[MD2] = 0xCD;
+               status = UpdateRegs(state, EP3, MD3);
+               if (status < 0)
+                       break;
+               msleep(5);
+               status = UpdateReg(state, EP1);
+               if (status < 0)
+                       break;
+               msleep(5);
+               state->m_Regs[EP5] = 0x87;
+               state->m_Regs[CD1] = 0x65;
+               state->m_Regs[CD2] = 0x50;
+               status = UpdateRegs(state, EP3, CD3);
+               if (status < 0)
+                       break;
+               msleep(5);
+               status = UpdateReg(state, EP2);
+               if (status < 0)
+                       break;
+               msleep(30);
+
+               /* Back to normal */
+               state->m_Regs[EP4] = 0x64;
+               status = UpdateReg(state, EP4);
+               if (status < 0)
+                       break;
+               status = UpdateReg(state, EP1);
+               if (status < 0)
+                       break;
+
+       } while (0);
+       return status;
+}
+
+static int InitCal(struct tda_state *state)
+{
+       int status = 0;
+
+       do {
+               status = FixedContentsI2CUpdate(state);
+               if (status < 0)
+                       break;
+               status = CalcRFFilterCurve(state);
+               if (status < 0)
+                       break;
+               status = StandBy(state);
+               if (status < 0)
+                       break;
+               /* m_bInitDone = true; */
+       } while (0);
+       return status;
+};
+
+static int RFTrackingFiltersCorrection(struct tda_state *state,
+                                      u32 Frequency)
+{
+       int status = 0;
+       s32 Cprog_table;
+       u8 RFBand;
+       u8 dCoverdT;
+
+       if (!SearchMap2(m_RF_Cal_Map, Frequency, &Cprog_table) ||
+           !SearchMap4(m_RF_Band_Map, Frequency, &RFBand) ||
+           !SearchMap1(m_RF_Cal_DC_Over_DT_Map, Frequency, &dCoverdT))
+
+               return -EINVAL;
+
+       do {
+               u8 TMValue_Current;
+               u32   RF1 = state->m_RF1[RFBand];
+               u32   RF2 = state->m_RF1[RFBand];
+               u32   RF3 = state->m_RF1[RFBand];
+               s32    RF_A1 = state->m_RF_A1[RFBand];
+               s32    RF_B1 = state->m_RF_B1[RFBand];
+               s32    RF_A2 = state->m_RF_A2[RFBand];
+               s32    RF_B2 = state->m_RF_B2[RFBand];
+               s32 Capprox = 0;
+               int TComp;
+
+               state->m_Regs[EP3] &= ~0xE0;  /* Power up */
+               status = UpdateReg(state, EP3);
+               if (status < 0)
+                       break;
+
+               status = ThermometerRead(state, &TMValue_Current);
+               if (status < 0)
+                       break;
+
+               if (RF3 == 0 || Frequency < RF2)
+                       Capprox = RF_A1 * ((s32)(Frequency) - (s32)(RF1)) + RF_B1 + Cprog_table;
+               else
+                       Capprox = RF_A2 * ((s32)(Frequency) - (s32)(RF2)) + RF_B2 + Cprog_table;
+
+               TComp = (int)(dCoverdT) * ((int)(TMValue_Current) - (int)(state->m_TMValue_RFCal))/1000;
+
+               Capprox += TComp;
+
+               if (Capprox < 0)
+                       Capprox = 0;
+               else if (Capprox > 255)
+                       Capprox = 255;
+
+
+               /* TODO Temperature compensation. There is defenitely a scale factor */
+               /*      missing in the datasheet, so leave it out for now.           */
+               state->m_Regs[EB14] = Capprox;
+
+               status = UpdateReg(state, EB14);
+               if (status < 0)
+                       break;
+
+       } while (0);
+       return status;
+}
+
+static int ChannelConfiguration(struct tda_state *state,
+                               u32 Frequency, int Standard)
+{
+
+       s32 IntermediateFrequency = m_StandardTable[Standard].m_IFFrequency;
+       int status = 0;
+
+       u8 BP_Filter = 0;
+       u8 RF_Band = 0;
+       u8 GainTaper = 0;
+       u8 IR_Meas = 0;
+
+       state->IF = IntermediateFrequency;
+       /* printk("tda18271c2dd: %s Freq = %d Standard = %d IF = %d\n", __func__, Frequency, Standard, IntermediateFrequency); */
+       /* get values from tables */
+
+       if (!(SearchMap1(m_BP_Filter_Map, Frequency, &BP_Filter) &&
+              SearchMap1(m_GainTaper_Map, Frequency, &GainTaper) &&
+              SearchMap1(m_IR_Meas_Map, Frequency, &IR_Meas) &&
+              SearchMap4(m_RF_Band_Map, Frequency, &RF_Band))) {
+
+               printk(KERN_ERR "tda18271c2dd: %s SearchMap failed\n", __func__);
+               return -EINVAL;
+       }
+
+       do {
+               state->m_Regs[EP3] = (state->m_Regs[EP3] & ~0x1F) | m_StandardTable[Standard].m_EP3_4_0;
+               state->m_Regs[EP3] &= ~0x04;   /* switch RFAGC to high speed mode */
+
+               /* m_EP4 default for XToutOn, CAL_Mode (0) */
+               state->m_Regs[EP4] = state->m_EP4 | ((Standard > HF_AnalogMax) ? state->m_IFLevelDigital : state->m_IFLevelAnalog);
+               /* state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelDigital; */
+               if (Standard <= HF_AnalogMax)
+                       state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelAnalog;
+               else if (Standard <= HF_ATSC)
+                       state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelDVBT;
+               else if (Standard <= HF_DVBC)
+                       state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelDVBC;
+               else
+                       state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelDigital;
+
+               if ((Standard == HF_FM_Radio) && state->m_bFMInput)
+                       state->m_Regs[EP4] |= 80;
+
+               state->m_Regs[MPD] &= ~0x80;
+               if (Standard > HF_AnalogMax)
+                       state->m_Regs[MPD] |= 0x80; /* Add IF_notch for digital */
+
+               state->m_Regs[EB22] = m_StandardTable[Standard].m_EB22;
+
+               /* Note: This is missing from flowchart in TDA18271 specification ( 1.5 MHz cutoff for FM ) */
+               if (Standard == HF_FM_Radio)
+                       state->m_Regs[EB23] |=  0x06; /* ForceLP_Fc2_En = 1, LPFc[2] = 1 */
+               else
+                       state->m_Regs[EB23] &= ~0x06; /* ForceLP_Fc2_En = 0, LPFc[2] = 0 */
+
+               status = UpdateRegs(state, EB22, EB23);
+               if (status < 0)
+                       break;
+
+               state->m_Regs[EP1] = (state->m_Regs[EP1] & ~0x07) | 0x40 | BP_Filter;   /* Dis_Power_level = 1, Filter */
+               state->m_Regs[EP5] = (state->m_Regs[EP5] & ~0x07) | IR_Meas;
+               state->m_Regs[EP2] = (RF_Band << 5) | GainTaper;
+
+               state->m_Regs[EB1] = (state->m_Regs[EB1] & ~0x07) |
+                       (state->m_bMaster ? 0x04 : 0x00); /* CALVCO_FortLOn = MS */
+               /* AGC1_always_master = 0 */
+               /* AGC_firstn = 0 */
+               status = UpdateReg(state, EB1);
+               if (status < 0)
+                       break;
+
+               if (state->m_bMaster) {
+                       status = CalcMainPLL(state, Frequency + IntermediateFrequency);
+                       if (status < 0)
+                               break;
+                       status = UpdateRegs(state, TM, EP5);
+                       if (status < 0)
+                               break;
+                       state->m_Regs[EB4] |= 0x20;    /* LO_forceSrce = 1 */
+                       status = UpdateReg(state, EB4);
+                       if (status < 0)
+                               break;
+                       msleep(1);
+                       state->m_Regs[EB4] &= ~0x20;   /* LO_forceSrce = 0 */
+                       status = UpdateReg(state, EB4);
+                       if (status < 0)
+                               break;
+               } else {
+                       u8 PostDiv = 0;
+                       u8 Div;
+                       status = CalcCalPLL(state, Frequency + IntermediateFrequency);
+                       if (status < 0)
+                               break;
+
+                       SearchMap3(m_Cal_PLL_Map, Frequency + IntermediateFrequency, &PostDiv, &Div);
+                       state->m_Regs[MPD] = (state->m_Regs[MPD] & ~0x7F) | (PostDiv & 0x77);
+                       status = UpdateReg(state, MPD);
+                       if (status < 0)
+                               break;
+                       status = UpdateRegs(state, TM, EP5);
+                       if (status < 0)
+                               break;
+
+                       state->m_Regs[EB7] |= 0x20;    /* CAL_forceSrce = 1 */
+                       status = UpdateReg(state, EB7);
+                       if (status < 0)
+                               break;
+                       msleep(1);
+                       state->m_Regs[EB7] &= ~0x20;   /* CAL_forceSrce = 0 */
+                       status = UpdateReg(state, EB7);
+                       if (status < 0)
+                               break;
+               }
+               msleep(20);
+               if (Standard != HF_FM_Radio)
+                       state->m_Regs[EP3] |= 0x04;    /* RFAGC to normal mode */
+               status = UpdateReg(state, EP3);
+               if (status < 0)
+                       break;
+
+       } while (0);
+       return status;
+}
+
+static int sleep(struct dvb_frontend *fe)
+{
+       struct tda_state *state = fe->tuner_priv;
+
+       StandBy(state);
+       return 0;
+}
+
+static int init(struct dvb_frontend *fe)
+{
+       return 0;
+}
+
+static int release(struct dvb_frontend *fe)
+{
+       kfree(fe->tuner_priv);
+       fe->tuner_priv = NULL;
+       return 0;
+}
+
+/*
+ * As defined on EN 300 429 Annex A and on ITU-T J.83 annex A, the DVB-C
+ * roll-off factor is 0.15.
+ * According with the specs, the amount of the needed bandwith is given by:
+ *     Bw = Symbol_rate * (1 + 0.15)
+ * As such, the maximum symbol rate supported by 6 MHz is
+ *     max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds
+ *NOTE: For ITU-T J.83 Annex C, the roll-off factor is 0.13. So:
+ *     max_symbol_rate = 6 MHz / 1.13 = 5309735 Baud
+ *     That means that an adjustment is needed for Japan,
+ *     but, as currently DRX-K is hardcoded to Annex A, let's stick
+ *     with 0.15 roll-off factor.
+ */
+#define MAX_SYMBOL_RATE_6MHz   5217391
+
+static int set_params(struct dvb_frontend *fe,
+                     struct dvb_frontend_parameters *params)
+{
+       struct tda_state *state = fe->tuner_priv;
+       int status = 0;
+       int Standard;
+
+       state->m_Frequency = params->frequency;
+
+       if (fe->ops.info.type == FE_OFDM)
+               switch (params->u.ofdm.bandwidth) {
+               case BANDWIDTH_6_MHZ:
+                       Standard = HF_DVBT_6MHZ;
+                       break;
+               case BANDWIDTH_7_MHZ:
+                       Standard = HF_DVBT_7MHZ;
+                       break;
+               default:
+               case BANDWIDTH_8_MHZ:
+                       Standard = HF_DVBT_8MHZ;
+                       break;
+               }
+       else if (fe->ops.info.type == FE_QAM) {
+               if (params->u.qam.symbol_rate <= MAX_SYMBOL_RATE_6MHz)
+                       Standard = HF_DVBC_6MHZ;
+               else
+                       Standard = HF_DVBC_8MHZ;
+       } else
+               return -EINVAL;
+       do {
+               status = RFTrackingFiltersCorrection(state, params->frequency);
+               if (status < 0)
+                       break;
+               status = ChannelConfiguration(state, params->frequency, Standard);
+               if (status < 0)
+                       break;
+
+               msleep(state->m_SettlingTime);  /* Allow AGC's to settle down */
+       } while (0);
+       return status;
+}
+
+#if 0
+static int GetSignalStrength(s32 *pSignalStrength, u32 RFAgc, u32 IFAgc)
+{
+       if (IFAgc < 500) {
+               /* Scale this from 0 to 50000 */
+               *pSignalStrength = IFAgc * 100;
+       } else {
+               /* Scale range 500-1500 to 50000-80000 */
+               *pSignalStrength = 50000 + (IFAgc - 500) * 30;
+       }
+
+       return 0;
+}
+#endif
+
+static int get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       struct tda_state *state = fe->tuner_priv;
+
+       *frequency = state->IF;
+       return 0;
+}
+
+static int get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+       /* struct tda_state *state = fe->tuner_priv; */
+       /* *bandwidth = priv->bandwidth; */
+       return 0;
+}
+
+
+static struct dvb_tuner_ops tuner_ops = {
+       .info = {
+               .name = "NXP TDA18271C2D",
+               .frequency_min  =  47125000,
+               .frequency_max  = 865000000,
+               .frequency_step =     62500
+       },
+       .init              = init,
+       .sleep             = sleep,
+       .set_params        = set_params,
+       .release           = release,
+       .get_frequency     = get_frequency,
+       .get_bandwidth     = get_bandwidth,
+};
+
+struct dvb_frontend *tda18271c2dd_attach(struct dvb_frontend *fe,
+                                        struct i2c_adapter *i2c, u8 adr)
+{
+       struct tda_state *state;
+
+       state = kzalloc(sizeof(struct tda_state), GFP_KERNEL);
+       if (!state)
+               return NULL;
+
+       fe->tuner_priv = state;
+       state->adr = adr;
+       state->i2c = i2c;
+       memcpy(&fe->ops.tuner_ops, &tuner_ops, sizeof(struct dvb_tuner_ops));
+       reset(state);
+       InitCal(state);
+
+       return fe;
+}
+EXPORT_SYMBOL_GPL(tda18271c2dd_attach);
+
+MODULE_DESCRIPTION("TDA18271C2 driver");
+MODULE_AUTHOR("DD");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/tda18271c2dd.h b/drivers/media/dvb/frontends/tda18271c2dd.h
new file mode 100644 (file)
index 0000000..1389c74
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _TDA18271C2DD_H_
+#define _TDA18271C2DD_H_
+#if defined(CONFIG_DVB_TDA18271C2DD) || (defined(CONFIG_DVB_TDA18271C2DD_MODULE) \
+        && defined(MODULE))
+struct dvb_frontend *tda18271c2dd_attach(struct dvb_frontend *fe,
+                                        struct i2c_adapter *i2c, u8 adr);
+#else
+static inline struct dvb_frontend *tda18271c2dd_attach(struct dvb_frontend *fe,
+                                        struct i2c_adapter *i2c, u8 adr)
+{
+        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+        return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/dvb/frontends/tda18271c2dd_maps.h b/drivers/media/dvb/frontends/tda18271c2dd_maps.h
new file mode 100644 (file)
index 0000000..b87661b
--- /dev/null
@@ -0,0 +1,814 @@
+enum HF_S {
+       HF_None = 0, HF_B, HF_DK, HF_G, HF_I, HF_L, HF_L1, HF_MN, HF_FM_Radio,
+       HF_AnalogMax, HF_DVBT_6MHZ, HF_DVBT_7MHZ, HF_DVBT_8MHZ,
+       HF_DVBT, HF_ATSC,  HF_DVBC_6MHZ,  HF_DVBC_7MHZ,
+       HF_DVBC_8MHZ, HF_DVBC
+};
+
+struct SStandardParam m_StandardTable[] = {
+       {       0,        0, 0x00, 0x00 },    /* HF_None */
+       { 6000000,  7000000, 0x1D, 0x2C },    /* HF_B, */
+       { 6900000,  8000000, 0x1E, 0x2C },    /* HF_DK, */
+       { 7100000,  8000000, 0x1E, 0x2C },    /* HF_G, */
+       { 7250000,  8000000, 0x1E, 0x2C },    /* HF_I, */
+       { 6900000,  8000000, 0x1E, 0x2C },    /* HF_L, */
+       { 1250000,  8000000, 0x1E, 0x2C },    /* HF_L1, */
+       { 5400000,  6000000, 0x1C, 0x2C },    /* HF_MN, */
+       { 1250000,   500000, 0x18, 0x2C },    /* HF_FM_Radio, */
+       {       0,        0, 0x00, 0x00 },    /* HF_AnalogMax (Unused) */
+       { 3300000,  6000000, 0x1C, 0x58 },    /* HF_DVBT_6MHZ */
+       { 3500000,  7000000, 0x1C, 0x37 },    /* HF_DVBT_7MHZ */
+       { 4000000,  8000000, 0x1D, 0x37 },    /* HF_DVBT_8MHZ */
+       {       0,        0, 0x00, 0x00 },    /* HF_DVBT (Unused) */
+       { 5000000,  6000000, 0x1C, 0x37 },    /* HF_ATSC  (center = 3.25 MHz) */
+       { 4000000,  6000000, 0x1D, 0x58 },    /* HF_DVBC_6MHZ (Chicago) */
+       { 4500000,  7000000, 0x1E, 0x37 },    /* HF_DVBC_7MHZ (not documented by NXP) */
+       { 5000000,  8000000, 0x1F, 0x37 },    /* HF_DVBC_8MHZ */
+       {       0,        0, 0x00, 0x00 },    /* HF_DVBC (Unused) */
+};
+
+struct SMap  m_BP_Filter_Map[] = {
+       {   62000000,  0x00 },
+       {   84000000,  0x01 },
+       {  100000000,  0x02 },
+       {  140000000,  0x03 },
+       {  170000000,  0x04 },
+       {  180000000,  0x05 },
+       {  865000000,  0x06 },
+       {          0,  0x00 },    /* Table End */
+};
+
+static struct SMapI m_RF_Cal_Map[] = {
+       {   41000000,  0x0F },
+       {   43000000,  0x1C },
+       {   45000000,  0x2F },
+       {   46000000,  0x39 },
+       {   47000000,  0x40 },
+       {   47900000,  0x50 },
+       {   49100000,  0x16 },
+       {   50000000,  0x18 },
+       {   51000000,  0x20 },
+       {   53000000,  0x28 },
+       {   55000000,  0x2B },
+       {   56000000,  0x32 },
+       {   57000000,  0x35 },
+       {   58000000,  0x3E },
+       {   59000000,  0x43 },
+       {   60000000,  0x4E },
+       {   61100000,  0x55 },
+       {   63000000,  0x0F },
+       {   64000000,  0x11 },
+       {   65000000,  0x12 },
+       {   66000000,  0x15 },
+       {   67000000,  0x16 },
+       {   68000000,  0x17 },
+       {   70000000,  0x19 },
+       {   71000000,  0x1C },
+       {   72000000,  0x1D },
+       {   73000000,  0x1F },
+       {   74000000,  0x20 },
+       {   75000000,  0x21 },
+       {   76000000,  0x24 },
+       {   77000000,  0x25 },
+       {   78000000,  0x27 },
+       {   80000000,  0x28 },
+       {   81000000,  0x29 },
+       {   82000000,  0x2D },
+       {   83000000,  0x2E },
+       {   84000000,  0x2F },
+       {   85000000,  0x31 },
+       {   86000000,  0x33 },
+       {   87000000,  0x34 },
+       {   88000000,  0x35 },
+       {   89000000,  0x37 },
+       {   90000000,  0x38 },
+       {   91000000,  0x39 },
+       {   93000000,  0x3C },
+       {   94000000,  0x3E },
+       {   95000000,  0x3F },
+       {   96000000,  0x40 },
+       {   97000000,  0x42 },
+       {   99000000,  0x45 },
+       {  100000000,  0x46 },
+       {  102000000,  0x48 },
+       {  103000000,  0x4A },
+       {  105000000,  0x4D },
+       {  106000000,  0x4E },
+       {  107000000,  0x50 },
+       {  108000000,  0x51 },
+       {  110000000,  0x54 },
+       {  111000000,  0x56 },
+       {  112000000,  0x57 },
+       {  113000000,  0x58 },
+       {  114000000,  0x59 },
+       {  115000000,  0x5C },
+       {  116000000,  0x5D },
+       {  117000000,  0x5F },
+       {  119000000,  0x60 },
+       {  120000000,  0x64 },
+       {  121000000,  0x65 },
+       {  122000000,  0x66 },
+       {  123000000,  0x68 },
+       {  124000000,  0x69 },
+       {  125000000,  0x6C },
+       {  126000000,  0x6D },
+       {  127000000,  0x6E },
+       {  128000000,  0x70 },
+       {  129000000,  0x71 },
+       {  130000000,  0x75 },
+       {  131000000,  0x77 },
+       {  132000000,  0x78 },
+       {  133000000,  0x7B },
+       {  134000000,  0x7E },
+       {  135000000,  0x81 },
+       {  136000000,  0x82 },
+       {  137000000,  0x87 },
+       {  138000000,  0x88 },
+       {  139000000,  0x8D },
+       {  140000000,  0x8E },
+       {  141000000,  0x91 },
+       {  142000000,  0x95 },
+       {  143000000,  0x9A },
+       {  144000000,  0x9D },
+       {  145000000,  0xA1 },
+       {  146000000,  0xA2 },
+       {  147000000,  0xA4 },
+       {  148000000,  0xA9 },
+       {  149000000,  0xAE },
+       {  150000000,  0xB0 },
+       {  151000000,  0xB1 },
+       {  152000000,  0xB7 },
+       {  152600000,  0xBD },
+       {  154000000,  0x20 },
+       {  155000000,  0x22 },
+       {  156000000,  0x24 },
+       {  157000000,  0x25 },
+       {  158000000,  0x27 },
+       {  159000000,  0x29 },
+       {  160000000,  0x2C },
+       {  161000000,  0x2D },
+       {  163000000,  0x2E },
+       {  164000000,  0x2F },
+       {  164700000,  0x30 },
+       {  166000000,  0x11 },
+       {  167000000,  0x12 },
+       {  168000000,  0x13 },
+       {  169000000,  0x14 },
+       {  170000000,  0x15 },
+       {  172000000,  0x16 },
+       {  173000000,  0x17 },
+       {  174000000,  0x18 },
+       {  175000000,  0x1A },
+       {  176000000,  0x1B },
+       {  178000000,  0x1D },
+       {  179000000,  0x1E },
+       {  180000000,  0x1F },
+       {  181000000,  0x20 },
+       {  182000000,  0x21 },
+       {  183000000,  0x22 },
+       {  184000000,  0x24 },
+       {  185000000,  0x25 },
+       {  186000000,  0x26 },
+       {  187000000,  0x27 },
+       {  188000000,  0x29 },
+       {  189000000,  0x2A },
+       {  190000000,  0x2C },
+       {  191000000,  0x2D },
+       {  192000000,  0x2E },
+       {  193000000,  0x2F },
+       {  194000000,  0x30 },
+       {  195000000,  0x33 },
+       {  196000000,  0x35 },
+       {  198000000,  0x36 },
+       {  200000000,  0x38 },
+       {  201000000,  0x3C },
+       {  202000000,  0x3D },
+       {  203500000,  0x3E },
+       {  206000000,  0x0E },
+       {  208000000,  0x0F },
+       {  212000000,  0x10 },
+       {  216000000,  0x11 },
+       {  217000000,  0x12 },
+       {  218000000,  0x13 },
+       {  220000000,  0x14 },
+       {  222000000,  0x15 },
+       {  225000000,  0x16 },
+       {  228000000,  0x17 },
+       {  231000000,  0x18 },
+       {  234000000,  0x19 },
+       {  235000000,  0x1A },
+       {  236000000,  0x1B },
+       {  237000000,  0x1C },
+       {  240000000,  0x1D },
+       {  242000000,  0x1E },
+       {  244000000,  0x1F },
+       {  247000000,  0x20 },
+       {  249000000,  0x21 },
+       {  252000000,  0x22 },
+       {  253000000,  0x23 },
+       {  254000000,  0x24 },
+       {  256000000,  0x25 },
+       {  259000000,  0x26 },
+       {  262000000,  0x27 },
+       {  264000000,  0x28 },
+       {  267000000,  0x29 },
+       {  269000000,  0x2A },
+       {  271000000,  0x2B },
+       {  273000000,  0x2C },
+       {  275000000,  0x2D },
+       {  277000000,  0x2E },
+       {  279000000,  0x2F },
+       {  282000000,  0x30 },
+       {  284000000,  0x31 },
+       {  286000000,  0x32 },
+       {  287000000,  0x33 },
+       {  290000000,  0x34 },
+       {  293000000,  0x35 },
+       {  295000000,  0x36 },
+       {  297000000,  0x37 },
+       {  300000000,  0x38 },
+       {  303000000,  0x39 },
+       {  305000000,  0x3A },
+       {  306000000,  0x3B },
+       {  307000000,  0x3C },
+       {  310000000,  0x3D },
+       {  312000000,  0x3E },
+       {  315000000,  0x3F },
+       {  318000000,  0x40 },
+       {  320000000,  0x41 },
+       {  323000000,  0x42 },
+       {  324000000,  0x43 },
+       {  325000000,  0x44 },
+       {  327000000,  0x45 },
+       {  331000000,  0x46 },
+       {  334000000,  0x47 },
+       {  337000000,  0x48 },
+       {  339000000,  0x49 },
+       {  340000000,  0x4A },
+       {  341000000,  0x4B },
+       {  343000000,  0x4C },
+       {  345000000,  0x4D },
+       {  349000000,  0x4E },
+       {  352000000,  0x4F },
+       {  353000000,  0x50 },
+       {  355000000,  0x51 },
+       {  357000000,  0x52 },
+       {  359000000,  0x53 },
+       {  361000000,  0x54 },
+       {  362000000,  0x55 },
+       {  364000000,  0x56 },
+       {  368000000,  0x57 },
+       {  370000000,  0x58 },
+       {  372000000,  0x59 },
+       {  375000000,  0x5A },
+       {  376000000,  0x5B },
+       {  377000000,  0x5C },
+       {  379000000,  0x5D },
+       {  382000000,  0x5E },
+       {  384000000,  0x5F },
+       {  385000000,  0x60 },
+       {  386000000,  0x61 },
+       {  388000000,  0x62 },
+       {  390000000,  0x63 },
+       {  393000000,  0x64 },
+       {  394000000,  0x65 },
+       {  396000000,  0x66 },
+       {  397000000,  0x67 },
+       {  398000000,  0x68 },
+       {  400000000,  0x69 },
+       {  402000000,  0x6A },
+       {  403000000,  0x6B },
+       {  407000000,  0x6C },
+       {  408000000,  0x6D },
+       {  409000000,  0x6E },
+       {  410000000,  0x6F },
+       {  411000000,  0x70 },
+       {  412000000,  0x71 },
+       {  413000000,  0x72 },
+       {  414000000,  0x73 },
+       {  417000000,  0x74 },
+       {  418000000,  0x75 },
+       {  420000000,  0x76 },
+       {  422000000,  0x77 },
+       {  423000000,  0x78 },
+       {  424000000,  0x79 },
+       {  427000000,  0x7A },
+       {  428000000,  0x7B },
+       {  429000000,  0x7D },
+       {  432000000,  0x7F },
+       {  434000000,  0x80 },
+       {  435000000,  0x81 },
+       {  436000000,  0x83 },
+       {  437000000,  0x84 },
+       {  438000000,  0x85 },
+       {  439000000,  0x86 },
+       {  440000000,  0x87 },
+       {  441000000,  0x88 },
+       {  442000000,  0x89 },
+       {  445000000,  0x8A },
+       {  446000000,  0x8B },
+       {  447000000,  0x8C },
+       {  448000000,  0x8E },
+       {  449000000,  0x8F },
+       {  450000000,  0x90 },
+       {  452000000,  0x91 },
+       {  453000000,  0x93 },
+       {  454000000,  0x94 },
+       {  456000000,  0x96 },
+       {  457800000,  0x98 },
+       {  461000000,  0x11 },
+       {  468000000,  0x12 },
+       {  472000000,  0x13 },
+       {  473000000,  0x14 },
+       {  474000000,  0x15 },
+       {  481000000,  0x16 },
+       {  486000000,  0x17 },
+       {  491000000,  0x18 },
+       {  498000000,  0x19 },
+       {  499000000,  0x1A },
+       {  501000000,  0x1B },
+       {  506000000,  0x1C },
+       {  511000000,  0x1D },
+       {  516000000,  0x1E },
+       {  520000000,  0x1F },
+       {  521000000,  0x20 },
+       {  525000000,  0x21 },
+       {  529000000,  0x22 },
+       {  533000000,  0x23 },
+       {  539000000,  0x24 },
+       {  541000000,  0x25 },
+       {  547000000,  0x26 },
+       {  549000000,  0x27 },
+       {  551000000,  0x28 },
+       {  556000000,  0x29 },
+       {  561000000,  0x2A },
+       {  563000000,  0x2B },
+       {  565000000,  0x2C },
+       {  569000000,  0x2D },
+       {  571000000,  0x2E },
+       {  577000000,  0x2F },
+       {  580000000,  0x30 },
+       {  582000000,  0x31 },
+       {  584000000,  0x32 },
+       {  588000000,  0x33 },
+       {  591000000,  0x34 },
+       {  596000000,  0x35 },
+       {  598000000,  0x36 },
+       {  603000000,  0x37 },
+       {  604000000,  0x38 },
+       {  606000000,  0x39 },
+       {  612000000,  0x3A },
+       {  615000000,  0x3B },
+       {  617000000,  0x3C },
+       {  621000000,  0x3D },
+       {  622000000,  0x3E },
+       {  625000000,  0x3F },
+       {  632000000,  0x40 },
+       {  633000000,  0x41 },
+       {  634000000,  0x42 },
+       {  642000000,  0x43 },
+       {  643000000,  0x44 },
+       {  647000000,  0x45 },
+       {  650000000,  0x46 },
+       {  652000000,  0x47 },
+       {  657000000,  0x48 },
+       {  661000000,  0x49 },
+       {  662000000,  0x4A },
+       {  665000000,  0x4B },
+       {  667000000,  0x4C },
+       {  670000000,  0x4D },
+       {  673000000,  0x4E },
+       {  676000000,  0x4F },
+       {  677000000,  0x50 },
+       {  681000000,  0x51 },
+       {  683000000,  0x52 },
+       {  686000000,  0x53 },
+       {  688000000,  0x54 },
+       {  689000000,  0x55 },
+       {  691000000,  0x56 },
+       {  695000000,  0x57 },
+       {  698000000,  0x58 },
+       {  703000000,  0x59 },
+       {  704000000,  0x5A },
+       {  705000000,  0x5B },
+       {  707000000,  0x5C },
+       {  710000000,  0x5D },
+       {  712000000,  0x5E },
+       {  717000000,  0x5F },
+       {  718000000,  0x60 },
+       {  721000000,  0x61 },
+       {  722000000,  0x62 },
+       {  723000000,  0x63 },
+       {  725000000,  0x64 },
+       {  727000000,  0x65 },
+       {  730000000,  0x66 },
+       {  732000000,  0x67 },
+       {  735000000,  0x68 },
+       {  740000000,  0x69 },
+       {  741000000,  0x6A },
+       {  742000000,  0x6B },
+       {  743000000,  0x6C },
+       {  745000000,  0x6D },
+       {  747000000,  0x6E },
+       {  748000000,  0x6F },
+       {  750000000,  0x70 },
+       {  752000000,  0x71 },
+       {  754000000,  0x72 },
+       {  757000000,  0x73 },
+       {  758000000,  0x74 },
+       {  760000000,  0x75 },
+       {  763000000,  0x76 },
+       {  764000000,  0x77 },
+       {  766000000,  0x78 },
+       {  767000000,  0x79 },
+       {  768000000,  0x7A },
+       {  773000000,  0x7B },
+       {  774000000,  0x7C },
+       {  776000000,  0x7D },
+       {  777000000,  0x7E },
+       {  778000000,  0x7F },
+       {  779000000,  0x80 },
+       {  781000000,  0x81 },
+       {  783000000,  0x82 },
+       {  784000000,  0x83 },
+       {  785000000,  0x84 },
+       {  786000000,  0x85 },
+       {  793000000,  0x86 },
+       {  794000000,  0x87 },
+       {  795000000,  0x88 },
+       {  797000000,  0x89 },
+       {  799000000,  0x8A },
+       {  801000000,  0x8B },
+       {  802000000,  0x8C },
+       {  803000000,  0x8D },
+       {  804000000,  0x8E },
+       {  810000000,  0x90 },
+       {  811000000,  0x91 },
+       {  812000000,  0x92 },
+       {  814000000,  0x93 },
+       {  816000000,  0x94 },
+       {  817000000,  0x96 },
+       {  818000000,  0x97 },
+       {  820000000,  0x98 },
+       {  821000000,  0x99 },
+       {  822000000,  0x9A },
+       {  828000000,  0x9B },
+       {  829000000,  0x9D },
+       {  830000000,  0x9F },
+       {  831000000,  0xA0 },
+       {  833000000,  0xA1 },
+       {  835000000,  0xA2 },
+       {  836000000,  0xA3 },
+       {  837000000,  0xA4 },
+       {  838000000,  0xA6 },
+       {  840000000,  0xA8 },
+       {  842000000,  0xA9 },
+       {  845000000,  0xAA },
+       {  846000000,  0xAB },
+       {  847000000,  0xAD },
+       {  848000000,  0xAE },
+       {  852000000,  0xAF },
+       {  853000000,  0xB0 },
+       {  858000000,  0xB1 },
+       {  860000000,  0xB2 },
+       {  861000000,  0xB3 },
+       {  862000000,  0xB4 },
+       {  863000000,  0xB6 },
+       {  864000000,  0xB8 },
+       {  865000000,  0xB9 },
+       {          0,  0x00 },    /* Table End */
+};
+
+
+static struct SMap2  m_KM_Map[] = {
+       {   47900000,  3, 2 },
+       {   61100000,  3, 1 },
+       {  350000000,  3, 0 },
+       {  720000000,  2, 1 },
+       {  865000000,  3, 3 },
+       {          0,  0x00 },    /* Table End */
+};
+
+static struct SMap2 m_Main_PLL_Map[] = {
+       {  33125000, 0x57, 0xF0 },
+       {  35500000, 0x56, 0xE0 },
+       {  38188000, 0x55, 0xD0 },
+       {  41375000, 0x54, 0xC0 },
+       {  45125000, 0x53, 0xB0 },
+       {  49688000, 0x52, 0xA0 },
+       {  55188000, 0x51, 0x90 },
+       {  62125000, 0x50, 0x80 },
+       {  66250000, 0x47, 0x78 },
+       {  71000000, 0x46, 0x70 },
+       {  76375000, 0x45, 0x68 },
+       {  82750000, 0x44, 0x60 },
+       {  90250000, 0x43, 0x58 },
+       {  99375000, 0x42, 0x50 },
+       { 110375000, 0x41, 0x48 },
+       { 124250000, 0x40, 0x40 },
+       { 132500000, 0x37, 0x3C },
+       { 142000000, 0x36, 0x38 },
+       { 152750000, 0x35, 0x34 },
+       { 165500000, 0x34, 0x30 },
+       { 180500000, 0x33, 0x2C },
+       { 198750000, 0x32, 0x28 },
+       { 220750000, 0x31, 0x24 },
+       { 248500000, 0x30, 0x20 },
+       { 265000000, 0x27, 0x1E },
+       { 284000000, 0x26, 0x1C },
+       { 305500000, 0x25, 0x1A },
+       { 331000000, 0x24, 0x18 },
+       { 361000000, 0x23, 0x16 },
+       { 397500000, 0x22, 0x14 },
+       { 441500000, 0x21, 0x12 },
+       { 497000000, 0x20, 0x10 },
+       { 530000000, 0x17, 0x0F },
+       { 568000000, 0x16, 0x0E },
+       { 611000000, 0x15, 0x0D },
+       { 662000000, 0x14, 0x0C },
+       { 722000000, 0x13, 0x0B },
+       { 795000000, 0x12, 0x0A },
+       { 883000000, 0x11, 0x09 },
+       { 994000000, 0x10, 0x08 },
+       {         0, 0x00, 0x00 },    /* Table End */
+};
+
+static struct SMap2 m_Cal_PLL_Map[] = {
+       {  33813000, 0xDD, 0xD0 },
+       {  36625000, 0xDC, 0xC0 },
+       {  39938000, 0xDB, 0xB0 },
+       {  43938000, 0xDA, 0xA0 },
+       {  48813000, 0xD9, 0x90 },
+       {  54938000, 0xD8, 0x80 },
+       {  62813000, 0xD3, 0x70 },
+       {  67625000, 0xCD, 0x68 },
+       {  73250000, 0xCC, 0x60 },
+       {  79875000, 0xCB, 0x58 },
+       {  87875000, 0xCA, 0x50 },
+       {  97625000, 0xC9, 0x48 },
+       { 109875000, 0xC8, 0x40 },
+       { 125625000, 0xC3, 0x38 },
+       { 135250000, 0xBD, 0x34 },
+       { 146500000, 0xBC, 0x30 },
+       { 159750000, 0xBB, 0x2C },
+       { 175750000, 0xBA, 0x28 },
+       { 195250000, 0xB9, 0x24 },
+       { 219750000, 0xB8, 0x20 },
+       { 251250000, 0xB3, 0x1C },
+       { 270500000, 0xAD, 0x1A },
+       { 293000000, 0xAC, 0x18 },
+       { 319500000, 0xAB, 0x16 },
+       { 351500000, 0xAA, 0x14 },
+       { 390500000, 0xA9, 0x12 },
+       { 439500000, 0xA8, 0x10 },
+       { 502500000, 0xA3, 0x0E },
+       { 541000000, 0x9D, 0x0D },
+       { 586000000, 0x9C, 0x0C },
+       { 639000000, 0x9B, 0x0B },
+       { 703000000, 0x9A, 0x0A },
+       { 781000000, 0x99, 0x09 },
+       { 879000000, 0x98, 0x08 },
+       {         0, 0x00, 0x00 },    /* Table End */
+};
+
+static struct SMap  m_GainTaper_Map[] = {
+       {  45400000, 0x1F },
+       {  45800000, 0x1E },
+       {  46200000, 0x1D },
+       {  46700000, 0x1C },
+       {  47100000, 0x1B },
+       {  47500000, 0x1A },
+       {  47900000, 0x19 },
+       {  49600000, 0x17 },
+       {  51200000, 0x16 },
+       {  52900000, 0x15 },
+       {  54500000, 0x14 },
+       {  56200000, 0x13 },
+       {  57800000, 0x12 },
+       {  59500000, 0x11 },
+       {  61100000, 0x10 },
+       {  67600000, 0x0D },
+       {  74200000, 0x0C },
+       {  80700000, 0x0B },
+       {  87200000, 0x0A },
+       {  93800000, 0x09 },
+       { 100300000, 0x08 },
+       { 106900000, 0x07 },
+       { 113400000, 0x06 },
+       { 119900000, 0x05 },
+       { 126500000, 0x04 },
+       { 133000000, 0x03 },
+       { 139500000, 0x02 },
+       { 146100000, 0x01 },
+       { 152600000, 0x00 },
+       { 154300000, 0x1F },
+       { 156100000, 0x1E },
+       { 157800000, 0x1D },
+       { 159500000, 0x1C },
+       { 161200000, 0x1B },
+       { 163000000, 0x1A },
+       { 164700000, 0x19 },
+       { 170200000, 0x17 },
+       { 175800000, 0x16 },
+       { 181300000, 0x15 },
+       { 186900000, 0x14 },
+       { 192400000, 0x13 },
+       { 198000000, 0x12 },
+       { 203500000, 0x11 },
+       { 216200000, 0x14 },
+       { 228900000, 0x13 },
+       { 241600000, 0x12 },
+       { 254400000, 0x11 },
+       { 267100000, 0x10 },
+       { 279800000, 0x0F },
+       { 292500000, 0x0E },
+       { 305200000, 0x0D },
+       { 317900000, 0x0C },
+       { 330700000, 0x0B },
+       { 343400000, 0x0A },
+       { 356100000, 0x09 },
+       { 368800000, 0x08 },
+       { 381500000, 0x07 },
+       { 394200000, 0x06 },
+       { 406900000, 0x05 },
+       { 419700000, 0x04 },
+       { 432400000, 0x03 },
+       { 445100000, 0x02 },
+       { 457800000, 0x01 },
+       { 476300000, 0x19 },
+       { 494800000, 0x18 },
+       { 513300000, 0x17 },
+       { 531800000, 0x16 },
+       { 550300000, 0x15 },
+       { 568900000, 0x14 },
+       { 587400000, 0x13 },
+       { 605900000, 0x12 },
+       { 624400000, 0x11 },
+       { 642900000, 0x10 },
+       { 661400000, 0x0F },
+       { 679900000, 0x0E },
+       { 698400000, 0x0D },
+       { 716900000, 0x0C },
+       { 735400000, 0x0B },
+       { 753900000, 0x0A },
+       { 772500000, 0x09 },
+       { 791000000, 0x08 },
+       { 809500000, 0x07 },
+       { 828000000, 0x06 },
+       { 846500000, 0x05 },
+       { 865000000, 0x04 },
+       {         0, 0x00 },    /* Table End */
+};
+
+static struct SMap m_RF_Cal_DC_Over_DT_Map[] = {
+       {  47900000, 0x00 },
+       {  55000000, 0x00 },
+       {  61100000, 0x0A },
+       {  64000000, 0x0A },
+       {  82000000, 0x14 },
+       {  84000000, 0x19 },
+       { 119000000, 0x1C },
+       { 124000000, 0x20 },
+       { 129000000, 0x2A },
+       { 134000000, 0x32 },
+       { 139000000, 0x39 },
+       { 144000000, 0x3E },
+       { 149000000, 0x3F },
+       { 152600000, 0x40 },
+       { 154000000, 0x40 },
+       { 164700000, 0x41 },
+       { 203500000, 0x32 },
+       { 353000000, 0x19 },
+       { 356000000, 0x1A },
+       { 359000000, 0x1B },
+       { 363000000, 0x1C },
+       { 366000000, 0x1D },
+       { 369000000, 0x1E },
+       { 373000000, 0x1F },
+       { 376000000, 0x20 },
+       { 379000000, 0x21 },
+       { 383000000, 0x22 },
+       { 386000000, 0x23 },
+       { 389000000, 0x24 },
+       { 393000000, 0x25 },
+       { 396000000, 0x26 },
+       { 399000000, 0x27 },
+       { 402000000, 0x28 },
+       { 404000000, 0x29 },
+       { 407000000, 0x2A },
+       { 409000000, 0x2B },
+       { 412000000, 0x2C },
+       { 414000000, 0x2D },
+       { 417000000, 0x2E },
+       { 419000000, 0x2F },
+       { 422000000, 0x30 },
+       { 424000000, 0x31 },
+       { 427000000, 0x32 },
+       { 429000000, 0x33 },
+       { 432000000, 0x34 },
+       { 434000000, 0x35 },
+       { 437000000, 0x36 },
+       { 439000000, 0x37 },
+       { 442000000, 0x38 },
+       { 444000000, 0x39 },
+       { 447000000, 0x3A },
+       { 449000000, 0x3B },
+       { 457800000, 0x3C },
+       { 465000000, 0x0F },
+       { 477000000, 0x12 },
+       { 483000000, 0x14 },
+       { 502000000, 0x19 },
+       { 508000000, 0x1B },
+       { 519000000, 0x1C },
+       { 522000000, 0x1D },
+       { 524000000, 0x1E },
+       { 534000000, 0x1F },
+       { 549000000, 0x20 },
+       { 554000000, 0x22 },
+       { 584000000, 0x24 },
+       { 589000000, 0x26 },
+       { 658000000, 0x27 },
+       { 664000000, 0x2C },
+       { 669000000, 0x2D },
+       { 699000000, 0x2E },
+       { 704000000, 0x30 },
+       { 709000000, 0x31 },
+       { 714000000, 0x32 },
+       { 724000000, 0x33 },
+       { 729000000, 0x36 },
+       { 739000000, 0x38 },
+       { 744000000, 0x39 },
+       { 749000000, 0x3B },
+       { 754000000, 0x3C },
+       { 759000000, 0x3D },
+       { 764000000, 0x3E },
+       { 769000000, 0x3F },
+       { 774000000, 0x40 },
+       { 779000000, 0x41 },
+       { 784000000, 0x43 },
+       { 789000000, 0x46 },
+       { 794000000, 0x48 },
+       { 799000000, 0x4B },
+       { 804000000, 0x4F },
+       { 809000000, 0x54 },
+       { 814000000, 0x59 },
+       { 819000000, 0x5D },
+       { 824000000, 0x61 },
+       { 829000000, 0x68 },
+       { 834000000, 0x6E },
+       { 839000000, 0x75 },
+       { 844000000, 0x7E },
+       { 849000000, 0x82 },
+       { 854000000, 0x84 },
+       { 859000000, 0x8F },
+       { 865000000, 0x9A },
+       {         0, 0x00 },    /* Table End */
+};
+
+
+static struct SMap  m_IR_Meas_Map[] = {
+       { 200000000, 0x05 },
+       { 400000000, 0x06 },
+       { 865000000, 0x07 },
+       {         0, 0x00 },    /* Table End */
+};
+
+static struct SMap2 m_CID_Target_Map[] = {
+       {  46000000, 0x04, 18 },
+       {  52200000, 0x0A, 15 },
+       {  70100000, 0x01, 40 },
+       { 136800000, 0x18, 40 },
+       { 156700000, 0x18, 40 },
+       { 186250000, 0x0A, 40 },
+       { 230000000, 0x0A, 40 },
+       { 345000000, 0x18, 40 },
+       { 426000000, 0x0E, 40 },
+       { 489500000, 0x1E, 40 },
+       { 697500000, 0x32, 40 },
+       { 842000000, 0x3A, 40 },
+       {         0, 0x00,  0 },    /* Table End */
+};
+
+static struct SRFBandMap  m_RF_Band_Map[7] = {
+       {   47900000,   46000000,           0,          0},
+       {   61100000,   52200000,           0,          0},
+       {  152600000,   70100000,   136800000,          0},
+       {  164700000,  156700000,           0,          0},
+       {  203500000,  186250000,           0,          0},
+       {  457800000,  230000000,   345000000,  426000000},
+       {  865000000,  489500000,   697500000,  842000000},
+};
+
+u8 m_Thermometer_Map_1[16] = {
+       60, 62, 66, 64,
+       74, 72, 68, 70,
+       90, 88, 84, 86,
+       76, 78, 82, 80,
+};
+
+u8 m_Thermometer_Map_2[16] = {
+       92, 94, 98, 96,
+       106, 104, 100, 102,
+       122, 120, 116, 118,
+       108, 110, 114, 112,
+};
index cec242b..64c8470 100644 (file)
@@ -5,6 +5,8 @@ config DVB_NGENE
        select DVB_STV6110x if !DVB_FE_CUSTOMISE
        select DVB_STV090x if !DVB_FE_CUSTOMISE
        select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+       select DVB_DRXK if !DVB_FE_CUSTOMISE
+       select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE
        select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE
        ---help---
          Support for Micronas PCI express cards with nGene bridge.
index fcf4be9..0564192 100644 (file)
@@ -40,6 +40,8 @@
 #include "lnbh24.h"
 #include "lgdt330x.h"
 #include "mt2131.h"
+#include "tda18271c2dd.h"
+#include "drxk.h"
 
 
 /****************************************************************************/
@@ -83,6 +85,49 @@ static int tuner_attach_stv6110(struct ngene_channel *chan)
 }
 
 
+static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       struct ngene_channel *chan = fe->sec_priv;
+       int status;
+
+       if (enable) {
+               down(&chan->dev->pll_mutex);
+               status = chan->gate_ctrl(fe, 1);
+       } else {
+               status = chan->gate_ctrl(fe, 0);
+               up(&chan->dev->pll_mutex);
+       }
+       return status;
+}
+
+static int tuner_attach_tda18271(struct ngene_channel *chan)
+{
+       struct i2c_adapter *i2c;
+       struct dvb_frontend *fe;
+
+       i2c = &chan->dev->channel[0].i2c_adapter;
+       if (chan->fe->ops.i2c_gate_ctrl)
+               chan->fe->ops.i2c_gate_ctrl(chan->fe, 1);
+       fe = dvb_attach(tda18271c2dd_attach, chan->fe, i2c, 0x60);
+       if (chan->fe->ops.i2c_gate_ctrl)
+               chan->fe->ops.i2c_gate_ctrl(chan->fe, 0);
+       if (!fe) {
+               printk(KERN_ERR "No TDA18271 found!\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int tuner_attach_probe(struct ngene_channel *chan)
+{
+       if (chan->demod_type == 0)
+               return tuner_attach_stv6110(chan);
+       if (chan->demod_type == 1)
+               return tuner_attach_tda18271(chan);
+       return -EINVAL;
+}
+
 static int demod_attach_stv0900(struct ngene_channel *chan)
 {
        struct i2c_adapter *i2c;
@@ -130,6 +175,60 @@ static void cineS2_tuner_i2c_lock(struct dvb_frontend *fe, int lock)
                up(&chan->dev->pll_mutex);
 }
 
+static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val)
+{
+       struct i2c_msg msgs[1] = {{.addr = adr,  .flags = I2C_M_RD,
+                                  .buf  = val,  .len   = 1 } };
+       return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1;
+}
+
+static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr,
+                         u16 reg, u8 *val)
+{
+       u8 msg[2] = {reg>>8, reg&0xff};
+       struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
+                                  .buf  = msg, .len   = 2},
+                                 {.addr = adr, .flags = I2C_M_RD,
+                                  .buf  = val, .len   = 1} };
+       return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
+}
+
+static int port_has_stv0900(struct i2c_adapter *i2c, int port)
+{
+       u8 val;
+       if (i2c_read_reg16(i2c, 0x68+port/2, 0xf100, &val) < 0)
+               return 0;
+       return 1;
+}
+
+static int port_has_drxk(struct i2c_adapter *i2c, int port)
+{
+       u8 val;
+
+       if (i2c_read(i2c, 0x29+port, &val) < 0)
+               return 0;
+       return 1;
+}
+
+static int demod_attach_drxk(struct ngene_channel *chan,
+                            struct i2c_adapter *i2c)
+{
+       struct drxk_config config;
+
+       memset(&config, 0, sizeof(config));
+       config.adr = 0x29 + (chan->number ^ 2);
+
+       chan->fe = dvb_attach(drxk_attach, &config, i2c, &chan->fe2);
+       if (!chan->fe) {
+               printk(KERN_ERR "No DRXK found!\n");
+               return -ENODEV;
+       }
+       chan->fe->sec_priv = chan;
+       chan->gate_ctrl = chan->fe->ops.i2c_gate_ctrl;
+       chan->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
+       return 0;
+}
+
 static int cineS2_probe(struct ngene_channel *chan)
 {
        struct i2c_adapter *i2c;
@@ -144,43 +243,42 @@ static int cineS2_probe(struct ngene_channel *chan)
        else
                i2c = &chan->dev->channel[1].i2c_adapter;
 
-       fe_conf = chan->dev->card_info->fe_config[chan->number];
-       i2c_msg.addr = fe_conf->address;
-
-       /* probe demod */
-       i2c_msg.len = 2;
-       buf[0] = 0xf1;
-       buf[1] = 0x00;
-       rc = i2c_transfer(i2c, &i2c_msg, 1);
-       if (rc != 1)
-               return -ENODEV;
-
-       /* demod found, attach it */
-       rc = demod_attach_stv0900(chan);
-       if (rc < 0 || chan->number < 2)
-               return rc;
-
-       /* demod #2: reprogram outputs DPN1 & DPN2 */
-       i2c_msg.len = 3;
-       buf[0] = 0xf1;
-       switch (chan->number) {
-       case 2:
-               buf[1] = 0x5c;
-               buf[2] = 0xc2;
-               break;
-       case 3:
-               buf[1] = 0x61;
-               buf[2] = 0xcc;
-               break;
-       default:
+       if (port_has_stv0900(i2c, chan->number)) {
+               chan->demod_type = 0;
+               fe_conf = chan->dev->card_info->fe_config[chan->number];
+               /* demod found, attach it */
+               rc = demod_attach_stv0900(chan);
+               if (rc < 0 || chan->number < 2)
+                       return rc;
+
+               /* demod #2: reprogram outputs DPN1 & DPN2 */
+               i2c_msg.addr = fe_conf->address;
+               i2c_msg.len = 3;
+               buf[0] = 0xf1;
+               switch (chan->number) {
+               case 2:
+                       buf[1] = 0x5c;
+                       buf[2] = 0xc2;
+                       break;
+               case 3:
+                       buf[1] = 0x61;
+                       buf[2] = 0xcc;
+                       break;
+               default:
+                       return -ENODEV;
+               }
+               rc = i2c_transfer(i2c, &i2c_msg, 1);
+               if (rc != 1) {
+                       printk(KERN_ERR DEVICE_NAME ": could not setup DPNx\n");
+                       return -EIO;
+               }
+       } else if (port_has_drxk(i2c, chan->number^2)) {
+               chan->demod_type = 1;
+               demod_attach_drxk(chan, i2c);
+       } else {
+               printk(KERN_ERR "No demod found on chan %d\n", chan->number);
                return -ENODEV;
        }
-       rc = i2c_transfer(i2c, &i2c_msg, 1);
-       if (rc != 1) {
-               printk(KERN_ERR DEVICE_NAME ": could not setup DPNx\n");
-               return -EIO;
-       }
-
        return 0;
 }
 
@@ -306,7 +404,7 @@ static struct ngene_info ngene_info_satixS2v2 = {
        .io_type        = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN,
                           NGENE_IO_TSOUT},
        .demod_attach   = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe},
-       .tuner_attach   = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110},
+       .tuner_attach   = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_probe, tuner_attach_probe},
        .fe_config      = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2},
        .tuner_config   = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1},
        .lnb            = {0x0a, 0x08, 0x0b, 0x09},
@@ -321,7 +419,7 @@ static struct ngene_info ngene_info_cineS2v5 = {
        .io_type        = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN,
                           NGENE_IO_TSOUT},
        .demod_attach   = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe},
-       .tuner_attach   = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110},
+       .tuner_attach   = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_probe, tuner_attach_probe},
        .fe_config      = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2},
        .tuner_config   = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1},
        .lnb            = {0x0a, 0x08, 0x0b, 0x09},
@@ -331,13 +429,13 @@ static struct ngene_info ngene_info_cineS2v5 = {
 };
 
 
-static struct ngene_info ngene_info_duoFlexS2 = {
+static struct ngene_info ngene_info_duoFlex = {
        .type           = NGENE_SIDEWINDER,
-       .name           = "Digital Devices DuoFlex S2 miniPCIe",
+       .name           = "Digital Devices DuoFlex PCIe or miniPCIe",
        .io_type        = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN,
                           NGENE_IO_TSOUT},
        .demod_attach   = {cineS2_probe, cineS2_probe, cineS2_probe, cineS2_probe},
-       .tuner_attach   = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110},
+       .tuner_attach   = {tuner_attach_probe, tuner_attach_probe, tuner_attach_probe, tuner_attach_probe},
        .fe_config      = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2},
        .tuner_config   = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1},
        .lnb            = {0x0a, 0x08, 0x0b, 0x09},
@@ -385,8 +483,8 @@ static const struct pci_device_id ngene_id_tbl[] __devinitdata = {
        NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2),
        NGENE_ID(0x18c3, 0xdb02, ngene_info_satixS2v2),
        NGENE_ID(0x18c3, 0xdd00, ngene_info_cineS2v5),
-       NGENE_ID(0x18c3, 0xdd10, ngene_info_duoFlexS2),
-       NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlexS2),
+       NGENE_ID(0x18c3, 0xdd10, ngene_info_duoFlex),
+       NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlex),
        NGENE_ID(0x1461, 0x062e, ngene_info_m780),
        {0}
 };
index 6927c72..f129a93 100644 (file)
@@ -41,7 +41,7 @@
 
 #include "ngene.h"
 
-static int one_adapter = 1;
+static int one_adapter;
 module_param(one_adapter, int, 0444);
 MODULE_PARM_DESC(one_adapter, "Use only one adapter.");
 
@@ -461,7 +461,7 @@ static u8 TSFeatureDecoderSetup[8 * 5] = {
        0x42, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00,
        0x40, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXH */
        0x71, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXHser */
-       0x72, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* S2ser */
+       0x72, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* S2ser */
        0x40, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* LGDT3303 */
 };
 
@@ -507,7 +507,7 @@ void FillTSBuffer(void *Buffer, int Length, u32 Flags)
 {
        u32 *ptr = Buffer;
 
-       memset(Buffer, 0xff, Length);
+       memset(Buffer, TS_FILLER, Length);
        while (Length > 0) {
                if (Flags & DF_SWAP32)
                        *ptr = 0x471FFF10;
@@ -1443,6 +1443,9 @@ static void release_channel(struct ngene_channel *chan)
                chan->ci_dev = NULL;
        }
 
+       if (chan->fe2)
+               dvb_unregister_frontend(chan->fe2);
+
        if (chan->fe) {
                dvb_unregister_frontend(chan->fe);
                dvb_frontend_detach(chan->fe);
@@ -1534,6 +1537,14 @@ static int init_channel(struct ngene_channel *chan)
                        goto err;
                chan->has_demux = true;
        }
+       if (chan->fe2) {
+               if (dvb_register_frontend(adapter, chan->fe2) < 0)
+                       goto err;
+               chan->fe2->tuner_priv = chan->fe->tuner_priv;
+               memcpy(&chan->fe2->ops.tuner_ops,
+                      &chan->fe->ops.tuner_ops,
+                      sizeof(struct dvb_tuner_ops));
+       }
 
        if (chan->has_demux) {
                ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux",
@@ -1571,11 +1582,18 @@ static int init_channels(struct ngene *dev)
        return 0;
 }
 
+static struct cxd2099_cfg cxd_cfg = {
+       .bitrate = 62000,
+       .adr = 0x40,
+       .polarity = 0,
+       .clock_mode = 0,
+};
+
 static void cxd_attach(struct ngene *dev)
 {
        struct ngene_ci *ci = &dev->ci;
 
-       ci->en = cxd2099_attach(0x40, dev, &dev->channel[0].i2c_adapter);
+       ci->en = cxd2099_attach(&cxd_cfg, dev, &dev->channel[0].i2c_adapter);
        ci->dev = dev;
        return;
 }
index 0b49432..fcb16a6 100644 (file)
@@ -118,6 +118,16 @@ static void swap_buffer(u32 *p, u32 len)
        }
 }
 
+/* start of filler packet */
+static u8 fill_ts[] = { 0x47, 0x1f, 0xff, 0x10, TS_FILLER };
+
+/* #define DEBUG_CI_XFER */
+#ifdef DEBUG_CI_XFER
+static u32 ok;
+static u32 overflow;
+static u32 stripped;
+#endif
+
 void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
 {
        struct ngene_channel *chan = priv;
@@ -126,21 +136,41 @@ void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
 
        if (flags & DF_SWAP32)
                swap_buffer(buf, len);
+
        if (dev->ci.en && chan->number == 2) {
-               if (dvb_ringbuffer_free(&dev->tsin_rbuf) > len) {
-                       dvb_ringbuffer_write(&dev->tsin_rbuf, buf, len);
-                       wake_up_interruptible(&dev->tsin_rbuf.queue);
+               while (len >= 188) {
+                       if (memcmp(buf, fill_ts, sizeof fill_ts) != 0) {
+                               if (dvb_ringbuffer_free(&dev->tsin_rbuf) >= 188) {
+                                       dvb_ringbuffer_write(&dev->tsin_rbuf, buf, 188);
+                                       wake_up(&dev->tsin_rbuf.queue);
+#ifdef DEBUG_CI_XFER
+                                       ok++;
+#endif
+                               }
+#ifdef DEBUG_CI_XFER
+                               else
+                                       overflow++;
+#endif
+                       }
+#ifdef DEBUG_CI_XFER
+                       else
+                               stripped++;
+
+                       if (ok % 100 == 0 && overflow)
+                               printk(KERN_WARNING "%s: ok %u overflow %u dropped %u\n", __func__, ok, overflow, stripped);
+#endif
+                       buf += 188;
+                       len -= 188;
                }
-               return 0;
+               return NULL;
        }
-       if (chan->users > 0) {
+
+       if (chan->users > 0)
                dvb_dmx_swfilter(&chan->demux, buf, len);
-       }
+
        return NULL;
 }
 
-u8 fill_ts[188] = { 0x47, 0x1f, 0xff, 0x10 };
-
 void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
 {
        struct ngene_channel *chan = priv;
index 40fce9e..5443dc0 100644 (file)
@@ -641,8 +641,11 @@ struct ngene_channel {
        int                   mode;
        bool                  has_adapter;
        bool                  has_demux;
+       int                   demod_type;
+       int (*gate_ctrl)(struct dvb_frontend *, int);
 
        struct dvb_frontend  *fe;
+       struct dvb_frontend  *fe2;
        struct dmxdev         dmxdev;
        struct dvb_demux      demux;
        struct dvb_net        dvbnet;
@@ -786,6 +789,8 @@ struct ngene {
        u8                    uart_rbuf[UART_RBUF_LEN];
        int                   uart_rp, uart_wp;
 
+#define TS_FILLER  0x6f
+
        u8                   *tsout_buf;
 #define TSOUT_BUF_SIZE (512*188*8)
        struct dvb_ringbuffer tsout_rbuf;
@@ -852,7 +857,7 @@ struct ngene_info {
 };
 
 #ifdef NGENE_V4L
-struct ngene_format{
+struct ngene_format {
        char *name;
        int   fourcc;          /* video4linux 2      */
        int   btformat;        /* BT848_COLOR_FMT_*  */
index 78765ed..7331e84 100644 (file)
@@ -1147,7 +1147,7 @@ static int smscore_validate_client(struct smscore_device_t *coredev,
 
        if (!client) {
                sms_err("bad parameter.");
-               return -EFAULT;
+               return -EINVAL;
        }
        registered_client = smscore_find_client(coredev, data_type, id);
        if (registered_client == client)
index 8ecadec..c592ae0 100644 (file)
@@ -22,7 +22,6 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #ifndef __SMS_CORE_API_H__
 #define __SMS_CORE_API_H__
 
-#include <linux/version.h>
 #include <linux/device.h>
 #include <linux/list.h>
 #include <linux/mm.h>
index 3d8cc42..25e58cb 100644 (file)
 /*
  * Version Information
  */
-#include <linux/version.h>     /* for KERNEL_VERSION MACRO     */
-
-#define DRIVER_VERSION "v0.46"
-#define RADIO_VERSION KERNEL_VERSION(0, 4, 6)
+#define DRIVER_VERSION "0.4.7"
 
 #define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
 #define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
@@ -335,7 +332,6 @@ static int vidioc_querycap(struct file *file, void *priv,
        strlcpy(v->driver, "dsbr100", sizeof(v->driver));
        strlcpy(v->card, "D-Link R-100 USB FM Radio", sizeof(v->card));
        usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
-       v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER;
        return 0;
 }
@@ -647,3 +643,4 @@ module_exit (dsbr100_exit);
 MODULE_AUTHOR( DRIVER_AUTHOR );
 MODULE_DESCRIPTION( DRIVER_DESC );
 MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
index 4ce10db..1c3f844 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/ioport.h>      /* request_region               */
 #include <linux/delay.h>       /* msleep                       */
 #include <linux/videodev2.h>   /* kernel radio structs         */
-#include <linux/version.h>     /* for KERNEL_VERSION MACRO     */
 #include <linux/io.h>          /* outb, outb_p                 */
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
@@ -41,6 +40,7 @@
 MODULE_AUTHOR("M.Kirkwood");
 MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card.");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.3");
 
 #ifndef CONFIG_RADIO_RTRACK_PORT
 #define CONFIG_RADIO_RTRACK_PORT -1
@@ -53,8 +53,6 @@ module_param(io, int, 0);
 MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20f or 0x30f)");
 module_param(radio_nr, int, 0);
 
-#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
-
 struct rtrack
 {
        struct v4l2_device v4l2_dev;
@@ -223,7 +221,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        strlcpy(v->driver, "radio-aimslab", sizeof(v->driver));
        strlcpy(v->card, "RadioTrack", sizeof(v->card));
        strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
index dd8a6ab..eed7b08 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/ioport.h>      /* request_region               */
 #include <linux/delay.h>       /* udelay                       */
 #include <linux/videodev2.h>   /* kernel radio structs         */
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
 #include <linux/io.h>          /* outb, outb_p                 */
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
@@ -38,6 +37,7 @@
 MODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
 MODULE_DESCRIPTION("A driver for the Aztech radio card.");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.3");
 
 /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
 
@@ -53,8 +53,6 @@ module_param(io, int, 0);
 module_param(radio_nr, int, 0);
 MODULE_PARM_DESC(io, "I/O address of the Aztech card (0x350 or 0x358)");
 
-#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
-
 struct aztech
 {
        struct v4l2_device v4l2_dev;
@@ -188,7 +186,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        strlcpy(v->driver, "radio-aztech", sizeof(v->driver));
        strlcpy(v->card, "Aztech Radio", sizeof(v->card));
        strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
index bc9ad08..16a089f 100644 (file)
@@ -30,7 +30,6 @@
  *             Changed API to V4L2
  */
 
-#include <linux/version.h>
 #include <linux/module.h>      /* Modules                      */
 #include <linux/init.h>                /* Initdata                     */
 #include <linux/ioport.h>      /* request_region               */
@@ -46,6 +45,7 @@
 MODULE_AUTHOR("Fred Gleason, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
 MODULE_DESCRIPTION("A driver for the ADS Cadet AM/FM/RDS radio card.");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.3.4");
 
 static int io = -1;            /* default to isapnp activation */
 static int radio_nr = -1;
@@ -54,8 +54,6 @@ module_param(io, int, 0);
 MODULE_PARM_DESC(io, "I/O address of Cadet card (0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e)");
 module_param(radio_nr, int, 0);
 
-#define CADET_VERSION KERNEL_VERSION(0, 3, 3)
-
 #define RDS_BUFFER 256
 #define RDS_RX_FLAG 1
 #define MBS_RX_FLAG 2
@@ -361,7 +359,6 @@ static int vidioc_querycap(struct file *file, void *priv,
        strlcpy(v->driver, "ADS Cadet", sizeof(v->driver));
        strlcpy(v->card, "ADS Cadet", sizeof(v->card));
        strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->version = CADET_VERSION;
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO |
                          V4L2_CAP_READWRITE | V4L2_CAP_RDS_CAPTURE;
        return 0;
index 2599364..edadc84 100644 (file)
 #include <linux/ioport.h>      /* request_region               */
 #include <linux/delay.h>       /* udelay                       */
 #include <linux/videodev2.h>   /* kernel radio structs         */
-#include <linux/version.h>     /* for KERNEL_VERSION MACRO     */
 #include <linux/mutex.h>
 #include <linux/io.h>          /* outb, outb_p                 */
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
 
-#define RADIO_VERSION KERNEL_VERSION(0, 0, 3)
-
 /*
  * Module info.
  */
 
-MODULE_AUTHOR("Jonas Munsin, Pekka Seppänen <pexu@kapsi.fi>");
+MODULE_AUTHOR("Jonas Munsin, Pekka Seppänen <pexu@kapsi.fi>");
 MODULE_DESCRIPTION("A driver for the GemTek Radio card.");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.4");
 
 /*
  * Module params.
@@ -387,7 +385,6 @@ static int vidioc_querycap(struct file *file, void *priv,
        strlcpy(v->driver, "radio-gemtek", sizeof(v->driver));
        strlcpy(v->card, "GemTek", sizeof(v->card));
        strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
index e83e840..f872a54 100644 (file)
 #include <linux/mutex.h>
 #include <linux/pci.h>
 #include <linux/videodev2.h>
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 
+#define DRIVER_VERSION "0.7.8"
+
+
 MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net");
 MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio.");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
 
 static int radio_nr = -1;
 module_param(radio_nr, int, 0);
@@ -58,10 +61,6 @@ static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "activates debug info");
 
-#define DRIVER_VERSION "0.77"
-
-#define RADIO_VERSION KERNEL_VERSION(0, 7, 7)
-
 #define dprintk(dev, num, fmt, arg...) \
        v4l2_dbg(num, debug, &dev->v4l2_dev, fmt, ## arg)
 
@@ -195,7 +194,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        strlcpy(v->driver, "radio-maxiradio", sizeof(v->driver));
        strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof(v->card));
        snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(dev->pdev));
-       v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
index b3a635b..1742bd8 100644 (file)
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <linux/usb.h>
-#include <linux/version.h>     /* for KERNEL_VERSION MACRO */
 #include <linux/mutex.h>
 
 /* driver and module definitions */
 #define DRIVER_AUTHOR "Alexey Klimov <klimov.linux@gmail.com>"
 #define DRIVER_DESC "AverMedia MR 800 USB FM radio driver"
-#define DRIVER_VERSION "0.11"
-#define RADIO_VERSION KERNEL_VERSION(0, 1, 1)
+#define DRIVER_VERSION "0.1.2"
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
 
 #define USB_AMRADIO_VENDOR 0x07ca
 #define USB_AMRADIO_PRODUCT 0xb800
@@ -301,7 +300,6 @@ static int vidioc_querycap(struct file *file, void *priv,
        strlcpy(v->driver, "radio-mr800", sizeof(v->driver));
        strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card));
        usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
-       v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER;
        return 0;
 }
index 8d6ea59..3628be6 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/delay.h>       /* udelay                       */
 #include <linux/videodev2.h>   /* kernel radio structs         */
 #include <linux/mutex.h>
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
 #include <linux/io.h>          /* outb, outb_p                 */
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
@@ -23,6 +22,7 @@
 MODULE_AUTHOR("Ben Pfaff");
 MODULE_DESCRIPTION("A driver for the RadioTrack II radio card.");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.3");
 
 #ifndef CONFIG_RADIO_RTRACK2_PORT
 #define CONFIG_RADIO_RTRACK2_PORT -1
@@ -35,8 +35,6 @@ module_param(io, int, 0);
 MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20c or 0x30c)");
 module_param(radio_nr, int, 0);
 
-#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
-
 struct rtrack2
 {
        struct v4l2_device v4l2_dev;
@@ -121,7 +119,6 @@ static int vidioc_querycap(struct file *file, void *priv,
        strlcpy(v->driver, "radio-rtrack2", sizeof(v->driver));
        strlcpy(v->card, "RadioTrack II", sizeof(v->card));
        strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
index b5a5f89..22c5743 100644 (file)
@@ -16,7 +16,6 @@
  * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
  */
 
-#include <linux/version.h>
 #include <linux/kernel.h>      /* __setup                      */
 #include <linux/module.h>      /* Modules                      */
 #include <linux/init.h>                /* Initdata                     */
@@ -32,6 +31,7 @@
 MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood");
 MODULE_DESCRIPTION("A driver for the SF16-FMI and SF16-FMP radio.");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.3");
 
 static int io = -1;
 static int radio_nr = -1;
@@ -40,8 +40,6 @@ module_param(io, int, 0);
 MODULE_PARM_DESC(io, "I/O address of the SF16-FMI or SF16-FMP card (0x284 or 0x384)");
 module_param(radio_nr, int, 0);
 
-#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
-
 struct fmi
 {
        struct v4l2_device v4l2_dev;
@@ -134,7 +132,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        strlcpy(v->driver, "radio-sf16fmi", sizeof(v->driver));
        strlcpy(v->card, "SF16-FMx radio", sizeof(v->card));
        strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
index 87bad76..2dd4859 100644 (file)
-/* SF16FMR2 radio driver for Linux radio support
- * heavily based on fmi driver...
- * (c) 2000-2002 Ziglio Frediano, freddy77@angelfire.com
+/* SF16-FMR2 radio driver for Linux
+ * Copyright (c) 2011 Ondrej Zary
  *
- * Notes on the hardware
- *
- *  Frequency control is done digitally -- ie out(port,encodefreq(95.8));
- *  No volume control - only mute/unmute - you have to use line volume
- *
- *  For read stereo/mono you must wait 0.1 sec after set frequency and
- *  card unmuted so I set frequency on unmute
- *  Signal handling seem to work only on autoscanning (not implemented)
- *
- *  Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
+ * Original driver was (c) 2000-2002 Ziglio Frediano, freddy77@angelfire.com
+ * but almost nothing remained here after conversion to generic TEA575x
+ * implementation
  */
 
+#include <linux/delay.h>
 #include <linux/module.h>      /* Modules                      */
 #include <linux/init.h>                /* Initdata                     */
 #include <linux/ioport.h>      /* request_region               */
-#include <linux/delay.h>       /* udelay                       */
-#include <linux/videodev2.h>   /* kernel radio structs         */
-#include <linux/mutex.h>
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
 #include <linux/io.h>          /* outb, outb_p                 */
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
+#include <sound/tea575x-tuner.h>
 
-MODULE_AUTHOR("Ziglio Frediano, freddy77@angelfire.com");
-MODULE_DESCRIPTION("A driver for the SF16FMR2 radio.");
+MODULE_AUTHOR("Ondrej Zary");
+MODULE_DESCRIPTION("MediaForte SF16-FMR2 FM radio card driver");
 MODULE_LICENSE("GPL");
 
-static int io = 0x384;
-static int radio_nr = -1;
-
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the SF16FMR2 card (should be 0x384, if do not work try 0x284)");
-module_param(radio_nr, int, 0);
-
-#define RADIO_VERSION KERNEL_VERSION(0,0,2)
-
-#define AUD_VOL_INDEX 1
-
-#undef DEBUG
-//#define DEBUG 1
-
-#ifdef DEBUG
-# define  debug_print(s) printk s
-#else
-# define  debug_print(s)
-#endif
-
-/* this should be static vars for module size */
-struct fmr2
-{
-       struct v4l2_device v4l2_dev;
-       struct video_device vdev;
-       struct mutex lock;
+struct fmr2 {
        int io;
-       int curvol; /* 0-15 */
-       int mute;
-       int stereo; /* card is producing stereo audio */
-       unsigned long curfreq; /* freq in kHz */
-       int card_type;
+       struct snd_tea575x tea;
+       struct v4l2_ctrl *volume;
+       struct v4l2_ctrl *balance;
 };
 
+/* the port is hardwired so no need to support multiple cards */
+#define FMR2_PORT      0x384
 static struct fmr2 fmr2_card;
 
-/* hw precision is 12.5 kHz
- * It is only useful to give freq in interval of 200 (=0.0125Mhz),
- * other bits will be truncated
- */
-#define RSF16_ENCODE(x)        ((x) / 200 + 856)
-#define RSF16_MINFREQ (87 * 16000)
-#define RSF16_MAXFREQ (108 * 16000)
-
-static inline void wait(int n, int io)
-{
-       for (; n; --n)
-               inb(io);
-}
-
-static void outbits(int bits, unsigned int data, int nWait, int io)
-{
-       int bit;
-
-       for (; --bits >= 0;) {
-               bit = (data >> bits) & 1;
-               outb(bit, io);
-               wait(nWait, io);
-               outb(bit | 2, io);
-               wait(nWait, io);
-               outb(bit, io);
-               wait(nWait, io);
-       }
-}
-
-static inline void fmr2_mute(int io)
-{
-       outb(0x00, io);
-       wait(4, io);
-}
-
-static inline void fmr2_unmute(int io)
-{
-       outb(0x04, io);
-       wait(4, io);
-}
-
-static inline int fmr2_stereo_mode(int io)
-{
-       int n = inb(io);
-
-       outb(6, io);
-       inb(io);
-       n = ((n >> 3) & 1) ^ 1;
-       debug_print((KERN_DEBUG "stereo: %d\n", n));
-       return n;
-}
-
-static int fmr2_product_info(struct fmr2 *dev)
-{
-       int n = inb(dev->io);
-
-       n &= 0xC1;
-       if (n == 0) {
-               /* this should support volume set */
-               dev->card_type = 12;
-               return 0;
-       }
-       /* not volume (mine is 11) */
-       dev->card_type = (n == 128) ? 11 : 0;
-       return n;
-}
+/* TEA575x tuner pins */
+#define STR_DATA       (1 << 0)
+#define STR_CLK                (1 << 1)
+#define STR_WREN       (1 << 2)
+#define STR_MOST       (1 << 3)
+/* PT2254A/TC9154A volume control pins */
+#define PT_ST          (1 << 4)
+#define PT_CK          (1 << 5)
+#define PT_DATA                (1 << 6)
+/* volume control presence pin */
+#define FMR2_HASVOL    (1 << 7)
 
-static inline int fmr2_getsigstr(struct fmr2 *dev)
+static void fmr2_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
 {
-       /* !!! works only if scanning freq */
-       int res = 0xffff;
-
-       outb(5, dev->io);
-       wait(4, dev->io);
-       if (!(inb(dev->io) & 1))
-               res = 0;
-       debug_print((KERN_DEBUG "signal: %d\n", res));
-       return res;
-}
-
-/* set frequency and unmute card */
-static int fmr2_setfreq(struct fmr2 *dev)
-{
-       unsigned long freq = dev->curfreq;
-
-       fmr2_mute(dev->io);
-
-       /* 0x42 for mono output
-        * 0x102 forward scanning
-        * 0x182 scansione avanti
-        */
-       outbits(9, 0x2, 3, dev->io);
-       outbits(16, RSF16_ENCODE(freq), 2, dev->io);
-
-       fmr2_unmute(dev->io);
+       struct fmr2 *fmr2 = tea->private_data;
+       u8 bits = 0;
 
-       /* wait 0.11 sec */
-       msleep(110);
+       bits |= (pins & TEA575X_DATA) ? STR_DATA : 0;
+       bits |= (pins & TEA575X_CLK)  ? STR_CLK  : 0;
+       /* WRITE_ENABLE is inverted, DATA must be high during read */
+       bits |= (pins & TEA575X_WREN) ? 0 : STR_WREN | STR_DATA;
 
-       /* NOTE if mute this stop radio
-          you must set freq on unmute */
-       dev->stereo = fmr2_stereo_mode(dev->io);
-       return 0;
-}
-
-/* !!! not tested, in my card this doesn't work !!! */
-static int fmr2_setvolume(struct fmr2 *dev)
-{
-       int vol[16] = { 0x021, 0x084, 0x090, 0x104,
-                       0x110, 0x204, 0x210, 0x402,
-                       0x404, 0x408, 0x410, 0x801,
-                       0x802, 0x804, 0x808, 0x810 };
-       int i, a;
-       int n = vol[dev->curvol & 0x0f];
-
-       if (dev->card_type != 11)
-               return 1;
-
-       for (i = 12; --i >= 0; ) {
-               a = ((n >> i) & 1) << 6; /* if (a==0) a = 0; else a = 0x40; */
-               outb(a | 4, dev->io);
-               wait(4, dev->io);
-               outb(a | 0x24, dev->io);
-               wait(4, dev->io);
-               outb(a | 4, dev->io);
-               wait(4, dev->io);
-       }
-       for (i = 6; --i >= 0; ) {
-               a = ((0x18 >> i) & 1) << 6;
-               outb(a | 4, dev->io);
-               wait(4, dev->io);
-               outb(a | 0x24, dev->io);
-               wait(4, dev->io);
-               outb(a | 4, dev->io);
-               wait(4, dev->io);
-       }
-       wait(4, dev->io);
-       outb(0x14, dev->io);
-       return 0;
+       outb(bits, fmr2->io);
 }
 
-static int vidioc_querycap(struct file *file, void  *priv,
-                                       struct v4l2_capability *v)
+static u8 fmr2_tea575x_get_pins(struct snd_tea575x *tea)
 {
-       strlcpy(v->driver, "radio-sf16fmr2", sizeof(v->driver));
-       strlcpy(v->card, "SF16-FMR2 radio", sizeof(v->card));
-       strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->version = RADIO_VERSION;
-       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
-       return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
-                                       struct v4l2_tuner *v)
-{
-       struct fmr2 *fmr2 = video_drvdata(file);
-
-       if (v->index > 0)
-               return -EINVAL;
+       struct fmr2 *fmr2 = tea->private_data;
+       u8 bits = inb(fmr2->io);
 
-       strlcpy(v->name, "FM", sizeof(v->name));
-       v->type = V4L2_TUNER_RADIO;
-
-       v->rangelow = RSF16_MINFREQ;
-       v->rangehigh = RSF16_MAXFREQ;
-       v->rxsubchans = fmr2->stereo ? V4L2_TUNER_SUB_STEREO :
-                                       V4L2_TUNER_SUB_MONO;
-       v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW;
-       v->audmode = V4L2_TUNER_MODE_STEREO;
-       mutex_lock(&fmr2->lock);
-       v->signal = fmr2_getsigstr(fmr2);
-       mutex_unlock(&fmr2->lock);
-       return 0;
+       return  (bits & STR_DATA) ? TEA575X_DATA : 0 |
+               (bits & STR_MOST) ? TEA575X_MOST : 0;
 }
 
-static int vidioc_s_tuner(struct file *file, void *priv,
-                                       struct v4l2_tuner *v)
+static void fmr2_tea575x_set_direction(struct snd_tea575x *tea, bool output)
 {
-       return v->index ? -EINVAL : 0;
 }
 
-static int vidioc_s_frequency(struct file *file, void *priv,
-                                       struct v4l2_frequency *f)
-{
-       struct fmr2 *fmr2 = video_drvdata(file);
+static struct snd_tea575x_ops fmr2_tea_ops = {
+       .set_pins = fmr2_tea575x_set_pins,
+       .get_pins = fmr2_tea575x_get_pins,
+       .set_direction = fmr2_tea575x_set_direction,
+};
 
-       if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
-               return -EINVAL;
-       if (f->frequency < RSF16_MINFREQ ||
-                       f->frequency > RSF16_MAXFREQ)
-               return -EINVAL;
-       /* rounding in steps of 200 to match the freq
-          that will be used */
-       fmr2->curfreq = (f->frequency / 200) * 200;
-
-       /* set card freq (if not muted) */
-       if (fmr2->curvol && !fmr2->mute) {
-               mutex_lock(&fmr2->lock);
-               fmr2_setfreq(fmr2);
-               mutex_unlock(&fmr2->lock);
+/* TC9154A/PT2254A volume control */
+
+/* 18-bit shift register bit definitions */
+#define TC9154A_ATT_MAJ_0DB    (1 << 0)
+#define TC9154A_ATT_MAJ_10DB   (1 << 1)
+#define TC9154A_ATT_MAJ_20DB   (1 << 2)
+#define TC9154A_ATT_MAJ_30DB   (1 << 3)
+#define TC9154A_ATT_MAJ_40DB   (1 << 4)
+#define TC9154A_ATT_MAJ_50DB   (1 << 5)
+#define TC9154A_ATT_MAJ_60DB   (1 << 6)
+
+#define TC9154A_ATT_MIN_0DB    (1 << 7)
+#define TC9154A_ATT_MIN_2DB    (1 << 8)
+#define TC9154A_ATT_MIN_4DB    (1 << 9)
+#define TC9154A_ATT_MIN_6DB    (1 << 10)
+#define TC9154A_ATT_MIN_8DB    (1 << 11)
+/* bit 12 is ignored */
+#define TC9154A_CHANNEL_LEFT   (1 << 13)
+#define TC9154A_CHANNEL_RIGHT  (1 << 14)
+/* bits 15, 16, 17 must be 0 */
+
+#define        TC9154A_ATT_MAJ(x)      (1 << x)
+#define TC9154A_ATT_MIN(x)     (1 << (7 + x))
+
+static void tc9154a_set_pins(struct fmr2 *fmr2, u8 pins)
+{
+       if (!fmr2->tea.mute)
+               pins |= STR_WREN;
+
+       outb(pins, fmr2->io);
+}
+
+static void tc9154a_set_attenuation(struct fmr2 *fmr2, int att, u32 channel)
+{
+       int i;
+       u32 reg;
+       u8 bit;
+
+       reg = TC9154A_ATT_MAJ(att / 10) | TC9154A_ATT_MIN((att % 10) / 2);
+       reg |= channel;
+       /* write 18-bit shift register, LSB first */
+       for (i = 0; i < 18; i++) {
+               bit = reg & (1 << i) ? PT_DATA : 0;
+               tc9154a_set_pins(fmr2, bit);
+               udelay(5);
+               tc9154a_set_pins(fmr2, bit | PT_CK);
+               udelay(5);
+               tc9154a_set_pins(fmr2, bit);
        }
-       return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
-                                       struct v4l2_frequency *f)
-{
-       struct fmr2 *fmr2 = video_drvdata(file);
-
-       if (f->tuner != 0)
-               return -EINVAL;
-       f->type = V4L2_TUNER_RADIO;
-       f->frequency = fmr2->curfreq;
-       return 0;
-}
 
-static int vidioc_queryctrl(struct file *file, void *priv,
-                                       struct v4l2_queryctrl *qc)
-{
-       struct fmr2 *fmr2 = video_drvdata(file);
-
-       switch (qc->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
-       case V4L2_CID_AUDIO_VOLUME:
-               /* Only card_type == 11 implements volume */
-               if (fmr2->card_type == 11)
-                       return v4l2_ctrl_query_fill(qc, 0, 15, 1, 0);
-               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
-       }
-       return -EINVAL;
+       /* latch register data */
+       udelay(5);
+       tc9154a_set_pins(fmr2, PT_ST);
+       udelay(5);
+       tc9154a_set_pins(fmr2, 0);
 }
 
-static int vidioc_g_ctrl(struct file *file, void *priv,
-                                       struct v4l2_control *ctrl)
+static int fmr2_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-       struct fmr2 *fmr2 = video_drvdata(file);
+       struct snd_tea575x *tea = container_of(ctrl->handler, struct snd_tea575x, ctrl_handler);
+       struct fmr2 *fmr2 = tea->private_data;
+       int volume, balance, left, right;
 
        switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               ctrl->value = fmr2->mute;
-               return 0;
        case V4L2_CID_AUDIO_VOLUME:
-               ctrl->value = fmr2->curvol;
-               return 0;
-       }
-       return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                                       struct v4l2_control *ctrl)
-{
-       struct fmr2 *fmr2 = video_drvdata(file);
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               fmr2->mute = ctrl->value;
+               volume = ctrl->val;
+               balance = fmr2->balance->cur.val;
                break;
-       case V4L2_CID_AUDIO_VOLUME:
-               fmr2->curvol = ctrl->value;
+       case V4L2_CID_AUDIO_BALANCE:
+               balance = ctrl->val;
+               volume = fmr2->volume->cur.val;
                break;
        default:
                return -EINVAL;
        }
 
-#ifdef DEBUG
-       if (fmr2->curvol && !fmr2->mute)
-               printk(KERN_DEBUG "unmute\n");
-       else
-               printk(KERN_DEBUG "mute\n");
-#endif
-
-       mutex_lock(&fmr2->lock);
-       if (fmr2->curvol && !fmr2->mute) {
-               fmr2_setvolume(fmr2);
-               /* Set frequency and unmute card */
-               fmr2_setfreq(fmr2);
-       } else
-               fmr2_mute(fmr2->io);
-       mutex_unlock(&fmr2->lock);
-       return 0;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-       *i = 0;
-       return 0;
-}
+       left = right = volume;
+       if (balance < 0)
+               right = max(0, right + balance);
+       if (balance > 0)
+               left = max(0, left - balance);
 
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-       return i ? -EINVAL : 0;
-}
+       tc9154a_set_attenuation(fmr2, abs(left - 68), TC9154A_CHANNEL_LEFT);
+       tc9154a_set_attenuation(fmr2, abs(right - 68), TC9154A_CHANNEL_RIGHT);
 
-static int vidioc_g_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
-{
-       a->index = 0;
-       strlcpy(a->name, "Radio", sizeof(a->name));
-       a->capability = V4L2_AUDCAP_STEREO;
        return 0;
 }
 
-static int vidioc_s_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
+static const struct v4l2_ctrl_ops fmr2_ctrl_ops = {
+       .s_ctrl = fmr2_s_ctrl,
+};
+
+static int fmr2_tea_ext_init(struct snd_tea575x *tea)
 {
-       return a->index ? -EINVAL : 0;
-}
+       struct fmr2 *fmr2 = tea->private_data;
 
-static const struct v4l2_file_operations fmr2_fops = {
-       .owner          = THIS_MODULE,
-       .unlocked_ioctl = video_ioctl2,
-};
+       if (inb(fmr2->io) & FMR2_HASVOL) {
+               fmr2->volume = v4l2_ctrl_new_std(&tea->ctrl_handler, &fmr2_ctrl_ops, V4L2_CID_AUDIO_VOLUME, 0, 68, 2, 56);
+               fmr2->balance = v4l2_ctrl_new_std(&tea->ctrl_handler, &fmr2_ctrl_ops, V4L2_CID_AUDIO_BALANCE, -68, 68, 2, 0);
+               if (tea->ctrl_handler.error) {
+                       printk(KERN_ERR "radio-sf16fmr2: can't initialize contrls\n");
+                       return tea->ctrl_handler.error;
+               }
+       }
 
-static const struct v4l2_ioctl_ops fmr2_ioctl_ops = {
-       .vidioc_querycap    = vidioc_querycap,
-       .vidioc_g_tuner     = vidioc_g_tuner,
-       .vidioc_s_tuner     = vidioc_s_tuner,
-       .vidioc_g_audio     = vidioc_g_audio,
-       .vidioc_s_audio     = vidioc_s_audio,
-       .vidioc_g_input     = vidioc_g_input,
-       .vidioc_s_input     = vidioc_s_input,
-       .vidioc_g_frequency = vidioc_g_frequency,
-       .vidioc_s_frequency = vidioc_s_frequency,
-       .vidioc_queryctrl   = vidioc_queryctrl,
-       .vidioc_g_ctrl      = vidioc_g_ctrl,
-       .vidioc_s_ctrl      = vidioc_s_ctrl,
-};
+       return 0;
+}
 
 static int __init fmr2_init(void)
 {
        struct fmr2 *fmr2 = &fmr2_card;
-       struct v4l2_device *v4l2_dev = &fmr2->v4l2_dev;
-       int res;
 
-       strlcpy(v4l2_dev->name, "sf16fmr2", sizeof(v4l2_dev->name));
-       fmr2->io = io;
-       fmr2->stereo = 1;
-       mutex_init(&fmr2->lock);
+       fmr2->io = FMR2_PORT;
 
-       if (!request_region(fmr2->io, 2, "sf16fmr2")) {
-               v4l2_err(v4l2_dev, "request_region failed!\n");
+       if (!request_region(fmr2->io, 2, "SF16-FMR2")) {
+               printk(KERN_ERR "radio-sf16fmr2: I/O port 0x%x already in use\n", fmr2->io);
                return -EBUSY;
        }
 
-       res = v4l2_device_register(NULL, v4l2_dev);
-       if (res < 0) {
-               release_region(fmr2->io, 2);
-               v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
-               return res;
-       }
+       fmr2->tea.private_data = fmr2;
+       fmr2->tea.ops = &fmr2_tea_ops;
+       fmr2->tea.ext_init = fmr2_tea_ext_init;
+       strlcpy(fmr2->tea.card, "SF16-FMR2", sizeof(fmr2->tea.card));
+       strcpy(fmr2->tea.bus_info, "ISA");
 
-       strlcpy(fmr2->vdev.name, v4l2_dev->name, sizeof(fmr2->vdev.name));
-       fmr2->vdev.v4l2_dev = v4l2_dev;
-       fmr2->vdev.fops = &fmr2_fops;
-       fmr2->vdev.ioctl_ops = &fmr2_ioctl_ops;
-       fmr2->vdev.release = video_device_release_empty;
-       video_set_drvdata(&fmr2->vdev, fmr2);
-
-       /* mute card - prevents noisy bootups */
-       fmr2_mute(fmr2->io);
-       fmr2_product_info(fmr2);
-
-       if (video_register_device(&fmr2->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
-               v4l2_device_unregister(v4l2_dev);
+       if (snd_tea575x_init(&fmr2->tea)) {
+               printk(KERN_ERR "radio-sf16fmr2: Unable to detect TEA575x tuner\n");
                release_region(fmr2->io, 2);
-               return -EINVAL;
+               return -ENODEV;
        }
 
-       v4l2_info(v4l2_dev, "SF16FMR2 radio card driver at 0x%x.\n", fmr2->io);
-       debug_print((KERN_DEBUG "card_type %d\n", fmr2->card_type));
+       printk(KERN_INFO "radio-sf16fmr2: SF16-FMR2 radio card at 0x%x.\n", fmr2->io);
        return 0;
 }
 
@@ -443,22 +211,9 @@ static void __exit fmr2_exit(void)
 {
        struct fmr2 *fmr2 = &fmr2_card;
 
-       video_unregister_device(&fmr2->vdev);
-       v4l2_device_unregister(&fmr2->v4l2_dev);
+       snd_tea575x_exit(&fmr2->tea);
        release_region(fmr2->io, 2);
 }
 
 module_init(fmr2_init);
 module_exit(fmr2_exit);
-
-#ifndef MODULE
-
-static int __init fmr2_setup_io(char *str)
-{
-       get_option(&str, &io);
-       return 1;
-}
-
-__setup("sf16fmr2=", fmr2_setup_io);
-
-#endif
index 0e71d81..95ddcc4 100644 (file)
 #include <linux/i2c.h>                 /* I2C                          */
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
-#include <linux/version.h>             /* for KERNEL_VERSION MACRO     */
 
-#define DRIVER_VERSION "v0.01"
-#define RADIO_VERSION  KERNEL_VERSION(0, 0, 1)
+#define DRIVER_VERSION "0.0.2"
 
 #define DRIVER_AUTHOR  "Fabio Belavenuto <belavenuto@gmail.com>"
 #define DRIVER_DESC    "A driver for the TEA5764 radio chip for EZX Phones."
@@ -300,7 +298,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        strlcpy(v->card, dev->name, sizeof(v->card));
        snprintf(v->bus_info, sizeof(v->bus_info),
                 "I2C:%s", dev_name(&dev->dev));
-       v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
@@ -595,8 +592,9 @@ static void __exit tea5764_exit(void)
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
 
-module_param(use_xtal, int, 1);
+module_param(use_xtal, int, 0);
 MODULE_PARM_DESC(use_xtal, "Chip have a xtal connected in board");
 module_param(radio_nr, int, 0);
 MODULE_PARM_DESC(radio_nr, "video4linux device number to use");
index a326639..f2ed9cc 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/ioport.h>      /* request_region               */
 #include <linux/videodev2.h>   /* kernel radio structs         */
 #include <linux/mutex.h>
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
 #include <linux/io.h>          /* outb, outb_p                 */
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
@@ -37,6 +36,7 @@
 MODULE_AUTHOR("R.OFFERMANNS & others");
 MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card.");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.3");
 
 #ifndef CONFIG_RADIO_TERRATEC_PORT
 #define CONFIG_RADIO_TERRATEC_PORT 0x590
@@ -49,8 +49,6 @@ module_param(io, int, 0);
 MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)");
 module_param(radio_nr, int, 0);
 
-#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
-
 static struct v4l2_queryctrl radio_qctrl[] = {
        {
                .id            = V4L2_CID_AUDIO_MUTE,
@@ -205,7 +203,6 @@ static int vidioc_querycap(struct file *file, void *priv,
        strlcpy(v->driver, "radio-terratec", sizeof(v->driver));
        strlcpy(v->card, "ActiveRadio", sizeof(v->card));
        strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
index a185610..f17b540 100644 (file)
@@ -16,7 +16,6 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/version.h>
 #include <linux/io.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
@@ -44,7 +43,6 @@ static int timbradio_vidioc_querycap(struct file *file, void  *priv,
        strlcpy(v->driver, DRIVER_NAME, sizeof(v->driver));
        strlcpy(v->card, "Timberdale Radio", sizeof(v->card));
        snprintf(v->bus_info, sizeof(v->bus_info), "platform:"DRIVER_NAME);
-       v->version = KERNEL_VERSION(0, 0, 1);
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
@@ -245,4 +243,5 @@ module_exit(timbradio_exit);
 MODULE_DESCRIPTION("Timberdale Radio driver");
 MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
 MODULE_LICENSE("GPL v2");
+MODULE_VERSION("0.0.2");
 MODULE_ALIAS("platform:"DRIVER_NAME);
index 22fa9cc..b3f45a0 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
 #include <linux/videodev2.h>
 #include <linux/io.h>
 #include <media/v4l2-device.h>
@@ -28,6 +27,7 @@
 MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
 MODULE_DESCRIPTION("A driver for the Trust FM Radio card.");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.3");
 
 /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
 
@@ -42,8 +42,6 @@ module_param(io, int, 0);
 MODULE_PARM_DESC(io, "I/O address of the Trust FM Radio card (0x350 or 0x358)");
 module_param(radio_nr, int, 0);
 
-#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
-
 struct trust {
        struct v4l2_device v4l2_dev;
        struct video_device vdev;
@@ -196,7 +194,6 @@ static int vidioc_querycap(struct file *file, void *priv,
        strlcpy(v->driver, "radio-trust", sizeof(v->driver));
        strlcpy(v->card, "Trust FM Radio", sizeof(v->card));
        strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
index 8dbbf08..398726a 100644 (file)
 #include <linux/module.h>      /* Modules                        */
 #include <linux/init.h>                /* Initdata                       */
 #include <linux/ioport.h>      /* request_region                 */
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
 #include <linux/videodev2.h>   /* kernel radio structs           */
 #include <linux/io.h>          /* outb, outb_p                   */
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 
+#define DRIVER_VERSION "0.1.2"
+
 MODULE_AUTHOR("Dr. Henrik Seidel");
 MODULE_DESCRIPTION("A driver for the Typhoon radio card (a.k.a. EcoRadio).");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
 
 #ifndef CONFIG_RADIO_TYPHOON_PORT
 #define CONFIG_RADIO_TYPHOON_PORT -1
@@ -61,9 +63,7 @@ static unsigned long mutefreq = CONFIG_RADIO_TYPHOON_MUTEFREQ;
 module_param(mutefreq, ulong, 0);
 MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)");
 
-#define RADIO_VERSION KERNEL_VERSION(0, 1, 1)
-
-#define BANNER "Typhoon Radio Card driver v0.1.1\n"
+#define BANNER "Typhoon Radio Card driver v" DRIVER_VERSION "\n"
 
 struct typhoon {
        struct v4l2_device v4l2_dev;
@@ -171,7 +171,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        strlcpy(v->driver, "radio-typhoon", sizeof(v->driver));
        strlcpy(v->card, "Typhoon Radio", sizeof(v->card));
        strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
index 459f727..46cacf8 100644 (file)
@@ -1382,7 +1382,7 @@ static int wl1273_fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
 
        switch (ctrl->id) {
        case  V4L2_CID_TUNE_ANTENNA_CAPACITOR:
-               ctrl->cur.val = wl1273_fm_get_tx_ctune(radio);
+               ctrl->val = wl1273_fm_get_tx_ctune(radio);
                break;
 
        default:
index af99c5b..f5613b9 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/delay.h>       /* udelay, msleep                 */
 #include <linux/videodev2.h>   /* kernel radio structs           */
 #include <linux/mutex.h>
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
 #include <linux/io.h>          /* outb, outb_p                   */
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
@@ -43,6 +42,7 @@
 MODULE_AUTHOR("C.van Schaik");
 MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus.");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.3");
 
 #ifndef CONFIG_RADIO_ZOLTRIX_PORT
 #define CONFIG_RADIO_ZOLTRIX_PORT -1
@@ -55,8 +55,6 @@ module_param(io, int, 0);
 MODULE_PARM_DESC(io, "I/O address of the Zoltrix Radio Plus (0x20c or 0x30c)");
 module_param(radio_nr, int, 0);
 
-#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
-
 struct zoltrix {
        struct v4l2_device v4l2_dev;
        struct video_device vdev;
@@ -228,7 +226,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        strlcpy(v->driver, "radio-zoltrix", sizeof(v->driver));
        strlcpy(v->card, "Zoltrix Radio", sizeof(v->card));
        strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
index a2a6777..fd3541b 100644 (file)
 
 /* driver definitions */
 #define DRIVER_AUTHOR "Joonyoung Shim <jy0922.shim@samsung.com>";
-#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 1)
 #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver"
 #define DRIVER_DESC "I2C radio driver for Si470x FM Radio Receivers"
-#define DRIVER_VERSION "1.0.1"
+#define DRIVER_VERSION "1.0.2"
 
 /* kernel includes */
 #include <linux/i2c.h>
@@ -248,7 +247,6 @@ int si470x_vidioc_querycap(struct file *file, void *priv,
 {
        strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
        strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
-       capability->version = DRIVER_KERNEL_VERSION;
        capability->capabilities = V4L2_CAP_HW_FREQ_SEEK |
                V4L2_CAP_TUNER | V4L2_CAP_RADIO;
 
index 392e84f..4cf5370 100644 (file)
@@ -29,7 +29,6 @@
 
 /* driver definitions */
 #define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>"
-#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 10)
 #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver"
 #define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers"
 #define DRIVER_VERSION "1.0.10"
@@ -626,7 +625,6 @@ int si470x_vidioc_querycap(struct file *file, void *priv,
        strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
        usb_make_path(radio->usbdev, capability->bus_info,
                        sizeof(capability->bus_info));
-       capability->version = DRIVER_KERNEL_VERSION;
        capability->capabilities = V4L2_CAP_HW_FREQ_SEEK |
                V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE;
 
@@ -699,7 +697,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
        radio->videodev = video_device_alloc();
        if (!radio->videodev) {
                retval = -ENOMEM;
-               goto err_intbuffer;
+               goto err_urb;
        }
        memcpy(radio->videodev, &si470x_viddev_template,
                        sizeof(si470x_viddev_template));
@@ -790,6 +788,8 @@ err_all:
        kfree(radio->buffer);
 err_video:
        video_device_release(radio->videodev);
+err_urb:
+       usb_free_urb(radio->int_in_urb);
 err_intbuffer:
        kfree(radio->int_in_buffer);
 err_radio:
index 68da001..f300a55 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/input.h>
-#include <linux/version.h>
 #include <linux/videodev2.h>
 #include <linux/mutex.h>
 #include <media/v4l2-common.h>
index 1a45a5d..d84ad9d 100644 (file)
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <linux/timer.h>
-#include <linux/version.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ctrls.h>
 
-#define FM_DRV_VERSION            "0.10"
-/* Should match with FM_DRV_VERSION */
-#define FM_DRV_RADIO_VERSION      KERNEL_VERSION(0, 0, 1)
+#define FM_DRV_VERSION            "0.1.1"
 #define FM_DRV_NAME               "ti_fmdrv"
 #define FM_DRV_CARD_SHORT_NAME    "TI FM Radio"
 #define FM_DRV_CARD_LONG_NAME     "Texas Instruments FM Radio"
index 8701072..8c0e192 100644 (file)
@@ -175,7 +175,6 @@ static int fm_v4l2_vidioc_querycap(struct file *file, void *priv,
        strlcpy(capability->card, FM_DRV_CARD_SHORT_NAME,
                        sizeof(capability->card));
        sprintf(capability->bus_info, "UART");
-       capability->version = FM_DRV_RADIO_VERSION;
        capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER |
                V4L2_CAP_RADIO | V4L2_CAP_MODULATOR |
                V4L2_CAP_AUDIO | V4L2_CAP_READWRITE |
@@ -191,7 +190,7 @@ static int fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
 
        switch (ctrl->id) {
        case  V4L2_CID_TUNE_ANTENNA_CAPACITOR:
-               ctrl->cur.val = fm_tx_get_tune_cap_val(fmdev);
+               ctrl->val = fm_tx_get_tune_cap_val(fmdev);
                break;
        default:
                fmwarn("%s: Unknown IOCTL: %d\n", __func__, ctrl->id);
index 7d4bbc2..899f783 100644 (file)
@@ -87,6 +87,17 @@ config IR_RC5_SZ_DECODER
           uses an IR protocol that is almost standard RC-5, but not quite,
           as it uses an additional bit).
 
+config IR_MCE_KBD_DECODER
+       tristate "Enable IR raw decoder for the MCE keyboard/mouse protocol"
+       depends on RC_CORE
+       select BITREVERSE
+       default y
+
+       ---help---
+          Enable this option if you have a Microsoft Remote Keyboard for
+          Windows Media Center Edition, which you would like to use with
+          a raw IR receiver in your system.
+
 config IR_LIRC_CODEC
        tristate "Enable IR to LIRC bridge"
        depends on RC_CORE
index 52830e5..f224db0 100644 (file)
@@ -10,6 +10,7 @@ obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o
 obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o
 obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
 obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o
+obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o
 obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
 
 # stand-alone IR receivers/transmitters
index a43ed6c..2b9c256 100644 (file)
@@ -953,13 +953,13 @@ static void ene_set_idle(struct rc_dev *rdev, bool idle)
 }
 
 /* outside interface: transmit */
-static int ene_transmit(struct rc_dev *rdev, int *buf, u32 n)
+static int ene_transmit(struct rc_dev *rdev, unsigned *buf, unsigned n)
 {
        struct ene_device *dev = rdev->priv;
        unsigned long flags;
 
        dev->tx_buffer = buf;
-       dev->tx_len = n / sizeof(int);
+       dev->tx_len = n;
        dev->tx_pos = 0;
        dev->tx_reg = 0;
        dev->tx_done = 0;
index 337a41d..017c209 100644 (file)
@@ -235,7 +235,7 @@ struct ene_device {
        bool tx_sample_pulse;                   /* current sample is pulse */
 
        /* TX buffer */
-       int *tx_buffer;                         /* input samples buffer*/
+       unsigned *tx_buffer;                    /* input samples buffer*/
        int tx_pos;                             /* position in that bufer */
        int tx_len;                             /* current len of tx buffer */
        int tx_done;                            /* done transmitting */
index 1c5cc65..e5eeec4 100644 (file)
@@ -103,19 +103,19 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char *buf,
 {
        struct lirc_codec *lirc;
        struct rc_dev *dev;
-       int *txbuf; /* buffer with values to transmit */
-       int ret = 0;
+       unsigned int *txbuf; /* buffer with values to transmit */
+       ssize_t ret = 0;
        size_t count;
 
        lirc = lirc_get_pdata(file);
        if (!lirc)
                return -EFAULT;
 
-       if (n % sizeof(int))
+       if (n < sizeof(unsigned) || n % sizeof(unsigned))
                return -EINVAL;
 
-       count = n / sizeof(int);
-       if (count > LIRCBUF_SIZE || count % 2 == 0 || n % sizeof(int) != 0)
+       count = n / sizeof(unsigned);
+       if (count > LIRCBUF_SIZE || count % 2 == 0)
                return -EINVAL;
 
        txbuf = memdup_user(buf, n);
@@ -129,7 +129,10 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char *buf,
        }
 
        if (dev->tx_ir)
-               ret = dev->tx_ir(dev, txbuf, (u32)n);
+               ret = dev->tx_ir(dev, txbuf, count);
+
+       if (ret > 0)
+               ret *= sizeof(unsigned);
 
 out:
        kfree(txbuf);
diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c
new file mode 100644 (file)
index 0000000..3784ebf
--- /dev/null
@@ -0,0 +1,449 @@
+/* ir-mce_kbd-decoder.c - A decoder for the RC6-ish keyboard/mouse IR protocol
+ * used by the Microsoft Remote Keyboard for Windows Media Center Edition,
+ * referred to by Microsoft's Windows Media Center remote specification docs
+ * as "an internal protocol called MCIR-2".
+ *
+ * Copyright (C) 2011 by Jarod Wilson <jarod@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 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.
+ */
+#include <linux/module.h>
+
+#include "rc-core-priv.h"
+
+/*
+ * This decoder currently supports:
+ * - MCIR-2 29-bit IR signals used for mouse movement and buttons
+ * - MCIR-2 32-bit IR signals used for standard keyboard keys
+ *
+ * The media keys on the keyboard send RC-6 signals that are inditinguishable
+ * from the keys of the same name on the stock MCE remote, and will be handled
+ * by the standard RC-6 decoder, and be made available to the system via the
+ * input device for the remote, rather than the keyboard/mouse one.
+ */
+
+#define MCIR2_UNIT             333333  /* ns */
+#define MCIR2_HEADER_NBITS     5
+#define MCIR2_MOUSE_NBITS      29
+#define MCIR2_KEYBOARD_NBITS   32
+#define MCIR2_PREFIX_PULSE     (8 * MCIR2_UNIT)
+#define MCIR2_PREFIX_SPACE     (1 * MCIR2_UNIT)
+#define MCIR2_MAX_LEN          (3 * MCIR2_UNIT)
+#define MCIR2_BIT_START                (1 * MCIR2_UNIT)
+#define MCIR2_BIT_END          (1 * MCIR2_UNIT)
+#define MCIR2_BIT_0            (1 * MCIR2_UNIT)
+#define MCIR2_BIT_SET          (2 * MCIR2_UNIT)
+#define MCIR2_MODE_MASK                0xf     /* for the header bits */
+#define MCIR2_KEYBOARD_HEADER  0x4
+#define MCIR2_MOUSE_HEADER     0x1
+#define MCIR2_MASK_KEYS_START  0xe0
+
+enum mce_kbd_mode {
+       MCIR2_MODE_KEYBOARD,
+       MCIR2_MODE_MOUSE,
+       MCIR2_MODE_UNKNOWN,
+};
+
+enum mce_kbd_state {
+       STATE_INACTIVE,
+       STATE_HEADER_BIT_START,
+       STATE_HEADER_BIT_END,
+       STATE_BODY_BIT_START,
+       STATE_BODY_BIT_END,
+       STATE_FINISHED,
+};
+
+static unsigned char kbd_keycodes[256] = {
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_A,
+       KEY_B,          KEY_C,          KEY_D,          KEY_E,          KEY_F,
+       KEY_G,          KEY_H,          KEY_I,          KEY_J,          KEY_K,
+       KEY_L,          KEY_M,          KEY_N,          KEY_O,          KEY_P,
+       KEY_Q,          KEY_R,          KEY_S,          KEY_T,          KEY_U,
+       KEY_V,          KEY_W,          KEY_X,          KEY_Y,          KEY_Z,
+       KEY_1,          KEY_2,          KEY_3,          KEY_4,          KEY_5,
+       KEY_6,          KEY_7,          KEY_8,          KEY_9,          KEY_0,
+       KEY_ENTER,      KEY_ESC,        KEY_BACKSPACE,  KEY_TAB,        KEY_SPACE,
+       KEY_MINUS,      KEY_EQUAL,      KEY_LEFTBRACE,  KEY_RIGHTBRACE, KEY_BACKSLASH,
+       KEY_RESERVED,   KEY_SEMICOLON,  KEY_APOSTROPHE, KEY_GRAVE,      KEY_COMMA,
+       KEY_DOT,        KEY_SLASH,      KEY_CAPSLOCK,   KEY_F1,         KEY_F2,
+       KEY_F3,         KEY_F4,         KEY_F5,         KEY_F6,         KEY_F7,
+       KEY_F8,         KEY_F9,         KEY_F10,        KEY_F11,        KEY_F12,
+       KEY_SYSRQ,      KEY_SCROLLLOCK, KEY_PAUSE,      KEY_INSERT,     KEY_HOME,
+       KEY_PAGEUP,     KEY_DELETE,     KEY_END,        KEY_PAGEDOWN,   KEY_RIGHT,
+       KEY_LEFT,       KEY_DOWN,       KEY_UP,         KEY_NUMLOCK,    KEY_KPSLASH,
+       KEY_KPASTERISK, KEY_KPMINUS,    KEY_KPPLUS,     KEY_KPENTER,    KEY_KP1,
+       KEY_KP2,        KEY_KP3,        KEY_KP4,        KEY_KP5,        KEY_KP6,
+       KEY_KP7,        KEY_KP8,        KEY_KP9,        KEY_KP0,        KEY_KPDOT,
+       KEY_102ND,      KEY_COMPOSE,    KEY_POWER,      KEY_KPEQUAL,    KEY_F13,
+       KEY_F14,        KEY_F15,        KEY_F16,        KEY_F17,        KEY_F18,
+       KEY_F19,        KEY_F20,        KEY_F21,        KEY_F22,        KEY_F23,
+       KEY_F24,        KEY_OPEN,       KEY_HELP,       KEY_PROPS,      KEY_FRONT,
+       KEY_STOP,       KEY_AGAIN,      KEY_UNDO,       KEY_CUT,        KEY_COPY,
+       KEY_PASTE,      KEY_FIND,       KEY_MUTE,       KEY_VOLUMEUP,   KEY_VOLUMEDOWN,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_KPCOMMA,    KEY_RESERVED,
+       KEY_RO,         KEY_KATAKANAHIRAGANA, KEY_YEN,  KEY_HENKAN,     KEY_MUHENKAN,
+       KEY_KPJPCOMMA,  KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_HANGUEL,
+       KEY_HANJA,      KEY_KATAKANA,   KEY_HIRAGANA,   KEY_ZENKAKUHANKAKU, KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_LEFTCTRL,
+       KEY_LEFTSHIFT,  KEY_LEFTALT,    KEY_LEFTMETA,   KEY_RIGHTCTRL,  KEY_RIGHTSHIFT,
+       KEY_RIGHTALT,   KEY_RIGHTMETA,  KEY_PLAYPAUSE,  KEY_STOPCD,     KEY_PREVIOUSSONG,
+       KEY_NEXTSONG,   KEY_EJECTCD,    KEY_VOLUMEUP,   KEY_VOLUMEDOWN, KEY_MUTE,
+       KEY_WWW,        KEY_BACK,       KEY_FORWARD,    KEY_STOP,       KEY_FIND,
+       KEY_SCROLLUP,   KEY_SCROLLDOWN, KEY_EDIT,       KEY_SLEEP,      KEY_COFFEE,
+       KEY_REFRESH,    KEY_CALC,       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED
+};
+
+static void mce_kbd_rx_timeout(unsigned long data)
+{
+       struct mce_kbd_dec *mce_kbd = (struct mce_kbd_dec *)data;
+       int i;
+       unsigned char maskcode;
+
+       IR_dprintk(2, "timer callback clearing all keys\n");
+
+       for (i = 0; i < 7; i++) {
+               maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i];
+               input_report_key(mce_kbd->idev, maskcode, 0);
+       }
+
+       for (i = 0; i < MCIR2_MASK_KEYS_START; i++)
+               input_report_key(mce_kbd->idev, kbd_keycodes[i], 0);
+}
+
+static enum mce_kbd_mode mce_kbd_mode(struct mce_kbd_dec *data)
+{
+       switch (data->header & MCIR2_MODE_MASK) {
+       case MCIR2_KEYBOARD_HEADER:
+               return MCIR2_MODE_KEYBOARD;
+       case MCIR2_MOUSE_HEADER:
+               return MCIR2_MODE_MOUSE;
+       default:
+               return MCIR2_MODE_UNKNOWN;
+       }
+}
+
+static void ir_mce_kbd_process_keyboard_data(struct input_dev *idev,
+                                            u32 scancode)
+{
+       u8 keydata   = (scancode >> 8) & 0xff;
+       u8 shiftmask = scancode & 0xff;
+       unsigned char keycode, maskcode;
+       int i, keystate;
+
+       IR_dprintk(1, "keyboard: keydata = 0x%02x, shiftmask = 0x%02x\n",
+                  keydata, shiftmask);
+
+       for (i = 0; i < 7; i++) {
+               maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i];
+               if (shiftmask & (1 << i))
+                       keystate = 1;
+               else
+                       keystate = 0;
+               input_report_key(idev, maskcode, keystate);
+       }
+
+       if (keydata) {
+               keycode = kbd_keycodes[keydata];
+               input_report_key(idev, keycode, 1);
+       } else {
+               for (i = 0; i < MCIR2_MASK_KEYS_START; i++)
+                       input_report_key(idev, kbd_keycodes[i], 0);
+       }
+}
+
+static void ir_mce_kbd_process_mouse_data(struct input_dev *idev, u32 scancode)
+{
+       /* raw mouse coordinates */
+       u8 xdata = (scancode >> 7) & 0x7f;
+       u8 ydata = (scancode >> 14) & 0x7f;
+       int x, y;
+       /* mouse buttons */
+       bool right = scancode & 0x40;
+       bool left  = scancode & 0x20;
+
+       if (xdata & 0x40)
+               x = -((~xdata & 0x7f) + 1);
+       else
+               x = xdata;
+
+       if (ydata & 0x40)
+               y = -((~ydata & 0x7f) + 1);
+       else
+               y = ydata;
+
+       IR_dprintk(1, "mouse: x = %d, y = %d, btns = %s%s\n",
+                  x, y, left ? "L" : "", right ? "R" : "");
+
+       input_report_rel(idev, REL_X, x);
+       input_report_rel(idev, REL_Y, y);
+
+       input_report_key(idev, BTN_LEFT, left);
+       input_report_key(idev, BTN_RIGHT, right);
+}
+
+/**
+ * ir_mce_kbd_decode() - Decode one mce_kbd pulse or space
+ * @dev:       the struct rc_dev descriptor of the device
+ * @ev:                the struct ir_raw_event descriptor of the pulse/space
+ *
+ * This function returns -EINVAL if the pulse violates the state machine
+ */
+static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
+{
+       struct mce_kbd_dec *data = &dev->raw->mce_kbd;
+       u32 scancode;
+       unsigned long delay;
+
+       if (!(dev->raw->enabled_protocols & RC_TYPE_MCE_KBD))
+               return 0;
+
+       if (!is_timing_event(ev)) {
+               if (ev.reset)
+                       data->state = STATE_INACTIVE;
+               return 0;
+       }
+
+       if (!geq_margin(ev.duration, MCIR2_UNIT, MCIR2_UNIT / 2))
+               goto out;
+
+again:
+       IR_dprintk(2, "started at state %i (%uus %s)\n",
+                  data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+
+       if (!geq_margin(ev.duration, MCIR2_UNIT, MCIR2_UNIT / 2))
+               return 0;
+
+       switch (data->state) {
+
+       case STATE_INACTIVE:
+               if (!ev.pulse)
+                       break;
+
+               /* Note: larger margin on first pulse since each MCIR2_UNIT
+                  is quite short and some hardware takes some time to
+                  adjust to the signal */
+               if (!eq_margin(ev.duration, MCIR2_PREFIX_PULSE, MCIR2_UNIT))
+                       break;
+
+               data->state = STATE_HEADER_BIT_START;
+               data->count = 0;
+               data->header = 0;
+               return 0;
+
+       case STATE_HEADER_BIT_START:
+               if (geq_margin(ev.duration, MCIR2_MAX_LEN, MCIR2_UNIT / 2))
+                       break;
+
+               data->header <<= 1;
+               if (ev.pulse)
+                       data->header |= 1;
+               data->count++;
+               data->state = STATE_HEADER_BIT_END;
+               return 0;
+
+       case STATE_HEADER_BIT_END:
+               if (!is_transition(&ev, &dev->raw->prev_ev))
+                       break;
+
+               decrease_duration(&ev, MCIR2_BIT_END);
+
+               if (data->count != MCIR2_HEADER_NBITS) {
+                       data->state = STATE_HEADER_BIT_START;
+                       goto again;
+               }
+
+               switch (mce_kbd_mode(data)) {
+               case MCIR2_MODE_KEYBOARD:
+                       data->wanted_bits = MCIR2_KEYBOARD_NBITS;
+                       break;
+               case MCIR2_MODE_MOUSE:
+                       data->wanted_bits = MCIR2_MOUSE_NBITS;
+                       break;
+               default:
+                       IR_dprintk(1, "not keyboard or mouse data\n");
+                       goto out;
+               }
+
+               data->count = 0;
+               data->body = 0;
+               data->state = STATE_BODY_BIT_START;
+               goto again;
+
+       case STATE_BODY_BIT_START:
+               if (geq_margin(ev.duration, MCIR2_MAX_LEN, MCIR2_UNIT / 2))
+                       break;
+
+               data->body <<= 1;
+               if (ev.pulse)
+                       data->body |= 1;
+               data->count++;
+               data->state = STATE_BODY_BIT_END;
+               return 0;
+
+       case STATE_BODY_BIT_END:
+               if (!is_transition(&ev, &dev->raw->prev_ev))
+                       break;
+
+               if (data->count == data->wanted_bits)
+                       data->state = STATE_FINISHED;
+               else
+                       data->state = STATE_BODY_BIT_START;
+
+               decrease_duration(&ev, MCIR2_BIT_END);
+               goto again;
+
+       case STATE_FINISHED:
+               if (ev.pulse)
+                       break;
+
+               switch (data->wanted_bits) {
+               case MCIR2_KEYBOARD_NBITS:
+                       scancode = data->body & 0xffff;
+                       IR_dprintk(1, "keyboard data 0x%08x\n", data->body);
+                       if (dev->timeout)
+                               delay = usecs_to_jiffies(dev->timeout / 1000);
+                       else
+                               delay = msecs_to_jiffies(100);
+                       mod_timer(&data->rx_timeout, jiffies + delay);
+                       /* Pass data to keyboard buffer parser */
+                       ir_mce_kbd_process_keyboard_data(data->idev, scancode);
+                       break;
+               case MCIR2_MOUSE_NBITS:
+                       scancode = data->body & 0x1fffff;
+                       IR_dprintk(1, "mouse data 0x%06x\n", scancode);
+                       /* Pass data to mouse buffer parser */
+                       ir_mce_kbd_process_mouse_data(data->idev, scancode);
+                       break;
+               default:
+                       IR_dprintk(1, "not keyboard or mouse data\n");
+                       goto out;
+               }
+
+               data->state = STATE_INACTIVE;
+               input_sync(data->idev);
+               return 0;
+       }
+
+out:
+       IR_dprintk(1, "failed at state %i (%uus %s)\n",
+                  data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+       data->state = STATE_INACTIVE;
+       input_sync(data->idev);
+       return -EINVAL;
+}
+
+static int ir_mce_kbd_register(struct rc_dev *dev)
+{
+       struct mce_kbd_dec *mce_kbd = &dev->raw->mce_kbd;
+       struct input_dev *idev;
+       int i, ret;
+
+       idev = input_allocate_device();
+       if (!idev)
+               return -ENOMEM;
+
+       snprintf(mce_kbd->name, sizeof(mce_kbd->name),
+                "MCE IR Keyboard/Mouse (%s)", dev->driver_name);
+       strlcat(mce_kbd->phys, "/input0", sizeof(mce_kbd->phys));
+
+       idev->name = mce_kbd->name;
+       idev->phys = mce_kbd->phys;
+
+       /* Keyboard bits */
+       set_bit(EV_KEY, idev->evbit);
+       set_bit(EV_REP, idev->evbit);
+       for (i = 0; i < sizeof(kbd_keycodes); i++)
+               set_bit(kbd_keycodes[i], idev->keybit);
+
+       /* Mouse bits */
+       set_bit(EV_REL, idev->evbit);
+       set_bit(REL_X, idev->relbit);
+       set_bit(REL_Y, idev->relbit);
+       set_bit(BTN_LEFT, idev->keybit);
+       set_bit(BTN_RIGHT, idev->keybit);
+
+       /* Report scancodes too */
+       set_bit(EV_MSC, idev->evbit);
+       set_bit(MSC_SCAN, idev->mscbit);
+
+       setup_timer(&mce_kbd->rx_timeout, mce_kbd_rx_timeout,
+                   (unsigned long)mce_kbd);
+
+       input_set_drvdata(idev, mce_kbd);
+
+#if 0
+       /* Adding this reference means two input devices are associated with
+        * this rc-core device, which ir-keytable doesn't cope with yet */
+       idev->dev.parent = &dev->dev;
+#endif
+
+       ret = input_register_device(idev);
+       if (ret < 0) {
+               input_free_device(idev);
+               return -EIO;
+       }
+
+       mce_kbd->idev = idev;
+
+       return 0;
+}
+
+static int ir_mce_kbd_unregister(struct rc_dev *dev)
+{
+       struct mce_kbd_dec *mce_kbd = &dev->raw->mce_kbd;
+       struct input_dev *idev = mce_kbd->idev;
+
+       del_timer_sync(&mce_kbd->rx_timeout);
+       input_unregister_device(idev);
+
+       return 0;
+}
+
+static struct ir_raw_handler mce_kbd_handler = {
+       .protocols      = RC_TYPE_MCE_KBD,
+       .decode         = ir_mce_kbd_decode,
+       .raw_register   = ir_mce_kbd_register,
+       .raw_unregister = ir_mce_kbd_unregister,
+};
+
+static int __init ir_mce_kbd_decode_init(void)
+{
+       ir_raw_handler_register(&mce_kbd_handler);
+
+       printk(KERN_INFO "IR MCE Keyboard/mouse protocol handler initialized\n");
+       return 0;
+}
+
+static void __exit ir_mce_kbd_decode_exit(void)
+{
+       ir_raw_handler_unregister(&mce_kbd_handler);
+}
+
+module_init(ir_mce_kbd_decode_init);
+module_exit(ir_mce_kbd_decode_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
+MODULE_DESCRIPTION("MCE Keyboard/mouse IR protocol decoder");
index 423ed45..27808bb 100644 (file)
@@ -355,6 +355,7 @@ static void init_decoders(struct work_struct *work)
        load_rc6_decode();
        load_jvc_decode();
        load_sony_decode();
+       load_mce_kbd_decode();
        load_lirc_codec();
 
        /* If needed, we may later add some init code. In this case,
index d20168f..682009d 100644 (file)
@@ -382,7 +382,7 @@ static int ite_set_tx_duty_cycle(struct rc_dev *rcdev, u32 duty_cycle)
 /* transmit out IR pulses; what you get here is a batch of alternating
  * pulse/space/pulse/space lengths that we should write out completely through
  * the FIFO, blocking on a full FIFO */
-static int ite_tx_ir(struct rc_dev *rcdev, int *txbuf, u32 n)
+static int ite_tx_ir(struct rc_dev *rcdev, unsigned *txbuf, unsigned n)
 {
        unsigned long flags;
        struct ite_dev *dev = rcdev->priv;
@@ -398,9 +398,6 @@ static int ite_tx_ir(struct rc_dev *rcdev, int *txbuf, u32 n)
        /* clear the array just in case */
        memset(last_sent, 0, ARRAY_SIZE(last_sent));
 
-       /* n comes in bytes; convert to ints */
-       n /= sizeof(int);
-
        spin_lock_irqsave(&dev->lock, flags);
 
        /* let everybody know we're now transmitting */
index 01b69bc..c3907e2 100644 (file)
@@ -29,7 +29,7 @@ static struct rc_map_table rc6_mce[] = {
 
        { 0x800f040a, KEY_DELETE },
        { 0x800f040b, KEY_ENTER },
-       { 0x800f040c, KEY_POWER },              /* PC Power */
+       { 0x800f040c, KEY_SLEEP },              /* Formerly PC Power */
        { 0x800f040d, KEY_MEDIA },              /* Windows MCE button */
        { 0x800f040e, KEY_MUTE },
        { 0x800f040f, KEY_INFO },
@@ -44,7 +44,6 @@ static struct rc_map_table rc6_mce[] = {
        { 0x800f0416, KEY_PLAY },
        { 0x800f0417, KEY_RECORD },
        { 0x800f0418, KEY_PAUSE },
-       { 0x800f046e, KEY_PLAYPAUSE },
        { 0x800f0419, KEY_STOP },
        { 0x800f041a, KEY_NEXT },
        { 0x800f041b, KEY_PREVIOUS },
index ec972dc..85ff9a1 100644 (file)
@@ -692,20 +692,18 @@ static void mce_flush_rx_buffer(struct mceusb_dev *ir, int size)
 }
 
 /* Send data out the IR blaster port(s) */
-static int mceusb_tx_ir(struct rc_dev *dev, int *txbuf, u32 n)
+static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
 {
        struct mceusb_dev *ir = dev->priv;
        int i, ret = 0;
-       int count, cmdcount = 0;
+       int cmdcount = 0;
        unsigned char *cmdbuf; /* MCE command buffer */
        long signal_duration = 0; /* Singnal length in us */
        struct timeval start_time, end_time;
 
        do_gettimeofday(&start_time);
 
-       count = n / sizeof(int);
-
-       cmdbuf = kzalloc(sizeof(int) * MCE_CMDBUF_SIZE, GFP_KERNEL);
+       cmdbuf = kzalloc(sizeof(unsigned) * MCE_CMDBUF_SIZE, GFP_KERNEL);
        if (!cmdbuf)
                return -ENOMEM;
 
@@ -774,7 +772,7 @@ static int mceusb_tx_ir(struct rc_dev *dev, int *txbuf, u32 n)
 
 out:
        kfree(cmdbuf);
-       return ret ? ret : n;
+       return ret ? ret : count;
 }
 
 /* Sets active IR outputs -- mce devices typically have two */
index ce595f9..eae05b5 100644 (file)
@@ -546,24 +546,18 @@ static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier)
  * number may larger than TXFCONT (0xff). So in interrupt_handler, it has to
  * set TXFCONT as 0xff, until buf_count less than 0xff.
  */
-static int nvt_tx_ir(struct rc_dev *dev, int *txbuf, u32 n)
+static int nvt_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned n)
 {
        struct nvt_dev *nvt = dev->priv;
        unsigned long flags;
-       size_t cur_count;
        unsigned int i;
        u8 iren;
        int ret;
 
        spin_lock_irqsave(&nvt->tx.lock, flags);
 
-       if (n >= TX_BUF_LEN) {
-               nvt->tx.buf_count = cur_count = TX_BUF_LEN;
-               ret = TX_BUF_LEN;
-       } else {
-               nvt->tx.buf_count = cur_count = n;
-               ret = n;
-       }
+       ret = min((unsigned)(TX_BUF_LEN / sizeof(unsigned)), n);
+       nvt->tx.buf_count = (ret * sizeof(unsigned));
 
        memcpy(nvt->tx.buf, txbuf, nvt->tx.buf_count);
 
index 873b387..04c2c72 100644 (file)
@@ -84,6 +84,17 @@ struct ir_raw_event_ctrl {
                unsigned count;
                unsigned wanted_bits;
        } rc5_sz;
+       struct mce_kbd_dec {
+               struct input_dev *idev;
+               struct timer_list rx_timeout;
+               char name[64];
+               char phys[64];
+               int state;
+               u8 header;
+               u32 body;
+               unsigned count;
+               unsigned wanted_bits;
+       } mce_kbd;
        struct lirc_codec {
                struct rc_dev *dev;
                struct lirc_driver *drv;
@@ -182,6 +193,13 @@ void ir_raw_init(void);
 #define load_sony_decode()     0
 #endif
 
+/* from ir-mce_kbd-decoder.c */
+#ifdef CONFIG_IR_MCE_KBD_DECODER_MODULE
+#define load_mce_kbd_decode()  request_module("ir-mce_kbd-decoder")
+#else
+#define load_mce_kbd_decode()  0
+#endif
+
 /* from ir-lirc-codec.c */
 #ifdef CONFIG_IR_LIRC_CODEC_MODULE
 #define load_lirc_codec()      request_module("ir-lirc-codec")
index cc846b2..efc6a51 100644 (file)
@@ -101,21 +101,14 @@ static int loop_set_rx_carrier_range(struct rc_dev *dev, u32 min, u32 max)
        return 0;
 }
 
-static int loop_tx_ir(struct rc_dev *dev, int *txbuf, u32 n)
+static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
 {
        struct loopback_dev *lodev = dev->priv;
        u32 rxmask;
-       unsigned count;
        unsigned total_duration = 0;
        unsigned i;
        DEFINE_IR_RAW_EVENT(rawir);
 
-       if (n == 0 || n % sizeof(int)) {
-               dprintk("invalid tx buffer size\n");
-               return -EINVAL;
-       }
-
-       count = n / sizeof(int);
        for (i = 0; i < count; i++)
                total_duration += abs(txbuf[i]);
 
@@ -142,7 +135,7 @@ static int loop_tx_ir(struct rc_dev *dev, int *txbuf, u32 n)
 
        for (i = 0; i < count; i++) {
                rawir.pulse = i % 2 ? false : true;
-               rawir.duration = abs(txbuf[i]) * 1000;
+               rawir.duration = txbuf[i] * 1000;
                if (rawir.duration)
                        ir_raw_event_store_with_filter(dev, &rawir);
        }
@@ -158,7 +151,7 @@ out:
        /* Lirc expects this function to take as long as the total duration */
        set_current_state(TASK_INTERRUPTIBLE);
        schedule_timeout(usecs_to_jiffies(total_duration));
-       return n;
+       return count;
 }
 
 static void loop_set_idle(struct rc_dev *dev, bool enable)
index 3186ac7..51a23f4 100644 (file)
@@ -735,6 +735,7 @@ static struct {
        { RC_TYPE_JVC,          "jvc"           },
        { RC_TYPE_SONY,         "sony"          },
        { RC_TYPE_RC5_SZ,       "rc-5-sz"       },
+       { RC_TYPE_MCE_KBD,      "mce_kbd"       },
        { RC_TYPE_LIRC,         "lirc"          },
        { RC_TYPE_OTHER,        "other"         },
 };
@@ -1099,7 +1100,6 @@ int rc_register_device(struct rc_dev *dev)
                if (rc < 0)
                        goto out_input;
        }
-       mutex_unlock(&dev->lock);
 
        if (dev->change_protocol) {
                rc = dev->change_protocol(dev, rc_map->rc_type);
@@ -1107,6 +1107,8 @@ int rc_register_device(struct rc_dev *dev)
                        goto out_raw;
        }
 
+       mutex_unlock(&dev->lock);
+
        IR_dprintk(1, "Registered rc%ld (driver: %s, remote: %s, mode %s)\n",
                   dev->devno,
                   dev->driver_name ? dev->driver_name : "unknown",
index 5147767..a166044 100644 (file)
@@ -205,6 +205,7 @@ struct redrat3_dev {
 
        /* rx signal timeout timer */
        struct timer_list rx_timeout;
+       u32 hw_timeout;
 
        /* Is the device currently receiving? */
        bool recv_in_progress;
@@ -414,20 +415,10 @@ static u32 redrat3_us_to_len(u32 microsec)
 
 }
 
-/* timer callback to send long trailing space on receive timeout */
+/* timer callback to send reset event */
 static void redrat3_rx_timeout(unsigned long data)
 {
        struct redrat3_dev *rr3 = (struct redrat3_dev *)data;
-       DEFINE_IR_RAW_EVENT(rawir);
-
-       rawir.pulse = false;
-       rawir.duration = rr3->rc->timeout;
-       rr3_dbg(rr3->dev, "storing trailing space with duration %d\n",
-               rawir.duration);
-       ir_raw_event_store_with_filter(rr3->rc, &rawir);
-
-       rr3_dbg(rr3->dev, "calling ir_raw_event_handle\n");
-       ir_raw_event_handle(rr3->rc);
 
        rr3_dbg(rr3->dev, "calling ir_raw_event_reset\n");
        ir_raw_event_reset(rr3->rc);
@@ -438,7 +429,7 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3)
        DEFINE_IR_RAW_EVENT(rawir);
        struct redrat3_signal_header header;
        struct device *dev;
-       int i;
+       int i, trailer = 0;
        unsigned long delay;
        u32 mod_freq, single_len;
        u16 *len_vals;
@@ -464,7 +455,8 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3)
        if (!(header.length >= RR3_HEADER_LENGTH))
                dev_warn(dev, "read returned less than rr3 header len\n");
 
-       delay = usecs_to_jiffies(rr3->rc->timeout / 1000);
+       /* Make sure we reset the IR kfifo after a bit of inactivity */
+       delay = usecs_to_jiffies(rr3->hw_timeout);
        mod_timer(&rr3->rx_timeout, jiffies + delay);
 
        memcpy(&tmp32, sig_data + RR3_PAUSE_OFFSET, sizeof(tmp32));
@@ -506,9 +498,6 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3)
                u16 val = len_vals[data_vals[i]];
                single_len = redrat3_len_to_us((u32)be16_to_cpu(val));
 
-               /* cap the value to IR_MAX_DURATION */
-               single_len &= IR_MAX_DURATION;
-
                /* we should always get pulse/space/pulse/space samples */
                if (i % 2)
                        rawir.pulse = false;
@@ -516,6 +505,12 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3)
                        rawir.pulse = true;
 
                rawir.duration = US_TO_NS(single_len);
+               /* Save initial pulse length to fudge trailer */
+               if (i == 0)
+                       trailer = rawir.duration;
+               /* cap the value to IR_MAX_DURATION */
+               rawir.duration &= IR_MAX_DURATION;
+
                rr3_dbg(dev, "storing %s with duration %d (i: %d)\n",
                        rawir.pulse ? "pulse" : "space", rawir.duration, i);
                ir_raw_event_store_with_filter(rr3->rc, &rawir);
@@ -525,7 +520,10 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3)
        if (i % 2) {
                rawir.pulse = false;
                /* this duration is made up, and may not be ideal... */
-               rawir.duration = rr3->rc->timeout / 2;
+               if (trailer < US_TO_NS(1000))
+                       rawir.duration = US_TO_NS(2800);
+               else
+                       rawir.duration = trailer;
                rr3_dbg(dev, "storing trailing space with duration %d\n",
                        rawir.duration);
                ir_raw_event_store_with_filter(rr3->rc, &rawir);
@@ -629,36 +627,31 @@ static inline void redrat3_delete(struct redrat3_dev *rr3,
        kfree(rr3);
 }
 
-static u32 redrat3_get_timeout(struct device *dev,
-                              struct rc_dev *rc, struct usb_device *udev)
+static u32 redrat3_get_timeout(struct redrat3_dev *rr3)
 {
        u32 *tmp;
-       u32 timeout = MS_TO_NS(150); /* a sane default, if things go haywire */
+       u32 timeout = MS_TO_US(150); /* a sane default, if things go haywire */
        int len, ret, pipe;
 
        len = sizeof(*tmp);
        tmp = kzalloc(len, GFP_KERNEL);
        if (!tmp) {
-               dev_warn(dev, "Memory allocation faillure\n");
+               dev_warn(rr3->dev, "Memory allocation faillure\n");
                return timeout;
        }
 
-       pipe = usb_rcvctrlpipe(udev, 0);
-       ret = usb_control_msg(udev, pipe, RR3_GET_IR_PARAM,
+       pipe = usb_rcvctrlpipe(rr3->udev, 0);
+       ret = usb_control_msg(rr3->udev, pipe, RR3_GET_IR_PARAM,
                              USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
                              RR3_IR_IO_SIG_TIMEOUT, 0, tmp, len, HZ * 5);
        if (ret != len) {
-               dev_warn(dev, "Failed to read timeout from hardware\n");
+               dev_warn(rr3->dev, "Failed to read timeout from hardware\n");
                return timeout;
        }
 
-       timeout = US_TO_NS(redrat3_len_to_us(be32_to_cpu(*tmp)));
-       if (timeout < rc->min_timeout)
-               timeout = rc->min_timeout;
-       else if (timeout > rc->max_timeout)
-               timeout = rc->max_timeout;
+       timeout = redrat3_len_to_us(be32_to_cpu(*tmp));
 
-       rr3_dbg(dev, "Got timeout of %d ms\n", timeout / (1000 * 1000));
+       rr3_dbg(rr3->dev, "Got timeout of %d ms\n", timeout / 1000);
        return timeout;
 }
 
@@ -1110,9 +1103,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3)
        rc->priv = rr3;
        rc->driver_type = RC_DRIVER_IR_RAW;
        rc->allowed_protos = RC_TYPE_ALL;
-       rc->min_timeout = MS_TO_NS(RR3_RX_MIN_TIMEOUT);
-       rc->max_timeout = MS_TO_NS(RR3_RX_MAX_TIMEOUT);
-       rc->timeout = redrat3_get_timeout(dev, rc, rr3->udev);
+       rc->timeout = US_TO_NS(2750);
        rc->tx_ir = redrat3_transmit_ir;
        rc->s_tx_carrier = redrat3_set_tx_carrier;
        rc->driver_name = DRIVER_NAME;
@@ -1186,7 +1177,7 @@ static int __devinit redrat3_dev_probe(struct usb_interface *intf,
        rr3 = kzalloc(sizeof(*rr3), GFP_KERNEL);
        if (rr3 == NULL) {
                dev_err(dev, "Memory allocation failure\n");
-               goto error;
+               goto no_endpoints;
        }
 
        rr3->dev = &intf->dev;
@@ -1242,6 +1233,9 @@ static int __devinit redrat3_dev_probe(struct usb_interface *intf,
        if (retval < 0)
                goto error;
 
+       /* store current hardware timeout, in us, will use for kfifo resets */
+       rr3->hw_timeout = redrat3_get_timeout(rr3);
+
        /* default.. will get overridden by any sends with a freq defined */
        rr3->carrier = 38000;
 
@@ -1280,6 +1274,7 @@ static void __devexit redrat3_dev_disconnect(struct usb_interface *intf)
 
        usb_set_intfdata(intf, NULL);
        rc_unregister_device(rr3->rc);
+       del_timer_sync(&rr3->rx_timeout);
        redrat3_delete(rr3, udev);
 
        rr3_ftr(&intf->dev, "RedRat3 IR Transceiver now disconnected\n");
index 5d06b89..bec8abc 100644 (file)
@@ -6,8 +6,8 @@
  *  could probably support others (Winbond WEC102X, NatSemi, etc)
  *  with minor modifications.
  *
- *  Original Author: David Härdeman <david@hardeman.nu>
- *     Copyright (C) 2009 - 2010 David Härdeman <david@hardeman.nu>
+ *  Original Author: David Härdeman <david@hardeman.nu>
+ *     Copyright (C) 2009 - 2011 David Härdeman <david@hardeman.nu>
  *
  *  Dedicated to my daughter Matilda, without whose loving attention this
  *  driver would have been finished in half the time and with a fraction
@@ -577,16 +577,12 @@ wbcir_txmask(struct rc_dev *dev, u32 mask)
 }
 
 static int
-wbcir_tx(struct rc_dev *dev, int *buf, u32 bufsize)
+wbcir_tx(struct rc_dev *dev, unsigned *buf, unsigned count)
 {
        struct wbcir_data *data = dev->priv;
-       u32 count;
        unsigned i;
        unsigned long flags;
 
-       /* bufsize has been sanity checked by the caller */
-       count = bufsize / sizeof(int);
-
        /* Not sure if this is possible, but better safe than sorry */
        spin_lock_irqsave(&data->spinlock, flags);
        if (data->txstate != WBCIR_TXSTATE_INACTIVE) {
@@ -876,18 +872,8 @@ wbcir_init_hw(struct wbcir_data *data)
        /* prescaler 1.0, tx/rx fifo lvl 16 */
        outb(0x30, data->sbase + WBCIR_REG_SP3_EXCR2);
 
-       /* Set baud divisor to generate one byte per bit/cell */
-       switch (protocol) {
-       case IR_PROTOCOL_RC5:
-               outb(0xA7, data->sbase + WBCIR_REG_SP3_BGDL);
-               break;
-       case IR_PROTOCOL_RC6:
-               outb(0x53, data->sbase + WBCIR_REG_SP3_BGDL);
-               break;
-       case IR_PROTOCOL_NEC:
-               outb(0x69, data->sbase + WBCIR_REG_SP3_BGDL);
-               break;
-       }
+       /* Set baud divisor to sample every 10 us */
+       outb(0x0F, data->sbase + WBCIR_REG_SP3_BGDL);
        outb(0x00, data->sbase + WBCIR_REG_SP3_BGDH);
 
        /* Set CEIR mode */
@@ -896,9 +882,9 @@ wbcir_init_hw(struct wbcir_data *data)
        inb(data->sbase + WBCIR_REG_SP3_LSR); /* Clear LSR */
        inb(data->sbase + WBCIR_REG_SP3_MSR); /* Clear MSR */
 
-       /* Disable RX demod, run-length encoding/decoding, set freq span */
+       /* Disable RX demod, enable run-length enc/dec, set freq span */
        wbcir_select_bank(data, WBCIR_BANK_7);
-       outb(0x10, data->sbase + WBCIR_REG_SP3_RCCFG);
+       outb(0x90, data->sbase + WBCIR_REG_SP3_RCCFG);
 
        /* Disable timer */
        wbcir_select_bank(data, WBCIR_BANK_4);
index bb53de7..f574dc0 100644 (file)
@@ -489,6 +489,15 @@ config VIDEO_TCM825X
          This is a driver for the Toshiba TCM825x VGA camera sensor.
          It is used for example in Nokia N800.
 
+comment "Flash devices"
+
+config VIDEO_ADP1653
+       tristate "ADP1653 flash support"
+       depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER
+       ---help---
+         This is a driver for the ADP1653 flash controller. It is used for
+         example in Nokia N900.
+
 comment "Video improvement chips"
 
 config VIDEO_UPD64031A
@@ -707,6 +716,8 @@ source "drivers/media/video/cx18/Kconfig"
 
 source "drivers/media/video/saa7164/Kconfig"
 
+source "drivers/media/video/marvell-ccic/Kconfig"
+
 config VIDEO_M32R_AR
        tristate "AR devices"
        depends on M32R && VIDEO_V4L2
@@ -726,15 +737,6 @@ config VIDEO_M32R_AR_M64278
          To compile this driver as a module, choose M here: the
          module will be called arv.
 
-config VIDEO_CAFE_CCIC
-       tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support"
-       depends on PCI && I2C && VIDEO_V4L2
-       select VIDEO_OV7670
-       ---help---
-         This is a video4linux2 driver for the Marvell 88ALP01 integrated
-         CMOS camera controller.  This is the controller found on first-
-         generation OLPC systems.
-
 config VIDEO_SR030PC30
        tristate "SR030PC30 VGA camera sensor support"
        depends on I2C && VIDEO_V4L2
@@ -846,6 +848,12 @@ config SOC_CAMERA_OV2640
        help
          This is a ov2640 camera driver
 
+config SOC_CAMERA_OV5642
+       tristate "ov5642 camera support"
+       depends on SOC_CAMERA && I2C
+       help
+         This is a V4L2 camera driver for the OmniVision OV5642 sensor
+
 config SOC_CAMERA_OV6650
        tristate "ov6650 sensor support"
        depends on SOC_CAMERA && I2C
@@ -952,6 +960,14 @@ config  VIDEO_SAMSUNG_S5P_FIMC
          To compile this driver as a module, choose M here: the
          module will be called s5p-fimc.
 
+config VIDEO_ATMEL_ISI
+       tristate "ATMEL Image Sensor Interface (ISI) support"
+       depends on VIDEO_DEV && SOC_CAMERA && ARCH_AT91
+       select VIDEOBUF2_DMA_CONTIG
+       ---help---
+         This module makes the ATMEL Image Sensor Interface available
+         as a v4l2 device.
+
 config VIDEO_S5P_MIPI_CSIS
        tristate "Samsung S5P and EXYNOS4 MIPI CSI receiver driver"
        depends on VIDEO_V4L2 && PM_RUNTIME && PLAT_S5P && VIDEO_V4L2_SUBDEV_API
@@ -961,6 +977,8 @@ config VIDEO_S5P_MIPI_CSIS
          To compile this driver as a module, choose M here: the
          module will be called s5p-csis.
 
+source "drivers/media/video/s5p-tv/Kconfig"
+
 #
 # USB Multimedia device configuration
 #
@@ -1056,4 +1074,12 @@ config VIDEO_MEM2MEM_TESTDEV
          framework.
 
 
+config VIDEO_SAMSUNG_S5P_MFC
+       tristate "Samsung S5P MFC 5.1 Video Codec"
+       depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P
+       select VIDEOBUF2_DMA_CONTIG
+       default n
+       help
+           MFC 5.1 driver for V4L2.
+
 endif # V4L_MEM2MEM_DRIVERS
index f0fecd6..2723900 100644 (file)
@@ -70,6 +70,7 @@ obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o
 obj-$(CONFIG_VIDEO_SR030PC30)  += sr030pc30.o
 obj-$(CONFIG_VIDEO_NOON010PC30)        += noon010pc30.o
 obj-$(CONFIG_VIDEO_M5MOLS)     += m5mols/
+obj-$(CONFIG_VIDEO_ADP1653)    += adp1653.o
 
 obj-$(CONFIG_SOC_CAMERA_IMX074)                += imx074.o
 obj-$(CONFIG_SOC_CAMERA_MT9M001)       += mt9m001.o
@@ -78,6 +79,7 @@ obj-$(CONFIG_SOC_CAMERA_MT9T031)      += mt9t031.o
 obj-$(CONFIG_SOC_CAMERA_MT9T112)       += mt9t112.o
 obj-$(CONFIG_SOC_CAMERA_MT9V022)       += mt9v022.o
 obj-$(CONFIG_SOC_CAMERA_OV2640)                += ov2640.o
+obj-$(CONFIG_SOC_CAMERA_OV5642)                += ov5642.o
 obj-$(CONFIG_SOC_CAMERA_OV6650)                += ov6650.o
 obj-$(CONFIG_SOC_CAMERA_OV772X)                += ov772x.o
 obj-$(CONFIG_SOC_CAMERA_OV9640)                += ov9640.o
@@ -127,7 +129,8 @@ obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
 
 obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
 
-obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
+obj-$(CONFIG_VIDEO_CAFE_CCIC) += marvell-ccic/
+obj-$(CONFIG_VIDEO_MMP_CAMERA) += marvell-ccic/
 
 obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o
 
@@ -166,8 +169,11 @@ obj-$(CONFIG_VIDEO_PXA27x)         += pxa_camera.o
 obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2)     += sh_mobile_csi2.o
 obj-$(CONFIG_VIDEO_SH_MOBILE_CEU)      += sh_mobile_ceu_camera.o
 obj-$(CONFIG_VIDEO_OMAP1)              += omap1_camera.o
+obj-$(CONFIG_VIDEO_ATMEL_ISI)          += atmel-isi.o
 
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC)   += s5p-fimc/
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC)    += s5p-mfc/
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_TV)     += s5p-tv/
 
 obj-$(CONFIG_ARCH_DAVINCI)             += davinci/
 
diff --git a/drivers/media/video/adp1653.c b/drivers/media/video/adp1653.c
new file mode 100644 (file)
index 0000000..be7befd
--- /dev/null
@@ -0,0 +1,491 @@
+/*
+ * drivers/media/video/adp1653.c
+ *
+ * Copyright (C) 2008--2011 Nokia Corporation
+ *
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * Contributors:
+ *     Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *     Tuukka Toivonen <tuukkat76@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
+ *
+ * TODO:
+ * - fault interrupt handling
+ * - hardware strobe
+ * - power doesn't need to be ON if all lights are off
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <media/adp1653.h>
+#include <media/v4l2-device.h>
+
+#define TIMEOUT_MAX            820000
+#define TIMEOUT_STEP           54600
+#define TIMEOUT_MIN            (TIMEOUT_MAX - ADP1653_REG_CONFIG_TMR_SET_MAX \
+                                * TIMEOUT_STEP)
+#define TIMEOUT_US_TO_CODE(t)  ((TIMEOUT_MAX + (TIMEOUT_STEP / 2) - (t)) \
+                                / TIMEOUT_STEP)
+#define TIMEOUT_CODE_TO_US(c)  (TIMEOUT_MAX - (c) * TIMEOUT_STEP)
+
+/* Write values into ADP1653 registers. */
+static int adp1653_update_hw(struct adp1653_flash *flash)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+       u8 out_sel;
+       u8 config = 0;
+       int rval;
+
+       out_sel = ADP1653_INDICATOR_INTENSITY_uA_TO_REG(
+               flash->indicator_intensity->val)
+               << ADP1653_REG_OUT_SEL_ILED_SHIFT;
+
+       switch (flash->led_mode->val) {
+       case V4L2_FLASH_LED_MODE_NONE:
+               break;
+       case V4L2_FLASH_LED_MODE_FLASH:
+               /* Flash mode, light on with strobe, duration from timer */
+               config = ADP1653_REG_CONFIG_TMR_CFG;
+               config |= TIMEOUT_US_TO_CODE(flash->flash_timeout->val)
+                         << ADP1653_REG_CONFIG_TMR_SET_SHIFT;
+               break;
+       case V4L2_FLASH_LED_MODE_TORCH:
+               /* Torch mode, light immediately on, duration indefinite */
+               out_sel |= ADP1653_FLASH_INTENSITY_mA_TO_REG(
+                       flash->torch_intensity->val)
+                       << ADP1653_REG_OUT_SEL_HPLED_SHIFT;
+               break;
+       }
+
+       rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, out_sel);
+       if (rval < 0)
+               return rval;
+
+       rval = i2c_smbus_write_byte_data(client, ADP1653_REG_CONFIG, config);
+       if (rval < 0)
+               return rval;
+
+       return 0;
+}
+
+static int adp1653_get_fault(struct adp1653_flash *flash)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+       int fault;
+       int rval;
+
+       fault = i2c_smbus_read_byte_data(client, ADP1653_REG_FAULT);
+       if (IS_ERR_VALUE(fault))
+               return fault;
+
+       flash->fault |= fault;
+
+       if (!flash->fault)
+               return 0;
+
+       /* Clear faults. */
+       rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, 0);
+       if (IS_ERR_VALUE(rval))
+               return rval;
+
+       flash->led_mode->val = V4L2_FLASH_LED_MODE_NONE;
+
+       rval = adp1653_update_hw(flash);
+       if (IS_ERR_VALUE(rval))
+               return rval;
+
+       return flash->fault;
+}
+
+static int adp1653_strobe(struct adp1653_flash *flash, int enable)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+       u8 out_sel = ADP1653_INDICATOR_INTENSITY_uA_TO_REG(
+               flash->indicator_intensity->val)
+               << ADP1653_REG_OUT_SEL_ILED_SHIFT;
+       int rval;
+
+       if (flash->led_mode->val != V4L2_FLASH_LED_MODE_FLASH)
+               return -EBUSY;
+
+       if (!enable)
+               return i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL,
+                                                out_sel);
+
+       out_sel |= ADP1653_FLASH_INTENSITY_mA_TO_REG(
+               flash->flash_intensity->val)
+               << ADP1653_REG_OUT_SEL_HPLED_SHIFT;
+       rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, out_sel);
+       if (rval)
+               return rval;
+
+       /* Software strobe using i2c */
+       rval = i2c_smbus_write_byte_data(client, ADP1653_REG_SW_STROBE,
+               ADP1653_REG_SW_STROBE_SW_STROBE);
+       if (rval)
+               return rval;
+       return i2c_smbus_write_byte_data(client, ADP1653_REG_SW_STROBE, 0);
+}
+
+/* --------------------------------------------------------------------------
+ * V4L2 controls
+ */
+
+static int adp1653_get_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct adp1653_flash *flash =
+               container_of(ctrl->handler, struct adp1653_flash, ctrls);
+       int rval;
+
+       rval = adp1653_get_fault(flash);
+       if (IS_ERR_VALUE(rval))
+               return rval;
+
+       ctrl->cur.val = 0;
+
+       if (flash->fault & ADP1653_REG_FAULT_FLT_SCP)
+               ctrl->cur.val |= V4L2_FLASH_FAULT_SHORT_CIRCUIT;
+       if (flash->fault & ADP1653_REG_FAULT_FLT_OT)
+               ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_TEMPERATURE;
+       if (flash->fault & ADP1653_REG_FAULT_FLT_TMR)
+               ctrl->cur.val |= V4L2_FLASH_FAULT_TIMEOUT;
+       if (flash->fault & ADP1653_REG_FAULT_FLT_OV)
+               ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_VOLTAGE;
+
+       flash->fault = 0;
+
+       return 0;
+}
+
+static int adp1653_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct adp1653_flash *flash =
+               container_of(ctrl->handler, struct adp1653_flash, ctrls);
+       int rval;
+
+       rval = adp1653_get_fault(flash);
+       if (IS_ERR_VALUE(rval))
+               return rval;
+       if ((rval & (ADP1653_REG_FAULT_FLT_SCP |
+                    ADP1653_REG_FAULT_FLT_OT |
+                    ADP1653_REG_FAULT_FLT_OV)) &&
+           (ctrl->id == V4L2_CID_FLASH_STROBE ||
+            ctrl->id == V4L2_CID_FLASH_TORCH_INTENSITY ||
+            ctrl->id == V4L2_CID_FLASH_LED_MODE))
+               return -EBUSY;
+
+       switch (ctrl->id) {
+       case V4L2_CID_FLASH_STROBE:
+               return adp1653_strobe(flash, 1);
+       case V4L2_CID_FLASH_STROBE_STOP:
+               return adp1653_strobe(flash, 0);
+       }
+
+       return adp1653_update_hw(flash);
+}
+
+static const struct v4l2_ctrl_ops adp1653_ctrl_ops = {
+       .g_volatile_ctrl = adp1653_get_ctrl,
+       .s_ctrl = adp1653_set_ctrl,
+};
+
+static int adp1653_init_controls(struct adp1653_flash *flash)
+{
+       struct v4l2_ctrl *fault;
+
+       v4l2_ctrl_handler_init(&flash->ctrls, 9);
+
+       flash->led_mode =
+               v4l2_ctrl_new_std_menu(&flash->ctrls, &adp1653_ctrl_ops,
+                                      V4L2_CID_FLASH_LED_MODE,
+                                      V4L2_FLASH_LED_MODE_TORCH, ~0x7, 0);
+       v4l2_ctrl_new_std_menu(&flash->ctrls, &adp1653_ctrl_ops,
+                              V4L2_CID_FLASH_STROBE_SOURCE,
+                              V4L2_FLASH_STROBE_SOURCE_SOFTWARE, ~0x1, 0);
+       v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+                         V4L2_CID_FLASH_STROBE, 0, 0, 0, 0);
+       v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+                         V4L2_CID_FLASH_STROBE_STOP, 0, 0, 0, 0);
+       flash->flash_timeout =
+               v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+                                 V4L2_CID_FLASH_TIMEOUT, TIMEOUT_MIN,
+                                 flash->platform_data->max_flash_timeout,
+                                 TIMEOUT_STEP,
+                                 flash->platform_data->max_flash_timeout);
+       flash->flash_intensity =
+               v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+                                 V4L2_CID_FLASH_INTENSITY,
+                                 ADP1653_FLASH_INTENSITY_MIN,
+                                 flash->platform_data->max_flash_intensity,
+                                 1, flash->platform_data->max_flash_intensity);
+       flash->torch_intensity =
+               v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+                                 V4L2_CID_FLASH_TORCH_INTENSITY,
+                                 ADP1653_TORCH_INTENSITY_MIN,
+                                 flash->platform_data->max_torch_intensity,
+                                 ADP1653_FLASH_INTENSITY_STEP,
+                                 flash->platform_data->max_torch_intensity);
+       flash->indicator_intensity =
+               v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+                                 V4L2_CID_FLASH_INDICATOR_INTENSITY,
+                                 ADP1653_INDICATOR_INTENSITY_MIN,
+                                 flash->platform_data->max_indicator_intensity,
+                                 ADP1653_INDICATOR_INTENSITY_STEP,
+                                 ADP1653_INDICATOR_INTENSITY_MIN);
+       fault = v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+                                 V4L2_CID_FLASH_FAULT, 0,
+                                 V4L2_FLASH_FAULT_OVER_VOLTAGE
+                                 | V4L2_FLASH_FAULT_OVER_TEMPERATURE
+                                 | V4L2_FLASH_FAULT_SHORT_CIRCUIT, 0, 0);
+
+       if (flash->ctrls.error)
+               return flash->ctrls.error;
+
+       fault->is_volatile = 1;
+
+       flash->subdev.ctrl_handler = &flash->ctrls;
+       return 0;
+}
+
+/* --------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+static int
+adp1653_init_device(struct adp1653_flash *flash)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+       int rval;
+
+       /* Clear FAULT register by writing zero to OUT_SEL */
+       rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, 0);
+       if (rval < 0) {
+               dev_err(&client->dev, "failed writing fault register\n");
+               return -EIO;
+       }
+
+       mutex_lock(&flash->ctrls.lock);
+       /* Reset faults before reading new ones. */
+       flash->fault = 0;
+       rval = adp1653_get_fault(flash);
+       mutex_unlock(&flash->ctrls.lock);
+       if (rval > 0) {
+               dev_err(&client->dev, "faults detected: 0x%1.1x\n", rval);
+               return -EIO;
+       }
+
+       mutex_lock(&flash->ctrls.lock);
+       rval = adp1653_update_hw(flash);
+       mutex_unlock(&flash->ctrls.lock);
+       if (rval) {
+               dev_err(&client->dev,
+                       "adp1653_update_hw failed at %s\n", __func__);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int
+__adp1653_set_power(struct adp1653_flash *flash, int on)
+{
+       int ret;
+
+       ret = flash->platform_data->power(&flash->subdev, on);
+       if (ret < 0)
+               return ret;
+
+       if (!on)
+               return 0;
+
+       ret = adp1653_init_device(flash);
+       if (ret < 0)
+               flash->platform_data->power(&flash->subdev, 0);
+
+       return ret;
+}
+
+static int
+adp1653_set_power(struct v4l2_subdev *subdev, int on)
+{
+       struct adp1653_flash *flash = to_adp1653_flash(subdev);
+       int ret = 0;
+
+       mutex_lock(&flash->power_lock);
+
+       /* If the power count is modified from 0 to != 0 or from != 0 to 0,
+        * update the power state.
+        */
+       if (flash->power_count == !on) {
+               ret = __adp1653_set_power(flash, !!on);
+               if (ret < 0)
+                       goto done;
+       }
+
+       /* Update the power count. */
+       flash->power_count += on ? 1 : -1;
+       WARN_ON(flash->power_count < 0);
+
+done:
+       mutex_unlock(&flash->power_lock);
+       return ret;
+}
+
+static int adp1653_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+       return adp1653_set_power(sd, 1);
+}
+
+static int adp1653_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+       return adp1653_set_power(sd, 0);
+}
+
+static const struct v4l2_subdev_core_ops adp1653_core_ops = {
+       .s_power = adp1653_set_power,
+};
+
+static const struct v4l2_subdev_ops adp1653_ops = {
+       .core = &adp1653_core_ops,
+};
+
+static const struct v4l2_subdev_internal_ops adp1653_internal_ops = {
+       .open = adp1653_open,
+       .close = adp1653_close,
+};
+
+/* --------------------------------------------------------------------------
+ * I2C driver
+ */
+#ifdef CONFIG_PM
+
+static int adp1653_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+       struct adp1653_flash *flash = to_adp1653_flash(subdev);
+
+       if (!flash->power_count)
+               return 0;
+
+       return __adp1653_set_power(flash, 0);
+}
+
+static int adp1653_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+       struct adp1653_flash *flash = to_adp1653_flash(subdev);
+
+       if (!flash->power_count)
+               return 0;
+
+       return __adp1653_set_power(flash, 1);
+}
+
+#else
+
+#define adp1653_suspend        NULL
+#define adp1653_resume NULL
+
+#endif /* CONFIG_PM */
+
+static int adp1653_probe(struct i2c_client *client,
+                        const struct i2c_device_id *devid)
+{
+       struct adp1653_flash *flash;
+       int ret;
+
+       flash = kzalloc(sizeof(*flash), GFP_KERNEL);
+       if (flash == NULL)
+               return -ENOMEM;
+
+       flash->platform_data = client->dev.platform_data;
+
+       mutex_init(&flash->power_lock);
+
+       v4l2_i2c_subdev_init(&flash->subdev, client, &adp1653_ops);
+       flash->subdev.internal_ops = &adp1653_internal_ops;
+       flash->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+       adp1653_init_controls(flash);
+
+       ret = media_entity_init(&flash->subdev.entity, 0, NULL, 0);
+       if (ret < 0)
+               kfree(flash);
+
+       return ret;
+}
+
+static int __exit adp1653_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+       struct adp1653_flash *flash = to_adp1653_flash(subdev);
+
+       v4l2_device_unregister_subdev(&flash->subdev);
+       v4l2_ctrl_handler_free(&flash->ctrls);
+       media_entity_cleanup(&flash->subdev.entity);
+       kfree(flash);
+       return 0;
+}
+
+static const struct i2c_device_id adp1653_id_table[] = {
+       { ADP1653_NAME, 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, adp1653_id_table);
+
+static struct dev_pm_ops adp1653_pm_ops = {
+       .suspend        = adp1653_suspend,
+       .resume         = adp1653_resume,
+};
+
+static struct i2c_driver adp1653_i2c_driver = {
+       .driver         = {
+               .name   = ADP1653_NAME,
+               .pm     = &adp1653_pm_ops,
+       },
+       .probe          = adp1653_probe,
+       .remove         = __exit_p(adp1653_remove),
+       .id_table       = adp1653_id_table,
+};
+
+static int __init adp1653_init(void)
+{
+       int rval;
+
+       rval = i2c_add_driver(&adp1653_i2c_driver);
+       if (rval)
+               printk(KERN_ALERT "%s: failed at i2c_add_driver\n", __func__);
+
+       return rval;
+}
+
+static void __exit adp1653_exit(void)
+{
+       i2c_del_driver(&adp1653_i2c_driver);
+}
+
+module_init(adp1653_init);
+module_exit(adp1653_exit);
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
+MODULE_DESCRIPTION("Analog Devices ADP1653 LED flash driver");
+MODULE_LICENSE("GPL");
index f989f28..b6ed44a 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
-#include <linux/version.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-device.h>
@@ -54,7 +53,7 @@
  */
 #define USE_INT                0       /* Don't modify */
 
-#define VERSION        "0.04"
+#define VERSION        "0.0.5"
 
 #define ar_inl(addr)           inl((unsigned long)(addr))
 #define ar_outl(val, addr)     outl((unsigned long)(val), (unsigned long)(addr))
@@ -404,7 +403,6 @@ static int ar_querycap(struct file *file, void  *priv,
        strlcpy(vcap->driver, ar->vdev.name, sizeof(vcap->driver));
        strlcpy(vcap->card, "Colour AR VGA", sizeof(vcap->card));
        strlcpy(vcap->bus_info, "Platform", sizeof(vcap->bus_info));
-       vcap->version = KERNEL_VERSION(0, 0, 4);
        vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
        return 0;
 }
@@ -879,3 +877,4 @@ module_exit(ar_cleanup_module);
 MODULE_AUTHOR("Takeo Takahashi <takahashi.takeo@renesas.com>");
 MODULE_DESCRIPTION("Colour AR M64278(VGA) for Video4Linux");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(VERSION);
diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/video/atmel-isi.c
new file mode 100644 (file)
index 0000000..7b89f00
--- /dev/null
@@ -0,0 +1,1048 @@
+/*
+ * Copyright (c) 2011 Atmel Corporation
+ * Josh Wu, <josh.wu@atmel.com>
+ *
+ * Based on previous work by Lars Haring, <lars.haring@atmel.com>
+ * and Sedji Gaouaou
+ * Based on the bttv driver for Bt848 with respective copyright holders
+ *
+ * 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/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <media/atmel-isi.h>
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+#include <media/videobuf2-dma-contig.h>
+
+#define MAX_BUFFER_NUM                 32
+#define MAX_SUPPORT_WIDTH              2048
+#define MAX_SUPPORT_HEIGHT             2048
+#define VID_LIMIT_BYTES                        (16 * 1024 * 1024)
+#define MIN_FRAME_RATE                 15
+#define FRAME_INTERVAL_MILLI_SEC       (1000 / MIN_FRAME_RATE)
+
+/* ISI states */
+enum {
+       ISI_STATE_IDLE = 0,
+       ISI_STATE_READY,
+       ISI_STATE_WAIT_SOF,
+};
+
+/* Frame buffer descriptor */
+struct fbd {
+       /* Physical address of the frame buffer */
+       u32 fb_address;
+       /* DMA Control Register(only in HISI2) */
+       u32 dma_ctrl;
+       /* Physical address of the next fbd */
+       u32 next_fbd_address;
+};
+
+static void set_dma_ctrl(struct fbd *fb_desc, u32 ctrl)
+{
+       fb_desc->dma_ctrl = ctrl;
+}
+
+struct isi_dma_desc {
+       struct list_head list;
+       struct fbd *p_fbd;
+       u32 fbd_phys;
+};
+
+/* Frame buffer data */
+struct frame_buffer {
+       struct vb2_buffer vb;
+       struct isi_dma_desc *p_dma_desc;
+       struct list_head list;
+};
+
+struct atmel_isi {
+       /* Protects the access of variables shared with the ISR */
+       spinlock_t                      lock;
+       void __iomem                    *regs;
+
+       int                             sequence;
+       /* State of the ISI module in capturing mode */
+       int                             state;
+
+       /* Wait queue for waiting for SOF */
+       wait_queue_head_t               vsync_wq;
+
+       struct vb2_alloc_ctx            *alloc_ctx;
+
+       /* Allocate descriptors for dma buffer use */
+       struct fbd                      *p_fb_descriptors;
+       u32                             fb_descriptors_phys;
+       struct                          list_head dma_desc_head;
+       struct isi_dma_desc             dma_desc[MAX_BUFFER_NUM];
+
+       struct completion               complete;
+       struct clk                      *pclk;
+       unsigned int                    irq;
+
+       struct isi_platform_data        *pdata;
+
+       struct list_head                video_buffer_list;
+       struct frame_buffer             *active;
+
+       struct soc_camera_device        *icd;
+       struct soc_camera_host          soc_host;
+};
+
+static void isi_writel(struct atmel_isi *isi, u32 reg, u32 val)
+{
+       writel(val, isi->regs + reg);
+}
+static u32 isi_readl(struct atmel_isi *isi, u32 reg)
+{
+       return readl(isi->regs + reg);
+}
+
+static int configure_geometry(struct atmel_isi *isi, u32 width,
+                       u32 height, enum v4l2_mbus_pixelcode code)
+{
+       u32 cfg2, cr;
+
+       switch (code) {
+       /* YUV, including grey */
+       case V4L2_MBUS_FMT_Y8_1X8:
+               cr = ISI_CFG2_GRAYSCALE;
+               break;
+       case V4L2_MBUS_FMT_UYVY8_2X8:
+               cr = ISI_CFG2_YCC_SWAP_MODE_3;
+               break;
+       case V4L2_MBUS_FMT_VYUY8_2X8:
+               cr = ISI_CFG2_YCC_SWAP_MODE_2;
+               break;
+       case V4L2_MBUS_FMT_YUYV8_2X8:
+               cr = ISI_CFG2_YCC_SWAP_MODE_1;
+               break;
+       case V4L2_MBUS_FMT_YVYU8_2X8:
+               cr = ISI_CFG2_YCC_SWAP_DEFAULT;
+               break;
+       /* RGB, TODO */
+       default:
+               return -EINVAL;
+       }
+
+       isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
+
+       cfg2 = isi_readl(isi, ISI_CFG2);
+       cfg2 |= cr;
+       /* Set width */
+       cfg2 &= ~(ISI_CFG2_IM_HSIZE_MASK);
+       cfg2 |= ((width - 1) << ISI_CFG2_IM_HSIZE_OFFSET) &
+                       ISI_CFG2_IM_HSIZE_MASK;
+       /* Set height */
+       cfg2 &= ~(ISI_CFG2_IM_VSIZE_MASK);
+       cfg2 |= ((height - 1) << ISI_CFG2_IM_VSIZE_OFFSET)
+                       & ISI_CFG2_IM_VSIZE_MASK;
+       isi_writel(isi, ISI_CFG2, cfg2);
+
+       return 0;
+}
+
+static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi)
+{
+       if (isi->active) {
+               struct vb2_buffer *vb = &isi->active->vb;
+               struct frame_buffer *buf = isi->active;
+
+               list_del_init(&buf->list);
+               do_gettimeofday(&vb->v4l2_buf.timestamp);
+               vb->v4l2_buf.sequence = isi->sequence++;
+               vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+       }
+
+       if (list_empty(&isi->video_buffer_list)) {
+               isi->active = NULL;
+       } else {
+               /* start next dma frame. */
+               isi->active = list_entry(isi->video_buffer_list.next,
+                                       struct frame_buffer, list);
+               isi_writel(isi, ISI_DMA_C_DSCR,
+                       isi->active->p_dma_desc->fbd_phys);
+               isi_writel(isi, ISI_DMA_C_CTRL,
+                       ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
+               isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH);
+       }
+       return IRQ_HANDLED;
+}
+
+/* ISI interrupt service routine */
+static irqreturn_t isi_interrupt(int irq, void *dev_id)
+{
+       struct atmel_isi *isi = dev_id;
+       u32 status, mask, pending;
+       irqreturn_t ret = IRQ_NONE;
+
+       spin_lock(&isi->lock);
+
+       status = isi_readl(isi, ISI_STATUS);
+       mask = isi_readl(isi, ISI_INTMASK);
+       pending = status & mask;
+
+       if (pending & ISI_CTRL_SRST) {
+               complete(&isi->complete);
+               isi_writel(isi, ISI_INTDIS, ISI_CTRL_SRST);
+               ret = IRQ_HANDLED;
+       } else if (pending & ISI_CTRL_DIS) {
+               complete(&isi->complete);
+               isi_writel(isi, ISI_INTDIS, ISI_CTRL_DIS);
+               ret = IRQ_HANDLED;
+       } else {
+               if ((pending & ISI_SR_VSYNC) &&
+                               (isi->state == ISI_STATE_IDLE)) {
+                       isi->state = ISI_STATE_READY;
+                       wake_up_interruptible(&isi->vsync_wq);
+                       ret = IRQ_HANDLED;
+               }
+               if (likely(pending & ISI_SR_CXFR_DONE))
+                       ret = atmel_isi_handle_streaming(isi);
+       }
+
+       spin_unlock(&isi->lock);
+       return ret;
+}
+
+#define        WAIT_ISI_RESET          1
+#define        WAIT_ISI_DISABLE        0
+static int atmel_isi_wait_status(struct atmel_isi *isi, int wait_reset)
+{
+       unsigned long timeout;
+       /*
+        * The reset or disable will only succeed if we have a
+        * pixel clock from the camera.
+        */
+       init_completion(&isi->complete);
+
+       if (wait_reset) {
+               isi_writel(isi, ISI_INTEN, ISI_CTRL_SRST);
+               isi_writel(isi, ISI_CTRL, ISI_CTRL_SRST);
+       } else {
+               isi_writel(isi, ISI_INTEN, ISI_CTRL_DIS);
+               isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
+       }
+
+       timeout = wait_for_completion_timeout(&isi->complete,
+                       msecs_to_jiffies(100));
+       if (timeout == 0)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+/* ------------------------------------------------------------------
+       Videobuf operations
+   ------------------------------------------------------------------*/
+static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
+                               unsigned int *nplanes, unsigned long sizes[],
+                               void *alloc_ctxs[])
+{
+       struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct atmel_isi *isi = ici->priv;
+       unsigned long size;
+       int ret, bytes_per_line;
+
+       /* Reset ISI */
+       ret = atmel_isi_wait_status(isi, WAIT_ISI_RESET);
+       if (ret < 0) {
+               dev_err(icd->parent, "Reset ISI timed out\n");
+               return ret;
+       }
+       /* Disable all interrupts */
+       isi_writel(isi, ISI_INTDIS, ~0UL);
+
+       bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+                                               icd->current_fmt->host_fmt);
+
+       if (bytes_per_line < 0)
+               return bytes_per_line;
+
+       size = bytes_per_line * icd->user_height;
+
+       if (!*nbuffers || *nbuffers > MAX_BUFFER_NUM)
+               *nbuffers = MAX_BUFFER_NUM;
+
+       if (size * *nbuffers > VID_LIMIT_BYTES)
+               *nbuffers = VID_LIMIT_BYTES / size;
+
+       *nplanes = 1;
+       sizes[0] = size;
+       alloc_ctxs[0] = isi->alloc_ctx;
+
+       isi->sequence = 0;
+       isi->active = NULL;
+
+       dev_dbg(icd->parent, "%s, count=%d, size=%ld\n", __func__,
+               *nbuffers, size);
+
+       return 0;
+}
+
+static int buffer_init(struct vb2_buffer *vb)
+{
+       struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb);
+
+       buf->p_dma_desc = NULL;
+       INIT_LIST_HEAD(&buf->list);
+
+       return 0;
+}
+
+static int buffer_prepare(struct vb2_buffer *vb)
+{
+       struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
+       struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct atmel_isi *isi = ici->priv;
+       unsigned long size;
+       struct isi_dma_desc *desc;
+       int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+                                               icd->current_fmt->host_fmt);
+
+       if (bytes_per_line < 0)
+               return bytes_per_line;
+
+       size = bytes_per_line * icd->user_height;
+
+       if (vb2_plane_size(vb, 0) < size) {
+               dev_err(icd->parent, "%s data will not fit into plane (%lu < %lu)\n",
+                               __func__, vb2_plane_size(vb, 0), size);
+               return -EINVAL;
+       }
+
+       vb2_set_plane_payload(&buf->vb, 0, size);
+
+       if (!buf->p_dma_desc) {
+               if (list_empty(&isi->dma_desc_head)) {
+                       dev_err(icd->parent, "Not enough dma descriptors.\n");
+                       return -EINVAL;
+               } else {
+                       /* Get an available descriptor */
+                       desc = list_entry(isi->dma_desc_head.next,
+                                               struct isi_dma_desc, list);
+                       /* Delete the descriptor since now it is used */
+                       list_del_init(&desc->list);
+
+                       /* Initialize the dma descriptor */
+                       desc->p_fbd->fb_address =
+                                       vb2_dma_contig_plane_paddr(vb, 0);
+                       desc->p_fbd->next_fbd_address = 0;
+                       set_dma_ctrl(desc->p_fbd, ISI_DMA_CTRL_WB);
+
+                       buf->p_dma_desc = desc;
+               }
+       }
+       return 0;
+}
+
+static void buffer_cleanup(struct vb2_buffer *vb)
+{
+       struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct atmel_isi *isi = ici->priv;
+       struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb);
+
+       /* This descriptor is available now and we add to head list */
+       if (buf->p_dma_desc)
+               list_add(&buf->p_dma_desc->list, &isi->dma_desc_head);
+}
+
+static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer)
+{
+       u32 ctrl, cfg1;
+
+       cfg1 = isi_readl(isi, ISI_CFG1);
+       /* Enable irq: cxfr for the codec path, pxfr for the preview path */
+       isi_writel(isi, ISI_INTEN,
+                       ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE);
+
+       /* Check if already in a frame */
+       if (isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) {
+               dev_err(isi->icd->parent, "Already in frame handling.\n");
+               return;
+       }
+
+       isi_writel(isi, ISI_DMA_C_DSCR, buffer->p_dma_desc->fbd_phys);
+       isi_writel(isi, ISI_DMA_C_CTRL, ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
+       isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH);
+
+       /* Enable linked list */
+       cfg1 |= isi->pdata->frate | ISI_CFG1_DISCR;
+
+       /* Enable codec path and ISI */
+       ctrl = ISI_CTRL_CDC | ISI_CTRL_EN;
+       isi_writel(isi, ISI_CTRL, ctrl);
+       isi_writel(isi, ISI_CFG1, cfg1);
+}
+
+static void buffer_queue(struct vb2_buffer *vb)
+{
+       struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct atmel_isi *isi = ici->priv;
+       struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb);
+       unsigned long flags = 0;
+
+       spin_lock_irqsave(&isi->lock, flags);
+       list_add_tail(&buf->list, &isi->video_buffer_list);
+
+       if (isi->active == NULL) {
+               isi->active = buf;
+               start_dma(isi, buf);
+       }
+       spin_unlock_irqrestore(&isi->lock, flags);
+}
+
+static int start_streaming(struct vb2_queue *vq)
+{
+       struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct atmel_isi *isi = ici->priv;
+
+       u32 sr = 0;
+       int ret;
+
+       spin_lock_irq(&isi->lock);
+       isi->state = ISI_STATE_IDLE;
+       /* Clear any pending SOF interrupt */
+       sr = isi_readl(isi, ISI_STATUS);
+       /* Enable VSYNC interrupt for SOF */
+       isi_writel(isi, ISI_INTEN, ISI_SR_VSYNC);
+       isi_writel(isi, ISI_CTRL, ISI_CTRL_EN);
+       spin_unlock_irq(&isi->lock);
+
+       dev_dbg(icd->parent, "Waiting for SOF\n");
+       ret = wait_event_interruptible(isi->vsync_wq,
+                                      isi->state != ISI_STATE_IDLE);
+       if (ret)
+               return ret;
+
+       if (isi->state != ISI_STATE_READY)
+               return -EIO;
+
+       spin_lock_irq(&isi->lock);
+       isi->state = ISI_STATE_WAIT_SOF;
+       isi_writel(isi, ISI_INTDIS, ISI_SR_VSYNC);
+       spin_unlock_irq(&isi->lock);
+
+       return 0;
+}
+
+/* abort streaming and wait for last buffer */
+static int stop_streaming(struct vb2_queue *vq)
+{
+       struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct atmel_isi *isi = ici->priv;
+       struct frame_buffer *buf, *node;
+       int ret = 0;
+       unsigned long timeout;
+
+       spin_lock_irq(&isi->lock);
+       isi->active = NULL;
+       /* Release all active buffers */
+       list_for_each_entry_safe(buf, node, &isi->video_buffer_list, list) {
+               list_del_init(&buf->list);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+       }
+       spin_unlock_irq(&isi->lock);
+
+       timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ;
+       /* Wait until the end of the current frame. */
+       while ((isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) &&
+                       time_before(jiffies, timeout))
+               msleep(1);
+
+       if (time_after(jiffies, timeout)) {
+               dev_err(icd->parent,
+                       "Timeout waiting for finishing codec request\n");
+               return -ETIMEDOUT;
+       }
+
+       /* Disable interrupts */
+       isi_writel(isi, ISI_INTDIS,
+                       ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE);
+
+       /* Disable ISI and wait for it is done */
+       ret = atmel_isi_wait_status(isi, WAIT_ISI_DISABLE);
+       if (ret < 0)
+               dev_err(icd->parent, "Disable ISI timed out\n");
+
+       return ret;
+}
+
+static struct vb2_ops isi_video_qops = {
+       .queue_setup            = queue_setup,
+       .buf_init               = buffer_init,
+       .buf_prepare            = buffer_prepare,
+       .buf_cleanup            = buffer_cleanup,
+       .buf_queue              = buffer_queue,
+       .start_streaming        = start_streaming,
+       .stop_streaming         = stop_streaming,
+       .wait_prepare           = soc_camera_unlock,
+       .wait_finish            = soc_camera_lock,
+};
+
+/* ------------------------------------------------------------------
+       SOC camera operations for the device
+   ------------------------------------------------------------------*/
+static int isi_camera_init_videobuf(struct vb2_queue *q,
+                                    struct soc_camera_device *icd)
+{
+       q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       q->io_modes = VB2_MMAP;
+       q->drv_priv = icd;
+       q->buf_struct_size = sizeof(struct frame_buffer);
+       q->ops = &isi_video_qops;
+       q->mem_ops = &vb2_dma_contig_memops;
+
+       return vb2_queue_init(q);
+}
+
+static int isi_camera_set_fmt(struct soc_camera_device *icd,
+                             struct v4l2_format *f)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct atmel_isi *isi = ici->priv;
+       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+       const struct soc_camera_format_xlate *xlate;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       struct v4l2_mbus_framefmt mf;
+       int ret;
+
+       xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
+       if (!xlate) {
+               dev_warn(icd->parent, "Format %x not found\n",
+                        pix->pixelformat);
+               return -EINVAL;
+       }
+
+       dev_dbg(icd->parent, "Plan to set format %dx%d\n",
+                       pix->width, pix->height);
+
+       mf.width        = pix->width;
+       mf.height       = pix->height;
+       mf.field        = pix->field;
+       mf.colorspace   = pix->colorspace;
+       mf.code         = xlate->code;
+
+       ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
+       if (ret < 0)
+               return ret;
+
+       if (mf.code != xlate->code)
+               return -EINVAL;
+
+       ret = configure_geometry(isi, pix->width, pix->height, xlate->code);
+       if (ret < 0)
+               return ret;
+
+       pix->width              = mf.width;
+       pix->height             = mf.height;
+       pix->field              = mf.field;
+       pix->colorspace         = mf.colorspace;
+       icd->current_fmt        = xlate;
+
+       dev_dbg(icd->parent, "Finally set format %dx%d\n",
+               pix->width, pix->height);
+
+       return ret;
+}
+
+static int isi_camera_try_fmt(struct soc_camera_device *icd,
+                             struct v4l2_format *f)
+{
+       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+       const struct soc_camera_format_xlate *xlate;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       struct v4l2_mbus_framefmt mf;
+       u32 pixfmt = pix->pixelformat;
+       int ret;
+
+       xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+       if (pixfmt && !xlate) {
+               dev_warn(icd->parent, "Format %x not found\n", pixfmt);
+               return -EINVAL;
+       }
+
+       /* limit to Atmel ISI hardware capabilities */
+       if (pix->height > MAX_SUPPORT_HEIGHT)
+               pix->height = MAX_SUPPORT_HEIGHT;
+       if (pix->width > MAX_SUPPORT_WIDTH)
+               pix->width = MAX_SUPPORT_WIDTH;
+
+       /* limit to sensor capabilities */
+       mf.width        = pix->width;
+       mf.height       = pix->height;
+       mf.field        = pix->field;
+       mf.colorspace   = pix->colorspace;
+       mf.code         = xlate->code;
+
+       ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
+       if (ret < 0)
+               return ret;
+
+       pix->width      = mf.width;
+       pix->height     = mf.height;
+       pix->colorspace = mf.colorspace;
+
+       switch (mf.field) {
+       case V4L2_FIELD_ANY:
+               pix->field = V4L2_FIELD_NONE;
+               break;
+       case V4L2_FIELD_NONE:
+               break;
+       default:
+               dev_err(icd->parent, "Field type %d unsupported.\n",
+                       mf.field);
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static const struct soc_mbus_pixelfmt isi_camera_formats[] = {
+       {
+               .fourcc                 = V4L2_PIX_FMT_YUYV,
+               .name                   = "Packed YUV422 16 bit",
+               .bits_per_sample        = 8,
+               .packing                = SOC_MBUS_PACKING_2X8_PADHI,
+               .order                  = SOC_MBUS_ORDER_LE,
+       },
+};
+
+/* This will be corrected as we get more formats */
+static bool isi_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt)
+{
+       return  fmt->packing == SOC_MBUS_PACKING_NONE ||
+               (fmt->bits_per_sample == 8 &&
+                fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) ||
+               (fmt->bits_per_sample > 8 &&
+                fmt->packing == SOC_MBUS_PACKING_EXTEND16);
+}
+
+static unsigned long make_bus_param(struct atmel_isi *isi)
+{
+       unsigned long flags;
+       /*
+        * Platform specified synchronization and pixel clock polarities are
+        * only a recommendation and are only used during probing. Atmel ISI
+        * camera interface only works in master mode, i.e., uses HSYNC and
+        * VSYNC signals from the sensor
+        */
+       flags = SOCAM_MASTER |
+               SOCAM_HSYNC_ACTIVE_HIGH |
+               SOCAM_HSYNC_ACTIVE_LOW |
+               SOCAM_VSYNC_ACTIVE_HIGH |
+               SOCAM_VSYNC_ACTIVE_LOW |
+               SOCAM_PCLK_SAMPLE_RISING |
+               SOCAM_PCLK_SAMPLE_FALLING |
+               SOCAM_DATA_ACTIVE_HIGH;
+
+       if (isi->pdata->data_width_flags & ISI_DATAWIDTH_10)
+               flags |= SOCAM_DATAWIDTH_10;
+
+       if (isi->pdata->data_width_flags & ISI_DATAWIDTH_8)
+               flags |= SOCAM_DATAWIDTH_8;
+
+       if (flags & SOCAM_DATAWIDTH_MASK)
+               return flags;
+
+       return 0;
+}
+
+static int isi_camera_try_bus_param(struct soc_camera_device *icd,
+                                   unsigned char buswidth)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct atmel_isi *isi = ici->priv;
+       unsigned long camera_flags;
+       int ret;
+
+       camera_flags = icd->ops->query_bus_param(icd);
+       ret = soc_camera_bus_param_compatible(camera_flags,
+                                       make_bus_param(isi));
+       if (!ret)
+               return -EINVAL;
+       return 0;
+}
+
+
+static int isi_camera_get_formats(struct soc_camera_device *icd,
+                                 unsigned int idx,
+                                 struct soc_camera_format_xlate *xlate)
+{
+       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+       int formats = 0, ret;
+       /* sensor format */
+       enum v4l2_mbus_pixelcode code;
+       /* soc camera host format */
+       const struct soc_mbus_pixelfmt *fmt;
+
+       ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code);
+       if (ret < 0)
+               /* No more formats */
+               return 0;
+
+       fmt = soc_mbus_get_fmtdesc(code);
+       if (!fmt) {
+               dev_err(icd->parent,
+                       "Invalid format code #%u: %d\n", idx, code);
+               return 0;
+       }
+
+       /* This also checks support for the requested bits-per-sample */
+       ret = isi_camera_try_bus_param(icd, fmt->bits_per_sample);
+       if (ret < 0) {
+               dev_err(icd->parent,
+                       "Fail to try the bus parameters.\n");
+               return 0;
+       }
+
+       switch (code) {
+       case V4L2_MBUS_FMT_UYVY8_2X8:
+       case V4L2_MBUS_FMT_VYUY8_2X8:
+       case V4L2_MBUS_FMT_YUYV8_2X8:
+       case V4L2_MBUS_FMT_YVYU8_2X8:
+               formats++;
+               if (xlate) {
+                       xlate->host_fmt = &isi_camera_formats[0];
+                       xlate->code     = code;
+                       xlate++;
+                       dev_dbg(icd->parent, "Providing format %s using code %d\n",
+                               isi_camera_formats[0].name, code);
+               }
+               break;
+       default:
+               if (!isi_camera_packing_supported(fmt))
+                       return 0;
+               if (xlate)
+                       dev_dbg(icd->parent,
+                               "Providing format %s in pass-through mode\n",
+                               fmt->name);
+       }
+
+       /* Generic pass-through */
+       formats++;
+       if (xlate) {
+               xlate->host_fmt = fmt;
+               xlate->code     = code;
+               xlate++;
+       }
+
+       return formats;
+}
+
+/* Called with .video_lock held */
+static int isi_camera_add_device(struct soc_camera_device *icd)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct atmel_isi *isi = ici->priv;
+       int ret;
+
+       if (isi->icd)
+               return -EBUSY;
+
+       ret = clk_enable(isi->pclk);
+       if (ret)
+               return ret;
+
+       isi->icd = icd;
+       dev_dbg(icd->parent, "Atmel ISI Camera driver attached to camera %d\n",
+                icd->devnum);
+       return 0;
+}
+/* Called with .video_lock held */
+static void isi_camera_remove_device(struct soc_camera_device *icd)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct atmel_isi *isi = ici->priv;
+
+       BUG_ON(icd != isi->icd);
+
+       clk_disable(isi->pclk);
+       isi->icd = NULL;
+
+       dev_dbg(icd->parent, "Atmel ISI Camera driver detached from camera %d\n",
+                icd->devnum);
+}
+
+static unsigned int isi_camera_poll(struct file *file, poll_table *pt)
+{
+       struct soc_camera_device *icd = file->private_data;
+
+       return vb2_poll(&icd->vb2_vidq, file, pt);
+}
+
+static int isi_camera_querycap(struct soc_camera_host *ici,
+                              struct v4l2_capability *cap)
+{
+       strcpy(cap->driver, "atmel-isi");
+       strcpy(cap->card, "Atmel Image Sensor Interface");
+       cap->capabilities = (V4L2_CAP_VIDEO_CAPTURE |
+                               V4L2_CAP_STREAMING);
+       return 0;
+}
+
+static int isi_camera_set_bus_param(struct soc_camera_device *icd, u32 pixfmt)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct atmel_isi *isi = ici->priv;
+       unsigned long bus_flags, camera_flags, common_flags;
+       int ret;
+       u32 cfg1 = 0;
+
+       camera_flags = icd->ops->query_bus_param(icd);
+
+       bus_flags = make_bus_param(isi);
+       common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags);
+       dev_dbg(icd->parent, "Flags cam: 0x%lx host: 0x%lx common: 0x%lx\n",
+               camera_flags, bus_flags, common_flags);
+       if (!common_flags)
+               return -EINVAL;
+
+       /* Make choises, based on platform preferences */
+       if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) &&
+           (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) {
+               if (isi->pdata->hsync_act_low)
+                       common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH;
+               else
+                       common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW;
+       }
+
+       if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) &&
+           (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) {
+               if (isi->pdata->vsync_act_low)
+                       common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH;
+               else
+                       common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW;
+       }
+
+       if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&
+           (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {
+               if (isi->pdata->pclk_act_falling)
+                       common_flags &= ~SOCAM_PCLK_SAMPLE_RISING;
+               else
+                       common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING;
+       }
+
+       ret = icd->ops->set_bus_param(icd, common_flags);
+       if (ret < 0) {
+               dev_dbg(icd->parent, "Camera set_bus_param(%lx) returned %d\n",
+                       common_flags, ret);
+               return ret;
+       }
+
+       /* set bus param for ISI */
+       if (common_flags & SOCAM_HSYNC_ACTIVE_LOW)
+               cfg1 |= ISI_CFG1_HSYNC_POL_ACTIVE_LOW;
+       if (common_flags & SOCAM_VSYNC_ACTIVE_LOW)
+               cfg1 |= ISI_CFG1_VSYNC_POL_ACTIVE_LOW;
+       if (common_flags & SOCAM_PCLK_SAMPLE_FALLING)
+               cfg1 |= ISI_CFG1_PIXCLK_POL_ACTIVE_FALLING;
+
+       if (isi->pdata->has_emb_sync)
+               cfg1 |= ISI_CFG1_EMB_SYNC;
+       if (isi->pdata->isi_full_mode)
+               cfg1 |= ISI_CFG1_FULL_MODE;
+
+       isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
+       isi_writel(isi, ISI_CFG1, cfg1);
+
+       return 0;
+}
+
+static struct soc_camera_host_ops isi_soc_camera_host_ops = {
+       .owner          = THIS_MODULE,
+       .add            = isi_camera_add_device,
+       .remove         = isi_camera_remove_device,
+       .set_fmt        = isi_camera_set_fmt,
+       .try_fmt        = isi_camera_try_fmt,
+       .get_formats    = isi_camera_get_formats,
+       .init_videobuf2 = isi_camera_init_videobuf,
+       .poll           = isi_camera_poll,
+       .querycap       = isi_camera_querycap,
+       .set_bus_param  = isi_camera_set_bus_param,
+};
+
+/* -----------------------------------------------------------------------*/
+static int __devexit atmel_isi_remove(struct platform_device *pdev)
+{
+       struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
+       struct atmel_isi *isi = container_of(soc_host,
+                                       struct atmel_isi, soc_host);
+
+       free_irq(isi->irq, isi);
+       soc_camera_host_unregister(soc_host);
+       vb2_dma_contig_cleanup_ctx(isi->alloc_ctx);
+       dma_free_coherent(&pdev->dev,
+                       sizeof(struct fbd) * MAX_BUFFER_NUM,
+                       isi->p_fb_descriptors,
+                       isi->fb_descriptors_phys);
+
+       iounmap(isi->regs);
+       clk_put(isi->pclk);
+       kfree(isi);
+
+       return 0;
+}
+
+static int __devinit atmel_isi_probe(struct platform_device *pdev)
+{
+       unsigned int irq;
+       struct atmel_isi *isi;
+       struct clk *pclk;
+       struct resource *regs;
+       int ret, i;
+       struct device *dev = &pdev->dev;
+       struct soc_camera_host *soc_host;
+       struct isi_platform_data *pdata;
+
+       pdata = dev->platform_data;
+       if (!pdata || !pdata->data_width_flags) {
+               dev_err(&pdev->dev,
+                       "No config available for Atmel ISI\n");
+               return -EINVAL;
+       }
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!regs)
+               return -ENXIO;
+
+       pclk = clk_get(&pdev->dev, "isi_clk");
+       if (IS_ERR(pclk))
+               return PTR_ERR(pclk);
+
+       isi = kzalloc(sizeof(struct atmel_isi), GFP_KERNEL);
+       if (!isi) {
+               ret = -ENOMEM;
+               dev_err(&pdev->dev, "Can't allocate interface!\n");
+               goto err_alloc_isi;
+       }
+
+       isi->pclk = pclk;
+       isi->pdata = pdata;
+       isi->active = NULL;
+       spin_lock_init(&isi->lock);
+       init_waitqueue_head(&isi->vsync_wq);
+       INIT_LIST_HEAD(&isi->video_buffer_list);
+       INIT_LIST_HEAD(&isi->dma_desc_head);
+
+       isi->p_fb_descriptors = dma_alloc_coherent(&pdev->dev,
+                               sizeof(struct fbd) * MAX_BUFFER_NUM,
+                               &isi->fb_descriptors_phys,
+                               GFP_KERNEL);
+       if (!isi->p_fb_descriptors) {
+               ret = -ENOMEM;
+               dev_err(&pdev->dev, "Can't allocate descriptors!\n");
+               goto err_alloc_descriptors;
+       }
+
+       for (i = 0; i < MAX_BUFFER_NUM; i++) {
+               isi->dma_desc[i].p_fbd = isi->p_fb_descriptors + i;
+               isi->dma_desc[i].fbd_phys = isi->fb_descriptors_phys +
+                                       i * sizeof(struct fbd);
+               list_add(&isi->dma_desc[i].list, &isi->dma_desc_head);
+       }
+
+       isi->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+       if (IS_ERR(isi->alloc_ctx)) {
+               ret = PTR_ERR(isi->alloc_ctx);
+               goto err_alloc_ctx;
+       }
+
+       isi->regs = ioremap(regs->start, resource_size(regs));
+       if (!isi->regs) {
+               ret = -ENOMEM;
+               goto err_ioremap;
+       }
+
+       isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               ret = irq;
+               goto err_req_irq;
+       }
+
+       ret = request_irq(irq, isi_interrupt, 0, "isi", isi);
+       if (ret) {
+               dev_err(&pdev->dev, "Unable to request irq %d\n", irq);
+               goto err_req_irq;
+       }
+       isi->irq = irq;
+
+       soc_host                = &isi->soc_host;
+       soc_host->drv_name      = "isi-camera";
+       soc_host->ops           = &isi_soc_camera_host_ops;
+       soc_host->priv          = isi;
+       soc_host->v4l2_dev.dev  = &pdev->dev;
+       soc_host->nr            = pdev->id;
+
+       ret = soc_camera_host_register(soc_host);
+       if (ret) {
+               dev_err(&pdev->dev, "Unable to register soc camera host\n");
+               goto err_register_soc_camera_host;
+       }
+       return 0;
+
+err_register_soc_camera_host:
+       free_irq(isi->irq, isi);
+err_req_irq:
+       iounmap(isi->regs);
+err_ioremap:
+       vb2_dma_contig_cleanup_ctx(isi->alloc_ctx);
+err_alloc_ctx:
+       dma_free_coherent(&pdev->dev,
+                       sizeof(struct fbd) * MAX_BUFFER_NUM,
+                       isi->p_fb_descriptors,
+                       isi->fb_descriptors_phys);
+err_alloc_descriptors:
+       kfree(isi);
+err_alloc_isi:
+       clk_put(isi->pclk);
+
+       return ret;
+}
+
+static struct platform_driver atmel_isi_driver = {
+       .probe          = atmel_isi_probe,
+       .remove         = __devexit_p(atmel_isi_remove),
+       .driver         = {
+               .name = "atmel_isi",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init atmel_isi_init_module(void)
+{
+       return  platform_driver_probe(&atmel_isi_driver, &atmel_isi_probe);
+}
+
+static void __exit atmel_isi_exit(void)
+{
+       platform_driver_unregister(&atmel_isi_driver);
+}
+module_init(atmel_isi_init_module);
+module_exit(atmel_isi_exit);
+
+MODULE_AUTHOR("Josh Wu <josh.wu@atmel.com>");
+MODULE_DESCRIPTION("The V4L2 driver for Atmel Linux");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("video");
index ca342e4..1e4ce50 100644 (file)
@@ -292,3 +292,4 @@ module_exit(au0828_exit);
 MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products");
 MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.2");
index c03eb29..0b3e481 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/suspend.h>
-#include <linux/version.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-chip-ident.h>
@@ -43,8 +42,6 @@
 
 static DEFINE_MUTEX(au0828_sysfs_lock);
 
-#define AU0828_VERSION_CODE KERNEL_VERSION(0, 0, 1)
-
 /* ------------------------------------------------------------------
        Videobuf operations
    ------------------------------------------------------------------*/
@@ -1254,8 +1251,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        strlcpy(cap->card, dev->board.name, sizeof(cap->card));
        strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
 
-       cap->version = AU0828_VERSION_CODE;
-
        /*set the device capabilities */
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
                V4L2_CAP_VBI_CAPTURE |
index 3c9e6c7..5b15f63 100644 (file)
@@ -2892,13 +2892,10 @@ void __devinit bttv_idcard(struct bttv *btv)
 {
        unsigned int gpiobits;
        int i,type;
-       unsigned short tmp;
 
        /* read PCI subsystem ID */
-       pci_read_config_word(btv->c.pci, PCI_SUBSYSTEM_ID, &tmp);
-       btv->cardid = tmp << 16;
-       pci_read_config_word(btv->c.pci, PCI_SUBSYSTEM_VENDOR_ID, &tmp);
-       btv->cardid |= tmp;
+       btv->cardid  = btv->c.pci->subsystem_device << 16;
+       btv->cardid |= btv->c.pci->subsystem_vendor;
 
        if (0 != btv->cardid && 0xffffffff != btv->cardid) {
                /* look for the card */
index 834a483..14444de 100644 (file)
@@ -57,6 +57,7 @@
 
 #include <media/saa6588.h>
 
+#define BTTV_VERSION "0.9.19"
 
 unsigned int bttv_num;                 /* number of Bt848s in use */
 struct bttv *bttvs[BTTV_MAX];
@@ -163,6 +164,7 @@ MODULE_PARM_DESC(radio_nr, "radio device numbers");
 MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards");
 MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(BTTV_VERSION);
 
 /* ----------------------------------------------------------------------- */
 /* sysfs                                                                   */
@@ -2616,7 +2618,6 @@ static int bttv_querycap(struct file *file, void  *priv,
        strlcpy(cap->card, btv->video_dev->name, sizeof(cap->card));
        snprintf(cap->bus_info, sizeof(cap->bus_info),
                 "PCI:%s", pci_name(btv->c.pci));
-       cap->version = BTTV_VERSION_CODE;
        cap->capabilities =
                V4L2_CAP_VIDEO_CAPTURE |
                V4L2_CAP_VBI_CAPTURE |
@@ -3416,7 +3417,6 @@ static int radio_querycap(struct file *file, void *priv,
        strcpy(cap->driver, "bttv");
        strlcpy(cap->card, btv->radio_dev->name, sizeof(cap->card));
        sprintf(cap->bus_info, "PCI:%s", pci_name(btv->c.pci));
-       cap->version = BTTV_VERSION_CODE;
        cap->capabilities = V4L2_CAP_TUNER;
 
        return 0;
@@ -4585,14 +4585,8 @@ static int __init bttv_init_module(void)
 
        bttv_num = 0;
 
-       printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n",
-              (BTTV_VERSION_CODE >> 16) & 0xff,
-              (BTTV_VERSION_CODE >> 8) & 0xff,
-              BTTV_VERSION_CODE & 0xff);
-#ifdef SNAPSHOT
-       printk(KERN_INFO "bttv: snapshot date %04d-%02d-%02d\n",
-              SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
-#endif
+       printk(KERN_INFO "bttv: driver version %s loaded\n",
+              BTTV_VERSION);
        if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
                gbuffers = 2;
        if (gbufsize > BTTV_MAX_FBUF)
index 9b776fa..318edf2 100644 (file)
@@ -25,9 +25,6 @@
 #ifndef _BTTVP_H_
 #define _BTTVP_H_
 
-#include <linux/version.h>
-#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,18)
-
 #include <linux/types.h>
 #include <linux/wait.h>
 #include <linux/i2c.h>
index c119350..f09df9d 100644 (file)
@@ -71,7 +71,6 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include <linux/mm.h>
 #include <linux/parport.h>
 #include <linux/sched.h>
-#include <linux/version.h>
 #include <linux/videodev2.h>
 #include <linux/mutex.h>
 #include <asm/uaccess.h>
@@ -647,7 +646,6 @@ static int qcam_querycap(struct file *file, void  *priv,
        strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver));
        strlcpy(vcap->card, "B&W Quickcam", sizeof(vcap->card));
        strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
-       vcap->version = KERNEL_VERSION(0, 0, 2);
        vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
        return 0;
 }
@@ -895,6 +893,7 @@ static struct qcam *qcam_init(struct parport *port)
 
        if (v4l2_device_register(NULL, v4l2_dev) < 0) {
                v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+               kfree(qcam);
                return NULL;
        }
 
@@ -1092,3 +1091,4 @@ module_init(init_bw_qcams);
 module_exit(exit_bw_qcams);
 
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.3");
index 24fc009..cd8ff04 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/sched.h>
 #include <linux/mutex.h>
 #include <linux/jiffies.h>
-#include <linux/version.h>
 #include <linux/videodev2.h>
 #include <asm/uaccess.h>
 #include <media/v4l2-device.h>
@@ -517,7 +516,6 @@ static int qcam_querycap(struct file *file, void  *priv,
        strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver));
        strlcpy(vcap->card, "Color Quickcam", sizeof(vcap->card));
        strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
-       vcap->version = KERNEL_VERSION(0, 0, 3);
        vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
        return 0;
 }
@@ -752,6 +750,7 @@ static struct qcam *qcam_init(struct parport *port)
 
        if (v4l2_device_register(NULL, v4l2_dev) < 0) {
                v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+               kfree(qcam);
                return NULL;
        }
 
@@ -886,6 +885,7 @@ static void __exit cqcam_cleanup(void)
 MODULE_AUTHOR("Philip Blundell <philb@gnu.org>");
 MODULE_DESCRIPTION(BANNER);
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.4");
 
 module_init(cqcam_init);
 module_exit(cqcam_cleanup);
diff --git a/drivers/media/video/cafe_ccic-regs.h b/drivers/media/video/cafe_ccic-regs.h
deleted file mode 100644 (file)
index 8e2a87c..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Register definitions for the m88alp01 camera interface.  Offsets in bytes
- * as given in the spec.
- *
- * Copyright 2006 One Laptop Per Child Association, Inc.
- *
- * Written by Jonathan Corbet, corbet@lwn.net.
- *
- * This file may be distributed under the terms of the GNU General
- * Public License, version 2.
- */
-#define REG_Y0BAR      0x00
-#define REG_Y1BAR      0x04
-#define REG_Y2BAR      0x08
-/* ... */
-
-#define REG_IMGPITCH   0x24    /* Image pitch register */
-#define   IMGP_YP_SHFT   2             /* Y pitch params */
-#define   IMGP_YP_MASK   0x00003ffc    /* Y pitch field */
-#define          IMGP_UVP_SHFT   18            /* UV pitch (planar) */
-#define   IMGP_UVP_MASK   0x3ffc0000
-#define REG_IRQSTATRAW 0x28    /* RAW IRQ Status */
-#define   IRQ_EOF0       0x00000001    /* End of frame 0 */
-#define   IRQ_EOF1       0x00000002    /* End of frame 1 */
-#define   IRQ_EOF2       0x00000004    /* End of frame 2 */
-#define   IRQ_SOF0       0x00000008    /* Start of frame 0 */
-#define   IRQ_SOF1       0x00000010    /* Start of frame 1 */
-#define   IRQ_SOF2       0x00000020    /* Start of frame 2 */
-#define   IRQ_OVERFLOW   0x00000040    /* FIFO overflow */
-#define   IRQ_TWSIW      0x00010000    /* TWSI (smbus) write */
-#define   IRQ_TWSIR      0x00020000    /* TWSI read */
-#define   IRQ_TWSIE      0x00040000    /* TWSI error */
-#define   TWSIIRQS (IRQ_TWSIW|IRQ_TWSIR|IRQ_TWSIE)
-#define   FRAMEIRQS (IRQ_EOF0|IRQ_EOF1|IRQ_EOF2|IRQ_SOF0|IRQ_SOF1|IRQ_SOF2)
-#define   ALLIRQS (TWSIIRQS|FRAMEIRQS|IRQ_OVERFLOW)
-#define REG_IRQMASK    0x2c    /* IRQ mask - same bits as IRQSTAT */
-#define REG_IRQSTAT    0x30    /* IRQ status / clear */
-
-#define REG_IMGSIZE    0x34    /* Image size */
-#define  IMGSZ_V_MASK    0x1fff0000
-#define  IMGSZ_V_SHIFT   16
-#define         IMGSZ_H_MASK     0x00003fff
-#define REG_IMGOFFSET  0x38    /* IMage offset */
-
-#define REG_CTRL0      0x3c    /* Control 0 */
-#define   C0_ENABLE      0x00000001    /* Makes the whole thing go */
-
-/* Mask for all the format bits */
-#define   C0_DF_MASK     0x00fffffc    /* Bits 2-23 */
-
-/* RGB ordering */
-#define   C0_RGB4_RGBX   0x00000000
-#define          C0_RGB4_XRGB    0x00000004
-#define          C0_RGB4_BGRX    0x00000008
-#define   C0_RGB4_XBGR   0x0000000c
-#define   C0_RGB5_RGGB   0x00000000
-#define          C0_RGB5_GRBG    0x00000004
-#define          C0_RGB5_GBRG    0x00000008
-#define   C0_RGB5_BGGR   0x0000000c
-
-/* Spec has two fields for DIN and DOUT, but they must match, so
-   combine them here. */
-#define   C0_DF_YUV      0x00000000    /* Data is YUV      */
-#define   C0_DF_RGB      0x000000a0    /* ... RGB                  */
-#define   C0_DF_BAYER     0x00000140   /* ... Bayer                */
-/* 8-8-8 must be missing from the below - ask */
-#define   C0_RGBF_565    0x00000000
-#define   C0_RGBF_444    0x00000800
-#define   C0_RGB_BGR     0x00001000    /* Blue comes first */
-#define   C0_YUV_PLANAR          0x00000000    /* YUV 422 planar format */
-#define   C0_YUV_PACKED          0x00008000    /* YUV 422 packed       */
-#define   C0_YUV_420PL   0x0000a000    /* YUV 420 planar       */
-/* Think that 420 packed must be 111 - ask */
-#define          C0_YUVE_YUYV    0x00000000    /* Y1CbY0Cr             */
-#define          C0_YUVE_YVYU    0x00010000    /* Y1CrY0Cb             */
-#define          C0_YUVE_VYUY    0x00020000    /* CrY1CbY0             */
-#define          C0_YUVE_UYVY    0x00030000    /* CbY1CrY0             */
-#define   C0_YUVE_XYUV   0x00000000    /* 420: .YUV            */
-#define          C0_YUVE_XYVU    0x00010000    /* 420: .YVU            */
-#define          C0_YUVE_XUVY    0x00020000    /* 420: .UVY            */
-#define          C0_YUVE_XVUY    0x00030000    /* 420: .VUY            */
-/* Bayer bits 18,19 if needed */
-#define   C0_HPOL_LOW    0x01000000    /* HSYNC polarity active low */
-#define   C0_VPOL_LOW    0x02000000    /* VSYNC polarity active low */
-#define   C0_VCLK_LOW    0x04000000    /* VCLK on falling edge */
-#define   C0_DOWNSCALE   0x08000000    /* Enable downscaler */
-#define          C0_SIFM_MASK    0xc0000000    /* SIF mode bits */
-#define   C0_SIF_HVSYNC          0x00000000    /* Use H/VSYNC */
-#define   CO_SOF_NOSYNC          0x40000000    /* Use inband active signaling */
-
-
-#define REG_CTRL1      0x40    /* Control 1 */
-#define   C1_444ALPHA    0x00f00000    /* Alpha field in RGB444 */
-#define   C1_ALPHA_SHFT          20
-#define   C1_DMAB32      0x00000000    /* 32-byte DMA burst */
-#define   C1_DMAB16      0x02000000    /* 16-byte DMA burst */
-#define          C1_DMAB64       0x04000000    /* 64-byte DMA burst */
-#define          C1_DMAB_MASK    0x06000000
-#define   C1_TWOBUFS     0x08000000    /* Use only two DMA buffers */
-#define   C1_PWRDWN      0x10000000    /* Power down */
-
-#define REG_CLKCTRL    0x88    /* Clock control */
-#define   CLK_DIV_MASK   0x0000ffff    /* Upper bits RW "reserved" */
-
-#define REG_GPR                0xb4    /* General purpose register.  This
-                                  controls inputs to the power and reset
-                                  pins on the OV7670 used with OLPC;
-                                  other deployments could differ.  */
-#define   GPR_C1EN       0x00000020    /* Pad 1 (power down) enable */
-#define   GPR_C0EN       0x00000010    /* Pad 0 (reset) enable */
-#define          GPR_C1          0x00000002    /* Control 1 value */
-/*
- * Control 0 is wired to reset on OLPC machines.  For ov7x sensors,
- * it is active low, for 0v6x, instead, it's active high.  What
- * fun.
- */
-#define   GPR_C0         0x00000001    /* Control 0 value */
-
-#define REG_TWSIC0     0xb8    /* TWSI (smbus) control 0 */
-#define   TWSIC0_EN       0x00000001   /* TWSI enable */
-#define   TWSIC0_MODE    0x00000002    /* 1 = 16-bit, 0 = 8-bit */
-#define   TWSIC0_SID     0x000003fc    /* Slave ID */
-#define   TWSIC0_SID_SHIFT 2
-#define   TWSIC0_CLKDIV   0x0007fc00   /* Clock divider */
-#define   TWSIC0_MASKACK  0x00400000   /* Mask ack from sensor */
-#define   TWSIC0_OVMAGIC  0x00800000   /* Make it work on OV sensors */
-
-#define REG_TWSIC1     0xbc    /* TWSI control 1 */
-#define   TWSIC1_DATA    0x0000ffff    /* Data to/from camchip */
-#define   TWSIC1_ADDR    0x00ff0000    /* Address (register) */
-#define   TWSIC1_ADDR_SHIFT 16
-#define   TWSIC1_READ    0x01000000    /* Set for read op */
-#define   TWSIC1_WSTAT   0x02000000    /* Write status */
-#define   TWSIC1_RVALID          0x04000000    /* Read data valid */
-#define   TWSIC1_ERROR   0x08000000    /* Something screwed up */
-
-
-#define REG_UBAR       0xc4    /* Upper base address register */
-
-/*
- * Here's the weird global control registers which are said to live
- * way up here.
- */
-#define REG_GL_CSR     0x3004  /* Control/status register */
-#define   GCSR_SRS      0x00000001     /* SW Reset set */
-#define   GCSR_SRC      0x00000002     /* SW Reset clear */
-#define          GCSR_MRS       0x00000004     /* Master reset set */
-#define          GCSR_MRC       0x00000008     /* HW Reset clear */
-#define   GCSR_CCIC_EN   0x00004000    /* CCIC Clock enable */
-#define REG_GL_IMASK   0x300c  /* Interrupt mask register */
-#define   GIMSK_CCIC_EN          0x00000004    /* CCIC Interrupt enable */
-
-#define REG_GL_FCR     0x3038  /* GPIO functional control register */
-#define          GFCR_GPIO_ON    0x08          /* Camera GPIO enabled */
-#define REG_GL_GPIOR   0x315c  /* GPIO register */
-#define   GGPIO_OUT            0x80000 /* GPIO output */
-#define   GGPIO_VAL            0x00008 /* Output pin value */
-
-#define REG_LEN                REG_GL_IMASK + 4
-
-
-/*
- * Useful stuff that probably belongs somewhere global.
- */
-#define VGA_WIDTH      640
-#define VGA_HEIGHT     480
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
deleted file mode 100644 (file)
index 6647033..0000000
+++ /dev/null
@@ -1,2267 +0,0 @@
-/*
- * A driver for the CMOS camera controller in the Marvell 88ALP01 "cafe"
- * multifunction chip.  Currently works with the Omnivision OV7670
- * sensor.
- *
- * The data sheet for this device can be found at:
- *    http://www.marvell.com/products/pc_connectivity/88alp01/ 
- *
- * Copyright 2006 One Laptop Per Child Association, Inc.
- * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
- *
- * Written by Jonathan Corbet, corbet@lwn.net.
- *
- * v4l2_device/v4l2_subdev conversion by:
- * Copyright (C) 2009 Hans Verkuil <hverkuil@xs4all.nl>
- *
- * Note: this conversion is untested! Please contact the linux-media
- * mailinglist if you can test this, together with the test results.
- *
- * This file may be distributed under the terms of the GNU General
- * Public License, version 2.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/dmi.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-#include <linux/i2c.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/videodev2.h>
-#include <linux/slab.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-chip-ident.h>
-#include <linux/device.h>
-#include <linux/wait.h>
-#include <linux/list.h>
-#include <linux/dma-mapping.h>
-#include <linux/delay.h>
-#include <linux/jiffies.h>
-#include <linux/vmalloc.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-#include "ov7670.h"
-#include "cafe_ccic-regs.h"
-
-#define CAFE_VERSION 0x000002
-
-
-/*
- * Parameters.
- */
-MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
-MODULE_DESCRIPTION("Marvell 88ALP01 CMOS Camera Controller driver");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("Video");
-
-/*
- * Internal DMA buffer management.  Since the controller cannot do S/G I/O,
- * we must have physically contiguous buffers to bring frames into.
- * These parameters control how many buffers we use, whether we
- * allocate them at load time (better chance of success, but nails down
- * memory) or when somebody tries to use the camera (riskier), and,
- * for load-time allocation, how big they should be.
- *
- * The controller can cycle through three buffers.  We could use
- * more by flipping pointers around, but it probably makes little
- * sense.
- */
-
-#define MAX_DMA_BUFS 3
-static int alloc_bufs_at_read;
-module_param(alloc_bufs_at_read, bool, 0444);
-MODULE_PARM_DESC(alloc_bufs_at_read,
-               "Non-zero value causes DMA buffers to be allocated when the "
-               "video capture device is read, rather than at module load "
-               "time.  This saves memory, but decreases the chances of "
-               "successfully getting those buffers.");
-
-static int n_dma_bufs = 3;
-module_param(n_dma_bufs, uint, 0644);
-MODULE_PARM_DESC(n_dma_bufs,
-               "The number of DMA buffers to allocate.  Can be either two "
-               "(saves memory, makes timing tighter) or three.");
-
-static int dma_buf_size = VGA_WIDTH * VGA_HEIGHT * 2;  /* Worst case */
-module_param(dma_buf_size, uint, 0444);
-MODULE_PARM_DESC(dma_buf_size,
-               "The size of the allocated DMA buffers.  If actual operating "
-               "parameters require larger buffers, an attempt to reallocate "
-               "will be made.");
-
-static int min_buffers = 1;
-module_param(min_buffers, uint, 0644);
-MODULE_PARM_DESC(min_buffers,
-               "The minimum number of streaming I/O buffers we are willing "
-               "to work with.");
-
-static int max_buffers = 10;
-module_param(max_buffers, uint, 0644);
-MODULE_PARM_DESC(max_buffers,
-               "The maximum number of streaming I/O buffers an application "
-               "will be allowed to allocate.  These buffers are big and live "
-               "in vmalloc space.");
-
-static int flip;
-module_param(flip, bool, 0444);
-MODULE_PARM_DESC(flip,
-               "If set, the sensor will be instructed to flip the image "
-               "vertically.");
-
-
-enum cafe_state {
-       S_NOTREADY,     /* Not yet initialized */
-       S_IDLE,         /* Just hanging around */
-       S_FLAKED,       /* Some sort of problem */
-       S_SINGLEREAD,   /* In read() */
-       S_SPECREAD,     /* Speculative read (for future read()) */
-       S_STREAMING     /* Streaming data */
-};
-
-/*
- * Tracking of streaming I/O buffers.
- */
-struct cafe_sio_buffer {
-       struct list_head list;
-       struct v4l2_buffer v4lbuf;
-       char *buffer;   /* Where it lives in kernel space */
-       int mapcount;
-       struct cafe_camera *cam;
-};
-
-/*
- * A description of one of our devices.
- * Locking: controlled by s_mutex.  Certain fields, however, require
- *         the dev_lock spinlock; they are marked as such by comments.
- *         dev_lock is also required for access to device registers.
- */
-struct cafe_camera
-{
-       struct v4l2_device v4l2_dev;
-       enum cafe_state state;
-       unsigned long flags;            /* Buffer status, mainly (dev_lock) */
-       int users;                      /* How many open FDs */
-       struct file *owner;             /* Who has data access (v4l2) */
-
-       /*
-        * Subsystem structures.
-        */
-       struct pci_dev *pdev;
-       struct video_device vdev;
-       struct i2c_adapter i2c_adapter;
-       struct v4l2_subdev *sensor;
-       unsigned short sensor_addr;
-
-       unsigned char __iomem *regs;
-       struct list_head dev_list;      /* link to other devices */
-
-       /* DMA buffers */
-       unsigned int nbufs;             /* How many are alloc'd */
-       int next_buf;                   /* Next to consume (dev_lock) */
-       unsigned int dma_buf_size;      /* allocated size */
-       void *dma_bufs[MAX_DMA_BUFS];   /* Internal buffer addresses */
-       dma_addr_t dma_handles[MAX_DMA_BUFS]; /* Buffer bus addresses */
-       unsigned int specframes;        /* Unconsumed spec frames (dev_lock) */
-       unsigned int sequence;          /* Frame sequence number */
-       unsigned int buf_seq[MAX_DMA_BUFS]; /* Sequence for individual buffers */
-
-       /* Streaming buffers */
-       unsigned int n_sbufs;           /* How many we have */
-       struct cafe_sio_buffer *sb_bufs; /* The array of housekeeping structs */
-       struct list_head sb_avail;      /* Available for data (we own) (dev_lock) */
-       struct list_head sb_full;       /* With data (user space owns) (dev_lock) */
-       struct tasklet_struct s_tasklet;
-
-       /* Current operating parameters */
-       u32 sensor_type;                /* Currently ov7670 only */
-       struct v4l2_pix_format pix_format;
-       enum v4l2_mbus_pixelcode mbus_code;
-
-       /* Locks */
-       struct mutex s_mutex; /* Access to this structure */
-       spinlock_t dev_lock;  /* Access to device */
-
-       /* Misc */
-       wait_queue_head_t smbus_wait;   /* Waiting on i2c events */
-       wait_queue_head_t iowait;       /* Waiting on frame data */
-};
-
-/*
- * Status flags.  Always manipulated with bit operations.
- */
-#define CF_BUF0_VALID   0      /* Buffers valid - first three */
-#define CF_BUF1_VALID   1
-#define CF_BUF2_VALID   2
-#define CF_DMA_ACTIVE   3      /* A frame is incoming */
-#define CF_CONFIG_NEEDED 4     /* Must configure hardware */
-
-#define sensor_call(cam, o, f, args...) \
-       v4l2_subdev_call(cam->sensor, o, f, ##args)
-
-static inline struct cafe_camera *to_cam(struct v4l2_device *dev)
-{
-       return container_of(dev, struct cafe_camera, v4l2_dev);
-}
-
-static struct cafe_format_struct {
-       __u8 *desc;
-       __u32 pixelformat;
-       int bpp;   /* Bytes per pixel */
-       enum v4l2_mbus_pixelcode mbus_code;
-} cafe_formats[] = {
-       {
-               .desc           = "YUYV 4:2:2",
-               .pixelformat    = V4L2_PIX_FMT_YUYV,
-               .mbus_code      = V4L2_MBUS_FMT_YUYV8_2X8,
-               .bpp            = 2,
-       },
-       {
-               .desc           = "RGB 444",
-               .pixelformat    = V4L2_PIX_FMT_RGB444,
-               .mbus_code      = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
-               .bpp            = 2,
-       },
-       {
-               .desc           = "RGB 565",
-               .pixelformat    = V4L2_PIX_FMT_RGB565,
-               .mbus_code      = V4L2_MBUS_FMT_RGB565_2X8_LE,
-               .bpp            = 2,
-       },
-       {
-               .desc           = "Raw RGB Bayer",
-               .pixelformat    = V4L2_PIX_FMT_SBGGR8,
-               .mbus_code      = V4L2_MBUS_FMT_SBGGR8_1X8,
-               .bpp            = 1
-       },
-};
-#define N_CAFE_FMTS ARRAY_SIZE(cafe_formats)
-
-static struct cafe_format_struct *cafe_find_format(u32 pixelformat)
-{
-       unsigned i;
-
-       for (i = 0; i < N_CAFE_FMTS; i++)
-               if (cafe_formats[i].pixelformat == pixelformat)
-                       return cafe_formats + i;
-       /* Not found? Then return the first format. */
-       return cafe_formats;
-}
-
-/*
- * Start over with DMA buffers - dev_lock needed.
- */
-static void cafe_reset_buffers(struct cafe_camera *cam)
-{
-       int i;
-
-       cam->next_buf = -1;
-       for (i = 0; i < cam->nbufs; i++)
-               clear_bit(i, &cam->flags);
-       cam->specframes = 0;
-}
-
-static inline int cafe_needs_config(struct cafe_camera *cam)
-{
-       return test_bit(CF_CONFIG_NEEDED, &cam->flags);
-}
-
-static void cafe_set_config_needed(struct cafe_camera *cam, int needed)
-{
-       if (needed)
-               set_bit(CF_CONFIG_NEEDED, &cam->flags);
-       else
-               clear_bit(CF_CONFIG_NEEDED, &cam->flags);
-}
-
-
-
-
-/*
- * Debugging and related.
- */
-#define cam_err(cam, fmt, arg...) \
-       dev_err(&(cam)->pdev->dev, fmt, ##arg);
-#define cam_warn(cam, fmt, arg...) \
-       dev_warn(&(cam)->pdev->dev, fmt, ##arg);
-#define cam_dbg(cam, fmt, arg...) \
-       dev_dbg(&(cam)->pdev->dev, fmt, ##arg);
-
-
-/* ---------------------------------------------------------------------*/
-
-/*
- * Device register I/O
- */
-static inline void cafe_reg_write(struct cafe_camera *cam, unsigned int reg,
-               unsigned int val)
-{
-       iowrite32(val, cam->regs + reg);
-}
-
-static inline unsigned int cafe_reg_read(struct cafe_camera *cam,
-               unsigned int reg)
-{
-       return ioread32(cam->regs + reg);
-}
-
-
-static inline void cafe_reg_write_mask(struct cafe_camera *cam, unsigned int reg,
-               unsigned int val, unsigned int mask)
-{
-       unsigned int v = cafe_reg_read(cam, reg);
-
-       v = (v & ~mask) | (val & mask);
-       cafe_reg_write(cam, reg, v);
-}
-
-static inline void cafe_reg_clear_bit(struct cafe_camera *cam,
-               unsigned int reg, unsigned int val)
-{
-       cafe_reg_write_mask(cam, reg, 0, val);
-}
-
-static inline void cafe_reg_set_bit(struct cafe_camera *cam,
-               unsigned int reg, unsigned int val)
-{
-       cafe_reg_write_mask(cam, reg, val, val);
-}
-
-
-
-/* -------------------------------------------------------------------- */
-/*
- * The I2C/SMBUS interface to the camera itself starts here.  The
- * controller handles SMBUS itself, presenting a relatively simple register
- * interface; all we have to do is to tell it where to route the data.
- */
-#define CAFE_SMBUS_TIMEOUT (HZ)  /* generous */
-
-static int cafe_smbus_write_done(struct cafe_camera *cam)
-{
-       unsigned long flags;
-       int c1;
-
-       /*
-        * We must delay after the interrupt, or the controller gets confused
-        * and never does give us good status.  Fortunately, we don't do this
-        * often.
-        */
-       udelay(20);
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       c1 = cafe_reg_read(cam, REG_TWSIC1);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-       return (c1 & (TWSIC1_WSTAT|TWSIC1_ERROR)) != TWSIC1_WSTAT;
-}
-
-static int cafe_smbus_write_data(struct cafe_camera *cam,
-               u16 addr, u8 command, u8 value)
-{
-       unsigned int rval;
-       unsigned long flags;
-
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID);
-       rval |= TWSIC0_OVMAGIC;  /* Make OV sensors work */
-       /*
-        * Marvell sez set clkdiv to all 1's for now.
-        */
-       rval |= TWSIC0_CLKDIV;
-       cafe_reg_write(cam, REG_TWSIC0, rval);
-       (void) cafe_reg_read(cam, REG_TWSIC1); /* force write */
-       rval = value | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR);
-       cafe_reg_write(cam, REG_TWSIC1, rval);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-
-       /* Unfortunately, reading TWSIC1 too soon after sending a command
-        * causes the device to die.
-        * Use a busy-wait because we often send a large quantity of small
-        * commands at-once; using msleep() would cause a lot of context
-        * switches which take longer than 2ms, resulting in a noticeable
-        * boot-time and capture-start delays.
-        */
-       mdelay(2);
-
-       /*
-        * Another sad fact is that sometimes, commands silently complete but
-        * cafe_smbus_write_done() never becomes aware of this.
-        * This happens at random and appears to possible occur with any
-        * command.
-        * We don't understand why this is. We work around this issue
-        * with the timeout in the wait below, assuming that all commands
-        * complete within the timeout.
-        */
-       wait_event_timeout(cam->smbus_wait, cafe_smbus_write_done(cam),
-                       CAFE_SMBUS_TIMEOUT);
-
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       rval = cafe_reg_read(cam, REG_TWSIC1);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-
-       if (rval & TWSIC1_WSTAT) {
-               cam_err(cam, "SMBUS write (%02x/%02x/%02x) timed out\n", addr,
-                               command, value);
-               return -EIO;
-       }
-       if (rval & TWSIC1_ERROR) {
-               cam_err(cam, "SMBUS write (%02x/%02x/%02x) error\n", addr,
-                               command, value);
-               return -EIO;
-       }
-       return 0;
-}
-
-
-
-static int cafe_smbus_read_done(struct cafe_camera *cam)
-{
-       unsigned long flags;
-       int c1;
-
-       /*
-        * We must delay after the interrupt, or the controller gets confused
-        * and never does give us good status.  Fortunately, we don't do this
-        * often.
-        */
-       udelay(20);
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       c1 = cafe_reg_read(cam, REG_TWSIC1);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-       return c1 & (TWSIC1_RVALID|TWSIC1_ERROR);
-}
-
-
-
-static int cafe_smbus_read_data(struct cafe_camera *cam,
-               u16 addr, u8 command, u8 *value)
-{
-       unsigned int rval;
-       unsigned long flags;
-
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID);
-       rval |= TWSIC0_OVMAGIC; /* Make OV sensors work */
-       /*
-        * Marvel sez set clkdiv to all 1's for now.
-        */
-       rval |= TWSIC0_CLKDIV;
-       cafe_reg_write(cam, REG_TWSIC0, rval);
-       (void) cafe_reg_read(cam, REG_TWSIC1); /* force write */
-       rval = TWSIC1_READ | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR);
-       cafe_reg_write(cam, REG_TWSIC1, rval);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-
-       wait_event_timeout(cam->smbus_wait,
-                       cafe_smbus_read_done(cam), CAFE_SMBUS_TIMEOUT);
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       rval = cafe_reg_read(cam, REG_TWSIC1);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-
-       if (rval & TWSIC1_ERROR) {
-               cam_err(cam, "SMBUS read (%02x/%02x) error\n", addr, command);
-               return -EIO;
-       }
-       if (! (rval & TWSIC1_RVALID)) {
-               cam_err(cam, "SMBUS read (%02x/%02x) timed out\n", addr,
-                               command);
-               return -EIO;
-       }
-       *value = rval & 0xff;
-       return 0;
-}
-
-/*
- * Perform a transfer over SMBUS.  This thing is called under
- * the i2c bus lock, so we shouldn't race with ourselves...
- */
-static int cafe_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
-               unsigned short flags, char rw, u8 command,
-               int size, union i2c_smbus_data *data)
-{
-       struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter);
-       struct cafe_camera *cam = to_cam(v4l2_dev);
-       int ret = -EINVAL;
-
-       /*
-        * This interface would appear to only do byte data ops.  OK
-        * it can do word too, but the cam chip has no use for that.
-        */
-       if (size != I2C_SMBUS_BYTE_DATA) {
-               cam_err(cam, "funky xfer size %d\n", size);
-               return -EINVAL;
-       }
-
-       if (rw == I2C_SMBUS_WRITE)
-               ret = cafe_smbus_write_data(cam, addr, command, data->byte);
-       else if (rw == I2C_SMBUS_READ)
-               ret = cafe_smbus_read_data(cam, addr, command, &data->byte);
-       return ret;
-}
-
-
-static void cafe_smbus_enable_irq(struct cafe_camera *cam)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       cafe_reg_set_bit(cam, REG_IRQMASK, TWSIIRQS);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-}
-
-static u32 cafe_smbus_func(struct i2c_adapter *adapter)
-{
-       return I2C_FUNC_SMBUS_READ_BYTE_DATA  |
-              I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
-}
-
-static struct i2c_algorithm cafe_smbus_algo = {
-       .smbus_xfer = cafe_smbus_xfer,
-       .functionality = cafe_smbus_func
-};
-
-/* Somebody is on the bus */
-static void cafe_ctlr_stop_dma(struct cafe_camera *cam);
-static void cafe_ctlr_power_down(struct cafe_camera *cam);
-
-static int cafe_smbus_setup(struct cafe_camera *cam)
-{
-       struct i2c_adapter *adap = &cam->i2c_adapter;
-       int ret;
-
-       cafe_smbus_enable_irq(cam);
-       adap->owner = THIS_MODULE;
-       adap->algo = &cafe_smbus_algo;
-       strcpy(adap->name, "cafe_ccic");
-       adap->dev.parent = &cam->pdev->dev;
-       i2c_set_adapdata(adap, &cam->v4l2_dev);
-       ret = i2c_add_adapter(adap);
-       if (ret)
-               printk(KERN_ERR "Unable to register cafe i2c adapter\n");
-       return ret;
-}
-
-static void cafe_smbus_shutdown(struct cafe_camera *cam)
-{
-       i2c_del_adapter(&cam->i2c_adapter);
-}
-
-
-/* ------------------------------------------------------------------- */
-/*
- * Deal with the controller.
- */
-
-/*
- * Do everything we think we need to have the interface operating
- * according to the desired format.
- */
-static void cafe_ctlr_dma(struct cafe_camera *cam)
-{
-       /*
-        * Store the first two Y buffers (we aren't supporting
-        * planar formats for now, so no UV bufs).  Then either
-        * set the third if it exists, or tell the controller
-        * to just use two.
-        */
-       cafe_reg_write(cam, REG_Y0BAR, cam->dma_handles[0]);
-       cafe_reg_write(cam, REG_Y1BAR, cam->dma_handles[1]);
-       if (cam->nbufs > 2) {
-               cafe_reg_write(cam, REG_Y2BAR, cam->dma_handles[2]);
-               cafe_reg_clear_bit(cam, REG_CTRL1, C1_TWOBUFS);
-       }
-       else
-               cafe_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS);
-       cafe_reg_write(cam, REG_UBAR, 0); /* 32 bits only for now */
-}
-
-static void cafe_ctlr_image(struct cafe_camera *cam)
-{
-       int imgsz;
-       struct v4l2_pix_format *fmt = &cam->pix_format;
-
-       imgsz = ((fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK) |
-               (fmt->bytesperline & IMGSZ_H_MASK);
-       cafe_reg_write(cam, REG_IMGSIZE, imgsz);
-       cafe_reg_write(cam, REG_IMGOFFSET, 0);
-       /* YPITCH just drops the last two bits */
-       cafe_reg_write_mask(cam, REG_IMGPITCH, fmt->bytesperline,
-                       IMGP_YP_MASK);
-       /*
-        * Tell the controller about the image format we are using.
-        */
-       switch (cam->pix_format.pixelformat) {
-       case V4L2_PIX_FMT_YUYV:
-           cafe_reg_write_mask(cam, REG_CTRL0,
-                           C0_DF_YUV|C0_YUV_PACKED|C0_YUVE_YUYV,
-                           C0_DF_MASK);
-           break;
-
-       case V4L2_PIX_FMT_RGB444:
-           cafe_reg_write_mask(cam, REG_CTRL0,
-                           C0_DF_RGB|C0_RGBF_444|C0_RGB4_XRGB,
-                           C0_DF_MASK);
-               /* Alpha value? */
-           break;
-
-       case V4L2_PIX_FMT_RGB565:
-           cafe_reg_write_mask(cam, REG_CTRL0,
-                           C0_DF_RGB|C0_RGBF_565|C0_RGB5_BGGR,
-                           C0_DF_MASK);
-           break;
-
-       default:
-           cam_err(cam, "Unknown format %x\n", cam->pix_format.pixelformat);
-           break;
-       }
-       /*
-        * Make sure it knows we want to use hsync/vsync.
-        */
-       cafe_reg_write_mask(cam, REG_CTRL0, C0_SIF_HVSYNC,
-                       C0_SIFM_MASK);
-}
-
-
-/*
- * Configure the controller for operation; caller holds the
- * device mutex.
- */
-static int cafe_ctlr_configure(struct cafe_camera *cam)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       cafe_ctlr_dma(cam);
-       cafe_ctlr_image(cam);
-       cafe_set_config_needed(cam, 0);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-       return 0;
-}
-
-static void cafe_ctlr_irq_enable(struct cafe_camera *cam)
-{
-       /*
-        * Clear any pending interrupts, since we do not
-        * expect to have I/O active prior to enabling.
-        */
-       cafe_reg_write(cam, REG_IRQSTAT, FRAMEIRQS);
-       cafe_reg_set_bit(cam, REG_IRQMASK, FRAMEIRQS);
-}
-
-static void cafe_ctlr_irq_disable(struct cafe_camera *cam)
-{
-       cafe_reg_clear_bit(cam, REG_IRQMASK, FRAMEIRQS);
-}
-
-/*
- * Make the controller start grabbing images.  Everything must
- * be set up before doing this.
- */
-static void cafe_ctlr_start(struct cafe_camera *cam)
-{
-       /* set_bit performs a read, so no other barrier should be
-          needed here */
-       cafe_reg_set_bit(cam, REG_CTRL0, C0_ENABLE);
-}
-
-static void cafe_ctlr_stop(struct cafe_camera *cam)
-{
-       cafe_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE);
-}
-
-static void cafe_ctlr_init(struct cafe_camera *cam)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       /*
-        * Added magic to bring up the hardware on the B-Test board
-        */
-       cafe_reg_write(cam, 0x3038, 0x8);
-       cafe_reg_write(cam, 0x315c, 0x80008);
-       /*
-        * Go through the dance needed to wake the device up.
-        * Note that these registers are global and shared
-        * with the NAND and SD devices.  Interaction between the
-        * three still needs to be examined.
-        */
-       cafe_reg_write(cam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */
-       cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRC);
-       cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRS);
-       /*
-        * Here we must wait a bit for the controller to come around.
-        */
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-       msleep(5);
-       spin_lock_irqsave(&cam->dev_lock, flags);
-
-       cafe_reg_write(cam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC);
-       cafe_reg_set_bit(cam, REG_GL_IMASK, GIMSK_CCIC_EN);
-       /*
-        * Make sure it's not powered down.
-        */
-       cafe_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN);
-       /*
-        * Turn off the enable bit.  It sure should be off anyway,
-        * but it's good to be sure.
-        */
-       cafe_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE);
-       /*
-        * Mask all interrupts.
-        */
-       cafe_reg_write(cam, REG_IRQMASK, 0);
-       /*
-        * Clock the sensor appropriately.  Controller clock should
-        * be 48MHz, sensor "typical" value is half that.
-        */
-       cafe_reg_write_mask(cam, REG_CLKCTRL, 2, CLK_DIV_MASK);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-}
-
-
-/*
- * Stop the controller, and don't return until we're really sure that no
- * further DMA is going on.
- */
-static void cafe_ctlr_stop_dma(struct cafe_camera *cam)
-{
-       unsigned long flags;
-
-       /*
-        * Theory: stop the camera controller (whether it is operating
-        * or not).  Delay briefly just in case we race with the SOF
-        * interrupt, then wait until no DMA is active.
-        */
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       cafe_ctlr_stop(cam);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-       mdelay(1);
-       wait_event_timeout(cam->iowait,
-                       !test_bit(CF_DMA_ACTIVE, &cam->flags), HZ);
-       if (test_bit(CF_DMA_ACTIVE, &cam->flags))
-               cam_err(cam, "Timeout waiting for DMA to end\n");
-               /* This would be bad news - what now? */
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       cam->state = S_IDLE;
-       cafe_ctlr_irq_disable(cam);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-}
-
-/*
- * Power up and down.
- */
-static void cafe_ctlr_power_up(struct cafe_camera *cam)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       cafe_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN);
-       /*
-        * Part one of the sensor dance: turn the global
-        * GPIO signal on.
-        */
-       cafe_reg_write(cam, REG_GL_FCR, GFCR_GPIO_ON);
-       cafe_reg_write(cam, REG_GL_GPIOR, GGPIO_OUT|GGPIO_VAL);
-       /*
-        * Put the sensor into operational mode (assumes OLPC-style
-        * wiring).  Control 0 is reset - set to 1 to operate.
-        * Control 1 is power down, set to 0 to operate.
-        */
-       cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */
-/*     mdelay(1); */ /* Marvell says 1ms will do it */
-       cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0);
-/*     mdelay(1); */ /* Enough? */
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-       msleep(5); /* Just to be sure */
-}
-
-static void cafe_ctlr_power_down(struct cafe_camera *cam)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C1);
-       cafe_reg_write(cam, REG_GL_FCR, GFCR_GPIO_ON);
-       cafe_reg_write(cam, REG_GL_GPIOR, GGPIO_OUT);
-       cafe_reg_set_bit(cam, REG_CTRL1, C1_PWRDWN);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-}
-
-/* -------------------------------------------------------------------- */
-/*
- * Communications with the sensor.
- */
-
-static int __cafe_cam_reset(struct cafe_camera *cam)
-{
-       return sensor_call(cam, core, reset, 0);
-}
-
-/*
- * We have found the sensor on the i2c.  Let's try to have a
- * conversation.
- */
-static int cafe_cam_init(struct cafe_camera *cam)
-{
-       struct v4l2_dbg_chip_ident chip;
-       int ret;
-
-       mutex_lock(&cam->s_mutex);
-       if (cam->state != S_NOTREADY)
-               cam_warn(cam, "Cam init with device in funky state %d",
-                               cam->state);
-       ret = __cafe_cam_reset(cam);
-       if (ret)
-               goto out;
-       chip.ident = V4L2_IDENT_NONE;
-       chip.match.type = V4L2_CHIP_MATCH_I2C_ADDR;
-       chip.match.addr = cam->sensor_addr;
-       ret = sensor_call(cam, core, g_chip_ident, &chip);
-       if (ret)
-               goto out;
-       cam->sensor_type = chip.ident;
-       if (cam->sensor_type != V4L2_IDENT_OV7670) {
-               cam_err(cam, "Unsupported sensor type 0x%x", cam->sensor_type);
-               ret = -EINVAL;
-               goto out;
-       }
-/* Get/set parameters? */
-       ret = 0;
-       cam->state = S_IDLE;
-  out:
-       cafe_ctlr_power_down(cam);
-       mutex_unlock(&cam->s_mutex);
-       return ret;
-}
-
-/*
- * Configure the sensor to match the parameters we have.  Caller should
- * hold s_mutex
- */
-static int cafe_cam_set_flip(struct cafe_camera *cam)
-{
-       struct v4l2_control ctrl;
-
-       memset(&ctrl, 0, sizeof(ctrl));
-       ctrl.id = V4L2_CID_VFLIP;
-       ctrl.value = flip;
-       return sensor_call(cam, core, s_ctrl, &ctrl);
-}
-
-
-static int cafe_cam_configure(struct cafe_camera *cam)
-{
-       struct v4l2_mbus_framefmt mbus_fmt;
-       int ret;
-
-       v4l2_fill_mbus_format(&mbus_fmt, &cam->pix_format, cam->mbus_code);
-       ret = sensor_call(cam, core, init, 0);
-       if (ret == 0)
-               ret = sensor_call(cam, video, s_mbus_fmt, &mbus_fmt);
-       /*
-        * OV7670 does weird things if flip is set *before* format...
-        */
-       ret += cafe_cam_set_flip(cam);
-       return ret;
-}
-
-/* -------------------------------------------------------------------- */
-/*
- * DMA buffer management.  These functions need s_mutex held.
- */
-
-/* FIXME: this is inefficient as hell, since dma_alloc_coherent just
- * does a get_free_pages() call, and we waste a good chunk of an orderN
- * allocation.  Should try to allocate the whole set in one chunk.
- */
-static int cafe_alloc_dma_bufs(struct cafe_camera *cam, int loadtime)
-{
-       int i;
-
-       cafe_set_config_needed(cam, 1);
-       if (loadtime)
-               cam->dma_buf_size = dma_buf_size;
-       else
-               cam->dma_buf_size = cam->pix_format.sizeimage;
-       if (n_dma_bufs > 3)
-               n_dma_bufs = 3;
-
-       cam->nbufs = 0;
-       for (i = 0; i < n_dma_bufs; i++) {
-               cam->dma_bufs[i] = dma_alloc_coherent(&cam->pdev->dev,
-                               cam->dma_buf_size, cam->dma_handles + i,
-                               GFP_KERNEL);
-               if (cam->dma_bufs[i] == NULL) {
-                       cam_warn(cam, "Failed to allocate DMA buffer\n");
-                       break;
-               }
-               /* For debug, remove eventually */
-               memset(cam->dma_bufs[i], 0xcc, cam->dma_buf_size);
-               (cam->nbufs)++;
-       }
-
-       switch (cam->nbufs) {
-       case 1:
-           dma_free_coherent(&cam->pdev->dev, cam->dma_buf_size,
-                           cam->dma_bufs[0], cam->dma_handles[0]);
-           cam->nbufs = 0;
-       case 0:
-           cam_err(cam, "Insufficient DMA buffers, cannot operate\n");
-           return -ENOMEM;
-
-       case 2:
-           if (n_dma_bufs > 2)
-                   cam_warn(cam, "Will limp along with only 2 buffers\n");
-           break;
-       }
-       return 0;
-}
-
-static void cafe_free_dma_bufs(struct cafe_camera *cam)
-{
-       int i;
-
-       for (i = 0; i < cam->nbufs; i++) {
-               dma_free_coherent(&cam->pdev->dev, cam->dma_buf_size,
-                               cam->dma_bufs[i], cam->dma_handles[i]);
-               cam->dma_bufs[i] = NULL;
-       }
-       cam->nbufs = 0;
-}
-
-
-
-
-
-/* ----------------------------------------------------------------------- */
-/*
- * Here starts the V4L2 interface code.
- */
-
-/*
- * Read an image from the device.
- */
-static ssize_t cafe_deliver_buffer(struct cafe_camera *cam,
-               char __user *buffer, size_t len, loff_t *pos)
-{
-       int bufno;
-       unsigned long flags;
-
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       if (cam->next_buf < 0) {
-               cam_err(cam, "deliver_buffer: No next buffer\n");
-               spin_unlock_irqrestore(&cam->dev_lock, flags);
-               return -EIO;
-       }
-       bufno = cam->next_buf;
-       clear_bit(bufno, &cam->flags);
-       if (++(cam->next_buf) >= cam->nbufs)
-               cam->next_buf = 0;
-       if (! test_bit(cam->next_buf, &cam->flags))
-               cam->next_buf = -1;
-       cam->specframes = 0;
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-
-       if (len > cam->pix_format.sizeimage)
-               len = cam->pix_format.sizeimage;
-       if (copy_to_user(buffer, cam->dma_bufs[bufno], len))
-               return -EFAULT;
-       (*pos) += len;
-       return len;
-}
-
-/*
- * Get everything ready, and start grabbing frames.
- */
-static int cafe_read_setup(struct cafe_camera *cam, enum cafe_state state)
-{
-       int ret;
-       unsigned long flags;
-
-       /*
-        * Configuration.  If we still don't have DMA buffers,
-        * make one last, desperate attempt.
-        */
-       if (cam->nbufs == 0)
-               if (cafe_alloc_dma_bufs(cam, 0))
-                       return -ENOMEM;
-
-       if (cafe_needs_config(cam)) {
-               cafe_cam_configure(cam);
-               ret = cafe_ctlr_configure(cam);
-               if (ret)
-                       return ret;
-       }
-
-       /*
-        * Turn it loose.
-        */
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       cafe_reset_buffers(cam);
-       cafe_ctlr_irq_enable(cam);
-       cam->state = state;
-       cafe_ctlr_start(cam);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-       return 0;
-}
-
-
-static ssize_t cafe_v4l_read(struct file *filp,
-               char __user *buffer, size_t len, loff_t *pos)
-{
-       struct cafe_camera *cam = filp->private_data;
-       int ret = 0;
-
-       /*
-        * Perhaps we're in speculative read mode and already
-        * have data?
-        */
-       mutex_lock(&cam->s_mutex);
-       if (cam->state == S_SPECREAD) {
-               if (cam->next_buf >= 0) {
-                       ret = cafe_deliver_buffer(cam, buffer, len, pos);
-                       if (ret != 0)
-                               goto out_unlock;
-               }
-       } else if (cam->state == S_FLAKED || cam->state == S_NOTREADY) {
-               ret = -EIO;
-               goto out_unlock;
-       } else if (cam->state != S_IDLE) {
-               ret = -EBUSY;
-               goto out_unlock;
-       }
-
-       /*
-        * v4l2: multiple processes can open the device, but only
-        * one gets to grab data from it.
-        */
-       if (cam->owner && cam->owner != filp) {
-               ret = -EBUSY;
-               goto out_unlock;
-       }
-       cam->owner = filp;
-
-       /*
-        * Do setup if need be.
-        */
-       if (cam->state != S_SPECREAD) {
-               ret = cafe_read_setup(cam, S_SINGLEREAD);
-               if (ret)
-                       goto out_unlock;
-       }
-       /*
-        * Wait for something to happen.  This should probably
-        * be interruptible (FIXME).
-        */
-       wait_event_timeout(cam->iowait, cam->next_buf >= 0, HZ);
-       if (cam->next_buf < 0) {
-               cam_err(cam, "read() operation timed out\n");
-               cafe_ctlr_stop_dma(cam);
-               ret = -EIO;
-               goto out_unlock;
-       }
-       /*
-        * Give them their data and we should be done.
-        */
-       ret = cafe_deliver_buffer(cam, buffer, len, pos);
-
-  out_unlock:
-       mutex_unlock(&cam->s_mutex);
-       return ret;
-}
-
-
-
-
-
-
-
-
-/*
- * Streaming I/O support.
- */
-
-
-
-static int cafe_vidioc_streamon(struct file *filp, void *priv,
-               enum v4l2_buf_type type)
-{
-       struct cafe_camera *cam = filp->private_data;
-       int ret = -EINVAL;
-
-       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               goto out;
-       mutex_lock(&cam->s_mutex);
-       if (cam->state != S_IDLE || cam->n_sbufs == 0)
-               goto out_unlock;
-
-       cam->sequence = 0;
-       ret = cafe_read_setup(cam, S_STREAMING);
-
-  out_unlock:
-       mutex_unlock(&cam->s_mutex);
-  out:
-       return ret;
-}
-
-
-static int cafe_vidioc_streamoff(struct file *filp, void *priv,
-               enum v4l2_buf_type type)
-{
-       struct cafe_camera *cam = filp->private_data;
-       int ret = -EINVAL;
-
-       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               goto out;
-       mutex_lock(&cam->s_mutex);
-       if (cam->state != S_STREAMING)
-               goto out_unlock;
-
-       cafe_ctlr_stop_dma(cam);
-       ret = 0;
-
-  out_unlock:
-       mutex_unlock(&cam->s_mutex);
-  out:
-       return ret;
-}
-
-
-
-static int cafe_setup_siobuf(struct cafe_camera *cam, int index)
-{
-       struct cafe_sio_buffer *buf = cam->sb_bufs + index;
-
-       INIT_LIST_HEAD(&buf->list);
-       buf->v4lbuf.length = PAGE_ALIGN(cam->pix_format.sizeimage);
-       buf->buffer = vmalloc_user(buf->v4lbuf.length);
-       if (buf->buffer == NULL)
-               return -ENOMEM;
-       buf->mapcount = 0;
-       buf->cam = cam;
-
-       buf->v4lbuf.index = index;
-       buf->v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       buf->v4lbuf.field = V4L2_FIELD_NONE;
-       buf->v4lbuf.memory = V4L2_MEMORY_MMAP;
-       /*
-        * Offset: must be 32-bit even on a 64-bit system.  videobuf-dma-sg
-        * just uses the length times the index, but the spec warns
-        * against doing just that - vma merging problems.  So we
-        * leave a gap between each pair of buffers.
-        */
-       buf->v4lbuf.m.offset = 2*index*buf->v4lbuf.length;
-       return 0;
-}
-
-static int cafe_free_sio_buffers(struct cafe_camera *cam)
-{
-       int i;
-
-       /*
-        * If any buffers are mapped, we cannot free them at all.
-        */
-       for (i = 0; i < cam->n_sbufs; i++)
-               if (cam->sb_bufs[i].mapcount > 0)
-                       return -EBUSY;
-       /*
-        * OK, let's do it.
-        */
-       for (i = 0; i < cam->n_sbufs; i++)
-               vfree(cam->sb_bufs[i].buffer);
-       cam->n_sbufs = 0;
-       kfree(cam->sb_bufs);
-       cam->sb_bufs = NULL;
-       INIT_LIST_HEAD(&cam->sb_avail);
-       INIT_LIST_HEAD(&cam->sb_full);
-       return 0;
-}
-
-
-
-static int cafe_vidioc_reqbufs(struct file *filp, void *priv,
-               struct v4l2_requestbuffers *req)
-{
-       struct cafe_camera *cam = filp->private_data;
-       int ret = 0;  /* Silence warning */
-
-       /*
-        * Make sure it's something we can do.  User pointers could be
-        * implemented without great pain, but that's not been done yet.
-        */
-       if (req->memory != V4L2_MEMORY_MMAP)
-               return -EINVAL;
-       /*
-        * If they ask for zero buffers, they really want us to stop streaming
-        * (if it's happening) and free everything.  Should we check owner?
-        */
-       mutex_lock(&cam->s_mutex);
-       if (req->count == 0) {
-               if (cam->state == S_STREAMING)
-                       cafe_ctlr_stop_dma(cam);
-               ret = cafe_free_sio_buffers (cam);
-               goto out;
-       }
-       /*
-        * Device needs to be idle and working.  We *could* try to do the
-        * right thing in S_SPECREAD by shutting things down, but it
-        * probably doesn't matter.
-        */
-       if (cam->state != S_IDLE || (cam->owner && cam->owner != filp)) {
-               ret = -EBUSY;
-               goto out;
-       }
-       cam->owner = filp;
-
-       if (req->count < min_buffers)
-               req->count = min_buffers;
-       else if (req->count > max_buffers)
-               req->count = max_buffers;
-       if (cam->n_sbufs > 0) {
-               ret = cafe_free_sio_buffers(cam);
-               if (ret)
-                       goto out;
-       }
-
-       cam->sb_bufs = kzalloc(req->count*sizeof(struct cafe_sio_buffer),
-                       GFP_KERNEL);
-       if (cam->sb_bufs == NULL) {
-               ret = -ENOMEM;
-               goto out;
-       }
-       for (cam->n_sbufs = 0; cam->n_sbufs < req->count; (cam->n_sbufs++)) {
-               ret = cafe_setup_siobuf(cam, cam->n_sbufs);
-               if (ret)
-                       break;
-       }
-
-       if (cam->n_sbufs == 0)  /* no luck at all - ret already set */
-               kfree(cam->sb_bufs);
-       req->count = cam->n_sbufs;  /* In case of partial success */
-
-  out:
-       mutex_unlock(&cam->s_mutex);
-       return ret;
-}
-
-
-static int cafe_vidioc_querybuf(struct file *filp, void *priv,
-               struct v4l2_buffer *buf)
-{
-       struct cafe_camera *cam = filp->private_data;
-       int ret = -EINVAL;
-
-       mutex_lock(&cam->s_mutex);
-       if (buf->index >= cam->n_sbufs)
-               goto out;
-       *buf = cam->sb_bufs[buf->index].v4lbuf;
-       ret = 0;
-  out:
-       mutex_unlock(&cam->s_mutex);
-       return ret;
-}
-
-static int cafe_vidioc_qbuf(struct file *filp, void *priv,
-               struct v4l2_buffer *buf)
-{
-       struct cafe_camera *cam = filp->private_data;
-       struct cafe_sio_buffer *sbuf;
-       int ret = -EINVAL;
-       unsigned long flags;
-
-       mutex_lock(&cam->s_mutex);
-       if (buf->index >= cam->n_sbufs)
-               goto out;
-       sbuf = cam->sb_bufs + buf->index;
-       if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED) {
-               ret = 0; /* Already queued?? */
-               goto out;
-       }
-       if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_DONE) {
-               /* Spec doesn't say anything, seems appropriate tho */
-               ret = -EBUSY;
-               goto out;
-       }
-       sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_QUEUED;
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       list_add(&sbuf->list, &cam->sb_avail);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-       ret = 0;
-  out:
-       mutex_unlock(&cam->s_mutex);
-       return ret;
-}
-
-static int cafe_vidioc_dqbuf(struct file *filp, void *priv,
-               struct v4l2_buffer *buf)
-{
-       struct cafe_camera *cam = filp->private_data;
-       struct cafe_sio_buffer *sbuf;
-       int ret = -EINVAL;
-       unsigned long flags;
-
-       mutex_lock(&cam->s_mutex);
-       if (cam->state != S_STREAMING)
-               goto out_unlock;
-       if (list_empty(&cam->sb_full) && filp->f_flags & O_NONBLOCK) {
-               ret = -EAGAIN;
-               goto out_unlock;
-       }
-
-       while (list_empty(&cam->sb_full) && cam->state == S_STREAMING) {
-               mutex_unlock(&cam->s_mutex);
-               if (wait_event_interruptible(cam->iowait,
-                                               !list_empty(&cam->sb_full))) {
-                       ret = -ERESTARTSYS;
-                       goto out;
-               }
-               mutex_lock(&cam->s_mutex);
-       }
-
-       if (cam->state != S_STREAMING)
-               ret = -EINTR;
-       else {
-               spin_lock_irqsave(&cam->dev_lock, flags);
-               /* Should probably recheck !list_empty() here */
-               sbuf = list_entry(cam->sb_full.next,
-                               struct cafe_sio_buffer, list);
-               list_del_init(&sbuf->list);
-               spin_unlock_irqrestore(&cam->dev_lock, flags);
-               sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE;
-               *buf = sbuf->v4lbuf;
-               ret = 0;
-       }
-
-  out_unlock:
-       mutex_unlock(&cam->s_mutex);
-  out:
-       return ret;
-}
-
-
-
-static void cafe_v4l_vm_open(struct vm_area_struct *vma)
-{
-       struct cafe_sio_buffer *sbuf = vma->vm_private_data;
-       /*
-        * Locking: done under mmap_sem, so we don't need to
-        * go back to the camera lock here.
-        */
-       sbuf->mapcount++;
-}
-
-
-static void cafe_v4l_vm_close(struct vm_area_struct *vma)
-{
-       struct cafe_sio_buffer *sbuf = vma->vm_private_data;
-
-       mutex_lock(&sbuf->cam->s_mutex);
-       sbuf->mapcount--;
-       /* Docs say we should stop I/O too... */
-       if (sbuf->mapcount == 0)
-               sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_MAPPED;
-       mutex_unlock(&sbuf->cam->s_mutex);
-}
-
-static const struct vm_operations_struct cafe_v4l_vm_ops = {
-       .open = cafe_v4l_vm_open,
-       .close = cafe_v4l_vm_close
-};
-
-
-static int cafe_v4l_mmap(struct file *filp, struct vm_area_struct *vma)
-{
-       struct cafe_camera *cam = filp->private_data;
-       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-       int ret = -EINVAL;
-       int i;
-       struct cafe_sio_buffer *sbuf = NULL;
-
-       if (! (vma->vm_flags & VM_WRITE) || ! (vma->vm_flags & VM_SHARED))
-               return -EINVAL;
-       /*
-        * Find the buffer they are looking for.
-        */
-       mutex_lock(&cam->s_mutex);
-       for (i = 0; i < cam->n_sbufs; i++)
-               if (cam->sb_bufs[i].v4lbuf.m.offset == offset) {
-                       sbuf = cam->sb_bufs + i;
-                       break;
-               }
-       if (sbuf == NULL)
-               goto out;
-
-       ret = remap_vmalloc_range(vma, sbuf->buffer, 0);
-       if (ret)
-               goto out;
-       vma->vm_flags |= VM_DONTEXPAND;
-       vma->vm_private_data = sbuf;
-       vma->vm_ops = &cafe_v4l_vm_ops;
-       sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_MAPPED;
-       cafe_v4l_vm_open(vma);
-       ret = 0;
-  out:
-       mutex_unlock(&cam->s_mutex);
-       return ret;
-}
-
-
-
-static int cafe_v4l_open(struct file *filp)
-{
-       struct cafe_camera *cam = video_drvdata(filp);
-
-       filp->private_data = cam;
-
-       mutex_lock(&cam->s_mutex);
-       if (cam->users == 0) {
-               cafe_ctlr_power_up(cam);
-               __cafe_cam_reset(cam);
-               cafe_set_config_needed(cam, 1);
-       /* FIXME make sure this is complete */
-       }
-       (cam->users)++;
-       mutex_unlock(&cam->s_mutex);
-       return 0;
-}
-
-
-static int cafe_v4l_release(struct file *filp)
-{
-       struct cafe_camera *cam = filp->private_data;
-
-       mutex_lock(&cam->s_mutex);
-       (cam->users)--;
-       if (filp == cam->owner) {
-               cafe_ctlr_stop_dma(cam);
-               cafe_free_sio_buffers(cam);
-               cam->owner = NULL;
-       }
-       if (cam->users == 0) {
-               cafe_ctlr_power_down(cam);
-               if (alloc_bufs_at_read)
-                       cafe_free_dma_bufs(cam);
-       }
-       mutex_unlock(&cam->s_mutex);
-       return 0;
-}
-
-
-
-static unsigned int cafe_v4l_poll(struct file *filp,
-               struct poll_table_struct *pt)
-{
-       struct cafe_camera *cam = filp->private_data;
-
-       poll_wait(filp, &cam->iowait, pt);
-       if (cam->next_buf >= 0)
-               return POLLIN | POLLRDNORM;
-       return 0;
-}
-
-
-
-static int cafe_vidioc_queryctrl(struct file *filp, void *priv,
-               struct v4l2_queryctrl *qc)
-{
-       struct cafe_camera *cam = priv;
-       int ret;
-
-       mutex_lock(&cam->s_mutex);
-       ret = sensor_call(cam, core, queryctrl, qc);
-       mutex_unlock(&cam->s_mutex);
-       return ret;
-}
-
-
-static int cafe_vidioc_g_ctrl(struct file *filp, void *priv,
-               struct v4l2_control *ctrl)
-{
-       struct cafe_camera *cam = priv;
-       int ret;
-
-       mutex_lock(&cam->s_mutex);
-       ret = sensor_call(cam, core, g_ctrl, ctrl);
-       mutex_unlock(&cam->s_mutex);
-       return ret;
-}
-
-
-static int cafe_vidioc_s_ctrl(struct file *filp, void *priv,
-               struct v4l2_control *ctrl)
-{
-       struct cafe_camera *cam = priv;
-       int ret;
-
-       mutex_lock(&cam->s_mutex);
-       ret = sensor_call(cam, core, s_ctrl, ctrl);
-       mutex_unlock(&cam->s_mutex);
-       return ret;
-}
-
-
-
-
-
-static int cafe_vidioc_querycap(struct file *file, void *priv,
-               struct v4l2_capability *cap)
-{
-       strcpy(cap->driver, "cafe_ccic");
-       strcpy(cap->card, "cafe_ccic");
-       cap->version = CAFE_VERSION;
-       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
-               V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
-       return 0;
-}
-
-
-/*
- * The default format we use until somebody says otherwise.
- */
-static const struct v4l2_pix_format cafe_def_pix_format = {
-       .width          = VGA_WIDTH,
-       .height         = VGA_HEIGHT,
-       .pixelformat    = V4L2_PIX_FMT_YUYV,
-       .field          = V4L2_FIELD_NONE,
-       .bytesperline   = VGA_WIDTH*2,
-       .sizeimage      = VGA_WIDTH*VGA_HEIGHT*2,
-};
-
-static const enum v4l2_mbus_pixelcode cafe_def_mbus_code =
-                                       V4L2_MBUS_FMT_YUYV8_2X8;
-
-static int cafe_vidioc_enum_fmt_vid_cap(struct file *filp,
-               void *priv, struct v4l2_fmtdesc *fmt)
-{
-       if (fmt->index >= N_CAFE_FMTS)
-               return -EINVAL;
-       strlcpy(fmt->description, cafe_formats[fmt->index].desc,
-                       sizeof(fmt->description));
-       fmt->pixelformat = cafe_formats[fmt->index].pixelformat;
-       return 0;
-}
-
-static int cafe_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
-               struct v4l2_format *fmt)
-{
-       struct cafe_camera *cam = priv;
-       struct cafe_format_struct *f;
-       struct v4l2_pix_format *pix = &fmt->fmt.pix;
-       struct v4l2_mbus_framefmt mbus_fmt;
-       int ret;
-
-       f = cafe_find_format(pix->pixelformat);
-       pix->pixelformat = f->pixelformat;
-       v4l2_fill_mbus_format(&mbus_fmt, pix, f->mbus_code);
-       mutex_lock(&cam->s_mutex);
-       ret = sensor_call(cam, video, try_mbus_fmt, &mbus_fmt);
-       mutex_unlock(&cam->s_mutex);
-       v4l2_fill_pix_format(pix, &mbus_fmt);
-       pix->bytesperline = pix->width * f->bpp;
-       pix->sizeimage = pix->height * pix->bytesperline;
-       return ret;
-}
-
-static int cafe_vidioc_s_fmt_vid_cap(struct file *filp, void *priv,
-               struct v4l2_format *fmt)
-{
-       struct cafe_camera *cam = priv;
-       struct cafe_format_struct *f;
-       int ret;
-
-       /*
-        * Can't do anything if the device is not idle
-        * Also can't if there are streaming buffers in place.
-        */
-       if (cam->state != S_IDLE || cam->n_sbufs > 0)
-               return -EBUSY;
-
-       f = cafe_find_format(fmt->fmt.pix.pixelformat);
-
-       /*
-        * See if the formatting works in principle.
-        */
-       ret = cafe_vidioc_try_fmt_vid_cap(filp, priv, fmt);
-       if (ret)
-               return ret;
-       /*
-        * Now we start to change things for real, so let's do it
-        * under lock.
-        */
-       mutex_lock(&cam->s_mutex);
-       cam->pix_format = fmt->fmt.pix;
-       cam->mbus_code = f->mbus_code;
-
-       /*
-        * Make sure we have appropriate DMA buffers.
-        */
-       ret = -ENOMEM;
-       if (cam->nbufs > 0 && cam->dma_buf_size < cam->pix_format.sizeimage)
-               cafe_free_dma_bufs(cam);
-       if (cam->nbufs == 0) {
-               if (cafe_alloc_dma_bufs(cam, 0))
-                       goto out;
-       }
-       /*
-        * It looks like this might work, so let's program the sensor.
-        */
-       ret = cafe_cam_configure(cam);
-       if (! ret)
-               ret = cafe_ctlr_configure(cam);
-  out:
-       mutex_unlock(&cam->s_mutex);
-       return ret;
-}
-
-/*
- * Return our stored notion of how the camera is/should be configured.
- * The V4l2 spec wants us to be smarter, and actually get this from
- * the camera (and not mess with it at open time).  Someday.
- */
-static int cafe_vidioc_g_fmt_vid_cap(struct file *filp, void *priv,
-               struct v4l2_format *f)
-{
-       struct cafe_camera *cam = priv;
-
-       f->fmt.pix = cam->pix_format;
-       return 0;
-}
-
-/*
- * We only have one input - the sensor - so minimize the nonsense here.
- */
-static int cafe_vidioc_enum_input(struct file *filp, void *priv,
-               struct v4l2_input *input)
-{
-       if (input->index != 0)
-               return -EINVAL;
-
-       input->type = V4L2_INPUT_TYPE_CAMERA;
-       input->std = V4L2_STD_ALL; /* Not sure what should go here */
-       strcpy(input->name, "Camera");
-       return 0;
-}
-
-static int cafe_vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-       *i = 0;
-       return 0;
-}
-
-static int cafe_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-       if (i != 0)
-               return -EINVAL;
-       return 0;
-}
-
-/* from vivi.c */
-static int cafe_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a)
-{
-       return 0;
-}
-
-/*
- * G/S_PARM.  Most of this is done by the sensor, but we are
- * the level which controls the number of read buffers.
- */
-static int cafe_vidioc_g_parm(struct file *filp, void *priv,
-               struct v4l2_streamparm *parms)
-{
-       struct cafe_camera *cam = priv;
-       int ret;
-
-       mutex_lock(&cam->s_mutex);
-       ret = sensor_call(cam, video, g_parm, parms);
-       mutex_unlock(&cam->s_mutex);
-       parms->parm.capture.readbuffers = n_dma_bufs;
-       return ret;
-}
-
-static int cafe_vidioc_s_parm(struct file *filp, void *priv,
-               struct v4l2_streamparm *parms)
-{
-       struct cafe_camera *cam = priv;
-       int ret;
-
-       mutex_lock(&cam->s_mutex);
-       ret = sensor_call(cam, video, s_parm, parms);
-       mutex_unlock(&cam->s_mutex);
-       parms->parm.capture.readbuffers = n_dma_bufs;
-       return ret;
-}
-
-static int cafe_vidioc_g_chip_ident(struct file *file, void *priv,
-               struct v4l2_dbg_chip_ident *chip)
-{
-       struct cafe_camera *cam = priv;
-
-       chip->ident = V4L2_IDENT_NONE;
-       chip->revision = 0;
-       if (v4l2_chip_match_host(&chip->match)) {
-               chip->ident = V4L2_IDENT_CAFE;
-               return 0;
-       }
-       return sensor_call(cam, core, g_chip_ident, chip);
-}
-
-static int cafe_vidioc_enum_framesizes(struct file *filp, void *priv,
-               struct v4l2_frmsizeenum *sizes)
-{
-       struct cafe_camera *cam = priv;
-       int ret;
-
-       mutex_lock(&cam->s_mutex);
-       ret = sensor_call(cam, video, enum_framesizes, sizes);
-       mutex_unlock(&cam->s_mutex);
-       return ret;
-}
-
-static int cafe_vidioc_enum_frameintervals(struct file *filp, void *priv,
-               struct v4l2_frmivalenum *interval)
-{
-       struct cafe_camera *cam = priv;
-       int ret;
-
-       mutex_lock(&cam->s_mutex);
-       ret = sensor_call(cam, video, enum_frameintervals, interval);
-       mutex_unlock(&cam->s_mutex);
-       return ret;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int cafe_vidioc_g_register(struct file *file, void *priv,
-               struct v4l2_dbg_register *reg)
-{
-       struct cafe_camera *cam = priv;
-
-       if (v4l2_chip_match_host(&reg->match)) {
-               reg->val = cafe_reg_read(cam, reg->reg);
-               reg->size = 4;
-               return 0;
-       }
-       return sensor_call(cam, core, g_register, reg);
-}
-
-static int cafe_vidioc_s_register(struct file *file, void *priv,
-               struct v4l2_dbg_register *reg)
-{
-       struct cafe_camera *cam = priv;
-
-       if (v4l2_chip_match_host(&reg->match)) {
-               cafe_reg_write(cam, reg->reg, reg->val);
-               return 0;
-       }
-       return sensor_call(cam, core, s_register, reg);
-}
-#endif
-
-/*
- * This template device holds all of those v4l2 methods; we
- * clone it for specific real devices.
- */
-
-static const struct v4l2_file_operations cafe_v4l_fops = {
-       .owner = THIS_MODULE,
-       .open = cafe_v4l_open,
-       .release = cafe_v4l_release,
-       .read = cafe_v4l_read,
-       .poll = cafe_v4l_poll,
-       .mmap = cafe_v4l_mmap,
-       .unlocked_ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops cafe_v4l_ioctl_ops = {
-       .vidioc_querycap        = cafe_vidioc_querycap,
-       .vidioc_enum_fmt_vid_cap = cafe_vidioc_enum_fmt_vid_cap,
-       .vidioc_try_fmt_vid_cap = cafe_vidioc_try_fmt_vid_cap,
-       .vidioc_s_fmt_vid_cap   = cafe_vidioc_s_fmt_vid_cap,
-       .vidioc_g_fmt_vid_cap   = cafe_vidioc_g_fmt_vid_cap,
-       .vidioc_enum_input      = cafe_vidioc_enum_input,
-       .vidioc_g_input         = cafe_vidioc_g_input,
-       .vidioc_s_input         = cafe_vidioc_s_input,
-       .vidioc_s_std           = cafe_vidioc_s_std,
-       .vidioc_reqbufs         = cafe_vidioc_reqbufs,
-       .vidioc_querybuf        = cafe_vidioc_querybuf,
-       .vidioc_qbuf            = cafe_vidioc_qbuf,
-       .vidioc_dqbuf           = cafe_vidioc_dqbuf,
-       .vidioc_streamon        = cafe_vidioc_streamon,
-       .vidioc_streamoff       = cafe_vidioc_streamoff,
-       .vidioc_queryctrl       = cafe_vidioc_queryctrl,
-       .vidioc_g_ctrl          = cafe_vidioc_g_ctrl,
-       .vidioc_s_ctrl          = cafe_vidioc_s_ctrl,
-       .vidioc_g_parm          = cafe_vidioc_g_parm,
-       .vidioc_s_parm          = cafe_vidioc_s_parm,
-       .vidioc_enum_framesizes = cafe_vidioc_enum_framesizes,
-       .vidioc_enum_frameintervals = cafe_vidioc_enum_frameintervals,
-       .vidioc_g_chip_ident    = cafe_vidioc_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .vidioc_g_register      = cafe_vidioc_g_register,
-       .vidioc_s_register      = cafe_vidioc_s_register,
-#endif
-};
-
-static struct video_device cafe_v4l_template = {
-       .name = "cafe",
-       .tvnorms = V4L2_STD_NTSC_M,
-       .current_norm = V4L2_STD_NTSC_M,  /* make mplayer happy */
-
-       .fops = &cafe_v4l_fops,
-       .ioctl_ops = &cafe_v4l_ioctl_ops,
-       .release = video_device_release_empty,
-};
-
-
-/* ---------------------------------------------------------------------- */
-/*
- * Interrupt handler stuff
- */
-
-
-
-static void cafe_frame_tasklet(unsigned long data)
-{
-       struct cafe_camera *cam = (struct cafe_camera *) data;
-       int i;
-       unsigned long flags;
-       struct cafe_sio_buffer *sbuf;
-
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       for (i = 0; i < cam->nbufs; i++) {
-               int bufno = cam->next_buf;
-               if (bufno < 0) {  /* "will never happen" */
-                       cam_err(cam, "No valid bufs in tasklet!\n");
-                       break;
-               }
-               if (++(cam->next_buf) >= cam->nbufs)
-                       cam->next_buf = 0;
-               if (! test_bit(bufno, &cam->flags))
-                       continue;
-               if (list_empty(&cam->sb_avail))
-                       break;  /* Leave it valid, hope for better later */
-               clear_bit(bufno, &cam->flags);
-               sbuf = list_entry(cam->sb_avail.next,
-                               struct cafe_sio_buffer, list);
-               /*
-                * Drop the lock during the big copy.  This *should* be safe...
-                */
-               spin_unlock_irqrestore(&cam->dev_lock, flags);
-               memcpy(sbuf->buffer, cam->dma_bufs[bufno],
-                               cam->pix_format.sizeimage);
-               sbuf->v4lbuf.bytesused = cam->pix_format.sizeimage;
-               sbuf->v4lbuf.sequence = cam->buf_seq[bufno];
-               sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED;
-               sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE;
-               spin_lock_irqsave(&cam->dev_lock, flags);
-               list_move_tail(&sbuf->list, &cam->sb_full);
-       }
-       if (! list_empty(&cam->sb_full))
-               wake_up(&cam->iowait);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-}
-
-
-
-static void cafe_frame_complete(struct cafe_camera *cam, int frame)
-{
-       /*
-        * Basic frame housekeeping.
-        */
-       if (test_bit(frame, &cam->flags) && printk_ratelimit())
-               cam_err(cam, "Frame overrun on %d, frames lost\n", frame);
-       set_bit(frame, &cam->flags);
-       clear_bit(CF_DMA_ACTIVE, &cam->flags);
-       if (cam->next_buf < 0)
-               cam->next_buf = frame;
-       cam->buf_seq[frame] = ++(cam->sequence);
-
-       switch (cam->state) {
-       /*
-        * If in single read mode, try going speculative.
-        */
-           case S_SINGLEREAD:
-               cam->state = S_SPECREAD;
-               cam->specframes = 0;
-               wake_up(&cam->iowait);
-               break;
-
-       /*
-        * If we are already doing speculative reads, and nobody is
-        * reading them, just stop.
-        */
-           case S_SPECREAD:
-               if (++(cam->specframes) >= cam->nbufs) {
-                       cafe_ctlr_stop(cam);
-                       cafe_ctlr_irq_disable(cam);
-                       cam->state = S_IDLE;
-               }
-               wake_up(&cam->iowait);
-               break;
-       /*
-        * For the streaming case, we defer the real work to the
-        * camera tasklet.
-        *
-        * FIXME: if the application is not consuming the buffers,
-        * we should eventually put things on hold and restart in
-        * vidioc_dqbuf().
-        */
-           case S_STREAMING:
-               tasklet_schedule(&cam->s_tasklet);
-               break;
-
-           default:
-               cam_err(cam, "Frame interrupt in non-operational state\n");
-               break;
-       }
-}
-
-
-
-
-static void cafe_frame_irq(struct cafe_camera *cam, unsigned int irqs)
-{
-       unsigned int frame;
-
-       cafe_reg_write(cam, REG_IRQSTAT, FRAMEIRQS); /* Clear'em all */
-       /*
-        * Handle any frame completions.  There really should
-        * not be more than one of these, or we have fallen
-        * far behind.
-        */
-       for (frame = 0; frame < cam->nbufs; frame++)
-               if (irqs & (IRQ_EOF0 << frame))
-                       cafe_frame_complete(cam, frame);
-       /*
-        * If a frame starts, note that we have DMA active.  This
-        * code assumes that we won't get multiple frame interrupts
-        * at once; may want to rethink that.
-        */
-       if (irqs & (IRQ_SOF0 | IRQ_SOF1 | IRQ_SOF2))
-               set_bit(CF_DMA_ACTIVE, &cam->flags);
-}
-
-
-
-static irqreturn_t cafe_irq(int irq, void *data)
-{
-       struct cafe_camera *cam = data;
-       unsigned int irqs;
-
-       spin_lock(&cam->dev_lock);
-       irqs = cafe_reg_read(cam, REG_IRQSTAT);
-       if ((irqs & ALLIRQS) == 0) {
-               spin_unlock(&cam->dev_lock);
-               return IRQ_NONE;
-       }
-       if (irqs & FRAMEIRQS)
-               cafe_frame_irq(cam, irqs);
-       if (irqs & TWSIIRQS) {
-               cafe_reg_write(cam, REG_IRQSTAT, TWSIIRQS);
-               wake_up(&cam->smbus_wait);
-       }
-       spin_unlock(&cam->dev_lock);
-       return IRQ_HANDLED;
-}
-
-
-/* -------------------------------------------------------------------------- */
-/*
- * PCI interface stuff.
- */
-
-static const struct dmi_system_id olpc_xo1_dmi[] = {
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "OLPC"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "XO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "1"),
-               },
-       },
-       { }
-};
-
-static int cafe_pci_probe(struct pci_dev *pdev,
-               const struct pci_device_id *id)
-{
-       int ret;
-       struct cafe_camera *cam;
-       struct ov7670_config sensor_cfg = {
-               /* This controller only does SMBUS */
-               .use_smbus = true,
-
-               /*
-                * Exclude QCIF mode, because it only captures a tiny portion
-                * of the sensor FOV
-                */
-               .min_width = 320,
-               .min_height = 240,
-       };
-       struct i2c_board_info ov7670_info = {
-               .type = "ov7670",
-               .addr = 0x42,
-               .platform_data = &sensor_cfg,
-       };
-
-       /*
-        * Start putting together one of our big camera structures.
-        */
-       ret = -ENOMEM;
-       cam = kzalloc(sizeof(struct cafe_camera), GFP_KERNEL);
-       if (cam == NULL)
-               goto out;
-       ret = v4l2_device_register(&pdev->dev, &cam->v4l2_dev);
-       if (ret)
-               goto out_free;
-
-       mutex_init(&cam->s_mutex);
-       spin_lock_init(&cam->dev_lock);
-       cam->state = S_NOTREADY;
-       cafe_set_config_needed(cam, 1);
-       init_waitqueue_head(&cam->smbus_wait);
-       init_waitqueue_head(&cam->iowait);
-       cam->pdev = pdev;
-       cam->pix_format = cafe_def_pix_format;
-       cam->mbus_code = cafe_def_mbus_code;
-       INIT_LIST_HEAD(&cam->dev_list);
-       INIT_LIST_HEAD(&cam->sb_avail);
-       INIT_LIST_HEAD(&cam->sb_full);
-       tasklet_init(&cam->s_tasklet, cafe_frame_tasklet, (unsigned long) cam);
-       /*
-        * Get set up on the PCI bus.
-        */
-       ret = pci_enable_device(pdev);
-       if (ret)
-               goto out_unreg;
-       pci_set_master(pdev);
-
-       ret = -EIO;
-       cam->regs = pci_iomap(pdev, 0, 0);
-       if (! cam->regs) {
-               printk(KERN_ERR "Unable to ioremap cafe-ccic regs\n");
-               goto out_unreg;
-       }
-       ret = request_irq(pdev->irq, cafe_irq, IRQF_SHARED, "cafe-ccic", cam);
-       if (ret)
-               goto out_iounmap;
-       /*
-        * Initialize the controller and leave it powered up.  It will
-        * stay that way until the sensor driver shows up.
-        */
-       cafe_ctlr_init(cam);
-       cafe_ctlr_power_up(cam);
-       /*
-        * Set up I2C/SMBUS communications.  We have to drop the mutex here
-        * because the sensor could attach in this call chain, leading to
-        * unsightly deadlocks.
-        */
-       ret = cafe_smbus_setup(cam);
-       if (ret)
-               goto out_freeirq;
-
-       /* Apply XO-1 clock speed */
-       if (dmi_check_system(olpc_xo1_dmi))
-               sensor_cfg.clock_speed = 45;
-
-       cam->sensor_addr = ov7670_info.addr;
-       cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev, &cam->i2c_adapter,
-                       &ov7670_info, NULL);
-       if (cam->sensor == NULL) {
-               ret = -ENODEV;
-               goto out_smbus;
-       }
-
-       ret = cafe_cam_init(cam);
-       if (ret)
-               goto out_smbus;
-
-       /*
-        * Get the v4l2 setup done.
-        */
-       mutex_lock(&cam->s_mutex);
-       cam->vdev = cafe_v4l_template;
-       cam->vdev.debug = 0;
-/*     cam->vdev.debug = V4L2_DEBUG_IOCTL_ARG;*/
-       cam->vdev.v4l2_dev = &cam->v4l2_dev;
-       ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
-       if (ret)
-               goto out_unlock;
-       video_set_drvdata(&cam->vdev, cam);
-
-       /*
-        * If so requested, try to get our DMA buffers now.
-        */
-       if (!alloc_bufs_at_read) {
-               if (cafe_alloc_dma_bufs(cam, 1))
-                       cam_warn(cam, "Unable to alloc DMA buffers at load"
-                                       " will try again later.");
-       }
-
-       mutex_unlock(&cam->s_mutex);
-       return 0;
-
-out_unlock:
-       mutex_unlock(&cam->s_mutex);
-out_smbus:
-       cafe_smbus_shutdown(cam);
-out_freeirq:
-       cafe_ctlr_power_down(cam);
-       free_irq(pdev->irq, cam);
-out_iounmap:
-       pci_iounmap(pdev, cam->regs);
-out_free:
-       v4l2_device_unregister(&cam->v4l2_dev);
-out_unreg:
-       kfree(cam);
-out:
-       return ret;
-}
-
-
-/*
- * Shut down an initialized device
- */
-static void cafe_shutdown(struct cafe_camera *cam)
-{
-/* FIXME: Make sure we take care of everything here */
-       if (cam->n_sbufs > 0)
-               /* What if they are still mapped?  Shouldn't be, but... */
-               cafe_free_sio_buffers(cam);
-       cafe_ctlr_stop_dma(cam);
-       cafe_ctlr_power_down(cam);
-       cafe_smbus_shutdown(cam);
-       cafe_free_dma_bufs(cam);
-       free_irq(cam->pdev->irq, cam);
-       pci_iounmap(cam->pdev, cam->regs);
-       video_unregister_device(&cam->vdev);
-}
-
-
-static void cafe_pci_remove(struct pci_dev *pdev)
-{
-       struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
-       struct cafe_camera *cam = to_cam(v4l2_dev);
-
-       if (cam == NULL) {
-               printk(KERN_WARNING "pci_remove on unknown pdev %p\n", pdev);
-               return;
-       }
-       mutex_lock(&cam->s_mutex);
-       if (cam->users > 0)
-               cam_warn(cam, "Removing a device with users!\n");
-       cafe_shutdown(cam);
-       v4l2_device_unregister(&cam->v4l2_dev);
-       kfree(cam);
-/* No unlock - it no longer exists */
-}
-
-
-#ifdef CONFIG_PM
-/*
- * Basic power management.
- */
-static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state)
-{
-       struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
-       struct cafe_camera *cam = to_cam(v4l2_dev);
-       int ret;
-       enum cafe_state cstate;
-
-       ret = pci_save_state(pdev);
-       if (ret)
-               return ret;
-       cstate = cam->state; /* HACK - stop_dma sets to idle */
-       cafe_ctlr_stop_dma(cam);
-       cafe_ctlr_power_down(cam);
-       pci_disable_device(pdev);
-       cam->state = cstate;
-       return 0;
-}
-
-
-static int cafe_pci_resume(struct pci_dev *pdev)
-{
-       struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
-       struct cafe_camera *cam = to_cam(v4l2_dev);
-       int ret = 0;
-
-       pci_restore_state(pdev);
-       ret = pci_enable_device(pdev);
-
-       if (ret) {
-               cam_warn(cam, "Unable to re-enable device on resume!\n");
-               return ret;
-       }
-       cafe_ctlr_init(cam);
-
-       mutex_lock(&cam->s_mutex);
-       if (cam->users > 0) {
-               cafe_ctlr_power_up(cam);
-               __cafe_cam_reset(cam);
-       } else {
-               cafe_ctlr_power_down(cam);
-       }
-       mutex_unlock(&cam->s_mutex);
-
-       set_bit(CF_CONFIG_NEEDED, &cam->flags);
-       if (cam->state == S_SPECREAD)
-               cam->state = S_IDLE;  /* Don't bother restarting */
-       else if (cam->state == S_SINGLEREAD || cam->state == S_STREAMING)
-               ret = cafe_read_setup(cam, cam->state);
-       return ret;
-}
-
-#endif  /* CONFIG_PM */
-
-
-static struct pci_device_id cafe_ids[] = {
-       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL,
-                    PCI_DEVICE_ID_MARVELL_88ALP01_CCIC) },
-       { 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, cafe_ids);
-
-static struct pci_driver cafe_pci_driver = {
-       .name = "cafe1000-ccic",
-       .id_table = cafe_ids,
-       .probe = cafe_pci_probe,
-       .remove = cafe_pci_remove,
-#ifdef CONFIG_PM
-       .suspend = cafe_pci_suspend,
-       .resume = cafe_pci_resume,
-#endif
-};
-
-
-
-
-static int __init cafe_init(void)
-{
-       int ret;
-
-       printk(KERN_NOTICE "Marvell M88ALP01 'CAFE' Camera Controller version %d\n",
-                       CAFE_VERSION);
-       ret = pci_register_driver(&cafe_pci_driver);
-       if (ret) {
-               printk(KERN_ERR "Unable to register cafe_ccic driver\n");
-               goto out;
-       }
-       ret = 0;
-
-  out:
-       return ret;
-}
-
-
-static void __exit cafe_exit(void)
-{
-       pci_unregister_driver(&cafe_pci_driver);
-}
-
-module_init(cafe_init);
-module_exit(cafe_exit);
index 6d6d184..ab25218 100644 (file)
@@ -31,7 +31,6 @@
 #ifndef __CPIA2_H__
 #define __CPIA2_H__
 
-#include <linux/version.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <linux/usb.h>
 /* define for verbose debug output */
 //#define _CPIA2_DEBUG_
 
-#define CPIA2_MAJ_VER  3
-#define CPIA2_MIN_VER   0
-#define CPIA2_PATCH_VER        0
-
 /***
  * Image defines
  ***/
index 40eb632..077eb1d 100644 (file)
@@ -29,8 +29,7 @@
  *             Alan Cox <alan@lxorguk.ukuu.org.uk>
  ****************************************************************************/
 
-#include <linux/version.h>
-
+#define CPIA_VERSION "3.0.1"
 
 #include <linux/module.h>
 #include <linux/time.h>
@@ -80,6 +79,7 @@ MODULE_AUTHOR("Steve Miller (STMicroelectronics) <steve.miller@st.com>");
 MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras");
 MODULE_SUPPORTED_DEVICE("video");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(CPIA_VERSION);
 
 #define ABOUT "V4L-Driver for Vision CPiA2 based cameras"
 
@@ -465,9 +465,6 @@ static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *v
        if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) <0)
                memset(vc->bus_info,0, sizeof(vc->bus_info));
 
-       vc->version = KERNEL_VERSION(CPIA2_MAJ_VER, CPIA2_MIN_VER,
-                                    CPIA2_PATCH_VER);
-
        vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
                           V4L2_CAP_READWRITE |
                           V4L2_CAP_STREAMING;
@@ -1558,8 +1555,8 @@ static void __init check_parameters(void)
  *****************************************************************************/
 static int __init cpia2_init(void)
 {
-       LOG("%s v%d.%d.%d\n",
-           ABOUT, CPIA2_MAJ_VER, CPIA2_MIN_VER, CPIA2_PATCH_VER);
+       LOG("%s v%s\n",
+           ABOUT, CPIA_VERSION);
        check_parameters();
        cpia2_usb_init();
        return 0;
@@ -1579,4 +1576,3 @@ static void __exit cpia2_exit(void)
 
 module_init(cpia2_init);
 module_exit(cpia2_exit);
-
index d50d69d..a1e6c2a 100644 (file)
@@ -192,6 +192,7 @@ static int snd_cx18_init(struct v4l2_device *v4l2_dev)
 err_exit_free:
        if (sc != NULL)
                snd_card_free(sc);
+       kfree(cxsc);
 err_exit:
        return ret;
 }
index 0864272..1834207 100644 (file)
@@ -25,7 +25,6 @@
 #ifndef CX18_DRIVER_H
 #define CX18_DRIVER_H
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
index e80134f..afe0a29 100644 (file)
@@ -469,7 +469,6 @@ static int cx18_querycap(struct file *file, void *fh,
        strlcpy(vcap->card, cx->card_name, sizeof(vcap->card));
        snprintf(vcap->bus_info, sizeof(vcap->bus_info),
                 "PCI:%s", pci_name(cx->pci_dev));
-       vcap->version = CX18_DRIVER_VERSION;        /* version */
        vcap->capabilities = cx->v4l2_cap;          /* capabilities */
        return 0;
 }
index cd189b6..fed48b6 100644 (file)
 #define CX18_VERSION_H
 
 #define CX18_DRIVER_NAME "cx18"
-#define CX18_DRIVER_VERSION_MAJOR 1
-#define CX18_DRIVER_VERSION_MINOR 5
-#define CX18_DRIVER_VERSION_PATCHLEVEL 0
-
-#define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL)
-#define CX18_DRIVER_VERSION KERNEL_VERSION(CX18_DRIVER_VERSION_MAJOR, \
-       CX18_DRIVER_VERSION_MINOR, CX18_DRIVER_VERSION_PATCHLEVEL)
+#define CX18_VERSION "1.5.1"
 
 #endif
index 8d78134..53ff26e 100644 (file)
@@ -355,6 +355,8 @@ int cx231xx_afe_update_power_control(struct cx231xx *dev,
        case CX231XX_BOARD_HAUPPAUGE_EXETER:
        case CX231XX_BOARD_HAUPPAUGE_USBLIVE2:
        case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
+       case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL:
+       case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC:
                if (avmode == POLARIS_AVMODE_ANALOGT_TV) {
                        while (afe_power_status != (FLD_PWRDN_TUNING_BIAS |
                                                FLD_PWRDN_ENABLE_PLL)) {
@@ -1733,6 +1735,8 @@ int cx231xx_dif_set_standard(struct cx231xx *dev, u32 standard)
                break;
        case CX231XX_BOARD_CNXT_RDE_253S:
        case CX231XX_BOARD_CNXT_RDU_253S:
+       case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL:
+       case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC:
                func_mode = 0x01;
                break;
        default:
index 2270381..53dae2a 100644 (file)
@@ -387,6 +387,7 @@ struct cx231xx_board cx231xx_boards[] = {
                .norm = V4L2_STD_NTSC,
                .no_alt_vanc = 1,
                .external_av = 1,
+               .dont_use_port_3 = 1,
                .input = {{
                        .type = CX231XX_VMUX_COMPOSITE1,
                        .vmux = CX231XX_VIN_2_1,
@@ -532,6 +533,76 @@ struct cx231xx_board cx231xx_boards[] = {
                        .gpio = NULL,
                } },
        },
+       [CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL] = {
+               .name = "Hauppauge WinTV USB2 FM (PAL)",
+               .tuner_type = TUNER_NXP_TDA18271,
+               .tuner_addr = 0x60,
+               .tuner_gpio = RDE250_XCV_TUNER,
+               .tuner_sif_gpio = 0x05,
+               .tuner_scl_gpio = 0x1a,
+               .tuner_sda_gpio = 0x1b,
+               .decoder = CX231XX_AVDECODER,
+               .output_mode = OUT_MODE_VIP11,
+               .ctl_pin_status_mask = 0xFFFFFFC4,
+               .agc_analog_digital_select_gpio = 0x0c,
+               .gpio_pin_status_mask = 0x4001000,
+               .tuner_i2c_master = 1,
+               .norm = V4L2_STD_PAL,
+
+               .input = {{
+                       .type = CX231XX_VMUX_TELEVISION,
+                       .vmux = CX231XX_VIN_3_1,
+                       .amux = CX231XX_AMUX_VIDEO,
+                       .gpio = NULL,
+               }, {
+                       .type = CX231XX_VMUX_COMPOSITE1,
+                       .vmux = CX231XX_VIN_2_1,
+                       .amux = CX231XX_AMUX_LINE_IN,
+                       .gpio = NULL,
+               }, {
+                       .type = CX231XX_VMUX_SVIDEO,
+                       .vmux = CX231XX_VIN_1_1 |
+                               (CX231XX_VIN_1_2 << 8) |
+                               CX25840_SVIDEO_ON,
+                       .amux = CX231XX_AMUX_LINE_IN,
+                       .gpio = NULL,
+               } },
+       },
+       [CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC] = {
+               .name = "Hauppauge WinTV USB2 FM (NTSC)",
+               .tuner_type = TUNER_NXP_TDA18271,
+               .tuner_addr = 0x60,
+               .tuner_gpio = RDE250_XCV_TUNER,
+               .tuner_sif_gpio = 0x05,
+               .tuner_scl_gpio = 0x1a,
+               .tuner_sda_gpio = 0x1b,
+               .decoder = CX231XX_AVDECODER,
+               .output_mode = OUT_MODE_VIP11,
+               .ctl_pin_status_mask = 0xFFFFFFC4,
+               .agc_analog_digital_select_gpio = 0x0c,
+               .gpio_pin_status_mask = 0x4001000,
+               .tuner_i2c_master = 1,
+               .norm = V4L2_STD_NTSC,
+
+               .input = {{
+                       .type = CX231XX_VMUX_TELEVISION,
+                       .vmux = CX231XX_VIN_3_1,
+                       .amux = CX231XX_AMUX_VIDEO,
+                       .gpio = NULL,
+               }, {
+                       .type = CX231XX_VMUX_COMPOSITE1,
+                       .vmux = CX231XX_VIN_2_1,
+                       .amux = CX231XX_AMUX_LINE_IN,
+                       .gpio = NULL,
+               }, {
+                       .type = CX231XX_VMUX_SVIDEO,
+                       .vmux = CX231XX_VIN_1_1 |
+                               (CX231XX_VIN_1_2 << 8) |
+                               CX25840_SVIDEO_ON,
+                       .amux = CX231XX_AMUX_LINE_IN,
+                       .gpio = NULL,
+               } },
+       },
 };
 const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards);
 
@@ -553,6 +624,10 @@ struct usb_device_id cx231xx_id_table[] = {
         .driver_info = CX231XX_BOARD_CNXT_RDE_250},
        {USB_DEVICE(0x0572, 0x58A0),
         .driver_info = CX231XX_BOARD_CNXT_RDU_250},
+       {USB_DEVICE(0x2040, 0xb110),
+        .driver_info = CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL},
+       {USB_DEVICE(0x2040, 0xb111),
+        .driver_info = CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC},
        {USB_DEVICE(0x2040, 0xb120),
         .driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER},
        {USB_DEVICE(0x2040, 0xb140),
@@ -1051,6 +1126,9 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
        if (assoc_desc->bFirstInterface != ifnum) {
                cx231xx_err(DRIVER_NAME ": Not found "
                            "matching IAD interface\n");
+               cx231xx_devused &= ~(1 << nr);
+               kfree(dev);
+               dev = NULL;
                return -ENODEV;
        }
 
index abe500f..d4457f9 100644 (file)
@@ -742,6 +742,8 @@ int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode)
                case CX231XX_BOARD_CNXT_RDU_253S:
                case CX231XX_BOARD_HAUPPAUGE_EXETER:
                case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
+               case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL:
+               case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC:
                errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0);
                        break;
                default:
@@ -1381,6 +1383,8 @@ int cx231xx_dev_init(struct cx231xx *dev)
        case CX231XX_BOARD_CNXT_RDU_253S:
        case CX231XX_BOARD_HAUPPAUGE_EXETER:
        case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
+       case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL:
+       case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC:
        errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0);
                break;
        default:
index a69c24d..6e81f97 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/bitmap.h>
 #include <linux/usb.h>
 #include <linux/i2c.h>
-#include <linux/version.h>
 #include <linux/mm.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
@@ -45,7 +44,7 @@
 #include "cx231xx.h"
 #include "cx231xx-vbi.h"
 
-#define CX231XX_VERSION_CODE            KERNEL_VERSION(0, 0, 1)
+#define CX231XX_VERSION "0.0.2"
 
 #define DRIVER_AUTHOR   "Srinivasa Deevi <srinivasa.deevi@conexant.com>"
 #define DRIVER_DESC     "Conexant cx231xx based USB video device driver"
@@ -70,6 +69,7 @@ do {\
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
+MODULE_VERSION(CX231XX_VERSION);
 
 static unsigned int card[]     = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET };
 static unsigned int video_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET };
@@ -1179,7 +1179,8 @@ static int vidioc_enum_input(struct file *file, void *priv,
 {
        struct cx231xx_fh *fh = priv;
        struct cx231xx *dev = fh->dev;
-       unsigned int n;
+       u32 gen_stat;
+       unsigned int ret, n;
 
        n = i->index;
        if (n >= MAX_CX231XX_INPUT)
@@ -1198,6 +1199,18 @@ static int vidioc_enum_input(struct file *file, void *priv,
 
        i->std = dev->vdev->tvnorms;
 
+       /* If they are asking about the active input, read signal status */
+       if (n == dev->video_input) {
+               ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
+                                           GEN_STAT, 2, &gen_stat, 4);
+               if (ret > 0) {
+                       if ((gen_stat & FLD_VPRES) == 0x00)
+                               i->status |= V4L2_IN_ST_NO_SIGNAL;
+                       if ((gen_stat & FLD_HLOCK) == 0x00)
+                               i->status |= V4L2_IN_ST_NO_H_LOCK;
+               }
+       }
+
        return 0;
 }
 
@@ -1869,8 +1882,6 @@ static int vidioc_querycap(struct file *file, void *priv,
        strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card));
        usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
 
-       cap->version = CX231XX_VERSION_CODE;
-
        cap->capabilities = V4L2_CAP_VBI_CAPTURE |
 #if 0
                V4L2_CAP_SLICED_VBI_CAPTURE |
@@ -2057,7 +2068,6 @@ static int radio_querycap(struct file *file, void *priv,
        strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card));
        usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
 
-       cap->version = CX231XX_VERSION_CODE;
        cap->capabilities = V4L2_CAP_TUNER;
        return 0;
 }
@@ -2570,11 +2580,8 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
 {
        int ret;
 
-       cx231xx_info("%s: v4l2 driver version %d.%d.%d\n",
-                    dev->name,
-                    (CX231XX_VERSION_CODE >> 16) & 0xff,
-                    (CX231XX_VERSION_CODE >> 8) & 0xff,
-                    CX231XX_VERSION_CODE & 0xff);
+       cx231xx_info("%s: v4l2 driver version %s\n",
+                    dev->name, CX231XX_VERSION);
 
        /* set default norm */
        /*dev->norm = cx231xx_video_template.current_norm; */
index 46dd840..2000bc6 100644 (file)
@@ -43,7 +43,7 @@
 #include "cx231xx-conf-reg.h"
 
 #define DRIVER_NAME                     "cx231xx"
-#define PWR_SLEEP_INTERVAL              5
+#define PWR_SLEEP_INTERVAL              10
 
 /* I2C addresses for control block in Cx231xx */
 #define     AFE_DEVICE_ADDRESS         0x60
@@ -67,6 +67,8 @@
 #define CX231XX_BOARD_PV_XCAPTURE_USB 11
 #define CX231XX_BOARD_KWORLD_UB430_USB_HYBRID 12
 #define CX231XX_BOARD_ICONBIT_U100 13
+#define CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL 14
+#define CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC 15
 
 /* Limits minimum and default number of buffers */
 #define CX231XX_MIN_BUF                 4
        V4L2_STD_PAL_BG |  V4L2_STD_PAL_DK    |  V4L2_STD_PAL_I    | \
        V4L2_STD_PAL_M  |  V4L2_STD_PAL_N     |  V4L2_STD_PAL_Nc   | \
        V4L2_STD_PAL_60 |  V4L2_STD_SECAM_L   |  V4L2_STD_SECAM_DK)
-#define CX231xx_VERSION_CODE KERNEL_VERSION(0, 0, 2)
 
 #define SLEEP_S5H1432    30
 #define CX23417_OSC_EN   8
index 678539b..1fa8927 100644 (file)
@@ -52,7 +52,6 @@
  * |  DATA7|  DATA6|  DATA5|  DATA4|  DATA3|  DATA2|  DATA1|  DATA0|
  * +-------+-------+-------+-------+-------+-------+-------+-------+
  */
-#include <linux/version.h>
 #include <media/videobuf-dma-sg.h>
 #include <media/videobuf-dvb.h>
 #include "altera-ci.h"
index 9a98dc5..67c4a59 100644 (file)
@@ -1359,7 +1359,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        strlcpy(cap->card, cx23885_boards[tsport->dev->board].name,
                sizeof(cap->card));
        sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
-       cap->version = CX23885_VERSION_CODE;
        cap->capabilities =
                V4L2_CAP_VIDEO_CAPTURE |
                V4L2_CAP_READWRITE     |
index 934185c..76b7563 100644 (file)
 #include "../../../staging/altera-stapl/altera.h"
 #include "cx23885.h"
 #include "tuner-xc2028.h"
+#include "netup-eeprom.h"
 #include "netup-init.h"
 #include "altera-ci.h"
+#include "xc4000.h"
 #include "xc5000.h"
 #include "cx23888-ir.h"
 
+static unsigned int netup_card_rev = 1;
+module_param(netup_card_rev, int, 0644);
+MODULE_PARM_DESC(netup_card_rev,
+               "NetUP Dual DVB-T/C CI card revision");
 static unsigned int enable_885_ir;
 module_param(enable_885_ir, int, 0644);
 MODULE_PARM_DESC(enable_885_ir,
@@ -175,6 +181,34 @@ struct cx23885_board cx23885_boards[] = {
                .name           = "Leadtek Winfast PxDVR3200 H",
                .portc          = CX23885_MPEG_DVB,
        },
+       [CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000] = {
+               .name           = "Leadtek Winfast PxDVR3200 H XC4000",
+               .porta          = CX23885_ANALOG_VIDEO,
+               .portc          = CX23885_MPEG_DVB,
+               .tuner_type     = TUNER_XC4000,
+               .tuner_addr     = 0x61,
+               .radio_type     = TUNER_XC4000,
+               .radio_addr     = 0x61,
+               .input          = {{
+                       .type   = CX23885_VMUX_TELEVISION,
+                       .vmux   = CX25840_VIN2_CH1 |
+                                 CX25840_VIN5_CH2 |
+                                 CX25840_NONE0_CH3,
+               }, {
+                       .type   = CX23885_VMUX_COMPOSITE1,
+                       .vmux   = CX25840_COMPOSITE1,
+               }, {
+                       .type   = CX23885_VMUX_SVIDEO,
+                       .vmux   = CX25840_SVIDEO_LUMA3 |
+                                 CX25840_SVIDEO_CHROMA4,
+               }, {
+                       .type   = CX23885_VMUX_COMPONENT,
+                       .vmux   = CX25840_VIN7_CH1 |
+                                 CX25840_VIN6_CH2 |
+                                 CX25840_VIN8_CH3 |
+                                 CX25840_COMPONENT_ON,
+               } },
+       },
        [CX23885_BOARD_COMPRO_VIDEOMATE_E650F] = {
                .name           = "Compro VideoMate E650F",
                .portc          = CX23885_MPEG_DVB,
@@ -432,6 +466,10 @@ struct cx23885_subid cx23885_subids[] = {
                .subvendor = 0x107d,
                .subdevice = 0x6681,
                .card      = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H,
+       }, {
+               .subvendor = 0x107d,
+               .subdevice = 0x6f39,
+               .card      = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000,
        }, {
                .subvendor = 0x185b,
                .subdevice = 0xe800,
@@ -749,6 +787,7 @@ int cx23885_tuner_callback(void *priv, int component, int command, int arg)
        case CX23885_BOARD_HAUPPAUGE_HVR1500:
        case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
        case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+       case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
        case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200:
@@ -909,6 +948,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
                cx_set(GP0_IO, 0x000f000f);
                break;
        case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+       case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
        case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200:
@@ -1097,12 +1137,19 @@ int cx23885_ir_init(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1800:
        case CX23885_BOARD_HAUPPAUGE_HVR1200:
        case CX23885_BOARD_HAUPPAUGE_HVR1400:
-       case CX23885_BOARD_HAUPPAUGE_HVR1270:
        case CX23885_BOARD_HAUPPAUGE_HVR1275:
        case CX23885_BOARD_HAUPPAUGE_HVR1255:
        case CX23885_BOARD_HAUPPAUGE_HVR1210:
                /* FIXME: Implement me */
                break;
+       case CX23885_BOARD_HAUPPAUGE_HVR1270:
+               ret = cx23888_ir_probe(dev);
+               if (ret)
+                       break;
+               dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_888_IR);
+               v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
+                                ir_rx_pin_cfg_count, ir_rx_pin_cfg);
+               break;
        case CX23885_BOARD_HAUPPAUGE_HVR1850:
        case CX23885_BOARD_HAUPPAUGE_HVR1290:
                ret = cx23888_ir_probe(dev);
@@ -1156,6 +1203,7 @@ int cx23885_ir_init(struct cx23885_dev *dev)
 void cx23885_ir_fini(struct cx23885_dev *dev)
 {
        switch (dev->board) {
+       case CX23885_BOARD_HAUPPAUGE_HVR1270:
        case CX23885_BOARD_HAUPPAUGE_HVR1850:
        case CX23885_BOARD_HAUPPAUGE_HVR1290:
                cx23885_irq_remove(dev, PCI_MSK_IR);
@@ -1199,6 +1247,7 @@ int netup_jtag_io(void *device, int tms, int tdi, int read_tdo)
 void cx23885_ir_pci_int_enable(struct cx23885_dev *dev)
 {
        switch (dev->board) {
+       case CX23885_BOARD_HAUPPAUGE_HVR1270:
        case CX23885_BOARD_HAUPPAUGE_HVR1850:
        case CX23885_BOARD_HAUPPAUGE_HVR1290:
                if (dev->sd_ir)
@@ -1325,6 +1374,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1700:
        case CX23885_BOARD_HAUPPAUGE_HVR1400:
        case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+       case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
        case CX23885_BOARD_HAUPPAUGE_HVR1270:
        case CX23885_BOARD_HAUPPAUGE_HVR1275:
@@ -1353,10 +1403,12 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
        case CX23885_BOARD_HAUPPAUGE_HVR1700:
        case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+       case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
        case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
        case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
+       case CX23885_BOARD_HAUPPAUGE_HVR1270:
        case CX23885_BOARD_HAUPPAUGE_HVR1850:
        case CX23885_BOARD_MYGICA_X8506:
        case CX23885_BOARD_MAGICPRO_PROHDTVE2:
@@ -1383,6 +1435,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
                const struct firmware *fw;
                const char *filename = "dvb-netup-altera-01.fw";
                char *action = "configure";
+               static struct netup_card_info cinfo;
                struct altera_config netup_config = {
                        .dev = dev,
                        .action = action,
@@ -1391,6 +1444,21 @@ void cx23885_card_setup(struct cx23885_dev *dev)
 
                netup_initialize(dev);
 
+               netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo);
+               if (netup_card_rev)
+                       cinfo.rev = netup_card_rev;
+
+               switch (cinfo.rev) {
+               case 0x4:
+                       filename = "dvb-netup-altera-04.fw";
+                       break;
+               default:
+                       filename = "dvb-netup-altera-01.fw";
+                       break;
+               }
+               printk(KERN_INFO "NetUP card rev=0x%x fw_filename=%s\n",
+                               cinfo.rev, filename);
+
                ret = request_firmware(&fw, filename, &dev->pci->dev);
                if (ret != 0)
                        printk(KERN_ERR "did not find the firmware file. (%s) "
index 419777a..ee41a88 100644 (file)
@@ -42,6 +42,7 @@
 MODULE_DESCRIPTION("Driver for cx23885 based TV cards");
 MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(CX23885_VERSION);
 
 static unsigned int debug;
 module_param(debug, int, 0644);
@@ -2147,14 +2148,8 @@ static struct pci_driver cx23885_pci_driver = {
 
 static int __init cx23885_init(void)
 {
-       printk(KERN_INFO "cx23885 driver version %d.%d.%d loaded\n",
-              (CX23885_VERSION_CODE >> 16) & 0xff,
-              (CX23885_VERSION_CODE >>  8) & 0xff,
-              CX23885_VERSION_CODE & 0xff);
-#ifdef SNAPSHOT
-       printk(KERN_INFO "cx23885: snapshot date %04d-%02d-%02d\n",
-              SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
-#endif
+       printk(KERN_INFO "cx23885 driver version %s loaded\n",
+               CX23885_VERSION);
        return pci_register_driver(&cx23885_pci_driver);
 }
 
@@ -2165,5 +2160,3 @@ static void __exit cx23885_fini(void)
 
 module_init(cx23885_init);
 module_exit(cx23885_fini);
-
-/* ----------------------------------------------------------- */
index 3c315f9..aa83f07 100644 (file)
@@ -37,6 +37,7 @@
 #include "tda8290.h"
 #include "tda18271.h"
 #include "lgdt330x.h"
+#include "xc4000.h"
 #include "xc5000.h"
 #include "max2165.h"
 #include "tda10048.h"
@@ -921,6 +922,26 @@ static int dvb_register(struct cx23885_tsport *port)
                                fe->ops.tuner_ops.set_config(fe, &ctl);
                }
                break;
+       case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
+               i2c_bus = &dev->i2c_bus[0];
+
+               fe0->dvb.frontend = dvb_attach(zl10353_attach,
+                                              &dvico_fusionhdtv_xc3028,
+                                              &i2c_bus->i2c_adap);
+               if (fe0->dvb.frontend != NULL) {
+                       struct dvb_frontend     *fe;
+                       struct xc4000_config    cfg = {
+                               .i2c_address      = 0x61,
+                               .default_pm       = 0,
+                               .dvb_amplitude    = 134,
+                               .set_smoothedcvbs = 1,
+                               .if_khz           = 4560
+                       };
+
+                       fe = dvb_attach(xc4000_attach, fe0->dvb.frontend,
+                                       &dev->i2c_bus[1].i2c_adap, &cfg);
+               }
+               break;
        case CX23885_BOARD_TBS_6920:
                i2c_bus = &dev->i2c_bus[1];
 
@@ -1249,7 +1270,7 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port)
         * implement MFE support.
         */
        fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
-       if (fe0->dvb.frontend)
+       if (fe0 && fe0->dvb.frontend)
                videobuf_dvb_unregister_bus(&port->frontends);
 
        switch (port->dev->board) {
index e97cafd..ce765e3 100644 (file)
@@ -82,6 +82,7 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
                return;
 
        switch (dev->board) {
+       case CX23885_BOARD_HAUPPAUGE_HVR1270:
        case CX23885_BOARD_HAUPPAUGE_HVR1850:
        case CX23885_BOARD_HAUPPAUGE_HVR1290:
        case CX23885_BOARD_TEVII_S470:
@@ -133,6 +134,7 @@ static int cx23885_input_ir_start(struct cx23885_dev *dev)
 
        v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
        switch (dev->board) {
+       case CX23885_BOARD_HAUPPAUGE_HVR1270:
        case CX23885_BOARD_HAUPPAUGE_HVR1850:
        case CX23885_BOARD_HAUPPAUGE_HVR1290:
        case CX23885_BOARD_HAUPPAUGE_HVR1250:
@@ -229,6 +231,9 @@ static void cx23885_input_ir_stop(struct cx23885_dev *dev)
                v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
                v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
        }
+       flush_work_sync(&dev->cx25840_work);
+       flush_work_sync(&dev->ir_rx_work);
+       flush_work_sync(&dev->ir_tx_work);
 }
 
 static void cx23885_input_ir_close(struct rc_dev *rc)
@@ -257,6 +262,7 @@ int cx23885_input_init(struct cx23885_dev *dev)
                return -ENODEV;
 
        switch (dev->board) {
+       case CX23885_BOARD_HAUPPAUGE_HVR1270:
        case CX23885_BOARD_HAUPPAUGE_HVR1850:
        case CX23885_BOARD_HAUPPAUGE_HVR1290:
        case CX23885_BOARD_HAUPPAUGE_HVR1250:
index ee57f6b..896bb32 100644 (file)
@@ -1000,7 +1000,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        strlcpy(cap->card, cx23885_boards[dev->board].name,
                sizeof(cap->card));
        sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
-       cap->version = CX23885_VERSION_CODE;
        cap->capabilities =
                V4L2_CAP_VIDEO_CAPTURE |
                V4L2_CAP_READWRITE     |
index c186473..d86bc0b 100644 (file)
 #include "cx23885-reg.h"
 #include "media/cx2341x.h"
 
-#include <linux/version.h>
 #include <linux/mutex.h>
 
-#define CX23885_VERSION_CODE KERNEL_VERSION(0, 0, 2)
+#define CX23885_VERSION "0.0.3"
 
 #define UNSET (-1U)
 
@@ -86,6 +85,7 @@
 #define CX23885_BOARD_LEADTEK_WINFAST_PXTV1200 28
 #define CX23885_BOARD_GOTVIEW_X5_3D_HYBRID     29
 #define CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF 30
+#define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000 31
 
 #define GPIO_0 0x00000001
 #define GPIO_1 0x00000002
index 423c1af..68d1240 100644 (file)
@@ -113,6 +113,8 @@ MODULE_DESCRIPTION("ALSA driver module for cx2388x based TV cards");
 MODULE_AUTHOR("Ricardo Cerqueira");
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(CX88_VERSION);
+
 MODULE_SUPPORTED_DEVICE("{{Conexant,23881},"
                        "{{Conexant,23882},"
                        "{{Conexant,23883}");
@@ -973,14 +975,8 @@ static struct pci_driver cx88_audio_pci_driver = {
  */
 static int __init cx88_audio_init(void)
 {
-       printk(KERN_INFO "cx2388x alsa driver version %d.%d.%d loaded\n",
-              (CX88_VERSION_CODE >> 16) & 0xff,
-              (CX88_VERSION_CODE >>  8) & 0xff,
-              CX88_VERSION_CODE & 0xff);
-#ifdef SNAPSHOT
-       printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
-              SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
-#endif
+       printk(KERN_INFO "cx2388x alsa driver version %s loaded\n",
+              CX88_VERSION);
        return pci_register_driver(&cx88_audio_pci_driver);
 }
 
@@ -994,10 +990,3 @@ static void __exit cx88_audio_fini(void)
 
 module_init(cx88_audio_init);
 module_exit(cx88_audio_fini);
-
-/* ----------------------------------------------------------- */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index 11e49bb..e46446a 100644 (file)
@@ -42,6 +42,7 @@
 MODULE_DESCRIPTION("driver for cx2388x/cx23416 based mpeg encoder cards");
 MODULE_AUTHOR("Jelle Foks <jelle@foks.us>, Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(CX88_VERSION);
 
 static unsigned int mpegbufs = 32;
 module_param(mpegbufs,int,0644);
@@ -730,7 +731,6 @@ static int vidioc_querycap (struct file *file, void  *priv,
        strcpy(cap->driver, "cx88_blackbird");
        strlcpy(cap->card, core->board.name, sizeof(cap->card));
        sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
-       cap->version = CX88_VERSION_CODE;
        cap->capabilities =
                V4L2_CAP_VIDEO_CAPTURE |
                V4L2_CAP_READWRITE     |
@@ -1368,14 +1368,8 @@ static struct cx8802_driver cx8802_blackbird_driver = {
 
 static int __init blackbird_init(void)
 {
-       printk(KERN_INFO "cx2388x blackbird driver version %d.%d.%d loaded\n",
-              (CX88_VERSION_CODE >> 16) & 0xff,
-              (CX88_VERSION_CODE >>  8) & 0xff,
-              CX88_VERSION_CODE & 0xff);
-#ifdef SNAPSHOT
-       printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
-              SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
-#endif
+       printk(KERN_INFO "cx2388x blackbird driver version %s loaded\n",
+              CX88_VERSION);
        return cx8802_register_driver(&cx8802_blackbird_driver);
 }
 
@@ -1389,11 +1383,3 @@ module_exit(blackbird_fini);
 
 module_param_named(video_debug,cx8802_mpeg_template.debug, int, 0644);
 MODULE_PARM_DESC(debug,"enable debug messages [video]");
-
-/* ----------------------------------------------------------- */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
- */
index 27222c9..0d719fa 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "cx88.h"
 #include "tea5767.h"
+#include "xc4000.h"
 
 static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
 static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
@@ -2119,6 +2120,99 @@ static const struct cx88_board cx88_boards[] = {
                },
                .mpeg           = CX88_MPEG_DVB,
        },
+       [CX88_BOARD_WINFAST_DTV1800H_XC4000] = {
+               .name           = "Leadtek WinFast DTV1800 H (XC4000)",
+               .tuner_type     = TUNER_XC4000,
+               .radio_type     = TUNER_XC4000,
+               .tuner_addr     = 0x61,
+               .radio_addr     = 0x61,
+               /*
+                * GPIO setting
+                *
+                *  2: mute (0=off,1=on)
+                * 12: tuner reset pin
+                * 13: audio source (0=tuner audio,1=line in)
+                * 14: FM (0=on,1=off ???)
+                */
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0x0400,       /* pin 2 = 0 */
+                       .gpio1  = 0x6040,       /* pin 13 = 0, pin 14 = 1 */
+                       .gpio2  = 0x0000,
+               }, {
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0x0400,       /* pin 2 = 0 */
+                       .gpio1  = 0x6060,       /* pin 13 = 1, pin 14 = 1 */
+                       .gpio2  = 0x0000,
+               }, {
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0x0400,       /* pin 2 = 0 */
+                       .gpio1  = 0x6060,       /* pin 13 = 1, pin 14 = 1 */
+                       .gpio2  = 0x0000,
+               }},
+               .radio = {
+                       .type   = CX88_RADIO,
+                       .gpio0  = 0x0400,       /* pin 2 = 0 */
+                       .gpio1  = 0x6000,       /* pin 13 = 0, pin 14 = 0 */
+                       .gpio2  = 0x0000,
+               },
+               .mpeg           = CX88_MPEG_DVB,
+       },
+       [CX88_BOARD_WINFAST_DTV2000H_PLUS] = {
+               .name           = "Leadtek WinFast DTV2000 H PLUS",
+               .tuner_type     = TUNER_XC4000,
+               .radio_type     = TUNER_XC4000,
+               .tuner_addr     = 0x61,
+               .radio_addr     = 0x61,
+               /*
+                * GPIO
+                *   2: 1: mute audio
+                *  12: 0: reset XC4000
+                *  13: 1: audio input is line in (0: tuner)
+                *  14: 0: FM radio
+                *  16: 0: RF input is cable
+                */
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0x0403,
+                       .gpio1  = 0xF0D7,
+                       .gpio2  = 0x0101,
+                       .gpio3  = 0x0000,
+               }, {
+                       .type   = CX88_VMUX_CABLE,
+                       .vmux   = 0,
+                       .gpio0  = 0x0403,
+                       .gpio1  = 0xF0D7,
+                       .gpio2  = 0x0100,
+                       .gpio3  = 0x0000,
+               }, {
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0x0403,       /* was 0x0407 */
+                       .gpio1  = 0xF0F7,
+                       .gpio2  = 0x0101,
+                       .gpio3  = 0x0000,
+               }, {
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0x0403,       /* was 0x0407 */
+                       .gpio1  = 0xF0F7,
+                       .gpio2  = 0x0101,
+                       .gpio3  = 0x0000,
+               }},
+               .radio = {
+                       .type   = CX88_RADIO,
+                       .gpio0  = 0x0403,
+                       .gpio1  = 0xF097,
+                       .gpio2  = 0x0100,
+                       .gpio3  = 0x0000,
+               },
+               .mpeg           = CX88_MPEG_DVB,
+       },
        [CX88_BOARD_PROF_7301] = {
                .name           = "Prof 7301 DVB-S/S2",
                .tuner_type     = UNSET,
@@ -2580,6 +2674,15 @@ static const struct cx88_subid cx88_subids[] = {
                .subvendor = 0x107d,
                .subdevice = 0x6654,
                .card      = CX88_BOARD_WINFAST_DTV1800H,
+       }, {
+               /* WinFast DTV1800 H with XC4000 tuner */
+               .subvendor = 0x107d,
+               .subdevice = 0x6f38,
+               .card      = CX88_BOARD_WINFAST_DTV1800H_XC4000,
+       }, {
+               .subvendor = 0x107d,
+               .subdevice = 0x6f42,
+               .card      = CX88_BOARD_WINFAST_DTV2000H_PLUS,
        }, {
                /* PVR2000 PAL Model [107d:6630] */
                .subvendor = 0x107d,
@@ -2846,6 +2949,23 @@ static int cx88_xc3028_winfast1800h_callback(struct cx88_core *core,
        return -EINVAL;
 }
 
+static int cx88_xc4000_winfast2000h_plus_callback(struct cx88_core *core,
+                                                 int command, int arg)
+{
+       switch (command) {
+       case XC4000_TUNER_RESET:
+               /* GPIO 12 (xc4000 tuner reset) */
+               cx_set(MO_GP1_IO, 0x1010);
+               mdelay(50);
+               cx_clear(MO_GP1_IO, 0x10);
+               mdelay(75);
+               cx_set(MO_GP1_IO, 0x10);
+               mdelay(75);
+               return 0;
+       }
+       return -EINVAL;
+}
+
 /* ------------------------------------------------------------------- */
 /* some Divco specific stuff                                           */
 static int cx88_pv_8000gt_callback(struct cx88_core *core,
@@ -2948,6 +3068,19 @@ static int cx88_xc2028_tuner_callback(struct cx88_core *core,
        return -EINVAL;
 }
 
+static int cx88_xc4000_tuner_callback(struct cx88_core *core,
+                                     int command, int arg)
+{
+       /* Board-specific callbacks */
+       switch (core->boardnr) {
+       case CX88_BOARD_WINFAST_DTV1800H_XC4000:
+       case CX88_BOARD_WINFAST_DTV2000H_PLUS:
+               return cx88_xc4000_winfast2000h_plus_callback(core,
+                                                             command, arg);
+       }
+       return -EINVAL;
+}
+
 /* ----------------------------------------------------------------------- */
 /* Tuner callback function. Currently only needed for the Pinnacle        *
  * PCTV HD 800i with an xc5000 sillicon tuner. This is used for both      *
@@ -3022,6 +3155,9 @@ int cx88_tuner_callback(void *priv, int component, int command, int arg)
                case TUNER_XC2028:
                        info_printk(core, "Calling XC2028/3028 callback\n");
                        return cx88_xc2028_tuner_callback(core, command, arg);
+               case TUNER_XC4000:
+                       info_printk(core, "Calling XC4000 callback\n");
+                       return cx88_xc4000_tuner_callback(core, command, arg);
                case TUNER_XC5000:
                        info_printk(core, "Calling XC5000 callback\n");
                        return cx88_xc5000_tuner_callback(core, command, arg);
@@ -3109,13 +3245,13 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core)
 
        case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
        case CX88_BOARD_WINFAST_DTV1800H:
-               /* GPIO 12 (xc3028 tuner reset) */
-               cx_set(MO_GP1_IO, 0x1010);
-               mdelay(50);
-               cx_clear(MO_GP1_IO, 0x10);
-               mdelay(50);
-               cx_set(MO_GP1_IO, 0x10);
-               mdelay(50);
+               cx88_xc3028_winfast1800h_callback(core, XC2028_TUNER_RESET, 0);
+               break;
+
+       case CX88_BOARD_WINFAST_DTV1800H_XC4000:
+       case CX88_BOARD_WINFAST_DTV2000H_PLUS:
+               cx88_xc4000_winfast2000h_plus_callback(core,
+                                                      XC4000_TUNER_RESET, 0);
                break;
 
        case CX88_BOARD_TWINHAN_VP1027_DVBS:
index 2e145f0..fbcaa1c 100644 (file)
@@ -636,6 +636,9 @@ int cx88_reset(struct cx88_core *core)
        cx_write(MO_PCI_INTSTAT,   0xFFFFFFFF); // Clear PCI int
        cx_write(MO_INT1_STAT,     0xFFFFFFFF); // Clear RISC int
 
+       /* set default notch filter */
+       cx_andor(MO_HTOTAL, 0x1800, (HLNotchFilter4xFsc << 11));
+
        /* Reset on-board parts */
        cx_write(MO_SRST_IO, 0);
        msleep(10);
@@ -759,8 +762,8 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig
        if (nocomb)
                value |= (3 << 5); // disable comb filter
 
-       cx_write(MO_FILTER_EVEN,  value);
-       cx_write(MO_FILTER_ODD,   value);
+       cx_andor(MO_FILTER_EVEN,  0x7ffc7f, value); /* preserve PEAKEN, PSEL */
+       cx_andor(MO_FILTER_ODD,   0x7ffc7f, value);
        dprintk(1,"set_scale: filter  0x%04x\n", value);
 
        return 0;
@@ -994,10 +997,10 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm)
        // htotal
        tmp64 = norm_htotal(norm) * (u64)vdec_clock;
        do_div(tmp64, fsc8);
-       htotal = (u32)tmp64 | (HLNotchFilter4xFsc << 11);
+       htotal = (u32)tmp64;
        dprintk(1,"set_tvnorm: MO_HTOTAL        0x%08x [old=0x%08x,htotal=%d]\n",
                htotal, cx_read(MO_HTOTAL), (u32)tmp64);
-       cx_write(MO_HTOTAL, htotal);
+       cx_andor(MO_HTOTAL, 0x07ff, htotal);
 
        // vbi stuff, set vbi offset to 10 (for 20 Clk*2 pixels), this makes
        // the effective vbi offset ~244 samples, the same as the Bt8x8
index c69df7e..cf3d33a 100644 (file)
@@ -41,6 +41,7 @@
 #include "or51132.h"
 #include "lgdt330x.h"
 #include "s5h1409.h"
+#include "xc4000.h"
 #include "xc5000.h"
 #include "nxt200x.h"
 #include "cx24123.h"
@@ -63,6 +64,7 @@ MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
 MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(CX88_VERSION);
 
 static unsigned int debug;
 module_param(debug, int, 0644);
@@ -605,6 +607,39 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
        return 0;
 }
 
+static int attach_xc4000(struct cx8802_dev *dev, struct xc4000_config *cfg)
+{
+       struct dvb_frontend *fe;
+       struct videobuf_dvb_frontend *fe0 = NULL;
+
+       /* Get the first frontend */
+       fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+       if (!fe0)
+               return -EINVAL;
+
+       if (!fe0->dvb.frontend) {
+               printk(KERN_ERR "%s/2: dvb frontend not attached. "
+                               "Can't attach xc4000\n",
+                      dev->core->name);
+               return -EINVAL;
+       }
+
+       fe = dvb_attach(xc4000_attach, fe0->dvb.frontend, &dev->core->i2c_adap,
+                       cfg);
+       if (!fe) {
+               printk(KERN_ERR "%s/2: xc4000 attach failed\n",
+                      dev->core->name);
+               dvb_frontend_detach(fe0->dvb.frontend);
+               dvb_unregister_frontend(fe0->dvb.frontend);
+               fe0->dvb.frontend = NULL;
+               return -EINVAL;
+       }
+
+       printk(KERN_INFO "%s/2: xc4000 attached\n", dev->core->name);
+
+       return 0;
+}
+
 static int cx24116_set_ts_param(struct dvb_frontend *fe,
        int is_punctured)
 {
@@ -1294,7 +1329,25 @@ static int dvb_register(struct cx8802_dev *dev)
                                goto frontend_detach;
                }
                break;
-        case CX88_BOARD_GENIATECH_X8000_MT:
+       case CX88_BOARD_WINFAST_DTV1800H_XC4000:
+       case CX88_BOARD_WINFAST_DTV2000H_PLUS:
+               fe0->dvb.frontend = dvb_attach(zl10353_attach,
+                                              &cx88_pinnacle_hybrid_pctv,
+                                              &core->i2c_adap);
+               if (fe0->dvb.frontend) {
+                       struct xc4000_config cfg = {
+                               .i2c_address      = 0x61,
+                               .default_pm       = 0,
+                               .dvb_amplitude    = 134,
+                               .set_smoothedcvbs = 1,
+                               .if_khz           = 4560
+                       };
+                       fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
+                       if (attach_xc4000(dev, &cfg) < 0)
+                               goto frontend_detach;
+               }
+               break;
+       case CX88_BOARD_GENIATECH_X8000_MT:
                dev->ts_gen_cntrl = 0x00;
 
                fe0->dvb.frontend = dvb_attach(zl10353_attach,
@@ -1577,6 +1630,11 @@ static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv)
                udelay(1000);
                break;
 
+       case CX88_BOARD_WINFAST_DTV2000H_PLUS:
+               /* set RF input to AIR for DVB-T (GPIO 16) */
+               cx_write(MO_GP2_IO, 0x0101);
+               break;
+
        default:
                err = -ENODEV;
        }
@@ -1692,14 +1750,8 @@ static struct cx8802_driver cx8802_dvb_driver = {
 
 static int __init dvb_init(void)
 {
-       printk(KERN_INFO "cx88/2: cx2388x dvb driver version %d.%d.%d loaded\n",
-              (CX88_VERSION_CODE >> 16) & 0xff,
-              (CX88_VERSION_CODE >>  8) & 0xff,
-              CX88_VERSION_CODE & 0xff);
-#ifdef SNAPSHOT
-       printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
-              SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
-#endif
+       printk(KERN_INFO "cx88/2: cx2388x dvb driver version %s loaded\n",
+              CX88_VERSION);
        return cx8802_register_driver(&cx8802_dvb_driver);
 }
 
@@ -1710,10 +1762,3 @@ static void __exit dvb_fini(void)
 
 module_init(dvb_init);
 module_exit(dvb_fini);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * compile-command: "make DVB=1"
- * End:
- */
index 3f44200..e614201 100644 (file)
@@ -100,6 +100,8 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
                break;
        case CX88_BOARD_WINFAST_DTV1000:
        case CX88_BOARD_WINFAST_DTV1800H:
+       case CX88_BOARD_WINFAST_DTV1800H_XC4000:
+       case CX88_BOARD_WINFAST_DTV2000H_PLUS:
        case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
                gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900);
                auxgpio = gpio;
@@ -289,6 +291,8 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
        case CX88_BOARD_WINFAST_DTV2000H:
        case CX88_BOARD_WINFAST_DTV2000H_J:
        case CX88_BOARD_WINFAST_DTV1800H:
+       case CX88_BOARD_WINFAST_DTV1800H_XC4000:
+       case CX88_BOARD_WINFAST_DTV2000H_PLUS:
                ir_codes = RC_MAP_WINFAST;
                ir->gpio_addr = MO_GP0_IO;
                ir->mask_keycode = 0x8f8;
index 1a7b983..cd5386e 100644 (file)
@@ -39,6 +39,7 @@ MODULE_AUTHOR("Jelle Foks <jelle@foks.us>");
 MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(CX88_VERSION);
 
 static unsigned int debug;
 module_param(debug,int,0644);
@@ -613,13 +614,17 @@ static int cx8802_request_acquire(struct cx8802_driver *drv)
            core->active_type_id != drv->type_id)
                return -EBUSY;
 
-       core->input = 0;
-       for (i = 0;
-            i < (sizeof(core->board.input) / sizeof(struct cx88_input));
-            i++) {
-               if (core->board.input[i].type == CX88_VMUX_DVB) {
-                       core->input = i;
-                       break;
+       if (drv->type_id == CX88_MPEG_DVB) {
+               /* When switching to DVB, always set the input to the tuner */
+               core->last_analog_input = core->input;
+               core->input = 0;
+               for (i = 0;
+                    i < (sizeof(core->board.input) / sizeof(struct cx88_input));
+                    i++) {
+                       if (core->board.input[i].type == CX88_VMUX_DVB) {
+                               core->input = i;
+                               break;
+                       }
                }
        }
 
@@ -644,6 +649,12 @@ static int cx8802_request_release(struct cx8802_driver *drv)
 
        if (drv->advise_release && --core->active_ref == 0)
        {
+               if (drv->type_id == CX88_MPEG_DVB) {
+                       /* If the DVB driver is releasing, reset the input
+                          state to the last configured analog input */
+                       core->input = core->last_analog_input;
+               }
+
                drv->advise_release(drv);
                core->active_type_id = CX88_BOARD_NONE;
                mpeg_dbg(1,"%s() Post release GPIO=%x\n", __func__, cx_read(MO_GP0_IO));
@@ -890,14 +901,8 @@ static struct pci_driver cx8802_pci_driver = {
 
 static int __init cx8802_init(void)
 {
-       printk(KERN_INFO "cx88/2: cx2388x MPEG-TS Driver Manager version %d.%d.%d loaded\n",
-              (CX88_VERSION_CODE >> 16) & 0xff,
-              (CX88_VERSION_CODE >>  8) & 0xff,
-              CX88_VERSION_CODE & 0xff);
-#ifdef SNAPSHOT
-       printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
-              SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
-#endif
+       printk(KERN_INFO "cx88/2: cx2388x MPEG-TS Driver Manager version %s loaded\n",
+              CX88_VERSION);
        return pci_register_driver(&cx8802_pci_driver);
 }
 
index cef4f28..60d28fd 100644 (file)
@@ -45,6 +45,7 @@
 MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(CX88_VERSION);
 
 /* ------------------------------------------------------------------ */
 
@@ -220,7 +221,23 @@ static const struct cx88_ctrl cx8800_ctls[] = {
                .reg                   = MO_UV_SATURATION,
                .mask                  = 0x00ff,
                .shift                 = 0,
-       },{
+       }, {
+               .v = {
+                       .id            = V4L2_CID_SHARPNESS,
+                       .name          = "Sharpness",
+                       .minimum       = 0,
+                       .maximum       = 4,
+                       .step          = 1,
+                       .default_value = 0x0,
+                       .type          = V4L2_CTRL_TYPE_INTEGER,
+               },
+               .off                   = 0,
+               /* NOTE: the value is converted and written to both even
+                  and odd registers in the code */
+               .reg                   = MO_FILTER_ODD,
+               .mask                  = 7 << 7,
+               .shift                 = 7,
+       }, {
                .v = {
                        .id            = V4L2_CID_CHROMA_AGC,
                        .name          = "Chroma AGC",
@@ -244,6 +261,20 @@ static const struct cx88_ctrl cx8800_ctls[] = {
                .reg                   = MO_INPUT_FORMAT,
                .mask                  = 1 << 9,
                .shift                 = 9,
+       }, {
+               .v = {
+                       .id            = V4L2_CID_BAND_STOP_FILTER,
+                       .name          = "Notch filter",
+                       .minimum       = 0,
+                       .maximum       = 3,
+                       .step          = 1,
+                       .default_value = 0x0,
+                       .type          = V4L2_CTRL_TYPE_INTEGER,
+               },
+               .off                   = 0,
+               .reg                   = MO_HTOTAL,
+               .mask                  = 3 << 11,
+               .shift                 = 11,
        }, {
        /* --- audio --- */
                .v = {
@@ -300,8 +331,10 @@ const u32 cx88_user_ctrls[] = {
        V4L2_CID_AUDIO_VOLUME,
        V4L2_CID_AUDIO_BALANCE,
        V4L2_CID_AUDIO_MUTE,
+       V4L2_CID_SHARPNESS,
        V4L2_CID_CHROMA_AGC,
        V4L2_CID_COLOR_KILLER,
+       V4L2_CID_BAND_STOP_FILTER,
        0
 };
 EXPORT_SYMBOL(cx88_user_ctrls);
@@ -962,6 +995,10 @@ int cx88_get_control (struct cx88_core  *core, struct v4l2_control *ctl)
        case V4L2_CID_AUDIO_VOLUME:
                ctl->value = 0x3f - (value & 0x3f);
                break;
+       case V4L2_CID_SHARPNESS:
+               ctl->value = ((value & 0x0200) ? (((value & 0x0180) >> 7) + 1)
+                                                : 0);
+               break;
        default:
                ctl->value = ((value + (c->off << c->shift)) & c->mask) >> c->shift;
                break;
@@ -1039,6 +1076,12 @@ int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl)
                }
                mask=0xffff;
                break;
+       case V4L2_CID_SHARPNESS:
+               /* 0b000, 0b100, 0b101, 0b110, or 0b111 */
+               value = (ctl->value < 1 ? 0 : ((ctl->value + 3) << 7));
+               /* needs to be set for both fields */
+               cx_andor(MO_FILTER_EVEN, mask, value);
+               break;
        case V4L2_CID_CHROMA_AGC:
                /* Do not allow chroma AGC to be enabled for SECAM */
                value = ((ctl->value - c->off) << c->shift) & c->mask;
@@ -1161,7 +1204,6 @@ static int vidioc_querycap (struct file *file, void  *priv,
        strcpy(cap->driver, "cx8800");
        strlcpy(cap->card, core->board.name, sizeof(cap->card));
        sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
-       cap->version = CX88_VERSION_CODE;
        cap->capabilities =
                V4L2_CAP_VIDEO_CAPTURE |
                V4L2_CAP_READWRITE     |
@@ -1480,7 +1522,6 @@ static int radio_querycap (struct file *file, void  *priv,
        strcpy(cap->driver, "cx8800");
        strlcpy(cap->card, core->board.name, sizeof(cap->card));
        sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
-       cap->version = CX88_VERSION_CODE;
        cap->capabilities = V4L2_CAP_TUNER;
        return 0;
 }
@@ -2139,14 +2180,8 @@ static struct pci_driver cx8800_pci_driver = {
 
 static int __init cx8800_init(void)
 {
-       printk(KERN_INFO "cx88/0: cx2388x v4l2 driver version %d.%d.%d loaded\n",
-              (CX88_VERSION_CODE >> 16) & 0xff,
-              (CX88_VERSION_CODE >>  8) & 0xff,
-              CX88_VERSION_CODE & 0xff);
-#ifdef SNAPSHOT
-       printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
-              SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
-#endif
+       printk(KERN_INFO "cx88/0: cx2388x v4l2 driver version %s loaded\n",
+              CX88_VERSION);
        return pci_register_driver(&cx8800_pci_driver);
 }
 
@@ -2157,11 +2192,3 @@ static void __exit cx8800_fini(void)
 
 module_init(cx8800_init);
 module_exit(cx8800_fini);
-
-/* ----------------------------------------------------------- */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
- */
index a399a8b..fa8d307 100644 (file)
@@ -39,9 +39,9 @@
 #include "cx88-reg.h"
 #include "tuner-xc2028.h"
 
-#include <linux/version.h>
 #include <linux/mutex.h>
-#define CX88_VERSION_CODE KERNEL_VERSION(0, 0, 8)
+
+#define CX88_VERSION "0.0.9"
 
 #define UNSET (-1U)
 
@@ -242,6 +242,8 @@ extern const struct sram_channel const cx88_sram_channels[];
 #define CX88_BOARD_SAMSUNG_SMT_7020        84
 #define CX88_BOARD_TWINHAN_VP1027_DVBS     85
 #define CX88_BOARD_TEVII_S464              86
+#define CX88_BOARD_WINFAST_DTV2000H_PLUS   87
+#define CX88_BOARD_WINFAST_DTV1800H_XC4000 88
 
 enum cx88_itype {
        CX88_VMUX_COMPOSITE1 = 1,
@@ -375,6 +377,7 @@ struct cx88_core {
        u32                        audiomode_manual;
        u32                        audiomode_current;
        u32                        input;
+       u32                        last_analog_input;
        u32                        astat;
        u32                        use_nicam;
        unsigned long              last_change;
index 6b19540..60a456e 100644 (file)
@@ -91,3 +91,26 @@ config VIDEO_ISIF
 
           To compile this driver as a module, choose M here: the
           module will be called vpfe.
+
+config VIDEO_DM644X_VPBE
+       tristate "DM644X VPBE HW module"
+       depends on ARCH_DAVINCI_DM644x
+       select VIDEO_VPSS_SYSTEM
+       select VIDEOBUF_DMA_CONTIG
+       help
+           Enables VPBE modules used for display on a DM644x
+           SoC.
+
+           To compile this driver as a module, choose M here: the
+           module will be called vpbe.
+
+
+config VIDEO_VPBE_DISPLAY
+       tristate "VPBE V4L2 Display driver"
+       depends on ARCH_DAVINCI_DM644x
+       select VIDEO_DM644X_VPBE
+       help
+           Enables VPBE V4L2 Display driver on a DM644x device
+
+           To compile this driver as a module, choose M here: the
+           module will be called vpbe_display.
index a379557..ae7dafb 100644 (file)
@@ -16,3 +16,5 @@ obj-$(CONFIG_VIDEO_VPFE_CAPTURE) += vpfe_capture.o
 obj-$(CONFIG_VIDEO_DM6446_CCDC) += dm644x_ccdc.o
 obj-$(CONFIG_VIDEO_DM355_CCDC) += dm355_ccdc.o
 obj-$(CONFIG_VIDEO_ISIF) += isif.o
+obj-$(CONFIG_VIDEO_DM644X_VPBE) += vpbe.o vpbe_osd.o vpbe_venc.o
+obj-$(CONFIG_VIDEO_VPBE_DISPLAY) += vpbe_display.o
diff --git a/drivers/media/video/davinci/vpbe.c b/drivers/media/video/davinci/vpbe.c
new file mode 100644 (file)
index 0000000..d773d30
--- /dev/null
@@ -0,0 +1,864 @@
+/*
+ * Copyright (C) 2010 Texas Instruments 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/wait.h>
+#include <linux/time.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include <media/v4l2-device.h>
+#include <media/davinci/vpbe_types.h>
+#include <media/davinci/vpbe.h>
+#include <media/davinci/vpss.h>
+#include <media/davinci/vpbe_venc.h>
+
+#define VPBE_DEFAULT_OUTPUT    "Composite"
+#define VPBE_DEFAULT_MODE      "ntsc"
+
+static char *def_output = VPBE_DEFAULT_OUTPUT;
+static char *def_mode = VPBE_DEFAULT_MODE;
+static int debug;
+
+module_param(def_output, charp, S_IRUGO);
+module_param(def_mode, charp, S_IRUGO);
+module_param(debug, int, 0644);
+
+MODULE_PARM_DESC(def_output, "vpbe output name (default:Composite)");
+MODULE_PARM_DESC(def_mode, "vpbe output mode name (default:ntsc");
+MODULE_PARM_DESC(debug, "Debug level 0-1");
+
+MODULE_DESCRIPTION("TI DMXXX VPBE Display controller");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Texas Instruments");
+
+/**
+ * vpbe_current_encoder_info - Get config info for current encoder
+ * @vpbe_dev - vpbe device ptr
+ *
+ * Return ptr to current encoder config info
+ */
+static struct encoder_config_info*
+vpbe_current_encoder_info(struct vpbe_device *vpbe_dev)
+{
+       struct vpbe_config *cfg = vpbe_dev->cfg;
+       int index = vpbe_dev->current_sd_index;
+
+       return ((index == 0) ? &cfg->venc :
+                               &cfg->ext_encoders[index-1]);
+}
+
+/**
+ * vpbe_find_encoder_sd_index - Given a name find encoder sd index
+ *
+ * @vpbe_config - ptr to vpbe cfg
+ * @output_index - index used by application
+ *
+ * Return sd index of the encoder
+ */
+static int vpbe_find_encoder_sd_index(struct vpbe_config *cfg,
+                            int index)
+{
+       char *encoder_name = cfg->outputs[index].subdev_name;
+       int i;
+
+       /* Venc is always first */
+       if (!strcmp(encoder_name, cfg->venc.module_name))
+               return 0;
+
+       for (i = 0; i < cfg->num_ext_encoders; i++) {
+               if (!strcmp(encoder_name,
+                    cfg->ext_encoders[i].module_name))
+                       return i+1;
+       }
+
+       return -EINVAL;
+}
+
+/**
+ * vpbe_g_cropcap - Get crop capabilities of the display
+ * @vpbe_dev - vpbe device ptr
+ * @cropcap - cropcap is a ptr to struct v4l2_cropcap
+ *
+ * Update the crop capabilities in crop cap for current
+ * mode
+ */
+static int vpbe_g_cropcap(struct vpbe_device *vpbe_dev,
+                         struct v4l2_cropcap *cropcap)
+{
+       if (NULL == cropcap)
+               return -EINVAL;
+       cropcap->bounds.left = 0;
+       cropcap->bounds.top = 0;
+       cropcap->bounds.width = vpbe_dev->current_timings.xres;
+       cropcap->bounds.height = vpbe_dev->current_timings.yres;
+       cropcap->defrect = cropcap->bounds;
+
+       return 0;
+}
+
+/**
+ * vpbe_enum_outputs - enumerate outputs
+ * @vpbe_dev - vpbe device ptr
+ * @output - ptr to v4l2_output structure
+ *
+ * Enumerates the outputs available at the vpbe display
+ * returns the status, -EINVAL if end of output list
+ */
+static int vpbe_enum_outputs(struct vpbe_device *vpbe_dev,
+                            struct v4l2_output *output)
+{
+       struct vpbe_config *cfg = vpbe_dev->cfg;
+       int temp_index = output->index;
+
+       if (temp_index >= cfg->num_outputs)
+               return -EINVAL;
+
+       *output = cfg->outputs[temp_index].output;
+       output->index = temp_index;
+
+       return 0;
+}
+
+static int vpbe_get_mode_info(struct vpbe_device *vpbe_dev, char *mode)
+{
+       struct vpbe_config *cfg = vpbe_dev->cfg;
+       struct vpbe_enc_mode_info var;
+       int curr_output = vpbe_dev->current_out_index;
+       int i;
+
+       if (NULL == mode)
+               return -EINVAL;
+
+       for (i = 0; i < cfg->outputs[curr_output].num_modes; i++) {
+               var = cfg->outputs[curr_output].modes[i];
+               if (!strcmp(mode, var.name)) {
+                       vpbe_dev->current_timings = var;
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int vpbe_get_current_mode_info(struct vpbe_device *vpbe_dev,
+                                     struct vpbe_enc_mode_info *mode_info)
+{
+       if (NULL == mode_info)
+               return -EINVAL;
+
+       *mode_info = vpbe_dev->current_timings;
+
+       return 0;
+}
+
+static int vpbe_get_dv_preset_info(struct vpbe_device *vpbe_dev,
+                                  unsigned int dv_preset)
+{
+       struct vpbe_config *cfg = vpbe_dev->cfg;
+       struct vpbe_enc_mode_info var;
+       int curr_output = vpbe_dev->current_out_index;
+       int i;
+
+       for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) {
+               var = cfg->outputs[curr_output].modes[i];
+               if ((var.timings_type & VPBE_ENC_DV_PRESET) &&
+                 (var.timings.dv_preset == dv_preset)) {
+                       vpbe_dev->current_timings = var;
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+/* Get std by std id */
+static int vpbe_get_std_info(struct vpbe_device *vpbe_dev,
+                            v4l2_std_id std_id)
+{
+       struct vpbe_config *cfg = vpbe_dev->cfg;
+       struct vpbe_enc_mode_info var;
+       int curr_output = vpbe_dev->current_out_index;
+       int i;
+
+       for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) {
+               var = cfg->outputs[curr_output].modes[i];
+               if ((var.timings_type & VPBE_ENC_STD) &&
+                 (var.timings.std_id & std_id)) {
+                       vpbe_dev->current_timings = var;
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int vpbe_get_std_info_by_name(struct vpbe_device *vpbe_dev,
+                               char *std_name)
+{
+       struct vpbe_config *cfg = vpbe_dev->cfg;
+       struct vpbe_enc_mode_info var;
+       int curr_output = vpbe_dev->current_out_index;
+       int i;
+
+       for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) {
+               var = cfg->outputs[curr_output].modes[i];
+               if (!strcmp(var.name, std_name)) {
+                       vpbe_dev->current_timings = var;
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+/**
+ * vpbe_set_output - Set output
+ * @vpbe_dev - vpbe device ptr
+ * @index - index of output
+ *
+ * Set vpbe output to the output specified by the index
+ */
+static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index)
+{
+       struct encoder_config_info *curr_enc_info =
+                       vpbe_current_encoder_info(vpbe_dev);
+       struct vpbe_config *cfg = vpbe_dev->cfg;
+       int enc_out_index;
+       int sd_index;
+       int ret = 0;
+
+       if (index >= cfg->num_outputs)
+               return -EINVAL;
+
+       mutex_lock(&vpbe_dev->lock);
+
+       sd_index = vpbe_dev->current_sd_index;
+       enc_out_index = cfg->outputs[index].output.index;
+       /*
+        * Currently we switch the encoder based on output selected
+        * by the application. If media controller is implemented later
+        * there is will be an API added to setup_link between venc
+        * and external encoder. So in that case below comparison always
+        * match and encoder will not be switched. But if application
+        * chose not to use media controller, then this provides current
+        * way of switching encoder at the venc output.
+        */
+       if (strcmp(curr_enc_info->module_name,
+                  cfg->outputs[index].subdev_name)) {
+               /* Need to switch the encoder at the output */
+               sd_index = vpbe_find_encoder_sd_index(cfg, index);
+               if (sd_index < 0) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               if (ret)
+                       goto out;
+       }
+
+       /* Set output at the encoder */
+       ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video,
+                                      s_routing, 0, enc_out_index, 0);
+       if (ret)
+               goto out;
+
+       /*
+        * It is assumed that venc or extenal encoder will set a default
+        * mode in the sub device. For external encoder or LCD pannel output,
+        * we also need to set up the lcd port for the required mode. So setup
+        * the lcd port for the default mode that is configured in the board
+        * arch/arm/mach-davinci/board-dm355-evm.setup file for the external
+        * encoder.
+        */
+       ret = vpbe_get_mode_info(vpbe_dev,
+                                cfg->outputs[index].default_mode);
+       if (!ret) {
+               struct osd_state *osd_device = vpbe_dev->osd_device;
+
+               osd_device->ops.set_left_margin(osd_device,
+                       vpbe_dev->current_timings.left_margin);
+               osd_device->ops.set_top_margin(osd_device,
+               vpbe_dev->current_timings.upper_margin);
+               vpbe_dev->current_sd_index = sd_index;
+               vpbe_dev->current_out_index = index;
+       }
+out:
+       mutex_unlock(&vpbe_dev->lock);
+       return ret;
+}
+
+static int vpbe_set_default_output(struct vpbe_device *vpbe_dev)
+{
+       struct vpbe_config *cfg = vpbe_dev->cfg;
+       int ret = 0;
+       int i;
+
+       for (i = 0; i < cfg->num_outputs; i++) {
+               if (!strcmp(def_output,
+                           cfg->outputs[i].output.name)) {
+                       ret = vpbe_set_output(vpbe_dev, i);
+                       if (!ret)
+                               vpbe_dev->current_out_index = i;
+                       return ret;
+               }
+       }
+       return ret;
+}
+
+/**
+ * vpbe_get_output - Get output
+ * @vpbe_dev - vpbe device ptr
+ *
+ * return current vpbe output to the the index
+ */
+static unsigned int vpbe_get_output(struct vpbe_device *vpbe_dev)
+{
+       return vpbe_dev->current_out_index;
+}
+
+/**
+ * vpbe_s_dv_preset - Set the given preset timings in the encoder
+ *
+ * Sets the preset if supported by the current encoder. Return the status.
+ * 0 - success & -EINVAL on error
+ */
+static int vpbe_s_dv_preset(struct vpbe_device *vpbe_dev,
+                    struct v4l2_dv_preset *dv_preset)
+{
+       struct vpbe_config *cfg = vpbe_dev->cfg;
+       int out_index = vpbe_dev->current_out_index;
+       int sd_index = vpbe_dev->current_sd_index;
+       int ret;
+
+
+       if (!(cfg->outputs[out_index].output.capabilities &
+           V4L2_OUT_CAP_PRESETS))
+               return -EINVAL;
+
+       ret = vpbe_get_dv_preset_info(vpbe_dev, dv_preset->preset);
+
+       if (ret)
+               return ret;
+
+       mutex_lock(&vpbe_dev->lock);
+
+
+       ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video,
+                                       s_dv_preset, dv_preset);
+       /* set the lcd controller output for the given mode */
+       if (!ret) {
+               struct osd_state *osd_device = vpbe_dev->osd_device;
+
+               osd_device->ops.set_left_margin(osd_device,
+               vpbe_dev->current_timings.left_margin);
+               osd_device->ops.set_top_margin(osd_device,
+               vpbe_dev->current_timings.upper_margin);
+       }
+       mutex_unlock(&vpbe_dev->lock);
+
+       return ret;
+}
+
+/**
+ * vpbe_g_dv_preset - Get the preset in the current encoder
+ *
+ * Get the preset in the current encoder. Return the status. 0 - success
+ * -EINVAL on error
+ */
+static int vpbe_g_dv_preset(struct vpbe_device *vpbe_dev,
+                    struct v4l2_dv_preset *dv_preset)
+{
+       if (vpbe_dev->current_timings.timings_type &
+         VPBE_ENC_DV_PRESET) {
+               dv_preset->preset = vpbe_dev->current_timings.timings.dv_preset;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+/**
+ * vpbe_enum_dv_presets - Enumerate the dv presets in the current encoder
+ *
+ * Get the preset in the current encoder. Return the status. 0 - success
+ * -EINVAL on error
+ */
+static int vpbe_enum_dv_presets(struct vpbe_device *vpbe_dev,
+                        struct v4l2_dv_enum_preset *preset_info)
+{
+       struct vpbe_config *cfg = vpbe_dev->cfg;
+       int out_index = vpbe_dev->current_out_index;
+       struct vpbe_output *output = &cfg->outputs[out_index];
+       int j = 0;
+       int i;
+
+       if (!(output->output.capabilities & V4L2_OUT_CAP_PRESETS))
+               return -EINVAL;
+
+       for (i = 0; i < output->num_modes; i++) {
+               if (output->modes[i].timings_type == VPBE_ENC_DV_PRESET) {
+                       if (j == preset_info->index)
+                               break;
+                       j++;
+               }
+       }
+
+       if (i == output->num_modes)
+               return -EINVAL;
+
+       return v4l_fill_dv_preset_info(output->modes[i].timings.dv_preset,
+                                       preset_info);
+}
+
+/**
+ * vpbe_s_std - Set the given standard in the encoder
+ *
+ * Sets the standard if supported by the current encoder. Return the status.
+ * 0 - success & -EINVAL on error
+ */
+static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id)
+{
+       struct vpbe_config *cfg = vpbe_dev->cfg;
+       int out_index = vpbe_dev->current_out_index;
+       int sd_index = vpbe_dev->current_sd_index;
+       int ret;
+
+       if (!(cfg->outputs[out_index].output.capabilities &
+               V4L2_OUT_CAP_STD))
+               return -EINVAL;
+
+       ret = vpbe_get_std_info(vpbe_dev, *std_id);
+       if (ret)
+               return ret;
+
+       mutex_lock(&vpbe_dev->lock);
+
+       ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video,
+                              s_std_output, *std_id);
+       /* set the lcd controller output for the given mode */
+       if (!ret) {
+               struct osd_state *osd_device = vpbe_dev->osd_device;
+
+               osd_device->ops.set_left_margin(osd_device,
+               vpbe_dev->current_timings.left_margin);
+               osd_device->ops.set_top_margin(osd_device,
+               vpbe_dev->current_timings.upper_margin);
+       }
+       mutex_unlock(&vpbe_dev->lock);
+
+       return ret;
+}
+
+/**
+ * vpbe_g_std - Get the standard in the current encoder
+ *
+ * Get the standard in the current encoder. Return the status. 0 - success
+ * -EINVAL on error
+ */
+static int vpbe_g_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id)
+{
+       struct vpbe_enc_mode_info cur_timings = vpbe_dev->current_timings;
+
+       if (cur_timings.timings_type & VPBE_ENC_STD) {
+               *std_id = cur_timings.timings.std_id;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+/**
+ * vpbe_set_mode - Set mode in the current encoder using mode info
+ *
+ * Use the mode string to decide what timings to set in the encoder
+ * This is typically useful when fbset command is used to change the current
+ * timings by specifying a string to indicate the timings.
+ */
+static int vpbe_set_mode(struct vpbe_device *vpbe_dev,
+                        struct vpbe_enc_mode_info *mode_info)
+{
+       struct vpbe_enc_mode_info *preset_mode = NULL;
+       struct vpbe_config *cfg = vpbe_dev->cfg;
+       struct v4l2_dv_preset dv_preset;
+       struct osd_state *osd_device;
+       int out_index = vpbe_dev->current_out_index;
+       int ret = 0;
+       int i;
+
+       if ((NULL == mode_info) || (NULL == mode_info->name))
+               return -EINVAL;
+
+       for (i = 0; i < cfg->outputs[out_index].num_modes; i++) {
+               if (!strcmp(mode_info->name,
+                    cfg->outputs[out_index].modes[i].name)) {
+                       preset_mode = &cfg->outputs[out_index].modes[i];
+                       /*
+                        * it may be one of the 3 timings type. Check and
+                        * invoke right API
+                        */
+                       if (preset_mode->timings_type & VPBE_ENC_STD)
+                               return vpbe_s_std(vpbe_dev,
+                                                &preset_mode->timings.std_id);
+                       if (preset_mode->timings_type & VPBE_ENC_DV_PRESET) {
+                               dv_preset.preset =
+                                       preset_mode->timings.dv_preset;
+                               return vpbe_s_dv_preset(vpbe_dev, &dv_preset);
+                       }
+               }
+       }
+
+       /* Only custom timing should reach here */
+       if (preset_mode == NULL)
+               return -EINVAL;
+
+       mutex_lock(&vpbe_dev->lock);
+
+       osd_device = vpbe_dev->osd_device;
+       vpbe_dev->current_timings = *preset_mode;
+       osd_device->ops.set_left_margin(osd_device,
+               vpbe_dev->current_timings.left_margin);
+       osd_device->ops.set_top_margin(osd_device,
+               vpbe_dev->current_timings.upper_margin);
+
+       mutex_unlock(&vpbe_dev->lock);
+
+       return ret;
+}
+
+static int vpbe_set_default_mode(struct vpbe_device *vpbe_dev)
+{
+       int ret;
+
+       ret = vpbe_get_std_info_by_name(vpbe_dev, def_mode);
+       if (ret)
+               return ret;
+
+       /* set the default mode in the encoder */
+       return vpbe_set_mode(vpbe_dev, &vpbe_dev->current_timings);
+}
+
+static int platform_device_get(struct device *dev, void *data)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct vpbe_device *vpbe_dev = data;
+
+       if (strcmp("vpbe-osd", pdev->name) == 0)
+               vpbe_dev->osd_device = platform_get_drvdata(pdev);
+
+       return 0;
+}
+
+/**
+ * vpbe_initialize() - Initialize the vpbe display controller
+ * @vpbe_dev - vpbe device ptr
+ *
+ * Master frame buffer device drivers calls this to initialize vpbe
+ * display controller. This will then registers v4l2 device and the sub
+ * devices and sets a current encoder sub device for display. v4l2 display
+ * device driver is the master and frame buffer display device driver is
+ * the slave. Frame buffer display driver checks the initialized during
+ * probe and exit if not initialized. Returns status.
+ */
+static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev)
+{
+       struct encoder_config_info *enc_info;
+       struct v4l2_subdev **enc_subdev;
+       struct osd_state *osd_device;
+       struct i2c_adapter *i2c_adap;
+       int output_index;
+       int num_encoders;
+       int ret = 0;
+       int err;
+       int i;
+
+       /*
+        * v4l2 abd FBDev frame buffer devices will get the vpbe_dev pointer
+        * from the platform device by iteration of platform drivers and
+        * matching with device name
+        */
+       if (NULL == vpbe_dev || NULL == dev) {
+               printk(KERN_ERR "Null device pointers.\n");
+               return -ENODEV;
+       }
+
+       if (vpbe_dev->initialized)
+               return 0;
+
+       mutex_lock(&vpbe_dev->lock);
+
+       if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) {
+               /* We have dac clock available for platform */
+               vpbe_dev->dac_clk = clk_get(vpbe_dev->pdev, "vpss_dac");
+               if (IS_ERR(vpbe_dev->dac_clk)) {
+                       ret =  PTR_ERR(vpbe_dev->dac_clk);
+                       goto vpbe_unlock;
+               }
+               if (clk_enable(vpbe_dev->dac_clk)) {
+                       ret =  -ENODEV;
+                       goto vpbe_unlock;
+               }
+       }
+
+       /* first enable vpss clocks */
+       vpss_enable_clock(VPSS_VPBE_CLOCK, 1);
+
+       /* First register a v4l2 device */
+       ret = v4l2_device_register(dev, &vpbe_dev->v4l2_dev);
+       if (ret) {
+               v4l2_err(dev->driver,
+                       "Unable to register v4l2 device.\n");
+               goto vpbe_fail_clock;
+       }
+       v4l2_info(&vpbe_dev->v4l2_dev, "vpbe v4l2 device registered\n");
+
+       err = bus_for_each_dev(&platform_bus_type, NULL, vpbe_dev,
+                              platform_device_get);
+       if (err < 0)
+               return err;
+
+       vpbe_dev->venc = venc_sub_dev_init(&vpbe_dev->v4l2_dev,
+                                          vpbe_dev->cfg->venc.module_name);
+       /* register venc sub device */
+       if (vpbe_dev->venc == NULL) {
+               v4l2_err(&vpbe_dev->v4l2_dev,
+                       "vpbe unable to init venc sub device\n");
+               ret = -ENODEV;
+               goto vpbe_fail_v4l2_device;
+       }
+       /* initialize osd device */
+       osd_device = vpbe_dev->osd_device;
+
+       if (NULL != osd_device->ops.initialize) {
+               err = osd_device->ops.initialize(osd_device);
+               if (err) {
+                       v4l2_err(&vpbe_dev->v4l2_dev,
+                                "unable to initialize the OSD device");
+                       err = -ENOMEM;
+                       goto vpbe_fail_v4l2_device;
+               }
+       }
+
+       /*
+        * Register any external encoders that are configured. At index 0 we
+        * store venc sd index.
+        */
+       num_encoders = vpbe_dev->cfg->num_ext_encoders + 1;
+       vpbe_dev->encoders = kmalloc(
+                               sizeof(struct v4l2_subdev *)*num_encoders,
+                               GFP_KERNEL);
+       if (NULL == vpbe_dev->encoders) {
+               v4l2_err(&vpbe_dev->v4l2_dev,
+                       "unable to allocate memory for encoders sub devices");
+               ret = -ENOMEM;
+               goto vpbe_fail_v4l2_device;
+       }
+
+       i2c_adap = i2c_get_adapter(vpbe_dev->cfg->i2c_adapter_id);
+       for (i = 0; i < (vpbe_dev->cfg->num_ext_encoders + 1); i++) {
+               if (i == 0) {
+                       /* venc is at index 0 */
+                       enc_subdev = &vpbe_dev->encoders[i];
+                       *enc_subdev = vpbe_dev->venc;
+                       continue;
+               }
+               enc_info = &vpbe_dev->cfg->ext_encoders[i];
+               if (enc_info->is_i2c) {
+                       enc_subdev = &vpbe_dev->encoders[i];
+                       *enc_subdev = v4l2_i2c_new_subdev_board(
+                                               &vpbe_dev->v4l2_dev, i2c_adap,
+                                               &enc_info->board_info, NULL);
+                       if (*enc_subdev)
+                               v4l2_info(&vpbe_dev->v4l2_dev,
+                                         "v4l2 sub device %s registered\n",
+                                         enc_info->module_name);
+                       else {
+                               v4l2_err(&vpbe_dev->v4l2_dev, "encoder %s"
+                                        " failed to register",
+                                        enc_info->module_name);
+                               ret = -ENODEV;
+                               goto vpbe_fail_sd_register;
+                       }
+               } else
+                       v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c encoders"
+                                " currently not supported");
+       }
+
+       /* set the current encoder and output to that of venc by default */
+       vpbe_dev->current_sd_index = 0;
+       vpbe_dev->current_out_index = 0;
+       output_index = 0;
+
+       mutex_unlock(&vpbe_dev->lock);
+
+       printk(KERN_NOTICE "Setting default output to %s\n", def_output);
+       ret = vpbe_set_default_output(vpbe_dev);
+       if (ret) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default output %s",
+                        def_output);
+               return ret;
+       }
+
+       printk(KERN_NOTICE "Setting default mode to %s\n", def_mode);
+       ret = vpbe_set_default_mode(vpbe_dev);
+       if (ret) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default mode %s",
+                        def_mode);
+               return ret;
+       }
+       vpbe_dev->initialized = 1;
+       /* TBD handling of bootargs for default output and mode */
+       return 0;
+
+vpbe_fail_sd_register:
+       kfree(vpbe_dev->encoders);
+vpbe_fail_v4l2_device:
+       v4l2_device_unregister(&vpbe_dev->v4l2_dev);
+vpbe_fail_clock:
+       if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0)
+               clk_put(vpbe_dev->dac_clk);
+vpbe_unlock:
+       mutex_unlock(&vpbe_dev->lock);
+       return ret;
+}
+
+/**
+ * vpbe_deinitialize() - de-initialize the vpbe display controller
+ * @dev - Master and slave device ptr
+ *
+ * vpbe_master and slave frame buffer devices calls this to de-initialize
+ * the display controller. It is called when master and slave device
+ * driver modules are removed and no longer requires the display controller.
+ */
+static void vpbe_deinitialize(struct device *dev, struct vpbe_device *vpbe_dev)
+{
+       v4l2_device_unregister(&vpbe_dev->v4l2_dev);
+       if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0)
+               clk_put(vpbe_dev->dac_clk);
+
+       kfree(vpbe_dev->encoders);
+       vpbe_dev->initialized = 0;
+       /* disable vpss clocks */
+       vpss_enable_clock(VPSS_VPBE_CLOCK, 0);
+}
+
+static struct vpbe_device_ops vpbe_dev_ops = {
+       .g_cropcap = vpbe_g_cropcap,
+       .enum_outputs = vpbe_enum_outputs,
+       .set_output = vpbe_set_output,
+       .get_output = vpbe_get_output,
+       .s_dv_preset = vpbe_s_dv_preset,
+       .g_dv_preset = vpbe_g_dv_preset,
+       .enum_dv_presets = vpbe_enum_dv_presets,
+       .s_std = vpbe_s_std,
+       .g_std = vpbe_g_std,
+       .initialize = vpbe_initialize,
+       .deinitialize = vpbe_deinitialize,
+       .get_mode_info = vpbe_get_current_mode_info,
+       .set_mode = vpbe_set_mode,
+};
+
+static __devinit int vpbe_probe(struct platform_device *pdev)
+{
+       struct vpbe_device *vpbe_dev;
+       struct vpbe_config *cfg;
+       int ret = -EINVAL;
+
+       if (pdev->dev.platform_data == NULL) {
+               v4l2_err(pdev->dev.driver, "No platform data\n");
+               return -ENODEV;
+       }
+       cfg = pdev->dev.platform_data;
+
+       if (!cfg->module_name[0] ||
+           !cfg->osd.module_name[0] ||
+           !cfg->venc.module_name[0]) {
+               v4l2_err(pdev->dev.driver, "vpbe display module names not"
+                        " defined\n");
+               return ret;
+       }
+
+       vpbe_dev = kzalloc(sizeof(*vpbe_dev), GFP_KERNEL);
+       if (vpbe_dev == NULL) {
+               v4l2_err(pdev->dev.driver, "Unable to allocate memory"
+                        " for vpbe_device\n");
+               return -ENOMEM;
+       }
+       vpbe_dev->cfg = cfg;
+       vpbe_dev->ops = vpbe_dev_ops;
+       vpbe_dev->pdev = &pdev->dev;
+
+       if (cfg->outputs->num_modes > 0)
+               vpbe_dev->current_timings = vpbe_dev->cfg->outputs[0].modes[0];
+       else
+               return -ENODEV;
+
+       /* set the driver data in platform device */
+       platform_set_drvdata(pdev, vpbe_dev);
+       mutex_init(&vpbe_dev->lock);
+
+       return 0;
+}
+
+static int vpbe_remove(struct platform_device *device)
+{
+       struct vpbe_device *vpbe_dev = platform_get_drvdata(device);
+
+       kfree(vpbe_dev);
+
+       return 0;
+}
+
+static struct platform_driver vpbe_driver = {
+       .driver = {
+               .name   = "vpbe_controller",
+               .owner  = THIS_MODULE,
+       },
+       .probe = vpbe_probe,
+       .remove = vpbe_remove,
+};
+
+/**
+ * vpbe_init: initialize the vpbe driver
+ *
+ * This function registers device and driver to the kernel
+ */
+static __init int vpbe_init(void)
+{
+       return platform_driver_register(&vpbe_driver);
+}
+
+/**
+ * vpbe_cleanup : cleanup function for vpbe driver
+ *
+ * This will un-registers the device and driver to the kernel
+ */
+static void vpbe_cleanup(void)
+{
+       platform_driver_unregister(&vpbe_driver);
+}
+
+/* Function for module initialization and cleanup */
+module_init(vpbe_init);
+module_exit(vpbe_cleanup);
diff --git a/drivers/media/video/davinci/vpbe_display.c b/drivers/media/video/davinci/vpbe_display.c
new file mode 100644 (file)
index 0000000..7f1d83a
--- /dev/null
@@ -0,0 +1,1860 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/wait.h>
+#include <linux/time.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+
+#include <asm/pgtable.h>
+#include <mach/cputype.h>
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/davinci/vpbe_display.h>
+#include <media/davinci/vpbe_types.h>
+#include <media/davinci/vpbe.h>
+#include <media/davinci/vpbe_venc.h>
+#include <media/davinci/vpbe_osd.h>
+#include "vpbe_venc_regs.h"
+
+#define VPBE_DISPLAY_DRIVER "vpbe-v4l2"
+
+static int debug;
+
+#define VPBE_DISPLAY_SD_BUF_SIZE (720*576*2)
+#define VPBE_DEFAULT_NUM_BUFS 3
+
+module_param(debug, int, 0644);
+
+static int venc_is_second_field(struct vpbe_display *disp_dev)
+{
+       struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+       int ret;
+       int val;
+
+       ret = v4l2_subdev_call(vpbe_dev->venc,
+                              core,
+                              ioctl,
+                              VENC_GET_FLD,
+                              &val);
+       if (ret < 0) {
+               v4l2_err(&vpbe_dev->v4l2_dev,
+                        "Error in getting Field ID 0\n");
+       }
+       return val;
+}
+
+static void vpbe_isr_even_field(struct vpbe_display *disp_obj,
+                               struct vpbe_layer *layer)
+{
+       struct timespec timevalue;
+
+       if (layer->cur_frm == layer->next_frm)
+               return;
+       ktime_get_ts(&timevalue);
+       layer->cur_frm->ts.tv_sec = timevalue.tv_sec;
+       layer->cur_frm->ts.tv_usec = timevalue.tv_nsec / NSEC_PER_USEC;
+       layer->cur_frm->state = VIDEOBUF_DONE;
+       wake_up_interruptible(&layer->cur_frm->done);
+       /* Make cur_frm pointing to next_frm */
+       layer->cur_frm = layer->next_frm;
+}
+
+static void vpbe_isr_odd_field(struct vpbe_display *disp_obj,
+                               struct vpbe_layer *layer)
+{
+       struct osd_state *osd_device = disp_obj->osd_device;
+       unsigned long addr;
+
+       spin_lock(&disp_obj->dma_queue_lock);
+       if (list_empty(&layer->dma_queue) ||
+               (layer->cur_frm != layer->next_frm)) {
+               spin_unlock(&disp_obj->dma_queue_lock);
+               return;
+       }
+       /*
+        * one field is displayed configure
+        * the next frame if it is available
+        * otherwise hold on current frame
+        * Get next from the buffer queue
+        */
+       layer->next_frm = list_entry(
+                               layer->dma_queue.next,
+                               struct  videobuf_buffer,
+                               queue);
+       /* Remove that from the buffer queue */
+       list_del(&layer->next_frm->queue);
+       spin_unlock(&disp_obj->dma_queue_lock);
+       /* Mark state of the frame to active */
+       layer->next_frm->state = VIDEOBUF_ACTIVE;
+       addr = videobuf_to_dma_contig(layer->next_frm);
+       osd_device->ops.start_layer(osd_device,
+                       layer->layer_info.id,
+                       addr,
+                       disp_obj->cbcr_ofst);
+}
+
+/* interrupt service routine */
+static irqreturn_t venc_isr(int irq, void *arg)
+{
+       struct vpbe_display *disp_dev = (struct vpbe_display *)arg;
+       struct vpbe_layer *layer;
+       static unsigned last_event;
+       unsigned event = 0;
+       int fid;
+       int i;
+
+       if ((NULL == arg) || (NULL == disp_dev->dev[0]))
+               return IRQ_HANDLED;
+
+       if (venc_is_second_field(disp_dev))
+               event |= VENC_SECOND_FIELD;
+       else
+               event |= VENC_FIRST_FIELD;
+
+       if (event == (last_event & ~VENC_END_OF_FRAME)) {
+               /*
+               * If the display is non-interlaced, then we need to flag the
+               * end-of-frame event at every interrupt regardless of the
+               * value of the FIDST bit.  We can conclude that the display is
+               * non-interlaced if the value of the FIDST bit is unchanged
+               * from the previous interrupt.
+               */
+               event |= VENC_END_OF_FRAME;
+       } else if (event == VENC_SECOND_FIELD) {
+               /* end-of-frame for interlaced display */
+               event |= VENC_END_OF_FRAME;
+       }
+       last_event = event;
+
+       for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
+               layer = disp_dev->dev[i];
+               /* If streaming is started in this layer */
+               if (!layer->started)
+                       continue;
+
+               if (layer->layer_first_int) {
+                       layer->layer_first_int = 0;
+                       continue;
+               }
+               /* Check the field format */
+               if ((V4L2_FIELD_NONE == layer->pix_fmt.field) &&
+                       (event & VENC_END_OF_FRAME)) {
+                       /* Progressive mode */
+
+                       vpbe_isr_even_field(disp_dev, layer);
+                       vpbe_isr_odd_field(disp_dev, layer);
+               } else {
+               /* Interlaced mode */
+
+                       layer->field_id ^= 1;
+                       if (event & VENC_FIRST_FIELD)
+                               fid = 0;
+                       else
+                               fid = 1;
+
+                       /*
+                       * If field id does not match with store
+                       * field id
+                       */
+                       if (fid != layer->field_id) {
+                               /* Make them in sync */
+                               layer->field_id = fid;
+                               continue;
+                       }
+                       /*
+                       * device field id and local field id are
+                       * in sync. If this is even field
+                       */
+                       if (0 == fid)
+                               vpbe_isr_even_field(disp_dev, layer);
+                       else  /* odd field */
+                               vpbe_isr_odd_field(disp_dev, layer);
+               }
+       }
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * vpbe_buffer_prepare()
+ * This is the callback function called from videobuf_qbuf() function
+ * the buffer is prepared and user space virtual address is converted into
+ * physical address
+ */
+static int vpbe_buffer_prepare(struct videobuf_queue *q,
+                                 struct videobuf_buffer *vb,
+                                 enum v4l2_field field)
+{
+       struct vpbe_fh *fh = q->priv_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       unsigned long addr;
+       int ret;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+                               "vpbe_buffer_prepare\n");
+
+       /* If buffer is not initialized, initialize it */
+       if (VIDEOBUF_NEEDS_INIT == vb->state) {
+               vb->width = layer->pix_fmt.width;
+               vb->height = layer->pix_fmt.height;
+               vb->size = layer->pix_fmt.sizeimage;
+               vb->field = field;
+
+               ret = videobuf_iolock(q, vb, NULL);
+               if (ret < 0) {
+                       v4l2_err(&vpbe_dev->v4l2_dev, "Failed to map \
+                               user address\n");
+                       return -EINVAL;
+               }
+
+               addr = videobuf_to_dma_contig(vb);
+
+               if (q->streaming) {
+                       if (!IS_ALIGNED(addr, 8)) {
+                               v4l2_err(&vpbe_dev->v4l2_dev,
+                                       "buffer_prepare:offset is \
+                                       not aligned to 32 bytes\n");
+                               return -EINVAL;
+                       }
+               }
+               vb->state = VIDEOBUF_PREPARED;
+       }
+       return 0;
+}
+
+/*
+ * vpbe_buffer_setup()
+ * This function allocates memory for the buffers
+ */
+static int vpbe_buffer_setup(struct videobuf_queue *q,
+                               unsigned int *count,
+                               unsigned int *size)
+{
+       /* Get the file handle object and layer object */
+       struct vpbe_fh *fh = q->priv_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_buffer_setup\n");
+
+       *size = layer->pix_fmt.sizeimage;
+
+       /* Store number of buffers allocated in numbuffer member */
+       if (*count < VPBE_DEFAULT_NUM_BUFS)
+               *count = layer->numbuffers = VPBE_DEFAULT_NUM_BUFS;
+
+       return 0;
+}
+
+/*
+ * vpbe_buffer_queue()
+ * This function adds the buffer to DMA queue
+ */
+static void vpbe_buffer_queue(struct videobuf_queue *q,
+                                struct videobuf_buffer *vb)
+{
+       /* Get the file handle object and layer object */
+       struct vpbe_fh *fh = q->priv_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_display *disp = fh->disp_dev;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       unsigned long flags;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+                       "vpbe_buffer_queue\n");
+
+       /* add the buffer to the DMA queue */
+       spin_lock_irqsave(&disp->dma_queue_lock, flags);
+       list_add_tail(&vb->queue, &layer->dma_queue);
+       spin_unlock_irqrestore(&disp->dma_queue_lock, flags);
+       /* Change state of the buffer */
+       vb->state = VIDEOBUF_QUEUED;
+}
+
+/*
+ * vpbe_buffer_release()
+ * This function is called from the videobuf layer to free memory allocated to
+ * the buffers
+ */
+static void vpbe_buffer_release(struct videobuf_queue *q,
+                                  struct videobuf_buffer *vb)
+{
+       /* Get the file handle object and layer object */
+       struct vpbe_fh *fh = q->priv_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+                       "vpbe_buffer_release\n");
+
+       if (V4L2_MEMORY_USERPTR != layer->memory)
+               videobuf_dma_contig_free(q, vb);
+
+       vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static struct videobuf_queue_ops video_qops = {
+       .buf_setup = vpbe_buffer_setup,
+       .buf_prepare = vpbe_buffer_prepare,
+       .buf_queue = vpbe_buffer_queue,
+       .buf_release = vpbe_buffer_release,
+};
+
+static
+struct vpbe_layer*
+_vpbe_display_get_other_win_layer(struct vpbe_display *disp_dev,
+                       struct vpbe_layer *layer)
+{
+       enum vpbe_display_device_id thiswin, otherwin;
+       thiswin = layer->device_id;
+
+       otherwin = (thiswin == VPBE_DISPLAY_DEVICE_0) ?
+       VPBE_DISPLAY_DEVICE_1 : VPBE_DISPLAY_DEVICE_0;
+       return disp_dev->dev[otherwin];
+}
+
+static int vpbe_set_osd_display_params(struct vpbe_display *disp_dev,
+                       struct vpbe_layer *layer)
+{
+       struct osd_layer_config *cfg  = &layer->layer_info.config;
+       struct osd_state *osd_device = disp_dev->osd_device;
+       struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+       unsigned long addr;
+       int ret;
+
+       addr = videobuf_to_dma_contig(layer->cur_frm);
+       /* Set address in the display registers */
+       osd_device->ops.start_layer(osd_device,
+                                   layer->layer_info.id,
+                                   addr,
+                                   disp_dev->cbcr_ofst);
+
+       ret = osd_device->ops.enable_layer(osd_device,
+                               layer->layer_info.id, 0);
+       if (ret < 0) {
+               v4l2_err(&vpbe_dev->v4l2_dev,
+                       "Error in enabling osd window layer 0\n");
+               return -1;
+       }
+
+       /* Enable the window */
+       layer->layer_info.enable = 1;
+       if (cfg->pixfmt == PIXFMT_NV12) {
+               struct vpbe_layer *otherlayer =
+                       _vpbe_display_get_other_win_layer(disp_dev, layer);
+
+               ret = osd_device->ops.enable_layer(osd_device,
+                               otherlayer->layer_info.id, 1);
+               if (ret < 0) {
+                       v4l2_err(&vpbe_dev->v4l2_dev,
+                               "Error in enabling osd window layer 1\n");
+                       return -1;
+               }
+               otherlayer->layer_info.enable = 1;
+       }
+       return 0;
+}
+
+static void
+vpbe_disp_calculate_scale_factor(struct vpbe_display *disp_dev,
+                       struct vpbe_layer *layer,
+                       int expected_xsize, int expected_ysize)
+{
+       struct display_layer_info *layer_info = &layer->layer_info;
+       struct v4l2_pix_format *pixfmt = &layer->pix_fmt;
+       struct osd_layer_config *cfg  = &layer->layer_info.config;
+       struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+       int calculated_xsize;
+       int h_exp = 0;
+       int v_exp = 0;
+       int h_scale;
+       int v_scale;
+
+       v4l2_std_id standard_id = vpbe_dev->current_timings.timings.std_id;
+
+       /*
+        * Application initially set the image format. Current display
+        * size is obtained from the vpbe display controller. expected_xsize
+        * and expected_ysize are set through S_CROP ioctl. Based on this,
+        * driver will calculate the scale factors for vertical and
+        * horizontal direction so that the image is displayed scaled
+        * and expanded. Application uses expansion to display the image
+        * in a square pixel. Otherwise it is displayed using displays
+        * pixel aspect ratio.It is expected that application chooses
+        * the crop coordinates for cropped or scaled display. if crop
+        * size is less than the image size, it is displayed cropped or
+        * it is displayed scaled and/or expanded.
+        *
+        * to begin with, set the crop window same as expected. Later we
+        * will override with scaled window size
+        */
+
+       cfg->xsize = pixfmt->width;
+       cfg->ysize = pixfmt->height;
+       layer_info->h_zoom = ZOOM_X1;   /* no horizontal zoom */
+       layer_info->v_zoom = ZOOM_X1;   /* no horizontal zoom */
+       layer_info->h_exp = H_EXP_OFF;  /* no horizontal zoom */
+       layer_info->v_exp = V_EXP_OFF;  /* no horizontal zoom */
+
+       if (pixfmt->width < expected_xsize) {
+               h_scale = vpbe_dev->current_timings.xres / pixfmt->width;
+               if (h_scale < 2)
+                       h_scale = 1;
+               else if (h_scale >= 4)
+                       h_scale = 4;
+               else
+                       h_scale = 2;
+               cfg->xsize *= h_scale;
+               if (cfg->xsize < expected_xsize) {
+                       if ((standard_id & V4L2_STD_525_60) ||
+                       (standard_id & V4L2_STD_625_50)) {
+                               calculated_xsize = (cfg->xsize *
+                                       VPBE_DISPLAY_H_EXP_RATIO_N) /
+                                       VPBE_DISPLAY_H_EXP_RATIO_D;
+                               if (calculated_xsize <= expected_xsize) {
+                                       h_exp = 1;
+                                       cfg->xsize = calculated_xsize;
+                               }
+                       }
+               }
+               if (h_scale == 2)
+                       layer_info->h_zoom = ZOOM_X2;
+               else if (h_scale == 4)
+                       layer_info->h_zoom = ZOOM_X4;
+               if (h_exp)
+                       layer_info->h_exp = H_EXP_9_OVER_8;
+       } else {
+               /* no scaling, only cropping. Set display area to crop area */
+               cfg->xsize = expected_xsize;
+       }
+
+       if (pixfmt->height < expected_ysize) {
+               v_scale = expected_ysize / pixfmt->height;
+               if (v_scale < 2)
+                       v_scale = 1;
+               else if (v_scale >= 4)
+                       v_scale = 4;
+               else
+                       v_scale = 2;
+               cfg->ysize *= v_scale;
+               if (cfg->ysize < expected_ysize) {
+                       if ((standard_id & V4L2_STD_625_50)) {
+                               calculated_xsize = (cfg->ysize *
+                                       VPBE_DISPLAY_V_EXP_RATIO_N) /
+                                       VPBE_DISPLAY_V_EXP_RATIO_D;
+                               if (calculated_xsize <= expected_ysize) {
+                                       v_exp = 1;
+                                       cfg->ysize = calculated_xsize;
+                               }
+                       }
+               }
+               if (v_scale == 2)
+                       layer_info->v_zoom = ZOOM_X2;
+               else if (v_scale == 4)
+                       layer_info->v_zoom = ZOOM_X4;
+               if (v_exp)
+                       layer_info->h_exp = V_EXP_6_OVER_5;
+       } else {
+               /* no scaling, only cropping. Set display area to crop area */
+               cfg->ysize = expected_ysize;
+       }
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+               "crop display xsize = %d, ysize = %d\n",
+               cfg->xsize, cfg->ysize);
+}
+
+static void vpbe_disp_adj_position(struct vpbe_display *disp_dev,
+                       struct vpbe_layer *layer,
+                       int top, int left)
+{
+       struct osd_layer_config *cfg = &layer->layer_info.config;
+       struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+
+       cfg->xpos = min((unsigned int)left,
+                       vpbe_dev->current_timings.xres - cfg->xsize);
+       cfg->ypos = min((unsigned int)top,
+                       vpbe_dev->current_timings.yres - cfg->ysize);
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+               "new xpos = %d, ypos = %d\n",
+               cfg->xpos, cfg->ypos);
+}
+
+static void vpbe_disp_check_window_params(struct vpbe_display *disp_dev,
+                       struct v4l2_rect *c)
+{
+       struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+
+       if ((c->width == 0) ||
+         ((c->width + c->left) > vpbe_dev->current_timings.xres))
+               c->width = vpbe_dev->current_timings.xres - c->left;
+
+       if ((c->height == 0) || ((c->height + c->top) >
+         vpbe_dev->current_timings.yres))
+               c->height = vpbe_dev->current_timings.yres - c->top;
+
+       /* window height must be even for interlaced display */
+       if (vpbe_dev->current_timings.interlaced)
+               c->height &= (~0x01);
+
+}
+
+/**
+ * vpbe_try_format()
+ * If user application provides width and height, and have bytesperline set
+ * to zero, driver calculates bytesperline and sizeimage based on hardware
+ * limits.
+ */
+static int vpbe_try_format(struct vpbe_display *disp_dev,
+                       struct v4l2_pix_format *pixfmt, int check)
+{
+       struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+       int min_height = 1;
+       int min_width = 32;
+       int max_height;
+       int max_width;
+       int bpp;
+
+       if ((pixfmt->pixelformat != V4L2_PIX_FMT_UYVY) &&
+           (pixfmt->pixelformat != V4L2_PIX_FMT_NV12))
+               /* choose default as V4L2_PIX_FMT_UYVY */
+               pixfmt->pixelformat = V4L2_PIX_FMT_UYVY;
+
+       /* Check the field format */
+       if ((pixfmt->field != V4L2_FIELD_INTERLACED) &&
+               (pixfmt->field != V4L2_FIELD_NONE)) {
+               if (vpbe_dev->current_timings.interlaced)
+                       pixfmt->field = V4L2_FIELD_INTERLACED;
+               else
+                       pixfmt->field = V4L2_FIELD_NONE;
+       }
+
+       if (pixfmt->field == V4L2_FIELD_INTERLACED)
+               min_height = 2;
+
+       if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12)
+               bpp = 1;
+       else
+               bpp = 2;
+
+       max_width = vpbe_dev->current_timings.xres;
+       max_height = vpbe_dev->current_timings.yres;
+
+       min_width /= bpp;
+
+       if (!pixfmt->width || (pixfmt->width < min_width) ||
+               (pixfmt->width > max_width)) {
+               pixfmt->width = vpbe_dev->current_timings.xres;
+       }
+
+       if (!pixfmt->height || (pixfmt->height  < min_height) ||
+               (pixfmt->height  > max_height)) {
+               pixfmt->height = vpbe_dev->current_timings.yres;
+       }
+
+       if (pixfmt->bytesperline < (pixfmt->width * bpp))
+               pixfmt->bytesperline = pixfmt->width * bpp;
+
+       /* Make the bytesperline 32 byte aligned */
+       pixfmt->bytesperline = ((pixfmt->width * bpp + 31) & ~31);
+
+       if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12)
+               pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height +
+                               (pixfmt->bytesperline * pixfmt->height >> 1);
+       else
+               pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height;
+
+       return 0;
+}
+
+static int vpbe_display_g_priority(struct file *file, void *priv,
+                               enum v4l2_priority *p)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+
+       *p = v4l2_prio_max(&layer->prio);
+
+       return 0;
+}
+
+static int vpbe_display_s_priority(struct file *file, void *priv,
+                               enum v4l2_priority p)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       int ret;
+
+       ret = v4l2_prio_change(&layer->prio, &fh->prio, p);
+
+       return ret;
+}
+
+static int vpbe_display_querycap(struct file *file, void  *priv,
+                              struct v4l2_capability *cap)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+       cap->version = VPBE_DISPLAY_VERSION_CODE;
+       cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
+       strlcpy(cap->driver, VPBE_DISPLAY_DRIVER, sizeof(cap->driver));
+       strlcpy(cap->bus_info, "platform", sizeof(cap->bus_info));
+       strlcpy(cap->card, vpbe_dev->cfg->module_name, sizeof(cap->card));
+
+       return 0;
+}
+
+static int vpbe_display_s_crop(struct file *file, void *priv,
+                            struct v4l2_crop *crop)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_display *disp_dev = fh->disp_dev;
+       struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+       struct osd_layer_config *cfg = &layer->layer_info.config;
+       struct osd_state *osd_device = disp_dev->osd_device;
+       struct v4l2_rect *rect = &crop->c;
+       int ret;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+               "VIDIOC_S_CROP, layer id = %d\n", layer->device_id);
+
+       if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buf type\n");
+               return -EINVAL;
+       }
+
+       if (rect->top < 0)
+               rect->top = 0;
+       if (rect->left < 0)
+               rect->left = 0;
+
+       vpbe_disp_check_window_params(disp_dev, rect);
+
+       osd_device->ops.get_layer_config(osd_device,
+                       layer->layer_info.id, cfg);
+
+       vpbe_disp_calculate_scale_factor(disp_dev, layer,
+                                       rect->width,
+                                       rect->height);
+       vpbe_disp_adj_position(disp_dev, layer, rect->top,
+                                       rect->left);
+       ret = osd_device->ops.set_layer_config(osd_device,
+                               layer->layer_info.id, cfg);
+       if (ret < 0) {
+               v4l2_err(&vpbe_dev->v4l2_dev,
+                       "Error in set layer config:\n");
+               return -EINVAL;
+       }
+
+       /* apply zooming and h or v expansion */
+       osd_device->ops.set_zoom(osd_device,
+                       layer->layer_info.id,
+                       layer->layer_info.h_zoom,
+                       layer->layer_info.v_zoom);
+       ret = osd_device->ops.set_vid_expansion(osd_device,
+                       layer->layer_info.h_exp,
+                       layer->layer_info.v_exp);
+       if (ret < 0) {
+               v4l2_err(&vpbe_dev->v4l2_dev,
+               "Error in set vid expansion:\n");
+               return -EINVAL;
+       }
+
+       if ((layer->layer_info.h_zoom != ZOOM_X1) ||
+               (layer->layer_info.v_zoom != ZOOM_X1) ||
+               (layer->layer_info.h_exp != H_EXP_OFF) ||
+               (layer->layer_info.v_exp != V_EXP_OFF))
+               /* Enable expansion filter */
+               osd_device->ops.set_interpolation_filter(osd_device, 1);
+       else
+               osd_device->ops.set_interpolation_filter(osd_device, 0);
+
+       return 0;
+}
+
+static int vpbe_display_g_crop(struct file *file, void *priv,
+                            struct v4l2_crop *crop)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct osd_layer_config *cfg = &layer->layer_info.config;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       struct osd_state *osd_device = fh->disp_dev->osd_device;
+       struct v4l2_rect *rect = &crop->c;
+       int ret;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+                       "VIDIOC_G_CROP, layer id = %d\n",
+                       layer->device_id);
+
+       if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buf type\n");
+               ret = -EINVAL;
+       }
+       osd_device->ops.get_layer_config(osd_device,
+                               layer->layer_info.id, cfg);
+       rect->top = cfg->ypos;
+       rect->left = cfg->xpos;
+       rect->width = cfg->xsize;
+       rect->height = cfg->ysize;
+
+       return 0;
+}
+
+static int vpbe_display_cropcap(struct file *file, void *priv,
+                             struct v4l2_cropcap *cropcap)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_CROPCAP ioctl\n");
+
+       cropcap->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+       cropcap->bounds.left = 0;
+       cropcap->bounds.top = 0;
+       cropcap->bounds.width = vpbe_dev->current_timings.xres;
+       cropcap->bounds.height = vpbe_dev->current_timings.yres;
+       cropcap->pixelaspect = vpbe_dev->current_timings.aspect;
+       cropcap->defrect = cropcap->bounds;
+       return 0;
+}
+
+static int vpbe_display_g_fmt(struct file *file, void *priv,
+                               struct v4l2_format *fmt)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+                       "VIDIOC_G_FMT, layer id = %d\n",
+                       layer->device_id);
+
+       /* If buffer type is video output */
+       if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "invalid type\n");
+               return -EINVAL;
+       }
+       /* Fill in the information about format */
+       fmt->fmt.pix = layer->pix_fmt;
+
+       return 0;
+}
+
+static int vpbe_display_enum_fmt(struct file *file, void  *priv,
+                                  struct v4l2_fmtdesc *fmt)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       unsigned int index = 0;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+                               "VIDIOC_ENUM_FMT, layer id = %d\n",
+                               layer->device_id);
+       if (fmt->index > 1) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Invalid format index\n");
+               return -EINVAL;
+       }
+
+       /* Fill in the information about format */
+       index = fmt->index;
+       memset(fmt, 0, sizeof(*fmt));
+       fmt->index = index;
+       fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+       if (index == 0) {
+               strcpy(fmt->description, "YUV 4:2:2 - UYVY");
+               fmt->pixelformat = V4L2_PIX_FMT_UYVY;
+       } else {
+               strcpy(fmt->description, "Y/CbCr 4:2:0");
+               fmt->pixelformat = V4L2_PIX_FMT_NV12;
+       }
+
+       return 0;
+}
+
+static int vpbe_display_s_fmt(struct file *file, void *priv,
+                               struct v4l2_format *fmt)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_display *disp_dev = fh->disp_dev;
+       struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+       struct osd_layer_config *cfg  = &layer->layer_info.config;
+       struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+       struct osd_state *osd_device = disp_dev->osd_device;
+       int ret;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+                       "VIDIOC_S_FMT, layer id = %d\n",
+                       layer->device_id);
+
+       /* If streaming is started, return error */
+       if (layer->started) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n");
+               return -EBUSY;
+       }
+       if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) {
+               v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "invalid type\n");
+               return -EINVAL;
+       }
+       /* Check for valid pixel format */
+       ret = vpbe_try_format(disp_dev, pixfmt, 1);
+       if (ret)
+               return ret;
+
+       /* YUV420 is requested, check availability of the
+       other video window */
+
+       layer->pix_fmt = *pixfmt;
+
+       /* Get osd layer config */
+       osd_device->ops.get_layer_config(osd_device,
+                       layer->layer_info.id, cfg);
+       /* Store the pixel format in the layer object */
+       cfg->xsize = pixfmt->width;
+       cfg->ysize = pixfmt->height;
+       cfg->line_length = pixfmt->bytesperline;
+       cfg->ypos = 0;
+       cfg->xpos = 0;
+       cfg->interlaced = vpbe_dev->current_timings.interlaced;
+
+       if (V4L2_PIX_FMT_UYVY == pixfmt->pixelformat)
+               cfg->pixfmt = PIXFMT_YCbCrI;
+
+       /* Change of the default pixel format for both video windows */
+       if (V4L2_PIX_FMT_NV12 == pixfmt->pixelformat) {
+               struct vpbe_layer *otherlayer;
+               cfg->pixfmt = PIXFMT_NV12;
+               otherlayer = _vpbe_display_get_other_win_layer(disp_dev,
+                                                               layer);
+               otherlayer->layer_info.config.pixfmt = PIXFMT_NV12;
+       }
+
+       /* Set the layer config in the osd window */
+       ret = osd_device->ops.set_layer_config(osd_device,
+                               layer->layer_info.id, cfg);
+       if (ret < 0) {
+               v4l2_err(&vpbe_dev->v4l2_dev,
+                               "Error in S_FMT params:\n");
+               return -EINVAL;
+       }
+
+       /* Readback and fill the local copy of current pix format */
+       osd_device->ops.get_layer_config(osd_device,
+                       layer->layer_info.id, cfg);
+
+       return 0;
+}
+
+static int vpbe_display_try_fmt(struct file *file, void *priv,
+                                 struct v4l2_format *fmt)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_display *disp_dev = fh->disp_dev;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_TRY_FMT\n");
+
+       if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "invalid type\n");
+               return -EINVAL;
+       }
+
+       /* Check for valid field format */
+       return  vpbe_try_format(disp_dev, pixfmt, 0);
+
+}
+
+/**
+ * vpbe_display_s_std - Set the given standard in the encoder
+ *
+ * Sets the standard if supported by the current encoder. Return the status.
+ * 0 - success & -EINVAL on error
+ */
+static int vpbe_display_s_std(struct file *file, void *priv,
+                               v4l2_std_id *std_id)
+{
+       struct vpbe_fh *fh = priv;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       int ret;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_STD\n");
+
+       /* If streaming is started, return error */
+       if (layer->started) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n");
+               return -EBUSY;
+       }
+       if (NULL != vpbe_dev->ops.s_std) {
+               ret = vpbe_dev->ops.s_std(vpbe_dev, std_id);
+               if (ret) {
+                       v4l2_err(&vpbe_dev->v4l2_dev,
+                       "Failed to set standard for sub devices\n");
+                       return -EINVAL;
+               }
+       } else {
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * vpbe_display_g_std - Get the standard in the current encoder
+ *
+ * Get the standard in the current encoder. Return the status. 0 - success
+ * -EINVAL on error
+ */
+static int vpbe_display_g_std(struct file *file, void *priv,
+                               v4l2_std_id *std_id)
+{
+       struct vpbe_fh *fh = priv;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_STD\n");
+
+       /* Get the standard from the current encoder */
+       if (vpbe_dev->current_timings.timings_type & VPBE_ENC_STD) {
+               *std_id = vpbe_dev->current_timings.timings.std_id;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+/**
+ * vpbe_display_enum_output - enumerate outputs
+ *
+ * Enumerates the outputs available at the vpbe display
+ * returns the status, -EINVAL if end of output list
+ */
+static int vpbe_display_enum_output(struct file *file, void *priv,
+                                   struct v4l2_output *output)
+{
+       struct vpbe_fh *fh = priv;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       int ret;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_OUTPUT\n");
+
+       /* Enumerate outputs */
+
+       if (NULL == vpbe_dev->ops.enum_outputs)
+               return -EINVAL;
+
+       ret = vpbe_dev->ops.enum_outputs(vpbe_dev, output);
+       if (ret) {
+               v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+                       "Failed to enumerate outputs\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * vpbe_display_s_output - Set output to
+ * the output specified by the index
+ */
+static int vpbe_display_s_output(struct file *file, void *priv,
+                               unsigned int i)
+{
+       struct vpbe_fh *fh = priv;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       int ret;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_OUTPUT\n");
+       /* If streaming is started, return error */
+       if (layer->started) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n");
+               return -EBUSY;
+       }
+       if (NULL == vpbe_dev->ops.set_output)
+               return -EINVAL;
+
+       ret = vpbe_dev->ops.set_output(vpbe_dev, i);
+       if (ret) {
+               v4l2_err(&vpbe_dev->v4l2_dev,
+                       "Failed to set output for sub devices\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * vpbe_display_g_output - Get output from subdevice
+ * for a given by the index
+ */
+static int vpbe_display_g_output(struct file *file, void *priv,
+                               unsigned int *i)
+{
+       struct vpbe_fh *fh = priv;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_OUTPUT\n");
+       /* Get the standard from the current encoder */
+       *i = vpbe_dev->current_out_index;
+
+       return 0;
+}
+
+/**
+ * vpbe_display_enum_dv_presets - Enumerate the dv presets
+ *
+ * enum the preset in the current encoder. Return the status. 0 - success
+ * -EINVAL on error
+ */
+static int
+vpbe_display_enum_dv_presets(struct file *file, void *priv,
+                       struct v4l2_dv_enum_preset *preset)
+{
+       struct vpbe_fh *fh = priv;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       int ret;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_DV_PRESETS\n");
+
+       /* Enumerate outputs */
+       if (NULL == vpbe_dev->ops.enum_dv_presets)
+               return -EINVAL;
+
+       ret = vpbe_dev->ops.enum_dv_presets(vpbe_dev, preset);
+       if (ret) {
+               v4l2_err(&vpbe_dev->v4l2_dev,
+                       "Failed to enumerate dv presets info\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * vpbe_display_s_dv_preset - Set the dv presets
+ *
+ * Set the preset in the current encoder. Return the status. 0 - success
+ * -EINVAL on error
+ */
+static int
+vpbe_display_s_dv_preset(struct file *file, void *priv,
+                               struct v4l2_dv_preset *preset)
+{
+       struct vpbe_fh *fh = priv;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       int ret;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_DV_PRESETS\n");
+
+
+       /* If streaming is started, return error */
+       if (layer->started) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n");
+               return -EBUSY;
+       }
+
+       /* Set the given standard in the encoder */
+       if (NULL != vpbe_dev->ops.s_dv_preset)
+               return -EINVAL;
+
+       ret = vpbe_dev->ops.s_dv_preset(vpbe_dev, preset);
+       if (ret) {
+               v4l2_err(&vpbe_dev->v4l2_dev,
+                       "Failed to set the dv presets info\n");
+               return -EINVAL;
+       }
+       /* set the current norm to zero to be consistent. If STD is used
+        * v4l2 layer will set the norm properly on successful s_std call
+        */
+       layer->video_dev.current_norm = 0;
+
+       return 0;
+}
+
+/**
+ * vpbe_display_g_dv_preset - Set the dv presets
+ *
+ * Get the preset in the current encoder. Return the status. 0 - success
+ * -EINVAL on error
+ */
+static int
+vpbe_display_g_dv_preset(struct file *file, void *priv,
+                               struct v4l2_dv_preset *dv_preset)
+{
+       struct vpbe_fh *fh = priv;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_DV_PRESETS\n");
+
+       /* Get the given standard in the encoder */
+
+       if (vpbe_dev->current_timings.timings_type &
+                               VPBE_ENC_DV_PRESET) {
+               dv_preset->preset =
+                       vpbe_dev->current_timings.timings.dv_preset;
+       } else {
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int vpbe_display_streamoff(struct file *file, void *priv,
+                               enum v4l2_buf_type buf_type)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       struct osd_state *osd_device = fh->disp_dev->osd_device;
+       int ret;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+                       "VIDIOC_STREAMOFF,layer id = %d\n",
+                       layer->device_id);
+
+       if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
+               return -EINVAL;
+       }
+
+       /* If io is allowed for this file handle, return error */
+       if (!fh->io_allowed) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n");
+               return -EACCES;
+       }
+
+       /* If streaming is not started, return error */
+       if (!layer->started) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "streaming not started in layer"
+                       " id = %d\n", layer->device_id);
+               return -EINVAL;
+       }
+
+       osd_device->ops.disable_layer(osd_device,
+                       layer->layer_info.id);
+       layer->started = 0;
+       ret = videobuf_streamoff(&layer->buffer_queue);
+
+       return ret;
+}
+
+static int vpbe_display_streamon(struct file *file, void *priv,
+                        enum v4l2_buf_type buf_type)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_display *disp_dev = fh->disp_dev;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       struct osd_state *osd_device = disp_dev->osd_device;
+       int ret;
+
+       osd_device->ops.disable_layer(osd_device,
+                       layer->layer_info.id);
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_STREAMON, layerid=%d\n",
+                                               layer->device_id);
+
+       if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
+               return -EINVAL;
+       }
+
+       /* If file handle is not allowed IO, return error */
+       if (!fh->io_allowed) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n");
+               return -EACCES;
+       }
+       /* If Streaming is already started, return error */
+       if (layer->started) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "layer is already streaming\n");
+               return -EBUSY;
+       }
+
+       /*
+        * Call videobuf_streamon to start streaming
+        * in videobuf
+        */
+       ret = videobuf_streamon(&layer->buffer_queue);
+       if (ret) {
+               v4l2_err(&vpbe_dev->v4l2_dev,
+               "error in videobuf_streamon\n");
+               return ret;
+       }
+       /* If buffer queue is empty, return error */
+       if (list_empty(&layer->dma_queue)) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "buffer queue is empty\n");
+               goto streamoff;
+       }
+       /* Get the next frame from the buffer queue */
+       layer->next_frm = layer->cur_frm = list_entry(layer->dma_queue.next,
+                               struct videobuf_buffer, queue);
+       /* Remove buffer from the buffer queue */
+       list_del(&layer->cur_frm->queue);
+       /* Mark state of the current frame to active */
+       layer->cur_frm->state = VIDEOBUF_ACTIVE;
+       /* Initialize field_id and started member */
+       layer->field_id = 0;
+
+       /* Set parameters in OSD and VENC */
+       ret = vpbe_set_osd_display_params(disp_dev, layer);
+       if (ret < 0)
+               goto streamoff;
+
+       /*
+        * if request format is yuv420 semiplanar, need to
+        * enable both video windows
+        */
+       layer->started = 1;
+
+       layer->layer_first_int = 1;
+
+       return ret;
+streamoff:
+       ret = videobuf_streamoff(&layer->buffer_queue);
+       return ret;
+}
+
+static int vpbe_display_dqbuf(struct file *file, void *priv,
+                     struct v4l2_buffer *buf)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       int ret;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+               "VIDIOC_DQBUF, layer id = %d\n",
+               layer->device_id);
+
+       if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
+               return -EINVAL;
+       }
+       /* If this file handle is not allowed to do IO, return error */
+       if (!fh->io_allowed) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n");
+               return -EACCES;
+       }
+       if (file->f_flags & O_NONBLOCK)
+               /* Call videobuf_dqbuf for non blocking mode */
+               ret = videobuf_dqbuf(&layer->buffer_queue, buf, 1);
+       else
+               /* Call videobuf_dqbuf for blocking mode */
+               ret = videobuf_dqbuf(&layer->buffer_queue, buf, 0);
+
+       return ret;
+}
+
+static int vpbe_display_qbuf(struct file *file, void *priv,
+                    struct v4l2_buffer *p)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+               "VIDIOC_QBUF, layer id = %d\n",
+               layer->device_id);
+
+       if (V4L2_BUF_TYPE_VIDEO_OUTPUT != p->type) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
+               return -EINVAL;
+       }
+
+       /* If this file handle is not allowed to do IO, return error */
+       if (!fh->io_allowed) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n");
+               return -EACCES;
+       }
+
+       return videobuf_qbuf(&layer->buffer_queue, p);
+}
+
+static int vpbe_display_querybuf(struct file *file, void *priv,
+                        struct v4l2_buffer *buf)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       int ret;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+               "VIDIOC_QUERYBUF, layer id = %d\n",
+               layer->device_id);
+
+       if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
+               return -EINVAL;
+       }
+
+       /* Call videobuf_querybuf to get information */
+       ret = videobuf_querybuf(&layer->buffer_queue, buf);
+
+       return ret;
+}
+
+static int vpbe_display_reqbufs(struct file *file, void *priv,
+                       struct v4l2_requestbuffers *req_buf)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       int ret;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_reqbufs\n");
+
+       if (V4L2_BUF_TYPE_VIDEO_OUTPUT != req_buf->type) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
+               return -EINVAL;
+       }
+
+       /* If io users of the layer is not zero, return error */
+       if (0 != layer->io_usrs) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "not IO user\n");
+               return -EBUSY;
+       }
+       /* Initialize videobuf queue as per the buffer type */
+       videobuf_queue_dma_contig_init(&layer->buffer_queue,
+                               &video_qops,
+                               vpbe_dev->pdev,
+                               &layer->irqlock,
+                               V4L2_BUF_TYPE_VIDEO_OUTPUT,
+                               layer->pix_fmt.field,
+                               sizeof(struct videobuf_buffer),
+                               fh, NULL);
+
+       /* Set io allowed member of file handle to TRUE */
+       fh->io_allowed = 1;
+       /* Increment io usrs member of layer object to 1 */
+       layer->io_usrs = 1;
+       /* Store type of memory requested in layer object */
+       layer->memory = req_buf->memory;
+       /* Initialize buffer queue */
+       INIT_LIST_HEAD(&layer->dma_queue);
+       /* Allocate buffers */
+       ret = videobuf_reqbufs(&layer->buffer_queue, req_buf);
+
+       return ret;
+}
+
+/*
+ * vpbe_display_mmap()
+ * It is used to map kernel space buffers into user spaces
+ */
+static int vpbe_display_mmap(struct file *filep, struct vm_area_struct *vma)
+{
+       /* Get the layer object and file handle object */
+       struct vpbe_fh *fh = filep->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_mmap\n");
+
+       return videobuf_mmap_mapper(&layer->buffer_queue, vma);
+}
+
+/* vpbe_display_poll(): It is used for select/poll system call
+ */
+static unsigned int vpbe_display_poll(struct file *filep, poll_table *wait)
+{
+       struct vpbe_fh *fh = filep->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       unsigned int err = 0;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_poll\n");
+       if (layer->started)
+               err = videobuf_poll_stream(filep, &layer->buffer_queue, wait);
+       return err;
+}
+
+/*
+ * vpbe_display_open()
+ * It creates object of file handle structure and stores it in private_data
+ * member of filepointer
+ */
+static int vpbe_display_open(struct file *file)
+{
+       struct vpbe_fh *fh = NULL;
+       struct vpbe_layer *layer = video_drvdata(file);
+       struct vpbe_display *disp_dev = layer->disp_dev;
+       struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+       struct osd_state *osd_device = disp_dev->osd_device;
+       int err;
+
+       /* Allocate memory for the file handle object */
+       fh = kmalloc(sizeof(struct vpbe_fh), GFP_KERNEL);
+       if (fh == NULL) {
+               v4l2_err(&vpbe_dev->v4l2_dev,
+                       "unable to allocate memory for file handle object\n");
+               return -ENOMEM;
+       }
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+                       "vpbe display open plane = %d\n",
+                       layer->device_id);
+
+       /* store pointer to fh in private_data member of filep */
+       file->private_data = fh;
+       fh->layer = layer;
+       fh->disp_dev = disp_dev;
+
+       if (!layer->usrs) {
+
+               /* First claim the layer for this device */
+               err = osd_device->ops.request_layer(osd_device,
+                                               layer->layer_info.id);
+               if (err < 0) {
+                       /* Couldn't get layer */
+                       v4l2_err(&vpbe_dev->v4l2_dev,
+                               "Display Manager failed to allocate layer\n");
+                       kfree(fh);
+                       return -EINVAL;
+               }
+       }
+       /* Increment layer usrs counter */
+       layer->usrs++;
+       /* Set io_allowed member to false */
+       fh->io_allowed = 0;
+       /* Initialize priority of this instance to default priority */
+       fh->prio = V4L2_PRIORITY_UNSET;
+       v4l2_prio_open(&layer->prio, &fh->prio);
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+                       "vpbe display device opened successfully\n");
+       return 0;
+}
+
+/*
+ * vpbe_display_release()
+ * This function deletes buffer queue, frees the buffers and the davinci
+ * display file * handle
+ */
+static int vpbe_display_release(struct file *file)
+{
+       /* Get the layer object and file handle object */
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct osd_layer_config *cfg  = &layer->layer_info.config;
+       struct vpbe_display *disp_dev = fh->disp_dev;
+       struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+       struct osd_state *osd_device = disp_dev->osd_device;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_release\n");
+
+       /* if this instance is doing IO */
+       if (fh->io_allowed) {
+               /* Reset io_usrs member of layer object */
+               layer->io_usrs = 0;
+
+               osd_device->ops.disable_layer(osd_device,
+                               layer->layer_info.id);
+               layer->started = 0;
+               /* Free buffers allocated */
+               videobuf_queue_cancel(&layer->buffer_queue);
+               videobuf_mmap_free(&layer->buffer_queue);
+       }
+
+       /* Decrement layer usrs counter */
+       layer->usrs--;
+       /* If this file handle has initialize encoder device, reset it */
+       if (!layer->usrs) {
+               if (cfg->pixfmt == PIXFMT_NV12) {
+                       struct vpbe_layer *otherlayer;
+                       otherlayer =
+                       _vpbe_display_get_other_win_layer(disp_dev, layer);
+                       osd_device->ops.disable_layer(osd_device,
+                                       otherlayer->layer_info.id);
+                       osd_device->ops.release_layer(osd_device,
+                                       otherlayer->layer_info.id);
+               }
+               osd_device->ops.disable_layer(osd_device,
+                               layer->layer_info.id);
+               osd_device->ops.release_layer(osd_device,
+                               layer->layer_info.id);
+       }
+       /* Close the priority */
+       v4l2_prio_close(&layer->prio, fh->prio);
+       file->private_data = NULL;
+
+       /* Free memory allocated to file handle object */
+       kfree(fh);
+
+       disp_dev->cbcr_ofst = 0;
+
+       return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vpbe_display_g_register(struct file *file, void *priv,
+                       struct v4l2_dbg_register *reg)
+{
+       struct v4l2_dbg_match *match = &reg->match;
+
+       if (match->type >= 2) {
+               v4l2_subdev_call(vpbe_dev->venc,
+                                core,
+                                g_register,
+                                reg);
+       }
+
+       return 0;
+}
+
+static int vpbe_display_s_register(struct file *file, void *priv,
+                       struct v4l2_dbg_register *reg)
+{
+       return 0;
+}
+#endif
+
+/* vpbe capture ioctl operations */
+static const struct v4l2_ioctl_ops vpbe_ioctl_ops = {
+       .vidioc_querycap         = vpbe_display_querycap,
+       .vidioc_g_fmt_vid_out    = vpbe_display_g_fmt,
+       .vidioc_enum_fmt_vid_out = vpbe_display_enum_fmt,
+       .vidioc_s_fmt_vid_out    = vpbe_display_s_fmt,
+       .vidioc_try_fmt_vid_out  = vpbe_display_try_fmt,
+       .vidioc_reqbufs          = vpbe_display_reqbufs,
+       .vidioc_querybuf         = vpbe_display_querybuf,
+       .vidioc_qbuf             = vpbe_display_qbuf,
+       .vidioc_dqbuf            = vpbe_display_dqbuf,
+       .vidioc_streamon         = vpbe_display_streamon,
+       .vidioc_streamoff        = vpbe_display_streamoff,
+       .vidioc_cropcap          = vpbe_display_cropcap,
+       .vidioc_g_crop           = vpbe_display_g_crop,
+       .vidioc_s_crop           = vpbe_display_s_crop,
+       .vidioc_g_priority       = vpbe_display_g_priority,
+       .vidioc_s_priority       = vpbe_display_s_priority,
+       .vidioc_s_std            = vpbe_display_s_std,
+       .vidioc_g_std            = vpbe_display_g_std,
+       .vidioc_enum_output      = vpbe_display_enum_output,
+       .vidioc_s_output         = vpbe_display_s_output,
+       .vidioc_g_output         = vpbe_display_g_output,
+       .vidioc_s_dv_preset      = vpbe_display_s_dv_preset,
+       .vidioc_g_dv_preset      = vpbe_display_g_dv_preset,
+       .vidioc_enum_dv_presets  = vpbe_display_enum_dv_presets,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_register       = vpbe_display_g_register,
+       .vidioc_s_register       = vpbe_display_s_register,
+#endif
+};
+
+static struct v4l2_file_operations vpbe_fops = {
+       .owner = THIS_MODULE,
+       .open = vpbe_display_open,
+       .release = vpbe_display_release,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap = vpbe_display_mmap,
+       .poll = vpbe_display_poll
+};
+
+static int vpbe_device_get(struct device *dev, void *data)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct vpbe_display *vpbe_disp  = data;
+
+       if (strcmp("vpbe_controller", pdev->name) == 0)
+               vpbe_disp->vpbe_dev = platform_get_drvdata(pdev);
+
+       if (strcmp("vpbe-osd", pdev->name) == 0)
+               vpbe_disp->osd_device = platform_get_drvdata(pdev);
+
+       return 0;
+}
+
+static __devinit int init_vpbe_layer(int i, struct vpbe_display *disp_dev,
+                                    struct platform_device *pdev)
+{
+       struct vpbe_layer *vpbe_display_layer = NULL;
+       struct video_device *vbd = NULL;
+
+       /* Allocate memory for four plane display objects */
+
+       disp_dev->dev[i] =
+               kzalloc(sizeof(struct vpbe_layer), GFP_KERNEL);
+
+       /* If memory allocation fails, return error */
+       if (!disp_dev->dev[i]) {
+               printk(KERN_ERR "ran out of memory\n");
+               return  -ENOMEM;
+       }
+       spin_lock_init(&disp_dev->dev[i]->irqlock);
+       mutex_init(&disp_dev->dev[i]->opslock);
+
+       /* Get the pointer to the layer object */
+       vpbe_display_layer = disp_dev->dev[i];
+       vbd = &vpbe_display_layer->video_dev;
+       /* Initialize field of video device */
+       vbd->release    = video_device_release_empty;
+       vbd->fops       = &vpbe_fops;
+       vbd->ioctl_ops  = &vpbe_ioctl_ops;
+       vbd->minor      = -1;
+       vbd->v4l2_dev   = &disp_dev->vpbe_dev->v4l2_dev;
+       vbd->lock       = &vpbe_display_layer->opslock;
+
+       if (disp_dev->vpbe_dev->current_timings.timings_type &
+                       VPBE_ENC_STD) {
+               vbd->tvnorms = (V4L2_STD_525_60 | V4L2_STD_625_50);
+               vbd->current_norm =
+                       disp_dev->vpbe_dev->
+                       current_timings.timings.std_id;
+       } else
+               vbd->current_norm = 0;
+
+       snprintf(vbd->name, sizeof(vbd->name),
+                       "DaVinci_VPBE Display_DRIVER_V%d.%d.%d",
+                       (VPBE_DISPLAY_VERSION_CODE >> 16) & 0xff,
+                       (VPBE_DISPLAY_VERSION_CODE >> 8) & 0xff,
+                       (VPBE_DISPLAY_VERSION_CODE) & 0xff);
+
+       vpbe_display_layer->device_id = i;
+
+       vpbe_display_layer->layer_info.id =
+               ((i == VPBE_DISPLAY_DEVICE_0) ? WIN_VID0 : WIN_VID1);
+
+       /* Initialize prio member of layer object */
+       v4l2_prio_init(&vpbe_display_layer->prio);
+
+       return 0;
+}
+
+static __devinit int register_device(struct vpbe_layer *vpbe_display_layer,
+                                       struct vpbe_display *disp_dev,
+                                       struct platform_device *pdev) {
+       int err;
+
+       v4l2_info(&disp_dev->vpbe_dev->v4l2_dev,
+                 "Trying to register VPBE display device.\n");
+       v4l2_info(&disp_dev->vpbe_dev->v4l2_dev,
+                 "layer=%x,layer->video_dev=%x\n",
+                 (int)vpbe_display_layer,
+                 (int)&vpbe_display_layer->video_dev);
+
+       err = video_register_device(&vpbe_display_layer->video_dev,
+                                   VFL_TYPE_GRABBER,
+                                   -1);
+       if (err)
+               return -ENODEV;
+
+       vpbe_display_layer->disp_dev = disp_dev;
+       /* set the driver data in platform device */
+       platform_set_drvdata(pdev, disp_dev);
+       video_set_drvdata(&vpbe_display_layer->video_dev,
+                         vpbe_display_layer);
+
+       return 0;
+}
+
+
+
+/*
+ * vpbe_display_probe()
+ * This function creates device entries by register itself to the V4L2 driver
+ * and initializes fields of each layer objects
+ */
+static __devinit int vpbe_display_probe(struct platform_device *pdev)
+{
+       struct vpbe_layer *vpbe_display_layer;
+       struct vpbe_display *disp_dev;
+       struct resource *res = NULL;
+       int k;
+       int i;
+       int err;
+       int irq;
+
+       printk(KERN_DEBUG "vpbe_display_probe\n");
+       /* Allocate memory for vpbe_display */
+       disp_dev = kzalloc(sizeof(struct vpbe_display), GFP_KERNEL);
+       if (!disp_dev) {
+               printk(KERN_ERR "ran out of memory\n");
+               return -ENOMEM;
+       }
+
+       spin_lock_init(&disp_dev->dma_queue_lock);
+       /*
+        * Scan all the platform devices to find the vpbe
+        * controller device and get the vpbe_dev object
+        */
+       err = bus_for_each_dev(&platform_bus_type, NULL, disp_dev,
+                       vpbe_device_get);
+       if (err < 0)
+               return err;
+       /* Initialize the vpbe display controller */
+       if (NULL != disp_dev->vpbe_dev->ops.initialize) {
+               err = disp_dev->vpbe_dev->ops.initialize(&pdev->dev,
+                                                        disp_dev->vpbe_dev);
+               if (err) {
+                       v4l2_err(&disp_dev->vpbe_dev->v4l2_dev,
+                                       "Error initing vpbe\n");
+                       err = -ENOMEM;
+                       goto probe_out;
+               }
+       }
+
+       for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
+               if (init_vpbe_layer(i, disp_dev, pdev)) {
+                       err = -ENODEV;
+                       goto probe_out;
+               }
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!res) {
+               v4l2_err(&disp_dev->vpbe_dev->v4l2_dev,
+                        "Unable to get VENC interrupt resource\n");
+               err = -ENODEV;
+               goto probe_out;
+       }
+
+       irq = res->start;
+       if (request_irq(irq, venc_isr,  IRQF_DISABLED, VPBE_DISPLAY_DRIVER,
+               disp_dev)) {
+               v4l2_err(&disp_dev->vpbe_dev->v4l2_dev,
+                               "Unable to request interrupt\n");
+               err = -ENODEV;
+               goto probe_out;
+       }
+
+       for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
+               if (register_device(disp_dev->dev[i], disp_dev, pdev)) {
+                       err = -ENODEV;
+                       goto probe_out;
+               }
+       }
+
+       printk(KERN_DEBUG "Successfully completed the probing of vpbe v4l2 device\n");
+       return 0;
+
+probe_out:
+       free_irq(res->start, disp_dev);
+       for (k = 0; k < VPBE_DISPLAY_MAX_DEVICES; k++) {
+               /* Get the pointer to the layer object */
+               vpbe_display_layer = disp_dev->dev[k];
+               /* Unregister video device */
+               if (vpbe_display_layer) {
+                       video_unregister_device(
+                               &vpbe_display_layer->video_dev);
+                               kfree(disp_dev->dev[k]);
+               }
+       }
+       kfree(disp_dev);
+       return err;
+}
+
+/*
+ * vpbe_display_remove()
+ * It un-register hardware layer from V4L2 driver
+ */
+static int vpbe_display_remove(struct platform_device *pdev)
+{
+       struct vpbe_layer *vpbe_display_layer;
+       struct vpbe_display *disp_dev = platform_get_drvdata(pdev);
+       struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+       struct resource *res;
+       int i;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_remove\n");
+
+       /* unregister irq */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       free_irq(res->start, disp_dev);
+
+       /* deinitialize the vpbe display controller */
+       if (NULL != vpbe_dev->ops.deinitialize)
+               vpbe_dev->ops.deinitialize(&pdev->dev, vpbe_dev);
+       /* un-register device */
+       for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
+               /* Get the pointer to the layer object */
+               vpbe_display_layer = disp_dev->dev[i];
+               /* Unregister video device */
+               video_unregister_device(&vpbe_display_layer->video_dev);
+
+       }
+       for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
+               kfree(disp_dev->dev[i]);
+               disp_dev->dev[i] = NULL;
+       }
+
+       return 0;
+}
+
+static struct platform_driver vpbe_display_driver = {
+       .driver = {
+               .name = VPBE_DISPLAY_DRIVER,
+               .owner = THIS_MODULE,
+               .bus = &platform_bus_type,
+       },
+       .probe = vpbe_display_probe,
+       .remove = __devexit_p(vpbe_display_remove),
+};
+
+/*
+ * vpbe_display_init()
+ * This function registers device and driver to the kernel, requests irq
+ * handler and allocates memory for layer objects
+ */
+static __devinit int vpbe_display_init(void)
+{
+       int err;
+
+       printk(KERN_DEBUG "vpbe_display_init\n");
+
+       /* Register driver to the kernel */
+       err = platform_driver_register(&vpbe_display_driver);
+       if (0 != err)
+               return err;
+
+       printk(KERN_DEBUG "vpbe_display_init:"
+                       "VPBE V4L2 Display Driver V1.0 loaded\n");
+       return 0;
+}
+
+/*
+ * vpbe_display_cleanup()
+ * This function un-registers device and driver to the kernel, frees requested
+ * irq handler and de-allocates memory allocated for layer objects.
+ */
+static void vpbe_display_cleanup(void)
+{
+       printk(KERN_DEBUG "vpbe_display_cleanup\n");
+
+       /* platform driver unregister */
+       platform_driver_unregister(&vpbe_display_driver);
+}
+
+/* Function for module initialization and cleanup */
+module_init(vpbe_display_init);
+module_exit(vpbe_display_cleanup);
+
+MODULE_DESCRIPTION("TI DM644x/DM355/DM365 VPBE Display controller");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Texas Instruments");
diff --git a/drivers/media/video/davinci/vpbe_osd.c b/drivers/media/video/davinci/vpbe_osd.c
new file mode 100644 (file)
index 0000000..5352884
--- /dev/null
@@ -0,0 +1,1231 @@
+/*
+ * Copyright (C) 2007-2010 Texas Instruments Inc
+ * Copyright (C) 2007 MontaVista Software, Inc.
+ *
+ * Andy Lowe (alowe@mvista.com), MontaVista Software
+ * - Initial version
+ * Murali Karicheri (mkaricheri@gmail.com), Texas Instruments Ltd.
+ * - ported to sub device interface
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+
+#include <mach/io.h>
+#include <mach/cputype.h>
+#include <mach/hardware.h>
+
+#include <media/davinci/vpss.h>
+#include <media/v4l2-device.h>
+#include <media/davinci/vpbe_types.h>
+#include <media/davinci/vpbe_osd.h>
+
+#include <linux/io.h>
+#include "vpbe_osd_regs.h"
+
+#define MODULE_NAME    VPBE_OSD_SUBDEV_NAME
+
+/* register access routines */
+static inline u32 osd_read(struct osd_state *sd, u32 offset)
+{
+       struct osd_state *osd = sd;
+
+       return readl(osd->osd_base + offset);
+}
+
+static inline u32 osd_write(struct osd_state *sd, u32 val, u32 offset)
+{
+       struct osd_state *osd = sd;
+
+       writel(val, osd->osd_base + offset);
+
+       return val;
+}
+
+static inline u32 osd_set(struct osd_state *sd, u32 mask, u32 offset)
+{
+       struct osd_state *osd = sd;
+
+       u32 addr = osd->osd_base + offset;
+       u32 val = readl(addr) | mask;
+
+       writel(val, addr);
+
+       return val;
+}
+
+static inline u32 osd_clear(struct osd_state *sd, u32 mask, u32 offset)
+{
+       struct osd_state *osd = sd;
+
+       u32 addr = osd->osd_base + offset;
+       u32 val = readl(addr) & ~mask;
+
+       writel(val, addr);
+
+       return val;
+}
+
+static inline u32 osd_modify(struct osd_state *sd, u32 mask, u32 val,
+                                u32 offset)
+{
+       struct osd_state *osd = sd;
+
+       u32 addr = osd->osd_base + offset;
+       u32 new_val = (readl(addr) & ~mask) | (val & mask);
+
+       writel(new_val, addr);
+
+       return new_val;
+}
+
+/* define some macros for layer and pixfmt classification */
+#define is_osd_win(layer) (((layer) == WIN_OSD0) || ((layer) == WIN_OSD1))
+#define is_vid_win(layer) (((layer) == WIN_VID0) || ((layer) == WIN_VID1))
+#define is_rgb_pixfmt(pixfmt) \
+       (((pixfmt) == PIXFMT_RGB565) || ((pixfmt) == PIXFMT_RGB888))
+#define is_yc_pixfmt(pixfmt) \
+       (((pixfmt) == PIXFMT_YCbCrI) || ((pixfmt) == PIXFMT_YCrCbI) || \
+       ((pixfmt) == PIXFMT_NV12))
+#define MAX_WIN_SIZE OSD_VIDWIN0XP_V0X
+#define MAX_LINE_LENGTH (OSD_VIDWIN0OFST_V0LO << 5)
+
+/**
+ * _osd_dm6446_vid0_pingpong() - field inversion fix for DM6446
+ * @sd - ptr to struct osd_state
+ * @field_inversion - inversion flag
+ * @fb_base_phys - frame buffer address
+ * @lconfig - ptr to layer config
+ *
+ * This routine implements a workaround for the field signal inversion silicon
+ * erratum described in Advisory 1.3.8 for the DM6446.  The fb_base_phys and
+ * lconfig parameters apply to the vid0 window.  This routine should be called
+ * whenever the vid0 layer configuration or start address is modified, or when
+ * the OSD field inversion setting is modified.
+ * Returns: 1 if the ping-pong buffers need to be toggled in the vsync isr, or
+ *          0 otherwise
+ */
+static int _osd_dm6446_vid0_pingpong(struct osd_state *sd,
+                                    int field_inversion,
+                                    unsigned long fb_base_phys,
+                                    const struct osd_layer_config *lconfig)
+{
+       struct osd_platform_data *pdata;
+
+       pdata = (struct osd_platform_data *)sd->dev->platform_data;
+       if (pdata->field_inv_wa_enable) {
+
+               if (!field_inversion || !lconfig->interlaced) {
+                       osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR);
+                       osd_write(sd, fb_base_phys & ~0x1F, OSD_PPVWIN0ADR);
+                       osd_modify(sd, OSD_MISCCTL_PPSW | OSD_MISCCTL_PPRV, 0,
+                                  OSD_MISCCTL);
+                       return 0;
+               } else {
+                       unsigned miscctl = OSD_MISCCTL_PPRV;
+
+                       osd_write(sd,
+                               (fb_base_phys & ~0x1F) - lconfig->line_length,
+                               OSD_VIDWIN0ADR);
+                       osd_write(sd,
+                               (fb_base_phys & ~0x1F) + lconfig->line_length,
+                               OSD_PPVWIN0ADR);
+                       osd_modify(sd,
+                               OSD_MISCCTL_PPSW | OSD_MISCCTL_PPRV, miscctl,
+                               OSD_MISCCTL);
+
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+static void _osd_set_field_inversion(struct osd_state *sd, int enable)
+{
+       unsigned fsinv = 0;
+
+       if (enable)
+               fsinv = OSD_MODE_FSINV;
+
+       osd_modify(sd, OSD_MODE_FSINV, fsinv, OSD_MODE);
+}
+
+static void _osd_set_blink_attribute(struct osd_state *sd, int enable,
+                                    enum osd_blink_interval blink)
+{
+       u32 osdatrmd = 0;
+
+       if (enable) {
+               osdatrmd |= OSD_OSDATRMD_BLNK;
+               osdatrmd |= blink << OSD_OSDATRMD_BLNKINT_SHIFT;
+       }
+       /* caller must ensure that OSD1 is configured in attribute mode */
+       osd_modify(sd, OSD_OSDATRMD_BLNKINT | OSD_OSDATRMD_BLNK, osdatrmd,
+                 OSD_OSDATRMD);
+}
+
+static void _osd_set_rom_clut(struct osd_state *sd,
+                             enum osd_rom_clut rom_clut)
+{
+       if (rom_clut == ROM_CLUT0)
+               osd_clear(sd, OSD_MISCCTL_RSEL, OSD_MISCCTL);
+       else
+               osd_set(sd, OSD_MISCCTL_RSEL, OSD_MISCCTL);
+}
+
+static void _osd_set_palette_map(struct osd_state *sd,
+                                enum osd_win_layer osdwin,
+                                unsigned char pixel_value,
+                                unsigned char clut_index,
+                                enum osd_pix_format pixfmt)
+{
+       static const int map_2bpp[] = { 0, 5, 10, 15 };
+       static const int map_1bpp[] = { 0, 15 };
+       int bmp_offset;
+       int bmp_shift;
+       int bmp_mask;
+       int bmp_reg;
+
+       switch (pixfmt) {
+       case PIXFMT_1BPP:
+               bmp_reg = map_1bpp[pixel_value & 0x1];
+               break;
+       case PIXFMT_2BPP:
+               bmp_reg = map_2bpp[pixel_value & 0x3];
+               break;
+       case PIXFMT_4BPP:
+               bmp_reg = pixel_value & 0xf;
+               break;
+       default:
+               return;
+       }
+
+       switch (osdwin) {
+       case OSDWIN_OSD0:
+               bmp_offset = OSD_W0BMP01 + (bmp_reg >> 1) * sizeof(u32);
+               break;
+       case OSDWIN_OSD1:
+               bmp_offset = OSD_W1BMP01 + (bmp_reg >> 1) * sizeof(u32);
+               break;
+       default:
+               return;
+       }
+
+       if (bmp_reg & 1) {
+               bmp_shift = 8;
+               bmp_mask = 0xff << 8;
+       } else {
+               bmp_shift = 0;
+               bmp_mask = 0xff;
+       }
+
+       osd_modify(sd, bmp_mask, clut_index << bmp_shift, bmp_offset);
+}
+
+static void _osd_set_rec601_attenuation(struct osd_state *sd,
+                                       enum osd_win_layer osdwin, int enable)
+{
+       switch (osdwin) {
+       case OSDWIN_OSD0:
+               osd_modify(sd, OSD_OSDWIN0MD_ATN0E,
+                         enable ? OSD_OSDWIN0MD_ATN0E : 0,
+                         OSD_OSDWIN0MD);
+               break;
+       case OSDWIN_OSD1:
+               osd_modify(sd, OSD_OSDWIN1MD_ATN1E,
+                         enable ? OSD_OSDWIN1MD_ATN1E : 0,
+                         OSD_OSDWIN1MD);
+               break;
+       }
+}
+
+static void _osd_set_blending_factor(struct osd_state *sd,
+                                    enum osd_win_layer osdwin,
+                                    enum osd_blending_factor blend)
+{
+       switch (osdwin) {
+       case OSDWIN_OSD0:
+               osd_modify(sd, OSD_OSDWIN0MD_BLND0,
+                         blend << OSD_OSDWIN0MD_BLND0_SHIFT, OSD_OSDWIN0MD);
+               break;
+       case OSDWIN_OSD1:
+               osd_modify(sd, OSD_OSDWIN1MD_BLND1,
+                         blend << OSD_OSDWIN1MD_BLND1_SHIFT, OSD_OSDWIN1MD);
+               break;
+       }
+}
+
+static void _osd_enable_color_key(struct osd_state *sd,
+                                 enum osd_win_layer osdwin,
+                                 unsigned colorkey,
+                                 enum osd_pix_format pixfmt)
+{
+       switch (pixfmt) {
+       case PIXFMT_RGB565:
+               osd_write(sd, colorkey & OSD_TRANSPVAL_RGBTRANS,
+                         OSD_TRANSPVAL);
+               break;
+       default:
+               break;
+       }
+
+       switch (osdwin) {
+       case OSDWIN_OSD0:
+               osd_set(sd, OSD_OSDWIN0MD_TE0, OSD_OSDWIN0MD);
+               break;
+       case OSDWIN_OSD1:
+               osd_set(sd, OSD_OSDWIN1MD_TE1, OSD_OSDWIN1MD);
+               break;
+       }
+}
+
+static void _osd_disable_color_key(struct osd_state *sd,
+                                  enum osd_win_layer osdwin)
+{
+       switch (osdwin) {
+       case OSDWIN_OSD0:
+               osd_clear(sd, OSD_OSDWIN0MD_TE0, OSD_OSDWIN0MD);
+               break;
+       case OSDWIN_OSD1:
+               osd_clear(sd, OSD_OSDWIN1MD_TE1, OSD_OSDWIN1MD);
+               break;
+       }
+}
+
+static void _osd_set_osd_clut(struct osd_state *sd,
+                             enum osd_win_layer osdwin,
+                             enum osd_clut clut)
+{
+       u32 winmd = 0;
+
+       switch (osdwin) {
+       case OSDWIN_OSD0:
+               if (clut == RAM_CLUT)
+                       winmd |= OSD_OSDWIN0MD_CLUTS0;
+               osd_modify(sd, OSD_OSDWIN0MD_CLUTS0, winmd, OSD_OSDWIN0MD);
+               break;
+       case OSDWIN_OSD1:
+               if (clut == RAM_CLUT)
+                       winmd |= OSD_OSDWIN1MD_CLUTS1;
+               osd_modify(sd, OSD_OSDWIN1MD_CLUTS1, winmd, OSD_OSDWIN1MD);
+               break;
+       }
+}
+
+static void _osd_set_zoom(struct osd_state *sd, enum osd_layer layer,
+                         enum osd_zoom_factor h_zoom,
+                         enum osd_zoom_factor v_zoom)
+{
+       u32 winmd = 0;
+
+       switch (layer) {
+       case WIN_OSD0:
+               winmd |= (h_zoom << OSD_OSDWIN0MD_OHZ0_SHIFT);
+               winmd |= (v_zoom << OSD_OSDWIN0MD_OVZ0_SHIFT);
+               osd_modify(sd, OSD_OSDWIN0MD_OHZ0 | OSD_OSDWIN0MD_OVZ0, winmd,
+                         OSD_OSDWIN0MD);
+               break;
+       case WIN_VID0:
+               winmd |= (h_zoom << OSD_VIDWINMD_VHZ0_SHIFT);
+               winmd |= (v_zoom << OSD_VIDWINMD_VVZ0_SHIFT);
+               osd_modify(sd, OSD_VIDWINMD_VHZ0 | OSD_VIDWINMD_VVZ0, winmd,
+                         OSD_VIDWINMD);
+               break;
+       case WIN_OSD1:
+               winmd |= (h_zoom << OSD_OSDWIN1MD_OHZ1_SHIFT);
+               winmd |= (v_zoom << OSD_OSDWIN1MD_OVZ1_SHIFT);
+               osd_modify(sd, OSD_OSDWIN1MD_OHZ1 | OSD_OSDWIN1MD_OVZ1, winmd,
+                         OSD_OSDWIN1MD);
+               break;
+       case WIN_VID1:
+               winmd |= (h_zoom << OSD_VIDWINMD_VHZ1_SHIFT);
+               winmd |= (v_zoom << OSD_VIDWINMD_VVZ1_SHIFT);
+               osd_modify(sd, OSD_VIDWINMD_VHZ1 | OSD_VIDWINMD_VVZ1, winmd,
+                         OSD_VIDWINMD);
+               break;
+       }
+}
+
+static void _osd_disable_layer(struct osd_state *sd, enum osd_layer layer)
+{
+       switch (layer) {
+       case WIN_OSD0:
+               osd_clear(sd, OSD_OSDWIN0MD_OACT0, OSD_OSDWIN0MD);
+               break;
+       case WIN_VID0:
+               osd_clear(sd, OSD_VIDWINMD_ACT0, OSD_VIDWINMD);
+               break;
+       case WIN_OSD1:
+               /* disable attribute mode as well as disabling the window */
+               osd_clear(sd, OSD_OSDWIN1MD_OASW | OSD_OSDWIN1MD_OACT1,
+                         OSD_OSDWIN1MD);
+               break;
+       case WIN_VID1:
+               osd_clear(sd, OSD_VIDWINMD_ACT1, OSD_VIDWINMD);
+               break;
+       }
+}
+
+static void osd_disable_layer(struct osd_state *sd, enum osd_layer layer)
+{
+       struct osd_state *osd = sd;
+       struct osd_window_state *win = &osd->win[layer];
+       unsigned long flags;
+
+       spin_lock_irqsave(&osd->lock, flags);
+
+       if (!win->is_enabled) {
+               spin_unlock_irqrestore(&osd->lock, flags);
+               return;
+       }
+       win->is_enabled = 0;
+
+       _osd_disable_layer(sd, layer);
+
+       spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static void _osd_enable_attribute_mode(struct osd_state *sd)
+{
+       /* enable attribute mode for OSD1 */
+       osd_set(sd, OSD_OSDWIN1MD_OASW, OSD_OSDWIN1MD);
+}
+
+static void _osd_enable_layer(struct osd_state *sd, enum osd_layer layer)
+{
+       switch (layer) {
+       case WIN_OSD0:
+               osd_set(sd, OSD_OSDWIN0MD_OACT0, OSD_OSDWIN0MD);
+               break;
+       case WIN_VID0:
+               osd_set(sd, OSD_VIDWINMD_ACT0, OSD_VIDWINMD);
+               break;
+       case WIN_OSD1:
+               /* enable OSD1 and disable attribute mode */
+               osd_modify(sd, OSD_OSDWIN1MD_OASW | OSD_OSDWIN1MD_OACT1,
+                         OSD_OSDWIN1MD_OACT1, OSD_OSDWIN1MD);
+               break;
+       case WIN_VID1:
+               osd_set(sd, OSD_VIDWINMD_ACT1, OSD_VIDWINMD);
+               break;
+       }
+}
+
+static int osd_enable_layer(struct osd_state *sd, enum osd_layer layer,
+                           int otherwin)
+{
+       struct osd_state *osd = sd;
+       struct osd_window_state *win = &osd->win[layer];
+       struct osd_layer_config *cfg = &win->lconfig;
+       unsigned long flags;
+
+       spin_lock_irqsave(&osd->lock, flags);
+
+       /*
+        * use otherwin flag to know this is the other vid window
+        * in YUV420 mode, if is, skip this check
+        */
+       if (!otherwin && (!win->is_allocated ||
+                       !win->fb_base_phys ||
+                       !cfg->line_length ||
+                       !cfg->xsize ||
+                       !cfg->ysize)) {
+               spin_unlock_irqrestore(&osd->lock, flags);
+               return -1;
+       }
+
+       if (win->is_enabled) {
+               spin_unlock_irqrestore(&osd->lock, flags);
+               return 0;
+       }
+       win->is_enabled = 1;
+
+       if (cfg->pixfmt != PIXFMT_OSD_ATTR)
+               _osd_enable_layer(sd, layer);
+       else {
+               _osd_enable_attribute_mode(sd);
+               _osd_set_blink_attribute(sd, osd->is_blinking, osd->blink);
+       }
+
+       spin_unlock_irqrestore(&osd->lock, flags);
+
+       return 0;
+}
+
+static void _osd_start_layer(struct osd_state *sd, enum osd_layer layer,
+                            unsigned long fb_base_phys,
+                            unsigned long cbcr_ofst)
+{
+       switch (layer) {
+       case WIN_OSD0:
+               osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN0ADR);
+               break;
+       case WIN_VID0:
+               osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR);
+               break;
+       case WIN_OSD1:
+               osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN1ADR);
+               break;
+       case WIN_VID1:
+               osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN1ADR);
+               break;
+       }
+}
+
+static void osd_start_layer(struct osd_state *sd, enum osd_layer layer,
+                           unsigned long fb_base_phys,
+                           unsigned long cbcr_ofst)
+{
+       struct osd_state *osd = sd;
+       struct osd_window_state *win = &osd->win[layer];
+       struct osd_layer_config *cfg = &win->lconfig;
+       unsigned long flags;
+
+       spin_lock_irqsave(&osd->lock, flags);
+
+       win->fb_base_phys = fb_base_phys & ~0x1F;
+       _osd_start_layer(sd, layer, fb_base_phys, cbcr_ofst);
+
+       if (layer == WIN_VID0) {
+               osd->pingpong =
+                   _osd_dm6446_vid0_pingpong(sd, osd->field_inversion,
+                                                      win->fb_base_phys,
+                                                      cfg);
+       }
+
+       spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static void osd_get_layer_config(struct osd_state *sd, enum osd_layer layer,
+                                struct osd_layer_config *lconfig)
+{
+       struct osd_state *osd = sd;
+       struct osd_window_state *win = &osd->win[layer];
+       unsigned long flags;
+
+       spin_lock_irqsave(&osd->lock, flags);
+
+       *lconfig = win->lconfig;
+
+       spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+/**
+ * try_layer_config() - Try a specific configuration for the layer
+ * @sd  - ptr to struct osd_state
+ * @layer - layer to configure
+ * @lconfig - layer configuration to try
+ *
+ * If the requested lconfig is completely rejected and the value of lconfig on
+ * exit is the current lconfig, then try_layer_config() returns 1.  Otherwise,
+ * try_layer_config() returns 0.  A return value of 0 does not necessarily mean
+ * that the value of lconfig on exit is identical to the value of lconfig on
+ * entry, but merely that it represents a change from the current lconfig.
+ */
+static int try_layer_config(struct osd_state *sd, enum osd_layer layer,
+                           struct osd_layer_config *lconfig)
+{
+       struct osd_state *osd = sd;
+       struct osd_window_state *win = &osd->win[layer];
+       int bad_config;
+
+       /* verify that the pixel format is compatible with the layer */
+       switch (lconfig->pixfmt) {
+       case PIXFMT_1BPP:
+       case PIXFMT_2BPP:
+       case PIXFMT_4BPP:
+       case PIXFMT_8BPP:
+       case PIXFMT_RGB565:
+               bad_config = !is_osd_win(layer);
+               break;
+       case PIXFMT_YCbCrI:
+       case PIXFMT_YCrCbI:
+               bad_config = !is_vid_win(layer);
+               break;
+       case PIXFMT_RGB888:
+               bad_config = !is_vid_win(layer);
+               break;
+       case PIXFMT_NV12:
+               bad_config = 1;
+               break;
+       case PIXFMT_OSD_ATTR:
+               bad_config = (layer != WIN_OSD1);
+               break;
+       default:
+               bad_config = 1;
+               break;
+       }
+       if (bad_config) {
+               /*
+                * The requested pixel format is incompatible with the layer,
+                * so keep the current layer configuration.
+                */
+               *lconfig = win->lconfig;
+               return bad_config;
+       }
+
+       /* DM6446: */
+       /* only one OSD window at a time can use RGB pixel formats */
+       if (is_osd_win(layer) && is_rgb_pixfmt(lconfig->pixfmt)) {
+               enum osd_pix_format pixfmt;
+               if (layer == WIN_OSD0)
+                       pixfmt = osd->win[WIN_OSD1].lconfig.pixfmt;
+               else
+                       pixfmt = osd->win[WIN_OSD0].lconfig.pixfmt;
+
+               if (is_rgb_pixfmt(pixfmt)) {
+                       /*
+                        * The other OSD window is already configured for an
+                        * RGB, so keep the current layer configuration.
+                        */
+                       *lconfig = win->lconfig;
+                       return 1;
+               }
+       }
+
+       /* DM6446: only one video window at a time can use RGB888 */
+       if (is_vid_win(layer) && lconfig->pixfmt == PIXFMT_RGB888) {
+               enum osd_pix_format pixfmt;
+
+               if (layer == WIN_VID0)
+                       pixfmt = osd->win[WIN_VID1].lconfig.pixfmt;
+               else
+                       pixfmt = osd->win[WIN_VID0].lconfig.pixfmt;
+
+               if (pixfmt == PIXFMT_RGB888) {
+                       /*
+                        * The other video window is already configured for
+                        * RGB888, so keep the current layer configuration.
+                        */
+                       *lconfig = win->lconfig;
+                       return 1;
+               }
+       }
+
+       /* window dimensions must be non-zero */
+       if (!lconfig->line_length || !lconfig->xsize || !lconfig->ysize) {
+               *lconfig = win->lconfig;
+               return 1;
+       }
+
+       /* round line_length up to a multiple of 32 */
+       lconfig->line_length = ((lconfig->line_length + 31) / 32) * 32;
+       lconfig->line_length =
+           min(lconfig->line_length, (unsigned)MAX_LINE_LENGTH);
+       lconfig->xsize = min(lconfig->xsize, (unsigned)MAX_WIN_SIZE);
+       lconfig->ysize = min(lconfig->ysize, (unsigned)MAX_WIN_SIZE);
+       lconfig->xpos = min(lconfig->xpos, (unsigned)MAX_WIN_SIZE);
+       lconfig->ypos = min(lconfig->ypos, (unsigned)MAX_WIN_SIZE);
+       lconfig->interlaced = (lconfig->interlaced != 0);
+       if (lconfig->interlaced) {
+               /* ysize and ypos must be even for interlaced displays */
+               lconfig->ysize &= ~1;
+               lconfig->ypos &= ~1;
+       }
+
+       return 0;
+}
+
+static void _osd_disable_vid_rgb888(struct osd_state *sd)
+{
+       /*
+        * The DM6446 supports RGB888 pixel format in a single video window.
+        * This routine disables RGB888 pixel format for both video windows.
+        * The caller must ensure that neither video window is currently
+        * configured for RGB888 pixel format.
+        */
+       osd_clear(sd, OSD_MISCCTL_RGBEN, OSD_MISCCTL);
+}
+
+static void _osd_enable_vid_rgb888(struct osd_state *sd,
+                                  enum osd_layer layer)
+{
+       /*
+        * The DM6446 supports RGB888 pixel format in a single video window.
+        * This routine enables RGB888 pixel format for the specified video
+        * window.  The caller must ensure that the other video window is not
+        * currently configured for RGB888 pixel format, as this routine will
+        * disable RGB888 pixel format for the other window.
+        */
+       if (layer == WIN_VID0) {
+               osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN,
+                         OSD_MISCCTL_RGBEN, OSD_MISCCTL);
+       } else if (layer == WIN_VID1) {
+               osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN,
+                         OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN,
+                         OSD_MISCCTL);
+       }
+}
+
+static void _osd_set_cbcr_order(struct osd_state *sd,
+                               enum osd_pix_format pixfmt)
+{
+       /*
+        * The caller must ensure that all windows using YC pixfmt use the same
+        * Cb/Cr order.
+        */
+       if (pixfmt == PIXFMT_YCbCrI)
+               osd_clear(sd, OSD_MODE_CS, OSD_MODE);
+       else if (pixfmt == PIXFMT_YCrCbI)
+               osd_set(sd, OSD_MODE_CS, OSD_MODE);
+}
+
+static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer,
+                                 const struct osd_layer_config *lconfig)
+{
+       u32 winmd = 0, winmd_mask = 0, bmw = 0;
+
+       _osd_set_cbcr_order(sd, lconfig->pixfmt);
+
+       switch (layer) {
+       case WIN_OSD0:
+               winmd_mask |= OSD_OSDWIN0MD_RGB0E;
+               if (lconfig->pixfmt == PIXFMT_RGB565)
+                       winmd |= OSD_OSDWIN0MD_RGB0E;
+
+               winmd_mask |= OSD_OSDWIN0MD_BMW0 | OSD_OSDWIN0MD_OFF0;
+
+               switch (lconfig->pixfmt) {
+               case PIXFMT_1BPP:
+                       bmw = 0;
+                       break;
+               case PIXFMT_2BPP:
+                       bmw = 1;
+                       break;
+               case PIXFMT_4BPP:
+                       bmw = 2;
+                       break;
+               case PIXFMT_8BPP:
+                       bmw = 3;
+                       break;
+               default:
+                       break;
+               }
+               winmd |= (bmw << OSD_OSDWIN0MD_BMW0_SHIFT);
+
+               if (lconfig->interlaced)
+                       winmd |= OSD_OSDWIN0MD_OFF0;
+
+               osd_modify(sd, winmd_mask, winmd, OSD_OSDWIN0MD);
+               osd_write(sd, lconfig->line_length >> 5, OSD_OSDWIN0OFST);
+               osd_write(sd, lconfig->xpos, OSD_OSDWIN0XP);
+               osd_write(sd, lconfig->xsize, OSD_OSDWIN0XL);
+               if (lconfig->interlaced) {
+                       osd_write(sd, lconfig->ypos >> 1, OSD_OSDWIN0YP);
+                       osd_write(sd, lconfig->ysize >> 1, OSD_OSDWIN0YL);
+               } else {
+                       osd_write(sd, lconfig->ypos, OSD_OSDWIN0YP);
+                       osd_write(sd, lconfig->ysize, OSD_OSDWIN0YL);
+               }
+               break;
+       case WIN_VID0:
+               winmd_mask |= OSD_VIDWINMD_VFF0;
+               if (lconfig->interlaced)
+                       winmd |= OSD_VIDWINMD_VFF0;
+
+               osd_modify(sd, winmd_mask, winmd, OSD_VIDWINMD);
+               osd_write(sd, lconfig->line_length >> 5, OSD_VIDWIN0OFST);
+               osd_write(sd, lconfig->xpos, OSD_VIDWIN0XP);
+               osd_write(sd, lconfig->xsize, OSD_VIDWIN0XL);
+               /*
+                * For YUV420P format the register contents are
+                * duplicated in both VID registers
+                */
+               if (lconfig->interlaced) {
+                       osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN0YP);
+                       osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN0YL);
+               } else {
+                       osd_write(sd, lconfig->ypos, OSD_VIDWIN0YP);
+                       osd_write(sd, lconfig->ysize, OSD_VIDWIN0YL);
+               }
+               break;
+       case WIN_OSD1:
+               /*
+                * The caller must ensure that OSD1 is disabled prior to
+                * switching from a normal mode to attribute mode or from
+                * attribute mode to a normal mode.
+                */
+               if (lconfig->pixfmt == PIXFMT_OSD_ATTR) {
+                       winmd_mask |=
+                           OSD_OSDWIN1MD_ATN1E | OSD_OSDWIN1MD_RGB1E |
+                           OSD_OSDWIN1MD_CLUTS1 |
+                           OSD_OSDWIN1MD_BLND1 | OSD_OSDWIN1MD_TE1;
+               } else {
+                       winmd_mask |= OSD_OSDWIN1MD_RGB1E;
+                       if (lconfig->pixfmt == PIXFMT_RGB565)
+                               winmd |= OSD_OSDWIN1MD_RGB1E;
+
+                       winmd_mask |= OSD_OSDWIN1MD_BMW1;
+                       switch (lconfig->pixfmt) {
+                       case PIXFMT_1BPP:
+                               bmw = 0;
+                               break;
+                       case PIXFMT_2BPP:
+                               bmw = 1;
+                               break;
+                       case PIXFMT_4BPP:
+                               bmw = 2;
+                               break;
+                       case PIXFMT_8BPP:
+                               bmw = 3;
+                               break;
+                       default:
+                               break;
+                       }
+                       winmd |= (bmw << OSD_OSDWIN1MD_BMW1_SHIFT);
+               }
+
+               winmd_mask |= OSD_OSDWIN1MD_OFF1;
+               if (lconfig->interlaced)
+                       winmd |= OSD_OSDWIN1MD_OFF1;
+
+               osd_modify(sd, winmd_mask, winmd, OSD_OSDWIN1MD);
+               osd_write(sd, lconfig->line_length >> 5, OSD_OSDWIN1OFST);
+               osd_write(sd, lconfig->xpos, OSD_OSDWIN1XP);
+               osd_write(sd, lconfig->xsize, OSD_OSDWIN1XL);
+               if (lconfig->interlaced) {
+                       osd_write(sd, lconfig->ypos >> 1, OSD_OSDWIN1YP);
+                       osd_write(sd, lconfig->ysize >> 1, OSD_OSDWIN1YL);
+               } else {
+                       osd_write(sd, lconfig->ypos, OSD_OSDWIN1YP);
+                       osd_write(sd, lconfig->ysize, OSD_OSDWIN1YL);
+               }
+               break;
+       case WIN_VID1:
+               winmd_mask |= OSD_VIDWINMD_VFF1;
+               if (lconfig->interlaced)
+                       winmd |= OSD_VIDWINMD_VFF1;
+
+               osd_modify(sd, winmd_mask, winmd, OSD_VIDWINMD);
+               osd_write(sd, lconfig->line_length >> 5, OSD_VIDWIN1OFST);
+               osd_write(sd, lconfig->xpos, OSD_VIDWIN1XP);
+               osd_write(sd, lconfig->xsize, OSD_VIDWIN1XL);
+               /*
+                * For YUV420P format the register contents are
+                * duplicated in both VID registers
+                */
+               osd_modify(sd, OSD_MISCCTL_S420D, ~OSD_MISCCTL_S420D,
+                          OSD_MISCCTL);
+
+               if (lconfig->interlaced) {
+                       osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN1YP);
+                       osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN1YL);
+               } else {
+                       osd_write(sd, lconfig->ypos, OSD_VIDWIN1YP);
+                       osd_write(sd, lconfig->ysize, OSD_VIDWIN1YL);
+               }
+               break;
+       }
+}
+
+static int osd_set_layer_config(struct osd_state *sd, enum osd_layer layer,
+                               struct osd_layer_config *lconfig)
+{
+       struct osd_state *osd = sd;
+       struct osd_window_state *win = &osd->win[layer];
+       struct osd_layer_config *cfg = &win->lconfig;
+       unsigned long flags;
+       int reject_config;
+
+       spin_lock_irqsave(&osd->lock, flags);
+
+       reject_config = try_layer_config(sd, layer, lconfig);
+       if (reject_config) {
+               spin_unlock_irqrestore(&osd->lock, flags);
+               return reject_config;
+       }
+
+       /* update the current Cb/Cr order */
+       if (is_yc_pixfmt(lconfig->pixfmt))
+               osd->yc_pixfmt = lconfig->pixfmt;
+
+       /*
+        * If we are switching OSD1 from normal mode to attribute mode or from
+        * attribute mode to normal mode, then we must disable the window.
+        */
+       if (layer == WIN_OSD1) {
+               if (((lconfig->pixfmt == PIXFMT_OSD_ATTR) &&
+                 (cfg->pixfmt != PIXFMT_OSD_ATTR)) ||
+                 ((lconfig->pixfmt != PIXFMT_OSD_ATTR) &&
+                 (cfg->pixfmt == PIXFMT_OSD_ATTR))) {
+                       win->is_enabled = 0;
+                       _osd_disable_layer(sd, layer);
+               }
+       }
+
+       _osd_set_layer_config(sd, layer, lconfig);
+
+       if (layer == WIN_OSD1) {
+               struct osd_osdwin_state *osdwin_state =
+                   &osd->osdwin[OSDWIN_OSD1];
+
+               if ((lconfig->pixfmt != PIXFMT_OSD_ATTR) &&
+                 (cfg->pixfmt == PIXFMT_OSD_ATTR)) {
+                       /*
+                        * We just switched OSD1 from attribute mode to normal
+                        * mode, so we must initialize the CLUT select, the
+                        * blend factor, transparency colorkey enable, and
+                        * attenuation enable (DM6446 only) bits in the
+                        * OSDWIN1MD register.
+                        */
+                       _osd_set_osd_clut(sd, OSDWIN_OSD1,
+                                                  osdwin_state->clut);
+                       _osd_set_blending_factor(sd, OSDWIN_OSD1,
+                                                         osdwin_state->blend);
+                       if (osdwin_state->colorkey_blending) {
+                               _osd_enable_color_key(sd, OSDWIN_OSD1,
+                                                              osdwin_state->
+                                                              colorkey,
+                                                              lconfig->pixfmt);
+                       } else
+                               _osd_disable_color_key(sd, OSDWIN_OSD1);
+                       _osd_set_rec601_attenuation(sd, OSDWIN_OSD1,
+                                                   osdwin_state->
+                                                   rec601_attenuation);
+               } else if ((lconfig->pixfmt == PIXFMT_OSD_ATTR) &&
+                 (cfg->pixfmt != PIXFMT_OSD_ATTR)) {
+                       /*
+                        * We just switched OSD1 from normal mode to attribute
+                        * mode, so we must initialize the blink enable and
+                        * blink interval bits in the OSDATRMD register.
+                        */
+                       _osd_set_blink_attribute(sd, osd->is_blinking,
+                                                         osd->blink);
+               }
+       }
+
+       /*
+        * If we just switched to a 1-, 2-, or 4-bits-per-pixel bitmap format
+        * then configure a default palette map.
+        */
+       if ((lconfig->pixfmt != cfg->pixfmt) &&
+         ((lconfig->pixfmt == PIXFMT_1BPP) ||
+         (lconfig->pixfmt == PIXFMT_2BPP) ||
+         (lconfig->pixfmt == PIXFMT_4BPP))) {
+               enum osd_win_layer osdwin =
+                   ((layer == WIN_OSD0) ? OSDWIN_OSD0 : OSDWIN_OSD1);
+               struct osd_osdwin_state *osdwin_state =
+                   &osd->osdwin[osdwin];
+               unsigned char clut_index;
+               unsigned char clut_entries = 0;
+
+               switch (lconfig->pixfmt) {
+               case PIXFMT_1BPP:
+                       clut_entries = 2;
+                       break;
+               case PIXFMT_2BPP:
+                       clut_entries = 4;
+                       break;
+               case PIXFMT_4BPP:
+                       clut_entries = 16;
+                       break;
+               default:
+                       break;
+               }
+               /*
+                * The default palette map maps the pixel value to the clut
+                * index, i.e. pixel value 0 maps to clut entry 0, pixel value
+                * 1 maps to clut entry 1, etc.
+                */
+               for (clut_index = 0; clut_index < 16; clut_index++) {
+                       osdwin_state->palette_map[clut_index] = clut_index;
+                       if (clut_index < clut_entries) {
+                               _osd_set_palette_map(sd, osdwin, clut_index,
+                                                    clut_index,
+                                                    lconfig->pixfmt);
+                       }
+               }
+       }
+
+       *cfg = *lconfig;
+       /* DM6446: configure the RGB888 enable and window selection */
+       if (osd->win[WIN_VID0].lconfig.pixfmt == PIXFMT_RGB888)
+               _osd_enable_vid_rgb888(sd, WIN_VID0);
+       else if (osd->win[WIN_VID1].lconfig.pixfmt == PIXFMT_RGB888)
+               _osd_enable_vid_rgb888(sd, WIN_VID1);
+       else
+               _osd_disable_vid_rgb888(sd);
+
+       if (layer == WIN_VID0) {
+               osd->pingpong =
+                   _osd_dm6446_vid0_pingpong(sd, osd->field_inversion,
+                                                      win->fb_base_phys,
+                                                      cfg);
+       }
+
+       spin_unlock_irqrestore(&osd->lock, flags);
+
+       return 0;
+}
+
+static void osd_init_layer(struct osd_state *sd, enum osd_layer layer)
+{
+       struct osd_state *osd = sd;
+       struct osd_window_state *win = &osd->win[layer];
+       enum osd_win_layer osdwin;
+       struct osd_osdwin_state *osdwin_state;
+       struct osd_layer_config *cfg = &win->lconfig;
+       unsigned long flags;
+
+       spin_lock_irqsave(&osd->lock, flags);
+
+       win->is_enabled = 0;
+       _osd_disable_layer(sd, layer);
+
+       win->h_zoom = ZOOM_X1;
+       win->v_zoom = ZOOM_X1;
+       _osd_set_zoom(sd, layer, win->h_zoom, win->v_zoom);
+
+       win->fb_base_phys = 0;
+       _osd_start_layer(sd, layer, win->fb_base_phys, 0);
+
+       cfg->line_length = 0;
+       cfg->xsize = 0;
+       cfg->ysize = 0;
+       cfg->xpos = 0;
+       cfg->ypos = 0;
+       cfg->interlaced = 0;
+       switch (layer) {
+       case WIN_OSD0:
+       case WIN_OSD1:
+               osdwin = (layer == WIN_OSD0) ? OSDWIN_OSD0 : OSDWIN_OSD1;
+               osdwin_state = &osd->osdwin[osdwin];
+               /*
+                * Other code relies on the fact that OSD windows default to a
+                * bitmap pixel format when they are deallocated, so don't
+                * change this default pixel format.
+                */
+               cfg->pixfmt = PIXFMT_8BPP;
+               _osd_set_layer_config(sd, layer, cfg);
+               osdwin_state->clut = RAM_CLUT;
+               _osd_set_osd_clut(sd, osdwin, osdwin_state->clut);
+               osdwin_state->colorkey_blending = 0;
+               _osd_disable_color_key(sd, osdwin);
+               osdwin_state->blend = OSD_8_VID_0;
+               _osd_set_blending_factor(sd, osdwin, osdwin_state->blend);
+               osdwin_state->rec601_attenuation = 0;
+               _osd_set_rec601_attenuation(sd, osdwin,
+                                                    osdwin_state->
+                                                    rec601_attenuation);
+               if (osdwin == OSDWIN_OSD1) {
+                       osd->is_blinking = 0;
+                       osd->blink = BLINK_X1;
+               }
+               break;
+       case WIN_VID0:
+       case WIN_VID1:
+               cfg->pixfmt = osd->yc_pixfmt;
+               _osd_set_layer_config(sd, layer, cfg);
+               break;
+       }
+
+       spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static void osd_release_layer(struct osd_state *sd, enum osd_layer layer)
+{
+       struct osd_state *osd = sd;
+       struct osd_window_state *win = &osd->win[layer];
+       unsigned long flags;
+
+       spin_lock_irqsave(&osd->lock, flags);
+
+       if (!win->is_allocated) {
+               spin_unlock_irqrestore(&osd->lock, flags);
+               return;
+       }
+
+       spin_unlock_irqrestore(&osd->lock, flags);
+       osd_init_layer(sd, layer);
+       spin_lock_irqsave(&osd->lock, flags);
+
+       win->is_allocated = 0;
+
+       spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static int osd_request_layer(struct osd_state *sd, enum osd_layer layer)
+{
+       struct osd_state *osd = sd;
+       struct osd_window_state *win = &osd->win[layer];
+       unsigned long flags;
+
+       spin_lock_irqsave(&osd->lock, flags);
+
+       if (win->is_allocated) {
+               spin_unlock_irqrestore(&osd->lock, flags);
+               return -1;
+       }
+       win->is_allocated = 1;
+
+       spin_unlock_irqrestore(&osd->lock, flags);
+
+       return 0;
+}
+
+static void _osd_init(struct osd_state *sd)
+{
+       osd_write(sd, 0, OSD_MODE);
+       osd_write(sd, 0, OSD_VIDWINMD);
+       osd_write(sd, 0, OSD_OSDWIN0MD);
+       osd_write(sd, 0, OSD_OSDWIN1MD);
+       osd_write(sd, 0, OSD_RECTCUR);
+       osd_write(sd, 0, OSD_MISCCTL);
+}
+
+static void osd_set_left_margin(struct osd_state *sd, u32 val)
+{
+       osd_write(sd, val, OSD_BASEPX);
+}
+
+static void osd_set_top_margin(struct osd_state *sd, u32 val)
+{
+       osd_write(sd, val, OSD_BASEPY);
+}
+
+static int osd_initialize(struct osd_state *osd)
+{
+       if (osd == NULL)
+               return -ENODEV;
+       _osd_init(osd);
+
+       /* set default Cb/Cr order */
+       osd->yc_pixfmt = PIXFMT_YCbCrI;
+
+       _osd_set_field_inversion(osd, osd->field_inversion);
+       _osd_set_rom_clut(osd, osd->rom_clut);
+
+       osd_init_layer(osd, WIN_OSD0);
+       osd_init_layer(osd, WIN_VID0);
+       osd_init_layer(osd, WIN_OSD1);
+       osd_init_layer(osd, WIN_VID1);
+
+       return 0;
+}
+
+static const struct vpbe_osd_ops osd_ops = {
+       .initialize = osd_initialize,
+       .request_layer = osd_request_layer,
+       .release_layer = osd_release_layer,
+       .enable_layer = osd_enable_layer,
+       .disable_layer = osd_disable_layer,
+       .set_layer_config = osd_set_layer_config,
+       .get_layer_config = osd_get_layer_config,
+       .start_layer = osd_start_layer,
+       .set_left_margin = osd_set_left_margin,
+       .set_top_margin = osd_set_top_margin,
+};
+
+static int osd_probe(struct platform_device *pdev)
+{
+       struct osd_platform_data *pdata;
+       struct osd_state *osd;
+       struct resource *res;
+       int ret = 0;
+
+       osd = kzalloc(sizeof(struct osd_state), GFP_KERNEL);
+       if (osd == NULL)
+               return -ENOMEM;
+
+       osd->dev = &pdev->dev;
+       pdata = (struct osd_platform_data *)pdev->dev.platform_data;
+       osd->vpbe_type = (enum vpbe_version)pdata->vpbe_type;
+       if (NULL == pdev->dev.platform_data) {
+               dev_err(osd->dev, "No platform data defined for OSD"
+                       " sub device\n");
+               ret = -ENOENT;
+               goto free_mem;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(osd->dev, "Unable to get OSD register address map\n");
+               ret = -ENODEV;
+               goto free_mem;
+       }
+       osd->osd_base_phys = res->start;
+       osd->osd_size = res->end - res->start + 1;
+       if (!request_mem_region(osd->osd_base_phys, osd->osd_size,
+                               MODULE_NAME)) {
+               dev_err(osd->dev, "Unable to reserve OSD MMIO region\n");
+               ret = -ENODEV;
+               goto free_mem;
+       }
+       osd->osd_base = (unsigned long)ioremap_nocache(res->start,
+                                                       osd->osd_size);
+       if (!osd->osd_base) {
+               dev_err(osd->dev, "Unable to map the OSD region\n");
+               ret = -ENODEV;
+               goto release_mem_region;
+       }
+       spin_lock_init(&osd->lock);
+       osd->ops = osd_ops;
+       platform_set_drvdata(pdev, osd);
+       dev_notice(osd->dev, "OSD sub device probe success\n");
+       return ret;
+
+release_mem_region:
+       release_mem_region(osd->osd_base_phys, osd->osd_size);
+free_mem:
+       kfree(osd);
+       return ret;
+}
+
+static int osd_remove(struct platform_device *pdev)
+{
+       struct osd_state *osd = platform_get_drvdata(pdev);
+
+       iounmap((void *)osd->osd_base);
+       release_mem_region(osd->osd_base_phys, osd->osd_size);
+       kfree(osd);
+       return 0;
+}
+
+static struct platform_driver osd_driver = {
+       .probe          = osd_probe,
+       .remove         = osd_remove,
+       .driver         = {
+               .name   = MODULE_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int osd_init(void)
+{
+       if (platform_driver_register(&osd_driver)) {
+               printk(KERN_ERR "Unable to register davinci osd driver\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void osd_exit(void)
+{
+       platform_driver_unregister(&osd_driver);
+}
+
+module_init(osd_init);
+module_exit(osd_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("DaVinci OSD Manager Driver");
+MODULE_AUTHOR("Texas Instruments");
diff --git a/drivers/media/video/davinci/vpbe_osd_regs.h b/drivers/media/video/davinci/vpbe_osd_regs.h
new file mode 100644 (file)
index 0000000..584520f
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2006-2010 Texas Instruments 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _VPBE_OSD_REGS_H
+#define _VPBE_OSD_REGS_H
+
+/* VPBE Global Registers */
+#define VPBE_PID                               0x0
+#define VPBE_PCR                               0x4
+
+/* VPSS CLock Registers */
+#define VPSSCLK_PID                            0x00
+#define VPSSCLK_CLKCTRL                                0x04
+
+/* VPSS Buffer Logic Registers */
+#define VPSSBL_PID                             0x00
+#define VPSSBL_PCR                             0x04
+#define VPSSBL_BCR                             0x08
+#define VPSSBL_INTSTAT                         0x0C
+#define VPSSBL_INTSEL                          0x10
+#define VPSSBL_EVTSEL                          0x14
+#define VPSSBL_MEMCTRL                         0x18
+#define VPSSBL_CCDCMUX                         0x1C
+
+/* DM365 ISP5 system configuration */
+#define ISP5_PID                               0x0
+#define ISP5_PCCR                              0x4
+#define ISP5_BCR                               0x8
+#define ISP5_INTSTAT                           0xC
+#define ISP5_INTSEL1                           0x10
+#define ISP5_INTSEL2                           0x14
+#define ISP5_INTSEL3                           0x18
+#define ISP5_EVTSEL                            0x1c
+#define ISP5_CCDCMUX                           0x20
+
+/* VPBE On-Screen Display Subsystem Registers (OSD) */
+#define OSD_MODE                               0x00
+#define OSD_VIDWINMD                           0x04
+#define OSD_OSDWIN0MD                          0x08
+#define OSD_OSDWIN1MD                          0x0C
+#define OSD_OSDATRMD                           0x0C
+#define OSD_RECTCUR                            0x10
+#define OSD_VIDWIN0OFST                                0x18
+#define OSD_VIDWIN1OFST                                0x1C
+#define OSD_OSDWIN0OFST                                0x20
+#define OSD_OSDWIN1OFST                                0x24
+#define OSD_VIDWINADH                          0x28
+#define OSD_VIDWIN0ADL                         0x2C
+#define OSD_VIDWIN0ADR                         0x2C
+#define OSD_VIDWIN1ADL                         0x30
+#define OSD_VIDWIN1ADR                         0x30
+#define OSD_OSDWINADH                          0x34
+#define OSD_OSDWIN0ADL                         0x38
+#define OSD_OSDWIN0ADR                         0x38
+#define OSD_OSDWIN1ADL                         0x3C
+#define OSD_OSDWIN1ADR                         0x3C
+#define OSD_BASEPX                             0x40
+#define OSD_BASEPY                             0x44
+#define OSD_VIDWIN0XP                          0x48
+#define OSD_VIDWIN0YP                          0x4C
+#define OSD_VIDWIN0XL                          0x50
+#define OSD_VIDWIN0YL                          0x54
+#define OSD_VIDWIN1XP                          0x58
+#define OSD_VIDWIN1YP                          0x5C
+#define OSD_VIDWIN1XL                          0x60
+#define OSD_VIDWIN1YL                          0x64
+#define OSD_OSDWIN0XP                          0x68
+#define OSD_OSDWIN0YP                          0x6C
+#define OSD_OSDWIN0XL                          0x70
+#define OSD_OSDWIN0YL                          0x74
+#define OSD_OSDWIN1XP                          0x78
+#define OSD_OSDWIN1YP                          0x7C
+#define OSD_OSDWIN1XL                          0x80
+#define OSD_OSDWIN1YL                          0x84
+#define OSD_CURXP                              0x88
+#define OSD_CURYP                              0x8C
+#define OSD_CURXL                              0x90
+#define OSD_CURYL                              0x94
+#define OSD_W0BMP01                            0xA0
+#define OSD_W0BMP23                            0xA4
+#define OSD_W0BMP45                            0xA8
+#define OSD_W0BMP67                            0xAC
+#define OSD_W0BMP89                            0xB0
+#define OSD_W0BMPAB                            0xB4
+#define OSD_W0BMPCD                            0xB8
+#define OSD_W0BMPEF                            0xBC
+#define OSD_W1BMP01                            0xC0
+#define OSD_W1BMP23                            0xC4
+#define OSD_W1BMP45                            0xC8
+#define OSD_W1BMP67                            0xCC
+#define OSD_W1BMP89                            0xD0
+#define OSD_W1BMPAB                            0xD4
+#define OSD_W1BMPCD                            0xD8
+#define OSD_W1BMPEF                            0xDC
+#define OSD_VBNDRY                             0xE0
+#define OSD_EXTMODE                            0xE4
+#define OSD_MISCCTL                            0xE8
+#define OSD_CLUTRAMYCB                         0xEC
+#define OSD_CLUTRAMCR                          0xF0
+#define OSD_TRANSPVAL                          0xF4
+#define OSD_TRANSPVALL                         0xF4
+#define OSD_TRANSPVALU                         0xF8
+#define OSD_TRANSPBMPIDX                       0xFC
+#define OSD_PPVWIN0ADR                         0xFC
+
+/* bit definitions */
+#define VPBE_PCR_VENC_DIV                      (1 << 1)
+#define VPBE_PCR_CLK_OFF                       (1 << 0)
+
+#define VPSSBL_INTSTAT_HSSIINT                 (1 << 14)
+#define VPSSBL_INTSTAT_CFALDINT                        (1 << 13)
+#define VPSSBL_INTSTAT_IPIPE_INT5              (1 << 12)
+#define VPSSBL_INTSTAT_IPIPE_INT4              (1 << 11)
+#define VPSSBL_INTSTAT_IPIPE_INT3              (1 << 10)
+#define VPSSBL_INTSTAT_IPIPE_INT2              (1 << 9)
+#define VPSSBL_INTSTAT_IPIPE_INT1              (1 << 8)
+#define VPSSBL_INTSTAT_IPIPE_INT0              (1 << 7)
+#define VPSSBL_INTSTAT_IPIPEIFINT              (1 << 6)
+#define VPSSBL_INTSTAT_OSDINT                  (1 << 5)
+#define VPSSBL_INTSTAT_VENCINT                 (1 << 4)
+#define VPSSBL_INTSTAT_H3AINT                  (1 << 3)
+#define VPSSBL_INTSTAT_CCDC_VDINT2             (1 << 2)
+#define VPSSBL_INTSTAT_CCDC_VDINT1             (1 << 1)
+#define VPSSBL_INTSTAT_CCDC_VDINT0             (1 << 0)
+
+/* DM365 ISP5 bit definitions */
+#define ISP5_INTSTAT_VENCINT                   (1 << 21)
+#define ISP5_INTSTAT_OSDINT                    (1 << 20)
+
+/* VMOD TVTYP options for HDMD=0 */
+#define SDTV_NTSC                              0
+#define SDTV_PAL                               1
+/* VMOD TVTYP options for HDMD=1 */
+#define HDTV_525P                              0
+#define HDTV_625P                              1
+#define HDTV_1080I                             2
+#define HDTV_720P                              3
+
+#define OSD_MODE_CS                            (1 << 15)
+#define OSD_MODE_OVRSZ                         (1 << 14)
+#define OSD_MODE_OHRSZ                         (1 << 13)
+#define OSD_MODE_EF                            (1 << 12)
+#define OSD_MODE_VVRSZ                         (1 << 11)
+#define OSD_MODE_VHRSZ                         (1 << 10)
+#define OSD_MODE_FSINV                         (1 << 9)
+#define OSD_MODE_BCLUT                         (1 << 8)
+#define OSD_MODE_CABG_SHIFT                    0
+#define OSD_MODE_CABG                          (0xff << 0)
+
+#define OSD_VIDWINMD_VFINV                     (1 << 15)
+#define OSD_VIDWINMD_V1EFC                     (1 << 14)
+#define OSD_VIDWINMD_VHZ1_SHIFT                        12
+#define OSD_VIDWINMD_VHZ1                      (3 << 12)
+#define OSD_VIDWINMD_VVZ1_SHIFT                        10
+#define OSD_VIDWINMD_VVZ1                      (3 << 10)
+#define OSD_VIDWINMD_VFF1                      (1 << 9)
+#define OSD_VIDWINMD_ACT1                      (1 << 8)
+#define OSD_VIDWINMD_V0EFC                     (1 << 6)
+#define OSD_VIDWINMD_VHZ0_SHIFT                        4
+#define OSD_VIDWINMD_VHZ0                      (3 << 4)
+#define OSD_VIDWINMD_VVZ0_SHIFT                        2
+#define OSD_VIDWINMD_VVZ0                      (3 << 2)
+#define OSD_VIDWINMD_VFF0                      (1 << 1)
+#define OSD_VIDWINMD_ACT0                      (1 << 0)
+
+#define OSD_OSDWIN0MD_ATN0E                    (1 << 14)
+#define OSD_OSDWIN0MD_RGB0E                    (1 << 13)
+#define OSD_OSDWIN0MD_BMP0MD_SHIFT             13
+#define OSD_OSDWIN0MD_BMP0MD                   (3 << 13)
+#define OSD_OSDWIN0MD_CLUTS0                   (1 << 12)
+#define OSD_OSDWIN0MD_OHZ0_SHIFT               10
+#define OSD_OSDWIN0MD_OHZ0                     (3 << 10)
+#define OSD_OSDWIN0MD_OVZ0_SHIFT               8
+#define OSD_OSDWIN0MD_OVZ0                     (3 << 8)
+#define OSD_OSDWIN0MD_BMW0_SHIFT               6
+#define OSD_OSDWIN0MD_BMW0                     (3 << 6)
+#define OSD_OSDWIN0MD_BLND0_SHIFT              3
+#define OSD_OSDWIN0MD_BLND0                    (7 << 3)
+#define OSD_OSDWIN0MD_TE0                      (1 << 2)
+#define OSD_OSDWIN0MD_OFF0                     (1 << 1)
+#define OSD_OSDWIN0MD_OACT0                    (1 << 0)
+
+#define OSD_OSDWIN1MD_OASW                     (1 << 15)
+#define OSD_OSDWIN1MD_ATN1E                    (1 << 14)
+#define OSD_OSDWIN1MD_RGB1E                    (1 << 13)
+#define OSD_OSDWIN1MD_BMP1MD_SHIFT             13
+#define OSD_OSDWIN1MD_BMP1MD                   (3 << 13)
+#define OSD_OSDWIN1MD_CLUTS1                   (1 << 12)
+#define OSD_OSDWIN1MD_OHZ1_SHIFT               10
+#define OSD_OSDWIN1MD_OHZ1                     (3 << 10)
+#define OSD_OSDWIN1MD_OVZ1_SHIFT               8
+#define OSD_OSDWIN1MD_OVZ1                     (3 << 8)
+#define OSD_OSDWIN1MD_BMW1_SHIFT               6
+#define OSD_OSDWIN1MD_BMW1                     (3 << 6)
+#define OSD_OSDWIN1MD_BLND1_SHIFT              3
+#define OSD_OSDWIN1MD_BLND1                    (7 << 3)
+#define OSD_OSDWIN1MD_TE1                      (1 << 2)
+#define OSD_OSDWIN1MD_OFF1                     (1 << 1)
+#define OSD_OSDWIN1MD_OACT1                    (1 << 0)
+
+#define OSD_OSDATRMD_OASW                      (1 << 15)
+#define OSD_OSDATRMD_OHZA_SHIFT                        10
+#define OSD_OSDATRMD_OHZA                      (3 << 10)
+#define OSD_OSDATRMD_OVZA_SHIFT                        8
+#define OSD_OSDATRMD_OVZA                      (3 << 8)
+#define OSD_OSDATRMD_BLNKINT_SHIFT             6
+#define OSD_OSDATRMD_BLNKINT                   (3 << 6)
+#define OSD_OSDATRMD_OFFA                      (1 << 1)
+#define OSD_OSDATRMD_BLNK                      (1 << 0)
+
+#define OSD_RECTCUR_RCAD_SHIFT                 8
+#define OSD_RECTCUR_RCAD                       (0xff << 8)
+#define OSD_RECTCUR_CLUTSR                     (1 << 7)
+#define OSD_RECTCUR_RCHW_SHIFT                 4
+#define OSD_RECTCUR_RCHW                       (7 << 4)
+#define OSD_RECTCUR_RCVW_SHIFT                 1
+#define OSD_RECTCUR_RCVW                       (7 << 1)
+#define OSD_RECTCUR_RCACT                      (1 << 0)
+
+#define OSD_VIDWIN0OFST_V0LO                   (0x1ff << 0)
+
+#define OSD_VIDWIN1OFST_V1LO                   (0x1ff << 0)
+
+#define OSD_OSDWIN0OFST_O0LO                   (0x1ff << 0)
+
+#define OSD_OSDWIN1OFST_O1LO                   (0x1ff << 0)
+
+#define OSD_WINOFST_AH_SHIFT                   9
+
+#define OSD_VIDWIN0OFST_V0AH                   (0xf << 9)
+#define OSD_VIDWIN1OFST_V1AH                   (0xf << 9)
+#define OSD_OSDWIN0OFST_O0AH                   (0xf << 9)
+#define OSD_OSDWIN1OFST_O1AH                   (0xf << 9)
+
+#define OSD_VIDWINADH_V1AH_SHIFT               8
+#define OSD_VIDWINADH_V1AH                     (0x7f << 8)
+#define OSD_VIDWINADH_V0AH_SHIFT               0
+#define OSD_VIDWINADH_V0AH                     (0x7f << 0)
+
+#define OSD_VIDWIN0ADL_V0AL                    (0xffff << 0)
+
+#define OSD_VIDWIN1ADL_V1AL                    (0xffff << 0)
+
+#define OSD_OSDWINADH_O1AH_SHIFT               8
+#define OSD_OSDWINADH_O1AH                     (0x7f << 8)
+#define OSD_OSDWINADH_O0AH_SHIFT               0
+#define OSD_OSDWINADH_O0AH                     (0x7f << 0)
+
+#define OSD_OSDWIN0ADL_O0AL                    (0xffff << 0)
+
+#define OSD_OSDWIN1ADL_O1AL                    (0xffff << 0)
+
+#define OSD_BASEPX_BPX                         (0x3ff << 0)
+
+#define OSD_BASEPY_BPY                         (0x1ff << 0)
+
+#define OSD_VIDWIN0XP_V0X                      (0x7ff << 0)
+
+#define OSD_VIDWIN0YP_V0Y                      (0x7ff << 0)
+
+#define OSD_VIDWIN0XL_V0W                      (0x7ff << 0)
+
+#define OSD_VIDWIN0YL_V0H                      (0x7ff << 0)
+
+#define OSD_VIDWIN1XP_V1X                      (0x7ff << 0)
+
+#define OSD_VIDWIN1YP_V1Y                      (0x7ff << 0)
+
+#define OSD_VIDWIN1XL_V1W                      (0x7ff << 0)
+
+#define OSD_VIDWIN1YL_V1H                      (0x7ff << 0)
+
+#define OSD_OSDWIN0XP_W0X                      (0x7ff << 0)
+
+#define OSD_OSDWIN0YP_W0Y                      (0x7ff << 0)
+
+#define OSD_OSDWIN0XL_W0W                      (0x7ff << 0)
+
+#define OSD_OSDWIN0YL_W0H                      (0x7ff << 0)
+
+#define OSD_OSDWIN1XP_W1X                      (0x7ff << 0)
+
+#define OSD_OSDWIN1YP_W1Y                      (0x7ff << 0)
+
+#define OSD_OSDWIN1XL_W1W                      (0x7ff << 0)
+
+#define OSD_OSDWIN1YL_W1H                      (0x7ff << 0)
+
+#define OSD_CURXP_RCSX                         (0x7ff << 0)
+
+#define OSD_CURYP_RCSY                         (0x7ff << 0)
+
+#define OSD_CURXL_RCSW                         (0x7ff << 0)
+
+#define OSD_CURYL_RCSH                         (0x7ff << 0)
+
+#define OSD_EXTMODE_EXPMDSEL                   (1 << 15)
+#define OSD_EXTMODE_SCRNHEXP_SHIFT             13
+#define OSD_EXTMODE_SCRNHEXP                   (3 << 13)
+#define OSD_EXTMODE_SCRNVEXP                   (1 << 12)
+#define OSD_EXTMODE_OSD1BLDCHR                 (1 << 11)
+#define OSD_EXTMODE_OSD0BLDCHR                 (1 << 10)
+#define OSD_EXTMODE_ATNOSD1EN                  (1 << 9)
+#define OSD_EXTMODE_ATNOSD0EN                  (1 << 8)
+#define OSD_EXTMODE_OSDHRSZ15                  (1 << 7)
+#define OSD_EXTMODE_VIDHRSZ15                  (1 << 6)
+#define OSD_EXTMODE_ZMFILV1HEN                 (1 << 5)
+#define OSD_EXTMODE_ZMFILV1VEN                 (1 << 4)
+#define OSD_EXTMODE_ZMFILV0HEN                 (1 << 3)
+#define OSD_EXTMODE_ZMFILV0VEN                 (1 << 2)
+#define OSD_EXTMODE_EXPFILHEN                  (1 << 1)
+#define OSD_EXTMODE_EXPFILVEN                  (1 << 0)
+
+#define OSD_MISCCTL_BLDSEL                     (1 << 15)
+#define OSD_MISCCTL_S420D                      (1 << 14)
+#define OSD_MISCCTL_BMAPT                      (1 << 13)
+#define OSD_MISCCTL_DM365M                     (1 << 12)
+#define OSD_MISCCTL_RGBEN                      (1 << 7)
+#define OSD_MISCCTL_RGBWIN                     (1 << 6)
+#define OSD_MISCCTL_DMANG                      (1 << 6)
+#define OSD_MISCCTL_TMON                       (1 << 5)
+#define OSD_MISCCTL_RSEL                       (1 << 4)
+#define OSD_MISCCTL_CPBSY                      (1 << 3)
+#define OSD_MISCCTL_PPSW                       (1 << 2)
+#define OSD_MISCCTL_PPRV                       (1 << 1)
+
+#define OSD_CLUTRAMYCB_Y_SHIFT                 8
+#define OSD_CLUTRAMYCB_Y                       (0xff << 8)
+#define OSD_CLUTRAMYCB_CB_SHIFT                        0
+#define OSD_CLUTRAMYCB_CB                      (0xff << 0)
+
+#define OSD_CLUTRAMCR_CR_SHIFT                 8
+#define OSD_CLUTRAMCR_CR                       (0xff << 8)
+#define OSD_CLUTRAMCR_CADDR_SHIFT              0
+#define OSD_CLUTRAMCR_CADDR                    (0xff << 0)
+
+#define OSD_TRANSPVAL_RGBTRANS                 (0xffff << 0)
+
+#define OSD_TRANSPVALL_RGBL                    (0xffff << 0)
+
+#define OSD_TRANSPVALU_Y_SHIFT                 8
+#define OSD_TRANSPVALU_Y                       (0xff << 8)
+#define OSD_TRANSPVALU_RGBU_SHIFT              0
+#define OSD_TRANSPVALU_RGBU                    (0xff << 0)
+
+#define OSD_TRANSPBMPIDX_BMP1_SHIFT            8
+#define OSD_TRANSPBMPIDX_BMP1                  (0xff << 8)
+#define OSD_TRANSPBMPIDX_BMP0_SHIFT            0
+#define OSD_TRANSPBMPIDX_BMP0                  0xff
+
+#endif                         /* _DAVINCI_VPBE_H_ */
diff --git a/drivers/media/video/davinci/vpbe_venc.c b/drivers/media/video/davinci/vpbe_venc.c
new file mode 100644 (file)
index 0000000..03a3e5c
--- /dev/null
@@ -0,0 +1,566 @@
+/*
+ * Copyright (C) 2010 Texas Instruments 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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/kernel.h>
+#include <linux/init.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+
+#include <mach/hardware.h>
+#include <mach/mux.h>
+#include <mach/io.h>
+#include <mach/i2c.h>
+
+#include <linux/io.h>
+
+#include <media/davinci/vpbe_types.h>
+#include <media/davinci/vpbe_venc.h>
+#include <media/davinci/vpss.h>
+#include <media/v4l2-device.h>
+
+#include "vpbe_venc_regs.h"
+
+#define MODULE_NAME    VPBE_VENC_SUBDEV_NAME
+
+static int debug = 2;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level 0-2");
+
+struct venc_state {
+       struct v4l2_subdev sd;
+       struct venc_callback *callback;
+       struct venc_platform_data *pdata;
+       struct device *pdev;
+       u32 output;
+       v4l2_std_id std;
+       spinlock_t lock;
+       void __iomem *venc_base;
+       void __iomem *vdaccfg_reg;
+};
+
+static inline struct venc_state *to_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct venc_state, sd);
+}
+
+static inline u32 venc_read(struct v4l2_subdev *sd, u32 offset)
+{
+       struct venc_state *venc = to_state(sd);
+
+       return readl(venc->venc_base + offset);
+}
+
+static inline u32 venc_write(struct v4l2_subdev *sd, u32 offset, u32 val)
+{
+       struct venc_state *venc = to_state(sd);
+
+       writel(val, (venc->venc_base + offset));
+
+       return val;
+}
+
+static inline u32 venc_modify(struct v4l2_subdev *sd, u32 offset,
+                                u32 val, u32 mask)
+{
+       u32 new_val = (venc_read(sd, offset) & ~mask) | (val & mask);
+
+       venc_write(sd, offset, new_val);
+
+       return new_val;
+}
+
+static inline u32 vdaccfg_write(struct v4l2_subdev *sd, u32 val)
+{
+       struct venc_state *venc = to_state(sd);
+
+       writel(val, venc->vdaccfg_reg);
+
+       val = readl(venc->vdaccfg_reg);
+
+       return val;
+}
+
+/* This function sets the dac of the VPBE for various outputs
+ */
+static int venc_set_dac(struct v4l2_subdev *sd, u32 out_index)
+{
+       switch (out_index) {
+       case 0:
+               v4l2_dbg(debug, 1, sd, "Setting output to Composite\n");
+               venc_write(sd, VENC_DACSEL, 0);
+               break;
+       case 1:
+               v4l2_dbg(debug, 1, sd, "Setting output to S-Video\n");
+               venc_write(sd, VENC_DACSEL, 0x210);
+               break;
+       case  2:
+               venc_write(sd, VENC_DACSEL, 0x543);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable)
+{
+       v4l2_dbg(debug, 2, sd, "venc_enabledigitaloutput\n");
+
+       if (benable) {
+               venc_write(sd, VENC_VMOD, 0);
+               venc_write(sd, VENC_CVBS, 0);
+               venc_write(sd, VENC_LCDOUT, 0);
+               venc_write(sd, VENC_HSPLS, 0);
+               venc_write(sd, VENC_HSTART, 0);
+               venc_write(sd, VENC_HVALID, 0);
+               venc_write(sd, VENC_HINT, 0);
+               venc_write(sd, VENC_VSPLS, 0);
+               venc_write(sd, VENC_VSTART, 0);
+               venc_write(sd, VENC_VVALID, 0);
+               venc_write(sd, VENC_VINT, 0);
+               venc_write(sd, VENC_YCCCTL, 0);
+               venc_write(sd, VENC_DACSEL, 0);
+
+       } else {
+               venc_write(sd, VENC_VMOD, 0);
+               /* disable VCLK output pin enable */
+               venc_write(sd, VENC_VIDCTL, 0x141);
+
+               /* Disable output sync pins */
+               venc_write(sd, VENC_SYNCCTL, 0);
+
+               /* Disable DCLOCK */
+               venc_write(sd, VENC_DCLKCTL, 0);
+               venc_write(sd, VENC_DRGBX1, 0x0000057C);
+
+               /* Disable LCD output control (accepting default polarity) */
+               venc_write(sd, VENC_LCDOUT, 0);
+               venc_write(sd, VENC_CMPNT, 0x100);
+               venc_write(sd, VENC_HSPLS, 0);
+               venc_write(sd, VENC_HINT, 0);
+               venc_write(sd, VENC_HSTART, 0);
+               venc_write(sd, VENC_HVALID, 0);
+
+               venc_write(sd, VENC_VSPLS, 0);
+               venc_write(sd, VENC_VINT, 0);
+               venc_write(sd, VENC_VSTART, 0);
+               venc_write(sd, VENC_VVALID, 0);
+
+               venc_write(sd, VENC_HSDLY, 0);
+               venc_write(sd, VENC_VSDLY, 0);
+
+               venc_write(sd, VENC_YCCCTL, 0);
+               venc_write(sd, VENC_VSTARTA, 0);
+
+               /* Set OSD clock and OSD Sync Adavance registers */
+               venc_write(sd, VENC_OSDCLK0, 1);
+               venc_write(sd, VENC_OSDCLK1, 2);
+       }
+}
+
+/*
+ * setting NTSC mode
+ */
+static int venc_set_ntsc(struct v4l2_subdev *sd)
+{
+       struct venc_state *venc = to_state(sd);
+       struct venc_platform_data *pdata = venc->pdata;
+
+       v4l2_dbg(debug, 2, sd, "venc_set_ntsc\n");
+
+       /* Setup clock at VPSS & VENC for SD */
+       vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1);
+       if (pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_525_60) < 0)
+               return -EINVAL;
+
+       venc_enabledigitaloutput(sd, 0);
+
+       /* to set VENC CLK DIV to 1 - final clock is 54 MHz */
+       venc_modify(sd, VENC_VIDCTL, 0, 1 << 1);
+       /* Set REC656 Mode */
+       venc_write(sd, VENC_YCCCTL, 0x1);
+       venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAFRQ);
+       venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAUPS);
+
+       venc_write(sd, VENC_VMOD, 0);
+       venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT),
+                       VENC_VMOD_VIE);
+       venc_modify(sd, VENC_VMOD, (0 << VENC_VMOD_VMD), VENC_VMOD_VMD);
+       venc_modify(sd, VENC_VMOD, (0 << VENC_VMOD_TVTYP_SHIFT),
+                       VENC_VMOD_TVTYP);
+       venc_write(sd, VENC_DACTST, 0x0);
+       venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC);
+
+       return 0;
+}
+
+/*
+ * setting PAL mode
+ */
+static int venc_set_pal(struct v4l2_subdev *sd)
+{
+       struct venc_state *venc = to_state(sd);
+
+       v4l2_dbg(debug, 2, sd, "venc_set_pal\n");
+
+       /* Setup clock at VPSS & VENC for SD */
+       vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1);
+       if (venc->pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_625_50) < 0)
+               return -EINVAL;
+
+       venc_enabledigitaloutput(sd, 0);
+
+       /* to set VENC CLK DIV to 1 - final clock is 54 MHz */
+       venc_modify(sd, VENC_VIDCTL, 0, 1 << 1);
+       /* Set REC656 Mode */
+       venc_write(sd, VENC_YCCCTL, 0x1);
+
+       venc_modify(sd, VENC_SYNCCTL, 1 << VENC_SYNCCTL_OVD_SHIFT,
+                       VENC_SYNCCTL_OVD);
+       venc_write(sd, VENC_VMOD, 0);
+       venc_modify(sd, VENC_VMOD,
+                       (1 << VENC_VMOD_VIE_SHIFT),
+                       VENC_VMOD_VIE);
+       venc_modify(sd, VENC_VMOD,
+                       (0 << VENC_VMOD_VMD), VENC_VMOD_VMD);
+       venc_modify(sd, VENC_VMOD,
+                       (1 << VENC_VMOD_TVTYP_SHIFT),
+                       VENC_VMOD_TVTYP);
+       venc_write(sd, VENC_DACTST, 0x0);
+       venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC);
+
+       return 0;
+}
+
+/*
+ * venc_set_480p59_94
+ *
+ * This function configures the video encoder to EDTV(525p) component setting.
+ */
+static int venc_set_480p59_94(struct v4l2_subdev *sd)
+{
+       struct venc_state *venc = to_state(sd);
+       struct venc_platform_data *pdata = venc->pdata;
+
+       v4l2_dbg(debug, 2, sd, "venc_set_480p59_94\n");
+
+       /* Setup clock at VPSS & VENC for SD */
+       if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_480P59_94) < 0)
+               return -EINVAL;
+
+       venc_enabledigitaloutput(sd, 0);
+
+       venc_write(sd, VENC_OSDCLK0, 0);
+       venc_write(sd, VENC_OSDCLK1, 1);
+       venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ,
+                   VENC_VDPRO_DAFRQ);
+       venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS,
+                   VENC_VDPRO_DAUPS);
+       venc_write(sd, VENC_VMOD, 0);
+       venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT),
+                   VENC_VMOD_VIE);
+       venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD);
+       venc_modify(sd, VENC_VMOD, (HDTV_525P << VENC_VMOD_TVTYP_SHIFT),
+                   VENC_VMOD_TVTYP);
+       venc_modify(sd, VENC_VMOD, VENC_VMOD_VDMD_YCBCR8 <<
+                   VENC_VMOD_VDMD_SHIFT, VENC_VMOD_VDMD);
+
+       venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC);
+
+       return 0;
+}
+
+/*
+ * venc_set_625p
+ *
+ * This function configures the video encoder to HDTV(625p) component setting
+ */
+static int venc_set_576p50(struct v4l2_subdev *sd)
+{
+       struct venc_state *venc = to_state(sd);
+       struct venc_platform_data *pdata = venc->pdata;
+
+       v4l2_dbg(debug, 2, sd, "venc_set_576p50\n");
+
+       /* Setup clock at VPSS & VENC for SD */
+       if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_576P50) < 0)
+               return -EINVAL;
+
+       venc_enabledigitaloutput(sd, 0);
+
+       venc_write(sd, VENC_OSDCLK0, 0);
+       venc_write(sd, VENC_OSDCLK1, 1);
+
+       venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ,
+                   VENC_VDPRO_DAFRQ);
+       venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS,
+                   VENC_VDPRO_DAUPS);
+
+       venc_write(sd, VENC_VMOD, 0);
+       venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT),
+                   VENC_VMOD_VIE);
+       venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD);
+       venc_modify(sd, VENC_VMOD, (HDTV_625P << VENC_VMOD_TVTYP_SHIFT),
+                   VENC_VMOD_TVTYP);
+
+       venc_modify(sd, VENC_VMOD, VENC_VMOD_VDMD_YCBCR8 <<
+                   VENC_VMOD_VDMD_SHIFT, VENC_VMOD_VDMD);
+       venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC);
+
+       return 0;
+}
+
+static int venc_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+       v4l2_dbg(debug, 1, sd, "venc_s_std_output\n");
+
+       if (norm & V4L2_STD_525_60)
+               return venc_set_ntsc(sd);
+       else if (norm & V4L2_STD_625_50)
+               return venc_set_pal(sd);
+
+       return -EINVAL;
+}
+
+static int venc_s_dv_preset(struct v4l2_subdev *sd,
+                           struct v4l2_dv_preset *dv_preset)
+{
+       v4l2_dbg(debug, 1, sd, "venc_s_dv_preset\n");
+
+       if (dv_preset->preset == V4L2_DV_576P50)
+               return venc_set_576p50(sd);
+       else if (dv_preset->preset == V4L2_DV_480P59_94)
+               return venc_set_480p59_94(sd);
+
+       return -EINVAL;
+}
+
+static int venc_s_routing(struct v4l2_subdev *sd, u32 input, u32 output,
+                         u32 config)
+{
+       struct venc_state *venc = to_state(sd);
+       int ret;
+
+       v4l2_dbg(debug, 1, sd, "venc_s_routing\n");
+
+       ret = venc_set_dac(sd, output);
+       if (!ret)
+               venc->output = output;
+
+       return ret;
+}
+
+static long venc_ioctl(struct v4l2_subdev *sd,
+                       unsigned int cmd,
+                       void *arg)
+{
+       u32 val;
+
+       switch (cmd) {
+       case VENC_GET_FLD:
+               val = venc_read(sd, VENC_VSTAT);
+               *((int *)arg) = ((val & VENC_VSTAT_FIDST) ==
+               VENC_VSTAT_FIDST);
+               break;
+       default:
+               v4l2_err(sd, "Wrong IOCTL cmd\n");
+               break;
+       }
+
+       return 0;
+}
+
+static const struct v4l2_subdev_core_ops venc_core_ops = {
+       .ioctl      = venc_ioctl,
+};
+
+static const struct v4l2_subdev_video_ops venc_video_ops = {
+       .s_routing = venc_s_routing,
+       .s_std_output = venc_s_std_output,
+       .s_dv_preset = venc_s_dv_preset,
+};
+
+static const struct v4l2_subdev_ops venc_ops = {
+       .core = &venc_core_ops,
+       .video = &venc_video_ops,
+};
+
+static int venc_initialize(struct v4l2_subdev *sd)
+{
+       struct venc_state *venc = to_state(sd);
+       int ret;
+
+       /* Set default to output to composite and std to NTSC */
+       venc->output = 0;
+       venc->std = V4L2_STD_525_60;
+
+       ret = venc_s_routing(sd, 0, venc->output, 0);
+       if (ret < 0) {
+               v4l2_err(sd, "Error setting output during init\n");
+               return -EINVAL;
+       }
+
+       ret = venc_s_std_output(sd, venc->std);
+       if (ret < 0) {
+               v4l2_err(sd, "Error setting std during init\n");
+               return -EINVAL;
+       }
+
+       return ret;
+}
+
+static int venc_device_get(struct device *dev, void *data)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct venc_state **venc = data;
+
+       if (strcmp(MODULE_NAME, pdev->name) == 0)
+               *venc = platform_get_drvdata(pdev);
+
+       return 0;
+}
+
+struct v4l2_subdev *venc_sub_dev_init(struct v4l2_device *v4l2_dev,
+               const char *venc_name)
+{
+       struct venc_state *venc;
+       int err;
+
+       err = bus_for_each_dev(&platform_bus_type, NULL, &venc,
+                       venc_device_get);
+       if (venc == NULL)
+               return NULL;
+
+       v4l2_subdev_init(&venc->sd, &venc_ops);
+
+       strcpy(venc->sd.name, venc_name);
+       if (v4l2_device_register_subdev(v4l2_dev, &venc->sd) < 0) {
+               v4l2_err(v4l2_dev,
+                       "vpbe unable to register venc sub device\n");
+               return NULL;
+       }
+       if (venc_initialize(&venc->sd)) {
+               v4l2_err(v4l2_dev,
+                       "vpbe venc initialization failed\n");
+               return NULL;
+       }
+
+       return &venc->sd;
+}
+EXPORT_SYMBOL(venc_sub_dev_init);
+
+static int venc_probe(struct platform_device *pdev)
+{
+       struct venc_state *venc;
+       struct resource *res;
+       int ret;
+
+       venc = kzalloc(sizeof(struct venc_state), GFP_KERNEL);
+       if (venc == NULL)
+               return -ENOMEM;
+
+       venc->pdev = &pdev->dev;
+       venc->pdata = pdev->dev.platform_data;
+       if (NULL == venc->pdata) {
+               dev_err(venc->pdev, "Unable to get platform data for"
+                       " VENC sub device");
+               ret = -ENOENT;
+               goto free_mem;
+       }
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(venc->pdev,
+                       "Unable to get VENC register address map\n");
+               ret = -ENODEV;
+               goto free_mem;
+       }
+
+       if (!request_mem_region(res->start, resource_size(res), "venc")) {
+               dev_err(venc->pdev, "Unable to reserve VENC MMIO region\n");
+               ret = -ENODEV;
+               goto free_mem;
+       }
+
+       venc->venc_base = ioremap_nocache(res->start, resource_size(res));
+       if (!venc->venc_base) {
+               dev_err(venc->pdev, "Unable to map VENC IO space\n");
+               ret = -ENODEV;
+               goto release_venc_mem_region;
+       }
+
+       spin_lock_init(&venc->lock);
+       platform_set_drvdata(pdev, venc);
+       dev_notice(venc->pdev, "VENC sub device probe success\n");
+       return 0;
+
+release_venc_mem_region:
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(res->start, resource_size(res));
+free_mem:
+       kfree(venc);
+       return ret;
+}
+
+static int venc_remove(struct platform_device *pdev)
+{
+       struct venc_state *venc = platform_get_drvdata(pdev);
+       struct resource *res;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       iounmap((void *)venc->venc_base);
+       release_mem_region(res->start, resource_size(res));
+       kfree(venc);
+
+       return 0;
+}
+
+static struct platform_driver venc_driver = {
+       .probe          = venc_probe,
+       .remove         = venc_remove,
+       .driver         = {
+               .name   = MODULE_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int venc_init(void)
+{
+       if (platform_driver_register(&venc_driver)) {
+               printk(KERN_ERR "Unable to register venc driver\n");
+               return -ENODEV;
+       }
+       return 0;
+}
+
+static void venc_exit(void)
+{
+       platform_driver_unregister(&venc_driver);
+       return;
+}
+
+module_init(venc_init);
+module_exit(venc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("VPBE VENC Driver");
+MODULE_AUTHOR("Texas Instruments");
diff --git a/drivers/media/video/davinci/vpbe_venc_regs.h b/drivers/media/video/davinci/vpbe_venc_regs.h
new file mode 100644 (file)
index 0000000..947cb15
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2006-2010 Texas Instruments 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..
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _VPBE_VENC_REGS_H
+#define _VPBE_VENC_REGS_H
+
+/* VPBE Video Encoder / Digital LCD Subsystem Registers (VENC) */
+#define VENC_VMOD                              0x00
+#define VENC_VIDCTL                            0x04
+#define VENC_VDPRO                             0x08
+#define VENC_SYNCCTL                           0x0C
+#define VENC_HSPLS                             0x10
+#define VENC_VSPLS                             0x14
+#define VENC_HINT                              0x18
+#define VENC_HSTART                            0x1C
+#define VENC_HVALID                            0x20
+#define VENC_VINT                              0x24
+#define VENC_VSTART                            0x28
+#define VENC_VVALID                            0x2C
+#define VENC_HSDLY                             0x30
+#define VENC_VSDLY                             0x34
+#define VENC_YCCCTL                            0x38
+#define VENC_RGBCTL                            0x3C
+#define VENC_RGBCLP                            0x40
+#define VENC_LINECTL                           0x44
+#define VENC_CULLLINE                          0x48
+#define VENC_LCDOUT                            0x4C
+#define VENC_BRTS                              0x50
+#define VENC_BRTW                              0x54
+#define VENC_ACCTL                             0x58
+#define VENC_PWMP                              0x5C
+#define VENC_PWMW                              0x60
+#define VENC_DCLKCTL                           0x64
+#define VENC_DCLKPTN0                          0x68
+#define VENC_DCLKPTN1                          0x6C
+#define VENC_DCLKPTN2                          0x70
+#define VENC_DCLKPTN3                          0x74
+#define VENC_DCLKPTN0A                         0x78
+#define VENC_DCLKPTN1A                         0x7C
+#define VENC_DCLKPTN2A                         0x80
+#define VENC_DCLKPTN3A                         0x84
+#define VENC_DCLKHS                            0x88
+#define VENC_DCLKHSA                           0x8C
+#define VENC_DCLKHR                            0x90
+#define VENC_DCLKVS                            0x94
+#define VENC_DCLKVR                            0x98
+#define VENC_CAPCTL                            0x9C
+#define VENC_CAPDO                             0xA0
+#define VENC_CAPDE                             0xA4
+#define VENC_ATR0                              0xA8
+#define VENC_ATR1                              0xAC
+#define VENC_ATR2                              0xB0
+#define VENC_VSTAT                             0xB8
+#define VENC_RAMADR                            0xBC
+#define VENC_RAMPORT                           0xC0
+#define VENC_DACTST                            0xC4
+#define VENC_YCOLVL                            0xC8
+#define VENC_SCPROG                            0xCC
+#define VENC_CVBS                              0xDC
+#define VENC_CMPNT                             0xE0
+#define VENC_ETMG0                             0xE4
+#define VENC_ETMG1                             0xE8
+#define VENC_ETMG2                             0xEC
+#define VENC_ETMG3                             0xF0
+#define VENC_DACSEL                            0xF4
+#define VENC_ARGBX0                            0x100
+#define VENC_ARGBX1                            0x104
+#define VENC_ARGBX2                            0x108
+#define VENC_ARGBX3                            0x10C
+#define VENC_ARGBX4                            0x110
+#define VENC_DRGBX0                            0x114
+#define VENC_DRGBX1                            0x118
+#define VENC_DRGBX2                            0x11C
+#define VENC_DRGBX3                            0x120
+#define VENC_DRGBX4                            0x124
+#define VENC_VSTARTA                           0x128
+#define VENC_OSDCLK0                           0x12C
+#define VENC_OSDCLK1                           0x130
+#define VENC_HVLDCL0                           0x134
+#define VENC_HVLDCL1                           0x138
+#define VENC_OSDHADV                           0x13C
+#define VENC_CLKCTL                            0x140
+#define VENC_GAMCTL                            0x144
+#define VENC_XHINTVL                           0x174
+
+/* bit definitions */
+#define VPBE_PCR_VENC_DIV                      (1 << 1)
+#define VPBE_PCR_CLK_OFF                       (1 << 0)
+
+#define VENC_VMOD_VDMD_SHIFT                   12
+#define VENC_VMOD_VDMD_YCBCR16                 0
+#define VENC_VMOD_VDMD_YCBCR8                  1
+#define VENC_VMOD_VDMD_RGB666                  2
+#define VENC_VMOD_VDMD_RGB8                    3
+#define VENC_VMOD_VDMD_EPSON                   4
+#define VENC_VMOD_VDMD_CASIO                   5
+#define VENC_VMOD_VDMD_UDISPQVGA               6
+#define VENC_VMOD_VDMD_STNLCD                  7
+#define VENC_VMOD_VIE_SHIFT                    1
+#define VENC_VMOD_VDMD                         (7 << 12)
+#define VENC_VMOD_ITLCL                                (1 << 11)
+#define VENC_VMOD_ITLC                         (1 << 10)
+#define VENC_VMOD_NSIT                         (1 << 9)
+#define VENC_VMOD_HDMD                         (1 << 8)
+#define VENC_VMOD_TVTYP_SHIFT                  6
+#define VENC_VMOD_TVTYP                                (3 << 6)
+#define VENC_VMOD_SLAVE                                (1 << 5)
+#define VENC_VMOD_VMD                          (1 << 4)
+#define VENC_VMOD_BLNK                         (1 << 3)
+#define VENC_VMOD_VIE                          (1 << 1)
+#define VENC_VMOD_VENC                         (1 << 0)
+
+/* VMOD TVTYP options for HDMD=0 */
+#define SDTV_NTSC                              0
+#define SDTV_PAL                               1
+/* VMOD TVTYP options for HDMD=1 */
+#define HDTV_525P                              0
+#define HDTV_625P                              1
+#define HDTV_1080I                             2
+#define HDTV_720P                              3
+
+#define VENC_VIDCTL_VCLKP                      (1 << 14)
+#define VENC_VIDCTL_VCLKE_SHIFT                        13
+#define VENC_VIDCTL_VCLKE                      (1 << 13)
+#define VENC_VIDCTL_VCLKZ_SHIFT                        12
+#define VENC_VIDCTL_VCLKZ                      (1 << 12)
+#define VENC_VIDCTL_SYDIR_SHIFT                        8
+#define VENC_VIDCTL_SYDIR                      (1 << 8)
+#define VENC_VIDCTL_DOMD_SHIFT                 4
+#define VENC_VIDCTL_DOMD                       (3 << 4)
+#define VENC_VIDCTL_YCDIR_SHIFT                        0
+#define VENC_VIDCTL_YCDIR                      (1 << 0)
+
+#define VENC_VDPRO_ATYCC_SHIFT                 5
+#define VENC_VDPRO_ATYCC                       (1 << 5)
+#define VENC_VDPRO_ATCOM_SHIFT                 4
+#define VENC_VDPRO_ATCOM                       (1 << 4)
+#define VENC_VDPRO_DAFRQ                       (1 << 3)
+#define VENC_VDPRO_DAUPS                       (1 << 2)
+#define VENC_VDPRO_CUPS                                (1 << 1)
+#define VENC_VDPRO_YUPS                                (1 << 0)
+
+#define VENC_SYNCCTL_VPL_SHIFT                 3
+#define VENC_SYNCCTL_VPL                       (1 << 3)
+#define VENC_SYNCCTL_HPL_SHIFT                 2
+#define VENC_SYNCCTL_HPL                       (1 << 2)
+#define VENC_SYNCCTL_SYEV_SHIFT                        1
+#define VENC_SYNCCTL_SYEV                      (1 << 1)
+#define VENC_SYNCCTL_SYEH_SHIFT                        0
+#define VENC_SYNCCTL_SYEH                      (1 << 0)
+#define VENC_SYNCCTL_OVD_SHIFT                 14
+#define VENC_SYNCCTL_OVD                       (1 << 14)
+
+#define VENC_DCLKCTL_DCKEC_SHIFT               11
+#define VENC_DCLKCTL_DCKEC                     (1 << 11)
+#define VENC_DCLKCTL_DCKPW_SHIFT               0
+#define VENC_DCLKCTL_DCKPW                     (0x3f << 0)
+
+#define VENC_VSTAT_FIDST                       (1 << 4)
+
+#define VENC_CMPNT_MRGB_SHIFT                  14
+#define VENC_CMPNT_MRGB                                (1 << 14)
+
+#endif                         /* _VPBE_VENC_REGS_H */
index d93ad74..49e4deb 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
-#include <linux/version.h>
 #include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
@@ -44,6 +43,7 @@
 
 MODULE_DESCRIPTION("TI DaVinci VPIF Capture driver");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(VPIF_CAPTURE_VERSION);
 
 #define vpif_err(fmt, arg...)  v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg)
 #define vpif_dbg(level, debug, fmt, arg...)    \
@@ -1677,7 +1677,6 @@ static int vpif_querycap(struct file *file, void  *priv,
 {
        struct vpif_capture_config *config = vpif_dev->platform_data;
 
-       cap->version = VPIF_CAPTURE_VERSION_CODE;
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
        strlcpy(cap->driver, "vpif capture", sizeof(cap->driver));
        strlcpy(cap->bus_info, "DM646x Platform", sizeof(cap->bus_info));
@@ -2211,10 +2210,8 @@ static __init int vpif_probe(struct platform_device *pdev)
                vfd->v4l2_dev = &vpif_obj.v4l2_dev;
                vfd->release = video_device_release;
                snprintf(vfd->name, sizeof(vfd->name),
-                        "DM646x_VPIFCapture_DRIVER_V%d.%d.%d",
-                        (VPIF_CAPTURE_VERSION_CODE >> 16) & 0xff,
-                        (VPIF_CAPTURE_VERSION_CODE >> 8) & 0xff,
-                        (VPIF_CAPTURE_VERSION_CODE) & 0xff);
+                        "DM646x_VPIFCapture_DRIVER_V%s",
+                        VPIF_CAPTURE_VERSION);
                /* Set video_dev to the video device */
                ch->video_dev = vfd;
        }
index 7a4196d..064550f 100644 (file)
@@ -23,7 +23,6 @@
 
 /* Header files */
 #include <linux/videodev2.h>
-#include <linux/version.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-device.h>
 #include <media/videobuf-core.h>
 #include "vpif.h"
 
 /* Macros */
-#define VPIF_MAJOR_RELEASE             0
-#define VPIF_MINOR_RELEASE             0
-#define VPIF_BUILD                     1
-#define VPIF_CAPTURE_VERSION_CODE      ((VPIF_MAJOR_RELEASE << 16) | \
-       (VPIF_MINOR_RELEASE << 8) | VPIF_BUILD)
+#define VPIF_CAPTURE_VERSION           "0.0.2"
 
 #define VPIF_VALID_FIELD(field)                (((V4L2_FIELD_ANY == field) || \
        (V4L2_FIELD_NONE == field)) || \
index cdf659a..286f029 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
-#include <linux/version.h>
 #include <linux/slab.h>
 
 #include <asm/irq.h>
@@ -47,6 +46,7 @@
 
 MODULE_DESCRIPTION("TI DaVinci VPIF Display driver");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(VPIF_DISPLAY_VERSION);
 
 #define DM646X_V4L2_STD (V4L2_STD_525_60 | V4L2_STD_625_50)
 
@@ -701,7 +701,6 @@ static int vpif_querycap(struct file *file, void  *priv,
 {
        struct vpif_display_config *config = vpif_dev->platform_data;
 
-       cap->version = VPIF_DISPLAY_VERSION_CODE;
        cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
        strlcpy(cap->driver, "vpif display", sizeof(cap->driver));
        strlcpy(cap->bus_info, "Platform", sizeof(cap->bus_info));
@@ -1740,10 +1739,8 @@ static __init int vpif_probe(struct platform_device *pdev)
                vfd->v4l2_dev = &vpif_obj.v4l2_dev;
                vfd->release = video_device_release;
                snprintf(vfd->name, sizeof(vfd->name),
-                        "DM646x_VPIFDisplay_DRIVER_V%d.%d.%d",
-                        (VPIF_DISPLAY_VERSION_CODE >> 16) & 0xff,
-                        (VPIF_DISPLAY_VERSION_CODE >> 8) & 0xff,
-                        (VPIF_DISPLAY_VERSION_CODE) & 0xff);
+                        "DM646x_VPIFDisplay_DRIVER_V%s",
+                        VPIF_DISPLAY_VERSION);
 
                /* Set video_dev to the video device */
                ch->video_dev = vfd;
index b53aaa8..5d1936d 100644 (file)
@@ -18,7 +18,6 @@
 
 /* Header files */
 #include <linux/videodev2.h>
-#include <linux/version.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-device.h>
 #include <media/videobuf-core.h>
 #include "vpif.h"
 
 /* Macros */
-#define VPIF_MAJOR_RELEASE     (0)
-#define VPIF_MINOR_RELEASE     (0)
-#define VPIF_BUILD             (1)
-
-#define VPIF_DISPLAY_VERSION_CODE \
-       ((VPIF_MAJOR_RELEASE << 16) | (VPIF_MINOR_RELEASE << 8) | VPIF_BUILD)
+#define VPIF_DISPLAY_VERSION   "0.0.2"
 
 #define VPIF_VALID_FIELD(field) \
        (((V4L2_FIELD_ANY == field) || (V4L2_FIELD_NONE == field)) || \
index 3cb78f2..281ee42 100644 (file)
@@ -3,7 +3,6 @@ config VIDEO_EM28XX
        depends on VIDEO_DEV && I2C
        select VIDEO_TUNER
        select VIDEO_TVEEPROM
-       depends on RC_CORE
        select VIDEOBUF_VMALLOC
        select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
        select VIDEO_TVP5150 if VIDEO_HELPER_CHIPS_AUTO
@@ -40,7 +39,18 @@ config VIDEO_EM28XX_DVB
        select DVB_S921 if !DVB_FE_CUSTOMISE
        select DVB_DRXD if !DVB_FE_CUSTOMISE
        select DVB_CXD2820R if !DVB_FE_CUSTOMISE
+       select DVB_DRXK if !DVB_FE_CUSTOMISE
+       select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE
        select VIDEOBUF_DVB
        ---help---
          This adds support for DVB cards based on the
          Empiatech em28xx chips.
+
+config VIDEO_EM28XX_RC
+        bool "EM28XX Remote Controller support"
+        depends on RC_CORE
+        depends on VIDEO_EM28XX
+        depends on !(RC_CORE=m && VIDEO_EM28XX=y)
+        default y
+        ---help---
+          Enables Remote Controller support on em28xx driver.
index d0f093d..38aaa00 100644 (file)
@@ -1,5 +1,7 @@
-em28xx-objs     := em28xx-video.o em28xx-i2c.o em28xx-cards.o em28xx-core.o \
-                  em28xx-input.o em28xx-vbi.o
+em28xx-y :=    em28xx-video.o em28xx-i2c.o em28xx-cards.o
+em28xx-y +=    em28xx-core.o  em28xx-vbi.o
+
+em28xx-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-input.o
 
 em28xx-alsa-objs := em28xx-audio.o
 
index 3c48a72..cff0768 100644 (file)
@@ -3,9 +3,9 @@
  *
  *  Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com>
  *
- *  Copyright (C) 2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *  Copyright (C) 2007-2011 Mauro Carvalho Chehab <mchehab@redhat.com>
  *     - Port to work with the in-kernel driver
- *     - Several cleanups
+ *     - Cleanups, fixes, alsa-controls, etc.
  *
  *  This driver is based on my previous au600 usb pstn audio driver
  *  and inherits all the copyrights
@@ -41,6 +41,7 @@
 #include <sound/info.h>
 #include <sound/initval.h>
 #include <sound/control.h>
+#include <sound/tlv.h>
 #include <media/v4l2-common.h>
 #include "em28xx.h"
 
@@ -212,9 +213,12 @@ static int em28xx_init_audio_isoc(struct em28xx *dev)
        for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
                errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
                if (errCode) {
+                       em28xx_errdev("submit of audio urb failed\n");
                        em28xx_deinit_isoc_audio(dev);
+                       atomic_set(&dev->stream_started, 0);
                        return errCode;
                }
+
        }
 
        return 0;
@@ -245,6 +249,7 @@ static struct snd_pcm_hardware snd_em28xx_hw_capture = {
        .info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
                SNDRV_PCM_INFO_MMAP           |
                SNDRV_PCM_INFO_INTERLEAVED    |
+               SNDRV_PCM_INFO_BATCH          |
                SNDRV_PCM_INFO_MMAP_VALID,
 
        .formats = SNDRV_PCM_FMTBIT_S16_LE,
@@ -276,24 +281,27 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
                return -ENODEV;
        }
 
-       /* Sets volume, mute, etc */
+       runtime->hw = snd_em28xx_hw_capture;
+       if ((dev->alt == 0 || dev->audio_ifnum) && dev->adev.users == 0) {
+               if (dev->audio_ifnum)
+                       dev->alt = 1;
+               else
+                       dev->alt = 7;
 
-       dev->mute = 0;
-       mutex_lock(&dev->lock);
-       ret = em28xx_audio_analog_set(dev);
-       if (ret < 0)
-               goto err;
+               dprintk("changing alternate number on interface %d to %d\n",
+                       dev->audio_ifnum, dev->alt);
+               usb_set_interface(dev->udev, dev->audio_ifnum, dev->alt);
 
-       runtime->hw = snd_em28xx_hw_capture;
-       if (dev->alt == 0 && dev->adev.users == 0) {
-               int errCode;
-               dev->alt = 7;
-               dprintk("changing alternate number to 7\n");
-               errCode = usb_set_interface(dev->udev, 0, 7);
-       }
+               /* Sets volume, mute, etc */
+               dev->mute = 0;
+               mutex_lock(&dev->lock);
+               ret = em28xx_audio_analog_set(dev);
+               if (ret < 0)
+                       goto err;
 
-       dev->adev.users++;
-       mutex_unlock(&dev->lock);
+               dev->adev.users++;
+               mutex_unlock(&dev->lock);
+       }
 
        snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
        dev->adev.capture_pcm_substream = substream;
@@ -342,6 +350,8 @@ static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream,
 
        ret = snd_pcm_alloc_vmalloc_buffer(substream,
                                params_buffer_bytes(hw_params));
+       if (ret < 0)
+               return ret;
        format = params_format(hw_params);
        rate = params_rate(hw_params);
        channels = params_channels(hw_params);
@@ -393,20 +403,24 @@ static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream,
                                      int cmd)
 {
        struct em28xx *dev = snd_pcm_substream_chip(substream);
-       int retval;
+       int retval = 0;
 
        switch (cmd) {
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
+       case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
        case SNDRV_PCM_TRIGGER_START:
                atomic_set(&dev->stream_started, 1);
                break;
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
+       case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
        case SNDRV_PCM_TRIGGER_STOP:
-               atomic_set(&dev->stream_started, 1);
+               atomic_set(&dev->stream_started, 0);
                break;
        default:
                retval = -EINVAL;
        }
        schedule_work(&dev->wq_trigger);
-       return 0;
+       return retval;
 }
 
 static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream
@@ -432,6 +446,179 @@ static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
        return vmalloc_to_page(pageptr);
 }
 
+/*
+ * AC97 volume control support
+ */
+static int em28xx_vol_info(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *info)
+{
+       info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       info->count = 2;
+       info->value.integer.min = 0;
+       info->value.integer.max = 0x1f;
+
+       return 0;
+}
+
+static int em28xx_vol_put(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *value)
+{
+       struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+       u16 val = (0x1f - (value->value.integer.value[0] & 0x1f)) |
+                 (0x1f - (value->value.integer.value[1] & 0x1f)) << 8;
+       int rc;
+
+       mutex_lock(&dev->lock);
+       rc = em28xx_read_ac97(dev, kcontrol->private_value);
+       if (rc < 0)
+               goto err;
+
+       val |= rc & 0x8000;     /* Preserve the mute flag */
+
+       rc = em28xx_write_ac97(dev, kcontrol->private_value, val);
+       if (rc < 0)
+               goto err;
+
+       dprintk("%sleft vol %d, right vol %d (0x%04x) to ac97 volume control 0x%04x\n",
+               (val & 0x8000) ? "muted " : "",
+               0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
+               val, (int)kcontrol->private_value);
+
+err:
+       mutex_unlock(&dev->lock);
+       return rc;
+}
+
+static int em28xx_vol_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *value)
+{
+       struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+       int val;
+
+       mutex_lock(&dev->lock);
+       val = em28xx_read_ac97(dev, kcontrol->private_value);
+       mutex_unlock(&dev->lock);
+       if (val < 0)
+               return val;
+
+       dprintk("%sleft vol %d, right vol %d (0x%04x) from ac97 volume control 0x%04x\n",
+               (val & 0x8000) ? "muted " : "",
+               0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
+               val, (int)kcontrol->private_value);
+
+       value->value.integer.value[0] = 0x1f - (val & 0x1f);
+       value->value.integer.value[1] = 0x1f - ((val << 8) & 0x1f);
+
+       return 0;
+}
+
+static int em28xx_vol_put_mute(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *value)
+{
+       struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+       u16 val = value->value.integer.value[0];
+       int rc;
+
+       mutex_lock(&dev->lock);
+       rc = em28xx_read_ac97(dev, kcontrol->private_value);
+       if (rc < 0)
+               goto err;
+
+       if (val)
+               rc &= 0x1f1f;
+       else
+               rc |= 0x8000;
+
+       rc = em28xx_write_ac97(dev, kcontrol->private_value, rc);
+       if (rc < 0)
+               goto err;
+
+       dprintk("%sleft vol %d, right vol %d (0x%04x) to ac97 volume control 0x%04x\n",
+               (val & 0x8000) ? "muted " : "",
+               0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
+               val, (int)kcontrol->private_value);
+
+err:
+       mutex_unlock(&dev->lock);
+       return rc;
+}
+
+static int em28xx_vol_get_mute(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *value)
+{
+       struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+       int val;
+
+       mutex_lock(&dev->lock);
+       val = em28xx_read_ac97(dev, kcontrol->private_value);
+       mutex_unlock(&dev->lock);
+       if (val < 0)
+               return val;
+
+       if (val & 0x8000)
+               value->value.integer.value[0] = 0;
+       else
+               value->value.integer.value[0] = 1;
+
+       dprintk("%sleft vol %d, right vol %d (0x%04x) from ac97 volume control 0x%04x\n",
+               (val & 0x8000) ? "muted " : "",
+               0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
+               val, (int)kcontrol->private_value);
+
+       return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(em28xx_db_scale, -3450, 150, 0);
+
+static int em28xx_cvol_new(struct snd_card *card, struct em28xx *dev,
+                          char *name, int id)
+{
+       int err;
+       char ctl_name[44];
+       struct snd_kcontrol *kctl;
+       struct snd_kcontrol_new tmp;
+
+       memset (&tmp, 0, sizeof(tmp));
+       tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       tmp.private_value = id,
+       tmp.name  = ctl_name,
+
+       /* Add Mute Control */
+       sprintf(ctl_name, "%s Switch", name);
+       tmp.get  = em28xx_vol_get_mute;
+       tmp.put  = em28xx_vol_put_mute;
+       tmp.info = snd_ctl_boolean_mono_info;
+       kctl = snd_ctl_new1(&tmp, dev);
+       err = snd_ctl_add(card, kctl);
+       if (err < 0)
+               return err;
+       dprintk("Added control %s for ac97 volume control 0x%04x\n",
+               ctl_name, id);
+
+       memset (&tmp, 0, sizeof(tmp));
+       tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       tmp.private_value = id,
+       tmp.name  = ctl_name,
+
+       /* Add Volume Control */
+       sprintf(ctl_name, "%s Volume", name);
+       tmp.get   = em28xx_vol_get;
+       tmp.put   = em28xx_vol_put;
+       tmp.info  = em28xx_vol_info;
+       tmp.tlv.p = em28xx_db_scale,
+       kctl = snd_ctl_new1(&tmp, dev);
+       err = snd_ctl_add(card, kctl);
+       if (err < 0)
+               return err;
+       dprintk("Added control %s for ac97 volume control 0x%04x\n",
+               ctl_name, id);
+
+       return 0;
+}
+
+/*
+ * register/unregister code and data
+ */
 static struct snd_pcm_ops snd_em28xx_pcm_capture = {
        .open      = snd_em28xx_capture_open,
        .close     = snd_em28xx_pcm_close,
@@ -452,17 +639,17 @@ static int em28xx_audio_init(struct em28xx *dev)
        static int          devnr;
        int                 err;
 
-       if (dev->has_alsa_audio != 1) {
+       if (!dev->has_alsa_audio || dev->audio_ifnum < 0) {
                /* This device does not support the extension (in this case
                   the device is expecting the snd-usb-audio module or
                   doesn't have analog audio support at all) */
                return 0;
        }
 
-       printk(KERN_INFO "em28xx-audio.c: probing for em28x1 "
-                        "non standard usbaudio\n");
+       printk(KERN_INFO "em28xx-audio.c: probing for em28xx Audio Vendor Class\n");
        printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
                         "Rechberger\n");
+       printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n");
 
        err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0,
                              &card);
@@ -488,6 +675,22 @@ static int em28xx_audio_init(struct em28xx *dev)
 
        INIT_WORK(&dev->wq_trigger, audio_trigger);
 
+       if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
+               em28xx_cvol_new(card, dev, "Video", AC97_VIDEO_VOL);
+               em28xx_cvol_new(card, dev, "Line In", AC97_LINEIN_VOL);
+               em28xx_cvol_new(card, dev, "Phone", AC97_PHONE_VOL);
+               em28xx_cvol_new(card, dev, "Microphone", AC97_PHONE_VOL);
+               em28xx_cvol_new(card, dev, "CD", AC97_CD_VOL);
+               em28xx_cvol_new(card, dev, "AUX", AC97_AUX_VOL);
+               em28xx_cvol_new(card, dev, "PCM", AC97_PCM_OUT_VOL);
+
+               em28xx_cvol_new(card, dev, "Master", AC97_MASTER_VOL);
+               em28xx_cvol_new(card, dev, "Line", AC97_LINE_LEVEL_VOL);
+               em28xx_cvol_new(card, dev, "Mono", AC97_MASTER_MONO_VOL);
+               em28xx_cvol_new(card, dev, "LFE", AC97_LFE_MASTER_VOL);
+               em28xx_cvol_new(card, dev, "Surround", AC97_SURR_MASTER_VOL);
+       }
+
        err = snd_card_register(card);
        if (err < 0) {
                snd_card_free(card);
@@ -538,7 +741,7 @@ static void __exit em28xx_alsa_unregister(void)
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Markus Rechberger <mrechberger@gmail.com>");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
 MODULE_DESCRIPTION("Em28xx Audio driver");
 
 module_init(em28xx_alsa_register);
index 4e37375..3e3959f 100644 (file)
@@ -289,7 +289,7 @@ static struct em28xx_reg_seq leadership_reset[] = {
        {       -1,             -1,     -1,     -1},
 };
 
-/* 2013:024f PCTV Systems nanoStick T2 290e
+/* 2013:024f PCTV nanoStick T2 290e
  * GPIO_6 - demod reset
  * GPIO_7 - LED
  */
@@ -300,6 +300,23 @@ static struct em28xx_reg_seq pctv_290e[] = {
        {-1,                    -1,     -1,             -1},
 };
 
+#if 0
+static struct em28xx_reg_seq terratec_h5_gpio[] = {
+       {EM28XX_R08_GPIO,       0xff,   0xff,   10},
+       {EM2874_R80_GPIO,       0xf6,   0xff,   100},
+       {EM2874_R80_GPIO,       0xf2,   0xff,   50},
+       {EM2874_R80_GPIO,       0xf6,   0xff,   50},
+       { -1,                   -1,     -1,     -1},
+};
+
+static struct em28xx_reg_seq terratec_h5_digital[] = {
+       {EM2874_R80_GPIO,       0xf6,   0xff,   10},
+       {EM2874_R80_GPIO,       0xe6,   0xff,   100},
+       {EM2874_R80_GPIO,       0xa6,   0xff,   10},
+       { -1,                   -1,     -1,     -1},
+};
+#endif
+
 /*
  *  Board definitions
  */
@@ -843,6 +860,19 @@ struct em28xx_board em28xx_boards[] = {
                        .gpio     = terratec_cinergy_USB_XS_FR_analog,
                } },
        },
+       [EM2884_BOARD_TERRATEC_H5] = {
+               .name         = "Terratec Cinergy H5",
+               .has_dvb      = 1,
+#if 0
+               .tuner_type   = TUNER_PHILIPS_TDA8290,
+               .tuner_addr   = 0x41,
+               .dvb_gpio     = terratec_h5_digital, /* FIXME: probably wrong */
+               .tuner_gpio   = terratec_h5_gpio,
+#endif
+               .i2c_speed    = EM2874_I2C_SECONDARY_BUS_SELECT |
+                               EM28XX_I2C_CLK_WAIT_ENABLE |
+                               EM28XX_I2C_FREQ_400_KHZ,
+       },
        [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = {
                .name         = "Hauppauge WinTV HVR 900",
                .tda9887_conf = TDA9887_PRESENT,
@@ -1259,7 +1289,7 @@ struct em28xx_board em28xx_boards[] = {
                } },
        },
 
-       [EM2874_LEADERSHIP_ISDBT] = {
+       [EM2874_BOARD_LEADERSHIP_ISDBT] = {
                .i2c_speed      = EM2874_I2C_SECONDARY_BUS_SELECT |
                                  EM28XX_I2C_CLK_WAIT_ENABLE |
                                  EM28XX_I2C_FREQ_100_KHZ,
@@ -1319,7 +1349,6 @@ struct em28xx_board em28xx_boards[] = {
        },
        [EM2880_BOARD_KWORLD_DVB_305U] = {
                .name         = "KWorld DVB-T 305U",
-               .valid        = EM28XX_BOARD_NOT_VALIDATED,
                .tuner_type   = TUNER_XC2028,
                .tuner_gpio   = default_tuner_gpio,
                .decoder      = EM28XX_TVP5150,
@@ -1770,16 +1799,16 @@ struct em28xx_board em28xx_boards[] = {
                .dvb_gpio   = kworld_a340_digital,
                .tuner_gpio = default_tuner_gpio,
        },
-       /* 2013:024f PCTV Systems nanoStick T2 290e.
+       /* 2013:024f PCTV nanoStick T2 290e.
         * Empia EM28174, Sony CXD2820R and NXP TDA18271HD/C2 */
        [EM28174_BOARD_PCTV_290E] = {
+               .name          = "PCTV nanoStick T2 290e",
                .i2c_speed      = EM2874_I2C_SECONDARY_BUS_SELECT |
                        EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_100_KHZ,
-               .xclk          = EM28XX_XCLK_FREQUENCY_12MHZ,
-               .name          = "PCTV Systems nanoStick T2 290e",
                .tuner_type    = TUNER_ABSENT,
                .tuner_gpio    = pctv_290e,
                .has_dvb       = 1,
+               .ir_codes      = RC_MAP_PINNACLE_PCTV_HD,
        },
 };
 const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
@@ -1855,8 +1884,10 @@ struct usb_device_id em28xx_id_table[] = {
        { USB_DEVICE(0x0ccd, 0x0042),
                        .driver_info = EM2882_BOARD_TERRATEC_HYBRID_XS },
        { USB_DEVICE(0x0ccd, 0x0043),
-                       .driver_info = EM2870_BOARD_TERRATEC_XS },
-       { USB_DEVICE(0x0ccd, 0x0047),
+                       .driver_info = EM2884_BOARD_TERRATEC_H5 },
+       { USB_DEVICE(0x0ccd, 0x10a2),   /* Rev. 1 */
+                       .driver_info = EM2884_BOARD_TERRATEC_H5 },
+       { USB_DEVICE(0x0ccd, 0x10ad),   /* Rev. 2 */
                        .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS },
        { USB_DEVICE(0x0ccd, 0x0084),
                        .driver_info = EM2860_BOARD_TERRATEC_AV350 },
@@ -1937,7 +1968,7 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = {
        {0x77800080, EM2860_BOARD_TVP5150_REFERENCE_DESIGN, TUNER_ABSENT},
        {0xc51200e3, EM2820_BOARD_GADMEI_TVR200, TUNER_LG_PAL_NEW_TAPC},
        {0x4ba50080, EM2861_BOARD_GADMEI_UTV330PLUS, TUNER_TNF_5335MF},
-       {0x6b800080, EM2874_LEADERSHIP_ISDBT, TUNER_ABSENT},
+       {0x6b800080, EM2874_BOARD_LEADERSHIP_ISDBT, TUNER_ABSENT},
 };
 
 /* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
@@ -2660,10 +2691,9 @@ void em28xx_card_setup(struct em28xx *dev)
                        .addr = 0xba >> 1,
                        .platform_data = &pdata,
                };
-               struct v4l2_subdev *sd;
 
                pdata.xtal = dev->sensor_xtal;
-               sd = v4l2_i2c_new_subdev_board(&dev->v4l2_dev, &dev->i2c_adap,
+               v4l2_i2c_new_subdev_board(&dev->v4l2_dev, &dev->i2c_adap,
                                &mt9v011_info, NULL);
        }
 
@@ -2842,11 +2872,26 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
                        em28xx_info("chip ID is em2882/em2883\n");
                        dev->wait_after_write = 0;
                        break;
+               case CHIP_ID_EM2884:
+                       em28xx_info("chip ID is em2884\n");
+                       dev->reg_gpio_num = EM2874_R80_GPIO;
+                       dev->wait_after_write = 0;
+                       break;
                default:
                        em28xx_info("em28xx chip ID = %d\n", dev->chip_id);
                }
        }
 
+       if (dev->is_audio_only) {
+               errCode = em28xx_audio_setup(dev);
+               if (errCode)
+                       return -ENODEV;
+               em28xx_add_into_devlist(dev);
+               em28xx_init_extension(dev);
+
+               return 0;
+       }
+
        /* Prepopulate cached GPO register content */
        retval = em28xx_read_reg(dev, dev->reg_gpo_num);
        if (retval >= 0)
@@ -2947,6 +2992,9 @@ fail_reg_devices:
        return retval;
 }
 
+/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
+#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
+
 /*
  * em28xx_usb_probe()
  * checks for supported devices
@@ -2956,15 +3004,15 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 {
        const struct usb_endpoint_descriptor *endpoint;
        struct usb_device *udev;
-       struct usb_interface *uif;
        struct em28xx *dev = NULL;
        int retval;
-       int i, nr, ifnum, isoc_pipe;
+       bool is_audio_only = false, has_audio = false;
+       int i, nr, isoc_pipe;
+       const int ifnum = interface->altsetting[0].desc.bInterfaceNumber;
        char *speed;
        char descr[255] = "";
 
        udev = usb_get_dev(interface_to_usbdev(interface));
-       ifnum = interface->altsetting[0].desc.bInterfaceNumber;
 
        /* Check to see next free device and mark as used */
        nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS);
@@ -2984,6 +3032,19 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                goto err;
        }
 
+       /* Get endpoints */
+       for (i = 0; i < interface->num_altsetting; i++) {
+               int ep;
+
+               for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) {
+                       struct usb_host_endpoint        *e;
+                       e = &interface->altsetting[i].endpoint[ep];
+
+                       if (e->desc.bEndpointAddress == 0x83)
+                               has_audio = true;
+               }
+       }
+
        endpoint = &interface->cur_altsetting->endpoint[0].desc;
 
        /* check if the device has the iso in endpoint at the correct place */
@@ -3003,19 +3064,22 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                        check_interface = 0;
 
                if (!check_interface) {
-                       em28xx_err(DRIVER_NAME " video device (%04x:%04x): "
-                               "interface %i, class %i found.\n",
-                               le16_to_cpu(udev->descriptor.idVendor),
-                               le16_to_cpu(udev->descriptor.idProduct),
-                               ifnum,
-                               interface->altsetting[0].desc.bInterfaceClass);
-
-                       em28xx_err(DRIVER_NAME " This is an anciliary "
-                               "interface not used by the driver\n");
-
-                       em28xx_devused &= ~(1<<nr);
-                       retval = -ENODEV;
-                       goto err;
+                       if (has_audio) {
+                               is_audio_only = true;
+                       } else {
+                               em28xx_err(DRIVER_NAME " video device (%04x:%04x): "
+                                       "interface %i, class %i found.\n",
+                                       le16_to_cpu(udev->descriptor.idVendor),
+                                       le16_to_cpu(udev->descriptor.idProduct),
+                                       ifnum,
+                                       interface->altsetting[0].desc.bInterfaceClass);
+                               em28xx_err(DRIVER_NAME " This is an anciliary "
+                                       "interface not used by the driver\n");
+
+                               em28xx_devused &= ~(1<<nr);
+                               retval = -ENODEV;
+                               goto err;
+                       }
                }
        }
 
@@ -3045,8 +3109,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
        if (*descr)
                strlcat(descr, " ", sizeof(descr));
 
-       printk(DRIVER_NAME ": New device %s@ %s Mbps "
-               "(%04x:%04x, interface %d, class %d)\n",
+       printk(KERN_INFO DRIVER_NAME
+               ": New device %s@ %s Mbps (%04x:%04x, interface %d, class %d)\n",
                descr,
                speed,
                le16_to_cpu(udev->descriptor.idVendor),
@@ -3054,6 +3118,11 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                ifnum,
                interface->altsetting->desc.bInterfaceNumber);
 
+       if (has_audio)
+               printk(KERN_INFO DRIVER_NAME
+                      ": Audio Vendor Class interface %i found\n",
+                      ifnum);
+
        /*
         * Make sure we have 480 Mbps of bandwidth, otherwise things like
         * video stream wouldn't likely work, since 12 Mbps is generally
@@ -3089,10 +3158,13 @@ static int em28xx_usb_probe(struct usb_interface *interface,
        dev->devno = nr;
        dev->model = id->driver_info;
        dev->alt   = -1;
+       dev->is_audio_only = is_audio_only;
+       dev->has_alsa_audio = has_audio;
+       dev->audio_ifnum = ifnum;
 
        /* Checks if audio is provided by some interface */
        for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
-               uif = udev->config->interface[i];
+               struct usb_interface *uif = udev->config->interface[i];
                if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
                        dev->has_audio_class = 1;
                        break;
@@ -3100,9 +3172,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
        }
 
        /* compute alternate max packet sizes */
-       uif = udev->actconfig->interface[0];
-
-       dev->num_alt = uif->num_altsetting;
+       dev->num_alt = interface->num_altsetting;
        dev->alt_max_pkt_size = kmalloc(32 * dev->num_alt, GFP_KERNEL);
 
        if (dev->alt_max_pkt_size == NULL) {
@@ -3114,14 +3184,21 @@ static int em28xx_usb_probe(struct usb_interface *interface,
        }
 
        for (i = 0; i < dev->num_alt ; i++) {
-               u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc.wMaxPacketSize);
-               dev->alt_max_pkt_size[i] =
-                   (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
+               u16 tmp = le16_to_cpu(interface->altsetting[i].endpoint[isoc_pipe].desc.wMaxPacketSize);
+               unsigned int size = tmp & 0x7ff;
+
+               if (udev->speed == USB_SPEED_HIGH)
+                       size = size * hb_mult(tmp);
+
+               dev->alt_max_pkt_size[i] = size;
        }
 
        if ((card[nr] >= 0) && (card[nr] < em28xx_bcount))
                dev->model = card[nr];
 
+       /* save our data pointer in this interface device */
+       usb_set_intfdata(interface, dev);
+
        /* allocate device struct */
        mutex_init(&dev->lock);
        mutex_lock(&dev->lock);
@@ -3133,9 +3210,6 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                goto err;
        }
 
-       /* save our data pointer in this interface device */
-       usb_set_intfdata(interface, dev);
-
        request_modules(dev);
 
        /* Should be the last thing to do, to avoid newer udev's to
@@ -3164,6 +3238,13 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
        if (!dev)
                return;
 
+       if (dev->is_audio_only) {
+               mutex_lock(&dev->lock);
+               em28xx_close_extension(dev);
+               mutex_unlock(&dev->lock);
+               return;
+       }
+
        em28xx_info("disconnecting %s\n", dev->vdev->name);
 
        flush_request_modules(dev);
index e33f145..57b1b5c 100644 (file)
@@ -211,6 +211,7 @@ int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val)
 {
        return em28xx_write_regs(dev, reg, &val, 1);
 }
+EXPORT_SYMBOL_GPL(em28xx_write_reg);
 
 /*
  * em28xx_write_reg_bits()
@@ -286,6 +287,7 @@ int em28xx_read_ac97(struct em28xx *dev, u8 reg)
                return ret;
        return le16_to_cpu(val);
 }
+EXPORT_SYMBOL_GPL(em28xx_read_ac97);
 
 /*
  * em28xx_write_ac97()
@@ -313,13 +315,14 @@ int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(em28xx_write_ac97);
 
-struct em28xx_vol_table {
+struct em28xx_vol_itable {
        enum em28xx_amux mux;
        u8               reg;
 };
 
-static struct em28xx_vol_table inputs[] = {
+static struct em28xx_vol_itable inputs[] = {
        { EM28XX_AMUX_VIDEO,    AC97_VIDEO_VOL   },
        { EM28XX_AMUX_LINE_IN,  AC97_LINEIN_VOL  },
        { EM28XX_AMUX_PHONE,    AC97_PHONE_VOL   },
@@ -403,7 +406,12 @@ static int em28xx_set_audio_source(struct em28xx *dev)
        return ret;
 }
 
-static const struct em28xx_vol_table outputs[] = {
+struct em28xx_vol_otable {
+       enum em28xx_aout mux;
+       u8               reg;
+};
+
+static const struct em28xx_vol_otable outputs[] = {
        { EM28XX_AOUT_MASTER, AC97_MASTER_VOL      },
        { EM28XX_AOUT_LINE,   AC97_LINE_LEVEL_VOL  },
        { EM28XX_AOUT_MONO,   AC97_MASTER_MONO_VOL },
@@ -492,17 +500,13 @@ int em28xx_audio_setup(struct em28xx *dev)
        if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874
                || dev->chip_id == CHIP_ID_EM28174) {
                /* Digital only device - don't load any alsa module */
-               dev->audio_mode.has_audio = 0;
-               dev->has_audio_class = 0;
-               dev->has_alsa_audio = 0;
+               dev->audio_mode.has_audio = false;
+               dev->has_audio_class = false;
+               dev->has_alsa_audio = false;
                return 0;
        }
 
-       /* If device doesn't support Usb Audio Class, use vendor class */
-       if (!dev->has_audio_class)
-               dev->has_alsa_audio = 1;
-
-       dev->audio_mode.has_audio = 1;
+       dev->audio_mode.has_audio = true;
 
        /* See how this device is configured */
        cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG);
@@ -512,8 +516,8 @@ int em28xx_audio_setup(struct em28xx *dev)
                cfg = EM28XX_CHIPCFG_AC97; /* Be conservative */
        } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == 0x00) {
                /* The device doesn't have vendor audio at all */
-               dev->has_alsa_audio = 0;
-               dev->audio_mode.has_audio = 0;
+               dev->has_alsa_audio = false;
+               dev->audio_mode.has_audio = false;
                return 0;
        } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
                   EM28XX_CHIPCFG_I2S_3_SAMPRATES) {
@@ -542,8 +546,8 @@ int em28xx_audio_setup(struct em28xx *dev)
                 */
                em28xx_warn("AC97 chip type couldn't be determined\n");
                dev->audio_mode.ac97 = EM28XX_NO_AC97;
-               dev->has_alsa_audio = 0;
-               dev->audio_mode.has_audio = 0;
+               dev->has_alsa_audio = false;
+               dev->audio_mode.has_audio = false;
                goto init_audio;
        }
 
@@ -615,7 +619,9 @@ int em28xx_capture_start(struct em28xx *dev, int start)
 {
        int rc;
 
-       if (dev->chip_id == CHIP_ID_EM2874 || dev->chip_id == CHIP_ID_EM28174) {
+       if (dev->chip_id == CHIP_ID_EM2874 ||
+           dev->chip_id == CHIP_ID_EM2884 ||
+           dev->chip_id == CHIP_ID_EM28174) {
                /* The Transport Stream Enable Register moved in em2874 */
                if (!start) {
                        rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
@@ -884,6 +890,7 @@ int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio)
        }
        return rc;
 }
+EXPORT_SYMBOL_GPL(em28xx_gpio_set);
 
 int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode)
 {
@@ -917,7 +924,7 @@ EXPORT_SYMBOL_GPL(em28xx_set_mode);
 static void em28xx_irq_callback(struct urb *urb)
 {
        struct em28xx *dev = urb->context;
-       int rc, i;
+       int i;
 
        switch (urb->status) {
        case 0:             /* success */
@@ -934,7 +941,7 @@ static void em28xx_irq_callback(struct urb *urb)
 
        /* Copy data from URB */
        spin_lock(&dev->slock);
-       rc = dev->isoc_ctl.isoc_copy(dev, urb);
+       dev->isoc_ctl.isoc_copy(dev, urb);
        spin_unlock(&dev->slock);
 
        /* Reset urb buffers */
@@ -1106,17 +1113,19 @@ EXPORT_SYMBOL_GPL(em28xx_init_isoc);
 int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev)
 {
        unsigned int chip_cfg2;
-       unsigned int packet_size = 564;
-
-       if (dev->chip_id == CHIP_ID_EM2874) {
-               /* FIXME - for now assume 564 like it was before, but the
-                  em2874 code should be added to return the proper value... */
-               packet_size = 564;
-       } else if (dev->chip_id == CHIP_ID_EM28174) {
-               /* FIXME same as em2874. 564 was enough for 22 Mbit DVB-T
-                  but too much for 44 Mbit DVB-C. */
-               packet_size = 752;
-       } else {
+       unsigned int packet_size;
+
+       switch (dev->chip_id) {
+       case CHIP_ID_EM2710:
+       case CHIP_ID_EM2750:
+       case CHIP_ID_EM2800:
+       case CHIP_ID_EM2820:
+       case CHIP_ID_EM2840:
+       case CHIP_ID_EM2860:
+               /* No DVB support */
+               return -EINVAL;
+       case CHIP_ID_EM2870:
+       case CHIP_ID_EM2883:
                /* TS max packet size stored in bits 1-0 of R01 */
                chip_cfg2 = em28xx_read_reg(dev, EM28XX_R01_CHIPCFG2);
                switch (chip_cfg2 & EM28XX_CHIPCFG2_TS_PACKETSIZE_MASK) {
@@ -1133,9 +1142,24 @@ int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev)
                        packet_size = 752;
                        break;
                }
+               break;
+       case CHIP_ID_EM2874:
+               /*
+                * FIXME: for now assumes 564 like it was before, but the
+                * em2874 code should be added to return the proper value
+                */
+               packet_size = 564;
+               break;
+       case CHIP_ID_EM2884:
+       case CHIP_ID_EM28174:
+       default:
+               /*
+                * FIXME: same as em2874. 564 was enough for 22 Mbit DVB-T
+                * but not enough for 44 Mbit DVB-C.
+                */
+               packet_size = 752;
        }
 
-       em28xx_coredbg("dvb max packet size=%d\n", packet_size);
        return packet_size;
 }
 EXPORT_SYMBOL_GPL(em28xx_isoc_dvb_max_packetsize);
index 7904ca4..e5916de 100644 (file)
@@ -1,7 +1,7 @@
 /*
  DVB device driver for em28xx
 
- (c) 2008 Mauro Carvalho Chehab <mchehab@infradead.org>
+ (c) 2008-2011 Mauro Carvalho Chehab <mchehab@infradead.org>
 
  (c) 2008 Devin Heitmueller <devin.heitmueller@gmail.com>
        - Fixes for the driver to properly work with HVR-950
@@ -40,6 +40,8 @@
 #include "s921.h"
 #include "drxd.h"
 #include "cxd2820r.h"
+#include "tda18271c2dd.h"
+#include "drxk.h"
 
 MODULE_DESCRIPTION("driver for em28xx based DVB cards");
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
@@ -73,6 +75,11 @@ struct em28xx_dvb {
        struct dmx_frontend        fe_hw;
        struct dmx_frontend        fe_mem;
        struct dvb_net             net;
+
+       /* Due to DRX-K - probably need changes */
+       int (*gate_ctrl)(struct dvb_frontend *, int);
+       struct semaphore      pll_mutex;
+       bool                    dont_attach_fe1;
 };
 
 
@@ -160,6 +167,11 @@ static int start_streaming(struct em28xx_dvb *dvb)
                return rc;
 
        max_dvb_packet_size = em28xx_isoc_dvb_max_packetsize(dev);
+       if (max_dvb_packet_size < 0)
+               return max_dvb_packet_size;
+       dprintk(1, "Using %d buffers each with %d bytes\n",
+               EM28XX_DVB_NUM_BUFS,
+               max_dvb_packet_size);
 
        return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS,
                                EM28XX_DVB_NUM_BUFS, max_dvb_packet_size,
@@ -295,6 +307,79 @@ static struct drxd_config em28xx_drxd = {
        .disable_i2c_gate_ctrl = 1,
 };
 
+struct drxk_config terratec_h5_drxk = {
+       .adr = 0x29,
+       .single_master = 1,
+       .no_i2c_bridge = 1,
+       .microcode_name = "dvb-usb-terratec-h5-drxk.fw",
+};
+
+static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       struct em28xx_dvb *dvb = fe->sec_priv;
+       int status;
+
+       if (!dvb)
+               return -EINVAL;
+
+       if (enable) {
+               down(&dvb->pll_mutex);
+               status = dvb->gate_ctrl(fe, 1);
+       } else {
+               status = dvb->gate_ctrl(fe, 0);
+               up(&dvb->pll_mutex);
+       }
+       return status;
+}
+
+static void terratec_h5_init(struct em28xx *dev)
+{
+       int i;
+       struct em28xx_reg_seq terratec_h5_init[] = {
+               {EM28XX_R08_GPIO,       0xff,   0xff,   10},
+               {EM2874_R80_GPIO,       0xf6,   0xff,   100},
+               {EM2874_R80_GPIO,       0xf2,   0xff,   50},
+               {EM2874_R80_GPIO,       0xf6,   0xff,   100},
+               { -1,                   -1,     -1,     -1},
+       };
+       struct em28xx_reg_seq terratec_h5_end[] = {
+               {EM2874_R80_GPIO,       0xe6,   0xff,   100},
+               {EM2874_R80_GPIO,       0xa6,   0xff,   50},
+               {EM2874_R80_GPIO,       0xe6,   0xff,   100},
+               { -1,                   -1,     -1,     -1},
+       };
+       struct {
+               unsigned char r[4];
+               int len;
+       } regs[] = {
+               {{ 0x06, 0x02, 0x00, 0x31 }, 4},
+               {{ 0x01, 0x02 }, 2},
+               {{ 0x01, 0x02, 0x00, 0xc6 }, 4},
+               {{ 0x01, 0x00 }, 2},
+               {{ 0x01, 0x00, 0xff, 0xaf }, 4},
+               {{ 0x01, 0x00, 0x03, 0xa0 }, 4},
+               {{ 0x01, 0x00 }, 2},
+               {{ 0x01, 0x00, 0x73, 0xaf }, 4},
+               {{ 0x04, 0x00 }, 2},
+               {{ 0x00, 0x04 }, 2},
+               {{ 0x00, 0x04, 0x00, 0x0a }, 4},
+               {{ 0x04, 0x14 }, 2},
+               {{ 0x04, 0x14, 0x00, 0x00 }, 4},
+       };
+
+       em28xx_gpio_set(dev, terratec_h5_init);
+       em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40);
+       msleep(10);
+       em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x45);
+       msleep(10);
+
+       dev->i2c_client.addr = 0x82 >> 1;
+
+       for (i = 0; i < ARRAY_SIZE(regs); i++)
+               i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len);
+       em28xx_gpio_set(dev, terratec_h5_end);
+};
+
 static int mt352_terratec_xs_init(struct dvb_frontend *fe)
 {
        /* Values extracted from a USB trace of the Terratec Windows driver */
@@ -516,7 +601,7 @@ static void unregister_dvb(struct em28xx_dvb *dvb)
        if (dvb->fe[1])
                dvb_unregister_frontend(dvb->fe[1]);
        dvb_unregister_frontend(dvb->fe[0]);
-       if (dvb->fe[1])
+       if (dvb->fe[1] && !dvb->dont_attach_fe1)
                dvb_frontend_detach(dvb->fe[1]);
        dvb_frontend_detach(dvb->fe[0]);
        dvb_unregister_adapter(&dvb->adapter);
@@ -546,7 +631,7 @@ static int dvb_init(struct em28xx *dev)
        em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
        /* init frontend */
        switch (dev->model) {
-       case EM2874_LEADERSHIP_ISDBT:
+       case EM2874_BOARD_LEADERSHIP_ISDBT:
                dvb->fe[0] = dvb_attach(s921_attach,
                                &sharp_isdbt, &dev->i2c_adap);
 
@@ -688,6 +773,41 @@ static int dvb_init(struct em28xx *dev)
                                /* leave FE 0 still active */
                        }
                }
+               break;
+       case EM2884_BOARD_TERRATEC_H5:
+               terratec_h5_init(dev);
+
+               dvb->dont_attach_fe1 = 1;
+
+               dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap, &dvb->fe[1]);
+               if (!dvb->fe[0]) {
+                       result = -EINVAL;
+                       goto out_free;
+               }
+
+               /* FIXME: do we need a pll semaphore? */
+               dvb->fe[0]->sec_priv = dvb;
+               sema_init(&dvb->pll_mutex, 1);
+               dvb->gate_ctrl = dvb->fe[0]->ops.i2c_gate_ctrl;
+               dvb->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;
+               dvb->fe[1]->id = 1;
+
+               /* Attach tda18271 to DVB-C frontend */
+               if (dvb->fe[0]->ops.i2c_gate_ctrl)
+                       dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1);
+               if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0], &dev->i2c_adap, 0x60)) {
+                       result = -EINVAL;
+                       goto out_free;
+               }
+               if (dvb->fe[0]->ops.i2c_gate_ctrl)
+                       dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 0);
+
+               /* Hack - needed by drxk/tda18271c2dd */
+               dvb->fe[1]->tuner_priv = dvb->fe[0]->tuner_priv;
+               memcpy(&dvb->fe[1]->ops.tuner_ops,
+                      &dvb->fe[0]->ops.tuner_ops,
+                      sizeof(dvb->fe[0]->ops.tuner_ops));
+
                break;
        default:
                em28xx_errdev("/2: The frontend of your DVB/ATSC card"
index 4739fc7..36f5a9b 100644 (file)
@@ -181,16 +181,25 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, unsigned char addr,
 
 /*
  * em28xx_i2c_send_bytes()
- * untested for more than 4 bytes
  */
 static int em28xx_i2c_send_bytes(void *data, unsigned char addr, char *buf,
                                 short len, int stop)
 {
        int wrcount = 0;
        struct em28xx *dev = (struct em28xx *)data;
+       int write_timeout, ret;
 
        wrcount = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len);
 
+       /* Seems to be required after a write */
+       for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
+            write_timeout -= 5) {
+               ret = dev->em28xx_read_reg(dev, 0x05);
+               if (!ret)
+                       break;
+               msleep(5);
+       }
+
        return wrcount;
 }
 
@@ -218,9 +227,7 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, unsigned char addr,
  */
 static int em28xx_i2c_check_for_device(struct em28xx *dev, unsigned char addr)
 {
-       char msg;
        int ret;
-       msg = addr;
 
        ret = dev->em28xx_read_reg_req(dev, 2, addr);
        if (ret < 0) {
@@ -332,7 +339,9 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
        struct em28xx_eeprom *em_eeprom = (void *)eedata;
        int i, err, size = len, block;
 
-       if (dev->chip_id == CHIP_ID_EM2874 || dev->chip_id == CHIP_ID_EM28174) {
+       if (dev->chip_id == CHIP_ID_EM2874 ||
+           dev->chip_id == CHIP_ID_EM28174 ||
+           dev->chip_id == CHIP_ID_EM2884) {
                /* Empia switched to a 16-bit addressable eeprom in newer
                   devices.  While we could certainly write a routine to read
                   the eeprom, there is nothing of use in there that cannot be
index ba1ba86..5d12b14 100644 (file)
@@ -372,6 +372,7 @@ int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 rc_type)
                ir->get_key = default_polling_getkey;
                break;
        case CHIP_ID_EM2874:
+       case CHIP_ID_EM28174:
                ir->get_key = em2874_polling_getkey;
                em28xx_write_regs(dev, EM2874_R50_IR_CONFIG, &ir_config, 1);
                break;
index e92a28e..66f7923 100644 (file)
@@ -201,6 +201,7 @@ enum em28xx_chip_id {
        CHIP_ID_EM2870 = 35,
        CHIP_ID_EM2883 = 36,
        CHIP_ID_EM2874 = 65,
+       CHIP_ID_EM2884 = 68,
        CHIP_ID_EM28174 = 113,
 };
 
index 7b6461d..d176dc0 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/bitmap.h>
 #include <linux/usb.h>
 #include <linux/i2c.h>
-#include <linux/version.h>
 #include <linux/mm.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
@@ -50,7 +49,8 @@
                      "Sascha Sommer <saschasommer@freenet.de>"
 
 #define DRIVER_DESC         "Empia em28xx based USB video device driver"
-#define EM28XX_VERSION_CODE  KERNEL_VERSION(0, 1, 2)
+
+#define EM28XX_VERSION "0.1.3"
 
 #define em28xx_videodbg(fmt, arg...) do {\
        if (video_debug) \
@@ -72,6 +72,7 @@ do {\
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
+MODULE_VERSION(EM28XX_VERSION);
 
 static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
 static unsigned int vbi_nr[]   = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
@@ -1757,8 +1758,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
        usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
 
-       cap->version = EM28XX_VERSION_CODE;
-
        cap->capabilities =
                        V4L2_CAP_SLICED_VBI_CAPTURE |
                        V4L2_CAP_VIDEO_CAPTURE |
@@ -1976,7 +1975,6 @@ static int radio_querycap(struct file *file, void  *priv,
        strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
        usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
 
-       cap->version = EM28XX_VERSION_CODE;
        cap->capabilities = V4L2_CAP_TUNER;
        return 0;
 }
@@ -2450,10 +2448,8 @@ int em28xx_register_analog_devices(struct em28xx *dev)
       u8 val;
        int ret;
 
-       printk(KERN_INFO "%s: v4l2 driver version %d.%d.%d\n",
-               dev->name,
-               (EM28XX_VERSION_CODE >> 16) & 0xff,
-               (EM28XX_VERSION_CODE >> 8) & 0xff, EM28XX_VERSION_CODE & 0xff);
+       printk(KERN_INFO "%s: v4l2 driver version %s\n",
+               dev->name, EM28XX_VERSION);
 
        /* set default norm */
        dev->norm = em28xx_video_template.current_norm;
index 3cca331..d80658b 100644 (file)
 #define EM2800_BOARD_VC211A                      74
 #define EM2882_BOARD_DIKOM_DK300                 75
 #define EM2870_BOARD_KWORLD_A340                 76
-#define EM2874_LEADERSHIP_ISDBT                          77
+#define EM2874_BOARD_LEADERSHIP_ISDBT            77
 #define EM28174_BOARD_PCTV_290E                   78
-
+#define EM2884_BOARD_TERRATEC_H5                 79
 
 /* Limits minimum and default number of buffers */
 #define EM28XX_MIN_BUF 4
@@ -487,6 +487,8 @@ struct em28xx {
        int devno;              /* marks the number of this device */
        enum em28xx_chip_id chip_id;
 
+       int audio_ifnum;
+
        struct v4l2_device v4l2_dev;
        struct em28xx_board board;
 
@@ -503,6 +505,7 @@ struct em28xx {
 
        unsigned int has_audio_class:1;
        unsigned int has_alsa_audio:1;
+       unsigned int is_audio_only:1;
 
        /* Controls audio streaming */
        struct work_struct wq_trigger;              /* Trigger to start/stop audio for alsa module */
@@ -697,6 +700,9 @@ int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
 void em28xx_release_resources(struct em28xx *dev);
 
 /* Provided by em28xx-input.c */
+
+#ifdef CONFIG_VIDEO_EM28XX_RC
+
 int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
 int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
 int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
@@ -709,6 +715,20 @@ void em28xx_deregister_snapshot_button(struct em28xx *dev);
 int em28xx_ir_init(struct em28xx *dev);
 int em28xx_ir_fini(struct em28xx *dev);
 
+#else
+
+#define em28xx_get_key_terratec                        NULL
+#define em28xx_get_key_em_haup                 NULL
+#define em28xx_get_key_pinnacle_usb_grey       NULL
+#define em28xx_get_key_winfast_usbii_deluxe    NULL
+
+static inline void em28xx_register_snapshot_button(struct em28xx *dev) {}
+static inline void em28xx_deregister_snapshot_button(struct em28xx *dev) {}
+static inline int em28xx_ir_init(struct em28xx *dev) { return 0; }
+static inline int em28xx_ir_fini(struct em28xx *dev) { return 0; }
+
+#endif
+
 /* Provided by em28xx-vbi.c */
 extern struct videobuf_queue_ops em28xx_vbi_qops;
 
index bf66189..14bb907 100644 (file)
@@ -21,7 +21,6 @@
 #ifndef _ET61X251_H_
 #define _ET61X251_H_
 
-#include <linux/version.h>
 #include <linux/usb.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
index a982750..9a1e80a 100644 (file)
@@ -18,6 +18,7 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
  ***************************************************************************/
 
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -48,8 +49,7 @@
 #define ET61X251_MODULE_AUTHOR  "(C) 2006-2007 Luca Risolia"
 #define ET61X251_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
 #define ET61X251_MODULE_LICENSE "GPL"
-#define ET61X251_MODULE_VERSION "1:1.09"
-#define ET61X251_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 9)
+#define ET61X251_MODULE_VERSION "1.1.10"
 
 /*****************************************************************************/
 
@@ -1579,7 +1579,7 @@ et61x251_vidioc_querycap(struct et61x251_device* cam, void __user * arg)
 {
        struct v4l2_capability cap = {
                .driver = "et61x251",
-               .version = ET61X251_MODULE_VERSION_CODE,
+               .version = LINUX_VERSION_CODE,
                .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
                                V4L2_CAP_STREAMING,
        };
@@ -2480,16 +2480,8 @@ static long et61x251_ioctl_v4l2(struct file *filp,
        case VIDIOC_S_PARM:
                return et61x251_vidioc_s_parm(cam, arg);
 
-       case VIDIOC_G_STD:
-       case VIDIOC_S_STD:
-       case VIDIOC_QUERYSTD:
-       case VIDIOC_ENUMSTD:
-       case VIDIOC_QUERYMENU:
-       case VIDIOC_ENUM_FRAMEINTERVALS:
-               return -EINVAL;
-
        default:
-               return -EINVAL;
+               return -ENOTTY;
 
        }
 }
index 908d701..27cb197 100644 (file)
 #include <linux/io.h>
 #include <linux/of_platform.h>
 #include <linux/slab.h>
-#include <linux/version.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/videobuf-dma-contig.h>
 
 #define DRV_NAME               "fsl_viu"
-#define VIU_MAJOR_VERSION      0
-#define VIU_MINOR_VERSION      5
-#define VIU_RELEASE            0
-#define VIU_VERSION            KERNEL_VERSION(VIU_MAJOR_VERSION, \
-                                              VIU_MINOR_VERSION, \
-                                              VIU_RELEASE)
+#define VIU_VERSION            "0.5.1"
 
 #define BUFFER_TIMEOUT         msecs_to_jiffies(500)  /* 0.5 seconds */
 
@@ -610,7 +604,6 @@ static int vidioc_querycap(struct file *file, void *priv,
 {
        strcpy(cap->driver, "viu");
        strcpy(cap->card, "viu");
-       cap->version = VIU_VERSION;
        cap->capabilities =     V4L2_CAP_VIDEO_CAPTURE |
                                V4L2_CAP_STREAMING     |
                                V4L2_CAP_VIDEO_OVERLAY |
@@ -1684,3 +1677,4 @@ module_exit(viu_exit);
 MODULE_DESCRIPTION("Freescale Video-In(VIU)");
 MODULE_AUTHOR("Hongjun Chen");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(VIU_VERSION);
index 34ae2c2..43d9a20 100644 (file)
@@ -179,6 +179,16 @@ config USB_GSPCA_PAC7311
          To compile this driver as a module, choose M here: the
          module will be called gspca_pac7311.
 
+config USB_GSPCA_SE401
+       tristate "SE401 USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+        Say Y here if you want support for cameras based on the
+        Endpoints (formerly known as AOX) se401 chip.
+
+        To compile this driver as a module, choose M here: the
+        module will be called gspca_se401.
+
 config USB_GSPCA_SN9C2028
        tristate "SONIX Dual-Mode USB Camera Driver"
        depends on VIDEO_V4L2 && USB_GSPCA
index 802fbe1..d6364a8 100644 (file)
@@ -16,6 +16,7 @@ obj-$(CONFIG_USB_GSPCA_OV534_9)  += gspca_ov534_9.o
 obj-$(CONFIG_USB_GSPCA_PAC207)   += gspca_pac207.o
 obj-$(CONFIG_USB_GSPCA_PAC7302)  += gspca_pac7302.o
 obj-$(CONFIG_USB_GSPCA_PAC7311)  += gspca_pac7311.o
+obj-$(CONFIG_USB_GSPCA_SE401)    += gspca_se401.o
 obj-$(CONFIG_USB_GSPCA_SN9C2028) += gspca_sn9c2028.o
 obj-$(CONFIG_USB_GSPCA_SN9C20X)  += gspca_sn9c20x.o
 obj-$(CONFIG_USB_GSPCA_SONIXB)   += gspca_sonixb.o
@@ -58,6 +59,7 @@ gspca_ov534_9-objs  := ov534_9.o
 gspca_pac207-objs   := pac207.o
 gspca_pac7302-objs  := pac7302.o
 gspca_pac7311-objs  := pac7311.o
+gspca_se401-objs    := se401.o
 gspca_sn9c2028-objs := sn9c2028.o
 gspca_sn9c20x-objs  := sn9c20x.o
 gspca_sonixb-objs   := sonixb.o
index 49ad4ac..0330a02 100644 (file)
@@ -18,7 +18,6 @@
  */
 #ifndef GL860_DEV_H
 #define GL860_DEV_H
-#include <linux/version.h>
 
 #include "gspca.h"
 
index 08ce994..5da4879 100644 (file)
@@ -24,7 +24,6 @@
 #define MODULE_NAME "gspca"
 
 #include <linux/init.h>
-#include <linux/version.h>
 #include <linux/fs.h>
 #include <linux/vmalloc.h>
 #include <linux/sched.h>
 #error "DEF_NURBS too big"
 #endif
 
+#define DRIVER_VERSION_NUMBER  "2.13.0"
+
 MODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>");
 MODULE_DESCRIPTION("GSPCA USB Camera Driver");
 MODULE_LICENSE("GPL");
-
-#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 13, 0)
+MODULE_VERSION(DRIVER_VERSION_NUMBER);
 
 #ifdef GSPCA_DEBUG
 int gspca_debug = D_ERR | D_PROBE;
@@ -443,8 +443,11 @@ void gspca_frame_add(struct gspca_dev *gspca_dev,
        } else {
                switch (gspca_dev->last_packet_type) {
                case DISCARD_PACKET:
-                       if (packet_type == LAST_PACKET)
+                       if (packet_type == LAST_PACKET) {
                                gspca_dev->last_packet_type = packet_type;
+                               gspca_dev->image = NULL;
+                               gspca_dev->image_len = 0;
+                       }
                        return;
                case LAST_PACKET:
                        return;
@@ -1278,10 +1281,10 @@ static int vidioc_querycap(struct file *file, void  *priv,
                ret = -ENODEV;
                goto out;
        }
-       strncpy((char *) cap->driver, gspca_dev->sd_desc->name,
+       strlcpy((char *) cap->driver, gspca_dev->sd_desc->name,
                        sizeof cap->driver);
        if (gspca_dev->dev->product != NULL) {
-               strncpy((char *) cap->card, gspca_dev->dev->product,
+               strlcpy((char *) cap->card, gspca_dev->dev->product,
                        sizeof cap->card);
        } else {
                snprintf((char *) cap->card, sizeof cap->card,
@@ -1291,7 +1294,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        }
        usb_make_path(gspca_dev->dev, (char *) cap->bus_info,
                        sizeof(cap->bus_info));
-       cap->version = DRIVER_VERSION_NUMBER;
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
                          | V4L2_CAP_STREAMING
                          | V4L2_CAP_READWRITE;
@@ -1460,7 +1462,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
                return -EINVAL;
        input->type = V4L2_INPUT_TYPE_CAMERA;
        input->status = gspca_dev->cam.input_flags;
-       strncpy(input->name, gspca_dev->sd_desc->name,
+       strlcpy(input->name, gspca_dev->sd_desc->name,
                sizeof input->name);
        return 0;
 }
@@ -2478,10 +2480,7 @@ EXPORT_SYMBOL(gspca_auto_gain_n_exposure);
 /* -- module insert / remove -- */
 static int __init gspca_init(void)
 {
-       info("v%d.%d.%d registered",
-               (DRIVER_VERSION_NUMBER >> 16) & 0xff,
-               (DRIVER_VERSION_NUMBER >> 8) & 0xff,
-               DRIVER_VERSION_NUMBER & 0xff);
+       info("v" DRIVER_VERSION_NUMBER " registered");
        return 0;
 }
 static void __exit gspca_exit(void)
index 057e287..0800433 100644 (file)
@@ -134,6 +134,7 @@ enum sensors {
        SEN_OV7670,
        SEN_OV76BE,
        SEN_OV8610,
+       SEN_OV9600,
 };
 
 /* Note this is a bit of a hack, but the w9968cf driver needs the code for all
@@ -340,6 +341,10 @@ static const unsigned ctrl_dis[] = {
                        (1 << EXPOSURE) |
                        (1 << AUTOGAIN) |
                        (1 << FREQ),
+[SEN_OV9600] =         ((1 << NCTRL) - 1)      /* no control */
+                       ^ ((1 << EXPOSURE)      /* but exposure */
+                        | (1 << AUTOGAIN)),    /* and autogain */
+
 };
 
 static const struct v4l2_pix_format ov519_vga_mode[] = {
@@ -525,6 +530,17 @@ static const struct v4l2_pix_format ovfx2_ov3610_mode[] = {
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 0},
 };
+static const struct v4l2_pix_format ovfx2_ov9600_mode[] = {
+       {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 640,
+               .sizeimage = 640 * 480,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 1},
+       {1280, 1024, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 1280,
+               .sizeimage = 1280 * 1024,
+               .colorspace = V4L2_COLORSPACE_SRGB},
+};
 
 /* Registers common to OV511 / OV518 */
 #define R51x_FIFO_PSIZE                        0x30    /* 2 bytes wide w/ OV518(+) */
@@ -1807,6 +1823,22 @@ static const struct ov_i2c_regvals norm_7660[] = {
                        | OV7670_COM8_AEC},
        {0xa1, 0xc8}
 };
+static const struct ov_i2c_regvals norm_9600[] = {
+       {0x12, 0x80},
+       {0x0c, 0x28},
+       {0x11, 0x80},
+       {0x13, 0xb5},
+       {0x14, 0x3e},
+       {0x1b, 0x04},
+       {0x24, 0xb0},
+       {0x25, 0x90},
+       {0x26, 0x94},
+       {0x35, 0x90},
+       {0x37, 0x07},
+       {0x38, 0x08},
+       {0x01, 0x8e},
+       {0x02, 0x85}
+};
 
 /* 7670. Defaults taken from OmniVision provided data,
 *  as provided by Jonathan Corbet of OLPC              */
@@ -2400,9 +2432,12 @@ static int ov518_i2c_r(struct sd *sd, u8 reg)
 
        /* Initiate 2-byte write cycle */
        reg_w(sd, R518_I2C_CTL, 0x03);
+       reg_r8(sd, R518_I2C_CTL);
 
        /* Initiate 2-byte read cycle */
        reg_w(sd, R518_I2C_CTL, 0x05);
+       reg_r8(sd, R518_I2C_CTL);
+
        value = reg_r(sd, R51x_I2C_DATA);
        PDEBUG(D_USBI, "ov518_i2c_r %02x %02x", reg, value);
        return value;
@@ -2686,7 +2721,7 @@ static void write_i2c_regvals(struct sd *sd,
  *
  ***************************************************************************/
 
-/* This initializes the OV2x10 / OV3610 / OV3620 */
+/* This initializes the OV2x10 / OV3610 / OV3620 / OV9600 */
 static void ov_hires_configure(struct sd *sd)
 {
        int high, low;
@@ -2702,19 +2737,32 @@ static void ov_hires_configure(struct sd *sd)
        high = i2c_r(sd, 0x0a);
        low = i2c_r(sd, 0x0b);
        /* info("%x, %x", high, low); */
-       if (high == 0x96 && low == 0x40) {
-               PDEBUG(D_PROBE, "Sensor is an OV2610");
-               sd->sensor = SEN_OV2610;
-       } else if (high == 0x96 && low == 0x41) {
-               PDEBUG(D_PROBE, "Sensor is an OV2610AE");
-               sd->sensor = SEN_OV2610AE;
-       } else if (high == 0x36 && (low & 0x0f) == 0x00) {
-               PDEBUG(D_PROBE, "Sensor is an OV3610");
-               sd->sensor = SEN_OV3610;
-       } else {
-               err("Error unknown sensor type: %02x%02x",
-                       high, low);
+       switch (high) {
+       case 0x96:
+               switch (low) {
+               case 0x40:
+                       PDEBUG(D_PROBE, "Sensor is a OV2610");
+                       sd->sensor = SEN_OV2610;
+                       return;
+               case 0x41:
+                       PDEBUG(D_PROBE, "Sensor is a OV2610AE");
+                       sd->sensor = SEN_OV2610AE;
+                       return;
+               case 0xb1:
+                       PDEBUG(D_PROBE, "Sensor is a OV9600");
+                       sd->sensor = SEN_OV9600;
+                       return;
+               }
+               break;
+       case 0x36:
+               if ((low & 0x0f) == 0x00) {
+                       PDEBUG(D_PROBE, "Sensor is a OV3610");
+                       sd->sensor = SEN_OV3610;
+                       return;
+               }
+               break;
        }
+       err("Error unknown sensor type: %02x%02x", high, low);
 }
 
 /* This initializes the OV8110, OV8610 sensor. The OV8110 uses
@@ -3400,6 +3448,10 @@ static int sd_init(struct gspca_dev *gspca_dev)
                        cam->cam_mode = ovfx2_ov3610_mode;
                        cam->nmodes = ARRAY_SIZE(ovfx2_ov3610_mode);
                        break;
+               case SEN_OV9600:
+                       cam->cam_mode = ovfx2_ov9600_mode;
+                       cam->nmodes = ARRAY_SIZE(ovfx2_ov9600_mode);
+                       break;
                default:
                        if (sd->sif) {
                                cam->cam_mode = ov519_sif_mode;
@@ -3497,6 +3549,12 @@ static int sd_init(struct gspca_dev *gspca_dev)
        case SEN_OV8610:
                write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610));
                break;
+       case SEN_OV9600:
+               write_i2c_regvals(sd, norm_9600, ARRAY_SIZE(norm_9600));
+
+               /* enable autoexpo */
+/*             i2c_w_mask(sd, 0x13, 0x05, 0x05); */
+               break;
        }
        return gspca_dev->usb_err;
 error:
@@ -4085,6 +4143,33 @@ static void mode_init_ov_sensor_regs(struct sd *sd)
                i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
                i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */
                break;
+       case SEN_OV9600: {
+               const struct ov_i2c_regvals *vals;
+               static const struct ov_i2c_regvals sxga_15[] = {
+                       {0x11, 0x80}, {0x14, 0x3e}, {0x24, 0x85}, {0x25, 0x75}
+               };
+               static const struct ov_i2c_regvals sxga_7_5[] = {
+                       {0x11, 0x81}, {0x14, 0x3e}, {0x24, 0x85}, {0x25, 0x75}
+               };
+               static const struct ov_i2c_regvals vga_30[] = {
+                       {0x11, 0x81}, {0x14, 0x7e}, {0x24, 0x70}, {0x25, 0x60}
+               };
+               static const struct ov_i2c_regvals vga_15[] = {
+                       {0x11, 0x83}, {0x14, 0x3e}, {0x24, 0x80}, {0x25, 0x70}
+               };
+
+               /* frame rates:
+                *      15fps / 7.5 fps for 1280x1024
+                *      30fps / 15fps for 640x480
+                */
+               i2c_w_mask(sd, 0x12, qvga ? 0x40 : 0x00, 0x40);
+               if (qvga)
+                       vals = sd->frame_rate < 30 ? vga_15 : vga_30;
+               else
+                       vals = sd->frame_rate < 15 ? sxga_7_5 : sxga_15;
+               write_i2c_regvals(sd, vals, ARRAY_SIZE(sxga_15));
+               return;
+           }
        default:
                return;
        }
@@ -4120,6 +4205,7 @@ static void set_ov_sensor_window(struct sd *sd)
        case SEN_OV2610AE:
        case SEN_OV3610:
        case SEN_OV7670:
+       case SEN_OV9600:
                mode_init_ov_sensor_regs(sd);
                return;
        case SEN_OV7660:
@@ -4920,7 +5006,8 @@ static const struct sd_desc sd_desc = {
 static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x041e, 0x4003), .driver_info = BRIDGE_W9968CF },
        {USB_DEVICE(0x041e, 0x4052), .driver_info = BRIDGE_OV519 },
-       {USB_DEVICE(0x041e, 0x405f), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x041e, 0x405f),
+               .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
        {USB_DEVICE(0x041e, 0x4060), .driver_info = BRIDGE_OV519 },
        {USB_DEVICE(0x041e, 0x4061), .driver_info = BRIDGE_OV519 },
        {USB_DEVICE(0x041e, 0x4064),
diff --git a/drivers/media/video/gspca/se401.c b/drivers/media/video/gspca/se401.c
new file mode 100644 (file)
index 0000000..4c283c2
--- /dev/null
@@ -0,0 +1,774 @@
+/*
+ * GSPCA Endpoints (formerly known as AOX) se401 USB Camera sub Driver
+ *
+ * Copyright (C) 2011 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Based on the v4l1 se401 driver which is:
+ *
+ * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#define MODULE_NAME "se401"
+
+#define BULK_SIZE 4096
+#define PACKET_SIZE 1024
+#define READ_REQ_SIZE 64
+#define MAX_MODES ((READ_REQ_SIZE - 6) / 4)
+/* The se401 compression algorithm uses a fixed quant factor, which
+   can be configured by setting the high nibble of the SE401_OPERATINGMODE
+   feature. This needs to exactly match what is in libv4l! */
+#define SE401_QUANT_FACT 8
+
+#include <linux/input.h>
+#include <linux/slab.h>
+#include "gspca.h"
+#include "se401.h"
+
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_DESCRIPTION("Endpoints se401");
+MODULE_LICENSE("GPL");
+
+/* controls */
+enum e_ctrl {
+       BRIGHTNESS,
+       GAIN,
+       EXPOSURE,
+       FREQ,
+       NCTRL   /* number of controls */
+};
+
+/* exposure change state machine states */
+enum {
+       EXPO_CHANGED,
+       EXPO_DROP_FRAME,
+       EXPO_NO_CHANGE,
+};
+
+/* specific webcam descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;     /* !! must be the first item */
+       struct gspca_ctrl ctrls[NCTRL];
+       struct v4l2_pix_format fmts[MAX_MODES];
+       int pixels_read;
+       int packet_read;
+       u8 packet[PACKET_SIZE];
+       u8 restart_stream;
+       u8 button_state;
+       u8 resetlevel;
+       u8 resetlevel_frame_count;
+       int resetlevel_adjust_dir;
+       int expo_change_state;
+};
+
+static void setbrightness(struct gspca_dev *gspca_dev);
+static void setgain(struct gspca_dev *gspca_dev);
+static void setexposure(struct gspca_dev *gspca_dev);
+
+static const struct ctrl sd_ctrls[NCTRL] = {
+[BRIGHTNESS] = {
+               {
+                       .id      = V4L2_CID_BRIGHTNESS,
+                       .type    = V4L2_CTRL_TYPE_INTEGER,
+                       .name    = "Brightness",
+                       .minimum = 0,
+                       .maximum = 255,
+                       .step    = 1,
+                       .default_value = 15,
+               },
+               .set_control = setbrightness
+       },
+[GAIN] = {
+               {
+                       .id      = V4L2_CID_GAIN,
+                       .type    = V4L2_CTRL_TYPE_INTEGER,
+                       .name    = "Gain",
+                       .minimum = 0,
+                       .maximum = 50, /* Really 63 but > 50 is not pretty */
+                       .step    = 1,
+                       .default_value = 25,
+               },
+               .set_control = setgain
+       },
+[EXPOSURE] = {
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "Exposure",
+                       .minimum = 0,
+                       .maximum = 32767,
+                       .step = 1,
+                       .default_value = 15000,
+               },
+               .set_control = setexposure
+       },
+[FREQ] = {
+               {
+                       .id      = V4L2_CID_POWER_LINE_FREQUENCY,
+                       .type    = V4L2_CTRL_TYPE_MENU,
+                       .name    = "Light frequency filter",
+                       .minimum = 0,
+                       .maximum = 2,
+                       .step    = 1,
+                       .default_value = 0,
+               },
+               .set_control = setexposure
+       },
+};
+
+static void se401_write_req(struct gspca_dev *gspca_dev, u16 req, u16 value,
+                           int silent)
+{
+       int err;
+
+       if (gspca_dev->usb_err < 0)
+               return;
+
+       err = usb_control_msg(gspca_dev->dev,
+                             usb_sndctrlpipe(gspca_dev->dev, 0), req,
+                             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             value, 0, NULL, 0, 1000);
+       if (err < 0) {
+               if (!silent)
+                       err("write req failed req %#04x val %#04x error %d",
+                           req, value, err);
+               gspca_dev->usb_err = err;
+       }
+}
+
+static void se401_read_req(struct gspca_dev *gspca_dev, u16 req, int silent)
+{
+       int err;
+
+       if (gspca_dev->usb_err < 0)
+               return;
+
+       if (USB_BUF_SZ < READ_REQ_SIZE) {
+               err("USB_BUF_SZ too small!!");
+               gspca_dev->usb_err = -ENOBUFS;
+               return;
+       }
+
+       err = usb_control_msg(gspca_dev->dev,
+                             usb_rcvctrlpipe(gspca_dev->dev, 0), req,
+                             USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             0, 0, gspca_dev->usb_buf, READ_REQ_SIZE, 1000);
+       if (err < 0) {
+               if (!silent)
+                       err("read req failed req %#04x error %d", req, err);
+               gspca_dev->usb_err = err;
+       }
+}
+
+static void se401_set_feature(struct gspca_dev *gspca_dev,
+                             u16 selector, u16 param)
+{
+       int err;
+
+       if (gspca_dev->usb_err < 0)
+               return;
+
+       err = usb_control_msg(gspca_dev->dev,
+                             usb_sndctrlpipe(gspca_dev->dev, 0),
+                             SE401_REQ_SET_EXT_FEATURE,
+                             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             param, selector, NULL, 0, 1000);
+       if (err < 0) {
+               err("set feature failed sel %#04x param %#04x error %d",
+                   selector, param, err);
+               gspca_dev->usb_err = err;
+       }
+}
+
+static int se401_get_feature(struct gspca_dev *gspca_dev, u16 selector)
+{
+       int err;
+
+       if (gspca_dev->usb_err < 0)
+               return gspca_dev->usb_err;
+
+       if (USB_BUF_SZ < 2) {
+               err("USB_BUF_SZ too small!!");
+               gspca_dev->usb_err = -ENOBUFS;
+               return gspca_dev->usb_err;
+       }
+
+       err = usb_control_msg(gspca_dev->dev,
+                             usb_rcvctrlpipe(gspca_dev->dev, 0),
+                             SE401_REQ_GET_EXT_FEATURE,
+                             USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             0, selector, gspca_dev->usb_buf, 2, 1000);
+       if (err < 0) {
+               err("get feature failed sel %#04x error %d", selector, err);
+               gspca_dev->usb_err = err;
+               return err;
+       }
+       return gspca_dev->usb_buf[0] | (gspca_dev->usb_buf[1] << 8);
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (gspca_dev->ctrl_dis & (1 << BRIGHTNESS))
+               return;
+
+       /* HDG: this does not seem to do anything on my cam */
+       se401_write_req(gspca_dev, SE401_REQ_SET_BRT,
+                       sd->ctrls[BRIGHTNESS].val, 0);
+}
+
+static void setgain(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u16 gain = 63 - sd->ctrls[GAIN].val;
+
+       /* red color gain */
+       se401_set_feature(gspca_dev, HV7131_REG_ARCG, gain);
+       /* green color gain */
+       se401_set_feature(gspca_dev, HV7131_REG_AGCG, gain);
+       /* blue color gain */
+       se401_set_feature(gspca_dev, HV7131_REG_ABCG, gain);
+}
+
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int integration = sd->ctrls[EXPOSURE].val << 6;
+       u8 expose_h, expose_m, expose_l;
+
+       /* Do this before the set_feature calls, for proper timing wrt
+          the interrupt driven pkt_scan. Note we may still race but that
+          is not a big issue, the expo change state machine is merely for
+          avoiding underexposed frames getting send out, if one sneaks
+          through so be it */
+       sd->expo_change_state = EXPO_CHANGED;
+
+       if (sd->ctrls[FREQ].val == V4L2_CID_POWER_LINE_FREQUENCY_50HZ)
+               integration = integration - integration % 106667;
+       if (sd->ctrls[FREQ].val == V4L2_CID_POWER_LINE_FREQUENCY_60HZ)
+               integration = integration - integration % 88889;
+
+       expose_h = (integration >> 16);
+       expose_m = (integration >> 8);
+       expose_l = integration;
+
+       /* integration time low */
+       se401_set_feature(gspca_dev, HV7131_REG_TITL, expose_l);
+       /* integration time mid */
+       se401_set_feature(gspca_dev, HV7131_REG_TITM, expose_m);
+       /* integration time high */
+       se401_set_feature(gspca_dev, HV7131_REG_TITU, expose_h);
+}
+
+static int sd_config(struct gspca_dev *gspca_dev,
+                       const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *)gspca_dev;
+       struct cam *cam = &gspca_dev->cam;
+       u8 *cd = gspca_dev->usb_buf;
+       int i, j, n;
+       int widths[MAX_MODES], heights[MAX_MODES];
+
+       /* Read the camera descriptor */
+       se401_read_req(gspca_dev, SE401_REQ_GET_CAMERA_DESCRIPTOR, 1);
+       if (gspca_dev->usb_err) {
+               /* Sometimes after being idle for a while the se401 won't
+                  respond and needs a good kicking  */
+               usb_reset_device(gspca_dev->dev);
+               gspca_dev->usb_err = 0;
+               se401_read_req(gspca_dev, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0);
+       }
+
+       /* Some cameras start with their LED on */
+       se401_write_req(gspca_dev, SE401_REQ_LED_CONTROL, 0, 0);
+       if (gspca_dev->usb_err)
+               return gspca_dev->usb_err;
+
+       if (cd[1] != 0x41) {
+               err("Wrong descriptor type");
+               return -ENODEV;
+       }
+
+       if (!(cd[2] & SE401_FORMAT_BAYER)) {
+               err("Bayer format not supported!");
+               return -ENODEV;
+       }
+
+       if (cd[3])
+               info("ExtraFeatures: %d", cd[3]);
+
+       n = cd[4] | (cd[5] << 8);
+       if (n > MAX_MODES) {
+               err("Too many frame sizes");
+               return -ENODEV;
+       }
+
+       for (i = 0; i < n ; i++) {
+               widths[i] = cd[6 + i * 4 + 0] | (cd[6 + i * 4 + 1] << 8);
+               heights[i] = cd[6 + i * 4 + 2] | (cd[6 + i * 4 + 3] << 8);
+       }
+
+       for (i = 0; i < n ; i++) {
+               sd->fmts[i].width = widths[i];
+               sd->fmts[i].height = heights[i];
+               sd->fmts[i].field = V4L2_FIELD_NONE;
+               sd->fmts[i].colorspace = V4L2_COLORSPACE_SRGB;
+               sd->fmts[i].priv = 1;
+
+               /* janggu compression only works for 1/4th or 1/16th res */
+               for (j = 0; j < n; j++) {
+                       if (widths[j] / 2 == widths[i] &&
+                           heights[j] / 2 == heights[i]) {
+                               sd->fmts[i].priv = 2;
+                               break;
+                       }
+               }
+               /* 1/16th if available too is better then 1/4th, because
+                  we then use a larger area of the sensor */
+               for (j = 0; j < n; j++) {
+                       if (widths[j] / 4 == widths[i] &&
+                           heights[j] / 4 == heights[i]) {
+                               sd->fmts[i].priv = 4;
+                               break;
+                       }
+               }
+
+               if (sd->fmts[i].priv == 1) {
+                       /* Not a 1/4th or 1/16th res, use bayer */
+                       sd->fmts[i].pixelformat = V4L2_PIX_FMT_SBGGR8;
+                       sd->fmts[i].bytesperline = widths[i];
+                       sd->fmts[i].sizeimage = widths[i] * heights[i];
+                       info("Frame size: %dx%d bayer", widths[i], heights[i]);
+               } else {
+                       /* Found a match use janggu compression */
+                       sd->fmts[i].pixelformat = V4L2_PIX_FMT_SE401;
+                       sd->fmts[i].bytesperline = 0;
+                       sd->fmts[i].sizeimage = widths[i] * heights[i] * 3;
+                       info("Frame size: %dx%d 1/%dth janggu",
+                            widths[i], heights[i],
+                            sd->fmts[i].priv * sd->fmts[i].priv);
+               }
+       }
+
+       cam->cam_mode = sd->fmts;
+       cam->nmodes = n;
+       cam->bulk = 1;
+       cam->bulk_size = BULK_SIZE;
+       cam->bulk_nurbs = 4;
+       cam->ctrls = sd->ctrls;
+       gspca_dev->nbalt = 1;  /* Ignore the bogus isoc alt settings */
+       sd->resetlevel = 0x2d; /* Set initial resetlevel */
+
+       /* See if the camera supports brightness */
+       se401_read_req(gspca_dev, SE401_REQ_GET_BRT, 1);
+       if (gspca_dev->usb_err) {
+               gspca_dev->ctrl_dis = (1 << BRIGHTNESS);
+               gspca_dev->usb_err = 0;
+       }
+
+       return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+       return 0;
+}
+
+/* -- start the camera -- */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *)gspca_dev;
+       int mult = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+       int mode = 0;
+
+       se401_write_req(gspca_dev, SE401_REQ_CAMERA_POWER, 1, 1);
+       if (gspca_dev->usb_err) {
+               /* Sometimes after being idle for a while the se401 won't
+                  respond and needs a good kicking  */
+               usb_reset_device(gspca_dev->dev);
+               gspca_dev->usb_err = 0;
+               se401_write_req(gspca_dev, SE401_REQ_CAMERA_POWER, 1, 0);
+       }
+       se401_write_req(gspca_dev, SE401_REQ_LED_CONTROL, 1, 0);
+
+       se401_set_feature(gspca_dev, HV7131_REG_MODE_B, 0x05);
+
+       /* set size + mode */
+       se401_write_req(gspca_dev, SE401_REQ_SET_WIDTH,
+                       gspca_dev->width * mult, 0);
+       se401_write_req(gspca_dev, SE401_REQ_SET_HEIGHT,
+                       gspca_dev->height * mult, 0);
+       /*
+        * HDG: disabled this as it does not seem to do anything
+        * se401_write_req(gspca_dev, SE401_REQ_SET_OUTPUT_MODE,
+        *                 SE401_FORMAT_BAYER, 0);
+        */
+
+       switch (mult) {
+       case 1: /* Raw bayer */
+               mode = 0x03; break;
+       case 2: /* 1/4th janggu */
+               mode = SE401_QUANT_FACT << 4; break;
+       case 4: /* 1/16th janggu */
+               mode = (SE401_QUANT_FACT << 4) | 0x02; break;
+       }
+       se401_set_feature(gspca_dev, SE401_OPERATINGMODE, mode);
+
+       setbrightness(gspca_dev);
+       setgain(gspca_dev);
+       setexposure(gspca_dev);
+       se401_set_feature(gspca_dev, HV7131_REG_ARLV, sd->resetlevel);
+
+       sd->packet_read = 0;
+       sd->pixels_read = 0;
+       sd->restart_stream = 0;
+       sd->resetlevel_frame_count = 0;
+       sd->resetlevel_adjust_dir = 0;
+       sd->expo_change_state = EXPO_NO_CHANGE;
+
+       se401_write_req(gspca_dev, SE401_REQ_START_CONTINUOUS_CAPTURE, 0, 0);
+
+       return gspca_dev->usb_err;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       se401_write_req(gspca_dev, SE401_REQ_STOP_CONTINUOUS_CAPTURE, 0, 0);
+       se401_write_req(gspca_dev, SE401_REQ_LED_CONTROL, 0, 0);
+       se401_write_req(gspca_dev, SE401_REQ_CAMERA_POWER, 0, 0);
+}
+
+static void sd_dq_callback(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *)gspca_dev;
+       unsigned int ahrc, alrc;
+       int oldreset, adjust_dir;
+
+       /* Restart the stream if requested do so by pkt_scan */
+       if (sd->restart_stream) {
+               sd_stopN(gspca_dev);
+               sd_start(gspca_dev);
+               sd->restart_stream = 0;
+       }
+
+       /* Automatically adjust sensor reset level
+          Hyundai have some really nice docs about this and other sensor
+          related stuff on their homepage: www.hei.co.kr */
+       sd->resetlevel_frame_count++;
+       if (sd->resetlevel_frame_count < 20)
+               return;
+
+       /* For some reason this normally read-only register doesn't get reset
+          to zero after reading them just once... */
+       se401_get_feature(gspca_dev, HV7131_REG_HIREFNOH);
+       se401_get_feature(gspca_dev, HV7131_REG_HIREFNOL);
+       se401_get_feature(gspca_dev, HV7131_REG_LOREFNOH);
+       se401_get_feature(gspca_dev, HV7131_REG_LOREFNOL);
+       ahrc = 256*se401_get_feature(gspca_dev, HV7131_REG_HIREFNOH) +
+           se401_get_feature(gspca_dev, HV7131_REG_HIREFNOL);
+       alrc = 256*se401_get_feature(gspca_dev, HV7131_REG_LOREFNOH) +
+           se401_get_feature(gspca_dev, HV7131_REG_LOREFNOL);
+
+       /* Not an exact science, but it seems to work pretty well... */
+       oldreset = sd->resetlevel;
+       if (alrc > 10) {
+               while (alrc >= 10 && sd->resetlevel < 63) {
+                       sd->resetlevel++;
+                       alrc /= 2;
+               }
+       } else if (ahrc > 20) {
+               while (ahrc >= 20 && sd->resetlevel > 0) {
+                       sd->resetlevel--;
+                       ahrc /= 2;
+               }
+       }
+       /* Detect ping-pong-ing and halve adjustment to avoid overshoot */
+       if (sd->resetlevel > oldreset)
+               adjust_dir = 1;
+       else
+               adjust_dir = -1;
+       if (sd->resetlevel_adjust_dir &&
+           sd->resetlevel_adjust_dir != adjust_dir)
+               sd->resetlevel = oldreset + (sd->resetlevel - oldreset) / 2;
+
+       if (sd->resetlevel != oldreset) {
+               sd->resetlevel_adjust_dir = adjust_dir;
+               se401_set_feature(gspca_dev, HV7131_REG_ARLV, sd->resetlevel);
+       }
+
+       sd->resetlevel_frame_count = 0;
+}
+
+static void sd_complete_frame(struct gspca_dev *gspca_dev, u8 *data, int len)
+{
+       struct sd *sd = (struct sd *)gspca_dev;
+
+       switch (sd->expo_change_state) {
+       case EXPO_CHANGED:
+               /* The exposure was changed while this frame
+                  was being send, so this frame is ok */
+               sd->expo_change_state = EXPO_DROP_FRAME;
+               break;
+       case EXPO_DROP_FRAME:
+               /* The exposure was changed while this frame
+                  was being captured, drop it! */
+               gspca_dev->last_packet_type = DISCARD_PACKET;
+               sd->expo_change_state = EXPO_NO_CHANGE;
+               break;
+       case EXPO_NO_CHANGE:
+               break;
+       }
+       gspca_frame_add(gspca_dev, LAST_PACKET, data, len);
+}
+
+static void sd_pkt_scan_janggu(struct gspca_dev *gspca_dev, u8 *data, int len)
+{
+       struct sd *sd = (struct sd *)gspca_dev;
+       int imagesize = gspca_dev->width * gspca_dev->height;
+       int i, plen, bits, pixels, info, count;
+
+       if (sd->restart_stream)
+               return;
+
+       /* Sometimes a 1024 bytes garbage bulk packet is send between frames */
+       if (gspca_dev->last_packet_type == LAST_PACKET && len == 1024) {
+               gspca_dev->last_packet_type = DISCARD_PACKET;
+               return;
+       }
+
+       i = 0;
+       while (i < len) {
+               /* Read header if not already be present from prev bulk pkt */
+               if (sd->packet_read < 4) {
+                       count = 4 - sd->packet_read;
+                       if (count > len - i)
+                               count = len - i;
+                       memcpy(&sd->packet[sd->packet_read], &data[i], count);
+                       sd->packet_read += count;
+                       i += count;
+                       if (sd->packet_read < 4)
+                               break;
+               }
+               bits   = sd->packet[3] + (sd->packet[2] << 8);
+               pixels = sd->packet[1] + ((sd->packet[0] & 0x3f) << 8);
+               info   = (sd->packet[0] & 0xc0) >> 6;
+               plen   = ((bits + 47) >> 4) << 1;
+               /* Sanity checks */
+               if (plen > 1024) {
+                       err("invalid packet len %d restarting stream", plen);
+                       goto error;
+               }
+               if (info == 3) {
+                       err("unknown frame info value restarting stream");
+                       goto error;
+               }
+
+               /* Read (remainder of) packet contents */
+               count = plen - sd->packet_read;
+               if (count > len - i)
+                       count = len - i;
+               memcpy(&sd->packet[sd->packet_read], &data[i], count);
+               sd->packet_read += count;
+               i += count;
+               if (sd->packet_read < plen)
+                       break;
+
+               sd->pixels_read += pixels;
+               sd->packet_read = 0;
+
+               switch (info) {
+               case 0: /* Frame data */
+                       gspca_frame_add(gspca_dev, INTER_PACKET, sd->packet,
+                                       plen);
+                       break;
+               case 1: /* EOF */
+                       if (sd->pixels_read != imagesize) {
+                               err("frame size %d expected %d",
+                                   sd->pixels_read, imagesize);
+                               goto error;
+                       }
+                       sd_complete_frame(gspca_dev, sd->packet, plen);
+                       return; /* Discard the rest of the bulk packet !! */
+               case 2: /* SOF */
+                       gspca_frame_add(gspca_dev, FIRST_PACKET, sd->packet,
+                                       plen);
+                       sd->pixels_read = pixels;
+                       break;
+               }
+       }
+       return;
+
+error:
+       sd->restart_stream = 1;
+       /* Give userspace a 0 bytes frame, so our dq callback gets
+          called and it can restart the stream */
+       gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
+       gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
+}
+
+static void sd_pkt_scan_bayer(struct gspca_dev *gspca_dev, u8 *data, int len)
+{
+       struct cam *cam = &gspca_dev->cam;
+       int imagesize = cam->cam_mode[gspca_dev->curr_mode].sizeimage;
+
+       if (gspca_dev->image_len == 0) {
+               gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
+               return;
+       }
+
+       if (gspca_dev->image_len + len >= imagesize) {
+               sd_complete_frame(gspca_dev, data, len);
+               return;
+       }
+
+       gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, int len)
+{
+       int mult = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+
+       if (len == 0)
+               return;
+
+       if (mult == 1) /* mult == 1 means raw bayer */
+               sd_pkt_scan_bayer(gspca_dev, data, len);
+       else
+               sd_pkt_scan_janggu(gspca_dev, data, len);
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+                       struct v4l2_querymenu *menu)
+{
+       switch (menu->id) {
+       case V4L2_CID_POWER_LINE_FREQUENCY:
+               switch (menu->index) {
+               case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED:
+                       strcpy((char *) menu->name, "NoFliker");
+                       return 0;
+               case V4L2_CID_POWER_LINE_FREQUENCY_50HZ:
+                       strcpy((char *) menu->name, "50 Hz");
+                       return 0;
+               case V4L2_CID_POWER_LINE_FREQUENCY_60HZ:
+                       strcpy((char *) menu->name, "60 Hz");
+                       return 0;
+               }
+               break;
+       }
+       return -EINVAL;
+}
+
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, int len)
+{
+       struct sd *sd = (struct sd *)gspca_dev;
+       u8 state;
+
+       if (len != 2)
+               return -EINVAL;
+
+       switch (data[0]) {
+       case 0:
+       case 1:
+               state = data[0];
+               break;
+       default:
+               return -EINVAL;
+       }
+       if (sd->button_state != state) {
+               input_report_key(gspca_dev->input_dev, KEY_CAMERA, state);
+               input_sync(gspca_dev->input_dev);
+               sd->button_state = state;
+       }
+
+       return 0;
+}
+#endif
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       .ctrls = sd_ctrls,
+       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .config = sd_config,
+       .init = sd_init,
+       .start = sd_start,
+       .stopN = sd_stopN,
+       .dq_callback = sd_dq_callback,
+       .pkt_scan = sd_pkt_scan,
+       .querymenu = sd_querymenu,
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+       .int_pkt_scan = sd_int_pkt_scan,
+#endif
+};
+
+/* -- module initialisation -- */
+static const struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x03e8, 0x0004)}, /* Endpoints/Aox SE401 */
+       {USB_DEVICE(0x0471, 0x030b)}, /* Philips PCVC665K */
+       {USB_DEVICE(0x047d, 0x5001)}, /* Kensington 67014 */
+       {USB_DEVICE(0x047d, 0x5002)}, /* Kensington 6701(5/7) */
+       {USB_DEVICE(0x047d, 0x5003)}, /* Kensington 67016 */
+       {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+                       const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+                               THIS_MODULE);
+}
+
+static int sd_pre_reset(struct usb_interface *intf)
+{
+       return 0;
+}
+
+static int sd_post_reset(struct usb_interface *intf)
+{
+       return 0;
+}
+
+static struct usb_driver sd_driver = {
+       .name = MODULE_NAME,
+       .id_table = device_table,
+       .probe = sd_probe,
+       .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
+       .pre_reset = sd_pre_reset,
+       .post_reset = sd_post_reset,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       return usb_register(&sd_driver);
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/se401.h b/drivers/media/video/gspca/se401.h
new file mode 100644 (file)
index 0000000..96d8ebf
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * GSPCA Endpoints (formerly known as AOX) se401 USB Camera sub Driver
+ *
+ * Copyright (C) 2011 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Based on the v4l1 se401 driver which is:
+ *
+ * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#define SE401_REQ_GET_CAMERA_DESCRIPTOR                0x06
+#define SE401_REQ_START_CONTINUOUS_CAPTURE     0x41
+#define SE401_REQ_STOP_CONTINUOUS_CAPTURE      0x42
+#define SE401_REQ_CAPTURE_FRAME                        0x43
+#define SE401_REQ_GET_BRT                      0x44
+#define SE401_REQ_SET_BRT                      0x45
+#define SE401_REQ_GET_WIDTH                    0x4c
+#define SE401_REQ_SET_WIDTH                    0x4d
+#define SE401_REQ_GET_HEIGHT                   0x4e
+#define SE401_REQ_SET_HEIGHT                   0x4f
+#define SE401_REQ_GET_OUTPUT_MODE              0x50
+#define SE401_REQ_SET_OUTPUT_MODE              0x51
+#define SE401_REQ_GET_EXT_FEATURE              0x52
+#define SE401_REQ_SET_EXT_FEATURE              0x53
+#define SE401_REQ_CAMERA_POWER                 0x56
+#define SE401_REQ_LED_CONTROL                  0x57
+#define SE401_REQ_BIOS                         0xff
+
+#define SE401_BIOS_READ                                0x07
+
+#define SE401_FORMAT_BAYER     0x40
+
+/* Hyundai hv7131b registers
+   7121 and 7141 should be the same (haven't really checked...) */
+/* Mode registers: */
+#define HV7131_REG_MODE_A              0x00
+#define HV7131_REG_MODE_B              0x01
+#define HV7131_REG_MODE_C              0x02
+/* Frame registers: */
+#define HV7131_REG_FRSU                0x10
+#define HV7131_REG_FRSL                0x11
+#define HV7131_REG_FCSU                0x12
+#define HV7131_REG_FCSL                0x13
+#define HV7131_REG_FWHU                0x14
+#define HV7131_REG_FWHL                0x15
+#define HV7131_REG_FWWU                0x16
+#define HV7131_REG_FWWL                0x17
+/* Timing registers: */
+#define HV7131_REG_THBU                0x20
+#define HV7131_REG_THBL                0x21
+#define HV7131_REG_TVBU                0x22
+#define HV7131_REG_TVBL                0x23
+#define HV7131_REG_TITU                0x25
+#define HV7131_REG_TITM                0x26
+#define HV7131_REG_TITL                0x27
+#define HV7131_REG_TMCD                0x28
+/* Adjust Registers: */
+#define HV7131_REG_ARLV                0x30
+#define HV7131_REG_ARCG                0x31
+#define HV7131_REG_AGCG                0x32
+#define HV7131_REG_ABCG                0x33
+#define HV7131_REG_APBV                0x34
+#define HV7131_REG_ASLP                0x54
+/* Offset Registers: */
+#define HV7131_REG_OFSR                0x50
+#define HV7131_REG_OFSG                0x51
+#define HV7131_REG_OFSB                0x52
+/* REset level statistics registers: */
+#define HV7131_REG_LOREFNOH    0x57
+#define HV7131_REG_LOREFNOL    0x58
+#define HV7131_REG_HIREFNOH    0x59
+#define HV7131_REG_HIREFNOL    0x5a
+
+/* se401 registers */
+#define SE401_OPERATINGMODE    0x2000
index b089c0d..6ec2329 100644 (file)
@@ -247,7 +247,6 @@ static const struct cmd spca504A_clicksmart420_init_data[] = {
        {0x30, 0x0004, 0x000a},
        {0xb0, 0x0001, 0x0000},
 
-
        {0xa1, 0x0080, 0x0001},
        {0x30, 0x0049, 0x0000},
        {0x30, 0x0060, 0x0005},
@@ -256,8 +255,6 @@ static const struct cmd spca504A_clicksmart420_init_data[] = {
        {0x00, 0x0000, 0x2000},
        {0x00, 0x0013, 0x2301},
        {0x00, 0x0003, 0x2000},
-       {0x00, 0x0000, 0x2000},
-
 };
 
 /* clicksmart 420 open data ? */
index 7e762d5..d1d733b 100644 (file)
@@ -1387,7 +1387,7 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
                return 0;
        case V4L2_CID_EFFECTS:
                if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) {
-                       strncpy((char *) menu->name,
+                       strlcpy((char *) menu->name,
                                effects_control[menu->index],
                                sizeof menu->name);
                        return 0;
index 5f1db46..441dacf 100644 (file)
@@ -474,5 +474,6 @@ module_init(hdpvr_init);
 module_exit(hdpvr_exit);
 
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.2.1");
 MODULE_AUTHOR("Janne Grunau");
 MODULE_DESCRIPTION("Hauppauge HD PVR driver");
index 514aea7..087f7c0 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/uaccess.h>
 #include <linux/usb.h>
 #include <linux/mutex.h>
-#include <linux/version.h>
 #include <linux/workqueue.h>
 
 #include <linux/videodev2.h>
@@ -574,7 +573,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        strcpy(cap->driver, "hdpvr");
        strcpy(cap->card, "Hauppauge HD PVR");
        usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
-       cap->version = HDPVR_VERSION;
        cap->capabilities =     V4L2_CAP_VIDEO_CAPTURE |
                                V4L2_CAP_AUDIO         |
                                V4L2_CAP_READWRITE;
index 072f23c..d6439db 100644 (file)
 #include <media/v4l2-device.h>
 #include <media/ir-kbd-i2c.h>
 
-#define HDPVR_MAJOR_VERSION 0
-#define HDPVR_MINOR_VERSION 2
-#define HDPVR_RELEASE 0
-#define HDPVR_VERSION \
-       KERNEL_VERSION(HDPVR_MAJOR_VERSION, HDPVR_MINOR_VERSION, HDPVR_RELEASE)
-
 #define HDPVR_MAX 8
 #define HDPVR_I2C_MAX_SIZE 128
 
index 84bdf0f..8f9cc17 100644 (file)
@@ -36,7 +36,6 @@
  *                using information provided by Jiun-Kuei Jung @ AVerMedia.
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/delay.h>
index a7f54b0..38f0522 100644 (file)
@@ -722,8 +722,8 @@ unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait)
 
        /* If there are subscribed events, then only use the new event
           API instead of the old video.h based API. */
-       if (!list_empty(&id->fh.events->subscribed)) {
-               poll_wait(filp, &id->fh.events->wait, wait);
+       if (!list_empty(&id->fh.subscribed)) {
+               poll_wait(filp, &id->fh.wait, wait);
                /* Turn off the old-style vsync events */
                clear_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags);
                if (v4l2_event_pending(&id->fh))
@@ -750,6 +750,7 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait)
        struct ivtv *itv = id->itv;
        struct ivtv_stream *s = &itv->streams[id->type];
        int eof = test_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+       unsigned res = 0;
 
        /* Start a capture if there is none */
        if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
@@ -769,12 +770,16 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait)
        /* add stream's waitq to the poll list */
        IVTV_DEBUG_HI_FILE("Encoder poll\n");
        poll_wait(filp, &s->waitq, wait);
+       if (v4l2_event_pending(&id->fh))
+               res |= POLLPRI;
+       else
+               poll_wait(filp, &id->fh.wait, wait);
 
        if (s->q_full.length || s->q_io.length)
-               return POLLIN | POLLRDNORM;
+               return res | POLLIN | POLLRDNORM;
        if (eof)
-               return POLLHUP;
-       return 0;
+               return res | POLLHUP;
+       return res;
 }
 
 void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end)
@@ -961,10 +966,6 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
                return -ENOMEM;
        }
        v4l2_fh_init(&item->fh, s->vdev);
-       if (s->type == IVTV_DEC_STREAM_TYPE_YUV ||
-           s->type == IVTV_DEC_STREAM_TYPE_MPG) {
-               res = v4l2_event_alloc(&item->fh, 60);
-       }
        if (res < 0) {
                v4l2_fh_exit(&item->fh);
                kfree(item);
index 120c7d8..3e5c090 100644 (file)
@@ -757,7 +757,6 @@ static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vc
        strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
        strlcpy(vcap->card, itv->card_name, sizeof(vcap->card));
        snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev));
-       vcap->version = IVTV_DRIVER_VERSION;        /* version */
        vcap->capabilities = itv->v4l2_cap;         /* capabilities */
        return 0;
 }
@@ -1451,11 +1450,11 @@ static int ivtv_subscribe_event(struct v4l2_fh *fh, struct v4l2_event_subscripti
        switch (sub->type) {
        case V4L2_EVENT_VSYNC:
        case V4L2_EVENT_EOS:
-               break;
+       case V4L2_EVENT_CTRL:
+               return v4l2_event_subscribe(fh, sub, 0);
        default:
                return -EINVAL;
        }
-       return v4l2_event_subscribe(fh, sub);
 }
 
 static int ivtv_log_status(struct file *file, void *fh)
index b67a404..a20f346 100644 (file)
 #define IVTV_VERSION_H
 
 #define IVTV_DRIVER_NAME "ivtv"
-#define IVTV_DRIVER_VERSION_MAJOR 1
-#define IVTV_DRIVER_VERSION_MINOR 4
-#define IVTV_DRIVER_VERSION_PATCHLEVEL 2
-
-#define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL)
-#define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL)
+#define IVTV_VERSION "1.4.3"
 
 #endif
index a45d8f0..3248ac8 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
-#include <linux/version.h>
 #include <linux/gpio.h>
 #include <linux/regulator/consumer.h>
 #include <linux/videodev2.h>
index 43c68f5..fb8e4a7 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
-#include <linux/version.h>
 #include <linux/gpio.h>
 #include <linux/regulator/consumer.h>
 #include <linux/videodev2.h>
diff --git a/drivers/media/video/marvell-ccic/Kconfig b/drivers/media/video/marvell-ccic/Kconfig
new file mode 100644 (file)
index 0000000..bf739e3
--- /dev/null
@@ -0,0 +1,23 @@
+config VIDEO_CAFE_CCIC
+       tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support"
+       depends on PCI && I2C && VIDEO_V4L2
+       select VIDEO_OV7670
+       select VIDEOBUF2_VMALLOC
+       select VIDEOBUF2_DMA_CONTIG
+       ---help---
+         This is a video4linux2 driver for the Marvell 88ALP01 integrated
+         CMOS camera controller.  This is the controller found on first-
+         generation OLPC systems.
+
+config VIDEO_MMP_CAMERA
+       tristate "Marvell Armada 610 integrated camera controller support"
+       depends on ARCH_MMP && I2C && VIDEO_V4L2
+       select VIDEO_OV7670
+       select I2C_GPIO
+       select VIDEOBUF2_DMA_SG
+       ---help---
+         This is a Video4Linux2 driver for the integrated camera
+         controller found on Marvell Armada 610 application
+         processors (and likely beyond).  This is the controller found
+         in OLPC XO 1.75 systems.
+
diff --git a/drivers/media/video/marvell-ccic/Makefile b/drivers/media/video/marvell-ccic/Makefile
new file mode 100644 (file)
index 0000000..05a792c
--- /dev/null
@@ -0,0 +1,6 @@
+obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
+cafe_ccic-y := cafe-driver.o mcam-core.o
+
+obj-$(CONFIG_VIDEO_MMP_CAMERA) += mmp_camera.o
+mmp_camera-y := mmp-driver.o mcam-core.o
+
diff --git a/drivers/media/video/marvell-ccic/cafe-driver.c b/drivers/media/video/marvell-ccic/cafe-driver.c
new file mode 100644 (file)
index 0000000..d030f9b
--- /dev/null
@@ -0,0 +1,654 @@
+/*
+ * A driver for the CMOS camera controller in the Marvell 88ALP01 "cafe"
+ * multifunction chip.  Currently works with the Omnivision OV7670
+ * sensor.
+ *
+ * The data sheet for this device can be found at:
+ *    http://www.marvell.com/products/pc_connectivity/88alp01/
+ *
+ * Copyright 2006-11 One Laptop Per Child Association, Inc.
+ * Copyright 2006-11 Jonathan Corbet <corbet@lwn.net>
+ *
+ * Written by Jonathan Corbet, corbet@lwn.net.
+ *
+ * v4l2_device/v4l2_subdev conversion by:
+ * Copyright (C) 2009 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This file may be distributed under the terms of the GNU General
+ * Public License, version 2.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include "mcam-core.h"
+
+#define CAFE_VERSION 0x000002
+
+
+/*
+ * Parameters.
+ */
+MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
+MODULE_DESCRIPTION("Marvell 88ALP01 CMOS Camera Controller driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("Video");
+
+
+
+
+struct cafe_camera {
+       int registered;                 /* Fully initialized? */
+       struct mcam_camera mcam;
+       struct pci_dev *pdev;
+       wait_queue_head_t smbus_wait;   /* Waiting on i2c events */
+};
+
+/*
+ * Most of the camera controller registers are defined in mcam-core.h,
+ * but the Cafe platform has some additional registers of its own;
+ * they are described here.
+ */
+
+/*
+ * "General purpose register" has a couple of GPIOs used for sensor
+ * power and reset on OLPC XO 1.0 systems.
+ */
+#define REG_GPR                0xb4
+#define          GPR_C1EN        0x00000020    /* Pad 1 (power down) enable */
+#define          GPR_C0EN        0x00000010    /* Pad 0 (reset) enable */
+#define          GPR_C1          0x00000002    /* Control 1 value */
+/*
+ * Control 0 is wired to reset on OLPC machines.  For ov7x sensors,
+ * it is active low.
+ */
+#define          GPR_C0          0x00000001    /* Control 0 value */
+
+/*
+ * These registers control the SMBUS module for communicating
+ * with the sensor.
+ */
+#define REG_TWSIC0     0xb8    /* TWSI (smbus) control 0 */
+#define          TWSIC0_EN       0x00000001    /* TWSI enable */
+#define          TWSIC0_MODE     0x00000002    /* 1 = 16-bit, 0 = 8-bit */
+#define          TWSIC0_SID      0x000003fc    /* Slave ID */
+/*
+ * Subtle trickery: the slave ID field starts with bit 2.  But the
+ * Linux i2c stack wants to treat the bottommost bit as a separate
+ * read/write bit, which is why slave ID's are usually presented
+ * >>1.  For consistency with that behavior, we shift over three
+ * bits instead of two.
+ */
+#define          TWSIC0_SID_SHIFT 3
+#define          TWSIC0_CLKDIV   0x0007fc00    /* Clock divider */
+#define          TWSIC0_MASKACK  0x00400000    /* Mask ack from sensor */
+#define          TWSIC0_OVMAGIC  0x00800000    /* Make it work on OV sensors */
+
+#define REG_TWSIC1     0xbc    /* TWSI control 1 */
+#define          TWSIC1_DATA     0x0000ffff    /* Data to/from camchip */
+#define          TWSIC1_ADDR     0x00ff0000    /* Address (register) */
+#define          TWSIC1_ADDR_SHIFT 16
+#define          TWSIC1_READ     0x01000000    /* Set for read op */
+#define          TWSIC1_WSTAT    0x02000000    /* Write status */
+#define          TWSIC1_RVALID   0x04000000    /* Read data valid */
+#define          TWSIC1_ERROR    0x08000000    /* Something screwed up */
+
+/*
+ * Here's the weird global control registers
+ */
+#define REG_GL_CSR     0x3004  /* Control/status register */
+#define          GCSR_SRS       0x00000001     /* SW Reset set */
+#define          GCSR_SRC       0x00000002     /* SW Reset clear */
+#define          GCSR_MRS       0x00000004     /* Master reset set */
+#define          GCSR_MRC       0x00000008     /* HW Reset clear */
+#define          GCSR_CCIC_EN   0x00004000    /* CCIC Clock enable */
+#define REG_GL_IMASK   0x300c  /* Interrupt mask register */
+#define          GIMSK_CCIC_EN          0x00000004    /* CCIC Interrupt enable */
+
+#define REG_GL_FCR     0x3038  /* GPIO functional control register */
+#define          GFCR_GPIO_ON    0x08          /* Camera GPIO enabled */
+#define REG_GL_GPIOR   0x315c  /* GPIO register */
+#define          GGPIO_OUT             0x80000 /* GPIO output */
+#define          GGPIO_VAL             0x00008 /* Output pin value */
+
+#define REG_LEN                       (REG_GL_IMASK + 4)
+
+
+/*
+ * Debugging and related.
+ */
+#define cam_err(cam, fmt, arg...) \
+       dev_err(&(cam)->pdev->dev, fmt, ##arg);
+#define cam_warn(cam, fmt, arg...) \
+       dev_warn(&(cam)->pdev->dev, fmt, ##arg);
+
+/* -------------------------------------------------------------------- */
+/*
+ * The I2C/SMBUS interface to the camera itself starts here.  The
+ * controller handles SMBUS itself, presenting a relatively simple register
+ * interface; all we have to do is to tell it where to route the data.
+ */
+#define CAFE_SMBUS_TIMEOUT (HZ)  /* generous */
+
+static inline struct cafe_camera *to_cam(struct v4l2_device *dev)
+{
+       struct mcam_camera *m = container_of(dev, struct mcam_camera, v4l2_dev);
+       return container_of(m, struct cafe_camera, mcam);
+}
+
+
+static int cafe_smbus_write_done(struct mcam_camera *mcam)
+{
+       unsigned long flags;
+       int c1;
+
+       /*
+        * We must delay after the interrupt, or the controller gets confused
+        * and never does give us good status.  Fortunately, we don't do this
+        * often.
+        */
+       udelay(20);
+       spin_lock_irqsave(&mcam->dev_lock, flags);
+       c1 = mcam_reg_read(mcam, REG_TWSIC1);
+       spin_unlock_irqrestore(&mcam->dev_lock, flags);
+       return (c1 & (TWSIC1_WSTAT|TWSIC1_ERROR)) != TWSIC1_WSTAT;
+}
+
+static int cafe_smbus_write_data(struct cafe_camera *cam,
+               u16 addr, u8 command, u8 value)
+{
+       unsigned int rval;
+       unsigned long flags;
+       struct mcam_camera *mcam = &cam->mcam;
+
+       spin_lock_irqsave(&mcam->dev_lock, flags);
+       rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID);
+       rval |= TWSIC0_OVMAGIC;  /* Make OV sensors work */
+       /*
+        * Marvell sez set clkdiv to all 1's for now.
+        */
+       rval |= TWSIC0_CLKDIV;
+       mcam_reg_write(mcam, REG_TWSIC0, rval);
+       (void) mcam_reg_read(mcam, REG_TWSIC1); /* force write */
+       rval = value | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR);
+       mcam_reg_write(mcam, REG_TWSIC1, rval);
+       spin_unlock_irqrestore(&mcam->dev_lock, flags);
+
+       /* Unfortunately, reading TWSIC1 too soon after sending a command
+        * causes the device to die.
+        * Use a busy-wait because we often send a large quantity of small
+        * commands at-once; using msleep() would cause a lot of context
+        * switches which take longer than 2ms, resulting in a noticeable
+        * boot-time and capture-start delays.
+        */
+       mdelay(2);
+
+       /*
+        * Another sad fact is that sometimes, commands silently complete but
+        * cafe_smbus_write_done() never becomes aware of this.
+        * This happens at random and appears to possible occur with any
+        * command.
+        * We don't understand why this is. We work around this issue
+        * with the timeout in the wait below, assuming that all commands
+        * complete within the timeout.
+        */
+       wait_event_timeout(cam->smbus_wait, cafe_smbus_write_done(mcam),
+                       CAFE_SMBUS_TIMEOUT);
+
+       spin_lock_irqsave(&mcam->dev_lock, flags);
+       rval = mcam_reg_read(mcam, REG_TWSIC1);
+       spin_unlock_irqrestore(&mcam->dev_lock, flags);
+
+       if (rval & TWSIC1_WSTAT) {
+               cam_err(cam, "SMBUS write (%02x/%02x/%02x) timed out\n", addr,
+                               command, value);
+               return -EIO;
+       }
+       if (rval & TWSIC1_ERROR) {
+               cam_err(cam, "SMBUS write (%02x/%02x/%02x) error\n", addr,
+                               command, value);
+               return -EIO;
+       }
+       return 0;
+}
+
+
+
+static int cafe_smbus_read_done(struct mcam_camera *mcam)
+{
+       unsigned long flags;
+       int c1;
+
+       /*
+        * We must delay after the interrupt, or the controller gets confused
+        * and never does give us good status.  Fortunately, we don't do this
+        * often.
+        */
+       udelay(20);
+       spin_lock_irqsave(&mcam->dev_lock, flags);
+       c1 = mcam_reg_read(mcam, REG_TWSIC1);
+       spin_unlock_irqrestore(&mcam->dev_lock, flags);
+       return c1 & (TWSIC1_RVALID|TWSIC1_ERROR);
+}
+
+
+
+static int cafe_smbus_read_data(struct cafe_camera *cam,
+               u16 addr, u8 command, u8 *value)
+{
+       unsigned int rval;
+       unsigned long flags;
+       struct mcam_camera *mcam = &cam->mcam;
+
+       spin_lock_irqsave(&mcam->dev_lock, flags);
+       rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID);
+       rval |= TWSIC0_OVMAGIC; /* Make OV sensors work */
+       /*
+        * Marvel sez set clkdiv to all 1's for now.
+        */
+       rval |= TWSIC0_CLKDIV;
+       mcam_reg_write(mcam, REG_TWSIC0, rval);
+       (void) mcam_reg_read(mcam, REG_TWSIC1); /* force write */
+       rval = TWSIC1_READ | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR);
+       mcam_reg_write(mcam, REG_TWSIC1, rval);
+       spin_unlock_irqrestore(&mcam->dev_lock, flags);
+
+       wait_event_timeout(cam->smbus_wait,
+                       cafe_smbus_read_done(mcam), CAFE_SMBUS_TIMEOUT);
+       spin_lock_irqsave(&mcam->dev_lock, flags);
+       rval = mcam_reg_read(mcam, REG_TWSIC1);
+       spin_unlock_irqrestore(&mcam->dev_lock, flags);
+
+       if (rval & TWSIC1_ERROR) {
+               cam_err(cam, "SMBUS read (%02x/%02x) error\n", addr, command);
+               return -EIO;
+       }
+       if (!(rval & TWSIC1_RVALID)) {
+               cam_err(cam, "SMBUS read (%02x/%02x) timed out\n", addr,
+                               command);
+               return -EIO;
+       }
+       *value = rval & 0xff;
+       return 0;
+}
+
+/*
+ * Perform a transfer over SMBUS.  This thing is called under
+ * the i2c bus lock, so we shouldn't race with ourselves...
+ */
+static int cafe_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
+               unsigned short flags, char rw, u8 command,
+               int size, union i2c_smbus_data *data)
+{
+       struct cafe_camera *cam = i2c_get_adapdata(adapter);
+       int ret = -EINVAL;
+
+       /*
+        * This interface would appear to only do byte data ops.  OK
+        * it can do word too, but the cam chip has no use for that.
+        */
+       if (size != I2C_SMBUS_BYTE_DATA) {
+               cam_err(cam, "funky xfer size %d\n", size);
+               return -EINVAL;
+       }
+
+       if (rw == I2C_SMBUS_WRITE)
+               ret = cafe_smbus_write_data(cam, addr, command, data->byte);
+       else if (rw == I2C_SMBUS_READ)
+               ret = cafe_smbus_read_data(cam, addr, command, &data->byte);
+       return ret;
+}
+
+
+static void cafe_smbus_enable_irq(struct cafe_camera *cam)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cam->mcam.dev_lock, flags);
+       mcam_reg_set_bit(&cam->mcam, REG_IRQMASK, TWSIIRQS);
+       spin_unlock_irqrestore(&cam->mcam.dev_lock, flags);
+}
+
+static u32 cafe_smbus_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_SMBUS_READ_BYTE_DATA  |
+              I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
+}
+
+static struct i2c_algorithm cafe_smbus_algo = {
+       .smbus_xfer = cafe_smbus_xfer,
+       .functionality = cafe_smbus_func
+};
+
+static int cafe_smbus_setup(struct cafe_camera *cam)
+{
+       struct i2c_adapter *adap;
+       int ret;
+
+       adap = kzalloc(sizeof(*adap), GFP_KERNEL);
+       if (adap == NULL)
+               return -ENOMEM;
+       cam->mcam.i2c_adapter = adap;
+       cafe_smbus_enable_irq(cam);
+       adap->owner = THIS_MODULE;
+       adap->algo = &cafe_smbus_algo;
+       strcpy(adap->name, "cafe_ccic");
+       adap->dev.parent = &cam->pdev->dev;
+       i2c_set_adapdata(adap, cam);
+       ret = i2c_add_adapter(adap);
+       if (ret)
+               printk(KERN_ERR "Unable to register cafe i2c adapter\n");
+       return ret;
+}
+
+static void cafe_smbus_shutdown(struct cafe_camera *cam)
+{
+       i2c_del_adapter(cam->mcam.i2c_adapter);
+       kfree(cam->mcam.i2c_adapter);
+}
+
+
+/*
+ * Controller-level stuff
+ */
+
+static void cafe_ctlr_init(struct mcam_camera *mcam)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mcam->dev_lock, flags);
+       /*
+        * Added magic to bring up the hardware on the B-Test board
+        */
+       mcam_reg_write(mcam, 0x3038, 0x8);
+       mcam_reg_write(mcam, 0x315c, 0x80008);
+       /*
+        * Go through the dance needed to wake the device up.
+        * Note that these registers are global and shared
+        * with the NAND and SD devices.  Interaction between the
+        * three still needs to be examined.
+        */
+       mcam_reg_write(mcam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */
+       mcam_reg_write(mcam, REG_GL_CSR, GCSR_SRC|GCSR_MRC);
+       mcam_reg_write(mcam, REG_GL_CSR, GCSR_SRC|GCSR_MRS);
+       /*
+        * Here we must wait a bit for the controller to come around.
+        */
+       spin_unlock_irqrestore(&mcam->dev_lock, flags);
+       msleep(5);
+       spin_lock_irqsave(&mcam->dev_lock, flags);
+
+       mcam_reg_write(mcam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC);
+       mcam_reg_set_bit(mcam, REG_GL_IMASK, GIMSK_CCIC_EN);
+       /*
+        * Mask all interrupts.
+        */
+       mcam_reg_write(mcam, REG_IRQMASK, 0);
+       spin_unlock_irqrestore(&mcam->dev_lock, flags);
+}
+
+
+static void cafe_ctlr_power_up(struct mcam_camera *mcam)
+{
+       /*
+        * Part one of the sensor dance: turn the global
+        * GPIO signal on.
+        */
+       mcam_reg_write(mcam, REG_GL_FCR, GFCR_GPIO_ON);
+       mcam_reg_write(mcam, REG_GL_GPIOR, GGPIO_OUT|GGPIO_VAL);
+       /*
+        * Put the sensor into operational mode (assumes OLPC-style
+        * wiring).  Control 0 is reset - set to 1 to operate.
+        * Control 1 is power down, set to 0 to operate.
+        */
+       mcam_reg_write(mcam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */
+       mcam_reg_write(mcam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0);
+}
+
+static void cafe_ctlr_power_down(struct mcam_camera *mcam)
+{
+       mcam_reg_write(mcam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C1);
+       mcam_reg_write(mcam, REG_GL_FCR, GFCR_GPIO_ON);
+       mcam_reg_write(mcam, REG_GL_GPIOR, GGPIO_OUT);
+}
+
+
+
+/*
+ * The platform interrupt handler.
+ */
+static irqreturn_t cafe_irq(int irq, void *data)
+{
+       struct cafe_camera *cam = data;
+       struct mcam_camera *mcam = &cam->mcam;
+       unsigned int irqs, handled;
+
+       spin_lock(&mcam->dev_lock);
+       irqs = mcam_reg_read(mcam, REG_IRQSTAT);
+       handled = cam->registered && mccic_irq(mcam, irqs);
+       if (irqs & TWSIIRQS) {
+               mcam_reg_write(mcam, REG_IRQSTAT, TWSIIRQS);
+               wake_up(&cam->smbus_wait);
+               handled = 1;
+       }
+       spin_unlock(&mcam->dev_lock);
+       return IRQ_RETVAL(handled);
+}
+
+
+/* -------------------------------------------------------------------------- */
+/*
+ * PCI interface stuff.
+ */
+
+static int cafe_pci_probe(struct pci_dev *pdev,
+               const struct pci_device_id *id)
+{
+       int ret;
+       struct cafe_camera *cam;
+       struct mcam_camera *mcam;
+
+       /*
+        * Start putting together one of our big camera structures.
+        */
+       ret = -ENOMEM;
+       cam = kzalloc(sizeof(struct cafe_camera), GFP_KERNEL);
+       if (cam == NULL)
+               goto out;
+       cam->pdev = pdev;
+       mcam = &cam->mcam;
+       mcam->chip_id = V4L2_IDENT_CAFE;
+       spin_lock_init(&mcam->dev_lock);
+       init_waitqueue_head(&cam->smbus_wait);
+       mcam->plat_power_up = cafe_ctlr_power_up;
+       mcam->plat_power_down = cafe_ctlr_power_down;
+       mcam->dev = &pdev->dev;
+       /*
+        * Set the clock speed for the XO 1; I don't believe this
+        * driver has ever run anywhere else.
+        */
+       mcam->clock_speed = 45;
+       mcam->use_smbus = 1;
+       /*
+        * Vmalloc mode for buffers is traditional with this driver.
+        * We *might* be able to run DMA_contig, especially on a system
+        * with CMA in it.
+        */
+       mcam->buffer_mode = B_vmalloc;
+       /*
+        * Get set up on the PCI bus.
+        */
+       ret = pci_enable_device(pdev);
+       if (ret)
+               goto out_free;
+       pci_set_master(pdev);
+
+       ret = -EIO;
+       mcam->regs = pci_iomap(pdev, 0, 0);
+       if (!mcam->regs) {
+               printk(KERN_ERR "Unable to ioremap cafe-ccic regs\n");
+               goto out_disable;
+       }
+       ret = request_irq(pdev->irq, cafe_irq, IRQF_SHARED, "cafe-ccic", cam);
+       if (ret)
+               goto out_iounmap;
+
+       /*
+        * Initialize the controller and leave it powered up.  It will
+        * stay that way until the sensor driver shows up.
+        */
+       cafe_ctlr_init(mcam);
+       cafe_ctlr_power_up(mcam);
+       /*
+        * Set up I2C/SMBUS communications.  We have to drop the mutex here
+        * because the sensor could attach in this call chain, leading to
+        * unsightly deadlocks.
+        */
+       ret = cafe_smbus_setup(cam);
+       if (ret)
+               goto out_pdown;
+
+       ret = mccic_register(mcam);
+       if (ret == 0) {
+               cam->registered = 1;
+               return 0;
+       }
+
+       cafe_smbus_shutdown(cam);
+out_pdown:
+       cafe_ctlr_power_down(mcam);
+       free_irq(pdev->irq, cam);
+out_iounmap:
+       pci_iounmap(pdev, mcam->regs);
+out_disable:
+       pci_disable_device(pdev);
+out_free:
+       kfree(cam);
+out:
+       return ret;
+}
+
+
+/*
+ * Shut down an initialized device
+ */
+static void cafe_shutdown(struct cafe_camera *cam)
+{
+       mccic_shutdown(&cam->mcam);
+       cafe_smbus_shutdown(cam);
+       free_irq(cam->pdev->irq, cam);
+       pci_iounmap(cam->pdev, cam->mcam.regs);
+}
+
+
+static void cafe_pci_remove(struct pci_dev *pdev)
+{
+       struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
+       struct cafe_camera *cam = to_cam(v4l2_dev);
+
+       if (cam == NULL) {
+               printk(KERN_WARNING "pci_remove on unknown pdev %p\n", pdev);
+               return;
+       }
+       cafe_shutdown(cam);
+       kfree(cam);
+}
+
+
+#ifdef CONFIG_PM
+/*
+ * Basic power management.
+ */
+static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
+       struct cafe_camera *cam = to_cam(v4l2_dev);
+       int ret;
+
+       ret = pci_save_state(pdev);
+       if (ret)
+               return ret;
+       mccic_suspend(&cam->mcam);
+       pci_disable_device(pdev);
+       return 0;
+}
+
+
+static int cafe_pci_resume(struct pci_dev *pdev)
+{
+       struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
+       struct cafe_camera *cam = to_cam(v4l2_dev);
+       int ret = 0;
+
+       pci_restore_state(pdev);
+       ret = pci_enable_device(pdev);
+
+       if (ret) {
+               cam_warn(cam, "Unable to re-enable device on resume!\n");
+               return ret;
+       }
+       cafe_ctlr_init(&cam->mcam);
+       return mccic_resume(&cam->mcam);
+}
+
+#endif  /* CONFIG_PM */
+
+static struct pci_device_id cafe_ids[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL,
+                    PCI_DEVICE_ID_MARVELL_88ALP01_CCIC) },
+       { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, cafe_ids);
+
+static struct pci_driver cafe_pci_driver = {
+       .name = "cafe1000-ccic",
+       .id_table = cafe_ids,
+       .probe = cafe_pci_probe,
+       .remove = cafe_pci_remove,
+#ifdef CONFIG_PM
+       .suspend = cafe_pci_suspend,
+       .resume = cafe_pci_resume,
+#endif
+};
+
+
+
+
+static int __init cafe_init(void)
+{
+       int ret;
+
+       printk(KERN_NOTICE "Marvell M88ALP01 'CAFE' Camera Controller version %d\n",
+                       CAFE_VERSION);
+       ret = pci_register_driver(&cafe_pci_driver);
+       if (ret) {
+               printk(KERN_ERR "Unable to register cafe_ccic driver\n");
+               goto out;
+       }
+       ret = 0;
+
+out:
+       return ret;
+}
+
+
+static void __exit cafe_exit(void)
+{
+       pci_unregister_driver(&cafe_pci_driver);
+}
+
+module_init(cafe_init);
+module_exit(cafe_exit);
diff --git a/drivers/media/video/marvell-ccic/mcam-core.c b/drivers/media/video/marvell-ccic/mcam-core.c
new file mode 100644 (file)
index 0000000..83c1451
--- /dev/null
@@ -0,0 +1,1843 @@
+/*
+ * The Marvell camera core.  This device appears in a number of settings,
+ * so it needs platform-specific support outside of the core.
+ *
+ * Copyright 2011 Jonathan Corbet corbet@lwn.net
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/vmalloc.h>
+#include <linux/io.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/ov7670.h>
+#include <media/videobuf2-vmalloc.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-dma-sg.h>
+
+#include "mcam-core.h"
+
+/*
+ * Basic frame stats - to be deleted shortly
+ */
+static int frames;
+static int singles;
+static int delivered;
+
+#ifdef MCAM_MODE_VMALLOC
+/*
+ * Internal DMA buffer management.  Since the controller cannot do S/G I/O,
+ * we must have physically contiguous buffers to bring frames into.
+ * These parameters control how many buffers we use, whether we
+ * allocate them at load time (better chance of success, but nails down
+ * memory) or when somebody tries to use the camera (riskier), and,
+ * for load-time allocation, how big they should be.
+ *
+ * The controller can cycle through three buffers.  We could use
+ * more by flipping pointers around, but it probably makes little
+ * sense.
+ */
+
+static int alloc_bufs_at_read;
+module_param(alloc_bufs_at_read, bool, 0444);
+MODULE_PARM_DESC(alloc_bufs_at_read,
+               "Non-zero value causes DMA buffers to be allocated when the "
+               "video capture device is read, rather than at module load "
+               "time.  This saves memory, but decreases the chances of "
+               "successfully getting those buffers.  This parameter is "
+               "only used in the vmalloc buffer mode");
+
+static int n_dma_bufs = 3;
+module_param(n_dma_bufs, uint, 0644);
+MODULE_PARM_DESC(n_dma_bufs,
+               "The number of DMA buffers to allocate.  Can be either two "
+               "(saves memory, makes timing tighter) or three.");
+
+static int dma_buf_size = VGA_WIDTH * VGA_HEIGHT * 2;  /* Worst case */
+module_param(dma_buf_size, uint, 0444);
+MODULE_PARM_DESC(dma_buf_size,
+               "The size of the allocated DMA buffers.  If actual operating "
+               "parameters require larger buffers, an attempt to reallocate "
+               "will be made.");
+#else /* MCAM_MODE_VMALLOC */
+static const int alloc_bufs_at_read = 0;
+static const int n_dma_bufs = 3;  /* Used by S/G_PARM */
+#endif /* MCAM_MODE_VMALLOC */
+
+static int flip;
+module_param(flip, bool, 0444);
+MODULE_PARM_DESC(flip,
+               "If set, the sensor will be instructed to flip the image "
+               "vertically.");
+
+static int buffer_mode = -1;
+module_param(buffer_mode, int, 0444);
+MODULE_PARM_DESC(buffer_mode,
+               "Set the buffer mode to be used; default is to go with what "
+               "the platform driver asks for.  Set to 0 for vmalloc, 1 for "
+               "DMA contiguous.");
+
+/*
+ * Status flags.  Always manipulated with bit operations.
+ */
+#define CF_BUF0_VALID   0      /* Buffers valid - first three */
+#define CF_BUF1_VALID   1
+#define CF_BUF2_VALID   2
+#define CF_DMA_ACTIVE   3      /* A frame is incoming */
+#define CF_CONFIG_NEEDED 4     /* Must configure hardware */
+#define CF_SINGLE_BUFFER 5     /* Running with a single buffer */
+#define CF_SG_RESTART   6      /* SG restart needed */
+
+#define sensor_call(cam, o, f, args...) \
+       v4l2_subdev_call(cam->sensor, o, f, ##args)
+
+static struct mcam_format_struct {
+       __u8 *desc;
+       __u32 pixelformat;
+       int bpp;   /* Bytes per pixel */
+       enum v4l2_mbus_pixelcode mbus_code;
+} mcam_formats[] = {
+       {
+               .desc           = "YUYV 4:2:2",
+               .pixelformat    = V4L2_PIX_FMT_YUYV,
+               .mbus_code      = V4L2_MBUS_FMT_YUYV8_2X8,
+               .bpp            = 2,
+       },
+       {
+               .desc           = "RGB 444",
+               .pixelformat    = V4L2_PIX_FMT_RGB444,
+               .mbus_code      = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
+               .bpp            = 2,
+       },
+       {
+               .desc           = "RGB 565",
+               .pixelformat    = V4L2_PIX_FMT_RGB565,
+               .mbus_code      = V4L2_MBUS_FMT_RGB565_2X8_LE,
+               .bpp            = 2,
+       },
+       {
+               .desc           = "Raw RGB Bayer",
+               .pixelformat    = V4L2_PIX_FMT_SBGGR8,
+               .mbus_code      = V4L2_MBUS_FMT_SBGGR8_1X8,
+               .bpp            = 1
+       },
+};
+#define N_MCAM_FMTS ARRAY_SIZE(mcam_formats)
+
+static struct mcam_format_struct *mcam_find_format(u32 pixelformat)
+{
+       unsigned i;
+
+       for (i = 0; i < N_MCAM_FMTS; i++)
+               if (mcam_formats[i].pixelformat == pixelformat)
+                       return mcam_formats + i;
+       /* Not found? Then return the first format. */
+       return mcam_formats;
+}
+
+/*
+ * The default format we use until somebody says otherwise.
+ */
+static const struct v4l2_pix_format mcam_def_pix_format = {
+       .width          = VGA_WIDTH,
+       .height         = VGA_HEIGHT,
+       .pixelformat    = V4L2_PIX_FMT_YUYV,
+       .field          = V4L2_FIELD_NONE,
+       .bytesperline   = VGA_WIDTH*2,
+       .sizeimage      = VGA_WIDTH*VGA_HEIGHT*2,
+};
+
+static const enum v4l2_mbus_pixelcode mcam_def_mbus_code =
+                                       V4L2_MBUS_FMT_YUYV8_2X8;
+
+
+/*
+ * The two-word DMA descriptor format used by the Armada 610 and like.  There
+ * Is a three-word format as well (set C1_DESC_3WORD) where the third
+ * word is a pointer to the next descriptor, but we don't use it.  Two-word
+ * descriptors have to be contiguous in memory.
+ */
+struct mcam_dma_desc {
+       u32 dma_addr;
+       u32 segment_len;
+};
+
+/*
+ * Our buffer type for working with videobuf2.  Note that the vb2
+ * developers have decreed that struct vb2_buffer must be at the
+ * beginning of this structure.
+ */
+struct mcam_vb_buffer {
+       struct vb2_buffer vb_buf;
+       struct list_head queue;
+       struct mcam_dma_desc *dma_desc; /* Descriptor virtual address */
+       dma_addr_t dma_desc_pa;         /* Descriptor physical address */
+       int dma_desc_nent;              /* Number of mapped descriptors */
+};
+
+static inline struct mcam_vb_buffer *vb_to_mvb(struct vb2_buffer *vb)
+{
+       return container_of(vb, struct mcam_vb_buffer, vb_buf);
+}
+
+/*
+ * Hand a completed buffer back to user space.
+ */
+static void mcam_buffer_done(struct mcam_camera *cam, int frame,
+               struct vb2_buffer *vbuf)
+{
+       vbuf->v4l2_buf.bytesused = cam->pix_format.sizeimage;
+       vbuf->v4l2_buf.sequence = cam->buf_seq[frame];
+       vb2_set_plane_payload(vbuf, 0, cam->pix_format.sizeimage);
+       vb2_buffer_done(vbuf, VB2_BUF_STATE_DONE);
+}
+
+
+
+/*
+ * Debugging and related.
+ */
+#define cam_err(cam, fmt, arg...) \
+       dev_err((cam)->dev, fmt, ##arg);
+#define cam_warn(cam, fmt, arg...) \
+       dev_warn((cam)->dev, fmt, ##arg);
+#define cam_dbg(cam, fmt, arg...) \
+       dev_dbg((cam)->dev, fmt, ##arg);
+
+
+/*
+ * Flag manipulation helpers
+ */
+static void mcam_reset_buffers(struct mcam_camera *cam)
+{
+       int i;
+
+       cam->next_buf = -1;
+       for (i = 0; i < cam->nbufs; i++)
+               clear_bit(i, &cam->flags);
+}
+
+static inline int mcam_needs_config(struct mcam_camera *cam)
+{
+       return test_bit(CF_CONFIG_NEEDED, &cam->flags);
+}
+
+static void mcam_set_config_needed(struct mcam_camera *cam, int needed)
+{
+       if (needed)
+               set_bit(CF_CONFIG_NEEDED, &cam->flags);
+       else
+               clear_bit(CF_CONFIG_NEEDED, &cam->flags);
+}
+
+/* ------------------------------------------------------------------- */
+/*
+ * Make the controller start grabbing images.  Everything must
+ * be set up before doing this.
+ */
+static void mcam_ctlr_start(struct mcam_camera *cam)
+{
+       /* set_bit performs a read, so no other barrier should be
+          needed here */
+       mcam_reg_set_bit(cam, REG_CTRL0, C0_ENABLE);
+}
+
+static void mcam_ctlr_stop(struct mcam_camera *cam)
+{
+       mcam_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE);
+}
+
+/* ------------------------------------------------------------------- */
+
+#ifdef MCAM_MODE_VMALLOC
+/*
+ * Code specific to the vmalloc buffer mode.
+ */
+
+/*
+ * Allocate in-kernel DMA buffers for vmalloc mode.
+ */
+static int mcam_alloc_dma_bufs(struct mcam_camera *cam, int loadtime)
+{
+       int i;
+
+       mcam_set_config_needed(cam, 1);
+       if (loadtime)
+               cam->dma_buf_size = dma_buf_size;
+       else
+               cam->dma_buf_size = cam->pix_format.sizeimage;
+       if (n_dma_bufs > 3)
+               n_dma_bufs = 3;
+
+       cam->nbufs = 0;
+       for (i = 0; i < n_dma_bufs; i++) {
+               cam->dma_bufs[i] = dma_alloc_coherent(cam->dev,
+                               cam->dma_buf_size, cam->dma_handles + i,
+                               GFP_KERNEL);
+               if (cam->dma_bufs[i] == NULL) {
+                       cam_warn(cam, "Failed to allocate DMA buffer\n");
+                       break;
+               }
+               (cam->nbufs)++;
+       }
+
+       switch (cam->nbufs) {
+       case 1:
+               dma_free_coherent(cam->dev, cam->dma_buf_size,
+                               cam->dma_bufs[0], cam->dma_handles[0]);
+               cam->nbufs = 0;
+       case 0:
+               cam_err(cam, "Insufficient DMA buffers, cannot operate\n");
+               return -ENOMEM;
+
+       case 2:
+               if (n_dma_bufs > 2)
+                       cam_warn(cam, "Will limp along with only 2 buffers\n");
+               break;
+       }
+       return 0;
+}
+
+static void mcam_free_dma_bufs(struct mcam_camera *cam)
+{
+       int i;
+
+       for (i = 0; i < cam->nbufs; i++) {
+               dma_free_coherent(cam->dev, cam->dma_buf_size,
+                               cam->dma_bufs[i], cam->dma_handles[i]);
+               cam->dma_bufs[i] = NULL;
+       }
+       cam->nbufs = 0;
+}
+
+
+/*
+ * Set up DMA buffers when operating in vmalloc mode
+ */
+static void mcam_ctlr_dma_vmalloc(struct mcam_camera *cam)
+{
+       /*
+        * Store the first two Y buffers (we aren't supporting
+        * planar formats for now, so no UV bufs).  Then either
+        * set the third if it exists, or tell the controller
+        * to just use two.
+        */
+       mcam_reg_write(cam, REG_Y0BAR, cam->dma_handles[0]);
+       mcam_reg_write(cam, REG_Y1BAR, cam->dma_handles[1]);
+       if (cam->nbufs > 2) {
+               mcam_reg_write(cam, REG_Y2BAR, cam->dma_handles[2]);
+               mcam_reg_clear_bit(cam, REG_CTRL1, C1_TWOBUFS);
+       } else
+               mcam_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS);
+       if (cam->chip_id == V4L2_IDENT_CAFE)
+               mcam_reg_write(cam, REG_UBAR, 0); /* 32 bits only */
+}
+
+/*
+ * Copy data out to user space in the vmalloc case
+ */
+static void mcam_frame_tasklet(unsigned long data)
+{
+       struct mcam_camera *cam = (struct mcam_camera *) data;
+       int i;
+       unsigned long flags;
+       struct mcam_vb_buffer *buf;
+
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       for (i = 0; i < cam->nbufs; i++) {
+               int bufno = cam->next_buf;
+
+               if (cam->state != S_STREAMING || bufno < 0)
+                       break;  /* I/O got stopped */
+               if (++(cam->next_buf) >= cam->nbufs)
+                       cam->next_buf = 0;
+               if (!test_bit(bufno, &cam->flags))
+                       continue;
+               if (list_empty(&cam->buffers)) {
+                       singles++;
+                       break;  /* Leave it valid, hope for better later */
+               }
+               delivered++;
+               clear_bit(bufno, &cam->flags);
+               buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer,
+                               queue);
+               list_del_init(&buf->queue);
+               /*
+                * Drop the lock during the big copy.  This *should* be safe...
+                */
+               spin_unlock_irqrestore(&cam->dev_lock, flags);
+               memcpy(vb2_plane_vaddr(&buf->vb_buf, 0), cam->dma_bufs[bufno],
+                               cam->pix_format.sizeimage);
+               mcam_buffer_done(cam, bufno, &buf->vb_buf);
+               spin_lock_irqsave(&cam->dev_lock, flags);
+       }
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+
+/*
+ * Make sure our allocated buffers are up to the task.
+ */
+static int mcam_check_dma_buffers(struct mcam_camera *cam)
+{
+       if (cam->nbufs > 0 && cam->dma_buf_size < cam->pix_format.sizeimage)
+                       mcam_free_dma_bufs(cam);
+       if (cam->nbufs == 0)
+               return mcam_alloc_dma_bufs(cam, 0);
+       return 0;
+}
+
+static void mcam_vmalloc_done(struct mcam_camera *cam, int frame)
+{
+       tasklet_schedule(&cam->s_tasklet);
+}
+
+#else /* MCAM_MODE_VMALLOC */
+
+static inline int mcam_alloc_dma_bufs(struct mcam_camera *cam, int loadtime)
+{
+       return 0;
+}
+
+static inline void mcam_free_dma_bufs(struct mcam_camera *cam)
+{
+       return;
+}
+
+static inline int mcam_check_dma_buffers(struct mcam_camera *cam)
+{
+       return 0;
+}
+
+
+
+#endif /* MCAM_MODE_VMALLOC */
+
+
+#ifdef MCAM_MODE_DMA_CONTIG
+/* ---------------------------------------------------------------------- */
+/*
+ * DMA-contiguous code.
+ */
+/*
+ * Set up a contiguous buffer for the given frame.  Here also is where
+ * the underrun strategy is set: if there is no buffer available, reuse
+ * the buffer from the other BAR and set the CF_SINGLE_BUFFER flag to
+ * keep the interrupt handler from giving that buffer back to user
+ * space.  In this way, we always have a buffer to DMA to and don't
+ * have to try to play games stopping and restarting the controller.
+ */
+static void mcam_set_contig_buffer(struct mcam_camera *cam, int frame)
+{
+       struct mcam_vb_buffer *buf;
+       /*
+        * If there are no available buffers, go into single mode
+        */
+       if (list_empty(&cam->buffers)) {
+               buf = cam->vb_bufs[frame ^ 0x1];
+               cam->vb_bufs[frame] = buf;
+               mcam_reg_write(cam, frame == 0 ? REG_Y0BAR : REG_Y1BAR,
+                               vb2_dma_contig_plane_paddr(&buf->vb_buf, 0));
+               set_bit(CF_SINGLE_BUFFER, &cam->flags);
+               singles++;
+               return;
+       }
+       /*
+        * OK, we have a buffer we can use.
+        */
+       buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue);
+       list_del_init(&buf->queue);
+       mcam_reg_write(cam, frame == 0 ? REG_Y0BAR : REG_Y1BAR,
+                       vb2_dma_contig_plane_paddr(&buf->vb_buf, 0));
+       cam->vb_bufs[frame] = buf;
+       clear_bit(CF_SINGLE_BUFFER, &cam->flags);
+}
+
+/*
+ * Initial B_DMA_contig setup.
+ */
+static void mcam_ctlr_dma_contig(struct mcam_camera *cam)
+{
+       mcam_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS);
+       cam->nbufs = 2;
+       mcam_set_contig_buffer(cam, 0);
+       mcam_set_contig_buffer(cam, 1);
+}
+
+/*
+ * Frame completion handling.
+ */
+static void mcam_dma_contig_done(struct mcam_camera *cam, int frame)
+{
+       struct mcam_vb_buffer *buf = cam->vb_bufs[frame];
+
+       if (!test_bit(CF_SINGLE_BUFFER, &cam->flags)) {
+               delivered++;
+               mcam_buffer_done(cam, frame, &buf->vb_buf);
+       }
+       mcam_set_contig_buffer(cam, frame);
+}
+
+#endif /* MCAM_MODE_DMA_CONTIG */
+
+#ifdef MCAM_MODE_DMA_SG
+/* ---------------------------------------------------------------------- */
+/*
+ * Scatter/gather-specific code.
+ */
+
+/*
+ * Set up the next buffer for S/G I/O; caller should be sure that
+ * the controller is stopped and a buffer is available.
+ */
+static void mcam_sg_next_buffer(struct mcam_camera *cam)
+{
+       struct mcam_vb_buffer *buf;
+
+       buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue);
+       list_del_init(&buf->queue);
+       mcam_reg_write(cam, REG_DMA_DESC_Y, buf->dma_desc_pa);
+       mcam_reg_write(cam, REG_DESC_LEN_Y,
+                       buf->dma_desc_nent*sizeof(struct mcam_dma_desc));
+       mcam_reg_write(cam, REG_DESC_LEN_U, 0);
+       mcam_reg_write(cam, REG_DESC_LEN_V, 0);
+       cam->vb_bufs[0] = buf;
+}
+
+/*
+ * Initial B_DMA_sg setup
+ */
+static void mcam_ctlr_dma_sg(struct mcam_camera *cam)
+{
+       mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_3WORD);
+       mcam_sg_next_buffer(cam);
+       mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA);
+       cam->nbufs = 3;
+}
+
+
+/*
+ * Frame completion with S/G is trickier.  We can't muck with
+ * a descriptor chain on the fly, since the controller buffers it
+ * internally.  So we have to actually stop and restart; Marvell
+ * says this is the way to do it.
+ *
+ * Of course, stopping is easier said than done; experience shows
+ * that the controller can start a frame *after* C0_ENABLE has been
+ * cleared.  So when running in S/G mode, the controller is "stopped"
+ * on receipt of the start-of-frame interrupt.  That means we can
+ * safely change the DMA descriptor array here and restart things
+ * (assuming there's another buffer waiting to go).
+ */
+static void mcam_dma_sg_done(struct mcam_camera *cam, int frame)
+{
+       struct mcam_vb_buffer *buf = cam->vb_bufs[0];
+
+       /*
+        * Very Bad Not Good Things happen if you don't clear
+        * C1_DESC_ENA before making any descriptor changes.
+        */
+       mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_ENA);
+       /*
+        * If we have another buffer available, put it in and
+        * restart the engine.
+        */
+       if (!list_empty(&cam->buffers)) {
+               mcam_sg_next_buffer(cam);
+               mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA);
+               mcam_ctlr_start(cam);
+       /*
+        * Otherwise set CF_SG_RESTART and the controller will
+        * be restarted once another buffer shows up.
+        */
+       } else {
+               set_bit(CF_SG_RESTART, &cam->flags);
+               singles++;
+       }
+       /*
+        * Now we can give the completed frame back to user space.
+        */
+       delivered++;
+       mcam_buffer_done(cam, frame, &buf->vb_buf);
+}
+
+
+/*
+ * Scatter/gather mode requires stopping the controller between
+ * frames so we can put in a new DMA descriptor array.  If no new
+ * buffer exists at frame completion, the controller is left stopped;
+ * this function is charged with gettig things going again.
+ */
+static void mcam_sg_restart(struct mcam_camera *cam)
+{
+       mcam_ctlr_dma_sg(cam);
+       mcam_ctlr_start(cam);
+       clear_bit(CF_SG_RESTART, &cam->flags);
+}
+
+#else /* MCAM_MODE_DMA_SG */
+
+static inline void mcam_sg_restart(struct mcam_camera *cam)
+{
+       return;
+}
+
+#endif /* MCAM_MODE_DMA_SG */
+
+/* ---------------------------------------------------------------------- */
+/*
+ * Buffer-mode-independent controller code.
+ */
+
+/*
+ * Image format setup
+ */
+static void mcam_ctlr_image(struct mcam_camera *cam)
+{
+       int imgsz;
+       struct v4l2_pix_format *fmt = &cam->pix_format;
+
+       imgsz = ((fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK) |
+               (fmt->bytesperline & IMGSZ_H_MASK);
+       mcam_reg_write(cam, REG_IMGSIZE, imgsz);
+       mcam_reg_write(cam, REG_IMGOFFSET, 0);
+       /* YPITCH just drops the last two bits */
+       mcam_reg_write_mask(cam, REG_IMGPITCH, fmt->bytesperline,
+                       IMGP_YP_MASK);
+       /*
+        * Tell the controller about the image format we are using.
+        */
+       switch (cam->pix_format.pixelformat) {
+       case V4L2_PIX_FMT_YUYV:
+           mcam_reg_write_mask(cam, REG_CTRL0,
+                           C0_DF_YUV|C0_YUV_PACKED|C0_YUVE_YUYV,
+                           C0_DF_MASK);
+           break;
+
+       case V4L2_PIX_FMT_RGB444:
+           mcam_reg_write_mask(cam, REG_CTRL0,
+                           C0_DF_RGB|C0_RGBF_444|C0_RGB4_XRGB,
+                           C0_DF_MASK);
+               /* Alpha value? */
+           break;
+
+       case V4L2_PIX_FMT_RGB565:
+           mcam_reg_write_mask(cam, REG_CTRL0,
+                           C0_DF_RGB|C0_RGBF_565|C0_RGB5_BGGR,
+                           C0_DF_MASK);
+           break;
+
+       default:
+           cam_err(cam, "Unknown format %x\n", cam->pix_format.pixelformat);
+           break;
+       }
+       /*
+        * Make sure it knows we want to use hsync/vsync.
+        */
+       mcam_reg_write_mask(cam, REG_CTRL0, C0_SIF_HVSYNC,
+                       C0_SIFM_MASK);
+}
+
+
+/*
+ * Configure the controller for operation; caller holds the
+ * device mutex.
+ */
+static int mcam_ctlr_configure(struct mcam_camera *cam)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       cam->dma_setup(cam);
+       mcam_ctlr_image(cam);
+       mcam_set_config_needed(cam, 0);
+       clear_bit(CF_SG_RESTART, &cam->flags);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+       return 0;
+}
+
+static void mcam_ctlr_irq_enable(struct mcam_camera *cam)
+{
+       /*
+        * Clear any pending interrupts, since we do not
+        * expect to have I/O active prior to enabling.
+        */
+       mcam_reg_write(cam, REG_IRQSTAT, FRAMEIRQS);
+       mcam_reg_set_bit(cam, REG_IRQMASK, FRAMEIRQS);
+}
+
+static void mcam_ctlr_irq_disable(struct mcam_camera *cam)
+{
+       mcam_reg_clear_bit(cam, REG_IRQMASK, FRAMEIRQS);
+}
+
+
+
+static void mcam_ctlr_init(struct mcam_camera *cam)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       /*
+        * Make sure it's not powered down.
+        */
+       mcam_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN);
+       /*
+        * Turn off the enable bit.  It sure should be off anyway,
+        * but it's good to be sure.
+        */
+       mcam_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE);
+       /*
+        * Clock the sensor appropriately.  Controller clock should
+        * be 48MHz, sensor "typical" value is half that.
+        */
+       mcam_reg_write_mask(cam, REG_CLKCTRL, 2, CLK_DIV_MASK);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+
+/*
+ * Stop the controller, and don't return until we're really sure that no
+ * further DMA is going on.
+ */
+static void mcam_ctlr_stop_dma(struct mcam_camera *cam)
+{
+       unsigned long flags;
+
+       /*
+        * Theory: stop the camera controller (whether it is operating
+        * or not).  Delay briefly just in case we race with the SOF
+        * interrupt, then wait until no DMA is active.
+        */
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       clear_bit(CF_SG_RESTART, &cam->flags);
+       mcam_ctlr_stop(cam);
+       cam->state = S_IDLE;
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+       msleep(40);
+       if (test_bit(CF_DMA_ACTIVE, &cam->flags))
+               cam_err(cam, "Timeout waiting for DMA to end\n");
+               /* This would be bad news - what now? */
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       mcam_ctlr_irq_disable(cam);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+/*
+ * Power up and down.
+ */
+static void mcam_ctlr_power_up(struct mcam_camera *cam)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       cam->plat_power_up(cam);
+       mcam_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+       msleep(5); /* Just to be sure */
+}
+
+static void mcam_ctlr_power_down(struct mcam_camera *cam)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       /*
+        * School of hard knocks department: be sure we do any register
+        * twiddling on the controller *before* calling the platform
+        * power down routine.
+        */
+       mcam_reg_set_bit(cam, REG_CTRL1, C1_PWRDWN);
+       cam->plat_power_down(cam);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+/* -------------------------------------------------------------------- */
+/*
+ * Communications with the sensor.
+ */
+
+static int __mcam_cam_reset(struct mcam_camera *cam)
+{
+       return sensor_call(cam, core, reset, 0);
+}
+
+/*
+ * We have found the sensor on the i2c.  Let's try to have a
+ * conversation.
+ */
+static int mcam_cam_init(struct mcam_camera *cam)
+{
+       struct v4l2_dbg_chip_ident chip;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       if (cam->state != S_NOTREADY)
+               cam_warn(cam, "Cam init with device in funky state %d",
+                               cam->state);
+       ret = __mcam_cam_reset(cam);
+       if (ret)
+               goto out;
+       chip.ident = V4L2_IDENT_NONE;
+       chip.match.type = V4L2_CHIP_MATCH_I2C_ADDR;
+       chip.match.addr = cam->sensor_addr;
+       ret = sensor_call(cam, core, g_chip_ident, &chip);
+       if (ret)
+               goto out;
+       cam->sensor_type = chip.ident;
+       if (cam->sensor_type != V4L2_IDENT_OV7670) {
+               cam_err(cam, "Unsupported sensor type 0x%x", cam->sensor_type);
+               ret = -EINVAL;
+               goto out;
+       }
+/* Get/set parameters? */
+       ret = 0;
+       cam->state = S_IDLE;
+out:
+       mcam_ctlr_power_down(cam);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+/*
+ * Configure the sensor to match the parameters we have.  Caller should
+ * hold s_mutex
+ */
+static int mcam_cam_set_flip(struct mcam_camera *cam)
+{
+       struct v4l2_control ctrl;
+
+       memset(&ctrl, 0, sizeof(ctrl));
+       ctrl.id = V4L2_CID_VFLIP;
+       ctrl.value = flip;
+       return sensor_call(cam, core, s_ctrl, &ctrl);
+}
+
+
+static int mcam_cam_configure(struct mcam_camera *cam)
+{
+       struct v4l2_mbus_framefmt mbus_fmt;
+       int ret;
+
+       v4l2_fill_mbus_format(&mbus_fmt, &cam->pix_format, cam->mbus_code);
+       ret = sensor_call(cam, core, init, 0);
+       if (ret == 0)
+               ret = sensor_call(cam, video, s_mbus_fmt, &mbus_fmt);
+       /*
+        * OV7670 does weird things if flip is set *before* format...
+        */
+       ret += mcam_cam_set_flip(cam);
+       return ret;
+}
+
+/*
+ * Get everything ready, and start grabbing frames.
+ */
+static int mcam_read_setup(struct mcam_camera *cam)
+{
+       int ret;
+       unsigned long flags;
+
+       /*
+        * Configuration.  If we still don't have DMA buffers,
+        * make one last, desperate attempt.
+        */
+       if (cam->buffer_mode == B_vmalloc && cam->nbufs == 0 &&
+                       mcam_alloc_dma_bufs(cam, 0))
+               return -ENOMEM;
+
+       if (mcam_needs_config(cam)) {
+               mcam_cam_configure(cam);
+               ret = mcam_ctlr_configure(cam);
+               if (ret)
+                       return ret;
+       }
+
+       /*
+        * Turn it loose.
+        */
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       mcam_reset_buffers(cam);
+       mcam_ctlr_irq_enable(cam);
+       cam->state = S_STREAMING;
+       mcam_ctlr_start(cam);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+/*
+ * Videobuf2 interface code.
+ */
+
+static int mcam_vb_queue_setup(struct vb2_queue *vq, unsigned int *nbufs,
+               unsigned int *num_planes, unsigned long sizes[],
+               void *alloc_ctxs[])
+{
+       struct mcam_camera *cam = vb2_get_drv_priv(vq);
+       int minbufs = (cam->buffer_mode == B_DMA_contig) ? 3 : 2;
+
+       sizes[0] = cam->pix_format.sizeimage;
+       *num_planes = 1; /* Someday we have to support planar formats... */
+       if (*nbufs < minbufs)
+               *nbufs = minbufs;
+       if (cam->buffer_mode == B_DMA_contig)
+               alloc_ctxs[0] = cam->vb_alloc_ctx;
+       return 0;
+}
+
+
+static void mcam_vb_buf_queue(struct vb2_buffer *vb)
+{
+       struct mcam_vb_buffer *mvb = vb_to_mvb(vb);
+       struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
+       unsigned long flags;
+       int start;
+
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       start = (cam->state == S_BUFWAIT) && !list_empty(&cam->buffers);
+       list_add(&mvb->queue, &cam->buffers);
+       if (test_bit(CF_SG_RESTART, &cam->flags))
+               mcam_sg_restart(cam);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+       if (start)
+               mcam_read_setup(cam);
+}
+
+
+/*
+ * vb2 uses these to release the mutex when waiting in dqbuf.  I'm
+ * not actually sure we need to do this (I'm not sure that vb2_dqbuf() needs
+ * to be called with the mutex held), but better safe than sorry.
+ */
+static void mcam_vb_wait_prepare(struct vb2_queue *vq)
+{
+       struct mcam_camera *cam = vb2_get_drv_priv(vq);
+
+       mutex_unlock(&cam->s_mutex);
+}
+
+static void mcam_vb_wait_finish(struct vb2_queue *vq)
+{
+       struct mcam_camera *cam = vb2_get_drv_priv(vq);
+
+       mutex_lock(&cam->s_mutex);
+}
+
+/*
+ * These need to be called with the mutex held from vb2
+ */
+static int mcam_vb_start_streaming(struct vb2_queue *vq)
+{
+       struct mcam_camera *cam = vb2_get_drv_priv(vq);
+
+       if (cam->state != S_IDLE)
+               return -EINVAL;
+       cam->sequence = 0;
+       /*
+        * Videobuf2 sneakily hoards all the buffers and won't
+        * give them to us until *after* streaming starts.  But
+        * we can't actually start streaming until we have a
+        * destination.  So go into a wait state and hope they
+        * give us buffers soon.
+        */
+       if (cam->buffer_mode != B_vmalloc && list_empty(&cam->buffers)) {
+               cam->state = S_BUFWAIT;
+               return 0;
+       }
+       return mcam_read_setup(cam);
+}
+
+static int mcam_vb_stop_streaming(struct vb2_queue *vq)
+{
+       struct mcam_camera *cam = vb2_get_drv_priv(vq);
+       unsigned long flags;
+
+       if (cam->state == S_BUFWAIT) {
+               /* They never gave us buffers */
+               cam->state = S_IDLE;
+               return 0;
+       }
+       if (cam->state != S_STREAMING)
+               return -EINVAL;
+       mcam_ctlr_stop_dma(cam);
+       /*
+        * VB2 reclaims the buffers, so we need to forget
+        * about them.
+        */
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       INIT_LIST_HEAD(&cam->buffers);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+       return 0;
+}
+
+
+static const struct vb2_ops mcam_vb2_ops = {
+       .queue_setup            = mcam_vb_queue_setup,
+       .buf_queue              = mcam_vb_buf_queue,
+       .start_streaming        = mcam_vb_start_streaming,
+       .stop_streaming         = mcam_vb_stop_streaming,
+       .wait_prepare           = mcam_vb_wait_prepare,
+       .wait_finish            = mcam_vb_wait_finish,
+};
+
+
+#ifdef MCAM_MODE_DMA_SG
+/*
+ * Scatter/gather mode uses all of the above functions plus a
+ * few extras to deal with DMA mapping.
+ */
+static int mcam_vb_sg_buf_init(struct vb2_buffer *vb)
+{
+       struct mcam_vb_buffer *mvb = vb_to_mvb(vb);
+       struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
+       int ndesc = cam->pix_format.sizeimage/PAGE_SIZE + 1;
+
+       mvb->dma_desc = dma_alloc_coherent(cam->dev,
+                       ndesc * sizeof(struct mcam_dma_desc),
+                       &mvb->dma_desc_pa, GFP_KERNEL);
+       if (mvb->dma_desc == NULL) {
+               cam_err(cam, "Unable to get DMA descriptor array\n");
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static int mcam_vb_sg_buf_prepare(struct vb2_buffer *vb)
+{
+       struct mcam_vb_buffer *mvb = vb_to_mvb(vb);
+       struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
+       struct vb2_dma_sg_desc *sgd = vb2_dma_sg_plane_desc(vb, 0);
+       struct mcam_dma_desc *desc = mvb->dma_desc;
+       struct scatterlist *sg;
+       int i;
+
+       mvb->dma_desc_nent = dma_map_sg(cam->dev, sgd->sglist, sgd->num_pages,
+                       DMA_FROM_DEVICE);
+       if (mvb->dma_desc_nent <= 0)
+               return -EIO;  /* Not sure what's right here */
+       for_each_sg(sgd->sglist, sg, mvb->dma_desc_nent, i) {
+               desc->dma_addr = sg_dma_address(sg);
+               desc->segment_len = sg_dma_len(sg);
+               desc++;
+       }
+       return 0;
+}
+
+static int mcam_vb_sg_buf_finish(struct vb2_buffer *vb)
+{
+       struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
+       struct vb2_dma_sg_desc *sgd = vb2_dma_sg_plane_desc(vb, 0);
+
+       dma_unmap_sg(cam->dev, sgd->sglist, sgd->num_pages, DMA_FROM_DEVICE);
+       return 0;
+}
+
+static void mcam_vb_sg_buf_cleanup(struct vb2_buffer *vb)
+{
+       struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
+       struct mcam_vb_buffer *mvb = vb_to_mvb(vb);
+       int ndesc = cam->pix_format.sizeimage/PAGE_SIZE + 1;
+
+       dma_free_coherent(cam->dev, ndesc * sizeof(struct mcam_dma_desc),
+                       mvb->dma_desc, mvb->dma_desc_pa);
+}
+
+
+static const struct vb2_ops mcam_vb2_sg_ops = {
+       .queue_setup            = mcam_vb_queue_setup,
+       .buf_init               = mcam_vb_sg_buf_init,
+       .buf_prepare            = mcam_vb_sg_buf_prepare,
+       .buf_queue              = mcam_vb_buf_queue,
+       .buf_finish             = mcam_vb_sg_buf_finish,
+       .buf_cleanup            = mcam_vb_sg_buf_cleanup,
+       .start_streaming        = mcam_vb_start_streaming,
+       .stop_streaming         = mcam_vb_stop_streaming,
+       .wait_prepare           = mcam_vb_wait_prepare,
+       .wait_finish            = mcam_vb_wait_finish,
+};
+
+#endif /* MCAM_MODE_DMA_SG */
+
+static int mcam_setup_vb2(struct mcam_camera *cam)
+{
+       struct vb2_queue *vq = &cam->vb_queue;
+
+       memset(vq, 0, sizeof(*vq));
+       vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       vq->drv_priv = cam;
+       INIT_LIST_HEAD(&cam->buffers);
+       switch (cam->buffer_mode) {
+       case B_DMA_contig:
+#ifdef MCAM_MODE_DMA_CONTIG
+               vq->ops = &mcam_vb2_ops;
+               vq->mem_ops = &vb2_dma_contig_memops;
+               cam->vb_alloc_ctx = vb2_dma_contig_init_ctx(cam->dev);
+               vq->io_modes = VB2_MMAP | VB2_USERPTR;
+               cam->dma_setup = mcam_ctlr_dma_contig;
+               cam->frame_complete = mcam_dma_contig_done;
+#endif
+               break;
+       case B_DMA_sg:
+#ifdef MCAM_MODE_DMA_SG
+               vq->ops = &mcam_vb2_sg_ops;
+               vq->mem_ops = &vb2_dma_sg_memops;
+               vq->io_modes = VB2_MMAP | VB2_USERPTR;
+               cam->dma_setup = mcam_ctlr_dma_sg;
+               cam->frame_complete = mcam_dma_sg_done;
+#endif
+               break;
+       case B_vmalloc:
+#ifdef MCAM_MODE_VMALLOC
+               tasklet_init(&cam->s_tasklet, mcam_frame_tasklet,
+                               (unsigned long) cam);
+               vq->ops = &mcam_vb2_ops;
+               vq->mem_ops = &vb2_vmalloc_memops;
+               vq->buf_struct_size = sizeof(struct mcam_vb_buffer);
+               vq->io_modes = VB2_MMAP;
+               cam->dma_setup = mcam_ctlr_dma_vmalloc;
+               cam->frame_complete = mcam_vmalloc_done;
+#endif
+               break;
+       }
+       return vb2_queue_init(vq);
+}
+
+static void mcam_cleanup_vb2(struct mcam_camera *cam)
+{
+       vb2_queue_release(&cam->vb_queue);
+#ifdef MCAM_MODE_DMA_CONTIG
+       if (cam->buffer_mode == B_DMA_contig)
+               vb2_dma_contig_cleanup_ctx(cam->vb_alloc_ctx);
+#endif
+}
+
+
+/* ---------------------------------------------------------------------- */
+/*
+ * The long list of V4L2 ioctl() operations.
+ */
+
+static int mcam_vidioc_streamon(struct file *filp, void *priv,
+               enum v4l2_buf_type type)
+{
+       struct mcam_camera *cam = filp->private_data;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = vb2_streamon(&cam->vb_queue, type);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+static int mcam_vidioc_streamoff(struct file *filp, void *priv,
+               enum v4l2_buf_type type)
+{
+       struct mcam_camera *cam = filp->private_data;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = vb2_streamoff(&cam->vb_queue, type);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+static int mcam_vidioc_reqbufs(struct file *filp, void *priv,
+               struct v4l2_requestbuffers *req)
+{
+       struct mcam_camera *cam = filp->private_data;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = vb2_reqbufs(&cam->vb_queue, req);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+static int mcam_vidioc_querybuf(struct file *filp, void *priv,
+               struct v4l2_buffer *buf)
+{
+       struct mcam_camera *cam = filp->private_data;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = vb2_querybuf(&cam->vb_queue, buf);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+static int mcam_vidioc_qbuf(struct file *filp, void *priv,
+               struct v4l2_buffer *buf)
+{
+       struct mcam_camera *cam = filp->private_data;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = vb2_qbuf(&cam->vb_queue, buf);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+static int mcam_vidioc_dqbuf(struct file *filp, void *priv,
+               struct v4l2_buffer *buf)
+{
+       struct mcam_camera *cam = filp->private_data;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = vb2_dqbuf(&cam->vb_queue, buf, filp->f_flags & O_NONBLOCK);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+
+static int mcam_vidioc_queryctrl(struct file *filp, void *priv,
+               struct v4l2_queryctrl *qc)
+{
+       struct mcam_camera *cam = priv;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = sensor_call(cam, core, queryctrl, qc);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+static int mcam_vidioc_g_ctrl(struct file *filp, void *priv,
+               struct v4l2_control *ctrl)
+{
+       struct mcam_camera *cam = priv;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = sensor_call(cam, core, g_ctrl, ctrl);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+static int mcam_vidioc_s_ctrl(struct file *filp, void *priv,
+               struct v4l2_control *ctrl)
+{
+       struct mcam_camera *cam = priv;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = sensor_call(cam, core, s_ctrl, ctrl);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+static int mcam_vidioc_querycap(struct file *file, void *priv,
+               struct v4l2_capability *cap)
+{
+       strcpy(cap->driver, "marvell_ccic");
+       strcpy(cap->card, "marvell_ccic");
+       cap->version = 1;
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+               V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+       return 0;
+}
+
+
+static int mcam_vidioc_enum_fmt_vid_cap(struct file *filp,
+               void *priv, struct v4l2_fmtdesc *fmt)
+{
+       if (fmt->index >= N_MCAM_FMTS)
+               return -EINVAL;
+       strlcpy(fmt->description, mcam_formats[fmt->index].desc,
+                       sizeof(fmt->description));
+       fmt->pixelformat = mcam_formats[fmt->index].pixelformat;
+       return 0;
+}
+
+static int mcam_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
+               struct v4l2_format *fmt)
+{
+       struct mcam_camera *cam = priv;
+       struct mcam_format_struct *f;
+       struct v4l2_pix_format *pix = &fmt->fmt.pix;
+       struct v4l2_mbus_framefmt mbus_fmt;
+       int ret;
+
+       f = mcam_find_format(pix->pixelformat);
+       pix->pixelformat = f->pixelformat;
+       v4l2_fill_mbus_format(&mbus_fmt, pix, f->mbus_code);
+       mutex_lock(&cam->s_mutex);
+       ret = sensor_call(cam, video, try_mbus_fmt, &mbus_fmt);
+       mutex_unlock(&cam->s_mutex);
+       v4l2_fill_pix_format(pix, &mbus_fmt);
+       pix->bytesperline = pix->width * f->bpp;
+       pix->sizeimage = pix->height * pix->bytesperline;
+       return ret;
+}
+
+static int mcam_vidioc_s_fmt_vid_cap(struct file *filp, void *priv,
+               struct v4l2_format *fmt)
+{
+       struct mcam_camera *cam = priv;
+       struct mcam_format_struct *f;
+       int ret;
+
+       /*
+        * Can't do anything if the device is not idle
+        * Also can't if there are streaming buffers in place.
+        */
+       if (cam->state != S_IDLE || cam->vb_queue.num_buffers > 0)
+               return -EBUSY;
+
+       f = mcam_find_format(fmt->fmt.pix.pixelformat);
+
+       /*
+        * See if the formatting works in principle.
+        */
+       ret = mcam_vidioc_try_fmt_vid_cap(filp, priv, fmt);
+       if (ret)
+               return ret;
+       /*
+        * Now we start to change things for real, so let's do it
+        * under lock.
+        */
+       mutex_lock(&cam->s_mutex);
+       cam->pix_format = fmt->fmt.pix;
+       cam->mbus_code = f->mbus_code;
+
+       /*
+        * Make sure we have appropriate DMA buffers.
+        */
+       if (cam->buffer_mode == B_vmalloc) {
+               ret = mcam_check_dma_buffers(cam);
+               if (ret)
+                       goto out;
+       }
+       mcam_set_config_needed(cam, 1);
+       ret = 0;
+out:
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+/*
+ * Return our stored notion of how the camera is/should be configured.
+ * The V4l2 spec wants us to be smarter, and actually get this from
+ * the camera (and not mess with it at open time).  Someday.
+ */
+static int mcam_vidioc_g_fmt_vid_cap(struct file *filp, void *priv,
+               struct v4l2_format *f)
+{
+       struct mcam_camera *cam = priv;
+
+       f->fmt.pix = cam->pix_format;
+       return 0;
+}
+
+/*
+ * We only have one input - the sensor - so minimize the nonsense here.
+ */
+static int mcam_vidioc_enum_input(struct file *filp, void *priv,
+               struct v4l2_input *input)
+{
+       if (input->index != 0)
+               return -EINVAL;
+
+       input->type = V4L2_INPUT_TYPE_CAMERA;
+       input->std = V4L2_STD_ALL; /* Not sure what should go here */
+       strcpy(input->name, "Camera");
+       return 0;
+}
+
+static int mcam_vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+       *i = 0;
+       return 0;
+}
+
+static int mcam_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+       if (i != 0)
+               return -EINVAL;
+       return 0;
+}
+
+/* from vivi.c */
+static int mcam_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a)
+{
+       return 0;
+}
+
+/*
+ * G/S_PARM.  Most of this is done by the sensor, but we are
+ * the level which controls the number of read buffers.
+ */
+static int mcam_vidioc_g_parm(struct file *filp, void *priv,
+               struct v4l2_streamparm *parms)
+{
+       struct mcam_camera *cam = priv;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = sensor_call(cam, video, g_parm, parms);
+       mutex_unlock(&cam->s_mutex);
+       parms->parm.capture.readbuffers = n_dma_bufs;
+       return ret;
+}
+
+static int mcam_vidioc_s_parm(struct file *filp, void *priv,
+               struct v4l2_streamparm *parms)
+{
+       struct mcam_camera *cam = priv;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = sensor_call(cam, video, s_parm, parms);
+       mutex_unlock(&cam->s_mutex);
+       parms->parm.capture.readbuffers = n_dma_bufs;
+       return ret;
+}
+
+static int mcam_vidioc_g_chip_ident(struct file *file, void *priv,
+               struct v4l2_dbg_chip_ident *chip)
+{
+       struct mcam_camera *cam = priv;
+
+       chip->ident = V4L2_IDENT_NONE;
+       chip->revision = 0;
+       if (v4l2_chip_match_host(&chip->match)) {
+               chip->ident = cam->chip_id;
+               return 0;
+       }
+       return sensor_call(cam, core, g_chip_ident, chip);
+}
+
+static int mcam_vidioc_enum_framesizes(struct file *filp, void *priv,
+               struct v4l2_frmsizeenum *sizes)
+{
+       struct mcam_camera *cam = priv;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = sensor_call(cam, video, enum_framesizes, sizes);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+static int mcam_vidioc_enum_frameintervals(struct file *filp, void *priv,
+               struct v4l2_frmivalenum *interval)
+{
+       struct mcam_camera *cam = priv;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = sensor_call(cam, video, enum_frameintervals, interval);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mcam_vidioc_g_register(struct file *file, void *priv,
+               struct v4l2_dbg_register *reg)
+{
+       struct mcam_camera *cam = priv;
+
+       if (v4l2_chip_match_host(&reg->match)) {
+               reg->val = mcam_reg_read(cam, reg->reg);
+               reg->size = 4;
+               return 0;
+       }
+       return sensor_call(cam, core, g_register, reg);
+}
+
+static int mcam_vidioc_s_register(struct file *file, void *priv,
+               struct v4l2_dbg_register *reg)
+{
+       struct mcam_camera *cam = priv;
+
+       if (v4l2_chip_match_host(&reg->match)) {
+               mcam_reg_write(cam, reg->reg, reg->val);
+               return 0;
+       }
+       return sensor_call(cam, core, s_register, reg);
+}
+#endif
+
+static const struct v4l2_ioctl_ops mcam_v4l_ioctl_ops = {
+       .vidioc_querycap        = mcam_vidioc_querycap,
+       .vidioc_enum_fmt_vid_cap = mcam_vidioc_enum_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap = mcam_vidioc_try_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap   = mcam_vidioc_s_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap   = mcam_vidioc_g_fmt_vid_cap,
+       .vidioc_enum_input      = mcam_vidioc_enum_input,
+       .vidioc_g_input         = mcam_vidioc_g_input,
+       .vidioc_s_input         = mcam_vidioc_s_input,
+       .vidioc_s_std           = mcam_vidioc_s_std,
+       .vidioc_reqbufs         = mcam_vidioc_reqbufs,
+       .vidioc_querybuf        = mcam_vidioc_querybuf,
+       .vidioc_qbuf            = mcam_vidioc_qbuf,
+       .vidioc_dqbuf           = mcam_vidioc_dqbuf,
+       .vidioc_streamon        = mcam_vidioc_streamon,
+       .vidioc_streamoff       = mcam_vidioc_streamoff,
+       .vidioc_queryctrl       = mcam_vidioc_queryctrl,
+       .vidioc_g_ctrl          = mcam_vidioc_g_ctrl,
+       .vidioc_s_ctrl          = mcam_vidioc_s_ctrl,
+       .vidioc_g_parm          = mcam_vidioc_g_parm,
+       .vidioc_s_parm          = mcam_vidioc_s_parm,
+       .vidioc_enum_framesizes = mcam_vidioc_enum_framesizes,
+       .vidioc_enum_frameintervals = mcam_vidioc_enum_frameintervals,
+       .vidioc_g_chip_ident    = mcam_vidioc_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_register      = mcam_vidioc_g_register,
+       .vidioc_s_register      = mcam_vidioc_s_register,
+#endif
+};
+
+/* ---------------------------------------------------------------------- */
+/*
+ * Our various file operations.
+ */
+static int mcam_v4l_open(struct file *filp)
+{
+       struct mcam_camera *cam = video_drvdata(filp);
+       int ret = 0;
+
+       filp->private_data = cam;
+
+       frames = singles = delivered = 0;
+       mutex_lock(&cam->s_mutex);
+       if (cam->users == 0) {
+               ret = mcam_setup_vb2(cam);
+               if (ret)
+                       goto out;
+               mcam_ctlr_power_up(cam);
+               __mcam_cam_reset(cam);
+               mcam_set_config_needed(cam, 1);
+       }
+       (cam->users)++;
+out:
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+static int mcam_v4l_release(struct file *filp)
+{
+       struct mcam_camera *cam = filp->private_data;
+
+       cam_err(cam, "Release, %d frames, %d singles, %d delivered\n", frames,
+                       singles, delivered);
+       mutex_lock(&cam->s_mutex);
+       (cam->users)--;
+       if (filp == cam->owner) {
+               mcam_ctlr_stop_dma(cam);
+               cam->owner = NULL;
+       }
+       if (cam->users == 0) {
+               mcam_cleanup_vb2(cam);
+               mcam_ctlr_power_down(cam);
+               if (cam->buffer_mode == B_vmalloc && alloc_bufs_at_read)
+                       mcam_free_dma_bufs(cam);
+       }
+       mutex_unlock(&cam->s_mutex);
+       return 0;
+}
+
+static ssize_t mcam_v4l_read(struct file *filp,
+               char __user *buffer, size_t len, loff_t *pos)
+{
+       struct mcam_camera *cam = filp->private_data;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = vb2_read(&cam->vb_queue, buffer, len, pos,
+                       filp->f_flags & O_NONBLOCK);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+
+static unsigned int mcam_v4l_poll(struct file *filp,
+               struct poll_table_struct *pt)
+{
+       struct mcam_camera *cam = filp->private_data;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = vb2_poll(&cam->vb_queue, filp, pt);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+static int mcam_v4l_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct mcam_camera *cam = filp->private_data;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = vb2_mmap(&cam->vb_queue, vma);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+
+static const struct v4l2_file_operations mcam_v4l_fops = {
+       .owner = THIS_MODULE,
+       .open = mcam_v4l_open,
+       .release = mcam_v4l_release,
+       .read = mcam_v4l_read,
+       .poll = mcam_v4l_poll,
+       .mmap = mcam_v4l_mmap,
+       .unlocked_ioctl = video_ioctl2,
+};
+
+
+/*
+ * This template device holds all of those v4l2 methods; we
+ * clone it for specific real devices.
+ */
+static struct video_device mcam_v4l_template = {
+       .name = "mcam",
+       .tvnorms = V4L2_STD_NTSC_M,
+       .current_norm = V4L2_STD_NTSC_M,  /* make mplayer happy */
+
+       .fops = &mcam_v4l_fops,
+       .ioctl_ops = &mcam_v4l_ioctl_ops,
+       .release = video_device_release_empty,
+};
+
+/* ---------------------------------------------------------------------- */
+/*
+ * Interrupt handler stuff
+ */
+static void mcam_frame_complete(struct mcam_camera *cam, int frame)
+{
+       /*
+        * Basic frame housekeeping.
+        */
+       set_bit(frame, &cam->flags);
+       clear_bit(CF_DMA_ACTIVE, &cam->flags);
+       cam->next_buf = frame;
+       cam->buf_seq[frame] = ++(cam->sequence);
+       frames++;
+       /*
+        * "This should never happen"
+        */
+       if (cam->state != S_STREAMING)
+               return;
+       /*
+        * Process the frame and set up the next one.
+        */
+       cam->frame_complete(cam, frame);
+}
+
+
+/*
+ * The interrupt handler; this needs to be called from the
+ * platform irq handler with the lock held.
+ */
+int mccic_irq(struct mcam_camera *cam, unsigned int irqs)
+{
+       unsigned int frame, handled = 0;
+
+       mcam_reg_write(cam, REG_IRQSTAT, FRAMEIRQS); /* Clear'em all */
+       /*
+        * Handle any frame completions.  There really should
+        * not be more than one of these, or we have fallen
+        * far behind.
+        *
+        * When running in S/G mode, the frame number lacks any
+        * real meaning - there's only one descriptor array - but
+        * the controller still picks a different one to signal
+        * each time.
+        */
+       for (frame = 0; frame < cam->nbufs; frame++)
+               if (irqs & (IRQ_EOF0 << frame)) {
+                       mcam_frame_complete(cam, frame);
+                       handled = 1;
+               }
+       /*
+        * If a frame starts, note that we have DMA active.  This
+        * code assumes that we won't get multiple frame interrupts
+        * at once; may want to rethink that.
+        */
+       if (irqs & (IRQ_SOF0 | IRQ_SOF1 | IRQ_SOF2)) {
+               set_bit(CF_DMA_ACTIVE, &cam->flags);
+               handled = 1;
+               if (cam->buffer_mode == B_DMA_sg)
+                       mcam_ctlr_stop(cam);
+       }
+       return handled;
+}
+
+/* ---------------------------------------------------------------------- */
+/*
+ * Registration and such.
+ */
+static struct ov7670_config sensor_cfg = {
+       /*
+        * Exclude QCIF mode, because it only captures a tiny portion
+        * of the sensor FOV
+        */
+       .min_width = 320,
+       .min_height = 240,
+};
+
+
+int mccic_register(struct mcam_camera *cam)
+{
+       struct i2c_board_info ov7670_info = {
+               .type = "ov7670",
+               .addr = 0x42 >> 1,
+               .platform_data = &sensor_cfg,
+       };
+       int ret;
+
+       /*
+        * Validate the requested buffer mode.
+        */
+       if (buffer_mode >= 0)
+               cam->buffer_mode = buffer_mode;
+       if (cam->buffer_mode == B_DMA_sg &&
+                       cam->chip_id == V4L2_IDENT_CAFE) {
+               printk(KERN_ERR "marvell-cam: Cafe can't do S/G I/O, "
+                       "attempting vmalloc mode instead\n");
+               cam->buffer_mode = B_vmalloc;
+       }
+       if (!mcam_buffer_mode_supported(cam->buffer_mode)) {
+               printk(KERN_ERR "marvell-cam: buffer mode %d unsupported\n",
+                               cam->buffer_mode);
+               return -EINVAL;
+       }
+       /*
+        * Register with V4L
+        */
+       ret = v4l2_device_register(cam->dev, &cam->v4l2_dev);
+       if (ret)
+               return ret;
+
+       mutex_init(&cam->s_mutex);
+       cam->state = S_NOTREADY;
+       mcam_set_config_needed(cam, 1);
+       cam->pix_format = mcam_def_pix_format;
+       cam->mbus_code = mcam_def_mbus_code;
+       INIT_LIST_HEAD(&cam->buffers);
+       mcam_ctlr_init(cam);
+
+       /*
+        * Try to find the sensor.
+        */
+       sensor_cfg.clock_speed = cam->clock_speed;
+       sensor_cfg.use_smbus = cam->use_smbus;
+       cam->sensor_addr = ov7670_info.addr;
+       cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev,
+                       cam->i2c_adapter, &ov7670_info, NULL);
+       if (cam->sensor == NULL) {
+               ret = -ENODEV;
+               goto out_unregister;
+       }
+
+       ret = mcam_cam_init(cam);
+       if (ret)
+               goto out_unregister;
+       /*
+        * Get the v4l2 setup done.
+        */
+       mutex_lock(&cam->s_mutex);
+       cam->vdev = mcam_v4l_template;
+       cam->vdev.debug = 0;
+       cam->vdev.v4l2_dev = &cam->v4l2_dev;
+       ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
+       if (ret)
+               goto out;
+       video_set_drvdata(&cam->vdev, cam);
+
+       /*
+        * If so requested, try to get our DMA buffers now.
+        */
+       if (cam->buffer_mode == B_vmalloc && !alloc_bufs_at_read) {
+               if (mcam_alloc_dma_bufs(cam, 1))
+                       cam_warn(cam, "Unable to alloc DMA buffers at load"
+                                       " will try again later.");
+       }
+
+out:
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+out_unregister:
+       v4l2_device_unregister(&cam->v4l2_dev);
+       return ret;
+}
+
+
+void mccic_shutdown(struct mcam_camera *cam)
+{
+       /*
+        * If we have no users (and we really, really should have no
+        * users) the device will already be powered down.  Trying to
+        * take it down again will wedge the machine, which is frowned
+        * upon.
+        */
+       if (cam->users > 0) {
+               cam_warn(cam, "Removing a device with users!\n");
+               mcam_ctlr_power_down(cam);
+       }
+       vb2_queue_release(&cam->vb_queue);
+       if (cam->buffer_mode == B_vmalloc)
+               mcam_free_dma_bufs(cam);
+       video_unregister_device(&cam->vdev);
+       v4l2_device_unregister(&cam->v4l2_dev);
+}
+
+/*
+ * Power management
+ */
+#ifdef CONFIG_PM
+
+void mccic_suspend(struct mcam_camera *cam)
+{
+       enum mcam_state cstate = cam->state;
+
+       mcam_ctlr_stop_dma(cam);
+       mcam_ctlr_power_down(cam);
+       cam->state = cstate;
+}
+
+int mccic_resume(struct mcam_camera *cam)
+{
+       int ret = 0;
+
+       mutex_lock(&cam->s_mutex);
+       if (cam->users > 0) {
+               mcam_ctlr_power_up(cam);
+               __mcam_cam_reset(cam);
+       } else {
+               mcam_ctlr_power_down(cam);
+       }
+       mutex_unlock(&cam->s_mutex);
+
+       set_bit(CF_CONFIG_NEEDED, &cam->flags);
+       if (cam->state == S_STREAMING)
+               ret = mcam_read_setup(cam);
+       return ret;
+}
+#endif /* CONFIG_PM */
diff --git a/drivers/media/video/marvell-ccic/mcam-core.h b/drivers/media/video/marvell-ccic/mcam-core.h
new file mode 100644 (file)
index 0000000..917200e
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * Marvell camera core structures.
+ *
+ * Copyright 2011 Jonathan Corbet corbet@lwn.net
+ */
+#ifndef _MCAM_CORE_H
+#define _MCAM_CORE_H
+
+#include <linux/list.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/videobuf2-core.h>
+
+/*
+ * Create our own symbols for the supported buffer modes, but, for now,
+ * base them entirely on which videobuf2 options have been selected.
+ */
+#if defined(CONFIG_VIDEOBUF2_VMALLOC) || defined(CONFIG_VIDEOBUF2_VMALLOC_MODULE)
+#define MCAM_MODE_VMALLOC 1
+#endif
+
+#if defined(CONFIG_VIDEOBUF2_DMA_CONTIG) || defined(CONFIG_VIDEOBUF2_DMA_CONTIG_MODULE)
+#define MCAM_MODE_DMA_CONTIG 1
+#endif
+
+#if defined(CONFIG_VIDEOBUF2_DMA_SG) || defined(CONFIG_VIDEOBUF2_DMA_SG_MODULE)
+#define MCAM_MODE_DMA_SG 1
+#endif
+
+#if !defined(MCAM_MODE_VMALLOC) && !defined(MCAM_MODE_DMA_CONTIG) && \
+       !defined(MCAM_MODE_DMA_SG)
+#error One of the videobuf buffer modes must be selected in the config
+#endif
+
+
+enum mcam_state {
+       S_NOTREADY,     /* Not yet initialized */
+       S_IDLE,         /* Just hanging around */
+       S_FLAKED,       /* Some sort of problem */
+       S_STREAMING,    /* Streaming data */
+       S_BUFWAIT       /* streaming requested but no buffers yet */
+};
+#define MAX_DMA_BUFS 3
+
+/*
+ * Different platforms work best with different buffer modes, so we
+ * let the platform pick.
+ */
+enum mcam_buffer_mode {
+       B_vmalloc = 0,
+       B_DMA_contig = 1,
+       B_DMA_sg = 2
+};
+
+/*
+ * Is a given buffer mode supported by the current kernel configuration?
+ */
+static inline int mcam_buffer_mode_supported(enum mcam_buffer_mode mode)
+{
+       switch (mode) {
+#ifdef MCAM_MODE_VMALLOC
+       case B_vmalloc:
+#endif
+#ifdef MCAM_MODE_DMA_CONTIG
+       case B_DMA_contig:
+#endif
+#ifdef MCAM_MODE_DMA_SG
+       case B_DMA_sg:
+#endif
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+
+/*
+ * A description of one of our devices.
+ * Locking: controlled by s_mutex.  Certain fields, however, require
+ *          the dev_lock spinlock; they are marked as such by comments.
+ *          dev_lock is also required for access to device registers.
+ */
+struct mcam_camera {
+       /*
+        * These fields should be set by the platform code prior to
+        * calling mcam_register().
+        */
+       struct i2c_adapter *i2c_adapter;
+       unsigned char __iomem *regs;
+       spinlock_t dev_lock;
+       struct device *dev; /* For messages, dma alloc */
+       unsigned int chip_id;
+       short int clock_speed;  /* Sensor clock speed, default 30 */
+       short int use_smbus;    /* SMBUS or straight I2c? */
+       enum mcam_buffer_mode buffer_mode;
+       /*
+        * Callbacks from the core to the platform code.
+        */
+       void (*plat_power_up) (struct mcam_camera *cam);
+       void (*plat_power_down) (struct mcam_camera *cam);
+
+       /*
+        * Everything below here is private to the mcam core and
+        * should not be touched by the platform code.
+        */
+       struct v4l2_device v4l2_dev;
+       enum mcam_state state;
+       unsigned long flags;            /* Buffer status, mainly (dev_lock) */
+       int users;                      /* How many open FDs */
+       struct file *owner;             /* Who has data access (v4l2) */
+
+       /*
+        * Subsystem structures.
+        */
+       struct video_device vdev;
+       struct v4l2_subdev *sensor;
+       unsigned short sensor_addr;
+
+       /* Videobuf2 stuff */
+       struct vb2_queue vb_queue;
+       struct list_head buffers;       /* Available frames */
+
+       unsigned int nbufs;             /* How many are alloc'd */
+       int next_buf;                   /* Next to consume (dev_lock) */
+
+       /* DMA buffers - vmalloc mode */
+#ifdef MCAM_MODE_VMALLOC
+       unsigned int dma_buf_size;      /* allocated size */
+       void *dma_bufs[MAX_DMA_BUFS];   /* Internal buffer addresses */
+       dma_addr_t dma_handles[MAX_DMA_BUFS]; /* Buffer bus addresses */
+       struct tasklet_struct s_tasklet;
+#endif
+       unsigned int sequence;          /* Frame sequence number */
+       unsigned int buf_seq[MAX_DMA_BUFS]; /* Sequence for individual bufs */
+
+       /* DMA buffers - DMA modes */
+       struct mcam_vb_buffer *vb_bufs[MAX_DMA_BUFS];
+       struct vb2_alloc_ctx *vb_alloc_ctx;
+
+       /* Mode-specific ops, set at open time */
+       void (*dma_setup)(struct mcam_camera *cam);
+       void (*frame_complete)(struct mcam_camera *cam, int frame);
+
+       /* Current operating parameters */
+       u32 sensor_type;                /* Currently ov7670 only */
+       struct v4l2_pix_format pix_format;
+       enum v4l2_mbus_pixelcode mbus_code;
+
+       /* Locks */
+       struct mutex s_mutex; /* Access to this structure */
+};
+
+
+/*
+ * Register I/O functions.  These are here because the platform code
+ * may legitimately need to mess with the register space.
+ */
+/*
+ * Device register I/O
+ */
+static inline void mcam_reg_write(struct mcam_camera *cam, unsigned int reg,
+               unsigned int val)
+{
+       iowrite32(val, cam->regs + reg);
+}
+
+static inline unsigned int mcam_reg_read(struct mcam_camera *cam,
+               unsigned int reg)
+{
+       return ioread32(cam->regs + reg);
+}
+
+
+static inline void mcam_reg_write_mask(struct mcam_camera *cam, unsigned int reg,
+               unsigned int val, unsigned int mask)
+{
+       unsigned int v = mcam_reg_read(cam, reg);
+
+       v = (v & ~mask) | (val & mask);
+       mcam_reg_write(cam, reg, v);
+}
+
+static inline void mcam_reg_clear_bit(struct mcam_camera *cam,
+               unsigned int reg, unsigned int val)
+{
+       mcam_reg_write_mask(cam, reg, 0, val);
+}
+
+static inline void mcam_reg_set_bit(struct mcam_camera *cam,
+               unsigned int reg, unsigned int val)
+{
+       mcam_reg_write_mask(cam, reg, val, val);
+}
+
+/*
+ * Functions for use by platform code.
+ */
+int mccic_register(struct mcam_camera *cam);
+int mccic_irq(struct mcam_camera *cam, unsigned int irqs);
+void mccic_shutdown(struct mcam_camera *cam);
+#ifdef CONFIG_PM
+void mccic_suspend(struct mcam_camera *cam);
+int mccic_resume(struct mcam_camera *cam);
+#endif
+
+/*
+ * Register definitions for the m88alp01 camera interface.  Offsets in bytes
+ * as given in the spec.
+ */
+#define REG_Y0BAR      0x00
+#define REG_Y1BAR      0x04
+#define REG_Y2BAR      0x08
+/* ... */
+
+#define REG_IMGPITCH   0x24    /* Image pitch register */
+#define   IMGP_YP_SHFT   2             /* Y pitch params */
+#define   IMGP_YP_MASK   0x00003ffc    /* Y pitch field */
+#define          IMGP_UVP_SHFT   18            /* UV pitch (planar) */
+#define   IMGP_UVP_MASK   0x3ffc0000
+#define REG_IRQSTATRAW 0x28    /* RAW IRQ Status */
+#define   IRQ_EOF0       0x00000001    /* End of frame 0 */
+#define   IRQ_EOF1       0x00000002    /* End of frame 1 */
+#define   IRQ_EOF2       0x00000004    /* End of frame 2 */
+#define   IRQ_SOF0       0x00000008    /* Start of frame 0 */
+#define   IRQ_SOF1       0x00000010    /* Start of frame 1 */
+#define   IRQ_SOF2       0x00000020    /* Start of frame 2 */
+#define   IRQ_OVERFLOW   0x00000040    /* FIFO overflow */
+#define   IRQ_TWSIW      0x00010000    /* TWSI (smbus) write */
+#define   IRQ_TWSIR      0x00020000    /* TWSI read */
+#define   IRQ_TWSIE      0x00040000    /* TWSI error */
+#define   TWSIIRQS (IRQ_TWSIW|IRQ_TWSIR|IRQ_TWSIE)
+#define   FRAMEIRQS (IRQ_EOF0|IRQ_EOF1|IRQ_EOF2|IRQ_SOF0|IRQ_SOF1|IRQ_SOF2)
+#define   ALLIRQS (TWSIIRQS|FRAMEIRQS|IRQ_OVERFLOW)
+#define REG_IRQMASK    0x2c    /* IRQ mask - same bits as IRQSTAT */
+#define REG_IRQSTAT    0x30    /* IRQ status / clear */
+
+#define REG_IMGSIZE    0x34    /* Image size */
+#define  IMGSZ_V_MASK    0x1fff0000
+#define  IMGSZ_V_SHIFT   16
+#define         IMGSZ_H_MASK     0x00003fff
+#define REG_IMGOFFSET  0x38    /* IMage offset */
+
+#define REG_CTRL0      0x3c    /* Control 0 */
+#define   C0_ENABLE      0x00000001    /* Makes the whole thing go */
+
+/* Mask for all the format bits */
+#define   C0_DF_MASK     0x00fffffc    /* Bits 2-23 */
+
+/* RGB ordering */
+#define          C0_RGB4_RGBX    0x00000000
+#define          C0_RGB4_XRGB    0x00000004
+#define          C0_RGB4_BGRX    0x00000008
+#define          C0_RGB4_XBGR    0x0000000c
+#define          C0_RGB5_RGGB    0x00000000
+#define          C0_RGB5_GRBG    0x00000004
+#define          C0_RGB5_GBRG    0x00000008
+#define          C0_RGB5_BGGR    0x0000000c
+
+/* Spec has two fields for DIN and DOUT, but they must match, so
+   combine them here. */
+#define          C0_DF_YUV       0x00000000    /* Data is YUV      */
+#define          C0_DF_RGB       0x000000a0    /* ... RGB                  */
+#define          C0_DF_BAYER     0x00000140    /* ... Bayer                */
+/* 8-8-8 must be missing from the below - ask */
+#define          C0_RGBF_565     0x00000000
+#define          C0_RGBF_444     0x00000800
+#define          C0_RGB_BGR      0x00001000    /* Blue comes first */
+#define          C0_YUV_PLANAR   0x00000000    /* YUV 422 planar format */
+#define          C0_YUV_PACKED   0x00008000    /* YUV 422 packed       */
+#define          C0_YUV_420PL    0x0000a000    /* YUV 420 planar       */
+/* Think that 420 packed must be 111 - ask */
+#define          C0_YUVE_YUYV    0x00000000    /* Y1CbY0Cr             */
+#define          C0_YUVE_YVYU    0x00010000    /* Y1CrY0Cb             */
+#define          C0_YUVE_VYUY    0x00020000    /* CrY1CbY0             */
+#define          C0_YUVE_UYVY    0x00030000    /* CbY1CrY0             */
+#define          C0_YUVE_XYUV    0x00000000    /* 420: .YUV            */
+#define          C0_YUVE_XYVU    0x00010000    /* 420: .YVU            */
+#define          C0_YUVE_XUVY    0x00020000    /* 420: .UVY            */
+#define          C0_YUVE_XVUY    0x00030000    /* 420: .VUY            */
+/* Bayer bits 18,19 if needed */
+#define          C0_HPOL_LOW     0x01000000    /* HSYNC polarity active low */
+#define          C0_VPOL_LOW     0x02000000    /* VSYNC polarity active low */
+#define          C0_VCLK_LOW     0x04000000    /* VCLK on falling edge */
+#define          C0_DOWNSCALE    0x08000000    /* Enable downscaler */
+#define          C0_SIFM_MASK    0xc0000000    /* SIF mode bits */
+#define          C0_SIF_HVSYNC   0x00000000    /* Use H/VSYNC */
+#define          CO_SOF_NOSYNC   0x40000000    /* Use inband active signaling */
+
+/* Bits below C1_444ALPHA are not present in Cafe */
+#define REG_CTRL1      0x40    /* Control 1 */
+#define          C1_CLKGATE      0x00000001    /* Sensor clock gate */
+#define   C1_DESC_ENA    0x00000100    /* DMA descriptor enable */
+#define   C1_DESC_3WORD   0x00000200   /* Three-word descriptors used */
+#define          C1_444ALPHA     0x00f00000    /* Alpha field in RGB444 */
+#define          C1_ALPHA_SHFT   20
+#define          C1_DMAB32       0x00000000    /* 32-byte DMA burst */
+#define          C1_DMAB16       0x02000000    /* 16-byte DMA burst */
+#define          C1_DMAB64       0x04000000    /* 64-byte DMA burst */
+#define          C1_DMAB_MASK    0x06000000
+#define          C1_TWOBUFS      0x08000000    /* Use only two DMA buffers */
+#define          C1_PWRDWN       0x10000000    /* Power down */
+
+#define REG_CLKCTRL    0x88    /* Clock control */
+#define          CLK_DIV_MASK    0x0000ffff    /* Upper bits RW "reserved" */
+
+/* This appears to be a Cafe-only register */
+#define REG_UBAR       0xc4    /* Upper base address register */
+
+/* Armada 610 DMA descriptor registers */
+#define        REG_DMA_DESC_Y  0x200
+#define        REG_DMA_DESC_U  0x204
+#define        REG_DMA_DESC_V  0x208
+#define REG_DESC_LEN_Y 0x20c   /* Lengths are in bytes */
+#define        REG_DESC_LEN_U  0x210
+#define REG_DESC_LEN_V 0x214
+
+/*
+ * Useful stuff that probably belongs somewhere global.
+ */
+#define VGA_WIDTH      640
+#define VGA_HEIGHT     480
+
+#endif /* _MCAM_CORE_H */
diff --git a/drivers/media/video/marvell-ccic/mmp-driver.c b/drivers/media/video/marvell-ccic/mmp-driver.c
new file mode 100644 (file)
index 0000000..d6b7645
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+ * Support for the camera device found on Marvell MMP processors; known
+ * to work with the Armada 610 as used in the OLPC 1.75 system.
+ *
+ * Copyright 2011 Jonathan Corbet <corbet@lwn.net>
+ *
+ * This file may be distributed under the terms of the GNU General
+ * Public License, version 2.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/i2c-gpio.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/mmp-camera.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+
+#include "mcam-core.h"
+
+MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
+MODULE_LICENSE("GPL");
+
+struct mmp_camera {
+       void *power_regs;
+       struct platform_device *pdev;
+       struct mcam_camera mcam;
+       struct list_head devlist;
+       int irq;
+};
+
+static inline struct mmp_camera *mcam_to_cam(struct mcam_camera *mcam)
+{
+       return container_of(mcam, struct mmp_camera, mcam);
+}
+
+/*
+ * A silly little infrastructure so we can keep track of our devices.
+ * Chances are that we will never have more than one of them, but
+ * the Armada 610 *does* have two controllers...
+ */
+
+static LIST_HEAD(mmpcam_devices);
+static struct mutex mmpcam_devices_lock;
+
+static void mmpcam_add_device(struct mmp_camera *cam)
+{
+       mutex_lock(&mmpcam_devices_lock);
+       list_add(&cam->devlist, &mmpcam_devices);
+       mutex_unlock(&mmpcam_devices_lock);
+}
+
+static void mmpcam_remove_device(struct mmp_camera *cam)
+{
+       mutex_lock(&mmpcam_devices_lock);
+       list_del(&cam->devlist);
+       mutex_unlock(&mmpcam_devices_lock);
+}
+
+/*
+ * Platform dev remove passes us a platform_device, and there's
+ * no handy unused drvdata to stash a backpointer in.  So just
+ * dig it out of our list.
+ */
+static struct mmp_camera *mmpcam_find_device(struct platform_device *pdev)
+{
+       struct mmp_camera *cam;
+
+       mutex_lock(&mmpcam_devices_lock);
+       list_for_each_entry(cam, &mmpcam_devices, devlist) {
+               if (cam->pdev == pdev) {
+                       mutex_unlock(&mmpcam_devices_lock);
+                       return cam;
+               }
+       }
+       mutex_unlock(&mmpcam_devices_lock);
+       return NULL;
+}
+
+
+
+
+/*
+ * Power-related registers; this almost certainly belongs
+ * somewhere else.
+ *
+ * ARMADA 610 register manual, sec 7.2.1, p1842.
+ */
+#define CPU_SUBSYS_PMU_BASE    0xd4282800
+#define REG_CCIC_DCGCR         0x28    /* CCIC dyn clock gate ctrl reg */
+#define REG_CCIC_CRCR          0x50    /* CCIC clk reset ctrl reg      */
+
+/*
+ * Power control.
+ */
+static void mmpcam_power_up(struct mcam_camera *mcam)
+{
+       struct mmp_camera *cam = mcam_to_cam(mcam);
+       struct mmp_camera_platform_data *pdata;
+/*
+ * Turn on power and clocks to the controller.
+ */
+       iowrite32(0x3f, cam->power_regs + REG_CCIC_DCGCR);
+       iowrite32(0x3805b, cam->power_regs + REG_CCIC_CRCR);
+       mdelay(1);
+/*
+ * Provide power to the sensor.
+ */
+       mcam_reg_write(mcam, REG_CLKCTRL, 0x60000002);
+       pdata = cam->pdev->dev.platform_data;
+       gpio_set_value(pdata->sensor_power_gpio, 1);
+       mdelay(5);
+       mcam_reg_clear_bit(mcam, REG_CTRL1, 0x10000000);
+       gpio_set_value(pdata->sensor_reset_gpio, 0); /* reset is active low */
+       mdelay(5);
+       gpio_set_value(pdata->sensor_reset_gpio, 1); /* reset is active low */
+       mdelay(5);
+}
+
+static void mmpcam_power_down(struct mcam_camera *mcam)
+{
+       struct mmp_camera *cam = mcam_to_cam(mcam);
+       struct mmp_camera_platform_data *pdata;
+/*
+ * Turn off clocks and set reset lines
+ */
+       iowrite32(0, cam->power_regs + REG_CCIC_DCGCR);
+       iowrite32(0, cam->power_regs + REG_CCIC_CRCR);
+/*
+ * Shut down the sensor.
+ */
+       pdata = cam->pdev->dev.platform_data;
+       gpio_set_value(pdata->sensor_power_gpio, 0);
+       gpio_set_value(pdata->sensor_reset_gpio, 0);
+}
+
+
+static irqreturn_t mmpcam_irq(int irq, void *data)
+{
+       struct mcam_camera *mcam = data;
+       unsigned int irqs, handled;
+
+       spin_lock(&mcam->dev_lock);
+       irqs = mcam_reg_read(mcam, REG_IRQSTAT);
+       handled = mccic_irq(mcam, irqs);
+       spin_unlock(&mcam->dev_lock);
+       return IRQ_RETVAL(handled);
+}
+
+
+static int mmpcam_probe(struct platform_device *pdev)
+{
+       struct mmp_camera *cam;
+       struct mcam_camera *mcam;
+       struct resource *res;
+       struct mmp_camera_platform_data *pdata;
+       int ret;
+
+       cam = kzalloc(sizeof(*cam), GFP_KERNEL);
+       if (cam == NULL)
+               return -ENOMEM;
+       cam->pdev = pdev;
+       INIT_LIST_HEAD(&cam->devlist);
+
+       mcam = &cam->mcam;
+       mcam->platform = MHP_Armada610;
+       mcam->plat_power_up = mmpcam_power_up;
+       mcam->plat_power_down = mmpcam_power_down;
+       mcam->dev = &pdev->dev;
+       mcam->use_smbus = 0;
+       mcam->chip_id = V4L2_IDENT_ARMADA610;
+       mcam->buffer_mode = B_DMA_sg;
+       spin_lock_init(&mcam->dev_lock);
+       /*
+        * Get our I/O memory.
+        */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "no iomem resource!\n");
+               ret = -ENODEV;
+               goto out_free;
+       }
+       mcam->regs = ioremap(res->start, resource_size(res));
+       if (mcam->regs == NULL) {
+               dev_err(&pdev->dev, "MMIO ioremap fail\n");
+               ret = -ENODEV;
+               goto out_free;
+       }
+       /*
+        * Power/clock memory is elsewhere; get it too.  Perhaps this
+        * should really be managed outside of this driver?
+        */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "no power resource!\n");
+               ret = -ENODEV;
+               goto out_unmap1;
+       }
+       cam->power_regs = ioremap(res->start, resource_size(res));
+       if (cam->power_regs == NULL) {
+               dev_err(&pdev->dev, "power MMIO ioremap fail\n");
+               ret = -ENODEV;
+               goto out_unmap1;
+       }
+       /*
+        * Find the i2c adapter.  This assumes, of course, that the
+        * i2c bus is already up and functioning.
+        */
+       pdata = pdev->dev.platform_data;
+       mcam->i2c_adapter = platform_get_drvdata(pdata->i2c_device);
+       if (mcam->i2c_adapter == NULL) {
+               ret = -ENODEV;
+               dev_err(&pdev->dev, "No i2c adapter\n");
+               goto out_unmap2;
+       }
+       /*
+        * Sensor GPIO pins.
+        */
+       ret = gpio_request(pdata->sensor_power_gpio, "cam-power");
+       if (ret) {
+               dev_err(&pdev->dev, "Can't get sensor power gpio %d",
+                               pdata->sensor_power_gpio);
+               goto out_unmap2;
+       }
+       gpio_direction_output(pdata->sensor_power_gpio, 0);
+       ret = gpio_request(pdata->sensor_reset_gpio, "cam-reset");
+       if (ret) {
+               dev_err(&pdev->dev, "Can't get sensor reset gpio %d",
+                               pdata->sensor_reset_gpio);
+               goto out_gpio;
+       }
+       gpio_direction_output(pdata->sensor_reset_gpio, 0);
+       /*
+        * Power the device up and hand it off to the core.
+        */
+       mmpcam_power_up(mcam);
+       ret = mccic_register(mcam);
+       if (ret)
+               goto out_gpio2;
+       /*
+        * Finally, set up our IRQ now that the core is ready to
+        * deal with it.
+        */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (res == NULL) {
+               ret = -ENODEV;
+               goto out_unregister;
+       }
+       cam->irq = res->start;
+       ret = request_irq(cam->irq, mmpcam_irq, IRQF_SHARED,
+                       "mmp-camera", mcam);
+       if (ret == 0) {
+               mmpcam_add_device(cam);
+               return 0;
+       }
+
+out_unregister:
+       mccic_shutdown(mcam);
+out_gpio2:
+       mmpcam_power_down(mcam);
+       gpio_free(pdata->sensor_reset_gpio);
+out_gpio:
+       gpio_free(pdata->sensor_power_gpio);
+out_unmap2:
+       iounmap(cam->power_regs);
+out_unmap1:
+       iounmap(mcam->regs);
+out_free:
+       kfree(cam);
+       return ret;
+}
+
+
+static int mmpcam_remove(struct mmp_camera *cam)
+{
+       struct mcam_camera *mcam = &cam->mcam;
+       struct mmp_camera_platform_data *pdata;
+
+       mmpcam_remove_device(cam);
+       free_irq(cam->irq, mcam);
+       mccic_shutdown(mcam);
+       mmpcam_power_down(mcam);
+       pdata = cam->pdev->dev.platform_data;
+       gpio_free(pdata->sensor_reset_gpio);
+       gpio_free(pdata->sensor_power_gpio);
+       iounmap(cam->power_regs);
+       iounmap(mcam->regs);
+       kfree(cam);
+       return 0;
+}
+
+static int mmpcam_platform_remove(struct platform_device *pdev)
+{
+       struct mmp_camera *cam = mmpcam_find_device(pdev);
+
+       if (cam == NULL)
+               return -ENODEV;
+       return mmpcam_remove(cam);
+}
+
+
+static struct platform_driver mmpcam_driver = {
+       .probe          = mmpcam_probe,
+       .remove         = mmpcam_platform_remove,
+       .driver = {
+               .name   = "mmp-camera",
+               .owner  = THIS_MODULE
+       }
+};
+
+
+static int __init mmpcam_init_module(void)
+{
+       mutex_init(&mmpcam_devices_lock);
+       return platform_driver_register(&mmpcam_driver);
+}
+
+static void __exit mmpcam_exit_module(void)
+{
+       platform_driver_unregister(&mmpcam_driver);
+       /*
+        * platform_driver_unregister() should have emptied the list
+        */
+       if (!list_empty(&mmpcam_devices))
+               printk(KERN_ERR "mmp_camera leaving devices behind\n");
+}
+
+module_init(mmpcam_init_module);
+module_exit(mmpcam_exit_module);
index b03d74e..166bf93 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/fs.h>
-#include <linux/version.h>
 #include <linux/timer.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
@@ -35,7 +34,7 @@
 MODULE_DESCRIPTION("Virtual device for mem2mem framework testing");
 MODULE_AUTHOR("Pawel Osciak, <pawel@osciak.com>");
 MODULE_LICENSE("GPL");
-
+MODULE_VERSION("0.1.1");
 
 #define MIN_W 32
 #define MIN_H 32
@@ -380,7 +379,6 @@ static int vidioc_querycap(struct file *file, void *priv,
        strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1);
        strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
        cap->bus_info[0] = 0;
-       cap->version = KERNEL_VERSION(0, 1, 0);
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT
                          | V4L2_CAP_STREAMING;
 
index e2bbd8c..4da9cca 100644 (file)
@@ -603,13 +603,9 @@ static int mt9m001_video_probe(struct soc_camera_device *icd,
        unsigned long flags;
        int ret;
 
-       /*
-        * We must have a parent by now. And it cannot be a wrong one.
-        * So this entire test is completely redundant.
-        */
-       if (!icd->dev.parent ||
-           to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
-               return -ENODEV;
+       /* We must have a parent by now. And it cannot be a wrong one. */
+       BUG_ON(!icd->parent ||
+              to_soc_camera_host(icd->parent)->nr != icd->iface);
 
        /* Enable the chip */
        data = reg_write(client, MT9M001_CHIP_ENABLE, 1);
@@ -675,8 +671,8 @@ static void mt9m001_video_remove(struct soc_camera_device *icd)
 {
        struct soc_camera_link *icl = to_soc_camera_link(icd);
 
-       dev_dbg(&icd->dev, "Video removed: %p, %p\n",
-               icd->dev.parent, icd->vdev);
+       dev_dbg(icd->pdev, "Video removed: %p, %p\n",
+               icd->parent, icd->vdev);
        if (icl->free_bus)
                icl->free_bus(icl);
 }
index ebebed9..a357aa8 100644 (file)
 #define MT9M111_RESET_RESTART_FRAME    (1 << 1)
 #define MT9M111_RESET_RESET_MODE       (1 << 0)
 
+#define MT9M111_RM_FULL_POWER_RD       (0 << 10)
+#define MT9M111_RM_LOW_POWER_RD                (1 << 10)
+#define MT9M111_RM_COL_SKIP_4X         (1 << 5)
+#define MT9M111_RM_ROW_SKIP_4X         (1 << 4)
+#define MT9M111_RM_COL_SKIP_2X         (1 << 3)
+#define MT9M111_RM_ROW_SKIP_2X         (1 << 2)
 #define MT9M111_RMB_MIRROR_COLS                (1 << 1)
 #define MT9M111_RMB_MIRROR_ROWS                (1 << 0)
 #define MT9M111_CTXT_CTRL_RESTART      (1 << 15)
 
 #define MT9M111_OPMODE_AUTOEXPO_EN     (1 << 14)
 #define MT9M111_OPMODE_AUTOWHITEBAL_EN (1 << 1)
-
+#define MT9M111_OUTFMT_FLIP_BAYER_COL  (1 << 9)
+#define MT9M111_OUTFMT_FLIP_BAYER_ROW  (1 << 8)
 #define MT9M111_OUTFMT_PROCESSED_BAYER (1 << 14)
 #define MT9M111_OUTFMT_BYPASS_IFP      (1 << 10)
 #define MT9M111_OUTFMT_INV_PIX_CLOCK   (1 << 9)
 #define MT9M111_OUTFMT_TST_RAMP_FRAME  (3 << 4)
 #define MT9M111_OUTFMT_SHIFT_3_UP      (1 << 3)
 #define MT9M111_OUTFMT_AVG_CHROMA      (1 << 2)
-#define MT9M111_OUTFMT_SWAP_YCbCr_C_Y  (1 << 1)
-#define MT9M111_OUTFMT_SWAP_RGB_EVEN   (1 << 1)
-#define MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr        (1 << 0)
+#define MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN (1 << 1)
+#define MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B        (1 << 0)
 
 /*
  * Camera control register addresses (0x200..0x2ff not implemented)
 #define reg_write(reg, val) mt9m111_reg_write(client, MT9M111_##reg, (val))
 #define reg_set(reg, val) mt9m111_reg_set(client, MT9M111_##reg, (val))
 #define reg_clear(reg, val) mt9m111_reg_clear(client, MT9M111_##reg, (val))
+#define reg_mask(reg, val, mask) mt9m111_reg_mask(client, MT9M111_##reg, \
+               (val), (mask))
 
 #define MT9M111_MIN_DARK_ROWS  8
 #define MT9M111_MIN_DARK_COLS  26
@@ -153,7 +161,11 @@ static const struct mt9m111_datafmt mt9m111_colour_fmts[] = {
        {V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG},
        {V4L2_MBUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_JPEG},
        {V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
+       {V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE, V4L2_COLORSPACE_SRGB},
        {V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
+       {V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB},
+       {V4L2_MBUS_FMT_BGR565_2X8_LE, V4L2_COLORSPACE_SRGB},
+       {V4L2_MBUS_FMT_BGR565_2X8_BE, V4L2_COLORSPACE_SRGB},
        {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
        {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
 };
@@ -169,6 +181,8 @@ struct mt9m111 {
                         * from v4l2-chip-ident.h */
        enum mt9m111_context context;
        struct v4l2_rect rect;
+       struct mutex power_lock; /* lock to protect power_count */
+       int power_count;
        const struct mt9m111_datafmt *fmt;
        unsigned int gain;
        unsigned char autoexposure;
@@ -176,10 +190,6 @@ struct mt9m111 {
        unsigned int powered:1;
        unsigned int hflip:1;
        unsigned int vflip:1;
-       unsigned int swap_rgb_even_odd:1;
-       unsigned int swap_rgb_red_blue:1;
-       unsigned int swap_yuv_y_chromas:1;
-       unsigned int swap_yuv_cb_cr:1;
        unsigned int autowhitebalance:1;
 };
 
@@ -248,12 +258,26 @@ static int mt9m111_reg_clear(struct i2c_client *client, const u16 reg,
        int ret;
 
        ret = mt9m111_reg_read(client, reg);
-       return mt9m111_reg_write(client, reg, ret & ~data);
+       if (ret >= 0)
+               ret = mt9m111_reg_write(client, reg, ret & ~data);
+       return ret;
 }
 
-static int mt9m111_set_context(struct i2c_client *client,
+static int mt9m111_reg_mask(struct i2c_client *client, const u16 reg,
+                           const u16 data, const u16 mask)
+{
+       int ret;
+
+       ret = mt9m111_reg_read(client, reg);
+       if (ret >= 0)
+               ret = mt9m111_reg_write(client, reg, (ret & ~mask) | data);
+       return ret;
+}
+
+static int mt9m111_set_context(struct mt9m111 *mt9m111,
                               enum mt9m111_context ctxt)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
        int valB = MT9M111_CTXT_CTRL_RESTART | MT9M111_CTXT_CTRL_DEFECTCOR_B
                | MT9M111_CTXT_CTRL_RESIZE_B | MT9M111_CTXT_CTRL_CTRL2_B
                | MT9M111_CTXT_CTRL_GAMMA_B | MT9M111_CTXT_CTRL_READ_MODE_B
@@ -267,10 +291,10 @@ static int mt9m111_set_context(struct i2c_client *client,
                return reg_write(CONTEXT_CONTROL, valA);
 }
 
-static int mt9m111_setup_rect(struct i2c_client *client,
+static int mt9m111_setup_rect(struct mt9m111 *mt9m111,
                              struct v4l2_rect *rect)
 {
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
        int ret, is_raw_format;
        int width = rect->width;
        int height = rect->height;
@@ -312,81 +336,9 @@ static int mt9m111_setup_rect(struct i2c_client *client,
        return ret;
 }
 
-static int mt9m111_setup_pixfmt(struct i2c_client *client, u16 outfmt)
+static int mt9m111_enable(struct mt9m111 *mt9m111)
 {
-       int ret;
-       u16 mask = MT9M111_OUTFMT_PROCESSED_BAYER | MT9M111_OUTFMT_RGB |
-               MT9M111_OUTFMT_BYPASS_IFP | MT9M111_OUTFMT_SWAP_RGB_EVEN |
-               MT9M111_OUTFMT_RGB565 | MT9M111_OUTFMT_RGB555 |
-               MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr |
-               MT9M111_OUTFMT_SWAP_YCbCr_C_Y;
-
-       ret = reg_read(OUTPUT_FORMAT_CTRL2_A);
-       if (ret >= 0)
-               ret = reg_write(OUTPUT_FORMAT_CTRL2_A, (ret & ~mask) | outfmt);
-       if (!ret)
-               ret = reg_read(OUTPUT_FORMAT_CTRL2_B);
-       if (ret >= 0)
-               ret = reg_write(OUTPUT_FORMAT_CTRL2_B, (ret & ~mask) | outfmt);
-
-       return ret;
-}
-
-static int mt9m111_setfmt_bayer8(struct i2c_client *client)
-{
-       return mt9m111_setup_pixfmt(client, MT9M111_OUTFMT_PROCESSED_BAYER |
-                                   MT9M111_OUTFMT_RGB);
-}
-
-static int mt9m111_setfmt_bayer10(struct i2c_client *client)
-{
-       return mt9m111_setup_pixfmt(client, MT9M111_OUTFMT_BYPASS_IFP);
-}
-
-static int mt9m111_setfmt_rgb565(struct i2c_client *client)
-{
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
-       int val = 0;
-
-       if (mt9m111->swap_rgb_red_blue)
-               val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr;
-       if (mt9m111->swap_rgb_even_odd)
-               val |= MT9M111_OUTFMT_SWAP_RGB_EVEN;
-       val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565;
-
-       return mt9m111_setup_pixfmt(client, val);
-}
-
-static int mt9m111_setfmt_rgb555(struct i2c_client *client)
-{
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
-       int val = 0;
-
-       if (mt9m111->swap_rgb_red_blue)
-               val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr;
-       if (mt9m111->swap_rgb_even_odd)
-               val |= MT9M111_OUTFMT_SWAP_RGB_EVEN;
-       val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555;
-
-       return mt9m111_setup_pixfmt(client, val);
-}
-
-static int mt9m111_setfmt_yuv(struct i2c_client *client)
-{
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
-       int val = 0;
-
-       if (mt9m111->swap_yuv_cb_cr)
-               val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr;
-       if (mt9m111->swap_yuv_y_chromas)
-               val |= MT9M111_OUTFMT_SWAP_YCbCr_C_Y;
-
-       return mt9m111_setup_pixfmt(client, val);
-}
-
-static int mt9m111_enable(struct i2c_client *client)
-{
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
        int ret;
 
        ret = reg_set(RESET, MT9M111_RESET_CHIP_ENABLE);
@@ -395,8 +347,9 @@ static int mt9m111_enable(struct i2c_client *client)
        return ret;
 }
 
-static int mt9m111_reset(struct i2c_client *client)
+static int mt9m111_reset(struct mt9m111 *mt9m111)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
        int ret;
 
        ret = reg_set(RESET, MT9M111_RESET_RESET_MODE);
@@ -424,11 +377,9 @@ static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f)
        return 0;
 }
 
-static int mt9m111_make_rect(struct i2c_client *client,
+static int mt9m111_make_rect(struct mt9m111 *mt9m111,
                             struct v4l2_rect *rect)
 {
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
-
        if (mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
            mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) {
                /* Bayer format - even size lengths */
@@ -444,14 +395,14 @@ static int mt9m111_make_rect(struct i2c_client *client,
        soc_camera_limit_side(&rect->top, &rect->height,
                     MT9M111_MIN_DARK_ROWS, 2, MT9M111_MAX_HEIGHT);
 
-       return mt9m111_setup_rect(client, rect);
+       return mt9m111_setup_rect(mt9m111, rect);
 }
 
 static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
        struct v4l2_rect rect = a->c;
        struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
        int ret;
 
        dev_dbg(&client->dev, "%s left=%d, top=%d, width=%d, height=%d\n",
@@ -460,7 +411,7 @@ static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
        if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
-       ret = mt9m111_make_rect(client, &rect);
+       ret = mt9m111_make_rect(mt9m111, &rect);
        if (!ret)
                mt9m111->rect = rect;
        return ret;
@@ -468,8 +419,7 @@ static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 
 static int mt9m111_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
 
        a->c    = mt9m111->rect;
        a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -496,8 +446,7 @@ static int mt9m111_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
 static int mt9m111_g_fmt(struct v4l2_subdev *sd,
                         struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
 
        mf->width       = mt9m111->rect.width;
        mf->height      = mt9m111->rect.height;
@@ -508,51 +457,73 @@ static int mt9m111_g_fmt(struct v4l2_subdev *sd,
        return 0;
 }
 
-static int mt9m111_set_pixfmt(struct i2c_client *client,
+static int mt9m111_set_pixfmt(struct mt9m111 *mt9m111,
                              enum v4l2_mbus_pixelcode code)
 {
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+       u16 data_outfmt2, mask_outfmt2 = MT9M111_OUTFMT_PROCESSED_BAYER |
+               MT9M111_OUTFMT_BYPASS_IFP | MT9M111_OUTFMT_RGB |
+               MT9M111_OUTFMT_RGB565 | MT9M111_OUTFMT_RGB555 |
+               MT9M111_OUTFMT_RGB444x | MT9M111_OUTFMT_RGBx444 |
+               MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN |
+               MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
        int ret;
 
        switch (code) {
        case V4L2_MBUS_FMT_SBGGR8_1X8:
-               ret = mt9m111_setfmt_bayer8(client);
+               data_outfmt2 = MT9M111_OUTFMT_PROCESSED_BAYER |
+                       MT9M111_OUTFMT_RGB;
                break;
        case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE:
-               ret = mt9m111_setfmt_bayer10(client);
+               data_outfmt2 = MT9M111_OUTFMT_BYPASS_IFP | MT9M111_OUTFMT_RGB;
                break;
        case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
-               ret = mt9m111_setfmt_rgb555(client);
+               data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555 |
+                       MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN;
+               break;
+       case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
+               data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555;
                break;
        case V4L2_MBUS_FMT_RGB565_2X8_LE:
-               ret = mt9m111_setfmt_rgb565(client);
+               data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 |
+                       MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN;
+               break;
+       case V4L2_MBUS_FMT_RGB565_2X8_BE:
+               data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565;
+               break;
+       case V4L2_MBUS_FMT_BGR565_2X8_BE:
+               data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 |
+                       MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
+               break;
+       case V4L2_MBUS_FMT_BGR565_2X8_LE:
+               data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 |
+                       MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN |
+                       MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
                break;
        case V4L2_MBUS_FMT_UYVY8_2X8:
-               mt9m111->swap_yuv_y_chromas = 0;
-               mt9m111->swap_yuv_cb_cr = 0;
-               ret = mt9m111_setfmt_yuv(client);
+               data_outfmt2 = 0;
                break;
        case V4L2_MBUS_FMT_VYUY8_2X8:
-               mt9m111->swap_yuv_y_chromas = 0;
-               mt9m111->swap_yuv_cb_cr = 1;
-               ret = mt9m111_setfmt_yuv(client);
+               data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
                break;
        case V4L2_MBUS_FMT_YUYV8_2X8:
-               mt9m111->swap_yuv_y_chromas = 1;
-               mt9m111->swap_yuv_cb_cr = 0;
-               ret = mt9m111_setfmt_yuv(client);
+               data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN;
                break;
        case V4L2_MBUS_FMT_YVYU8_2X8:
-               mt9m111->swap_yuv_y_chromas = 1;
-               mt9m111->swap_yuv_cb_cr = 1;
-               ret = mt9m111_setfmt_yuv(client);
+               data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN |
+                       MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
                break;
        default:
-               dev_err(&client->dev, "Pixel format not handled : %x\n",
-                       code);
-               ret = -EINVAL;
+               dev_err(&client->dev, "Pixel format not handled: %x\n", code);
+               return -EINVAL;
        }
 
+       ret = reg_mask(OUTPUT_FORMAT_CTRL2_A, data_outfmt2,
+                      mask_outfmt2);
+       if (!ret)
+               ret = reg_mask(OUTPUT_FORMAT_CTRL2_B, data_outfmt2,
+                              mask_outfmt2);
+
        return ret;
 }
 
@@ -561,7 +532,7 @@ static int mt9m111_s_fmt(struct v4l2_subdev *sd,
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        const struct mt9m111_datafmt *fmt;
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
        struct v4l2_rect rect = {
                .left   = mt9m111->rect.left,
                .top    = mt9m111->rect.top,
@@ -579,9 +550,9 @@ static int mt9m111_s_fmt(struct v4l2_subdev *sd,
                "%s code=%x left=%d, top=%d, width=%d, height=%d\n", __func__,
                mf->code, rect.left, rect.top, rect.width, rect.height);
 
-       ret = mt9m111_make_rect(client, &rect);
+       ret = mt9m111_make_rect(mt9m111, &rect);
        if (!ret)
-               ret = mt9m111_set_pixfmt(client, mf->code);
+               ret = mt9m111_set_pixfmt(mt9m111, mf->code);
        if (!ret) {
                mt9m111->rect   = rect;
                mt9m111->fmt    = fmt;
@@ -594,8 +565,7 @@ static int mt9m111_s_fmt(struct v4l2_subdev *sd,
 static int mt9m111_try_fmt(struct v4l2_subdev *sd,
                           struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
        const struct mt9m111_datafmt *fmt;
        bool bayer = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
                mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE;
@@ -635,7 +605,7 @@ static int mt9m111_g_chip_ident(struct v4l2_subdev *sd,
                                struct v4l2_dbg_chip_ident *id)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
 
        if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
                return -EINVAL;
@@ -726,21 +696,16 @@ static const struct v4l2_queryctrl mt9m111_controls[] = {
        }
 };
 
-static int mt9m111_resume(struct soc_camera_device *icd);
-static int mt9m111_suspend(struct soc_camera_device *icd, pm_message_t state);
-
 static struct soc_camera_ops mt9m111_ops = {
-       .suspend                = mt9m111_suspend,
-       .resume                 = mt9m111_resume,
        .query_bus_param        = mt9m111_query_bus_param,
        .set_bus_param          = mt9m111_set_bus_param,
        .controls               = mt9m111_controls,
        .num_controls           = ARRAY_SIZE(mt9m111_controls),
 };
 
-static int mt9m111_set_flip(struct i2c_client *client, int flip, int mask)
+static int mt9m111_set_flip(struct mt9m111 *mt9m111, int flip, int mask)
 {
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
        int ret;
 
        if (mt9m111->context == HIGHPOWER) {
@@ -758,8 +723,9 @@ static int mt9m111_set_flip(struct i2c_client *client, int flip, int mask)
        return ret;
 }
 
-static int mt9m111_get_global_gain(struct i2c_client *client)
+static int mt9m111_get_global_gain(struct mt9m111 *mt9m111)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
        int data;
 
        data = reg_read(GLOBAL_GAIN);
@@ -769,9 +735,9 @@ static int mt9m111_get_global_gain(struct i2c_client *client)
        return data;
 }
 
-static int mt9m111_set_global_gain(struct i2c_client *client, int gain)
+static int mt9m111_set_global_gain(struct mt9m111 *mt9m111, int gain)
 {
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
        u16 val;
 
        if (gain > 63 * 2 * 2)
@@ -788,9 +754,9 @@ static int mt9m111_set_global_gain(struct i2c_client *client, int gain)
        return reg_write(GLOBAL_GAIN, val);
 }
 
-static int mt9m111_set_autoexposure(struct i2c_client *client, int on)
+static int mt9m111_set_autoexposure(struct mt9m111 *mt9m111, int on)
 {
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
        int ret;
 
        if (on)
@@ -804,9 +770,9 @@ static int mt9m111_set_autoexposure(struct i2c_client *client, int on)
        return ret;
 }
 
-static int mt9m111_set_autowhitebalance(struct i2c_client *client, int on)
+static int mt9m111_set_autowhitebalance(struct mt9m111 *mt9m111, int on)
 {
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
        int ret;
 
        if (on)
@@ -823,7 +789,7 @@ static int mt9m111_set_autowhitebalance(struct i2c_client *client, int on)
 static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
        int data;
 
        switch (ctrl->id) {
@@ -848,7 +814,7 @@ static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
                ctrl->value = !!(data & MT9M111_RMB_MIRROR_COLS);
                break;
        case V4L2_CID_GAIN:
-               data = mt9m111_get_global_gain(client);
+               data = mt9m111_get_global_gain(mt9m111);
                if (data < 0)
                        return data;
                ctrl->value = data;
@@ -865,8 +831,7 @@ static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 
 static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
        const struct v4l2_queryctrl *qctrl;
        int ret;
 
@@ -877,22 +842,22 @@ static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
        switch (ctrl->id) {
        case V4L2_CID_VFLIP:
                mt9m111->vflip = ctrl->value;
-               ret = mt9m111_set_flip(client, ctrl->value,
+               ret = mt9m111_set_flip(mt9m111, ctrl->value,
                                        MT9M111_RMB_MIRROR_ROWS);
                break;
        case V4L2_CID_HFLIP:
                mt9m111->hflip = ctrl->value;
-               ret = mt9m111_set_flip(client, ctrl->value,
+               ret = mt9m111_set_flip(mt9m111, ctrl->value,
                                        MT9M111_RMB_MIRROR_COLS);
                break;
        case V4L2_CID_GAIN:
-               ret = mt9m111_set_global_gain(client, ctrl->value);
+               ret = mt9m111_set_global_gain(mt9m111, ctrl->value);
                break;
        case V4L2_CID_EXPOSURE_AUTO:
-               ret =  mt9m111_set_autoexposure(client, ctrl->value);
+               ret =  mt9m111_set_autoexposure(mt9m111, ctrl->value);
                break;
        case V4L2_CID_AUTO_WHITE_BALANCE:
-               ret =  mt9m111_set_autowhitebalance(client, ctrl->value);
+               ret =  mt9m111_set_autowhitebalance(mt9m111, ctrl->value);
                break;
        default:
                ret = -EINVAL;
@@ -901,60 +866,52 @@ static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
        return ret;
 }
 
-static int mt9m111_suspend(struct soc_camera_device *icd, pm_message_t state)
+static int mt9m111_suspend(struct mt9m111 *mt9m111)
 {
-       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
-
-       mt9m111->gain = mt9m111_get_global_gain(client);
+       mt9m111->gain = mt9m111_get_global_gain(mt9m111);
 
        return 0;
 }
 
-static int mt9m111_restore_state(struct i2c_client *client)
+static void mt9m111_restore_state(struct mt9m111 *mt9m111)
 {
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
-
-       mt9m111_set_context(client, mt9m111->context);
-       mt9m111_set_pixfmt(client, mt9m111->fmt->code);
-       mt9m111_setup_rect(client, &mt9m111->rect);
-       mt9m111_set_flip(client, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS);
-       mt9m111_set_flip(client, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS);
-       mt9m111_set_global_gain(client, mt9m111->gain);
-       mt9m111_set_autoexposure(client, mt9m111->autoexposure);
-       mt9m111_set_autowhitebalance(client, mt9m111->autowhitebalance);
-       return 0;
+       mt9m111_set_context(mt9m111, mt9m111->context);
+       mt9m111_set_pixfmt(mt9m111, mt9m111->fmt->code);
+       mt9m111_setup_rect(mt9m111, &mt9m111->rect);
+       mt9m111_set_flip(mt9m111, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS);
+       mt9m111_set_flip(mt9m111, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS);
+       mt9m111_set_global_gain(mt9m111, mt9m111->gain);
+       mt9m111_set_autoexposure(mt9m111, mt9m111->autoexposure);
+       mt9m111_set_autowhitebalance(mt9m111, mt9m111->autowhitebalance);
 }
 
-static int mt9m111_resume(struct soc_camera_device *icd)
+static int mt9m111_resume(struct mt9m111 *mt9m111)
 {
-       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
        int ret = 0;
 
        if (mt9m111->powered) {
-               ret = mt9m111_enable(client);
+               ret = mt9m111_enable(mt9m111);
                if (!ret)
-                       ret = mt9m111_reset(client);
+                       ret = mt9m111_reset(mt9m111);
                if (!ret)
-                       ret = mt9m111_restore_state(client);
+                       mt9m111_restore_state(mt9m111);
        }
        return ret;
 }
 
-static int mt9m111_init(struct i2c_client *client)
+static int mt9m111_init(struct mt9m111 *mt9m111)
 {
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
        int ret;
 
        mt9m111->context = HIGHPOWER;
-       ret = mt9m111_enable(client);
+       ret = mt9m111_enable(mt9m111);
        if (!ret)
-               ret = mt9m111_reset(client);
+               ret = mt9m111_reset(mt9m111);
        if (!ret)
-               ret = mt9m111_set_context(client, mt9m111->context);
+               ret = mt9m111_set_context(mt9m111, mt9m111->context);
        if (!ret)
-               ret = mt9m111_set_autoexposure(client, mt9m111->autoexposure);
+               ret = mt9m111_set_autoexposure(mt9m111, mt9m111->autoexposure);
        if (ret)
                dev_err(&client->dev, "mt9m111 init failed: %d\n", ret);
        return ret;
@@ -971,20 +928,13 @@ static int mt9m111_video_probe(struct soc_camera_device *icd,
        s32 data;
        int ret;
 
-       /*
-        * We must have a parent by now. And it cannot be a wrong one.
-        * So this entire test is completely redundant.
-        */
-       if (!icd->dev.parent ||
-           to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
-               return -ENODEV;
+       /* We must have a parent by now. And it cannot be a wrong one. */
+       BUG_ON(!icd->parent ||
+              to_soc_camera_host(icd->parent)->nr != icd->iface);
 
        mt9m111->autoexposure = 1;
        mt9m111->autowhitebalance = 1;
 
-       mt9m111->swap_rgb_even_odd = 1;
-       mt9m111->swap_rgb_red_blue = 1;
-
        data = reg_read(CHIP_VERSION);
 
        switch (data) {
@@ -1005,16 +955,51 @@ static int mt9m111_video_probe(struct soc_camera_device *icd,
                goto ei2c;
        }
 
-       ret = mt9m111_init(client);
+       ret = mt9m111_init(mt9m111);
 
 ei2c:
        return ret;
 }
 
+static int mt9m111_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret = 0;
+
+       mutex_lock(&mt9m111->power_lock);
+
+       /*
+        * If the power count is modified from 0 to != 0 or from != 0 to 0,
+        * update the power state.
+        */
+       if (mt9m111->power_count == !on) {
+               if (on) {
+                       ret = mt9m111_resume(mt9m111);
+                       if (ret) {
+                               dev_err(&client->dev,
+                                       "Failed to resume the sensor: %d\n", ret);
+                               goto out;
+                       }
+               } else {
+                       mt9m111_suspend(mt9m111);
+               }
+       }
+
+       /* Update the power count. */
+       mt9m111->power_count += on ? 1 : -1;
+       WARN_ON(mt9m111->power_count < 0);
+
+out:
+       mutex_unlock(&mt9m111->power_lock);
+       return ret;
+}
+
 static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = {
        .g_ctrl         = mt9m111_g_ctrl,
        .s_ctrl         = mt9m111_s_ctrl,
        .g_chip_ident   = mt9m111_g_chip_ident,
+       .s_power        = mt9m111_s_power,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register     = mt9m111_g_register,
        .s_register     = mt9m111_s_register,
index 7ce279c..30547cc 100644 (file)
@@ -700,8 +700,7 @@ static int mt9t031_runtime_suspend(struct device *dev)
 static int mt9t031_runtime_resume(struct device *dev)
 {
        struct video_device *vdev = to_video_device(dev);
-       struct soc_camera_device *icd = container_of(vdev->parent,
-               struct soc_camera_device, dev);
+       struct soc_camera_device *icd = dev_get_drvdata(vdev->parent);
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9t031 *mt9t031 = to_mt9t031(client);
index bffa9ee..d2e0a50 100644 (file)
@@ -1057,13 +1057,9 @@ static int mt9t112_camera_probe(struct soc_camera_device *icd,
        const char          *devname;
        int                  chipid;
 
-       /*
-        * We must have a parent by now. And it cannot be a wrong one.
-        * So this entire test is completely redundant.
-        */
-       if (!icd->dev.parent ||
-           to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
-               return -ENODEV;
+       /* We must have a parent by now. And it cannot be a wrong one. */
+       BUG_ON(!icd->parent ||
+              to_soc_camera_host(icd->parent)->nr != icd->iface);
 
        /*
         * check and show chip ID
index 4904d25..893a8b8 100644 (file)
@@ -54,10 +54,19 @@ static struct v4l2_queryctrl mt9v011_qctrl[] = {
                .type = V4L2_CTRL_TYPE_INTEGER,
                .name = "Gain",
                .minimum = 0,
-               .maximum = (1 << 10) - 1,
+               .maximum = (1 << 12) - 1 - 0x0020,
                .step = 1,
                .default_value = 0x0020,
                .flags = 0,
+       }, {
+               .id = V4L2_CID_EXPOSURE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Exposure",
+               .minimum = 0,
+               .maximum = 2047,
+               .step = 1,
+               .default_value = 0x01fc,
+               .flags = 0,
        }, {
                .id = V4L2_CID_RED_BALANCE,
                .type = V4L2_CTRL_TYPE_INTEGER,
@@ -105,7 +114,8 @@ struct mt9v011 {
        unsigned hflip:1;
        unsigned vflip:1;
 
-       u16 global_gain, red_bal, blue_bal;
+       u16 global_gain, exposure;
+       s16 red_bal, blue_bal;
 };
 
 static inline struct mt9v011 *to_mt9v011(struct v4l2_subdev *sd)
@@ -180,24 +190,68 @@ static const struct i2c_reg_value mt9v011_init_default[] = {
                { R07_MT9V011_OUT_CTRL, 0x0002 },       /* chip enable */
 };
 
+
+static u16 calc_mt9v011_gain(s16 lineargain)
+{
+
+       u16 digitalgain = 0;
+       u16 analogmult = 0;
+       u16 analoginit = 0;
+
+       if (lineargain < 0)
+               lineargain = 0;
+
+       /* recommended minimum */
+       lineargain += 0x0020;
+
+       if (lineargain > 2047)
+               lineargain = 2047;
+
+       if (lineargain > 1023) {
+               digitalgain = 3;
+               analogmult = 3;
+               analoginit = lineargain / 16;
+       } else if (lineargain > 511) {
+               digitalgain = 1;
+               analogmult = 3;
+               analoginit = lineargain / 8;
+       } else if (lineargain > 255) {
+               analogmult = 3;
+               analoginit = lineargain / 4;
+       } else if (lineargain > 127) {
+               analogmult = 1;
+               analoginit = lineargain / 2;
+       } else
+               analoginit = lineargain;
+
+       return analoginit + (analogmult << 7) + (digitalgain << 9);
+
+}
+
 static void set_balance(struct v4l2_subdev *sd)
 {
        struct mt9v011 *core = to_mt9v011(sd);
-       u16 green1_gain, green2_gain, blue_gain, red_gain;
+       u16 green_gain, blue_gain, red_gain;
+       u16 exposure;
+       s16 bal;
 
-       green1_gain = core->global_gain;
-       green2_gain = core->global_gain;
+       exposure = core->exposure;
 
-       blue_gain = core->global_gain +
-                   core->global_gain * core->blue_bal / (1 << 9);
+       green_gain = calc_mt9v011_gain(core->global_gain);
 
-       red_gain = core->global_gain +
-                  core->global_gain * core->blue_bal / (1 << 9);
+       bal = core->global_gain;
+       bal += (core->blue_bal * core->global_gain / (1 << 7));
+       blue_gain = calc_mt9v011_gain(bal);
 
-       mt9v011_write(sd, R2B_MT9V011_GREEN_1_GAIN, green1_gain);
-       mt9v011_write(sd, R2E_MT9V011_GREEN_2_GAIN,  green1_gain);
+       bal = core->global_gain;
+       bal += (core->red_bal * core->global_gain / (1 << 7));
+       red_gain = calc_mt9v011_gain(bal);
+
+       mt9v011_write(sd, R2B_MT9V011_GREEN_1_GAIN, green_gain);
+       mt9v011_write(sd, R2E_MT9V011_GREEN_2_GAIN, green_gain);
        mt9v011_write(sd, R2C_MT9V011_BLUE_GAIN, blue_gain);
        mt9v011_write(sd, R2D_MT9V011_RED_GAIN, red_gain);
+       mt9v011_write(sd, R09_MT9V011_SHUTTER_WIDTH, exposure);
 }
 
 static void calc_fps(struct v4l2_subdev *sd, u32 *numerator, u32 *denominator)
@@ -286,7 +340,7 @@ static void set_res(struct v4l2_subdev *sd)
         * be missing.
         */
 
-       hstart = 14 + (640 - core->width) / 2;
+       hstart = 20 + (640 - core->width) / 2;
        mt9v011_write(sd, R02_MT9V011_COLSTART, hstart);
        mt9v011_write(sd, R04_MT9V011_WIDTH, core->width);
        mt9v011_write(sd, R05_MT9V011_HBLANK, 771 - core->width);
@@ -338,6 +392,9 @@ static int mt9v011_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
        case V4L2_CID_GAIN:
                ctrl->value = core->global_gain;
                return 0;
+       case V4L2_CID_EXPOSURE:
+               ctrl->value = core->exposure;
+               return 0;
        case V4L2_CID_RED_BALANCE:
                ctrl->value = core->red_bal;
                return 0;
@@ -392,6 +449,9 @@ static int mt9v011_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
        case V4L2_CID_GAIN:
                core->global_gain = ctrl->value;
                break;
+       case V4L2_CID_EXPOSURE:
+               core->exposure = ctrl->value;
+               break;
        case V4L2_CID_RED_BALANCE:
                core->red_bal = ctrl->value;
                break;
@@ -598,6 +658,7 @@ static int mt9v011_probe(struct i2c_client *c,
        }
 
        core->global_gain = 0x0024;
+       core->exposure = 0x01fc;
        core->width  = 640;
        core->height = 480;
        core->xtal = 27000000;  /* Hz */
index fc76ed1..51b0fcc 100644 (file)
@@ -728,9 +728,9 @@ static int mt9v022_video_probe(struct soc_camera_device *icd,
        int ret;
        unsigned long flags;
 
-       if (!icd->dev.parent ||
-           to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
-               return -ENODEV;
+       /* We must have a parent by now. And it cannot be a wrong one. */
+       BUG_ON(!icd->parent ||
+              to_soc_camera_host(icd->parent)->nr != icd->iface);
 
        /* Read out the chip version register */
        data = reg_read(client, MT9V022_CHIP_VERSION);
@@ -809,8 +809,8 @@ static void mt9v022_video_remove(struct soc_camera_device *icd)
 {
        struct soc_camera_link *icl = to_soc_camera_link(icd);
 
-       dev_dbg(&icd->dev, "Video removed: %p, %p\n",
-               icd->dev.parent, icd->vdev);
+       dev_dbg(icd->pdev, "Video removed: %p, %p\n",
+               icd->parent, icd->vdev);
        if (icl->free_bus)
                icl->free_bus(icl);
 }
index 1319c2c..c64e1dc 100644 (file)
 #define MT9V032_CHIP_VERSION                           0x00
 #define                MT9V032_CHIP_ID_REV1                    0x1311
 #define                MT9V032_CHIP_ID_REV3                    0x1313
-#define MT9V032_ROW_START                              0x01
-#define                MT9V032_ROW_START_MIN                   4
-#define                MT9V032_ROW_START_DEF                   10
-#define                MT9V032_ROW_START_MAX                   482
-#define MT9V032_COLUMN_START                           0x02
+#define MT9V032_COLUMN_START                           0x01
 #define                MT9V032_COLUMN_START_MIN                1
-#define                MT9V032_COLUMN_START_DEF                2
+#define                MT9V032_COLUMN_START_DEF                1
 #define                MT9V032_COLUMN_START_MAX                752
+#define MT9V032_ROW_START                              0x02
+#define                MT9V032_ROW_START_MIN                   4
+#define                MT9V032_ROW_START_DEF                   5
+#define                MT9V032_ROW_START_MAX                   482
 #define MT9V032_WINDOW_HEIGHT                          0x03
 #define                MT9V032_WINDOW_HEIGHT_MIN               1
 #define                MT9V032_WINDOW_HEIGHT_DEF               480
@@ -420,13 +420,13 @@ static int mt9v032_set_crop(struct v4l2_subdev *subdev,
        struct v4l2_rect *__crop;
        struct v4l2_rect rect;
 
-       /* Clamp the crop rectangle boundaries and align them to a multiple of 2
-        * pixels.
+       /* Clamp the crop rectangle boundaries and align them to a non multiple
+        * of 2 pixels to ensure a GRBG Bayer pattern.
         */
-       rect.left = clamp(ALIGN(crop->rect.left, 2),
+       rect.left = clamp(ALIGN(crop->rect.left + 1, 2) - 1,
                          MT9V032_COLUMN_START_MIN,
                          MT9V032_COLUMN_START_MAX);
-       rect.top = clamp(ALIGN(crop->rect.top, 2),
+       rect.top = clamp(ALIGN(crop->rect.top + 1, 2) - 1,
                         MT9V032_ROW_START_MIN,
                         MT9V032_ROW_START_MAX);
        rect.width = clamp(ALIGN(crop->rect.width, 2),
index 63f8a0c..087db12 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/time.h>
-#include <linux/version.h>
 #include <linux/videodev2.h>
 
 #include <media/soc_camera.h>
@@ -73,7 +72,7 @@
 #define CSISR_SOF_INT          (1 << 16)
 #define CSISR_DRDY             (1 << 0)
 
-#define VERSION_CODE KERNEL_VERSION(0, 0, 1)
+#define DRIVER_VERSION "0.0.2"
 #define DRIVER_NAME "mx1-camera"
 
 #define CSI_IRQ_MASK   (CSISR_SFF_OR_INT | CSISR_RFF_OR_INT | \
@@ -142,7 +141,7 @@ static int mx1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
        if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024)
                *count = (MAX_VIDEO_MEM * 1024 * 1024) / *size;
 
-       dev_dbg(icd->dev.parent, "count=%d, size=%d\n", *count, *size);
+       dev_dbg(icd->parent, "count=%d, size=%d\n", *count, *size);
 
        return 0;
 }
@@ -154,7 +153,7 @@ static void free_buffer(struct videobuf_queue *vq, struct mx1_buffer *buf)
 
        BUG_ON(in_interrupt());
 
-       dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
                vb, vb->baddr, vb->bsize);
 
        /*
@@ -179,7 +178,7 @@ static int mx1_videobuf_prepare(struct videobuf_queue *vq,
        if (bytes_per_line < 0)
                return bytes_per_line;
 
-       dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
                vb, vb->baddr, vb->bsize);
 
        /* Added list head initialization on alloc */
@@ -232,7 +231,7 @@ out:
 static int mx1_camera_setup_dma(struct mx1_camera_dev *pcdev)
 {
        struct videobuf_buffer *vbuf = &pcdev->active->vb;
-       struct device *dev = pcdev->icd->dev.parent;
+       struct device *dev = pcdev->icd->parent;
        int ret;
 
        if (unlikely(!pcdev->active)) {
@@ -256,11 +255,11 @@ static void mx1_videobuf_queue(struct videobuf_queue *vq,
                                                struct videobuf_buffer *vb)
 {
        struct soc_camera_device *icd = vq->priv_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx1_camera_dev *pcdev = ici->priv;
        struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb);
 
-       dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
                vb, vb->baddr, vb->bsize);
 
        list_add_tail(&vb->queue, &pcdev->capture);
@@ -287,7 +286,7 @@ static void mx1_videobuf_release(struct videobuf_queue *vq,
        struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb);
 #ifdef DEBUG
        struct soc_camera_device *icd = vq->priv_data;
-       struct device *dev = icd->dev.parent;
+       struct device *dev = icd->parent;
 
        dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
                vb, vb->baddr, vb->bsize);
@@ -343,7 +342,7 @@ static void mx1_camera_wakeup(struct mx1_camera_dev *pcdev,
 static void mx1_camera_dma_irq(int channel, void *data)
 {
        struct mx1_camera_dev *pcdev = data;
-       struct device *dev = pcdev->icd->dev.parent;
+       struct device *dev = pcdev->icd->parent;
        struct mx1_buffer *buf;
        struct videobuf_buffer *vb;
        unsigned long flags;
@@ -378,10 +377,10 @@ static struct videobuf_queue_ops mx1_videobuf_ops = {
 static void mx1_camera_init_videobuf(struct videobuf_queue *q,
                                     struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx1_camera_dev *pcdev = ici->priv;
 
-       videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, icd->dev.parent,
+       videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, icd->parent,
                                &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                V4L2_FIELD_NONE,
                                sizeof(struct mx1_buffer), icd, &icd->video_lock);
@@ -401,7 +400,7 @@ static int mclk_get_divisor(struct mx1_camera_dev *pcdev)
         */
        div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1;
 
-       dev_dbg(pcdev->icd->dev.parent,
+       dev_dbg(pcdev->icd->parent,
                "System clock %lukHz, target freq %dkHz, divisor %lu\n",
                lcdclk / 1000, mclk / 1000, div);
 
@@ -412,7 +411,7 @@ static void mx1_camera_activate(struct mx1_camera_dev *pcdev)
 {
        unsigned int csicr1 = CSICR1_EN;
 
-       dev_dbg(pcdev->icd->dev.parent, "Activate device\n");
+       dev_dbg(pcdev->icd->parent, "Activate device\n");
 
        clk_enable(pcdev->clk);
 
@@ -428,7 +427,7 @@ static void mx1_camera_activate(struct mx1_camera_dev *pcdev)
 
 static void mx1_camera_deactivate(struct mx1_camera_dev *pcdev)
 {
-       dev_dbg(pcdev->icd->dev.parent, "Deactivate device\n");
+       dev_dbg(pcdev->icd->parent, "Deactivate device\n");
 
        /* Disable all CSI interface */
        __raw_writel(0x00, pcdev->base + CSICR1);
@@ -442,13 +441,13 @@ static void mx1_camera_deactivate(struct mx1_camera_dev *pcdev)
  */
 static int mx1_camera_add_device(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx1_camera_dev *pcdev = ici->priv;
 
        if (pcdev->icd)
                return -EBUSY;
 
-       dev_info(icd->dev.parent, "MX1 Camera driver attached to camera %d\n",
+       dev_info(icd->parent, "MX1 Camera driver attached to camera %d\n",
                 icd->devnum);
 
        mx1_camera_activate(pcdev);
@@ -460,7 +459,7 @@ static int mx1_camera_add_device(struct soc_camera_device *icd)
 
 static void mx1_camera_remove_device(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx1_camera_dev *pcdev = ici->priv;
        unsigned int csicr1;
 
@@ -473,7 +472,7 @@ static void mx1_camera_remove_device(struct soc_camera_device *icd)
        /* Stop DMA engine */
        imx_dma_disable(pcdev->dma_chan);
 
-       dev_info(icd->dev.parent, "MX1 Camera driver detached from camera %d\n",
+       dev_info(icd->parent, "MX1 Camera driver detached from camera %d\n",
                 icd->devnum);
 
        mx1_camera_deactivate(pcdev);
@@ -491,7 +490,7 @@ static int mx1_camera_set_crop(struct soc_camera_device *icd,
 
 static int mx1_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx1_camera_dev *pcdev = ici->priv;
        unsigned long camera_flags, common_flags;
        unsigned int csicr1;
@@ -562,14 +561,14 @@ static int mx1_camera_set_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
        if (!xlate) {
-               dev_warn(icd->dev.parent, "Format %x not found\n",
+               dev_warn(icd->parent, "Format %x not found\n",
                         pix->pixelformat);
                return -EINVAL;
        }
 
        buswidth = xlate->host_fmt->bits_per_sample;
        if (buswidth > 8) {
-               dev_warn(icd->dev.parent,
+               dev_warn(icd->parent,
                         "bits-per-sample %d for format %x unsupported\n",
                         buswidth, pix->pixelformat);
                return -EINVAL;
@@ -609,7 +608,7 @@ static int mx1_camera_try_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
        if (!xlate) {
-               dev_warn(icd->dev.parent, "Format %x not found\n",
+               dev_warn(icd->parent, "Format %x not found\n",
                         pix->pixelformat);
                return -EINVAL;
        }
@@ -676,7 +675,6 @@ static int mx1_camera_querycap(struct soc_camera_host *ici,
 {
        /* cap->name is set by the friendly caller:-> */
        strlcpy(cap->card, "i.MX1/i.MXL Camera", sizeof(cap->card));
-       cap->version = VERSION_CODE;
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
 
        return 0;
@@ -883,4 +881,5 @@ module_exit(mx1_camera_exit);
 MODULE_DESCRIPTION("i.MX1/i.MXL SoC Camera Host driver");
 MODULE_AUTHOR("Paulius Zaleckas <paulius.zaleckas@teltonika.lt>");
 MODULE_LICENSE("GPL v2");
+MODULE_VERSION(DRIVER_VERSION);
 MODULE_ALIAS("platform:" DRIVER_NAME);
index 4eab1c6..ec2410c 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/mm.h>
 #include <linux/moduleparam.h>
 #include <linux/time.h>
-#include <linux/version.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/mutex.h>
@@ -47,7 +46,7 @@
 #include <asm/dma.h>
 
 #define MX2_CAM_DRV_NAME "mx2-camera"
-#define MX2_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 5)
+#define MX2_CAM_VERSION "0.0.6"
 #define MX2_CAM_DRIVER_DESCRIPTION "i.MX2x_Camera"
 
 /* reset values */
@@ -278,7 +277,7 @@ static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev)
  */
 static int mx2_camera_add_device(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx2_camera_dev *pcdev = ici->priv;
        int ret;
        u32 csicr1;
@@ -303,7 +302,7 @@ static int mx2_camera_add_device(struct soc_camera_device *icd)
 
        pcdev->icd = icd;
 
-       dev_info(icd->dev.parent, "Camera driver attached to camera %d\n",
+       dev_info(icd->parent, "Camera driver attached to camera %d\n",
                 icd->devnum);
 
        return 0;
@@ -311,12 +310,12 @@ static int mx2_camera_add_device(struct soc_camera_device *icd)
 
 static void mx2_camera_remove_device(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx2_camera_dev *pcdev = ici->priv;
 
        BUG_ON(icd != pcdev->icd);
 
-       dev_info(icd->dev.parent, "Camera driver detached from camera %d\n",
+       dev_info(icd->parent, "Camera driver detached from camera %d\n",
                 icd->devnum);
 
        mx2_camera_deactivate(pcdev);
@@ -437,7 +436,7 @@ static int mx2_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
        int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
                        icd->current_fmt->host_fmt);
 
-       dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
+       dev_dbg(icd->parent, "count=%d, size=%d\n", *count, *size);
 
        if (bytes_per_line < 0)
                return bytes_per_line;
@@ -457,7 +456,7 @@ static void free_buffer(struct videobuf_queue *vq, struct mx2_buffer *buf)
        struct soc_camera_device *icd = vq->priv_data;
        struct videobuf_buffer *vb = &buf->vb;
 
-       dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
                vb, vb->baddr, vb->bsize);
 
        /*
@@ -467,7 +466,7 @@ static void free_buffer(struct videobuf_queue *vq, struct mx2_buffer *buf)
        videobuf_waiton(vq, vb, 0, 0);
 
        videobuf_dma_contig_free(vq, vb);
-       dev_dbg(&icd->dev, "%s freed\n", __func__);
+       dev_dbg(icd->parent, "%s freed\n", __func__);
 
        vb->state = VIDEOBUF_NEEDS_INIT;
 }
@@ -481,7 +480,7 @@ static int mx2_videobuf_prepare(struct videobuf_queue *vq,
                        icd->current_fmt->host_fmt);
        int ret = 0;
 
-       dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
                vb, vb->baddr, vb->bsize);
 
        if (bytes_per_line < 0)
@@ -533,12 +532,12 @@ static void mx2_videobuf_queue(struct videobuf_queue *vq,
 {
        struct soc_camera_device *icd = vq->priv_data;
        struct soc_camera_host *ici =
-               to_soc_camera_host(icd->dev.parent);
+               to_soc_camera_host(icd->parent);
        struct mx2_camera_dev *pcdev = ici->priv;
        struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
        unsigned long flags;
 
-       dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
                vb, vb->baddr, vb->bsize);
 
        spin_lock_irqsave(&pcdev->lock, flags);
@@ -611,27 +610,27 @@ static void mx2_videobuf_release(struct videobuf_queue *vq,
                                 struct videobuf_buffer *vb)
 {
        struct soc_camera_device *icd = vq->priv_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx2_camera_dev *pcdev = ici->priv;
        struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
        unsigned long flags;
 
 #ifdef DEBUG
-       dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
                vb, vb->baddr, vb->bsize);
 
        switch (vb->state) {
        case VIDEOBUF_ACTIVE:
-               dev_info(&icd->dev, "%s (active)\n", __func__);
+               dev_info(icd->parent, "%s (active)\n", __func__);
                break;
        case VIDEOBUF_QUEUED:
-               dev_info(&icd->dev, "%s (queued)\n", __func__);
+               dev_info(icd->parent, "%s (queued)\n", __func__);
                break;
        case VIDEOBUF_PREPARED:
-               dev_info(&icd->dev, "%s (prepared)\n", __func__);
+               dev_info(icd->parent, "%s (prepared)\n", __func__);
                break;
        default:
-               dev_info(&icd->dev, "%s (unknown) %d\n", __func__,
+               dev_info(icd->parent, "%s (unknown) %d\n", __func__,
                                vb->state);
                break;
        }
@@ -678,7 +677,7 @@ static struct videobuf_queue_ops mx2_videobuf_ops = {
 static void mx2_camera_init_videobuf(struct videobuf_queue *q,
                              struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx2_camera_dev *pcdev = ici->priv;
 
        videobuf_queue_dma_contig_init(q, &mx2_videobuf_ops, pcdev->dev,
@@ -719,7 +718,7 @@ static void mx27_camera_emma_buf_init(struct soc_camera_device *icd,
                int bytesperline)
 {
        struct soc_camera_host *ici =
-               to_soc_camera_host(icd->dev.parent);
+               to_soc_camera_host(icd->parent);
        struct mx2_camera_dev *pcdev = ici->priv;
 
        writel(pcdev->discard_buffer_dma,
@@ -772,7 +771,7 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd,
                __u32 pixfmt)
 {
        struct soc_camera_host *ici =
-               to_soc_camera_host(icd->dev.parent);
+               to_soc_camera_host(icd->parent);
        struct mx2_camera_dev *pcdev = ici->priv;
        unsigned long camera_flags, common_flags;
        int ret = 0;
@@ -891,7 +890,7 @@ static int mx2_camera_set_crop(struct soc_camera_device *icd,
        if (ret < 0)
                return ret;
 
-       dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n",
+       dev_dbg(icd->parent, "Sensor cropped %dx%d\n",
                mf.width, mf.height);
 
        icd->user_width         = mf.width;
@@ -911,7 +910,7 @@ static int mx2_camera_set_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
        if (!xlate) {
-               dev_warn(icd->dev.parent, "Format %x not found\n",
+               dev_warn(icd->parent, "Format %x not found\n",
                                pix->pixelformat);
                return -EINVAL;
        }
@@ -951,7 +950,7 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
        if (pixfmt && !xlate) {
-               dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt);
+               dev_warn(icd->parent, "Format %x not found\n", pixfmt);
                return -EINVAL;
        }
 
@@ -974,11 +973,16 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd,
                if (pix->bytesperline < 0)
                        return pix->bytesperline;
                pix->sizeimage = pix->height * pix->bytesperline;
-               if (pix->sizeimage > (4 * 0x3ffff)) { /* CSIRXCNT limit */
-                       dev_warn(icd->dev.parent,
-                                       "Image size (%u) above limit\n",
-                                       pix->sizeimage);
-                       return -EINVAL;
+               /* Check against the CSIRXCNT limit */
+               if (pix->sizeimage > 4 * 0x3ffff) {
+                       /* Adjust geometry, preserve aspect ratio */
+                       unsigned int new_height = int_sqrt(4 * 0x3ffff *
+                                       pix->height / pix->bytesperline);
+                       pix->width = new_height * pix->width / pix->height;
+                       pix->height = new_height;
+                       pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
+                                                       xlate->host_fmt);
+                       BUG_ON(pix->bytesperline < 0);
                }
        }
 
@@ -996,7 +1000,7 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd,
        if (mf.field == V4L2_FIELD_ANY)
                mf.field = V4L2_FIELD_NONE;
        if (mf.field != V4L2_FIELD_NONE) {
-               dev_err(icd->dev.parent, "Field type %d unsupported.\n",
+               dev_err(icd->parent, "Field type %d unsupported.\n",
                                mf.field);
                return -EINVAL;
        }
@@ -1014,7 +1018,6 @@ static int mx2_camera_querycap(struct soc_camera_host *ici,
 {
        /* cap->name is set by the friendly caller:-> */
        strlcpy(cap->card, MX2_CAM_DRIVER_DESCRIPTION, sizeof(cap->card));
-       cap->version = MX2_CAM_VERSION_CODE;
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
 
        return 0;
@@ -1523,3 +1526,4 @@ module_exit(mx2_camera_exit);
 MODULE_DESCRIPTION("i.MX27/i.MX25 SoC Camera Host driver");
 MODULE_AUTHOR("Sascha Hauer <sha@pengutronix.de>");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(MX2_CAM_VERSION);
index c7680eb..c045b47 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/videodev2.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
@@ -195,7 +194,7 @@ static int mx3_videobuf_setup(struct vb2_queue *vq,
                        unsigned long sizes[], void *alloc_ctxs[])
 {
        struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
        int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
                                                icd->current_fmt->host_fmt);
@@ -224,7 +223,7 @@ static int mx3_videobuf_setup(struct vb2_queue *vq,
 static int mx3_videobuf_prepare(struct vb2_buffer *vb)
 {
        struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
        struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
        struct scatterlist *sg;
@@ -242,7 +241,7 @@ static int mx3_videobuf_prepare(struct vb2_buffer *vb)
        new_size = bytes_per_line * icd->user_height;
 
        if (vb2_plane_size(vb, 0) < new_size) {
-               dev_err(icd->dev.parent, "Buffer too small (%lu < %zu)\n",
+               dev_err(icd->parent, "Buffer too small (%lu < %zu)\n",
                        vb2_plane_size(vb, 0), new_size);
                return -ENOBUFS;
        }
@@ -284,7 +283,7 @@ static enum pixel_fmt fourcc_to_ipu_pix(__u32 fourcc)
 static void mx3_videobuf_queue(struct vb2_buffer *vb)
 {
        struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
        struct mx3_camera_buffer *buf = to_mx3_vb(vb);
        struct dma_async_tx_descriptor *txd = buf->txd;
@@ -337,7 +336,7 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb)
        spin_unlock_irq(&mx3_cam->lock);
 
        cookie = txd->tx_submit(txd);
-       dev_dbg(icd->dev.parent, "Submitted cookie %d DMA 0x%08x\n",
+       dev_dbg(icd->parent, "Submitted cookie %d DMA 0x%08x\n",
                cookie, sg_dma_address(&buf->sg));
 
        if (cookie >= 0)
@@ -358,13 +357,13 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb)
 static void mx3_videobuf_release(struct vb2_buffer *vb)
 {
        struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
        struct mx3_camera_buffer *buf = to_mx3_vb(vb);
        struct dma_async_tx_descriptor *txd = buf->txd;
        unsigned long flags;
 
-       dev_dbg(icd->dev.parent,
+       dev_dbg(icd->parent,
                "Release%s DMA 0x%08x, queue %sempty\n",
                mx3_cam->active == buf ? " active" : "", sg_dma_address(&buf->sg),
                list_empty(&buf->queue) ? "" : "not ");
@@ -403,7 +402,7 @@ static int mx3_videobuf_init(struct vb2_buffer *vb)
 static int mx3_stop_streaming(struct vb2_queue *q)
 {
        struct soc_camera_device *icd = soc_camera_from_vb2q(q);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
        struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
        struct dma_chan *chan;
@@ -499,7 +498,7 @@ static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam,
 
        clk_enable(mx3_cam->clk);
        rate = clk_round_rate(mx3_cam->clk, mx3_cam->mclk);
-       dev_dbg(icd->dev.parent, "Set SENS_CONF to %x, rate %ld\n", conf, rate);
+       dev_dbg(icd->parent, "Set SENS_CONF to %x, rate %ld\n", conf, rate);
        if (rate)
                clk_set_rate(mx3_cam->clk, rate);
 }
@@ -507,7 +506,7 @@ static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam,
 /* Called with .video_lock held */
 static int mx3_camera_add_device(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
 
        if (mx3_cam->icd)
@@ -517,7 +516,7 @@ static int mx3_camera_add_device(struct soc_camera_device *icd)
 
        mx3_cam->icd = icd;
 
-       dev_info(icd->dev.parent, "MX3 Camera driver attached to camera %d\n",
+       dev_info(icd->parent, "MX3 Camera driver attached to camera %d\n",
                 icd->devnum);
 
        return 0;
@@ -526,7 +525,7 @@ static int mx3_camera_add_device(struct soc_camera_device *icd)
 /* Called with .video_lock held */
 static void mx3_camera_remove_device(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
        struct idmac_channel **ichan = &mx3_cam->idmac_channel[0];
 
@@ -541,7 +540,7 @@ static void mx3_camera_remove_device(struct soc_camera_device *icd)
 
        mx3_cam->icd = NULL;
 
-       dev_info(icd->dev.parent, "MX3 Camera driver detached from camera %d\n",
+       dev_info(icd->parent, "MX3 Camera driver detached from camera %d\n",
                 icd->devnum);
 }
 
@@ -608,12 +607,12 @@ static int test_platform_param(struct mx3_camera_dev *mx3_cam,
 static int mx3_camera_try_bus_param(struct soc_camera_device *icd,
                                    const unsigned int depth)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
        unsigned long bus_flags, camera_flags;
        int ret = test_platform_param(mx3_cam, depth, &bus_flags);
 
-       dev_dbg(icd->dev.parent, "request bus width %d bit: %d\n", depth, ret);
+       dev_dbg(icd->parent, "request bus width %d bit: %d\n", depth, ret);
 
        if (ret < 0)
                return ret;
@@ -622,7 +621,7 @@ static int mx3_camera_try_bus_param(struct soc_camera_device *icd,
 
        ret = soc_camera_bus_param_compatible(camera_flags, bus_flags);
        if (ret < 0)
-               dev_warn(icd->dev.parent,
+               dev_warn(icd->parent,
                         "Flags incompatible: camera %lx, host %lx\n",
                         camera_flags, bus_flags);
 
@@ -676,7 +675,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id
                                  struct soc_camera_format_xlate *xlate)
 {
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-       struct device *dev = icd->dev.parent;
+       struct device *dev = icd->parent;
        int formats = 0, ret;
        enum v4l2_mbus_pixelcode code;
        const struct soc_mbus_pixelfmt *fmt;
@@ -688,7 +687,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id
 
        fmt = soc_mbus_get_fmtdesc(code);
        if (!fmt) {
-               dev_warn(icd->dev.parent,
+               dev_warn(icd->parent,
                         "Unsupported format code #%u: %d\n", idx, code);
                return 0;
        }
@@ -816,7 +815,7 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd,
                               struct v4l2_crop *a)
 {
        struct v4l2_rect *rect = &a->c;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        struct v4l2_mbus_framefmt mf;
@@ -849,7 +848,7 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd,
                configure_geometry(mx3_cam, mf.width, mf.height,
                                   icd->current_fmt->host_fmt);
 
-       dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n",
+       dev_dbg(icd->parent, "Sensor cropped %dx%d\n",
                mf.width, mf.height);
 
        icd->user_width         = mf.width;
@@ -861,7 +860,7 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd,
 static int mx3_camera_set_fmt(struct soc_camera_device *icd,
                              struct v4l2_format *f)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        const struct soc_camera_format_xlate *xlate;
@@ -871,13 +870,13 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
        if (!xlate) {
-               dev_warn(icd->dev.parent, "Format %x not found\n",
+               dev_warn(icd->parent, "Format %x not found\n",
                         pix->pixelformat);
                return -EINVAL;
        }
 
        stride_align(&pix->width);
-       dev_dbg(icd->dev.parent, "Set format %dx%d\n", pix->width, pix->height);
+       dev_dbg(icd->parent, "Set format %dx%d\n", pix->width, pix->height);
 
        /*
         * Might have to perform a complete interface initialisation like in
@@ -913,13 +912,7 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd,
        pix->colorspace         = mf.colorspace;
        icd->current_fmt        = xlate;
 
-       pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
-                                                   xlate->host_fmt);
-       if (pix->bytesperline < 0)
-               return pix->bytesperline;
-       pix->sizeimage = pix->height * pix->bytesperline;
-
-       dev_dbg(icd->dev.parent, "Sensor set %dx%d\n", pix->width, pix->height);
+       dev_dbg(icd->parent, "Sensor set %dx%d\n", pix->width, pix->height);
 
        return ret;
 }
@@ -936,7 +929,7 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
        if (pixfmt && !xlate) {
-               dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt);
+               dev_warn(icd->parent, "Format %x not found\n", pixfmt);
                return -EINVAL;
        }
 
@@ -946,12 +939,6 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd,
        if (pix->width > 4096)
                pix->width = 4096;
 
-       pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
-                                                   xlate->host_fmt);
-       if (pix->bytesperline < 0)
-               return pix->bytesperline;
-       pix->sizeimage = pix->height * pix->bytesperline;
-
        /* limit to sensor capabilities */
        mf.width        = pix->width;
        mf.height       = pix->height;
@@ -974,7 +961,7 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd,
        case V4L2_FIELD_NONE:
                break;
        default:
-               dev_err(icd->dev.parent, "Field type %d unsupported.\n",
+               dev_err(icd->parent, "Field type %d unsupported.\n",
                        mf.field);
                ret = -EINVAL;
        }
@@ -1000,7 +987,6 @@ static int mx3_camera_querycap(struct soc_camera_host *ici,
 {
        /* cap->name is set by the firendly caller:-> */
        strlcpy(cap->card, "i.MX3x Camera", sizeof(cap->card));
-       cap->version = KERNEL_VERSION(0, 2, 2);
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
 
        return 0;
@@ -1008,7 +994,7 @@ static int mx3_camera_querycap(struct soc_camera_host *ici,
 
 static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
        unsigned long bus_flags, camera_flags, common_flags;
        u32 dw, sens_conf;
@@ -1016,7 +1002,7 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
        int buswidth;
        int ret;
        const struct soc_camera_format_xlate *xlate;
-       struct device *dev = icd->dev.parent;
+       struct device *dev = icd->parent;
 
        fmt = soc_mbus_get_fmtdesc(icd->current_fmt->code);
        if (!fmt)
@@ -1325,4 +1311,5 @@ module_exit(mx3_camera_exit);
 MODULE_DESCRIPTION("i.MX3x SoC Camera Host driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>");
 MODULE_LICENSE("GPL v2");
+MODULE_VERSION("0.2.3");
 MODULE_ALIAS("platform:" MX3_CAM_DRV_NAME);
index e63233f..390ab09 100644 (file)
@@ -1,11 +1,14 @@
+config VIDEO_OMAP2_VOUT_VRFB
+       bool
+
 config VIDEO_OMAP2_VOUT
        tristate "OMAP2/OMAP3 V4L2-Display driver"
        depends on ARCH_OMAP2 || ARCH_OMAP3
        select VIDEOBUF_GEN
        select VIDEOBUF_DMA_CONTIG
        select OMAP2_DSS
-       select OMAP2_VRAM
-       select OMAP2_VRFB
+       select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
+       select VIDEO_OMAP2_VOUT_VRFB if VIDEO_OMAP2_VOUT && OMAP2_VRFB
        default n
        ---help---
          V4L2 Display driver support for OMAP2/3 based boards.
index b287880..fc410b4 100644 (file)
@@ -4,4 +4,5 @@
 
 # OMAP2/3 Display driver
 omap-vout-y := omap_vout.o omap_voutlib.o
+omap-vout-$(CONFIG_VIDEO_OMAP2_VOUT_VRFB) += omap_vout_vrfb.o
 obj-$(CONFIG_VIDEO_OMAP2_VOUT) += omap-vout.o
index a647894..b5ef362 100644 (file)
 #include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
 #include <linux/irq.h>
 #include <linux/videodev2.h>
-#include <linux/slab.h>
+#include <linux/dma-mapping.h>
 
 #include <media/videobuf-dma-contig.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 
 #include <plat/dma.h>
-#include <plat/vram.h>
 #include <plat/vrfb.h>
 #include <video/omapdss.h>
 
 #include "omap_voutlib.h"
 #include "omap_voutdef.h"
+#include "omap_vout_vrfb.h"
 
 MODULE_AUTHOR("Texas Instruments");
 MODULE_DESCRIPTION("OMAP Video for Linux Video out driver");
 MODULE_LICENSE("GPL");
 
-
 /* Driver Configuration macros */
 #define VOUT_NAME              "omap_vout"
 
@@ -65,31 +63,6 @@ enum omap_vout_channels {
        OMAP_VIDEO2,
 };
 
-enum dma_channel_state {
-       DMA_CHAN_NOT_ALLOTED,
-       DMA_CHAN_ALLOTED,
-};
-
-#define QQVGA_WIDTH            160
-#define QQVGA_HEIGHT           120
-
-/* Max Resolution supported by the driver */
-#define VID_MAX_WIDTH          1280    /* Largest width */
-#define VID_MAX_HEIGHT         720     /* Largest height */
-
-/* Mimimum requirement is 2x2 for DSS */
-#define VID_MIN_WIDTH          2
-#define VID_MIN_HEIGHT         2
-
-/* 2048 x 2048 is max res supported by OMAP display controller */
-#define MAX_PIXELS_PER_LINE     2048
-
-#define VRFB_TX_TIMEOUT         1000
-#define VRFB_NUM_BUFS          4
-
-/* Max buffer size tobe allocated during init */
-#define OMAP_VOUT_MAX_BUF_SIZE (VID_MAX_WIDTH*VID_MAX_HEIGHT*4)
-
 static struct videobuf_queue_ops video_vbq_ops;
 /* Variables configurable through module params*/
 static u32 video1_numbuffers = 3;
@@ -171,84 +144,6 @@ static const struct v4l2_fmtdesc omap_formats[] = {
 
 #define NUM_OUTPUT_FORMATS (ARRAY_SIZE(omap_formats))
 
-/*
- * Allocate buffers
- */
-static unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr)
-{
-       u32 order, size;
-       unsigned long virt_addr, addr;
-
-       size = PAGE_ALIGN(buf_size);
-       order = get_order(size);
-       virt_addr = __get_free_pages(GFP_KERNEL | GFP_DMA, order);
-       addr = virt_addr;
-
-       if (virt_addr) {
-               while (size > 0) {
-                       SetPageReserved(virt_to_page(addr));
-                       addr += PAGE_SIZE;
-                       size -= PAGE_SIZE;
-               }
-       }
-       *phys_addr = (u32) virt_to_phys((void *) virt_addr);
-       return virt_addr;
-}
-
-/*
- * Free buffers
- */
-static void omap_vout_free_buffer(unsigned long virtaddr, u32 buf_size)
-{
-       u32 order, size;
-       unsigned long addr = virtaddr;
-
-       size = PAGE_ALIGN(buf_size);
-       order = get_order(size);
-
-       while (size > 0) {
-               ClearPageReserved(virt_to_page(addr));
-               addr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-       free_pages((unsigned long) virtaddr, order);
-}
-
-/*
- * Function for allocating video buffers
- */
-static int omap_vout_allocate_vrfb_buffers(struct omap_vout_device *vout,
-               unsigned int *count, int startindex)
-{
-       int i, j;
-
-       for (i = 0; i < *count; i++) {
-               if (!vout->smsshado_virt_addr[i]) {
-                       vout->smsshado_virt_addr[i] =
-                               omap_vout_alloc_buffer(vout->smsshado_size,
-                                               &vout->smsshado_phy_addr[i]);
-               }
-               if (!vout->smsshado_virt_addr[i] && startindex != -1) {
-                       if (V4L2_MEMORY_MMAP == vout->memory && i >= startindex)
-                               break;
-               }
-               if (!vout->smsshado_virt_addr[i]) {
-                       for (j = 0; j < i; j++) {
-                               omap_vout_free_buffer(
-                                               vout->smsshado_virt_addr[j],
-                                               vout->smsshado_size);
-                               vout->smsshado_virt_addr[j] = 0;
-                               vout->smsshado_phy_addr[j] = 0;
-                       }
-                       *count = 0;
-                       return -ENOMEM;
-               }
-               memset((void *) vout->smsshado_virt_addr[i], 0,
-                               vout->smsshado_size);
-       }
-       return 0;
-}
-
 /*
  * Try format
  */
@@ -341,74 +236,10 @@ static u32 omap_vout_uservirt_to_phys(u32 virtp)
        return physp;
 }
 
-/*
- * Wakes up the application once the DMA transfer to VRFB space is completed.
- */
-static void omap_vout_vrfb_dma_tx_callback(int lch, u16 ch_status, void *data)
-{
-       struct vid_vrfb_dma *t = (struct vid_vrfb_dma *) data;
-
-       t->tx_status = 1;
-       wake_up_interruptible(&t->wait);
-}
-
-/*
- * Release the VRFB context once the module exits
- */
-static void omap_vout_release_vrfb(struct omap_vout_device *vout)
-{
-       int i;
-
-       for (i = 0; i < VRFB_NUM_BUFS; i++)
-               omap_vrfb_release_ctx(&vout->vrfb_context[i]);
-
-       if (vout->vrfb_dma_tx.req_status == DMA_CHAN_ALLOTED) {
-               vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED;
-               omap_free_dma(vout->vrfb_dma_tx.dma_ch);
-       }
-}
-
-/*
- * Return true if rotation is 90 or 270
- */
-static inline int rotate_90_or_270(const struct omap_vout_device *vout)
-{
-       return (vout->rotation == dss_rotation_90_degree ||
-                       vout->rotation == dss_rotation_270_degree);
-}
-
-/*
- * Return true if rotation is enabled
- */
-static inline int rotation_enabled(const struct omap_vout_device *vout)
-{
-       return vout->rotation || vout->mirror;
-}
-
-/*
- * Reverse the rotation degree if mirroring is enabled
- */
-static inline int calc_rotation(const struct omap_vout_device *vout)
-{
-       if (!vout->mirror)
-               return vout->rotation;
-
-       switch (vout->rotation) {
-       case dss_rotation_90_degree:
-               return dss_rotation_270_degree;
-       case dss_rotation_270_degree:
-               return dss_rotation_90_degree;
-       case dss_rotation_180_degree:
-               return dss_rotation_0_degree;
-       default:
-               return dss_rotation_180_degree;
-       }
-}
-
 /*
  * Free the V4L2 buffers
  */
-static void omap_vout_free_buffers(struct omap_vout_device *vout)
+void omap_vout_free_buffers(struct omap_vout_device *vout)
 {
        int i, numbuffers;
 
@@ -424,52 +255,6 @@ static void omap_vout_free_buffers(struct omap_vout_device *vout)
        }
 }
 
-/*
- * Free VRFB buffers
- */
-static void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout)
-{
-       int j;
-
-       for (j = 0; j < VRFB_NUM_BUFS; j++) {
-               omap_vout_free_buffer(vout->smsshado_virt_addr[j],
-                               vout->smsshado_size);
-               vout->smsshado_virt_addr[j] = 0;
-               vout->smsshado_phy_addr[j] = 0;
-       }
-}
-
-/*
- * Allocate the buffers for the VRFB space.  Data is copied from V4L2
- * buffers to the VRFB buffers using the DMA engine.
- */
-static int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
-                         unsigned int *count, unsigned int startindex)
-{
-       int i;
-       bool yuv_mode;
-
-       /* Allocate the VRFB buffers only if the buffers are not
-        * allocated during init time.
-        */
-       if ((rotation_enabled(vout)) && !vout->vrfb_static_allocation)
-               if (omap_vout_allocate_vrfb_buffers(vout, count, startindex))
-                       return -ENOMEM;
-
-       if (vout->dss_mode == OMAP_DSS_COLOR_YUV2 ||
-                       vout->dss_mode == OMAP_DSS_COLOR_UYVY)
-               yuv_mode = true;
-       else
-               yuv_mode = false;
-
-       for (i = 0; i < *count; i++)
-               omap_vrfb_setup(&vout->vrfb_context[i],
-                               vout->smsshado_phy_addr[i], vout->pix.width,
-                               vout->pix.height, vout->bpp, yuv_mode);
-
-       return 0;
-}
-
 /*
  * Convert V4L2 rotation to DSS rotation
  *     V4L2 understand 0, 90, 180, 270.
@@ -499,124 +284,38 @@ static int v4l2_rot_to_dss_rot(int v4l2_rotation,
        return ret;
 }
 
-/*
- * Calculate the buffer offsets from which the streaming should
- * start. This offset calculation is mainly required because of
- * the VRFB 32 pixels alignment with rotation.
- */
 static int omap_vout_calculate_offset(struct omap_vout_device *vout)
 {
-       struct omap_overlay *ovl;
-       enum dss_rotation rotation;
        struct omapvideo_info *ovid;
-       bool mirroring = vout->mirror;
-       struct omap_dss_device *cur_display;
        struct v4l2_rect *crop = &vout->crop;
        struct v4l2_pix_format *pix = &vout->pix;
        int *cropped_offset = &vout->cropped_offset;
-       int vr_ps = 1, ps = 2, temp_ps = 2;
-       int offset = 0, ctop = 0, cleft = 0, line_length = 0;
+       int ps = 2, line_length = 0;
 
        ovid = &vout->vid_info;
-       ovl = ovid->overlays[0];
-       /* get the display device attached to the overlay */
-       if (!ovl->manager || !ovl->manager->device)
-               return -1;
 
-       cur_display = ovl->manager->device;
-       rotation = calc_rotation(vout);
+       if (ovid->rotation_type == VOUT_ROT_VRFB) {
+               omap_vout_calculate_vrfb_offset(vout);
+       } else {
+               vout->line_length = line_length = pix->width;
 
-       if (V4L2_PIX_FMT_YUYV == pix->pixelformat ||
-                       V4L2_PIX_FMT_UYVY == pix->pixelformat) {
-               if (rotation_enabled(vout)) {
-                       /*
-                        * ps    - Actual pixel size for YUYV/UYVY for
-                        *         VRFB/Mirroring is 4 bytes
-                        * vr_ps - Virtually pixel size for YUYV/UYVY is
-                        *         2 bytes
-                        */
+               if (V4L2_PIX_FMT_YUYV == pix->pixelformat ||
+                       V4L2_PIX_FMT_UYVY == pix->pixelformat)
+                       ps = 2;
+               else if (V4L2_PIX_FMT_RGB32 == pix->pixelformat)
                        ps = 4;
-                       vr_ps = 2;
-               } else {
-                       ps = 2; /* otherwise the pixel size is 2 byte */
-               }
-       } else if (V4L2_PIX_FMT_RGB32 == pix->pixelformat) {
-               ps = 4;
-       } else if (V4L2_PIX_FMT_RGB24 == pix->pixelformat) {
-               ps = 3;
-       }
-       vout->ps = ps;
-       vout->vr_ps = vr_ps;
-
-       if (rotation_enabled(vout)) {
-               line_length = MAX_PIXELS_PER_LINE;
-               ctop = (pix->height - crop->height) - crop->top;
-               cleft = (pix->width - crop->width) - crop->left;
-       } else {
-               line_length = pix->width;
-       }
-       vout->line_length = line_length;
-       switch (rotation) {
-       case dss_rotation_90_degree:
-               offset = vout->vrfb_context[0].yoffset *
-                       vout->vrfb_context[0].bytespp;
-               temp_ps = ps / vr_ps;
-               if (mirroring == 0) {
-                       *cropped_offset = offset + line_length *
-                               temp_ps * cleft + crop->top * temp_ps;
-               } else {
-                       *cropped_offset = offset + line_length * temp_ps *
-                               cleft + crop->top * temp_ps + (line_length *
-                               ((crop->width / (vr_ps)) - 1) * ps);
-               }
-               break;
-       case dss_rotation_180_degree:
-               offset = ((MAX_PIXELS_PER_LINE * vout->vrfb_context[0].yoffset *
-                       vout->vrfb_context[0].bytespp) +
-                       (vout->vrfb_context[0].xoffset *
-                       vout->vrfb_context[0].bytespp));
-               if (mirroring == 0) {
-                       *cropped_offset = offset + (line_length * ps * ctop) +
-                               (cleft / vr_ps) * ps;
+               else if (V4L2_PIX_FMT_RGB24 == pix->pixelformat)
+                       ps = 3;
 
-               } else {
-                       *cropped_offset = offset + (line_length * ps * ctop) +
-                               (cleft / vr_ps) * ps + (line_length *
-                               (crop->height - 1) * ps);
-               }
-               break;
-       case dss_rotation_270_degree:
-               offset = MAX_PIXELS_PER_LINE * vout->vrfb_context[0].xoffset *
-                       vout->vrfb_context[0].bytespp;
-               temp_ps = ps / vr_ps;
-               if (mirroring == 0) {
-                       *cropped_offset = offset + line_length *
-                           temp_ps * crop->left + ctop * ps;
-               } else {
-                       *cropped_offset = offset + line_length *
-                               temp_ps * crop->left + ctop * ps +
-                               (line_length * ((crop->width / vr_ps) - 1) *
-                                ps);
-               }
-               break;
-       case dss_rotation_0_degree:
-               if (mirroring == 0) {
-                       *cropped_offset = (line_length * ps) *
-                               crop->top + (crop->left / vr_ps) * ps;
-               } else {
-                       *cropped_offset = (line_length * ps) *
-                               crop->top + (crop->left / vr_ps) * ps +
-                               (line_length * (crop->height - 1) * ps);
-               }
-               break;
-       default:
-               *cropped_offset = (line_length * ps * crop->top) /
-                       vr_ps + (crop->left * ps) / vr_ps +
-                       ((crop->width / vr_ps) - 1) * ps;
-               break;
+               vout->ps = ps;
+
+               *cropped_offset = (line_length * ps) *
+                       crop->top + crop->left * ps;
        }
+
        v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "%s Offset:%x\n",
-                       __func__, *cropped_offset);
+                       __func__, vout->cropped_offset);
+
        return 0;
 }
 
@@ -664,7 +363,7 @@ static int video_mode_to_dss_mode(struct omap_vout_device *vout)
 /*
  * Setup the overlay
  */
-int omapvid_setup_overlay(struct omap_vout_device *vout,
+static int omapvid_setup_overlay(struct omap_vout_device *vout,
                struct omap_overlay *ovl, int posx, int posy, int outw,
                int outh, u32 addr)
 {
@@ -687,7 +386,7 @@ int omapvid_setup_overlay(struct omap_vout_device *vout,
        /* Setup the input plane parameters according to
         * rotation value selected.
         */
-       if (rotate_90_or_270(vout)) {
+       if (is_rotation_90_or_270(vout)) {
                cropheight = vout->crop.width;
                cropwidth = vout->crop.height;
                pixheight = vout->pix.width;
@@ -711,7 +410,7 @@ int omapvid_setup_overlay(struct omap_vout_device *vout,
        info.out_width = outw;
        info.out_height = outh;
        info.global_alpha = vout->win.global_alpha;
-       if (!rotation_enabled(vout)) {
+       if (!is_rotation_enabled(vout)) {
                info.rotation = 0;
                info.rotation_type = OMAP_DSS_ROT_DMA;
                info.screen_width = pixwidth;
@@ -744,7 +443,7 @@ setup_ovl_err:
 /*
  * Initialize the overlay structure
  */
-int omapvid_init(struct omap_vout_device *vout, u32 addr)
+static int omapvid_init(struct omap_vout_device *vout, u32 addr)
 {
        int ret = 0, i;
        struct v4l2_window *win;
@@ -809,7 +508,7 @@ omapvid_init_err:
 /*
  * Apply the changes set the go bit of DSS
  */
-int omapvid_apply_changes(struct omap_vout_device *vout)
+static int omapvid_apply_changes(struct omap_vout_device *vout)
 {
        int i;
        struct omap_overlay *ovl;
@@ -825,7 +524,7 @@ int omapvid_apply_changes(struct omap_vout_device *vout)
        return 0;
 }
 
-void omap_vout_isr(void *arg, unsigned int irqstatus)
+static void omap_vout_isr(void *arg, unsigned int irqstatus)
 {
        int ret;
        u32 addr, fid;
@@ -848,10 +547,20 @@ void omap_vout_isr(void *arg, unsigned int irqstatus)
 
        spin_lock(&vout->vbq_lock);
        do_gettimeofday(&timevalue);
-       if (cur_display->type == OMAP_DISPLAY_TYPE_DPI) {
-               if (!(irqstatus & DISPC_IRQ_VSYNC))
-                       goto vout_isr_err;
 
+       if (cur_display->type != OMAP_DISPLAY_TYPE_VENC) {
+               switch (cur_display->type) {
+               case OMAP_DISPLAY_TYPE_DPI:
+                       if (!(irqstatus & (DISPC_IRQ_VSYNC | DISPC_IRQ_VSYNC2)))
+                               goto vout_isr_err;
+                       break;
+               case OMAP_DISPLAY_TYPE_HDMI:
+                       if (!(irqstatus & DISPC_IRQ_EVSYNC_EVEN))
+                               goto vout_isr_err;
+                       break;
+               default:
+                       goto vout_isr_err;
+               }
                if (!vout->first_int && (vout->cur_frm != vout->next_frm)) {
                        vout->cur_frm->ts = timevalue;
                        vout->cur_frm->state = VIDEOBUF_DONE;
@@ -875,7 +584,7 @@ void omap_vout_isr(void *arg, unsigned int irqstatus)
                ret = omapvid_init(vout, addr);
                if (ret)
                        printk(KERN_ERR VOUT_NAME
-                                       "failed to set overlay info\n");
+                               "failed to set overlay info\n");
                /* Enable the pipeline and set the Go bit */
                ret = omapvid_apply_changes(vout);
                if (ret)
@@ -954,6 +663,7 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
        int startindex = 0, i, j;
        u32 phy_addr = 0, virt_addr = 0;
        struct omap_vout_device *vout = q->priv_data;
+       struct omapvideo_info *ovid = &vout->vid_info;
 
        if (!vout)
                return -EINVAL;
@@ -966,13 +676,10 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
        if (V4L2_MEMORY_MMAP == vout->memory && *count < startindex)
                *count = startindex;
 
-       if ((rotation_enabled(vout)) && *count > VRFB_NUM_BUFS)
-               *count = VRFB_NUM_BUFS;
-
-       /* If rotation is enabled, allocate memory for VRFB space also */
-       if (rotation_enabled(vout))
+       if (ovid->rotation_type == VOUT_ROT_VRFB) {
                if (omap_vout_vrfb_buffer_setup(vout, count, startindex))
                        return -ENOMEM;
+       }
 
        if (V4L2_MEMORY_MMAP != vout->memory)
                return 0;
@@ -996,8 +703,11 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
                virt_addr = omap_vout_alloc_buffer(vout->buffer_size,
                                &phy_addr);
                if (!virt_addr) {
-                       if (!rotation_enabled(vout))
+                       if (ovid->rotation_type == VOUT_ROT_NONE) {
                                break;
+                       } else {
+                               if (!is_rotation_enabled(vout))
+                                       break;
                        /* Free the VRFB buffers if no space for V4L2 buffers */
                        for (j = i; j < *count; j++) {
                                omap_vout_free_buffer(
@@ -1005,6 +715,7 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
                                                vout->smsshado_size);
                                vout->smsshado_virt_addr[j] = 0;
                                vout->smsshado_phy_addr[j] = 0;
+                               }
                        }
                }
                vout->buf_virt_addr[i] = virt_addr;
@@ -1017,9 +728,9 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
 
 /*
  * Free the V4L2 buffers additionally allocated than default
- * number of buffers and free all the VRFB buffers
+ * number of buffers
  */
-static void omap_vout_free_allbuffers(struct omap_vout_device *vout)
+static void omap_vout_free_extra_buffers(struct omap_vout_device *vout)
 {
        int num_buffers = 0, i;
 
@@ -1034,20 +745,6 @@ static void omap_vout_free_allbuffers(struct omap_vout_device *vout)
                vout->buf_virt_addr[i] = 0;
                vout->buf_phy_addr[i] = 0;
        }
-       /* Free the VRFB buffers only if they are allocated
-        * during reqbufs.  Don't free if init time allocated
-        */
-       if (!vout->vrfb_static_allocation) {
-               for (i = 0; i < VRFB_NUM_BUFS; i++) {
-                       if (vout->smsshado_virt_addr[i]) {
-                               omap_vout_free_buffer(
-                                               vout->smsshado_virt_addr[i],
-                                               vout->smsshado_size);
-                               vout->smsshado_virt_addr[i] = 0;
-                               vout->smsshado_phy_addr[i] = 0;
-                       }
-               }
-       }
        vout->buffer_allocated = num_buffers;
 }
 
@@ -1059,16 +756,11 @@ static void omap_vout_free_allbuffers(struct omap_vout_device *vout)
  * buffer into VRFB memory space before giving it to the DSS.
  */
 static int omap_vout_buffer_prepare(struct videobuf_queue *q,
-                           struct videobuf_buffer *vb,
-                           enum v4l2_field field)
+                       struct videobuf_buffer *vb,
+                       enum v4l2_field field)
 {
-       dma_addr_t dmabuf;
-       struct vid_vrfb_dma *tx;
-       enum dss_rotation rotation;
        struct omap_vout_device *vout = q->priv_data;
-       u32 dest_frame_index = 0, src_element_index = 0;
-       u32 dest_element_index = 0, src_frame_index = 0;
-       u32 elem_count = 0, frame_count = 0, pixsize = 2;
+       struct omapvideo_info *ovid = &vout->vid_info;
 
        if (VIDEOBUF_NEEDS_INIT == vb->state) {
                vb->width = vout->pix.width;
@@ -1087,66 +779,24 @@ static int omap_vout_buffer_prepare(struct videobuf_queue *q,
                vout->queued_buf_addr[vb->i] = (u8 *)
                        omap_vout_uservirt_to_phys(vb->baddr);
        } else {
-               vout->queued_buf_addr[vb->i] = (u8 *)vout->buf_phy_addr[vb->i];
-       }
+               u32 addr, dma_addr;
+               unsigned long size;
 
-       if (!rotation_enabled(vout))
-               return 0;
+               addr = (unsigned long) vout->buf_virt_addr[vb->i];
+               size = (unsigned long) vb->size;
 
-       dmabuf = vout->buf_phy_addr[vb->i];
-       /* If rotation is enabled, copy input buffer into VRFB
-        * memory space using DMA. We are copying input buffer
-        * into VRFB memory space of desired angle and DSS will
-        * read image VRFB memory for 0 degree angle
-        */
-       pixsize = vout->bpp * vout->vrfb_bpp;
-       /*
-        * DMA transfer in double index mode
-        */
+               dma_addr = dma_map_single(vout->vid_dev->v4l2_dev.dev, (void *) addr,
+                               size, DMA_TO_DEVICE);
+               if (dma_mapping_error(vout->vid_dev->v4l2_dev.dev, dma_addr))
+                       v4l2_err(&vout->vid_dev->v4l2_dev, "dma_map_single failed\n");
 
-       /* Frame index */
-       dest_frame_index = ((MAX_PIXELS_PER_LINE * pixsize) -
-                       (vout->pix.width * vout->bpp)) + 1;
-
-       /* Source and destination parameters */
-       src_element_index = 0;
-       src_frame_index = 0;
-       dest_element_index = 1;
-       /* Number of elements per frame */
-       elem_count = vout->pix.width * vout->bpp;
-       frame_count = vout->pix.height;
-       tx = &vout->vrfb_dma_tx;
-       tx->tx_status = 0;
-       omap_set_dma_transfer_params(tx->dma_ch, OMAP_DMA_DATA_TYPE_S32,
-                       (elem_count / 4), frame_count, OMAP_DMA_SYNC_ELEMENT,
-                       tx->dev_id, 0x0);
-       /* src_port required only for OMAP1 */
-       omap_set_dma_src_params(tx->dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
-                       dmabuf, src_element_index, src_frame_index);
-       /*set dma source burst mode for VRFB */
-       omap_set_dma_src_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16);
-       rotation = calc_rotation(vout);
-
-       /* dest_port required only for OMAP1 */
-       omap_set_dma_dest_params(tx->dma_ch, 0, OMAP_DMA_AMODE_DOUBLE_IDX,
-                       vout->vrfb_context[vb->i].paddr[0], dest_element_index,
-                       dest_frame_index);
-       /*set dma dest burst mode for VRFB */
-       omap_set_dma_dest_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16);
-       omap_dma_set_global_params(DMA_DEFAULT_ARB_RATE, 0x20, 0);
-
-       omap_start_dma(tx->dma_ch);
-       interruptible_sleep_on_timeout(&tx->wait, VRFB_TX_TIMEOUT);
-
-       if (tx->tx_status == 0) {
-               omap_stop_dma(tx->dma_ch);
-               return -EINVAL;
+               vout->queued_buf_addr[vb->i] = (u8 *)vout->buf_phy_addr[vb->i];
        }
-       /* Store buffers physical address into an array. Addresses
-        * from this array will be used to configure DSS */
-       vout->queued_buf_addr[vb->i] = (u8 *)
-               vout->vrfb_context[vb->i].paddr[rotation];
-       return 0;
+
+       if (ovid->rotation_type == VOUT_ROT_VRFB)
+               return omap_vout_prepare_vrfb(vout, vb);
+       else
+               return 0;
 }
 
 /*
@@ -1298,7 +948,15 @@ static int omap_vout_release(struct file *file)
                                "Unable to apply changes\n");
 
        /* Free all buffers */
-       omap_vout_free_allbuffers(vout);
+       omap_vout_free_extra_buffers(vout);
+
+       /* Free the VRFB buffers only if they are allocated
+        * during reqbufs.  Don't free if init time allocated
+        */
+       if (ovid->rotation_type == VOUT_ROT_VRFB) {
+               if (!vout->vrfb_static_allocation)
+                       omap_vout_free_vrfb_buffers(vout);
+       }
        videobuf_mmap_free(q);
 
        /* Even if apply changes fails we should continue
@@ -1307,7 +965,7 @@ static int omap_vout_release(struct file *file)
                u32 mask = 0;
 
                mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN |
-                       DISPC_IRQ_EVSYNC_ODD;
+                       DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_VSYNC2;
                omap_dispc_unregister_isr(omap_vout_isr, vout, mask);
                vout->streaming = 0;
 
@@ -1383,10 +1041,7 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *fh,
                        struct v4l2_fmtdesc *fmt)
 {
        int index = fmt->index;
-       enum v4l2_buf_type type = fmt->type;
 
-       fmt->index = index;
-       fmt->type = type;
        if (index >= NUM_OUTPUT_FORMATS)
                return -EINVAL;
 
@@ -1457,7 +1112,7 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *fh,
 
        /* We dont support RGB24-packed mode if vrfb rotation
         * is enabled*/
-       if ((rotation_enabled(vout)) &&
+       if ((is_rotation_enabled(vout)) &&
                        f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) {
                ret = -EINVAL;
                goto s_fmt_vid_out_exit;
@@ -1465,7 +1120,7 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *fh,
 
        /* get the framebuffer parameters */
 
-       if (rotate_90_or_270(vout)) {
+       if (is_rotation_90_or_270(vout)) {
                vout->fbuf.fmt.height = timing->x_res;
                vout->fbuf.fmt.width = timing->y_res;
        } else {
@@ -1555,10 +1210,7 @@ static int vidioc_enum_fmt_vid_overlay(struct file *file, void *fh,
                        struct v4l2_fmtdesc *fmt)
 {
        int index = fmt->index;
-       enum v4l2_buf_type type = fmt->type;
 
-       fmt->index = index;
-       fmt->type = type;
        if (index >= NUM_OUTPUT_FORMATS)
                return -EINVAL;
 
@@ -1645,7 +1297,7 @@ static int vidioc_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
        /* get the display device attached to the overlay */
        timing = &ovl->manager->device->panel.timings;
 
-       if (rotate_90_or_270(vout)) {
+       if (is_rotation_90_or_270(vout)) {
                vout->fbuf.fmt.height = timing->x_res;
                vout->fbuf.fmt.width = timing->y_res;
        } else {
@@ -1725,9 +1377,17 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a)
        switch (a->id) {
        case V4L2_CID_ROTATE:
        {
+               struct omapvideo_info *ovid;
                int rotation = a->value;
 
+               ovid = &vout->vid_info;
+
                mutex_lock(&vout->lock);
+               if (rotation && ovid->rotation_type == VOUT_ROT_NONE) {
+                       mutex_unlock(&vout->lock);
+                       ret = -ERANGE;
+                       break;
+               }
 
                if (rotation && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) {
                        mutex_unlock(&vout->lock);
@@ -1783,6 +1443,11 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a)
                ovl = ovid->overlays[0];
 
                mutex_lock(&vout->lock);
+               if (mirror && ovid->rotation_type == VOUT_ROT_NONE) {
+                       mutex_unlock(&vout->lock);
+                       ret = -ERANGE;
+                       break;
+               }
 
                if (mirror  && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) {
                        mutex_unlock(&vout->lock);
@@ -1893,7 +1558,7 @@ static int vidioc_qbuf(struct file *file, void *fh,
                }
        }
 
-       if ((rotation_enabled(vout)) &&
+       if ((is_rotation_enabled(vout)) &&
                        vout->vrfb_dma_tx.req_status == DMA_CHAN_NOT_ALLOTED) {
                v4l2_warn(&vout->vid_dev->v4l2_dev,
                                "DMA Channel not allocated for Rotation\n");
@@ -1908,15 +1573,28 @@ static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
        struct omap_vout_device *vout = fh;
        struct videobuf_queue *q = &vout->vbq;
 
+       int ret;
+       u32 addr;
+       unsigned long size;
+       struct videobuf_buffer *vb;
+
+       vb = q->bufs[b->index];
+
        if (!vout->streaming)
                return -EINVAL;
 
        if (file->f_flags & O_NONBLOCK)
                /* Call videobuf_dqbuf for non blocking mode */
-               return videobuf_dqbuf(q, (struct v4l2_buffer *)b, 1);
+               ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 1);
        else
                /* Call videobuf_dqbuf for  blocking mode */
-               return videobuf_dqbuf(q, (struct v4l2_buffer *)b, 0);
+               ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 0);
+
+       addr = (unsigned long) vout->buf_phy_addr[vb->i];
+       size = (unsigned long) vb->size;
+       dma_unmap_single(vout->vid_dev->v4l2_dev.dev,  addr,
+                               size, DMA_TO_DEVICE);
+       return ret;
 }
 
 static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
@@ -1965,7 +1643,8 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
        addr = (unsigned long) vout->queued_buf_addr[vout->cur_frm->i]
                + vout->cropped_offset;
 
-       mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD;
+       mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD
+               | DISPC_IRQ_VSYNC2;
 
        omap_dispc_register_isr(omap_vout_isr, vout, mask);
 
@@ -2015,7 +1694,8 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
                return -EINVAL;
 
        vout->streaming = 0;
-       mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD;
+       mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD
+               | DISPC_IRQ_VSYNC2;
 
        omap_dispc_unregister_isr(omap_vout_isr, vout, mask);
 
@@ -2228,7 +1908,8 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout)
        vout->mirror = 0;
        vout->control[2].id = V4L2_CID_HFLIP;
        vout->control[2].value = 0;
-       vout->vrfb_bpp = 2;
+       if (vout->vid_info.rotation_type == VOUT_ROT_VRFB)
+               vout->vrfb_bpp = 2;
 
        control[1].id = V4L2_CID_BG_COLOR;
        control[1].value = 0;
@@ -2260,17 +1941,15 @@ static int __init omap_vout_setup_video_bufs(struct platform_device *pdev,
                int vid_num)
 {
        u32 numbuffers;
-       int ret = 0, i, j;
-       int image_width, image_height;
-       struct video_device *vfd;
+       int ret = 0, i;
+       struct omapvideo_info *ovid;
        struct omap_vout_device *vout;
-       int static_vrfb_allocation = 0, vrfb_num_bufs = VRFB_NUM_BUFS;
        struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
        struct omap2video_device *vid_dev =
                container_of(v4l2_dev, struct omap2video_device, v4l2_dev);
 
        vout = vid_dev->vouts[vid_num];
-       vfd = vout->vfd;
+       ovid = &vout->vid_info;
 
        numbuffers = (vid_num == 0) ? video1_numbuffers : video2_numbuffers;
        vout->buffer_size = (vid_num == 0) ? video1_bufsize : video2_bufsize;
@@ -2287,66 +1966,16 @@ static int __init omap_vout_setup_video_bufs(struct platform_device *pdev,
                }
        }
 
-       for (i = 0; i < VRFB_NUM_BUFS; i++) {
-               if (omap_vrfb_request_ctx(&vout->vrfb_context[i])) {
-                       dev_info(&pdev->dev, ": VRFB allocation failed\n");
-                       for (j = 0; j < i; j++)
-                               omap_vrfb_release_ctx(&vout->vrfb_context[j]);
-                       ret = -ENOMEM;
-                       goto free_buffers;
-               }
-       }
        vout->cropped_offset = 0;
 
-       /* Calculate VRFB memory size */
-       /* allocate for worst case size */
-       image_width = VID_MAX_WIDTH / TILE_SIZE;
-       if (VID_MAX_WIDTH % TILE_SIZE)
-               image_width++;
-
-       image_width = image_width * TILE_SIZE;
-       image_height = VID_MAX_HEIGHT / TILE_SIZE;
-
-       if (VID_MAX_HEIGHT % TILE_SIZE)
-               image_height++;
-
-       image_height = image_height * TILE_SIZE;
-       vout->smsshado_size = PAGE_ALIGN(image_width * image_height * 2 * 2);
-
-       /*
-        * Request and Initialize DMA, for DMA based VRFB transfer
-        */
-       vout->vrfb_dma_tx.dev_id = OMAP_DMA_NO_DEVICE;
-       vout->vrfb_dma_tx.dma_ch = -1;
-       vout->vrfb_dma_tx.req_status = DMA_CHAN_ALLOTED;
-       ret = omap_request_dma(vout->vrfb_dma_tx.dev_id, "VRFB DMA TX",
-                       omap_vout_vrfb_dma_tx_callback,
-                       (void *) &vout->vrfb_dma_tx, &vout->vrfb_dma_tx.dma_ch);
-       if (ret < 0) {
-               vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED;
-               dev_info(&pdev->dev, ": failed to allocate DMA Channel for"
-                               " video%d\n", vfd->minor);
-       }
-       init_waitqueue_head(&vout->vrfb_dma_tx.wait);
-
-       /* Allocate VRFB buffers if selected through bootargs */
-       static_vrfb_allocation = (vid_num == 0) ?
-               vid1_static_vrfb_alloc : vid2_static_vrfb_alloc;
-
-       /* statically allocated the VRFB buffer is done through
-          commands line aruments */
-       if (static_vrfb_allocation) {
-               if (omap_vout_allocate_vrfb_buffers(vout, &vrfb_num_bufs, -1)) {
-                       ret =  -ENOMEM;
-                       goto release_vrfb_ctx;
-               }
-               vout->vrfb_static_allocation = 1;
+       if (ovid->rotation_type == VOUT_ROT_VRFB) {
+               int static_vrfb_allocation = (vid_num == 0) ?
+                       vid1_static_vrfb_alloc : vid2_static_vrfb_alloc;
+               ret = omap_vout_setup_vrfb_bufs(pdev, vid_num,
+                               static_vrfb_allocation);
        }
-       return 0;
 
-release_vrfb_ctx:
-       for (j = 0; j < VRFB_NUM_BUFS; j++)
-               omap_vrfb_release_ctx(&vout->vrfb_context[j]);
+       return ret;
 
 free_buffers:
        for (i = 0; i < numbuffers; i++) {
@@ -2389,6 +2018,10 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev)
                vout->vid_info.num_overlays = 1;
                vout->vid_info.id = k + 1;
 
+               /* Set VRFB as rotation_type for omap2 and omap3 */
+               if (cpu_is_omap24xx() || cpu_is_omap34xx())
+                       vout->vid_info.rotation_type = VOUT_ROT_VRFB;
+
                /* Setup the default configuration for the video devices
                 */
                if (omap_vout_setup_video_data(vout) != 0) {
@@ -2422,7 +2055,8 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev)
                        goto success;
 
 error2:
-               omap_vout_release_vrfb(vout);
+               if (vout->vid_info.rotation_type == VOUT_ROT_VRFB)
+                       omap_vout_release_vrfb(vout);
                omap_vout_free_buffers(vout);
 error1:
                video_device_release(vfd);
@@ -2443,11 +2077,13 @@ success:
 static void omap_vout_cleanup_device(struct omap_vout_device *vout)
 {
        struct video_device *vfd;
+       struct omapvideo_info *ovid;
 
        if (!vout)
                return;
 
        vfd = vout->vfd;
+       ovid = &vout->vid_info;
        if (vfd) {
                if (!video_is_registered(vfd)) {
                        /*
@@ -2463,14 +2099,15 @@ static void omap_vout_cleanup_device(struct omap_vout_device *vout)
                        video_unregister_device(vfd);
                }
        }
-
-       omap_vout_release_vrfb(vout);
+       if (ovid->rotation_type == VOUT_ROT_VRFB) {
+               omap_vout_release_vrfb(vout);
+               /* Free the VRFB buffer if allocated
+                * init time
+                */
+               if (vout->vrfb_static_allocation)
+                       omap_vout_free_vrfb_buffers(vout);
+       }
        omap_vout_free_buffers(vout);
-       /* Free the VRFB buffer if allocated
-        * init time
-        */
-       if (vout->vrfb_static_allocation)
-               omap_vout_free_vrfb_buffers(vout);
 
        kfree(vout);
 }
diff --git a/drivers/media/video/omap/omap_vout_vrfb.c b/drivers/media/video/omap/omap_vout_vrfb.c
new file mode 100644 (file)
index 0000000..ebebcac
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ * omap_vout_vrfb.c
+ *
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * 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/sched.h>
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+
+#include <media/videobuf-dma-contig.h>
+#include <media/v4l2-device.h>
+
+#include <plat/dma.h>
+#include <plat/vrfb.h>
+
+#include "omap_voutdef.h"
+#include "omap_voutlib.h"
+
+/*
+ * Function for allocating video buffers
+ */
+static int omap_vout_allocate_vrfb_buffers(struct omap_vout_device *vout,
+               unsigned int *count, int startindex)
+{
+       int i, j;
+
+       for (i = 0; i < *count; i++) {
+               if (!vout->smsshado_virt_addr[i]) {
+                       vout->smsshado_virt_addr[i] =
+                               omap_vout_alloc_buffer(vout->smsshado_size,
+                                               &vout->smsshado_phy_addr[i]);
+               }
+               if (!vout->smsshado_virt_addr[i] && startindex != -1) {
+                       if (V4L2_MEMORY_MMAP == vout->memory && i >= startindex)
+                               break;
+               }
+               if (!vout->smsshado_virt_addr[i]) {
+                       for (j = 0; j < i; j++) {
+                               omap_vout_free_buffer(
+                                               vout->smsshado_virt_addr[j],
+                                               vout->smsshado_size);
+                               vout->smsshado_virt_addr[j] = 0;
+                               vout->smsshado_phy_addr[j] = 0;
+                       }
+                       *count = 0;
+                       return -ENOMEM;
+               }
+               memset((void *) vout->smsshado_virt_addr[i], 0,
+                               vout->smsshado_size);
+       }
+       return 0;
+}
+
+/*
+ * Wakes up the application once the DMA transfer to VRFB space is completed.
+ */
+static void omap_vout_vrfb_dma_tx_callback(int lch, u16 ch_status, void *data)
+{
+       struct vid_vrfb_dma *t = (struct vid_vrfb_dma *) data;
+
+       t->tx_status = 1;
+       wake_up_interruptible(&t->wait);
+}
+
+/*
+ * Free VRFB buffers
+ */
+void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout)
+{
+       int j;
+
+       for (j = 0; j < VRFB_NUM_BUFS; j++) {
+               omap_vout_free_buffer(vout->smsshado_virt_addr[j],
+                               vout->smsshado_size);
+               vout->smsshado_virt_addr[j] = 0;
+               vout->smsshado_phy_addr[j] = 0;
+       }
+}
+
+int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
+                       u32 static_vrfb_allocation)
+{
+       int ret = 0, i, j;
+       struct omap_vout_device *vout;
+       struct video_device *vfd;
+       int image_width, image_height;
+       int vrfb_num_bufs = VRFB_NUM_BUFS;
+       struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
+       struct omap2video_device *vid_dev =
+               container_of(v4l2_dev, struct omap2video_device, v4l2_dev);
+
+       vout = vid_dev->vouts[vid_num];
+       vfd = vout->vfd;
+
+       for (i = 0; i < VRFB_NUM_BUFS; i++) {
+               if (omap_vrfb_request_ctx(&vout->vrfb_context[i])) {
+                       dev_info(&pdev->dev, ": VRFB allocation failed\n");
+                       for (j = 0; j < i; j++)
+                               omap_vrfb_release_ctx(&vout->vrfb_context[j]);
+                       ret = -ENOMEM;
+                       goto free_buffers;
+               }
+       }
+
+       /* Calculate VRFB memory size */
+       /* allocate for worst case size */
+       image_width = VID_MAX_WIDTH / TILE_SIZE;
+       if (VID_MAX_WIDTH % TILE_SIZE)
+               image_width++;
+
+       image_width = image_width * TILE_SIZE;
+       image_height = VID_MAX_HEIGHT / TILE_SIZE;
+
+       if (VID_MAX_HEIGHT % TILE_SIZE)
+               image_height++;
+
+       image_height = image_height * TILE_SIZE;
+       vout->smsshado_size = PAGE_ALIGN(image_width * image_height * 2 * 2);
+
+       /*
+        * Request and Initialize DMA, for DMA based VRFB transfer
+        */
+       vout->vrfb_dma_tx.dev_id = OMAP_DMA_NO_DEVICE;
+       vout->vrfb_dma_tx.dma_ch = -1;
+       vout->vrfb_dma_tx.req_status = DMA_CHAN_ALLOTED;
+       ret = omap_request_dma(vout->vrfb_dma_tx.dev_id, "VRFB DMA TX",
+                       omap_vout_vrfb_dma_tx_callback,
+                       (void *) &vout->vrfb_dma_tx, &vout->vrfb_dma_tx.dma_ch);
+       if (ret < 0) {
+               vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED;
+               dev_info(&pdev->dev, ": failed to allocate DMA Channel for"
+                               " video%d\n", vfd->minor);
+       }
+       init_waitqueue_head(&vout->vrfb_dma_tx.wait);
+
+       /* statically allocated the VRFB buffer is done through
+          commands line aruments */
+       if (static_vrfb_allocation) {
+               if (omap_vout_allocate_vrfb_buffers(vout, &vrfb_num_bufs, -1)) {
+                       ret =  -ENOMEM;
+                       goto release_vrfb_ctx;
+               }
+               vout->vrfb_static_allocation = 1;
+       }
+       return 0;
+
+release_vrfb_ctx:
+       for (j = 0; j < VRFB_NUM_BUFS; j++)
+               omap_vrfb_release_ctx(&vout->vrfb_context[j]);
+free_buffers:
+       omap_vout_free_buffers(vout);
+
+       return ret;
+}
+
+/*
+ * Release the VRFB context once the module exits
+ */
+void omap_vout_release_vrfb(struct omap_vout_device *vout)
+{
+       int i;
+
+       for (i = 0; i < VRFB_NUM_BUFS; i++)
+               omap_vrfb_release_ctx(&vout->vrfb_context[i]);
+
+       if (vout->vrfb_dma_tx.req_status == DMA_CHAN_ALLOTED) {
+               vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED;
+               omap_free_dma(vout->vrfb_dma_tx.dma_ch);
+       }
+}
+
+/*
+ * Allocate the buffers for the VRFB space.  Data is copied from V4L2
+ * buffers to the VRFB buffers using the DMA engine.
+ */
+int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
+                         unsigned int *count, unsigned int startindex)
+{
+       int i;
+       bool yuv_mode;
+
+       if (!is_rotation_enabled(vout))
+               return 0;
+
+       /* If rotation is enabled, allocate memory for VRFB space also */
+       *count = *count > VRFB_NUM_BUFS ? VRFB_NUM_BUFS : *count;
+
+       /* Allocate the VRFB buffers only if the buffers are not
+        * allocated during init time.
+        */
+       if (!vout->vrfb_static_allocation)
+               if (omap_vout_allocate_vrfb_buffers(vout, count, startindex))
+                       return -ENOMEM;
+
+       if (vout->dss_mode == OMAP_DSS_COLOR_YUV2 ||
+                       vout->dss_mode == OMAP_DSS_COLOR_UYVY)
+               yuv_mode = true;
+       else
+               yuv_mode = false;
+
+       for (i = 0; i < *count; i++)
+               omap_vrfb_setup(&vout->vrfb_context[i],
+                               vout->smsshado_phy_addr[i], vout->pix.width,
+                               vout->pix.height, vout->bpp, yuv_mode);
+
+       return 0;
+}
+
+int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
+                               struct videobuf_buffer *vb)
+{
+       dma_addr_t dmabuf;
+       struct vid_vrfb_dma *tx;
+       enum dss_rotation rotation;
+       u32 dest_frame_index = 0, src_element_index = 0;
+       u32 dest_element_index = 0, src_frame_index = 0;
+       u32 elem_count = 0, frame_count = 0, pixsize = 2;
+
+       if (!is_rotation_enabled(vout))
+               return 0;
+
+       dmabuf = vout->buf_phy_addr[vb->i];
+       /* If rotation is enabled, copy input buffer into VRFB
+        * memory space using DMA. We are copying input buffer
+        * into VRFB memory space of desired angle and DSS will
+        * read image VRFB memory for 0 degree angle
+        */
+       pixsize = vout->bpp * vout->vrfb_bpp;
+       /*
+        * DMA transfer in double index mode
+        */
+
+       /* Frame index */
+       dest_frame_index = ((MAX_PIXELS_PER_LINE * pixsize) -
+                       (vout->pix.width * vout->bpp)) + 1;
+
+       /* Source and destination parameters */
+       src_element_index = 0;
+       src_frame_index = 0;
+       dest_element_index = 1;
+       /* Number of elements per frame */
+       elem_count = vout->pix.width * vout->bpp;
+       frame_count = vout->pix.height;
+       tx = &vout->vrfb_dma_tx;
+       tx->tx_status = 0;
+       omap_set_dma_transfer_params(tx->dma_ch, OMAP_DMA_DATA_TYPE_S32,
+                       (elem_count / 4), frame_count, OMAP_DMA_SYNC_ELEMENT,
+                       tx->dev_id, 0x0);
+       /* src_port required only for OMAP1 */
+       omap_set_dma_src_params(tx->dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
+                       dmabuf, src_element_index, src_frame_index);
+       /*set dma source burst mode for VRFB */
+       omap_set_dma_src_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16);
+       rotation = calc_rotation(vout);
+
+       /* dest_port required only for OMAP1 */
+       omap_set_dma_dest_params(tx->dma_ch, 0, OMAP_DMA_AMODE_DOUBLE_IDX,
+                       vout->vrfb_context[vb->i].paddr[0], dest_element_index,
+                       dest_frame_index);
+       /*set dma dest burst mode for VRFB */
+       omap_set_dma_dest_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16);
+       omap_dma_set_global_params(DMA_DEFAULT_ARB_RATE, 0x20, 0);
+
+       omap_start_dma(tx->dma_ch);
+       interruptible_sleep_on_timeout(&tx->wait, VRFB_TX_TIMEOUT);
+
+       if (tx->tx_status == 0) {
+               omap_stop_dma(tx->dma_ch);
+               return -EINVAL;
+       }
+       /* Store buffers physical address into an array. Addresses
+        * from this array will be used to configure DSS */
+       vout->queued_buf_addr[vb->i] = (u8 *)
+               vout->vrfb_context[vb->i].paddr[rotation];
+       return 0;
+}
+
+/*
+ * Calculate the buffer offsets from which the streaming should
+ * start. This offset calculation is mainly required because of
+ * the VRFB 32 pixels alignment with rotation.
+ */
+void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout)
+{
+       enum dss_rotation rotation;
+       bool mirroring = vout->mirror;
+       struct v4l2_rect *crop = &vout->crop;
+       struct v4l2_pix_format *pix = &vout->pix;
+       int *cropped_offset = &vout->cropped_offset;
+       int vr_ps = 1, ps = 2, temp_ps = 2;
+       int offset = 0, ctop = 0, cleft = 0, line_length = 0;
+
+       rotation = calc_rotation(vout);
+
+       if (V4L2_PIX_FMT_YUYV == pix->pixelformat ||
+                       V4L2_PIX_FMT_UYVY == pix->pixelformat) {
+               if (is_rotation_enabled(vout)) {
+                       /*
+                        * ps    - Actual pixel size for YUYV/UYVY for
+                        *         VRFB/Mirroring is 4 bytes
+                        * vr_ps - Virtually pixel size for YUYV/UYVY is
+                        *         2 bytes
+                        */
+                       ps = 4;
+                       vr_ps = 2;
+               } else {
+                       ps = 2; /* otherwise the pixel size is 2 byte */
+               }
+       } else if (V4L2_PIX_FMT_RGB32 == pix->pixelformat) {
+               ps = 4;
+       } else if (V4L2_PIX_FMT_RGB24 == pix->pixelformat) {
+               ps = 3;
+       }
+       vout->ps = ps;
+       vout->vr_ps = vr_ps;
+
+       if (is_rotation_enabled(vout)) {
+               line_length = MAX_PIXELS_PER_LINE;
+               ctop = (pix->height - crop->height) - crop->top;
+               cleft = (pix->width - crop->width) - crop->left;
+       } else {
+               line_length = pix->width;
+       }
+       vout->line_length = line_length;
+       switch (rotation) {
+       case dss_rotation_90_degree:
+               offset = vout->vrfb_context[0].yoffset *
+                       vout->vrfb_context[0].bytespp;
+               temp_ps = ps / vr_ps;
+               if (mirroring == 0) {
+                       *cropped_offset = offset + line_length *
+                               temp_ps * cleft + crop->top * temp_ps;
+               } else {
+                       *cropped_offset = offset + line_length * temp_ps *
+                               cleft + crop->top * temp_ps + (line_length *
+                               ((crop->width / (vr_ps)) - 1) * ps);
+               }
+               break;
+       case dss_rotation_180_degree:
+               offset = ((MAX_PIXELS_PER_LINE * vout->vrfb_context[0].yoffset *
+                       vout->vrfb_context[0].bytespp) +
+                       (vout->vrfb_context[0].xoffset *
+                       vout->vrfb_context[0].bytespp));
+               if (mirroring == 0) {
+                       *cropped_offset = offset + (line_length * ps * ctop) +
+                               (cleft / vr_ps) * ps;
+
+               } else {
+                       *cropped_offset = offset + (line_length * ps * ctop) +
+                               (cleft / vr_ps) * ps + (line_length *
+                               (crop->height - 1) * ps);
+               }
+               break;
+       case dss_rotation_270_degree:
+               offset = MAX_PIXELS_PER_LINE * vout->vrfb_context[0].xoffset *
+                       vout->vrfb_context[0].bytespp;
+               temp_ps = ps / vr_ps;
+               if (mirroring == 0) {
+                       *cropped_offset = offset + line_length *
+                           temp_ps * crop->left + ctop * ps;
+               } else {
+                       *cropped_offset = offset + line_length *
+                               temp_ps * crop->left + ctop * ps +
+                               (line_length * ((crop->width / vr_ps) - 1) *
+                                ps);
+               }
+               break;
+       case dss_rotation_0_degree:
+               if (mirroring == 0) {
+                       *cropped_offset = (line_length * ps) *
+                               crop->top + (crop->left / vr_ps) * ps;
+               } else {
+                       *cropped_offset = (line_length * ps) *
+                               crop->top + (crop->left / vr_ps) * ps +
+                               (line_length * (crop->height - 1) * ps);
+               }
+               break;
+       default:
+               *cropped_offset = (line_length * ps * crop->top) /
+                       vr_ps + (crop->left * ps) / vr_ps +
+                       ((crop->width / vr_ps) - 1) * ps;
+               break;
+       }
+}
diff --git a/drivers/media/video/omap/omap_vout_vrfb.h b/drivers/media/video/omap/omap_vout_vrfb.h
new file mode 100644 (file)
index 0000000..ffde741
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * omap_vout_vrfb.h
+ *
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * 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 OMAP_VOUT_VRFB_H
+#define OMAP_VOUT_VRFB_H
+
+#ifdef CONFIG_VIDEO_OMAP2_VOUT_VRFB
+void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout);
+int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
+                       u32 static_vrfb_allocation);
+void omap_vout_release_vrfb(struct omap_vout_device *vout);
+int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
+                       unsigned int *count, unsigned int startindex);
+int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
+                       struct videobuf_buffer *vb);
+void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout);
+#else
+void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) { }
+int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
+                       u32 static_vrfb_allocation)
+               { return 0; }
+void omap_vout_release_vrfb(struct omap_vout_device *vout) { }
+int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
+                       unsigned int *count, unsigned int startindex)
+               { return 0; }
+int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
+                       struct videobuf_buffer *vb)
+               { return 0; }
+void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout) { }
+#endif
+
+#endif
index 659497b..d793501 100644 (file)
@@ -12,6 +12,7 @@
 #define OMAP_VOUTDEF_H
 
 #include <video/omapdss.h>
+#include <plat/vrfb.h>
 
 #define YUYV_BPP        2
 #define RGB565_BPP      2
 #define MAX_DISPLAYS   3
 #define MAX_MANAGERS   3
 
+#define QQVGA_WIDTH            160
+#define QQVGA_HEIGHT           120
+
+/* Max Resolution supported by the driver */
+#define VID_MAX_WIDTH          1280    /* Largest width */
+#define VID_MAX_HEIGHT         720     /* Largest height */
+
+/* Mimimum requirement is 2x2 for DSS */
+#define VID_MIN_WIDTH          2
+#define VID_MIN_HEIGHT         2
+
+/* 2048 x 2048 is max res supported by OMAP display controller */
+#define MAX_PIXELS_PER_LINE     2048
+
+#define VRFB_TX_TIMEOUT         1000
+#define VRFB_NUM_BUFS          4
+
+/* Max buffer size tobe allocated during init */
+#define OMAP_VOUT_MAX_BUF_SIZE (VID_MAX_WIDTH*VID_MAX_HEIGHT*4)
+
+enum dma_channel_state {
+       DMA_CHAN_NOT_ALLOTED,
+       DMA_CHAN_ALLOTED,
+};
+
 /* Enum for Rotation
  * DSS understands rotation in 0, 1, 2, 3 context
  * while V4L2 driver understands it as 0, 90, 180, 270
@@ -37,6 +63,18 @@ enum dss_rotation {
        dss_rotation_180_degree = 2,
        dss_rotation_270_degree = 3,
 };
+
+/* Enum for choosing rotation type for vout
+ * DSS2 doesn't understand no rotation as an
+ * option while V4L2 driver doesn't support
+ * rotation in the case where VRFB is not built in
+ * the kernel
+ */
+enum vout_rotaion_type {
+       VOUT_ROT_NONE   = 0,
+       VOUT_ROT_VRFB   = 1,
+};
+
 /*
  * This structure is used to store the DMA transfer parameters
  * for VRFB hidden buffer
@@ -53,6 +91,7 @@ struct omapvideo_info {
        int id;
        int num_overlays;
        struct omap_overlay *overlays[MAX_OVLS];
+       enum vout_rotaion_type rotation_type;
 };
 
 struct omap2video_device {
@@ -144,4 +183,43 @@ struct omap_vout_device {
        int io_allowed;
 
 };
+
+/*
+ * Return true if rotation is 90 or 270
+ */
+static inline int is_rotation_90_or_270(const struct omap_vout_device *vout)
+{
+       return (vout->rotation == dss_rotation_90_degree ||
+                       vout->rotation == dss_rotation_270_degree);
+}
+
+/*
+ * Return true if rotation is enabled
+ */
+static inline int is_rotation_enabled(const struct omap_vout_device *vout)
+{
+       return vout->rotation || vout->mirror;
+}
+
+/*
+ * Reverse the rotation degree if mirroring is enabled
+ */
+static inline int calc_rotation(const struct omap_vout_device *vout)
+{
+       if (!vout->mirror)
+               return vout->rotation;
+
+       switch (vout->rotation) {
+       case dss_rotation_90_degree:
+               return dss_rotation_270_degree;
+       case dss_rotation_270_degree:
+               return dss_rotation_90_degree;
+       case dss_rotation_180_degree:
+               return dss_rotation_0_degree;
+       default:
+               return dss_rotation_180_degree;
+       }
+}
+
+void omap_vout_free_buffers(struct omap_vout_device *vout);
 #endif /* ifndef OMAP_VOUTDEF_H */
index 8ae7481..115408b 100644 (file)
 #include <linux/types.h>
 #include <linux/videodev2.h>
 
+#include <linux/dma-mapping.h>
+
 #include <plat/cpu.h>
 
+#include "omap_voutlib.h"
+
 MODULE_AUTHOR("Texas Instruments");
 MODULE_DESCRIPTION("OMAP Video library");
 MODULE_LICENSE("GPL");
@@ -291,3 +295,45 @@ void omap_vout_new_format(struct v4l2_pix_format *pix,
 }
 EXPORT_SYMBOL_GPL(omap_vout_new_format);
 
+/*
+ * Allocate buffers
+ */
+unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr)
+{
+       u32 order, size;
+       unsigned long virt_addr, addr;
+
+       size = PAGE_ALIGN(buf_size);
+       order = get_order(size);
+       virt_addr = __get_free_pages(GFP_KERNEL, order);
+       addr = virt_addr;
+
+       if (virt_addr) {
+               while (size > 0) {
+                       SetPageReserved(virt_to_page(addr));
+                       addr += PAGE_SIZE;
+                       size -= PAGE_SIZE;
+               }
+       }
+       *phys_addr = (u32) virt_to_phys((void *) virt_addr);
+       return virt_addr;
+}
+
+/*
+ * Free buffers
+ */
+void omap_vout_free_buffer(unsigned long virtaddr, u32 buf_size)
+{
+       u32 order, size;
+       unsigned long addr = virtaddr;
+
+       size = PAGE_ALIGN(buf_size);
+       order = get_order(size);
+
+       while (size > 0) {
+               ClearPageReserved(virt_to_page(addr));
+               addr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+       free_pages((unsigned long) virtaddr, order);
+}
index a60b16e..e51750a 100644 (file)
 #ifndef OMAP_VOUTLIB_H
 #define OMAP_VOUTLIB_H
 
-extern void omap_vout_default_crop(struct v4l2_pix_format *pix,
+void omap_vout_default_crop(struct v4l2_pix_format *pix,
                struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop);
 
-extern int omap_vout_new_crop(struct v4l2_pix_format *pix,
+int omap_vout_new_crop(struct v4l2_pix_format *pix,
                struct v4l2_rect *crop, struct v4l2_window *win,
                struct v4l2_framebuffer *fbuf,
                const struct v4l2_rect *new_crop);
 
-extern int omap_vout_try_window(struct v4l2_framebuffer *fbuf,
+int omap_vout_try_window(struct v4l2_framebuffer *fbuf,
                struct v4l2_window *new_win);
 
-extern int omap_vout_new_window(struct v4l2_rect *crop,
+int omap_vout_new_window(struct v4l2_rect *crop,
                struct v4l2_window *win, struct v4l2_framebuffer *fbuf,
                struct v4l2_window *new_win);
 
-extern void omap_vout_new_format(struct v4l2_pix_format *pix,
+void omap_vout_new_format(struct v4l2_pix_format *pix,
                struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop,
                struct v4l2_window *win);
+unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr);
+void omap_vout_free_buffer(unsigned long virtaddr, u32 buf_size);
 #endif /* #ifndef OMAP_VOUTLIB_H */
 
index e7cfc85..8a947e6 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
-#include <linux/version.h>
 
 #include <media/omap1_camera.h>
 #include <media/soc_camera.h>
@@ -38,7 +37,7 @@
 
 
 #define DRIVER_NAME            "omap1-camera"
-#define VERSION_CODE           KERNEL_VERSION(0, 0, 1)
+#define DRIVER_VERSION         "0.0.2"
 
 
 /*
@@ -208,7 +207,7 @@ static int omap1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
        struct soc_camera_device *icd = vq->priv_data;
        int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
                        icd->current_fmt->host_fmt);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct omap1_cam_dev *pcdev = ici->priv;
 
        if (bytes_per_line < 0)
@@ -222,7 +221,7 @@ static int omap1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
        if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024)
                *count = (MAX_VIDEO_MEM * 1024 * 1024) / *size;
 
-       dev_dbg(icd->dev.parent,
+       dev_dbg(icd->parent,
                        "%s: count=%d, size=%d\n", __func__, *count, *size);
 
        return 0;
@@ -241,7 +240,7 @@ static void free_buffer(struct videobuf_queue *vq, struct omap1_cam_buf *buf,
                videobuf_dma_contig_free(vq, vb);
        } else {
                struct soc_camera_device *icd = vq->priv_data;
-               struct device *dev = icd->dev.parent;
+               struct device *dev = icd->parent;
                struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
 
                videobuf_dma_unmap(dev, dma);
@@ -258,7 +257,7 @@ static int omap1_videobuf_prepare(struct videobuf_queue *vq,
        struct omap1_cam_buf *buf = container_of(vb, struct omap1_cam_buf, vb);
        int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
                        icd->current_fmt->host_fmt);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct omap1_cam_dev *pcdev = ici->priv;
        int ret;
 
@@ -490,7 +489,7 @@ static void omap1_videobuf_queue(struct videobuf_queue *vq,
                                                struct videobuf_buffer *vb)
 {
        struct soc_camera_device *icd = vq->priv_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct omap1_cam_dev *pcdev = ici->priv;
        struct omap1_cam_buf *buf;
        u32 mode;
@@ -519,7 +518,7 @@ static void omap1_videobuf_queue(struct videobuf_queue *vq,
        pcdev->active = buf;
        pcdev->ready = NULL;
 
-       dev_dbg(icd->dev.parent,
+       dev_dbg(icd->parent,
                "%s: capture not active, setup FIFO, start DMA\n", __func__);
        mode = CAM_READ_CACHE(pcdev, MODE) & ~THRESHOLD_MASK;
        mode |= THRESHOLD_LEVEL(pcdev->vb_mode) << THRESHOLD_SHIFT;
@@ -543,8 +542,8 @@ static void omap1_videobuf_release(struct videobuf_queue *vq,
        struct omap1_cam_buf *buf =
                        container_of(vb, struct omap1_cam_buf, vb);
        struct soc_camera_device *icd = vq->priv_data;
-       struct device *dev = icd->dev.parent;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct device *dev = icd->parent;
+       struct soc_camera_host *ici = to_soc_camera_host(dev);
        struct omap1_cam_dev *pcdev = ici->priv;
 
        switch (vb->state) {
@@ -573,7 +572,7 @@ static void videobuf_done(struct omap1_cam_dev *pcdev,
 {
        struct omap1_cam_buf *buf = pcdev->active;
        struct videobuf_buffer *vb;
-       struct device *dev = pcdev->icd->dev.parent;
+       struct device *dev = pcdev->icd->parent;
 
        if (WARN_ON(!buf)) {
                suspend_capture(pcdev);
@@ -799,7 +798,7 @@ out:
 static irqreturn_t cam_isr(int irq, void *data)
 {
        struct omap1_cam_dev *pcdev = data;
-       struct device *dev = pcdev->icd->dev.parent;
+       struct device *dev = pcdev->icd->parent;
        struct omap1_cam_buf *buf = pcdev->active;
        u32 it_status;
        unsigned long flags;
@@ -909,7 +908,7 @@ static void sensor_reset(struct omap1_cam_dev *pcdev, bool reset)
  */
 static int omap1_cam_add_device(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct omap1_cam_dev *pcdev = ici->priv;
        u32 ctrlclock;
 
@@ -952,14 +951,14 @@ static int omap1_cam_add_device(struct soc_camera_device *icd)
 
        pcdev->icd = icd;
 
-       dev_dbg(icd->dev.parent, "OMAP1 Camera driver attached to camera %d\n",
+       dev_dbg(icd->parent, "OMAP1 Camera driver attached to camera %d\n",
                        icd->devnum);
        return 0;
 }
 
 static void omap1_cam_remove_device(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct omap1_cam_dev *pcdev = ici->priv;
        u32 ctrlclock;
 
@@ -985,7 +984,7 @@ static void omap1_cam_remove_device(struct soc_camera_device *icd)
 
        pcdev->icd = NULL;
 
-       dev_dbg(icd->dev.parent,
+       dev_dbg(icd->parent,
                "OMAP1 Camera driver detached from camera %d\n", icd->devnum);
 }
 
@@ -1070,7 +1069,7 @@ static int omap1_cam_get_formats(struct soc_camera_device *icd,
                unsigned int idx, struct soc_camera_format_xlate *xlate)
 {
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-       struct device *dev = icd->dev.parent;
+       struct device *dev = icd->parent;
        int formats = 0, ret;
        enum v4l2_mbus_pixelcode code;
        const struct soc_mbus_pixelfmt *fmt;
@@ -1222,9 +1221,9 @@ static int omap1_cam_set_crop(struct soc_camera_device *icd,
        struct v4l2_rect *rect = &crop->c;
        const struct soc_camera_format_xlate *xlate = icd->current_fmt;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct device *dev = icd->parent;
+       struct soc_camera_host *ici = to_soc_camera_host(dev);
        struct omap1_cam_dev *pcdev = ici->priv;
-       struct device *dev = icd->dev.parent;
        struct v4l2_mbus_framefmt mf;
        int ret;
 
@@ -1270,8 +1269,8 @@ static int omap1_cam_set_fmt(struct soc_camera_device *icd,
 {
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        const struct soc_camera_format_xlate *xlate;
-       struct device *dev = icd->dev.parent;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct device *dev = icd->parent;
+       struct soc_camera_host *ici = to_soc_camera_host(dev);
        struct omap1_cam_dev *pcdev = ici->priv;
        struct v4l2_pix_format *pix = &f->fmt.pix;
        struct v4l2_mbus_framefmt mf;
@@ -1326,7 +1325,7 @@ static int omap1_cam_try_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
        if (!xlate) {
-               dev_warn(icd->dev.parent, "Format %#x not found\n",
+               dev_warn(icd->parent, "Format %#x not found\n",
                         pix->pixelformat);
                return -EINVAL;
        }
@@ -1362,7 +1361,7 @@ static int omap1_cam_mmap_mapper(struct videobuf_queue *q,
                                  struct vm_area_struct *vma)
 {
        struct soc_camera_device *icd = q->priv_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct omap1_cam_dev *pcdev = ici->priv;
        int ret;
 
@@ -1377,17 +1376,17 @@ static int omap1_cam_mmap_mapper(struct videobuf_queue *q,
 static void omap1_cam_init_videobuf(struct videobuf_queue *q,
                                     struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct omap1_cam_dev *pcdev = ici->priv;
 
        if (!sg_mode)
                videobuf_queue_dma_contig_init(q, &omap1_videobuf_ops,
-                               icd->dev.parent, &pcdev->lock,
+                               icd->parent, &pcdev->lock,
                                V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
                                sizeof(struct omap1_cam_buf), icd, &icd->video_lock);
        else
                videobuf_queue_sg_init(q, &omap1_videobuf_ops,
-                               icd->dev.parent, &pcdev->lock,
+                               icd->parent, &pcdev->lock,
                                V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
                                sizeof(struct omap1_cam_buf), icd, &icd->video_lock);
 
@@ -1431,7 +1430,6 @@ static int omap1_cam_querycap(struct soc_camera_host *ici,
 {
        /* cap->name is set by the friendly caller:-> */
        strlcpy(cap->card, "OMAP1 Camera", sizeof(cap->card));
-       cap->version = VERSION_CODE;
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
 
        return 0;
@@ -1440,9 +1438,9 @@ static int omap1_cam_querycap(struct soc_camera_host *ici,
 static int omap1_cam_set_bus_param(struct soc_camera_device *icd,
                __u32 pixfmt)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct device *dev = icd->parent;
+       struct soc_camera_host *ici = to_soc_camera_host(dev);
        struct omap1_cam_dev *pcdev = ici->priv;
-       struct device *dev = icd->dev.parent;
        const struct soc_camera_format_xlate *xlate;
        const struct soc_mbus_pixelfmt *fmt;
        unsigned long camera_flags, common_flags;
@@ -1718,4 +1716,5 @@ MODULE_PARM_DESC(sg_mode, "videobuf mode, 0: dma-contig (default), 1: dma-sg");
 MODULE_DESCRIPTION("OMAP1 Camera Interface driver");
 MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>");
 MODULE_LICENSE("GPL v2");
+MODULE_LICENSE(DRIVER_VERSION);
 MODULE_ALIAS("platform:" DRIVER_NAME);
index 69b60ba..eb97bff 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/interrupt.h>
 #include <linux/videodev2.h>
 #include <linux/pci.h>         /* needed for videobufs */
-#include <linux/version.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/io.h>
@@ -43,7 +42,7 @@
 
 #include "omap24xxcam.h"
 
-#define OMAP24XXCAM_VERSION KERNEL_VERSION(0, 0, 0)
+#define OMAP24XXCAM_VERSION "0.0.1"
 
 #define RESET_TIMEOUT_NS 10000
 
@@ -309,11 +308,11 @@ static int omap24xxcam_vbq_alloc_mmap_buffer(struct videobuf_buffer *vb)
                        order--;
 
                /* try to allocate as many contiguous pages as possible */
-               page = alloc_pages(GFP_KERNEL | GFP_DMA, order);
+               page = alloc_pages(GFP_KERNEL, order);
                /* if allocation fails, try to allocate smaller amount */
                while (page == NULL) {
                        order--;
-                       page = alloc_pages(GFP_KERNEL | GFP_DMA, order);
+                       page = alloc_pages(GFP_KERNEL, order);
                        if (page == NULL && !order) {
                                err = -ENOMEM;
                                goto out;
@@ -993,7 +992,6 @@ static int vidioc_querycap(struct file *file, void *fh,
 
        strlcpy(cap->driver, CAM_NAME, sizeof(cap->driver));
        strlcpy(cap->card, cam->vfd->name, sizeof(cap->card));
-       cap->version = OMAP24XXCAM_VERSION;
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
 
        return 0;
@@ -1888,6 +1886,7 @@ static void __exit omap24xxcam_cleanup(void)
 MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
 MODULE_DESCRIPTION("OMAP24xx Video for Linux camera driver");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(OMAP24XXCAM_VERSION);
 module_param(video_nr, int, 0);
 MODULE_PARM_DESC(video_nr,
                 "Minor number for video device (-1 ==> auto assign)");
index 94b6ed8..5cea2bb 100644 (file)
@@ -2234,3 +2234,4 @@ module_exit(isp_cleanup);
 MODULE_AUTHOR("Nokia Corporation");
 MODULE_DESCRIPTION("TI OMAP3 ISP driver");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(ISP_VIDEO_DRIVER_VERSION);
index 2620c40..529e582 100644 (file)
@@ -139,6 +139,10 @@ struct isp_reg {
  *             3 - CAMEXT[13:6] -> CAM[7:0]
  * @clk_pol: Pixel clock polarity
  *             0 - Non Inverted, 1 - Inverted
+ * @hs_pol: Horizontal synchronization polarity
+ *             0 - Active high, 1 - Active low
+ * @vs_pol: Vertical synchronization polarity
+ *             0 - Active high, 1 - Active low
  * @bridge: CCDC Bridge input control
  *             ISPCTRL_PAR_BRIDGE_DISABLE - Disable
  *             ISPCTRL_PAR_BRIDGE_LENDIAN - Little endian
@@ -147,6 +151,8 @@ struct isp_reg {
 struct isp_parallel_platform_data {
        unsigned int data_lane_shift:2;
        unsigned int clk_pol:1;
+       unsigned int hs_pol:1;
+       unsigned int vs_pol:1;
        unsigned int bridge:4;
 };
 
index 39d501b..9d3459d 100644 (file)
@@ -1148,6 +1148,8 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
        omap3isp_configure_bridge(isp, ccdc->input, pdata, shift);
 
        ccdc->syncif.datsz = depth_out;
+       ccdc->syncif.hdpol = pdata ? pdata->hs_pol : 0;
+       ccdc->syncif.vdpol = pdata ? pdata->vs_pol : 0;
        ccdc_config_sync_if(ccdc, &ccdc->syncif);
 
        /* CCDC_PAD_SINK */
@@ -1691,7 +1693,7 @@ static int ccdc_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
        if (sub->type != V4L2_EVENT_OMAP3ISP_HS_VS)
                return -EINVAL;
 
-       return v4l2_event_subscribe(fh, sub);
+       return v4l2_event_subscribe(fh, sub, OMAP3ISP_CCDC_NEVENTS);
 }
 
 static int ccdc_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
@@ -2162,7 +2164,6 @@ static int ccdc_init_entities(struct isp_ccdc_device *ccdc)
        sd->grp_id = 1 << 16;   /* group ID for isp subdevs */
        v4l2_set_subdevdata(sd, ccdc);
        sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
-       sd->nevents = OMAP3ISP_CCDC_NEVENTS;
 
        pads[CCDC_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
        pads[CCDC_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE;
@@ -2257,8 +2258,6 @@ int omap3isp_ccdc_init(struct isp_device *isp)
        ccdc->syncif.fldout = 0;
        ccdc->syncif.fldpol = 0;
        ccdc->syncif.fldstat = 0;
-       ccdc->syncif.hdpol = 0;
-       ccdc->syncif.vdpol = 0;
 
        ccdc->clamp.oblen = 0;
        ccdc->clamp.dcsubval = 0;
index 0e16cab..ec9e395 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/uaccess.h>
+#include <linux/regulator/consumer.h>
 
 #include "isp.h"
 #include "ispreg.h"
@@ -163,6 +164,9 @@ static void ccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable)
        struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity);
        int i;
 
+       if (enable && ccp2->vdds_csib)
+               regulator_enable(ccp2->vdds_csib);
+
        /* Enable/Disable all the LCx channels */
        for (i = 0; i < CCP2_LCx_CHANS_NUM; i++)
                isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(i),
@@ -186,6 +190,9 @@ static void ccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable)
                                    ISPCCP2_LC01_IRQENABLE,
                                    ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ);
        }
+
+       if (!enable && ccp2->vdds_csib)
+               regulator_disable(ccp2->vdds_csib);
 }
 
 /*
@@ -1137,6 +1144,9 @@ error:
  */
 void omap3isp_ccp2_cleanup(struct isp_device *isp)
 {
+       struct isp_ccp2_device *ccp2 = &isp->isp_ccp2;
+
+       regulator_put(ccp2->vdds_csib);
 }
 
 /*
@@ -1151,14 +1161,27 @@ int omap3isp_ccp2_init(struct isp_device *isp)
 
        init_waitqueue_head(&ccp2->wait);
 
-       /* On the OMAP36xx, the CCP2 uses the CSI PHY1 or PHY2, shared with
+       /*
+        * On the OMAP34xx the CSI1 receiver is operated in the CSIb IO
+        * complex, which is powered by vdds_csib power rail. Hence the
+        * request for the regulator.
+        *
+        * On the OMAP36xx, the CCP2 uses the CSI PHY1 or PHY2, shared with
         * the CSI2c or CSI2a receivers. The PHY then needs to be explicitly
         * configured.
         *
         * TODO: Don't hardcode the usage of PHY1 (shared with CSI2c).
         */
-       if (isp->revision == ISP_REVISION_15_0)
+       if (isp->revision == ISP_REVISION_2_0) {
+               ccp2->vdds_csib = regulator_get(isp->dev, "vdds_csib");
+               if (IS_ERR(ccp2->vdds_csib)) {
+                       dev_dbg(isp->dev,
+                               "Could not get regulator vdds_csib\n");
+                       ccp2->vdds_csib = NULL;
+               }
+       } else if (isp->revision == ISP_REVISION_15_0) {
                ccp2->phy = &isp->isp_csiphy1;
+       }
 
        ret = ccp2_init_entities(ccp2);
        if (ret < 0)
index 5505a86..6674e9d 100644 (file)
@@ -81,6 +81,7 @@ struct isp_ccp2_device {
        struct isp_interface_mem_config mem_cfg;
        struct isp_video video_in;
        struct isp_csiphy *phy;
+       struct regulator *vdds_csib;
        unsigned int error;
        enum isp_pipeline_stream_state state;
        wait_queue_head_t wait;
index b44cb68..8080659 100644 (file)
@@ -1032,7 +1032,6 @@ static int isp_stat_init_entities(struct ispstat *stat, const char *name,
        snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "OMAP3 ISP %s", name);
        subdev->grp_id = 1 << 16;       /* group ID for isp subdevs */
        subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
-       subdev->nevents = STAT_NEVENTS;
        v4l2_set_subdevdata(subdev, stat);
 
        stat->pad.flags = MEDIA_PAD_FL_SINK;
@@ -1050,7 +1049,7 @@ int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev,
        if (sub->type != stat->event_type)
                return -EINVAL;
 
-       return v4l2_event_subscribe(fh, sub);
+       return v4l2_event_subscribe(fh, sub, STAT_NEVENTS);
 }
 
 int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev,
index 9cd8f1a..fd965ad 100644 (file)
@@ -695,7 +695,6 @@ isp_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
        strlcpy(cap->driver, ISP_VIDEO_DRIVER_NAME, sizeof(cap->driver));
        strlcpy(cap->card, video->video.name, sizeof(cap->card));
        strlcpy(cap->bus_info, "media", sizeof(cap->bus_info));
-       cap->version = ISP_VIDEO_DRIVER_VERSION;
 
        if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
                cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
index 911bea6..53160aa 100644 (file)
@@ -27,7 +27,6 @@
 #define OMAP3_ISP_VIDEO_H
 
 #include <linux/v4l2-mediabus.h>
-#include <linux/version.h>
 #include <media/media-entity.h>
 #include <media/v4l2-dev.h>
 #include <media/v4l2-fh.h>
@@ -35,7 +34,7 @@
 #include "ispqueue.h"
 
 #define ISP_VIDEO_DRIVER_NAME          "ispvideo"
-#define ISP_VIDEO_DRIVER_VERSION       KERNEL_VERSION(0, 0, 1)
+#define ISP_VIDEO_DRIVER_VERSION       "0.0.2"
 
 struct isp_device;
 struct isp_video;
index 0cea0cf..9ce2fa0 100644 (file)
@@ -1031,16 +1031,9 @@ static int ov2640_video_probe(struct soc_camera_device *icd,
        const char *devname;
        int ret;
 
-       /*
-        * we must have a parent by now. And it cannot be a wrong one.
-        * So this entire test is completely redundant.
-        */
-       if (!icd->dev.parent ||
-           to_soc_camera_host(icd->dev.parent)->nr != icd->iface) {
-               dev_err(&client->dev, "Parent missing or invalid!\n");
-               ret = -ENODEV;
-               goto err;
-       }
+       /* We must have a parent by now. And it cannot be a wrong one. */
+       BUG_ON(!icd->parent ||
+              to_soc_camera_host(icd->parent)->nr != icd->iface);
 
        /*
         * check and show product ID and manufacturer ID
diff --git a/drivers/media/video/ov5642.c b/drivers/media/video/ov5642.c
new file mode 100644 (file)
index 0000000..349a4ad
--- /dev/null
@@ -0,0 +1,1012 @@
+/*
+ * Driver for OV5642 CMOS Image Sensor from Omnivision
+ *
+ * Copyright (C) 2011, Bastian Hecht <hechtb@gmail.com>
+ *
+ * Based on Sony IMX074 Camera Driver
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * Based on Omnivision OV7670 Camera Driver
+ * Copyright (C) 2006-7 Jonathan Corbet <corbet@lwn.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/module.h>
+
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-subdev.h>
+
+/* OV5642 registers */
+#define REG_CHIP_ID_HIGH               0x300a
+#define REG_CHIP_ID_LOW                        0x300b
+
+#define REG_WINDOW_START_X_HIGH                0x3800
+#define REG_WINDOW_START_X_LOW         0x3801
+#define REG_WINDOW_START_Y_HIGH                0x3802
+#define REG_WINDOW_START_Y_LOW         0x3803
+#define REG_WINDOW_WIDTH_HIGH          0x3804
+#define REG_WINDOW_WIDTH_LOW           0x3805
+#define REG_WINDOW_HEIGHT_HIGH                 0x3806
+#define REG_WINDOW_HEIGHT_LOW          0x3807
+#define REG_OUT_WIDTH_HIGH             0x3808
+#define REG_OUT_WIDTH_LOW              0x3809
+#define REG_OUT_HEIGHT_HIGH            0x380a
+#define REG_OUT_HEIGHT_LOW             0x380b
+#define REG_OUT_TOTAL_WIDTH_HIGH       0x380c
+#define REG_OUT_TOTAL_WIDTH_LOW                0x380d
+#define REG_OUT_TOTAL_HEIGHT_HIGH      0x380e
+#define REG_OUT_TOTAL_HEIGHT_LOW       0x380f
+
+/*
+ * define standard resolution.
+ * Works currently only for up to 720 lines
+ * eg. 320x240, 640x480, 800x600, 1280x720, 2048x720
+ */
+
+#define OV5642_WIDTH           1280
+#define OV5642_HEIGHT          720
+#define OV5642_TOTAL_WIDTH     3200
+#define OV5642_TOTAL_HEIGHT    2000
+#define OV5642_SENSOR_SIZE_X   2592
+#define OV5642_SENSOR_SIZE_Y   1944
+
+struct regval_list {
+       u16 reg_num;
+       u8 value;
+};
+
+static struct regval_list ov5642_default_regs_init[] = {
+       { 0x3103, 0x93 },
+       { 0x3008, 0x82 },
+       { 0x3017, 0x7f },
+       { 0x3018, 0xfc },
+       { 0x3810, 0xc2 },
+       { 0x3615, 0xf0 },
+       { 0x3000, 0x0  },
+       { 0x3001, 0x0  },
+       { 0x3002, 0x0  },
+       { 0x3003, 0x0  },
+       { 0x3004, 0xff },
+       { 0x3030, 0x2b },
+       { 0x3011, 0x8  },
+       { 0x3010, 0x10 },
+       { 0x3604, 0x60 },
+       { 0x3622, 0x60 },
+       { 0x3621, 0x9  },
+       { 0x3709, 0x0  },
+       { 0x4000, 0x21 },
+       { 0x401d, 0x22 },
+       { 0x3600, 0x54 },
+       { 0x3605, 0x4  },
+       { 0x3606, 0x3f },
+       { 0x3c01, 0x80 },
+       { 0x300d, 0x22 },
+       { 0x3623, 0x22 },
+       { 0x5000, 0x4f },
+       { 0x5020, 0x4  },
+       { 0x5181, 0x79 },
+       { 0x5182, 0x0  },
+       { 0x5185, 0x22 },
+       { 0x5197, 0x1  },
+       { 0x5500, 0xa  },
+       { 0x5504, 0x0  },
+       { 0x5505, 0x7f },
+       { 0x5080, 0x8  },
+       { 0x300e, 0x18 },
+       { 0x4610, 0x0  },
+       { 0x471d, 0x5  },
+       { 0x4708, 0x6  },
+       { 0x370c, 0xa0 },
+       { 0x5687, 0x94 },
+       { 0x501f, 0x0  },
+       { 0x5000, 0x4f },
+       { 0x5001, 0xcf },
+       { 0x4300, 0x30 },
+       { 0x4300, 0x30 },
+       { 0x460b, 0x35 },
+       { 0x471d, 0x0  },
+       { 0x3002, 0xc  },
+       { 0x3002, 0x0  },
+       { 0x4713, 0x3  },
+       { 0x471c, 0x50 },
+       { 0x4721, 0x2  },
+       { 0x4402, 0x90 },
+       { 0x460c, 0x22 },
+       { 0x3815, 0x44 },
+       { 0x3503, 0x7  },
+       { 0x3501, 0x73 },
+       { 0x3502, 0x80 },
+       { 0x350b, 0x0  },
+       { 0x3818, 0xc8 },
+       { 0x3824, 0x11 },
+       { 0x3a00, 0x78 },
+       { 0x3a1a, 0x4  },
+       { 0x3a13, 0x30 },
+       { 0x3a18, 0x0  },
+       { 0x3a19, 0x7c },
+       { 0x3a08, 0x12 },
+       { 0x3a09, 0xc0 },
+       { 0x3a0a, 0xf  },
+       { 0x3a0b, 0xa0 },
+       { 0x350c, 0x7  },
+       { 0x350d, 0xd0 },
+       { 0x3a0d, 0x8  },
+       { 0x3a0e, 0x6  },
+       { 0x3500, 0x0  },
+       { 0x3501, 0x0  },
+       { 0x3502, 0x0  },
+       { 0x350a, 0x0  },
+       { 0x350b, 0x0  },
+       { 0x3503, 0x0  },
+       { 0x3a0f, 0x3c },
+       { 0x3a10, 0x32 },
+       { 0x3a1b, 0x3c },
+       { 0x3a1e, 0x32 },
+       { 0x3a11, 0x80 },
+       { 0x3a1f, 0x20 },
+       { 0x3030, 0x2b },
+       { 0x3a02, 0x0  },
+       { 0x3a03, 0x7d },
+       { 0x3a04, 0x0  },
+       { 0x3a14, 0x0  },
+       { 0x3a15, 0x7d },
+       { 0x3a16, 0x0  },
+       { 0x3a00, 0x78 },
+       { 0x3a08, 0x9  },
+       { 0x3a09, 0x60 },
+       { 0x3a0a, 0x7  },
+       { 0x3a0b, 0xd0 },
+       { 0x3a0d, 0x10 },
+       { 0x3a0e, 0xd  },
+       { 0x4407, 0x4  },
+       { 0x5193, 0x70 },
+       { 0x589b, 0x0  },
+       { 0x589a, 0xc0 },
+       { 0x401e, 0x20 },
+       { 0x4001, 0x42 },
+       { 0x401c, 0x6  },
+       { 0x3825, 0xac },
+       { 0x3827, 0xc  },
+       { 0x528a, 0x1  },
+       { 0x528b, 0x4  },
+       { 0x528c, 0x8  },
+       { 0x528d, 0x10 },
+       { 0x528e, 0x20 },
+       { 0x528f, 0x28 },
+       { 0x5290, 0x30 },
+       { 0x5292, 0x0  },
+       { 0x5293, 0x1  },
+       { 0x5294, 0x0  },
+       { 0x5295, 0x4  },
+       { 0x5296, 0x0  },
+       { 0x5297, 0x8  },
+       { 0x5298, 0x0  },
+       { 0x5299, 0x10 },
+       { 0x529a, 0x0  },
+       { 0x529b, 0x20 },
+       { 0x529c, 0x0  },
+       { 0x529d, 0x28 },
+       { 0x529e, 0x0  },
+       { 0x529f, 0x30 },
+       { 0x5282, 0x0  },
+       { 0x5300, 0x0  },
+       { 0x5301, 0x20 },
+       { 0x5302, 0x0  },
+       { 0x5303, 0x7c },
+       { 0x530c, 0x0  },
+       { 0x530d, 0xc  },
+       { 0x530e, 0x20 },
+       { 0x530f, 0x80 },
+       { 0x5310, 0x20 },
+       { 0x5311, 0x80 },
+       { 0x5308, 0x20 },
+       { 0x5309, 0x40 },
+       { 0x5304, 0x0  },
+       { 0x5305, 0x30 },
+       { 0x5306, 0x0  },
+       { 0x5307, 0x80 },
+       { 0x5314, 0x8  },
+       { 0x5315, 0x20 },
+       { 0x5319, 0x30 },
+       { 0x5316, 0x10 },
+       { 0x5317, 0x0  },
+       { 0x5318, 0x2  },
+       { 0x5380, 0x1  },
+       { 0x5381, 0x0  },
+       { 0x5382, 0x0  },
+       { 0x5383, 0x4e },
+       { 0x5384, 0x0  },
+       { 0x5385, 0xf  },
+       { 0x5386, 0x0  },
+       { 0x5387, 0x0  },
+       { 0x5388, 0x1  },
+       { 0x5389, 0x15 },
+       { 0x538a, 0x0  },
+       { 0x538b, 0x31 },
+       { 0x538c, 0x0  },
+       { 0x538d, 0x0  },
+       { 0x538e, 0x0  },
+       { 0x538f, 0xf  },
+       { 0x5390, 0x0  },
+       { 0x5391, 0xab },
+       { 0x5392, 0x0  },
+       { 0x5393, 0xa2 },
+       { 0x5394, 0x8  },
+       { 0x5480, 0x14 },
+       { 0x5481, 0x21 },
+       { 0x5482, 0x36 },
+       { 0x5483, 0x57 },
+       { 0x5484, 0x65 },
+       { 0x5485, 0x71 },
+       { 0x5486, 0x7d },
+       { 0x5487, 0x87 },
+       { 0x5488, 0x91 },
+       { 0x5489, 0x9a },
+       { 0x548a, 0xaa },
+       { 0x548b, 0xb8 },
+       { 0x548c, 0xcd },
+       { 0x548d, 0xdd },
+       { 0x548e, 0xea },
+       { 0x548f, 0x1d },
+       { 0x5490, 0x5  },
+       { 0x5491, 0x0  },
+       { 0x5492, 0x4  },
+       { 0x5493, 0x20 },
+       { 0x5494, 0x3  },
+       { 0x5495, 0x60 },
+       { 0x5496, 0x2  },
+       { 0x5497, 0xb8 },
+       { 0x5498, 0x2  },
+       { 0x5499, 0x86 },
+       { 0x549a, 0x2  },
+       { 0x549b, 0x5b },
+       { 0x549c, 0x2  },
+       { 0x549d, 0x3b },
+       { 0x549e, 0x2  },
+       { 0x549f, 0x1c },
+       { 0x54a0, 0x2  },
+       { 0x54a1, 0x4  },
+       { 0x54a2, 0x1  },
+       { 0x54a3, 0xed },
+       { 0x54a4, 0x1  },
+       { 0x54a5, 0xc5 },
+       { 0x54a6, 0x1  },
+       { 0x54a7, 0xa5 },
+       { 0x54a8, 0x1  },
+       { 0x54a9, 0x6c },
+       { 0x54aa, 0x1  },
+       { 0x54ab, 0x41 },
+       { 0x54ac, 0x1  },
+       { 0x54ad, 0x20 },
+       { 0x54ae, 0x0  },
+       { 0x54af, 0x16 },
+       { 0x54b0, 0x1  },
+       { 0x54b1, 0x20 },
+       { 0x54b2, 0x0  },
+       { 0x54b3, 0x10 },
+       { 0x54b4, 0x0  },
+       { 0x54b5, 0xf0 },
+       { 0x54b6, 0x0  },
+       { 0x54b7, 0xdf },
+       { 0x5402, 0x3f },
+       { 0x5403, 0x0  },
+       { 0x3406, 0x0  },
+       { 0x5180, 0xff },
+       { 0x5181, 0x52 },
+       { 0x5182, 0x11 },
+       { 0x5183, 0x14 },
+       { 0x5184, 0x25 },
+       { 0x5185, 0x24 },
+       { 0x5186, 0x6  },
+       { 0x5187, 0x8  },
+       { 0x5188, 0x8  },
+       { 0x5189, 0x7c },
+       { 0x518a, 0x60 },
+       { 0x518b, 0xb2 },
+       { 0x518c, 0xb2 },
+       { 0x518d, 0x44 },
+       { 0x518e, 0x3d },
+       { 0x518f, 0x58 },
+       { 0x5190, 0x46 },
+       { 0x5191, 0xf8 },
+       { 0x5192, 0x4  },
+       { 0x5193, 0x70 },
+       { 0x5194, 0xf0 },
+       { 0x5195, 0xf0 },
+       { 0x5196, 0x3  },
+       { 0x5197, 0x1  },
+       { 0x5198, 0x4  },
+       { 0x5199, 0x12 },
+       { 0x519a, 0x4  },
+       { 0x519b, 0x0  },
+       { 0x519c, 0x6  },
+       { 0x519d, 0x82 },
+       { 0x519e, 0x0  },
+       { 0x5025, 0x80 },
+       { 0x3a0f, 0x38 },
+       { 0x3a10, 0x30 },
+       { 0x3a1b, 0x3a },
+       { 0x3a1e, 0x2e },
+       { 0x3a11, 0x60 },
+       { 0x3a1f, 0x10 },
+       { 0x5688, 0xa6 },
+       { 0x5689, 0x6a },
+       { 0x568a, 0xea },
+       { 0x568b, 0xae },
+       { 0x568c, 0xa6 },
+       { 0x568d, 0x6a },
+       { 0x568e, 0x62 },
+       { 0x568f, 0x26 },
+       { 0x5583, 0x40 },
+       { 0x5584, 0x40 },
+       { 0x5580, 0x2  },
+       { 0x5000, 0xcf },
+       { 0x5800, 0x27 },
+       { 0x5801, 0x19 },
+       { 0x5802, 0x12 },
+       { 0x5803, 0xf  },
+       { 0x5804, 0x10 },
+       { 0x5805, 0x15 },
+       { 0x5806, 0x1e },
+       { 0x5807, 0x2f },
+       { 0x5808, 0x15 },
+       { 0x5809, 0xd  },
+       { 0x580a, 0xa  },
+       { 0x580b, 0x9  },
+       { 0x580c, 0xa  },
+       { 0x580d, 0xc  },
+       { 0x580e, 0x12 },
+       { 0x580f, 0x19 },
+       { 0x5810, 0xb  },
+       { 0x5811, 0x7  },
+       { 0x5812, 0x4  },
+       { 0x5813, 0x3  },
+       { 0x5814, 0x3  },
+       { 0x5815, 0x6  },
+       { 0x5816, 0xa  },
+       { 0x5817, 0xf  },
+       { 0x5818, 0xa  },
+       { 0x5819, 0x5  },
+       { 0x581a, 0x1  },
+       { 0x581b, 0x0  },
+       { 0x581c, 0x0  },
+       { 0x581d, 0x3  },
+       { 0x581e, 0x8  },
+       { 0x581f, 0xc  },
+       { 0x5820, 0xa  },
+       { 0x5821, 0x5  },
+       { 0x5822, 0x1  },
+       { 0x5823, 0x0  },
+       { 0x5824, 0x0  },
+       { 0x5825, 0x3  },
+       { 0x5826, 0x8  },
+       { 0x5827, 0xc  },
+       { 0x5828, 0xe  },
+       { 0x5829, 0x8  },
+       { 0x582a, 0x6  },
+       { 0x582b, 0x4  },
+       { 0x582c, 0x5  },
+       { 0x582d, 0x7  },
+       { 0x582e, 0xb  },
+       { 0x582f, 0x12 },
+       { 0x5830, 0x18 },
+       { 0x5831, 0x10 },
+       { 0x5832, 0xc  },
+       { 0x5833, 0xa  },
+       { 0x5834, 0xb  },
+       { 0x5835, 0xe  },
+       { 0x5836, 0x15 },
+       { 0x5837, 0x19 },
+       { 0x5838, 0x32 },
+       { 0x5839, 0x1f },
+       { 0x583a, 0x18 },
+       { 0x583b, 0x16 },
+       { 0x583c, 0x17 },
+       { 0x583d, 0x1e },
+       { 0x583e, 0x26 },
+       { 0x583f, 0x53 },
+       { 0x5840, 0x10 },
+       { 0x5841, 0xf  },
+       { 0x5842, 0xd  },
+       { 0x5843, 0xc  },
+       { 0x5844, 0xe  },
+       { 0x5845, 0x9  },
+       { 0x5846, 0x11 },
+       { 0x5847, 0x10 },
+       { 0x5848, 0x10 },
+       { 0x5849, 0x10 },
+       { 0x584a, 0x10 },
+       { 0x584b, 0xe  },
+       { 0x584c, 0x10 },
+       { 0x584d, 0x10 },
+       { 0x584e, 0x11 },
+       { 0x584f, 0x10 },
+       { 0x5850, 0xf  },
+       { 0x5851, 0xc  },
+       { 0x5852, 0xf  },
+       { 0x5853, 0x10 },
+       { 0x5854, 0x10 },
+       { 0x5855, 0xf  },
+       { 0x5856, 0xe  },
+       { 0x5857, 0xb  },
+       { 0x5858, 0x10 },
+       { 0x5859, 0xd  },
+       { 0x585a, 0xd  },
+       { 0x585b, 0xc  },
+       { 0x585c, 0xc  },
+       { 0x585d, 0xc  },
+       { 0x585e, 0xb  },
+       { 0x585f, 0xc  },
+       { 0x5860, 0xc  },
+       { 0x5861, 0xc  },
+       { 0x5862, 0xd  },
+       { 0x5863, 0x8  },
+       { 0x5864, 0x11 },
+       { 0x5865, 0x18 },
+       { 0x5866, 0x18 },
+       { 0x5867, 0x19 },
+       { 0x5868, 0x17 },
+       { 0x5869, 0x19 },
+       { 0x586a, 0x16 },
+       { 0x586b, 0x13 },
+       { 0x586c, 0x13 },
+       { 0x586d, 0x12 },
+       { 0x586e, 0x13 },
+       { 0x586f, 0x16 },
+       { 0x5870, 0x14 },
+       { 0x5871, 0x12 },
+       { 0x5872, 0x10 },
+       { 0x5873, 0x11 },
+       { 0x5874, 0x11 },
+       { 0x5875, 0x16 },
+       { 0x5876, 0x14 },
+       { 0x5877, 0x11 },
+       { 0x5878, 0x10 },
+       { 0x5879, 0xf  },
+       { 0x587a, 0x10 },
+       { 0x587b, 0x14 },
+       { 0x587c, 0x13 },
+       { 0x587d, 0x12 },
+       { 0x587e, 0x11 },
+       { 0x587f, 0x11 },
+       { 0x5880, 0x12 },
+       { 0x5881, 0x15 },
+       { 0x5882, 0x14 },
+       { 0x5883, 0x15 },
+       { 0x5884, 0x15 },
+       { 0x5885, 0x15 },
+       { 0x5886, 0x13 },
+       { 0x5887, 0x17 },
+       { 0x3710, 0x10 },
+       { 0x3632, 0x51 },
+       { 0x3702, 0x10 },
+       { 0x3703, 0xb2 },
+       { 0x3704, 0x18 },
+       { 0x370b, 0x40 },
+       { 0x370d, 0x3  },
+       { 0x3631, 0x1  },
+       { 0x3632, 0x52 },
+       { 0x3606, 0x24 },
+       { 0x3620, 0x96 },
+       { 0x5785, 0x7  },
+       { 0x3a13, 0x30 },
+       { 0x3600, 0x52 },
+       { 0x3604, 0x48 },
+       { 0x3606, 0x1b },
+       { 0x370d, 0xb  },
+       { 0x370f, 0xc0 },
+       { 0x3709, 0x1  },
+       { 0x3823, 0x0  },
+       { 0x5007, 0x0  },
+       { 0x5009, 0x0  },
+       { 0x5011, 0x0  },
+       { 0x5013, 0x0  },
+       { 0x519e, 0x0  },
+       { 0x5086, 0x0  },
+       { 0x5087, 0x0  },
+       { 0x5088, 0x0  },
+       { 0x5089, 0x0  },
+       { 0x302b, 0x0  },
+       { 0x3503, 0x7  },
+       { 0x3011, 0x8  },
+       { 0x350c, 0x2  },
+       { 0x350d, 0xe4 },
+       { 0x3621, 0xc9 },
+       { 0x370a, 0x81 },
+       { 0xffff, 0xff },
+};
+
+static struct regval_list ov5642_default_regs_finalise[] = {
+       { 0x3810, 0xc2 },
+       { 0x3818, 0xc9 },
+       { 0x381c, 0x10 },
+       { 0x381d, 0xa0 },
+       { 0x381e, 0x5  },
+       { 0x381f, 0xb0 },
+       { 0x3820, 0x0  },
+       { 0x3821, 0x0  },
+       { 0x3824, 0x11 },
+       { 0x3a08, 0x1b },
+       { 0x3a09, 0xc0 },
+       { 0x3a0a, 0x17 },
+       { 0x3a0b, 0x20 },
+       { 0x3a0d, 0x2  },
+       { 0x3a0e, 0x1  },
+       { 0x401c, 0x4  },
+       { 0x5682, 0x5  },
+       { 0x5683, 0x0  },
+       { 0x5686, 0x2  },
+       { 0x5687, 0xcc },
+       { 0x5001, 0x4f },
+       { 0x589b, 0x6  },
+       { 0x589a, 0xc5 },
+       { 0x3503, 0x0  },
+       { 0x460c, 0x20 },
+       { 0x460b, 0x37 },
+       { 0x471c, 0xd0 },
+       { 0x471d, 0x5  },
+       { 0x3815, 0x1  },
+       { 0x3818, 0xc1 },
+       { 0x501f, 0x0  },
+       { 0x5002, 0xe0 },
+       { 0x4300, 0x32 }, /* UYVY */
+       { 0x3002, 0x1c },
+       { 0x4800, 0x14 },
+       { 0x4801, 0xf  },
+       { 0x3007, 0x3b },
+       { 0x300e, 0x4  },
+       { 0x4803, 0x50 },
+       { 0x3815, 0x1  },
+       { 0x4713, 0x2  },
+       { 0x4842, 0x1  },
+       { 0x300f, 0xe  },
+       { 0x3003, 0x3  },
+       { 0x3003, 0x1  },
+       { 0xffff, 0xff },
+};
+
+struct ov5642_datafmt {
+       enum v4l2_mbus_pixelcode        code;
+       enum v4l2_colorspace            colorspace;
+};
+
+struct ov5642 {
+       struct v4l2_subdev              subdev;
+       const struct ov5642_datafmt     *fmt;
+};
+
+static const struct ov5642_datafmt ov5642_colour_fmts[] = {
+       {V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG},
+};
+
+static struct ov5642 *to_ov5642(const struct i2c_client *client)
+{
+       return container_of(i2c_get_clientdata(client), struct ov5642, subdev);
+}
+
+/* Find a data format by a pixel code in an array */
+static const struct ov5642_datafmt
+                       *ov5642_find_datafmt(enum v4l2_mbus_pixelcode code)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ov5642_colour_fmts); i++)
+               if (ov5642_colour_fmts[i].code == code)
+                       return ov5642_colour_fmts + i;
+
+       return NULL;
+}
+
+static int reg_read(struct i2c_client *client, u16 reg, u8 *val)
+{
+       int ret;
+       /* We have 16-bit i2c addresses - care for endianess */
+       unsigned char data[2] = { reg >> 8, reg & 0xff };
+
+       ret = i2c_master_send(client, data, 2);
+       if (ret < 2) {
+               dev_err(&client->dev, "%s: i2c read error, reg: %x\n",
+                       __func__, reg);
+               return ret < 0 ? ret : -EIO;
+       }
+
+       ret = i2c_master_recv(client, val, 1);
+       if (ret < 1) {
+               dev_err(&client->dev, "%s: i2c read error, reg: %x\n",
+                               __func__, reg);
+               return ret < 0 ? ret : -EIO;
+       }
+       return 0;
+}
+
+static int reg_write(struct i2c_client *client, u16 reg, u8 val)
+{
+       int ret;
+       unsigned char data[3] = { reg >> 8, reg & 0xff, val };
+
+       ret = i2c_master_send(client, data, 3);
+       if (ret < 3) {
+               dev_err(&client->dev, "%s: i2c write error, reg: %x\n",
+                       __func__, reg);
+               return ret < 0 ? ret : -EIO;
+       }
+
+       return 0;
+}
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov5642_get_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+       u8 val;
+
+       if (reg->reg & ~0xffff)
+               return -EINVAL;
+
+       reg->size = 1;
+
+       ret = reg_read(client, reg->reg, &val);
+       if (!ret)
+               reg->val = (__u64)val;
+
+       return ret;
+}
+
+static int ov5642_set_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (reg->reg & ~0xffff || reg->val & ~0xff)
+               return -EINVAL;
+
+       return reg_write(client, reg->reg, reg->val);
+}
+#endif
+
+static int ov5642_write_array(struct i2c_client *client,
+                               struct regval_list *vals)
+{
+       while (vals->reg_num != 0xffff || vals->value != 0xff) {
+               int ret = reg_write(client, vals->reg_num, vals->value);
+               if (ret < 0)
+                       return ret;
+               vals++;
+       }
+       dev_dbg(&client->dev, "Register list loaded\n");
+       return 0;
+}
+
+static int ov5642_set_resolution(struct i2c_client *client)
+{
+       int ret;
+       u8 start_x_high = ((OV5642_SENSOR_SIZE_X - OV5642_WIDTH) / 2) >> 8;
+       u8 start_x_low  = ((OV5642_SENSOR_SIZE_X - OV5642_WIDTH) / 2) & 0xff;
+       u8 start_y_high = ((OV5642_SENSOR_SIZE_Y - OV5642_HEIGHT) / 2) >> 8;
+       u8 start_y_low  = ((OV5642_SENSOR_SIZE_Y - OV5642_HEIGHT) / 2) & 0xff;
+
+       u8 width_high   = OV5642_WIDTH  >> 8;
+       u8 width_low    = OV5642_WIDTH  & 0xff;
+       u8 height_high  = OV5642_HEIGHT >> 8;
+       u8 height_low   = OV5642_HEIGHT & 0xff;
+
+       u8 total_width_high  = OV5642_TOTAL_WIDTH  >> 8;
+       u8 total_width_low   = OV5642_TOTAL_WIDTH  & 0xff;
+       u8 total_height_high = OV5642_TOTAL_HEIGHT >> 8;
+       u8 total_height_low  = OV5642_TOTAL_HEIGHT & 0xff;
+
+       ret = reg_write(client, REG_WINDOW_START_X_HIGH, start_x_high);
+       if (!ret)
+               ret = reg_write(client, REG_WINDOW_START_X_LOW, start_x_low);
+       if (!ret)
+               ret = reg_write(client, REG_WINDOW_START_Y_HIGH, start_y_high);
+       if (!ret)
+               ret = reg_write(client, REG_WINDOW_START_Y_LOW, start_y_low);
+
+       if (!ret)
+               ret = reg_write(client, REG_WINDOW_WIDTH_HIGH, width_high);
+       if (!ret)
+               ret = reg_write(client, REG_WINDOW_WIDTH_LOW , width_low);
+       if (!ret)
+               ret = reg_write(client, REG_WINDOW_HEIGHT_HIGH, height_high);
+       if (!ret)
+               ret = reg_write(client, REG_WINDOW_HEIGHT_LOW,  height_low);
+
+       if (!ret)
+               ret = reg_write(client, REG_OUT_WIDTH_HIGH, width_high);
+       if (!ret)
+               ret = reg_write(client, REG_OUT_WIDTH_LOW , width_low);
+       if (!ret)
+               ret = reg_write(client, REG_OUT_HEIGHT_HIGH, height_high);
+       if (!ret)
+               ret = reg_write(client, REG_OUT_HEIGHT_LOW,  height_low);
+
+       if (!ret)
+               ret = reg_write(client, REG_OUT_TOTAL_WIDTH_HIGH, total_width_high);
+       if (!ret)
+               ret = reg_write(client, REG_OUT_TOTAL_WIDTH_LOW, total_width_low);
+       if (!ret)
+               ret = reg_write(client, REG_OUT_TOTAL_HEIGHT_HIGH, total_height_high);
+       if (!ret)
+               ret = reg_write(client, REG_OUT_TOTAL_HEIGHT_LOW,  total_height_low);
+
+       return ret;
+}
+
+static int ov5642_try_fmt(struct v4l2_subdev *sd,
+                         struct v4l2_mbus_framefmt *mf)
+{
+       const struct ov5642_datafmt *fmt = ov5642_find_datafmt(mf->code);
+
+       dev_dbg(sd->v4l2_dev->dev, "%s(%u) width: %u heigth: %u\n",
+                       __func__, mf->code, mf->width, mf->height);
+
+       if (!fmt) {
+               mf->code        = ov5642_colour_fmts[0].code;
+               mf->colorspace  = ov5642_colour_fmts[0].colorspace;
+       }
+
+       mf->width       = OV5642_WIDTH;
+       mf->height      = OV5642_HEIGHT;
+       mf->field       = V4L2_FIELD_NONE;
+
+       return 0;
+}
+
+static int ov5642_s_fmt(struct v4l2_subdev *sd,
+                       struct v4l2_mbus_framefmt *mf)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov5642 *priv = to_ov5642(client);
+
+       dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code);
+
+       /* MIPI CSI could have changed the format, double-check */
+       if (!ov5642_find_datafmt(mf->code))
+               return -EINVAL;
+
+       ov5642_try_fmt(sd, mf);
+
+       priv->fmt = ov5642_find_datafmt(mf->code);
+
+       ov5642_write_array(client, ov5642_default_regs_init);
+       ov5642_set_resolution(client);
+       ov5642_write_array(client, ov5642_default_regs_finalise);
+
+       return 0;
+}
+
+static int ov5642_g_fmt(struct v4l2_subdev *sd,
+                       struct v4l2_mbus_framefmt *mf)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov5642 *priv = to_ov5642(client);
+
+       const struct ov5642_datafmt *fmt = priv->fmt;
+
+       mf->code        = fmt->code;
+       mf->colorspace  = fmt->colorspace;
+       mf->width       = OV5642_WIDTH;
+       mf->height      = OV5642_HEIGHT;
+       mf->field       = V4L2_FIELD_NONE;
+
+       return 0;
+}
+
+static int ov5642_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+                          enum v4l2_mbus_pixelcode *code)
+{
+       if (index >= ARRAY_SIZE(ov5642_colour_fmts))
+               return -EINVAL;
+
+       *code = ov5642_colour_fmts[index].code;
+       return 0;
+}
+
+static int ov5642_g_chip_ident(struct v4l2_subdev *sd,
+                              struct v4l2_dbg_chip_ident *id)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+               return -EINVAL;
+
+       if (id->match.addr != client->addr)
+               return -ENODEV;
+
+       id->ident       = V4L2_IDENT_OV5642;
+       id->revision    = 0;
+
+       return 0;
+}
+
+static int ov5642_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+       struct v4l2_rect *rect = &a->c;
+
+       a->type         = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       rect->top       = 0;
+       rect->left      = 0;
+       rect->width     = OV5642_WIDTH;
+       rect->height    = OV5642_HEIGHT;
+
+       return 0;
+}
+
+static int ov5642_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+       a->bounds.left                  = 0;
+       a->bounds.top                   = 0;
+       a->bounds.width                 = OV5642_WIDTH;
+       a->bounds.height                = OV5642_HEIGHT;
+       a->defrect                      = a->bounds;
+       a->type                         = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       a->pixelaspect.numerator        = 1;
+       a->pixelaspect.denominator      = 1;
+
+       return 0;
+}
+
+static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = {
+       .s_mbus_fmt     = ov5642_s_fmt,
+       .g_mbus_fmt     = ov5642_g_fmt,
+       .try_mbus_fmt   = ov5642_try_fmt,
+       .enum_mbus_fmt  = ov5642_enum_fmt,
+       .g_crop         = ov5642_g_crop,
+       .cropcap        = ov5642_cropcap,
+};
+
+static struct v4l2_subdev_core_ops ov5642_subdev_core_ops = {
+       .g_chip_ident   = ov5642_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register     = ov5642_get_register,
+       .s_register     = ov5642_set_register,
+#endif
+};
+
+static struct v4l2_subdev_ops ov5642_subdev_ops = {
+       .core   = &ov5642_subdev_core_ops,
+       .video  = &ov5642_subdev_video_ops,
+};
+
+/*
+ * We have to provide soc-camera operations, but we don't have anything to say
+ * there. The MIPI CSI2 driver will provide .query_bus_param and .set_bus_param
+ */
+static unsigned long soc_ov5642_query_bus_param(struct soc_camera_device *icd)
+{
+       return 0;
+}
+
+static int soc_ov5642_set_bus_param(struct soc_camera_device *icd,
+                                unsigned long flags)
+{
+       return -EINVAL;
+}
+
+static struct soc_camera_ops soc_ov5642_ops = {
+       .query_bus_param        = soc_ov5642_query_bus_param,
+       .set_bus_param          = soc_ov5642_set_bus_param,
+};
+
+static int ov5642_video_probe(struct soc_camera_device *icd,
+                             struct i2c_client *client)
+{
+       int ret;
+       u8 id_high, id_low;
+       u16 id;
+
+       /* Read sensor Model ID */
+       ret = reg_read(client, REG_CHIP_ID_HIGH, &id_high);
+       if (ret < 0)
+               return ret;
+
+       id = id_high << 8;
+
+       ret = reg_read(client, REG_CHIP_ID_LOW, &id_low);
+       if (ret < 0)
+               return ret;
+
+       id |= id_low;
+
+       dev_info(&client->dev, "Chip ID 0x%04x detected\n", id);
+
+       if (id != 0x5642)
+               return -ENODEV;
+
+       return 0;
+}
+
+static int ov5642_probe(struct i2c_client *client,
+                       const struct i2c_device_id *did)
+{
+       struct ov5642 *priv;
+       struct soc_camera_device *icd = client->dev.platform_data;
+       struct soc_camera_link *icl;
+       int ret;
+
+       if (!icd) {
+               dev_err(&client->dev, "OV5642: missing soc-camera data!\n");
+               return -EINVAL;
+       }
+
+       icl = to_soc_camera_link(icd);
+       if (!icl) {
+               dev_err(&client->dev, "OV5642: missing platform data!\n");
+               return -EINVAL;
+       }
+
+       priv = kzalloc(sizeof(struct ov5642), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       v4l2_i2c_subdev_init(&priv->subdev, client, &ov5642_subdev_ops);
+
+       icd->ops        = &soc_ov5642_ops;
+       priv->fmt       = &ov5642_colour_fmts[0];
+
+       ret = ov5642_video_probe(icd, client);
+       if (ret < 0)
+               goto error;
+
+       return 0;
+
+error:
+       icd->ops = NULL;
+       kfree(priv);
+       return ret;
+}
+
+static int ov5642_remove(struct i2c_client *client)
+{
+       struct ov5642 *priv = to_ov5642(client);
+       struct soc_camera_device *icd = client->dev.platform_data;
+       struct soc_camera_link *icl = to_soc_camera_link(icd);
+
+       icd->ops = NULL;
+       if (icl->free_bus)
+               icl->free_bus(icl);
+       kfree(priv);
+
+       return 0;
+}
+
+static const struct i2c_device_id ov5642_id[] = {
+       { "ov5642", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ov5642_id);
+
+static struct i2c_driver ov5642_i2c_driver = {
+       .driver = {
+               .name = "ov5642",
+       },
+       .probe          = ov5642_probe,
+       .remove         = ov5642_remove,
+       .id_table       = ov5642_id,
+};
+
+static int __init ov5642_mod_init(void)
+{
+       return i2c_add_driver(&ov5642_i2c_driver);
+}
+
+static void __exit ov5642_mod_exit(void)
+{
+       i2c_del_driver(&ov5642_i2c_driver);
+}
+
+module_init(ov5642_mod_init);
+module_exit(ov5642_mod_exit);
+
+MODULE_DESCRIPTION("Omnivision OV5642 Camera driver");
+MODULE_AUTHOR("Bastian Hecht <hechtb@gmail.com>");
+MODULE_LICENSE("GPL v2");
index d4e7c11..8aa0585 100644 (file)
@@ -19,8 +19,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
 #include <media/v4l2-mediabus.h>
-
-#include "ov7670.h"
+#include <media/ov7670.h>
 
 MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
 MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors");
index 48895ef..397870f 100644 (file)
@@ -1032,13 +1032,9 @@ static int ov772x_video_probe(struct soc_camera_device *icd,
        u8                  pid, ver;
        const char         *devname;
 
-       /*
-        * We must have a parent by now. And it cannot be a wrong one.
-        * So this entire test is completely redundant.
-        */
-       if (!icd->dev.parent ||
-           to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
-               return -ENODEV;
+       /* We must have a parent by now. And it cannot be a wrong one. */
+       BUG_ON(!icd->parent ||
+              to_soc_camera_host(icd->parent)->nr != icd->iface);
 
        /*
         * check and show product ID and manufacturer ID
index 5173ac4..3681a6f 100644 (file)
@@ -657,16 +657,9 @@ static int ov9640_video_probe(struct soc_camera_device *icd,
        const char      *devname;
        int             ret = 0;
 
-       /*
-        * We must have a parent by now. And it cannot be a wrong one.
-        * So this entire test is completely redundant.
-        */
-       if (!icd->dev.parent ||
-           to_soc_camera_host(icd->dev.parent)->nr != icd->iface) {
-               dev_err(&client->dev, "Parent missing or invalid!\n");
-               ret = -ENODEV;
-               goto err;
-       }
+       /* We must have a parent by now. And it cannot be a wrong one. */
+       BUG_ON(!icd->parent ||
+              to_soc_camera_host(icd->parent)->nr != icd->iface);
 
        /*
         * check and show product ID and manufacturer ID
index 4d4ee4f..edd1ffc 100644 (file)
 #define OV9740_Y_ADDR_START_LO         0x0347
 #define OV9740_X_ADDR_END_HI           0x0348
 #define OV9740_X_ADDR_END_LO           0x0349
-#define OV9740_Y_ADDR_END_HI           0x034A
-#define OV9740_Y_ADDR_END_LO           0x034B
-#define OV9740_X_OUTPUT_SIZE_HI                0x034C
-#define OV9740_X_OUTPUT_SIZE_LO                0x034D
-#define OV9740_Y_OUTPUT_SIZE_HI                0x034E
-#define OV9740_Y_OUTPUT_SIZE_LO                0x034F
+#define OV9740_Y_ADDR_END_HI           0x034a
+#define OV9740_Y_ADDR_END_LO           0x034b
+#define OV9740_X_OUTPUT_SIZE_HI                0x034c
+#define OV9740_X_OUTPUT_SIZE_LO                0x034d
+#define OV9740_Y_OUTPUT_SIZE_HI                0x034e
+#define OV9740_Y_OUTPUT_SIZE_LO                0x034f
 
 /* IO Control Registers */
 #define OV9740_IO_CREL00               0x3002
@@ -68,6 +68,7 @@
 #define OV9740_ANALOG_CTRL04           0x3604
 #define OV9740_ANALOG_CTRL10           0x3610
 #define OV9740_ANALOG_CTRL12           0x3612
+#define OV9740_ANALOG_CTRL15           0x3615
 #define OV9740_ANALOG_CTRL20           0x3620
 #define OV9740_ANALOG_CTRL21           0x3621
 #define OV9740_ANALOG_CTRL22           0x3622
 #define OV9740_TIMING_CTRL35           0x3835
 
 /* Banding Filter */
-#define OV9740_AEC_MAXEXPO_60_H                0x3A02
-#define OV9740_AEC_MAXEXPO_60_L                0x3A03
-#define OV9740_AEC_B50_STEP_HI         0x3A08
-#define OV9740_AEC_B50_STEP_LO         0x3A09
-#define OV9740_AEC_B60_STEP_HI         0x3A0A
-#define OV9740_AEC_B60_STEP_LO         0x3A0B
-#define OV9740_AEC_CTRL0D              0x3A0D
-#define OV9740_AEC_CTRL0E              0x3A0E
-#define OV9740_AEC_MAXEXPO_50_H                0x3A14
-#define OV9740_AEC_MAXEXPO_50_L                0x3A15
+#define OV9740_AEC_MAXEXPO_60_H                0x3a02
+#define OV9740_AEC_MAXEXPO_60_L                0x3a03
+#define OV9740_AEC_B50_STEP_HI         0x3a08
+#define OV9740_AEC_B50_STEP_LO         0x3a09
+#define OV9740_AEC_B60_STEP_HI         0x3a0a
+#define OV9740_AEC_B60_STEP_LO         0x3a0b
+#define OV9740_AEC_CTRL0D              0x3a0d
+#define OV9740_AEC_CTRL0E              0x3a0e
+#define OV9740_AEC_MAXEXPO_50_H                0x3a14
+#define OV9740_AEC_MAXEXPO_50_L                0x3a15
 
 /* AEC/AGC Control */
 #define OV9740_AEC_ENABLE              0x3503
-#define OV9740_GAIN_CEILING_01         0x3A18
-#define OV9740_GAIN_CEILING_02         0x3A19
-#define OV9740_AEC_HI_THRESHOLD                0x3A11
-#define OV9740_AEC_3A1A                        0x3A1A
-#define OV9740_AEC_CTRL1B_WPT2         0x3A1B
-#define OV9740_AEC_CTRL0F_WPT          0x3A0F
-#define OV9740_AEC_CTRL10_BPT          0x3A10
-#define OV9740_AEC_CTRL1E_BPT2         0x3A1E
-#define OV9740_AEC_LO_THRESHOLD                0x3A1F
+#define OV9740_GAIN_CEILING_01         0x3a18
+#define OV9740_GAIN_CEILING_02         0x3a19
+#define OV9740_AEC_HI_THRESHOLD                0x3a11
+#define OV9740_AEC_3A1A                        0x3a1a
+#define OV9740_AEC_CTRL1B_WPT2         0x3a1b
+#define OV9740_AEC_CTRL0F_WPT          0x3a0f
+#define OV9740_AEC_CTRL10_BPT          0x3a10
+#define OV9740_AEC_CTRL1E_BPT2         0x3a1e
+#define OV9740_AEC_LO_THRESHOLD                0x3a1f
 
 /* BLC Control */
 #define OV9740_BLC_AUTO_ENABLE         0x4002
 #define OV9740_VT_SYS_CLK_DIV          0x0303
 #define OV9740_VT_PIX_CLK_DIV          0x0301
 #define OV9740_PLL_CTRL3010            0x3010
-#define OV9740_VFIFO_CTRL00            0x460E
+#define OV9740_VFIFO_CTRL00            0x460e
 
 /* ISP Control */
 #define OV9740_ISP_CTRL00              0x5000
 #define OV9740_ISP_CTRL05              0x5005
 #define OV9740_ISP_CTRL12              0x5012
 #define OV9740_ISP_CTRL19              0x5019
-#define OV9740_ISP_CTRL1A              0x501A
-#define OV9740_ISP_CTRL1E              0x501E
-#define OV9740_ISP_CTRL1F              0x501F
+#define OV9740_ISP_CTRL1A              0x501a
+#define OV9740_ISP_CTRL1E              0x501e
+#define OV9740_ISP_CTRL1F              0x501f
 #define OV9740_ISP_CTRL20              0x5020
 #define OV9740_ISP_CTRL21              0x5021
 
 #define OV9740_AWB_ADV_CTRL04          0x5187
 #define OV9740_AWB_ADV_CTRL05          0x5188
 #define OV9740_AWB_ADV_CTRL06          0x5189
-#define OV9740_AWB_ADV_CTRL07          0x518A
-#define OV9740_AWB_ADV_CTRL08          0x518B
-#define OV9740_AWB_ADV_CTRL09          0x518C
-#define OV9740_AWB_ADV_CTRL10          0x518D
-#define OV9740_AWB_ADV_CTRL11          0x518E
-#define OV9740_AWB_CTRL0F              0x518F
+#define OV9740_AWB_ADV_CTRL07          0x518a
+#define OV9740_AWB_ADV_CTRL08          0x518b
+#define OV9740_AWB_ADV_CTRL09          0x518c
+#define OV9740_AWB_ADV_CTRL10          0x518d
+#define OV9740_AWB_ADV_CTRL11          0x518e
+#define OV9740_AWB_CTRL0F              0x518f
 #define OV9740_AWB_CTRL10              0x5190
 #define OV9740_AWB_CTRL11              0x5191
 #define OV9740_AWB_CTRL12              0x5192
 #define OV9740_MIPI_CTRL_3012          0x3012
 #define OV9740_SC_CMMM_MIPI_CTR                0x3014
 
-/* supported resolutions */
-enum {
-       OV9740_VGA,
-       OV9740_720P,
-};
-
-struct ov9740_resolution {
-       unsigned int width;
-       unsigned int height;
-};
-
-static struct ov9740_resolution ov9740_resolutions[] = {
-       [OV9740_VGA] = {
-               .width  = 640,
-               .height = 480,
-       },
-       [OV9740_720P] = {
-               .width  = 1280,
-               .height = 720,
-       },
-};
+#define OV9740_MAX_WIDTH               1280
+#define OV9740_MAX_HEIGHT              720
 
 /* Misc. structures */
 struct ov9740_reg {
@@ -219,9 +201,16 @@ struct ov9740_priv {
 
        bool                            flag_vflip;
        bool                            flag_hflip;
+
+       /* For suspend/resume. */
+       struct v4l2_mbus_framefmt       current_mf;
+       bool                            current_enable;
 };
 
 static const struct ov9740_reg ov9740_defaults[] = {
+       /* Software Reset */
+       { OV9740_SOFTWARE_RESET,        0x01 },
+
        /* Banding Filter */
        { OV9740_AEC_B50_STEP_HI,       0x00 },
        { OV9740_AEC_B50_STEP_LO,       0xe8 },
@@ -241,36 +230,36 @@ static const struct ov9740_reg ov9740_defaults[] = {
        /* Un-documented OV9740 registers */
        { 0x5800, 0x29 }, { 0x5801, 0x25 }, { 0x5802, 0x20 }, { 0x5803, 0x21 },
        { 0x5804, 0x26 }, { 0x5805, 0x2e }, { 0x5806, 0x11 }, { 0x5807, 0x0c },
-       { 0x5808, 0x09 }, { 0x5809, 0x0a }, { 0x580A, 0x0e }, { 0x580B, 0x16 },
-       { 0x580C, 0x06 }, { 0x580D, 0x02 }, { 0x580E, 0x00 }, { 0x580F, 0x00 },
+       { 0x5808, 0x09 }, { 0x5809, 0x0a }, { 0x580a, 0x0e }, { 0x580b, 0x16 },
+       { 0x580c, 0x06 }, { 0x580d, 0x02 }, { 0x580e, 0x00 }, { 0x580f, 0x00 },
        { 0x5810, 0x04 }, { 0x5811, 0x0a }, { 0x5812, 0x05 }, { 0x5813, 0x02 },
        { 0x5814, 0x00 }, { 0x5815, 0x00 }, { 0x5816, 0x03 }, { 0x5817, 0x09 },
-       { 0x5818, 0x0f }, { 0x5819, 0x0a }, { 0x581A, 0x07 }, { 0x581B, 0x08 },
-       { 0x581C, 0x0b }, { 0x581D, 0x14 }, { 0x581E, 0x28 }, { 0x581F, 0x23 },
+       { 0x5818, 0x0f }, { 0x5819, 0x0a }, { 0x581a, 0x07 }, { 0x581b, 0x08 },
+       { 0x581c, 0x0b }, { 0x581d, 0x14 }, { 0x581e, 0x28 }, { 0x581f, 0x23 },
        { 0x5820, 0x1d }, { 0x5821, 0x1e }, { 0x5822, 0x24 }, { 0x5823, 0x2a },
        { 0x5824, 0x4f }, { 0x5825, 0x6f }, { 0x5826, 0x5f }, { 0x5827, 0x7f },
-       { 0x5828, 0x9f }, { 0x5829, 0x5f }, { 0x582A, 0x8f }, { 0x582B, 0x9e },
-       { 0x582C, 0x8f }, { 0x582D, 0x9f }, { 0x582E, 0x4f }, { 0x582F, 0x87 },
+       { 0x5828, 0x9f }, { 0x5829, 0x5f }, { 0x582a, 0x8f }, { 0x582b, 0x9e },
+       { 0x582c, 0x8f }, { 0x582d, 0x9f }, { 0x582e, 0x4f }, { 0x582f, 0x87 },
        { 0x5830, 0x86 }, { 0x5831, 0x97 }, { 0x5832, 0xae }, { 0x5833, 0x3f },
        { 0x5834, 0x8e }, { 0x5835, 0x7c }, { 0x5836, 0x7e }, { 0x5837, 0xaf },
-       { 0x5838, 0x8f }, { 0x5839, 0x8f }, { 0x583A, 0x9f }, { 0x583B, 0x7f },
-       { 0x583C, 0x5f },
+       { 0x5838, 0x8f }, { 0x5839, 0x8f }, { 0x583a, 0x9f }, { 0x583b, 0x7f },
+       { 0x583c, 0x5f },
 
        /* Y Gamma */
        { 0x5480, 0x07 }, { 0x5481, 0x18 }, { 0x5482, 0x2c }, { 0x5483, 0x4e },
        { 0x5484, 0x5e }, { 0x5485, 0x6b }, { 0x5486, 0x77 }, { 0x5487, 0x82 },
-       { 0x5488, 0x8c }, { 0x5489, 0x95 }, { 0x548A, 0xa4 }, { 0x548B, 0xb1 },
-       { 0x548C, 0xc6 }, { 0x548D, 0xd8 }, { 0x548E, 0xe9 },
+       { 0x5488, 0x8c }, { 0x5489, 0x95 }, { 0x548a, 0xa4 }, { 0x548b, 0xb1 },
+       { 0x548c, 0xc6 }, { 0x548d, 0xd8 }, { 0x548e, 0xe9 },
 
        /* UV Gamma */
        { 0x5490, 0x0f }, { 0x5491, 0xff }, { 0x5492, 0x0d }, { 0x5493, 0x05 },
        { 0x5494, 0x07 }, { 0x5495, 0x1a }, { 0x5496, 0x04 }, { 0x5497, 0x01 },
-       { 0x5498, 0x03 }, { 0x5499, 0x53 }, { 0x549A, 0x02 }, { 0x549B, 0xeb },
-       { 0x549C, 0x02 }, { 0x549D, 0xa0 }, { 0x549E, 0x02 }, { 0x549F, 0x67 },
-       { 0x54A0, 0x02 }, { 0x54A1, 0x3b }, { 0x54A2, 0x02 }, { 0x54A3, 0x18 },
-       { 0x54A4, 0x01 }, { 0x54A5, 0xe7 }, { 0x54A6, 0x01 }, { 0x54A7, 0xc3 },
-       { 0x54A8, 0x01 }, { 0x54A9, 0x94 }, { 0x54AA, 0x01 }, { 0x54AB, 0x72 },
-       { 0x54AC, 0x01 }, { 0x54AD, 0x57 },
+       { 0x5498, 0x03 }, { 0x5499, 0x53 }, { 0x549a, 0x02 }, { 0x549b, 0xeb },
+       { 0x549c, 0x02 }, { 0x549d, 0xa0 }, { 0x549e, 0x02 }, { 0x549f, 0x67 },
+       { 0x54a0, 0x02 }, { 0x54a1, 0x3b }, { 0x54a2, 0x02 }, { 0x54a3, 0x18 },
+       { 0x54a4, 0x01 }, { 0x54a5, 0xe7 }, { 0x54a6, 0x01 }, { 0x54a7, 0xc3 },
+       { 0x54a8, 0x01 }, { 0x54a9, 0x94 }, { 0x54aa, 0x01 }, { 0x54ab, 0x72 },
+       { 0x54ac, 0x01 }, { 0x54ad, 0x57 },
 
        /* AWB */
        { OV9740_AWB_CTRL00,            0xf0 },
@@ -296,18 +285,18 @@ static const struct ov9740_reg ov9740_defaults[] = {
        { OV9740_AWB_CTRL14,            0x00 },
 
        /* CIP */
-       { 0x530D, 0x12 },
+       { 0x530d, 0x12 },
 
        /* CMX */
        { 0x5380, 0x01 }, { 0x5381, 0x00 }, { 0x5382, 0x00 }, { 0x5383, 0x17 },
        { 0x5384, 0x00 }, { 0x5385, 0x01 }, { 0x5386, 0x00 }, { 0x5387, 0x00 },
-       { 0x5388, 0x00 }, { 0x5389, 0xe0 }, { 0x538A, 0x00 }, { 0x538B, 0x20 },
-       { 0x538C, 0x00 }, { 0x538D, 0x00 }, { 0x538E, 0x00 }, { 0x538F, 0x16 },
+       { 0x5388, 0x00 }, { 0x5389, 0xe0 }, { 0x538a, 0x00 }, { 0x538b, 0x20 },
+       { 0x538c, 0x00 }, { 0x538d, 0x00 }, { 0x538e, 0x00 }, { 0x538f, 0x16 },
        { 0x5390, 0x00 }, { 0x5391, 0x9c }, { 0x5392, 0x00 }, { 0x5393, 0xa0 },
        { 0x5394, 0x18 },
 
        /* 50/60 Detection */
-       { 0x3C0A, 0x9c }, { 0x3C0B, 0x3f },
+       { 0x3c0a, 0x9c }, { 0x3c0b, 0x3f },
 
        /* Output Select */
        { OV9740_IO_OUTPUT_SEL01,       0x00 },
@@ -333,6 +322,7 @@ static const struct ov9740_reg ov9740_defaults[] = {
        { OV9740_ANALOG_CTRL10,         0xa1 },
        { OV9740_ANALOG_CTRL12,         0x24 },
        { OV9740_ANALOG_CTRL22,         0x9f },
+       { OV9740_ANALOG_CTRL15,         0xf0 },
 
        /* Sensor Control */
        { OV9740_SENSOR_CTRL03,         0x42 },
@@ -385,7 +375,7 @@ static const struct ov9740_reg ov9740_defaults[] = {
        { OV9740_LN_LENGTH_PCK_LO,      0x62 },
 
        /* MIPI Control */
-       { OV9740_MIPI_CTRL00,           0x44 },
+       { OV9740_MIPI_CTRL00,           0x44 }, /* 0x64 for discontinuous clk */
        { OV9740_MIPI_3837,             0x01 },
        { OV9740_MIPI_CTRL01,           0x0f },
        { OV9740_MIPI_CTRL03,           0x05 },
@@ -393,54 +383,9 @@ static const struct ov9740_reg ov9740_defaults[] = {
        { OV9740_VFIFO_RD_CTRL,         0x16 },
        { OV9740_MIPI_CTRL_3012,        0x70 },
        { OV9740_SC_CMMM_MIPI_CTR,      0x01 },
-};
-
-static const struct ov9740_reg ov9740_regs_vga[] = {
-       { OV9740_X_ADDR_START_HI,       0x00 },
-       { OV9740_X_ADDR_START_LO,       0xa0 },
-       { OV9740_Y_ADDR_START_HI,       0x00 },
-       { OV9740_Y_ADDR_START_LO,       0x00 },
-       { OV9740_X_ADDR_END_HI,         0x04 },
-       { OV9740_X_ADDR_END_LO,         0x63 },
-       { OV9740_Y_ADDR_END_HI,         0x02 },
-       { OV9740_Y_ADDR_END_LO,         0xd3 },
-       { OV9740_X_OUTPUT_SIZE_HI,      0x02 },
-       { OV9740_X_OUTPUT_SIZE_LO,      0x80 },
-       { OV9740_Y_OUTPUT_SIZE_HI,      0x01 },
-       { OV9740_Y_OUTPUT_SIZE_LO,      0xe0 },
-       { OV9740_ISP_CTRL1E,            0x03 },
-       { OV9740_ISP_CTRL1F,            0xc0 },
-       { OV9740_ISP_CTRL20,            0x02 },
-       { OV9740_ISP_CTRL21,            0xd0 },
-       { OV9740_VFIFO_READ_START_HI,   0x01 },
-       { OV9740_VFIFO_READ_START_LO,   0x40 },
-       { OV9740_ISP_CTRL00,            0xff },
-       { OV9740_ISP_CTRL01,            0xff },
-       { OV9740_ISP_CTRL03,            0xff },
-};
 
-static const struct ov9740_reg ov9740_regs_720p[] = {
-       { OV9740_X_ADDR_START_HI,       0x00 },
-       { OV9740_X_ADDR_START_LO,       0x00 },
-       { OV9740_Y_ADDR_START_HI,       0x00 },
-       { OV9740_Y_ADDR_START_LO,       0x00 },
-       { OV9740_X_ADDR_END_HI,         0x05 },
-       { OV9740_X_ADDR_END_LO,         0x03 },
-       { OV9740_Y_ADDR_END_HI,         0x02 },
-       { OV9740_Y_ADDR_END_LO,         0xd3 },
-       { OV9740_X_OUTPUT_SIZE_HI,      0x05 },
-       { OV9740_X_OUTPUT_SIZE_LO,      0x00 },
-       { OV9740_Y_OUTPUT_SIZE_HI,      0x02 },
-       { OV9740_Y_OUTPUT_SIZE_LO,      0xd0 },
-       { OV9740_ISP_CTRL1E,            0x05 },
-       { OV9740_ISP_CTRL1F,            0x00 },
-       { OV9740_ISP_CTRL20,            0x02 },
-       { OV9740_ISP_CTRL21,            0xd0 },
-       { OV9740_VFIFO_READ_START_HI,   0x02 },
-       { OV9740_VFIFO_READ_START_LO,   0x30 },
-       { OV9740_ISP_CTRL00,            0xff },
-       { OV9740_ISP_CTRL01,            0xef },
-       { OV9740_ISP_CTRL03,            0xff },
+       /* YUYV order */
+       { OV9740_ISP_CTRL19,            0x02 },
 };
 
 static enum v4l2_mbus_pixelcode ov9740_codes[] = {
@@ -537,7 +482,8 @@ static int ov9740_reg_rmw(struct i2c_client *client, u16 reg, u8 set, u8 unset)
        ret = ov9740_reg_read(client, reg, &val);
        if (ret < 0) {
                dev_err(&client->dev,
-                       "[Read]-Modify-Write of register %02x failed!\n", reg);
+                       "[Read]-Modify-Write of register 0x%04x failed!\n",
+                       reg);
                return ret;
        }
 
@@ -547,7 +493,8 @@ static int ov9740_reg_rmw(struct i2c_client *client, u16 reg, u8 set, u8 unset)
        ret = ov9740_reg_write(client, reg, val);
        if (ret < 0) {
                dev_err(&client->dev,
-                       "Read-Modify-[Write] of register %02x failed!\n", reg);
+                       "Read-Modify-[Write] of register 0x%04x failed!\n",
+                       reg);
                return ret;
        }
 
@@ -608,6 +555,8 @@ static int ov9740_s_stream(struct v4l2_subdev *sd, int enable)
                                               0x00);
        }
 
+       priv->current_enable = enable;
+
        return ret;
 }
 
@@ -630,126 +579,127 @@ static unsigned long ov9740_query_bus_param(struct soc_camera_device *icd)
        return soc_camera_apply_sensor_flags(icl, flags);
 }
 
-/* Get status of additional camera capabilities */
-static int ov9740_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-       struct ov9740_priv *priv = to_ov9740(sd);
-
-       switch (ctrl->id) {
-       case V4L2_CID_VFLIP:
-               ctrl->value = priv->flag_vflip;
-               break;
-       case V4L2_CID_HFLIP:
-               ctrl->value = priv->flag_hflip;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/* Set status of additional camera capabilities */
-static int ov9740_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-       struct ov9740_priv *priv = to_ov9740(sd);
-
-       switch (ctrl->id) {
-       case V4L2_CID_VFLIP:
-               priv->flag_vflip = ctrl->value;
-               break;
-       case V4L2_CID_HFLIP:
-               priv->flag_hflip = ctrl->value;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/* Get chip identification */
-static int ov9740_g_chip_ident(struct v4l2_subdev *sd,
-                              struct v4l2_dbg_chip_ident *id)
+/* select nearest higher resolution for capture */
+static void ov9740_res_roundup(u32 *width, u32 *height)
 {
-       struct ov9740_priv *priv = to_ov9740(sd);
+       /* Width must be a multiple of 4 pixels. */
+       *width = ALIGN(*width, 4);
 
-       id->ident = priv->ident;
-       id->revision = priv->revision;
+       /* Max resolution is 1280x720 (720p). */
+       if (*width > OV9740_MAX_WIDTH)
+               *width = OV9740_MAX_WIDTH;
 
-       return 0;
+       if (*height > OV9740_MAX_HEIGHT)
+               *height = OV9740_MAX_HEIGHT;
 }
 
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int ov9740_get_register(struct v4l2_subdev *sd,
-                              struct v4l2_dbg_register *reg)
+/* Setup registers according to resolution and color encoding */
+static int ov9740_set_res(struct i2c_client *client, u32 width, u32 height)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       u32 x_start;
+       u32 y_start;
+       u32 x_end;
+       u32 y_end;
+       bool scaling = 0;
+       u32 scale_input_x;
+       u32 scale_input_y;
        int ret;
-       u8 val;
-
-       if (reg->reg & ~0xffff)
-               return -EINVAL;
 
-       reg->size = 2;
-
-       ret = ov9740_reg_read(client, reg->reg, &val);
-       if (ret)
-               return ret;
-
-       reg->val = (__u64)val;
+       if ((width != OV9740_MAX_WIDTH) || (height != OV9740_MAX_HEIGHT))
+               scaling = 1;
 
-       return ret;
-}
-
-static int ov9740_set_register(struct v4l2_subdev *sd,
-                              struct v4l2_dbg_register *reg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       /*
+        * Try to use as much of the sensor area as possible when supporting
+        * smaller resolutions.  Depending on the aspect ratio of the
+        * chosen resolution, we can either use the full width of the sensor,
+        * or the full height of the sensor (or both if the aspect ratio is
+        * the same as 1280x720.
+        */
+       if ((OV9740_MAX_WIDTH * height) > (OV9740_MAX_HEIGHT * width)) {
+               scale_input_x = (OV9740_MAX_HEIGHT * width) / height;
+               scale_input_y = OV9740_MAX_HEIGHT;
+       } else {
+               scale_input_x = OV9740_MAX_WIDTH;
+               scale_input_y = (OV9740_MAX_WIDTH * height) / width;
+       }
 
-       if (reg->reg & ~0xffff || reg->val & ~0xff)
-               return -EINVAL;
+       /* These describe the area of the sensor to use. */
+       x_start = (OV9740_MAX_WIDTH - scale_input_x) / 2;
+       y_start = (OV9740_MAX_HEIGHT - scale_input_y) / 2;
+       x_end = x_start + scale_input_x - 1;
+       y_end = y_start + scale_input_y - 1;
 
-       return ov9740_reg_write(client, reg->reg, reg->val);
-}
-#endif
+       ret = ov9740_reg_write(client, OV9740_X_ADDR_START_HI, x_start >> 8);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_X_ADDR_START_LO, x_start & 0xff);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_Y_ADDR_START_HI, y_start >> 8);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_Y_ADDR_START_LO, y_start & 0xff);
+       if (ret)
+               goto done;
 
-/* select nearest higher resolution for capture */
-static void ov9740_res_roundup(u32 *width, u32 *height)
-{
-       int i;
+       ret = ov9740_reg_write(client, OV9740_X_ADDR_END_HI, x_end >> 8);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_X_ADDR_END_LO, x_end & 0xff);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_Y_ADDR_END_HI, y_end >> 8);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_Y_ADDR_END_LO, y_end & 0xff);
+       if (ret)
+               goto done;
 
-       for (i = 0; i < ARRAY_SIZE(ov9740_resolutions); i++)
-               if ((ov9740_resolutions[i].width >= *width) &&
-                   (ov9740_resolutions[i].height >= *height)) {
-                       *width = ov9740_resolutions[i].width;
-                       *height = ov9740_resolutions[i].height;
-                       return;
-               }
+       ret = ov9740_reg_write(client, OV9740_X_OUTPUT_SIZE_HI, width >> 8);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_X_OUTPUT_SIZE_LO, width & 0xff);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_Y_OUTPUT_SIZE_HI, height >> 8);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_Y_OUTPUT_SIZE_LO, height & 0xff);
+       if (ret)
+               goto done;
 
-       *width = ov9740_resolutions[OV9740_720P].width;
-       *height = ov9740_resolutions[OV9740_720P].height;
-}
+       ret = ov9740_reg_write(client, OV9740_ISP_CTRL1E, scale_input_x >> 8);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_ISP_CTRL1F, scale_input_x & 0xff);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_ISP_CTRL20, scale_input_y >> 8);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_ISP_CTRL21, scale_input_y & 0xff);
+       if (ret)
+               goto done;
 
-/* Setup registers according to resolution and color encoding */
-static int ov9740_set_res(struct i2c_client *client, u32 width)
-{
-       int ret;
+       ret = ov9740_reg_write(client, OV9740_VFIFO_READ_START_HI,
+                              (scale_input_x - width) >> 8);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_VFIFO_READ_START_LO,
+                              (scale_input_x - width) & 0xff);
+       if (ret)
+               goto done;
 
-       /* select register configuration for given resolution */
-       if (width == ov9740_resolutions[OV9740_VGA].width) {
-               dev_dbg(&client->dev, "Setting image size to 640x480\n");
-               ret = ov9740_reg_write_array(client, ov9740_regs_vga,
-                                            ARRAY_SIZE(ov9740_regs_vga));
-       } else if (width == ov9740_resolutions[OV9740_720P].width) {
-               dev_dbg(&client->dev, "Setting image size to 1280x720\n");
-               ret = ov9740_reg_write_array(client, ov9740_regs_720p,
-                                            ARRAY_SIZE(ov9740_regs_720p));
-       } else {
-               dev_err(&client->dev, "Failed to select resolution!\n");
-               return -EINVAL;
-       }
+       ret = ov9740_reg_write(client, OV9740_ISP_CTRL00, 0xff);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_ISP_CTRL01, 0xef |
+                                                         (scaling << 4));
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_ISP_CTRL03, 0xff);
 
+done:
        return ret;
 }
 
@@ -758,6 +708,7 @@ static int ov9740_s_fmt(struct v4l2_subdev *sd,
                        struct v4l2_mbus_framefmt *mf)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov9740_priv *priv = to_ov9740(sd);
        enum v4l2_colorspace cspace;
        enum v4l2_mbus_pixelcode code = mf->code;
        int ret;
@@ -777,13 +728,15 @@ static int ov9740_s_fmt(struct v4l2_subdev *sd,
        if (ret < 0)
                return ret;
 
-       ret = ov9740_set_res(client, mf->width);
+       ret = ov9740_set_res(client, mf->width, mf->height);
        if (ret < 0)
                return ret;
 
        mf->code        = code;
        mf->colorspace  = cspace;
 
+       memcpy(&priv->current_mf, mf, sizeof(struct v4l2_mbus_framefmt));
+
        return ret;
 }
 
@@ -814,8 +767,8 @@ static int ov9740_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
 {
        a->bounds.left          = 0;
        a->bounds.top           = 0;
-       a->bounds.width         = ov9740_resolutions[OV9740_720P].width;
-       a->bounds.height        = ov9740_resolutions[OV9740_720P].height;
+       a->bounds.width         = OV9740_MAX_WIDTH;
+       a->bounds.height        = OV9740_MAX_HEIGHT;
        a->defrect              = a->bounds;
        a->type                 = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        a->pixelaspect.numerator        = 1;
@@ -828,13 +781,115 @@ static int ov9740_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
        a->c.left               = 0;
        a->c.top                = 0;
-       a->c.width              = ov9740_resolutions[OV9740_720P].width;
-       a->c.height             = ov9740_resolutions[OV9740_720P].height;
+       a->c.width              = OV9740_MAX_WIDTH;
+       a->c.height             = OV9740_MAX_HEIGHT;
        a->type                 = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
        return 0;
 }
 
+/* Get status of additional camera capabilities */
+static int ov9740_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct ov9740_priv *priv = to_ov9740(sd);
+
+       switch (ctrl->id) {
+       case V4L2_CID_VFLIP:
+               ctrl->value = priv->flag_vflip;
+               break;
+       case V4L2_CID_HFLIP:
+               ctrl->value = priv->flag_hflip;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* Set status of additional camera capabilities */
+static int ov9740_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct ov9740_priv *priv = to_ov9740(sd);
+
+       switch (ctrl->id) {
+       case V4L2_CID_VFLIP:
+               priv->flag_vflip = ctrl->value;
+               break;
+       case V4L2_CID_HFLIP:
+               priv->flag_hflip = ctrl->value;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* Get chip identification */
+static int ov9740_g_chip_ident(struct v4l2_subdev *sd,
+                              struct v4l2_dbg_chip_ident *id)
+{
+       struct ov9740_priv *priv = to_ov9740(sd);
+
+       id->ident = priv->ident;
+       id->revision = priv->revision;
+
+       return 0;
+}
+
+static int ov9740_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct ov9740_priv *priv = to_ov9740(sd);
+
+       if (!priv->current_enable)
+               return 0;
+
+       if (on) {
+               ov9740_s_fmt(sd, &priv->current_mf);
+               ov9740_s_stream(sd, priv->current_enable);
+       } else {
+               ov9740_s_stream(sd, 0);
+               priv->current_enable = true;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov9740_get_register(struct v4l2_subdev *sd,
+                              struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+       u8 val;
+
+       if (reg->reg & ~0xffff)
+               return -EINVAL;
+
+       reg->size = 2;
+
+       ret = ov9740_reg_read(client, reg->reg, &val);
+       if (ret)
+               return ret;
+
+       reg->val = (__u64)val;
+
+       return ret;
+}
+
+static int ov9740_set_register(struct v4l2_subdev *sd,
+                              struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (reg->reg & ~0xffff || reg->val & ~0xff)
+               return -EINVAL;
+
+       return ov9740_reg_write(client, reg->reg, reg->val);
+}
+#endif
+
 static int ov9740_video_probe(struct soc_camera_device *icd,
                              struct i2c_client *client)
 {
@@ -843,16 +898,9 @@ static int ov9740_video_probe(struct soc_camera_device *icd,
        u8 modelhi, modello;
        int ret;
 
-       /*
-        * We must have a parent by now. And it cannot be a wrong one.
-        * So this entire test is completely redundant.
-        */
-       if (!icd->dev.parent ||
-           to_soc_camera_host(icd->dev.parent)->nr != icd->iface) {
-               dev_err(&client->dev, "Parent missing or invalid!\n");
-               ret = -ENODEV;
-               goto err;
-       }
+       /* We must have a parent by now. And it cannot be a wrong one. */
+       BUG_ON(!icd->parent ||
+              to_soc_camera_host(icd->parent)->nr != icd->iface);
 
        /*
         * check and show product ID and manufacturer ID
@@ -901,24 +949,24 @@ static struct soc_camera_ops ov9740_ops = {
        .num_controls           = ARRAY_SIZE(ov9740_controls),
 };
 
+static struct v4l2_subdev_video_ops ov9740_video_ops = {
+       .s_stream               = ov9740_s_stream,
+       .s_mbus_fmt             = ov9740_s_fmt,
+       .try_mbus_fmt           = ov9740_try_fmt,
+       .enum_mbus_fmt          = ov9740_enum_fmt,
+       .cropcap                = ov9740_cropcap,
+       .g_crop                 = ov9740_g_crop,
+};
+
 static struct v4l2_subdev_core_ops ov9740_core_ops = {
        .g_ctrl                 = ov9740_g_ctrl,
        .s_ctrl                 = ov9740_s_ctrl,
        .g_chip_ident           = ov9740_g_chip_ident,
+       .s_power                = ov9740_s_power,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register             = ov9740_get_register,
        .s_register             = ov9740_set_register,
 #endif
-
-};
-
-static struct v4l2_subdev_video_ops ov9740_video_ops = {
-       .s_stream               = ov9740_s_stream,
-       .s_mbus_fmt             = ov9740_s_fmt,
-       .try_mbus_fmt           = ov9740_try_fmt,
-       .enum_mbus_fmt          = ov9740_enum_fmt,
-       .cropcap                = ov9740_cropcap,
-       .g_crop                 = ov9740_g_crop,
 };
 
 static struct v4l2_subdev_ops ov9740_subdev_ops = {
index 7551907..e753b5e 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
-#include <linux/version.h>
 #include <linux/mutex.h>
 #include <linux/uaccess.h>
 #include <asm/io.h>
@@ -39,7 +38,7 @@
 #include <media/v4l2-device.h>
 
 MODULE_LICENSE("GPL");
-
+MODULE_VERSION("0.0.4");
 
 #define MOTOROLA       1
 #define PHILIPS2       2               /* SAA7191 */
@@ -678,7 +677,6 @@ static int pms_querycap(struct file *file, void  *priv,
        strlcpy(vcap->driver, dev->v4l2_dev.name, sizeof(vcap->driver));
        strlcpy(vcap->card, "Mediavision PMS", sizeof(vcap->card));
        strlcpy(vcap->bus_info, "ISA", sizeof(vcap->bus_info));
-       vcap->version = KERNEL_VERSION(0, 0, 3);
        vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
        return 0;
 }
index 2254194..c1d9bb6 100644 (file)
@@ -168,6 +168,7 @@ module_exit(pvr_exit);
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.9.1");
 
 
 /*
index 3876114..e27f8ab 100644 (file)
@@ -91,7 +91,7 @@ static struct v4l2_capability pvr_capability ={
        .driver         = "pvrusb2",
        .card           = "Hauppauge WinTV pvr-usb2",
        .bus_info       = "usb",
-       .version        = KERNEL_VERSION(0, 9, 0),
+       .version        = LINUX_VERSION_CODE,
        .capabilities   = (V4L2_CAP_VIDEO_CAPTURE |
                           V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
                           V4L2_CAP_READWRITE),
@@ -369,11 +369,6 @@ static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                break;
        }
 
-       case VIDIOC_S_AUDIO:
-       {
-               ret = -EINVAL;
-               break;
-       }
        case VIDIOC_G_TUNER:
        {
                struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
@@ -850,7 +845,7 @@ static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 #endif
 
        default :
-               ret = -EINVAL;
+               ret = -ENOTTY;
                break;
        }
 
index 8da42e4..d63d0a8 100644 (file)
@@ -1,6 +1,7 @@
 config USB_PWC
        tristate "USB Philips Cameras"
        depends on VIDEO_V4L2
+       select VIDEOBUF2_VMALLOC
        ---help---
          Say Y or M here if you want to use one of these Philips & OEM
          webcams:
index 760b4de..3977add 100644 (file)
@@ -3,6 +3,7 @@
    video modes.
    (C) 1999-2003 Nemosoft Unv.
    (C) 2004-2006 Luc Saillard (luc@saillard.org)
+   (C) 2011 Hans de Goede <hdegoede@redhat.com>
 
    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
    driver and thus may have bugs that are not present in the original version.
 #include <asm/errno.h>
 
 #include "pwc.h"
-#include "pwc-uncompress.h"
 #include "pwc-kiara.h"
 #include "pwc-timon.h"
 #include "pwc-dec1.h"
 #include "pwc-dec23.h"
 
-/* Request types: video */
-#define SET_LUM_CTL                    0x01
-#define GET_LUM_CTL                    0x02
-#define SET_CHROM_CTL                  0x03
-#define GET_CHROM_CTL                  0x04
-#define SET_STATUS_CTL                 0x05
-#define GET_STATUS_CTL                 0x06
-#define SET_EP_STREAM_CTL              0x07
-#define GET_EP_STREAM_CTL              0x08
-#define GET_XX_CTL                     0x09
-#define SET_XX_CTL                     0x0A
-#define GET_XY_CTL                     0x0B
-#define SET_XY_CTL                     0x0C
-#define SET_MPT_CTL                    0x0D
-#define GET_MPT_CTL                    0x0E
-
-/* Selectors for the Luminance controls [GS]ET_LUM_CTL */
-#define AGC_MODE_FORMATTER                     0x2000
-#define PRESET_AGC_FORMATTER                   0x2100
-#define SHUTTER_MODE_FORMATTER                 0x2200
-#define PRESET_SHUTTER_FORMATTER               0x2300
-#define PRESET_CONTOUR_FORMATTER               0x2400
-#define AUTO_CONTOUR_FORMATTER                 0x2500
-#define BACK_LIGHT_COMPENSATION_FORMATTER      0x2600
-#define CONTRAST_FORMATTER                     0x2700
-#define DYNAMIC_NOISE_CONTROL_FORMATTER                0x2800
-#define FLICKERLESS_MODE_FORMATTER             0x2900
-#define AE_CONTROL_SPEED                       0x2A00
-#define BRIGHTNESS_FORMATTER                   0x2B00
-#define GAMMA_FORMATTER                                0x2C00
-
-/* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */
-#define WB_MODE_FORMATTER                      0x1000
-#define AWB_CONTROL_SPEED_FORMATTER            0x1100
-#define AWB_CONTROL_DELAY_FORMATTER            0x1200
-#define PRESET_MANUAL_RED_GAIN_FORMATTER       0x1300
-#define PRESET_MANUAL_BLUE_GAIN_FORMATTER      0x1400
-#define COLOUR_MODE_FORMATTER                  0x1500
-#define SATURATION_MODE_FORMATTER1             0x1600
-#define SATURATION_MODE_FORMATTER2             0x1700
-
-/* Selectors for the Status controls [GS]ET_STATUS_CTL */
-#define SAVE_USER_DEFAULTS_FORMATTER           0x0200
-#define RESTORE_USER_DEFAULTS_FORMATTER                0x0300
-#define RESTORE_FACTORY_DEFAULTS_FORMATTER     0x0400
-#define READ_AGC_FORMATTER                     0x0500
-#define READ_SHUTTER_FORMATTER                 0x0600
-#define READ_RED_GAIN_FORMATTER                        0x0700
-#define READ_BLUE_GAIN_FORMATTER               0x0800
+/* Selectors for status controls used only in this file */
 #define GET_STATUS_B00                         0x0B00
 #define SENSOR_TYPE_FORMATTER1                 0x0C00
 #define GET_STATUS_3000                                0x3000
 /* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */
 #define VIDEO_OUTPUT_CONTROL_FORMATTER         0x0100
 
-/* Formatters for the motorized pan & tilt [GS]ET_MPT_CTL */
-#define PT_RELATIVE_CONTROL_FORMATTER          0x01
-#define PT_RESET_CONTROL_FORMATTER             0x02
-#define PT_STATUS_FORMATTER                    0x03
-
 static const char *size2name[PSZ_MAX] =
 {
        "subQCIF",
@@ -160,7 +107,7 @@ static void pwc_set_image_buffer_size(struct pwc_device *pdev);
 /****************************************************************************/
 
 static int _send_control_msg(struct pwc_device *pdev,
-       u8 request, u16 value, int index, void *buf, int buflen, int timeout)
+       u8 request, u16 value, int index, void *buf, int buflen)
 {
        int rc;
        void *kbuf = NULL;
@@ -177,7 +124,7 @@ static int _send_control_msg(struct pwc_device *pdev,
                USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                value,
                index,
-               kbuf, buflen, timeout);
+               kbuf, buflen, USB_CTRL_SET_TIMEOUT);
 
        kfree(kbuf);
        return rc;
@@ -197,9 +144,13 @@ static int recv_control_msg(struct pwc_device *pdev,
                USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                value,
                pdev->vcinterface,
-               kbuf, buflen, 500);
+               kbuf, buflen, USB_CTRL_GET_TIMEOUT);
        memcpy(buf, kbuf, buflen);
        kfree(kbuf);
+
+       if (rc < 0)
+               PWC_ERROR("recv_control_msg error %d req %02x val %04x\n",
+                         rc, request, value);
        return rc;
 }
 
@@ -210,18 +161,16 @@ static inline int send_video_command(struct pwc_device *pdev,
                SET_EP_STREAM_CTL,
                VIDEO_OUTPUT_CONTROL_FORMATTER,
                index,
-               buf, buflen, 1000);
+               buf, buflen);
 }
 
-static inline int send_control_msg(struct pwc_device *pdev,
+int send_control_msg(struct pwc_device *pdev,
        u8 request, u16 value, void *buf, int buflen)
 {
        return _send_control_msg(pdev,
-               request, value, pdev->vcinterface, buf, buflen, 500);
+               request, value, pdev->vcinterface, buf, buflen);
 }
 
-
-
 static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
 {
        unsigned char buf[3];
@@ -261,8 +210,11 @@ static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
                PWC_DEBUG_MODULE("Failed to send video command... %d\n", ret);
                return ret;
        }
-       if (pEntry->compressed && pdev->pixfmt == V4L2_PIX_FMT_YUV420)
-               pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data);
+       if (pEntry->compressed && pdev->pixfmt == V4L2_PIX_FMT_YUV420) {
+               ret = pwc_dec1_init(pdev, pdev->type, pdev->release, buf);
+               if (ret < 0)
+                       return ret;
+       }
 
        pdev->cmd_len = 3;
        memcpy(pdev->cmd_buf, buf, 3);
@@ -321,8 +273,11 @@ static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, i
        if (ret < 0)
                return ret;
 
-       if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420)
-               pwc_dec23_init(pdev, pdev->type, buf);
+       if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420) {
+               ret = pwc_dec23_init(pdev, pdev->type, buf);
+               if (ret < 0)
+                       return ret;
+       }
 
        pdev->cmd_len = 13;
        memcpy(pdev->cmd_buf, buf, 13);
@@ -394,8 +349,11 @@ static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, i
        if (ret < 0)
                return ret;
 
-       if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420)
-               pwc_dec23_init(pdev, pdev->type, buf);
+       if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420) {
+               ret = pwc_dec23_init(pdev, pdev->type, buf);
+               if (ret < 0)
+                       return ret;
+       }
 
        pdev->cmd_len = 12;
        memcpy(pdev->cmd_buf, buf, 12);
@@ -452,6 +410,7 @@ int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frame
        }
        pdev->view.x = width;
        pdev->view.y = height;
+       pdev->vcompression = compression;
        pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size;
        pwc_set_image_buffer_size(pdev);
        PWC_DEBUG_SIZE("Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y);
@@ -511,13 +470,9 @@ unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned i
        return ret;
 }
 
-#define BLACK_Y 0
-#define BLACK_U 128
-#define BLACK_V 128
-
 static void pwc_set_image_buffer_size(struct pwc_device *pdev)
 {
-       int i, factor = 0;
+       int factor = 0;
 
        /* for V4L2_PIX_FMT_YUV420 */
        switch (pdev->pixfmt) {
@@ -541,442 +496,108 @@ static void pwc_set_image_buffer_size(struct pwc_device *pdev)
         */
        pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC;
        pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE;
-
-       /* Fill buffers with black colors */
-       for (i = 0; i < pwc_mbufs; i++) {
-               unsigned char *p = pdev->image_data + pdev->images[i].offset;
-               memset(p, BLACK_Y, pdev->view.x * pdev->view.y);
-               p += pdev->view.x * pdev->view.y;
-               memset(p, BLACK_U, pdev->view.x * pdev->view.y/4);
-               p += pdev->view.x * pdev->view.y/4;
-               memset(p, BLACK_V, pdev->view.x * pdev->view.y/4);
-       }
 }
 
-
-
-/* BRIGHTNESS */
-
-int pwc_get_brightness(struct pwc_device *pdev)
+int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
 {
-       char buf;
        int ret;
+       u8 buf;
 
-       ret = recv_control_msg(pdev,
-               GET_LUM_CTL, BRIGHTNESS_FORMATTER, &buf, sizeof(buf));
+       ret = recv_control_msg(pdev, request, value, &buf, sizeof(buf));
        if (ret < 0)
                return ret;
-       return buf;
-}
 
-int pwc_set_brightness(struct pwc_device *pdev, int value)
-{
-       char buf;
-
-       if (value < 0)
-               value = 0;
-       if (value > 0xffff)
-               value = 0xffff;
-       buf = (value >> 9) & 0x7f;
-       return send_control_msg(pdev,
-               SET_LUM_CTL, BRIGHTNESS_FORMATTER, &buf, sizeof(buf));
+       *data = buf;
+       return 0;
 }
 
-/* CONTRAST */
-
-int pwc_get_contrast(struct pwc_device *pdev)
+int pwc_set_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, u8 data)
 {
-       char buf;
        int ret;
 
-       ret = recv_control_msg(pdev,
-               GET_LUM_CTL, CONTRAST_FORMATTER, &buf, sizeof(buf));
+       ret = send_control_msg(pdev, request, value, &data, sizeof(data));
        if (ret < 0)
                return ret;
-       return buf;
-}
 
-int pwc_set_contrast(struct pwc_device *pdev, int value)
-{
-       char buf;
-
-       if (value < 0)
-               value = 0;
-       if (value > 0xffff)
-               value = 0xffff;
-       buf = (value >> 10) & 0x3f;
-       return send_control_msg(pdev,
-               SET_LUM_CTL, CONTRAST_FORMATTER, &buf, sizeof(buf));
+       return 0;
 }
 
-/* GAMMA */
-
-int pwc_get_gamma(struct pwc_device *pdev)
+int pwc_get_s8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
 {
-       char buf;
        int ret;
+       s8 buf;
 
-       ret = recv_control_msg(pdev,
-               GET_LUM_CTL, GAMMA_FORMATTER, &buf, sizeof(buf));
+       ret = recv_control_msg(pdev, request, value, &buf, sizeof(buf));
        if (ret < 0)
                return ret;
-       return buf;
-}
-
-int pwc_set_gamma(struct pwc_device *pdev, int value)
-{
-       char buf;
 
-       if (value < 0)
-               value = 0;
-       if (value > 0xffff)
-               value = 0xffff;
-       buf = (value >> 11) & 0x1f;
-       return send_control_msg(pdev,
-               SET_LUM_CTL, GAMMA_FORMATTER, &buf, sizeof(buf));
-}
-
-
-/* SATURATION */
-
-/* return a value between [-100 , 100] */
-int pwc_get_saturation(struct pwc_device *pdev, int *value)
-{
-       char buf;
-       int ret, saturation_register;
-
-       if (pdev->type < 675)
-               return -EINVAL;
-       if (pdev->type < 730)
-               saturation_register = SATURATION_MODE_FORMATTER2;
-       else
-               saturation_register = SATURATION_MODE_FORMATTER1;
-       ret = recv_control_msg(pdev,
-               GET_CHROM_CTL, saturation_register, &buf, sizeof(buf));
-       if (ret < 0)
-               return ret;
-       *value = (signed)buf;
+       *data = buf;
        return 0;
 }
 
-/* @param value saturation color between [-100 , 100] */
-int pwc_set_saturation(struct pwc_device *pdev, int value)
+int pwc_get_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
 {
-       char buf;
-       int saturation_register;
-
-       if (pdev->type < 675)
-               return -EINVAL;
-       if (value < -100)
-               value = -100;
-       if (value > 100)
-               value = 100;
-       if (pdev->type < 730)
-               saturation_register = SATURATION_MODE_FORMATTER2;
-       else
-               saturation_register = SATURATION_MODE_FORMATTER1;
-       return send_control_msg(pdev,
-               SET_CHROM_CTL, saturation_register, &buf, sizeof(buf));
-}
-
-/* AGC */
-
-int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
-{
-       char buf;
        int ret;
+       u8 buf[2];
 
-       if (mode)
-               buf = 0x0; /* auto */
-       else
-               buf = 0xff; /* fixed */
-
-       ret = send_control_msg(pdev,
-               SET_LUM_CTL, AGC_MODE_FORMATTER, &buf, sizeof(buf));
-
-       if (!mode && ret >= 0) {
-               if (value < 0)
-                       value = 0;
-               if (value > 0xffff)
-                       value = 0xffff;
-               buf = (value >> 10) & 0x3F;
-               ret = send_control_msg(pdev,
-                       SET_LUM_CTL, PRESET_AGC_FORMATTER, &buf, sizeof(buf));
-       }
+       ret = recv_control_msg(pdev, request, value, buf, sizeof(buf));
        if (ret < 0)
                return ret;
+
+       *data = (buf[1] << 8) | buf[0];
        return 0;
 }
 
-int pwc_get_agc(struct pwc_device *pdev, int *value)
+int pwc_set_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, u16 data)
 {
-       unsigned char buf;
        int ret;
+       u8 buf[2];
 
-       ret = recv_control_msg(pdev,
-               GET_LUM_CTL, AGC_MODE_FORMATTER, &buf, sizeof(buf));
+       buf[0] = data & 0xff;
+       buf[1] = data >> 8;
+       ret = send_control_msg(pdev, request, value, buf, sizeof(buf));
        if (ret < 0)
                return ret;
 
-       if (buf != 0) { /* fixed */
-               ret = recv_control_msg(pdev,
-                       GET_LUM_CTL, PRESET_AGC_FORMATTER, &buf, sizeof(buf));
-               if (ret < 0)
-                       return ret;
-               if (buf > 0x3F)
-                       buf = 0x3F;
-               *value = (buf << 10);
-       }
-       else { /* auto */
-               ret = recv_control_msg(pdev,
-                       GET_STATUS_CTL, READ_AGC_FORMATTER, &buf, sizeof(buf));
-               if (ret < 0)
-                       return ret;
-               /* Gah... this value ranges from 0x00 ... 0x9F */
-               if (buf > 0x9F)
-                       buf = 0x9F;
-               *value = -(48 + buf * 409);
-       }
-
        return 0;
 }
 
-int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value)
-{
-       char buf[2];
-       int speed, ret;
-
-
-       if (mode)
-               buf[0] = 0x0;   /* auto */
-       else
-               buf[0] = 0xff; /* fixed */
-
-       ret = send_control_msg(pdev,
-               SET_LUM_CTL, SHUTTER_MODE_FORMATTER, &buf, 1);
-
-       if (!mode && ret >= 0) {
-               if (value < 0)
-                       value = 0;
-               if (value > 0xffff)
-                       value = 0xffff;
-
-               if (DEVICE_USE_CODEC2(pdev->type)) {
-                       /* speed ranges from 0x0 to 0x290 (656) */
-                       speed = (value / 100);
-                       buf[1] = speed >> 8;
-                       buf[0] = speed & 0xff;
-               } else if (DEVICE_USE_CODEC3(pdev->type)) {
-                       /* speed seems to range from 0x0 to 0xff */
-                       buf[1] = 0;
-                       buf[0] = value >> 8;
-               }
-
-               ret = send_control_msg(pdev,
-                       SET_LUM_CTL, PRESET_SHUTTER_FORMATTER,
-                       &buf, sizeof(buf));
-       }
-       return ret;
-}
-
-/* This function is not exported to v4l1, so output values between 0 -> 256 */
-int pwc_get_shutter_speed(struct pwc_device *pdev, int *value)
+int pwc_button_ctrl(struct pwc_device *pdev, u16 value)
 {
-       unsigned char buf[2];
        int ret;
 
-       ret = recv_control_msg(pdev,
-               GET_STATUS_CTL, READ_SHUTTER_FORMATTER, &buf, sizeof(buf));
+       ret = send_control_msg(pdev, SET_STATUS_CTL, value, NULL, 0);
        if (ret < 0)
                return ret;
-       *value = buf[0] + (buf[1] << 8);
-       if (DEVICE_USE_CODEC2(pdev->type)) {
-               /* speed ranges from 0x0 to 0x290 (656) */
-               *value *= 256/656;
-       } else if (DEVICE_USE_CODEC3(pdev->type)) {
-               /* speed seems to range from 0x0 to 0xff */
-       }
+
        return 0;
 }
 
-
 /* POWER */
-
-int pwc_camera_power(struct pwc_device *pdev, int power)
+void pwc_camera_power(struct pwc_device *pdev, int power)
 {
        char buf;
+       int r;
+
+       if (!pdev->power_save)
+               return;
 
        if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6))
-               return 0;       /* Not supported by Nala or Timon < release 6 */
+               return; /* Not supported by Nala or Timon < release 6 */
 
        if (power)
                buf = 0x00; /* active */
        else
                buf = 0xFF; /* power save */
-       return send_control_msg(pdev,
+       r = send_control_msg(pdev,
                SET_STATUS_CTL, SET_POWER_SAVE_MODE_FORMATTER,
                &buf, sizeof(buf));
-}
-
-
-
-/* private calls */
-
-int pwc_restore_user(struct pwc_device *pdev)
-{
-       return send_control_msg(pdev,
-               SET_STATUS_CTL, RESTORE_USER_DEFAULTS_FORMATTER, NULL, 0);
-}
-
-int pwc_save_user(struct pwc_device *pdev)
-{
-       return send_control_msg(pdev,
-               SET_STATUS_CTL, SAVE_USER_DEFAULTS_FORMATTER, NULL, 0);
-}
-
-int pwc_restore_factory(struct pwc_device *pdev)
-{
-       return send_control_msg(pdev,
-               SET_STATUS_CTL, RESTORE_FACTORY_DEFAULTS_FORMATTER, NULL, 0);
-}
-
- /* ************************************************* */
- /* Patch by Alvarado: (not in the original version   */
-
- /*
-  * the camera recognizes modes from 0 to 4:
-  *
-  * 00: indoor (incandescant lighting)
-  * 01: outdoor (sunlight)
-  * 02: fluorescent lighting
-  * 03: manual
-  * 04: auto
-  */
-int pwc_set_awb(struct pwc_device *pdev, int mode)
-{
-       char buf;
-       int ret;
-
-       if (mode < 0)
-           mode = 0;
-
-       if (mode > 4)
-           mode = 4;
-
-       buf = mode & 0x07; /* just the lowest three bits */
-
-       ret = send_control_msg(pdev,
-               SET_CHROM_CTL, WB_MODE_FORMATTER, &buf, sizeof(buf));
-
-       if (ret < 0)
-               return ret;
-       return 0;
-}
-
-int pwc_get_awb(struct pwc_device *pdev)
-{
-       unsigned char buf;
-       int ret;
-
-       ret = recv_control_msg(pdev,
-               GET_CHROM_CTL, WB_MODE_FORMATTER, &buf, sizeof(buf));
-
-       if (ret < 0)
-               return ret;
-       return buf;
-}
-
-int pwc_set_red_gain(struct pwc_device *pdev, int value)
-{
-       unsigned char buf;
-
-       if (value < 0)
-               value = 0;
-       if (value > 0xffff)
-               value = 0xffff;
-       /* only the msb is considered */
-       buf = value >> 8;
-       return send_control_msg(pdev,
-               SET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER,
-               &buf, sizeof(buf));
-}
-
-int pwc_get_red_gain(struct pwc_device *pdev, int *value)
-{
-       unsigned char buf;
-       int ret;
-
-       ret = recv_control_msg(pdev,
-               GET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER,
-               &buf, sizeof(buf));
-       if (ret < 0)
-           return ret;
-       *value = buf << 8;
-       return 0;
-}
-
-
-int pwc_set_blue_gain(struct pwc_device *pdev, int value)
-{
-       unsigned char buf;
-
-       if (value < 0)
-               value = 0;
-       if (value > 0xffff)
-               value = 0xffff;
-       /* only the msb is considered */
-       buf = value >> 8;
-       return send_control_msg(pdev,
-               SET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER,
-               &buf, sizeof(buf));
-}
-
-int pwc_get_blue_gain(struct pwc_device *pdev, int *value)
-{
-       unsigned char buf;
-       int ret;
-
-       ret = recv_control_msg(pdev,
-               GET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER,
-               &buf, sizeof(buf));
-       if (ret < 0)
-           return ret;
-       *value = buf << 8;
-       return 0;
-}
-
 
-/* The following two functions are different, since they only read the
-   internal red/blue gains, which may be different from the manual
-   gains set or read above.
- */
-static int pwc_read_red_gain(struct pwc_device *pdev, int *value)
-{
-       unsigned char buf;
-       int ret;
-
-       ret = recv_control_msg(pdev,
-               GET_STATUS_CTL, READ_RED_GAIN_FORMATTER, &buf, sizeof(buf));
-       if (ret < 0)
-               return ret;
-       *value = buf << 8;
-       return 0;
+       if (r < 0)
+               PWC_ERROR("Failed to power %s camera (%d)\n",
+                         power ? "on" : "off", r);
 }
 
-static int pwc_read_blue_gain(struct pwc_device *pdev, int *value)
-{
-       unsigned char buf;
-       int ret;
-
-       ret = recv_control_msg(pdev,
-               GET_STATUS_CTL, READ_BLUE_GAIN_FORMATTER, &buf, sizeof(buf));
-       if (ret < 0)
-               return ret;
-       *value = buf << 8;
-       return 0;
-}
-
-
 static int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
 {
        unsigned char buf;
@@ -1028,6 +649,7 @@ static int pwc_get_wb_delay(struct pwc_device *pdev, int *value)
 int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value)
 {
        unsigned char buf[2];
+       int r;
 
        if (pdev->type < 730)
                return 0;
@@ -1045,8 +667,12 @@ int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value)
        buf[0] = on_value;
        buf[1] = off_value;
 
-       return send_control_msg(pdev,
+       r = send_control_msg(pdev,
                SET_STATUS_CTL, LED_FORMATTER, &buf, sizeof(buf));
+       if (r < 0)
+               PWC_ERROR("Failed to set LED on/off time (%d)\n", r);
+
+       return r;
 }
 
 static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
@@ -1069,164 +695,6 @@ static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
        return 0;
 }
 
-int pwc_set_contour(struct pwc_device *pdev, int contour)
-{
-       unsigned char buf;
-       int ret;
-
-       if (contour < 0)
-               buf = 0xff; /* auto contour on */
-       else
-               buf = 0x0; /* auto contour off */
-       ret = send_control_msg(pdev,
-               SET_LUM_CTL, AUTO_CONTOUR_FORMATTER, &buf, sizeof(buf));
-       if (ret < 0)
-               return ret;
-
-       if (contour < 0)
-               return 0;
-       if (contour > 0xffff)
-               contour = 0xffff;
-
-       buf = (contour >> 10); /* contour preset is [0..3f] */
-       ret = send_control_msg(pdev,
-               SET_LUM_CTL, PRESET_CONTOUR_FORMATTER, &buf, sizeof(buf));
-       if (ret < 0)
-               return ret;
-       return 0;
-}
-
-int pwc_get_contour(struct pwc_device *pdev, int *contour)
-{
-       unsigned char buf;
-       int ret;
-
-       ret = recv_control_msg(pdev,
-               GET_LUM_CTL, AUTO_CONTOUR_FORMATTER, &buf, sizeof(buf));
-       if (ret < 0)
-               return ret;
-
-       if (buf == 0) {
-               /* auto mode off, query current preset value */
-               ret = recv_control_msg(pdev,
-                       GET_LUM_CTL, PRESET_CONTOUR_FORMATTER,
-                       &buf, sizeof(buf));
-               if (ret < 0)
-                       return ret;
-               *contour = buf << 10;
-       }
-       else
-               *contour = -1;
-       return 0;
-}
-
-
-int pwc_set_backlight(struct pwc_device *pdev, int backlight)
-{
-       unsigned char buf;
-
-       if (backlight)
-               buf = 0xff;
-       else
-               buf = 0x0;
-       return send_control_msg(pdev,
-               SET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER,
-               &buf, sizeof(buf));
-}
-
-int pwc_get_backlight(struct pwc_device *pdev, int *backlight)
-{
-       int ret;
-       unsigned char buf;
-
-       ret = recv_control_msg(pdev,
-               GET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER,
-               &buf, sizeof(buf));
-       if (ret < 0)
-               return ret;
-       *backlight = !!buf;
-       return 0;
-}
-
-int pwc_set_colour_mode(struct pwc_device *pdev, int colour)
-{
-       unsigned char buf;
-
-       if (colour)
-               buf = 0xff;
-       else
-               buf = 0x0;
-       return send_control_msg(pdev,
-               SET_CHROM_CTL, COLOUR_MODE_FORMATTER, &buf, sizeof(buf));
-}
-
-int pwc_get_colour_mode(struct pwc_device *pdev, int *colour)
-{
-       int ret;
-       unsigned char buf;
-
-       ret = recv_control_msg(pdev,
-               GET_CHROM_CTL, COLOUR_MODE_FORMATTER, &buf, sizeof(buf));
-       if (ret < 0)
-               return ret;
-       *colour = !!buf;
-       return 0;
-}
-
-
-int pwc_set_flicker(struct pwc_device *pdev, int flicker)
-{
-       unsigned char buf;
-
-       if (flicker)
-               buf = 0xff;
-       else
-               buf = 0x0;
-       return send_control_msg(pdev,
-               SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, &buf, sizeof(buf));
-}
-
-int pwc_get_flicker(struct pwc_device *pdev, int *flicker)
-{
-       int ret;
-       unsigned char buf;
-
-       ret = recv_control_msg(pdev,
-               GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, &buf, sizeof(buf));
-       if (ret < 0)
-               return ret;
-       *flicker = !!buf;
-       return 0;
-}
-
-int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
-{
-       unsigned char buf;
-
-       if (noise < 0)
-               noise = 0;
-       if (noise > 3)
-               noise = 3;
-       buf = noise;
-       return send_control_msg(pdev,
-               SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER,
-               &buf, sizeof(buf));
-}
-
-int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise)
-{
-       int ret;
-       unsigned char buf;
-
-       ret = recv_control_msg(pdev,
-               GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER,
-               &buf, sizeof(buf));
-       if (ret < 0)
-               return ret;
-       *noise = buf;
-       return 0;
-}
-
 static int _pwc_mpt_reset(struct pwc_device *pdev, int flags)
 {
        unsigned char buf;
@@ -1309,7 +777,7 @@ static int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *st
        return 0;
 }
 
-
+#ifdef CONFIG_USB_PWC_DEBUG
 int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor)
 {
        unsigned char buf;
@@ -1332,7 +800,7 @@ int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor)
                *sensor = buf;
        return 0;
 }
-
+#endif
 
  /* End of Add-Ons                                    */
  /* ************************************************* */
@@ -1356,37 +824,41 @@ int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor)
 /* copy local variable to arg */
 #define ARG_OUT(ARG_name) /* nothing */
 
+/*
+ * Our ctrls use native values, but the old custom pwc ioctl interface expects
+ * values from 0 - 65535, define 2 helper functions to scale things. */
+static int pwc_ioctl_g_ctrl(struct v4l2_ctrl *ctrl)
+{
+       return v4l2_ctrl_g_ctrl(ctrl) * 65535 / ctrl->maximum;
+}
+
+static int pwc_ioctl_s_ctrl(struct v4l2_ctrl *ctrl, int val)
+{
+       return v4l2_ctrl_s_ctrl(ctrl, val * ctrl->maximum / 65535);
+}
+
 long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
 {
        long ret = 0;
 
        switch(cmd) {
        case VIDIOCPWCRUSER:
-       {
-               if (pwc_restore_user(pdev))
-                       ret = -EINVAL;
+               ret = pwc_button_ctrl(pdev, RESTORE_USER_DEFAULTS_FORMATTER);
                break;
-       }
 
        case VIDIOCPWCSUSER:
-       {
-               if (pwc_save_user(pdev))
-                       ret = -EINVAL;
+               ret = pwc_button_ctrl(pdev, SAVE_USER_DEFAULTS_FORMATTER);
                break;
-       }
 
        case VIDIOCPWCFACTORY:
-       {
-               if (pwc_restore_factory(pdev))
-                       ret = -EINVAL;
+               ret = pwc_button_ctrl(pdev, RESTORE_FACTORY_DEFAULTS_FORMATTER);
                break;
-       }
 
        case VIDIOCPWCSCQUAL:
        {
                ARG_DEF(int, qual)
 
-               if (pdev->iso_init) {
+               if (vb2_is_streaming(&pdev->vb_queue)) {
                        ret = -EBUSY;
                        break;
                }
@@ -1396,8 +868,6 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
                        ret = -EINVAL;
                else
                        ret = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot);
-               if (ret >= 0)
-                       pdev->vcompression = ARGR(qual);
                break;
        }
 
@@ -1432,71 +902,59 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
        case VIDIOCPWCSAGC:
        {
                ARG_DEF(int, agc)
-
                ARG_IN(agc)
-               if (pwc_set_agc(pdev, ARGR(agc) < 0 ? 1 : 0, ARGR(agc)))
-                       ret = -EINVAL;
+               ret = v4l2_ctrl_s_ctrl(pdev->autogain, ARGR(agc) < 0);
+               if (ret == 0 && ARGR(agc) >= 0)
+                       ret = pwc_ioctl_s_ctrl(pdev->gain, ARGR(agc));
                break;
        }
 
        case VIDIOCPWCGAGC:
        {
                ARG_DEF(int, agc)
-
-               if (pwc_get_agc(pdev, ARGA(agc)))
-                       ret = -EINVAL;
+               if (v4l2_ctrl_g_ctrl(pdev->autogain))
+                       ARGR(agc) = -1;
+               else
+                       ARGR(agc) = pwc_ioctl_g_ctrl(pdev->gain);
                ARG_OUT(agc)
                break;
        }
 
        case VIDIOCPWCSSHUTTER:
        {
-               ARG_DEF(int, shutter_speed)
-
-               ARG_IN(shutter_speed)
-               ret = pwc_set_shutter_speed(pdev, ARGR(shutter_speed) < 0 ? 1 : 0, ARGR(shutter_speed));
+               ARG_DEF(int, shutter)
+               ARG_IN(shutter)
+               ret = v4l2_ctrl_s_ctrl(pdev->exposure_auto,
+                                      /* Menu idx 0 = auto, idx 1 = manual */
+                                      ARGR(shutter) >= 0);
+               if (ret == 0 && ARGR(shutter) >= 0)
+                       ret = pwc_ioctl_s_ctrl(pdev->exposure, ARGR(shutter));
                break;
        }
 
        case VIDIOCPWCSAWB:
        {
                ARG_DEF(struct pwc_whitebalance, wb)
-
                ARG_IN(wb)
-               ret = pwc_set_awb(pdev, ARGR(wb).mode);
-               if (ret >= 0 && ARGR(wb).mode == PWC_WB_MANUAL) {
-                       pwc_set_red_gain(pdev, ARGR(wb).manual_red);
-                       pwc_set_blue_gain(pdev, ARGR(wb).manual_blue);
-               }
+               ret = v4l2_ctrl_s_ctrl(pdev->auto_white_balance,
+                                      ARGR(wb).mode);
+               if (ret == 0 && ARGR(wb).mode == PWC_WB_MANUAL)
+                       ret = pwc_ioctl_s_ctrl(pdev->red_balance,
+                                              ARGR(wb).manual_red);
+               if (ret == 0 && ARGR(wb).mode == PWC_WB_MANUAL)
+                       ret = pwc_ioctl_s_ctrl(pdev->blue_balance,
+                                              ARGR(wb).manual_blue);
                break;
        }
 
        case VIDIOCPWCGAWB:
        {
                ARG_DEF(struct pwc_whitebalance, wb)
-
-               memset(ARGA(wb), 0, sizeof(struct pwc_whitebalance));
-               ARGR(wb).mode = pwc_get_awb(pdev);
-               if (ARGR(wb).mode < 0)
-                       ret = -EINVAL;
-               else {
-                       if (ARGR(wb).mode == PWC_WB_MANUAL) {
-                               ret = pwc_get_red_gain(pdev, &ARGR(wb).manual_red);
-                               if (ret < 0)
-                                       break;
-                               ret = pwc_get_blue_gain(pdev, &ARGR(wb).manual_blue);
-                               if (ret < 0)
-                                       break;
-                       }
-                       if (ARGR(wb).mode == PWC_WB_AUTO) {
-                               ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red);
-                               if (ret < 0)
-                                       break;
-                               ret = pwc_read_blue_gain(pdev, &ARGR(wb).read_blue);
-                               if (ret < 0)
-                                       break;
-                       }
-               }
+               ARGR(wb).mode = v4l2_ctrl_g_ctrl(pdev->auto_white_balance);
+               ARGR(wb).manual_red = ARGR(wb).read_red =
+                       pwc_ioctl_g_ctrl(pdev->red_balance);
+               ARGR(wb).manual_blue = ARGR(wb).read_blue =
+                       pwc_ioctl_g_ctrl(pdev->blue_balance);
                ARG_OUT(wb)
                break;
        }
@@ -1550,17 +1008,20 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
        case VIDIOCPWCSCONTOUR:
        {
                ARG_DEF(int, contour)
-
                ARG_IN(contour)
-               ret = pwc_set_contour(pdev, ARGR(contour));
+               ret = v4l2_ctrl_s_ctrl(pdev->autocontour, ARGR(contour) < 0);
+               if (ret == 0 && ARGR(contour) >= 0)
+                       ret = pwc_ioctl_s_ctrl(pdev->contour, ARGR(contour));
                break;
        }
 
        case VIDIOCPWCGCONTOUR:
        {
                ARG_DEF(int, contour)
-
-               ret = pwc_get_contour(pdev, ARGA(contour));
+               if (v4l2_ctrl_g_ctrl(pdev->autocontour))
+                       ARGR(contour) = -1;
+               else
+                       ARGR(contour) = pwc_ioctl_g_ctrl(pdev->contour);
                ARG_OUT(contour)
                break;
        }
@@ -1568,17 +1029,15 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
        case VIDIOCPWCSBACKLIGHT:
        {
                ARG_DEF(int, backlight)
-
                ARG_IN(backlight)
-               ret = pwc_set_backlight(pdev, ARGR(backlight));
+               ret = v4l2_ctrl_s_ctrl(pdev->backlight, ARGR(backlight));
                break;
        }
 
        case VIDIOCPWCGBACKLIGHT:
        {
                ARG_DEF(int, backlight)
-
-               ret = pwc_get_backlight(pdev, ARGA(backlight));
+               ARGR(backlight) = v4l2_ctrl_g_ctrl(pdev->backlight);
                ARG_OUT(backlight)
                break;
        }
@@ -1586,17 +1045,15 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
        case VIDIOCPWCSFLICKER:
        {
                ARG_DEF(int, flicker)
-
                ARG_IN(flicker)
-               ret = pwc_set_flicker(pdev, ARGR(flicker));
+               ret = v4l2_ctrl_s_ctrl(pdev->flicker, ARGR(flicker));
                break;
        }
 
        case VIDIOCPWCGFLICKER:
        {
                ARG_DEF(int, flicker)
-
-               ret = pwc_get_flicker(pdev, ARGA(flicker));
+               ARGR(flicker) = v4l2_ctrl_g_ctrl(pdev->flicker);
                ARG_OUT(flicker)
                break;
        }
@@ -1604,17 +1061,15 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
        case VIDIOCPWCSDYNNOISE:
        {
                ARG_DEF(int, dynnoise)
-
                ARG_IN(dynnoise)
-               ret = pwc_set_dynamic_noise(pdev, ARGR(dynnoise));
+               ret = v4l2_ctrl_s_ctrl(pdev->noise_reduction, ARGR(dynnoise));
                break;
        }
 
        case VIDIOCPWCGDYNNOISE:
        {
                ARG_DEF(int, dynnoise)
-
-               ret = pwc_get_dynamic_noise(pdev, ARGA(dynnoise));
+               ARGR(dynnoise) = v4l2_ctrl_g_ctrl(pdev->noise_reduction);
                ARG_OUT(dynnoise);
                break;
        }
index c29593f..be0e02c 100644 (file)
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
-
-
-
 #include "pwc-dec1.h"
 
-
-void pwc_dec1_init(int type, int release, void *buffer, void *table)
+int pwc_dec1_init(struct pwc_device *pwc, int type, int release, void *buffer)
 {
+       struct pwc_dec1_private *pdec;
 
-}
-
-void pwc_dec1_exit(void)
-{
+       if (pwc->decompress_data == NULL) {
+               pdec = kmalloc(sizeof(struct pwc_dec1_private), GFP_KERNEL);
+               if (pdec == NULL)
+                       return -ENOMEM;
+               pwc->decompress_data = pdec;
+       }
+       pdec = pwc->decompress_data;
 
-
-
-}
-
-int pwc_dec1_alloc(struct pwc_device *pwc)
-{
-       pwc->decompress_data = kmalloc(sizeof(struct pwc_dec1_private), GFP_KERNEL);
-       if (pwc->decompress_data == NULL)
-               return -ENOMEM;
        return 0;
 }
-
index 8b62ddc..a57d860 100644 (file)
@@ -22,8 +22,6 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 
-
-
 #ifndef PWC_DEC1_H
 #define PWC_DEC1_H
 
 struct pwc_dec1_private
 {
        int version;
-
 };
 
-int  pwc_dec1_alloc(struct pwc_device *pwc);
-void pwc_dec1_init(int type, int release, void *buffer, void *private_data);
-void pwc_dec1_exit(void);
+int pwc_dec1_init(struct pwc_device *pwc, int type, int release, void *buffer);
 
 #endif
-
index 0c801b8..06a4e87 100644 (file)
@@ -916,27 +916,5 @@ void pwc_dec23_decompress(const struct pwc_device *pwc,
                        pout_planar_v += pwc->view.x;
 
                }
-
        }
-
 }
-
-void pwc_dec23_exit(void)
-{
-       /* Do nothing */
-
-}
-
-/**
- * Allocate a private structure used by lookup table.
- * You must call kfree() to free the memory allocated.
- */
-int pwc_dec23_alloc(struct pwc_device *pwc)
-{
-       pwc->decompress_data = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);
-       if (pwc->decompress_data == NULL)
-               return -ENOMEM;
-       return 0;
-}
-
-/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
index 1c55298..a0ac4f3 100644 (file)
@@ -49,19 +49,9 @@ struct pwc_dec23_private
 
 };
 
-
-int pwc_dec23_alloc(struct pwc_device *pwc);
 int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd);
-void pwc_dec23_exit(void);
 void pwc_dec23_decompress(const struct pwc_device *pwc,
                          const void *src,
                          void *dst,
                          int flags);
-
-
-
 #endif
-
-
-/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
-
index b0bde5a..51ca358 100644 (file)
@@ -2,6 +2,7 @@
    USB and Video4Linux interface part.
    (C) 1999-2004 Nemosoft Unv.
    (C) 2004-2006 Luc Saillard (luc@saillard.org)
+   (C) 2011 Hans de Goede <hdegoede@redhat.com>
 
    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
    driver and thus may have bugs that are not present in the original version.
@@ -74,7 +75,6 @@
 #include "pwc-timon.h"
 #include "pwc-dec23.h"
 #include "pwc-dec1.h"
-#include "pwc-uncompress.h"
 
 /* Function prototypes and driver templates */
 
@@ -116,6 +116,7 @@ MODULE_DEVICE_TABLE(usb, pwc_device_table);
 
 static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id);
 static void usb_pwc_disconnect(struct usb_interface *intf);
+static void pwc_isoc_cleanup(struct pwc_device *pdev);
 
 static struct usb_driver pwc_driver = {
        .name =                 "Philips webcam",       /* name */
@@ -127,14 +128,11 @@ static struct usb_driver pwc_driver = {
 #define MAX_DEV_HINTS  20
 #define MAX_ISOC_ERRORS        20
 
-static int default_size = PSZ_QCIF;
 static int default_fps = 10;
-static int default_fbufs = 3;   /* Default number of frame buffers */
-       int pwc_mbufs = 2;      /* Default number of mmap() buffers */
 #ifdef CONFIG_USB_PWC_DEBUG
        int pwc_trace = PWC_DEBUG_LEVEL;
 #endif
-static int power_save;
+static int power_save = -1;
 static int led_on = 100, led_off; /* defaults to LED that is on while in use */
 static int pwc_preferred_compression = 1; /* 0..3 = uncompressed..high */
 static struct {
@@ -173,389 +171,20 @@ static struct video_device pwc_template = {
 /***************************************************************************/
 /* Private functions */
 
-/* Here we want the physical address of the memory.
- * This is used when initializing the contents of the area.
- */
-
-
-
-static void *pwc_rvmalloc(unsigned long size)
-{
-       void * mem;
-       unsigned long adr;
-
-       mem=vmalloc_32(size);
-       if (!mem)
-               return NULL;
-
-       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
-       adr=(unsigned long) mem;
-       while (size > 0)
-        {
-          SetPageReserved(vmalloc_to_page((void *)adr));
-          adr  += PAGE_SIZE;
-          size -= PAGE_SIZE;
-        }
-       return mem;
-}
-
-static void pwc_rvfree(void * mem, unsigned long size)
-{
-       unsigned long adr;
-
-       if (!mem)
-               return;
-
-       adr=(unsigned long) mem;
-       while ((long) size > 0)
-        {
-          ClearPageReserved(vmalloc_to_page((void *)adr));
-          adr  += PAGE_SIZE;
-          size -= PAGE_SIZE;
-        }
-       vfree(mem);
-}
-
-
-
-
-static int pwc_allocate_buffers(struct pwc_device *pdev)
-{
-       int i, err;
-       void *kbuf;
-
-       PWC_DEBUG_MEMORY(">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);
-
-       if (pdev == NULL)
-               return -ENXIO;
-
-       /* Allocate Isochronuous pipe buffers */
-       for (i = 0; i < MAX_ISO_BUFS; i++) {
-               if (pdev->sbuf[i].data == NULL) {
-                       kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
-                       if (kbuf == NULL) {
-                               PWC_ERROR("Failed to allocate iso buffer %d.\n", i);
-                               return -ENOMEM;
-                       }
-                       PWC_DEBUG_MEMORY("Allocated iso buffer at %p.\n", kbuf);
-                       pdev->sbuf[i].data = kbuf;
-               }
-       }
-
-       /* Allocate frame buffer structure */
-       if (pdev->fbuf == NULL) {
-               kbuf = kzalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL);
-               if (kbuf == NULL) {
-                       PWC_ERROR("Failed to allocate frame buffer structure.\n");
-                       return -ENOMEM;
-               }
-               PWC_DEBUG_MEMORY("Allocated frame buffer structure at %p.\n", kbuf);
-               pdev->fbuf = kbuf;
-       }
-
-       /* create frame buffers, and make circular ring */
-       for (i = 0; i < default_fbufs; i++) {
-               if (pdev->fbuf[i].data == NULL) {
-                       kbuf = vzalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */
-                       if (kbuf == NULL) {
-                               PWC_ERROR("Failed to allocate frame buffer %d.\n", i);
-                               return -ENOMEM;
-                       }
-                       PWC_DEBUG_MEMORY("Allocated frame buffer %d at %p.\n", i, kbuf);
-                       pdev->fbuf[i].data = kbuf;
-               }
-       }
-
-       /* Allocate decompressor table space */
-       if (DEVICE_USE_CODEC1(pdev->type))
-               err = pwc_dec1_alloc(pdev);
-       else
-               err = pwc_dec23_alloc(pdev);
-
-       if (err) {
-               PWC_ERROR("Failed to allocate decompress table.\n");
-               return err;
-       }
-
-       /* Allocate image buffer; double buffer for mmap() */
-       kbuf = pwc_rvmalloc(pwc_mbufs * pdev->len_per_image);
-       if (kbuf == NULL) {
-               PWC_ERROR("Failed to allocate image buffer(s). needed (%d)\n",
-                               pwc_mbufs * pdev->len_per_image);
-               return -ENOMEM;
-       }
-       PWC_DEBUG_MEMORY("Allocated image buffer at %p.\n", kbuf);
-       pdev->image_data = kbuf;
-       for (i = 0; i < pwc_mbufs; i++) {
-               pdev->images[i].offset = i * pdev->len_per_image;
-               pdev->images[i].vma_use_count = 0;
-       }
-       for (; i < MAX_IMAGES; i++) {
-               pdev->images[i].offset = 0;
-       }
-
-       kbuf = NULL;
-
-       PWC_DEBUG_MEMORY("<< pwc_allocate_buffers()\n");
-       return 0;
-}
-
-static void pwc_free_buffers(struct pwc_device *pdev)
-{
-       int i;
-
-       PWC_DEBUG_MEMORY("Entering free_buffers(%p).\n", pdev);
-
-       if (pdev == NULL)
-               return;
-       /* Release Iso-pipe buffers */
-       for (i = 0; i < MAX_ISO_BUFS; i++)
-               if (pdev->sbuf[i].data != NULL) {
-                       PWC_DEBUG_MEMORY("Freeing ISO buffer at %p.\n", pdev->sbuf[i].data);
-                       kfree(pdev->sbuf[i].data);
-                       pdev->sbuf[i].data = NULL;
-               }
-
-       /* The same for frame buffers */
-       if (pdev->fbuf != NULL) {
-               for (i = 0; i < default_fbufs; i++) {
-                       if (pdev->fbuf[i].data != NULL) {
-                               PWC_DEBUG_MEMORY("Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data);
-                               vfree(pdev->fbuf[i].data);
-                               pdev->fbuf[i].data = NULL;
-                       }
-               }
-               kfree(pdev->fbuf);
-               pdev->fbuf = NULL;
-       }
-
-       /* Intermediate decompression buffer & tables */
-       if (pdev->decompress_data != NULL) {
-               PWC_DEBUG_MEMORY("Freeing decompression buffer at %p.\n", pdev->decompress_data);
-               kfree(pdev->decompress_data);
-               pdev->decompress_data = NULL;
-       }
-
-       /* Release image buffers */
-       if (pdev->image_data != NULL) {
-               PWC_DEBUG_MEMORY("Freeing image buffer at %p.\n", pdev->image_data);
-               pwc_rvfree(pdev->image_data, pwc_mbufs * pdev->len_per_image);
-       }
-       pdev->image_data = NULL;
-
-       PWC_DEBUG_MEMORY("Leaving free_buffers().\n");
-}
-
-/* The frame & image buffer mess.
-
-   Yes, this is a mess. Well, it used to be simple, but alas...  In this
-   module, 3 buffers schemes are used to get the data from the USB bus to
-   the user program. The first scheme involves the ISO buffers (called thus
-   since they transport ISO data from the USB controller), and not really
-   interesting. Suffices to say the data from this buffer is quickly
-   gathered in an interrupt handler (pwc_isoc_handler) and placed into the
-   frame buffer.
-
-   The frame buffer is the second scheme, and is the central element here.
-   It collects the data from a single frame from the camera (hence, the
-   name). Frames are delimited by the USB camera with a short USB packet,
-   so that's easy to detect. The frame buffers form a list that is filled
-   by the camera+USB controller and drained by the user process through
-   either read() or mmap().
-
-   The image buffer is the third scheme, in which frames are decompressed
-   and converted into planar format. For mmap() there is more than
-   one image buffer available.
-
-   The frame buffers provide the image buffering. In case the user process
-   is a bit slow, this introduces lag and some undesired side-effects.
-   The problem arises when the frame buffer is full. I used to drop the last
-   frame, which makes the data in the queue stale very quickly. But dropping
-   the frame at the head of the queue proved to be a litte bit more difficult.
-   I tried a circular linked scheme, but this introduced more problems than
-   it solved.
-
-   Because filling and draining are completely asynchronous processes, this
-   requires some fiddling with pointers and mutexes.
-
-   Eventually, I came up with a system with 2 lists: an 'empty' frame list
-   and a 'full' frame list:
-     * Initially, all frame buffers but one are on the 'empty' list; the one
-       remaining buffer is our initial fill frame.
-     * If a frame is needed for filling, we try to take it from the 'empty'
-       list, unless that list is empty, in which case we take the buffer at
-       the head of the 'full' list.
-     * When our fill buffer has been filled, it is appended to the 'full'
-       list.
-     * If a frame is needed by read() or mmap(), it is taken from the head of
-       the 'full' list, handled, and then appended to the 'empty' list. If no
-       buffer is present on the 'full' list, we wait.
-   The advantage is that the buffer that is currently being decompressed/
-   converted, is on neither list, and thus not in our way (any other scheme
-   I tried had the problem of old data lingering in the queue).
-
-   Whatever strategy you choose, it always remains a tradeoff: with more
-   frame buffers the chances of a missed frame are reduced. On the other
-   hand, on slower machines it introduces lag because the queue will
-   always be full.
- */
-
-/**
-  \brief Find next frame buffer to fill. Take from empty or full list, whichever comes first.
- */
-static int pwc_next_fill_frame(struct pwc_device *pdev)
-{
-       int ret;
-       unsigned long flags;
-
-       ret = 0;
-       spin_lock_irqsave(&pdev->ptrlock, flags);
-       if (pdev->fill_frame != NULL) {
-               /* append to 'full' list */
-               if (pdev->full_frames == NULL) {
-                       pdev->full_frames = pdev->fill_frame;
-                       pdev->full_frames_tail = pdev->full_frames;
-               }
-               else {
-                       pdev->full_frames_tail->next = pdev->fill_frame;
-                       pdev->full_frames_tail = pdev->fill_frame;
-               }
-       }
-       if (pdev->empty_frames != NULL) {
-               /* We have empty frames available. That's easy */
-               pdev->fill_frame = pdev->empty_frames;
-               pdev->empty_frames = pdev->empty_frames->next;
-       }
-       else {
-               /* Hmm. Take it from the full list */
-               /* sanity check */
-               if (pdev->full_frames == NULL) {
-                       PWC_ERROR("Neither empty or full frames available!\n");
-                       spin_unlock_irqrestore(&pdev->ptrlock, flags);
-                       return -EINVAL;
-               }
-               pdev->fill_frame = pdev->full_frames;
-               pdev->full_frames = pdev->full_frames->next;
-               ret = 1;
-       }
-       pdev->fill_frame->next = NULL;
-       spin_unlock_irqrestore(&pdev->ptrlock, flags);
-       return ret;
-}
-
-
-/**
-  \brief Reset all buffers, pointers and lists, except for the image_used[] buffer.
-
-  If the image_used[] buffer is cleared too, mmap()/VIDIOCSYNC will run into trouble.
- */
-static void pwc_reset_buffers(struct pwc_device *pdev)
-{
-       int i;
-       unsigned long flags;
-
-       PWC_DEBUG_MEMORY(">> %s __enter__\n", __func__);
-
-       spin_lock_irqsave(&pdev->ptrlock, flags);
-       pdev->full_frames = NULL;
-       pdev->full_frames_tail = NULL;
-       for (i = 0; i < default_fbufs; i++) {
-               pdev->fbuf[i].filled = 0;
-               if (i > 0)
-                       pdev->fbuf[i].next = &pdev->fbuf[i - 1];
-               else
-                       pdev->fbuf->next = NULL;
-       }
-       pdev->empty_frames = &pdev->fbuf[default_fbufs - 1];
-       pdev->empty_frames_tail = pdev->fbuf;
-       pdev->read_frame = NULL;
-       pdev->fill_frame = pdev->empty_frames;
-       pdev->empty_frames = pdev->empty_frames->next;
-
-       pdev->image_read_pos = 0;
-       pdev->fill_image = 0;
-       spin_unlock_irqrestore(&pdev->ptrlock, flags);
-
-       PWC_DEBUG_MEMORY("<< %s __leaving__\n", __func__);
-}
-
-
-/**
-  \brief Do all the handling for getting one frame: get pointer, decompress, advance pointers.
- */
-int pwc_handle_frame(struct pwc_device *pdev)
+struct pwc_frame_buf *pwc_get_next_fill_buf(struct pwc_device *pdev)
 {
-       int ret = 0;
-       unsigned long flags;
-
-       spin_lock_irqsave(&pdev->ptrlock, flags);
-       /* First grab our read_frame; this is removed from all lists, so
-          we can release the lock after this without problems */
-       if (pdev->read_frame != NULL) {
-               /* This can't theoretically happen */
-               PWC_ERROR("Huh? Read frame still in use?\n");
-               spin_unlock_irqrestore(&pdev->ptrlock, flags);
-               return ret;
-       }
-
-
-       if (pdev->full_frames == NULL) {
-               PWC_ERROR("Woops. No frames ready.\n");
-       }
-       else {
-               pdev->read_frame = pdev->full_frames;
-               pdev->full_frames = pdev->full_frames->next;
-               pdev->read_frame->next = NULL;
-       }
-
-       if (pdev->read_frame != NULL) {
-               /* Decompression is a lengthy process, so it's outside of the lock.
-                  This gives the isoc_handler the opportunity to fill more frames
-                  in the mean time.
-               */
-               spin_unlock_irqrestore(&pdev->ptrlock, flags);
-               ret = pwc_decompress(pdev);
-               spin_lock_irqsave(&pdev->ptrlock, flags);
-
-               /* We're done with read_buffer, tack it to the end of the empty buffer list */
-               if (pdev->empty_frames == NULL) {
-                       pdev->empty_frames = pdev->read_frame;
-                       pdev->empty_frames_tail = pdev->empty_frames;
-               }
-               else {
-                       pdev->empty_frames_tail->next = pdev->read_frame;
-                       pdev->empty_frames_tail = pdev->read_frame;
-               }
-               pdev->read_frame = NULL;
-       }
-       spin_unlock_irqrestore(&pdev->ptrlock, flags);
-       return ret;
-}
-
-/**
-  \brief Advance pointers of image buffer (after each user request)
-*/
-void pwc_next_image(struct pwc_device *pdev)
-{
-       pdev->image_used[pdev->fill_image] = 0;
-       pdev->fill_image = (pdev->fill_image + 1) % pwc_mbufs;
-}
-
-/**
- * Print debug information when a frame is discarded because all of our buffer
- * is full
- */
-static void pwc_frame_dumped(struct pwc_device *pdev)
-{
-       pdev->vframes_dumped++;
-       if (pdev->vframe_count < FRAME_LOWMARK)
-               return;
-
-       if (pdev->vframes_dumped < 20)
-               PWC_DEBUG_FLOW("Dumping frame %d\n", pdev->vframe_count);
-       else if (pdev->vframes_dumped == 20)
-               PWC_DEBUG_FLOW("Dumping frame %d (last message)\n",
-                               pdev->vframe_count);
+       unsigned long flags = 0;
+       struct pwc_frame_buf *buf = NULL;
+
+       spin_lock_irqsave(&pdev->queued_bufs_lock, flags);
+       if (list_empty(&pdev->queued_bufs))
+               goto leave;
+
+       buf = list_entry(pdev->queued_bufs.next, struct pwc_frame_buf, list);
+       list_del(&buf->list);
+leave:
+       spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags);
+       return buf;
 }
 
 static void pwc_snapshot_button(struct pwc_device *pdev, int down)
@@ -575,9 +204,9 @@ static void pwc_snapshot_button(struct pwc_device *pdev, int down)
 #endif
 }
 
-static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_buf *fbuf)
+static void pwc_frame_complete(struct pwc_device *pdev)
 {
-       int awake = 0;
+       struct pwc_frame_buf *fbuf = pdev->fill_buf;
 
        /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus
           frames on the USB wire after an exposure change. This conditition is
@@ -589,7 +218,6 @@ static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_
                if (ptr[1] == 1 && ptr[0] & 0x10) {
                        PWC_TRACE("Hyundai CMOS sensor bug. Dropping frame.\n");
                        pdev->drop_frames += 2;
-                       pdev->vframes_error++;
                }
                if ((ptr[0] ^ pdev->vmirror) & 0x01) {
                        pwc_snapshot_button(pdev, ptr[0] & 0x01);
@@ -612,8 +240,7 @@ static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_
                   */
                if (fbuf->filled == 4)
                        pdev->drop_frames++;
-       }
-       else if (pdev->type == 740 || pdev->type == 720) {
+       } else if (pdev->type == 740 || pdev->type == 720) {
                unsigned char *ptr = (unsigned char *)fbuf->data;
                if ((ptr[0] ^ pdev->vmirror) & 0x01) {
                        pwc_snapshot_button(pdev, ptr[0] & 0x01);
@@ -621,33 +248,23 @@ static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_
                pdev->vmirror = ptr[0] & 0x03;
        }
 
-       /* In case we were instructed to drop the frame, do so silently.
-          The buffer pointers are not updated either (but the counters are reset below).
-          */
-       if (pdev->drop_frames > 0)
+       /* In case we were instructed to drop the frame, do so silently. */
+       if (pdev->drop_frames > 0) {
                pdev->drop_frames--;
-       else {
+       else {
                /* Check for underflow first */
                if (fbuf->filled < pdev->frame_total_size) {
                        PWC_DEBUG_FLOW("Frame buffer underflow (%d bytes);"
                                       " discarded.\n", fbuf->filled);
-                       pdev->vframes_error++;
-               }
-               else {
-                       /* Send only once per EOF */
-                       awake = 1; /* delay wake_ups */
-
-                       /* Find our next frame to fill. This will always succeed, since we
-                        * nick a frame from either empty or full list, but if we had to
-                        * take it from the full list, it means a frame got dropped.
-                        */
-                       if (pwc_next_fill_frame(pdev))
-                               pwc_frame_dumped(pdev);
-
+               } else {
+                       fbuf->vb.v4l2_buf.field = V4L2_FIELD_NONE;
+                       fbuf->vb.v4l2_buf.sequence = pdev->vframe_count;
+                       vb2_buffer_done(&fbuf->vb, VB2_BUF_STATE_DONE);
+                       pdev->fill_buf = NULL;
+                       pdev->vsync = 0;
                }
        } /* !drop_frames */
        pdev->vframe_count++;
-       return awake;
 }
 
 /* This gets called for the Isochronous pipe (video). This is done in
@@ -655,24 +272,20 @@ static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_
  */
 static void pwc_isoc_handler(struct urb *urb)
 {
-       struct pwc_device *pdev;
+       struct pwc_device *pdev = (struct pwc_device *)urb->context;
        int i, fst, flen;
-       int awake;
-       struct pwc_frame_buf *fbuf;
-       unsigned char *fillptr = NULL, *iso_buf = NULL;
+       unsigned char *iso_buf = NULL;
 
-       awake = 0;
-       pdev = (struct pwc_device *)urb->context;
-       if (pdev == NULL) {
-               PWC_ERROR("isoc_handler() called with NULL device?!\n");
-               return;
-       }
-
-       if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
+       if (urb->status == -ENOENT || urb->status == -ECONNRESET ||
+           urb->status == -ESHUTDOWN) {
                PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
                return;
        }
-       if (urb->status != -EINPROGRESS && urb->status != 0) {
+
+       if (pdev->fill_buf == NULL)
+               pdev->fill_buf = pwc_get_next_fill_buf(pdev);
+
+       if (urb->status != 0) {
                const char *errmsg;
 
                errmsg = "Unknown";
@@ -684,29 +297,21 @@ static void pwc_isoc_handler(struct urb *urb)
                        case -EILSEQ:           errmsg = "CRC/Timeout (could be anything)"; break;
                        case -ETIME:            errmsg = "Device does not respond"; break;
                }
-               PWC_DEBUG_FLOW("pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);
-               /* Give up after a number of contiguous errors on the USB bus.
-                  Appearantly something is wrong so we simulate an unplug event.
-                */
+               PWC_ERROR("pwc_isoc_handler() called with status %d [%s].\n",
+                         urb->status, errmsg);
+               /* Give up after a number of contiguous errors */
                if (++pdev->visoc_errors > MAX_ISOC_ERRORS)
                {
-                       PWC_INFO("Too many ISOC errors, bailing out.\n");
-                       pdev->error_status = EIO;
-                       awake = 1;
-                       wake_up_interruptible(&pdev->frameq);
+                       PWC_ERROR("Too many ISOC errors, bailing out.\n");
+                       if (pdev->fill_buf) {
+                               vb2_buffer_done(&pdev->fill_buf->vb,
+                                               VB2_BUF_STATE_ERROR);
+                               pdev->fill_buf = NULL;
+                       }
                }
-               goto handler_end; // ugly, but practical
-       }
-
-       fbuf = pdev->fill_frame;
-       if (fbuf == NULL) {
-               PWC_ERROR("pwc_isoc_handler without valid fill frame.\n");
-               awake = 1;
+               pdev->vsync = 0; /* Drop the current frame */
                goto handler_end;
        }
-       else {
-               fillptr = fbuf->data + fbuf->filled;
-       }
 
        /* Reset ISOC error counter. We did get here, after all. */
        pdev->visoc_errors = 0;
@@ -720,89 +325,73 @@ static void pwc_isoc_handler(struct urb *urb)
                fst  = urb->iso_frame_desc[i].status;
                flen = urb->iso_frame_desc[i].actual_length;
                iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-               if (fst == 0) {
-                       if (flen > 0) { /* if valid data... */
-                               if (pdev->vsync > 0) { /* ...and we are not sync-hunting... */
-                                       pdev->vsync = 2;
-
-                                       /* ...copy data to frame buffer, if possible */
-                                       if (flen + fbuf->filled > pdev->frame_total_size) {
-                                               PWC_DEBUG_FLOW("Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size);
-                                               pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */
-                                               pdev->vframes_error++;
-                                       }
-                                       else {
-                                               memmove(fillptr, iso_buf, flen);
-                                               fillptr += flen;
-                                       }
-                               }
+               if (fst != 0) {
+                       PWC_ERROR("Iso frame %d has error %d\n", i, fst);
+                       continue;
+               }
+               if (flen > 0 && pdev->vsync) {
+                       struct pwc_frame_buf *fbuf = pdev->fill_buf;
+
+                       if (pdev->vsync == 1) {
+                               do_gettimeofday(&fbuf->vb.v4l2_buf.timestamp);
+                               pdev->vsync = 2;
+                       }
+
+                       if (flen + fbuf->filled > pdev->frame_total_size) {
+                               PWC_ERROR("Frame overflow (%d > %d)\n",
+                                         flen + fbuf->filled,
+                                         pdev->frame_total_size);
+                               pdev->vsync = 0; /* Let's wait for an EOF */
+                       } else {
+                               memcpy(fbuf->data + fbuf->filled, iso_buf,
+                                      flen);
                                fbuf->filled += flen;
-                       } /* ..flen > 0 */
-
-                       if (flen < pdev->vlast_packet_size) {
-                               /* Shorter packet... We probably have the end of an image-frame;
-                                  wake up read() process and let select()/poll() do something.
-                                  Decompression is done in user time over there.
-                                  */
-                               if (pdev->vsync == 2) {
-                                       if (pwc_rcv_short_packet(pdev, fbuf)) {
-                                               awake = 1;
-                                               fbuf = pdev->fill_frame;
-                                       }
-                               }
-                               fbuf->filled = 0;
-                               fillptr = fbuf->data;
+                       }
+               }
+               if (flen < pdev->vlast_packet_size) {
+                       /* Shorter packet... end of frame */
+                       if (pdev->vsync == 2)
+                               pwc_frame_complete(pdev);
+                       if (pdev->fill_buf == NULL)
+                               pdev->fill_buf = pwc_get_next_fill_buf(pdev);
+                       if (pdev->fill_buf) {
+                               pdev->fill_buf->filled = 0;
                                pdev->vsync = 1;
                        }
-
-                       pdev->vlast_packet_size = flen;
-               } /* ..status == 0 */
-               else {
-                       /* This is normally not interesting to the user, unless
-                        * you are really debugging something, default = 0 */
-                       static int iso_error;
-                       iso_error++;
-                       if (iso_error < 20)
-                               PWC_DEBUG_FLOW("Iso frame %d of USB has error %d\n", i, fst);
                }
+               pdev->vlast_packet_size = flen;
        }
 
 handler_end:
-       if (awake)
-               wake_up_interruptible(&pdev->frameq);
-
-       urb->dev = pdev->udev;
        i = usb_submit_urb(urb, GFP_ATOMIC);
        if (i != 0)
                PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
 }
 
-
-int pwc_isoc_init(struct pwc_device *pdev)
+static int pwc_isoc_init(struct pwc_device *pdev)
 {
        struct usb_device *udev;
        struct urb *urb;
        int i, j, ret;
-
        struct usb_interface *intf;
        struct usb_host_interface *idesc = NULL;
 
-       if (pdev == NULL)
-               return -EFAULT;
        if (pdev->iso_init)
                return 0;
+
        pdev->vsync = 0;
+       pdev->vlast_packet_size = 0;
+       pdev->fill_buf = NULL;
+       pdev->vframe_count = 0;
+       pdev->visoc_errors = 0;
        udev = pdev->udev;
 
        /* Get the current alternate interface, adjust packet size */
-       if (!udev->actconfig)
-               return -EFAULT;
        intf = usb_ifnum_to_if(udev, 0);
        if (intf)
                idesc = usb_altnum_to_altsetting(intf, pdev->valternate);
-
        if (!idesc)
-               return -EFAULT;
+               return -EIO;
 
        /* Search video endpoint */
        pdev->vmax_packet_size = -1;
@@ -825,34 +414,32 @@ int pwc_isoc_init(struct pwc_device *pdev)
        if (ret < 0)
                return ret;
 
+       /* Allocate and init Isochronuous urbs */
        for (i = 0; i < MAX_ISO_BUFS; i++) {
                urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
                if (urb == NULL) {
                        PWC_ERROR("Failed to allocate urb %d\n", i);
-                       ret = -ENOMEM;
-                       break;
+                       pdev->iso_init = 1;
+                       pwc_isoc_cleanup(pdev);
+                       return -ENOMEM;
                }
-               pdev->sbuf[i].urb = urb;
+               pdev->urbs[i] = urb;
                PWC_DEBUG_MEMORY("Allocated URB at 0x%p\n", urb);
-       }
-       if (ret) {
-               /* De-allocate in reverse order */
-               while (i--) {
-                       usb_free_urb(pdev->sbuf[i].urb);
-                       pdev->sbuf[i].urb = NULL;
-               }
-               return ret;
-       }
-
-       /* init URB structure */
-       for (i = 0; i < MAX_ISO_BUFS; i++) {
-               urb = pdev->sbuf[i].urb;
 
                urb->interval = 1; // devik
                urb->dev = udev;
                urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint);
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->transfer_buffer = pdev->sbuf[i].data;
+               urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+               urb->transfer_buffer = usb_alloc_coherent(udev,
+                                                         ISO_BUFFER_SIZE,
+                                                         GFP_KERNEL,
+                                                         &urb->transfer_dma);
+               if (urb->transfer_buffer == NULL) {
+                       PWC_ERROR("Failed to allocate urb buffer %d\n", i);
+                       pdev->iso_init = 1;
+                       pwc_isoc_cleanup(pdev);
+                       return -ENOMEM;
+               }
                urb->transfer_buffer_length = ISO_BUFFER_SIZE;
                urb->complete = pwc_isoc_handler;
                urb->context = pdev;
@@ -866,14 +453,14 @@ int pwc_isoc_init(struct pwc_device *pdev)
 
        /* link */
        for (i = 0; i < MAX_ISO_BUFS; i++) {
-               ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL);
+               ret = usb_submit_urb(pdev->urbs[i], GFP_KERNEL);
                if (ret) {
                        PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret);
                        pdev->iso_init = 1;
                        pwc_isoc_cleanup(pdev);
                        return ret;
                }
-               PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->sbuf[i].urb);
+               PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->urbs[i]);
        }
 
        /* All is done... */
@@ -888,12 +475,9 @@ static void pwc_iso_stop(struct pwc_device *pdev)
 
        /* Unlinking ISOC buffers one by one */
        for (i = 0; i < MAX_ISO_BUFS; i++) {
-               struct urb *urb;
-
-               urb = pdev->sbuf[i].urb;
-               if (urb) {
-                       PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb);
-                       usb_kill_urb(urb);
+               if (pdev->urbs[i]) {
+                       PWC_DEBUG_MEMORY("Unlinking URB %p\n", pdev->urbs[i]);
+                       usb_kill_urb(pdev->urbs[i]);
                }
        }
 }
@@ -904,40 +488,51 @@ static void pwc_iso_free(struct pwc_device *pdev)
 
        /* Freeing ISOC buffers one by one */
        for (i = 0; i < MAX_ISO_BUFS; i++) {
-               struct urb *urb;
-
-               urb = pdev->sbuf[i].urb;
-               if (urb) {
+               if (pdev->urbs[i]) {
                        PWC_DEBUG_MEMORY("Freeing URB\n");
-                       usb_free_urb(urb);
-                       pdev->sbuf[i].urb = NULL;
+                       if (pdev->urbs[i]->transfer_buffer) {
+                               usb_free_coherent(pdev->udev,
+                                       pdev->urbs[i]->transfer_buffer_length,
+                                       pdev->urbs[i]->transfer_buffer,
+                                       pdev->urbs[i]->transfer_dma);
+                       }
+                       usb_free_urb(pdev->urbs[i]);
+                       pdev->urbs[i] = NULL;
                }
        }
 }
 
-void pwc_isoc_cleanup(struct pwc_device *pdev)
+static void pwc_isoc_cleanup(struct pwc_device *pdev)
 {
        PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n");
-       if (pdev == NULL)
-               return;
+
        if (pdev->iso_init == 0)
                return;
 
        pwc_iso_stop(pdev);
        pwc_iso_free(pdev);
-
-       /* Stop camera, but only if we are sure the camera is still there (unplug
-          is signalled by EPIPE)
-        */
-       if (pdev->error_status != EPIPE) {
-               PWC_DEBUG_OPEN("Setting alternate interface 0.\n");
-               usb_set_interface(pdev->udev, 0, 0);
-       }
+       usb_set_interface(pdev->udev, 0, 0);
 
        pdev->iso_init = 0;
        PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n");
 }
 
+/*
+ * Release all queued buffers, no need to take queued_bufs_lock, since all
+ * iso urbs have been killed when we're called so pwc_isoc_handler won't run.
+ */
+static void pwc_cleanup_queued_bufs(struct pwc_device *pdev)
+{
+       while (!list_empty(&pdev->queued_bufs)) {
+               struct pwc_frame_buf *buf;
+
+               buf = list_entry(pdev->queued_bufs.next, struct pwc_frame_buf,
+                                list);
+               list_del(&buf->list);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+       }
+}
+
 /*********
  * sysfs
  *********/
@@ -1051,98 +646,15 @@ static const char *pwc_sensor_type_to_string(unsigned int sensor_type)
 
 static int pwc_video_open(struct file *file)
 {
-       int i, ret;
        struct video_device *vdev = video_devdata(file);
        struct pwc_device *pdev;
 
        PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev);
 
        pdev = video_get_drvdata(vdev);
-       BUG_ON(!pdev);
-       if (pdev->vopen) {
-               PWC_DEBUG_OPEN("I'm busy, someone is using the device.\n");
-               return -EBUSY;
-       }
-
-       pwc_construct(pdev); /* set min/max sizes correct */
-       if (!pdev->usb_init) {
-               PWC_DEBUG_OPEN("Doing first time initialization.\n");
-               pdev->usb_init = 1;
-
-               /* Query sensor type */
-               ret = pwc_get_cmos_sensor(pdev, &i);
-               if (ret >= 0)
-               {
-                       PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n",
-                                       pdev->vdev.name,
-                                       pwc_sensor_type_to_string(i), i);
-               }
-       }
-
-       /* Turn on camera */
-       if (power_save) {
-               i = pwc_camera_power(pdev, 1);
-               if (i < 0)
-                       PWC_DEBUG_OPEN("Failed to restore power to the camera! (%d)\n", i);
-       }
-       /* Set LED on/off time */
-       if (pwc_set_leds(pdev, led_on, led_off) < 0)
-               PWC_DEBUG_OPEN("Failed to set LED on/off time.\n");
-
-
-       /* So far, so good. Allocate memory. */
-       i = pwc_allocate_buffers(pdev);
-       if (i < 0) {
-               PWC_DEBUG_OPEN("Failed to allocate buffers memory.\n");
-               pwc_free_buffers(pdev);
-               return i;
-       }
-
-       /* Reset buffers & parameters */
-       pwc_reset_buffers(pdev);
-       for (i = 0; i < pwc_mbufs; i++)
-               pdev->image_used[i] = 0;
-       pdev->vframe_count = 0;
-       pdev->vframes_dumped = 0;
-       pdev->vframes_error = 0;
-       pdev->visoc_errors = 0;
-       pdev->error_status = 0;
-       pwc_construct(pdev); /* set min/max sizes correct */
-
-       /* Set some defaults */
-       pdev->vsnapshot = 0;
-
-       /* Set video size, first try the last used video size
-          (or the default one); if that fails try QCIF/10 or QSIF/10;
-          it that fails too, give up.
-        */
-       i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0);
-       if (i)  {
-               unsigned int default_resolution;
-               PWC_DEBUG_OPEN("First attempt at set_video_mode failed.\n");
-               if (pdev->type>= 730)
-                       default_resolution = PSZ_QSIF;
-               else
-                       default_resolution = PSZ_QCIF;
-
-               i = pwc_set_video_mode(pdev,
-                                      pwc_image_sizes[default_resolution].x,
-                                      pwc_image_sizes[default_resolution].y,
-                                      10,
-                                      pdev->vcompression,
-                                      0);
-       }
-       if (i) {
-               PWC_DEBUG_OPEN("Second attempt at set_video_mode failed.\n");
-               pwc_free_buffers(pdev);
-               return i;
-       }
-
-       /* Initialize the webcam to sane value */
-       pwc_set_brightness(pdev, 0x7fff);
-       pwc_set_agc(pdev, 1, 0);
+       if (!pdev->udev)
+               return -ENODEV;
 
-       pdev->vopen++;
        file->private_data = vdev;
        PWC_DEBUG_OPEN("<< video_open() returns 0.\n");
        return 0;
@@ -1158,239 +670,211 @@ static void pwc_video_release(struct video_device *vfd)
                if (device_hint[hint].pdev == pdev)
                        device_hint[hint].pdev = NULL;
 
+       /* Free intermediate decompression buffer & tables */
+       if (pdev->decompress_data != NULL) {
+               PWC_DEBUG_MEMORY("Freeing decompression buffer at %p.\n",
+                                pdev->decompress_data);
+               kfree(pdev->decompress_data);
+               pdev->decompress_data = NULL;
+       }
+
+       v4l2_ctrl_handler_free(&pdev->ctrl_handler);
+
        kfree(pdev);
 }
 
-/* Note that all cleanup is done in the reverse order as in _open */
 static int pwc_video_close(struct file *file)
 {
        struct video_device *vdev = file->private_data;
        struct pwc_device *pdev;
-       int i;
 
        PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);
 
        pdev = video_get_drvdata(vdev);
-       if (pdev->vopen == 0)
-               PWC_DEBUG_MODULE("video_close() called on closed device?\n");
-
-       /* Dump statistics, but only if a reasonable amount of frames were
-          processed (to prevent endless log-entries in case of snap-shot
-          programs)
-        */
-       if (pdev->vframe_count > 20)
-               PWC_DEBUG_MODULE("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error);
-
-       if (DEVICE_USE_CODEC1(pdev->type))
-           pwc_dec1_exit();
-       else
-           pwc_dec23_exit();
-
-       pwc_isoc_cleanup(pdev);
-       pwc_free_buffers(pdev);
-
-       /* Turn off LEDS and power down camera, but only when not unplugged */
-       if (!pdev->unplugged) {
-               /* Turn LEDs off */
-               if (pwc_set_leds(pdev, 0, 0) < 0)
-                       PWC_DEBUG_MODULE("Failed to set LED on/off time.\n");
-               if (power_save) {
-                       i = pwc_camera_power(pdev, 0);
-                       if (i < 0)
-                               PWC_ERROR("Failed to power down camera (%d)\n", i);
-               }
-               pdev->vopen--;
-               PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen);
+       if (pdev->capt_file == file) {
+               vb2_queue_release(&pdev->vb_queue);
+               pdev->capt_file = NULL;
        }
 
+       PWC_DEBUG_OPEN("<< video_close()\n");
        return 0;
 }
 
-/*
- *     FIXME: what about two parallel reads ????
- *      ANSWER: Not supported. You can't open the device more than once,
-               despite what the V4L1 interface says. First, I don't see
-               the need, second there's no mechanism of alerting the
-               2nd/3rd/... process of events like changing image size.
-               And I don't see the point of blocking that for the
-               2nd/3rd/... process.
-               In multi-threaded environments reading parallel from any
-               device is tricky anyhow.
- */
-
 static ssize_t pwc_video_read(struct file *file, char __user *buf,
-                         size_t count, loff_t *ppos)
+                             size_t count, loff_t *ppos)
 {
        struct video_device *vdev = file->private_data;
-       struct pwc_device *pdev;
-       int noblock = file->f_flags & O_NONBLOCK;
-       DECLARE_WAITQUEUE(wait, current);
-       int bytes_to_read, rv = 0;
-       void *image_buffer_addr;
-
-       PWC_DEBUG_READ("pwc_video_read(vdev=0x%p, buf=%p, count=%zd) called.\n",
-                       vdev, buf, count);
-       if (vdev == NULL)
-               return -EFAULT;
-       pdev = video_get_drvdata(vdev);
-       if (pdev == NULL)
-               return -EFAULT;
+       struct pwc_device *pdev = video_get_drvdata(vdev);
 
-       if (pdev->error_status) {
-               rv = -pdev->error_status; /* Something happened, report what. */
-               goto err_out;
-       }
+       if (!pdev->udev)
+               return -ENODEV;
 
-       /* Start the stream (if not already started) */
-       rv = pwc_isoc_init(pdev);
-       if (rv)
-               goto err_out;
-
-       /* In case we're doing partial reads, we don't have to wait for a frame */
-       if (pdev->image_read_pos == 0) {
-               /* Do wait queueing according to the (doc)book */
-               add_wait_queue(&pdev->frameq, &wait);
-               while (pdev->full_frames == NULL) {
-                       /* Check for unplugged/etc. here */
-                       if (pdev->error_status) {
-                               remove_wait_queue(&pdev->frameq, &wait);
-                               set_current_state(TASK_RUNNING);
-                               rv = -pdev->error_status ;
-                               goto err_out;
-                       }
-                       if (noblock) {
-                               remove_wait_queue(&pdev->frameq, &wait);
-                               set_current_state(TASK_RUNNING);
-                               rv = -EWOULDBLOCK;
-                               goto err_out;
-                       }
-                       if (signal_pending(current)) {
-                               remove_wait_queue(&pdev->frameq, &wait);
-                               set_current_state(TASK_RUNNING);
-                               rv = -ERESTARTSYS;
-                               goto err_out;
-                       }
-                       mutex_unlock(&pdev->modlock);
-                       schedule();
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       mutex_lock(&pdev->modlock);
-               }
-               remove_wait_queue(&pdev->frameq, &wait);
-               set_current_state(TASK_RUNNING);
+       if (pdev->capt_file != NULL &&
+           pdev->capt_file != file)
+               return -EBUSY;
 
-               /* Decompress and release frame */
-               if (pwc_handle_frame(pdev)) {
-                       rv = -EFAULT;
-                       goto err_out;
-               }
-       }
+       pdev->capt_file = file;
 
-       PWC_DEBUG_READ("Copying data to user space.\n");
-       if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
-               bytes_to_read = pdev->frame_size + sizeof(struct pwc_raw_frame);
-       else
-               bytes_to_read = pdev->view.size;
-
-       /* copy bytes to user space; we allow for partial reads */
-       if (count + pdev->image_read_pos > bytes_to_read)
-               count = bytes_to_read - pdev->image_read_pos;
-       image_buffer_addr = pdev->image_data;
-       image_buffer_addr += pdev->images[pdev->fill_image].offset;
-       image_buffer_addr += pdev->image_read_pos;
-       if (copy_to_user(buf, image_buffer_addr, count)) {
-               rv = -EFAULT;
-               goto err_out;
-       }
-       pdev->image_read_pos += count;
-       if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */
-               pdev->image_read_pos = 0;
-               pwc_next_image(pdev);
-       }
-       return count;
-err_out:
-       return rv;
+       return vb2_read(&pdev->vb_queue, buf, count, ppos,
+                       file->f_flags & O_NONBLOCK);
 }
 
 static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
 {
        struct video_device *vdev = file->private_data;
-       struct pwc_device *pdev;
-       int ret;
+       struct pwc_device *pdev = video_get_drvdata(vdev);
 
-       if (vdev == NULL)
-               return -EFAULT;
-       pdev = video_get_drvdata(vdev);
-       if (pdev == NULL)
-               return -EFAULT;
+       if (!pdev->udev)
+               return POLL_ERR;
 
-       /* Start the stream (if not already started) */
-       ret = pwc_isoc_init(pdev);
-       if (ret)
-               return ret;
+       return vb2_poll(&pdev->vb_queue, file, wait);
+}
+
+static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct video_device *vdev = file->private_data;
+       struct pwc_device *pdev = video_get_drvdata(vdev);
+
+       if (pdev->capt_file != file)
+               return -EBUSY;
+
+       return vb2_mmap(&pdev->vb_queue, vma);
+}
+
+/***************************************************************************/
+/* Videobuf2 operations */
+
+static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
+                               unsigned int *nplanes, unsigned long sizes[],
+                               void *alloc_ctxs[])
+{
+       struct pwc_device *pdev = vb2_get_drv_priv(vq);
+
+       if (*nbuffers < MIN_FRAMES)
+               *nbuffers = MIN_FRAMES;
+       else if (*nbuffers > MAX_FRAMES)
+               *nbuffers = MAX_FRAMES;
+
+       *nplanes = 1;
 
-       poll_wait(file, &pdev->frameq, wait);
-       if (pdev->error_status)
-               return POLLERR;
-       if (pdev->full_frames != NULL) /* we have frames waiting */
-               return (POLLIN | POLLRDNORM);
+       sizes[0] = PAGE_ALIGN((pdev->abs_max.x * pdev->abs_max.y * 3) / 2);
 
        return 0;
 }
 
-static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
+static int buffer_init(struct vb2_buffer *vb)
 {
-       struct video_device *vdev = file->private_data;
-       struct pwc_device *pdev;
-       unsigned long start;
-       unsigned long size;
-       unsigned long page, pos = 0;
-       int index;
+       struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
 
-       PWC_DEBUG_MEMORY(">> %s\n", __func__);
-       pdev = video_get_drvdata(vdev);
-       size = vma->vm_end - vma->vm_start;
-       start = vma->vm_start;
+       /* need vmalloc since frame buffer > 128K */
+       buf->data = vzalloc(PWC_FRAME_SIZE);
+       if (buf->data == NULL)
+               return -ENOMEM;
 
-       /* Find the idx buffer for this mapping */
-       for (index = 0; index < pwc_mbufs; index++) {
-               pos = pdev->images[index].offset;
-               if ((pos>>PAGE_SHIFT) == vma->vm_pgoff)
-                       break;
+       return 0;
+}
+
+static int buffer_prepare(struct vb2_buffer *vb)
+{
+       struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue);
+
+       /* Don't allow queing new buffers after device disconnection */
+       if (!pdev->udev)
+               return -ENODEV;
+
+       return 0;
+}
+
+static int buffer_finish(struct vb2_buffer *vb)
+{
+       struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue);
+       struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
+
+       /*
+        * Application has called dqbuf and is getting back a buffer we've
+        * filled, take the pwc data we've stored in buf->data and decompress
+        * it into a usable format, storing the result in the vb2_buffer
+        */
+       return pwc_decompress(pdev, buf);
+}
+
+static void buffer_cleanup(struct vb2_buffer *vb)
+{
+       struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
+
+       vfree(buf->data);
+}
+
+static void buffer_queue(struct vb2_buffer *vb)
+{
+       struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue);
+       struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
+       unsigned long flags = 0;
+
+       spin_lock_irqsave(&pdev->queued_bufs_lock, flags);
+       list_add_tail(&buf->list, &pdev->queued_bufs);
+       spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags);
+}
+
+static int start_streaming(struct vb2_queue *vq)
+{
+       struct pwc_device *pdev = vb2_get_drv_priv(vq);
+
+       if (!pdev->udev)
+               return -ENODEV;
+
+       /* Turn on camera and set LEDS on */
+       pwc_camera_power(pdev, 1);
+       if (pdev->power_save) {
+               /* Restore video mode */
+               pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y,
+                                  pdev->vframes, pdev->vcompression,
+                                  pdev->vsnapshot);
        }
-       if (index == MAX_IMAGES)
-               return -EINVAL;
-       if (index == 0) {
-               /*
-                * Special case for v4l1. In v4l1, we map only one big buffer,
-                * but in v4l2 each buffer is mapped
-                */
-               unsigned long total_size;
-               total_size = pwc_mbufs * pdev->len_per_image;
-               if (size != pdev->len_per_image && size != total_size) {
-                       PWC_ERROR("Wrong size (%lu) needed to be len_per_image=%d or total_size=%lu\n",
-                                  size, pdev->len_per_image, total_size);
-                       return -EINVAL;
-               }
-       } else if (size > pdev->len_per_image)
-               return -EINVAL;
-
-       vma->vm_flags |= VM_IO; /* from 2.6.9-acX */
-
-       pos += (unsigned long)pdev->image_data;
-       while (size > 0) {
-               page = vmalloc_to_pfn((void *)pos);
-               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
-                       return -EAGAIN;
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               if (size > PAGE_SIZE)
-                       size -= PAGE_SIZE;
-               else
-                       size = 0;
+       pwc_set_leds(pdev, led_on, led_off);
+
+       return pwc_isoc_init(pdev);
+}
+
+static int stop_streaming(struct vb2_queue *vq)
+{
+       struct pwc_device *pdev = vb2_get_drv_priv(vq);
+
+       if (pdev->udev) {
+               pwc_set_leds(pdev, 0, 0);
+               pwc_camera_power(pdev, 0);
+               pwc_isoc_cleanup(pdev);
        }
+       pwc_cleanup_queued_bufs(pdev);
+
        return 0;
 }
 
+static void pwc_lock(struct vb2_queue *vq)
+{
+       struct pwc_device *pdev = vb2_get_drv_priv(vq);
+       mutex_lock(&pdev->modlock);
+}
+
+static void pwc_unlock(struct vb2_queue *vq)
+{
+       struct pwc_device *pdev = vb2_get_drv_priv(vq);
+       mutex_unlock(&pdev->modlock);
+}
+
+static struct vb2_ops pwc_vb_queue_ops = {
+       .queue_setup            = queue_setup,
+       .buf_init               = buffer_init,
+       .buf_prepare            = buffer_prepare,
+       .buf_finish             = buffer_finish,
+       .buf_cleanup            = buffer_cleanup,
+       .buf_queue              = buffer_queue,
+       .start_streaming        = start_streaming,
+       .stop_streaming         = stop_streaming,
+       .wait_prepare           = pwc_unlock,
+       .wait_finish            = pwc_lock,
+};
+
 /***************************************************************************/
 /* USB functions */
 
@@ -1406,6 +890,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        int hint, rc;
        int features = 0;
        int video_nr = -1; /* default: use next available device */
+       int my_power_save = power_save;
        char serial_number[30], *name;
 
        vendor_id = le16_to_cpu(udev->descriptor.idVendor);
@@ -1513,6 +998,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                        PWC_INFO("Logitech QuickCam 4000 Pro USB webcam detected.\n");
                        name = "Logitech QuickCam Pro 4000";
                        type_id = 740; /* CCD sensor */
+                       if (my_power_save == -1)
+                               my_power_save = 1;
                        break;
                case 0x08b3:
                        PWC_INFO("Logitech QuickCam Zoom USB webcam detected.\n");
@@ -1523,12 +1010,15 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                        PWC_INFO("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
                        name = "Logitech QuickCam Zoom";
                        type_id = 740; /* CCD sensor */
-                       power_save = 1;
+                       if (my_power_save == -1)
+                               my_power_save = 1;
                        break;
                case 0x08b5:
                        PWC_INFO("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
                        name = "Logitech QuickCam Orbit";
                        type_id = 740; /* CCD sensor */
+                       if (my_power_save == -1)
+                               my_power_save = 1;
                        features |= FEATURE_MOTOR_PANTILT;
                        break;
                case 0x08b6:
@@ -1583,6 +1073,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                        PWC_INFO("Creative Labs Webcam 5 detected.\n");
                        name = "Creative Labs Webcam 5";
                        type_id = 730;
+                       if (my_power_save == -1)
+                               my_power_save = 1;
                        break;
                case 0x4011:
                        PWC_INFO("Creative Labs Webcam Pro Ex detected.\n");
@@ -1640,6 +1132,9 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        else
                return -ENODEV; /* Not any of the know types; but the list keeps growing. */
 
+       if (my_power_save == -1)
+               my_power_save = 0;
+
        memset(serial_number, 0, 30);
        usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29);
        PWC_DEBUG_PROBE("Device serial number is %s\n", serial_number);
@@ -1654,7 +1149,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                return -ENOMEM;
        }
        pdev->type = type_id;
-       pdev->vsize = default_size;
        pdev->vframes = default_fps;
        strcpy(pdev->serial, serial_number);
        pdev->features = features;
@@ -1668,13 +1162,26 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                pdev->angle_range.tilt_min = -3000;
                pdev->angle_range.tilt_max =  2500;
        }
+       pwc_construct(pdev); /* set min/max sizes correct */
 
        mutex_init(&pdev->modlock);
-       spin_lock_init(&pdev->ptrlock);
+       mutex_init(&pdev->udevlock);
+       spin_lock_init(&pdev->queued_bufs_lock);
+       INIT_LIST_HEAD(&pdev->queued_bufs);
 
        pdev->udev = udev;
-       init_waitqueue_head(&pdev->frameq);
        pdev->vcompression = pwc_preferred_compression;
+       pdev->power_save = my_power_save;
+
+       /* Init videobuf2 queue structure */
+       memset(&pdev->vb_queue, 0, sizeof(pdev->vb_queue));
+       pdev->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       pdev->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+       pdev->vb_queue.drv_priv = pdev;
+       pdev->vb_queue.buf_struct_size = sizeof(struct pwc_frame_buf);
+       pdev->vb_queue.ops = &pwc_vb_queue_ops;
+       pdev->vb_queue.mem_ops = &vb2_vmalloc_memops;
+       vb2_queue_init(&pdev->vb_queue);
 
        /* Init video_device structure */
        memcpy(&pdev->vdev, &pwc_template, sizeof(pwc_template));
@@ -1707,14 +1214,40 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev);
        usb_set_intfdata(intf, pdev);
 
+#ifdef CONFIG_USB_PWC_DEBUG
+       /* Query sensor type */
+       if (pwc_get_cmos_sensor(pdev, &rc) >= 0) {
+               PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n",
+                               pdev->vdev.name,
+                               pwc_sensor_type_to_string(rc), rc);
+       }
+#endif
+
        /* Set the leds off */
        pwc_set_leds(pdev, 0, 0);
+
+       /* Setup intial videomode */
+       rc = pwc_set_video_mode(pdev, pdev->view_max.x, pdev->view_max.y,
+                               pdev->vframes, pdev->vcompression, 0);
+       if (rc)
+               goto err_free_mem;
+
+       /* Register controls (and read default values from camera */
+       rc = pwc_init_controls(pdev);
+       if (rc) {
+               PWC_ERROR("Failed to register v4l2 controls (%d).\n", rc);
+               goto err_free_mem;
+       }
+
+       pdev->vdev.ctrl_handler = &pdev->ctrl_handler;
+
+       /* And powerdown the camera until streaming starts */
        pwc_camera_power(pdev, 0);
 
        rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, video_nr);
        if (rc < 0) {
                PWC_ERROR("Failed to register as video device (%d).\n", rc);
-               goto err_free_mem;
+               goto err_free_controls;
        }
        rc = pwc_create_sysfs_files(pdev);
        if (rc)
@@ -1757,7 +1290,10 @@ err_video_unreg:
        if (hint < MAX_DEV_HINTS)
                device_hint[hint].pdev = NULL;
        video_unregister_device(&pdev->vdev);
+err_free_controls:
+       v4l2_ctrl_handler_free(&pdev->ctrl_handler);
 err_free_mem:
+       usb_set_intfdata(intf, NULL);
        kfree(pdev);
        return rc;
 }
@@ -1767,33 +1303,17 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
 {
        struct pwc_device *pdev  = usb_get_intfdata(intf);
 
+       mutex_lock(&pdev->udevlock);
        mutex_lock(&pdev->modlock);
-       usb_set_intfdata (intf, NULL);
-       if (pdev == NULL) {
-               PWC_ERROR("pwc_disconnect() Called without private pointer.\n");
-               goto disconnect_out;
-       }
-       if (pdev->udev == NULL) {
-               PWC_ERROR("pwc_disconnect() already called for %p\n", pdev);
-               goto disconnect_out;
-       }
-       if (pdev->udev != interface_to_usbdev(intf)) {
-               PWC_ERROR("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n");
-               goto disconnect_out;
-       }
-
-       /* We got unplugged; this is signalled by an EPIPE error code */
-       pdev->error_status = EPIPE;
-       pdev->unplugged = 1;
-
-       /* Alert waiting processes */
-       wake_up_interruptible(&pdev->frameq);
 
+       usb_set_intfdata(intf, NULL);
        /* No need to keep the urbs around after disconnection */
        pwc_isoc_cleanup(pdev);
+       pwc_cleanup_queued_bufs(pdev);
+       pdev->udev = NULL;
 
-disconnect_out:
        mutex_unlock(&pdev->modlock);
+       mutex_unlock(&pdev->udevlock);
 
        pwc_remove_sysfs_files(pdev);
        video_unregister_device(&pdev->vdev);
@@ -1809,36 +1329,27 @@ disconnect_out:
  * Initialization code & module stuff
  */
 
-static char *size;
 static int fps;
-static int fbufs;
-static int mbufs;
 static int compression = -1;
 static int leds[2] = { -1, -1 };
 static unsigned int leds_nargs;
 static char *dev_hint[MAX_DEV_HINTS];
 static unsigned int dev_hint_nargs;
 
-module_param(size, charp, 0444);
 module_param(fps, int, 0444);
-module_param(fbufs, int, 0444);
-module_param(mbufs, int, 0444);
 #ifdef CONFIG_USB_PWC_DEBUG
 module_param_named(trace, pwc_trace, int, 0644);
 #endif
-module_param(power_save, int, 0444);
+module_param(power_save, int, 0644);
 module_param(compression, int, 0444);
 module_param_array(leds, int, &leds_nargs, 0444);
 module_param_array(dev_hint, charp, &dev_hint_nargs, 0444);
 
-MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga");
 MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30");
-MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve");
-MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers");
 #ifdef CONFIG_USB_PWC_DEBUG
 MODULE_PARM_DESC(trace, "For debugging purposes");
 #endif
-MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off");
+MODULE_PARM_DESC(power_save, "Turn power saving for new cameras on or off");
 MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)");
 MODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
 MODULE_PARM_DESC(dev_hint, "Device node hints");
@@ -1851,14 +1362,19 @@ MODULE_VERSION( PWC_VERSION );
 
 static int __init usb_pwc_init(void)
 {
-       int i, sz;
-       char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" };
+       int i;
 
+#ifdef CONFIG_USB_PWC_DEBUG
        PWC_INFO("Philips webcam module version " PWC_VERSION " loaded.\n");
        PWC_INFO("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n");
        PWC_INFO("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
        PWC_INFO("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n");
 
+       if (pwc_trace >= 0) {
+               PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace);
+       }
+#endif
+
        if (fps) {
                if (fps < 4 || fps > 30) {
                        PWC_ERROR("Framerate out of bounds (4-30).\n");
@@ -1868,41 +1384,6 @@ static int __init usb_pwc_init(void)
                PWC_DEBUG_MODULE("Default framerate set to %d.\n", default_fps);
        }
 
-       if (size) {
-               /* string; try matching with array */
-               for (sz = 0; sz < PSZ_MAX; sz++) {
-                       if (!strcmp(sizenames[sz], size)) { /* Found! */
-                               default_size = sz;
-                               break;
-                       }
-               }
-               if (sz == PSZ_MAX) {
-                       PWC_ERROR("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n");
-                       return -EINVAL;
-               }
-               PWC_DEBUG_MODULE("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y);
-       }
-       if (mbufs) {
-               if (mbufs < 1 || mbufs > MAX_IMAGES) {
-                       PWC_ERROR("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES);
-                       return -EINVAL;
-               }
-               pwc_mbufs = mbufs;
-               PWC_DEBUG_MODULE("Number of image buffers set to %d.\n", pwc_mbufs);
-       }
-       if (fbufs) {
-               if (fbufs < 2 || fbufs > MAX_FRAMES) {
-                       PWC_ERROR("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES);
-                       return -EINVAL;
-               }
-               default_fbufs = fbufs;
-               PWC_DEBUG_MODULE("Number of frame buffers set to %d.\n", default_fbufs);
-       }
-#ifdef CONFIG_USB_PWC_DEBUG
-       if (pwc_trace >= 0) {
-               PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace);
-       }
-#endif
        if (compression >= 0) {
                if (compression > 3) {
                        PWC_ERROR("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
@@ -1911,8 +1392,6 @@ static int __init usb_pwc_init(void)
                pwc_preferred_compression = compression;
                PWC_DEBUG_MODULE("Preferred compression set to %d.\n", pwc_preferred_compression);
        }
-       if (power_save)
-               PWC_DEBUG_MODULE("Enabling power save on open/close.\n");
        if (leds[0] >= 0)
                led_on = leds[0];
        if (leds[1] >= 0)
diff --git a/drivers/media/video/pwc/pwc-ioctl.h b/drivers/media/video/pwc/pwc-ioctl.h
deleted file mode 100644 (file)
index 8c0cae7..0000000
+++ /dev/null
@@ -1,323 +0,0 @@
-#ifndef PWC_IOCTL_H
-#define PWC_IOCTL_H
-
-/* (C) 2001-2004 Nemosoft Unv.
-   (C) 2004-2006 Luc Saillard (luc@saillard.org)
-
-   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
-   driver and thus may have bugs that are not present in the original version.
-   Please send bug reports and support requests to <luc@saillard.org>.
-   The decompression routines have been implemented by reverse-engineering the
-   Nemosoft binary pwcx module. Caveat emptor.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-/* This is pwc-ioctl.h belonging to PWC 10.0.10
-   It contains structures and defines to communicate from user space
-   directly to the driver.
- */
-
-/*
-   Changes
-   2001/08/03  Alvarado   Added ioctl constants to access methods for
-                         changing white balance and red/blue gains
-   2002/12/15  G. H. Fernandez-Toribio   VIDIOCGREALSIZE
-   2003/12/13  Nemosft Unv. Some modifications to make interfacing to
-              PWCX easier
- */
-
-/* These are private ioctl() commands, specific for the Philips webcams.
-   They contain functions not found in other webcams, and settings not
-   specified in the Video4Linux API.
-
-   The #define names are built up like follows:
-   VIDIOC              VIDeo IOCtl prefix
-        PWC            Philps WebCam
-           G           optional: Get
-           S           optional: Set
-            ...        the function
- */
-
-#include <linux/types.h>
-#include <linux/version.h>
-
- /* Enumeration of image sizes */
-#define PSZ_SQCIF      0x00
-#define PSZ_QSIF       0x01
-#define PSZ_QCIF       0x02
-#define PSZ_SIF                0x03
-#define PSZ_CIF                0x04
-#define PSZ_VGA                0x05
-#define PSZ_MAX                6
-
-
-/* The frame rate is encoded in the video_window.flags parameter using
-   the upper 16 bits, since some flags are defined nowadays. The following
-   defines provide a mask and shift to filter out this value.
-   This value can also be passing using the private flag when using v4l2 and
-   VIDIOC_S_FMT ioctl.
-
-   In 'Snapshot' mode the camera freezes its automatic exposure and colour
-   balance controls.
- */
-#define PWC_FPS_SHIFT          16
-#define PWC_FPS_MASK           0x00FF0000
-#define PWC_FPS_FRMASK         0x003F0000
-#define PWC_FPS_SNAPSHOT       0x00400000
-#define PWC_QLT_MASK           0x03000000
-#define PWC_QLT_SHIFT          24
-
-
-/* structure for transferring x & y coordinates */
-struct pwc_coord
-{
-       int x, y;               /* guess what */
-       int size;               /* size, or offset */
-};
-
-
-/* Used with VIDIOCPWCPROBE */
-struct pwc_probe
-{
-       char name[32];
-       int type;
-};
-
-struct pwc_serial
-{
-       char serial[30];        /* String with serial number. Contains terminating 0 */
-};
-
-/* pwc_whitebalance.mode values */
-#define PWC_WB_INDOOR          0
-#define PWC_WB_OUTDOOR         1
-#define PWC_WB_FL              2
-#define PWC_WB_MANUAL          3
-#define PWC_WB_AUTO            4
-
-/* Used with VIDIOCPWC[SG]AWB (Auto White Balance).
-   Set mode to one of the PWC_WB_* values above.
-   *red and *blue are the respective gains of these colour components inside
-   the camera; range 0..65535
-   When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read;
-   otherwise undefined.
-   'read_red' and 'read_blue' are read-only.
-*/
-struct pwc_whitebalance
-{
-       int mode;
-       int manual_red, manual_blue;    /* R/W */
-       int read_red, read_blue;        /* R/O */
-};
-
-/*
-   'control_speed' and 'control_delay' are used in automatic whitebalance mode,
-   and tell the camera how fast it should react to changes in lighting, and
-   with how much delay. Valid values are 0..65535.
-*/
-struct pwc_wb_speed
-{
-       int control_speed;
-       int control_delay;
-
-};
-
-/* Used with VIDIOCPWC[SG]LED */
-struct pwc_leds
-{
-       int led_on;                     /* Led on-time; range = 0..25000 */
-       int led_off;                    /* Led off-time; range = 0..25000  */
-};
-
-/* Image size (used with GREALSIZE) */
-struct pwc_imagesize
-{
-       int width;
-       int height;
-};
-
-/* Defines and structures for Motorized Pan & Tilt */
-#define PWC_MPT_PAN            0x01
-#define PWC_MPT_TILT           0x02
-#define PWC_MPT_TIMEOUT                0x04 /* for status */
-
-/* Set angles; when absolute != 0, the angle is absolute and the
-   driver calculates the relative offset for you. This can only
-   be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns
-   absolute angles.
- */
-struct pwc_mpt_angles
-{
-       int absolute;           /* write-only */
-       int pan;                /* degrees * 100 */
-       int tilt;               /* degress * 100 */
-};
-
-/* Range of angles of the camera, both horizontally and vertically.
- */
-struct pwc_mpt_range
-{
-       int pan_min, pan_max;           /* degrees * 100 */
-       int tilt_min, tilt_max;
-};
-
-struct pwc_mpt_status
-{
-       int status;
-       int time_pan;
-       int time_tilt;
-};
-
-
-/* This is used for out-of-kernel decompression. With it, you can get
-   all the necessary information to initialize and use the decompressor
-   routines in standalone applications.
- */
-struct pwc_video_command
-{
-       int type;               /* camera type (645, 675, 730, etc.) */
-       int release;            /* release number */
-
-       int size;               /* one of PSZ_* */
-       int alternate;
-       int command_len;        /* length of USB video command */
-       unsigned char command_buf[13];  /* Actual USB video command */
-       int bandlength;         /* >0 = compressed */
-       int frame_size;         /* Size of one (un)compressed frame */
-};
-
-/* Flags for PWCX subroutines. Not all modules honour all flags. */
-#define PWCX_FLAG_PLANAR       0x0001
-#define PWCX_FLAG_BAYER                0x0008
-
-
-/* IOCTL definitions */
-
- /* Restore user settings */
-#define VIDIOCPWCRUSER         _IO('v', 192)
- /* Save user settings */
-#define VIDIOCPWCSUSER         _IO('v', 193)
- /* Restore factory settings */
-#define VIDIOCPWCFACTORY       _IO('v', 194)
-
- /* You can manipulate the compression factor. A compression preference of 0
-    means use uncompressed modes when available; 1 is low compression, 2 is
-    medium and 3 is high compression preferred. Of course, the higher the
-    compression, the lower the bandwidth used but more chance of artefacts
-    in the image. The driver automatically chooses a higher compression when
-    the preferred mode is not available.
-  */
- /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */
-#define VIDIOCPWCSCQUAL                _IOW('v', 195, int)
- /* Get preferred compression quality */
-#define VIDIOCPWCGCQUAL                _IOR('v', 195, int)
-
-
-/* Retrieve serial number of camera */
-#define VIDIOCPWCGSERIAL       _IOR('v', 198, struct pwc_serial)
-
- /* This is a probe function; since so many devices are supported, it
-    becomes difficult to include all the names in programs that want to
-    check for the enhanced Philips stuff. So in stead, try this PROBE;
-    it returns a structure with the original name, and the corresponding
-    Philips type.
-    To use, fill the structure with zeroes, call PROBE and if that succeeds,
-    compare the name with that returned from VIDIOCGCAP; they should be the
-    same. If so, you can be assured it is a Philips (OEM) cam and the type
-    is valid.
- */
-#define VIDIOCPWCPROBE         _IOR('v', 199, struct pwc_probe)
-
- /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */
-#define VIDIOCPWCSAGC          _IOW('v', 200, int)
- /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */
-#define VIDIOCPWCGAGC          _IOR('v', 200, int)
- /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */
-#define VIDIOCPWCSSHUTTER      _IOW('v', 201, int)
-
- /* Color compensation (Auto White Balance) */
-#define VIDIOCPWCSAWB           _IOW('v', 202, struct pwc_whitebalance)
-#define VIDIOCPWCGAWB           _IOR('v', 202, struct pwc_whitebalance)
-
- /* Auto WB speed */
-#define VIDIOCPWCSAWBSPEED     _IOW('v', 203, struct pwc_wb_speed)
-#define VIDIOCPWCGAWBSPEED     _IOR('v', 203, struct pwc_wb_speed)
-
- /* LEDs on/off/blink; int range 0..65535 */
-#define VIDIOCPWCSLED           _IOW('v', 205, struct pwc_leds)
-#define VIDIOCPWCGLED           _IOR('v', 205, struct pwc_leds)
-
-  /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */
-#define VIDIOCPWCSCONTOUR      _IOW('v', 206, int)
-#define VIDIOCPWCGCONTOUR      _IOR('v', 206, int)
-
-  /* Backlight compensation; 0 = off, otherwise on */
-#define VIDIOCPWCSBACKLIGHT    _IOW('v', 207, int)
-#define VIDIOCPWCGBACKLIGHT    _IOR('v', 207, int)
-
-  /* Flickerless mode; = 0 off, otherwise on */
-#define VIDIOCPWCSFLICKER      _IOW('v', 208, int)
-#define VIDIOCPWCGFLICKER      _IOR('v', 208, int)
-
-  /* Dynamic noise reduction; 0 off, 3 = high noise reduction */
-#define VIDIOCPWCSDYNNOISE     _IOW('v', 209, int)
-#define VIDIOCPWCGDYNNOISE     _IOR('v', 209, int)
-
- /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */
-#define VIDIOCPWCGREALSIZE     _IOR('v', 210, struct pwc_imagesize)
-
- /* Motorized pan & tilt functions */
-#define VIDIOCPWCMPTRESET      _IOW('v', 211, int)
-#define VIDIOCPWCMPTGRANGE     _IOR('v', 211, struct pwc_mpt_range)
-#define VIDIOCPWCMPTSANGLE     _IOW('v', 212, struct pwc_mpt_angles)
-#define VIDIOCPWCMPTGANGLE     _IOR('v', 212, struct pwc_mpt_angles)
-#define VIDIOCPWCMPTSTATUS     _IOR('v', 213, struct pwc_mpt_status)
-
- /* Get the USB set-video command; needed for initializing libpwcx */
-#define VIDIOCPWCGVIDCMD       _IOR('v', 215, struct pwc_video_command)
-struct pwc_table_init_buffer {
-   int len;
-   char *buffer;
-
-};
-#define VIDIOCPWCGVIDTABLE     _IOR('v', 216, struct pwc_table_init_buffer)
-
-/*
- * This is private command used when communicating with v4l2.
- * In the future all private ioctl will be remove/replace to
- * use interface offer by v4l2.
- */
-
-#define V4L2_CID_PRIVATE_SAVE_USER       (V4L2_CID_PRIVATE_BASE + 0)
-#define V4L2_CID_PRIVATE_RESTORE_USER    (V4L2_CID_PRIVATE_BASE + 1)
-#define V4L2_CID_PRIVATE_RESTORE_FACTORY (V4L2_CID_PRIVATE_BASE + 2)
-#define V4L2_CID_PRIVATE_COLOUR_MODE     (V4L2_CID_PRIVATE_BASE + 3)
-#define V4L2_CID_PRIVATE_AUTOCONTOUR     (V4L2_CID_PRIVATE_BASE + 4)
-#define V4L2_CID_PRIVATE_CONTOUR         (V4L2_CID_PRIVATE_BASE + 5)
-#define V4L2_CID_PRIVATE_BACKLIGHT       (V4L2_CID_PRIVATE_BASE + 6)
-#define V4L2_CID_PRIVATE_FLICKERLESS     (V4L2_CID_PRIVATE_BASE + 7)
-#define V4L2_CID_PRIVATE_NOISE_REDUCTION (V4L2_CID_PRIVATE_BASE + 8)
-
-struct pwc_raw_frame {
-   __le16 type;                /* type of the webcam */
-   __le16 vbandlength; /* Size of 4lines compressed (used by the decompressor) */
-   __u8   cmd[4];      /* the four byte of the command (in case of nala,
-                          only the first 3 bytes is filled) */
-   __u8   rawframe[0]; /* frame_size = H/4*vbandlength */
-} __attribute__ ((packed));
-
-
-#endif
index f4ae83c..e5f4fd8 100644 (file)
@@ -40,7 +40,6 @@
 
 
 #include "pwc-kiara.h"
-#include "pwc-uncompress.h"
 
 const unsigned int Kiara_fps_vector[PWC_FPS_MAX_KIARA] = { 5, 10, 15, 20, 25, 30 };
 
index 6af5bb5..0b03133 100644 (file)
@@ -126,8 +126,4 @@ void pwc_construct(struct pwc_device *pdev)
        pdev->pixfmt = V4L2_PIX_FMT_YUV420; /* default */
        pdev->view_min.size = pdev->view_min.x * pdev->view_min.y;
        pdev->view_max.size = pdev->view_max.x * pdev->view_max.y;
-       /* length of image, in YUV format; always allocate enough memory. */
-       pdev->len_per_image = PAGE_ALIGN((pdev->abs_max.x * pdev->abs_max.y * 3) / 2);
 }
-
-
index 3b73f29..5126509 100644 (file)
 #include <asm/types.h>
 
 #include "pwc.h"
-#include "pwc-uncompress.h"
 #include "pwc-dec1.h"
 #include "pwc-dec23.h"
 
-int pwc_decompress(struct pwc_device *pdev)
+int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf)
 {
-       struct pwc_frame_buf *fbuf;
        int n, line, col, stride;
        void *yuv, *image;
        u16 *src;
        u16 *dsty, *dstu, *dstv;
 
-       if (pdev == NULL)
-               return -EFAULT;
-
-       fbuf = pdev->read_frame;
-       if (fbuf == NULL)
-               return -EFAULT;
-       image  = pdev->image_data;
-       image += pdev->images[pdev->fill_image].offset;
+       image = vb2_plane_vaddr(&fbuf->vb, 0);
 
        yuv = fbuf->data + pdev->frame_header_size;  /* Skip header */
 
@@ -64,9 +55,13 @@ int pwc_decompress(struct pwc_device *pdev)
                         * determine this using the type of the webcam */
                memcpy(raw_frame->cmd, pdev->cmd_buf, 4);
                memcpy(raw_frame+1, yuv, pdev->frame_size);
+               vb2_set_plane_payload(&fbuf->vb, 0,
+                       pdev->frame_size + sizeof(struct pwc_raw_frame));
                return 0;
        }
 
+       vb2_set_plane_payload(&fbuf->vb, 0, pdev->view.size);
+
        if (pdev->vbandlength == 0) {
                /* Uncompressed mode.
                 * We copy the data into the output buffer, using the viewport
diff --git a/drivers/media/video/pwc/pwc-uncompress.h b/drivers/media/video/pwc/pwc-uncompress.h
deleted file mode 100644 (file)
index 43028e7..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/* (C) 1999-2003 Nemosoft Unv.
-   (C) 2004-2006 Luc Saillard (luc@saillard.org)
-
-   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
-   driver and thus may have bugs that are not present in the original version.
-   Please send bug reports and support requests to <luc@saillard.org>.
-   The decompression routines have been implemented by reverse-engineering the
-   Nemosoft binary pwcx module. Caveat emptor.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-/* This file is the bridge between the kernel module and the plugin; it
-   describes the structures and datatypes used in both modules. Any
-   significant change should be reflected by increasing the
-   pwc_decompressor_version major number.
- */
-#ifndef PWC_UNCOMPRESS_H
-#define PWC_UNCOMPRESS_H
-
-
-#include <media/pwc-ioctl.h>
-
-/* from pwc-dec.h */
-#define PWCX_FLAG_PLANAR        0x0001
-/* */
-
-#endif
index f85c512..e9a0e94 100644 (file)
@@ -2,6 +2,7 @@
    USB and Video4Linux interface part.
    (C) 1999-2004 Nemosoft Unv.
    (C) 2004-2006 Luc Saillard (luc@saillard.org)
+   (C) 2011 Hans de Goede <hdegoede@redhat.com>
 
    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
    driver and thus may have bugs that are not present in the original version.
 #include <linux/module.h>
 #include <linux/poll.h>
 #include <linux/vmalloc.h>
+#include <linux/jiffies.h>
 #include <asm/io.h>
 
 #include "pwc.h"
 
-static struct v4l2_queryctrl pwc_controls[] = {
-       {
-           .id      = V4L2_CID_BRIGHTNESS,
-           .type    = V4L2_CTRL_TYPE_INTEGER,
-           .name    = "Brightness",
-           .minimum = 0,
-           .maximum = 128,
-           .step    = 1,
-           .default_value = 64,
-       },
-       {
-           .id      = V4L2_CID_CONTRAST,
-           .type    = V4L2_CTRL_TYPE_INTEGER,
-           .name    = "Contrast",
-           .minimum = 0,
-           .maximum = 64,
-           .step    = 1,
-           .default_value = 0,
-       },
-       {
-           .id      = V4L2_CID_SATURATION,
-           .type    = V4L2_CTRL_TYPE_INTEGER,
-           .name    = "Saturation",
-           .minimum = -100,
-           .maximum = 100,
-           .step    = 1,
-           .default_value = 0,
-       },
-       {
-           .id      = V4L2_CID_GAMMA,
-           .type    = V4L2_CTRL_TYPE_INTEGER,
-           .name    = "Gamma",
-           .minimum = 0,
-           .maximum = 32,
-           .step    = 1,
-           .default_value = 0,
-       },
-       {
-           .id      = V4L2_CID_RED_BALANCE,
-           .type    = V4L2_CTRL_TYPE_INTEGER,
-           .name    = "Red Gain",
-           .minimum = 0,
-           .maximum = 256,
-           .step    = 1,
-           .default_value = 0,
-       },
-       {
-           .id      = V4L2_CID_BLUE_BALANCE,
-           .type    = V4L2_CTRL_TYPE_INTEGER,
-           .name    = "Blue Gain",
-           .minimum = 0,
-           .maximum = 256,
-           .step    = 1,
-           .default_value = 0,
-       },
-       {
-           .id      = V4L2_CID_AUTO_WHITE_BALANCE,
-           .type    = V4L2_CTRL_TYPE_BOOLEAN,
-           .name    = "Auto White Balance",
-           .minimum = 0,
-           .maximum = 1,
-           .step    = 1,
-           .default_value = 0,
-       },
-       {
-           .id      = V4L2_CID_EXPOSURE,
-           .type    = V4L2_CTRL_TYPE_INTEGER,
-           .name    = "Shutter Speed (Exposure)",
-           .minimum = 0,
-           .maximum = 256,
-           .step    = 1,
-           .default_value = 200,
-       },
-       {
-           .id      = V4L2_CID_AUTOGAIN,
-           .type    = V4L2_CTRL_TYPE_BOOLEAN,
-           .name    = "Auto Gain Enabled",
-           .minimum = 0,
-           .maximum = 1,
-           .step    = 1,
-           .default_value = 1,
-       },
-       {
-           .id      = V4L2_CID_GAIN,
-           .type    = V4L2_CTRL_TYPE_INTEGER,
-           .name    = "Gain Level",
-           .minimum = 0,
-           .maximum = 256,
-           .step    = 1,
-           .default_value = 0,
-       },
-       {
-           .id      = V4L2_CID_PRIVATE_SAVE_USER,
-           .type    = V4L2_CTRL_TYPE_BUTTON,
-           .name    = "Save User Settings",
-           .minimum = 0,
-           .maximum = 0,
-           .step    = 0,
-           .default_value = 0,
-       },
-       {
-           .id      = V4L2_CID_PRIVATE_RESTORE_USER,
-           .type    = V4L2_CTRL_TYPE_BUTTON,
-           .name    = "Restore User Settings",
-           .minimum = 0,
-           .maximum = 0,
-           .step    = 0,
-           .default_value = 0,
-       },
-       {
-           .id      = V4L2_CID_PRIVATE_RESTORE_FACTORY,
-           .type    = V4L2_CTRL_TYPE_BUTTON,
-           .name    = "Restore Factory Settings",
-           .minimum = 0,
-           .maximum = 0,
-           .step    = 0,
-           .default_value = 0,
-       },
-       {
-           .id      = V4L2_CID_PRIVATE_COLOUR_MODE,
-           .type    = V4L2_CTRL_TYPE_BOOLEAN,
-           .name    = "Colour mode",
-           .minimum = 0,
-           .maximum = 1,
-           .step    = 1,
-           .default_value = 0,
-       },
-       {
-           .id      = V4L2_CID_PRIVATE_AUTOCONTOUR,
-           .type    = V4L2_CTRL_TYPE_BOOLEAN,
-           .name    = "Auto contour",
-           .minimum = 0,
-           .maximum = 1,
-           .step    = 1,
-           .default_value = 0,
-       },
-       {
-           .id      = V4L2_CID_PRIVATE_CONTOUR,
-           .type    = V4L2_CTRL_TYPE_INTEGER,
-           .name    = "Contour",
-           .minimum = 0,
-           .maximum = 63,
-           .step    = 1,
-           .default_value = 0,
-       },
-       {
-           .id      = V4L2_CID_PRIVATE_BACKLIGHT,
-           .type    = V4L2_CTRL_TYPE_BOOLEAN,
-           .name    = "Backlight compensation",
-           .minimum = 0,
-           .maximum = 1,
-           .step    = 1,
-           .default_value = 0,
-       },
-       {
-         .id      = V4L2_CID_PRIVATE_FLICKERLESS,
-           .type    = V4L2_CTRL_TYPE_BOOLEAN,
-           .name    = "Flickerless",
-           .minimum = 0,
-           .maximum = 1,
-           .step    = 1,
-           .default_value = 0,
-       },
-       {
-           .id      = V4L2_CID_PRIVATE_NOISE_REDUCTION,
-           .type    = V4L2_CTRL_TYPE_INTEGER,
-           .name    = "Noise reduction",
-           .minimum = 0,
-           .maximum = 3,
-           .step    = 1,
-           .default_value = 0,
-       },
+#define PWC_CID_CUSTOM(ctrl) ((V4L2_CID_USER_BASE | 0xf000) + custom_ ## ctrl)
+
+static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl);
+static int pwc_s_ctrl(struct v4l2_ctrl *ctrl);
+
+static const struct v4l2_ctrl_ops pwc_ctrl_ops = {
+       .g_volatile_ctrl = pwc_g_volatile_ctrl,
+       .s_ctrl = pwc_s_ctrl,
+};
+
+enum { awb_indoor, awb_outdoor, awb_fl, awb_manual, awb_auto };
+enum { custom_autocontour, custom_contour, custom_noise_reduction,
+       custom_save_user, custom_restore_user, custom_restore_factory };
+
+const char * const pwc_auto_whitebal_qmenu[] = {
+       "Indoor (Incandescant Lighting) Mode",
+       "Outdoor (Sunlight) Mode",
+       "Indoor (Fluorescent Lighting) Mode",
+       "Manual Mode",
+       "Auto Mode",
+       NULL
+};
+
+static const struct v4l2_ctrl_config pwc_auto_white_balance_cfg = {
+       .ops    = &pwc_ctrl_ops,
+       .id     = V4L2_CID_AUTO_WHITE_BALANCE,
+       .type   = V4L2_CTRL_TYPE_MENU,
+       .max    = awb_auto,
+       .qmenu  = pwc_auto_whitebal_qmenu,
+};
+
+static const struct v4l2_ctrl_config pwc_autocontour_cfg = {
+       .ops    = &pwc_ctrl_ops,
+       .id     = PWC_CID_CUSTOM(autocontour),
+       .type   = V4L2_CTRL_TYPE_BOOLEAN,
+       .name   = "Auto contour",
+       .min    = 0,
+       .max    = 1,
+       .step   = 1,
+};
+
+static const struct v4l2_ctrl_config pwc_contour_cfg = {
+       .ops    = &pwc_ctrl_ops,
+       .id     = PWC_CID_CUSTOM(contour),
+       .type   = V4L2_CTRL_TYPE_INTEGER,
+       .name   = "Contour",
+       .min    = 0,
+       .max    = 63,
+       .step   = 1,
+};
+
+static const struct v4l2_ctrl_config pwc_backlight_cfg = {
+       .ops    = &pwc_ctrl_ops,
+       .id     = V4L2_CID_BACKLIGHT_COMPENSATION,
+       .type   = V4L2_CTRL_TYPE_BOOLEAN,
+       .min    = 0,
+       .max    = 1,
+       .step   = 1,
+};
+
+static const struct v4l2_ctrl_config pwc_flicker_cfg = {
+       .ops    = &pwc_ctrl_ops,
+       .id     = V4L2_CID_BAND_STOP_FILTER,
+       .type   = V4L2_CTRL_TYPE_BOOLEAN,
+       .min    = 0,
+       .max    = 1,
+       .step   = 1,
+};
+
+static const struct v4l2_ctrl_config pwc_noise_reduction_cfg = {
+       .ops    = &pwc_ctrl_ops,
+       .id     = PWC_CID_CUSTOM(noise_reduction),
+       .type   = V4L2_CTRL_TYPE_INTEGER,
+       .name   = "Dynamic Noise Reduction",
+       .min    = 0,
+       .max    = 3,
+       .step   = 1,
+};
+
+static const struct v4l2_ctrl_config pwc_save_user_cfg = {
+       .ops    = &pwc_ctrl_ops,
+       .id     = PWC_CID_CUSTOM(save_user),
+       .type   = V4L2_CTRL_TYPE_BUTTON,
+       .name    = "Save User Settings",
 };
 
+static const struct v4l2_ctrl_config pwc_restore_user_cfg = {
+       .ops    = &pwc_ctrl_ops,
+       .id     = PWC_CID_CUSTOM(restore_user),
+       .type   = V4L2_CTRL_TYPE_BUTTON,
+       .name    = "Restore User Settings",
+};
+
+static const struct v4l2_ctrl_config pwc_restore_factory_cfg = {
+       .ops    = &pwc_ctrl_ops,
+       .id     = PWC_CID_CUSTOM(restore_factory),
+       .type   = V4L2_CTRL_TYPE_BUTTON,
+       .name    = "Restore Factory Settings",
+};
+
+int pwc_init_controls(struct pwc_device *pdev)
+{
+       struct v4l2_ctrl_handler *hdl;
+       struct v4l2_ctrl_config cfg;
+       int r, def;
+
+       hdl = &pdev->ctrl_handler;
+       r = v4l2_ctrl_handler_init(hdl, 20);
+       if (r)
+               return r;
+
+       /* Brightness, contrast, saturation, gamma */
+       r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, BRIGHTNESS_FORMATTER, &def);
+       if (r || def > 127)
+               def = 63;
+       pdev->brightness = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                               V4L2_CID_BRIGHTNESS, 0, 127, 1, def);
+
+       r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, CONTRAST_FORMATTER, &def);
+       if (r || def > 63)
+               def = 31;
+       pdev->contrast = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                               V4L2_CID_CONTRAST, 0, 63, 1, def);
+
+       if (pdev->type >= 675) {
+               if (pdev->type < 730)
+                       pdev->saturation_fmt = SATURATION_MODE_FORMATTER2;
+               else
+                       pdev->saturation_fmt = SATURATION_MODE_FORMATTER1;
+               r = pwc_get_s8_ctrl(pdev, GET_CHROM_CTL, pdev->saturation_fmt,
+                                   &def);
+               if (r || def < -100 || def > 100)
+                       def = 0;
+               pdev->saturation = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                                     V4L2_CID_SATURATION, -100, 100, 1, def);
+       }
+
+       r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, GAMMA_FORMATTER, &def);
+       if (r || def > 31)
+               def = 15;
+       pdev->gamma = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                               V4L2_CID_GAMMA, 0, 31, 1, def);
+
+       /* auto white balance, red gain, blue gain */
+       r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL, WB_MODE_FORMATTER, &def);
+       if (r || def > awb_auto)
+               def = awb_auto;
+       cfg = pwc_auto_white_balance_cfg;
+       cfg.name = v4l2_ctrl_get_name(cfg.id);
+       cfg.def = def;
+       pdev->auto_white_balance = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
+       /* check auto controls to avoid NULL deref in v4l2_ctrl_auto_cluster */
+       if (!pdev->auto_white_balance)
+               return hdl->error;
+
+       r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL,
+                           PRESET_MANUAL_RED_GAIN_FORMATTER, &def);
+       if (r)
+               def = 127;
+       pdev->red_balance = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                               V4L2_CID_RED_BALANCE, 0, 255, 1, def);
+
+       r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL,
+                           PRESET_MANUAL_BLUE_GAIN_FORMATTER, &def);
+       if (r)
+               def = 127;
+       pdev->blue_balance = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                               V4L2_CID_BLUE_BALANCE, 0, 255, 1, def);
+
+       v4l2_ctrl_auto_cluster(3, &pdev->auto_white_balance, awb_manual,
+                              pdev->auto_white_balance->cur.val == awb_auto);
+
+       /* autogain, gain */
+       r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, AGC_MODE_FORMATTER, &def);
+       if (r || (def != 0 && def != 0xff))
+               def = 0;
+       /* Note a register value if 0 means auto gain is on */
+       pdev->autogain = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                               V4L2_CID_AUTOGAIN, 0, 1, 1, def == 0);
+       if (!pdev->autogain)
+               return hdl->error;
+
+       r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, PRESET_AGC_FORMATTER, &def);
+       if (r || def > 63)
+               def = 31;
+       pdev->gain = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                               V4L2_CID_GAIN, 0, 63, 1, def);
+
+       /* auto exposure, exposure */
+       if (DEVICE_USE_CODEC2(pdev->type)) {
+               r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, SHUTTER_MODE_FORMATTER,
+                                   &def);
+               if (r || (def != 0 && def != 0xff))
+                       def = 0;
+               /*
+                * def = 0 auto, def = ff manual
+                * menu idx 0 = auto, idx 1 = manual
+                */
+               pdev->exposure_auto = v4l2_ctrl_new_std_menu(hdl,
+                                       &pwc_ctrl_ops,
+                                       V4L2_CID_EXPOSURE_AUTO,
+                                       1, 0, def != 0);
+               if (!pdev->exposure_auto)
+                       return hdl->error;
+
+               /* GET_LUM_CTL, PRESET_SHUTTER_FORMATTER is unreliable */
+               r = pwc_get_u16_ctrl(pdev, GET_STATUS_CTL,
+                                    READ_SHUTTER_FORMATTER, &def);
+               if (r || def > 655)
+                       def = 655;
+               pdev->exposure = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                                       V4L2_CID_EXPOSURE, 0, 655, 1, def);
+               /* CODEC2: separate auto gain & auto exposure */
+               v4l2_ctrl_auto_cluster(2, &pdev->autogain, 0, true);
+               v4l2_ctrl_auto_cluster(2, &pdev->exposure_auto,
+                                      V4L2_EXPOSURE_MANUAL, true);
+       } else if (DEVICE_USE_CODEC3(pdev->type)) {
+               /* GET_LUM_CTL, PRESET_SHUTTER_FORMATTER is unreliable */
+               r = pwc_get_u16_ctrl(pdev, GET_STATUS_CTL,
+                                    READ_SHUTTER_FORMATTER, &def);
+               if (r || def > 255)
+                       def = 255;
+               pdev->exposure = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                                       V4L2_CID_EXPOSURE, 0, 255, 1, def);
+               /* CODEC3: both gain and exposure controlled by autogain */
+               pdev->autogain_expo_cluster[0] = pdev->autogain;
+               pdev->autogain_expo_cluster[1] = pdev->gain;
+               pdev->autogain_expo_cluster[2] = pdev->exposure;
+               v4l2_ctrl_auto_cluster(3, pdev->autogain_expo_cluster,
+                                      0, true);
+       }
+
+       /* color / bw setting */
+       r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL, COLOUR_MODE_FORMATTER,
+                        &def);
+       if (r || (def != 0 && def != 0xff))
+               def = 0xff;
+       /* def = 0 bw, def = ff color, menu idx 0 = color, idx 1 = bw */
+       pdev->colorfx = v4l2_ctrl_new_std_menu(hdl, &pwc_ctrl_ops,
+                               V4L2_CID_COLORFX, 1, 0, def == 0);
+
+       /* autocontour, contour */
+       r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, AUTO_CONTOUR_FORMATTER, &def);
+       if (r || (def != 0 && def != 0xff))
+               def = 0;
+       cfg = pwc_autocontour_cfg;
+       cfg.def = def == 0;
+       pdev->autocontour = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
+       if (!pdev->autocontour)
+               return hdl->error;
+
+       r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, PRESET_CONTOUR_FORMATTER, &def);
+       if (r || def > 63)
+               def = 31;
+       cfg = pwc_contour_cfg;
+       cfg.def = def;
+       pdev->contour = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
+
+       v4l2_ctrl_auto_cluster(2, &pdev->autocontour, 0, false);
+
+       /* backlight */
+       r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL,
+                           BACK_LIGHT_COMPENSATION_FORMATTER, &def);
+       if (r || (def != 0 && def != 0xff))
+               def = 0;
+       cfg = pwc_backlight_cfg;
+       cfg.name = v4l2_ctrl_get_name(cfg.id);
+       cfg.def = def == 0;
+       pdev->backlight = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
+
+       /* flikker rediction */
+       r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL,
+                           FLICKERLESS_MODE_FORMATTER, &def);
+       if (r || (def != 0 && def != 0xff))
+               def = 0;
+       cfg = pwc_flicker_cfg;
+       cfg.name = v4l2_ctrl_get_name(cfg.id);
+       cfg.def = def == 0;
+       pdev->flicker = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
+
+       /* Dynamic noise reduction */
+       r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL,
+                           DYNAMIC_NOISE_CONTROL_FORMATTER, &def);
+       if (r || def > 3)
+               def = 2;
+       cfg = pwc_noise_reduction_cfg;
+       cfg.def = def;
+       pdev->noise_reduction = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
+
+       /* Save / Restore User / Factory Settings */
+       pdev->save_user = v4l2_ctrl_new_custom(hdl, &pwc_save_user_cfg, NULL);
+       pdev->restore_user = v4l2_ctrl_new_custom(hdl, &pwc_restore_user_cfg,
+                                                 NULL);
+       if (pdev->restore_user)
+               pdev->restore_user->flags = V4L2_CTRL_FLAG_UPDATE;
+       pdev->restore_factory = v4l2_ctrl_new_custom(hdl,
+                                                    &pwc_restore_factory_cfg,
+                                                    NULL);
+       if (pdev->restore_factory)
+               pdev->restore_factory->flags = V4L2_CTRL_FLAG_UPDATE;
+
+       if (!pdev->features & FEATURE_MOTOR_PANTILT)
+               return hdl->error;
+
+       /* Motor pan / tilt / reset */
+       pdev->motor_pan = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                               V4L2_CID_PAN_RELATIVE, -4480, 4480, 64, 0);
+       if (!pdev->motor_pan)
+               return hdl->error;
+       pdev->motor_tilt = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                               V4L2_CID_TILT_RELATIVE, -1920, 1920, 64, 0);
+       pdev->motor_pan_reset = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                               V4L2_CID_PAN_RESET, 0, 0, 0, 0);
+       pdev->motor_tilt_reset = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                               V4L2_CID_TILT_RESET, 0, 0, 0, 0);
+       v4l2_ctrl_cluster(4, &pdev->motor_pan);
+
+       return hdl->error;
+}
 
 static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f)
 {
@@ -284,10 +431,21 @@ static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
 }
 
 /* ioctl(VIDIOC_SET_FMT) */
-static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
+
+static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
 {
+       struct pwc_device *pdev = video_drvdata(file);
        int ret, fps, snapshot, compression, pixelformat;
 
+       if (!pdev->udev)
+               return -ENODEV;
+
+       if (pdev->capt_file != NULL &&
+           pdev->capt_file != file)
+               return -EBUSY;
+
+       pdev->capt_file = file;
+
        ret = pwc_vidioc_try_fmt(pdev, f);
        if (ret<0)
                return ret;
@@ -309,7 +467,7 @@ static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
            pixelformat != V4L2_PIX_FMT_PWC2)
                return -EINVAL;
 
-       if (pdev->iso_init)
+       if (vb2_is_streaming(&pdev->vb_queue))
                return -EBUSY;
 
        PWC_DEBUG_IOCTL("Trying to set format to: width=%d height=%d fps=%d "
@@ -343,13 +501,14 @@ static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
 
 static int pwc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
 {
-       struct video_device *vdev = video_devdata(file);
        struct pwc_device *pdev = video_drvdata(file);
 
+       if (!pdev->udev)
+               return -ENODEV;
+
        strcpy(cap->driver, PWC_NAME);
-       strlcpy(cap->card, vdev->name, sizeof(cap->card));
+       strlcpy(cap->card, pdev->vdev.name, sizeof(cap->card));
        usb_make_path(pdev->udev, cap->bus_info, sizeof(cap->bus_info));
-       cap->version = PWC_VERSION_CODE;
        cap->capabilities =
                V4L2_CAP_VIDEO_CAPTURE  |
                V4L2_CAP_STREAMING      |
@@ -377,255 +536,396 @@ static int pwc_s_input(struct file *file, void *fh, unsigned int i)
        return i ? -EINVAL : 0;
 }
 
-static int pwc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c)
+static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
 {
-       int i, idx;
-       u32 id;
-
-       id = c->id;
-       if (id & V4L2_CTRL_FLAG_NEXT_CTRL) {
-               id &= V4L2_CTRL_ID_MASK;
-               id++;
-               idx = -1;
-               for (i = 0; i < ARRAY_SIZE(pwc_controls); i++) {
-                       if (pwc_controls[i].id < id)
-                               continue;
-                       if (idx >= 0
-                        && pwc_controls[i].id > pwc_controls[idx].id)
-                               continue;
-                       idx = i;
+       struct pwc_device *pdev =
+               container_of(ctrl->handler, struct pwc_device, ctrl_handler);
+       int ret = 0;
+
+       /*
+        * Sometimes it can take quite long for the pwc to complete usb control
+        * transfers, so release the modlock to give streaming by another
+        * process / thread the chance to continue with a dqbuf.
+        */
+       mutex_unlock(&pdev->modlock);
+
+       /*
+        * Take the udev-lock to protect against the disconnect handler
+        * completing and setting dev->udev to NULL underneath us. Other code
+        * does not need to do this since it is protected by the modlock.
+        */
+       mutex_lock(&pdev->udevlock);
+
+       if (!pdev->udev) {
+               ret = -ENODEV;
+               goto leave;
+       }
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUTO_WHITE_BALANCE:
+               if (pdev->color_bal_valid && time_before(jiffies,
+                               pdev->last_color_bal_update + HZ / 4)) {
+                       pdev->red_balance->val  = pdev->last_red_balance;
+                       pdev->blue_balance->val = pdev->last_blue_balance;
+                       break;
                }
-               if (idx < 0)
-                       return -EINVAL;
-               memcpy(c, &pwc_controls[idx], sizeof pwc_controls[0]);
-               return 0;
+               ret = pwc_get_u8_ctrl(pdev, GET_STATUS_CTL,
+                                     READ_RED_GAIN_FORMATTER,
+                                     &pdev->red_balance->val);
+               if (ret)
+                       break;
+               ret = pwc_get_u8_ctrl(pdev, GET_STATUS_CTL,
+                                     READ_BLUE_GAIN_FORMATTER,
+                                     &pdev->blue_balance->val);
+               if (ret)
+                       break;
+               pdev->last_red_balance  = pdev->red_balance->val;
+               pdev->last_blue_balance = pdev->blue_balance->val;
+               pdev->last_color_bal_update = jiffies;
+               pdev->color_bal_valid = true;
+               break;
+       case V4L2_CID_AUTOGAIN:
+               if (pdev->gain_valid && time_before(jiffies,
+                               pdev->last_gain_update + HZ / 4)) {
+                       pdev->gain->val = pdev->last_gain;
+                       break;
+               }
+               ret = pwc_get_u8_ctrl(pdev, GET_STATUS_CTL,
+                                     READ_AGC_FORMATTER, &pdev->gain->val);
+               if (ret)
+                       break;
+               pdev->last_gain = pdev->gain->val;
+               pdev->last_gain_update = jiffies;
+               pdev->gain_valid = true;
+               if (!DEVICE_USE_CODEC3(pdev->type))
+                       break;
+               /* Fall through for CODEC3 where autogain also controls expo */
+       case V4L2_CID_EXPOSURE_AUTO:
+               if (pdev->exposure_valid && time_before(jiffies,
+                               pdev->last_exposure_update + HZ / 4)) {
+                       pdev->exposure->val = pdev->last_exposure;
+                       break;
+               }
+               ret = pwc_get_u16_ctrl(pdev, GET_STATUS_CTL,
+                                      READ_SHUTTER_FORMATTER,
+                                      &pdev->exposure->val);
+               if (ret)
+                       break;
+               pdev->last_exposure = pdev->exposure->val;
+               pdev->last_exposure_update = jiffies;
+               pdev->exposure_valid = true;
+               break;
+       default:
+               ret = -EINVAL;
        }
-       for (i = 0; i < sizeof(pwc_controls) / sizeof(struct v4l2_queryctrl); i++) {
-               if (pwc_controls[i].id == c->id) {
-                       PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n");
-                       memcpy(c, &pwc_controls[i], sizeof(struct v4l2_queryctrl));
-                       return 0;
+
+       if (ret)
+               PWC_ERROR("g_ctrl %s error %d\n", ctrl->name, ret);
+
+leave:
+       mutex_unlock(&pdev->udevlock);
+       mutex_lock(&pdev->modlock);
+       return ret;
+}
+
+static int pwc_set_awb(struct pwc_device *pdev)
+{
+       int ret = 0;
+
+       if (pdev->auto_white_balance->is_new) {
+               ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL,
+                                     WB_MODE_FORMATTER,
+                                     pdev->auto_white_balance->val);
+               if (ret)
+                       return ret;
+
+               /* Update val when coming from auto or going to a preset */
+               if (pdev->red_balance->is_volatile ||
+                   pdev->auto_white_balance->val == awb_indoor ||
+                   pdev->auto_white_balance->val == awb_outdoor ||
+                   pdev->auto_white_balance->val == awb_fl) {
+                       if (!pdev->red_balance->is_new)
+                               pwc_get_u8_ctrl(pdev, GET_STATUS_CTL,
+                                       READ_RED_GAIN_FORMATTER,
+                                       &pdev->red_balance->val);
+                       if (!pdev->blue_balance->is_new)
+                               pwc_get_u8_ctrl(pdev, GET_STATUS_CTL,
+                                       READ_BLUE_GAIN_FORMATTER,
+                                       &pdev->blue_balance->val);
+               }
+               if (pdev->auto_white_balance->val == awb_auto) {
+                       pdev->red_balance->is_volatile = true;
+                       pdev->blue_balance->is_volatile = true;
+                       pdev->color_bal_valid = false; /* Force cache update */
+               } else {
+                       pdev->red_balance->is_volatile = false;
+                       pdev->blue_balance->is_volatile = false;
                }
        }
-       return -EINVAL;
+
+       if (ret == 0 && pdev->red_balance->is_new) {
+               if (pdev->auto_white_balance->val != awb_manual)
+                       return -EBUSY;
+               ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL,
+                                     PRESET_MANUAL_RED_GAIN_FORMATTER,
+                                     pdev->red_balance->val);
+       }
+
+       if (ret == 0 && pdev->blue_balance->is_new) {
+               if (pdev->auto_white_balance->val != awb_manual)
+                       return -EBUSY;
+               ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL,
+                                     PRESET_MANUAL_BLUE_GAIN_FORMATTER,
+                                     pdev->blue_balance->val);
+       }
+       return ret;
 }
 
-static int pwc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c)
+/* For CODEC2 models which have separate autogain and auto exposure */
+static int pwc_set_autogain(struct pwc_device *pdev)
 {
-       struct pwc_device *pdev = video_drvdata(file);
-       int ret;
+       int ret = 0;
+
+       if (pdev->autogain->is_new) {
+               ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
+                                     AGC_MODE_FORMATTER,
+                                     pdev->autogain->val ? 0 : 0xff);
+               if (ret)
+                       return ret;
+               if (pdev->autogain->val)
+                       pdev->gain_valid = false; /* Force cache update */
+               else if (!pdev->gain->is_new)
+                       pwc_get_u8_ctrl(pdev, GET_STATUS_CTL,
+                                       READ_AGC_FORMATTER,
+                                       &pdev->gain->val);
+       }
+       if (ret == 0 && pdev->gain->is_new) {
+               if (pdev->autogain->val)
+                       return -EBUSY;
+               ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
+                                     PRESET_AGC_FORMATTER,
+                                     pdev->gain->val);
+       }
+       return ret;
+}
 
-       switch (c->id) {
-       case V4L2_CID_BRIGHTNESS:
-               c->value = pwc_get_brightness(pdev);
-               if (c->value < 0)
-                       return -EINVAL;
-               return 0;
-       case V4L2_CID_CONTRAST:
-               c->value = pwc_get_contrast(pdev);
-               if (c->value < 0)
-                       return -EINVAL;
-               return 0;
-       case V4L2_CID_SATURATION:
-               ret = pwc_get_saturation(pdev, &c->value);
-               if (ret < 0)
-                       return -EINVAL;
-               return 0;
-       case V4L2_CID_GAMMA:
-               c->value = pwc_get_gamma(pdev);
-               if (c->value < 0)
-                       return -EINVAL;
-               return 0;
-       case V4L2_CID_RED_BALANCE:
-               ret = pwc_get_red_gain(pdev, &c->value);
-               if (ret < 0)
-                       return -EINVAL;
-               c->value >>= 8;
-               return 0;
-       case V4L2_CID_BLUE_BALANCE:
-               ret = pwc_get_blue_gain(pdev, &c->value);
-               if (ret < 0)
-                       return -EINVAL;
-               c->value >>= 8;
-               return 0;
-       case V4L2_CID_AUTO_WHITE_BALANCE:
-               ret = pwc_get_awb(pdev);
-               if (ret < 0)
-                       return -EINVAL;
-               c->value = (ret == PWC_WB_MANUAL) ? 0 : 1;
-               return 0;
-       case V4L2_CID_GAIN:
-               ret = pwc_get_agc(pdev, &c->value);
-               if (ret < 0)
-                       return -EINVAL;
-               c->value >>= 8;
-               return 0;
-       case V4L2_CID_AUTOGAIN:
-               ret = pwc_get_agc(pdev, &c->value);
-               if (ret < 0)
-                       return -EINVAL;
-               c->value = (c->value < 0) ? 1 : 0;
-               return 0;
-       case V4L2_CID_EXPOSURE:
-               ret = pwc_get_shutter_speed(pdev, &c->value);
-               if (ret < 0)
-                       return -EINVAL;
-               return 0;
-       case V4L2_CID_PRIVATE_COLOUR_MODE:
-               ret = pwc_get_colour_mode(pdev, &c->value);
-               if (ret < 0)
-                       return -EINVAL;
-               return 0;
-       case V4L2_CID_PRIVATE_AUTOCONTOUR:
-               ret = pwc_get_contour(pdev, &c->value);
-               if (ret < 0)
-                       return -EINVAL;
-               c->value = (c->value == -1 ? 1 : 0);
-               return 0;
-       case V4L2_CID_PRIVATE_CONTOUR:
-               ret = pwc_get_contour(pdev, &c->value);
-               if (ret < 0)
-                       return -EINVAL;
-               c->value >>= 10;
-               return 0;
-       case V4L2_CID_PRIVATE_BACKLIGHT:
-               ret = pwc_get_backlight(pdev, &c->value);
-               if (ret < 0)
-                       return -EINVAL;
-               return 0;
-       case V4L2_CID_PRIVATE_FLICKERLESS:
-               ret = pwc_get_flicker(pdev, &c->value);
-               if (ret < 0)
-                       return -EINVAL;
-               c->value = (c->value ? 1 : 0);
-               return 0;
-       case V4L2_CID_PRIVATE_NOISE_REDUCTION:
-               ret = pwc_get_dynamic_noise(pdev, &c->value);
-               if (ret < 0)
-                       return -EINVAL;
-               return 0;
+/* For CODEC2 models which have separate autogain and auto exposure */
+static int pwc_set_exposure_auto(struct pwc_device *pdev)
+{
+       int ret = 0;
+       int is_auto = pdev->exposure_auto->val == V4L2_EXPOSURE_AUTO;
+
+       if (pdev->exposure_auto->is_new) {
+               ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
+                                     SHUTTER_MODE_FORMATTER,
+                                     is_auto ? 0 : 0xff);
+               if (ret)
+                       return ret;
+               if (is_auto)
+                       pdev->exposure_valid = false; /* Force cache update */
+               else if (!pdev->exposure->is_new)
+                       pwc_get_u16_ctrl(pdev, GET_STATUS_CTL,
+                                        READ_SHUTTER_FORMATTER,
+                                        &pdev->exposure->val);
+       }
+       if (ret == 0 && pdev->exposure->is_new) {
+               if (is_auto)
+                       return -EBUSY;
+               ret = pwc_set_u16_ctrl(pdev, SET_LUM_CTL,
+                                      PRESET_SHUTTER_FORMATTER,
+                                      pdev->exposure->val);
+       }
+       return ret;
+}
 
-       case V4L2_CID_PRIVATE_SAVE_USER:
-       case V4L2_CID_PRIVATE_RESTORE_USER:
-       case V4L2_CID_PRIVATE_RESTORE_FACTORY:
-               return -EINVAL;
+/* For CODEC3 models which have autogain controlling both gain and exposure */
+static int pwc_set_autogain_expo(struct pwc_device *pdev)
+{
+       int ret = 0;
+
+       if (pdev->autogain->is_new) {
+               ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
+                                     AGC_MODE_FORMATTER,
+                                     pdev->autogain->val ? 0 : 0xff);
+               if (ret)
+                       return ret;
+               if (pdev->autogain->val) {
+                       pdev->gain_valid     = false; /* Force cache update */
+                       pdev->exposure_valid = false; /* Force cache update */
+               } else {
+                       if (!pdev->gain->is_new)
+                               pwc_get_u8_ctrl(pdev, GET_STATUS_CTL,
+                                               READ_AGC_FORMATTER,
+                                               &pdev->gain->val);
+                       if (!pdev->exposure->is_new)
+                               pwc_get_u16_ctrl(pdev, GET_STATUS_CTL,
+                                                READ_SHUTTER_FORMATTER,
+                                                &pdev->exposure->val);
+               }
        }
-       return -EINVAL;
+       if (ret == 0 && pdev->gain->is_new) {
+               if (pdev->autogain->val)
+                       return -EBUSY;
+               ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
+                                     PRESET_AGC_FORMATTER,
+                                     pdev->gain->val);
+       }
+       if (ret == 0 && pdev->exposure->is_new) {
+               if (pdev->autogain->val)
+                       return -EBUSY;
+               ret = pwc_set_u16_ctrl(pdev, SET_LUM_CTL,
+                                      PRESET_SHUTTER_FORMATTER,
+                                      pdev->exposure->val);
+       }
+       return ret;
 }
 
-static int pwc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
+static int pwc_set_motor(struct pwc_device *pdev)
 {
-       struct pwc_device *pdev = video_drvdata(file);
        int ret;
+       u8 buf[4];
+
+       buf[0] = 0;
+       if (pdev->motor_pan_reset->is_new)
+               buf[0] |= 0x01;
+       if (pdev->motor_tilt_reset->is_new)
+               buf[0] |= 0x02;
+       if (pdev->motor_pan_reset->is_new || pdev->motor_tilt_reset->is_new) {
+               ret = send_control_msg(pdev, SET_MPT_CTL,
+                                      PT_RESET_CONTROL_FORMATTER, buf, 1);
+               if (ret < 0)
+                       return ret;
+       }
 
-       switch (c->id) {
-       case V4L2_CID_BRIGHTNESS:
-               c->value <<= 9;
-               ret = pwc_set_brightness(pdev, c->value);
+       memset(buf, 0, sizeof(buf));
+       if (pdev->motor_pan->is_new) {
+               buf[0] = pdev->motor_pan->val & 0xFF;
+               buf[1] = (pdev->motor_pan->val >> 8);
+       }
+       if (pdev->motor_tilt->is_new) {
+               buf[2] = pdev->motor_tilt->val & 0xFF;
+               buf[3] = (pdev->motor_tilt->val >> 8);
+       }
+       if (pdev->motor_pan->is_new || pdev->motor_tilt->is_new) {
+               ret = send_control_msg(pdev, SET_MPT_CTL,
+                                      PT_RELATIVE_CONTROL_FORMATTER,
+                                      buf, sizeof(buf));
                if (ret < 0)
-                       return -EINVAL;
-               return 0;
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int pwc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct pwc_device *pdev =
+               container_of(ctrl->handler, struct pwc_device, ctrl_handler);
+       int ret = 0;
+
+       /* See the comments on locking in pwc_g_volatile_ctrl */
+       mutex_unlock(&pdev->modlock);
+       mutex_lock(&pdev->udevlock);
+
+       if (!pdev->udev) {
+               ret = -ENODEV;
+               goto leave;
+       }
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
+                                     BRIGHTNESS_FORMATTER, ctrl->val);
+               break;
        case V4L2_CID_CONTRAST:
-               c->value <<= 10;
-               ret = pwc_set_contrast(pdev, c->value);
-               if (ret < 0)
-                       return -EINVAL;
-               return 0;
+               ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
+                                     CONTRAST_FORMATTER, ctrl->val);
+               break;
        case V4L2_CID_SATURATION:
-               ret = pwc_set_saturation(pdev, c->value);
-               if (ret < 0)
-                       return -EINVAL;
-               return 0;
+               ret = pwc_set_s8_ctrl(pdev, SET_CHROM_CTL,
+                                     pdev->saturation_fmt, ctrl->val);
+               break;
        case V4L2_CID_GAMMA:
-               c->value <<= 11;
-               ret = pwc_set_gamma(pdev, c->value);
-               if (ret < 0)
-                       return -EINVAL;
-               return 0;
-       case V4L2_CID_RED_BALANCE:
-               c->value <<= 8;
-               ret = pwc_set_red_gain(pdev, c->value);
-               if (ret < 0)
-                       return -EINVAL;
-               return 0;
-       case V4L2_CID_BLUE_BALANCE:
-               c->value <<= 8;
-               ret = pwc_set_blue_gain(pdev, c->value);
-               if (ret < 0)
-                       return -EINVAL;
-               return 0;
+               ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
+                                     GAMMA_FORMATTER, ctrl->val);
+               break;
        case V4L2_CID_AUTO_WHITE_BALANCE:
-               c->value = (c->value == 0) ? PWC_WB_MANUAL : PWC_WB_AUTO;
-               ret = pwc_set_awb(pdev, c->value);
-               if (ret < 0)
-                       return -EINVAL;
-               return 0;
-       case V4L2_CID_EXPOSURE:
-               c->value <<= 8;
-               ret = pwc_set_shutter_speed(pdev, c->value ? 0 : 1, c->value);
-               if (ret < 0)
-                       return -EINVAL;
-               return 0;
+               ret = pwc_set_awb(pdev);
+               break;
        case V4L2_CID_AUTOGAIN:
-               /* autogain off means nothing without a gain */
-               if (c->value == 0)
-                       return 0;
-               ret = pwc_set_agc(pdev, c->value, 0);
-               if (ret < 0)
-                       return -EINVAL;
-               return 0;
-       case V4L2_CID_GAIN:
-               c->value <<= 8;
-               ret = pwc_set_agc(pdev, 0, c->value);
-               if (ret < 0)
-                       return -EINVAL;
-               return 0;
-       case V4L2_CID_PRIVATE_SAVE_USER:
-               if (pwc_save_user(pdev))
-                       return -EINVAL;
-               return 0;
-       case V4L2_CID_PRIVATE_RESTORE_USER:
-               if (pwc_restore_user(pdev))
-                       return -EINVAL;
-               return 0;
-       case V4L2_CID_PRIVATE_RESTORE_FACTORY:
-               if (pwc_restore_factory(pdev))
-                       return -EINVAL;
-               return 0;
-       case V4L2_CID_PRIVATE_COLOUR_MODE:
-               ret = pwc_set_colour_mode(pdev, c->value);
-               if (ret < 0)
-                       return -EINVAL;
-               return 0;
-       case V4L2_CID_PRIVATE_AUTOCONTOUR:
-               c->value = (c->value == 1) ? -1 : 0;
-               ret = pwc_set_contour(pdev, c->value);
-               if (ret < 0)
-                       return -EINVAL;
-               return 0;
-       case V4L2_CID_PRIVATE_CONTOUR:
-               c->value <<= 10;
-               ret = pwc_set_contour(pdev, c->value);
-               if (ret < 0)
-                       return -EINVAL;
-               return 0;
-       case V4L2_CID_PRIVATE_BACKLIGHT:
-               ret = pwc_set_backlight(pdev, c->value);
-               if (ret < 0)
-                       return -EINVAL;
-               return 0;
-       case V4L2_CID_PRIVATE_FLICKERLESS:
-               ret = pwc_set_flicker(pdev, c->value);
-               if (ret < 0)
-                       return -EINVAL;
-       case V4L2_CID_PRIVATE_NOISE_REDUCTION:
-               ret = pwc_set_dynamic_noise(pdev, c->value);
-               if (ret < 0)
-                       return -EINVAL;
-               return 0;
-
+               if (DEVICE_USE_CODEC2(pdev->type))
+                       ret = pwc_set_autogain(pdev);
+               else if (DEVICE_USE_CODEC3(pdev->type))
+                       ret = pwc_set_autogain_expo(pdev);
+               else
+                       ret = -EINVAL;
+               break;
+       case V4L2_CID_EXPOSURE_AUTO:
+               if (DEVICE_USE_CODEC2(pdev->type))
+                       ret = pwc_set_exposure_auto(pdev);
+               else
+                       ret = -EINVAL;
+               break;
+       case V4L2_CID_COLORFX:
+               ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL,
+                                     COLOUR_MODE_FORMATTER,
+                                     ctrl->val ? 0 : 0xff);
+               break;
+       case PWC_CID_CUSTOM(autocontour):
+               if (pdev->autocontour->is_new) {
+                       ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
+                                       AUTO_CONTOUR_FORMATTER,
+                                       pdev->autocontour->val ? 0 : 0xff);
+               }
+               if (ret == 0 && pdev->contour->is_new) {
+                       if (pdev->autocontour->val) {
+                               ret = -EBUSY;
+                               break;
+                       }
+                       ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
+                                             PRESET_CONTOUR_FORMATTER,
+                                             pdev->contour->val);
+               }
+               break;
+       case V4L2_CID_BACKLIGHT_COMPENSATION:
+               ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
+                                     BACK_LIGHT_COMPENSATION_FORMATTER,
+                                     ctrl->val ? 0 : 0xff);
+               break;
+       case V4L2_CID_BAND_STOP_FILTER:
+               ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
+                                     FLICKERLESS_MODE_FORMATTER,
+                                     ctrl->val ? 0 : 0xff);
+               break;
+       case PWC_CID_CUSTOM(noise_reduction):
+               ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
+                                     DYNAMIC_NOISE_CONTROL_FORMATTER,
+                                     ctrl->val);
+               break;
+       case PWC_CID_CUSTOM(save_user):
+               ret = pwc_button_ctrl(pdev, SAVE_USER_DEFAULTS_FORMATTER);
+               break;
+       case PWC_CID_CUSTOM(restore_user):
+               ret = pwc_button_ctrl(pdev, RESTORE_USER_DEFAULTS_FORMATTER);
+               break;
+       case PWC_CID_CUSTOM(restore_factory):
+               ret = pwc_button_ctrl(pdev,
+                                     RESTORE_FACTORY_DEFAULTS_FORMATTER);
+               break;
+       case V4L2_CID_PAN_RELATIVE:
+               ret = pwc_set_motor(pdev);
+               break;
+       default:
+               ret = -EINVAL;
        }
-       return -EINVAL;
+
+       if (ret)
+               PWC_ERROR("s_ctrl %s error %d\n", ctrl->name, ret);
+
+leave:
+       mutex_unlock(&pdev->udevlock);
+       mutex_lock(&pdev->modlock);
+       return ret;
 }
 
 static int pwc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
@@ -667,157 +967,77 @@ static int pwc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *
        return pwc_vidioc_try_fmt(pdev, f);
 }
 
-static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
+static int pwc_reqbufs(struct file *file, void *fh,
+                      struct v4l2_requestbuffers *rb)
 {
        struct pwc_device *pdev = video_drvdata(file);
 
-       return pwc_vidioc_set_fmt(pdev, f);
-}
-
-static int pwc_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb)
-{
-       int nbuffers;
+       if (pdev->capt_file != NULL &&
+           pdev->capt_file != file)
+               return -EBUSY;
 
-       PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n", rb->count);
-       if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       if (rb->memory != V4L2_MEMORY_MMAP)
-               return -EINVAL;
+       pdev->capt_file = file;
 
-       nbuffers = rb->count;
-       if (nbuffers < 2)
-               nbuffers = 2;
-       else if (nbuffers > pwc_mbufs)
-               nbuffers = pwc_mbufs;
-       /* Force to use our # of buffers */
-       rb->count = pwc_mbufs;
-       return 0;
+       return vb2_reqbufs(&pdev->vb_queue, rb);
 }
 
 static int pwc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
 {
        struct pwc_device *pdev = video_drvdata(file);
-       int index;
 
-       PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n", buf->index);
-       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n");
-               return -EINVAL;
-       }
-       index = buf->index;
-       if (index < 0 || index >= pwc_mbufs) {
-               PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index);
-               return -EINVAL;
-       }
-
-       buf->m.offset = index * pdev->len_per_image;
-       if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
-               buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
-       else
-               buf->bytesused = pdev->view.size;
-       buf->field = V4L2_FIELD_NONE;
-       buf->memory = V4L2_MEMORY_MMAP;
-       /*buf->flags = V4L2_BUF_FLAG_MAPPED;*/
-       buf->length = pdev->len_per_image;
-
-       PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n", buf->index);
-       PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n", buf->m.offset);
-       PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n", buf->bytesused);
-
-       return 0;
+       return vb2_querybuf(&pdev->vb_queue, buf);
 }
 
 static int pwc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
 {
-       PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n", buf->index);
-       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       if (buf->memory != V4L2_MEMORY_MMAP)
-               return -EINVAL;
-       if (buf->index >= pwc_mbufs)
-               return -EINVAL;
+       struct pwc_device *pdev = video_drvdata(file);
 
-       buf->flags |= V4L2_BUF_FLAG_QUEUED;
-       buf->flags &= ~V4L2_BUF_FLAG_DONE;
+       if (!pdev->udev)
+               return -ENODEV;
 
-       return 0;
+       if (pdev->capt_file != file)
+               return -EBUSY;
+
+       return vb2_qbuf(&pdev->vb_queue, buf);
 }
 
 static int pwc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
 {
-       DECLARE_WAITQUEUE(wait, current);
        struct pwc_device *pdev = video_drvdata(file);
-       int ret;
 
-       PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n");
+       if (!pdev->udev)
+               return -ENODEV;
 
-       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       add_wait_queue(&pdev->frameq, &wait);
-       while (pdev->full_frames == NULL) {
-               if (pdev->error_status) {
-                       remove_wait_queue(&pdev->frameq, &wait);
-                       set_current_state(TASK_RUNNING);
-                       return -pdev->error_status;
-               }
-
-               if (signal_pending(current)) {
-                       remove_wait_queue(&pdev->frameq, &wait);
-                       set_current_state(TASK_RUNNING);
-                       return -ERESTARTSYS;
-               }
-               mutex_unlock(&pdev->modlock);
-               schedule();
-               set_current_state(TASK_INTERRUPTIBLE);
-               mutex_lock(&pdev->modlock);
-       }
-       remove_wait_queue(&pdev->frameq, &wait);
-       set_current_state(TASK_RUNNING);
-
-       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n");
-       /* Decompress data in pdev->images[pdev->fill_image] */
-       ret = pwc_handle_frame(pdev);
-       if (ret)
-               return -EFAULT;
-       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n");
-
-       buf->index = pdev->fill_image;
-       if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
-               buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
-       else
-               buf->bytesused = pdev->view.size;
-       buf->flags = V4L2_BUF_FLAG_MAPPED;
-       buf->field = V4L2_FIELD_NONE;
-       do_gettimeofday(&buf->timestamp);
-       buf->sequence = 0;
-       buf->memory = V4L2_MEMORY_MMAP;
-       buf->m.offset = pdev->fill_image * pdev->len_per_image;
-       buf->length = pdev->len_per_image;
-       pwc_next_image(pdev);
-
-       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n", buf->index);
-       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n", buf->length);
-       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n", buf->m.offset);
-       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n", buf->bytesused);
-       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n");
-       return 0;
+       if (pdev->capt_file != file)
+               return -EBUSY;
 
+       return vb2_dqbuf(&pdev->vb_queue, buf, file->f_flags & O_NONBLOCK);
 }
 
 static int pwc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
 {
        struct pwc_device *pdev = video_drvdata(file);
 
-       return pwc_isoc_init(pdev);
+       if (!pdev->udev)
+               return -ENODEV;
+
+       if (pdev->capt_file != file)
+               return -EBUSY;
+
+       return vb2_streamon(&pdev->vb_queue, i);
 }
 
 static int pwc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
 {
        struct pwc_device *pdev = video_drvdata(file);
 
-       pwc_isoc_cleanup(pdev);
-       return 0;
+       if (!pdev->udev)
+               return -ENODEV;
+
+       if (pdev->capt_file != file)
+               return -EBUSY;
+
+       return vb2_streamoff(&pdev->vb_queue, i);
 }
 
 static int pwc_enum_framesizes(struct file *file, void *fh,
@@ -896,9 +1116,6 @@ const struct v4l2_ioctl_ops pwc_ioctl_ops = {
        .vidioc_g_fmt_vid_cap               = pwc_g_fmt_vid_cap,
        .vidioc_s_fmt_vid_cap               = pwc_s_fmt_vid_cap,
        .vidioc_try_fmt_vid_cap             = pwc_try_fmt_vid_cap,
-       .vidioc_queryctrl                   = pwc_queryctrl,
-       .vidioc_g_ctrl                      = pwc_g_ctrl,
-       .vidioc_s_ctrl                      = pwc_s_ctrl,
        .vidioc_reqbufs                     = pwc_reqbufs,
        .vidioc_querybuf                    = pwc_querybuf,
        .vidioc_qbuf                        = pwc_qbuf,
index 083f8b1..0e4e2d7 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/usb.h>
 #include <linux/spinlock.h>
 #include <linux/wait.h>
-#include <linux/version.h>
 #include <linux/mutex.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/videobuf2-vmalloc.h>
 #ifdef CONFIG_USB_PWC_INPUT_EVDEV
 #include <linux/input.h>
 #endif
 
-#include "pwc-uncompress.h"
 #include <media/pwc-ioctl.h>
 
 /* Version block */
-#define PWC_MAJOR      10
-#define PWC_MINOR      0
-#define PWC_EXTRAMINOR 12
-#define PWC_VERSION_CODE KERNEL_VERSION(PWC_MAJOR,PWC_MINOR,PWC_EXTRAMINOR)
-#define PWC_VERSION    "10.0.14"
+#define PWC_VERSION    "10.0.15"
 #define PWC_NAME       "pwc"
 #define PFX            PWC_NAME ": "
 
@@ -81,9 +77,9 @@
 #define PWC_DEBUG_LEVEL        (PWC_DEBUG_LEVEL_MODULE)
 
 #define PWC_DEBUG(level, fmt, args...) do {\
-         if ((PWC_DEBUG_LEVEL_ ##level) & pwc_trace) \
-            printk(KERN_DEBUG PFX fmt, ##args); \
-         } while(0)
+       if ((PWC_DEBUG_LEVEL_ ##level) & pwc_trace) \
+               printk(KERN_DEBUG PFX fmt, ##args); \
+       } while (0)
 
 #define PWC_ERROR(fmt, args...) printk(KERN_ERR PFX fmt, ##args)
 #define PWC_WARNING(fmt, args...) printk(KERN_WARNING PFX fmt, ##args)
 #define FEATURE_CODEC1                 0x0002
 #define FEATURE_CODEC2                 0x0004
 
-/* Turn certain features on/off */
-#define PWC_INT_PIPE 0
-
 /* Ignore errors in the first N frames, to allow for startup delays */
 #define FRAME_LOWMARK 5
 
 /* Size and number of buffers for the ISO pipe. */
-#define MAX_ISO_BUFS           2
+#define MAX_ISO_BUFS           3
 #define ISO_FRAMES_PER_DESC    10
 #define ISO_MAX_FRAME_SIZE     960
 #define ISO_BUFFER_SIZE        (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE)
 
-/* Frame buffers: contains compressed or uncompressed video data. */
-#define MAX_FRAMES             5
 /* Maximum size after decompression is 640x480 YUV data, 1.5 * 640 * 480 */
 #define PWC_FRAME_SIZE                 (460800 + TOUCAM_HEADER_SIZE + TOUCAM_TRAILER_SIZE)
 
-/* Absolute maximum number of buffers available for mmap() */
-#define MAX_IMAGES             10
+/* Absolute minimum and maximum number of buffers available for mmap() */
+#define MIN_FRAMES             2
+#define MAX_FRAMES             16
 
 /* Some macros to quickly find the type of a webcam */
 #define DEVICE_USE_CODEC1(x) ((x)<675)
 #define DEVICE_USE_CODEC3(x) ((x)>=700)
 #define DEVICE_USE_CODEC23(x) ((x)>=675)
 
-/* The following structures were based on cpia.h. Why reinvent the wheel? :-) */
-struct pwc_iso_buf
-{
-       void *data;
-       int  length;
-       int  read;
-       struct urb *urb;
-};
+/* from pwc-dec.h */
+#define PWCX_FLAG_PLANAR        0x0001
+
+/* Request types: video */
+#define SET_LUM_CTL                    0x01
+#define GET_LUM_CTL                    0x02
+#define SET_CHROM_CTL                  0x03
+#define GET_CHROM_CTL                  0x04
+#define SET_STATUS_CTL                 0x05
+#define GET_STATUS_CTL                 0x06
+#define SET_EP_STREAM_CTL              0x07
+#define GET_EP_STREAM_CTL              0x08
+#define GET_XX_CTL                     0x09
+#define SET_XX_CTL                     0x0A
+#define GET_XY_CTL                     0x0B
+#define SET_XY_CTL                     0x0C
+#define SET_MPT_CTL                    0x0D
+#define GET_MPT_CTL                    0x0E
+
+/* Selectors for the Luminance controls [GS]ET_LUM_CTL */
+#define AGC_MODE_FORMATTER                     0x2000
+#define PRESET_AGC_FORMATTER                   0x2100
+#define SHUTTER_MODE_FORMATTER                 0x2200
+#define PRESET_SHUTTER_FORMATTER               0x2300
+#define PRESET_CONTOUR_FORMATTER               0x2400
+#define AUTO_CONTOUR_FORMATTER                 0x2500
+#define BACK_LIGHT_COMPENSATION_FORMATTER      0x2600
+#define CONTRAST_FORMATTER                     0x2700
+#define DYNAMIC_NOISE_CONTROL_FORMATTER                0x2800
+#define FLICKERLESS_MODE_FORMATTER             0x2900
+#define AE_CONTROL_SPEED                       0x2A00
+#define BRIGHTNESS_FORMATTER                   0x2B00
+#define GAMMA_FORMATTER                                0x2C00
+
+/* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */
+#define WB_MODE_FORMATTER                      0x1000
+#define AWB_CONTROL_SPEED_FORMATTER            0x1100
+#define AWB_CONTROL_DELAY_FORMATTER            0x1200
+#define PRESET_MANUAL_RED_GAIN_FORMATTER       0x1300
+#define PRESET_MANUAL_BLUE_GAIN_FORMATTER      0x1400
+#define COLOUR_MODE_FORMATTER                  0x1500
+#define SATURATION_MODE_FORMATTER1             0x1600
+#define SATURATION_MODE_FORMATTER2             0x1700
+
+/* Selectors for the Status controls [GS]ET_STATUS_CTL */
+#define SAVE_USER_DEFAULTS_FORMATTER           0x0200
+#define RESTORE_USER_DEFAULTS_FORMATTER                0x0300
+#define RESTORE_FACTORY_DEFAULTS_FORMATTER     0x0400
+#define READ_AGC_FORMATTER                     0x0500
+#define READ_SHUTTER_FORMATTER                 0x0600
+#define READ_RED_GAIN_FORMATTER                        0x0700
+#define READ_BLUE_GAIN_FORMATTER               0x0800
+
+/* Formatters for the motorized pan & tilt [GS]ET_MPT_CTL */
+#define PT_RELATIVE_CONTROL_FORMATTER          0x01
+#define PT_RESET_CONTROL_FORMATTER             0x02
+#define PT_STATUS_FORMATTER                    0x03
 
 /* intermediate buffers with raw data from the USB cam */
 struct pwc_frame_buf
 {
-   void *data;
-   volatile int filled;                /* number of bytes filled */
-   struct pwc_frame_buf *next; /* list */
-};
-
-/* additionnal informations used when dealing image between kernel and userland */
-struct pwc_imgbuf
-{
-       unsigned long offset;   /* offset of this buffer in the big array of image_data */
-       int   vma_use_count;    /* count the number of time this memory is mapped */
+       struct vb2_buffer vb;   /* common v4l buffer stuff -- must be first */
+       struct list_head list;
+       void *data;
+       int filled;             /* number of bytes filled */
 };
 
 struct pwc_device
 {
        struct video_device vdev;
-
-   /* Pointer to our usb_device, may be NULL after unplug */
-   struct usb_device *udev;
-
-   int type;                    /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */
-   int release;                        /* release number */
-   int features;               /* feature bits */
-   char serial[30];            /* serial number (string) */
-   int error_status;           /* set when something goes wrong with the cam (unplugged, USB errors) */
-   int usb_init;               /* set when the cam has been initialized over USB */
-
-   /*** Video data ***/
-   int vopen;                  /* flag */
-   int vendpoint;              /* video isoc endpoint */
-   int vcinterface;            /* video control interface */
-   int valternate;             /* alternate interface needed */
-   int vframes, vsize;         /* frames-per-second & size (see PSZ_*) */
-   int pixfmt;                 /* pixelformat: V4L2_PIX_FMT_YUV420 or raw: _PWC1, _PWC2 */
-   int vframe_count;           /* received frames */
-   int vframes_dumped;                 /* counter for dumped frames */
-   int vframes_error;          /* frames received in error */
-   int vmax_packet_size;       /* USB maxpacket size */
-   int vlast_packet_size;      /* for frame synchronisation */
-   int visoc_errors;           /* number of contiguous ISOC errors */
-   int vcompression;           /* desired compression factor */
-   int vbandlength;            /* compressed band length; 0 is uncompressed */
-   char vsnapshot;             /* snapshot mode */
-   char vsync;                 /* used by isoc handler */
-   char vmirror;               /* for ToUCaM series */
-       char unplugged;
-
-   int cmd_len;
-   unsigned char cmd_buf[13];
-
-   /* The image acquisition requires 3 to 4 steps:
-      1. data is gathered in short packets from the USB controller
-      2. data is synchronized and packed into a frame buffer
-      3a. in case data is compressed, decompress it directly into image buffer
-      3b. in case data is uncompressed, copy into image buffer with viewport
-      4. data is transferred to the user process
-
-      Note that MAX_ISO_BUFS != MAX_FRAMES != MAX_IMAGES....
-      We have in effect a back-to-back-double-buffer system.
-    */
-   /* 1: isoc */
-   struct pwc_iso_buf sbuf[MAX_ISO_BUFS];
-   char iso_init;
-
-   /* 2: frame */
-   struct pwc_frame_buf *fbuf; /* all frames */
-   struct pwc_frame_buf *empty_frames, *empty_frames_tail;     /* all empty frames */
-   struct pwc_frame_buf *full_frames, *full_frames_tail;       /* all filled frames */
-   struct pwc_frame_buf *fill_frame;   /* frame currently being filled */
-   struct pwc_frame_buf *read_frame;   /* frame currently read by user process */
-   int frame_header_size, frame_trailer_size;
-   int frame_size;
-   int frame_total_size; /* including header & trailer */
-   int drop_frames;
-
-   /* 3: decompression */
-   void *decompress_data;              /* private data for decompression engine */
-
-   /* 4: image */
-   /* We have an 'image' and a 'view', where 'image' is the fixed-size image
-      as delivered by the camera, and 'view' is the size requested by the
-      program. The camera image is centered in this viewport, laced with
-      a gray or black border. view_min <= image <= view <= view_max;
-    */
-   int image_mask;                     /* bitmask of supported sizes */
-   struct pwc_coord view_min, view_max;        /* minimum and maximum viewable sizes */
-   struct pwc_coord abs_max;            /* maximum supported size with compression */
-   struct pwc_coord image, view;       /* image and viewport size */
-   struct pwc_coord offset;            /* offset within the viewport */
-
-   void *image_data;                   /* total buffer, which is subdivided into ... */
-   struct pwc_imgbuf images[MAX_IMAGES];/* ...several images... */
-   int fill_image;                     /* ...which are rotated. */
-   int len_per_image;                  /* length per image */
-   int image_read_pos;                 /* In case we read data in pieces, keep track of were we are in the imagebuffer */
-   int image_used[MAX_IMAGES];         /* For MCAPTURE and SYNC */
-
-   struct mutex modlock;               /* to prevent races in video_open(), etc */
-   spinlock_t ptrlock;                 /* for manipulating the buffer pointers */
-
-   /*** motorized pan/tilt feature */
-   struct pwc_mpt_range angle_range;
-   int pan_angle;                      /* in degrees * 100 */
-   int tilt_angle;                     /* absolute angle; 0,0 is home position */
-   int snapshot_button_status;         /* set to 1 when the user push the button, reset to 0 when this value is read */
+       struct mutex modlock;
+
+       /* Pointer to our usb_device, may be NULL after unplug */
+       struct usb_device *udev;
+       /* Protects the setting of udev to NULL by our disconnect handler */
+       struct mutex udevlock;
+
+       /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */
+       int type;
+       int release;            /* release number */
+       int features;           /* feature bits */
+       char serial[30];        /* serial number (string) */
+
+       /*** Video data ***/
+       struct file *capt_file; /* file doing video capture */
+       int vendpoint;          /* video isoc endpoint */
+       int vcinterface;        /* video control interface */
+       int valternate;         /* alternate interface needed */
+       int vframes, vsize;     /* frames-per-second & size (see PSZ_*) */
+       int pixfmt;             /* pixelformat: V4L2_PIX_FMT_YUV420 or _PWCX */
+       int vframe_count;       /* received frames */
+       int vmax_packet_size;   /* USB maxpacket size */
+       int vlast_packet_size;  /* for frame synchronisation */
+       int visoc_errors;       /* number of contiguous ISOC errors */
+       int vcompression;       /* desired compression factor */
+       int vbandlength;        /* compressed band length; 0 is uncompressed */
+       char vsnapshot;         /* snapshot mode */
+       char vsync;             /* used by isoc handler */
+       char vmirror;           /* for ToUCaM series */
+       char power_save;        /* Do powersaving for this cam */
+
+       int cmd_len;
+       unsigned char cmd_buf[13];
+
+       struct urb *urbs[MAX_ISO_BUFS];
+       char iso_init;
+
+       /* videobuf2 queue and queued buffers list */
+       struct vb2_queue vb_queue;
+       struct list_head queued_bufs;
+       spinlock_t queued_bufs_lock;
+
+       /*
+        * Frame currently being filled, this only gets touched by the
+        * isoc urb complete handler, and by stream start / stop since
+        * start / stop touch it before / after starting / killing the urbs
+        * no locking is needed around this
+        */
+       struct pwc_frame_buf *fill_buf;
+
+       int frame_header_size, frame_trailer_size;
+       int frame_size;
+       int frame_total_size;   /* including header & trailer */
+       int drop_frames;
+
+       void *decompress_data;  /* private data for decompression engine */
+
+       /*
+        * We have an 'image' and a 'view', where 'image' is the fixed-size img
+        * as delivered by the camera, and 'view' is the size requested by the
+        * program. The camera image is centered in this viewport, laced with
+        * a gray or black border. view_min <= image <= view <= view_max;
+        */
+       int image_mask;                         /* supported sizes */
+       struct pwc_coord view_min, view_max;    /* minimum and maximum view */
+       struct pwc_coord abs_max;               /* maximum supported size */
+       struct pwc_coord image, view;           /* image and viewport size */
+       struct pwc_coord offset;                /* offset of the viewport */
+
+       /*** motorized pan/tilt feature */
+       struct pwc_mpt_range angle_range;
+       int pan_angle;                  /* in degrees * 100 */
+       int tilt_angle;                 /* absolute angle; 0,0 is home */
+
+       /*
+        * Set to 1 when the user push the button, reset to 0
+        * when this value is read from sysfs.
+        */
+       int snapshot_button_status;
 #ifdef CONFIG_USB_PWC_INPUT_EVDEV
-   struct input_dev *button_dev;       /* webcam snapshot button input */
-   char button_phys[64];
+       struct input_dev *button_dev;   /* webcam snapshot button input */
+       char button_phys[64];
 #endif
 
-   /*** Misc. data ***/
-   wait_queue_head_t frameq;           /* When waiting for a frame to finish... */
-#if PWC_INT_PIPE
-   void *usb_int_handler;              /* for the interrupt endpoint */
-#endif
+       /* controls */
+       struct v4l2_ctrl_handler        ctrl_handler;
+       u16                             saturation_fmt;
+       struct v4l2_ctrl                *brightness;
+       struct v4l2_ctrl                *contrast;
+       struct v4l2_ctrl                *saturation;
+       struct v4l2_ctrl                *gamma;
+       struct {
+               /* awb / red-blue balance cluster */
+               struct v4l2_ctrl        *auto_white_balance;
+               struct v4l2_ctrl        *red_balance;
+               struct v4l2_ctrl        *blue_balance;
+               /* usb ctrl transfers are slow, so we cache things */
+               int                     color_bal_valid;
+               unsigned long           last_color_bal_update; /* In jiffies */
+               s32                     last_red_balance;
+               s32                     last_blue_balance;
+       };
+       struct {
+               /* autogain / gain cluster */
+               struct v4l2_ctrl        *autogain;
+               struct v4l2_ctrl        *gain;
+               int                     gain_valid;
+               unsigned long           last_gain_update; /* In jiffies */
+               s32                     last_gain;
+       };
+       struct {
+               /* exposure_auto / exposure cluster */
+               struct v4l2_ctrl        *exposure_auto;
+               struct v4l2_ctrl        *exposure;
+               int                     exposure_valid;
+               unsigned long           last_exposure_update; /* In jiffies */
+               s32                     last_exposure;
+       };
+       struct v4l2_ctrl                *colorfx;
+       struct {
+               /* autocontour/contour cluster */
+               struct v4l2_ctrl        *autocontour;
+               struct v4l2_ctrl        *contour;
+       };
+       struct v4l2_ctrl                *backlight;
+       struct v4l2_ctrl                *flicker;
+       struct v4l2_ctrl                *noise_reduction;
+       struct v4l2_ctrl                *save_user;
+       struct v4l2_ctrl                *restore_user;
+       struct v4l2_ctrl                *restore_factory;
+       struct {
+               /* motor control cluster */
+               struct v4l2_ctrl        *motor_pan;
+               struct v4l2_ctrl        *motor_tilt;
+               struct v4l2_ctrl        *motor_pan_reset;
+               struct v4l2_ctrl        *motor_tilt_reset;
+       };
+       /* CODEC3 models have both gain and exposure controlled by autogain */
+       struct v4l2_ctrl                *autogain_expo_cluster[3];
 };
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Global variables */
 #ifdef CONFIG_USB_PWC_DEBUG
 extern int pwc_trace;
 #endif
-extern int pwc_mbufs;
-
-/** functions in pwc-if.c */
-int pwc_handle_frame(struct pwc_device *pdev);
-void pwc_next_image(struct pwc_device *pdev);
-int pwc_isoc_init(struct pwc_device *pdev);
-void pwc_isoc_cleanup(struct pwc_device *pdev);
 
 /** Functions in pwc-misc.c */
 /* sizes in pixels */
@@ -291,50 +355,25 @@ void pwc_construct(struct pwc_device *pdev);
 /* Request a certain video mode. Returns < 0 if not possible */
 extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot);
 extern unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size);
-/* Calculate the number of bytes per image (not frame) */
 extern int pwc_mpt_reset(struct pwc_device *pdev, int flags);
 extern int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt);
-
-/* Various controls; should be obvious. Value 0..65535, or < 0 on error */
-extern int pwc_get_brightness(struct pwc_device *pdev);
-extern int pwc_set_brightness(struct pwc_device *pdev, int value);
-extern int pwc_get_contrast(struct pwc_device *pdev);
-extern int pwc_set_contrast(struct pwc_device *pdev, int value);
-extern int pwc_get_gamma(struct pwc_device *pdev);
-extern int pwc_set_gamma(struct pwc_device *pdev, int value);
-extern int pwc_get_saturation(struct pwc_device *pdev, int *value);
-extern int pwc_set_saturation(struct pwc_device *pdev, int value);
 extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value);
 extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor);
-extern int pwc_restore_user(struct pwc_device *pdev);
-extern int pwc_save_user(struct pwc_device *pdev);
-extern int pwc_restore_factory(struct pwc_device *pdev);
-
-/* exported for use by v4l2 controls */
-extern int pwc_get_red_gain(struct pwc_device *pdev, int *value);
-extern int pwc_set_red_gain(struct pwc_device *pdev, int value);
-extern int pwc_get_blue_gain(struct pwc_device *pdev, int *value);
-extern int pwc_set_blue_gain(struct pwc_device *pdev, int value);
-extern int pwc_get_awb(struct pwc_device *pdev);
-extern int pwc_set_awb(struct pwc_device *pdev, int mode);
-extern int pwc_set_agc(struct pwc_device *pdev, int mode, int value);
-extern int pwc_get_agc(struct pwc_device *pdev, int *value);
-extern int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value);
-extern int pwc_get_shutter_speed(struct pwc_device *pdev, int *value);
-
-extern int pwc_set_colour_mode(struct pwc_device *pdev, int colour);
-extern int pwc_get_colour_mode(struct pwc_device *pdev, int *colour);
-extern int pwc_set_contour(struct pwc_device *pdev, int contour);
-extern int pwc_get_contour(struct pwc_device *pdev, int *contour);
-extern int pwc_set_backlight(struct pwc_device *pdev, int backlight);
-extern int pwc_get_backlight(struct pwc_device *pdev, int *backlight);
-extern int pwc_set_flicker(struct pwc_device *pdev, int flicker);
-extern int pwc_get_flicker(struct pwc_device *pdev, int *flicker);
-extern int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise);
-extern int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise);
+extern int send_control_msg(struct pwc_device *pdev,
+                           u8 request, u16 value, void *buf, int buflen);
+
+/* Control get / set helpers */
+int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data);
+int pwc_set_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, u8 data);
+int pwc_get_s8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data);
+#define pwc_set_s8_ctrl pwc_set_u8_ctrl
+int pwc_get_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *dat);
+int pwc_set_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, u16 data);
+int pwc_button_ctrl(struct pwc_device *pdev, u16 value);
+int pwc_init_controls(struct pwc_device *pdev);
 
 /* Power down or up the camera; not supported by all models */
-extern int pwc_camera_power(struct pwc_device *pdev, int power);
+extern void pwc_camera_power(struct pwc_device *pdev, int power);
 
 /* Private ioctl()s; see pwc-ioctl.h */
 extern long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg);
@@ -343,12 +382,6 @@ extern const struct v4l2_ioctl_ops pwc_ioctl_ops;
 
 /** pwc-uncompress.c */
 /* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */
-extern int pwc_decompress(struct pwc_device *pdev);
-
-#ifdef __cplusplus
-}
-#endif
-
+int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf);
 
 #endif
-/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
index b42bfa5..d07df22 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/mm.h>
 #include <linux/moduleparam.h>
 #include <linux/time.h>
-#include <linux/version.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
@@ -40,7 +39,7 @@
 #include <mach/dma.h>
 #include <mach/camera.h>
 
-#define PXA_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 5)
+#define PXA_CAM_VERSION "0.0.6"
 #define PXA_CAM_DRV_NAME "pxa27x-camera"
 
 /* Camera Interface */
@@ -247,7 +246,7 @@ static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
        if (bytes_per_line < 0)
                return bytes_per_line;
 
-       dev_dbg(icd->dev.parent, "count=%d, size=%d\n", *count, *size);
+       dev_dbg(icd->parent, "count=%d, size=%d\n", *count, *size);
 
        *size = bytes_per_line * icd->user_height;
 
@@ -262,13 +261,13 @@ static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
 static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
 {
        struct soc_camera_device *icd = vq->priv_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
        int i;
 
        BUG_ON(in_interrupt());
 
-       dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
                &buf->vb, buf->vb.baddr, buf->vb.bsize);
 
        /*
@@ -429,7 +428,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
                struct videobuf_buffer *vb, enum v4l2_field field)
 {
        struct soc_camera_device *icd = vq->priv_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct pxa_camera_dev *pcdev = ici->priv;
        struct device *dev = pcdev->soc_host.v4l2_dev.dev;
        struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
@@ -636,11 +635,11 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq,
                               struct videobuf_buffer *vb)
 {
        struct soc_camera_device *icd = vq->priv_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct pxa_camera_dev *pcdev = ici->priv;
        struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
 
-       dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d active=%p\n",
+       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d active=%p\n",
                __func__, vb, vb->baddr, vb->bsize, pcdev->active);
 
        list_add_tail(&vb->queue, &pcdev->capture);
@@ -658,7 +657,7 @@ static void pxa_videobuf_release(struct videobuf_queue *vq,
        struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
 #ifdef DEBUG
        struct soc_camera_device *icd = vq->priv_data;
-       struct device *dev = icd->dev.parent;
+       struct device *dev = icd->parent;
 
        dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
                vb, vb->baddr, vb->bsize);
@@ -843,7 +842,7 @@ static struct videobuf_queue_ops pxa_videobuf_ops = {
 static void pxa_camera_init_videobuf(struct videobuf_queue *q,
                              struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct pxa_camera_dev *pcdev = ici->priv;
 
        /*
@@ -972,7 +971,7 @@ static irqreturn_t pxa_camera_irq(int irq, void *data)
  */
 static int pxa_camera_add_device(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct pxa_camera_dev *pcdev = ici->priv;
 
        if (pcdev->icd)
@@ -982,7 +981,7 @@ static int pxa_camera_add_device(struct soc_camera_device *icd)
 
        pcdev->icd = icd;
 
-       dev_info(icd->dev.parent, "PXA Camera driver attached to camera %d\n",
+       dev_info(icd->parent, "PXA Camera driver attached to camera %d\n",
                 icd->devnum);
 
        return 0;
@@ -991,12 +990,12 @@ static int pxa_camera_add_device(struct soc_camera_device *icd)
 /* Called with .video_lock held */
 static void pxa_camera_remove_device(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct pxa_camera_dev *pcdev = ici->priv;
 
        BUG_ON(icd != pcdev->icd);
 
-       dev_info(icd->dev.parent, "PXA Camera driver detached from camera %d\n",
+       dev_info(icd->parent, "PXA Camera driver detached from camera %d\n",
                 icd->devnum);
 
        /* disable capture, disable interrupts */
@@ -1057,7 +1056,7 @@ static int test_platform_param(struct pxa_camera_dev *pcdev,
 static void pxa_camera_setup_cicr(struct soc_camera_device *icd,
                                  unsigned long flags, __u32 pixfmt)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct pxa_camera_dev *pcdev = ici->priv;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        unsigned long dw, bpp;
@@ -1152,7 +1151,7 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd,
 
 static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct pxa_camera_dev *pcdev = ici->priv;
        unsigned long bus_flags, camera_flags, common_flags;
        int ret;
@@ -1210,7 +1209,7 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
 static int pxa_camera_try_bus_param(struct soc_camera_device *icd,
                                    unsigned char buswidth)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct pxa_camera_dev *pcdev = ici->priv;
        unsigned long bus_flags, camera_flags;
        int ret = test_platform_param(pcdev, buswidth, &bus_flags);
@@ -1247,7 +1246,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int id
                                  struct soc_camera_format_xlate *xlate)
 {
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-       struct device *dev = icd->dev.parent;
+       struct device *dev = icd->parent;
        int formats = 0, ret;
        struct pxa_cam *cam;
        enum v4l2_mbus_pixelcode code;
@@ -1335,9 +1334,9 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd,
                               struct v4l2_crop *a)
 {
        struct v4l2_rect *rect = &a->c;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct device *dev = icd->parent;
+       struct soc_camera_host *ici = to_soc_camera_host(dev);
        struct pxa_camera_dev *pcdev = ici->priv;
-       struct device *dev = icd->dev.parent;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        struct soc_camera_sense sense = {
                .master_clock = pcdev->mclk,
@@ -1379,7 +1378,7 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd,
                        return ret;
 
                if (pxa_camera_check_frame(mf.width, mf.height)) {
-                       dev_warn(icd->dev.parent,
+                       dev_warn(icd->parent,
                                 "Inconsistent state. Use S_FMT to repair\n");
                        return -EINVAL;
                }
@@ -1406,9 +1405,9 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd,
 static int pxa_camera_set_fmt(struct soc_camera_device *icd,
                              struct v4l2_format *f)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct device *dev = icd->parent;
+       struct soc_camera_host *ici = to_soc_camera_host(dev);
        struct pxa_camera_dev *pcdev = ici->priv;
-       struct device *dev = icd->dev.parent;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        const struct soc_camera_format_xlate *xlate = NULL;
        struct soc_camera_sense sense = {
@@ -1485,7 +1484,7 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
        if (!xlate) {
-               dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt);
+               dev_warn(icd->parent, "Format %x not found\n", pixfmt);
                return -EINVAL;
        }
 
@@ -1499,16 +1498,11 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd,
                              &pix->height, 32, 2048, 0,
                              pixfmt == V4L2_PIX_FMT_YUV422P ? 4 : 0);
 
-       pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
-                                                   xlate->host_fmt);
-       if (pix->bytesperline < 0)
-               return pix->bytesperline;
-       pix->sizeimage = pix->height * pix->bytesperline;
-
        /* limit to sensor capabilities */
        mf.width        = pix->width;
        mf.height       = pix->height;
-       mf.field        = pix->field;
+       /* Only progressive video supported so far */
+       mf.field        = V4L2_FIELD_NONE;
        mf.colorspace   = pix->colorspace;
        mf.code         = xlate->code;
 
@@ -1527,7 +1521,7 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd,
                break;
        default:
                /* TODO: support interlaced at least in pass-through mode */
-               dev_err(icd->dev.parent, "Field type %d unsupported.\n",
+               dev_err(icd->parent, "Field type %d unsupported.\n",
                        mf.field);
                return -EINVAL;
        }
@@ -1578,15 +1572,14 @@ static int pxa_camera_querycap(struct soc_camera_host *ici,
 {
        /* cap->name is set by the firendly caller:-> */
        strlcpy(cap->card, pxa_cam_driver_description, sizeof(cap->card));
-       cap->version = PXA_CAM_VERSION_CODE;
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
 
        return 0;
 }
 
-static int pxa_camera_suspend(struct soc_camera_device *icd, pm_message_t state)
+static int pxa_camera_suspend(struct device *dev)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(dev);
        struct pxa_camera_dev *pcdev = ici->priv;
        int i = 0, ret = 0;
 
@@ -1596,15 +1589,19 @@ static int pxa_camera_suspend(struct soc_camera_device *icd, pm_message_t state)
        pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR3);
        pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR4);
 
-       if ((pcdev->icd) && (pcdev->icd->ops->suspend))
-               ret = pcdev->icd->ops->suspend(pcdev->icd, state);
+       if (pcdev->icd) {
+               struct v4l2_subdev *sd = soc_camera_to_subdev(pcdev->icd);
+               ret = v4l2_subdev_call(sd, core, s_power, 0);
+               if (ret == -ENOIOCTLCMD)
+                       ret = 0;
+       }
 
        return ret;
 }
 
-static int pxa_camera_resume(struct soc_camera_device *icd)
+static int pxa_camera_resume(struct device *dev)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(dev);
        struct pxa_camera_dev *pcdev = ici->priv;
        int i = 0, ret = 0;
 
@@ -1618,8 +1615,12 @@ static int pxa_camera_resume(struct soc_camera_device *icd)
        __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR3);
        __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR4);
 
-       if ((pcdev->icd) && (pcdev->icd->ops->resume))
-               ret = pcdev->icd->ops->resume(pcdev->icd);
+       if (pcdev->icd) {
+               struct v4l2_subdev *sd = soc_camera_to_subdev(pcdev->icd);
+               ret = v4l2_subdev_call(sd, core, s_power, 1);
+               if (ret == -ENOIOCTLCMD)
+                       ret = 0;
+       }
 
        /* Restart frame capture if active buffer exists */
        if (!ret && pcdev->active)
@@ -1632,8 +1633,6 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
        .owner          = THIS_MODULE,
        .add            = pxa_camera_add_device,
        .remove         = pxa_camera_remove_device,
-       .suspend        = pxa_camera_suspend,
-       .resume         = pxa_camera_resume,
        .set_crop       = pxa_camera_set_crop,
        .get_formats    = pxa_camera_get_formats,
        .put_formats    = pxa_camera_put_formats,
@@ -1818,9 +1817,15 @@ static int __devexit pxa_camera_remove(struct platform_device *pdev)
        return 0;
 }
 
+static struct dev_pm_ops pxa_camera_pm = {
+       .suspend        = pxa_camera_suspend,
+       .resume         = pxa_camera_resume,
+};
+
 static struct platform_driver pxa_camera_driver = {
        .driver         = {
                .name   = PXA_CAM_DRV_NAME,
+               .pm     = &pxa_camera_pm,
        },
        .probe          = pxa_camera_probe,
        .remove         = __devexit_p(pxa_camera_remove),
@@ -1843,4 +1848,5 @@ module_exit(pxa_camera_exit);
 MODULE_DESCRIPTION("PXA27x SoC Camera Host driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(PXA_CAM_VERSION);
 MODULE_ALIAS("platform:" PXA_CAM_DRV_NAME);
index 57e11b6..847ccc0 100644 (file)
@@ -1364,10 +1364,9 @@ static int rj54n1_video_probe(struct soc_camera_device *icd,
        int data1, data2;
        int ret;
 
-       /* This could be a BUG_ON() or a WARN_ON(), or remove it completely */
-       if (!icd->dev.parent ||
-           to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
-               return -ENODEV;
+       /* We must have a parent by now. And it cannot be a wrong one. */
+       BUG_ON(!icd->parent ||
+              to_soc_camera_host(icd->parent)->nr != icd->iface);
 
        /* Read out the chip version register */
        data1 = reg_read(client, RJ54N1_DEV_CODE);
index 5b9dce8..803c9c8 100644 (file)
  * Example maximum bandwidth utilization:
  *
  * -full size, color mode YUYV or YUV422P: 2 channels at once
- *
  * -full or half size Grey scale: all 4 channels at once
- *
  * -half size, color mode YUYV or YUV422P: all 4 channels at once
- *
  * -full size, color mode YUYV or YUV422P 1/2 frame rate: all 4 channels
  *  at once.
- *  (TODO: Incorporate videodev2 frame rate(FR) enumeration,
- *  which is currently experimental.)
  *
  * 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
@@ -47,7 +42,6 @@
 #include <linux/mutex.h>
 #include <linux/slab.h>
 #include <linux/videodev2.h>
-#include <linux/version.h>
 #include <linux/mm.h>
 #include <media/videobuf-vmalloc.h>
 #include <media/v4l2-common.h>
 #include <linux/vmalloc.h>
 #include <linux/usb.h>
 
-#define S2255_MAJOR_VERSION    1
-#define S2255_MINOR_VERSION    21
-#define S2255_RELEASE          0
-#define S2255_VERSION          KERNEL_VERSION(S2255_MAJOR_VERSION, \
-                                              S2255_MINOR_VERSION, \
-                                              S2255_RELEASE)
+#define S2255_VERSION          "1.22.1"
 #define FIRMWARE_FILE_NAME "f2255usb.bin"
 
 /* default JPEG quality */
 #define MASK_COLOR       0x000000ff
 #define MASK_JPG_QUALITY 0x0000ff00
 #define MASK_INPUT_TYPE  0x000f0000
-/* frame decimation. Not implemented by V4L yet(experimental in V4L) */
+/* frame decimation. */
 #define FDEC_1         1       /* capture every frame. default */
 #define FDEC_2         2       /* capture every 2nd frame */
 #define FDEC_3         3       /* capture every 3rd frame */
@@ -312,9 +301,9 @@ struct s2255_fh {
 };
 
 /* current cypress EEPROM firmware version */
-#define S2255_CUR_USB_FWVER    ((3 << 8) | 11)
+#define S2255_CUR_USB_FWVER    ((3 << 8) | 12)
 /* current DSP FW version */
-#define S2255_CUR_DSP_FWVER     10102
+#define S2255_CUR_DSP_FWVER     10104
 /* Need DSP version 5+ for video status feature */
 #define S2255_MIN_DSP_STATUS      5
 #define S2255_MIN_DSP_COLORFILTER 8
@@ -502,7 +491,7 @@ static void planar422p_to_yuv_packed(const unsigned char *in,
 
 static void s2255_reset_dsppower(struct s2255_dev *dev)
 {
-       s2255_vendor_req(dev, 0x40, 0x0b0b, 0x0b01, NULL, 0, 1);
+       s2255_vendor_req(dev, 0x40, 0x0000, 0x0001, NULL, 0, 1);
        msleep(10);
        s2255_vendor_req(dev, 0x50, 0x0000, 0x0000, NULL, 0, 1);
        msleep(600);
@@ -856,7 +845,6 @@ static int vidioc_querycap(struct file *file, void *priv,
        strlcpy(cap->driver, "s2255", sizeof(cap->driver));
        strlcpy(cap->card, "s2255", sizeof(cap->card));
        usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
-       cap->version = S2255_VERSION;
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
        return 0;
 }
@@ -1984,9 +1972,8 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
                          video_device_node_name(&channel->vdev));
 
        }
-       printk(KERN_INFO "Sensoray 2255 V4L driver Revision: %d.%d\n",
-              S2255_MAJOR_VERSION,
-              S2255_MINOR_VERSION);
+       printk(KERN_INFO "Sensoray 2255 V4L driver Revision: %s\n",
+              S2255_VERSION);
        /* if no channels registered, return error and probe will fail*/
        if (atomic_read(&dev->num_channels) == 0) {
                v4l2_device_unregister(&dev->v4l2_dev);
@@ -2302,15 +2289,12 @@ static int s2255_board_init(struct s2255_dev *dev)
        /* query the firmware */
        fw_ver = s2255_get_fx2fw(dev);
 
-       printk(KERN_INFO "2255 usb firmware version %d.%d\n",
+       printk(KERN_INFO "s2255: usb firmware version %d.%d\n",
               (fw_ver >> 8) & 0xff,
               fw_ver & 0xff);
 
        if (fw_ver < S2255_CUR_USB_FWVER)
-               dev_err(&dev->udev->dev,
-                       "usb firmware not up to date %d.%d\n",
-                       (fw_ver >> 8) & 0xff,
-                       fw_ver & 0xff);
+               printk(KERN_INFO "s2255: newer USB firmware available\n");
 
        for (j = 0; j < MAX_CHANNELS; j++) {
                struct s2255_channel *channel = &dev->channel[j];
@@ -2721,3 +2705,4 @@ module_exit(usb_s2255_exit);
 MODULE_DESCRIPTION("Sensoray 2255 Video for Linux driver");
 MODULE_AUTHOR("Dean Anderson (Sensoray Company Inc.)");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(S2255_VERSION);
index 81b4a82..0d730e5 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/bug.h>
@@ -451,7 +450,6 @@ static int fimc_vidioc_querycap_capture(struct file *file, void *priv,
        strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1);
        strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1);
        cap->bus_info[0] = 0;
-       cap->version = KERNEL_VERSION(1, 0, 0);
        cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE |
                            V4L2_CAP_VIDEO_CAPTURE_MPLANE;
 
index bdf19ad..aa55066 100644 (file)
@@ -12,7 +12,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/bug.h>
@@ -774,7 +773,6 @@ static int fimc_m2m_querycap(struct file *file, void *priv,
        strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1);
        strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1);
        cap->bus_info[0] = 0;
-       cap->version = KERNEL_VERSION(1, 0, 0);
        cap->capabilities = V4L2_CAP_STREAMING |
                V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
                V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
@@ -1937,3 +1935,4 @@ module_exit(fimc_exit);
 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
 MODULE_DESCRIPTION("S5P FIMC camera host interface/video postprocessor driver");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0.1");
diff --git a/drivers/media/video/s5p-mfc/Makefile b/drivers/media/video/s5p-mfc/Makefile
new file mode 100644 (file)
index 0000000..d066340
--- /dev/null
@@ -0,0 +1,5 @@
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) := s5p-mfc.o
+s5p-mfc-y += s5p_mfc.o s5p_mfc_intr.o s5p_mfc_opr.o
+s5p-mfc-y += s5p_mfc_dec.o s5p_mfc_enc.o
+s5p-mfc-y += s5p_mfc_ctrl.o s5p_mfc_cmd.o
+s5p-mfc-y += s5p_mfc_pm.o s5p_mfc_shm.o
diff --git a/drivers/media/video/s5p-mfc/regs-mfc.h b/drivers/media/video/s5p-mfc/regs-mfc.h
new file mode 100644 (file)
index 0000000..053a8a8
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+ * Register definition file for Samsung MFC V5.1 Interface (FIMV) driver
+ *
+ * Kamil Debski, Copyright (c) 2010 Samsung Electronics
+ * http://www.samsung.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 _REGS_FIMV_H
+#define _REGS_FIMV_H
+
+#define S5P_FIMV_REG_SIZE      (S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR)
+#define S5P_FIMV_REG_COUNT     ((S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) / 4)
+
+/* Number of bits that the buffer address should be shifted for particular
+ * MFC buffers.  */
+#define S5P_FIMV_START_ADDR            0x0000
+#define S5P_FIMV_END_ADDR              0xe008
+
+#define S5P_FIMV_SW_RESET              0x0000
+#define S5P_FIMV_RISC_HOST_INT         0x0008
+
+/* Command from HOST to RISC */
+#define S5P_FIMV_HOST2RISC_CMD         0x0030
+#define S5P_FIMV_HOST2RISC_ARG1                0x0034
+#define S5P_FIMV_HOST2RISC_ARG2                0x0038
+#define S5P_FIMV_HOST2RISC_ARG3                0x003c
+#define S5P_FIMV_HOST2RISC_ARG4                0x0040
+
+/* Command from RISC to HOST */
+#define S5P_FIMV_RISC2HOST_CMD         0x0044
+#define S5P_FIMV_RISC2HOST_CMD_MASK    0x1FFFF
+#define S5P_FIMV_RISC2HOST_ARG1                0x0048
+#define S5P_FIMV_RISC2HOST_ARG2                0x004c
+#define S5P_FIMV_RISC2HOST_ARG3                0x0050
+#define S5P_FIMV_RISC2HOST_ARG4                0x0054
+
+#define S5P_FIMV_FW_VERSION            0x0058
+#define S5P_FIMV_SYS_MEM_SZ            0x005c
+#define S5P_FIMV_FW_STATUS             0x0080
+
+/* Memory controller register */
+#define S5P_FIMV_MC_DRAMBASE_ADR_A     0x0508
+#define S5P_FIMV_MC_DRAMBASE_ADR_B     0x050c
+#define S5P_FIMV_MC_STATUS             0x0510
+
+/* Common register */
+#define S5P_FIMV_COMMON_BASE_A         0x0600
+#define S5P_FIMV_COMMON_BASE_B         0x0700
+
+/* Decoder */
+#define S5P_FIMV_DEC_CHROMA_ADR                (S5P_FIMV_COMMON_BASE_A)
+#define S5P_FIMV_DEC_LUMA_ADR          (S5P_FIMV_COMMON_BASE_B)
+
+/* H.264 decoding */
+#define S5P_FIMV_H264_VERT_NB_MV_ADR   (S5P_FIMV_COMMON_BASE_A + 0x8c)
+                                       /* vertical neighbor motion vector */
+#define S5P_FIMV_H264_NB_IP_ADR                (S5P_FIMV_COMMON_BASE_A + 0x90)
+                                       /* neighbor pixels for intra pred */
+#define S5P_FIMV_H264_MV_ADR           (S5P_FIMV_COMMON_BASE_B + 0x80)
+                                       /* H264 motion vector */
+
+/* MPEG4 decoding */
+#define S5P_FIMV_MPEG4_NB_DCAC_ADR     (S5P_FIMV_COMMON_BASE_A + 0x8c)
+                                       /* neighbor AC/DC coeff. */
+#define S5P_FIMV_MPEG4_UP_NB_MV_ADR    (S5P_FIMV_COMMON_BASE_A + 0x90)
+                                       /* upper neighbor motion vector */
+#define S5P_FIMV_MPEG4_SA_MV_ADR       (S5P_FIMV_COMMON_BASE_A + 0x94)
+                                       /* subseq. anchor motion vector */
+#define S5P_FIMV_MPEG4_OT_LINE_ADR     (S5P_FIMV_COMMON_BASE_A + 0x98)
+                                       /* overlap transform line */
+#define S5P_FIMV_MPEG4_SP_ADR          (S5P_FIMV_COMMON_BASE_A + 0xa8)
+                                       /* syntax parser */
+
+/* H.263 decoding */
+#define S5P_FIMV_H263_NB_DCAC_ADR      (S5P_FIMV_COMMON_BASE_A + 0x8c)
+#define S5P_FIMV_H263_UP_NB_MV_ADR     (S5P_FIMV_COMMON_BASE_A + 0x90)
+#define S5P_FIMV_H263_SA_MV_ADR                (S5P_FIMV_COMMON_BASE_A + 0x94)
+#define S5P_FIMV_H263_OT_LINE_ADR      (S5P_FIMV_COMMON_BASE_A + 0x98)
+
+/* VC-1 decoding */
+#define S5P_FIMV_VC1_NB_DCAC_ADR       (S5P_FIMV_COMMON_BASE_A + 0x8c)
+#define S5P_FIMV_VC1_UP_NB_MV_ADR      (S5P_FIMV_COMMON_BASE_A + 0x90)
+#define S5P_FIMV_VC1_SA_MV_ADR         (S5P_FIMV_COMMON_BASE_A + 0x94)
+#define S5P_FIMV_VC1_OT_LINE_ADR       (S5P_FIMV_COMMON_BASE_A + 0x98)
+#define S5P_FIMV_VC1_BITPLANE3_ADR     (S5P_FIMV_COMMON_BASE_A + 0x9c)
+                                       /* bitplane3 */
+#define S5P_FIMV_VC1_BITPLANE2_ADR     (S5P_FIMV_COMMON_BASE_A + 0xa0)
+                                       /* bitplane2 */
+#define S5P_FIMV_VC1_BITPLANE1_ADR     (S5P_FIMV_COMMON_BASE_A + 0xa4)
+                                       /* bitplane1 */
+
+/* Encoder */
+#define S5P_FIMV_ENC_REF0_LUMA_ADR     (S5P_FIMV_COMMON_BASE_A + 0x1c)
+#define S5P_FIMV_ENC_REF1_LUMA_ADR     (S5P_FIMV_COMMON_BASE_A + 0x20)
+                                       /* reconstructed luma */
+#define S5P_FIMV_ENC_REF0_CHROMA_ADR   (S5P_FIMV_COMMON_BASE_B)
+#define S5P_FIMV_ENC_REF1_CHROMA_ADR   (S5P_FIMV_COMMON_BASE_B + 0x04)
+                                       /* reconstructed chroma */
+#define S5P_FIMV_ENC_REF2_LUMA_ADR     (S5P_FIMV_COMMON_BASE_B + 0x10)
+#define S5P_FIMV_ENC_REF2_CHROMA_ADR   (S5P_FIMV_COMMON_BASE_B + 0x08)
+#define S5P_FIMV_ENC_REF3_LUMA_ADR     (S5P_FIMV_COMMON_BASE_B + 0x14)
+#define S5P_FIMV_ENC_REF3_CHROMA_ADR   (S5P_FIMV_COMMON_BASE_B + 0x0c)
+
+/* H.264 encoding */
+#define S5P_FIMV_H264_UP_MV_ADR                (S5P_FIMV_COMMON_BASE_A)
+                                       /* upper motion vector */
+#define S5P_FIMV_H264_NBOR_INFO_ADR    (S5P_FIMV_COMMON_BASE_A + 0x04)
+                                       /* entropy engine's neighbor info. */
+#define S5P_FIMV_H264_UP_INTRA_MD_ADR  (S5P_FIMV_COMMON_BASE_A + 0x08)
+                                       /* upper intra MD */
+#define S5P_FIMV_H264_COZERO_FLAG_ADR  (S5P_FIMV_COMMON_BASE_A + 0x10)
+                                       /* direct cozero flag */
+#define S5P_FIMV_H264_UP_INTRA_PRED_ADR        (S5P_FIMV_COMMON_BASE_B + 0x40)
+                                       /* upper intra PRED */
+
+/* H.263 encoding */
+#define S5P_FIMV_H263_UP_MV_ADR                (S5P_FIMV_COMMON_BASE_A)
+                                       /* upper motion vector */
+#define S5P_FIMV_H263_ACDC_COEF_ADR    (S5P_FIMV_COMMON_BASE_A + 0x04)
+                                       /* upper Q coeff. */
+
+/* MPEG4 encoding */
+#define S5P_FIMV_MPEG4_UP_MV_ADR       (S5P_FIMV_COMMON_BASE_A)
+                                       /* upper motion vector */
+#define S5P_FIMV_MPEG4_ACDC_COEF_ADR   (S5P_FIMV_COMMON_BASE_A + 0x04)
+                                       /* upper Q coeff. */
+#define S5P_FIMV_MPEG4_COZERO_FLAG_ADR (S5P_FIMV_COMMON_BASE_A + 0x10)
+                                       /* direct cozero flag */
+
+#define S5P_FIMV_ENC_REF_B_LUMA_ADR     0x062c /* ref B Luma addr */
+#define S5P_FIMV_ENC_REF_B_CHROMA_ADR   0x0630 /* ref B Chroma addr */
+
+#define S5P_FIMV_ENC_CUR_LUMA_ADR      0x0718 /* current Luma addr */
+#define S5P_FIMV_ENC_CUR_CHROMA_ADR    0x071C /* current Chroma addr */
+
+/* Codec common register */
+#define S5P_FIMV_ENC_HSIZE_PX          0x0818 /* frame width at encoder */
+#define S5P_FIMV_ENC_VSIZE_PX          0x081c /* frame height at encoder */
+#define S5P_FIMV_ENC_PROFILE           0x0830 /* profile register */
+#define S5P_FIMV_ENC_PROFILE_H264_MAIN                 0
+#define S5P_FIMV_ENC_PROFILE_H264_HIGH                 1
+#define S5P_FIMV_ENC_PROFILE_H264_BASELINE             2
+#define S5P_FIMV_ENC_PROFILE_MPEG4_SIMPLE              0
+#define S5P_FIMV_ENC_PROFILE_MPEG4_ADVANCED_SIMPLE     1
+#define S5P_FIMV_ENC_PIC_STRUCT                0x083c /* picture field/frame flag */
+#define S5P_FIMV_ENC_LF_CTRL           0x0848 /* loop filter control */
+#define S5P_FIMV_ENC_ALPHA_OFF         0x084c /* loop filter alpha offset */
+#define S5P_FIMV_ENC_BETA_OFF          0x0850 /* loop filter beta offset */
+#define S5P_FIMV_MR_BUSIF_CTRL         0x0854 /* hidden, bus interface ctrl */
+#define S5P_FIMV_ENC_PXL_CACHE_CTRL    0x0a00 /* pixel cache control */
+
+/* Channel & stream interface register */
+#define S5P_FIMV_SI_RTN_CHID           0x2000 /* Return CH inst ID register */
+#define S5P_FIMV_SI_CH0_INST_ID                0x2040 /* codec instance ID */
+#define S5P_FIMV_SI_CH1_INST_ID                0x2080 /* codec instance ID */
+/* Decoder */
+#define S5P_FIMV_SI_VRESOL             0x2004 /* vertical res of decoder */
+#define S5P_FIMV_SI_HRESOL             0x2008 /* horizontal res of decoder */
+#define S5P_FIMV_SI_BUF_NUMBER         0x200c /* number of frames in the
+                                                               decoded pic */
+#define S5P_FIMV_SI_DISPLAY_Y_ADR      0x2010 /* luma addr of displayed pic */
+#define S5P_FIMV_SI_DISPLAY_C_ADR      0x2014 /* chroma addrof displayed pic */
+#define S5P_FIMV_SI_CONSUMED_BYTES     0x2018 /* Consumed number of bytes to
+                                                       decode a frame */
+#define S5P_FIMV_SI_DISPLAY_STATUS     0x201c /* status of decoded picture */
+
+#define S5P_FIMV_SI_CH0_SB_ST_ADR      0x2044 /* start addr of stream buf */
+#define S5P_FIMV_SI_CH0_SB_FRM_SIZE    0x2048 /* size of stream buf */
+#define S5P_FIMV_SI_CH0_DESC_ADR       0x204c /* addr of descriptor buf */
+#define S5P_FIMV_SI_CH0_CPB_SIZE       0x2058 /* max size of coded pic. buf */
+#define S5P_FIMV_SI_CH0_DESC_SIZE      0x205c /* max size of descriptor buf */
+
+#define S5P_FIMV_SI_CH1_SB_ST_ADR      0x2084 /* start addr of stream buf */
+#define S5P_FIMV_SI_CH1_SB_FRM_SIZE    0x2088 /* size of stream buf */
+#define S5P_FIMV_SI_CH1_DESC_ADR       0x208c /* addr of descriptor buf */
+#define S5P_FIMV_SI_CH1_CPB_SIZE       0x2098 /* max size of coded pic. buf */
+#define S5P_FIMV_SI_CH1_DESC_SIZE      0x209c /* max size of descriptor buf */
+
+#define S5P_FIMV_CRC_LUMA0             0x2030 /* luma crc data per frame
+                                                               (top field) */
+#define S5P_FIMV_CRC_CHROMA0           0x2034 /* chroma crc data per frame
+                                                               (top field) */
+#define S5P_FIMV_CRC_LUMA1             0x2038 /* luma crc data per bottom
+                                                               field */
+#define S5P_FIMV_CRC_CHROMA1           0x203c /* chroma crc data per bottom
+                                                               field */
+
+/* Display status */
+#define S5P_FIMV_DEC_STATUS_DECODING_ONLY              0
+#define S5P_FIMV_DEC_STATUS_DECODING_DISPLAY           1
+#define S5P_FIMV_DEC_STATUS_DISPLAY_ONLY               2
+#define S5P_FIMV_DEC_STATUS_DECODING_EMPTY             3
+#define S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK       7
+#define S5P_FIMV_DEC_STATUS_PROGRESSIVE                        (0<<3)
+#define S5P_FIMV_DEC_STATUS_INTERLACE                  (1<<3)
+#define S5P_FIMV_DEC_STATUS_INTERLACE_MASK             (1<<3)
+#define S5P_FIMV_DEC_STATUS_CRC_NUMBER_TWO             (0<<4)
+#define S5P_FIMV_DEC_STATUS_CRC_NUMBER_FOUR            (1<<4)
+#define S5P_FIMV_DEC_STATUS_CRC_NUMBER_MASK            (1<<4)
+#define S5P_FIMV_DEC_STATUS_CRC_GENERATED              (1<<5)
+#define S5P_FIMV_DEC_STATUS_CRC_NOT_GENERATED          (0<<5)
+#define S5P_FIMV_DEC_STATUS_CRC_MASK                   (1<<5)
+
+#define S5P_FIMV_DEC_STATUS_RESOLUTION_MASK            (3<<4)
+#define S5P_FIMV_DEC_STATUS_RESOLUTION_INC             (1<<4)
+#define S5P_FIMV_DEC_STATUS_RESOLUTION_DEC             (2<<4)
+
+/* Decode frame address */
+#define S5P_FIMV_DECODE_Y_ADR                  0x2024
+#define S5P_FIMV_DECODE_C_ADR                  0x2028
+
+/* Decoded frame tpe */
+#define S5P_FIMV_DECODE_FRAME_TYPE             0x2020
+#define S5P_FIMV_DECODE_FRAME_MASK             7
+
+#define S5P_FIMV_DECODE_FRAME_SKIPPED          0
+#define S5P_FIMV_DECODE_FRAME_I_FRAME          1
+#define S5P_FIMV_DECODE_FRAME_P_FRAME          2
+#define S5P_FIMV_DECODE_FRAME_B_FRAME          3
+#define S5P_FIMV_DECODE_FRAME_OTHER_FRAME      4
+
+/* Sizes of buffers required for decoding */
+#define S5P_FIMV_DEC_NB_IP_SIZE                        (32 * 1024)
+#define S5P_FIMV_DEC_VERT_NB_MV_SIZE           (16 * 1024)
+#define S5P_FIMV_DEC_NB_DCAC_SIZE              (16 * 1024)
+#define S5P_FIMV_DEC_UPNB_MV_SIZE              (68 * 1024)
+#define S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE                (136 * 1024)
+#define S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE     (32 * 1024)
+#define S5P_FIMV_DEC_VC1_BITPLANE_SIZE         (2 * 1024)
+#define S5P_FIMV_DEC_STX_PARSER_SIZE           (68 * 1024)
+
+#define S5P_FIMV_DEC_BUF_ALIGN                 (8 * 1024)
+#define S5P_FIMV_ENC_BUF_ALIGN                 (8 * 1024)
+#define S5P_FIMV_NV12M_HALIGN                  16
+#define S5P_FIMV_NV12M_LVALIGN                 16
+#define S5P_FIMV_NV12M_CVALIGN                 8
+#define S5P_FIMV_NV12MT_HALIGN                 128
+#define S5P_FIMV_NV12MT_VALIGN                 32
+#define S5P_FIMV_NV12M_SALIGN                  2048
+#define S5P_FIMV_NV12MT_SALIGN                 8192
+
+/* Sizes of buffers required for encoding */
+#define S5P_FIMV_ENC_UPMV_SIZE         0x10000
+#define S5P_FIMV_ENC_COLFLG_SIZE       0x10000
+#define S5P_FIMV_ENC_INTRAMD_SIZE      0x10000
+#define S5P_FIMV_ENC_INTRAPRED_SIZE    0x4000
+#define S5P_FIMV_ENC_NBORINFO_SIZE     0x10000
+#define S5P_FIMV_ENC_ACDCCOEF_SIZE     0x10000
+
+/* Encoder */
+#define S5P_FIMV_ENC_SI_STRM_SIZE      0x2004 /* stream size */
+#define S5P_FIMV_ENC_SI_PIC_CNT                0x2008 /* picture count */
+#define S5P_FIMV_ENC_SI_WRITE_PTR      0x200c /* write pointer */
+#define S5P_FIMV_ENC_SI_SLICE_TYPE     0x2010 /* slice type(I/P/B/IDR) */
+#define S5P_FIMV_ENC_SI_SLICE_TYPE_NON_CODED   0
+#define S5P_FIMV_ENC_SI_SLICE_TYPE_I           1
+#define S5P_FIMV_ENC_SI_SLICE_TYPE_P           2
+#define S5P_FIMV_ENC_SI_SLICE_TYPE_B           3
+#define S5P_FIMV_ENC_SI_SLICE_TYPE_SKIPPED     4
+#define S5P_FIMV_ENC_SI_SLICE_TYPE_OTHERS      5
+#define S5P_FIMV_ENCODED_Y_ADDR         0x2014 /* the addr of the encoded
+                                                               luma pic */
+#define S5P_FIMV_ENCODED_C_ADDR         0x2018 /* the addr of the encoded
+                                                               chroma pic */
+
+#define S5P_FIMV_ENC_SI_CH0_SB_ADR     0x2044 /* addr of stream buf */
+#define S5P_FIMV_ENC_SI_CH0_SB_SIZE    0x204c /* size of stream buf */
+#define S5P_FIMV_ENC_SI_CH0_CUR_Y_ADR  0x2050 /* current Luma addr */
+#define S5P_FIMV_ENC_SI_CH0_CUR_C_ADR  0x2054 /* current Chroma addr */
+#define S5P_FIMV_ENC_SI_CH0_FRAME_INS  0x2058 /* frame insertion */
+
+#define S5P_FIMV_ENC_SI_CH1_SB_ADR     0x2084 /* addr of stream buf */
+#define S5P_FIMV_ENC_SI_CH1_SB_SIZE    0x208c /* size of stream buf */
+#define S5P_FIMV_ENC_SI_CH1_CUR_Y_ADR  0x2090 /* current Luma addr */
+#define S5P_FIMV_ENC_SI_CH1_CUR_C_ADR  0x2094 /* current Chroma addr */
+#define S5P_FIMV_ENC_SI_CH1_FRAME_INS  0x2098 /* frame insertion */
+
+#define S5P_FIMV_ENC_PIC_TYPE_CTRL     0xc504 /* pic type level control */
+#define S5P_FIMV_ENC_B_RECON_WRITE_ON  0xc508 /* B frame recon write ctrl */
+#define S5P_FIMV_ENC_MSLICE_CTRL       0xc50c /* multi slice control */
+#define S5P_FIMV_ENC_MSLICE_MB         0xc510 /* MB number in the one slice */
+#define S5P_FIMV_ENC_MSLICE_BIT                0xc514 /* bit count for one slice */
+#define S5P_FIMV_ENC_CIR_CTRL          0xc518 /* number of intra refresh MB */
+#define S5P_FIMV_ENC_MAP_FOR_CUR       0xc51c /* linear or tiled mode */
+#define S5P_FIMV_ENC_PADDING_CTRL      0xc520 /* padding control */
+
+#define S5P_FIMV_ENC_RC_CONFIG         0xc5a0 /* RC config */
+#define S5P_FIMV_ENC_RC_BIT_RATE       0xc5a8 /* bit rate */
+#define S5P_FIMV_ENC_RC_QBOUND         0xc5ac /* max/min QP */
+#define S5P_FIMV_ENC_RC_RPARA          0xc5b0 /* rate control reaction coeff */
+#define S5P_FIMV_ENC_RC_MB_CTRL                0xc5b4 /* MB adaptive scaling */
+
+/* Encoder for H264 only */
+#define S5P_FIMV_ENC_H264_ENTROPY_MODE 0xd004 /* CAVLC or CABAC */
+#define S5P_FIMV_ENC_H264_ALPHA_OFF    0xd008 /* loop filter alpha offset */
+#define S5P_FIMV_ENC_H264_BETA_OFF     0xd00c /* loop filter beta offset */
+#define S5P_FIMV_ENC_H264_NUM_OF_REF   0xd010 /* number of reference for P/B */
+#define S5P_FIMV_ENC_H264_TRANS_FLAG   0xd034 /* 8x8 transform flag in PPS &
+                                                               high profile */
+
+#define S5P_FIMV_ENC_RC_FRAME_RATE     0xd0d0 /* frame rate */
+
+/* Encoder for MPEG4 only */
+#define S5P_FIMV_ENC_MPEG4_QUART_PXL   0xe008 /* qpel interpolation ctrl */
+
+/* Additional */
+#define S5P_FIMV_SI_CH0_DPB_CONF_CTRL   0x2068 /* DPB Config Control Register */
+#define S5P_FIMV_SLICE_INT_MASK                1
+#define S5P_FIMV_SLICE_INT_SHIFT       31
+#define S5P_FIMV_DDELAY_ENA_SHIFT      30
+#define S5P_FIMV_DDELAY_VAL_MASK       0xff
+#define S5P_FIMV_DDELAY_VAL_SHIFT      16
+#define S5P_FIMV_DPB_COUNT_MASK                0xffff
+#define S5P_FIMV_DPB_FLUSH_MASK                1
+#define S5P_FIMV_DPB_FLUSH_SHIFT       14
+
+
+#define S5P_FIMV_SI_CH0_RELEASE_BUF     0x2060 /* DPB release buffer register */
+#define S5P_FIMV_SI_CH0_HOST_WR_ADR    0x2064 /* address of shared memory */
+
+/* Codec numbers  */
+#define S5P_FIMV_CODEC_NONE            -1
+
+#define S5P_FIMV_CODEC_H264_DEC                0
+#define S5P_FIMV_CODEC_VC1_DEC         1
+#define S5P_FIMV_CODEC_MPEG4_DEC       2
+#define S5P_FIMV_CODEC_MPEG2_DEC       3
+#define S5P_FIMV_CODEC_H263_DEC                4
+#define S5P_FIMV_CODEC_VC1RCV_DEC      5
+
+#define S5P_FIMV_CODEC_H264_ENC                16
+#define S5P_FIMV_CODEC_MPEG4_ENC       17
+#define S5P_FIMV_CODEC_H263_ENC                18
+
+/* Channel Control Register */
+#define S5P_FIMV_CH_SEQ_HEADER         1
+#define S5P_FIMV_CH_FRAME_START                2
+#define S5P_FIMV_CH_LAST_FRAME         3
+#define S5P_FIMV_CH_INIT_BUFS          4
+#define S5P_FIMV_CH_FRAME_START_REALLOC        5
+#define S5P_FIMV_CH_MASK               7
+#define S5P_FIMV_CH_SHIFT              16
+
+
+/* Host to RISC command */
+#define S5P_FIMV_H2R_CMD_EMPTY         0
+#define S5P_FIMV_H2R_CMD_OPEN_INSTANCE 1
+#define S5P_FIMV_H2R_CMD_CLOSE_INSTANCE        2
+#define S5P_FIMV_H2R_CMD_SYS_INIT      3
+#define S5P_FIMV_H2R_CMD_FLUSH         4
+#define S5P_FIMV_H2R_CMD_SLEEP         5
+#define S5P_FIMV_H2R_CMD_WAKEUP                6
+
+#define S5P_FIMV_R2H_CMD_EMPTY                 0
+#define S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET     1
+#define S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET    2
+#define S5P_FIMV_R2H_CMD_RSV_RET               3
+#define S5P_FIMV_R2H_CMD_SEQ_DONE_RET          4
+#define S5P_FIMV_R2H_CMD_FRAME_DONE_RET                5
+#define S5P_FIMV_R2H_CMD_SLICE_DONE_RET                6
+#define S5P_FIMV_R2H_CMD_ENC_COMPLETE_RET      7
+#define S5P_FIMV_R2H_CMD_SYS_INIT_RET          8
+#define S5P_FIMV_R2H_CMD_FW_STATUS_RET         9
+#define S5P_FIMV_R2H_CMD_SLEEP_RET             10
+#define S5P_FIMV_R2H_CMD_WAKEUP_RET            11
+#define S5P_FIMV_R2H_CMD_FLUSH_RET             12
+#define S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET      15
+#define S5P_FIMV_R2H_CMD_EDFU_INIT_RET         16
+#define S5P_FIMV_R2H_CMD_ERR_RET               32
+
+/* Error handling defines */
+#define S5P_FIMV_ERR_WARNINGS_START            145
+#define S5P_FIMV_ERR_DEC_MASK                  0xFFFF
+#define S5P_FIMV_ERR_DEC_SHIFT                 0
+#define S5P_FIMV_ERR_DSPL_MASK                 0xFFFF0000
+#define S5P_FIMV_ERR_DSPL_SHIFT                        16
+
+/* Shared memory registers' offsets */
+
+/* An offset of the start position in the stream when
+ * the start position is not aligned */
+#define S5P_FIMV_SHARED_CROP_INFO_H            0x0020
+#define S5P_FIMV_SHARED_CROP_LEFT_MASK         0xFFFF
+#define S5P_FIMV_SHARED_CROP_LEFT_SHIFT                0
+#define S5P_FIMV_SHARED_CROP_RIGHT_MASK                0xFFFF0000
+#define S5P_FIMV_SHARED_CROP_RIGHT_SHIFT       16
+#define S5P_FIMV_SHARED_CROP_INFO_V            0x0024
+#define S5P_FIMV_SHARED_CROP_TOP_MASK          0xFFFF
+#define S5P_FIMV_SHARED_CROP_TOP_SHIFT         0
+#define S5P_FIMV_SHARED_CROP_BOTTOM_MASK       0xFFFF0000
+#define S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT      16
+#define S5P_FIMV_SHARED_SET_FRAME_TAG          0x0004
+#define S5P_FIMV_SHARED_GET_FRAME_TAG_TOP      0x0008
+#define S5P_FIMV_SHARED_GET_FRAME_TAG_BOT      0x000C
+#define S5P_FIMV_SHARED_START_BYTE_NUM         0x0018
+#define S5P_FIMV_SHARED_RC_VOP_TIMING          0x0030
+#define S5P_FIMV_SHARED_LUMA_DPB_SIZE          0x0064
+#define S5P_FIMV_SHARED_CHROMA_DPB_SIZE                0x0068
+#define S5P_FIMV_SHARED_MV_SIZE                        0x006C
+#define S5P_FIMV_SHARED_PIC_TIME_TOP           0x0010
+#define S5P_FIMV_SHARED_PIC_TIME_BOTTOM                0x0014
+#define S5P_FIMV_SHARED_EXT_ENC_CONTROL                0x0028
+#define S5P_FIMV_SHARED_P_B_FRAME_QP           0x0070
+#define S5P_FIMV_SHARED_ASPECT_RATIO_IDC       0x0074
+#define S5P_FIMV_SHARED_EXTENDED_SAR           0x0078
+#define S5P_FIMV_SHARED_H264_I_PERIOD          0x009C
+#define S5P_FIMV_SHARED_RC_CONTROL_CONFIG      0x00A0
+
+#endif /* _REGS_FIMV_H */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc.c b/drivers/media/video/s5p-mfc/s5p_mfc.c
new file mode 100644 (file)
index 0000000..7dc7eab
--- /dev/null
@@ -0,0 +1,1274 @@
+/*
+ * Samsung S5P Multi Format Codec v 5.1
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Kamil Debski, <k.debski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
+#include <linux/workqueue.h>
+#include <media/videobuf2-core.h>
+#include "regs-mfc.h"
+#include "s5p_mfc_ctrl.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_dec.h"
+#include "s5p_mfc_enc.h"
+#include "s5p_mfc_intr.h"
+#include "s5p_mfc_opr.h"
+#include "s5p_mfc_pm.h"
+#include "s5p_mfc_shm.h"
+
+#define S5P_MFC_NAME           "s5p-mfc"
+#define S5P_MFC_DEC_NAME       "s5p-mfc-dec"
+#define S5P_MFC_ENC_NAME       "s5p-mfc-enc"
+
+int debug;
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug level - higher value produces more verbose messages");
+
+/* Helper functions for interrupt processing */
+/* Remove from hw execution round robin */
+static void clear_work_bit(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       spin_lock(&dev->condlock);
+       clear_bit(ctx->num, &dev->ctx_work_bits);
+       spin_unlock(&dev->condlock);
+}
+
+/* Wake up context wait_queue */
+static void wake_up_ctx(struct s5p_mfc_ctx *ctx, unsigned int reason,
+                       unsigned int err)
+{
+       ctx->int_cond = 1;
+       ctx->int_type = reason;
+       ctx->int_err = err;
+       wake_up(&ctx->queue);
+}
+
+/* Wake up device wait_queue */
+static void wake_up_dev(struct s5p_mfc_dev *dev, unsigned int reason,
+                       unsigned int err)
+{
+       dev->int_cond = 1;
+       dev->int_type = reason;
+       dev->int_err = err;
+       wake_up(&dev->queue);
+}
+
+void s5p_mfc_watchdog(unsigned long arg)
+{
+       struct s5p_mfc_dev *dev = (struct s5p_mfc_dev *)arg;
+
+       if (test_bit(0, &dev->hw_lock))
+               atomic_inc(&dev->watchdog_cnt);
+       if (atomic_read(&dev->watchdog_cnt) >= MFC_WATCHDOG_CNT) {
+               /* This means that hw is busy and no interrupts were
+                * generated by hw for the Nth time of running this
+                * watchdog timer. This usually means a serious hw
+                * error. Now it is time to kill all instances and
+                * reset the MFC. */
+               mfc_err("Time out during waiting for HW\n");
+               queue_work(dev->watchdog_workqueue, &dev->watchdog_work);
+       }
+       dev->watchdog_timer.expires = jiffies +
+                                       msecs_to_jiffies(MFC_WATCHDOG_INTERVAL);
+       add_timer(&dev->watchdog_timer);
+}
+
+static void s5p_mfc_watchdog_worker(struct work_struct *work)
+{
+       struct s5p_mfc_dev *dev;
+       struct s5p_mfc_ctx *ctx;
+       unsigned long flags;
+       int mutex_locked;
+       int i, ret;
+
+       dev = container_of(work, struct s5p_mfc_dev, watchdog_work);
+
+       mfc_err("Driver timeout error handling\n");
+       /* Lock the mutex that protects open and release.
+        * This is necessary as they may load and unload firmware. */
+       mutex_locked = mutex_trylock(&dev->mfc_mutex);
+       if (!mutex_locked)
+               mfc_err("Error: some instance may be closing/opening\n");
+       spin_lock_irqsave(&dev->irqlock, flags);
+
+       s5p_mfc_clock_off();
+
+       for (i = 0; i < MFC_NUM_CONTEXTS; i++) {
+               ctx = dev->ctx[i];
+               if (!ctx)
+                       continue;
+               ctx->state = MFCINST_ERROR;
+               s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
+               s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
+               clear_work_bit(ctx);
+               wake_up_ctx(ctx, S5P_FIMV_R2H_CMD_ERR_RET, 0);
+       }
+       clear_bit(0, &dev->hw_lock);
+       spin_unlock_irqrestore(&dev->irqlock, flags);
+       /* Double check if there is at least one instance running.
+        * If no instance is in memory than no firmware should be present */
+       if (dev->num_inst > 0) {
+               ret = s5p_mfc_reload_firmware(dev);
+               if (ret) {
+                       mfc_err("Failed to reload FW\n");
+                       goto unlock;
+               }
+               s5p_mfc_clock_on();
+               ret = s5p_mfc_init_hw(dev);
+               if (ret)
+                       mfc_err("Failed to reinit FW\n");
+       }
+unlock:
+       if (mutex_locked)
+               mutex_unlock(&dev->mfc_mutex);
+}
+
+static enum s5p_mfc_node_type s5p_mfc_get_node_type(struct file *file)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (!vdev) {
+               mfc_err("failed to get video_device");
+               return MFCNODE_INVALID;
+       }
+       if (vdev->index == 0)
+               return MFCNODE_DECODER;
+       else if (vdev->index == 1)
+               return MFCNODE_ENCODER;
+       return MFCNODE_INVALID;
+}
+
+static void s5p_mfc_clear_int_flags(struct s5p_mfc_dev *dev)
+{
+       mfc_write(dev, 0, S5P_FIMV_RISC_HOST_INT);
+       mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD);
+       mfc_write(dev, 0xffff, S5P_FIMV_SI_RTN_CHID);
+}
+
+static void s5p_mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_buf *dst_buf;
+
+       ctx->state = MFCINST_FINISHED;
+       ctx->sequence++;
+       while (!list_empty(&ctx->dst_queue)) {
+               dst_buf = list_entry(ctx->dst_queue.next,
+                                    struct s5p_mfc_buf, list);
+               mfc_debug(2, "Cleaning up buffer: %d\n",
+                                         dst_buf->b->v4l2_buf.index);
+               vb2_set_plane_payload(dst_buf->b, 0, 0);
+               vb2_set_plane_payload(dst_buf->b, 1, 0);
+               list_del(&dst_buf->list);
+               ctx->dst_queue_cnt--;
+               dst_buf->b->v4l2_buf.sequence = (ctx->sequence++);
+
+               if (s5p_mfc_read_shm(ctx, PIC_TIME_TOP) ==
+                       s5p_mfc_read_shm(ctx, PIC_TIME_BOT))
+                       dst_buf->b->v4l2_buf.field = V4L2_FIELD_NONE;
+               else
+                       dst_buf->b->v4l2_buf.field = V4L2_FIELD_INTERLACED;
+
+               ctx->dec_dst_flag &= ~(1 << dst_buf->b->v4l2_buf.index);
+               vb2_buffer_done(dst_buf->b, VB2_BUF_STATE_DONE);
+       }
+}
+
+static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_buf  *dst_buf, *src_buf;
+       size_t dec_y_addr = s5p_mfc_get_dec_y_adr();
+       unsigned int frame_type = s5p_mfc_get_frame_type();
+
+       /* Copy timestamp / timecode from decoded src to dst and set
+          appropraite flags */
+       src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+       list_for_each_entry(dst_buf, &ctx->dst_queue, list) {
+               if (vb2_dma_contig_plane_paddr(dst_buf->b, 0) == dec_y_addr) {
+                       memcpy(&dst_buf->b->v4l2_buf.timecode,
+                               &src_buf->b->v4l2_buf.timecode,
+                               sizeof(struct v4l2_timecode));
+                       memcpy(&dst_buf->b->v4l2_buf.timestamp,
+                               &src_buf->b->v4l2_buf.timestamp,
+                               sizeof(struct timeval));
+                       switch (frame_type) {
+                       case S5P_FIMV_DECODE_FRAME_I_FRAME:
+                               dst_buf->b->v4l2_buf.flags |=
+                                               V4L2_BUF_FLAG_KEYFRAME;
+                               break;
+                       case S5P_FIMV_DECODE_FRAME_P_FRAME:
+                               dst_buf->b->v4l2_buf.flags |=
+                                               V4L2_BUF_FLAG_PFRAME;
+                               break;
+                       case S5P_FIMV_DECODE_FRAME_B_FRAME:
+                               dst_buf->b->v4l2_buf.flags |=
+                                               V4L2_BUF_FLAG_BFRAME;
+                               break;
+                       }
+                       break;
+               }
+       }
+}
+
+static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_buf  *dst_buf;
+       size_t dspl_y_addr = s5p_mfc_get_dspl_y_adr();
+       unsigned int frame_type = s5p_mfc_get_frame_type();
+       unsigned int index;
+
+       /* If frame is same as previous then skip and do not dequeue */
+       if (frame_type == S5P_FIMV_DECODE_FRAME_SKIPPED) {
+               if (!ctx->after_packed_pb)
+                       ctx->sequence++;
+               ctx->after_packed_pb = 0;
+               return;
+       }
+       ctx->sequence++;
+       /* The MFC returns address of the buffer, now we have to
+        * check which videobuf does it correspond to */
+       list_for_each_entry(dst_buf, &ctx->dst_queue, list) {
+               /* Check if this is the buffer we're looking for */
+               if (vb2_dma_contig_plane_paddr(dst_buf->b, 0) == dspl_y_addr) {
+                       list_del(&dst_buf->list);
+                       ctx->dst_queue_cnt--;
+                       dst_buf->b->v4l2_buf.sequence = ctx->sequence;
+                       if (s5p_mfc_read_shm(ctx, PIC_TIME_TOP) ==
+                               s5p_mfc_read_shm(ctx, PIC_TIME_BOT))
+                               dst_buf->b->v4l2_buf.field = V4L2_FIELD_NONE;
+                       else
+                               dst_buf->b->v4l2_buf.field =
+                                                       V4L2_FIELD_INTERLACED;
+                       vb2_set_plane_payload(dst_buf->b, 0, ctx->luma_size);
+                       vb2_set_plane_payload(dst_buf->b, 1, ctx->chroma_size);
+                       clear_bit(dst_buf->b->v4l2_buf.index,
+                                                       &ctx->dec_dst_flag);
+
+                       vb2_buffer_done(dst_buf->b,
+                               err ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+
+                       index = dst_buf->b->v4l2_buf.index;
+                       break;
+               }
+       }
+}
+
+/* Handle frame decoding interrupt */
+static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
+                                       unsigned int reason, unsigned int err)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned int dst_frame_status;
+       struct s5p_mfc_buf *src_buf;
+       unsigned long flags;
+       unsigned int res_change;
+
+       unsigned int index;
+
+       dst_frame_status = s5p_mfc_get_dspl_status()
+                               & S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK;
+       res_change = s5p_mfc_get_dspl_status()
+                               & S5P_FIMV_DEC_STATUS_RESOLUTION_MASK;
+       mfc_debug(2, "Frame Status: %x\n", dst_frame_status);
+       if (ctx->state == MFCINST_RES_CHANGE_INIT)
+               ctx->state = MFCINST_RES_CHANGE_FLUSH;
+       if (res_change) {
+               ctx->state = MFCINST_RES_CHANGE_INIT;
+               s5p_mfc_clear_int_flags(dev);
+               wake_up_ctx(ctx, reason, err);
+               if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+                       BUG();
+               s5p_mfc_clock_off();
+               s5p_mfc_try_run(dev);
+               return;
+       }
+       if (ctx->dpb_flush_flag)
+               ctx->dpb_flush_flag = 0;
+
+       spin_lock_irqsave(&dev->irqlock, flags);
+       /* All frames remaining in the buffer have been extracted  */
+       if (dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_EMPTY) {
+               if (ctx->state == MFCINST_RES_CHANGE_FLUSH) {
+                       s5p_mfc_handle_frame_all_extracted(ctx);
+                       ctx->state = MFCINST_RES_CHANGE_END;
+                       goto leave_handle_frame;
+               } else {
+                       s5p_mfc_handle_frame_all_extracted(ctx);
+               }
+       }
+
+       if (dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_DISPLAY ||
+               dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_ONLY)
+               s5p_mfc_handle_frame_copy_time(ctx);
+
+       /* A frame has been decoded and is in the buffer  */
+       if (dst_frame_status == S5P_FIMV_DEC_STATUS_DISPLAY_ONLY ||
+           dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_DISPLAY) {
+               s5p_mfc_handle_frame_new(ctx, err);
+       } else {
+               mfc_debug(2, "No frame decode\n");
+       }
+       /* Mark source buffer as complete */
+       if (dst_frame_status != S5P_FIMV_DEC_STATUS_DISPLAY_ONLY
+               && !list_empty(&ctx->src_queue)) {
+               src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf,
+                                                               list);
+               ctx->consumed_stream += s5p_mfc_get_consumed_stream();
+               if (ctx->codec_mode != S5P_FIMV_CODEC_H264_DEC &&
+                       s5p_mfc_get_frame_type() == S5P_FIMV_DECODE_FRAME_P_FRAME
+                                       && ctx->consumed_stream + STUFF_BYTE <
+                                       src_buf->b->v4l2_planes[0].bytesused) {
+                       /* Run MFC again on the same buffer */
+                       mfc_debug(2, "Running again the same buffer\n");
+                       ctx->after_packed_pb = 1;
+               } else {
+                       index = src_buf->b->v4l2_buf.index;
+                       mfc_debug(2, "MFC needs next buffer\n");
+                       ctx->consumed_stream = 0;
+                       list_del(&src_buf->list);
+                       ctx->src_queue_cnt--;
+                       if (s5p_mfc_err_dec(err) > 0)
+                               vb2_buffer_done(src_buf->b, VB2_BUF_STATE_ERROR);
+                       else
+                               vb2_buffer_done(src_buf->b, VB2_BUF_STATE_DONE);
+               }
+       }
+leave_handle_frame:
+       spin_unlock_irqrestore(&dev->irqlock, flags);
+       if ((ctx->src_queue_cnt == 0 && ctx->state != MFCINST_FINISHING)
+                                   || ctx->dst_queue_cnt < ctx->dpb_count)
+               clear_work_bit(ctx);
+       s5p_mfc_clear_int_flags(dev);
+       wake_up_ctx(ctx, reason, err);
+       if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+               BUG();
+       s5p_mfc_clock_off();
+       s5p_mfc_try_run(dev);
+}
+
+/* Error handling for interrupt */
+static void s5p_mfc_handle_error(struct s5p_mfc_ctx *ctx,
+                                unsigned int reason, unsigned int err)
+{
+       struct s5p_mfc_dev *dev;
+       unsigned long flags;
+
+       /* If no context is available then all necessary
+        * processing has been done. */
+       if (ctx == 0)
+               return;
+
+       dev = ctx->dev;
+       mfc_err("Interrupt Error: %08x\n", err);
+       s5p_mfc_clear_int_flags(dev);
+       wake_up_dev(dev, reason, err);
+
+       /* Error recovery is dependent on the state of context */
+       switch (ctx->state) {
+       case MFCINST_INIT:
+               /* This error had to happen while acquireing instance */
+       case MFCINST_GOT_INST:
+               /* This error had to happen while parsing the header */
+       case MFCINST_HEAD_PARSED:
+               /* This error had to happen while setting dst buffers */
+       case MFCINST_RETURN_INST:
+               /* This error had to happen while releasing instance */
+               clear_work_bit(ctx);
+               wake_up_ctx(ctx, reason, err);
+               if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+                       BUG();
+               s5p_mfc_clock_off();
+               ctx->state = MFCINST_ERROR;
+               break;
+       case MFCINST_FINISHING:
+       case MFCINST_FINISHED:
+       case MFCINST_RUNNING:
+               /* It is higly probable that an error occured
+                * while decoding a frame */
+               clear_work_bit(ctx);
+               ctx->state = MFCINST_ERROR;
+               /* Mark all dst buffers as having an error */
+               spin_lock_irqsave(&dev->irqlock, flags);
+               s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
+               /* Mark all src buffers as having an error */
+               s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
+               spin_unlock_irqrestore(&dev->irqlock, flags);
+               if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+                       BUG();
+               s5p_mfc_clock_off();
+               break;
+       default:
+               mfc_err("Encountered an error interrupt which had not been handled\n");
+               break;
+       }
+       return;
+}
+
+/* Header parsing interrupt handling */
+static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx,
+                                unsigned int reason, unsigned int err)
+{
+       struct s5p_mfc_dev *dev;
+       unsigned int guard_width, guard_height;
+
+       if (ctx == 0)
+               return;
+       dev = ctx->dev;
+       if (ctx->c_ops->post_seq_start) {
+               if (ctx->c_ops->post_seq_start(ctx))
+                       mfc_err("post_seq_start() failed\n");
+       } else {
+               ctx->img_width = s5p_mfc_get_img_width();
+               ctx->img_height = s5p_mfc_get_img_height();
+
+               ctx->buf_width = ALIGN(ctx->img_width,
+                                               S5P_FIMV_NV12MT_HALIGN);
+               ctx->buf_height = ALIGN(ctx->img_height,
+                                               S5P_FIMV_NV12MT_VALIGN);
+               mfc_debug(2, "SEQ Done: Movie dimensions %dx%d, "
+                       "buffer dimensions: %dx%d\n", ctx->img_width,
+                               ctx->img_height, ctx->buf_width,
+                                               ctx->buf_height);
+               if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) {
+                       ctx->luma_size = ALIGN(ctx->buf_width *
+                               ctx->buf_height, S5P_FIMV_DEC_BUF_ALIGN);
+                       ctx->chroma_size = ALIGN(ctx->buf_width *
+                                        ALIGN((ctx->img_height >> 1),
+                                              S5P_FIMV_NV12MT_VALIGN),
+                                              S5P_FIMV_DEC_BUF_ALIGN);
+                       ctx->mv_size = ALIGN(ctx->buf_width *
+                                       ALIGN((ctx->buf_height >> 2),
+                                       S5P_FIMV_NV12MT_VALIGN),
+                                       S5P_FIMV_DEC_BUF_ALIGN);
+               } else {
+                       guard_width = ALIGN(ctx->img_width + 24,
+                                       S5P_FIMV_NV12MT_HALIGN);
+                       guard_height = ALIGN(ctx->img_height + 16,
+                                               S5P_FIMV_NV12MT_VALIGN);
+                       ctx->luma_size = ALIGN(guard_width *
+                               guard_height, S5P_FIMV_DEC_BUF_ALIGN);
+                       guard_width = ALIGN(ctx->img_width + 16,
+                                               S5P_FIMV_NV12MT_HALIGN);
+                       guard_height = ALIGN((ctx->img_height >> 1) + 4,
+                                               S5P_FIMV_NV12MT_VALIGN);
+                       ctx->chroma_size = ALIGN(guard_width *
+                               guard_height, S5P_FIMV_DEC_BUF_ALIGN);
+                       ctx->mv_size = 0;
+               }
+               ctx->dpb_count = s5p_mfc_get_dpb_count();
+               if (ctx->img_width == 0 || ctx->img_width == 0)
+                       ctx->state = MFCINST_ERROR;
+               else
+                       ctx->state = MFCINST_HEAD_PARSED;
+       }
+       s5p_mfc_clear_int_flags(dev);
+       clear_work_bit(ctx);
+       if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+               BUG();
+       s5p_mfc_clock_off();
+       s5p_mfc_try_run(dev);
+       wake_up_ctx(ctx, reason, err);
+}
+
+/* Header parsing interrupt handling */
+static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx,
+                                unsigned int reason, unsigned int err)
+{
+       struct s5p_mfc_buf *src_buf;
+       struct s5p_mfc_dev *dev;
+       unsigned long flags;
+
+       if (ctx == 0)
+               return;
+       dev = ctx->dev;
+       s5p_mfc_clear_int_flags(dev);
+       ctx->int_type = reason;
+       ctx->int_err = err;
+       ctx->int_cond = 1;
+       spin_lock(&dev->condlock);
+       clear_bit(ctx->num, &dev->ctx_work_bits);
+       spin_unlock(&dev->condlock);
+       if (err == 0) {
+               ctx->state = MFCINST_RUNNING;
+               if (!ctx->dpb_flush_flag) {
+                       spin_lock_irqsave(&dev->irqlock, flags);
+                       if (!list_empty(&ctx->src_queue)) {
+                               src_buf = list_entry(ctx->src_queue.next,
+                                            struct s5p_mfc_buf, list);
+                               list_del(&src_buf->list);
+                               ctx->src_queue_cnt--;
+                               vb2_buffer_done(src_buf->b,
+                                               VB2_BUF_STATE_DONE);
+                       }
+                       spin_unlock_irqrestore(&dev->irqlock, flags);
+               } else {
+                       ctx->dpb_flush_flag = 0;
+               }
+               if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+                       BUG();
+
+               s5p_mfc_clock_off();
+
+               wake_up(&ctx->queue);
+               s5p_mfc_try_run(dev);
+       } else {
+               if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+                       BUG();
+
+               s5p_mfc_clock_off();
+
+               wake_up(&ctx->queue);
+       }
+}
+
+/* Interrupt processing */
+static irqreturn_t s5p_mfc_irq(int irq, void *priv)
+{
+       struct s5p_mfc_dev *dev = priv;
+       struct s5p_mfc_ctx *ctx;
+       unsigned int reason;
+       unsigned int err;
+
+       mfc_debug_enter();
+       /* Reset the timeout watchdog */
+       atomic_set(&dev->watchdog_cnt, 0);
+       ctx = dev->ctx[dev->curr_ctx];
+       /* Get the reason of interrupt and the error code */
+       reason = s5p_mfc_get_int_reason();
+       err = s5p_mfc_get_int_err();
+       mfc_debug(1, "Int reason: %d (err: %08x)\n", reason, err);
+       switch (reason) {
+       case S5P_FIMV_R2H_CMD_ERR_RET:
+               /* An error has occured */
+               if (ctx->state == MFCINST_RUNNING &&
+                       s5p_mfc_err_dec(err) >= S5P_FIMV_ERR_WARNINGS_START)
+                       s5p_mfc_handle_frame(ctx, reason, err);
+               else
+                       s5p_mfc_handle_error(ctx, reason, err);
+               clear_bit(0, &dev->enter_suspend);
+               break;
+
+       case S5P_FIMV_R2H_CMD_SLICE_DONE_RET:
+       case S5P_FIMV_R2H_CMD_FRAME_DONE_RET:
+               if (ctx->c_ops->post_frame_start) {
+                       if (ctx->c_ops->post_frame_start(ctx))
+                               mfc_err("post_frame_start() failed\n");
+                       s5p_mfc_clear_int_flags(dev);
+                       wake_up_ctx(ctx, reason, err);
+                       if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+                               BUG();
+                       s5p_mfc_clock_off();
+                       s5p_mfc_try_run(dev);
+               } else {
+                       s5p_mfc_handle_frame(ctx, reason, err);
+               }
+               break;
+
+       case S5P_FIMV_R2H_CMD_SEQ_DONE_RET:
+               s5p_mfc_handle_seq_done(ctx, reason, err);
+               break;
+
+       case S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET:
+               ctx->inst_no = s5p_mfc_get_inst_no();
+               ctx->state = MFCINST_GOT_INST;
+               clear_work_bit(ctx);
+               wake_up(&ctx->queue);
+               goto irq_cleanup_hw;
+
+       case S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET:
+               clear_work_bit(ctx);
+               ctx->state = MFCINST_FREE;
+               wake_up(&ctx->queue);
+               goto irq_cleanup_hw;
+
+       case S5P_FIMV_R2H_CMD_SYS_INIT_RET:
+       case S5P_FIMV_R2H_CMD_FW_STATUS_RET:
+       case S5P_FIMV_R2H_CMD_SLEEP_RET:
+       case S5P_FIMV_R2H_CMD_WAKEUP_RET:
+               if (ctx)
+                       clear_work_bit(ctx);
+               s5p_mfc_clear_int_flags(dev);
+               wake_up_dev(dev, reason, err);
+               clear_bit(0, &dev->hw_lock);
+               clear_bit(0, &dev->enter_suspend);
+               break;
+
+       case S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET:
+               s5p_mfc_handle_init_buffers(ctx, reason, err);
+               break;
+       default:
+               mfc_debug(2, "Unknown int reason\n");
+               s5p_mfc_clear_int_flags(dev);
+       }
+       mfc_debug_leave();
+       return IRQ_HANDLED;
+irq_cleanup_hw:
+       s5p_mfc_clear_int_flags(dev);
+       ctx->int_type = reason;
+       ctx->int_err = err;
+       ctx->int_cond = 1;
+       if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+               mfc_err("Failed to unlock hw\n");
+
+       s5p_mfc_clock_off();
+
+       s5p_mfc_try_run(dev);
+       mfc_debug(2, "Exit via irq_cleanup_hw\n");
+       return IRQ_HANDLED;
+}
+
+/* Open an MFC node */
+static int s5p_mfc_open(struct file *file)
+{
+       struct s5p_mfc_dev *dev = video_drvdata(file);
+       struct s5p_mfc_ctx *ctx = NULL;
+       struct vb2_queue *q;
+       unsigned long flags;
+       int ret = 0;
+
+       mfc_debug_enter();
+       dev->num_inst++;        /* It is guarded by mfc_mutex in vfd */
+       /* Allocate memory for context */
+       ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+       if (!ctx) {
+               mfc_err("Not enough memory\n");
+               ret = -ENOMEM;
+               goto err_alloc;
+       }
+       v4l2_fh_init(&ctx->fh, video_devdata(file));
+       file->private_data = &ctx->fh;
+       v4l2_fh_add(&ctx->fh);
+       ctx->dev = dev;
+       INIT_LIST_HEAD(&ctx->src_queue);
+       INIT_LIST_HEAD(&ctx->dst_queue);
+       ctx->src_queue_cnt = 0;
+       ctx->dst_queue_cnt = 0;
+       /* Get context number */
+       ctx->num = 0;
+       while (dev->ctx[ctx->num]) {
+               ctx->num++;
+               if (ctx->num >= MFC_NUM_CONTEXTS) {
+                       mfc_err("Too many open contexts\n");
+                       ret = -EBUSY;
+                       goto err_no_ctx;
+               }
+       }
+       /* Mark context as idle */
+       spin_lock_irqsave(&dev->condlock, flags);
+       clear_bit(ctx->num, &dev->ctx_work_bits);
+       spin_unlock_irqrestore(&dev->condlock, flags);
+       dev->ctx[ctx->num] = ctx;
+       if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) {
+               ctx->type = MFCINST_DECODER;
+               ctx->c_ops = get_dec_codec_ops();
+               /* Setup ctrl handler */
+               ret = s5p_mfc_dec_ctrls_setup(ctx);
+               if (ret) {
+                       mfc_err("Failed to setup mfc controls\n");
+                       goto err_ctrls_setup;
+               }
+       } else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) {
+               ctx->type = MFCINST_ENCODER;
+               ctx->c_ops = get_enc_codec_ops();
+               /* only for encoder */
+               INIT_LIST_HEAD(&ctx->ref_queue);
+               ctx->ref_queue_cnt = 0;
+               /* Setup ctrl handler */
+               ret = s5p_mfc_enc_ctrls_setup(ctx);
+               if (ret) {
+                       mfc_err("Failed to setup mfc controls\n");
+                       goto err_ctrls_setup;
+               }
+       } else {
+               ret = -ENOENT;
+               goto err_bad_node;
+       }
+       ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+       ctx->inst_no = -1;
+       /* Load firmware if this is the first instance */
+       if (dev->num_inst == 1) {
+               dev->watchdog_timer.expires = jiffies +
+                                       msecs_to_jiffies(MFC_WATCHDOG_INTERVAL);
+               add_timer(&dev->watchdog_timer);
+               ret = s5p_mfc_power_on();
+               if (ret < 0) {
+                       mfc_err("power on failed\n");
+                       goto err_pwr_enable;
+               }
+               s5p_mfc_clock_on();
+               ret = s5p_mfc_alloc_and_load_firmware(dev);
+               if (ret)
+                       goto err_alloc_fw;
+               /* Init the FW */
+               ret = s5p_mfc_init_hw(dev);
+               if (ret)
+                       goto err_init_hw;
+               s5p_mfc_clock_off();
+       }
+       /* Init videobuf2 queue for CAPTURE */
+       q = &ctx->vq_dst;
+       q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+       q->drv_priv = &ctx->fh;
+       if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) {
+               q->io_modes = VB2_MMAP;
+               q->ops = get_dec_queue_ops();
+       } else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) {
+               q->io_modes = VB2_MMAP | VB2_USERPTR;
+               q->ops = get_enc_queue_ops();
+       } else {
+               ret = -ENOENT;
+               goto err_queue_init;
+       }
+       q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops;
+       ret = vb2_queue_init(q);
+       if (ret) {
+               mfc_err("Failed to initialize videobuf2 queue(capture)\n");
+               goto err_queue_init;
+       }
+       /* Init videobuf2 queue for OUTPUT */
+       q = &ctx->vq_src;
+       q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+       q->io_modes = VB2_MMAP;
+       q->drv_priv = &ctx->fh;
+       if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) {
+               q->io_modes = VB2_MMAP;
+               q->ops = get_dec_queue_ops();
+       } else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) {
+               q->io_modes = VB2_MMAP | VB2_USERPTR;
+               q->ops = get_enc_queue_ops();
+       } else {
+               ret = -ENOENT;
+               goto err_queue_init;
+       }
+       q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops;
+       ret = vb2_queue_init(q);
+       if (ret) {
+               mfc_err("Failed to initialize videobuf2 queue(output)\n");
+               goto err_queue_init;
+       }
+       init_waitqueue_head(&ctx->queue);
+       mfc_debug_leave();
+       return ret;
+       /* Deinit when failure occured */
+err_queue_init:
+err_init_hw:
+       s5p_mfc_release_firmware(dev);
+err_alloc_fw:
+       dev->ctx[ctx->num] = 0;
+       del_timer_sync(&dev->watchdog_timer);
+       s5p_mfc_clock_off();
+err_pwr_enable:
+       if (dev->num_inst == 1) {
+               if (s5p_mfc_power_off() < 0)
+                       mfc_err("power off failed\n");
+               s5p_mfc_release_firmware(dev);
+       }
+err_ctrls_setup:
+       s5p_mfc_dec_ctrls_delete(ctx);
+err_bad_node:
+err_no_ctx:
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
+       kfree(ctx);
+err_alloc:
+       dev->num_inst--;
+       mfc_debug_leave();
+       return ret;
+}
+
+/* Release MFC context */
+static int s5p_mfc_release(struct file *file)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data);
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned long flags;
+
+       mfc_debug_enter();
+       s5p_mfc_clock_on();
+       vb2_queue_release(&ctx->vq_src);
+       vb2_queue_release(&ctx->vq_dst);
+       /* Mark context as idle */
+       spin_lock_irqsave(&dev->condlock, flags);
+       clear_bit(ctx->num, &dev->ctx_work_bits);
+       spin_unlock_irqrestore(&dev->condlock, flags);
+       /* If instance was initialised then
+        * return instance and free reosurces */
+       if (ctx->inst_no != MFC_NO_INSTANCE_SET) {
+               mfc_debug(2, "Has to free instance\n");
+               ctx->state = MFCINST_RETURN_INST;
+               spin_lock_irqsave(&dev->condlock, flags);
+               set_bit(ctx->num, &dev->ctx_work_bits);
+               spin_unlock_irqrestore(&dev->condlock, flags);
+               s5p_mfc_clean_ctx_int_flags(ctx);
+               s5p_mfc_try_run(dev);
+               /* Wait until instance is returned or timeout occured */
+               if (s5p_mfc_wait_for_done_ctx
+                   (ctx, S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET, 0)) {
+                       s5p_mfc_clock_off();
+                       mfc_err("Err returning instance\n");
+               }
+               mfc_debug(2, "After free instance\n");
+               /* Free resources */
+               s5p_mfc_release_codec_buffers(ctx);
+               s5p_mfc_release_instance_buffer(ctx);
+               if (ctx->type == MFCINST_DECODER)
+                       s5p_mfc_release_dec_desc_buffer(ctx);
+
+               ctx->inst_no = MFC_NO_INSTANCE_SET;
+       }
+       /* hardware locking scheme */
+       if (dev->curr_ctx == ctx->num)
+               clear_bit(0, &dev->hw_lock);
+       dev->num_inst--;
+       if (dev->num_inst == 0) {
+               mfc_debug(2, "Last instance - release firmware\n");
+               /* reset <-> F/W release */
+               s5p_mfc_reset(dev);
+               s5p_mfc_release_firmware(dev);
+               del_timer_sync(&dev->watchdog_timer);
+               if (s5p_mfc_power_off() < 0)
+                       mfc_err("Power off failed\n");
+       }
+       mfc_debug(2, "Shutting down clock\n");
+       s5p_mfc_clock_off();
+       dev->ctx[ctx->num] = 0;
+       s5p_mfc_dec_ctrls_delete(ctx);
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
+       kfree(ctx);
+       mfc_debug_leave();
+       return 0;
+}
+
+/* Poll */
+static unsigned int s5p_mfc_poll(struct file *file,
+                                struct poll_table_struct *wait)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data);
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct vb2_queue *src_q, *dst_q;
+       struct vb2_buffer *src_vb = NULL, *dst_vb = NULL;
+       unsigned int rc = 0;
+       unsigned long flags;
+
+       src_q = &ctx->vq_src;
+       dst_q = &ctx->vq_dst;
+       /*
+        * There has to be at least one buffer queued on each queued_list, which
+        * means either in driver already or waiting for driver to claim it
+        * and start processing.
+        */
+       if ((!src_q->streaming || list_empty(&src_q->queued_list))
+               && (!dst_q->streaming || list_empty(&dst_q->queued_list))) {
+               rc = POLLERR;
+               goto end;
+       }
+       mutex_unlock(&dev->mfc_mutex);
+       poll_wait(file, &src_q->done_wq, wait);
+       poll_wait(file, &dst_q->done_wq, wait);
+       mutex_lock(&dev->mfc_mutex);
+       spin_lock_irqsave(&src_q->done_lock, flags);
+       if (!list_empty(&src_q->done_list))
+               src_vb = list_first_entry(&src_q->done_list, struct vb2_buffer,
+                                                               done_entry);
+       if (src_vb && (src_vb->state == VB2_BUF_STATE_DONE
+                               || src_vb->state == VB2_BUF_STATE_ERROR))
+               rc |= POLLOUT | POLLWRNORM;
+       spin_unlock_irqrestore(&src_q->done_lock, flags);
+       spin_lock_irqsave(&dst_q->done_lock, flags);
+       if (!list_empty(&dst_q->done_list))
+               dst_vb = list_first_entry(&dst_q->done_list, struct vb2_buffer,
+                                                               done_entry);
+       if (dst_vb && (dst_vb->state == VB2_BUF_STATE_DONE
+                               || dst_vb->state == VB2_BUF_STATE_ERROR))
+               rc |= POLLIN | POLLRDNORM;
+       spin_unlock_irqrestore(&dst_q->done_lock, flags);
+end:
+       return rc;
+}
+
+/* Mmap */
+static int s5p_mfc_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data);
+       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+       int ret;
+       if (offset < DST_QUEUE_OFF_BASE) {
+               mfc_debug(2, "mmaping source\n");
+               ret = vb2_mmap(&ctx->vq_src, vma);
+       } else {                /* capture */
+               mfc_debug(2, "mmaping destination\n");
+               vma->vm_pgoff -= (DST_QUEUE_OFF_BASE >> PAGE_SHIFT);
+               ret = vb2_mmap(&ctx->vq_dst, vma);
+       }
+       return ret;
+}
+
+/* v4l2 ops */
+static const struct v4l2_file_operations s5p_mfc_fops = {
+       .owner = THIS_MODULE,
+       .open = s5p_mfc_open,
+       .release = s5p_mfc_release,
+       .poll = s5p_mfc_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap = s5p_mfc_mmap,
+};
+
+static int match_child(struct device *dev, void *data)
+{
+       if (!dev_name(dev))
+               return 0;
+       return !strcmp(dev_name(dev), (char *)data);
+}
+
+
+/* MFC probe function */
+static int __devinit s5p_mfc_probe(struct platform_device *pdev)
+{
+       struct s5p_mfc_dev *dev;
+       struct video_device *vfd;
+       struct resource *res;
+       int ret;
+
+       pr_debug("%s++\n", __func__);
+       dev = kzalloc(sizeof *dev, GFP_KERNEL);
+       if (!dev) {
+               dev_err(&pdev->dev, "Not enough memory for MFC device\n");
+               return -ENOMEM;
+       }
+
+       spin_lock_init(&dev->irqlock);
+       spin_lock_init(&dev->condlock);
+       dev->plat_dev = pdev;
+       if (!dev->plat_dev) {
+               dev_err(&pdev->dev, "No platform data specified\n");
+               ret = -ENODEV;
+               goto err_dev;
+       }
+
+       ret = s5p_mfc_init_pm(dev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to get mfc clock source\n");
+               goto err_clk;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "failed to get memory region resource\n");
+               ret = -ENOENT;
+               goto err_res;
+       }
+
+       dev->mfc_mem = request_mem_region(res->start, resource_size(res),
+                                         pdev->name);
+       if (dev->mfc_mem == NULL) {
+               dev_err(&pdev->dev, "failed to get memory region\n");
+               ret = -ENOENT;
+               goto err_mem_reg;
+       }
+       dev->regs_base = ioremap(dev->mfc_mem->start, resource_size(dev->mfc_mem));
+       if (dev->regs_base == NULL) {
+               dev_err(&pdev->dev, "failed to ioremap address region\n");
+               ret = -ENOENT;
+               goto err_ioremap;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "failed to get irq resource\n");
+               ret = -ENOENT;
+               goto err_get_res;
+       }
+       dev->irq = res->start;
+       ret = request_irq(dev->irq, s5p_mfc_irq, IRQF_DISABLED, pdev->name,
+                                                                       dev);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to install irq (%d)\n", ret);
+               goto err_req_irq;
+       }
+
+       dev->mem_dev_l = device_find_child(&dev->plat_dev->dev, "s5p-mfc-l",
+                                          match_child);
+       if (!dev->mem_dev_l) {
+               mfc_err("Mem child (L) device get failed\n");
+               ret = -ENODEV;
+               goto err_find_child;
+       }
+       dev->mem_dev_r = device_find_child(&dev->plat_dev->dev, "s5p-mfc-r",
+                                          match_child);
+       if (!dev->mem_dev_r) {
+               mfc_err("Mem child (R) device get failed\n");
+               ret = -ENODEV;
+               goto err_find_child;
+       }
+
+       dev->alloc_ctx[0] = vb2_dma_contig_init_ctx(dev->mem_dev_l);
+       if (IS_ERR_OR_NULL(dev->alloc_ctx[0])) {
+               ret = PTR_ERR(dev->alloc_ctx[0]);
+               goto err_mem_init_ctx_0;
+       }
+       dev->alloc_ctx[1] = vb2_dma_contig_init_ctx(dev->mem_dev_r);
+       if (IS_ERR_OR_NULL(dev->alloc_ctx[1])) {
+               ret = PTR_ERR(dev->alloc_ctx[1]);
+               goto err_mem_init_ctx_1;
+       }
+
+       mutex_init(&dev->mfc_mutex);
+
+       ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+       if (ret)
+               goto err_v4l2_dev_reg;
+       init_waitqueue_head(&dev->queue);
+
+       /* decoder */
+       vfd = video_device_alloc();
+       if (!vfd) {
+               v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
+               ret = -ENOMEM;
+               goto err_dec_alloc;
+       }
+       vfd->fops       = &s5p_mfc_fops,
+       vfd->ioctl_ops  = get_dec_v4l2_ioctl_ops();
+       vfd->release    = video_device_release,
+       vfd->lock       = &dev->mfc_mutex;
+       vfd->v4l2_dev   = &dev->v4l2_dev;
+       snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_DEC_NAME);
+       dev->vfd_dec    = vfd;
+       ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+       if (ret) {
+               v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+               video_device_release(vfd);
+               goto err_dec_reg;
+       }
+       v4l2_info(&dev->v4l2_dev,
+                 "decoder registered as /dev/video%d\n", vfd->num);
+       video_set_drvdata(vfd, dev);
+
+       /* encoder */
+       vfd = video_device_alloc();
+       if (!vfd) {
+               v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
+               ret = -ENOMEM;
+               goto err_enc_alloc;
+       }
+       vfd->fops       = &s5p_mfc_fops,
+       vfd->ioctl_ops  = get_enc_v4l2_ioctl_ops();
+       vfd->release    = video_device_release,
+       vfd->lock       = &dev->mfc_mutex;
+       vfd->v4l2_dev   = &dev->v4l2_dev;
+       snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_ENC_NAME);
+       dev->vfd_enc    = vfd;
+       ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+       if (ret) {
+               v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+               video_device_release(vfd);
+               goto err_enc_reg;
+       }
+       v4l2_info(&dev->v4l2_dev,
+                 "encoder registered as /dev/video%d\n", vfd->num);
+       video_set_drvdata(vfd, dev);
+       platform_set_drvdata(pdev, dev);
+
+       dev->hw_lock = 0;
+       dev->watchdog_workqueue = create_singlethread_workqueue(S5P_MFC_NAME);
+       INIT_WORK(&dev->watchdog_work, s5p_mfc_watchdog_worker);
+       atomic_set(&dev->watchdog_cnt, 0);
+       init_timer(&dev->watchdog_timer);
+       dev->watchdog_timer.data = (unsigned long)dev;
+       dev->watchdog_timer.function = s5p_mfc_watchdog;
+
+       pr_debug("%s--\n", __func__);
+       return 0;
+
+/* Deinit MFC if probe had failed */
+err_enc_reg:
+       video_device_release(dev->vfd_enc);
+err_enc_alloc:
+       video_unregister_device(dev->vfd_dec);
+err_dec_reg:
+       video_device_release(dev->vfd_dec);
+err_dec_alloc:
+       v4l2_device_unregister(&dev->v4l2_dev);
+err_v4l2_dev_reg:
+       vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[1]);
+err_mem_init_ctx_1:
+       vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[0]);
+err_mem_init_ctx_0:
+err_find_child:
+       free_irq(dev->irq, dev);
+err_req_irq:
+err_get_res:
+       iounmap(dev->regs_base);
+       dev->regs_base = NULL;
+err_ioremap:
+       release_resource(dev->mfc_mem);
+       kfree(dev->mfc_mem);
+err_mem_reg:
+err_res:
+       s5p_mfc_final_pm(dev);
+err_clk:
+err_dev:
+       kfree(dev);
+       pr_debug("%s-- with error\n", __func__);
+       return ret;
+
+}
+
+/* Remove the driver */
+static int __devexit s5p_mfc_remove(struct platform_device *pdev)
+{
+       struct s5p_mfc_dev *dev = platform_get_drvdata(pdev);
+
+       v4l2_info(&dev->v4l2_dev, "Removing %s\n", pdev->name);
+
+       del_timer_sync(&dev->watchdog_timer);
+       flush_workqueue(dev->watchdog_workqueue);
+       destroy_workqueue(dev->watchdog_workqueue);
+
+       video_unregister_device(dev->vfd_enc);
+       video_unregister_device(dev->vfd_dec);
+       v4l2_device_unregister(&dev->v4l2_dev);
+       vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[0]);
+       vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[1]);
+
+       free_irq(dev->irq, dev);
+       iounmap(dev->regs_base);
+       if (dev->mfc_mem) {
+               release_resource(dev->mfc_mem);
+               kfree(dev->mfc_mem);
+               dev->mfc_mem = NULL;
+       }
+       s5p_mfc_final_pm(dev);
+       kfree(dev);
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int s5p_mfc_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev);
+       int ret;
+
+       if (m_dev->num_inst == 0)
+               return 0;
+       return s5p_mfc_sleep(m_dev);
+       if (test_and_set_bit(0, &m_dev->enter_suspend) != 0) {
+               mfc_err("Error: going to suspend for a second time\n");
+               return -EIO;
+       }
+
+       /* Check if we're processing then wait if it necessary. */
+       while (test_and_set_bit(0, &m_dev->hw_lock) != 0) {
+               /* Try and lock the HW */
+               /* Wait on the interrupt waitqueue */
+               ret = wait_event_interruptible_timeout(m_dev->queue,
+                       m_dev->int_cond || m_dev->ctx[m_dev->curr_ctx]->int_cond,
+                       msecs_to_jiffies(MFC_INT_TIMEOUT));
+
+               if (ret == 0) {
+                       mfc_err("Waiting for hardware to finish timed out\n");
+                       return -EIO;
+               }
+       }
+       return 0;
+}
+
+static int s5p_mfc_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev);
+
+       if (m_dev->num_inst == 0)
+               return 0;
+       return s5p_mfc_wakeup(m_dev);
+}
+#endif
+
+#ifdef CONFIG_PM_RUNTIME
+static int s5p_mfc_runtime_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev);
+
+       atomic_set(&m_dev->pm.power, 0);
+       return 0;
+}
+
+static int s5p_mfc_runtime_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev);
+       int pre_power;
+
+       if (!m_dev->alloc_ctx)
+               return 0;
+       pre_power = atomic_read(&m_dev->pm.power);
+       atomic_set(&m_dev->pm.power, 1);
+       return 0;
+}
+#endif
+
+/* Power management */
+static const struct dev_pm_ops s5p_mfc_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(s5p_mfc_suspend, s5p_mfc_resume)
+       SET_RUNTIME_PM_OPS(s5p_mfc_runtime_suspend, s5p_mfc_runtime_resume,
+                          NULL)
+};
+
+static struct platform_driver s5p_mfc_pdrv = {
+       .probe  = s5p_mfc_probe,
+       .remove = __devexit_p(s5p_mfc_remove),
+       .driver = {
+               .name   = S5P_MFC_NAME,
+               .owner  = THIS_MODULE,
+               .pm     = &s5p_mfc_pm_ops
+       },
+};
+
+static char banner[] __initdata =
+                       "S5P MFC V4L2 Driver, (C) 2011 Samsung Electronics\n";
+
+static int __init s5p_mfc_init(void)
+{
+       int ret;
+
+       pr_info("%s", banner);
+       ret = platform_driver_register(&s5p_mfc_pdrv);
+       if (ret)
+               pr_err("Platform device registration failed.\n");
+       return ret;
+}
+
+static void __devexit s5p_mfc_exit(void)
+{
+       platform_driver_unregister(&s5p_mfc_pdrv);
+}
+
+module_init(s5p_mfc_init);
+module_exit(s5p_mfc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
+MODULE_DESCRIPTION("Samsung S5P Multi Format Codec V4L2 driver");
+
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_cmd.c b/drivers/media/video/s5p-mfc/s5p_mfc_cmd.c
new file mode 100644 (file)
index 0000000..f0665ed
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * linux/drivers/media/video/s5p-mfc/s5p_mfc_cmd.c
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "regs-mfc.h"
+#include "s5p_mfc_cmd.h"
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+
+/* This function is used to send a command to the MFC */
+static int s5p_mfc_cmd_host2risc(struct s5p_mfc_dev *dev, int cmd,
+                                               struct s5p_mfc_cmd_args *args)
+{
+       int cur_cmd;
+       unsigned long timeout;
+
+       timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT);
+       /* wait until host to risc command register becomes 'H2R_CMD_EMPTY' */
+       do {
+               if (time_after(jiffies, timeout)) {
+                       mfc_err("Timeout while waiting for hardware\n");
+                       return -EIO;
+               }
+               cur_cmd = mfc_read(dev, S5P_FIMV_HOST2RISC_CMD);
+       } while (cur_cmd != S5P_FIMV_H2R_CMD_EMPTY);
+       mfc_write(dev, args->arg[0], S5P_FIMV_HOST2RISC_ARG1);
+       mfc_write(dev, args->arg[1], S5P_FIMV_HOST2RISC_ARG2);
+       mfc_write(dev, args->arg[2], S5P_FIMV_HOST2RISC_ARG3);
+       mfc_write(dev, args->arg[3], S5P_FIMV_HOST2RISC_ARG4);
+       /* Issue the command */
+       mfc_write(dev, cmd, S5P_FIMV_HOST2RISC_CMD);
+       return 0;
+}
+
+/* Initialize the MFC */
+int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev)
+{
+       struct s5p_mfc_cmd_args h2r_args;
+
+       memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
+       h2r_args.arg[0] = dev->fw_size;
+       return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SYS_INIT, &h2r_args);
+}
+
+/* Suspend the MFC hardware */
+int s5p_mfc_sleep_cmd(struct s5p_mfc_dev *dev)
+{
+       struct s5p_mfc_cmd_args h2r_args;
+
+       memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
+       return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SLEEP, &h2r_args);
+}
+
+/* Wake up the MFC hardware */
+int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev)
+{
+       struct s5p_mfc_cmd_args h2r_args;
+
+       memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
+       return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_WAKEUP, &h2r_args);
+}
+
+
+int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_cmd_args h2r_args;
+       int ret;
+
+       /* Preparing decoding - getting instance number */
+       mfc_debug(2, "Getting instance number (codec: %d)\n", ctx->codec_mode);
+       dev->curr_ctx = ctx->num;
+       memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
+       h2r_args.arg[0] = ctx->codec_mode;
+       h2r_args.arg[1] = 0; /* no crc & no pixelcache */
+       h2r_args.arg[2] = ctx->ctx_ofs;
+       h2r_args.arg[3] = ctx->ctx_size;
+       ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE,
+                                                               &h2r_args);
+       if (ret) {
+               mfc_err("Failed to create a new instance\n");
+               ctx->state = MFCINST_ERROR;
+       }
+       return ret;
+}
+
+int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_cmd_args h2r_args;
+       int ret;
+
+       if (ctx->state == MFCINST_FREE) {
+               mfc_err("Instance already returned\n");
+               ctx->state = MFCINST_ERROR;
+               return -EINVAL;
+       }
+       /* Closing decoding instance  */
+       mfc_debug(2, "Returning instance number %d\n", ctx->inst_no);
+       dev->curr_ctx = ctx->num;
+       memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
+       h2r_args.arg[0] = ctx->inst_no;
+       ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_CLOSE_INSTANCE,
+                                                               &h2r_args);
+       if (ret) {
+               mfc_err("Failed to return an instance\n");
+               ctx->state = MFCINST_ERROR;
+               return -EINVAL;
+       }
+       return 0;
+}
+
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_cmd.h b/drivers/media/video/s5p-mfc/s5p_mfc_cmd.h
new file mode 100644 (file)
index 0000000..5ceebfe
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * linux/drivers/media/video/s5p-mfc/s5p_mfc_cmd.h
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.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.
+ */
+
+#ifndef S5P_MFC_CMD_H_
+#define S5P_MFC_CMD_H_
+
+#include "s5p_mfc_common.h"
+
+#define MAX_H2R_ARG    4
+
+struct s5p_mfc_cmd_args {
+       unsigned int    arg[MAX_H2R_ARG];
+};
+
+int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev);
+int s5p_mfc_sleep_cmd(struct s5p_mfc_dev *dev);
+int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev);
+int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx);
+
+#endif /* S5P_MFC_CMD_H_ */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_common.h b/drivers/media/video/s5p-mfc/s5p_mfc_common.h
new file mode 100644 (file)
index 0000000..91146fa
--- /dev/null
@@ -0,0 +1,572 @@
+/*
+ * Samsung S5P Multi Format Codec v 5.0
+ *
+ * This file contains definitions of enums and structs used by the codec
+ * driver.
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Kamil Debski, <k.debski@samsung.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
+ */
+
+#ifndef S5P_MFC_COMMON_H_
+#define S5P_MFC_COMMON_H_
+
+#include "regs-mfc.h"
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+
+/* Definitions related to MFC memory */
+
+/* Offset base used to differentiate between CAPTURE and OUTPUT
+*  while mmaping */
+#define DST_QUEUE_OFF_BASE      (TASK_SIZE / 2)
+
+/* Offset used by the hardware to store addresses */
+#define MFC_OFFSET_SHIFT       11
+
+#define FIRMWARE_ALIGN         0x20000         /* 128KB */
+#define MFC_H264_CTX_BUF_SIZE  0x96000         /* 600KB per H264 instance */
+#define MFC_CTX_BUF_SIZE       0x2800          /* 10KB per instance */
+#define DESC_BUF_SIZE          0x20000         /* 128KB for DESC buffer */
+#define SHARED_BUF_SIZE                0x2000          /* 8KB for shared buffer */
+
+#define DEF_CPB_SIZE           0x40000         /* 512KB */
+
+#define MFC_BANK1_ALLOC_CTX    0
+#define MFC_BANK2_ALLOC_CTX    1
+
+#define MFC_BANK1_ALIGN_ORDER  13
+#define MFC_BANK2_ALIGN_ORDER  13
+#define MFC_BASE_ALIGN_ORDER   17
+
+#include <media/videobuf2-dma-contig.h>
+
+static inline dma_addr_t s5p_mfc_mem_cookie(void *a, void *b)
+{
+       /* Same functionality as the vb2_dma_contig_plane_paddr */
+       dma_addr_t *paddr = vb2_dma_contig_memops.cookie(b);
+
+       return *paddr;
+}
+
+/* MFC definitions */
+#define MFC_MAX_EXTRA_DPB       5
+#define MFC_MAX_BUFFERS                32
+#define MFC_NUM_CONTEXTS       4
+/* Interrupt timeout */
+#define MFC_INT_TIMEOUT                2000
+/* Busy wait timeout */
+#define MFC_BW_TIMEOUT         500
+/* Watchdog interval */
+#define MFC_WATCHDOG_INTERVAL   1000
+/* After how many executions watchdog should assume lock up */
+#define MFC_WATCHDOG_CNT        10
+#define MFC_NO_INSTANCE_SET    -1
+#define MFC_ENC_CAP_PLANE_COUNT        1
+#define MFC_ENC_OUT_PLANE_COUNT        2
+#define STUFF_BYTE             4
+#define MFC_MAX_CTRLS          64
+
+#define mfc_read(dev, offset)          readl(dev->regs_base + (offset))
+#define mfc_write(dev, data, offset)   writel((data), dev->regs_base + \
+                                                               (offset))
+
+/**
+ * enum s5p_mfc_fmt_type - type of the pixelformat
+ */
+enum s5p_mfc_fmt_type {
+       MFC_FMT_DEC,
+       MFC_FMT_ENC,
+       MFC_FMT_RAW,
+};
+
+/**
+ * enum s5p_mfc_node_type - The type of an MFC device node.
+ */
+enum s5p_mfc_node_type {
+       MFCNODE_INVALID = -1,
+       MFCNODE_DECODER = 0,
+       MFCNODE_ENCODER = 1,
+};
+
+/**
+ * enum s5p_mfc_inst_type - The type of an MFC instance.
+ */
+enum s5p_mfc_inst_type {
+       MFCINST_INVALID,
+       MFCINST_DECODER,
+       MFCINST_ENCODER,
+};
+
+/**
+ * enum s5p_mfc_inst_state - The state of an MFC instance.
+ */
+enum s5p_mfc_inst_state {
+       MFCINST_FREE = 0,
+       MFCINST_INIT = 100,
+       MFCINST_GOT_INST,
+       MFCINST_HEAD_PARSED,
+       MFCINST_BUFS_SET,
+       MFCINST_RUNNING,
+       MFCINST_FINISHING,
+       MFCINST_FINISHED,
+       MFCINST_RETURN_INST,
+       MFCINST_ERROR,
+       MFCINST_ABORT,
+       MFCINST_RES_CHANGE_INIT,
+       MFCINST_RES_CHANGE_FLUSH,
+       MFCINST_RES_CHANGE_END,
+};
+
+/**
+ * enum s5p_mfc_queue_state - The state of buffer queue.
+ */
+enum s5p_mfc_queue_state {
+       QUEUE_FREE,
+       QUEUE_BUFS_REQUESTED,
+       QUEUE_BUFS_QUERIED,
+       QUEUE_BUFS_MMAPED,
+};
+
+/**
+ * enum s5p_mfc_decode_arg - type of frame decoding
+ */
+enum s5p_mfc_decode_arg {
+       MFC_DEC_FRAME,
+       MFC_DEC_LAST_FRAME,
+       MFC_DEC_RES_CHANGE,
+};
+
+struct s5p_mfc_ctx;
+
+/**
+ * struct s5p_mfc_buf - MFC buffer
+ */
+struct s5p_mfc_buf {
+       struct list_head list;
+       struct vb2_buffer *b;
+       union {
+               struct {
+                       size_t luma;
+                       size_t chroma;
+               } raw;
+               size_t stream;
+       } cookie;
+       int used;
+};
+
+/**
+ * struct s5p_mfc_pm - power management data structure
+ */
+struct s5p_mfc_pm {
+       struct clk      *clock;
+       struct clk      *clock_gate;
+       atomic_t        power;
+       struct device   *device;
+};
+
+/**
+ * struct s5p_mfc_dev - The struct containing driver internal parameters.
+ *
+ * @v4l2_dev:          v4l2_device
+ * @vfd_dec:           video device for decoding
+ * @vfd_enc:           video device for encoding
+ * @plat_dev:          platform device
+ * @mem_dev_l:         child device of the left memory bank (0)
+ * @mem_dev_r:         child device of the right memory bank (1)
+ * @regs_base:         base address of the MFC hw registers
+ * @irq:               irq resource
+ * @mfc_mem:           MFC registers memory resource
+ * @dec_ctrl_handler:  control framework handler for decoding
+ * @enc_ctrl_handler:  control framework handler for encoding
+ * @pm:                        power management control
+ * @num_inst:          couter of active MFC instances
+ * @irqlock:           lock for operations on videobuf2 queues
+ * @condlock:          lock for changing/checking if a context is ready to be
+ *                     processed
+ * @mfc_mutex:         lock for video_device
+ * @int_cond:          variable used by the waitqueue
+ * @int_type:          type of last interrupt
+ * @int_err:           error number for last interrupt
+ * @queue:             waitqueue for waiting for completion of device commands
+ * @fw_size:           size of firmware
+ * @bank1:             address of the beggining of bank 1 memory
+ * @bank2:             address of the beggining of bank 2 memory
+ * @hw_lock:           used for hardware locking
+ * @ctx:               array of driver contexts
+ * @curr_ctx:          number of the currently running context
+ * @ctx_work_bits:     used to mark which contexts are waiting for hardware
+ * @watchdog_cnt:      counter for the watchdog
+ * @watchdog_workqueue:        workqueue for the watchdog
+ * @watchdog_work:     worker for the watchdog
+ * @alloc_ctx:         videobuf2 allocator contexts for two memory banks
+ * @enter_suspend:     flag set when entering suspend
+ *
+ */
+struct s5p_mfc_dev {
+       struct v4l2_device      v4l2_dev;
+       struct video_device     *vfd_dec;
+       struct video_device     *vfd_enc;
+       struct platform_device  *plat_dev;
+       struct device           *mem_dev_l;
+       struct device           *mem_dev_r;
+       void __iomem            *regs_base;
+       int                     irq;
+       struct resource         *mfc_mem;
+       struct v4l2_ctrl_handler dec_ctrl_handler;
+       struct v4l2_ctrl_handler enc_ctrl_handler;
+       struct s5p_mfc_pm       pm;
+       int num_inst;
+       spinlock_t irqlock;     /* lock when operating on videobuf2 queues */
+       spinlock_t condlock;    /* lock when changing/checking if a context is
+                                       ready to be processed */
+       struct mutex mfc_mutex; /* video_device lock */
+       int int_cond;
+       int int_type;
+       unsigned int int_err;
+       wait_queue_head_t queue;
+       size_t fw_size;
+       size_t bank1;
+       size_t bank2;
+       unsigned long hw_lock;
+       struct s5p_mfc_ctx *ctx[MFC_NUM_CONTEXTS];
+       int curr_ctx;
+       unsigned long ctx_work_bits;
+       atomic_t watchdog_cnt;
+       struct timer_list watchdog_timer;
+       struct workqueue_struct *watchdog_workqueue;
+       struct work_struct watchdog_work;
+       void *alloc_ctx[2];
+       unsigned long enter_suspend;
+};
+
+/**
+ * struct s5p_mfc_h264_enc_params - encoding parameters for h264
+ */
+struct s5p_mfc_h264_enc_params {
+       enum v4l2_mpeg_video_h264_profile profile;
+       enum v4l2_mpeg_video_h264_loop_filter_mode loop_filter_mode;
+       s8 loop_filter_alpha;
+       s8 loop_filter_beta;
+       enum v4l2_mpeg_video_h264_entropy_mode entropy_mode;
+       u8 max_ref_pic;
+       u8 num_ref_pic_4p;
+       int _8x8_transform;
+       int rc_mb;
+       int rc_mb_dark;
+       int rc_mb_smooth;
+       int rc_mb_static;
+       int rc_mb_activity;
+       int vui_sar;
+       u8 vui_sar_idc;
+       u16 vui_ext_sar_width;
+       u16 vui_ext_sar_height;
+       int open_gop;
+       u16 open_gop_size;
+       u8 rc_frame_qp;
+       u8 rc_min_qp;
+       u8 rc_max_qp;
+       u8 rc_p_frame_qp;
+       u8 rc_b_frame_qp;
+       enum v4l2_mpeg_video_h264_level level_v4l2;
+       int level;
+       u16 cpb_size;
+};
+
+/**
+ * struct s5p_mfc_mpeg4_enc_params - encoding parameters for h263 and mpeg4
+ */
+struct s5p_mfc_mpeg4_enc_params {
+       /* MPEG4 Only */
+       enum v4l2_mpeg_video_mpeg4_profile profile;
+       int quarter_pixel;
+       /* Common for MPEG4, H263 */
+       u16 vop_time_res;
+       u16 vop_frm_delta;
+       u8 rc_frame_qp;
+       u8 rc_min_qp;
+       u8 rc_max_qp;
+       u8 rc_p_frame_qp;
+       u8 rc_b_frame_qp;
+       enum v4l2_mpeg_video_mpeg4_level level_v4l2;
+       int level;
+};
+
+/**
+ * struct s5p_mfc_enc_params - general encoding parameters
+ */
+struct s5p_mfc_enc_params {
+       u16 width;
+       u16 height;
+
+       u16 gop_size;
+       enum v4l2_mpeg_video_multi_slice_mode slice_mode;
+       u16 slice_mb;
+       u32 slice_bit;
+       u16 intra_refresh_mb;
+       int pad;
+       u8 pad_luma;
+       u8 pad_cb;
+       u8 pad_cr;
+       int rc_frame;
+       u32 rc_bitrate;
+       u16 rc_reaction_coeff;
+       u16 vbv_size;
+
+       enum v4l2_mpeg_video_header_mode seq_hdr_mode;
+       enum v4l2_mpeg_mfc51_video_frame_skip_mode frame_skip_mode;
+       int fixed_target_bit;
+
+       u8 num_b_frame;
+       u32 rc_framerate_num;
+       u32 rc_framerate_denom;
+       int interlace;
+
+       union {
+               struct s5p_mfc_h264_enc_params h264;
+               struct s5p_mfc_mpeg4_enc_params mpeg4;
+       } codec;
+
+};
+
+/**
+ * struct s5p_mfc_codec_ops - codec ops, used by encoding
+ */
+struct s5p_mfc_codec_ops {
+       /* initialization routines */
+       int (*pre_seq_start) (struct s5p_mfc_ctx *ctx);
+       int (*post_seq_start) (struct s5p_mfc_ctx *ctx);
+       /* execution routines */
+       int (*pre_frame_start) (struct s5p_mfc_ctx *ctx);
+       int (*post_frame_start) (struct s5p_mfc_ctx *ctx);
+};
+
+#define call_cop(c, op, args...)                               \
+       (((c)->c_ops->op) ?                                     \
+               ((c)->c_ops->op(args)) : 0)
+
+/**
+ * struct s5p_mfc_ctx - This struct contains the instance context
+ *
+ * @dev:               pointer to the s5p_mfc_dev of the device
+ * @fh:                        struct v4l2_fh
+ * @num:               number of the context that this structure describes
+ * @int_cond:          variable used by the waitqueue
+ * @int_type:          type of the last interrupt
+ * @int_err:           error number received from MFC hw in the interrupt
+ * @queue:             waitqueue that can be used to wait for this context to
+ *                     finish
+ * @src_fmt:           source pixelformat information
+ * @dst_fmt:           destination pixelformat information
+ * @vq_src:            vb2 queue for source buffers
+ * @vq_dst:            vb2 queue for destination buffers
+ * @src_queue:         driver internal queue for source buffers
+ * @dst_queue:         driver internal queue for destination buffers
+ * @src_queue_cnt:     number of buffers queued on the source internal queue
+ * @dst_queue_cnt:     number of buffers queued on the dest internal queue
+ * @type:              type of the instance - decoder or encoder
+ * @state:             state of the context
+ * @inst_no:           number of hw instance associated with the context
+ * @img_width:         width of the image that is decoded or encoded
+ * @img_height:                height of the image that is decoded or encoded
+ * @buf_width:         width of the buffer for processed image
+ * @buf_height:                height of the buffer for processed image
+ * @luma_size:         size of a luma plane
+ * @chroma_size:       size of a chroma plane
+ * @mv_size:           size of a motion vectors buffer
+ * @consumed_stream:   number of bytes that have been used so far from the
+ *                     decoding buffer
+ * @dpb_flush_flag:    flag used to indicate that a DPB buffers are being
+ *                     flushed
+ * @bank1_buf:         handle to memory allocated for temporary buffers from
+ *                     memory bank 1
+ * @bank1_phys:                address of the temporary buffers from memory bank 1
+ * @bank1_size:                size of the memory allocated for temporary buffers from
+ *                     memory bank 1
+ * @bank2_buf:         handle to memory allocated for temporary buffers from
+ *                     memory bank 2
+ * @bank2_phys:                address of the temporary buffers from memory bank 2
+ * @bank2_size:                size of the memory allocated for temporary buffers from
+ *                     memory bank 2
+ * @capture_state:     state of the capture buffers queue
+ * @output_state:      state of the output buffers queue
+ * @src_bufs:          information on allocated source buffers
+ * @dst_bufs:          information on allocated destination buffers
+ * @sequence:          counter for the sequence number for v4l2
+ * @dec_dst_flag:      flags for buffers queued in the hardware
+ * @dec_src_buf_size:  size of the buffer for source buffers in decoding
+ * @codec_mode:                number of codec mode used by MFC hw
+ * @slice_interface:   slice interface flag
+ * @loop_filter_mpeg4: loop filter for MPEG4 flag
+ * @display_delay:     value of the display delay for H264
+ * @display_delay_enable:      display delay for H264 enable flag
+ * @after_packed_pb:   flag used to track buffer when stream is in
+ *                     Packed PB format
+ * @dpb_count:         count of the DPB buffers required by MFC hw
+ * @total_dpb_count:   count of DPB buffers with additional buffers
+ *                     requested by the application
+ * @ctx_buf:           handle to the memory associated with this context
+ * @ctx_phys:          address of the memory associated with this context
+ * @ctx_size:          size of the memory associated with this context
+ * @desc_buf:          description buffer for decoding handle
+ * @desc_phys:         description buffer for decoding address
+ * @shm_alloc:         handle for the shared memory buffer
+ * @shm:               virtual address for the shared memory buffer
+ * @shm_ofs:           address offset for shared memory
+ * @enc_params:                encoding parameters for MFC
+ * @enc_dst_buf_size:  size of the buffers for encoder output
+ * @frame_type:                used to force the type of the next encoded frame
+ * @ref_queue:         list of the reference buffers for encoding
+ * @ref_queue_cnt:     number of the buffers in the reference list
+ * @c_ops:             ops for encoding
+ * @ctrls:             array of controls, used when adding controls to the
+ *                     v4l2 control framework
+ * @ctrl_handler:      handler for v4l2 framework
+ */
+struct s5p_mfc_ctx {
+       struct s5p_mfc_dev *dev;
+       struct v4l2_fh fh;
+
+       int num;
+
+       int int_cond;
+       int int_type;
+       unsigned int int_err;
+       wait_queue_head_t queue;
+
+       struct s5p_mfc_fmt *src_fmt;
+       struct s5p_mfc_fmt *dst_fmt;
+
+       struct vb2_queue vq_src;
+       struct vb2_queue vq_dst;
+
+       struct list_head src_queue;
+       struct list_head dst_queue;
+
+       unsigned int src_queue_cnt;
+       unsigned int dst_queue_cnt;
+
+       enum s5p_mfc_inst_type type;
+       enum s5p_mfc_inst_state state;
+       int inst_no;
+
+       /* Image parameters */
+       int img_width;
+       int img_height;
+       int buf_width;
+       int buf_height;
+
+       int luma_size;
+       int chroma_size;
+       int mv_size;
+
+       unsigned long consumed_stream;
+
+       unsigned int dpb_flush_flag;
+
+       /* Buffers */
+       void *bank1_buf;
+       size_t bank1_phys;
+       size_t bank1_size;
+
+       void *bank2_buf;
+       size_t bank2_phys;
+       size_t bank2_size;
+
+       enum s5p_mfc_queue_state capture_state;
+       enum s5p_mfc_queue_state output_state;
+
+       struct s5p_mfc_buf src_bufs[MFC_MAX_BUFFERS];
+       int src_bufs_cnt;
+       struct s5p_mfc_buf dst_bufs[MFC_MAX_BUFFERS];
+       int dst_bufs_cnt;
+
+       unsigned int sequence;
+       unsigned long dec_dst_flag;
+       size_t dec_src_buf_size;
+
+       /* Control values */
+       int codec_mode;
+       int slice_interface;
+       int loop_filter_mpeg4;
+       int display_delay;
+       int display_delay_enable;
+       int after_packed_pb;
+
+       int dpb_count;
+       int total_dpb_count;
+
+       /* Buffers */
+       void *ctx_buf;
+       size_t ctx_phys;
+       size_t ctx_ofs;
+       size_t ctx_size;
+
+       void *desc_buf;
+       size_t desc_phys;
+
+
+       void *shm_alloc;
+       void *shm;
+       size_t shm_ofs;
+
+       struct s5p_mfc_enc_params enc_params;
+
+       size_t enc_dst_buf_size;
+
+       enum v4l2_mpeg_mfc51_video_force_frame_type force_frame_type;
+
+       struct list_head ref_queue;
+       unsigned int ref_queue_cnt;
+
+       struct s5p_mfc_codec_ops *c_ops;
+
+       struct v4l2_ctrl *ctrls[MFC_MAX_CTRLS];
+       struct v4l2_ctrl_handler ctrl_handler;
+};
+
+/*
+ * struct s5p_mfc_fmt -        structure used to store information about pixelformats
+ *                     used by the MFC
+ */
+struct s5p_mfc_fmt {
+       char *name;
+       u32 fourcc;
+       u32 codec_mode;
+       enum s5p_mfc_fmt_type type;
+       u32 num_planes;
+};
+
+/**
+ * struct mfc_control -        structure used to store information about MFC controls
+ *                     it is used to initialize the control framework.
+ */
+struct mfc_control {
+       __u32                   id;
+       enum v4l2_ctrl_type     type;
+       __u8                    name[32];  /* Whatever */
+       __s32                   minimum;   /* Note signedness */
+       __s32                   maximum;
+       __s32                   step;
+       __u32                   menu_skip_mask;
+       __s32                   default_value;
+       __u32                   flags;
+       __u32                   reserved[2];
+       __u8                    is_volatile;
+};
+
+
+#define fh_to_ctx(__fh) container_of(__fh, struct s5p_mfc_ctx, fh)
+#define ctrl_to_ctx(__ctrl) \
+       container_of((__ctrl)->handler, struct s5p_mfc_ctx, ctrl_handler)
+
+#endif /* S5P_MFC_COMMON_H_ */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c
new file mode 100644 (file)
index 0000000..5f4da80
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * linux/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/firmware.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include "regs-mfc.h"
+#include "s5p_mfc_cmd.h"
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_intr.h"
+#include "s5p_mfc_pm.h"
+
+static void *s5p_mfc_bitproc_buf;
+static size_t s5p_mfc_bitproc_phys;
+static unsigned char *s5p_mfc_bitproc_virt;
+
+/* Allocate and load firmware */
+int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev)
+{
+       struct firmware *fw_blob;
+       size_t bank2_base_phys;
+       void *b_base;
+       int err;
+
+       /* Firmare has to be present as a separate file or compiled
+        * into kernel. */
+       mfc_debug_enter();
+       err = request_firmware((const struct firmware **)&fw_blob,
+                                    "s5pc110-mfc.fw", dev->v4l2_dev.dev);
+       if (err != 0) {
+               mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n");
+               return -EINVAL;
+       }
+       dev->fw_size = ALIGN(fw_blob->size, FIRMWARE_ALIGN);
+       if (s5p_mfc_bitproc_buf) {
+               mfc_err("Attempting to allocate firmware when it seems that it is already loaded\n");
+               release_firmware(fw_blob);
+               return -ENOMEM;
+       }
+       s5p_mfc_bitproc_buf = vb2_dma_contig_memops.alloc(
+               dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], dev->fw_size);
+       if (IS_ERR(s5p_mfc_bitproc_buf)) {
+               s5p_mfc_bitproc_buf = 0;
+               mfc_err("Allocating bitprocessor buffer failed\n");
+               release_firmware(fw_blob);
+               return -ENOMEM;
+       }
+       s5p_mfc_bitproc_phys = s5p_mfc_mem_cookie(
+               dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], s5p_mfc_bitproc_buf);
+       if (s5p_mfc_bitproc_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) {
+               mfc_err("The base memory for bank 1 is not aligned to 128KB\n");
+               vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
+               s5p_mfc_bitproc_phys = 0;
+               s5p_mfc_bitproc_buf = 0;
+               release_firmware(fw_blob);
+               return -EIO;
+       }
+       s5p_mfc_bitproc_virt = vb2_dma_contig_memops.vaddr(s5p_mfc_bitproc_buf);
+       if (!s5p_mfc_bitproc_virt) {
+               mfc_err("Bitprocessor memory remap failed\n");
+               vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
+               s5p_mfc_bitproc_phys = 0;
+               s5p_mfc_bitproc_buf = 0;
+               release_firmware(fw_blob);
+               return -EIO;
+       }
+       dev->bank1 = s5p_mfc_bitproc_phys;
+       b_base = vb2_dma_contig_memops.alloc(
+               dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], 1 << MFC_BANK2_ALIGN_ORDER);
+       if (IS_ERR(b_base)) {
+               vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
+               s5p_mfc_bitproc_phys = 0;
+               s5p_mfc_bitproc_buf = 0;
+               mfc_err("Allocating bank2 base failed\n");
+       release_firmware(fw_blob);
+               return -ENOMEM;
+       }
+       bank2_base_phys = s5p_mfc_mem_cookie(
+               dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], b_base);
+       vb2_dma_contig_memops.put(b_base);
+       if (bank2_base_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) {
+               mfc_err("The base memory for bank 2 is not aligned to 128KB\n");
+               vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
+               s5p_mfc_bitproc_phys = 0;
+               s5p_mfc_bitproc_buf = 0;
+               release_firmware(fw_blob);
+               return -EIO;
+       }
+       dev->bank2 = bank2_base_phys;
+       memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size);
+       wmb();
+       release_firmware(fw_blob);
+       mfc_debug_leave();
+       return 0;
+}
+
+/* Reload firmware to MFC */
+int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev)
+{
+       struct firmware *fw_blob;
+       int err;
+
+       /* Firmare has to be present as a separate file or compiled
+        * into kernel. */
+       mfc_debug_enter();
+       err = request_firmware((const struct firmware **)&fw_blob,
+                                    "s5pc110-mfc.fw", dev->v4l2_dev.dev);
+       if (err != 0) {
+               mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n");
+               return -EINVAL;
+       }
+       if (fw_blob->size > dev->fw_size) {
+               mfc_err("MFC firmware is too big to be loaded\n");
+               release_firmware(fw_blob);
+               return -ENOMEM;
+       }
+       if (s5p_mfc_bitproc_buf == 0 || s5p_mfc_bitproc_phys == 0) {
+               mfc_err("MFC firmware is not allocated or was not mapped correctly\n");
+               release_firmware(fw_blob);
+               return -EINVAL;
+       }
+       memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size);
+       wmb();
+       release_firmware(fw_blob);
+       mfc_debug_leave();
+       return 0;
+}
+
+/* Release firmware memory */
+int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev)
+{
+       /* Before calling this function one has to make sure
+        * that MFC is no longer processing */
+       if (!s5p_mfc_bitproc_buf)
+               return -EINVAL;
+       vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
+       s5p_mfc_bitproc_virt =  0;
+       s5p_mfc_bitproc_phys = 0;
+       s5p_mfc_bitproc_buf = 0;
+       return 0;
+}
+
+/* Reset the device */
+int s5p_mfc_reset(struct s5p_mfc_dev *dev)
+{
+       unsigned int mc_status;
+       unsigned long timeout;
+
+       mfc_debug_enter();
+       /* Stop procedure */
+       /*  reset RISC */
+       mfc_write(dev, 0x3f6, S5P_FIMV_SW_RESET);
+       /*  All reset except for MC */
+       mfc_write(dev, 0x3e2, S5P_FIMV_SW_RESET);
+       mdelay(10);
+
+       timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT);
+       /* Check MC status */
+       do {
+               if (time_after(jiffies, timeout)) {
+                       mfc_err("Timeout while resetting MFC\n");
+                       return -EIO;
+               }
+
+               mc_status = mfc_read(dev, S5P_FIMV_MC_STATUS);
+
+       } while (mc_status & 0x3);
+
+       mfc_write(dev, 0x0, S5P_FIMV_SW_RESET);
+       mfc_write(dev, 0x3fe, S5P_FIMV_SW_RESET);
+       mfc_debug_leave();
+       return 0;
+}
+
+static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev)
+{
+       mfc_write(dev, dev->bank1, S5P_FIMV_MC_DRAMBASE_ADR_A);
+       mfc_write(dev, dev->bank2, S5P_FIMV_MC_DRAMBASE_ADR_B);
+       mfc_debug(2, "Bank1: %08x, Bank2: %08x\n", dev->bank1, dev->bank2);
+}
+
+static inline void s5p_mfc_clear_cmds(struct s5p_mfc_dev *dev)
+{
+       mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH0_INST_ID);
+       mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH1_INST_ID);
+       mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD);
+       mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD);
+}
+
+/* Initialize hardware */
+int s5p_mfc_init_hw(struct s5p_mfc_dev *dev)
+{
+       unsigned int ver;
+       int ret;
+
+       mfc_debug_enter();
+       if (!s5p_mfc_bitproc_buf)
+               return -EINVAL;
+
+       /* 0. MFC reset */
+       mfc_debug(2, "MFC reset..\n");
+       s5p_mfc_clock_on();
+       ret = s5p_mfc_reset(dev);
+       if (ret) {
+               mfc_err("Failed to reset MFC - timeout\n");
+               return ret;
+       }
+       mfc_debug(2, "Done MFC reset..\n");
+       /* 1. Set DRAM base Addr */
+       s5p_mfc_init_memctrl(dev);
+       /* 2. Initialize registers of channel I/F */
+       s5p_mfc_clear_cmds(dev);
+       /* 3. Release reset signal to the RISC */
+       s5p_mfc_clean_dev_int_flags(dev);
+       mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
+       mfc_debug(2, "Will now wait for completion of firmware transfer\n");
+       if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_FW_STATUS_RET)) {
+               mfc_err("Failed to load firmware\n");
+               s5p_mfc_reset(dev);
+               s5p_mfc_clock_off();
+               return -EIO;
+       }
+       s5p_mfc_clean_dev_int_flags(dev);
+       /* 4. Initialize firmware */
+       ret = s5p_mfc_sys_init_cmd(dev);
+       if (ret) {
+               mfc_err("Failed to send command to MFC - timeout\n");
+               s5p_mfc_reset(dev);
+               s5p_mfc_clock_off();
+               return ret;
+       }
+       mfc_debug(2, "Ok, now will write a command to init the system\n");
+       if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SYS_INIT_RET)) {
+               mfc_err("Failed to load firmware\n");
+               s5p_mfc_reset(dev);
+               s5p_mfc_clock_off();
+               return -EIO;
+       }
+       dev->int_cond = 0;
+       if (dev->int_err != 0 || dev->int_type !=
+                                       S5P_FIMV_R2H_CMD_SYS_INIT_RET) {
+               /* Failure. */
+               mfc_err("Failed to init firmware - error: %d int: %d\n",
+                                               dev->int_err, dev->int_type);
+               s5p_mfc_reset(dev);
+               s5p_mfc_clock_off();
+               return -EIO;
+       }
+       ver = mfc_read(dev, S5P_FIMV_FW_VERSION);
+       mfc_debug(2, "MFC F/W version : %02xyy, %02xmm, %02xdd\n",
+               (ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF);
+       s5p_mfc_clock_off();
+       mfc_debug_leave();
+       return 0;
+}
+
+
+int s5p_mfc_sleep(struct s5p_mfc_dev *dev)
+{
+       int ret;
+
+       mfc_debug_enter();
+       s5p_mfc_clock_on();
+       s5p_mfc_clean_dev_int_flags(dev);
+       ret = s5p_mfc_sleep_cmd(dev);
+       if (ret) {
+               mfc_err("Failed to send command to MFC - timeout\n");
+               return ret;
+       }
+       if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SLEEP_RET)) {
+               mfc_err("Failed to sleep\n");
+               return -EIO;
+       }
+       s5p_mfc_clock_off();
+       dev->int_cond = 0;
+       if (dev->int_err != 0 || dev->int_type !=
+                                               S5P_FIMV_R2H_CMD_SLEEP_RET) {
+               /* Failure. */
+               mfc_err("Failed to sleep - error: %d int: %d\n", dev->int_err,
+                                                               dev->int_type);
+               return -EIO;
+       }
+       mfc_debug_leave();
+       return ret;
+}
+
+int s5p_mfc_wakeup(struct s5p_mfc_dev *dev)
+{
+       int ret;
+
+       mfc_debug_enter();
+       /* 0. MFC reset */
+       mfc_debug(2, "MFC reset..\n");
+       s5p_mfc_clock_on();
+       ret = s5p_mfc_reset(dev);
+       if (ret) {
+               mfc_err("Failed to reset MFC - timeout\n");
+               return ret;
+       }
+       mfc_debug(2, "Done MFC reset..\n");
+       /* 1. Set DRAM base Addr */
+       s5p_mfc_init_memctrl(dev);
+       /* 2. Initialize registers of channel I/F */
+       s5p_mfc_clear_cmds(dev);
+       s5p_mfc_clean_dev_int_flags(dev);
+       /* 3. Initialize firmware */
+       ret = s5p_mfc_wakeup_cmd(dev);
+       if (ret) {
+               mfc_err("Failed to send command to MFC - timeout\n");
+               return ret;
+       }
+       /* 4. Release reset signal to the RISC */
+       mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
+       mfc_debug(2, "Ok, now will write a command to wakeup the system\n");
+       if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_WAKEUP_RET)) {
+               mfc_err("Failed to load firmware\n");
+               return -EIO;
+       }
+       s5p_mfc_clock_off();
+       dev->int_cond = 0;
+       if (dev->int_err != 0 || dev->int_type !=
+                                               S5P_FIMV_R2H_CMD_WAKEUP_RET) {
+               /* Failure. */
+               mfc_err("Failed to wakeup - error: %d int: %d\n", dev->int_err,
+                                                               dev->int_type);
+               return -EIO;
+       }
+       mfc_debug_leave();
+       return 0;
+}
+
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.h b/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.h
new file mode 100644 (file)
index 0000000..61dc23b
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * linux/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.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.
+ */
+
+#ifndef S5P_MFC_CTRL_H
+#define S5P_MFC_CTRL_H
+
+#include "s5p_mfc_common.h"
+
+int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev);
+int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev);
+int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev);
+
+int s5p_mfc_init_hw(struct s5p_mfc_dev *dev);
+
+int s5p_mfc_sleep(struct s5p_mfc_dev *dev);
+int s5p_mfc_wakeup(struct s5p_mfc_dev *dev);
+
+int s5p_mfc_reset(struct s5p_mfc_dev *dev);
+
+#endif /* S5P_MFC_CTRL_H */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_debug.h b/drivers/media/video/s5p-mfc/s5p_mfc_debug.h
new file mode 100644 (file)
index 0000000..ecb8616
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * drivers/media/video/samsung/mfc5/s5p_mfc_debug.h
+ *
+ * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
+ * This file contains debug macros
+ *
+ * Kamil Debski, Copyright (c) 2011 Samsung Electronics
+ * http://www.samsung.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 S5P_MFC_DEBUG_H_
+#define S5P_MFC_DEBUG_H_
+
+#define DEBUG
+
+#ifdef DEBUG
+extern int debug;
+
+#define mfc_debug(level, fmt, args...)                         \
+       do {                                                    \
+               if (debug >= level)                             \
+                       printk(KERN_DEBUG "%s:%d: " fmt,        \
+                               __func__, __LINE__, ##args);    \
+       } while (0)
+#else
+#define mfc_debug(level, fmt, args...)
+#endif
+
+#define mfc_debug_enter() mfc_debug(5, "enter")
+#define mfc_debug_leave() mfc_debug(5, "leave")
+
+#define mfc_err(fmt, args...)                          \
+       do {                                            \
+               printk(KERN_ERR "%s:%d: " fmt,          \
+                      __func__, __LINE__, ##args);     \
+       } while (0)
+
+#define mfc_info(fmt, args...)                         \
+       do {                                            \
+               printk(KERN_INFO "%s:%d: " fmt,         \
+                      __func__, __LINE__, ##args);     \
+       } while (0)
+
+#endif /* S5P_MFC_DEBUG_H_ */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c
new file mode 100644 (file)
index 0000000..b2c5052
--- /dev/null
@@ -0,0 +1,1036 @@
+/*
+ * linux/drivers/media/video/s5p-mfc/s5p_mfc_dec.c
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ * Kamil Debski, <k.debski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
+#include <linux/workqueue.h>
+#include <media/v4l2-ctrls.h>
+#include <media/videobuf2-core.h>
+#include "regs-mfc.h"
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_dec.h"
+#include "s5p_mfc_intr.h"
+#include "s5p_mfc_opr.h"
+#include "s5p_mfc_pm.h"
+#include "s5p_mfc_shm.h"
+
+static struct s5p_mfc_fmt formats[] = {
+       {
+               .name           = "4:2:0 2 Planes 64x32 Tiles",
+               .fourcc         = V4L2_PIX_FMT_NV12MT,
+               .codec_mode     = S5P_FIMV_CODEC_NONE,
+               .type           = MFC_FMT_RAW,
+               .num_planes     = 2,
+        },
+       {
+               .name = "4:2:0 2 Planes",
+               .fourcc = V4L2_PIX_FMT_NV12M,
+               .codec_mode = S5P_FIMV_CODEC_NONE,
+               .type = MFC_FMT_RAW,
+               .num_planes = 2,
+       },
+       {
+               .name = "H264 Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_H264,
+               .codec_mode = S5P_FIMV_CODEC_H264_DEC,
+               .type = MFC_FMT_DEC,
+               .num_planes = 1,
+       },
+       {
+               .name = "H263 Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_H263,
+               .codec_mode = S5P_FIMV_CODEC_H263_DEC,
+               .type = MFC_FMT_DEC,
+               .num_planes = 1,
+       },
+       {
+               .name = "MPEG1 Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_MPEG1,
+               .codec_mode = S5P_FIMV_CODEC_MPEG2_DEC,
+               .type = MFC_FMT_DEC,
+               .num_planes = 1,
+       },
+       {
+               .name = "MPEG2 Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_MPEG2,
+               .codec_mode = S5P_FIMV_CODEC_MPEG2_DEC,
+               .type = MFC_FMT_DEC,
+               .num_planes = 1,
+       },
+       {
+               .name = "MPEG4 Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_MPEG4,
+               .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC,
+               .type = MFC_FMT_DEC,
+               .num_planes = 1,
+       },
+       {
+               .name = "XviD Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_XVID,
+               .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC,
+               .type = MFC_FMT_DEC,
+               .num_planes = 1,
+       },
+       {
+               .name = "VC1 Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G,
+               .codec_mode = S5P_FIMV_CODEC_VC1_DEC,
+               .type = MFC_FMT_DEC,
+               .num_planes = 1,
+       },
+       {
+               .name = "VC1 RCV Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L,
+               .codec_mode = S5P_FIMV_CODEC_VC1RCV_DEC,
+               .type = MFC_FMT_DEC,
+               .num_planes = 1,
+       },
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+/* Find selected format description */
+static struct s5p_mfc_fmt *find_format(struct v4l2_format *f, unsigned int t)
+{
+       unsigned int i;
+
+       for (i = 0; i < NUM_FORMATS; i++) {
+               if (formats[i].fourcc == f->fmt.pix_mp.pixelformat &&
+                   formats[i].type == t)
+                       return &formats[i];
+       }
+       return NULL;
+}
+
+static struct mfc_control controls[] = {
+       {
+               .id = V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "H264 Display Delay",
+               .minimum = 0,
+               .maximum = 16383,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .name = "H264 Display Delay Enable",
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .name = "Mpeg4 Loop Filter Enable",
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .name = "Slice Interface Enable",
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Minimum number of cap bufs",
+               .minimum = 1,
+               .maximum = 32,
+               .step = 1,
+               .default_value = 1,
+               .is_volatile = 1,
+       },
+};
+
+#define NUM_CTRLS ARRAY_SIZE(controls)
+
+/* Check whether a context should be run on hardware */
+static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx)
+{
+       /* Context is to parse header */
+       if (ctx->src_queue_cnt >= 1 && ctx->state == MFCINST_GOT_INST)
+               return 1;
+       /* Context is to decode a frame */
+       if (ctx->src_queue_cnt >= 1 &&
+           ctx->state == MFCINST_RUNNING &&
+           ctx->dst_queue_cnt >= ctx->dpb_count)
+               return 1;
+       /* Context is to return last frame */
+       if (ctx->state == MFCINST_FINISHING &&
+           ctx->dst_queue_cnt >= ctx->dpb_count)
+               return 1;
+       /* Context is to set buffers */
+       if (ctx->src_queue_cnt >= 1 &&
+           ctx->state == MFCINST_HEAD_PARSED &&
+           ctx->capture_state == QUEUE_BUFS_MMAPED)
+               return 1;
+       /* Resolution change */
+       if ((ctx->state == MFCINST_RES_CHANGE_INIT ||
+               ctx->state == MFCINST_RES_CHANGE_FLUSH) &&
+               ctx->dst_queue_cnt >= ctx->dpb_count)
+               return 1;
+       if (ctx->state == MFCINST_RES_CHANGE_END &&
+               ctx->src_queue_cnt >= 1)
+               return 1;
+       mfc_debug(2, "ctx is not ready\n");
+       return 0;
+}
+
+static struct s5p_mfc_codec_ops decoder_codec_ops = {
+       .pre_seq_start          = NULL,
+       .post_seq_start         = NULL,
+       .pre_frame_start        = NULL,
+       .post_frame_start       = NULL,
+};
+
+/* Query capabilities of the device */
+static int vidioc_querycap(struct file *file, void *priv,
+                          struct v4l2_capability *cap)
+{
+       struct s5p_mfc_dev *dev = video_drvdata(file);
+
+       strncpy(cap->driver, dev->plat_dev->name, sizeof(cap->driver) - 1);
+       strncpy(cap->card, dev->plat_dev->name, sizeof(cap->card) - 1);
+       cap->bus_info[0] = 0;
+       cap->version = KERNEL_VERSION(1, 0, 0);
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT
+                                                   | V4L2_CAP_STREAMING;
+       return 0;
+}
+
+/* Enumerate format */
+static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool mplane, bool out)
+{
+       struct s5p_mfc_fmt *fmt;
+       int i, j = 0;
+
+       for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+               if (mplane && formats[i].num_planes == 1)
+                       continue;
+               else if (!mplane && formats[i].num_planes > 1)
+                       continue;
+               if (out && formats[i].type != MFC_FMT_DEC)
+                       continue;
+               else if (!out && formats[i].type != MFC_FMT_RAW)
+                       continue;
+
+               if (j == f->index)
+                       break;
+               ++j;
+       }
+       if (i == ARRAY_SIZE(formats))
+               return -EINVAL;
+       fmt = &formats[i];
+       strlcpy(f->description, fmt->name, sizeof(f->description));
+       f->pixelformat = fmt->fourcc;
+       return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv,
+                                                       struct v4l2_fmtdesc *f)
+{
+       return vidioc_enum_fmt(f, false, false);
+}
+
+static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
+                                                       struct v4l2_fmtdesc *f)
+{
+       return vidioc_enum_fmt(f, true, false);
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *prov,
+                                                       struct v4l2_fmtdesc *f)
+{
+       return vidioc_enum_fmt(f, false, true);
+}
+
+static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov,
+                                                       struct v4l2_fmtdesc *f)
+{
+       return vidioc_enum_fmt(f, true, true);
+}
+
+/* Get format */
+static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+       struct v4l2_pix_format_mplane *pix_mp;
+
+       mfc_debug_enter();
+       pix_mp = &f->fmt.pix_mp;
+       if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+           (ctx->state == MFCINST_GOT_INST || ctx->state ==
+                                               MFCINST_RES_CHANGE_END)) {
+               /* If the MFC is parsing the header,
+                * so wait until it is finished */
+               s5p_mfc_clean_ctx_int_flags(ctx);
+               s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_SEQ_DONE_RET,
+                                                                       0);
+       }
+       if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+           ctx->state >= MFCINST_HEAD_PARSED &&
+           ctx->state < MFCINST_ABORT) {
+               /* This is run on CAPTURE (decode output) */
+               /* Width and height are set to the dimensions
+                  of the movie, the buffer is bigger and
+                  further processing stages should crop to this
+                  rectangle. */
+               pix_mp->width = ctx->buf_width;
+               pix_mp->height = ctx->buf_height;
+               pix_mp->field = V4L2_FIELD_NONE;
+               pix_mp->num_planes = 2;
+               /* Set pixelformat to the format in which MFC
+                  outputs the decoded frame */
+               pix_mp->pixelformat = V4L2_PIX_FMT_NV12MT;
+               pix_mp->plane_fmt[0].bytesperline = ctx->buf_width;
+               pix_mp->plane_fmt[0].sizeimage = ctx->luma_size;
+               pix_mp->plane_fmt[1].bytesperline = ctx->buf_width;
+               pix_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
+       } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               /* This is run on OUTPUT
+                  The buffer contains compressed image
+                  so width and height have no meaning */
+               pix_mp->width = 0;
+               pix_mp->height = 0;
+               pix_mp->field = V4L2_FIELD_NONE;
+               pix_mp->plane_fmt[0].bytesperline = ctx->dec_src_buf_size;
+               pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size;
+               pix_mp->pixelformat = ctx->src_fmt->fourcc;
+               pix_mp->num_planes = ctx->src_fmt->num_planes;
+       } else {
+               mfc_err("Format could not be read\n");
+               mfc_debug(2, "%s-- with error\n", __func__);
+               return -EINVAL;
+       }
+       mfc_debug_leave();
+       return 0;
+}
+
+/* Try format */
+static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+       struct s5p_mfc_fmt *fmt;
+
+       if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               mfc_err("This node supports decoding only\n");
+               return -EINVAL;
+       }
+       fmt = find_format(f, MFC_FMT_DEC);
+       if (!fmt) {
+               mfc_err("Unsupported format\n");
+               return -EINVAL;
+       }
+       if (fmt->type != MFC_FMT_DEC) {
+               mfc_err("\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/* Set format */
+static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+       struct s5p_mfc_dev *dev = video_drvdata(file);
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+       int ret = 0;
+       struct s5p_mfc_fmt *fmt;
+       struct v4l2_pix_format_mplane *pix_mp;
+
+       mfc_debug_enter();
+       ret = vidioc_try_fmt(file, priv, f);
+       pix_mp = &f->fmt.pix_mp;
+       if (ret)
+               return ret;
+       if (ctx->vq_src.streaming || ctx->vq_dst.streaming) {
+               v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__);
+               ret = -EBUSY;
+               goto out;
+       }
+       fmt = find_format(f, MFC_FMT_DEC);
+       if (!fmt || fmt->codec_mode == S5P_FIMV_CODEC_NONE) {
+               mfc_err("Unknown codec\n");
+               ret = -EINVAL;
+               goto out;
+       }
+       if (fmt->type != MFC_FMT_DEC) {
+               mfc_err("Wrong format selected, you should choose "
+                                       "format for decoding\n");
+               ret = -EINVAL;
+               goto out;
+       }
+       ctx->src_fmt = fmt;
+       ctx->codec_mode = fmt->codec_mode;
+       mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode);
+       pix_mp->height = 0;
+       pix_mp->width = 0;
+       if (pix_mp->plane_fmt[0].sizeimage)
+               ctx->dec_src_buf_size = pix_mp->plane_fmt[0].sizeimage;
+       else
+               pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size =
+                                                               DEF_CPB_SIZE;
+       pix_mp->plane_fmt[0].bytesperline = 0;
+       ctx->state = MFCINST_INIT;
+out:
+       mfc_debug_leave();
+       return ret;
+}
+
+/* Reqeust buffers */
+static int vidioc_reqbufs(struct file *file, void *priv,
+                                         struct v4l2_requestbuffers *reqbufs)
+{
+       struct s5p_mfc_dev *dev = video_drvdata(file);
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+       int ret = 0;
+       unsigned long flags;
+
+       if (reqbufs->memory != V4L2_MEMORY_MMAP) {
+               mfc_err("Only V4L2_MEMORY_MAP is supported\n");
+               return -EINVAL;
+       }
+       if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               /* Can only request buffers after an instance has been opened.*/
+               if (ctx->state == MFCINST_INIT) {
+                       ctx->src_bufs_cnt = 0;
+                       if (reqbufs->count == 0) {
+                               mfc_debug(2, "Freeing buffers\n");
+                               s5p_mfc_clock_on();
+                               ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
+                               s5p_mfc_clock_off();
+                               return ret;
+                       }
+                       /* Decoding */
+                       if (ctx->output_state != QUEUE_FREE) {
+                               mfc_err("Bufs have already been requested\n");
+                               return -EINVAL;
+                       }
+                       s5p_mfc_clock_on();
+                       ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
+                       s5p_mfc_clock_off();
+                       if (ret) {
+                               mfc_err("vb2_reqbufs on output failed\n");
+                               return ret;
+                       }
+                       mfc_debug(2, "vb2_reqbufs: %d\n", ret);
+                       ctx->output_state = QUEUE_BUFS_REQUESTED;
+               }
+       } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               ctx->dst_bufs_cnt = 0;
+               if (reqbufs->count == 0) {
+                       mfc_debug(2, "Freeing buffers\n");
+                       s5p_mfc_clock_on();
+                       ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+                       s5p_mfc_clock_off();
+                       return ret;
+               }
+               if (ctx->capture_state != QUEUE_FREE) {
+                       mfc_err("Bufs have already been requested\n");
+                       return -EINVAL;
+               }
+               ctx->capture_state = QUEUE_BUFS_REQUESTED;
+               s5p_mfc_clock_on();
+               ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+               s5p_mfc_clock_off();
+               if (ret) {
+                       mfc_err("vb2_reqbufs on capture failed\n");
+                       return ret;
+               }
+               if (reqbufs->count < ctx->dpb_count) {
+                       mfc_err("Not enough buffers allocated\n");
+                       reqbufs->count = 0;
+                       s5p_mfc_clock_on();
+                       ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+                       s5p_mfc_clock_off();
+                       return -ENOMEM;
+               }
+               ctx->total_dpb_count = reqbufs->count;
+               ret = s5p_mfc_alloc_codec_buffers(ctx);
+               if (ret) {
+                       mfc_err("Failed to allocate decoding buffers\n");
+                       reqbufs->count = 0;
+                       s5p_mfc_clock_on();
+                       ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+                       s5p_mfc_clock_off();
+                       return -ENOMEM;
+               }
+               if (ctx->dst_bufs_cnt == ctx->total_dpb_count) {
+                       ctx->capture_state = QUEUE_BUFS_MMAPED;
+               } else {
+                       mfc_err("Not all buffers passed to buf_init\n");
+                       reqbufs->count = 0;
+                       s5p_mfc_clock_on();
+                       ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+                       s5p_mfc_release_codec_buffers(ctx);
+                       s5p_mfc_clock_off();
+                       return -ENOMEM;
+               }
+               if (s5p_mfc_ctx_ready(ctx)) {
+                       spin_lock_irqsave(&dev->condlock, flags);
+                       set_bit(ctx->num, &dev->ctx_work_bits);
+                       spin_unlock_irqrestore(&dev->condlock, flags);
+               }
+               s5p_mfc_try_run(dev);
+               s5p_mfc_wait_for_done_ctx(ctx,
+                                        S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET, 0);
+       }
+       return ret;
+}
+
+/* Query buffer */
+static int vidioc_querybuf(struct file *file, void *priv,
+                                                  struct v4l2_buffer *buf)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+       int ret;
+       int i;
+
+       if (buf->memory != V4L2_MEMORY_MMAP) {
+               mfc_err("Only mmaped buffers can be used\n");
+               return -EINVAL;
+       }
+       mfc_debug(2, "State: %d, buf->type: %d\n", ctx->state, buf->type);
+       if (ctx->state == MFCINST_INIT &&
+                       buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               ret = vb2_querybuf(&ctx->vq_src, buf);
+       } else if (ctx->state == MFCINST_RUNNING &&
+                       buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               ret = vb2_querybuf(&ctx->vq_dst, buf);
+               for (i = 0; i < buf->length; i++)
+                       buf->m.planes[i].m.mem_offset += DST_QUEUE_OFF_BASE;
+       } else {
+               mfc_err("vidioc_querybuf called in an inappropriate state\n");
+               ret = -EINVAL;
+       }
+       mfc_debug_leave();
+       return ret;
+}
+
+/* Queue a buffer */
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+       if (ctx->state == MFCINST_ERROR) {
+               mfc_err("Call on QBUF after unrecoverable error\n");
+               return -EIO;
+       }
+       if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               return vb2_qbuf(&ctx->vq_src, buf);
+       else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               return vb2_qbuf(&ctx->vq_dst, buf);
+       return -EINVAL;
+}
+
+/* Dequeue a buffer */
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+       if (ctx->state == MFCINST_ERROR) {
+               mfc_err("Call on DQBUF after unrecoverable error\n");
+               return -EIO;
+       }
+       if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               return vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK);
+       else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               return vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK);
+       return -EINVAL;
+}
+
+/* Stream on */
+static int vidioc_streamon(struct file *file, void *priv,
+                          enum v4l2_buf_type type)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned long flags;
+       int ret = -EINVAL;
+
+       mfc_debug_enter();
+       if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+
+               if (ctx->state == MFCINST_INIT) {
+                       ctx->dst_bufs_cnt = 0;
+                       ctx->src_bufs_cnt = 0;
+                       ctx->capture_state = QUEUE_FREE;
+                       ctx->output_state = QUEUE_FREE;
+                       s5p_mfc_alloc_instance_buffer(ctx);
+                       s5p_mfc_alloc_dec_temp_buffers(ctx);
+                       spin_lock_irqsave(&dev->condlock, flags);
+                       set_bit(ctx->num, &dev->ctx_work_bits);
+                       spin_unlock_irqrestore(&dev->condlock, flags);
+                       s5p_mfc_clean_ctx_int_flags(ctx);
+                       s5p_mfc_try_run(dev);
+
+                       if (s5p_mfc_wait_for_done_ctx(ctx,
+                               S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET, 0)) {
+                               /* Error or timeout */
+                               mfc_err("Error getting instance from hardware\n");
+                               s5p_mfc_release_instance_buffer(ctx);
+                               s5p_mfc_release_dec_desc_buffer(ctx);
+                               return -EIO;
+                       }
+                       mfc_debug(2, "Got instance number: %d\n", ctx->inst_no);
+               }
+               ret = vb2_streamon(&ctx->vq_src, type);
+               }
+       else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               ret = vb2_streamon(&ctx->vq_dst, type);
+       mfc_debug_leave();
+       return ret;
+}
+
+/* Stream off, which equals to a pause */
+static int vidioc_streamoff(struct file *file, void *priv,
+                           enum v4l2_buf_type type)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+       if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               return vb2_streamoff(&ctx->vq_src, type);
+       else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               return vb2_streamoff(&ctx->vq_dst, type);
+       return -EINVAL;
+}
+
+/* Set controls - v4l2 control framework */
+static int s5p_mfc_dec_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl);
+
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY:
+               ctx->loop_filter_mpeg4 = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE:
+               ctx->display_delay_enable = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:
+               ctx->display_delay = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE:
+               ctx->slice_interface = ctrl->val;
+               break;
+       default:
+               mfc_err("Invalid control 0x%08x\n", ctrl->id);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int s5p_mfc_dec_g_v_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl);
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       switch (ctrl->id) {
+       case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
+               if (ctx->state >= MFCINST_HEAD_PARSED &&
+                   ctx->state < MFCINST_ABORT) {
+                       ctrl->val = ctx->dpb_count;
+                       break;
+               } else if (ctx->state != MFCINST_INIT) {
+                       v4l2_err(&dev->v4l2_dev, "Decoding not initialised\n");
+                       return -EINVAL;
+               }
+               /* Should wait for the header to be parsed */
+               s5p_mfc_clean_ctx_int_flags(ctx);
+               s5p_mfc_wait_for_done_ctx(ctx,
+                               S5P_FIMV_R2H_CMD_SEQ_DONE_RET, 0);
+               if (ctx->state >= MFCINST_HEAD_PARSED &&
+                   ctx->state < MFCINST_ABORT) {
+                       ctrl->val = ctx->dpb_count;
+               } else {
+                       v4l2_err(&dev->v4l2_dev, "Decoding not initialised\n");
+                       return -EINVAL;
+               }
+               break;
+       }
+       return 0;
+}
+
+
+static const struct v4l2_ctrl_ops s5p_mfc_dec_ctrl_ops = {
+       .s_ctrl = s5p_mfc_dec_s_ctrl,
+       .g_volatile_ctrl = s5p_mfc_dec_g_v_ctrl,
+};
+
+/* Get cropping information */
+static int vidioc_g_crop(struct file *file, void *priv,
+               struct v4l2_crop *cr)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+       u32 left, right, top, bottom;
+
+       if (ctx->state != MFCINST_HEAD_PARSED &&
+       ctx->state != MFCINST_RUNNING && ctx->state != MFCINST_FINISHING
+                                       && ctx->state != MFCINST_FINISHED) {
+                       mfc_err("Cannont set crop\n");
+                       return -EINVAL;
+               }
+       if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_H264) {
+               left = s5p_mfc_read_shm(ctx, CROP_INFO_H);
+               right = left >> S5P_FIMV_SHARED_CROP_RIGHT_SHIFT;
+               left = left & S5P_FIMV_SHARED_CROP_LEFT_MASK;
+               top = s5p_mfc_read_shm(ctx, CROP_INFO_V);
+               bottom = top >> S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT;
+               top = top & S5P_FIMV_SHARED_CROP_TOP_MASK;
+               cr->c.left = left;
+               cr->c.top = top;
+               cr->c.width = ctx->img_width - left - right;
+               cr->c.height = ctx->img_height - top - bottom;
+               mfc_debug(2, "Cropping info [h264]: l=%d t=%d "
+                       "w=%d h=%d (r=%d b=%d fw=%d fh=%d\n", left, top,
+                       cr->c.width, cr->c.height, right, bottom,
+                       ctx->buf_width, ctx->buf_height);
+       } else {
+               cr->c.left = 0;
+               cr->c.top = 0;
+               cr->c.width = ctx->img_width;
+               cr->c.height = ctx->img_height;
+               mfc_debug(2, "Cropping info: w=%d h=%d fw=%d "
+                       "fh=%d\n", cr->c.width, cr->c.height, ctx->buf_width,
+                                                       ctx->buf_height);
+       }
+       return 0;
+}
+
+/* v4l2_ioctl_ops */
+static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = {
+       .vidioc_querycap = vidioc_querycap,
+       .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+       .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
+       .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
+       .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
+       .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt,
+       .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt,
+       .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt,
+       .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt,
+       .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt,
+       .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt,
+       .vidioc_reqbufs = vidioc_reqbufs,
+       .vidioc_querybuf = vidioc_querybuf,
+       .vidioc_qbuf = vidioc_qbuf,
+       .vidioc_dqbuf = vidioc_dqbuf,
+       .vidioc_streamon = vidioc_streamon,
+       .vidioc_streamoff = vidioc_streamoff,
+       .vidioc_g_crop = vidioc_g_crop,
+};
+
+static int s5p_mfc_queue_setup(struct vb2_queue *vq, unsigned int *buf_count,
+                              unsigned int *plane_count, unsigned long psize[],
+                              void *allocators[])
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+
+       /* Video output for decoding (source)
+        * this can be set after getting an instance */
+       if (ctx->state == MFCINST_INIT &&
+           vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               /* A single plane is required for input */
+               *plane_count = 1;
+               if (*buf_count < 1)
+                       *buf_count = 1;
+               if (*buf_count > MFC_MAX_BUFFERS)
+                       *buf_count = MFC_MAX_BUFFERS;
+       /* Video capture for decoding (destination)
+        * this can be set after the header was parsed */
+       } else if (ctx->state == MFCINST_HEAD_PARSED &&
+                  vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               /* Output plane count is 2 - one for Y and one for CbCr */
+               *plane_count = 2;
+               /* Setup buffer count */
+               if (*buf_count < ctx->dpb_count)
+                       *buf_count = ctx->dpb_count;
+               if (*buf_count > ctx->dpb_count + MFC_MAX_EXTRA_DPB)
+                       *buf_count = ctx->dpb_count + MFC_MAX_EXTRA_DPB;
+               if (*buf_count > MFC_MAX_BUFFERS)
+                       *buf_count = MFC_MAX_BUFFERS;
+       } else {
+               mfc_err("State seems invalid. State = %d, vq->type = %d\n",
+                                                       ctx->state, vq->type);
+               return -EINVAL;
+       }
+       mfc_debug(2, "Buffer count=%d, plane count=%d\n",
+                                               *buf_count, *plane_count);
+       if (ctx->state == MFCINST_HEAD_PARSED &&
+           vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               psize[0] = ctx->luma_size;
+               psize[1] = ctx->chroma_size;
+               allocators[0] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX];
+               allocators[1] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
+       } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
+                  ctx->state == MFCINST_INIT) {
+               psize[0] = ctx->dec_src_buf_size;
+               allocators[0] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
+       } else {
+               mfc_err("This video node is dedicated to decoding. Decoding not initalised\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static void s5p_mfc_unlock(struct vb2_queue *q)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       mutex_unlock(&dev->mfc_mutex);
+}
+
+static void s5p_mfc_lock(struct vb2_queue *q)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       mutex_lock(&dev->mfc_mutex);
+}
+
+static int s5p_mfc_buf_init(struct vb2_buffer *vb)
+{
+       struct vb2_queue *vq = vb->vb2_queue;
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+       unsigned int i;
+
+       if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               if (ctx->capture_state == QUEUE_BUFS_MMAPED)
+                       return 0;
+               for (i = 0; i <= ctx->src_fmt->num_planes ; i++) {
+                       if (IS_ERR_OR_NULL(ERR_PTR(
+                                       vb2_dma_contig_plane_paddr(vb, i)))) {
+                               mfc_err("Plane mem not allocated\n");
+                               return -EINVAL;
+                       }
+               }
+               if (vb2_plane_size(vb, 0) < ctx->luma_size ||
+                       vb2_plane_size(vb, 1) < ctx->chroma_size) {
+                       mfc_err("Plane buffer (CAPTURE) is too small\n");
+                       return -EINVAL;
+               }
+               i = vb->v4l2_buf.index;
+               ctx->dst_bufs[i].b = vb;
+               ctx->dst_bufs[i].cookie.raw.luma =
+                                       vb2_dma_contig_plane_paddr(vb, 0);
+               ctx->dst_bufs[i].cookie.raw.chroma =
+                                       vb2_dma_contig_plane_paddr(vb, 1);
+               ctx->dst_bufs_cnt++;
+       } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               if (IS_ERR_OR_NULL(ERR_PTR(
+                                       vb2_dma_contig_plane_paddr(vb, 0)))) {
+                       mfc_err("Plane memory not allocated\n");
+                       return -EINVAL;
+               }
+               if (vb2_plane_size(vb, 0) < ctx->dec_src_buf_size) {
+                       mfc_err("Plane buffer (OUTPUT) is too small\n");
+                       return -EINVAL;
+               }
+
+               i = vb->v4l2_buf.index;
+               ctx->src_bufs[i].b = vb;
+               ctx->src_bufs[i].cookie.stream =
+                                       vb2_dma_contig_plane_paddr(vb, 0);
+               ctx->src_bufs_cnt++;
+       } else {
+               mfc_err("s5p_mfc_buf_init: unknown queue type\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int s5p_mfc_start_streaming(struct vb2_queue *q)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned long flags;
+
+       v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
+       if (ctx->state == MFCINST_FINISHING ||
+               ctx->state == MFCINST_FINISHED)
+               ctx->state = MFCINST_RUNNING;
+       /* If context is ready then dev = work->data;schedule it to run */
+       if (s5p_mfc_ctx_ready(ctx)) {
+               spin_lock_irqsave(&dev->condlock, flags);
+               set_bit(ctx->num, &dev->ctx_work_bits);
+               spin_unlock_irqrestore(&dev->condlock, flags);
+       }
+       s5p_mfc_try_run(dev);
+       return 0;
+}
+
+static int s5p_mfc_stop_streaming(struct vb2_queue *q)
+{
+       unsigned long flags;
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+       struct s5p_mfc_dev *dev = ctx->dev;
+       int aborted = 0;
+
+       if ((ctx->state == MFCINST_FINISHING ||
+               ctx->state ==  MFCINST_RUNNING) &&
+               dev->curr_ctx == ctx->num && dev->hw_lock) {
+               ctx->state = MFCINST_ABORT;
+               s5p_mfc_wait_for_done_ctx(ctx,
+                                       S5P_FIMV_R2H_CMD_FRAME_DONE_RET, 0);
+               aborted = 1;
+       }
+       spin_lock_irqsave(&dev->irqlock, flags);
+       if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
+               INIT_LIST_HEAD(&ctx->dst_queue);
+               ctx->dst_queue_cnt = 0;
+               ctx->dpb_flush_flag = 1;
+               ctx->dec_dst_flag = 0;
+       }
+       if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
+               INIT_LIST_HEAD(&ctx->src_queue);
+               ctx->src_queue_cnt = 0;
+       }
+       if (aborted)
+               ctx->state = MFCINST_RUNNING;
+       spin_unlock_irqrestore(&dev->irqlock, flags);
+       return 0;
+}
+
+
+static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
+{
+       struct vb2_queue *vq = vb->vb2_queue;
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned long flags;
+       struct s5p_mfc_buf *mfc_buf;
+
+       if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               mfc_buf = &ctx->src_bufs[vb->v4l2_buf.index];
+               mfc_buf->used = 0;
+               spin_lock_irqsave(&dev->irqlock, flags);
+               list_add_tail(&mfc_buf->list, &ctx->src_queue);
+               ctx->src_queue_cnt++;
+               spin_unlock_irqrestore(&dev->irqlock, flags);
+       } else if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               mfc_buf = &ctx->dst_bufs[vb->v4l2_buf.index];
+               mfc_buf->used = 0;
+               /* Mark destination as available for use by MFC */
+               spin_lock_irqsave(&dev->irqlock, flags);
+               set_bit(vb->v4l2_buf.index, &ctx->dec_dst_flag);
+               list_add_tail(&mfc_buf->list, &ctx->dst_queue);
+               ctx->dst_queue_cnt++;
+               spin_unlock_irqrestore(&dev->irqlock, flags);
+       } else {
+               mfc_err("Unsupported buffer type (%d)\n", vq->type);
+       }
+       if (s5p_mfc_ctx_ready(ctx)) {
+               spin_lock_irqsave(&dev->condlock, flags);
+               set_bit(ctx->num, &dev->ctx_work_bits);
+               spin_unlock_irqrestore(&dev->condlock, flags);
+       }
+       s5p_mfc_try_run(dev);
+}
+
+static struct vb2_ops s5p_mfc_dec_qops = {
+       .queue_setup            = s5p_mfc_queue_setup,
+       .wait_prepare           = s5p_mfc_unlock,
+       .wait_finish            = s5p_mfc_lock,
+       .buf_init               = s5p_mfc_buf_init,
+       .start_streaming        = s5p_mfc_start_streaming,
+       .stop_streaming         = s5p_mfc_stop_streaming,
+       .buf_queue              = s5p_mfc_buf_queue,
+};
+
+struct s5p_mfc_codec_ops *get_dec_codec_ops(void)
+{
+       return &decoder_codec_ops;
+}
+
+struct vb2_ops *get_dec_queue_ops(void)
+{
+       return &s5p_mfc_dec_qops;
+}
+
+const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void)
+{
+       return &s5p_mfc_dec_ioctl_ops;
+}
+
+#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2CLASS(x) == V4L2_CTRL_CLASS_MPEG) \
+                                               && V4L2_CTRL_DRIVER_PRIV(x))
+
+int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx)
+{
+       struct v4l2_ctrl_config cfg;
+       int i;
+
+       v4l2_ctrl_handler_init(&ctx->ctrl_handler, NUM_CTRLS);
+       if (ctx->ctrl_handler.error) {
+               mfc_err("v4l2_ctrl_handler_init failed\n");
+               return ctx->ctrl_handler.error;
+       }
+
+       for (i = 0; i < NUM_CTRLS; i++) {
+               if (IS_MFC51_PRIV(controls[i].id)) {
+                       cfg.ops = &s5p_mfc_dec_ctrl_ops;
+                       cfg.id = controls[i].id;
+                       cfg.min = controls[i].minimum;
+                       cfg.max = controls[i].maximum;
+                       cfg.def = controls[i].default_value;
+                       cfg.name = controls[i].name;
+                       cfg.type = controls[i].type;
+
+                       cfg.step = controls[i].step;
+                       cfg.menu_skip_mask = 0;
+
+                       ctx->ctrls[i] = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
+                                       &cfg, NULL);
+               } else {
+                       ctx->ctrls[i] = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+                                       &s5p_mfc_dec_ctrl_ops,
+                                       controls[i].id, controls[i].minimum,
+                                       controls[i].maximum, controls[i].step,
+                                       controls[i].default_value);
+               }
+               if (ctx->ctrl_handler.error) {
+                       mfc_err("Adding control (%d) failed\n", i);
+                       return ctx->ctrl_handler.error;
+               }
+               if (controls[i].is_volatile && ctx->ctrls[i])
+                       ctx->ctrls[i]->is_volatile = 1;
+       }
+       return 0;
+}
+
+void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx)
+{
+       int i;
+
+       v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+       for (i = 0; i < NUM_CTRLS; i++)
+               ctx->ctrls[i] = NULL;
+}
+
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_dec.h b/drivers/media/video/s5p-mfc/s5p_mfc_dec.h
new file mode 100644 (file)
index 0000000..fb8b215
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * linux/drivers/media/video/s5p-mfc/s5p_mfc_dec.h
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.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.
+ */
+
+#ifndef S5P_MFC_DEC_H_
+#define S5P_MFC_DEC_H_
+
+struct s5p_mfc_codec_ops *get_dec_codec_ops(void);
+struct vb2_ops *get_dec_queue_ops(void);
+const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void);
+struct s5p_mfc_fmt *get_dec_def_fmt(bool src);
+int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx);
+
+#endif /* S5P_MFC_DEC_H_ */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c
new file mode 100644 (file)
index 0000000..fee094a
--- /dev/null
@@ -0,0 +1,1829 @@
+/*
+ * linux/drivers/media/video/s5p-mfc/s5p_mfc_enc.c
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * Jeongtae Park       <jtp.park@samsung.com>
+ * Kamil Debski                <k.debski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
+#include <linux/workqueue.h>
+#include <media/v4l2-ctrls.h>
+#include <media/videobuf2-core.h>
+#include "regs-mfc.h"
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_enc.h"
+#include "s5p_mfc_intr.h"
+#include "s5p_mfc_opr.h"
+
+static struct s5p_mfc_fmt formats[] = {
+       {
+               .name = "4:2:0 2 Planes 64x32 Tiles",
+               .fourcc = V4L2_PIX_FMT_NV12MT,
+               .codec_mode = S5P_FIMV_CODEC_NONE,
+               .type = MFC_FMT_RAW,
+               .num_planes = 2,
+       },
+       {
+               .name = "4:2:0 2 Planes",
+               .fourcc = V4L2_PIX_FMT_NV12M,
+               .codec_mode = S5P_FIMV_CODEC_NONE,
+               .type = MFC_FMT_RAW,
+               .num_planes = 2,
+       },
+       {
+               .name = "H264 Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_H264,
+               .codec_mode = S5P_FIMV_CODEC_H264_ENC,
+               .type = MFC_FMT_ENC,
+               .num_planes = 1,
+       },
+       {
+               .name = "MPEG4 Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_MPEG4,
+               .codec_mode = S5P_FIMV_CODEC_MPEG4_ENC,
+               .type = MFC_FMT_ENC,
+               .num_planes = 1,
+       },
+       {
+               .name = "H264 Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_H263,
+               .codec_mode = S5P_FIMV_CODEC_H263_ENC,
+               .type = MFC_FMT_ENC,
+               .num_planes = 1,
+       },
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+static struct s5p_mfc_fmt *find_format(struct v4l2_format *f, unsigned int t)
+{
+       unsigned int i;
+
+       for (i = 0; i < NUM_FORMATS; i++) {
+               if (formats[i].fourcc == f->fmt.pix_mp.pixelformat &&
+                   formats[i].type == t)
+                       return &formats[i];
+       }
+       return NULL;
+}
+
+static struct mfc_control controls[] = {
+       {
+               .id = V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = (1 << 16) - 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
+               .type = V4L2_CTRL_TYPE_MENU,
+               .minimum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
+               .maximum = V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES,
+               .default_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
+               .menu_skip_mask = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 1,
+               .maximum = (1 << 16) - 1,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 1900,
+               .maximum = (1 << 30) - 1,
+               .step = 1,
+               .default_value = 1900,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = (1 << 16) - 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_MFC51_VIDEO_PADDING,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .name = "Padding Control Enable",
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Padding Color YUV Value",
+               .minimum = 0,
+               .maximum = (1 << 25) - 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_BITRATE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 1,
+               .maximum = (1 << 30) - 1,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Rate Control Reaction Coeff.",
+               .minimum = 1,
+               .maximum = (1 << 16) - 1,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE,
+               .type = V4L2_CTRL_TYPE_MENU,
+               .name = "Force frame type",
+               .minimum = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED,
+               .maximum = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_NOT_CODED,
+               .default_value = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED,
+               .menu_skip_mask = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_VBV_SIZE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = (1 << 16) - 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = (1 << 16) - 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_HEADER_MODE,
+               .type = V4L2_CTRL_TYPE_MENU,
+               .minimum = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
+               .maximum = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
+               .default_value = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
+               .menu_skip_mask = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE,
+               .type = V4L2_CTRL_TYPE_MENU,
+               .name = "Frame Skip Enable",
+               .minimum = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED,
+               .maximum = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT,
+               .menu_skip_mask = 0,
+               .default_value = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED,
+       },
+       {
+               .id = V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .name = "Fixed Target Bit Enable",
+               .minimum = 0,
+               .maximum = 1,
+               .default_value = 0,
+               .menu_skip_mask = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_B_FRAMES,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = 2,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+               .type = V4L2_CTRL_TYPE_MENU,
+               .minimum = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+               .maximum = V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH,
+               .default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+               .menu_skip_mask = ~(
+                               (1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
+                               (1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
+                               (1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)
+                               ),
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+               .type = V4L2_CTRL_TYPE_MENU,
+               .minimum = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+               .maximum = V4L2_MPEG_VIDEO_H264_LEVEL_4_0,
+               .default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+               .menu_skip_mask = ~(
+                               (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_1) |
+                               (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_2) |
+                               (1 << V4L2_MPEG_VIDEO_H264_LEVEL_5_0) |
+                               (1 << V4L2_MPEG_VIDEO_H264_LEVEL_5_1)
+                               ),
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
+               .type = V4L2_CTRL_TYPE_MENU,
+               .minimum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+               .maximum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5,
+               .default_value = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+               .menu_skip_mask = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+               .type = V4L2_CTRL_TYPE_MENU,
+               .minimum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
+               .maximum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY,
+               .default_value = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
+               .menu_skip_mask = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = -6,
+               .maximum = 6,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = -6,
+               .maximum = 6,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
+               .type = V4L2_CTRL_TYPE_MENU,
+               .minimum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+               .maximum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
+               .default_value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+               .menu_skip_mask = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "The Number of Ref. Pic for P",
+               .minimum = 1,
+               .maximum = 2,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = 51,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = 51,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = 51,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = 51,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = 51,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "H263 I-Frame QP value",
+               .minimum = 1,
+               .maximum = 31,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H263_MIN_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "H263 Minimum QP value",
+               .minimum = 1,
+               .maximum = 31,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H263_MAX_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "H263 Maximum QP value",
+               .minimum = 1,
+               .maximum = 31,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "H263 P frame QP value",
+               .minimum = 1,
+               .maximum = 31,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "H263 B frame QP value",
+               .minimum = 1,
+               .maximum = 31,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "MPEG4 I-Frame QP value",
+               .minimum = 1,
+               .maximum = 31,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "MPEG4 Minimum QP value",
+               .minimum = 1,
+               .maximum = 31,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "MPEG4 Maximum QP value",
+               .minimum = 0,
+               .maximum = 51,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "MPEG4 P frame QP value",
+               .minimum = 1,
+               .maximum = 31,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "MPEG4 B frame QP value",
+               .minimum = 1,
+               .maximum = 31,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .name = "H264 Dark Reg Adaptive RC",
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .name = "H264 Smooth Reg Adaptive RC",
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .name = "H264 Static Reg Adaptive RC",
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .name = "H264 Activity Reg Adaptive RC",
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC,
+               .type = V4L2_CTRL_TYPE_MENU,
+               .minimum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED,
+               .maximum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED,
+               .default_value = 0,
+               .menu_skip_mask = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = (1 << 16) - 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = (1 << 16) - 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = (1 << 16) - 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
+               .type = V4L2_CTRL_TYPE_MENU,
+               .minimum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
+               .maximum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE,
+               .default_value = 0,
+               .menu_skip_mask = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_MPEG4_QPEL,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 0,
+       },
+};
+
+#define NUM_CTRLS ARRAY_SIZE(controls)
+static const char * const *mfc51_get_menu(u32 id)
+{
+       static const char * const mfc51_video_frame_skip[] = {
+               "Disabled",
+               "Level Limit",
+               "VBV/CPB Limit",
+               NULL,
+       };
+       static const char * const mfc51_video_force_frame[] = {
+               "Disabled",
+               "I Frame",
+               "Not Coded",
+               NULL,
+       };
+       switch (id) {
+       case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE:
+               return mfc51_video_frame_skip;
+       case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
+               return mfc51_video_force_frame;
+       }
+       return NULL;
+}
+
+static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx)
+{
+       mfc_debug(2, "src=%d, dst=%d, state=%d\n",
+                 ctx->src_queue_cnt, ctx->dst_queue_cnt, ctx->state);
+       /* context is ready to make header */
+       if (ctx->state == MFCINST_GOT_INST && ctx->dst_queue_cnt >= 1)
+               return 1;
+       /* context is ready to encode a frame */
+       if (ctx->state == MFCINST_RUNNING &&
+               ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1)
+               return 1;
+       /* context is ready to encode remain frames */
+       if (ctx->state == MFCINST_FINISHING &&
+               ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1)
+               return 1;
+       mfc_debug(2, "ctx is not ready\n");
+       return 0;
+}
+
+static void cleanup_ref_queue(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_buf *mb_entry;
+       unsigned long mb_y_addr, mb_c_addr;
+
+       /* move buffers in ref queue to src queue */
+       while (!list_empty(&ctx->ref_queue)) {
+               mb_entry = list_entry((&ctx->ref_queue)->next,
+                                               struct s5p_mfc_buf, list);
+               mb_y_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 0);
+               mb_c_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 1);
+               list_del(&mb_entry->list);
+               ctx->ref_queue_cnt--;
+               list_add_tail(&mb_entry->list, &ctx->src_queue);
+               ctx->src_queue_cnt++;
+       }
+       mfc_debug(2, "enc src count: %d, enc ref count: %d\n",
+                 ctx->src_queue_cnt, ctx->ref_queue_cnt);
+       INIT_LIST_HEAD(&ctx->ref_queue);
+       ctx->ref_queue_cnt = 0;
+}
+
+static int enc_pre_seq_start(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_buf *dst_mb;
+       unsigned long dst_addr;
+       unsigned int dst_size;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->irqlock, flags);
+       dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
+       dst_addr = vb2_dma_contig_plane_paddr(dst_mb->b, 0);
+       dst_size = vb2_plane_size(dst_mb->b, 0);
+       s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
+       spin_unlock_irqrestore(&dev->irqlock, flags);
+       return 0;
+}
+
+static int enc_post_seq_start(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_enc_params *p = &ctx->enc_params;
+       struct s5p_mfc_buf *dst_mb;
+       unsigned long flags;
+
+       if (p->seq_hdr_mode == V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) {
+               spin_lock_irqsave(&dev->irqlock, flags);
+               dst_mb = list_entry(ctx->dst_queue.next,
+                               struct s5p_mfc_buf, list);
+               list_del(&dst_mb->list);
+               ctx->dst_queue_cnt--;
+               vb2_set_plane_payload(dst_mb->b, 0,
+                                               s5p_mfc_get_enc_strm_size());
+               vb2_buffer_done(dst_mb->b, VB2_BUF_STATE_DONE);
+               spin_unlock_irqrestore(&dev->irqlock, flags);
+       }
+       ctx->state = MFCINST_RUNNING;
+       if (s5p_mfc_ctx_ready(ctx)) {
+               spin_lock_irqsave(&dev->condlock, flags);
+               set_bit(ctx->num, &dev->ctx_work_bits);
+               spin_unlock_irqrestore(&dev->condlock, flags);
+       }
+       s5p_mfc_try_run(dev);
+       return 0;
+}
+
+static int enc_pre_frame_start(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_buf *dst_mb;
+       struct s5p_mfc_buf *src_mb;
+       unsigned long flags;
+       unsigned long src_y_addr, src_c_addr, dst_addr;
+       unsigned int dst_size;
+
+       spin_lock_irqsave(&dev->irqlock, flags);
+       src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+       src_y_addr = vb2_dma_contig_plane_paddr(src_mb->b, 0);
+       src_c_addr = vb2_dma_contig_plane_paddr(src_mb->b, 1);
+       s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, src_c_addr);
+       spin_unlock_irqrestore(&dev->irqlock, flags);
+
+       spin_lock_irqsave(&dev->irqlock, flags);
+       dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
+       dst_addr = vb2_dma_contig_plane_paddr(dst_mb->b, 0);
+       dst_size = vb2_plane_size(dst_mb->b, 0);
+       s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
+       spin_unlock_irqrestore(&dev->irqlock, flags);
+
+       return 0;
+}
+
+static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_buf *mb_entry;
+       unsigned long enc_y_addr, enc_c_addr;
+       unsigned long mb_y_addr, mb_c_addr;
+       int slice_type;
+       unsigned int strm_size;
+       unsigned long flags;
+
+       slice_type = s5p_mfc_get_enc_slice_type();
+       strm_size = s5p_mfc_get_enc_strm_size();
+       mfc_debug(2, "Encoded slice type: %d", slice_type);
+       mfc_debug(2, "Encoded stream size: %d", strm_size);
+       mfc_debug(2, "Display order: %d",
+                 mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT));
+       spin_lock_irqsave(&dev->irqlock, flags);
+       if (slice_type >= 0) {
+               s5p_mfc_get_enc_frame_buffer(ctx, &enc_y_addr, &enc_c_addr);
+               list_for_each_entry(mb_entry, &ctx->src_queue, list) {
+                       mb_y_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 0);
+                       mb_c_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 1);
+                       if ((enc_y_addr == mb_y_addr) &&
+                                               (enc_c_addr == mb_c_addr)) {
+                               list_del(&mb_entry->list);
+                               ctx->src_queue_cnt--;
+                               vb2_buffer_done(mb_entry->b,
+                                                       VB2_BUF_STATE_DONE);
+                               break;
+                       }
+               }
+               list_for_each_entry(mb_entry, &ctx->ref_queue, list) {
+                       mb_y_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 0);
+                       mb_c_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 1);
+                       if ((enc_y_addr == mb_y_addr) &&
+                                               (enc_c_addr == mb_c_addr)) {
+                               list_del(&mb_entry->list);
+                               ctx->ref_queue_cnt--;
+                               vb2_buffer_done(mb_entry->b,
+                                                       VB2_BUF_STATE_DONE);
+                               break;
+                       }
+               }
+       }
+       if ((ctx->src_queue_cnt > 0) && (ctx->state == MFCINST_RUNNING)) {
+               mb_entry = list_entry(ctx->src_queue.next, struct s5p_mfc_buf,
+                                                                       list);
+               if (mb_entry->used) {
+                       list_del(&mb_entry->list);
+                       ctx->src_queue_cnt--;
+                       list_add_tail(&mb_entry->list, &ctx->ref_queue);
+                       ctx->ref_queue_cnt++;
+               }
+               mfc_debug(2, "enc src count: %d, enc ref count: %d\n",
+                         ctx->src_queue_cnt, ctx->ref_queue_cnt);
+       }
+       if (strm_size > 0) {
+               /* at least one more dest. buffers exist always  */
+               mb_entry = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf,
+                                                                       list);
+               list_del(&mb_entry->list);
+               ctx->dst_queue_cnt--;
+               switch (slice_type) {
+               case S5P_FIMV_ENC_SI_SLICE_TYPE_I:
+                       mb_entry->b->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+                       break;
+               case S5P_FIMV_ENC_SI_SLICE_TYPE_P:
+                       mb_entry->b->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
+                       break;
+               case S5P_FIMV_ENC_SI_SLICE_TYPE_B:
+                       mb_entry->b->v4l2_buf.flags |= V4L2_BUF_FLAG_BFRAME;
+                       break;
+               }
+               vb2_set_plane_payload(mb_entry->b, 0, strm_size);
+               vb2_buffer_done(mb_entry->b, VB2_BUF_STATE_DONE);
+       }
+       spin_unlock_irqrestore(&dev->irqlock, flags);
+       if ((ctx->src_queue_cnt == 0) || (ctx->dst_queue_cnt == 0)) {
+               spin_lock(&dev->condlock);
+               clear_bit(ctx->num, &dev->ctx_work_bits);
+               spin_unlock(&dev->condlock);
+       }
+       return 0;
+}
+
+static struct s5p_mfc_codec_ops encoder_codec_ops = {
+       .pre_seq_start          = enc_pre_seq_start,
+       .post_seq_start         = enc_post_seq_start,
+       .pre_frame_start        = enc_pre_frame_start,
+       .post_frame_start       = enc_post_frame_start,
+};
+
+/* Query capabilities of the device */
+static int vidioc_querycap(struct file *file, void *priv,
+                          struct v4l2_capability *cap)
+{
+       struct s5p_mfc_dev *dev = video_drvdata(file);
+
+       strncpy(cap->driver, dev->plat_dev->name, sizeof(cap->driver) - 1);
+       strncpy(cap->card, dev->plat_dev->name, sizeof(cap->card) - 1);
+       cap->bus_info[0] = 0;
+       cap->version = KERNEL_VERSION(1, 0, 0);
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
+                         | V4L2_CAP_VIDEO_OUTPUT
+                         | V4L2_CAP_STREAMING;
+       return 0;
+}
+
+static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool mplane, bool out)
+{
+       struct s5p_mfc_fmt *fmt;
+       int i, j = 0;
+
+       for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+               if (mplane && formats[i].num_planes == 1)
+                       continue;
+               else if (!mplane && formats[i].num_planes > 1)
+                       continue;
+               if (out && formats[i].type != MFC_FMT_RAW)
+                       continue;
+               else if (!out && formats[i].type != MFC_FMT_ENC)
+                       continue;
+               if (j == f->index) {
+                       fmt = &formats[i];
+                       strlcpy(f->description, fmt->name,
+                               sizeof(f->description));
+                       f->pixelformat = fmt->fourcc;
+                       return 0;
+               }
+               ++j;
+       }
+       return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv,
+                                  struct v4l2_fmtdesc *f)
+{
+       return vidioc_enum_fmt(f, false, false);
+}
+
+static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
+                                         struct v4l2_fmtdesc *f)
+{
+       return vidioc_enum_fmt(f, true, false);
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *prov,
+                                  struct v4l2_fmtdesc *f)
+{
+       return vidioc_enum_fmt(f, false, true);
+}
+
+static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov,
+                                         struct v4l2_fmtdesc *f)
+{
+       return vidioc_enum_fmt(f, true, true);
+}
+
+static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+       struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+
+       mfc_debug(2, "f->type = %d ctx->state = %d\n", f->type, ctx->state);
+       if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               /* This is run on output (encoder dest) */
+               pix_fmt_mp->width = 0;
+               pix_fmt_mp->height = 0;
+               pix_fmt_mp->field = V4L2_FIELD_NONE;
+               pix_fmt_mp->pixelformat = ctx->dst_fmt->fourcc;
+               pix_fmt_mp->num_planes = ctx->dst_fmt->num_planes;
+
+               pix_fmt_mp->plane_fmt[0].bytesperline = ctx->enc_dst_buf_size;
+               pix_fmt_mp->plane_fmt[0].sizeimage = ctx->enc_dst_buf_size;
+       } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               /* This is run on capture (encoder src) */
+               pix_fmt_mp->width = ctx->img_width;
+               pix_fmt_mp->height = ctx->img_height;
+
+               pix_fmt_mp->field = V4L2_FIELD_NONE;
+               pix_fmt_mp->pixelformat = ctx->src_fmt->fourcc;
+               pix_fmt_mp->num_planes = ctx->src_fmt->num_planes;
+
+               pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
+               pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
+               pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
+               pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
+       } else {
+               mfc_err("invalid buf type\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+       struct s5p_mfc_fmt *fmt;
+       struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+
+       if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               fmt = find_format(f, MFC_FMT_ENC);
+               if (!fmt) {
+                       mfc_err("failed to try output format\n");
+                       return -EINVAL;
+               }
+
+               if (pix_fmt_mp->plane_fmt[0].sizeimage == 0) {
+                       mfc_err("must be set encoding output size\n");
+                       return -EINVAL;
+               }
+
+               pix_fmt_mp->plane_fmt[0].bytesperline =
+                       pix_fmt_mp->plane_fmt[0].sizeimage;
+       } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               fmt = find_format(f, MFC_FMT_RAW);
+               if (!fmt) {
+                       mfc_err("failed to try output format\n");
+                       return -EINVAL;
+               }
+
+               if (fmt->num_planes != pix_fmt_mp->num_planes) {
+                       mfc_err("failed to try output format\n");
+                       return -EINVAL;
+               }
+       } else {
+               mfc_err("invalid buf type\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+       struct s5p_mfc_dev *dev = video_drvdata(file);
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+       struct s5p_mfc_fmt *fmt;
+       struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+       unsigned long flags;
+       int ret = 0;
+
+       ret = vidioc_try_fmt(file, priv, f);
+       if (ret)
+               return ret;
+       if (ctx->vq_src.streaming || ctx->vq_dst.streaming) {
+               v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__);
+               ret = -EBUSY;
+               goto out;
+       }
+       if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               fmt = find_format(f, MFC_FMT_ENC);
+               if (!fmt) {
+                       mfc_err("failed to set capture format\n");
+                       return -EINVAL;
+               }
+               ctx->state = MFCINST_INIT;
+               ctx->dst_fmt = fmt;
+               ctx->codec_mode = ctx->dst_fmt->codec_mode;
+               ctx->enc_dst_buf_size = pix_fmt_mp->plane_fmt[0].sizeimage;
+               pix_fmt_mp->plane_fmt[0].bytesperline = 0;
+               ctx->dst_bufs_cnt = 0;
+               ctx->capture_state = QUEUE_FREE;
+               s5p_mfc_alloc_instance_buffer(ctx);
+               spin_lock_irqsave(&dev->condlock, flags);
+               set_bit(ctx->num, &dev->ctx_work_bits);
+               spin_unlock_irqrestore(&dev->condlock, flags);
+               s5p_mfc_clean_ctx_int_flags(ctx);
+               s5p_mfc_try_run(dev);
+               if (s5p_mfc_wait_for_done_ctx(ctx, \
+                               S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET, 1)) {
+                               /* Error or timeout */
+                       mfc_err("Error getting instance from hardware\n");
+                       s5p_mfc_release_instance_buffer(ctx);
+                       ret = -EIO;
+                       goto out;
+               }
+               mfc_debug(2, "Got instance number: %d\n", ctx->inst_no);
+       } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               fmt = find_format(f, MFC_FMT_RAW);
+               if (!fmt) {
+                       mfc_err("failed to set output format\n");
+                       return -EINVAL;
+               }
+               if (fmt->num_planes != pix_fmt_mp->num_planes) {
+                       mfc_err("failed to set output format\n");
+                       ret = -EINVAL;
+                       goto out;
+               }
+               ctx->src_fmt = fmt;
+               ctx->img_width = pix_fmt_mp->width;
+               ctx->img_height = pix_fmt_mp->height;
+               mfc_debug(2, "codec number: %d\n", ctx->src_fmt->codec_mode);
+               mfc_debug(2, "fmt - w: %d, h: %d, ctx - w: %d, h: %d\n",
+                       pix_fmt_mp->width, pix_fmt_mp->height,
+                       ctx->img_width, ctx->img_height);
+               if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) {
+                       ctx->buf_width = ALIGN(ctx->img_width,
+                                                       S5P_FIMV_NV12M_HALIGN);
+                       ctx->luma_size = ALIGN(ctx->img_width,
+                               S5P_FIMV_NV12M_HALIGN) * ALIGN(ctx->img_height,
+                               S5P_FIMV_NV12M_LVALIGN);
+                       ctx->chroma_size = ALIGN(ctx->img_width,
+                               S5P_FIMV_NV12M_HALIGN) * ALIGN((ctx->img_height
+                               >> 1), S5P_FIMV_NV12M_CVALIGN);
+
+                       ctx->luma_size = ALIGN(ctx->luma_size,
+                                                       S5P_FIMV_NV12M_SALIGN);
+                       ctx->chroma_size = ALIGN(ctx->chroma_size,
+                                                       S5P_FIMV_NV12M_SALIGN);
+
+                       pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
+                       pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
+                       pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
+                       pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
+
+               } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) {
+                       ctx->buf_width = ALIGN(ctx->img_width,
+                                                       S5P_FIMV_NV12MT_HALIGN);
+                       ctx->luma_size = ALIGN(ctx->img_width,
+                               S5P_FIMV_NV12MT_HALIGN) * ALIGN(ctx->img_height,
+                               S5P_FIMV_NV12MT_VALIGN);
+                       ctx->chroma_size = ALIGN(ctx->img_width,
+                               S5P_FIMV_NV12MT_HALIGN) * ALIGN((ctx->img_height
+                               >> 1), S5P_FIMV_NV12MT_VALIGN);
+                       ctx->luma_size = ALIGN(ctx->luma_size,
+                                                       S5P_FIMV_NV12MT_SALIGN);
+                       ctx->chroma_size = ALIGN(ctx->chroma_size,
+                                                       S5P_FIMV_NV12MT_SALIGN);
+
+                       pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
+                       pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
+                       pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
+                       pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
+               }
+               ctx->src_bufs_cnt = 0;
+               ctx->output_state = QUEUE_FREE;
+       } else {
+               mfc_err("invalid buf type\n");
+               return -EINVAL;
+       }
+out:
+       mfc_debug_leave();
+       return ret;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+                                         struct v4l2_requestbuffers *reqbufs)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+       int ret = 0;
+
+       /* if memory is not mmp or userptr return error */
+       if ((reqbufs->memory != V4L2_MEMORY_MMAP) &&
+               (reqbufs->memory != V4L2_MEMORY_USERPTR))
+               return -EINVAL;
+       if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               if (ctx->capture_state != QUEUE_FREE) {
+                       mfc_err("invalid capture state: %d\n",
+                                                       ctx->capture_state);
+                       return -EINVAL;
+               }
+               ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+               if (ret != 0) {
+                       mfc_err("error in vb2_reqbufs() for E(D)\n");
+                       return ret;
+               }
+               ctx->capture_state = QUEUE_BUFS_REQUESTED;
+               ret = s5p_mfc_alloc_codec_buffers(ctx);
+               if (ret) {
+                       mfc_err("Failed to allocate encoding buffers\n");
+                       reqbufs->count = 0;
+                       ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+                       return -ENOMEM;
+               }
+       } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               if (ctx->output_state != QUEUE_FREE) {
+                       mfc_err("invalid output state: %d\n",
+                                                       ctx->output_state);
+                       return -EINVAL;
+               }
+               ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
+               if (ret != 0) {
+                       mfc_err("error in vb2_reqbufs() for E(S)\n");
+                       return ret;
+               }
+               ctx->output_state = QUEUE_BUFS_REQUESTED;
+       } else {
+               mfc_err("invalid buf type\n");
+               return -EINVAL;
+       }
+       return ret;
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+                                                  struct v4l2_buffer *buf)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+       int ret = 0;
+
+       /* if memory is not mmp or userptr return error */
+       if ((buf->memory != V4L2_MEMORY_MMAP) &&
+               (buf->memory != V4L2_MEMORY_USERPTR))
+               return -EINVAL;
+       if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               if (ctx->state != MFCINST_GOT_INST) {
+                       mfc_err("invalid context state: %d\n", ctx->state);
+                       return -EINVAL;
+               }
+               ret = vb2_querybuf(&ctx->vq_dst, buf);
+               if (ret != 0) {
+                       mfc_err("error in vb2_querybuf() for E(D)\n");
+                       return ret;
+               }
+               buf->m.planes[0].m.mem_offset += DST_QUEUE_OFF_BASE;
+       } else if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               ret = vb2_querybuf(&ctx->vq_src, buf);
+               if (ret != 0) {
+                       mfc_err("error in vb2_querybuf() for E(S)\n");
+                       return ret;
+               }
+       } else {
+               mfc_err("invalid buf type\n");
+               return -EINVAL;
+       }
+       return ret;
+}
+
+/* Queue a buffer */
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+       if (ctx->state == MFCINST_ERROR) {
+               mfc_err("Call on QBUF after unrecoverable error\n");
+               return -EIO;
+       }
+       if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               return vb2_qbuf(&ctx->vq_src, buf);
+       else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               return vb2_qbuf(&ctx->vq_dst, buf);
+       return -EINVAL;
+}
+
+/* Dequeue a buffer */
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+       if (ctx->state == MFCINST_ERROR) {
+               mfc_err("Call on DQBUF after unrecoverable error\n");
+               return -EIO;
+       }
+       if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               return vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK);
+       else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               return vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK);
+       return -EINVAL;
+}
+
+/* Stream on */
+static int vidioc_streamon(struct file *file, void *priv,
+                          enum v4l2_buf_type type)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+       if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               return vb2_streamon(&ctx->vq_src, type);
+       else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               return vb2_streamon(&ctx->vq_dst, type);
+       return -EINVAL;
+}
+
+/* Stream off, which equals to a pause */
+static int vidioc_streamoff(struct file *file, void *priv,
+                           enum v4l2_buf_type type)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+       if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               return vb2_streamoff(&ctx->vq_src, type);
+       else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               return vb2_streamoff(&ctx->vq_dst, type);
+       return -EINVAL;
+}
+
+static inline int h264_level(enum v4l2_mpeg_video_h264_level lvl)
+{
+       static unsigned int t[V4L2_MPEG_VIDEO_H264_LEVEL_4_0 + 1] = {
+               /* V4L2_MPEG_VIDEO_H264_LEVEL_1_0   */ 10,
+               /* V4L2_MPEG_VIDEO_H264_LEVEL_1B    */ 9,
+               /* V4L2_MPEG_VIDEO_H264_LEVEL_1_1   */ 11,
+               /* V4L2_MPEG_VIDEO_H264_LEVEL_1_2   */ 12,
+               /* V4L2_MPEG_VIDEO_H264_LEVEL_1_3   */ 13,
+               /* V4L2_MPEG_VIDEO_H264_LEVEL_2_0   */ 20,
+               /* V4L2_MPEG_VIDEO_H264_LEVEL_2_1   */ 21,
+               /* V4L2_MPEG_VIDEO_H264_LEVEL_2_2   */ 22,
+               /* V4L2_MPEG_VIDEO_H264_LEVEL_3_0   */ 30,
+               /* V4L2_MPEG_VIDEO_H264_LEVEL_3_1   */ 31,
+               /* V4L2_MPEG_VIDEO_H264_LEVEL_3_2   */ 32,
+               /* V4L2_MPEG_VIDEO_H264_LEVEL_4_0   */ 40,
+       };
+       return t[lvl];
+}
+
+static inline int mpeg4_level(enum v4l2_mpeg_video_mpeg4_level lvl)
+{
+       static unsigned int t[V4L2_MPEG_VIDEO_MPEG4_LEVEL_5 + 1] = {
+               /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_0    */ 0,
+               /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B   */ 9,
+               /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_1    */ 1,
+               /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_2    */ 2,
+               /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_3    */ 3,
+               /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B   */ 7,
+               /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_4    */ 4,
+               /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_5    */ 5,
+       };
+       return t[lvl];
+}
+
+static inline int vui_sar_idc(enum v4l2_mpeg_video_h264_vui_sar_idc sar)
+{
+       static unsigned int t[V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED + 1] = {
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED     */ 0,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1             */ 1,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_12x11           */ 2,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_10x11           */ 3,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_16x11           */ 4,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_40x33           */ 5,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_24x11           */ 6,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_20x11           */ 7,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_32x11           */ 8,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_80x33           */ 9,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_18x11           */ 10,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_15x11           */ 11,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_64x33           */ 12,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_160x99          */ 13,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_4x3             */ 14,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_3x2             */ 15,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1             */ 16,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED        */ 255,
+       };
+       return t[sar];
+}
+
+static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl);
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_enc_params *p = &ctx->enc_params;
+       int ret = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+               p->gop_size = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+               p->slice_mode = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+               p->slice_mb = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
+               p->slice_bit = ctrl->val * 8;
+               break;
+       case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
+               p->intra_refresh_mb = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_MFC51_VIDEO_PADDING:
+               p->pad = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV:
+               p->pad_luma = (ctrl->val >> 16) & 0xff;
+               p->pad_cb = (ctrl->val >> 8) & 0xff;
+               p->pad_cr = (ctrl->val >> 0) & 0xff;
+               break;
+       case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
+               p->rc_frame = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE:
+               p->rc_bitrate = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF:
+               p->rc_reaction_coeff = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
+               ctx->force_frame_type = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_VBV_SIZE:
+               p->vbv_size = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE:
+               p->codec.h264.cpb_size = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
+               p->seq_hdr_mode = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE:
+               p->frame_skip_mode = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT:
+               p->fixed_target_bit = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+               p->num_b_frame = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+               switch (ctrl->val) {
+               case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+                       p->codec.h264.profile =
+                                       S5P_FIMV_ENC_PROFILE_H264_MAIN;
+                       break;
+               case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
+                       p->codec.h264.profile =
+                                       S5P_FIMV_ENC_PROFILE_H264_HIGH;
+                       break;
+               case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+                       p->codec.h264.profile =
+                               S5P_FIMV_ENC_PROFILE_H264_BASELINE;
+                       break;
+               default:
+                       ret = -EINVAL;
+               }
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+               p->codec.h264.level_v4l2 = ctrl->val;
+               p->codec.h264.level = h264_level(ctrl->val);
+               if (p->codec.h264.level < 0) {
+                       mfc_err("Level number is wrong\n");
+                       ret = p->codec.h264.level;
+               }
+               break;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+               p->codec.mpeg4.level_v4l2 = ctrl->val;
+               p->codec.mpeg4.level = mpeg4_level(ctrl->val);
+               if (p->codec.mpeg4.level < 0) {
+                       mfc_err("Level number is wrong\n");
+                       ret = p->codec.mpeg4.level;
+               }
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+               p->codec.h264.loop_filter_mode = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
+               p->codec.h264.loop_filter_alpha = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
+               p->codec.h264.loop_filter_beta = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+               p->codec.h264.entropy_mode = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P:
+               p->codec.h264.num_ref_pic_4p = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:
+               p->codec.h264._8x8_transform = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:
+               p->codec.h264.rc_mb = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+               p->codec.h264.rc_frame_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
+               p->codec.h264.rc_min_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
+               p->codec.h264.rc_max_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+               p->codec.h264.rc_p_frame_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
+               p->codec.h264.rc_b_frame_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
+       case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP:
+               p->codec.mpeg4.rc_frame_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP:
+       case V4L2_CID_MPEG_VIDEO_H263_MIN_QP:
+               p->codec.mpeg4.rc_min_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP:
+       case V4L2_CID_MPEG_VIDEO_H263_MAX_QP:
+               p->codec.mpeg4.rc_max_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
+       case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP:
+               p->codec.mpeg4.rc_p_frame_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP:
+       case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP:
+               p->codec.mpeg4.rc_b_frame_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK:
+               p->codec.h264.rc_mb_dark = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH:
+               p->codec.h264.rc_mb_smooth = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC:
+               p->codec.h264.rc_mb_static = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY:
+               p->codec.h264.rc_mb_activity = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:
+               p->codec.h264.vui_sar = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
+               p->codec.h264.vui_sar_idc = vui_sar_idc(ctrl->val);
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH:
+               p->codec.h264.vui_ext_sar_width = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT:
+               p->codec.h264.vui_ext_sar_height = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+               p->codec.h264.open_gop = !ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:
+               p->codec.h264.open_gop_size = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+               switch (ctrl->val) {
+               case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE:
+                       p->codec.mpeg4.profile =
+                               S5P_FIMV_ENC_PROFILE_MPEG4_SIMPLE;
+                       break;
+               case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE:
+                       p->codec.mpeg4.profile =
+                       S5P_FIMV_ENC_PROFILE_MPEG4_ADVANCED_SIMPLE;
+                       break;
+               default:
+                       ret = -EINVAL;
+               }
+               break;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL:
+               p->codec.mpeg4.quarter_pixel = ctrl->val;
+               break;
+       default:
+               v4l2_err(&dev->v4l2_dev, "Invalid control, id=%d, val=%d\n",
+                                                       ctrl->id, ctrl->val);
+               ret = -EINVAL;
+       }
+       return ret;
+}
+
+static const struct v4l2_ctrl_ops s5p_mfc_enc_ctrl_ops = {
+       .s_ctrl = s5p_mfc_enc_s_ctrl,
+};
+
+int vidioc_s_parm(struct file *file, void *priv, struct v4l2_streamparm *a)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+       if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               ctx->enc_params.rc_framerate_num =
+                                       a->parm.output.timeperframe.denominator;
+               ctx->enc_params.rc_framerate_denom =
+                                       a->parm.output.timeperframe.numerator;
+       } else {
+               mfc_err("Setting FPS is only possible for the output queue\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+int vidioc_g_parm(struct file *file, void *priv, struct v4l2_streamparm *a)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+       if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+               a->parm.output.timeperframe.denominator =
+                                       ctx->enc_params.rc_framerate_num;
+               a->parm.output.timeperframe.numerator =
+                                       ctx->enc_params.rc_framerate_denom;
+       } else {
+               mfc_err("Setting FPS is only possible for the output queue\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static const struct v4l2_ioctl_ops s5p_mfc_enc_ioctl_ops = {
+       .vidioc_querycap = vidioc_querycap,
+       .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+       .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
+       .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
+       .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
+       .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt,
+       .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt,
+       .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt,
+       .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt,
+       .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt,
+       .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt,
+       .vidioc_reqbufs = vidioc_reqbufs,
+       .vidioc_querybuf = vidioc_querybuf,
+       .vidioc_qbuf = vidioc_qbuf,
+       .vidioc_dqbuf = vidioc_dqbuf,
+       .vidioc_streamon = vidioc_streamon,
+       .vidioc_streamoff = vidioc_streamoff,
+       .vidioc_s_parm = vidioc_s_parm,
+       .vidioc_g_parm = vidioc_g_parm,
+};
+
+static int check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb)
+{
+       int i;
+
+       if (!fmt)
+               return -EINVAL;
+       if (fmt->num_planes != vb->num_planes) {
+               mfc_err("invalid plane number for the format\n");
+               return -EINVAL;
+       }
+       for (i = 0; i < fmt->num_planes; i++) {
+               if (!vb2_dma_contig_plane_paddr(vb, i)) {
+                       mfc_err("failed to get plane cookie\n");
+                       return -EINVAL;
+               }
+               mfc_debug(2, "index: %d, plane[%d] cookie: 0x%08zx",
+                               vb->v4l2_buf.index, i,
+                               vb2_dma_contig_plane_paddr(vb, i));
+       }
+       return 0;
+}
+
+static int s5p_mfc_queue_setup(struct vb2_queue *vq,
+                      unsigned int *buf_count, unsigned int *plane_count,
+                      unsigned long psize[], void *allocators[])
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+
+       if (ctx->state != MFCINST_GOT_INST) {
+               mfc_err("inavlid state: %d\n", ctx->state);
+               return -EINVAL;
+       }
+       if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               if (ctx->dst_fmt)
+                       *plane_count = ctx->dst_fmt->num_planes;
+               else
+                       *plane_count = MFC_ENC_CAP_PLANE_COUNT;
+               if (*buf_count < 1)
+                       *buf_count = 1;
+               if (*buf_count > MFC_MAX_BUFFERS)
+                       *buf_count = MFC_MAX_BUFFERS;
+               psize[0] = ctx->enc_dst_buf_size;
+               allocators[0] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
+       } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               if (ctx->src_fmt)
+                       *plane_count = ctx->src_fmt->num_planes;
+               else
+                       *plane_count = MFC_ENC_OUT_PLANE_COUNT;
+
+               if (*buf_count < 1)
+                       *buf_count = 1;
+               if (*buf_count > MFC_MAX_BUFFERS)
+                       *buf_count = MFC_MAX_BUFFERS;
+               psize[0] = ctx->luma_size;
+               psize[1] = ctx->chroma_size;
+               allocators[0] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX];
+               allocators[1] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX];
+       } else {
+               mfc_err("inavlid queue type: %d\n", vq->type);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static void s5p_mfc_unlock(struct vb2_queue *q)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       mutex_unlock(&dev->mfc_mutex);
+}
+
+static void s5p_mfc_lock(struct vb2_queue *q)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       mutex_lock(&dev->mfc_mutex);
+}
+
+static int s5p_mfc_buf_init(struct vb2_buffer *vb)
+{
+       struct vb2_queue *vq = vb->vb2_queue;
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+       unsigned int i;
+       int ret;
+
+       if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               ret = check_vb_with_fmt(ctx->dst_fmt, vb);
+               if (ret < 0)
+                       return ret;
+               i = vb->v4l2_buf.index;
+               ctx->dst_bufs[i].b = vb;
+               ctx->dst_bufs[i].cookie.stream =
+                                       vb2_dma_contig_plane_paddr(vb, 0);
+               ctx->dst_bufs_cnt++;
+       } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               ret = check_vb_with_fmt(ctx->src_fmt, vb);
+               if (ret < 0)
+                       return ret;
+               i = vb->v4l2_buf.index;
+               ctx->src_bufs[i].b = vb;
+               ctx->src_bufs[i].cookie.raw.luma =
+                                       vb2_dma_contig_plane_paddr(vb, 0);
+               ctx->src_bufs[i].cookie.raw.chroma =
+                                       vb2_dma_contig_plane_paddr(vb, 1);
+               ctx->src_bufs_cnt++;
+       } else {
+               mfc_err("inavlid queue type: %d\n", vq->type);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int s5p_mfc_buf_prepare(struct vb2_buffer *vb)
+{
+       struct vb2_queue *vq = vb->vb2_queue;
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+       int ret;
+
+       if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               ret = check_vb_with_fmt(ctx->dst_fmt, vb);
+               if (ret < 0)
+                       return ret;
+               mfc_debug(2, "plane size: %ld, dst size: %d\n",
+                       vb2_plane_size(vb, 0), ctx->enc_dst_buf_size);
+               if (vb2_plane_size(vb, 0) < ctx->enc_dst_buf_size) {
+                       mfc_err("plane size is too small for capture\n");
+                       return -EINVAL;
+               }
+       } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               ret = check_vb_with_fmt(ctx->src_fmt, vb);
+               if (ret < 0)
+                       return ret;
+               mfc_debug(2, "plane size: %ld, luma size: %d\n",
+                       vb2_plane_size(vb, 0), ctx->luma_size);
+               mfc_debug(2, "plane size: %ld, chroma size: %d\n",
+                       vb2_plane_size(vb, 1), ctx->chroma_size);
+               if (vb2_plane_size(vb, 0) < ctx->luma_size ||
+                   vb2_plane_size(vb, 1) < ctx->chroma_size) {
+                       mfc_err("plane size is too small for output\n");
+                       return -EINVAL;
+               }
+       } else {
+               mfc_err("inavlid queue type: %d\n", vq->type);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int s5p_mfc_start_streaming(struct vb2_queue *q)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned long flags;
+
+       v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
+       /* If context is ready then dev = work->data;schedule it to run */
+       if (s5p_mfc_ctx_ready(ctx)) {
+               spin_lock_irqsave(&dev->condlock, flags);
+               set_bit(ctx->num, &dev->ctx_work_bits);
+               spin_unlock_irqrestore(&dev->condlock, flags);
+       }
+       s5p_mfc_try_run(dev);
+       return 0;
+}
+
+static int s5p_mfc_stop_streaming(struct vb2_queue *q)
+{
+       unsigned long flags;
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       if ((ctx->state == MFCINST_FINISHING ||
+               ctx->state == MFCINST_RUNNING) &&
+               dev->curr_ctx == ctx->num && dev->hw_lock) {
+               ctx->state = MFCINST_ABORT;
+               s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_FRAME_DONE_RET,
+                                         0);
+       }
+       ctx->state = MFCINST_FINISHED;
+       spin_lock_irqsave(&dev->irqlock, flags);
+       if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
+               INIT_LIST_HEAD(&ctx->dst_queue);
+               ctx->dst_queue_cnt = 0;
+       }
+       if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               cleanup_ref_queue(ctx);
+               s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
+               INIT_LIST_HEAD(&ctx->src_queue);
+               ctx->src_queue_cnt = 0;
+       }
+       spin_unlock_irqrestore(&dev->irqlock, flags);
+       return 0;
+}
+
+static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
+{
+       struct vb2_queue *vq = vb->vb2_queue;
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned long flags;
+       struct s5p_mfc_buf *mfc_buf;
+
+       if (ctx->state == MFCINST_ERROR) {
+               vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+               cleanup_ref_queue(ctx);
+               return;
+       }
+       if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               mfc_buf = &ctx->dst_bufs[vb->v4l2_buf.index];
+               mfc_buf->used = 0;
+               /* Mark destination as available for use by MFC */
+               spin_lock_irqsave(&dev->irqlock, flags);
+               list_add_tail(&mfc_buf->list, &ctx->dst_queue);
+               ctx->dst_queue_cnt++;
+               spin_unlock_irqrestore(&dev->irqlock, flags);
+       } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               mfc_buf = &ctx->src_bufs[vb->v4l2_buf.index];
+               mfc_buf->used = 0;
+               spin_lock_irqsave(&dev->irqlock, flags);
+               if (vb->v4l2_planes[0].bytesused == 0) {
+                       mfc_debug(1, "change state to FINISHING\n");
+                       ctx->state = MFCINST_FINISHING;
+                       vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+                       cleanup_ref_queue(ctx);
+               } else {
+                       list_add_tail(&mfc_buf->list, &ctx->src_queue);
+                       ctx->src_queue_cnt++;
+               }
+               spin_unlock_irqrestore(&dev->irqlock, flags);
+       } else {
+               mfc_err("unsupported buffer type (%d)\n", vq->type);
+       }
+       if (s5p_mfc_ctx_ready(ctx)) {
+               spin_lock_irqsave(&dev->condlock, flags);
+               set_bit(ctx->num, &dev->ctx_work_bits);
+               spin_unlock_irqrestore(&dev->condlock, flags);
+       }
+       s5p_mfc_try_run(dev);
+}
+
+static struct vb2_ops s5p_mfc_enc_qops = {
+       .queue_setup            = s5p_mfc_queue_setup,
+       .wait_prepare           = s5p_mfc_unlock,
+       .wait_finish            = s5p_mfc_lock,
+       .buf_init               = s5p_mfc_buf_init,
+       .buf_prepare            = s5p_mfc_buf_prepare,
+       .start_streaming        = s5p_mfc_start_streaming,
+       .stop_streaming         = s5p_mfc_stop_streaming,
+       .buf_queue              = s5p_mfc_buf_queue,
+};
+
+struct s5p_mfc_codec_ops *get_enc_codec_ops(void)
+{
+       return &encoder_codec_ops;
+}
+
+struct vb2_ops *get_enc_queue_ops(void)
+{
+       return &s5p_mfc_enc_qops;
+}
+
+const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void)
+{
+       return &s5p_mfc_enc_ioctl_ops;
+}
+
+#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2CLASS(x) == V4L2_CTRL_CLASS_MPEG) \
+                                               && V4L2_CTRL_DRIVER_PRIV(x))
+
+int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx)
+{
+       struct v4l2_ctrl_config cfg;
+       int i;
+
+       v4l2_ctrl_handler_init(&ctx->ctrl_handler, NUM_CTRLS);
+       if (ctx->ctrl_handler.error) {
+               mfc_err("v4l2_ctrl_handler_init failed\n");
+               return ctx->ctrl_handler.error;
+       }
+       for (i = 0; i < NUM_CTRLS; i++) {
+               if (IS_MFC51_PRIV(controls[i].id)) {
+                       cfg.ops = &s5p_mfc_enc_ctrl_ops;
+                       cfg.id = controls[i].id;
+                       cfg.min = controls[i].minimum;
+                       cfg.max = controls[i].maximum;
+                       cfg.def = controls[i].default_value;
+                       cfg.name = controls[i].name;
+                       cfg.type = controls[i].type;
+                       cfg.flags = 0;
+
+                       if (cfg.type == V4L2_CTRL_TYPE_MENU) {
+                               cfg.step = 0;
+                               cfg.menu_skip_mask = cfg.menu_skip_mask;
+                               cfg.qmenu = mfc51_get_menu(cfg.id);
+                       } else {
+                               cfg.step = controls[i].step;
+                               cfg.menu_skip_mask = 0;
+                       }
+                       ctx->ctrls[i] = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
+                                       &cfg, NULL);
+               } else {
+                       if (controls[i].type == V4L2_CTRL_TYPE_MENU) {
+                               ctx->ctrls[i] = v4l2_ctrl_new_std_menu(
+                                       &ctx->ctrl_handler,
+                                       &s5p_mfc_enc_ctrl_ops, controls[i].id,
+                                       controls[i].maximum, 0,
+                                       controls[i].default_value);
+                       } else {
+                               ctx->ctrls[i] = v4l2_ctrl_new_std(
+                                       &ctx->ctrl_handler,
+                                       &s5p_mfc_enc_ctrl_ops, controls[i].id,
+                                       controls[i].minimum,
+                                       controls[i].maximum, controls[i].step,
+                                       controls[i].default_value);
+                       }
+               }
+               if (ctx->ctrl_handler.error) {
+                       mfc_err("Adding control (%d) failed\n", i);
+                       return ctx->ctrl_handler.error;
+               }
+               if (controls[i].is_volatile && ctx->ctrls[i])
+                       ctx->ctrls[i]->is_volatile = 1;
+       }
+       return 0;
+}
+
+void s5p_mfc_enc_ctrls_delete(struct s5p_mfc_ctx *ctx)
+{
+       int i;
+
+       v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+       for (i = 0; i < NUM_CTRLS; i++)
+               ctx->ctrls[i] = NULL;
+}
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_enc.h b/drivers/media/video/s5p-mfc/s5p_mfc_enc.h
new file mode 100644 (file)
index 0000000..405bdd3
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * linux/drivers/media/video/s5p-mfc/s5p_mfc_enc.h
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.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.
+ */
+
+#ifndef S5P_MFC_ENC_H_
+#define S5P_MFC_ENC_H_
+
+struct s5p_mfc_codec_ops *get_enc_codec_ops(void);
+struct vb2_ops *get_enc_queue_ops(void);
+const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void);
+struct s5p_mfc_fmt *get_enc_def_fmt(bool src);
+int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_enc_ctrls_delete(struct s5p_mfc_ctx *ctx);
+
+#endif /* S5P_MFC_ENC_H_  */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_intr.c b/drivers/media/video/s5p-mfc/s5p_mfc_intr.c
new file mode 100644 (file)
index 0000000..8f2f8bf
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * drivers/media/video/samsung/mfc5/s5p_mfc_intr.c
+ *
+ * C file for Samsung MFC (Multi Function Codec - FIMV) driver
+ * This file contains functions used to wait for command completion.
+ *
+ * Kamil Debski, Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.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/delay.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include "regs-mfc.h"
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_intr.h"
+
+int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command)
+{
+       int ret;
+
+       ret = wait_event_interruptible_timeout(dev->queue,
+               (dev->int_cond && (dev->int_type == command
+               || dev->int_type == S5P_FIMV_R2H_CMD_ERR_RET)),
+               msecs_to_jiffies(MFC_INT_TIMEOUT));
+       if (ret == 0) {
+               mfc_err("Interrupt (dev->int_type:%d, command:%d) timed out\n",
+                                                       dev->int_type, command);
+               return 1;
+       } else if (ret == -ERESTARTSYS) {
+               mfc_err("Interrupted by a signal\n");
+               return 1;
+       }
+       mfc_debug(1, "Finished waiting (dev->int_type:%d, command: %d)\n",
+                                                       dev->int_type, command);
+       if (dev->int_type == S5P_FIMV_R2H_CMD_ERR_RET)
+               return 1;
+       return 0;
+}
+
+void s5p_mfc_clean_dev_int_flags(struct s5p_mfc_dev *dev)
+{
+       dev->int_cond = 0;
+       dev->int_type = 0;
+       dev->int_err = 0;
+}
+
+int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx,
+                                   int command, int interrupt)
+{
+       int ret;
+
+       if (interrupt) {
+               ret = wait_event_interruptible_timeout(ctx->queue,
+                               (ctx->int_cond && (ctx->int_type == command
+                       || ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET)),
+                                       msecs_to_jiffies(MFC_INT_TIMEOUT));
+       } else {
+               ret = wait_event_timeout(ctx->queue,
+                               (ctx->int_cond && (ctx->int_type == command
+                       || ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET)),
+                                       msecs_to_jiffies(MFC_INT_TIMEOUT));
+       }
+       if (ret == 0) {
+               mfc_err("Interrupt (ctx->int_type:%d, command:%d) timed out\n",
+                                                       ctx->int_type, command);
+               return 1;
+       } else if (ret == -ERESTARTSYS) {
+               mfc_err("Interrupted by a signal\n");
+               return 1;
+       }
+       mfc_debug(1, "Finished waiting (ctx->int_type:%d, command: %d)\n",
+                                                       ctx->int_type, command);
+       if (ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET)
+               return 1;
+       return 0;
+}
+
+void s5p_mfc_clean_ctx_int_flags(struct s5p_mfc_ctx *ctx)
+{
+       ctx->int_cond = 0;
+       ctx->int_type = 0;
+       ctx->int_err = 0;
+}
+
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_intr.h b/drivers/media/video/s5p-mfc/s5p_mfc_intr.h
new file mode 100644 (file)
index 0000000..122d773
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * drivers/media/video/samsung/mfc5/s5p_mfc_intr.h
+ *
+ * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
+ * It contains waiting functions declarations.
+ *
+ * Kamil Debski, Copyright (C) 2011 Samsung Electronics
+ * http://www.samsung.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 S5P_MFC_INTR_H_
+#define S5P_MFC_INTR_H_
+
+#include "s5p_mfc_common.h"
+
+int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx,
+                             int command, int interrupt);
+int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command);
+void s5p_mfc_clean_ctx_int_flags(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_clean_dev_int_flags(struct s5p_mfc_dev *dev);
+
+#endif /* S5P_MFC_INTR_H_ */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_opr.c b/drivers/media/video/s5p-mfc/s5p_mfc_opr.c
new file mode 100644 (file)
index 0000000..7b23916
--- /dev/null
@@ -0,0 +1,1397 @@
+/*
+ * drivers/media/video/samsung/mfc5/s5p_mfc_opr.c
+ *
+ * Samsung MFC (Multi Function Codec - FIMV) driver
+ * This file contains hw related functions.
+ *
+ * Kamil Debski, Copyright (c) 2011 Samsung Electronics
+ * http://www.samsung.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 "regs-mfc.h"
+#include "s5p_mfc_cmd.h"
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_ctrl.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_intr.h"
+#include "s5p_mfc_opr.h"
+#include "s5p_mfc_pm.h"
+#include "s5p_mfc_shm.h"
+#include <asm/cacheflush.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#define OFFSETA(x)             (((x) - dev->bank1) >> MFC_OFFSET_SHIFT)
+#define OFFSETB(x)             (((x) - dev->bank2) >> MFC_OFFSET_SHIFT)
+
+/* Allocate temporary buffers for decoding */
+int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx)
+{
+       void *desc_virt;
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       ctx->desc_buf = vb2_dma_contig_memops.alloc(
+                       dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], DESC_BUF_SIZE);
+       if (IS_ERR_VALUE((int)ctx->desc_buf)) {
+               ctx->desc_buf = 0;
+               mfc_err("Allocating DESC buffer failed\n");
+               return -ENOMEM;
+       }
+       ctx->desc_phys = s5p_mfc_mem_cookie(
+                       dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->desc_buf);
+       BUG_ON(ctx->desc_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1));
+       desc_virt = vb2_dma_contig_memops.vaddr(ctx->desc_buf);
+       if (desc_virt == NULL) {
+               vb2_dma_contig_memops.put(ctx->desc_buf);
+               ctx->desc_phys = 0;
+               ctx->desc_buf = 0;
+               mfc_err("Remapping DESC buffer failed\n");
+               return -ENOMEM;
+       }
+       memset(desc_virt, 0, DESC_BUF_SIZE);
+       wmb();
+       return 0;
+}
+
+/* Release temporary buffers for decoding */
+void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx)
+{
+       if (ctx->desc_phys) {
+               vb2_dma_contig_memops.put(ctx->desc_buf);
+               ctx->desc_phys = 0;
+               ctx->desc_buf = 0;
+       }
+}
+
+/* Allocate codec buffers */
+int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned int enc_ref_y_size = 0;
+       unsigned int enc_ref_c_size = 0;
+       unsigned int guard_width, guard_height;
+
+       if (ctx->type == MFCINST_DECODER) {
+               mfc_debug(2, "Luma size:%d Chroma size:%d MV size:%d\n",
+                         ctx->luma_size, ctx->chroma_size, ctx->mv_size);
+               mfc_debug(2, "Totals bufs: %d\n", ctx->total_dpb_count);
+       } else if (ctx->type == MFCINST_ENCODER) {
+               enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN)
+                       * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN);
+               enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN);
+
+               if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) {
+                       enc_ref_c_size = ALIGN(ctx->img_width,
+                                               S5P_FIMV_NV12MT_HALIGN)
+                                               * ALIGN(ctx->img_height >> 1,
+                                               S5P_FIMV_NV12MT_VALIGN);
+                       enc_ref_c_size = ALIGN(enc_ref_c_size,
+                                                       S5P_FIMV_NV12MT_SALIGN);
+               } else {
+                       guard_width = ALIGN(ctx->img_width + 16,
+                                                       S5P_FIMV_NV12MT_HALIGN);
+                       guard_height = ALIGN((ctx->img_height >> 1) + 4,
+                                                       S5P_FIMV_NV12MT_VALIGN);
+                       enc_ref_c_size = ALIGN(guard_width * guard_height,
+                                              S5P_FIMV_NV12MT_SALIGN);
+               }
+               mfc_debug(2, "recon luma size: %d chroma size: %d\n",
+                         enc_ref_y_size, enc_ref_c_size);
+       } else {
+               return -EINVAL;
+       }
+       /* Codecs have different memory requirements */
+       switch (ctx->codec_mode) {
+       case S5P_FIMV_CODEC_H264_DEC:
+               ctx->bank1_size =
+                   ALIGN(S5P_FIMV_DEC_NB_IP_SIZE +
+                                       S5P_FIMV_DEC_VERT_NB_MV_SIZE,
+                                       S5P_FIMV_DEC_BUF_ALIGN);
+               ctx->bank2_size = ctx->total_dpb_count * ctx->mv_size;
+               break;
+       case S5P_FIMV_CODEC_MPEG4_DEC:
+               ctx->bank1_size =
+                   ALIGN(S5P_FIMV_DEC_NB_DCAC_SIZE +
+                                    S5P_FIMV_DEC_UPNB_MV_SIZE +
+                                    S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE +
+                                    S5P_FIMV_DEC_STX_PARSER_SIZE +
+                                    S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE,
+                                    S5P_FIMV_DEC_BUF_ALIGN);
+               ctx->bank2_size = 0;
+               break;
+       case S5P_FIMV_CODEC_VC1RCV_DEC:
+       case S5P_FIMV_CODEC_VC1_DEC:
+               ctx->bank1_size =
+                   ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE +
+                            S5P_FIMV_DEC_UPNB_MV_SIZE +
+                            S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE +
+                            S5P_FIMV_DEC_NB_DCAC_SIZE +
+                            3 * S5P_FIMV_DEC_VC1_BITPLANE_SIZE,
+                            S5P_FIMV_DEC_BUF_ALIGN);
+               ctx->bank2_size = 0;
+               break;
+       case S5P_FIMV_CODEC_MPEG2_DEC:
+               ctx->bank1_size = 0;
+               ctx->bank2_size = 0;
+               break;
+       case S5P_FIMV_CODEC_H263_DEC:
+               ctx->bank1_size =
+                   ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE +
+                            S5P_FIMV_DEC_UPNB_MV_SIZE +
+                            S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE +
+                            S5P_FIMV_DEC_NB_DCAC_SIZE,
+                            S5P_FIMV_DEC_BUF_ALIGN);
+               ctx->bank2_size = 0;
+               break;
+       case S5P_FIMV_CODEC_H264_ENC:
+               ctx->bank1_size = (enc_ref_y_size * 2) +
+                                  S5P_FIMV_ENC_UPMV_SIZE +
+                                  S5P_FIMV_ENC_COLFLG_SIZE +
+                                  S5P_FIMV_ENC_INTRAMD_SIZE +
+                                  S5P_FIMV_ENC_NBORINFO_SIZE;
+               ctx->bank2_size = (enc_ref_y_size * 2) +
+                                  (enc_ref_c_size * 4) +
+                                  S5P_FIMV_ENC_INTRAPRED_SIZE;
+               break;
+       case S5P_FIMV_CODEC_MPEG4_ENC:
+               ctx->bank1_size = (enc_ref_y_size * 2) +
+                                  S5P_FIMV_ENC_UPMV_SIZE +
+                                  S5P_FIMV_ENC_COLFLG_SIZE +
+                                  S5P_FIMV_ENC_ACDCCOEF_SIZE;
+               ctx->bank2_size = (enc_ref_y_size * 2) +
+                                  (enc_ref_c_size * 4);
+               break;
+       case S5P_FIMV_CODEC_H263_ENC:
+               ctx->bank1_size = (enc_ref_y_size * 2) +
+                                  S5P_FIMV_ENC_UPMV_SIZE +
+                                  S5P_FIMV_ENC_ACDCCOEF_SIZE;
+               ctx->bank2_size = (enc_ref_y_size * 2) +
+                                  (enc_ref_c_size * 4);
+               break;
+       default:
+               break;
+       }
+       /* Allocate only if memory from bank 1 is necessary */
+       if (ctx->bank1_size > 0) {
+               ctx->bank1_buf = vb2_dma_contig_memops.alloc(
+               dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_size);
+               if (IS_ERR(ctx->bank1_buf)) {
+                       ctx->bank1_buf = 0;
+                       printk(KERN_ERR
+                              "Buf alloc for decoding failed (port A)\n");
+                       return -ENOMEM;
+               }
+               ctx->bank1_phys = s5p_mfc_mem_cookie(
+               dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_buf);
+               BUG_ON(ctx->bank1_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1));
+       }
+       /* Allocate only if memory from bank 2 is necessary */
+       if (ctx->bank2_size > 0) {
+               ctx->bank2_buf = vb2_dma_contig_memops.alloc(
+               dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_size);
+               if (IS_ERR(ctx->bank2_buf)) {
+                       ctx->bank2_buf = 0;
+                       mfc_err("Buf alloc for decoding failed (port B)\n");
+                       return -ENOMEM;
+               }
+               ctx->bank2_phys = s5p_mfc_mem_cookie(
+               dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_buf);
+               BUG_ON(ctx->bank2_phys & ((1 << MFC_BANK2_ALIGN_ORDER) - 1));
+       }
+       return 0;
+}
+
+/* Release buffers allocated for codec */
+void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx)
+{
+       if (ctx->bank1_buf) {
+               vb2_dma_contig_memops.put(ctx->bank1_buf);
+               ctx->bank1_buf = 0;
+               ctx->bank1_phys = 0;
+               ctx->bank1_size = 0;
+       }
+       if (ctx->bank2_buf) {
+               vb2_dma_contig_memops.put(ctx->bank2_buf);
+               ctx->bank2_buf = 0;
+               ctx->bank2_phys = 0;
+               ctx->bank2_size = 0;
+       }
+}
+
+/* Allocate memory for instance data buffer */
+int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx)
+{
+       void *context_virt;
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC ||
+               ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC)
+               ctx->ctx_size = MFC_H264_CTX_BUF_SIZE;
+       else
+               ctx->ctx_size = MFC_CTX_BUF_SIZE;
+       ctx->ctx_buf = vb2_dma_contig_memops.alloc(
+               dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx_size);
+       if (IS_ERR(ctx->ctx_buf)) {
+               mfc_err("Allocating context buffer failed\n");
+               ctx->ctx_phys = 0;
+               ctx->ctx_buf = 0;
+               return -ENOMEM;
+       }
+       ctx->ctx_phys = s5p_mfc_mem_cookie(
+               dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx_buf);
+       BUG_ON(ctx->ctx_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1));
+       ctx->ctx_ofs = OFFSETA(ctx->ctx_phys);
+       context_virt = vb2_dma_contig_memops.vaddr(ctx->ctx_buf);
+       if (context_virt == NULL) {
+               mfc_err("Remapping instance buffer failed\n");
+               vb2_dma_contig_memops.put(ctx->ctx_buf);
+               ctx->ctx_phys = 0;
+               ctx->ctx_buf = 0;
+               return -ENOMEM;
+       }
+       /* Zero content of the allocated memory */
+       memset(context_virt, 0, ctx->ctx_size);
+       wmb();
+       if (s5p_mfc_init_shm(ctx) < 0) {
+               vb2_dma_contig_memops.put(ctx->ctx_buf);
+               ctx->ctx_phys = 0;
+               ctx->ctx_buf = 0;
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+/* Release instance buffer */
+void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx)
+{
+       if (ctx->ctx_buf) {
+               vb2_dma_contig_memops.put(ctx->ctx_buf);
+               ctx->ctx_phys = 0;
+               ctx->ctx_buf = 0;
+       }
+       if (ctx->shm_alloc) {
+               vb2_dma_contig_memops.put(ctx->shm_alloc);
+               ctx->shm_alloc = 0;
+               ctx->shm = 0;
+       }
+}
+
+/* Set registers for decoding temporary buffers */
+void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       mfc_write(dev, OFFSETA(ctx->desc_phys), S5P_FIMV_SI_CH0_DESC_ADR);
+       mfc_write(dev, DESC_BUF_SIZE, S5P_FIMV_SI_CH0_DESC_SIZE);
+}
+
+/* Set registers for shared buffer */
+void s5p_mfc_set_shared_buffer(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       mfc_write(dev, ctx->shm_ofs, S5P_FIMV_SI_CH0_HOST_WR_ADR);
+}
+
+/* Set registers for decoding stream buffer */
+int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, int buf_addr,
+                 unsigned int start_num_byte, unsigned int buf_size)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       mfc_write(dev, OFFSETA(buf_addr), S5P_FIMV_SI_CH0_SB_ST_ADR);
+       mfc_write(dev, ctx->dec_src_buf_size, S5P_FIMV_SI_CH0_CPB_SIZE);
+       mfc_write(dev, buf_size, S5P_FIMV_SI_CH0_SB_FRM_SIZE);
+       s5p_mfc_write_shm(ctx, start_num_byte, START_BYTE_NUM);
+       return 0;
+}
+
+/* Set decoding frame buffer */
+int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx)
+{
+       unsigned int frame_size, i;
+       unsigned int frame_size_ch, frame_size_mv;
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned int dpb;
+       size_t buf_addr1, buf_addr2;
+       int buf_size1, buf_size2;
+
+       buf_addr1 = ctx->bank1_phys;
+       buf_size1 = ctx->bank1_size;
+       buf_addr2 = ctx->bank2_phys;
+       buf_size2 = ctx->bank2_size;
+       dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) &
+                                               ~S5P_FIMV_DPB_COUNT_MASK;
+       mfc_write(dev, ctx->total_dpb_count | dpb,
+                                               S5P_FIMV_SI_CH0_DPB_CONF_CTRL);
+       s5p_mfc_set_shared_buffer(ctx);
+       switch (ctx->codec_mode) {
+       case S5P_FIMV_CODEC_H264_DEC:
+               mfc_write(dev, OFFSETA(buf_addr1),
+                                               S5P_FIMV_H264_VERT_NB_MV_ADR);
+               buf_addr1 += S5P_FIMV_DEC_VERT_NB_MV_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_VERT_NB_MV_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_NB_IP_ADR);
+               buf_addr1 += S5P_FIMV_DEC_NB_IP_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_NB_IP_SIZE;
+               break;
+       case S5P_FIMV_CODEC_MPEG4_DEC:
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_NB_DCAC_ADR);
+               buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_NB_MV_ADR);
+               buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SA_MV_ADR);
+               buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SP_ADR);
+               buf_addr1 += S5P_FIMV_DEC_STX_PARSER_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_STX_PARSER_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_OT_LINE_ADR);
+               buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+               break;
+       case S5P_FIMV_CODEC_H263_DEC:
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_OT_LINE_ADR);
+               buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_NB_MV_ADR);
+               buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_SA_MV_ADR);
+               buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_NB_DCAC_ADR);
+               buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE;
+               break;
+       case S5P_FIMV_CODEC_VC1_DEC:
+       case S5P_FIMV_CODEC_VC1RCV_DEC:
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_NB_DCAC_ADR);
+               buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_OT_LINE_ADR);
+               buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_UP_NB_MV_ADR);
+               buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_SA_MV_ADR);
+               buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE3_ADR);
+               buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE2_ADR);
+               buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE1_ADR);
+               buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+               break;
+       case S5P_FIMV_CODEC_MPEG2_DEC:
+               break;
+       default:
+               mfc_err("Unknown codec for decoding (%x)\n",
+                       ctx->codec_mode);
+               return -EINVAL;
+               break;
+       }
+       frame_size = ctx->luma_size;
+       frame_size_ch = ctx->chroma_size;
+       frame_size_mv = ctx->mv_size;
+       mfc_debug(2, "Frm size: %d ch: %d mv: %d\n", frame_size, frame_size_ch,
+                                                               frame_size_mv);
+       for (i = 0; i < ctx->total_dpb_count; i++) {
+               /* Bank2 */
+               mfc_debug(2, "Luma %d: %x\n", i,
+                                       ctx->dst_bufs[i].cookie.raw.luma);
+               mfc_write(dev, OFFSETB(ctx->dst_bufs[i].cookie.raw.luma),
+                                               S5P_FIMV_DEC_LUMA_ADR + i * 4);
+               mfc_debug(2, "\tChroma %d: %x\n", i,
+                                       ctx->dst_bufs[i].cookie.raw.chroma);
+               mfc_write(dev, OFFSETA(ctx->dst_bufs[i].cookie.raw.chroma),
+                                              S5P_FIMV_DEC_CHROMA_ADR + i * 4);
+               if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) {
+                       mfc_debug(2, "\tBuf2: %x, size: %d\n",
+                                                       buf_addr2, buf_size2);
+                       mfc_write(dev, OFFSETB(buf_addr2),
+                                               S5P_FIMV_H264_MV_ADR + i * 4);
+                       buf_addr2 += frame_size_mv;
+                       buf_size2 -= frame_size_mv;
+               }
+       }
+       mfc_debug(2, "Buf1: %u, buf_size1: %d\n", buf_addr1, buf_size1);
+       mfc_debug(2, "Buf 1/2 size after: %d/%d (frames %d)\n",
+                       buf_size1,  buf_size2, ctx->total_dpb_count);
+       if (buf_size1 < 0 || buf_size2 < 0) {
+               mfc_debug(2, "Not enough memory has been allocated\n");
+               return -ENOMEM;
+       }
+       s5p_mfc_write_shm(ctx, frame_size, ALLOC_LUMA_DPB_SIZE);
+       s5p_mfc_write_shm(ctx, frame_size_ch, ALLOC_CHROMA_DPB_SIZE);
+       if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC)
+               s5p_mfc_write_shm(ctx, frame_size_mv, ALLOC_MV_SIZE);
+       mfc_write(dev, ((S5P_FIMV_CH_INIT_BUFS & S5P_FIMV_CH_MASK)
+                                       << S5P_FIMV_CH_SHIFT) | (ctx->inst_no),
+                                               S5P_FIMV_SI_CH0_INST_ID);
+       return 0;
+}
+
+/* Set registers for encoding stream buffer */
+int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx,
+               unsigned long addr, unsigned int size)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       mfc_write(dev, OFFSETA(addr), S5P_FIMV_ENC_SI_CH0_SB_ADR);
+       mfc_write(dev, size, S5P_FIMV_ENC_SI_CH0_SB_SIZE);
+       return 0;
+}
+
+void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+               unsigned long y_addr, unsigned long c_addr)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       mfc_write(dev, OFFSETB(y_addr), S5P_FIMV_ENC_SI_CH0_CUR_Y_ADR);
+       mfc_write(dev, OFFSETB(c_addr), S5P_FIMV_ENC_SI_CH0_CUR_C_ADR);
+}
+
+void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+               unsigned long *y_addr, unsigned long *c_addr)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       *y_addr = dev->bank2 + (mfc_read(dev, S5P_FIMV_ENCODED_Y_ADDR)
+                                                       << MFC_OFFSET_SHIFT);
+       *c_addr = dev->bank2 + (mfc_read(dev, S5P_FIMV_ENCODED_C_ADDR)
+                                                       << MFC_OFFSET_SHIFT);
+}
+
+/* Set encoding ref & codec buffer */
+int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       size_t buf_addr1, buf_addr2;
+       size_t buf_size1, buf_size2;
+       unsigned int enc_ref_y_size, enc_ref_c_size;
+       unsigned int guard_width, guard_height;
+       int i;
+
+       buf_addr1 = ctx->bank1_phys;
+       buf_size1 = ctx->bank1_size;
+       buf_addr2 = ctx->bank2_phys;
+       buf_size2 = ctx->bank2_size;
+       enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN)
+               * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN);
+       enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN);
+       if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) {
+               enc_ref_c_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN)
+                       * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12MT_VALIGN);
+               enc_ref_c_size = ALIGN(enc_ref_c_size, S5P_FIMV_NV12MT_SALIGN);
+       } else {
+               guard_width = ALIGN(ctx->img_width + 16,
+                                               S5P_FIMV_NV12MT_HALIGN);
+               guard_height = ALIGN((ctx->img_height >> 1) + 4,
+                                               S5P_FIMV_NV12MT_VALIGN);
+               enc_ref_c_size = ALIGN(guard_width * guard_height,
+                                      S5P_FIMV_NV12MT_SALIGN);
+       }
+       mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", buf_size1, buf_size2);
+       switch (ctx->codec_mode) {
+       case S5P_FIMV_CODEC_H264_ENC:
+               for (i = 0; i < 2; i++) {
+                       mfc_write(dev, OFFSETA(buf_addr1),
+                               S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i));
+                       buf_addr1 += enc_ref_y_size;
+                       buf_size1 -= enc_ref_y_size;
+
+                       mfc_write(dev, OFFSETB(buf_addr2),
+                               S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i));
+                       buf_addr2 += enc_ref_y_size;
+                       buf_size2 -= enc_ref_y_size;
+               }
+               for (i = 0; i < 4; i++) {
+                       mfc_write(dev, OFFSETB(buf_addr2),
+                               S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i));
+                       buf_addr2 += enc_ref_c_size;
+                       buf_size2 -= enc_ref_c_size;
+               }
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_UP_MV_ADR);
+               buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE;
+               buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1),
+                                       S5P_FIMV_H264_COZERO_FLAG_ADR);
+               buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE;
+               buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1),
+                                       S5P_FIMV_H264_UP_INTRA_MD_ADR);
+               buf_addr1 += S5P_FIMV_ENC_INTRAMD_SIZE;
+               buf_size1 -= S5P_FIMV_ENC_INTRAMD_SIZE;
+               mfc_write(dev, OFFSETB(buf_addr2),
+                                       S5P_FIMV_H264_UP_INTRA_PRED_ADR);
+               buf_addr2 += S5P_FIMV_ENC_INTRAPRED_SIZE;
+               buf_size2 -= S5P_FIMV_ENC_INTRAPRED_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1),
+                                       S5P_FIMV_H264_NBOR_INFO_ADR);
+               buf_addr1 += S5P_FIMV_ENC_NBORINFO_SIZE;
+               buf_size1 -= S5P_FIMV_ENC_NBORINFO_SIZE;
+               mfc_debug(2, "buf_size1: %d, buf_size2: %d\n",
+                       buf_size1, buf_size2);
+               break;
+       case S5P_FIMV_CODEC_MPEG4_ENC:
+               for (i = 0; i < 2; i++) {
+                       mfc_write(dev, OFFSETA(buf_addr1),
+                               S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i));
+                       buf_addr1 += enc_ref_y_size;
+                       buf_size1 -= enc_ref_y_size;
+                       mfc_write(dev, OFFSETB(buf_addr2),
+                               S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i));
+                       buf_addr2 += enc_ref_y_size;
+                       buf_size2 -= enc_ref_y_size;
+               }
+               for (i = 0; i < 4; i++) {
+                       mfc_write(dev, OFFSETB(buf_addr2),
+                               S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i));
+                       buf_addr2 += enc_ref_c_size;
+                       buf_size2 -= enc_ref_c_size;
+               }
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_MV_ADR);
+               buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE;
+               buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1),
+                                               S5P_FIMV_MPEG4_COZERO_FLAG_ADR);
+               buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE;
+               buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1),
+                                               S5P_FIMV_MPEG4_ACDC_COEF_ADR);
+               buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE;
+               buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE;
+               mfc_debug(2, "buf_size1: %d, buf_size2: %d\n",
+                       buf_size1, buf_size2);
+               break;
+       case S5P_FIMV_CODEC_H263_ENC:
+               for (i = 0; i < 2; i++) {
+                       mfc_write(dev, OFFSETA(buf_addr1),
+                               S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i));
+                       buf_addr1 += enc_ref_y_size;
+                       buf_size1 -= enc_ref_y_size;
+                       mfc_write(dev, OFFSETB(buf_addr2),
+                               S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i));
+                       buf_addr2 += enc_ref_y_size;
+                       buf_size2 -= enc_ref_y_size;
+               }
+               for (i = 0; i < 4; i++) {
+                       mfc_write(dev, OFFSETB(buf_addr2),
+                               S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i));
+                       buf_addr2 += enc_ref_c_size;
+                       buf_size2 -= enc_ref_c_size;
+               }
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_MV_ADR);
+               buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE;
+               buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_ACDC_COEF_ADR);
+               buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE;
+               buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE;
+               mfc_debug(2, "buf_size1: %d, buf_size2: %d\n",
+                       buf_size1, buf_size2);
+               break;
+       default:
+               mfc_err("Unknown codec set for encoding: %d\n",
+                       ctx->codec_mode);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_enc_params *p = &ctx->enc_params;
+       unsigned int reg;
+       unsigned int shm;
+
+       /* width */
+       mfc_write(dev, ctx->img_width, S5P_FIMV_ENC_HSIZE_PX);
+       /* height */
+       mfc_write(dev, ctx->img_height, S5P_FIMV_ENC_VSIZE_PX);
+       /* pictype : enable, IDR period */
+       reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL);
+       reg |= (1 << 18);
+       reg &= ~(0xFFFF);
+       reg |= p->gop_size;
+       mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL);
+       mfc_write(dev, 0, S5P_FIMV_ENC_B_RECON_WRITE_ON);
+       /* multi-slice control */
+       /* multi-slice MB number or bit size */
+       mfc_write(dev, p->slice_mode, S5P_FIMV_ENC_MSLICE_CTRL);
+       if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) {
+               mfc_write(dev, p->slice_mb, S5P_FIMV_ENC_MSLICE_MB);
+       } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) {
+               mfc_write(dev, p->slice_bit, S5P_FIMV_ENC_MSLICE_BIT);
+       } else {
+               mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_MB);
+               mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_BIT);
+       }
+       /* cyclic intra refresh */
+       mfc_write(dev, p->intra_refresh_mb, S5P_FIMV_ENC_CIR_CTRL);
+       /* memory structure cur. frame */
+       if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M)
+               mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR);
+       else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT)
+               mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR);
+       /* padding control & value */
+       reg = mfc_read(dev, S5P_FIMV_ENC_PADDING_CTRL);
+       if (p->pad) {
+               /** enable */
+               reg |= (1 << 31);
+               /** cr value */
+               reg &= ~(0xFF << 16);
+               reg |= (p->pad_cr << 16);
+               /** cb value */
+               reg &= ~(0xFF << 8);
+               reg |= (p->pad_cb << 8);
+               /** y value */
+               reg &= ~(0xFF);
+               reg |= (p->pad_luma);
+       } else {
+               /** disable & all value clear */
+               reg = 0;
+       }
+       mfc_write(dev, reg, S5P_FIMV_ENC_PADDING_CTRL);
+       /* rate control config. */
+       reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG);
+       /** frame-level rate control */
+       reg &= ~(0x1 << 9);
+       reg |= (p->rc_frame << 9);
+       mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG);
+       /* bit rate */
+       if (p->rc_frame)
+               mfc_write(dev, p->rc_bitrate,
+                       S5P_FIMV_ENC_RC_BIT_RATE);
+       else
+               mfc_write(dev, 0, S5P_FIMV_ENC_RC_BIT_RATE);
+       /* reaction coefficient */
+       if (p->rc_frame)
+               mfc_write(dev, p->rc_reaction_coeff, S5P_FIMV_ENC_RC_RPARA);
+       shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL);
+       /* seq header ctrl */
+       shm &= ~(0x1 << 3);
+       shm |= (p->seq_hdr_mode << 3);
+       /* frame skip mode */
+       shm &= ~(0x3 << 1);
+       shm |= (p->frame_skip_mode << 1);
+       s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL);
+       /* fixed target bit */
+       s5p_mfc_write_shm(ctx, p->fixed_target_bit, RC_CONTROL_CONFIG);
+       return 0;
+}
+
+static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_enc_params *p = &ctx->enc_params;
+       struct s5p_mfc_h264_enc_params *p_264 = &p->codec.h264;
+       unsigned int reg;
+       unsigned int shm;
+
+       s5p_mfc_set_enc_params(ctx);
+       /* pictype : number of B */
+       reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL);
+       /* num_b_frame - 0 ~ 2 */
+       reg &= ~(0x3 << 16);
+       reg |= (p->num_b_frame << 16);
+       mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL);
+       /* profile & level */
+       reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE);
+       /* level */
+       reg &= ~(0xFF << 8);
+       reg |= (p_264->level << 8);
+       /* profile - 0 ~ 2 */
+       reg &= ~(0x3F);
+       reg |= p_264->profile;
+       mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE);
+       /* interlace  */
+       mfc_write(dev, p->interlace, S5P_FIMV_ENC_PIC_STRUCT);
+       /* height */
+       if (p->interlace)
+               mfc_write(dev, ctx->img_height >> 1, S5P_FIMV_ENC_VSIZE_PX);
+       /* loopfilter ctrl */
+       mfc_write(dev, p_264->loop_filter_mode, S5P_FIMV_ENC_LF_CTRL);
+       /* loopfilter alpha offset */
+       if (p_264->loop_filter_alpha < 0) {
+               reg = 0x10;
+               reg |= (0xFF - p_264->loop_filter_alpha) + 1;
+       } else {
+               reg = 0x00;
+               reg |= (p_264->loop_filter_alpha & 0xF);
+       }
+       mfc_write(dev, reg, S5P_FIMV_ENC_ALPHA_OFF);
+       /* loopfilter beta offset */
+       if (p_264->loop_filter_beta < 0) {
+               reg = 0x10;
+               reg |= (0xFF - p_264->loop_filter_beta) + 1;
+       } else {
+               reg = 0x00;
+               reg |= (p_264->loop_filter_beta & 0xF);
+       }
+       mfc_write(dev, reg, S5P_FIMV_ENC_BETA_OFF);
+       /* entropy coding mode */
+       if (p_264->entropy_mode == V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC)
+               mfc_write(dev, 1, S5P_FIMV_ENC_H264_ENTROPY_MODE);
+       else
+               mfc_write(dev, 0, S5P_FIMV_ENC_H264_ENTROPY_MODE);
+       /* number of ref. picture */
+       reg = mfc_read(dev, S5P_FIMV_ENC_H264_NUM_OF_REF);
+       /* num of ref. pictures of P */
+       reg &= ~(0x3 << 5);
+       reg |= (p_264->num_ref_pic_4p << 5);
+       /* max number of ref. pictures */
+       reg &= ~(0x1F);
+       reg |= p_264->max_ref_pic;
+       mfc_write(dev, reg, S5P_FIMV_ENC_H264_NUM_OF_REF);
+       /* 8x8 transform enable */
+       mfc_write(dev, p_264->_8x8_transform, S5P_FIMV_ENC_H264_TRANS_FLAG);
+       /* rate control config. */
+       reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG);
+       /* macroblock level rate control */
+       reg &= ~(0x1 << 8);
+       reg |= (p_264->rc_mb << 8);
+       /* frame QP */
+       reg &= ~(0x3F);
+       reg |= p_264->rc_frame_qp;
+       mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG);
+       /* frame rate */
+       if (p->rc_frame && p->rc_framerate_denom)
+               mfc_write(dev, p->rc_framerate_num * 1000
+                       / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE);
+       else
+               mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE);
+       /* max & min value of QP */
+       reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND);
+       /* max QP */
+       reg &= ~(0x3F << 8);
+       reg |= (p_264->rc_max_qp << 8);
+       /* min QP */
+       reg &= ~(0x3F);
+       reg |= p_264->rc_min_qp;
+       mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND);
+       /* macroblock adaptive scaling features */
+       if (p_264->rc_mb) {
+               reg = mfc_read(dev, S5P_FIMV_ENC_RC_MB_CTRL);
+               /* dark region */
+               reg &= ~(0x1 << 3);
+               reg |= (p_264->rc_mb_dark << 3);
+               /* smooth region */
+               reg &= ~(0x1 << 2);
+               reg |= (p_264->rc_mb_smooth << 2);
+               /* static region */
+               reg &= ~(0x1 << 1);
+               reg |= (p_264->rc_mb_static << 1);
+               /* high activity region */
+               reg &= ~(0x1);
+               reg |= p_264->rc_mb_activity;
+               mfc_write(dev, reg, S5P_FIMV_ENC_RC_MB_CTRL);
+       }
+       if (!p->rc_frame &&
+           !p_264->rc_mb) {
+               shm = s5p_mfc_read_shm(ctx, P_B_FRAME_QP);
+               shm &= ~(0xFFF);
+               shm |= ((p_264->rc_b_frame_qp & 0x3F) << 6);
+               shm |= (p_264->rc_p_frame_qp & 0x3F);
+               s5p_mfc_write_shm(ctx, shm, P_B_FRAME_QP);
+       }
+       /* extended encoder ctrl */
+       shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL);
+       /* AR VUI control */
+       shm &= ~(0x1 << 15);
+       shm |= (p_264->vui_sar << 1);
+       s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL);
+       if (p_264->vui_sar) {
+               /* aspect ration IDC */
+               shm = s5p_mfc_read_shm(ctx, SAMPLE_ASPECT_RATIO_IDC);
+               shm &= ~(0xFF);
+               shm |= p_264->vui_sar_idc;
+               s5p_mfc_write_shm(ctx, shm, SAMPLE_ASPECT_RATIO_IDC);
+               if (p_264->vui_sar_idc == 0xFF) {
+                       /* sample  AR info */
+                       shm = s5p_mfc_read_shm(ctx, EXTENDED_SAR);
+                       shm &= ~(0xFFFFFFFF);
+                       shm |= p_264->vui_ext_sar_width << 16;
+                       shm |= p_264->vui_ext_sar_height;
+                       s5p_mfc_write_shm(ctx, shm, EXTENDED_SAR);
+               }
+       }
+       /* intra picture period for H.264 */
+       shm = s5p_mfc_read_shm(ctx, H264_I_PERIOD);
+       /* control */
+       shm &= ~(0x1 << 16);
+       shm |= (p_264->open_gop << 16);
+       /* value */
+       if (p_264->open_gop) {
+               shm &= ~(0xFFFF);
+               shm |= p_264->open_gop_size;
+       }
+       s5p_mfc_write_shm(ctx, shm, H264_I_PERIOD);
+       /* extended encoder ctrl */
+       shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL);
+       /* vbv buffer size */
+       if (p->frame_skip_mode ==
+                       V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
+               shm &= ~(0xFFFF << 16);
+               shm |= (p_264->cpb_size << 16);
+       }
+       s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL);
+       return 0;
+}
+
+static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_enc_params *p = &ctx->enc_params;
+       struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4;
+       unsigned int reg;
+       unsigned int shm;
+       unsigned int framerate;
+
+       s5p_mfc_set_enc_params(ctx);
+       /* pictype : number of B */
+       reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL);
+       /* num_b_frame - 0 ~ 2 */
+       reg &= ~(0x3 << 16);
+       reg |= (p->num_b_frame << 16);
+       mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL);
+       /* profile & level */
+       reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE);
+       /* level */
+       reg &= ~(0xFF << 8);
+       reg |= (p_mpeg4->level << 8);
+       /* profile - 0 ~ 2 */
+       reg &= ~(0x3F);
+       reg |= p_mpeg4->profile;
+       mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE);
+       /* quarter_pixel */
+       mfc_write(dev, p_mpeg4->quarter_pixel, S5P_FIMV_ENC_MPEG4_QUART_PXL);
+       /* qp */
+       if (!p->rc_frame) {
+               shm = s5p_mfc_read_shm(ctx, P_B_FRAME_QP);
+               shm &= ~(0xFFF);
+               shm |= ((p_mpeg4->rc_b_frame_qp & 0x3F) << 6);
+               shm |= (p_mpeg4->rc_p_frame_qp & 0x3F);
+               s5p_mfc_write_shm(ctx, shm, P_B_FRAME_QP);
+       }
+       /* frame rate */
+       if (p->rc_frame) {
+               if (p->rc_framerate_denom > 0) {
+                       framerate = p->rc_framerate_num * 1000 /
+                                               p->rc_framerate_denom;
+                       mfc_write(dev, framerate,
+                               S5P_FIMV_ENC_RC_FRAME_RATE);
+                       shm = s5p_mfc_read_shm(ctx, RC_VOP_TIMING);
+                       shm &= ~(0xFFFFFFFF);
+                       shm |= (1 << 31);
+                       shm |= ((p->rc_framerate_num & 0x7FFF) << 16);
+                       shm |= (p->rc_framerate_denom & 0xFFFF);
+                       s5p_mfc_write_shm(ctx, shm, RC_VOP_TIMING);
+               }
+       } else {
+               mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE);
+       }
+       /* rate control config. */
+       reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG);
+       /* frame QP */
+       reg &= ~(0x3F);
+       reg |= p_mpeg4->rc_frame_qp;
+       mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG);
+       /* max & min value of QP */
+       reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND);
+       /* max QP */
+       reg &= ~(0x3F << 8);
+       reg |= (p_mpeg4->rc_max_qp << 8);
+       /* min QP */
+       reg &= ~(0x3F);
+       reg |= p_mpeg4->rc_min_qp;
+       mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND);
+       /* extended encoder ctrl */
+       shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL);
+       /* vbv buffer size */
+       if (p->frame_skip_mode ==
+                       V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
+               shm &= ~(0xFFFF << 16);
+               shm |= (p->vbv_size << 16);
+       }
+       s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL);
+       return 0;
+}
+
+static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_enc_params *p = &ctx->enc_params;
+       struct s5p_mfc_mpeg4_enc_params *p_h263 = &p->codec.mpeg4;
+       unsigned int reg;
+       unsigned int shm;
+
+       s5p_mfc_set_enc_params(ctx);
+       /* qp */
+       if (!p->rc_frame) {
+               shm = s5p_mfc_read_shm(ctx, P_B_FRAME_QP);
+               shm &= ~(0xFFF);
+               shm |= (p_h263->rc_p_frame_qp & 0x3F);
+               s5p_mfc_write_shm(ctx, shm, P_B_FRAME_QP);
+       }
+       /* frame rate */
+       if (p->rc_frame && p->rc_framerate_denom)
+               mfc_write(dev, p->rc_framerate_num * 1000
+                       / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE);
+       else
+               mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE);
+       /* rate control config. */
+       reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG);
+       /* frame QP */
+       reg &= ~(0x3F);
+       reg |= p_h263->rc_frame_qp;
+       mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG);
+       /* max & min value of QP */
+       reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND);
+       /* max QP */
+       reg &= ~(0x3F << 8);
+       reg |= (p_h263->rc_max_qp << 8);
+       /* min QP */
+       reg &= ~(0x3F);
+       reg |= p_h263->rc_min_qp;
+       mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND);
+       /* extended encoder ctrl */
+       shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL);
+       /* vbv buffer size */
+       if (p->frame_skip_mode ==
+                       V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
+               shm &= ~(0xFFFF << 16);
+               shm |= (p->vbv_size << 16);
+       }
+       s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL);
+       return 0;
+}
+
+/* Initialize decoding */
+int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       s5p_mfc_set_shared_buffer(ctx);
+       /* Setup loop filter, for decoding this is only valid for MPEG4 */
+       if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG4_DEC)
+               mfc_write(dev, ctx->loop_filter_mpeg4, S5P_FIMV_ENC_LF_CTRL);
+       else
+               mfc_write(dev, 0, S5P_FIMV_ENC_LF_CTRL);
+       mfc_write(dev, ((ctx->slice_interface & S5P_FIMV_SLICE_INT_MASK) <<
+               S5P_FIMV_SLICE_INT_SHIFT) | (ctx->display_delay_enable <<
+               S5P_FIMV_DDELAY_ENA_SHIFT) | ((ctx->display_delay &
+               S5P_FIMV_DDELAY_VAL_MASK) << S5P_FIMV_DDELAY_VAL_SHIFT),
+               S5P_FIMV_SI_CH0_DPB_CONF_CTRL);
+       mfc_write(dev,
+       ((S5P_FIMV_CH_SEQ_HEADER & S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT)
+                               | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
+       return 0;
+}
+
+static void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned int dpb;
+
+       if (flush)
+               dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) | (
+                       S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT);
+       else
+               dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) &
+                       ~(S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT);
+       mfc_write(dev, dpb, S5P_FIMV_SI_CH0_DPB_CONF_CTRL);
+}
+
+/* Decode a single frame */
+int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx,
+                                       enum s5p_mfc_decode_arg last_frame)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       mfc_write(dev, ctx->dec_dst_flag, S5P_FIMV_SI_CH0_RELEASE_BUF);
+       s5p_mfc_set_shared_buffer(ctx);
+       s5p_mfc_set_flush(ctx, ctx->dpb_flush_flag);
+       /* Issue different commands to instance basing on whether it
+        * is the last frame or not. */
+       switch (last_frame) {
+       case MFC_DEC_FRAME:
+               mfc_write(dev, ((S5P_FIMV_CH_FRAME_START & S5P_FIMV_CH_MASK) <<
+               S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
+               break;
+       case MFC_DEC_LAST_FRAME:
+               mfc_write(dev, ((S5P_FIMV_CH_LAST_FRAME & S5P_FIMV_CH_MASK) <<
+               S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
+               break;
+       case MFC_DEC_RES_CHANGE:
+               mfc_write(dev, ((S5P_FIMV_CH_FRAME_START_REALLOC &
+               S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) | (ctx->inst_no),
+               S5P_FIMV_SI_CH0_INST_ID);
+               break;
+       }
+       mfc_debug(2, "Decoding a usual frame\n");
+       return 0;
+}
+
+int s5p_mfc_init_encode(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC)
+               s5p_mfc_set_enc_params_h264(ctx);
+       else if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG4_ENC)
+               s5p_mfc_set_enc_params_mpeg4(ctx);
+       else if (ctx->codec_mode == S5P_FIMV_CODEC_H263_ENC)
+               s5p_mfc_set_enc_params_h263(ctx);
+       else {
+               mfc_err("Unknown codec for encoding (%x)\n",
+                       ctx->codec_mode);
+               return -EINVAL;
+       }
+       s5p_mfc_set_shared_buffer(ctx);
+       mfc_write(dev, ((S5P_FIMV_CH_SEQ_HEADER << 16) & 0x70000) |
+               (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
+       return 0;
+}
+
+/* Encode a single frame */
+int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       /* memory structure cur. frame */
+       if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M)
+               mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR);
+       else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT)
+               mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR);
+       s5p_mfc_set_shared_buffer(ctx);
+       mfc_write(dev, (S5P_FIMV_CH_FRAME_START << 16 & 0x70000) |
+               (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
+       return 0;
+}
+
+static int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev)
+{
+       unsigned long flags;
+       int new_ctx;
+       int cnt;
+
+       spin_lock_irqsave(&dev->condlock, flags);
+       new_ctx = (dev->curr_ctx + 1) % MFC_NUM_CONTEXTS;
+       cnt = 0;
+       while (!test_bit(new_ctx, &dev->ctx_work_bits)) {
+               new_ctx = (new_ctx + 1) % MFC_NUM_CONTEXTS;
+               if (++cnt > MFC_NUM_CONTEXTS) {
+                       /* No contexts to run */
+                       spin_unlock_irqrestore(&dev->condlock, flags);
+                       return -EAGAIN;
+               }
+       }
+       spin_unlock_irqrestore(&dev->condlock, flags);
+       return new_ctx;
+}
+
+static void s5p_mfc_run_res_change(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       s5p_mfc_set_dec_stream_buffer(ctx, 0, 0, 0);
+       dev->curr_ctx = ctx->num;
+       s5p_mfc_clean_ctx_int_flags(ctx);
+       s5p_mfc_decode_one_frame(ctx, MFC_DEC_RES_CHANGE);
+}
+
+static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_buf *temp_vb;
+       unsigned long flags;
+       unsigned int index;
+
+       spin_lock_irqsave(&dev->irqlock, flags);
+       /* Frames are being decoded */
+       if (list_empty(&ctx->src_queue)) {
+               mfc_debug(2, "No src buffers\n");
+               spin_unlock_irqrestore(&dev->irqlock, flags);
+               return -EAGAIN;
+       }
+       /* Get the next source buffer */
+       temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+       temp_vb->used = 1;
+       s5p_mfc_set_dec_stream_buffer(ctx,
+               vb2_dma_contig_plane_paddr(temp_vb->b, 0), ctx->consumed_stream,
+                                       temp_vb->b->v4l2_planes[0].bytesused);
+       spin_unlock_irqrestore(&dev->irqlock, flags);
+       index = temp_vb->b->v4l2_buf.index;
+       dev->curr_ctx = ctx->num;
+       s5p_mfc_clean_ctx_int_flags(ctx);
+       if (temp_vb->b->v4l2_planes[0].bytesused == 0) {
+               last_frame = MFC_DEC_LAST_FRAME;
+               mfc_debug(2, "Setting ctx->state to FINISHING\n");
+               ctx->state = MFCINST_FINISHING;
+       }
+       s5p_mfc_decode_one_frame(ctx, last_frame);
+       return 0;
+}
+
+static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned long flags;
+       struct s5p_mfc_buf *dst_mb;
+       struct s5p_mfc_buf *src_mb;
+       unsigned long src_y_addr, src_c_addr, dst_addr;
+       unsigned int dst_size;
+
+       spin_lock_irqsave(&dev->irqlock, flags);
+       if (list_empty(&ctx->src_queue)) {
+               mfc_debug(2, "no src buffers\n");
+               spin_unlock_irqrestore(&dev->irqlock, flags);
+               return -EAGAIN;
+       }
+       if (list_empty(&ctx->dst_queue)) {
+               mfc_debug(2, "no dst buffers\n");
+               spin_unlock_irqrestore(&dev->irqlock, flags);
+               return -EAGAIN;
+       }
+       src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+       src_mb->used = 1;
+       src_y_addr = vb2_dma_contig_plane_paddr(src_mb->b, 0);
+       src_c_addr = vb2_dma_contig_plane_paddr(src_mb->b, 1);
+       s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, src_c_addr);
+       dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
+       dst_mb->used = 1;
+       dst_addr = vb2_dma_contig_plane_paddr(dst_mb->b, 0);
+       dst_size = vb2_plane_size(dst_mb->b, 0);
+       s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
+       spin_unlock_irqrestore(&dev->irqlock, flags);
+       dev->curr_ctx = ctx->num;
+       s5p_mfc_clean_ctx_int_flags(ctx);
+       s5p_mfc_encode_one_frame(ctx);
+       return 0;
+}
+
+static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned long flags;
+       struct s5p_mfc_buf *temp_vb;
+
+       /* Initializing decoding - parsing header */
+       spin_lock_irqsave(&dev->irqlock, flags);
+       mfc_debug(2, "Preparing to init decoding\n");
+       temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+       s5p_mfc_set_dec_desc_buffer(ctx);
+       mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused);
+       s5p_mfc_set_dec_stream_buffer(ctx,
+                               vb2_dma_contig_plane_paddr(temp_vb->b, 0),
+                               0, temp_vb->b->v4l2_planes[0].bytesused);
+       spin_unlock_irqrestore(&dev->irqlock, flags);
+       dev->curr_ctx = ctx->num;
+       s5p_mfc_clean_ctx_int_flags(ctx);
+       s5p_mfc_init_decode(ctx);
+}
+
+static void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned long flags;
+       struct s5p_mfc_buf *dst_mb;
+       unsigned long dst_addr;
+       unsigned int dst_size;
+
+       s5p_mfc_set_enc_ref_buffer(ctx);
+       spin_lock_irqsave(&dev->irqlock, flags);
+       dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
+       dst_addr = vb2_dma_contig_plane_paddr(dst_mb->b, 0);
+       dst_size = vb2_plane_size(dst_mb->b, 0);
+       s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
+       spin_unlock_irqrestore(&dev->irqlock, flags);
+       dev->curr_ctx = ctx->num;
+       s5p_mfc_clean_ctx_int_flags(ctx);
+       s5p_mfc_init_encode(ctx);
+}
+
+static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned long flags;
+       struct s5p_mfc_buf *temp_vb;
+       int ret;
+
+       /*
+        * Header was parsed now starting processing
+        * First set the output frame buffers
+        */
+       if (ctx->capture_state != QUEUE_BUFS_MMAPED) {
+               mfc_err("It seems that not all destionation buffers were "
+                       "mmaped\nMFC requires that all destination are mmaped "
+                       "before starting processing\n");
+               return -EAGAIN;
+       }
+       spin_lock_irqsave(&dev->irqlock, flags);
+       if (list_empty(&ctx->src_queue)) {
+               mfc_err("Header has been deallocated in the middle of"
+                       " initialization\n");
+               spin_unlock_irqrestore(&dev->irqlock, flags);
+               return -EIO;
+       }
+       temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+       mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused);
+       s5p_mfc_set_dec_stream_buffer(ctx,
+                               vb2_dma_contig_plane_paddr(temp_vb->b, 0),
+                               0, temp_vb->b->v4l2_planes[0].bytesused);
+       spin_unlock_irqrestore(&dev->irqlock, flags);
+       dev->curr_ctx = ctx->num;
+       s5p_mfc_clean_ctx_int_flags(ctx);
+       ret = s5p_mfc_set_dec_frame_buffer(ctx);
+       if (ret) {
+               mfc_err("Failed to alloc frame mem\n");
+               ctx->state = MFCINST_ERROR;
+       }
+       return ret;
+}
+
+/* Try running an operation on hardware */
+void s5p_mfc_try_run(struct s5p_mfc_dev *dev)
+{
+       struct s5p_mfc_ctx *ctx;
+       int new_ctx;
+       unsigned int ret = 0;
+
+       if (test_bit(0, &dev->enter_suspend)) {
+               mfc_debug(1, "Entering suspend so do not schedule any jobs\n");
+               return;
+       }
+       /* Check whether hardware is not running */
+       if (test_and_set_bit(0, &dev->hw_lock) != 0) {
+               /* This is perfectly ok, the scheduled ctx should wait */
+               mfc_debug(1, "Couldn't lock HW\n");
+               return;
+       }
+       /* Choose the context to run */
+       new_ctx = s5p_mfc_get_new_ctx(dev);
+       if (new_ctx < 0) {
+               /* No contexts to run */
+               if (test_and_clear_bit(0, &dev->hw_lock) == 0) {
+                       mfc_err("Failed to unlock hardware\n");
+                       return;
+               }
+               mfc_debug(1, "No ctx is scheduled to be run\n");
+               return;
+       }
+       ctx = dev->ctx[new_ctx];
+       /* Got context to run in ctx */
+       /*
+        * Last frame has already been sent to MFC.
+        * Now obtaining frames from MFC buffer
+        */
+       s5p_mfc_clock_on();
+       if (ctx->type == MFCINST_DECODER) {
+               s5p_mfc_set_dec_desc_buffer(ctx);
+               switch (ctx->state) {
+               case MFCINST_FINISHING:
+                       s5p_mfc_run_dec_frame(ctx, MFC_DEC_LAST_FRAME);
+                       break;
+               case MFCINST_RUNNING:
+                       ret = s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME);
+                       break;
+               case MFCINST_INIT:
+                       s5p_mfc_clean_ctx_int_flags(ctx);
+                       ret = s5p_mfc_open_inst_cmd(ctx);
+                       break;
+               case MFCINST_RETURN_INST:
+                       s5p_mfc_clean_ctx_int_flags(ctx);
+                       ret = s5p_mfc_close_inst_cmd(ctx);
+                       break;
+               case MFCINST_GOT_INST:
+                       s5p_mfc_run_init_dec(ctx);
+                       break;
+               case MFCINST_HEAD_PARSED:
+                       ret = s5p_mfc_run_init_dec_buffers(ctx);
+                       mfc_debug(1, "head parsed\n");
+                       break;
+               case MFCINST_RES_CHANGE_INIT:
+                       s5p_mfc_run_res_change(ctx);
+                       break;
+               case MFCINST_RES_CHANGE_FLUSH:
+                       s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME);
+                       break;
+               case MFCINST_RES_CHANGE_END:
+                       mfc_debug(2, "Finished remaining frames after resolution change\n");
+                       ctx->capture_state = QUEUE_FREE;
+                       mfc_debug(2, "Will re-init the codec\n");
+                       s5p_mfc_run_init_dec(ctx);
+                       break;
+               default:
+                       ret = -EAGAIN;
+               }
+       } else if (ctx->type == MFCINST_ENCODER) {
+               switch (ctx->state) {
+               case MFCINST_FINISHING:
+               case MFCINST_RUNNING:
+                       ret = s5p_mfc_run_enc_frame(ctx);
+                       break;
+               case MFCINST_INIT:
+                       s5p_mfc_clean_ctx_int_flags(ctx);
+                       ret = s5p_mfc_open_inst_cmd(ctx);
+                       break;
+               case MFCINST_RETURN_INST:
+                       s5p_mfc_clean_ctx_int_flags(ctx);
+                       ret = s5p_mfc_close_inst_cmd(ctx);
+                       break;
+               case MFCINST_GOT_INST:
+                       s5p_mfc_run_init_enc(ctx);
+                       break;
+               default:
+                       ret = -EAGAIN;
+               }
+       } else {
+               mfc_err("Invalid context type: %d\n", ctx->type);
+               ret = -EAGAIN;
+       }
+
+       if (ret) {
+               /* Free hardware lock */
+               if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+                       mfc_err("Failed to unlock hardware\n");
+
+               /* This is in deed imporant, as no operation has been
+                * scheduled, reduce the clock count as no one will
+                * ever do this, because no interrupt related to this try_run
+                * will ever come from hardware. */
+               s5p_mfc_clock_off();
+       }
+}
+
+
+void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq)
+{
+       struct s5p_mfc_buf *b;
+       int i;
+
+       while (!list_empty(lh)) {
+               b = list_entry(lh->next, struct s5p_mfc_buf, list);
+               for (i = 0; i < b->b->num_planes; i++)
+                       vb2_set_plane_payload(b->b, i, 0);
+               vb2_buffer_done(b->b, VB2_BUF_STATE_ERROR);
+               list_del(&b->list);
+       }
+}
+
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_opr.h b/drivers/media/video/s5p-mfc/s5p_mfc_opr.h
new file mode 100644 (file)
index 0000000..db83836
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * drivers/media/video/samsung/mfc5/s5p_mfc_opr.h
+ *
+ * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
+ * Contains declarations of hw related functions.
+ *
+ * Kamil Debski, Copyright (C) 2011 Samsung Electronics
+ * http://www.samsung.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 S5P_MFC_OPR_H_
+#define S5P_MFC_OPR_H_
+
+#include "s5p_mfc_common.h"
+
+int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_init_encode(struct s5p_mfc_ctx *mfc_ctx);
+
+/* Decoding functions */
+int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, int buf_addr,
+                                                 unsigned int start_num_byte,
+                                                 unsigned int buf_size);
+
+/* Encoding functions */
+void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+               unsigned long y_addr, unsigned long c_addr);
+int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx,
+               unsigned long addr, unsigned int size);
+void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+               unsigned long *y_addr, unsigned long *c_addr);
+int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *mfc_ctx);
+
+int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx,
+                                       enum s5p_mfc_decode_arg last_frame);
+int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *mfc_ctx);
+
+/* Memory allocation */
+int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx);
+
+int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx);
+
+int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx);
+
+void s5p_mfc_try_run(struct s5p_mfc_dev *dev);
+void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq);
+
+#define s5p_mfc_get_dspl_y_adr()       (readl(dev->regs_base + \
+                                       S5P_FIMV_SI_DISPLAY_Y_ADR) << \
+                                       MFC_OFFSET_SHIFT)
+#define s5p_mfc_get_dec_y_adr()                (readl(dev->regs_base + \
+                                       S5P_FIMV_SI_DISPLAY_Y_ADR) << \
+                                       MFC_OFFSET_SHIFT)
+#define s5p_mfc_get_dspl_status()      readl(dev->regs_base + \
+                                               S5P_FIMV_SI_DISPLAY_STATUS)
+#define s5p_mfc_get_frame_type()       (readl(dev->regs_base + \
+                                               S5P_FIMV_DECODE_FRAME_TYPE) \
+                                       & S5P_FIMV_DECODE_FRAME_MASK)
+#define s5p_mfc_get_consumed_stream()  readl(dev->regs_base + \
+                                               S5P_FIMV_SI_CONSUMED_BYTES)
+#define s5p_mfc_get_int_reason()       (readl(dev->regs_base + \
+                                       S5P_FIMV_RISC2HOST_CMD) & \
+                                       S5P_FIMV_RISC2HOST_CMD_MASK)
+#define s5p_mfc_get_int_err()          readl(dev->regs_base + \
+                                               S5P_FIMV_RISC2HOST_ARG2)
+#define s5p_mfc_err_dec(x)             (((x) & S5P_FIMV_ERR_DEC_MASK) >> \
+                                                       S5P_FIMV_ERR_DEC_SHIFT)
+#define s5p_mfc_err_dspl(x)            (((x) & S5P_FIMV_ERR_DSPL_MASK) >> \
+                                                       S5P_FIMV_ERR_DSPL_SHIFT)
+#define s5p_mfc_get_img_width()                readl(dev->regs_base + \
+                                               S5P_FIMV_SI_HRESOL)
+#define s5p_mfc_get_img_height()       readl(dev->regs_base + \
+                                               S5P_FIMV_SI_VRESOL)
+#define s5p_mfc_get_dpb_count()                readl(dev->regs_base + \
+                                               S5P_FIMV_SI_BUF_NUMBER)
+#define s5p_mfc_get_inst_no()          readl(dev->regs_base + \
+                                               S5P_FIMV_RISC2HOST_ARG1)
+#define s5p_mfc_get_enc_strm_size()    readl(dev->regs_base + \
+                                               S5P_FIMV_ENC_SI_STRM_SIZE)
+#define s5p_mfc_get_enc_slice_type()   readl(dev->regs_base + \
+                                               S5P_FIMV_ENC_SI_SLICE_TYPE)
+
+#endif /* S5P_MFC_OPR_H_ */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_pm.c b/drivers/media/video/s5p-mfc/s5p_mfc_pm.c
new file mode 100644 (file)
index 0000000..f6a3035
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * linux/drivers/media/video/s5p-mfc/s5p_mfc_pm.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#ifdef CONFIG_PM_RUNTIME
+#include <linux/pm_runtime.h>
+#endif
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_pm.h"
+
+#define MFC_CLKNAME            "sclk_mfc"
+#define MFC_GATE_CLK_NAME      "mfc"
+
+#define CLK_DEBUG
+
+static struct s5p_mfc_pm *pm;
+static struct s5p_mfc_dev *p_dev;
+
+#ifdef CLK_DEBUG
+atomic_t clk_ref;
+#endif
+
+int s5p_mfc_init_pm(struct s5p_mfc_dev *dev)
+{
+       int ret = 0;
+
+       pm = &dev->pm;
+       p_dev = dev;
+       pm->clock_gate = clk_get(&dev->plat_dev->dev, MFC_GATE_CLK_NAME);
+       if (IS_ERR(pm->clock_gate)) {
+               mfc_err("Failed to get clock-gating control\n");
+               ret = -ENOENT;
+               goto err_g_ip_clk;
+       }
+       pm->clock = clk_get(&dev->plat_dev->dev, MFC_CLKNAME);
+       if (IS_ERR(pm->clock)) {
+               mfc_err("Failed to get MFC clock\n");
+               ret = -ENOENT;
+               goto err_g_ip_clk_2;
+       }
+       atomic_set(&pm->power, 0);
+#ifdef CONFIG_PM_RUNTIME
+       pm->device = &dev->plat_dev->dev;
+       pm_runtime_enable(pm->device);
+#endif
+#ifdef CLK_DEBUG
+       atomic_set(&clk_ref, 0);
+#endif
+       return 0;
+err_g_ip_clk_2:
+       clk_put(pm->clock_gate);
+err_g_ip_clk:
+       return ret;
+}
+
+void s5p_mfc_final_pm(struct s5p_mfc_dev *dev)
+{
+       clk_put(pm->clock_gate);
+       clk_put(pm->clock);
+#ifdef CONFIG_PM_RUNTIME
+       pm_runtime_disable(pm->device);
+#endif
+}
+
+int s5p_mfc_clock_on(void)
+{
+       int ret;
+#ifdef CLK_DEBUG
+       atomic_inc(&clk_ref);
+       mfc_debug(3, "+ %d", atomic_read(&clk_ref));
+#endif
+       ret = clk_enable(pm->clock_gate);
+       return ret;
+}
+
+void s5p_mfc_clock_off(void)
+{
+#ifdef CLK_DEBUG
+       atomic_dec(&clk_ref);
+       mfc_debug(3, "- %d", atomic_read(&clk_ref));
+#endif
+       clk_disable(pm->clock_gate);
+}
+
+int s5p_mfc_power_on(void)
+{
+#ifdef CONFIG_PM_RUNTIME
+       return pm_runtime_get_sync(pm->device);
+#else
+       atomic_set(&pm->power, 1);
+       return 0;
+#endif
+}
+
+int s5p_mfc_power_off(void)
+{
+#ifdef CONFIG_PM_RUNTIME
+       return pm_runtime_put_sync(pm->device);
+#else
+       atomic_set(&pm->power, 0);
+       return 0;
+#endif
+}
+
+
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_pm.h b/drivers/media/video/s5p-mfc/s5p_mfc_pm.h
new file mode 100644 (file)
index 0000000..5107914
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * linux/drivers/media/video/s5p-mfc/s5p_mfc_pm.h
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.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.
+ */
+
+#ifndef S5P_MFC_PM_H_
+#define S5P_MFC_PM_H_
+
+int s5p_mfc_init_pm(struct s5p_mfc_dev *dev);
+void s5p_mfc_final_pm(struct s5p_mfc_dev *dev);
+
+int s5p_mfc_clock_on(void);
+void s5p_mfc_clock_off(void);
+int s5p_mfc_power_on(void);
+int s5p_mfc_power_off(void);
+
+#endif /* S5P_MFC_PM_H_ */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_shm.c b/drivers/media/video/s5p-mfc/s5p_mfc_shm.c
new file mode 100644 (file)
index 0000000..91fdbac
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * linux/drivers/media/video/s5p-mfc/s5p_mfc_shm.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.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.
+ */
+
+#ifdef CONFIG_ARCH_EXYNOS4
+#include <linux/dma-mapping.h>
+#endif
+#include <linux/io.h>
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+
+int s5p_mfc_init_shm(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       void *shm_alloc_ctx = dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
+
+       ctx->shm_alloc = vb2_dma_contig_memops.alloc(shm_alloc_ctx,
+                                                       SHARED_BUF_SIZE);
+       if (IS_ERR(ctx->shm_alloc)) {
+               mfc_err("failed to allocate shared memory\n");
+               return PTR_ERR(ctx->shm_alloc);
+       }
+       /* shm_ofs only keeps the offset from base (port a) */
+       ctx->shm_ofs = s5p_mfc_mem_cookie(shm_alloc_ctx, ctx->shm_alloc)
+                                                               - dev->bank1;
+       BUG_ON(ctx->shm_ofs & ((1 << MFC_BANK1_ALIGN_ORDER) - 1));
+       ctx->shm = vb2_dma_contig_memops.vaddr(ctx->shm_alloc);
+       if (!ctx->shm) {
+               vb2_dma_contig_memops.put(ctx->shm_alloc);
+               ctx->shm_ofs = 0;
+               ctx->shm_alloc = NULL;
+               mfc_err("failed to virt addr of shared memory\n");
+               return -ENOMEM;
+       }
+       memset((void *)ctx->shm, 0, SHARED_BUF_SIZE);
+       wmb();
+       return 0;
+}
+
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_shm.h b/drivers/media/video/s5p-mfc/s5p_mfc_shm.h
new file mode 100644 (file)
index 0000000..764eac6
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * linux/drivers/media/video/s5p-mfc/s5p_mfc_shm.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.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.
+ */
+
+#ifndef S5P_MFC_SHM_H_
+#define S5P_MFC_SHM_H_
+
+enum MFC_SHM_OFS
+{
+       EXTENEDED_DECODE_STATUS = 0x00, /* D */
+       SET_FRAME_TAG           = 0x04, /* D */
+       GET_FRAME_TAG_TOP       = 0x08, /* D */
+       GET_FRAME_TAG_BOT       = 0x0C, /* D */
+       PIC_TIME_TOP            = 0x10, /* D */
+       PIC_TIME_BOT            = 0x14, /* D */
+       START_BYTE_NUM          = 0x18, /* D */
+
+       CROP_INFO_H             = 0x20, /* D */
+       CROP_INFO_V             = 0x24, /* D */
+       EXT_ENC_CONTROL         = 0x28, /* E */
+       ENC_PARAM_CHANGE        = 0x2C, /* E */
+       RC_VOP_TIMING           = 0x30, /* E, MPEG4 */
+       HEC_PERIOD              = 0x34, /* E, MPEG4 */
+       METADATA_ENABLE         = 0x38, /* C */
+       METADATA_STATUS         = 0x3C, /* C */
+       METADATA_DISPLAY_INDEX  = 0x40, /* C */
+       EXT_METADATA_START_ADDR = 0x44, /* C */
+       PUT_EXTRADATA           = 0x48, /* C */
+       EXTRADATA_ADDR          = 0x4C, /* C */
+
+       ALLOC_LUMA_DPB_SIZE     = 0x64, /* D */
+       ALLOC_CHROMA_DPB_SIZE   = 0x68, /* D */
+       ALLOC_MV_SIZE           = 0x6C, /* D */
+       P_B_FRAME_QP            = 0x70, /* E */
+       SAMPLE_ASPECT_RATIO_IDC = 0x74, /* E, H.264, depend on
+                               ASPECT_RATIO_VUI_ENABLE in EXT_ENC_CONTROL */
+       EXTENDED_SAR            = 0x78, /* E, H.264, depned on
+                               ASPECT_RATIO_VUI_ENABLE in EXT_ENC_CONTROL */
+       DISP_PIC_PROFILE        = 0x7C, /* D */
+       FLUSH_CMD_TYPE          = 0x80, /* C */
+       FLUSH_CMD_INBUF1        = 0x84, /* C */
+       FLUSH_CMD_INBUF2        = 0x88, /* C */
+       FLUSH_CMD_OUTBUF        = 0x8C, /* E */
+       NEW_RC_BIT_RATE         = 0x90, /* E, format as RC_BIT_RATE(0xC5A8)
+                       depend on RC_BIT_RATE_CHANGE in ENC_PARAM_CHANGE */
+       NEW_RC_FRAME_RATE       = 0x94, /* E, format as RC_FRAME_RATE(0xD0D0)
+                       depend on RC_FRAME_RATE_CHANGE in ENC_PARAM_CHANGE */
+       NEW_I_PERIOD            = 0x98, /* E, format as I_FRM_CTRL(0xC504)
+                       depend on I_PERIOD_CHANGE in ENC_PARAM_CHANGE */
+       H264_I_PERIOD           = 0x9C, /* E, H.264, open GOP */
+       RC_CONTROL_CONFIG       = 0xA0, /* E */
+       BATCH_INPUT_ADDR        = 0xA4, /* E */
+       BATCH_OUTPUT_ADDR       = 0xA8, /* E */
+       BATCH_OUTPUT_SIZE       = 0xAC, /* E */
+       MIN_LUMA_DPB_SIZE       = 0xB0, /* D */
+       DEVICE_FORMAT_ID        = 0xB4, /* C */
+       H264_POC_TYPE           = 0xB8, /* D */
+       MIN_CHROMA_DPB_SIZE     = 0xBC, /* D */
+       DISP_PIC_FRAME_TYPE     = 0xC0, /* D */
+       FREE_LUMA_DPB           = 0xC4, /* D, VC1 MPEG4 */
+       ASPECT_RATIO_INFO       = 0xC8, /* D, MPEG4 */
+       EXTENDED_PAR            = 0xCC, /* D, MPEG4 */
+       DBG_HISTORY_INPUT0      = 0xD0, /* C */
+       DBG_HISTORY_INPUT1      = 0xD4, /* C */
+       DBG_HISTORY_OUTPUT      = 0xD8, /* C */
+       HIERARCHICAL_P_QP       = 0xE0, /* E, H.264 */
+};
+
+int s5p_mfc_init_shm(struct s5p_mfc_ctx *ctx);
+
+#define s5p_mfc_write_shm(ctx, x, ofs)         \
+       do {                                    \
+               writel(x, (ctx->shm + ofs));    \
+               wmb();                          \
+       } while (0)
+
+static inline u32 s5p_mfc_read_shm(struct s5p_mfc_ctx *ctx, unsigned int ofs)
+{
+       rmb();
+       return readl(ctx->shm + ofs);
+}
+
+#endif /* S5P_MFC_SHM_H_ */
diff --git a/drivers/media/video/s5p-tv/Kconfig b/drivers/media/video/s5p-tv/Kconfig
new file mode 100644 (file)
index 0000000..9c37dee
--- /dev/null
@@ -0,0 +1,76 @@
+# drivers/media/video/s5p-tv/Kconfig
+#
+# Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+#      http://www.samsung.com/
+# Tomasz Stanislawski <t.stanislaws@samsung.com>
+#
+# Licensed under GPL
+
+config VIDEO_SAMSUNG_S5P_TV
+       bool "Samsung TV driver for S5P platform (experimental)"
+       depends on PLAT_S5P
+       depends on EXPERIMENTAL
+       default n
+       ---help---
+         Say Y here to enable selecting the TV output devices for
+         Samsung S5P platform.
+
+if VIDEO_SAMSUNG_S5P_TV
+
+config VIDEO_SAMSUNG_S5P_HDMI
+       tristate "Samsung HDMI Driver"
+       depends on VIDEO_V4L2
+       depends on VIDEO_SAMSUNG_S5P_TV
+       select VIDEO_SAMSUNG_S5P_HDMIPHY
+       help
+         Say Y here if you want support for the HDMI output
+         interface in S5P Samsung SoC. The driver can be compiled
+         as module. It is an auxiliary driver, that exposes a V4L2
+         subdev for use by other drivers. This driver requires
+         hdmiphy driver to work correctly.
+
+config VIDEO_SAMSUNG_S5P_HDMI_DEBUG
+       bool "Enable debug for HDMI Driver"
+       depends on VIDEO_SAMSUNG_S5P_HDMI
+       default n
+       help
+         Enables debugging for HDMI driver.
+
+config VIDEO_SAMSUNG_S5P_HDMIPHY
+       tristate "Samsung HDMIPHY Driver"
+       depends on VIDEO_DEV && VIDEO_V4L2 && I2C
+       depends on VIDEO_SAMSUNG_S5P_TV
+       help
+         Say Y here if you want support for the physical HDMI
+         interface in S5P Samsung SoC. The driver can be compiled
+         as module. It is an I2C driver, that exposes a V4L2
+         subdev for use by other drivers.
+
+config VIDEO_SAMSUNG_S5P_SDO
+       tristate "Samsung Analog TV Driver"
+       depends on VIDEO_DEV && VIDEO_V4L2
+       depends on VIDEO_SAMSUNG_S5P_TV
+       help
+         Say Y here if you want support for the analog TV output
+         interface in S5P Samsung SoC. The driver can be compiled
+         as module. It is an auxiliary driver, that exposes a V4L2
+         subdev for use by other drivers. This driver requires
+         hdmiphy driver to work correctly.
+
+config VIDEO_SAMSUNG_S5P_MIXER
+       tristate "Samsung Mixer and Video Processor Driver"
+       depends on VIDEO_DEV && VIDEO_V4L2
+       depends on VIDEO_SAMSUNG_S5P_TV
+       select VIDEOBUF2_DMA_CONTIG
+       help
+         Say Y here if you want support for the Mixer in Samsung S5P SoCs.
+         This device produce image data to one of output interfaces.
+
+config VIDEO_SAMSUNG_S5P_MIXER_DEBUG
+       bool "Enable debug for Mixer Driver"
+       depends on VIDEO_SAMSUNG_S5P_MIXER
+       default n
+       help
+         Enables debugging for Mixer driver.
+
+endif # VIDEO_SAMSUNG_S5P_TV
diff --git a/drivers/media/video/s5p-tv/Makefile b/drivers/media/video/s5p-tv/Makefile
new file mode 100644 (file)
index 0000000..37e4c17
--- /dev/null
@@ -0,0 +1,17 @@
+# drivers/media/video/samsung/tvout/Makefile
+#
+# Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+#      http://www.samsung.com/
+# Tomasz Stanislawski <t.stanislaws@samsung.com>
+#
+# Licensed under GPL
+
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMIPHY) += s5p-hdmiphy.o
+s5p-hdmiphy-y += hdmiphy_drv.o
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMI) += s5p-hdmi.o
+s5p-hdmi-y += hdmi_drv.o
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_SDO) += s5p-sdo.o
+s5p-sdo-y += sdo_drv.o
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MIXER) += s5p-mixer.o
+s5p-mixer-y += mixer_drv.o mixer_video.o mixer_reg.o mixer_grp_layer.o mixer_vp_layer.o
+
diff --git a/drivers/media/video/s5p-tv/hdmi_drv.c b/drivers/media/video/s5p-tv/hdmi_drv.c
new file mode 100644 (file)
index 0000000..06d6663
--- /dev/null
@@ -0,0 +1,1042 @@
+/*
+ * Samsung HDMI interface driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#ifdef CONFIG_VIDEO_SAMSUNG_S5P_HDMI_DEBUG
+#define DEBUG
+#endif
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-subdev.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/bug.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+
+#include "regs-hdmi.h"
+
+MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung HDMI");
+MODULE_LICENSE("GPL");
+
+/* default preset configured on probe */
+#define HDMI_DEFAULT_PRESET V4L2_DV_1080P60
+
+struct hdmi_resources {
+       struct clk *hdmi;
+       struct clk *sclk_hdmi;
+       struct clk *sclk_pixel;
+       struct clk *sclk_hdmiphy;
+       struct clk *hdmiphy;
+       struct regulator_bulk_data *regul_bulk;
+       int regul_count;
+};
+
+struct hdmi_device {
+       /** base address of HDMI registers */
+       void __iomem *regs;
+       /** HDMI interrupt */
+       unsigned int irq;
+       /** pointer to device parent */
+       struct device *dev;
+       /** subdev generated by HDMI device */
+       struct v4l2_subdev sd;
+       /** V4L2 device structure */
+       struct v4l2_device v4l2_dev;
+       /** subdev of HDMIPHY interface */
+       struct v4l2_subdev *phy_sd;
+       /** configuration of current graphic mode */
+       const struct hdmi_preset_conf *cur_conf;
+       /** current preset */
+       u32 cur_preset;
+       /** other resources */
+       struct hdmi_resources res;
+};
+
+struct hdmi_driver_data {
+       int hdmiphy_bus;
+};
+
+struct hdmi_tg_regs {
+       u8 cmd;
+       u8 h_fsz_l;
+       u8 h_fsz_h;
+       u8 hact_st_l;
+       u8 hact_st_h;
+       u8 hact_sz_l;
+       u8 hact_sz_h;
+       u8 v_fsz_l;
+       u8 v_fsz_h;
+       u8 vsync_l;
+       u8 vsync_h;
+       u8 vsync2_l;
+       u8 vsync2_h;
+       u8 vact_st_l;
+       u8 vact_st_h;
+       u8 vact_sz_l;
+       u8 vact_sz_h;
+       u8 field_chg_l;
+       u8 field_chg_h;
+       u8 vact_st2_l;
+       u8 vact_st2_h;
+       u8 vsync_top_hdmi_l;
+       u8 vsync_top_hdmi_h;
+       u8 vsync_bot_hdmi_l;
+       u8 vsync_bot_hdmi_h;
+       u8 field_top_hdmi_l;
+       u8 field_top_hdmi_h;
+       u8 field_bot_hdmi_l;
+       u8 field_bot_hdmi_h;
+};
+
+struct hdmi_core_regs {
+       u8 h_blank[2];
+       u8 v_blank[3];
+       u8 h_v_line[3];
+       u8 vsync_pol[1];
+       u8 int_pro_mode[1];
+       u8 v_blank_f[3];
+       u8 h_sync_gen[3];
+       u8 v_sync_gen1[3];
+       u8 v_sync_gen2[3];
+       u8 v_sync_gen3[3];
+};
+
+struct hdmi_preset_conf {
+       struct hdmi_core_regs core;
+       struct hdmi_tg_regs tg;
+       struct v4l2_mbus_framefmt mbus_fmt;
+};
+
+/* I2C module and id for HDMIPHY */
+static struct i2c_board_info hdmiphy_info = {
+       I2C_BOARD_INFO("hdmiphy", 0x38),
+};
+
+static struct hdmi_driver_data hdmi_driver_data[] = {
+       { .hdmiphy_bus = 3 },
+       { .hdmiphy_bus = 8 },
+};
+
+static struct platform_device_id hdmi_driver_types[] = {
+       {
+               .name           = "s5pv210-hdmi",
+               .driver_data    = (unsigned long)&hdmi_driver_data[0],
+       }, {
+               .name           = "exynos4-hdmi",
+               .driver_data    = (unsigned long)&hdmi_driver_data[1],
+       }, {
+               /* end node */
+       }
+};
+
+static const struct v4l2_subdev_ops hdmi_sd_ops;
+
+static struct hdmi_device *sd_to_hdmi_dev(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct hdmi_device, sd);
+}
+
+static inline
+void hdmi_write(struct hdmi_device *hdev, u32 reg_id, u32 value)
+{
+       writel(value, hdev->regs + reg_id);
+}
+
+static inline
+void hdmi_write_mask(struct hdmi_device *hdev, u32 reg_id, u32 value, u32 mask)
+{
+       u32 old = readl(hdev->regs + reg_id);
+       value = (value & mask) | (old & ~mask);
+       writel(value, hdev->regs + reg_id);
+}
+
+static inline
+void hdmi_writeb(struct hdmi_device *hdev, u32 reg_id, u8 value)
+{
+       writeb(value, hdev->regs + reg_id);
+}
+
+static inline u32 hdmi_read(struct hdmi_device *hdev, u32 reg_id)
+{
+       return readl(hdev->regs + reg_id);
+}
+
+static irqreturn_t hdmi_irq_handler(int irq, void *dev_data)
+{
+       struct hdmi_device *hdev = dev_data;
+       u32 intc_flag;
+
+       (void)irq;
+       intc_flag = hdmi_read(hdev, HDMI_INTC_FLAG);
+       /* clearing flags for HPD plug/unplug */
+       if (intc_flag & HDMI_INTC_FLAG_HPD_UNPLUG) {
+               printk(KERN_INFO "unplugged\n");
+               hdmi_write_mask(hdev, HDMI_INTC_FLAG, ~0,
+                       HDMI_INTC_FLAG_HPD_UNPLUG);
+       }
+       if (intc_flag & HDMI_INTC_FLAG_HPD_PLUG) {
+               printk(KERN_INFO "plugged\n");
+               hdmi_write_mask(hdev, HDMI_INTC_FLAG, ~0,
+                       HDMI_INTC_FLAG_HPD_PLUG);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void hdmi_reg_init(struct hdmi_device *hdev)
+{
+       /* enable HPD interrupts */
+       hdmi_write_mask(hdev, HDMI_INTC_CON, ~0, HDMI_INTC_EN_GLOBAL |
+               HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
+       /* choose HDMI mode */
+       hdmi_write_mask(hdev, HDMI_MODE_SEL,
+               HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
+       /* disable bluescreen */
+       hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
+       /* choose bluescreen (fecal) color */
+       hdmi_writeb(hdev, HDMI_BLUE_SCREEN_0, 0x12);
+       hdmi_writeb(hdev, HDMI_BLUE_SCREEN_1, 0x34);
+       hdmi_writeb(hdev, HDMI_BLUE_SCREEN_2, 0x56);
+       /* enable AVI packet every vsync, fixes purple line problem */
+       hdmi_writeb(hdev, HDMI_AVI_CON, 0x02);
+       /* force YUV444, look to CEA-861-D, table 7 for more detail */
+       hdmi_writeb(hdev, HDMI_AVI_BYTE(0), 2 << 5);
+       hdmi_write_mask(hdev, HDMI_CON_1, 2, 3 << 5);
+}
+
+static void hdmi_timing_apply(struct hdmi_device *hdev,
+       const struct hdmi_preset_conf *conf)
+{
+       const struct hdmi_core_regs *core = &conf->core;
+       const struct hdmi_tg_regs *tg = &conf->tg;
+
+       /* setting core registers */
+       hdmi_writeb(hdev, HDMI_H_BLANK_0, core->h_blank[0]);
+       hdmi_writeb(hdev, HDMI_H_BLANK_1, core->h_blank[1]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_0, core->v_blank[0]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_1, core->v_blank[1]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_2, core->v_blank[2]);
+       hdmi_writeb(hdev, HDMI_H_V_LINE_0, core->h_v_line[0]);
+       hdmi_writeb(hdev, HDMI_H_V_LINE_1, core->h_v_line[1]);
+       hdmi_writeb(hdev, HDMI_H_V_LINE_2, core->h_v_line[2]);
+       hdmi_writeb(hdev, HDMI_VSYNC_POL, core->vsync_pol[0]);
+       hdmi_writeb(hdev, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_F_0, core->v_blank_f[0]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_F_1, core->v_blank_f[1]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_F_2, core->v_blank_f[2]);
+       hdmi_writeb(hdev, HDMI_H_SYNC_GEN_0, core->h_sync_gen[0]);
+       hdmi_writeb(hdev, HDMI_H_SYNC_GEN_1, core->h_sync_gen[1]);
+       hdmi_writeb(hdev, HDMI_H_SYNC_GEN_2, core->h_sync_gen[2]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
+       /* Timing generator registers */
+       hdmi_writeb(hdev, HDMI_TG_H_FSZ_L, tg->h_fsz_l);
+       hdmi_writeb(hdev, HDMI_TG_H_FSZ_H, tg->h_fsz_h);
+       hdmi_writeb(hdev, HDMI_TG_HACT_ST_L, tg->hact_st_l);
+       hdmi_writeb(hdev, HDMI_TG_HACT_ST_H, tg->hact_st_h);
+       hdmi_writeb(hdev, HDMI_TG_HACT_SZ_L, tg->hact_sz_l);
+       hdmi_writeb(hdev, HDMI_TG_HACT_SZ_H, tg->hact_sz_h);
+       hdmi_writeb(hdev, HDMI_TG_V_FSZ_L, tg->v_fsz_l);
+       hdmi_writeb(hdev, HDMI_TG_V_FSZ_H, tg->v_fsz_h);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC_L, tg->vsync_l);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC_H, tg->vsync_h);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC2_L, tg->vsync2_l);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC2_H, tg->vsync2_h);
+       hdmi_writeb(hdev, HDMI_TG_VACT_ST_L, tg->vact_st_l);
+       hdmi_writeb(hdev, HDMI_TG_VACT_ST_H, tg->vact_st_h);
+       hdmi_writeb(hdev, HDMI_TG_VACT_SZ_L, tg->vact_sz_l);
+       hdmi_writeb(hdev, HDMI_TG_VACT_SZ_H, tg->vact_sz_h);
+       hdmi_writeb(hdev, HDMI_TG_FIELD_CHG_L, tg->field_chg_l);
+       hdmi_writeb(hdev, HDMI_TG_FIELD_CHG_H, tg->field_chg_h);
+       hdmi_writeb(hdev, HDMI_TG_VACT_ST2_L, tg->vact_st2_l);
+       hdmi_writeb(hdev, HDMI_TG_VACT_ST2_H, tg->vact_st2_h);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi_l);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi_h);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi_l);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi_h);
+       hdmi_writeb(hdev, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi_l);
+       hdmi_writeb(hdev, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi_h);
+       hdmi_writeb(hdev, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi_l);
+       hdmi_writeb(hdev, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi_h);
+}
+
+static int hdmi_conf_apply(struct hdmi_device *hdmi_dev)
+{
+       struct device *dev = hdmi_dev->dev;
+       const struct hdmi_preset_conf *conf = hdmi_dev->cur_conf;
+       struct v4l2_dv_preset preset;
+       int ret;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       /* reset hdmiphy */
+       hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
+       mdelay(10);
+       hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT,  0, HDMI_PHY_SW_RSTOUT);
+       mdelay(10);
+
+       /* configure presets */
+       preset.preset = hdmi_dev->cur_preset;
+       ret = v4l2_subdev_call(hdmi_dev->phy_sd, video, s_dv_preset, &preset);
+       if (ret) {
+               dev_err(dev, "failed to set preset (%u)\n", preset.preset);
+               return ret;
+       }
+
+       /* resetting HDMI core */
+       hdmi_write_mask(hdmi_dev, HDMI_CORE_RSTOUT,  0, HDMI_CORE_SW_RSTOUT);
+       mdelay(10);
+       hdmi_write_mask(hdmi_dev, HDMI_CORE_RSTOUT, ~0, HDMI_CORE_SW_RSTOUT);
+       mdelay(10);
+
+       hdmi_reg_init(hdmi_dev);
+
+       /* setting core registers */
+       hdmi_timing_apply(hdmi_dev, conf);
+
+       return 0;
+}
+
+static void hdmi_dumpregs(struct hdmi_device *hdev, char *prefix)
+{
+#define DUMPREG(reg_id) \
+       dev_dbg(hdev->dev, "%s:" #reg_id " = %08x\n", prefix, \
+               readl(hdev->regs + reg_id))
+
+       dev_dbg(hdev->dev, "%s: ---- CONTROL REGISTERS ----\n", prefix);
+       DUMPREG(HDMI_INTC_FLAG);
+       DUMPREG(HDMI_INTC_CON);
+       DUMPREG(HDMI_HPD_STATUS);
+       DUMPREG(HDMI_PHY_RSTOUT);
+       DUMPREG(HDMI_PHY_VPLL);
+       DUMPREG(HDMI_PHY_CMU);
+       DUMPREG(HDMI_CORE_RSTOUT);
+
+       dev_dbg(hdev->dev, "%s: ---- CORE REGISTERS ----\n", prefix);
+       DUMPREG(HDMI_CON_0);
+       DUMPREG(HDMI_CON_1);
+       DUMPREG(HDMI_CON_2);
+       DUMPREG(HDMI_SYS_STATUS);
+       DUMPREG(HDMI_PHY_STATUS);
+       DUMPREG(HDMI_STATUS_EN);
+       DUMPREG(HDMI_HPD);
+       DUMPREG(HDMI_MODE_SEL);
+       DUMPREG(HDMI_HPD_GEN);
+       DUMPREG(HDMI_DC_CONTROL);
+       DUMPREG(HDMI_VIDEO_PATTERN_GEN);
+
+       dev_dbg(hdev->dev, "%s: ---- CORE SYNC REGISTERS ----\n", prefix);
+       DUMPREG(HDMI_H_BLANK_0);
+       DUMPREG(HDMI_H_BLANK_1);
+       DUMPREG(HDMI_V_BLANK_0);
+       DUMPREG(HDMI_V_BLANK_1);
+       DUMPREG(HDMI_V_BLANK_2);
+       DUMPREG(HDMI_H_V_LINE_0);
+       DUMPREG(HDMI_H_V_LINE_1);
+       DUMPREG(HDMI_H_V_LINE_2);
+       DUMPREG(HDMI_VSYNC_POL);
+       DUMPREG(HDMI_INT_PRO_MODE);
+       DUMPREG(HDMI_V_BLANK_F_0);
+       DUMPREG(HDMI_V_BLANK_F_1);
+       DUMPREG(HDMI_V_BLANK_F_2);
+       DUMPREG(HDMI_H_SYNC_GEN_0);
+       DUMPREG(HDMI_H_SYNC_GEN_1);
+       DUMPREG(HDMI_H_SYNC_GEN_2);
+       DUMPREG(HDMI_V_SYNC_GEN_1_0);
+       DUMPREG(HDMI_V_SYNC_GEN_1_1);
+       DUMPREG(HDMI_V_SYNC_GEN_1_2);
+       DUMPREG(HDMI_V_SYNC_GEN_2_0);
+       DUMPREG(HDMI_V_SYNC_GEN_2_1);
+       DUMPREG(HDMI_V_SYNC_GEN_2_2);
+       DUMPREG(HDMI_V_SYNC_GEN_3_0);
+       DUMPREG(HDMI_V_SYNC_GEN_3_1);
+       DUMPREG(HDMI_V_SYNC_GEN_3_2);
+
+       dev_dbg(hdev->dev, "%s: ---- TG REGISTERS ----\n", prefix);
+       DUMPREG(HDMI_TG_CMD);
+       DUMPREG(HDMI_TG_H_FSZ_L);
+       DUMPREG(HDMI_TG_H_FSZ_H);
+       DUMPREG(HDMI_TG_HACT_ST_L);
+       DUMPREG(HDMI_TG_HACT_ST_H);
+       DUMPREG(HDMI_TG_HACT_SZ_L);
+       DUMPREG(HDMI_TG_HACT_SZ_H);
+       DUMPREG(HDMI_TG_V_FSZ_L);
+       DUMPREG(HDMI_TG_V_FSZ_H);
+       DUMPREG(HDMI_TG_VSYNC_L);
+       DUMPREG(HDMI_TG_VSYNC_H);
+       DUMPREG(HDMI_TG_VSYNC2_L);
+       DUMPREG(HDMI_TG_VSYNC2_H);
+       DUMPREG(HDMI_TG_VACT_ST_L);
+       DUMPREG(HDMI_TG_VACT_ST_H);
+       DUMPREG(HDMI_TG_VACT_SZ_L);
+       DUMPREG(HDMI_TG_VACT_SZ_H);
+       DUMPREG(HDMI_TG_FIELD_CHG_L);
+       DUMPREG(HDMI_TG_FIELD_CHG_H);
+       DUMPREG(HDMI_TG_VACT_ST2_L);
+       DUMPREG(HDMI_TG_VACT_ST2_H);
+       DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
+       DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
+       DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
+       DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
+       DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
+       DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
+       DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
+       DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
+#undef DUMPREG
+}
+
+static const struct hdmi_preset_conf hdmi_conf_480p = {
+       .core = {
+               .h_blank = {0x8a, 0x00},
+               .v_blank = {0x0d, 0x6a, 0x01},
+               .h_v_line = {0x0d, 0xa2, 0x35},
+               .vsync_pol = {0x01},
+               .int_pro_mode = {0x00},
+               .v_blank_f = {0x00, 0x00, 0x00},
+               .h_sync_gen = {0x0e, 0x30, 0x11},
+               .v_sync_gen1 = {0x0f, 0x90, 0x00},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x5a, 0x03, /* h_fsz */
+               0x8a, 0x00, 0xd0, 0x02, /* hact */
+               0x0d, 0x02, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x2d, 0x00, 0xe0, 0x01, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x49, 0x02, /* vact_st2 */
+               0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+       },
+       .mbus_fmt = {
+               .width = 720,
+               .height = 480,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_720p60 = {
+       .core = {
+               .h_blank = {0x72, 0x01},
+               .v_blank = {0xee, 0xf2, 0x00},
+               .h_v_line = {0xee, 0x22, 0x67},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
+               .h_sync_gen = {0x6c, 0x50, 0x02},
+               .v_sync_gen1 = {0x0a, 0x50, 0x00},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x72, 0x06, /* h_fsz */
+               0x72, 0x01, 0x00, 0x05, /* hact */
+               0xee, 0x02, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x1e, 0x00, 0xd0, 0x02, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x49, 0x02, /* vact_st2 */
+               0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+       },
+       .mbus_fmt = {
+               .width = 1280,
+               .height = 720,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p50 = {
+       .core = {
+               .h_blank = {0xd0, 0x02},
+               .v_blank = {0x65, 0x6c, 0x01},
+               .h_v_line = {0x65, 0x04, 0xa5},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
+               .h_sync_gen = {0x0e, 0xea, 0x08},
+               .v_sync_gen1 = {0x09, 0x40, 0x00},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x98, 0x08, /* h_fsz */
+               0x18, 0x01, 0x80, 0x07, /* hact */
+               0x65, 0x04, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x2d, 0x00, 0x38, 0x04, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x49, 0x02, /* vact_st2 */
+               0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p60 = {
+       .core = {
+               .h_blank = {0x18, 0x01},
+               .v_blank = {0x65, 0x6c, 0x01},
+               .h_v_line = {0x65, 0x84, 0x89},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
+               .h_sync_gen = {0x56, 0x08, 0x02},
+               .v_sync_gen1 = {0x09, 0x40, 0x00},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x98, 0x08, /* h_fsz */
+               0x18, 0x01, 0x80, 0x07, /* hact */
+               0x65, 0x04, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x2d, 0x00, 0x38, 0x04, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x48, 0x02, /* vact_st2 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct {
+       u32 preset;
+       const struct hdmi_preset_conf *conf;
+} hdmi_conf[] = {
+       { V4L2_DV_480P59_94, &hdmi_conf_480p },
+       { V4L2_DV_720P59_94, &hdmi_conf_720p60 },
+       { V4L2_DV_1080P50, &hdmi_conf_1080p50 },
+       { V4L2_DV_1080P30, &hdmi_conf_1080p60 },
+       { V4L2_DV_1080P60, &hdmi_conf_1080p60 },
+};
+
+static const struct hdmi_preset_conf *hdmi_preset2conf(u32 preset)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(hdmi_conf); ++i)
+               if (hdmi_conf[i].preset == preset)
+                       return  hdmi_conf[i].conf;
+       return NULL;
+}
+
+static int hdmi_streamon(struct hdmi_device *hdev)
+{
+       struct device *dev = hdev->dev;
+       struct hdmi_resources *res = &hdev->res;
+       int ret, tries;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       ret = v4l2_subdev_call(hdev->phy_sd, video, s_stream, 1);
+       if (ret)
+               return ret;
+
+       /* waiting for HDMIPHY's PLL to get to steady state */
+       for (tries = 100; tries; --tries) {
+               u32 val = hdmi_read(hdev, HDMI_PHY_STATUS);
+               if (val & HDMI_PHY_STATUS_READY)
+                       break;
+               mdelay(1);
+       }
+       /* steady state not achieved */
+       if (tries == 0) {
+               dev_err(dev, "hdmiphy's pll could not reach steady state.\n");
+               v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0);
+               hdmi_dumpregs(hdev, "s_stream");
+               return -EIO;
+       }
+
+       /* hdmiphy clock is used for HDMI in streaming mode */
+       clk_disable(res->sclk_hdmi);
+       clk_set_parent(res->sclk_hdmi, res->sclk_hdmiphy);
+       clk_enable(res->sclk_hdmi);
+
+       /* enable HDMI and timing generator */
+       hdmi_write_mask(hdev, HDMI_CON_0, ~0, HDMI_EN);
+       hdmi_write_mask(hdev, HDMI_TG_CMD, ~0, HDMI_TG_EN);
+       hdmi_dumpregs(hdev, "streamon");
+       return 0;
+}
+
+static int hdmi_streamoff(struct hdmi_device *hdev)
+{
+       struct device *dev = hdev->dev;
+       struct hdmi_resources *res = &hdev->res;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_EN);
+       hdmi_write_mask(hdev, HDMI_TG_CMD, 0, HDMI_TG_EN);
+
+       /* pixel(vpll) clock is used for HDMI in config mode */
+       clk_disable(res->sclk_hdmi);
+       clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
+       clk_enable(res->sclk_hdmi);
+
+       v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0);
+
+       hdmi_dumpregs(hdev, "streamoff");
+       return 0;
+}
+
+static int hdmi_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+       struct device *dev = hdev->dev;
+
+       dev_dbg(dev, "%s(%d)\n", __func__, enable);
+       if (enable)
+               return hdmi_streamon(hdev);
+       return hdmi_streamoff(hdev);
+}
+
+static void hdmi_resource_poweron(struct hdmi_resources *res)
+{
+       /* turn HDMI power on */
+       regulator_bulk_enable(res->regul_count, res->regul_bulk);
+       /* power-on hdmi physical interface */
+       clk_enable(res->hdmiphy);
+       /* use VPP as parent clock; HDMIPHY is not working yet */
+       clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
+       /* turn clocks on */
+       clk_enable(res->sclk_hdmi);
+}
+
+static void hdmi_resource_poweroff(struct hdmi_resources *res)
+{
+       /* turn clocks off */
+       clk_disable(res->sclk_hdmi);
+       /* power-off hdmiphy */
+       clk_disable(res->hdmiphy);
+       /* turn HDMI power off */
+       regulator_bulk_disable(res->regul_count, res->regul_bulk);
+}
+
+static int hdmi_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+       int ret;
+
+       if (on)
+               ret = pm_runtime_get_sync(hdev->dev);
+       else
+               ret = pm_runtime_put_sync(hdev->dev);
+       /* only values < 0 indicate errors */
+       return IS_ERR_VALUE(ret) ? ret : 0;
+}
+
+static int hdmi_s_dv_preset(struct v4l2_subdev *sd,
+       struct v4l2_dv_preset *preset)
+{
+       struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+       struct device *dev = hdev->dev;
+       const struct hdmi_preset_conf *conf;
+
+       conf = hdmi_preset2conf(preset->preset);
+       if (conf == NULL) {
+               dev_err(dev, "preset (%u) not supported\n", preset->preset);
+               return -EINVAL;
+       }
+       hdev->cur_conf = conf;
+       hdev->cur_preset = preset->preset;
+       return 0;
+}
+
+static int hdmi_g_dv_preset(struct v4l2_subdev *sd,
+       struct v4l2_dv_preset *preset)
+{
+       memset(preset, 0, sizeof(*preset));
+       preset->preset = sd_to_hdmi_dev(sd)->cur_preset;
+       return 0;
+}
+
+static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd,
+         struct v4l2_mbus_framefmt *fmt)
+{
+       struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+       struct device *dev = hdev->dev;
+
+       dev_dbg(dev, "%s\n", __func__);
+       if (!hdev->cur_conf)
+               return -EINVAL;
+       *fmt = hdev->cur_conf->mbus_fmt;
+       return 0;
+}
+
+static int hdmi_enum_dv_presets(struct v4l2_subdev *sd,
+       struct v4l2_dv_enum_preset *preset)
+{
+       if (preset->index >= ARRAY_SIZE(hdmi_conf))
+               return -EINVAL;
+       return v4l_fill_dv_preset_info(hdmi_conf[preset->index].preset, preset);
+}
+
+static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = {
+       .s_power = hdmi_s_power,
+};
+
+static const struct v4l2_subdev_video_ops hdmi_sd_video_ops = {
+       .s_dv_preset = hdmi_s_dv_preset,
+       .g_dv_preset = hdmi_g_dv_preset,
+       .enum_dv_presets = hdmi_enum_dv_presets,
+       .g_mbus_fmt = hdmi_g_mbus_fmt,
+       .s_stream = hdmi_s_stream,
+};
+
+static const struct v4l2_subdev_ops hdmi_sd_ops = {
+       .core = &hdmi_sd_core_ops,
+       .video = &hdmi_sd_video_ops,
+};
+
+static int hdmi_runtime_suspend(struct device *dev)
+{
+       struct v4l2_subdev *sd = dev_get_drvdata(dev);
+       struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+
+       dev_dbg(dev, "%s\n", __func__);
+       hdmi_resource_poweroff(&hdev->res);
+       return 0;
+}
+
+static int hdmi_runtime_resume(struct device *dev)
+{
+       struct v4l2_subdev *sd = dev_get_drvdata(dev);
+       struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+       int ret = 0;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       hdmi_resource_poweron(&hdev->res);
+
+       ret = hdmi_conf_apply(hdev);
+       if (ret)
+               goto fail;
+
+       dev_dbg(dev, "poweron succeed\n");
+
+       return 0;
+
+fail:
+       hdmi_resource_poweroff(&hdev->res);
+       dev_err(dev, "poweron failed\n");
+
+       return ret;
+}
+
+static const struct dev_pm_ops hdmi_pm_ops = {
+       .runtime_suspend = hdmi_runtime_suspend,
+       .runtime_resume  = hdmi_runtime_resume,
+};
+
+static void hdmi_resources_cleanup(struct hdmi_device *hdev)
+{
+       struct hdmi_resources *res = &hdev->res;
+
+       dev_dbg(hdev->dev, "HDMI resource cleanup\n");
+       /* put clocks, power */
+       if (res->regul_count)
+               regulator_bulk_free(res->regul_count, res->regul_bulk);
+       /* kfree is NULL-safe */
+       kfree(res->regul_bulk);
+       if (!IS_ERR_OR_NULL(res->hdmiphy))
+               clk_put(res->hdmiphy);
+       if (!IS_ERR_OR_NULL(res->sclk_hdmiphy))
+               clk_put(res->sclk_hdmiphy);
+       if (!IS_ERR_OR_NULL(res->sclk_pixel))
+               clk_put(res->sclk_pixel);
+       if (!IS_ERR_OR_NULL(res->sclk_hdmi))
+               clk_put(res->sclk_hdmi);
+       if (!IS_ERR_OR_NULL(res->hdmi))
+               clk_put(res->hdmi);
+       memset(res, 0, sizeof *res);
+}
+
+static int hdmi_resources_init(struct hdmi_device *hdev)
+{
+       struct device *dev = hdev->dev;
+       struct hdmi_resources *res = &hdev->res;
+       static char *supply[] = {
+               "hdmi-en",
+               "vdd",
+               "vdd_osc",
+               "vdd_pll",
+       };
+       int i, ret;
+
+       dev_dbg(dev, "HDMI resource init\n");
+
+       memset(res, 0, sizeof *res);
+       /* get clocks, power */
+
+       res->hdmi = clk_get(dev, "hdmi");
+       if (IS_ERR_OR_NULL(res->hdmi)) {
+               dev_err(dev, "failed to get clock 'hdmi'\n");
+               goto fail;
+       }
+       res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
+       if (IS_ERR_OR_NULL(res->sclk_hdmi)) {
+               dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
+               goto fail;
+       }
+       res->sclk_pixel = clk_get(dev, "sclk_pixel");
+       if (IS_ERR_OR_NULL(res->sclk_pixel)) {
+               dev_err(dev, "failed to get clock 'sclk_pixel'\n");
+               goto fail;
+       }
+       res->sclk_hdmiphy = clk_get(dev, "sclk_hdmiphy");
+       if (IS_ERR_OR_NULL(res->sclk_hdmiphy)) {
+               dev_err(dev, "failed to get clock 'sclk_hdmiphy'\n");
+               goto fail;
+       }
+       res->hdmiphy = clk_get(dev, "hdmiphy");
+       if (IS_ERR_OR_NULL(res->hdmiphy)) {
+               dev_err(dev, "failed to get clock 'hdmiphy'\n");
+               goto fail;
+       }
+       res->regul_bulk = kzalloc(ARRAY_SIZE(supply) *
+               sizeof res->regul_bulk[0], GFP_KERNEL);
+       if (!res->regul_bulk) {
+               dev_err(dev, "failed to get memory for regulators\n");
+               goto fail;
+       }
+       for (i = 0; i < ARRAY_SIZE(supply); ++i) {
+               res->regul_bulk[i].supply = supply[i];
+               res->regul_bulk[i].consumer = NULL;
+       }
+
+       ret = regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
+       if (ret) {
+               dev_err(dev, "failed to get regulators\n");
+               goto fail;
+       }
+       res->regul_count = ARRAY_SIZE(supply);
+
+       return 0;
+fail:
+       dev_err(dev, "HDMI resource init - failed\n");
+       hdmi_resources_cleanup(hdev);
+       return -ENODEV;
+}
+
+static int __devinit hdmi_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+       struct i2c_adapter *phy_adapter;
+       struct v4l2_subdev *sd;
+       struct hdmi_device *hdmi_dev = NULL;
+       struct hdmi_driver_data *drv_data;
+       int ret;
+
+       dev_dbg(dev, "probe start\n");
+
+       hdmi_dev = kzalloc(sizeof(*hdmi_dev), GFP_KERNEL);
+       if (!hdmi_dev) {
+               dev_err(dev, "out of memory\n");
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       hdmi_dev->dev = dev;
+
+       ret = hdmi_resources_init(hdmi_dev);
+       if (ret)
+               goto fail_hdev;
+
+       /* mapping HDMI registers */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(dev, "get memory resource failed.\n");
+               ret = -ENXIO;
+               goto fail_init;
+       }
+
+       hdmi_dev->regs = ioremap(res->start, resource_size(res));
+       if (hdmi_dev->regs == NULL) {
+               dev_err(dev, "register mapping failed.\n");
+               ret = -ENXIO;
+               goto fail_hdev;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (res == NULL) {
+               dev_err(dev, "get interrupt resource failed.\n");
+               ret = -ENXIO;
+               goto fail_regs;
+       }
+
+       ret = request_irq(res->start, hdmi_irq_handler, 0, "hdmi", hdmi_dev);
+       if (ret) {
+               dev_err(dev, "request interrupt failed.\n");
+               goto fail_regs;
+       }
+       hdmi_dev->irq = res->start;
+
+       /* setting v4l2 name to prevent WARN_ON in v4l2_device_register */
+       strlcpy(hdmi_dev->v4l2_dev.name, dev_name(dev),
+               sizeof(hdmi_dev->v4l2_dev.name));
+       /* passing NULL owner prevents driver from erasing drvdata */
+       ret = v4l2_device_register(NULL, &hdmi_dev->v4l2_dev);
+       if (ret) {
+               dev_err(dev, "could not register v4l2 device.\n");
+               goto fail_irq;
+       }
+
+       drv_data = (struct hdmi_driver_data *)
+               platform_get_device_id(pdev)->driver_data;
+       phy_adapter = i2c_get_adapter(drv_data->hdmiphy_bus);
+       if (phy_adapter == NULL) {
+               dev_err(dev, "adapter request failed\n");
+               ret = -ENXIO;
+               goto fail_vdev;
+       }
+
+       hdmi_dev->phy_sd = v4l2_i2c_new_subdev_board(&hdmi_dev->v4l2_dev,
+               phy_adapter, &hdmiphy_info, NULL);
+       /* on failure or not adapter is no longer useful */
+       i2c_put_adapter(phy_adapter);
+       if (hdmi_dev->phy_sd == NULL) {
+               dev_err(dev, "missing subdev for hdmiphy\n");
+               ret = -ENODEV;
+               goto fail_vdev;
+       }
+
+       clk_enable(hdmi_dev->res.hdmi);
+
+       pm_runtime_enable(dev);
+
+       sd = &hdmi_dev->sd;
+       v4l2_subdev_init(sd, &hdmi_sd_ops);
+       sd->owner = THIS_MODULE;
+
+       strlcpy(sd->name, "s5p-hdmi", sizeof sd->name);
+       hdmi_dev->cur_preset = HDMI_DEFAULT_PRESET;
+       /* FIXME: missing fail preset is not supported */
+       hdmi_dev->cur_conf = hdmi_preset2conf(hdmi_dev->cur_preset);
+
+       /* storing subdev for call that have only access to struct device */
+       dev_set_drvdata(dev, sd);
+
+       dev_info(dev, "probe sucessful\n");
+
+       return 0;
+
+fail_vdev:
+       v4l2_device_unregister(&hdmi_dev->v4l2_dev);
+
+fail_irq:
+       free_irq(hdmi_dev->irq, hdmi_dev);
+
+fail_regs:
+       iounmap(hdmi_dev->regs);
+
+fail_init:
+       hdmi_resources_cleanup(hdmi_dev);
+
+fail_hdev:
+       kfree(hdmi_dev);
+
+fail:
+       dev_err(dev, "probe failed\n");
+       return ret;
+}
+
+static int __devexit hdmi_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct v4l2_subdev *sd = dev_get_drvdata(dev);
+       struct hdmi_device *hdmi_dev = sd_to_hdmi_dev(sd);
+
+       pm_runtime_disable(dev);
+       clk_disable(hdmi_dev->res.hdmi);
+       v4l2_device_unregister(&hdmi_dev->v4l2_dev);
+       disable_irq(hdmi_dev->irq);
+       free_irq(hdmi_dev->irq, hdmi_dev);
+       iounmap(hdmi_dev->regs);
+       hdmi_resources_cleanup(hdmi_dev);
+       kfree(hdmi_dev);
+       dev_info(dev, "remove sucessful\n");
+
+       return 0;
+}
+
+static struct platform_driver hdmi_driver __refdata = {
+       .probe = hdmi_probe,
+       .remove = __devexit_p(hdmi_remove),
+       .id_table = hdmi_driver_types,
+       .driver = {
+               .name = "s5p-hdmi",
+               .owner = THIS_MODULE,
+               .pm = &hdmi_pm_ops,
+       }
+};
+
+/* D R I V E R   I N I T I A L I Z A T I O N */
+
+static int __init hdmi_init(void)
+{
+       int ret;
+       static const char banner[] __initdata = KERN_INFO \
+               "Samsung HDMI output driver, "
+               "(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
+       printk(banner);
+
+       ret = platform_driver_register(&hdmi_driver);
+       if (ret)
+               printk(KERN_ERR "HDMI platform driver register failed\n");
+
+       return ret;
+}
+module_init(hdmi_init);
+
+static void __exit hdmi_exit(void)
+{
+       platform_driver_unregister(&hdmi_driver);
+}
+module_exit(hdmi_exit);
+
+
diff --git a/drivers/media/video/s5p-tv/hdmiphy_drv.c b/drivers/media/video/s5p-tv/hdmiphy_drv.c
new file mode 100644 (file)
index 0000000..6693f4a
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Samsung HDMI Physical interface driver
+ *
+ * Copyright (C) 2010-2011 Samsung Electronics Co.Ltd
+ * Author: Tomasz Stanislawski <t.stanislaws@samsung.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+
+#include <media/v4l2-subdev.h>
+
+MODULE_AUTHOR("Tomasz Stanislawski <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung HDMI Physical interface driver");
+MODULE_LICENSE("GPL");
+
+struct hdmiphy_conf {
+       u32 preset;
+       const u8 *data;
+};
+
+static const u8 hdmiphy_conf27[32] = {
+       0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
+       0x6B, 0x10, 0x02, 0x51, 0xDf, 0xF2, 0x54, 0x87,
+       0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+       0x22, 0x40, 0xe3, 0x26, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const u8 hdmiphy_conf74_175[32] = {
+       0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
+       0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
+       0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+       0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
+};
+
+static const u8 hdmiphy_conf74_25[32] = {
+       0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
+       0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
+       0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xe0,
+       0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
+};
+
+static const u8 hdmiphy_conf148_5[32] = {
+       0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
+       0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
+       0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
+       0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
+};
+
+static const struct hdmiphy_conf hdmiphy_conf[] = {
+       { V4L2_DV_480P59_94, hdmiphy_conf27 },
+       { V4L2_DV_1080P30, hdmiphy_conf74_175 },
+       { V4L2_DV_720P59_94, hdmiphy_conf74_175 },
+       { V4L2_DV_720P60, hdmiphy_conf74_25 },
+       { V4L2_DV_1080P50, hdmiphy_conf148_5 },
+       { V4L2_DV_1080P60, hdmiphy_conf148_5 },
+};
+
+const u8 *hdmiphy_preset2conf(u32 preset)
+{
+       int i;
+       for (i = 0; i < ARRAY_SIZE(hdmiphy_conf); ++i)
+               if (hdmiphy_conf[i].preset == preset)
+                       return hdmiphy_conf[i].data;
+       return NULL;
+}
+
+static int hdmiphy_s_power(struct v4l2_subdev *sd, int on)
+{
+       /* to be implemented */
+       return 0;
+}
+
+static int hdmiphy_s_dv_preset(struct v4l2_subdev *sd,
+       struct v4l2_dv_preset *preset)
+{
+       const u8 *data;
+       u8 buffer[32];
+       int ret;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct device *dev = &client->dev;
+
+       dev_info(dev, "s_dv_preset(preset = %d)\n", preset->preset);
+       data = hdmiphy_preset2conf(preset->preset);
+       if (!data) {
+               dev_err(dev, "format not supported\n");
+               return -EINVAL;
+       }
+
+       /* storing configuration to the device */
+       memcpy(buffer, data, 32);
+       ret = i2c_master_send(client, buffer, 32);
+       if (ret != 32) {
+               dev_err(dev, "failed to configure HDMIPHY via I2C\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int hdmiphy_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct device *dev = &client->dev;
+       u8 buffer[2];
+       int ret;
+
+       dev_info(dev, "s_stream(%d)\n", enable);
+       /* going to/from configuration from/to operation mode */
+       buffer[0] = 0x1f;
+       buffer[1] = enable ? 0x80 : 0x00;
+
+       ret = i2c_master_send(client, buffer, 2);
+       if (ret != 2) {
+               dev_err(dev, "stream (%d) failed\n", enable);
+               return -EIO;
+       }
+       return 0;
+}
+
+static const struct v4l2_subdev_core_ops hdmiphy_core_ops = {
+       .s_power =  hdmiphy_s_power,
+};
+
+static const struct v4l2_subdev_video_ops hdmiphy_video_ops = {
+       .s_dv_preset = hdmiphy_s_dv_preset,
+       .s_stream =  hdmiphy_s_stream,
+};
+
+static const struct v4l2_subdev_ops hdmiphy_ops = {
+       .core = &hdmiphy_core_ops,
+       .video = &hdmiphy_video_ops,
+};
+
+static int __devinit hdmiphy_probe(struct i2c_client *client,
+       const struct i2c_device_id *id)
+{
+       static struct v4l2_subdev sd;
+
+       v4l2_i2c_subdev_init(&sd, client, &hdmiphy_ops);
+       dev_info(&client->dev, "probe successful\n");
+       return 0;
+}
+
+static int __devexit hdmiphy_remove(struct i2c_client *client)
+{
+       dev_info(&client->dev, "remove successful\n");
+       return 0;
+}
+
+static const struct i2c_device_id hdmiphy_id[] = {
+       { "hdmiphy", 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, hdmiphy_id);
+
+static struct i2c_driver hdmiphy_driver = {
+       .driver = {
+               .name   = "s5p-hdmiphy",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = hdmiphy_probe,
+       .remove         = __devexit_p(hdmiphy_remove),
+       .id_table = hdmiphy_id,
+};
+
+static int __init hdmiphy_init(void)
+{
+       return i2c_add_driver(&hdmiphy_driver);
+}
+module_init(hdmiphy_init);
+
+static void __exit hdmiphy_exit(void)
+{
+       i2c_del_driver(&hdmiphy_driver);
+}
+module_exit(hdmiphy_exit);
diff --git a/drivers/media/video/s5p-tv/mixer.h b/drivers/media/video/s5p-tv/mixer.h
new file mode 100644 (file)
index 0000000..e224224
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#ifndef SAMSUNG_MIXER_H
+#define SAMSUNG_MIXER_H
+
+#ifdef CONFIG_VIDEO_SAMSUNG_S5P_MIXER_DEBUG
+       #define DEBUG
+#endif
+
+#include <linux/fb.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf2-core.h>
+
+#include "regs-mixer.h"
+
+/** maximum number of output interfaces */
+#define MXR_MAX_OUTPUTS 2
+/** maximum number of input interfaces (layers) */
+#define MXR_MAX_LAYERS 3
+#define MXR_DRIVER_NAME "s5p-mixer"
+/** maximal number of planes for every layer */
+#define MXR_MAX_PLANES 2
+
+#define MXR_ENABLE 1
+#define MXR_DISABLE 0
+
+/** description of a macroblock for packed formats */
+struct mxr_block {
+       /** vertical number of pixels in macroblock */
+       unsigned int width;
+       /** horizontal number of pixels in macroblock */
+       unsigned int height;
+       /** size of block in bytes */
+       unsigned int size;
+};
+
+/** description of supported format */
+struct mxr_format {
+       /** format name/mnemonic */
+       const char *name;
+       /** fourcc identifier */
+       u32 fourcc;
+       /** colorspace identifier */
+       enum v4l2_colorspace colorspace;
+       /** number of planes in image data */
+       int num_planes;
+       /** description of block for each plane */
+       struct mxr_block plane[MXR_MAX_PLANES];
+       /** number of subframes in image data */
+       int num_subframes;
+       /** specifies to which subframe belong given plane */
+       int plane2subframe[MXR_MAX_PLANES];
+       /** internal code, driver dependant */
+       unsigned long cookie;
+};
+
+/** description of crop configuration for image */
+struct mxr_crop {
+       /** width of layer in pixels */
+       unsigned int full_width;
+       /** height of layer in pixels */
+       unsigned int full_height;
+       /** horizontal offset of first pixel to be displayed */
+       unsigned int x_offset;
+       /** vertical offset of first pixel to be displayed */
+       unsigned int y_offset;
+       /** width of displayed data in pixels */
+       unsigned int width;
+       /** height of displayed data in pixels */
+       unsigned int height;
+       /** indicate which fields are present in buffer */
+       unsigned int field;
+};
+
+/** description of transformation from source to destination image */
+struct mxr_geometry {
+       /** cropping for source image */
+       struct mxr_crop src;
+       /** cropping for destination image */
+       struct mxr_crop dst;
+       /** layer-dependant description of horizontal scaling */
+       unsigned int x_ratio;
+       /** layer-dependant description of vertical scaling */
+       unsigned int y_ratio;
+};
+
+/** instance of a buffer */
+struct mxr_buffer {
+       /** common v4l buffer stuff -- must be first */
+       struct vb2_buffer       vb;
+       /** node for layer's lists */
+       struct list_head        list;
+};
+
+
+/** internal states of layer */
+enum mxr_layer_state {
+       /** layers is not shown */
+       MXR_LAYER_IDLE = 0,
+       /** state between STREAMON and hardware start */
+       MXR_LAYER_STREAMING_START,
+       /** layer is shown */
+       MXR_LAYER_STREAMING,
+       /** state before STREAMOFF is finished */
+       MXR_LAYER_STREAMING_FINISH,
+};
+
+/** forward declarations */
+struct mxr_device;
+struct mxr_layer;
+
+/** callback for layers operation */
+struct mxr_layer_ops {
+       /* TODO: try to port it to subdev API */
+       /** handler for resource release function */
+       void (*release)(struct mxr_layer *);
+       /** setting buffer to HW */
+       void (*buffer_set)(struct mxr_layer *, struct mxr_buffer *);
+       /** setting format and geometry in HW */
+       void (*format_set)(struct mxr_layer *);
+       /** streaming stop/start */
+       void (*stream_set)(struct mxr_layer *, int);
+       /** adjusting geometry */
+       void (*fix_geometry)(struct mxr_layer *);
+};
+
+/** layer instance, a single window and content displayed on output */
+struct mxr_layer {
+       /** parent mixer device */
+       struct mxr_device *mdev;
+       /** layer index (unique identifier) */
+       int idx;
+       /** callbacks for layer methods */
+       struct mxr_layer_ops ops;
+       /** format array */
+       const struct mxr_format **fmt_array;
+       /** size of format array */
+       unsigned long fmt_array_size;
+
+       /** lock for protection of list and state fields */
+       spinlock_t enq_slock;
+       /** list for enqueued buffers */
+       struct list_head enq_list;
+       /** buffer currently owned by hardware in temporary registers */
+       struct mxr_buffer *update_buf;
+       /** buffer currently owned by hardware in shadow registers */
+       struct mxr_buffer *shadow_buf;
+       /** state of layer IDLE/STREAMING */
+       enum mxr_layer_state state;
+
+       /** mutex for protection of fields below */
+       struct mutex mutex;
+       /** handler for video node */
+       struct video_device vfd;
+       /** queue for output buffers */
+       struct vb2_queue vb_queue;
+       /** current image format */
+       const struct mxr_format *fmt;
+       /** current geometry of image */
+       struct mxr_geometry geo;
+};
+
+/** description of mixers output interface */
+struct mxr_output {
+       /** name of output */
+       char name[32];
+       /** output subdev */
+       struct v4l2_subdev *sd;
+       /** cookie used for configuration of registers */
+       int cookie;
+};
+
+/** specify source of output subdevs */
+struct mxr_output_conf {
+       /** name of output (connector) */
+       char *output_name;
+       /** name of module that generates output subdev */
+       char *module_name;
+       /** cookie need for mixer HW */
+       int cookie;
+};
+
+struct clk;
+struct regulator;
+
+/** auxiliary resources used my mixer */
+struct mxr_resources {
+       /** interrupt index */
+       int irq;
+       /** pointer to Mixer registers */
+       void __iomem *mxr_regs;
+       /** pointer to Video Processor registers */
+       void __iomem *vp_regs;
+       /** other resources, should used under mxr_device.mutex */
+       struct clk *mixer;
+       struct clk *vp;
+       struct clk *sclk_mixer;
+       struct clk *sclk_hdmi;
+       struct clk *sclk_dac;
+};
+
+/* event flags used  */
+enum mxr_devide_flags {
+       MXR_EVENT_VSYNC = 0,
+};
+
+/** drivers instance */
+struct mxr_device {
+       /** master device */
+       struct device *dev;
+       /** state of each layer */
+       struct mxr_layer *layer[MXR_MAX_LAYERS];
+       /** state of each output */
+       struct mxr_output *output[MXR_MAX_OUTPUTS];
+       /** number of registered outputs */
+       int output_cnt;
+
+       /* video resources */
+
+       /** V4L2 device */
+       struct v4l2_device v4l2_dev;
+       /** context of allocator */
+       void *alloc_ctx;
+       /** event wait queue */
+       wait_queue_head_t event_queue;
+       /** state flags */
+       unsigned long event_flags;
+
+       /** spinlock for protection of registers */
+       spinlock_t reg_slock;
+
+       /** mutex for protection of fields below */
+       struct mutex mutex;
+       /** number of entities depndant on output configuration */
+       int n_output;
+       /** number of users that do streaming */
+       int n_streamer;
+       /** index of current output */
+       int current_output;
+       /** auxiliary resources used my mixer */
+       struct mxr_resources res;
+};
+
+/** transform device structure into mixer device */
+static inline struct mxr_device *to_mdev(struct device *dev)
+{
+       struct v4l2_device *vdev = dev_get_drvdata(dev);
+       return container_of(vdev, struct mxr_device, v4l2_dev);
+}
+
+/** get current output data, should be called under mdev's mutex */
+static inline struct mxr_output *to_output(struct mxr_device *mdev)
+{
+       return mdev->output[mdev->current_output];
+}
+
+/** get current output subdev, should be called under mdev's mutex */
+static inline struct v4l2_subdev *to_outsd(struct mxr_device *mdev)
+{
+       struct mxr_output *out = to_output(mdev);
+       return out ? out->sd : NULL;
+}
+
+/** forward declaration for mixer platform data */
+struct mxr_platform_data;
+
+/** acquiring common video resources */
+int __devinit mxr_acquire_video(struct mxr_device *mdev,
+       struct mxr_output_conf *output_cont, int output_count);
+
+/** releasing common video resources */
+void __devexit mxr_release_video(struct mxr_device *mdev);
+
+struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx);
+struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx);
+struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
+       int idx, char *name, struct mxr_layer_ops *ops);
+
+void mxr_base_layer_release(struct mxr_layer *layer);
+void mxr_layer_release(struct mxr_layer *layer);
+
+int mxr_base_layer_register(struct mxr_layer *layer);
+void mxr_base_layer_unregister(struct mxr_layer *layer);
+
+unsigned long mxr_get_plane_size(const struct mxr_block *blk,
+       unsigned int width, unsigned int height);
+
+/** adds new consumer for mixer's power */
+int __must_check mxr_power_get(struct mxr_device *mdev);
+/** removes consumer for mixer's power */
+void mxr_power_put(struct mxr_device *mdev);
+/** add new client for output configuration */
+void mxr_output_get(struct mxr_device *mdev);
+/** removes new client for output configuration */
+void mxr_output_put(struct mxr_device *mdev);
+/** add new client for streaming */
+void mxr_streamer_get(struct mxr_device *mdev);
+/** removes new client for streaming */
+void mxr_streamer_put(struct mxr_device *mdev);
+/** returns format of data delivared to current output */
+void mxr_get_mbus_fmt(struct mxr_device *mdev,
+       struct v4l2_mbus_framefmt *mbus_fmt);
+
+/* Debug */
+
+#define mxr_err(mdev, fmt, ...)  dev_err(mdev->dev, fmt, ##__VA_ARGS__)
+#define mxr_warn(mdev, fmt, ...) dev_warn(mdev->dev, fmt, ##__VA_ARGS__)
+#define mxr_info(mdev, fmt, ...) dev_info(mdev->dev, fmt, ##__VA_ARGS__)
+
+#ifdef CONFIG_VIDEO_SAMSUNG_S5P_MIXER_DEBUG
+       #define mxr_dbg(mdev, fmt, ...)  dev_dbg(mdev->dev, fmt, ##__VA_ARGS__)
+#else
+       #define mxr_dbg(mdev, fmt, ...)  do { (void) mdev; } while (0)
+#endif
+
+/* accessing Mixer's and Video Processor's registers */
+
+void mxr_vsync_set_update(struct mxr_device *mdev, int en);
+void mxr_reg_reset(struct mxr_device *mdev);
+irqreturn_t mxr_irq_handler(int irq, void *dev_data);
+void mxr_reg_s_output(struct mxr_device *mdev, int cookie);
+void mxr_reg_streamon(struct mxr_device *mdev);
+void mxr_reg_streamoff(struct mxr_device *mdev);
+int mxr_reg_wait4vsync(struct mxr_device *mdev);
+void mxr_reg_set_mbus_fmt(struct mxr_device *mdev,
+       struct v4l2_mbus_framefmt *fmt);
+void mxr_reg_graph_layer_stream(struct mxr_device *mdev, int idx, int en);
+void mxr_reg_graph_buffer(struct mxr_device *mdev, int idx, dma_addr_t addr);
+void mxr_reg_graph_format(struct mxr_device *mdev, int idx,
+       const struct mxr_format *fmt, const struct mxr_geometry *geo);
+
+void mxr_reg_vp_layer_stream(struct mxr_device *mdev, int en);
+void mxr_reg_vp_buffer(struct mxr_device *mdev,
+       dma_addr_t luma_addr[2], dma_addr_t chroma_addr[2]);
+void mxr_reg_vp_format(struct mxr_device *mdev,
+       const struct mxr_format *fmt, const struct mxr_geometry *geo);
+void mxr_reg_dump(struct mxr_device *mdev);
+
+#endif /* SAMSUNG_MIXER_H */
+
diff --git a/drivers/media/video/s5p-tv/mixer_drv.c b/drivers/media/video/s5p-tv/mixer_drv.c
new file mode 100644 (file)
index 0000000..0064309
--- /dev/null
@@ -0,0 +1,487 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "mixer.h"
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+
+MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung MIXER");
+MODULE_LICENSE("GPL");
+
+/* --------- DRIVER PARAMETERS ---------- */
+
+static struct mxr_output_conf mxr_output_conf[] = {
+       {
+               .output_name = "S5P HDMI connector",
+               .module_name = "s5p-hdmi",
+               .cookie = 1,
+       },
+       {
+               .output_name = "S5P SDO connector",
+               .module_name = "s5p-sdo",
+               .cookie = 0,
+       },
+};
+
+void mxr_get_mbus_fmt(struct mxr_device *mdev,
+       struct v4l2_mbus_framefmt *mbus_fmt)
+{
+       struct v4l2_subdev *sd;
+       int ret;
+
+       mutex_lock(&mdev->mutex);
+       sd = to_outsd(mdev);
+       ret = v4l2_subdev_call(sd, video, g_mbus_fmt, mbus_fmt);
+       WARN(ret, "failed to get mbus_fmt for output %s\n", sd->name);
+       mutex_unlock(&mdev->mutex);
+}
+
+void mxr_streamer_get(struct mxr_device *mdev)
+{
+       mutex_lock(&mdev->mutex);
+       ++mdev->n_streamer;
+       mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer);
+       if (mdev->n_streamer == 1) {
+               struct v4l2_subdev *sd = to_outsd(mdev);
+               struct v4l2_mbus_framefmt mbus_fmt;
+               struct mxr_resources *res = &mdev->res;
+               int ret;
+
+               if (to_output(mdev)->cookie == 0)
+                       clk_set_parent(res->sclk_mixer, res->sclk_dac);
+               else
+                       clk_set_parent(res->sclk_mixer, res->sclk_hdmi);
+               mxr_reg_s_output(mdev, to_output(mdev)->cookie);
+
+               ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mbus_fmt);
+               WARN(ret, "failed to get mbus_fmt for output %s\n", sd->name);
+               ret = v4l2_subdev_call(sd, video, s_stream, 1);
+               WARN(ret, "starting stream failed for output %s\n", sd->name);
+
+               mxr_reg_set_mbus_fmt(mdev, &mbus_fmt);
+               mxr_reg_streamon(mdev);
+               ret = mxr_reg_wait4vsync(mdev);
+               WARN(ret, "failed to get vsync (%d) from output\n", ret);
+       }
+       mutex_unlock(&mdev->mutex);
+       mxr_reg_dump(mdev);
+       /* FIXME: what to do when streaming fails? */
+}
+
+void mxr_streamer_put(struct mxr_device *mdev)
+{
+       mutex_lock(&mdev->mutex);
+       --mdev->n_streamer;
+       mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer);
+       if (mdev->n_streamer == 0) {
+               int ret;
+               struct v4l2_subdev *sd = to_outsd(mdev);
+
+               mxr_reg_streamoff(mdev);
+               /* vsync applies Mixer setup */
+               ret = mxr_reg_wait4vsync(mdev);
+               WARN(ret, "failed to get vsync (%d) from output\n", ret);
+               ret = v4l2_subdev_call(sd, video, s_stream, 0);
+               WARN(ret, "stopping stream failed for output %s\n", sd->name);
+       }
+       WARN(mdev->n_streamer < 0, "negative number of streamers (%d)\n",
+               mdev->n_streamer);
+       mutex_unlock(&mdev->mutex);
+       mxr_reg_dump(mdev);
+}
+
+void mxr_output_get(struct mxr_device *mdev)
+{
+       mutex_lock(&mdev->mutex);
+       ++mdev->n_output;
+       mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_output);
+       /* turn on auxiliary driver */
+       if (mdev->n_output == 1)
+               v4l2_subdev_call(to_outsd(mdev), core, s_power, 1);
+       mutex_unlock(&mdev->mutex);
+}
+
+void mxr_output_put(struct mxr_device *mdev)
+{
+       mutex_lock(&mdev->mutex);
+       --mdev->n_output;
+       mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_output);
+       /* turn on auxiliary driver */
+       if (mdev->n_output == 0)
+               v4l2_subdev_call(to_outsd(mdev), core, s_power, 0);
+       WARN(mdev->n_output < 0, "negative number of output users (%d)\n",
+               mdev->n_output);
+       mutex_unlock(&mdev->mutex);
+}
+
+int mxr_power_get(struct mxr_device *mdev)
+{
+       int ret = pm_runtime_get_sync(mdev->dev);
+
+       /* returning 1 means that power is already enabled,
+        * so zero success be returned */
+       if (IS_ERR_VALUE(ret))
+               return ret;
+       return 0;
+}
+
+void mxr_power_put(struct mxr_device *mdev)
+{
+       pm_runtime_put_sync(mdev->dev);
+}
+
+/* --------- RESOURCE MANAGEMENT -------------*/
+
+static int __devinit mxr_acquire_plat_resources(struct mxr_device *mdev,
+       struct platform_device *pdev)
+{
+       struct resource *res;
+       int ret;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mxr");
+       if (res == NULL) {
+               mxr_err(mdev, "get memory resource failed.\n");
+               ret = -ENXIO;
+               goto fail;
+       }
+
+       mdev->res.mxr_regs = ioremap(res->start, resource_size(res));
+       if (mdev->res.mxr_regs == NULL) {
+               mxr_err(mdev, "register mapping failed.\n");
+               ret = -ENXIO;
+               goto fail;
+       }
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp");
+       if (res == NULL) {
+               mxr_err(mdev, "get memory resource failed.\n");
+               ret = -ENXIO;
+               goto fail_mxr_regs;
+       }
+
+       mdev->res.vp_regs = ioremap(res->start, resource_size(res));
+       if (mdev->res.vp_regs == NULL) {
+               mxr_err(mdev, "register mapping failed.\n");
+               ret = -ENXIO;
+               goto fail_mxr_regs;
+       }
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq");
+       if (res == NULL) {
+               mxr_err(mdev, "get interrupt resource failed.\n");
+               ret = -ENXIO;
+               goto fail_vp_regs;
+       }
+
+       ret = request_irq(res->start, mxr_irq_handler, 0, "s5p-mixer", mdev);
+       if (ret) {
+               mxr_err(mdev, "request interrupt failed.\n");
+               goto fail_vp_regs;
+       }
+       mdev->res.irq = res->start;
+
+       return 0;
+
+fail_vp_regs:
+       iounmap(mdev->res.vp_regs);
+
+fail_mxr_regs:
+       iounmap(mdev->res.mxr_regs);
+
+fail:
+       return ret;
+}
+
+static void mxr_release_plat_resources(struct mxr_device *mdev)
+{
+       free_irq(mdev->res.irq, mdev);
+       iounmap(mdev->res.vp_regs);
+       iounmap(mdev->res.mxr_regs);
+}
+
+static void mxr_release_clocks(struct mxr_device *mdev)
+{
+       struct mxr_resources *res = &mdev->res;
+
+       if (!IS_ERR_OR_NULL(res->sclk_dac))
+               clk_put(res->sclk_dac);
+       if (!IS_ERR_OR_NULL(res->sclk_hdmi))
+               clk_put(res->sclk_hdmi);
+       if (!IS_ERR_OR_NULL(res->sclk_mixer))
+               clk_put(res->sclk_mixer);
+       if (!IS_ERR_OR_NULL(res->vp))
+               clk_put(res->vp);
+       if (!IS_ERR_OR_NULL(res->mixer))
+               clk_put(res->mixer);
+}
+
+static int mxr_acquire_clocks(struct mxr_device *mdev)
+{
+       struct mxr_resources *res = &mdev->res;
+       struct device *dev = mdev->dev;
+
+       res->mixer = clk_get(dev, "mixer");
+       if (IS_ERR_OR_NULL(res->mixer)) {
+               mxr_err(mdev, "failed to get clock 'mixer'\n");
+               goto fail;
+       }
+       res->vp = clk_get(dev, "vp");
+       if (IS_ERR_OR_NULL(res->vp)) {
+               mxr_err(mdev, "failed to get clock 'vp'\n");
+               goto fail;
+       }
+       res->sclk_mixer = clk_get(dev, "sclk_mixer");
+       if (IS_ERR_OR_NULL(res->sclk_mixer)) {
+               mxr_err(mdev, "failed to get clock 'sclk_mixer'\n");
+               goto fail;
+       }
+       res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
+       if (IS_ERR_OR_NULL(res->sclk_hdmi)) {
+               mxr_err(mdev, "failed to get clock 'sclk_hdmi'\n");
+               goto fail;
+       }
+       res->sclk_dac = clk_get(dev, "sclk_dac");
+       if (IS_ERR_OR_NULL(res->sclk_dac)) {
+               mxr_err(mdev, "failed to get clock 'sclk_dac'\n");
+               goto fail;
+       }
+
+       return 0;
+fail:
+       mxr_release_clocks(mdev);
+       return -ENODEV;
+}
+
+static int __devinit mxr_acquire_resources(struct mxr_device *mdev,
+       struct platform_device *pdev)
+{
+       int ret;
+       ret = mxr_acquire_plat_resources(mdev, pdev);
+
+       if (ret)
+               goto fail;
+
+       ret = mxr_acquire_clocks(mdev);
+       if (ret)
+               goto fail_plat;
+
+       mxr_info(mdev, "resources acquired\n");
+       return 0;
+
+fail_plat:
+       mxr_release_plat_resources(mdev);
+fail:
+       mxr_err(mdev, "resources acquire failed\n");
+       return ret;
+}
+
+static void mxr_release_resources(struct mxr_device *mdev)
+{
+       mxr_release_clocks(mdev);
+       mxr_release_plat_resources(mdev);
+       memset(&mdev->res, 0, sizeof mdev->res);
+}
+
+static void mxr_release_layers(struct mxr_device *mdev)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(mdev->layer); ++i)
+               if (mdev->layer[i])
+                       mxr_layer_release(mdev->layer[i]);
+}
+
+static int __devinit mxr_acquire_layers(struct mxr_device *mdev,
+       struct mxr_platform_data *pdata)
+{
+       mdev->layer[0] = mxr_graph_layer_create(mdev, 0);
+       mdev->layer[1] = mxr_graph_layer_create(mdev, 1);
+       mdev->layer[2] = mxr_vp_layer_create(mdev, 0);
+
+       if (!mdev->layer[0] || !mdev->layer[1] || !mdev->layer[2]) {
+               mxr_err(mdev, "failed to acquire layers\n");
+               goto fail;
+       }
+
+       return 0;
+
+fail:
+       mxr_release_layers(mdev);
+       return -ENODEV;
+}
+
+/* ---------- POWER MANAGEMENT ----------- */
+
+static int mxr_runtime_resume(struct device *dev)
+{
+       struct mxr_device *mdev = to_mdev(dev);
+       struct mxr_resources *res = &mdev->res;
+
+       mxr_dbg(mdev, "resume - start\n");
+       mutex_lock(&mdev->mutex);
+       /* turn clocks on */
+       clk_enable(res->mixer);
+       clk_enable(res->vp);
+       clk_enable(res->sclk_mixer);
+       /* apply default configuration */
+       mxr_reg_reset(mdev);
+       mxr_dbg(mdev, "resume - finished\n");
+
+       mutex_unlock(&mdev->mutex);
+       return 0;
+}
+
+static int mxr_runtime_suspend(struct device *dev)
+{
+       struct mxr_device *mdev = to_mdev(dev);
+       struct mxr_resources *res = &mdev->res;
+       mxr_dbg(mdev, "suspend - start\n");
+       mutex_lock(&mdev->mutex);
+       /* turn clocks off */
+       clk_disable(res->sclk_mixer);
+       clk_disable(res->vp);
+       clk_disable(res->mixer);
+       mutex_unlock(&mdev->mutex);
+       mxr_dbg(mdev, "suspend - finished\n");
+       return 0;
+}
+
+static const struct dev_pm_ops mxr_pm_ops = {
+       .runtime_suspend = mxr_runtime_suspend,
+       .runtime_resume  = mxr_runtime_resume,
+};
+
+/* --------- DRIVER INITIALIZATION ---------- */
+
+static int __devinit mxr_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct mxr_platform_data *pdata = dev->platform_data;
+       struct mxr_device *mdev;
+       int ret;
+
+       /* mdev does not exist yet so no mxr_dbg is used */
+       dev_info(dev, "probe start\n");
+
+       mdev = kzalloc(sizeof *mdev, GFP_KERNEL);
+       if (!mdev) {
+               mxr_err(mdev, "not enough memory.\n");
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       /* setup pointer to master device */
+       mdev->dev = dev;
+
+       mutex_init(&mdev->mutex);
+       spin_lock_init(&mdev->reg_slock);
+       init_waitqueue_head(&mdev->event_queue);
+
+       /* acquire resources: regs, irqs, clocks, regulators */
+       ret = mxr_acquire_resources(mdev, pdev);
+       if (ret)
+               goto fail_mem;
+
+       /* configure resources for video output */
+       ret = mxr_acquire_video(mdev, mxr_output_conf,
+               ARRAY_SIZE(mxr_output_conf));
+       if (ret)
+               goto fail_resources;
+
+       /* configure layers */
+       ret = mxr_acquire_layers(mdev, pdata);
+       if (ret)
+               goto fail_video;
+
+       pm_runtime_enable(dev);
+
+       mxr_info(mdev, "probe successful\n");
+       return 0;
+
+fail_video:
+       mxr_release_video(mdev);
+
+fail_resources:
+       mxr_release_resources(mdev);
+
+fail_mem:
+       kfree(mdev);
+
+fail:
+       dev_info(dev, "probe failed\n");
+       return ret;
+}
+
+static int __devexit mxr_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct mxr_device *mdev = to_mdev(dev);
+
+       pm_runtime_disable(dev);
+
+       mxr_release_layers(mdev);
+       mxr_release_video(mdev);
+       mxr_release_resources(mdev);
+
+       kfree(mdev);
+
+       dev_info(dev, "remove sucessful\n");
+       return 0;
+}
+
+static struct platform_driver mxr_driver __refdata = {
+       .probe = mxr_probe,
+       .remove = __devexit_p(mxr_remove),
+       .driver = {
+               .name = MXR_DRIVER_NAME,
+               .owner = THIS_MODULE,
+               .pm = &mxr_pm_ops,
+       }
+};
+
+static int __init mxr_init(void)
+{
+       int i, ret;
+       static const char banner[] __initdata = KERN_INFO
+               "Samsung TV Mixer driver, "
+               "(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
+       printk(banner);
+
+       /* Loading auxiliary modules */
+       for (i = 0; i < ARRAY_SIZE(mxr_output_conf); ++i)
+               request_module(mxr_output_conf[i].module_name);
+
+       ret = platform_driver_register(&mxr_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "registration of MIXER driver failed\n");
+               return -ENXIO;
+       }
+
+       return 0;
+}
+module_init(mxr_init);
+
+static void __exit mxr_exit(void)
+{
+       platform_driver_unregister(&mxr_driver);
+}
+module_exit(mxr_exit);
diff --git a/drivers/media/video/s5p-tv/mixer_grp_layer.c b/drivers/media/video/s5p-tv/mixer_grp_layer.c
new file mode 100644 (file)
index 0000000..58f0ba4
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "mixer.h"
+
+#include <media/videobuf2-dma-contig.h>
+
+/* FORMAT DEFINITIONS */
+
+static const struct mxr_format mxr_fb_fmt_rgb565 = {
+       .name = "RGB565",
+       .fourcc = V4L2_PIX_FMT_RGB565,
+       .colorspace = V4L2_COLORSPACE_SRGB,
+       .num_planes = 1,
+       .plane = {
+               { .width = 1, .height = 1, .size = 2 },
+       },
+       .num_subframes = 1,
+       .cookie = 4,
+};
+
+static const struct mxr_format mxr_fb_fmt_argb1555 = {
+       .name = "ARGB1555",
+       .num_planes = 1,
+       .fourcc = V4L2_PIX_FMT_RGB555,
+       .colorspace = V4L2_COLORSPACE_SRGB,
+       .plane = {
+               { .width = 1, .height = 1, .size = 2 },
+       },
+       .num_subframes = 1,
+       .cookie = 5,
+};
+
+static const struct mxr_format mxr_fb_fmt_argb4444 = {
+       .name = "ARGB4444",
+       .num_planes = 1,
+       .fourcc = V4L2_PIX_FMT_RGB444,
+       .colorspace = V4L2_COLORSPACE_SRGB,
+       .plane = {
+               { .width = 1, .height = 1, .size = 2 },
+       },
+       .num_subframes = 1,
+       .cookie = 6,
+};
+
+static const struct mxr_format mxr_fb_fmt_argb8888 = {
+       .name = "ARGB8888",
+       .fourcc = V4L2_PIX_FMT_BGR32,
+       .colorspace = V4L2_COLORSPACE_SRGB,
+       .num_planes = 1,
+       .plane = {
+               { .width = 1, .height = 1, .size = 4 },
+       },
+       .num_subframes = 1,
+       .cookie = 7,
+};
+
+static const struct mxr_format *mxr_graph_format[] = {
+       &mxr_fb_fmt_rgb565,
+       &mxr_fb_fmt_argb1555,
+       &mxr_fb_fmt_argb4444,
+       &mxr_fb_fmt_argb8888,
+};
+
+/* AUXILIARY CALLBACKS */
+
+static void mxr_graph_layer_release(struct mxr_layer *layer)
+{
+       mxr_base_layer_unregister(layer);
+       mxr_base_layer_release(layer);
+}
+
+static void mxr_graph_buffer_set(struct mxr_layer *layer,
+       struct mxr_buffer *buf)
+{
+       dma_addr_t addr = 0;
+
+       if (buf)
+               addr = vb2_dma_contig_plane_paddr(&buf->vb, 0);
+       mxr_reg_graph_buffer(layer->mdev, layer->idx, addr);
+}
+
+static void mxr_graph_stream_set(struct mxr_layer *layer, int en)
+{
+       mxr_reg_graph_layer_stream(layer->mdev, layer->idx, en);
+}
+
+static void mxr_graph_format_set(struct mxr_layer *layer)
+{
+       mxr_reg_graph_format(layer->mdev, layer->idx,
+               layer->fmt, &layer->geo);
+}
+
+static void mxr_graph_fix_geometry(struct mxr_layer *layer)
+{
+       struct mxr_geometry *geo = &layer->geo;
+
+       /* limit to boundary size */
+       geo->src.full_width = clamp_val(geo->src.full_width, 1, 32767);
+       geo->src.full_height = clamp_val(geo->src.full_height, 1, 2047);
+       geo->src.width = clamp_val(geo->src.width, 1, geo->src.full_width);
+       geo->src.width = min(geo->src.width, 2047U);
+       /* not possible to crop of Y axis */
+       geo->src.y_offset = min(geo->src.y_offset, geo->src.full_height - 1);
+       geo->src.height = geo->src.full_height - geo->src.y_offset;
+       /* limitting offset */
+       geo->src.x_offset = min(geo->src.x_offset,
+               geo->src.full_width - geo->src.width);
+
+       /* setting position in output */
+       geo->dst.width = min(geo->dst.width, geo->dst.full_width);
+       geo->dst.height = min(geo->dst.height, geo->dst.full_height);
+
+       /* Mixer supports only 1x and 2x scaling */
+       if (geo->dst.width >= 2 * geo->src.width) {
+               geo->x_ratio = 1;
+               geo->dst.width = 2 * geo->src.width;
+       } else {
+               geo->x_ratio = 0;
+               geo->dst.width = geo->src.width;
+       }
+
+       if (geo->dst.height >= 2 * geo->src.height) {
+               geo->y_ratio = 1;
+               geo->dst.height = 2 * geo->src.height;
+       } else {
+               geo->y_ratio = 0;
+               geo->dst.height = geo->src.height;
+       }
+
+       geo->dst.x_offset = min(geo->dst.x_offset,
+               geo->dst.full_width - geo->dst.width);
+       geo->dst.y_offset = min(geo->dst.y_offset,
+               geo->dst.full_height - geo->dst.height);
+}
+
+/* PUBLIC API */
+
+struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx)
+{
+       struct mxr_layer *layer;
+       int ret;
+       struct mxr_layer_ops ops = {
+               .release = mxr_graph_layer_release,
+               .buffer_set = mxr_graph_buffer_set,
+               .stream_set = mxr_graph_stream_set,
+               .format_set = mxr_graph_format_set,
+               .fix_geometry = mxr_graph_fix_geometry,
+       };
+       char name[32];
+
+       sprintf(name, "graph%d", idx);
+
+       layer = mxr_base_layer_create(mdev, idx, name, &ops);
+       if (layer == NULL) {
+               mxr_err(mdev, "failed to initialize layer(%d) base\n", idx);
+               goto fail;
+       }
+
+       layer->fmt_array = mxr_graph_format;
+       layer->fmt_array_size = ARRAY_SIZE(mxr_graph_format);
+
+       ret = mxr_base_layer_register(layer);
+       if (ret)
+               goto fail_layer;
+
+       return layer;
+
+fail_layer:
+       mxr_base_layer_release(layer);
+
+fail:
+       return NULL;
+}
+
diff --git a/drivers/media/video/s5p-tv/mixer_reg.c b/drivers/media/video/s5p-tv/mixer_reg.c
new file mode 100644 (file)
index 0000000..38dac67
--- /dev/null
@@ -0,0 +1,541 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "mixer.h"
+#include "regs-mixer.h"
+#include "regs-vp.h"
+
+#include <linux/delay.h>
+
+/* Register access subroutines */
+
+static inline u32 vp_read(struct mxr_device *mdev, u32 reg_id)
+{
+       return readl(mdev->res.vp_regs + reg_id);
+}
+
+static inline void vp_write(struct mxr_device *mdev, u32 reg_id, u32 val)
+{
+       writel(val, mdev->res.vp_regs + reg_id);
+}
+
+static inline void vp_write_mask(struct mxr_device *mdev, u32 reg_id,
+       u32 val, u32 mask)
+{
+       u32 old = vp_read(mdev, reg_id);
+
+       val = (val & mask) | (old & ~mask);
+       writel(val, mdev->res.vp_regs + reg_id);
+}
+
+static inline u32 mxr_read(struct mxr_device *mdev, u32 reg_id)
+{
+       return readl(mdev->res.mxr_regs + reg_id);
+}
+
+static inline void mxr_write(struct mxr_device *mdev, u32 reg_id, u32 val)
+{
+       writel(val, mdev->res.mxr_regs + reg_id);
+}
+
+static inline void mxr_write_mask(struct mxr_device *mdev, u32 reg_id,
+       u32 val, u32 mask)
+{
+       u32 old = mxr_read(mdev, reg_id);
+
+       val = (val & mask) | (old & ~mask);
+       writel(val, mdev->res.mxr_regs + reg_id);
+}
+
+void mxr_vsync_set_update(struct mxr_device *mdev, int en)
+{
+       /* block update on vsync */
+       mxr_write_mask(mdev, MXR_STATUS, en ? MXR_STATUS_SYNC_ENABLE : 0,
+               MXR_STATUS_SYNC_ENABLE);
+       vp_write(mdev, VP_SHADOW_UPDATE, en ? VP_SHADOW_UPDATE_ENABLE : 0);
+}
+
+static void __mxr_reg_vp_reset(struct mxr_device *mdev)
+{
+       int tries = 100;
+
+       vp_write(mdev, VP_SRESET, VP_SRESET_PROCESSING);
+       for (tries = 100; tries; --tries) {
+               /* waiting until VP_SRESET_PROCESSING is 0 */
+               if (~vp_read(mdev, VP_SRESET) & VP_SRESET_PROCESSING)
+                       break;
+               mdelay(10);
+       }
+       WARN(tries == 0, "failed to reset Video Processor\n");
+}
+
+static void mxr_reg_vp_default_filter(struct mxr_device *mdev);
+
+void mxr_reg_reset(struct mxr_device *mdev)
+{
+       unsigned long flags;
+       u32 val; /* value stored to register */
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+       /* set output in RGB888 mode */
+       mxr_write(mdev, MXR_CFG, MXR_CFG_OUT_YUV444);
+
+       /* 16 beat burst in DMA */
+       mxr_write_mask(mdev, MXR_STATUS, MXR_STATUS_16_BURST,
+               MXR_STATUS_BURST_MASK);
+
+       /* setting default layer priority: layer1 > video > layer0
+        * because typical usage scenario would be
+        * layer0 - framebuffer
+        * video - video overlay
+        * layer1 - OSD
+        */
+       val  = MXR_LAYER_CFG_GRP0_VAL(1);
+       val |= MXR_LAYER_CFG_VP_VAL(2);
+       val |= MXR_LAYER_CFG_GRP1_VAL(3);
+       mxr_write(mdev, MXR_LAYER_CFG, val);
+
+       /* use dark gray background color */
+       mxr_write(mdev, MXR_BG_COLOR0, 0x808080);
+       mxr_write(mdev, MXR_BG_COLOR1, 0x808080);
+       mxr_write(mdev, MXR_BG_COLOR2, 0x808080);
+
+       /* setting graphical layers */
+
+       val  = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
+       val |= MXR_GRP_CFG_BLEND_PRE_MUL; /* premul mode */
+       val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
+
+       /* the same configuration for both layers */
+       mxr_write(mdev, MXR_GRAPHIC_CFG(0), val);
+       mxr_write(mdev, MXR_GRAPHIC_CFG(1), val);
+
+       /* configuration of Video Processor Registers */
+       __mxr_reg_vp_reset(mdev);
+       mxr_reg_vp_default_filter(mdev);
+
+       /* enable all interrupts */
+       mxr_write_mask(mdev, MXR_INT_EN, ~0, MXR_INT_EN_ALL);
+
+       mxr_vsync_set_update(mdev, MXR_ENABLE);
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_graph_format(struct mxr_device *mdev, int idx,
+       const struct mxr_format *fmt, const struct mxr_geometry *geo)
+{
+       u32 val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+       /* setup format */
+       mxr_write_mask(mdev, MXR_GRAPHIC_CFG(idx),
+               MXR_GRP_CFG_FORMAT_VAL(fmt->cookie), MXR_GRP_CFG_FORMAT_MASK);
+
+       /* setup geometry */
+       mxr_write(mdev, MXR_GRAPHIC_SPAN(idx), geo->src.full_width);
+       val  = MXR_GRP_WH_WIDTH(geo->src.width);
+       val |= MXR_GRP_WH_HEIGHT(geo->src.height);
+       val |= MXR_GRP_WH_H_SCALE(geo->x_ratio);
+       val |= MXR_GRP_WH_V_SCALE(geo->y_ratio);
+       mxr_write(mdev, MXR_GRAPHIC_WH(idx), val);
+
+       /* setup offsets in source image */
+       val  = MXR_GRP_SXY_SX(geo->src.x_offset);
+       val |= MXR_GRP_SXY_SY(geo->src.y_offset);
+       mxr_write(mdev, MXR_GRAPHIC_SXY(idx), val);
+
+       /* setup offsets in display image */
+       val  = MXR_GRP_DXY_DX(geo->dst.x_offset);
+       val |= MXR_GRP_DXY_DY(geo->dst.y_offset);
+       mxr_write(mdev, MXR_GRAPHIC_DXY(idx), val);
+
+       mxr_vsync_set_update(mdev, MXR_ENABLE);
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_vp_format(struct mxr_device *mdev,
+       const struct mxr_format *fmt, const struct mxr_geometry *geo)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+       vp_write_mask(mdev, VP_MODE, fmt->cookie, VP_MODE_FMT_MASK);
+
+       /* setting size of input image */
+       vp_write(mdev, VP_IMG_SIZE_Y, VP_IMG_HSIZE(geo->src.full_width) |
+               VP_IMG_VSIZE(geo->src.full_height));
+       /* chroma height has to reduced by 2 to avoid chroma distorions */
+       vp_write(mdev, VP_IMG_SIZE_C, VP_IMG_HSIZE(geo->src.full_width) |
+               VP_IMG_VSIZE(geo->src.full_height / 2));
+
+       vp_write(mdev, VP_SRC_WIDTH, geo->src.width);
+       vp_write(mdev, VP_SRC_HEIGHT, geo->src.height);
+       vp_write(mdev, VP_SRC_H_POSITION,
+               VP_SRC_H_POSITION_VAL(geo->src.x_offset));
+       vp_write(mdev, VP_SRC_V_POSITION, geo->src.y_offset);
+
+       vp_write(mdev, VP_DST_WIDTH, geo->dst.width);
+       vp_write(mdev, VP_DST_H_POSITION, geo->dst.x_offset);
+       if (geo->dst.field == V4L2_FIELD_INTERLACED) {
+               vp_write(mdev, VP_DST_HEIGHT, geo->dst.height / 2);
+               vp_write(mdev, VP_DST_V_POSITION, geo->dst.y_offset / 2);
+       } else {
+               vp_write(mdev, VP_DST_HEIGHT, geo->dst.height);
+               vp_write(mdev, VP_DST_V_POSITION, geo->dst.y_offset);
+       }
+
+       vp_write(mdev, VP_H_RATIO, geo->x_ratio);
+       vp_write(mdev, VP_V_RATIO, geo->y_ratio);
+
+       vp_write(mdev, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
+
+       mxr_vsync_set_update(mdev, MXR_ENABLE);
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+
+}
+
+void mxr_reg_graph_buffer(struct mxr_device *mdev, int idx, dma_addr_t addr)
+{
+       u32 val = addr ? ~0 : 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+       if (idx == 0)
+               mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
+       else
+               mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
+       mxr_write(mdev, MXR_GRAPHIC_BASE(idx), addr);
+
+       mxr_vsync_set_update(mdev, MXR_ENABLE);
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_vp_buffer(struct mxr_device *mdev,
+       dma_addr_t luma_addr[2], dma_addr_t chroma_addr[2])
+{
+       u32 val = luma_addr[0] ? ~0 : 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+       mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_VP_ENABLE);
+       vp_write_mask(mdev, VP_ENABLE, val, VP_ENABLE_ON);
+       /* TODO: fix tiled mode */
+       vp_write(mdev, VP_TOP_Y_PTR, luma_addr[0]);
+       vp_write(mdev, VP_TOP_C_PTR, chroma_addr[0]);
+       vp_write(mdev, VP_BOT_Y_PTR, luma_addr[1]);
+       vp_write(mdev, VP_BOT_C_PTR, chroma_addr[1]);
+
+       mxr_vsync_set_update(mdev, MXR_ENABLE);
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+static void mxr_irq_layer_handle(struct mxr_layer *layer)
+{
+       struct list_head *head = &layer->enq_list;
+       struct mxr_buffer *done;
+
+       /* skip non-existing layer */
+       if (layer == NULL)
+               return;
+
+       spin_lock(&layer->enq_slock);
+       if (layer->state == MXR_LAYER_IDLE)
+               goto done;
+
+       done = layer->shadow_buf;
+       layer->shadow_buf = layer->update_buf;
+
+       if (list_empty(head)) {
+               if (layer->state != MXR_LAYER_STREAMING)
+                       layer->update_buf = NULL;
+       } else {
+               struct mxr_buffer *next;
+               next = list_first_entry(head, struct mxr_buffer, list);
+               list_del(&next->list);
+               layer->update_buf = next;
+       }
+
+       layer->ops.buffer_set(layer, layer->update_buf);
+
+       if (done && done != layer->shadow_buf)
+               vb2_buffer_done(&done->vb, VB2_BUF_STATE_DONE);
+
+done:
+       spin_unlock(&layer->enq_slock);
+}
+
+irqreturn_t mxr_irq_handler(int irq, void *dev_data)
+{
+       struct mxr_device *mdev = dev_data;
+       u32 i, val;
+
+       spin_lock(&mdev->reg_slock);
+       val = mxr_read(mdev, MXR_INT_STATUS);
+
+       /* wake up process waiting for VSYNC */
+       if (val & MXR_INT_STATUS_VSYNC) {
+               set_bit(MXR_EVENT_VSYNC, &mdev->event_flags);
+               wake_up(&mdev->event_queue);
+       }
+
+       /* clear interrupts */
+       if (~val & MXR_INT_EN_VSYNC) {
+               /* vsync interrupt use different bit for read and clear */
+               val &= ~MXR_INT_EN_VSYNC;
+               val |= MXR_INT_CLEAR_VSYNC;
+       }
+       mxr_write(mdev, MXR_INT_STATUS, val);
+
+       spin_unlock(&mdev->reg_slock);
+       /* leave on non-vsync event */
+       if (~val & MXR_INT_CLEAR_VSYNC)
+               return IRQ_HANDLED;
+       for (i = 0; i < MXR_MAX_LAYERS; ++i)
+               mxr_irq_layer_handle(mdev->layer[i]);
+       return IRQ_HANDLED;
+}
+
+void mxr_reg_s_output(struct mxr_device *mdev, int cookie)
+{
+       u32 val;
+
+       val = cookie == 0 ? MXR_CFG_DST_SDO : MXR_CFG_DST_HDMI;
+       mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_DST_MASK);
+}
+
+void mxr_reg_streamon(struct mxr_device *mdev)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       /* single write -> no need to block vsync update */
+
+       /* start MIXER */
+       mxr_write_mask(mdev, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
+
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_streamoff(struct mxr_device *mdev)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       /* single write -> no need to block vsync update */
+
+       /* stop MIXER */
+       mxr_write_mask(mdev, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
+
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+int mxr_reg_wait4vsync(struct mxr_device *mdev)
+{
+       int ret;
+
+       clear_bit(MXR_EVENT_VSYNC, &mdev->event_flags);
+       /* TODO: consider adding interruptible */
+       ret = wait_event_timeout(mdev->event_queue,
+               test_bit(MXR_EVENT_VSYNC, &mdev->event_flags),
+               msecs_to_jiffies(1000));
+       if (ret > 0)
+               return 0;
+       if (ret < 0)
+               return ret;
+       mxr_warn(mdev, "no vsync detected - timeout\n");
+       return -ETIME;
+}
+
+void mxr_reg_set_mbus_fmt(struct mxr_device *mdev,
+       struct v4l2_mbus_framefmt *fmt)
+{
+       u32 val = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+       /* choosing between interlace and progressive mode */
+       if (fmt->field == V4L2_FIELD_INTERLACED)
+               val |= MXR_CFG_SCAN_INTERLACE;
+       else
+               val |= MXR_CFG_SCAN_PROGRASSIVE;
+
+       /* choosing between porper HD and SD mode */
+       if (fmt->height == 480)
+               val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
+       else if (fmt->height == 576)
+               val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
+       else if (fmt->height == 720)
+               val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
+       else if (fmt->height == 1080)
+               val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
+       else
+               WARN(1, "unrecognized mbus height %u!\n", fmt->height);
+
+       mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_SCAN_MASK);
+
+       val = (fmt->field == V4L2_FIELD_INTERLACED) ? ~0 : 0;
+       vp_write_mask(mdev, VP_MODE, val,
+               VP_MODE_LINE_SKIP | VP_MODE_FIELD_ID_AUTO_TOGGLING);
+
+       mxr_vsync_set_update(mdev, MXR_ENABLE);
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_graph_layer_stream(struct mxr_device *mdev, int idx, int en)
+{
+       /* no extra actions need to be done */
+}
+
+void mxr_reg_vp_layer_stream(struct mxr_device *mdev, int en)
+{
+       /* no extra actions need to be done */
+}
+
+static const u8 filter_y_horiz_tap8[] = {
+       0,      -1,     -1,     -1,     -1,     -1,     -1,     -1,
+       -1,     -1,     -1,     -1,     -1,     0,      0,      0,
+       0,      2,      4,      5,      6,      6,      6,      6,
+       6,      5,      5,      4,      3,      2,      1,      1,
+       0,      -6,     -12,    -16,    -18,    -20,    -21,    -20,
+       -20,    -18,    -16,    -13,    -10,    -8,     -5,     -2,
+       127,    126,    125,    121,    114,    107,    99,     89,
+       79,     68,     57,     46,     35,     25,     16,     8,
+};
+
+static const u8 filter_y_vert_tap4[] = {
+       0,      -3,     -6,     -8,     -8,     -8,     -8,     -7,
+       -6,     -5,     -4,     -3,     -2,     -1,     -1,     0,
+       127,    126,    124,    118,    111,    102,    92,     81,
+       70,     59,     48,     37,     27,     19,     11,     5,
+       0,      5,      11,     19,     27,     37,     48,     59,
+       70,     81,     92,     102,    111,    118,    124,    126,
+       0,      0,      -1,     -1,     -2,     -3,     -4,     -5,
+       -6,     -7,     -8,     -8,     -8,     -8,     -6,     -3,
+};
+
+static const u8 filter_cr_horiz_tap4[] = {
+       0,      -3,     -6,     -8,     -8,     -8,     -8,     -7,
+       -6,     -5,     -4,     -3,     -2,     -1,     -1,     0,
+       127,    126,    124,    118,    111,    102,    92,     81,
+       70,     59,     48,     37,     27,     19,     11,     5,
+};
+
+static inline void mxr_reg_vp_filter_set(struct mxr_device *mdev,
+       int reg_id, const u8 *data, unsigned int size)
+{
+       /* assure 4-byte align */
+       BUG_ON(size & 3);
+       for (; size; size -= 4, reg_id += 4, data += 4) {
+               u32 val = (data[0] << 24) |  (data[1] << 16) |
+                       (data[2] << 8) | data[3];
+               vp_write(mdev, reg_id, val);
+       }
+}
+
+static void mxr_reg_vp_default_filter(struct mxr_device *mdev)
+{
+       mxr_reg_vp_filter_set(mdev, VP_POLY8_Y0_LL,
+               filter_y_horiz_tap8, sizeof filter_y_horiz_tap8);
+       mxr_reg_vp_filter_set(mdev, VP_POLY4_Y0_LL,
+               filter_y_vert_tap4, sizeof filter_y_vert_tap4);
+       mxr_reg_vp_filter_set(mdev, VP_POLY4_C0_LL,
+               filter_cr_horiz_tap4, sizeof filter_cr_horiz_tap4);
+}
+
+static void mxr_reg_mxr_dump(struct mxr_device *mdev)
+{
+#define DUMPREG(reg_id) \
+do { \
+       mxr_dbg(mdev, #reg_id " = %08x\n", \
+               (u32)readl(mdev->res.mxr_regs + reg_id)); \
+} while (0)
+
+       DUMPREG(MXR_STATUS);
+       DUMPREG(MXR_CFG);
+       DUMPREG(MXR_INT_EN);
+       DUMPREG(MXR_INT_STATUS);
+
+       DUMPREG(MXR_LAYER_CFG);
+       DUMPREG(MXR_VIDEO_CFG);
+
+       DUMPREG(MXR_GRAPHIC0_CFG);
+       DUMPREG(MXR_GRAPHIC0_BASE);
+       DUMPREG(MXR_GRAPHIC0_SPAN);
+       DUMPREG(MXR_GRAPHIC0_WH);
+       DUMPREG(MXR_GRAPHIC0_SXY);
+       DUMPREG(MXR_GRAPHIC0_DXY);
+
+       DUMPREG(MXR_GRAPHIC1_CFG);
+       DUMPREG(MXR_GRAPHIC1_BASE);
+       DUMPREG(MXR_GRAPHIC1_SPAN);
+       DUMPREG(MXR_GRAPHIC1_WH);
+       DUMPREG(MXR_GRAPHIC1_SXY);
+       DUMPREG(MXR_GRAPHIC1_DXY);
+#undef DUMPREG
+}
+
+static void mxr_reg_vp_dump(struct mxr_device *mdev)
+{
+#define DUMPREG(reg_id) \
+do { \
+       mxr_dbg(mdev, #reg_id " = %08x\n", \
+               (u32) readl(mdev->res.vp_regs + reg_id)); \
+} while (0)
+
+
+       DUMPREG(VP_ENABLE);
+       DUMPREG(VP_SRESET);
+       DUMPREG(VP_SHADOW_UPDATE);
+       DUMPREG(VP_FIELD_ID);
+       DUMPREG(VP_MODE);
+       DUMPREG(VP_IMG_SIZE_Y);
+       DUMPREG(VP_IMG_SIZE_C);
+       DUMPREG(VP_PER_RATE_CTRL);
+       DUMPREG(VP_TOP_Y_PTR);
+       DUMPREG(VP_BOT_Y_PTR);
+       DUMPREG(VP_TOP_C_PTR);
+       DUMPREG(VP_BOT_C_PTR);
+       DUMPREG(VP_ENDIAN_MODE);
+       DUMPREG(VP_SRC_H_POSITION);
+       DUMPREG(VP_SRC_V_POSITION);
+       DUMPREG(VP_SRC_WIDTH);
+       DUMPREG(VP_SRC_HEIGHT);
+       DUMPREG(VP_DST_H_POSITION);
+       DUMPREG(VP_DST_V_POSITION);
+       DUMPREG(VP_DST_WIDTH);
+       DUMPREG(VP_DST_HEIGHT);
+       DUMPREG(VP_H_RATIO);
+       DUMPREG(VP_V_RATIO);
+
+#undef DUMPREG
+}
+
+void mxr_reg_dump(struct mxr_device *mdev)
+{
+       mxr_reg_mxr_dump(mdev);
+       mxr_reg_vp_dump(mdev);
+}
+
diff --git a/drivers/media/video/s5p-tv/mixer_video.c b/drivers/media/video/s5p-tv/mixer_video.c
new file mode 100644 (file)
index 0000000..43ac22f
--- /dev/null
@@ -0,0 +1,1006 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "mixer.h"
+
+#include <media/v4l2-ioctl.h>
+#include <linux/videodev2.h>
+#include <linux/mm.h>
+#include <linux/version.h>
+#include <linux/timer.h>
+#include <media/videobuf2-dma-contig.h>
+
+static int find_reg_callback(struct device *dev, void *p)
+{
+       struct v4l2_subdev **sd = p;
+
+       *sd = dev_get_drvdata(dev);
+       /* non-zero value stops iteration */
+       return 1;
+}
+
+static struct v4l2_subdev *find_and_register_subdev(
+       struct mxr_device *mdev, char *module_name)
+{
+       struct device_driver *drv;
+       struct v4l2_subdev *sd = NULL;
+       int ret;
+
+       /* TODO: add waiting until probe is finished */
+       drv = driver_find(module_name, &platform_bus_type);
+       if (!drv) {
+               mxr_warn(mdev, "module %s is missing\n", module_name);
+               return NULL;
+       }
+       /* driver refcnt is increased, it is safe to iterate over devices */
+       ret = driver_for_each_device(drv, NULL, &sd, find_reg_callback);
+       /* ret == 0 means that find_reg_callback was never executed */
+       if (sd == NULL) {
+               mxr_warn(mdev, "module %s provides no subdev!\n", module_name);
+               goto done;
+       }
+       /* v4l2_device_register_subdev detects if sd is NULL */
+       ret = v4l2_device_register_subdev(&mdev->v4l2_dev, sd);
+       if (ret) {
+               mxr_warn(mdev, "failed to register subdev %s\n", sd->name);
+               sd = NULL;
+       }
+
+done:
+       put_driver(drv);
+       return sd;
+}
+
+int __devinit mxr_acquire_video(struct mxr_device *mdev,
+       struct mxr_output_conf *output_conf, int output_count)
+{
+       struct device *dev = mdev->dev;
+       struct v4l2_device *v4l2_dev = &mdev->v4l2_dev;
+       int i;
+       int ret = 0;
+       struct v4l2_subdev *sd;
+
+       strlcpy(v4l2_dev->name, dev_name(mdev->dev), sizeof(v4l2_dev->name));
+       /* prepare context for V4L2 device */
+       ret = v4l2_device_register(dev, v4l2_dev);
+       if (ret) {
+               mxr_err(mdev, "could not register v4l2 device.\n");
+               goto fail;
+       }
+
+       mdev->alloc_ctx = vb2_dma_contig_init_ctx(mdev->dev);
+       if (IS_ERR_OR_NULL(mdev->alloc_ctx)) {
+               mxr_err(mdev, "could not acquire vb2 allocator\n");
+               goto fail_v4l2_dev;
+       }
+
+       /* registering outputs */
+       mdev->output_cnt = 0;
+       for (i = 0; i < output_count; ++i) {
+               struct mxr_output_conf *conf = &output_conf[i];
+               struct mxr_output *out;
+
+               sd = find_and_register_subdev(mdev, conf->module_name);
+               /* trying to register next output */
+               if (sd == NULL)
+                       continue;
+               out = kzalloc(sizeof *out, GFP_KERNEL);
+               if (out == NULL) {
+                       mxr_err(mdev, "no memory for '%s'\n",
+                               conf->output_name);
+                       ret = -ENOMEM;
+                       /* registered subdevs are removed in fail_v4l2_dev */
+                       goto fail_output;
+               }
+               strlcpy(out->name, conf->output_name, sizeof(out->name));
+               out->sd = sd;
+               out->cookie = conf->cookie;
+               mdev->output[mdev->output_cnt++] = out;
+               mxr_info(mdev, "added output '%s' from module '%s'\n",
+                       conf->output_name, conf->module_name);
+               /* checking if maximal number of outputs is reached */
+               if (mdev->output_cnt >= MXR_MAX_OUTPUTS)
+                       break;
+       }
+
+       if (mdev->output_cnt == 0) {
+               mxr_err(mdev, "failed to register any output\n");
+               ret = -ENODEV;
+               /* skipping fail_output because there is nothing to free */
+               goto fail_vb2_allocator;
+       }
+
+       return 0;
+
+fail_output:
+       /* kfree is NULL-safe */
+       for (i = 0; i < mdev->output_cnt; ++i)
+               kfree(mdev->output[i]);
+       memset(mdev->output, 0, sizeof mdev->output);
+
+fail_vb2_allocator:
+       /* freeing allocator context */
+       vb2_dma_contig_cleanup_ctx(mdev->alloc_ctx);
+
+fail_v4l2_dev:
+       /* NOTE: automatically unregister all subdevs */
+       v4l2_device_unregister(v4l2_dev);
+
+fail:
+       return ret;
+}
+
+void __devexit mxr_release_video(struct mxr_device *mdev)
+{
+       int i;
+
+       /* kfree is NULL-safe */
+       for (i = 0; i < mdev->output_cnt; ++i)
+               kfree(mdev->output[i]);
+
+       vb2_dma_contig_cleanup_ctx(mdev->alloc_ctx);
+       v4l2_device_unregister(&mdev->v4l2_dev);
+}
+
+static int mxr_querycap(struct file *file, void *priv,
+       struct v4l2_capability *cap)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+       strlcpy(cap->driver, MXR_DRIVER_NAME, sizeof cap->driver);
+       strlcpy(cap->card, layer->vfd.name, sizeof cap->card);
+       sprintf(cap->bus_info, "%d", layer->idx);
+       cap->version = KERNEL_VERSION(0, 1, 0);
+       cap->capabilities = V4L2_CAP_STREAMING |
+               V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+
+       return 0;
+}
+
+/* Geometry handling */
+static void mxr_layer_geo_fix(struct mxr_layer *layer)
+{
+       struct mxr_device *mdev = layer->mdev;
+       struct v4l2_mbus_framefmt mbus_fmt;
+
+       /* TODO: add some dirty flag to avoid unnecessary adjustments */
+       mxr_get_mbus_fmt(mdev, &mbus_fmt);
+       layer->geo.dst.full_width = mbus_fmt.width;
+       layer->geo.dst.full_height = mbus_fmt.height;
+       layer->geo.dst.field = mbus_fmt.field;
+       layer->ops.fix_geometry(layer);
+}
+
+static void mxr_layer_default_geo(struct mxr_layer *layer)
+{
+       struct mxr_device *mdev = layer->mdev;
+       struct v4l2_mbus_framefmt mbus_fmt;
+
+       memset(&layer->geo, 0, sizeof layer->geo);
+
+       mxr_get_mbus_fmt(mdev, &mbus_fmt);
+
+       layer->geo.dst.full_width = mbus_fmt.width;
+       layer->geo.dst.full_height = mbus_fmt.height;
+       layer->geo.dst.width = layer->geo.dst.full_width;
+       layer->geo.dst.height = layer->geo.dst.full_height;
+       layer->geo.dst.field = mbus_fmt.field;
+
+       layer->geo.src.full_width = mbus_fmt.width;
+       layer->geo.src.full_height = mbus_fmt.height;
+       layer->geo.src.width = layer->geo.src.full_width;
+       layer->geo.src.height = layer->geo.src.full_height;
+
+       layer->ops.fix_geometry(layer);
+}
+
+static void mxr_geometry_dump(struct mxr_device *mdev, struct mxr_geometry *geo)
+{
+       mxr_dbg(mdev, "src.full_size = (%u, %u)\n",
+               geo->src.full_width, geo->src.full_height);
+       mxr_dbg(mdev, "src.size = (%u, %u)\n",
+               geo->src.width, geo->src.height);
+       mxr_dbg(mdev, "src.offset = (%u, %u)\n",
+               geo->src.x_offset, geo->src.y_offset);
+       mxr_dbg(mdev, "dst.full_size = (%u, %u)\n",
+               geo->dst.full_width, geo->dst.full_height);
+       mxr_dbg(mdev, "dst.size = (%u, %u)\n",
+               geo->dst.width, geo->dst.height);
+       mxr_dbg(mdev, "dst.offset = (%u, %u)\n",
+               geo->dst.x_offset, geo->dst.y_offset);
+       mxr_dbg(mdev, "ratio = (%u, %u)\n",
+               geo->x_ratio, geo->y_ratio);
+}
+
+
+static const struct mxr_format *find_format_by_fourcc(
+       struct mxr_layer *layer, unsigned long fourcc);
+static const struct mxr_format *find_format_by_index(
+       struct mxr_layer *layer, unsigned long index);
+
+static int mxr_enum_fmt(struct file *file, void  *priv,
+       struct v4l2_fmtdesc *f)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       const struct mxr_format *fmt;
+
+       mxr_dbg(mdev, "%s\n", __func__);
+       fmt = find_format_by_index(layer, f->index);
+       if (fmt == NULL)
+               return -EINVAL;
+
+       strlcpy(f->description, fmt->name, sizeof(f->description));
+       f->pixelformat = fmt->fourcc;
+
+       return 0;
+}
+
+static int mxr_s_fmt(struct file *file, void *priv,
+       struct v4l2_format *f)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       const struct mxr_format *fmt;
+       struct v4l2_pix_format_mplane *pix;
+       struct mxr_device *mdev = layer->mdev;
+       struct mxr_geometry *geo = &layer->geo;
+
+       mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__);
+
+       pix = &f->fmt.pix_mp;
+       fmt = find_format_by_fourcc(layer, pix->pixelformat);
+       if (fmt == NULL) {
+               mxr_warn(mdev, "not recognized fourcc: %08x\n",
+                       pix->pixelformat);
+               return -EINVAL;
+       }
+       layer->fmt = fmt;
+       geo->src.full_width = pix->width;
+       geo->src.width = pix->width;
+       geo->src.full_height = pix->height;
+       geo->src.height = pix->height;
+       /* assure consistency of geometry */
+       mxr_layer_geo_fix(layer);
+       mxr_dbg(mdev, "width=%u height=%u span=%u\n",
+               geo->src.width, geo->src.height, geo->src.full_width);
+
+       return 0;
+}
+
+static unsigned int divup(unsigned int divident, unsigned int divisor)
+{
+       return (divident + divisor - 1) / divisor;
+}
+
+unsigned long mxr_get_plane_size(const struct mxr_block *blk,
+       unsigned int width, unsigned int height)
+{
+       unsigned int bl_width = divup(width, blk->width);
+       unsigned int bl_height = divup(height, blk->height);
+
+       return bl_width * bl_height * blk->size;
+}
+
+static void mxr_mplane_fill(struct v4l2_plane_pix_format *planes,
+       const struct mxr_format *fmt, u32 width, u32 height)
+{
+       int i;
+
+       memset(planes, 0, sizeof(*planes) * fmt->num_subframes);
+       for (i = 0; i < fmt->num_planes; ++i) {
+               struct v4l2_plane_pix_format *plane = planes
+                       + fmt->plane2subframe[i];
+               const struct mxr_block *blk = &fmt->plane[i];
+               u32 bl_width = divup(width, blk->width);
+               u32 bl_height = divup(height, blk->height);
+               u32 sizeimage = bl_width * bl_height * blk->size;
+               u16 bytesperline = bl_width * blk->size / blk->height;
+
+               plane->sizeimage += sizeimage;
+               plane->bytesperline = max(plane->bytesperline, bytesperline);
+       }
+}
+
+static int mxr_g_fmt(struct file *file, void *priv,
+                            struct v4l2_format *f)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+       pix->width = layer->geo.src.full_width;
+       pix->height = layer->geo.src.full_height;
+       pix->field = V4L2_FIELD_NONE;
+       pix->pixelformat = layer->fmt->fourcc;
+       pix->colorspace = layer->fmt->colorspace;
+       mxr_mplane_fill(pix->plane_fmt, layer->fmt, pix->width, pix->height);
+
+       return 0;
+}
+
+static inline struct mxr_crop *choose_crop_by_type(struct mxr_geometry *geo,
+       enum v4l2_buf_type type)
+{
+       switch (type) {
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+               return &geo->dst;
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+               return &geo->src;
+       default:
+               return NULL;
+       }
+}
+
+static int mxr_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_crop *crop;
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+       crop = choose_crop_by_type(&layer->geo, a->type);
+       if (crop == NULL)
+               return -EINVAL;
+       mxr_layer_geo_fix(layer);
+       a->c.left = crop->x_offset;
+       a->c.top = crop->y_offset;
+       a->c.width = crop->width;
+       a->c.height = crop->height;
+       return 0;
+}
+
+static int mxr_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_crop *crop;
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+       crop = choose_crop_by_type(&layer->geo, a->type);
+       if (crop == NULL)
+               return -EINVAL;
+       crop->x_offset = a->c.left;
+       crop->y_offset = a->c.top;
+       crop->width = a->c.width;
+       crop->height = a->c.height;
+       mxr_layer_geo_fix(layer);
+       return 0;
+}
+
+static int mxr_cropcap(struct file *file, void *fh, struct v4l2_cropcap *a)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_crop *crop;
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+       crop = choose_crop_by_type(&layer->geo, a->type);
+       if (crop == NULL)
+               return -EINVAL;
+       mxr_layer_geo_fix(layer);
+       a->bounds.left = 0;
+       a->bounds.top = 0;
+       a->bounds.width = crop->full_width;
+       a->bounds.top = crop->full_height;
+       a->defrect = a->bounds;
+       /* setting pixel aspect to 1/1 */
+       a->pixelaspect.numerator = 1;
+       a->pixelaspect.denominator = 1;
+       return 0;
+}
+
+static int mxr_enum_dv_presets(struct file *file, void *fh,
+       struct v4l2_dv_enum_preset *preset)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       int ret;
+
+       /* lock protects from changing sd_out */
+       mutex_lock(&mdev->mutex);
+       ret = v4l2_subdev_call(to_outsd(mdev), video, enum_dv_presets, preset);
+       mutex_unlock(&mdev->mutex);
+
+       return ret ? -EINVAL : 0;
+}
+
+static int mxr_s_dv_preset(struct file *file, void *fh,
+       struct v4l2_dv_preset *preset)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       int ret;
+
+       /* lock protects from changing sd_out */
+       mutex_lock(&mdev->mutex);
+
+       /* preset change cannot be done while there is an entity
+        * dependant on output configuration
+        */
+       if (mdev->n_output > 0) {
+               mutex_unlock(&mdev->mutex);
+               return -EBUSY;
+       }
+
+       ret = v4l2_subdev_call(to_outsd(mdev), video, s_dv_preset, preset);
+
+       mutex_unlock(&mdev->mutex);
+
+       /* any failure should return EINVAL according to V4L2 doc */
+       return ret ? -EINVAL : 0;
+}
+
+static int mxr_g_dv_preset(struct file *file, void *fh,
+       struct v4l2_dv_preset *preset)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       int ret;
+
+       /* lock protects from changing sd_out */
+       mutex_lock(&mdev->mutex);
+       ret = v4l2_subdev_call(to_outsd(mdev), video, g_dv_preset, preset);
+       mutex_unlock(&mdev->mutex);
+
+       return ret ? -EINVAL : 0;
+}
+
+static int mxr_s_std(struct file *file, void *fh, v4l2_std_id *norm)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       int ret;
+
+       /* lock protects from changing sd_out */
+       mutex_lock(&mdev->mutex);
+
+       /* standard change cannot be done while there is an entity
+        * dependant on output configuration
+        */
+       if (mdev->n_output > 0) {
+               mutex_unlock(&mdev->mutex);
+               return -EBUSY;
+       }
+
+       ret = v4l2_subdev_call(to_outsd(mdev), video, s_std_output, *norm);
+
+       mutex_unlock(&mdev->mutex);
+
+       return ret ? -EINVAL : 0;
+}
+
+static int mxr_g_std(struct file *file, void *fh, v4l2_std_id *norm)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       int ret;
+
+       /* lock protects from changing sd_out */
+       mutex_lock(&mdev->mutex);
+       ret = v4l2_subdev_call(to_outsd(mdev), video, g_std_output, norm);
+       mutex_unlock(&mdev->mutex);
+
+       return ret ? -EINVAL : 0;
+}
+
+static int mxr_enum_output(struct file *file, void *fh, struct v4l2_output *a)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       struct mxr_output *out;
+       struct v4l2_subdev *sd;
+
+       if (a->index >= mdev->output_cnt)
+               return -EINVAL;
+       out = mdev->output[a->index];
+       BUG_ON(out == NULL);
+       sd = out->sd;
+       strlcpy(a->name, out->name, sizeof(a->name));
+
+       /* try to obtain supported tv norms */
+       v4l2_subdev_call(sd, video, g_tvnorms_output, &a->std);
+       a->capabilities = 0;
+       if (sd->ops->video && sd->ops->video->s_dv_preset)
+               a->capabilities |= V4L2_OUT_CAP_PRESETS;
+       if (sd->ops->video && sd->ops->video->s_std_output)
+               a->capabilities |= V4L2_OUT_CAP_STD;
+       a->type = V4L2_OUTPUT_TYPE_ANALOG;
+
+       return 0;
+}
+
+static int mxr_s_output(struct file *file, void *fh, unsigned int i)
+{
+       struct video_device *vfd = video_devdata(file);
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       int ret = 0;
+
+       if (i >= mdev->output_cnt || mdev->output[i] == NULL)
+               return -EINVAL;
+
+       mutex_lock(&mdev->mutex);
+       if (mdev->n_output > 0) {
+               ret = -EBUSY;
+               goto done;
+       }
+       mdev->current_output = i;
+       vfd->tvnorms = 0;
+       v4l2_subdev_call(to_outsd(mdev), video, g_tvnorms_output,
+               &vfd->tvnorms);
+       mxr_dbg(mdev, "tvnorms = %08llx\n", vfd->tvnorms);
+
+done:
+       mutex_unlock(&mdev->mutex);
+       return ret;
+}
+
+static int mxr_g_output(struct file *file, void *fh, unsigned int *p)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+
+       mutex_lock(&mdev->mutex);
+       *p = mdev->current_output;
+       mutex_unlock(&mdev->mutex);
+
+       return 0;
+}
+
+static int mxr_reqbufs(struct file *file, void *priv,
+                         struct v4l2_requestbuffers *p)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+       return vb2_reqbufs(&layer->vb_queue, p);
+}
+
+static int mxr_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+       return vb2_querybuf(&layer->vb_queue, p);
+}
+
+static int mxr_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d(%d)\n", __func__, __LINE__, p->index);
+       return vb2_qbuf(&layer->vb_queue, p);
+}
+
+static int mxr_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+       return vb2_dqbuf(&layer->vb_queue, p, file->f_flags & O_NONBLOCK);
+}
+
+static int mxr_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+       return vb2_streamon(&layer->vb_queue, i);
+}
+
+static int mxr_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+       return vb2_streamoff(&layer->vb_queue, i);
+}
+
+static const struct v4l2_ioctl_ops mxr_ioctl_ops = {
+       .vidioc_querycap = mxr_querycap,
+       /* format handling */
+       .vidioc_enum_fmt_vid_out = mxr_enum_fmt,
+       .vidioc_s_fmt_vid_out_mplane = mxr_s_fmt,
+       .vidioc_g_fmt_vid_out_mplane = mxr_g_fmt,
+       /* buffer control */
+       .vidioc_reqbufs = mxr_reqbufs,
+       .vidioc_querybuf = mxr_querybuf,
+       .vidioc_qbuf = mxr_qbuf,
+       .vidioc_dqbuf = mxr_dqbuf,
+       /* Streaming control */
+       .vidioc_streamon = mxr_streamon,
+       .vidioc_streamoff = mxr_streamoff,
+       /* Preset functions */
+       .vidioc_enum_dv_presets = mxr_enum_dv_presets,
+       .vidioc_s_dv_preset = mxr_s_dv_preset,
+       .vidioc_g_dv_preset = mxr_g_dv_preset,
+       /* analog TV standard functions */
+       .vidioc_s_std = mxr_s_std,
+       .vidioc_g_std = mxr_g_std,
+       /* Output handling */
+       .vidioc_enum_output = mxr_enum_output,
+       .vidioc_s_output = mxr_s_output,
+       .vidioc_g_output = mxr_g_output,
+       /* Crop ioctls */
+       .vidioc_g_crop = mxr_g_crop,
+       .vidioc_s_crop = mxr_s_crop,
+       .vidioc_cropcap = mxr_cropcap,
+};
+
+static int mxr_video_open(struct file *file)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       int ret = 0;
+
+       mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__);
+       /* assure device probe is finished */
+       wait_for_device_probe();
+       /* creating context for file descriptor */
+       ret = v4l2_fh_open(file);
+       if (ret) {
+               mxr_err(mdev, "v4l2_fh_open failed\n");
+               return ret;
+       }
+
+       /* leaving if layer is already initialized */
+       if (!v4l2_fh_is_singular_file(file))
+               return 0;
+
+       /* FIXME: should power be enabled on open? */
+       ret = mxr_power_get(mdev);
+       if (ret) {
+               mxr_err(mdev, "power on failed\n");
+               goto fail_fh_open;
+       }
+
+       ret = vb2_queue_init(&layer->vb_queue);
+       if (ret != 0) {
+               mxr_err(mdev, "failed to initialize vb2 queue\n");
+               goto fail_power;
+       }
+       /* set default format, first on the list */
+       layer->fmt = layer->fmt_array[0];
+       /* setup default geometry */
+       mxr_layer_default_geo(layer);
+
+       return 0;
+
+fail_power:
+       mxr_power_put(mdev);
+
+fail_fh_open:
+       v4l2_fh_release(file);
+
+       return ret;
+}
+
+static unsigned int
+mxr_video_poll(struct file *file, struct poll_table_struct *wait)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+       return vb2_poll(&layer->vb_queue, file, wait);
+}
+
+static int mxr_video_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+       return vb2_mmap(&layer->vb_queue, vma);
+}
+
+static int mxr_video_release(struct file *file)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+       if (v4l2_fh_is_singular_file(file)) {
+               vb2_queue_release(&layer->vb_queue);
+               mxr_power_put(layer->mdev);
+       }
+       v4l2_fh_release(file);
+       return 0;
+}
+
+static const struct v4l2_file_operations mxr_fops = {
+       .owner = THIS_MODULE,
+       .open = mxr_video_open,
+       .poll = mxr_video_poll,
+       .mmap = mxr_video_mmap,
+       .release = mxr_video_release,
+       .unlocked_ioctl = video_ioctl2,
+};
+
+static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
+       unsigned int *nplanes, unsigned long sizes[],
+       void *alloc_ctxs[])
+{
+       struct mxr_layer *layer = vb2_get_drv_priv(vq);
+       const struct mxr_format *fmt = layer->fmt;
+       int i;
+       struct mxr_device *mdev = layer->mdev;
+       struct v4l2_plane_pix_format planes[3];
+
+       mxr_dbg(mdev, "%s\n", __func__);
+       /* checking if format was configured */
+       if (fmt == NULL)
+               return -EINVAL;
+       mxr_dbg(mdev, "fmt = %s\n", fmt->name);
+       mxr_mplane_fill(planes, fmt, layer->geo.src.full_width,
+               layer->geo.src.full_height);
+
+       *nplanes = fmt->num_subframes;
+       for (i = 0; i < fmt->num_subframes; ++i) {
+               alloc_ctxs[i] = layer->mdev->alloc_ctx;
+               sizes[i] = PAGE_ALIGN(planes[i].sizeimage);
+               mxr_dbg(mdev, "size[%d] = %08lx\n", i, sizes[i]);
+       }
+
+       if (*nbuffers == 0)
+               *nbuffers = 1;
+
+       return 0;
+}
+
+static void buf_queue(struct vb2_buffer *vb)
+{
+       struct mxr_buffer *buffer = container_of(vb, struct mxr_buffer, vb);
+       struct mxr_layer *layer = vb2_get_drv_priv(vb->vb2_queue);
+       struct mxr_device *mdev = layer->mdev;
+       unsigned long flags;
+       int must_start = 0;
+
+       spin_lock_irqsave(&layer->enq_slock, flags);
+       if (layer->state == MXR_LAYER_STREAMING_START) {
+               layer->state = MXR_LAYER_STREAMING;
+               must_start = 1;
+       }
+       list_add_tail(&buffer->list, &layer->enq_list);
+       spin_unlock_irqrestore(&layer->enq_slock, flags);
+       if (must_start) {
+               layer->ops.stream_set(layer, MXR_ENABLE);
+               mxr_streamer_get(mdev);
+       }
+
+       mxr_dbg(mdev, "queuing buffer\n");
+}
+
+static void wait_lock(struct vb2_queue *vq)
+{
+       struct mxr_layer *layer = vb2_get_drv_priv(vq);
+
+       mxr_dbg(layer->mdev, "%s\n", __func__);
+       mutex_lock(&layer->mutex);
+}
+
+static void wait_unlock(struct vb2_queue *vq)
+{
+       struct mxr_layer *layer = vb2_get_drv_priv(vq);
+
+       mxr_dbg(layer->mdev, "%s\n", __func__);
+       mutex_unlock(&layer->mutex);
+}
+
+static int start_streaming(struct vb2_queue *vq)
+{
+       struct mxr_layer *layer = vb2_get_drv_priv(vq);
+       struct mxr_device *mdev = layer->mdev;
+       unsigned long flags;
+
+       mxr_dbg(mdev, "%s\n", __func__);
+       /* block any changes in output configuration */
+       mxr_output_get(mdev);
+
+       /* update layers geometry */
+       mxr_layer_geo_fix(layer);
+       mxr_geometry_dump(mdev, &layer->geo);
+
+       layer->ops.format_set(layer);
+       /* enabling layer in hardware */
+       spin_lock_irqsave(&layer->enq_slock, flags);
+       layer->state = MXR_LAYER_STREAMING_START;
+       spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+       return 0;
+}
+
+static void mxr_watchdog(unsigned long arg)
+{
+       struct mxr_layer *layer = (struct mxr_layer *) arg;
+       struct mxr_device *mdev = layer->mdev;
+       unsigned long flags;
+
+       mxr_err(mdev, "watchdog fired for layer %s\n", layer->vfd.name);
+
+       spin_lock_irqsave(&layer->enq_slock, flags);
+
+       if (layer->update_buf == layer->shadow_buf)
+               layer->update_buf = NULL;
+       if (layer->update_buf) {
+               vb2_buffer_done(&layer->update_buf->vb, VB2_BUF_STATE_ERROR);
+               layer->update_buf = NULL;
+       }
+       if (layer->shadow_buf) {
+               vb2_buffer_done(&layer->shadow_buf->vb, VB2_BUF_STATE_ERROR);
+               layer->shadow_buf = NULL;
+       }
+       spin_unlock_irqrestore(&layer->enq_slock, flags);
+}
+
+static int stop_streaming(struct vb2_queue *vq)
+{
+       struct mxr_layer *layer = vb2_get_drv_priv(vq);
+       struct mxr_device *mdev = layer->mdev;
+       unsigned long flags;
+       struct timer_list watchdog;
+       struct mxr_buffer *buf, *buf_tmp;
+
+       mxr_dbg(mdev, "%s\n", __func__);
+
+       spin_lock_irqsave(&layer->enq_slock, flags);
+
+       /* reset list */
+       layer->state = MXR_LAYER_STREAMING_FINISH;
+
+       /* set all buffer to be done */
+       list_for_each_entry_safe(buf, buf_tmp, &layer->enq_list, list) {
+               list_del(&buf->list);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+       }
+
+       spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+       /* give 1 seconds to complete to complete last buffers */
+       setup_timer_on_stack(&watchdog, mxr_watchdog,
+               (unsigned long)layer);
+       mod_timer(&watchdog, jiffies + msecs_to_jiffies(1000));
+
+       /* wait until all buffers are goes to done state */
+       vb2_wait_for_all_buffers(vq);
+
+       /* stop timer if all synchronization is done */
+       del_timer_sync(&watchdog);
+       destroy_timer_on_stack(&watchdog);
+
+       /* stopping hardware */
+       spin_lock_irqsave(&layer->enq_slock, flags);
+       layer->state = MXR_LAYER_IDLE;
+       spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+       /* disabling layer in hardware */
+       layer->ops.stream_set(layer, MXR_DISABLE);
+       /* remove one streamer */
+       mxr_streamer_put(mdev);
+       /* allow changes in output configuration */
+       mxr_output_put(mdev);
+       return 0;
+}
+
+static struct vb2_ops mxr_video_qops = {
+       .queue_setup = queue_setup,
+       .buf_queue = buf_queue,
+       .wait_prepare = wait_unlock,
+       .wait_finish = wait_lock,
+       .start_streaming = start_streaming,
+       .stop_streaming = stop_streaming,
+};
+
+/* FIXME: try to put this functions to mxr_base_layer_create */
+int mxr_base_layer_register(struct mxr_layer *layer)
+{
+       struct mxr_device *mdev = layer->mdev;
+       int ret;
+
+       ret = video_register_device(&layer->vfd, VFL_TYPE_GRABBER, -1);
+       if (ret)
+               mxr_err(mdev, "failed to register video device\n");
+       else
+               mxr_info(mdev, "registered layer %s as /dev/video%d\n",
+                       layer->vfd.name, layer->vfd.num);
+       return ret;
+}
+
+void mxr_base_layer_unregister(struct mxr_layer *layer)
+{
+       video_unregister_device(&layer->vfd);
+}
+
+void mxr_layer_release(struct mxr_layer *layer)
+{
+       if (layer->ops.release)
+               layer->ops.release(layer);
+}
+
+void mxr_base_layer_release(struct mxr_layer *layer)
+{
+       kfree(layer);
+}
+
+static void mxr_vfd_release(struct video_device *vdev)
+{
+       printk(KERN_INFO "video device release\n");
+}
+
+struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
+       int idx, char *name, struct mxr_layer_ops *ops)
+{
+       struct mxr_layer *layer;
+
+       layer = kzalloc(sizeof *layer, GFP_KERNEL);
+       if (layer == NULL) {
+               mxr_err(mdev, "not enough memory for layer.\n");
+               goto fail;
+       }
+
+       layer->mdev = mdev;
+       layer->idx = idx;
+       layer->ops = *ops;
+
+       spin_lock_init(&layer->enq_slock);
+       INIT_LIST_HEAD(&layer->enq_list);
+       mutex_init(&layer->mutex);
+
+       layer->vfd = (struct video_device) {
+               .minor = -1,
+               .release = mxr_vfd_release,
+               .fops = &mxr_fops,
+               .ioctl_ops = &mxr_ioctl_ops,
+       };
+       strlcpy(layer->vfd.name, name, sizeof(layer->vfd.name));
+       /* let framework control PRIORITY */
+       set_bit(V4L2_FL_USE_FH_PRIO, &layer->vfd.flags);
+
+       video_set_drvdata(&layer->vfd, layer);
+       layer->vfd.lock = &layer->mutex;
+       layer->vfd.v4l2_dev = &mdev->v4l2_dev;
+
+       layer->vb_queue = (struct vb2_queue) {
+               .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+               .io_modes = VB2_MMAP | VB2_USERPTR,
+               .drv_priv = layer,
+               .buf_struct_size = sizeof(struct mxr_buffer),
+               .ops = &mxr_video_qops,
+               .mem_ops = &vb2_dma_contig_memops,
+       };
+
+       return layer;
+
+fail:
+       return NULL;
+}
+
+static const struct mxr_format *find_format_by_fourcc(
+       struct mxr_layer *layer, unsigned long fourcc)
+{
+       int i;
+
+       for (i = 0; i < layer->fmt_array_size; ++i)
+               if (layer->fmt_array[i]->fourcc == fourcc)
+                       return layer->fmt_array[i];
+       return NULL;
+}
+
+static const struct mxr_format *find_format_by_index(
+       struct mxr_layer *layer, unsigned long index)
+{
+       if (index >= layer->fmt_array_size)
+               return NULL;
+       return layer->fmt_array[index];
+}
+
diff --git a/drivers/media/video/s5p-tv/mixer_vp_layer.c b/drivers/media/video/s5p-tv/mixer_vp_layer.c
new file mode 100644 (file)
index 0000000..6950ed8
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "mixer.h"
+
+#include "regs-vp.h"
+
+#include <media/videobuf2-dma-contig.h>
+
+/* FORMAT DEFINITIONS */
+static const struct mxr_format mxr_fmt_nv12 = {
+       .name = "NV12",
+       .fourcc = V4L2_PIX_FMT_NV12,
+       .colorspace = V4L2_COLORSPACE_JPEG,
+       .num_planes = 2,
+       .plane = {
+               { .width = 1, .height = 1, .size = 1 },
+               { .width = 2, .height = 2, .size = 2 },
+       },
+       .num_subframes = 1,
+       .cookie = VP_MODE_NV12 | VP_MODE_MEM_LINEAR,
+};
+
+static const struct mxr_format mxr_fmt_nv21 = {
+       .name = "NV21",
+       .fourcc = V4L2_PIX_FMT_NV21,
+       .colorspace = V4L2_COLORSPACE_JPEG,
+       .num_planes = 2,
+       .plane = {
+               { .width = 1, .height = 1, .size = 1 },
+               { .width = 2, .height = 2, .size = 2 },
+       },
+       .num_subframes = 1,
+       .cookie = VP_MODE_NV21 | VP_MODE_MEM_LINEAR,
+};
+
+static const struct mxr_format mxr_fmt_nv12m = {
+       .name = "NV12 (mplane)",
+       .fourcc = V4L2_PIX_FMT_NV12M,
+       .colorspace = V4L2_COLORSPACE_JPEG,
+       .num_planes = 2,
+       .plane = {
+               { .width = 1, .height = 1, .size = 1 },
+               { .width = 2, .height = 2, .size = 2 },
+       },
+       .num_subframes = 2,
+       .plane2subframe = {0, 1},
+       .cookie = VP_MODE_NV12 | VP_MODE_MEM_LINEAR,
+};
+
+static const struct mxr_format mxr_fmt_nv12mt = {
+       .name = "NV12 tiled (mplane)",
+       .fourcc = V4L2_PIX_FMT_NV12MT,
+       .colorspace = V4L2_COLORSPACE_JPEG,
+       .num_planes = 2,
+       .plane = {
+               { .width = 128, .height = 32, .size = 4096 },
+               { .width = 128, .height = 32, .size = 2048 },
+       },
+       .num_subframes = 2,
+       .plane2subframe = {0, 1},
+       .cookie = VP_MODE_NV12 | VP_MODE_MEM_TILED,
+};
+
+static const struct mxr_format *mxr_video_format[] = {
+       &mxr_fmt_nv12,
+       &mxr_fmt_nv21,
+       &mxr_fmt_nv12m,
+       &mxr_fmt_nv12mt,
+};
+
+/* AUXILIARY CALLBACKS */
+
+static void mxr_vp_layer_release(struct mxr_layer *layer)
+{
+       mxr_base_layer_unregister(layer);
+       mxr_base_layer_release(layer);
+}
+
+static void mxr_vp_buffer_set(struct mxr_layer *layer,
+       struct mxr_buffer *buf)
+{
+       dma_addr_t luma_addr[2] = {0, 0};
+       dma_addr_t chroma_addr[2] = {0, 0};
+
+       if (buf == NULL) {
+               mxr_reg_vp_buffer(layer->mdev, luma_addr, chroma_addr);
+               return;
+       }
+       luma_addr[0] = vb2_dma_contig_plane_paddr(&buf->vb, 0);
+       if (layer->fmt->num_subframes == 2) {
+               chroma_addr[0] = vb2_dma_contig_plane_paddr(&buf->vb, 1);
+       } else {
+               /* FIXME: mxr_get_plane_size compute integer division,
+                * which is slow and should not be performed in interrupt */
+               chroma_addr[0] = luma_addr[0] + mxr_get_plane_size(
+                       &layer->fmt->plane[0], layer->geo.src.full_width,
+                       layer->geo.src.full_height);
+       }
+       if (layer->fmt->cookie & VP_MODE_MEM_TILED) {
+               luma_addr[1] = luma_addr[0] + 0x40;
+               chroma_addr[1] = chroma_addr[0] + 0x40;
+       } else {
+               luma_addr[1] = luma_addr[0] + layer->geo.src.full_width;
+               chroma_addr[1] = chroma_addr[0];
+       }
+       mxr_reg_vp_buffer(layer->mdev, luma_addr, chroma_addr);
+}
+
+static void mxr_vp_stream_set(struct mxr_layer *layer, int en)
+{
+       mxr_reg_vp_layer_stream(layer->mdev, en);
+}
+
+static void mxr_vp_format_set(struct mxr_layer *layer)
+{
+       mxr_reg_vp_format(layer->mdev, layer->fmt, &layer->geo);
+}
+
+static void mxr_vp_fix_geometry(struct mxr_layer *layer)
+{
+       struct mxr_geometry *geo = &layer->geo;
+
+       /* align horizontal size to 8 pixels */
+       geo->src.full_width = ALIGN(geo->src.full_width, 8);
+       /* limit to boundary size */
+       geo->src.full_width = clamp_val(geo->src.full_width, 8, 8192);
+       geo->src.full_height = clamp_val(geo->src.full_height, 1, 8192);
+       geo->src.width = clamp_val(geo->src.width, 32, geo->src.full_width);
+       geo->src.width = min(geo->src.width, 2047U);
+       geo->src.height = clamp_val(geo->src.height, 4, geo->src.full_height);
+       geo->src.height = min(geo->src.height, 2047U);
+
+       /* setting size of output window */
+       geo->dst.width = clamp_val(geo->dst.width, 8, geo->dst.full_width);
+       geo->dst.height = clamp_val(geo->dst.height, 1, geo->dst.full_height);
+
+       /* ensure that scaling is in range 1/4x to 16x */
+       if (geo->src.width >= 4 * geo->dst.width)
+               geo->src.width = 4 * geo->dst.width;
+       if (geo->dst.width >= 16 * geo->src.width)
+               geo->dst.width = 16 * geo->src.width;
+       if (geo->src.height >= 4 * geo->dst.height)
+               geo->src.height = 4 * geo->dst.height;
+       if (geo->dst.height >= 16 * geo->src.height)
+               geo->dst.height = 16 * geo->src.height;
+
+       /* setting scaling ratio */
+       geo->x_ratio = (geo->src.width << 16) / geo->dst.width;
+       geo->y_ratio = (geo->src.height << 16) / geo->dst.height;
+
+       /* adjust offsets */
+       geo->src.x_offset = min(geo->src.x_offset,
+               geo->src.full_width - geo->src.width);
+       geo->src.y_offset = min(geo->src.y_offset,
+               geo->src.full_height - geo->src.height);
+       geo->dst.x_offset = min(geo->dst.x_offset,
+               geo->dst.full_width - geo->dst.width);
+       geo->dst.y_offset = min(geo->dst.y_offset,
+               geo->dst.full_height - geo->dst.height);
+}
+
+/* PUBLIC API */
+
+struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx)
+{
+       struct mxr_layer *layer;
+       int ret;
+       struct mxr_layer_ops ops = {
+               .release = mxr_vp_layer_release,
+               .buffer_set = mxr_vp_buffer_set,
+               .stream_set = mxr_vp_stream_set,
+               .format_set = mxr_vp_format_set,
+               .fix_geometry = mxr_vp_fix_geometry,
+       };
+       char name[32];
+
+       sprintf(name, "video%d", idx);
+
+       layer = mxr_base_layer_create(mdev, idx, name, &ops);
+       if (layer == NULL) {
+               mxr_err(mdev, "failed to initialize layer(%d) base\n", idx);
+               goto fail;
+       }
+
+       layer->fmt_array = mxr_video_format;
+       layer->fmt_array_size = ARRAY_SIZE(mxr_video_format);
+
+       ret = mxr_base_layer_register(layer);
+       if (ret)
+               goto fail_layer;
+
+       return layer;
+
+fail_layer:
+       mxr_base_layer_release(layer);
+
+fail:
+       return NULL;
+}
+
diff --git a/drivers/media/video/s5p-tv/regs-hdmi.h b/drivers/media/video/s5p-tv/regs-hdmi.h
new file mode 100644 (file)
index 0000000..ac93ad6
--- /dev/null
@@ -0,0 +1,141 @@
+/* linux/arch/arm/mach-exynos4/include/mach/regs-hdmi.h
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * HDMI register header file for Samsung TVOUT driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef SAMSUNG_REGS_HDMI_H
+#define SAMSUNG_REGS_HDMI_H
+
+/*
+ * Register part
+*/
+
+#define HDMI_CTRL_BASE(x)              ((x) + 0x00000000)
+#define HDMI_CORE_BASE(x)              ((x) + 0x00010000)
+#define HDMI_TG_BASE(x)                        ((x) + 0x00050000)
+
+/* Control registers */
+#define HDMI_INTC_CON                  HDMI_CTRL_BASE(0x0000)
+#define HDMI_INTC_FLAG                 HDMI_CTRL_BASE(0x0004)
+#define HDMI_HPD_STATUS                        HDMI_CTRL_BASE(0x000C)
+#define HDMI_PHY_RSTOUT                        HDMI_CTRL_BASE(0x0014)
+#define HDMI_PHY_VPLL                  HDMI_CTRL_BASE(0x0018)
+#define HDMI_PHY_CMU                   HDMI_CTRL_BASE(0x001C)
+#define HDMI_CORE_RSTOUT               HDMI_CTRL_BASE(0x0020)
+
+/* Core registers */
+#define HDMI_CON_0                     HDMI_CORE_BASE(0x0000)
+#define HDMI_CON_1                     HDMI_CORE_BASE(0x0004)
+#define HDMI_CON_2                     HDMI_CORE_BASE(0x0008)
+#define HDMI_SYS_STATUS                        HDMI_CORE_BASE(0x0010)
+#define HDMI_PHY_STATUS                        HDMI_CORE_BASE(0x0014)
+#define HDMI_STATUS_EN                 HDMI_CORE_BASE(0x0020)
+#define HDMI_HPD                       HDMI_CORE_BASE(0x0030)
+#define HDMI_MODE_SEL                  HDMI_CORE_BASE(0x0040)
+#define HDMI_BLUE_SCREEN_0             HDMI_CORE_BASE(0x0050)
+#define HDMI_BLUE_SCREEN_1             HDMI_CORE_BASE(0x0054)
+#define HDMI_BLUE_SCREEN_2             HDMI_CORE_BASE(0x0058)
+#define HDMI_H_BLANK_0                 HDMI_CORE_BASE(0x00A0)
+#define HDMI_H_BLANK_1                 HDMI_CORE_BASE(0x00A4)
+#define HDMI_V_BLANK_0                 HDMI_CORE_BASE(0x00B0)
+#define HDMI_V_BLANK_1                 HDMI_CORE_BASE(0x00B4)
+#define HDMI_V_BLANK_2                 HDMI_CORE_BASE(0x00B8)
+#define HDMI_H_V_LINE_0                        HDMI_CORE_BASE(0x00C0)
+#define HDMI_H_V_LINE_1                        HDMI_CORE_BASE(0x00C4)
+#define HDMI_H_V_LINE_2                        HDMI_CORE_BASE(0x00C8)
+#define HDMI_VSYNC_POL                 HDMI_CORE_BASE(0x00E4)
+#define HDMI_INT_PRO_MODE              HDMI_CORE_BASE(0x00E8)
+#define HDMI_V_BLANK_F_0               HDMI_CORE_BASE(0x0110)
+#define HDMI_V_BLANK_F_1               HDMI_CORE_BASE(0x0114)
+#define HDMI_V_BLANK_F_2               HDMI_CORE_BASE(0x0118)
+#define HDMI_H_SYNC_GEN_0              HDMI_CORE_BASE(0x0120)
+#define HDMI_H_SYNC_GEN_1              HDMI_CORE_BASE(0x0124)
+#define HDMI_H_SYNC_GEN_2              HDMI_CORE_BASE(0x0128)
+#define HDMI_V_SYNC_GEN_1_0            HDMI_CORE_BASE(0x0130)
+#define HDMI_V_SYNC_GEN_1_1            HDMI_CORE_BASE(0x0134)
+#define HDMI_V_SYNC_GEN_1_2            HDMI_CORE_BASE(0x0138)
+#define HDMI_V_SYNC_GEN_2_0            HDMI_CORE_BASE(0x0140)
+#define HDMI_V_SYNC_GEN_2_1            HDMI_CORE_BASE(0x0144)
+#define HDMI_V_SYNC_GEN_2_2            HDMI_CORE_BASE(0x0148)
+#define HDMI_V_SYNC_GEN_3_0            HDMI_CORE_BASE(0x0150)
+#define HDMI_V_SYNC_GEN_3_1            HDMI_CORE_BASE(0x0154)
+#define HDMI_V_SYNC_GEN_3_2            HDMI_CORE_BASE(0x0158)
+#define HDMI_AVI_CON                   HDMI_CORE_BASE(0x0300)
+#define HDMI_AVI_BYTE(n)               HDMI_CORE_BASE(0x0320 + 4 * (n))
+#define        HDMI_DC_CONTROL                 HDMI_CORE_BASE(0x05C0)
+#define HDMI_VIDEO_PATTERN_GEN         HDMI_CORE_BASE(0x05C4)
+#define HDMI_HPD_GEN                   HDMI_CORE_BASE(0x05C8)
+
+/* Timing generator registers */
+#define HDMI_TG_CMD                    HDMI_TG_BASE(0x0000)
+#define HDMI_TG_H_FSZ_L                        HDMI_TG_BASE(0x0018)
+#define HDMI_TG_H_FSZ_H                        HDMI_TG_BASE(0x001C)
+#define HDMI_TG_HACT_ST_L              HDMI_TG_BASE(0x0020)
+#define HDMI_TG_HACT_ST_H              HDMI_TG_BASE(0x0024)
+#define HDMI_TG_HACT_SZ_L              HDMI_TG_BASE(0x0028)
+#define HDMI_TG_HACT_SZ_H              HDMI_TG_BASE(0x002C)
+#define HDMI_TG_V_FSZ_L                        HDMI_TG_BASE(0x0030)
+#define HDMI_TG_V_FSZ_H                        HDMI_TG_BASE(0x0034)
+#define HDMI_TG_VSYNC_L                        HDMI_TG_BASE(0x0038)
+#define HDMI_TG_VSYNC_H                        HDMI_TG_BASE(0x003C)
+#define HDMI_TG_VSYNC2_L               HDMI_TG_BASE(0x0040)
+#define HDMI_TG_VSYNC2_H               HDMI_TG_BASE(0x0044)
+#define HDMI_TG_VACT_ST_L              HDMI_TG_BASE(0x0048)
+#define HDMI_TG_VACT_ST_H              HDMI_TG_BASE(0x004C)
+#define HDMI_TG_VACT_SZ_L              HDMI_TG_BASE(0x0050)
+#define HDMI_TG_VACT_SZ_H              HDMI_TG_BASE(0x0054)
+#define HDMI_TG_FIELD_CHG_L            HDMI_TG_BASE(0x0058)
+#define HDMI_TG_FIELD_CHG_H            HDMI_TG_BASE(0x005C)
+#define HDMI_TG_VACT_ST2_L             HDMI_TG_BASE(0x0060)
+#define HDMI_TG_VACT_ST2_H             HDMI_TG_BASE(0x0064)
+#define HDMI_TG_VSYNC_TOP_HDMI_L       HDMI_TG_BASE(0x0078)
+#define HDMI_TG_VSYNC_TOP_HDMI_H       HDMI_TG_BASE(0x007C)
+#define HDMI_TG_VSYNC_BOT_HDMI_L       HDMI_TG_BASE(0x0080)
+#define HDMI_TG_VSYNC_BOT_HDMI_H       HDMI_TG_BASE(0x0084)
+#define HDMI_TG_FIELD_TOP_HDMI_L       HDMI_TG_BASE(0x0088)
+#define HDMI_TG_FIELD_TOP_HDMI_H       HDMI_TG_BASE(0x008C)
+#define HDMI_TG_FIELD_BOT_HDMI_L       HDMI_TG_BASE(0x0090)
+#define HDMI_TG_FIELD_BOT_HDMI_H       HDMI_TG_BASE(0x0094)
+
+/*
+ * Bit definition part
+ */
+
+/* HDMI_INTC_CON */
+#define HDMI_INTC_EN_GLOBAL            (1 << 6)
+#define HDMI_INTC_EN_HPD_PLUG          (1 << 3)
+#define HDMI_INTC_EN_HPD_UNPLUG                (1 << 2)
+
+/* HDMI_INTC_FLAG */
+#define HDMI_INTC_FLAG_HPD_PLUG                (1 << 3)
+#define HDMI_INTC_FLAG_HPD_UNPLUG      (1 << 2)
+
+/* HDMI_PHY_RSTOUT */
+#define HDMI_PHY_SW_RSTOUT             (1 << 0)
+
+/* HDMI_CORE_RSTOUT */
+#define HDMI_CORE_SW_RSTOUT            (1 << 0)
+
+/* HDMI_CON_0 */
+#define HDMI_BLUE_SCR_EN               (1 << 5)
+#define HDMI_EN                                (1 << 0)
+
+/* HDMI_PHY_STATUS */
+#define HDMI_PHY_STATUS_READY          (1 << 0)
+
+/* HDMI_MODE_SEL */
+#define HDMI_MODE_HDMI_EN              (1 << 1)
+#define HDMI_MODE_DVI_EN               (1 << 0)
+#define HDMI_MODE_MASK                 (3 << 0)
+
+/* HDMI_TG_CMD */
+#define HDMI_TG_EN                     (1 << 0)
+
+#endif /* SAMSUNG_REGS_HDMI_H */
diff --git a/drivers/media/video/s5p-tv/regs-mixer.h b/drivers/media/video/s5p-tv/regs-mixer.h
new file mode 100644 (file)
index 0000000..3c84426
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Mixer register header file for Samsung Mixer driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+#ifndef SAMSUNG_REGS_MIXER_H
+#define SAMSUNG_REGS_MIXER_H
+
+/*
+ * Register part
+ */
+#define MXR_STATUS                     0x0000
+#define MXR_CFG                                0x0004
+#define MXR_INT_EN                     0x0008
+#define MXR_INT_STATUS                 0x000C
+#define MXR_LAYER_CFG                  0x0010
+#define MXR_VIDEO_CFG                  0x0014
+#define MXR_GRAPHIC0_CFG               0x0020
+#define MXR_GRAPHIC0_BASE              0x0024
+#define MXR_GRAPHIC0_SPAN              0x0028
+#define MXR_GRAPHIC0_SXY               0x002C
+#define MXR_GRAPHIC0_WH                        0x0030
+#define MXR_GRAPHIC0_DXY               0x0034
+#define MXR_GRAPHIC0_BLANK             0x0038
+#define MXR_GRAPHIC1_CFG               0x0040
+#define MXR_GRAPHIC1_BASE              0x0044
+#define MXR_GRAPHIC1_SPAN              0x0048
+#define MXR_GRAPHIC1_SXY               0x004C
+#define MXR_GRAPHIC1_WH                        0x0050
+#define MXR_GRAPHIC1_DXY               0x0054
+#define MXR_GRAPHIC1_BLANK             0x0058
+#define MXR_BG_CFG                     0x0060
+#define MXR_BG_COLOR0                  0x0064
+#define MXR_BG_COLOR1                  0x0068
+#define MXR_BG_COLOR2                  0x006C
+
+/* for parametrized access to layer registers */
+#define MXR_GRAPHIC_CFG(i)             (0x0020 + (i) * 0x20)
+#define MXR_GRAPHIC_BASE(i)            (0x0024 + (i) * 0x20)
+#define MXR_GRAPHIC_SPAN(i)            (0x0028 + (i) * 0x20)
+#define MXR_GRAPHIC_SXY(i)             (0x002C + (i) * 0x20)
+#define MXR_GRAPHIC_WH(i)              (0x0030 + (i) * 0x20)
+#define MXR_GRAPHIC_DXY(i)             (0x0034 + (i) * 0x20)
+
+/*
+ * Bit definition part
+ */
+
+/* generates mask for range of bits */
+#define MXR_MASK(high_bit, low_bit) \
+       (((2 << ((high_bit) - (low_bit))) - 1) << (low_bit))
+
+#define MXR_MASK_VAL(val, high_bit, low_bit) \
+       (((val) << (low_bit)) & MXR_MASK(high_bit, low_bit))
+
+/* bits for MXR_STATUS */
+#define MXR_STATUS_16_BURST            (1 << 7)
+#define MXR_STATUS_BURST_MASK          (1 << 7)
+#define MXR_STATUS_SYNC_ENABLE         (1 << 2)
+#define MXR_STATUS_REG_RUN             (1 << 0)
+
+/* bits for MXR_CFG */
+#define MXR_CFG_OUT_YUV444             (0 << 8)
+#define MXR_CFG_OUT_RGB888             (1 << 8)
+#define MXR_CFG_DST_SDO                        (0 << 7)
+#define MXR_CFG_DST_HDMI               (1 << 7)
+#define MXR_CFG_DST_MASK               (1 << 7)
+#define MXR_CFG_SCAN_HD_720            (0 << 6)
+#define MXR_CFG_SCAN_HD_1080           (1 << 6)
+#define MXR_CFG_GRP1_ENABLE            (1 << 5)
+#define MXR_CFG_GRP0_ENABLE            (1 << 4)
+#define MXR_CFG_VP_ENABLE              (1 << 3)
+#define MXR_CFG_SCAN_INTERLACE         (0 << 2)
+#define MXR_CFG_SCAN_PROGRASSIVE       (1 << 2)
+#define MXR_CFG_SCAN_NTSC              (0 << 1)
+#define MXR_CFG_SCAN_PAL               (1 << 1)
+#define MXR_CFG_SCAN_SD                        (0 << 0)
+#define MXR_CFG_SCAN_HD                        (1 << 0)
+#define MXR_CFG_SCAN_MASK              0x47
+
+/* bits for MXR_GRAPHICn_CFG */
+#define MXR_GRP_CFG_COLOR_KEY_DISABLE  (1 << 21)
+#define MXR_GRP_CFG_BLEND_PRE_MUL      (1 << 20)
+#define MXR_GRP_CFG_FORMAT_VAL(x)      MXR_MASK_VAL(x, 11, 8)
+#define MXR_GRP_CFG_FORMAT_MASK                MXR_GRP_CFG_FORMAT_VAL(~0)
+#define MXR_GRP_CFG_ALPHA_VAL(x)       MXR_MASK_VAL(x, 7, 0)
+
+/* bits for MXR_GRAPHICn_WH */
+#define MXR_GRP_WH_H_SCALE(x)          MXR_MASK_VAL(x, 28, 28)
+#define MXR_GRP_WH_V_SCALE(x)          MXR_MASK_VAL(x, 12, 12)
+#define MXR_GRP_WH_WIDTH(x)            MXR_MASK_VAL(x, 26, 16)
+#define MXR_GRP_WH_HEIGHT(x)           MXR_MASK_VAL(x, 10, 0)
+
+/* bits for MXR_GRAPHICn_SXY */
+#define MXR_GRP_SXY_SX(x)              MXR_MASK_VAL(x, 26, 16)
+#define MXR_GRP_SXY_SY(x)              MXR_MASK_VAL(x, 10, 0)
+
+/* bits for MXR_GRAPHICn_DXY */
+#define MXR_GRP_DXY_DX(x)              MXR_MASK_VAL(x, 26, 16)
+#define MXR_GRP_DXY_DY(x)              MXR_MASK_VAL(x, 10, 0)
+
+/* bits for MXR_INT_EN */
+#define MXR_INT_EN_VSYNC               (1 << 11)
+#define MXR_INT_EN_ALL                 (0x0f << 8)
+
+/* bit for MXR_INT_STATUS */
+#define MXR_INT_CLEAR_VSYNC            (1 << 11)
+#define MXR_INT_STATUS_VSYNC           (1 << 0)
+
+/* bit for MXR_LAYER_CFG */
+#define MXR_LAYER_CFG_GRP1_VAL(x)      MXR_MASK_VAL(x, 11, 8)
+#define MXR_LAYER_CFG_GRP0_VAL(x)      MXR_MASK_VAL(x, 7, 4)
+#define MXR_LAYER_CFG_VP_VAL(x)                MXR_MASK_VAL(x, 3, 0)
+
+#endif /* SAMSUNG_REGS_MIXER_H */
+
diff --git a/drivers/media/video/s5p-tv/regs-sdo.h b/drivers/media/video/s5p-tv/regs-sdo.h
new file mode 100644 (file)
index 0000000..7f7c2b8
--- /dev/null
@@ -0,0 +1,63 @@
+/* drivers/media/video/s5p-tv/regs-sdo.h
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * SDO register description file
+ *
+ * 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 SAMSUNG_REGS_SDO_H
+#define SAMSUNG_REGS_SDO_H
+
+/*
+ * Register part
+ */
+
+#define SDO_CLKCON                     0x0000
+#define SDO_CONFIG                     0x0008
+#define SDO_VBI                                0x0014
+#define SDO_DAC                                0x003C
+#define SDO_CCCON                      0x0180
+#define SDO_IRQ                                0x0280
+#define SDO_IRQMASK                    0x0284
+#define SDO_VERSION                    0x03D8
+
+/*
+ * Bit definition part
+ */
+
+/* SDO Clock Control Register (SDO_CLKCON) */
+#define SDO_TVOUT_SW_RESET             (1 << 4)
+#define SDO_TVOUT_CLOCK_READY          (1 << 1)
+#define SDO_TVOUT_CLOCK_ON             (1 << 0)
+
+/* SDO Video Standard Configuration Register (SDO_CONFIG) */
+#define SDO_PROGRESSIVE                        (1 << 4)
+#define SDO_NTSC_M                     0
+#define SDO_PAL_M                      1
+#define SDO_PAL_BGHID                  2
+#define SDO_PAL_N                      3
+#define SDO_PAL_NC                     4
+#define SDO_NTSC_443                   8
+#define SDO_PAL_60                     9
+#define SDO_STANDARD_MASK              0xf
+
+/* SDO VBI Configuration Register (SDO_VBI) */
+#define SDO_CVBS_WSS_INS               (1 << 14)
+#define SDO_CVBS_CLOSED_CAPTION_MASK   (3 << 12)
+
+/* SDO DAC Configuration Register (SDO_DAC) */
+#define SDO_POWER_ON_DAC               (1 << 0)
+
+/* SDO Color Compensation On/Off Control (SDO_CCCON) */
+#define SDO_COMPENSATION_BHS_ADJ_OFF   (1 << 4)
+#define SDO_COMPENSATION_CVBS_COMP_OFF (1 << 0)
+
+/* SDO Interrupt Request Register (SDO_IRQ) */
+#define SDO_VSYNC_IRQ_PEND             (1 << 0)
+
+#endif /* SAMSUNG_REGS_SDO_H */
diff --git a/drivers/media/video/s5p-tv/regs-vp.h b/drivers/media/video/s5p-tv/regs-vp.h
new file mode 100644 (file)
index 0000000..6c63984
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * Video processor register header file for Samsung Mixer driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef SAMSUNG_REGS_VP_H
+#define SAMSUNG_REGS_VP_H
+
+/*
+ * Register part
+ */
+
+#define VP_ENABLE                      0x0000
+#define VP_SRESET                      0x0004
+#define VP_SHADOW_UPDATE               0x0008
+#define VP_FIELD_ID                    0x000C
+#define VP_MODE                                0x0010
+#define VP_IMG_SIZE_Y                  0x0014
+#define VP_IMG_SIZE_C                  0x0018
+#define VP_PER_RATE_CTRL               0x001C
+#define VP_TOP_Y_PTR                   0x0028
+#define VP_BOT_Y_PTR                   0x002C
+#define VP_TOP_C_PTR                   0x0030
+#define VP_BOT_C_PTR                   0x0034
+#define VP_ENDIAN_MODE                 0x03CC
+#define VP_SRC_H_POSITION              0x0044
+#define VP_SRC_V_POSITION              0x0048
+#define VP_SRC_WIDTH                   0x004C
+#define VP_SRC_HEIGHT                  0x0050
+#define VP_DST_H_POSITION              0x0054
+#define VP_DST_V_POSITION              0x0058
+#define VP_DST_WIDTH                   0x005C
+#define VP_DST_HEIGHT                  0x0060
+#define VP_H_RATIO                     0x0064
+#define VP_V_RATIO                     0x0068
+#define VP_POLY8_Y0_LL                 0x006C
+#define VP_POLY4_Y0_LL                 0x00EC
+#define VP_POLY4_C0_LL                 0x012C
+
+/*
+ * Bit definition part
+ */
+
+/* generates mask for range of bits */
+
+#define VP_MASK(high_bit, low_bit) \
+       (((2 << ((high_bit) - (low_bit))) - 1) << (low_bit))
+
+#define VP_MASK_VAL(val, high_bit, low_bit) \
+       (((val) << (low_bit)) & VP_MASK(high_bit, low_bit))
+
+ /* VP_ENABLE */
+#define VP_ENABLE_ON                   (1 << 0)
+
+/* VP_SRESET */
+#define VP_SRESET_PROCESSING           (1 << 0)
+
+/* VP_SHADOW_UPDATE */
+#define VP_SHADOW_UPDATE_ENABLE                (1 << 0)
+
+/* VP_MODE */
+#define VP_MODE_NV12                   (0 << 6)
+#define VP_MODE_NV21                   (1 << 6)
+#define VP_MODE_LINE_SKIP              (1 << 5)
+#define VP_MODE_MEM_LINEAR             (0 << 4)
+#define VP_MODE_MEM_TILED              (1 << 4)
+#define VP_MODE_FMT_MASK               (5 << 4)
+#define VP_MODE_FIELD_ID_AUTO_TOGGLING (1 << 2)
+#define VP_MODE_2D_IPC                 (1 << 1)
+
+/* VP_IMG_SIZE_Y */
+/* VP_IMG_SIZE_C */
+#define VP_IMG_HSIZE(x)                        VP_MASK_VAL(x, 29, 16)
+#define VP_IMG_VSIZE(x)                        VP_MASK_VAL(x, 13, 0)
+
+/* VP_SRC_H_POSITION */
+#define VP_SRC_H_POSITION_VAL(x)       VP_MASK_VAL(x, 14, 4)
+
+/* VP_ENDIAN_MODE */
+#define VP_ENDIAN_MODE_LITTLE          (1 << 0)
+
+#endif /* SAMSUNG_REGS_VP_H */
diff --git a/drivers/media/video/s5p-tv/sdo_drv.c b/drivers/media/video/s5p-tv/sdo_drv.c
new file mode 100644 (file)
index 0000000..4dddd6b
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+ * Samsung Standard Definition Output (SDO) driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include <media/v4l2-subdev.h>
+
+#include "regs-sdo.h"
+
+MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung Standard Definition Output (SDO)");
+MODULE_LICENSE("GPL");
+
+#define SDO_DEFAULT_STD        V4L2_STD_PAL
+
+struct sdo_format {
+       v4l2_std_id id;
+       /* all modes are 720 pixels wide */
+       unsigned int height;
+       unsigned int cookie;
+};
+
+struct sdo_device {
+       /** pointer to device parent */
+       struct device *dev;
+       /** base address of SDO registers */
+       void __iomem *regs;
+       /** SDO interrupt */
+       unsigned int irq;
+       /** DAC source clock */
+       struct clk *sclk_dac;
+       /** DAC clock */
+       struct clk *dac;
+       /** DAC physical interface */
+       struct clk *dacphy;
+       /** clock for control of VPLL */
+       struct clk *fout_vpll;
+       /** regulator for SDO IP power */
+       struct regulator *vdac;
+       /** regulator for SDO plug detection */
+       struct regulator *vdet;
+       /** subdev used as device interface */
+       struct v4l2_subdev sd;
+       /** current format */
+       const struct sdo_format *fmt;
+};
+
+static inline struct sdo_device *sd_to_sdev(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct sdo_device, sd);
+}
+
+static inline
+void sdo_write_mask(struct sdo_device *sdev, u32 reg_id, u32 value, u32 mask)
+{
+       u32 old = readl(sdev->regs + reg_id);
+       value = (value & mask) | (old & ~mask);
+       writel(value, sdev->regs + reg_id);
+}
+
+static inline
+void sdo_write(struct sdo_device *sdev, u32 reg_id, u32 value)
+{
+       writel(value, sdev->regs + reg_id);
+}
+
+static inline
+u32 sdo_read(struct sdo_device *sdev, u32 reg_id)
+{
+       return readl(sdev->regs + reg_id);
+}
+
+static irqreturn_t sdo_irq_handler(int irq, void *dev_data)
+{
+       struct sdo_device *sdev = dev_data;
+
+       /* clear interrupt */
+       sdo_write_mask(sdev, SDO_IRQ, ~0, SDO_VSYNC_IRQ_PEND);
+       return IRQ_HANDLED;
+}
+
+static void sdo_reg_debug(struct sdo_device *sdev)
+{
+#define DBGREG(reg_id) \
+       dev_info(sdev->dev, #reg_id " = %08x\n", \
+               sdo_read(sdev, reg_id))
+
+       DBGREG(SDO_CLKCON);
+       DBGREG(SDO_CONFIG);
+       DBGREG(SDO_VBI);
+       DBGREG(SDO_DAC);
+       DBGREG(SDO_IRQ);
+       DBGREG(SDO_IRQMASK);
+       DBGREG(SDO_VERSION);
+}
+
+static const struct sdo_format sdo_format[] = {
+       { V4L2_STD_PAL_N,       .height = 576, .cookie = SDO_PAL_N },
+       { V4L2_STD_PAL_Nc,      .height = 576, .cookie = SDO_PAL_NC },
+       { V4L2_STD_PAL_M,       .height = 480, .cookie = SDO_PAL_M },
+       { V4L2_STD_PAL_60,      .height = 480, .cookie = SDO_PAL_60 },
+       { V4L2_STD_NTSC_443,    .height = 480, .cookie = SDO_NTSC_443 },
+       { V4L2_STD_PAL,         .height = 576, .cookie = SDO_PAL_BGHID },
+       { V4L2_STD_NTSC_M,      .height = 480, .cookie = SDO_NTSC_M },
+};
+
+static const struct sdo_format *sdo_find_format(v4l2_std_id id)
+{
+       int i;
+       for (i = 0; i < ARRAY_SIZE(sdo_format); ++i)
+               if (sdo_format[i].id & id)
+                       return &sdo_format[i];
+       return NULL;
+}
+
+static int sdo_g_tvnorms_output(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+       *std = V4L2_STD_NTSC_M | V4L2_STD_PAL_M | V4L2_STD_PAL |
+               V4L2_STD_PAL_N | V4L2_STD_PAL_Nc |
+               V4L2_STD_NTSC_443 | V4L2_STD_PAL_60;
+       return 0;
+}
+
+static int sdo_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       struct sdo_device *sdev = sd_to_sdev(sd);
+       const struct sdo_format *fmt;
+       fmt = sdo_find_format(std);
+       if (fmt == NULL)
+               return -EINVAL;
+       sdev->fmt = fmt;
+       return 0;
+}
+
+static int sdo_g_std_output(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+       *std = sd_to_sdev(sd)->fmt->id;
+       return 0;
+}
+
+static int sdo_g_mbus_fmt(struct v4l2_subdev *sd,
+       struct v4l2_mbus_framefmt *fmt)
+{
+       struct sdo_device *sdev = sd_to_sdev(sd);
+
+       if (!sdev->fmt)
+               return -ENXIO;
+       /* all modes are 720 pixels wide */
+       fmt->width = 720;
+       fmt->height = sdev->fmt->height;
+       fmt->code = V4L2_MBUS_FMT_FIXED;
+       fmt->field = V4L2_FIELD_INTERLACED;
+       return 0;
+}
+
+static int sdo_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct sdo_device *sdev = sd_to_sdev(sd);
+       struct device *dev = sdev->dev;
+       int ret;
+
+       dev_info(dev, "sdo_s_power(%d)\n", on);
+
+       if (on)
+               ret = pm_runtime_get_sync(dev);
+       else
+               ret = pm_runtime_put_sync(dev);
+
+       /* only values < 0 indicate errors */
+       return IS_ERR_VALUE(ret) ? ret : 0;
+}
+
+static int sdo_streamon(struct sdo_device *sdev)
+{
+       /* set proper clock for Timing Generator */
+       clk_set_rate(sdev->fout_vpll, 54000000);
+       dev_info(sdev->dev, "fout_vpll.rate = %lu\n",
+       clk_get_rate(sdev->fout_vpll));
+       /* enable clock in SDO */
+       sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_CLOCK_ON);
+       clk_enable(sdev->dacphy);
+       /* enable DAC */
+       sdo_write_mask(sdev, SDO_DAC, ~0, SDO_POWER_ON_DAC);
+       sdo_reg_debug(sdev);
+       return 0;
+}
+
+static int sdo_streamoff(struct sdo_device *sdev)
+{
+       int tries;
+
+       sdo_write_mask(sdev, SDO_DAC, 0, SDO_POWER_ON_DAC);
+       clk_disable(sdev->dacphy);
+       sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_CLOCK_ON);
+       for (tries = 100; tries; --tries) {
+               if (sdo_read(sdev, SDO_CLKCON) & SDO_TVOUT_CLOCK_READY)
+                       break;
+               mdelay(1);
+       }
+       if (tries == 0)
+               dev_err(sdev->dev, "failed to stop streaming\n");
+       return tries ? 0 : -EIO;
+}
+
+static int sdo_s_stream(struct v4l2_subdev *sd, int on)
+{
+       struct sdo_device *sdev = sd_to_sdev(sd);
+       return on ? sdo_streamon(sdev) : sdo_streamoff(sdev);
+}
+
+static const struct v4l2_subdev_core_ops sdo_sd_core_ops = {
+       .s_power = sdo_s_power,
+};
+
+static const struct v4l2_subdev_video_ops sdo_sd_video_ops = {
+       .s_std_output = sdo_s_std_output,
+       .g_std_output = sdo_g_std_output,
+       .g_tvnorms_output = sdo_g_tvnorms_output,
+       .g_mbus_fmt = sdo_g_mbus_fmt,
+       .s_stream = sdo_s_stream,
+};
+
+static const struct v4l2_subdev_ops sdo_sd_ops = {
+       .core = &sdo_sd_core_ops,
+       .video = &sdo_sd_video_ops,
+};
+
+static int sdo_runtime_suspend(struct device *dev)
+{
+       struct v4l2_subdev *sd = dev_get_drvdata(dev);
+       struct sdo_device *sdev = sd_to_sdev(sd);
+
+       dev_info(dev, "suspend\n");
+       regulator_disable(sdev->vdet);
+       regulator_disable(sdev->vdac);
+       clk_disable(sdev->sclk_dac);
+       return 0;
+}
+
+static int sdo_runtime_resume(struct device *dev)
+{
+       struct v4l2_subdev *sd = dev_get_drvdata(dev);
+       struct sdo_device *sdev = sd_to_sdev(sd);
+
+       dev_info(dev, "resume\n");
+       clk_enable(sdev->sclk_dac);
+       regulator_enable(sdev->vdac);
+       regulator_enable(sdev->vdet);
+
+       /* software reset */
+       sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_SW_RESET);
+       mdelay(10);
+       sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_SW_RESET);
+
+       /* setting TV mode */
+       sdo_write_mask(sdev, SDO_CONFIG, sdev->fmt->cookie, SDO_STANDARD_MASK);
+       /* XXX: forcing interlaced mode using undocumented bit */
+       sdo_write_mask(sdev, SDO_CONFIG, 0, SDO_PROGRESSIVE);
+       /* turn all VBI off */
+       sdo_write_mask(sdev, SDO_VBI, 0, SDO_CVBS_WSS_INS |
+               SDO_CVBS_CLOSED_CAPTION_MASK);
+       /* turn all post processing off */
+       sdo_write_mask(sdev, SDO_CCCON, ~0, SDO_COMPENSATION_BHS_ADJ_OFF |
+               SDO_COMPENSATION_CVBS_COMP_OFF);
+       sdo_reg_debug(sdev);
+       return 0;
+}
+
+static const struct dev_pm_ops sdo_pm_ops = {
+       .runtime_suspend = sdo_runtime_suspend,
+       .runtime_resume  = sdo_runtime_resume,
+};
+
+static int __devinit sdo_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct sdo_device *sdev;
+       struct resource *res;
+       int ret = 0;
+       struct clk *sclk_vpll;
+
+       dev_info(dev, "probe start\n");
+       sdev = kzalloc(sizeof *sdev, GFP_KERNEL);
+       if (!sdev) {
+               dev_err(dev, "not enough memory.\n");
+               ret = -ENOMEM;
+               goto fail;
+       }
+       sdev->dev = dev;
+
+       /* mapping registers */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(dev, "get memory resource failed.\n");
+               ret = -ENXIO;
+               goto fail_sdev;
+       }
+
+       sdev->regs = ioremap(res->start, resource_size(res));
+       if (sdev->regs == NULL) {
+               dev_err(dev, "register mapping failed.\n");
+               ret = -ENXIO;
+               goto fail_sdev;
+       }
+
+       /* acquiring interrupt */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (res == NULL) {
+               dev_err(dev, "get interrupt resource failed.\n");
+               ret = -ENXIO;
+               goto fail_regs;
+       }
+       ret = request_irq(res->start, sdo_irq_handler, 0, "s5p-sdo", sdev);
+       if (ret) {
+               dev_err(dev, "request interrupt failed.\n");
+               goto fail_regs;
+       }
+       sdev->irq = res->start;
+
+       /* acquire clocks */
+       sdev->sclk_dac = clk_get(dev, "sclk_dac");
+       if (IS_ERR_OR_NULL(sdev->sclk_dac)) {
+               dev_err(dev, "failed to get clock 'sclk_dac'\n");
+               ret = -ENXIO;
+               goto fail_irq;
+       }
+       sdev->dac = clk_get(dev, "dac");
+       if (IS_ERR_OR_NULL(sdev->dac)) {
+               dev_err(dev, "failed to get clock 'dac'\n");
+               ret = -ENXIO;
+               goto fail_sclk_dac;
+       }
+       sdev->dacphy = clk_get(dev, "dacphy");
+       if (IS_ERR_OR_NULL(sdev->dacphy)) {
+               dev_err(dev, "failed to get clock 'dacphy'\n");
+               ret = -ENXIO;
+               goto fail_dac;
+       }
+       sclk_vpll = clk_get(dev, "sclk_vpll");
+       if (IS_ERR_OR_NULL(sclk_vpll)) {
+               dev_err(dev, "failed to get clock 'sclk_vpll'\n");
+               ret = -ENXIO;
+               goto fail_dacphy;
+       }
+       clk_set_parent(sdev->sclk_dac, sclk_vpll);
+       clk_put(sclk_vpll);
+       sdev->fout_vpll = clk_get(dev, "fout_vpll");
+       if (IS_ERR_OR_NULL(sdev->fout_vpll)) {
+               dev_err(dev, "failed to get clock 'fout_vpll'\n");
+               goto fail_dacphy;
+       }
+       dev_info(dev, "fout_vpll.rate = %lu\n", clk_get_rate(sclk_vpll));
+
+       /* acquire regulator */
+       sdev->vdac = regulator_get(dev, "vdd33a_dac");
+       if (IS_ERR_OR_NULL(sdev->vdac)) {
+               dev_err(dev, "failed to get regulator 'vdac'\n");
+               goto fail_fout_vpll;
+       }
+       sdev->vdet = regulator_get(dev, "vdet");
+       if (IS_ERR_OR_NULL(sdev->vdet)) {
+               dev_err(dev, "failed to get regulator 'vdet'\n");
+               goto fail_vdac;
+       }
+
+       /* enable gate for dac clock, because mixer uses it */
+       clk_enable(sdev->dac);
+
+       /* configure power management */
+       pm_runtime_enable(dev);
+
+       /* configuration of interface subdevice */
+       v4l2_subdev_init(&sdev->sd, &sdo_sd_ops);
+       sdev->sd.owner = THIS_MODULE;
+       strlcpy(sdev->sd.name, "s5p-sdo", sizeof sdev->sd.name);
+
+       /* set default format */
+       sdev->fmt = sdo_find_format(SDO_DEFAULT_STD);
+       BUG_ON(sdev->fmt == NULL);
+
+       /* keeping subdev in device's private for use by other drivers */
+       dev_set_drvdata(dev, &sdev->sd);
+
+       dev_info(dev, "probe succeeded\n");
+       return 0;
+
+fail_vdac:
+       regulator_put(sdev->vdac);
+fail_fout_vpll:
+       clk_put(sdev->fout_vpll);
+fail_dacphy:
+       clk_put(sdev->dacphy);
+fail_dac:
+       clk_put(sdev->dac);
+fail_sclk_dac:
+       clk_put(sdev->sclk_dac);
+fail_irq:
+       free_irq(sdev->irq, sdev);
+fail_regs:
+       iounmap(sdev->regs);
+fail_sdev:
+       kfree(sdev);
+fail:
+       dev_info(dev, "probe failed\n");
+       return ret;
+}
+
+static int __devexit sdo_remove(struct platform_device *pdev)
+{
+       struct v4l2_subdev *sd = dev_get_drvdata(&pdev->dev);
+       struct sdo_device *sdev = sd_to_sdev(sd);
+
+       pm_runtime_disable(&pdev->dev);
+       clk_disable(sdev->dac);
+       regulator_put(sdev->vdet);
+       regulator_put(sdev->vdac);
+       clk_put(sdev->fout_vpll);
+       clk_put(sdev->dacphy);
+       clk_put(sdev->dac);
+       clk_put(sdev->sclk_dac);
+       free_irq(sdev->irq, sdev);
+       iounmap(sdev->regs);
+       kfree(sdev);
+
+       dev_info(&pdev->dev, "remove successful\n");
+       return 0;
+}
+
+static struct platform_driver sdo_driver __refdata = {
+       .probe = sdo_probe,
+       .remove = __devexit_p(sdo_remove),
+       .driver = {
+               .name = "s5p-sdo",
+               .owner = THIS_MODULE,
+               .pm = &sdo_pm_ops,
+       }
+};
+
+static int __init sdo_init(void)
+{
+       int ret;
+       static const char banner[] __initdata = KERN_INFO \
+               "Samsung Standard Definition Output (SDO) driver, "
+               "(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
+       printk(banner);
+
+       ret = platform_driver_register(&sdo_driver);
+       if (ret)
+               printk(KERN_ERR "SDO platform driver register failed\n");
+
+       return ret;
+}
+module_init(sdo_init);
+
+static void __exit sdo_exit(void)
+{
+       platform_driver_unregister(&sdo_driver);
+}
+module_exit(sdo_exit);
index 0db9092..f2ae405 100644 (file)
@@ -757,8 +757,8 @@ static int saa711x_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
        switch (ctrl->id) {
        case V4L2_CID_CHROMA_AGC:
                /* chroma gain cluster */
-               if (state->agc->cur.val)
-                       state->gain->cur.val =
+               if (state->agc->val)
+                       state->gain->val =
                                saa711x_read(sd, R_0F_CHROMA_GAIN_CNTL) & 0x7f;
                break;
        }
index e2062b2..0f9fb99 100644 (file)
@@ -4951,8 +4951,9 @@ struct saa7134_board saa7134_boards[] = {
                .audio_clock    = 0x00187de7,
                .tuner_type     = TUNER_XC2028,
                .radio_type     = UNSET,
-               .tuner_addr     = ADDR_UNSET,
+               .tuner_addr     = 0x61,
                .radio_addr     = ADDR_UNSET,
+               .mpeg           = SAA7134_MPEG_DVB,
                .inputs = {{
                        .name   = name_tv,
                        .vmux   = 3,
@@ -6992,6 +6993,11 @@ static int saa7134_xc2028_callback(struct saa7134_dev *dev,
                        msleep(10);
                        saa7134_set_gpio(dev, 18, 1);
                break;
+               case SAA7134_BOARD_VIDEOMATE_T750:
+                       saa7134_set_gpio(dev, 20, 0);
+                       msleep(10);
+                       saa7134_set_gpio(dev, 20, 1);
+               break;
                }
        return 0;
        }
@@ -7451,6 +7457,11 @@ int saa7134_board_init1(struct saa7134_dev *dev)
                saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x0e050000, 0x0c050000);
                saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0e050000, 0x0c050000);
                break;
+       case SAA7134_BOARD_VIDEOMATE_T750:
+               /* enable the analog tuner */
+               saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x00008000, 0x00008000);
+               saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00008000, 0x00008000);
+               break;
        }
        return 0;
 }
index f9be737..ca65cda 100644 (file)
@@ -39,6 +39,8 @@
 MODULE_DESCRIPTION("v4l2 driver module for saa7130/34 based TV cards");
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(SAA7134_VERSION);
+
 
 /* ------------------------------------------------------------------ */
 
@@ -1332,14 +1334,8 @@ static struct pci_driver saa7134_pci_driver = {
 static int __init saa7134_init(void)
 {
        INIT_LIST_HEAD(&saa7134_devlist);
-       printk(KERN_INFO "saa7130/34: v4l2 driver version %d.%d.%d loaded\n",
-              (SAA7134_VERSION_CODE >> 16) & 0xff,
-              (SAA7134_VERSION_CODE >>  8) & 0xff,
-              SAA7134_VERSION_CODE & 0xff);
-#ifdef SNAPSHOT
-       printk(KERN_INFO "saa7130/34: snapshot date %04d-%02d-%02d\n",
-              SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
-#endif
+       printk(KERN_INFO "saa7130/34: v4l2 driver version %s loaded\n",
+              SAA7134_VERSION);
        return pci_register_driver(&saa7134_pci_driver);
 }
 
index 996a206..1e4ef16 100644 (file)
@@ -56,6 +56,7 @@
 #include "lgs8gxx.h"
 
 #include "zl10353.h"
+#include "qt1010.h"
 
 #include "zl10036.h"
 #include "zl10039.h"
@@ -939,6 +940,18 @@ static struct zl10353_config behold_x7_config = {
        .disable_i2c_gate_ctrl = 1,
 };
 
+static struct zl10353_config videomate_t750_zl10353_config = {
+       .demod_address         = 0x0f,
+       .no_tuner              = 1,
+       .parallel_ts           = 1,
+       .disable_i2c_gate_ctrl = 1,
+};
+
+static struct qt1010_config videomate_t750_qt1010_config = {
+       .i2c_address = 0x62
+};
+
+
 /* ==================================================================
  * tda10086 based DVB-S cards, helper functions
  */
@@ -1649,6 +1662,18 @@ static int dvb_init(struct saa7134_dev *dev)
                                wprintk("%s: No zl10039 found!\n",
                                        __func__);
 
+               break;
+       case SAA7134_BOARD_VIDEOMATE_T750:
+               fe0->dvb.frontend = dvb_attach(zl10353_attach,
+                                               &videomate_t750_zl10353_config,
+                                               &dev->i2c_adap);
+               if (fe0->dvb.frontend != NULL) {
+                       if (dvb_attach(qt1010_attach,
+                                       fe0->dvb.frontend,
+                                       &dev->i2c_adap,
+                                       &videomate_t750_qt1010_config) == NULL)
+                               wprintk("error attaching QT1010\n");
+               }
                break;
        case SAA7134_BOARD_ZOLID_HYBRID_PCI:
                fe0->dvb.frontend = dvb_attach(tda10048_attach,
index 18294db..dde361a 100644 (file)
@@ -172,7 +172,6 @@ static int empress_querycap(struct file *file, void  *priv,
        strlcpy(cap->card, saa7134_boards[dev->board].name,
                sizeof(cap->card));
        sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
-       cap->version = SAA7134_VERSION_CODE;
        cap->capabilities =
                V4L2_CAP_VIDEO_CAPTURE |
                V4L2_CAP_READWRITE |
index 776ba2d..9cf7914 100644 (file)
@@ -1810,7 +1810,6 @@ static int saa7134_querycap(struct file *file, void  *priv,
        strlcpy(cap->card, saa7134_boards[dev->board].name,
                sizeof(cap->card));
        sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
-       cap->version = SAA7134_VERSION_CODE;
        cap->capabilities =
                V4L2_CAP_VIDEO_CAPTURE |
                V4L2_CAP_VBI_CAPTURE |
@@ -2307,7 +2306,6 @@ static int radio_querycap(struct file *file, void *priv,
        strcpy(cap->driver, "saa7134");
        strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card));
        sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
-       cap->version = SAA7134_VERSION_CODE;
        cap->capabilities = V4L2_CAP_TUNER;
        return 0;
 }
index 28eb103..bc8d6bb 100644 (file)
@@ -19,8 +19,7 @@
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/version.h>
-#define SAA7134_VERSION_CODE KERNEL_VERSION(0, 2, 16)
+#define SAA7134_VERSION "0, 2, 17"
 
 #include <linux/pci.h>
 #include <linux/i2c.h>
index 4003645..2fd38a0 100644 (file)
@@ -1246,7 +1246,6 @@ static unsigned int fops_poll(struct file *file, poll_table *wait)
        struct saa7164_encoder_fh *fh =
                (struct saa7164_encoder_fh *)file->private_data;
        struct saa7164_port *port = fh->port;
-       struct saa7164_user_buffer *ubuf;
        unsigned int mask = 0;
 
        port->last_poll_msecs_diff = port->last_poll_msecs;
@@ -1278,10 +1277,7 @@ static unsigned int fops_poll(struct file *file, poll_table *wait)
        }
 
        /* Pull the first buffer from the used list */
-       ubuf = list_first_entry(&port->list_buf_used.list,
-               struct saa7164_user_buffer, list);
-
-       if (ubuf)
+       if (!list_empty(&port->list_buf_used.list))
                mask |= POLLIN | POLLRDNORM;
 
        return mask;
index bc1fced..e2e0341 100644 (file)
@@ -1192,7 +1192,6 @@ static unsigned int fops_poll(struct file *file, poll_table *wait)
 {
        struct saa7164_vbi_fh *fh = (struct saa7164_vbi_fh *)file->private_data;
        struct saa7164_port *port = fh->port;
-       struct saa7164_user_buffer *ubuf;
        unsigned int mask = 0;
 
        port->last_poll_msecs_diff = port->last_poll_msecs;
@@ -1224,10 +1223,7 @@ static unsigned int fops_poll(struct file *file, poll_table *wait)
        }
 
        /* Pull the first buffer from the used list */
-       ubuf = list_first_entry(&port->list_buf_used.list,
-               struct saa7164_user_buffer, list);
-
-       if (ubuf)
+       if (!list_empty(&port->list_buf_used.list))
                mask |= POLLIN | POLLRDNORM;
 
        return mask;
index 16745d2..6678bf1 100644 (file)
@@ -48,7 +48,6 @@
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 #include <linux/kdev_t.h>
-#include <linux/version.h>
 #include <linux/mutex.h>
 #include <linux/crc32.h>
 #include <linux/kthread.h>
index 3ae5c9c..e540898 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/mm.h>
 #include <linux/moduleparam.h>
 #include <linux/time.h>
-#include <linux/version.h>
 #include <linux/slab.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
@@ -39,6 +38,7 @@
 #include <media/v4l2-dev.h>
 #include <media/soc_camera.h>
 #include <media/sh_mobile_ceu.h>
+#include <media/sh_mobile_csi2.h>
 #include <media/videobuf2-dma-contig.h>
 #include <media/v4l2-mediabus.h>
 #include <media/soc_mediabus.h>
@@ -96,6 +96,7 @@ struct sh_mobile_ceu_buffer {
 struct sh_mobile_ceu_dev {
        struct soc_camera_host ici;
        struct soc_camera_device *icd;
+       struct platform_device *csi2_pdev;
 
        unsigned int irq;
        void __iomem *base;
@@ -205,7 +206,7 @@ static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev)
 
 
        if (2 != success) {
-               dev_warn(&icd->dev, "soft reset time out\n");
+               dev_warn(icd->pdev, "soft reset time out\n");
                return -EIO;
        }
 
@@ -220,7 +221,7 @@ static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq,
                        unsigned long sizes[], void *alloc_ctxs[])
 {
        struct soc_camera_device *icd = container_of(vq, struct soc_camera_device, vb2_vidq);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
                                                icd->current_fmt->host_fmt);
@@ -242,7 +243,7 @@ static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq,
                        *count = pcdev->video_limit / PAGE_ALIGN(sizes[0]);
        }
 
-       dev_dbg(icd->dev.parent, "count=%d, size=%lu\n", *count, sizes[0]);
+       dev_dbg(icd->parent, "count=%d, size=%lu\n", *count, sizes[0]);
 
        return 0;
 }
@@ -351,7 +352,7 @@ static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb)
 
        buf = to_ceu_vb(vb);
 
-       dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
                vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
 
        /* Added list head initialization on alloc */
@@ -371,7 +372,7 @@ static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb)
        size = icd->user_height * bytes_per_line;
 
        if (vb2_plane_size(vb, 0) < size) {
-               dev_err(icd->dev.parent, "Buffer too small (%lu < %lu)\n",
+               dev_err(icd->parent, "Buffer too small (%lu < %lu)\n",
                        vb2_plane_size(vb, 0), size);
                return -ENOBUFS;
        }
@@ -384,11 +385,11 @@ static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb)
 static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb)
 {
        struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb);
 
-       dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
                vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
 
        spin_lock_irq(&pcdev->lock);
@@ -409,7 +410,7 @@ static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb)
 static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb)
 {
        struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
 
@@ -421,8 +422,12 @@ static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb)
                pcdev->active = NULL;
        }
 
-       /* Doesn't hurt also if the list is empty */
-       list_del_init(&buf->queue);
+       /*
+        * Doesn't hurt also if the list is empty, but it hurts, if queuing the
+        * buffer failed, and .buf_init() hasn't been called
+        */
+       if (buf->queue.next)
+               list_del_init(&buf->queue);
 
        spin_unlock_irq(&pcdev->lock);
 }
@@ -437,7 +442,7 @@ static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb)
 static int sh_mobile_ceu_stop_streaming(struct vb2_queue *q)
 {
        struct soc_camera_device *icd = container_of(q, struct soc_camera_device, vb2_vidq);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        struct list_head *buf_head, *tmp;
 
@@ -499,25 +504,48 @@ out:
        return IRQ_HANDLED;
 }
 
+static struct v4l2_subdev *find_csi2(struct sh_mobile_ceu_dev *pcdev)
+{
+       struct v4l2_subdev *sd;
+
+       if (!pcdev->csi2_pdev)
+               return NULL;
+
+       v4l2_device_for_each_subdev(sd, &pcdev->ici.v4l2_dev)
+               if (&pcdev->csi2_pdev->dev == v4l2_get_subdevdata(sd))
+                       return sd;
+
+       return NULL;
+}
+
 /* Called with .video_lock held */
 static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
+       struct v4l2_subdev *csi2_sd;
        int ret;
 
        if (pcdev->icd)
                return -EBUSY;
 
-       dev_info(icd->dev.parent,
+       dev_info(icd->parent,
                 "SuperH Mobile CEU driver attached to camera %d\n",
                 icd->devnum);
 
        pm_runtime_get_sync(ici->v4l2_dev.dev);
 
        ret = sh_mobile_ceu_soft_reset(pcdev);
-       if (!ret)
+
+       csi2_sd = find_csi2(pcdev);
+
+       ret = v4l2_subdev_call(csi2_sd, core, s_power, 1);
+       if (ret != -ENODEV && ret != -ENOIOCTLCMD && ret < 0) {
+               pm_runtime_put_sync(ici->v4l2_dev.dev);
+       } else {
                pcdev->icd = icd;
+               ret = 0;
+       }
 
        return ret;
 }
@@ -525,11 +553,13 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
 /* Called with .video_lock held */
 static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
+       struct v4l2_subdev *csi2_sd = find_csi2(pcdev);
 
        BUG_ON(icd != pcdev->icd);
 
+       v4l2_subdev_call(csi2_sd, core, s_power, 0);
        /* disable capture, disable interrupts */
        ceu_write(pcdev, CEIER, 0);
        sh_mobile_ceu_soft_reset(pcdev);
@@ -545,7 +575,7 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
 
        pm_runtime_put_sync(ici->v4l2_dev.dev);
 
-       dev_info(icd->dev.parent,
+       dev_info(icd->parent,
                 "SuperH Mobile CEU driver detached from camera %d\n",
                 icd->devnum);
 
@@ -585,14 +615,14 @@ static u16 calc_scale(unsigned int src, unsigned int *dst)
 /* rect is guaranteed to not exceed the scaled camera rectangle */
 static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_cam *cam = icd->host_priv;
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        unsigned int height, width, cdwdr_width, in_width, in_height;
        unsigned int left_offset, top_offset;
        u32 camor;
 
-       dev_geo(icd->dev.parent, "Crop %ux%u@%u:%u\n",
+       dev_geo(icd->parent, "Crop %ux%u@%u:%u\n",
                icd->user_width, icd->user_height, cam->ceu_left, cam->ceu_top);
 
        left_offset     = cam->ceu_left;
@@ -641,7 +671,7 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd)
        }
 
        /* CSI2 special configuration */
-       if (pcdev->pdata->csi2_dev) {
+       if (pcdev->pdata->csi2) {
                in_width = ((in_width - 2) * 2);
                left_offset *= 2;
        }
@@ -649,7 +679,7 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd)
        /* Set CAMOR, CAPWR, CFSZR, take care of CDWDR */
        camor = left_offset | (top_offset << 16);
 
-       dev_geo(icd->dev.parent,
+       dev_geo(icd->parent,
                "CAMOR 0x%x, CAPWR 0x%x, CFSZR 0x%x, CDWDR 0x%x\n", camor,
                (in_height << 16) | in_width, (height << 16) | width,
                cdwdr_width);
@@ -697,7 +727,7 @@ static void capture_restore(struct sh_mobile_ceu_dev *pcdev, u32 capsr)
 static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
                                       __u32 pixfmt)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        int ret;
        unsigned long camera_flags, common_flags, value;
@@ -783,7 +813,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
        value |= pcdev->is_16bit ? 1 << 12 : 0;
 
        /* CSI2 mode */
-       if (pcdev->pdata->csi2_dev)
+       if (pcdev->pdata->csi2)
                value |= 3 << 12;
 
        ceu_write(pcdev, CAMCR, value);
@@ -806,7 +836,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
        sh_mobile_ceu_set_rect(icd);
        mdelay(1);
 
-       dev_geo(icd->dev.parent, "CFLCR 0x%x\n", pcdev->cflcr);
+       dev_geo(icd->parent, "CFLCR 0x%x\n", pcdev->cflcr);
        ceu_write(pcdev, CFLCR, pcdev->cflcr);
 
        /*
@@ -829,7 +859,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
        ceu_write(pcdev, CDOCR, value);
        ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */
 
-       dev_dbg(icd->dev.parent, "S_FMT successful for %c%c%c%c %ux%u\n",
+       dev_dbg(icd->parent, "S_FMT successful for %c%c%c%c %ux%u\n",
                pixfmt & 0xff, (pixfmt >> 8) & 0xff,
                (pixfmt >> 16) & 0xff, (pixfmt >> 24) & 0xff,
                icd->user_width, icd->user_height);
@@ -843,7 +873,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
 static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd,
                                       unsigned char buswidth)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        unsigned long camera_flags, common_flags;
 
@@ -901,7 +931,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
                                     struct soc_camera_format_xlate *xlate)
 {
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-       struct device *dev = icd->dev.parent;
+       struct device *dev = icd->parent;
        struct soc_camera_host *ici = to_soc_camera_host(dev);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        int ret, k, n;
@@ -921,7 +951,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
                return 0;
        }
 
-       if (!pcdev->pdata->csi2_dev) {
+       if (!pcdev->pdata->csi2) {
                ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample);
                if (ret < 0)
                        return 0;
@@ -1244,7 +1274,7 @@ static int client_s_fmt(struct soc_camera_device *icd,
 {
        struct sh_mobile_ceu_cam *cam = icd->host_priv;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-       struct device *dev = icd->dev.parent;
+       struct device *dev = icd->parent;
        unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h;
        unsigned int max_width, max_height;
        struct v4l2_cropcap cap;
@@ -1313,7 +1343,7 @@ static int client_scale(struct soc_camera_device *icd,
                        bool ceu_can_scale)
 {
        struct sh_mobile_ceu_cam *cam = icd->host_priv;
-       struct device *dev = icd->dev.parent;
+       struct device *dev = icd->parent;
        struct v4l2_mbus_framefmt mf_tmp = *mf;
        unsigned int scale_h, scale_v;
        int ret;
@@ -1363,13 +1393,13 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
                                  struct v4l2_crop *a)
 {
        struct v4l2_rect *rect = &a->c;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct device *dev = icd->parent;
+       struct soc_camera_host *ici = to_soc_camera_host(dev);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        struct v4l2_crop cam_crop;
        struct sh_mobile_ceu_cam *cam = icd->host_priv;
        struct v4l2_rect *cam_rect = &cam_crop.c;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-       struct device *dev = icd->dev.parent;
        struct v4l2_mbus_framefmt mf;
        unsigned int scale_cam_h, scale_cam_v, scale_ceu_h, scale_ceu_v,
                out_width, out_height;
@@ -1511,7 +1541,7 @@ static void calculate_client_output(struct soc_camera_device *icd,
                struct v4l2_pix_format *pix, struct v4l2_mbus_framefmt *mf)
 {
        struct sh_mobile_ceu_cam *cam = icd->host_priv;
-       struct device *dev = icd->dev.parent;
+       struct device *dev = icd->parent;
        struct v4l2_rect *cam_subrect = &cam->subrect;
        unsigned int scale_v, scale_h;
 
@@ -1555,12 +1585,12 @@ static void calculate_client_output(struct soc_camera_device *icd,
 static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
                                 struct v4l2_format *f)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct device *dev = icd->parent;
+       struct soc_camera_host *ici = to_soc_camera_host(dev);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        struct sh_mobile_ceu_cam *cam = icd->host_priv;
        struct v4l2_pix_format *pix = &f->fmt.pix;
        struct v4l2_mbus_framefmt mf;
-       struct device *dev = icd->dev.parent;
        __u32 pixfmt = pix->pixelformat;
        const struct soc_camera_format_xlate *xlate;
        /* Keep Compiler Happy */
@@ -1684,12 +1714,12 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
        int width, height;
        int ret;
 
-       dev_geo(icd->dev.parent, "TRY_FMT(pix=0x%x, %ux%u)\n",
+       dev_geo(icd->parent, "TRY_FMT(pix=0x%x, %ux%u)\n",
                 pixfmt, pix->width, pix->height);
 
        xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
        if (!xlate) {
-               dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt);
+               dev_warn(icd->parent, "Format %x not found\n", pixfmt);
                return -EINVAL;
        }
 
@@ -1701,11 +1731,6 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
        width = pix->width;
        height = pix->height;
 
-       pix->bytesperline = soc_mbus_bytes_per_line(width, xlate->host_fmt);
-       if ((int)pix->bytesperline < 0)
-               return pix->bytesperline;
-       pix->sizeimage = height * pix->bytesperline;
-
        /* limit to sensor capabilities */
        mf.width        = pix->width;
        mf.height       = pix->height;
@@ -1741,7 +1766,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
                                                         try_mbus_fmt, &mf);
                        if (ret < 0) {
                                /* Shouldn't actually happen... */
-                               dev_err(icd->dev.parent,
+                               dev_err(icd->parent,
                                        "FIXME: client try_fmt() = %d\n", ret);
                                return ret;
                        }
@@ -1753,7 +1778,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
                        pix->height = height;
        }
 
-       dev_geo(icd->dev.parent, "%s(): return %d, fmt 0x%x, %ux%u\n",
+       dev_geo(icd->parent, "%s(): return %d, fmt 0x%x, %ux%u\n",
                __func__, ret, pix->pixelformat, pix->width, pix->height);
 
        return ret;
@@ -1763,7 +1788,7 @@ static int sh_mobile_ceu_set_livecrop(struct soc_camera_device *icd,
                                      struct v4l2_crop *a)
 {
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        u32 out_width = icd->user_width, out_height = icd->user_height;
        int ret;
@@ -1775,13 +1800,13 @@ static int sh_mobile_ceu_set_livecrop(struct soc_camera_device *icd,
        /* Stop the client */
        ret = v4l2_subdev_call(sd, video, s_stream, 0);
        if (ret < 0)
-               dev_warn(icd->dev.parent,
+               dev_warn(icd->parent,
                         "Client failed to stop the stream: %d\n", ret);
        else
                /* Do the crop, if it fails, there's nothing more we can do */
                sh_mobile_ceu_set_crop(icd, a);
 
-       dev_geo(icd->dev.parent, "Output after crop: %ux%u\n", icd->user_width, icd->user_height);
+       dev_geo(icd->parent, "Output after crop: %ux%u\n", icd->user_width, icd->user_height);
 
        if (icd->user_width != out_width || icd->user_height != out_height) {
                struct v4l2_format f = {
@@ -1827,7 +1852,6 @@ static int sh_mobile_ceu_querycap(struct soc_camera_host *ici,
                                  struct v4l2_capability *cap)
 {
        strlcpy(cap->card, "SuperH_Mobile_CEU", sizeof(cap->card));
-       cap->version = KERNEL_VERSION(0, 0, 5);
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
        return 0;
 }
@@ -1848,7 +1872,7 @@ static int sh_mobile_ceu_init_videobuf(struct vb2_queue *q,
 static int sh_mobile_ceu_get_ctrl(struct soc_camera_device *icd,
                                  struct v4l2_control *ctrl)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        u32 val;
 
@@ -1864,7 +1888,7 @@ static int sh_mobile_ceu_get_ctrl(struct soc_camera_device *icd,
 static int sh_mobile_ceu_set_ctrl(struct soc_camera_device *icd,
                                  struct v4l2_control *ctrl)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
 
        switch (ctrl->id) {
@@ -1950,7 +1974,7 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
                .completion = COMPLETION_INITIALIZER_ONSTACK(wait.completion),
                .notifier.notifier_call = bus_notify,
        };
-       struct device *csi2;
+       struct sh_mobile_ceu_companion *csi2;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        irq = platform_get_irq(pdev, 0);
@@ -2023,26 +2047,61 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
        pcdev->ici.drv_name = dev_name(&pdev->dev);
        pcdev->ici.ops = &sh_mobile_ceu_host_ops;
 
+       pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+       if (IS_ERR(pcdev->alloc_ctx)) {
+               err = PTR_ERR(pcdev->alloc_ctx);
+               goto exit_free_clk;
+       }
+
+       err = soc_camera_host_register(&pcdev->ici);
+       if (err)
+               goto exit_free_ctx;
+
        /* CSI2 interfacing */
-       csi2 = pcdev->pdata->csi2_dev;
+       csi2 = pcdev->pdata->csi2;
        if (csi2) {
-               wait.dev = csi2;
+               struct platform_device *csi2_pdev =
+                       platform_device_alloc("sh-mobile-csi2", csi2->id);
+               struct sh_csi2_pdata *csi2_pdata = csi2->platform_data;
+
+               if (!csi2_pdev) {
+                       err = -ENOMEM;
+                       goto exit_host_unregister;
+               }
+
+               pcdev->csi2_pdev                = csi2_pdev;
+
+               err = platform_device_add_data(csi2_pdev, csi2_pdata, sizeof(*csi2_pdata));
+               if (err < 0)
+                       goto exit_pdev_put;
+
+               csi2_pdata                      = csi2_pdev->dev.platform_data;
+               csi2_pdata->v4l2_dev            = &pcdev->ici.v4l2_dev;
+
+               csi2_pdev->resource             = csi2->resource;
+               csi2_pdev->num_resources        = csi2->num_resources;
+
+               err = platform_device_add(csi2_pdev);
+               if (err < 0)
+                       goto exit_pdev_put;
+
+               wait.dev = &csi2_pdev->dev;
 
                err = bus_register_notifier(&platform_bus_type, &wait.notifier);
                if (err < 0)
-                       goto exit_free_clk;
+                       goto exit_pdev_unregister;
 
                /*
                 * From this point the driver module will not unload, until
                 * we complete the completion.
                 */
 
-               if (!csi2->driver) {
+               if (!csi2_pdev->dev.driver) {
                        complete(&wait.completion);
                        /* Either too late, or probing failed */
                        bus_unregister_notifier(&platform_bus_type, &wait.notifier);
                        err = -ENXIO;
-                       goto exit_free_clk;
+                       goto exit_pdev_unregister;
                }
 
                /*
@@ -2051,34 +2110,28 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
                 * the "owner" is safe!
                 */
 
-               err = try_module_get(csi2->driver->owner);
+               err = try_module_get(csi2_pdev->dev.driver->owner);
 
                /* Let notifier complete, if it has been locked */
                complete(&wait.completion);
                bus_unregister_notifier(&platform_bus_type, &wait.notifier);
                if (!err) {
                        err = -ENODEV;
-                       goto exit_free_clk;
+                       goto exit_pdev_unregister;
                }
        }
 
-       pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
-       if (IS_ERR(pcdev->alloc_ctx)) {
-               err = PTR_ERR(pcdev->alloc_ctx);
-               goto exit_module_put;
-       }
-
-       err = soc_camera_host_register(&pcdev->ici);
-       if (err)
-               goto exit_free_ctx;
-
        return 0;
 
+exit_pdev_unregister:
+       platform_device_del(pcdev->csi2_pdev);
+exit_pdev_put:
+       pcdev->csi2_pdev->resource = NULL;
+       platform_device_put(pcdev->csi2_pdev);
+exit_host_unregister:
+       soc_camera_host_unregister(&pcdev->ici);
 exit_free_ctx:
        vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
-exit_module_put:
-       if (csi2 && csi2->driver)
-               module_put(csi2->driver->owner);
 exit_free_clk:
        pm_runtime_disable(&pdev->dev);
        free_irq(pcdev->irq, pcdev);
@@ -2098,7 +2151,7 @@ static int __devexit sh_mobile_ceu_remove(struct platform_device *pdev)
        struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
        struct sh_mobile_ceu_dev *pcdev = container_of(soc_host,
                                        struct sh_mobile_ceu_dev, ici);
-       struct device *csi2 = pcdev->pdata->csi2_dev;
+       struct platform_device *csi2_pdev = pcdev->csi2_pdev;
 
        soc_camera_host_unregister(soc_host);
        pm_runtime_disable(&pdev->dev);
@@ -2107,8 +2160,13 @@ static int __devexit sh_mobile_ceu_remove(struct platform_device *pdev)
                dma_release_declared_memory(&pdev->dev);
        iounmap(pcdev->base);
        vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
-       if (csi2 && csi2->driver)
-               module_put(csi2->driver->owner);
+       if (csi2_pdev && csi2_pdev->dev.driver) {
+               struct module *csi2_drv = csi2_pdev->dev.driver->owner;
+               platform_device_del(csi2_pdev);
+               csi2_pdev->resource = NULL;
+               platform_device_put(csi2_pdev);
+               module_put(csi2_drv);
+       }
        kfree(pcdev);
 
        return 0;
@@ -2158,4 +2216,5 @@ module_exit(sh_mobile_ceu_exit);
 MODULE_DESCRIPTION("SuperH Mobile CEU driver");
 MODULE_AUTHOR("Magnus Damm");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.6");
 MODULE_ALIAS("platform:sh_mobile_ceu");
index 98b8748..2893a01 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 
+#include <media/sh_mobile_ceu.h>
 #include <media/sh_mobile_csi2.h>
 #include <media/soc_camera.h>
 #include <media/v4l2-common.h>
@@ -33,7 +34,6 @@
 struct sh_csi2 {
        struct v4l2_subdev              subdev;
        struct list_head                list;
-       struct notifier_block           notifier;
        unsigned int                    irq;
        void __iomem                    *base;
        struct platform_device          *pdev;
@@ -132,13 +132,6 @@ static struct v4l2_subdev_video_ops sh_csi2_subdev_video_ops = {
        .try_mbus_fmt   = sh_csi2_try_fmt,
 };
 
-static struct v4l2_subdev_core_ops sh_csi2_subdev_core_ops;
-
-static struct v4l2_subdev_ops sh_csi2_subdev_ops = {
-       .core   = &sh_csi2_subdev_core_ops,
-       .video  = &sh_csi2_subdev_video_ops,
-};
-
 static void sh_csi2_hwinit(struct sh_csi2 *priv)
 {
        struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data;
@@ -186,65 +179,84 @@ static unsigned long sh_csi2_query_bus_param(struct soc_camera_device *icd)
        return soc_camera_apply_sensor_flags(icl, flags);
 }
 
-static int sh_csi2_notify(struct notifier_block *nb,
-                         unsigned long action, void *data)
+static int sh_csi2_client_connect(struct sh_csi2 *priv)
 {
-       struct device *dev = data;
-       struct soc_camera_device *icd = to_soc_camera_dev(dev);
-       struct v4l2_device *v4l2_dev = dev_get_drvdata(dev->parent);
-       struct sh_csi2 *priv =
-               container_of(nb, struct sh_csi2, notifier);
        struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data;
-       int ret, i;
+       struct v4l2_subdev *sd, *csi2_sd = &priv->subdev;
+       struct soc_camera_device *icd = NULL;
+       struct device *dev = v4l2_get_subdevdata(&priv->subdev);
+       int i;
+
+       v4l2_device_for_each_subdev(sd, csi2_sd->v4l2_dev)
+               if (sd->grp_id) {
+                       icd = (struct soc_camera_device *)sd->grp_id;
+                       break;
+               }
+
+       if (!icd)
+               return -EINVAL;
 
        for (i = 0; i < pdata->num_clients; i++)
                if (&pdata->clients[i].pdev->dev == icd->pdev)
                        break;
 
-       dev_dbg(dev, "%s(%p): action = %lu, found #%d\n", __func__, dev, action, i);
+       dev_dbg(dev, "%s(%p): found #%d\n", __func__, dev, i);
 
        if (i == pdata->num_clients)
-               return NOTIFY_DONE;
+               return -ENODEV;
 
-       switch (action) {
-       case BUS_NOTIFY_BOUND_DRIVER:
-               snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s%s",
-                        dev_name(v4l2_dev->dev), ".mipi-csi");
-               priv->subdev.grp_id = (long)icd;
-               ret = v4l2_device_register_subdev(v4l2_dev, &priv->subdev);
-               dev_dbg(dev, "%s(%p): ret(register_subdev) = %d\n", __func__, priv, ret);
-               if (ret < 0)
-                       return NOTIFY_DONE;
+       priv->client = pdata->clients + i;
 
-               priv->client = pdata->clients + i;
+       priv->set_bus_param             = icd->ops->set_bus_param;
+       priv->query_bus_param           = icd->ops->query_bus_param;
+       icd->ops->set_bus_param         = sh_csi2_set_bus_param;
+       icd->ops->query_bus_param       = sh_csi2_query_bus_param;
 
-               priv->set_bus_param             = icd->ops->set_bus_param;
-               priv->query_bus_param           = icd->ops->query_bus_param;
-               icd->ops->set_bus_param         = sh_csi2_set_bus_param;
-               icd->ops->query_bus_param       = sh_csi2_query_bus_param;
+       csi2_sd->grp_id = (long)icd;
 
-               pm_runtime_get_sync(v4l2_get_subdevdata(&priv->subdev));
+       pm_runtime_get_sync(dev);
 
-               sh_csi2_hwinit(priv);
-               break;
-       case BUS_NOTIFY_UNBIND_DRIVER:
-               priv->client = NULL;
+       sh_csi2_hwinit(priv);
 
-               /* Driver is about to be unbound */
-               icd->ops->set_bus_param         = priv->set_bus_param;
-               icd->ops->query_bus_param       = priv->query_bus_param;
-               priv->set_bus_param             = NULL;
-               priv->query_bus_param           = NULL;
+       return 0;
+}
 
-               v4l2_device_unregister_subdev(&priv->subdev);
+static void sh_csi2_client_disconnect(struct sh_csi2 *priv)
+{
+       struct soc_camera_device *icd = (struct soc_camera_device *)priv->subdev.grp_id;
 
-               pm_runtime_put(v4l2_get_subdevdata(&priv->subdev));
-               break;
-       }
+       priv->client = NULL;
+       priv->subdev.grp_id = 0;
 
-       return NOTIFY_OK;
+       /* Driver is about to be unbound */
+       icd->ops->set_bus_param         = priv->set_bus_param;
+       icd->ops->query_bus_param       = priv->query_bus_param;
+       priv->set_bus_param             = NULL;
+       priv->query_bus_param           = NULL;
+
+       pm_runtime_put(v4l2_get_subdevdata(&priv->subdev));
 }
 
+static int sh_csi2_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev);
+
+       if (on)
+               return sh_csi2_client_connect(priv);
+
+       sh_csi2_client_disconnect(priv);
+       return 0;
+}
+
+static struct v4l2_subdev_core_ops sh_csi2_subdev_core_ops = {
+       .s_power        = sh_csi2_s_power,
+};
+
+static struct v4l2_subdev_ops sh_csi2_subdev_ops = {
+       .core   = &sh_csi2_subdev_core_ops,
+       .video  = &sh_csi2_subdev_video_ops,
+};
+
 static __devinit int sh_csi2_probe(struct platform_device *pdev)
 {
        struct resource *res;
@@ -274,14 +286,6 @@ static __devinit int sh_csi2_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        priv->irq = irq;
-       priv->notifier.notifier_call = sh_csi2_notify;
-
-       /* We MUST attach after the MIPI sensor */
-       ret = bus_register_notifier(&soc_camera_bus_type, &priv->notifier);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "CSI2 cannot register notifier\n");
-               goto ernotify;
-       }
 
        if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
                dev_err(&pdev->dev, "CSI2 register region already claimed\n");
@@ -297,11 +301,17 @@ static __devinit int sh_csi2_probe(struct platform_device *pdev)
        }
 
        priv->pdev = pdev;
+       platform_set_drvdata(pdev, priv);
 
        v4l2_subdev_init(&priv->subdev, &sh_csi2_subdev_ops);
        v4l2_set_subdevdata(&priv->subdev, &pdev->dev);
 
-       platform_set_drvdata(pdev, priv);
+       snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s.mipi-csi",
+                dev_name(pdata->v4l2_dev->dev));
+       ret = v4l2_device_register_subdev(pdata->v4l2_dev, &priv->subdev);
+       dev_dbg(&pdev->dev, "%s(%p): ret(register_subdev) = %d\n", __func__, priv, ret);
+       if (ret < 0)
+               goto esdreg;
 
        pm_runtime_enable(&pdev->dev);
 
@@ -309,11 +319,11 @@ static __devinit int sh_csi2_probe(struct platform_device *pdev)
 
        return 0;
 
+esdreg:
+       iounmap(priv->base);
 eremap:
        release_mem_region(res->start, resource_size(res));
 ereqreg:
-       bus_unregister_notifier(&soc_camera_bus_type, &priv->notifier);
-ernotify:
        kfree(priv);
 
        return ret;
@@ -324,7 +334,7 @@ static __devexit int sh_csi2_remove(struct platform_device *pdev)
        struct sh_csi2 *priv = platform_get_drvdata(pdev);
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
-       bus_unregister_notifier(&soc_camera_bus_type, &priv->notifier);
+       v4l2_device_unregister_subdev(&priv->subdev);
        pm_runtime_disable(&pdev->dev);
        iounmap(priv->base);
        release_mem_region(res->start, resource_size(res));
@@ -335,8 +345,9 @@ static __devexit int sh_csi2_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver __refdata sh_csi2_pdrv = {
-       .remove  = __devexit_p(sh_csi2_remove),
-       .driver  = {
+       .remove = __devexit_p(sh_csi2_remove),
+       .probe  = sh_csi2_probe,
+       .driver = {
                .name   = "sh-mobile-csi2",
                .owner  = THIS_MODULE,
        },
@@ -344,7 +355,7 @@ static struct platform_driver __refdata sh_csi2_pdrv = {
 
 static int __init sh_csi2_init(void)
 {
-       return platform_driver_probe(&sh_csi2_pdrv, sh_csi2_probe);
+       return platform_driver_register(&sh_csi2_pdrv);
 }
 
 static void __exit sh_csi2_exit(void)
index 07cf0c6..6a72987 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
-#include <linux/version.h>
 #include <linux/videodev2.h>
 
 #include <media/sh_vou.h>
@@ -393,7 +392,6 @@ static int sh_vou_querycap(struct file *file, void  *priv,
        dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
 
        strlcpy(cap->card, "SuperH VOU", sizeof(cap->card));
-       cap->version = KERNEL_VERSION(0, 1, 0);
        cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
        return 0;
 }
@@ -1490,4 +1488,5 @@ module_exit(sh_vou_exit);
 MODULE_DESCRIPTION("SuperH VOU driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
 MODULE_LICENSE("GPL v2");
+MODULE_VERSION("0.1.0");
 MODULE_ALIAS("platform:sh-vou");
index cbfc444..22ea211 100644 (file)
@@ -21,7 +21,6 @@
 #ifndef _SN9C102_H_
 #define _SN9C102_H_
 
-#include <linux/version.h>
 #include <linux/usb.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
index 0e07c49..16cb07c 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/stat.h>
 #include <linux/mm.h>
 #include <linux/vmalloc.h>
+#include <linux/version.h>
 #include <linux/page-flags.h>
 #include <asm/byteorder.h>
 #include <asm/page.h>
@@ -47,8 +48,7 @@
 #define SN9C102_MODULE_AUTHOR   "(C) 2004-2007 Luca Risolia"
 #define SN9C102_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
 #define SN9C102_MODULE_LICENSE  "GPL"
-#define SN9C102_MODULE_VERSION  "1:1.47pre49"
-#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 47)
+#define SN9C102_MODULE_VERSION  "1:1.48"
 
 /*****************************************************************************/
 
@@ -2158,7 +2158,7 @@ sn9c102_vidioc_querycap(struct sn9c102_device* cam, void __user * arg)
 {
        struct v4l2_capability cap = {
                .driver = "sn9c102",
-               .version = SN9C102_MODULE_VERSION_CODE,
+               .version = LINUX_VERSION_CODE,
                .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
                                V4L2_CAP_STREAMING,
        };
@@ -3187,16 +3187,8 @@ static long sn9c102_ioctl_v4l2(struct file *filp,
        case VIDIOC_S_AUDIO:
                return sn9c102_vidioc_s_audio(cam, arg);
 
-       case VIDIOC_G_STD:
-       case VIDIOC_S_STD:
-       case VIDIOC_QUERYSTD:
-       case VIDIOC_ENUMSTD:
-       case VIDIOC_QUERYMENU:
-       case VIDIOC_ENUM_FRAMEINTERVALS:
-               return -EINVAL;
-
        default:
-               return -EINVAL;
+               return -ENOTTY;
 
        }
 }
index 4e4d412..5bdfe7e 100644 (file)
@@ -60,14 +60,14 @@ static int soc_camera_power_set(struct soc_camera_device *icd,
                ret = regulator_bulk_enable(icl->num_regulators,
                                            icl->regulators);
                if (ret < 0) {
-                       dev_err(&icd->dev, "Cannot enable regulators\n");
+                       dev_err(icd->pdev, "Cannot enable regulators\n");
                        return ret;
                }
 
                if (icl->power)
                        ret = icl->power(icd->pdev, power_on);
                if (ret < 0) {
-                       dev_err(&icd->dev,
+                       dev_err(icd->pdev,
                                "Platform failed to power-on the camera.\n");
 
                        regulator_bulk_disable(icl->num_regulators,
@@ -79,7 +79,7 @@ static int soc_camera_power_set(struct soc_camera_device *icd,
                if (icl->power)
                        ret = icl->power(icd->pdev, 0);
                if (ret < 0) {
-                       dev_err(&icd->dev,
+                       dev_err(icd->pdev,
                                "Platform failed to power-off the camera.\n");
                        return ret;
                }
@@ -87,7 +87,7 @@ static int soc_camera_power_set(struct soc_camera_device *icd,
                ret = regulator_bulk_disable(icl->num_regulators,
                                             icl->regulators);
                if (ret < 0) {
-                       dev_err(&icd->dev, "Cannot disable regulators\n");
+                       dev_err(icd->pdev, "Cannot disable regulators\n");
                        return ret;
                }
        }
@@ -147,11 +147,11 @@ EXPORT_SYMBOL(soc_camera_apply_sensor_flags);
 static int soc_camera_try_fmt(struct soc_camera_device *icd,
                              struct v4l2_format *f)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct v4l2_pix_format *pix = &f->fmt.pix;
        int ret;
 
-       dev_dbg(&icd->dev, "TRY_FMT(%c%c%c%c, %ux%u)\n",
+       dev_dbg(icd->pdev, "TRY_FMT(%c%c%c%c, %ux%u)\n",
                pixfmtstr(pix->pixelformat), pix->width, pix->height);
 
        pix->bytesperline = 0;
@@ -199,22 +199,15 @@ static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
 static int soc_camera_enum_input(struct file *file, void *priv,
                                 struct v4l2_input *inp)
 {
-       struct soc_camera_device *icd = file->private_data;
-       int ret = 0;
-
        if (inp->index != 0)
                return -EINVAL;
 
-       if (icd->ops->enum_input)
-               ret = icd->ops->enum_input(icd, inp);
-       else {
-               /* default is camera */
-               inp->type = V4L2_INPUT_TYPE_CAMERA;
-               inp->std  = V4L2_STD_UNKNOWN;
-               strcpy(inp->name, "Camera");
-       }
+       /* default is camera */
+       inp->type = V4L2_INPUT_TYPE_CAMERA;
+       inp->std  = V4L2_STD_UNKNOWN;
+       strcpy(inp->name, "Camera");
 
-       return ret;
+       return 0;
 }
 
 static int soc_camera_g_input(struct file *file, void *priv, unsigned int *i)
@@ -244,7 +237,7 @@ static int soc_camera_enum_fsizes(struct file *file, void *fh,
                                         struct v4l2_frmsizeenum *fsize)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
        return ici->ops->enum_fsizes(icd, fsize);
 }
@@ -254,7 +247,7 @@ static int soc_camera_reqbufs(struct file *file, void *priv,
 {
        int ret;
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
        WARN_ON(priv != file->private_data);
 
@@ -281,7 +274,7 @@ static int soc_camera_querybuf(struct file *file, void *priv,
                               struct v4l2_buffer *p)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
        WARN_ON(priv != file->private_data);
 
@@ -295,7 +288,7 @@ static int soc_camera_qbuf(struct file *file, void *priv,
                           struct v4l2_buffer *p)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
        WARN_ON(priv != file->private_data);
 
@@ -312,7 +305,7 @@ static int soc_camera_dqbuf(struct file *file, void *priv,
                            struct v4l2_buffer *p)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
        WARN_ON(priv != file->private_data);
 
@@ -329,7 +322,7 @@ static int soc_camera_dqbuf(struct file *file, void *priv,
 static int soc_camera_init_user_formats(struct soc_camera_device *icd)
 {
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        unsigned int i, fmts = 0, raw_fmts = 0;
        int ret;
        enum v4l2_mbus_pixelcode code;
@@ -363,7 +356,7 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd)
        if (!icd->user_formats)
                return -ENOMEM;
 
-       dev_dbg(&icd->dev, "Found %d supported formats.\n", fmts);
+       dev_dbg(icd->pdev, "Found %d supported formats.\n", fmts);
 
        /* Second pass - actually fill data formats */
        fmts = 0;
@@ -395,7 +388,7 @@ egfmt:
 /* Always entered with .video_lock held */
 static void soc_camera_free_user_formats(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
        if (ici->ops->put_formats)
                ici->ops->put_formats(icd);
@@ -409,11 +402,11 @@ static void soc_camera_free_user_formats(struct soc_camera_device *icd)
 static int soc_camera_set_fmt(struct soc_camera_device *icd,
                              struct v4l2_format *f)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct v4l2_pix_format *pix = &f->fmt.pix;
        int ret;
 
-       dev_dbg(&icd->dev, "S_FMT(%c%c%c%c, %ux%u)\n",
+       dev_dbg(icd->pdev, "S_FMT(%c%c%c%c, %ux%u)\n",
                pixfmtstr(pix->pixelformat), pix->width, pix->height);
 
        /* We always call try_fmt() before set_fmt() or set_crop() */
@@ -426,7 +419,7 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd,
                return ret;
        } else if (!icd->current_fmt ||
                   icd->current_fmt->host_fmt->fourcc != pix->pixelformat) {
-               dev_err(&icd->dev,
+               dev_err(icd->pdev,
                        "Host driver hasn't set up current format correctly!\n");
                return -EINVAL;
        }
@@ -440,7 +433,7 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd,
        if (ici->ops->init_videobuf)
                icd->vb_vidq.field = pix->field;
 
-       dev_dbg(&icd->dev, "set width: %d height: %d\n",
+       dev_dbg(icd->pdev, "set width: %d height: %d\n",
                icd->user_width, icd->user_height);
 
        /* set physical bus parameters */
@@ -450,9 +443,7 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd,
 static int soc_camera_open(struct file *file)
 {
        struct video_device *vdev = video_devdata(file);
-       struct soc_camera_device *icd = container_of(vdev->parent,
-                                                    struct soc_camera_device,
-                                                    dev);
+       struct soc_camera_device *icd = dev_get_drvdata(vdev->parent);
        struct soc_camera_link *icl = to_soc_camera_link(icd);
        struct soc_camera_host *ici;
        int ret;
@@ -461,10 +452,10 @@ static int soc_camera_open(struct file *file)
                /* No device driver attached */
                return -ENODEV;
 
-       ici = to_soc_camera_host(icd->dev.parent);
+       ici = to_soc_camera_host(icd->parent);
 
        if (!try_module_get(ici->ops->owner)) {
-               dev_err(&icd->dev, "Couldn't lock capture bus driver.\n");
+               dev_err(icd->pdev, "Couldn't lock capture bus driver.\n");
                return -EINVAL;
        }
 
@@ -495,7 +486,7 @@ static int soc_camera_open(struct file *file)
 
                ret = ici->ops->add(icd);
                if (ret < 0) {
-                       dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret);
+                       dev_err(icd->pdev, "Couldn't activate the camera: %d\n", ret);
                        goto eiciadd;
                }
 
@@ -524,7 +515,7 @@ static int soc_camera_open(struct file *file)
        }
 
        file->private_data = icd;
-       dev_dbg(&icd->dev, "camera device open\n");
+       dev_dbg(icd->pdev, "camera device open\n");
 
        return 0;
 
@@ -549,7 +540,7 @@ epower:
 static int soc_camera_close(struct file *file)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
        icd->use_count--;
        if (!icd->use_count) {
@@ -570,7 +561,7 @@ static int soc_camera_close(struct file *file)
 
        module_put(ici->ops->owner);
 
-       dev_dbg(&icd->dev, "camera device close\n");
+       dev_dbg(icd->pdev, "camera device close\n");
 
        return 0;
 }
@@ -581,7 +572,7 @@ static ssize_t soc_camera_read(struct file *file, char __user *buf,
        struct soc_camera_device *icd = file->private_data;
        int err = -EINVAL;
 
-       dev_err(&icd->dev, "camera device read not implemented\n");
+       dev_err(icd->pdev, "camera device read not implemented\n");
 
        return err;
 }
@@ -589,10 +580,10 @@ static ssize_t soc_camera_read(struct file *file, char __user *buf,
 static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        int err;
 
-       dev_dbg(&icd->dev, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
+       dev_dbg(icd->pdev, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
 
        if (icd->streamer != file)
                return -EBUSY;
@@ -602,7 +593,7 @@ static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma)
        else
                err = vb2_mmap(&icd->vb2_vidq, vma);
 
-       dev_dbg(&icd->dev, "vma start=0x%08lx, size=%ld, ret=%d\n",
+       dev_dbg(icd->pdev, "vma start=0x%08lx, size=%ld, ret=%d\n",
                (unsigned long)vma->vm_start,
                (unsigned long)vma->vm_end - (unsigned long)vma->vm_start,
                err);
@@ -613,13 +604,13 @@ static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma)
 static unsigned int soc_camera_poll(struct file *file, poll_table *pt)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
        if (icd->streamer != file)
                return -EBUSY;
 
        if (ici->ops->init_videobuf && list_empty(&icd->vb_vidq.stream)) {
-               dev_err(&icd->dev, "Trying to poll with no queued buffers!\n");
+               dev_err(icd->pdev, "Trying to poll with no queued buffers!\n");
                return POLLERR;
        }
 
@@ -659,15 +650,15 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
        WARN_ON(priv != file->private_data);
 
        if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               dev_warn(&icd->dev, "Wrong buf-type %d\n", f->type);
+               dev_warn(icd->pdev, "Wrong buf-type %d\n", f->type);
                return -EINVAL;
        }
 
        if (icd->streamer && icd->streamer != file)
                return -EBUSY;
 
-       if (is_streaming(to_soc_camera_host(icd->dev.parent), icd)) {
-               dev_err(&icd->dev, "S_FMT denied: queue initialised\n");
+       if (is_streaming(to_soc_camera_host(icd->parent), icd)) {
+               dev_err(icd->pdev, "S_FMT denied: queue initialised\n");
                return -EBUSY;
        }
 
@@ -716,7 +707,7 @@ static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
        pix->field              = icd->field;
        pix->pixelformat        = icd->current_fmt->host_fmt->fourcc;
        pix->colorspace         = icd->colorspace;
-       dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n",
+       dev_dbg(icd->pdev, "current_fmt->fourcc: 0x%08x\n",
                icd->current_fmt->host_fmt->fourcc);
        return 0;
 }
@@ -725,7 +716,7 @@ static int soc_camera_querycap(struct file *file, void  *priv,
                               struct v4l2_capability *cap)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
        WARN_ON(priv != file->private_data);
 
@@ -737,7 +728,7 @@ static int soc_camera_streamon(struct file *file, void *priv,
                               enum v4l2_buf_type i)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        int ret;
 
@@ -766,7 +757,7 @@ static int soc_camera_streamoff(struct file *file, void *priv,
 {
        struct soc_camera_device *icd = file->private_data;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
        WARN_ON(priv != file->private_data);
 
@@ -794,7 +785,7 @@ static int soc_camera_queryctrl(struct file *file, void *priv,
                                struct v4l2_queryctrl *qc)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        int i;
 
        WARN_ON(priv != file->private_data);
@@ -825,7 +816,7 @@ static int soc_camera_g_ctrl(struct file *file, void *priv,
                             struct v4l2_control *ctrl)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        int ret;
 
@@ -844,7 +835,7 @@ static int soc_camera_s_ctrl(struct file *file, void *priv,
                             struct v4l2_control *ctrl)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        int ret;
 
@@ -863,7 +854,7 @@ static int soc_camera_cropcap(struct file *file, void *fh,
                              struct v4l2_cropcap *a)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
        return ici->ops->cropcap(icd, a);
 }
@@ -872,7 +863,7 @@ static int soc_camera_g_crop(struct file *file, void *fh,
                             struct v4l2_crop *a)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        int ret;
 
        ret = ici->ops->get_crop(icd, a);
@@ -889,7 +880,7 @@ static int soc_camera_s_crop(struct file *file, void *fh,
                             struct v4l2_crop *a)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct v4l2_rect *rect = &a->c;
        struct v4l2_crop current_crop;
        int ret;
@@ -897,7 +888,7 @@ static int soc_camera_s_crop(struct file *file, void *fh,
        if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
-       dev_dbg(&icd->dev, "S_CROP(%ux%u@%u:%u)\n",
+       dev_dbg(icd->pdev, "S_CROP(%ux%u@%u:%u)\n",
                rect->width, rect->height, rect->left, rect->top);
 
        /* If get_crop fails, we'll let host and / or client drivers decide */
@@ -905,7 +896,7 @@ static int soc_camera_s_crop(struct file *file, void *fh,
 
        /* Prohibit window size change with initialised buffers */
        if (ret < 0) {
-               dev_err(&icd->dev,
+               dev_err(icd->pdev,
                        "S_CROP denied: getting current crop failed\n");
        } else if ((a->c.width == current_crop.c.width &&
                    a->c.height == current_crop.c.height) ||
@@ -915,7 +906,7 @@ static int soc_camera_s_crop(struct file *file, void *fh,
        } else if (ici->ops->set_livecrop) {
                ret = ici->ops->set_livecrop(icd, a);
        } else {
-               dev_err(&icd->dev,
+               dev_err(icd->pdev,
                        "S_CROP denied: queue initialised and sizes differ\n");
                ret = -EBUSY;
        }
@@ -927,7 +918,7 @@ static int soc_camera_g_parm(struct file *file, void *fh,
                             struct v4l2_streamparm *a)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
        if (ici->ops->get_parm)
                return ici->ops->get_parm(icd, a);
@@ -939,7 +930,7 @@ static int soc_camera_s_parm(struct file *file, void *fh,
                             struct v4l2_streamparm *a)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
        if (ici->ops->set_parm)
                return ici->ops->set_parm(icd, a);
@@ -976,6 +967,8 @@ static int soc_camera_s_register(struct file *file, void *fh,
 }
 #endif
 
+static int soc_camera_probe(struct soc_camera_device *icd);
+
 /* So far this function cannot fail */
 static void scan_add_host(struct soc_camera_host *ici)
 {
@@ -986,15 +979,9 @@ static void scan_add_host(struct soc_camera_host *ici)
        list_for_each_entry(icd, &devices, list) {
                if (icd->iface == ici->nr) {
                        int ret;
-                       icd->dev.parent = ici->v4l2_dev.dev;
-                       dev_set_name(&icd->dev, "%u-%u", icd->iface,
-                                    icd->devnum);
-                       ret = device_register(&icd->dev);
-                       if (ret < 0) {
-                               icd->dev.parent = NULL;
-                               dev_err(&icd->dev,
-                                       "Cannot register device: %d\n", ret);
-                       }
+
+                       icd->parent = ici->v4l2_dev.dev;
+                       ret = soc_camera_probe(icd);
                }
        }
 
@@ -1006,12 +993,12 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd,
                               struct soc_camera_link *icl)
 {
        struct i2c_client *client;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct i2c_adapter *adap = i2c_get_adapter(icl->i2c_adapter_id);
        struct v4l2_subdev *subdev;
 
        if (!adap) {
-               dev_err(&icd->dev, "Cannot get I2C adapter #%d. No driver?\n",
+               dev_err(icd->pdev, "Cannot get I2C adapter #%d. No driver?\n",
                        icl->i2c_adapter_id);
                goto ei2cga;
        }
@@ -1026,7 +1013,7 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd,
        client = v4l2_get_subdevdata(subdev);
 
        /* Use to_i2c_client(dev) to recover the i2c client */
-       dev_set_drvdata(&icd->dev, &client->dev);
+       icd->control = &client->dev;
 
        return 0;
 ei2cnd:
@@ -1040,7 +1027,8 @@ static void soc_camera_free_i2c(struct soc_camera_device *icd)
        struct i2c_client *client =
                to_i2c_client(to_soc_camera_control(icd));
        struct i2c_adapter *adap = client->adapter;
-       dev_set_drvdata(&icd->dev, NULL);
+
+       icd->control = NULL;
        v4l2_device_unregister_subdev(i2c_get_clientdata(client));
        i2c_unregister_device(client);
        i2c_put_adapter(adap);
@@ -1053,17 +1041,16 @@ static void soc_camera_free_i2c(struct soc_camera_device *icd)
 static int soc_camera_video_start(struct soc_camera_device *icd);
 static int video_dev_create(struct soc_camera_device *icd);
 /* Called during host-driver probe */
-static int soc_camera_probe(struct device *dev)
+static int soc_camera_probe(struct soc_camera_device *icd)
 {
-       struct soc_camera_device *icd = to_soc_camera_dev(dev);
-       struct soc_camera_host *ici = to_soc_camera_host(dev->parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct soc_camera_link *icl = to_soc_camera_link(icd);
        struct device *control = NULL;
        struct v4l2_subdev *sd;
        struct v4l2_mbus_framefmt mf;
        int ret;
 
-       dev_info(dev, "Probing %s\n", dev_name(dev));
+       dev_info(icd->pdev, "Probing %s\n", dev_name(icd->pdev));
 
        ret = regulator_bulk_get(icd->pdev, icl->num_regulators,
                                 icl->regulators);
@@ -1099,7 +1086,7 @@ static int soc_camera_probe(struct device *dev)
                if (icl->module_name)
                        ret = request_module(icl->module_name);
 
-               ret = icl->add_device(icl, &icd->dev);
+               ret = icl->add_device(icd);
                if (ret < 0)
                        goto eadddev;
 
@@ -1110,7 +1097,7 @@ static int soc_camera_probe(struct device *dev)
                control = to_soc_camera_control(icd);
                if (!control || !control->driver || !dev_get_drvdata(control) ||
                    !try_module_get(control->driver->owner)) {
-                       icl->del_device(icl);
+                       icl->del_device(icd);
                        goto enodrv;
                }
        }
@@ -1125,8 +1112,6 @@ static int soc_camera_probe(struct device *dev)
 
        icd->field = V4L2_FIELD_ANY;
 
-       icd->vdev->lock = &icd->video_lock;
-
        /*
         * ..._video_start() will create a device node, video_register_device()
         * itself is protected against concurrent open() calls, but we also have
@@ -1146,11 +1131,6 @@ static int soc_camera_probe(struct device *dev)
                icd->field              = mf.field;
        }
 
-       /* Do we have to sysfs_remove_link() before device_unregister()? */
-       if (sysfs_create_link(&icd->dev.kobj, &to_soc_camera_control(icd)->kobj,
-                             "control"))
-               dev_warn(&icd->dev, "Failed creating the control symlink\n");
-
        ici->ops->remove(icd);
 
        soc_camera_power_set(icd, icl, 0);
@@ -1166,7 +1146,7 @@ eiufmt:
        if (icl->board_info) {
                soc_camera_free_i2c(icd);
        } else {
-               icl->del_device(icl);
+               icl->del_device(icd);
                module_put(control->driver->owner);
        }
 enodrv:
@@ -1186,13 +1166,12 @@ ereg:
  * This is called on device_unregister, which only means we have to disconnect
  * from the host, but not remove ourselves from the device list
  */
-static int soc_camera_remove(struct device *dev)
+static int soc_camera_remove(struct soc_camera_device *icd)
 {
-       struct soc_camera_device *icd = to_soc_camera_dev(dev);
        struct soc_camera_link *icl = to_soc_camera_link(icd);
        struct video_device *vdev = icd->vdev;
 
-       BUG_ON(!dev->parent);
+       BUG_ON(!icd->parent);
 
        if (vdev) {
                video_unregister_device(vdev);
@@ -1202,10 +1181,9 @@ static int soc_camera_remove(struct device *dev)
        if (icl->board_info) {
                soc_camera_free_i2c(icd);
        } else {
-               struct device_driver *drv = to_soc_camera_control(icd) ?
-                       to_soc_camera_control(icd)->driver : NULL;
+               struct device_driver *drv = to_soc_camera_control(icd)->driver;
                if (drv) {
-                       icl->del_device(icl);
+                       icl->del_device(icd);
                        module_put(drv->owner);
                }
        }
@@ -1216,49 +1194,6 @@ static int soc_camera_remove(struct device *dev)
        return 0;
 }
 
-static int soc_camera_suspend(struct device *dev, pm_message_t state)
-{
-       struct soc_camera_device *icd = to_soc_camera_dev(dev);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
-       int ret = 0;
-
-       if (ici->ops->suspend)
-               ret = ici->ops->suspend(icd, state);
-
-       return ret;
-}
-
-static int soc_camera_resume(struct device *dev)
-{
-       struct soc_camera_device *icd = to_soc_camera_dev(dev);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
-       int ret = 0;
-
-       if (ici->ops->resume)
-               ret = ici->ops->resume(icd);
-
-       return ret;
-}
-
-struct bus_type soc_camera_bus_type = {
-       .name           = "soc-camera",
-       .probe          = soc_camera_probe,
-       .remove         = soc_camera_remove,
-       .suspend        = soc_camera_suspend,
-       .resume         = soc_camera_resume,
-};
-EXPORT_SYMBOL_GPL(soc_camera_bus_type);
-
-static struct device_driver ic_drv = {
-       .name   = "camera",
-       .bus    = &soc_camera_bus_type,
-       .owner  = THIS_MODULE,
-};
-
-static void dummy_release(struct device *dev)
-{
-}
-
 static int default_cropcap(struct soc_camera_device *icd,
                           struct v4l2_cropcap *a)
 {
@@ -1317,13 +1252,6 @@ static int default_enum_fsizes(struct soc_camera_device *icd,
        return 0;
 }
 
-static void soc_camera_device_init(struct device *dev, void *pdata)
-{
-       dev->platform_data      = pdata;
-       dev->bus                = &soc_camera_bus_type;
-       dev->release            = dummy_release;
-}
-
 int soc_camera_host_register(struct soc_camera_host *ici)
 {
        struct soc_camera_host *ix;
@@ -1389,24 +1317,9 @@ void soc_camera_host_unregister(struct soc_camera_host *ici)
        mutex_lock(&list_lock);
 
        list_del(&ici->list);
-
-       list_for_each_entry(icd, &devices, list) {
-               if (icd->iface == ici->nr) {
-                       void *pdata = icd->dev.platform_data;
-                       /* The bus->remove will be called */
-                       device_unregister(&icd->dev);
-                       /*
-                        * Not before device_unregister(), .remove
-                        * needs parent to call ici->ops->remove().
-                        * If the host module is loaded again, device_register()
-                        * would complain "already initialised," since 2.6.32
-                        * this is also needed to prevent use-after-free of the
-                        * device private data.
-                        */
-                       memset(&icd->dev, 0, sizeof(icd->dev));
-                       soc_camera_device_init(&icd->dev, pdata);
-               }
-       }
+       list_for_each_entry(icd, &devices, list)
+               if (icd->iface == ici->nr && to_soc_camera_control(icd))
+                       soc_camera_remove(icd);
 
        mutex_unlock(&list_lock);
 
@@ -1448,11 +1361,6 @@ static int soc_camera_device_register(struct soc_camera_device *icd)
        return 0;
 }
 
-static void soc_camera_device_unregister(struct soc_camera_device *icd)
-{
-       list_del(&icd->list);
-}
-
 static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
        .vidioc_querycap         = soc_camera_querycap,
        .vidioc_g_fmt_vid_cap    = soc_camera_g_fmt_vid_cap,
@@ -1487,7 +1395,7 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
 
 static int video_dev_create(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct video_device *vdev = video_device_alloc();
 
        if (!vdev)
@@ -1495,12 +1403,13 @@ static int video_dev_create(struct soc_camera_device *icd)
 
        strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));
 
-       vdev->parent            = &icd->dev;
+       vdev->parent            = icd->pdev;
        vdev->current_norm      = V4L2_STD_UNKNOWN;
        vdev->fops              = &soc_camera_fops;
        vdev->ioctl_ops         = &soc_camera_ioctl_ops;
        vdev->release           = video_device_release;
        vdev->tvnorms           = V4L2_STD_UNKNOWN;
+       vdev->lock              = &icd->video_lock;
 
        icd->vdev = vdev;
 
@@ -1515,7 +1424,7 @@ static int soc_camera_video_start(struct soc_camera_device *icd)
        const struct device_type *type = icd->vdev->dev.type;
        int ret;
 
-       if (!icd->dev.parent)
+       if (!icd->parent)
                return -ENODEV;
 
        if (!icd->ops ||
@@ -1525,7 +1434,7 @@ static int soc_camera_video_start(struct soc_camera_device *icd)
 
        ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, -1);
        if (ret < 0) {
-               dev_err(&icd->dev, "video_register_device failed: %d\n", ret);
+               dev_err(icd->pdev, "video_register_device failed: %d\n", ret);
                return ret;
        }
 
@@ -1549,6 +1458,7 @@ static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        icd->iface = icl->bus_id;
+       icd->link = icl;
        icd->pdev = &pdev->dev;
        platform_set_drvdata(pdev, icd);
 
@@ -1556,8 +1466,6 @@ static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev)
        if (ret < 0)
                goto escdevreg;
 
-       soc_camera_device_init(&icd->dev, icl);
-
        icd->user_width         = DEFAULT_WIDTH;
        icd->user_height        = DEFAULT_HEIGHT;
 
@@ -1581,7 +1489,7 @@ static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev)
        if (!icd)
                return -EINVAL;
 
-       soc_camera_device_unregister(icd);
+       list_del(&icd->list);
 
        kfree(icd);
 
@@ -1598,31 +1506,12 @@ static struct platform_driver __refdata soc_camera_pdrv = {
 
 static int __init soc_camera_init(void)
 {
-       int ret = bus_register(&soc_camera_bus_type);
-       if (ret)
-               return ret;
-       ret = driver_register(&ic_drv);
-       if (ret)
-               goto edrvr;
-
-       ret = platform_driver_probe(&soc_camera_pdrv, soc_camera_pdrv_probe);
-       if (ret)
-               goto epdr;
-
-       return 0;
-
-epdr:
-       driver_unregister(&ic_drv);
-edrvr:
-       bus_unregister(&soc_camera_bus_type);
-       return ret;
+       return platform_driver_probe(&soc_camera_pdrv, soc_camera_pdrv_probe);
 }
 
 static void __exit soc_camera_exit(void)
 {
        platform_driver_unregister(&soc_camera_pdrv);
-       driver_unregister(&ic_drv);
-       bus_unregister(&soc_camera_bus_type);
 }
 
 module_init(soc_camera_init);
index bf406e8..8069cd6 100644 (file)
@@ -146,7 +146,7 @@ static int soc_camera_platform_probe(struct platform_device *pdev)
        if (!p)
                return -EINVAL;
 
-       if (!p->dev) {
+       if (!p->icd) {
                dev_err(&pdev->dev,
                        "Platform has not set soc_camera_device pointer!\n");
                return -EINVAL;
@@ -156,16 +156,16 @@ static int soc_camera_platform_probe(struct platform_device *pdev)
        if (!priv)
                return -ENOMEM;
 
-       icd = to_soc_camera_dev(p->dev);
+       icd = p->icd;
 
        /* soc-camera convention: control's drvdata points to the subdev */
        platform_set_drvdata(pdev, &priv->subdev);
        /* Set the control device reference */
-       dev_set_drvdata(&icd->dev, &pdev->dev);
+       icd->control = &pdev->dev;
 
        icd->ops = &soc_camera_platform_ops;
 
-       ici = to_soc_camera_host(icd->dev.parent);
+       ici = to_soc_camera_host(icd->parent);
 
        v4l2_subdev_init(&priv->subdev, &platform_subdev_ops);
        v4l2_set_subdevdata(&priv->subdev, p);
@@ -188,7 +188,7 @@ static int soc_camera_platform_remove(struct platform_device *pdev)
 {
        struct soc_camera_platform_priv *priv = get_priv(pdev);
        struct soc_camera_platform_info *p = pdev->dev.platform_data;
-       struct soc_camera_device *icd = to_soc_camera_dev(p->dev);
+       struct soc_camera_device *icd = p->icd;
 
        v4l2_device_unregister_subdev(&priv->subdev);
        icd->ops = NULL;
index c901721..8afb0e8 100644 (file)
@@ -726,8 +726,10 @@ static int sr030pc30_s_power(struct v4l2_subdev *sd, int on)
        const struct sr030pc30_platform_data *pdata = info->pdata;
        int ret;
 
-       if (WARN(pdata == NULL, "No platform data!\n"))
-               return -ENOMEM;
+       if (pdata == NULL) {
+               WARN(1, "No platform data!\n");
+               return -EINVAL;
+       }
 
        /*
         * Put sensor into power sleep mode before switching off
@@ -746,6 +748,7 @@ static int sr030pc30_s_power(struct v4l2_subdev *sd, int on)
        if (on) {
                ret = sr030pc30_base_config(sd);
        } else {
+               ret = 0;
                info->curr_win = NULL;
                info->curr_fmt = NULL;
        }
index 3941f95..bd21854 100644 (file)
@@ -49,10 +49,11 @@ static int maxvol;
 static int loudness; /* disable loudness by default */
 static int debug;       /* insmod parameter */
 module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Set debugging level from 0 to 3. Default is off(0).");
 module_param(loudness, int, S_IRUGO);
-MODULE_PARM_DESC(maxvol,"Set maximium volume to +20db (0), default is 0db(1)");
+MODULE_PARM_DESC(loudness, "Turn loudness on(1) else off(0). Default is off(0).");
 module_param(maxvol, int, S_IRUGO | S_IWUSR);
-
+MODULE_PARM_DESC(maxvol, "Set maximium volume to +20dB(0) else +0dB(1). Default is +20dB(0).");
 
 
 /* Structure of address and subaddresses for the tda7432 */
index fc611eb..84cd1b6 100644 (file)
@@ -20,7 +20,6 @@
  * Timberdale FPGA LogiWin Video In
  */
 
-#include <linux/version.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/dmaengine.h>
index 46066bd..56564e6 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef PD_COMMON_H
 #define PD_COMMON_H
 
-#include <linux/version.h>
 #include <linux/fs.h>
 #include <linux/wait.h>
 #include <linux/list.h>
index 99c81a9..129f135 100644 (file)
@@ -531,3 +531,4 @@ module_exit(poseidon_exit);
 MODULE_AUTHOR("Telegent Systems");
 MODULE_DESCRIPTION("For tlg2300-based USB device ");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.2");
index fae84c2..4fad1df 100644 (file)
@@ -6,7 +6,6 @@
 #include <linux/usb.h>
 #include <linux/i2c.h>
 #include <media/v4l2-dev.h>
-#include <linux/version.h>
 #include <linux/mm.h>
 #include <linux/mutex.h>
 #include <media/v4l2-ioctl.h>
@@ -149,7 +148,6 @@ static int vidioc_querycap(struct file *file, void *priv,
        strlcpy(v->driver, "tele-radio", sizeof(v->driver));
        strlcpy(v->card, "Telegent Poseidon", sizeof(v->card));
        usb_make_path(p->udev, v->bus_info, sizeof(v->bus_info));
-       v->version = KERNEL_VERSION(0, 0, 1);
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
index a03945a..11cc980 100644 (file)
@@ -39,6 +39,7 @@
 #include "tda9887.h"
 #include "xc5000.h"
 #include "tda18271.h"
+#include "xc4000.h"
 
 #define UNSET (-1U)
 
@@ -391,6 +392,23 @@ static void set_type(struct i2c_client *c, unsigned int type,
                tune_now = 0;
                break;
        }
+       case TUNER_XC4000:
+       {
+               struct xc4000_config xc4000_cfg = {
+                       .i2c_address      = t->i2c->addr,
+                       /* FIXME: the correct parameters will be set */
+                       /* only when the digital dvb_attach() occurs */
+                       .default_pm       = 0,
+                       .dvb_amplitude    = 0,
+                       .set_smoothedcvbs = 0,
+                       .if_khz           = 0
+               };
+               if (!dvb_attach(xc4000_attach,
+                               &t->fe, t->i2c->adapter, &xc4000_cfg))
+                       goto attach_failed;
+               tune_now = 0;
+               break;
+       }
        default:
                if (!dvb_attach(simple_tuner_attach, &t->fe,
                                t->i2c->adapter, t->i2c->addr, t->type))
index 0347bbe..742482e 100644 (file)
@@ -552,16 +552,6 @@ static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
        return ret;
 }
 
-static int tw9910_enum_input(struct soc_camera_device *icd,
-                            struct v4l2_input *inp)
-{
-       inp->type = V4L2_INPUT_TYPE_TUNER;
-       inp->std  = V4L2_STD_UNKNOWN;
-       strcpy(inp->name, "Video");
-
-       return 0;
-}
-
 static int tw9910_g_chip_ident(struct v4l2_subdev *sd,
                               struct v4l2_dbg_chip_ident *id)
 {
@@ -846,13 +836,9 @@ static int tw9910_video_probe(struct soc_camera_device *icd,
        struct tw9910_priv *priv = to_tw9910(client);
        s32 id;
 
-       /*
-        * We must have a parent by now. And it cannot be a wrong one.
-        * So this entire test is completely redundant.
-        */
-       if (!icd->dev.parent ||
-           to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
-               return -ENODEV;
+       /* We must have a parent by now. And it cannot be a wrong one. */
+       BUG_ON(!icd->parent ||
+              to_soc_camera_host(icd->parent)->nr != icd->iface);
 
        /*
         * tw9910 only use 8 or 16 bit bus width
@@ -891,7 +877,6 @@ static int tw9910_video_probe(struct soc_camera_device *icd,
 static struct soc_camera_ops tw9910_ops = {
        .set_bus_param          = tw9910_set_bus_param,
        .query_bus_param        = tw9910_query_bus_param,
-       .enum_input             = tw9910_enum_input,
 };
 
 static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = {
index ea8ea8a..5a74f5e 100644 (file)
@@ -45,7 +45,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/timer.h>
 #define DRIVER_ALIAS "USBVision"
 #define DRIVER_DESC "USBVision USB Video Device Driver for Linux"
 #define DRIVER_LICENSE "GPL"
-#define USBVISION_DRIVER_VERSION_MAJOR 0
-#define USBVISION_DRIVER_VERSION_MINOR 9
-#define USBVISION_DRIVER_VERSION_PATCHLEVEL 10
-#define USBVISION_DRIVER_VERSION KERNEL_VERSION(USBVISION_DRIVER_VERSION_MAJOR,\
-USBVISION_DRIVER_VERSION_MINOR,\
-USBVISION_DRIVER_VERSION_PATCHLEVEL)
-#define USBVISION_VERSION_STRING __stringify(USBVISION_DRIVER_VERSION_MAJOR) \
-"." __stringify(USBVISION_DRIVER_VERSION_MINOR) \
-"." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL)
+#define USBVISION_VERSION_STRING "0.9.11"
 
 #define        ENABLE_HEXDUMP  0       /* Enable if you need it */
 
@@ -516,7 +507,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
                usbvision_device_data[usbvision->dev_model].model_string,
                sizeof(vc->card));
        usb_make_path(usbvision->dev, vc->bus_info, sizeof(vc->bus_info));
-       vc->version = USBVISION_DRIVER_VERSION;
        vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
                V4L2_CAP_AUDIO |
                V4L2_CAP_READWRITE |
index 2c8954e..10c2364 100644 (file)
@@ -1664,8 +1664,8 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
                return -EINVAL;
        }
 
-       /* Search for the matching (GUID/CS) control in the given device */
-       list_for_each_entry(entity, &dev->entities, list) {
+       /* Search for the matching (GUID/CS) control on the current chain */
+       list_for_each_entry(entity, &chain->entities, chain) {
                unsigned int i;
 
                if (UVC_ENTITY_TYPE(entity) != UVC_VC_EXTENSION_UNIT ||
index b6eae48..d29f9c2 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/videodev2.h>
 #include <linux/vmalloc.h>
 #include <linux/wait.h>
+#include <linux/version.h>
 #include <asm/atomic.h>
 #include <asm/unaligned.h>
 
@@ -1857,7 +1858,7 @@ static int uvc_probe(struct usb_interface *intf,
                        sizeof(dev->mdev.serial));
        strcpy(dev->mdev.bus_info, udev->devpath);
        dev->mdev.hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
-       dev->mdev.driver_version = DRIVER_VERSION_NUMBER;
+       dev->mdev.driver_version = LINUX_VERSION_CODE;
        if (media_device_register(&dev->mdev) < 0)
                goto error;
 
@@ -2130,6 +2131,15 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_PROBE_MINMAX
                                | UVC_QUIRK_BUILTIN_ISIGHT },
+       /* Foxlink ("HP Webcam" on HP Mini 5103) */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x05c8,
+         .idProduct            = 0x0403,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_FIX_BANDWIDTH },
        /* Genesys Logic USB 2.0 PC Camera */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
index dde6533..ea71d5f 100644 (file)
@@ -83,7 +83,7 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain,
        default:
                uvc_trace(UVC_TRACE_CONTROL, "Unsupported V4L2 control type "
                          "%u.\n", xmap->v4l2_type);
-               ret = -EINVAL;
+               ret = -ENOTTY;
                goto done;
        }
 
@@ -571,7 +571,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                strlcpy(cap->card, vdev->name, sizeof cap->card);
                usb_make_path(stream->dev->udev,
                              cap->bus_info, sizeof(cap->bus_info));
-               cap->version = DRIVER_VERSION_NUMBER;
+               cap->version = LINUX_VERSION_CODE;
                if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
                        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
                                          | V4L2_CAP_STREAMING;
index 20107fd..df32a43 100644 (file)
@@ -183,8 +183,7 @@ struct uvc_xu_control {
  * Driver specific constants.
  */
 
-#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(1, 1, 0)
-#define DRIVER_VERSION         "v1.1.0"
+#define DRIVER_VERSION         "1.1.1"
 
 /* Number of isochronous URBs. */
 #define UVC_URBS               5
index 06b9f9f..5c6100f 100644 (file)
@@ -105,6 +105,9 @@ int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
                    menu_items[ctrl->value][0] == '\0')
                        return -EINVAL;
        }
+       if (qctrl->type == V4L2_CTRL_TYPE_BITMASK &&
+                       (ctrl->value & ~qctrl->maximum))
+               return -ERANGE;
        return 0;
 }
 EXPORT_SYMBOL(v4l2_ctrl_check);
index 7c26947..61979b7 100644 (file)
@@ -662,6 +662,32 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
        return 0;
 }
 
+struct v4l2_event32 {
+       __u32                           type;
+       union {
+               __u8                    data[64];
+       } u;
+       __u32                           pending;
+       __u32                           sequence;
+       struct compat_timespec          timestamp;
+       __u32                           id;
+       __u32                           reserved[8];
+};
+
+static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up)
+{
+       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_event32)) ||
+               put_user(kp->type, &up->type) ||
+               copy_to_user(&up->u, &kp->u, sizeof(kp->u)) ||
+               put_user(kp->pending, &up->pending) ||
+               put_user(kp->sequence, &up->sequence) ||
+               put_compat_timespec(&kp->timestamp, &up->timestamp) ||
+               put_user(kp->id, &up->id) ||
+               copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32)))
+                       return -EFAULT;
+       return 0;
+}
+
 #define VIDIOC_G_FMT32         _IOWR('V',  4, struct v4l2_format32)
 #define VIDIOC_S_FMT32         _IOWR('V',  5, struct v4l2_format32)
 #define VIDIOC_QUERYBUF32      _IOWR('V',  9, struct v4l2_buffer32)
@@ -675,6 +701,7 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
 #define VIDIOC_G_EXT_CTRLS32    _IOWR('V', 71, struct v4l2_ext_controls32)
 #define VIDIOC_S_EXT_CTRLS32    _IOWR('V', 72, struct v4l2_ext_controls32)
 #define VIDIOC_TRY_EXT_CTRLS32  _IOWR('V', 73, struct v4l2_ext_controls32)
+#define        VIDIOC_DQEVENT32        _IOR ('V', 89, struct v4l2_event32)
 
 #define VIDIOC_OVERLAY32       _IOW ('V', 14, s32)
 #define VIDIOC_STREAMON32      _IOW ('V', 18, s32)
@@ -693,6 +720,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
                struct v4l2_input v2i;
                struct v4l2_standard v2s;
                struct v4l2_ext_controls v2ecs;
+               struct v4l2_event v2ev;
                unsigned long vx;
                int vi;
        } karg;
@@ -715,6 +743,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
        case VIDIOC_G_EXT_CTRLS32: cmd = VIDIOC_G_EXT_CTRLS; break;
        case VIDIOC_S_EXT_CTRLS32: cmd = VIDIOC_S_EXT_CTRLS; break;
        case VIDIOC_TRY_EXT_CTRLS32: cmd = VIDIOC_TRY_EXT_CTRLS; break;
+       case VIDIOC_DQEVENT32: cmd = VIDIOC_DQEVENT; break;
        case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break;
        case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break;
        case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
@@ -778,6 +807,9 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
                err = get_v4l2_ext_controls32(&karg.v2ecs, up);
                compatible_arg = 0;
                break;
+       case VIDIOC_DQEVENT:
+               compatible_arg = 0;
+               break;
        }
        if (err)
                return err;
@@ -818,6 +850,10 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
                err = put_v4l2_framebuffer32(&karg.v2fb, up);
                break;
 
+       case VIDIOC_DQEVENT:
+               err = put_v4l2_event32(&karg.v2ev, up);
+               break;
+
        case VIDIOC_G_FMT:
        case VIDIOC_S_FMT:
        case VIDIOC_TRY_FMT:
@@ -920,6 +956,7 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
        case VIDIOC_S_DV_TIMINGS:
        case VIDIOC_G_DV_TIMINGS:
        case VIDIOC_DQEVENT:
+       case VIDIOC_DQEVENT32:
        case VIDIOC_SUBSCRIBE_EVENT:
        case VIDIOC_UNSUBSCRIBE_EVENT:
                ret = do_video_ioctl(file, cmd, arg);
index 2412f08..06b6014 100644 (file)
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
 #include <media/v4l2-dev.h>
 
+#define has_op(master, op) \
+       (master->ops && master->ops->op)
+#define call_op(master, op) \
+       (has_op(master, op) ? master->ops->op(master) : 0)
+
 /* Internal temporary helper struct, one for each v4l2_ext_control */
-struct ctrl_helper {
+struct v4l2_ctrl_helper {
+       /* Pointer to the control reference of the master control */
+       struct v4l2_ctrl_ref *mref;
        /* The control corresponding to the v4l2_ext_control ID field. */
        struct v4l2_ctrl *ctrl;
-       /* Used internally to mark whether this control was already
-          processed. */
-       bool handled;
+       /* v4l2_ext_control index of the next control belonging to the
+          same cluster, or 0 if there isn't any. */
+       u32 next;
 };
 
+/* Small helper function to determine if the autocluster is set to manual
+   mode. In that case the is_volatile flag should be ignored. */
+static bool is_cur_manual(const struct v4l2_ctrl *master)
+{
+       return master->is_auto && master->cur.val == master->manual_mode_value;
+}
+
+/* Same as above, but this checks the against the new value instead of the
+   current value. */
+static bool is_new_manual(const struct v4l2_ctrl *master)
+{
+       return master->is_auto && master->val == master->manual_mode_value;
+}
+
 /* Returns NULL or a character pointer array containing the menu for
    the given control ID. The pointer array ends with a NULL pointer.
    An empty string signifies a menu entry that is invalid. This allows
@@ -181,7 +203,7 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
        };
        static const char * const mpeg_stream_vbi_fmt[] = {
                "No VBI",
-               "Private packet, IVTV format",
+               "Private Packet, IVTV Format",
                NULL
        };
        static const char * const camera_power_line_frequency[] = {
@@ -204,18 +226,130 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
                "Negative",
                "Emboss",
                "Sketch",
-               "Sky blue",
-               "Grass green",
-               "Skin whiten",
+               "Sky Blue",
+               "Grass Green",
+               "Skin Whiten",
                "Vivid",
                NULL
        };
        static const char * const tune_preemphasis[] = {
-               "No preemphasis",
+               "No Preemphasis",
                "50 useconds",
                "75 useconds",
                NULL,
        };
+       static const char * const header_mode[] = {
+               "Separate Buffer",
+               "Joined With 1st Frame",
+               NULL,
+       };
+       static const char * const multi_slice[] = {
+               "Single",
+               "Max Macroblocks",
+               "Max Bytes",
+               NULL,
+       };
+       static const char * const entropy_mode[] = {
+               "CAVLC",
+               "CABAC",
+               NULL,
+       };
+       static const char * const mpeg_h264_level[] = {
+               "1",
+               "1b",
+               "1.1",
+               "1.2",
+               "1.3",
+               "2",
+               "2.1",
+               "2.2",
+               "3",
+               "3.1",
+               "3.2",
+               "4",
+               "4.1",
+               "4.2",
+               "5",
+               "5.1",
+               NULL,
+       };
+       static const char * const h264_loop_filter[] = {
+               "Enabled",
+               "Disabled",
+               "Disabled at Slice Boundary",
+               NULL,
+       };
+       static const char * const h264_profile[] = {
+               "Baseline",
+               "Constrained Baseline",
+               "Main",
+               "Extended",
+               "High",
+               "High 10",
+               "High 422",
+               "High 444 Predictive",
+               "High 10 Intra",
+               "High 422 Intra",
+               "High 444 Intra",
+               "CAVLC 444 Intra",
+               "Scalable Baseline",
+               "Scalable High",
+               "Scalable High Intra",
+               "Multiview High",
+               NULL,
+       };
+       static const char * const vui_sar_idc[] = {
+               "Unspecified",
+               "1:1",
+               "12:11",
+               "10:11",
+               "16:11",
+               "40:33",
+               "24:11",
+               "20:11",
+               "32:11",
+               "80:33",
+               "18:11",
+               "15:11",
+               "64:33",
+               "160:99",
+               "4:3",
+               "3:2",
+               "2:1",
+               "Extended SAR",
+               NULL,
+       };
+       static const char * const mpeg_mpeg4_level[] = {
+               "0",
+               "0b",
+               "1",
+               "2",
+               "3",
+               "3b",
+               "4",
+               "5",
+               NULL,
+       };
+       static const char * const mpeg4_profile[] = {
+               "Simple",
+               "Adcanved Simple",
+               "Core",
+               "Simple Scalable",
+               "Advanced Coding Efficency",
+               NULL,
+       };
+
+       static const char * const flash_led_mode[] = {
+               "Off",
+               "Flash",
+               "Torch",
+               NULL,
+       };
+       static const char * const flash_strobe_source[] = {
+               "Software",
+               "External",
+               NULL,
+       };
 
        switch (id) {
        case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
@@ -256,6 +390,28 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
                return colorfx;
        case V4L2_CID_TUNE_PREEMPHASIS:
                return tune_preemphasis;
+       case V4L2_CID_FLASH_LED_MODE:
+               return flash_led_mode;
+       case V4L2_CID_FLASH_STROBE_SOURCE:
+               return flash_strobe_source;
+       case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
+               return header_mode;
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+               return multi_slice;
+       case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+               return entropy_mode;
+       case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+               return mpeg_h264_level;
+       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+               return h264_loop_filter;
+       case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+               return h264_profile;
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
+               return vui_sar_idc;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+               return mpeg_mpeg4_level;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+               return mpeg4_profile;
        default:
                return NULL;
        }
@@ -307,6 +463,8 @@ const char *v4l2_ctrl_get_name(u32 id)
        case V4L2_CID_CHROMA_GAIN:              return "Chroma Gain";
        case V4L2_CID_ILLUMINATORS_1:           return "Illuminator 1";
        case V4L2_CID_ILLUMINATORS_2:           return "Illuminator 2";
+       case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:  return "Minimum Number of Capture Buffers";
+       case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:   return "Minimum Number of Output Buffers";
 
        /* MPEG controls */
        /* Keep the order of the 'case's the same as in videodev2.h! */
@@ -343,6 +501,48 @@ const char *v4l2_ctrl_get_name(u32 id)
        case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: return "Video Temporal Decimation";
        case V4L2_CID_MPEG_VIDEO_MUTE:          return "Video Mute";
        case V4L2_CID_MPEG_VIDEO_MUTE_YUV:      return "Video Mute YUV";
+       case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE:       return "Decoder Slice Interface";
+       case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:  return "MPEG4 Loop Filter Enable";
+       case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:       return "The Number of Intra Refresh MBs";
+       case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:               return "Frame Level Rate Control Enable";
+       case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:                  return "H264 MB Level Rate Control";
+       case V4L2_CID_MPEG_VIDEO_HEADER_MODE:                   return "Sequence Header Mode";
+       case V4L2_CID_MPEG_VIDEO_MAX_REF_PIC:                   return "The Max Number of Reference Picture";
+       case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP:               return "H263 I-Frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP:               return "H263 P frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP:               return "H263 B frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_H263_MIN_QP:                   return "H263 Minimum QP Value";
+       case V4L2_CID_MPEG_VIDEO_H263_MAX_QP:                   return "H263 Maximum QP Value";
+       case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:               return "H264 I-Frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:               return "H264 P frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:               return "H264 B frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:                   return "H264 Maximum QP Value";
+       case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:                   return "H264 Minimum QP Value";
+       case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:            return "H264 8x8 Transform Enable";
+       case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE:                 return "H264 CPB Buffer Size";
+       case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:             return "H264 Entorpy Mode";
+       case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:                 return "H264 I Period";
+       case V4L2_CID_MPEG_VIDEO_H264_LEVEL:                    return "H264 Level";
+       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:        return "H264 Loop Filter Alpha Offset";
+       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:         return "H264 Loop Filter Beta Offset";
+       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:         return "H264 Loop Filter Mode";
+       case V4L2_CID_MPEG_VIDEO_H264_PROFILE:                  return "H264 Profile";
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT:       return "Vertical Size of SAR";
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH:        return "Horizontal Size of SAR";
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:           return "Aspect Ratio VUI Enable";
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:              return "VUI Aspect Ratio IDC";
+       case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:              return "MPEG4 I-Frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:              return "MPEG4 P frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP:              return "MPEG4 B frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP:                  return "MPEG4 Minimum QP Value";
+       case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP:                  return "MPEG4 Maximum QP Value";
+       case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:                   return "MPEG4 Level";
+       case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:                 return "MPEG4 Profile";
+       case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL:                    return "Quarter Pixel Search Enable";
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:         return "The Maximum Bytes Per Slice";
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:            return "The Number of MB in a Slice";
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:              return "The Slice Partitioning Method";
+       case V4L2_CID_MPEG_VIDEO_VBV_SIZE:                      return "VBV Buffer Size";
 
        /* CAMERA controls */
        /* Keep the order of the 'case's the same as in videodev2.h! */
@@ -389,6 +589,21 @@ const char *v4l2_ctrl_get_name(u32 id)
        case V4L2_CID_TUNE_POWER_LEVEL:         return "Tune Power Level";
        case V4L2_CID_TUNE_ANTENNA_CAPACITOR:   return "Tune Antenna Capacitor";
 
+       /* Flash controls */
+       case V4L2_CID_FLASH_CLASS:              return "Flash controls";
+       case V4L2_CID_FLASH_LED_MODE:           return "LED mode";
+       case V4L2_CID_FLASH_STROBE_SOURCE:      return "Strobe source";
+       case V4L2_CID_FLASH_STROBE:             return "Strobe";
+       case V4L2_CID_FLASH_STROBE_STOP:        return "Stop strobe";
+       case V4L2_CID_FLASH_STROBE_STATUS:      return "Strobe status";
+       case V4L2_CID_FLASH_TIMEOUT:            return "Strobe timeout";
+       case V4L2_CID_FLASH_INTENSITY:          return "Intensity, flash mode";
+       case V4L2_CID_FLASH_TORCH_INTENSITY:    return "Intensity, torch mode";
+       case V4L2_CID_FLASH_INDICATOR_INTENSITY: return "Intensity, indicator";
+       case V4L2_CID_FLASH_FAULT:              return "Faults";
+       case V4L2_CID_FLASH_CHARGE:             return "Charge";
+       case V4L2_CID_FLASH_READY:              return "Ready to strobe";
+
        default:
                return NULL;
        }
@@ -423,12 +638,24 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
        case V4L2_CID_PILOT_TONE_ENABLED:
        case V4L2_CID_ILLUMINATORS_1:
        case V4L2_CID_ILLUMINATORS_2:
+       case V4L2_CID_FLASH_STROBE_STATUS:
+       case V4L2_CID_FLASH_CHARGE:
+       case V4L2_CID_FLASH_READY:
+       case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:
+       case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE:
+       case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
+       case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:
+       case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:
+       case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL:
                *type = V4L2_CTRL_TYPE_BOOLEAN;
                *min = 0;
                *max = *step = 1;
                break;
        case V4L2_CID_PAN_RESET:
        case V4L2_CID_TILT_RESET:
+       case V4L2_CID_FLASH_STROBE:
+       case V4L2_CID_FLASH_STROBE_STOP:
                *type = V4L2_CTRL_TYPE_BUTTON;
                *flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
                *min = *max = *step = *def = 0;
@@ -452,6 +679,17 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
        case V4L2_CID_EXPOSURE_AUTO:
        case V4L2_CID_COLORFX:
        case V4L2_CID_TUNE_PREEMPHASIS:
+       case V4L2_CID_FLASH_LED_MODE:
+       case V4L2_CID_FLASH_STROBE_SOURCE:
+       case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+       case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+       case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+       case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
+       case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+       case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
                *type = V4L2_CTRL_TYPE_MENU;
                break;
        case V4L2_CID_RDS_TX_PS_NAME:
@@ -462,6 +700,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
        case V4L2_CID_CAMERA_CLASS:
        case V4L2_CID_MPEG_CLASS:
        case V4L2_CID_FM_TX_CLASS:
+       case V4L2_CID_FLASH_CLASS:
                *type = V4L2_CTRL_TYPE_CTRL_CLASS;
                /* You can neither read not write these */
                *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY;
@@ -474,6 +713,14 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
                /* Max is calculated as RGB888 that is 2^24 */
                *max = 0xFFFFFF;
                break;
+       case V4L2_CID_FLASH_FAULT:
+               *type = V4L2_CTRL_TYPE_BITMASK;
+               break;
+       case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
+       case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:
+               *type = V4L2_CTRL_TYPE_INTEGER;
+               *flags |= V4L2_CTRL_FLAG_READ_ONLY;
+               break;
        default:
                *type = V4L2_CTRL_TYPE_INTEGER;
                break;
@@ -519,6 +766,10 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
        case V4L2_CID_ZOOM_RELATIVE:
                *flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
                break;
+       case V4L2_CID_FLASH_STROBE_STATUS:
+       case V4L2_CID_FLASH_READY:
+               *flags |= V4L2_CTRL_FLAG_READ_ONLY;
+               break;
        }
 }
 EXPORT_SYMBOL(v4l2_ctrl_fill);
@@ -537,6 +788,42 @@ static bool type_is_int(const struct v4l2_ctrl *ctrl)
        }
 }
 
+static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 changes)
+{
+       memset(ev->reserved, 0, sizeof(ev->reserved));
+       ev->type = V4L2_EVENT_CTRL;
+       ev->id = ctrl->id;
+       ev->u.ctrl.changes = changes;
+       ev->u.ctrl.type = ctrl->type;
+       ev->u.ctrl.flags = ctrl->flags;
+       if (ctrl->type == V4L2_CTRL_TYPE_STRING)
+               ev->u.ctrl.value64 = 0;
+       else
+               ev->u.ctrl.value64 = ctrl->cur.val64;
+       ev->u.ctrl.minimum = ctrl->minimum;
+       ev->u.ctrl.maximum = ctrl->maximum;
+       if (ctrl->type == V4L2_CTRL_TYPE_MENU)
+               ev->u.ctrl.step = 1;
+       else
+               ev->u.ctrl.step = ctrl->step;
+       ev->u.ctrl.default_value = ctrl->default_value;
+}
+
+static void send_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 changes)
+{
+       struct v4l2_event ev;
+       struct v4l2_subscribed_event *sev;
+
+       if (list_empty(&ctrl->ev_subs))
+               return;
+       fill_event(&ev, ctrl, changes);
+
+       list_for_each_entry(sev, &ctrl->ev_subs, node)
+               if (sev->fh && (sev->fh != fh ||
+                               (sev->flags & V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK)))
+                       v4l2_event_queue_fh(sev->fh, &ev);
+}
+
 /* Helper function: copy the current control value back to the caller */
 static int cur_to_user(struct v4l2_ext_control *c,
                       struct v4l2_ctrl *ctrl)
@@ -624,22 +911,45 @@ static int new_to_user(struct v4l2_ext_control *c,
 }
 
 /* Copy the new value to the current value. */
-static void new_to_cur(struct v4l2_ctrl *ctrl)
+static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
+                                               bool update_inactive)
 {
+       bool changed = false;
+
        if (ctrl == NULL)
                return;
        switch (ctrl->type) {
+       case V4L2_CTRL_TYPE_BUTTON:
+               changed = true;
+               break;
        case V4L2_CTRL_TYPE_STRING:
                /* strings are always 0-terminated */
+               changed = strcmp(ctrl->string, ctrl->cur.string);
                strcpy(ctrl->cur.string, ctrl->string);
                break;
        case V4L2_CTRL_TYPE_INTEGER64:
+               changed = ctrl->val64 != ctrl->cur.val64;
                ctrl->cur.val64 = ctrl->val64;
                break;
        default:
+               changed = ctrl->val != ctrl->cur.val;
                ctrl->cur.val = ctrl->val;
                break;
        }
+       if (update_inactive) {
+               ctrl->flags &= ~V4L2_CTRL_FLAG_INACTIVE;
+               if (!is_cur_manual(ctrl->cluster[0]))
+                       ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+       }
+       if (changed || update_inactive) {
+               /* If a control was changed that was not one of the controls
+                  modified by the application, then send the event to all. */
+               if (!ctrl->is_new)
+                       fh = NULL;
+               send_event(fh, ctrl,
+                       (changed ? V4L2_EVENT_CTRL_CH_VALUE : 0) |
+                       (update_inactive ? V4L2_EVENT_CTRL_CH_FLAGS : 0));
+       }
 }
 
 /* Copy the current value to the new value */
@@ -692,13 +1002,11 @@ static int cluster_changed(struct v4l2_ctrl *master)
        return diff;
 }
 
-/* Validate a new control */
-static int validate_new(struct v4l2_ctrl *ctrl)
+/* Validate integer-type control */
+static int validate_new_int(const struct v4l2_ctrl *ctrl, s32 *pval)
 {
-       s32 val = ctrl->val;
-       char *s = ctrl->string;
+       s32 val = *pval;
        u32 offset;
-       size_t len;
 
        switch (ctrl->type) {
        case V4L2_CTRL_TYPE_INTEGER:
@@ -711,11 +1019,11 @@ static int validate_new(struct v4l2_ctrl *ctrl)
                offset = val - ctrl->minimum;
                offset = ctrl->step * (offset / ctrl->step);
                val = ctrl->minimum + offset;
-               ctrl->val = val;
+               *pval = val;
                return 0;
 
        case V4L2_CTRL_TYPE_BOOLEAN:
-               ctrl->val = !!ctrl->val;
+               *pval = !!val;
                return 0;
 
        case V4L2_CTRL_TYPE_MENU:
@@ -726,11 +1034,35 @@ static int validate_new(struct v4l2_ctrl *ctrl)
                        return -EINVAL;
                return 0;
 
+       case V4L2_CTRL_TYPE_BITMASK:
+               *pval &= ctrl->maximum;
+               return 0;
+
        case V4L2_CTRL_TYPE_BUTTON:
        case V4L2_CTRL_TYPE_CTRL_CLASS:
-               ctrl->val64 = 0;
+               *pval = 0;
                return 0;
 
+       default:
+               return -EINVAL;
+       }
+}
+
+/* Validate a new control */
+static int validate_new(const struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c)
+{
+       char *s = c->string;
+       size_t len;
+
+       switch (ctrl->type) {
+       case V4L2_CTRL_TYPE_INTEGER:
+       case V4L2_CTRL_TYPE_BOOLEAN:
+       case V4L2_CTRL_TYPE_MENU:
+       case V4L2_CTRL_TYPE_BITMASK:
+       case V4L2_CTRL_TYPE_BUTTON:
+       case V4L2_CTRL_TYPE_CTRL_CLASS:
+               return validate_new_int(ctrl, &c->value);
+
        case V4L2_CTRL_TYPE_INTEGER64:
                return 0;
 
@@ -780,6 +1112,7 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
 {
        struct v4l2_ctrl_ref *ref, *next_ref;
        struct v4l2_ctrl *ctrl, *next_ctrl;
+       struct v4l2_subscribed_event *sev, *next_sev;
 
        if (hdl == NULL || hdl->buckets == NULL)
                return;
@@ -793,6 +1126,8 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
        /* Free all controls owned by the handler */
        list_for_each_entry_safe(ctrl, next_ctrl, &hdl->ctrls, node) {
                list_del(&ctrl->node);
+               list_for_each_entry_safe(sev, next_sev, &ctrl->ev_subs, node)
+                       list_del(&sev->node);
                kfree(ctrl);
        }
        kfree(hdl->buckets);
@@ -962,13 +1297,17 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 
        /* Sanity checks */
        if (id == 0 || name == NULL || id >= V4L2_CID_PRIVATE_BASE ||
-           max < min ||
            (type == V4L2_CTRL_TYPE_INTEGER && step == 0) ||
+           (type == V4L2_CTRL_TYPE_BITMASK && max == 0) ||
            (type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) ||
            (type == V4L2_CTRL_TYPE_STRING && max == 0)) {
                handler_set_err(hdl, -ERANGE);
                return NULL;
        }
+       if (type != V4L2_CTRL_TYPE_BITMASK && max < min) {
+               handler_set_err(hdl, -ERANGE);
+               return NULL;
+       }
        if ((type == V4L2_CTRL_TYPE_INTEGER ||
             type == V4L2_CTRL_TYPE_MENU ||
             type == V4L2_CTRL_TYPE_BOOLEAN) &&
@@ -976,6 +1315,10 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
                handler_set_err(hdl, -ERANGE);
                return NULL;
        }
+       if (type == V4L2_CTRL_TYPE_BITMASK && ((def & ~max) || min || step)) {
+               handler_set_err(hdl, -ERANGE);
+               return NULL;
+       }
 
        if (type == V4L2_CTRL_TYPE_BUTTON)
                flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
@@ -991,6 +1334,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
        }
 
        INIT_LIST_HEAD(&ctrl->node);
+       INIT_LIST_HEAD(&ctrl->ev_subs);
        ctrl->handler = hdl;
        ctrl->ops = ops;
        ctrl->id = id;
@@ -1132,6 +1476,9 @@ int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
                /* Skip handler-private controls. */
                if (ctrl->is_private)
                        continue;
+               /* And control classes */
+               if (ctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
+                       continue;
                ret = handler_new_ref(hdl, ctrl);
                if (ret)
                        break;
@@ -1147,7 +1494,7 @@ void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls)
        int i;
 
        /* The first control is the master control and it must not be NULL */
-       BUG_ON(controls[0] == NULL);
+       BUG_ON(ncontrols == 0 || controls[0] == NULL);
 
        for (i = 0; i < ncontrols; i++) {
                if (controls[i]) {
@@ -1158,18 +1505,47 @@ void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls)
 }
 EXPORT_SYMBOL(v4l2_ctrl_cluster);
 
+void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls,
+                           u8 manual_val, bool set_volatile)
+{
+       struct v4l2_ctrl *master = controls[0];
+       u32 flag;
+       int i;
+
+       v4l2_ctrl_cluster(ncontrols, controls);
+       WARN_ON(ncontrols <= 1);
+       WARN_ON(manual_val < master->minimum || manual_val > master->maximum);
+       master->is_auto = true;
+       master->manual_mode_value = manual_val;
+       master->flags |= V4L2_CTRL_FLAG_UPDATE;
+       flag = is_cur_manual(master) ? 0 : V4L2_CTRL_FLAG_INACTIVE;
+
+       for (i = 1; i < ncontrols; i++)
+               if (controls[i]) {
+                       controls[i]->is_volatile = set_volatile;
+                       controls[i]->flags |= flag;
+               }
+}
+EXPORT_SYMBOL(v4l2_ctrl_auto_cluster);
+
 /* Activate/deactivate a control. */
 void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active)
 {
+       /* invert since the actual flag is called 'inactive' */
+       bool inactive = !active;
+       bool old;
+
        if (ctrl == NULL)
                return;
 
-       if (!active)
+       if (inactive)
                /* set V4L2_CTRL_FLAG_INACTIVE */
-               set_bit(4, &ctrl->flags);
+               old = test_and_set_bit(4, &ctrl->flags);
        else
                /* clear V4L2_CTRL_FLAG_INACTIVE */
-               clear_bit(4, &ctrl->flags);
+               old = test_and_clear_bit(4, &ctrl->flags);
+       if (old != inactive)
+               send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_FLAGS);
 }
 EXPORT_SYMBOL(v4l2_ctrl_activate);
 
@@ -1181,15 +1557,21 @@ EXPORT_SYMBOL(v4l2_ctrl_activate);
    these controls. */
 void v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed)
 {
+       bool old;
+
        if (ctrl == NULL)
                return;
 
+       v4l2_ctrl_lock(ctrl);
        if (grabbed)
                /* set V4L2_CTRL_FLAG_GRABBED */
-               set_bit(1, &ctrl->flags);
+               old = test_and_set_bit(1, &ctrl->flags);
        else
                /* clear V4L2_CTRL_FLAG_GRABBED */
-               clear_bit(1, &ctrl->flags);
+               old = test_and_clear_bit(1, &ctrl->flags);
+       if (old != grabbed)
+               send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_FLAGS);
+       v4l2_ctrl_unlock(ctrl);
 }
 EXPORT_SYMBOL(v4l2_ctrl_grab);
 
@@ -1217,6 +1599,9 @@ static void log_ctrl(const struct v4l2_ctrl *ctrl,
        case V4L2_CTRL_TYPE_MENU:
                printk(KERN_CONT "%s", ctrl->qmenu[ctrl->cur.val]);
                break;
+       case V4L2_CTRL_TYPE_BITMASK:
+               printk(KERN_CONT "0x%08x", ctrl->cur.val);
+               break;
        case V4L2_CTRL_TYPE_INTEGER64:
                printk(KERN_CONT "%lld", ctrl->cur.val64);
                break;
@@ -1277,26 +1662,21 @@ int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)
                int i;
 
                /* Skip if this control was already handled by a cluster. */
-               if (ctrl->done)
+               /* Skip button controls and read-only controls. */
+               if (ctrl->done || ctrl->type == V4L2_CTRL_TYPE_BUTTON ||
+                   (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY))
                        continue;
 
                for (i = 0; i < master->ncontrols; i++) {
                        if (master->cluster[i]) {
                                cur_to_new(master->cluster[i]);
                                master->cluster[i]->is_new = 1;
+                               master->cluster[i]->done = true;
                        }
                }
-
-               /* Skip button controls and read-only controls. */
-               if (ctrl->type == V4L2_CTRL_TYPE_BUTTON ||
-                   (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY))
-                       continue;
-               ret = master->ops->s_ctrl(master);
+               ret = call_op(master, s_ctrl);
                if (ret)
                        break;
-               for (i = 0; i < master->ncontrols; i++)
-                       if (master->cluster[i])
-                               master->cluster[i]->done = true;
        }
        mutex_unlock(&hdl->lock);
        return ret;
@@ -1447,18 +1827,19 @@ EXPORT_SYMBOL(v4l2_subdev_querymenu);
    Find the controls in the control array and do some basic checks. */
 static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
                             struct v4l2_ext_controls *cs,
-                            struct ctrl_helper *helpers,
-                            bool try)
+                            struct v4l2_ctrl_helper *helpers)
 {
+       struct v4l2_ctrl_helper *h;
+       bool have_clusters = false;
        u32 i;
 
-       for (i = 0; i < cs->count; i++) {
+       for (i = 0, h = helpers; i < cs->count; i++, h++) {
                struct v4l2_ext_control *c = &cs->controls[i];
+               struct v4l2_ctrl_ref *ref;
                struct v4l2_ctrl *ctrl;
                u32 id = c->id & V4L2_CTRL_ID_MASK;
 
-               if (try)
-                       cs->error_idx = i;
+               cs->error_idx = i;
 
                if (cs->ctrl_class && V4L2_CTRL_ID2CLASS(id) != cs->ctrl_class)
                        return -EINVAL;
@@ -1467,53 +1848,59 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
                   extended controls */
                if (id >= V4L2_CID_PRIVATE_BASE)
                        return -EINVAL;
-               ctrl = v4l2_ctrl_find(hdl, id);
-               if (ctrl == NULL)
+               ref = find_ref_lock(hdl, id);
+               if (ref == NULL)
                        return -EINVAL;
+               ctrl = ref->ctrl;
                if (ctrl->flags & V4L2_CTRL_FLAG_DISABLED)
                        return -EINVAL;
 
-               helpers[i].ctrl = ctrl;
-               helpers[i].handled = false;
+               if (ctrl->cluster[0]->ncontrols > 1)
+                       have_clusters = true;
+               if (ctrl->cluster[0] != ctrl)
+                       ref = find_ref_lock(hdl, ctrl->cluster[0]->id);
+               /* Store the ref to the master control of the cluster */
+               h->mref = ref;
+               h->ctrl = ctrl;
+               /* Initially set next to 0, meaning that there is no other
+                  control in this helper array belonging to the same
+                  cluster */
+               h->next = 0;
        }
-       return 0;
-}
 
-typedef int (*cluster_func)(struct v4l2_ext_control *c,
-                           struct v4l2_ctrl *ctrl);
+       /* We are done if there were no controls that belong to a multi-
+          control cluster. */
+       if (!have_clusters)
+               return 0;
 
-/* Walk over all controls in v4l2_ext_controls belonging to the same cluster
-   and call the provided function. */
-static int cluster_walk(unsigned from,
-                       struct v4l2_ext_controls *cs,
-                       struct ctrl_helper *helpers,
-                       cluster_func f)
-{
-       struct v4l2_ctrl **cluster = helpers[from].ctrl->cluster;
-       int ret = 0;
-       int i;
+       /* The code below figures out in O(n) time which controls in the list
+          belong to the same cluster. */
 
-       /* Find any controls from the same cluster and call the function */
-       for (i = from; !ret && i < cs->count; i++) {
-               struct v4l2_ctrl *ctrl = helpers[i].ctrl;
+       /* This has to be done with the handler lock taken. */
+       mutex_lock(&hdl->lock);
 
-               if (!helpers[i].handled && ctrl->cluster == cluster)
-                       ret = f(&cs->controls[i], ctrl);
+       /* First zero the helper field in the master control references */
+       for (i = 0; i < cs->count; i++)
+               helpers[i].mref->helper = 0;
+       for (i = 0, h = helpers; i < cs->count; i++, h++) {
+               struct v4l2_ctrl_ref *mref = h->mref;
+
+               /* If the mref->helper is set, then it points to an earlier
+                  helper that belongs to the same cluster. */
+               if (mref->helper) {
+                       /* Set the next field of mref->helper to the current
+                          index: this means that that earlier helper now
+                          points to the next helper in the same cluster. */
+                       mref->helper->next = i;
+                       /* mref should be set only for the first helper in the
+                          cluster, clear the others. */
+                       h->mref = NULL;
+               }
+               /* Point the mref helper to the current helper struct. */
+               mref->helper = h;
        }
-       return ret;
-}
-
-static void cluster_done(unsigned from,
-                        struct v4l2_ext_controls *cs,
-                        struct ctrl_helper *helpers)
-{
-       struct v4l2_ctrl **cluster = helpers[from].ctrl->cluster;
-       int i;
-
-       /* Find any controls from the same cluster and mark them as handled */
-       for (i = from; i < cs->count; i++)
-               if (helpers[i].ctrl->cluster == cluster)
-                       helpers[i].handled = true;
+       mutex_unlock(&hdl->lock);
+       return 0;
 }
 
 /* Handles the corner case where cs->count == 0. It checks whether the
@@ -1531,10 +1918,10 @@ static int class_check(struct v4l2_ctrl_handler *hdl, u32 ctrl_class)
 /* Get extended controls. Allocates the helpers array if needed. */
 int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs)
 {
-       struct ctrl_helper helper[4];
-       struct ctrl_helper *helpers = helper;
+       struct v4l2_ctrl_helper helper[4];
+       struct v4l2_ctrl_helper *helpers = helper;
        int ret;
-       int i;
+       int i, j;
 
        cs->error_idx = cs->count;
        cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class);
@@ -1551,30 +1938,46 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
                        return -ENOMEM;
        }
 
-       ret = prepare_ext_ctrls(hdl, cs, helpers, false);
+       ret = prepare_ext_ctrls(hdl, cs, helpers);
+       cs->error_idx = cs->count;
 
        for (i = 0; !ret && i < cs->count; i++)
                if (helpers[i].ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)
                        ret = -EACCES;
 
        for (i = 0; !ret && i < cs->count; i++) {
-               struct v4l2_ctrl *ctrl = helpers[i].ctrl;
-               struct v4l2_ctrl *master = ctrl->cluster[0];
+               int (*ctrl_to_user)(struct v4l2_ext_control *c,
+                                   struct v4l2_ctrl *ctrl) = cur_to_user;
+               struct v4l2_ctrl *master;
 
-               if (helpers[i].handled)
+               if (helpers[i].mref == NULL)
                        continue;
 
+               master = helpers[i].mref->ctrl;
                cs->error_idx = i;
 
                v4l2_ctrl_lock(master);
-               /* g_volatile_ctrl will update the current control values */
-               if (ctrl->is_volatile && master->ops->g_volatile_ctrl)
-                       ret = master->ops->g_volatile_ctrl(master);
-               /* If OK, then copy the current control values to the caller */
-               if (!ret)
-                       ret = cluster_walk(i, cs, helpers, cur_to_user);
+
+               /* g_volatile_ctrl will update the new control values */
+               if (has_op(master, g_volatile_ctrl) && !is_cur_manual(master)) {
+                       for (j = 0; j < master->ncontrols; j++)
+                               cur_to_new(master->cluster[j]);
+                       ret = call_op(master, g_volatile_ctrl);
+                       ctrl_to_user = new_to_user;
+               }
+               /* If OK, then copy the current (for non-volatile controls)
+                  or the new (for volatile controls) control values to the
+                  caller */
+               if (!ret) {
+                       u32 idx = i;
+
+                       do {
+                               ret = ctrl_to_user(cs->controls + idx,
+                                                  helpers[idx].ctrl);
+                               idx = helpers[idx].next;
+                       } while (!ret && idx);
+               }
                v4l2_ctrl_unlock(master);
-               cluster_done(i, cs, helpers);
        }
 
        if (cs->count > ARRAY_SIZE(helper))
@@ -1594,15 +1997,21 @@ static int get_ctrl(struct v4l2_ctrl *ctrl, s32 *val)
 {
        struct v4l2_ctrl *master = ctrl->cluster[0];
        int ret = 0;
+       int i;
 
        if (ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)
                return -EACCES;
 
        v4l2_ctrl_lock(master);
        /* g_volatile_ctrl will update the current control values */
-       if (ctrl->is_volatile && master->ops->g_volatile_ctrl)
-               ret = master->ops->g_volatile_ctrl(master);
-       *val = ctrl->cur.val;
+       if (ctrl->is_volatile && !is_cur_manual(master)) {
+               for (i = 0; i < master->ncontrols; i++)
+                       cur_to_new(master->cluster[i]);
+               ret = call_op(master, g_volatile_ctrl);
+               *val = ctrl->val;
+       } else {
+               *val = ctrl->cur.val;
+       }
        v4l2_ctrl_unlock(master);
        return ret;
 }
@@ -1638,72 +2047,61 @@ EXPORT_SYMBOL(v4l2_ctrl_g_ctrl);
 /* Core function that calls try/s_ctrl and ensures that the new value is
    copied to the current value on a set.
    Must be called with ctrl->handler->lock held. */
-static int try_or_set_control_cluster(struct v4l2_ctrl *master, bool set)
+static int try_or_set_cluster(struct v4l2_fh *fh,
+                             struct v4l2_ctrl *master, bool set)
 {
-       bool try = !set;
-       int ret = 0;
+       bool update_flag;
+       int ret;
        int i;
 
        /* Go through the cluster and either validate the new value or
           (if no new value was set), copy the current value to the new
           value, ensuring a consistent view for the control ops when
           called. */
-       for (i = 0; !ret && i < master->ncontrols; i++) {
+       for (i = 0; i < master->ncontrols; i++) {
                struct v4l2_ctrl *ctrl = master->cluster[i];
 
                if (ctrl == NULL)
                        continue;
 
-               if (ctrl->is_new) {
-                       /* Double check this: it may have changed since the
-                          last check in try_or_set_ext_ctrls(). */
-                       if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED))
-                               return -EBUSY;
-
-                       /* Validate if required */
-                       if (!set)
-                               ret = validate_new(ctrl);
+               if (!ctrl->is_new) {
+                       cur_to_new(ctrl);
                        continue;
                }
-               /* No new value was set, so copy the current and force
-                  a call to try_ctrl later, since the values for the cluster
-                  may now have changed and the end result might be invalid. */
-               try = true;
-               cur_to_new(ctrl);
+               /* Check again: it may have changed since the
+                  previous check in try_or_set_ext_ctrls(). */
+               if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED))
+                       return -EBUSY;
        }
 
-       /* For larger clusters you have to call try_ctrl again to
-          verify that the controls are still valid after the
-          'cur_to_new' above. */
-       if (!ret && master->ops->try_ctrl && try)
-               ret = master->ops->try_ctrl(master);
+       ret = call_op(master, try_ctrl);
 
        /* Don't set if there is no change */
-       if (!ret && set && cluster_changed(master)) {
-               ret = master->ops->s_ctrl(master);
-               /* If OK, then make the new values permanent. */
-               if (!ret)
-                       for (i = 0; i < master->ncontrols; i++)
-                               new_to_cur(master->cluster[i]);
-       }
-       return ret;
+       if (ret || !set || !cluster_changed(master))
+               return ret;
+       ret = call_op(master, s_ctrl);
+       if (ret)
+               return ret;
+
+       /* If OK, then make the new values permanent. */
+       update_flag = is_cur_manual(master) != is_new_manual(master);
+       for (i = 0; i < master->ncontrols; i++)
+               new_to_cur(fh, master->cluster[i], update_flag && i > 0);
+       return 0;
 }
 
-/* Try or set controls. */
-static int try_or_set_ext_ctrls(struct v4l2_ctrl_handler *hdl,
-                               struct v4l2_ext_controls *cs,
-                               struct ctrl_helper *helpers,
-                               bool set)
+/* Validate controls. */
+static int validate_ctrls(struct v4l2_ext_controls *cs,
+                         struct v4l2_ctrl_helper *helpers, bool set)
 {
-       unsigned i, j;
+       unsigned i;
        int ret = 0;
 
        cs->error_idx = cs->count;
        for (i = 0; i < cs->count; i++) {
                struct v4l2_ctrl *ctrl = helpers[i].ctrl;
 
-               if (!set)
-                       cs->error_idx = i;
+               cs->error_idx = i;
 
                if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)
                        return -EACCES;
@@ -1715,50 +2113,22 @@ static int try_or_set_ext_ctrls(struct v4l2_ctrl_handler *hdl,
                   best-effort to avoid that. */
                if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED))
                        return -EBUSY;
+               ret = validate_new(ctrl, &cs->controls[i]);
+               if (ret)
+                       return ret;
        }
-
-       for (i = 0; !ret && i < cs->count; i++) {
-               struct v4l2_ctrl *ctrl = helpers[i].ctrl;
-               struct v4l2_ctrl *master = ctrl->cluster[0];
-
-               cs->error_idx = i;
-
-               if (helpers[i].handled)
-                       continue;
-
-               v4l2_ctrl_lock(ctrl);
-
-               /* Reset the 'is_new' flags of the cluster */
-               for (j = 0; j < master->ncontrols; j++)
-                       if (master->cluster[j])
-                               master->cluster[j]->is_new = 0;
-
-               /* Copy the new caller-supplied control values.
-                  user_to_new() sets 'is_new' to 1. */
-               ret = cluster_walk(i, cs, helpers, user_to_new);
-
-               if (!ret)
-                       ret = try_or_set_control_cluster(master, set);
-
-               /* Copy the new values back to userspace. */
-               if (!ret)
-                       ret = cluster_walk(i, cs, helpers, new_to_user);
-
-               v4l2_ctrl_unlock(ctrl);
-               cluster_done(i, cs, helpers);
-       }
-       return ret;
+       return 0;
 }
 
 /* Try or try-and-set controls */
-static int try_set_ext_ctrls(struct v4l2_ctrl_handler *hdl,
+static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
                             struct v4l2_ext_controls *cs,
                             bool set)
 {
-       struct ctrl_helper helper[4];
-       struct ctrl_helper *helpers = helper;
+       struct v4l2_ctrl_helper helper[4];
+       struct v4l2_ctrl_helper *helpers = helper;
+       unsigned i, j;
        int ret;
-       int i;
 
        cs->error_idx = cs->count;
        cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class);
@@ -1774,25 +2144,49 @@ static int try_set_ext_ctrls(struct v4l2_ctrl_handler *hdl,
                if (!helpers)
                        return -ENOMEM;
        }
-       ret = prepare_ext_ctrls(hdl, cs, helpers, !set);
-       if (ret)
-               goto free;
-
-       /* First 'try' all controls and abort on error */
-       ret = try_or_set_ext_ctrls(hdl, cs, helpers, false);
-       /* If this is a 'set' operation and the initial 'try' failed,
-          then set error_idx to count to tell the application that no
-          controls changed value yet. */
-       if (set)
+       ret = prepare_ext_ctrls(hdl, cs, helpers);
+       if (!ret)
+               ret = validate_ctrls(cs, helpers, set);
+       if (ret && set)
                cs->error_idx = cs->count;
-       if (!ret && set) {
-               /* Reset 'handled' state */
-               for (i = 0; i < cs->count; i++)
-                       helpers[i].handled = false;
-               ret = try_or_set_ext_ctrls(hdl, cs, helpers, true);
+       for (i = 0; !ret && i < cs->count; i++) {
+               struct v4l2_ctrl *master;
+               u32 idx = i;
+
+               if (helpers[i].mref == NULL)
+                       continue;
+
+               cs->error_idx = i;
+               master = helpers[i].mref->ctrl;
+               v4l2_ctrl_lock(master);
+
+               /* Reset the 'is_new' flags of the cluster */
+               for (j = 0; j < master->ncontrols; j++)
+                       if (master->cluster[j])
+                               master->cluster[j]->is_new = 0;
+
+               /* Copy the new caller-supplied control values.
+                  user_to_new() sets 'is_new' to 1. */
+               do {
+                       ret = user_to_new(cs->controls + idx, helpers[idx].ctrl);
+                       idx = helpers[idx].next;
+               } while (!ret && idx);
+
+               if (!ret)
+                       ret = try_or_set_cluster(fh, master, set);
+
+               /* Copy the new values back to userspace. */
+               if (!ret) {
+                       idx = i;
+                       do {
+                               ret = new_to_user(cs->controls + idx,
+                                               helpers[idx].ctrl);
+                               idx = helpers[idx].next;
+                       } while (!ret && idx);
+               }
+               v4l2_ctrl_unlock(master);
        }
 
-free:
        if (cs->count > ARRAY_SIZE(helper))
                kfree(helpers);
        return ret;
@@ -1800,37 +2194,39 @@ free:
 
 int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs)
 {
-       return try_set_ext_ctrls(hdl, cs, false);
+       return try_set_ext_ctrls(NULL, hdl, cs, false);
 }
 EXPORT_SYMBOL(v4l2_try_ext_ctrls);
 
-int v4l2_s_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs)
+int v4l2_s_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
+                                       struct v4l2_ext_controls *cs)
 {
-       return try_set_ext_ctrls(hdl, cs, true);
+       return try_set_ext_ctrls(fh, hdl, cs, true);
 }
 EXPORT_SYMBOL(v4l2_s_ext_ctrls);
 
 int v4l2_subdev_try_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs)
 {
-       return try_set_ext_ctrls(sd->ctrl_handler, cs, false);
+       return try_set_ext_ctrls(NULL, sd->ctrl_handler, cs, false);
 }
 EXPORT_SYMBOL(v4l2_subdev_try_ext_ctrls);
 
 int v4l2_subdev_s_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs)
 {
-       return try_set_ext_ctrls(sd->ctrl_handler, cs, true);
+       return try_set_ext_ctrls(NULL, sd->ctrl_handler, cs, true);
 }
 EXPORT_SYMBOL(v4l2_subdev_s_ext_ctrls);
 
 /* Helper function for VIDIOC_S_CTRL compatibility */
-static int set_ctrl(struct v4l2_ctrl *ctrl, s32 *val)
+static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, s32 *val)
 {
        struct v4l2_ctrl *master = ctrl->cluster[0];
        int ret;
        int i;
 
-       if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)
-               return -EACCES;
+       ret = validate_new_int(ctrl, val);
+       if (ret)
+               return ret;
 
        v4l2_ctrl_lock(ctrl);
 
@@ -1841,28 +2237,30 @@ static int set_ctrl(struct v4l2_ctrl *ctrl, s32 *val)
 
        ctrl->val = *val;
        ctrl->is_new = 1;
-       ret = try_or_set_control_cluster(master, false);
-       if (!ret)
-               ret = try_or_set_control_cluster(master, true);
+       ret = try_or_set_cluster(fh, master, true);
        *val = ctrl->cur.val;
        v4l2_ctrl_unlock(ctrl);
        return ret;
 }
 
-int v4l2_s_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *control)
+int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
+                                       struct v4l2_control *control)
 {
        struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id);
 
        if (ctrl == NULL || !type_is_int(ctrl))
                return -EINVAL;
 
-       return set_ctrl(ctrl, &control->value);
+       if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)
+               return -EACCES;
+
+       return set_ctrl(fh, ctrl, &control->value);
 }
 EXPORT_SYMBOL(v4l2_s_ctrl);
 
 int v4l2_subdev_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *control)
 {
-       return v4l2_s_ctrl(sd->ctrl_handler, control);
+       return v4l2_s_ctrl(NULL, sd->ctrl_handler, control);
 }
 EXPORT_SYMBOL(v4l2_subdev_s_ctrl);
 
@@ -1870,6 +2268,34 @@ int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val)
 {
        /* It's a driver bug if this happens. */
        WARN_ON(!type_is_int(ctrl));
-       return set_ctrl(ctrl, &val);
+       return set_ctrl(NULL, ctrl, &val);
 }
 EXPORT_SYMBOL(v4l2_ctrl_s_ctrl);
+
+void v4l2_ctrl_add_event(struct v4l2_ctrl *ctrl,
+                               struct v4l2_subscribed_event *sev)
+{
+       v4l2_ctrl_lock(ctrl);
+       list_add_tail(&sev->node, &ctrl->ev_subs);
+       if (ctrl->type != V4L2_CTRL_TYPE_CTRL_CLASS &&
+           (sev->flags & V4L2_EVENT_SUB_FL_SEND_INITIAL)) {
+               struct v4l2_event ev;
+               u32 changes = V4L2_EVENT_CTRL_CH_FLAGS;
+
+               if (!(ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY))
+                       changes |= V4L2_EVENT_CTRL_CH_VALUE;
+               fill_event(&ev, ctrl, changes);
+               v4l2_event_queue_fh(sev->fh, &ev);
+       }
+       v4l2_ctrl_unlock(ctrl);
+}
+EXPORT_SYMBOL(v4l2_ctrl_add_event);
+
+void v4l2_ctrl_del_event(struct v4l2_ctrl *ctrl,
+                               struct v4l2_subscribed_event *sev)
+{
+       v4l2_ctrl_lock(ctrl);
+       list_del(&sev->node);
+       v4l2_ctrl_unlock(ctrl);
+}
+EXPORT_SYMBOL(v4l2_ctrl_del_event);
index 4aae501..c72856c 100644 (file)
@@ -209,6 +209,7 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
                vdev->v4l2_dev = v4l2_dev;
                vdev->fops = &v4l2_subdev_fops;
                vdev->release = video_device_release_empty;
+               vdev->ctrl_handler = sd->ctrl_handler;
                err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
                                              sd->owner);
                if (err < 0)
index 69fd343..53b190c 100644 (file)
 #include <media/v4l2-dev.h>
 #include <media/v4l2-fh.h>
 #include <media/v4l2-event.h>
+#include <media/v4l2-ctrls.h>
 
 #include <linux/sched.h>
 #include <linux/slab.h>
 
-int v4l2_event_init(struct v4l2_fh *fh)
+static unsigned sev_pos(const struct v4l2_subscribed_event *sev, unsigned idx)
 {
-       fh->events = kzalloc(sizeof(*fh->events), GFP_KERNEL);
-       if (fh->events == NULL)
-               return -ENOMEM;
-
-       init_waitqueue_head(&fh->events->wait);
-
-       INIT_LIST_HEAD(&fh->events->free);
-       INIT_LIST_HEAD(&fh->events->available);
-       INIT_LIST_HEAD(&fh->events->subscribed);
-
-       fh->events->sequence = -1;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(v4l2_event_init);
-
-int v4l2_event_alloc(struct v4l2_fh *fh, unsigned int n)
-{
-       struct v4l2_events *events = fh->events;
-       unsigned long flags;
-
-       if (!events) {
-               WARN_ON(1);
-               return -ENOMEM;
-       }
-
-       while (events->nallocated < n) {
-               struct v4l2_kevent *kev;
-
-               kev = kzalloc(sizeof(*kev), GFP_KERNEL);
-               if (kev == NULL)
-                       return -ENOMEM;
-
-               spin_lock_irqsave(&fh->vdev->fh_lock, flags);
-               list_add_tail(&kev->list, &events->free);
-               events->nallocated++;
-               spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(v4l2_event_alloc);
-
-#define list_kfree(list, type, member)                         \
-       while (!list_empty(list)) {                             \
-               type *hi;                                       \
-               hi = list_first_entry(list, type, member);      \
-               list_del(&hi->member);                          \
-               kfree(hi);                                      \
-       }
-
-void v4l2_event_free(struct v4l2_fh *fh)
-{
-       struct v4l2_events *events = fh->events;
-
-       if (!events)
-               return;
-
-       list_kfree(&events->free, struct v4l2_kevent, list);
-       list_kfree(&events->available, struct v4l2_kevent, list);
-       list_kfree(&events->subscribed, struct v4l2_subscribed_event, list);
-
-       kfree(events);
-       fh->events = NULL;
+       idx += sev->first;
+       return idx >= sev->elems ? idx - sev->elems : idx;
 }
-EXPORT_SYMBOL_GPL(v4l2_event_free);
 
 static int __v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event)
 {
-       struct v4l2_events *events = fh->events;
        struct v4l2_kevent *kev;
        unsigned long flags;
 
        spin_lock_irqsave(&fh->vdev->fh_lock, flags);
 
-       if (list_empty(&events->available)) {
+       if (list_empty(&fh->available)) {
                spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
                return -ENOENT;
        }
 
-       WARN_ON(events->navailable == 0);
+       WARN_ON(fh->navailable == 0);
 
-       kev = list_first_entry(&events->available, struct v4l2_kevent, list);
-       list_move(&kev->list, &events->free);
-       events->navailable--;
+       kev = list_first_entry(&fh->available, struct v4l2_kevent, list);
+       list_del(&kev->list);
+       fh->navailable--;
 
-       kev->event.pending = events->navailable;
+       kev->event.pending = fh->navailable;
        *event = kev->event;
+       kev->sev->first = sev_pos(kev->sev, 1);
+       kev->sev->in_use--;
 
        spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
 
@@ -128,7 +67,6 @@ static int __v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event)
 int v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event,
                       int nonblocking)
 {
-       struct v4l2_events *events = fh->events;
        int ret;
 
        if (nonblocking)
@@ -139,8 +77,8 @@ int v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event,
                mutex_unlock(fh->vdev->lock);
 
        do {
-               ret = wait_event_interruptible(events->wait,
-                                              events->navailable != 0);
+               ret = wait_event_interruptible(fh->wait,
+                                              fh->navailable != 0);
                if (ret < 0)
                        break;
 
@@ -154,23 +92,72 @@ int v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event,
 }
 EXPORT_SYMBOL_GPL(v4l2_event_dequeue);
 
-/* Caller must hold fh->event->lock! */
+/* Caller must hold fh->vdev->fh_lock! */
 static struct v4l2_subscribed_event *v4l2_event_subscribed(
-       struct v4l2_fh *fh, u32 type)
+               struct v4l2_fh *fh, u32 type, u32 id)
 {
-       struct v4l2_events *events = fh->events;
        struct v4l2_subscribed_event *sev;
 
        assert_spin_locked(&fh->vdev->fh_lock);
 
-       list_for_each_entry(sev, &events->subscribed, list) {
-               if (sev->type == type)
+       list_for_each_entry(sev, &fh->subscribed, list)
+               if (sev->type == type && sev->id == id)
                        return sev;
-       }
 
        return NULL;
 }
 
+static void __v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *ev,
+               const struct timespec *ts)
+{
+       struct v4l2_subscribed_event *sev;
+       struct v4l2_kevent *kev;
+       bool copy_payload = true;
+
+       /* Are we subscribed? */
+       sev = v4l2_event_subscribed(fh, ev->type, ev->id);
+       if (sev == NULL)
+               return;
+
+       /* Increase event sequence number on fh. */
+       fh->sequence++;
+
+       /* Do we have any free events? */
+       if (sev->in_use == sev->elems) {
+               /* no, remove the oldest one */
+               kev = sev->events + sev_pos(sev, 0);
+               list_del(&kev->list);
+               sev->in_use--;
+               sev->first = sev_pos(sev, 1);
+               fh->navailable--;
+               if (sev->elems == 1) {
+                       if (sev->replace) {
+                               sev->replace(&kev->event, ev);
+                               copy_payload = false;
+                       }
+               } else if (sev->merge) {
+                       struct v4l2_kevent *second_oldest =
+                               sev->events + sev_pos(sev, 0);
+                       sev->merge(&kev->event, &second_oldest->event);
+               }
+       }
+
+       /* Take one and fill it. */
+       kev = sev->events + sev_pos(sev, sev->in_use);
+       kev->event.type = ev->type;
+       if (copy_payload)
+               kev->event.u = ev->u;
+       kev->event.id = ev->id;
+       kev->event.timestamp = *ts;
+       kev->event.sequence = fh->sequence;
+       sev->in_use++;
+       list_add_tail(&kev->list, &fh->available);
+
+       fh->navailable++;
+
+       wake_up_all(&fh->wait);
+}
+
 void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev)
 {
        struct v4l2_fh *fh;
@@ -181,81 +168,95 @@ void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev)
 
        spin_lock_irqsave(&vdev->fh_lock, flags);
 
-       list_for_each_entry(fh, &vdev->fh_list, list) {
-               struct v4l2_events *events = fh->events;
-               struct v4l2_kevent *kev;
+       list_for_each_entry(fh, &vdev->fh_list, list)
+               __v4l2_event_queue_fh(fh, ev, &timestamp);
 
-               /* Are we subscribed? */
-               if (!v4l2_event_subscribed(fh, ev->type))
-                       continue;
+       spin_unlock_irqrestore(&vdev->fh_lock, flags);
+}
+EXPORT_SYMBOL_GPL(v4l2_event_queue);
 
-               /* Increase event sequence number on fh. */
-               events->sequence++;
+void v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *ev)
+{
+       unsigned long flags;
+       struct timespec timestamp;
 
-               /* Do we have any free events? */
-               if (list_empty(&events->free))
-                       continue;
+       ktime_get_ts(&timestamp);
 
-               /* Take one and fill it. */
-               kev = list_first_entry(&events->free, struct v4l2_kevent, list);
-               kev->event.type = ev->type;
-               kev->event.u = ev->u;
-               kev->event.timestamp = timestamp;
-               kev->event.sequence = events->sequence;
-               list_move_tail(&kev->list, &events->available);
+       spin_lock_irqsave(&fh->vdev->fh_lock, flags);
+       __v4l2_event_queue_fh(fh, ev, &timestamp);
+       spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
+}
+EXPORT_SYMBOL_GPL(v4l2_event_queue_fh);
 
-               events->navailable++;
+int v4l2_event_pending(struct v4l2_fh *fh)
+{
+       return fh->navailable;
+}
+EXPORT_SYMBOL_GPL(v4l2_event_pending);
 
-               wake_up_all(&events->wait);
-       }
+static void ctrls_replace(struct v4l2_event *old, const struct v4l2_event *new)
+{
+       u32 old_changes = old->u.ctrl.changes;
 
-       spin_unlock_irqrestore(&vdev->fh_lock, flags);
+       old->u.ctrl = new->u.ctrl;
+       old->u.ctrl.changes |= old_changes;
 }
-EXPORT_SYMBOL_GPL(v4l2_event_queue);
 
-int v4l2_event_pending(struct v4l2_fh *fh)
+static void ctrls_merge(const struct v4l2_event *old, struct v4l2_event *new)
 {
-       return fh->events->navailable;
+       new->u.ctrl.changes |= old->u.ctrl.changes;
 }
-EXPORT_SYMBOL_GPL(v4l2_event_pending);
 
 int v4l2_event_subscribe(struct v4l2_fh *fh,
-                        struct v4l2_event_subscription *sub)
+                        struct v4l2_event_subscription *sub, unsigned elems)
 {
-       struct v4l2_events *events = fh->events;
-       struct v4l2_subscribed_event *sev;
+       struct v4l2_subscribed_event *sev, *found_ev;
+       struct v4l2_ctrl *ctrl = NULL;
        unsigned long flags;
-
-       if (fh->events == NULL) {
-               WARN_ON(1);
-               return -ENOMEM;
+       unsigned i;
+
+       if (elems < 1)
+               elems = 1;
+       if (sub->type == V4L2_EVENT_CTRL) {
+               ctrl = v4l2_ctrl_find(fh->ctrl_handler, sub->id);
+               if (ctrl == NULL)
+                       return -EINVAL;
        }
 
-       sev = kmalloc(sizeof(*sev), GFP_KERNEL);
+       sev = kzalloc(sizeof(*sev) + sizeof(struct v4l2_kevent) * elems, GFP_KERNEL);
        if (!sev)
                return -ENOMEM;
-
-       spin_lock_irqsave(&fh->vdev->fh_lock, flags);
-
-       if (v4l2_event_subscribed(fh, sub->type) == NULL) {
-               INIT_LIST_HEAD(&sev->list);
-               sev->type = sub->type;
-
-               list_add(&sev->list, &events->subscribed);
-               sev = NULL;
+       for (i = 0; i < elems; i++)
+               sev->events[i].sev = sev;
+       sev->type = sub->type;
+       sev->id = sub->id;
+       sev->flags = sub->flags;
+       sev->fh = fh;
+       sev->elems = elems;
+       if (ctrl) {
+               sev->replace = ctrls_replace;
+               sev->merge = ctrls_merge;
        }
 
+       spin_lock_irqsave(&fh->vdev->fh_lock, flags);
+       found_ev = v4l2_event_subscribed(fh, sub->type, sub->id);
+       if (!found_ev)
+               list_add(&sev->list, &fh->subscribed);
        spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
 
-       kfree(sev);
+       /* v4l2_ctrl_add_event uses a mutex, so do this outside the spin lock */
+       if (found_ev)
+               kfree(sev);
+       else if (ctrl)
+               v4l2_ctrl_add_event(ctrl, sev);
 
        return 0;
 }
 EXPORT_SYMBOL_GPL(v4l2_event_subscribe);
 
-static void v4l2_event_unsubscribe_all(struct v4l2_fh *fh)
+void v4l2_event_unsubscribe_all(struct v4l2_fh *fh)
 {
-       struct v4l2_events *events = fh->events;
+       struct v4l2_event_subscription sub;
        struct v4l2_subscribed_event *sev;
        unsigned long flags;
 
@@ -263,15 +264,18 @@ static void v4l2_event_unsubscribe_all(struct v4l2_fh *fh)
                sev = NULL;
 
                spin_lock_irqsave(&fh->vdev->fh_lock, flags);
-               if (!list_empty(&events->subscribed)) {
-                       sev = list_first_entry(&events->subscribed,
-                                      struct v4l2_subscribed_event, list);
-                       list_del(&sev->list);
+               if (!list_empty(&fh->subscribed)) {
+                       sev = list_first_entry(&fh->subscribed,
+                                       struct v4l2_subscribed_event, list);
+                       sub.type = sev->type;
+                       sub.id = sev->id;
                }
                spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
-               kfree(sev);
+               if (sev)
+                       v4l2_event_unsubscribe(fh, &sub);
        } while (sev);
 }
+EXPORT_SYMBOL_GPL(v4l2_event_unsubscribe_all);
 
 int v4l2_event_unsubscribe(struct v4l2_fh *fh,
                           struct v4l2_event_subscription *sub)
@@ -286,11 +290,19 @@ int v4l2_event_unsubscribe(struct v4l2_fh *fh,
 
        spin_lock_irqsave(&fh->vdev->fh_lock, flags);
 
-       sev = v4l2_event_subscribed(fh, sub->type);
-       if (sev != NULL)
+       sev = v4l2_event_subscribed(fh, sub->type, sub->id);
+       if (sev != NULL) {
                list_del(&sev->list);
+               sev->fh = NULL;
+       }
 
        spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
+       if (sev && sev->type == V4L2_EVENT_CTRL) {
+               struct v4l2_ctrl *ctrl = v4l2_ctrl_find(fh->ctrl_handler, sev->id);
+
+               if (ctrl)
+                       v4l2_ctrl_del_event(ctrl, sev);
+       }
 
        kfree(sev);
 
index 717f71e..122822d 100644 (file)
 #include <media/v4l2-event.h>
 #include <media/v4l2-ioctl.h>
 
-int v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev)
+void v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev)
 {
        fh->vdev = vdev;
+       /* Inherit from video_device. May be overridden by the driver. */
+       fh->ctrl_handler = vdev->ctrl_handler;
        INIT_LIST_HEAD(&fh->list);
        set_bit(V4L2_FL_USES_V4L2_FH, &fh->vdev->flags);
        fh->prio = V4L2_PRIORITY_UNSET;
-
-       /*
-        * fh->events only needs to be initialized if the driver
-        * supports the VIDIOC_SUBSCRIBE_EVENT ioctl.
-        */
-       if (vdev->ioctl_ops && vdev->ioctl_ops->vidioc_subscribe_event)
-               return v4l2_event_init(fh);
-
-       fh->events = NULL;
-
-       return 0;
+       init_waitqueue_head(&fh->wait);
+       INIT_LIST_HEAD(&fh->available);
+       INIT_LIST_HEAD(&fh->subscribed);
+       fh->sequence = -1;
 }
 EXPORT_SYMBOL_GPL(v4l2_fh_init);
 
@@ -91,10 +86,8 @@ void v4l2_fh_exit(struct v4l2_fh *fh)
 {
        if (fh->vdev == NULL)
                return;
-
+       v4l2_event_unsubscribe_all(fh);
        fh->vdev = NULL;
-
-       v4l2_event_free(fh);
 }
 EXPORT_SYMBOL_GPL(v4l2_fh_exit);
 
index 69e8c6f..002ce13 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/version.h>
 
 #include <linux/videodev2.h>
 
@@ -542,12 +543,12 @@ static long __video_do_ioctl(struct file *file,
        struct v4l2_fh *vfh = NULL;
        struct v4l2_format f_copy;
        int use_fh_prio = 0;
-       long ret = -EINVAL;
+       long ret = -ENOTTY;
 
        if (ops == NULL) {
                printk(KERN_WARNING "videodev: \"%s\" has no ioctl_ops.\n",
                                vfd->name);
-               return -EINVAL;
+               return ret;
        }
 
        if ((vfd->debug & V4L2_DEBUG_IOCTL) &&
@@ -605,6 +606,7 @@ static long __video_do_ioctl(struct file *file,
                if (!ops->vidioc_querycap)
                        break;
 
+               cap->version = LINUX_VERSION_CODE;
                ret = ops->vidioc_querycap(file, fh, cap);
                if (!ret)
                        dbgarg(cmd, "driver=%s, card=%s, bus=%s, "
@@ -1418,7 +1420,9 @@ static long __video_do_ioctl(struct file *file,
        {
                struct v4l2_queryctrl *p = arg;
 
-               if (vfd->ctrl_handler)
+               if (vfh && vfh->ctrl_handler)
+                       ret = v4l2_queryctrl(vfh->ctrl_handler, p);
+               else if (vfd->ctrl_handler)
                        ret = v4l2_queryctrl(vfd->ctrl_handler, p);
                else if (ops->vidioc_queryctrl)
                        ret = ops->vidioc_queryctrl(file, fh, p);
@@ -1438,7 +1442,9 @@ static long __video_do_ioctl(struct file *file,
        {
                struct v4l2_control *p = arg;
 
-               if (vfd->ctrl_handler)
+               if (vfh && vfh->ctrl_handler)
+                       ret = v4l2_g_ctrl(vfh->ctrl_handler, p);
+               else if (vfd->ctrl_handler)
                        ret = v4l2_g_ctrl(vfd->ctrl_handler, p);
                else if (ops->vidioc_g_ctrl)
                        ret = ops->vidioc_g_ctrl(file, fh, p);
@@ -1470,14 +1476,18 @@ static long __video_do_ioctl(struct file *file,
                struct v4l2_ext_controls ctrls;
                struct v4l2_ext_control ctrl;
 
-               if (!vfd->ctrl_handler &&
+               if (!(vfh && vfh->ctrl_handler) && !vfd->ctrl_handler &&
                        !ops->vidioc_s_ctrl && !ops->vidioc_s_ext_ctrls)
                        break;
 
                dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value);
 
+               if (vfh && vfh->ctrl_handler) {
+                       ret = v4l2_s_ctrl(vfh, vfh->ctrl_handler, p);
+                       break;
+               }
                if (vfd->ctrl_handler) {
-                       ret = v4l2_s_ctrl(vfd->ctrl_handler, p);
+                       ret = v4l2_s_ctrl(NULL, vfd->ctrl_handler, p);
                        break;
                }
                if (ops->vidioc_s_ctrl) {
@@ -1501,7 +1511,9 @@ static long __video_do_ioctl(struct file *file,
                struct v4l2_ext_controls *p = arg;
 
                p->error_idx = p->count;
-               if (vfd->ctrl_handler)
+               if (vfh && vfh->ctrl_handler)
+                       ret = v4l2_g_ext_ctrls(vfh->ctrl_handler, p);
+               else if (vfd->ctrl_handler)
                        ret = v4l2_g_ext_ctrls(vfd->ctrl_handler, p);
                else if (ops->vidioc_g_ext_ctrls && check_ext_ctrls(p, 0))
                        ret = ops->vidioc_g_ext_ctrls(file, fh, p);
@@ -1515,11 +1527,14 @@ static long __video_do_ioctl(struct file *file,
                struct v4l2_ext_controls *p = arg;
 
                p->error_idx = p->count;
-               if (!vfd->ctrl_handler && !ops->vidioc_s_ext_ctrls)
+               if (!(vfh && vfh->ctrl_handler) && !vfd->ctrl_handler &&
+                               !ops->vidioc_s_ext_ctrls)
                        break;
                v4l_print_ext_ctrls(cmd, vfd, p, 1);
-               if (vfd->ctrl_handler)
-                       ret = v4l2_s_ext_ctrls(vfd->ctrl_handler, p);
+               if (vfh && vfh->ctrl_handler)
+                       ret = v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, p);
+               else if (vfd->ctrl_handler)
+                       ret = v4l2_s_ext_ctrls(NULL, vfd->ctrl_handler, p);
                else if (check_ext_ctrls(p, 0))
                        ret = ops->vidioc_s_ext_ctrls(file, fh, p);
                break;
@@ -1529,10 +1544,13 @@ static long __video_do_ioctl(struct file *file,
                struct v4l2_ext_controls *p = arg;
 
                p->error_idx = p->count;
-               if (!vfd->ctrl_handler && !ops->vidioc_try_ext_ctrls)
+               if (!(vfh && vfh->ctrl_handler) && !vfd->ctrl_handler &&
+                               !ops->vidioc_try_ext_ctrls)
                        break;
                v4l_print_ext_ctrls(cmd, vfd, p, 1);
-               if (vfd->ctrl_handler)
+               if (vfh && vfh->ctrl_handler)
+                       ret = v4l2_try_ext_ctrls(vfh->ctrl_handler, p);
+               else if (vfd->ctrl_handler)
                        ret = v4l2_try_ext_ctrls(vfd->ctrl_handler, p);
                else if (check_ext_ctrls(p, 0))
                        ret = ops->vidioc_try_ext_ctrls(file, fh, p);
@@ -1542,7 +1560,9 @@ static long __video_do_ioctl(struct file *file,
        {
                struct v4l2_querymenu *p = arg;
 
-               if (vfd->ctrl_handler)
+               if (vfh && vfh->ctrl_handler)
+                       ret = v4l2_querymenu(vfh->ctrl_handler, p);
+               else if (vfd->ctrl_handler)
                        ret = v4l2_querymenu(vfd->ctrl_handler, p);
                else if (ops->vidioc_querymenu)
                        ret = ops->vidioc_querymenu(file, fh, p);
@@ -2276,7 +2296,7 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
                                break;
                        }
                        *user_ptr = (void __user *)buf->m.planes;
-                       *kernel_ptr = (void **)&buf->m.planes;
+                       *kernel_ptr = (void *)&buf->m.planes;
                        *array_size = sizeof(struct v4l2_plane) * buf->length;
                        ret = 1;
                }
@@ -2290,7 +2310,7 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
 
                if (ctrls->count != 0) {
                        *user_ptr = (void __user *)ctrls->controls;
-                       *kernel_ptr = (void **)&ctrls->controls;
+                       *kernel_ptr = (void *)&ctrls->controls;
                        *array_size = sizeof(struct v4l2_ext_control)
                                    * ctrls->count;
                        ret = 1;
index 812729e..b7967c9 100644 (file)
@@ -75,20 +75,7 @@ static int subdev_open(struct file *file)
                return ret;
        }
 
-       ret = v4l2_fh_init(&subdev_fh->vfh, vdev);
-       if (ret)
-               goto err;
-
-       if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) {
-               ret = v4l2_event_init(&subdev_fh->vfh);
-               if (ret)
-                       goto err;
-
-               ret = v4l2_event_alloc(&subdev_fh->vfh, sd->nevents);
-               if (ret)
-                       goto err;
-       }
-
+       v4l2_fh_init(&subdev_fh->vfh, vdev);
        v4l2_fh_add(&subdev_fh->vfh);
        file->private_data = &subdev_fh->vfh;
 #if defined(CONFIG_MEDIA_CONTROLLER)
@@ -155,25 +142,25 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
        switch (cmd) {
        case VIDIOC_QUERYCTRL:
-               return v4l2_queryctrl(sd->ctrl_handler, arg);
+               return v4l2_queryctrl(vfh->ctrl_handler, arg);
 
        case VIDIOC_QUERYMENU:
-               return v4l2_querymenu(sd->ctrl_handler, arg);
+               return v4l2_querymenu(vfh->ctrl_handler, arg);
 
        case VIDIOC_G_CTRL:
-               return v4l2_g_ctrl(sd->ctrl_handler, arg);
+               return v4l2_g_ctrl(vfh->ctrl_handler, arg);
 
        case VIDIOC_S_CTRL:
-               return v4l2_s_ctrl(sd->ctrl_handler, arg);
+               return v4l2_s_ctrl(vfh, vfh->ctrl_handler, arg);
 
        case VIDIOC_G_EXT_CTRLS:
-               return v4l2_g_ext_ctrls(sd->ctrl_handler, arg);
+               return v4l2_g_ext_ctrls(vfh->ctrl_handler, arg);
 
        case VIDIOC_S_EXT_CTRLS:
-               return v4l2_s_ext_ctrls(sd->ctrl_handler, arg);
+               return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, arg);
 
        case VIDIOC_TRY_EXT_CTRLS:
-               return v4l2_try_ext_ctrls(sd->ctrl_handler, arg);
+               return v4l2_try_ext_ctrls(vfh->ctrl_handler, arg);
 
        case VIDIOC_DQEVENT:
                if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
@@ -297,7 +284,7 @@ static unsigned int subdev_poll(struct file *file, poll_table *wait)
        if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
                return POLLERR;
 
-       poll_wait(file, &fh->events->wait, wait);
+       poll_wait(file, &fh->wait, wait);
 
        if (v4l2_event_pending(fh))
                return POLLPRI;
index ddb8f4b..f300dea 100644 (file)
@@ -108,8 +108,9 @@ static struct scatterlist *videobuf_pages_to_sg(struct page **pages,
        if (PageHighMem(pages[0]))
                /* DMA to highmem pages might not work */
                goto highmem;
-       sg_set_page(&sglist[0], pages[0], PAGE_SIZE - offset, offset);
-       size -= PAGE_SIZE - offset;
+       sg_set_page(&sglist[0], pages[0],
+                       min_t(size_t, PAGE_SIZE - offset, size), offset);
+       size -= min_t(size_t, PAGE_SIZE - offset, size);
        for (i = 1; i < nr_pages; i++) {
                if (NULL == pages[i])
                        goto nopage;
index 10a20d9..065f468 100644 (file)
@@ -48,12 +48,10 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size)
        buf->sg_desc.size = size;
        buf->sg_desc.num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
 
-       buf->sg_desc.sglist = vmalloc(buf->sg_desc.num_pages *
+       buf->sg_desc.sglist = vzalloc(buf->sg_desc.num_pages *
                                      sizeof(*buf->sg_desc.sglist));
        if (!buf->sg_desc.sglist)
                goto fail_sglist_alloc;
-       memset(buf->sg_desc.sglist, 0, buf->sg_desc.num_pages *
-              sizeof(*buf->sg_desc.sglist));
        sg_init_table(buf->sg_desc.sglist, buf->sg_desc.num_pages);
 
        buf->pages = kzalloc(buf->sg_desc.num_pages * sizeof(struct page *),
@@ -136,13 +134,11 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
        last  = ((vaddr + size - 1) & PAGE_MASK) >> PAGE_SHIFT;
        buf->sg_desc.num_pages = last - first + 1;
 
-       buf->sg_desc.sglist = vmalloc(
+       buf->sg_desc.sglist = vzalloc(
                buf->sg_desc.num_pages * sizeof(*buf->sg_desc.sglist));
        if (!buf->sg_desc.sglist)
                goto userptr_fail_sglist_alloc;
 
-       memset(buf->sg_desc.sglist, 0,
-               buf->sg_desc.num_pages * sizeof(*buf->sg_desc.sglist));
        sg_init_table(buf->sg_desc.sglist, buf->sg_desc.num_pages);
 
        buf->pages = kzalloc(buf->sg_desc.num_pages * sizeof(struct page *),
index b03c3ae..569eeb3 100644 (file)
@@ -176,7 +176,7 @@ int vb2_mmap_pfn_range(struct vm_area_struct *vma, unsigned long paddr,
 
        vma->vm_ops->open(vma);
 
-       printk(KERN_DEBUG "%s: mapped paddr 0x%08lx at 0x%08lx, size %ld\n",
+       pr_debug("%s: mapped paddr 0x%08lx at 0x%08lx, size %ld\n",
                        __func__, paddr, vma->vm_start, size);
 
        return 0;
@@ -194,7 +194,7 @@ static void vb2_common_vm_open(struct vm_area_struct *vma)
 {
        struct vb2_vmarea_handler *h = vma->vm_private_data;
 
-       printk(KERN_DEBUG "%s: %p, refcount: %d, vma: %08lx-%08lx\n",
+       pr_debug("%s: %p, refcount: %d, vma: %08lx-%08lx\n",
               __func__, h, atomic_read(h->refcount), vma->vm_start,
               vma->vm_end);
 
@@ -212,7 +212,7 @@ static void vb2_common_vm_close(struct vm_area_struct *vma)
 {
        struct vb2_vmarea_handler *h = vma->vm_private_data;
 
-       printk(KERN_DEBUG "%s: %p, refcount: %d, vma: %08lx-%08lx\n",
+       pr_debug("%s: %p, refcount: %d, vma: %08lx-%08lx\n",
               __func__, h, atomic_read(h->refcount), vma->vm_start,
               vma->vm_end);
 
index d63e9d9..52a0a37 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/time.h>
-#include <linux/version.h>
 #include <linux/kmod.h>
 
 #include <linux/i2c.h>
@@ -61,8 +60,7 @@
 // #define VINO_DEBUG
 // #define VINO_DEBUG_INT
 
-#define VINO_MODULE_VERSION "0.0.6"
-#define VINO_VERSION_CODE KERNEL_VERSION(0, 0, 6)
+#define VINO_MODULE_VERSION "0.0.7"
 
 MODULE_DESCRIPTION("SGI VINO Video4Linux2 driver");
 MODULE_VERSION(VINO_MODULE_VERSION);
@@ -2934,7 +2932,6 @@ static int vino_querycap(struct file *file, void *__fh,
        strcpy(cap->driver, vino_driver_name);
        strcpy(cap->card, vino_driver_description);
        strcpy(cap->bus_info, vino_bus_name);
-       cap->version = VINO_VERSION_CODE;
        cap->capabilities =
                V4L2_CAP_VIDEO_CAPTURE |
                V4L2_CAP_STREAMING;
index 2238a61..a848bd2 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/font.h>
-#include <linux/version.h>
 #include <linux/mutex.h>
 #include <linux/videodev2.h>
 #include <linux/kthread.h>
@@ -32,6 +31,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
 #include <media/v4l2-common.h>
 
 #define VIVI_MODULE_NAME "vivi"
 #define MAX_WIDTH 1920
 #define MAX_HEIGHT 1200
 
-#define VIVI_MAJOR_VERSION 0
-#define VIVI_MINOR_VERSION 8
-#define VIVI_RELEASE 0
-#define VIVI_VERSION \
-       KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
+#define VIVI_VERSION "0.8.1"
 
 MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
 MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
 MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(VIVI_VERSION);
 
 static unsigned video_nr = -1;
 module_param(video_nr, uint, 0644);
@@ -167,6 +164,11 @@ struct vivi_dev {
        struct v4l2_ctrl           *contrast;
        struct v4l2_ctrl           *saturation;
        struct v4l2_ctrl           *hue;
+       struct {
+               /* autogain/gain cluster */
+               struct v4l2_ctrl           *autogain;
+               struct v4l2_ctrl           *gain;
+       };
        struct v4l2_ctrl           *volume;
        struct v4l2_ctrl           *button;
        struct v4l2_ctrl           *boolean;
@@ -174,6 +176,7 @@ struct vivi_dev {
        struct v4l2_ctrl           *int64;
        struct v4l2_ctrl           *menu;
        struct v4l2_ctrl           *string;
+       struct v4l2_ctrl           *bitmask;
 
        spinlock_t                 slock;
        struct mutex               mutex;
@@ -457,6 +460,7 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
        unsigned ms;
        char str[100];
        int h, line = 1;
+       s32 gain;
 
        if (!vbuf)
                return;
@@ -479,6 +483,7 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
                        dev->width, dev->height, dev->input);
        gen_text(dev, vbuf, line++ * 16, 16, str);
 
+       gain = v4l2_ctrl_g_ctrl(dev->gain);
        mutex_lock(&dev->ctrl_handler.lock);
        snprintf(str, sizeof(str), " brightness %3d, contrast %3d, saturation %3d, hue %d ",
                        dev->brightness->cur.val,
@@ -486,11 +491,13 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
                        dev->saturation->cur.val,
                        dev->hue->cur.val);
        gen_text(dev, vbuf, line++ * 16, 16, str);
-       snprintf(str, sizeof(str), " volume %3d ", dev->volume->cur.val);
+       snprintf(str, sizeof(str), " autogain %d, gain %3d, volume %3d ",
+                       dev->autogain->cur.val, gain, dev->volume->cur.val);
        gen_text(dev, vbuf, line++ * 16, 16, str);
-       snprintf(str, sizeof(str), " int32 %d, int64 %lld ",
+       snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ",
                        dev->int32->cur.val,
-                       dev->int64->cur.val64);
+                       dev->int64->cur.val64,
+                       dev->bitmask->cur.val);
        gen_text(dev, vbuf, line++ * 16, 16, str);
        snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ",
                        dev->boolean->cur.val,
@@ -524,11 +531,13 @@ static void vivi_thread_tick(struct vivi_dev *dev)
        spin_lock_irqsave(&dev->slock, flags);
        if (list_empty(&dma_q->active)) {
                dprintk(dev, 1, "No active queue to serve\n");
-               goto unlock;
+               spin_unlock_irqrestore(&dev->slock, flags);
+               return;
        }
 
        buf = list_entry(dma_q->active.next, struct vivi_buffer, list);
        list_del(&buf->list);
+       spin_unlock_irqrestore(&dev->slock, flags);
 
        do_gettimeofday(&buf->vb.v4l2_buf.timestamp);
 
@@ -538,8 +547,6 @@ static void vivi_thread_tick(struct vivi_dev *dev)
 
        vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
        dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);
-unlock:
-       spin_unlock_irqrestore(&dev->slock, flags);
 }
 
 #define frames_to_ms(frames)                                   \
@@ -812,7 +819,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        strcpy(cap->driver, "vivi");
        strcpy(cap->card, "vivi");
        strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
-       cap->version = VIVI_VERSION;
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | \
                            V4L2_CAP_READWRITE;
        return 0;
@@ -975,14 +981,37 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
        if (i >= NUM_INPUTS)
                return -EINVAL;
 
+       if (i == dev->input)
+               return 0;
+
        dev->input = i;
        precalculate_bars(dev);
        precalculate_line(dev);
        return 0;
 }
 
+static int vidioc_subscribe_event(struct v4l2_fh *fh,
+                               struct v4l2_event_subscription *sub)
+{
+       switch (sub->type) {
+       case V4L2_EVENT_CTRL:
+               return v4l2_event_subscribe(fh, sub, 0);
+       default:
+               return -EINVAL;
+       }
+}
+
 /* --- controls ---------------------------------------------- */
 
+static int vivi_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler);
+
+       if (ctrl == dev->autogain)
+               dev->gain->val = jiffies & 0xff;
+       return 0;
+}
+
 static int vivi_s_ctrl(struct v4l2_ctrl *ctrl)
 {
        struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler);
@@ -1010,10 +1039,17 @@ static unsigned int
 vivi_poll(struct file *file, struct poll_table_struct *wait)
 {
        struct vivi_dev *dev = video_drvdata(file);
+       struct v4l2_fh *fh = file->private_data;
        struct vb2_queue *q = &dev->vb_vidq;
+       unsigned int res;
 
        dprintk(dev, 1, "%s\n", __func__);
-       return vb2_poll(q, file, wait);
+       res = vb2_poll(q, file, wait);
+       if (v4l2_event_pending(fh))
+               res |= POLLPRI;
+       else
+               poll_wait(file, &fh->wait, wait);
+       return res;
 }
 
 static int vivi_close(struct file *file)
@@ -1045,6 +1081,7 @@ static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
 }
 
 static const struct v4l2_ctrl_ops vivi_ctrl_ops = {
+       .g_volatile_ctrl = vivi_g_volatile_ctrl,
        .s_ctrl = vivi_s_ctrl,
 };
 
@@ -1117,9 +1154,20 @@ static const struct v4l2_ctrl_config vivi_ctrl_string = {
        .step = 1,
 };
 
+static const struct v4l2_ctrl_config vivi_ctrl_bitmask = {
+       .ops = &vivi_ctrl_ops,
+       .id = VIVI_CID_CUSTOM_BASE + 6,
+       .name = "Bitmask",
+       .type = V4L2_CTRL_TYPE_BITMASK,
+       .def = 0x80002000,
+       .min = 0,
+       .max = 0x80402010,
+       .step = 0,
+};
+
 static const struct v4l2_file_operations vivi_fops = {
        .owner          = THIS_MODULE,
-       .open           = v4l2_fh_open,
+       .open           = v4l2_fh_open,
        .release        = vivi_close,
        .read           = vivi_read,
        .poll           = vivi_poll,
@@ -1143,6 +1191,8 @@ static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
        .vidioc_s_input       = vidioc_s_input,
        .vidioc_streamon      = vidioc_streamon,
        .vidioc_streamoff     = vidioc_streamoff,
+       .vidioc_subscribe_event = vidioc_subscribe_event,
+       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
 static struct video_device vivi_template = {
@@ -1213,16 +1263,22 @@ static int __init vivi_create_instance(int inst)
                        V4L2_CID_SATURATION, 0, 255, 1, 127);
        dev->hue = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
                        V4L2_CID_HUE, -128, 127, 1, 0);
+       dev->autogain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+                       V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+       dev->gain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+                       V4L2_CID_GAIN, 0, 255, 1, 100);
        dev->button = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_button, NULL);
        dev->int32 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int32, NULL);
        dev->int64 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int64, NULL);
        dev->boolean = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_boolean, NULL);
        dev->menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_menu, NULL);
        dev->string = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_string, NULL);
+       dev->bitmask = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_bitmask, NULL);
        if (hdl->error) {
                ret = hdl->error;
                goto unreg_dev;
        }
+       v4l2_ctrl_auto_cluster(2, &dev->autogain, 0, true);
        dev->v4l2_dev.ctrl_handler = hdl;
 
        /* initialize locks */
@@ -1325,9 +1381,8 @@ static int __init vivi_init(void)
        }
 
        printk(KERN_INFO "Video Technology Magazine Virtual Video "
-                       "Capture Board ver %u.%u.%u successfully loaded.\n",
-                       (VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF,
-                       VIVI_VERSION & 0xFF);
+                       "Capture Board ver %s successfully loaded.\n",
+                       VIVI_VERSION);
 
        /* n_devs will reflect the actual number of allocated devices */
        n_devs = i;
index fa35639..453dbbd 100644 (file)
@@ -57,7 +57,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/delay.h>
-#include <linux/version.h>
 #include <linux/videodev2.h>
 #include <linux/slab.h>
 #include <media/v4l2-common.h>
@@ -127,7 +126,7 @@ struct w9966 {
 MODULE_AUTHOR("Jakob Kemi <jakob.kemi@post.utfors.se>");
 MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (0.32)");
 MODULE_LICENSE("GPL");
-
+MODULE_VERSION("0.33.1");
 
 #ifdef MODULE
 static const char *pardev[] = {[0 ... W9966_MAXCAMS] = ""};
@@ -568,7 +567,6 @@ static int cam_querycap(struct file *file, void  *priv,
        strlcpy(vcap->driver, cam->v4l2_dev.name, sizeof(vcap->driver));
        strlcpy(vcap->card, W9966_DRIVERNAME, sizeof(vcap->card));
        strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
-       vcap->version = KERNEL_VERSION(0, 33, 0);
        vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
        return 0;
 }
index f3f6400..d7166af 100644 (file)
@@ -41,10 +41,6 @@ struct zoran_sync {
 };
 
 
-#define MAJOR_VERSION 0                /* driver major version */
-#define MINOR_VERSION 10       /* driver minor version */
-#define RELEASE_VERSION 0      /* release version */
-
 #define ZORAN_NAME    "ZORAN"  /* name of the device */
 
 #define ZR_DEVNAME(zr) ((zr)->name)
index 79b04ac..c3602d6 100644 (file)
@@ -123,9 +123,12 @@ int zr36067_debug = 1;
 module_param_named(debug, zr36067_debug, int, 0644);
 MODULE_PARM_DESC(debug, "Debug level (0-5)");
 
+#define ZORAN_VERSION "0.10.1"
+
 MODULE_DESCRIPTION("Zoran-36057/36067 JPEG codec driver");
 MODULE_AUTHOR("Serguei Miridonov");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(ZORAN_VERSION);
 
 #define ZR_DEVICE(subven, subdev, data)        { \
        .vendor = PCI_VENDOR_ID_ZORAN, .device = PCI_DEVICE_ID_ZORAN_36057, \
@@ -1459,8 +1462,8 @@ static int __init zoran_init(void)
 {
        int res;
 
-       printk(KERN_INFO "Zoran MJPEG board driver version %d.%d.%d\n",
-              MAJOR_VERSION, MINOR_VERSION, RELEASE_VERSION);
+       printk(KERN_INFO "Zoran MJPEG board driver version %s\n",
+              ZORAN_VERSION);
 
        /* check the parameters we have been given, adjust if necessary */
        if (v4l_nbufs < 2)
index 2771d81..d4d05d2 100644 (file)
@@ -44,7 +44,6 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/delay.h>
@@ -1538,8 +1537,6 @@ static int zoran_querycap(struct file *file, void *__fh, struct v4l2_capability
        strncpy(cap->driver, "zoran", sizeof(cap->driver)-1);
        snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
                 pci_name(zr->pci_dev));
-       cap->version = KERNEL_VERSION(MAJOR_VERSION, MINOR_VERSION,
-                          RELEASE_VERSION);
        cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE |
                            V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OVERLAY;
        return 0;
index 7dfb01e..c492846 100644 (file)
@@ -29,7 +29,6 @@
 
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/usb.h>
 #include <linux/vmalloc.h>
@@ -42,8 +41,7 @@
 
 
 /* Version Information */
-#define DRIVER_VERSION "v0.73"
-#define ZR364XX_VERSION_CODE KERNEL_VERSION(0, 7, 3)
+#define DRIVER_VERSION "0.7.4"
 #define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/"
 #define DRIVER_DESC "Zoran 364xx"
 
@@ -744,7 +742,6 @@ static int zr364xx_vidioc_querycap(struct file *file, void *priv,
        strlcpy(cap->card, cam->udev->product, sizeof(cap->card));
        strlcpy(cap->bus_info, dev_name(&cam->udev->dev),
                sizeof(cap->bus_info));
-       cap->version = ZR364XX_VERSION_CODE;
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
                            V4L2_CAP_READWRITE |
                            V4L2_CAP_STREAMING;
@@ -1721,3 +1718,4 @@ module_exit(zr364xx_exit);
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
index a1d4ee6..ce61a57 100644 (file)
@@ -827,7 +827,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
                                 * DID_SOFT_ERROR is set.
                                 */
                                if (ioc->bus_type == SPI) {
-                                       if (pScsiReq->CDB[0] == READ_6  ||
+                                       if ((pScsiReq->CDB[0] == READ_6  && ((pScsiReq->CDB[1] & 0x02) == 0)) ||
                                            pScsiReq->CDB[0] == READ_10 ||
                                            pScsiReq->CDB[0] == READ_12 ||
                                            pScsiReq->CDB[0] == READ_16 ||
index 37b83eb..21574bd 100644 (file)
@@ -171,6 +171,37 @@ config MFD_TPS6586X
          This driver can also be built as a module.  If so, the module
          will be called tps6586x.
 
+config MFD_TPS65910
+       bool "TPS65910 Power Management chip"
+       depends on I2C=y && GPIOLIB
+       select MFD_CORE
+       select GPIO_TPS65910
+       help
+         if you say yes here you get support for the TPS65910 series of
+         Power Management chips.
+
+config MFD_TPS65912
+       bool
+       depends on GPIOLIB
+
+config MFD_TPS65912_I2C
+       bool "TPS95612 Power Management chip with I2C"
+       select MFD_CORE
+       select MFD_TPS65912
+       depends on I2C=y && GPIOLIB
+       help
+         If you say yes here you get support for the TPS65912 series of
+         PM chips with I2C interface.
+
+config MFD_TPS65912_SPI
+       bool "TPS65912 Power Management chip with SPI"
+       select MFD_CORE
+       select MFD_TPS65912
+       depends on SPI_MASTER && GPIOLIB
+       help
+         If you say yes here you get support for the TPS65912 series of
+         PM chips with SPI interface.
+
 config MENELAUS
        bool "Texas Instruments TWL92330/Menelaus PM chip"
        depends on I2C=y && ARCH_OMAP2
@@ -662,8 +693,9 @@ config MFD_JANZ_CMODIO
          CAN and GPIO controllers.
 
 config MFD_JZ4740_ADC
-       tristate "Support for the JZ4740 SoC ADC core"
+       bool "Support for the JZ4740 SoC ADC core"
        select MFD_CORE
+       select GENERIC_IRQ_CHIP
        depends on MACH_JZ4740
        help
          Say yes here if you want support for the ADC unit in the JZ4740 SoC.
@@ -725,18 +757,19 @@ config MFD_PM8XXX_IRQ
          This is required to use certain other PM 8xxx features, such as GPIO
          and MPP.
 
-config MFD_TPS65910
-       bool "TPS65910 Power Management chip"
-       depends on I2C=y && GPIOLIB
-       select MFD_CORE
-       select GPIO_TPS65910
-       help
-         if you say yes here you get support for the TPS65910 series of
-         Power Management chips.
-
 config TPS65911_COMPARATOR
        tristate
 
+config MFD_AAT2870_CORE
+       bool "Support for the AnalogicTech AAT2870"
+       select MFD_CORE
+       depends on I2C=y && GPIOLIB
+       help
+         If you say yes here you get support for the AAT2870.
+         This driver provides common support for accessing the device,
+         additional drivers must be enabled in order to use the
+         functionality of the device.
+
 endif # MFD_SUPPORT
 
 menu "Multimedia Capabilities Port drivers"
index 22a280f..c580203 100644 (file)
@@ -23,6 +23,7 @@ obj-$(CONFIG_MFD_TC6393XB)    += tc6393xb.o tmio_core.o
 
 obj-$(CONFIG_MFD_WM8400)       += wm8400-core.o
 wm831x-objs                    := wm831x-core.o wm831x-irq.o wm831x-otp.o
+wm831x-objs                    += wm831x-auxadc.o
 obj-$(CONFIG_MFD_WM831X)       += wm831x.o
 obj-$(CONFIG_MFD_WM831X_I2C)   += wm831x-i2c.o
 obj-$(CONFIG_MFD_WM831X_SPI)   += wm831x-spi.o
@@ -35,6 +36,11 @@ obj-$(CONFIG_MFD_WM8994)     += wm8994-core.o wm8994-irq.o
 obj-$(CONFIG_TPS6105X)         += tps6105x.o
 obj-$(CONFIG_TPS65010)         += tps65010.o
 obj-$(CONFIG_TPS6507X)         += tps6507x.o
+obj-$(CONFIG_MFD_TPS65910)     += tps65910.o tps65910-irq.o
+tps65912-objs                   := tps65912-core.o tps65912-irq.o
+obj-$(CONFIG_MFD_TPS65912)     += tps65912.o
+obj-$(CONFIG_MFD_TPS65912_I2C) += tps65912-i2c.o
+obj-$(CONFIG_MFD_TPS65912_SPI)  += tps65912-spi.o
 obj-$(CONFIG_MENELAUS)         += menelaus.o
 
 obj-$(CONFIG_TWL4030_CORE)     += twl-core.o twl4030-irq.o twl6030-irq.o
@@ -94,5 +100,5 @@ obj-$(CONFIG_MFD_CS5535)     += cs5535-mfd.o
 obj-$(CONFIG_MFD_OMAP_USB_HOST)        += omap-usb-host.o
 obj-$(CONFIG_MFD_PM8921_CORE)  += pm8921-core.o
 obj-$(CONFIG_MFD_PM8XXX_IRQ)   += pm8xxx-irq.o
-obj-$(CONFIG_MFD_TPS65910)     += tps65910.o tps65910-irq.o
 obj-$(CONFIG_TPS65911_COMPARATOR)      += tps65911-comparator.o
+obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o
diff --git a/drivers/mfd/aat2870-core.c b/drivers/mfd/aat2870-core.c
new file mode 100644 (file)
index 0000000..345dc65
--- /dev/null
@@ -0,0 +1,535 @@
+/*
+ * linux/drivers/mfd/aat2870-core.c
+ *
+ * Copyright (c) 2011, NVIDIA Corporation.
+ * Author: Jin Park <jinyoungp@nvidia.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
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/aat2870.h>
+#include <linux/regulator/machine.h>
+
+static struct aat2870_register aat2870_regs[AAT2870_REG_NUM] = {
+       /* readable, writeable, value */
+       { 0, 1, 0x00 }, /* 0x00 AAT2870_BL_CH_EN */
+       { 0, 1, 0x16 }, /* 0x01 AAT2870_BLM */
+       { 0, 1, 0x16 }, /* 0x02 AAT2870_BLS */
+       { 0, 1, 0x56 }, /* 0x03 AAT2870_BL1 */
+       { 0, 1, 0x56 }, /* 0x04 AAT2870_BL2 */
+       { 0, 1, 0x56 }, /* 0x05 AAT2870_BL3 */
+       { 0, 1, 0x56 }, /* 0x06 AAT2870_BL4 */
+       { 0, 1, 0x56 }, /* 0x07 AAT2870_BL5 */
+       { 0, 1, 0x56 }, /* 0x08 AAT2870_BL6 */
+       { 0, 1, 0x56 }, /* 0x09 AAT2870_BL7 */
+       { 0, 1, 0x56 }, /* 0x0A AAT2870_BL8 */
+       { 0, 1, 0x00 }, /* 0x0B AAT2870_FLR */
+       { 0, 1, 0x03 }, /* 0x0C AAT2870_FM */
+       { 0, 1, 0x03 }, /* 0x0D AAT2870_FS */
+       { 0, 1, 0x10 }, /* 0x0E AAT2870_ALS_CFG0 */
+       { 0, 1, 0x06 }, /* 0x0F AAT2870_ALS_CFG1 */
+       { 0, 1, 0x00 }, /* 0x10 AAT2870_ALS_CFG2 */
+       { 1, 0, 0x00 }, /* 0x11 AAT2870_AMB */
+       { 0, 1, 0x00 }, /* 0x12 AAT2870_ALS0 */
+       { 0, 1, 0x00 }, /* 0x13 AAT2870_ALS1 */
+       { 0, 1, 0x00 }, /* 0x14 AAT2870_ALS2 */
+       { 0, 1, 0x00 }, /* 0x15 AAT2870_ALS3 */
+       { 0, 1, 0x00 }, /* 0x16 AAT2870_ALS4 */
+       { 0, 1, 0x00 }, /* 0x17 AAT2870_ALS5 */
+       { 0, 1, 0x00 }, /* 0x18 AAT2870_ALS6 */
+       { 0, 1, 0x00 }, /* 0x19 AAT2870_ALS7 */
+       { 0, 1, 0x00 }, /* 0x1A AAT2870_ALS8 */
+       { 0, 1, 0x00 }, /* 0x1B AAT2870_ALS9 */
+       { 0, 1, 0x00 }, /* 0x1C AAT2870_ALSA */
+       { 0, 1, 0x00 }, /* 0x1D AAT2870_ALSB */
+       { 0, 1, 0x00 }, /* 0x1E AAT2870_ALSC */
+       { 0, 1, 0x00 }, /* 0x1F AAT2870_ALSD */
+       { 0, 1, 0x00 }, /* 0x20 AAT2870_ALSE */
+       { 0, 1, 0x00 }, /* 0x21 AAT2870_ALSF */
+       { 0, 1, 0x00 }, /* 0x22 AAT2870_SUB_SET */
+       { 0, 1, 0x00 }, /* 0x23 AAT2870_SUB_CTRL */
+       { 0, 1, 0x00 }, /* 0x24 AAT2870_LDO_AB */
+       { 0, 1, 0x00 }, /* 0x25 AAT2870_LDO_CD */
+       { 0, 1, 0x00 }, /* 0x26 AAT2870_LDO_EN */
+};
+
+static struct mfd_cell aat2870_devs[] = {
+       {
+               .name = "aat2870-backlight",
+               .id = AAT2870_ID_BL,
+               .pdata_size = sizeof(struct aat2870_bl_platform_data),
+       },
+       {
+               .name = "aat2870-regulator",
+               .id = AAT2870_ID_LDOA,
+               .pdata_size = sizeof(struct regulator_init_data),
+       },
+       {
+               .name = "aat2870-regulator",
+               .id = AAT2870_ID_LDOB,
+               .pdata_size = sizeof(struct regulator_init_data),
+       },
+       {
+               .name = "aat2870-regulator",
+               .id = AAT2870_ID_LDOC,
+               .pdata_size = sizeof(struct regulator_init_data),
+       },
+       {
+               .name = "aat2870-regulator",
+               .id = AAT2870_ID_LDOD,
+               .pdata_size = sizeof(struct regulator_init_data),
+       },
+};
+
+static int __aat2870_read(struct aat2870_data *aat2870, u8 addr, u8 *val)
+{
+       int ret;
+
+       if (addr >= AAT2870_REG_NUM) {
+               dev_err(aat2870->dev, "Invalid address, 0x%02x\n", addr);
+               return -EINVAL;
+       }
+
+       if (!aat2870->reg_cache[addr].readable) {
+               *val = aat2870->reg_cache[addr].value;
+               goto out;
+       }
+
+       ret = i2c_master_send(aat2870->client, &addr, 1);
+       if (ret < 0)
+               return ret;
+       if (ret != 1)
+               return -EIO;
+
+       ret = i2c_master_recv(aat2870->client, val, 1);
+       if (ret < 0)
+               return ret;
+       if (ret != 1)
+               return -EIO;
+
+out:
+       dev_dbg(aat2870->dev, "read: addr=0x%02x, val=0x%02x\n", addr, *val);
+       return 0;
+}
+
+static int __aat2870_write(struct aat2870_data *aat2870, u8 addr, u8 val)
+{
+       u8 msg[2];
+       int ret;
+
+       if (addr >= AAT2870_REG_NUM) {
+               dev_err(aat2870->dev, "Invalid address, 0x%02x\n", addr);
+               return -EINVAL;
+       }
+
+       if (!aat2870->reg_cache[addr].writeable) {
+               dev_err(aat2870->dev, "Address 0x%02x is not writeable\n",
+                       addr);
+               return -EINVAL;
+       }
+
+       msg[0] = addr;
+       msg[1] = val;
+       ret = i2c_master_send(aat2870->client, msg, 2);
+       if (ret < 0)
+               return ret;
+       if (ret != 2)
+               return -EIO;
+
+       aat2870->reg_cache[addr].value = val;
+
+       dev_dbg(aat2870->dev, "write: addr=0x%02x, val=0x%02x\n", addr, val);
+       return 0;
+}
+
+static int aat2870_read(struct aat2870_data *aat2870, u8 addr, u8 *val)
+{
+       int ret;
+
+       mutex_lock(&aat2870->io_lock);
+       ret = __aat2870_read(aat2870, addr, val);
+       mutex_unlock(&aat2870->io_lock);
+
+       return ret;
+}
+
+static int aat2870_write(struct aat2870_data *aat2870, u8 addr, u8 val)
+{
+       int ret;
+
+       mutex_lock(&aat2870->io_lock);
+       ret = __aat2870_write(aat2870, addr, val);
+       mutex_unlock(&aat2870->io_lock);
+
+       return ret;
+}
+
+static int aat2870_update(struct aat2870_data *aat2870, u8 addr, u8 mask,
+                         u8 val)
+{
+       int change;
+       u8 old_val, new_val;
+       int ret;
+
+       mutex_lock(&aat2870->io_lock);
+
+       ret = __aat2870_read(aat2870, addr, &old_val);
+       if (ret)
+               goto out_unlock;
+
+       new_val = (old_val & ~mask) | (val & mask);
+       change = old_val != new_val;
+       if (change)
+               ret = __aat2870_write(aat2870, addr, new_val);
+
+out_unlock:
+       mutex_unlock(&aat2870->io_lock);
+
+       return ret;
+}
+
+static inline void aat2870_enable(struct aat2870_data *aat2870)
+{
+       if (aat2870->en_pin >= 0)
+               gpio_set_value(aat2870->en_pin, 1);
+
+       aat2870->is_enable = 1;
+}
+
+static inline void aat2870_disable(struct aat2870_data *aat2870)
+{
+       if (aat2870->en_pin >= 0)
+               gpio_set_value(aat2870->en_pin, 0);
+
+       aat2870->is_enable = 0;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t aat2870_dump_reg(struct aat2870_data *aat2870, char *buf)
+{
+       u8 addr, val;
+       ssize_t count = 0;
+       int ret;
+
+       count += sprintf(buf, "aat2870 registers\n");
+       for (addr = 0; addr < AAT2870_REG_NUM; addr++) {
+               count += sprintf(buf + count, "0x%02x: ", addr);
+               if (count >= PAGE_SIZE - 1)
+                       break;
+
+               ret = aat2870->read(aat2870, addr, &val);
+               if (ret == 0)
+                       count += snprintf(buf + count, PAGE_SIZE - count,
+                                         "0x%02x", val);
+               else
+                       count += snprintf(buf + count, PAGE_SIZE - count,
+                                         "<read fail: %d>", ret);
+
+               if (count >= PAGE_SIZE - 1)
+                       break;
+
+               count += snprintf(buf + count, PAGE_SIZE - count, "\n");
+               if (count >= PAGE_SIZE - 1)
+                       break;
+       }
+
+       /* Truncate count; min() would cause a warning */
+       if (count >= PAGE_SIZE)
+               count = PAGE_SIZE - 1;
+
+       return count;
+}
+
+static int aat2870_reg_open_file(struct inode *inode, struct file *file)
+{
+       file->private_data = inode->i_private;
+
+       return 0;
+}
+
+static ssize_t aat2870_reg_read_file(struct file *file, char __user *user_buf,
+                                    size_t count, loff_t *ppos)
+{
+       struct aat2870_data *aat2870 = file->private_data;
+       char *buf;
+       ssize_t ret;
+
+       buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       ret = aat2870_dump_reg(aat2870, buf);
+       if (ret >= 0)
+               ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+       kfree(buf);
+
+       return ret;
+}
+
+static ssize_t aat2870_reg_write_file(struct file *file,
+                                     const char __user *user_buf, size_t count,
+                                     loff_t *ppos)
+{
+       struct aat2870_data *aat2870 = file->private_data;
+       char buf[32];
+       int buf_size;
+       char *start = buf;
+       unsigned long addr, val;
+       int ret;
+
+       buf_size = min(count, (sizeof(buf)-1));
+       if (copy_from_user(buf, user_buf, buf_size)) {
+               dev_err(aat2870->dev, "Failed to copy from user\n");
+               return -EFAULT;
+       }
+       buf[buf_size] = 0;
+
+       while (*start == ' ')
+               start++;
+
+       addr = simple_strtoul(start, &start, 16);
+       if (addr >= AAT2870_REG_NUM) {
+               dev_err(aat2870->dev, "Invalid address, 0x%lx\n", addr);
+               return -EINVAL;
+       }
+
+       while (*start == ' ')
+               start++;
+
+       if (strict_strtoul(start, 16, &val))
+               return -EINVAL;
+
+       ret = aat2870->write(aat2870, (u8)addr, (u8)val);
+       if (ret)
+               return ret;
+
+       return buf_size;
+}
+
+static const struct file_operations aat2870_reg_fops = {
+       .open = aat2870_reg_open_file,
+       .read = aat2870_reg_read_file,
+       .write = aat2870_reg_write_file,
+};
+
+static void aat2870_init_debugfs(struct aat2870_data *aat2870)
+{
+       aat2870->dentry_root = debugfs_create_dir("aat2870", NULL);
+       if (!aat2870->dentry_root) {
+               dev_warn(aat2870->dev,
+                        "Failed to create debugfs root directory\n");
+               return;
+       }
+
+       aat2870->dentry_reg = debugfs_create_file("regs", 0644,
+                                                 aat2870->dentry_root,
+                                                 aat2870, &aat2870_reg_fops);
+       if (!aat2870->dentry_reg)
+               dev_warn(aat2870->dev,
+                        "Failed to create debugfs register file\n");
+}
+
+static void aat2870_uninit_debugfs(struct aat2870_data *aat2870)
+{
+       debugfs_remove_recursive(aat2870->dentry_root);
+}
+#else
+static inline void aat2870_init_debugfs(struct aat2870_data *aat2870)
+{
+}
+
+static inline void aat2870_uninit_debugfs(struct aat2870_data *aat2870)
+{
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static int aat2870_i2c_probe(struct i2c_client *client,
+                            const struct i2c_device_id *id)
+{
+       struct aat2870_platform_data *pdata = client->dev.platform_data;
+       struct aat2870_data *aat2870;
+       int i, j;
+       int ret = 0;
+
+       aat2870 = kzalloc(sizeof(struct aat2870_data), GFP_KERNEL);
+       if (!aat2870) {
+               dev_err(&client->dev,
+                       "Failed to allocate memory for aat2870\n");
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       aat2870->dev = &client->dev;
+       dev_set_drvdata(aat2870->dev, aat2870);
+
+       aat2870->client = client;
+       i2c_set_clientdata(client, aat2870);
+
+       aat2870->reg_cache = aat2870_regs;
+
+       if (pdata->en_pin < 0)
+               aat2870->en_pin = -1;
+       else
+               aat2870->en_pin = pdata->en_pin;
+
+       aat2870->init = pdata->init;
+       aat2870->uninit = pdata->uninit;
+       aat2870->read = aat2870_read;
+       aat2870->write = aat2870_write;
+       aat2870->update = aat2870_update;
+
+       mutex_init(&aat2870->io_lock);
+
+       if (aat2870->init)
+               aat2870->init(aat2870);
+
+       if (aat2870->en_pin >= 0) {
+               ret = gpio_request(aat2870->en_pin, "aat2870-en");
+               if (ret < 0) {
+                       dev_err(&client->dev,
+                               "Failed to request GPIO %d\n", aat2870->en_pin);
+                       goto out_kfree;
+               }
+               gpio_direction_output(aat2870->en_pin, 1);
+       }
+
+       aat2870_enable(aat2870);
+
+       for (i = 0; i < pdata->num_subdevs; i++) {
+               for (j = 0; j < ARRAY_SIZE(aat2870_devs); j++) {
+                       if ((pdata->subdevs[i].id == aat2870_devs[j].id) &&
+                                       !strcmp(pdata->subdevs[i].name,
+                                               aat2870_devs[j].name)) {
+                               aat2870_devs[j].platform_data =
+                                       pdata->subdevs[i].platform_data;
+                               break;
+                       }
+               }
+       }
+
+       ret = mfd_add_devices(aat2870->dev, 0, aat2870_devs,
+                             ARRAY_SIZE(aat2870_devs), NULL, 0);
+       if (ret != 0) {
+               dev_err(aat2870->dev, "Failed to add subdev: %d\n", ret);
+               goto out_disable;
+       }
+
+       aat2870_init_debugfs(aat2870);
+
+       return 0;
+
+out_disable:
+       aat2870_disable(aat2870);
+       if (aat2870->en_pin >= 0)
+               gpio_free(aat2870->en_pin);
+out_kfree:
+       kfree(aat2870);
+out:
+       return ret;
+}
+
+static int aat2870_i2c_remove(struct i2c_client *client)
+{
+       struct aat2870_data *aat2870 = i2c_get_clientdata(client);
+
+       aat2870_uninit_debugfs(aat2870);
+
+       mfd_remove_devices(aat2870->dev);
+       aat2870_disable(aat2870);
+       if (aat2870->en_pin >= 0)
+               gpio_free(aat2870->en_pin);
+       if (aat2870->uninit)
+               aat2870->uninit(aat2870);
+       kfree(aat2870);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int aat2870_i2c_suspend(struct i2c_client *client, pm_message_t state)
+{
+       struct aat2870_data *aat2870 = i2c_get_clientdata(client);
+
+       aat2870_disable(aat2870);
+
+       return 0;
+}
+
+static int aat2870_i2c_resume(struct i2c_client *client)
+{
+       struct aat2870_data *aat2870 = i2c_get_clientdata(client);
+       struct aat2870_register *reg = NULL;
+       int i;
+
+       aat2870_enable(aat2870);
+
+       /* restore registers */
+       for (i = 0; i < AAT2870_REG_NUM; i++) {
+               reg = &aat2870->reg_cache[i];
+               if (reg->writeable)
+                       aat2870->write(aat2870, i, reg->value);
+       }
+
+       return 0;
+}
+#else
+#define aat2870_i2c_suspend    NULL
+#define aat2870_i2c_resume     NULL
+#endif /* CONFIG_PM */
+
+static struct i2c_device_id aat2870_i2c_id_table[] = {
+       { "aat2870", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, aat2870_i2c_id_table);
+
+static struct i2c_driver aat2870_i2c_driver = {
+       .driver = {
+               .name   = "aat2870",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = aat2870_i2c_probe,
+       .remove         = aat2870_i2c_remove,
+       .suspend        = aat2870_i2c_suspend,
+       .resume         = aat2870_i2c_resume,
+       .id_table       = aat2870_i2c_id_table,
+};
+
+static int __init aat2870_init(void)
+{
+       return i2c_add_driver(&aat2870_i2c_driver);
+}
+subsys_initcall(aat2870_init);
+
+static void __exit aat2870_exit(void)
+{
+       i2c_del_driver(&aat2870_i2c_driver);
+}
+module_exit(aat2870_exit);
+
+MODULE_DESCRIPTION("Core support for the AnalogicTech AAT2870");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jin Park <jinyoungp@nvidia.com>");
index 3d7dce6..56ba194 100644 (file)
@@ -879,20 +879,13 @@ static ssize_t ab3550_bank_write(struct file *file,
        size_t count, loff_t *ppos)
 {
        struct ab3550 *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);
+       err = kstrtoul_from_user(user_buf, count, 0, &user_bank);
        if (err)
-               return -EINVAL;
+               return err;
 
        if (user_bank >= AB3550_NUM_BANKS) {
                dev_err(&ab->i2c_client[0]->dev,
@@ -902,7 +895,7 @@ static ssize_t ab3550_bank_write(struct file *file,
 
        ab->debug_bank = user_bank;
 
-       return buf_size;
+       return count;
 }
 
 static int ab3550_address_print(struct seq_file *s, void *p)
@@ -923,27 +916,21 @@ static ssize_t ab3550_address_write(struct file *file,
        size_t count, loff_t *ppos)
 {
        struct ab3550 *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);
+       err = kstrtoul_from_user(user_buf, count, 0, &user_address);
        if (err)
-               return -EINVAL;
+               return err;
+
        if (user_address > 0xff) {
                dev_err(&ab->i2c_client[0]->dev,
                        "debugfs error input > 0xff\n");
                return -EINVAL;
        }
        ab->debug_address = user_address;
-       return buf_size;
+       return count;
 }
 
 static int ab3550_val_print(struct seq_file *s, void *p)
@@ -971,21 +958,15 @@ static ssize_t ab3550_val_write(struct file *file,
        size_t count, loff_t *ppos)
 {
        struct ab3550 *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);
+       err = kstrtoul_from_user(user_buf, count, 0, &user_val);
        if (err)
-               return -EINVAL;
+               return err;
+
        if (user_val > 0xff) {
                dev_err(&ab->i2c_client[0]->dev,
                        "debugfs error input > 0xff\n");
@@ -1002,7 +983,7 @@ static ssize_t ab3550_val_write(struct file *file,
        if (err)
                return -EINVAL;
 
-       return buf_size;
+       return count;
 }
 
 static const struct file_operations ab3550_bank_fops = {
index fc0c1af..387705e 100644 (file)
@@ -363,7 +363,7 @@ static void ab8500_irq_remove(struct ab8500 *ab8500)
        }
 }
 
-static struct resource ab8500_gpio_resources[] = {
+static struct resource __devinitdata ab8500_gpio_resources[] = {
        {
                .name   = "GPIO_INT6",
                .start  = AB8500_INT_GPIO6R,
@@ -372,7 +372,7 @@ static struct resource ab8500_gpio_resources[] = {
        }
 };
 
-static struct resource ab8500_gpadc_resources[] = {
+static struct resource __devinitdata ab8500_gpadc_resources[] = {
        {
                .name   = "HW_CONV_END",
                .start  = AB8500_INT_GP_HW_ADC_CONV_END,
@@ -387,7 +387,7 @@ static struct resource ab8500_gpadc_resources[] = {
        },
 };
 
-static struct resource ab8500_rtc_resources[] = {
+static struct resource __devinitdata ab8500_rtc_resources[] = {
        {
                .name   = "60S",
                .start  = AB8500_INT_RTC_60S,
@@ -402,7 +402,7 @@ static struct resource ab8500_rtc_resources[] = {
        },
 };
 
-static struct resource ab8500_poweronkey_db_resources[] = {
+static struct resource __devinitdata ab8500_poweronkey_db_resources[] = {
        {
                .name   = "ONKEY_DBF",
                .start  = AB8500_INT_PON_KEY1DB_F,
@@ -417,19 +417,46 @@ static struct resource ab8500_poweronkey_db_resources[] = {
        },
 };
 
-static struct resource ab8500_bm_resources[] = {
+static struct resource __devinitdata ab8500_av_acc_detect_resources[] = {
        {
-               .name = "MAIN_EXT_CH_NOT_OK",
-               .start = AB8500_INT_MAIN_EXT_CH_NOT_OK,
-               .end = AB8500_INT_MAIN_EXT_CH_NOT_OK,
-               .flags = IORESOURCE_IRQ,
+              .name = "ACC_DETECT_1DB_F",
+              .start = AB8500_INT_ACC_DETECT_1DB_F,
+              .end = AB8500_INT_ACC_DETECT_1DB_F,
+              .flags = IORESOURCE_IRQ,
        },
        {
-               .name = "BATT_OVV",
-               .start = AB8500_INT_BATT_OVV,
-               .end = AB8500_INT_BATT_OVV,
-               .flags = IORESOURCE_IRQ,
+              .name = "ACC_DETECT_1DB_R",
+              .start = AB8500_INT_ACC_DETECT_1DB_R,
+              .end = AB8500_INT_ACC_DETECT_1DB_R,
+              .flags = IORESOURCE_IRQ,
+       },
+       {
+              .name = "ACC_DETECT_21DB_F",
+              .start = AB8500_INT_ACC_DETECT_21DB_F,
+              .end = AB8500_INT_ACC_DETECT_21DB_F,
+              .flags = IORESOURCE_IRQ,
+       },
+       {
+              .name = "ACC_DETECT_21DB_R",
+              .start = AB8500_INT_ACC_DETECT_21DB_R,
+              .end = AB8500_INT_ACC_DETECT_21DB_R,
+              .flags = IORESOURCE_IRQ,
+       },
+       {
+              .name = "ACC_DETECT_22DB_F",
+              .start = AB8500_INT_ACC_DETECT_22DB_F,
+              .end = AB8500_INT_ACC_DETECT_22DB_F,
+              .flags = IORESOURCE_IRQ,
        },
+       {
+              .name = "ACC_DETECT_22DB_R",
+              .start = AB8500_INT_ACC_DETECT_22DB_R,
+              .end = AB8500_INT_ACC_DETECT_22DB_R,
+              .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource __devinitdata ab8500_charger_resources[] = {
        {
                .name = "MAIN_CH_UNPLUG_DET",
                .start = AB8500_INT_MAIN_CH_UNPLUG_DET,
@@ -442,12 +469,6 @@ static struct resource ab8500_bm_resources[] = {
                .end = AB8500_INT_MAIN_CH_PLUG_DET,
                .flags = IORESOURCE_IRQ,
        },
-       {
-               .name = "VBUS_DET_F",
-               .start = AB8500_INT_VBUS_DET_F,
-               .end = AB8500_INT_VBUS_DET_F,
-               .flags = IORESOURCE_IRQ,
-       },
        {
                .name = "VBUS_DET_R",
                .start = AB8500_INT_VBUS_DET_R,
@@ -455,15 +476,21 @@ static struct resource ab8500_bm_resources[] = {
                .flags = IORESOURCE_IRQ,
        },
        {
-               .name = "BAT_CTRL_INDB",
-               .start = AB8500_INT_BAT_CTRL_INDB,
-               .end = AB8500_INT_BAT_CTRL_INDB,
+               .name = "VBUS_DET_F",
+               .start = AB8500_INT_VBUS_DET_F,
+               .end = AB8500_INT_VBUS_DET_F,
                .flags = IORESOURCE_IRQ,
        },
        {
-               .name = "CH_WD_EXP",
-               .start = AB8500_INT_CH_WD_EXP,
-               .end = AB8500_INT_CH_WD_EXP,
+               .name = "USB_LINK_STATUS",
+               .start = AB8500_INT_USB_LINK_STATUS,
+               .end = AB8500_INT_USB_LINK_STATUS,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "USB_CHARGE_DET_DONE",
+               .start = AB8500_INT_USB_CHG_DET_DONE,
+               .end = AB8500_INT_USB_CHG_DET_DONE,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -473,21 +500,60 @@ static struct resource ab8500_bm_resources[] = {
                .flags = IORESOURCE_IRQ,
        },
        {
-               .name = "NCONV_ACCU",
-               .start = AB8500_INT_CCN_CONV_ACC,
-               .end = AB8500_INT_CCN_CONV_ACC,
+               .name = "USB_CH_TH_PROT_R",
+               .start = AB8500_INT_USB_CH_TH_PROT_R,
+               .end = AB8500_INT_USB_CH_TH_PROT_R,
                .flags = IORESOURCE_IRQ,
        },
        {
-               .name = "LOW_BAT_F",
-               .start = AB8500_INT_LOW_BAT_F,
-               .end = AB8500_INT_LOW_BAT_F,
+               .name = "USB_CH_TH_PROT_F",
+               .start = AB8500_INT_USB_CH_TH_PROT_F,
+               .end = AB8500_INT_USB_CH_TH_PROT_F,
                .flags = IORESOURCE_IRQ,
        },
        {
-               .name = "LOW_BAT_R",
-               .start = AB8500_INT_LOW_BAT_R,
-               .end = AB8500_INT_LOW_BAT_R,
+               .name = "MAIN_EXT_CH_NOT_OK",
+               .start = AB8500_INT_MAIN_EXT_CH_NOT_OK,
+               .end = AB8500_INT_MAIN_EXT_CH_NOT_OK,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "MAIN_CH_TH_PROT_R",
+               .start = AB8500_INT_MAIN_CH_TH_PROT_R,
+               .end = AB8500_INT_MAIN_CH_TH_PROT_R,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "MAIN_CH_TH_PROT_F",
+               .start = AB8500_INT_MAIN_CH_TH_PROT_F,
+               .end = AB8500_INT_MAIN_CH_TH_PROT_F,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "USB_CHARGER_NOT_OKR",
+               .start = AB8500_INT_USB_CHARGER_NOT_OK,
+               .end = AB8500_INT_USB_CHARGER_NOT_OK,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "USB_CHARGER_NOT_OKF",
+               .start = AB8500_INT_USB_CHARGER_NOT_OKF,
+               .end = AB8500_INT_USB_CHARGER_NOT_OKF,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "CH_WD_EXP",
+               .start = AB8500_INT_CH_WD_EXP,
+               .end = AB8500_INT_CH_WD_EXP,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource __devinitdata ab8500_btemp_resources[] = {
+       {
+               .name = "BAT_CTRL_INDB",
+               .start = AB8500_INT_BAT_CTRL_INDB,
+               .end = AB8500_INT_BAT_CTRL_INDB,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -503,38 +569,55 @@ static struct resource ab8500_bm_resources[] = {
                .flags = IORESOURCE_IRQ,
        },
        {
-               .name = "USB_CHARGER_NOT_OKR",
-               .start = AB8500_INT_USB_CHARGER_NOT_OK,
-               .end = AB8500_INT_USB_CHARGER_NOT_OK,
+               .name = "BTEMP_LOW_MEDIUM",
+               .start = AB8500_INT_BTEMP_LOW_MEDIUM,
+               .end = AB8500_INT_BTEMP_LOW_MEDIUM,
                .flags = IORESOURCE_IRQ,
        },
        {
-               .name = "USB_CHARGE_DET_DONE",
-               .start = AB8500_INT_USB_CHG_DET_DONE,
-               .end = AB8500_INT_USB_CHG_DET_DONE,
+               .name = "BTEMP_MEDIUM_HIGH",
+               .start = AB8500_INT_BTEMP_MEDIUM_HIGH,
+               .end = AB8500_INT_BTEMP_MEDIUM_HIGH,
                .flags = IORESOURCE_IRQ,
        },
+};
+
+static struct resource __devinitdata ab8500_fg_resources[] = {
        {
-               .name = "USB_CH_TH_PROT_R",
-               .start = AB8500_INT_USB_CH_TH_PROT_R,
-               .end = AB8500_INT_USB_CH_TH_PROT_R,
+               .name = "NCONV_ACCU",
+               .start = AB8500_INT_CCN_CONV_ACC,
+               .end = AB8500_INT_CCN_CONV_ACC,
                .flags = IORESOURCE_IRQ,
        },
        {
-               .name = "MAIN_CH_TH_PROT_R",
-               .start = AB8500_INT_MAIN_CH_TH_PROT_R,
-               .end = AB8500_INT_MAIN_CH_TH_PROT_R,
+               .name = "BATT_OVV",
+               .start = AB8500_INT_BATT_OVV,
+               .end = AB8500_INT_BATT_OVV,
                .flags = IORESOURCE_IRQ,
        },
        {
-               .name = "USB_CHARGER_NOT_OKF",
-               .start = AB8500_INT_USB_CHARGER_NOT_OKF,
-               .end = AB8500_INT_USB_CHARGER_NOT_OKF,
+               .name = "LOW_BAT_F",
+               .start = AB8500_INT_LOW_BAT_F,
+               .end = AB8500_INT_LOW_BAT_F,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "LOW_BAT_R",
+               .start = AB8500_INT_LOW_BAT_R,
+               .end = AB8500_INT_LOW_BAT_R,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "CC_INT_CALIB",
+               .start = AB8500_INT_CC_INT_CALIB,
+               .end = AB8500_INT_CC_INT_CALIB,
                .flags = IORESOURCE_IRQ,
        },
 };
 
-static struct resource ab8500_debug_resources[] = {
+static struct resource __devinitdata ab8500_chargalg_resources[] = {};
+
+static struct resource __devinitdata ab8500_debug_resources[] = {
        {
                .name   = "IRQ_FIRST",
                .start  = AB8500_INT_MAIN_EXT_CH_NOT_OK,
@@ -549,7 +632,7 @@ static struct resource ab8500_debug_resources[] = {
        },
 };
 
-static struct resource ab8500_usb_resources[] = {
+static struct resource __devinitdata ab8500_usb_resources[] = {
        {
                .name = "ID_WAKEUP_R",
                .start = AB8500_INT_ID_WAKEUP_R,
@@ -580,9 +663,21 @@ static struct resource ab8500_usb_resources[] = {
                .end = AB8500_INT_USB_LINK_STATUS,
                .flags = IORESOURCE_IRQ,
        },
+       {
+               .name = "USB_ADP_PROBE_PLUG",
+               .start = AB8500_INT_ADP_PROBE_PLUG,
+               .end = AB8500_INT_ADP_PROBE_PLUG,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "USB_ADP_PROBE_UNPLUG",
+               .start = AB8500_INT_ADP_PROBE_UNPLUG,
+               .end = AB8500_INT_ADP_PROBE_UNPLUG,
+               .flags = IORESOURCE_IRQ,
+       },
 };
 
-static struct resource ab8500_temp_resources[] = {
+static struct resource __devinitdata ab8500_temp_resources[] = {
        {
                .name  = "AB8500_TEMP_WARM",
                .start = AB8500_INT_TEMP_WARM,
@@ -591,7 +686,7 @@ static struct resource ab8500_temp_resources[] = {
        },
 };
 
-static struct mfd_cell ab8500_devs[] = {
+static struct mfd_cell __devinitdata ab8500_devs[] = {
 #ifdef CONFIG_DEBUG_FS
        {
                .name = "ab8500-debug",
@@ -621,11 +716,33 @@ static struct mfd_cell ab8500_devs[] = {
                .resources = ab8500_rtc_resources,
        },
        {
-               .name = "ab8500-bm",
-               .num_resources = ARRAY_SIZE(ab8500_bm_resources),
-               .resources = ab8500_bm_resources,
+               .name = "ab8500-charger",
+               .num_resources = ARRAY_SIZE(ab8500_charger_resources),
+               .resources = ab8500_charger_resources,
+       },
+       {
+               .name = "ab8500-btemp",
+               .num_resources = ARRAY_SIZE(ab8500_btemp_resources),
+               .resources = ab8500_btemp_resources,
+       },
+       {
+               .name = "ab8500-fg",
+               .num_resources = ARRAY_SIZE(ab8500_fg_resources),
+               .resources = ab8500_fg_resources,
+       },
+       {
+               .name = "ab8500-chargalg",
+               .num_resources = ARRAY_SIZE(ab8500_chargalg_resources),
+               .resources = ab8500_chargalg_resources,
+       },
+       {
+               .name = "ab8500-acc-det",
+               .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources),
+               .resources = ab8500_av_acc_detect_resources,
+       },
+       {
+               .name = "ab8500-codec",
        },
-       { .name = "ab8500-codec", },
        {
                .name = "ab8500-usb",
                .num_resources = ARRAY_SIZE(ab8500_usb_resources),
index 64748e4..64bdeeb 100644 (file)
@@ -419,20 +419,13 @@ static ssize_t ab8500_bank_write(struct file *file,
        size_t count, loff_t *ppos)
 {
        struct device *dev = ((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);
+       err = kstrtoul_from_user(user_buf, count, 0, &user_bank);
        if (err)
-               return -EINVAL;
+               return err;
 
        if (user_bank >= AB8500_NUM_BANKS) {
                dev_err(dev, "debugfs error input > number of banks\n");
@@ -441,7 +434,7 @@ static ssize_t ab8500_bank_write(struct file *file,
 
        debug_bank = user_bank;
 
-       return buf_size;
+       return count;
 }
 
 static int ab8500_address_print(struct seq_file *s, void *p)
@@ -459,26 +452,20 @@ static ssize_t ab8500_address_write(struct file *file,
        size_t count, loff_t *ppos)
 {
        struct device *dev = ((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);
+       err = kstrtoul_from_user(user_buf, count, 0, &user_address);
        if (err)
-               return -EINVAL;
+               return err;
+
        if (user_address > 0xff) {
                dev_err(dev, "debugfs error input > 0xff\n");
                return -EINVAL;
        }
        debug_address = user_address;
-       return buf_size;
+       return count;
 }
 
 static int ab8500_val_print(struct seq_file *s, void *p)
@@ -509,20 +496,14 @@ static ssize_t ab8500_val_write(struct file *file,
        size_t count, loff_t *ppos)
 {
        struct device *dev = ((struct seq_file *)(file->private_data))->private;
-       char buf[32];
-       int buf_size;
        unsigned long user_val;
        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_val);
+       err = kstrtoul_from_user(user_buf, count, 0, &user_val);
        if (err)
-               return -EINVAL;
+               return err;
+
        if (user_val > 0xff) {
                dev_err(dev, "debugfs error input > 0xff\n");
                return -EINVAL;
@@ -534,7 +515,7 @@ static ssize_t ab8500_val_write(struct file *file,
                return -EINVAL;
        }
 
-       return buf_size;
+       return count;
 }
 
 static const struct file_operations ab8500_bank_fops = {
index a0bd0cf..21131c7 100644 (file)
@@ -56,7 +56,7 @@ struct jz4740_adc {
        void __iomem *base;
 
        int irq;
-       int irq_base;
+       struct irq_chip_generic *gc;
 
        struct clk *clk;
        atomic_t clk_ref;
@@ -64,63 +64,17 @@ struct jz4740_adc {
        spinlock_t lock;
 };
 
-static inline void jz4740_adc_irq_set_masked(struct jz4740_adc *adc, int irq,
-       bool masked)
-{
-       unsigned long flags;
-       uint8_t val;
-
-       irq -= adc->irq_base;
-
-       spin_lock_irqsave(&adc->lock, flags);
-
-       val = readb(adc->base + JZ_REG_ADC_CTRL);
-       if (masked)
-               val |= BIT(irq);
-       else
-               val &= ~BIT(irq);
-       writeb(val, adc->base + JZ_REG_ADC_CTRL);
-
-       spin_unlock_irqrestore(&adc->lock, flags);
-}
-
-static void jz4740_adc_irq_mask(struct irq_data *data)
-{
-       struct jz4740_adc *adc = irq_data_get_irq_chip_data(data);
-       jz4740_adc_irq_set_masked(adc, data->irq, true);
-}
-
-static void jz4740_adc_irq_unmask(struct irq_data *data)
-{
-       struct jz4740_adc *adc = irq_data_get_irq_chip_data(data);
-       jz4740_adc_irq_set_masked(adc, data->irq, false);
-}
-
-static void jz4740_adc_irq_ack(struct irq_data *data)
-{
-       struct jz4740_adc *adc = irq_data_get_irq_chip_data(data);
-       unsigned int irq = data->irq - adc->irq_base;
-       writeb(BIT(irq), adc->base + JZ_REG_ADC_STATUS);
-}
-
-static struct irq_chip jz4740_adc_irq_chip = {
-       .name = "jz4740-adc",
-       .irq_mask = jz4740_adc_irq_mask,
-       .irq_unmask = jz4740_adc_irq_unmask,
-       .irq_ack = jz4740_adc_irq_ack,
-};
-
 static void jz4740_adc_irq_demux(unsigned int irq, struct irq_desc *desc)
 {
-       struct jz4740_adc *adc = irq_desc_get_handler_data(desc);
+       struct irq_chip_generic *gc = irq_desc_get_handler_data(desc);
        uint8_t status;
        unsigned int i;
 
-       status = readb(adc->base + JZ_REG_ADC_STATUS);
+       status = readb(gc->reg_base + JZ_REG_ADC_STATUS);
 
        for (i = 0; i < 5; ++i) {
                if (status & BIT(i))
-                       generic_handle_irq(adc->irq_base + i);
+                       generic_handle_irq(gc->irq_base + i);
        }
 }
 
@@ -249,10 +203,12 @@ const struct mfd_cell jz4740_adc_cells[] = {
 
 static int __devinit jz4740_adc_probe(struct platform_device *pdev)
 {
-       int ret;
+       struct irq_chip_generic *gc;
+       struct irq_chip_type *ct;
        struct jz4740_adc *adc;
        struct resource *mem_base;
-       int irq;
+       int ret;
+       int irq_base;
 
        adc = kmalloc(sizeof(*adc), GFP_KERNEL);
        if (!adc) {
@@ -267,9 +223,9 @@ static int __devinit jz4740_adc_probe(struct platform_device *pdev)
                goto err_free;
        }
 
-       adc->irq_base = platform_get_irq(pdev, 1);
-       if (adc->irq_base < 0) {
-               ret = adc->irq_base;
+       irq_base = platform_get_irq(pdev, 1);
+       if (irq_base < 0) {
+               ret = irq_base;
                dev_err(&pdev->dev, "Failed to get irq base: %d\n", ret);
                goto err_free;
        }
@@ -309,20 +265,28 @@ static int __devinit jz4740_adc_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, adc);
 
-       for (irq = adc->irq_base; irq < adc->irq_base + 5; ++irq) {
-               irq_set_chip_data(irq, adc);
-               irq_set_chip_and_handler(irq, &jz4740_adc_irq_chip,
-                                        handle_level_irq);
-       }
+       gc = irq_alloc_generic_chip("INTC", 1, irq_base, adc->base,
+               handle_level_irq);
+
+       ct = gc->chip_types;
+       ct->regs.mask = JZ_REG_ADC_CTRL;
+       ct->regs.ack = JZ_REG_ADC_STATUS;
+       ct->chip.irq_mask = irq_gc_mask_set_bit;
+       ct->chip.irq_unmask = irq_gc_mask_clr_bit;
+       ct->chip.irq_ack = irq_gc_ack;
+
+       irq_setup_generic_chip(gc, IRQ_MSK(5), 0, 0, IRQ_NOPROBE | IRQ_LEVEL);
+
+       adc->gc = gc;
 
-       irq_set_handler_data(adc->irq, adc);
+       irq_set_handler_data(adc->irq, gc);
        irq_set_chained_handler(adc->irq, jz4740_adc_irq_demux);
 
        writeb(0x00, adc->base + JZ_REG_ADC_ENABLE);
        writeb(0xff, adc->base + JZ_REG_ADC_CTRL);
 
        ret = mfd_add_devices(&pdev->dev, 0, jz4740_adc_cells,
-               ARRAY_SIZE(jz4740_adc_cells), mem_base, adc->irq_base);
+               ARRAY_SIZE(jz4740_adc_cells), mem_base, irq_base);
        if (ret < 0)
                goto err_clk_put;
 
@@ -347,6 +311,8 @@ static int __devexit jz4740_adc_remove(struct platform_device *pdev)
 
        mfd_remove_devices(&pdev->dev);
 
+       irq_remove_generic_chip(adc->gc, IRQ_MSK(5), IRQ_NOPROBE | IRQ_LEVEL, 0);
+       kfree(adc->gc);
        irq_set_handler_data(adc->irq, NULL);
        irq_set_chained_handler(adc->irq, NULL);
 
index ea3f52c..ea1169b 100644 (file)
@@ -37,6 +37,9 @@
 #define GPIOBASE       0x44
 #define GPIO_IO_SIZE   64
 
+#define WDTBASE                0x84
+#define WDT_IO_SIZE    64
+
 static struct resource smbus_sch_resource = {
                .flags = IORESOURCE_IO,
 };
@@ -59,6 +62,18 @@ static struct mfd_cell lpc_sch_cells[] = {
        },
 };
 
+static struct resource wdt_sch_resource = {
+               .flags = IORESOURCE_IO,
+};
+
+static struct mfd_cell tunnelcreek_cells[] = {
+       {
+               .name = "tunnelcreek_wdt",
+               .num_resources = 1,
+               .resources = &wdt_sch_resource,
+       },
+};
+
 static struct pci_device_id lpc_sch_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ITC_LPC) },
@@ -72,6 +87,7 @@ static int __devinit lpc_sch_probe(struct pci_dev *dev,
        unsigned int base_addr_cfg;
        unsigned short base_addr;
        int i;
+       int ret;
 
        pci_read_config_dword(dev, SMBASE, &base_addr_cfg);
        if (!(base_addr_cfg & (1 << 31))) {
@@ -104,8 +120,39 @@ static int __devinit lpc_sch_probe(struct pci_dev *dev,
        for (i=0; i < ARRAY_SIZE(lpc_sch_cells); i++)
                lpc_sch_cells[i].id = id->device;
 
-       return mfd_add_devices(&dev->dev, 0,
+       ret = mfd_add_devices(&dev->dev, 0,
                        lpc_sch_cells, ARRAY_SIZE(lpc_sch_cells), NULL, 0);
+       if (ret)
+               goto out_dev;
+
+       if (id->device == PCI_DEVICE_ID_INTEL_ITC_LPC) {
+               pci_read_config_dword(dev, WDTBASE, &base_addr_cfg);
+               if (!(base_addr_cfg & (1 << 31))) {
+                       dev_err(&dev->dev, "Decode of the WDT I/O range disabled\n");
+                       ret = -ENODEV;
+                       goto out_dev;
+               }
+               base_addr = (unsigned short)base_addr_cfg;
+               if (base_addr == 0) {
+                       dev_err(&dev->dev, "I/O space for WDT uninitialized\n");
+                       ret = -ENODEV;
+                       goto out_dev;
+               }
+
+               wdt_sch_resource.start = base_addr;
+               wdt_sch_resource.end = base_addr + WDT_IO_SIZE - 1;
+
+               for (i = 0; i < ARRAY_SIZE(tunnelcreek_cells); i++)
+                       tunnelcreek_cells[i].id = id->device;
+
+               ret = mfd_add_devices(&dev->dev, 0, tunnelcreek_cells,
+                       ARRAY_SIZE(tunnelcreek_cells), NULL, 0);
+       }
+
+       return ret;
+out_dev:
+       mfd_remove_devices(&dev->dev);
+       return ret;
 }
 
 static void __devexit lpc_sch_remove(struct pci_dev *dev)
index 638bf7e..09274cf 100644 (file)
@@ -58,8 +58,6 @@ static struct i2c_client *get_i2c(struct max8997_dev *max8997,
        default:
                return ERR_PTR(-EINVAL);
        }
-
-       return ERR_PTR(-EINVAL);
 }
 
 struct max8997_irq_data {
index 9ec7570..de4096a 100644 (file)
@@ -39,6 +39,8 @@ static struct mfd_cell max8998_devs[] = {
                .name = "max8998-pmic",
        }, {
                .name = "max8998-rtc",
+       }, {
+               .name = "max8998-battery",
        },
 };
 
index 1717144..29601e7 100644 (file)
@@ -998,9 +998,9 @@ static void usbhs_disable(struct device *dev)
 
        if (is_omap_usbhs_rev2(omap)) {
                if (is_ehci_tll_mode(pdata->port_mode[0]))
-                       clk_enable(omap->usbtll_p1_fck);
+                       clk_disable(omap->usbtll_p1_fck);
                if (is_ehci_tll_mode(pdata->port_mode[1]))
-                       clk_enable(omap->usbtll_p2_fck);
+                       clk_disable(omap->usbtll_p2_fck);
                clk_disable(omap->utmi_p2_fck);
                clk_disable(omap->utmi_p1_fck);
        }
index 7ab7746..2963689 100644 (file)
@@ -228,7 +228,7 @@ int stmpe_block_write(struct stmpe *stmpe, u8 reg, u8 length,
 EXPORT_SYMBOL_GPL(stmpe_block_write);
 
 /**
- * stmpe_set_altfunc: set the alternate function for STMPE pins
+ * stmpe_set_altfunc()- set the alternate function for STMPE pins
  * @stmpe:     Device to configure
  * @pins:      Bitmask of pins to affect
  * @block:     block to enable alternate functions for
index 0dbdc4e..e4ee389 100644 (file)
@@ -42,6 +42,7 @@ struct stmpe_variant_block {
  * @id_mask:   bits valid in CHIPID register for comparison with id_val
  * @num_gpios: number of GPIOS
  * @af_bits:   number of bits used to specify the alternate function
+ * @regs: variant specific registers.
  * @blocks:    list of blocks present on this device
  * @num_blocks:        number of blocks present on this device
  * @num_irqs:  number of internal IRQs available on this device
index 69272e4..696879e 100644 (file)
@@ -287,12 +287,8 @@ static __devinitdata struct i2c_board_info timberdale_saa7706_i2c_board_info = {
 static __devinitdata struct timb_radio_platform_data
        timberdale_radio_platform_data = {
        .i2c_adapter = 0,
-       .tuner = {
-               .info = &timberdale_tef6868_i2c_board_info
-       },
-       .dsp = {
-               .info = &timberdale_saa7706_i2c_board_info
-       }
+       .tuner = &timberdale_tef6868_i2c_board_info,
+       .dsp = &timberdale_saa7706_i2c_board_info
 };
 
 static const __devinitconst struct resource timberdale_video_resources[] = {
index 2229e66..6f5b8cf 100644 (file)
@@ -147,12 +147,11 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
        if (init_data == NULL)
                return -ENOMEM;
 
-       init_data->irq = pmic_plat_data->irq;
-       init_data->irq_base = pmic_plat_data->irq;
-
        tps65910 = kzalloc(sizeof(struct tps65910), GFP_KERNEL);
-       if (tps65910 == NULL)
+       if (tps65910 == NULL) {
+               kfree(init_data);
                return -ENOMEM;
+       }
 
        i2c_set_clientdata(i2c, tps65910);
        tps65910->dev = &i2c->dev;
@@ -168,17 +167,22 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
        if (ret < 0)
                goto err;
 
+       init_data->irq = pmic_plat_data->irq;
+       init_data->irq_base = pmic_plat_data->irq;
+
        tps65910_gpio_init(tps65910, pmic_plat_data->gpio_base);
 
        ret = tps65910_irq_init(tps65910, init_data->irq, init_data);
        if (ret < 0)
                goto err;
 
+       kfree(init_data);
        return ret;
 
 err:
        mfd_remove_devices(tps65910->dev);
        kfree(tps65910);
+       kfree(init_data);
        return ret;
 }
 
@@ -187,6 +191,7 @@ static int tps65910_i2c_remove(struct i2c_client *i2c)
        struct tps65910 *tps65910 = i2c_get_clientdata(i2c);
 
        mfd_remove_devices(tps65910->dev);
+       tps65910_irq_exit(tps65910);
        kfree(tps65910);
 
        return 0;
index 283ac67..e7ff783 100644 (file)
@@ -157,6 +157,8 @@ static __devexit int tps65911_comparator_remove(struct platform_device *pdev)
        struct tps65910 *tps65910;
 
        tps65910 = dev_get_drvdata(pdev->dev.parent);
+       device_remove_file(&pdev->dev, &dev_attr_comp2_threshold);
+       device_remove_file(&pdev->dev, &dev_attr_comp1_threshold);
 
        return 0;
 }
diff --git a/drivers/mfd/tps65912-core.c b/drivers/mfd/tps65912-core.c
new file mode 100644 (file)
index 0000000..955bc00
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * tps65912-core.c  --  TI TPS65912x
+ *
+ * Copyright 2011 Texas Instruments Inc.
+ *
+ * Author: Margarita Olaya Cabrera <magi@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.
+ *
+ *  This driver is based on wm8350 implementation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/tps65912.h>
+
+static struct mfd_cell tps65912s[] = {
+       {
+               .name = "tps65912-pmic",
+       },
+};
+
+int tps65912_set_bits(struct tps65912 *tps65912, u8 reg, u8 mask)
+{
+       u8 data;
+       int err;
+
+       mutex_lock(&tps65912->io_mutex);
+
+       err = tps65912->read(tps65912, reg, 1, &data);
+       if (err) {
+               dev_err(tps65912->dev, "Read from reg 0x%x failed\n", reg);
+               goto out;
+       }
+
+       data |= mask;
+       err = tps65912->write(tps65912, reg, 1, &data);
+       if (err)
+               dev_err(tps65912->dev, "Write to reg 0x%x failed\n", reg);
+
+out:
+       mutex_unlock(&tps65912->io_mutex);
+       return err;
+}
+EXPORT_SYMBOL_GPL(tps65912_set_bits);
+
+int tps65912_clear_bits(struct tps65912 *tps65912, u8 reg, u8 mask)
+{
+       u8 data;
+       int err;
+
+       mutex_lock(&tps65912->io_mutex);
+       err = tps65912->read(tps65912, reg, 1, &data);
+       if (err) {
+               dev_err(tps65912->dev, "Read from reg 0x%x failed\n", reg);
+               goto out;
+       }
+
+       data &= ~mask;
+       err = tps65912->write(tps65912, reg, 1, &data);
+       if (err)
+               dev_err(tps65912->dev, "Write to reg 0x%x failed\n", reg);
+
+out:
+       mutex_unlock(&tps65912->io_mutex);
+       return err;
+}
+EXPORT_SYMBOL_GPL(tps65912_clear_bits);
+
+static inline int tps65912_read(struct tps65912 *tps65912, u8 reg)
+{
+       u8 val;
+       int err;
+
+       err = tps65912->read(tps65912, reg, 1, &val);
+       if (err < 0)
+               return err;
+
+       return val;
+}
+
+static inline int tps65912_write(struct tps65912 *tps65912, u8 reg, u8 val)
+{
+       return tps65912->write(tps65912, reg, 1, &val);
+}
+
+int tps65912_reg_read(struct tps65912 *tps65912, u8 reg)
+{
+       int data;
+
+       mutex_lock(&tps65912->io_mutex);
+
+       data = tps65912_read(tps65912, reg);
+       if (data < 0)
+               dev_err(tps65912->dev, "Read from reg 0x%x failed\n", reg);
+
+       mutex_unlock(&tps65912->io_mutex);
+       return data;
+}
+EXPORT_SYMBOL_GPL(tps65912_reg_read);
+
+int tps65912_reg_write(struct tps65912 *tps65912, u8 reg, u8 val)
+{
+       int err;
+
+       mutex_lock(&tps65912->io_mutex);
+
+       err = tps65912_write(tps65912, reg, val);
+       if (err < 0)
+               dev_err(tps65912->dev, "Write for reg 0x%x failed\n", reg);
+
+       mutex_unlock(&tps65912->io_mutex);
+       return err;
+}
+EXPORT_SYMBOL_GPL(tps65912_reg_write);
+
+int tps65912_device_init(struct tps65912 *tps65912)
+{
+       struct tps65912_board *pmic_plat_data = tps65912->dev->platform_data;
+       struct tps65912_platform_data *init_data;
+       int ret, dcdc_avs, value;
+
+       init_data = kzalloc(sizeof(struct tps65912_platform_data), GFP_KERNEL);
+       if (init_data == NULL)
+               return -ENOMEM;
+
+       init_data->irq = pmic_plat_data->irq;
+       init_data->irq_base = pmic_plat_data->irq;
+
+       mutex_init(&tps65912->io_mutex);
+       dev_set_drvdata(tps65912->dev, tps65912);
+
+       dcdc_avs = (pmic_plat_data->is_dcdc1_avs << 0 |
+                       pmic_plat_data->is_dcdc2_avs  << 1 |
+                               pmic_plat_data->is_dcdc3_avs << 2 |
+                                       pmic_plat_data->is_dcdc4_avs << 3);
+       if (dcdc_avs) {
+               tps65912->read(tps65912, TPS65912_I2C_SPI_CFG, 1, &value);
+               dcdc_avs |= value;
+               tps65912->write(tps65912, TPS65912_I2C_SPI_CFG, 1, &dcdc_avs);
+       }
+
+       ret = mfd_add_devices(tps65912->dev, -1,
+                             tps65912s, ARRAY_SIZE(tps65912s),
+                             NULL, 0);
+       if (ret < 0)
+               goto err;
+
+       ret = tps65912_irq_init(tps65912, init_data->irq, init_data);
+       if (ret < 0)
+               goto err;
+
+       return ret;
+
+err:
+       kfree(init_data);
+       mfd_remove_devices(tps65912->dev);
+       kfree(tps65912);
+       return ret;
+}
+
+void tps65912_device_exit(struct tps65912 *tps65912)
+{
+       mfd_remove_devices(tps65912->dev);
+       kfree(tps65912);
+}
+
+MODULE_AUTHOR("Margarita Olaya <magi@slimlogic.co.uk>");
+MODULE_DESCRIPTION("TPS65912x chip family multi-function driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/tps65912-i2c.c b/drivers/mfd/tps65912-i2c.c
new file mode 100644 (file)
index 0000000..c041f2c
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * tps65912-i2c.c  --  I2C access for TI TPS65912x PMIC
+ *
+ * Copyright 2011 Texas Instruments Inc.
+ *
+ * Author: Margarita Olaya Cabrera <magi@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.
+ *
+ *  This driver is based on wm8350 implementation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/tps65912.h>
+
+static int tps65912_i2c_read(struct tps65912 *tps65912, u8 reg,
+                                 int bytes, void *dest)
+{
+       struct i2c_client *i2c = tps65912->control_data;
+       struct i2c_msg xfer[2];
+       int ret;
+
+       /* Write register */
+       xfer[0].addr = i2c->addr;
+       xfer[0].flags = 0;
+       xfer[0].len = 1;
+       xfer[0].buf = &reg;
+
+       /* Read data */
+       xfer[1].addr = i2c->addr;
+       xfer[1].flags = I2C_M_RD;
+       xfer[1].len = bytes;
+       xfer[1].buf = dest;
+
+       ret = i2c_transfer(i2c->adapter, xfer, 2);
+       if (ret == 2)
+               ret = 0;
+       else if (ret >= 0)
+               ret = -EIO;
+       return ret;
+}
+
+static int tps65912_i2c_write(struct tps65912 *tps65912, u8 reg,
+                                  int bytes, void *src)
+{
+       struct i2c_client *i2c = tps65912->control_data;
+       /* we add 1 byte for device register */
+       u8 msg[TPS6591X_MAX_REGISTER + 1];
+       int ret;
+
+       if (bytes > TPS6591X_MAX_REGISTER)
+               return -EINVAL;
+
+       msg[0] = reg;
+       memcpy(&msg[1], src, bytes);
+
+       ret = i2c_master_send(i2c, msg, bytes + 1);
+       if (ret < 0)
+               return ret;
+       if (ret != bytes + 1)
+               return -EIO;
+
+       return 0;
+}
+
+static int tps65912_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
+{
+       struct tps65912 *tps65912;
+
+       tps65912 = kzalloc(sizeof(struct tps65912), GFP_KERNEL);
+       if (tps65912 == NULL)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, tps65912);
+       tps65912->dev = &i2c->dev;
+       tps65912->control_data = i2c;
+       tps65912->read = tps65912_i2c_read;
+       tps65912->write = tps65912_i2c_write;
+
+       return tps65912_device_init(tps65912);
+}
+
+static int tps65912_i2c_remove(struct i2c_client *i2c)
+{
+       struct tps65912 *tps65912 = i2c_get_clientdata(i2c);
+
+       tps65912_device_exit(tps65912);
+
+       return 0;
+}
+
+static const struct i2c_device_id tps65912_i2c_id[] = {
+       {"tps65912", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, tps65912_i2c_id);
+
+static struct i2c_driver tps65912_i2c_driver = {
+       .driver = {
+                  .name = "tps65912",
+                  .owner = THIS_MODULE,
+       },
+       .probe = tps65912_i2c_probe,
+       .remove = tps65912_i2c_remove,
+       .id_table = tps65912_i2c_id,
+};
+
+static int __init tps65912_i2c_init(void)
+{
+       int ret;
+
+       ret = i2c_add_driver(&tps65912_i2c_driver);
+       if (ret != 0)
+               pr_err("Failed to register TPS65912 I2C driver: %d\n", ret);
+
+       return ret;
+}
+/* init early so consumer devices can complete system boot */
+subsys_initcall(tps65912_i2c_init);
+
+static void __exit tps65912_i2c_exit(void)
+{
+       i2c_del_driver(&tps65912_i2c_driver);
+}
+module_exit(tps65912_i2c_exit);
+
+MODULE_AUTHOR("Margarita Olaya <magi@slimlogic.co.uk>");
+MODULE_DESCRIPTION("TPS6591x chip family multi-function driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/tps65912-irq.c b/drivers/mfd/tps65912-irq.c
new file mode 100644 (file)
index 0000000..d360a83
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * tps65912-irq.c  --  TI TPS6591x
+ *
+ * Copyright 2011 Texas Instruments Inc.
+ *
+ * Author: Margarita Olaya <magi@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.
+ *
+ * This driver is based on wm8350 implementation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/mfd/tps65912.h>
+
+static inline int irq_to_tps65912_irq(struct tps65912 *tps65912,
+                                                       int irq)
+{
+       return irq - tps65912->irq_base;
+}
+
+/*
+ * This is a threaded IRQ handler so can access I2C/SPI.  Since the
+ * IRQ handler explicitly clears the IRQ it handles the IRQ line
+ * will be reasserted and the physical IRQ will be handled again if
+ * another interrupt is asserted while we run - in the normal course
+ * of events this is a rare occurrence so we save I2C/SPI reads. We're
+ * also assuming that it's rare to get lots of interrupts firing
+ * simultaneously so try to minimise I/O.
+ */
+static irqreturn_t tps65912_irq(int irq, void *irq_data)
+{
+       struct tps65912 *tps65912 = irq_data;
+       u32 irq_sts;
+       u32 irq_mask;
+       u8 reg;
+       int i;
+
+
+       tps65912->read(tps65912, TPS65912_INT_STS, 1, &reg);
+       irq_sts = reg;
+       tps65912->read(tps65912, TPS65912_INT_STS2, 1, &reg);
+       irq_sts |= reg << 8;
+       tps65912->read(tps65912, TPS65912_INT_STS3, 1, &reg);
+       irq_sts |= reg << 16;
+       tps65912->read(tps65912, TPS65912_INT_STS4, 1, &reg);
+       irq_sts |= reg << 24;
+
+       tps65912->read(tps65912, TPS65912_INT_MSK, 1, &reg);
+       irq_mask = reg;
+       tps65912->read(tps65912, TPS65912_INT_MSK2, 1, &reg);
+       irq_mask |= reg << 8;
+       tps65912->read(tps65912, TPS65912_INT_MSK3, 1, &reg);
+       irq_mask |= reg << 16;
+       tps65912->read(tps65912, TPS65912_INT_MSK4, 1, &reg);
+       irq_mask |= reg << 24;
+
+       irq_sts &= ~irq_mask;
+       if (!irq_sts)
+               return IRQ_NONE;
+
+       for (i = 0; i < tps65912->irq_num; i++) {
+               if (!(irq_sts & (1 << i)))
+                       continue;
+
+               handle_nested_irq(tps65912->irq_base + i);
+       }
+
+       /* Write the STS register back to clear IRQs we handled */
+       reg = irq_sts & 0xFF;
+       irq_sts >>= 8;
+       if (reg)
+               tps65912->write(tps65912, TPS65912_INT_STS, 1, &reg);
+       reg = irq_sts & 0xFF;
+       irq_sts >>= 8;
+       if (reg)
+               tps65912->write(tps65912, TPS65912_INT_STS2, 1, &reg);
+       reg = irq_sts & 0xFF;
+       irq_sts >>= 8;
+       if (reg)
+               tps65912->write(tps65912, TPS65912_INT_STS3, 1, &reg);
+       reg = irq_sts & 0xFF;
+       if (reg)
+               tps65912->write(tps65912, TPS65912_INT_STS4, 1, &reg);
+
+       return IRQ_HANDLED;
+}
+
+static void tps65912_irq_lock(struct irq_data *data)
+{
+       struct tps65912 *tps65912 = irq_data_get_irq_chip_data(data);
+
+       mutex_lock(&tps65912->irq_lock);
+}
+
+static void tps65912_irq_sync_unlock(struct irq_data *data)
+{
+       struct tps65912 *tps65912 = irq_data_get_irq_chip_data(data);
+       u32 reg_mask;
+       u8 reg;
+
+       tps65912->read(tps65912, TPS65912_INT_MSK, 1, &reg);
+       reg_mask = reg;
+       tps65912->read(tps65912, TPS65912_INT_MSK2, 1, &reg);
+       reg_mask |= reg << 8;
+       tps65912->read(tps65912, TPS65912_INT_MSK3, 1, &reg);
+       reg_mask |= reg << 16;
+       tps65912->read(tps65912, TPS65912_INT_MSK4, 1, &reg);
+       reg_mask |= reg << 24;
+
+       if (tps65912->irq_mask != reg_mask) {
+               reg = tps65912->irq_mask & 0xFF;
+               tps65912->write(tps65912, TPS65912_INT_MSK, 1, &reg);
+               reg = tps65912->irq_mask >> 8 & 0xFF;
+               tps65912->write(tps65912, TPS65912_INT_MSK2, 1, &reg);
+               reg = tps65912->irq_mask >> 16 & 0xFF;
+               tps65912->write(tps65912, TPS65912_INT_MSK3, 1, &reg);
+               reg = tps65912->irq_mask >> 24 & 0xFF;
+               tps65912->write(tps65912, TPS65912_INT_MSK4, 1, &reg);
+       }
+
+       mutex_unlock(&tps65912->irq_lock);
+}
+
+static void tps65912_irq_enable(struct irq_data *data)
+{
+       struct tps65912 *tps65912 = irq_data_get_irq_chip_data(data);
+
+       tps65912->irq_mask &= ~(1 << irq_to_tps65912_irq(tps65912, data->irq));
+}
+
+static void tps65912_irq_disable(struct irq_data *data)
+{
+       struct tps65912 *tps65912 = irq_data_get_irq_chip_data(data);
+
+       tps65912->irq_mask |= (1 << irq_to_tps65912_irq(tps65912, data->irq));
+}
+
+static struct irq_chip tps65912_irq_chip = {
+       .name = "tps65912",
+       .irq_bus_lock = tps65912_irq_lock,
+       .irq_bus_sync_unlock = tps65912_irq_sync_unlock,
+       .irq_disable = tps65912_irq_disable,
+       .irq_enable = tps65912_irq_enable,
+};
+
+int tps65912_irq_init(struct tps65912 *tps65912, int irq,
+                           struct tps65912_platform_data *pdata)
+{
+       int ret, cur_irq;
+       int flags = IRQF_ONESHOT;
+       u8 reg;
+
+       if (!irq) {
+               dev_warn(tps65912->dev, "No interrupt support, no core IRQ\n");
+               return 0;
+       }
+
+       if (!pdata || !pdata->irq_base) {
+               dev_warn(tps65912->dev, "No interrupt support, no IRQ base\n");
+               return 0;
+       }
+
+       /* Clear unattended interrupts */
+       tps65912->read(tps65912, TPS65912_INT_STS, 1, &reg);
+       tps65912->write(tps65912, TPS65912_INT_STS, 1, &reg);
+       tps65912->read(tps65912, TPS65912_INT_STS2, 1, &reg);
+       tps65912->write(tps65912, TPS65912_INT_STS2, 1, &reg);
+       tps65912->read(tps65912, TPS65912_INT_STS3, 1, &reg);
+       tps65912->write(tps65912, TPS65912_INT_STS3, 1, &reg);
+       tps65912->read(tps65912, TPS65912_INT_STS4, 1, &reg);
+       tps65912->write(tps65912, TPS65912_INT_STS4, 1, &reg);
+
+       /* Mask top level interrupts */
+       tps65912->irq_mask = 0xFFFFFFFF;
+
+       mutex_init(&tps65912->irq_lock);
+       tps65912->chip_irq = irq;
+       tps65912->irq_base = pdata->irq_base;
+
+       tps65912->irq_num = TPS65912_NUM_IRQ;
+
+       /* Register with genirq */
+       for (cur_irq = tps65912->irq_base;
+            cur_irq < tps65912->irq_num + tps65912->irq_base;
+            cur_irq++) {
+               irq_set_chip_data(cur_irq, tps65912);
+               irq_set_chip_and_handler(cur_irq, &tps65912_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
+       }
+
+       ret = request_threaded_irq(irq, NULL, tps65912_irq, flags,
+                                  "tps65912", tps65912);
+
+       irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);
+       if (ret != 0)
+               dev_err(tps65912->dev, "Failed to request IRQ: %d\n", ret);
+
+       return ret;
+}
+
+int tps65912_irq_exit(struct tps65912 *tps65912)
+{
+       free_irq(tps65912->chip_irq, tps65912);
+       return 0;
+}
diff --git a/drivers/mfd/tps65912-spi.c b/drivers/mfd/tps65912-spi.c
new file mode 100644 (file)
index 0000000..6d71e0d
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * tps65912-spi.c  --  SPI access for TI TPS65912x PMIC
+ *
+ * Copyright 2011 Texas Instruments Inc.
+ *
+ * Author: Margarita Olaya Cabrera <magi@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.
+ *
+ *  This driver is based on wm8350 implementation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/tps65912.h>
+
+static int tps65912_spi_write(struct tps65912 *tps65912, u8 addr,
+                                                       int bytes, void *src)
+{
+       struct spi_device *spi = tps65912->control_data;
+       u8 *data = (u8 *) src;
+       int ret;
+       /* bit 23 is the read/write bit */
+       unsigned long spi_data = 1 << 23 | addr << 15 | *data;
+       struct spi_transfer xfer;
+       struct spi_message msg;
+       u32 tx_buf, rx_buf;
+
+       tx_buf = spi_data;
+       rx_buf = 0;
+
+       xfer.tx_buf     = &tx_buf;
+       xfer.rx_buf     = NULL;
+       xfer.len        = sizeof(unsigned long);
+       xfer.bits_per_word = 24;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+
+       ret = spi_sync(spi, &msg);
+       return ret;
+}
+
+static int tps65912_spi_read(struct tps65912 *tps65912, u8 addr,
+                                                       int bytes, void *dest)
+{
+       struct spi_device *spi = tps65912->control_data;
+       /* bit 23 is the read/write bit */
+       unsigned long spi_data = 0 << 23 | addr << 15;
+       struct spi_transfer xfer;
+       struct spi_message msg;
+       int ret;
+       u8 *data = (u8 *) dest;
+       u32 tx_buf, rx_buf;
+
+       tx_buf = spi_data;
+       rx_buf = 0;
+
+       xfer.tx_buf     = &tx_buf;
+       xfer.rx_buf     = &rx_buf;
+       xfer.len        = sizeof(unsigned long);
+       xfer.bits_per_word = 24;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+
+       if (spi == NULL)
+               return 0;
+
+       ret = spi_sync(spi, &msg);
+       if (ret == 0)
+               *data = (u8) (rx_buf & 0xFF);
+       return ret;
+}
+
+static int __devinit tps65912_spi_probe(struct spi_device *spi)
+{
+       struct tps65912 *tps65912;
+
+       tps65912 = kzalloc(sizeof(struct tps65912), GFP_KERNEL);
+       if (tps65912 == NULL)
+               return -ENOMEM;
+
+       tps65912->dev = &spi->dev;
+       tps65912->control_data = spi;
+       tps65912->read = tps65912_spi_read;
+       tps65912->write = tps65912_spi_write;
+
+       spi_set_drvdata(spi, tps65912);
+
+       return tps65912_device_init(tps65912);
+}
+
+static int __devexit tps65912_spi_remove(struct spi_device *spi)
+{
+       struct tps65912 *tps65912 = spi_get_drvdata(spi);
+
+       tps65912_device_exit(tps65912);
+
+       return 0;
+}
+
+static struct spi_driver tps65912_spi_driver = {
+       .driver = {
+               .name = "tps65912",
+               .bus = &spi_bus_type,
+               .owner = THIS_MODULE,
+       },
+       .probe  = tps65912_spi_probe,
+       .remove = __devexit_p(tps65912_spi_remove),
+};
+
+static int __init tps65912_spi_init(void)
+{
+       int ret;
+
+       ret = spi_register_driver(&tps65912_spi_driver);
+       if (ret != 0)
+               pr_err("Failed to register TPS65912 SPI driver: %d\n", ret);
+
+       return 0;
+}
+/* init early so consumer devices can complete system boot */
+subsys_initcall(tps65912_spi_init);
+
+static void __exit tps65912_spi_exit(void)
+{
+       spi_unregister_driver(&tps65912_spi_driver);
+}
+module_exit(tps65912_spi_exit);
+
+MODULE_AUTHOR("Margarita Olaya <magi@slimlogic.co.uk>");
+MODULE_DESCRIPTION("SPI support for TPS65912 chip family mfd");
+MODULE_LICENSE("GPL");
index a2eddc7..01ecfee 100644 (file)
@@ -1283,6 +1283,8 @@ static const struct i2c_device_id twl_ids[] = {
        { "tps65950", 0 },              /* catalog version of twl5030 */
        { "tps65930", TPS_SUBSET },     /* fewer LDOs and DACs; no charger */
        { "tps65920", TPS_SUBSET },     /* fewer LDOs; no codec or charger */
+       { "tps65921", TPS_SUBSET },     /* fewer LDOs; no codec, no LED
+                                          and vibrator. Charger in USB module*/
        { "twl6030", TWL6030_CLASS },   /* "Phoenix power chip" */
        { "twl6025", TWL6030_CLASS | TWL6025_SUBCLASS }, /* "Phoenix lite" */
        { /* end of list */ },
index 3941ddc..b5d598c 100644 (file)
@@ -530,13 +530,13 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req)
        if (ret) {
                dev_err(twl4030_madc->dev,
                        "unable to write sel register 0x%X\n", method->sel + 1);
-               return ret;
+               goto out;
        }
        ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, ch_lsb, method->sel);
        if (ret) {
                dev_err(twl4030_madc->dev,
                        "unable to write sel register 0x%X\n", method->sel + 1);
-               return ret;
+               goto out;
        }
        /* Select averaging for all channels if do_avg is set */
        if (req->do_avg) {
@@ -546,7 +546,7 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req)
                        dev_err(twl4030_madc->dev,
                                "unable to write avg register 0x%X\n",
                                method->avg + 1);
-                       return ret;
+                       goto out;
                }
                ret = twl_i2c_write_u8(TWL4030_MODULE_MADC,
                                       ch_lsb, method->avg);
@@ -554,7 +554,7 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req)
                        dev_err(twl4030_madc->dev,
                                "unable to write sel reg 0x%X\n",
                                method->sel + 1);
-                       return ret;
+                       goto out;
                }
        }
        if (req->type == TWL4030_MADC_IRQ_ONESHOT && req->func_cb != NULL) {
index 5d25bdc..e8fee14 100644 (file)
@@ -161,3 +161,5 @@ void pwm_free(struct pwm_device *pwm)
        kfree(pwm);
 }
 EXPORT_SYMBOL(pwm_free);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/wm831x-auxadc.c b/drivers/mfd/wm831x-auxadc.c
new file mode 100644 (file)
index 0000000..8721095
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * wm831x-auxadc.c  --  AUXADC for Wolfson WM831x PMICs
+ *
+ * Copyright 2009-2011 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/mfd/core.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+
+#include <linux/mfd/wm831x/core.h>
+#include <linux/mfd/wm831x/pdata.h>
+#include <linux/mfd/wm831x/irq.h>
+#include <linux/mfd/wm831x/auxadc.h>
+#include <linux/mfd/wm831x/otp.h>
+#include <linux/mfd/wm831x/regulator.h>
+
+struct wm831x_auxadc_req {
+       struct list_head list;
+       enum wm831x_auxadc input;
+       int val;
+       struct completion done;
+};
+
+static int wm831x_auxadc_read_irq(struct wm831x *wm831x,
+                                 enum wm831x_auxadc input)
+{
+       struct wm831x_auxadc_req *req;
+       int ret;
+       bool ena = false;
+
+       req = kzalloc(sizeof(*req), GFP_KERNEL);
+       if (!req)
+               return -ENOMEM;
+
+       init_completion(&req->done);
+       req->input = input;
+       req->val = -ETIMEDOUT;
+
+       mutex_lock(&wm831x->auxadc_lock);
+
+       /* Enqueue the request */
+       list_add(&req->list, &wm831x->auxadc_pending);
+
+       ena = !wm831x->auxadc_active;
+
+       if (ena) {
+               ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL,
+                                     WM831X_AUX_ENA, WM831X_AUX_ENA);
+               if (ret != 0) {
+                       dev_err(wm831x->dev, "Failed to enable AUXADC: %d\n",
+                               ret);
+                       goto out;
+               }
+       }
+
+       /* Enable the conversion if not already running */
+       if (!(wm831x->auxadc_active & (1 << input))) {
+               ret = wm831x_set_bits(wm831x, WM831X_AUXADC_SOURCE,
+                                     1 << input, 1 << input);
+               if (ret != 0) {
+                       dev_err(wm831x->dev,
+                               "Failed to set AUXADC source: %d\n", ret);
+                       goto out;
+               }
+
+               wm831x->auxadc_active |= 1 << input;
+       }
+
+       /* We convert at the fastest rate possible */
+       if (ena) {
+               ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL,
+                                     WM831X_AUX_CVT_ENA |
+                                     WM831X_AUX_RATE_MASK,
+                                     WM831X_AUX_CVT_ENA |
+                                     WM831X_AUX_RATE_MASK);
+               if (ret != 0) {
+                       dev_err(wm831x->dev, "Failed to start AUXADC: %d\n",
+                               ret);
+                       goto out;
+               }
+       }
+
+       mutex_unlock(&wm831x->auxadc_lock);
+
+       /* Wait for an interrupt */
+       wait_for_completion_timeout(&req->done, msecs_to_jiffies(500));
+
+       mutex_lock(&wm831x->auxadc_lock);
+
+       list_del(&req->list);
+       ret = req->val;
+
+out:
+       mutex_unlock(&wm831x->auxadc_lock);
+
+       kfree(req);
+
+       return ret;
+}
+
+static irqreturn_t wm831x_auxadc_irq(int irq, void *irq_data)
+{
+       struct wm831x *wm831x = irq_data;
+       struct wm831x_auxadc_req *req;
+       int ret, input, val;
+
+       ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA);
+       if (ret < 0) {
+               dev_err(wm831x->dev,
+                       "Failed to read AUXADC data: %d\n", ret);
+               return IRQ_NONE;
+       }
+
+       input = ((ret & WM831X_AUX_DATA_SRC_MASK)
+                >> WM831X_AUX_DATA_SRC_SHIFT) - 1;
+
+       if (input == 14)
+               input = WM831X_AUX_CAL;
+
+       val = ret & WM831X_AUX_DATA_MASK;
+
+       mutex_lock(&wm831x->auxadc_lock);
+
+       /* Disable this conversion, we're about to complete all users */
+       wm831x_set_bits(wm831x, WM831X_AUXADC_SOURCE,
+                       1 << input, 0);
+       wm831x->auxadc_active &= ~(1 << input);
+
+       /* Turn off the entire convertor if idle */
+       if (!wm831x->auxadc_active)
+               wm831x_reg_write(wm831x, WM831X_AUXADC_CONTROL, 0);
+
+       /* Wake up any threads waiting for this request */
+       list_for_each_entry(req, &wm831x->auxadc_pending, list) {
+               if (req->input == input) {
+                       req->val = val;
+                       complete(&req->done);
+               }
+       }
+
+       mutex_unlock(&wm831x->auxadc_lock);
+
+       return IRQ_HANDLED;
+}
+
+static int wm831x_auxadc_read_polled(struct wm831x *wm831x,
+                                    enum wm831x_auxadc input)
+{
+       int ret, src, timeout;
+
+       mutex_lock(&wm831x->auxadc_lock);
+
+       ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL,
+                             WM831X_AUX_ENA, WM831X_AUX_ENA);
+       if (ret < 0) {
+               dev_err(wm831x->dev, "Failed to enable AUXADC: %d\n", ret);
+               goto out;
+       }
+
+       /* We force a single source at present */
+       src = input;
+       ret = wm831x_reg_write(wm831x, WM831X_AUXADC_SOURCE,
+                              1 << src);
+       if (ret < 0) {
+               dev_err(wm831x->dev, "Failed to set AUXADC source: %d\n", ret);
+               goto out;
+       }
+
+       ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL,
+                             WM831X_AUX_CVT_ENA, WM831X_AUX_CVT_ENA);
+       if (ret < 0) {
+               dev_err(wm831x->dev, "Failed to start AUXADC: %d\n", ret);
+               goto disable;
+       }
+
+       /* If we're not using interrupts then poll the
+        * interrupt status register */
+       timeout = 5;
+       while (timeout) {
+               msleep(1);
+
+               ret = wm831x_reg_read(wm831x,
+                                     WM831X_INTERRUPT_STATUS_1);
+               if (ret < 0) {
+                       dev_err(wm831x->dev,
+                               "ISR 1 read failed: %d\n", ret);
+                       goto disable;
+               }
+
+               /* Did it complete? */
+               if (ret & WM831X_AUXADC_DATA_EINT) {
+                       wm831x_reg_write(wm831x,
+                                        WM831X_INTERRUPT_STATUS_1,
+                                        WM831X_AUXADC_DATA_EINT);
+                       break;
+               } else {
+                       dev_err(wm831x->dev,
+                               "AUXADC conversion timeout\n");
+                       ret = -EBUSY;
+                       goto disable;
+               }
+       }
+
+       ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA);
+       if (ret < 0) {
+               dev_err(wm831x->dev,
+                       "Failed to read AUXADC data: %d\n", ret);
+               goto disable;
+       }
+
+       src = ((ret & WM831X_AUX_DATA_SRC_MASK)
+              >> WM831X_AUX_DATA_SRC_SHIFT) - 1;
+
+       if (src == 14)
+               src = WM831X_AUX_CAL;
+
+       if (src != input) {
+               dev_err(wm831x->dev, "Data from source %d not %d\n",
+                       src, input);
+               ret = -EINVAL;
+       } else {
+               ret &= WM831X_AUX_DATA_MASK;
+       }
+
+disable:
+       wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, WM831X_AUX_ENA, 0);
+out:
+       mutex_unlock(&wm831x->auxadc_lock);
+       return ret;
+}
+
+/**
+ * wm831x_auxadc_read: Read a value from the WM831x AUXADC
+ *
+ * @wm831x: Device to read from.
+ * @input: AUXADC input to read.
+ */
+int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input)
+{
+       return wm831x->auxadc_read(wm831x, input);
+}
+EXPORT_SYMBOL_GPL(wm831x_auxadc_read);
+
+/**
+ * wm831x_auxadc_read_uv: Read a voltage from the WM831x AUXADC
+ *
+ * @wm831x: Device to read from.
+ * @input: AUXADC input to read.
+ */
+int wm831x_auxadc_read_uv(struct wm831x *wm831x, enum wm831x_auxadc input)
+{
+       int ret;
+
+       ret = wm831x_auxadc_read(wm831x, input);
+       if (ret < 0)
+               return ret;
+
+       ret *= 1465;
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(wm831x_auxadc_read_uv);
+
+void wm831x_auxadc_init(struct wm831x *wm831x)
+{
+       int ret;
+
+       mutex_init(&wm831x->auxadc_lock);
+       INIT_LIST_HEAD(&wm831x->auxadc_pending);
+
+       if (wm831x->irq && wm831x->irq_base) {
+               wm831x->auxadc_read = wm831x_auxadc_read_irq;
+
+               ret = request_threaded_irq(wm831x->irq_base +
+                                          WM831X_IRQ_AUXADC_DATA,
+                                          NULL, wm831x_auxadc_irq, 0,
+                                          "auxadc", wm831x);
+               if (ret < 0) {
+                       dev_err(wm831x->dev, "AUXADC IRQ request failed: %d\n",
+                               ret);
+                       wm831x->auxadc_read = NULL;
+               }
+       }
+
+       if (!wm831x->auxadc_read)
+               wm831x->auxadc_read = wm831x_auxadc_read_polled;
+}
index 265f75f..282e76a 100644 (file)
@@ -295,7 +295,7 @@ int wm831x_set_bits(struct wm831x *wm831x, unsigned short reg,
                goto out;
 
        r &= ~mask;
-       r |= val;
+       r |= val & mask;
 
        ret = wm831x_write(wm831x, reg, 2, &r);
 
@@ -306,146 +306,6 @@ out:
 }
 EXPORT_SYMBOL_GPL(wm831x_set_bits);
 
-/**
- * wm831x_auxadc_read: Read a value from the WM831x AUXADC
- *
- * @wm831x: Device to read from.
- * @input: AUXADC input to read.
- */
-int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input)
-{
-       int ret, src, irq_masked, timeout;
-
-       /* Are we using the interrupt? */
-       irq_masked = wm831x_reg_read(wm831x, WM831X_INTERRUPT_STATUS_1_MASK);
-       irq_masked &= WM831X_AUXADC_DATA_EINT;
-
-       mutex_lock(&wm831x->auxadc_lock);
-
-       ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL,
-                             WM831X_AUX_ENA, WM831X_AUX_ENA);
-       if (ret < 0) {
-               dev_err(wm831x->dev, "Failed to enable AUXADC: %d\n", ret);
-               goto out;
-       }
-
-       /* We force a single source at present */
-       src = input;
-       ret = wm831x_reg_write(wm831x, WM831X_AUXADC_SOURCE,
-                              1 << src);
-       if (ret < 0) {
-               dev_err(wm831x->dev, "Failed to set AUXADC source: %d\n", ret);
-               goto out;
-       }
-
-       /* Clear any notification from a very late arriving interrupt */
-       try_wait_for_completion(&wm831x->auxadc_done);
-
-       ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL,
-                             WM831X_AUX_CVT_ENA, WM831X_AUX_CVT_ENA);
-       if (ret < 0) {
-               dev_err(wm831x->dev, "Failed to start AUXADC: %d\n", ret);
-               goto disable;
-       }
-
-       if (irq_masked) {
-               /* If we're not using interrupts then poll the
-                * interrupt status register */
-               timeout = 5;
-               while (timeout) {
-                       msleep(1);
-
-                       ret = wm831x_reg_read(wm831x,
-                                             WM831X_INTERRUPT_STATUS_1);
-                       if (ret < 0) {
-                               dev_err(wm831x->dev,
-                                       "ISR 1 read failed: %d\n", ret);
-                               goto disable;
-                       }
-
-                       /* Did it complete? */
-                       if (ret & WM831X_AUXADC_DATA_EINT) {
-                               wm831x_reg_write(wm831x,
-                                                WM831X_INTERRUPT_STATUS_1,
-                                                WM831X_AUXADC_DATA_EINT);
-                               break;
-                       } else {
-                               dev_err(wm831x->dev,
-                                       "AUXADC conversion timeout\n");
-                               ret = -EBUSY;
-                               goto disable;
-                       }
-               }
-       } else {
-               /* If we are using interrupts then wait for the
-                * interrupt to complete.  Use an extremely long
-                * timeout to handle situations with heavy load where
-                * the notification of the interrupt may be delayed by
-                * threaded IRQ handling. */
-               if (!wait_for_completion_timeout(&wm831x->auxadc_done,
-                                                msecs_to_jiffies(500))) {
-                       dev_err(wm831x->dev, "Timed out waiting for AUXADC\n");
-                       ret = -EBUSY;
-                       goto disable;
-               }
-       }
-
-       ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA);
-       if (ret < 0) {
-               dev_err(wm831x->dev, "Failed to read AUXADC data: %d\n", ret);
-       } else {
-               src = ((ret & WM831X_AUX_DATA_SRC_MASK)
-                      >> WM831X_AUX_DATA_SRC_SHIFT) - 1;
-
-               if (src == 14)
-                       src = WM831X_AUX_CAL;
-
-               if (src != input) {
-                       dev_err(wm831x->dev, "Data from source %d not %d\n",
-                               src, input);
-                       ret = -EINVAL;
-               } else {
-                       ret &= WM831X_AUX_DATA_MASK;
-               }
-       }
-
-disable:
-       wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, WM831X_AUX_ENA, 0);
-out:
-       mutex_unlock(&wm831x->auxadc_lock);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(wm831x_auxadc_read);
-
-static irqreturn_t wm831x_auxadc_irq(int irq, void *irq_data)
-{
-       struct wm831x *wm831x = irq_data;
-
-       complete(&wm831x->auxadc_done);
-
-       return IRQ_HANDLED;
-}
-
-/**
- * wm831x_auxadc_read_uv: Read a voltage from the WM831x AUXADC
- *
- * @wm831x: Device to read from.
- * @input: AUXADC input to read.
- */
-int wm831x_auxadc_read_uv(struct wm831x *wm831x, enum wm831x_auxadc input)
-{
-       int ret;
-
-       ret = wm831x_auxadc_read(wm831x, input);
-       if (ret < 0)
-               return ret;
-
-       ret *= 1465;
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(wm831x_auxadc_read_uv);
-
 static struct resource wm831x_dcdc1_resources[] = {
        {
                .start = WM831X_DC1_CONTROL_1,
@@ -871,6 +731,9 @@ static struct mfd_cell wm8310_devs[] = {
                .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
                .resources = wm831x_dcdc4_resources,
        },
+       {
+               .name = "wm831x-clk",
+       },
        {
                .name = "wm831x-epe",
                .id = 1,
@@ -975,11 +838,6 @@ static struct mfd_cell wm8310_devs[] = {
                .num_resources = ARRAY_SIZE(wm831x_power_resources),
                .resources = wm831x_power_resources,
        },
-       {
-               .name = "wm831x-rtc",
-               .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
-               .resources = wm831x_rtc_resources,
-       },
        {
                .name = "wm831x-status",
                .id = 1,
@@ -1027,6 +885,9 @@ static struct mfd_cell wm8311_devs[] = {
                .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
                .resources = wm831x_dcdc4_resources,
        },
+       {
+               .name = "wm831x-clk",
+       },
        {
                .name = "wm831x-epe",
                .id = 1,
@@ -1107,11 +968,6 @@ static struct mfd_cell wm8311_devs[] = {
                .num_resources = ARRAY_SIZE(wm831x_power_resources),
                .resources = wm831x_power_resources,
        },
-       {
-               .name = "wm831x-rtc",
-               .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
-               .resources = wm831x_rtc_resources,
-       },
        {
                .name = "wm831x-status",
                .id = 1,
@@ -1124,11 +980,6 @@ static struct mfd_cell wm8311_devs[] = {
                .num_resources = ARRAY_SIZE(wm831x_status2_resources),
                .resources = wm831x_status2_resources,
        },
-       {
-               .name = "wm831x-touch",
-               .num_resources = ARRAY_SIZE(wm831x_touch_resources),
-               .resources = wm831x_touch_resources,
-       },
        {
                .name = "wm831x-watchdog",
                .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
@@ -1164,6 +1015,9 @@ static struct mfd_cell wm8312_devs[] = {
                .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
                .resources = wm831x_dcdc4_resources,
        },
+       {
+               .name = "wm831x-clk",
+       },
        {
                .name = "wm831x-epe",
                .id = 1,
@@ -1268,11 +1122,6 @@ static struct mfd_cell wm8312_devs[] = {
                .num_resources = ARRAY_SIZE(wm831x_power_resources),
                .resources = wm831x_power_resources,
        },
-       {
-               .name = "wm831x-rtc",
-               .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
-               .resources = wm831x_rtc_resources,
-       },
        {
                .name = "wm831x-status",
                .id = 1,
@@ -1285,11 +1134,6 @@ static struct mfd_cell wm8312_devs[] = {
                .num_resources = ARRAY_SIZE(wm831x_status2_resources),
                .resources = wm831x_status2_resources,
        },
-       {
-               .name = "wm831x-touch",
-               .num_resources = ARRAY_SIZE(wm831x_touch_resources),
-               .resources = wm831x_touch_resources,
-       },
        {
                .name = "wm831x-watchdog",
                .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
@@ -1325,6 +1169,9 @@ static struct mfd_cell wm8320_devs[] = {
                .num_resources = ARRAY_SIZE(wm8320_dcdc4_buck_resources),
                .resources = wm8320_dcdc4_buck_resources,
        },
+       {
+               .name = "wm831x-clk",
+       },
        {
                .name = "wm831x-gpio",
                .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
@@ -1404,11 +1251,6 @@ static struct mfd_cell wm8320_devs[] = {
                .num_resources = ARRAY_SIZE(wm831x_on_resources),
                .resources = wm831x_on_resources,
        },
-       {
-               .name = "wm831x-rtc",
-               .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
-               .resources = wm831x_rtc_resources,
-       },
        {
                .name = "wm831x-status",
                .id = 1,
@@ -1428,6 +1270,22 @@ static struct mfd_cell wm8320_devs[] = {
        },
 };
 
+static struct mfd_cell touch_devs[] = {
+       {
+               .name = "wm831x-touch",
+               .num_resources = ARRAY_SIZE(wm831x_touch_resources),
+               .resources = wm831x_touch_resources,
+       },
+};
+
+static struct mfd_cell rtc_devs[] = {
+       {
+               .name = "wm831x-rtc",
+               .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
+               .resources = wm831x_rtc_resources,
+       },
+};
+
 static struct mfd_cell backlight_devs[] = {
        {
                .name = "wm831x-backlight",
@@ -1440,14 +1298,12 @@ static struct mfd_cell backlight_devs[] = {
 int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
 {
        struct wm831x_pdata *pdata = wm831x->dev->platform_data;
-       int rev;
+       int rev, wm831x_num;
        enum wm831x_parent parent;
        int ret, i;
 
        mutex_init(&wm831x->io_lock);
        mutex_init(&wm831x->key_lock);
-       mutex_init(&wm831x->auxadc_lock);
-       init_completion(&wm831x->auxadc_done);
        dev_set_drvdata(wm831x->dev, wm831x);
 
        ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID);
@@ -1592,45 +1448,51 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
                }
        }
 
+       /* Multiply by 10 as we have many subdevices of the same type */
+       if (pdata && pdata->wm831x_num)
+               wm831x_num = pdata->wm831x_num * 10;
+       else
+               wm831x_num = -1;
+
        ret = wm831x_irq_init(wm831x, irq);
        if (ret != 0)
                goto err;
 
-       if (wm831x->irq_base) {
-               ret = request_threaded_irq(wm831x->irq_base +
-                                          WM831X_IRQ_AUXADC_DATA,
-                                          NULL, wm831x_auxadc_irq, 0,
-                                          "auxadc", wm831x);
-               if (ret < 0)
-                       dev_err(wm831x->dev, "AUXADC IRQ request failed: %d\n",
-                               ret);
-       }
+       wm831x_auxadc_init(wm831x);
 
        /* The core device is up, instantiate the subdevices. */
        switch (parent) {
        case WM8310:
-               ret = mfd_add_devices(wm831x->dev, -1,
+               ret = mfd_add_devices(wm831x->dev, wm831x_num,
                                      wm8310_devs, ARRAY_SIZE(wm8310_devs),
                                      NULL, wm831x->irq_base);
                break;
 
        case WM8311:
-               ret = mfd_add_devices(wm831x->dev, -1,
+               ret = mfd_add_devices(wm831x->dev, wm831x_num,
                                      wm8311_devs, ARRAY_SIZE(wm8311_devs),
                                      NULL, wm831x->irq_base);
+               if (!pdata || !pdata->disable_touch)
+                       mfd_add_devices(wm831x->dev, wm831x_num,
+                                       touch_devs, ARRAY_SIZE(touch_devs),
+                                       NULL, wm831x->irq_base);
                break;
 
        case WM8312:
-               ret = mfd_add_devices(wm831x->dev, -1,
+               ret = mfd_add_devices(wm831x->dev, wm831x_num,
                                      wm8312_devs, ARRAY_SIZE(wm8312_devs),
                                      NULL, wm831x->irq_base);
+               if (!pdata || !pdata->disable_touch)
+                       mfd_add_devices(wm831x->dev, wm831x_num,
+                                       touch_devs, ARRAY_SIZE(touch_devs),
+                                       NULL, wm831x->irq_base);
                break;
 
        case WM8320:
        case WM8321:
        case WM8325:
        case WM8326:
-               ret = mfd_add_devices(wm831x->dev, -1,
+               ret = mfd_add_devices(wm831x->dev, wm831x_num,
                                      wm8320_devs, ARRAY_SIZE(wm8320_devs),
                                      NULL, wm831x->irq_base);
                break;
@@ -1645,9 +1507,30 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
                goto err_irq;
        }
 
+       /* The RTC can only be used if the 32.768kHz crystal is
+        * enabled; this can't be controlled by software at runtime.
+        */
+       ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_2);
+       if (ret < 0) {
+               dev_err(wm831x->dev, "Failed to read clock status: %d\n", ret);
+               goto err_irq;
+       }
+
+       if (ret & WM831X_XTAL_ENA) {
+               ret = mfd_add_devices(wm831x->dev, wm831x_num,
+                                     rtc_devs, ARRAY_SIZE(rtc_devs),
+                                     NULL, wm831x->irq_base);
+               if (ret != 0) {
+                       dev_err(wm831x->dev, "Failed to add RTC: %d\n", ret);
+                       goto err_irq;
+               }
+       } else {
+               dev_info(wm831x->dev, "32.768kHz clock disabled, no RTC\n");
+       }
+
        if (pdata && pdata->backlight) {
                /* Treat errors as non-critical */
-               ret = mfd_add_devices(wm831x->dev, -1, backlight_devs,
+               ret = mfd_add_devices(wm831x->dev, wm831x_num, backlight_devs,
                                      ARRAY_SIZE(backlight_devs), NULL,
                                      wm831x->irq_base);
                if (ret < 0)
index 42b928e..ada1835 100644 (file)
@@ -348,6 +348,15 @@ static void wm831x_irq_sync_unlock(struct irq_data *data)
        struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
        int i;
 
+       for (i = 0; i < ARRAY_SIZE(wm831x->gpio_update); i++) {
+               if (wm831x->gpio_update[i]) {
+                       wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + i,
+                                       WM831X_GPN_INT_MODE | WM831X_GPN_POL,
+                                       wm831x->gpio_update[i]);
+                       wm831x->gpio_update[i] = 0;
+               }
+       }
+
        for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) {
                /* If there's been a change in the mask write it back
                 * to the hardware. */
@@ -387,7 +396,7 @@ static void wm831x_irq_disable(struct irq_data *data)
 static int wm831x_irq_set_type(struct irq_data *data, unsigned int type)
 {
        struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
-       int val, irq;
+       int irq;
 
        irq = data->irq - wm831x->irq_base;
 
@@ -399,22 +408,30 @@ static int wm831x_irq_set_type(struct irq_data *data, unsigned int type)
                        return -EINVAL;
        }
 
+       /* Rebase the IRQ into the GPIO range so we've got a sensible array
+        * index.
+        */
+       irq -= WM831X_IRQ_GPIO_1;
+
+       /* We set the high bit to flag that we need an update; don't
+        * do the update here as we can be called with the bus lock
+        * held.
+        */
        switch (type) {
        case IRQ_TYPE_EDGE_BOTH:
-               val = WM831X_GPN_INT_MODE;
+               wm831x->gpio_update[irq] = 0x10000 | WM831X_GPN_INT_MODE;
                break;
        case IRQ_TYPE_EDGE_RISING:
-               val = WM831X_GPN_POL;
+               wm831x->gpio_update[irq] = 0x10000 | WM831X_GPN_POL;
                break;
        case IRQ_TYPE_EDGE_FALLING:
-               val = 0;
+               wm831x->gpio_update[irq] = 0x10000;
                break;
        default:
                return -EINVAL;
        }
 
-       return wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + irq,
-                              WM831X_GPN_INT_MODE | WM831X_GPN_POL, val);
+       return 0;
 }
 
 static struct irq_chip wm831x_irq_chip = {
@@ -432,7 +449,7 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data)
 {
        struct wm831x *wm831x = data;
        unsigned int i;
-       int primary;
+       int primary, status_addr;
        int status_regs[WM831X_NUM_IRQ_REGS] = { 0 };
        int read[WM831X_NUM_IRQ_REGS] = { 0 };
        int *status;
@@ -467,8 +484,9 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data)
                /* Hopefully there should only be one register to read
                 * each time otherwise we ought to do a block read. */
                if (!read[offset]) {
-                       *status = wm831x_reg_read(wm831x,
-                                    irq_data_to_status_reg(&wm831x_irqs[i]));
+                       status_addr = irq_data_to_status_reg(&wm831x_irqs[i]);
+
+                       *status = wm831x_reg_read(wm831x, status_addr);
                        if (*status < 0) {
                                dev_err(wm831x->dev,
                                        "Failed to read IRQ status: %d\n",
@@ -477,26 +495,21 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data)
                        }
 
                        read[offset] = 1;
+
+                       /* Ignore any bits that we don't think are masked */
+                       *status &= ~wm831x->irq_masks_cur[offset];
+
+                       /* Acknowledge now so we don't miss
+                        * notifications while we handle.
+                        */
+                       wm831x_reg_write(wm831x, status_addr, *status);
                }
 
-               /* Report it if it isn't masked, or forget the status. */
-               if ((*status & ~wm831x->irq_masks_cur[offset])
-                   & wm831x_irqs[i].mask)
+               if (*status & wm831x_irqs[i].mask)
                        handle_nested_irq(wm831x->irq_base + i);
-               else
-                       *status &= ~wm831x_irqs[i].mask;
        }
 
 out:
-       /* Touchscreen interrupts are handled specially in the driver */
-       status_regs[0] &= ~(WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT);
-
-       for (i = 0; i < ARRAY_SIZE(status_regs); i++) {
-               if (status_regs[i])
-                       wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1 + i,
-                                        status_regs[i]);
-       }
-
        return IRQ_HANDLED;
 }
 
@@ -515,13 +528,22 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
                                 0xffff);
        }
 
-       if (!pdata || !pdata->irq_base) {
-               dev_err(wm831x->dev,
-                       "No interrupt base specified, no interrupts\n");
+       /* Try to dynamically allocate IRQs if no base is specified */
+       if (!pdata || !pdata->irq_base)
+               wm831x->irq_base = -1;
+       else
+               wm831x->irq_base = pdata->irq_base;
+
+       wm831x->irq_base = irq_alloc_descs(wm831x->irq_base, 0,
+                                          WM831X_NUM_IRQS, 0);
+       if (wm831x->irq_base < 0) {
+               dev_warn(wm831x->dev, "Failed to allocate IRQs: %d\n",
+                        wm831x->irq_base);
+               wm831x->irq_base = 0;
                return 0;
        }
 
-       if (pdata->irq_cmos)
+       if (pdata && pdata->irq_cmos)
                i = 0;
        else
                i = WM831X_IRQ_OD;
@@ -541,7 +563,6 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
        }
 
        wm831x->irq = irq;
-       wm831x->irq_base = pdata->irq_base;
 
        /* Register them with genirq */
        for (cur_irq = wm831x->irq_base;
index ed4b22a..8a1fafd 100644 (file)
@@ -473,17 +473,13 @@ int wm8350_irq_init(struct wm8350 *wm8350, int irq,
 {
        int ret, cur_irq, i;
        int flags = IRQF_ONESHOT;
+       int irq_base = -1;
 
        if (!irq) {
                dev_warn(wm8350->dev, "No interrupt support, no core IRQ\n");
                return 0;
        }
 
-       if (!pdata || !pdata->irq_base) {
-               dev_warn(wm8350->dev, "No interrupt support, no IRQ base\n");
-               return 0;
-       }
-
        /* Mask top level interrupts */
        wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0xFFFF);
 
@@ -502,7 +498,17 @@ int wm8350_irq_init(struct wm8350 *wm8350, int irq,
        wm8350->chip_irq = irq;
        wm8350->irq_base = pdata->irq_base;
 
-       if (pdata->irq_high) {
+       if (pdata && pdata->irq_base > 0)
+               irq_base = pdata->irq_base;
+
+       wm8350->irq_base = irq_alloc_descs(irq_base, 0, ARRAY_SIZE(wm8350_irqs), 0);
+       if (wm8350->irq_base < 0) {
+               dev_warn(wm8350->dev, "Allocating irqs failed with %d\n",
+                       wm8350->irq_base);
+               return 0;
+       }
+
+       if (pdata && pdata->irq_high) {
                flags |= IRQF_TRIGGER_HIGH;
 
                wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1,
index e198d40..96479c9 100644 (file)
@@ -316,7 +316,7 @@ static int wm8994_suspend(struct device *dev)
 static int wm8994_resume(struct device *dev)
 {
        struct wm8994 *wm8994 = dev_get_drvdata(dev);
-       int ret;
+       int ret, i;
 
        /* We may have lied to the PM core about suspending */
        if (!wm8994->suspended)
@@ -329,10 +329,16 @@ static int wm8994_resume(struct device *dev)
                return ret;
        }
 
-       ret = wm8994_write(wm8994, WM8994_INTERRUPT_STATUS_1_MASK,
-                          WM8994_NUM_IRQ_REGS * 2, &wm8994->irq_masks_cur);
-       if (ret < 0)
-               dev_err(dev, "Failed to restore interrupt masks: %d\n", ret);
+       /* Write register at a time as we use the cache on the CPU so store
+        * it in native endian.
+        */
+       for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) {
+               ret = wm8994_reg_write(wm8994, WM8994_INTERRUPT_STATUS_1_MASK
+                                      + i, wm8994->irq_masks_cur[i]);
+               if (ret < 0)
+                       dev_err(dev, "Failed to restore interrupt masks: %d\n",
+                               ret);
+       }
 
        ret = wm8994_write(wm8994, WM8994_LDO_1, WM8994_NUM_LDO_REGS * 2,
                           &wm8994->ldo_regs);
@@ -403,7 +409,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
                break;
        default:
                BUG();
-               return -EINVAL;
+               goto err;
        }
 
        wm8994->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
@@ -425,7 +431,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
                break;
        default:
                BUG();
-               return -EINVAL;
+               goto err;
        }
                
        ret = regulator_bulk_get(wm8994->dev, wm8994->num_supplies,
@@ -476,13 +482,18 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
                goto err_enable;
        }
 
-       switch (ret) {
-       case 0:
-       case 1:
-               if (wm8994->type == WM8994)
+       switch (wm8994->type) {
+       case WM8994:
+               switch (ret) {
+               case 0:
+               case 1:
                        dev_warn(wm8994->dev,
                                 "revision %c not fully supported\n",
                                 'A' + ret);
+                       break;
+               default:
+                       break;
+               }
                break;
        default:
                break;
index 71c6e8f..d682f7b 100644 (file)
@@ -231,12 +231,6 @@ static irqreturn_t wm8994_irq_thread(int irq, void *data)
                status[i] &= ~wm8994->irq_masks_cur[i];
        }
 
-       /* Report */
-       for (i = 0; i < ARRAY_SIZE(wm8994_irqs); i++) {
-               if (status[wm8994_irqs[i].reg - 1] & wm8994_irqs[i].mask)
-                       handle_nested_irq(wm8994->irq_base + i);
-       }
-
        /* Ack any unmasked IRQs */
        for (i = 0; i < ARRAY_SIZE(status); i++) {
                if (status[i])
@@ -244,6 +238,12 @@ static irqreturn_t wm8994_irq_thread(int irq, void *data)
                                         status[i]);
        }
 
+       /* Report */
+       for (i = 0; i < ARRAY_SIZE(wm8994_irqs); i++) {
+               if (status[wm8994_irqs[i].reg - 1] & wm8994_irqs[i].mask)
+                       handle_nested_irq(wm8994->irq_base + i);
+       }
+
        return IRQ_HANDLED;
 }
 
index efec413..68cd05b 100644 (file)
@@ -33,7 +33,7 @@ EXPORT_SYMBOL_GPL(cb710_pci_update_config_reg);
 static int __devinit cb710_pci_configure(struct pci_dev *pdev)
 {
        unsigned int devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0);
-       struct pci_dev *pdev0 = pci_get_slot(pdev->bus, devfn);
+       struct pci_dev *pdev0;
        u32 val;
 
        cb710_pci_update_config_reg(pdev, 0x48,
@@ -43,6 +43,7 @@ static int __devinit cb710_pci_configure(struct pci_dev *pdev)
        if (val & 0x80000000)
                return 0;
 
+       pdev0 = pci_get_slot(pdev->bus, devfn);
        if (!pdev0)
                return -ENODEV;
 
index 006a5e9..2bf229a 100644 (file)
@@ -224,7 +224,7 @@ static void mmc_test_prepare_mrq(struct mmc_test_card *test,
 static int mmc_test_busy(struct mmc_command *cmd)
 {
        return !(cmd->resp[0] & R1_READY_FOR_DATA) ||
-               (R1_CURRENT_STATE(cmd->resp[0]) == 7);
+               (R1_CURRENT_STATE(cmd->resp[0]) == R1_STATE_PRG);
 }
 
 /*
@@ -2900,7 +2900,7 @@ static const struct file_operations mmc_test_fops_testlist = {
        .release        = single_release,
 };
 
-static void mmc_test_free_file_test(struct mmc_card *card)
+static void mmc_test_free_dbgfs_file(struct mmc_card *card)
 {
        struct mmc_test_dbgfs_file *df, *dfs;
 
@@ -2917,34 +2917,21 @@ static void mmc_test_free_file_test(struct mmc_card *card)
        mutex_unlock(&mmc_test_lock);
 }
 
-static int mmc_test_register_file_test(struct mmc_card *card)
+static int __mmc_test_register_dbgfs_file(struct mmc_card *card,
+       const char *name, mode_t mode, const struct file_operations *fops)
 {
        struct dentry *file = NULL;
        struct mmc_test_dbgfs_file *df;
-       int ret = 0;
-
-       mutex_lock(&mmc_test_lock);
-
-       if (card->debugfs_root)
-               file = debugfs_create_file("test", S_IWUSR | S_IRUGO,
-                       card->debugfs_root, card, &mmc_test_fops_test);
-
-       if (IS_ERR_OR_NULL(file)) {
-               dev_err(&card->dev,
-                       "Can't create test. Perhaps debugfs is disabled.\n");
-               ret = -ENODEV;
-               goto err;
-       }
 
        if (card->debugfs_root)
-               file = debugfs_create_file("testlist", S_IRUGO,
-                       card->debugfs_root, card, &mmc_test_fops_testlist);
+               file = debugfs_create_file(name, mode, card->debugfs_root,
+                       card, fops);
 
        if (IS_ERR_OR_NULL(file)) {
                dev_err(&card->dev,
-                       "Can't create testlist. Perhaps debugfs is disabled.\n");
-               ret = -ENODEV;
-               goto err;
+                       "Can't create %s. Perhaps debugfs is disabled.\n",
+                       name);
+               return -ENODEV;
        }
 
        df = kmalloc(sizeof(struct mmc_test_dbgfs_file), GFP_KERNEL);
@@ -2952,14 +2939,31 @@ static int mmc_test_register_file_test(struct mmc_card *card)
                debugfs_remove(file);
                dev_err(&card->dev,
                        "Can't allocate memory for internal usage.\n");
-               ret = -ENOMEM;
-               goto err;
+               return -ENOMEM;
        }
 
        df->card = card;
        df->file = file;
 
        list_add(&df->link, &mmc_test_file_test);
+       return 0;
+}
+
+static int mmc_test_register_dbgfs_file(struct mmc_card *card)
+{
+       int ret;
+
+       mutex_lock(&mmc_test_lock);
+
+       ret = __mmc_test_register_dbgfs_file(card, "test", S_IWUSR | S_IRUGO,
+               &mmc_test_fops_test);
+       if (ret)
+               goto err;
+
+       ret = __mmc_test_register_dbgfs_file(card, "testlist", S_IRUGO,
+               &mmc_test_fops_testlist);
+       if (ret)
+               goto err;
 
 err:
        mutex_unlock(&mmc_test_lock);
@@ -2974,7 +2978,7 @@ static int mmc_test_probe(struct mmc_card *card)
        if (!mmc_card_mmc(card) && !mmc_card_sd(card))
                return -ENODEV;
 
-       ret = mmc_test_register_file_test(card);
+       ret = mmc_test_register_dbgfs_file(card);
        if (ret)
                return ret;
 
@@ -2986,7 +2990,7 @@ static int mmc_test_probe(struct mmc_card *card)
 static void mmc_test_remove(struct mmc_card *card)
 {
        mmc_test_free_result(card);
-       mmc_test_free_file_test(card);
+       mmc_test_free_dbgfs_file(card);
 }
 
 static struct mmc_driver mmc_driver = {
@@ -3006,7 +3010,7 @@ static void __exit mmc_test_exit(void)
 {
        /* Clear stalled data if card is still plugged */
        mmc_test_free_result(NULL);
-       mmc_test_free_file_test(NULL);
+       mmc_test_free_dbgfs_file(NULL);
 
        mmc_unregister_driver(&mmc_driver);
 }
index 89bdeae..91a0a74 100644 (file)
@@ -1502,7 +1502,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
                        goto out;
                }
        } while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
-                R1_CURRENT_STATE(cmd.resp[0]) == 7);
+                R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG);
 out:
        return err;
 }
index aa7d1d7..5700b1c 100644 (file)
@@ -259,7 +259,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
        }
 
        card->ext_csd.rev = ext_csd[EXT_CSD_REV];
-       if (card->ext_csd.rev > 5) {
+       if (card->ext_csd.rev > 6) {
                printk(KERN_ERR "%s: unrecognised EXT_CSD revision %d\n",
                        mmc_hostname(card->host), card->ext_csd.rev);
                err = -EINVAL;
index 845ce7c..770c3d0 100644 (file)
@@ -407,7 +407,7 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
                        break;
                if (mmc_host_is_spi(card->host))
                        break;
-       } while (R1_CURRENT_STATE(status) == 7);
+       } while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
 
        if (mmc_host_is_spi(card->host)) {
                if (status & R1_SPI_ILLEGAL_COMMAND)
index 77f0b6b..ff0f714 100644 (file)
@@ -62,7 +62,7 @@ struct idmac_desc {
 
        u32             des1;   /* Buffer sizes */
 #define IDMAC_SET_BUFFER1_SIZE(d, s) \
-       ((d)->des1 = ((d)->des1 & 0x03ffc000) | ((s) & 0x3fff))
+       ((d)->des1 = ((d)->des1 & 0x03ffe000) | ((s) & 0x1fff))
 
        u32             des2;   /* buffer 1 physical address */
 
@@ -699,7 +699,7 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        }
 
        /* DDR mode set */
-       if (ios->ddr) {
+       if (ios->timing == MMC_TIMING_UHS_DDR50) {
                regs = mci_readl(slot->host, UHS_REG);
                regs |= (0x1 << slot->id) << 16;
                mci_writel(slot->host, UHS_REG, regs);
@@ -1646,7 +1646,7 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
                        mmc->caps |= MMC_CAP_4_BIT_DATA;
 
        if (host->pdata->quirks & DW_MCI_QUIRK_HIGHSPEED)
-               mmc->caps |= MMC_CAP_SD_HIGHSPEED;
+               mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
 
 #ifdef CONFIG_MMC_DW_IDMAC
        mmc->max_segs = host->ring_size;
index 710b706..0e9780f 100644 (file)
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/sdio.h>
-#include <mach/hardware.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
 #include <mach/esdhc.h>
 #include "sdhci-pltfm.h"
 #include "sdhci-esdhc.h"
 
+#define        SDHCI_CTRL_D3CD                 0x08
 /* VENDOR SPEC register */
 #define SDHCI_VENDOR_SPEC              0xC0
 #define  SDHCI_VENDOR_SPEC_SDIO_QUIRK  0x00000002
 
-#define ESDHC_FLAG_GPIO_FOR_CD         (1 << 0)
 /*
  * The CMDTYPE of the CMD register (offset 0xE) should be set to
  * "11" when the STOP CMD12 is issued on imx53 to abort one
  */
 #define ESDHC_FLAG_MULTIBLK_NO_INT     (1 << 1)
 
+enum imx_esdhc_type {
+       IMX25_ESDHC,
+       IMX35_ESDHC,
+       IMX51_ESDHC,
+       IMX53_ESDHC,
+};
+
 struct pltfm_imx_data {
        int flags;
        u32 scratchpad;
+       enum imx_esdhc_type devtype;
+       struct esdhc_platform_data boarddata;
+};
+
+static struct platform_device_id imx_esdhc_devtype[] = {
+       {
+               .name = "sdhci-esdhc-imx25",
+               .driver_data = IMX25_ESDHC,
+       }, {
+               .name = "sdhci-esdhc-imx35",
+               .driver_data = IMX35_ESDHC,
+       }, {
+               .name = "sdhci-esdhc-imx51",
+               .driver_data = IMX51_ESDHC,
+       }, {
+               .name = "sdhci-esdhc-imx53",
+               .driver_data = IMX53_ESDHC,
+       }, {
+               /* sentinel */
+       }
 };
+MODULE_DEVICE_TABLE(platform, imx_esdhc_devtype);
+
+static const struct of_device_id imx_esdhc_dt_ids[] = {
+       { .compatible = "fsl,imx25-esdhc", .data = &imx_esdhc_devtype[IMX25_ESDHC], },
+       { .compatible = "fsl,imx35-esdhc", .data = &imx_esdhc_devtype[IMX35_ESDHC], },
+       { .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], },
+       { .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids);
+
+static inline int is_imx25_esdhc(struct pltfm_imx_data *data)
+{
+       return data->devtype == IMX25_ESDHC;
+}
+
+static inline int is_imx35_esdhc(struct pltfm_imx_data *data)
+{
+       return data->devtype == IMX35_ESDHC;
+}
+
+static inline int is_imx51_esdhc(struct pltfm_imx_data *data)
+{
+       return data->devtype == IMX51_ESDHC;
+}
+
+static inline int is_imx53_esdhc(struct pltfm_imx_data *data)
+{
+       return data->devtype == IMX53_ESDHC;
+}
 
 static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
 {
@@ -60,17 +119,14 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct pltfm_imx_data *imx_data = pltfm_host->priv;
+       struct esdhc_platform_data *boarddata = &imx_data->boarddata;
 
-       /* fake CARD_PRESENT flag on mx25/35 */
+       /* fake CARD_PRESENT flag */
        u32 val = readl(host->ioaddr + reg);
 
        if (unlikely((reg == SDHCI_PRESENT_STATE)
-                       && (imx_data->flags & ESDHC_FLAG_GPIO_FOR_CD))) {
-               struct esdhc_platform_data *boarddata =
-                               host->mmc->parent->platform_data;
-
-               if (boarddata && gpio_is_valid(boarddata->cd_gpio)
-                               && gpio_get_value(boarddata->cd_gpio))
+                       && gpio_is_valid(boarddata->cd_gpio))) {
+               if (gpio_get_value(boarddata->cd_gpio))
                        /* no card, if a valid gpio says so... */
                        val &= ~SDHCI_CARD_PRESENT;
                else
@@ -85,14 +141,33 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct pltfm_imx_data *imx_data = pltfm_host->priv;
-
-       if (unlikely((reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)
-                       && (imx_data->flags & ESDHC_FLAG_GPIO_FOR_CD)))
-               /*
-                * these interrupts won't work with a custom card_detect gpio
-                * (only applied to mx25/35)
-                */
-               val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT);
+       struct esdhc_platform_data *boarddata = &imx_data->boarddata;
+       u32 data;
+
+       if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) {
+               if (boarddata->cd_type == ESDHC_CD_GPIO)
+                       /*
+                        * These interrupts won't work with a custom
+                        * card_detect gpio (only applied to mx25/35)
+                        */
+                       val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT);
+
+               if (val & SDHCI_INT_CARD_INT) {
+                       /*
+                        * Clear and then set D3CD bit to avoid missing the
+                        * card interrupt.  This is a eSDHC controller problem
+                        * so we need to apply the following workaround: clear
+                        * and set D3CD bit will make eSDHC re-sample the card
+                        * interrupt. In case a card interrupt was lost,
+                        * re-sample it by the following steps.
+                        */
+                       data = readl(host->ioaddr + SDHCI_HOST_CONTROL);
+                       data &= ~SDHCI_CTRL_D3CD;
+                       writel(data, host->ioaddr + SDHCI_HOST_CONTROL);
+                       data |= SDHCI_CTRL_D3CD;
+                       writel(data, host->ioaddr + SDHCI_HOST_CONTROL);
+               }
+       }
 
        if (unlikely((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
                                && (reg == SDHCI_INT_STATUS)
@@ -162,8 +237,10 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
                 */
                return;
        case SDHCI_HOST_CONTROL:
-               /* FSL messed up here, so we can just keep those two */
-               new_val = val & (SDHCI_CTRL_LED | SDHCI_CTRL_4BITBUS);
+               /* FSL messed up here, so we can just keep those three */
+               new_val = val & (SDHCI_CTRL_LED | \
+                               SDHCI_CTRL_4BITBUS | \
+                               SDHCI_CTRL_D3CD);
                /* ensure the endianess */
                new_val |= ESDHC_HOST_CONTROL_LE;
                /* DMA mode bits are shifted */
@@ -173,6 +250,17 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
                return;
        }
        esdhc_clrset_le(host, 0xff, val, reg);
+
+       /*
+        * The esdhc has a design violation to SDHC spec which tells
+        * that software reset should not affect card detection circuit.
+        * But esdhc clears its SYSCTL register bits [0..2] during the
+        * software reset.  This will stop those clocks that card detection
+        * circuit relies on.  To work around it, we turn the clocks on back
+        * to keep card detection circuit functional.
+        */
+       if ((reg == SDHCI_SOFTWARE_RESET) && (val & 1))
+               esdhc_clrset_le(host, 0x7, 0x7, ESDHC_SYSTEM_CONTROL);
 }
 
 static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host)
@@ -189,6 +277,26 @@ static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
        return clk_get_rate(pltfm_host->clk) / 256 / 16;
 }
 
+static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct pltfm_imx_data *imx_data = pltfm_host->priv;
+       struct esdhc_platform_data *boarddata = &imx_data->boarddata;
+
+       switch (boarddata->wp_type) {
+       case ESDHC_WP_GPIO:
+               if (gpio_is_valid(boarddata->wp_gpio))
+                       return gpio_get_value(boarddata->wp_gpio);
+       case ESDHC_WP_CONTROLLER:
+               return !(readl(host->ioaddr + SDHCI_PRESENT_STATE) &
+                              SDHCI_WRITE_PROTECT);
+       case ESDHC_WP_NONE:
+               break;
+       }
+
+       return -ENOSYS;
+}
+
 static struct sdhci_ops sdhci_esdhc_ops = {
        .read_l = esdhc_readl_le,
        .read_w = esdhc_readw_le,
@@ -198,6 +306,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
        .set_clock = esdhc_set_clock,
        .get_max_clock = esdhc_pltfm_get_max_clock,
        .get_min_clock = esdhc_pltfm_get_min_clock,
+       .get_ro = esdhc_pltfm_get_ro,
 };
 
 static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
@@ -207,17 +316,6 @@ static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
        .ops = &sdhci_esdhc_ops,
 };
 
-static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
-{
-       struct esdhc_platform_data *boarddata =
-                       host->mmc->parent->platform_data;
-
-       if (boarddata && gpio_is_valid(boarddata->wp_gpio))
-               return gpio_get_value(boarddata->wp_gpio);
-       else
-               return -ENOSYS;
-}
-
 static irqreturn_t cd_irq(int irq, void *data)
 {
        struct sdhci_host *sdhost = (struct sdhci_host *)data;
@@ -226,8 +324,48 @@ static irqreturn_t cd_irq(int irq, void *data)
        return IRQ_HANDLED;
 };
 
+#ifdef CONFIG_OF
+static int __devinit
+sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
+                        struct esdhc_platform_data *boarddata)
+{
+       struct device_node *np = pdev->dev.of_node;
+
+       if (!np)
+               return -ENODEV;
+
+       if (of_get_property(np, "fsl,card-wired", NULL))
+               boarddata->cd_type = ESDHC_CD_PERMANENT;
+
+       if (of_get_property(np, "fsl,cd-controller", NULL))
+               boarddata->cd_type = ESDHC_CD_CONTROLLER;
+
+       if (of_get_property(np, "fsl,wp-controller", NULL))
+               boarddata->wp_type = ESDHC_WP_CONTROLLER;
+
+       boarddata->cd_gpio = of_get_named_gpio(np, "cd-gpios", 0);
+       if (gpio_is_valid(boarddata->cd_gpio))
+               boarddata->cd_type = ESDHC_CD_GPIO;
+
+       boarddata->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0);
+       if (gpio_is_valid(boarddata->wp_gpio))
+               boarddata->wp_type = ESDHC_WP_GPIO;
+
+       return 0;
+}
+#else
+static inline int
+sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
+                        struct esdhc_platform_data *boarddata)
+{
+       return -ENODEV;
+}
+#endif
+
 static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
 {
+       const struct of_device_id *of_id =
+                       of_match_device(imx_esdhc_dt_ids, &pdev->dev);
        struct sdhci_pltfm_host *pltfm_host;
        struct sdhci_host *host;
        struct esdhc_platform_data *boarddata;
@@ -242,8 +380,14 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
        pltfm_host = sdhci_priv(host);
 
        imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL);
-       if (!imx_data)
-               return -ENOMEM;
+       if (!imx_data) {
+               err = -ENOMEM;
+               goto err_imx_data;
+       }
+
+       if (of_id)
+               pdev->id_entry = of_id->data;
+       imx_data->devtype = pdev->id_entry->driver_data;
        pltfm_host->priv = imx_data;
 
        clk = clk_get(mmc_dev(host->mmc), NULL);
@@ -255,50 +399,72 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
        clk_enable(clk);
        pltfm_host->clk = clk;
 
-       if (!cpu_is_mx25())
+       if (!is_imx25_esdhc(imx_data))
                host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
 
-       if (cpu_is_mx25() || cpu_is_mx35()) {
+       if (is_imx25_esdhc(imx_data) || is_imx35_esdhc(imx_data))
                /* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */
                host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK;
-               /* write_protect can't be routed to controller, use gpio */
-               sdhci_esdhc_ops.get_ro = esdhc_pltfm_get_ro;
-       }
 
-       if (!(cpu_is_mx25() || cpu_is_mx35() || cpu_is_mx51()))
+       if (is_imx53_esdhc(imx_data))
                imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT;
 
-       boarddata = host->mmc->parent->platform_data;
-       if (boarddata) {
+       boarddata = &imx_data->boarddata;
+       if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) {
+               if (!host->mmc->parent->platform_data) {
+                       dev_err(mmc_dev(host->mmc), "no board data!\n");
+                       err = -EINVAL;
+                       goto no_board_data;
+               }
+               imx_data->boarddata = *((struct esdhc_platform_data *)
+                                       host->mmc->parent->platform_data);
+       }
+
+       /* write_protect */
+       if (boarddata->wp_type == ESDHC_WP_GPIO) {
                err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP");
                if (err) {
                        dev_warn(mmc_dev(host->mmc),
-                               "no write-protect pin available!\n");
-                       boarddata->wp_gpio = err;
+                                "no write-protect pin available!\n");
+                       boarddata->wp_gpio = -EINVAL;
                }
+       } else {
+               boarddata->wp_gpio = -EINVAL;
+       }
 
+       /* card_detect */
+       if (boarddata->cd_type != ESDHC_CD_GPIO)
+               boarddata->cd_gpio = -EINVAL;
+
+       switch (boarddata->cd_type) {
+       case ESDHC_CD_GPIO:
                err = gpio_request_one(boarddata->cd_gpio, GPIOF_IN, "ESDHC_CD");
                if (err) {
-                       dev_warn(mmc_dev(host->mmc),
+                       dev_err(mmc_dev(host->mmc),
                                "no card-detect pin available!\n");
                        goto no_card_detect_pin;
                }
 
-               /* i.MX5x has issues to be researched */
-               if (!cpu_is_mx25() && !cpu_is_mx35())
-                       goto not_supported;
-
                err = request_irq(gpio_to_irq(boarddata->cd_gpio), cd_irq,
                                 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
                                 mmc_hostname(host->mmc), host);
                if (err) {
-                       dev_warn(mmc_dev(host->mmc), "request irq error\n");
+                       dev_err(mmc_dev(host->mmc), "request irq error\n");
                        goto no_card_detect_irq;
                }
+               /* fall through */
 
-               imx_data->flags |= ESDHC_FLAG_GPIO_FOR_CD;
-               /* Now we have a working card_detect again */
+       case ESDHC_CD_CONTROLLER:
+               /* we have a working card_detect back */
                host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
+               break;
+
+       case ESDHC_CD_PERMANENT:
+               host->mmc->caps = MMC_CAP_NONREMOVABLE;
+               break;
+
+       case ESDHC_CD_NONE:
+               break;
        }
 
        err = sdhci_add_host(host);
@@ -307,16 +473,21 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
 
        return 0;
 
- no_card_detect_irq:
-       gpio_free(boarddata->cd_gpio);
- no_card_detect_pin:
-       boarddata->cd_gpio = err;
- not_supported:
-       kfree(imx_data);
- err_add_host:
+err_add_host:
+       if (gpio_is_valid(boarddata->cd_gpio))
+               free_irq(gpio_to_irq(boarddata->cd_gpio), host);
+no_card_detect_irq:
+       if (gpio_is_valid(boarddata->cd_gpio))
+               gpio_free(boarddata->cd_gpio);
+       if (gpio_is_valid(boarddata->wp_gpio))
+               gpio_free(boarddata->wp_gpio);
+no_card_detect_pin:
+no_board_data:
        clk_disable(pltfm_host->clk);
        clk_put(pltfm_host->clk);
- err_clk_get:
+err_clk_get:
+       kfree(imx_data);
+err_imx_data:
        sdhci_pltfm_free(pdev);
        return err;
 }
@@ -325,20 +496,18 @@ static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev)
 {
        struct sdhci_host *host = platform_get_drvdata(pdev);
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-       struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
        struct pltfm_imx_data *imx_data = pltfm_host->priv;
+       struct esdhc_platform_data *boarddata = &imx_data->boarddata;
        int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
 
        sdhci_remove_host(host, dead);
 
-       if (boarddata && gpio_is_valid(boarddata->wp_gpio))
+       if (gpio_is_valid(boarddata->wp_gpio))
                gpio_free(boarddata->wp_gpio);
 
-       if (boarddata && gpio_is_valid(boarddata->cd_gpio)) {
+       if (gpio_is_valid(boarddata->cd_gpio)) {
+               free_irq(gpio_to_irq(boarddata->cd_gpio), host);
                gpio_free(boarddata->cd_gpio);
-
-               if (!(host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION))
-                       free_irq(gpio_to_irq(boarddata->cd_gpio), host);
        }
 
        clk_disable(pltfm_host->clk);
@@ -354,7 +523,9 @@ static struct platform_driver sdhci_esdhc_imx_driver = {
        .driver         = {
                .name   = "sdhci-esdhc-imx",
                .owner  = THIS_MODULE,
+               .of_match_table = imx_esdhc_dt_ids,
        },
+       .id_table       = imx_esdhc_devtype,
        .probe          = sdhci_esdhc_imx_probe,
        .remove         = __devexit_p(sdhci_esdhc_imx_remove),
 #ifdef CONFIG_PM
index 71c0ce1..6414efe 100644 (file)
@@ -85,6 +85,7 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
 {
        struct sdhci_host *host;
        struct sdhci_pltfm_host *pltfm_host;
+       struct device_node *np = pdev->dev.of_node;
        struct resource *iomem;
        int ret;
 
@@ -98,7 +99,7 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
                dev_err(&pdev->dev, "Invalid iomem size!\n");
 
        /* Some PCI-based MFD need the parent here */
-       if (pdev->dev.parent != &platform_bus)
+       if (pdev->dev.parent != &platform_bus && !np)
                host = sdhci_alloc_host(pdev->dev.parent, sizeof(*pltfm_host));
        else
                host = sdhci_alloc_host(&pdev->dev, sizeof(*pltfm_host));
index 4198dbb..fc7e4a5 100644 (file)
@@ -195,7 +195,8 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
        clk_enable(clk);
 
        host->quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
-               | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC;
+               | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
+               | SDHCI_QUIRK_32BIT_ADMA_SIZE;
 
        /* enable 1/8V DDR capable */
        host->mmc->caps |= MMC_CAP_1_8V_DDR;
index 460ffaf..2bd7bf4 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
+#include <linux/module.h>
 
 #include <linux/mmc/host.h>
 
@@ -502,6 +503,9 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
        /* This host supports the Auto CMD12 */
        host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
 
+       /* Samsung SoCs need BROKEN_ADMA_ZEROLEN_DESC */
+       host->quirks |= SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC;
+
        if (pdata->cd_type == S3C_SDHCI_CD_NONE ||
            pdata->cd_type == S3C_SDHCI_CD_PERMANENT)
                host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
index c31a334..0e02cc1 100644 (file)
@@ -628,12 +628,11 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
        /* timeout in us */
        if (!data)
                target_timeout = cmd->cmd_timeout_ms * 1000;
-       else
-               target_timeout = data->timeout_ns / 1000 +
-                       data->timeout_clks / host->clock;
-
-       if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
-               host->timeout_clk = host->clock / 1000;
+       else {
+               target_timeout = data->timeout_ns / 1000;
+               if (host->clock)
+                       target_timeout += data->timeout_clks / host->clock;
+       }
 
        /*
         * Figure out needed cycles.
@@ -645,7 +644,6 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
         *     =>
         *     (1) / (2) > 2^6
         */
-       BUG_ON(!host->timeout_clk);
        count = 0;
        current_timeout = (1 << 13) * 1000 / host->timeout_clk;
        while (current_timeout < target_timeout) {
@@ -1867,9 +1865,6 @@ static void sdhci_tasklet_finish(unsigned long param)
 
        del_timer(&host->timer);
 
-       if (host->version >= SDHCI_SPEC_300)
-               del_timer(&host->tuning_timer);
-
        mrq = host->mrq;
 
        /*
@@ -2461,22 +2456,6 @@ int sdhci_add_host(struct sdhci_host *host)
                host->max_clk = host->ops->get_max_clock(host);
        }
 
-       host->timeout_clk =
-               (caps[0] & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
-       if (host->timeout_clk == 0) {
-               if (host->ops->get_timeout_clock) {
-                       host->timeout_clk = host->ops->get_timeout_clock(host);
-               } else if (!(host->quirks &
-                               SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
-                       printk(KERN_ERR
-                              "%s: Hardware doesn't specify timeout clock "
-                              "frequency.\n", mmc_hostname(mmc));
-                       return -ENODEV;
-               }
-       }
-       if (caps[0] & SDHCI_TIMEOUT_CLK_UNIT)
-               host->timeout_clk *= 1000;
-
        /*
         * In case of Host Controller v3.00, find out whether clock
         * multiplier is supported.
@@ -2509,10 +2488,26 @@ int sdhci_add_host(struct sdhci_host *host)
        } else
                mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
 
+       host->timeout_clk =
+               (caps[0] & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
+       if (host->timeout_clk == 0) {
+               if (host->ops->get_timeout_clock) {
+                       host->timeout_clk = host->ops->get_timeout_clock(host);
+               } else if (!(host->quirks &
+                               SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
+                       printk(KERN_ERR
+                              "%s: Hardware doesn't specify timeout clock "
+                              "frequency.\n", mmc_hostname(mmc));
+                       return -ENODEV;
+               }
+       }
+       if (caps[0] & SDHCI_TIMEOUT_CLK_UNIT)
+               host->timeout_clk *= 1000;
+
        if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
-               mmc->max_discard_to = (1 << 27) / (mmc->f_max / 1000);
-       else
-               mmc->max_discard_to = (1 << 27) / host->timeout_clk;
+               host->timeout_clk = mmc->f_max / 1000;
+
+       mmc->max_discard_to = (1 << 27) / host->timeout_clk;
 
        mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
 
index 8d185de..44a9668 100644 (file)
@@ -27,7 +27,6 @@
 static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state)
 {
        const struct mfd_cell *cell = mfd_get_cell(dev);
-       struct mmc_host *mmc = platform_get_drvdata(dev);
        int ret;
 
        ret = tmio_mmc_host_suspend(&dev->dev);
@@ -42,7 +41,6 @@ static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state)
 static int tmio_mmc_resume(struct platform_device *dev)
 {
        const struct mfd_cell *cell = mfd_get_cell(dev);
-       struct mmc_host *mmc = platform_get_drvdata(dev);
        int ret = 0;
 
        /* Tell the MFD core we are ready to be enabled */
index c423504..e46df53 100644 (file)
@@ -315,6 +315,14 @@ union db_prod {
        u32             raw;
 };
 
+/* dropless fc FW/HW related params */
+#define BRB_SIZE(bp)           (CHIP_IS_E3(bp) ? 1024 : 512)
+#define MAX_AGG_QS(bp)         (CHIP_IS_E1(bp) ? \
+                                       ETH_MAX_AGGREGATION_QUEUES_E1 :\
+                                       ETH_MAX_AGGREGATION_QUEUES_E1H_E2)
+#define FW_DROP_LEVEL(bp)      (3 + MAX_SPQ_PENDING + MAX_AGG_QS(bp))
+#define FW_PREFETCH_CNT                16
+#define DROPLESS_FC_HEADROOM   100
 
 /* MC hsi */
 #define BCM_PAGE_SHIFT         12
@@ -331,15 +339,35 @@ union db_prod {
 /* SGE ring related macros */
 #define NUM_RX_SGE_PAGES       2
 #define RX_SGE_CNT             (BCM_PAGE_SIZE / sizeof(struct eth_rx_sge))
-#define MAX_RX_SGE_CNT         (RX_SGE_CNT - 2)
+#define NEXT_PAGE_SGE_DESC_CNT 2
+#define MAX_RX_SGE_CNT         (RX_SGE_CNT - NEXT_PAGE_SGE_DESC_CNT)
 /* RX_SGE_CNT is promised to be a power of 2 */
 #define RX_SGE_MASK            (RX_SGE_CNT - 1)
 #define NUM_RX_SGE             (RX_SGE_CNT * NUM_RX_SGE_PAGES)
 #define MAX_RX_SGE             (NUM_RX_SGE - 1)
 #define NEXT_SGE_IDX(x)                ((((x) & RX_SGE_MASK) == \
-                                 (MAX_RX_SGE_CNT - 1)) ? (x) + 3 : (x) + 1)
+                                 (MAX_RX_SGE_CNT - 1)) ? \
+                                       (x) + 1 + NEXT_PAGE_SGE_DESC_CNT : \
+                                       (x) + 1)
 #define RX_SGE(x)              ((x) & MAX_RX_SGE)
 
+/*
+ * Number of required  SGEs is the sum of two:
+ * 1. Number of possible opened aggregations (next packet for
+ *    these aggregations will probably consume SGE immidiatelly)
+ * 2. Rest of BRB blocks divided by 2 (block will consume new SGE only
+ *    after placement on BD for new TPA aggregation)
+ *
+ * Takes into account NEXT_PAGE_SGE_DESC_CNT "next" elements on each page
+ */
+#define NUM_SGE_REQ            (MAX_AGG_QS(bp) + \
+                                       (BRB_SIZE(bp) - MAX_AGG_QS(bp)) / 2)
+#define NUM_SGE_PG_REQ         ((NUM_SGE_REQ + MAX_RX_SGE_CNT - 1) / \
+                                               MAX_RX_SGE_CNT)
+#define SGE_TH_LO(bp)          (NUM_SGE_REQ + \
+                                NUM_SGE_PG_REQ * NEXT_PAGE_SGE_DESC_CNT)
+#define SGE_TH_HI(bp)          (SGE_TH_LO(bp) + DROPLESS_FC_HEADROOM)
+
 /* Manipulate a bit vector defined as an array of u64 */
 
 /* Number of bits in one sge_mask array element */
@@ -551,24 +579,43 @@ struct bnx2x_fastpath {
 
 #define NUM_TX_RINGS           16
 #define TX_DESC_CNT            (BCM_PAGE_SIZE / sizeof(union eth_tx_bd_types))
-#define MAX_TX_DESC_CNT                (TX_DESC_CNT - 1)
+#define NEXT_PAGE_TX_DESC_CNT  1
+#define MAX_TX_DESC_CNT                (TX_DESC_CNT - NEXT_PAGE_TX_DESC_CNT)
 #define NUM_TX_BD              (TX_DESC_CNT * NUM_TX_RINGS)
 #define MAX_TX_BD              (NUM_TX_BD - 1)
 #define MAX_TX_AVAIL           (MAX_TX_DESC_CNT * NUM_TX_RINGS - 2)
 #define NEXT_TX_IDX(x)         ((((x) & MAX_TX_DESC_CNT) == \
-                                 (MAX_TX_DESC_CNT - 1)) ? (x) + 2 : (x) + 1)
+                                 (MAX_TX_DESC_CNT - 1)) ? \
+                                       (x) + 1 + NEXT_PAGE_TX_DESC_CNT : \
+                                       (x) + 1)
 #define TX_BD(x)               ((x) & MAX_TX_BD)
 #define TX_BD_POFF(x)          ((x) & MAX_TX_DESC_CNT)
 
 /* The RX BD ring is special, each bd is 8 bytes but the last one is 16 */
 #define NUM_RX_RINGS           8
 #define RX_DESC_CNT            (BCM_PAGE_SIZE / sizeof(struct eth_rx_bd))
-#define MAX_RX_DESC_CNT                (RX_DESC_CNT - 2)
+#define NEXT_PAGE_RX_DESC_CNT  2
+#define MAX_RX_DESC_CNT                (RX_DESC_CNT - NEXT_PAGE_RX_DESC_CNT)
 #define RX_DESC_MASK           (RX_DESC_CNT - 1)
 #define NUM_RX_BD              (RX_DESC_CNT * NUM_RX_RINGS)
 #define MAX_RX_BD              (NUM_RX_BD - 1)
 #define MAX_RX_AVAIL           (MAX_RX_DESC_CNT * NUM_RX_RINGS - 2)
-#define MIN_RX_AVAIL           128
+
+/* dropless fc calculations for BDs
+ *
+ * Number of BDs should as number of buffers in BRB:
+ * Low threshold takes into account NEXT_PAGE_RX_DESC_CNT
+ * "next" elements on each page
+ */
+#define NUM_BD_REQ             BRB_SIZE(bp)
+#define NUM_BD_PG_REQ          ((NUM_BD_REQ + MAX_RX_DESC_CNT - 1) / \
+                                             MAX_RX_DESC_CNT)
+#define BD_TH_LO(bp)           (NUM_BD_REQ + \
+                                NUM_BD_PG_REQ * NEXT_PAGE_RX_DESC_CNT + \
+                                FW_DROP_LEVEL(bp))
+#define BD_TH_HI(bp)           (BD_TH_LO(bp) + DROPLESS_FC_HEADROOM)
+
+#define MIN_RX_AVAIL           ((bp)->dropless_fc ? BD_TH_HI(bp) + 128 : 128)
 
 #define MIN_RX_SIZE_TPA_HW     (CHIP_IS_E1(bp) ? \
                                        ETH_MIN_RX_CQES_WITH_TPA_E1 : \
@@ -579,7 +626,9 @@ struct bnx2x_fastpath {
                                                                MIN_RX_AVAIL))
 
 #define NEXT_RX_IDX(x)         ((((x) & RX_DESC_MASK) == \
-                                 (MAX_RX_DESC_CNT - 1)) ? (x) + 3 : (x) + 1)
+                                 (MAX_RX_DESC_CNT - 1)) ? \
+                                       (x) + 1 + NEXT_PAGE_RX_DESC_CNT : \
+                                       (x) + 1)
 #define RX_BD(x)               ((x) & MAX_RX_BD)
 
 /*
@@ -589,14 +638,31 @@ struct bnx2x_fastpath {
 #define CQE_BD_REL     (sizeof(union eth_rx_cqe) / sizeof(struct eth_rx_bd))
 #define NUM_RCQ_RINGS          (NUM_RX_RINGS * CQE_BD_REL)
 #define RCQ_DESC_CNT           (BCM_PAGE_SIZE / sizeof(union eth_rx_cqe))
-#define MAX_RCQ_DESC_CNT       (RCQ_DESC_CNT - 1)
+#define NEXT_PAGE_RCQ_DESC_CNT 1
+#define MAX_RCQ_DESC_CNT       (RCQ_DESC_CNT - NEXT_PAGE_RCQ_DESC_CNT)
 #define NUM_RCQ_BD             (RCQ_DESC_CNT * NUM_RCQ_RINGS)
 #define MAX_RCQ_BD             (NUM_RCQ_BD - 1)
 #define MAX_RCQ_AVAIL          (MAX_RCQ_DESC_CNT * NUM_RCQ_RINGS - 2)
 #define NEXT_RCQ_IDX(x)                ((((x) & MAX_RCQ_DESC_CNT) == \
-                                 (MAX_RCQ_DESC_CNT - 1)) ? (x) + 2 : (x) + 1)
+                                 (MAX_RCQ_DESC_CNT - 1)) ? \
+                                       (x) + 1 + NEXT_PAGE_RCQ_DESC_CNT : \
+                                       (x) + 1)
 #define RCQ_BD(x)              ((x) & MAX_RCQ_BD)
 
+/* dropless fc calculations for RCQs
+ *
+ * Number of RCQs should be as number of buffers in BRB:
+ * Low threshold takes into account NEXT_PAGE_RCQ_DESC_CNT
+ * "next" elements on each page
+ */
+#define NUM_RCQ_REQ            BRB_SIZE(bp)
+#define NUM_RCQ_PG_REQ         ((NUM_BD_REQ + MAX_RCQ_DESC_CNT - 1) / \
+                                             MAX_RCQ_DESC_CNT)
+#define RCQ_TH_LO(bp)          (NUM_RCQ_REQ + \
+                                NUM_RCQ_PG_REQ * NEXT_PAGE_RCQ_DESC_CNT + \
+                                FW_DROP_LEVEL(bp))
+#define RCQ_TH_HI(bp)          (RCQ_TH_LO(bp) + DROPLESS_FC_HEADROOM)
+
 
 /* This is needed for determining of last_max */
 #define SUB_S16(a, b)          (s16)((s16)(a) - (s16)(b))
@@ -685,24 +751,17 @@ struct bnx2x_fastpath {
 #define FP_CSB_FUNC_OFF        \
                        offsetof(struct cstorm_status_block_c, func)
 
-#define HC_INDEX_TOE_RX_CQ_CONS                0 /* Formerly Ustorm TOE CQ index */
-                                         /* (HC_INDEX_U_TOE_RX_CQ_CONS)  */
-#define HC_INDEX_ETH_RX_CQ_CONS                1 /* Formerly Ustorm ETH CQ index */
-                                         /* (HC_INDEX_U_ETH_RX_CQ_CONS)  */
-#define HC_INDEX_ETH_RX_BD_CONS                2 /* Formerly Ustorm ETH BD index */
-                                         /* (HC_INDEX_U_ETH_RX_BD_CONS)  */
-
-#define HC_INDEX_TOE_TX_CQ_CONS                4 /* Formerly Cstorm TOE CQ index   */
-                                         /* (HC_INDEX_C_TOE_TX_CQ_CONS)    */
-#define HC_INDEX_ETH_TX_CQ_CONS_COS0   5 /* Formerly Cstorm ETH CQ index   */
-                                         /* (HC_INDEX_C_ETH_TX_CQ_CONS)    */
-#define HC_INDEX_ETH_TX_CQ_CONS_COS1   6 /* Formerly Cstorm ETH CQ index   */
-                                         /* (HC_INDEX_C_ETH_TX_CQ_CONS)    */
-#define HC_INDEX_ETH_TX_CQ_CONS_COS2   7 /* Formerly Cstorm ETH CQ index   */
-                                         /* (HC_INDEX_C_ETH_TX_CQ_CONS)    */
+#define HC_INDEX_ETH_RX_CQ_CONS                1
 
-#define HC_INDEX_ETH_FIRST_TX_CQ_CONS  HC_INDEX_ETH_TX_CQ_CONS_COS0
+#define HC_INDEX_OOO_TX_CQ_CONS                4
 
+#define HC_INDEX_ETH_TX_CQ_CONS_COS0   5
+
+#define HC_INDEX_ETH_TX_CQ_CONS_COS1   6
+
+#define HC_INDEX_ETH_TX_CQ_CONS_COS2   7
+
+#define HC_INDEX_ETH_FIRST_TX_CQ_CONS  HC_INDEX_ETH_TX_CQ_CONS_COS0
 
 #define BNX2X_RX_SB_INDEX \
        (&fp->sb_index_values[HC_INDEX_ETH_RX_CQ_CONS])
@@ -1100,11 +1159,12 @@ struct bnx2x {
 #define BP_PORT(bp)                    (bp->pfid & 1)
 #define BP_FUNC(bp)                    (bp->pfid)
 #define BP_ABS_FUNC(bp)                        (bp->pf_num)
-#define BP_E1HVN(bp)                   (bp->pfid >> 1)
-#define BP_VN(bp)                      (BP_E1HVN(bp)) /*remove when approved*/
-#define BP_L_ID(bp)                    (BP_E1HVN(bp) << 2)
-#define BP_FW_MB_IDX(bp)               (BP_PORT(bp) +\
-         BP_VN(bp) * ((CHIP_IS_E1x(bp) || (CHIP_MODE_IS_4_PORT(bp))) ? 2  : 1))
+#define BP_VN(bp)                      ((bp)->pfid >> 1)
+#define BP_MAX_VN_NUM(bp)              (CHIP_MODE_IS_4_PORT(bp) ? 2 : 4)
+#define BP_L_ID(bp)                    (BP_VN(bp) << 2)
+#define BP_FW_MB_IDX_VN(bp, vn)                (BP_PORT(bp) +\
+         (vn) * ((CHIP_IS_E1x(bp) || (CHIP_MODE_IS_4_PORT(bp))) ? 2  : 1))
+#define BP_FW_MB_IDX(bp)               BP_FW_MB_IDX_VN(bp, BP_VN(bp))
 
        struct net_device       *dev;
        struct pci_dev          *pdev;
@@ -1767,7 +1827,7 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
 
 #define MAX_DMAE_C_PER_PORT            8
 #define INIT_DMAE_C(bp)                        (BP_PORT(bp) * MAX_DMAE_C_PER_PORT + \
-                                        BP_E1HVN(bp))
+                                        BP_VN(bp))
 #define PMF_DMAE_C(bp)                 (BP_PORT(bp) * MAX_DMAE_C_PER_PORT + \
                                         E1HVN_MAX)
 
@@ -1793,7 +1853,7 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
 
 /* must be used on a CID before placing it on a HW ring */
 #define HW_CID(bp, x)                  ((BP_PORT(bp) << 23) | \
-                                        (BP_E1HVN(bp) << BNX2X_SWCID_SHIFT) | \
+                                        (BP_VN(bp) << BNX2X_SWCID_SHIFT) | \
                                         (x))
 
 #define SP_DESC_CNT            (BCM_PAGE_SIZE / sizeof(struct eth_spe))
index 5b0dba6..c4cbf97 100644 (file)
@@ -63,8 +63,9 @@ static inline void bnx2x_bz_fp(struct bnx2x *bp, int index)
        fp->disable_tpa = ((bp->flags & TPA_ENABLE_FLAG) == 0);
 
 #ifdef BCM_CNIC
-       /* We don't want TPA on FCoE, FWD and OOO L2 rings */
-       bnx2x_fcoe(bp, disable_tpa) = 1;
+       /* We don't want TPA on an FCoE L2 ring */
+       if (IS_FCOE_FP(fp))
+               fp->disable_tpa = 1;
 #endif
 }
 
@@ -986,8 +987,6 @@ void __bnx2x_link_report(struct bnx2x *bp)
 void bnx2x_init_rx_rings(struct bnx2x *bp)
 {
        int func = BP_FUNC(bp);
-       int max_agg_queues = CHIP_IS_E1(bp) ? ETH_MAX_AGGREGATION_QUEUES_E1 :
-                                             ETH_MAX_AGGREGATION_QUEUES_E1H_E2;
        u16 ring_prod;
        int i, j;
 
@@ -1000,7 +999,7 @@ void bnx2x_init_rx_rings(struct bnx2x *bp)
 
                if (!fp->disable_tpa) {
                        /* Fill the per-aggregtion pool */
-                       for (i = 0; i < max_agg_queues; i++) {
+                       for (i = 0; i < MAX_AGG_QS(bp); i++) {
                                struct bnx2x_agg_info *tpa_info =
                                        &fp->tpa_info[i];
                                struct sw_rx_bd *first_buf =
@@ -1040,7 +1039,7 @@ void bnx2x_init_rx_rings(struct bnx2x *bp)
                                        bnx2x_free_rx_sge_range(bp, fp,
                                                                ring_prod);
                                        bnx2x_free_tpa_pool(bp, fp,
-                                                           max_agg_queues);
+                                                           MAX_AGG_QS(bp));
                                        fp->disable_tpa = 1;
                                        ring_prod = 0;
                                        break;
@@ -1136,9 +1135,7 @@ static void bnx2x_free_rx_skbs(struct bnx2x *bp)
                bnx2x_free_rx_bds(fp);
 
                if (!fp->disable_tpa)
-                       bnx2x_free_tpa_pool(bp, fp, CHIP_IS_E1(bp) ?
-                                           ETH_MAX_AGGREGATION_QUEUES_E1 :
-                                           ETH_MAX_AGGREGATION_QUEUES_E1H_E2);
+                       bnx2x_free_tpa_pool(bp, fp, MAX_AGG_QS(bp));
        }
 }
 
@@ -1404,10 +1401,9 @@ void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw)
 u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb)
 {
        struct bnx2x *bp = netdev_priv(dev);
+
 #ifdef BCM_CNIC
-       if (NO_FCOE(bp))
-               return skb_tx_hash(dev, skb);
-       else {
+       if (!NO_FCOE(bp)) {
                struct ethhdr *hdr = (struct ethhdr *)skb->data;
                u16 ether_type = ntohs(hdr->h_proto);
 
@@ -1424,8 +1420,7 @@ u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb)
                        return bnx2x_fcoe_tx(bp, txq_index);
        }
 #endif
-       /* Select a none-FCoE queue:  if FCoE is enabled, exclude FCoE L2 ring
-        */
+       /* select a non-FCoE queue */
        return __skb_tx_hash(dev, skb, BNX2X_NUM_ETH_QUEUES(bp));
 }
 
@@ -1448,6 +1443,28 @@ void bnx2x_set_num_queues(struct bnx2x *bp)
        bp->num_queues += NON_ETH_CONTEXT_USE;
 }
 
+/**
+ * bnx2x_set_real_num_queues - configure netdev->real_num_[tx,rx]_queues
+ *
+ * @bp:                Driver handle
+ *
+ * We currently support for at most 16 Tx queues for each CoS thus we will
+ * allocate a multiple of 16 for ETH L2 rings according to the value of the
+ * bp->max_cos.
+ *
+ * If there is an FCoE L2 queue the appropriate Tx queue will have the next
+ * index after all ETH L2 indices.
+ *
+ * If the actual number of Tx queues (for each CoS) is less than 16 then there
+ * will be the holes at the end of each group of 16 ETh L2 indices (0..15,
+ * 16..31,...) with indicies that are not coupled with any real Tx queue.
+ *
+ * The proper configuration of skb->queue_mapping is handled by
+ * bnx2x_select_queue() and __skb_tx_hash().
+ *
+ * bnx2x_setup_tc() takes care of the proper TC mappings so that __skb_tx_hash()
+ * will return a proper Tx index if TC is enabled (netdev->num_tc > 0).
+ */
 static inline int bnx2x_set_real_num_queues(struct bnx2x *bp)
 {
        int rc, tx, rx;
@@ -1989,14 +2006,20 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
                return -EINVAL;
        }
 
+       /*
+        * It's important to set the bp->state to the value different from
+        * BNX2X_STATE_OPEN and only then stop the Tx. Otherwise bnx2x_tx_int()
+        * may restart the Tx from the NAPI context (see bnx2x_tx_int()).
+        */
+       bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT;
+       smp_mb();
+
        /* Stop Tx */
        bnx2x_tx_disable(bp);
 
 #ifdef BCM_CNIC
        bnx2x_cnic_notify(bp, CNIC_CTL_STOP_CMD);
 #endif
-       bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT;
-       smp_mb();
 
        bp->rx_mode = BNX2X_RX_MODE_NONE;
 
@@ -3068,15 +3091,20 @@ static int bnx2x_alloc_fp_mem_at(struct bnx2x *bp, int index)
        struct bnx2x_fastpath *fp = &bp->fp[index];
        int ring_size = 0;
        u8 cos;
+       int rx_ring_size = 0;
 
        /* if rx_ring_size specified - use it */
-       int rx_ring_size = bp->rx_ring_size ? bp->rx_ring_size :
-                          MAX_RX_AVAIL/BNX2X_NUM_RX_QUEUES(bp);
+       if (!bp->rx_ring_size) {
+
+               rx_ring_size = MAX_RX_AVAIL/BNX2X_NUM_RX_QUEUES(bp);
 
-       /* allocate at least number of buffers required by FW */
-       rx_ring_size = max_t(int, bp->disable_tpa ? MIN_RX_SIZE_NONTPA :
-                                                   MIN_RX_SIZE_TPA,
-                                 rx_ring_size);
+               /* allocate at least number of buffers required by FW */
+               rx_ring_size = max_t(int, bp->disable_tpa ? MIN_RX_SIZE_NONTPA :
+                                    MIN_RX_SIZE_TPA, rx_ring_size);
+
+               bp->rx_ring_size = rx_ring_size;
+       } else
+               rx_ring_size = bp->rx_ring_size;
 
        /* Common */
        sb = &bnx2x_fp(bp, index, status_blk);
index a4ea35f..a1e004a 100644 (file)
@@ -920,7 +920,7 @@ static void bnx2x_dcbx_admin_mib_updated_params(struct bnx2x *bp,
 
 void bnx2x_dcbx_set_state(struct bnx2x *bp, bool dcb_on, u32 dcbx_enabled)
 {
-       if (!CHIP_IS_E1x(bp)) {
+       if (!CHIP_IS_E1x(bp) && !CHIP_IS_E3(bp)) {
                bp->dcb_state = dcb_on;
                bp->dcbx_enabled = dcbx_enabled;
        } else {
index 2218630..0ceb6c7 100644 (file)
@@ -1310,10 +1310,7 @@ static void bnx2x_get_ringparam(struct net_device *dev,
        if (bp->rx_ring_size)
                ering->rx_pending = bp->rx_ring_size;
        else
-               if (bp->state == BNX2X_STATE_OPEN && bp->num_queues)
-                       ering->rx_pending = MAX_RX_AVAIL/bp->num_queues;
-               else
-                       ering->rx_pending = MAX_RX_AVAIL;
+               ering->rx_pending = MAX_RX_AVAIL;
 
        ering->rx_mini_pending = 0;
        ering->rx_jumbo_pending = 0;
index 06727f3..dc24de4 100644 (file)
@@ -1204,6 +1204,8 @@ struct drv_port_mb {
 
        #define LINK_STATUS_PFC_ENABLED                         0x20000000
 
+       #define LINK_STATUS_PHYSICAL_LINK_FLAG                  0x40000000
+
        u32 port_stx;
 
        u32 stat_nig_timer;
index bcd8f00..d45b155 100644 (file)
@@ -1546,6 +1546,12 @@ static void bnx2x_umac_enable(struct link_params *params,
                               vars->line_speed);
                break;
        }
+       if (!(vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
+               val |= UMAC_COMMAND_CONFIG_REG_IGNORE_TX_PAUSE;
+
+       if (!(vars->flow_ctrl & BNX2X_FLOW_CTRL_RX))
+               val |= UMAC_COMMAND_CONFIG_REG_PAUSE_IGNORE;
+
        REG_WR(bp, umac_base + UMAC_REG_COMMAND_CONFIG, val);
        udelay(50);
 
@@ -1661,10 +1667,20 @@ static void bnx2x_xmac_disable(struct link_params *params)
 {
        u8 port = params->port;
        struct bnx2x *bp = params->bp;
-       u32 xmac_base = (port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0;
+       u32 pfc_ctrl, xmac_base = (port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0;
 
        if (REG_RD(bp, MISC_REG_RESET_REG_2) &
            MISC_REGISTERS_RESET_REG_2_XMAC) {
+               /*
+                * Send an indication to change the state in the NIG back to XON
+                * Clearing this bit enables the next set of this bit to get
+                * rising edge
+                */
+               pfc_ctrl = REG_RD(bp, xmac_base + XMAC_REG_PFC_CTRL_HI);
+               REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL_HI,
+                      (pfc_ctrl & ~(1<<1)));
+               REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL_HI,
+                      (pfc_ctrl | (1<<1)));
                DP(NETIF_MSG_LINK, "Disable XMAC on port %x\n", port);
                REG_WR(bp, xmac_base + XMAC_REG_CTRL, 0);
                usleep_range(1000, 1000);
@@ -1729,6 +1745,10 @@ static int bnx2x_emac_enable(struct link_params *params,
 
        DP(NETIF_MSG_LINK, "enabling EMAC\n");
 
+       /* Disable BMAC */
+       REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
+              (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
+
        /* enable emac and not bmac */
        REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1);
 
@@ -2583,12 +2603,6 @@ static int bnx2x_bmac1_enable(struct link_params *params,
        REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
                    wb_data, 2);
 
-       if (vars->phy_flags & PHY_TX_ERROR_CHECK_FLAG) {
-               REG_RD_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LSS_STATUS,
-                           wb_data, 2);
-               if (wb_data[0] > 0)
-                       return -ESRCH;
-       }
        return 0;
 }
 
@@ -2654,16 +2668,6 @@ static int bnx2x_bmac2_enable(struct link_params *params,
        udelay(30);
        bnx2x_update_pfc_bmac2(params, vars, is_lb);
 
-       if (vars->phy_flags & PHY_TX_ERROR_CHECK_FLAG) {
-               REG_RD_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_LSS_STAT,
-                           wb_data, 2);
-               if (wb_data[0] > 0) {
-                       DP(NETIF_MSG_LINK, "Got bad LSS status 0x%x\n",
-                                      wb_data[0]);
-                       return -ESRCH;
-               }
-       }
-
        return 0;
 }
 
@@ -2949,7 +2953,9 @@ static int bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy,
        u32 val;
        u16 i;
        int rc = 0;
-
+       if (phy->flags & FLAGS_MDC_MDIO_WA_B0)
+               bnx2x_bits_en(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_STATUS,
+                             EMAC_MDIO_STATUS_10MB);
        /* address */
        val = ((phy->addr << 21) | (devad << 16) | reg |
               EMAC_MDIO_COMM_COMMAND_ADDRESS |
@@ -3003,6 +3009,9 @@ static int bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy,
                }
        }
 
+       if (phy->flags & FLAGS_MDC_MDIO_WA_B0)
+               bnx2x_bits_dis(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_STATUS,
+                              EMAC_MDIO_STATUS_10MB);
        return rc;
 }
 
@@ -3012,6 +3021,9 @@ static int bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy,
        u32 tmp;
        u8 i;
        int rc = 0;
+       if (phy->flags & FLAGS_MDC_MDIO_WA_B0)
+               bnx2x_bits_en(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_STATUS,
+                             EMAC_MDIO_STATUS_10MB);
 
        /* address */
 
@@ -3065,7 +3077,9 @@ static int bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy,
                        bnx2x_cl45_read(bp, phy, devad, 0xf, &temp_val);
                }
        }
-
+       if (phy->flags & FLAGS_MDC_MDIO_WA_B0)
+               bnx2x_bits_dis(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_STATUS,
+                              EMAC_MDIO_STATUS_10MB);
        return rc;
 }
 
@@ -4353,6 +4367,9 @@ void bnx2x_link_status_update(struct link_params *params,
 
        vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
        vars->phy_flags = PHY_XGXS_FLAG;
+       if (vars->link_status & LINK_STATUS_PHYSICAL_LINK_FLAG)
+               vars->phy_flags |= PHY_PHYSICAL_LINK_FLAG;
+
        if (vars->link_up) {
                DP(NETIF_MSG_LINK, "phy link up\n");
 
@@ -4444,6 +4461,8 @@ void bnx2x_link_status_update(struct link_params *params,
 
                /* indicate no mac active */
                vars->mac_type = MAC_TYPE_NONE;
+               if (vars->link_status & LINK_STATUS_PHYSICAL_LINK_FLAG)
+                       vars->phy_flags |= PHY_HALF_OPEN_CONN_FLAG;
        }
 
        /* Sync media type */
@@ -5903,20 +5922,30 @@ int bnx2x_set_led(struct link_params *params,
                                tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
                                EMAC_WR(bp, EMAC_REG_EMAC_LED,
                                        (tmp | EMAC_LED_OVERRIDE));
-                               return rc;
+                               /*
+                                * return here without enabling traffic
+                                * LED blink andsetting rate in ON mode.
+                                * In oper mode, enabling LED blink
+                                * and setting rate is needed.
+                                */
+                               if (mode == LED_MODE_ON)
+                                       return rc;
                        }
-               } else if (SINGLE_MEDIA_DIRECT(params) &&
-                          (CHIP_IS_E1x(bp) ||
-                           CHIP_IS_E2(bp))) {
+               } else if (SINGLE_MEDIA_DIRECT(params)) {
                        /*
                         * This is a work-around for HW issue found when link
                         * is up in CL73
                         */
-                       REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
                        REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
-               } else {
+                       if (CHIP_IS_E1x(bp) ||
+                           CHIP_IS_E2(bp) ||
+                           (mode == LED_MODE_ON))
+                               REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
+                       else
+                               REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
+                                      hw_led_mode);
+               } else
                        REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, hw_led_mode);
-               }
 
                REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 + port*4, 0);
                /* Set blinking rate to ~15.9Hz */
@@ -6160,6 +6189,7 @@ static int bnx2x_update_link_down(struct link_params *params,
        /* update shared memory */
        vars->link_status &= ~(LINK_STATUS_SPEED_AND_DUPLEX_MASK |
                               LINK_STATUS_LINK_UP |
+                              LINK_STATUS_PHYSICAL_LINK_FLAG |
                               LINK_STATUS_AUTO_NEGOTIATE_COMPLETE |
                               LINK_STATUS_RX_FLOW_CONTROL_FLAG_MASK |
                               LINK_STATUS_TX_FLOW_CONTROL_FLAG_MASK |
@@ -6197,7 +6227,8 @@ static int bnx2x_update_link_up(struct link_params *params,
        u8 port = params->port;
        int rc = 0;
 
-       vars->link_status |= LINK_STATUS_LINK_UP;
+       vars->link_status |= (LINK_STATUS_LINK_UP |
+                             LINK_STATUS_PHYSICAL_LINK_FLAG);
        vars->phy_flags |= PHY_PHYSICAL_LINK_FLAG;
 
        if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
@@ -7998,6 +8029,9 @@ static void bnx2x_warpcore_set_limiting_mode(struct link_params *params,
        bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
                        MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE, &val);
 
+       /* Restart microcode to re-read the new mode */
+       bnx2x_warpcore_reset_lane(bp, phy, 1);
+       bnx2x_warpcore_reset_lane(bp, phy, 0);
 
 }
 
@@ -8116,7 +8150,6 @@ void bnx2x_handle_module_detect_int(struct link_params *params)
                                 offsetof(struct shmem_region, dev_info.
                                          port_feature_config[params->port].
                                          config));
-
                bnx2x_set_gpio_int(bp, gpio_num,
                                   MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
                                   gpio_port);
@@ -8125,8 +8158,9 @@ void bnx2x_handle_module_detect_int(struct link_params *params)
                 * Disable transmit for this module
                 */
                phy->media_type = ETH_PHY_NOT_PRESENT;
-               if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
-                   PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
+               if (((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+                    PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) ||
+                   CHIP_IS_E3(bp))
                        bnx2x_sfp_set_transmitter(params, phy, 0);
        }
 }
@@ -8228,9 +8262,6 @@ static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy,
        u16 cnt, val, tmp1;
        struct bnx2x *bp = params->bp;
 
-       /* SPF+ PHY: Set flag to check for Tx error */
-       vars->phy_flags = PHY_TX_ERROR_CHECK_FLAG;
-
        bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
                       MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
        /* HW reset */
@@ -8414,9 +8445,6 @@ static int bnx2x_8726_config_init(struct bnx2x_phy *phy,
        struct bnx2x *bp = params->bp;
        DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
 
-       /* SPF+ PHY: Set flag to check for Tx error */
-       vars->phy_flags = PHY_TX_ERROR_CHECK_FLAG;
-
        bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
        bnx2x_wait_reset_complete(bp, phy, params);
 
@@ -8585,9 +8613,6 @@ static int bnx2x_8727_config_init(struct bnx2x_phy *phy,
        struct bnx2x *bp = params->bp;
        /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
 
-       /* SPF+ PHY: Set flag to check for Tx error */
-       vars->phy_flags = PHY_TX_ERROR_CHECK_FLAG;
-
        bnx2x_wait_reset_complete(bp, phy, params);
        rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
        /* Should be 0x6 to enable XS on Tx side. */
@@ -9243,7 +9268,13 @@ static int bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
        if (phy->req_duplex == DUPLEX_FULL)
                autoneg_val |= (1<<8);
 
-       bnx2x_cl45_write(bp, phy,
+       /*
+        * Always write this if this is not 84833.
+        * For 84833, write it only when it's a forced speed.
+        */
+       if ((phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) ||
+               ((autoneg_val & (1<<12)) == 0))
+               bnx2x_cl45_write(bp, phy,
                         MDIO_AN_DEVAD,
                         MDIO_AN_REG_8481_LEGACY_MII_CTRL, autoneg_val);
 
@@ -9257,13 +9288,12 @@ static int bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
                        bnx2x_cl45_write(bp, phy,
                                 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL,
                                 0x3200);
-       } else if (phy->req_line_speed != SPEED_10 &&
-                  phy->req_line_speed != SPEED_100) {
+       } else
                bnx2x_cl45_write(bp, phy,
                                 MDIO_AN_DEVAD,
                                 MDIO_AN_REG_8481_10GBASE_T_AN_CTRL,
                                 1);
-       }
+
        /* Save spirom version */
        bnx2x_save_848xx_spirom_version(phy, params);
 
@@ -9756,11 +9786,9 @@ static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy,
                bnx2x_cl45_read(bp, phy,
                                MDIO_CTL_DEVAD,
                                0x400f, &val16);
-               /* Put to low power mode on newer FW */
-               if ((val16 & 0x303f) > 0x1009)
-                       bnx2x_cl45_write(bp, phy,
-                                       MDIO_PMA_DEVAD,
-                                       MDIO_PMA_REG_CTRL, 0x800);
+               bnx2x_cl45_write(bp, phy,
+                               MDIO_PMA_DEVAD,
+                               MDIO_PMA_REG_CTRL, 0x800);
        }
 }
 
@@ -10191,8 +10219,15 @@ static void bnx2x_54618se_link_reset(struct bnx2x_phy *phy,
        u32 cfg_pin;
        u8 port;
 
-       /* This works with E3 only, no need to check the chip
-          before determining the port. */
+       /*
+        * In case of no EPIO routed to reset the GPHY, put it
+        * in low power mode.
+        */
+       bnx2x_cl22_write(bp, phy, MDIO_PMA_REG_CTRL, 0x800);
+       /*
+        * This works with E3 only, no need to check the chip
+        * before determining the port.
+        */
        port = params->port;
        cfg_pin = (REG_RD(bp, params->shmem_base +
                        offsetof(struct shmem_region,
@@ -10603,7 +10638,8 @@ static struct bnx2x_phy phy_warpcore = {
        .type           = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT,
        .addr           = 0xff,
        .def_md_devad   = 0,
-       .flags          = FLAGS_HW_LOCK_REQUIRED,
+       .flags          = (FLAGS_HW_LOCK_REQUIRED |
+                          FLAGS_TX_ERROR_CHECK),
        .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .mdio_ctrl      = 0,
@@ -10729,7 +10765,8 @@ static struct bnx2x_phy phy_8706 = {
        .type           = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706,
        .addr           = 0xff,
        .def_md_devad   = 0,
-       .flags          = FLAGS_INIT_XGXS_FIRST,
+       .flags          = (FLAGS_INIT_XGXS_FIRST |
+                          FLAGS_TX_ERROR_CHECK),
        .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .mdio_ctrl      = 0,
@@ -10760,7 +10797,8 @@ static struct bnx2x_phy phy_8726 = {
        .addr           = 0xff,
        .def_md_devad   = 0,
        .flags          = (FLAGS_HW_LOCK_REQUIRED |
-                          FLAGS_INIT_XGXS_FIRST),
+                          FLAGS_INIT_XGXS_FIRST |
+                          FLAGS_TX_ERROR_CHECK),
        .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .mdio_ctrl      = 0,
@@ -10791,7 +10829,8 @@ static struct bnx2x_phy phy_8727 = {
        .type           = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
        .addr           = 0xff,
        .def_md_devad   = 0,
-       .flags          = FLAGS_FAN_FAILURE_DET_REQ,
+       .flags          = (FLAGS_FAN_FAILURE_DET_REQ |
+                          FLAGS_TX_ERROR_CHECK),
        .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .mdio_ctrl      = 0,
@@ -11112,6 +11151,8 @@ static int bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port,
                 */
                if (CHIP_REV(bp) == CHIP_REV_Ax)
                        phy->flags |= FLAGS_MDC_MDIO_WA;
+               else
+                       phy->flags |= FLAGS_MDC_MDIO_WA_B0;
        } else {
                switch (switch_cfg) {
                case SWITCH_CFG_1G:
@@ -11500,13 +11541,12 @@ void bnx2x_init_xmac_loopback(struct link_params *params,
         * Set WC to loopback mode since link is required to provide clock
         * to the XMAC in 20G mode
         */
-       if (vars->line_speed == SPEED_20000) {
-               bnx2x_set_aer_mmd(params, &params->phy[0]);
-               bnx2x_warpcore_reset_lane(bp, &params->phy[0], 0);
-               params->phy[INT_PHY].config_loopback(
+       bnx2x_set_aer_mmd(params, &params->phy[0]);
+       bnx2x_warpcore_reset_lane(bp, &params->phy[0], 0);
+       params->phy[INT_PHY].config_loopback(
                        &params->phy[INT_PHY],
                        params);
-       }
+
        bnx2x_xmac_enable(params, vars, 1);
        REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
 }
@@ -11684,12 +11724,16 @@ int bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
        bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
 
        if (reset_ext_phy) {
+               bnx2x_set_mdio_clk(bp, params->chip_id, port);
                for (phy_index = EXT_PHY1; phy_index < params->num_phys;
                      phy_index++) {
-                       if (params->phy[phy_index].link_reset)
+                       if (params->phy[phy_index].link_reset) {
+                               bnx2x_set_aer_mmd(params,
+                                                 &params->phy[phy_index]);
                                params->phy[phy_index].link_reset(
                                        &params->phy[phy_index],
                                        params);
+                       }
                        if (params->phy[phy_index].flags &
                            FLAGS_REARM_LATCH_SIGNAL)
                                clear_latch_ind = 1;
@@ -12178,10 +12222,6 @@ static void bnx2x_analyze_link_error(struct link_params *params,
        u8 led_mode;
        u32 half_open_conn = (vars->phy_flags & PHY_HALF_OPEN_CONN_FLAG) > 0;
 
-       /*DP(NETIF_MSG_LINK, "CHECK LINK: %x half_open:%x-> lss:%x\n",
-                      vars->link_up,
-                      half_open_conn, lss_status);*/
-
        if ((lss_status ^ half_open_conn) == 0)
                return;
 
@@ -12194,6 +12234,7 @@ static void bnx2x_analyze_link_error(struct link_params *params,
         * b. Update link_vars->link_up
         */
        if (lss_status) {
+               DP(NETIF_MSG_LINK, "Remote Fault detected !!!\n");
                vars->link_status &= ~LINK_STATUS_LINK_UP;
                vars->link_up = 0;
                vars->phy_flags |= PHY_HALF_OPEN_CONN_FLAG;
@@ -12203,6 +12244,7 @@ static void bnx2x_analyze_link_error(struct link_params *params,
                 */
                led_mode = LED_MODE_OFF;
        } else {
+               DP(NETIF_MSG_LINK, "Remote Fault cleared\n");
                vars->link_status |= LINK_STATUS_LINK_UP;
                vars->link_up = 1;
                vars->phy_flags &= ~PHY_HALF_OPEN_CONN_FLAG;
@@ -12219,6 +12261,15 @@ static void bnx2x_analyze_link_error(struct link_params *params,
        bnx2x_notify_link_changed(bp);
 }
 
+/******************************************************************************
+* Description:
+*      This function checks for half opened connection change indication.
+*      When such change occurs, it calls the bnx2x_analyze_link_error
+*      to check if Remote Fault is set or cleared. Reception of remote fault
+*      status message in the MAC indicates that the peer's MAC has detected
+*      a fault, for example, due to break in the TX side of fiber.
+*
+******************************************************************************/
 static void bnx2x_check_half_open_conn(struct link_params *params,
                                       struct link_vars *vars)
 {
@@ -12229,9 +12280,28 @@ static void bnx2x_check_half_open_conn(struct link_params *params,
        if ((vars->phy_flags & PHY_PHYSICAL_LINK_FLAG) == 0)
                return;
 
-       if (!CHIP_IS_E3(bp) &&
+       if (CHIP_IS_E3(bp) &&
            (REG_RD(bp, MISC_REG_RESET_REG_2) &
-                  (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port))) {
+             (MISC_REGISTERS_RESET_REG_2_XMAC))) {
+               /* Check E3 XMAC */
+               /*
+                * Note that link speed cannot be queried here, since it may be
+                * zero while link is down. In case UMAC is active, LSS will
+                * simply not be set
+                */
+               mac_base = (params->port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0;
+
+               /* Clear stick bits (Requires rising edge) */
+               REG_WR(bp, mac_base + XMAC_REG_CLEAR_RX_LSS_STATUS, 0);
+               REG_WR(bp, mac_base + XMAC_REG_CLEAR_RX_LSS_STATUS,
+                      XMAC_CLEAR_RX_LSS_STATUS_REG_CLEAR_LOCAL_FAULT_STATUS |
+                      XMAC_CLEAR_RX_LSS_STATUS_REG_CLEAR_REMOTE_FAULT_STATUS);
+               if (REG_RD(bp, mac_base + XMAC_REG_RX_LSS_STATUS))
+                       lss_status = 1;
+
+               bnx2x_analyze_link_error(params, vars, lss_status);
+       } else if (REG_RD(bp, MISC_REG_RESET_REG_2) &
+                  (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port)) {
                /* Check E1X / E2 BMAC */
                u32 lss_status_reg;
                u32 wb_data[2];
@@ -12253,14 +12323,20 @@ static void bnx2x_check_half_open_conn(struct link_params *params,
 void bnx2x_period_func(struct link_params *params, struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
+       u16 phy_idx;
        if (!params) {
-               DP(NETIF_MSG_LINK, "Ininitliazed params !\n");
+               DP(NETIF_MSG_LINK, "Uninitialized params !\n");
                return;
        }
-       /* DP(NETIF_MSG_LINK, "Periodic called vars->phy_flags 0x%x speed 0x%x
-        RESET_REG_2 0x%x\n", vars->phy_flags, vars->line_speed,
-         REG_RD(bp, MISC_REG_RESET_REG_2)); */
-       bnx2x_check_half_open_conn(params, vars);
+
+       for (phy_idx = INT_PHY; phy_idx < MAX_PHYS; phy_idx++) {
+               if (params->phy[phy_idx].flags & FLAGS_TX_ERROR_CHECK) {
+                       bnx2x_set_aer_mmd(params, &params->phy[phy_idx]);
+                       bnx2x_check_half_open_conn(params, vars);
+                       break;
+               }
+       }
+
        if (CHIP_IS_E3(bp))
                bnx2x_check_over_curr(params, vars);
 }
index 6a7708d..c12db6d 100644 (file)
@@ -145,6 +145,8 @@ struct bnx2x_phy {
 #define FLAGS_SFP_NOT_APPROVED         (1<<7)
 #define FLAGS_MDC_MDIO_WA              (1<<8)
 #define FLAGS_DUMMY_READ               (1<<9)
+#define FLAGS_MDC_MDIO_WA_B0           (1<<10)
+#define FLAGS_TX_ERROR_CHECK           (1<<12)
 
        /* preemphasis values for the rx side */
        u16 rx_preemphasis[4];
@@ -276,7 +278,6 @@ struct link_vars {
 #define PHY_PHYSICAL_LINK_FLAG         (1<<2)
 #define PHY_HALF_OPEN_CONN_FLAG                (1<<3)
 #define PHY_OVER_CURRENT_FLAG          (1<<4)
-#define PHY_TX_ERROR_CHECK_FLAG                (1<<5)
 
        u8 mac_type;
 #define MAC_TYPE_NONE          0
index 1507091..c027e93 100644 (file)
@@ -407,8 +407,8 @@ u32 bnx2x_dmae_opcode(struct bnx2x *bp, u8 src_type, u8 dst_type,
        opcode |= (DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET);
 
        opcode |= (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0);
-       opcode |= ((BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT) |
-                  (BP_E1HVN(bp) << DMAE_COMMAND_DST_VN_SHIFT));
+       opcode |= ((BP_VN(bp) << DMAE_CMD_E1HVN_SHIFT) |
+                  (BP_VN(bp) << DMAE_COMMAND_DST_VN_SHIFT));
        opcode |= (DMAE_COM_SET_ERR << DMAE_COMMAND_ERR_POLICY_SHIFT);
 
 #ifdef __BIG_ENDIAN
@@ -1419,7 +1419,7 @@ static void bnx2x_hc_int_enable(struct bnx2x *bp)
        if (!CHIP_IS_E1(bp)) {
                /* init leading/trailing edge */
                if (IS_MF(bp)) {
-                       val = (0xee0f | (1 << (BP_E1HVN(bp) + 4)));
+                       val = (0xee0f | (1 << (BP_VN(bp) + 4)));
                        if (bp->port.pmf)
                                /* enable nig and gpio3 attention */
                                val |= 0x1100;
@@ -1471,7 +1471,7 @@ static void bnx2x_igu_int_enable(struct bnx2x *bp)
 
        /* init leading/trailing edge */
        if (IS_MF(bp)) {
-               val = (0xee0f | (1 << (BP_E1HVN(bp) + 4)));
+               val = (0xee0f | (1 << (BP_VN(bp) + 4)));
                if (bp->port.pmf)
                        /* enable nig and gpio3 attention */
                        val |= 0x1100;
@@ -2287,7 +2287,7 @@ static void bnx2x_calc_vn_weight_sum(struct bnx2x *bp)
        int vn;
 
        bp->vn_weight_sum = 0;
-       for (vn = VN_0; vn < E1HVN_MAX; vn++) {
+       for (vn = VN_0; vn < BP_MAX_VN_NUM(bp); vn++) {
                u32 vn_cfg = bp->mf_config[vn];
                u32 vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >>
                                   FUNC_MF_CFG_MIN_BW_SHIFT) * 100;
@@ -2320,12 +2320,18 @@ static void bnx2x_calc_vn_weight_sum(struct bnx2x *bp)
                                        CMNG_FLAGS_PER_PORT_FAIRNESS_VN;
 }
 
+/* returns func by VN for current port */
+static inline int func_by_vn(struct bnx2x *bp, int vn)
+{
+       return 2 * vn + BP_PORT(bp);
+}
+
 static void bnx2x_init_vn_minmax(struct bnx2x *bp, int vn)
 {
        struct rate_shaping_vars_per_vn m_rs_vn;
        struct fairness_vars_per_vn m_fair_vn;
        u32 vn_cfg = bp->mf_config[vn];
-       int func = 2*vn + BP_PORT(bp);
+       int func = func_by_vn(bp, vn);
        u16 vn_min_rate, vn_max_rate;
        int i;
 
@@ -2422,7 +2428,7 @@ void bnx2x_read_mf_cfg(struct bnx2x *bp)
         *
         *      and there are 2 functions per port
         */
-       for (vn = VN_0; vn < E1HVN_MAX; vn++) {
+       for (vn = VN_0; vn < BP_MAX_VN_NUM(bp); vn++) {
                int /*abs*/func = n * (2 * vn + BP_PORT(bp)) + BP_PATH(bp);
 
                if (func >= E1H_FUNC_MAX)
@@ -2454,7 +2460,7 @@ static void bnx2x_cmng_fns_init(struct bnx2x *bp, u8 read_cfg, u8 cmng_type)
 
                /* calculate and set min-max rate for each vn */
                if (bp->port.pmf)
-                       for (vn = VN_0; vn < E1HVN_MAX; vn++)
+                       for (vn = VN_0; vn < BP_MAX_VN_NUM(bp); vn++)
                                bnx2x_init_vn_minmax(bp, vn);
 
                /* always enable rate shaping and fairness */
@@ -2473,16 +2479,15 @@ static void bnx2x_cmng_fns_init(struct bnx2x *bp, u8 read_cfg, u8 cmng_type)
 
 static inline void bnx2x_link_sync_notify(struct bnx2x *bp)
 {
-       int port = BP_PORT(bp);
        int func;
        int vn;
 
        /* Set the attention towards other drivers on the same port */
-       for (vn = VN_0; vn < E1HVN_MAX; vn++) {
-               if (vn == BP_E1HVN(bp))
+       for (vn = VN_0; vn < BP_MAX_VN_NUM(bp); vn++) {
+               if (vn == BP_VN(bp))
                        continue;
 
-               func = ((vn << 1) | port);
+               func = func_by_vn(bp, vn);
                REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_0 +
                       (LINK_SYNC_ATTENTION_BIT_FUNC_0 + func)*4, 1);
        }
@@ -2577,7 +2582,7 @@ static void bnx2x_pmf_update(struct bnx2x *bp)
        bnx2x_dcbx_pmf_update(bp);
 
        /* enable nig attention */
-       val = (0xff0f | (1 << (BP_E1HVN(bp) + 4)));
+       val = (0xff0f | (1 << (BP_VN(bp) + 4)));
        if (bp->common.int_block == INT_BLOCK_HC) {
                REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, val);
                REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, val);
@@ -2756,8 +2761,14 @@ static void bnx2x_pf_rx_q_prep(struct bnx2x *bp,
        u16 tpa_agg_size = 0;
 
        if (!fp->disable_tpa) {
-               pause->sge_th_hi = 250;
-               pause->sge_th_lo = 150;
+               pause->sge_th_lo = SGE_TH_LO(bp);
+               pause->sge_th_hi = SGE_TH_HI(bp);
+
+               /* validate SGE ring has enough to cross high threshold */
+               WARN_ON(bp->dropless_fc &&
+                               pause->sge_th_hi + FW_PREFETCH_CNT >
+                               MAX_RX_SGE_CNT * NUM_RX_SGE_PAGES);
+
                tpa_agg_size = min_t(u32,
                        (min_t(u32, 8, MAX_SKB_FRAGS) *
                        SGE_PAGE_SIZE * PAGES_PER_SGE), 0xffff);
@@ -2771,10 +2782,21 @@ static void bnx2x_pf_rx_q_prep(struct bnx2x *bp,
 
        /* pause - not for e1 */
        if (!CHIP_IS_E1(bp)) {
-               pause->bd_th_hi = 350;
-               pause->bd_th_lo = 250;
-               pause->rcq_th_hi = 350;
-               pause->rcq_th_lo = 250;
+               pause->bd_th_lo = BD_TH_LO(bp);
+               pause->bd_th_hi = BD_TH_HI(bp);
+
+               pause->rcq_th_lo = RCQ_TH_LO(bp);
+               pause->rcq_th_hi = RCQ_TH_HI(bp);
+               /*
+                * validate that rings have enough entries to cross
+                * high thresholds
+                */
+               WARN_ON(bp->dropless_fc &&
+                               pause->bd_th_hi + FW_PREFETCH_CNT >
+                               bp->rx_ring_size);
+               WARN_ON(bp->dropless_fc &&
+                               pause->rcq_th_hi + FW_PREFETCH_CNT >
+                               NUM_RCQ_RINGS * MAX_RCQ_DESC_CNT);
 
                pause->pri_map = 1;
        }
@@ -2802,9 +2824,7 @@ static void bnx2x_pf_rx_q_prep(struct bnx2x *bp,
         * For PF Clients it should be the maximum avaliable number.
         * VF driver(s) may want to define it to a smaller value.
         */
-       rxq_init->max_tpa_queues =
-               (CHIP_IS_E1(bp) ? ETH_MAX_AGGREGATION_QUEUES_E1 :
-               ETH_MAX_AGGREGATION_QUEUES_E1H_E2);
+       rxq_init->max_tpa_queues = MAX_AGG_QS(bp);
 
        rxq_init->cache_line_log = BNX2X_RX_ALIGN_SHIFT;
        rxq_init->fw_sb_id = fp->fw_sb_id;
@@ -4808,6 +4828,37 @@ void bnx2x_setup_ndsb_state_machine(struct hc_status_block_sm *hc_sm,
        hc_sm->time_to_expire = 0xFFFFFFFF;
 }
 
+
+/* allocates state machine ids. */
+static inline
+void bnx2x_map_sb_state_machines(struct hc_index_data *index_data)
+{
+       /* zero out state machine indices */
+       /* rx indices */
+       index_data[HC_INDEX_ETH_RX_CQ_CONS].flags &= ~HC_INDEX_DATA_SM_ID;
+
+       /* tx indices */
+       index_data[HC_INDEX_OOO_TX_CQ_CONS].flags &= ~HC_INDEX_DATA_SM_ID;
+       index_data[HC_INDEX_ETH_TX_CQ_CONS_COS0].flags &= ~HC_INDEX_DATA_SM_ID;
+       index_data[HC_INDEX_ETH_TX_CQ_CONS_COS1].flags &= ~HC_INDEX_DATA_SM_ID;
+       index_data[HC_INDEX_ETH_TX_CQ_CONS_COS2].flags &= ~HC_INDEX_DATA_SM_ID;
+
+       /* map indices */
+       /* rx indices */
+       index_data[HC_INDEX_ETH_RX_CQ_CONS].flags |=
+               SM_RX_ID << HC_INDEX_DATA_SM_ID_SHIFT;
+
+       /* tx indices */
+       index_data[HC_INDEX_OOO_TX_CQ_CONS].flags |=
+               SM_TX_ID << HC_INDEX_DATA_SM_ID_SHIFT;
+       index_data[HC_INDEX_ETH_TX_CQ_CONS_COS0].flags |=
+               SM_TX_ID << HC_INDEX_DATA_SM_ID_SHIFT;
+       index_data[HC_INDEX_ETH_TX_CQ_CONS_COS1].flags |=
+               SM_TX_ID << HC_INDEX_DATA_SM_ID_SHIFT;
+       index_data[HC_INDEX_ETH_TX_CQ_CONS_COS2].flags |=
+               SM_TX_ID << HC_INDEX_DATA_SM_ID_SHIFT;
+}
+
 static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid,
                          u8 vf_valid, int fw_sb_id, int igu_sb_id)
 {
@@ -4839,6 +4890,7 @@ static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid,
                hc_sm_p = sb_data_e2.common.state_machine;
                sb_data_p = (u32 *)&sb_data_e2;
                data_size = sizeof(struct hc_status_block_data_e2)/sizeof(u32);
+               bnx2x_map_sb_state_machines(sb_data_e2.index_data);
        } else {
                memset(&sb_data_e1x, 0,
                       sizeof(struct hc_status_block_data_e1x));
@@ -4853,6 +4905,7 @@ static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid,
                hc_sm_p = sb_data_e1x.common.state_machine;
                sb_data_p = (u32 *)&sb_data_e1x;
                data_size = sizeof(struct hc_status_block_data_e1x)/sizeof(u32);
+               bnx2x_map_sb_state_machines(sb_data_e1x.index_data);
        }
 
        bnx2x_setup_ndsb_state_machine(&hc_sm_p[SM_RX_ID],
@@ -5798,6 +5851,12 @@ static int bnx2x_init_hw_common(struct bnx2x *bp)
 
        DP(BNX2X_MSG_MCP, "starting common init  func %d\n", BP_ABS_FUNC(bp));
 
+       /*
+        * take the UNDI lock to protect undi_unload flow from accessing
+        * registers while we're resetting the chip
+        */
+       bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_RESET);
+
        bnx2x_reset_common(bp);
        REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0xffffffff);
 
@@ -5808,6 +5867,8 @@ static int bnx2x_init_hw_common(struct bnx2x *bp)
        }
        REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, val);
 
+       bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RESET);
+
        bnx2x_init_block(bp, BLOCK_MISC, PHASE_COMMON);
 
        if (!CHIP_IS_E1x(bp)) {
@@ -6663,12 +6724,16 @@ static int bnx2x_init_hw_func(struct bnx2x *bp)
                        if (CHIP_MODE_IS_4_PORT(bp))
                                dsb_idx = BP_FUNC(bp);
                        else
-                               dsb_idx = BP_E1HVN(bp);
+                               dsb_idx = BP_VN(bp);
 
                        prod_offset = (CHIP_INT_MODE_IS_BC(bp) ?
                                       IGU_BC_BASE_DSB_PROD + dsb_idx :
                                       IGU_NORM_BASE_DSB_PROD + dsb_idx);
 
+                       /*
+                        * igu prods come in chunks of E1HVN_MAX (4) -
+                        * does not matters what is the current chip mode
+                        */
                        for (i = 0; i < (num_segs * E1HVN_MAX);
                             i += E1HVN_MAX) {
                                addr = IGU_REG_PROD_CONS_MEMORY +
@@ -7562,7 +7627,7 @@ u32 bnx2x_send_unload_req(struct bnx2x *bp, int unload_mode)
                u32 val;
                /* The mac address is written to entries 1-4 to
                   preserve entry 0 which is used by the PMF */
-               u8 entry = (BP_E1HVN(bp) + 1)*8;
+               u8 entry = (BP_VN(bp) + 1)*8;
 
                val = (mac_addr[0] << 8) | mac_addr[1];
                EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + entry, val);
@@ -8538,10 +8603,12 @@ static void __devinit bnx2x_undi_unload(struct bnx2x *bp)
        /* Check if there is any driver already loaded */
        val = REG_RD(bp, MISC_REG_UNPREPARED);
        if (val == 0x1) {
-               /* Check if it is the UNDI driver
+
+               bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_RESET);
+               /*
+                * Check if it is the UNDI driver
                 * UNDI driver initializes CID offset for normal bell to 0x7
                 */
-               bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_UNDI);
                val = REG_RD(bp, DORQ_REG_NORM_CID_OFST);
                if (val == 0x7) {
                        u32 reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS;
@@ -8579,9 +8646,6 @@ static void __devinit bnx2x_undi_unload(struct bnx2x *bp)
                                bnx2x_fw_command(bp, reset_code, 0);
                        }
 
-                       /* now it's safe to release the lock */
-                       bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_UNDI);
-
                        bnx2x_undi_int_disable(bp);
                        port = BP_PORT(bp);
 
@@ -8631,8 +8695,10 @@ static void __devinit bnx2x_undi_unload(struct bnx2x *bp)
                        bp->fw_seq =
                              (SHMEM_RD(bp, func_mb[bp->pf_num].drv_mb_header) &
                                DRV_MSG_SEQ_NUMBER_MASK);
-               } else
-                       bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_UNDI);
+               }
+
+               /* now it's safe to release the lock */
+               bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RESET);
        }
 }
 
@@ -8769,13 +8835,13 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
 static void __devinit bnx2x_get_igu_cam_info(struct bnx2x *bp)
 {
        int pfid = BP_FUNC(bp);
-       int vn = BP_E1HVN(bp);
        int igu_sb_id;
        u32 val;
        u8 fid, igu_sb_cnt = 0;
 
        bp->igu_base_sb = 0xff;
        if (CHIP_INT_MODE_IS_BC(bp)) {
+               int vn = BP_VN(bp);
                igu_sb_cnt = bp->igu_sb_cnt;
                bp->igu_base_sb = (CHIP_MODE_IS_4_PORT(bp) ? pfid : vn) *
                        FP_SB_MAX_E1x;
@@ -9408,6 +9474,10 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
                bp->igu_base_sb = 0;
        } else {
                bp->common.int_block = INT_BLOCK_IGU;
+
+               /* do not allow device reset during IGU info preocessing */
+               bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_RESET);
+
                val = REG_RD(bp, IGU_REG_BLOCK_CONFIGURATION);
 
                if (val & IGU_BLOCK_CONFIGURATION_REG_BACKWARD_COMP_EN) {
@@ -9439,6 +9509,7 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
 
                bnx2x_get_igu_cam_info(bp);
 
+               bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RESET);
        }
 
        /*
@@ -9465,7 +9536,7 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
 
        bp->mf_ov = 0;
        bp->mf_mode = 0;
-       vn = BP_E1HVN(bp);
+       vn = BP_VN(bp);
 
        if (!CHIP_IS_E1(bp) && !BP_NOMCP(bp)) {
                BNX2X_DEV_INFO("shmem2base 0x%x, size %d, mfcfg offset %d\n",
@@ -9585,13 +9656,6 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
        /* port info */
        bnx2x_get_port_hwinfo(bp);
 
-       if (!BP_NOMCP(bp)) {
-               bp->fw_seq =
-                       (SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
-                        DRV_MSG_SEQ_NUMBER_MASK);
-               BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq);
-       }
-
        /* Get MAC addresses */
        bnx2x_get_mac_hwinfo(bp);
 
@@ -9757,6 +9821,14 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
        if (!BP_NOMCP(bp))
                bnx2x_undi_unload(bp);
 
+       /* init fw_seq after undi_unload! */
+       if (!BP_NOMCP(bp)) {
+               bp->fw_seq =
+                       (SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
+                        DRV_MSG_SEQ_NUMBER_MASK);
+               BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq);
+       }
+
        if (CHIP_REV_IS_FPGA(bp))
                dev_err(&bp->pdev->dev, "FPGA detected\n");
 
@@ -10251,10 +10323,21 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
        /* clean indirect addresses */
        pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS,
                               PCICFG_VENDOR_ID_OFFSET);
-       REG_WR(bp, PXP2_REG_PGL_ADDR_88_F0 + BP_PORT(bp)*16, 0);
-       REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F0 + BP_PORT(bp)*16, 0);
-       REG_WR(bp, PXP2_REG_PGL_ADDR_90_F0 + BP_PORT(bp)*16, 0);
-       REG_WR(bp, PXP2_REG_PGL_ADDR_94_F0 + BP_PORT(bp)*16, 0);
+       /*
+        * Clean the following indirect addresses for all functions since it
+        * is not used by the driver.
+        */
+       REG_WR(bp, PXP2_REG_PGL_ADDR_88_F0, 0);
+       REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F0, 0);
+       REG_WR(bp, PXP2_REG_PGL_ADDR_90_F0, 0);
+       REG_WR(bp, PXP2_REG_PGL_ADDR_94_F0, 0);
+
+       if (CHIP_IS_E1x(bp)) {
+               REG_WR(bp, PXP2_REG_PGL_ADDR_88_F1, 0);
+               REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F1, 0);
+               REG_WR(bp, PXP2_REG_PGL_ADDR_90_F1, 0);
+               REG_WR(bp, PXP2_REG_PGL_ADDR_94_F1, 0);
+       }
 
        /*
         * Enable internal target-read (in case we are probed after PF FLR).
index 02461fe..dac217d 100644 (file)
 /* [R 6] Debug only: Number of used entries in the data FIFO */
 #define PXP2_REG_HST_DATA_FIFO_STATUS                           0x12047c
 /* [R 7] Debug only: Number of used entries in the header FIFO */
-#define PXP2_REG_HST_HEADER_FIFO_STATUS                         0x120478
-#define PXP2_REG_PGL_ADDR_88_F0                                 0x120534
-#define PXP2_REG_PGL_ADDR_8C_F0                                 0x120538
-#define PXP2_REG_PGL_ADDR_90_F0                                 0x12053c
-#define PXP2_REG_PGL_ADDR_94_F0                                 0x120540
+#define PXP2_REG_HST_HEADER_FIFO_STATUS                                 0x120478
+#define PXP2_REG_PGL_ADDR_88_F0                                         0x120534
+/* [R 32] GRC address for configuration access to PCIE config address 0x88.
+ * any write to this PCIE address will cause a GRC write access to the
+ * address that's in t this register */
+#define PXP2_REG_PGL_ADDR_88_F1                                         0x120544
+#define PXP2_REG_PGL_ADDR_8C_F0                                         0x120538
+/* [R 32] GRC address for configuration access to PCIE config address 0x8c.
+ * any write to this PCIE address will cause a GRC write access to the
+ * address that's in t this register */
+#define PXP2_REG_PGL_ADDR_8C_F1                                         0x120548
+#define PXP2_REG_PGL_ADDR_90_F0                                         0x12053c
+/* [R 32] GRC address for configuration access to PCIE config address 0x90.
+ * any write to this PCIE address will cause a GRC write access to the
+ * address that's in t this register */
+#define PXP2_REG_PGL_ADDR_90_F1                                         0x12054c
+#define PXP2_REG_PGL_ADDR_94_F0                                         0x120540
+/* [R 32] GRC address for configuration access to PCIE config address 0x94.
+ * any write to this PCIE address will cause a GRC write access to the
+ * address that's in t this register */
+#define PXP2_REG_PGL_ADDR_94_F1                                         0x120550
 #define PXP2_REG_PGL_CONTROL0                                   0x120490
 #define PXP2_REG_PGL_CONTROL1                                   0x120514
 #define PXP2_REG_PGL_DEBUG                                      0x120520
    The fields are: [4:0] - tail pointer; 10:5] - Link List size; 15:11] -
    header pointer. */
 #define UCM_REG_XX_TABLE                                        0xe0300
+#define UMAC_COMMAND_CONFIG_REG_IGNORE_TX_PAUSE                         (0x1<<28)
 #define UMAC_COMMAND_CONFIG_REG_LOOP_ENA                        (0x1<<15)
 #define UMAC_COMMAND_CONFIG_REG_NO_LGTH_CHECK                   (0x1<<24)
 #define UMAC_COMMAND_CONFIG_REG_PAD_EN                          (0x1<<5)
+#define UMAC_COMMAND_CONFIG_REG_PAUSE_IGNORE                    (0x1<<8)
 #define UMAC_COMMAND_CONFIG_REG_PROMIS_EN                       (0x1<<4)
 #define UMAC_COMMAND_CONFIG_REG_RX_ENA                          (0x1<<1)
 #define UMAC_COMMAND_CONFIG_REG_SW_RESET                        (0x1<<13)
 #define EMAC_MDIO_COMM_START_BUSY                               (1L<<29)
 #define EMAC_MDIO_MODE_AUTO_POLL                                (1L<<4)
 #define EMAC_MDIO_MODE_CLAUSE_45                                (1L<<31)
-#define EMAC_MDIO_MODE_CLOCK_CNT                                (0x3fL<<16)
+#define EMAC_MDIO_MODE_CLOCK_CNT                                (0x3ffL<<16)
 #define EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT                       16
+#define EMAC_MDIO_STATUS_10MB                                   (1L<<1)
 #define EMAC_MODE_25G_MODE                                      (1L<<5)
 #define EMAC_MODE_HALF_DUPLEX                                   (1L<<1)
 #define EMAC_MODE_PORT_GMII                                     (2L<<2)
 #define EMAC_REG_EMAC_MAC_MATCH                                 0x10
 #define EMAC_REG_EMAC_MDIO_COMM                                 0xac
 #define EMAC_REG_EMAC_MDIO_MODE                                 0xb4
+#define EMAC_REG_EMAC_MDIO_STATUS                               0xb0
 #define EMAC_REG_EMAC_MODE                                      0x0
 #define EMAC_REG_EMAC_RX_MODE                                   0xc8
 #define EMAC_REG_EMAC_RX_MTU_SIZE                               0x9c
 #define HW_LOCK_RESOURCE_RECOVERY_LEADER_0                      8
 #define HW_LOCK_RESOURCE_RECOVERY_LEADER_1                      9
 #define HW_LOCK_RESOURCE_SPIO                                   2
-#define HW_LOCK_RESOURCE_UNDI                                   5
+#define HW_LOCK_RESOURCE_RESET                                  5
 #define AEU_INPUTS_ATTN_BITS_ATC_HW_INTERRUPT                   (0x1<<4)
 #define AEU_INPUTS_ATTN_BITS_ATC_PARITY_ERROR                   (0x1<<5)
 #define AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR                   (0x1<<18)
index 771f680..9908f2b 100644 (file)
@@ -710,7 +710,8 @@ static int bnx2x_hw_stats_update(struct bnx2x *bp)
                break;
 
        case MAC_TYPE_NONE: /* unreached */
-               BNX2X_ERR("stats updated by DMAE but no MAC active\n");
+               DP(BNX2X_MSG_STATS,
+                  "stats updated by DMAE but no MAC active\n");
                return -1;
 
        default: /* unreached */
@@ -1391,7 +1392,7 @@ static void bnx2x_port_stats_base_init(struct bnx2x *bp)
 
 static void bnx2x_func_stats_base_init(struct bnx2x *bp)
 {
-       int vn, vn_max = IS_MF(bp) ? E1HVN_MAX : E1VN_MAX;
+       int vn, vn_max = IS_MF(bp) ? BP_MAX_VN_NUM(bp) : E1VN_MAX;
        u32 func_stx;
 
        /* sanity */
@@ -1404,7 +1405,7 @@ static void bnx2x_func_stats_base_init(struct bnx2x *bp)
        func_stx = bp->func_stx;
 
        for (vn = VN_0; vn < vn_max; vn++) {
-               int mb_idx = CHIP_IS_E1x(bp) ? 2*vn + BP_PORT(bp) : vn;
+               int mb_idx = BP_FW_MB_IDX_VN(bp, vn);
 
                bp->func_stx = SHMEM_RD(bp, func_mb[mb_idx].fw_mb_param);
                bnx2x_func_stats_init(bp);
index 38a83ac..43f2ea5 100644 (file)
@@ -3419,9 +3419,27 @@ static int bond_xmit_hash_policy_l2(struct sk_buff *skb, int count)
 static int bond_open(struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
+       struct slave *slave;
+       int i;
 
        bond->kill_timers = 0;
 
+       /* reset slave->backup and slave->inactive */
+       read_lock(&bond->lock);
+       if (bond->slave_cnt > 0) {
+               read_lock(&bond->curr_slave_lock);
+               bond_for_each_slave(bond, slave, i) {
+                       if ((bond->params.mode == BOND_MODE_ACTIVEBACKUP)
+                               && (slave != bond->curr_active_slave)) {
+                               bond_set_slave_inactive_flags(slave);
+                       } else {
+                               bond_set_slave_active_flags(slave);
+                       }
+               }
+               read_unlock(&bond->curr_slave_lock);
+       }
+       read_unlock(&bond->lock);
+
        INIT_DELAYED_WORK(&bond->mcast_work, bond_resend_igmp_join_requests_delayed);
 
        if (bond_is_lb(bond)) {
index 231385b..c7f3d4e 100644 (file)
@@ -408,7 +408,7 @@ static void plx_pci_del_card(struct pci_dev *pdev)
        struct sja1000_priv *priv;
        int i = 0;
 
-       for (i = 0; i < card->channels; i++) {
+       for (i = 0; i < PLX_PCI_MAX_CHAN; i++) {
                dev = card->net_dev[i];
                if (!dev)
                        continue;
@@ -536,7 +536,6 @@ static int __devinit plx_pci_add_card(struct pci_dev *pdev,
                        if (err) {
                                dev_err(&pdev->dev, "Registering device failed "
                                        "(err=%d)\n", err);
-                               free_sja1000dev(dev);
                                goto failure_cleanup;
                        }
 
@@ -549,6 +548,7 @@ static int __devinit plx_pci_add_card(struct pci_dev *pdev,
                        dev_err(&pdev->dev, "Channel #%d not detected\n",
                                i + 1);
                        free_sja1000dev(dev);
+                       card->net_dev[i] = NULL;
                }
        }
 
index f523f1c..4b70b7e 100644 (file)
@@ -197,7 +197,7 @@ static void slc_bump(struct slcan *sl)
        skb->ip_summed = CHECKSUM_UNNECESSARY;
        memcpy(skb_put(skb, sizeof(struct can_frame)),
               &cf, sizeof(struct can_frame));
-       netif_rx(skb);
+       netif_rx_ni(skb);
 
        sl->dev->stats.rx_packets++;
        sl->dev->stats.rx_bytes += cf.can_dlc;
index f7bbde9..a812492 100644 (file)
@@ -503,9 +503,9 @@ static netdev_tx_t ti_hecc_xmit(struct sk_buff *skb, struct net_device *ndev)
        spin_unlock_irqrestore(&priv->mbx_lock, flags);
 
        /* Prepare mailbox for transmission */
+       data = cf->can_dlc | (get_tx_head_prio(priv) << 8);
        if (cf->can_id & CAN_RTR_FLAG) /* Remote transmission request */
                data |= HECC_CANMCF_RTR;
-       data |= get_tx_head_prio(priv) << 8;
        hecc_write_mbx(priv, mbxno, HECC_CANMCF, data);
 
        if (cf->can_id & CAN_EFF_FLAG) /* Extended frame format */
@@ -923,6 +923,7 @@ static int ti_hecc_probe(struct platform_device *pdev)
        priv->can.do_get_state = ti_hecc_get_state;
        priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
 
+       spin_lock_init(&priv->mbx_lock);
        ndev->irq = irq->start;
        ndev->flags |= IFF_ECHO;
        platform_set_drvdata(pdev, ndev);
index 646c86b..fdb7a17 100644 (file)
@@ -2452,14 +2452,13 @@ static irqreturn_t cas_interruptN(int irq, void *dev_id)
        struct net_device *dev = dev_id;
        struct cas *cp = netdev_priv(dev);
        unsigned long flags;
-       int ring;
+       int ring = (irq == cp->pci_irq_INTC) ? 2 : 3;
        u32 status = readl(cp->regs + REG_PLUS_INTRN_STATUS(ring));
 
        /* check for shared irq */
        if (status == 0)
                return IRQ_NONE;
 
-       ring = (irq == cp->pci_irq_INTC) ? 2 : 3;
        spin_lock_irqsave(&cp->lock, flags);
        if (status & INTR_RX_DONE_ALT) { /* handle rx separately */
 #ifdef USE_NAPI
index c5f0f04..5548d46 100644 (file)
@@ -838,6 +838,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
 
        /* Disable all the interrupts */
        ew32(IMC, 0xFFFFFFFF);
+       E1000_WRITE_FLUSH();
        msleep(10);
 
        /* Test each interrupt */
@@ -856,6 +857,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
                        adapter->test_icr = 0;
                        ew32(IMC, mask);
                        ew32(ICS, mask);
+                       E1000_WRITE_FLUSH();
                        msleep(10);
 
                        if (adapter->test_icr & mask) {
@@ -873,6 +875,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
                adapter->test_icr = 0;
                ew32(IMS, mask);
                ew32(ICS, mask);
+               E1000_WRITE_FLUSH();
                msleep(10);
 
                if (!(adapter->test_icr & mask)) {
@@ -890,6 +893,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
                        adapter->test_icr = 0;
                        ew32(IMC, ~mask & 0x00007FFF);
                        ew32(ICS, ~mask & 0x00007FFF);
+                       E1000_WRITE_FLUSH();
                        msleep(10);
 
                        if (adapter->test_icr) {
@@ -901,6 +905,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
 
        /* Disable all the interrupts */
        ew32(IMC, 0xFFFFFFFF);
+       E1000_WRITE_FLUSH();
        msleep(10);
 
        /* Unhook test interrupt handler */
@@ -1394,6 +1399,7 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter)
                        if (unlikely(++k == txdr->count)) k = 0;
                }
                ew32(TDT, k);
+               E1000_WRITE_FLUSH();
                msleep(200);
                time = jiffies; /* set the start time for the receive */
                good_cnt = 0;
index 1698622..8545c7a 100644 (file)
@@ -446,6 +446,7 @@ s32 e1000_reset_hw(struct e1000_hw *hw)
        /* Must reset the PHY before resetting the MAC */
        if ((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
                ew32(CTRL, (ctrl | E1000_CTRL_PHY_RST));
+               E1000_WRITE_FLUSH();
                msleep(5);
        }
 
@@ -3752,6 +3753,7 @@ static s32 e1000_acquire_eeprom(struct e1000_hw *hw)
                /* Clear SK and CS */
                eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
                ew32(EECD, eecd);
+               E1000_WRITE_FLUSH();
                udelay(1);
        }
 
@@ -3824,6 +3826,7 @@ static void e1000_release_eeprom(struct e1000_hw *hw)
                eecd &= ~E1000_EECD_SK; /* Lower SCK */
 
                ew32(EECD, eecd);
+               E1000_WRITE_FLUSH();
 
                udelay(hw->eeprom.delay_usec);
        } else if (hw->eeprom.type == e1000_eeprom_microwire) {
index 480f259..536b3a5 100644 (file)
@@ -2085,7 +2085,8 @@ struct e1000_info e1000_82574_info = {
                                  | FLAG_HAS_AMT
                                  | FLAG_HAS_CTRLEXT_ON_LOAD,
        .flags2                   = FLAG2_CHECK_PHY_HANG
-                                 | FLAG2_DISABLE_ASPM_L0S,
+                                 | FLAG2_DISABLE_ASPM_L0S
+                                 | FLAG2_NO_DISABLE_RX,
        .pba                    = 32,
        .max_hw_frame_size      = DEFAULT_JUMBO,
        .get_variants           = e1000_get_variants_82571,
@@ -2104,7 +2105,8 @@ struct e1000_info e1000_82583_info = {
                                  | FLAG_HAS_AMT
                                  | FLAG_HAS_JUMBO_FRAMES
                                  | FLAG_HAS_CTRLEXT_ON_LOAD,
-       .flags2                 = FLAG2_DISABLE_ASPM_L0S,
+       .flags2                 = FLAG2_DISABLE_ASPM_L0S
+                                 | FLAG2_NO_DISABLE_RX,
        .pba                    = 32,
        .max_hw_frame_size      = DEFAULT_JUMBO,
        .get_variants           = e1000_get_variants_82571,
index 638d175..8533ad7 100644 (file)
@@ -155,6 +155,9 @@ struct e1000_info;
 #define HV_M_STATUS_SPEED_1000            0x0200
 #define HV_M_STATUS_LINK_UP               0x0040
 
+#define E1000_ICH_FWSM_PCIM2PCI                0x01000000 /* ME PCIm-to-PCI active */
+#define E1000_ICH_FWSM_PCIM2PCI_COUNT  2000
+
 /* Time to wait before putting the device into D3 if there's no link (in ms). */
 #define LINK_TIMEOUT           100
 
@@ -453,6 +456,8 @@ struct e1000_info {
 #define FLAG2_DISABLE_ASPM_L0S            (1 << 7)
 #define FLAG2_DISABLE_AIM                 (1 << 8)
 #define FLAG2_CHECK_PHY_HANG              (1 << 9)
+#define FLAG2_NO_DISABLE_RX               (1 << 10)
+#define FLAG2_PCIM2PCI_ARBITER_WA         (1 << 11)
 
 #define E1000_RX_DESC_PS(R, i)     \
        (&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
index c0ecb2d..e4f4225 100644 (file)
@@ -1313,6 +1313,7 @@ static s32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
        kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
                       E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
        ew32(KMRNCTRLSTA, kmrnctrlsta);
+       e1e_flush();
 
        udelay(2);
 
@@ -1347,6 +1348,7 @@ static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
        kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
                       E1000_KMRNCTRLSTA_OFFSET) | data;
        ew32(KMRNCTRLSTA, kmrnctrlsta);
+       e1e_flush();
 
        udelay(2);
 
index cb1a362..6a0526a 100644 (file)
@@ -28,8 +28,8 @@
 
 /* ethtool support for e1000 */
 
-#include <linux/interrupt.h>
 #include <linux/netdevice.h>
+#include <linux/interrupt.h>
 #include <linux/ethtool.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
@@ -964,6 +964,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
 
        /* Disable all the interrupts */
        ew32(IMC, 0xFFFFFFFF);
+       e1e_flush();
        usleep_range(10000, 20000);
 
        /* Test each interrupt */
@@ -996,6 +997,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
                        adapter->test_icr = 0;
                        ew32(IMC, mask);
                        ew32(ICS, mask);
+                       e1e_flush();
                        usleep_range(10000, 20000);
 
                        if (adapter->test_icr & mask) {
@@ -1014,6 +1016,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
                adapter->test_icr = 0;
                ew32(IMS, mask);
                ew32(ICS, mask);
+               e1e_flush();
                usleep_range(10000, 20000);
 
                if (!(adapter->test_icr & mask)) {
@@ -1032,6 +1035,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
                        adapter->test_icr = 0;
                        ew32(IMC, ~mask & 0x00007FFF);
                        ew32(ICS, ~mask & 0x00007FFF);
+                       e1e_flush();
                        usleep_range(10000, 20000);
 
                        if (adapter->test_icr) {
@@ -1043,6 +1047,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
 
        /* Disable all the interrupts */
        ew32(IMC, 0xFFFFFFFF);
+       e1e_flush();
        usleep_range(10000, 20000);
 
        /* Unhook test interrupt handler */
@@ -1201,7 +1206,8 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
        rx_ring->next_to_clean = 0;
 
        rctl = er32(RCTL);
-       ew32(RCTL, rctl & ~E1000_RCTL_EN);
+       if (!(adapter->flags2 & FLAG2_NO_DISABLE_RX))
+               ew32(RCTL, rctl & ~E1000_RCTL_EN);
        ew32(RDBAL, ((u64) rx_ring->dma & 0xFFFFFFFF));
        ew32(RDBAH, ((u64) rx_ring->dma >> 32));
        ew32(RDLEN, rx_ring->size);
@@ -1276,6 +1282,7 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
                             E1000_CTRL_FD);     /* Force Duplex to FULL */
 
                ew32(CTRL, ctrl_reg);
+               e1e_flush();
                udelay(500);
 
                return 0;
@@ -1418,6 +1425,7 @@ static int e1000_set_82571_fiber_loopback(struct e1000_adapter *adapter)
         */
 #define E1000_SERDES_LB_ON 0x410
        ew32(SCTL, E1000_SERDES_LB_ON);
+       e1e_flush();
        usleep_range(10000, 20000);
 
        return 0;
@@ -1513,6 +1521,7 @@ static void e1000_loopback_cleanup(struct e1000_adapter *adapter)
                    hw->phy.media_type == e1000_media_type_internal_serdes) {
 #define E1000_SERDES_LB_OFF 0x400
                        ew32(SCTL, E1000_SERDES_LB_OFF);
+                       e1e_flush();
                        usleep_range(10000, 20000);
                        break;
                }
@@ -1592,6 +1601,7 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter)
                                k = 0;
                }
                ew32(TDT, k);
+               e1e_flush();
                msleep(200);
                time = jiffies; /* set the start time for the receive */
                good_cnt = 0;
index c175212..54add27 100644 (file)
 #define HV_PM_CTRL             PHY_REG(770, 17)
 
 /* PHY Low Power Idle Control */
-#define I82579_LPI_CTRL                        PHY_REG(772, 20)
-#define I82579_LPI_CTRL_ENABLE_MASK    0x6000
+#define I82579_LPI_CTRL                                PHY_REG(772, 20)
+#define I82579_LPI_CTRL_ENABLE_MASK            0x6000
+#define I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT   0x80
 
 /* EMI Registers */
 #define I82579_EMI_ADDR         0x10
 #define HV_KMRN_MODE_CTRL      PHY_REG(769, 16)
 #define HV_KMRN_MDIO_SLOW      0x0400
 
+/* KMRN FIFO Control and Status */
+#define HV_KMRN_FIFO_CTRLSTA                  PHY_REG(770, 16)
+#define HV_KMRN_FIFO_CTRLSTA_PREAMBLE_MASK    0x7000
+#define HV_KMRN_FIFO_CTRLSTA_PREAMBLE_SHIFT   12
+
 /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
 /* Offset 04h HSFSTS */
 union ich8_hws_flash_status {
@@ -283,6 +289,7 @@ static void e1000_toggle_lanphypc_value_ich8lan(struct e1000_hw *hw)
        ctrl |= E1000_CTRL_LANPHYPC_OVERRIDE;
        ctrl &= ~E1000_CTRL_LANPHYPC_VALUE;
        ew32(CTRL, ctrl);
+       e1e_flush();
        udelay(10);
        ctrl &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
        ew32(CTRL, ctrl);
@@ -656,6 +663,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
        struct e1000_mac_info *mac = &hw->mac;
        s32 ret_val;
        bool link;
+       u16 phy_reg;
 
        /*
         * We only want to go out to the PHY registers to see if Auto-Neg
@@ -688,16 +696,35 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
 
        mac->get_link_status = false;
 
-       if (hw->phy.type == e1000_phy_82578) {
-               ret_val = e1000_link_stall_workaround_hv(hw);
-               if (ret_val)
-                       goto out;
-       }
-
-       if (hw->mac.type == e1000_pch2lan) {
+       switch (hw->mac.type) {
+       case e1000_pch2lan:
                ret_val = e1000_k1_workaround_lv(hw);
                if (ret_val)
                        goto out;
+               /* fall-thru */
+       case e1000_pchlan:
+               if (hw->phy.type == e1000_phy_82578) {
+                       ret_val = e1000_link_stall_workaround_hv(hw);
+                       if (ret_val)
+                               goto out;
+               }
+
+               /*
+                * Workaround for PCHx parts in half-duplex:
+                * Set the number of preambles removed from the packet
+                * when it is passed from the PHY to the MAC to prevent
+                * the MAC from misinterpreting the packet type.
+                */
+               e1e_rphy(hw, HV_KMRN_FIFO_CTRLSTA, &phy_reg);
+               phy_reg &= ~HV_KMRN_FIFO_CTRLSTA_PREAMBLE_MASK;
+
+               if ((er32(STATUS) & E1000_STATUS_FD) != E1000_STATUS_FD)
+                       phy_reg |= (1 << HV_KMRN_FIFO_CTRLSTA_PREAMBLE_SHIFT);
+
+               e1e_wphy(hw, HV_KMRN_FIFO_CTRLSTA, phy_reg);
+               break;
+       default:
+               break;
        }
 
        /*
@@ -787,6 +814,11 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
            (adapter->hw.phy.type == e1000_phy_igp_3))
                adapter->flags |= FLAG_LSC_GIG_SPEED_DROP;
 
+       /* Enable workaround for 82579 w/ ME enabled */
+       if ((adapter->hw.mac.type == e1000_pch2lan) &&
+           (er32(FWSM) & E1000_ICH_FWSM_FW_VALID))
+               adapter->flags2 |= FLAG2_PCIM2PCI_ARBITER_WA;
+
        /* Disable EEE by default until IEEE802.3az spec is finalized */
        if (adapter->flags2 & FLAG2_HAS_EEE)
                adapter->hw.dev_spec.ich8lan.eee_disable = true;
@@ -1230,9 +1262,11 @@ s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable)
        ew32(CTRL, reg);
 
        ew32(CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_SPD_BYPS);
+       e1e_flush();
        udelay(20);
        ew32(CTRL, ctrl_reg);
        ew32(CTRL_EXT, ctrl_ext);
+       e1e_flush();
        udelay(20);
 
 out:
@@ -1352,7 +1386,7 @@ static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw)
                        return ret_val;
 
                /* Preamble tuning for SSC */
-               ret_val = e1e_wphy(hw, PHY_REG(770, 16), 0xA204);
+               ret_val = e1e_wphy(hw, HV_KMRN_FIFO_CTRLSTA, 0xA204);
                if (ret_val)
                        return ret_val;
        }
@@ -1642,6 +1676,7 @@ static s32 e1000_k1_workaround_lv(struct e1000_hw *hw)
        s32 ret_val = 0;
        u16 status_reg = 0;
        u32 mac_reg;
+       u16 phy_reg;
 
        if (hw->mac.type != e1000_pch2lan)
                goto out;
@@ -1656,12 +1691,19 @@ static s32 e1000_k1_workaround_lv(struct e1000_hw *hw)
                mac_reg = er32(FEXTNVM4);
                mac_reg &= ~E1000_FEXTNVM4_BEACON_DURATION_MASK;
 
-               if (status_reg & HV_M_STATUS_SPEED_1000)
+               ret_val = e1e_rphy(hw, I82579_LPI_CTRL, &phy_reg);
+               if (ret_val)
+                       goto out;
+
+               if (status_reg & HV_M_STATUS_SPEED_1000) {
                        mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_8USEC;
-               else
+                       phy_reg &= ~I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT;
+               } else {
                        mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_16USEC;
-
+                       phy_reg |= I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT;
+               }
                ew32(FEXTNVM4, mac_reg);
+               ret_val = e1e_wphy(hw, I82579_LPI_CTRL, phy_reg);
        }
 
 out:
@@ -2134,8 +2176,7 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
 
        ret_val = 0;
        for (i = 0; i < words; i++) {
-               if ((dev_spec->shadow_ram) &&
-                   (dev_spec->shadow_ram[offset+i].modified)) {
+               if (dev_spec->shadow_ram[offset+i].modified) {
                        data[i] = dev_spec->shadow_ram[offset+i].value;
                } else {
                        ret_val = e1000_read_flash_word_ich8lan(hw,
@@ -3090,6 +3131,7 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
        ret_val = e1000_acquire_swflag_ich8lan(hw);
        e_dbg("Issuing a global reset to ich8lan\n");
        ew32(CTRL, (ctrl | E1000_CTRL_RST));
+       /* cannot issue a flush here because it hangs the hardware */
        msleep(20);
 
        if (!ret_val)
index 65580b4..0893ab1 100644 (file)
@@ -190,7 +190,8 @@ s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw)
        /* Check for LOM (vs. NIC) or one of two valid mezzanine cards */
        if (!((nvm_data & NVM_COMPAT_LOM) ||
              (hw->adapter->pdev->device == E1000_DEV_ID_82571EB_SERDES_DUAL) ||
-             (hw->adapter->pdev->device == E1000_DEV_ID_82571EB_SERDES_QUAD)))
+             (hw->adapter->pdev->device == E1000_DEV_ID_82571EB_SERDES_QUAD) ||
+             (hw->adapter->pdev->device == E1000_DEV_ID_82571EB_SERDES)))
                goto out;
 
        ret_val = e1000_read_nvm(hw, NVM_ALT_MAC_ADDR_PTR, 1,
@@ -200,10 +201,10 @@ s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw)
                goto out;
        }
 
-       if (nvm_alt_mac_addr_offset == 0xFFFF) {
+       if ((nvm_alt_mac_addr_offset == 0xFFFF) ||
+           (nvm_alt_mac_addr_offset == 0x0000))
                /* There is no Alternate MAC Address */
                goto out;
-       }
 
        if (hw->bus.func == E1000_FUNC_1)
                nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN1;
@@ -1986,6 +1987,7 @@ static s32 e1000_ready_nvm_eeprom(struct e1000_hw *hw)
                /* Clear SK and CS */
                eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
                ew32(EECD, eecd);
+               e1e_flush();
                udelay(1);
 
                /*
index 4353ad5..2198e61 100644 (file)
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/init.h>
-#include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/vmalloc.h>
 #include <linux/pagemap.h>
 #include <linux/delay.h>
 #include <linux/netdevice.h>
+#include <linux/interrupt.h>
 #include <linux/tcp.h>
 #include <linux/ipv6.h>
 #include <linux/slab.h>
@@ -56,7 +56,7 @@
 
 #define DRV_EXTRAVERSION "-k"
 
-#define DRV_VERSION "1.3.16" DRV_EXTRAVERSION
+#define DRV_VERSION "1.4.4" DRV_EXTRAVERSION
 char e1000e_driver_name[] = "e1000e";
 const char e1000e_driver_version[] = DRV_VERSION;
 
@@ -518,6 +518,63 @@ static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err,
        adapter->hw_csum_good++;
 }
 
+/**
+ * e1000e_update_tail_wa - helper function for e1000e_update_[rt]dt_wa()
+ * @hw: pointer to the HW structure
+ * @tail: address of tail descriptor register
+ * @i: value to write to tail descriptor register
+ *
+ * When updating the tail register, the ME could be accessing Host CSR
+ * registers at the same time.  Normally, this is handled in h/w by an
+ * arbiter but on some parts there is a bug that acknowledges Host accesses
+ * later than it should which could result in the descriptor register to
+ * have an incorrect value.  Workaround this by checking the FWSM register
+ * which has bit 24 set while ME is accessing Host CSR registers, wait
+ * if it is set and try again a number of times.
+ **/
+static inline s32 e1000e_update_tail_wa(struct e1000_hw *hw, u8 __iomem * tail,
+                                       unsigned int i)
+{
+       unsigned int j = 0;
+
+       while ((j++ < E1000_ICH_FWSM_PCIM2PCI_COUNT) &&
+              (er32(FWSM) & E1000_ICH_FWSM_PCIM2PCI))
+               udelay(50);
+
+       writel(i, tail);
+
+       if ((j == E1000_ICH_FWSM_PCIM2PCI_COUNT) && (i != readl(tail)))
+               return E1000_ERR_SWFW_SYNC;
+
+       return 0;
+}
+
+static void e1000e_update_rdt_wa(struct e1000_adapter *adapter, unsigned int i)
+{
+       u8 __iomem *tail = (adapter->hw.hw_addr + adapter->rx_ring->tail);
+       struct e1000_hw *hw = &adapter->hw;
+
+       if (e1000e_update_tail_wa(hw, tail, i)) {
+               u32 rctl = er32(RCTL);
+               ew32(RCTL, rctl & ~E1000_RCTL_EN);
+               e_err("ME firmware caused invalid RDT - resetting\n");
+               schedule_work(&adapter->reset_task);
+       }
+}
+
+static void e1000e_update_tdt_wa(struct e1000_adapter *adapter, unsigned int i)
+{
+       u8 __iomem *tail = (adapter->hw.hw_addr + adapter->tx_ring->tail);
+       struct e1000_hw *hw = &adapter->hw;
+
+       if (e1000e_update_tail_wa(hw, tail, i)) {
+               u32 tctl = er32(TCTL);
+               ew32(TCTL, tctl & ~E1000_TCTL_EN);
+               e_err("ME firmware caused invalid TDT - resetting\n");
+               schedule_work(&adapter->reset_task);
+       }
+}
+
 /**
  * e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended
  * @adapter: address of board private structure
@@ -573,7 +630,10 @@ map_skb:
                         * such as IA-64).
                         */
                        wmb();
-                       writel(i, adapter->hw.hw_addr + rx_ring->tail);
+                       if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
+                               e1000e_update_rdt_wa(adapter, i);
+                       else
+                               writel(i, adapter->hw.hw_addr + rx_ring->tail);
                }
                i++;
                if (i == rx_ring->count)
@@ -673,7 +733,11 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
                         * such as IA-64).
                         */
                        wmb();
-                       writel(i << 1, adapter->hw.hw_addr + rx_ring->tail);
+                       if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
+                               e1000e_update_rdt_wa(adapter, i << 1);
+                       else
+                               writel(i << 1,
+                                      adapter->hw.hw_addr + rx_ring->tail);
                }
 
                i++;
@@ -756,7 +820,10 @@ check_page:
                 * applicable for weak-ordered memory model archs,
                 * such as IA-64). */
                wmb();
-               writel(i, adapter->hw.hw_addr + rx_ring->tail);
+               if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
+                       e1000e_update_rdt_wa(adapter, i);
+               else
+                       writel(i, adapter->hw.hw_addr + rx_ring->tail);
        }
 }
 
@@ -2915,7 +2982,8 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
 
        /* disable receives while setting up the descriptors */
        rctl = er32(RCTL);
-       ew32(RCTL, rctl & ~E1000_RCTL_EN);
+       if (!(adapter->flags2 & FLAG2_NO_DISABLE_RX))
+               ew32(RCTL, rctl & ~E1000_RCTL_EN);
        e1e_flush();
        usleep_range(10000, 20000);
 
@@ -3394,7 +3462,8 @@ void e1000e_down(struct e1000_adapter *adapter)
 
        /* disable receives in the hardware */
        rctl = er32(RCTL);
-       ew32(RCTL, rctl & ~E1000_RCTL_EN);
+       if (!(adapter->flags2 & FLAG2_NO_DISABLE_RX))
+               ew32(RCTL, rctl & ~E1000_RCTL_EN);
        /* flush and sleep below */
 
        netif_stop_queue(netdev);
@@ -3403,6 +3472,7 @@ void e1000e_down(struct e1000_adapter *adapter)
        tctl = er32(TCTL);
        tctl &= ~E1000_TCTL_EN;
        ew32(TCTL, tctl);
+
        /* flush both disables and wait for them to finish */
        e1e_flush();
        usleep_range(10000, 20000);
@@ -4686,7 +4756,12 @@ static void e1000_tx_queue(struct e1000_adapter *adapter,
        wmb();
 
        tx_ring->next_to_use = i;
-       writel(i, adapter->hw.hw_addr + tx_ring->tail);
+
+       if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
+               e1000e_update_tdt_wa(adapter, i);
+       else
+               writel(i, adapter->hw.hw_addr + tx_ring->tail);
+
        /*
         * we need this if more than one processor can write to our tail
         * at a time, it synchronizes IO on IA64/Altix systems
index 2a6ee13..8666476 100644 (file)
@@ -537,6 +537,7 @@ static s32 __e1000_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data,
        kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
                       E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
        ew32(KMRNCTRLSTA, kmrnctrlsta);
+       e1e_flush();
 
        udelay(2);
 
@@ -609,6 +610,7 @@ static s32 __e1000_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data,
        kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
                       E1000_KMRNCTRLSTA_OFFSET) | data;
        ew32(KMRNCTRLSTA, kmrnctrlsta);
+       e1e_flush();
 
        udelay(2);
 
index 5b631fe..e8266cc 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/phy.h>
 #include <linux/fec.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of_net.h>
 
 #include <asm/cacheflush.h>
 
 #define FEC_QUIRK_ENET_MAC             (1 << 0)
 /* Controller needs driver to swap frame */
 #define FEC_QUIRK_SWAP_FRAME           (1 << 1)
+/* Controller uses gasket */
+#define FEC_QUIRK_USE_GASKET           (1 << 2)
 
 static struct platform_device_id fec_devtype[] = {
        {
+               /* keep it for coldfire */
                .name = DRIVER_NAME,
                .driver_data = 0,
+       }, {
+               .name = "imx25-fec",
+               .driver_data = FEC_QUIRK_USE_GASKET,
+       }, {
+               .name = "imx27-fec",
+               .driver_data = 0,
        }, {
                .name = "imx28-fec",
                .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME,
-       },
-       { }
+       }, {
+               /* sentinel */
+       }
 };
+MODULE_DEVICE_TABLE(platform, fec_devtype);
+
+enum imx_fec_type {
+       IMX25_FEC = 1,  /* runs on i.mx25/50/53 */
+       IMX27_FEC,      /* runs on i.mx27/35/51 */
+       IMX28_FEC,
+};
+
+static const struct of_device_id fec_dt_ids[] = {
+       { .compatible = "fsl,imx25-fec", .data = &fec_devtype[IMX25_FEC], },
+       { .compatible = "fsl,imx27-fec", .data = &fec_devtype[IMX27_FEC], },
+       { .compatible = "fsl,imx28-fec", .data = &fec_devtype[IMX28_FEC], },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, fec_dt_ids);
 
 static unsigned char macaddr[ETH_ALEN];
 module_param_array(macaddr, byte, NULL, 0);
@@ -427,7 +456,7 @@ fec_restart(struct net_device *ndev, int duplex)
 
        } else {
 #ifdef FEC_MIIGSK_ENR
-               if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) {
+               if (id_entry->driver_data & FEC_QUIRK_USE_GASKET) {
                        /* disable the gasket and wait */
                        writel(0, fep->hwp + FEC_MIIGSK_ENR);
                        while (readl(fep->hwp + FEC_MIIGSK_ENR) & 4)
@@ -436,8 +465,11 @@ fec_restart(struct net_device *ndev, int duplex)
                        /*
                         * configure the gasket:
                         *   RMII, 50 MHz, no loopback, no echo
+                        *   MII, 25 MHz, no loopback, no echo
                         */
-                       writel(1, fep->hwp + FEC_MIIGSK_CFGR);
+                       writel((fep->phy_interface == PHY_INTERFACE_MODE_RMII) ?
+                                       1 : 0, fep->hwp + FEC_MIIGSK_CFGR);
+
 
                        /* re-enable the gasket */
                        writel(2, fep->hwp + FEC_MIIGSK_ENR);
@@ -734,8 +766,22 @@ static void __inline__ fec_get_mac(struct net_device *ndev)
         */
        iap = macaddr;
 
+#ifdef CONFIG_OF
        /*
-        * 2) from flash or fuse (via platform data)
+        * 2) from device tree data
+        */
+       if (!is_valid_ether_addr(iap)) {
+               struct device_node *np = fep->pdev->dev.of_node;
+               if (np) {
+                       const char *mac = of_get_mac_address(np);
+                       if (mac)
+                               iap = (unsigned char *) mac;
+               }
+       }
+#endif
+
+       /*
+        * 3) from flash or fuse (via platform data)
         */
        if (!is_valid_ether_addr(iap)) {
 #ifdef CONFIG_M5272
@@ -748,7 +794,7 @@ static void __inline__ fec_get_mac(struct net_device *ndev)
        }
 
        /*
-        * 3) FEC mac registers set by bootloader
+        * 4) FEC mac registers set by bootloader
         */
        if (!is_valid_ether_addr(iap)) {
                *((unsigned long *) &tmpaddr[0]) =
@@ -1354,6 +1400,52 @@ static int fec_enet_init(struct net_device *ndev)
        return 0;
 }
 
+#ifdef CONFIG_OF
+static int __devinit fec_get_phy_mode_dt(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+
+       if (np)
+               return of_get_phy_mode(np);
+
+       return -ENODEV;
+}
+
+static int __devinit fec_reset_phy(struct platform_device *pdev)
+{
+       int err, phy_reset;
+       struct device_node *np = pdev->dev.of_node;
+
+       if (!np)
+               return -ENODEV;
+
+       phy_reset = of_get_named_gpio(np, "phy-reset-gpios", 0);
+       err = gpio_request_one(phy_reset, GPIOF_OUT_INIT_LOW, "phy-reset");
+       if (err) {
+               pr_warn("FEC: failed to get gpio phy-reset: %d\n", err);
+               return err;
+       }
+       msleep(1);
+       gpio_set_value(phy_reset, 1);
+
+       return 0;
+}
+#else /* CONFIG_OF */
+static inline int fec_get_phy_mode_dt(struct platform_device *pdev)
+{
+       return -ENODEV;
+}
+
+static inline int fec_reset_phy(struct platform_device *pdev)
+{
+       /*
+        * In case of platform probe, the reset has been done
+        * by machine code.
+        */
+       return 0;
+}
+#endif /* CONFIG_OF */
+
 static int __devinit
 fec_probe(struct platform_device *pdev)
 {
@@ -1362,6 +1454,11 @@ fec_probe(struct platform_device *pdev)
        struct net_device *ndev;
        int i, irq, ret = 0;
        struct resource *r;
+       const struct of_device_id *of_id;
+
+       of_id = of_match_device(fec_dt_ids, &pdev->dev);
+       if (of_id)
+               pdev->id_entry = of_id->data;
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!r)
@@ -1393,9 +1490,18 @@ fec_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, ndev);
 
-       pdata = pdev->dev.platform_data;
-       if (pdata)
-               fep->phy_interface = pdata->phy;
+       ret = fec_get_phy_mode_dt(pdev);
+       if (ret < 0) {
+               pdata = pdev->dev.platform_data;
+               if (pdata)
+                       fep->phy_interface = pdata->phy;
+               else
+                       fep->phy_interface = PHY_INTERFACE_MODE_MII;
+       } else {
+               fep->phy_interface = ret;
+       }
+
+       fec_reset_phy(pdev);
 
        /* This device has up to three irqs on some platforms */
        for (i = 0; i < 3; i++) {
@@ -1530,6 +1636,7 @@ static struct platform_driver fec_driver = {
 #ifdef CONFIG_PM
                .pm     = &fec_pm_ops,
 #endif
+               .of_match_table = fec_dt_ids,
        },
        .id_table = fec_devtype,
        .probe  = fec_probe,
index e55df30..6d5fbd4 100644 (file)
@@ -5615,7 +5615,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
                goto out_error;
        }
 
-       nv_vlan_mode(dev, dev->features);
+       if (id->driver_data & DEV_HAS_VLAN)
+               nv_vlan_mode(dev, dev->features);
 
        netif_carrier_off(dev);
 
index 2659daa..31d5c57 100644 (file)
@@ -2710,8 +2710,13 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
        /* Tell the skb what kind of packet this is */
        skb->protocol = eth_type_trans(skb, dev);
 
-       /* Set vlan tag */
-       if (fcb->flags & RXFCB_VLN)
+       /*
+        * There's need to check for NETIF_F_HW_VLAN_RX here.
+        * Even if vlan rx accel is disabled, on some chips
+        * RXFCB_VLN is pseudo randomly set.
+        */
+       if (dev->features & NETIF_F_HW_VLAN_RX &&
+           fcb->flags & RXFCB_VLN)
                __vlan_hwaccel_put_tag(skb, fcb->vlctl);
 
        /* Send the packet up the stack */
index 6e35069..25a8c2a 100644 (file)
@@ -686,10 +686,21 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u
 {
        unsigned int last_rule_idx = priv->cur_filer_idx;
        unsigned int cmp_rqfpr;
-       unsigned int local_rqfpr[MAX_FILER_IDX + 1];
-       unsigned int local_rqfcr[MAX_FILER_IDX + 1];
+       unsigned int *local_rqfpr;
+       unsigned int *local_rqfcr;
        int i = 0x0, k = 0x0;
        int j = MAX_FILER_IDX, l = 0x0;
+       int ret = 1;
+
+       local_rqfpr = kmalloc(sizeof(unsigned int) * (MAX_FILER_IDX + 1),
+               GFP_KERNEL);
+       local_rqfcr = kmalloc(sizeof(unsigned int) * (MAX_FILER_IDX + 1),
+               GFP_KERNEL);
+       if (!local_rqfpr || !local_rqfcr) {
+               pr_err("Out of memory\n");
+               ret = 0;
+               goto err;
+       }
 
        switch (class) {
        case TCP_V4_FLOW:
@@ -706,7 +717,8 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u
                break;
        default:
                pr_err("Right now this class is not supported\n");
-               return 0;
+               ret = 0;
+               goto err;
        }
 
        for (i = 0; i < MAX_FILER_IDX + 1; i++) {
@@ -721,7 +733,8 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u
 
        if (i == MAX_FILER_IDX + 1) {
                pr_err("No parse rule found, can't create hash rules\n");
-               return 0;
+               ret = 0;
+               goto err;
        }
 
        /* If a match was found, then it begins the starting of a cluster rule
@@ -765,7 +778,10 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u
                priv->cur_filer_idx = priv->cur_filer_idx - 1;
        }
 
-       return 1;
+err:
+       kfree(local_rqfcr);
+       kfree(local_rqfpr);
+       return ret;
 }
 
 static int gfar_set_hash_opts(struct gfar_private *priv, struct ethtool_rxnfc *cmd)
index 1c97861..f67b8ae 100644 (file)
@@ -193,14 +193,9 @@ static void set_alarm(struct etsects *etsects)
 /* Caller must hold etsects->lock. */
 static void set_fipers(struct etsects *etsects)
 {
-       u32 tmr_ctrl = gfar_read(&etsects->regs->tmr_ctrl);
-
-       gfar_write(&etsects->regs->tmr_ctrl,   tmr_ctrl & (~TE));
-       gfar_write(&etsects->regs->tmr_prsc,   etsects->tmr_prsc);
+       set_alarm(etsects);
        gfar_write(&etsects->regs->tmr_fiper1, etsects->tmr_fiper1);
        gfar_write(&etsects->regs->tmr_fiper2, etsects->tmr_fiper2);
-       set_alarm(etsects);
-       gfar_write(&etsects->regs->tmr_ctrl,   tmr_ctrl|TE);
 }
 
 /*
@@ -511,7 +506,7 @@ static int gianfar_ptp_probe(struct platform_device *dev)
        gfar_write(&etsects->regs->tmr_fiper1, etsects->tmr_fiper1);
        gfar_write(&etsects->regs->tmr_fiper2, etsects->tmr_fiper2);
        set_alarm(etsects);
-       gfar_write(&etsects->regs->tmr_ctrl,   tmr_ctrl|FS|RTPE|TE);
+       gfar_write(&etsects->regs->tmr_ctrl,   tmr_ctrl|FS|RTPE|TE|FRD);
 
        spin_unlock_irqrestore(&etsects->lock, flags);
 
index 725399e..70cb7d8 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/bitops.h>
 #include <linux/workqueue.h>
 #include <linux/of.h>
+#include <linux/of_net.h>
 #include <linux/slab.h>
 
 #include <asm/processor.h>
@@ -2506,18 +2507,6 @@ static int __devinit emac_init_config(struct emac_instance *dev)
 {
        struct device_node *np = dev->ofdev->dev.of_node;
        const void *p;
-       unsigned int plen;
-       const char *pm, *phy_modes[] = {
-               [PHY_MODE_NA] = "",
-               [PHY_MODE_MII] = "mii",
-               [PHY_MODE_RMII] = "rmii",
-               [PHY_MODE_SMII] = "smii",
-               [PHY_MODE_RGMII] = "rgmii",
-               [PHY_MODE_TBI] = "tbi",
-               [PHY_MODE_GMII] = "gmii",
-               [PHY_MODE_RTBI] = "rtbi",
-               [PHY_MODE_SGMII] = "sgmii",
-       };
 
        /* Read config from device-tree */
        if (emac_read_uint_prop(np, "mal-device", &dev->mal_ph, 1))
@@ -2566,23 +2555,9 @@ static int __devinit emac_init_config(struct emac_instance *dev)
                dev->mal_burst_size = 256;
 
        /* PHY mode needs some decoding */
-       dev->phy_mode = PHY_MODE_NA;
-       pm = of_get_property(np, "phy-mode", &plen);
-       if (pm != NULL) {
-               int i;
-               for (i = 0; i < ARRAY_SIZE(phy_modes); i++)
-                       if (!strcasecmp(pm, phy_modes[i])) {
-                               dev->phy_mode = i;
-                               break;
-                       }
-       }
-
-       /* Backward compat with non-final DT */
-       if (dev->phy_mode == PHY_MODE_NA && pm != NULL && plen == 4) {
-               u32 nmode = *(const u32 *)pm;
-               if (nmode > PHY_MODE_NA && nmode <= PHY_MODE_SGMII)
-                       dev->phy_mode = nmode;
-       }
+       dev->phy_mode = of_get_phy_mode(np);
+       if (dev->phy_mode < 0)
+               dev->phy_mode = PHY_MODE_NA;
 
        /* Check EMAC version */
        if (of_device_is_compatible(np, "ibm,emac4sync")) {
index 8a61b59..1568278 100644 (file)
@@ -26,6 +26,7 @@
 #define __IBM_NEWEMAC_H
 
 #include <linux/types.h>
+#include <linux/phy.h>
 
 /* EMAC registers                      Write Access rules */
 struct emac_regs {
@@ -106,15 +107,15 @@ struct emac_regs {
 /*
  * PHY mode settings (EMAC <-> ZMII/RGMII bridge <-> PHY)
  */
-#define PHY_MODE_NA    0
-#define PHY_MODE_MII   1
-#define PHY_MODE_RMII  2
-#define PHY_MODE_SMII  3
-#define PHY_MODE_RGMII 4
-#define PHY_MODE_TBI   5
-#define PHY_MODE_GMII  6
-#define PHY_MODE_RTBI  7
-#define PHY_MODE_SGMII 8
+#define PHY_MODE_NA    PHY_INTERFACE_MODE_NA
+#define PHY_MODE_MII   PHY_INTERFACE_MODE_MII
+#define PHY_MODE_RMII  PHY_INTERFACE_MODE_RMII
+#define PHY_MODE_SMII  PHY_INTERFACE_MODE_SMII
+#define PHY_MODE_RGMII PHY_INTERFACE_MODE_RGMII
+#define PHY_MODE_TBI   PHY_INTERFACE_MODE_TBI
+#define PHY_MODE_GMII  PHY_INTERFACE_MODE_GMII
+#define PHY_MODE_RTBI  PHY_INTERFACE_MODE_RTBI
+#define PHY_MODE_SGMII PHY_INTERFACE_MODE_SGMII
 
 /* EMACx_MR0 */
 #define EMAC_MR0_RXI                   0x80000000
index ac9d964..ab4e596 100644 (file)
 #include "emac.h"
 #include "phy.h"
 
-static inline int phy_read(struct mii_phy *phy, int reg)
+#define phy_read _phy_read
+#define phy_write _phy_write
+
+static inline int _phy_read(struct mii_phy *phy, int reg)
 {
        return phy->mdio_read(phy->dev, phy->address, reg);
 }
 
-static inline void phy_write(struct mii_phy *phy, int reg, int val)
+static inline void _phy_write(struct mii_phy *phy, int reg, int val)
 {
        phy->mdio_write(phy->dev, phy->address, reg, val);
 }
index ba99af0..3e66792 100644 (file)
@@ -395,7 +395,7 @@ static inline struct sk_buff *ibmveth_rxq_get_buffer(struct ibmveth_adapter *ada
 }
 
 /* recycle the current buffer on the rx queue */
-static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter)
+static int ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter)
 {
        u32 q_index = adapter->rx_queue.index;
        u64 correlator = adapter->rx_queue.queue_addr[q_index].correlator;
@@ -403,6 +403,7 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter)
        unsigned int index = correlator & 0xffffffffUL;
        union ibmveth_buf_desc desc;
        unsigned long lpar_rc;
+       int ret = 1;
 
        BUG_ON(pool >= IBMVETH_NUM_BUFF_POOLS);
        BUG_ON(index >= adapter->rx_buff_pool[pool].size);
@@ -410,7 +411,7 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter)
        if (!adapter->rx_buff_pool[pool].active) {
                ibmveth_rxq_harvest_buffer(adapter);
                ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[pool]);
-               return;
+               goto out;
        }
 
        desc.fields.flags_len = IBMVETH_BUF_VALID |
@@ -423,12 +424,16 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter)
                netdev_dbg(adapter->netdev, "h_add_logical_lan_buffer failed "
                           "during recycle rc=%ld", lpar_rc);
                ibmveth_remove_buffer_from_pool(adapter, adapter->rx_queue.queue_addr[adapter->rx_queue.index].correlator);
+               ret = 0;
        }
 
        if (++adapter->rx_queue.index == adapter->rx_queue.num_slots) {
                adapter->rx_queue.index = 0;
                adapter->rx_queue.toggle = !adapter->rx_queue.toggle;
        }
+
+out:
+       return ret;
 }
 
 static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter)
@@ -1084,8 +1089,9 @@ restart_poll:
                                if (rx_flush)
                                        ibmveth_flush_buffer(skb->data,
                                                length + offset);
+                               if (!ibmveth_rxq_recycle_buffer(adapter))
+                                       kfree_skb(skb);
                                skb = new_skb;
-                               ibmveth_rxq_recycle_buffer(adapter);
                        } else {
                                ibmveth_rxq_harvest_buffer(adapter);
                                skb_reserve(skb, offset);
index 7dcd65c..4040712 100644 (file)
@@ -285,6 +285,7 @@ static s32 igb_ready_nvm_eeprom(struct e1000_hw *hw)
                /* Clear SK and CS */
                eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
                wr32(E1000_EECD, eecd);
+               wrfl();
                udelay(1);
                timeout = NVM_MAX_RETRY_SPI;
 
index ff244ce..414b022 100644 (file)
@@ -1225,6 +1225,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)
 
        /* Disable all the interrupts */
        wr32(E1000_IMC, ~0);
+       wrfl();
        msleep(10);
 
        /* Define all writable bits for ICS */
@@ -1268,6 +1269,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)
 
                        wr32(E1000_IMC, mask);
                        wr32(E1000_ICS, mask);
+                       wrfl();
                        msleep(10);
 
                        if (adapter->test_icr & mask) {
@@ -1289,6 +1291,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)
 
                wr32(E1000_IMS, mask);
                wr32(E1000_ICS, mask);
+               wrfl();
                msleep(10);
 
                if (!(adapter->test_icr & mask)) {
@@ -1310,6 +1313,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)
 
                        wr32(E1000_IMC, ~mask);
                        wr32(E1000_ICS, ~mask);
+                       wrfl();
                        msleep(10);
 
                        if (adapter->test_icr & mask) {
@@ -1321,6 +1325,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)
 
        /* Disable all the interrupts */
        wr32(E1000_IMC, ~0);
+       wrfl();
        msleep(10);
 
        /* Unhook test interrupt handler */
index dc59905..40d4c40 100644 (file)
@@ -1052,6 +1052,7 @@ msi_only:
                kfree(adapter->vf_data);
                adapter->vf_data = NULL;
                wr32(E1000_IOVCTL, E1000_IOVCTL_REUSE_VFQ);
+               wrfl();
                msleep(100);
                dev_info(&adapter->pdev->dev, "IOV Disabled\n");
        }
@@ -2022,7 +2023,7 @@ static int __devinit igb_probe(struct pci_dev *pdev,
 
        if (hw->bus.func == 0)
                hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data);
-       else if (hw->mac.type == e1000_82580)
+       else if (hw->mac.type >= e1000_82580)
                hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A +
                                 NVM_82580_LAN_FUNC_OFFSET(hw->bus.func), 1,
                                 &eeprom_data);
@@ -2198,6 +2199,7 @@ static void __devexit igb_remove(struct pci_dev *pdev)
                kfree(adapter->vf_data);
                adapter->vf_data = NULL;
                wr32(E1000_IOVCTL, E1000_IOVCTL_REUSE_VFQ);
+               wrfl();
                msleep(100);
                dev_info(&pdev->dev, "IOV Disabled\n");
        }
index 1330c8e..40ed066 100644 (file)
@@ -1226,6 +1226,7 @@ static void igbvf_configure_tx(struct igbvf_adapter *adapter)
        /* disable transmits */
        txdctl = er32(TXDCTL(0));
        ew32(TXDCTL(0), txdctl & ~E1000_TXDCTL_QUEUE_ENABLE);
+       e1e_flush();
        msleep(10);
 
        /* Setup the HW Tx Head and Tail descriptor pointers */
@@ -1306,6 +1307,7 @@ static void igbvf_configure_rx(struct igbvf_adapter *adapter)
        /* disable receives */
        rxdctl = er32(RXDCTL(0));
        ew32(RXDCTL(0), rxdctl & ~E1000_RXDCTL_QUEUE_ENABLE);
+       e1e_flush();
        msleep(10);
 
        rdlen = rx_ring->count * sizeof(union e1000_adv_rx_desc);
index 4488bd5..8266067 100644 (file)
@@ -22,6 +22,8 @@
  *  - DMA transfer support
  *  - FIFO mode support
  */
+#include <linux/io.h>
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
index 52a7c86..ed7d7d6 100644 (file)
@@ -12,6 +12,8 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/io.h>
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
@@ -511,7 +513,7 @@ static void sh_sir_tx(struct sh_sir_self *self, int phase)
 
 static int sh_sir_read_data(struct sh_sir_self *self)
 {
-       u16 val;
+       u16 val = 0;
        int timeout = 1024;
 
        while (timeout--) {
index 954f6e9..8b1c348 100644 (file)
@@ -2405,8 +2405,6 @@ static int __init smsc_superio_lpc(unsigned short cfg_base)
  * addresses making a subsystem device table necessary.
  */
 #ifdef CONFIG_PCI
-#define PCIID_VENDOR_INTEL 0x8086
-#define PCIID_VENDOR_ALI 0x10b9
 static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __initdata = {
        /*
         * Subsystems needing entries:
@@ -2416,7 +2414,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini
         */
        {
                /* Guessed entry */
-               .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */
+               .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801DBM LPC bridge */
                .device = 0x24cc,
                .subvendor = 0x103c,
                .subdevice = 0x08bc,
@@ -2429,7 +2427,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini
                .name = "HP nx5000 family",
        },
        {
-               .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */
+               .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801DBM LPC bridge */
                .device = 0x24cc,
                .subvendor = 0x103c,
                .subdevice = 0x088c,
@@ -2443,7 +2441,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini
                .name = "HP nc8000 family",
        },
        {
-               .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */
+               .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801DBM LPC bridge */
                .device = 0x24cc,
                .subvendor = 0x103c,
                .subdevice = 0x0890,
@@ -2456,7 +2454,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini
                .name = "HP nc6000 family",
        },
        {
-               .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */
+               .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801DBM LPC bridge */
                .device = 0x24cc,
                .subvendor = 0x0e11,
                .subdevice = 0x0860,
@@ -2471,7 +2469,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini
        },
        {
                /* Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge */
-               .vendor = PCIID_VENDOR_INTEL,
+               .vendor = PCI_VENDOR_ID_INTEL,
                .device = 0x24c0,
                .subvendor = 0x1179,
                .subdevice = 0xffff, /* 0xffff is "any" */
@@ -2484,7 +2482,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini
                .name = "Toshiba laptop with Intel 82801DB/DBL LPC bridge",
        },
        {
-               .vendor = PCIID_VENDOR_INTEL, /* Intel 82801CAM ISA bridge */
+               .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801CAM ISA bridge */
                .device = 0x248c,
                .subvendor = 0x1179,
                .subdevice = 0xffff, /* 0xffff is "any" */
@@ -2498,7 +2496,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini
        },
        {
                /* 82801DBM (ICH4-M) LPC Interface Bridge */
-               .vendor = PCIID_VENDOR_INTEL,
+               .vendor = PCI_VENDOR_ID_INTEL,
                .device = 0x24cc,
                .subvendor = 0x1179,
                .subdevice = 0xffff, /* 0xffff is "any" */
@@ -2512,7 +2510,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini
        },
        {
                /* ALi M1533/M1535 PCI to ISA Bridge [Aladdin IV/V/V+] */
-               .vendor = PCIID_VENDOR_ALI,
+               .vendor = PCI_VENDOR_ID_AL,
                .device = 0x1533,
                .subvendor = 0x1179,
                .subdevice = 0xffff, /* 0xffff is "any" */
index c982ab9..38b362b 100644 (file)
@@ -57,6 +57,7 @@ ixgb_raise_clock(struct ixgb_hw *hw,
         */
        *eecd_reg = *eecd_reg | IXGB_EECD_SK;
        IXGB_WRITE_REG(hw, EECD, *eecd_reg);
+       IXGB_WRITE_FLUSH(hw);
        udelay(50);
 }
 
@@ -75,6 +76,7 @@ ixgb_lower_clock(struct ixgb_hw *hw,
         */
        *eecd_reg = *eecd_reg & ~IXGB_EECD_SK;
        IXGB_WRITE_REG(hw, EECD, *eecd_reg);
+       IXGB_WRITE_FLUSH(hw);
        udelay(50);
 }
 
@@ -112,6 +114,7 @@ ixgb_shift_out_bits(struct ixgb_hw *hw,
                        eecd_reg |= IXGB_EECD_DI;
 
                IXGB_WRITE_REG(hw, EECD, eecd_reg);
+               IXGB_WRITE_FLUSH(hw);
 
                udelay(50);
 
@@ -206,21 +209,25 @@ ixgb_standby_eeprom(struct ixgb_hw *hw)
        /*  Deselect EEPROM  */
        eecd_reg &= ~(IXGB_EECD_CS | IXGB_EECD_SK);
        IXGB_WRITE_REG(hw, EECD, eecd_reg);
+       IXGB_WRITE_FLUSH(hw);
        udelay(50);
 
        /*  Clock high  */
        eecd_reg |= IXGB_EECD_SK;
        IXGB_WRITE_REG(hw, EECD, eecd_reg);
+       IXGB_WRITE_FLUSH(hw);
        udelay(50);
 
        /*  Select EEPROM  */
        eecd_reg |= IXGB_EECD_CS;
        IXGB_WRITE_REG(hw, EECD, eecd_reg);
+       IXGB_WRITE_FLUSH(hw);
        udelay(50);
 
        /*  Clock low  */
        eecd_reg &= ~IXGB_EECD_SK;
        IXGB_WRITE_REG(hw, EECD, eecd_reg);
+       IXGB_WRITE_FLUSH(hw);
        udelay(50);
 }
 
@@ -239,11 +246,13 @@ ixgb_clock_eeprom(struct ixgb_hw *hw)
        /*  Rising edge of clock  */
        eecd_reg |= IXGB_EECD_SK;
        IXGB_WRITE_REG(hw, EECD, eecd_reg);
+       IXGB_WRITE_FLUSH(hw);
        udelay(50);
 
        /*  Falling edge of clock  */
        eecd_reg &= ~IXGB_EECD_SK;
        IXGB_WRITE_REG(hw, EECD, eecd_reg);
+       IXGB_WRITE_FLUSH(hw);
        udelay(50);
 }
 
index 6cb2e42..3d61a9e 100644 (file)
@@ -149,6 +149,7 @@ ixgb_adapter_stop(struct ixgb_hw *hw)
         */
        IXGB_WRITE_REG(hw, RCTL, IXGB_READ_REG(hw, RCTL) & ~IXGB_RCTL_RXEN);
        IXGB_WRITE_REG(hw, TCTL, IXGB_READ_REG(hw, TCTL) & ~IXGB_TCTL_TXEN);
+       IXGB_WRITE_FLUSH(hw);
        msleep(IXGB_DELAY_BEFORE_RESET);
 
        /* Issue a global reset to the MAC.  This will reset the chip's
@@ -1220,6 +1221,7 @@ ixgb_optics_reset_bcm(struct ixgb_hw *hw)
        ctrl &= ~IXGB_CTRL0_SDP2;
        ctrl |= IXGB_CTRL0_SDP3;
        IXGB_WRITE_REG(hw, CTRL0, ctrl);
+       IXGB_WRITE_FLUSH(hw);
 
        /* SerDes needs extra delay */
        msleep(IXGB_SUN_PHY_RESET_DELAY);
index 3b3dd4d..34f30ec 100644 (file)
@@ -213,6 +213,7 @@ static s32 ixgbe_init_phy_ops_82599(struct ixgbe_hw *hw)
        switch (hw->phy.type) {
        case ixgbe_phy_tn:
                phy->ops.check_link = &ixgbe_check_phy_link_tnx;
+               phy->ops.setup_link = &ixgbe_setup_phy_link_tnx;
                phy->ops.get_firmware_version =
                             &ixgbe_get_phy_firmware_version_tnx;
                break;
index 777051f..fc1375f 100644 (file)
@@ -2632,6 +2632,7 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index)
                autoc_reg |= IXGBE_AUTOC_AN_RESTART;
                autoc_reg |= IXGBE_AUTOC_FLU;
                IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg);
+               IXGBE_WRITE_FLUSH(hw);
                usleep_range(10000, 20000);
        }
 
index dc64955..82d4244 100644 (file)
@@ -1378,6 +1378,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data)
 
        /* Disable all the interrupts */
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF);
+       IXGBE_WRITE_FLUSH(&adapter->hw);
        usleep_range(10000, 20000);
 
        /* Test each interrupt */
@@ -1398,6 +1399,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data)
                                        ~mask & 0x00007FFF);
                        IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS,
                                        ~mask & 0x00007FFF);
+                       IXGBE_WRITE_FLUSH(&adapter->hw);
                        usleep_range(10000, 20000);
 
                        if (adapter->test_icr & mask) {
@@ -1415,6 +1417,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data)
                adapter->test_icr = 0;
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask);
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask);
+               IXGBE_WRITE_FLUSH(&adapter->hw);
                usleep_range(10000, 20000);
 
                if (!(adapter->test_icr &mask)) {
@@ -1435,6 +1438,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data)
                                        ~mask & 0x00007FFF);
                        IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS,
                                        ~mask & 0x00007FFF);
+                       IXGBE_WRITE_FLUSH(&adapter->hw);
                        usleep_range(10000, 20000);
 
                        if (adapter->test_icr) {
@@ -1446,6 +1450,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data)
 
        /* Disable all the interrupts */
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF);
+       IXGBE_WRITE_FLUSH(&adapter->hw);
        usleep_range(10000, 20000);
 
        /* Unhook test interrupt handler */
index 1be6175..2279039 100644 (file)
@@ -184,6 +184,7 @@ static inline void ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
        vmdctl = IXGBE_READ_REG(hw, IXGBE_VT_CTL);
        vmdctl &= ~IXGBE_VT_CTL_POOL_MASK;
        IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vmdctl);
+       IXGBE_WRITE_FLUSH(hw);
 
        /* take a breather then clean up driver data */
        msleep(100);
@@ -1005,7 +1006,7 @@ static int __ixgbe_notify_dca(struct device *dev, void *data)
        struct ixgbe_adapter *adapter = dev_get_drvdata(dev);
        unsigned long event = *(unsigned long *)data;
 
-       if (!(adapter->flags & IXGBE_FLAG_DCA_ENABLED))
+       if (!(adapter->flags & IXGBE_FLAG_DCA_CAPABLE))
                return 0;
 
        switch (event) {
@@ -1458,8 +1459,10 @@ static void ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
                if (ixgbe_rx_is_fcoe(adapter, rx_desc)) {
                        ddp_bytes = ixgbe_fcoe_ddp(adapter, rx_desc, skb,
                                                   staterr);
-                       if (!ddp_bytes)
+                       if (!ddp_bytes) {
+                               dev_kfree_skb_any(skb);
                                goto next_desc;
+                       }
                }
 #endif /* IXGBE_FCOE */
                ixgbe_receive_skb(q_vector, skb, staterr, rx_ring, rx_desc);
index 735f686..f7ca351 100644 (file)
@@ -1585,6 +1585,7 @@ static s32 ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
        *i2cctl |= IXGBE_I2C_CLK_OUT;
 
        IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl);
+       IXGBE_WRITE_FLUSH(hw);
 
        /* SCL rise time (1000ns) */
        udelay(IXGBE_I2C_T_RISE);
@@ -1605,6 +1606,7 @@ static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
        *i2cctl &= ~IXGBE_I2C_CLK_OUT;
 
        IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl);
+       IXGBE_WRITE_FLUSH(hw);
 
        /* SCL fall time (300ns) */
        udelay(IXGBE_I2C_T_FALL);
@@ -1628,6 +1630,7 @@ static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data)
                *i2cctl &= ~IXGBE_I2C_DATA_OUT;
 
        IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl);
+       IXGBE_WRITE_FLUSH(hw);
 
        /* Data rise/fall (1000ns/300ns) and set-up time (250ns) */
        udelay(IXGBE_I2C_T_RISE + IXGBE_I2C_T_FALL + IXGBE_I2C_T_SU_DATA);
index bec30ed..2696c78 100644 (file)
@@ -162,6 +162,7 @@ mac_reset_top:
        ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
        ctrl_ext |= IXGBE_CTRL_EXT_PFRSTD;
        IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
+       IXGBE_WRITE_FLUSH(hw);
 
        msleep(50);
 
index 0fcdc25..dc4e305 100644 (file)
@@ -322,6 +322,9 @@ static void macb_tx(struct macb *bp)
                for (i = 0; i < TX_RING_SIZE; i++)
                        bp->tx_ring[i].ctrl = MACB_BIT(TX_USED);
 
+               /* Add wrap bit */
+               bp->tx_ring[TX_RING_SIZE - 1].ctrl |= MACB_BIT(TX_WRAP);
+
                /* free transmit buffer in upper layer*/
                for (tail = bp->tx_tail; tail != head; tail = NEXT_TX(tail)) {
                        struct ring_info *rp = &bp->tx_skb[tail];
index 5e71091..5ada5b4 100644 (file)
@@ -128,7 +128,7 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
        memset(context, 0, sizeof *context);
 
        context->base_qpn = cpu_to_be32(base_qpn);
-       context->n_mac = 0x7;
+       context->n_mac = 0x2;
        context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT |
                                       base_qpn);
        context->mcast = cpu_to_be32(m_promisc << SET_PORT_MC_PROMISC_SHIFT |
index c94b342..f0ee35d 100644 (file)
@@ -1117,6 +1117,8 @@ static int mlx4_init_port_info(struct mlx4_dev *dev, int port)
        info->port = port;
        mlx4_init_mac_table(dev, &info->mac_table);
        mlx4_init_vlan_table(dev, &info->vlan_table);
+       info->base_qpn = dev->caps.reserved_qps_base[MLX4_QP_REGION_ETH_ADDR] +
+                       (port - 1) * (1 << log_num_mac);
 
        sprintf(info->dev_name, "mlx4_port%d", port);
        info->port_attr.attr.name = info->dev_name;
index 1f95afd..609e0ec 100644 (file)
@@ -258,9 +258,12 @@ void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, int qpn)
        if (validate_index(dev, table, index))
                goto out;
 
-       table->entries[index] = 0;
-       mlx4_set_port_mac_table(dev, port, table->entries);
-       --table->total;
+       /* Check whether this address has reference count */
+       if (!(--table->refs[index])) {
+               table->entries[index] = 0;
+               mlx4_set_port_mac_table(dev, port, table->entries);
+               --table->total;
+       }
 out:
        mutex_unlock(&table->mutex);
 }
index cd6c231..ed47585 100644 (file)
@@ -9201,7 +9201,7 @@ static int __devinit niu_ldg_init(struct niu *np)
 
        first_chan = 0;
        for (i = 0; i < port; i++)
-               first_chan += parent->rxchan_per_port[port];
+               first_chan += parent->rxchan_per_port[i];
        num_chan = parent->rxchan_per_port[port];
 
        for (i = first_chan; i < (first_chan + num_chan); i++) {
@@ -9217,7 +9217,7 @@ static int __devinit niu_ldg_init(struct niu *np)
 
        first_chan = 0;
        for (i = 0; i < port; i++)
-               first_chan += parent->txchan_per_port[port];
+               first_chan += parent->txchan_per_port[i];
        num_chan = parent->txchan_per_port[port];
        for (i = first_chan; i < (first_chan + num_chan); i++) {
                err = niu_ldg_assign_ldn(np, parent,
index 1cd9394..cffbc03 100644 (file)
@@ -809,7 +809,7 @@ static int smc91c92_config(struct pcmcia_device *link)
     struct net_device *dev = link->priv;
     struct smc_private *smc = netdev_priv(dev);
     char *name;
-    int i, j, rev;
+    int i, rev, j = 0;
     unsigned int ioaddr;
     u_long mir;
 
index 8b3090d..80b6f36 100644 (file)
@@ -82,7 +82,7 @@ static int cards_found;
 /*
  * VLB I/O addresses
  */
-static unsigned int pcnet32_portlist[] __initdata =
+static unsigned int pcnet32_portlist[] =
     { 0x300, 0x320, 0x340, 0x360, 0 };
 
 static int pcnet32_debug;
index 2cd8dc5..cb6e0b4 100644 (file)
@@ -34,8 +34,7 @@
 #define PAGESEL                0x13
 #define LAYER4         0x02
 #define LAYER2         0x01
-#define MAX_RXTS       4
-#define MAX_TXTS       4
+#define MAX_RXTS       64
 #define N_EXT_TS       1
 #define PSF_PTPVER     2
 #define PSF_EVNT       0x4000
@@ -218,7 +217,7 @@ static void phy2rxts(struct phy_rxts *p, struct rxts *rxts)
        rxts->seqid = p->seqid;
        rxts->msgtype = (p->msgtype >> 12) & 0xf;
        rxts->hash = p->msgtype & 0x0fff;
-       rxts->tmo = jiffies + HZ;
+       rxts->tmo = jiffies + 2;
 }
 
 static u64 phy2txts(struct phy_txts *p)
index 0620ba9..04bb8fc 100644 (file)
@@ -25,8 +25,9 @@
 /* DP83865 phy identifier values */
 #define DP83865_PHY_ID 0x20005c7a
 
-#define DP83865_INT_MASK_REG 0x15
-#define DP83865_INT_MASK_STATUS 0x14
+#define DP83865_INT_STATUS     0x14
+#define DP83865_INT_MASK       0x15
+#define DP83865_INT_CLEAR      0x17
 
 #define DP83865_INT_REMOTE_FAULT 0x0008
 #define DP83865_INT_ANE_COMPLETED 0x0010
@@ -68,21 +69,25 @@ static int ns_config_intr(struct phy_device *phydev)
        int err;
 
        if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
-               err = phy_write(phydev, DP83865_INT_MASK_REG,
+               err = phy_write(phydev, DP83865_INT_MASK,
                                DP83865_INT_MASK_DEFAULT);
        else
-               err = phy_write(phydev, DP83865_INT_MASK_REG, 0);
+               err = phy_write(phydev, DP83865_INT_MASK, 0);
 
        return err;
 }
 
 static int ns_ack_interrupt(struct phy_device *phydev)
 {
-       int ret = phy_read(phydev, DP83865_INT_MASK_STATUS);
+       int ret = phy_read(phydev, DP83865_INT_STATUS);
        if (ret < 0)
                return ret;
 
-       return 0;
+       /* Clear the interrupt status bit by writing a “1”
+        * to the corresponding bit in INT_CLEAR (2:0 are reserved) */
+       ret = phy_write(phydev, DP83865_INT_CLEAR, ret & ~0x7);
+
+       return ret;
 }
 
 static void ns_giga_speed_fallback(struct phy_device *phydev, int mode)
index 7d9c650..02339b3 100644 (file)
@@ -239,6 +239,7 @@ static DEFINE_PCI_DEVICE_TABLE(rtl8169_pci_tbl) = {
        { PCI_DEVICE(PCI_VENDOR_ID_REALTEK,     0x8168), 0, 0, RTL_CFG_1 },
        { PCI_DEVICE(PCI_VENDOR_ID_REALTEK,     0x8169), 0, 0, RTL_CFG_0 },
        { PCI_DEVICE(PCI_VENDOR_ID_DLINK,       0x4300), 0, 0, RTL_CFG_0 },
+       { PCI_DEVICE(PCI_VENDOR_ID_DLINK,       0x4302), 0, 0, RTL_CFG_0 },
        { PCI_DEVICE(PCI_VENDOR_ID_AT,          0xc107), 0, 0, RTL_CFG_0 },
        { PCI_DEVICE(0x16ec,                    0x0116), 0, 0, RTL_CFG_0 },
        { PCI_VENDOR_ID_LINKSYS,                0x1032,
@@ -1091,6 +1092,21 @@ rtl_w1w0_eri(void __iomem *ioaddr, int addr, u32 mask, u32 p, u32 m, int type)
        rtl_eri_write(ioaddr, addr, mask, (val & ~m) | p, type);
 }
 
+struct exgmac_reg {
+       u16 addr;
+       u16 mask;
+       u32 val;
+};
+
+static void rtl_write_exgmac_batch(void __iomem *ioaddr,
+                                  const struct exgmac_reg *r, int len)
+{
+       while (len-- > 0) {
+               rtl_eri_write(ioaddr, r->addr, r->mask, r->val, ERIAR_EXGMAC);
+               r++;
+       }
+}
+
 static u8 rtl8168d_efuse_read(void __iomem *ioaddr, int reg_addr)
 {
        u8 value = 0xff;
@@ -3116,6 +3132,18 @@ static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr)
        RTL_W32(MAC0, low);
        RTL_R32(MAC0);
 
+       if (tp->mac_version == RTL_GIGA_MAC_VER_34) {
+               const struct exgmac_reg e[] = {
+                       { .addr = 0xe0, ERIAR_MASK_1111, .val = low },
+                       { .addr = 0xe4, ERIAR_MASK_1111, .val = high },
+                       { .addr = 0xf0, ERIAR_MASK_1111, .val = low << 16 },
+                       { .addr = 0xf4, ERIAR_MASK_1111, .val = high << 16 |
+                                                               low  >> 16 },
+               };
+
+               rtl_write_exgmac_batch(ioaddr, e, ARRAY_SIZE(e));
+       }
+
        RTL_W8(Cfg9346, Cfg9346_Lock);
 
        spin_unlock_irq(&tp->lock);
index ad35c21..1c1666e 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/dma-mapping.h>
 #include <linux/etherdevice.h>
 #include <linux/delay.h>
@@ -30,6 +31,7 @@
 #include <linux/phy.h>
 #include <linux/cache.h>
 #include <linux/io.h>
+#include <linux/interrupt.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/ethtool.h>
index 8ad7bfb..3c0f131 100644 (file)
@@ -1825,6 +1825,16 @@ static int sis190_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                generic_mii_ioctl(&tp->mii_if, if_mii(ifr), cmd, NULL);
 }
 
+static int sis190_mac_addr(struct net_device  *dev, void *p)
+{
+       int rc;
+
+       rc = eth_mac_addr(dev, p);
+       if (!rc)
+               sis190_init_rxfilter(dev);
+       return rc;
+}
+
 static const struct net_device_ops sis190_netdev_ops = {
        .ndo_open               = sis190_open,
        .ndo_stop               = sis190_close,
@@ -1833,7 +1843,7 @@ static const struct net_device_ops sis190_netdev_ops = {
        .ndo_tx_timeout         = sis190_tx_timeout,
        .ndo_set_multicast_list = sis190_set_rx_mode,
        .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_set_mac_address    = sis190_mac_addr,
        .ndo_validate_addr      = eth_validate_addr,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller     = sis190_netpoll,
index f11b3f3..4c61753 100644 (file)
@@ -367,7 +367,7 @@ static void sl_bump(struct slip *sl)
        memcpy(skb_put(skb, count), sl->rbuff, count);
        skb_reset_mac_header(skb);
        skb->protocol = htons(ETH_P_IP);
-       netif_rx(skb);
+       netif_rx_ni(skb);
        dev->stats.rx_packets++;
 }
 
index be745ae..ade35dd 100644 (file)
 #include <asm/byteorder.h>
 #include <asm/uaccess.h>
 #include <asm/irq.h>
-#include <asm/prom.h>
 
 #ifdef CONFIG_SPARC
 #include <asm/idprom.h>
+#include <asm/prom.h>
 #endif
 
 #ifdef CONFIG_PPC_PMAC
 #include <asm/pci-bridge.h>
+#include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/pmac_feature.h>
 #endif
index fd622a6..f06fb78 100644 (file)
@@ -53,7 +53,7 @@
 #include <linux/usb/usbnet.h>
 #include <linux/usb/cdc.h>
 
-#define        DRIVER_VERSION                          "01-June-2011"
+#define        DRIVER_VERSION                          "04-Aug-2011"
 
 /* CDC NCM subclass 3.2.1 */
 #define USB_CDC_NCM_NDP16_LENGTH_MIN           0x10
@@ -163,35 +163,8 @@ cdc_ncm_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
        usb_make_path(dev->udev, info->bus_info, sizeof(info->bus_info));
 }
 
-static int
-cdc_ncm_do_request(struct cdc_ncm_ctx *ctx, struct usb_cdc_notification *req,
-                  void *data, u16 flags, u16 *actlen, u16 timeout)
-{
-       int err;
-
-       err = usb_control_msg(ctx->udev, (req->bmRequestType & USB_DIR_IN) ?
-                               usb_rcvctrlpipe(ctx->udev, 0) :
-                               usb_sndctrlpipe(ctx->udev, 0),
-                               req->bNotificationType, req->bmRequestType,
-                               req->wValue,
-                               req->wIndex, data,
-                               req->wLength, timeout);
-
-       if (err < 0) {
-               if (actlen)
-                       *actlen = 0;
-               return err;
-       }
-
-       if (actlen)
-               *actlen = err;
-
-       return 0;
-}
-
 static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx)
 {
-       struct usb_cdc_notification req;
        u32 val;
        u8 flags;
        u8 iface_no;
@@ -200,14 +173,14 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx)
 
        iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber;
 
-       req.bmRequestType = USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE;
-       req.bNotificationType = USB_CDC_GET_NTB_PARAMETERS;
-       req.wValue = 0;
-       req.wIndex = cpu_to_le16(iface_no);
-       req.wLength = cpu_to_le16(sizeof(ctx->ncm_parm));
-
-       err = cdc_ncm_do_request(ctx, &req, &ctx->ncm_parm, 0, NULL, 1000);
-       if (err) {
+       err = usb_control_msg(ctx->udev,
+                               usb_rcvctrlpipe(ctx->udev, 0),
+                               USB_CDC_GET_NTB_PARAMETERS,
+                               USB_TYPE_CLASS | USB_DIR_IN
+                                | USB_RECIP_INTERFACE,
+                               0, iface_no, &ctx->ncm_parm,
+                               sizeof(ctx->ncm_parm), 10000);
+       if (err < 0) {
                pr_debug("failed GET_NTB_PARAMETERS\n");
                return 1;
        }
@@ -253,31 +226,43 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx)
 
        /* inform device about NTB input size changes */
        if (ctx->rx_max != le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize)) {
-               req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT |
-                                                       USB_RECIP_INTERFACE;
-               req.bNotificationType = USB_CDC_SET_NTB_INPUT_SIZE;
-               req.wValue = 0;
-               req.wIndex = cpu_to_le16(iface_no);
 
                if (flags & USB_CDC_NCM_NCAP_NTB_INPUT_SIZE) {
-                       struct usb_cdc_ncm_ndp_input_size ndp_in_sz;
-
-                       req.wLength = 8;
-                       ndp_in_sz.dwNtbInMaxSize = cpu_to_le32(ctx->rx_max);
-                       ndp_in_sz.wNtbInMaxDatagrams =
-                                       cpu_to_le16(CDC_NCM_DPT_DATAGRAMS_MAX);
-                       ndp_in_sz.wReserved = 0;
-                       err = cdc_ncm_do_request(ctx, &req, &ndp_in_sz, 0, NULL,
-                                                                       1000);
-               } else {
-                       __le32 dwNtbInMaxSize = cpu_to_le32(ctx->rx_max);
+                       struct usb_cdc_ncm_ndp_input_size *ndp_in_sz;
 
-                       req.wLength = 4;
-                       err = cdc_ncm_do_request(ctx, &req, &dwNtbInMaxSize, 0,
-                                                               NULL, 1000);
-               }
+                       ndp_in_sz = kzalloc(sizeof(*ndp_in_sz), GFP_KERNEL);
+                       if (!ndp_in_sz) {
+                               err = -ENOMEM;
+                               goto size_err;
+                       }
 
-               if (err)
+                       err = usb_control_msg(ctx->udev,
+                                       usb_sndctrlpipe(ctx->udev, 0),
+                                       USB_CDC_SET_NTB_INPUT_SIZE,
+                                       USB_TYPE_CLASS | USB_DIR_OUT
+                                        | USB_RECIP_INTERFACE,
+                                       0, iface_no, ndp_in_sz, 8, 1000);
+                       kfree(ndp_in_sz);
+               } else {
+                       __le32 *dwNtbInMaxSize;
+                       dwNtbInMaxSize = kzalloc(sizeof(*dwNtbInMaxSize),
+                                       GFP_KERNEL);
+                       if (!dwNtbInMaxSize) {
+                               err = -ENOMEM;
+                               goto size_err;
+                       }
+                       *dwNtbInMaxSize = cpu_to_le32(ctx->rx_max);
+
+                       err = usb_control_msg(ctx->udev,
+                                       usb_sndctrlpipe(ctx->udev, 0),
+                                       USB_CDC_SET_NTB_INPUT_SIZE,
+                                       USB_TYPE_CLASS | USB_DIR_OUT
+                                        | USB_RECIP_INTERFACE,
+                                       0, iface_no, dwNtbInMaxSize, 4, 1000);
+                       kfree(dwNtbInMaxSize);
+               }
+size_err:
+               if (err < 0)
                        pr_debug("Setting NTB Input Size failed\n");
        }
 
@@ -332,29 +317,24 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx)
 
        /* set CRC Mode */
        if (flags & USB_CDC_NCM_NCAP_CRC_MODE) {
-               req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT |
-                                                       USB_RECIP_INTERFACE;
-               req.bNotificationType = USB_CDC_SET_CRC_MODE;
-               req.wValue = cpu_to_le16(USB_CDC_NCM_CRC_NOT_APPENDED);
-               req.wIndex = cpu_to_le16(iface_no);
-               req.wLength = 0;
-
-               err = cdc_ncm_do_request(ctx, &req, NULL, 0, NULL, 1000);
-               if (err)
+               err = usb_control_msg(ctx->udev, usb_sndctrlpipe(ctx->udev, 0),
+                               USB_CDC_SET_CRC_MODE,
+                               USB_TYPE_CLASS | USB_DIR_OUT
+                                | USB_RECIP_INTERFACE,
+                               USB_CDC_NCM_CRC_NOT_APPENDED,
+                               iface_no, NULL, 0, 1000);
+               if (err < 0)
                        pr_debug("Setting CRC mode off failed\n");
        }
 
        /* set NTB format, if both formats are supported */
        if (ntb_fmt_supported & USB_CDC_NCM_NTH32_SIGN) {
-               req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT |
-                                                       USB_RECIP_INTERFACE;
-               req.bNotificationType = USB_CDC_SET_NTB_FORMAT;
-               req.wValue = cpu_to_le16(USB_CDC_NCM_NTB16_FORMAT);
-               req.wIndex = cpu_to_le16(iface_no);
-               req.wLength = 0;
-
-               err = cdc_ncm_do_request(ctx, &req, NULL, 0, NULL, 1000);
-               if (err)
+               err = usb_control_msg(ctx->udev, usb_sndctrlpipe(ctx->udev, 0),
+                               USB_CDC_SET_NTB_FORMAT, USB_TYPE_CLASS
+                                | USB_DIR_OUT | USB_RECIP_INTERFACE,
+                               USB_CDC_NCM_NTB16_FORMAT,
+                               iface_no, NULL, 0, 1000);
+               if (err < 0)
                        pr_debug("Setting NTB format to 16-bit failed\n");
        }
 
@@ -362,23 +342,29 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx)
 
        /* set Max Datagram Size (MTU) */
        if (flags & USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE) {
-               __le16 max_datagram_size;
+               __le16 *max_datagram_size;
                u16 eth_max_sz = le16_to_cpu(ctx->ether_desc->wMaxSegmentSize);
 
-               req.bmRequestType = USB_TYPE_CLASS | USB_DIR_IN |
-                                                       USB_RECIP_INTERFACE;
-               req.bNotificationType = USB_CDC_GET_MAX_DATAGRAM_SIZE;
-               req.wValue = 0;
-               req.wIndex = cpu_to_le16(iface_no);
-               req.wLength = cpu_to_le16(2);
+               max_datagram_size = kzalloc(sizeof(*max_datagram_size),
+                               GFP_KERNEL);
+               if (!max_datagram_size) {
+                       err = -ENOMEM;
+                       goto max_dgram_err;
+               }
 
-               err = cdc_ncm_do_request(ctx, &req, &max_datagram_size, 0, NULL,
-                                                                       1000);
-               if (err) {
+               err = usb_control_msg(ctx->udev, usb_rcvctrlpipe(ctx->udev, 0),
+                               USB_CDC_GET_MAX_DATAGRAM_SIZE,
+                               USB_TYPE_CLASS | USB_DIR_IN
+                                | USB_RECIP_INTERFACE,
+                               0, iface_no, max_datagram_size,
+                               2, 1000);
+               if (err < 0) {
                        pr_debug("GET_MAX_DATAGRAM_SIZE failed, use size=%u\n",
                                                CDC_NCM_MIN_DATAGRAM_SIZE);
+                       kfree(max_datagram_size);
                } else {
-                       ctx->max_datagram_size = le16_to_cpu(max_datagram_size);
+                       ctx->max_datagram_size =
+                               le16_to_cpu(*max_datagram_size);
                        /* Check Eth descriptor value */
                        if (eth_max_sz < CDC_NCM_MAX_DATAGRAM_SIZE) {
                                if (ctx->max_datagram_size > eth_max_sz)
@@ -395,17 +381,17 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx)
                                        CDC_NCM_MIN_DATAGRAM_SIZE;
 
                        /* if value changed, update device */
-                       req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT |
-                                                       USB_RECIP_INTERFACE;
-                       req.bNotificationType = USB_CDC_SET_MAX_DATAGRAM_SIZE;
-                       req.wValue = 0;
-                       req.wIndex = cpu_to_le16(iface_no);
-                       req.wLength = 2;
-                       max_datagram_size = cpu_to_le16(ctx->max_datagram_size);
-
-                       err = cdc_ncm_do_request(ctx, &req, &max_datagram_size,
-                                                               0, NULL, 1000);
-                       if (err)
+                       err = usb_control_msg(ctx->udev,
+                                               usb_sndctrlpipe(ctx->udev, 0),
+                                               USB_CDC_SET_MAX_DATAGRAM_SIZE,
+                                               USB_TYPE_CLASS | USB_DIR_OUT
+                                                | USB_RECIP_INTERFACE,
+                                               0,
+                                               iface_no, max_datagram_size,
+                                               2, 1000);
+                       kfree(max_datagram_size);
+max_dgram_err:
+                       if (err < 0)
                                pr_debug("SET_MAX_DATAGRAM_SIZE failed\n");
                }
 
@@ -671,7 +657,7 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
        u32 rem;
        u32 offset;
        u32 last_offset;
-       u16 n = 0;
+       u16 n = 0, index;
        u8 ready2send = 0;
 
        /* if there is a remaining skb, it gets priority */
@@ -859,8 +845,8 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
                                        cpu_to_le16(sizeof(ctx->tx_ncm.nth16));
        ctx->tx_ncm.nth16.wSequence = cpu_to_le16(ctx->tx_seq);
        ctx->tx_ncm.nth16.wBlockLength = cpu_to_le16(last_offset);
-       ctx->tx_ncm.nth16.wNdpIndex = ALIGN(sizeof(struct usb_cdc_ncm_nth16),
-                                                       ctx->tx_ndp_modulus);
+       index = ALIGN(sizeof(struct usb_cdc_ncm_nth16), ctx->tx_ndp_modulus);
+       ctx->tx_ncm.nth16.wNdpIndex = cpu_to_le16(index);
 
        memcpy(skb_out->data, &(ctx->tx_ncm.nth16), sizeof(ctx->tx_ncm.nth16));
        ctx->tx_seq++;
@@ -873,12 +859,11 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
        ctx->tx_ncm.ndp16.wLength = cpu_to_le16(rem);
        ctx->tx_ncm.ndp16.wNextNdpIndex = 0; /* reserved */
 
-       memcpy(((u8 *)skb_out->data) + ctx->tx_ncm.nth16.wNdpIndex,
+       memcpy(((u8 *)skb_out->data) + index,
                                                &(ctx->tx_ncm.ndp16),
                                                sizeof(ctx->tx_ncm.ndp16));
 
-       memcpy(((u8 *)skb_out->data) + ctx->tx_ncm.nth16.wNdpIndex +
-                                       sizeof(ctx->tx_ncm.ndp16),
+       memcpy(((u8 *)skb_out->data) + index + sizeof(ctx->tx_ncm.ndp16),
                                        &(ctx->tx_ncm.dpe16),
                                        (ctx->tx_curr_frame_num + 1) *
                                        sizeof(struct usb_cdc_ncm_dpe16));
index 15772b1..13c1f04 100644 (file)
@@ -59,6 +59,7 @@
 #define USB_PRODUCT_IPHONE_3G   0x1292
 #define USB_PRODUCT_IPHONE_3GS  0x1294
 #define USB_PRODUCT_IPHONE_4   0x1297
+#define USB_PRODUCT_IPHONE_4_VZW 0x129c
 
 #define IPHETH_USBINTF_CLASS    255
 #define IPHETH_USBINTF_SUBCLASS 253
@@ -98,6 +99,10 @@ static struct usb_device_id ipheth_table[] = {
                USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4,
                IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
                IPHETH_USBINTF_PROTO) },
+       { USB_DEVICE_AND_INTERFACE_INFO(
+               USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4_VZW,
+               IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
+               IPHETH_USBINTF_PROTO) },
        { }
 };
 MODULE_DEVICE_TABLE(usb, ipheth_table);
index 041fb7d..ef3b236 100644 (file)
@@ -977,7 +977,6 @@ static void rtl8150_disconnect(struct usb_interface *intf)
        usb_set_intfdata(intf, NULL);
        if (dev) {
                set_bit(RTL8150_UNPLUG, &dev->flags);
-               tasklet_disable(&dev->tl);
                tasklet_kill(&dev->tl);
                unregister_netdev(dev->netdev);
                unlink_all_urbs(dev);
index deb1eca..7c5336c 100644 (file)
@@ -515,10 +515,6 @@ static void velocity_init_cam_filter(struct velocity_info *vptr)
        mac_set_cam_mask(regs, vptr->mCAMmask);
 
        /* Enable VCAMs */
-
-       if (test_bit(0, vptr->active_vlans))
-               WORD_REG_BITS_ON(MCFG_RTGOPT, &regs->MCFG);
-
        for_each_set_bit(vid, vptr->active_vlans, VLAN_N_VID) {
                mac_set_vlan_cam(regs, i, (u8 *) &vid);
                vptr->vCAMmask[i / 8] |= 0x1 << (i % 8);
index 1cbacb3..0959583 100644 (file)
@@ -1929,14 +1929,17 @@ static void
 vmxnet3_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
 {
        struct vmxnet3_adapter *adapter = netdev_priv(netdev);
-       u32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
-       unsigned long flags;
 
-       VMXNET3_SET_VFTABLE_ENTRY(vfTable, vid);
-       spin_lock_irqsave(&adapter->cmd_lock, flags);
-       VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
-                              VMXNET3_CMD_UPDATE_VLAN_FILTERS);
-       spin_unlock_irqrestore(&adapter->cmd_lock, flags);
+       if (!(netdev->flags & IFF_PROMISC)) {
+               u32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
+               unsigned long flags;
+
+               VMXNET3_SET_VFTABLE_ENTRY(vfTable, vid);
+               spin_lock_irqsave(&adapter->cmd_lock, flags);
+               VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
+                                      VMXNET3_CMD_UPDATE_VLAN_FILTERS);
+               spin_unlock_irqrestore(&adapter->cmd_lock, flags);
+       }
 
        set_bit(vid, adapter->active_vlans);
 }
@@ -1946,14 +1949,17 @@ static void
 vmxnet3_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
 {
        struct vmxnet3_adapter *adapter = netdev_priv(netdev);
-       u32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
-       unsigned long flags;
 
-       VMXNET3_CLEAR_VFTABLE_ENTRY(vfTable, vid);
-       spin_lock_irqsave(&adapter->cmd_lock, flags);
-       VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
-                              VMXNET3_CMD_UPDATE_VLAN_FILTERS);
-       spin_unlock_irqrestore(&adapter->cmd_lock, flags);
+       if (!(netdev->flags & IFF_PROMISC)) {
+               u32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
+               unsigned long flags;
+
+               VMXNET3_CLEAR_VFTABLE_ENTRY(vfTable, vid);
+               spin_lock_irqsave(&adapter->cmd_lock, flags);
+               VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
+                                      VMXNET3_CMD_UPDATE_VLAN_FILTERS);
+               spin_unlock_irqrestore(&adapter->cmd_lock, flags);
+       }
 
        clear_bit(vid, adapter->active_vlans);
 }
index c052a0d..5441ad1 100644 (file)
@@ -648,6 +648,8 @@ static const struct pcmcia_device_id hostap_cs_ids[] = {
                                         0x74c5e40d),
        PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "Intersil",
                                         0x4b801a17),
+       PCMCIA_DEVICE_MANF_CARD_PROD_ID3(0x0156, 0x0002, "Version 01.02",
+                                        0x4b74baa0),
        PCMCIA_MFC_DEVICE_PROD_ID12(0, "SanDisk", "ConnectPlus",
                                    0x7a954bd9, 0x74be00c6),
        PCMCIA_DEVICE_PROD_ID123(
index 3f7fc4a..d7dbc00 100644 (file)
@@ -239,7 +239,6 @@ static int orinoco_cs_resume(struct pcmcia_device *link)
 
 static const struct pcmcia_device_id orinoco_cs_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), /* 3Com AirConnect PCI 777A */
-       PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), /* Lucent Orinoco and old Intersil */
        PCMCIA_DEVICE_MANF_CARD(0x016b, 0x0001), /* Ericsson WLAN Card C11 */
        PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a), /* Nortel Networks eMobility 802.11 Wireless Adapter */
        PCMCIA_DEVICE_MANF_CARD(0x0261, 0x0002), /* AirWay 802.11 Adapter (PCMCIA) */
@@ -272,6 +271,7 @@ static const struct pcmcia_device_id orinoco_cs_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PCI CARD HARMONY 80211B", 0xc6536a5e, 0x9f494e26),
        PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "11Mbps WLAN Card", 0x43d74cb4, 0x579bd91b),
        PCMCIA_DEVICE_PROD_ID12("Symbol Technologies", "LA4111 Spectrum24 Wireless LAN PC Card", 0x3f02b4d6, 0x3663cb0e),
+       PCMCIA_DEVICE_MANF_CARD_PROD_ID3(0x0156, 0x0002, "Version 01.01", 0xd27deb1a), /* Lucent Orinoco */
 #ifdef CONFIG_HERMES_PRISM
        /* Only entries that certainly identify Prism chipset */
        PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), /* SonicWALL Long Range Wireless Card */
@@ -321,6 +321,9 @@ static const struct pcmcia_device_id orinoco_cs_ids[] = {
        PCMCIA_DEVICE_PROD_ID3("ISL37100P", 0x630d52b2),
        PCMCIA_DEVICE_PROD_ID3("ISL37101P-10", 0xdd97a26b),
        PCMCIA_DEVICE_PROD_ID3("ISL37300P", 0xc9049a39),
+
+       /* This may be Agere or Intersil Firmware */
+       PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002),
 #endif
        PCMCIA_DEVICE_NULL,
 };
index da1f4b9..72c33fb 100644 (file)
@@ -610,6 +610,6 @@ void __iomem *of_iomap(struct device_node *np, int index)
        if (of_address_to_resource(np, index, &res))
                return NULL;
 
-       return ioremap(res.start, 1 + res.end - res.start);
+       return ioremap(res.start, resource_size(&res));
 }
 EXPORT_SYMBOL(of_iomap);
index 02ed367..3ff22e3 100644 (file)
@@ -610,8 +610,9 @@ EXPORT_SYMBOL(of_find_node_by_phandle);
  *
  * The out_value is modified only if a valid u32 value can be decoded.
  */
-int of_property_read_u32_array(const struct device_node *np, char *propname,
-                              u32 *out_values, size_t sz)
+int of_property_read_u32_array(const struct device_node *np,
+                              const char *propname, u32 *out_values,
+                              size_t sz)
 {
        struct property *prop = of_find_property(np, propname, NULL);
        const __be32 *val;
@@ -645,7 +646,7 @@ EXPORT_SYMBOL_GPL(of_property_read_u32_array);
  *
  * The out_string pointer is modified only if a valid string can be decoded.
  */
-int of_property_read_string(struct device_node *np, char *propname,
+int of_property_read_string(struct device_node *np, const char *propname,
                                const char **out_string)
 {
        struct property *prop = of_find_property(np, propname, NULL);
index 3007662..ef0105f 100644 (file)
@@ -127,8 +127,8 @@ EXPORT_SYMBOL(of_gpio_count);
  * gpio chips. This function performs only one sanity check: whether gpio
  * is less than ngpios (that is specified in the gpio_chip).
  */
-static int of_gpio_simple_xlate(struct gpio_chip *gc, struct device_node *np,
-                               const void *gpio_spec, u32 *flags)
+int of_gpio_simple_xlate(struct gpio_chip *gc, struct device_node *np,
+                        const void *gpio_spec, u32 *flags)
 {
        const __be32 *gpio = gpio_spec;
        const u32 n = be32_to_cpup(gpio);
@@ -152,6 +152,7 @@ static int of_gpio_simple_xlate(struct gpio_chip *gc, struct device_node *np,
 
        return n;
 }
+EXPORT_SYMBOL(of_gpio_simple_xlate);
 
 /**
  * of_mm_gpiochip_add - Add memory mapped GPIO chip (bank)
index 86f334a..bb18471 100644 (file)
@@ -8,6 +8,51 @@
 #include <linux/etherdevice.h>
 #include <linux/kernel.h>
 #include <linux/of_net.h>
+#include <linux/phy.h>
+
+/**
+ * It maps 'enum phy_interface_t' found in include/linux/phy.h
+ * into the device tree binding of 'phy-mode', so that Ethernet
+ * device driver can get phy interface from device tree.
+ */
+static const char *phy_modes[] = {
+       [PHY_INTERFACE_MODE_NA]         = "",
+       [PHY_INTERFACE_MODE_MII]        = "mii",
+       [PHY_INTERFACE_MODE_GMII]       = "gmii",
+       [PHY_INTERFACE_MODE_SGMII]      = "sgmii",
+       [PHY_INTERFACE_MODE_TBI]        = "tbi",
+       [PHY_INTERFACE_MODE_RMII]       = "rmii",
+       [PHY_INTERFACE_MODE_RGMII]      = "rgmii",
+       [PHY_INTERFACE_MODE_RGMII_ID]   = "rgmii-id",
+       [PHY_INTERFACE_MODE_RGMII_RXID] = "rgmii-rxid",
+       [PHY_INTERFACE_MODE_RGMII_TXID] = "rgmii-txid",
+       [PHY_INTERFACE_MODE_RTBI]       = "rtbi",
+       [PHY_INTERFACE_MODE_SMII]       = "smii",
+};
+
+/**
+ * of_get_phy_mode - Get phy mode for given device_node
+ * @np:        Pointer to the given device_node
+ *
+ * The function gets phy interface string from property 'phy-mode',
+ * and return its index in phy_modes table, or errno in error case.
+ */
+const int of_get_phy_mode(struct device_node *np)
+{
+       const char *pm;
+       int err, i;
+
+       err = of_property_read_string(np, "phy-mode", &pm);
+       if (err < 0)
+               return err;
+
+       for (i = 0; i < ARRAY_SIZE(phy_modes); i++)
+               if (!strcasecmp(pm, phy_modes[i]))
+                       return i;
+
+       return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(of_get_phy_mode);
 
 /**
  * Search the device tree for the best MAC address to use.  'mac-address' is
index 8f3faf3..095f29e 100644 (file)
@@ -408,7 +408,7 @@ got_one:
 }
 EXPORT_SYMBOL(acpi_get_hp_hw_control_from_firmware);
 
-static int is_ejectable(acpi_handle handle)
+static int pcihp_is_ejectable(acpi_handle handle)
 {
        acpi_status status;
        acpi_handle tmp;
@@ -442,7 +442,7 @@ int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle)
                return 0;
        if (bridge_handle != parent_handle)
                return 0;
-       return is_ejectable(handle);
+       return pcihp_is_ejectable(handle);
 }
 EXPORT_SYMBOL_GPL(acpi_pci_check_ejectable);
 
@@ -450,7 +450,7 @@ static acpi_status
 check_hotplug(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
        int *found = (int *)context;
-       if (is_ejectable(handle)) {
+       if (pcihp_is_ejectable(handle)) {
                *found = 1;
                return AE_CTRL_TERMINATE;
        }
index a70fa89..2202857 100644 (file)
@@ -110,7 +110,7 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val,
 }
 
 
-static struct acpi_dock_ops acpiphp_dock_ops = {
+static const struct acpi_dock_ops acpiphp_dock_ops = {
        .handler = handle_hotplug_event_func,
 };
 
index 4952c3b..f1ce99c 100644 (file)
@@ -840,8 +840,9 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        /* Need to read VID early b/c it's used to differentiate CPQ and INTC
         * discovery
         */
-       rc = pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor_id);
-       if (rc || ((vendor_id != PCI_VENDOR_ID_COMPAQ) && (vendor_id != PCI_VENDOR_ID_INTEL))) {
+       vendor_id = pdev->vendor;
+       if ((vendor_id != PCI_VENDOR_ID_COMPAQ) &&
+           (vendor_id != PCI_VENDOR_ID_INTEL)) {
                err(msg_HPC_non_compaq_or_intel);
                rc = -ENODEV;
                goto err_disable_device;
@@ -868,11 +869,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        /* TODO: This code can be made to support non-Compaq or Intel
         * subsystem IDs
         */
-       rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vid);
-       if (rc) {
-               err("%s : pci_read_config_word failed\n", __func__);
-               goto err_disable_device;
-       }
+       subsystem_vid = pdev->subsystem_vendor;
        dbg("Subsystem Vendor ID: %x\n", subsystem_vid);
        if ((subsystem_vid != PCI_VENDOR_ID_COMPAQ) && (subsystem_vid != PCI_VENDOR_ID_INTEL)) {
                err(msg_HPC_non_compaq_or_intel);
@@ -887,11 +884,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_disable_device;
        }
 
-       rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsystem_deviceid);
-       if (rc) {
-               err("%s : pci_read_config_word failed\n", __func__);
-               goto err_free_ctrl;
-       }
+       subsystem_deviceid = pdev->subsystem_device;
 
        info("Hot Plug Subsystem Device ID: %x\n", subsystem_deviceid);
 
index 085dbb5..1e9c9aa 100644 (file)
@@ -213,6 +213,9 @@ static int board_added(struct slot *p_slot)
                goto err_exit;
        }
 
+       /* Wait for 1 second after checking link training status */
+       msleep(1000);
+
        /* Check for a power fault */
        if (ctrl->power_fault_detected || pciehp_query_power_fault(p_slot)) {
                ctrl_err(ctrl, "Power fault on slot %s\n", slot_name(p_slot));
index 50a23da..96dc473 100644 (file)
@@ -275,16 +275,9 @@ int pciehp_check_link_status(struct controller *ctrl)
          * hot-plug capable downstream port. But old controller might
          * not implement it. In this case, we wait for 1000 ms.
          */
-        if (ctrl->link_active_reporting){
-                /* Wait for Data Link Layer Link Active bit to be set */
+        if (ctrl->link_active_reporting)
                 pcie_wait_link_active(ctrl);
-                /*
-                 * We must wait for 100 ms after the Data Link Layer
-                 * Link Active bit reads 1b before initiating a
-                 * configuration access to the hot added device.
-                 */
-                msleep(100);
-        } else
+        else
                 msleep(1000);
 
        retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status);
index 749fdf0..753b21a 100644 (file)
@@ -158,47 +158,6 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp)
         */
 }
 
-/* Program PCIE MaxPayload setting on device: ensure parent maxpayload <= device */
-static int pci_set_payload(struct pci_dev *dev)
-{
-       int pos, ppos;
-       u16 pctl, psz;
-       u16 dctl, dsz, dcap, dmax;
-       struct pci_dev *parent;
-
-       parent = dev->bus->self;
-       pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
-       if (!pos)
-               return 0;
-
-       /* Read Device MaxPayload capability and setting */
-       pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &dctl);
-       pci_read_config_word(dev, pos + PCI_EXP_DEVCAP, &dcap);
-       dsz = (dctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5;
-       dmax = (dcap & PCI_EXP_DEVCAP_PAYLOAD);
-
-       /* Read Parent MaxPayload setting */
-       ppos = pci_find_capability(parent, PCI_CAP_ID_EXP);
-       if (!ppos)
-               return 0;
-       pci_read_config_word(parent, ppos + PCI_EXP_DEVCTL, &pctl);
-       psz = (pctl &  PCI_EXP_DEVCTL_PAYLOAD) >> 5;
-
-       /* If parent payload > device max payload -> error
-        * If parent payload > device payload -> set speed
-        * If parent payload <= device payload -> do nothing
-        */
-       if (psz > dmax)
-               return -1;
-       else if (psz > dsz) {
-               dev_info(&dev->dev, "Setting MaxPayload to %d\n", 128 << psz);
-               pci_write_config_word(dev, pos + PCI_EXP_DEVCTL,
-                                     (dctl & ~PCI_EXP_DEVCTL_PAYLOAD) +
-                                     (psz << 5));
-       }
-       return 0;
-}
-
 void pci_configure_slot(struct pci_dev *dev)
 {
        struct pci_dev *cdev;
@@ -210,9 +169,7 @@ void pci_configure_slot(struct pci_dev *dev)
                        (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)))
                return;
 
-       ret = pci_set_payload(dev);
-       if (ret)
-               dev_warn(&dev->dev, "could not set device max payload\n");
+       pcie_bus_configure_settings(dev->bus, dev->bus->self->pcie_mpss);
 
        memset(&hpp, 0, sizeof(hpp));
        ret = pci_get_hp_params(dev, &hpp);
index c94d37e..f092993 100644 (file)
@@ -55,7 +55,7 @@ struct device_node * __weak pcibios_get_phb_of_node(struct pci_bus *bus)
         */
        if (bus->bridge->of_node)
                return of_node_get(bus->bridge->of_node);
-       if (bus->bridge->parent->of_node)
+       if (bus->bridge->parent && bus->bridge->parent->of_node)
                return of_node_get(bus->bridge->parent->of_node);
        return NULL;
 }
index 692671b..0ce6742 100644 (file)
@@ -77,6 +77,8 @@ unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE;
 unsigned long pci_hotplug_io_size  = DEFAULT_HOTPLUG_IO_SIZE;
 unsigned long pci_hotplug_mem_size = DEFAULT_HOTPLUG_MEM_SIZE;
 
+enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_PERFORMANCE;
+
 /*
  * The default CLS is used if arch didn't set CLS explicitly and not
  * all pci devices agree on the same value.  Arch can override either
@@ -1905,7 +1907,7 @@ void pci_enable_ari(struct pci_dev *dev)
 {
        int pos;
        u32 cap;
-       u16 ctrl;
+       u16 flags, ctrl;
        struct pci_dev *bridge;
 
        if (!pci_is_pcie(dev) || dev->devfn)
@@ -1923,6 +1925,11 @@ void pci_enable_ari(struct pci_dev *dev)
        if (!pos)
                return;
 
+       /* ARI is a PCIe v2 feature */
+       pci_read_config_word(bridge, pos + PCI_EXP_FLAGS, &flags);
+       if ((flags & PCI_EXP_FLAGS_VERS) < 2)
+               return;
+
        pci_read_config_dword(bridge, pos + PCI_EXP_DEVCAP2, &cap);
        if (!(cap & PCI_EXP_DEVCAP2_ARI))
                return;
@@ -3186,7 +3193,7 @@ EXPORT_SYMBOL(pcie_get_readrq);
  * @rq: maximum memory read count in bytes
  *    valid values are 128, 256, 512, 1024, 2048, 4096
  *
- * If possible sets maximum read byte count
+ * If possible sets maximum memory read request in bytes
  */
 int pcie_set_readrq(struct pci_dev *dev, int rq)
 {
@@ -3209,7 +3216,7 @@ int pcie_set_readrq(struct pci_dev *dev, int rq)
        if ((ctl & PCI_EXP_DEVCTL_READRQ) != v) {
                ctl &= ~PCI_EXP_DEVCTL_READRQ;
                ctl |= v;
-               err = pci_write_config_dword(dev, cap + PCI_EXP_DEVCTL, ctl);
+               err = pci_write_config_word(dev, cap + PCI_EXP_DEVCTL, ctl);
        }
 
 out:
@@ -3217,6 +3224,67 @@ out:
 }
 EXPORT_SYMBOL(pcie_set_readrq);
 
+/**
+ * pcie_get_mps - get PCI Express maximum payload size
+ * @dev: PCI device to query
+ *
+ * Returns maximum payload size in bytes
+ *    or appropriate error value.
+ */
+int pcie_get_mps(struct pci_dev *dev)
+{
+       int ret, cap;
+       u16 ctl;
+
+       cap = pci_pcie_cap(dev);
+       if (!cap)
+               return -EINVAL;
+
+       ret = pci_read_config_word(dev, cap + PCI_EXP_DEVCTL, &ctl);
+       if (!ret)
+               ret = 128 << ((ctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5);
+
+       return ret;
+}
+
+/**
+ * pcie_set_mps - set PCI Express maximum payload size
+ * @dev: PCI device to query
+ * @mps: maximum payload size in bytes
+ *    valid values are 128, 256, 512, 1024, 2048, 4096
+ *
+ * If possible sets maximum payload size
+ */
+int pcie_set_mps(struct pci_dev *dev, int mps)
+{
+       int cap, err = -EINVAL;
+       u16 ctl, v;
+
+       if (mps < 128 || mps > 4096 || !is_power_of_2(mps))
+               goto out;
+
+       v = ffs(mps) - 8;
+       if (v > dev->pcie_mpss) 
+               goto out;
+       v <<= 5;
+
+       cap = pci_pcie_cap(dev);
+       if (!cap)
+               goto out;
+
+       err = pci_read_config_word(dev, cap + PCI_EXP_DEVCTL, &ctl);
+       if (err)
+               goto out;
+
+       if ((ctl & PCI_EXP_DEVCTL_PAYLOAD) != v) {
+               ctl &= ~PCI_EXP_DEVCTL_PAYLOAD;
+               ctl |= v;
+               err = pci_write_config_word(dev, cap + PCI_EXP_DEVCTL, ctl);
+       }
+out:
+       return err;
+}
+
 /**
  * pci_select_bars - Make BAR mask from the type of resource
  * @dev: the PCI device for which BAR mask is made
@@ -3500,6 +3568,10 @@ static int __init pci_setup(char *str)
                                pci_hotplug_io_size = memparse(str + 9, &str);
                        } else if (!strncmp(str, "hpmemsize=", 10)) {
                                pci_hotplug_mem_size = memparse(str + 10, &str);
+                       } else if (!strncmp(str, "pcie_bus_safe", 13)) {
+                               pcie_bus_config = PCIE_BUS_SAFE;
+                       } else if (!strncmp(str, "pcie_bus_perf", 13)) {
+                               pcie_bus_config = PCIE_BUS_PERFORMANCE;
                        } else {
                                printk(KERN_ERR "PCI: Unknown option `%s'\n",
                                                str);
index c8cee76..b74084e 100644 (file)
@@ -283,6 +283,8 @@ static inline int pci_iov_bus_range(struct pci_bus *bus)
 
 #endif /* CONFIG_PCI_IOV */
 
+extern unsigned long pci_cardbus_resource_alignment(struct resource *);
+
 static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
                                         struct resource *res)
 {
@@ -292,6 +294,8 @@ static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
        if (resno >= PCI_IOV_RESOURCES && resno <= PCI_IOV_RESOURCE_END)
                return pci_sriov_resource_alignment(dev, resno);
 #endif
+       if (dev->class >> 8  == PCI_CLASS_BRIDGE_CARDBUS)
+               return pci_cardbus_resource_alignment(res);
        return resource_alignment(res);
 }
 
index 43421fb..9674e9f 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/suspend.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/kfifo.h>
 #include "aerdrv.h"
 
 static int forceload;
@@ -445,8 +446,7 @@ static struct pcie_port_service_driver *find_aer_service(struct pci_dev *dev)
        return drv;
 }
 
-static pci_ers_result_t reset_link(struct pcie_device *aerdev,
-               struct pci_dev *dev)
+static pci_ers_result_t reset_link(struct pci_dev *dev)
 {
        struct pci_dev *udev;
        pci_ers_result_t status;
@@ -486,7 +486,6 @@ static pci_ers_result_t reset_link(struct pcie_device *aerdev,
 
 /**
  * do_recovery - handle nonfatal/fatal error recovery process
- * @aerdev: pointer to a pcie_device data structure of root port
  * @dev: pointer to a pci_dev data structure of agent detecting an error
  * @severity: error severity type
  *
@@ -494,8 +493,7 @@ static pci_ers_result_t reset_link(struct pcie_device *aerdev,
  * error detected message to all downstream drivers within a hierarchy in
  * question and return the returned code.
  */
-static void do_recovery(struct pcie_device *aerdev, struct pci_dev *dev,
-               int severity)
+static void do_recovery(struct pci_dev *dev, int severity)
 {
        pci_ers_result_t status, result = PCI_ERS_RESULT_RECOVERED;
        enum pci_channel_state state;
@@ -511,7 +509,7 @@ static void do_recovery(struct pcie_device *aerdev, struct pci_dev *dev,
                        report_error_detected);
 
        if (severity == AER_FATAL) {
-               result = reset_link(aerdev, dev);
+               result = reset_link(dev);
                if (result != PCI_ERS_RESULT_RECOVERED)
                        goto failed;
        }
@@ -576,9 +574,73 @@ static void handle_error_source(struct pcie_device *aerdev,
                        pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS,
                                        info->status);
        } else
-               do_recovery(aerdev, dev, info->severity);
+               do_recovery(dev, info->severity);
 }
 
+#ifdef CONFIG_ACPI_APEI_PCIEAER
+static void aer_recover_work_func(struct work_struct *work);
+
+#define AER_RECOVER_RING_ORDER         4
+#define AER_RECOVER_RING_SIZE          (1 << AER_RECOVER_RING_ORDER)
+
+struct aer_recover_entry
+{
+       u8      bus;
+       u8      devfn;
+       u16     domain;
+       int     severity;
+};
+
+static DEFINE_KFIFO(aer_recover_ring, struct aer_recover_entry,
+                   AER_RECOVER_RING_SIZE);
+/*
+ * Mutual exclusion for writers of aer_recover_ring, reader side don't
+ * need lock, because there is only one reader and lock is not needed
+ * between reader and writer.
+ */
+static DEFINE_SPINLOCK(aer_recover_ring_lock);
+static DECLARE_WORK(aer_recover_work, aer_recover_work_func);
+
+void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn,
+                      int severity)
+{
+       unsigned long flags;
+       struct aer_recover_entry entry = {
+               .bus            = bus,
+               .devfn          = devfn,
+               .domain         = domain,
+               .severity       = severity,
+       };
+
+       spin_lock_irqsave(&aer_recover_ring_lock, flags);
+       if (kfifo_put(&aer_recover_ring, &entry))
+               schedule_work(&aer_recover_work);
+       else
+               pr_err("AER recover: Buffer overflow when recovering AER for %04x:%02x:%02x:%x\n",
+                      domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+       spin_unlock_irqrestore(&aer_recover_ring_lock, flags);
+}
+EXPORT_SYMBOL_GPL(aer_recover_queue);
+
+static void aer_recover_work_func(struct work_struct *work)
+{
+       struct aer_recover_entry entry;
+       struct pci_dev *pdev;
+
+       while (kfifo_get(&aer_recover_ring, &entry)) {
+               pdev = pci_get_domain_bus_and_slot(entry.domain, entry.bus,
+                                                  entry.devfn);
+               if (!pdev) {
+                       pr_err("AER recover: Can not find pci_dev for %04x:%02x:%02x:%x\n",
+                              entry.domain, entry.bus,
+                              PCI_SLOT(entry.devfn), PCI_FUNC(entry.devfn));
+                       continue;
+               }
+               do_recovery(pdev, entry.severity);
+       }
+}
+#endif
+
 /**
  * get_device_error_info - read error status from dev and store it to info
  * @dev: pointer to the device expected to have a error record
index b07a42e..3ea5173 100644 (file)
@@ -204,7 +204,7 @@ void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info)
 }
 
 #ifdef CONFIG_ACPI_APEI_PCIEAER
-static int cper_severity_to_aer(int cper_severity)
+int cper_severity_to_aer(int cper_severity)
 {
        switch (cper_severity) {
        case CPER_SEV_RECOVERABLE:
@@ -215,6 +215,7 @@ static int cper_severity_to_aer(int cper_severity)
                return AER_CORRECTABLE;
        }
 }
+EXPORT_SYMBOL_GPL(cper_severity_to_aer);
 
 void cper_print_aer(const char *prefix, int cper_severity,
                    struct aer_capability_regs *aer)
index 9ab492f..8473727 100644 (file)
@@ -68,21 +68,6 @@ static int __init pcibus_class_init(void)
 }
 postcore_initcall(pcibus_class_init);
 
-/*
- * Translate the low bits of the PCI base
- * to the resource type
- */
-static inline unsigned int pci_calc_resource_flags(unsigned int flags)
-{
-       if (flags & PCI_BASE_ADDRESS_SPACE_IO)
-               return IORESOURCE_IO;
-
-       if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH)
-               return IORESOURCE_MEM | IORESOURCE_PREFETCH;
-
-       return IORESOURCE_MEM;
-}
-
 static u64 pci_size(u64 base, u64 maxbase, u64 mask)
 {
        u64 size = mask & maxbase;      /* Find the significant bits */
@@ -101,18 +86,39 @@ static u64 pci_size(u64 base, u64 maxbase, u64 mask)
        return size;
 }
 
-static inline enum pci_bar_type decode_bar(struct resource *res, u32 bar)
+static inline unsigned long decode_bar(struct pci_dev *dev, u32 bar)
 {
+       u32 mem_type;
+       unsigned long flags;
+
        if ((bar & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
-               res->flags = bar & ~PCI_BASE_ADDRESS_IO_MASK;
-               return pci_bar_io;
+               flags = bar & ~PCI_BASE_ADDRESS_IO_MASK;
+               flags |= IORESOURCE_IO;
+               return flags;
        }
 
-       res->flags = bar & ~PCI_BASE_ADDRESS_MEM_MASK;
+       flags = bar & ~PCI_BASE_ADDRESS_MEM_MASK;
+       flags |= IORESOURCE_MEM;
+       if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH)
+               flags |= IORESOURCE_PREFETCH;
 
-       if (res->flags & PCI_BASE_ADDRESS_MEM_TYPE_64)
-               return pci_bar_mem64;
-       return pci_bar_mem32;
+       mem_type = bar & PCI_BASE_ADDRESS_MEM_TYPE_MASK;
+       switch (mem_type) {
+       case PCI_BASE_ADDRESS_MEM_TYPE_32:
+               break;
+       case PCI_BASE_ADDRESS_MEM_TYPE_1M:
+               dev_info(&dev->dev, "1M mem BAR treated as 32-bit BAR\n");
+               break;
+       case PCI_BASE_ADDRESS_MEM_TYPE_64:
+               flags |= IORESOURCE_MEM_64;
+               break;
+       default:
+               dev_warn(&dev->dev,
+                        "mem unknown type %x treated as 32-bit BAR\n",
+                        mem_type);
+               break;
+       }
+       return flags;
 }
 
 /**
@@ -165,9 +171,9 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
                l = 0;
 
        if (type == pci_bar_unknown) {
-               type = decode_bar(res, l);
-               res->flags |= pci_calc_resource_flags(l) | IORESOURCE_SIZEALIGN;
-               if (type == pci_bar_io) {
+               res->flags = decode_bar(dev, l);
+               res->flags |= IORESOURCE_SIZEALIGN;
+               if (res->flags & IORESOURCE_IO) {
                        l &= PCI_BASE_ADDRESS_IO_MASK;
                        mask = PCI_BASE_ADDRESS_IO_MASK & (u32) IO_SPACE_LIMIT;
                } else {
@@ -180,7 +186,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
                mask = (u32)PCI_ROM_ADDRESS_MASK;
        }
 
-       if (type == pci_bar_mem64) {
+       if (res->flags & IORESOURCE_MEM_64) {
                u64 l64 = l;
                u64 sz64 = sz;
                u64 mask64 = mask | (u64)~0 << 32;
@@ -204,7 +210,6 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
                        goto fail;
                }
 
-               res->flags |= IORESOURCE_MEM_64;
                if ((sizeof(resource_size_t) < 8) && l) {
                        /* Address above 32-bit boundary; disable the BAR */
                        pci_write_config_dword(dev, pos, 0);
@@ -230,7 +235,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
        }
 
  out:
-       return (type == pci_bar_mem64) ? 1 : 0;
+       return (res->flags & IORESOURCE_MEM_64) ? 1 : 0;
  fail:
        res->flags = 0;
        goto out;
@@ -284,10 +289,6 @@ static void __devinit pci_read_bridge_io(struct pci_bus *child)
                if (!res->end)
                        res->end = limit + 0xfff;
                dev_printk(KERN_DEBUG, &dev->dev, "  bridge window %pR\n", res);
-       } else {
-               dev_printk(KERN_DEBUG, &dev->dev,
-                        "  bridge window [io  %#06lx-%#06lx] (disabled)\n",
-                                base, limit);
        }
 }
 
@@ -308,10 +309,6 @@ static void __devinit pci_read_bridge_mmio(struct pci_bus *child)
                res->start = base;
                res->end = limit + 0xfffff;
                dev_printk(KERN_DEBUG, &dev->dev, "  bridge window %pR\n", res);
-       } else {
-               dev_printk(KERN_DEBUG, &dev->dev,
-                       "  bridge window [mem %#010lx-%#010lx] (disabled)\n",
-                                        base, limit + 0xfffff);
        }
 }
 
@@ -359,10 +356,6 @@ static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child)
                res->start = base;
                res->end = limit + 0xfffff;
                dev_printk(KERN_DEBUG, &dev->dev, "  bridge window %pR\n", res);
-       } else {
-               dev_printk(KERN_DEBUG, &dev->dev,
-                    "  bridge window [mem %#010lx-%#010lx pref] (disabled)\n",
-                                        base, limit + 0xfffff);
        }
 }
 
@@ -725,12 +718,14 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
                pci_write_config_word(dev, PCI_STATUS, 0xffff);
 
                /* Prevent assigning a bus number that already exists.
-                * This can happen when a bridge is hot-plugged */
-               if (pci_find_bus(pci_domain_nr(bus), max+1))
-                       goto out;
-               child = pci_add_new_bus(bus, dev, ++max);
-               if (!child)
-                       goto out;
+                * This can happen when a bridge is hot-plugged, so in
+                * this case we only re-scan this bus. */
+               child = pci_find_bus(pci_domain_nr(bus), max+1);
+               if (!child) {
+                       child = pci_add_new_bus(bus, dev, ++max);
+                       if (!child)
+                               goto out;
+               }
                buses = (buses & 0xff000000)
                      | ((unsigned int)(child->primary)     <<  0)
                      | ((unsigned int)(child->secondary)   <<  8)
@@ -861,6 +856,8 @@ void set_pcie_port_type(struct pci_dev *pdev)
        pdev->pcie_cap = pos;
        pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, &reg16);
        pdev->pcie_type = (reg16 & PCI_EXP_FLAGS_TYPE) >> 4;
+       pci_read_config_word(pdev, pos + PCI_EXP_DEVCAP, &reg16);
+       pdev->pcie_mpss = reg16 & PCI_EXP_DEVCAP_PAYLOAD;
 }
 
 void set_pcie_hotplug_bridge(struct pci_dev *pdev)
@@ -1331,6 +1328,150 @@ int pci_scan_slot(struct pci_bus *bus, int devfn)
        return nr;
 }
 
+static int pcie_find_smpss(struct pci_dev *dev, void *data)
+{
+       u8 *smpss = data;
+
+       if (!pci_is_pcie(dev))
+               return 0;
+
+       /* For PCIE hotplug enabled slots not connected directly to a
+        * PCI-E root port, there can be problems when hotplugging
+        * devices.  This is due to the possibility of hotplugging a
+        * device into the fabric with a smaller MPS that the devices
+        * currently running have configured.  Modifying the MPS on the
+        * running devices could cause a fatal bus error due to an
+        * incoming frame being larger than the newly configured MPS.
+        * To work around this, the MPS for the entire fabric must be
+        * set to the minimum size.  Any devices hotplugged into this
+        * fabric will have the minimum MPS set.  If the PCI hotplug
+        * slot is directly connected to the root port and there are not
+        * other devices on the fabric (which seems to be the most
+        * common case), then this is not an issue and MPS discovery
+        * will occur as normal.
+        */
+       if (dev->is_hotplug_bridge && (!list_is_singular(&dev->bus->devices) ||
+           dev->bus->self->pcie_type != PCI_EXP_TYPE_ROOT_PORT))
+               *smpss = 0;
+
+       if (*smpss > dev->pcie_mpss)
+               *smpss = dev->pcie_mpss;
+
+       return 0;
+}
+
+static void pcie_write_mps(struct pci_dev *dev, int mps)
+{
+       int rc, dev_mpss;
+
+       dev_mpss = 128 << dev->pcie_mpss;
+
+       if (pcie_bus_config == PCIE_BUS_PERFORMANCE) {
+               if (dev->bus->self) {
+                       dev_dbg(&dev->bus->dev, "Bus MPSS %d\n",
+                               128 << dev->bus->self->pcie_mpss);
+
+                       /* For "MPS Force Max", the assumption is made that
+                        * downstream communication will never be larger than
+                        * the MRRS.  So, the MPS only needs to be configured
+                        * for the upstream communication.  This being the case,
+                        * walk from the top down and set the MPS of the child
+                        * to that of the parent bus.
+                        */
+                       mps = 128 << dev->bus->self->pcie_mpss;
+                       if (mps > dev_mpss)
+                               dev_warn(&dev->dev, "MPS configured higher than"
+                                        " maximum supported by the device.  If"
+                                        " a bus issue occurs, try running with"
+                                        " pci=pcie_bus_safe.\n");
+               }
+
+               dev->pcie_mpss = ffs(mps) - 8;
+       }
+
+       rc = pcie_set_mps(dev, mps);
+       if (rc)
+               dev_err(&dev->dev, "Failed attempting to set the MPS\n");
+}
+
+static void pcie_write_mrrs(struct pci_dev *dev, int mps)
+{
+       int rc, mrrs;
+
+       if (pcie_bus_config == PCIE_BUS_PERFORMANCE) {
+               int dev_mpss = 128 << dev->pcie_mpss;
+
+               /* For Max performance, the MRRS must be set to the largest
+                * supported value.  However, it cannot be configured larger
+                * than the MPS the device or the bus can support.  This assumes
+                * that the largest MRRS available on the device cannot be
+                * smaller than the device MPSS.
+                */
+               mrrs = mps < dev_mpss ? mps : dev_mpss;
+       } else
+               /* In the "safe" case, configure the MRRS for fairness on the
+                * bus by making all devices have the same size
+                */
+               mrrs = mps;
+
+
+       /* MRRS is a R/W register.  Invalid values can be written, but a
+        * subsiquent read will verify if the value is acceptable or not.
+        * If the MRRS value provided is not acceptable (e.g., too large),
+        * shrink the value until it is acceptable to the HW.
+        */
+       while (mrrs != pcie_get_readrq(dev) && mrrs >= 128) {
+               rc = pcie_set_readrq(dev, mrrs);
+               if (rc)
+                       dev_err(&dev->dev, "Failed attempting to set the MRRS\n");
+
+               mrrs /= 2;
+       }
+}
+
+static int pcie_bus_configure_set(struct pci_dev *dev, void *data)
+{
+       int mps = 128 << *(u8 *)data;
+
+       if (!pci_is_pcie(dev))
+               return 0;
+
+       dev_info(&dev->dev, "Dev MPS %d MPSS %d MRRS %d\n",
+                pcie_get_mps(dev), 128<<dev->pcie_mpss, pcie_get_readrq(dev));
+
+       pcie_write_mps(dev, mps);
+       pcie_write_mrrs(dev, mps);
+
+       dev_info(&dev->dev, "Dev MPS %d MPSS %d MRRS %d\n",
+                pcie_get_mps(dev), 128<<dev->pcie_mpss, pcie_get_readrq(dev));
+
+       return 0;
+}
+
+/* pcie_bus_configure_mps requires that pci_walk_bus work in a top-down,
+ * parents then children fashion.  If this changes, then this code will not
+ * work as designed.
+ */
+void pcie_bus_configure_settings(struct pci_bus *bus, u8 mpss)
+{
+       u8 smpss = mpss;
+
+       if (!bus->self)
+               return;
+
+       if (!pci_is_pcie(bus->self))
+               return;
+
+       if (pcie_bus_config == PCIE_BUS_SAFE) {
+               pcie_find_smpss(bus->self, &smpss);
+               pci_walk_bus(bus, pcie_find_smpss, &smpss);
+       }
+
+       pcie_bus_configure_set(bus->self, &smpss);
+       pci_walk_bus(bus, pcie_bus_configure_set, &smpss);
+}
+EXPORT_SYMBOL_GPL(pcie_bus_configure_settings);
+
 unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
 {
        unsigned int devfn, pass, max = bus->secondary;
index 9995842..784da9d 100644 (file)
@@ -34,6 +34,7 @@ struct resource_list_x {
        resource_size_t start;
        resource_size_t end;
        resource_size_t add_size;
+       resource_size_t min_align;
        unsigned long flags;
 };
 
@@ -65,7 +66,7 @@ void pci_realloc(void)
  */
 static void add_to_list(struct resource_list_x *head,
                 struct pci_dev *dev, struct resource *res,
-                resource_size_t add_size)
+                resource_size_t add_size, resource_size_t min_align)
 {
        struct resource_list_x *list = head;
        struct resource_list_x *ln = list->next;
@@ -84,13 +85,16 @@ static void add_to_list(struct resource_list_x *head,
        tmp->end = res->end;
        tmp->flags = res->flags;
        tmp->add_size = add_size;
+       tmp->min_align = min_align;
        list->next = tmp;
 }
 
 static void add_to_failed_list(struct resource_list_x *head,
                                struct pci_dev *dev, struct resource *res)
 {
-       add_to_list(head, dev, res, 0);
+       add_to_list(head, dev, res,
+                       0 /* dont care */,
+                       0 /* dont care */);
 }
 
 static void __dev_sort_resources(struct pci_dev *dev,
@@ -121,18 +125,18 @@ static inline void reset_resource(struct resource *res)
 }
 
 /**
- * adjust_resources_sorted() - satisfy any additional resource requests
+ * reassign_resources_sorted() - satisfy any additional resource requests
  *
- * @add_head : head of the list tracking requests requiring additional
+ * @realloc_head : head of the list tracking requests requiring additional
  *             resources
  * @head     : head of the list tracking requests with allocated
  *             resources
  *
- * Walk through each element of the add_head and try to procure
+ * Walk through each element of the realloc_head and try to procure
  * additional resources for the element, provided the element
  * is in the head list.
  */
-static void adjust_resources_sorted(struct resource_list_x *add_head,
+static void reassign_resources_sorted(struct resource_list_x *realloc_head,
                struct resource_list *head)
 {
        struct resource *res;
@@ -141,8 +145,8 @@ static void adjust_resources_sorted(struct resource_list_x *add_head,
        resource_size_t add_size;
        int idx;
 
-       prev = add_head;
-       for (list = add_head->next; list;) {
+       prev = realloc_head;
+       for (list = realloc_head->next; list;) {
                res = list->res;
                /* skip resource that has been reset */
                if (!res->flags)
@@ -159,13 +163,17 @@ static void adjust_resources_sorted(struct resource_list_x *add_head,
 
                idx = res - &list->dev->resource[0];
                add_size=list->add_size;
-               if (!resource_size(res) && add_size) {
-                        res->end = res->start + add_size - 1;
-                        if(pci_assign_resource(list->dev, idx))
+               if (!resource_size(res)) {
+                       res->start = list->start;
+                       res->end = res->start + add_size - 1;
+                       if(pci_assign_resource(list->dev, idx))
                                reset_resource(res);
-               } else if (add_size) {
-                       adjust_resource(res, res->start,
-                               resource_size(res) + add_size);
+               } else {
+                       resource_size_t align = list->min_align;
+                       res->flags |= list->flags & (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN);
+                       if (pci_reassign_resource(list->dev, idx, add_size, align))
+                               dev_printk(KERN_DEBUG, &list->dev->dev, "failed to add optional resources res=%pR\n",
+                                                       res);
                }
 out:
                tmp = list;
@@ -210,16 +218,16 @@ static void assign_requested_resources_sorted(struct resource_list *head,
 }
 
 static void __assign_resources_sorted(struct resource_list *head,
-                                struct resource_list_x *add_head,
+                                struct resource_list_x *realloc_head,
                                 struct resource_list_x *fail_head)
 {
        /* Satisfy the must-have resource requests */
        assign_requested_resources_sorted(head, fail_head);
 
-       /* Try to satisfy any additional nice-to-have resource
+       /* Try to satisfy any additional optional resource
                requests */
-       if (add_head)
-               adjust_resources_sorted(add_head, head);
+       if (realloc_head)
+               reassign_resources_sorted(realloc_head, head);
        free_list(resource_list, head);
 }
 
@@ -235,7 +243,7 @@ static void pdev_assign_resources_sorted(struct pci_dev *dev,
 }
 
 static void pbus_assign_resources_sorted(const struct pci_bus *bus,
-                                        struct resource_list_x *add_head,
+                                        struct resource_list_x *realloc_head,
                                         struct resource_list_x *fail_head)
 {
        struct pci_dev *dev;
@@ -245,7 +253,7 @@ static void pbus_assign_resources_sorted(const struct pci_bus *bus,
        list_for_each_entry(dev, &bus->devices, bus_list)
                __dev_sort_resources(dev, &head);
 
-       __assign_resources_sorted(&head, add_head, fail_head);
+       __assign_resources_sorted(&head, realloc_head, fail_head);
 }
 
 void pci_setup_cardbus(struct pci_bus *bus)
@@ -336,7 +344,6 @@ static void pci_setup_bridge_io(struct pci_bus *bus)
                /* Clear upper 16 bits of I/O base/limit. */
                io_upper16 = 0;
                l = 0x00f0;
-               dev_info(&bridge->dev, "  bridge window [io  disabled]\n");
        }
        /* Temporarily disable the I/O range before updating PCI_IO_BASE. */
        pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0x0000ffff);
@@ -362,7 +369,6 @@ static void pci_setup_bridge_mmio(struct pci_bus *bus)
                dev_info(&bridge->dev, "  bridge window %pR\n", res);
        } else {
                l = 0x0000fff0;
-               dev_info(&bridge->dev, "  bridge window [mem disabled]\n");
        }
        pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
 }
@@ -393,7 +399,6 @@ static void pci_setup_bridge_mmio_pref(struct pci_bus *bus)
                dev_info(&bridge->dev, "  bridge window %pR\n", res);
        } else {
                l = 0x0000fff0;
-               dev_info(&bridge->dev, "  bridge window [mem pref disabled]\n");
        }
        pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
 
@@ -543,13 +548,27 @@ static resource_size_t calculate_memsize(resource_size_t size,
        return size;
 }
 
+static resource_size_t get_res_add_size(struct resource_list_x *realloc_head,
+                                       struct resource *res)
+{
+       struct resource_list_x *list;
+
+       /* check if it is in realloc_head list */
+       for (list = realloc_head->next; list && list->res != res;
+                       list = list->next);
+       if (list)
+               return list->add_size;
+
+       return 0;
+}
+
 /**
  * pbus_size_io() - size the io window of a given bus
  *
  * @bus : the bus
  * @min_size : the minimum io window that must to be allocated
  * @add_size : additional optional io window
- * @add_head : track the additional io window on this list
+ * @realloc_head : track the additional io window on this list
  *
  * Sizing the IO windows of the PCI-PCI bridge is trivial,
  * since these windows have 4K granularity and the IO ranges
@@ -557,11 +576,12 @@ static resource_size_t calculate_memsize(resource_size_t size,
  * We must be careful with the ISA aliasing though.
  */
 static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
-               resource_size_t add_size, struct resource_list_x *add_head)
+               resource_size_t add_size, struct resource_list_x *realloc_head)
 {
        struct pci_dev *dev;
        struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO);
        unsigned long size = 0, size0 = 0, size1 = 0;
+       resource_size_t children_add_size = 0;
 
        if (!b_res)
                return;
@@ -582,11 +602,16 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
                                size += r_size;
                        else
                                size1 += r_size;
+
+                       if (realloc_head)
+                               children_add_size += get_res_add_size(realloc_head, r);
                }
        }
        size0 = calculate_iosize(size, min_size, size1,
                        resource_size(b_res), 4096);
-       size1 = (!add_head || (add_head && !add_size)) ? size0 :
+       if (children_add_size > add_size)
+               add_size = children_add_size;
+       size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 :
                calculate_iosize(size, min_size+add_size, size1,
                        resource_size(b_res), 4096);
        if (!size0 && !size1) {
@@ -601,8 +626,8 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
        b_res->start = 4096;
        b_res->end = b_res->start + size0 - 1;
        b_res->flags |= IORESOURCE_STARTALIGN;
-       if (size1 > size0 && add_head)
-               add_to_list(add_head, bus->self, b_res, size1-size0);
+       if (size1 > size0 && realloc_head)
+               add_to_list(realloc_head, bus->self, b_res, size1-size0, 4096);
 }
 
 /**
@@ -611,7 +636,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
  * @bus : the bus
  * @min_size : the minimum memory window that must to be allocated
  * @add_size : additional optional memory window
- * @add_head : track the additional memory window on this list
+ * @realloc_head : track the additional memory window on this list
  *
  * Calculate the size of the bus and minimal alignment which
  * guarantees that all child resources fit in this size.
@@ -619,7 +644,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
 static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
                         unsigned long type, resource_size_t min_size,
                        resource_size_t add_size,
-                       struct resource_list_x *add_head)
+                       struct resource_list_x *realloc_head)
 {
        struct pci_dev *dev;
        resource_size_t min_align, align, size, size0, size1;
@@ -627,6 +652,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
        int order, max_order;
        struct resource *b_res = find_free_bus_resource(bus, type);
        unsigned int mem64_mask = 0;
+       resource_size_t children_add_size = 0;
 
        if (!b_res)
                return 0;
@@ -648,6 +674,16 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
                        if (r->parent || (r->flags & mask) != type)
                                continue;
                        r_size = resource_size(r);
+#ifdef CONFIG_PCI_IOV
+                       /* put SRIOV requested res to the optional list */
+                       if (realloc_head && i >= PCI_IOV_RESOURCES &&
+                                       i <= PCI_IOV_RESOURCE_END) {
+                               r->end = r->start - 1;
+                               add_to_list(realloc_head, dev, r, r_size, 0/* dont' care */);
+                               children_add_size += r_size;
+                               continue;
+                       }
+#endif
                        /* For bridges size != alignment */
                        align = pci_resource_alignment(dev, r);
                        order = __ffs(align) - 20;
@@ -668,6 +704,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
                        if (order > max_order)
                                max_order = order;
                        mem64_mask &= r->flags & IORESOURCE_MEM_64;
+
+                       if (realloc_head)
+                               children_add_size += get_res_add_size(realloc_head, r);
                }
        }
        align = 0;
@@ -684,7 +723,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
                align += aligns[order];
        }
        size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align);
-       size1 = (!add_head || (add_head && !add_size)) ? size0 :
+       if (children_add_size > add_size)
+               add_size = children_add_size;
+       size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 :
                calculate_memsize(size, min_size+add_size, 0,
                                resource_size(b_res), min_align);
        if (!size0 && !size1) {
@@ -698,12 +739,22 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
        b_res->start = min_align;
        b_res->end = size0 + min_align - 1;
        b_res->flags |= IORESOURCE_STARTALIGN | mem64_mask;
-       if (size1 > size0 && add_head)
-               add_to_list(add_head, bus->self, b_res, size1-size0);
+       if (size1 > size0 && realloc_head)
+               add_to_list(realloc_head, bus->self, b_res, size1-size0, min_align);
        return 1;
 }
 
-static void pci_bus_size_cardbus(struct pci_bus *bus)
+unsigned long pci_cardbus_resource_alignment(struct resource *res)
+{
+       if (res->flags & IORESOURCE_IO)
+               return pci_cardbus_io_size;
+       if (res->flags & IORESOURCE_MEM)
+               return pci_cardbus_mem_size;
+       return 0;
+}
+
+static void pci_bus_size_cardbus(struct pci_bus *bus,
+                       struct resource_list_x *realloc_head)
 {
        struct pci_dev *bridge = bus->self;
        struct resource *b_res = &bridge->resource[PCI_BRIDGE_RESOURCES];
@@ -714,12 +765,14 @@ static void pci_bus_size_cardbus(struct pci_bus *bus)
         * a fixed amount of bus space for CardBus bridges.
         */
        b_res[0].start = 0;
-       b_res[0].end = pci_cardbus_io_size - 1;
        b_res[0].flags |= IORESOURCE_IO | IORESOURCE_SIZEALIGN;
+       if (realloc_head)
+               add_to_list(realloc_head, bridge, b_res, pci_cardbus_io_size, 0 /* dont care */);
 
        b_res[1].start = 0;
-       b_res[1].end = pci_cardbus_io_size - 1;
        b_res[1].flags |= IORESOURCE_IO | IORESOURCE_SIZEALIGN;
+       if (realloc_head)
+               add_to_list(realloc_head, bridge, b_res+1, pci_cardbus_io_size, 0 /* dont care */);
 
        /*
         * Check whether prefetchable memory is supported
@@ -739,21 +792,31 @@ static void pci_bus_size_cardbus(struct pci_bus *bus)
         */
        if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) {
                b_res[2].start = 0;
-               b_res[2].end = pci_cardbus_mem_size - 1;
                b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_SIZEALIGN;
+               if (realloc_head)
+                       add_to_list(realloc_head, bridge, b_res+2, pci_cardbus_mem_size, 0 /* dont care */);
 
                b_res[3].start = 0;
-               b_res[3].end = pci_cardbus_mem_size - 1;
                b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_SIZEALIGN;
+               if (realloc_head)
+                       add_to_list(realloc_head, bridge, b_res+3, pci_cardbus_mem_size, 0 /* dont care */);
        } else {
                b_res[3].start = 0;
-               b_res[3].end = pci_cardbus_mem_size * 2 - 1;
                b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_SIZEALIGN;
+               if (realloc_head)
+                       add_to_list(realloc_head, bridge, b_res+3, pci_cardbus_mem_size * 2, 0 /* dont care */);
        }
+
+       /* set the size of the resource to zero, so that the resource does not
+        * get assigned during required-resource allocation cycle but gets assigned
+        * during the optional-resource allocation cycle.
+        */
+       b_res[0].start = b_res[1].start = b_res[2].start = b_res[3].start = 1;
+       b_res[0].end = b_res[1].end = b_res[2].end = b_res[3].end = 0;
 }
 
 void __ref __pci_bus_size_bridges(struct pci_bus *bus,
-                       struct resource_list_x *add_head)
+                       struct resource_list_x *realloc_head)
 {
        struct pci_dev *dev;
        unsigned long mask, prefmask;
@@ -766,12 +829,12 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus,
 
                switch (dev->class >> 8) {
                case PCI_CLASS_BRIDGE_CARDBUS:
-                       pci_bus_size_cardbus(b);
+                       pci_bus_size_cardbus(b, realloc_head);
                        break;
 
                case PCI_CLASS_BRIDGE_PCI:
                default:
-                       __pci_bus_size_bridges(b, add_head);
+                       __pci_bus_size_bridges(b, realloc_head);
                        break;
                }
        }
@@ -795,7 +858,7 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus,
                 * Follow thru
                 */
        default:
-               pbus_size_io(bus, 0, additional_io_size, add_head);
+               pbus_size_io(bus, 0, additional_io_size, realloc_head);
                /* If the bridge supports prefetchable range, size it
                   separately. If it doesn't, or its prefetchable window
                   has already been allocated by arch code, try
@@ -803,11 +866,11 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus,
                   resources. */
                mask = IORESOURCE_MEM;
                prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH;
-               if (pbus_size_mem(bus, prefmask, prefmask, 0, additional_mem_size, add_head))
+               if (pbus_size_mem(bus, prefmask, prefmask, 0, additional_mem_size, realloc_head))
                        mask = prefmask; /* Success, size non-prefetch only. */
                else
                        additional_mem_size += additional_mem_size;
-               pbus_size_mem(bus, mask, IORESOURCE_MEM, 0, additional_mem_size, add_head);
+               pbus_size_mem(bus, mask, IORESOURCE_MEM, 0, additional_mem_size, realloc_head);
                break;
        }
 }
@@ -819,20 +882,20 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus)
 EXPORT_SYMBOL(pci_bus_size_bridges);
 
 static void __ref __pci_bus_assign_resources(const struct pci_bus *bus,
-                                        struct resource_list_x *add_head,
+                                        struct resource_list_x *realloc_head,
                                         struct resource_list_x *fail_head)
 {
        struct pci_bus *b;
        struct pci_dev *dev;
 
-       pbus_assign_resources_sorted(bus, add_head, fail_head);
+       pbus_assign_resources_sorted(bus, realloc_head, fail_head);
 
        list_for_each_entry(dev, &bus->devices, bus_list) {
                b = dev->subordinate;
                if (!b)
                        continue;
 
-               __pci_bus_assign_resources(b, add_head, fail_head);
+               __pci_bus_assign_resources(b, realloc_head, fail_head);
 
                switch (dev->class >> 8) {
                case PCI_CLASS_BRIDGE_PCI:
@@ -1042,7 +1105,7 @@ void __init
 pci_assign_unassigned_resources(void)
 {
        struct pci_bus *bus;
-       struct resource_list_x add_list; /* list of resources that
+       struct resource_list_x realloc_list; /* list of resources that
                                        want additional resources */
        int tried_times = 0;
        enum release_type rel_type = leaf_only;
@@ -1055,7 +1118,7 @@ pci_assign_unassigned_resources(void)
 
 
        head.next = NULL;
-       add_list.next = NULL;
+       realloc_list.next = NULL;
 
        pci_try_num = max_depth + 1;
        printk(KERN_DEBUG "PCI: max bus depth: %d pci_try_num: %d\n",
@@ -1065,12 +1128,12 @@ again:
        /* Depth first, calculate sizes and alignments of all
           subordinate buses. */
        list_for_each_entry(bus, &pci_root_buses, node)
-               __pci_bus_size_bridges(bus, &add_list);
+               __pci_bus_size_bridges(bus, &realloc_list);
 
        /* Depth last, allocate resources and update the hardware. */
        list_for_each_entry(bus, &pci_root_buses, node)
-               __pci_bus_assign_resources(bus, &add_list, &head);
-       BUG_ON(add_list.next);
+               __pci_bus_assign_resources(bus, &realloc_list, &head);
+       BUG_ON(realloc_list.next);
        tried_times++;
 
        /* any device complain? */
index eec9738..eb219a1 100644 (file)
@@ -21,7 +21,7 @@
 static void __init
 pdev_fixup_irq(struct pci_dev *dev,
               u8 (*swizzle)(struct pci_dev *, u8 *),
-              int (*map_irq)(struct pci_dev *, u8, u8))
+              int (*map_irq)(const struct pci_dev *, u8, u8))
 {
        u8 pin, slot;
        int irq = 0;
@@ -56,7 +56,7 @@ pdev_fixup_irq(struct pci_dev *dev,
 
 void __init
 pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *),
-              int (*map_irq)(struct pci_dev *, u8, u8))
+              int (*map_irq)(const struct pci_dev *, u8, u8))
 {
        struct pci_dev *dev = NULL;
        for_each_pci_dev(dev)
index bc0e6ee..51a9095 100644 (file)
@@ -74,8 +74,7 @@ void pci_update_resource(struct pci_dev *dev, int resno)
                        resno, new, check);
        }
 
-       if ((new & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
-           (PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64)) {
+       if (res->flags & IORESOURCE_MEM_64) {
                new = region.start >> 16 >> 16;
                pci_write_config_dword(dev, reg + 4, new);
                pci_read_config_dword(dev, reg + 4, &check);
@@ -129,16 +128,16 @@ void pci_disable_bridge_window(struct pci_dev *dev)
 }
 #endif /* CONFIG_PCI_QUIRKS */
 
+
+
 static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
-                                int resno)
+               int resno, resource_size_t size, resource_size_t align)
 {
        struct resource *res = dev->resource + resno;
-       resource_size_t size, min, align;
+       resource_size_t min;
        int ret;
 
-       size = resource_size(res);
        min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
-       align = pci_resource_alignment(dev, res);
 
        /* First, try exact prefetching match.. */
        ret = pci_bus_alloc_resource(bus, res, size, align, min,
@@ -155,56 +154,101 @@ static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
                ret = pci_bus_alloc_resource(bus, res, size, align, min, 0,
                                             pcibios_align_resource, dev);
        }
+       return ret;
+}
 
-       if (ret < 0 && dev->fw_addr[resno]) {
-               struct resource *root, *conflict;
-               resource_size_t start, end;
+static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev, 
+               int resno, resource_size_t size)
+{
+       struct resource *root, *conflict;
+       resource_size_t start, end;
+       int ret = 0;
 
-               /*
-                * If we failed to assign anything, let's try the address
-                * where firmware left it.  That at least has a chance of
-                * working, which is better than just leaving it disabled.
-                */
+       if (res->flags & IORESOURCE_IO)
+               root = &ioport_resource;
+       else
+               root = &iomem_resource;
+
+       start = res->start;
+       end = res->end;
+       res->start = dev->fw_addr[resno];
+       res->end = res->start + size - 1;
+       dev_info(&dev->dev, "BAR %d: trying firmware assignment %pR\n",
+                resno, res);
+       conflict = request_resource_conflict(root, res);
+       if (conflict) {
+               dev_info(&dev->dev,
+                        "BAR %d: %pR conflicts with %s %pR\n", resno,
+                        res, conflict->name, conflict);
+               res->start = start;
+               res->end = end;
+               ret = 1;
+       }
+       return ret;
+}
+
+static int _pci_assign_resource(struct pci_dev *dev, int resno, int size, resource_size_t min_align)
+{
+       struct resource *res = dev->resource + resno;
+       struct pci_bus *bus;
+       int ret;
+       char *type;
 
-               if (res->flags & IORESOURCE_IO)
-                       root = &ioport_resource;
+       bus = dev->bus;
+       while ((ret = __pci_assign_resource(bus, dev, resno, size, min_align))) {
+               if (!bus->parent || !bus->self->transparent)
+                       break;
+               bus = bus->parent;
+       }
+
+       if (ret) {
+               if (res->flags & IORESOURCE_MEM)
+                       if (res->flags & IORESOURCE_PREFETCH)
+                               type = "mem pref";
+                       else
+                               type = "mem";
+               else if (res->flags & IORESOURCE_IO)
+                       type = "io";
                else
-                       root = &iomem_resource;
-
-               start = res->start;
-               end = res->end;
-               res->start = dev->fw_addr[resno];
-               res->end = res->start + size - 1;
-               dev_info(&dev->dev, "BAR %d: trying firmware assignment %pR\n",
-                        resno, res);
-               conflict = request_resource_conflict(root, res);
-               if (conflict) {
-                       dev_info(&dev->dev,
-                                "BAR %d: %pR conflicts with %s %pR\n", resno,
-                                res, conflict->name, conflict);
-                       res->start = start;
-                       res->end = end;
-               } else
-                       ret = 0;
+                       type = "unknown";
+               dev_info(&dev->dev,
+                        "BAR %d: can't assign %s (size %#llx)\n",
+                        resno, type, (unsigned long long) resource_size(res));
        }
 
+       return ret;
+}
+
+int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsize,
+                       resource_size_t min_align)
+{
+       struct resource *res = dev->resource + resno;
+       resource_size_t new_size;
+       int ret;
+
+       if (!res->parent) {
+               dev_info(&dev->dev, "BAR %d: can't reassign an unassigned resouce %pR "
+                        "\n", resno, res);
+               return -EINVAL;
+       }
+
+       new_size = resource_size(res) + addsize + min_align;
+       ret = _pci_assign_resource(dev, resno, new_size, min_align);
        if (!ret) {
                res->flags &= ~IORESOURCE_STARTALIGN;
                dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res);
                if (resno < PCI_BRIDGE_RESOURCES)
                        pci_update_resource(dev, resno);
        }
-
        return ret;
 }
 
 int pci_assign_resource(struct pci_dev *dev, int resno)
 {
        struct resource *res = dev->resource + resno;
-       resource_size_t align;
+       resource_size_t align, size;
        struct pci_bus *bus;
        int ret;
-       char *type;
 
        align = pci_resource_alignment(dev, res);
        if (!align) {
@@ -214,34 +258,27 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
        }
 
        bus = dev->bus;
-       while ((ret = __pci_assign_resource(bus, dev, resno))) {
-               if (bus->parent && bus->self->transparent)
-                       bus = bus->parent;
-               else
-                       bus = NULL;
-               if (bus)
-                       continue;
-               break;
-       }
+       size = resource_size(res);
+       ret = _pci_assign_resource(dev, resno, size, align);
 
-       if (ret) {
-               if (res->flags & IORESOURCE_MEM)
-                       if (res->flags & IORESOURCE_PREFETCH)
-                               type = "mem pref";
-                       else
-                               type = "mem";
-               else if (res->flags & IORESOURCE_IO)
-                       type = "io";
-               else
-                       type = "unknown";
-               dev_info(&dev->dev,
-                        "BAR %d: can't assign %s (size %#llx)\n",
-                        resno, type, (unsigned long long) resource_size(res));
-       }
+       /*
+        * If we failed to assign anything, let's try the address
+        * where firmware left it.  That at least has a chance of
+        * working, which is better than just leaving it disabled.
+        */
+       if (ret < 0 && dev->fw_addr[resno])
+               ret = pci_revert_fw_address(res, dev, resno, size);
 
+       if (!ret) {
+               res->flags &= ~IORESOURCE_STARTALIGN;
+               dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res);
+               if (resno < PCI_BRIDGE_RESOURCES)
+                       pci_update_resource(dev, resno);
+       }
        return ret;
 }
 
+
 /* Sort resources by alignment */
 void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
 {
index 4c3e94c..f56d7de 100644 (file)
@@ -103,22 +103,12 @@ static int balloon3_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
        return 0;
 }
 
-static void balloon3_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-}
-
-static void balloon3_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-}
-
 static struct pcmcia_low_level balloon3_pcmcia_ops = {
        .owner                  = THIS_MODULE,
        .hw_init                = balloon3_pcmcia_hw_init,
        .hw_shutdown            = balloon3_pcmcia_hw_shutdown,
        .socket_state           = balloon3_pcmcia_socket_state,
        .configure_socket       = balloon3_pcmcia_configure_socket,
-       .socket_init            = balloon3_pcmcia_socket_init,
-       .socket_suspend         = balloon3_pcmcia_socket_suspend,
        .first                  = 0,
        .nr                     = 1,
 };
index 05913d0..63f4d52 100644 (file)
@@ -102,23 +102,12 @@ static int cmx255_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
        return 0;
 }
 
-static void cmx255_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-}
-
-static void cmx255_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-}
-
-
 static struct pcmcia_low_level cmx255_pcmcia_ops __initdata = {
        .owner                  = THIS_MODULE,
        .hw_init                = cmx255_pcmcia_hw_init,
        .hw_shutdown            = cmx255_pcmcia_shutdown,
        .socket_state           = cmx255_pcmcia_socket_state,
        .configure_socket       = cmx255_pcmcia_configure_socket,
-       .socket_init            = cmx255_pcmcia_socket_init,
-       .socket_suspend         = cmx255_pcmcia_socket_suspend,
        .nr                     = 1,
 };
 
index 5662646..6ee42b4 100644 (file)
@@ -82,23 +82,12 @@ static int cmx270_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
        return 0;
 }
 
-static void cmx270_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-}
-
-static void cmx270_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-}
-
-
 static struct pcmcia_low_level cmx270_pcmcia_ops __initdata = {
        .owner                  = THIS_MODULE,
        .hw_init                = cmx270_pcmcia_hw_init,
        .hw_shutdown            = cmx270_pcmcia_shutdown,
        .socket_state           = cmx270_pcmcia_socket_state,
        .configure_socket       = cmx270_pcmcia_configure_socket,
-       .socket_init            = cmx270_pcmcia_socket_init,
-       .socket_suspend         = cmx270_pcmcia_socket_suspend,
        .nr                     = 1,
 };
 
index 443cb7f..c6dec57 100644 (file)
@@ -116,14 +116,6 @@ colibri_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
        return 0;
 }
 
-static void colibri_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-}
-
-static void colibri_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-}
-
 static struct pcmcia_low_level colibri_pcmcia_ops = {
        .owner                  = THIS_MODULE,
 
@@ -135,9 +127,6 @@ static struct pcmcia_low_level colibri_pcmcia_ops = {
 
        .socket_state           = colibri_pcmcia_socket_state,
        .configure_socket       = colibri_pcmcia_configure_socket,
-
-       .socket_init            = colibri_pcmcia_socket_init,
-       .socket_suspend         = colibri_pcmcia_socket_suspend,
 };
 
 static struct platform_device *colibri_pcmcia_device;
index 92016fe..aded706 100644 (file)
@@ -128,22 +128,12 @@ static int mst_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
        return ret;
 }
 
-static void mst_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-}
-
-static void mst_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-}
-
 static struct pcmcia_low_level mst_pcmcia_ops __initdata = {
        .owner                  = THIS_MODULE,
        .hw_init                = mst_pcmcia_hw_init,
        .hw_shutdown            = mst_pcmcia_hw_shutdown,
        .socket_state           = mst_pcmcia_socket_state,
        .configure_socket       = mst_pcmcia_configure_socket,
-       .socket_init            = mst_pcmcia_socket_init,
-       .socket_suspend         = mst_pcmcia_socket_suspend,
        .nr                     = 2,
 };
 
index 69f7367..d589ad1 100644 (file)
@@ -65,14 +65,6 @@ static int palmld_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
        return 0;
 }
 
-static void palmld_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-}
-
-static void palmld_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-}
-
 static struct pcmcia_low_level palmld_pcmcia_ops = {
        .owner                  = THIS_MODULE,
 
@@ -84,9 +76,6 @@ static struct pcmcia_low_level palmld_pcmcia_ops = {
 
        .socket_state           = palmld_pcmcia_socket_state,
        .configure_socket       = palmld_pcmcia_configure_socket,
-
-       .socket_init            = palmld_pcmcia_socket_init,
-       .socket_suspend         = palmld_pcmcia_socket_suspend,
 };
 
 static struct platform_device *palmld_pcmcia_device;
index d0ad6a7..9c6a04b 100644 (file)
@@ -117,14 +117,6 @@ static int palmtc_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
        return ret;
 }
 
-static void palmtc_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-}
-
-static void palmtc_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-}
-
 static struct pcmcia_low_level palmtc_pcmcia_ops = {
        .owner                  = THIS_MODULE,
 
@@ -136,9 +128,6 @@ static struct pcmcia_low_level palmtc_pcmcia_ops = {
 
        .socket_state           = palmtc_pcmcia_socket_state,
        .configure_socket       = palmtc_pcmcia_configure_socket,
-
-       .socket_init            = palmtc_pcmcia_socket_init,
-       .socket_suspend         = palmtc_pcmcia_socket_suspend,
 };
 
 static struct platform_device *palmtc_pcmcia_device;
index 1a25804..80645a6 100644 (file)
@@ -67,14 +67,6 @@ palmtx_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
        return 0;
 }
 
-static void palmtx_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-}
-
-static void palmtx_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-}
-
 static struct pcmcia_low_level palmtx_pcmcia_ops = {
        .owner                  = THIS_MODULE,
 
@@ -86,9 +78,6 @@ static struct pcmcia_low_level palmtx_pcmcia_ops = {
 
        .socket_state           = palmtx_pcmcia_socket_state,
        .configure_socket       = palmtx_pcmcia_configure_socket,
-
-       .socket_init            = palmtx_pcmcia_socket_init,
-       .socket_suspend         = palmtx_pcmcia_socket_suspend,
 };
 
 static struct platform_device *palmtx_pcmcia_device;
index d08802f..9396222 100644 (file)
@@ -28,7 +28,6 @@
 
 #include "soc_common.h"
 
-#define SG2_S0_BUFF_CTL                120
 #define SG2_S0_POWER_CTL       108
 #define SG2_S0_GPIO_RESET      82
 #define SG2_S0_GPIO_DETECT     53
@@ -38,6 +37,11 @@ static struct pcmcia_irqs irqs[] = {
        { 0, IRQ_GPIO(SG2_S0_GPIO_DETECT), "PCMCIA0 CD" },
 };
 
+static struct gpio sg2_pcmcia_gpios[] = {
+       { SG2_S0_GPIO_RESET, GPIOF_OUT_INIT_HIGH, "PCMCIA Reset" },
+       { SG2_S0_POWER_CTL, GPIOF_OUT_INIT_HIGH, "PCMCIA Power Ctrl" },
+};
+
 static int sg2_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
        skt->socket.pci_irq = IRQ_GPIO(SG2_S0_GPIO_READY);
@@ -122,37 +126,23 @@ static int __init sg2_pcmcia_init(void)
        if (!sg2_pcmcia_device)
                return -ENOMEM;
 
-       ret = gpio_request(SG2_S0_BUFF_CTL, "SG2 CF buff ctl");
+       ret = gpio_request_array(sg2_pcmcia_gpios, ARRAY_SIZE(sg2_pcmcia_gpios));
        if (ret)
                goto error_put_platform_device;
-       ret = gpio_request(SG2_S0_POWER_CTL, "SG2 CF power ctl");
-       if (ret)
-               goto error_free_gpio_buff_ctl;
-       ret = gpio_request(SG2_S0_GPIO_RESET, "SG2 CF reset");
-       if (ret)
-               goto error_free_gpio_power_ctl;
-       /* Set gpio directions */
-       gpio_direction_output(SG2_S0_BUFF_CTL, 0);
-       gpio_direction_output(SG2_S0_POWER_CTL, 1);
-       gpio_direction_output(SG2_S0_GPIO_RESET, 1);
 
        ret = platform_device_add_data(sg2_pcmcia_device,
                                       &sg2_pcmcia_ops,
                                       sizeof(sg2_pcmcia_ops));
        if (ret)
-               goto error_free_gpio_reset;
+               goto error_free_gpios;
 
        ret = platform_device_add(sg2_pcmcia_device);
        if (ret)
-               goto error_free_gpio_reset;
+               goto error_free_gpios;
 
        return 0;
-error_free_gpio_reset:
-       gpio_free(SG2_S0_GPIO_RESET);
-error_free_gpio_power_ctl:
-       gpio_free(SG2_S0_POWER_CTL);
-error_free_gpio_buff_ctl:
-       gpio_free(SG2_S0_BUFF_CTL);
+error_free_gpios:
+       gpio_free_array(sg2_pcmcia_gpios, ARRAY_SIZE(sg2_pcmcia_gpios));
 error_put_platform_device:
        platform_device_put(sg2_pcmcia_device);
 
@@ -162,9 +152,7 @@ error_put_platform_device:
 static void __exit sg2_pcmcia_exit(void)
 {
        platform_device_unregister(sg2_pcmcia_device);
-       gpio_free(SG2_S0_BUFF_CTL);
-       gpio_free(SG2_S0_POWER_CTL);
-       gpio_free(SG2_S0_GPIO_RESET);
+       gpio_free_array(sg2_pcmcia_gpios, ARRAY_SIZE(sg2_pcmcia_gpios));
 }
 
 fs_initcall(sg2_pcmcia_init);
index a51f207..1064b1c 100644 (file)
@@ -136,22 +136,12 @@ static int viper_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
        return 0;
 }
 
-static void viper_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-}
-
-static void viper_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-}
-
 static struct pcmcia_low_level viper_pcmcia_ops = {
        .owner                  = THIS_MODULE,
        .hw_init                = viper_pcmcia_hw_init,
        .hw_shutdown            = viper_pcmcia_hw_shutdown,
        .socket_state           = viper_pcmcia_socket_state,
        .configure_socket       = viper_pcmcia_configure_socket,
-       .socket_init            = viper_pcmcia_socket_init,
-       .socket_suspend         = viper_pcmcia_socket_suspend,
        .nr                     = 1,
 };
 
index 768f957..a0a9c2a 100644 (file)
@@ -186,8 +186,8 @@ static int soc_common_pcmcia_sock_init(struct pcmcia_socket *sock)
        struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
 
        debug(skt, 2, "initializing socket\n");
-
-       skt->ops->socket_init(skt);
+       if (skt->ops->socket_init)
+               skt->ops->socket_init(skt);
        return 0;
 }
 
@@ -207,7 +207,8 @@ static int soc_common_pcmcia_suspend(struct pcmcia_socket *sock)
 
        debug(skt, 2, "suspending socket\n");
 
-       skt->ops->socket_suspend(skt);
+       if (skt->ops->socket_suspend)
+               skt->ops->socket_suspend(skt);
 
        return 0;
 }
index 45e0191..1e88d47 100644 (file)
@@ -769,4 +769,12 @@ config INTEL_OAKTRAIL
          enable/disable the Camera, WiFi, BT etc. devices. If in doubt, say Y
          here; it will only load on supported platforms.
 
+config SAMSUNG_Q10
+       tristate "Samsung Q10 Extras"
+       depends on SERIO_I8042
+       select BACKLIGHT_CLASS_DEVICE
+       ---help---
+         This driver provides support for backlight control on Samsung Q10
+         and related laptops, including Dell Latitude X200.
+
 endif # X86_PLATFORM_DEVICES
index afc1f83..293a320 100644 (file)
@@ -44,3 +44,4 @@ obj-$(CONFIG_SAMSUNG_LAPTOP)  += samsung-laptop.o
 obj-$(CONFIG_MXM_WMI)          += mxm-wmi.o
 obj-$(CONFIG_INTEL_MID_POWER_BUTTON)   += intel_mid_powerbtn.o
 obj-$(CONFIG_INTEL_OAKTRAIL)   += intel_oaktrail.o
+obj-$(CONFIG_SAMSUNG_Q10)      += samsung-q10.o
index e1c4938..af2bb20 100644 (file)
@@ -99,6 +99,7 @@ enum acer_wmi_event_ids {
 static const struct key_entry acer_wmi_keymap[] = {
        {KE_KEY, 0x01, {KEY_WLAN} },     /* WiFi */
        {KE_KEY, 0x03, {KEY_WLAN} },     /* WiFi */
+       {KE_KEY, 0x04, {KEY_WLAN} },     /* WiFi */
        {KE_KEY, 0x12, {KEY_BLUETOOTH} },       /* BT */
        {KE_KEY, 0x21, {KEY_PROG1} },    /* Backup */
        {KE_KEY, 0x22, {KEY_PROG2} },    /* Arcade */
@@ -304,6 +305,10 @@ static struct quirk_entry quirk_fujitsu_amilo_li_1718 = {
        .wireless = 2,
 };
 
+static struct quirk_entry quirk_lenovo_ideapad_s205 = {
+       .wireless = 3,
+};
+
 /* The Aspire One has a dummy ACPI-WMI interface - disable it */
 static struct dmi_system_id __devinitdata acer_blacklist[] = {
        {
@@ -450,6 +455,15 @@ static struct dmi_system_id acer_quirks[] = {
                },
                .driver_data = &quirk_medion_md_98300,
        },
+       {
+               .callback = dmi_matched,
+               .ident = "Lenovo Ideapad S205",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "10382LG"),
+               },
+               .driver_data = &quirk_lenovo_ideapad_s205,
+       },
        {}
 };
 
@@ -542,6 +556,12 @@ struct wmi_interface *iface)
                                return AE_ERROR;
                        *value = result & 0x1;
                        return AE_OK;
+               case 3:
+                       err = ec_read(0x78, &result);
+                       if (err)
+                               return AE_ERROR;
+                       *value = result & 0x1;
+                       return AE_OK;
                default:
                        err = ec_read(0xA, &result);
                        if (err)
@@ -1266,8 +1286,13 @@ static void acer_rfkill_update(struct work_struct *ignored)
        acpi_status status;
 
        status = get_u32(&state, ACER_CAP_WIRELESS);
-       if (ACPI_SUCCESS(status))
-               rfkill_set_sw_state(wireless_rfkill, !state);
+       if (ACPI_SUCCESS(status)) {
+               if (quirks->wireless == 3) {
+                       rfkill_set_hw_state(wireless_rfkill, !state);
+               } else {
+                       rfkill_set_sw_state(wireless_rfkill, !state);
+               }
+       }
 
        if (has_cap(ACER_CAP_BLUETOOTH)) {
                status = get_u32(&state, ACER_CAP_BLUETOOTH);
@@ -1400,6 +1425,9 @@ static ssize_t show_bool_threeg(struct device *dev,
 {
        u32 result; \
        acpi_status status;
+
+       pr_info("This threeg sysfs will be removed in 2012"
+               " - used by: %s\n", current->comm);
        if (wmi_has_guid(WMID_GUID3))
                status = wmid3_get_device_status(&result,
                                ACER_WMID3_GDS_THREEG);
@@ -1415,8 +1443,10 @@ static ssize_t set_bool_threeg(struct device *dev,
 {
        u32 tmp = simple_strtoul(buf, NULL, 10);
        acpi_status status = set_u32(tmp, ACER_CAP_THREEG);
-               if (ACPI_FAILURE(status))
-                       return -EINVAL;
+       pr_info("This threeg sysfs will be removed in 2012"
+               " - used by: %s\n", current->comm);
+       if (ACPI_FAILURE(status))
+               return -EINVAL;
        return count;
 }
 static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg,
@@ -1425,6 +1455,8 @@ static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg,
 static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
        char *buf)
 {
+       pr_info("This interface sysfs will be removed in 2012"
+               " - used by: %s\n", current->comm);
        switch (interface->type) {
        case ACER_AMW0:
                return sprintf(buf, "AMW0\n");
index fca3489..760c6d7 100644 (file)
@@ -182,6 +182,7 @@ static const struct bios_settings_t bios_tbl[] = {
        {"Acer", "Aspire 1810T",  "v1.3308", 0x55, 0x58, {0x9e, 0x00} },
        {"Acer", "Aspire 1810TZ", "v1.3310", 0x55, 0x58, {0x9e, 0x00} },
        {"Acer", "Aspire 1810T",  "v1.3310", 0x55, 0x58, {0x9e, 0x00} },
+       {"Acer", "Aspire 1810TZ", "v1.3314", 0x55, 0x58, {0x9e, 0x00} },
        /* Acer 531 */
        {"Acer", "AO531h", "v0.3201", 0x55, 0x58, {0x20, 0x00} },
        /* Gateway */
@@ -703,15 +704,15 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Peter Feuerer");
 MODULE_DESCRIPTION("Aspire One temperature and fan driver");
 MODULE_ALIAS("dmi:*:*Acer*:pnAOA*:");
-MODULE_ALIAS("dmi:*:*Acer*:pnAspire 1410*:");
-MODULE_ALIAS("dmi:*:*Acer*:pnAspire 1810*:");
+MODULE_ALIAS("dmi:*:*Acer*:pnAspire*1410*:");
+MODULE_ALIAS("dmi:*:*Acer*:pnAspire*1810*:");
 MODULE_ALIAS("dmi:*:*Acer*:pnAO531*:");
 MODULE_ALIAS("dmi:*:*Gateway*:pnAOA*:");
 MODULE_ALIAS("dmi:*:*Gateway*:pnLT31*:");
-MODULE_ALIAS("dmi:*:*Packard Bell*:pnAOA*:");
-MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOA*:");
-MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOTMU*:");
-MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOTMA*:");
+MODULE_ALIAS("dmi:*:*Packard*Bell*:pnAOA*:");
+MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOA*:");
+MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOTMU*:");
+MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOTMA*:");
 
 module_init(acerhdf_init);
 module_exit(acerhdf_exit);
index d65df92..fa6d7ec 100644 (file)
@@ -70,11 +70,10 @@ MODULE_LICENSE("GPL");
  * WAPF defines the behavior of the Fn+Fx wlan key
  * The significance of values is yet to be found, but
  * most of the time:
- * 0x0 will do nothing
- * 0x1 will allow to control the device with Fn+Fx key.
- * 0x4 will send an ACPI event (0x88) while pressing the Fn+Fx key
- * 0x5 like 0x1 or 0x4
- * So, if something doesn't work as you want, just try other values =)
+ * Bit | Bluetooth | WLAN
+ *  0  | Hardware  | Hardware
+ *  1  | Hardware  | Software
+ *  4  | Software  | Software
  */
 static uint wapf = 1;
 module_param(wapf, uint, 0444);
index 0580d99..b0859d4 100644 (file)
@@ -38,6 +38,24 @@ MODULE_LICENSE("GPL");
 
 MODULE_ALIAS("wmi:"ASUS_NB_WMI_EVENT_GUID);
 
+/*
+ * WAPF defines the behavior of the Fn+Fx wlan key
+ * The significance of values is yet to be found, but
+ * most of the time:
+ * Bit | Bluetooth | WLAN
+ *  0  | Hardware  | Hardware
+ *  1  | Hardware  | Software
+ *  4  | Software  | Software
+ */
+static uint wapf;
+module_param(wapf, uint, 0444);
+MODULE_PARM_DESC(wapf, "WAPF value");
+
+static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver)
+{
+       driver->wapf = wapf;
+}
+
 static const struct key_entry asus_nb_wmi_keymap[] = {
        { KE_KEY, 0x30, { KEY_VOLUMEUP } },
        { KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
@@ -53,16 +71,16 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
        { KE_KEY, 0x51, { KEY_WWW } },
        { KE_KEY, 0x55, { KEY_CALC } },
        { KE_KEY, 0x5C, { KEY_F15 } },  /* Power Gear key */
-       { KE_KEY, 0x5D, { KEY_WLAN } },
-       { KE_KEY, 0x5E, { KEY_WLAN } },
-       { KE_KEY, 0x5F, { KEY_WLAN } },
+       { KE_KEY, 0x5D, { KEY_WLAN } }, /* Wireless console Toggle */
+       { KE_KEY, 0x5E, { KEY_WLAN } }, /* Wireless console Enable */
+       { KE_KEY, 0x5F, { KEY_WLAN } }, /* Wireless console Disable */
        { KE_KEY, 0x60, { KEY_SWITCHVIDEOMODE } },
        { KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } },
        { KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } },
        { KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } },
        { KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } },
-       { KE_KEY, 0x7E, { KEY_BLUETOOTH } },
        { KE_KEY, 0x7D, { KEY_BLUETOOTH } },
+       { KE_KEY, 0x7E, { KEY_BLUETOOTH } },
        { KE_KEY, 0x82, { KEY_CAMERA } },
        { KE_KEY, 0x88, { KEY_RFKILL  } },
        { KE_KEY, 0x8A, { KEY_PROG1 } },
@@ -81,6 +99,7 @@ static struct asus_wmi_driver asus_nb_wmi_driver = {
        .keymap = asus_nb_wmi_keymap,
        .input_name = "Asus WMI hotkeys",
        .input_phys = ASUS_NB_WMI_FILE "/input0",
+       .quirks = asus_nb_wmi_quirks,
 };
 
 
index 65b66aa..95cba9e 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/platform_device.h>
+#include <linux/thermal.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 
@@ -66,6 +67,8 @@ MODULE_LICENSE("GPL");
 #define NOTIFY_BRNUP_MAX               0x1f
 #define NOTIFY_BRNDOWN_MIN             0x20
 #define NOTIFY_BRNDOWN_MAX             0x2e
+#define NOTIFY_KBD_BRTUP               0xc4
+#define NOTIFY_KBD_BRTDWN              0xc5
 
 /* WMI Methods */
 #define ASUS_WMI_METHODID_SPEC         0x43455053 /* BIOS SPECification */
@@ -93,6 +96,7 @@ MODULE_LICENSE("GPL");
 /* Wireless */
 #define ASUS_WMI_DEVID_HW_SWITCH       0x00010001
 #define ASUS_WMI_DEVID_WIRELESS_LED    0x00010002
+#define ASUS_WMI_DEVID_CWAP            0x00010003
 #define ASUS_WMI_DEVID_WLAN            0x00010011
 #define ASUS_WMI_DEVID_BLUETOOTH       0x00010013
 #define ASUS_WMI_DEVID_GPS             0x00010015
@@ -102,6 +106,12 @@ MODULE_LICENSE("GPL");
 
 /* Leds */
 /* 0x000200XX and 0x000400XX */
+#define ASUS_WMI_DEVID_LED1            0x00020011
+#define ASUS_WMI_DEVID_LED2            0x00020012
+#define ASUS_WMI_DEVID_LED3            0x00020013
+#define ASUS_WMI_DEVID_LED4            0x00020014
+#define ASUS_WMI_DEVID_LED5            0x00020015
+#define ASUS_WMI_DEVID_LED6            0x00020016
 
 /* Backlight and Brightness */
 #define ASUS_WMI_DEVID_BACKLIGHT       0x00050011
@@ -174,13 +184,18 @@ struct asus_wmi {
 
        struct led_classdev tpd_led;
        int tpd_led_wk;
+       struct led_classdev kbd_led;
+       int kbd_led_wk;
        struct workqueue_struct *led_workqueue;
        struct work_struct tpd_led_work;
+       struct work_struct kbd_led_work;
 
        struct asus_rfkill wlan;
        struct asus_rfkill bluetooth;
        struct asus_rfkill wimax;
        struct asus_rfkill wwan3g;
+       struct asus_rfkill gps;
+       struct asus_rfkill uwb;
 
        struct hotplug_slot *hotplug_slot;
        struct mutex hotplug_lock;
@@ -205,6 +220,7 @@ static int asus_wmi_input_init(struct asus_wmi *asus)
        asus->inputdev->phys = asus->driver->input_phys;
        asus->inputdev->id.bustype = BUS_HOST;
        asus->inputdev->dev.parent = &asus->platform_device->dev;
+       set_bit(EV_REP, asus->inputdev->evbit);
 
        err = sparse_keymap_setup(asus->inputdev, asus->driver->keymap, NULL);
        if (err)
@@ -359,30 +375,80 @@ static enum led_brightness tpd_led_get(struct led_classdev *led_cdev)
        return read_tpd_led_state(asus);
 }
 
-static int asus_wmi_led_init(struct asus_wmi *asus)
+static void kbd_led_update(struct work_struct *work)
 {
-       int rv;
+       int ctrl_param = 0;
+       struct asus_wmi *asus;
 
-       if (read_tpd_led_state(asus) < 0)
-               return 0;
+       asus = container_of(work, struct asus_wmi, kbd_led_work);
 
-       asus->led_workqueue = create_singlethread_workqueue("led_workqueue");
-       if (!asus->led_workqueue)
-               return -ENOMEM;
-       INIT_WORK(&asus->tpd_led_work, tpd_led_update);
+       /*
+        * bits 0-2: level
+        * bit 7: light on/off
+        */
+       if (asus->kbd_led_wk > 0)
+               ctrl_param = 0x80 | (asus->kbd_led_wk & 0x7F);
 
-       asus->tpd_led.name = "asus::touchpad";
-       asus->tpd_led.brightness_set = tpd_led_set;
-       asus->tpd_led.brightness_get = tpd_led_get;
-       asus->tpd_led.max_brightness = 1;
+       asus_wmi_set_devstate(ASUS_WMI_DEVID_KBD_BACKLIGHT, ctrl_param, NULL);
+}
 
-       rv = led_classdev_register(&asus->platform_device->dev, &asus->tpd_led);
-       if (rv) {
-               destroy_workqueue(asus->led_workqueue);
-               return rv;
+static int kbd_led_read(struct asus_wmi *asus, int *level, int *env)
+{
+       int retval;
+
+       /*
+        * bits 0-2: level
+        * bit 7: light on/off
+        * bit 8-10: environment (0: dark, 1: normal, 2: light)
+        * bit 17: status unknown
+        */
+       retval = asus_wmi_get_devstate_bits(asus, ASUS_WMI_DEVID_KBD_BACKLIGHT,
+                                           0xFFFF);
+
+       /* Unknown status is considered as off */
+       if (retval == 0x8000)
+               retval = 0;
+
+       if (retval >= 0) {
+               if (level)
+                       *level = retval & 0x80 ? retval & 0x7F : 0;
+               if (env)
+                       *env = (retval >> 8) & 0x7F;
+               retval = 0;
        }
 
-       return 0;
+       return retval;
+}
+
+static void kbd_led_set(struct led_classdev *led_cdev,
+                       enum led_brightness value)
+{
+       struct asus_wmi *asus;
+
+       asus = container_of(led_cdev, struct asus_wmi, kbd_led);
+
+       if (value > asus->kbd_led.max_brightness)
+               value = asus->kbd_led.max_brightness;
+       else if (value < 0)
+               value = 0;
+
+       asus->kbd_led_wk = value;
+       queue_work(asus->led_workqueue, &asus->kbd_led_work);
+}
+
+static enum led_brightness kbd_led_get(struct led_classdev *led_cdev)
+{
+       struct asus_wmi *asus;
+       int retval, value;
+
+       asus = container_of(led_cdev, struct asus_wmi, kbd_led);
+
+       retval = kbd_led_read(asus, &value, NULL);
+
+       if (retval < 0)
+               return retval;
+
+       return value;
 }
 
 static void asus_wmi_led_exit(struct asus_wmi *asus)
@@ -393,6 +459,48 @@ static void asus_wmi_led_exit(struct asus_wmi *asus)
                destroy_workqueue(asus->led_workqueue);
 }
 
+static int asus_wmi_led_init(struct asus_wmi *asus)
+{
+       int rv = 0;
+
+       asus->led_workqueue = create_singlethread_workqueue("led_workqueue");
+       if (!asus->led_workqueue)
+               return -ENOMEM;
+
+       if (read_tpd_led_state(asus) >= 0) {
+               INIT_WORK(&asus->tpd_led_work, tpd_led_update);
+
+               asus->tpd_led.name = "asus::touchpad";
+               asus->tpd_led.brightness_set = tpd_led_set;
+               asus->tpd_led.brightness_get = tpd_led_get;
+               asus->tpd_led.max_brightness = 1;
+
+               rv = led_classdev_register(&asus->platform_device->dev,
+                                          &asus->tpd_led);
+               if (rv)
+                       goto error;
+       }
+
+       if (kbd_led_read(asus, NULL, NULL) >= 0) {
+               INIT_WORK(&asus->kbd_led_work, kbd_led_update);
+
+               asus->kbd_led.name = "asus::kbd_backlight";
+               asus->kbd_led.brightness_set = kbd_led_set;
+               asus->kbd_led.brightness_get = kbd_led_get;
+               asus->kbd_led.max_brightness = 3;
+
+               rv = led_classdev_register(&asus->platform_device->dev,
+                                          &asus->kbd_led);
+       }
+
+error:
+       if (rv)
+               asus_wmi_led_exit(asus);
+
+       return rv;
+}
+
+
 /*
  * PCI hotplug (for wlan rfkill)
  */
@@ -729,6 +837,16 @@ static void asus_wmi_rfkill_exit(struct asus_wmi *asus)
                rfkill_destroy(asus->wwan3g.rfkill);
                asus->wwan3g.rfkill = NULL;
        }
+       if (asus->gps.rfkill) {
+               rfkill_unregister(asus->gps.rfkill);
+               rfkill_destroy(asus->gps.rfkill);
+               asus->gps.rfkill = NULL;
+       }
+       if (asus->uwb.rfkill) {
+               rfkill_unregister(asus->uwb.rfkill);
+               rfkill_destroy(asus->uwb.rfkill);
+               asus->uwb.rfkill = NULL;
+       }
 }
 
 static int asus_wmi_rfkill_init(struct asus_wmi *asus)
@@ -763,6 +881,18 @@ static int asus_wmi_rfkill_init(struct asus_wmi *asus)
        if (result && result != -ENODEV)
                goto exit;
 
+       result = asus_new_rfkill(asus, &asus->gps, "asus-gps",
+                                RFKILL_TYPE_GPS, ASUS_WMI_DEVID_GPS);
+
+       if (result && result != -ENODEV)
+               goto exit;
+
+       result = asus_new_rfkill(asus, &asus->uwb, "asus-uwb",
+                                RFKILL_TYPE_UWB, ASUS_WMI_DEVID_UWB);
+
+       if (result && result != -ENODEV)
+               goto exit;
+
        if (!asus->driver->hotplug_wireless)
                goto exit;
 
@@ -797,8 +927,8 @@ exit:
  * Hwmon device
  */
 static ssize_t asus_hwmon_pwm1(struct device *dev,
-                           struct device_attribute *attr,
-                           char *buf)
+                              struct device_attribute *attr,
+                              char *buf)
 {
        struct asus_wmi *asus = dev_get_drvdata(dev);
        u32 value;
@@ -809,7 +939,7 @@ static ssize_t asus_hwmon_pwm1(struct device *dev,
        if (err < 0)
                return err;
 
-       value |= 0xFF;
+       value &= 0xFF;
 
        if (value == 1) /* Low Speed */
                value = 85;
@@ -825,7 +955,26 @@ static ssize_t asus_hwmon_pwm1(struct device *dev,
        return sprintf(buf, "%d\n", value);
 }
 
+static ssize_t asus_hwmon_temp1(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf)
+{
+       struct asus_wmi *asus = dev_get_drvdata(dev);
+       u32 value;
+       int err;
+
+       err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_THERMAL_CTRL, &value);
+
+       if (err < 0)
+               return err;
+
+       value = KELVIN_TO_CELSIUS((value & 0xFFFF)) * 1000;
+
+       return sprintf(buf, "%d\n", value);
+}
+
 static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO, asus_hwmon_pwm1, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, asus_hwmon_temp1, NULL, 0);
 
 static ssize_t
 show_name(struct device *dev, struct device_attribute *attr, char *buf)
@@ -836,12 +985,13 @@ static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
 
 static struct attribute *hwmon_attributes[] = {
        &sensor_dev_attr_pwm1.dev_attr.attr,
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
        &sensor_dev_attr_name.dev_attr.attr,
        NULL
 };
 
 static mode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj,
-                                   struct attribute *attr, int idx)
+                                         struct attribute *attr, int idx)
 {
        struct device *dev = container_of(kobj, struct device, kobj);
        struct platform_device *pdev = to_platform_device(dev->parent);
@@ -852,6 +1002,8 @@ static mode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj,
 
        if (attr == &sensor_dev_attr_pwm1.dev_attr.attr)
                dev_id = ASUS_WMI_DEVID_FAN_CTRL;
+       else if (attr == &sensor_dev_attr_temp1_input.dev_attr.attr)
+               dev_id = ASUS_WMI_DEVID_THERMAL_CTRL;
 
        if (dev_id != -1) {
                int err = asus_wmi_get_devstate(asus, dev_id, &value);
@@ -869,9 +1021,13 @@ static mode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj,
                 * - reverved bits are non-zero
                 * - sfun and presence bit are not set
                 */
-               if (value != ASUS_WMI_UNSUPPORTED_METHOD || value & 0xFFF80000
+               if (value == ASUS_WMI_UNSUPPORTED_METHOD || value & 0xFFF80000
                    || (!asus->sfun && !(value & ASUS_WMI_DSTS_PRESENCE_BIT)))
                        ok = false;
+       } else if (dev_id == ASUS_WMI_DEVID_THERMAL_CTRL) {
+               /* If value is zero, something is clearly wrong */
+               if (value == 0)
+                       ok = false;
        }
 
        return ok ? attr->mode : 0;
@@ -904,6 +1060,7 @@ static int asus_wmi_hwmon_init(struct asus_wmi *asus)
                pr_err("Could not register asus hwmon device\n");
                return PTR_ERR(hwmon);
        }
+       dev_set_drvdata(hwmon, asus);
        asus->hwmon_device = hwmon;
        result = sysfs_create_group(&hwmon->kobj, &hwmon_attribute_group);
        if (result)
@@ -1060,6 +1217,8 @@ static void asus_wmi_notify(u32 value, void *context)
        acpi_status status;
        int code;
        int orig_code;
+       unsigned int key_value = 1;
+       bool autorelease = 1;
 
        status = wmi_get_event_data(value, &response);
        if (status != AE_OK) {
@@ -1075,6 +1234,13 @@ static void asus_wmi_notify(u32 value, void *context)
        code = obj->integer.value;
        orig_code = code;
 
+       if (asus->driver->key_filter) {
+               asus->driver->key_filter(asus->driver, &code, &key_value,
+                                        &autorelease);
+               if (code == ASUS_WMI_KEY_IGNORE)
+                       goto exit;
+       }
+
        if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)
                code = NOTIFY_BRNUP_MIN;
        else if (code >= NOTIFY_BRNDOWN_MIN &&
@@ -1084,7 +1250,8 @@ static void asus_wmi_notify(u32 value, void *context)
        if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) {
                if (!acpi_video_backlight_support())
                        asus_wmi_backlight_notify(asus, orig_code);
-       } else if (!sparse_keymap_report_event(asus->inputdev, code, 1, true))
+       } else if (!sparse_keymap_report_event(asus->inputdev, code,
+                                              key_value, autorelease))
                pr_info("Unknown key %x pressed\n", code);
 
 exit:
@@ -1164,14 +1331,18 @@ ASUS_WMI_CREATE_DEVICE_ATTR(cardr, 0644, ASUS_WMI_DEVID_CARDREADER);
 static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr,
                           const char *buf, size_t count)
 {
-       int value;
+       int value, rv;
 
        if (!count || sscanf(buf, "%i", &value) != 1)
                return -EINVAL;
        if (value < 0 || value > 2)
                return -EINVAL;
 
-       return asus_wmi_evaluate_method(ASUS_WMI_METHODID_CFVS, value, 0, NULL);
+       rv = asus_wmi_evaluate_method(ASUS_WMI_METHODID_CFVS, value, 0, NULL);
+       if (rv < 0)
+               return rv;
+
+       return count;
 }
 
 static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv);
@@ -1234,7 +1405,7 @@ static int asus_wmi_platform_init(struct asus_wmi *asus)
 
        /* We don't know yet what to do with this version... */
        if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_SPEC, 0, 0x9, &rv)) {
-               pr_info("BIOS WMI version: %d.%d", rv >> 8, rv & 0xFF);
+               pr_info("BIOS WMI version: %d.%d", rv >> 16, rv & 0xFF);
                asus->spec = rv;
        }
 
@@ -1266,6 +1437,12 @@ static int asus_wmi_platform_init(struct asus_wmi *asus)
                return -ENODEV;
        }
 
+       /* CWAP allow to define the behavior of the Fn+F2 key,
+        * this method doesn't seems to be present on Eee PCs */
+       if (asus->driver->wapf >= 0)
+               asus_wmi_set_devstate(ASUS_WMI_DEVID_CWAP,
+                                     asus->driver->wapf, NULL);
+
        return asus_wmi_sysfs_init(asus->platform_device);
 }
 
@@ -1568,6 +1745,14 @@ static int asus_hotk_restore(struct device *device)
                bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WWAN3G);
                rfkill_set_sw_state(asus->wwan3g.rfkill, bl);
        }
+       if (asus->gps.rfkill) {
+               bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_GPS);
+               rfkill_set_sw_state(asus->gps.rfkill, bl);
+       }
+       if (asus->uwb.rfkill) {
+               bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_UWB);
+               rfkill_set_sw_state(asus->uwb.rfkill, bl);
+       }
 
        return 0;
 }
@@ -1604,7 +1789,7 @@ static int asus_wmi_probe(struct platform_device *pdev)
 
 static bool used;
 
-int asus_wmi_register_driver(struct asus_wmi_driver *driver)
+int __init_or_module asus_wmi_register_driver(struct asus_wmi_driver *driver)
 {
        struct platform_driver *platform_driver;
        struct platform_device *platform_device;
index c044522..8147c10 100644 (file)
 
 #include <linux/platform_device.h>
 
+#define ASUS_WMI_KEY_IGNORE (-1)
+
 struct module;
 struct key_entry;
 struct asus_wmi;
 
 struct asus_wmi_driver {
        bool                    hotplug_wireless;
+       int                     wapf;
 
        const char              *name;
        struct module           *owner;
@@ -44,6 +47,10 @@ struct asus_wmi_driver {
        const struct key_entry  *keymap;
        const char              *input_name;
        const char              *input_phys;
+       /* Returns new code, value, and autorelease values in arguments.
+        * Return ASUS_WMI_KEY_IGNORE in code if event should be ignored. */
+       void (*key_filter) (struct asus_wmi_driver *driver, int *code,
+                           unsigned int *value, bool *autorelease);
 
        int (*probe) (struct platform_device *device);
        void (*quirks) (struct asus_wmi_driver *driver);
index e39ab1d..f31fa4e 100644 (file)
@@ -612,7 +612,6 @@ static int __init dell_init(void)
        if (!bufferpage)
                goto fail_buffer;
        buffer = page_address(bufferpage);
-       mutex_init(&buffer_mutex);
 
        ret = dell_setup_rfkill();
 
index ce79082..fa9a217 100644 (file)
@@ -54,6 +54,8 @@ MODULE_ALIAS("wmi:"DELL_EVENT_GUID);
  */
 
 static const struct key_entry dell_wmi_legacy_keymap[] __initconst = {
+       { KE_IGNORE, 0x003a, { KEY_CAPSLOCK } },
+
        { KE_KEY, 0xe045, { KEY_PROG1 } },
        { KE_KEY, 0xe009, { KEY_EJECTCD } },
 
@@ -85,6 +87,11 @@ static const struct key_entry dell_wmi_legacy_keymap[] __initconst = {
        { KE_IGNORE, 0xe013, { KEY_RESERVED } },
 
        { KE_IGNORE, 0xe020, { KEY_MUTE } },
+
+       /* Shortcut and audio panel keys */
+       { KE_IGNORE, 0xe025, { KEY_RESERVED } },
+       { KE_IGNORE, 0xe026, { KEY_RESERVED } },
+
        { KE_IGNORE, 0xe02e, { KEY_VOLUMEDOWN } },
        { KE_IGNORE, 0xe030, { KEY_VOLUMEUP } },
        { KE_IGNORE, 0xe033, { KEY_KBDILLUMUP } },
@@ -92,6 +99,9 @@ static const struct key_entry dell_wmi_legacy_keymap[] __initconst = {
        { KE_IGNORE, 0xe03a, { KEY_CAPSLOCK } },
        { KE_IGNORE, 0xe045, { KEY_NUMLOCK } },
        { KE_IGNORE, 0xe046, { KEY_SCROLLLOCK } },
+       { KE_IGNORE, 0xe0f7, { KEY_MUTE } },
+       { KE_IGNORE, 0xe0f8, { KEY_VOLUMEDOWN } },
+       { KE_IGNORE, 0xe0f9, { KEY_VOLUMEUP } },
        { KE_END, 0 }
 };
 
index 4aa867a..9f6e643 100644 (file)
@@ -56,6 +56,11 @@ MODULE_PARM_DESC(hotplug_wireless,
                 "If your laptop needs that, please report to "
                 "acpi4asus-user@lists.sourceforge.net.");
 
+/* Values for T101MT "Home" key */
+#define HOME_PRESS     0xe4
+#define HOME_HOLD      0xea
+#define HOME_RELEASE   0xe5
+
 static const struct key_entry eeepc_wmi_keymap[] = {
        /* Sleep already handled via generic ACPI code */
        { KE_KEY, 0x30, { KEY_VOLUMEUP } },
@@ -71,6 +76,7 @@ static const struct key_entry eeepc_wmi_keymap[] = {
        { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } },
        { KE_KEY, 0xe0, { KEY_PROG1 } }, /* Task Manager */
        { KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */
+       { KE_KEY, HOME_PRESS, { KEY_CONFIG } }, /* Home/Express gate key */
        { KE_KEY, 0xe8, { KEY_SCREENLOCK } },
        { KE_KEY, 0xe9, { KEY_BRIGHTNESS_ZERO } },
        { KE_KEY, 0xeb, { KEY_CAMERA_ZOOMOUT } },
@@ -81,6 +87,25 @@ static const struct key_entry eeepc_wmi_keymap[] = {
        { KE_END, 0},
 };
 
+static void eeepc_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code,
+                                unsigned int *value, bool *autorelease)
+{
+       switch (*code) {
+       case HOME_PRESS:
+               *value = 1;
+               *autorelease = 0;
+               break;
+       case HOME_HOLD:
+               *code = ASUS_WMI_KEY_IGNORE;
+               break;
+       case HOME_RELEASE:
+               *code = HOME_PRESS;
+               *value = 0;
+               *autorelease = 0;
+               break;
+       }
+}
+
 static acpi_status eeepc_wmi_parse_device(acpi_handle handle, u32 level,
                                                 void *context, void **retval)
 {
@@ -141,6 +166,7 @@ static void eeepc_dmi_check(struct asus_wmi_driver *driver)
 static void eeepc_wmi_quirks(struct asus_wmi_driver *driver)
 {
        driver->hotplug_wireless = hotplug_wireless;
+       driver->wapf = -1;
        eeepc_dmi_check(driver);
 }
 
@@ -151,6 +177,7 @@ static struct asus_wmi_driver asus_wmi_driver = {
        .keymap = eeepc_wmi_keymap,
        .input_name = "Eee PC WMI hotkeys",
        .input_phys = EEEPC_WMI_FILE "/input0",
+       .key_filter = eeepc_wmi_key_filter,
        .probe = eeepc_wmi_probe,
        .quirks = eeepc_wmi_quirks,
 };
index bfdda33..0c59541 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/input.h>
 #include <linux/input/sparse-keymap.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
 
 #define IDEAPAD_RFKILL_DEV_NUM (3)
 
+#define CFG_BT_BIT     (16)
+#define CFG_3G_BIT     (17)
+#define CFG_WIFI_BIT   (18)
+#define CFG_CAMERA_BIT (19)
+
 struct ideapad_private {
        struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM];
        struct platform_device *platform_device;
        struct input_dev *inputdev;
+       struct backlight_device *blightdev;
+       unsigned long cfg;
 };
 
 static acpi_handle ideapad_handle;
@@ -155,7 +164,7 @@ static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data)
 }
 
 /*
- * camera power
+ * sysfs
  */
 static ssize_t show_ideapad_cam(struct device *dev,
                                struct device_attribute *attr,
@@ -186,6 +195,44 @@ static ssize_t store_ideapad_cam(struct device *dev,
 
 static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam);
 
+static ssize_t show_ideapad_cfg(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf)
+{
+       struct ideapad_private *priv = dev_get_drvdata(dev);
+
+       return sprintf(buf, "0x%.8lX\n", priv->cfg);
+}
+
+static DEVICE_ATTR(cfg, 0444, show_ideapad_cfg, NULL);
+
+static struct attribute *ideapad_attributes[] = {
+       &dev_attr_camera_power.attr,
+       &dev_attr_cfg.attr,
+       NULL
+};
+
+static mode_t ideapad_is_visible(struct kobject *kobj,
+                                struct attribute *attr,
+                                int idx)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct ideapad_private *priv = dev_get_drvdata(dev);
+       bool supported;
+
+       if (attr == &dev_attr_camera_power.attr)
+               supported = test_bit(CFG_CAMERA_BIT, &(priv->cfg));
+       else
+               supported = true;
+
+       return supported ? attr->mode : 0;
+}
+
+static struct attribute_group ideapad_attribute_group = {
+       .is_visible = ideapad_is_visible,
+       .attrs = ideapad_attributes
+};
+
 /*
  * Rfkill
  */
@@ -197,9 +244,9 @@ struct ideapad_rfk_data {
 };
 
 const struct ideapad_rfk_data ideapad_rfk_data[] = {
-       { "ideapad_wlan",       18, 0x15, RFKILL_TYPE_WLAN },
-       { "ideapad_bluetooth",  16, 0x17, RFKILL_TYPE_BLUETOOTH },
-       { "ideapad_3g",         17, 0x20, RFKILL_TYPE_WWAN },
+       { "ideapad_wlan",      CFG_WIFI_BIT, 0x15, RFKILL_TYPE_WLAN },
+       { "ideapad_bluetooth", CFG_BT_BIT,   0x17, RFKILL_TYPE_BLUETOOTH },
+       { "ideapad_3g",        CFG_3G_BIT,   0x20, RFKILL_TYPE_WWAN },
 };
 
 static int ideapad_rfk_set(void *data, bool blocked)
@@ -265,8 +312,7 @@ static int __devinit ideapad_register_rfkill(struct acpi_device *adevice,
        return 0;
 }
 
-static void __devexit ideapad_unregister_rfkill(struct acpi_device *adevice,
-                                               int dev)
+static void ideapad_unregister_rfkill(struct acpi_device *adevice, int dev)
 {
        struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
 
@@ -280,15 +326,6 @@ static void __devexit ideapad_unregister_rfkill(struct acpi_device *adevice,
 /*
  * Platform device
  */
-static struct attribute *ideapad_attributes[] = {
-       &dev_attr_camera_power.attr,
-       NULL
-};
-
-static struct attribute_group ideapad_attribute_group = {
-       .attrs = ideapad_attributes
-};
-
 static int __devinit ideapad_platform_init(struct ideapad_private *priv)
 {
        int result;
@@ -369,7 +406,7 @@ err_free_dev:
        return error;
 }
 
-static void __devexit ideapad_input_exit(struct ideapad_private *priv)
+static void ideapad_input_exit(struct ideapad_private *priv)
 {
        sparse_keymap_free(priv->inputdev);
        input_unregister_device(priv->inputdev);
@@ -382,6 +419,98 @@ static void ideapad_input_report(struct ideapad_private *priv,
        sparse_keymap_report_event(priv->inputdev, scancode, 1, true);
 }
 
+/*
+ * backlight
+ */
+static int ideapad_backlight_get_brightness(struct backlight_device *blightdev)
+{
+       unsigned long now;
+
+       if (read_ec_data(ideapad_handle, 0x12, &now))
+               return -EIO;
+       return now;
+}
+
+static int ideapad_backlight_update_status(struct backlight_device *blightdev)
+{
+       if (write_ec_cmd(ideapad_handle, 0x13, blightdev->props.brightness))
+               return -EIO;
+       if (write_ec_cmd(ideapad_handle, 0x33,
+                        blightdev->props.power == FB_BLANK_POWERDOWN ? 0 : 1))
+               return -EIO;
+
+       return 0;
+}
+
+static const struct backlight_ops ideapad_backlight_ops = {
+       .get_brightness = ideapad_backlight_get_brightness,
+       .update_status = ideapad_backlight_update_status,
+};
+
+static int ideapad_backlight_init(struct ideapad_private *priv)
+{
+       struct backlight_device *blightdev;
+       struct backlight_properties props;
+       unsigned long max, now, power;
+
+       if (read_ec_data(ideapad_handle, 0x11, &max))
+               return -EIO;
+       if (read_ec_data(ideapad_handle, 0x12, &now))
+               return -EIO;
+       if (read_ec_data(ideapad_handle, 0x18, &power))
+               return -EIO;
+
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = max;
+       props.type = BACKLIGHT_PLATFORM;
+       blightdev = backlight_device_register("ideapad",
+                                             &priv->platform_device->dev,
+                                             priv,
+                                             &ideapad_backlight_ops,
+                                             &props);
+       if (IS_ERR(blightdev)) {
+               pr_err("Could not register backlight device\n");
+               return PTR_ERR(blightdev);
+       }
+
+       priv->blightdev = blightdev;
+       blightdev->props.brightness = now;
+       blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
+       backlight_update_status(blightdev);
+
+       return 0;
+}
+
+static void ideapad_backlight_exit(struct ideapad_private *priv)
+{
+       if (priv->blightdev)
+               backlight_device_unregister(priv->blightdev);
+       priv->blightdev = NULL;
+}
+
+static void ideapad_backlight_notify_power(struct ideapad_private *priv)
+{
+       unsigned long power;
+       struct backlight_device *blightdev = priv->blightdev;
+
+       if (read_ec_data(ideapad_handle, 0x18, &power))
+               return;
+       blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
+}
+
+static void ideapad_backlight_notify_brightness(struct ideapad_private *priv)
+{
+       unsigned long now;
+
+       /* if we control brightness via acpi video driver */
+       if (priv->blightdev == NULL) {
+               read_ec_data(ideapad_handle, 0x12, &now);
+               return;
+       }
+
+       backlight_force_update(priv->blightdev, BACKLIGHT_UPDATE_HOTKEY);
+}
+
 /*
  * module init/exit
  */
@@ -393,10 +522,11 @@ MODULE_DEVICE_TABLE(acpi, ideapad_device_ids);
 
 static int __devinit ideapad_acpi_add(struct acpi_device *adevice)
 {
-       int ret, i, cfg;
+       int ret, i;
+       unsigned long cfg;
        struct ideapad_private *priv;
 
-       if (read_method_int(adevice->handle, "_CFG", &cfg))
+       if (read_method_int(adevice->handle, "_CFG", (int *)&cfg))
                return -ENODEV;
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
@@ -404,6 +534,7 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice)
                return -ENOMEM;
        dev_set_drvdata(&adevice->dev, priv);
        ideapad_handle = adevice->handle;
+       priv->cfg = cfg;
 
        ret = ideapad_platform_init(priv);
        if (ret)
@@ -414,15 +545,25 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice)
                goto input_failed;
 
        for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) {
-               if (test_bit(ideapad_rfk_data[i].cfgbit, (unsigned long *)&cfg))
+               if (test_bit(ideapad_rfk_data[i].cfgbit, &cfg))
                        ideapad_register_rfkill(adevice, i);
                else
                        priv->rfk[i] = NULL;
        }
        ideapad_sync_rfk_state(adevice);
 
+       if (!acpi_video_backlight_support()) {
+               ret = ideapad_backlight_init(priv);
+               if (ret && ret != -ENODEV)
+                       goto backlight_failed;
+       }
+
        return 0;
 
+backlight_failed:
+       for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
+               ideapad_unregister_rfkill(adevice, i);
+       ideapad_input_exit(priv);
 input_failed:
        ideapad_platform_exit(priv);
 platform_failed:
@@ -435,6 +576,7 @@ static int __devexit ideapad_acpi_remove(struct acpi_device *adevice, int type)
        struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
        int i;
 
+       ideapad_backlight_exit(priv);
        for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
                ideapad_unregister_rfkill(adevice, i);
        ideapad_input_exit(priv);
@@ -459,12 +601,19 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
        vpc1 = (vpc2 << 8) | vpc1;
        for (vpc_bit = 0; vpc_bit < 16; vpc_bit++) {
                if (test_bit(vpc_bit, &vpc1)) {
-                       if (vpc_bit == 9)
+                       switch (vpc_bit) {
+                       case 9:
                                ideapad_sync_rfk_state(adevice);
-                       else if (vpc_bit == 4)
-                               read_ec_data(handle, 0x12, &vpc2);
-                       else
+                               break;
+                       case 4:
+                               ideapad_backlight_notify_brightness(priv);
+                               break;
+                       case 2:
+                               ideapad_backlight_notify_power(priv);
+                               break;
+                       default:
                                ideapad_input_report(priv, vpc_bit);
+                       }
                }
        }
 }
index 5ffe7c3..809a3ae 100644 (file)
@@ -403,7 +403,7 @@ static void ips_cpu_raise(struct ips_driver *ips)
 
        thm_writew(THM_MPCPC, (new_tdp_limit * 10) / 8);
 
-       turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDC_OVR_EN;
+       turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDP_OVR_EN;
        wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override);
 
        turbo_override &= ~TURBO_TDP_MASK;
@@ -438,7 +438,7 @@ static void ips_cpu_lower(struct ips_driver *ips)
 
        thm_writew(THM_MPCPC, (new_limit * 10) / 8);
 
-       turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDC_OVR_EN;
+       turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDP_OVR_EN;
        wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override);
 
        turbo_override &= ~TURBO_TDP_MASK;
index 809adea..abddc83 100644 (file)
@@ -477,6 +477,8 @@ static acpi_status intel_menlow_register_sensor(acpi_handle handle, u32 lvl,
                return AE_ERROR;
        }
 
+       return AE_OK;
+
  aux1_not_found:
        if (status == AE_NOT_FOUND)
                return AE_OK;
index 3a57832..ccd7b1f 100644 (file)
@@ -493,20 +493,30 @@ static int mid_thermal_probe(struct platform_device *pdev)
 
        /* Register each sensor with the generic thermal framework*/
        for (i = 0; i < MSIC_THERMAL_SENSORS; i++) {
+               struct thermal_device_info *td_info = initialize_sensor(i);
+
+               if (!td_info) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
                pinfo->tzd[i] = thermal_zone_device_register(name[i],
-                               0, initialize_sensor(i), &tzd_ops, 0, 0, 0, 0);
-               if (IS_ERR(pinfo->tzd[i]))
-                       goto reg_fail;
+                               0, td_info, &tzd_ops, 0, 0, 0, 0);
+               if (IS_ERR(pinfo->tzd[i])) {
+                       kfree(td_info);
+                       ret = PTR_ERR(pinfo->tzd[i]);
+                       goto err;
+               }
        }
 
        pinfo->pdev = pdev;
        platform_set_drvdata(pdev, pinfo);
        return 0;
 
-reg_fail:
-       ret = PTR_ERR(pinfo->tzd[i]);
-       while (--i >= 0)
+err:
+       while (--i >= 0) {
+               kfree(pinfo->tzd[i]->devdata);
                thermal_zone_device_unregister(pinfo->tzd[i]);
+       }
        configure_adc(0);
        kfree(pinfo);
        return ret;
@@ -524,8 +534,10 @@ static int mid_thermal_remove(struct platform_device *pdev)
        int i;
        struct platform_info *pinfo = platform_get_drvdata(pdev);
 
-       for (i = 0; i < MSIC_THERMAL_SENSORS; i++)
+       for (i = 0; i < MSIC_THERMAL_SENSORS; i++) {
+               kfree(pinfo->tzd[i]->devdata);
                thermal_zone_device_unregister(pinfo->tzd[i]);
+       }
 
        kfree(pinfo);
        platform_set_drvdata(pdev, NULL);
index bde47e9..c8a6aed 100644 (file)
@@ -637,15 +637,13 @@ end_function:
        return error;
 }
 
-const struct pci_device_id rar_pci_id_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(rar_pci_id_tbl) = {
        { PCI_VDEVICE(INTEL, 0x4110) },
        { 0 }
 };
 
 MODULE_DEVICE_TABLE(pci, rar_pci_id_tbl);
 
-const struct pci_device_id *my_id_table = rar_pci_id_tbl;
-
 /* field for registering driver to PCI device */
 static struct pci_driver rar_pci_driver = {
        .name = "rar_register_driver",
index 940accb..c866653 100644 (file)
@@ -725,7 +725,7 @@ static void ipc_remove(struct pci_dev *pdev)
        intel_scu_devices_destroy();
 }
 
-static const struct pci_device_id pci_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(pci_ids) = {
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080e)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x082a)},
        { 0,}
index 3ff629d..f204643 100644 (file)
@@ -538,6 +538,15 @@ static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = {
                },
                .callback = dmi_check_cb
        },
+       {
+               .ident = "MSI U270",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR,
+                               "Micro-Star International Co., Ltd."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "U270 series"),
+               },
+               .callback = dmi_check_cb
+       },
        { }
 };
 
@@ -996,3 +1005,4 @@ MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N034:*");
 MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N051:*");
 MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N014:*");
 MODULE_ALIAS("dmi:*:svnMicro-StarInternational*:pnCR620:*");
+MODULE_ALIAS("dmi:*:svnMicro-StarInternational*:pnU270series:*");
index c832e33..6f40bf2 100644 (file)
@@ -272,6 +272,7 @@ static int __init msi_wmi_init(void)
 err_free_backlight:
        backlight_device_unregister(backlight);
 err_free_input:
+       sparse_keymap_free(msi_wmi_input_dev);
        input_unregister_device(msi_wmi_input_dev);
 err_uninstall_notifier:
        wmi_remove_notify_handler(MSIWMI_EVENT_GUID);
index d347116..3591630 100644 (file)
@@ -520,6 +520,16 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
                },
                .callback = dmi_check_cb,
        },
+       {
+               .ident = "N510",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR,
+                                       "SAMSUNG ELECTRONICS CO., LTD."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "N510"),
+                       DMI_MATCH(DMI_BOARD_NAME, "N510"),
+               },
+               .callback = dmi_check_cb,
+       },
        {
                .ident = "X125",
                .matches = {
@@ -600,6 +610,16 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
                },
                .callback = dmi_check_cb,
        },
+       {
+               .ident = "N150/N210/N220",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR,
+                                       "SAMSUNG ELECTRONICS CO., LTD."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
+                       DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
+               },
+               .callback = dmi_check_cb,
+       },
        {
                .ident = "N150/N210/N220/N230",
                .matches = {
diff --git a/drivers/platform/x86/samsung-q10.c b/drivers/platform/x86/samsung-q10.c
new file mode 100644 (file)
index 0000000..1e54ae7
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ *  Driver for Samsung Q10 and related laptops: controls the backlight
+ *
+ *  Copyright (c) 2011 Frederick van der Wyck <fvanderwyck@gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/backlight.h>
+#include <linux/i8042.h>
+#include <linux/dmi.h>
+
+#define SAMSUNGQ10_BL_MAX_INTENSITY      255
+#define SAMSUNGQ10_BL_DEFAULT_INTENSITY  185
+
+#define SAMSUNGQ10_BL_8042_CMD           0xbe
+#define SAMSUNGQ10_BL_8042_DATA          { 0x89, 0x91 }
+
+static int samsungq10_bl_brightness;
+
+static bool force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force,
+               "Disable the DMI check and force the driver to be loaded");
+
+static int samsungq10_bl_set_intensity(struct backlight_device *bd)
+{
+
+       int brightness = bd->props.brightness;
+       unsigned char c[3] = SAMSUNGQ10_BL_8042_DATA;
+
+       c[2] = (unsigned char)brightness;
+       i8042_lock_chip();
+       i8042_command(c, (0x30 << 8) | SAMSUNGQ10_BL_8042_CMD);
+       i8042_unlock_chip();
+       samsungq10_bl_brightness = brightness;
+
+       return 0;
+}
+
+static int samsungq10_bl_get_intensity(struct backlight_device *bd)
+{
+       return samsungq10_bl_brightness;
+}
+
+static const struct backlight_ops samsungq10_bl_ops = {
+       .get_brightness = samsungq10_bl_get_intensity,
+       .update_status  = samsungq10_bl_set_intensity,
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int samsungq10_suspend(struct device *dev)
+{
+       return 0;
+}
+
+static int samsungq10_resume(struct device *dev)
+{
+
+       struct backlight_device *bd = dev_get_drvdata(dev);
+
+       samsungq10_bl_set_intensity(bd);
+       return 0;
+}
+#else
+#define samsungq10_suspend NULL
+#define samsungq10_resume  NULL
+#endif
+
+static SIMPLE_DEV_PM_OPS(samsungq10_pm_ops,
+                         samsungq10_suspend, samsungq10_resume);
+
+static int __devinit samsungq10_probe(struct platform_device *pdev)
+{
+
+       struct backlight_properties props;
+       struct backlight_device *bd;
+
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_PLATFORM;
+       props.max_brightness = SAMSUNGQ10_BL_MAX_INTENSITY;
+       bd = backlight_device_register("samsung", &pdev->dev, NULL,
+                                      &samsungq10_bl_ops, &props);
+       if (IS_ERR(bd))
+               return PTR_ERR(bd);
+
+       platform_set_drvdata(pdev, bd);
+
+       bd->props.brightness = SAMSUNGQ10_BL_DEFAULT_INTENSITY;
+       samsungq10_bl_set_intensity(bd);
+
+       return 0;
+}
+
+static int __devexit samsungq10_remove(struct platform_device *pdev)
+{
+
+       struct backlight_device *bd = platform_get_drvdata(pdev);
+
+       bd->props.brightness = SAMSUNGQ10_BL_DEFAULT_INTENSITY;
+       samsungq10_bl_set_intensity(bd);
+
+       backlight_device_unregister(bd);
+
+       return 0;
+}
+
+static struct platform_driver samsungq10_driver = {
+       .driver         = {
+               .name   = KBUILD_MODNAME,
+               .owner  = THIS_MODULE,
+               .pm     = &samsungq10_pm_ops,
+       },
+       .probe          = samsungq10_probe,
+       .remove         = __devexit_p(samsungq10_remove),
+};
+
+static struct platform_device *samsungq10_device;
+
+static int __init dmi_check_callback(const struct dmi_system_id *id)
+{
+       printk(KERN_INFO KBUILD_MODNAME ": found model '%s'\n", id->ident);
+       return 1;
+}
+
+static struct dmi_system_id __initdata samsungq10_dmi_table[] = {
+       {
+               .ident = "Samsung Q10",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Samsung"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "SQ10"),
+               },
+               .callback = dmi_check_callback,
+       },
+       {
+               .ident = "Samsung Q20",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG Electronics"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "SENS Q20"),
+               },
+               .callback = dmi_check_callback,
+       },
+       {
+               .ident = "Samsung Q25",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG Electronics"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "NQ25"),
+               },
+               .callback = dmi_check_callback,
+       },
+       {
+               .ident = "Dell Latitude X200",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X200"),
+               },
+               .callback = dmi_check_callback,
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(dmi, samsungq10_dmi_table);
+
+static int __init samsungq10_init(void)
+{
+       if (!force && !dmi_check_system(samsungq10_dmi_table))
+               return -ENODEV;
+
+       samsungq10_device = platform_create_bundle(&samsungq10_driver,
+                                                  samsungq10_probe,
+                                                  NULL, 0, NULL, 0);
+
+       if (IS_ERR(samsungq10_device))
+               return PTR_ERR(samsungq10_device);
+
+       return 0;
+}
+
+static void __exit samsungq10_exit(void)
+{
+       platform_device_unregister(samsungq10_device);
+       platform_driver_unregister(&samsungq10_driver);
+}
+
+module_init(samsungq10_init);
+module_exit(samsungq10_exit);
+
+MODULE_AUTHOR("Frederick van der Wyck <fvanderwyck@gmail.com>");
+MODULE_DESCRIPTION("Samsung Q10 Driver");
+MODULE_LICENSE("GPL");
index 26c5b11..7bd829f 100644 (file)
@@ -3185,9 +3185,18 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
 
                KEY_VENDOR,     /* 0x17: Thinkpad/AccessIBM/Lenovo */
 
+               /* (assignments unknown, please report if found) */
+               KEY_UNKNOWN, KEY_UNKNOWN,
+
+               /*
+                * The mic mute button only sends 0x1a.  It does not
+                * automatically mute the mic or change the mute light.
+                */
+               KEY_MICMUTE,    /* 0x1a: Mic mute (since ?400 or so) */
+
                /* (assignments unknown, please report if found) */
                KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
-               KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+               KEY_UNKNOWN,
                },
        };
 
index e57b50b..57de051 100644 (file)
@@ -235,4 +235,18 @@ config CHARGER_GPIO
          This driver can be build as a module. If so, the module will be
          called gpio-charger.
 
+config CHARGER_MAX8997
+       tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver"
+       depends on MFD_MAX8997 && REGULATOR_MAX8997
+       help
+         Say Y to enable support for the battery charger control sysfs and
+         platform data of MAX8997/LP3974 PMICs.
+
+config CHARGER_MAX8998
+       tristate "Maxim MAX8998/LP3974 PMIC battery charger driver"
+       depends on MFD_MAX8998 && REGULATOR_MAX8998
+       help
+         Say Y to enable support for the battery charger control sysfs and
+         platform data of MAX8998/LP3974 PMICs.
+
 endif # POWER_SUPPLY
index 009a90f..b4af13d 100644 (file)
@@ -36,3 +36,5 @@ obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o
 obj-$(CONFIG_CHARGER_MAX8903)  += max8903_charger.o
 obj-$(CONFIG_CHARGER_TWL4030)  += twl4030_charger.o
 obj-$(CONFIG_CHARGER_GPIO)     += gpio-charger.o
+obj-$(CONFIG_CHARGER_MAX8997)  += max8997_charger.o
+obj-$(CONFIG_CHARGER_MAX8998)  += max8998_charger.o
index dc628cb..8a612de 100644 (file)
 #include <linux/apm-emulation.h>
 
 
-#define PSY_PROP(psy, prop, val) psy->get_property(psy, \
-                        POWER_SUPPLY_PROP_##prop, val)
+#define PSY_PROP(psy, prop, val) (psy->get_property(psy, \
+                        POWER_SUPPLY_PROP_##prop, val))
 
-#define _MPSY_PROP(prop, val) main_battery->get_property(main_battery, \
-                                                        prop, val)
+#define _MPSY_PROP(prop, val) (main_battery->get_property(main_battery, \
+                                                        prop, val))
 
 #define MPSY_PROP(prop, val) _MPSY_PROP(POWER_SUPPLY_PROP_##prop, val)
 
index 506585e..9c5e5be 100644 (file)
@@ -152,6 +152,10 @@ struct bq20z75_info {
        bool                            gpio_detect;
        bool                            enable_detection;
        int                             irq;
+       int                             last_state;
+       int                             poll_time;
+       struct delayed_work             work;
+       int                             ignore_changes;
 };
 
 static int bq20z75_read_word_data(struct i2c_client *client, u8 address)
@@ -279,6 +283,7 @@ static int bq20z75_get_battery_property(struct i2c_client *client,
        int reg_offset, enum power_supply_property psp,
        union power_supply_propval *val)
 {
+       struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
        s32 ret;
 
        ret = bq20z75_read_word_data(client,
@@ -293,15 +298,24 @@ static int bq20z75_get_battery_property(struct i2c_client *client,
        if (ret >= bq20z75_data[reg_offset].min_value &&
            ret <= bq20z75_data[reg_offset].max_value) {
                val->intval = ret;
-               if (psp == POWER_SUPPLY_PROP_STATUS) {
-                       if (ret & BATTERY_FULL_CHARGED)
-                               val->intval = POWER_SUPPLY_STATUS_FULL;
-                       else if (ret & BATTERY_FULL_DISCHARGED)
-                               val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
-                       else if (ret & BATTERY_DISCHARGING)
-                               val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
-                       else
-                               val->intval = POWER_SUPPLY_STATUS_CHARGING;
+               if (psp != POWER_SUPPLY_PROP_STATUS)
+                       return 0;
+
+               if (ret & BATTERY_FULL_CHARGED)
+                       val->intval = POWER_SUPPLY_STATUS_FULL;
+               else if (ret & BATTERY_FULL_DISCHARGED)
+                       val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+               else if (ret & BATTERY_DISCHARGING)
+                       val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+               else
+                       val->intval = POWER_SUPPLY_STATUS_CHARGING;
+
+               if (bq20z75_device->poll_time == 0)
+                       bq20z75_device->last_state = val->intval;
+               else if (bq20z75_device->last_state != val->intval) {
+                       cancel_delayed_work_sync(&bq20z75_device->work);
+                       power_supply_changed(&bq20z75_device->power_supply);
+                       bq20z75_device->poll_time = 0;
                }
        } else {
                if (psp == POWER_SUPPLY_PROP_STATUS)
@@ -545,6 +559,60 @@ static irqreturn_t bq20z75_irq(int irq, void *devid)
        return IRQ_HANDLED;
 }
 
+static void bq20z75_external_power_changed(struct power_supply *psy)
+{
+       struct bq20z75_info *bq20z75_device;
+
+       bq20z75_device = container_of(psy, struct bq20z75_info, power_supply);
+
+       if (bq20z75_device->ignore_changes > 0) {
+               bq20z75_device->ignore_changes--;
+               return;
+       }
+
+       /* cancel outstanding work */
+       cancel_delayed_work_sync(&bq20z75_device->work);
+
+       schedule_delayed_work(&bq20z75_device->work, HZ);
+       bq20z75_device->poll_time = bq20z75_device->pdata->poll_retry_count;
+}
+
+static void bq20z75_delayed_work(struct work_struct *work)
+{
+       struct bq20z75_info *bq20z75_device;
+       s32 ret;
+
+       bq20z75_device = container_of(work, struct bq20z75_info, work.work);
+
+       ret = bq20z75_read_word_data(bq20z75_device->client,
+                                    bq20z75_data[REG_STATUS].addr);
+       /* if the read failed, give up on this work */
+       if (ret < 0) {
+               bq20z75_device->poll_time = 0;
+               return;
+       }
+
+       if (ret & BATTERY_FULL_CHARGED)
+               ret = POWER_SUPPLY_STATUS_FULL;
+       else if (ret & BATTERY_FULL_DISCHARGED)
+               ret = POWER_SUPPLY_STATUS_NOT_CHARGING;
+       else if (ret & BATTERY_DISCHARGING)
+               ret = POWER_SUPPLY_STATUS_DISCHARGING;
+       else
+               ret = POWER_SUPPLY_STATUS_CHARGING;
+
+       if (bq20z75_device->last_state != ret) {
+               bq20z75_device->poll_time = 0;
+               power_supply_changed(&bq20z75_device->power_supply);
+               return;
+       }
+       if (bq20z75_device->poll_time > 0) {
+               schedule_delayed_work(&bq20z75_device->work, HZ);
+               bq20z75_device->poll_time--;
+               return;
+       }
+}
+
 static int __devinit bq20z75_probe(struct i2c_client *client,
        const struct i2c_device_id *id)
 {
@@ -566,6 +634,13 @@ static int __devinit bq20z75_probe(struct i2c_client *client,
        bq20z75_device->power_supply.num_properties =
                ARRAY_SIZE(bq20z75_properties);
        bq20z75_device->power_supply.get_property = bq20z75_get_property;
+       /* ignore first notification of external change, it is generated
+        * from the power_supply_register call back
+        */
+       bq20z75_device->ignore_changes = 1;
+       bq20z75_device->last_state = POWER_SUPPLY_STATUS_UNKNOWN;
+       bq20z75_device->power_supply.external_power_changed =
+               bq20z75_external_power_changed;
 
        if (pdata) {
                bq20z75_device->gpio_detect =
@@ -625,6 +700,10 @@ skip_gpio:
        dev_info(&client->dev,
                "%s: battery gas gauge device registered\n", client->name);
 
+       INIT_DELAYED_WORK(&bq20z75_device->work, bq20z75_delayed_work);
+
+       bq20z75_device->enable_detection = true;
+
        return 0;
 
 exit_psupply:
@@ -648,6 +727,9 @@ static int __devexit bq20z75_remove(struct i2c_client *client)
                gpio_free(bq20z75_device->pdata->battery_detect);
 
        power_supply_unregister(&bq20z75_device->power_supply);
+
+       cancel_delayed_work_sync(&bq20z75_device->work);
+
        kfree(bq20z75_device);
        bq20z75_device = NULL;
 
@@ -661,6 +743,9 @@ static int bq20z75_suspend(struct i2c_client *client,
        struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
        s32 ret;
 
+       if (bq20z75_device->poll_time > 0)
+               cancel_delayed_work_sync(&bq20z75_device->work);
+
        /* write to manufacturer access with sleep command */
        ret = bq20z75_write_word_data(client,
                bq20z75_data[REG_MANUFACTURER_DATA].addr,
index 718f2c5..a64b885 100644 (file)
@@ -127,7 +127,7 @@ static int __devinit gpio_charger_probe(struct platform_device *pdev)
                ret = request_any_context_irq(irq, gpio_charger_irq,
                                IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
                                dev_name(&pdev->dev), charger);
-               if (ret)
+               if (ret < 0)
                        dev_warn(&pdev->dev, "Failed to request irq: %d\n", ret);
                else
                        gpio_charger->irq = irq;
index c5c8805..98bfab3 100644 (file)
 #include <linux/power_supply.h>
 #include <linux/power/max17042_battery.h>
 
-enum max17042_register {
-       MAX17042_STATUS         = 0x00,
-       MAX17042_VALRT_Th       = 0x01,
-       MAX17042_TALRT_Th       = 0x02,
-       MAX17042_SALRT_Th       = 0x03,
-       MAX17042_AtRate         = 0x04,
-       MAX17042_RepCap         = 0x05,
-       MAX17042_RepSOC         = 0x06,
-       MAX17042_Age            = 0x07,
-       MAX17042_TEMP           = 0x08,
-       MAX17042_VCELL          = 0x09,
-       MAX17042_Current        = 0x0A,
-       MAX17042_AvgCurrent     = 0x0B,
-       MAX17042_Qresidual      = 0x0C,
-       MAX17042_SOC            = 0x0D,
-       MAX17042_AvSOC          = 0x0E,
-       MAX17042_RemCap         = 0x0F,
-       MAX17402_FullCAP        = 0x10,
-       MAX17042_TTE            = 0x11,
-       MAX17042_V_empty        = 0x12,
-
-       MAX17042_RSLOW          = 0x14,
-
-       MAX17042_AvgTA          = 0x16,
-       MAX17042_Cycles         = 0x17,
-       MAX17042_DesignCap      = 0x18,
-       MAX17042_AvgVCELL       = 0x19,
-       MAX17042_MinMaxTemp     = 0x1A,
-       MAX17042_MinMaxVolt     = 0x1B,
-       MAX17042_MinMaxCurr     = 0x1C,
-       MAX17042_CONFIG         = 0x1D,
-       MAX17042_ICHGTerm       = 0x1E,
-       MAX17042_AvCap          = 0x1F,
-       MAX17042_ManName        = 0x20,
-       MAX17042_DevName        = 0x21,
-       MAX17042_DevChem        = 0x22,
-
-       MAX17042_TempNom        = 0x24,
-       MAX17042_TempCold       = 0x25,
-       MAX17042_TempHot        = 0x26,
-       MAX17042_AIN            = 0x27,
-       MAX17042_LearnCFG       = 0x28,
-       MAX17042_SHFTCFG        = 0x29,
-       MAX17042_RelaxCFG       = 0x2A,
-       MAX17042_MiscCFG        = 0x2B,
-       MAX17042_TGAIN          = 0x2C,
-       MAx17042_TOFF           = 0x2D,
-       MAX17042_CGAIN          = 0x2E,
-       MAX17042_COFF           = 0x2F,
-
-       MAX17042_Q_empty        = 0x33,
-       MAX17042_T_empty        = 0x34,
-
-       MAX17042_RCOMP0         = 0x38,
-       MAX17042_TempCo         = 0x39,
-       MAX17042_Rx             = 0x3A,
-       MAX17042_T_empty0       = 0x3B,
-       MAX17042_TaskPeriod     = 0x3C,
-       MAX17042_FSTAT          = 0x3D,
-
-       MAX17042_SHDNTIMER      = 0x3F,
-
-       MAX17042_VFRemCap       = 0x4A,
-
-       MAX17042_QH             = 0x4D,
-       MAX17042_QL             = 0x4E,
-};
-
 struct max17042_chip {
        struct i2c_client *client;
        struct power_supply battery;
@@ -123,10 +55,27 @@ static int max17042_read_reg(struct i2c_client *client, u8 reg)
        return ret;
 }
 
+static void max17042_set_reg(struct i2c_client *client,
+                            struct max17042_reg_data *data, int size)
+{
+       int i;
+
+       for (i = 0; i < size; i++)
+               max17042_write_reg(client, data[i].addr, data[i].data);
+}
+
 static enum power_supply_property max17042_battery_props[] = {
+       POWER_SUPPLY_PROP_PRESENT,
+       POWER_SUPPLY_PROP_CYCLE_COUNT,
+       POWER_SUPPLY_PROP_VOLTAGE_MAX,
+       POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
        POWER_SUPPLY_PROP_VOLTAGE_NOW,
        POWER_SUPPLY_PROP_VOLTAGE_AVG,
        POWER_SUPPLY_PROP_CAPACITY,
+       POWER_SUPPLY_PROP_CHARGE_FULL,
+       POWER_SUPPLY_PROP_TEMP,
+       POWER_SUPPLY_PROP_CURRENT_NOW,
+       POWER_SUPPLY_PROP_CURRENT_AVG,
 };
 
 static int max17042_get_property(struct power_supply *psy,
@@ -137,6 +86,30 @@ static int max17042_get_property(struct power_supply *psy,
                                struct max17042_chip, battery);
 
        switch (psp) {
+       case POWER_SUPPLY_PROP_PRESENT:
+               val->intval = max17042_read_reg(chip->client,
+                               MAX17042_STATUS);
+               if (val->intval & MAX17042_STATUS_BattAbsent)
+                       val->intval = 0;
+               else
+                       val->intval = 1;
+               break;
+       case POWER_SUPPLY_PROP_CYCLE_COUNT:
+               val->intval = max17042_read_reg(chip->client,
+                               MAX17042_Cycles);
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+               val->intval = max17042_read_reg(chip->client,
+                               MAX17042_MinMaxVolt);
+               val->intval >>= 8;
+               val->intval *= 20000; /* Units of LSB = 20mV */
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+               val->intval = max17042_read_reg(chip->client,
+                               MAX17042_V_empty);
+               val->intval >>= 7;
+               val->intval *= 10000; /* Units of LSB = 10mV */
+               break;
        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
                val->intval = max17042_read_reg(chip->client,
                                MAX17042_VCELL) * 83; /* 1000 / 12 = 83 */
@@ -149,6 +122,57 @@ static int max17042_get_property(struct power_supply *psy,
                val->intval = max17042_read_reg(chip->client,
                                MAX17042_SOC) / 256;
                break;
+       case POWER_SUPPLY_PROP_CHARGE_FULL:
+               val->intval = max17042_read_reg(chip->client,
+                               MAX17042_RepSOC);
+               if ((val->intval / 256) >= MAX17042_BATTERY_FULL)
+                       val->intval = 1;
+               else if (val->intval >= 0)
+                       val->intval = 0;
+               break;
+       case POWER_SUPPLY_PROP_TEMP:
+               val->intval = max17042_read_reg(chip->client,
+                               MAX17042_TEMP);
+               /* The value is signed. */
+               if (val->intval & 0x8000) {
+                       val->intval = (0x7fff & ~val->intval) + 1;
+                       val->intval *= -1;
+               }
+               /* The value is converted into deci-centigrade scale */
+               /* Units of LSB = 1 / 256 degree Celsius */
+               val->intval = val->intval * 10 / 256;
+               break;
+       case POWER_SUPPLY_PROP_CURRENT_NOW:
+               if (chip->pdata->enable_current_sense) {
+                       val->intval = max17042_read_reg(chip->client,
+                                       MAX17042_Current);
+                       if (val->intval & 0x8000) {
+                               /* Negative */
+                               val->intval = ~val->intval & 0x7fff;
+                               val->intval++;
+                               val->intval *= -1;
+                       }
+                       val->intval >>= 4;
+                       val->intval *= 1000000 * 25 / chip->pdata->r_sns;
+               } else {
+                       return -EINVAL;
+               }
+               break;
+       case POWER_SUPPLY_PROP_CURRENT_AVG:
+               if (chip->pdata->enable_current_sense) {
+                       val->intval = max17042_read_reg(chip->client,
+                                       MAX17042_AvgCurrent);
+                       if (val->intval & 0x8000) {
+                               /* Negative */
+                               val->intval = ~val->intval & 0x7fff;
+                               val->intval++;
+                               val->intval *= -1;
+                       }
+                       val->intval *= 1562500 / chip->pdata->r_sns;
+               } else {
+                       return -EINVAL;
+               }
+               break;
        default:
                return -EINVAL;
        }
@@ -180,18 +204,30 @@ static int __devinit max17042_probe(struct i2c_client *client,
        chip->battery.properties        = max17042_battery_props;
        chip->battery.num_properties    = ARRAY_SIZE(max17042_battery_props);
 
+       /* When current is not measured,
+        * CURRENT_NOW and CURRENT_AVG properties should be invisible. */
+       if (!chip->pdata->enable_current_sense)
+               chip->battery.num_properties -= 2;
+
        ret = power_supply_register(&client->dev, &chip->battery);
        if (ret) {
                dev_err(&client->dev, "failed: power supply register\n");
-               i2c_set_clientdata(client, NULL);
                kfree(chip);
                return ret;
        }
 
+       /* Initialize registers according to values from the platform data */
+       if (chip->pdata->init_data)
+               max17042_set_reg(client, chip->pdata->init_data,
+                                chip->pdata->num_init_data);
+
        if (!chip->pdata->enable_current_sense) {
                max17042_write_reg(client, MAX17042_CGAIN, 0x0000);
                max17042_write_reg(client, MAX17042_MiscCFG, 0x0003);
                max17042_write_reg(client, MAX17042_LearnCFG, 0x0007);
+       } else {
+               if (chip->pdata->r_sns == 0)
+                       chip->pdata->r_sns = MAX17042_DEFAULT_SNS_RESISTOR;
        }
 
        return 0;
@@ -202,7 +238,6 @@ static int __devexit max17042_remove(struct i2c_client *client)
        struct max17042_chip *chip = i2c_get_clientdata(client);
 
        power_supply_unregister(&chip->battery);
-       i2c_set_clientdata(client, NULL);
        kfree(chip);
        return 0;
 }
index 33ff0e3..a9b0209 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/power/max8903_charger.h>
 
 struct max8903_data {
-       struct max8903_pdata *pdata;
+       struct max8903_pdata pdata;
        struct device *dev;
        struct power_supply psy;
        bool fault;
@@ -52,8 +52,8 @@ static int max8903_get_property(struct power_supply *psy,
        switch (psp) {
        case POWER_SUPPLY_PROP_STATUS:
                val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
-               if (data->pdata->chg) {
-                       if (gpio_get_value(data->pdata->chg) == 0)
+               if (data->pdata.chg) {
+                       if (gpio_get_value(data->pdata.chg) == 0)
                                val->intval = POWER_SUPPLY_STATUS_CHARGING;
                        else if (data->usb_in || data->ta_in)
                                val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
@@ -80,7 +80,7 @@ static int max8903_get_property(struct power_supply *psy,
 static irqreturn_t max8903_dcin(int irq, void *_data)
 {
        struct max8903_data *data = _data;
-       struct max8903_pdata *pdata = data->pdata;
+       struct max8903_pdata *pdata = &data->pdata;
        bool ta_in;
        enum power_supply_type old_type;
 
@@ -121,7 +121,7 @@ static irqreturn_t max8903_dcin(int irq, void *_data)
 static irqreturn_t max8903_usbin(int irq, void *_data)
 {
        struct max8903_data *data = _data;
-       struct max8903_pdata *pdata = data->pdata;
+       struct max8903_pdata *pdata = &data->pdata;
        bool usb_in;
        enum power_supply_type old_type;
 
@@ -160,7 +160,7 @@ static irqreturn_t max8903_usbin(int irq, void *_data)
 static irqreturn_t max8903_fault(int irq, void *_data)
 {
        struct max8903_data *data = _data;
-       struct max8903_pdata *pdata = data->pdata;
+       struct max8903_pdata *pdata = &data->pdata;
        bool fault;
 
        fault = gpio_get_value(pdata->flt) ? false : true;
@@ -193,7 +193,7 @@ static __devinit int max8903_probe(struct platform_device *pdev)
                dev_err(dev, "Cannot allocate memory.\n");
                return -ENOMEM;
        }
-       data->pdata = pdata;
+       memcpy(&data->pdata, pdata, sizeof(struct max8903_pdata));
        data->dev = dev;
        platform_set_drvdata(pdev, data);
 
@@ -349,7 +349,7 @@ static __devexit int max8903_remove(struct platform_device *pdev)
        struct max8903_data *data = platform_get_drvdata(pdev);
 
        if (data) {
-               struct max8903_pdata *pdata = data->pdata;
+               struct max8903_pdata *pdata = &data->pdata;
 
                if (pdata->flt)
                        free_irq(gpio_to_irq(pdata->flt), data);
diff --git a/drivers/power/max8997_charger.c b/drivers/power/max8997_charger.c
new file mode 100644 (file)
index 0000000..ffc5033
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * max8997_charger.c - Power supply consumer driver for the Maxim 8997/8966
+ *
+ *  Copyright (C) 2011 Samsung Electronics
+ *  MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/mfd/max8997.h>
+#include <linux/mfd/max8997-private.h>
+
+struct charger_data {
+       struct device *dev;
+       struct max8997_dev *iodev;
+       struct power_supply battery;
+};
+
+static enum power_supply_property max8997_battery_props[] = {
+       POWER_SUPPLY_PROP_STATUS, /* "FULL" or "NOT FULL" only. */
+       POWER_SUPPLY_PROP_PRESENT, /* the presence of battery */
+       POWER_SUPPLY_PROP_ONLINE, /* charger is active or not */
+};
+
+/* Note that the charger control is done by a current regulator "CHARGER" */
+static int max8997_battery_get_property(struct power_supply *psy,
+               enum power_supply_property psp,
+               union power_supply_propval *val)
+{
+       struct charger_data *charger = container_of(psy,
+                       struct charger_data, battery);
+       struct i2c_client *i2c = charger->iodev->i2c;
+       int ret;
+       u8 reg;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_STATUS:
+               val->intval = 0;
+               ret = max8997_read_reg(i2c, MAX8997_REG_STATUS4, &reg);
+               if (ret)
+                       return ret;
+               if ((reg & (1 << 0)) == 0x1)
+                       val->intval = POWER_SUPPLY_STATUS_FULL;
+
+               break;
+       case POWER_SUPPLY_PROP_PRESENT:
+               val->intval = 0;
+               ret = max8997_read_reg(i2c, MAX8997_REG_STATUS4, &reg);
+               if (ret)
+                       return ret;
+               if ((reg & (1 << 2)) == 0x0)
+                       val->intval = 1;
+
+               break;
+       case POWER_SUPPLY_PROP_ONLINE:
+               val->intval = 0;
+               ret = max8997_read_reg(i2c, MAX8997_REG_STATUS4, &reg);
+               if (ret)
+                       return ret;
+               /* DCINOK */
+               if (reg & (1 << 1))
+                       val->intval = 1;
+
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static __devinit int max8997_battery_probe(struct platform_device *pdev)
+{
+       int ret = 0;
+       struct charger_data *charger;
+       struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+       struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev);
+
+       if (!pdata)
+               return -EINVAL;
+
+       if (pdata->eoc_mA) {
+               u8 val = (pdata->eoc_mA - 50) / 10;
+               if (val < 0)
+                       val = 0;
+               if (val > 0xf)
+                       val = 0xf;
+
+               ret = max8997_update_reg(iodev->i2c,
+                               MAX8997_REG_MBCCTRL5, val, 0xf);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "Cannot use i2c bus.\n");
+                       return ret;
+               }
+       }
+
+       switch (pdata->timeout) {
+       case 5:
+               ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
+                               0x2 << 4, 0x7 << 4);
+               break;
+       case 6:
+               ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
+                               0x3 << 4, 0x7 << 4);
+               break;
+       case 7:
+               ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
+                               0x4 << 4, 0x7 << 4);
+               break;
+       case 0:
+               ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
+                               0x7 << 4, 0x7 << 4);
+               break;
+       default:
+               dev_err(&pdev->dev, "incorrect timeout value (%d)\n",
+                               pdata->timeout);
+               return -EINVAL;
+       }
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Cannot use i2c bus.\n");
+               return ret;
+       }
+
+       charger = kzalloc(sizeof(struct charger_data), GFP_KERNEL);
+       if (charger == NULL) {
+               dev_err(&pdev->dev, "Cannot allocate memory.\n");
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(pdev, charger);
+
+       charger->battery.name = "max8997_pmic";
+       charger->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+       charger->battery.get_property = max8997_battery_get_property;
+       charger->battery.properties = max8997_battery_props;
+       charger->battery.num_properties = ARRAY_SIZE(max8997_battery_props);
+
+       charger->dev = &pdev->dev;
+       charger->iodev = iodev;
+
+       ret = power_supply_register(&pdev->dev, &charger->battery);
+       if (ret) {
+               dev_err(&pdev->dev, "failed: power supply register\n");
+               goto err;
+       }
+
+       return 0;
+err:
+       kfree(charger);
+       return ret;
+}
+
+static int __devexit max8997_battery_remove(struct platform_device *pdev)
+{
+       struct charger_data *charger = platform_get_drvdata(pdev);
+
+       power_supply_unregister(&charger->battery);
+       kfree(charger);
+       return 0;
+}
+
+static const struct platform_device_id max8997_battery_id[] = {
+       { "max8997-battery", 0 },
+};
+
+static struct platform_driver max8997_battery_driver = {
+       .driver = {
+               .name = "max8997-battery",
+               .owner = THIS_MODULE,
+       },
+       .probe = max8997_battery_probe,
+       .remove = __devexit_p(max8997_battery_remove),
+       .id_table = max8997_battery_id,
+};
+
+static int __init max8997_battery_init(void)
+{
+       return platform_driver_register(&max8997_battery_driver);
+}
+subsys_initcall(max8997_battery_init);
+
+static void __exit max8997_battery_cleanup(void)
+{
+       platform_driver_unregister(&max8997_battery_driver);
+}
+module_exit(max8997_battery_cleanup);
+
+MODULE_DESCRIPTION("MAXIM 8997/8966 battery control driver");
+MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/max8998_charger.c b/drivers/power/max8998_charger.c
new file mode 100644 (file)
index 0000000..ef8efad
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * max8998_charger.c - Power supply consumer driver for the Maxim 8998/LP3974
+ *
+ *  Copyright (C) 2009-2010 Samsung Electronics
+ *  MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/mfd/max8998.h>
+#include <linux/mfd/max8998-private.h>
+
+struct max8998_battery_data {
+       struct device *dev;
+       struct max8998_dev *iodev;
+       struct power_supply battery;
+};
+
+static enum power_supply_property max8998_battery_props[] = {
+       POWER_SUPPLY_PROP_PRESENT, /* the presence of battery */
+       POWER_SUPPLY_PROP_ONLINE, /* charger is active or not */
+};
+
+/* Note that the charger control is done by a current regulator "CHARGER" */
+static int max8998_battery_get_property(struct power_supply *psy,
+               enum power_supply_property psp,
+               union power_supply_propval *val)
+{
+       struct max8998_battery_data *max8998 = container_of(psy,
+                       struct max8998_battery_data, battery);
+       struct i2c_client *i2c = max8998->iodev->i2c;
+       int ret;
+       u8 reg;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_PRESENT:
+               ret = max8998_read_reg(i2c, MAX8998_REG_STATUS2, &reg);
+               if (ret)
+                       return ret;
+               if (reg & (1 << 4))
+                       val->intval = 0;
+               else
+                       val->intval = 1;
+               break;
+       case POWER_SUPPLY_PROP_ONLINE:
+               ret = max8998_read_reg(i2c, MAX8998_REG_STATUS2, &reg);
+               if (ret)
+                       return ret;
+               if (reg & (1 << 3))
+                       val->intval = 0;
+               else
+                       val->intval = 1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static __devinit int max8998_battery_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 max8998_battery_data *max8998;
+       struct i2c_client *i2c;
+       int ret = 0;
+
+       if (!pdata) {
+               dev_err(pdev->dev.parent, "No platform init data supplied\n");
+               return -ENODEV;
+       }
+
+       max8998 = kzalloc(sizeof(struct max8998_battery_data), GFP_KERNEL);
+       if (!max8998)
+               return -ENOMEM;
+
+       max8998->dev = &pdev->dev;
+       max8998->iodev = iodev;
+       platform_set_drvdata(pdev, max8998);
+       i2c = max8998->iodev->i2c;
+
+       /* Setup "End of Charge" */
+       /* If EOC value equals 0,
+        * remain value set from bootloader or default value */
+       if (pdata->eoc >= 10 && pdata->eoc <= 45) {
+               max8998_update_reg(i2c, MAX8998_REG_CHGR1,
+                               (pdata->eoc / 5 - 2) << 5, 0x7 << 5);
+       } else if (pdata->eoc == 0) {
+               dev_dbg(max8998->dev,
+                       "EOC value not set: leave it unchanged.\n");
+       } else {
+               dev_err(max8998->dev, "Invalid EOC value\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       /* Setup Charge Restart Level */
+       switch (pdata->restart) {
+       case 100:
+               max8998_update_reg(i2c, MAX8998_REG_CHGR1, 0x1 << 3, 0x3 << 3);
+               break;
+       case 150:
+               max8998_update_reg(i2c, MAX8998_REG_CHGR1, 0x0 << 3, 0x3 << 3);
+               break;
+       case 200:
+               max8998_update_reg(i2c, MAX8998_REG_CHGR1, 0x2 << 3, 0x3 << 3);
+               break;
+       case -1:
+               max8998_update_reg(i2c, MAX8998_REG_CHGR1, 0x3 << 3, 0x3 << 3);
+               break;
+       case 0:
+               dev_dbg(max8998->dev,
+                       "Restart Level not set: leave it unchanged.\n");
+               break;
+       default:
+               dev_err(max8998->dev, "Invalid Restart Level\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       /* Setup Charge Full Timeout */
+       switch (pdata->timeout) {
+       case 5:
+               max8998_update_reg(i2c, MAX8998_REG_CHGR2, 0x0 << 4, 0x3 << 4);
+               break;
+       case 6:
+               max8998_update_reg(i2c, MAX8998_REG_CHGR2, 0x1 << 4, 0x3 << 4);
+               break;
+       case 7:
+               max8998_update_reg(i2c, MAX8998_REG_CHGR2, 0x2 << 4, 0x3 << 4);
+               break;
+       case -1:
+               max8998_update_reg(i2c, MAX8998_REG_CHGR2, 0x3 << 4, 0x3 << 4);
+               break;
+       case 0:
+               dev_dbg(max8998->dev,
+                       "Full Timeout not set: leave it unchanged.\n");
+       default:
+               dev_err(max8998->dev, "Invalid Full Timeout value\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       max8998->battery.name = "max8998_pmic";
+       max8998->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+       max8998->battery.get_property = max8998_battery_get_property;
+       max8998->battery.properties = max8998_battery_props;
+       max8998->battery.num_properties = ARRAY_SIZE(max8998_battery_props);
+
+       ret = power_supply_register(max8998->dev, &max8998->battery);
+       if (ret) {
+               dev_err(max8998->dev, "failed: power supply register\n");
+               goto err;
+       }
+
+       return 0;
+err:
+       kfree(max8998);
+       return ret;
+}
+
+static int __devexit max8998_battery_remove(struct platform_device *pdev)
+{
+       struct max8998_battery_data *max8998 = platform_get_drvdata(pdev);
+
+       power_supply_unregister(&max8998->battery);
+       kfree(max8998);
+
+       return 0;
+}
+
+static const struct platform_device_id max8998_battery_id[] = {
+       { "max8998-battery", TYPE_MAX8998 },
+};
+
+static struct platform_driver max8998_battery_driver = {
+       .driver = {
+               .name = "max8998-battery",
+               .owner = THIS_MODULE,
+       },
+       .probe = max8998_battery_probe,
+       .remove = __devexit_p(max8998_battery_remove),
+       .id_table = max8998_battery_id,
+};
+
+static int __init max8998_battery_init(void)
+{
+       return platform_driver_register(&max8998_battery_driver);
+}
+module_init(max8998_battery_init);
+
+static void __exit max8998_battery_cleanup(void)
+{
+       platform_driver_unregister(&max8998_battery_driver);
+}
+module_exit(max8998_battery_cleanup);
+
+MODULE_DESCRIPTION("MAXIM 8998 battery control driver");
+MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:max8998-battery");
index d36c289..d32d0d7 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/s3c_adc_battery.h>
 #include <linux/errno.h>
 #include <linux/init.h>
+#include <linux/module.h>
 
 #include <plat/adc.h>
 
@@ -266,7 +267,7 @@ static irqreturn_t s3c_adc_bat_charged(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __init s3c_adc_bat_probe(struct platform_device *pdev)
+static int __devinit s3c_adc_bat_probe(struct platform_device *pdev)
 {
        struct s3c_adc_client   *client;
        struct s3c_adc_bat_pdata *pdata = pdev->dev.platform_data;
index 92c16e1..54b9198 100644 (file)
@@ -62,7 +62,7 @@
 #define TWL4030_MSTATEC_COMPLETE4      0x0e
 
 static bool allow_usb;
-module_param(allow_usb, bool, 1);
+module_param(allow_usb, bool, 0644);
 MODULE_PARM_DESC(allow_usb, "Allow USB charge drawing default current");
 
 struct twl4030_bci {
@@ -425,7 +425,7 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
 {
        struct twl4030_bci *bci;
        int ret;
-       int reg;
+       u32 reg;
 
        bci = kzalloc(sizeof(*bci), GFP_KERNEL);
        if (bci == NULL)
@@ -486,7 +486,7 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
        }
 
        /* Enable interrupts now. */
-       reg = ~(TWL4030_ICHGLOW | TWL4030_ICHGEOC | TWL4030_TBATOR2 |
+       reg = ~(u32)(TWL4030_ICHGLOW | TWL4030_ICHGEOC | TWL4030_TBATOR2 |
                TWL4030_TBATOR1 | TWL4030_BATSTS);
        ret = twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, reg,
                               TWL4030_INTERRUPTS_BCIIMR1A);
@@ -495,7 +495,7 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
                goto fail_unmask_interrupts;
        }
 
-       reg = ~(TWL4030_VBATOV | TWL4030_VBUSOV | TWL4030_ACCHGOV);
+       reg = ~(u32)(TWL4030_VBATOV | TWL4030_VBUSOV | TWL4030_ACCHGOV);
        ret = twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, reg,
                               TWL4030_INTERRUPTS_BCIIMR2A);
        if (ret < 0)
@@ -572,7 +572,7 @@ static void __exit twl4030_bci_exit(void)
 }
 module_exit(twl4030_bci_exit);
 
-MODULE_AUTHOR("Gražydas Ignotas");
+MODULE_AUTHOR("Gražvydas Ignotas");
 MODULE_DESCRIPTION("TWL4030 Battery Charger Interface driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:twl4030_bci");
index 0fd130d..e648cbe 100644 (file)
@@ -22,6 +22,7 @@
 struct wm831x_backup {
        struct wm831x *wm831x;
        struct power_supply backup;
+       char name[20];
 };
 
 static int wm831x_backup_read_voltage(struct wm831x *wm831x,
@@ -163,6 +164,7 @@ static enum power_supply_property wm831x_backup_props[] = {
 static __devinit int wm831x_backup_probe(struct platform_device *pdev)
 {
        struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
+       struct wm831x_pdata *wm831x_pdata = wm831x->dev->platform_data;
        struct wm831x_backup *devdata;
        struct power_supply *backup;
        int ret;
@@ -182,7 +184,14 @@ static __devinit int wm831x_backup_probe(struct platform_device *pdev)
         */
        wm831x_config_backup(wm831x);
 
-       backup->name = "wm831x-backup";
+       if (wm831x_pdata && wm831x_pdata->wm831x_num)
+               snprintf(devdata->name, sizeof(devdata->name),
+                        "wm831x-backup.%d", wm831x_pdata->wm831x_num);
+       else
+               snprintf(devdata->name, sizeof(devdata->name),
+                        "wm831x-backup");
+
+       backup->name = devdata->name;
        backup->type = POWER_SUPPLY_TYPE_BATTERY;
        backup->properties = wm831x_backup_props;
        backup->num_properties = ARRAY_SIZE(wm831x_backup_props);
@@ -203,6 +212,7 @@ static __devexit int wm831x_backup_remove(struct platform_device *pdev)
        struct wm831x_backup *devdata = platform_get_drvdata(pdev);
 
        power_supply_unregister(&devdata->backup);
+       kfree(devdata->backup.name);
        kfree(devdata);
 
        return 0;
index ddf8cf5..6cc2ca6 100644 (file)
@@ -24,6 +24,9 @@ struct wm831x_power {
        struct power_supply wall;
        struct power_supply usb;
        struct power_supply battery;
+       char wall_name[20];
+       char usb_name[20];
+       char battery_name[20];
 };
 
 static int wm831x_power_check_online(struct wm831x *wm831x, int supply,
@@ -486,6 +489,7 @@ static irqreturn_t wm831x_pwr_src_irq(int irq, void *data)
 static __devinit int wm831x_power_probe(struct platform_device *pdev)
 {
        struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
+       struct wm831x_pdata *wm831x_pdata = wm831x->dev->platform_data;
        struct wm831x_power *power;
        struct power_supply *usb;
        struct power_supply *battery;
@@ -503,12 +507,28 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev)
        battery = &power->battery;
        wall = &power->wall;
 
+       if (wm831x_pdata && wm831x_pdata->wm831x_num) {
+               snprintf(power->wall_name, sizeof(power->wall_name),
+                        "wm831x-wall.%d", wm831x_pdata->wm831x_num);
+               snprintf(power->battery_name, sizeof(power->wall_name),
+                        "wm831x-battery.%d", wm831x_pdata->wm831x_num);
+               snprintf(power->usb_name, sizeof(power->wall_name),
+                        "wm831x-usb.%d", wm831x_pdata->wm831x_num);
+       } else {
+               snprintf(power->wall_name, sizeof(power->wall_name),
+                        "wm831x-wall");
+               snprintf(power->battery_name, sizeof(power->wall_name),
+                        "wm831x-battery");
+               snprintf(power->usb_name, sizeof(power->wall_name),
+                        "wm831x-usb");
+       }
+
        /* We ignore configuration failures since we can still read back
         * the status without enabling the charger.
         */
        wm831x_config_battery(wm831x);
 
-       wall->name = "wm831x-wall";
+       wall->name = power->wall_name;
        wall->type = POWER_SUPPLY_TYPE_MAINS;
        wall->properties = wm831x_wall_props;
        wall->num_properties = ARRAY_SIZE(wm831x_wall_props);
@@ -517,7 +537,7 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev)
        if (ret)
                goto err_kmalloc;
 
-       battery->name = "wm831x-battery";
+       battery->name = power->battery_name;
        battery->properties = wm831x_bat_props;
        battery->num_properties = ARRAY_SIZE(wm831x_bat_props);
        battery->get_property = wm831x_bat_get_prop;
@@ -526,7 +546,7 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev)
        if (ret)
                goto err_wall;
 
-       usb->name = "wm831x-usb",
+       usb->name = power->usb_name,
        usb->type = POWER_SUPPLY_TYPE_USB;
        usb->properties = wm831x_usb_props;
        usb->num_properties = ARRAY_SIZE(wm831x_usb_props);
index 118eb21..c7fd2c0 100644 (file)
@@ -249,6 +249,12 @@ 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_TPS65912
+       tristate "TI TPS65912 Power regulator"
+       depends on (MFD_TPS65912_I2C || MFD_TPS65912_SPI)
+       help
+           This driver supports TPS65912 voltage regulator chip.
+
 config REGULATOR_88PM8607
        bool "Marvell 88PM8607 Power regulators"
        depends on MFD_88PM860X=y
@@ -304,5 +310,12 @@ config REGULATOR_TPS65910
        help
          This driver supports TPS65910 voltage regulator chips.
 
+config REGULATOR_AAT2870
+       tristate "AnalogicTech AAT2870 Regulators"
+       depends on MFD_AAT2870_CORE
+       help
+         If you have a AnalogicTech AAT2870 say Y to enable the
+         regulator driver.
+
 endif
 
index 3932d2e..040d5aa 100644 (file)
@@ -38,10 +38,12 @@ obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
 obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
 obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o
 obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o
+obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o
 obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
 obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
 obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o
 obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o
 obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
+obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o
 
 ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/aat2870-regulator.c b/drivers/regulator/aat2870-regulator.c
new file mode 100644 (file)
index 0000000..cd41045
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * linux/drivers/regulator/aat2870-regulator.c
+ *
+ * Copyright (c) 2011, NVIDIA Corporation.
+ * Author: Jin Park <jinyoungp@nvidia.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
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/aat2870.h>
+
+struct aat2870_regulator {
+       struct platform_device *pdev;
+       struct regulator_desc desc;
+
+       const int *voltages; /* uV */
+
+       int min_uV;
+       int max_uV;
+
+       u8 enable_addr;
+       u8 enable_shift;
+       u8 enable_mask;
+
+       u8 voltage_addr;
+       u8 voltage_shift;
+       u8 voltage_mask;
+};
+
+static int aat2870_ldo_list_voltage(struct regulator_dev *rdev,
+                                   unsigned selector)
+{
+       struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
+
+       return ri->voltages[selector];
+}
+
+static int aat2870_ldo_set_voltage_sel(struct regulator_dev *rdev,
+                                      unsigned selector)
+{
+       struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
+       struct aat2870_data *aat2870 = dev_get_drvdata(ri->pdev->dev.parent);
+
+       return aat2870->update(aat2870, ri->voltage_addr, ri->voltage_mask,
+                       (selector << ri->voltage_shift) & ri->voltage_mask);
+}
+
+static int aat2870_ldo_get_voltage_sel(struct regulator_dev *rdev)
+{
+       struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
+       struct aat2870_data *aat2870 = dev_get_drvdata(ri->pdev->dev.parent);
+       u8 val;
+       int ret;
+
+       ret = aat2870->read(aat2870, ri->voltage_addr, &val);
+       if (ret)
+               return ret;
+
+       return (val & ri->voltage_mask) >> ri->voltage_shift;
+}
+
+static int aat2870_ldo_enable(struct regulator_dev *rdev)
+{
+       struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
+       struct aat2870_data *aat2870 = dev_get_drvdata(ri->pdev->dev.parent);
+
+       return aat2870->update(aat2870, ri->enable_addr, ri->enable_mask,
+                              ri->enable_mask);
+}
+
+static int aat2870_ldo_disable(struct regulator_dev *rdev)
+{
+       struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
+       struct aat2870_data *aat2870 = dev_get_drvdata(ri->pdev->dev.parent);
+
+       return aat2870->update(aat2870, ri->enable_addr, ri->enable_mask, 0);
+}
+
+static int aat2870_ldo_is_enabled(struct regulator_dev *rdev)
+{
+       struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
+       struct aat2870_data *aat2870 = dev_get_drvdata(ri->pdev->dev.parent);
+       u8 val;
+       int ret;
+
+       ret = aat2870->read(aat2870, ri->enable_addr, &val);
+       if (ret)
+               return ret;
+
+       return val & ri->enable_mask ? 1 : 0;
+}
+
+static struct regulator_ops aat2870_ldo_ops = {
+       .list_voltage = aat2870_ldo_list_voltage,
+       .set_voltage_sel = aat2870_ldo_set_voltage_sel,
+       .get_voltage_sel = aat2870_ldo_get_voltage_sel,
+       .enable = aat2870_ldo_enable,
+       .disable = aat2870_ldo_disable,
+       .is_enabled = aat2870_ldo_is_enabled,
+};
+
+static const int aat2870_ldo_voltages[] = {
+       1200000, 1300000, 1500000, 1600000,
+       1800000, 2000000, 2200000, 2500000,
+       2600000, 2700000, 2800000, 2900000,
+       3000000, 3100000, 3200000, 3300000,
+};
+
+#define AAT2870_LDO(ids)                               \
+       {                                               \
+               .desc = {                               \
+                       .name = #ids,                   \
+                       .id = AAT2870_ID_##ids,         \
+                       .n_voltages = ARRAY_SIZE(aat2870_ldo_voltages), \
+                       .ops = &aat2870_ldo_ops,        \
+                       .type = REGULATOR_VOLTAGE,      \
+                       .owner = THIS_MODULE,           \
+               },                                      \
+               .voltages = aat2870_ldo_voltages,       \
+               .min_uV = 1200000,                      \
+               .max_uV = 3300000,                      \
+       }
+
+static struct aat2870_regulator aat2870_regulators[] = {
+       AAT2870_LDO(LDOA),
+       AAT2870_LDO(LDOB),
+       AAT2870_LDO(LDOC),
+       AAT2870_LDO(LDOD),
+};
+
+static struct aat2870_regulator *aat2870_get_regulator(int id)
+{
+       struct aat2870_regulator *ri = NULL;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(aat2870_regulators); i++) {
+               ri = &aat2870_regulators[i];
+               if (ri->desc.id == id)
+                       break;
+       }
+
+       if (!ri)
+               return NULL;
+
+       ri->enable_addr = AAT2870_LDO_EN;
+       ri->enable_shift = id - AAT2870_ID_LDOA;
+       ri->enable_mask = 0x1 << ri->enable_shift;
+
+       ri->voltage_addr = (id - AAT2870_ID_LDOA) / 2 ?
+                          AAT2870_LDO_CD : AAT2870_LDO_AB;
+       ri->voltage_shift = (id - AAT2870_ID_LDOA) % 2 ? 0 : 4;
+       ri->voltage_mask = 0xF << ri->voltage_shift;
+
+       return ri;
+}
+
+static int aat2870_regulator_probe(struct platform_device *pdev)
+{
+       struct aat2870_regulator *ri;
+       struct regulator_dev *rdev;
+
+       ri = aat2870_get_regulator(pdev->id);
+       if (!ri) {
+               dev_err(&pdev->dev, "Invalid device ID, %d\n", pdev->id);
+               return -EINVAL;
+       }
+       ri->pdev = pdev;
+
+       rdev = regulator_register(&ri->desc, &pdev->dev,
+                                 pdev->dev.platform_data, ri);
+       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 aat2870_regulator_remove(struct platform_device *pdev)
+{
+       struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+       regulator_unregister(rdev);
+       return 0;
+}
+
+static struct platform_driver aat2870_regulator_driver = {
+       .driver = {
+               .name   = "aat2870-regulator",
+               .owner  = THIS_MODULE,
+       },
+       .probe  = aat2870_regulator_probe,
+       .remove = __devexit_p(aat2870_regulator_remove),
+};
+
+static int __init aat2870_regulator_init(void)
+{
+       return platform_driver_register(&aat2870_regulator_driver);
+}
+subsys_initcall(aat2870_regulator_init);
+
+static void __exit aat2870_regulator_exit(void)
+{
+       platform_driver_unregister(&aat2870_regulator_driver);
+}
+module_exit(aat2870_regulator_exit);
+
+MODULE_DESCRIPTION("AnalogicTech AAT2870 Regulator");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jin Park <jinyoungp@nvidia.com>");
index d3e3879..d8e6a42 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/debugfs.h>
 #include <linux/device.h>
 #include <linux/slab.h>
+#include <linux/async.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <linux/suspend.h>
@@ -33,6 +34,8 @@
 
 #include "dummy.h"
 
+#define rdev_crit(rdev, fmt, ...)                                      \
+       pr_crit("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
 #define rdev_err(rdev, fmt, ...)                                       \
        pr_err("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
 #define rdev_warn(rdev, fmt, ...)                                      \
@@ -78,11 +81,13 @@ struct regulator {
        char *supply_name;
        struct device_attribute dev_attr;
        struct regulator_dev *rdev;
+#ifdef CONFIG_DEBUG_FS
+       struct dentry *debugfs;
+#endif
 };
 
 static int _regulator_is_enabled(struct regulator_dev *rdev);
-static int _regulator_disable(struct regulator_dev *rdev,
-               struct regulator_dev **supply_rdev_ptr);
+static int _regulator_disable(struct regulator_dev *rdev);
 static int _regulator_get_voltage(struct regulator_dev *rdev);
 static int _regulator_get_current_limit(struct regulator_dev *rdev);
 static unsigned int _regulator_get_mode(struct regulator_dev *rdev);
@@ -90,6 +95,9 @@ static void _notifier_call_chain(struct regulator_dev *rdev,
                                  unsigned long event, void *data);
 static int _regulator_do_set_voltage(struct regulator_dev *rdev,
                                     int min_uV, int max_uV);
+static struct regulator *create_regulator(struct regulator_dev *rdev,
+                                         struct device *dev,
+                                         const char *supply_name);
 
 static const char *rdev_get_name(struct regulator_dev *rdev)
 {
@@ -143,8 +151,11 @@ static int regulator_check_voltage(struct regulator_dev *rdev,
        if (*min_uV < rdev->constraints->min_uV)
                *min_uV = rdev->constraints->min_uV;
 
-       if (*min_uV > *max_uV)
+       if (*min_uV > *max_uV) {
+               rdev_err(rdev, "unsupportable voltage range: %d-%duV\n",
+                        *min_uV, *max_uV);
                return -EINVAL;
+       }
 
        return 0;
 }
@@ -197,8 +208,11 @@ static int regulator_check_current_limit(struct regulator_dev *rdev,
        if (*min_uA < rdev->constraints->min_uA)
                *min_uA = rdev->constraints->min_uA;
 
-       if (*min_uA > *max_uA)
+       if (*min_uA > *max_uA) {
+               rdev_err(rdev, "unsupportable current range: %d-%duA\n",
+                        *min_uA, *max_uA);
                return -EINVAL;
+       }
 
        return 0;
 }
@@ -213,6 +227,7 @@ static int regulator_mode_constrain(struct regulator_dev *rdev, int *mode)
        case REGULATOR_MODE_STANDBY:
                break;
        default:
+               rdev_err(rdev, "invalid mode %x specified\n", *mode);
                return -EINVAL;
        }
 
@@ -779,7 +794,6 @@ static int machine_constraints_voltage(struct regulator_dev *rdev,
                if (ret < 0) {
                        rdev_err(rdev, "failed to apply %duV constraint\n",
                                 rdev->constraints->min_uV);
-                       rdev->constraints = NULL;
                        return ret;
                }
        }
@@ -882,7 +896,6 @@ static int set_machine_constraints(struct regulator_dev *rdev,
                ret = suspend_prepare(rdev, rdev->constraints->initial_state);
                if (ret < 0) {
                        rdev_err(rdev, "failed to set suspend state\n");
-                       rdev->constraints = NULL;
                        goto out;
                }
        }
@@ -909,13 +922,15 @@ static int set_machine_constraints(struct regulator_dev *rdev,
                ret = ops->enable(rdev);
                if (ret < 0) {
                        rdev_err(rdev, "failed to enable\n");
-                       rdev->constraints = NULL;
                        goto out;
                }
        }
 
        print_constraints(rdev);
+       return 0;
 out:
+       kfree(rdev->constraints);
+       rdev->constraints = NULL;
        return ret;
 }
 
@@ -929,21 +944,20 @@ out:
  * core if it's child is enabled.
  */
 static int set_supply(struct regulator_dev *rdev,
-       struct regulator_dev *supply_rdev)
+                     struct regulator_dev *supply_rdev)
 {
        int err;
 
-       err = sysfs_create_link(&rdev->dev.kobj, &supply_rdev->dev.kobj,
-                               "supply");
-       if (err) {
-               rdev_err(rdev, "could not add device link %s err %d\n",
-                        supply_rdev->dev.kobj.name, err);
-                      goto out;
+       rdev_info(rdev, "supplied by %s\n", rdev_get_name(supply_rdev));
+
+       rdev->supply = create_regulator(supply_rdev, &rdev->dev, "SUPPLY");
+       if (IS_ERR(rdev->supply)) {
+               err = PTR_ERR(rdev->supply);
+               rdev->supply = NULL;
+               return err;
        }
-       rdev->supply = supply_rdev;
-       list_add(&rdev->slist, &supply_rdev->supply_list);
-out:
-       return err;
+
+       return 0;
 }
 
 /**
@@ -1032,7 +1046,7 @@ static void unset_regulator_supplies(struct regulator_dev *rdev)
        }
 }
 
-#define REG_STR_SIZE   32
+#define REG_STR_SIZE   64
 
 static struct regulator *create_regulator(struct regulator_dev *rdev,
                                          struct device *dev,
@@ -1052,8 +1066,9 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
 
        if (dev) {
                /* create a 'requested_microamps_name' sysfs entry */
-               size = scnprintf(buf, REG_STR_SIZE, "microamps_requested_%s",
-                       supply_name);
+               size = scnprintf(buf, REG_STR_SIZE,
+                                "microamps_requested_%s-%s",
+                                dev_name(dev), supply_name);
                if (size >= REG_STR_SIZE)
                        goto overflow_err;
 
@@ -1088,7 +1103,28 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
                                  dev->kobj.name, err);
                        goto link_name_err;
                }
+       } else {
+               regulator->supply_name = kstrdup(supply_name, GFP_KERNEL);
+               if (regulator->supply_name == NULL)
+                       goto attr_err;
+       }
+
+#ifdef CONFIG_DEBUG_FS
+       regulator->debugfs = debugfs_create_dir(regulator->supply_name,
+                                               rdev->debugfs);
+       if (IS_ERR_OR_NULL(regulator->debugfs)) {
+               rdev_warn(rdev, "Failed to create debugfs directory\n");
+               regulator->debugfs = NULL;
+       } else {
+               debugfs_create_u32("uA_load", 0444, regulator->debugfs,
+                                  &regulator->uA_load);
+               debugfs_create_u32("min_uV", 0444, regulator->debugfs,
+                                  &regulator->min_uV);
+               debugfs_create_u32("max_uV", 0444, regulator->debugfs,
+                                  &regulator->max_uV);
        }
+#endif
+
        mutex_unlock(&rdev->mutex);
        return regulator;
 link_name_err:
@@ -1267,13 +1303,17 @@ void regulator_put(struct regulator *regulator)
        mutex_lock(&regulator_list_mutex);
        rdev = regulator->rdev;
 
+#ifdef CONFIG_DEBUG_FS
+       debugfs_remove_recursive(regulator->debugfs);
+#endif
+
        /* remove any sysfs entries */
        if (regulator->dev) {
                sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name);
-               kfree(regulator->supply_name);
                device_remove_file(regulator->dev, &regulator->dev_attr);
                kfree(regulator->dev_attr.attr.name);
        }
+       kfree(regulator->supply_name);
        list_del(&regulator->list);
        kfree(regulator);
 
@@ -1301,19 +1341,6 @@ static int _regulator_enable(struct regulator_dev *rdev)
 {
        int ret, delay;
 
-       if (rdev->use_count == 0) {
-               /* do we need to enable the supply regulator first */
-               if (rdev->supply) {
-                       mutex_lock(&rdev->supply->mutex);
-                       ret = _regulator_enable(rdev->supply);
-                       mutex_unlock(&rdev->supply->mutex);
-                       if (ret < 0) {
-                               rdev_err(rdev, "failed to enable: %d\n", ret);
-                               return ret;
-                       }
-               }
-       }
-
        /* check voltage and requested load before enabling */
        if (rdev->constraints &&
            (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS))
@@ -1388,19 +1415,27 @@ int regulator_enable(struct regulator *regulator)
        struct regulator_dev *rdev = regulator->rdev;
        int ret = 0;
 
+       if (rdev->supply) {
+               ret = regulator_enable(rdev->supply);
+               if (ret != 0)
+                       return ret;
+       }
+
        mutex_lock(&rdev->mutex);
        ret = _regulator_enable(rdev);
        mutex_unlock(&rdev->mutex);
+
+       if (ret != 0)
+               regulator_disable(rdev->supply);
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(regulator_enable);
 
 /* locks held by regulator_disable() */
-static int _regulator_disable(struct regulator_dev *rdev,
-               struct regulator_dev **supply_rdev_ptr)
+static int _regulator_disable(struct regulator_dev *rdev)
 {
        int ret = 0;
-       *supply_rdev_ptr = NULL;
 
        if (WARN(rdev->use_count <= 0,
                 "unbalanced disables for %s\n", rdev_get_name(rdev)))
@@ -1427,9 +1462,6 @@ static int _regulator_disable(struct regulator_dev *rdev,
                                             NULL);
                }
 
-               /* decrease our supplies ref count and disable if required */
-               *supply_rdev_ptr = rdev->supply;
-
                rdev->use_count = 0;
        } else if (rdev->use_count > 1) {
 
@@ -1440,6 +1472,7 @@ static int _regulator_disable(struct regulator_dev *rdev,
 
                rdev->use_count--;
        }
+
        return ret;
 }
 
@@ -1458,29 +1491,21 @@ static int _regulator_disable(struct regulator_dev *rdev,
 int regulator_disable(struct regulator *regulator)
 {
        struct regulator_dev *rdev = regulator->rdev;
-       struct regulator_dev *supply_rdev = NULL;
        int ret = 0;
 
        mutex_lock(&rdev->mutex);
-       ret = _regulator_disable(rdev, &supply_rdev);
+       ret = _regulator_disable(rdev);
        mutex_unlock(&rdev->mutex);
 
-       /* decrease our supplies ref count and disable if required */
-       while (supply_rdev != NULL) {
-               rdev = supply_rdev;
-
-               mutex_lock(&rdev->mutex);
-               _regulator_disable(rdev, &supply_rdev);
-               mutex_unlock(&rdev->mutex);
-       }
+       if (ret == 0 && rdev->supply)
+               regulator_disable(rdev->supply);
 
        return ret;
 }
 EXPORT_SYMBOL_GPL(regulator_disable);
 
 /* locks held by regulator_force_disable() */
-static int _regulator_force_disable(struct regulator_dev *rdev,
-               struct regulator_dev **supply_rdev_ptr)
+static int _regulator_force_disable(struct regulator_dev *rdev)
 {
        int ret = 0;
 
@@ -1497,10 +1522,6 @@ static int _regulator_force_disable(struct regulator_dev *rdev,
                        REGULATOR_EVENT_DISABLE, NULL);
        }
 
-       /* decrease our supplies ref count and disable if required */
-       *supply_rdev_ptr = rdev->supply;
-
-       rdev->use_count = 0;
        return ret;
 }
 
@@ -1516,16 +1537,16 @@ static int _regulator_force_disable(struct regulator_dev *rdev,
 int regulator_force_disable(struct regulator *regulator)
 {
        struct regulator_dev *rdev = regulator->rdev;
-       struct regulator_dev *supply_rdev = NULL;
        int ret;
 
        mutex_lock(&rdev->mutex);
        regulator->uA_load = 0;
-       ret = _regulator_force_disable(rdev, &supply_rdev);
+       ret = _regulator_force_disable(regulator->rdev);
        mutex_unlock(&rdev->mutex);
 
-       if (supply_rdev)
-               regulator_disable(get_device_regulator(rdev_get_dev(supply_rdev)));
+       if (rdev->supply)
+               while (rdev->open_count--)
+                       regulator_disable(rdev->supply);
 
        return ret;
 }
@@ -2136,7 +2157,7 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
        /* get input voltage */
        input_uV = 0;
        if (rdev->supply)
-               input_uV = _regulator_get_voltage(rdev->supply);
+               input_uV = regulator_get_voltage(rdev->supply);
        if (input_uV <= 0)
                input_uV = rdev->constraints->input_uV;
        if (input_uV <= 0) {
@@ -2206,17 +2227,8 @@ EXPORT_SYMBOL_GPL(regulator_unregister_notifier);
 static void _notifier_call_chain(struct regulator_dev *rdev,
                                  unsigned long event, void *data)
 {
-       struct regulator_dev *_rdev;
-
        /* call rdev chain first */
        blocking_notifier_call_chain(&rdev->notifier, event, NULL);
-
-       /* now notify regulator we supply */
-       list_for_each_entry(_rdev, &rdev->supply_list, slist) {
-               mutex_lock(&_rdev->mutex);
-               _notifier_call_chain(_rdev, event, data);
-               mutex_unlock(&_rdev->mutex);
-       }
 }
 
 /**
@@ -2264,6 +2276,13 @@ err:
 }
 EXPORT_SYMBOL_GPL(regulator_bulk_get);
 
+static void regulator_bulk_enable_async(void *data, async_cookie_t cookie)
+{
+       struct regulator_bulk_data *bulk = data;
+
+       bulk->ret = regulator_enable(bulk->consumer);
+}
+
 /**
  * regulator_bulk_enable - enable multiple regulator consumers
  *
@@ -2279,21 +2298,33 @@ EXPORT_SYMBOL_GPL(regulator_bulk_get);
 int regulator_bulk_enable(int num_consumers,
                          struct regulator_bulk_data *consumers)
 {
+       LIST_HEAD(async_domain);
        int i;
-       int ret;
+       int ret = 0;
+
+       for (i = 0; i < num_consumers; i++)
+               async_schedule_domain(regulator_bulk_enable_async,
+                                     &consumers[i], &async_domain);
+
+       async_synchronize_full_domain(&async_domain);
 
+       /* If any consumer failed we need to unwind any that succeeded */
        for (i = 0; i < num_consumers; i++) {
-               ret = regulator_enable(consumers[i].consumer);
-               if (ret != 0)
+               if (consumers[i].ret != 0) {
+                       ret = consumers[i].ret;
                        goto err;
+               }
        }
 
        return 0;
 
 err:
-       pr_err("Failed to enable %s: %d\n", consumers[i].supply, ret);
-       for (--i; i >= 0; --i)
-               regulator_disable(consumers[i].consumer);
+       for (i = 0; i < num_consumers; i++)
+               if (consumers[i].ret == 0)
+                       regulator_disable(consumers[i].consumer);
+               else
+                       pr_err("Failed to enable %s: %d\n",
+                              consumers[i].supply, consumers[i].ret);
 
        return ret;
 }
@@ -2589,9 +2620,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
        rdev->owner = regulator_desc->owner;
        rdev->desc = regulator_desc;
        INIT_LIST_HEAD(&rdev->consumer_list);
-       INIT_LIST_HEAD(&rdev->supply_list);
        INIT_LIST_HEAD(&rdev->list);
-       INIT_LIST_HEAD(&rdev->slist);
        BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier);
 
        /* preform any regulator specific init */
@@ -2672,6 +2701,7 @@ unset_supplies:
        unset_regulator_supplies(rdev);
 
 scrub:
+       kfree(rdev->constraints);
        device_unregister(&rdev->dev);
        /* device core frees rdev */
        rdev = ERR_PTR(ret);
@@ -2703,7 +2733,7 @@ void regulator_unregister(struct regulator_dev *rdev)
        unset_regulator_supplies(rdev);
        list_del(&rdev->list);
        if (rdev->supply)
-               sysfs_remove_link(&rdev->dev.kobj, "supply");
+               regulator_put(rdev->supply);
        device_unregister(&rdev->dev);
        kfree(rdev->constraints);
        mutex_unlock(&regulator_list_mutex);
index c7410bd..f6ef669 100644 (file)
@@ -36,6 +36,29 @@ static struct regulator_desc dummy_desc = {
        .ops = &dummy_ops,
 };
 
+static int __devinit dummy_regulator_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       dummy_regulator_rdev = regulator_register(&dummy_desc, NULL,
+                                                 &dummy_initdata, NULL);
+       if (IS_ERR(dummy_regulator_rdev)) {
+               ret = PTR_ERR(dummy_regulator_rdev);
+               pr_err("Failed to register regulator: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct platform_driver dummy_regulator_driver = {
+       .probe          = dummy_regulator_probe,
+       .driver         = {
+               .name           = "reg-dummy",
+               .owner          = THIS_MODULE,
+       },
+};
+
 static struct platform_device *dummy_pdev;
 
 void __init regulator_dummy_init(void)
@@ -55,12 +78,9 @@ void __init regulator_dummy_init(void)
                return;
        }
 
-       dummy_regulator_rdev = regulator_register(&dummy_desc, NULL,
-                                                 &dummy_initdata, NULL);
-       if (IS_ERR(dummy_regulator_rdev)) {
-               ret = PTR_ERR(dummy_regulator_rdev);
-               pr_err("Failed to register regulator: %d\n", ret);
+       ret = platform_driver_register(&dummy_regulator_driver);
+       if (ret != 0) {
+               pr_err("Failed to register dummy regulator driver: %d\n", ret);
                platform_device_unregister(dummy_pdev);
-               return;
        }
 }
index 55dd4e6..66d2d60 100644 (file)
@@ -49,7 +49,6 @@
 #define TPS65911_REG_LDO7              11
 #define TPS65911_REG_LDO8              12
 
-#define TPS65910_NUM_REGULATOR         13
 #define TPS65910_SUPPLY_STATE_ENABLED  0x1
 
 /* supported VIO voltages in milivolts */
@@ -264,11 +263,12 @@ static struct tps_info tps65911_regs[] = {
 };
 
 struct tps65910_reg {
-       struct regulator_desc desc[TPS65910_NUM_REGULATOR];
+       struct regulator_desc *desc;
        struct tps65910 *mfd;
-       struct regulator_dev *rdev[TPS65910_NUM_REGULATOR];
-       struct tps_info *info[TPS65910_NUM_REGULATOR];
+       struct regulator_dev **rdev;
+       struct tps_info **info;
        struct mutex mutex;
+       int num_regulators;
        int mode;
        int  (*get_ctrl_reg)(int);
 };
@@ -759,8 +759,13 @@ static int tps65910_list_voltage_dcdc(struct regulator_dev *dev,
                mult = (selector / VDD1_2_NUM_VOLTS) + 1;
                volt = VDD1_2_MIN_VOLT +
                                (selector % VDD1_2_NUM_VOLTS) * VDD1_2_OFFSET;
+               break;
        case TPS65911_REG_VDDCTRL:
                volt = VDDCTRL_MIN_VOLT + (selector * VDDCTRL_OFFSET);
+               break;
+       default:
+               BUG();
+               return -EINVAL;
        }
 
        return  volt * 100 * mult;
@@ -897,16 +902,42 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
        switch(tps65910_chip_id(tps65910)) {
        case TPS65910:
                pmic->get_ctrl_reg = &tps65910_get_ctrl_register;
+               pmic->num_regulators = ARRAY_SIZE(tps65910_regs);
                info = tps65910_regs;
+               break;
        case TPS65911:
                pmic->get_ctrl_reg = &tps65911_get_ctrl_register;
+               pmic->num_regulators = ARRAY_SIZE(tps65911_regs);
                info = tps65911_regs;
+               break;
        default:
                pr_err("Invalid tps chip version\n");
+               kfree(pmic);
                return -ENODEV;
        }
 
-       for (i = 0; i < TPS65910_NUM_REGULATOR; i++, info++, reg_data++) {
+       pmic->desc = kcalloc(pmic->num_regulators,
+                       sizeof(struct regulator_desc), GFP_KERNEL);
+       if (!pmic->desc) {
+               err = -ENOMEM;
+               goto err_free_pmic;
+       }
+
+       pmic->info = kcalloc(pmic->num_regulators,
+                       sizeof(struct tps_info *), GFP_KERNEL);
+       if (!pmic->info) {
+               err = -ENOMEM;
+               goto err_free_desc;
+       }
+
+       pmic->rdev = kcalloc(pmic->num_regulators,
+                       sizeof(struct regulator_dev *), GFP_KERNEL);
+       if (!pmic->rdev) {
+               err = -ENOMEM;
+               goto err_free_info;
+       }
+
+       for (i = 0; i < pmic->num_regulators; i++, info++, reg_data++) {
                /* Register the regulators */
                pmic->info[i] = info;
 
@@ -938,7 +969,7 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
                                "failed to register %s regulator\n",
                                pdev->name);
                        err = PTR_ERR(rdev);
-                       goto err;
+                       goto err_unregister_regulator;
                }
 
                /* Save regulator for cleanup */
@@ -946,23 +977,31 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
        }
        return 0;
 
-err:
+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;
 }
 
 static int __devexit tps65910_remove(struct platform_device *pdev)
 {
-       struct tps65910_reg *tps65910_reg = platform_get_drvdata(pdev);
+       struct tps65910_reg *pmic = platform_get_drvdata(pdev);
        int i;
 
-       for (i = 0; i < TPS65910_NUM_REGULATOR; i++)
-               regulator_unregister(tps65910_reg->rdev[i]);
+       for (i = 0; i < pmic->num_regulators; i++)
+               regulator_unregister(pmic->rdev[i]);
 
-       kfree(tps65910_reg);
+       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
new file mode 100644 (file)
index 0000000..3a9313e
--- /dev/null
@@ -0,0 +1,800 @@
+/*
+ * tps65912.c  --  TI tps65912
+ *
+ * Copyright 2011 Texas Instruments Inc.
+ *
+ * Author: Margarita Olaya Cabrera <magi@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.
+ *
+ * This driver is based on wm8350 implementation.
+ */
+
+#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/delay.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/mfd/tps65912.h>
+
+/* DCDC's */
+#define TPS65912_REG_DCDC1     0
+#define TPS65912_REG_DCDC2     1
+#define TPS65912_REG_DCDC3     2
+#define TPS65912_REG_DCDC4     3
+
+/* LDOs */
+#define TPS65912_REG_LDO1      4
+#define TPS65912_REG_LDO2      5
+#define TPS65912_REG_LDO3      6
+#define TPS65912_REG_LDO4      7
+#define TPS65912_REG_LDO5      8
+#define TPS65912_REG_LDO6      9
+#define TPS65912_REG_LDO7      10
+#define TPS65912_REG_LDO8      11
+#define TPS65912_REG_LDO9      12
+#define TPS65912_REG_LDO10     13
+
+#define TPS65912_MAX_REG_ID    TPS65912_REG_LDO_10
+
+/* Number of step-down converters available */
+#define TPS65912_NUM_DCDC      4
+
+/* Number of LDO voltage regulators  available */
+#define TPS65912_NUM_LDO       10
+
+/* Number of total regulators available */
+#define TPS65912_NUM_REGULATOR         (TPS65912_NUM_DCDC + TPS65912_NUM_LDO)
+
+#define TPS65912_REG_ENABLED   0x80
+#define OP_SELREG_MASK         0x40
+#define OP_SELREG_SHIFT                6
+
+struct tps_info {
+       const char *name;
+};
+
+static struct tps_info tps65912_regs[] = {
+       {
+               .name = "DCDC1",
+       },
+       {
+               .name = "DCDC2",
+       },
+       {
+               .name = "DCDC3",
+       },
+       {
+               .name = "DCDC4",
+       },
+       {
+               .name = "LDO1",
+       },
+       {
+               .name = "LDO2",
+       },
+       {
+               .name = "LDO3",
+       },
+       {
+               .name = "LDO4",
+       },
+       {
+               .name = "LDO5",
+       },
+       {
+               .name = "LDO6",
+       },
+       {
+               .name = "LDO7",
+       },
+       {
+               .name = "LDO8",
+       },
+       {
+               .name = "LDO9",
+       },
+       {
+               .name = "LDO10",
+       },
+};
+
+struct tps65912_reg {
+       struct regulator_desc desc[TPS65912_NUM_REGULATOR];
+       struct tps65912 *mfd;
+       struct regulator_dev *rdev[TPS65912_NUM_REGULATOR];
+       struct tps_info *info[TPS65912_NUM_REGULATOR];
+       /* for read/write access */
+       struct mutex io_lock;
+       int mode;
+       int (*get_ctrl_reg)(int);
+       int dcdc1_range;
+       int dcdc2_range;
+       int dcdc3_range;
+       int dcdc4_range;
+       int pwm_mode_reg;
+       int eco_reg;
+};
+
+static int tps65912_get_range(struct tps65912_reg *pmic, int id)
+{
+       struct tps65912 *mfd = pmic->mfd;
+
+       if (id > TPS65912_REG_DCDC4)
+               return 0;
+
+       switch (id) {
+       case TPS65912_REG_DCDC1:
+               pmic->dcdc1_range = tps65912_reg_read(mfd,
+                                                       TPS65912_DCDC1_LIMIT);
+               if (pmic->dcdc1_range < 0)
+                       return pmic->dcdc1_range;
+               pmic->dcdc1_range = (pmic->dcdc1_range &
+                       DCDC_LIMIT_RANGE_MASK) >> DCDC_LIMIT_RANGE_SHIFT;
+               return pmic->dcdc1_range;
+       case TPS65912_REG_DCDC2:
+               pmic->dcdc2_range = tps65912_reg_read(mfd,
+                                                       TPS65912_DCDC2_LIMIT);
+               if (pmic->dcdc2_range < 0)
+                       return pmic->dcdc2_range;
+               pmic->dcdc2_range = (pmic->dcdc2_range &
+                       DCDC_LIMIT_RANGE_MASK) >> DCDC_LIMIT_RANGE_SHIFT;
+               return pmic->dcdc2_range;
+       case TPS65912_REG_DCDC3:
+               pmic->dcdc3_range = tps65912_reg_read(mfd,
+                                                       TPS65912_DCDC3_LIMIT);
+               if (pmic->dcdc3_range < 0)
+                       return pmic->dcdc3_range;
+               pmic->dcdc3_range = (pmic->dcdc3_range &
+                       DCDC_LIMIT_RANGE_MASK) >> DCDC_LIMIT_RANGE_SHIFT;
+               return pmic->dcdc3_range;
+       case TPS65912_REG_DCDC4:
+               pmic->dcdc4_range = tps65912_reg_read(mfd,
+                                                       TPS65912_DCDC4_LIMIT);
+               if (pmic->dcdc4_range < 0)
+                       return pmic->dcdc4_range;
+               pmic->dcdc4_range = (pmic->dcdc4_range &
+                       DCDC_LIMIT_RANGE_MASK) >> DCDC_LIMIT_RANGE_SHIFT;
+               return pmic->dcdc4_range;
+       default:
+               return 0;
+       }
+}
+
+static unsigned long tps65912_vsel_to_uv_range0(u8 vsel)
+{
+       unsigned long uv;
+
+       uv = ((vsel * 12500) + 500000);
+       return uv;
+}
+
+static unsigned long tps65912_vsel_to_uv_range1(u8 vsel)
+{
+       unsigned long uv;
+
+        uv = ((vsel * 12500) + 700000);
+       return uv;
+}
+
+static unsigned long tps65912_vsel_to_uv_range2(u8 vsel)
+{
+       unsigned long uv;
+
+       uv = ((vsel * 25000) + 500000);
+       return uv;
+}
+
+static unsigned long tps65912_vsel_to_uv_range3(u8 vsel)
+{
+       unsigned long uv;
+
+       if (vsel == 0x3f)
+               uv = 3800000;
+       else
+               uv = ((vsel * 50000) + 500000);
+
+       return uv;
+}
+
+static unsigned long tps65912_vsel_to_uv_ldo(u8 vsel)
+{
+       unsigned long uv = 0;
+
+       if (vsel <= 32)
+               uv = ((vsel * 25000) + 800000);
+       else if (vsel > 32 && vsel <= 60)
+               uv = (((vsel - 32) * 50000) + 1600000);
+       else if (vsel > 60)
+               uv = (((vsel - 60) * 100000) + 3000000);
+
+       return uv;
+}
+
+static int tps65912_get_ctrl_register(int id)
+{
+       switch (id) {
+       case TPS65912_REG_DCDC1:
+               return TPS65912_DCDC1_AVS;
+       case TPS65912_REG_DCDC2:
+               return TPS65912_DCDC2_AVS;
+       case TPS65912_REG_DCDC3:
+               return TPS65912_DCDC3_AVS;
+       case TPS65912_REG_DCDC4:
+               return TPS65912_DCDC4_AVS;
+       case TPS65912_REG_LDO1:
+               return TPS65912_LDO1_AVS;
+       case TPS65912_REG_LDO2:
+               return TPS65912_LDO2_AVS;
+       case TPS65912_REG_LDO3:
+               return TPS65912_LDO3_AVS;
+       case TPS65912_REG_LDO4:
+               return TPS65912_LDO4_AVS;
+       case TPS65912_REG_LDO5:
+               return TPS65912_LDO5;
+       case TPS65912_REG_LDO6:
+               return TPS65912_LDO6;
+       case TPS65912_REG_LDO7:
+               return TPS65912_LDO7;
+       case TPS65912_REG_LDO8:
+               return TPS65912_LDO8;
+       case TPS65912_REG_LDO9:
+               return TPS65912_LDO9;
+       case TPS65912_REG_LDO10:
+               return TPS65912_LDO10;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int tps65912_get_dcdc_sel_register(struct tps65912_reg *pmic, int id)
+{
+       struct tps65912 *mfd = pmic->mfd;
+       int opvsel = 0, sr = 0;
+       u8 reg = 0;
+
+       if (id < TPS65912_REG_DCDC1 || id > TPS65912_REG_DCDC4)
+               return -EINVAL;
+
+       switch (id) {
+       case TPS65912_REG_DCDC1:
+               opvsel = tps65912_reg_read(mfd, TPS65912_DCDC1_OP);
+               sr = ((opvsel & OP_SELREG_MASK) >> OP_SELREG_SHIFT);
+               if (sr)
+                       reg = TPS65912_DCDC1_AVS;
+               else
+                       reg = TPS65912_DCDC1_OP;
+               break;
+       case TPS65912_REG_DCDC2:
+               opvsel = tps65912_reg_read(mfd, TPS65912_DCDC2_OP);
+               sr = (opvsel & OP_SELREG_MASK) >> OP_SELREG_SHIFT;
+               if (sr)
+                       reg = TPS65912_DCDC2_AVS;
+               else
+                       reg = TPS65912_DCDC2_OP;
+               break;
+       case TPS65912_REG_DCDC3:
+               opvsel = tps65912_reg_read(mfd, TPS65912_DCDC3_OP);
+               sr = (opvsel & OP_SELREG_MASK) >> OP_SELREG_SHIFT;
+               if (sr)
+                       reg = TPS65912_DCDC3_AVS;
+               else
+                       reg = TPS65912_DCDC3_OP;
+               break;
+       case TPS65912_REG_DCDC4:
+               opvsel = tps65912_reg_read(mfd, TPS65912_DCDC4_OP);
+               sr = (opvsel & OP_SELREG_MASK) >> OP_SELREG_SHIFT;
+               if (sr)
+                       reg = TPS65912_DCDC4_AVS;
+               else
+                       reg = TPS65912_DCDC4_OP;
+               break;
+       }
+       return reg;
+}
+
+static int tps65912_get_ldo_sel_register(struct tps65912_reg *pmic, int id)
+{
+       struct tps65912 *mfd = pmic->mfd;
+       int opvsel = 0, sr = 0;
+       u8 reg = 0;
+
+       if (id < TPS65912_REG_LDO1 || id > TPS65912_REG_LDO10)
+               return -EINVAL;
+
+       switch (id) {
+       case TPS65912_REG_LDO1:
+               opvsel = tps65912_reg_read(mfd, TPS65912_LDO1_OP);
+               sr = (opvsel & OP_SELREG_MASK) >> OP_SELREG_SHIFT;
+               if (sr)
+                       reg = TPS65912_LDO1_AVS;
+               else
+                       reg = TPS65912_LDO1_OP;
+               break;
+       case TPS65912_REG_LDO2:
+               opvsel = tps65912_reg_read(mfd, TPS65912_LDO2_OP);
+               sr = (opvsel & OP_SELREG_MASK) >> OP_SELREG_SHIFT;
+               if (sr)
+                       reg = TPS65912_LDO2_AVS;
+               else
+                       reg = TPS65912_LDO2_OP;
+               break;
+       case TPS65912_REG_LDO3:
+               opvsel = tps65912_reg_read(mfd, TPS65912_LDO3_OP);
+               sr = (opvsel & OP_SELREG_MASK) >> OP_SELREG_SHIFT;
+               if (sr)
+                       reg = TPS65912_LDO3_AVS;
+               else
+                       reg = TPS65912_LDO3_OP;
+               break;
+       case TPS65912_REG_LDO4:
+               opvsel = tps65912_reg_read(mfd, TPS65912_LDO4_OP);
+               sr = (opvsel & OP_SELREG_MASK) >> OP_SELREG_SHIFT;
+               if (sr)
+                       reg = TPS65912_LDO4_AVS;
+               else
+                       reg = TPS65912_LDO4_OP;
+               break;
+       case TPS65912_REG_LDO5:
+               reg = TPS65912_LDO5;
+               break;
+       case TPS65912_REG_LDO6:
+               reg = TPS65912_LDO6;
+               break;
+       case TPS65912_REG_LDO7:
+               reg = TPS65912_LDO7;
+               break;
+       case TPS65912_REG_LDO8:
+               reg = TPS65912_LDO8;
+               break;
+       case TPS65912_REG_LDO9:
+               reg = TPS65912_LDO9;
+               break;
+       case TPS65912_REG_LDO10:
+               reg = TPS65912_LDO10;
+               break;
+       }
+
+       return reg;
+}
+
+static int tps65912_get_mode_regiters(struct tps65912_reg *pmic, int id)
+{
+       switch (id) {
+       case TPS65912_REG_DCDC1:
+               pmic->pwm_mode_reg = TPS65912_DCDC1_CTRL;
+               pmic->eco_reg = TPS65912_DCDC1_AVS;
+               break;
+       case TPS65912_REG_DCDC2:
+               pmic->pwm_mode_reg = TPS65912_DCDC2_CTRL;
+               pmic->eco_reg = TPS65912_DCDC2_AVS;
+               break;
+       case TPS65912_REG_DCDC3:
+               pmic->pwm_mode_reg = TPS65912_DCDC3_CTRL;
+               pmic->eco_reg = TPS65912_DCDC3_AVS;
+               break;
+       case TPS65912_REG_DCDC4:
+               pmic->pwm_mode_reg = TPS65912_DCDC4_CTRL;
+               pmic->eco_reg = TPS65912_DCDC4_AVS;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int tps65912_reg_is_enabled(struct regulator_dev *dev)
+{
+       struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+       struct tps65912 *mfd = pmic->mfd;
+       int reg, value, id = rdev_get_id(dev);
+
+       if (id < TPS65912_REG_DCDC1 || id > TPS65912_REG_LDO10)
+               return -EINVAL;
+
+       reg = pmic->get_ctrl_reg(id);
+       if (reg < 0)
+               return reg;
+
+       value = tps65912_reg_read(mfd, reg);
+       if (value < 0)
+               return value;
+
+       return value & TPS65912_REG_ENABLED;
+}
+
+static int tps65912_reg_enable(struct regulator_dev *dev)
+{
+       struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+       struct tps65912 *mfd = pmic->mfd;
+       int id = rdev_get_id(dev);
+       int reg;
+
+       if (id < TPS65912_REG_DCDC1 || id > TPS65912_REG_LDO10)
+               return -EINVAL;
+
+       reg = pmic->get_ctrl_reg(id);
+       if (reg < 0)
+               return reg;
+
+       return tps65912_set_bits(mfd, reg, TPS65912_REG_ENABLED);
+}
+
+static int tps65912_reg_disable(struct regulator_dev *dev)
+{
+       struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+       struct tps65912 *mfd = pmic->mfd;
+       int id = rdev_get_id(dev), reg;
+
+       reg = pmic->get_ctrl_reg(id);
+       if (reg < 0)
+               return reg;
+
+       return tps65912_clear_bits(mfd, reg, TPS65912_REG_ENABLED);
+}
+
+static int tps65912_set_mode(struct regulator_dev *dev, unsigned int mode)
+{
+       struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+       struct tps65912 *mfd = pmic->mfd;
+       int pwm_mode, eco, id = rdev_get_id(dev);
+
+       tps65912_get_mode_regiters(pmic, id);
+
+       pwm_mode = tps65912_reg_read(mfd, pmic->pwm_mode_reg);
+       eco = tps65912_reg_read(mfd, pmic->eco_reg);
+
+       pwm_mode &= DCDCCTRL_DCDC_MODE_MASK;
+       eco &= DCDC_AVS_ECO_MASK;
+
+       switch (mode) {
+       case REGULATOR_MODE_FAST:
+               /* Verify if mode alredy set */
+               if (pwm_mode && !eco)
+                       break;
+               tps65912_set_bits(mfd, pmic->pwm_mode_reg, DCDCCTRL_DCDC_MODE_MASK);
+               tps65912_clear_bits(mfd, pmic->eco_reg, DCDC_AVS_ECO_MASK);
+               break;
+       case REGULATOR_MODE_NORMAL:
+       case REGULATOR_MODE_IDLE:
+               if (!pwm_mode && !eco)
+                       break;
+               tps65912_clear_bits(mfd, pmic->pwm_mode_reg, DCDCCTRL_DCDC_MODE_MASK);
+               tps65912_clear_bits(mfd, pmic->eco_reg, DCDC_AVS_ECO_MASK);
+               break;
+       case REGULATOR_MODE_STANDBY:
+               if (!pwm_mode && eco)
+                       break;
+               tps65912_clear_bits(mfd, pmic->pwm_mode_reg, DCDCCTRL_DCDC_MODE_MASK);
+               tps65912_set_bits(mfd, pmic->eco_reg, DCDC_AVS_ECO_MASK);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static unsigned int tps65912_get_mode(struct regulator_dev *dev)
+{
+       struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+       struct tps65912 *mfd = pmic->mfd;
+       int pwm_mode, eco, mode = 0, id = rdev_get_id(dev);
+
+       tps65912_get_mode_regiters(pmic, id);
+
+       pwm_mode = tps65912_reg_read(mfd, pmic->pwm_mode_reg);
+       eco = tps65912_reg_read(mfd, pmic->eco_reg);
+
+       pwm_mode &= DCDCCTRL_DCDC_MODE_MASK;
+       eco &= DCDC_AVS_ECO_MASK;
+
+       if (pwm_mode && !eco)
+               mode = REGULATOR_MODE_FAST;
+       else if (!pwm_mode && !eco)
+               mode = REGULATOR_MODE_NORMAL;
+       else if (!pwm_mode && eco)
+               mode = REGULATOR_MODE_STANDBY;
+
+       return mode;
+}
+
+static int tps65912_get_voltage_dcdc(struct regulator_dev *dev)
+{
+       struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+       struct tps65912 *mfd = pmic->mfd;
+       int id = rdev_get_id(dev), voltage = 0, range;
+       int opvsel = 0, avsel = 0, sr, vsel;
+
+       switch (id) {
+       case TPS65912_REG_DCDC1:
+               opvsel = tps65912_reg_read(mfd, TPS65912_DCDC1_OP);
+               avsel = tps65912_reg_read(mfd, TPS65912_DCDC1_AVS);
+               range = pmic->dcdc1_range;
+               break;
+       case TPS65912_REG_DCDC2:
+               opvsel = tps65912_reg_read(mfd, TPS65912_DCDC2_OP);
+               avsel = tps65912_reg_read(mfd, TPS65912_DCDC2_AVS);
+               range = pmic->dcdc2_range;
+               break;
+       case TPS65912_REG_DCDC3:
+               opvsel = tps65912_reg_read(mfd, TPS65912_DCDC3_OP);
+               avsel = tps65912_reg_read(mfd, TPS65912_DCDC3_AVS);
+               range = pmic->dcdc3_range;
+               break;
+       case TPS65912_REG_DCDC4:
+               opvsel = tps65912_reg_read(mfd, TPS65912_DCDC4_OP);
+               avsel = tps65912_reg_read(mfd, TPS65912_DCDC4_AVS);
+               range = pmic->dcdc4_range;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       sr = (opvsel & OP_SELREG_MASK) >> OP_SELREG_SHIFT;
+       if (sr)
+               vsel = avsel;
+       else
+               vsel = opvsel;
+       vsel &= 0x3F;
+
+       switch (range) {
+       case 0:
+               /* 0.5 - 1.2875V in 12.5mV steps */
+               voltage = tps65912_vsel_to_uv_range0(vsel);
+               break;
+       case 1:
+               /* 0.7 - 1.4875V in 12.5mV steps */
+               voltage = tps65912_vsel_to_uv_range1(vsel);
+               break;
+       case 2:
+               /* 0.5 - 2.075V in 25mV steps */
+               voltage = tps65912_vsel_to_uv_range2(vsel);
+               break;
+       case 3:
+               /* 0.5 - 3.8V in 50mV steps */
+               voltage = tps65912_vsel_to_uv_range3(vsel);
+               break;
+       }
+       return voltage;
+}
+
+static int tps65912_set_voltage_dcdc(struct regulator_dev *dev,
+                                               unsigned selector)
+{
+       struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+       struct tps65912 *mfd = pmic->mfd;
+       int id = rdev_get_id(dev);
+       int value;
+       u8 reg;
+
+       reg = tps65912_get_dcdc_sel_register(pmic, id);
+       value = tps65912_reg_read(mfd, reg);
+       value &= 0xC0;
+       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_ldo_sel_register(pmic, id);
+       vsel = tps65912_reg_read(mfd, reg);
+       vsel &= 0x3F;
+
+       return tps65912_vsel_to_uv_ldo(vsel);
+}
+
+static int tps65912_set_voltage_ldo(struct regulator_dev *dev,
+                                               unsigned selector)
+{
+       struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+       struct tps65912 *mfd = pmic->mfd;
+       int id = rdev_get_id(dev), reg, value;
+
+       reg = tps65912_get_ldo_sel_register(pmic, id);
+       value = tps65912_reg_read(mfd, reg);
+       value &= 0xC0;
+       return tps65912_reg_write(mfd, reg, selector | value);
+}
+
+static int tps65912_list_voltage_dcdc(struct regulator_dev *dev,
+                                       unsigned selector)
+{
+       struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+       int range, voltage = 0, id = rdev_get_id(dev);
+
+       switch (id) {
+       case TPS65912_REG_DCDC1:
+               range = pmic->dcdc1_range;
+               break;
+       case TPS65912_REG_DCDC2:
+               range = pmic->dcdc2_range;
+               break;
+       case TPS65912_REG_DCDC3:
+               range = pmic->dcdc3_range;
+               break;
+       case TPS65912_REG_DCDC4:
+               range = pmic->dcdc4_range;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (range) {
+       case 0:
+               /* 0.5 - 1.2875V in 12.5mV steps */
+               voltage = tps65912_vsel_to_uv_range0(selector);
+               break;
+       case 1:
+               /* 0.7 - 1.4875V in 12.5mV steps */
+               voltage = tps65912_vsel_to_uv_range1(selector);
+               break;
+       case 2:
+               /* 0.5 - 2.075V in 25mV steps */
+               voltage = tps65912_vsel_to_uv_range2(selector);
+               break;
+       case 3:
+               /* 0.5 - 3.8V in 50mV steps */
+               voltage = tps65912_vsel_to_uv_range3(selector);
+               break;
+       }
+       return voltage;
+}
+
+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,
+       .enable = tps65912_reg_enable,
+       .disable = tps65912_reg_disable,
+       .set_mode = tps65912_set_mode,
+       .get_mode = tps65912_get_mode,
+       .get_voltage = tps65912_get_voltage_dcdc,
+       .set_voltage_sel = tps65912_set_voltage_dcdc,
+       .list_voltage = tps65912_list_voltage_dcdc,
+};
+
+/* Operations permitted on LDOx */
+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,
+       .set_voltage_sel = tps65912_set_voltage_ldo,
+       .list_voltage = tps65912_list_voltage_ldo,
+};
+
+static __devinit int tps65912_probe(struct platform_device *pdev)
+{
+       struct tps65912 *tps65912 = dev_get_drvdata(pdev->dev.parent);
+       struct tps_info *info;
+       struct regulator_init_data *reg_data;
+       struct regulator_dev *rdev;
+       struct tps65912_reg *pmic;
+       struct tps65912_board *pmic_plat_data;
+       int i, err;
+
+       pmic_plat_data = dev_get_platdata(tps65912->dev);
+       if (!pmic_plat_data)
+               return -EINVAL;
+
+       reg_data = pmic_plat_data->tps65912_pmic_init_data;
+
+       pmic = kzalloc(sizeof(*pmic), GFP_KERNEL);
+       if (!pmic)
+               return -ENOMEM;
+
+       mutex_init(&pmic->io_lock);
+       pmic->mfd = tps65912;
+       platform_set_drvdata(pdev, pmic);
+
+       pmic->get_ctrl_reg = &tps65912_get_ctrl_register;
+       info = tps65912_regs;
+
+       for (i = 0; i < TPS65912_NUM_REGULATOR; i++, info++, reg_data++) {
+               int range = 0;
+               /* Register the regulators */
+               pmic->info[i] = info;
+
+               pmic->desc[i].name = info->name;
+               pmic->desc[i].id = i;
+               pmic->desc[i].n_voltages = 64;
+               pmic->desc[i].ops = (i > TPS65912_REG_DCDC4 ?
+                       &tps65912_ops_ldo : &tps65912_ops_dcdc);
+               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);
+               if (IS_ERR(rdev)) {
+                       dev_err(tps65912->dev,
+                               "failed to register %s regulator\n",
+                               pdev->name);
+                       err = PTR_ERR(rdev);
+                       goto err;
+               }
+
+               /* Save regulator for cleanup */
+               pmic->rdev[i] = rdev;
+       }
+       return 0;
+
+err:
+       while (--i >= 0)
+               regulator_unregister(pmic->rdev[i]);
+
+       kfree(pmic);
+       return err;
+}
+
+static int __devexit tps65912_remove(struct platform_device *pdev)
+{
+       struct tps65912_reg *tps65912_reg = platform_get_drvdata(pdev);
+       int i;
+
+       for (i = 0; i < TPS65912_NUM_REGULATOR; i++)
+               regulator_unregister(tps65912_reg->rdev[i]);
+
+       kfree(tps65912_reg);
+       return 0;
+}
+
+static struct platform_driver tps65912_driver = {
+       .driver = {
+               .name = "tps65912-pmic",
+               .owner = THIS_MODULE,
+       },
+       .probe = tps65912_probe,
+       .remove = __devexit_p(tps65912_remove),
+};
+
+/**
+ * tps65912_init
+ *
+ * Module init function
+ */
+static int __init tps65912_init(void)
+{
+       return platform_driver_register(&tps65912_driver);
+}
+subsys_initcall(tps65912_init);
+
+/**
+ * tps65912_cleanup
+ *
+ * Module exit function
+ */
+static void __exit tps65912_cleanup(void)
+{
+       platform_driver_unregister(&tps65912_driver);
+}
+module_exit(tps65912_cleanup);
+
+MODULE_AUTHOR("Margarita Olaya Cabrera <magi@slimlogic.co.uk>");
+MODULE_DESCRIPTION("TPS65912 voltage regulator driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:tps65912-pmic");
index 87fe0f7..ee8747f 100644 (file)
@@ -835,8 +835,8 @@ static struct regulator_ops twlsmps_ops = {
                        remap_conf) \
                TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
                        remap_conf, TWL4030, twl4030fixed_ops)
-#define TWL6030_FIXED_LDO(label, offset, mVolts, num, turnon_delay) \
-               TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
+#define TWL6030_FIXED_LDO(label, offset, mVolts, turnon_delay) \
+               TWL_FIXED_LDO(label, offset, mVolts, 0x0, turnon_delay, \
                        0x0, TWL6030, twl6030fixed_ops)
 
 #define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) { \
@@ -856,24 +856,22 @@ static struct regulator_ops twlsmps_ops = {
                }, \
        }
 
-#define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts, num) { \
+#define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) { \
        .base = offset, \
-       .id = num, \
        .min_mV = min_mVolts, \
        .max_mV = max_mVolts, \
        .desc = { \
                .name = #label, \
                .id = TWL6030_REG_##label, \
-               .n_voltages = (max_mVolts - min_mVolts)/100, \
+               .n_voltages = (max_mVolts - min_mVolts)/100 + 1, \
                .ops = &twl6030ldo_ops, \
                .type = REGULATOR_VOLTAGE, \
                .owner = THIS_MODULE, \
                }, \
        }
 
-#define TWL6025_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts, num) { \
+#define TWL6025_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) { \
        .base = offset, \
-       .id = num, \
        .min_mV = min_mVolts, \
        .max_mV = max_mVolts, \
        .desc = { \
@@ -903,9 +901,8 @@ static struct regulator_ops twlsmps_ops = {
                }, \
        }
 
-#define TWL6030_FIXED_RESOURCE(label, offset, num, turnon_delay) { \
+#define TWL6030_FIXED_RESOURCE(label, offset, turnon_delay) { \
        .base = offset, \
-       .id = num, \
        .delay = turnon_delay, \
        .desc = { \
                .name = #label, \
@@ -916,9 +913,8 @@ static struct regulator_ops twlsmps_ops = {
                }, \
        }
 
-#define TWL6025_ADJUSTABLE_SMPS(label, offset, num) { \
+#define TWL6025_ADJUSTABLE_SMPS(label, offset) { \
        .base = offset, \
-       .id = num, \
        .min_mV = 600, \
        .max_mV = 2100, \
        .desc = { \
@@ -961,32 +957,32 @@ static struct twlreg_info twl_regs[] = {
        /* 6030 REG with base as PMC Slave Misc : 0x0030 */
        /* Turnon-delay and remap configuration values for 6030 are not
           verified since the specification is not public */
-       TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1000, 3300, 1),
-       TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 1000, 3300, 2),
-       TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 1000, 3300, 3),
-       TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000, 3300, 4),
-       TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000, 3300, 5),
-       TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000, 3300, 7),
-       TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15, 0),
-       TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16, 0),
-       TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0),
-       TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0),
-       TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 48, 0),
+       TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1000, 3300),
+       TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 1000, 3300),
+       TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 1000, 3300),
+       TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000, 3300),
+       TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000, 3300),
+       TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000, 3300),
+       TWL6030_FIXED_LDO(VANA, 0x50, 2100, 0),
+       TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 0),
+       TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 0),
+       TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 0),
+       TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 0),
 
        /* 6025 are renamed compared to 6030 versions */
-       TWL6025_ADJUSTABLE_LDO(LDO2, 0x54, 1000, 3300, 1),
-       TWL6025_ADJUSTABLE_LDO(LDO4, 0x58, 1000, 3300, 2),
-       TWL6025_ADJUSTABLE_LDO(LDO3, 0x5c, 1000, 3300, 3),
-       TWL6025_ADJUSTABLE_LDO(LDO5, 0x68, 1000, 3300, 4),
-       TWL6025_ADJUSTABLE_LDO(LDO1, 0x6c, 1000, 3300, 5),
-       TWL6025_ADJUSTABLE_LDO(LDO7, 0x74, 1000, 3300, 7),
-       TWL6025_ADJUSTABLE_LDO(LDO6, 0x60, 1000, 3300, 16),
-       TWL6025_ADJUSTABLE_LDO(LDOLN, 0x64, 1000, 3300, 17),
-       TWL6025_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000, 3300, 18),
-
-       TWL6025_ADJUSTABLE_SMPS(SMPS3, 0x34, 1),
-       TWL6025_ADJUSTABLE_SMPS(SMPS4, 0x10, 2),
-       TWL6025_ADJUSTABLE_SMPS(VIO, 0x16, 3),
+       TWL6025_ADJUSTABLE_LDO(LDO2, 0x54, 1000, 3300),
+       TWL6025_ADJUSTABLE_LDO(LDO4, 0x58, 1000, 3300),
+       TWL6025_ADJUSTABLE_LDO(LDO3, 0x5c, 1000, 3300),
+       TWL6025_ADJUSTABLE_LDO(LDO5, 0x68, 1000, 3300),
+       TWL6025_ADJUSTABLE_LDO(LDO1, 0x6c, 1000, 3300),
+       TWL6025_ADJUSTABLE_LDO(LDO7, 0x74, 1000, 3300),
+       TWL6025_ADJUSTABLE_LDO(LDO6, 0x60, 1000, 3300),
+       TWL6025_ADJUSTABLE_LDO(LDOLN, 0x64, 1000, 3300),
+       TWL6025_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000, 3300),
+
+       TWL6025_ADJUSTABLE_SMPS(SMPS3, 0x34),
+       TWL6025_ADJUSTABLE_SMPS(SMPS4, 0x10),
+       TWL6025_ADJUSTABLE_SMPS(VIO, 0x16),
 };
 
 static u8 twl_get_smps_offset(void)
index a0982e8..bd3531d 100644 (file)
@@ -267,23 +267,6 @@ static int wm831x_buckv_select_min_voltage(struct regulator_dev *rdev,
        return vsel;
 }
 
-static int wm831x_buckv_select_max_voltage(struct regulator_dev *rdev,
-                                          int min_uV, int max_uV)
-{
-       u16 vsel;
-
-       if (max_uV < 600000 || max_uV > 1800000)
-               return -EINVAL;
-
-       vsel = ((max_uV - 600000) / 12500) + 8;
-
-       if (wm831x_buckv_list_voltage(rdev, vsel) < min_uV ||
-           wm831x_buckv_list_voltage(rdev, vsel) < max_uV)
-               return -EINVAL;
-
-       return vsel;
-}
-
 static int wm831x_buckv_set_dvs(struct regulator_dev *rdev, int state)
 {
        struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
@@ -338,28 +321,23 @@ static int wm831x_buckv_set_voltage(struct regulator_dev *rdev,
        if (ret < 0)
                return ret;
 
-       /* Set the high voltage as the DVS voltage.  This is optimised
-        * for CPUfreq usage, most processors will keep the maximum
-        * voltage constant and lower the minimum with the frequency. */
-       vsel = wm831x_buckv_select_max_voltage(rdev, min_uV, max_uV);
-       if (vsel < 0) {
-               /* This should never happen - at worst the same vsel
-                * should be chosen */
-               WARN_ON(vsel < 0);
-               return 0;
+       /*
+        * If this VSEL is higher than the last one we've seen then
+        * remember it as the DVS VSEL.  This is optimised for CPUfreq
+        * usage where we want to get to the highest voltage very
+        * quickly.
+        */
+       if (vsel > dcdc->dvs_vsel) {
+               ret = wm831x_set_bits(wm831x, dvs_reg,
+                                     WM831X_DC1_DVS_VSEL_MASK,
+                                     dcdc->dvs_vsel);
+               if (ret == 0)
+                       dcdc->dvs_vsel = vsel;
+               else
+                       dev_warn(wm831x->dev,
+                                "Failed to set DCDC DVS VSEL: %d\n", ret);
        }
 
-       /* Don't bother if it's the same VSEL we're already using */
-       if (vsel == dcdc->on_vsel)
-               return 0;
-
-       ret = wm831x_set_bits(wm831x, dvs_reg, WM831X_DC1_DVS_VSEL_MASK, vsel);
-       if (ret == 0)
-               dcdc->dvs_vsel = vsel;
-       else
-               dev_warn(wm831x->dev, "Failed to set DCDC DVS VSEL: %d\n",
-                        ret);
-
        return 0;
 }
 
@@ -456,27 +434,6 @@ static __devinit void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc,
        if (!pdata || !pdata->dvs_gpio)
                return;
 
-       switch (pdata->dvs_control_src) {
-       case 1:
-               ctrl = 2 << WM831X_DC1_DVS_SRC_SHIFT;
-               break;
-       case 2:
-               ctrl = 3 << WM831X_DC1_DVS_SRC_SHIFT;
-               break;
-       default:
-               dev_err(wm831x->dev, "Invalid DVS control source %d for %s\n",
-                       pdata->dvs_control_src, dcdc->name);
-               return;
-       }
-
-       ret = wm831x_set_bits(wm831x, dcdc->base + WM831X_DCDC_DVS_CONTROL,
-                             WM831X_DC1_DVS_SRC_MASK, ctrl);
-       if (ret < 0) {
-               dev_err(wm831x->dev, "Failed to set %s DVS source: %d\n",
-                       dcdc->name, ret);
-               return;
-       }
-
        ret = gpio_request(pdata->dvs_gpio, "DCDC DVS");
        if (ret < 0) {
                dev_err(wm831x->dev, "Failed to get %s DVS GPIO: %d\n",
@@ -498,17 +455,57 @@ static __devinit void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc,
        }
 
        dcdc->dvs_gpio = pdata->dvs_gpio;
+
+       switch (pdata->dvs_control_src) {
+       case 1:
+               ctrl = 2 << WM831X_DC1_DVS_SRC_SHIFT;
+               break;
+       case 2:
+               ctrl = 3 << WM831X_DC1_DVS_SRC_SHIFT;
+               break;
+       default:
+               dev_err(wm831x->dev, "Invalid DVS control source %d for %s\n",
+                       pdata->dvs_control_src, dcdc->name);
+               return;
+       }
+
+       /* If DVS_VSEL is set to the minimum value then raise it to ON_VSEL
+        * to make bootstrapping a bit smoother.
+        */
+       if (!dcdc->dvs_vsel) {
+               ret = wm831x_set_bits(wm831x,
+                                     dcdc->base + WM831X_DCDC_DVS_CONTROL,
+                                     WM831X_DC1_DVS_VSEL_MASK, dcdc->on_vsel);
+               if (ret == 0)
+                       dcdc->dvs_vsel = dcdc->on_vsel;
+               else
+                       dev_warn(wm831x->dev, "Failed to set DVS_VSEL: %d\n",
+                                ret);
+       }
+
+       ret = wm831x_set_bits(wm831x, dcdc->base + WM831X_DCDC_DVS_CONTROL,
+                             WM831X_DC1_DVS_SRC_MASK, ctrl);
+       if (ret < 0) {
+               dev_err(wm831x->dev, "Failed to set %s DVS source: %d\n",
+                       dcdc->name, ret);
+       }
 }
 
 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;
-       int id = pdev->id % ARRAY_SIZE(pdata->dcdc);
+       int id;
        struct wm831x_dcdc *dcdc;
        struct resource *res;
        int ret, irq;
 
+       if (pdata && pdata->wm831x_num)
+               id = (pdata->wm831x_num * 10) + 1;
+       else
+               id = 0;
+       id = pdev->id - id;
+
        dev_dbg(&pdev->dev, "Probing DCDC%d\n", id + 1);
 
        if (pdata == NULL || pdata->dcdc[id] == NULL)
@@ -545,7 +542,7 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev)
        }
        dcdc->on_vsel = ret & WM831X_DC1_ON_VSEL_MASK;
 
-       ret = wm831x_reg_read(wm831x, dcdc->base + WM831X_DCDC_ON_CONFIG);
+       ret = wm831x_reg_read(wm831x, dcdc->base + WM831X_DCDC_DVS_CONTROL);
        if (ret < 0) {
                dev_err(wm831x->dev, "Failed to read DVS VSEL: %d\n", ret);
                goto err;
@@ -709,11 +706,17 @@ 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;
-       int id = pdev->id % ARRAY_SIZE(pdata->dcdc);
+       int id;
        struct wm831x_dcdc *dcdc;
        struct resource *res;
        int ret, irq;
 
+       if (pdata && pdata->wm831x_num)
+               id = (pdata->wm831x_num * 10) + 1;
+       else
+               id = 0;
+       id = pdev->id - id;
+
        dev_dbg(&pdev->dev, "Probing DCDC%d\n", id + 1);
 
        if (pdata == NULL || pdata->dcdc[id] == NULL)
@@ -1046,3 +1049,4 @@ MODULE_DESCRIPTION("WM831x DC-DC convertor driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:wm831x-buckv");
 MODULE_ALIAS("platform:wm831x-buckp");
+MODULE_ALIAS("platform:wm831x-epe");
index 2220cf8..6709710 100644 (file)
@@ -310,11 +310,17 @@ 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;
-       int id = pdev->id % ARRAY_SIZE(pdata->ldo);
+       int id;
        struct wm831x_ldo *ldo;
        struct resource *res;
        int ret, irq;
 
+       if (pdata && pdata->wm831x_num)
+               id = (pdata->wm831x_num * 10) + 1;
+       else
+               id = 0;
+       id = pdev->id - id;
+
        dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
 
        if (pdata == NULL || pdata->ldo[id] == NULL)
@@ -574,11 +580,17 @@ 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;
-       int id = pdev->id % ARRAY_SIZE(pdata->ldo);
+       int id;
        struct wm831x_ldo *ldo;
        struct resource *res;
        int ret, irq;
 
+       if (pdata && pdata->wm831x_num)
+               id = (pdata->wm831x_num * 10) + 1;
+       else
+               id = 0;
+       id = pdev->id - id;
+
        dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
 
        if (pdata == NULL || pdata->ldo[id] == NULL)
@@ -764,11 +776,18 @@ 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;
-       int id = pdev->id % ARRAY_SIZE(pdata->ldo);
+       int id;
        struct wm831x_ldo *ldo;
        struct resource *res;
        int ret;
 
+       if (pdata && pdata->wm831x_num)
+               id = (pdata->wm831x_num * 10) + 1;
+       else
+               id = 0;
+       id = pdev->id - id;
+
+
        dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
 
        if (pdata == NULL || pdata->ldo[id] == NULL)
index 35b2958..1a6a690 100644 (file)
@@ -43,7 +43,7 @@ static int wm8994_ldo_enable(struct regulator_dev *rdev)
        if (!ldo->enable)
                return 0;
 
-       gpio_set_value(ldo->enable, 1);
+       gpio_set_value_cansleep(ldo->enable, 1);
        ldo->is_enabled = true;
 
        return 0;
@@ -57,7 +57,7 @@ static int wm8994_ldo_disable(struct regulator_dev *rdev)
        if (!ldo->enable)
                return -EINVAL;
 
-       gpio_set_value(ldo->enable, 0);
+       gpio_set_value_cansleep(ldo->enable, 0);
        ldo->is_enabled = false;
 
        return 0;
index 3195dbd..44e91e5 100644 (file)
@@ -639,7 +639,7 @@ EXPORT_SYMBOL_GPL(rtc_irq_unregister);
 static int rtc_update_hrtimer(struct rtc_device *rtc, int enabled)
 {
        /*
-        * We unconditionally cancel the timer here, because otherwise
+        * We always cancel the timer here first, because otherwise
         * we could run into BUG_ON(timer->state != HRTIMER_STATE_CALLBACK);
         * when we manage to start the timer before the callback
         * returns HRTIMER_RESTART.
@@ -708,7 +708,7 @@ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq)
        int err = 0;
        unsigned long flags;
 
-       if (freq <= 0 || freq > 5000)
+       if (freq <= 0 || freq > RTC_MAX_FREQ)
                return -EINVAL;
 retry:
        spin_lock_irqsave(&rtc->irq_task_lock, flags);
index bcae8dd..7789002 100644 (file)
@@ -368,7 +368,7 @@ static int __init omap_rtc_probe(struct platform_device *pdev)
                pr_info("%s: already running\n", pdev->name);
 
        /* force to 24 hour mode */
-       new_ctrl = reg & ~(OMAP_RTC_CTRL_SPLIT|OMAP_RTC_CTRL_AUTO_COMP);
+       new_ctrl = reg & (OMAP_RTC_CTRL_SPLIT|OMAP_RTC_CTRL_AUTO_COMP);
        new_ctrl |= OMAP_RTC_CTRL_STOP;
 
        /* BOARD-SPECIFIC CUSTOMIZATION CAN GO HERE:
index 432444a..a1d3ddb 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/mutex.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
+#include <linux/vmalloc.h>
 
 #include <asm/ccwdev.h>
 #include <asm/ebcdic.h>
@@ -888,11 +889,11 @@ char *dasd_get_user_string(const char __user *user_buf, size_t user_len)
 {
        char *buffer;
 
-       buffer = kmalloc(user_len + 1, GFP_KERNEL);
+       buffer = vmalloc(user_len + 1);
        if (buffer == NULL)
                return ERR_PTR(-ENOMEM);
        if (copy_from_user(buffer, user_buf, user_len) != 0) {
-               kfree(buffer);
+               vfree(buffer);
                return ERR_PTR(-EFAULT);
        }
        /* got the string, now strip linefeed. */
@@ -930,7 +931,7 @@ static ssize_t dasd_stats_write(struct file *file,
                dasd_profile_off(prof);
        } else
                rc = -EINVAL;
-       kfree(buffer);
+       vfree(buffer);
        return rc;
 }
 
@@ -1042,7 +1043,7 @@ static ssize_t dasd_stats_global_write(struct file *file,
                dasd_global_profile_level = DASD_PROFILE_OFF;
        } else
                rc = -EINVAL;
-       kfree(buffer);
+       vfree(buffer);
        return rc;
 }
 
index 30fb979..6e835c9 100644 (file)
@@ -1461,6 +1461,15 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
                                "Read device characteristic failed, rc=%d", rc);
                goto out_err3;
        }
+
+       if ((device->features & DASD_FEATURE_USERAW) &&
+           !(private->rdc_data.facilities.RT_in_LR)) {
+               dev_err(&device->cdev->dev, "The storage server does not "
+                       "support raw-track access\n");
+               rc = -EINVAL;
+               goto out_err3;
+       }
+
        /* find the valid cylinder size */
        if (private->rdc_data.no_cyl == LV_COMPAT_CYL &&
            private->rdc_data.long_no_cyl)
index 6c3c536..e12989f 100644 (file)
@@ -312,14 +312,14 @@ static ssize_t dasd_stats_proc_write(struct file *file,
                pr_info("The statistics have been reset\n");
        } else
                goto out_parse_error;
-       kfree(buffer);
+       vfree(buffer);
        return user_len;
 out_parse_error:
        rc = -EINVAL;
        pr_warning("%s is not a supported value for /proc/dasd/statistics\n",
                str);
 out_error:
-       kfree(buffer);
+       vfree(buffer);
        return rc;
 #else
        pr_warning("/proc/dasd/statistics: is not activated in this kernel\n");
index 7ad30e7..5f9f929 100644 (file)
@@ -82,12 +82,9 @@ static int proc_handler_callhome(struct ctl_table *ctl, int write,
                        return -EFAULT;
        } else {
                len = *count;
-               rc = copy_from_user(buf, buffer, sizeof(buf));
-               if (rc != 0)
-                       return -EFAULT;
-               buf[sizeof(buf) - 1] = '\0';
-               if (strict_strtoul(buf, 0, &val) != 0)
-                       return -EINVAL;
+               rc = kstrtoul_from_user(buffer, len, 0, &val);
+               if (rc)
+                       return rc;
                if (val != 0 && val != 1)
                        return -EINVAL;
                callhome_enabled = val;
index 7bc643f..e5c9664 100644 (file)
@@ -14,6 +14,8 @@
 #include "chsc.h"
 
 #define QDIO_BUSY_BIT_PATIENCE         (100 << 12)     /* 100 microseconds */
+#define QDIO_BUSY_BIT_RETRY_DELAY      10              /* 10 milliseconds */
+#define QDIO_BUSY_BIT_RETRIES          1000            /* = 10s retry time */
 #define QDIO_INPUT_THRESHOLD           (500 << 12)     /* 500 microseconds */
 
 /*
index f8b03a6..0e615cb 100644 (file)
@@ -188,19 +188,13 @@ static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
        struct qdio_irq *irq_ptr = seq->private;
        struct qdio_q *q;
        unsigned long val;
-       char buf[8];
        int ret, i;
 
        if (!irq_ptr)
                return 0;
-       if (count >= sizeof(buf))
-               return -EINVAL;
-       if (copy_from_user(&buf, ubuf, count))
-               return -EFAULT;
-       buf[count] = 0;
-
-       ret = strict_strtoul(buf, 10, &val);
-       if (ret < 0)
+
+       ret = kstrtoul_from_user(ubuf, count, 10, &val);
+       if (ret)
                return ret;
 
        switch (val) {
index e58169c..288c914 100644 (file)
@@ -313,7 +313,7 @@ static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit)
        unsigned long schid = *((u32 *) &q->irq_ptr->schid);
        unsigned int fc = QDIO_SIGA_WRITE;
        u64 start_time = 0;
-       int cc;
+       int retries = 0, cc;
 
        if (is_qebsm(q)) {
                schid = q->irq_ptr->sch_token;
@@ -325,6 +325,7 @@ again:
        /* hipersocket busy condition */
        if (unlikely(*busy_bit)) {
                WARN_ON(queue_type(q) != QDIO_IQDIO_QFMT || cc != 2);
+               retries++;
 
                if (!start_time) {
                        start_time = get_clock();
@@ -333,6 +334,11 @@ again:
                if ((get_clock() - start_time) < QDIO_BUSY_BIT_PATIENCE)
                        goto again;
        }
+       if (retries) {
+               DBF_DEV_EVENT(DBF_WARN, q->irq_ptr,
+                             "%4x cc2 BB1:%1d", SCH_NO(q), q->nr);
+               DBF_DEV_EVENT(DBF_WARN, q->irq_ptr, "count:%u", retries);
+       }
        return cc;
 }
 
@@ -728,13 +734,14 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q)
 
 static int qdio_kick_outbound_q(struct qdio_q *q)
 {
+       int retries = 0, cc;
        unsigned int busy_bit;
-       int cc;
 
        if (!need_siga_out(q))
                return 0;
 
        DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr);
+retry:
        qperf_inc(q, siga_write);
 
        cc = qdio_siga_output(q, &busy_bit);
@@ -743,7 +750,11 @@ static int qdio_kick_outbound_q(struct qdio_q *q)
                break;
        case 2:
                if (busy_bit) {
-                       DBF_ERROR("%4x cc2 REP:%1d", SCH_NO(q), q->nr);
+                       while (++retries < QDIO_BUSY_BIT_RETRIES) {
+                               mdelay(QDIO_BUSY_BIT_RETRY_DELAY);
+                               goto retry;
+                       }
+                       DBF_ERROR("%4x cc2 BBC:%1d", SCH_NO(q), q->nr);
                        cc |= QDIO_ERROR_SIGA_BUSY;
                } else
                        DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", q->nr);
@@ -753,6 +764,10 @@ static int qdio_kick_outbound_q(struct qdio_q *q)
                DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc);
                break;
        }
+       if (retries) {
+               DBF_ERROR("%4x cc2 BB2:%1d", SCH_NO(q), q->nr);
+               DBF_ERROR("count:%u", retries);
+       }
        return cc;
 }
 
index 3b0af11..a796de9 100644 (file)
@@ -27,6 +27,7 @@
 struct bfa_s;
 
 typedef void (*bfa_isr_func_t) (struct bfa_s *bfa, struct bfi_msg_s *m);
+typedef void (*bfa_cb_cbfn_status_t) (void *cbarg, bfa_status_t status);
 
 /*
  * Interrupt message handlers
@@ -121,6 +122,7 @@ bfa_reqq_winit(struct bfa_reqq_wait_s *wqe, void (*qresume) (void *cbarg),
 #define bfa_cb_queue(__bfa, __hcb_qe, __cbfn, __cbarg) do {    \
                (__hcb_qe)->cbfn  = (__cbfn);      \
                (__hcb_qe)->cbarg = (__cbarg);      \
+               (__hcb_qe)->pre_rmv = BFA_FALSE;                \
                list_add_tail(&(__hcb_qe)->qe, &(__bfa)->comp_q);      \
        } while (0)
 
@@ -135,6 +137,11 @@ bfa_reqq_winit(struct bfa_reqq_wait_s *wqe, void (*qresume) (void *cbarg),
                }                                                       \
        } while (0)
 
+#define bfa_cb_queue_status(__bfa, __hcb_qe, __status) do {            \
+               (__hcb_qe)->fw_status = (__status);                     \
+               list_add_tail(&(__hcb_qe)->qe, &(__bfa)->comp_q);       \
+} while (0)
+
 #define bfa_cb_queue_done(__hcb_qe) do {       \
                (__hcb_qe)->once = BFA_FALSE;   \
        } while (0)
@@ -177,7 +184,7 @@ struct bfa_msix_s {
 struct bfa_hwif_s {
        void (*hw_reginit)(struct bfa_s *bfa);
        void (*hw_reqq_ack)(struct bfa_s *bfa, int reqq);
-       void (*hw_rspq_ack)(struct bfa_s *bfa, int rspq);
+       void (*hw_rspq_ack)(struct bfa_s *bfa, int rspq, u32 ci);
        void (*hw_msix_init)(struct bfa_s *bfa, int nvecs);
        void (*hw_msix_ctrl_install)(struct bfa_s *bfa);
        void (*hw_msix_queue_install)(struct bfa_s *bfa);
@@ -268,10 +275,8 @@ struct bfa_iocfc_s {
        ((__bfa)->iocfc.hwif.hw_msix_queue_install(__bfa))
 #define bfa_msix_uninstall(__bfa)                                      \
        ((__bfa)->iocfc.hwif.hw_msix_uninstall(__bfa))
-#define bfa_isr_rspq_ack(__bfa, __queue) do {                          \
-       if ((__bfa)->iocfc.hwif.hw_rspq_ack)                            \
-               (__bfa)->iocfc.hwif.hw_rspq_ack(__bfa, __queue);        \
-} while (0)
+#define bfa_isr_rspq_ack(__bfa, __queue, __ci)                         \
+       ((__bfa)->iocfc.hwif.hw_rspq_ack(__bfa, __queue, __ci))
 #define bfa_isr_reqq_ack(__bfa, __queue) do {                          \
        if ((__bfa)->iocfc.hwif.hw_reqq_ack)                            \
                (__bfa)->iocfc.hwif.hw_reqq_ack(__bfa, __queue);        \
@@ -311,7 +316,7 @@ void bfa_msix_rspq(struct bfa_s *bfa, int vec);
 void bfa_msix_lpu_err(struct bfa_s *bfa, int vec);
 
 void bfa_hwcb_reginit(struct bfa_s *bfa);
-void bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq);
+void bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq, u32 ci);
 void bfa_hwcb_msix_init(struct bfa_s *bfa, int nvecs);
 void bfa_hwcb_msix_ctrl_install(struct bfa_s *bfa);
 void bfa_hwcb_msix_queue_install(struct bfa_s *bfa);
@@ -324,7 +329,8 @@ void bfa_hwcb_msix_get_rme_range(struct bfa_s *bfa, u32 *start,
 void bfa_hwct_reginit(struct bfa_s *bfa);
 void bfa_hwct2_reginit(struct bfa_s *bfa);
 void bfa_hwct_reqq_ack(struct bfa_s *bfa, int rspq);
-void bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq);
+void bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq, u32 ci);
+void bfa_hwct2_rspq_ack(struct bfa_s *bfa, int rspq, u32 ci);
 void bfa_hwct_msix_init(struct bfa_s *bfa, int nvecs);
 void bfa_hwct_msix_ctrl_install(struct bfa_s *bfa);
 void bfa_hwct_msix_queue_install(struct bfa_s *bfa);
@@ -376,6 +382,22 @@ int bfa_iocfc_get_pbc_vports(struct bfa_s *bfa,
 #define bfa_get_fw_clock_res(__bfa)            \
        ((__bfa)->iocfc.cfgrsp->fwcfg.fw_tick_res)
 
+/*
+ * lun mask macros return NULL when min cfg is enabled and there is
+ * no memory allocated for lunmask.
+ */
+#define bfa_get_lun_mask(__bfa)                                        \
+       ((&(__bfa)->modules.dconf_mod)->min_cfg) ? NULL :       \
+        (&(BFA_DCONF_MOD(__bfa)->dconf->lun_mask))
+
+#define bfa_get_lun_mask_list(_bfa)                            \
+       ((&(_bfa)->modules.dconf_mod)->min_cfg) ? NULL :        \
+        (bfa_get_lun_mask(_bfa)->lun_list)
+
+#define bfa_get_lun_mask_status(_bfa)                          \
+       (((&(_bfa)->modules.dconf_mod)->min_cfg)                \
+        ? BFA_LUNMASK_MINCFG : ((bfa_get_lun_mask(_bfa))->status))
+
 void bfa_get_pciids(struct bfa_pciid_s **pciids, int *npciids);
 void bfa_cfg_get_default(struct bfa_iocfc_cfg_s *cfg);
 void bfa_cfg_get_min(struct bfa_iocfc_cfg_s *cfg);
@@ -406,7 +428,22 @@ bfa_status_t bfa_iocfc_israttr_set(struct bfa_s *bfa,
 
 void bfa_iocfc_enable(struct bfa_s *bfa);
 void bfa_iocfc_disable(struct bfa_s *bfa);
+void bfa_iocfc_cb_dconf_modinit(struct bfa_s *bfa, bfa_status_t status);
 #define bfa_timer_start(_bfa, _timer, _timercb, _arg, _timeout)                \
        bfa_timer_begin(&(_bfa)->timer_mod, _timer, _timercb, _arg, _timeout)
 
+struct bfa_cb_pending_q_s {
+       struct bfa_cb_qe_s      hcb_qe;
+       void                    *data;  /* Driver buffer */
+};
+
+/* Common macros to operate on pending stats/attr apis */
+#define bfa_pending_q_init(__qe, __cbfn, __cbarg, __data) do { \
+       bfa_q_qe_init(&((__qe)->hcb_qe.qe));                    \
+       (__qe)->hcb_qe.cbfn = (__cbfn);                         \
+       (__qe)->hcb_qe.cbarg = (__cbarg);                       \
+       (__qe)->hcb_qe.pre_rmv = BFA_TRUE;                      \
+       (__qe)->data = (__data);                                \
+} while (0)
+
 #endif /* __BFA_H__ */
index c38e589..4bd546b 100644 (file)
@@ -33,6 +33,7 @@ static struct bfa_module_s *hal_mods[] = {
        &hal_mod_uf,
        &hal_mod_rport,
        &hal_mod_fcp,
+       &hal_mod_dconf,
        NULL
 };
 
@@ -237,8 +238,6 @@ bfa_isr_rspq(struct bfa_s *bfa, int qid)
        u32     pi, ci;
        struct list_head *waitq;
 
-       bfa_isr_rspq_ack(bfa, qid);
-
        ci = bfa_rspq_ci(bfa, qid);
        pi = bfa_rspq_pi(bfa, qid);
 
@@ -251,11 +250,9 @@ bfa_isr_rspq(struct bfa_s *bfa, int qid)
        }
 
        /*
-        * update CI
+        * acknowledge RME completions and update CI
         */
-       bfa_rspq_ci(bfa, qid) = pi;
-       writel(pi, bfa->iocfc.bfa_regs.rme_q_ci[qid]);
-       mmiowb();
+       bfa_isr_rspq_ack(bfa, qid, ci);
 
        /*
         * Resume any pending requests in the corresponding reqq.
@@ -325,23 +322,19 @@ bfa_intx(struct bfa_s *bfa)
        int queue;
 
        intr = readl(bfa->iocfc.bfa_regs.intr_status);
-       if (!intr)
-               return BFA_FALSE;
 
        qintr = intr & (__HFN_INT_RME_MASK | __HFN_INT_CPE_MASK);
        if (qintr)
                writel(qintr, bfa->iocfc.bfa_regs.intr_status);
 
        /*
-        * RME completion queue interrupt
+        * Unconditional RME completion queue interrupt
         */
-       qintr = intr & __HFN_INT_RME_MASK;
-       if (qintr && bfa->queue_process) {
+       if (bfa->queue_process) {
                for (queue = 0; queue < BFI_IOC_MAX_CQS; queue++)
                        bfa_isr_rspq(bfa, queue);
        }
 
-       intr &= ~qintr;
        if (!intr)
                return BFA_TRUE;
 
@@ -432,7 +425,8 @@ bfa_msix_lpu_err(struct bfa_s *bfa, int vec)
                                   __HFN_INT_MBOX_LPU1_CT2);
                intr    &= __HFN_INT_ERR_MASK_CT2;
        } else {
-               halt_isr = intr & __HFN_INT_LL_HALT;
+               halt_isr = bfa_asic_id_ct(bfa->ioc.pcidev.device_id) ?
+                                         (intr & __HFN_INT_LL_HALT) : 0;
                pss_isr  = intr & __HFN_INT_ERR_PSS;
                lpu_isr  = intr & (__HFN_INT_MBOX_LPU0 | __HFN_INT_MBOX_LPU1);
                intr    &= __HFN_INT_ERR_MASK;
@@ -578,7 +572,7 @@ bfa_iocfc_init_mem(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
        } else {
                iocfc->hwif.hw_reginit = bfa_hwcb_reginit;
                iocfc->hwif.hw_reqq_ack = NULL;
-               iocfc->hwif.hw_rspq_ack = NULL;
+               iocfc->hwif.hw_rspq_ack = bfa_hwcb_rspq_ack;
                iocfc->hwif.hw_msix_init = bfa_hwcb_msix_init;
                iocfc->hwif.hw_msix_ctrl_install = bfa_hwcb_msix_ctrl_install;
                iocfc->hwif.hw_msix_queue_install = bfa_hwcb_msix_queue_install;
@@ -595,7 +589,7 @@ bfa_iocfc_init_mem(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
        if (bfa_asic_id_ct2(bfa_ioc_devid(&bfa->ioc))) {
                iocfc->hwif.hw_reginit = bfa_hwct2_reginit;
                iocfc->hwif.hw_isr_mode_set = NULL;
-               iocfc->hwif.hw_rspq_ack = NULL;
+               iocfc->hwif.hw_rspq_ack = bfa_hwct2_rspq_ack;
        }
 
        iocfc->hwif.hw_reginit(bfa);
@@ -685,7 +679,7 @@ bfa_iocfc_start_submod(struct bfa_s *bfa)
 
        bfa->queue_process = BFA_TRUE;
        for (i = 0; i < BFI_IOC_MAX_CQS; i++)
-               bfa_isr_rspq_ack(bfa, i);
+               bfa_isr_rspq_ack(bfa, i, bfa_rspq_ci(bfa, i));
 
        for (i = 0; hal_mods[i]; i++)
                hal_mods[i]->start(bfa);
@@ -709,7 +703,7 @@ bfa_iocfc_init_cb(void *bfa_arg, bfa_boolean_t complete)
        struct bfa_s    *bfa = bfa_arg;
 
        if (complete) {
-               if (bfa->iocfc.cfgdone)
+               if (bfa->iocfc.cfgdone && BFA_DCONF_MOD(bfa)->flashdone)
                        bfa_cb_init(bfa->bfad, BFA_STATUS_OK);
                else
                        bfa_cb_init(bfa->bfad, BFA_STATUS_FAILED);
@@ -822,9 +816,11 @@ bfa_iocfc_cfgrsp(struct bfa_s *bfa)
         */
        bfa_fcport_init(bfa);
 
-       if (iocfc->action == BFA_IOCFC_ACT_INIT)
-               bfa_cb_queue(bfa, &iocfc->init_hcb_qe, bfa_iocfc_init_cb, bfa);
-       else {
+       if (iocfc->action == BFA_IOCFC_ACT_INIT) {
+               if (BFA_DCONF_MOD(bfa)->flashdone == BFA_TRUE)
+                       bfa_cb_queue(bfa, &iocfc->init_hcb_qe,
+                               bfa_iocfc_init_cb, bfa);
+       } else {
                if (bfa->iocfc.action == BFA_IOCFC_ACT_ENABLE)
                        bfa_cb_queue(bfa, &bfa->iocfc.en_hcb_qe,
                                        bfa_iocfc_enable_cb, bfa);
@@ -1045,6 +1041,7 @@ bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status)
        }
 
        bfa_iocfc_send_cfg(bfa);
+       bfa_dconf_modinit(bfa);
 }
 
 /*
@@ -1207,7 +1204,9 @@ bfa_iocfc_stop(struct bfa_s *bfa)
        bfa->iocfc.action = BFA_IOCFC_ACT_STOP;
 
        bfa->queue_process = BFA_FALSE;
-       bfa_ioc_disable(&bfa->ioc);
+       bfa_dconf_modexit(bfa);
+       if (BFA_DCONF_MOD(bfa)->flashdone == BFA_TRUE)
+               bfa_ioc_disable(&bfa->ioc);
 }
 
 void
@@ -1540,10 +1539,17 @@ bfa_comp_process(struct bfa_s *bfa, struct list_head *comp_q)
        struct list_head                *qe;
        struct list_head                *qen;
        struct bfa_cb_qe_s      *hcb_qe;
+       bfa_cb_cbfn_status_t    cbfn;
 
        list_for_each_safe(qe, qen, comp_q) {
                hcb_qe = (struct bfa_cb_qe_s *) qe;
-               hcb_qe->cbfn(hcb_qe->cbarg, BFA_TRUE);
+               if (hcb_qe->pre_rmv) {
+                       /* qe is invalid after return, dequeue before cbfn() */
+                       list_del(qe);
+                       cbfn = (bfa_cb_cbfn_status_t)(hcb_qe->cbfn);
+                       cbfn(hcb_qe->cbarg, hcb_qe->fw_status);
+               } else
+                       hcb_qe->cbfn(hcb_qe->cbarg, BFA_TRUE);
        }
 }
 
@@ -1556,10 +1562,20 @@ bfa_comp_free(struct bfa_s *bfa, struct list_head *comp_q)
        while (!list_empty(comp_q)) {
                bfa_q_deq(comp_q, &qe);
                hcb_qe = (struct bfa_cb_qe_s *) qe;
+               WARN_ON(hcb_qe->pre_rmv);
                hcb_qe->cbfn(hcb_qe->cbarg, BFA_FALSE);
        }
 }
 
+void
+bfa_iocfc_cb_dconf_modinit(struct bfa_s *bfa, bfa_status_t status)
+{
+       if (bfa->iocfc.action == BFA_IOCFC_ACT_INIT) {
+               if (bfa->iocfc.cfgdone == BFA_TRUE)
+                       bfa_cb_queue(bfa, &bfa->iocfc.init_hcb_qe,
+                               bfa_iocfc_init_cb, bfa);
+       }
+}
 
 /*
  * Return the list of PCI vendor/device id lists supported by this
index ed8d31b..7b3d235 100644 (file)
@@ -144,6 +144,7 @@ enum bfa_status {
        BFA_STATUS_INVLD_DFSZ   = 24,   /*  Invalid Max data field size */
        BFA_STATUS_CMD_NOTSUPP  = 26,   /*  Command/API not supported */
        BFA_STATUS_FABRIC_RJT   = 29,   /*  Reject from attached fabric */
+       BFA_STATUS_UNKNOWN_VWWN = 30,   /*  VPORT PWWN not found */
        BFA_STATUS_PORT_OFFLINE = 34,   /*  Port is not online */
        BFA_STATUS_VPORT_WWN_BP = 46,   /*  WWN is same as base port's WWN */
        BFA_STATUS_PORT_NOT_DISABLED = 47, /* Port not disabled disable port */
@@ -164,6 +165,8 @@ enum bfa_status {
        BFA_STATUS_INVALID_MAC  = 134, /*  Invalid MAC address */
        BFA_STATUS_PBC          = 154, /*  Operation not allowed for pre-boot
                                        *  configuration */
+       BFA_STATUS_BAD_FWCFG = 156,     /* Bad firmware configuration */
+       BFA_STATUS_INVALID_VENDOR = 158, /* Invalid switch vendor */
        BFA_STATUS_SFP_NOT_READY = 159, /* SFP info is not ready. Retry */
        BFA_STATUS_TRUNK_ENABLED = 164, /* Trunk is already enabled on
                                         * this adapter */
@@ -172,11 +175,15 @@ enum bfa_status {
        BFA_STATUS_IOPROFILE_OFF = 175, /* IO profile OFF */
        BFA_STATUS_PHY_NOT_PRESENT = 183, /* PHY module not present */
        BFA_STATUS_FEATURE_NOT_SUPPORTED = 192, /* Feature not supported */
+       BFA_STATUS_ENTRY_EXISTS = 193,  /* Entry already exists */
+       BFA_STATUS_ENTRY_NOT_EXISTS = 194, /* Entry does not exist */
+       BFA_STATUS_NO_CHANGE = 195,     /* Feature already in that state */
        BFA_STATUS_FAA_ENABLED = 197,   /* FAA is already enabled */
        BFA_STATUS_FAA_DISABLED = 198,  /* FAA is already disabled */
        BFA_STATUS_FAA_ACQUIRED = 199,  /* FAA is already acquired */
        BFA_STATUS_FAA_ACQ_ADDR = 200,  /* Acquiring addr */
        BFA_STATUS_ERROR_TRUNK_ENABLED = 203,   /* Trunk enabled on adapter */
+       BFA_STATUS_MAX_ENTRY_REACHED = 212,     /* MAX entry reached */
        BFA_STATUS_MAX_VAL              /* Unknown error code */
 };
 #define bfa_status_t enum bfa_status
@@ -358,6 +365,139 @@ struct bfa_ioc_attr_s {
        u8                              rsvd[4];        /*  64bit align */
 };
 
+/*
+ *                     AEN related definitions
+ */
+enum bfa_aen_category {
+       BFA_AEN_CAT_ADAPTER     = 1,
+       BFA_AEN_CAT_PORT        = 2,
+       BFA_AEN_CAT_LPORT       = 3,
+       BFA_AEN_CAT_RPORT       = 4,
+       BFA_AEN_CAT_ITNIM       = 5,
+       BFA_AEN_CAT_AUDIT       = 8,
+       BFA_AEN_CAT_IOC         = 9,
+};
+
+/* BFA adapter level events */
+enum bfa_adapter_aen_event {
+       BFA_ADAPTER_AEN_ADD     = 1,    /* New Adapter found event */
+       BFA_ADAPTER_AEN_REMOVE  = 2,    /* Adapter removed event */
+};
+
+struct bfa_adapter_aen_data_s {
+       char    serial_num[BFA_ADAPTER_SERIAL_NUM_LEN];
+       u32     nports; /* Number of NPorts */
+       wwn_t   pwwn;   /* WWN of one of its physical port */
+};
+
+/* BFA physical port Level events */
+enum bfa_port_aen_event {
+       BFA_PORT_AEN_ONLINE     = 1,    /* Physical Port online event */
+       BFA_PORT_AEN_OFFLINE    = 2,    /* Physical Port offline event */
+       BFA_PORT_AEN_RLIR       = 3,    /* RLIR event, not supported */
+       BFA_PORT_AEN_SFP_INSERT = 4,    /* SFP inserted event */
+       BFA_PORT_AEN_SFP_REMOVE = 5,    /* SFP removed event */
+       BFA_PORT_AEN_SFP_POM    = 6,    /* SFP POM event */
+       BFA_PORT_AEN_ENABLE     = 7,    /* Physical Port enable event */
+       BFA_PORT_AEN_DISABLE    = 8,    /* Physical Port disable event */
+       BFA_PORT_AEN_AUTH_ON    = 9,    /* Physical Port auth success event */
+       BFA_PORT_AEN_AUTH_OFF   = 10,   /* Physical Port auth fail event */
+       BFA_PORT_AEN_DISCONNECT = 11,   /* Physical Port disconnect event */
+       BFA_PORT_AEN_QOS_NEG    = 12,   /* Base Port QOS negotiation event */
+       BFA_PORT_AEN_FABRIC_NAME_CHANGE = 13, /* Fabric Name/WWN change */
+       BFA_PORT_AEN_SFP_ACCESS_ERROR   = 14, /* SFP read error event */
+       BFA_PORT_AEN_SFP_UNSUPPORT      = 15, /* Unsupported SFP event */
+};
+
+enum bfa_port_aen_sfp_pom {
+       BFA_PORT_AEN_SFP_POM_GREEN = 1, /* Normal */
+       BFA_PORT_AEN_SFP_POM_AMBER = 2, /* Warning */
+       BFA_PORT_AEN_SFP_POM_RED   = 3, /* Critical */
+       BFA_PORT_AEN_SFP_POM_MAX   = BFA_PORT_AEN_SFP_POM_RED
+};
+
+struct bfa_port_aen_data_s {
+       wwn_t           pwwn;           /* WWN of the physical port */
+       wwn_t           fwwn;           /* WWN of the fabric port */
+       u32             phy_port_num;   /* For SFP related events */
+       u16             ioc_type;
+       u16             level;          /* Only transitions will be informed */
+       mac_t           mac;            /* MAC address of the ethernet port */
+       u16             rsvd;
+};
+
+/* BFA AEN logical port events */
+enum bfa_lport_aen_event {
+       BFA_LPORT_AEN_NEW       = 1,            /* LPort created event */
+       BFA_LPORT_AEN_DELETE    = 2,            /* LPort deleted event */
+       BFA_LPORT_AEN_ONLINE    = 3,            /* LPort online event */
+       BFA_LPORT_AEN_OFFLINE   = 4,            /* LPort offline event */
+       BFA_LPORT_AEN_DISCONNECT = 5,           /* LPort disconnect event */
+       BFA_LPORT_AEN_NEW_PROP  = 6,            /* VPort created event */
+       BFA_LPORT_AEN_DELETE_PROP = 7,          /* VPort deleted event */
+       BFA_LPORT_AEN_NEW_STANDARD = 8,         /* VPort created event */
+       BFA_LPORT_AEN_DELETE_STANDARD = 9,      /* VPort deleted event */
+       BFA_LPORT_AEN_NPIV_DUP_WWN = 10,        /* VPort with duplicate WWN */
+       BFA_LPORT_AEN_NPIV_FABRIC_MAX = 11,     /* Max NPIV in fabric/fport */
+       BFA_LPORT_AEN_NPIV_UNKNOWN = 12,        /* Unknown NPIV Error code */
+};
+
+struct bfa_lport_aen_data_s {
+       u16     vf_id;  /* vf_id of this logical port */
+       u16     roles;  /* Logical port mode,IM/TM/IP etc */
+       u32     rsvd;
+       wwn_t   ppwwn;  /* WWN of its physical port */
+       wwn_t   lpwwn;  /* WWN of this logical port */
+};
+
+/* BFA ITNIM events */
+enum bfa_itnim_aen_event {
+       BFA_ITNIM_AEN_ONLINE     = 1,   /* Target online */
+       BFA_ITNIM_AEN_OFFLINE    = 2,   /* Target offline */
+       BFA_ITNIM_AEN_DISCONNECT = 3,   /* Target disconnected */
+};
+
+struct bfa_itnim_aen_data_s {
+       u16             vf_id;          /* vf_id of the IT nexus */
+       u16             rsvd[3];
+       wwn_t           ppwwn;          /* WWN of its physical port */
+       wwn_t           lpwwn;          /* WWN of logical port */
+       wwn_t           rpwwn;          /* WWN of remote(target) port */
+};
+
+/* BFA audit events */
+enum bfa_audit_aen_event {
+       BFA_AUDIT_AEN_AUTH_ENABLE       = 1,
+       BFA_AUDIT_AEN_AUTH_DISABLE      = 2,
+       BFA_AUDIT_AEN_FLASH_ERASE       = 3,
+       BFA_AUDIT_AEN_FLASH_UPDATE      = 4,
+};
+
+struct bfa_audit_aen_data_s {
+       wwn_t   pwwn;
+       int     partition_inst;
+       int     partition_type;
+};
+
+/* BFA IOC level events */
+enum bfa_ioc_aen_event {
+       BFA_IOC_AEN_HBGOOD  = 1,        /* Heart Beat restore event     */
+       BFA_IOC_AEN_HBFAIL  = 2,        /* Heart Beat failure event     */
+       BFA_IOC_AEN_ENABLE  = 3,        /* IOC enabled event            */
+       BFA_IOC_AEN_DISABLE = 4,        /* IOC disabled event           */
+       BFA_IOC_AEN_FWMISMATCH  = 5,    /* IOC firmware mismatch        */
+       BFA_IOC_AEN_FWCFG_ERROR = 6,    /* IOC firmware config error    */
+       BFA_IOC_AEN_INVALID_VENDOR = 7,
+       BFA_IOC_AEN_INVALID_NWWN = 8,   /* Zero NWWN                    */
+       BFA_IOC_AEN_INVALID_PWWN = 9    /* Zero PWWN                    */
+};
+
+struct bfa_ioc_aen_data_s {
+       wwn_t   pwwn;
+       u16     ioc_type;
+       mac_t   mac;
+};
+
 /*
  * ---------------------- mfg definitions ------------
  */
@@ -520,6 +660,20 @@ struct bfa_boot_bootlun_s {
 /*
  * BOOT boot configuraton
  */
+struct bfa_boot_cfg_s {
+       u8              version;
+       u8              rsvd1;
+       u16             chksum;
+       u8              enable;         /* enable/disable SAN boot */
+       u8              speed;          /* boot speed settings */
+       u8              topology;       /* boot topology setting */
+       u8              bootopt;        /* bfa_boot_bootopt_t */
+       u32             nbluns;         /* number of boot luns */
+       u32             rsvd2;
+       struct bfa_boot_bootlun_s blun[BFA_BOOT_BOOTLUN_MAX];
+       struct bfa_boot_bootlun_s blun_disc[BFA_BOOT_BOOTLUN_MAX];
+};
+
 struct bfa_boot_pbc_s {
        u8              enable;         /*  enable/disable SAN boot */
        u8              speed;          /*  boot speed settings */
@@ -529,6 +683,15 @@ struct bfa_boot_pbc_s {
        struct bfa_boot_bootlun_s pblun[BFA_PREBOOT_BOOTLUN_MAX];
 };
 
+struct bfa_ethboot_cfg_s {
+       u8              version;
+       u8              rsvd1;
+       u16             chksum;
+       u8              enable; /* enable/disable Eth/PXE boot */
+       u8              rsvd2;
+       u16             vlan;
+};
+
 /*
  * ASIC block configuration related structures
  */
@@ -587,6 +750,14 @@ struct bfa_ablk_cfg_s {
  */
 #define SFP_DIAGMON_SIZE       10 /* num bytes of diag monitor data */
 
+/* SFP state change notification event */
+#define BFA_SFP_SCN_REMOVED    0
+#define BFA_SFP_SCN_INSERTED   1
+#define BFA_SFP_SCN_POM                2
+#define BFA_SFP_SCN_FAILED     3
+#define BFA_SFP_SCN_UNSUPPORT  4
+#define BFA_SFP_SCN_VALID      5
+
 enum bfa_defs_sfp_media_e {
        BFA_SFP_MEDIA_UNKNOWN   = 0x00,
        BFA_SFP_MEDIA_CU        = 0x01,
index 0b97525..863c6ba 100644 (file)
@@ -268,6 +268,7 @@ struct bfa_fw_port_snsm_stats_s {
     u32    error_resets;       /*  error resets initiated by upsm      */
     u32    sync_lost;          /*  Sync loss count                     */
     u32    sig_lost;           /*  Signal loss count                   */
+       u32     asn8g_attempts; /* SNSM HWSM at 8Gbps attempts */
 };
 
 struct bfa_fw_port_physm_stats_s {
@@ -468,6 +469,7 @@ struct bfa_fw_stats_s {
  * QoS states
  */
 enum bfa_qos_state {
+       BFA_QOS_DISABLED = 0,           /* QoS is disabled */
        BFA_QOS_ONLINE = 1,             /*  QoS is online */
        BFA_QOS_OFFLINE = 2,            /*  QoS is offline */
 };
@@ -670,6 +672,12 @@ struct bfa_itnim_iostats_s {
        u32     tm_iocdowns;            /*  TM cleaned-up due to IOC down   */
        u32     tm_cleanups;            /*  TM cleanup requests */
        u32     tm_cleanup_comps;       /*  TM cleanup completions      */
+       u32     lm_lun_across_sg;       /*  LM lun is across sg data buf */
+       u32     lm_lun_not_sup;         /*  LM lun not supported */
+       u32     lm_rpl_data_changed;    /*  LM report-lun data changed */
+       u32     lm_wire_residue_changed; /* LM report-lun rsp residue changed */
+       u32     lm_small_buf_addresidue; /* LM buf smaller than reported cnt */
+       u32     lm_lun_not_rdy;         /* LM lun not ready */
 };
 
 /* Modify char* port_stt[] in bfal_port.c if a new state was added */
@@ -785,7 +793,50 @@ enum bfa_port_linkstate_rsn {
        CEE_ISCSI_PRI_PFC_OFF                   = 42,
        CEE_ISCSI_PRI_OVERLAP_FCOE_PRI          = 43
 };
+
+#define MAX_LUN_MASK_CFG 16
+
+/*
+ * Initially flash content may be fff. On making LUN mask enable and disable
+ * state chnage.  when report lun command is being processed it goes from
+ * BFA_LUN_MASK_ACTIVE to BFA_LUN_MASK_FETCH and comes back to
+ * BFA_LUN_MASK_ACTIVE.
+ */
+enum bfa_ioim_lun_mask_state_s {
+       BFA_IOIM_LUN_MASK_INACTIVE = 0,
+       BFA_IOIM_LUN_MASK_ACTIVE = 1,
+       BFA_IOIM_LUN_MASK_FETCHED = 2,
+};
+
+enum bfa_lunmask_state_s {
+       BFA_LUNMASK_DISABLED = 0x00,
+       BFA_LUNMASK_ENABLED = 0x01,
+       BFA_LUNMASK_MINCFG = 0x02,
+       BFA_LUNMASK_UNINITIALIZED = 0xff,
+};
+
 #pragma pack(1)
+/*
+ * LUN mask configuration
+ */
+struct bfa_lun_mask_s {
+       wwn_t           lp_wwn;
+       wwn_t           rp_wwn;
+       struct scsi_lun lun;
+       u8              ua;
+       u8              rsvd[3];
+       u16             rp_tag;
+       u8              lp_tag;
+       u8              state;
+};
+
+#define MAX_LUN_MASK_CFG 16
+struct bfa_lunmask_cfg_s {
+       u32     status;
+       u32     rsvd;
+       struct bfa_lun_mask_s   lun_list[MAX_LUN_MASK_CFG];
+};
+
 /*
  *      Physical port configuration
  */
@@ -1228,4 +1279,52 @@ struct bfa_cee_stats_s {
 
 #pragma pack()
 
+/*
+ *                     AEN related definitions
+ */
+#define BFAD_NL_VENDOR_ID (((u64)0x01 << SCSI_NL_VID_TYPE_SHIFT) \
+                          | BFA_PCI_VENDOR_ID_BROCADE)
+
+/* BFA remote port events */
+enum bfa_rport_aen_event {
+       BFA_RPORT_AEN_ONLINE     = 1,   /* RPort online event */
+       BFA_RPORT_AEN_OFFLINE    = 2,   /* RPort offline event */
+       BFA_RPORT_AEN_DISCONNECT = 3,   /* RPort disconnect event */
+       BFA_RPORT_AEN_QOS_PRIO   = 4,   /* QOS priority change event */
+       BFA_RPORT_AEN_QOS_FLOWID = 5,   /* QOS flow Id change event */
+};
+
+struct bfa_rport_aen_data_s {
+       u16             vf_id;  /* vf_id of this logical port */
+       u16             rsvd[3];
+       wwn_t           ppwwn;  /* WWN of its physical port */
+       wwn_t           lpwwn;  /* WWN of this logical port */
+       wwn_t           rpwwn;  /* WWN of this remote port */
+       union {
+               struct bfa_rport_qos_attr_s qos;
+       } priv;
+};
+
+union bfa_aen_data_u {
+       struct bfa_adapter_aen_data_s   adapter;
+       struct bfa_port_aen_data_s      port;
+       struct bfa_lport_aen_data_s     lport;
+       struct bfa_rport_aen_data_s     rport;
+       struct bfa_itnim_aen_data_s     itnim;
+       struct bfa_audit_aen_data_s     audit;
+       struct bfa_ioc_aen_data_s       ioc;
+};
+
+#define BFA_AEN_MAX_ENTRY      512
+
+struct bfa_aen_entry_s {
+       struct list_head        qe;
+       enum bfa_aen_category   aen_category;
+       u32                     aen_type;
+       union bfa_aen_data_u    aen_data;
+       struct timeval          aen_tv;
+       u32                     seq_num;
+       u32                     bfad_num;
+};
+
 #endif /* __BFA_DEFS_SVC_H__ */
index 8d0b88f..50b6a1c 100644 (file)
@@ -56,6 +56,161 @@ struct scsi_cdb_s {
 
 #define SCSI_MAX_ALLOC_LEN      0xFF    /* maximum allocarion length */
 
+#define SCSI_SENSE_CUR_ERR     0x70
+#define SCSI_SENSE_DEF_ERR     0x71
+
+/*
+ * SCSI additional sense codes
+ */
+#define SCSI_ASC_LUN_NOT_READY         0x04
+#define SCSI_ASC_LUN_NOT_SUPPORTED     0x25
+#define SCSI_ASC_TOCC                  0x3F
+
+/*
+ * SCSI additional sense code qualifiers
+ */
+#define SCSI_ASCQ_MAN_INTR_REQ         0x03    /* manual intervention req */
+#define SCSI_ASCQ_RL_DATA_CHANGED      0x0E    /* report luns data changed */
+
+/*
+ * Methods of reporting informational exceptions
+ */
+#define SCSI_MP_IEC_UNIT_ATTN          0x2     /* generate unit attention */
+
+struct scsi_report_luns_data_s {
+       u32             lun_list_length;        /* length of LUN list length */
+       u32             reserved;
+       struct scsi_lun lun[1];                 /* first LUN in lun list */
+};
+
+struct scsi_inquiry_vendor_s {
+       u8      vendor_id[8];
+};
+
+struct scsi_inquiry_prodid_s {
+       u8      product_id[16];
+};
+
+struct scsi_inquiry_prodrev_s {
+       u8      product_rev[4];
+};
+
+struct scsi_inquiry_data_s {
+#ifdef __BIG_ENDIAN
+       u8              peripheral_qual:3;      /* peripheral qualifier */
+       u8              device_type:5;          /* peripheral device type */
+       u8              rmb:1;                  /* removable medium bit */
+       u8              device_type_mod:7;      /* device type modifier */
+       u8              version;
+       u8              aenc:1;         /* async evt notification capability */
+       u8              trm_iop:1;      /* terminate I/O process */
+       u8              norm_aca:1;     /* normal ACA supported */
+       u8              hi_support:1;   /* SCSI-3: supports REPORT LUNS */
+       u8              rsp_data_format:4;
+       u8              additional_len;
+       u8              sccs:1;
+       u8              reserved1:7;
+       u8              reserved2:1;
+       u8              enc_serv:1;     /* enclosure service component */
+       u8              reserved3:1;
+       u8              multi_port:1;   /* multi-port device */
+       u8              m_chngr:1;      /* device in medium transport element */
+       u8              ack_req_q:1;    /* SIP specific bit */
+       u8              addr32:1;       /* SIP specific bit */
+       u8              addr16:1;       /* SIP specific bit */
+       u8              rel_adr:1;      /* relative address */
+       u8              w_bus32:1;
+       u8              w_bus16:1;
+       u8              synchronous:1;
+       u8              linked_commands:1;
+       u8              trans_dis:1;
+       u8              cmd_queue:1;    /* command queueing supported */
+       u8              soft_reset:1;   /* soft reset alternative (VS) */
+#else
+       u8              device_type:5;  /* peripheral device type */
+       u8              peripheral_qual:3; /* peripheral qualifier */
+       u8              device_type_mod:7; /* device type modifier */
+       u8              rmb:1;          /* removable medium bit */
+       u8              version;
+       u8              rsp_data_format:4;
+       u8              hi_support:1;   /* SCSI-3: supports REPORT LUNS */
+       u8              norm_aca:1;     /* normal ACA supported */
+       u8              terminate_iop:1;/* terminate I/O process */
+       u8              aenc:1;         /* async evt notification capability */
+       u8              additional_len;
+       u8              reserved1:7;
+       u8              sccs:1;
+       u8              addr16:1;       /* SIP specific bit */
+       u8              addr32:1;       /* SIP specific bit */
+       u8              ack_req_q:1;    /* SIP specific bit */
+       u8              m_chngr:1;      /* device in medium transport element */
+       u8              multi_port:1;   /* multi-port device */
+       u8              reserved3:1;    /* TBD - Vendor Specific */
+       u8              enc_serv:1;     /* enclosure service component */
+       u8              reserved2:1;
+       u8              soft_seset:1;   /* soft reset alternative (VS) */
+       u8              cmd_queue:1;    /* command queueing supported */
+       u8              trans_dis:1;
+       u8              linked_commands:1;
+       u8              synchronous:1;
+       u8              w_bus16:1;
+       u8              w_bus32:1;
+       u8              rel_adr:1;      /* relative address */
+#endif
+       struct scsi_inquiry_vendor_s    vendor_id;
+       struct scsi_inquiry_prodid_s    product_id;
+       struct scsi_inquiry_prodrev_s   product_rev;
+       u8              vendor_specific[20];
+       u8              reserved4[40];
+};
+
+/*
+ *     SCSI sense data format
+ */
+struct scsi_sense_s {
+#ifdef __BIG_ENDIAN
+       u8              valid:1;
+       u8              rsp_code:7;
+#else
+       u8              rsp_code:7;
+       u8              valid:1;
+#endif
+       u8              seg_num;
+#ifdef __BIG_ENDIAN
+       u8              file_mark:1;
+       u8              eom:1;          /* end of media */
+       u8              ili:1;          /* incorrect length indicator */
+       u8              reserved:1;
+       u8              sense_key:4;
+#else
+       u8              sense_key:4;
+       u8              reserved:1;
+       u8              ili:1;          /* incorrect length indicator */
+       u8              eom:1;          /* end of media */
+       u8              file_mark:1;
+#endif
+       u8              information[4]; /* device-type or cmd specific info */
+       u8              add_sense_length; /* additional sense length */
+       u8              command_info[4];/* command specific information */
+       u8              asc;            /* additional sense code */
+       u8              ascq;           /* additional sense code qualifier */
+       u8              fru_code;       /* field replaceable unit code */
+#ifdef __BIG_ENDIAN
+       u8              sksv:1;         /* sense key specific valid */
+       u8              c_d:1;          /* command/data bit */
+       u8              res1:2;
+       u8              bpv:1;          /* bit pointer valid */
+       u8              bpointer:3;     /* bit pointer */
+#else
+       u8              bpointer:3;     /* bit pointer */
+       u8              bpv:1;          /* bit pointer valid */
+       u8              res1:2;
+       u8              c_d:1;          /* command/data bit */
+       u8              sksv:1;         /* sense key specific valid */
+#endif
+       u8              fpointer[2];    /* field pointer */
+};
+
 /*
  * Fibre Channel Header Structure (FCHS) definition
  */
index a4e7951..e07bd47 100644 (file)
@@ -24,6 +24,9 @@ BFA_TRC_FILE(HAL, FCPIM);
  *  BFA ITNIM Related definitions
  */
 static void bfa_itnim_update_del_itn_stats(struct bfa_itnim_s *itnim);
+static bfa_boolean_t bfa_ioim_lm_proc_rpl_data(struct bfa_ioim_s *ioim);
+static bfa_boolean_t bfa_ioim_lm_proc_inq_data(struct bfa_ioim_s *ioim);
+static void bfa_ioim_lm_init(struct bfa_s *bfa);
 
 #define BFA_ITNIM_FROM_TAG(_fcpim, _tag)                                \
        (((_fcpim)->itnim_arr + ((_tag) & ((_fcpim)->num_itnims - 1))))
@@ -57,6 +60,14 @@ static void bfa_itnim_update_del_itn_stats(struct bfa_itnim_s *itnim);
        }                                                               \
 } while (0)
 
+#define bfa_ioim_rp_wwn(__ioim)                                                \
+       (((struct bfa_fcs_rport_s *)                                    \
+        (__ioim)->itnim->rport->rport_drv)->pwwn)
+
+#define bfa_ioim_lp_wwn(__ioim)                                                \
+       ((BFA_LPS_FROM_TAG(BFA_LPS_MOD((__ioim)->bfa),                  \
+       (__ioim)->itnim->rport->rport_info.lp_tag))->pwwn)              \
+
 #define bfa_itnim_sler_cb(__itnim) do {                                        \
        if ((__itnim)->bfa->fcs)                                        \
                bfa_cb_itnim_sler((__itnim)->ditn);      \
@@ -66,6 +77,18 @@ static void bfa_itnim_update_del_itn_stats(struct bfa_itnim_s *itnim);
        }                                                               \
 } while (0)
 
+enum bfa_ioim_lm_status {
+       BFA_IOIM_LM_PRESENT = 1,
+       BFA_IOIM_LM_LUN_NOT_SUP = 2,
+       BFA_IOIM_LM_RPL_DATA_CHANGED = 3,
+       BFA_IOIM_LM_LUN_NOT_RDY = 4,
+};
+
+enum bfa_ioim_lm_ua_status {
+       BFA_IOIM_LM_UA_RESET = 0,
+       BFA_IOIM_LM_UA_SET = 1,
+};
+
 /*
  *  itnim state machine event
  */
@@ -122,6 +145,9 @@ enum bfa_ioim_event {
        BFA_IOIM_SM_TMDONE      = 16,   /*  IO cleanup from tskim */
        BFA_IOIM_SM_HWFAIL      = 17,   /*  IOC h/w failure event */
        BFA_IOIM_SM_IOTOV       = 18,   /*  ITN offline TOV */
+       BFA_IOIM_SM_LM_LUN_NOT_SUP = 19,/*  lunmask lun not supported */
+       BFA_IOIM_SM_LM_RPL_DC = 20,     /*  lunmask report-lun data changed */
+       BFA_IOIM_SM_LM_LUN_NOT_RDY = 21,/*  lunmask lun not ready */
 };
 
 
@@ -219,6 +245,9 @@ static void __bfa_cb_ioim_abort(void *cbarg, bfa_boolean_t complete);
 static void __bfa_cb_ioim_failed(void *cbarg, bfa_boolean_t complete);
 static void __bfa_cb_ioim_pathtov(void *cbarg, bfa_boolean_t complete);
 static bfa_boolean_t    bfa_ioim_is_abortable(struct bfa_ioim_s *ioim);
+static void __bfa_cb_ioim_lm_lun_not_sup(void *cbarg, bfa_boolean_t complete);
+static void __bfa_cb_ioim_lm_rpl_dc(void *cbarg, bfa_boolean_t complete);
+static void __bfa_cb_ioim_lm_lun_not_rdy(void *cbarg, bfa_boolean_t complete);
 
 /*
  * forward declaration of BFA IO state machine
@@ -416,6 +445,12 @@ bfa_fcpim_add_stats(struct bfa_itnim_iostats_s *lstats,
        bfa_fcpim_add_iostats(lstats, rstats, output_reqs);
        bfa_fcpim_add_iostats(lstats, rstats, rd_throughput);
        bfa_fcpim_add_iostats(lstats, rstats, wr_throughput);
+       bfa_fcpim_add_iostats(lstats, rstats, lm_lun_across_sg);
+       bfa_fcpim_add_iostats(lstats, rstats, lm_lun_not_sup);
+       bfa_fcpim_add_iostats(lstats, rstats, lm_rpl_data_changed);
+       bfa_fcpim_add_iostats(lstats, rstats, lm_wire_residue_changed);
+       bfa_fcpim_add_iostats(lstats, rstats, lm_small_buf_addresidue);
+       bfa_fcpim_add_iostats(lstats, rstats, lm_lun_not_rdy);
 }
 
 bfa_status_t
@@ -437,6 +472,59 @@ bfa_fcpim_port_iostats(struct bfa_s *bfa,
        return BFA_STATUS_OK;
 }
 
+void
+bfa_ioim_profile_comp(struct bfa_ioim_s *ioim)
+{
+       struct bfa_itnim_latency_s *io_lat =
+                       &(ioim->itnim->ioprofile.io_latency);
+       u32 val, idx;
+
+       val = (u32)(jiffies - ioim->start_time);
+       idx = bfa_ioim_get_index(scsi_bufflen((struct scsi_cmnd *)ioim->dio));
+       bfa_itnim_ioprofile_update(ioim->itnim, idx);
+
+       io_lat->count[idx]++;
+       io_lat->min[idx] = (io_lat->min[idx] < val) ? io_lat->min[idx] : val;
+       io_lat->max[idx] = (io_lat->max[idx] > val) ? io_lat->max[idx] : val;
+       io_lat->avg[idx] += val;
+}
+
+void
+bfa_ioim_profile_start(struct bfa_ioim_s *ioim)
+{
+       ioim->start_time = jiffies;
+}
+
+bfa_status_t
+bfa_fcpim_profile_on(struct bfa_s *bfa, u32 time)
+{
+       struct bfa_itnim_s *itnim;
+       struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa);
+       struct list_head *qe, *qen;
+
+       /* accumulate IO stats from itnim */
+       list_for_each_safe(qe, qen, &fcpim->itnim_q) {
+               itnim = (struct bfa_itnim_s *) qe;
+               bfa_itnim_clear_stats(itnim);
+       }
+       fcpim->io_profile = BFA_TRUE;
+       fcpim->io_profile_start_time = time;
+       fcpim->profile_comp = bfa_ioim_profile_comp;
+       fcpim->profile_start = bfa_ioim_profile_start;
+       return BFA_STATUS_OK;
+}
+
+bfa_status_t
+bfa_fcpim_profile_off(struct bfa_s *bfa)
+{
+       struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa);
+       fcpim->io_profile = BFA_FALSE;
+       fcpim->io_profile_start_time = 0;
+       fcpim->profile_comp = NULL;
+       fcpim->profile_start = NULL;
+       return BFA_STATUS_OK;
+}
+
 u16
 bfa_fcpim_qdepth_get(struct bfa_s *bfa)
 {
@@ -1401,6 +1489,26 @@ bfa_itnim_hold_io(struct bfa_itnim_s *itnim)
                 bfa_sm_cmp_state(itnim, bfa_itnim_sm_iocdisable));
 }
 
+#define bfa_io_lat_clock_res_div       HZ
+#define bfa_io_lat_clock_res_mul       1000
+bfa_status_t
+bfa_itnim_get_ioprofile(struct bfa_itnim_s *itnim,
+                       struct bfa_itnim_ioprofile_s *ioprofile)
+{
+       struct bfa_fcpim_s *fcpim = BFA_FCPIM(itnim->bfa);
+       if (!fcpim->io_profile)
+               return BFA_STATUS_IOPROFILE_OFF;
+
+       itnim->ioprofile.index = BFA_IOBUCKET_MAX;
+       itnim->ioprofile.io_profile_start_time =
+                               bfa_io_profile_start_time(itnim->bfa);
+       itnim->ioprofile.clock_res_mul = bfa_io_lat_clock_res_mul;
+       itnim->ioprofile.clock_res_div = bfa_io_lat_clock_res_div;
+       *ioprofile = itnim->ioprofile;
+
+       return BFA_STATUS_OK;
+}
+
 void
 bfa_itnim_clear_stats(struct bfa_itnim_s *itnim)
 {
@@ -1469,7 +1577,28 @@ bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
                bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
                WARN_ON(!bfa_q_is_on_q(&ioim->itnim->pending_q, ioim));
                bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
-                               __bfa_cb_ioim_abort, ioim);
+                       __bfa_cb_ioim_abort, ioim);
+               break;
+
+       case BFA_IOIM_SM_LM_LUN_NOT_SUP:
+               bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+               bfa_ioim_move_to_comp_q(ioim);
+               bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
+                       __bfa_cb_ioim_lm_lun_not_sup, ioim);
+               break;
+
+       case BFA_IOIM_SM_LM_RPL_DC:
+               bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+               bfa_ioim_move_to_comp_q(ioim);
+               bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
+                               __bfa_cb_ioim_lm_rpl_dc, ioim);
+               break;
+
+       case BFA_IOIM_SM_LM_LUN_NOT_RDY:
+               bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+               bfa_ioim_move_to_comp_q(ioim);
+               bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
+                       __bfa_cb_ioim_lm_lun_not_rdy, ioim);
                break;
 
        default:
@@ -2009,6 +2138,264 @@ bfa_ioim_sm_resfree(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
        }
 }
 
+/*
+ * This is called from bfa_fcpim_start after the bfa_init() with flash read
+ * is complete by driver. now invalidate the stale content of lun mask
+ * like unit attention, rp tag and lp tag.
+ */
+static void
+bfa_ioim_lm_init(struct bfa_s *bfa)
+{
+       struct bfa_lun_mask_s *lunm_list;
+       int     i;
+
+       if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_MINCFG)
+               return;
+
+       lunm_list = bfa_get_lun_mask_list(bfa);
+       for (i = 0; i < MAX_LUN_MASK_CFG; i++) {
+               lunm_list[i].ua = BFA_IOIM_LM_UA_RESET;
+               lunm_list[i].lp_tag = BFA_LP_TAG_INVALID;
+               lunm_list[i].rp_tag = BFA_RPORT_TAG_INVALID;
+       }
+}
+
+/*
+ * Validate LUN for LUN masking
+ */
+static enum bfa_ioim_lm_status
+bfa_ioim_lm_check(struct bfa_ioim_s *ioim, struct bfa_lps_s *lps,
+               struct bfa_rport_s *rp, struct scsi_lun lun)
+{
+       u8 i;
+       struct bfa_lun_mask_s *lun_list = bfa_get_lun_mask_list(ioim->bfa);
+       struct scsi_cmnd *cmnd = (struct scsi_cmnd *)ioim->dio;
+       struct scsi_cdb_s *cdb = (struct scsi_cdb_s *)cmnd->cmnd;
+
+       if ((cdb->scsi_cdb[0] == REPORT_LUNS) &&
+           (scsilun_to_int((struct scsi_lun *)&lun) == 0)) {
+               ioim->proc_rsp_data = bfa_ioim_lm_proc_rpl_data;
+               return BFA_IOIM_LM_PRESENT;
+       }
+
+       for (i = 0; i < MAX_LUN_MASK_CFG; i++) {
+
+               if (lun_list[i].state != BFA_IOIM_LUN_MASK_ACTIVE)
+                       continue;
+
+               if ((scsilun_to_int((struct scsi_lun *)&lun_list[i].lun) ==
+                   scsilun_to_int((struct scsi_lun *)&lun))
+                   && (rp->rport_tag == lun_list[i].rp_tag)
+                   && ((u8)ioim->itnim->rport->rport_info.lp_tag ==
+                                               lun_list[i].lp_tag)) {
+                       bfa_trc(ioim->bfa, lun_list[i].rp_tag);
+                       bfa_trc(ioim->bfa, lun_list[i].lp_tag);
+                       bfa_trc(ioim->bfa, scsilun_to_int(
+                               (struct scsi_lun *)&lun_list[i].lun));
+
+                       if ((lun_list[i].ua == BFA_IOIM_LM_UA_SET) &&
+                           ((cdb->scsi_cdb[0] != INQUIRY) ||
+                           (cdb->scsi_cdb[0] != REPORT_LUNS))) {
+                               lun_list[i].ua = BFA_IOIM_LM_UA_RESET;
+                               return BFA_IOIM_LM_RPL_DATA_CHANGED;
+                       }
+
+                       if (cdb->scsi_cdb[0] == REPORT_LUNS)
+                               ioim->proc_rsp_data = bfa_ioim_lm_proc_rpl_data;
+
+                       return BFA_IOIM_LM_PRESENT;
+               }
+       }
+
+       if ((cdb->scsi_cdb[0] == INQUIRY) &&
+           (scsilun_to_int((struct scsi_lun *)&lun) == 0)) {
+               ioim->proc_rsp_data = bfa_ioim_lm_proc_inq_data;
+               return BFA_IOIM_LM_PRESENT;
+       }
+
+       if (cdb->scsi_cdb[0] == TEST_UNIT_READY)
+               return BFA_IOIM_LM_LUN_NOT_RDY;
+
+       return BFA_IOIM_LM_LUN_NOT_SUP;
+}
+
+static bfa_boolean_t
+bfa_ioim_lm_proc_rsp_data_dummy(struct bfa_ioim_s *ioim)
+{
+       return BFA_TRUE;
+}
+
+static void
+bfa_ioim_lm_fetch_lun(struct bfa_ioim_s *ioim, u8 *rl_data, int offset,
+               int buf_lun_cnt)
+{
+       struct bfa_lun_mask_s *lun_list = bfa_get_lun_mask_list(ioim->bfa);
+       struct scsi_lun *lun_data = (struct scsi_lun *)(rl_data + offset);
+       struct scsi_lun lun;
+       int i, j;
+
+       bfa_trc(ioim->bfa, buf_lun_cnt);
+       for (j = 0; j < buf_lun_cnt; j++) {
+               lun = *((struct scsi_lun *)(lun_data + j));
+               for (i = 0; i < MAX_LUN_MASK_CFG; i++) {
+                       if (lun_list[i].state != BFA_IOIM_LUN_MASK_ACTIVE)
+                               continue;
+                       if ((lun_list[i].rp_wwn == bfa_ioim_rp_wwn(ioim)) &&
+                           (lun_list[i].lp_wwn == bfa_ioim_lp_wwn(ioim)) &&
+                           (scsilun_to_int((struct scsi_lun *)&lun_list[i].lun)
+                               == scsilun_to_int((struct scsi_lun *)&lun))) {
+                               lun_list[i].state = BFA_IOIM_LUN_MASK_FETCHED;
+                               break;
+                       }
+               } /* next lun in mask DB */
+       } /* next lun in buf */
+}
+
+static int
+bfa_ioim_lm_update_lun_sg(struct bfa_ioim_s *ioim, u32 *pgdlen,
+               struct scsi_report_luns_data_s *rl)
+{
+       struct scsi_cmnd *cmnd = (struct scsi_cmnd *)ioim->dio;
+       struct scatterlist *sg = scsi_sglist(cmnd);
+       struct bfa_lun_mask_s *lun_list = bfa_get_lun_mask_list(ioim->bfa);
+       struct scsi_lun *prev_rl_data = NULL, *base_rl_data;
+       int i, j, sgeid, lun_fetched_cnt = 0, prev_sg_len = 0, base_count;
+       int lun_across_sg_bytes, bytes_from_next_buf;
+       u64     last_lun, temp_last_lun;
+
+       /* fetch luns from the first sg element */
+       bfa_ioim_lm_fetch_lun(ioim, (u8 *)(rl->lun), 0,
+                       (sg_dma_len(sg) / sizeof(struct scsi_lun)) - 1);
+
+       /* fetch luns from multiple sg elements */
+       scsi_for_each_sg(cmnd, sg, scsi_sg_count(cmnd), sgeid) {
+               if (sgeid == 0) {
+                       prev_sg_len = sg_dma_len(sg);
+                       prev_rl_data = (struct scsi_lun *)
+                                       phys_to_virt(sg_dma_address(sg));
+                       continue;
+               }
+
+               /* if the buf is having more data */
+               lun_across_sg_bytes = prev_sg_len % sizeof(struct scsi_lun);
+               if (lun_across_sg_bytes) {
+                       bfa_trc(ioim->bfa, lun_across_sg_bytes);
+                       bfa_stats(ioim->itnim, lm_lun_across_sg);
+                       bytes_from_next_buf = sizeof(struct scsi_lun) -
+                                             lun_across_sg_bytes;
+
+                       /* from next buf take higher bytes */
+                       temp_last_lun = *((u64 *)
+                                         phys_to_virt(sg_dma_address(sg)));
+                       last_lun |= temp_last_lun >>
+                                   (lun_across_sg_bytes * BITS_PER_BYTE);
+
+                       /* from prev buf take higher bytes */
+                       temp_last_lun = *((u64 *)(prev_rl_data +
+                                         (prev_sg_len - lun_across_sg_bytes)));
+                       temp_last_lun >>= bytes_from_next_buf * BITS_PER_BYTE;
+                       last_lun = last_lun | (temp_last_lun <<
+                                  (bytes_from_next_buf * BITS_PER_BYTE));
+
+                       bfa_ioim_lm_fetch_lun(ioim, (u8 *)&last_lun, 0, 1);
+               } else
+                       bytes_from_next_buf = 0;
+
+               *pgdlen += sg_dma_len(sg);
+               prev_sg_len = sg_dma_len(sg);
+               prev_rl_data = (struct scsi_lun *)
+                               phys_to_virt(sg_dma_address(sg));
+               bfa_ioim_lm_fetch_lun(ioim, (u8 *)prev_rl_data,
+                               bytes_from_next_buf,
+                               sg_dma_len(sg) / sizeof(struct scsi_lun));
+       }
+
+       /* update the report luns data - based on fetched luns */
+       sg = scsi_sglist(cmnd);
+       base_rl_data = (struct scsi_lun *)rl->lun;
+       base_count = (sg_dma_len(sg) / sizeof(struct scsi_lun)) - 1;
+       for (i = 0, j = 0; i < MAX_LUN_MASK_CFG; i++) {
+               if (lun_list[i].state == BFA_IOIM_LUN_MASK_FETCHED) {
+                       base_rl_data[j] = lun_list[i].lun;
+                       lun_list[i].state = BFA_IOIM_LUN_MASK_ACTIVE;
+                       j++;
+                       lun_fetched_cnt++;
+               }
+
+               if (j > base_count) {
+                       j = 0;
+                       sg = sg_next(sg);
+                       base_rl_data = (struct scsi_lun *)
+                                       phys_to_virt(sg_dma_address(sg));
+                       base_count = sg_dma_len(sg) / sizeof(struct scsi_lun);
+               }
+       }
+
+       bfa_trc(ioim->bfa, lun_fetched_cnt);
+       return lun_fetched_cnt;
+}
+
+static bfa_boolean_t
+bfa_ioim_lm_proc_inq_data(struct bfa_ioim_s *ioim)
+{
+       struct scsi_inquiry_data_s *inq;
+       struct scatterlist *sg = scsi_sglist((struct scsi_cmnd *)ioim->dio);
+
+       ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy;
+       inq = (struct scsi_inquiry_data_s *)phys_to_virt(sg_dma_address(sg));
+
+       bfa_trc(ioim->bfa, inq->device_type);
+       inq->peripheral_qual = SCSI_INQ_PQ_NOT_CON;
+       return 0;
+}
+
+static bfa_boolean_t
+bfa_ioim_lm_proc_rpl_data(struct bfa_ioim_s *ioim)
+{
+       struct scsi_cmnd *cmnd = (struct scsi_cmnd *)ioim->dio;
+       struct scatterlist *sg = scsi_sglist(cmnd);
+       struct bfi_ioim_rsp_s *m;
+       struct scsi_report_luns_data_s *rl = NULL;
+       int lun_count = 0, lun_fetched_cnt = 0;
+       u32 residue, pgdlen = 0;
+
+       ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy;
+       if (bfa_get_lun_mask_status(ioim->bfa) != BFA_LUNMASK_ENABLED)
+               return BFA_TRUE;
+
+       m = (struct bfi_ioim_rsp_s *) &ioim->iosp->comp_rspmsg;
+       if (m->scsi_status == SCSI_STATUS_CHECK_CONDITION)
+               return BFA_TRUE;
+
+       pgdlen = sg_dma_len(sg);
+       bfa_trc(ioim->bfa, pgdlen);
+       rl = (struct scsi_report_luns_data_s *)phys_to_virt(sg_dma_address(sg));
+       lun_count = cpu_to_be32(rl->lun_list_length) / sizeof(struct scsi_lun);
+       lun_fetched_cnt = bfa_ioim_lm_update_lun_sg(ioim, &pgdlen, rl);
+
+       if (lun_count == lun_fetched_cnt)
+               return BFA_TRUE;
+
+       bfa_trc(ioim->bfa, lun_count);
+       bfa_trc(ioim->bfa, lun_fetched_cnt);
+       bfa_trc(ioim->bfa, be32_to_cpu(rl->lun_list_length));
+
+       if (be32_to_cpu(rl->lun_list_length) <= pgdlen)
+               rl->lun_list_length = be32_to_cpu(lun_fetched_cnt) *
+                                     sizeof(struct scsi_lun);
+       else
+               bfa_stats(ioim->itnim, lm_small_buf_addresidue);
+
+       bfa_trc(ioim->bfa, be32_to_cpu(rl->lun_list_length));
+       bfa_trc(ioim->bfa, be32_to_cpu(m->residue));
+
+       residue = be32_to_cpu(m->residue);
+       residue += (lun_count - lun_fetched_cnt) * sizeof(struct scsi_lun);
+       bfa_stats(ioim->itnim, lm_wire_residue_changed);
+       m->residue = be32_to_cpu(residue);
+       bfa_trc(ioim->bfa, ioim->nsges);
+       return BFA_FALSE;
+}
 
 static void
 __bfa_cb_ioim_good_comp(void *cbarg, bfa_boolean_t complete)
@@ -2067,6 +2454,299 @@ __bfa_cb_ioim_comp(void *cbarg, bfa_boolean_t complete)
                          m->scsi_status, sns_len, snsinfo, residue);
 }
 
+static void
+__bfa_cb_ioim_lm_lun_not_sup(void *cbarg, bfa_boolean_t complete)
+{
+       struct bfa_ioim_s *ioim = cbarg;
+       int sns_len = 0xD;
+       u32 residue = scsi_bufflen((struct scsi_cmnd *)ioim->dio);
+       struct scsi_sense_s *snsinfo;
+
+       if (!complete) {
+               bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB);
+               return;
+       }
+
+       snsinfo = (struct scsi_sense_s *)BFA_SNSINFO_FROM_TAG(
+                                       ioim->fcpim->fcp, ioim->iotag);
+       snsinfo->rsp_code = SCSI_SENSE_CUR_ERR;
+       snsinfo->add_sense_length = 0xa;
+       snsinfo->asc = SCSI_ASC_LUN_NOT_SUPPORTED;
+       snsinfo->sense_key = ILLEGAL_REQUEST;
+       bfa_trc(ioim->bfa, residue);
+       bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_OK,
+                       SCSI_STATUS_CHECK_CONDITION, sns_len,
+                       (u8 *)snsinfo, residue);
+}
+
+static void
+__bfa_cb_ioim_lm_rpl_dc(void *cbarg, bfa_boolean_t complete)
+{
+       struct bfa_ioim_s *ioim = cbarg;
+       int sns_len = 0xD;
+       u32 residue = scsi_bufflen((struct scsi_cmnd *)ioim->dio);
+       struct scsi_sense_s *snsinfo;
+
+       if (!complete) {
+               bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB);
+               return;
+       }
+
+       snsinfo = (struct scsi_sense_s *)BFA_SNSINFO_FROM_TAG(ioim->fcpim->fcp,
+                                                      ioim->iotag);
+       snsinfo->rsp_code = SCSI_SENSE_CUR_ERR;
+       snsinfo->sense_key = SCSI_MP_IEC_UNIT_ATTN;
+       snsinfo->asc = SCSI_ASC_TOCC;
+       snsinfo->add_sense_length = 0x6;
+       snsinfo->ascq = SCSI_ASCQ_RL_DATA_CHANGED;
+       bfa_trc(ioim->bfa, residue);
+       bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_OK,
+                       SCSI_STATUS_CHECK_CONDITION, sns_len,
+                       (u8 *)snsinfo, residue);
+}
+
+static void
+__bfa_cb_ioim_lm_lun_not_rdy(void *cbarg, bfa_boolean_t complete)
+{
+       struct bfa_ioim_s *ioim = cbarg;
+       int sns_len = 0xD;
+       u32 residue = scsi_bufflen((struct scsi_cmnd *)ioim->dio);
+       struct scsi_sense_s *snsinfo;
+
+       if (!complete) {
+               bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB);
+               return;
+       }
+
+       snsinfo = (struct scsi_sense_s *)BFA_SNSINFO_FROM_TAG(
+                                       ioim->fcpim->fcp, ioim->iotag);
+       snsinfo->rsp_code = SCSI_SENSE_CUR_ERR;
+       snsinfo->add_sense_length = 0xa;
+       snsinfo->sense_key = NOT_READY;
+       snsinfo->asc = SCSI_ASC_LUN_NOT_READY;
+       snsinfo->ascq = SCSI_ASCQ_MAN_INTR_REQ;
+       bfa_trc(ioim->bfa, residue);
+       bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_OK,
+                       SCSI_STATUS_CHECK_CONDITION, sns_len,
+                       (u8 *)snsinfo, residue);
+}
+
+void
+bfa_fcpim_lunmask_rp_update(struct bfa_s *bfa, wwn_t lp_wwn, wwn_t rp_wwn,
+                       u16 rp_tag, u8 lp_tag)
+{
+       struct bfa_lun_mask_s *lun_list;
+       u8      i;
+
+       if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_MINCFG)
+               return;
+
+       lun_list = bfa_get_lun_mask_list(bfa);
+       for (i = 0; i < MAX_LUN_MASK_CFG; i++) {
+               if (lun_list[i].state == BFA_IOIM_LUN_MASK_ACTIVE) {
+                       if ((lun_list[i].lp_wwn == lp_wwn) &&
+                           (lun_list[i].rp_wwn == rp_wwn)) {
+                               lun_list[i].rp_tag = rp_tag;
+                               lun_list[i].lp_tag = lp_tag;
+                       }
+               }
+       }
+}
+
+/*
+ * set UA for all active luns in LM DB
+ */
+static void
+bfa_ioim_lm_set_ua(struct bfa_s *bfa)
+{
+       struct bfa_lun_mask_s   *lunm_list;
+       int     i;
+
+       lunm_list = bfa_get_lun_mask_list(bfa);
+       for (i = 0; i < MAX_LUN_MASK_CFG; i++) {
+               if (lunm_list[i].state != BFA_IOIM_LUN_MASK_ACTIVE)
+                       continue;
+               lunm_list[i].ua = BFA_IOIM_LM_UA_SET;
+       }
+}
+
+bfa_status_t
+bfa_fcpim_lunmask_update(struct bfa_s *bfa, u32 update)
+{
+       struct bfa_lunmask_cfg_s        *lun_mask;
+
+       bfa_trc(bfa, bfa_get_lun_mask_status(bfa));
+       if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_MINCFG)
+               return BFA_STATUS_FAILED;
+
+       if (bfa_get_lun_mask_status(bfa) == update)
+               return BFA_STATUS_NO_CHANGE;
+
+       lun_mask = bfa_get_lun_mask(bfa);
+       lun_mask->status = update;
+
+       if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_ENABLED)
+               bfa_ioim_lm_set_ua(bfa);
+
+       return  bfa_dconf_update(bfa);
+}
+
+bfa_status_t
+bfa_fcpim_lunmask_clear(struct bfa_s *bfa)
+{
+       int i;
+       struct bfa_lun_mask_s   *lunm_list;
+
+       bfa_trc(bfa, bfa_get_lun_mask_status(bfa));
+       if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_MINCFG)
+               return BFA_STATUS_FAILED;
+
+       lunm_list = bfa_get_lun_mask_list(bfa);
+       for (i = 0; i < MAX_LUN_MASK_CFG; i++) {
+               if (lunm_list[i].state == BFA_IOIM_LUN_MASK_ACTIVE) {
+                       if (lunm_list[i].rp_tag != BFA_RPORT_TAG_INVALID)
+                               bfa_rport_unset_lunmask(bfa,
+                                 BFA_RPORT_FROM_TAG(bfa, lunm_list[i].rp_tag));
+               }
+       }
+
+       memset(lunm_list, 0, sizeof(struct bfa_lun_mask_s) * MAX_LUN_MASK_CFG);
+       return bfa_dconf_update(bfa);
+}
+
+bfa_status_t
+bfa_fcpim_lunmask_query(struct bfa_s *bfa, void *buf)
+{
+       struct bfa_lunmask_cfg_s *lun_mask;
+
+       bfa_trc(bfa, bfa_get_lun_mask_status(bfa));
+       if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_MINCFG)
+               return BFA_STATUS_FAILED;
+
+       lun_mask = bfa_get_lun_mask(bfa);
+       memcpy(buf, lun_mask, sizeof(struct bfa_lunmask_cfg_s));
+       return BFA_STATUS_OK;
+}
+
+bfa_status_t
+bfa_fcpim_lunmask_add(struct bfa_s *bfa, u16 vf_id, wwn_t *pwwn,
+                     wwn_t rpwwn, struct scsi_lun lun)
+{
+       struct bfa_lun_mask_s *lunm_list;
+       struct bfa_rport_s *rp = NULL;
+       int i, free_index = MAX_LUN_MASK_CFG + 1;
+       struct bfa_fcs_lport_s *port = NULL;
+       struct bfa_fcs_rport_s *rp_fcs;
+
+       bfa_trc(bfa, bfa_get_lun_mask_status(bfa));
+       if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_MINCFG)
+               return BFA_STATUS_FAILED;
+
+       port = bfa_fcs_lookup_port(&((struct bfad_s *)bfa->bfad)->bfa_fcs,
+                                  vf_id, *pwwn);
+       if (port) {
+               *pwwn = port->port_cfg.pwwn;
+               rp_fcs = bfa_fcs_lport_get_rport_by_pwwn(port, rpwwn);
+               rp = rp_fcs->bfa_rport;
+       }
+
+       lunm_list = bfa_get_lun_mask_list(bfa);
+       /* if entry exists */
+       for (i = 0; i < MAX_LUN_MASK_CFG; i++) {
+               if (lunm_list[i].state != BFA_IOIM_LUN_MASK_ACTIVE)
+                       free_index = i;
+               if ((lunm_list[i].lp_wwn == *pwwn) &&
+                   (lunm_list[i].rp_wwn == rpwwn) &&
+                   (scsilun_to_int((struct scsi_lun *)&lunm_list[i].lun) ==
+                    scsilun_to_int((struct scsi_lun *)&lun)))
+                       return  BFA_STATUS_ENTRY_EXISTS;
+       }
+
+       if (free_index > MAX_LUN_MASK_CFG)
+               return BFA_STATUS_MAX_ENTRY_REACHED;
+
+       if (rp) {
+               lunm_list[free_index].lp_tag = bfa_lps_get_tag_from_pid(bfa,
+                                                  rp->rport_info.local_pid);
+               lunm_list[free_index].rp_tag = rp->rport_tag;
+       } else {
+               lunm_list[free_index].lp_tag = BFA_LP_TAG_INVALID;
+               lunm_list[free_index].rp_tag = BFA_RPORT_TAG_INVALID;
+       }
+
+       lunm_list[free_index].lp_wwn = *pwwn;
+       lunm_list[free_index].rp_wwn = rpwwn;
+       lunm_list[free_index].lun = lun;
+       lunm_list[free_index].state = BFA_IOIM_LUN_MASK_ACTIVE;
+
+       /* set for all luns in this rp */
+       for (i = 0; i < MAX_LUN_MASK_CFG; i++) {
+               if ((lunm_list[i].lp_wwn == *pwwn) &&
+                   (lunm_list[i].rp_wwn == rpwwn))
+                       lunm_list[i].ua = BFA_IOIM_LM_UA_SET;
+       }
+
+       return bfa_dconf_update(bfa);
+}
+
+bfa_status_t
+bfa_fcpim_lunmask_delete(struct bfa_s *bfa, u16 vf_id, wwn_t *pwwn,
+                        wwn_t rpwwn, struct scsi_lun lun)
+{
+       struct bfa_lun_mask_s   *lunm_list;
+       struct bfa_rport_s      *rp = NULL;
+       struct bfa_fcs_lport_s *port = NULL;
+       struct bfa_fcs_rport_s *rp_fcs;
+       int     i;
+
+       /* in min cfg lunm_list could be NULL but  no commands should run. */
+       if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_MINCFG)
+               return BFA_STATUS_FAILED;
+
+       bfa_trc(bfa, bfa_get_lun_mask_status(bfa));
+       bfa_trc(bfa, *pwwn);
+       bfa_trc(bfa, rpwwn);
+       bfa_trc(bfa, scsilun_to_int((struct scsi_lun *)&lun));
+
+       if (*pwwn == 0) {
+               port = bfa_fcs_lookup_port(
+                               &((struct bfad_s *)bfa->bfad)->bfa_fcs,
+                               vf_id, *pwwn);
+               if (port) {
+                       *pwwn = port->port_cfg.pwwn;
+                       rp_fcs = bfa_fcs_lport_get_rport_by_pwwn(port, rpwwn);
+                       rp = rp_fcs->bfa_rport;
+               }
+       }
+
+       lunm_list = bfa_get_lun_mask_list(bfa);
+       for (i = 0; i < MAX_LUN_MASK_CFG; i++) {
+               if ((lunm_list[i].lp_wwn == *pwwn) &&
+                   (lunm_list[i].rp_wwn == rpwwn) &&
+                   (scsilun_to_int((struct scsi_lun *)&lunm_list[i].lun) ==
+                    scsilun_to_int((struct scsi_lun *)&lun))) {
+                       lunm_list[i].lp_wwn = 0;
+                       lunm_list[i].rp_wwn = 0;
+                       int_to_scsilun(0, &lunm_list[i].lun);
+                       lunm_list[i].state = BFA_IOIM_LUN_MASK_INACTIVE;
+                       if (lunm_list[i].rp_tag != BFA_RPORT_TAG_INVALID) {
+                               lunm_list[i].rp_tag = BFA_RPORT_TAG_INVALID;
+                               lunm_list[i].lp_tag = BFA_LP_TAG_INVALID;
+                       }
+                       return bfa_dconf_update(bfa);
+               }
+       }
+
+       /* set for all luns in this rp */
+       for (i = 0; i < MAX_LUN_MASK_CFG; i++) {
+               if ((lunm_list[i].lp_wwn == *pwwn) &&
+                   (lunm_list[i].rp_wwn == rpwwn))
+                       lunm_list[i].ua = BFA_IOIM_LM_UA_SET;
+       }
+
+       return BFA_STATUS_ENTRY_NOT_EXISTS;
+}
+
 static void
 __bfa_cb_ioim_failed(void *cbarg, bfa_boolean_t complete)
 {
@@ -2077,6 +2757,7 @@ __bfa_cb_ioim_failed(void *cbarg, bfa_boolean_t complete)
                return;
        }
 
+       ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy;
        bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_ABORTED,
                          0, 0, NULL, 0);
 }
@@ -2092,6 +2773,7 @@ __bfa_cb_ioim_pathtov(void *cbarg, bfa_boolean_t complete)
                return;
        }
 
+       ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy;
        bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_PATHTOV,
                          0, 0, NULL, 0);
 }
@@ -2106,6 +2788,7 @@ __bfa_cb_ioim_abort(void *cbarg, bfa_boolean_t complete)
                return;
        }
 
+       ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy;
        bfa_cb_ioim_abort(ioim->bfa->bfad, ioim->dio);
 }
 
@@ -2449,6 +3132,7 @@ bfa_ioim_attach(struct bfa_fcpim_s *fcpim)
                ioim->bfa     = fcpim->bfa;
                ioim->fcpim   = fcpim;
                ioim->iosp    = iosp;
+               ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy;
                INIT_LIST_HEAD(&ioim->sgpg_q);
                bfa_reqq_winit(&ioim->iosp->reqq_wait,
                                   bfa_ioim_qresume, ioim);
@@ -2486,6 +3170,7 @@ bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
                        evt = BFA_IOIM_SM_DONE;
                else
                        evt = BFA_IOIM_SM_COMP;
+               ioim->proc_rsp_data(ioim);
                break;
 
        case BFI_IOIM_STS_TIMEDOUT:
@@ -2521,6 +3206,7 @@ bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
                if (rsp->abort_tag != ioim->abort_tag) {
                        bfa_trc(ioim->bfa, rsp->abort_tag);
                        bfa_trc(ioim->bfa, ioim->abort_tag);
+                       ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy;
                        return;
                }
 
@@ -2539,6 +3225,7 @@ bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
                WARN_ON(1);
        }
 
+       ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy;
        bfa_sm_send_event(ioim, evt);
 }
 
@@ -2556,7 +3243,16 @@ bfa_ioim_good_comp_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
        WARN_ON(BFA_IOIM_TAG_2_ID(ioim->iotag) != iotag);
 
        bfa_ioim_cb_profile_comp(fcpim, ioim);
-       bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP_GOOD);
+
+       if (bfa_get_lun_mask_status(bfa) != BFA_LUNMASK_ENABLED)  {
+               bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP_GOOD);
+               return;
+       }
+
+       if (ioim->proc_rsp_data(ioim) == BFA_TRUE)
+               bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP_GOOD);
+       else
+               bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP);
 }
 
 /*
@@ -2668,6 +3364,35 @@ bfa_ioim_free(struct bfa_ioim_s *ioim)
 void
 bfa_ioim_start(struct bfa_ioim_s *ioim)
 {
+       struct scsi_cmnd *cmnd = (struct scsi_cmnd *)ioim->dio;
+       struct bfa_lps_s        *lps;
+       enum bfa_ioim_lm_status status;
+       struct scsi_lun scsilun;
+
+       if (bfa_get_lun_mask_status(ioim->bfa) == BFA_LUNMASK_ENABLED) {
+               lps = BFA_IOIM_TO_LPS(ioim);
+               int_to_scsilun(cmnd->device->lun, &scsilun);
+               status = bfa_ioim_lm_check(ioim, lps,
+                               ioim->itnim->rport, scsilun);
+               if (status == BFA_IOIM_LM_LUN_NOT_RDY) {
+                       bfa_sm_send_event(ioim, BFA_IOIM_SM_LM_LUN_NOT_RDY);
+                       bfa_stats(ioim->itnim, lm_lun_not_rdy);
+                       return;
+               }
+
+               if (status == BFA_IOIM_LM_LUN_NOT_SUP) {
+                       bfa_sm_send_event(ioim, BFA_IOIM_SM_LM_LUN_NOT_SUP);
+                       bfa_stats(ioim->itnim, lm_lun_not_sup);
+                       return;
+               }
+
+               if (status == BFA_IOIM_LM_RPL_DATA_CHANGED) {
+                       bfa_sm_send_event(ioim, BFA_IOIM_SM_LM_RPL_DC);
+                       bfa_stats(ioim->itnim, lm_rpl_data_changed);
+                       return;
+               }
+       }
+
        bfa_ioim_cb_profile_start(ioim->fcpim, ioim);
 
        /*
@@ -3411,6 +4136,13 @@ bfa_fcp_detach(struct bfa_s *bfa)
 static void
 bfa_fcp_start(struct bfa_s *bfa)
 {
+       struct bfa_fcp_mod_s *fcp = BFA_FCP_MOD(bfa);
+
+       /*
+        * bfa_init() with flash read is complete. now invalidate the stale
+        * content of lun mask like unit attention, rp tag and lp tag.
+        */
+       bfa_ioim_lm_init(fcp->bfa);
 }
 
 static void
index 57b695a..1080bcb 100644 (file)
@@ -79,14 +79,22 @@ bfa_ioim_get_index(u32 n) {
        if (n >= (1UL)<<22)
                return BFA_IOBUCKET_MAX - 1;
        n >>= 8;
-       if (n >= (1UL)<<16)
-               n >>= 16; pos += 16;
-       if (n >= 1 << 8)
-               n >>= 8; pos += 8;
-       if (n >= 1 << 4)
-               n >>= 4; pos += 4;
-       if (n >= 1 << 2)
-               n >>= 2; pos += 2;
+       if (n >= (1UL)<<16) {
+               n >>= 16;
+               pos += 16;
+       }
+       if (n >= 1 << 8) {
+               n >>= 8;
+               pos += 8;
+       }
+       if (n >= 1 << 4) {
+               n >>= 4;
+               pos += 4;
+       }
+       if (n >= 1 << 2) {
+               n >>= 2;
+               pos += 2;
+       }
        if (n >= 1 << 1)
                pos += 1;
 
@@ -102,6 +110,7 @@ struct bfad_ioim_s;
 struct bfad_tskim_s;
 
 typedef void    (*bfa_fcpim_profile_t) (struct bfa_ioim_s *ioim);
+typedef bfa_boolean_t (*bfa_ioim_lm_proc_rsp_data_t) (struct bfa_ioim_s *ioim);
 
 struct bfa_fcpim_s {
        struct bfa_s            *bfa;
@@ -115,7 +124,7 @@ struct bfa_fcpim_s {
        u32                     path_tov;
        u16                     q_depth;
        u8                      reqq;           /*  Request queue to be used */
-       u8                      rsvd;
+       u8                      lun_masking_pending;
        struct list_head        itnim_q;        /*  queue of active itnim */
        struct list_head        ioim_resfree_q; /*  IOs waiting for f/w */
        struct list_head        ioim_comp_q;    /*  IO global comp Q    */
@@ -170,7 +179,9 @@ struct bfa_ioim_s {
        bfa_cb_cbfn_t           io_cbfn;        /*  IO completion handler */
        struct bfa_ioim_sp_s    *iosp;          /*  slow-path IO handling */
        u8                      reqq;           /*  Request queue for I/O */
+       u8                      mode;           /*  IO is passthrough or not */
        u64                     start_time;     /*  IO's Profile start val */
+       bfa_ioim_lm_proc_rsp_data_t proc_rsp_data; /* RSP data adjust */
 };
 
 struct bfa_ioim_sp_s {
@@ -250,6 +261,10 @@ struct bfa_itnim_s {
        (__ioim)->iotag |= k << BFA_IOIM_RETRY_TAG_OFFSET;              \
 } while (0)
 
+#define BFA_IOIM_TO_LPS(__ioim)                \
+       BFA_LPS_FROM_TAG(BFA_LPS_MOD(__ioim->bfa),      \
+               __ioim->itnim->rport->rport_info.lp_tag)
+
 static inline bfa_boolean_t
 bfa_ioim_maxretry_reached(struct bfa_ioim_s *ioim)
 {
@@ -297,6 +312,8 @@ bfa_status_t bfa_fcpim_port_iostats(struct bfa_s *bfa,
                        struct bfa_itnim_iostats_s *stats, u8 lp_tag);
 void bfa_fcpim_add_stats(struct bfa_itnim_iostats_s *fcpim_stats,
                        struct bfa_itnim_iostats_s *itnim_stats);
+bfa_status_t bfa_fcpim_profile_on(struct bfa_s *bfa, u32 time);
+bfa_status_t bfa_fcpim_profile_off(struct bfa_s *bfa);
 
 #define bfa_fcpim_ioredirect_enabled(__bfa)                            \
        (((struct bfa_fcpim_s *)(BFA_FCPIM(__bfa)))->ioredirect)
@@ -397,4 +414,14 @@ void bfa_tskim_start(struct bfa_tskim_s *tskim,
 void bfa_cb_tskim_done(void *bfad, struct bfad_tskim_s *dtsk,
                        enum bfi_tskim_status tsk_status);
 
+void   bfa_fcpim_lunmask_rp_update(struct bfa_s *bfa, wwn_t lp_wwn,
+                       wwn_t rp_wwn, u16 rp_tag, u8 lp_tag);
+bfa_status_t   bfa_fcpim_lunmask_update(struct bfa_s *bfa, u32 on_off);
+bfa_status_t   bfa_fcpim_lunmask_query(struct bfa_s *bfa, void *buf);
+bfa_status_t   bfa_fcpim_lunmask_delete(struct bfa_s *bfa, u16 vf_id,
+                               wwn_t *pwwn, wwn_t rpwwn, struct scsi_lun lun);
+bfa_status_t   bfa_fcpim_lunmask_add(struct bfa_s *bfa, u16 vf_id,
+                               wwn_t *pwwn, wwn_t rpwwn, struct scsi_lun lun);
+bfa_status_t   bfa_fcpim_lunmask_clear(struct bfa_s *bfa);
+
 #endif /* __BFA_FCPIM_H__ */
index a9b22bc..eaac57e 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include "bfad_drv.h"
+#include "bfad_im.h"
 #include "bfa_fcs.h"
 #include "bfa_fcbuild.h"
 
@@ -1327,6 +1328,29 @@ bfa_fcs_fabric_flogiacc_comp(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
        bfa_trc(fabric->fcs, status);
 }
 
+
+/*
+ * Send AEN notification
+ */
+static void
+bfa_fcs_fabric_aen_post(struct bfa_fcs_lport_s *port,
+                       enum bfa_port_aen_event event)
+{
+       struct bfad_s *bfad = (struct bfad_s *)port->fabric->fcs->bfad;
+       struct bfa_aen_entry_s  *aen_entry;
+
+       bfad_get_aen_entry(bfad, aen_entry);
+       if (!aen_entry)
+               return;
+
+       aen_entry->aen_data.port.pwwn = bfa_fcs_lport_get_pwwn(port);
+       aen_entry->aen_data.port.fwwn = bfa_fcs_lport_get_fabric_name(port);
+
+       /* Send the AEN notification */
+       bfad_im_post_vendor_event(aen_entry, bfad, ++port->fcs->fcs_aen_seq,
+                                 BFA_AEN_CAT_PORT, event);
+}
+
 /*
  *
  * @param[in] fabric - fabric
@@ -1358,6 +1382,8 @@ bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric,
                BFA_LOG(KERN_WARNING, bfad, bfa_log_level,
                        "Base port WWN = %s Fabric WWN = %s\n",
                        pwwn_ptr, fwwn_ptr);
+               bfa_fcs_fabric_aen_post(&fabric->bport,
+                               BFA_PORT_AEN_FABRIC_NAME_CHANGE);
        }
 }
 
index a5f1faf..e75e07d 100644 (file)
@@ -675,6 +675,7 @@ struct bfa_fcs_s {
        struct bfa_fcs_fabric_s fabric; /*  base fabric state machine */
        struct bfa_fcs_stats_s  stats;  /*  FCS statistics */
        struct bfa_wc_s         wc;     /*  waiting counter */
+       int                     fcs_aen_seq;
 };
 
 /*
index 29b4108..9272840 100644 (file)
@@ -37,6 +37,8 @@ static void   bfa_fcs_itnim_prli_response(void *fcsarg,
                         struct bfa_fcxp_s *fcxp, void *cbarg,
                            bfa_status_t req_status, u32 rsp_len,
                            u32 resid_len, struct fchs_s *rsp_fchs);
+static void    bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim,
+                       enum bfa_itnim_aen_event event);
 
 /*
  *  fcs_itnim_sm FCS itnim state machine events
@@ -269,6 +271,7 @@ bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim,
                BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                "Target (WWN = %s) is online for initiator (WWN = %s)\n",
                rpwwn_buf, lpwwn_buf);
+               bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_ONLINE);
                break;
 
        case BFA_FCS_ITNIM_SM_OFFLINE:
@@ -305,14 +308,17 @@ bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim,
                bfa_itnim_offline(itnim->bfa_itnim);
                wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(itnim->rport->port));
                wwn2str(rpwwn_buf, itnim->rport->pwwn);
-               if (bfa_fcs_lport_is_online(itnim->rport->port) == BFA_TRUE)
+               if (bfa_fcs_lport_is_online(itnim->rport->port) == BFA_TRUE) {
                        BFA_LOG(KERN_ERR, bfad, bfa_log_level,
                        "Target (WWN = %s) connectivity lost for "
                        "initiator (WWN = %s)\n", rpwwn_buf, lpwwn_buf);
-               else
+                       bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_DISCONNECT);
+               } else {
                        BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                        "Target (WWN = %s) offlined by initiator (WWN = %s)\n",
                        rpwwn_buf, lpwwn_buf);
+                       bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_OFFLINE);
+               }
                break;
 
        case BFA_FCS_ITNIM_SM_DELETE:
@@ -381,6 +387,33 @@ bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim,
        }
 }
 
+static void
+bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim,
+                       enum bfa_itnim_aen_event event)
+{
+       struct bfa_fcs_rport_s *rport = itnim->rport;
+       struct bfad_s *bfad = (struct bfad_s *)itnim->fcs->bfad;
+       struct bfa_aen_entry_s  *aen_entry;
+
+       /* Don't post events for well known addresses */
+       if (BFA_FCS_PID_IS_WKA(rport->pid))
+               return;
+
+       bfad_get_aen_entry(bfad, aen_entry);
+       if (!aen_entry)
+               return;
+
+       aen_entry->aen_data.itnim.vf_id = rport->port->fabric->vf_id;
+       aen_entry->aen_data.itnim.ppwwn = bfa_fcs_lport_get_pwwn(
+                                       bfa_fcs_get_base_port(itnim->fcs));
+       aen_entry->aen_data.itnim.lpwwn = bfa_fcs_lport_get_pwwn(rport->port);
+       aen_entry->aen_data.itnim.rpwwn = rport->pwwn;
+
+       /* Send the AEN notification */
+       bfad_im_post_vendor_event(aen_entry, bfad, ++rport->fcs->fcs_aen_seq,
+                                 BFA_AEN_CAT_ITNIM, event);
+}
+
 static void
 bfa_fcs_itnim_send_prli(void *itnim_cbarg, struct bfa_fcxp_s *fcxp_alloced)
 {
index f8251a9..d4f951f 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #include "bfad_drv.h"
+#include "bfad_im.h"
 #include "bfa_fcs.h"
 #include "bfa_fcbuild.h"
 #include "bfa_fc.h"
@@ -299,6 +300,31 @@ bfa_fcs_lport_sm_deleting(
  *  fcs_port_pvt
  */
 
+/*
+ * Send AEN notification
+ */
+static void
+bfa_fcs_lport_aen_post(struct bfa_fcs_lport_s *port,
+                       enum bfa_lport_aen_event event)
+{
+       struct bfad_s *bfad = (struct bfad_s *)port->fabric->fcs->bfad;
+       struct bfa_aen_entry_s  *aen_entry;
+
+       bfad_get_aen_entry(bfad, aen_entry);
+       if (!aen_entry)
+               return;
+
+       aen_entry->aen_data.lport.vf_id = port->fabric->vf_id;
+       aen_entry->aen_data.lport.roles = port->port_cfg.roles;
+       aen_entry->aen_data.lport.ppwwn = bfa_fcs_lport_get_pwwn(
+                                       bfa_fcs_get_base_port(port->fcs));
+       aen_entry->aen_data.lport.lpwwn = bfa_fcs_lport_get_pwwn(port);
+
+       /* Send the AEN notification */
+       bfad_im_post_vendor_event(aen_entry, bfad, ++port->fcs->fcs_aen_seq,
+                                 BFA_AEN_CAT_LPORT, event);
+}
+
 /*
  * Send a LS reject
  */
@@ -593,6 +619,7 @@ bfa_fcs_lport_online_actions(struct bfa_fcs_lport_s *port)
        BFA_LOG(KERN_INFO, 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);
 
        bfad->bfad_flags |= BFAD_PORT_ONLINE;
 }
@@ -611,14 +638,17 @@ 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_fcs_fabric_sm_online) == BFA_TRUE) {
                BFA_LOG(KERN_ERR, bfad, bfa_log_level,
                "Logical port lost fabric connectivity: WWN = %s Role = %s\n",
                lpwwn_buf, "Initiator");
-       else
+               bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_DISCONNECT);
+       } else {
                BFA_LOG(KERN_INFO, 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);
+       }
 
        list_for_each_safe(qe, qen, &port->rport_q) {
                rport = (struct bfa_fcs_rport_s *) qe;
@@ -676,6 +706,7 @@ bfa_fcs_lport_deleted(struct bfa_fcs_lport_s *port)
        BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                "Logical port deleted: WWN = %s Role = %s\n",
                lpwwn_buf, "Initiator");
+       bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_DELETE);
 
        /* Base port will be deleted by the OS driver */
        if (port->vport) {
@@ -973,6 +1004,7 @@ bfa_fcs_lport_init(struct bfa_fcs_lport_s *lport,
        BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                "New logical port created: WWN = %s Role = %s\n",
                lpwwn_buf, "Initiator");
+       bfa_fcs_lport_aen_post(lport, BFA_LPORT_AEN_NEW);
 
        bfa_sm_set_state(lport, bfa_fcs_lport_sm_uninit);
        bfa_sm_send_event(lport, BFA_FCS_PORT_SM_CREATE);
@@ -5558,6 +5590,31 @@ bfa_fcs_vport_sm_logo(struct bfa_fcs_vport_s *vport,
 /*
  *  fcs_vport_private FCS virtual port private functions
  */
+/*
+ * Send AEN notification
+ */
+static void
+bfa_fcs_vport_aen_post(struct bfa_fcs_lport_s *port,
+                      enum bfa_lport_aen_event event)
+{
+       struct bfad_s *bfad = (struct bfad_s *)port->fabric->fcs->bfad;
+       struct bfa_aen_entry_s  *aen_entry;
+
+       bfad_get_aen_entry(bfad, aen_entry);
+       if (!aen_entry)
+               return;
+
+       aen_entry->aen_data.lport.vf_id = port->fabric->vf_id;
+       aen_entry->aen_data.lport.roles = port->port_cfg.roles;
+       aen_entry->aen_data.lport.ppwwn = bfa_fcs_lport_get_pwwn(
+                                       bfa_fcs_get_base_port(port->fcs));
+       aen_entry->aen_data.lport.lpwwn = bfa_fcs_lport_get_pwwn(port);
+
+       /* Send the AEN notification */
+       bfad_im_post_vendor_event(aen_entry, bfad, ++port->fcs->fcs_aen_seq,
+                                 BFA_AEN_CAT_LPORT, event);
+}
+
 /*
  * This routine will be called to send a FDISC command.
  */
@@ -5585,8 +5642,11 @@ bfa_fcs_vport_fdisc_rejected(struct bfa_fcs_vport_s *vport)
        case FC_LS_RJT_EXP_INVALID_NPORT_ID: /* by Cisco */
                if (vport->fdisc_retries < BFA_FCS_VPORT_MAX_RETRIES)
                        bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR);
-               else
+               else {
+                       bfa_fcs_vport_aen_post(&vport->lport,
+                                       BFA_LPORT_AEN_NPIV_DUP_WWN);
                        bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_DUP_WWN);
+               }
                break;
 
        case FC_LS_RJT_EXP_INSUFF_RES:
@@ -5596,11 +5656,17 @@ bfa_fcs_vport_fdisc_rejected(struct bfa_fcs_vport_s *vport)
                 */
                if (vport->fdisc_retries < BFA_FCS_VPORT_MAX_RETRIES)
                        bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR);
-               else
+               else {
+                       bfa_fcs_vport_aen_post(&vport->lport,
+                                       BFA_LPORT_AEN_NPIV_FABRIC_MAX);
                        bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_FAILED);
+               }
                break;
 
        default:
+               if (vport->fdisc_retries == 0)
+                       bfa_fcs_vport_aen_post(&vport->lport,
+                                       BFA_LPORT_AEN_NPIV_UNKNOWN);
                bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR);
        }
 }
index 2c51445..52628d5 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include "bfad_drv.h"
+#include "bfad_im.h"
 #include "bfa_fcs.h"
 #include "bfa_fcbuild.h"
 
@@ -2040,6 +2041,35 @@ bfa_fcs_rport_free(struct bfa_fcs_rport_s *rport)
        kfree(rport->rp_drv);
 }
 
+static void
+bfa_fcs_rport_aen_post(struct bfa_fcs_rport_s *rport,
+                       enum bfa_rport_aen_event event,
+                       struct bfa_rport_aen_data_s *data)
+{
+       struct bfa_fcs_lport_s *port = rport->port;
+       struct bfad_s *bfad = (struct bfad_s *)port->fcs->bfad;
+       struct bfa_aen_entry_s  *aen_entry;
+
+       bfad_get_aen_entry(bfad, aen_entry);
+       if (!aen_entry)
+               return;
+
+       if (event == BFA_RPORT_AEN_QOS_PRIO)
+               aen_entry->aen_data.rport.priv.qos = data->priv.qos;
+       else if (event == BFA_RPORT_AEN_QOS_FLOWID)
+               aen_entry->aen_data.rport.priv.qos = data->priv.qos;
+
+       aen_entry->aen_data.rport.vf_id = rport->port->fabric->vf_id;
+       aen_entry->aen_data.rport.ppwwn = bfa_fcs_lport_get_pwwn(
+                                       bfa_fcs_get_base_port(rport->fcs));
+       aen_entry->aen_data.rport.lpwwn = bfa_fcs_lport_get_pwwn(rport->port);
+       aen_entry->aen_data.rport.rpwwn = rport->pwwn;
+
+       /* Send the AEN notification */
+       bfad_im_post_vendor_event(aen_entry, bfad, ++rport->fcs->fcs_aen_seq,
+                                 BFA_AEN_CAT_RPORT, event);
+}
+
 static void
 bfa_fcs_rport_online_action(struct bfa_fcs_rport_s *rport)
 {
@@ -2063,10 +2093,12 @@ bfa_fcs_rport_online_action(struct bfa_fcs_rport_s *rport)
 
        wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port));
        wwn2str(rpwwn_buf, rport->pwwn);
-       if (!BFA_FCS_PID_IS_WKA(rport->pid))
+       if (!BFA_FCS_PID_IS_WKA(rport->pid)) {
                BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                "Remote port (WWN = %s) online for logical port (WWN = %s)\n",
                rpwwn_buf, lpwwn_buf);
+               bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_ONLINE, NULL);
+       }
 }
 
 static void
@@ -2083,16 +2115,21 @@ bfa_fcs_rport_offline_action(struct bfa_fcs_rport_s *rport)
        wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port));
        wwn2str(rpwwn_buf, rport->pwwn);
        if (!BFA_FCS_PID_IS_WKA(rport->pid)) {
-               if (bfa_fcs_lport_is_online(rport->port) == BFA_TRUE)
+               if (bfa_fcs_lport_is_online(rport->port) == BFA_TRUE) {
                        BFA_LOG(KERN_ERR, bfad, bfa_log_level,
                                "Remote port (WWN = %s) connectivity lost for "
                                "logical port (WWN = %s)\n",
                                rpwwn_buf, lpwwn_buf);
-               else
+                       bfa_fcs_rport_aen_post(rport,
+                               BFA_RPORT_AEN_DISCONNECT, NULL);
+               } else {
                        BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                                "Remote port (WWN = %s) offlined by "
                                "logical port (WWN = %s)\n",
                                rpwwn_buf, lpwwn_buf);
+                       bfa_fcs_rport_aen_post(rport,
+                               BFA_RPORT_AEN_OFFLINE, NULL);
+               }
        }
 
        if (bfa_fcs_lport_is_initiator(port)) {
@@ -2366,8 +2403,11 @@ bfa_cb_rport_qos_scn_flowid(void *cbarg,
                struct bfa_rport_qos_attr_s new_qos_attr)
 {
        struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *) cbarg;
+       struct bfa_rport_aen_data_s aen_data;
 
        bfa_trc(rport->fcs, rport->pwwn);
+       aen_data.priv.qos = new_qos_attr;
+       bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_QOS_FLOWID, &aen_data);
 }
 
 /*
@@ -2390,8 +2430,11 @@ bfa_cb_rport_qos_scn_prio(void *cbarg,
                struct bfa_rport_qos_attr_s new_qos_attr)
 {
        struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *) cbarg;
+       struct bfa_rport_aen_data_s aen_data;
 
        bfa_trc(rport->fcs, rport->pwwn);
+       aen_data.priv.qos = new_qos_attr;
+       bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_QOS_PRIO, &aen_data);
 }
 
 /*
index e7ffd82..ea24d4c 100644 (file)
@@ -42,11 +42,36 @@ bfa_hwcb_reqq_ack_msix(struct bfa_s *bfa, int reqq)
                        bfa->iocfc.bfa_regs.intr_status);
 }
 
+/*
+ * Actions to respond RME Interrupt for Crossbow ASIC:
+ * - Write 1 to Interrupt Status register
+ *              INTX - done in bfa_intx()
+ *              MSIX - done in bfa_hwcb_rspq_ack_msix()
+ * - Update CI (only if new CI)
+ */
 static void
-bfa_hwcb_rspq_ack_msix(struct bfa_s *bfa, int rspq)
+bfa_hwcb_rspq_ack_msix(struct bfa_s *bfa, int rspq, u32 ci)
 {
        writel(__HFN_INT_RME_Q0 << RME_Q_NUM(bfa_ioc_pcifn(&bfa->ioc), rspq),
-                       bfa->iocfc.bfa_regs.intr_status);
+               bfa->iocfc.bfa_regs.intr_status);
+
+       if (bfa_rspq_ci(bfa, rspq) == ci)
+               return;
+
+       bfa_rspq_ci(bfa, rspq) = ci;
+       writel(ci, bfa->iocfc.bfa_regs.rme_q_ci[rspq]);
+       mmiowb();
+}
+
+void
+bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq, u32 ci)
+{
+       if (bfa_rspq_ci(bfa, rspq) == ci)
+               return;
+
+       bfa_rspq_ci(bfa, rspq) = ci;
+       writel(ci, bfa->iocfc.bfa_regs.rme_q_ci[rspq]);
+       mmiowb();
 }
 
 void
@@ -149,8 +174,13 @@ bfa_hwcb_msix_uninstall(struct bfa_s *bfa)
 void
 bfa_hwcb_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix)
 {
-       bfa->iocfc.hwif.hw_reqq_ack = bfa_hwcb_reqq_ack_msix;
-       bfa->iocfc.hwif.hw_rspq_ack = bfa_hwcb_rspq_ack_msix;
+       if (msix) {
+               bfa->iocfc.hwif.hw_reqq_ack = bfa_hwcb_reqq_ack_msix;
+               bfa->iocfc.hwif.hw_rspq_ack = bfa_hwcb_rspq_ack_msix;
+       } else {
+               bfa->iocfc.hwif.hw_reqq_ack = NULL;
+               bfa->iocfc.hwif.hw_rspq_ack = bfa_hwcb_rspq_ack;
+       }
 }
 
 void
index 989bbce..637527f 100644 (file)
@@ -64,13 +64,36 @@ bfa_hwct_reqq_ack(struct bfa_s *bfa, int reqq)
        writel(r32, bfa->iocfc.bfa_regs.cpe_q_ctrl[reqq]);
 }
 
+/*
+ * Actions to respond RME Interrupt for Catapult ASIC:
+ * - Write 1 to Interrupt Status register (INTx only - done in bfa_intx())
+ * - Acknowledge by writing to RME Queue Control register
+ * - Update CI
+ */
 void
-bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq)
+bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq, u32 ci)
 {
        u32     r32;
 
        r32 = readl(bfa->iocfc.bfa_regs.rme_q_ctrl[rspq]);
        writel(r32, bfa->iocfc.bfa_regs.rme_q_ctrl[rspq]);
+
+       bfa_rspq_ci(bfa, rspq) = ci;
+       writel(ci, bfa->iocfc.bfa_regs.rme_q_ci[rspq]);
+       mmiowb();
+}
+
+/*
+ * Actions to respond RME Interrupt for Catapult2 ASIC:
+ * - Write 1 to Interrupt Status register (INTx only - done in bfa_intx())
+ * - Update CI
+ */
+void
+bfa_hwct2_rspq_ack(struct bfa_s *bfa, int rspq, u32 ci)
+{
+       bfa_rspq_ci(bfa, rspq) = ci;
+       writel(ci, bfa->iocfc.bfa_regs.rme_q_ci[rspq]);
+       mmiowb();
 }
 
 void
index d6c2bf3..1ac5aec 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #include "bfad_drv.h"
+#include "bfad_im.h"
 #include "bfa_ioc.h"
 #include "bfi_reg.h"
 #include "bfa_defs.h"
@@ -458,6 +459,7 @@ bfa_ioc_sm_op_entry(struct bfa_ioc_s *ioc)
        ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_OK);
        bfa_ioc_event_notify(ioc, BFA_IOC_E_ENABLED);
        BFA_LOG(KERN_INFO, bfad, bfa_log_level, "IOC enabled\n");
+       bfa_ioc_aen_post(ioc, BFA_IOC_AEN_ENABLE);
 }
 
 static void
@@ -502,6 +504,7 @@ bfa_ioc_sm_disabling_entry(struct bfa_ioc_s *ioc)
        struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad;
        bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_DISABLE);
        BFA_LOG(KERN_INFO, bfad, bfa_log_level, "IOC disabled\n");
+       bfa_ioc_aen_post(ioc, BFA_IOC_AEN_DISABLE);
 }
 
 /*
@@ -1966,6 +1969,7 @@ bfa_ioc_fail_notify(struct bfa_ioc_s *ioc)
 
        BFA_LOG(KERN_CRIT, bfad, bfa_log_level,
                "Heart Beat of IOC has failed\n");
+       bfa_ioc_aen_post(ioc, BFA_IOC_AEN_HBFAIL);
 
 }
 
@@ -1980,6 +1984,7 @@ bfa_ioc_pf_fwmismatch(struct bfa_ioc_s *ioc)
        BFA_LOG(KERN_WARNING, bfad, bfa_log_level,
                "Running firmware version is incompatible "
                "with the driver version\n");
+       bfa_ioc_aen_post(ioc, BFA_IOC_AEN_FWMISMATCH);
 }
 
 bfa_status_t
@@ -2678,6 +2683,43 @@ bfa_ioc_get_mfg_mac(struct bfa_ioc_s *ioc)
        return m;
 }
 
+/*
+ * Send AEN notification
+ */
+void
+bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event)
+{
+       struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad;
+       struct bfa_aen_entry_s  *aen_entry;
+       enum bfa_ioc_type_e ioc_type;
+
+       bfad_get_aen_entry(bfad, aen_entry);
+       if (!aen_entry)
+               return;
+
+       ioc_type = bfa_ioc_get_type(ioc);
+       switch (ioc_type) {
+       case BFA_IOC_TYPE_FC:
+               aen_entry->aen_data.ioc.pwwn = ioc->attr->pwwn;
+               break;
+       case BFA_IOC_TYPE_FCoE:
+               aen_entry->aen_data.ioc.pwwn = ioc->attr->pwwn;
+               aen_entry->aen_data.ioc.mac = bfa_ioc_get_mac(ioc);
+               break;
+       case BFA_IOC_TYPE_LL:
+               aen_entry->aen_data.ioc.mac = bfa_ioc_get_mac(ioc);
+               break;
+       default:
+               WARN_ON(ioc_type != BFA_IOC_TYPE_FC);
+               break;
+       }
+
+       /* Send the AEN notification */
+       aen_entry->aen_data.ioc.ioc_type = ioc_type;
+       bfad_im_post_vendor_event(aen_entry, bfad, ++ioc->ioc_aen_seq,
+                                 BFA_AEN_CAT_IOC, event);
+}
+
 /*
  * Retrieve saved firmware trace from a prior IOC failure.
  */
@@ -2879,6 +2921,10 @@ bfa_ioc_check_attr_wwns(struct bfa_ioc_s *ioc)
 {
        if (bfa_ioc_get_type(ioc) == BFA_IOC_TYPE_LL)
                return;
+       if (ioc->attr->nwwn == 0)
+               bfa_ioc_aen_post(ioc, BFA_IOC_AEN_INVALID_NWWN);
+       if (ioc->attr->pwwn == 0)
+               bfa_ioc_aen_post(ioc, BFA_IOC_AEN_INVALID_PWWN);
 }
 
 /*
@@ -3442,6 +3488,54 @@ bfa_sfp_notify(void *sfp_arg, enum bfa_ioc_event_e event)
        }
 }
 
+/*
+ * SFP's State Change Notification post to AEN
+ */
+static void
+bfa_sfp_scn_aen_post(struct bfa_sfp_s *sfp, struct bfi_sfp_scn_s *rsp)
+{
+       struct bfad_s *bfad = (struct bfad_s *)sfp->ioc->bfa->bfad;
+       struct bfa_aen_entry_s  *aen_entry;
+       enum bfa_port_aen_event aen_evt = 0;
+
+       bfa_trc(sfp, (((u64)rsp->pomlvl) << 16) | (((u64)rsp->sfpid) << 8) |
+                     ((u64)rsp->event));
+
+       bfad_get_aen_entry(bfad, aen_entry);
+       if (!aen_entry)
+               return;
+
+       aen_entry->aen_data.port.ioc_type = bfa_ioc_get_type(sfp->ioc);
+       aen_entry->aen_data.port.pwwn = sfp->ioc->attr->pwwn;
+       aen_entry->aen_data.port.mac = bfa_ioc_get_mac(sfp->ioc);
+
+       switch (rsp->event) {
+       case BFA_SFP_SCN_INSERTED:
+               aen_evt = BFA_PORT_AEN_SFP_INSERT;
+               break;
+       case BFA_SFP_SCN_REMOVED:
+               aen_evt = BFA_PORT_AEN_SFP_REMOVE;
+               break;
+       case BFA_SFP_SCN_FAILED:
+               aen_evt = BFA_PORT_AEN_SFP_ACCESS_ERROR;
+               break;
+       case BFA_SFP_SCN_UNSUPPORT:
+               aen_evt = BFA_PORT_AEN_SFP_UNSUPPORT;
+               break;
+       case BFA_SFP_SCN_POM:
+               aen_evt = BFA_PORT_AEN_SFP_POM;
+               aen_entry->aen_data.port.level = rsp->pomlvl;
+               break;
+       default:
+               bfa_trc(sfp, rsp->event);
+               WARN_ON(1);
+       }
+
+       /* Send the AEN notification */
+       bfad_im_post_vendor_event(aen_entry, bfad, ++sfp->ioc->ioc_aen_seq,
+                                 BFA_AEN_CAT_PORT, aen_evt);
+}
+
 /*
  *     SFP get data send
  */
@@ -3481,6 +3575,50 @@ bfa_sfp_getdata(struct bfa_sfp_s *sfp, enum bfi_sfp_mem_e memtype)
        bfa_sfp_getdata_send(sfp);
 }
 
+/*
+ *     SFP scn handler
+ */
+static void
+bfa_sfp_scn(struct bfa_sfp_s *sfp, struct bfi_mbmsg_s *msg)
+{
+       struct bfi_sfp_scn_s *rsp = (struct bfi_sfp_scn_s *) msg;
+
+       switch (rsp->event) {
+       case BFA_SFP_SCN_INSERTED:
+               sfp->state = BFA_SFP_STATE_INSERTED;
+               sfp->data_valid = 0;
+               bfa_sfp_scn_aen_post(sfp, rsp);
+               break;
+       case BFA_SFP_SCN_REMOVED:
+               sfp->state = BFA_SFP_STATE_REMOVED;
+               sfp->data_valid = 0;
+               bfa_sfp_scn_aen_post(sfp, rsp);
+                break;
+       case BFA_SFP_SCN_FAILED:
+               sfp->state = BFA_SFP_STATE_FAILED;
+               sfp->data_valid = 0;
+               bfa_sfp_scn_aen_post(sfp, rsp);
+               break;
+       case BFA_SFP_SCN_UNSUPPORT:
+               sfp->state = BFA_SFP_STATE_UNSUPPORT;
+               bfa_sfp_scn_aen_post(sfp, rsp);
+               if (!sfp->lock)
+                       bfa_sfp_getdata(sfp, BFI_SFP_MEM_ALL);
+               break;
+       case BFA_SFP_SCN_POM:
+               bfa_sfp_scn_aen_post(sfp, rsp);
+               break;
+       case BFA_SFP_SCN_VALID:
+               sfp->state = BFA_SFP_STATE_VALID;
+               if (!sfp->lock)
+                       bfa_sfp_getdata(sfp, BFI_SFP_MEM_ALL);
+               break;
+       default:
+               bfa_trc(sfp, rsp->event);
+               WARN_ON(1);
+       }
+}
+
 /*
  * SFP show complete
  */
@@ -3645,7 +3783,7 @@ bfa_sfp_intr(void *sfparg, struct bfi_mbmsg_s *msg)
                break;
 
        case BFI_SFP_I2H_SCN:
-               bfa_trc(sfp, msg->mh.msg_id);
+               bfa_sfp_scn(sfp, msg);
                break;
 
        default:
@@ -3837,6 +3975,26 @@ bfa_sfp_speed(struct bfa_sfp_s *sfp, enum bfa_port_speed portspeed,
 #define BFA_FLASH_DMA_BUF_SZ   \
        BFA_ROUNDUP(0x010000 + sizeof(struct bfa_mfg_block_s), BFA_FLASH_SEG_SZ)
 
+static void
+bfa_flash_aen_audit_post(struct bfa_ioc_s *ioc, enum bfa_audit_aen_event event,
+                       int inst, int type)
+{
+       struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad;
+       struct bfa_aen_entry_s  *aen_entry;
+
+       bfad_get_aen_entry(bfad, aen_entry);
+       if (!aen_entry)
+               return;
+
+       aen_entry->aen_data.audit.pwwn = ioc->attr->pwwn;
+       aen_entry->aen_data.audit.partition_inst = inst;
+       aen_entry->aen_data.audit.partition_type = type;
+
+       /* Send the AEN notification */
+       bfad_im_post_vendor_event(aen_entry, bfad, ++ioc->ioc_aen_seq,
+                                 BFA_AEN_CAT_AUDIT, event);
+}
+
 static void
 bfa_flash_cb(struct bfa_flash_s *flash)
 {
@@ -3978,6 +4136,7 @@ bfa_flash_intr(void *flasharg, struct bfi_mbmsg_s *msg)
                struct bfi_flash_erase_rsp_s *erase;
                struct bfi_flash_write_rsp_s *write;
                struct bfi_flash_read_rsp_s *read;
+               struct bfi_flash_event_s *event;
                struct bfi_mbmsg_s   *msg;
        } m;
 
@@ -4061,8 +4220,19 @@ bfa_flash_intr(void *flasharg, struct bfi_mbmsg_s *msg)
                }
                break;
        case BFI_FLASH_I2H_BOOT_VER_RSP:
+               break;
        case BFI_FLASH_I2H_EVENT:
-               bfa_trc(flash, msg->mh.msg_id);
+               status = be32_to_cpu(m.event->status);
+               bfa_trc(flash, status);
+               if (status == BFA_STATUS_BAD_FWCFG)
+                       bfa_ioc_aen_post(flash->ioc, BFA_IOC_AEN_FWCFG_ERROR);
+               else if (status == BFA_STATUS_INVALID_VENDOR) {
+                       u32 param;
+                       param = be32_to_cpu(m.event->param);
+                       bfa_trc(flash, param);
+                       bfa_ioc_aen_post(flash->ioc,
+                               BFA_IOC_AEN_INVALID_VENDOR);
+               }
                break;
 
        default:
@@ -4204,6 +4374,8 @@ bfa_flash_erase_part(struct bfa_flash_s *flash, enum bfa_flash_part_type type,
        flash->instance = instance;
 
        bfa_flash_erase_send(flash);
+       bfa_flash_aen_audit_post(flash->ioc, BFA_AUDIT_AEN_FLASH_ERASE,
+                               instance, type);
        return BFA_STATUS_OK;
 }
 
@@ -5416,3 +5588,396 @@ bfa_phy_intr(void *phyarg, struct bfi_mbmsg_s *msg)
                WARN_ON(1);
        }
 }
+
+/*
+ *     DCONF module specific
+ */
+
+BFA_MODULE(dconf);
+
+/*
+ * DCONF state machine events
+ */
+enum bfa_dconf_event {
+       BFA_DCONF_SM_INIT               = 1,    /* dconf Init */
+       BFA_DCONF_SM_FLASH_COMP         = 2,    /* read/write to flash */
+       BFA_DCONF_SM_WR                 = 3,    /* binding change, map */
+       BFA_DCONF_SM_TIMEOUT            = 4,    /* Start timer */
+       BFA_DCONF_SM_EXIT               = 5,    /* exit dconf module */
+       BFA_DCONF_SM_IOCDISABLE         = 6,    /* IOC disable event */
+};
+
+/* forward declaration of DCONF state machine */
+static void bfa_dconf_sm_uninit(struct bfa_dconf_mod_s *dconf,
+                               enum bfa_dconf_event event);
+static void bfa_dconf_sm_flash_read(struct bfa_dconf_mod_s *dconf,
+                               enum bfa_dconf_event event);
+static void bfa_dconf_sm_ready(struct bfa_dconf_mod_s *dconf,
+                               enum bfa_dconf_event event);
+static void bfa_dconf_sm_dirty(struct bfa_dconf_mod_s *dconf,
+                               enum bfa_dconf_event event);
+static void bfa_dconf_sm_sync(struct bfa_dconf_mod_s *dconf,
+                               enum bfa_dconf_event event);
+static void bfa_dconf_sm_final_sync(struct bfa_dconf_mod_s *dconf,
+                               enum bfa_dconf_event event);
+static void bfa_dconf_sm_iocdown_dirty(struct bfa_dconf_mod_s *dconf,
+                               enum bfa_dconf_event event);
+
+static void bfa_dconf_cbfn(void *dconf, bfa_status_t status);
+static void bfa_dconf_timer(void *cbarg);
+static bfa_status_t bfa_dconf_flash_write(struct bfa_dconf_mod_s *dconf);
+static void bfa_dconf_init_cb(void *arg, bfa_status_t status);
+
+/*
+ * Begining state of dconf module. Waiting for an event to start.
+ */
+static void
+bfa_dconf_sm_uninit(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event)
+{
+       bfa_status_t bfa_status;
+       bfa_trc(dconf->bfa, event);
+
+       switch (event) {
+       case BFA_DCONF_SM_INIT:
+               if (dconf->min_cfg) {
+                       bfa_trc(dconf->bfa, dconf->min_cfg);
+                       return;
+               }
+               bfa_sm_set_state(dconf, bfa_dconf_sm_flash_read);
+               dconf->flashdone = BFA_FALSE;
+               bfa_trc(dconf->bfa, dconf->flashdone);
+               bfa_status = bfa_flash_read_part(BFA_FLASH(dconf->bfa),
+                                       BFA_FLASH_PART_DRV, dconf->instance,
+                                       dconf->dconf,
+                                       sizeof(struct bfa_dconf_s), 0,
+                                       bfa_dconf_init_cb, dconf->bfa);
+               if (bfa_status != BFA_STATUS_OK) {
+                       bfa_dconf_init_cb(dconf->bfa, BFA_STATUS_FAILED);
+                       bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);
+                       return;
+               }
+               break;
+       case BFA_DCONF_SM_EXIT:
+               dconf->flashdone = BFA_TRUE;
+       case BFA_DCONF_SM_IOCDISABLE:
+       case BFA_DCONF_SM_WR:
+       case BFA_DCONF_SM_FLASH_COMP:
+               break;
+       default:
+               bfa_sm_fault(dconf->bfa, event);
+       }
+}
+
+/*
+ * Read flash for dconf entries and make a call back to the driver once done.
+ */
+static void
+bfa_dconf_sm_flash_read(struct bfa_dconf_mod_s *dconf,
+                       enum bfa_dconf_event event)
+{
+       bfa_trc(dconf->bfa, event);
+
+       switch (event) {
+       case BFA_DCONF_SM_FLASH_COMP:
+               bfa_sm_set_state(dconf, bfa_dconf_sm_ready);
+               break;
+       case BFA_DCONF_SM_TIMEOUT:
+               bfa_sm_set_state(dconf, bfa_dconf_sm_ready);
+               break;
+       case BFA_DCONF_SM_EXIT:
+               dconf->flashdone = BFA_TRUE;
+               bfa_trc(dconf->bfa, dconf->flashdone);
+       case BFA_DCONF_SM_IOCDISABLE:
+               bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);
+               break;
+       default:
+               bfa_sm_fault(dconf->bfa, event);
+       }
+}
+
+/*
+ * DCONF Module is in ready state. Has completed the initialization.
+ */
+static void
+bfa_dconf_sm_ready(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event)
+{
+       bfa_trc(dconf->bfa, event);
+
+       switch (event) {
+       case BFA_DCONF_SM_WR:
+               bfa_timer_start(dconf->bfa, &dconf->timer,
+                       bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV);
+               bfa_sm_set_state(dconf, bfa_dconf_sm_dirty);
+               break;
+       case BFA_DCONF_SM_EXIT:
+               dconf->flashdone = BFA_TRUE;
+               bfa_trc(dconf->bfa, dconf->flashdone);
+               bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);
+               break;
+       case BFA_DCONF_SM_INIT:
+       case BFA_DCONF_SM_IOCDISABLE:
+               break;
+       default:
+               bfa_sm_fault(dconf->bfa, event);
+       }
+}
+
+/*
+ * entries are dirty, write back to the flash.
+ */
+
+static void
+bfa_dconf_sm_dirty(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event)
+{
+       bfa_trc(dconf->bfa, event);
+
+       switch (event) {
+       case BFA_DCONF_SM_TIMEOUT:
+               bfa_sm_set_state(dconf, bfa_dconf_sm_sync);
+               bfa_dconf_flash_write(dconf);
+               break;
+       case BFA_DCONF_SM_WR:
+               bfa_timer_stop(&dconf->timer);
+               bfa_timer_start(dconf->bfa, &dconf->timer,
+                       bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV);
+               break;
+       case BFA_DCONF_SM_EXIT:
+               bfa_timer_stop(&dconf->timer);
+               bfa_timer_start(dconf->bfa, &dconf->timer,
+                       bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV);
+               bfa_sm_set_state(dconf, bfa_dconf_sm_final_sync);
+               bfa_dconf_flash_write(dconf);
+               break;
+       case BFA_DCONF_SM_FLASH_COMP:
+               break;
+       case BFA_DCONF_SM_IOCDISABLE:
+               bfa_timer_stop(&dconf->timer);
+               bfa_sm_set_state(dconf, bfa_dconf_sm_iocdown_dirty);
+               break;
+       default:
+               bfa_sm_fault(dconf->bfa, event);
+       }
+}
+
+/*
+ * Sync the dconf entries to the flash.
+ */
+static void
+bfa_dconf_sm_final_sync(struct bfa_dconf_mod_s *dconf,
+                       enum bfa_dconf_event event)
+{
+       bfa_trc(dconf->bfa, event);
+
+       switch (event) {
+       case BFA_DCONF_SM_IOCDISABLE:
+       case BFA_DCONF_SM_FLASH_COMP:
+               bfa_timer_stop(&dconf->timer);
+       case BFA_DCONF_SM_TIMEOUT:
+               bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);
+               dconf->flashdone = BFA_TRUE;
+               bfa_trc(dconf->bfa, dconf->flashdone);
+               bfa_ioc_disable(&dconf->bfa->ioc);
+               break;
+       default:
+               bfa_sm_fault(dconf->bfa, event);
+       }
+}
+
+static void
+bfa_dconf_sm_sync(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event)
+{
+       bfa_trc(dconf->bfa, event);
+
+       switch (event) {
+       case BFA_DCONF_SM_FLASH_COMP:
+               bfa_sm_set_state(dconf, bfa_dconf_sm_ready);
+               break;
+       case BFA_DCONF_SM_WR:
+               bfa_timer_start(dconf->bfa, &dconf->timer,
+                       bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV);
+               bfa_sm_set_state(dconf, bfa_dconf_sm_dirty);
+               break;
+       case BFA_DCONF_SM_EXIT:
+               bfa_timer_start(dconf->bfa, &dconf->timer,
+                       bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV);
+               bfa_sm_set_state(dconf, bfa_dconf_sm_final_sync);
+               break;
+       case BFA_DCONF_SM_IOCDISABLE:
+               bfa_sm_set_state(dconf, bfa_dconf_sm_iocdown_dirty);
+               break;
+       default:
+               bfa_sm_fault(dconf->bfa, event);
+       }
+}
+
+static void
+bfa_dconf_sm_iocdown_dirty(struct bfa_dconf_mod_s *dconf,
+                       enum bfa_dconf_event event)
+{
+       bfa_trc(dconf->bfa, event);
+
+       switch (event) {
+       case BFA_DCONF_SM_INIT:
+               bfa_timer_start(dconf->bfa, &dconf->timer,
+                       bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV);
+               bfa_sm_set_state(dconf, bfa_dconf_sm_dirty);
+               break;
+       case BFA_DCONF_SM_EXIT:
+               dconf->flashdone = BFA_TRUE;
+               bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);
+               break;
+       case BFA_DCONF_SM_IOCDISABLE:
+               break;
+       default:
+               bfa_sm_fault(dconf->bfa, event);
+       }
+}
+
+/*
+ * Compute and return memory needed by DRV_CFG module.
+ */
+static void
+bfa_dconf_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo,
+                 struct bfa_s *bfa)
+{
+       struct bfa_mem_kva_s *dconf_kva = BFA_MEM_DCONF_KVA(bfa);
+
+       if (cfg->drvcfg.min_cfg)
+               bfa_mem_kva_setup(meminfo, dconf_kva,
+                               sizeof(struct bfa_dconf_hdr_s));
+       else
+               bfa_mem_kva_setup(meminfo, dconf_kva,
+                               sizeof(struct bfa_dconf_s));
+}
+
+static void
+bfa_dconf_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
+               struct bfa_pcidev_s *pcidev)
+{
+       struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa);
+
+       dconf->bfad = bfad;
+       dconf->bfa = bfa;
+       dconf->instance = bfa->ioc.port_id;
+       bfa_trc(bfa, dconf->instance);
+
+       dconf->dconf = (struct bfa_dconf_s *) bfa_mem_kva_curp(dconf);
+       if (cfg->drvcfg.min_cfg) {
+               bfa_mem_kva_curp(dconf) += sizeof(struct bfa_dconf_hdr_s);
+               dconf->min_cfg = BFA_TRUE;
+               /*
+                * Set the flashdone flag to TRUE explicitly as no flash
+                * write will happen in min_cfg mode.
+                */
+               dconf->flashdone = BFA_TRUE;
+       } else {
+               dconf->min_cfg = BFA_FALSE;
+               bfa_mem_kva_curp(dconf) += sizeof(struct bfa_dconf_s);
+       }
+
+       bfa_dconf_read_data_valid(bfa) = BFA_FALSE;
+       bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);
+}
+
+static void
+bfa_dconf_init_cb(void *arg, bfa_status_t status)
+{
+       struct bfa_s *bfa = arg;
+       struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa);
+
+       dconf->flashdone = BFA_TRUE;
+       bfa_trc(bfa, dconf->flashdone);
+       bfa_iocfc_cb_dconf_modinit(bfa, status);
+       if (status == BFA_STATUS_OK) {
+               bfa_dconf_read_data_valid(bfa) = BFA_TRUE;
+               if (dconf->dconf->hdr.signature != BFI_DCONF_SIGNATURE)
+                       dconf->dconf->hdr.signature = BFI_DCONF_SIGNATURE;
+               if (dconf->dconf->hdr.version != BFI_DCONF_VERSION)
+                       dconf->dconf->hdr.version = BFI_DCONF_VERSION;
+       }
+       bfa_sm_send_event(dconf, BFA_DCONF_SM_FLASH_COMP);
+}
+
+void
+bfa_dconf_modinit(struct bfa_s *bfa)
+{
+       struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa);
+       bfa_sm_send_event(dconf, BFA_DCONF_SM_INIT);
+}
+static void
+bfa_dconf_start(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_dconf_stop(struct bfa_s *bfa)
+{
+}
+
+static void bfa_dconf_timer(void *cbarg)
+{
+       struct bfa_dconf_mod_s *dconf = cbarg;
+       bfa_sm_send_event(dconf, BFA_DCONF_SM_TIMEOUT);
+}
+static void
+bfa_dconf_iocdisable(struct bfa_s *bfa)
+{
+       struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa);
+       bfa_sm_send_event(dconf, BFA_DCONF_SM_IOCDISABLE);
+}
+
+static void
+bfa_dconf_detach(struct bfa_s *bfa)
+{
+}
+
+static bfa_status_t
+bfa_dconf_flash_write(struct bfa_dconf_mod_s *dconf)
+{
+       bfa_status_t bfa_status;
+       bfa_trc(dconf->bfa, 0);
+
+       bfa_status = bfa_flash_update_part(BFA_FLASH(dconf->bfa),
+                               BFA_FLASH_PART_DRV, dconf->instance,
+                               dconf->dconf,  sizeof(struct bfa_dconf_s), 0,
+                               bfa_dconf_cbfn, dconf);
+       if (bfa_status != BFA_STATUS_OK)
+               WARN_ON(bfa_status);
+       bfa_trc(dconf->bfa, bfa_status);
+
+       return bfa_status;
+}
+
+bfa_status_t
+bfa_dconf_update(struct bfa_s *bfa)
+{
+       struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa);
+       bfa_trc(dconf->bfa, 0);
+       if (bfa_sm_cmp_state(dconf, bfa_dconf_sm_iocdown_dirty))
+               return BFA_STATUS_FAILED;
+
+       if (dconf->min_cfg) {
+               bfa_trc(dconf->bfa, dconf->min_cfg);
+               return BFA_STATUS_FAILED;
+       }
+
+       bfa_sm_send_event(dconf, BFA_DCONF_SM_WR);
+       return BFA_STATUS_OK;
+}
+
+static void
+bfa_dconf_cbfn(void *arg, bfa_status_t status)
+{
+       struct bfa_dconf_mod_s *dconf = arg;
+       WARN_ON(status);
+       bfa_sm_send_event(dconf, BFA_DCONF_SM_FLASH_COMP);
+}
+
+void
+bfa_dconf_modexit(struct bfa_s *bfa)
+{
+       struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa);
+       BFA_DCONF_MOD(bfa)->flashdone = BFA_FALSE;
+       bfa_trc(bfa, BFA_DCONF_MOD(bfa)->flashdone);
+       bfa_sm_send_event(dconf, BFA_DCONF_SM_EXIT);
+}
index c5ecd2e..546d46b 100644 (file)
@@ -327,6 +327,7 @@ struct bfa_ioc_s {
        enum bfa_mode_s         port_mode;
        u8                      ad_cap_bm;      /* adapter cap bit mask */
        u8                      port_mode_cfg;  /* config port mode */
+       int                     ioc_aen_seq;
 };
 
 struct bfa_ioc_hwif_s {
@@ -366,6 +367,8 @@ struct bfa_cb_qe_s {
        struct list_head        qe;
        bfa_cb_cbfn_t   cbfn;
        bfa_boolean_t   once;
+       bfa_boolean_t   pre_rmv;        /* set for stack based qe(s) */
+       bfa_status_t    fw_status;      /* to access fw status in comp proc */
        void            *cbarg;
 };
 
@@ -658,7 +661,6 @@ struct bfa_phy_s {
        struct bfa_ioc_notify_s ioc_notify; /* ioc event notify */
        struct bfa_mem_dma_s    phy_dma;
 };
-
 #define BFA_PHY(__bfa) (&(__bfa)->modules.phy)
 #define BFA_MEM_PHY_DMA(__bfa) (&(BFA_PHY(__bfa)->phy_dma))
 
@@ -683,6 +685,49 @@ void bfa_phy_memclaim(struct bfa_phy_s *phy,
                u8 *dm_kva, u64 dm_pa, bfa_boolean_t mincfg);
 void bfa_phy_intr(void *phyarg, struct bfi_mbmsg_s *msg);
 
+/*
+ * Driver Config( dconf) specific
+ */
+#define BFI_DCONF_SIGNATURE    0xabcdabcd
+#define BFI_DCONF_VERSION      1
+
+#pragma pack(1)
+struct bfa_dconf_hdr_s {
+       u32     signature;
+       u32     version;
+};
+
+struct bfa_dconf_s {
+       struct bfa_dconf_hdr_s          hdr;
+       struct bfa_lunmask_cfg_s        lun_mask;
+};
+#pragma pack()
+
+struct bfa_dconf_mod_s {
+       bfa_sm_t                sm;
+       u8                      instance;
+       bfa_boolean_t           flashdone;
+       bfa_boolean_t           read_data_valid;
+       bfa_boolean_t           min_cfg;
+       struct bfa_timer_s      timer;
+       struct bfa_s            *bfa;
+       void                    *bfad;
+       void                    *trcmod;
+       struct bfa_dconf_s      *dconf;
+       struct bfa_mem_kva_s    kva_seg;
+};
+
+#define BFA_DCONF_MOD(__bfa)   \
+       (&(__bfa)->modules.dconf_mod)
+#define BFA_MEM_DCONF_KVA(__bfa)       (&(BFA_DCONF_MOD(__bfa)->kva_seg))
+#define bfa_dconf_read_data_valid(__bfa)       \
+       (BFA_DCONF_MOD(__bfa)->read_data_valid)
+#define BFA_DCONF_UPDATE_TOV   5000    /* memtest timeout in msec */
+
+void   bfa_dconf_modinit(struct bfa_s *bfa);
+void   bfa_dconf_modexit(struct bfa_s *bfa);
+bfa_status_t   bfa_dconf_update(struct bfa_s *bfa);
+
 /*
  *     IOC specfic macros
  */
@@ -803,6 +848,7 @@ void bfa_ioc_fwver_get(struct bfa_ioc_s *ioc,
                        struct bfi_ioc_image_hdr_s *fwhdr);
 bfa_boolean_t bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc,
                        struct bfi_ioc_image_hdr_s *fwhdr);
+void bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event);
 bfa_status_t bfa_ioc_fw_stats_get(struct bfa_ioc_s *ioc, void *stats);
 bfa_status_t bfa_ioc_fw_stats_clear(struct bfa_ioc_s *ioc);
 
index 1c6efd4..2d36e48 100644 (file)
@@ -44,6 +44,7 @@ struct bfa_modules_s {
        struct bfa_flash_s      flash;          /*  flash module */
        struct bfa_diag_s       diag_mod;       /*  diagnostics module  */
        struct bfa_phy_s        phy;            /*  phy module          */
+       struct bfa_dconf_mod_s  dconf_mod;      /*  DCONF common module */
 };
 
 /*
@@ -119,6 +120,7 @@ struct bfa_s {
        struct list_head        reqq_waitq[BFI_IOC_MAX_CQS];
        bfa_boolean_t           fcs;            /*  FCS is attached to BFA */
        struct bfa_msix_s       msix;
+       int                     bfa_aen_seq;
 };
 
 extern bfa_boolean_t bfa_auto_recover;
@@ -130,5 +132,6 @@ extern struct bfa_module_s hal_mod_lps;
 extern struct bfa_module_s hal_mod_uf;
 extern struct bfa_module_s hal_mod_rport;
 extern struct bfa_module_s hal_mod_fcp;
+extern struct bfa_module_s hal_mod_dconf;
 
 #endif /* __BFA_MODULES_H__ */
index 21caaef..aa8a0ea 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #include "bfad_drv.h"
+#include "bfad_im.h"
 #include "bfa_plog.h"
 #include "bfa_cs.h"
 #include "bfa_modules.h"
@@ -2007,6 +2008,24 @@ bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
        }
 }
 
+static void
+bfa_fcport_aen_post(struct bfa_fcport_s *fcport, enum bfa_port_aen_event event)
+{
+       struct bfad_s *bfad = (struct bfad_s *)fcport->bfa->bfad;
+       struct bfa_aen_entry_s  *aen_entry;
+
+       bfad_get_aen_entry(bfad, aen_entry);
+       if (!aen_entry)
+               return;
+
+       aen_entry->aen_data.port.ioc_type = bfa_get_type(fcport->bfa);
+       aen_entry->aen_data.port.pwwn = fcport->pwwn;
+
+       /* Send the AEN notification */
+       bfad_im_post_vendor_event(aen_entry, bfad, ++fcport->bfa->bfa_aen_seq,
+                                 BFA_AEN_CAT_PORT, event);
+}
+
 /*
  * FC PORT state machine functions
  */
@@ -2095,6 +2114,7 @@ bfa_fcport_sm_enabling_qwait(struct bfa_fcport_s *fcport,
                wwn2str(pwwn_buf, fcport->pwwn);
                BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                        "Base port disabled: WWN = %s\n", pwwn_buf);
+               bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISABLE);
                break;
 
        case BFA_FCPORT_SM_LINKUP:
@@ -2155,6 +2175,7 @@ bfa_fcport_sm_enabling(struct bfa_fcport_s *fcport,
                wwn2str(pwwn_buf, fcport->pwwn);
                BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                        "Base port disabled: WWN = %s\n", pwwn_buf);
+               bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISABLE);
                break;
 
        case BFA_FCPORT_SM_STOP:
@@ -2208,6 +2229,12 @@ bfa_fcport_sm_linkdown(struct bfa_fcport_s *fcport,
                wwn2str(pwwn_buf, fcport->pwwn);
                BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                        "Base port online: WWN = %s\n", pwwn_buf);
+               bfa_fcport_aen_post(fcport, BFA_PORT_AEN_ONLINE);
+
+               /* If QoS is enabled and it is not online, send AEN */
+               if (fcport->cfg.qos_enabled &&
+                   fcport->qos_attr.state != BFA_QOS_ONLINE)
+                       bfa_fcport_aen_post(fcport, BFA_PORT_AEN_QOS_NEG);
                break;
 
        case BFA_FCPORT_SM_LINKDOWN:
@@ -2234,6 +2261,7 @@ bfa_fcport_sm_linkdown(struct bfa_fcport_s *fcport,
                wwn2str(pwwn_buf, fcport->pwwn);
                BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                        "Base port disabled: WWN = %s\n", pwwn_buf);
+               bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISABLE);
                break;
 
        case BFA_FCPORT_SM_STOP:
@@ -2279,8 +2307,10 @@ bfa_fcport_sm_linkup(struct bfa_fcport_s *fcport,
                wwn2str(pwwn_buf, fcport->pwwn);
                BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                        "Base port offline: WWN = %s\n", pwwn_buf);
+               bfa_fcport_aen_post(fcport, BFA_PORT_AEN_OFFLINE);
                BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                        "Base port disabled: WWN = %s\n", pwwn_buf);
+               bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISABLE);
                break;
 
        case BFA_FCPORT_SM_LINKDOWN:
@@ -2290,26 +2320,32 @@ bfa_fcport_sm_linkup(struct bfa_fcport_s *fcport,
                bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
                                BFA_PL_EID_PORT_ST_CHANGE, 0, "Port Linkdown");
                wwn2str(pwwn_buf, fcport->pwwn);
-               if (BFA_PORT_IS_DISABLED(fcport->bfa))
+               if (BFA_PORT_IS_DISABLED(fcport->bfa)) {
                        BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                                "Base port offline: WWN = %s\n", pwwn_buf);
-               else
+                       bfa_fcport_aen_post(fcport, BFA_PORT_AEN_OFFLINE);
+               } else {
                        BFA_LOG(KERN_ERR, bfad, bfa_log_level,
                                "Base port (WWN = %s) "
                                "lost fabric connectivity\n", pwwn_buf);
+                       bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT);
+               }
                break;
 
        case BFA_FCPORT_SM_STOP:
                bfa_sm_set_state(fcport, bfa_fcport_sm_stopped);
                bfa_fcport_reset_linkinfo(fcport);
                wwn2str(pwwn_buf, fcport->pwwn);
-               if (BFA_PORT_IS_DISABLED(fcport->bfa))
+               if (BFA_PORT_IS_DISABLED(fcport->bfa)) {
                        BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                                "Base port offline: WWN = %s\n", pwwn_buf);
-               else
+                       bfa_fcport_aen_post(fcport, BFA_PORT_AEN_OFFLINE);
+               } else {
                        BFA_LOG(KERN_ERR, bfad, bfa_log_level,
                                "Base port (WWN = %s) "
                                "lost fabric connectivity\n", pwwn_buf);
+                       bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT);
+               }
                break;
 
        case BFA_FCPORT_SM_HWFAIL:
@@ -2317,13 +2353,16 @@ bfa_fcport_sm_linkup(struct bfa_fcport_s *fcport,
                bfa_fcport_reset_linkinfo(fcport);
                bfa_fcport_scn(fcport, BFA_PORT_LINKDOWN, BFA_FALSE);
                wwn2str(pwwn_buf, fcport->pwwn);
-               if (BFA_PORT_IS_DISABLED(fcport->bfa))
+               if (BFA_PORT_IS_DISABLED(fcport->bfa)) {
                        BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                                "Base port offline: WWN = %s\n", pwwn_buf);
-               else
+                       bfa_fcport_aen_post(fcport, BFA_PORT_AEN_OFFLINE);
+               } else {
                        BFA_LOG(KERN_ERR, bfad, bfa_log_level,
                                "Base port (WWN = %s) "
                                "lost fabric connectivity\n", pwwn_buf);
+                       bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT);
+               }
                break;
 
        default:
@@ -2454,6 +2493,7 @@ bfa_fcport_sm_disabling(struct bfa_fcport_s *fcport,
                wwn2str(pwwn_buf, fcport->pwwn);
                BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                        "Base port enabled: WWN = %s\n", pwwn_buf);
+               bfa_fcport_aen_post(fcport, BFA_PORT_AEN_ENABLE);
                break;
 
        case BFA_FCPORT_SM_STOP:
@@ -2508,6 +2548,7 @@ bfa_fcport_sm_disabled(struct bfa_fcport_s *fcport,
                wwn2str(pwwn_buf, fcport->pwwn);
                BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                        "Base port enabled: WWN = %s\n", pwwn_buf);
+               bfa_fcport_aen_post(fcport, BFA_PORT_AEN_ENABLE);
                break;
 
        case BFA_FCPORT_SM_DISABLE:
@@ -2874,6 +2915,9 @@ bfa_fcport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
 
        port_cfg->trl_def_speed = BFA_PORT_SPEED_1GBPS;
 
+       INIT_LIST_HEAD(&fcport->stats_pending_q);
+       INIT_LIST_HEAD(&fcport->statsclr_pending_q);
+
        bfa_reqq_winit(&fcport->reqq_wait, bfa_fcport_qresume, fcport);
 }
 
@@ -3102,30 +3146,38 @@ bfa_fcport_fcoe_stats_swap(struct bfa_fcoe_stats_s *d,
 static void
 __bfa_cb_fcport_stats_get(void *cbarg, bfa_boolean_t complete)
 {
-       struct bfa_fcport_s *fcport = cbarg;
+       struct bfa_fcport_s *fcport = (struct bfa_fcport_s *)cbarg;
+       struct bfa_cb_pending_q_s *cb;
+       struct list_head *qe, *qen;
+       union bfa_fcport_stats_u *ret;
 
        if (complete) {
-               if (fcport->stats_status == BFA_STATUS_OK) {
-                       struct timeval tv;
-
-                       /* Swap FC QoS or FCoE stats */
-                       if (bfa_ioc_get_fcmode(&fcport->bfa->ioc)) {
-                               bfa_fcport_qos_stats_swap(
-                                       &fcport->stats_ret->fcqos,
-                                       &fcport->stats->fcqos);
-                       } else {
-                               bfa_fcport_fcoe_stats_swap(
-                                       &fcport->stats_ret->fcoe,
-                                       &fcport->stats->fcoe);
-
-                               do_gettimeofday(&tv);
-                               fcport->stats_ret->fcoe.secs_reset =
+               struct timeval tv;
+               if (fcport->stats_status == BFA_STATUS_OK)
+                       do_gettimeofday(&tv);
+
+               list_for_each_safe(qe, qen, &fcport->stats_pending_q) {
+                       bfa_q_deq(&fcport->stats_pending_q, &qe);
+                       cb = (struct bfa_cb_pending_q_s *)qe;
+                       if (fcport->stats_status == BFA_STATUS_OK) {
+                               ret = (union bfa_fcport_stats_u *)cb->data;
+                               /* Swap FC QoS or FCoE stats */
+                               if (bfa_ioc_get_fcmode(&fcport->bfa->ioc))
+                                       bfa_fcport_qos_stats_swap(&ret->fcqos,
+                                                       &fcport->stats->fcqos);
+                               else {
+                                       bfa_fcport_fcoe_stats_swap(&ret->fcoe,
+                                                       &fcport->stats->fcoe);
+                                       ret->fcoe.secs_reset =
                                        tv.tv_sec - fcport->stats_reset_time;
+                               }
                        }
+                       bfa_cb_queue_status(fcport->bfa, &cb->hcb_qe,
+                                       fcport->stats_status);
                }
-               fcport->stats_cbfn(fcport->stats_cbarg, fcport->stats_status);
+               fcport->stats_status = BFA_STATUS_OK;
        } else {
-               fcport->stats_busy = BFA_FALSE;
+               INIT_LIST_HEAD(&fcport->stats_pending_q);
                fcport->stats_status = BFA_STATUS_OK;
        }
 }
@@ -3143,8 +3195,7 @@ bfa_fcport_stats_get_timeout(void *cbarg)
        }
 
        fcport->stats_status = BFA_STATUS_ETIMER;
-       bfa_cb_queue(fcport->bfa, &fcport->hcb_qe, __bfa_cb_fcport_stats_get,
-               fcport);
+       __bfa_cb_fcport_stats_get(fcport, BFA_TRUE);
 }
 
 static void
@@ -3174,7 +3225,9 @@ bfa_fcport_send_stats_get(void *cbarg)
 static void
 __bfa_cb_fcport_stats_clr(void *cbarg, bfa_boolean_t complete)
 {
-       struct bfa_fcport_s *fcport = cbarg;
+       struct bfa_fcport_s *fcport = (struct bfa_fcport_s *) cbarg;
+       struct bfa_cb_pending_q_s *cb;
+       struct list_head *qe, *qen;
 
        if (complete) {
                struct timeval tv;
@@ -3184,10 +3237,15 @@ __bfa_cb_fcport_stats_clr(void *cbarg, bfa_boolean_t complete)
                 */
                do_gettimeofday(&tv);
                fcport->stats_reset_time = tv.tv_sec;
-
-               fcport->stats_cbfn(fcport->stats_cbarg, fcport->stats_status);
+               list_for_each_safe(qe, qen, &fcport->statsclr_pending_q) {
+                       bfa_q_deq(&fcport->statsclr_pending_q, &qe);
+                       cb = (struct bfa_cb_pending_q_s *)qe;
+                       bfa_cb_queue_status(fcport->bfa, &cb->hcb_qe,
+                                               fcport->stats_status);
+               }
+               fcport->stats_status = BFA_STATUS_OK;
        } else {
-               fcport->stats_busy = BFA_FALSE;
+               INIT_LIST_HEAD(&fcport->statsclr_pending_q);
                fcport->stats_status = BFA_STATUS_OK;
        }
 }
@@ -3205,8 +3263,7 @@ bfa_fcport_stats_clr_timeout(void *cbarg)
        }
 
        fcport->stats_status = BFA_STATUS_ETIMER;
-       bfa_cb_queue(fcport->bfa, &fcport->hcb_qe,
-                       __bfa_cb_fcport_stats_clr, fcport);
+       __bfa_cb_fcport_stats_clr(fcport, BFA_TRUE);
 }
 
 static void
@@ -3402,6 +3459,11 @@ bfa_fcport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg)
                                fcport->use_flash_cfg = BFA_FALSE;
                        }
 
+                       if (fcport->cfg.qos_enabled)
+                               fcport->qos_attr.state = BFA_QOS_OFFLINE;
+                       else
+                               fcport->qos_attr.state = BFA_QOS_DISABLED;
+
                        bfa_sm_send_event(fcport, BFA_FCPORT_SM_FWRSP);
                }
                break;
@@ -3426,28 +3488,26 @@ bfa_fcport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg)
                /*
                 * check for timer pop before processing the rsp
                 */
-               if (fcport->stats_busy == BFA_FALSE ||
-                   fcport->stats_status == BFA_STATUS_ETIMER)
+               if (list_empty(&fcport->stats_pending_q) ||
+                   (fcport->stats_status == BFA_STATUS_ETIMER))
                        break;
 
                bfa_timer_stop(&fcport->timer);
                fcport->stats_status = i2hmsg.pstatsget_rsp->status;
-               bfa_cb_queue(fcport->bfa, &fcport->hcb_qe,
-                               __bfa_cb_fcport_stats_get, fcport);
+               __bfa_cb_fcport_stats_get(fcport, BFA_TRUE);
                break;
 
        case BFI_FCPORT_I2H_STATS_CLEAR_RSP:
                /*
                 * check for timer pop before processing the rsp
                 */
-               if (fcport->stats_busy == BFA_FALSE ||
-                   fcport->stats_status == BFA_STATUS_ETIMER)
+               if (list_empty(&fcport->statsclr_pending_q) ||
+                   (fcport->stats_status == BFA_STATUS_ETIMER))
                        break;
 
                bfa_timer_stop(&fcport->timer);
                fcport->stats_status = BFA_STATUS_OK;
-               bfa_cb_queue(fcport->bfa, &fcport->hcb_qe,
-                               __bfa_cb_fcport_stats_clr, fcport);
+               __bfa_cb_fcport_stats_clr(fcport, BFA_TRUE);
                break;
 
        case BFI_FCPORT_I2H_ENABLE_AEN:
@@ -3779,25 +3839,25 @@ bfa_fcport_get_attr(struct bfa_s *bfa, struct bfa_port_attr_s *attr)
  * Fetch port statistics (FCQoS or FCoE).
  */
 bfa_status_t
-bfa_fcport_get_stats(struct bfa_s *bfa, union bfa_fcport_stats_u *stats,
-       bfa_cb_port_t cbfn, void *cbarg)
+bfa_fcport_get_stats(struct bfa_s *bfa, struct bfa_cb_pending_q_s *cb)
 {
        struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
-       if (fcport->stats_busy) {
-               bfa_trc(bfa, fcport->stats_busy);
-               return BFA_STATUS_DEVBUSY;
-       }
+       if (bfa_ioc_is_disabled(&bfa->ioc))
+               return BFA_STATUS_IOC_DISABLED;
 
-       fcport->stats_busy  = BFA_TRUE;
-       fcport->stats_ret   = stats;
-       fcport->stats_cbfn  = cbfn;
-       fcport->stats_cbarg = cbarg;
+       if (!list_empty(&fcport->statsclr_pending_q))
+               return BFA_STATUS_DEVBUSY;
 
-       bfa_fcport_send_stats_get(fcport);
+       if (list_empty(&fcport->stats_pending_q)) {
+               list_add_tail(&cb->hcb_qe.qe, &fcport->stats_pending_q);
+               bfa_fcport_send_stats_get(fcport);
+               bfa_timer_start(bfa, &fcport->timer,
+                               bfa_fcport_stats_get_timeout,
+                               fcport, BFA_FCPORT_STATS_TOV);
+       } else
+               list_add_tail(&cb->hcb_qe.qe, &fcport->stats_pending_q);
 
-       bfa_timer_start(bfa, &fcport->timer, bfa_fcport_stats_get_timeout,
-                       fcport, BFA_FCPORT_STATS_TOV);
        return BFA_STATUS_OK;
 }
 
@@ -3805,27 +3865,25 @@ bfa_fcport_get_stats(struct bfa_s *bfa, union bfa_fcport_stats_u *stats,
  * Reset port statistics (FCQoS or FCoE).
  */
 bfa_status_t
-bfa_fcport_clear_stats(struct bfa_s *bfa, bfa_cb_port_t cbfn, void *cbarg)
+bfa_fcport_clear_stats(struct bfa_s *bfa, struct bfa_cb_pending_q_s *cb)
 {
        struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
-       if (fcport->stats_busy) {
-               bfa_trc(bfa, fcport->stats_busy);
+       if (!list_empty(&fcport->stats_pending_q))
                return BFA_STATUS_DEVBUSY;
-       }
-
-       fcport->stats_busy  = BFA_TRUE;
-       fcport->stats_cbfn  = cbfn;
-       fcport->stats_cbarg = cbarg;
 
-       bfa_fcport_send_stats_clear(fcport);
+       if (list_empty(&fcport->statsclr_pending_q)) {
+               list_add_tail(&cb->hcb_qe.qe, &fcport->statsclr_pending_q);
+               bfa_fcport_send_stats_clear(fcport);
+               bfa_timer_start(bfa, &fcport->timer,
+                               bfa_fcport_stats_clr_timeout,
+                               fcport, BFA_FCPORT_STATS_TOV);
+       } else
+               list_add_tail(&cb->hcb_qe.qe, &fcport->statsclr_pending_q);
 
-       bfa_timer_start(bfa, &fcport->timer, bfa_fcport_stats_clr_timeout,
-                       fcport, BFA_FCPORT_STATS_TOV);
        return BFA_STATUS_OK;
 }
 
-
 /*
  * Fetch port attributes.
  */
@@ -4619,6 +4677,7 @@ bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
                rp = BFA_RPORT_FROM_TAG(bfa, msg.create_rsp->bfa_handle);
                rp->fw_handle = msg.create_rsp->fw_handle;
                rp->qos_attr = msg.create_rsp->qos_attr;
+               bfa_rport_set_lunmask(bfa, rp);
                WARN_ON(msg.create_rsp->status != BFA_STATUS_OK);
                bfa_sm_send_event(rp, BFA_RPORT_SM_FWRSP);
                break;
@@ -4626,6 +4685,7 @@ bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
        case BFI_RPORT_I2H_DELETE_RSP:
                rp = BFA_RPORT_FROM_TAG(bfa, msg.delete_rsp->bfa_handle);
                WARN_ON(msg.delete_rsp->status != BFA_STATUS_OK);
+               bfa_rport_unset_lunmask(bfa, rp);
                bfa_sm_send_event(rp, BFA_RPORT_SM_FWRSP);
                break;
 
@@ -4706,6 +4766,37 @@ bfa_rport_speed(struct bfa_rport_s *rport, enum bfa_port_speed speed)
        bfa_sm_send_event(rport, BFA_RPORT_SM_SET_SPEED);
 }
 
+/* Set Rport LUN Mask */
+void
+bfa_rport_set_lunmask(struct bfa_s *bfa, struct bfa_rport_s *rp)
+{
+       struct bfa_lps_mod_s    *lps_mod = BFA_LPS_MOD(bfa);
+       wwn_t   lp_wwn, rp_wwn;
+       u8 lp_tag = (u8)rp->rport_info.lp_tag;
+
+       rp_wwn = ((struct bfa_fcs_rport_s *)rp->rport_drv)->pwwn;
+       lp_wwn = (BFA_LPS_FROM_TAG(lps_mod, rp->rport_info.lp_tag))->pwwn;
+
+       BFA_LPS_FROM_TAG(lps_mod, rp->rport_info.lp_tag)->lun_mask =
+                                       rp->lun_mask = BFA_TRUE;
+       bfa_fcpim_lunmask_rp_update(bfa, lp_wwn, rp_wwn, rp->rport_tag, lp_tag);
+}
+
+/* Unset Rport LUN mask */
+void
+bfa_rport_unset_lunmask(struct bfa_s *bfa, struct bfa_rport_s *rp)
+{
+       struct bfa_lps_mod_s    *lps_mod = BFA_LPS_MOD(bfa);
+       wwn_t   lp_wwn, rp_wwn;
+
+       rp_wwn = ((struct bfa_fcs_rport_s *)rp->rport_drv)->pwwn;
+       lp_wwn = (BFA_LPS_FROM_TAG(lps_mod, rp->rport_info.lp_tag))->pwwn;
+
+       BFA_LPS_FROM_TAG(lps_mod, rp->rport_info.lp_tag)->lun_mask =
+                               rp->lun_mask = BFA_FALSE;
+       bfa_fcpim_lunmask_rp_update(bfa, lp_wwn, rp_wwn,
+                       BFA_RPORT_TAG_INVALID, BFA_LP_TAG_INVALID);
+}
 
 /*
  * SGPG related functions
@@ -5517,11 +5608,29 @@ bfa_fcdiag_loopback(struct bfa_s *bfa, enum bfa_port_opmode opmode,
                return BFA_STATUS_PORT_NOT_DISABLED;
        }
 
-       /* Check if the speed is supported */
-       bfa_fcport_get_attr(bfa, &attr);
-       bfa_trc(fcdiag, attr.speed_supported);
-       if (speed > attr.speed_supported)
-               return BFA_STATUS_UNSUPP_SPEED;
+       /*
+        * Check if input speed is supported by the port mode
+        */
+       if (bfa_ioc_get_type(&bfa->ioc) == BFA_IOC_TYPE_FC) {
+               if (!(speed == BFA_PORT_SPEED_1GBPS ||
+                     speed == BFA_PORT_SPEED_2GBPS ||
+                     speed == BFA_PORT_SPEED_4GBPS ||
+                     speed == BFA_PORT_SPEED_8GBPS ||
+                     speed == BFA_PORT_SPEED_16GBPS ||
+                     speed == BFA_PORT_SPEED_AUTO)) {
+                       bfa_trc(fcdiag, speed);
+                       return BFA_STATUS_UNSUPP_SPEED;
+               }
+               bfa_fcport_get_attr(bfa, &attr);
+               bfa_trc(fcdiag, attr.speed_supported);
+               if (speed > attr.speed_supported)
+                       return BFA_STATUS_UNSUPP_SPEED;
+       } else {
+               if (speed != BFA_PORT_SPEED_10GBPS) {
+                       bfa_trc(fcdiag, speed);
+                       return BFA_STATUS_UNSUPP_SPEED;
+               }
+       }
 
        /* For Mezz card, port speed entered needs to be checked */
        if (bfa_mfg_is_mezz(bfa->ioc.attr->card_type)) {
index fbe513a..95adb86 100644 (file)
@@ -297,6 +297,7 @@ struct bfa_rport_s {
        void            *rport_drv;     /*  fcs/driver rport object         */
        u16     fw_handle;      /*  firmware rport handle           */
        u16     rport_tag;      /*  BFA rport tag                   */
+       u8      lun_mask;       /*  LUN mask flag                   */
        struct bfa_rport_info_s rport_info; /*  rport info from fcs/driver */
        struct bfa_reqq_wait_s reqq_wait; /*  to wait for room in reqq     */
        struct bfa_cb_qe_s hcb_qe;      /*  BFA callback qelem              */
@@ -404,6 +405,7 @@ struct bfa_lps_s {
        u8              bb_scn;         /*  local BB_SCN                */
        u8              lsrjt_rsn;      /*  LSRJT reason                */
        u8              lsrjt_expl;     /*  LSRJT explanation           */
+       u8              lun_mask;       /*  LUN mask flag               */
        wwn_t           pwwn;           /*  port wwn of lport           */
        wwn_t           nwwn;           /*  node wwn of lport           */
        wwn_t           pr_pwwn;        /*  port wwn of lport peer      */
@@ -441,7 +443,6 @@ void        bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
  */
 
 #define BFA_FCPORT(_bfa)       (&((_bfa)->modules.port))
-typedef void (*bfa_cb_port_t) (void *cbarg, enum bfa_status status);
 
 /*
  * Link notification data structure
@@ -495,13 +496,11 @@ struct bfa_fcport_s {
        u8                      *stats_kva;
        u64             stats_pa;
        union bfa_fcport_stats_u *stats;
-       union bfa_fcport_stats_u *stats_ret; /*  driver stats location */
        bfa_status_t            stats_status; /*  stats/statsclr status */
-       bfa_boolean_t           stats_busy; /*  outstanding stats/statsclr */
+       struct list_head        stats_pending_q;
+       struct list_head        statsclr_pending_q;
        bfa_boolean_t           stats_qfull;
        u32             stats_reset_time; /*  stats reset time stamp */
-       bfa_cb_port_t           stats_cbfn; /*  driver callback function */
-       void                    *stats_cbarg; /* *!< user callback arg */
        bfa_boolean_t           diag_busy; /*  diag busy status */
        bfa_boolean_t           beacon; /*  port beacon status */
        bfa_boolean_t           link_e2e_beacon; /*  link beacon status */
@@ -552,10 +551,9 @@ void bfa_fcport_beacon(void *dev, bfa_boolean_t beacon,
                        bfa_boolean_t link_e2e_beacon);
 bfa_boolean_t  bfa_fcport_is_linkup(struct bfa_s *bfa);
 bfa_status_t bfa_fcport_get_stats(struct bfa_s *bfa,
-                                 union bfa_fcport_stats_u *stats,
-                                 bfa_cb_port_t cbfn, void *cbarg);
-bfa_status_t bfa_fcport_clear_stats(struct bfa_s *bfa, bfa_cb_port_t cbfn,
-                                   void *cbarg);
+                       struct bfa_cb_pending_q_s *cb);
+bfa_status_t bfa_fcport_clear_stats(struct bfa_s *bfa,
+                       struct bfa_cb_pending_q_s *cb);
 bfa_boolean_t bfa_fcport_is_qos_enabled(struct bfa_s *bfa);
 bfa_boolean_t bfa_fcport_is_trunk_enabled(struct bfa_s *bfa);
 bfa_status_t bfa_fcport_is_pbcdisabled(struct bfa_s *bfa);
@@ -577,6 +575,19 @@ void bfa_cb_rport_qos_scn_prio(void *rport,
                               struct bfa_rport_qos_attr_s old_qos_attr,
                               struct bfa_rport_qos_attr_s new_qos_attr);
 
+/*
+ *     Rport LUN masking related
+ */
+#define BFA_RPORT_TAG_INVALID  0xffff
+#define BFA_LP_TAG_INVALID     0xff
+void   bfa_rport_set_lunmask(struct bfa_s *bfa, struct bfa_rport_s *rp);
+void   bfa_rport_unset_lunmask(struct bfa_s *bfa, struct bfa_rport_s *rp);
+bfa_boolean_t  bfa_rport_lunmask_active(struct bfa_rport_s *rp);
+wwn_t  bfa_rport_get_pwwn(struct bfa_s *bfa, struct bfa_rport_s *rp);
+struct bfa_rport_s *bfa_rport_get_by_wwn(struct bfa_s *bfa, u16 vf_id,
+                                        wwn_t *lpwwn, wwn_t rpwwn);
+void *bfa_cb_get_rp_by_wwn(void *arg, u16 vf_id, wwn_t *lpwwn, wwn_t rpwwn);
+
 /*
  * bfa fcxp API functions
  */
index beb30a7..66fb725 100644 (file)
@@ -1348,7 +1348,7 @@ int
 bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
 {
        struct bfad_s   *bfad;
-       int             error = -ENODEV, retval;
+       int             error = -ENODEV, retval, i;
 
        /* For single port cards - only claim function 0 */
        if ((pdev->device == BFA_PCI_DEVICE_ID_FC_8G1P) &&
@@ -1372,6 +1372,12 @@ bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
        bfa_trc_init(bfad->trcmod);
        bfa_trc(bfad, bfad_inst);
 
+       /* AEN INIT */
+       INIT_LIST_HEAD(&bfad->free_aen_q);
+       INIT_LIST_HEAD(&bfad->active_aen_q);
+       for (i = 0; i < BFA_AEN_MAX_ENTRY; i++)
+               list_add_tail(&bfad->aen_list[i].qe, &bfad->free_aen_q);
+
        if (!(bfad_load_fwimg(pdev))) {
                kfree(bfad->trcmod);
                goto out_alloc_trace_failure;
index 89f863e..06fc00c 100644 (file)
@@ -56,7 +56,7 @@ bfad_iocmd_ioc_disable(struct bfad_s *bfad, void *cmd)
        spin_lock_irqsave(&bfad->bfad_lock, flags);
        if (bfad->disable_active) {
                spin_unlock_irqrestore(&bfad->bfad_lock, flags);
-               return EBUSY;
+               return -EBUSY;
        }
 
        bfad->disable_active = BFA_TRUE;
@@ -90,6 +90,7 @@ bfad_iocmd_ioc_get_info(struct bfad_s *bfad, void *cmd)
        bfa_get_adapter_serial_num(&bfad->bfa, iocmd->serialnum);
        iocmd->factorynwwn = pattr.factorynwwn;
        iocmd->factorypwwn = pattr.factorypwwn;
+       iocmd->bfad_num = bfad->inst_no;
        im_port = bfad->pport.im_port;
        iocmd->host = im_port->shost->host_no;
        spin_unlock_irqrestore(&bfad->bfad_lock, flags);
@@ -177,6 +178,38 @@ out:
        return 0;
 }
 
+int
+bfad_iocmd_ioc_reset_stats(struct bfad_s *bfad, void *cmd, unsigned int v_cmd)
+{
+       struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd;
+       unsigned long   flags;
+
+       if (v_cmd == IOCMD_IOC_RESET_STATS) {
+               bfa_ioc_clear_stats(&bfad->bfa);
+               iocmd->status = BFA_STATUS_OK;
+       } else if (v_cmd == IOCMD_IOC_RESET_FWSTATS) {
+               spin_lock_irqsave(&bfad->bfad_lock, flags);
+               iocmd->status = bfa_ioc_fw_stats_clear(&bfad->bfa.ioc);
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       }
+
+       return 0;
+}
+
+int
+bfad_iocmd_ioc_set_name(struct bfad_s *bfad, void *cmd, unsigned int v_cmd)
+{
+       struct bfa_bsg_ioc_name_s *iocmd = (struct bfa_bsg_ioc_name_s *) cmd;
+
+       if (v_cmd == IOCMD_IOC_SET_ADAPTER_NAME)
+               strcpy(bfad->adapter_name, iocmd->name);
+       else if (v_cmd == IOCMD_IOC_SET_PORT_NAME)
+               strcpy(bfad->port_name, iocmd->name);
+
+       iocmd->status = BFA_STATUS_OK;
+       return 0;
+}
+
 int
 bfad_iocmd_iocfc_get_attr(struct bfad_s *bfad, void *cmd)
 {
@@ -306,6 +339,81 @@ out:
        return 0;
 }
 
+int
+bfad_iocmd_port_reset_stats(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd;
+       struct bfad_hal_comp fcomp;
+       unsigned long   flags;
+
+       init_completion(&fcomp.comp);
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       iocmd->status = bfa_port_clear_stats(&bfad->bfa.modules.port,
+                                       bfad_hcb_comp, &fcomp);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       if (iocmd->status != BFA_STATUS_OK) {
+               bfa_trc(bfad, iocmd->status);
+               return 0;
+       }
+       wait_for_completion(&fcomp.comp);
+       iocmd->status = fcomp.status;
+       return 0;
+}
+
+int
+bfad_iocmd_set_port_cfg(struct bfad_s *bfad, void *iocmd, unsigned int v_cmd)
+{
+       struct bfa_bsg_port_cfg_s *cmd = (struct bfa_bsg_port_cfg_s *)iocmd;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       if (v_cmd == IOCMD_PORT_CFG_TOPO)
+               cmd->status = bfa_fcport_cfg_topology(&bfad->bfa, cmd->param);
+       else if (v_cmd == IOCMD_PORT_CFG_SPEED)
+               cmd->status = bfa_fcport_cfg_speed(&bfad->bfa, cmd->param);
+       else if (v_cmd == IOCMD_PORT_CFG_ALPA)
+               cmd->status = bfa_fcport_cfg_hardalpa(&bfad->bfa, cmd->param);
+       else if (v_cmd == IOCMD_PORT_CLR_ALPA)
+               cmd->status = bfa_fcport_clr_hardalpa(&bfad->bfa);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+       return 0;
+}
+
+int
+bfad_iocmd_port_cfg_maxfrsize(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_port_cfg_maxfrsize_s *iocmd =
+                               (struct bfa_bsg_port_cfg_maxfrsize_s *)cmd;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       iocmd->status = bfa_fcport_cfg_maxfrsize(&bfad->bfa, iocmd->maxfrsize);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+       return 0;
+}
+
+int
+bfad_iocmd_port_cfg_bbsc(struct bfad_s *bfad, void *cmd, unsigned int v_cmd)
+{
+       struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd;
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa);
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       if (bfa_ioc_get_type(&bfad->bfa.ioc) == BFA_IOC_TYPE_FC) {
+               if (v_cmd == IOCMD_PORT_BBSC_ENABLE)
+                       fcport->cfg.bb_scn_state = BFA_TRUE;
+               else if (v_cmd == IOCMD_PORT_BBSC_DISABLE)
+                       fcport->cfg.bb_scn_state = BFA_FALSE;
+       }
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+       iocmd->status = BFA_STATUS_OK;
+       return 0;
+}
+
 static int
 bfad_iocmd_lport_get_attr(struct bfad_s *bfad, void *cmd)
 {
@@ -353,6 +461,40 @@ out:
        return 0;
 }
 
+int
+bfad_iocmd_lport_reset_stats(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_fcs_lport_s *fcs_port;
+       struct bfa_bsg_reset_stats_s *iocmd =
+                       (struct bfa_bsg_reset_stats_s *)cmd;
+       struct bfa_fcpim_s *fcpim = BFA_FCPIM(&bfad->bfa);
+       struct list_head *qe, *qen;
+       struct bfa_itnim_s *itnim;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs,
+                               iocmd->vf_id, iocmd->vpwwn);
+       if (fcs_port == NULL) {
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+               iocmd->status = BFA_STATUS_UNKNOWN_LWWN;
+               goto out;
+       }
+
+       bfa_fcs_lport_clear_stats(fcs_port);
+       /* clear IO stats from all active itnims */
+       list_for_each_safe(qe, qen, &fcpim->itnim_q) {
+               itnim = (struct bfa_itnim_s *) qe;
+               if (itnim->rport->rport_info.lp_tag != fcs_port->lp_tag)
+                       continue;
+               bfa_itnim_clear_stats(itnim);
+       }
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       iocmd->status = BFA_STATUS_OK;
+out:
+       return 0;
+}
+
 int
 bfad_iocmd_lport_get_iostats(struct bfad_s *bfad, void *cmd)
 {
@@ -389,7 +531,7 @@ bfad_iocmd_lport_get_rports(struct bfad_s *bfad, void *cmd,
        void    *iocmd_bufptr;
 
        if (iocmd->nrports == 0)
-               return EINVAL;
+               return -EINVAL;
 
        if (bfad_chk_iocmd_sz(payload_len,
                        sizeof(struct bfa_bsg_lport_get_rports_s),
@@ -539,6 +681,152 @@ out:
        return 0;
 }
 
+int
+bfad_iocmd_rport_clr_stats(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_rport_reset_stats_s *iocmd =
+                               (struct bfa_bsg_rport_reset_stats_s *)cmd;
+       struct bfa_fcs_lport_s *fcs_port;
+       struct bfa_fcs_rport_s *fcs_rport;
+       struct bfa_rport_s *rport;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs,
+                               iocmd->vf_id, iocmd->pwwn);
+       if (fcs_port == NULL) {
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+               iocmd->status = BFA_STATUS_UNKNOWN_LWWN;
+               goto out;
+       }
+
+       fcs_rport = bfa_fcs_rport_lookup(fcs_port, iocmd->rpwwn);
+       if (fcs_rport == NULL) {
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+               iocmd->status = BFA_STATUS_UNKNOWN_RWWN;
+               goto out;
+       }
+
+       memset((char *)&fcs_rport->stats, 0, sizeof(struct bfa_rport_stats_s));
+       rport = bfa_fcs_rport_get_halrport(fcs_rport);
+       memset(&rport->stats, 0, sizeof(rport->stats));
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       iocmd->status = BFA_STATUS_OK;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_rport_set_speed(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_rport_set_speed_s *iocmd =
+                               (struct bfa_bsg_rport_set_speed_s *)cmd;
+       struct bfa_fcs_lport_s *fcs_port;
+       struct bfa_fcs_rport_s *fcs_rport;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs,
+                               iocmd->vf_id, iocmd->pwwn);
+       if (fcs_port == NULL) {
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+               iocmd->status = BFA_STATUS_UNKNOWN_LWWN;
+               goto out;
+       }
+
+       fcs_rport = bfa_fcs_rport_lookup(fcs_port, iocmd->rpwwn);
+       if (fcs_rport == NULL) {
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+               iocmd->status = BFA_STATUS_UNKNOWN_RWWN;
+               goto out;
+       }
+
+       fcs_rport->rpf.assigned_speed  = iocmd->speed;
+       /* Set this speed in f/w only if the RPSC speed is not available */
+       if (fcs_rport->rpf.rpsc_speed == BFA_PORT_SPEED_UNKNOWN)
+               bfa_rport_speed(fcs_rport->bfa_rport, iocmd->speed);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       iocmd->status = BFA_STATUS_OK;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_vport_get_attr(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_fcs_vport_s *fcs_vport;
+       struct bfa_bsg_vport_attr_s *iocmd = (struct bfa_bsg_vport_attr_s *)cmd;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs,
+                               iocmd->vf_id, iocmd->vpwwn);
+       if (fcs_vport == NULL) {
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+               iocmd->status = BFA_STATUS_UNKNOWN_VWWN;
+               goto out;
+       }
+
+       bfa_fcs_vport_get_attr(fcs_vport, &iocmd->vport_attr);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       iocmd->status = BFA_STATUS_OK;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_vport_get_stats(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_fcs_vport_s *fcs_vport;
+       struct bfa_bsg_vport_stats_s *iocmd =
+                               (struct bfa_bsg_vport_stats_s *)cmd;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs,
+                               iocmd->vf_id, iocmd->vpwwn);
+       if (fcs_vport == NULL) {
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+               iocmd->status = BFA_STATUS_UNKNOWN_VWWN;
+               goto out;
+       }
+
+       memcpy((void *)&iocmd->vport_stats, (void *)&fcs_vport->vport_stats,
+               sizeof(struct bfa_vport_stats_s));
+       memcpy((void *)&iocmd->vport_stats.port_stats,
+              (void *)&fcs_vport->lport.stats,
+               sizeof(struct bfa_lport_stats_s));
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       iocmd->status = BFA_STATUS_OK;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_vport_clr_stats(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_fcs_vport_s *fcs_vport;
+       struct bfa_bsg_reset_stats_s *iocmd =
+                               (struct bfa_bsg_reset_stats_s *)cmd;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs,
+                               iocmd->vf_id, iocmd->vpwwn);
+       if (fcs_vport == NULL) {
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+               iocmd->status = BFA_STATUS_UNKNOWN_VWWN;
+               goto out;
+       }
+
+       memset(&fcs_vport->vport_stats, 0, sizeof(struct bfa_vport_stats_s));
+       memset(&fcs_vport->lport.stats, 0, sizeof(struct bfa_lport_stats_s));
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       iocmd->status = BFA_STATUS_OK;
+out:
+       return 0;
+}
+
 static int
 bfad_iocmd_fabric_get_lports(struct bfad_s *bfad, void *cmd,
                        unsigned int payload_len)
@@ -581,6 +869,66 @@ out:
        return 0;
 }
 
+int
+bfad_iocmd_ratelim(struct bfad_s *bfad, unsigned int cmd, void *pcmd)
+{
+       struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)pcmd;
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa);
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+
+       if (cmd == IOCMD_RATELIM_ENABLE)
+               fcport->cfg.ratelimit = BFA_TRUE;
+       else if (cmd == IOCMD_RATELIM_DISABLE)
+               fcport->cfg.ratelimit = BFA_FALSE;
+
+       if (fcport->cfg.trl_def_speed == BFA_PORT_SPEED_UNKNOWN)
+               fcport->cfg.trl_def_speed = BFA_PORT_SPEED_1GBPS;
+
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       iocmd->status = BFA_STATUS_OK;
+
+       return 0;
+}
+
+int
+bfad_iocmd_ratelim_speed(struct bfad_s *bfad, unsigned int cmd, void *pcmd)
+{
+       struct bfa_bsg_trl_speed_s *iocmd = (struct bfa_bsg_trl_speed_s *)pcmd;
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa);
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+
+       /* Auto and speeds greater than the supported speed, are invalid */
+       if ((iocmd->speed == BFA_PORT_SPEED_AUTO) ||
+           (iocmd->speed > fcport->speed_sup)) {
+               iocmd->status = BFA_STATUS_UNSUPP_SPEED;
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+               return 0;
+       }
+
+       fcport->cfg.trl_def_speed = iocmd->speed;
+       iocmd->status = BFA_STATUS_OK;
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+       return 0;
+}
+
+int
+bfad_iocmd_cfg_fcpim(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_fcpim_s *iocmd = (struct bfa_bsg_fcpim_s *)cmd;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       bfa_fcpim_path_tov_set(&bfad->bfa, iocmd->param);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       iocmd->status = BFA_STATUS_OK;
+       return 0;
+}
+
 int
 bfad_iocmd_fcpim_get_modstats(struct bfad_s *bfad, void *cmd)
 {
@@ -603,6 +951,28 @@ bfad_iocmd_fcpim_get_modstats(struct bfad_s *bfad, void *cmd)
        return 0;
 }
 
+int
+bfad_iocmd_fcpim_clr_modstats(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_fcpim_modstatsclr_s *iocmd =
+                               (struct bfa_bsg_fcpim_modstatsclr_s *)cmd;
+       struct bfa_fcpim_s *fcpim = BFA_FCPIM(&bfad->bfa);
+       struct list_head *qe, *qen;
+       struct bfa_itnim_s *itnim;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       list_for_each_safe(qe, qen, &fcpim->itnim_q) {
+               itnim = (struct bfa_itnim_s *) qe;
+               bfa_itnim_clear_stats(itnim);
+       }
+       memset(&fcpim->del_itn_stats, 0,
+               sizeof(struct bfa_fcpim_del_itn_stats_s));
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       iocmd->status = BFA_STATUS_OK;
+       return 0;
+}
+
 int
 bfad_iocmd_fcpim_get_del_itn_stats(struct bfad_s *bfad, void *cmd)
 {
@@ -670,7 +1040,36 @@ bfad_iocmd_itnim_get_iostats(struct bfad_s *bfad, void *cmd)
 }
 
 static int
-bfad_iocmd_itnim_get_itnstats(struct bfad_s *bfad, void *cmd)
+bfad_iocmd_itnim_reset_stats(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_rport_reset_stats_s *iocmd =
+                       (struct bfa_bsg_rport_reset_stats_s *)cmd;
+       struct bfa_fcs_lport_s  *fcs_port;
+       struct bfa_fcs_itnim_s  *itnim;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs,
+                               iocmd->vf_id, iocmd->pwwn);
+       if (!fcs_port)
+               iocmd->status = BFA_STATUS_UNKNOWN_LWWN;
+       else {
+               itnim = bfa_fcs_itnim_lookup(fcs_port, iocmd->rpwwn);
+               if (itnim == NULL)
+                       iocmd->status = BFA_STATUS_UNKNOWN_RWWN;
+               else {
+                       iocmd->status = BFA_STATUS_OK;
+                       bfa_fcs_itnim_stats_clear(fcs_port, iocmd->rpwwn);
+                       bfa_itnim_clear_stats(bfa_fcs_itnim_get_halitn(itnim));
+               }
+       }
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+       return 0;
+}
+
+static int
+bfad_iocmd_itnim_get_itnstats(struct bfad_s *bfad, void *cmd)
 {
        struct bfa_bsg_itnim_itnstats_s *iocmd =
                        (struct bfa_bsg_itnim_itnstats_s *)cmd;
@@ -1511,11 +1910,545 @@ out:
        return 0;
 }
 
+#define BFA_DEBUG_FW_CORE_CHUNK_SZ     0x4000U /* 16K chunks for FW dump */
+int
+bfad_iocmd_debug_fw_core(struct bfad_s *bfad, void *cmd,
+                       unsigned int payload_len)
+{
+       struct bfa_bsg_debug_s *iocmd = (struct bfa_bsg_debug_s *)cmd;
+       void    *iocmd_bufptr;
+       unsigned long   flags;
+
+       if (bfad_chk_iocmd_sz(payload_len, sizeof(struct bfa_bsg_debug_s),
+                       BFA_DEBUG_FW_CORE_CHUNK_SZ) != BFA_STATUS_OK) {
+               iocmd->status = BFA_STATUS_VERSION_FAIL;
+               return 0;
+       }
+
+       if (iocmd->bufsz < BFA_DEBUG_FW_CORE_CHUNK_SZ ||
+                       !IS_ALIGNED(iocmd->bufsz, sizeof(u16)) ||
+                       !IS_ALIGNED(iocmd->offset, sizeof(u32))) {
+               bfa_trc(bfad, BFA_DEBUG_FW_CORE_CHUNK_SZ);
+               iocmd->status = BFA_STATUS_EINVAL;
+               goto out;
+       }
+
+       iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_debug_s);
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       iocmd->status = bfa_ioc_debug_fwcore(&bfad->bfa.ioc, iocmd_bufptr,
+                               (u32 *)&iocmd->offset, &iocmd->bufsz);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_debug_ctl(struct bfad_s *bfad, void *cmd, unsigned int v_cmd)
+{
+       struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd;
+       unsigned long   flags;
+
+       if (v_cmd == IOCMD_DEBUG_FW_STATE_CLR) {
+               spin_lock_irqsave(&bfad->bfad_lock, flags);
+               bfad->bfa.ioc.dbg_fwsave_once = BFA_TRUE;
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       } else if (v_cmd == IOCMD_DEBUG_PORTLOG_CLR)
+               bfad->plog_buf.head = bfad->plog_buf.tail = 0;
+       else if (v_cmd == IOCMD_DEBUG_START_DTRC)
+               bfa_trc_init(bfad->trcmod);
+       else if (v_cmd == IOCMD_DEBUG_STOP_DTRC)
+               bfa_trc_stop(bfad->trcmod);
+
+       iocmd->status = BFA_STATUS_OK;
+       return 0;
+}
+
+int
+bfad_iocmd_porglog_ctl(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_portlogctl_s *iocmd = (struct bfa_bsg_portlogctl_s *)cmd;
+
+       if (iocmd->ctl == BFA_TRUE)
+               bfad->plog_buf.plog_enabled = 1;
+       else
+               bfad->plog_buf.plog_enabled = 0;
+
+       iocmd->status = BFA_STATUS_OK;
+       return 0;
+}
+
+int
+bfad_iocmd_fcpim_cfg_profile(struct bfad_s *bfad, void *cmd, unsigned int v_cmd)
+{
+       struct bfa_bsg_fcpim_profile_s *iocmd =
+                               (struct bfa_bsg_fcpim_profile_s *)cmd;
+       struct timeval  tv;
+       unsigned long   flags;
+
+       do_gettimeofday(&tv);
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       if (v_cmd == IOCMD_FCPIM_PROFILE_ON)
+               iocmd->status = bfa_fcpim_profile_on(&bfad->bfa, tv.tv_sec);
+       else if (v_cmd == IOCMD_FCPIM_PROFILE_OFF)
+               iocmd->status = bfa_fcpim_profile_off(&bfad->bfa);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+       return 0;
+}
+
+static int
+bfad_iocmd_itnim_get_ioprofile(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_itnim_ioprofile_s *iocmd =
+                               (struct bfa_bsg_itnim_ioprofile_s *)cmd;
+       struct bfa_fcs_lport_s *fcs_port;
+       struct bfa_fcs_itnim_s *itnim;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs,
+                               iocmd->vf_id, iocmd->lpwwn);
+       if (!fcs_port)
+               iocmd->status = BFA_STATUS_UNKNOWN_LWWN;
+       else {
+               itnim = bfa_fcs_itnim_lookup(fcs_port, iocmd->rpwwn);
+               if (itnim == NULL)
+                       iocmd->status = BFA_STATUS_UNKNOWN_RWWN;
+               else
+                       iocmd->status = bfa_itnim_get_ioprofile(
+                                               bfa_fcs_itnim_get_halitn(itnim),
+                                               &iocmd->ioprofile);
+       }
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       return 0;
+}
+
+int
+bfad_iocmd_fcport_get_stats(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_fcport_stats_s *iocmd =
+                               (struct bfa_bsg_fcport_stats_s *)cmd;
+       struct bfad_hal_comp fcomp;
+       unsigned long   flags;
+       struct bfa_cb_pending_q_s cb_qe;
+
+       init_completion(&fcomp.comp);
+       bfa_pending_q_init(&cb_qe, (bfa_cb_cbfn_t)bfad_hcb_comp,
+                          &fcomp, &iocmd->stats);
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       iocmd->status = bfa_fcport_get_stats(&bfad->bfa, &cb_qe);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       if (iocmd->status != BFA_STATUS_OK) {
+               bfa_trc(bfad, iocmd->status);
+               goto out;
+       }
+       wait_for_completion(&fcomp.comp);
+       iocmd->status = fcomp.status;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_fcport_reset_stats(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd;
+       struct bfad_hal_comp fcomp;
+       unsigned long   flags;
+       struct bfa_cb_pending_q_s cb_qe;
+
+       init_completion(&fcomp.comp);
+       bfa_pending_q_init(&cb_qe, (bfa_cb_cbfn_t)bfad_hcb_comp, &fcomp, NULL);
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       iocmd->status = bfa_fcport_clear_stats(&bfad->bfa, &cb_qe);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       if (iocmd->status != BFA_STATUS_OK) {
+               bfa_trc(bfad, iocmd->status);
+               goto out;
+       }
+       wait_for_completion(&fcomp.comp);
+       iocmd->status = fcomp.status;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_boot_cfg(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_boot_s *iocmd = (struct bfa_bsg_boot_s *)cmd;
+       struct bfad_hal_comp fcomp;
+       unsigned long   flags;
+
+       init_completion(&fcomp.comp);
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       iocmd->status = bfa_flash_update_part(BFA_FLASH(&bfad->bfa),
+                       BFA_FLASH_PART_BOOT, PCI_FUNC(bfad->pcidev->devfn),
+                       &iocmd->cfg, sizeof(struct bfa_boot_cfg_s), 0,
+                       bfad_hcb_comp, &fcomp);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       if (iocmd->status != BFA_STATUS_OK)
+               goto out;
+       wait_for_completion(&fcomp.comp);
+       iocmd->status = fcomp.status;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_boot_query(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_boot_s *iocmd = (struct bfa_bsg_boot_s *)cmd;
+       struct bfad_hal_comp fcomp;
+       unsigned long   flags;
+
+       init_completion(&fcomp.comp);
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       iocmd->status = bfa_flash_read_part(BFA_FLASH(&bfad->bfa),
+                       BFA_FLASH_PART_BOOT, PCI_FUNC(bfad->pcidev->devfn),
+                       &iocmd->cfg, sizeof(struct bfa_boot_cfg_s), 0,
+                       bfad_hcb_comp, &fcomp);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       if (iocmd->status != BFA_STATUS_OK)
+               goto out;
+       wait_for_completion(&fcomp.comp);
+       iocmd->status = fcomp.status;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_preboot_query(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_preboot_s *iocmd = (struct bfa_bsg_preboot_s *)cmd;
+       struct bfi_iocfc_cfgrsp_s *cfgrsp = bfad->bfa.iocfc.cfgrsp;
+       struct bfa_boot_pbc_s *pbcfg = &iocmd->cfg;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       pbcfg->enable = cfgrsp->pbc_cfg.boot_enabled;
+       pbcfg->nbluns = cfgrsp->pbc_cfg.nbluns;
+       pbcfg->speed = cfgrsp->pbc_cfg.port_speed;
+       memcpy(pbcfg->pblun, cfgrsp->pbc_cfg.blun, sizeof(pbcfg->pblun));
+       iocmd->status = BFA_STATUS_OK;
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+       return 0;
+}
+
+int
+bfad_iocmd_ethboot_cfg(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_ethboot_s *iocmd = (struct bfa_bsg_ethboot_s *)cmd;
+       struct bfad_hal_comp fcomp;
+       unsigned long   flags;
+
+       init_completion(&fcomp.comp);
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       iocmd->status = bfa_flash_update_part(BFA_FLASH(&bfad->bfa),
+                               BFA_FLASH_PART_PXECFG,
+                               bfad->bfa.ioc.port_id, &iocmd->cfg,
+                               sizeof(struct bfa_ethboot_cfg_s), 0,
+                               bfad_hcb_comp, &fcomp);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       if (iocmd->status != BFA_STATUS_OK)
+               goto out;
+       wait_for_completion(&fcomp.comp);
+       iocmd->status = fcomp.status;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_ethboot_query(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_ethboot_s *iocmd = (struct bfa_bsg_ethboot_s *)cmd;
+       struct bfad_hal_comp fcomp;
+       unsigned long   flags;
+
+       init_completion(&fcomp.comp);
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       iocmd->status = bfa_flash_read_part(BFA_FLASH(&bfad->bfa),
+                               BFA_FLASH_PART_PXECFG,
+                               bfad->bfa.ioc.port_id, &iocmd->cfg,
+                               sizeof(struct bfa_ethboot_cfg_s), 0,
+                               bfad_hcb_comp, &fcomp);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       if (iocmd->status != BFA_STATUS_OK)
+               goto out;
+       wait_for_completion(&fcomp.comp);
+       iocmd->status = fcomp.status;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_cfg_trunk(struct bfad_s *bfad, void *cmd, unsigned int v_cmd)
+{
+       struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd;
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa);
+       struct bfa_fcport_trunk_s *trunk = &fcport->trunk;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+
+       if (v_cmd == IOCMD_TRUNK_ENABLE) {
+               trunk->attr.state = BFA_TRUNK_OFFLINE;
+               bfa_fcport_disable(&bfad->bfa);
+               fcport->cfg.trunked = BFA_TRUE;
+       } else if (v_cmd == IOCMD_TRUNK_DISABLE) {
+               trunk->attr.state = BFA_TRUNK_DISABLED;
+               bfa_fcport_disable(&bfad->bfa);
+               fcport->cfg.trunked = BFA_FALSE;
+       }
+
+       if (!bfa_fcport_is_disabled(&bfad->bfa))
+               bfa_fcport_enable(&bfad->bfa);
+
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+       iocmd->status = BFA_STATUS_OK;
+       return 0;
+}
+
+int
+bfad_iocmd_trunk_get_attr(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_trunk_attr_s *iocmd = (struct bfa_bsg_trunk_attr_s *)cmd;
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa);
+       struct bfa_fcport_trunk_s *trunk = &fcport->trunk;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       memcpy((void *)&iocmd->attr, (void *)&trunk->attr,
+               sizeof(struct bfa_trunk_attr_s));
+       iocmd->attr.port_id = bfa_lps_get_base_pid(&bfad->bfa);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+       iocmd->status = BFA_STATUS_OK;
+       return 0;
+}
+
+int
+bfad_iocmd_qos(struct bfad_s *bfad, void *cmd, unsigned int v_cmd)
+{
+       struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd;
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa);
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       if (bfa_ioc_get_type(&bfad->bfa.ioc) == BFA_IOC_TYPE_FC) {
+               if (v_cmd == IOCMD_QOS_ENABLE)
+                       fcport->cfg.qos_enabled = BFA_TRUE;
+               else if (v_cmd == IOCMD_QOS_DISABLE)
+                       fcport->cfg.qos_enabled = BFA_FALSE;
+       }
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+       iocmd->status = BFA_STATUS_OK;
+       return 0;
+}
+
+int
+bfad_iocmd_qos_get_attr(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_qos_attr_s *iocmd = (struct bfa_bsg_qos_attr_s *)cmd;
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa);
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       iocmd->attr.state = fcport->qos_attr.state;
+       iocmd->attr.total_bb_cr = be32_to_cpu(fcport->qos_attr.total_bb_cr);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+       iocmd->status = BFA_STATUS_OK;
+       return 0;
+}
+
+int
+bfad_iocmd_qos_get_vc_attr(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_qos_vc_attr_s *iocmd =
+                               (struct bfa_bsg_qos_vc_attr_s *)cmd;
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa);
+       struct bfa_qos_vc_attr_s *bfa_vc_attr = &fcport->qos_vc_attr;
+       unsigned long   flags;
+       u32     i = 0;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       iocmd->attr.total_vc_count = be16_to_cpu(bfa_vc_attr->total_vc_count);
+       iocmd->attr.shared_credit  = be16_to_cpu(bfa_vc_attr->shared_credit);
+       iocmd->attr.elp_opmode_flags  =
+                               be32_to_cpu(bfa_vc_attr->elp_opmode_flags);
+
+       /* Individual VC info */
+       while (i < iocmd->attr.total_vc_count) {
+               iocmd->attr.vc_info[i].vc_credit =
+                               bfa_vc_attr->vc_info[i].vc_credit;
+               iocmd->attr.vc_info[i].borrow_credit =
+                               bfa_vc_attr->vc_info[i].borrow_credit;
+               iocmd->attr.vc_info[i].priority =
+                               bfa_vc_attr->vc_info[i].priority;
+               i++;
+       }
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+       iocmd->status = BFA_STATUS_OK;
+       return 0;
+}
+
+int
+bfad_iocmd_qos_get_stats(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_fcport_stats_s *iocmd =
+                               (struct bfa_bsg_fcport_stats_s *)cmd;
+       struct bfad_hal_comp fcomp;
+       unsigned long   flags;
+       struct bfa_cb_pending_q_s cb_qe;
+
+       init_completion(&fcomp.comp);
+       bfa_pending_q_init(&cb_qe, (bfa_cb_cbfn_t)bfad_hcb_comp,
+                          &fcomp, &iocmd->stats);
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       WARN_ON(!bfa_ioc_get_fcmode(&bfad->bfa.ioc));
+       iocmd->status = bfa_fcport_get_stats(&bfad->bfa, &cb_qe);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       if (iocmd->status != BFA_STATUS_OK) {
+               bfa_trc(bfad, iocmd->status);
+               goto out;
+       }
+       wait_for_completion(&fcomp.comp);
+       iocmd->status = fcomp.status;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_qos_reset_stats(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd;
+       struct bfad_hal_comp fcomp;
+       unsigned long   flags;
+       struct bfa_cb_pending_q_s cb_qe;
+
+       init_completion(&fcomp.comp);
+       bfa_pending_q_init(&cb_qe, (bfa_cb_cbfn_t)bfad_hcb_comp,
+                          &fcomp, NULL);
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       WARN_ON(!bfa_ioc_get_fcmode(&bfad->bfa.ioc));
+       iocmd->status = bfa_fcport_clear_stats(&bfad->bfa, &cb_qe);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       if (iocmd->status != BFA_STATUS_OK) {
+               bfa_trc(bfad, iocmd->status);
+               goto out;
+       }
+       wait_for_completion(&fcomp.comp);
+       iocmd->status = fcomp.status;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_vf_get_stats(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_vf_stats_s *iocmd =
+                       (struct bfa_bsg_vf_stats_s *)cmd;
+       struct bfa_fcs_fabric_s *fcs_vf;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       fcs_vf = bfa_fcs_vf_lookup(&bfad->bfa_fcs, iocmd->vf_id);
+       if (fcs_vf == NULL) {
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+               iocmd->status = BFA_STATUS_UNKNOWN_VFID;
+               goto out;
+       }
+       memcpy((void *)&iocmd->stats, (void *)&fcs_vf->stats,
+               sizeof(struct bfa_vf_stats_s));
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       iocmd->status = BFA_STATUS_OK;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_vf_clr_stats(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_vf_reset_stats_s *iocmd =
+                       (struct bfa_bsg_vf_reset_stats_s *)cmd;
+       struct bfa_fcs_fabric_s *fcs_vf;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       fcs_vf = bfa_fcs_vf_lookup(&bfad->bfa_fcs, iocmd->vf_id);
+       if (fcs_vf == NULL) {
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+               iocmd->status = BFA_STATUS_UNKNOWN_VFID;
+               goto out;
+       }
+       memset((void *)&fcs_vf->stats, 0, sizeof(struct bfa_vf_stats_s));
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       iocmd->status = BFA_STATUS_OK;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_lunmask(struct bfad_s *bfad, void *pcmd, unsigned int v_cmd)
+{
+       struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)pcmd;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       if (v_cmd == IOCMD_FCPIM_LUNMASK_ENABLE)
+               iocmd->status = bfa_fcpim_lunmask_update(&bfad->bfa, BFA_TRUE);
+       else if (v_cmd == IOCMD_FCPIM_LUNMASK_DISABLE)
+               iocmd->status = bfa_fcpim_lunmask_update(&bfad->bfa, BFA_FALSE);
+       else if (v_cmd == IOCMD_FCPIM_LUNMASK_CLEAR)
+               iocmd->status = bfa_fcpim_lunmask_clear(&bfad->bfa);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       return 0;
+}
+
+int
+bfad_iocmd_fcpim_lunmask_query(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_fcpim_lunmask_query_s *iocmd =
+                       (struct bfa_bsg_fcpim_lunmask_query_s *)cmd;
+       struct bfa_lunmask_cfg_s *lun_mask = &iocmd->lun_mask;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       iocmd->status = bfa_fcpim_lunmask_query(&bfad->bfa, lun_mask);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       return 0;
+}
+
+int
+bfad_iocmd_fcpim_cfg_lunmask(struct bfad_s *bfad, void *cmd, unsigned int v_cmd)
+{
+       struct bfa_bsg_fcpim_lunmask_s *iocmd =
+                               (struct bfa_bsg_fcpim_lunmask_s *)cmd;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       if (v_cmd == IOCMD_FCPIM_LUNMASK_ADD)
+               iocmd->status = bfa_fcpim_lunmask_add(&bfad->bfa, iocmd->vf_id,
+                                       &iocmd->pwwn, iocmd->rpwwn, iocmd->lun);
+       else if (v_cmd == IOCMD_FCPIM_LUNMASK_DELETE)
+               iocmd->status = bfa_fcpim_lunmask_delete(&bfad->bfa,
+                                       iocmd->vf_id, &iocmd->pwwn,
+                                       iocmd->rpwwn, iocmd->lun);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       return 0;
+}
+
 static int
 bfad_iocmd_handler(struct bfad_s *bfad, unsigned int cmd, void *iocmd,
                unsigned int payload_len)
 {
-       int rc = EINVAL;
+       int rc = -EINVAL;
 
        switch (cmd) {
        case IOCMD_IOC_ENABLE:
@@ -1536,6 +2469,14 @@ bfad_iocmd_handler(struct bfad_s *bfad, unsigned int cmd, void *iocmd,
        case IOCMD_IOC_GET_FWSTATS:
                rc = bfad_iocmd_ioc_get_fwstats(bfad, iocmd, payload_len);
                break;
+       case IOCMD_IOC_RESET_STATS:
+       case IOCMD_IOC_RESET_FWSTATS:
+               rc = bfad_iocmd_ioc_reset_stats(bfad, iocmd, cmd);
+               break;
+       case IOCMD_IOC_SET_ADAPTER_NAME:
+       case IOCMD_IOC_SET_PORT_NAME:
+               rc = bfad_iocmd_ioc_set_name(bfad, iocmd, cmd);
+               break;
        case IOCMD_IOCFC_GET_ATTR:
                rc = bfad_iocmd_iocfc_get_attr(bfad, iocmd);
                break;
@@ -1554,12 +2495,31 @@ bfad_iocmd_handler(struct bfad_s *bfad, unsigned int cmd, void *iocmd,
        case IOCMD_PORT_GET_STATS:
                rc = bfad_iocmd_port_get_stats(bfad, iocmd, payload_len);
                break;
+       case IOCMD_PORT_RESET_STATS:
+               rc = bfad_iocmd_port_reset_stats(bfad, iocmd);
+               break;
+       case IOCMD_PORT_CFG_TOPO:
+       case IOCMD_PORT_CFG_SPEED:
+       case IOCMD_PORT_CFG_ALPA:
+       case IOCMD_PORT_CLR_ALPA:
+               rc = bfad_iocmd_set_port_cfg(bfad, iocmd, cmd);
+               break;
+       case IOCMD_PORT_CFG_MAXFRSZ:
+               rc = bfad_iocmd_port_cfg_maxfrsize(bfad, iocmd);
+               break;
+       case IOCMD_PORT_BBSC_ENABLE:
+       case IOCMD_PORT_BBSC_DISABLE:
+               rc = bfad_iocmd_port_cfg_bbsc(bfad, iocmd, cmd);
+               break;
        case IOCMD_LPORT_GET_ATTR:
                rc = bfad_iocmd_lport_get_attr(bfad, iocmd);
                break;
        case IOCMD_LPORT_GET_STATS:
                rc = bfad_iocmd_lport_get_stats(bfad, iocmd);
                break;
+       case IOCMD_LPORT_RESET_STATS:
+               rc = bfad_iocmd_lport_reset_stats(bfad, iocmd);
+               break;
        case IOCMD_LPORT_GET_IOSTATS:
                rc = bfad_iocmd_lport_get_iostats(bfad, iocmd);
                break;
@@ -1575,12 +2535,40 @@ bfad_iocmd_handler(struct bfad_s *bfad, unsigned int cmd, void *iocmd,
        case IOCMD_RPORT_GET_STATS:
                rc = bfad_iocmd_rport_get_stats(bfad, iocmd);
                break;
+       case IOCMD_RPORT_RESET_STATS:
+               rc = bfad_iocmd_rport_clr_stats(bfad, iocmd);
+               break;
+       case IOCMD_RPORT_SET_SPEED:
+               rc = bfad_iocmd_rport_set_speed(bfad, iocmd);
+               break;
+       case IOCMD_VPORT_GET_ATTR:
+               rc = bfad_iocmd_vport_get_attr(bfad, iocmd);
+               break;
+       case IOCMD_VPORT_GET_STATS:
+               rc = bfad_iocmd_vport_get_stats(bfad, iocmd);
+               break;
+       case IOCMD_VPORT_RESET_STATS:
+               rc = bfad_iocmd_vport_clr_stats(bfad, iocmd);
+               break;
        case IOCMD_FABRIC_GET_LPORTS:
                rc = bfad_iocmd_fabric_get_lports(bfad, iocmd, payload_len);
                break;
+       case IOCMD_RATELIM_ENABLE:
+       case IOCMD_RATELIM_DISABLE:
+               rc = bfad_iocmd_ratelim(bfad, cmd, iocmd);
+               break;
+       case IOCMD_RATELIM_DEF_SPEED:
+               rc = bfad_iocmd_ratelim_speed(bfad, cmd, iocmd);
+               break;
+       case IOCMD_FCPIM_FAILOVER:
+               rc = bfad_iocmd_cfg_fcpim(bfad, iocmd);
+               break;
        case IOCMD_FCPIM_MODSTATS:
                rc = bfad_iocmd_fcpim_get_modstats(bfad, iocmd);
                break;
+       case IOCMD_FCPIM_MODSTATSCLR:
+               rc = bfad_iocmd_fcpim_clr_modstats(bfad, iocmd);
+               break;
        case IOCMD_FCPIM_DEL_ITN_STATS:
                rc = bfad_iocmd_fcpim_get_del_itn_stats(bfad, iocmd);
                break;
@@ -1590,6 +2578,9 @@ bfad_iocmd_handler(struct bfad_s *bfad, unsigned int cmd, void *iocmd,
        case IOCMD_ITNIM_GET_IOSTATS:
                rc = bfad_iocmd_itnim_get_iostats(bfad, iocmd);
                break;
+       case IOCMD_ITNIM_RESET_STATS:
+               rc = bfad_iocmd_itnim_reset_stats(bfad, iocmd);
+               break;
        case IOCMD_ITNIM_GET_ITNSTATS:
                rc = bfad_iocmd_itnim_get_itnstats(bfad, iocmd);
                break;
@@ -1702,11 +2693,92 @@ bfad_iocmd_handler(struct bfad_s *bfad, unsigned int cmd, void *iocmd,
        case IOCMD_DEBUG_PORTLOG:
                rc = bfad_iocmd_porglog_get(bfad, iocmd);
                break;
+       case IOCMD_DEBUG_FW_CORE:
+               rc = bfad_iocmd_debug_fw_core(bfad, iocmd, payload_len);
+               break;
+       case IOCMD_DEBUG_FW_STATE_CLR:
+       case IOCMD_DEBUG_PORTLOG_CLR:
+       case IOCMD_DEBUG_START_DTRC:
+       case IOCMD_DEBUG_STOP_DTRC:
+               rc = bfad_iocmd_debug_ctl(bfad, iocmd, cmd);
+               break;
+       case IOCMD_DEBUG_PORTLOG_CTL:
+               rc = bfad_iocmd_porglog_ctl(bfad, iocmd);
+               break;
+       case IOCMD_FCPIM_PROFILE_ON:
+       case IOCMD_FCPIM_PROFILE_OFF:
+               rc = bfad_iocmd_fcpim_cfg_profile(bfad, iocmd, cmd);
+               break;
+       case IOCMD_ITNIM_GET_IOPROFILE:
+               rc = bfad_iocmd_itnim_get_ioprofile(bfad, iocmd);
+               break;
+       case IOCMD_FCPORT_GET_STATS:
+               rc = bfad_iocmd_fcport_get_stats(bfad, iocmd);
+               break;
+       case IOCMD_FCPORT_RESET_STATS:
+               rc = bfad_iocmd_fcport_reset_stats(bfad, iocmd);
+               break;
+       case IOCMD_BOOT_CFG:
+               rc = bfad_iocmd_boot_cfg(bfad, iocmd);
+               break;
+       case IOCMD_BOOT_QUERY:
+               rc = bfad_iocmd_boot_query(bfad, iocmd);
+               break;
+       case IOCMD_PREBOOT_QUERY:
+               rc = bfad_iocmd_preboot_query(bfad, iocmd);
+               break;
+       case IOCMD_ETHBOOT_CFG:
+               rc = bfad_iocmd_ethboot_cfg(bfad, iocmd);
+               break;
+       case IOCMD_ETHBOOT_QUERY:
+               rc = bfad_iocmd_ethboot_query(bfad, iocmd);
+               break;
+       case IOCMD_TRUNK_ENABLE:
+       case IOCMD_TRUNK_DISABLE:
+               rc = bfad_iocmd_cfg_trunk(bfad, iocmd, cmd);
+               break;
+       case IOCMD_TRUNK_GET_ATTR:
+               rc = bfad_iocmd_trunk_get_attr(bfad, iocmd);
+               break;
+       case IOCMD_QOS_ENABLE:
+       case IOCMD_QOS_DISABLE:
+               rc = bfad_iocmd_qos(bfad, iocmd, cmd);
+               break;
+       case IOCMD_QOS_GET_ATTR:
+               rc = bfad_iocmd_qos_get_attr(bfad, iocmd);
+               break;
+       case IOCMD_QOS_GET_VC_ATTR:
+               rc = bfad_iocmd_qos_get_vc_attr(bfad, iocmd);
+               break;
+       case IOCMD_QOS_GET_STATS:
+               rc = bfad_iocmd_qos_get_stats(bfad, iocmd);
+               break;
+       case IOCMD_QOS_RESET_STATS:
+               rc = bfad_iocmd_qos_reset_stats(bfad, iocmd);
+               break;
+       case IOCMD_VF_GET_STATS:
+               rc = bfad_iocmd_vf_get_stats(bfad, iocmd);
+               break;
+       case IOCMD_VF_RESET_STATS:
+               rc = bfad_iocmd_vf_clr_stats(bfad, iocmd);
+               break;
+       case IOCMD_FCPIM_LUNMASK_ENABLE:
+       case IOCMD_FCPIM_LUNMASK_DISABLE:
+       case IOCMD_FCPIM_LUNMASK_CLEAR:
+               rc = bfad_iocmd_lunmask(bfad, iocmd, cmd);
+               break;
+       case IOCMD_FCPIM_LUNMASK_QUERY:
+               rc = bfad_iocmd_fcpim_lunmask_query(bfad, iocmd);
+               break;
+       case IOCMD_FCPIM_LUNMASK_ADD:
+       case IOCMD_FCPIM_LUNMASK_DELETE:
+               rc = bfad_iocmd_fcpim_cfg_lunmask(bfad, iocmd, cmd);
+               break;
        default:
-               rc = EINVAL;
+               rc = -EINVAL;
                break;
        }
-       return -rc;
+       return rc;
 }
 
 static int
index 99b0e8a..e859adb 100644 (file)
@@ -30,24 +30,48 @@ enum {
        IOCMD_IOC_GET_INFO,
        IOCMD_IOC_GET_STATS,
        IOCMD_IOC_GET_FWSTATS,
+       IOCMD_IOC_RESET_STATS,
+       IOCMD_IOC_RESET_FWSTATS,
+       IOCMD_IOC_SET_ADAPTER_NAME,
+       IOCMD_IOC_SET_PORT_NAME,
        IOCMD_IOCFC_GET_ATTR,
        IOCMD_IOCFC_SET_INTR,
        IOCMD_PORT_ENABLE,
        IOCMD_PORT_DISABLE,
        IOCMD_PORT_GET_ATTR,
        IOCMD_PORT_GET_STATS,
+       IOCMD_PORT_RESET_STATS,
+       IOCMD_PORT_CFG_TOPO,
+       IOCMD_PORT_CFG_SPEED,
+       IOCMD_PORT_CFG_ALPA,
+       IOCMD_PORT_CFG_MAXFRSZ,
+       IOCMD_PORT_CLR_ALPA,
+       IOCMD_PORT_BBSC_ENABLE,
+       IOCMD_PORT_BBSC_DISABLE,
        IOCMD_LPORT_GET_ATTR,
        IOCMD_LPORT_GET_RPORTS,
        IOCMD_LPORT_GET_STATS,
+       IOCMD_LPORT_RESET_STATS,
        IOCMD_LPORT_GET_IOSTATS,
        IOCMD_RPORT_GET_ATTR,
        IOCMD_RPORT_GET_ADDR,
        IOCMD_RPORT_GET_STATS,
+       IOCMD_RPORT_RESET_STATS,
+       IOCMD_RPORT_SET_SPEED,
+       IOCMD_VPORT_GET_ATTR,
+       IOCMD_VPORT_GET_STATS,
+       IOCMD_VPORT_RESET_STATS,
        IOCMD_FABRIC_GET_LPORTS,
+       IOCMD_RATELIM_ENABLE,
+       IOCMD_RATELIM_DISABLE,
+       IOCMD_RATELIM_DEF_SPEED,
+       IOCMD_FCPIM_FAILOVER,
        IOCMD_FCPIM_MODSTATS,
+       IOCMD_FCPIM_MODSTATSCLR,
        IOCMD_FCPIM_DEL_ITN_STATS,
        IOCMD_ITNIM_GET_ATTR,
        IOCMD_ITNIM_GET_IOSTATS,
+       IOCMD_ITNIM_RESET_STATS,
        IOCMD_ITNIM_GET_ITNSTATS,
        IOCMD_IOC_PCIFN_CFG,
        IOCMD_FCPORT_ENABLE,
@@ -86,6 +110,39 @@ enum {
        IOCMD_PHY_READ_FW,
        IOCMD_VHBA_QUERY,
        IOCMD_DEBUG_PORTLOG,
+       IOCMD_DEBUG_FW_CORE,
+       IOCMD_DEBUG_FW_STATE_CLR,
+       IOCMD_DEBUG_PORTLOG_CLR,
+       IOCMD_DEBUG_START_DTRC,
+       IOCMD_DEBUG_STOP_DTRC,
+       IOCMD_DEBUG_PORTLOG_CTL,
+       IOCMD_FCPIM_PROFILE_ON,
+       IOCMD_FCPIM_PROFILE_OFF,
+       IOCMD_ITNIM_GET_IOPROFILE,
+       IOCMD_FCPORT_GET_STATS,
+       IOCMD_FCPORT_RESET_STATS,
+       IOCMD_BOOT_CFG,
+       IOCMD_BOOT_QUERY,
+       IOCMD_PREBOOT_QUERY,
+       IOCMD_ETHBOOT_CFG,
+       IOCMD_ETHBOOT_QUERY,
+       IOCMD_TRUNK_ENABLE,
+       IOCMD_TRUNK_DISABLE,
+       IOCMD_TRUNK_GET_ATTR,
+       IOCMD_QOS_ENABLE,
+       IOCMD_QOS_DISABLE,
+       IOCMD_QOS_GET_ATTR,
+       IOCMD_QOS_GET_VC_ATTR,
+       IOCMD_QOS_GET_STATS,
+       IOCMD_QOS_RESET_STATS,
+       IOCMD_VF_GET_STATS,
+       IOCMD_VF_RESET_STATS,
+       IOCMD_FCPIM_LUNMASK_ENABLE,
+       IOCMD_FCPIM_LUNMASK_DISABLE,
+       IOCMD_FCPIM_LUNMASK_CLEAR,
+       IOCMD_FCPIM_LUNMASK_QUERY,
+       IOCMD_FCPIM_LUNMASK_ADD,
+       IOCMD_FCPIM_LUNMASK_DELETE,
 };
 
 struct bfa_bsg_gen_s {
@@ -94,6 +151,43 @@ struct bfa_bsg_gen_s {
        u16             rsvd;
 };
 
+struct bfa_bsg_portlogctl_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             rsvd;
+       bfa_boolean_t   ctl;
+       int             inst_no;
+};
+
+struct bfa_bsg_fcpim_profile_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             rsvd;
+};
+
+struct bfa_bsg_itnim_ioprofile_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             vf_id;
+       wwn_t           lpwwn;
+       wwn_t           rpwwn;
+       struct bfa_itnim_ioprofile_s ioprofile;
+};
+
+struct bfa_bsg_fcport_stats_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             rsvd;
+       union bfa_fcport_stats_u stats;
+};
+
+struct bfa_bsg_ioc_name_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             rsvd;
+       char            name[BFA_ADAPTER_SYM_NAME_LEN];
+};
+
 struct bfa_bsg_ioc_info_s {
        bfa_status_t    status;
        u16             bfad_num;
@@ -164,6 +258,20 @@ struct bfa_bsg_port_attr_s {
        struct bfa_port_attr_s  attr;
 };
 
+struct bfa_bsg_port_cfg_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             rsvd;
+       u32             param;
+       u32             rsvd1;
+};
+
+struct bfa_bsg_port_cfg_maxfrsize_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             maxfrsize;
+};
+
 struct bfa_bsg_port_stats_s {
        bfa_status_t    status;
        u16             bfad_num;
@@ -237,6 +345,47 @@ struct bfa_bsg_rport_scsi_addr_s {
        u32             lun;
 };
 
+struct bfa_bsg_rport_reset_stats_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             vf_id;
+       wwn_t           pwwn;
+       wwn_t           rpwwn;
+};
+
+struct bfa_bsg_rport_set_speed_s {
+       bfa_status_t            status;
+       u16                     bfad_num;
+       u16                     vf_id;
+       enum bfa_port_speed     speed;
+       u32                     rsvd;
+       wwn_t                   pwwn;
+       wwn_t                   rpwwn;
+};
+
+struct bfa_bsg_vport_attr_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             vf_id;
+       wwn_t           vpwwn;
+       struct bfa_vport_attr_s vport_attr;
+};
+
+struct bfa_bsg_vport_stats_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             vf_id;
+       wwn_t           vpwwn;
+       struct bfa_vport_stats_s vport_stats;
+};
+
+struct bfa_bsg_reset_stats_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             vf_id;
+       wwn_t           vpwwn;
+};
+
 struct bfa_bsg_fabric_get_lports_s {
        bfa_status_t    status;
        u16             bfad_num;
@@ -246,6 +395,19 @@ struct bfa_bsg_fabric_get_lports_s {
        u32             rsvd;
 };
 
+struct bfa_bsg_trl_speed_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             rsvd;
+       enum bfa_port_speed speed;
+};
+
+struct bfa_bsg_fcpim_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             param;
+};
+
 struct bfa_bsg_fcpim_modstats_s {
        bfa_status_t    status;
        u16             bfad_num;
@@ -258,6 +420,11 @@ struct bfa_bsg_fcpim_del_itn_stats_s {
        struct bfa_fcpim_del_itn_stats_s modstats;
 };
 
+struct bfa_bsg_fcpim_modstatsclr_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+};
+
 struct bfa_bsg_itnim_attr_s {
        bfa_status_t    status;
        u16             bfad_num;
@@ -485,6 +652,76 @@ struct bfa_bsg_vhba_attr_s {
        struct bfa_vhba_attr_s  attr;
 };
 
+struct bfa_bsg_boot_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             rsvd;
+       struct bfa_boot_cfg_s   cfg;
+};
+
+struct bfa_bsg_preboot_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             rsvd;
+       struct bfa_boot_pbc_s   cfg;
+};
+
+struct bfa_bsg_ethboot_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             rsvd;
+       struct  bfa_ethboot_cfg_s  cfg;
+};
+
+struct bfa_bsg_trunk_attr_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             rsvd;
+       struct bfa_trunk_attr_s attr;
+};
+
+struct bfa_bsg_qos_attr_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             rsvd;
+       struct bfa_qos_attr_s   attr;
+};
+
+struct bfa_bsg_qos_vc_attr_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             rsvd;
+       struct bfa_qos_vc_attr_s attr;
+};
+
+struct bfa_bsg_vf_stats_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             vf_id;
+       struct bfa_vf_stats_s   stats;
+};
+
+struct bfa_bsg_vf_reset_stats_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             vf_id;
+};
+
+struct bfa_bsg_fcpim_lunmask_query_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       struct bfa_lunmask_cfg_s lun_mask;
+};
+
+struct bfa_bsg_fcpim_lunmask_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             vf_id;
+       wwn_t           pwwn;
+       wwn_t           rpwwn;
+       struct scsi_lun lun;
+};
+
 struct bfa_bsg_fcpt_s {
        bfa_status_t    status;
        u16             vf_id;
index 48661a2..bda999a 100644 (file)
@@ -56,7 +56,7 @@
 #ifdef BFA_DRIVER_VERSION
 #define BFAD_DRIVER_VERSION    BFA_DRIVER_VERSION
 #else
-#define BFAD_DRIVER_VERSION    "3.0.2.1"
+#define BFAD_DRIVER_VERSION    "3.0.2.2"
 #endif
 
 #define BFAD_PROTO_NAME FCPI_NAME
@@ -224,6 +224,10 @@ struct bfad_s {
        char *regdata;
        u32 reglen;
        struct dentry *bfad_dentry_files[5];
+       struct list_head        free_aen_q;
+       struct list_head        active_aen_q;
+       struct bfa_aen_entry_s  aen_list[BFA_AEN_MAX_ENTRY];
+       spinlock_t              bfad_aen_spinlock;
 };
 
 /* BFAD state machine events */
index f2bf812..0131238 100644 (file)
@@ -656,6 +656,31 @@ bfad_im_port_clean(struct bfad_im_port_s *im_port)
        spin_unlock_irqrestore(&bfad->bfad_lock, flags);
 }
 
+static void bfad_aen_im_notify_handler(struct work_struct *work)
+{
+       struct bfad_im_s *im =
+               container_of(work, struct bfad_im_s, aen_im_notify_work);
+       struct bfa_aen_entry_s *aen_entry;
+       struct bfad_s *bfad = im->bfad;
+       struct Scsi_Host *shost = bfad->pport.im_port->shost;
+       void *event_data;
+       unsigned long flags;
+
+       while (!list_empty(&bfad->active_aen_q)) {
+               spin_lock_irqsave(&bfad->bfad_aen_spinlock, flags);
+               bfa_q_deq(&bfad->active_aen_q, &aen_entry);
+               spin_unlock_irqrestore(&bfad->bfad_aen_spinlock, flags);
+               event_data = (char *)aen_entry + sizeof(struct list_head);
+               fc_host_post_vendor_event(shost, fc_get_event_number(),
+                               sizeof(struct bfa_aen_entry_s) -
+                               sizeof(struct list_head),
+                               (char *)event_data, BFAD_NL_VENDOR_ID);
+               spin_lock_irqsave(&bfad->bfad_aen_spinlock, flags);
+               list_add_tail(&aen_entry->qe, &bfad->free_aen_q);
+               spin_unlock_irqrestore(&bfad->bfad_aen_spinlock, flags);
+       }
+}
+
 bfa_status_t
 bfad_im_probe(struct bfad_s *bfad)
 {
@@ -676,6 +701,7 @@ bfad_im_probe(struct bfad_s *bfad)
                rc = BFA_STATUS_FAILED;
        }
 
+       INIT_WORK(&im->aen_im_notify_work, bfad_aen_im_notify_handler);
 ext:
        return rc;
 }
index 4fe34d5..004b6cf 100644 (file)
@@ -115,8 +115,30 @@ struct bfad_im_s {
        struct bfad_s         *bfad;
        struct workqueue_struct *drv_workq;
        char            drv_workq_name[KOBJ_NAME_LEN];
+       struct work_struct      aen_im_notify_work;
 };
 
+#define bfad_get_aen_entry(_drv, _entry) do {                          \
+       unsigned long   _flags;                                         \
+       spin_lock_irqsave(&(_drv)->bfad_aen_spinlock, _flags);          \
+       bfa_q_deq(&(_drv)->free_aen_q, &(_entry));                      \
+       if (_entry)                                                     \
+               list_add_tail(&(_entry)->qe, &(_drv)->active_aen_q);    \
+       spin_unlock_irqrestore(&(_drv)->bfad_aen_spinlock, _flags);     \
+} while (0)
+
+/* post fc_host vendor event */
+#define bfad_im_post_vendor_event(_entry, _drv, _cnt, _cat, _evt) do {       \
+       do_gettimeofday(&(_entry)->aen_tv);                                   \
+       (_entry)->bfad_num = (_drv)->inst_no;                                 \
+       (_entry)->seq_num = (_cnt);                                           \
+       (_entry)->aen_category = (_cat);                                      \
+       (_entry)->aen_type = (_evt);                                          \
+       if ((_drv)->bfad_flags & BFAD_FC4_PROBE_DONE)                         \
+               queue_work((_drv)->im->drv_workq,                             \
+                          &(_drv)->im->aen_im_notify_work);                  \
+} while (0)
+
 struct Scsi_Host *bfad_scsi_host_alloc(struct bfad_im_port_s *im_port,
                                struct bfad_s *);
 bfa_status_t bfad_thread_workq(struct bfad_s *bfad);
index 1e258d5..b2ba0b2 100644 (file)
@@ -783,6 +783,17 @@ enum bfi_sfp_i2h_e {
        BFI_SFP_I2H_SCN  = BFA_I2HM(BFI_SFP_H2I_SCN),
 };
 
+/*
+ *     SFP state change notification
+ */
+struct bfi_sfp_scn_s {
+       struct bfi_mhdr_s mhr;  /* host msg header        */
+       u8      event;
+       u8      sfpid;
+       u8      pomlvl; /* pom level: normal/warning/alarm */
+       u8      is_elb; /* e-loopback */
+};
+
 /*
  *     SFP state
  */
@@ -925,6 +936,15 @@ struct bfi_flash_erase_rsp_s {
        u32     status;
 };
 
+/*
+ * Flash event notification
+ */
+struct bfi_flash_event_s {
+       struct bfi_mhdr_s       mh;     /* Common msg header */
+       bfa_status_t            status;
+       u32                     param;
+};
+
 /*
  *----------------------------------------------------------------------
  *                             DIAG
index d924236..42228ca 100644 (file)
@@ -2,7 +2,7 @@
 #define _BNX2FC_H_
 /* bnx2fc.h: Broadcom NetXtreme II Linux FCoE offload driver.
  *
- * Copyright (c) 2008 - 2010 Broadcom Corporation
+ * Copyright (c) 2008 - 2011 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
@@ -62,7 +62,7 @@
 #include "bnx2fc_constants.h"
 
 #define BNX2FC_NAME            "bnx2fc"
-#define BNX2FC_VERSION         "1.0.3"
+#define BNX2FC_VERSION         "1.0.4"
 
 #define PFX                    "bnx2fc: "
 
 
 #define BNX2FC_RNID_HBA                        0x7
 
+#define SRR_RETRY_COUNT                        5
+#define REC_RETRY_COUNT                        1
+#define BNX2FC_NUM_ERR_BITS            63
+
 /* bnx2fc driver uses only one instance of fcoe_percpu_s */
 extern struct fcoe_percpu_s bnx2fc_global;
 
@@ -153,18 +157,13 @@ struct bnx2fc_percpu_s {
 };
 
 struct bnx2fc_hba {
-       struct list_head link;
+       struct list_head list;
        struct cnic_dev *cnic;
        struct pci_dev *pcidev;
-       struct net_device *netdev;
        struct net_device *phys_dev;
        unsigned long reg_with_cnic;
                #define BNX2FC_CNIC_REGISTERED           1
-       struct packet_type fcoe_packet_type;
-       struct packet_type fip_packet_type;
        struct bnx2fc_cmd_mgr *cmd_mgr;
-       struct workqueue_struct *timer_work_queue;
-       struct kref kref;
        spinlock_t hba_lock;
        struct mutex hba_mutex;
        unsigned long adapter_state;
@@ -172,15 +171,9 @@ struct bnx2fc_hba {
                #define ADAPTER_STATE_GOING_DOWN        1
                #define ADAPTER_STATE_LINK_DOWN         2
                #define ADAPTER_STATE_READY             3
-       u32 flags;
-       unsigned long init_done;
-               #define BNX2FC_FW_INIT_DONE             0
-               #define BNX2FC_CTLR_INIT_DONE           1
-               #define BNX2FC_CREATE_DONE              2
-       struct fcoe_ctlr ctlr;
-       struct list_head vports;
-       u8 vlan_enabled;
-       int vlan_id;
+       unsigned long flags;
+               #define BNX2FC_FLAG_FW_INIT_DONE        0
+               #define BNX2FC_FLAG_DESTROY_CMPL        1
        u32 next_conn_id;
        struct fcoe_task_ctx_entry **task_ctx;
        dma_addr_t *task_ctx_dma;
@@ -199,38 +192,41 @@ struct bnx2fc_hba {
        char *dummy_buffer;
        dma_addr_t dummy_buf_dma;
 
+       /* Active list of offloaded sessions */
+       struct bnx2fc_rport **tgt_ofld_list;
+
+       /* statistics */
        struct fcoe_statistics_params *stats_buffer;
        dma_addr_t stats_buf_dma;
-
-       /*
-        * PCI related info.
-        */
-       u16 pci_did;
-       u16 pci_vid;
-       u16 pci_sdid;
-       u16 pci_svid;
-       u16 pci_func;
-       u16 pci_devno;
-
-       struct task_struct *l2_thread;
-
-       /* linkdown handling */
-       wait_queue_head_t shutdown_wait;
-       int wait_for_link_down;
+       struct completion stat_req_done;
 
        /*destroy handling */
        struct timer_list destroy_timer;
        wait_queue_head_t destroy_wait;
 
-       /* Active list of offloaded sessions */
-       struct bnx2fc_rport *tgt_ofld_list[BNX2FC_NUM_MAX_SESS];
+       /* linkdown handling */
+       wait_queue_head_t shutdown_wait;
+       int wait_for_link_down;
        int num_ofld_sess;
+       struct list_head vports;
+};
 
-       /* statistics */
-       struct completion stat_req_done;
+struct bnx2fc_interface {
+       struct list_head list;
+       unsigned long if_flags;
+               #define BNX2FC_CTLR_INIT_DONE           0
+       struct bnx2fc_hba *hba;
+       struct net_device *netdev;
+       struct packet_type fcoe_packet_type;
+       struct packet_type fip_packet_type;
+       struct workqueue_struct *timer_work_queue;
+       struct kref kref;
+       struct fcoe_ctlr ctlr;
+       u8 vlan_enabled;
+       int vlan_id;
 };
 
-#define bnx2fc_from_ctlr(fip) container_of(fip, struct bnx2fc_hba, ctlr)
+#define bnx2fc_from_ctlr(fip) container_of(fip, struct bnx2fc_interface, ctlr)
 
 struct bnx2fc_lport {
        struct list_head list;
@@ -252,9 +248,11 @@ struct bnx2fc_rport {
        struct fc_rport_priv *rdata;
        void __iomem *ctx_base;
 #define DPM_TRIGER_TYPE                0x40
+       u32 io_timeout;
        u32 fcoe_conn_id;
        u32 context_id;
        u32 sid;
+       int dev_type;
 
        unsigned long flags;
 #define BNX2FC_FLAG_SESSION_READY      0x1
@@ -262,10 +260,9 @@ struct bnx2fc_rport {
 #define BNX2FC_FLAG_DISABLED           0x3
 #define BNX2FC_FLAG_DESTROYED          0x4
 #define BNX2FC_FLAG_OFLD_REQ_CMPL      0x5
-#define BNX2FC_FLAG_DESTROY_CMPL       0x6
-#define BNX2FC_FLAG_CTX_ALLOC_FAILURE  0x7
-#define BNX2FC_FLAG_UPLD_REQ_COMPL     0x8
-#define BNX2FC_FLAG_EXPL_LOGO          0x9
+#define BNX2FC_FLAG_CTX_ALLOC_FAILURE  0x6
+#define BNX2FC_FLAG_UPLD_REQ_COMPL     0x7
+#define BNX2FC_FLAG_EXPL_LOGO          0x8
 
        u8 src_addr[ETH_ALEN];
        u32 max_sqes;
@@ -327,12 +324,9 @@ struct bnx2fc_rport {
        spinlock_t cq_lock;
        atomic_t num_active_ios;
        u32 flush_in_prog;
-       unsigned long work_time_slice;
        unsigned long timestamp;
        struct list_head free_task_list;
        struct bnx2fc_cmd *pending_queue[BNX2FC_SQ_WQES_MAX+1];
-       atomic_t pi;
-       atomic_t ci;
        struct list_head active_cmd_queue;
        struct list_head els_queue;
        struct list_head io_retire_queue;
@@ -367,6 +361,8 @@ struct bnx2fc_els_cb_arg {
        struct bnx2fc_cmd *aborted_io_req;
        struct bnx2fc_cmd *io_req;
        u16 l2_oxid;
+       u32 offset;
+       enum fc_rctl r_ctl;
 };
 
 /* bnx2fc command structure */
@@ -380,6 +376,7 @@ struct bnx2fc_cmd {
 #define BNX2FC_ABTS                    3
 #define BNX2FC_ELS                     4
 #define BNX2FC_CLEANUP                 5
+#define BNX2FC_SEQ_CLEANUP             6
        u8 io_req_flags;
        struct kref refcount;
        struct fcoe_port *port;
@@ -393,6 +390,7 @@ struct bnx2fc_cmd {
        struct completion tm_done;
        int wait_for_comp;
        u16 xid;
+       struct fcoe_err_report_entry err_entry;
        struct fcoe_task_ctx_entry *task;
        struct io_bdt *bd_tbl;
        struct fcp_rsp *rsp;
@@ -409,6 +407,12 @@ struct bnx2fc_cmd {
 #define BNX2FC_FLAG_IO_COMPL           0x9
 #define BNX2FC_FLAG_ELS_DONE           0xa
 #define BNX2FC_FLAG_ELS_TIMEOUT                0xb
+#define BNX2FC_FLAG_CMD_LOST           0xc
+#define BNX2FC_FLAG_SRR_SENT           0xd
+       u8 rec_retry;
+       u8 srr_retry;
+       u32 srr_offset;
+       u8 srr_rctl;
        u32 fcp_resid;
        u32 fcp_rsp_len;
        u32 fcp_sns_len;
@@ -439,6 +443,7 @@ struct bnx2fc_unsol_els {
 
 
 
+struct bnx2fc_cmd *bnx2fc_cmd_alloc(struct bnx2fc_rport *tgt);
 struct bnx2fc_cmd *bnx2fc_elstm_alloc(struct bnx2fc_rport *tgt, int type);
 void bnx2fc_cmd_release(struct kref *ref);
 int bnx2fc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd);
@@ -476,6 +481,10 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req);
 void bnx2fc_init_cleanup_task(struct bnx2fc_cmd *io_req,
                              struct fcoe_task_ctx_entry *task,
                              u16 orig_xid);
+void bnx2fc_init_seq_cleanup_task(struct bnx2fc_cmd *seq_clnup_req,
+                                 struct fcoe_task_ctx_entry *task,
+                                 struct bnx2fc_cmd *orig_io_req,
+                                 u32 offset);
 void bnx2fc_init_mp_task(struct bnx2fc_cmd *io_req,
                         struct fcoe_task_ctx_entry *task);
 void bnx2fc_init_task(struct bnx2fc_cmd *io_req,
@@ -525,5 +534,13 @@ void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt,
                                   unsigned char *buf,
                                   u32 frame_len, u16 l2_oxid);
 int bnx2fc_send_stat_req(struct bnx2fc_hba *hba);
+int bnx2fc_post_io_req(struct bnx2fc_rport *tgt, struct bnx2fc_cmd *io_req);
+int bnx2fc_send_rec(struct bnx2fc_cmd *orig_io_req);
+int bnx2fc_send_srr(struct bnx2fc_cmd *orig_io_req, u32 offset, u8 r_ctl);
+void bnx2fc_process_seq_cleanup_compl(struct bnx2fc_cmd *seq_clnup_req,
+                                     struct fcoe_task_ctx_entry *task,
+                                     u8 rx_state);
+int bnx2fc_initiate_seq_cleanup(struct bnx2fc_cmd *orig_io_req, u32 offset,
+                               enum fc_rctl r_ctl);
 
 #endif
index 7f6aff6..3416d9a 100644 (file)
@@ -21,21 +21,21 @@ extern unsigned int bnx2fc_debug_level;
 
 #define BNX2FC_ELS_DBG(fmt, arg...)                                    \
        BNX2FC_CHK_LOGGING(LOG_ELS,                                     \
-                          printk(KERN_ALERT PFX fmt, ##arg))
+                          printk(KERN_INFO PFX fmt, ##arg))
 
 #define BNX2FC_MISC_DBG(fmt, arg...)                                   \
        BNX2FC_CHK_LOGGING(LOG_MISC,                                    \
-                          printk(KERN_ALERT PFX fmt, ##arg))
+                          printk(KERN_INFO PFX fmt, ##arg))
 
 #define BNX2FC_IO_DBG(io_req, fmt, arg...)                             \
        do {                                                            \
                if (!io_req || !io_req->port || !io_req->port->lport || \
                    !io_req->port->lport->host)                         \
                        BNX2FC_CHK_LOGGING(LOG_IO,                      \
-                          printk(KERN_ALERT PFX "NULL " fmt, ##arg));  \
+                          printk(KERN_INFO PFX "NULL " fmt, ##arg));   \
                else                                                    \
                        BNX2FC_CHK_LOGGING(LOG_IO,                      \
-                          shost_printk(KERN_ALERT,                     \
+                          shost_printk(KERN_INFO,                      \
                                   (io_req)->port->lport->host,         \
                                   PFX "xid:0x%x " fmt,                 \
                                   (io_req)->xid, ##arg));              \
@@ -46,10 +46,10 @@ extern unsigned int bnx2fc_debug_level;
                if (!tgt || !tgt->port || !tgt->port->lport ||          \
                    !tgt->port->lport->host || !tgt->rport)             \
                        BNX2FC_CHK_LOGGING(LOG_TGT,                     \
-                          printk(KERN_ALERT PFX "NULL " fmt, ##arg));  \
+                          printk(KERN_INFO PFX "NULL " fmt, ##arg));   \
                else                                                    \
                        BNX2FC_CHK_LOGGING(LOG_TGT,                     \
-                          shost_printk(KERN_ALERT,                     \
+                          shost_printk(KERN_INFO,                      \
                                   (tgt)->port->lport->host,            \
                                   PFX "port:%x " fmt,                  \
                                   (tgt)->rport->port_id, ##arg));      \
@@ -60,10 +60,10 @@ extern unsigned int bnx2fc_debug_level;
        do {                                                            \
                if (!lport || !lport->host)                             \
                        BNX2FC_CHK_LOGGING(LOG_HBA,                     \
-                          printk(KERN_ALERT PFX "NULL " fmt, ##arg));  \
+                          printk(KERN_INFO PFX "NULL " fmt, ##arg));   \
                else                                                    \
                        BNX2FC_CHK_LOGGING(LOG_HBA,                     \
-                          shost_printk(KERN_ALERT, lport->host,        \
+                          shost_printk(KERN_INFO, lport->host, \
                                   PFX fmt, ##arg));                    \
        } while (0)
 
index 7e89143..d66dcbd 100644 (file)
@@ -3,7 +3,7 @@
  * This file contains helper routines that handle ELS requests
  * and responses.
  *
- * Copyright (c) 2008 - 2010 Broadcom Corporation
+ * Copyright (c) 2008 - 2011 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
@@ -253,13 +253,417 @@ int bnx2fc_send_rls(struct bnx2fc_rport *tgt, struct fc_frame *fp)
        return rc;
 }
 
+void bnx2fc_srr_compl(struct bnx2fc_els_cb_arg *cb_arg)
+{
+       struct bnx2fc_mp_req *mp_req;
+       struct fc_frame_header *fc_hdr, *fh;
+       struct bnx2fc_cmd *srr_req;
+       struct bnx2fc_cmd *orig_io_req;
+       struct fc_frame *fp;
+       unsigned char *buf;
+       void *resp_buf;
+       u32 resp_len, hdr_len;
+       u8 opcode;
+       int rc = 0;
+
+       orig_io_req = cb_arg->aborted_io_req;
+       srr_req = cb_arg->io_req;
+       if (test_bit(BNX2FC_FLAG_IO_COMPL, &orig_io_req->req_flags)) {
+               BNX2FC_IO_DBG(srr_req, "srr_compl: xid - 0x%x completed",
+                       orig_io_req->xid);
+               goto srr_compl_done;
+       }
+       if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &orig_io_req->req_flags)) {
+               BNX2FC_IO_DBG(srr_req, "rec abts in prog "
+                      "orig_io - 0x%x\n",
+                       orig_io_req->xid);
+               goto srr_compl_done;
+       }
+       if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, &srr_req->req_flags)) {
+               /* SRR timedout */
+               BNX2FC_IO_DBG(srr_req, "srr timed out, abort "
+                      "orig_io - 0x%x\n",
+                       orig_io_req->xid);
+               rc = bnx2fc_initiate_abts(srr_req);
+               if (rc != SUCCESS) {
+                       BNX2FC_IO_DBG(srr_req, "srr_compl: initiate_abts "
+                               "failed. issue cleanup\n");
+                       bnx2fc_initiate_cleanup(srr_req);
+               }
+               orig_io_req->srr_retry++;
+               if (orig_io_req->srr_retry <= SRR_RETRY_COUNT) {
+                       struct bnx2fc_rport *tgt = orig_io_req->tgt;
+                       spin_unlock_bh(&tgt->tgt_lock);
+                       rc = bnx2fc_send_srr(orig_io_req,
+                                            orig_io_req->srr_offset,
+                                            orig_io_req->srr_rctl);
+                       spin_lock_bh(&tgt->tgt_lock);
+                       if (!rc)
+                               goto srr_compl_done;
+               }
+
+               rc = bnx2fc_initiate_abts(orig_io_req);
+               if (rc != SUCCESS) {
+                       BNX2FC_IO_DBG(srr_req, "srr_compl: initiate_abts "
+                               "failed xid = 0x%x. issue cleanup\n",
+                               orig_io_req->xid);
+                       bnx2fc_initiate_cleanup(orig_io_req);
+               }
+               goto srr_compl_done;
+       }
+       mp_req = &(srr_req->mp_req);
+       fc_hdr = &(mp_req->resp_fc_hdr);
+       resp_len = mp_req->resp_len;
+       resp_buf = mp_req->resp_buf;
+
+       hdr_len = sizeof(*fc_hdr);
+       buf = kzalloc(PAGE_SIZE, GFP_ATOMIC);
+       if (!buf) {
+               printk(KERN_ERR PFX "srr buf: mem alloc failure\n");
+               goto srr_compl_done;
+       }
+       memcpy(buf, fc_hdr, hdr_len);
+       memcpy(buf + hdr_len, resp_buf, resp_len);
+
+       fp = fc_frame_alloc(NULL, resp_len);
+       if (!fp) {
+               printk(KERN_ERR PFX "fc_frame_alloc failure\n");
+               goto free_buf;
+       }
+
+       fh = (struct fc_frame_header *) fc_frame_header_get(fp);
+       /* Copy FC Frame header and payload into the frame */
+       memcpy(fh, buf, hdr_len + resp_len);
+
+       opcode = fc_frame_payload_op(fp);
+       switch (opcode) {
+       case ELS_LS_ACC:
+               BNX2FC_IO_DBG(srr_req, "SRR success\n");
+               break;
+       case ELS_LS_RJT:
+               BNX2FC_IO_DBG(srr_req, "SRR rejected\n");
+               rc = bnx2fc_initiate_abts(orig_io_req);
+               if (rc != SUCCESS) {
+                       BNX2FC_IO_DBG(srr_req, "srr_compl: initiate_abts "
+                               "failed xid = 0x%x. issue cleanup\n",
+                               orig_io_req->xid);
+                       bnx2fc_initiate_cleanup(orig_io_req);
+               }
+               break;
+       default:
+               BNX2FC_IO_DBG(srr_req, "srr compl - invalid opcode = %d\n",
+                       opcode);
+               break;
+       }
+       fc_frame_free(fp);
+free_buf:
+       kfree(buf);
+srr_compl_done:
+       kref_put(&orig_io_req->refcount, bnx2fc_cmd_release);
+}
+
+void bnx2fc_rec_compl(struct bnx2fc_els_cb_arg *cb_arg)
+{
+       struct bnx2fc_cmd *orig_io_req, *new_io_req;
+       struct bnx2fc_cmd *rec_req;
+       struct bnx2fc_mp_req *mp_req;
+       struct fc_frame_header *fc_hdr, *fh;
+       struct fc_els_ls_rjt *rjt;
+       struct fc_els_rec_acc *acc;
+       struct bnx2fc_rport *tgt;
+       struct fcoe_err_report_entry *err_entry;
+       struct scsi_cmnd *sc_cmd;
+       enum fc_rctl r_ctl;
+       unsigned char *buf;
+       void *resp_buf;
+       struct fc_frame *fp;
+       u8 opcode;
+       u32 offset;
+       u32 e_stat;
+       u32 resp_len, hdr_len;
+       int rc = 0;
+       bool send_seq_clnp = false;
+       bool abort_io = false;
+
+       BNX2FC_MISC_DBG("Entered rec_compl callback\n");
+       rec_req = cb_arg->io_req;
+       orig_io_req = cb_arg->aborted_io_req;
+       BNX2FC_IO_DBG(rec_req, "rec_compl: orig xid = 0x%x", orig_io_req->xid);
+       tgt = orig_io_req->tgt;
+
+       if (test_bit(BNX2FC_FLAG_IO_COMPL, &orig_io_req->req_flags)) {
+               BNX2FC_IO_DBG(rec_req, "completed"
+                      "orig_io - 0x%x\n",
+                       orig_io_req->xid);
+               goto rec_compl_done;
+       }
+       if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &orig_io_req->req_flags)) {
+               BNX2FC_IO_DBG(rec_req, "abts in prog "
+                      "orig_io - 0x%x\n",
+                       orig_io_req->xid);
+               goto rec_compl_done;
+       }
+       /* Handle REC timeout case */
+       if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, &rec_req->req_flags)) {
+               BNX2FC_IO_DBG(rec_req, "timed out, abort "
+                      "orig_io - 0x%x\n",
+                       orig_io_req->xid);
+               /* els req is timed out. send abts for els */
+               rc = bnx2fc_initiate_abts(rec_req);
+               if (rc != SUCCESS) {
+                       BNX2FC_IO_DBG(rec_req, "rec_compl: initiate_abts "
+                               "failed. issue cleanup\n");
+                       bnx2fc_initiate_cleanup(rec_req);
+               }
+               orig_io_req->rec_retry++;
+               /* REC timedout. send ABTS to the orig IO req */
+               if (orig_io_req->rec_retry <= REC_RETRY_COUNT) {
+                       spin_unlock_bh(&tgt->tgt_lock);
+                       rc = bnx2fc_send_rec(orig_io_req);
+                       spin_lock_bh(&tgt->tgt_lock);
+                       if (!rc)
+                               goto rec_compl_done;
+               }
+               rc = bnx2fc_initiate_abts(orig_io_req);
+               if (rc != SUCCESS) {
+                       BNX2FC_IO_DBG(rec_req, "rec_compl: initiate_abts "
+                               "failed xid = 0x%x. issue cleanup\n",
+                               orig_io_req->xid);
+                       bnx2fc_initiate_cleanup(orig_io_req);
+               }
+               goto rec_compl_done;
+       }
+       mp_req = &(rec_req->mp_req);
+       fc_hdr = &(mp_req->resp_fc_hdr);
+       resp_len = mp_req->resp_len;
+       acc = resp_buf = mp_req->resp_buf;
+
+       hdr_len = sizeof(*fc_hdr);
+
+       buf = kzalloc(PAGE_SIZE, GFP_ATOMIC);
+       if (!buf) {
+               printk(KERN_ERR PFX "rec buf: mem alloc failure\n");
+               goto rec_compl_done;
+       }
+       memcpy(buf, fc_hdr, hdr_len);
+       memcpy(buf + hdr_len, resp_buf, resp_len);
+
+       fp = fc_frame_alloc(NULL, resp_len);
+       if (!fp) {
+               printk(KERN_ERR PFX "fc_frame_alloc failure\n");
+               goto free_buf;
+       }
+
+       fh = (struct fc_frame_header *) fc_frame_header_get(fp);
+       /* Copy FC Frame header and payload into the frame */
+       memcpy(fh, buf, hdr_len + resp_len);
+
+       opcode = fc_frame_payload_op(fp);
+       if (opcode == ELS_LS_RJT) {
+               BNX2FC_IO_DBG(rec_req, "opcode is RJT\n");
+               rjt = fc_frame_payload_get(fp, sizeof(*rjt));
+               if ((rjt->er_reason == ELS_RJT_LOGIC ||
+                   rjt->er_reason == ELS_RJT_UNAB) &&
+                   rjt->er_explan == ELS_EXPL_OXID_RXID) {
+                       BNX2FC_IO_DBG(rec_req, "handle CMD LOST case\n");
+                       new_io_req = bnx2fc_cmd_alloc(tgt);
+                       if (!new_io_req)
+                               goto abort_io;
+                       new_io_req->sc_cmd = orig_io_req->sc_cmd;
+                       /* cleanup orig_io_req that is with the FW */
+                       set_bit(BNX2FC_FLAG_CMD_LOST,
+                               &orig_io_req->req_flags);
+                       bnx2fc_initiate_cleanup(orig_io_req);
+                       /* Post a new IO req with the same sc_cmd */
+                       BNX2FC_IO_DBG(rec_req, "Post IO request again\n");
+                       spin_unlock_bh(&tgt->tgt_lock);
+                       rc = bnx2fc_post_io_req(tgt, new_io_req);
+                       spin_lock_bh(&tgt->tgt_lock);
+                       if (!rc)
+                               goto free_frame;
+                       BNX2FC_IO_DBG(rec_req, "REC: io post err\n");
+               }
+abort_io:
+               rc = bnx2fc_initiate_abts(orig_io_req);
+               if (rc != SUCCESS) {
+                       BNX2FC_IO_DBG(rec_req, "rec_compl: initiate_abts "
+                               "failed. issue cleanup\n");
+                       bnx2fc_initiate_cleanup(orig_io_req);
+               }
+       } else if (opcode == ELS_LS_ACC) {
+               /* REVISIT: Check if the exchange is already aborted */
+               offset = ntohl(acc->reca_fc4value);
+               e_stat = ntohl(acc->reca_e_stat);
+               if (e_stat & ESB_ST_SEQ_INIT)  {
+                       BNX2FC_IO_DBG(rec_req, "target has the seq init\n");
+                       goto free_frame;
+               }
+               BNX2FC_IO_DBG(rec_req, "e_stat = 0x%x, offset = 0x%x\n",
+                       e_stat, offset);
+               /* Seq initiative is with us */
+               err_entry = (struct fcoe_err_report_entry *)
+                            &orig_io_req->err_entry;
+               sc_cmd = orig_io_req->sc_cmd;
+               if (sc_cmd->sc_data_direction == DMA_TO_DEVICE) {
+                       /* SCSI WRITE command */
+                       if (offset == orig_io_req->data_xfer_len) {
+                               BNX2FC_IO_DBG(rec_req, "WRITE - resp lost\n");
+                               /* FCP_RSP lost */
+                               r_ctl = FC_RCTL_DD_CMD_STATUS;
+                               offset = 0;
+                       } else  {
+                               /* start transmitting from offset */
+                               BNX2FC_IO_DBG(rec_req, "XFER_RDY/DATA lost\n");
+                               send_seq_clnp = true;
+                               r_ctl = FC_RCTL_DD_DATA_DESC;
+                               if (bnx2fc_initiate_seq_cleanup(orig_io_req,
+                                                               offset, r_ctl))
+                                       abort_io = true;
+                               /* XFER_RDY */
+                       }
+               } else {
+                       /* SCSI READ command */
+                       if (err_entry->data.rx_buf_off ==
+                                       orig_io_req->data_xfer_len) {
+                               /* FCP_RSP lost */
+                               BNX2FC_IO_DBG(rec_req, "READ - resp lost\n");
+                               r_ctl = FC_RCTL_DD_CMD_STATUS;
+                               offset = 0;
+                       } else  {
+                               /* request retransmission from this offset */
+                               send_seq_clnp = true;
+                               offset = err_entry->data.rx_buf_off;
+                               BNX2FC_IO_DBG(rec_req, "RD DATA lost\n");
+                               /* FCP_DATA lost */
+                               r_ctl = FC_RCTL_DD_SOL_DATA;
+                               if (bnx2fc_initiate_seq_cleanup(orig_io_req,
+                                                               offset, r_ctl))
+                                       abort_io = true;
+                       }
+               }
+               if (abort_io) {
+                       rc = bnx2fc_initiate_abts(orig_io_req);
+                       if (rc != SUCCESS) {
+                               BNX2FC_IO_DBG(rec_req, "rec_compl:initiate_abts"
+                                             " failed. issue cleanup\n");
+                               bnx2fc_initiate_cleanup(orig_io_req);
+                       }
+               } else if (!send_seq_clnp) {
+                       BNX2FC_IO_DBG(rec_req, "Send SRR - FCP_RSP\n");
+                       spin_unlock_bh(&tgt->tgt_lock);
+                       rc = bnx2fc_send_srr(orig_io_req, offset, r_ctl);
+                       spin_lock_bh(&tgt->tgt_lock);
+
+                       if (rc) {
+                               BNX2FC_IO_DBG(rec_req, "Unable to send SRR"
+                                       " IO will abort\n");
+                       }
+               }
+       }
+free_frame:
+       fc_frame_free(fp);
+free_buf:
+       kfree(buf);
+rec_compl_done:
+       kref_put(&orig_io_req->refcount, bnx2fc_cmd_release);
+       kfree(cb_arg);
+}
+
+int bnx2fc_send_rec(struct bnx2fc_cmd *orig_io_req)
+{
+       struct fc_els_rec rec;
+       struct bnx2fc_rport *tgt = orig_io_req->tgt;
+       struct fc_lport *lport = tgt->rdata->local_port;
+       struct bnx2fc_els_cb_arg *cb_arg = NULL;
+       u32 sid = tgt->sid;
+       u32 r_a_tov = lport->r_a_tov;
+       int rc;
+
+       BNX2FC_IO_DBG(orig_io_req, "Sending REC\n");
+       memset(&rec, 0, sizeof(rec));
+
+       cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC);
+       if (!cb_arg) {
+               printk(KERN_ERR PFX "Unable to allocate cb_arg for REC\n");
+               rc = -ENOMEM;
+               goto rec_err;
+       }
+       kref_get(&orig_io_req->refcount);
+
+       cb_arg->aborted_io_req = orig_io_req;
+
+       rec.rec_cmd = ELS_REC;
+       hton24(rec.rec_s_id, sid);
+       rec.rec_ox_id = htons(orig_io_req->xid);
+       rec.rec_rx_id = htons(orig_io_req->task->rxwr_txrd.var_ctx.rx_id);
+
+       rc = bnx2fc_initiate_els(tgt, ELS_REC, &rec, sizeof(rec),
+                                bnx2fc_rec_compl, cb_arg,
+                                r_a_tov);
+rec_err:
+       if (rc) {
+               BNX2FC_IO_DBG(orig_io_req, "REC failed - release\n");
+               spin_lock_bh(&tgt->tgt_lock);
+               kref_put(&orig_io_req->refcount, bnx2fc_cmd_release);
+               spin_unlock_bh(&tgt->tgt_lock);
+               kfree(cb_arg);
+       }
+       return rc;
+}
+
+int bnx2fc_send_srr(struct bnx2fc_cmd *orig_io_req, u32 offset, u8 r_ctl)
+{
+       struct fcp_srr srr;
+       struct bnx2fc_rport *tgt = orig_io_req->tgt;
+       struct fc_lport *lport = tgt->rdata->local_port;
+       struct bnx2fc_els_cb_arg *cb_arg = NULL;
+       u32 r_a_tov = lport->r_a_tov;
+       int rc;
+
+       BNX2FC_IO_DBG(orig_io_req, "Sending SRR\n");
+       memset(&srr, 0, sizeof(srr));
+
+       cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC);
+       if (!cb_arg) {
+               printk(KERN_ERR PFX "Unable to allocate cb_arg for SRR\n");
+               rc = -ENOMEM;
+               goto srr_err;
+       }
+       kref_get(&orig_io_req->refcount);
+
+       cb_arg->aborted_io_req = orig_io_req;
+
+       srr.srr_op = ELS_SRR;
+       srr.srr_ox_id = htons(orig_io_req->xid);
+       srr.srr_rx_id = htons(orig_io_req->task->rxwr_txrd.var_ctx.rx_id);
+       srr.srr_rel_off = htonl(offset);
+       srr.srr_r_ctl = r_ctl;
+       orig_io_req->srr_offset = offset;
+       orig_io_req->srr_rctl = r_ctl;
+
+       rc = bnx2fc_initiate_els(tgt, ELS_SRR, &srr, sizeof(srr),
+                                bnx2fc_srr_compl, cb_arg,
+                                r_a_tov);
+srr_err:
+       if (rc) {
+               BNX2FC_IO_DBG(orig_io_req, "SRR failed - release\n");
+               spin_lock_bh(&tgt->tgt_lock);
+               kref_put(&orig_io_req->refcount, bnx2fc_cmd_release);
+               spin_unlock_bh(&tgt->tgt_lock);
+               kfree(cb_arg);
+       } else
+               set_bit(BNX2FC_FLAG_SRR_SENT, &orig_io_req->req_flags);
+
+       return rc;
+}
+
 static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op,
                        void *data, u32 data_len,
                        void (*cb_func)(struct bnx2fc_els_cb_arg *cb_arg),
                        struct bnx2fc_els_cb_arg *cb_arg, u32 timer_msec)
 {
        struct fcoe_port *port = tgt->port;
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
        struct fc_rport *rport = tgt->rport;
        struct fc_lport *lport = port->lport;
        struct bnx2fc_cmd *els_req;
@@ -274,12 +678,12 @@ static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op,
 
        rc = fc_remote_port_chkready(rport);
        if (rc) {
-               printk(KERN_ALERT PFX "els 0x%x: rport not ready\n", op);
+               printk(KERN_ERR PFX "els 0x%x: rport not ready\n", op);
                rc = -EINVAL;
                goto els_err;
        }
        if (lport->state != LPORT_ST_READY || !(lport->link_up)) {
-               printk(KERN_ALERT PFX "els 0x%x: link is not ready\n", op);
+               printk(KERN_ERR PFX "els 0x%x: link is not ready\n", op);
                rc = -EINVAL;
                goto els_err;
        }
@@ -305,7 +709,7 @@ static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op,
        mp_req = (struct bnx2fc_mp_req *)&(els_req->mp_req);
        rc = bnx2fc_init_mp_req(els_req);
        if (rc == FAILED) {
-               printk(KERN_ALERT PFX "ELS MP request init failed\n");
+               printk(KERN_ERR PFX "ELS MP request init failed\n");
                spin_lock_bh(&tgt->tgt_lock);
                kref_put(&els_req->refcount, bnx2fc_cmd_release);
                spin_unlock_bh(&tgt->tgt_lock);
@@ -324,7 +728,7 @@ static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op,
        if ((op >= ELS_LS_RJT) && (op <= ELS_AUTH_ELS)) {
                memcpy(mp_req->req_buf, data, data_len);
        } else {
-               printk(KERN_ALERT PFX "Invalid ELS op 0x%x\n", op);
+               printk(KERN_ERR PFX "Invalid ELS op 0x%x\n", op);
                els_req->cb_func = NULL;
                els_req->cb_arg = NULL;
                spin_lock_bh(&tgt->tgt_lock);
@@ -342,9 +746,14 @@ static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op,
        did = tgt->rport->port_id;
        sid = tgt->sid;
 
-       __fc_fill_fc_hdr(fc_hdr, FC_RCTL_ELS_REQ, did, sid,
-                          FC_TYPE_ELS, FC_FC_FIRST_SEQ | FC_FC_END_SEQ |
-                          FC_FC_SEQ_INIT, 0);
+       if (op == ELS_SRR)
+               __fc_fill_fc_hdr(fc_hdr, FC_RCTL_ELS4_REQ, did, sid,
+                                  FC_TYPE_FCP, FC_FC_FIRST_SEQ |
+                                  FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
+       else
+               __fc_fill_fc_hdr(fc_hdr, FC_RCTL_ELS_REQ, did, sid,
+                                  FC_TYPE_ELS, FC_FC_FIRST_SEQ |
+                                  FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
 
        /* Obtain exchange id */
        xid = els_req->xid;
@@ -352,7 +761,8 @@ static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op,
        index = xid % BNX2FC_TASKS_PER_PAGE;
 
        /* Initialize task context for this IO request */
-       task_page = (struct fcoe_task_ctx_entry *) hba->task_ctx[task_idx];
+       task_page = (struct fcoe_task_ctx_entry *)
+                       interface->hba->task_ctx[task_idx];
        task = &(task_page[index]);
        bnx2fc_init_mp_task(els_req, task);
 
@@ -496,8 +906,8 @@ struct fc_seq *bnx2fc_elsct_send(struct fc_lport *lport, u32 did,
                                      void *arg, u32 timeout)
 {
        struct fcoe_port *port = lport_priv(lport);
-       struct bnx2fc_hba *hba = port->priv;
-       struct fcoe_ctlr *fip = &hba->ctlr;
+       struct bnx2fc_interface *interface = port->priv;
+       struct fcoe_ctlr *fip = &interface->ctlr;
        struct fc_frame_header *fh = fc_frame_header_get(fp);
 
        switch (op) {
index a97aff3..7cb2cd4 100644 (file)
@@ -3,7 +3,7 @@
  * cnic modules to create FCoE instances, send/receive non-offloaded
  * FIP/FCoE packets, listen to link events etc.
  *
- * Copyright (c) 2008 - 2010 Broadcom Corporation
+ * Copyright (c) 2008 - 2011 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
 #include "bnx2fc.h"
 
 static struct list_head adapter_list;
+static struct list_head if_list;
 static u32 adapter_count;
 static DEFINE_MUTEX(bnx2fc_dev_lock);
 DEFINE_PER_CPU(struct bnx2fc_percpu_s, bnx2fc_percpu);
 
 #define DRV_MODULE_NAME                "bnx2fc"
 #define DRV_MODULE_VERSION     BNX2FC_VERSION
-#define DRV_MODULE_RELDATE     "Jun 10, 2011"
+#define DRV_MODULE_RELDATE     "Jun 23, 2011"
 
 
 static char version[] __devinitdata =
@@ -61,7 +62,7 @@ static int bnx2fc_disable(struct net_device *netdev);
 
 static void bnx2fc_recv_frame(struct sk_buff *skb);
 
-static void bnx2fc_start_disc(struct bnx2fc_hba *hba);
+static void bnx2fc_start_disc(struct bnx2fc_interface *interface);
 static int bnx2fc_shost_config(struct fc_lport *lport, struct device *dev);
 static int bnx2fc_net_config(struct fc_lport *lp);
 static int bnx2fc_lport_config(struct fc_lport *lport);
@@ -70,18 +71,20 @@ static int bnx2fc_bind_adapter_devices(struct bnx2fc_hba *hba);
 static void bnx2fc_unbind_adapter_devices(struct bnx2fc_hba *hba);
 static int bnx2fc_bind_pcidev(struct bnx2fc_hba *hba);
 static void bnx2fc_unbind_pcidev(struct bnx2fc_hba *hba);
-static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba,
+static struct fc_lport *bnx2fc_if_create(struct bnx2fc_interface *interface,
                                  struct device *parent, int npiv);
 static void bnx2fc_destroy_work(struct work_struct *work);
 
 static struct bnx2fc_hba *bnx2fc_hba_lookup(struct net_device *phys_dev);
+static struct bnx2fc_interface *bnx2fc_interface_lookup(struct net_device
+                                                       *phys_dev);
 static struct bnx2fc_hba *bnx2fc_find_hba_for_cnic(struct cnic_dev *cnic);
 
 static int bnx2fc_fw_init(struct bnx2fc_hba *hba);
 static void bnx2fc_fw_destroy(struct bnx2fc_hba *hba);
 
 static void bnx2fc_port_shutdown(struct fc_lport *lport);
-static void bnx2fc_stop(struct bnx2fc_hba *hba);
+static void bnx2fc_stop(struct bnx2fc_interface *interface);
 static int __init bnx2fc_mod_init(void);
 static void __exit bnx2fc_mod_exit(void);
 
@@ -142,7 +145,8 @@ static void bnx2fc_abort_io(struct fc_lport *lport)
 static void bnx2fc_cleanup(struct fc_lport *lport)
 {
        struct fcoe_port *port = lport_priv(lport);
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        struct bnx2fc_rport *tgt;
        int i;
 
@@ -219,7 +223,8 @@ static int bnx2fc_xmit(struct fc_lport *lport, struct fc_frame *fp)
        struct fcoe_crc_eof     *cp;
        struct sk_buff          *skb;
        struct fc_frame_header  *fh;
-       struct bnx2fc_hba       *hba;
+       struct bnx2fc_interface *interface;
+       struct bnx2fc_hba *hba;
        struct fcoe_port        *port;
        struct fcoe_hdr         *hp;
        struct bnx2fc_rport     *tgt;
@@ -230,7 +235,8 @@ static int bnx2fc_xmit(struct fc_lport *lport, struct fc_frame *fp)
        int                     wlen, rc = 0;
 
        port = (struct fcoe_port *)lport_priv(lport);
-       hba = port->priv;
+       interface = port->priv;
+       hba = interface->hba;
 
        fh = fc_frame_header_get(fp);
 
@@ -242,12 +248,12 @@ static int bnx2fc_xmit(struct fc_lport *lport, struct fc_frame *fp)
        }
 
        if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ)) {
-               if (!hba->ctlr.sel_fcf) {
+               if (!interface->ctlr.sel_fcf) {
                        BNX2FC_HBA_DBG(lport, "FCF not selected yet!\n");
                        kfree_skb(skb);
                        return -EINVAL;
                }
-               if (fcoe_ctlr_els_send(&hba->ctlr, lport, skb))
+               if (fcoe_ctlr_els_send(&interface->ctlr, lport, skb))
                        return 0;
        }
 
@@ -316,19 +322,19 @@ static int bnx2fc_xmit(struct fc_lport *lport, struct fc_frame *fp)
        skb_reset_network_header(skb);
        skb->mac_len = elen;
        skb->protocol = htons(ETH_P_FCOE);
-       skb->dev = hba->netdev;
+       skb->dev = interface->netdev;
 
        /* fill up mac and fcoe headers */
        eh = eth_hdr(skb);
        eh->h_proto = htons(ETH_P_FCOE);
-       if (hba->ctlr.map_dest)
+       if (interface->ctlr.map_dest)
                fc_fcoe_set_mac(eh->h_dest, fh->fh_d_id);
        else
                /* insert GW address */
-               memcpy(eh->h_dest, hba->ctlr.dest_addr, ETH_ALEN);
+               memcpy(eh->h_dest, interface->ctlr.dest_addr, ETH_ALEN);
 
-       if (unlikely(hba->ctlr.flogi_oxid != FC_XID_UNKNOWN))
-               memcpy(eh->h_source, hba->ctlr.ctl_src_addr, ETH_ALEN);
+       if (unlikely(interface->ctlr.flogi_oxid != FC_XID_UNKNOWN))
+               memcpy(eh->h_source, interface->ctlr.ctl_src_addr, ETH_ALEN);
        else
                memcpy(eh->h_source, port->data_src_addr, ETH_ALEN);
 
@@ -377,22 +383,23 @@ static int bnx2fc_rcv(struct sk_buff *skb, struct net_device *dev,
                struct packet_type *ptype, struct net_device *olddev)
 {
        struct fc_lport *lport;
-       struct bnx2fc_hba *hba;
+       struct bnx2fc_interface *interface;
        struct fc_frame_header *fh;
        struct fcoe_rcv_info *fr;
        struct fcoe_percpu_s *bg;
        unsigned short oxid;
 
-       hba = container_of(ptype, struct bnx2fc_hba, fcoe_packet_type);
-       lport = hba->ctlr.lp;
+       interface = container_of(ptype, struct bnx2fc_interface,
+                                fcoe_packet_type);
+       lport = interface->ctlr.lp;
 
        if (unlikely(lport == NULL)) {
-               printk(KERN_ALERT PFX "bnx2fc_rcv: lport is NULL\n");
+               printk(KERN_ERR PFX "bnx2fc_rcv: lport is NULL\n");
                goto err;
        }
 
        if (unlikely(eth_hdr(skb)->h_proto != htons(ETH_P_FCOE))) {
-               printk(KERN_ALERT PFX "bnx2fc_rcv: Wrong FC type frame\n");
+               printk(KERN_ERR PFX "bnx2fc_rcv: Wrong FC type frame\n");
                goto err;
        }
 
@@ -411,7 +418,6 @@ static int bnx2fc_rcv(struct sk_buff *skb, struct net_device *dev,
 
        fr = fcoe_dev_from_skb(skb);
        fr->fr_dev = lport;
-       fr->ptype = ptype;
 
        bg = &bnx2fc_global;
        spin_lock_bh(&bg->fcoe_rx_list.lock);
@@ -469,7 +475,7 @@ static void bnx2fc_recv_frame(struct sk_buff *skb)
        fr = fcoe_dev_from_skb(skb);
        lport = fr->fr_dev;
        if (unlikely(lport == NULL)) {
-               printk(KERN_ALERT PFX "Invalid lport struct\n");
+               printk(KERN_ERR PFX "Invalid lport struct\n");
                kfree_skb(skb);
                return;
        }
@@ -594,7 +600,8 @@ static struct fc_host_statistics *bnx2fc_get_host_stats(struct Scsi_Host *shost)
        struct fc_host_statistics *bnx2fc_stats;
        struct fc_lport *lport = shost_priv(shost);
        struct fcoe_port *port = lport_priv(lport);
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        struct fcoe_statistics_params *fw_stats;
        int rc = 0;
 
@@ -631,7 +638,7 @@ static struct fc_host_statistics *bnx2fc_get_host_stats(struct Scsi_Host *shost)
 static int bnx2fc_shost_config(struct fc_lport *lport, struct device *dev)
 {
        struct fcoe_port *port = lport_priv(lport);
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
        struct Scsi_Host *shost = lport->host;
        int rc = 0;
 
@@ -654,7 +661,7 @@ static int bnx2fc_shost_config(struct fc_lport *lport, struct device *dev)
                fc_host_max_npiv_vports(lport->host) = USHRT_MAX;
        sprintf(fc_host_symbolic_name(lport->host), "%s v%s over %s",
                BNX2FC_NAME, BNX2FC_VERSION,
-               hba->netdev->name);
+               interface->netdev->name);
 
        return 0;
 }
@@ -662,8 +669,8 @@ static int bnx2fc_shost_config(struct fc_lport *lport, struct device *dev)
 static void bnx2fc_link_speed_update(struct fc_lport *lport)
 {
        struct fcoe_port *port = lport_priv(lport);
-       struct bnx2fc_hba *hba = port->priv;
-       struct net_device *netdev = hba->netdev;
+       struct bnx2fc_interface *interface = port->priv;
+       struct net_device *netdev = interface->netdev;
        struct ethtool_cmd ecmd;
 
        if (!dev_ethtool_get_settings(netdev, &ecmd)) {
@@ -691,7 +698,8 @@ static void bnx2fc_link_speed_update(struct fc_lport *lport)
 static int bnx2fc_link_ok(struct fc_lport *lport)
 {
        struct fcoe_port *port = lport_priv(lport);
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        struct net_device *dev = hba->phys_dev;
        int rc = 0;
 
@@ -713,7 +721,7 @@ static int bnx2fc_link_ok(struct fc_lport *lport)
  */
 void bnx2fc_get_link_state(struct bnx2fc_hba *hba)
 {
-       if (test_bit(__LINK_STATE_NOCARRIER, &hba->netdev->state))
+       if (test_bit(__LINK_STATE_NOCARRIER, &hba->phys_dev->state))
                set_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state);
        else
                clear_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state);
@@ -722,11 +730,13 @@ void bnx2fc_get_link_state(struct bnx2fc_hba *hba)
 static int bnx2fc_net_config(struct fc_lport *lport)
 {
        struct bnx2fc_hba *hba;
+       struct bnx2fc_interface *interface;
        struct fcoe_port *port;
        u64 wwnn, wwpn;
 
        port = lport_priv(lport);
-       hba = port->priv;
+       interface = port->priv;
+       hba = interface->hba;
 
        /* require support for get_pauseparam ethtool op. */
        if (!hba->phys_dev->ethtool_ops ||
@@ -743,11 +753,11 @@ static int bnx2fc_net_config(struct fc_lport *lport)
        bnx2fc_link_speed_update(lport);
 
        if (!lport->vport) {
-               wwnn = fcoe_wwn_from_mac(hba->ctlr.ctl_src_addr, 1, 0);
+               wwnn = fcoe_wwn_from_mac(interface->ctlr.ctl_src_addr, 1, 0);
                BNX2FC_HBA_DBG(lport, "WWNN = 0x%llx\n", wwnn);
                fc_set_wwnn(lport, wwnn);
 
-               wwpn = fcoe_wwn_from_mac(hba->ctlr.ctl_src_addr, 2, 0);
+               wwpn = fcoe_wwn_from_mac(interface->ctlr.ctl_src_addr, 2, 0);
                BNX2FC_HBA_DBG(lport, "WWPN = 0x%llx\n", wwpn);
                fc_set_wwpn(lport, wwpn);
        }
@@ -759,9 +769,9 @@ static void bnx2fc_destroy_timer(unsigned long data)
 {
        struct bnx2fc_hba *hba = (struct bnx2fc_hba *)data;
 
-       BNX2FC_HBA_DBG(hba->ctlr.lp, "ERROR:bnx2fc_destroy_timer - "
+       BNX2FC_MISC_DBG("ERROR:bnx2fc_destroy_timer - "
                   "Destroy compl not received!!\n");
-       hba->flags |= BNX2FC_FLAG_DESTROY_CMPL;
+       set_bit(BNX2FC_FLAG_DESTROY_CMPL, &hba->flags);
        wake_up_interruptible(&hba->destroy_wait);
 }
 
@@ -779,54 +789,35 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event,
                                     u16 vlan_id)
 {
        struct bnx2fc_hba *hba = (struct bnx2fc_hba *)context;
-       struct fc_lport *lport = hba->ctlr.lp;
+       struct fc_lport *lport;
        struct fc_lport *vport;
+       struct bnx2fc_interface *interface;
+       int wait_for_upload = 0;
        u32 link_possible = 1;
 
        /* Ignore vlans for now */
        if (vlan_id != 0)
                return;
 
-       if (!test_bit(BNX2FC_CREATE_DONE, &hba->init_done)) {
-               BNX2FC_MISC_DBG("driver not ready. event=%s %ld\n",
-                          hba->netdev->name, event);
-               return;
-       }
-
-       /*
-        * ASSUMPTION:
-        * indicate_netevent cannot be called from cnic unless bnx2fc
-        * does register_device
-        */
-       BUG_ON(!lport);
-
-       BNX2FC_HBA_DBG(lport, "enter netevent handler - event=%s %ld\n",
-                               hba->netdev->name, event);
-
        switch (event) {
        case NETDEV_UP:
-               BNX2FC_HBA_DBG(lport, "Port up, adapter_state = %ld\n",
-                       hba->adapter_state);
                if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state))
                        printk(KERN_ERR "indicate_netevent: "\
-                                       "adapter is not UP!!\n");
+                                       "hba is not UP!!\n");
                break;
 
        case NETDEV_DOWN:
-               BNX2FC_HBA_DBG(lport, "Port down\n");
                clear_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state);
                clear_bit(ADAPTER_STATE_UP, &hba->adapter_state);
                link_possible = 0;
                break;
 
        case NETDEV_GOING_DOWN:
-               BNX2FC_HBA_DBG(lport, "Port going down\n");
                set_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state);
                link_possible = 0;
                break;
 
        case NETDEV_CHANGE:
-               BNX2FC_HBA_DBG(lport, "NETDEV_CHANGE\n");
                break;
 
        default:
@@ -834,15 +825,22 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event,
                return;
        }
 
-       bnx2fc_link_speed_update(lport);
+       mutex_lock(&bnx2fc_dev_lock);
+       list_for_each_entry(interface, &if_list, list) {
 
-       if (link_possible && !bnx2fc_link_ok(lport)) {
-               printk(KERN_ERR "indicate_netevent: call ctlr_link_up\n");
-               fcoe_ctlr_link_up(&hba->ctlr);
-       } else {
-               printk(KERN_ERR "indicate_netevent: call ctlr_link_down\n");
-               if (fcoe_ctlr_link_down(&hba->ctlr)) {
-                       clear_bit(ADAPTER_STATE_READY, &hba->adapter_state);
+               if (interface->hba != hba)
+                       continue;
+
+               lport = interface->ctlr.lp;
+               BNX2FC_HBA_DBG(lport, "netevent handler - event=%s %ld\n",
+                               interface->netdev->name, event);
+
+               bnx2fc_link_speed_update(lport);
+
+               if (link_possible && !bnx2fc_link_ok(lport)) {
+                       printk(KERN_ERR "indicate_netevent: ctlr_link_up\n");
+                       fcoe_ctlr_link_up(&interface->ctlr);
+               } else if (fcoe_ctlr_link_down(&interface->ctlr)) {
                        mutex_lock(&lport->lp_mutex);
                        list_for_each_entry(vport, &lport->vports, list)
                                fc_host_port_type(vport->host) =
@@ -853,24 +851,26 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event,
                                    get_cpu())->LinkFailureCount++;
                        put_cpu();
                        fcoe_clean_pending_queue(lport);
+                       wait_for_upload = 1;
+               }
+       }
+       mutex_unlock(&bnx2fc_dev_lock);
 
-                       init_waitqueue_head(&hba->shutdown_wait);
-                       BNX2FC_HBA_DBG(lport, "indicate_netevent "
-                                            "num_ofld_sess = %d\n",
-                                  hba->num_ofld_sess);
-                       hba->wait_for_link_down = 1;
-                       BNX2FC_HBA_DBG(lport, "waiting for uploads to "
-                                            "compl proc = %s\n",
-                                  current->comm);
-                       wait_event_interruptible(hba->shutdown_wait,
-                                                (hba->num_ofld_sess == 0));
-                       BNX2FC_HBA_DBG(lport, "wakeup - num_ofld_sess = %d\n",
+       if (wait_for_upload) {
+               clear_bit(ADAPTER_STATE_READY, &hba->adapter_state);
+               init_waitqueue_head(&hba->shutdown_wait);
+               BNX2FC_MISC_DBG("indicate_netevent "
+                               "num_ofld_sess = %d\n",
+                               hba->num_ofld_sess);
+               hba->wait_for_link_down = 1;
+               wait_event_interruptible(hba->shutdown_wait,
+                                        (hba->num_ofld_sess == 0));
+               BNX2FC_MISC_DBG("wakeup - num_ofld_sess = %d\n",
                                hba->num_ofld_sess);
-                       hba->wait_for_link_down = 0;
+               hba->wait_for_link_down = 0;
 
-                       if (signal_pending(current))
-                               flush_signals(current);
-               }
+               if (signal_pending(current))
+                       flush_signals(current);
        }
 }
 
@@ -889,23 +889,12 @@ static int bnx2fc_libfc_config(struct fc_lport *lport)
 
 static int bnx2fc_em_config(struct fc_lport *lport)
 {
-       struct fcoe_port *port = lport_priv(lport);
-       struct bnx2fc_hba *hba = port->priv;
-
        if (!fc_exch_mgr_alloc(lport, FC_CLASS_3, FCOE_MIN_XID,
                                FCOE_MAX_XID, NULL)) {
                printk(KERN_ERR PFX "em_config:fc_exch_mgr_alloc failed\n");
                return -ENOMEM;
        }
 
-       hba->cmd_mgr = bnx2fc_cmd_mgr_alloc(hba, BNX2FC_MIN_XID,
-                                           BNX2FC_MAX_XID);
-
-       if (!hba->cmd_mgr) {
-               printk(KERN_ERR PFX "em_config:bnx2fc_cmd_mgr_alloc failed\n");
-               fc_exch_mgr_free(lport);
-               return -ENOMEM;
-       }
        return 0;
 }
 
@@ -918,11 +907,8 @@ static int bnx2fc_lport_config(struct fc_lport *lport)
        lport->e_d_tov = 2 * 1000;
        lport->r_a_tov = 10 * 1000;
 
-       /* REVISIT: enable when supporting tape devices
        lport->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS |
                                FCP_SPPF_RETRY | FCP_SPPF_CONF_COMPL);
-       */
-       lport->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS);
        lport->does_npiv = 1;
 
        memset(&lport->rnid_gen, 0, sizeof(struct fc_els_rnid_gen));
@@ -952,9 +938,10 @@ static int bnx2fc_fip_recv(struct sk_buff *skb, struct net_device *dev,
                           struct packet_type *ptype,
                           struct net_device *orig_dev)
 {
-       struct bnx2fc_hba *hba;
-       hba = container_of(ptype, struct bnx2fc_hba, fip_packet_type);
-       fcoe_ctlr_recv(&hba->ctlr, skb);
+       struct bnx2fc_interface *interface;
+       interface = container_of(ptype, struct bnx2fc_interface,
+                                fip_packet_type);
+       fcoe_ctlr_recv(&interface->ctlr, skb);
        return 0;
 }
 
@@ -1005,17 +992,17 @@ static int bnx2fc_vport_create(struct fc_vport *vport, bool disabled)
        struct Scsi_Host *shost = vport_to_shost(vport);
        struct fc_lport *n_port = shost_priv(shost);
        struct fcoe_port *port = lport_priv(n_port);
-       struct bnx2fc_hba *hba = port->priv;
-       struct net_device *netdev = hba->netdev;
+       struct bnx2fc_interface *interface = port->priv;
+       struct net_device *netdev = interface->netdev;
        struct fc_lport *vn_port;
 
-       if (!test_bit(BNX2FC_FW_INIT_DONE, &hba->init_done)) {
+       if (!test_bit(BNX2FC_FLAG_FW_INIT_DONE, &interface->hba->flags)) {
                printk(KERN_ERR PFX "vn ports cannot be created on"
-                       "this hba\n");
+                       "this interface\n");
                return -EIO;
        }
        mutex_lock(&bnx2fc_dev_lock);
-       vn_port = bnx2fc_if_create(hba, &vport->dev, 1);
+       vn_port = bnx2fc_if_create(interface, &vport->dev, 1);
        mutex_unlock(&bnx2fc_dev_lock);
 
        if (IS_ERR(vn_port)) {
@@ -1065,10 +1052,10 @@ static int bnx2fc_vport_disable(struct fc_vport *vport, bool disable)
 }
 
 
-static int bnx2fc_netdev_setup(struct bnx2fc_hba *hba)
+static int bnx2fc_netdev_setup(struct bnx2fc_interface *interface)
 {
-       struct net_device *netdev = hba->netdev;
-       struct net_device *physdev = hba->phys_dev;
+       struct net_device *netdev = interface->netdev;
+       struct net_device *physdev = interface->hba->phys_dev;
        struct netdev_hw_addr *ha;
        int sel_san_mac = 0;
 
@@ -1083,7 +1070,8 @@ static int bnx2fc_netdev_setup(struct bnx2fc_hba *hba)
 
                if ((ha->type == NETDEV_HW_ADDR_T_SAN) &&
                    (is_valid_ether_addr(ha->addr))) {
-                       memcpy(hba->ctlr.ctl_src_addr, ha->addr, ETH_ALEN);
+                       memcpy(interface->ctlr.ctl_src_addr, ha->addr,
+                              ETH_ALEN);
                        sel_san_mac = 1;
                        BNX2FC_MISC_DBG("Found SAN MAC\n");
                }
@@ -1093,15 +1081,15 @@ static int bnx2fc_netdev_setup(struct bnx2fc_hba *hba)
        if (!sel_san_mac)
                return -ENODEV;
 
-       hba->fip_packet_type.func = bnx2fc_fip_recv;
-       hba->fip_packet_type.type = htons(ETH_P_FIP);
-       hba->fip_packet_type.dev = netdev;
-       dev_add_pack(&hba->fip_packet_type);
+       interface->fip_packet_type.func = bnx2fc_fip_recv;
+       interface->fip_packet_type.type = htons(ETH_P_FIP);
+       interface->fip_packet_type.dev = netdev;
+       dev_add_pack(&interface->fip_packet_type);
 
-       hba->fcoe_packet_type.func = bnx2fc_rcv;
-       hba->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE);
-       hba->fcoe_packet_type.dev = netdev;
-       dev_add_pack(&hba->fcoe_packet_type);
+       interface->fcoe_packet_type.func = bnx2fc_rcv;
+       interface->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE);
+       interface->fcoe_packet_type.dev = netdev;
+       dev_add_pack(&interface->fcoe_packet_type);
 
        return 0;
 }
@@ -1137,53 +1125,54 @@ static void bnx2fc_release_transport(void)
 
 static void bnx2fc_interface_release(struct kref *kref)
 {
-       struct bnx2fc_hba *hba;
+       struct bnx2fc_interface *interface;
        struct net_device *netdev;
-       struct net_device *phys_dev;
 
-       hba = container_of(kref, struct bnx2fc_hba, kref);
+       interface = container_of(kref, struct bnx2fc_interface, kref);
        BNX2FC_MISC_DBG("Interface is being released\n");
 
-       netdev = hba->netdev;
-       phys_dev = hba->phys_dev;
+       netdev = interface->netdev;
 
        /* tear-down FIP controller */
-       if (test_and_clear_bit(BNX2FC_CTLR_INIT_DONE, &hba->init_done))
-               fcoe_ctlr_destroy(&hba->ctlr);
+       if (test_and_clear_bit(BNX2FC_CTLR_INIT_DONE, &interface->if_flags))
+               fcoe_ctlr_destroy(&interface->ctlr);
+
+       kfree(interface);
 
-       /* Free the command manager */
-       if (hba->cmd_mgr) {
-               bnx2fc_cmd_mgr_free(hba->cmd_mgr);
-               hba->cmd_mgr = NULL;
-       }
        dev_put(netdev);
        module_put(THIS_MODULE);
 }
 
-static inline void bnx2fc_interface_get(struct bnx2fc_hba *hba)
+static inline void bnx2fc_interface_get(struct bnx2fc_interface *interface)
 {
-       kref_get(&hba->kref);
+       kref_get(&interface->kref);
 }
 
-static inline void bnx2fc_interface_put(struct bnx2fc_hba *hba)
+static inline void bnx2fc_interface_put(struct bnx2fc_interface *interface)
 {
-       kref_put(&hba->kref, bnx2fc_interface_release);
+       kref_put(&interface->kref, bnx2fc_interface_release);
 }
-static void bnx2fc_interface_destroy(struct bnx2fc_hba *hba)
+static void bnx2fc_hba_destroy(struct bnx2fc_hba *hba)
 {
+       /* Free the command manager */
+       if (hba->cmd_mgr) {
+               bnx2fc_cmd_mgr_free(hba->cmd_mgr);
+               hba->cmd_mgr = NULL;
+       }
+       kfree(hba->tgt_ofld_list);
        bnx2fc_unbind_pcidev(hba);
        kfree(hba);
 }
 
 /**
- * bnx2fc_interface_create - create a new fcoe instance
+ * bnx2fc_hba_create - create a new bnx2fc hba
  *
  * @cnic:      pointer to cnic device
  *
- * Creates a new FCoE instance on the given device which include allocating
- *     hba structure, scsi_host and lport structures.
+ * Creates a new FCoE hba on the given device.
+ *
  */
-static struct bnx2fc_hba *bnx2fc_interface_create(struct cnic_dev *cnic)
+static struct bnx2fc_hba *bnx2fc_hba_create(struct cnic_dev *cnic)
 {
        struct bnx2fc_hba *hba;
        int rc;
@@ -1198,65 +1187,83 @@ static struct bnx2fc_hba *bnx2fc_interface_create(struct cnic_dev *cnic)
 
        hba->cnic = cnic;
        rc = bnx2fc_bind_pcidev(hba);
-       if (rc)
+       if (rc) {
+               printk(KERN_ERR PFX "create_adapter:  bind error\n");
                goto bind_err;
+       }
        hba->phys_dev = cnic->netdev;
-       /* will get overwritten after we do vlan discovery */
-       hba->netdev = hba->phys_dev;
+       hba->next_conn_id = 0;
+
+       hba->tgt_ofld_list =
+               kzalloc(sizeof(struct bnx2fc_rport *) * BNX2FC_NUM_MAX_SESS,
+                       GFP_KERNEL);
+       if (!hba->tgt_ofld_list) {
+               printk(KERN_ERR PFX "Unable to allocate tgt offload list\n");
+               goto tgtofld_err;
+       }
+
+       hba->num_ofld_sess = 0;
+
+       hba->cmd_mgr = bnx2fc_cmd_mgr_alloc(hba, BNX2FC_MIN_XID,
+                                               BNX2FC_MAX_XID);
+       if (!hba->cmd_mgr) {
+               printk(KERN_ERR PFX "em_config:bnx2fc_cmd_mgr_alloc failed\n");
+               goto cmgr_err;
+       }
 
        init_waitqueue_head(&hba->shutdown_wait);
        init_waitqueue_head(&hba->destroy_wait);
+       INIT_LIST_HEAD(&hba->vports);
 
        return hba;
+
+cmgr_err:
+       kfree(hba->tgt_ofld_list);
+tgtofld_err:
+       bnx2fc_unbind_pcidev(hba);
 bind_err:
-       printk(KERN_ERR PFX "create_interface: bind error\n");
        kfree(hba);
        return NULL;
 }
 
-static int bnx2fc_interface_setup(struct bnx2fc_hba *hba,
-                                 enum fip_state fip_mode)
+struct bnx2fc_interface *bnx2fc_interface_create(struct bnx2fc_hba *hba,
+                                     struct net_device *netdev,
+                                     enum fip_state fip_mode)
 {
+       struct bnx2fc_interface *interface;
        int rc = 0;
-       struct net_device *netdev = hba->netdev;
-       struct fcoe_ctlr *fip = &hba->ctlr;
 
+       interface = kzalloc(sizeof(*interface), GFP_KERNEL);
+       if (!interface) {
+               printk(KERN_ERR PFX "Unable to allocate interface structure\n");
+               return NULL;
+       }
        dev_hold(netdev);
-       kref_init(&hba->kref);
-
-       hba->flags = 0;
+       kref_init(&interface->kref);
+       interface->hba = hba;
+       interface->netdev = netdev;
 
        /* Initialize FIP */
-       memset(fip, 0, sizeof(*fip));
-       fcoe_ctlr_init(fip, fip_mode);
-       hba->ctlr.send = bnx2fc_fip_send;
-       hba->ctlr.update_mac = bnx2fc_update_src_mac;
-       hba->ctlr.get_src_addr = bnx2fc_get_src_mac;
-       set_bit(BNX2FC_CTLR_INIT_DONE, &hba->init_done);
-
-       INIT_LIST_HEAD(&hba->vports);
-       rc = bnx2fc_netdev_setup(hba);
-       if (rc)
-               goto setup_err;
+       fcoe_ctlr_init(&interface->ctlr, fip_mode);
+       interface->ctlr.send = bnx2fc_fip_send;
+       interface->ctlr.update_mac = bnx2fc_update_src_mac;
+       interface->ctlr.get_src_addr = bnx2fc_get_src_mac;
+       set_bit(BNX2FC_CTLR_INIT_DONE, &interface->if_flags);
 
-       hba->next_conn_id = 0;
+       rc = bnx2fc_netdev_setup(interface);
+       if (!rc)
+               return interface;
 
-       memset(hba->tgt_ofld_list, 0, sizeof(hba->tgt_ofld_list));
-       hba->num_ofld_sess = 0;
-
-       return 0;
-
-setup_err:
-       fcoe_ctlr_destroy(&hba->ctlr);
+       fcoe_ctlr_destroy(&interface->ctlr);
        dev_put(netdev);
-       bnx2fc_interface_put(hba);
-       return rc;
+       kfree(interface);
+       return NULL;
 }
 
 /**
  * bnx2fc_if_create - Create FCoE instance on a given interface
  *
- * @hba:       FCoE interface to create a local port on
+ * @interface: FCoE interface to create a local port on
  * @parent:    Device pointer to be the parent in sysfs for the SCSI host
  * @npiv:      Indicates if the port is vport or not
  *
@@ -1264,7 +1271,7 @@ setup_err:
  *
  * Returns:    Allocated fc_lport or an error pointer
  */
-static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba,
+static struct fc_lport *bnx2fc_if_create(struct bnx2fc_interface *interface,
                                  struct device *parent, int npiv)
 {
        struct fc_lport         *lport, *n_port;
@@ -1272,11 +1279,12 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba,
        struct Scsi_Host        *shost;
        struct fc_vport         *vport = dev_to_vport(parent);
        struct bnx2fc_lport     *blport;
+       struct bnx2fc_hba       *hba;
        int                     rc = 0;
 
        blport = kzalloc(sizeof(struct bnx2fc_lport), GFP_KERNEL);
        if (!blport) {
-               BNX2FC_HBA_DBG(hba->ctlr.lp, "Unable to alloc bnx2fc_lport\n");
+               BNX2FC_HBA_DBG(interface->ctlr.lp, "Unable to alloc blport\n");
                return NULL;
        }
 
@@ -1293,7 +1301,7 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba,
        shost = lport->host;
        port = lport_priv(lport);
        port->lport = lport;
-       port->priv = hba;
+       port->priv = interface;
        INIT_WORK(&port->destroy_work, bnx2fc_destroy_work);
 
        /* Configure fcoe_port */
@@ -1317,7 +1325,7 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba,
        rc = bnx2fc_shost_config(lport, parent);
        if (rc) {
                printk(KERN_ERR PFX "Couldnt configure shost for %s\n",
-                       hba->netdev->name);
+                       interface->netdev->name);
                goto lp_config_err;
        }
 
@@ -1343,8 +1351,9 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba,
                goto shost_err;
        }
 
-       bnx2fc_interface_get(hba);
+       bnx2fc_interface_get(interface);
 
+       hba = interface->hba;
        spin_lock_bh(&hba->hba_lock);
        blport->lport = lport;
        list_add_tail(&blport->list, &hba->vports);
@@ -1361,21 +1370,19 @@ free_blport:
        return NULL;
 }
 
-static void bnx2fc_netdev_cleanup(struct bnx2fc_hba *hba)
+static void bnx2fc_netdev_cleanup(struct bnx2fc_interface *interface)
 {
        /* Dont listen for Ethernet packets anymore */
-       __dev_remove_pack(&hba->fcoe_packet_type);
-       __dev_remove_pack(&hba->fip_packet_type);
+       __dev_remove_pack(&interface->fcoe_packet_type);
+       __dev_remove_pack(&interface->fip_packet_type);
        synchronize_net();
 }
 
-static void bnx2fc_if_destroy(struct fc_lport *lport)
+static void bnx2fc_if_destroy(struct fc_lport *lport, struct bnx2fc_hba *hba)
 {
        struct fcoe_port *port = lport_priv(lport);
-       struct bnx2fc_hba *hba = port->priv;
        struct bnx2fc_lport *blport, *tmp;
 
-       BNX2FC_HBA_DBG(hba->ctlr.lp, "ENTERED bnx2fc_if_destroy\n");
        /* Stop the transmit retry timer */
        del_timer_sync(&port->timer);
 
@@ -1409,8 +1416,6 @@ static void bnx2fc_if_destroy(struct fc_lport *lport)
 
        /* Release Scsi_Host */
        scsi_host_put(lport->host);
-
-       bnx2fc_interface_put(hba);
 }
 
 /**
@@ -1425,46 +1430,31 @@ static void bnx2fc_if_destroy(struct fc_lport *lport)
  */
 static int bnx2fc_destroy(struct net_device *netdev)
 {
-       struct bnx2fc_hba *hba = NULL;
-       struct net_device *phys_dev;
+       struct bnx2fc_interface *interface = NULL;
+       struct bnx2fc_hba *hba;
+       struct fc_lport *lport;
        int rc = 0;
 
        rtnl_lock();
-
        mutex_lock(&bnx2fc_dev_lock);
-       /* obtain physical netdev */
-       if (netdev->priv_flags & IFF_802_1Q_VLAN)
-               phys_dev = vlan_dev_real_dev(netdev);
-       else {
-               printk(KERN_ERR PFX "Not a vlan device\n");
-               rc = -ENODEV;
-               goto netdev_err;
-       }
 
-       hba = bnx2fc_hba_lookup(phys_dev);
-       if (!hba || !hba->ctlr.lp) {
+       interface = bnx2fc_interface_lookup(netdev);
+       if (!interface || !interface->ctlr.lp) {
                rc = -ENODEV;
-               printk(KERN_ERR PFX "bnx2fc_destroy: hba or lport not found\n");
-               goto netdev_err;
-       }
-
-       if (!test_bit(BNX2FC_CREATE_DONE, &hba->init_done)) {
-               printk(KERN_ERR PFX "bnx2fc_destroy: Create not called\n");
+               printk(KERN_ERR PFX "bnx2fc_destroy: interface or lport not found\n");
                goto netdev_err;
        }
 
-       bnx2fc_netdev_cleanup(hba);
-
-       bnx2fc_stop(hba);
-
-       bnx2fc_if_destroy(hba->ctlr.lp);
+       hba = interface->hba;
 
-       destroy_workqueue(hba->timer_work_queue);
+       bnx2fc_netdev_cleanup(interface);
+       lport = interface->ctlr.lp;
+       bnx2fc_stop(interface);
+       list_del(&interface->list);
+       destroy_workqueue(interface->timer_work_queue);
+       bnx2fc_interface_put(interface);
+       bnx2fc_if_destroy(lport, hba);
 
-       if (test_bit(BNX2FC_FW_INIT_DONE, &hba->init_done))
-               bnx2fc_fw_destroy(hba);
-
-       clear_bit(BNX2FC_CREATE_DONE, &hba->init_done);
 netdev_err:
        mutex_unlock(&bnx2fc_dev_lock);
        rtnl_unlock();
@@ -1475,16 +1465,20 @@ static void bnx2fc_destroy_work(struct work_struct *work)
 {
        struct fcoe_port *port;
        struct fc_lport *lport;
+       struct bnx2fc_interface *interface;
+       struct bnx2fc_hba *hba;
 
        port = container_of(work, struct fcoe_port, destroy_work);
        lport = port->lport;
+       interface = port->priv;
+       hba = interface->hba;
 
        BNX2FC_HBA_DBG(lport, "Entered bnx2fc_destroy_work\n");
 
        bnx2fc_port_shutdown(lport);
        rtnl_lock();
        mutex_lock(&bnx2fc_dev_lock);
-       bnx2fc_if_destroy(lport);
+       bnx2fc_if_destroy(lport, hba);
        mutex_unlock(&bnx2fc_dev_lock);
        rtnl_unlock();
 }
@@ -1556,28 +1550,27 @@ static void bnx2fc_unbind_pcidev(struct bnx2fc_hba *hba)
 static void bnx2fc_ulp_start(void *handle)
 {
        struct bnx2fc_hba *hba = handle;
-       struct fc_lport *lport = hba->ctlr.lp;
+       struct bnx2fc_interface *interface;
+       struct fc_lport *lport;
 
-       BNX2FC_MISC_DBG("Entered %s\n", __func__);
        mutex_lock(&bnx2fc_dev_lock);
 
-       if (test_bit(BNX2FC_FW_INIT_DONE, &hba->init_done))
-               goto start_disc;
-
-       if (test_bit(BNX2FC_CREATE_DONE, &hba->init_done))
+       if (!test_bit(BNX2FC_FLAG_FW_INIT_DONE, &hba->flags))
                bnx2fc_fw_init(hba);
 
-start_disc:
-       mutex_unlock(&bnx2fc_dev_lock);
-
        BNX2FC_MISC_DBG("bnx2fc started.\n");
 
-       /* Kick off Fabric discovery*/
-       if (test_bit(BNX2FC_CREATE_DONE, &hba->init_done)) {
-               printk(KERN_ERR PFX "ulp_init: start discovery\n");
-               lport->tt.frame_send = bnx2fc_xmit;
-               bnx2fc_start_disc(hba);
+       list_for_each_entry(interface, &if_list, list) {
+               if (interface->hba == hba) {
+                       lport = interface->ctlr.lp;
+                       /* Kick off Fabric discovery*/
+                       printk(KERN_ERR PFX "ulp_init: start discovery\n");
+                       lport->tt.frame_send = bnx2fc_xmit;
+                       bnx2fc_start_disc(interface);
+               }
        }
+
+       mutex_unlock(&bnx2fc_dev_lock);
 }
 
 static void bnx2fc_port_shutdown(struct fc_lport *lport)
@@ -1587,37 +1580,25 @@ static void bnx2fc_port_shutdown(struct fc_lport *lport)
        fc_lport_destroy(lport);
 }
 
-static void bnx2fc_stop(struct bnx2fc_hba *hba)
+static void bnx2fc_stop(struct bnx2fc_interface *interface)
 {
        struct fc_lport *lport;
        struct fc_lport *vport;
 
-       BNX2FC_MISC_DBG("ENTERED %s - init_done = %ld\n", __func__,
-                  hba->init_done);
-       if (test_bit(BNX2FC_FW_INIT_DONE, &hba->init_done) &&
-           test_bit(BNX2FC_CREATE_DONE, &hba->init_done)) {
-               lport = hba->ctlr.lp;
-               bnx2fc_port_shutdown(lport);
-               BNX2FC_HBA_DBG(lport, "bnx2fc_stop: waiting for %d "
-                               "offloaded sessions\n",
-                               hba->num_ofld_sess);
-               wait_event_interruptible(hba->shutdown_wait,
-                                        (hba->num_ofld_sess == 0));
-               mutex_lock(&lport->lp_mutex);
-               list_for_each_entry(vport, &lport->vports, list)
-                       fc_host_port_type(vport->host) = FC_PORTTYPE_UNKNOWN;
-               mutex_unlock(&lport->lp_mutex);
-               fc_host_port_type(lport->host) = FC_PORTTYPE_UNKNOWN;
-               fcoe_ctlr_link_down(&hba->ctlr);
-               fcoe_clean_pending_queue(lport);
-
-               mutex_lock(&hba->hba_mutex);
-               clear_bit(ADAPTER_STATE_UP, &hba->adapter_state);
-               clear_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state);
+       if (!test_bit(BNX2FC_FLAG_FW_INIT_DONE, &interface->hba->flags))
+               return;
 
-               clear_bit(ADAPTER_STATE_READY, &hba->adapter_state);
-               mutex_unlock(&hba->hba_mutex);
-       }
+       lport = interface->ctlr.lp;
+       bnx2fc_port_shutdown(lport);
+
+       mutex_lock(&lport->lp_mutex);
+       list_for_each_entry(vport, &lport->vports, list)
+               fc_host_port_type(vport->host) =
+                                       FC_PORTTYPE_UNKNOWN;
+       mutex_unlock(&lport->lp_mutex);
+       fc_host_port_type(lport->host) = FC_PORTTYPE_UNKNOWN;
+       fcoe_ctlr_link_down(&interface->ctlr);
+       fcoe_clean_pending_queue(lport);
 }
 
 static int bnx2fc_fw_init(struct bnx2fc_hba *hba)
@@ -1656,8 +1637,7 @@ static int bnx2fc_fw_init(struct bnx2fc_hba *hba)
        }
 
 
-       /* Mark HBA to indicate that the FW INIT is done */
-       set_bit(BNX2FC_FW_INIT_DONE, &hba->init_done);
+       set_bit(BNX2FC_FLAG_FW_INIT_DONE, &hba->flags);
        return 0;
 
 err_unbind:
@@ -1668,7 +1648,7 @@ err_out:
 
 static void bnx2fc_fw_destroy(struct bnx2fc_hba *hba)
 {
-       if (test_and_clear_bit(BNX2FC_FW_INIT_DONE, &hba->init_done)) {
+       if (test_and_clear_bit(BNX2FC_FLAG_FW_INIT_DONE, &hba->flags)) {
                if (bnx2fc_send_fw_fcoe_destroy_msg(hba) == 0) {
                        init_timer(&hba->destroy_timer);
                        hba->destroy_timer.expires = BNX2FC_FW_TIMEOUT +
@@ -1677,8 +1657,8 @@ static void bnx2fc_fw_destroy(struct bnx2fc_hba *hba)
                        hba->destroy_timer.data = (unsigned long)hba;
                        add_timer(&hba->destroy_timer);
                        wait_event_interruptible(hba->destroy_wait,
-                                                (hba->flags &
-                                                 BNX2FC_FLAG_DESTROY_CMPL));
+                                       test_bit(BNX2FC_FLAG_DESTROY_CMPL,
+                                                &hba->flags));
                        /* This should never happen */
                        if (signal_pending(current))
                                flush_signals(current);
@@ -1699,40 +1679,57 @@ static void bnx2fc_fw_destroy(struct bnx2fc_hba *hba)
  */
 static void bnx2fc_ulp_stop(void *handle)
 {
-       struct bnx2fc_hba *hba = (struct bnx2fc_hba *)handle;
+       struct bnx2fc_hba *hba = handle;
+       struct bnx2fc_interface *interface;
 
        printk(KERN_ERR "ULP_STOP\n");
 
        mutex_lock(&bnx2fc_dev_lock);
-       bnx2fc_stop(hba);
+       if (!test_bit(BNX2FC_FLAG_FW_INIT_DONE, &hba->flags))
+               goto exit;
+       list_for_each_entry(interface, &if_list, list) {
+               if (interface->hba == hba)
+                       bnx2fc_stop(interface);
+       }
+       BUG_ON(hba->num_ofld_sess != 0);
+
+       mutex_lock(&hba->hba_mutex);
+       clear_bit(ADAPTER_STATE_UP, &hba->adapter_state);
+       clear_bit(ADAPTER_STATE_GOING_DOWN,
+                 &hba->adapter_state);
+
+       clear_bit(ADAPTER_STATE_READY, &hba->adapter_state);
+       mutex_unlock(&hba->hba_mutex);
+
        bnx2fc_fw_destroy(hba);
+exit:
        mutex_unlock(&bnx2fc_dev_lock);
 }
 
-static void bnx2fc_start_disc(struct bnx2fc_hba *hba)
+static void bnx2fc_start_disc(struct bnx2fc_interface *interface)
 {
        struct fc_lport *lport;
        int wait_cnt = 0;
 
        BNX2FC_MISC_DBG("Entered %s\n", __func__);
        /* Kick off FIP/FLOGI */
-       if (!test_bit(BNX2FC_FW_INIT_DONE, &hba->init_done)) {
+       if (!test_bit(BNX2FC_FLAG_FW_INIT_DONE, &interface->hba->flags)) {
                printk(KERN_ERR PFX "Init not done yet\n");
                return;
        }
 
-       lport = hba->ctlr.lp;
+       lport = interface->ctlr.lp;
        BNX2FC_HBA_DBG(lport, "calling fc_fabric_login\n");
 
        if (!bnx2fc_link_ok(lport)) {
                BNX2FC_HBA_DBG(lport, "ctlr_link_up\n");
-               fcoe_ctlr_link_up(&hba->ctlr);
+               fcoe_ctlr_link_up(&interface->ctlr);
                fc_host_port_type(lport->host) = FC_PORTTYPE_NPORT;
-               set_bit(ADAPTER_STATE_READY, &hba->adapter_state);
+               set_bit(ADAPTER_STATE_READY, &interface->hba->adapter_state);
        }
 
        /* wait for the FCF to be selected before issuing FLOGI */
-       while (!hba->ctlr.sel_fcf) {
+       while (!interface->ctlr.sel_fcf) {
                msleep(250);
                /* give up after 3 secs */
                if (++wait_cnt > 12)
@@ -1758,15 +1755,15 @@ static void bnx2fc_ulp_init(struct cnic_dev *dev)
 
        BNX2FC_MISC_DBG("Entered %s\n", __func__);
        /* bnx2fc works only when bnx2x is loaded */
-       if (!test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) {
+       if (!test_bit(CNIC_F_BNX2X_CLASS, &dev->flags) ||
+           (dev->max_fcoe_conn == 0)) {
                printk(KERN_ERR PFX "bnx2fc FCoE not supported on %s,"
-                                   " flags: %lx\n",
-                       dev->netdev->name, dev->flags);
+                                   " flags: %lx fcoe_conn: %d\n",
+                       dev->netdev->name, dev->flags, dev->max_fcoe_conn);
                return;
        }
 
-       /* Configure FCoE interface */
-       hba = bnx2fc_interface_create(dev);
+       hba = bnx2fc_hba_create(dev);
        if (!hba) {
                printk(KERN_ERR PFX "hba initialization failed\n");
                return;
@@ -1774,7 +1771,7 @@ static void bnx2fc_ulp_init(struct cnic_dev *dev)
 
        /* Add HBA to the adapter list */
        mutex_lock(&bnx2fc_dev_lock);
-       list_add_tail(&hba->link, &adapter_list);
+       list_add_tail(&hba->list, &adapter_list);
        adapter_count++;
        mutex_unlock(&bnx2fc_dev_lock);
 
@@ -1782,7 +1779,7 @@ static void bnx2fc_ulp_init(struct cnic_dev *dev)
        rc = dev->register_device(dev, CNIC_ULP_FCOE,
                                                (void *) hba);
        if (rc)
-               printk(KERN_ALERT PFX "register_device failed, rc = %d\n", rc);
+               printk(KERN_ERR PFX "register_device failed, rc = %d\n", rc);
        else
                set_bit(BNX2FC_CNIC_REGISTERED, &hba->reg_with_cnic);
 }
@@ -1790,52 +1787,21 @@ static void bnx2fc_ulp_init(struct cnic_dev *dev)
 
 static int bnx2fc_disable(struct net_device *netdev)
 {
-       struct bnx2fc_hba *hba;
-       struct net_device *phys_dev;
-       struct ethtool_drvinfo drvinfo;
+       struct bnx2fc_interface *interface;
        int rc = 0;
 
        rtnl_lock();
-
        mutex_lock(&bnx2fc_dev_lock);
 
-       /* obtain physical netdev */
-       if (netdev->priv_flags & IFF_802_1Q_VLAN)
-               phys_dev = vlan_dev_real_dev(netdev);
-       else {
-               printk(KERN_ERR PFX "Not a vlan device\n");
-               rc = -ENODEV;
-               goto nodev;
-       }
-
-       /* verify if the physical device is a netxtreme2 device */
-       if (phys_dev->ethtool_ops && phys_dev->ethtool_ops->get_drvinfo) {
-               memset(&drvinfo, 0, sizeof(drvinfo));
-               phys_dev->ethtool_ops->get_drvinfo(phys_dev, &drvinfo);
-               if (strcmp(drvinfo.driver, "bnx2x")) {
-                       printk(KERN_ERR PFX "Not a netxtreme2 device\n");
-                       rc = -ENODEV;
-                       goto nodev;
-               }
-       } else {
-               printk(KERN_ERR PFX "unable to obtain drv_info\n");
-               rc = -ENODEV;
-               goto nodev;
-       }
-
-       printk(KERN_ERR PFX "phys_dev is netxtreme2 device\n");
-
-       /* obtain hba and initialize rest of the structure */
-       hba = bnx2fc_hba_lookup(phys_dev);
-       if (!hba || !hba->ctlr.lp) {
+       interface = bnx2fc_interface_lookup(netdev);
+       if (!interface || !interface->ctlr.lp) {
                rc = -ENODEV;
-               printk(KERN_ERR PFX "bnx2fc_disable: hba or lport not found\n");
+               printk(KERN_ERR PFX "bnx2fc_disable: interface or lport not found\n");
        } else {
-               fcoe_ctlr_link_down(&hba->ctlr);
-               fcoe_clean_pending_queue(hba->ctlr.lp);
+               fcoe_ctlr_link_down(&interface->ctlr);
+               fcoe_clean_pending_queue(interface->ctlr.lp);
        }
 
-nodev:
        mutex_unlock(&bnx2fc_dev_lock);
        rtnl_unlock();
        return rc;
@@ -1844,48 +1810,19 @@ nodev:
 
 static int bnx2fc_enable(struct net_device *netdev)
 {
-       struct bnx2fc_hba *hba;
-       struct net_device *phys_dev;
-       struct ethtool_drvinfo drvinfo;
+       struct bnx2fc_interface *interface;
        int rc = 0;
 
        rtnl_lock();
-
-       BNX2FC_MISC_DBG("Entered %s\n", __func__);
        mutex_lock(&bnx2fc_dev_lock);
 
-       /* obtain physical netdev */
-       if (netdev->priv_flags & IFF_802_1Q_VLAN)
-               phys_dev = vlan_dev_real_dev(netdev);
-       else {
-               printk(KERN_ERR PFX "Not a vlan device\n");
-               rc = -ENODEV;
-               goto nodev;
-       }
-       /* verify if the physical device is a netxtreme2 device */
-       if (phys_dev->ethtool_ops && phys_dev->ethtool_ops->get_drvinfo) {
-               memset(&drvinfo, 0, sizeof(drvinfo));
-               phys_dev->ethtool_ops->get_drvinfo(phys_dev, &drvinfo);
-               if (strcmp(drvinfo.driver, "bnx2x")) {
-                       printk(KERN_ERR PFX "Not a netxtreme2 device\n");
-                       rc = -ENODEV;
-                       goto nodev;
-               }
-       } else {
-               printk(KERN_ERR PFX "unable to obtain drv_info\n");
+       interface = bnx2fc_interface_lookup(netdev);
+       if (!interface || !interface->ctlr.lp) {
                rc = -ENODEV;
-               goto nodev;
-       }
-
-       /* obtain hba and initialize rest of the structure */
-       hba = bnx2fc_hba_lookup(phys_dev);
-       if (!hba || !hba->ctlr.lp) {
-               rc = -ENODEV;
-               printk(KERN_ERR PFX "bnx2fc_enable: hba or lport not found\n");
-       } else if (!bnx2fc_link_ok(hba->ctlr.lp))
-               fcoe_ctlr_link_up(&hba->ctlr);
+               printk(KERN_ERR PFX "bnx2fc_enable: interface or lport not found\n");
+       } else if (!bnx2fc_link_ok(interface->ctlr.lp))
+               fcoe_ctlr_link_up(&interface->ctlr);
 
-nodev:
        mutex_unlock(&bnx2fc_dev_lock);
        rtnl_unlock();
        return rc;
@@ -1903,6 +1840,7 @@ nodev:
  */
 static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode)
 {
+       struct bnx2fc_interface *interface;
        struct bnx2fc_hba *hba;
        struct net_device *phys_dev;
        struct fc_lport *lport;
@@ -1938,7 +1876,7 @@ static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode)
        if (phys_dev->ethtool_ops && phys_dev->ethtool_ops->get_drvinfo) {
                memset(&drvinfo, 0, sizeof(drvinfo));
                phys_dev->ethtool_ops->get_drvinfo(phys_dev, &drvinfo);
-               if (strcmp(drvinfo.driver, "bnx2x")) {
+               if (strncmp(drvinfo.driver, "bnx2x", strlen("bnx2x"))) {
                        printk(KERN_ERR PFX "Not a netxtreme2 device\n");
                        rc = -EINVAL;
                        goto netdev_err;
@@ -1949,7 +1887,7 @@ static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode)
                goto netdev_err;
        }
 
-       /* obtain hba and initialize rest of the structure */
+       /* obtain interface and initialize rest of the structure */
        hba = bnx2fc_hba_lookup(phys_dev);
        if (!hba) {
                rc = -ENODEV;
@@ -1957,67 +1895,61 @@ static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode)
                goto netdev_err;
        }
 
-       if (!test_bit(BNX2FC_FW_INIT_DONE, &hba->init_done)) {
-               rc = bnx2fc_fw_init(hba);
-               if (rc)
-                       goto netdev_err;
-       }
-
-       if (test_bit(BNX2FC_CREATE_DONE, &hba->init_done)) {
+       if (bnx2fc_interface_lookup(netdev)) {
                rc = -EEXIST;
                goto netdev_err;
        }
 
-       /* update netdev with vlan netdev */
-       hba->netdev = netdev;
-       hba->vlan_id = vlan_id;
-       hba->vlan_enabled = 1;
-
-       rc = bnx2fc_interface_setup(hba, fip_mode);
-       if (rc) {
-               printk(KERN_ERR PFX "bnx2fc_interface_setup failed\n");
+       interface = bnx2fc_interface_create(hba, netdev, fip_mode);
+       if (!interface) {
+               printk(KERN_ERR PFX "bnx2fc_interface_create failed\n");
                goto ifput_err;
        }
 
-       hba->timer_work_queue =
+       interface->vlan_id = vlan_id;
+       interface->vlan_enabled = 1;
+
+       interface->timer_work_queue =
                        create_singlethread_workqueue("bnx2fc_timer_wq");
-       if (!hba->timer_work_queue) {
+       if (!interface->timer_work_queue) {
                printk(KERN_ERR PFX "ulp_init could not create timer_wq\n");
                rc = -EINVAL;
                goto ifput_err;
        }
 
-       lport = bnx2fc_if_create(hba, &hba->pcidev->dev, 0);
+       lport = bnx2fc_if_create(interface, &interface->hba->pcidev->dev, 0);
        if (!lport) {
                printk(KERN_ERR PFX "Failed to create interface (%s)\n",
                        netdev->name);
-               bnx2fc_netdev_cleanup(hba);
+               bnx2fc_netdev_cleanup(interface);
                rc = -EINVAL;
                goto if_create_err;
        }
 
+       /* Add interface to if_list */
+       list_add_tail(&interface->list, &if_list);
+
        lport->boot_time = jiffies;
 
        /* Make this master N_port */
-       hba->ctlr.lp = lport;
+       interface->ctlr.lp = lport;
 
-       set_bit(BNX2FC_CREATE_DONE, &hba->init_done);
-       printk(KERN_ERR PFX "create: START DISC\n");
-       bnx2fc_start_disc(hba);
+       BNX2FC_HBA_DBG(lport, "create: START DISC\n");
+       bnx2fc_start_disc(interface);
        /*
         * Release from kref_init in bnx2fc_interface_setup, on success
         * lport should be holding a reference taken in bnx2fc_if_create
         */
-       bnx2fc_interface_put(hba);
+       bnx2fc_interface_put(interface);
        /* put netdev that was held while calling dev_get_by_name */
        mutex_unlock(&bnx2fc_dev_lock);
        rtnl_unlock();
        return 0;
 
 if_create_err:
-       destroy_workqueue(hba->timer_work_queue);
+       destroy_workqueue(interface->timer_work_queue);
 ifput_err:
-       bnx2fc_interface_put(hba);
+       bnx2fc_interface_put(interface);
 netdev_err:
        module_put(THIS_MODULE);
 mod_err:
@@ -2027,7 +1959,7 @@ mod_err:
 }
 
 /**
- * bnx2fc_find_hba_for_cnic - maps cnic instance to bnx2fc adapter instance
+ * bnx2fc_find_hba_for_cnic - maps cnic instance to bnx2fc hba instance
  *
  * @cnic:      Pointer to cnic device instance
  *
@@ -2047,19 +1979,30 @@ static struct bnx2fc_hba *bnx2fc_find_hba_for_cnic(struct cnic_dev *cnic)
        return NULL;
 }
 
-static struct bnx2fc_hba *bnx2fc_hba_lookup(struct net_device *phys_dev)
+static struct bnx2fc_interface *bnx2fc_interface_lookup(struct net_device
+                                                       *netdev)
+{
+       struct bnx2fc_interface *interface;
+
+       /* Called with bnx2fc_dev_lock held */
+       list_for_each_entry(interface, &if_list, list) {
+               if (interface->netdev == netdev)
+                       return interface;
+       }
+       return NULL;
+}
+
+static struct bnx2fc_hba *bnx2fc_hba_lookup(struct net_device
+                                                     *phys_dev)
 {
-       struct list_head *list;
-       struct list_head *temp;
        struct bnx2fc_hba *hba;
 
        /* Called with bnx2fc_dev_lock held */
-       list_for_each_safe(list, temp, &adapter_list) {
-               hba = (struct bnx2fc_hba *)list;
+       list_for_each_entry(hba, &adapter_list, list) {
                if (hba->phys_dev == phys_dev)
                        return hba;
        }
-       printk(KERN_ERR PFX "hba_lookup: hba NULL\n");
+       printk(KERN_ERR PFX "adapter_lookup: hba NULL\n");
        return NULL;
 }
 
@@ -2071,6 +2014,8 @@ static struct bnx2fc_hba *bnx2fc_hba_lookup(struct net_device *phys_dev)
 static void bnx2fc_ulp_exit(struct cnic_dev *dev)
 {
        struct bnx2fc_hba *hba;
+       struct bnx2fc_interface *interface, *tmp;
+       struct fc_lport *lport;
 
        BNX2FC_MISC_DBG("Entered bnx2fc_ulp_exit\n");
 
@@ -2089,13 +2034,20 @@ static void bnx2fc_ulp_exit(struct cnic_dev *dev)
                return;
        }
 
-       list_del_init(&hba->link);
+       list_del_init(&hba->list);
        adapter_count--;
 
-       if (test_bit(BNX2FC_CREATE_DONE, &hba->init_done)) {
+       list_for_each_entry_safe(interface, tmp, &if_list, list) {
                /* destroy not called yet, move to quiesced list */
-               bnx2fc_netdev_cleanup(hba);
-               bnx2fc_if_destroy(hba->ctlr.lp);
+               if (interface->hba == hba) {
+                       bnx2fc_netdev_cleanup(interface);
+                       bnx2fc_stop(interface);
+
+                       list_del(&interface->list);
+                       lport = interface->ctlr.lp;
+                       bnx2fc_interface_put(interface);
+                       bnx2fc_if_destroy(lport, hba);
+               }
        }
        mutex_unlock(&bnx2fc_dev_lock);
 
@@ -2103,7 +2055,7 @@ static void bnx2fc_ulp_exit(struct cnic_dev *dev)
        /* unregister cnic device */
        if (test_and_clear_bit(BNX2FC_CNIC_REGISTERED, &hba->reg_with_cnic))
                hba->cnic->unregister_device(hba->cnic, CNIC_ULP_FCOE);
-       bnx2fc_interface_destroy(hba);
+       bnx2fc_hba_destroy(hba);
 }
 
 /**
@@ -2259,6 +2211,7 @@ static int __init bnx2fc_mod_init(void)
        }
 
        INIT_LIST_HEAD(&adapter_list);
+       INIT_LIST_HEAD(&if_list);
        mutex_init(&bnx2fc_dev_lock);
        adapter_count = 0;
 
@@ -2336,16 +2289,17 @@ static void __exit bnx2fc_mod_exit(void)
        mutex_unlock(&bnx2fc_dev_lock);
 
        /* Unregister with cnic */
-       list_for_each_entry_safe(hba, next, &to_be_deleted, link) {
-               list_del_init(&hba->link);
-               printk(KERN_ERR PFX "MOD_EXIT:destroy hba = 0x%p, kref = %d\n",
-                       hba, atomic_read(&hba->kref.refcount));
+       list_for_each_entry_safe(hba, next, &to_be_deleted, list) {
+               list_del_init(&hba->list);
+               printk(KERN_ERR PFX "MOD_EXIT:destroy hba = 0x%p\n",
+                      hba);
                bnx2fc_ulp_stop(hba);
                /* unregister cnic device */
                if (test_and_clear_bit(BNX2FC_CNIC_REGISTERED,
                                       &hba->reg_with_cnic))
-                       hba->cnic->unregister_device(hba->cnic, CNIC_ULP_FCOE);
-               bnx2fc_interface_destroy(hba);
+                       hba->cnic->unregister_device(hba->cnic,
+                                                        CNIC_ULP_FCOE);
+               bnx2fc_hba_destroy(hba);
        }
        cnic_unregister_driver(CNIC_ULP_FCOE);
 
index 09bdd9b..72cfb14 100644 (file)
@@ -2,7 +2,7 @@
  * This file contains the code that low level functions that interact
  * with 57712 FCoE firmware.
  *
- * Copyright (c) 2008 - 2010 Broadcom Corporation
+ * Copyright (c) 2008 - 2011 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
@@ -23,7 +23,7 @@ static void bnx2fc_process_enable_conn_cmpl(struct bnx2fc_hba *hba,
                                                struct fcoe_kcqe *ofld_kcqe);
 static void bnx2fc_init_failure(struct bnx2fc_hba *hba, u32 err_code);
 static void bnx2fc_process_conn_destroy_cmpl(struct bnx2fc_hba *hba,
-                                       struct fcoe_kcqe *conn_destroy);
+                                       struct fcoe_kcqe *destroy_kcqe);
 
 int bnx2fc_send_stat_req(struct bnx2fc_hba *hba)
 {
@@ -67,7 +67,7 @@ int bnx2fc_send_fw_fcoe_init_msg(struct bnx2fc_hba *hba)
        int rc = 0;
 
        if (!hba->cnic) {
-               printk(KERN_ALERT PFX "hba->cnic NULL during fcoe fw init\n");
+               printk(KERN_ERR PFX "hba->cnic NULL during fcoe fw init\n");
                return -ENODEV;
        }
 
@@ -103,6 +103,7 @@ int bnx2fc_send_fw_fcoe_init_msg(struct bnx2fc_hba *hba)
        fcoe_init2.hsi_major_version = FCOE_HSI_MAJOR_VERSION;
        fcoe_init2.hsi_minor_version = FCOE_HSI_MINOR_VERSION;
 
+
        fcoe_init2.hash_tbl_pbl_addr_lo = (u32) hba->hash_tbl_pbl_dma;
        fcoe_init2.hash_tbl_pbl_addr_hi = (u32)
                                           ((u64) hba->hash_tbl_pbl_dma >> 32);
@@ -165,7 +166,8 @@ int bnx2fc_send_session_ofld_req(struct fcoe_port *port,
                                        struct bnx2fc_rport *tgt)
 {
        struct fc_lport *lport = port->lport;
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        struct kwqe *kwqe_arr[4];
        struct fcoe_kwqe_conn_offload1 ofld_req1;
        struct fcoe_kwqe_conn_offload2 ofld_req2;
@@ -227,7 +229,7 @@ int bnx2fc_send_session_ofld_req(struct fcoe_port *port,
        ofld_req3.hdr.flags =
                (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT);
 
-       ofld_req3.vlan_tag = hba->vlan_id <<
+       ofld_req3.vlan_tag = interface->vlan_id <<
                                FCOE_KWQE_CONN_OFFLOAD3_VLAN_ID_SHIFT;
        ofld_req3.vlan_tag |= 3 << FCOE_KWQE_CONN_OFFLOAD3_PRIORITY_SHIFT;
 
@@ -277,8 +279,20 @@ int bnx2fc_send_session_ofld_req(struct fcoe_port *port,
        ofld_req3.flags |= (((rdata->sp_features & FC_SP_FT_SEQC) ? 1 : 0) <<
                             FCOE_KWQE_CONN_OFFLOAD3_B_CONT_INCR_SEQ_CNT_SHIFT);
 
+       /*
+        * Info from PRLI response, this info is used for sequence level error
+        * recovery support
+        */
+       if (tgt->dev_type == TYPE_TAPE) {
+               ofld_req3.flags |= 1 <<
+                                   FCOE_KWQE_CONN_OFFLOAD3_B_CONF_REQ_SHIFT;
+               ofld_req3.flags |= (((rdata->flags & FC_RP_FLAGS_REC_SUPPORTED)
+                                   ? 1 : 0) <<
+                                   FCOE_KWQE_CONN_OFFLOAD3_B_REC_VALID_SHIFT);
+       }
+
        /* vlan flag */
-       ofld_req3.flags |= (hba->vlan_enabled <<
+       ofld_req3.flags |= (interface->vlan_enabled <<
                            FCOE_KWQE_CONN_OFFLOAD3_B_VLAN_FLAG_SHIFT);
 
        /* C2_VALID and ACK flags are not set as they are not suppported */
@@ -300,12 +314,13 @@ int bnx2fc_send_session_ofld_req(struct fcoe_port *port,
        ofld_req4.src_mac_addr_mid[1] =  port->data_src_addr[2];
        ofld_req4.src_mac_addr_hi[0] =  port->data_src_addr[1];
        ofld_req4.src_mac_addr_hi[1] =  port->data_src_addr[0];
-       ofld_req4.dst_mac_addr_lo[0] =  hba->ctlr.dest_addr[5];/* fcf mac */
-       ofld_req4.dst_mac_addr_lo[1] =  hba->ctlr.dest_addr[4];
-       ofld_req4.dst_mac_addr_mid[0] =  hba->ctlr.dest_addr[3];
-       ofld_req4.dst_mac_addr_mid[1] =  hba->ctlr.dest_addr[2];
-       ofld_req4.dst_mac_addr_hi[0] =  hba->ctlr.dest_addr[1];
-       ofld_req4.dst_mac_addr_hi[1] =  hba->ctlr.dest_addr[0];
+       ofld_req4.dst_mac_addr_lo[0] =  interface->ctlr.dest_addr[5];
+                                                       /* fcf mac */
+       ofld_req4.dst_mac_addr_lo[1] =  interface->ctlr.dest_addr[4];
+       ofld_req4.dst_mac_addr_mid[0] =  interface->ctlr.dest_addr[3];
+       ofld_req4.dst_mac_addr_mid[1] =  interface->ctlr.dest_addr[2];
+       ofld_req4.dst_mac_addr_hi[0] =  interface->ctlr.dest_addr[1];
+       ofld_req4.dst_mac_addr_hi[1] =  interface->ctlr.dest_addr[0];
 
        ofld_req4.lcq_addr_lo = (u32) tgt->lcq_dma;
        ofld_req4.lcq_addr_hi = (u32)((u64) tgt->lcq_dma >> 32);
@@ -335,7 +350,8 @@ static int bnx2fc_send_session_enable_req(struct fcoe_port *port,
                                        struct bnx2fc_rport *tgt)
 {
        struct kwqe *kwqe_arr[2];
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        struct fcoe_kwqe_conn_enable_disable enbl_req;
        struct fc_lport *lport = port->lport;
        struct fc_rport *rport = tgt->rport;
@@ -358,12 +374,12 @@ static int bnx2fc_send_session_enable_req(struct fcoe_port *port,
        enbl_req.src_mac_addr_hi[1] =  port->data_src_addr[0];
        memcpy(tgt->src_addr, port->data_src_addr, ETH_ALEN);
 
-       enbl_req.dst_mac_addr_lo[0] =  hba->ctlr.dest_addr[5];/* fcf mac */
-       enbl_req.dst_mac_addr_lo[1] =  hba->ctlr.dest_addr[4];
-       enbl_req.dst_mac_addr_mid[0] =  hba->ctlr.dest_addr[3];
-       enbl_req.dst_mac_addr_mid[1] =  hba->ctlr.dest_addr[2];
-       enbl_req.dst_mac_addr_hi[0] =  hba->ctlr.dest_addr[1];
-       enbl_req.dst_mac_addr_hi[1] =  hba->ctlr.dest_addr[0];
+       enbl_req.dst_mac_addr_lo[0] =  interface->ctlr.dest_addr[5];
+       enbl_req.dst_mac_addr_lo[1] =  interface->ctlr.dest_addr[4];
+       enbl_req.dst_mac_addr_mid[0] =  interface->ctlr.dest_addr[3];
+       enbl_req.dst_mac_addr_mid[1] =  interface->ctlr.dest_addr[2];
+       enbl_req.dst_mac_addr_hi[0] =  interface->ctlr.dest_addr[1];
+       enbl_req.dst_mac_addr_hi[1] =  interface->ctlr.dest_addr[0];
 
        port_id = fc_host_port_id(lport->host);
        if (port_id != tgt->sid) {
@@ -379,10 +395,10 @@ static int bnx2fc_send_session_enable_req(struct fcoe_port *port,
        enbl_req.d_id[0] = (port_id & 0x000000FF);
        enbl_req.d_id[1] = (port_id & 0x0000FF00) >> 8;
        enbl_req.d_id[2] = (port_id & 0x00FF0000) >> 16;
-       enbl_req.vlan_tag = hba->vlan_id <<
+       enbl_req.vlan_tag = interface->vlan_id <<
                                FCOE_KWQE_CONN_ENABLE_DISABLE_VLAN_ID_SHIFT;
        enbl_req.vlan_tag |= 3 << FCOE_KWQE_CONN_ENABLE_DISABLE_PRIORITY_SHIFT;
-       enbl_req.vlan_flag = hba->vlan_enabled;
+       enbl_req.vlan_flag = interface->vlan_enabled;
        enbl_req.context_id = tgt->context_id;
        enbl_req.conn_id = tgt->fcoe_conn_id;
 
@@ -402,7 +418,8 @@ static int bnx2fc_send_session_enable_req(struct fcoe_port *port,
 int bnx2fc_send_session_disable_req(struct fcoe_port *port,
                                    struct bnx2fc_rport *tgt)
 {
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        struct fcoe_kwqe_conn_enable_disable disable_req;
        struct kwqe *kwqe_arr[2];
        struct fc_rport *rport = tgt->rport;
@@ -423,12 +440,12 @@ int bnx2fc_send_session_disable_req(struct fcoe_port *port,
        disable_req.src_mac_addr_hi[0] =  tgt->src_addr[1];
        disable_req.src_mac_addr_hi[1] =  tgt->src_addr[0];
 
-       disable_req.dst_mac_addr_lo[0] =  hba->ctlr.dest_addr[5];/* fcf mac */
-       disable_req.dst_mac_addr_lo[1] =  hba->ctlr.dest_addr[4];
-       disable_req.dst_mac_addr_mid[0] =  hba->ctlr.dest_addr[3];
-       disable_req.dst_mac_addr_mid[1] =  hba->ctlr.dest_addr[2];
-       disable_req.dst_mac_addr_hi[0] =  hba->ctlr.dest_addr[1];
-       disable_req.dst_mac_addr_hi[1] =  hba->ctlr.dest_addr[0];
+       disable_req.dst_mac_addr_lo[0] =  interface->ctlr.dest_addr[5];
+       disable_req.dst_mac_addr_lo[1] =  interface->ctlr.dest_addr[4];
+       disable_req.dst_mac_addr_mid[0] =  interface->ctlr.dest_addr[3];
+       disable_req.dst_mac_addr_mid[1] =  interface->ctlr.dest_addr[2];
+       disable_req.dst_mac_addr_hi[0] =  interface->ctlr.dest_addr[1];
+       disable_req.dst_mac_addr_hi[1] =  interface->ctlr.dest_addr[0];
 
        port_id = tgt->sid;
        disable_req.s_id[0] = (port_id & 0x000000FF);
@@ -442,11 +459,11 @@ int bnx2fc_send_session_disable_req(struct fcoe_port *port,
        disable_req.d_id[2] = (port_id & 0x00FF0000) >> 16;
        disable_req.context_id = tgt->context_id;
        disable_req.conn_id = tgt->fcoe_conn_id;
-       disable_req.vlan_tag = hba->vlan_id <<
+       disable_req.vlan_tag = interface->vlan_id <<
                                FCOE_KWQE_CONN_ENABLE_DISABLE_VLAN_ID_SHIFT;
        disable_req.vlan_tag |=
                        3 << FCOE_KWQE_CONN_ENABLE_DISABLE_PRIORITY_SHIFT;
-       disable_req.vlan_flag = hba->vlan_enabled;
+       disable_req.vlan_flag = interface->vlan_enabled;
 
        kwqe_arr[0] = (struct kwqe *) &disable_req;
 
@@ -525,7 +542,7 @@ void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt,
 {
        struct fcoe_port *port = tgt->port;
        struct fc_lport *lport = port->lport;
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
        struct bnx2fc_unsol_els *unsol_els;
        struct fc_frame_header *fh;
        struct fc_frame *fp;
@@ -586,7 +603,7 @@ void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt,
                fr_eof(fp) = FC_EOF_T;
                fr_crc(fp) = cpu_to_le32(~crc);
                unsol_els->lport = lport;
-               unsol_els->hba = hba;
+               unsol_els->hba = interface->hba;
                unsol_els->fp = fp;
                INIT_WORK(&unsol_els->unsol_els_work, bnx2fc_unsol_els_work);
                queue_work(bnx2fc_wq, &unsol_els->unsol_els_work);
@@ -608,9 +625,12 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe)
        u32 frame_len, len;
        struct bnx2fc_cmd *io_req = NULL;
        struct fcoe_task_ctx_entry *task, *task_page;
-       struct bnx2fc_hba *hba = tgt->port->priv;
+       struct bnx2fc_interface *interface = tgt->port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        int task_idx, index;
        int rc = 0;
+       u64 err_warn_bit_map;
+       u8 err_warn = 0xff;
 
 
        BNX2FC_TGT_DBG(tgt, "Entered UNSOL COMPLETION wqe = 0x%x\n", wqe);
@@ -673,39 +693,43 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe)
                BNX2FC_TGT_DBG(tgt, "buf_offsets - tx = 0x%x, rx = 0x%x\n",
                        err_entry->data.tx_buf_off, err_entry->data.rx_buf_off);
 
-               bnx2fc_return_rqe(tgt, 1);
 
                if (xid > BNX2FC_MAX_XID) {
                        BNX2FC_TGT_DBG(tgt, "xid(0x%x) out of FW range\n",
                                   xid);
-                       spin_unlock_bh(&tgt->tgt_lock);
-                       break;
+                       goto ret_err_rqe;
                }
 
                task_idx = xid / BNX2FC_TASKS_PER_PAGE;
                index = xid % BNX2FC_TASKS_PER_PAGE;
                task_page = (struct fcoe_task_ctx_entry *)
-                                               hba->task_ctx[task_idx];
+                                       hba->task_ctx[task_idx];
                task = &(task_page[index]);
 
                io_req = (struct bnx2fc_cmd *)hba->cmd_mgr->cmds[xid];
-               if (!io_req) {
-                       spin_unlock_bh(&tgt->tgt_lock);
-                       break;
-               }
+               if (!io_req)
+                       goto ret_err_rqe;
 
                if (io_req->cmd_type != BNX2FC_SCSI_CMD) {
                        printk(KERN_ERR PFX "err_warn: Not a SCSI cmd\n");
-                       spin_unlock_bh(&tgt->tgt_lock);
-                       break;
+                       goto ret_err_rqe;
                }
 
                if (test_and_clear_bit(BNX2FC_FLAG_IO_CLEANUP,
                                       &io_req->req_flags)) {
                        BNX2FC_IO_DBG(io_req, "unsol_err: cleanup in "
                                            "progress.. ignore unsol err\n");
-                       spin_unlock_bh(&tgt->tgt_lock);
-                       break;
+                       goto ret_err_rqe;
+               }
+
+               err_warn_bit_map = (u64)
+                       ((u64)err_entry->data.err_warn_bitmap_hi << 32) |
+                       (u64)err_entry->data.err_warn_bitmap_lo;
+               for (i = 0; i < BNX2FC_NUM_ERR_BITS; i++) {
+                       if (err_warn_bit_map & (u64)((u64)1 << i)) {
+                               err_warn = i;
+                               break;
+                       }
                }
 
                /*
@@ -715,26 +739,61 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe)
                 * logging out the target, when the ABTS eventually
                 * times out.
                 */
-               if (!test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS,
-                                     &io_req->req_flags)) {
-                       /*
-                        * Cancel the timeout_work, as we received IO
-                        * completion with FW error.
-                        */
-                       if (cancel_delayed_work(&io_req->timeout_work))
-                               kref_put(&io_req->refcount,
-                                        bnx2fc_cmd_release); /* timer hold */
-
-                       rc = bnx2fc_initiate_abts(io_req);
-                       if (rc != SUCCESS) {
-                               BNX2FC_IO_DBG(io_req, "err_warn: initiate_abts "
-                                       "failed. issue cleanup\n");
-                               rc = bnx2fc_initiate_cleanup(io_req);
-                               BUG_ON(rc);
-                       }
-               } else
+               if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) {
                        printk(KERN_ERR PFX "err_warn: io_req (0x%x) already "
                                            "in ABTS processing\n", xid);
+                       goto ret_err_rqe;
+               }
+               BNX2FC_TGT_DBG(tgt, "err = 0x%x\n", err_warn);
+               if (tgt->dev_type != TYPE_TAPE)
+                       goto skip_rec;
+               switch (err_warn) {
+               case FCOE_ERROR_CODE_REC_TOV_TIMER_EXPIRATION:
+               case FCOE_ERROR_CODE_DATA_OOO_RO:
+               case FCOE_ERROR_CODE_COMMON_INCORRECT_SEQ_CNT:
+               case FCOE_ERROR_CODE_DATA_SOFI3_SEQ_ACTIVE_SET:
+               case FCOE_ERROR_CODE_FCP_RSP_OPENED_SEQ:
+               case FCOE_ERROR_CODE_DATA_SOFN_SEQ_ACTIVE_RESET:
+                       BNX2FC_TGT_DBG(tgt, "REC TOV popped for xid - 0x%x\n",
+                                  xid);
+                       memset(&io_req->err_entry, 0,
+                              sizeof(struct fcoe_err_report_entry));
+                       memcpy(&io_req->err_entry, err_entry,
+                              sizeof(struct fcoe_err_report_entry));
+                       if (!test_bit(BNX2FC_FLAG_SRR_SENT,
+                                     &io_req->req_flags)) {
+                               spin_unlock_bh(&tgt->tgt_lock);
+                               rc = bnx2fc_send_rec(io_req);
+                               spin_lock_bh(&tgt->tgt_lock);
+
+                               if (rc)
+                                       goto skip_rec;
+                       } else
+                               printk(KERN_ERR PFX "SRR in progress\n");
+                       goto ret_err_rqe;
+                       break;
+               default:
+                       break;
+               }
+
+skip_rec:
+               set_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags);
+               /*
+                * Cancel the timeout_work, as we received IO
+                * completion with FW error.
+                */
+               if (cancel_delayed_work(&io_req->timeout_work))
+                       kref_put(&io_req->refcount, bnx2fc_cmd_release);
+
+               rc = bnx2fc_initiate_abts(io_req);
+               if (rc != SUCCESS) {
+                       printk(KERN_ERR PFX "err_warn: initiate_abts "
+                               "failed xid = 0x%x. issue cleanup\n",
+                               io_req->xid);
+                       bnx2fc_initiate_cleanup(io_req);
+               }
+ret_err_rqe:
+               bnx2fc_return_rqe(tgt, 1);
                spin_unlock_bh(&tgt->tgt_lock);
                break;
 
@@ -755,6 +814,47 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe)
                BNX2FC_TGT_DBG(tgt, "buf_offsets - tx = 0x%x, rx = 0x%x",
                        err_entry->data.tx_buf_off, err_entry->data.rx_buf_off);
 
+               if (xid > BNX2FC_MAX_XID) {
+                       BNX2FC_TGT_DBG(tgt, "xid(0x%x) out of FW range\n", xid);
+                       goto ret_warn_rqe;
+               }
+
+               err_warn_bit_map = (u64)
+                       ((u64)err_entry->data.err_warn_bitmap_hi << 32) |
+                       (u64)err_entry->data.err_warn_bitmap_lo;
+               for (i = 0; i < BNX2FC_NUM_ERR_BITS; i++) {
+                       if (err_warn_bit_map & (u64) (1 << i)) {
+                               err_warn = i;
+                               break;
+                       }
+               }
+               BNX2FC_TGT_DBG(tgt, "warn = 0x%x\n", err_warn);
+
+               task_idx = xid / BNX2FC_TASKS_PER_PAGE;
+               index = xid % BNX2FC_TASKS_PER_PAGE;
+               task_page = (struct fcoe_task_ctx_entry *)
+                            interface->hba->task_ctx[task_idx];
+               task = &(task_page[index]);
+               io_req = (struct bnx2fc_cmd *)hba->cmd_mgr->cmds[xid];
+               if (!io_req)
+                       goto ret_warn_rqe;
+
+               if (io_req->cmd_type != BNX2FC_SCSI_CMD) {
+                       printk(KERN_ERR PFX "err_warn: Not a SCSI cmd\n");
+                       goto ret_warn_rqe;
+               }
+
+               memset(&io_req->err_entry, 0,
+                      sizeof(struct fcoe_err_report_entry));
+               memcpy(&io_req->err_entry, err_entry,
+                      sizeof(struct fcoe_err_report_entry));
+
+               if (err_warn == FCOE_ERROR_CODE_REC_TOV_TIMER_EXPIRATION)
+                       /* REC_TOV is not a warning code */
+                       BUG_ON(1);
+               else
+                       BNX2FC_TGT_DBG(tgt, "Unsolicited warning\n");
+ret_warn_rqe:
                bnx2fc_return_rqe(tgt, 1);
                spin_unlock_bh(&tgt->tgt_lock);
                break;
@@ -770,7 +870,8 @@ void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe)
        struct fcoe_task_ctx_entry *task;
        struct fcoe_task_ctx_entry *task_page;
        struct fcoe_port *port = tgt->port;
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        struct bnx2fc_cmd *io_req;
        int task_idx, index;
        u16 xid;
@@ -781,7 +882,7 @@ void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe)
        spin_lock_bh(&tgt->tgt_lock);
        xid = wqe & FCOE_PEND_WQ_CQE_TASK_ID;
        if (xid >= BNX2FC_MAX_TASKS) {
-               printk(KERN_ALERT PFX "ERROR:xid out of range\n");
+               printk(KERN_ERR PFX "ERROR:xid out of range\n");
                spin_unlock_bh(&tgt->tgt_lock);
                return;
        }
@@ -861,6 +962,13 @@ void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe)
                kref_put(&io_req->refcount, bnx2fc_cmd_release);
                break;
 
+       case BNX2FC_SEQ_CLEANUP:
+               BNX2FC_IO_DBG(io_req, "cq_compl(0x%x) - seq cleanup resp\n",
+                             io_req->xid);
+               bnx2fc_process_seq_cleanup_compl(io_req, task, rx_state);
+               kref_put(&io_req->refcount, bnx2fc_cmd_release);
+               break;
+
        default:
                printk(KERN_ERR PFX "Invalid cmd_type %d\n", cmd_type);
                break;
@@ -962,8 +1070,10 @@ unlock:
                                1 - tgt->cq_curr_toggle_bit;
                }
        }
-       bnx2fc_arm_cq(tgt);
-       atomic_add(num_free_sqes, &tgt->free_sqes);
+       if (num_free_sqes) {
+               bnx2fc_arm_cq(tgt);
+               atomic_add(num_free_sqes, &tgt->free_sqes);
+       }
        spin_unlock_bh(&tgt->cq_lock);
        return 0;
 }
@@ -983,7 +1093,7 @@ static void bnx2fc_fastpath_notification(struct bnx2fc_hba *hba,
        struct bnx2fc_rport *tgt = hba->tgt_ofld_list[conn_id];
 
        if (!tgt) {
-               printk(KERN_ALERT PFX "conn_id 0x%x not valid\n", conn_id);
+               printk(KERN_ERR PFX "conn_id 0x%x not valid\n", conn_id);
                return;
        }
 
@@ -1004,6 +1114,7 @@ static void bnx2fc_process_ofld_cmpl(struct bnx2fc_hba *hba,
 {
        struct bnx2fc_rport             *tgt;
        struct fcoe_port                *port;
+       struct bnx2fc_interface         *interface;
        u32                             conn_id;
        u32                             context_id;
        int                             rc;
@@ -1018,8 +1129,9 @@ static void bnx2fc_process_ofld_cmpl(struct bnx2fc_hba *hba,
        BNX2FC_TGT_DBG(tgt, "Entered ofld compl - context_id = 0x%x\n",
                ofld_kcqe->fcoe_conn_context_id);
        port = tgt->port;
-       if (hba != tgt->port->priv) {
-               printk(KERN_ALERT PFX "ERROR:ofld_cmpl: HBA mis-match\n");
+       interface = tgt->port->priv;
+       if (hba != interface->hba) {
+               printk(KERN_ERR PFX "ERROR:ofld_cmpl: HBA mis-match\n");
                goto ofld_cmpl_err;
        }
        /*
@@ -1040,7 +1152,7 @@ static void bnx2fc_process_ofld_cmpl(struct bnx2fc_hba *hba,
                /* now enable the session */
                rc = bnx2fc_send_session_enable_req(port, tgt);
                if (rc) {
-                       printk(KERN_ALERT PFX "enable session failed\n");
+                       printk(KERN_ERR PFX "enable session failed\n");
                        goto ofld_cmpl_err;
                }
        }
@@ -1063,6 +1175,7 @@ static void bnx2fc_process_enable_conn_cmpl(struct bnx2fc_hba *hba,
                                                struct fcoe_kcqe *ofld_kcqe)
 {
        struct bnx2fc_rport             *tgt;
+       struct bnx2fc_interface         *interface;
        u32                             conn_id;
        u32                             context_id;
 
@@ -1070,7 +1183,7 @@ static void bnx2fc_process_enable_conn_cmpl(struct bnx2fc_hba *hba,
        conn_id = ofld_kcqe->fcoe_conn_id;
        tgt = hba->tgt_ofld_list[conn_id];
        if (!tgt) {
-               printk(KERN_ALERT PFX "ERROR:enbl_cmpl: No pending ofld req\n");
+               printk(KERN_ERR PFX "ERROR:enbl_cmpl: No pending ofld req\n");
                return;
        }
 
@@ -1082,16 +1195,17 @@ static void bnx2fc_process_enable_conn_cmpl(struct bnx2fc_hba *hba,
         * and enable
         */
        if (tgt->context_id != context_id) {
-               printk(KERN_ALERT PFX "context id mis-match\n");
+               printk(KERN_ERR PFX "context id mis-match\n");
                return;
        }
-       if (hba != tgt->port->priv) {
-               printk(KERN_ALERT PFX "bnx2fc-enbl_cmpl: HBA mis-match\n");
+       interface = tgt->port->priv;
+       if (hba != interface->hba) {
+               printk(KERN_ERR PFX "bnx2fc-enbl_cmpl: HBA mis-match\n");
                goto enbl_cmpl_err;
        }
-       if (ofld_kcqe->completion_status) {
+       if (ofld_kcqe->completion_status)
                goto enbl_cmpl_err;
-       else {
+       else {
                /* enable successful - rport ready for issuing IOs */
                set_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags);
                set_bit(BNX2FC_FLAG_OFLD_REQ_CMPL, &tgt->flags);
@@ -1114,14 +1228,14 @@ static void bnx2fc_process_conn_disable_cmpl(struct bnx2fc_hba *hba,
        conn_id = disable_kcqe->fcoe_conn_id;
        tgt = hba->tgt_ofld_list[conn_id];
        if (!tgt) {
-               printk(KERN_ALERT PFX "ERROR: disable_cmpl: No disable req\n");
+               printk(KERN_ERR PFX "ERROR: disable_cmpl: No disable req\n");
                return;
        }
 
        BNX2FC_TGT_DBG(tgt, PFX "disable_cmpl: conn_id %d\n", conn_id);
 
        if (disable_kcqe->completion_status) {
-               printk(KERN_ALERT PFX "ERROR: Disable failed with cmpl status %d\n",
+               printk(KERN_ERR PFX "Disable failed with cmpl status %d\n",
                        disable_kcqe->completion_status);
                return;
        } else {
@@ -1143,14 +1257,14 @@ static void bnx2fc_process_conn_destroy_cmpl(struct bnx2fc_hba *hba,
        conn_id = destroy_kcqe->fcoe_conn_id;
        tgt = hba->tgt_ofld_list[conn_id];
        if (!tgt) {
-               printk(KERN_ALERT PFX "destroy_cmpl: No destroy req\n");
+               printk(KERN_ERR PFX "destroy_cmpl: No destroy req\n");
                return;
        }
 
        BNX2FC_TGT_DBG(tgt, "destroy_cmpl: conn_id %d\n", conn_id);
 
        if (destroy_kcqe->completion_status) {
-               printk(KERN_ALERT PFX "Destroy conn failed, cmpl status %d\n",
+               printk(KERN_ERR PFX "Destroy conn failed, cmpl status %d\n",
                        destroy_kcqe->completion_status);
                return;
        } else {
@@ -1182,6 +1296,7 @@ static void bnx2fc_init_failure(struct bnx2fc_hba *hba, u32 err_code)
                break;
        case FCOE_KCQE_COMPLETION_STATUS_WRONG_HSI_VERSION:
                printk(KERN_ERR PFX "init failure due to HSI mismatch\n");
+               break;
        default:
                printk(KERN_ERR PFX "Unknown Error code %d\n", err_code);
        }
@@ -1240,7 +1355,7 @@ void bnx2fc_indicate_kcqe(void *context, struct kcqe *kcq[],
                        } else {
                                printk(KERN_ERR PFX "DESTROY success\n");
                        }
-                       hba->flags |= BNX2FC_FLAG_DESTROY_CMPL;
+                       set_bit(BNX2FC_FLAG_DESTROY_CMPL, &hba->flags);
                        wake_up_interruptible(&hba->destroy_wait);
                        break;
 
@@ -1262,7 +1377,7 @@ void bnx2fc_indicate_kcqe(void *context, struct kcqe *kcq[],
                case FCOE_KCQE_OPCODE_FCOE_ERROR:
                        /* fall thru */
                default:
-                       printk(KERN_ALERT PFX "unknown opcode 0x%x\n",
+                       printk(KERN_ERR PFX "unknown opcode 0x%x\n",
                                                                kcqe->op_code);
                }
        }
@@ -1305,7 +1420,8 @@ int bnx2fc_map_doorbell(struct bnx2fc_rport *tgt)
        struct fcoe_port *port = tgt->port;
        u32 reg_off;
        resource_size_t reg_base;
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
 
        reg_base = pci_resource_start(hba->pcidev,
                                        BNX2X_DOORBELL_PCI_BAR);
@@ -1344,6 +1460,96 @@ void bnx2fc_return_rqe(struct bnx2fc_rport *tgt, u8 num_items)
        tgt->conn_db->rq_prod = tgt->rq_prod_idx;
 }
 
+void bnx2fc_init_seq_cleanup_task(struct bnx2fc_cmd *seq_clnp_req,
+                                 struct fcoe_task_ctx_entry *task,
+                                 struct bnx2fc_cmd *orig_io_req,
+                                 u32 offset)
+{
+       struct scsi_cmnd *sc_cmd = orig_io_req->sc_cmd;
+       struct bnx2fc_rport *tgt = seq_clnp_req->tgt;
+       struct bnx2fc_interface *interface = tgt->port->priv;
+       struct fcoe_bd_ctx *bd = orig_io_req->bd_tbl->bd_tbl;
+       struct fcoe_task_ctx_entry *orig_task;
+       struct fcoe_task_ctx_entry *task_page;
+       struct fcoe_ext_mul_sges_ctx *sgl;
+       u8 task_type = FCOE_TASK_TYPE_SEQUENCE_CLEANUP;
+       u8 orig_task_type;
+       u16 orig_xid = orig_io_req->xid;
+       u32 context_id = tgt->context_id;
+       u64 phys_addr = (u64)orig_io_req->bd_tbl->bd_tbl_dma;
+       u32 orig_offset = offset;
+       int bd_count;
+       int orig_task_idx, index;
+       int i;
+
+       memset(task, 0, sizeof(struct fcoe_task_ctx_entry));
+
+       if (sc_cmd->sc_data_direction == DMA_TO_DEVICE)
+               orig_task_type = FCOE_TASK_TYPE_WRITE;
+       else
+               orig_task_type = FCOE_TASK_TYPE_READ;
+
+       /* Tx flags */
+       task->txwr_rxrd.const_ctx.tx_flags =
+                               FCOE_TASK_TX_STATE_SEQUENCE_CLEANUP <<
+                               FCOE_TCE_TX_WR_RX_RD_CONST_TX_STATE_SHIFT;
+       /* init flags */
+       task->txwr_rxrd.const_ctx.init_flags = task_type <<
+                               FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT;
+       task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_CLASS_TYPE_3 <<
+                               FCOE_TCE_TX_WR_RX_RD_CONST_CLASS_TYPE_SHIFT;
+       task->rxwr_txrd.const_ctx.init_flags = context_id <<
+                               FCOE_TCE_RX_WR_TX_RD_CONST_CID_SHIFT;
+       task->rxwr_txrd.const_ctx.init_flags = context_id <<
+                               FCOE_TCE_RX_WR_TX_RD_CONST_CID_SHIFT;
+
+       task->txwr_rxrd.union_ctx.cleanup.ctx.cleaned_task_id = orig_xid;
+
+       task->txwr_rxrd.union_ctx.cleanup.ctx.rolled_tx_seq_cnt = 0;
+       task->txwr_rxrd.union_ctx.cleanup.ctx.rolled_tx_data_offset = offset;
+
+       bd_count = orig_io_req->bd_tbl->bd_valid;
+
+       /* obtain the appropriate bd entry from relative offset */
+       for (i = 0; i < bd_count; i++) {
+               if (offset < bd[i].buf_len)
+                       break;
+               offset -= bd[i].buf_len;
+       }
+       phys_addr += (i * sizeof(struct fcoe_bd_ctx));
+
+       if (orig_task_type == FCOE_TASK_TYPE_WRITE) {
+               task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.lo =
+                               (u32)phys_addr;
+               task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.hi =
+                               (u32)((u64)phys_addr >> 32);
+               task->txwr_only.sgl_ctx.sgl.mul_sgl.sgl_size =
+                               bd_count;
+               task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_off =
+                               offset; /* adjusted offset */
+               task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_idx = i;
+       } else {
+               orig_task_idx = orig_xid / BNX2FC_TASKS_PER_PAGE;
+               index = orig_xid % BNX2FC_TASKS_PER_PAGE;
+
+               task_page = (struct fcoe_task_ctx_entry *)
+                            interface->hba->task_ctx[orig_task_idx];
+               orig_task = &(task_page[index]);
+
+               /* Multiple SGEs were used for this IO */
+               sgl = &task->rxwr_only.union_ctx.read_info.sgl_ctx.sgl;
+               sgl->mul_sgl.cur_sge_addr.lo = (u32)phys_addr;
+               sgl->mul_sgl.cur_sge_addr.hi = (u32)((u64)phys_addr >> 32);
+               sgl->mul_sgl.sgl_size = bd_count;
+               sgl->mul_sgl.cur_sge_off = offset; /*adjusted offset */
+               sgl->mul_sgl.cur_sge_idx = i;
+
+               memset(&task->rxwr_only.rx_seq_ctx, 0,
+                      sizeof(struct fcoe_rx_seq_ctx));
+               task->rxwr_only.rx_seq_ctx.low_exp_ro = orig_offset;
+               task->rxwr_only.rx_seq_ctx.high_exp_ro = orig_offset;
+       }
+}
 void bnx2fc_init_cleanup_task(struct bnx2fc_cmd *io_req,
                              struct fcoe_task_ctx_entry *task,
                              u16 orig_xid)
@@ -1360,7 +1566,12 @@ void bnx2fc_init_cleanup_task(struct bnx2fc_cmd *io_req,
                                FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT;
        task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_CLASS_TYPE_3 <<
                                FCOE_TCE_TX_WR_RX_RD_CONST_CLASS_TYPE_SHIFT;
-       task->txwr_rxrd.const_ctx.init_flags |=
+       if (tgt->dev_type == TYPE_TAPE)
+               task->txwr_rxrd.const_ctx.init_flags |=
+                               FCOE_TASK_DEV_TYPE_TAPE <<
+                               FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT;
+       else
+               task->txwr_rxrd.const_ctx.init_flags |=
                                FCOE_TASK_DEV_TYPE_DISK <<
                                FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT;
        task->txwr_rxrd.union_ctx.cleanup.ctx.cleaned_task_id = orig_xid;
@@ -1420,7 +1631,12 @@ void bnx2fc_init_mp_task(struct bnx2fc_cmd *io_req,
        /* init flags */
        task->txwr_rxrd.const_ctx.init_flags = task_type <<
                                FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT;
-       task->txwr_rxrd.const_ctx.init_flags |=
+       if (tgt->dev_type == TYPE_TAPE)
+               task->txwr_rxrd.const_ctx.init_flags |=
+                               FCOE_TASK_DEV_TYPE_TAPE <<
+                               FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT;
+       else
+               task->txwr_rxrd.const_ctx.init_flags |=
                                FCOE_TASK_DEV_TYPE_DISK <<
                                FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT;
        task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_CLASS_TYPE_3 <<
@@ -1477,6 +1693,7 @@ void bnx2fc_init_task(struct bnx2fc_cmd *io_req,
        struct bnx2fc_rport *tgt = io_req->tgt;
        struct fcoe_cached_sge_ctx *cached_sge;
        struct fcoe_ext_mul_sges_ctx *sgl;
+       int dev_type = tgt->dev_type;
        u64 *fcp_cmnd;
        u64 tmp_fcp_cmnd[4];
        u32 context_id;
@@ -1494,20 +1711,40 @@ void bnx2fc_init_task(struct bnx2fc_cmd *io_req,
                task_type = FCOE_TASK_TYPE_READ;
 
        /* Tx only */
+       bd_count = bd_tbl->bd_valid;
        if (task_type == FCOE_TASK_TYPE_WRITE) {
-               task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.lo =
-                               (u32)bd_tbl->bd_tbl_dma;
-               task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.hi =
-                               (u32)((u64)bd_tbl->bd_tbl_dma >> 32);
-               task->txwr_only.sgl_ctx.sgl.mul_sgl.sgl_size =
-                               bd_tbl->bd_valid;
+               if ((dev_type == TYPE_DISK) && (bd_count == 1)) {
+                       struct fcoe_bd_ctx *fcoe_bd_tbl = bd_tbl->bd_tbl;
+
+                       task->txwr_only.sgl_ctx.cached_sge.cur_buf_addr.lo =
+                                       fcoe_bd_tbl->buf_addr_lo;
+                       task->txwr_only.sgl_ctx.cached_sge.cur_buf_addr.hi =
+                                       fcoe_bd_tbl->buf_addr_hi;
+                       task->txwr_only.sgl_ctx.cached_sge.cur_buf_rem =
+                                       fcoe_bd_tbl->buf_len;
+
+                       task->txwr_rxrd.const_ctx.init_flags |= 1 <<
+                               FCOE_TCE_TX_WR_RX_RD_CONST_CACHED_SGE_SHIFT;
+               } else {
+                       task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.lo =
+                                       (u32)bd_tbl->bd_tbl_dma;
+                       task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.hi =
+                                       (u32)((u64)bd_tbl->bd_tbl_dma >> 32);
+                       task->txwr_only.sgl_ctx.sgl.mul_sgl.sgl_size =
+                                       bd_tbl->bd_valid;
+               }
        }
 
        /*Tx Write Rx Read */
        /* Init state to NORMAL */
-       task->txwr_rxrd.const_ctx.init_flags = task_type <<
+       task->txwr_rxrd.const_ctx.init_flags |= task_type <<
                                FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT;
-       task->txwr_rxrd.const_ctx.init_flags |=
+       if (dev_type == TYPE_TAPE)
+               task->txwr_rxrd.const_ctx.init_flags |=
+                               FCOE_TASK_DEV_TYPE_TAPE <<
+                               FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT;
+       else
+               task->txwr_rxrd.const_ctx.init_flags |=
                                FCOE_TASK_DEV_TYPE_DISK <<
                                FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT;
        task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_CLASS_TYPE_3 <<
@@ -1550,7 +1787,8 @@ void bnx2fc_init_task(struct bnx2fc_cmd *io_req,
        cached_sge = &task->rxwr_only.union_ctx.read_info.sgl_ctx.cached_sge;
        sgl = &task->rxwr_only.union_ctx.read_info.sgl_ctx.sgl;
        bd_count = bd_tbl->bd_valid;
-       if (task_type == FCOE_TASK_TYPE_READ) {
+       if (task_type == FCOE_TASK_TYPE_READ &&
+           dev_type == TYPE_DISK) {
                if (bd_count == 1) {
 
                        struct fcoe_bd_ctx *fcoe_bd_tbl = bd_tbl->bd_tbl;
@@ -1582,6 +1820,11 @@ void bnx2fc_init_task(struct bnx2fc_cmd *io_req,
                                        (u32)((u64)bd_tbl->bd_tbl_dma >> 32);
                        sgl->mul_sgl.sgl_size = bd_count;
                }
+       } else {
+               sgl->mul_sgl.cur_sge_addr.lo = (u32)bd_tbl->bd_tbl_dma;
+               sgl->mul_sgl.cur_sge_addr.hi =
+                               (u32)((u64)bd_tbl->bd_tbl_dma >> 32);
+               sgl->mul_sgl.sgl_size = bd_count;
        }
 }
 
index 45eba6d..6cc3789 100644 (file)
@@ -1,7 +1,7 @@
 /* bnx2fc_io.c: Broadcom NetXtreme II Linux FCoE offload driver.
  * IO manager and SCSI IO processing.
  *
- * Copyright (c) 2008 - 2010 Broadcom Corporation
+ * Copyright (c) 2008 - 2011 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
@@ -18,8 +18,6 @@ static int bnx2fc_split_bd(struct bnx2fc_cmd *io_req, u64 addr, int sg_len,
                           int bd_index);
 static int bnx2fc_map_sg(struct bnx2fc_cmd *io_req);
 static void bnx2fc_build_bd_list_from_sg(struct bnx2fc_cmd *io_req);
-static int bnx2fc_post_io_req(struct bnx2fc_rport *tgt,
-                              struct bnx2fc_cmd *io_req);
 static void bnx2fc_unmap_sg_list(struct bnx2fc_cmd *io_req);
 static void bnx2fc_free_mp_resc(struct bnx2fc_cmd *io_req);
 static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req,
@@ -29,10 +27,11 @@ static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req,
 void bnx2fc_cmd_timer_set(struct bnx2fc_cmd *io_req,
                          unsigned int timer_msec)
 {
-       struct bnx2fc_hba *hba = io_req->port->priv;
+       struct bnx2fc_interface *interface = io_req->port->priv;
 
-       if (queue_delayed_work(hba->timer_work_queue, &io_req->timeout_work,
-                                 msecs_to_jiffies(timer_msec)))
+       if (queue_delayed_work(interface->timer_work_queue,
+                              &io_req->timeout_work,
+                              msecs_to_jiffies(timer_msec)))
                kref_get(&io_req->refcount);
 }
 
@@ -217,6 +216,11 @@ static void bnx2fc_scsi_done(struct bnx2fc_cmd *io_req, int err_code)
                return;
 
        BNX2FC_IO_DBG(io_req, "scsi_done. err_code = 0x%x\n", err_code);
+       if (test_bit(BNX2FC_FLAG_CMD_LOST, &io_req->req_flags)) {
+               /* Do not call scsi done for this IO */
+               return;
+       }
+
        bnx2fc_unmap_sg_list(io_req);
        io_req->sc_cmd = NULL;
        if (!sc_cmd) {
@@ -419,8 +423,8 @@ free_cmgr:
 struct bnx2fc_cmd *bnx2fc_elstm_alloc(struct bnx2fc_rport *tgt, int type)
 {
        struct fcoe_port *port = tgt->port;
-       struct bnx2fc_hba *hba = port->priv;
-       struct bnx2fc_cmd_mgr *cmd_mgr = hba->cmd_mgr;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_cmd_mgr *cmd_mgr = interface->hba->cmd_mgr;
        struct bnx2fc_cmd *io_req;
        struct list_head *listp;
        struct io_bdt *bd_tbl;
@@ -485,11 +489,12 @@ struct bnx2fc_cmd *bnx2fc_elstm_alloc(struct bnx2fc_rport *tgt, int type)
        kref_init(&io_req->refcount);
        return io_req;
 }
-static struct bnx2fc_cmd *bnx2fc_cmd_alloc(struct bnx2fc_rport *tgt)
+
+struct bnx2fc_cmd *bnx2fc_cmd_alloc(struct bnx2fc_rport *tgt)
 {
        struct fcoe_port *port = tgt->port;
-       struct bnx2fc_hba *hba = port->priv;
-       struct bnx2fc_cmd_mgr *cmd_mgr = hba->cmd_mgr;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_cmd_mgr *cmd_mgr = interface->hba->cmd_mgr;
        struct bnx2fc_cmd *io_req;
        struct list_head *listp;
        struct io_bdt *bd_tbl;
@@ -570,7 +575,8 @@ void bnx2fc_cmd_release(struct kref *ref)
 static void bnx2fc_free_mp_resc(struct bnx2fc_cmd *io_req)
 {
        struct bnx2fc_mp_req *mp_req = &(io_req->mp_req);
-       struct bnx2fc_hba *hba = io_req->port->priv;
+       struct bnx2fc_interface *interface = io_req->port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        size_t sz = sizeof(struct fcoe_bd_ctx);
 
        /* clear tm flags */
@@ -606,7 +612,8 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req)
        struct bnx2fc_mp_req *mp_req;
        struct fcoe_bd_ctx *mp_req_bd;
        struct fcoe_bd_ctx *mp_resp_bd;
-       struct bnx2fc_hba *hba = io_req->port->priv;
+       struct bnx2fc_interface *interface = io_req->port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        dma_addr_t addr;
        size_t sz;
 
@@ -682,7 +689,7 @@ static int bnx2fc_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags)
        struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device));
        struct fc_rport_libfc_priv *rp = rport->dd_data;
        struct fcoe_port *port;
-       struct bnx2fc_hba *hba;
+       struct bnx2fc_interface *interface;
        struct bnx2fc_rport *tgt;
        struct bnx2fc_cmd *io_req;
        struct bnx2fc_mp_req *tm_req;
@@ -699,10 +706,10 @@ static int bnx2fc_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags)
 
        lport = shost_priv(host);
        port = lport_priv(lport);
-       hba = port->priv;
+       interface = port->priv;
 
        if (rport == NULL) {
-               printk(KERN_ALERT PFX "device_reset: rport is NULL\n");
+               printk(KERN_ERR PFX "device_reset: rport is NULL\n");
                rc = FAILED;
                goto tmf_err;
        }
@@ -745,7 +752,9 @@ retry_tmf:
        rc = bnx2fc_init_mp_req(io_req);
        if (rc == FAILED) {
                printk(KERN_ERR PFX "Task mgmt MP request init failed\n");
+               spin_lock_bh(&tgt->tgt_lock);
                kref_put(&io_req->refcount, bnx2fc_cmd_release);
+               spin_unlock_bh(&tgt->tgt_lock);
                goto tmf_err;
        }
 
@@ -774,7 +783,8 @@ retry_tmf:
        index = xid % BNX2FC_TASKS_PER_PAGE;
 
        /* Initialize task context for this IO request */
-       task_page = (struct fcoe_task_ctx_entry *) hba->task_ctx[task_idx];
+       task_page = (struct fcoe_task_ctx_entry *)
+                       interface->hba->task_ctx[task_idx];
        task = &(task_page[index]);
        bnx2fc_init_mp_task(io_req, task);
 
@@ -806,10 +816,10 @@ retry_tmf:
        spin_unlock_bh(&tgt->tgt_lock);
 
        if (!rc) {
-               printk(KERN_ERR PFX "task mgmt command failed...\n");
+               BNX2FC_TGT_DBG(tgt, "task mgmt command failed...\n");
                rc = FAILED;
        } else {
-               printk(KERN_ERR PFX "task mgmt command success...\n");
+               BNX2FC_TGT_DBG(tgt, "task mgmt command success...\n");
                rc = SUCCESS;
        }
 tmf_err:
@@ -822,7 +832,7 @@ int bnx2fc_initiate_abts(struct bnx2fc_cmd *io_req)
        struct bnx2fc_rport *tgt = io_req->tgt;
        struct fc_rport *rport = tgt->rport;
        struct fc_rport_priv *rdata = tgt->rdata;
-       struct bnx2fc_hba *hba;
+       struct bnx2fc_interface *interface;
        struct fcoe_port *port;
        struct bnx2fc_cmd *abts_io_req;
        struct fcoe_task_ctx_entry *task;
@@ -839,7 +849,7 @@ int bnx2fc_initiate_abts(struct bnx2fc_cmd *io_req)
        BNX2FC_IO_DBG(io_req, "Entered bnx2fc_initiate_abts\n");
 
        port = io_req->port;
-       hba = port->priv;
+       interface = port->priv;
        lport = port->lport;
 
        if (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) {
@@ -849,7 +859,7 @@ int bnx2fc_initiate_abts(struct bnx2fc_cmd *io_req)
        }
 
        if (rport == NULL) {
-               printk(KERN_ALERT PFX "initiate_abts: rport is NULL\n");
+               printk(KERN_ERR PFX "initiate_abts: rport is NULL\n");
                rc = FAILED;
                goto abts_err;
        }
@@ -896,7 +906,8 @@ int bnx2fc_initiate_abts(struct bnx2fc_cmd *io_req)
        index = xid % BNX2FC_TASKS_PER_PAGE;
 
        /* Initialize task context for this IO request */
-       task_page = (struct fcoe_task_ctx_entry *) hba->task_ctx[task_idx];
+       task_page = (struct fcoe_task_ctx_entry *)
+                       interface->hba->task_ctx[task_idx];
        task = &(task_page[index]);
        bnx2fc_init_mp_task(abts_io_req, task);
 
@@ -924,11 +935,81 @@ abts_err:
        return rc;
 }
 
+int bnx2fc_initiate_seq_cleanup(struct bnx2fc_cmd *orig_io_req, u32 offset,
+                               enum fc_rctl r_ctl)
+{
+       struct fc_lport *lport;
+       struct bnx2fc_rport *tgt = orig_io_req->tgt;
+       struct bnx2fc_interface *interface;
+       struct fcoe_port *port;
+       struct bnx2fc_cmd *seq_clnp_req;
+       struct fcoe_task_ctx_entry *task;
+       struct fcoe_task_ctx_entry *task_page;
+       struct bnx2fc_els_cb_arg *cb_arg = NULL;
+       int task_idx, index;
+       u16 xid;
+       int rc = 0;
+
+       BNX2FC_IO_DBG(orig_io_req, "bnx2fc_initiate_seq_cleanup xid = 0x%x\n",
+                  orig_io_req->xid);
+       kref_get(&orig_io_req->refcount);
+
+       port = orig_io_req->port;
+       interface = port->priv;
+       lport = port->lport;
+
+       cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC);
+       if (!cb_arg) {
+               printk(KERN_ERR PFX "Unable to alloc cb_arg for seq clnup\n");
+               rc = -ENOMEM;
+               goto cleanup_err;
+       }
+
+       seq_clnp_req = bnx2fc_elstm_alloc(tgt, BNX2FC_SEQ_CLEANUP);
+       if (!seq_clnp_req) {
+               printk(KERN_ERR PFX "cleanup: couldnt allocate cmd\n");
+               rc = -ENOMEM;
+               kfree(cb_arg);
+               goto cleanup_err;
+       }
+       /* Initialize rest of io_req fields */
+       seq_clnp_req->sc_cmd = NULL;
+       seq_clnp_req->port = port;
+       seq_clnp_req->tgt = tgt;
+       seq_clnp_req->data_xfer_len = 0; /* No data transfer for cleanup */
+
+       xid = seq_clnp_req->xid;
+
+       task_idx = xid/BNX2FC_TASKS_PER_PAGE;
+       index = xid % BNX2FC_TASKS_PER_PAGE;
+
+       /* Initialize task context for this IO request */
+       task_page = (struct fcoe_task_ctx_entry *)
+                    interface->hba->task_ctx[task_idx];
+       task = &(task_page[index]);
+       cb_arg->aborted_io_req = orig_io_req;
+       cb_arg->io_req = seq_clnp_req;
+       cb_arg->r_ctl = r_ctl;
+       cb_arg->offset = offset;
+       seq_clnp_req->cb_arg = cb_arg;
+
+       printk(KERN_ERR PFX "call init_seq_cleanup_task\n");
+       bnx2fc_init_seq_cleanup_task(seq_clnp_req, task, orig_io_req, offset);
+
+       /* Obtain free SQ entry */
+       bnx2fc_add_2_sq(tgt, xid);
+
+       /* Ring doorbell */
+       bnx2fc_ring_doorbell(tgt);
+cleanup_err:
+       return rc;
+}
+
 int bnx2fc_initiate_cleanup(struct bnx2fc_cmd *io_req)
 {
        struct fc_lport *lport;
        struct bnx2fc_rport *tgt = io_req->tgt;
-       struct bnx2fc_hba *hba;
+       struct bnx2fc_interface *interface;
        struct fcoe_port *port;
        struct bnx2fc_cmd *cleanup_io_req;
        struct fcoe_task_ctx_entry *task;
@@ -941,7 +1022,7 @@ int bnx2fc_initiate_cleanup(struct bnx2fc_cmd *io_req)
        BNX2FC_IO_DBG(io_req, "Entered bnx2fc_initiate_cleanup\n");
 
        port = io_req->port;
-       hba = port->priv;
+       interface = port->priv;
        lport = port->lport;
 
        cleanup_io_req = bnx2fc_elstm_alloc(tgt, BNX2FC_CLEANUP);
@@ -963,7 +1044,8 @@ int bnx2fc_initiate_cleanup(struct bnx2fc_cmd *io_req)
        index = xid % BNX2FC_TASKS_PER_PAGE;
 
        /* Initialize task context for this IO request */
-       task_page = (struct fcoe_task_ctx_entry *) hba->task_ctx[task_idx];
+       task_page = (struct fcoe_task_ctx_entry *)
+                       interface->hba->task_ctx[task_idx];
        task = &(task_page[index]);
        orig_xid = io_req->xid;
 
@@ -1031,7 +1113,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
 
        lport = shost_priv(sc_cmd->device->host);
        if ((lport->state != LPORT_ST_READY) || !(lport->link_up)) {
-               printk(KERN_ALERT PFX "eh_abort: link not ready\n");
+               printk(KERN_ERR PFX "eh_abort: link not ready\n");
                return rc;
        }
 
@@ -1062,7 +1144,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
         * io_req is no longer in the active_q.
         */
        if (tgt->flush_in_prog) {
-               printk(KERN_ALERT PFX "eh_abort: io_req (xid = 0x%x) "
+               printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) "
                        "flush in progress\n", io_req->xid);
                kref_put(&io_req->refcount, bnx2fc_cmd_release);
                spin_unlock_bh(&tgt->tgt_lock);
@@ -1070,7 +1152,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
        }
 
        if (io_req->on_active_queue == 0) {
-               printk(KERN_ALERT PFX "eh_abort: io_req (xid = 0x%x) "
+               printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) "
                                "not on active_q\n", io_req->xid);
                /*
                 * This condition can happen only due to the FW bug,
@@ -1108,7 +1190,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
                set_bit(BNX2FC_FLAG_EH_ABORT, &io_req->req_flags);
                rc = bnx2fc_initiate_abts(io_req);
        } else {
-               printk(KERN_ALERT PFX "eh_abort: io_req (xid = 0x%x) "
+               printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) "
                                "already in abts processing\n", io_req->xid);
                kref_put(&io_req->refcount, bnx2fc_cmd_release);
                spin_unlock_bh(&tgt->tgt_lock);
@@ -1149,6 +1231,42 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
        return rc;
 }
 
+void bnx2fc_process_seq_cleanup_compl(struct bnx2fc_cmd *seq_clnp_req,
+                                     struct fcoe_task_ctx_entry *task,
+                                     u8 rx_state)
+{
+       struct bnx2fc_els_cb_arg *cb_arg = seq_clnp_req->cb_arg;
+       struct bnx2fc_cmd *orig_io_req = cb_arg->aborted_io_req;
+       u32 offset = cb_arg->offset;
+       enum fc_rctl r_ctl = cb_arg->r_ctl;
+       int rc = 0;
+       struct bnx2fc_rport *tgt = orig_io_req->tgt;
+
+       BNX2FC_IO_DBG(orig_io_req, "Entered process_cleanup_compl xid = 0x%x"
+                             "cmd_type = %d\n",
+                  seq_clnp_req->xid, seq_clnp_req->cmd_type);
+
+       if (rx_state == FCOE_TASK_RX_STATE_IGNORED_SEQUENCE_CLEANUP) {
+               printk(KERN_ERR PFX "seq cleanup ignored - xid = 0x%x\n",
+                       seq_clnp_req->xid);
+               goto free_cb_arg;
+       }
+       kref_get(&orig_io_req->refcount);
+
+       spin_unlock_bh(&tgt->tgt_lock);
+       rc = bnx2fc_send_srr(orig_io_req, offset, r_ctl);
+       spin_lock_bh(&tgt->tgt_lock);
+
+       if (rc)
+               printk(KERN_ERR PFX "clnup_compl: Unable to send SRR"
+                       " IO will abort\n");
+       seq_clnp_req->cb_arg = NULL;
+       kref_put(&orig_io_req->refcount, bnx2fc_cmd_release);
+free_cb_arg:
+       kfree(cb_arg);
+       return;
+}
+
 void bnx2fc_process_cleanup_compl(struct bnx2fc_cmd *io_req,
                                  struct fcoe_task_ctx_entry *task,
                                  u8 num_rq)
@@ -1378,7 +1496,7 @@ void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req,
                        fc_hdr->fh_r_ctl);
        }
        if (!sc_cmd->SCp.ptr) {
-               printk(KERN_ALERT PFX "tm_compl: SCp.ptr is NULL\n");
+               printk(KERN_ERR PFX "tm_compl: SCp.ptr is NULL\n");
                return;
        }
        switch (io_req->fcp_status) {
@@ -1410,7 +1528,7 @@ void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req,
                io_req->on_tmf_queue = 0;
        } else {
 
-               printk(KERN_ALERT PFX "Command not on active_cmd_queue!\n");
+               printk(KERN_ERR PFX "Command not on active_cmd_queue!\n");
                return;
        }
 
@@ -1597,7 +1715,7 @@ static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req,
 
                if (rq_buff_len > num_rq * BNX2FC_RQ_BUF_SZ) {
                        /* Invalid sense sense length. */
-                       printk(KERN_ALERT PFX "invalid sns length %d\n",
+                       printk(KERN_ERR PFX "invalid sns length %d\n",
                                rq_buff_len);
                        /* reset rq_buff_len */
                        rq_buff_len =  num_rq * BNX2FC_RQ_BUF_SZ;
@@ -1780,7 +1898,7 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req,
                        scsi_set_resid(sc_cmd, io_req->fcp_resid);
                break;
        default:
-               printk(KERN_ALERT PFX "scsi_cmd_compl: fcp_status = %d\n",
+               printk(KERN_ERR PFX "scsi_cmd_compl: fcp_status = %d\n",
                        io_req->fcp_status);
                break;
        }
@@ -1789,14 +1907,15 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req,
        kref_put(&io_req->refcount, bnx2fc_cmd_release);
 }
 
-static int bnx2fc_post_io_req(struct bnx2fc_rport *tgt,
+int bnx2fc_post_io_req(struct bnx2fc_rport *tgt,
                               struct bnx2fc_cmd *io_req)
 {
        struct fcoe_task_ctx_entry *task;
        struct fcoe_task_ctx_entry *task_page;
        struct scsi_cmnd *sc_cmd = io_req->sc_cmd;
        struct fcoe_port *port = tgt->port;
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        struct fc_lport *lport = port->lport;
        struct fcoe_dev_stats *stats;
        int task_idx, index;
@@ -1854,7 +1973,8 @@ static int bnx2fc_post_io_req(struct bnx2fc_rport *tgt,
        }
 
        /* Time IO req */
-       bnx2fc_cmd_timer_set(io_req, BNX2FC_IO_TIMEOUT);
+       if (tgt->io_timeout)
+               bnx2fc_cmd_timer_set(io_req, BNX2FC_IO_TIMEOUT);
        /* Obtain free SQ entry */
        bnx2fc_add_2_sq(tgt, xid);
 
index 3e892bd..d5311b5 100644 (file)
@@ -2,7 +2,7 @@
  * Handles operations such as session offload/upload etc, and manages
  * session resources such as connection id and qp resources.
  *
- * Copyright (c) 2008 - 2010 Broadcom Corporation
+ * Copyright (c) 2008 - 2011 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
@@ -65,7 +65,8 @@ static void bnx2fc_offload_session(struct fcoe_port *port,
 {
        struct fc_lport *lport = rdata->local_port;
        struct fc_rport *rport = rdata->rport;
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        int rval;
        int i = 0;
 
@@ -237,7 +238,8 @@ void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt)
 static void bnx2fc_upload_session(struct fcoe_port *port,
                                        struct bnx2fc_rport *tgt)
 {
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
 
        BNX2FC_TGT_DBG(tgt, "upload_session: active_ios = %d\n",
                tgt->num_active_ios.counter);
@@ -316,7 +318,8 @@ static int bnx2fc_init_tgt(struct bnx2fc_rport *tgt,
 {
 
        struct fc_rport *rport = rdata->rport;
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        struct b577xx_doorbell_set_prod *sq_db = &tgt->sq_db;
        struct b577xx_fcoe_rx_doorbell *rx_db = &tgt->rx_db;
 
@@ -350,6 +353,14 @@ static int bnx2fc_init_tgt(struct bnx2fc_rport *tgt,
        tgt->rq_cons_idx = 0;
        atomic_set(&tgt->num_active_ios, 0);
 
+       if (rdata->flags & FC_RP_FLAGS_RETRY) {
+               tgt->dev_type = TYPE_TAPE;
+               tgt->io_timeout = 0; /* use default ULP timeout */
+       } else {
+               tgt->dev_type = TYPE_DISK;
+               tgt->io_timeout = BNX2FC_IO_TIMEOUT;
+       }
+
        /* initialize sq doorbell */
        sq_db->header.header = B577XX_DOORBELL_HDR_DB_TYPE;
        sq_db->header.header |= B577XX_FCOE_CONNECTION_TYPE <<
@@ -392,7 +403,8 @@ void bnx2fc_rport_event_handler(struct fc_lport *lport,
                                enum fc_rport_event event)
 {
        struct fcoe_port *port = lport_priv(lport);
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        struct fc_rport *rport = rdata->rport;
        struct fc_rport_libfc_priv *rp;
        struct bnx2fc_rport *tgt;
@@ -403,7 +415,7 @@ void bnx2fc_rport_event_handler(struct fc_lport *lport,
        switch (event) {
        case RPORT_EV_READY:
                if (!rport) {
-                       printk(KERN_ALERT PFX "rport is NULL: ERROR!\n");
+                       printk(KERN_ERR PFX "rport is NULL: ERROR!\n");
                        break;
                }
 
@@ -415,7 +427,7 @@ void bnx2fc_rport_event_handler(struct fc_lport *lport,
                         * We should not come here, as lport will
                         * take care of fabric login
                         */
-                       printk(KERN_ALERT PFX "%x - rport_event_handler ERROR\n",
+                       printk(KERN_ERR PFX "%x - rport_event_handler ERROR\n",
                                rdata->ids.port_id);
                        break;
                }
@@ -483,7 +495,7 @@ void bnx2fc_rport_event_handler(struct fc_lport *lport,
                        break;
 
                if (!rport) {
-                       printk(KERN_ALERT PFX "%x - rport not created Yet!!\n",
+                       printk(KERN_INFO PFX "%x - rport not created Yet!!\n",
                                port_id);
                        break;
                }
@@ -537,7 +549,8 @@ void bnx2fc_rport_event_handler(struct fc_lport *lport,
 struct bnx2fc_rport *bnx2fc_tgt_lookup(struct fcoe_port *port,
                                             u32 port_id)
 {
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        struct bnx2fc_rport *tgt;
        struct fc_rport_priv *rdata;
        int i;
@@ -552,7 +565,7 @@ struct bnx2fc_rport *bnx2fc_tgt_lookup(struct fcoe_port *port,
                                                "obtained\n");
                                        return tgt;
                                } else {
-                                       printk(KERN_ERR PFX "rport 0x%x "
+                                       BNX2FC_TGT_DBG(tgt, "rport 0x%x "
                                                "is in DELETED state\n",
                                                rdata->ids.port_id);
                                        return NULL;
@@ -633,7 +646,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
        tgt->sq = dma_alloc_coherent(&hba->pcidev->dev, tgt->sq_mem_size,
                                     &tgt->sq_dma, GFP_KERNEL);
        if (!tgt->sq) {
-               printk(KERN_ALERT PFX "unable to allocate SQ memory %d\n",
+               printk(KERN_ERR PFX "unable to allocate SQ memory %d\n",
                        tgt->sq_mem_size);
                goto mem_alloc_failure;
        }
@@ -646,7 +659,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
        tgt->cq = dma_alloc_coherent(&hba->pcidev->dev, tgt->cq_mem_size,
                                     &tgt->cq_dma, GFP_KERNEL);
        if (!tgt->cq) {
-               printk(KERN_ALERT PFX "unable to allocate CQ memory %d\n",
+               printk(KERN_ERR PFX "unable to allocate CQ memory %d\n",
                        tgt->cq_mem_size);
                goto mem_alloc_failure;
        }
@@ -659,7 +672,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
        tgt->rq = dma_alloc_coherent(&hba->pcidev->dev, tgt->rq_mem_size,
                                        &tgt->rq_dma, GFP_KERNEL);
        if (!tgt->rq) {
-               printk(KERN_ALERT PFX "unable to allocate RQ memory %d\n",
+               printk(KERN_ERR PFX "unable to allocate RQ memory %d\n",
                        tgt->rq_mem_size);
                goto mem_alloc_failure;
        }
@@ -671,7 +684,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
        tgt->rq_pbl = dma_alloc_coherent(&hba->pcidev->dev, tgt->rq_pbl_size,
                                         &tgt->rq_pbl_dma, GFP_KERNEL);
        if (!tgt->rq_pbl) {
-               printk(KERN_ALERT PFX "unable to allocate RQ PBL %d\n",
+               printk(KERN_ERR PFX "unable to allocate RQ PBL %d\n",
                        tgt->rq_pbl_size);
                goto mem_alloc_failure;
        }
@@ -697,7 +710,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
        tgt->xferq = dma_alloc_coherent(&hba->pcidev->dev, tgt->xferq_mem_size,
                                        &tgt->xferq_dma, GFP_KERNEL);
        if (!tgt->xferq) {
-               printk(KERN_ALERT PFX "unable to allocate XFERQ %d\n",
+               printk(KERN_ERR PFX "unable to allocate XFERQ %d\n",
                        tgt->xferq_mem_size);
                goto mem_alloc_failure;
        }
@@ -711,7 +724,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
        tgt->confq = dma_alloc_coherent(&hba->pcidev->dev, tgt->confq_mem_size,
                                        &tgt->confq_dma, GFP_KERNEL);
        if (!tgt->confq) {
-               printk(KERN_ALERT PFX "unable to allocate CONFQ %d\n",
+               printk(KERN_ERR PFX "unable to allocate CONFQ %d\n",
                        tgt->confq_mem_size);
                goto mem_alloc_failure;
        }
@@ -726,7 +739,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
                                            tgt->confq_pbl_size,
                                            &tgt->confq_pbl_dma, GFP_KERNEL);
        if (!tgt->confq_pbl) {
-               printk(KERN_ALERT PFX "unable to allocate CONFQ PBL %d\n",
+               printk(KERN_ERR PFX "unable to allocate CONFQ PBL %d\n",
                        tgt->confq_pbl_size);
                goto mem_alloc_failure;
        }
@@ -751,7 +764,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
                                          tgt->conn_db_mem_size,
                                          &tgt->conn_db_dma, GFP_KERNEL);
        if (!tgt->conn_db) {
-               printk(KERN_ALERT PFX "unable to allocate conn_db %d\n",
+               printk(KERN_ERR PFX "unable to allocate conn_db %d\n",
                                                tgt->conn_db_mem_size);
                goto mem_alloc_failure;
        }
@@ -767,7 +780,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
                                      &tgt->lcq_dma, GFP_KERNEL);
 
        if (!tgt->lcq) {
-               printk(KERN_ALERT PFX "unable to allocate lcq %d\n",
+               printk(KERN_ERR PFX "unable to allocate lcq %d\n",
                       tgt->lcq_mem_size);
                goto mem_alloc_failure;
        }
index 2e7c136..27c9d65 100644 (file)
@@ -128,25 +128,7 @@ struct c4_inquiry {
        u8      reserved[2];
 };
 
-struct rdac_controller {
-       u8                      subsys_id[SUBSYS_ID_LEN];
-       u8                      slot_id[SLOT_ID_LEN];
-       int                     use_ms10;
-       struct kref             kref;
-       struct list_head        node; /* list of all controllers */
-       union                   {
-               struct rdac_pg_legacy legacy;
-               struct rdac_pg_expanded expanded;
-       } mode_select;
-       u8      index;
-       u8      array_name[ARRAY_LABEL_LEN];
-       spinlock_t              ms_lock;
-       int                     ms_queued;
-       struct work_struct      ms_work;
-       struct scsi_device      *ms_sdev;
-       struct list_head        ms_head;
-};
-
+#define UNIQUE_ID_LEN 16
 struct c8_inquiry {
        u8      peripheral_info;
        u8      page_code; /* 0xC8 */
@@ -159,12 +141,31 @@ struct c8_inquiry {
        u8      vol_user_label_len;
        u8      vol_user_label[60];
        u8      array_uniq_id_len;
-       u8      array_unique_id[16];
+       u8      array_unique_id[UNIQUE_ID_LEN];
        u8      array_user_label_len;
        u8      array_user_label[60];
        u8      lun[8];
 };
 
+struct rdac_controller {
+       u8                      array_id[UNIQUE_ID_LEN];
+       int                     use_ms10;
+       struct kref             kref;
+       struct list_head        node; /* list of all controllers */
+       union                   {
+               struct rdac_pg_legacy legacy;
+               struct rdac_pg_expanded expanded;
+       } mode_select;
+       u8      index;
+       u8      array_name[ARRAY_LABEL_LEN];
+       struct Scsi_Host        *host;
+       spinlock_t              ms_lock;
+       int                     ms_queued;
+       struct work_struct      ms_work;
+       struct scsi_device      *ms_sdev;
+       struct list_head        ms_head;
+};
+
 struct c2_inquiry {
        u8      peripheral_info;
        u8      page_code;      /* 0xC2 */
@@ -369,16 +370,17 @@ static void release_controller(struct kref *kref)
        kfree(ctlr);
 }
 
-static struct rdac_controller *get_controller(u8 *subsys_id, u8 *slot_id,
-                                               char *array_name)
+static struct rdac_controller *get_controller(int index, char *array_name,
+                       u8 *array_id, struct scsi_device *sdev)
 {
        struct rdac_controller *ctlr, *tmp;
 
        spin_lock(&list_lock);
 
        list_for_each_entry(tmp, &ctlr_list, node) {
-               if ((memcmp(tmp->subsys_id, subsys_id, SUBSYS_ID_LEN) == 0) &&
-                         (memcmp(tmp->slot_id, slot_id, SLOT_ID_LEN) == 0)) {
+               if ((memcmp(tmp->array_id, array_id, UNIQUE_ID_LEN) == 0) &&
+                         (tmp->index == index) &&
+                         (tmp->host == sdev->host)) {
                        kref_get(&tmp->kref);
                        spin_unlock(&list_lock);
                        return tmp;
@@ -389,16 +391,11 @@ static struct rdac_controller *get_controller(u8 *subsys_id, u8 *slot_id,
                goto done;
 
        /* initialize fields of controller */
-       memcpy(ctlr->subsys_id, subsys_id, SUBSYS_ID_LEN);
-       memcpy(ctlr->slot_id, slot_id, SLOT_ID_LEN);
+       memcpy(ctlr->array_id, array_id, UNIQUE_ID_LEN);
+       ctlr->index = index;
+       ctlr->host = sdev->host;
        memcpy(ctlr->array_name, array_name, ARRAY_LABEL_LEN);
 
-       /* update the controller index */
-       if (slot_id[1] == 0x31)
-               ctlr->index = 0;
-       else
-               ctlr->index = 1;
-
        kref_init(&ctlr->kref);
        ctlr->use_ms10 = -1;
        ctlr->ms_queued = 0;
@@ -444,7 +441,7 @@ done:
 }
 
 static int get_lun_info(struct scsi_device *sdev, struct rdac_dh_data *h,
-                       char *array_name)
+                       char *array_name, u8 *array_id)
 {
        int err, i;
        struct c8_inquiry *inqp;
@@ -463,6 +460,8 @@ static int get_lun_info(struct scsi_device *sdev, struct rdac_dh_data *h,
                        *(array_name+i) = inqp->array_user_label[(2*i)+1];
 
                *(array_name+ARRAY_LABEL_LEN-1) = '\0';
+               memset(array_id, 0, UNIQUE_ID_LEN);
+               memcpy(array_id, inqp->array_unique_id, inqp->array_uniq_id_len);
        }
        return err;
 }
@@ -504,16 +503,20 @@ static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h)
 }
 
 static int initialize_controller(struct scsi_device *sdev,
-                                struct rdac_dh_data *h, char *array_name)
+               struct rdac_dh_data *h, char *array_name, u8 *array_id)
 {
-       int err;
+       int err, index;
        struct c4_inquiry *inqp;
 
        err = submit_inquiry(sdev, 0xC4, sizeof(struct c4_inquiry), h);
        if (err == SCSI_DH_OK) {
                inqp = &h->inq.c4;
-               h->ctlr = get_controller(inqp->subsys_id, inqp->slot_id,
-                                       array_name);
+               /* get the controller index */
+               if (inqp->slot_id[1] == 0x31)
+                       index = 0;
+               else
+                       index = 1;
+               h->ctlr = get_controller(index, array_name, array_id, sdev);
                if (!h->ctlr)
                        err = SCSI_DH_RES_TEMP_UNAVAIL;
        }
@@ -835,6 +838,7 @@ static int rdac_bus_attach(struct scsi_device *sdev)
        unsigned long flags;
        int err;
        char array_name[ARRAY_LABEL_LEN];
+       char array_id[UNIQUE_ID_LEN];
 
        scsi_dh_data = kzalloc(sizeof(*scsi_dh_data)
                               + sizeof(*h) , GFP_KERNEL);
@@ -849,11 +853,11 @@ static int rdac_bus_attach(struct scsi_device *sdev)
        h->lun = UNINITIALIZED_LUN;
        h->state = RDAC_STATE_ACTIVE;
 
-       err = get_lun_info(sdev, h, array_name);
+       err = get_lun_info(sdev, h, array_name, array_id);
        if (err != SCSI_DH_OK)
                goto failed;
 
-       err = initialize_controller(sdev, h, array_name);
+       err = initialize_controller(sdev, h, array_name, array_id);
        if (err != SCSI_DH_OK)
                goto failed;
 
index 204fa8d..ba710e3 100644 (file)
@@ -486,6 +486,19 @@ static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *netdev,
        return 0;
 }
 
+/**
+ * fcoe_port_send() - Send an Ethernet-encapsulated FIP/FCoE frame
+ * @port: The FCoE port
+ * @skb: The FIP/FCoE packet to be sent
+ */
+static void fcoe_port_send(struct fcoe_port *port, struct sk_buff *skb)
+{
+       if (port->fcoe_pending_queue.qlen)
+               fcoe_check_wait_queue(port->lport, skb);
+       else if (fcoe_start_io(skb))
+               fcoe_check_wait_queue(port->lport, skb);
+}
+
 /**
  * fcoe_fip_send() - Send an Ethernet-encapsulated FIP frame
  * @fip: The FCoE controller
@@ -494,7 +507,7 @@ static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *netdev,
 static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
 {
        skb->dev = fcoe_from_ctlr(fip)->netdev;
-       dev_queue_xmit(skb);
+       fcoe_port_send(lport_priv(fip->lp), skb);
 }
 
 /**
@@ -1257,30 +1270,20 @@ static int fcoe_cpu_callback(struct notifier_block *nfb,
 /**
  * fcoe_select_cpu() - Selects CPU to handle post-processing of incoming
  *                     command.
- * @curr_cpu:   CPU which received request
  *
- * This routine selects next CPU based on cpumask.
+ * This routine selects next CPU based on cpumask to distribute
+ * incoming requests in round robin.
  *
- * Returns: int (CPU number). Caller to verify if returned CPU is online or not.
+ * Returns: int CPU number
  */
-static unsigned int fcoe_select_cpu(unsigned int curr_cpu)
+static inline unsigned int fcoe_select_cpu(void)
 {
        static unsigned int selected_cpu;
 
-       if (num_online_cpus() == 1)
-               return curr_cpu;
-       /*
-        * Doing following check, to skip "curr_cpu (smp_processor_id)"
-        * from selection of CPU is intentional. This is to avoid same CPU
-        * doing post-processing of command. "curr_cpu" to just receive
-        * incoming request in case where rx_id is UNKNOWN and all other
-        * CPU to actually process the command(s)
-        */
-       do {
-               selected_cpu = cpumask_next(selected_cpu, cpu_online_mask);
-               if (selected_cpu >= nr_cpu_ids)
-                       selected_cpu = cpumask_first(cpu_online_mask);
-       } while (selected_cpu == curr_cpu);
+       selected_cpu = cpumask_next(selected_cpu, cpu_online_mask);
+       if (selected_cpu >= nr_cpu_ids)
+               selected_cpu = cpumask_first(cpu_online_mask);
+
        return selected_cpu;
 }
 
@@ -1350,30 +1353,26 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
 
        fr = fcoe_dev_from_skb(skb);
        fr->fr_dev = lport;
-       fr->ptype = ptype;
 
        /*
         * In case the incoming frame's exchange is originated from
         * the initiator, then received frame's exchange id is ANDed
         * with fc_cpu_mask bits to get the same cpu on which exchange
-        * was originated, otherwise just use the current cpu.
+        * was originated, otherwise select cpu using rx exchange id
+        * or fcoe_select_cpu().
         */
        if (ntoh24(fh->fh_f_ctl) & FC_FC_EX_CTX)
                cpu = ntohs(fh->fh_ox_id) & fc_cpu_mask;
        else {
-               cpu = smp_processor_id();
-
-               if ((fh->fh_type == FC_TYPE_FCP) &&
-                   (ntohs(fh->fh_rx_id) == FC_XID_UNKNOWN)) {
-                       do {
-                               cpu = fcoe_select_cpu(cpu);
-                       } while (!cpu_online(cpu));
-               } else  if ((fh->fh_type == FC_TYPE_FCP) &&
-                           (ntohs(fh->fh_rx_id) != FC_XID_UNKNOWN)) {
+               if (ntohs(fh->fh_rx_id) == FC_XID_UNKNOWN)
+                       cpu = fcoe_select_cpu();
+               else
                        cpu = ntohs(fh->fh_rx_id) & fc_cpu_mask;
-               } else
-                       cpu = smp_processor_id();
        }
+
+       if (cpu >= nr_cpu_ids)
+               goto err;
+
        fps = &per_cpu(fcoe_percpu, cpu);
        spin_lock_bh(&fps->fcoe_rx_list.lock);
        if (unlikely(!fps->thread)) {
@@ -1572,11 +1571,7 @@ int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)
 
        /* send down to lld */
        fr_dev(fp) = lport;
-       if (port->fcoe_pending_queue.qlen)
-               fcoe_check_wait_queue(lport, skb);
-       else if (fcoe_start_io(skb))
-               fcoe_check_wait_queue(lport, skb);
-
+       fcoe_port_send(port, skb);
        return 0;
 }
 
index c6f99b1..ec61bdb 100644 (file)
@@ -1219,8 +1219,8 @@ static void complete_scsi_command(struct CommandList *cp)
                dev_warn(&h->pdev->dev, "cp %p reports abort failed\n", cp);
                break;
        case CMD_UNSOLICITED_ABORT:
-               cmd->result = DID_RESET << 16;
-               dev_warn(&h->pdev->dev, "cp %p aborted do to an unsolicited "
+               cmd->result = DID_SOFT_ERROR << 16; /* retry the command */
+               dev_warn(&h->pdev->dev, "cp %p aborted due to an unsolicited "
                        "abort\n", cp);
                break;
        case CMD_TIMEOUT:
index 6d8dcd4..7f53cea 100644 (file)
@@ -214,7 +214,7 @@ static void SA5_submit_command(struct ctlr_info *h,
        dev_dbg(&h->pdev->dev, "Sending %x, tag = %x\n", c->busaddr,
                c->Header.Tag.lower);
        writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET);
-       (void) readl(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;
index 888086c..8d63630 100644 (file)
@@ -8778,14 +8778,14 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
        if (rc != PCIBIOS_SUCCESSFUL) {
                dev_err(&pdev->dev, "Failed to save PCI config space\n");
                rc = -EIO;
-               goto cleanup_nomem;
+               goto out_msi_disable;
        }
 
        if ((rc = ipr_save_pcix_cmd_reg(ioa_cfg)))
-               goto cleanup_nomem;
+               goto out_msi_disable;
 
        if ((rc = ipr_set_pcix_cmd_reg(ioa_cfg)))
-               goto cleanup_nomem;
+               goto out_msi_disable;
 
        if (ioa_cfg->sis64)
                ioa_cfg->cfg_table_size = (sizeof(struct ipr_config_table_hdr64)
@@ -8800,7 +8800,7 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
        if (rc < 0) {
                dev_err(&pdev->dev,
                        "Couldn't allocate enough memory for device driver!\n");
-               goto cleanup_nomem;
+               goto out_msi_disable;
        }
 
        /*
@@ -8845,10 +8845,10 @@ out:
 
 cleanup_nolog:
        ipr_free_mem(ioa_cfg);
-cleanup_nomem:
-       iounmap(ipr_regs);
 out_msi_disable:
        pci_disable_msi(pdev);
+cleanup_nomem:
+       iounmap(ipr_regs);
 out_release_regions:
        pci_release_regions(pdev);
 out_scsi_host_put:
index f5a0665..01ff082 100644 (file)
@@ -802,10 +802,8 @@ static struct fc_exch *fc_exch_find(struct fc_exch_mgr *mp, u16 xid)
                pool = per_cpu_ptr(mp->pool, xid & fc_cpu_mask);
                spin_lock_bh(&pool->lock);
                ep = fc_exch_ptr_get(pool, (xid - mp->min_xid) >> fc_cpu_order);
-               if (ep) {
+               if (ep && ep->xid == xid)
                        fc_exch_hold(ep);
-                       WARN_ON(ep->xid != xid);
-               }
                spin_unlock_bh(&pool->lock);
        }
        return ep;
@@ -2465,8 +2463,11 @@ int fc_setup_exch_mgr(void)
 
        fc_exch_workqueue = create_singlethread_workqueue("fc_exch_workqueue");
        if (!fc_exch_workqueue)
-               return -ENOMEM;
+               goto err;
        return 0;
+err:
+       kmem_cache_destroy(fc_em_cachep);
+       return -ENOMEM;
 }
 
 /**
index 9cd2149..afb63c8 100644 (file)
@@ -498,7 +498,7 @@ crc_err:
                        stats = per_cpu_ptr(lport->dev_stats, get_cpu());
                        stats->ErrorFrames++;
                        /* per cpu count, not total count, but OK for limit */
-                       if (stats->InvalidCRCCount++ < 5)
+                       if (stats->InvalidCRCCount++ < FC_MAX_ERROR_CNT)
                                printk(KERN_WARNING "libfc: CRC error on data "
                                       "frame for port (%6.6x)\n",
                                       lport->port_id);
@@ -690,7 +690,7 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq,
 }
 
 /**
- * fc_fcp_abts_resp() - Send an ABTS response
+ * fc_fcp_abts_resp() - Receive an ABTS response
  * @fsp: The FCP packet that is being aborted
  * @fp:         The response frame
  */
@@ -730,7 +730,7 @@ static void fc_fcp_abts_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
 }
 
 /**
- * fc_fcp_recv() - Reveive an FCP frame
+ * fc_fcp_recv() - Receive an FCP frame
  * @seq: The sequence the frame is on
  * @fp:         The received frame
  * @arg: The related FCP packet
@@ -1084,6 +1084,7 @@ static int fc_fcp_pkt_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp)
        rc = lport->tt.fcp_cmd_send(lport, fsp, fc_fcp_recv);
        if (unlikely(rc)) {
                spin_lock_irqsave(&si->scsi_queue_lock, flags);
+               fsp->cmd->SCp.ptr = NULL;
                list_del(&fsp->list);
                spin_unlock_irqrestore(&si->scsi_queue_lock, flags);
        }
@@ -1645,12 +1646,10 @@ static void fc_fcp_srr(struct fc_fcp_pkt *fsp, enum fc_rctl r_ctl, u32 offset)
        struct fc_seq *seq;
        struct fcp_srr *srr;
        struct fc_frame *fp;
-       u8 cdb_op;
        unsigned int rec_tov;
 
        rport = fsp->rport;
        rpriv = rport->dd_data;
-       cdb_op = fsp->cdb_cmd.fc_cdb[0];
 
        if (!(rpriv->flags & FC_RP_FLAGS_RETRY) ||
            rpriv->rp_state != RPORT_ST_READY)
index e008b16..e55ed9c 100644 (file)
@@ -1352,7 +1352,6 @@ static void fc_lport_timeout(struct work_struct *work)
                WARN_ON(1);
                break;
        case LPORT_ST_READY:
-               WARN_ON(1);
                break;
        case LPORT_ST_RESET:
                break;
index 874e29d..f84084b 100644 (file)
@@ -849,6 +849,9 @@ static struct domain_device *sas_ex_discover_expander(
 
        res = sas_discover_expander(child);
        if (res) {
+               spin_lock_irq(&parent->port->dev_list_lock);
+               list_del(&child->dev_list_node);
+               spin_unlock_irq(&parent->port->dev_list_lock);
                kfree(child);
                return NULL;
        }
index 8ec2c86..c088a36 100644 (file)
  *******************************************************************/
 
 #include <scsi/scsi_host.h>
+
+#if defined(CONFIG_DEBUG_FS) && !defined(CONFIG_SCSI_LPFC_DEBUG_FS)
+#define CONFIG_SCSI_LPFC_DEBUG_FS
+#endif
+
 struct lpfc_sli2_slim;
 
 #define LPFC_PCI_DEV_LP                0x1
@@ -465,9 +470,10 @@ enum intr_type_t {
 struct unsol_rcv_ct_ctx {
        uint32_t ctxt_id;
        uint32_t SID;
-       uint32_t oxid;
        uint32_t flags;
 #define UNSOL_VALID    0x00000001
+       uint16_t oxid;
+       uint16_t rxid;
 };
 
 #define LPFC_USER_LINK_SPEED_AUTO      0       /* auto select (default)*/
@@ -674,6 +680,9 @@ struct lpfc_hba {
        uint32_t cfg_enable_rrq;
        uint32_t cfg_topology;
        uint32_t cfg_link_speed;
+#define LPFC_FCF_FOV 1         /* Fast fcf failover */
+#define LPFC_FCF_PRIORITY 2    /* Priority fcf failover */
+       uint32_t cfg_fcf_failover_policy;
        uint32_t cfg_cr_delay;
        uint32_t cfg_cr_count;
        uint32_t cfg_multi_ring_support;
@@ -845,9 +854,13 @@ struct lpfc_hba {
        /* iDiag debugfs sub-directory */
        struct dentry *idiag_root;
        struct dentry *idiag_pci_cfg;
+       struct dentry *idiag_bar_acc;
        struct dentry *idiag_que_info;
        struct dentry *idiag_que_acc;
        struct dentry *idiag_drb_acc;
+       struct dentry *idiag_ctl_acc;
+       struct dentry *idiag_mbx_acc;
+       struct dentry *idiag_ext_acc;
 #endif
 
        /* Used for deferred freeing of ELS data buffers */
index 135a53b..2542f1f 100644 (file)
@@ -754,6 +754,47 @@ lpfc_issue_reset(struct device *dev, struct device_attribute *attr,
                return status;
 }
 
+/**
+ * lpfc_sli4_pdev_status_reg_wait - Wait for pdev status register for readyness
+ * @phba: lpfc_hba pointer.
+ *
+ * Description:
+ * SLI4 interface type-2 device to wait on the sliport status register for
+ * the readyness after performing a firmware reset.
+ *
+ * Returns:
+ * zero for success
+ **/
+static int
+lpfc_sli4_pdev_status_reg_wait(struct lpfc_hba *phba)
+{
+       struct lpfc_register portstat_reg;
+       int i;
+
+
+       lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr,
+                  &portstat_reg.word0);
+
+       /* wait for the SLI port firmware ready after firmware reset */
+       for (i = 0; i < LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT; i++) {
+               msleep(10);
+               lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr,
+                          &portstat_reg.word0);
+               if (!bf_get(lpfc_sliport_status_err, &portstat_reg))
+                       continue;
+               if (!bf_get(lpfc_sliport_status_rn, &portstat_reg))
+                       continue;
+               if (!bf_get(lpfc_sliport_status_rdy, &portstat_reg))
+                       continue;
+               break;
+       }
+
+       if (i < LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT)
+               return 0;
+       else
+               return -EIO;
+}
+
 /**
  * lpfc_sli4_pdev_reg_request - Request physical dev to perform a register acc
  * @phba: lpfc_hba pointer.
@@ -769,6 +810,7 @@ static ssize_t
 lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode)
 {
        struct completion online_compl;
+       struct pci_dev *pdev = phba->pcidev;
        uint32_t reg_val;
        int status = 0;
        int rc;
@@ -781,6 +823,14 @@ lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode)
             LPFC_SLI_INTF_IF_TYPE_2))
                return -EPERM;
 
+       if (!pdev->is_physfn)
+               return -EPERM;
+
+       /* Disable SR-IOV virtual functions if enabled */
+       if (phba->cfg_sriov_nr_virtfn) {
+               pci_disable_sriov(pdev);
+               phba->cfg_sriov_nr_virtfn = 0;
+       }
        status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
 
        if (status != 0)
@@ -805,7 +855,10 @@ lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode)
        readl(phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PDEV_CTL_OFFSET);
 
        /* delay driver action following IF_TYPE_2 reset */
-       msleep(100);
+       rc = lpfc_sli4_pdev_status_reg_wait(phba);
+
+       if (rc)
+               return -EIO;
 
        init_completion(&online_compl);
        rc = lpfc_workq_post_event(phba, &status, &online_compl,
@@ -895,6 +948,10 @@ lpfc_board_mode_store(struct device *dev, struct device_attribute *attr,
 
        if (!phba->cfg_enable_hba_reset)
                return -EACCES;
+
+       lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+               "3050 lpfc_board_mode set to %s\n", buf);
+
        init_completion(&online_compl);
 
        if(strncmp(buf, "online", sizeof("online") - 1) == 0) {
@@ -1290,6 +1347,10 @@ lpfc_poll_store(struct device *dev, struct device_attribute *attr,
        if (phba->sli_rev == LPFC_SLI_REV4)
                val = 0;
 
+       lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+               "3051 lpfc_poll changed from %d to %d\n",
+               phba->cfg_poll, val);
+
        spin_lock_irq(&phba->hbalock);
 
        old_val = phba->cfg_poll;
@@ -1414,80 +1475,10 @@ lpfc_sriov_hw_max_virtfn_show(struct device *dev,
        struct Scsi_Host *shost = class_to_shost(dev);
        struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
        struct lpfc_hba *phba = vport->phba;
-       struct pci_dev *pdev = phba->pcidev;
-       union  lpfc_sli4_cfg_shdr *shdr;
-       uint32_t shdr_status, shdr_add_status;
-       LPFC_MBOXQ_t *mboxq;
-       struct lpfc_mbx_get_prof_cfg *get_prof_cfg;
-       struct lpfc_rsrc_desc_pcie *desc;
-       uint32_t max_nr_virtfn;
-       uint32_t desc_count;
-       int length, rc, i;
-
-       if ((phba->sli_rev < LPFC_SLI_REV4) ||
-           (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
-            LPFC_SLI_INTF_IF_TYPE_2))
-               return -EPERM;
-
-       if (!pdev->is_physfn)
-               return snprintf(buf, PAGE_SIZE, "%d\n", 0);
-
-       mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-       if (!mboxq)
-               return -ENOMEM;
-
-       /* get the maximum number of virtfn support by physfn */
-       length = (sizeof(struct lpfc_mbx_get_prof_cfg) -
-                 sizeof(struct lpfc_sli4_cfg_mhdr));
-       lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON,
-                        LPFC_MBOX_OPCODE_GET_PROFILE_CONFIG,
-                        length, LPFC_SLI4_MBX_EMBED);
-       shdr = (union lpfc_sli4_cfg_shdr *)
-               &mboxq->u.mqe.un.sli4_config.header.cfg_shdr;
-       bf_set(lpfc_mbox_hdr_pf_num, &shdr->request,
-              phba->sli4_hba.iov.pf_number + 1);
-
-       get_prof_cfg = &mboxq->u.mqe.un.get_prof_cfg;
-       bf_set(lpfc_mbx_get_prof_cfg_prof_tp, &get_prof_cfg->u.request,
-              LPFC_CFG_TYPE_CURRENT_ACTIVE);
-
-       rc = lpfc_sli_issue_mbox_wait(phba, mboxq,
-                               lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG));
-
-       if (rc != MBX_TIMEOUT) {
-               /* check return status */
-               shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
-               shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
-                                        &shdr->response);
-               if (shdr_status || shdr_add_status || rc)
-                       goto error_out;
-
-       } else
-               goto error_out;
-
-       desc_count = get_prof_cfg->u.response.prof_cfg.rsrc_desc_count;
-
-       for (i = 0; i < LPFC_RSRC_DESC_MAX_NUM; i++) {
-               desc = (struct lpfc_rsrc_desc_pcie *)
-                       &get_prof_cfg->u.response.prof_cfg.desc[i];
-               if (LPFC_RSRC_DESC_TYPE_PCIE ==
-                   bf_get(lpfc_rsrc_desc_pcie_type, desc)) {
-                       max_nr_virtfn = bf_get(lpfc_rsrc_desc_pcie_nr_virtfn,
-                                              desc);
-                       break;
-               }
-       }
-
-       if (i < LPFC_RSRC_DESC_MAX_NUM) {
-               if (rc != MBX_TIMEOUT)
-                       mempool_free(mboxq, phba->mbox_mem_pool);
-               return snprintf(buf, PAGE_SIZE, "%d\n", max_nr_virtfn);
-       }
+       uint16_t max_nr_virtfn;
 
-error_out:
-       if (rc != MBX_TIMEOUT)
-               mempool_free(mboxq, phba->mbox_mem_pool);
-       return -EIO;
+       max_nr_virtfn = lpfc_sli_sriov_nr_virtfn_get(phba);
+       return snprintf(buf, PAGE_SIZE, "%d\n", max_nr_virtfn);
 }
 
 /**
@@ -1605,6 +1596,9 @@ static int \
 lpfc_##attr##_set(struct lpfc_hba *phba, uint val) \
 { \
        if (val >= minval && val <= maxval) {\
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT, \
+                       "3052 lpfc_" #attr " changed from %d to %d\n", \
+                       phba->cfg_##attr, val); \
                phba->cfg_##attr = val;\
                return 0;\
        }\
@@ -1762,6 +1756,9 @@ static int \
 lpfc_##attr##_set(struct lpfc_vport *vport, uint val) \
 { \
        if (val >= minval && val <= maxval) {\
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, \
+                       "3053 lpfc_" #attr " changed from %d to %d\n", \
+                       vport->cfg_##attr, val); \
                vport->cfg_##attr = val;\
                return 0;\
        }\
@@ -2196,6 +2193,9 @@ lpfc_param_show(enable_npiv);
 lpfc_param_init(enable_npiv, 1, 0, 1);
 static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO, lpfc_enable_npiv_show, NULL);
 
+LPFC_ATTR_R(fcf_failover_policy, 1, 1, 2,
+       "FCF Fast failover=1 Priority failover=2");
+
 int lpfc_enable_rrq;
 module_param(lpfc_enable_rrq, int, S_IRUGO);
 MODULE_PARM_DESC(lpfc_enable_rrq, "Enable RRQ functionality");
@@ -2678,6 +2678,9 @@ lpfc_topology_store(struct device *dev, struct device_attribute *attr,
                if (nolip)
                        return strlen(buf);
 
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+                       "3054 lpfc_topology changed from %d to %d\n",
+                       prev_val, val);
                err = lpfc_issue_lip(lpfc_shost_from_vport(phba->pport));
                if (err) {
                        phba->cfg_topology = prev_val;
@@ -3101,6 +3104,10 @@ lpfc_link_speed_store(struct device *dev, struct device_attribute *attr,
        if (sscanf(val_buf, "%i", &val) != 1)
                return -EINVAL;
 
+       lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+               "3055 lpfc_link_speed changed from %d to %d %s\n",
+               phba->cfg_link_speed, val, nolip ? "(nolip)" : "(lip)");
+
        if (((val == LPFC_USER_LINK_SPEED_1G) && !(phba->lmt & LMT_1Gb)) ||
            ((val == LPFC_USER_LINK_SPEED_2G) && !(phba->lmt & LMT_2Gb)) ||
            ((val == LPFC_USER_LINK_SPEED_4G) && !(phba->lmt & LMT_4Gb)) ||
@@ -3678,7 +3685,9 @@ LPFC_ATTR_R(enable_bg, 0, 0, 1, "Enable BlockGuard Support");
 #      - Default will result in registering capabilities for all profiles.
 #
 */
-unsigned int lpfc_prot_mask = SHOST_DIF_TYPE1_PROTECTION;
+unsigned int lpfc_prot_mask = SHOST_DIF_TYPE1_PROTECTION |
+                             SHOST_DIX_TYPE0_PROTECTION |
+                             SHOST_DIX_TYPE1_PROTECTION;
 
 module_param(lpfc_prot_mask, uint, S_IRUGO);
 MODULE_PARM_DESC(lpfc_prot_mask, "host protection mask");
@@ -3769,6 +3778,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
        &dev_attr_lpfc_fdmi_on,
        &dev_attr_lpfc_max_luns,
        &dev_attr_lpfc_enable_npiv,
+       &dev_attr_lpfc_fcf_failover_policy,
        &dev_attr_lpfc_enable_rrq,
        &dev_attr_nport_evt_cnt,
        &dev_attr_board_mode,
@@ -4989,6 +4999,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
        lpfc_link_speed_init(phba, lpfc_link_speed);
        lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
        lpfc_enable_npiv_init(phba, lpfc_enable_npiv);
+       lpfc_fcf_failover_policy_init(phba, lpfc_fcf_failover_policy);
        lpfc_enable_rrq_init(phba, lpfc_enable_rrq);
        lpfc_use_msi_init(phba, lpfc_use_msi);
        lpfc_fcp_imax_init(phba, lpfc_fcp_imax);
index 7fb0ba4..6760c69 100644 (file)
@@ -42,6 +42,7 @@
 #include "lpfc.h"
 #include "lpfc_logmsg.h"
 #include "lpfc_crtn.h"
+#include "lpfc_debugfs.h"
 #include "lpfc_vport.h"
 #include "lpfc_version.h"
 
@@ -960,8 +961,10 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                                                    evt_dat->immed_dat].oxid,
                                                phba->ct_ctx[
                                                    evt_dat->immed_dat].SID);
+                       phba->ct_ctx[evt_dat->immed_dat].rxid =
+                               piocbq->iocb.ulpContext;
                        phba->ct_ctx[evt_dat->immed_dat].oxid =
-                                               piocbq->iocb.ulpContext;
+                               piocbq->iocb.unsli3.rcvsli3.ox_id;
                        phba->ct_ctx[evt_dat->immed_dat].SID =
                                piocbq->iocb.un.rcvels.remoteID;
                        phba->ct_ctx[evt_dat->immed_dat].flags = UNSOL_VALID;
@@ -1312,7 +1315,8 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,
                        rc = IOCB_ERROR;
                        goto issue_ct_rsp_exit;
                }
-               icmd->ulpContext = phba->ct_ctx[tag].oxid;
+               icmd->ulpContext = phba->ct_ctx[tag].rxid;
+               icmd->unsli3.rcvsli3.ox_id = phba->ct_ctx[tag].oxid;
                ndlp = lpfc_findnode_did(phba->pport, phba->ct_ctx[tag].SID);
                if (!ndlp) {
                        lpfc_printf_log(phba, KERN_WARNING, LOG_ELS,
@@ -1337,9 +1341,7 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,
                        goto issue_ct_rsp_exit;
                }
 
-               icmd->un.ulpWord[3] = ndlp->nlp_rpi;
-               if (phba->sli_rev == LPFC_SLI_REV4)
-                       icmd->ulpContext =
+               icmd->un.ulpWord[3] =
                                phba->sli4_hba.rpi_ids[ndlp->nlp_rpi];
 
                /* The exchange is done, mark the entry as invalid */
@@ -1351,8 +1353,8 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,
 
        /* Xmit CT response on exchange <xid> */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-                       "2722 Xmit CT response on exchange x%x Data: x%x x%x\n",
-                       icmd->ulpContext, icmd->ulpIoTag, phba->link_state);
+               "2722 Xmit CT response on exchange x%x Data: x%x x%x x%x\n",
+               icmd->ulpContext, icmd->ulpIoTag, tag, phba->link_state);
 
        ctiocb->iocb_cmpl = NULL;
        ctiocb->iocb_flag |= LPFC_IO_LIBDFC;
@@ -1471,13 +1473,12 @@ send_mgmt_rsp_exit:
 /**
  * lpfc_bsg_diag_mode_enter - process preparing into device diag loopback mode
  * @phba: Pointer to HBA context object.
- * @job: LPFC_BSG_VENDOR_DIAG_MODE
  *
  * This function is responsible for preparing driver for diag loopback
  * on device.
  */
 static int
-lpfc_bsg_diag_mode_enter(struct lpfc_hba *phba, struct fc_bsg_job *job)
+lpfc_bsg_diag_mode_enter(struct lpfc_hba *phba)
 {
        struct lpfc_vport **vports;
        struct Scsi_Host *shost;
@@ -1521,7 +1522,6 @@ lpfc_bsg_diag_mode_enter(struct lpfc_hba *phba, struct fc_bsg_job *job)
 /**
  * lpfc_bsg_diag_mode_exit - exit process from device diag loopback mode
  * @phba: Pointer to HBA context object.
- * @job: LPFC_BSG_VENDOR_DIAG_MODE
  *
  * This function is responsible for driver exit processing of setting up
  * diag loopback mode on device.
@@ -1567,7 +1567,7 @@ lpfc_sli3_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job)
        uint32_t link_flags;
        uint32_t timeout;
        LPFC_MBOXQ_t *pmboxq;
-       int mbxstatus;
+       int mbxstatus = MBX_SUCCESS;
        int i = 0;
        int rc = 0;
 
@@ -1586,7 +1586,7 @@ lpfc_sli3_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job)
                goto job_error;
        }
 
-       rc = lpfc_bsg_diag_mode_enter(phba, job);
+       rc = lpfc_bsg_diag_mode_enter(phba);
        if (rc)
                goto job_error;
 
@@ -1741,7 +1741,7 @@ lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job)
        uint32_t link_flags, timeout, req_len, alloc_len;
        struct lpfc_mbx_set_link_diag_loopback *link_diag_loopback;
        LPFC_MBOXQ_t *pmboxq = NULL;
-       int mbxstatus, i, rc = 0;
+       int mbxstatus = MBX_SUCCESS, i, rc = 0;
 
        /* no data to return just the return code */
        job->reply->reply_payload_rcv_len = 0;
@@ -1758,7 +1758,7 @@ lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job)
                goto job_error;
        }
 
-       rc = lpfc_bsg_diag_mode_enter(phba, job);
+       rc = lpfc_bsg_diag_mode_enter(phba);
        if (rc)
                goto job_error;
 
@@ -1982,7 +1982,7 @@ lpfc_sli4_bsg_link_diag_test(struct fc_bsg_job *job)
                goto job_error;
        }
 
-       rc = lpfc_bsg_diag_mode_enter(phba, job);
+       rc = lpfc_bsg_diag_mode_enter(phba);
        if (rc)
                goto job_error;
 
@@ -3178,6 +3178,11 @@ lpfc_bsg_issue_mbox_ext_handle_job(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
                                "(x%x/x%x) complete bsg job done, bsize:%d\n",
                                phba->mbox_ext_buf_ctx.nembType,
                                phba->mbox_ext_buf_ctx.mboxType, size);
+               lpfc_idiag_mbxacc_dump_bsg_mbox(phba,
+                                       phba->mbox_ext_buf_ctx.nembType,
+                                       phba->mbox_ext_buf_ctx.mboxType,
+                                       dma_ebuf, sta_pos_addr,
+                                       phba->mbox_ext_buf_ctx.mbx_dmabuf, 0);
        } else
                spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
 
@@ -3430,6 +3435,10 @@ lpfc_bsg_sli_cfg_read_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
                                "ext_buf_cnt:%d\n", ext_buf_cnt);
        }
 
+       /* before dma descriptor setup */
+       lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_rd, dma_mbox,
+                                       sta_pre_addr, dmabuf, ext_buf_cnt);
+
        /* reject non-embedded mailbox command with none external buffer */
        if (ext_buf_cnt == 0) {
                rc = -EPERM;
@@ -3477,6 +3486,10 @@ lpfc_bsg_sli_cfg_read_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
                }
        }
 
+       /* after dma descriptor setup */
+       lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_rd, dma_mbox,
+                                       sta_pos_addr, dmabuf, ext_buf_cnt);
+
        /* construct base driver mbox command */
        pmb = &pmboxq->u.mb;
        pmbx = (uint8_t *)dmabuf->virt;
@@ -3511,7 +3524,7 @@ lpfc_bsg_sli_cfg_read_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
                lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
                                "2947 Issued SLI_CONFIG ext-buffer "
                                "maibox command, rc:x%x\n", rc);
-               return 1;
+               return SLI_CONFIG_HANDLED;
        }
        lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
                        "2948 Failed to issue SLI_CONFIG ext-buffer "
@@ -3549,7 +3562,7 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
        LPFC_MBOXQ_t *pmboxq = NULL;
        MAILBOX_t *pmb;
        uint8_t *mbx;
-       int rc = 0, i;
+       int rc = SLI_CONFIG_NOT_HANDLED, i;
 
        mbox_req =
           (struct dfc_mbox_req *)job->request->rqst_data.h_vendor.vendor_cmd;
@@ -3591,12 +3604,20 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
                                "ext_buf_cnt:%d\n", ext_buf_cnt);
        }
 
+       /* before dma buffer descriptor setup */
+       lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_wr, dma_mbox,
+                                       sta_pre_addr, dmabuf, ext_buf_cnt);
+
        if (ext_buf_cnt == 0)
                return -EPERM;
 
        /* for the first external buffer */
        lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, 0, dmabuf, dmabuf);
 
+       /* after dma descriptor setup */
+       lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_wr, dma_mbox,
+                                       sta_pos_addr, dmabuf, ext_buf_cnt);
+
        /* log for looking forward */
        for (i = 1; i < ext_buf_cnt; i++) {
                if (nemb_tp == nemb_mse)
@@ -3660,7 +3681,7 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
                        lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
                                        "2955 Issued SLI_CONFIG ext-buffer "
                                        "maibox command, rc:x%x\n", rc);
-                       return 1;
+                       return SLI_CONFIG_HANDLED;
                }
                lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
                                "2956 Failed to issue SLI_CONFIG ext-buffer "
@@ -3668,6 +3689,11 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
                rc = -EPIPE;
        }
 
+       /* wait for additoinal external buffers */
+       job->reply->result = 0;
+       job->job_done(job);
+       return SLI_CONFIG_HANDLED;
+
 job_error:
        if (pmboxq)
                mempool_free(pmboxq, phba->mbox_mem_pool);
@@ -3840,6 +3866,12 @@ lpfc_bsg_read_ebuf_get(struct lpfc_hba *phba, struct fc_bsg_job *job)
        dmabuf = list_first_entry(&phba->mbox_ext_buf_ctx.ext_dmabuf_list,
                                  struct lpfc_dmabuf, list);
        list_del_init(&dmabuf->list);
+
+       /* after dma buffer descriptor setup */
+       lpfc_idiag_mbxacc_dump_bsg_mbox(phba, phba->mbox_ext_buf_ctx.nembType,
+                                       mbox_rd, dma_ebuf, sta_pos_addr,
+                                       dmabuf, index);
+
        pbuf = (uint8_t *)dmabuf->virt;
        job->reply->reply_payload_rcv_len =
                sg_copy_from_buffer(job->reply_payload.sg_list,
@@ -3922,6 +3954,11 @@ lpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct fc_bsg_job *job,
                                        dmabuf);
        list_add_tail(&dmabuf->list, &phba->mbox_ext_buf_ctx.ext_dmabuf_list);
 
+       /* after write dma buffer */
+       lpfc_idiag_mbxacc_dump_bsg_mbox(phba, phba->mbox_ext_buf_ctx.nembType,
+                                       mbox_wr, dma_ebuf, sta_pos_addr,
+                                       dmabuf, index);
+
        if (phba->mbox_ext_buf_ctx.seqNum == phba->mbox_ext_buf_ctx.numBuf) {
                lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
                                "2968 SLI_CONFIG ext-buffer wr all %d "
@@ -3959,7 +3996,7 @@ lpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct fc_bsg_job *job,
                        lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
                                        "2969 Issued SLI_CONFIG ext-buffer "
                                        "maibox command, rc:x%x\n", rc);
-                       return 1;
+                       return SLI_CONFIG_HANDLED;
                }
                lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
                                "2970 Failed to issue SLI_CONFIG ext-buffer "
@@ -4039,14 +4076,14 @@ lpfc_bsg_handle_sli_cfg_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
                            struct lpfc_dmabuf *dmabuf)
 {
        struct dfc_mbox_req *mbox_req;
-       int rc;
+       int rc = SLI_CONFIG_NOT_HANDLED;
 
        mbox_req =
           (struct dfc_mbox_req *)job->request->rqst_data.h_vendor.vendor_cmd;
 
        /* mbox command with/without single external buffer */
        if (mbox_req->extMboxTag == 0 && mbox_req->extSeqNum == 0)
-               return SLI_CONFIG_NOT_HANDLED;
+               return rc;
 
        /* mbox command and first external buffer */
        if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_IDLE) {
@@ -4249,7 +4286,7 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
                 * mailbox extension size
                 */
                if ((transmit_length > receive_length) ||
-                       (transmit_length > MAILBOX_EXT_SIZE)) {
+                       (transmit_length > BSG_MBOX_SIZE - sizeof(MAILBOX_t))) {
                        rc = -ERANGE;
                        goto job_done;
                }
@@ -4272,7 +4309,7 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
                /* receive length cannot be greater than mailbox
                 * extension size
                 */
-               if (receive_length > MAILBOX_EXT_SIZE) {
+               if (receive_length > BSG_MBOX_SIZE - sizeof(MAILBOX_t)) {
                        rc = -ERANGE;
                        goto job_done;
                }
@@ -4306,7 +4343,8 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
                        bde = (struct ulp_bde64 *)&pmb->un.varWords[4];
 
                        /* bde size cannot be greater than mailbox ext size */
-                       if (bde->tus.f.bdeSize > MAILBOX_EXT_SIZE) {
+                       if (bde->tus.f.bdeSize >
+                           BSG_MBOX_SIZE - sizeof(MAILBOX_t)) {
                                rc = -ERANGE;
                                goto job_done;
                        }
@@ -4332,7 +4370,8 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
                                 * mailbox extension size
                                 */
                                if ((receive_length == 0) ||
-                                   (receive_length > MAILBOX_EXT_SIZE)) {
+                                   (receive_length >
+                                    BSG_MBOX_SIZE - sizeof(MAILBOX_t))) {
                                        rc = -ERANGE;
                                        goto job_done;
                                }
index fc20c24..a6db6ae 100644 (file)
@@ -235,9 +235,11 @@ int lpfc_sli4_redisc_fcf_table(struct lpfc_hba *);
 void lpfc_fcf_redisc_wait_start_timer(struct lpfc_hba *);
 void lpfc_sli4_fcf_dead_failthrough(struct lpfc_hba *);
 uint16_t lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *);
+void lpfc_sli4_set_fcf_flogi_fail(struct lpfc_hba *, uint16_t);
 int lpfc_sli4_fcf_rr_index_set(struct lpfc_hba *, uint16_t);
 void lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *, uint16_t);
 int lpfc_sli4_fcf_rr_next_proc(struct lpfc_vport *, uint16_t);
+void lpfc_sli4_clear_fcf_rr_bmask(struct lpfc_hba *);
 
 int lpfc_mem_alloc(struct lpfc_hba *, int align);
 void lpfc_mem_free(struct lpfc_hba *);
@@ -371,6 +373,10 @@ extern struct lpfc_hbq_init *lpfc_hbq_defs[];
 /* SLI4 if_type 2 externs. */
 int lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *);
 int lpfc_sli4_dealloc_resource_identifiers(struct lpfc_hba *);
+int lpfc_sli4_get_allocated_extnts(struct lpfc_hba *, uint16_t,
+                                  uint16_t *, uint16_t *);
+int lpfc_sli4_get_avail_extnt_rsrc(struct lpfc_hba *, uint16_t,
+                                         uint16_t *, uint16_t *);
 
 /* externs BlockGuard */
 extern char *_dump_buf_data;
@@ -432,10 +438,16 @@ void lpfc_handle_rrq_active(struct lpfc_hba *);
 int lpfc_send_rrq(struct lpfc_hba *, struct lpfc_node_rrq *);
 int lpfc_set_rrq_active(struct lpfc_hba *, struct lpfc_nodelist *,
        uint16_t, uint16_t, uint16_t);
+uint16_t lpfc_sli4_xri_inrange(struct lpfc_hba *, uint16_t);
 void lpfc_cleanup_wt_rrqs(struct lpfc_hba *);
 void lpfc_cleanup_vports_rrqs(struct lpfc_vport *, struct lpfc_nodelist *);
 struct lpfc_node_rrq *lpfc_get_active_rrq(struct lpfc_vport *, uint16_t,
        uint32_t);
+void lpfc_idiag_mbxacc_dump_bsg_mbox(struct lpfc_hba *, enum nemb_type,
+       enum mbox_type, enum dma_type, enum sta_type,
+       struct lpfc_dmabuf *, uint32_t);
+void lpfc_idiag_mbxacc_dump_issue_mbox(struct lpfc_hba *, MAILBOX_t *);
 int lpfc_wr_object(struct lpfc_hba *, struct list_head *, uint32_t, uint32_t *);
 /* functions to support SR-IOV */
 int lpfc_sli_probe_sriov_nr_virtfn(struct lpfc_hba *, int);
+uint16_t lpfc_sli_sriov_nr_virtfn_get(struct lpfc_hba *);
index 30b25c5..a0424dd 100644 (file)
@@ -48,6 +48,7 @@
 #include "lpfc_version.h"
 #include "lpfc_compat.h"
 #include "lpfc_debugfs.h"
+#include "lpfc_bsg.h"
 
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
 /*
@@ -135,7 +136,11 @@ lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size)
        int i, index, len, enable;
        uint32_t ms;
        struct lpfc_debugfs_trc *dtp;
-       char buffer[LPFC_DEBUG_TRC_ENTRY_SIZE];
+       char *buffer;
+
+       buffer = kmalloc(LPFC_DEBUG_TRC_ENTRY_SIZE, GFP_KERNEL);
+       if (!buffer)
+               return 0;
 
        enable = lpfc_debugfs_enable;
        lpfc_debugfs_enable = 0;
@@ -167,6 +172,8 @@ lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size)
        }
 
        lpfc_debugfs_enable = enable;
+       kfree(buffer);
+
        return len;
 }
 
@@ -195,8 +202,11 @@ lpfc_debugfs_slow_ring_trc_data(struct lpfc_hba *phba, char *buf, int size)
        int i, index, len, enable;
        uint32_t ms;
        struct lpfc_debugfs_trc *dtp;
-       char buffer[LPFC_DEBUG_TRC_ENTRY_SIZE];
+       char *buffer;
 
+       buffer = kmalloc(LPFC_DEBUG_TRC_ENTRY_SIZE, GFP_KERNEL);
+       if (!buffer)
+               return 0;
 
        enable = lpfc_debugfs_enable;
        lpfc_debugfs_enable = 0;
@@ -228,6 +238,8 @@ lpfc_debugfs_slow_ring_trc_data(struct lpfc_hba *phba, char *buf, int size)
        }
 
        lpfc_debugfs_enable = enable;
+       kfree(buffer);
+
        return len;
 }
 
@@ -378,7 +390,11 @@ lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba *phba, char *buf, int size)
        int len = 0;
        int i, off;
        uint32_t *ptr;
-       char buffer[1024];
+       char *buffer;
+
+       buffer = kmalloc(1024, GFP_KERNEL);
+       if (!buffer)
+               return 0;
 
        off = 0;
        spin_lock_irq(&phba->hbalock);
@@ -407,6 +423,8 @@ lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba *phba, char *buf, int size)
        }
 
        spin_unlock_irq(&phba->hbalock);
+       kfree(buffer);
+
        return len;
 }
 
@@ -1327,8 +1345,8 @@ lpfc_idiag_pcicfg_read(struct file *file, char __user *buf, size_t nbytes,
                return 0;
 
        if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_RD) {
-               where = idiag.cmd.data[0];
-               count = idiag.cmd.data[1];
+               where = idiag.cmd.data[IDIAG_PCICFG_WHERE_INDX];
+               count = idiag.cmd.data[IDIAG_PCICFG_COUNT_INDX];
        } else
                return 0;
 
@@ -1373,6 +1391,11 @@ pcicfg_browse:
                len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
                                "%08x ", u32val);
                offset += sizeof(uint32_t);
+               if (offset >= LPFC_PCI_CFG_SIZE) {
+                       len += snprintf(pbuffer+len,
+                                       LPFC_PCI_CFG_SIZE-len, "\n");
+                       break;
+               }
                index -= sizeof(uint32_t);
                if (!index)
                        len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
@@ -1385,8 +1408,11 @@ pcicfg_browse:
        }
 
        /* Set up the offset for next portion of pci cfg read */
-       idiag.offset.last_rd += LPFC_PCI_CFG_RD_SIZE;
-       if (idiag.offset.last_rd >= LPFC_PCI_CFG_SIZE)
+       if (index == 0) {
+               idiag.offset.last_rd += LPFC_PCI_CFG_RD_SIZE;
+               if (idiag.offset.last_rd >= LPFC_PCI_CFG_SIZE)
+                       idiag.offset.last_rd = 0;
+       } else
                idiag.offset.last_rd = 0;
 
        return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
@@ -1439,8 +1465,8 @@ lpfc_idiag_pcicfg_write(struct file *file, const char __user *buf,
                if (rc != LPFC_PCI_CFG_RD_CMD_ARG)
                        goto error_out;
                /* Read command from PCI config space, set up command fields */
-               where = idiag.cmd.data[0];
-               count = idiag.cmd.data[1];
+               where = idiag.cmd.data[IDIAG_PCICFG_WHERE_INDX];
+               count = idiag.cmd.data[IDIAG_PCICFG_COUNT_INDX];
                if (count == LPFC_PCI_CFG_BROWSE) {
                        if (where % sizeof(uint32_t))
                                goto error_out;
@@ -1475,9 +1501,9 @@ lpfc_idiag_pcicfg_write(struct file *file, const char __user *buf,
                if (rc != LPFC_PCI_CFG_WR_CMD_ARG)
                        goto error_out;
                /* Write command to PCI config space, read-modify-write */
-               where = idiag.cmd.data[0];
-               count = idiag.cmd.data[1];
-               value = idiag.cmd.data[2];
+               where = idiag.cmd.data[IDIAG_PCICFG_WHERE_INDX];
+               count = idiag.cmd.data[IDIAG_PCICFG_COUNT_INDX];
+               value = idiag.cmd.data[IDIAG_PCICFG_VALUE_INDX];
                /* Sanity checks */
                if ((count != sizeof(uint8_t)) &&
                    (count != sizeof(uint16_t)) &&
@@ -1569,6 +1595,292 @@ error_out:
        return -EINVAL;
 }
 
+/**
+ * lpfc_idiag_baracc_read - idiag debugfs pci bar access read
+ * @file: The file pointer to read from.
+ * @buf: The buffer to copy the data to.
+ * @nbytes: The number of bytes to read.
+ * @ppos: The position in the file to start reading from.
+ *
+ * Description:
+ * This routine reads data from the @phba pci bar memory mapped space
+ * according to the idiag command, and copies to user @buf.
+ *
+ * Returns:
+ * This function returns the amount of data that was read (this could be less
+ * than @nbytes if the end of the file was reached) or a negative error value.
+ **/
+static ssize_t
+lpfc_idiag_baracc_read(struct file *file, char __user *buf, size_t nbytes,
+                      loff_t *ppos)
+{
+       struct lpfc_debug *debug = file->private_data;
+       struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
+       int offset_label, offset, offset_run, len = 0, index;
+       int bar_num, acc_range, bar_size;
+       char *pbuffer;
+       void __iomem *mem_mapped_bar;
+       uint32_t if_type;
+       struct pci_dev *pdev;
+       uint32_t u32val;
+
+       pdev = phba->pcidev;
+       if (!pdev)
+               return 0;
+
+       /* This is a user read operation */
+       debug->op = LPFC_IDIAG_OP_RD;
+
+       if (!debug->buffer)
+               debug->buffer = kmalloc(LPFC_PCI_BAR_RD_BUF_SIZE, GFP_KERNEL);
+       if (!debug->buffer)
+               return 0;
+       pbuffer = debug->buffer;
+
+       if (*ppos)
+               return 0;
+
+       if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_RD) {
+               bar_num   = idiag.cmd.data[IDIAG_BARACC_BAR_NUM_INDX];
+               offset    = idiag.cmd.data[IDIAG_BARACC_OFF_SET_INDX];
+               acc_range = idiag.cmd.data[IDIAG_BARACC_ACC_MOD_INDX];
+               bar_size = idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX];
+       } else
+               return 0;
+
+       if (acc_range == 0)
+               return 0;
+
+       if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
+       if (if_type == LPFC_SLI_INTF_IF_TYPE_0) {
+               if (bar_num == IDIAG_BARACC_BAR_0)
+                       mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p;
+               else if (bar_num == IDIAG_BARACC_BAR_1)
+                       mem_mapped_bar = phba->sli4_hba.ctrl_regs_memmap_p;
+               else if (bar_num == IDIAG_BARACC_BAR_2)
+                       mem_mapped_bar = phba->sli4_hba.drbl_regs_memmap_p;
+               else
+                       return 0;
+       } else if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
+               if (bar_num == IDIAG_BARACC_BAR_0)
+                       mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p;
+               else
+                       return 0;
+       } else
+               return 0;
+
+       /* Read single PCI bar space register */
+       if (acc_range == SINGLE_WORD) {
+               offset_run = offset;
+               u32val = readl(mem_mapped_bar + offset_run);
+               len += snprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len,
+                               "%05x: %08x\n", offset_run, u32val);
+       } else
+               goto baracc_browse;
+
+       return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
+
+baracc_browse:
+
+       /* Browse all PCI bar space registers */
+       offset_label = idiag.offset.last_rd;
+       offset_run = offset_label;
+
+       /* Read PCI bar memory mapped space */
+       len += snprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len,
+                       "%05x: ", offset_label);
+       index = LPFC_PCI_BAR_RD_SIZE;
+       while (index > 0) {
+               u32val = readl(mem_mapped_bar + offset_run);
+               len += snprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len,
+                               "%08x ", u32val);
+               offset_run += sizeof(uint32_t);
+               if (acc_range == LPFC_PCI_BAR_BROWSE) {
+                       if (offset_run >= bar_size) {
+                               len += snprintf(pbuffer+len,
+                                       LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n");
+                               break;
+                       }
+               } else {
+                       if (offset_run >= offset +
+                           (acc_range * sizeof(uint32_t))) {
+                               len += snprintf(pbuffer+len,
+                                       LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n");
+                               break;
+                       }
+               }
+               index -= sizeof(uint32_t);
+               if (!index)
+                       len += snprintf(pbuffer+len,
+                                       LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n");
+               else if (!(index % (8 * sizeof(uint32_t)))) {
+                       offset_label += (8 * sizeof(uint32_t));
+                       len += snprintf(pbuffer+len,
+                                       LPFC_PCI_BAR_RD_BUF_SIZE-len,
+                                       "\n%05x: ", offset_label);
+               }
+       }
+
+       /* Set up the offset for next portion of pci bar read */
+       if (index == 0) {
+               idiag.offset.last_rd += LPFC_PCI_BAR_RD_SIZE;
+               if (acc_range == LPFC_PCI_BAR_BROWSE) {
+                       if (idiag.offset.last_rd >= bar_size)
+                               idiag.offset.last_rd = 0;
+               } else {
+                       if (offset_run >= offset +
+                           (acc_range * sizeof(uint32_t)))
+                               idiag.offset.last_rd = offset;
+               }
+       } else {
+               if (acc_range == LPFC_PCI_BAR_BROWSE)
+                       idiag.offset.last_rd = 0;
+               else
+                       idiag.offset.last_rd = offset;
+       }
+
+       return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
+}
+
+/**
+ * lpfc_idiag_baracc_write - Syntax check and set up idiag bar access commands
+ * @file: The file pointer to read from.
+ * @buf: The buffer to copy the user data from.
+ * @nbytes: The number of bytes to get.
+ * @ppos: The position in the file to start reading from.
+ *
+ * This routine get the debugfs idiag command struct from user space and
+ * then perform the syntax check for PCI bar memory mapped space read or
+ * write command accordingly. In the case of PCI bar memory mapped space
+ * read command, it sets up the command in the idiag command struct for
+ * the debugfs read operation. In the case of PCI bar memorpy mapped space
+ * write operation, it executes the write operation into the PCI bar memory
+ * mapped space accordingly.
+ *
+ * It returns the @nbytges passing in from debugfs user space when successful.
+ * In case of error conditions, it returns proper error code back to the user
+ * space.
+ */
+static ssize_t
+lpfc_idiag_baracc_write(struct file *file, const char __user *buf,
+                       size_t nbytes, loff_t *ppos)
+{
+       struct lpfc_debug *debug = file->private_data;
+       struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
+       uint32_t bar_num, bar_size, offset, value, acc_range;
+       struct pci_dev *pdev;
+       void __iomem *mem_mapped_bar;
+       uint32_t if_type;
+       uint32_t u32val;
+       int rc;
+
+       pdev = phba->pcidev;
+       if (!pdev)
+               return -EFAULT;
+
+       /* This is a user write operation */
+       debug->op = LPFC_IDIAG_OP_WR;
+
+       rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
+       if (rc < 0)
+               return rc;
+
+       if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
+       bar_num = idiag.cmd.data[IDIAG_BARACC_BAR_NUM_INDX];
+
+       if (if_type == LPFC_SLI_INTF_IF_TYPE_0) {
+               if ((bar_num != IDIAG_BARACC_BAR_0) &&
+                   (bar_num != IDIAG_BARACC_BAR_1) &&
+                   (bar_num != IDIAG_BARACC_BAR_2))
+                       goto error_out;
+       } else if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
+               if (bar_num != IDIAG_BARACC_BAR_0)
+                       goto error_out;
+       } else
+               goto error_out;
+
+       if (if_type == LPFC_SLI_INTF_IF_TYPE_0) {
+               if (bar_num == IDIAG_BARACC_BAR_0) {
+                       idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] =
+                               LPFC_PCI_IF0_BAR0_SIZE;
+                       mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p;
+               } else if (bar_num == IDIAG_BARACC_BAR_1) {
+                       idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] =
+                               LPFC_PCI_IF0_BAR1_SIZE;
+                       mem_mapped_bar = phba->sli4_hba.ctrl_regs_memmap_p;
+               } else if (bar_num == IDIAG_BARACC_BAR_2) {
+                       idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] =
+                               LPFC_PCI_IF0_BAR2_SIZE;
+                       mem_mapped_bar = phba->sli4_hba.drbl_regs_memmap_p;
+               } else
+                       goto error_out;
+       } else if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
+               if (bar_num == IDIAG_BARACC_BAR_0) {
+                       idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] =
+                               LPFC_PCI_IF2_BAR0_SIZE;
+                       mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p;
+               } else
+                       goto error_out;
+       } else
+               goto error_out;
+
+       offset = idiag.cmd.data[IDIAG_BARACC_OFF_SET_INDX];
+       if (offset % sizeof(uint32_t))
+               goto error_out;
+
+       bar_size = idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX];
+       if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_RD) {
+               /* Sanity check on PCI config read command line arguments */
+               if (rc != LPFC_PCI_BAR_RD_CMD_ARG)
+                       goto error_out;
+               acc_range = idiag.cmd.data[IDIAG_BARACC_ACC_MOD_INDX];
+               if (acc_range == LPFC_PCI_BAR_BROWSE) {
+                       if (offset > bar_size - sizeof(uint32_t))
+                               goto error_out;
+                       /* Starting offset to browse */
+                       idiag.offset.last_rd = offset;
+               } else if (acc_range > SINGLE_WORD) {
+                       if (offset + acc_range * sizeof(uint32_t) > bar_size)
+                               goto error_out;
+                       /* Starting offset to browse */
+                       idiag.offset.last_rd = offset;
+               } else if (acc_range != SINGLE_WORD)
+                       goto error_out;
+       } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_WR ||
+                  idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_ST ||
+                  idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_CL) {
+               /* Sanity check on PCI bar write command line arguments */
+               if (rc != LPFC_PCI_BAR_WR_CMD_ARG)
+                       goto error_out;
+               /* Write command to PCI bar space, read-modify-write */
+               acc_range = SINGLE_WORD;
+               value = idiag.cmd.data[IDIAG_BARACC_REG_VAL_INDX];
+               if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_WR) {
+                       writel(value, mem_mapped_bar + offset);
+                       readl(mem_mapped_bar + offset);
+               }
+               if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_ST) {
+                       u32val = readl(mem_mapped_bar + offset);
+                       u32val |= value;
+                       writel(u32val, mem_mapped_bar + offset);
+                       readl(mem_mapped_bar + offset);
+               }
+               if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_CL) {
+                       u32val = readl(mem_mapped_bar + offset);
+                       u32val &= ~value;
+                       writel(u32val, mem_mapped_bar + offset);
+                       readl(mem_mapped_bar + offset);
+               }
+       } else
+               /* All other opecodes are illegal for now */
+               goto error_out;
+
+       return nbytes;
+error_out:
+       memset(&idiag, 0, sizeof(idiag));
+       return -EINVAL;
+}
+
 /**
  * lpfc_idiag_queinfo_read - idiag debugfs read queue information
  * @file: The file pointer to read from.
@@ -1871,8 +2183,8 @@ lpfc_idiag_queacc_read(struct file *file, char __user *buf, size_t nbytes,
                return 0;
 
        if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) {
-               index = idiag.cmd.data[2];
-               count = idiag.cmd.data[3];
+               index = idiag.cmd.data[IDIAG_QUEACC_INDEX_INDX];
+               count = idiag.cmd.data[IDIAG_QUEACC_COUNT_INDX];
                pque = (struct lpfc_queue *)idiag.ptr_private;
        } else
                return 0;
@@ -1944,12 +2256,12 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf,
                return rc;
 
        /* Get and sanity check on command feilds */
-       quetp  = idiag.cmd.data[0];
-       queid  = idiag.cmd.data[1];
-       index  = idiag.cmd.data[2];
-       count  = idiag.cmd.data[3];
-       offset = idiag.cmd.data[4];
-       value  = idiag.cmd.data[5];
+       quetp  = idiag.cmd.data[IDIAG_QUEACC_QUETP_INDX];
+       queid  = idiag.cmd.data[IDIAG_QUEACC_QUEID_INDX];
+       index  = idiag.cmd.data[IDIAG_QUEACC_INDEX_INDX];
+       count  = idiag.cmd.data[IDIAG_QUEACC_COUNT_INDX];
+       offset = idiag.cmd.data[IDIAG_QUEACC_OFFST_INDX];
+       value  = idiag.cmd.data[IDIAG_QUEACC_VALUE_INDX];
 
        /* Sanity check on command line arguments */
        if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR ||
@@ -2218,7 +2530,7 @@ lpfc_idiag_drbacc_read(struct file *file, char __user *buf, size_t nbytes,
                return 0;
 
        if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_RD)
-               drb_reg_id = idiag.cmd.data[0];
+               drb_reg_id = idiag.cmd.data[IDIAG_DRBACC_REGID_INDX];
        else
                return 0;
 
@@ -2257,7 +2569,7 @@ lpfc_idiag_drbacc_write(struct file *file, const char __user *buf,
 {
        struct lpfc_debug *debug = file->private_data;
        struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
-       uint32_t drb_reg_id, value, reg_val;
+       uint32_t drb_reg_id, value, reg_val = 0;
        void __iomem *drb_reg;
        int rc;
 
@@ -2269,8 +2581,8 @@ lpfc_idiag_drbacc_write(struct file *file, const char __user *buf,
                return rc;
 
        /* Sanity check on command line arguments */
-       drb_reg_id = idiag.cmd.data[0];
-       value = idiag.cmd.data[1];
+       drb_reg_id = idiag.cmd.data[IDIAG_DRBACC_REGID_INDX];
+       value = idiag.cmd.data[IDIAG_DRBACC_VALUE_INDX];
 
        if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR ||
            idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST ||
@@ -2330,63 +2642,736 @@ error_out:
        return -EINVAL;
 }
 
-#undef lpfc_debugfs_op_disc_trc
-static const struct file_operations lpfc_debugfs_op_disc_trc = {
-       .owner =        THIS_MODULE,
-       .open =         lpfc_debugfs_disc_trc_open,
-       .llseek =       lpfc_debugfs_lseek,
-       .read =         lpfc_debugfs_read,
-       .release =      lpfc_debugfs_release,
-};
+/**
+ * lpfc_idiag_ctlacc_read_reg - idiag debugfs read a control registers
+ * @phba: The pointer to hba structure.
+ * @pbuffer: The pointer to the buffer to copy the data to.
+ * @len: The lenght of bytes to copied.
+ * @drbregid: The id to doorbell registers.
+ *
+ * Description:
+ * This routine reads a control register and copies its content to the
+ * user buffer pointed to by @pbuffer.
+ *
+ * Returns:
+ * This function returns the amount of data that was copied into @pbuffer.
+ **/
+static int
+lpfc_idiag_ctlacc_read_reg(struct lpfc_hba *phba, char *pbuffer,
+                          int len, uint32_t ctlregid)
+{
 
-#undef lpfc_debugfs_op_nodelist
-static const struct file_operations lpfc_debugfs_op_nodelist = {
-       .owner =        THIS_MODULE,
-       .open =         lpfc_debugfs_nodelist_open,
-       .llseek =       lpfc_debugfs_lseek,
-       .read =         lpfc_debugfs_read,
-       .release =      lpfc_debugfs_release,
-};
+       if (!pbuffer)
+               return 0;
 
-#undef lpfc_debugfs_op_hbqinfo
-static const struct file_operations lpfc_debugfs_op_hbqinfo = {
-       .owner =        THIS_MODULE,
-       .open =         lpfc_debugfs_hbqinfo_open,
-       .llseek =       lpfc_debugfs_lseek,
-       .read =         lpfc_debugfs_read,
-       .release =      lpfc_debugfs_release,
-};
+       switch (ctlregid) {
+       case LPFC_CTL_PORT_SEM:
+               len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
+                               "Port SemReg:   0x%08x\n",
+                               readl(phba->sli4_hba.conf_regs_memmap_p +
+                                     LPFC_CTL_PORT_SEM_OFFSET));
+               break;
+       case LPFC_CTL_PORT_STA:
+               len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
+                               "Port StaReg:   0x%08x\n",
+                               readl(phba->sli4_hba.conf_regs_memmap_p +
+                                     LPFC_CTL_PORT_STA_OFFSET));
+               break;
+       case LPFC_CTL_PORT_CTL:
+               len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
+                               "Port CtlReg:   0x%08x\n",
+                               readl(phba->sli4_hba.conf_regs_memmap_p +
+                                     LPFC_CTL_PORT_CTL_OFFSET));
+               break;
+       case LPFC_CTL_PORT_ER1:
+               len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
+                               "Port Er1Reg:   0x%08x\n",
+                               readl(phba->sli4_hba.conf_regs_memmap_p +
+                                     LPFC_CTL_PORT_ER1_OFFSET));
+               break;
+       case LPFC_CTL_PORT_ER2:
+               len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
+                               "Port Er2Reg:   0x%08x\n",
+                               readl(phba->sli4_hba.conf_regs_memmap_p +
+                                     LPFC_CTL_PORT_ER2_OFFSET));
+               break;
+       case LPFC_CTL_PDEV_CTL:
+               len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
+                               "PDev CtlReg:   0x%08x\n",
+                               readl(phba->sli4_hba.conf_regs_memmap_p +
+                                     LPFC_CTL_PDEV_CTL_OFFSET));
+               break;
+       default:
+               break;
+       }
+       return len;
+}
 
-#undef lpfc_debugfs_op_dumpHBASlim
-static const struct file_operations lpfc_debugfs_op_dumpHBASlim = {
-       .owner =        THIS_MODULE,
-       .open =         lpfc_debugfs_dumpHBASlim_open,
-       .llseek =       lpfc_debugfs_lseek,
-       .read =         lpfc_debugfs_read,
-       .release =      lpfc_debugfs_release,
-};
+/**
+ * lpfc_idiag_ctlacc_read - idiag debugfs read port and device control register
+ * @file: The file pointer to read from.
+ * @buf: The buffer to copy the data to.
+ * @nbytes: The number of bytes to read.
+ * @ppos: The position in the file to start reading from.
+ *
+ * Description:
+ * This routine reads data from the @phba port and device registers according
+ * to the idiag command, and copies to user @buf.
+ *
+ * Returns:
+ * This function returns the amount of data that was read (this could be less
+ * than @nbytes if the end of the file was reached) or a negative error value.
+ **/
+static ssize_t
+lpfc_idiag_ctlacc_read(struct file *file, char __user *buf, size_t nbytes,
+                      loff_t *ppos)
+{
+       struct lpfc_debug *debug = file->private_data;
+       struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
+       uint32_t ctl_reg_id, i;
+       char *pbuffer;
+       int len = 0;
 
-#undef lpfc_debugfs_op_dumpHostSlim
-static const struct file_operations lpfc_debugfs_op_dumpHostSlim = {
-       .owner =        THIS_MODULE,
-       .open =         lpfc_debugfs_dumpHostSlim_open,
-       .llseek =       lpfc_debugfs_lseek,
-       .read =         lpfc_debugfs_read,
-       .release =      lpfc_debugfs_release,
-};
+       /* This is a user read operation */
+       debug->op = LPFC_IDIAG_OP_RD;
 
-#undef lpfc_debugfs_op_dumpData
-static const struct file_operations lpfc_debugfs_op_dumpData = {
-       .owner =        THIS_MODULE,
-       .open =         lpfc_debugfs_dumpData_open,
-       .llseek =       lpfc_debugfs_lseek,
-       .read =         lpfc_debugfs_read,
-       .write =        lpfc_debugfs_dumpDataDif_write,
-       .release =      lpfc_debugfs_dumpDataDif_release,
-};
+       if (!debug->buffer)
+               debug->buffer = kmalloc(LPFC_CTL_ACC_BUF_SIZE, GFP_KERNEL);
+       if (!debug->buffer)
+               return 0;
+       pbuffer = debug->buffer;
 
-#undef lpfc_debugfs_op_dumpDif
-static const struct file_operations lpfc_debugfs_op_dumpDif = {
+       if (*ppos)
+               return 0;
+
+       if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_RD)
+               ctl_reg_id = idiag.cmd.data[IDIAG_CTLACC_REGID_INDX];
+       else
+               return 0;
+
+       if (ctl_reg_id == LPFC_CTL_ACC_ALL)
+               for (i = 1; i <= LPFC_CTL_MAX; i++)
+                       len = lpfc_idiag_ctlacc_read_reg(phba,
+                                                        pbuffer, len, i);
+       else
+               len = lpfc_idiag_ctlacc_read_reg(phba,
+                                                pbuffer, len, ctl_reg_id);
+
+       return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
+}
+
+/**
+ * lpfc_idiag_ctlacc_write - Syntax check and set up idiag ctlacc commands
+ * @file: The file pointer to read from.
+ * @buf: The buffer to copy the user data from.
+ * @nbytes: The number of bytes to get.
+ * @ppos: The position in the file to start reading from.
+ *
+ * This routine get the debugfs idiag command struct from user space and then
+ * perform the syntax check for port and device control register read (dump)
+ * or write (set) command accordingly.
+ *
+ * It returns the @nbytges passing in from debugfs user space when successful.
+ * In case of error conditions, it returns proper error code back to the user
+ * space.
+ **/
+static ssize_t
+lpfc_idiag_ctlacc_write(struct file *file, const char __user *buf,
+                       size_t nbytes, loff_t *ppos)
+{
+       struct lpfc_debug *debug = file->private_data;
+       struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
+       uint32_t ctl_reg_id, value, reg_val = 0;
+       void __iomem *ctl_reg;
+       int rc;
+
+       /* This is a user write operation */
+       debug->op = LPFC_IDIAG_OP_WR;
+
+       rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
+       if (rc < 0)
+               return rc;
+
+       /* Sanity check on command line arguments */
+       ctl_reg_id = idiag.cmd.data[IDIAG_CTLACC_REGID_INDX];
+       value = idiag.cmd.data[IDIAG_CTLACC_VALUE_INDX];
+
+       if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_WR ||
+           idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_ST ||
+           idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_CL) {
+               if (rc != LPFC_CTL_ACC_WR_CMD_ARG)
+                       goto error_out;
+               if (ctl_reg_id > LPFC_CTL_MAX)
+                       goto error_out;
+       } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_RD) {
+               if (rc != LPFC_CTL_ACC_RD_CMD_ARG)
+                       goto error_out;
+               if ((ctl_reg_id > LPFC_CTL_MAX) &&
+                   (ctl_reg_id != LPFC_CTL_ACC_ALL))
+                       goto error_out;
+       } else
+               goto error_out;
+
+       /* Perform the write access operation */
+       if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_WR ||
+           idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_ST ||
+           idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_CL) {
+               switch (ctl_reg_id) {
+               case LPFC_CTL_PORT_SEM:
+                       ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
+                                       LPFC_CTL_PORT_SEM_OFFSET;
+                       break;
+               case LPFC_CTL_PORT_STA:
+                       ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
+                                       LPFC_CTL_PORT_STA_OFFSET;
+                       break;
+               case LPFC_CTL_PORT_CTL:
+                       ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
+                                       LPFC_CTL_PORT_CTL_OFFSET;
+                       break;
+               case LPFC_CTL_PORT_ER1:
+                       ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
+                                       LPFC_CTL_PORT_ER1_OFFSET;
+                       break;
+               case LPFC_CTL_PORT_ER2:
+                       ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
+                                       LPFC_CTL_PORT_ER2_OFFSET;
+                       break;
+               case LPFC_CTL_PDEV_CTL:
+                       ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
+                                       LPFC_CTL_PDEV_CTL_OFFSET;
+                       break;
+               default:
+                       goto error_out;
+               }
+
+               if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_WR)
+                       reg_val = value;
+               if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_ST) {
+                       reg_val = readl(ctl_reg);
+                       reg_val |= value;
+               }
+               if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_CL) {
+                       reg_val = readl(ctl_reg);
+                       reg_val &= ~value;
+               }
+               writel(reg_val, ctl_reg);
+               readl(ctl_reg); /* flush */
+       }
+       return nbytes;
+
+error_out:
+       /* Clean out command structure on command error out */
+       memset(&idiag, 0, sizeof(idiag));
+       return -EINVAL;
+}
+
+/**
+ * lpfc_idiag_mbxacc_get_setup - idiag debugfs get mailbox access setup
+ * @phba: Pointer to HBA context object.
+ * @pbuffer: Pointer to data buffer.
+ *
+ * Description:
+ * This routine gets the driver mailbox access debugfs setup information.
+ *
+ * Returns:
+ * This function returns the amount of data that was read (this could be less
+ * than @nbytes if the end of the file was reached) or a negative error value.
+ **/
+static int
+lpfc_idiag_mbxacc_get_setup(struct lpfc_hba *phba, char *pbuffer)
+{
+       uint32_t mbx_dump_map, mbx_dump_cnt, mbx_word_cnt, mbx_mbox_cmd;
+       int len = 0;
+
+       mbx_mbox_cmd = idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX];
+       mbx_dump_map = idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX];
+       mbx_dump_cnt = idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX];
+       mbx_word_cnt = idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX];
+
+       len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
+                       "mbx_dump_map: 0x%08x\n", mbx_dump_map);
+       len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
+                       "mbx_dump_cnt: %04d\n", mbx_dump_cnt);
+       len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
+                       "mbx_word_cnt: %04d\n", mbx_word_cnt);
+       len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
+                       "mbx_mbox_cmd: 0x%02x\n", mbx_mbox_cmd);
+
+       return len;
+}
+
+/**
+ * lpfc_idiag_mbxacc_read - idiag debugfs read on mailbox access
+ * @file: The file pointer to read from.
+ * @buf: The buffer to copy the data to.
+ * @nbytes: The number of bytes to read.
+ * @ppos: The position in the file to start reading from.
+ *
+ * Description:
+ * This routine reads data from the @phba driver mailbox access debugfs setup
+ * information.
+ *
+ * Returns:
+ * This function returns the amount of data that was read (this could be less
+ * than @nbytes if the end of the file was reached) or a negative error value.
+ **/
+static ssize_t
+lpfc_idiag_mbxacc_read(struct file *file, char __user *buf, size_t nbytes,
+                      loff_t *ppos)
+{
+       struct lpfc_debug *debug = file->private_data;
+       struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
+       char *pbuffer;
+       int len = 0;
+
+       /* This is a user read operation */
+       debug->op = LPFC_IDIAG_OP_RD;
+
+       if (!debug->buffer)
+               debug->buffer = kmalloc(LPFC_MBX_ACC_BUF_SIZE, GFP_KERNEL);
+       if (!debug->buffer)
+               return 0;
+       pbuffer = debug->buffer;
+
+       if (*ppos)
+               return 0;
+
+       if ((idiag.cmd.opcode != LPFC_IDIAG_CMD_MBXACC_DP) &&
+           (idiag.cmd.opcode != LPFC_IDIAG_BSG_MBXACC_DP))
+               return 0;
+
+       len = lpfc_idiag_mbxacc_get_setup(phba, pbuffer);
+
+       return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
+}
+
+/**
+ * lpfc_idiag_mbxacc_write - Syntax check and set up idiag mbxacc commands
+ * @file: The file pointer to read from.
+ * @buf: The buffer to copy the user data from.
+ * @nbytes: The number of bytes to get.
+ * @ppos: The position in the file to start reading from.
+ *
+ * This routine get the debugfs idiag command struct from user space and then
+ * perform the syntax check for driver mailbox command (dump) and sets up the
+ * necessary states in the idiag command struct accordingly.
+ *
+ * It returns the @nbytges passing in from debugfs user space when successful.
+ * In case of error conditions, it returns proper error code back to the user
+ * space.
+ **/
+static ssize_t
+lpfc_idiag_mbxacc_write(struct file *file, const char __user *buf,
+                       size_t nbytes, loff_t *ppos)
+{
+       struct lpfc_debug *debug = file->private_data;
+       uint32_t mbx_dump_map, mbx_dump_cnt, mbx_word_cnt, mbx_mbox_cmd;
+       int rc;
+
+       /* This is a user write operation */
+       debug->op = LPFC_IDIAG_OP_WR;
+
+       rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
+       if (rc < 0)
+               return rc;
+
+       /* Sanity check on command line arguments */
+       mbx_mbox_cmd = idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX];
+       mbx_dump_map = idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX];
+       mbx_dump_cnt = idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX];
+       mbx_word_cnt = idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX];
+
+       if (idiag.cmd.opcode == LPFC_IDIAG_CMD_MBXACC_DP) {
+               if (!(mbx_dump_map & LPFC_MBX_DMP_MBX_ALL))
+                       goto error_out;
+               if ((mbx_dump_map & ~LPFC_MBX_DMP_MBX_ALL) &&
+                   (mbx_dump_map != LPFC_MBX_DMP_ALL))
+                       goto error_out;
+               if (mbx_word_cnt > sizeof(MAILBOX_t))
+                       goto error_out;
+       } else if (idiag.cmd.opcode == LPFC_IDIAG_BSG_MBXACC_DP) {
+               if (!(mbx_dump_map & LPFC_BSG_DMP_MBX_ALL))
+                       goto error_out;
+               if ((mbx_dump_map & ~LPFC_BSG_DMP_MBX_ALL) &&
+                   (mbx_dump_map != LPFC_MBX_DMP_ALL))
+                       goto error_out;
+               if (mbx_word_cnt > (BSG_MBOX_SIZE)/4)
+                       goto error_out;
+               if (mbx_mbox_cmd != 0x9b)
+                       goto error_out;
+       } else
+               goto error_out;
+
+       if (mbx_word_cnt == 0)
+               goto error_out;
+       if (rc != LPFC_MBX_DMP_ARG)
+               goto error_out;
+       if (mbx_mbox_cmd & ~0xff)
+               goto error_out;
+
+       /* condition for stop mailbox dump */
+       if (mbx_dump_cnt == 0)
+               goto reset_out;
+
+       return nbytes;
+
+reset_out:
+       /* Clean out command structure on command error out */
+       memset(&idiag, 0, sizeof(idiag));
+       return nbytes;
+
+error_out:
+       /* Clean out command structure on command error out */
+       memset(&idiag, 0, sizeof(idiag));
+       return -EINVAL;
+}
+
+/**
+ * lpfc_idiag_extacc_avail_get - get the available extents information
+ * @phba: pointer to lpfc hba data structure.
+ * @pbuffer: pointer to internal buffer.
+ * @len: length into the internal buffer data has been copied.
+ *
+ * Description:
+ * This routine is to get the available extent information.
+ *
+ * Returns:
+ * overall lenth of the data read into the internal buffer.
+ **/
+static int
+lpfc_idiag_extacc_avail_get(struct lpfc_hba *phba, char *pbuffer, int len)
+{
+       uint16_t ext_cnt, ext_size;
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\nAvailable Extents Information:\n");
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\tPort Available VPI extents: ");
+       lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_VPI,
+                                      &ext_cnt, &ext_size);
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "Count %3d, Size %3d\n", ext_cnt, ext_size);
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\tPort Available VFI extents: ");
+       lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_VFI,
+                                      &ext_cnt, &ext_size);
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "Count %3d, Size %3d\n", ext_cnt, ext_size);
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\tPort Available RPI extents: ");
+       lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_RPI,
+                                      &ext_cnt, &ext_size);
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "Count %3d, Size %3d\n", ext_cnt, ext_size);
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\tPort Available XRI extents: ");
+       lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_XRI,
+                                      &ext_cnt, &ext_size);
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "Count %3d, Size %3d\n", ext_cnt, ext_size);
+
+       return len;
+}
+
+/**
+ * lpfc_idiag_extacc_alloc_get - get the allocated extents information
+ * @phba: pointer to lpfc hba data structure.
+ * @pbuffer: pointer to internal buffer.
+ * @len: length into the internal buffer data has been copied.
+ *
+ * Description:
+ * This routine is to get the allocated extent information.
+ *
+ * Returns:
+ * overall lenth of the data read into the internal buffer.
+ **/
+static int
+lpfc_idiag_extacc_alloc_get(struct lpfc_hba *phba, char *pbuffer, int len)
+{
+       uint16_t ext_cnt, ext_size;
+       int rc;
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\nAllocated Extents Information:\n");
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\tHost Allocated VPI extents: ");
+       rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_VPI,
+                                           &ext_cnt, &ext_size);
+       if (!rc)
+               len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                               "Port %d Extent %3d, Size %3d\n",
+                               phba->brd_no, ext_cnt, ext_size);
+       else
+               len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                               "N/A\n");
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\tHost Allocated VFI extents: ");
+       rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_VFI,
+                                           &ext_cnt, &ext_size);
+       if (!rc)
+               len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                               "Port %d Extent %3d, Size %3d\n",
+                               phba->brd_no, ext_cnt, ext_size);
+       else
+               len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                               "N/A\n");
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\tHost Allocated RPI extents: ");
+       rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_RPI,
+                                           &ext_cnt, &ext_size);
+       if (!rc)
+               len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                               "Port %d Extent %3d, Size %3d\n",
+                               phba->brd_no, ext_cnt, ext_size);
+       else
+               len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                               "N/A\n");
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\tHost Allocated XRI extents: ");
+       rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_XRI,
+                                           &ext_cnt, &ext_size);
+       if (!rc)
+               len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                               "Port %d Extent %3d, Size %3d\n",
+                               phba->brd_no, ext_cnt, ext_size);
+       else
+               len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                               "N/A\n");
+
+       return len;
+}
+
+/**
+ * lpfc_idiag_extacc_drivr_get - get driver extent information
+ * @phba: pointer to lpfc hba data structure.
+ * @pbuffer: pointer to internal buffer.
+ * @len: length into the internal buffer data has been copied.
+ *
+ * Description:
+ * This routine is to get the driver extent information.
+ *
+ * Returns:
+ * overall lenth of the data read into the internal buffer.
+ **/
+static int
+lpfc_idiag_extacc_drivr_get(struct lpfc_hba *phba, char *pbuffer, int len)
+{
+       struct lpfc_rsrc_blks *rsrc_blks;
+       int index;
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\nDriver Extents Information:\n");
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\tVPI extents:\n");
+       index = 0;
+       list_for_each_entry(rsrc_blks, &phba->lpfc_vpi_blk_list, list) {
+               len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                               "\t\tBlock %3d: Start %4d, Count %4d\n",
+                               index, rsrc_blks->rsrc_start,
+                               rsrc_blks->rsrc_size);
+               index++;
+       }
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\tVFI extents:\n");
+       index = 0;
+       list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_vfi_blk_list,
+                           list) {
+               len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                               "\t\tBlock %3d: Start %4d, Count %4d\n",
+                               index, rsrc_blks->rsrc_start,
+                               rsrc_blks->rsrc_size);
+               index++;
+       }
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\tRPI extents:\n");
+       index = 0;
+       list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_rpi_blk_list,
+                           list) {
+               len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                               "\t\tBlock %3d: Start %4d, Count %4d\n",
+                               index, rsrc_blks->rsrc_start,
+                               rsrc_blks->rsrc_size);
+               index++;
+       }
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\tXRI extents:\n");
+       index = 0;
+       list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_xri_blk_list,
+                           list) {
+               len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                               "\t\tBlock %3d: Start %4d, Count %4d\n",
+                               index, rsrc_blks->rsrc_start,
+                               rsrc_blks->rsrc_size);
+               index++;
+       }
+
+       return len;
+}
+
+/**
+ * lpfc_idiag_extacc_write - Syntax check and set up idiag extacc commands
+ * @file: The file pointer to read from.
+ * @buf: The buffer to copy the user data from.
+ * @nbytes: The number of bytes to get.
+ * @ppos: The position in the file to start reading from.
+ *
+ * This routine get the debugfs idiag command struct from user space and then
+ * perform the syntax check for extent information access commands and sets
+ * up the necessary states in the idiag command struct accordingly.
+ *
+ * It returns the @nbytges passing in from debugfs user space when successful.
+ * In case of error conditions, it returns proper error code back to the user
+ * space.
+ **/
+static ssize_t
+lpfc_idiag_extacc_write(struct file *file, const char __user *buf,
+                       size_t nbytes, loff_t *ppos)
+{
+       struct lpfc_debug *debug = file->private_data;
+       uint32_t ext_map;
+       int rc;
+
+       /* This is a user write operation */
+       debug->op = LPFC_IDIAG_OP_WR;
+
+       rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
+       if (rc < 0)
+               return rc;
+
+       ext_map = idiag.cmd.data[IDIAG_EXTACC_EXMAP_INDX];
+
+       if (idiag.cmd.opcode != LPFC_IDIAG_CMD_EXTACC_RD)
+               goto error_out;
+       if (rc != LPFC_EXT_ACC_CMD_ARG)
+               goto error_out;
+       if (!(ext_map & LPFC_EXT_ACC_ALL))
+               goto error_out;
+
+       return nbytes;
+error_out:
+       /* Clean out command structure on command error out */
+       memset(&idiag, 0, sizeof(idiag));
+       return -EINVAL;
+}
+
+/**
+ * lpfc_idiag_extacc_read - idiag debugfs read access to extent information
+ * @file: The file pointer to read from.
+ * @buf: The buffer to copy the data to.
+ * @nbytes: The number of bytes to read.
+ * @ppos: The position in the file to start reading from.
+ *
+ * Description:
+ * This routine reads data from the proper extent information according to
+ * the idiag command, and copies to user @buf.
+ *
+ * Returns:
+ * This function returns the amount of data that was read (this could be less
+ * than @nbytes if the end of the file was reached) or a negative error value.
+ **/
+static ssize_t
+lpfc_idiag_extacc_read(struct file *file, char __user *buf, size_t nbytes,
+                      loff_t *ppos)
+{
+       struct lpfc_debug *debug = file->private_data;
+       struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
+       char *pbuffer;
+       uint32_t ext_map;
+       int len = 0;
+
+       /* This is a user read operation */
+       debug->op = LPFC_IDIAG_OP_RD;
+
+       if (!debug->buffer)
+               debug->buffer = kmalloc(LPFC_EXT_ACC_BUF_SIZE, GFP_KERNEL);
+       if (!debug->buffer)
+               return 0;
+       pbuffer = debug->buffer;
+       if (*ppos)
+               return 0;
+       if (idiag.cmd.opcode != LPFC_IDIAG_CMD_EXTACC_RD)
+               return 0;
+
+       ext_map = idiag.cmd.data[IDIAG_EXTACC_EXMAP_INDX];
+       if (ext_map & LPFC_EXT_ACC_AVAIL)
+               len = lpfc_idiag_extacc_avail_get(phba, pbuffer, len);
+       if (ext_map & LPFC_EXT_ACC_ALLOC)
+               len = lpfc_idiag_extacc_alloc_get(phba, pbuffer, len);
+       if (ext_map & LPFC_EXT_ACC_DRIVR)
+               len = lpfc_idiag_extacc_drivr_get(phba, pbuffer, len);
+
+       return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
+}
+
+#undef lpfc_debugfs_op_disc_trc
+static const struct file_operations lpfc_debugfs_op_disc_trc = {
+       .owner =        THIS_MODULE,
+       .open =         lpfc_debugfs_disc_trc_open,
+       .llseek =       lpfc_debugfs_lseek,
+       .read =         lpfc_debugfs_read,
+       .release =      lpfc_debugfs_release,
+};
+
+#undef lpfc_debugfs_op_nodelist
+static const struct file_operations lpfc_debugfs_op_nodelist = {
+       .owner =        THIS_MODULE,
+       .open =         lpfc_debugfs_nodelist_open,
+       .llseek =       lpfc_debugfs_lseek,
+       .read =         lpfc_debugfs_read,
+       .release =      lpfc_debugfs_release,
+};
+
+#undef lpfc_debugfs_op_hbqinfo
+static const struct file_operations lpfc_debugfs_op_hbqinfo = {
+       .owner =        THIS_MODULE,
+       .open =         lpfc_debugfs_hbqinfo_open,
+       .llseek =       lpfc_debugfs_lseek,
+       .read =         lpfc_debugfs_read,
+       .release =      lpfc_debugfs_release,
+};
+
+#undef lpfc_debugfs_op_dumpHBASlim
+static const struct file_operations lpfc_debugfs_op_dumpHBASlim = {
+       .owner =        THIS_MODULE,
+       .open =         lpfc_debugfs_dumpHBASlim_open,
+       .llseek =       lpfc_debugfs_lseek,
+       .read =         lpfc_debugfs_read,
+       .release =      lpfc_debugfs_release,
+};
+
+#undef lpfc_debugfs_op_dumpHostSlim
+static const struct file_operations lpfc_debugfs_op_dumpHostSlim = {
+       .owner =        THIS_MODULE,
+       .open =         lpfc_debugfs_dumpHostSlim_open,
+       .llseek =       lpfc_debugfs_lseek,
+       .read =         lpfc_debugfs_read,
+       .release =      lpfc_debugfs_release,
+};
+
+#undef lpfc_debugfs_op_dumpData
+static const struct file_operations lpfc_debugfs_op_dumpData = {
+       .owner =        THIS_MODULE,
+       .open =         lpfc_debugfs_dumpData_open,
+       .llseek =       lpfc_debugfs_lseek,
+       .read =         lpfc_debugfs_read,
+       .write =        lpfc_debugfs_dumpDataDif_write,
+       .release =      lpfc_debugfs_dumpDataDif_release,
+};
+
+#undef lpfc_debugfs_op_dumpDif
+static const struct file_operations lpfc_debugfs_op_dumpDif = {
        .owner =        THIS_MODULE,
        .open =         lpfc_debugfs_dumpDif_open,
        .llseek =       lpfc_debugfs_lseek,
@@ -2420,6 +3405,16 @@ static const struct file_operations lpfc_idiag_op_pciCfg = {
        .release =      lpfc_idiag_cmd_release,
 };
 
+#undef lpfc_idiag_op_barAcc
+static const struct file_operations lpfc_idiag_op_barAcc = {
+       .owner =        THIS_MODULE,
+       .open =         lpfc_idiag_open,
+       .llseek =       lpfc_debugfs_lseek,
+       .read =         lpfc_idiag_baracc_read,
+       .write =        lpfc_idiag_baracc_write,
+       .release =      lpfc_idiag_cmd_release,
+};
+
 #undef lpfc_idiag_op_queInfo
 static const struct file_operations lpfc_idiag_op_queInfo = {
        .owner =        THIS_MODULE,
@@ -2428,7 +3423,7 @@ static const struct file_operations lpfc_idiag_op_queInfo = {
        .release =      lpfc_idiag_release,
 };
 
-#undef lpfc_idiag_op_queacc
+#undef lpfc_idiag_op_queAcc
 static const struct file_operations lpfc_idiag_op_queAcc = {
        .owner =        THIS_MODULE,
        .open =         lpfc_idiag_open,
@@ -2438,7 +3433,7 @@ static const struct file_operations lpfc_idiag_op_queAcc = {
        .release =      lpfc_idiag_cmd_release,
 };
 
-#undef lpfc_idiag_op_drbacc
+#undef lpfc_idiag_op_drbAcc
 static const struct file_operations lpfc_idiag_op_drbAcc = {
        .owner =        THIS_MODULE,
        .open =         lpfc_idiag_open,
@@ -2448,8 +3443,234 @@ static const struct file_operations lpfc_idiag_op_drbAcc = {
        .release =      lpfc_idiag_cmd_release,
 };
 
+#undef lpfc_idiag_op_ctlAcc
+static const struct file_operations lpfc_idiag_op_ctlAcc = {
+       .owner =        THIS_MODULE,
+       .open =         lpfc_idiag_open,
+       .llseek =       lpfc_debugfs_lseek,
+       .read =         lpfc_idiag_ctlacc_read,
+       .write =        lpfc_idiag_ctlacc_write,
+       .release =      lpfc_idiag_cmd_release,
+};
+
+#undef lpfc_idiag_op_mbxAcc
+static const struct file_operations lpfc_idiag_op_mbxAcc = {
+       .owner =        THIS_MODULE,
+       .open =         lpfc_idiag_open,
+       .llseek =       lpfc_debugfs_lseek,
+       .read =         lpfc_idiag_mbxacc_read,
+       .write =        lpfc_idiag_mbxacc_write,
+       .release =      lpfc_idiag_cmd_release,
+};
+
+#undef lpfc_idiag_op_extAcc
+static const struct file_operations lpfc_idiag_op_extAcc = {
+       .owner =        THIS_MODULE,
+       .open =         lpfc_idiag_open,
+       .llseek =       lpfc_debugfs_lseek,
+       .read =         lpfc_idiag_extacc_read,
+       .write =        lpfc_idiag_extacc_write,
+       .release =      lpfc_idiag_cmd_release,
+};
+
 #endif
 
+/* lpfc_idiag_mbxacc_dump_bsg_mbox - idiag debugfs dump bsg mailbox command
+ * @phba: Pointer to HBA context object.
+ * @dmabuf: Pointer to a DMA buffer descriptor.
+ *
+ * Description:
+ * This routine dump a bsg pass-through non-embedded mailbox command with
+ * external buffer.
+ **/
+void
+lpfc_idiag_mbxacc_dump_bsg_mbox(struct lpfc_hba *phba, enum nemb_type nemb_tp,
+                               enum mbox_type mbox_tp, enum dma_type dma_tp,
+                               enum sta_type sta_tp,
+                               struct lpfc_dmabuf *dmabuf, uint32_t ext_buf)
+{
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+       uint32_t *mbx_mbox_cmd, *mbx_dump_map, *mbx_dump_cnt, *mbx_word_cnt;
+       char line_buf[LPFC_MBX_ACC_LBUF_SZ];
+       int len = 0;
+       uint32_t do_dump = 0;
+       uint32_t *pword;
+       uint32_t i;
+
+       if (idiag.cmd.opcode != LPFC_IDIAG_BSG_MBXACC_DP)
+               return;
+
+       mbx_mbox_cmd = &idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX];
+       mbx_dump_map = &idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX];
+       mbx_dump_cnt = &idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX];
+       mbx_word_cnt = &idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX];
+
+       if (!(*mbx_dump_map & LPFC_MBX_DMP_ALL) ||
+           (*mbx_dump_cnt == 0) ||
+           (*mbx_word_cnt == 0))
+               return;
+
+       if (*mbx_mbox_cmd != 0x9B)
+               return;
+
+       if ((mbox_tp == mbox_rd) && (dma_tp == dma_mbox)) {
+               if (*mbx_dump_map & LPFC_BSG_DMP_MBX_RD_MBX) {
+                       do_dump |= LPFC_BSG_DMP_MBX_RD_MBX;
+                       printk(KERN_ERR "\nRead mbox command (x%x), "
+                              "nemb:0x%x, extbuf_cnt:%d:\n",
+                              sta_tp, nemb_tp, ext_buf);
+               }
+       }
+       if ((mbox_tp == mbox_rd) && (dma_tp == dma_ebuf)) {
+               if (*mbx_dump_map & LPFC_BSG_DMP_MBX_RD_BUF) {
+                       do_dump |= LPFC_BSG_DMP_MBX_RD_BUF;
+                       printk(KERN_ERR "\nRead mbox buffer (x%x), "
+                              "nemb:0x%x, extbuf_seq:%d:\n",
+                              sta_tp, nemb_tp, ext_buf);
+               }
+       }
+       if ((mbox_tp == mbox_wr) && (dma_tp == dma_mbox)) {
+               if (*mbx_dump_map & LPFC_BSG_DMP_MBX_WR_MBX) {
+                       do_dump |= LPFC_BSG_DMP_MBX_WR_MBX;
+                       printk(KERN_ERR "\nWrite mbox command (x%x), "
+                              "nemb:0x%x, extbuf_cnt:%d:\n",
+                              sta_tp, nemb_tp, ext_buf);
+               }
+       }
+       if ((mbox_tp == mbox_wr) && (dma_tp == dma_ebuf)) {
+               if (*mbx_dump_map & LPFC_BSG_DMP_MBX_WR_BUF) {
+                       do_dump |= LPFC_BSG_DMP_MBX_WR_BUF;
+                       printk(KERN_ERR "\nWrite mbox buffer (x%x), "
+                              "nemb:0x%x, extbuf_seq:%d:\n",
+                              sta_tp, nemb_tp, ext_buf);
+               }
+       }
+
+       /* dump buffer content */
+       if (do_dump) {
+               pword = (uint32_t *)dmabuf->virt;
+               for (i = 0; i < *mbx_word_cnt; i++) {
+                       if (!(i % 8)) {
+                               if (i != 0)
+                                       printk(KERN_ERR "%s\n", line_buf);
+                               len = 0;
+                               len += snprintf(line_buf+len,
+                                               LPFC_MBX_ACC_LBUF_SZ-len,
+                                               "%03d: ", i);
+                       }
+                       len += snprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len,
+                                       "%08x ", (uint32_t)*pword);
+                       pword++;
+               }
+               if ((i - 1) % 8)
+                       printk(KERN_ERR "%s\n", line_buf);
+               (*mbx_dump_cnt)--;
+       }
+
+       /* Clean out command structure on reaching dump count */
+       if (*mbx_dump_cnt == 0)
+               memset(&idiag, 0, sizeof(idiag));
+       return;
+#endif
+}
+
+/* lpfc_idiag_mbxacc_dump_issue_mbox - idiag debugfs dump issue mailbox command
+ * @phba: Pointer to HBA context object.
+ * @dmabuf: Pointer to a DMA buffer descriptor.
+ *
+ * Description:
+ * This routine dump a pass-through non-embedded mailbox command from issue
+ * mailbox command.
+ **/
+void
+lpfc_idiag_mbxacc_dump_issue_mbox(struct lpfc_hba *phba, MAILBOX_t *pmbox)
+{
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+       uint32_t *mbx_dump_map, *mbx_dump_cnt, *mbx_word_cnt, *mbx_mbox_cmd;
+       char line_buf[LPFC_MBX_ACC_LBUF_SZ];
+       int len = 0;
+       uint32_t *pword;
+       uint8_t *pbyte;
+       uint32_t i, j;
+
+       if (idiag.cmd.opcode != LPFC_IDIAG_CMD_MBXACC_DP)
+               return;
+
+       mbx_mbox_cmd = &idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX];
+       mbx_dump_map = &idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX];
+       mbx_dump_cnt = &idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX];
+       mbx_word_cnt = &idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX];
+
+       if (!(*mbx_dump_map & LPFC_MBX_DMP_MBX_ALL) ||
+           (*mbx_dump_cnt == 0) ||
+           (*mbx_word_cnt == 0))
+               return;
+
+       if ((*mbx_mbox_cmd != LPFC_MBX_ALL_CMD) &&
+           (*mbx_mbox_cmd != pmbox->mbxCommand))
+               return;
+
+       /* dump buffer content */
+       if (*mbx_dump_map & LPFC_MBX_DMP_MBX_WORD) {
+               printk(KERN_ERR "Mailbox command:0x%x dump by word:\n",
+                      pmbox->mbxCommand);
+               pword = (uint32_t *)pmbox;
+               for (i = 0; i < *mbx_word_cnt; i++) {
+                       if (!(i % 8)) {
+                               if (i != 0)
+                                       printk(KERN_ERR "%s\n", line_buf);
+                               len = 0;
+                               memset(line_buf, 0, LPFC_MBX_ACC_LBUF_SZ);
+                               len += snprintf(line_buf+len,
+                                               LPFC_MBX_ACC_LBUF_SZ-len,
+                                               "%03d: ", i);
+                       }
+                       len += snprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len,
+                                       "%08x ",
+                                       ((uint32_t)*pword) & 0xffffffff);
+                       pword++;
+               }
+               if ((i - 1) % 8)
+                       printk(KERN_ERR "%s\n", line_buf);
+               printk(KERN_ERR "\n");
+       }
+       if (*mbx_dump_map & LPFC_MBX_DMP_MBX_BYTE) {
+               printk(KERN_ERR "Mailbox command:0x%x dump by byte:\n",
+                      pmbox->mbxCommand);
+               pbyte = (uint8_t *)pmbox;
+               for (i = 0; i < *mbx_word_cnt; i++) {
+                       if (!(i % 8)) {
+                               if (i != 0)
+                                       printk(KERN_ERR "%s\n", line_buf);
+                               len = 0;
+                               memset(line_buf, 0, LPFC_MBX_ACC_LBUF_SZ);
+                               len += snprintf(line_buf+len,
+                                               LPFC_MBX_ACC_LBUF_SZ-len,
+                                               "%03d: ", i);
+                       }
+                       for (j = 0; j < 4; j++) {
+                               len += snprintf(line_buf+len,
+                                               LPFC_MBX_ACC_LBUF_SZ-len,
+                                               "%02x",
+                                               ((uint8_t)*pbyte) & 0xff);
+                               pbyte++;
+                       }
+                       len += snprintf(line_buf+len,
+                                       LPFC_MBX_ACC_LBUF_SZ-len, " ");
+               }
+               if ((i - 1) % 8)
+                       printk(KERN_ERR "%s\n", line_buf);
+               printk(KERN_ERR "\n");
+       }
+       (*mbx_dump_cnt)--;
+
+       /* Clean out command structure on reaching dump count */
+       if (*mbx_dump_cnt == 0)
+               memset(&idiag, 0, sizeof(idiag));
+       return;
+#endif
+}
+
 /**
  * lpfc_debugfs_initialize - Initialize debugfs for a vport
  * @vport: The vport pointer to initialize.
@@ -2673,7 +3894,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
                                 vport, &lpfc_debugfs_op_nodelist);
        if (!vport->debug_nodelist) {
                lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
-                                "0409 Can't create debugfs nodelist\n");
+                                "2985 Can't create debugfs nodelist\n");
                goto debug_failed;
        }
 
@@ -2710,6 +3931,20 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
                idiag.offset.last_rd = 0;
        }
 
+       /* iDiag PCI BAR access */
+       snprintf(name, sizeof(name), "barAcc");
+       if (!phba->idiag_bar_acc) {
+               phba->idiag_bar_acc =
+                       debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
+                               phba->idiag_root, phba, &lpfc_idiag_op_barAcc);
+               if (!phba->idiag_bar_acc) {
+                       lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+                                       "3056 Can't create idiag debugfs\n");
+                       goto debug_failed;
+               }
+               idiag.offset.last_rd = 0;
+       }
+
        /* iDiag get PCI function queue information */
        snprintf(name, sizeof(name), "queInfo");
        if (!phba->idiag_que_info) {
@@ -2749,6 +3984,50 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
                }
        }
 
+       /* iDiag access PCI function control registers */
+       snprintf(name, sizeof(name), "ctlAcc");
+       if (!phba->idiag_ctl_acc) {
+               phba->idiag_ctl_acc =
+                       debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
+                               phba->idiag_root, phba, &lpfc_idiag_op_ctlAcc);
+               if (!phba->idiag_ctl_acc) {
+                       lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+                                        "2981 Can't create idiag debugfs\n");
+                       goto debug_failed;
+               }
+       }
+
+       /* iDiag access mbox commands */
+       snprintf(name, sizeof(name), "mbxAcc");
+       if (!phba->idiag_mbx_acc) {
+               phba->idiag_mbx_acc =
+                       debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
+                               phba->idiag_root, phba, &lpfc_idiag_op_mbxAcc);
+               if (!phba->idiag_mbx_acc) {
+                       lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+                                       "2980 Can't create idiag debugfs\n");
+                       goto debug_failed;
+               }
+       }
+
+       /* iDiag extents access commands */
+       if (phba->sli4_hba.extents_in_use) {
+               snprintf(name, sizeof(name), "extAcc");
+               if (!phba->idiag_ext_acc) {
+                       phba->idiag_ext_acc =
+                               debugfs_create_file(name,
+                                                   S_IFREG|S_IRUGO|S_IWUSR,
+                                                   phba->idiag_root, phba,
+                                                   &lpfc_idiag_op_extAcc);
+                       if (!phba->idiag_ext_acc) {
+                               lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+                                               "2986 Cant create "
+                                               "idiag debugfs\n");
+                               goto debug_failed;
+                       }
+               }
+       }
+
 debug_failed:
        return;
 #endif
@@ -2783,7 +4062,6 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport)
                debugfs_remove(vport->debug_nodelist); /* nodelist */
                vport->debug_nodelist = NULL;
        }
-
        if (vport->vport_debugfs_root) {
                debugfs_remove(vport->vport_debugfs_root); /* vportX */
                vport->vport_debugfs_root = NULL;
@@ -2827,6 +4105,21 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport)
                 * iDiag release
                 */
                if (phba->sli_rev == LPFC_SLI_REV4) {
+                       if (phba->idiag_ext_acc) {
+                               /* iDiag extAcc */
+                               debugfs_remove(phba->idiag_ext_acc);
+                               phba->idiag_ext_acc = NULL;
+                       }
+                       if (phba->idiag_mbx_acc) {
+                               /* iDiag mbxAcc */
+                               debugfs_remove(phba->idiag_mbx_acc);
+                               phba->idiag_mbx_acc = NULL;
+                       }
+                       if (phba->idiag_ctl_acc) {
+                               /* iDiag ctlAcc */
+                               debugfs_remove(phba->idiag_ctl_acc);
+                               phba->idiag_ctl_acc = NULL;
+                       }
                        if (phba->idiag_drb_acc) {
                                /* iDiag drbAcc */
                                debugfs_remove(phba->idiag_drb_acc);
@@ -2842,6 +4135,11 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport)
                                debugfs_remove(phba->idiag_que_info);
                                phba->idiag_que_info = NULL;
                        }
+                       if (phba->idiag_bar_acc) {
+                               /* iDiag barAcc */
+                               debugfs_remove(phba->idiag_bar_acc);
+                               phba->idiag_bar_acc = NULL;
+                       }
                        if (phba->idiag_pci_cfg) {
                                /* iDiag pciCfg */
                                debugfs_remove(phba->idiag_pci_cfg);
index 6525a5e..f83bd94 100644 (file)
 /* hbqinfo output buffer size */
 #define LPFC_HBQINFO_SIZE 8192
 
+/*
+ * For SLI4 iDiag debugfs diagnostics tool
+ */
+
 /* pciConf */
 #define LPFC_PCI_CFG_BROWSE 0xffff
 #define LPFC_PCI_CFG_RD_CMD_ARG 2
 #define LPFC_PCI_CFG_WR_CMD_ARG 3
 #define LPFC_PCI_CFG_SIZE 4096
-#define LPFC_PCI_CFG_RD_BUF_SIZE (LPFC_PCI_CFG_SIZE/2)
 #define LPFC_PCI_CFG_RD_SIZE (LPFC_PCI_CFG_SIZE/4)
 
+#define IDIAG_PCICFG_WHERE_INDX 0
+#define IDIAG_PCICFG_COUNT_INDX 1
+#define IDIAG_PCICFG_VALUE_INDX 2
+
+/* barAcc */
+#define LPFC_PCI_BAR_BROWSE 0xffff
+#define LPFC_PCI_BAR_RD_CMD_ARG 3
+#define LPFC_PCI_BAR_WR_CMD_ARG 3
+
+#define LPFC_PCI_IF0_BAR0_SIZE (1024 *  16)
+#define LPFC_PCI_IF0_BAR1_SIZE (1024 * 128)
+#define LPFC_PCI_IF0_BAR2_SIZE (1024 * 128)
+#define LPFC_PCI_IF2_BAR0_SIZE (1024 *  32)
+
+#define LPFC_PCI_BAR_RD_BUF_SIZE 4096
+#define LPFC_PCI_BAR_RD_SIZE (LPFC_PCI_BAR_RD_BUF_SIZE/4)
+
+#define LPFC_PCI_IF0_BAR0_RD_SIZE (LPFC_PCI_IF0_BAR0_SIZE/4)
+#define LPFC_PCI_IF0_BAR1_RD_SIZE (LPFC_PCI_IF0_BAR1_SIZE/4)
+#define LPFC_PCI_IF0_BAR2_RD_SIZE (LPFC_PCI_IF0_BAR2_SIZE/4)
+#define LPFC_PCI_IF2_BAR0_RD_SIZE (LPFC_PCI_IF2_BAR0_SIZE/4)
+
+#define IDIAG_BARACC_BAR_NUM_INDX 0
+#define IDIAG_BARACC_OFF_SET_INDX 1
+#define IDIAG_BARACC_ACC_MOD_INDX 2
+#define IDIAG_BARACC_REG_VAL_INDX 2
+#define IDIAG_BARACC_BAR_SZE_INDX 3
+
+#define IDIAG_BARACC_BAR_0 0
+#define IDIAG_BARACC_BAR_1 1
+#define IDIAG_BARACC_BAR_2 2
+
+#define SINGLE_WORD 1
+
 /* queue info */
 #define LPFC_QUE_INFO_GET_BUF_SIZE 4096
 
 #define LPFC_IDIAG_WQ 4
 #define LPFC_IDIAG_RQ 5
 
-/* doorbell acc */
+#define IDIAG_QUEACC_QUETP_INDX 0
+#define IDIAG_QUEACC_QUEID_INDX 1
+#define IDIAG_QUEACC_INDEX_INDX 2
+#define IDIAG_QUEACC_COUNT_INDX 3
+#define IDIAG_QUEACC_OFFST_INDX 4
+#define IDIAG_QUEACC_VALUE_INDX 5
+
+/* doorbell register acc */
 #define LPFC_DRB_ACC_ALL 0xffff
 #define LPFC_DRB_ACC_RD_CMD_ARG 1
 #define LPFC_DRB_ACC_WR_CMD_ARG 2
 
 #define LPFC_DRB_MAX  4
 
+#define IDIAG_DRBACC_REGID_INDX 0
+#define IDIAG_DRBACC_VALUE_INDX 1
+
+/* control register acc */
+#define LPFC_CTL_ACC_ALL 0xffff
+#define LPFC_CTL_ACC_RD_CMD_ARG 1
+#define LPFC_CTL_ACC_WR_CMD_ARG 2
+#define LPFC_CTL_ACC_BUF_SIZE 256
+
+#define LPFC_CTL_PORT_SEM  1
+#define LPFC_CTL_PORT_STA  2
+#define LPFC_CTL_PORT_CTL  3
+#define LPFC_CTL_PORT_ER1  4
+#define LPFC_CTL_PORT_ER2  5
+#define LPFC_CTL_PDEV_CTL  6
+
+#define LPFC_CTL_MAX  6
+
+#define IDIAG_CTLACC_REGID_INDX 0
+#define IDIAG_CTLACC_VALUE_INDX 1
+
+/* mailbox access */
+#define LPFC_MBX_DMP_ARG 4
+
+#define LPFC_MBX_ACC_BUF_SIZE 512
+#define LPFC_MBX_ACC_LBUF_SZ 128
+
+#define LPFC_MBX_DMP_MBX_WORD 0x00000001
+#define LPFC_MBX_DMP_MBX_BYTE 0x00000002
+#define LPFC_MBX_DMP_MBX_ALL (LPFC_MBX_DMP_MBX_WORD | LPFC_MBX_DMP_MBX_BYTE)
+
+#define LPFC_BSG_DMP_MBX_RD_MBX 0x00000001
+#define LPFC_BSG_DMP_MBX_RD_BUF 0x00000002
+#define LPFC_BSG_DMP_MBX_WR_MBX 0x00000004
+#define LPFC_BSG_DMP_MBX_WR_BUF 0x00000008
+#define LPFC_BSG_DMP_MBX_ALL (LPFC_BSG_DMP_MBX_RD_MBX | \
+                             LPFC_BSG_DMP_MBX_RD_BUF | \
+                             LPFC_BSG_DMP_MBX_WR_MBX | \
+                             LPFC_BSG_DMP_MBX_WR_BUF)
+
+#define LPFC_MBX_DMP_ALL 0xffff
+#define LPFC_MBX_ALL_CMD 0xff
+
+#define IDIAG_MBXACC_MBCMD_INDX 0
+#define IDIAG_MBXACC_DPMAP_INDX 1
+#define IDIAG_MBXACC_DPCNT_INDX 2
+#define IDIAG_MBXACC_WDCNT_INDX 3
+
+/* extents access */
+#define LPFC_EXT_ACC_CMD_ARG 1
+#define LPFC_EXT_ACC_BUF_SIZE 4096
+
+#define LPFC_EXT_ACC_AVAIL 0x1
+#define LPFC_EXT_ACC_ALLOC 0x2
+#define LPFC_EXT_ACC_DRIVR 0x4
+#define LPFC_EXT_ACC_ALL   (LPFC_EXT_ACC_DRIVR | \
+                           LPFC_EXT_ACC_AVAIL | \
+                           LPFC_EXT_ACC_ALLOC)
+
+#define IDIAG_EXTACC_EXMAP_INDX 0
+
 #define SIZE_U8  sizeof(uint8_t)
 #define SIZE_U16 sizeof(uint16_t)
 #define SIZE_U32 sizeof(uint32_t)
@@ -110,6 +215,11 @@ struct lpfc_idiag_cmd {
 #define LPFC_IDIAG_CMD_PCICFG_ST 0x00000003
 #define LPFC_IDIAG_CMD_PCICFG_CL 0x00000004
 
+#define LPFC_IDIAG_CMD_BARACC_RD 0x00000008
+#define LPFC_IDIAG_CMD_BARACC_WR 0x00000009
+#define LPFC_IDIAG_CMD_BARACC_ST 0x0000000a
+#define LPFC_IDIAG_CMD_BARACC_CL 0x0000000b
+
 #define LPFC_IDIAG_CMD_QUEACC_RD 0x00000011
 #define LPFC_IDIAG_CMD_QUEACC_WR 0x00000012
 #define LPFC_IDIAG_CMD_QUEACC_ST 0x00000013
@@ -119,6 +229,17 @@ struct lpfc_idiag_cmd {
 #define LPFC_IDIAG_CMD_DRBACC_WR 0x00000022
 #define LPFC_IDIAG_CMD_DRBACC_ST 0x00000023
 #define LPFC_IDIAG_CMD_DRBACC_CL 0x00000024
+
+#define LPFC_IDIAG_CMD_CTLACC_RD 0x00000031
+#define LPFC_IDIAG_CMD_CTLACC_WR 0x00000032
+#define LPFC_IDIAG_CMD_CTLACC_ST 0x00000033
+#define LPFC_IDIAG_CMD_CTLACC_CL 0x00000034
+
+#define LPFC_IDIAG_CMD_MBXACC_DP 0x00000041
+#define LPFC_IDIAG_BSG_MBXACC_DP 0x00000042
+
+#define LPFC_IDIAG_CMD_EXTACC_RD 0x00000051
+
        uint32_t data[LPFC_IDIAG_CMD_DATA_SIZE];
 };
 
index 32a0845..023da0e 100644 (file)
@@ -647,21 +647,15 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                }
                lpfc_cleanup_pending_mbox(vport);
 
-               if (phba->sli_rev == LPFC_SLI_REV4)
+               if (phba->sli_rev == LPFC_SLI_REV4) {
                        lpfc_sli4_unreg_all_rpis(vport);
-
-               if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
                        lpfc_mbx_unreg_vpi(vport);
                        spin_lock_irq(shost->host_lock);
                        vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
-                       spin_unlock_irq(shost->host_lock);
-               }
-               /*
-                * If VPI is unreged, driver need to do INIT_VPI
-                * before re-registering
-                */
-               if (phba->sli_rev == LPFC_SLI_REV4) {
-                       spin_lock_irq(shost->host_lock);
+                       /*
+                       * 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);
                }
@@ -880,6 +874,8 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                                        phba->fcf.current_rec.fcf_indx,
                                        irsp->ulpStatus, irsp->un.ulpWord[4],
                                        irsp->ulpTimeout);
+                       lpfc_sli4_set_fcf_flogi_fail(phba,
+                                       phba->fcf.current_rec.fcf_indx);
                        fcf_index = lpfc_sli4_fcf_rr_next_index_get(phba);
                        rc = lpfc_sli4_fcf_rr_next_proc(vport, fcf_index);
                        if (rc)
@@ -1096,11 +1092,14 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                        /* Set the fcfi to the fcfi we registered with */
                        elsiocb->iocb.ulpContext = phba->fcf.fcfi;
                }
-       } else if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
-               sp->cmn.request_multiple_Nport = 1;
-               /* For FLOGI, Let FLOGI rsp set the NPortID for VPI 0 */
-               icmd->ulpCt_h = 1;
-               icmd->ulpCt_l = 0;
+       } else {
+               if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
+                       sp->cmn.request_multiple_Nport = 1;
+                       /* For FLOGI, Let FLOGI rsp set the NPortID for VPI 0 */
+                       icmd->ulpCt_h = 1;
+                       icmd->ulpCt_l = 0;
+               } else
+                       sp->cmn.request_multiple_Nport = 0;
        }
 
        if (phba->fc_topology != LPFC_TOPOLOGY_LOOP) {
@@ -3656,7 +3655,8 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
                }
 
                icmd = &elsiocb->iocb;
-               icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
+               icmd->ulpContext = oldcmd->ulpContext;  /* Xri / rx_id */
+               icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
                pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
                *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
                pcmd += sizeof(uint32_t);
@@ -3673,7 +3673,8 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
                        return 1;
 
                icmd = &elsiocb->iocb;
-               icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
+               icmd->ulpContext = oldcmd->ulpContext;  /* Xri / rx_id */
+               icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
                pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
 
                if (mbox)
@@ -3695,7 +3696,8 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
                        return 1;
 
                icmd = &elsiocb->iocb;
-               icmd->ulpContext = oldcmd->ulpContext; /* Xri */
+               icmd->ulpContext = oldcmd->ulpContext;  /* Xri / rx_id */
+               icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
                pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
 
                memcpy(pcmd, ((struct lpfc_dmabuf *) oldiocb->context2)->virt,
@@ -3781,7 +3783,8 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,
 
        icmd = &elsiocb->iocb;
        oldcmd = &oldiocb->iocb;
-       icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
+       icmd->ulpContext = oldcmd->ulpContext;  /* Xri / rx_id */
+       icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
        pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
 
        *((uint32_t *) (pcmd)) = ELS_CMD_LS_RJT;
@@ -3853,7 +3856,8 @@ lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
 
        icmd = &elsiocb->iocb;
        oldcmd = &oldiocb->iocb;
-       icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
+       icmd->ulpContext = oldcmd->ulpContext;  /* Xri / rx_id */
+       icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
 
        /* Xmit ADISC ACC response tag <ulpIoTag> */
        lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
@@ -3931,7 +3935,9 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
 
        icmd = &elsiocb->iocb;
        oldcmd = &oldiocb->iocb;
-       icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
+       icmd->ulpContext = oldcmd->ulpContext;  /* Xri / rx_id */
+       icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
+
        /* Xmit PRLI ACC response tag <ulpIoTag> */
        lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
                         "0131 Xmit PRLI ACC response tag x%x xri x%x, "
@@ -4035,7 +4041,9 @@ lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format,
 
        icmd = &elsiocb->iocb;
        oldcmd = &oldiocb->iocb;
-       icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
+       icmd->ulpContext = oldcmd->ulpContext;  /* Xri / rx_id */
+       icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
+
        /* Xmit RNID ACC response tag <ulpIoTag> */
        lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
                         "0132 Xmit RNID ACC response tag x%x xri x%x\n",
@@ -4163,7 +4171,9 @@ lpfc_els_rsp_echo_acc(struct lpfc_vport *vport, uint8_t *data,
        if (!elsiocb)
                return 1;
 
-       elsiocb->iocb.ulpContext = oldiocb->iocb.ulpContext;    /* Xri */
+       elsiocb->iocb.ulpContext = oldiocb->iocb.ulpContext;  /* Xri / rx_id */
+       elsiocb->iocb.unsli3.rcvsli3.ox_id = oldiocb->iocb.unsli3.rcvsli3.ox_id;
+
        /* Xmit ECHO ACC response tag <ulpIoTag> */
        lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
                         "2876 Xmit ECHO ACC response tag x%x xri x%x\n",
@@ -5054,13 +5064,15 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        uint8_t *pcmd;
        struct lpfc_iocbq *elsiocb;
        struct lpfc_nodelist *ndlp;
-       uint16_t xri;
+       uint16_t oxid;
+       uint16_t rxid;
        uint32_t cmdsize;
 
        mb = &pmb->u.mb;
 
        ndlp = (struct lpfc_nodelist *) pmb->context2;
-       xri = (uint16_t) ((unsigned long)(pmb->context1));
+       rxid = (uint16_t) ((unsigned long)(pmb->context1) & 0xffff);
+       oxid = (uint16_t) (((unsigned long)(pmb->context1) >> 16) & 0xffff);
        pmb->context1 = NULL;
        pmb->context2 = NULL;
 
@@ -5082,7 +5094,8 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                return;
 
        icmd = &elsiocb->iocb;
-       icmd->ulpContext = xri;
+       icmd->ulpContext = rxid;
+       icmd->unsli3.rcvsli3.ox_id = oxid;
 
        pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
        *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
@@ -5137,13 +5150,16 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        uint8_t *pcmd;
        struct lpfc_iocbq *elsiocb;
        struct lpfc_nodelist *ndlp;
-       uint16_t xri, status;
+       uint16_t status;
+       uint16_t oxid;
+       uint16_t rxid;
        uint32_t cmdsize;
 
        mb = &pmb->u.mb;
 
        ndlp = (struct lpfc_nodelist *) pmb->context2;
-       xri = (uint16_t) ((unsigned long)(pmb->context1));
+       rxid = (uint16_t) ((unsigned long)(pmb->context1) & 0xffff);
+       oxid = (uint16_t) (((unsigned long)(pmb->context1) >> 16) & 0xffff);
        pmb->context1 = NULL;
        pmb->context2 = NULL;
 
@@ -5165,7 +5181,8 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                return;
 
        icmd = &elsiocb->iocb;
-       icmd->ulpContext = xri;
+       icmd->ulpContext = rxid;
+       icmd->unsli3.rcvsli3.ox_id = oxid;
 
        pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
        *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
@@ -5238,8 +5255,9 @@ lpfc_els_rcv_rls(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
        mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC);
        if (mbox) {
                lpfc_read_lnk_stat(phba, mbox);
-               mbox->context1 =
-                   (void *)((unsigned long) cmdiocb->iocb.ulpContext);
+               mbox->context1 = (void *)((unsigned long)
+                       ((cmdiocb->iocb.unsli3.rcvsli3.ox_id << 16) |
+                       cmdiocb->iocb.ulpContext)); /* rx_id */
                mbox->context2 = lpfc_nlp_get(ndlp);
                mbox->vport = vport;
                mbox->mbox_cmpl = lpfc_els_rsp_rls_acc;
@@ -5314,7 +5332,8 @@ lpfc_els_rcv_rtv(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
        pcmd += sizeof(uint32_t); /* Skip past command */
 
        /* use the command's xri in the response */
-       elsiocb->iocb.ulpContext = cmdiocb->iocb.ulpContext;
+       elsiocb->iocb.ulpContext = cmdiocb->iocb.ulpContext;  /* Xri / rx_id */
+       elsiocb->iocb.unsli3.rcvsli3.ox_id = cmdiocb->iocb.unsli3.rcvsli3.ox_id;
 
        rtv_rsp = (struct RTV_RSP *)pcmd;
 
@@ -5399,8 +5418,9 @@ lpfc_els_rcv_rps(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
                mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC);
                if (mbox) {
                        lpfc_read_lnk_stat(phba, mbox);
-                       mbox->context1 =
-                           (void *)((unsigned long) cmdiocb->iocb.ulpContext);
+                       mbox->context1 = (void *)((unsigned long)
+                               ((cmdiocb->iocb.unsli3.rcvsli3.ox_id << 16) |
+                               cmdiocb->iocb.ulpContext)); /* rx_id */
                        mbox->context2 = lpfc_nlp_get(ndlp);
                        mbox->vport = vport;
                        mbox->mbox_cmpl = lpfc_els_rsp_rps_acc;
@@ -5554,7 +5574,8 @@ lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize,
 
        icmd = &elsiocb->iocb;
        oldcmd = &oldiocb->iocb;
-       icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
+       icmd->ulpContext = oldcmd->ulpContext;  /* Xri / rx_id */
+       icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
 
        pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
        *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
@@ -6586,7 +6607,7 @@ lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi)
 {
        struct lpfc_vport *vport;
        unsigned long flags;
-       int i;
+       int i = 0;
 
        /* The physical ports are always vpi 0 - translate is unnecessary. */
        if (vpi > 0) {
@@ -6609,7 +6630,7 @@ lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi)
 
        spin_lock_irqsave(&phba->hbalock, flags);
        list_for_each_entry(vport, &phba->port_list, listentry) {
-               if (vport->vpi == vpi) {
+               if (vport->vpi == i) {
                        spin_unlock_irqrestore(&phba->hbalock, flags);
                        return vport;
                }
@@ -7787,6 +7808,7 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba,
 {
        uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri);
        uint16_t rxid = bf_get(lpfc_wcqe_xa_remote_xid, axri);
+       uint16_t lxri = 0;
 
        struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL;
        unsigned long iflag = 0;
@@ -7815,7 +7837,12 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba,
                }
        }
        spin_unlock(&phba->sli4_hba.abts_sgl_list_lock);
-       sglq_entry = __lpfc_get_active_sglq(phba, xri);
+       lxri = lpfc_sli4_xri_inrange(phba, xri);
+       if (lxri == NO_XRI) {
+               spin_unlock_irqrestore(&phba->hbalock, iflag);
+               return;
+       }
+       sglq_entry = __lpfc_get_active_sglq(phba, lxri);
        if (!sglq_entry || (sglq_entry->sli4_xritag != xri)) {
                spin_unlock_irqrestore(&phba->hbalock, iflag);
                return;
index 18d0dbf..0b47adf 100644 (file)
@@ -1109,6 +1109,28 @@ out:
        return;
 }
 
+/**
+ * lpfc_sli4_clear_fcf_rr_bmask
+ * @phba pointer to the struct lpfc_hba for this port.
+ * This fucnction resets the round robin bit mask and clears the
+ * fcf priority list. The list deletions are done while holding the
+ * hbalock. The ON_LIST flag and the FLOGI_FAILED flags are cleared
+ * from the lpfc_fcf_pri record.
+ **/
+void
+lpfc_sli4_clear_fcf_rr_bmask(struct lpfc_hba *phba)
+{
+       struct lpfc_fcf_pri *fcf_pri;
+       struct lpfc_fcf_pri *next_fcf_pri;
+       memset(phba->fcf.fcf_rr_bmask, 0, sizeof(*phba->fcf.fcf_rr_bmask));
+       spin_lock_irq(&phba->hbalock);
+       list_for_each_entry_safe(fcf_pri, next_fcf_pri,
+                               &phba->fcf.fcf_pri_list, list) {
+               list_del_init(&fcf_pri->list);
+               fcf_pri->fcf_rec.flag = 0;
+       }
+       spin_unlock_irq(&phba->hbalock);
+}
 static void
 lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
 {
@@ -1130,7 +1152,8 @@ lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
        spin_unlock_irq(&phba->hbalock);
 
        /* If there is a pending FCoE event, restart FCF table scan. */
-       if (lpfc_check_pending_fcoe_event(phba, LPFC_UNREG_FCF))
+       if ((!(phba->hba_flag & FCF_RR_INPROG)) &&
+               lpfc_check_pending_fcoe_event(phba, LPFC_UNREG_FCF))
                goto fail_out;
 
        /* Mark successful completion of FCF table scan */
@@ -1249,6 +1272,30 @@ lpfc_vlan_id_match(uint16_t curr_vlan_id, uint16_t new_vlan_id)
        return (curr_vlan_id == new_vlan_id);
 }
 
+/**
+ * lpfc_update_fcf_record - Update driver fcf record
+ * __lpfc_update_fcf_record_pri - update the lpfc_fcf_pri record.
+ * @phba: pointer to lpfc hba data structure.
+ * @fcf_index: Index for the lpfc_fcf_record.
+ * @new_fcf_record: pointer to hba fcf record.
+ *
+ * This routine updates the driver FCF priority record from the new HBA FCF
+ * record. This routine is called with the host lock held.
+ **/
+static void
+__lpfc_update_fcf_record_pri(struct lpfc_hba *phba, uint16_t fcf_index,
+                                struct fcf_record *new_fcf_record
+                                )
+{
+       struct lpfc_fcf_pri *fcf_pri;
+
+       fcf_pri = &phba->fcf.fcf_pri[fcf_index];
+       fcf_pri->fcf_rec.fcf_index = fcf_index;
+       /* FCF record priority */
+       fcf_pri->fcf_rec.priority = new_fcf_record->fip_priority;
+
+}
+
 /**
  * lpfc_copy_fcf_record - Copy fcf information to lpfc_hba.
  * @fcf: pointer to driver fcf record.
@@ -1332,6 +1379,9 @@ __lpfc_update_fcf_record(struct lpfc_hba *phba, struct lpfc_fcf_rec *fcf_rec,
        fcf_rec->addr_mode = addr_mode;
        fcf_rec->vlan_id = vlan_id;
        fcf_rec->flag |= (flag | RECORD_VALID);
+       __lpfc_update_fcf_record_pri(phba,
+               bf_get(lpfc_fcf_record_fcf_index, new_fcf_record),
+                                new_fcf_record);
 }
 
 /**
@@ -1834,6 +1884,8 @@ lpfc_sli4_fcf_record_match(struct lpfc_hba *phba,
                return false;
        if (!lpfc_fab_name_match(fcf_rec->fabric_name, new_fcf_record))
                return false;
+       if (fcf_rec->priority != new_fcf_record->fip_priority)
+               return false;
        return true;
 }
 
@@ -1896,6 +1948,152 @@ stop_flogi_current_fcf:
        return 1;
 }
 
+/**
+ * lpfc_sli4_fcf_pri_list_del
+ * @phba: pointer to lpfc hba data structure.
+ * @fcf_index the index of the fcf record to delete
+ * This routine checks the on list flag of the fcf_index to be deleted.
+ * If it is one the list then it is removed from the list, and the flag
+ * is cleared. This routine grab the hbalock before removing the fcf
+ * record from the list.
+ **/
+static void lpfc_sli4_fcf_pri_list_del(struct lpfc_hba *phba,
+                       uint16_t fcf_index)
+{
+       struct lpfc_fcf_pri *new_fcf_pri;
+
+       new_fcf_pri = &phba->fcf.fcf_pri[fcf_index];
+       lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+               "3058 deleting idx x%x pri x%x flg x%x\n",
+               fcf_index, new_fcf_pri->fcf_rec.priority,
+                new_fcf_pri->fcf_rec.flag);
+       spin_lock_irq(&phba->hbalock);
+       if (new_fcf_pri->fcf_rec.flag & LPFC_FCF_ON_PRI_LIST) {
+               if (phba->fcf.current_rec.priority ==
+                               new_fcf_pri->fcf_rec.priority)
+                       phba->fcf.eligible_fcf_cnt--;
+               list_del_init(&new_fcf_pri->list);
+               new_fcf_pri->fcf_rec.flag &= ~LPFC_FCF_ON_PRI_LIST;
+       }
+       spin_unlock_irq(&phba->hbalock);
+}
+
+/**
+ * lpfc_sli4_set_fcf_flogi_fail
+ * @phba: pointer to lpfc hba data structure.
+ * @fcf_index the index of the fcf record to update
+ * This routine acquires the hbalock and then set the LPFC_FCF_FLOGI_FAILED
+ * flag so the the round robin slection for the particular priority level
+ * will try a different fcf record that does not have this bit set.
+ * If the fcf record is re-read for any reason this flag is cleared brfore
+ * adding it to the priority list.
+ **/
+void
+lpfc_sli4_set_fcf_flogi_fail(struct lpfc_hba *phba, uint16_t fcf_index)
+{
+       struct lpfc_fcf_pri *new_fcf_pri;
+       new_fcf_pri = &phba->fcf.fcf_pri[fcf_index];
+       spin_lock_irq(&phba->hbalock);
+       new_fcf_pri->fcf_rec.flag |= LPFC_FCF_FLOGI_FAILED;
+       spin_unlock_irq(&phba->hbalock);
+}
+
+/**
+ * lpfc_sli4_fcf_pri_list_add
+ * @phba: pointer to lpfc hba data structure.
+ * @fcf_index the index of the fcf record to add
+ * This routine checks the priority of the fcf_index to be added.
+ * If it is a lower priority than the current head of the fcf_pri list
+ * then it is added to the list in the right order.
+ * If it is the same priority as the current head of the list then it
+ * is added to the head of the list and its bit in the rr_bmask is set.
+ * If the fcf_index to be added is of a higher priority than the current
+ * head of the list then the rr_bmask is cleared, its bit is set in the
+ * rr_bmask and it is added to the head of the list.
+ * returns:
+ * 0=success 1=failure
+ **/
+int lpfc_sli4_fcf_pri_list_add(struct lpfc_hba *phba, uint16_t fcf_index,
+       struct fcf_record *new_fcf_record)
+{
+       uint16_t current_fcf_pri;
+       uint16_t last_index;
+       struct lpfc_fcf_pri *fcf_pri;
+       struct lpfc_fcf_pri *next_fcf_pri;
+       struct lpfc_fcf_pri *new_fcf_pri;
+       int ret;
+
+       new_fcf_pri = &phba->fcf.fcf_pri[fcf_index];
+       lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+               "3059 adding idx x%x pri x%x flg x%x\n",
+               fcf_index, new_fcf_record->fip_priority,
+                new_fcf_pri->fcf_rec.flag);
+       spin_lock_irq(&phba->hbalock);
+       if (new_fcf_pri->fcf_rec.flag & LPFC_FCF_ON_PRI_LIST)
+               list_del_init(&new_fcf_pri->list);
+       new_fcf_pri->fcf_rec.fcf_index = fcf_index;
+       new_fcf_pri->fcf_rec.priority = new_fcf_record->fip_priority;
+       if (list_empty(&phba->fcf.fcf_pri_list)) {
+               list_add(&new_fcf_pri->list, &phba->fcf.fcf_pri_list);
+               ret = lpfc_sli4_fcf_rr_index_set(phba,
+                               new_fcf_pri->fcf_rec.fcf_index);
+               goto out;
+       }
+
+       last_index = find_first_bit(phba->fcf.fcf_rr_bmask,
+                               LPFC_SLI4_FCF_TBL_INDX_MAX);
+       if (last_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
+               ret = 0; /* Empty rr list */
+               goto out;
+       }
+       current_fcf_pri = phba->fcf.fcf_pri[last_index].fcf_rec.priority;
+       if (new_fcf_pri->fcf_rec.priority <=  current_fcf_pri) {
+               list_add(&new_fcf_pri->list, &phba->fcf.fcf_pri_list);
+               if (new_fcf_pri->fcf_rec.priority <  current_fcf_pri) {
+                       memset(phba->fcf.fcf_rr_bmask, 0,
+                               sizeof(*phba->fcf.fcf_rr_bmask));
+                       /* fcfs_at_this_priority_level = 1; */
+                       phba->fcf.eligible_fcf_cnt = 1;
+               } else
+                       /* fcfs_at_this_priority_level++; */
+                       phba->fcf.eligible_fcf_cnt++;
+               ret = lpfc_sli4_fcf_rr_index_set(phba,
+                               new_fcf_pri->fcf_rec.fcf_index);
+               goto out;
+       }
+
+       list_for_each_entry_safe(fcf_pri, next_fcf_pri,
+                               &phba->fcf.fcf_pri_list, list) {
+               if (new_fcf_pri->fcf_rec.priority <=
+                               fcf_pri->fcf_rec.priority) {
+                       if (fcf_pri->list.prev == &phba->fcf.fcf_pri_list)
+                               list_add(&new_fcf_pri->list,
+                                               &phba->fcf.fcf_pri_list);
+                       else
+                               list_add(&new_fcf_pri->list,
+                                        &((struct lpfc_fcf_pri *)
+                                       fcf_pri->list.prev)->list);
+                       ret = 0;
+                       goto out;
+               } else if (fcf_pri->list.next == &phba->fcf.fcf_pri_list
+                       || new_fcf_pri->fcf_rec.priority <
+                               next_fcf_pri->fcf_rec.priority) {
+                       list_add(&new_fcf_pri->list, &fcf_pri->list);
+                       ret = 0;
+                       goto out;
+               }
+               if (new_fcf_pri->fcf_rec.priority > fcf_pri->fcf_rec.priority)
+                       continue;
+
+       }
+       ret = 1;
+out:
+       /* we use = instead of |= to clear the FLOGI_FAILED flag. */
+       new_fcf_pri->fcf_rec.flag = LPFC_FCF_ON_PRI_LIST;
+       spin_unlock_irq(&phba->hbalock);
+       return ret;
+}
+
 /**
  * lpfc_mbx_cmpl_fcf_scan_read_fcf_rec - fcf scan read_fcf mbox cmpl handler.
  * @phba: pointer to lpfc hba data structure.
@@ -1958,6 +2156,9 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
         * record for roundrobin FCF failover.
         */
        if (!rc) {
+               lpfc_sli4_fcf_pri_list_del(phba,
+                                       bf_get(lpfc_fcf_record_fcf_index,
+                                              new_fcf_record));
                lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
                                "2781 FCF (x%x) failed connection "
                                "list check: (x%x/x%x)\n",
@@ -2005,7 +2206,8 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
                goto read_next_fcf;
        } else {
                fcf_index = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record);
-               rc = lpfc_sli4_fcf_rr_index_set(phba, fcf_index);
+               rc = lpfc_sli4_fcf_pri_list_add(phba, fcf_index,
+                                                       new_fcf_record);
                if (rc)
                        goto read_next_fcf;
        }
@@ -2018,7 +2220,8 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
         */
        spin_lock_irq(&phba->hbalock);
        if (phba->fcf.fcf_flag & FCF_IN_USE) {
-               if (lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec,
+               if (phba->cfg_fcf_failover_policy == LPFC_FCF_FOV &&
+                       lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec,
                    new_fcf_record, vlan_id)) {
                        if (bf_get(lpfc_fcf_record_fcf_index, new_fcf_record) ==
                            phba->fcf.current_rec.fcf_indx) {
@@ -2232,7 +2435,8 @@ read_next_fcf:
                            (phba->fcf.fcf_flag & FCF_REDISC_PEND))
                                return;
 
-                       if (phba->fcf.fcf_flag & FCF_IN_USE) {
+                       if (phba->cfg_fcf_failover_policy == LPFC_FCF_FOV &&
+                               phba->fcf.fcf_flag & FCF_IN_USE) {
                                /*
                                 * In case the current in-use FCF record no
                                 * longer existed during FCF discovery that
@@ -2247,7 +2451,6 @@ read_next_fcf:
                                spin_lock_irq(&phba->hbalock);
                                phba->fcf.fcf_flag |= FCF_REDISC_FOV;
                                spin_unlock_irq(&phba->hbalock);
-                               lpfc_sli4_mbox_cmd_free(phba, mboxq);
                                lpfc_sli4_fcf_scan_read_fcf_rec(phba,
                                                LPFC_FCOE_FCF_GET_FIRST);
                                return;
@@ -2424,7 +2627,8 @@ lpfc_mbx_cmpl_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
 
        /* Update the eligible FCF record index bmask */
        fcf_index = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record);
-       rc = lpfc_sli4_fcf_rr_index_set(phba, fcf_index);
+
+       rc = lpfc_sli4_fcf_pri_list_add(phba, fcf_index, new_fcf_record);
 
 out:
        lpfc_sli4_mbox_cmd_free(phba, mboxq);
@@ -2645,6 +2849,7 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
        vport->vpi_state |= LPFC_VPI_REGISTERED;
        vport->fc_flag |= FC_VFI_REGISTERED;
        vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
+       vport->fc_flag &= ~FC_VPORT_NEEDS_INIT_VPI;
        spin_unlock_irq(shost->host_lock);
 
        if (vport->port_state == LPFC_FABRIC_CFG_LINK) {
@@ -2893,8 +3098,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
                        goto out;
                }
                /* Reset FCF roundrobin bmask for new discovery */
-               memset(phba->fcf.fcf_rr_bmask, 0,
-                      sizeof(*phba->fcf.fcf_rr_bmask));
+               lpfc_sli4_clear_fcf_rr_bmask(phba);
        }
 
        return;
@@ -5592,7 +5796,7 @@ lpfc_unregister_fcf_rescan(struct lpfc_hba *phba)
        spin_unlock_irq(&phba->hbalock);
 
        /* Reset FCF roundrobin bmask for new discovery */
-       memset(phba->fcf.fcf_rr_bmask, 0, sizeof(*phba->fcf.fcf_rr_bmask));
+       lpfc_sli4_clear_fcf_rr_bmask(phba);
 
        rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba, LPFC_FCOE_FCF_GET_FIRST);
 
index ab4c4d6..046edc4 100644 (file)
@@ -3470,11 +3470,16 @@ typedef struct {
    or CMD_IOCB_RCV_SEQ64_CX (0xB5) */
 
 struct rcv_sli3 {
-       uint32_t word8Rsvd;
 #ifdef __BIG_ENDIAN_BITFIELD
+       uint16_t ox_id;
+       uint16_t seq_cnt;
+
        uint16_t vpi;
        uint16_t word9Rsvd;
 #else  /*  __LITTLE_ENDIAN */
+       uint16_t seq_cnt;
+       uint16_t ox_id;
+
        uint16_t word9Rsvd;
        uint16_t vpi;
 #endif
index 11e26a2..7f8003b 100644 (file)
@@ -170,15 +170,8 @@ struct lpfc_sli_intf {
 #define LPFC_PCI_FUNC3         3
 #define LPFC_PCI_FUNC4         4
 
-/* SLI4 interface type-2 control register offsets */
-#define LPFC_CTL_PORT_SEM_OFFSET       0x400
-#define LPFC_CTL_PORT_STA_OFFSET       0x404
-#define LPFC_CTL_PORT_CTL_OFFSET       0x408
-#define LPFC_CTL_PORT_ER1_OFFSET       0x40C
-#define LPFC_CTL_PORT_ER2_OFFSET       0x410
+/* SLI4 interface type-2 PDEV_CTL register */
 #define LPFC_CTL_PDEV_CTL_OFFSET       0x414
-
-/* Some SLI4 interface type-2 PDEV_CTL register bits */
 #define LPFC_CTL_PDEV_CTL_DRST         0x00000001
 #define LPFC_CTL_PDEV_CTL_FRST         0x00000002
 #define LPFC_CTL_PDEV_CTL_DD           0x00000004
@@ -337,6 +330,7 @@ struct lpfc_cqe {
 #define CQE_CODE_RELEASE_WQE           0x2
 #define CQE_CODE_RECEIVE               0x4
 #define CQE_CODE_XRI_ABORTED           0x5
+#define CQE_CODE_RECEIVE_V1            0x9
 
 /* completion queue entry for wqe completions */
 struct lpfc_wcqe_complete {
@@ -440,7 +434,10 @@ struct lpfc_rcqe {
 #define FC_STATUS_RQ_BUF_LEN_EXCEEDED  0x11 /* payload truncated */
 #define FC_STATUS_INSUFF_BUF_NEED_BUF  0x12 /* Insufficient buffers */
 #define FC_STATUS_INSUFF_BUF_FRM_DISC  0x13 /* Frame Discard */
-       uint32_t reserved1;
+       uint32_t word1;
+#define lpfc_rcqe_fcf_id_v1_SHIFT      0
+#define lpfc_rcqe_fcf_id_v1_MASK       0x0000003F
+#define lpfc_rcqe_fcf_id_v1_WORD       word1
        uint32_t word2;
 #define lpfc_rcqe_length_SHIFT         16
 #define lpfc_rcqe_length_MASK          0x0000FFFF
@@ -451,6 +448,9 @@ struct lpfc_rcqe {
 #define lpfc_rcqe_fcf_id_SHIFT         0
 #define lpfc_rcqe_fcf_id_MASK          0x0000003F
 #define lpfc_rcqe_fcf_id_WORD          word2
+#define lpfc_rcqe_rq_id_v1_SHIFT       0
+#define lpfc_rcqe_rq_id_v1_MASK                0x0000FFFF
+#define lpfc_rcqe_rq_id_v1_WORD                word2
        uint32_t word3;
 #define lpfc_rcqe_valid_SHIFT          lpfc_cqe_valid_SHIFT
 #define lpfc_rcqe_valid_MASK           lpfc_cqe_valid_MASK
@@ -515,7 +515,7 @@ struct lpfc_register {
 /* The following BAR0 register sets are defined for if_type 0 and 2 UCNAs. */
 #define LPFC_SLI_INTF                  0x0058
 
-#define LPFC_SLIPORT_IF2_SMPHR         0x0400
+#define LPFC_CTL_PORT_SEM_OFFSET       0x400
 #define lpfc_port_smphr_perr_SHIFT     31
 #define lpfc_port_smphr_perr_MASK      0x1
 #define lpfc_port_smphr_perr_WORD      word0
@@ -575,7 +575,7 @@ struct lpfc_register {
 #define LPFC_POST_STAGE_PORT_READY                     0xC000
 #define LPFC_POST_STAGE_PORT_UE                        0xF000
 
-#define LPFC_SLIPORT_STATUS            0x0404
+#define LPFC_CTL_PORT_STA_OFFSET       0x404
 #define lpfc_sliport_status_err_SHIFT  31
 #define lpfc_sliport_status_err_MASK   0x1
 #define lpfc_sliport_status_err_WORD   word0
@@ -593,7 +593,7 @@ struct lpfc_register {
 #define lpfc_sliport_status_rdy_WORD   word0
 #define MAX_IF_TYPE_2_RESETS   1000
 
-#define LPFC_SLIPORT_CNTRL             0x0408
+#define LPFC_CTL_PORT_CTL_OFFSET       0x408
 #define lpfc_sliport_ctrl_end_SHIFT    30
 #define lpfc_sliport_ctrl_end_MASK     0x1
 #define lpfc_sliport_ctrl_end_WORD     word0
@@ -604,8 +604,8 @@ struct lpfc_register {
 #define lpfc_sliport_ctrl_ip_WORD      word0
 #define LPFC_SLIPORT_INIT_PORT 1
 
-#define LPFC_SLIPORT_ERR_1             0x040C
-#define LPFC_SLIPORT_ERR_2             0x0410
+#define LPFC_CTL_PORT_ER1_OFFSET       0x40C
+#define LPFC_CTL_PORT_ER2_OFFSET       0x410
 
 /* The following Registers apply to SLI4 if_type 0 UCNAs. They typically
  * reside in BAR 2.
@@ -3198,6 +3198,8 @@ struct lpfc_grp_hdr {
 #define lpfc_grp_hdr_id_MASK           0x000000FF
 #define lpfc_grp_hdr_id_WORD           word2
        uint8_t rev_name[128];
+       uint8_t date[12];
+       uint8_t revision[32];
 };
 
 #define FCP_COMMAND 0x0
index 148b98d..a3c8200 100644 (file)
@@ -2927,6 +2927,8 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost)
                                 sizeof fc_host_symbolic_name(shost));
 
        fc_host_supported_speeds(shost) = 0;
+       if (phba->lmt & LMT_16Gb)
+               fc_host_supported_speeds(shost) |= FC_PORTSPEED_16GBIT;
        if (phba->lmt & LMT_10Gb)
                fc_host_supported_speeds(shost) |= FC_PORTSPEED_10GBIT;
        if (phba->lmt & LMT_8Gb)
@@ -3632,8 +3634,7 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba,
                        lpfc_sli4_fcf_dead_failthrough(phba);
                } else {
                        /* Reset FCF roundrobin bmask for new discovery */
-                       memset(phba->fcf.fcf_rr_bmask, 0,
-                              sizeof(*phba->fcf.fcf_rr_bmask));
+                       lpfc_sli4_clear_fcf_rr_bmask(phba);
                        /*
                         * Handling fast FCF failover to a DEAD FCF event is
                         * considered equalivant to receiving CVL to all vports.
@@ -3647,7 +3648,7 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba,
                        " tag 0x%x\n", acqe_fip->index, acqe_fip->event_tag);
 
                vport = lpfc_find_vport_by_vpid(phba,
-                               acqe_fip->index - phba->vpi_base);
+                                               acqe_fip->index);
                ndlp = lpfc_sli4_perform_vport_cvl(vport);
                if (!ndlp)
                        break;
@@ -3719,8 +3720,7 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba,
                                 * Reset FCF roundrobin bmask for new
                                 * discovery.
                                 */
-                               memset(phba->fcf.fcf_rr_bmask, 0,
-                                      sizeof(*phba->fcf.fcf_rr_bmask));
+                               lpfc_sli4_clear_fcf_rr_bmask(phba);
                }
                break;
        default:
@@ -4034,6 +4034,34 @@ lpfc_reset_hba(struct lpfc_hba *phba)
        lpfc_unblock_mgmt_io(phba);
 }
 
+/**
+ * lpfc_sli_sriov_nr_virtfn_get - Get the number of sr-iov virtual functions
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This function enables the PCI SR-IOV virtual functions to a physical
+ * function. It invokes the PCI SR-IOV api with the @nr_vfn provided to
+ * enable the number of virtual functions to the physical function. As
+ * not all devices support SR-IOV, the return code from the pci_enable_sriov()
+ * API call does not considered as an error condition for most of the device.
+ **/
+uint16_t
+lpfc_sli_sriov_nr_virtfn_get(struct lpfc_hba *phba)
+{
+       struct pci_dev *pdev = phba->pcidev;
+       uint16_t nr_virtfn;
+       int pos;
+
+       if (!pdev->is_physfn)
+               return 0;
+
+       pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
+       if (pos == 0)
+               return 0;
+
+       pci_read_config_word(pdev, pos + PCI_SRIOV_TOTAL_VF, &nr_virtfn);
+       return nr_virtfn;
+}
+
 /**
  * lpfc_sli_probe_sriov_nr_virtfn - Enable a number of sr-iov virtual functions
  * @phba: pointer to lpfc hba data structure.
@@ -4049,8 +4077,17 @@ int
 lpfc_sli_probe_sriov_nr_virtfn(struct lpfc_hba *phba, int nr_vfn)
 {
        struct pci_dev *pdev = phba->pcidev;
+       uint16_t max_nr_vfn;
        int rc;
 
+       max_nr_vfn = lpfc_sli_sriov_nr_virtfn_get(phba);
+       if (nr_vfn > max_nr_vfn) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "3057 Requested vfs (%d) greater than "
+                               "supported vfs (%d)", nr_vfn, max_nr_vfn);
+               return -EINVAL;
+       }
+
        rc = pci_enable_sriov(pdev, nr_vfn);
        if (rc) {
                lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
@@ -4516,7 +4553,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
                }
        }
 
-       return rc;
+       return 0;
 
 out_free_fcp_eq_hdl:
        kfree(phba->sli4_hba.fcp_eq_hdl);
@@ -4966,17 +5003,14 @@ out_free_mem:
  * @phba: pointer to lpfc hba data structure.
  *
  * This routine is invoked to post rpi header templates to the
- * HBA consistent with the SLI-4 interface spec.  This routine
+ * port for those SLI4 ports that do not support extents.  This routine
  * posts a PAGE_SIZE memory region to the port to hold up to
- * PAGE_SIZE modulo 64 rpi context headers.
- * No locks are held here because this is an initialization routine
- * called only from probe or lpfc_online when interrupts are not
- * enabled and the driver is reinitializing the device.
+ * PAGE_SIZE modulo 64 rpi context headers.  This is an initialization routine
+ * and should be called only when interrupts are disabled.
  *
  * Return codes
  *     0 - successful
- *     -ENOMEM - No available memory
- *      -EIO - The mailbox failed to complete successfully.
+ *     -ERROR - otherwise.
  **/
 int
 lpfc_sli4_init_rpi_hdrs(struct lpfc_hba *phba)
@@ -5687,17 +5721,22 @@ lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba, uint32_t if_type)
                break;
        case LPFC_SLI_INTF_IF_TYPE_2:
                phba->sli4_hba.u.if_type2.ERR1regaddr =
-                       phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_ERR_1;
+                       phba->sli4_hba.conf_regs_memmap_p +
+                                               LPFC_CTL_PORT_ER1_OFFSET;
                phba->sli4_hba.u.if_type2.ERR2regaddr =
-                       phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_ERR_2;
+                       phba->sli4_hba.conf_regs_memmap_p +
+                                               LPFC_CTL_PORT_ER2_OFFSET;
                phba->sli4_hba.u.if_type2.CTRLregaddr =
-                       phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_CNTRL;
+                       phba->sli4_hba.conf_regs_memmap_p +
+                                               LPFC_CTL_PORT_CTL_OFFSET;
                phba->sli4_hba.u.if_type2.STATUSregaddr =
-                       phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_STATUS;
+                       phba->sli4_hba.conf_regs_memmap_p +
+                                               LPFC_CTL_PORT_STA_OFFSET;
                phba->sli4_hba.SLIINTFregaddr =
                        phba->sli4_hba.conf_regs_memmap_p + LPFC_SLI_INTF;
                phba->sli4_hba.PSMPHRregaddr =
-                    phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_IF2_SMPHR;
+                       phba->sli4_hba.conf_regs_memmap_p +
+                                               LPFC_CTL_PORT_SEM_OFFSET;
                phba->sli4_hba.RQDBregaddr =
                        phba->sli4_hba.conf_regs_memmap_p + LPFC_RQ_DOORBELL;
                phba->sli4_hba.WQDBregaddr =
@@ -8859,11 +8898,11 @@ lpfc_write_firmware(struct lpfc_hba *phba, const struct firmware *fw)
                return -EINVAL;
        }
        lpfc_decode_firmware_rev(phba, fwrev, 1);
-       if (strncmp(fwrev, image->rev_name, strnlen(fwrev, 16))) {
+       if (strncmp(fwrev, image->revision, strnlen(image->revision, 16))) {
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                                "3023 Updating Firmware. Current Version:%s "
                                "New Version:%s\n",
-                               fwrev, image->rev_name);
+                               fwrev, image->revision);
                for (i = 0; i < LPFC_MBX_WR_CONFIG_MAX_BDE; i++) {
                        dmabuf = kzalloc(sizeof(struct lpfc_dmabuf),
                                         GFP_KERNEL);
@@ -8892,9 +8931,9 @@ lpfc_write_firmware(struct lpfc_hba *phba, const struct firmware *fw)
                                               fw->size - offset);
                                        break;
                                }
-                               temp_offset += SLI4_PAGE_SIZE;
                                memcpy(dmabuf->virt, fw->data + temp_offset,
                                       SLI4_PAGE_SIZE);
+                               temp_offset += SLI4_PAGE_SIZE;
                        }
                        rc = lpfc_wr_object(phba, &dma_buffer_list,
                                    (fw->size - offset), &offset);
@@ -9005,6 +9044,7 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
        }
 
        INIT_LIST_HEAD(&phba->active_rrq_list);
+       INIT_LIST_HEAD(&phba->fcf.fcf_pri_list);
 
        /* Set up common device driver resources */
        error = lpfc_setup_driver_resource_phase2(phba);
@@ -9112,7 +9152,6 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
 
        /* Check if there are static vports to be created. */
        lpfc_create_static_vport(phba);
-
        return 0;
 
 out_disable_intr:
@@ -9483,6 +9522,13 @@ lpfc_io_slot_reset_s4(struct pci_dev *pdev)
        }
 
        pci_restore_state(pdev);
+
+       /*
+        * As the new kernel behavior of pci_restore_state() API call clears
+        * device saved_state flag, need to save the restored state again.
+        */
+       pci_save_state(pdev);
+
        if (pdev->is_busmaster)
                pci_set_master(pdev);
 
index 5567670..83450cc 100644 (file)
@@ -2031,7 +2031,7 @@ lpfc_init_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport)
        bf_set(lpfc_init_vfi_vp, init_vfi, 1);
        bf_set(lpfc_init_vfi_vfi, init_vfi,
               vport->phba->sli4_hba.vfi_ids[vport->vfi]);
-       bf_set(lpfc_init_vpi_vpi, init_vfi,
+       bf_set(lpfc_init_vfi_vpi, init_vfi,
               vport->phba->vpi_ids[vport->vpi]);
        bf_set(lpfc_init_vfi_fcfi, init_vfi,
               vport->phba->fcf.fcfi);
index 3ccc974..eadd241 100644 (file)
@@ -1302,13 +1302,13 @@ lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc,
                case SCSI_PROT_NORMAL:
                default:
                        lpfc_printf_log(phba, KERN_ERR, LOG_BG,
-                               "9063 BLKGRD: Bad op/guard:%d/%d combination\n",
-                                       scsi_get_prot_op(sc), guard_type);
+                               "9063 BLKGRD: Bad op/guard:%d/IP combination\n",
+                                       scsi_get_prot_op(sc));
                        ret = 1;
                        break;
 
                }
-       } else if (guard_type == SHOST_DIX_GUARD_CRC) {
+       } else {
                switch (scsi_get_prot_op(sc)) {
                case SCSI_PROT_READ_STRIP:
                case SCSI_PROT_WRITE_INSERT:
@@ -1324,17 +1324,18 @@ lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc,
 
                case SCSI_PROT_READ_INSERT:
                case SCSI_PROT_WRITE_STRIP:
+                       *txop = BG_OP_IN_CRC_OUT_NODIF;
+                       *rxop = BG_OP_IN_NODIF_OUT_CRC;
+                       break;
+
                case SCSI_PROT_NORMAL:
                default:
                        lpfc_printf_log(phba, KERN_ERR, LOG_BG,
-                               "9075 BLKGRD: Bad op/guard:%d/%d combination\n",
-                                       scsi_get_prot_op(sc), guard_type);
+                               "9075 BLKGRD: Bad op/guard:%d/CRC combination\n",
+                                       scsi_get_prot_op(sc));
                        ret = 1;
                        break;
                }
-       } else {
-               /* unsupported format */
-               BUG();
        }
 
        return ret;
@@ -1352,45 +1353,6 @@ lpfc_cmd_blksize(struct scsi_cmnd *sc)
        return sc->device->sector_size;
 }
 
-/**
- * lpfc_get_cmd_dif_parms - Extract DIF parameters from SCSI command
- * @sc:             in: SCSI command
- * @apptagmask:     out: app tag mask
- * @apptagval:      out: app tag value
- * @reftag:         out: ref tag (reference tag)
- *
- * Description:
- *   Extract DIF parameters from the command if possible.  Otherwise,
- *   use default parameters.
- *
- **/
-static inline void
-lpfc_get_cmd_dif_parms(struct scsi_cmnd *sc, uint16_t *apptagmask,
-               uint16_t *apptagval, uint32_t *reftag)
-{
-       struct  scsi_dif_tuple *spt;
-       unsigned char op = scsi_get_prot_op(sc);
-       unsigned int protcnt = scsi_prot_sg_count(sc);
-       static int cnt;
-
-       if (protcnt && (op == SCSI_PROT_WRITE_STRIP ||
-                               op == SCSI_PROT_WRITE_PASS)) {
-
-               cnt++;
-               spt = page_address(sg_page(scsi_prot_sglist(sc))) +
-                       scsi_prot_sglist(sc)[0].offset;
-               *apptagmask = 0;
-               *apptagval = 0;
-               *reftag = cpu_to_be32(spt->ref_tag);
-
-       } else {
-               /* SBC defines ref tag to be lower 32bits of LBA */
-               *reftag = (uint32_t) (0xffffffff & scsi_get_lba(sc));
-               *apptagmask = 0;
-               *apptagval = 0;
-       }
-}
-
 /*
  * This function sets up buffer list for protection groups of
  * type LPFC_PG_TYPE_NO_DIF
@@ -1427,9 +1389,8 @@ 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;
-       unsigned blksize;
        uint32_t reftag;
-       uint16_t apptagmask, apptagval;
+       unsigned blksize;
        uint8_t txop, rxop;
 
        status  = lpfc_sc_to_bg_opcodes(phba, sc, &txop, &rxop);
@@ -1438,17 +1399,16 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
 
        /* extract some info from the scsi command for pde*/
        blksize = lpfc_cmd_blksize(sc);
-       lpfc_get_cmd_dif_parms(sc, &apptagmask, &apptagval, &reftag);
+       reftag = scsi_get_lba(sc) & 0xffffffff;
 
        /* setup PDE5 with what we have */
        pde5 = (struct lpfc_pde5 *) bpl;
        memset(pde5, 0, sizeof(struct lpfc_pde5));
        bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR);
-       pde5->reftag = reftag;
 
        /* Endianness conversion if necessary for PDE5 */
        pde5->word0 = cpu_to_le32(pde5->word0);
-       pde5->reftag = cpu_to_le32(pde5->reftag);
+       pde5->reftag = cpu_to_le32(reftag);
 
        /* advance bpl and increment bde count */
        num_bde++;
@@ -1463,10 +1423,10 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
        if (datadir == DMA_FROM_DEVICE) {
                bf_set(pde6_ce, pde6, 1);
                bf_set(pde6_re, pde6, 1);
-               bf_set(pde6_ae, pde6, 1);
        }
        bf_set(pde6_ai, pde6, 1);
-       bf_set(pde6_apptagval, pde6, apptagval);
+       bf_set(pde6_ae, pde6, 0);
+       bf_set(pde6_apptagval, pde6, 0);
 
        /* Endianness conversion if necessary for PDE6 */
        pde6->word0 = cpu_to_le32(pde6->word0);
@@ -1551,7 +1511,6 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
        unsigned char pgdone = 0, alldone = 0;
        unsigned blksize;
        uint32_t reftag;
-       uint16_t apptagmask, apptagval;
        uint8_t txop, rxop;
        int num_bde = 0;
 
@@ -1571,7 +1530,7 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
 
        /* extract some info from the scsi command */
        blksize = lpfc_cmd_blksize(sc);
-       lpfc_get_cmd_dif_parms(sc, &apptagmask, &apptagval, &reftag);
+       reftag = scsi_get_lba(sc) & 0xffffffff;
 
        split_offset = 0;
        do {
@@ -1579,11 +1538,10 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
                pde5 = (struct lpfc_pde5 *) bpl;
                memset(pde5, 0, sizeof(struct lpfc_pde5));
                bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR);
-               pde5->reftag = reftag;
 
                /* Endianness conversion if necessary for PDE5 */
                pde5->word0 = cpu_to_le32(pde5->word0);
-               pde5->reftag = cpu_to_le32(pde5->reftag);
+               pde5->reftag = cpu_to_le32(reftag);
 
                /* advance bpl and increment bde count */
                num_bde++;
@@ -1597,9 +1555,9 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
                bf_set(pde6_oprx, pde6, rxop);
                bf_set(pde6_ce, pde6, 1);
                bf_set(pde6_re, pde6, 1);
-               bf_set(pde6_ae, pde6, 1);
                bf_set(pde6_ai, pde6, 1);
-               bf_set(pde6_apptagval, pde6, apptagval);
+               bf_set(pde6_ae, pde6, 0);
+               bf_set(pde6_apptagval, pde6, 0);
 
                /* Endianness conversion if necessary for PDE6 */
                pde6->word0 = cpu_to_le32(pde6->word0);
@@ -1621,8 +1579,8 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
                memset(pde7, 0, sizeof(struct lpfc_pde7));
                bf_set(pde7_type, pde7, LPFC_PDE7_DESCRIPTOR);
 
-               pde7->addrHigh = le32_to_cpu(putPaddrLow(protphysaddr));
-               pde7->addrLow = le32_to_cpu(putPaddrHigh(protphysaddr));
+               pde7->addrHigh = le32_to_cpu(putPaddrHigh(protphysaddr));
+               pde7->addrLow = le32_to_cpu(putPaddrLow(protphysaddr));
 
                protgrp_blks = protgroup_len / 8;
                protgrp_bytes = protgrp_blks * blksize;
@@ -1632,7 +1590,7 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
                        protgroup_remainder = 0x1000 - (pde7->addrLow & 0xfff);
                        protgroup_offset += protgroup_remainder;
                        protgrp_blks = protgroup_remainder / 8;
-                       protgrp_bytes = protgroup_remainder * blksize;
+                       protgrp_bytes = protgrp_blks * blksize;
                } else {
                        protgroup_offset = 0;
                        curr_prot++;
@@ -2006,16 +1964,21 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd,
        if (lpfc_bgs_get_hi_water_mark_present(bgstat)) {
                /*
                 * setup sense data descriptor 0 per SPC-4 as an information
-                * field, and put the failing LBA in it
+                * field, and put the failing LBA in it.
+                * This code assumes there was also a guard/app/ref tag error
+                * indication.
                 */
-               cmd->sense_buffer[8] = 0;     /* Information */
-               cmd->sense_buffer[9] = 0xa;   /* Add. length */
+               cmd->sense_buffer[7] = 0xc;   /* Additional sense length */
+               cmd->sense_buffer[8] = 0;     /* Information descriptor type */
+               cmd->sense_buffer[9] = 0xa;   /* Additional descriptor length */
+               cmd->sense_buffer[10] = 0x80; /* Validity bit */
                bghm /= cmd->device->sector_size;
 
                failing_sector = scsi_get_lba(cmd);
                failing_sector += bghm;
 
-               put_unaligned_be64(failing_sector, &cmd->sense_buffer[10]);
+               /* Descriptor Information */
+               put_unaligned_be64(failing_sector, &cmd->sense_buffer[12]);
        }
 
        if (!ret) {
index 98999bb..8b799f0 100644 (file)
@@ -560,7 +560,7 @@ __lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
        rrq = mempool_alloc(phba->rrq_pool, GFP_KERNEL);
        if (rrq) {
                rrq->send_rrq = send_rrq;
-               rrq->xritag = phba->sli4_hba.xri_ids[xritag];
+               rrq->xritag = xritag;
                rrq->rrq_stop_time = jiffies + HZ * (phba->fc_ratov + 1);
                rrq->ndlp = ndlp;
                rrq->nlp_DID = ndlp->nlp_DID;
@@ -2452,7 +2452,8 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 
                /* search continue save q for same XRI */
                list_for_each_entry(iocbq, &pring->iocb_continue_saveq, clist) {
-                       if (iocbq->iocb.ulpContext == saveq->iocb.ulpContext) {
+                       if (iocbq->iocb.unsli3.rcvsli3.ox_id ==
+                               saveq->iocb.unsli3.rcvsli3.ox_id) {
                                list_add_tail(&saveq->list, &iocbq->list);
                                found = 1;
                                break;
@@ -3355,6 +3356,7 @@ lpfc_sli_handle_slow_ring_event_s4(struct lpfc_hba *phba,
                                                           irspiocbq);
                        break;
                case CQE_CODE_RECEIVE:
+               case CQE_CODE_RECEIVE_V1:
                        dmabuf = container_of(cq_event, struct hbq_dmabuf,
                                              cq_event);
                        lpfc_sli4_handle_received_buffer(phba, dmabuf);
@@ -4712,10 +4714,15 @@ lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba)
  * lpfc_sli4_get_avail_extnt_rsrc - Get available resource extent count.
  * @phba: Pointer to HBA context object.
  * @type: The resource extent type.
+ * @extnt_count: buffer to hold port available extent count.
+ * @extnt_size: buffer to hold element count per extent.
  *
- * This function allocates all SLI4 resource identifiers.
+ * This function calls the port and retrievs the number of available
+ * extents and their size for a particular extent type.
+ *
+ * Returns: 0 if successful.  Nonzero otherwise.
  **/
-static int
+int
 lpfc_sli4_get_avail_extnt_rsrc(struct lpfc_hba *phba, uint16_t type,
                               uint16_t *extnt_count, uint16_t *extnt_size)
 {
@@ -4892,7 +4899,7 @@ lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t *extnt_cnt,
                                     req_len, *emb);
        if (alloc_len < req_len) {
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                       "9000 Allocated DMA memory size (x%x) is "
+                       "2982 Allocated DMA memory size (x%x) is "
                        "less than the requested DMA memory "
                        "size (x%x)\n", alloc_len, req_len);
                return -ENOMEM;
@@ -5505,6 +5512,154 @@ lpfc_sli4_dealloc_resource_identifiers(struct lpfc_hba *phba)
        return 0;
 }
 
+/**
+ * lpfc_sli4_get_allocated_extnts - Get the port's allocated extents.
+ * @phba: Pointer to HBA context object.
+ * @type: The resource extent type.
+ * @extnt_count: buffer to hold port extent count response
+ * @extnt_size: buffer to hold port extent size response.
+ *
+ * This function calls the port to read the host allocated extents
+ * for a particular type.
+ **/
+int
+lpfc_sli4_get_allocated_extnts(struct lpfc_hba *phba, uint16_t type,
+                              uint16_t *extnt_cnt, uint16_t *extnt_size)
+{
+       bool emb;
+       int rc = 0;
+       uint16_t curr_blks = 0;
+       uint32_t req_len, emb_len;
+       uint32_t alloc_len, mbox_tmo;
+       struct list_head *blk_list_head;
+       struct lpfc_rsrc_blks *rsrc_blk;
+       LPFC_MBOXQ_t *mbox;
+       void *virtaddr = NULL;
+       struct lpfc_mbx_nembed_rsrc_extent *n_rsrc;
+       struct lpfc_mbx_alloc_rsrc_extents *rsrc_ext;
+       union  lpfc_sli4_cfg_shdr *shdr;
+
+       switch (type) {
+       case LPFC_RSC_TYPE_FCOE_VPI:
+               blk_list_head = &phba->lpfc_vpi_blk_list;
+               break;
+       case LPFC_RSC_TYPE_FCOE_XRI:
+               blk_list_head = &phba->sli4_hba.lpfc_xri_blk_list;
+               break;
+       case LPFC_RSC_TYPE_FCOE_VFI:
+               blk_list_head = &phba->sli4_hba.lpfc_vfi_blk_list;
+               break;
+       case LPFC_RSC_TYPE_FCOE_RPI:
+               blk_list_head = &phba->sli4_hba.lpfc_rpi_blk_list;
+               break;
+       default:
+               return -EIO;
+       }
+
+       /* Count the number of extents currently allocatd for this type. */
+       list_for_each_entry(rsrc_blk, blk_list_head, list) {
+               if (curr_blks == 0) {
+                       /*
+                        * The GET_ALLOCATED mailbox does not return the size,
+                        * just the count.  The size should be just the size
+                        * stored in the current allocated block and all sizes
+                        * for an extent type are the same so set the return
+                        * value now.
+                        */
+                       *extnt_size = rsrc_blk->rsrc_size;
+               }
+               curr_blks++;
+       }
+
+       /* Calculate the total requested length of the dma memory. */
+       req_len = curr_blks * sizeof(uint16_t);
+
+       /*
+        * Calculate the size of an embedded mailbox.  The uint32_t
+        * accounts for extents-specific word.
+        */
+       emb_len = sizeof(MAILBOX_t) - sizeof(struct mbox_header) -
+               sizeof(uint32_t);
+
+       /*
+        * Presume the allocation and response will fit into an embedded
+        * mailbox.  If not true, reconfigure to a non-embedded mailbox.
+        */
+       emb = LPFC_SLI4_MBX_EMBED;
+       req_len = emb_len;
+       if (req_len > emb_len) {
+               req_len = curr_blks * sizeof(uint16_t) +
+                       sizeof(union lpfc_sli4_cfg_shdr) +
+                       sizeof(uint32_t);
+               emb = LPFC_SLI4_MBX_NEMBED;
+       }
+
+       mbox = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox)
+               return -ENOMEM;
+       memset(mbox, 0, sizeof(LPFC_MBOXQ_t));
+
+       alloc_len = lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
+                                    LPFC_MBOX_OPCODE_GET_ALLOC_RSRC_EXTENT,
+                                    req_len, emb);
+       if (alloc_len < req_len) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                       "2983 Allocated DMA memory size (x%x) is "
+                       "less than the requested DMA memory "
+                       "size (x%x)\n", alloc_len, req_len);
+               rc = -ENOMEM;
+               goto err_exit;
+       }
+       rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, curr_blks, type, emb);
+       if (unlikely(rc)) {
+               rc = -EIO;
+               goto err_exit;
+       }
+
+       if (!phba->sli4_hba.intr_enable)
+               rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+       else {
+               mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG);
+               rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
+       }
+
+       if (unlikely(rc)) {
+               rc = -EIO;
+               goto err_exit;
+       }
+
+       /*
+        * Figure out where the response is located.  Then get local pointers
+        * to the response data.  The port does not guarantee to respond to
+        * all extents counts request so update the local variable with the
+        * allocated count from the port.
+        */
+       if (emb == LPFC_SLI4_MBX_EMBED) {
+               rsrc_ext = &mbox->u.mqe.un.alloc_rsrc_extents;
+               shdr = &rsrc_ext->header.cfg_shdr;
+               *extnt_cnt = bf_get(lpfc_mbx_rsrc_cnt, &rsrc_ext->u.rsp);
+       } else {
+               virtaddr = mbox->sge_array->addr[0];
+               n_rsrc = (struct lpfc_mbx_nembed_rsrc_extent *) virtaddr;
+               shdr = &n_rsrc->cfg_shdr;
+               *extnt_cnt = bf_get(lpfc_mbx_rsrc_cnt, n_rsrc);
+       }
+
+       if (bf_get(lpfc_mbox_hdr_status, &shdr->response)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT,
+                       "2984 Failed to read allocated resources "
+                       "for type %d - Status 0x%x Add'l Status 0x%x.\n",
+                       type,
+                       bf_get(lpfc_mbox_hdr_status, &shdr->response),
+                       bf_get(lpfc_mbox_hdr_add_status, &shdr->response));
+               rc = -EIO;
+               goto err_exit;
+       }
+ err_exit:
+       lpfc_sli4_mbox_cmd_free(phba, mbox);
+       return rc;
+}
+
 /**
  * lpfc_sli4_hba_setup - SLI4 device intialization PCI function
  * @phba: Pointer to HBA context object.
@@ -5837,6 +5992,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
                                        "Advanced Error Reporting (AER)\n");
                        phba->cfg_aer_support = 0;
                }
+               rc = 0;
        }
 
        if (!(phba->hba_flag & HBA_FCOE_MODE)) {
@@ -6634,6 +6790,9 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
        unsigned long iflags;
        int rc;
 
+       /* dump from issue mailbox command if setup */
+       lpfc_idiag_mbxacc_dump_issue_mbox(phba, &mboxq->u.mb);
+
        rc = lpfc_mbox_dev_check(phba);
        if (unlikely(rc)) {
                lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
@@ -7318,12 +7477,12 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                bf_set(wqe_qosd, &wqe->els_req.wqe_com, 1);
                bf_set(wqe_lenloc, &wqe->els_req.wqe_com, LPFC_WQE_LENLOC_NONE);
                bf_set(wqe_ebde_cnt, &wqe->els_req.wqe_com, 0);
-       break;
+               break;
        case CMD_XMIT_SEQUENCE64_CX:
                bf_set(wqe_ctxt_tag, &wqe->xmit_sequence.wqe_com,
                       iocbq->iocb.un.ulpWord[3]);
                bf_set(wqe_rcvoxid, &wqe->xmit_sequence.wqe_com,
-                      iocbq->iocb.ulpContext);
+                      iocbq->iocb.unsli3.rcvsli3.ox_id);
                /* The entire sequence is transmitted for this IOCB */
                xmit_len = total_len;
                cmnd = CMD_XMIT_SEQUENCE64_CR;
@@ -7341,7 +7500,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                bf_set(wqe_ebde_cnt, &wqe->xmit_sequence.wqe_com, 0);
                wqe->xmit_sequence.xmit_len = xmit_len;
                command_type = OTHER_COMMAND;
-       break;
+               break;
        case CMD_XMIT_BCAST64_CN:
                /* word3 iocb=iotag32 wqe=seq_payload_len */
                wqe->xmit_bcast64.seq_payload_len = xmit_len;
@@ -7355,7 +7514,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                bf_set(wqe_lenloc, &wqe->xmit_bcast64.wqe_com,
                       LPFC_WQE_LENLOC_WORD3);
                bf_set(wqe_ebde_cnt, &wqe->xmit_bcast64.wqe_com, 0);
-       break;
+               break;
        case CMD_FCP_IWRITE64_CR:
                command_type = FCP_COMMAND_DATA_OUT;
                /* word3 iocb=iotag wqe=payload_offset_len */
@@ -7375,7 +7534,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                       LPFC_WQE_LENLOC_WORD4);
                bf_set(wqe_ebde_cnt, &wqe->fcp_iwrite.wqe_com, 0);
                bf_set(wqe_pu, &wqe->fcp_iwrite.wqe_com, iocbq->iocb.ulpPU);
-       break;
+               break;
        case CMD_FCP_IREAD64_CR:
                /* word3 iocb=iotag wqe=payload_offset_len */
                /* Add the FCP_CMD and FCP_RSP sizes to get the offset */
@@ -7394,7 +7553,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                       LPFC_WQE_LENLOC_WORD4);
                bf_set(wqe_ebde_cnt, &wqe->fcp_iread.wqe_com, 0);
                bf_set(wqe_pu, &wqe->fcp_iread.wqe_com, iocbq->iocb.ulpPU);
-       break;
+               break;
        case CMD_FCP_ICMND64_CR:
                /* word3 iocb=IO_TAG wqe=reserved */
                wqe->fcp_icmd.rsrvd3 = 0;
@@ -7407,7 +7566,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                bf_set(wqe_lenloc, &wqe->fcp_icmd.wqe_com,
                       LPFC_WQE_LENLOC_NONE);
                bf_set(wqe_ebde_cnt, &wqe->fcp_icmd.wqe_com, 0);
-       break;
+               break;
        case CMD_GEN_REQUEST64_CR:
                /* For this command calculate the xmit length of the
                 * request bde.
@@ -7442,7 +7601,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                bf_set(wqe_lenloc, &wqe->gen_req.wqe_com, LPFC_WQE_LENLOC_NONE);
                bf_set(wqe_ebde_cnt, &wqe->gen_req.wqe_com, 0);
                command_type = OTHER_COMMAND;
-       break;
+               break;
        case CMD_XMIT_ELS_RSP64_CX:
                ndlp = (struct lpfc_nodelist *)iocbq->context1;
                /* words0-2 BDE memcpy */
@@ -7457,7 +7616,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                       ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l));
                bf_set(wqe_pu, &wqe->xmit_els_rsp.wqe_com, iocbq->iocb.ulpPU);
                bf_set(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com,
-                      iocbq->iocb.ulpContext);
+                      iocbq->iocb.unsli3.rcvsli3.ox_id);
                if (!iocbq->iocb.ulpCt_h && iocbq->iocb.ulpCt_l)
                        bf_set(wqe_ctxt_tag, &wqe->xmit_els_rsp.wqe_com,
                               phba->vpi_ids[iocbq->vport->vpi]);
@@ -7470,7 +7629,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                bf_set(wqe_rsp_temp_rpi, &wqe->xmit_els_rsp,
                       phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]);
                command_type = OTHER_COMMAND;
-       break;
+               break;
        case CMD_CLOSE_XRI_CN:
        case CMD_ABORT_XRI_CN:
        case CMD_ABORT_XRI_CX:
@@ -7509,7 +7668,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                cmnd = CMD_ABORT_XRI_CX;
                command_type = OTHER_COMMAND;
                xritag = 0;
-       break;
+               break;
        case CMD_XMIT_BLS_RSP64_CX:
                /* As BLS ABTS RSP WQE is very different from other WQEs,
                 * we re-construct this WQE here based on information in
@@ -7553,7 +7712,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                               bf_get(lpfc_rsn_code, &iocbq->iocb.un.bls_rsp));
                }
 
-       break;
+               break;
        case CMD_XRI_ABORTED_CX:
        case CMD_CREATE_XRI_CR: /* Do we expect to use this? */
        case CMD_IOCB_FCP_IBIDIR64_CR: /* bidirectional xfer */
@@ -7565,7 +7724,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                                "2014 Invalid command 0x%x\n",
                                iocbq->iocb.ulpCommand);
                return IOCB_ERROR;
-       break;
+               break;
        }
 
        bf_set(wqe_xri_tag, &wqe->generic.wqe_com, xritag);
@@ -10481,10 +10640,14 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe)
        struct lpfc_queue *hrq = phba->sli4_hba.hdr_rq;
        struct lpfc_queue *drq = phba->sli4_hba.dat_rq;
        struct hbq_dmabuf *dma_buf;
-       uint32_t status;
+       uint32_t status, rq_id;
        unsigned long iflags;
 
-       if (bf_get(lpfc_rcqe_rq_id, rcqe) != hrq->queue_id)
+       if (bf_get(lpfc_cqe_code, rcqe) == CQE_CODE_RECEIVE_V1)
+               rq_id = bf_get(lpfc_rcqe_rq_id_v1, rcqe);
+       else
+               rq_id = bf_get(lpfc_rcqe_rq_id, rcqe);
+       if (rq_id != hrq->queue_id)
                goto out;
 
        status = bf_get(lpfc_rcqe_status, rcqe);
@@ -10563,6 +10726,7 @@ lpfc_sli4_sp_handle_cqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
                                (struct sli4_wcqe_xri_aborted *)&cqevt);
                break;
        case CQE_CODE_RECEIVE:
+       case CQE_CODE_RECEIVE_V1:
                /* Process the RQ event */
                phba->last_completion_time = jiffies;
                workposted = lpfc_sli4_sp_handle_rcqe(phba,
@@ -12345,19 +12509,18 @@ lpfc_sli4_post_sgl(struct lpfc_hba *phba,
 }
 
 /**
- * lpfc_sli4_init_rpi_hdrs - Post the rpi header memory region to the port
+ * lpfc_sli4_alloc_xri - Get an available rpi in the device's range
  * @phba: pointer to lpfc hba data structure.
  *
  * This routine is invoked to post rpi header templates to the
- * port for those SLI4 ports that do not support extents.  This routine
- * posts a PAGE_SIZE memory region to the port to hold up to
- * PAGE_SIZE modulo 64 rpi context headers.  This is an initialization routine
- * and should be called only when interrupts are disabled.
+ * HBA consistent with the SLI-4 interface spec.  This routine
+ * posts a SLI4_PAGE_SIZE memory region to the port to hold up to
+ * SLI4_PAGE_SIZE modulo 64 rpi context headers.
  *
- * Return codes
- *     0 - successful
- *     -ERROR - otherwise.
- */
+ * Returns
+ *     A nonzero rpi defined as rpi_base <= rpi < max_rpi if successful
+ *     LPFC_RPI_ALLOC_ERROR if no rpis are available.
+ **/
 uint16_t
 lpfc_sli4_alloc_xri(struct lpfc_hba *phba)
 {
@@ -13406,7 +13569,7 @@ lpfc_sli4_seq_abort_rsp_cmpl(struct lpfc_hba *phba,
  * This function validates the xri maps to the known range of XRIs allocated an
  * used by the driver.
  **/
-static uint16_t
+uint16_t
 lpfc_sli4_xri_inrange(struct lpfc_hba *phba,
                      uint16_t xri)
 {
@@ -13643,10 +13806,12 @@ lpfc_seq_complete(struct hbq_dmabuf *dmabuf)
 static struct lpfc_iocbq *
 lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
 {
+       struct hbq_dmabuf *hbq_buf;
        struct lpfc_dmabuf *d_buf, *n_buf;
        struct lpfc_iocbq *first_iocbq, *iocbq;
        struct fc_frame_header *fc_hdr;
        uint32_t sid;
+       uint32_t len, tot_len;
        struct ulp_bde64 *pbde;
 
        fc_hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt;
@@ -13655,6 +13820,7 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
        lpfc_update_rcv_time_stamp(vport);
        /* get the Remote Port's SID */
        sid = sli4_sid_from_fc_hdr(fc_hdr);
+       tot_len = 0;
        /* Get an iocbq struct to fill in. */
        first_iocbq = lpfc_sli_get_iocbq(vport->phba);
        if (first_iocbq) {
@@ -13662,9 +13828,12 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
                first_iocbq->iocb.unsli3.rcvsli3.acc_len = 0;
                first_iocbq->iocb.ulpStatus = IOSTAT_SUCCESS;
                first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_SEQ64_CX;
-               first_iocbq->iocb.ulpContext = be16_to_cpu(fc_hdr->fh_ox_id);
-               /* iocbq is prepped for internal consumption.  Logical vpi. */
-               first_iocbq->iocb.unsli3.rcvsli3.vpi = vport->vpi;
+               first_iocbq->iocb.ulpContext = NO_XRI;
+               first_iocbq->iocb.unsli3.rcvsli3.ox_id =
+                       be16_to_cpu(fc_hdr->fh_ox_id);
+               /* iocbq is prepped for internal consumption.  Physical vpi. */
+               first_iocbq->iocb.unsli3.rcvsli3.vpi =
+                       vport->phba->vpi_ids[vport->vpi];
                /* put the first buffer into the first IOCBq */
                first_iocbq->context2 = &seq_dmabuf->dbuf;
                first_iocbq->context3 = NULL;
@@ -13672,9 +13841,9 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
                first_iocbq->iocb.un.cont64[0].tus.f.bdeSize =
                                                        LPFC_DATA_BUF_SIZE;
                first_iocbq->iocb.un.rcvels.remoteID = sid;
-               first_iocbq->iocb.unsli3.rcvsli3.acc_len +=
-                               bf_get(lpfc_rcqe_length,
+               tot_len = bf_get(lpfc_rcqe_length,
                                       &seq_dmabuf->cq_event.cqe.rcqe_cmpl);
+               first_iocbq->iocb.unsli3.rcvsli3.acc_len = tot_len;
        }
        iocbq = first_iocbq;
        /*
@@ -13692,9 +13861,13 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
                        pbde = (struct ulp_bde64 *)
                                        &iocbq->iocb.unsli3.sli3Words[4];
                        pbde->tus.f.bdeSize = LPFC_DATA_BUF_SIZE;
-                       first_iocbq->iocb.unsli3.rcvsli3.acc_len +=
-                               bf_get(lpfc_rcqe_length,
-                                      &seq_dmabuf->cq_event.cqe.rcqe_cmpl);
+
+                       /* We need to get the size out of the right CQE */
+                       hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
+                       len = bf_get(lpfc_rcqe_length,
+                                      &hbq_buf->cq_event.cqe.rcqe_cmpl);
+                       iocbq->iocb.unsli3.rcvsli3.acc_len += len;
+                       tot_len += len;
                } else {
                        iocbq = lpfc_sli_get_iocbq(vport->phba);
                        if (!iocbq) {
@@ -13712,9 +13885,14 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
                        iocbq->iocb.ulpBdeCount = 1;
                        iocbq->iocb.un.cont64[0].tus.f.bdeSize =
                                                        LPFC_DATA_BUF_SIZE;
-                       first_iocbq->iocb.unsli3.rcvsli3.acc_len +=
-                               bf_get(lpfc_rcqe_length,
-                                      &seq_dmabuf->cq_event.cqe.rcqe_cmpl);
+
+                       /* We need to get the size out of the right CQE */
+                       hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
+                       len = bf_get(lpfc_rcqe_length,
+                                      &hbq_buf->cq_event.cqe.rcqe_cmpl);
+                       tot_len += len;
+                       iocbq->iocb.unsli3.rcvsli3.acc_len = tot_len;
+
                        iocbq->iocb.un.rcvels.remoteID = sid;
                        list_add_tail(&iocbq->list, &first_iocbq->list);
                }
@@ -13787,7 +13965,13 @@ lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba,
                lpfc_in_buf_free(phba, &dmabuf->dbuf);
                return;
        }
-       fcfi = bf_get(lpfc_rcqe_fcf_id, &dmabuf->cq_event.cqe.rcqe_cmpl);
+       if ((bf_get(lpfc_cqe_code,
+                   &dmabuf->cq_event.cqe.rcqe_cmpl) == CQE_CODE_RECEIVE_V1))
+               fcfi = bf_get(lpfc_rcqe_fcf_id_v1,
+                             &dmabuf->cq_event.cqe.rcqe_cmpl);
+       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)) {
                /* throw out the frame */
@@ -14450,6 +14634,92 @@ fail_fcf_read:
        return error;
 }
 
+/**
+ * lpfc_check_next_fcf_pri
+ * phba pointer to the lpfc_hba struct for this port.
+ * This routine is called from the lpfc_sli4_fcf_rr_next_index_get
+ * routine when the rr_bmask is empty. The FCF indecies are put into the
+ * rr_bmask based on their priority level. Starting from the highest priority
+ * to the lowest. The most likely FCF candidate will be in the highest
+ * priority group. When this routine is called it searches the fcf_pri list for
+ * next lowest priority group and repopulates the rr_bmask with only those
+ * fcf_indexes.
+ * returns:
+ * 1=success 0=failure
+ **/
+int
+lpfc_check_next_fcf_pri_level(struct lpfc_hba *phba)
+{
+       uint16_t next_fcf_pri;
+       uint16_t last_index;
+       struct lpfc_fcf_pri *fcf_pri;
+       int rc;
+       int ret = 0;
+
+       last_index = find_first_bit(phba->fcf.fcf_rr_bmask,
+                       LPFC_SLI4_FCF_TBL_INDX_MAX);
+       lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+                       "3060 Last IDX %d\n", last_index);
+       if (list_empty(&phba->fcf.fcf_pri_list)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
+                       "3061 Last IDX %d\n", last_index);
+               return 0; /* Empty rr list */
+       }
+       next_fcf_pri = 0;
+       /*
+        * Clear the rr_bmask and set all of the bits that are at this
+        * priority.
+        */
+       memset(phba->fcf.fcf_rr_bmask, 0,
+                       sizeof(*phba->fcf.fcf_rr_bmask));
+       spin_lock_irq(&phba->hbalock);
+       list_for_each_entry(fcf_pri, &phba->fcf.fcf_pri_list, list) {
+               if (fcf_pri->fcf_rec.flag & LPFC_FCF_FLOGI_FAILED)
+                       continue;
+               /*
+                * the 1st priority that has not FLOGI failed
+                * will be the highest.
+                */
+               if (!next_fcf_pri)
+                       next_fcf_pri = fcf_pri->fcf_rec.priority;
+               spin_unlock_irq(&phba->hbalock);
+               if (fcf_pri->fcf_rec.priority == next_fcf_pri) {
+                       rc = lpfc_sli4_fcf_rr_index_set(phba,
+                                               fcf_pri->fcf_rec.fcf_index);
+                       if (rc)
+                               return 0;
+               }
+               spin_lock_irq(&phba->hbalock);
+       }
+       /*
+        * if next_fcf_pri was not set above and the list is not empty then
+        * we have failed flogis on all of them. So reset flogi failed
+        * and start at the begining.
+        */
+       if (!next_fcf_pri && !list_empty(&phba->fcf.fcf_pri_list)) {
+               list_for_each_entry(fcf_pri, &phba->fcf.fcf_pri_list, list) {
+                       fcf_pri->fcf_rec.flag &= ~LPFC_FCF_FLOGI_FAILED;
+                       /*
+                        * the 1st priority that has not FLOGI failed
+                        * will be the highest.
+                        */
+                       if (!next_fcf_pri)
+                               next_fcf_pri = fcf_pri->fcf_rec.priority;
+                       spin_unlock_irq(&phba->hbalock);
+                       if (fcf_pri->fcf_rec.priority == next_fcf_pri) {
+                               rc = lpfc_sli4_fcf_rr_index_set(phba,
+                                               fcf_pri->fcf_rec.fcf_index);
+                               if (rc)
+                                       return 0;
+                       }
+                       spin_lock_irq(&phba->hbalock);
+               }
+       } else
+               ret = 1;
+       spin_unlock_irq(&phba->hbalock);
+
+       return ret;
+}
 /**
  * lpfc_sli4_fcf_rr_next_index_get - Get next eligible fcf record index
  * @phba: pointer to lpfc hba data structure.
@@ -14466,6 +14736,7 @@ lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba)
        uint16_t next_fcf_index;
 
        /* Search start from next bit of currently registered FCF index */
+next_priority:
        next_fcf_index = (phba->fcf.current_rec.fcf_indx + 1) %
                                        LPFC_SLI4_FCF_TBL_INDX_MAX;
        next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask,
@@ -14473,17 +14744,46 @@ lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba)
                                       next_fcf_index);
 
        /* Wrap around condition on phba->fcf.fcf_rr_bmask */
-       if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX)
+       if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
+               /*
+                * If we have wrapped then we need to clear the bits that
+                * have been tested so that we can detect when we should
+                * change the priority level.
+                */
                next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask,
                                               LPFC_SLI4_FCF_TBL_INDX_MAX, 0);
+       }
+
 
        /* Check roundrobin failover list empty condition */
-       if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
+       if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX ||
+               next_fcf_index == phba->fcf.current_rec.fcf_indx) {
+               /*
+                * If next fcf index is not found check if there are lower
+                * Priority level fcf's in the fcf_priority list.
+                * Set up the rr_bmask with all of the avaiable fcf bits
+                * at that level and continue the selection process.
+                */
+               if (lpfc_check_next_fcf_pri_level(phba))
+                       goto next_priority;
                lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
                                "2844 No roundrobin failover FCF available\n");
-               return LPFC_FCOE_FCF_NEXT_NONE;
+               if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX)
+                       return LPFC_FCOE_FCF_NEXT_NONE;
+               else {
+                       lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
+                               "3063 Only FCF available idx %d, flag %x\n",
+                               next_fcf_index,
+                       phba->fcf.fcf_pri[next_fcf_index].fcf_rec.flag);
+                       return next_fcf_index;
+               }
        }
 
+       if (next_fcf_index < LPFC_SLI4_FCF_TBL_INDX_MAX &&
+               phba->fcf.fcf_pri[next_fcf_index].fcf_rec.flag &
+               LPFC_FCF_FLOGI_FAILED)
+               goto next_priority;
+
        lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
                        "2845 Get next roundrobin failover FCF (x%x)\n",
                        next_fcf_index);
@@ -14535,6 +14835,7 @@ lpfc_sli4_fcf_rr_index_set(struct lpfc_hba *phba, uint16_t fcf_index)
 void
 lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *phba, uint16_t fcf_index)
 {
+       struct lpfc_fcf_pri *fcf_pri;
        if (fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
                lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
                                "2762 FCF (x%x) reached driver's book "
@@ -14543,6 +14844,14 @@ lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *phba, uint16_t fcf_index)
                return;
        }
        /* Clear the eligible FCF record index bmask */
+       spin_lock_irq(&phba->hbalock);
+       list_for_each_entry(fcf_pri, &phba->fcf.fcf_pri_list, list) {
+               if (fcf_pri->fcf_rec.fcf_index == fcf_index) {
+                       list_del_init(&fcf_pri->list);
+                       break;
+               }
+       }
+       spin_unlock_irq(&phba->hbalock);
        clear_bit(fcf_index, phba->fcf.fcf_rr_bmask);
 
        lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
index 4b17035..19bb87a 100644 (file)
@@ -81,6 +81,8 @@
         (fc_hdr)->fh_f_ctl[1] <<  8 | \
         (fc_hdr)->fh_f_ctl[2])
 
+#define LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT 12000
+
 enum lpfc_sli4_queue_type {
        LPFC_EQ,
        LPFC_GCQ,
@@ -157,6 +159,25 @@ struct lpfc_fcf_rec {
 #define RECORD_VALID   0x02
 };
 
+struct lpfc_fcf_pri_rec {
+       uint16_t fcf_index;
+#define LPFC_FCF_ON_PRI_LIST 0x0001
+#define LPFC_FCF_FLOGI_FAILED 0x0002
+       uint16_t flag;
+       uint32_t priority;
+};
+
+struct lpfc_fcf_pri {
+       struct list_head list;
+       struct lpfc_fcf_pri_rec fcf_rec;
+};
+
+/*
+ * Maximum FCF table index, it is for driver internal book keeping, it
+ * just needs to be no less than the supported HBA's FCF table size.
+ */
+#define LPFC_SLI4_FCF_TBL_INDX_MAX     32
+
 struct lpfc_fcf {
        uint16_t fcfi;
        uint32_t fcf_flag;
@@ -176,15 +197,13 @@ struct lpfc_fcf {
        uint32_t eligible_fcf_cnt;
        struct lpfc_fcf_rec current_rec;
        struct lpfc_fcf_rec failover_rec;
+       struct list_head fcf_pri_list;
+       struct lpfc_fcf_pri fcf_pri[LPFC_SLI4_FCF_TBL_INDX_MAX];
+       uint32_t current_fcf_scan_pri;
        struct timer_list redisc_wait;
        unsigned long *fcf_rr_bmask; /* Eligible FCF indexes for RR failover */
 };
 
-/*
- * Maximum FCF table index, it is for driver internal book keeping, it
- * just needs to be no less than the supported HBA's FCF table size.
- */
-#define LPFC_SLI4_FCF_TBL_INDX_MAX     32
 
 #define LPFC_REGION23_SIGNATURE "RG23"
 #define LPFC_REGION23_VERSION  1
index c03921b..c1e0ae9 100644 (file)
@@ -18,7 +18,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "8.3.23"
+#define LPFC_DRIVER_VERSION "8.3.25"
 #define LPFC_DRIVER_NAME               "lpfc"
 #define LPFC_SP_DRIVER_HANDLER_NAME    "lpfc:sp"
 #define LPFC_FP_DRIVER_HANDLER_NAME    "lpfc:fp"
index 7370c08..3948a00 100644 (file)
@@ -33,9 +33,9 @@
 /*
  * MegaRAID SAS Driver meta data
  */
-#define MEGASAS_VERSION                                "00.00.05.38-rc1"
-#define MEGASAS_RELDATE                                "May. 11, 2011"
-#define MEGASAS_EXT_VERSION                    "Wed. May. 11 17:00:00 PDT 2011"
+#define MEGASAS_VERSION                                "00.00.05.40-rc1"
+#define MEGASAS_RELDATE                                "Jul. 26, 2011"
+#define MEGASAS_EXT_VERSION                    "Tue. Jul. 26 17:00:00 PDT 2011"
 
 /*
  * Device IDs
index 2d8cdce..776d019 100644 (file)
@@ -18,7 +18,7 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  *  FILE: megaraid_sas_base.c
- *  Version : v00.00.05.38-rc1
+ *  Version : v00.00.05.40-rc1
  *
  *  Authors: LSI Corporation
  *           Sreenivas Bagalkote
@@ -54,6 +54,7 @@
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
 #include "megaraid_sas_fusion.h"
 #include "megaraid_sas.h"
 
@@ -2057,6 +2058,20 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
        }
 }
 
+static int megasas_change_queue_depth(struct scsi_device *sdev,
+                                     int queue_depth, int reason)
+{
+       if (reason != SCSI_QDEPTH_DEFAULT)
+               return -EOPNOTSUPP;
+
+       if (queue_depth > sdev->host->can_queue)
+               queue_depth = sdev->host->can_queue;
+       scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev),
+                               queue_depth);
+
+       return queue_depth;
+}
+
 /*
  * Scsi host template for megaraid_sas driver
  */
@@ -2074,6 +2089,7 @@ static struct scsi_host_template megasas_template = {
        .eh_timed_out = megasas_reset_timer,
        .bios_param = megasas_bios_param,
        .use_clustering = ENABLE_CLUSTERING,
+       .change_queue_depth = megasas_change_queue_depth,
 };
 
 /**
index 8fe3a45..5a5af1f 100644 (file)
@@ -288,7 +288,6 @@ u8 MR_GetPhyParams(u32 ld, u64 stripRow, u16 stripRef, u64 *pdBlock,
                                /* Get dev handle from Pd */
                                *pDevHandle = MR_PdDevHandleGet(pd, map);
                }
-               retval = FALSE;
        }
 
        *pdBlock += stripRef + MR_LdSpanPtrGet(ld, span, map)->startBlk;
index 939f283..6abd2fc 100644 (file)
@@ -4258,6 +4258,7 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
        u32 log_info;
        struct MPT2SAS_DEVICE *sas_device_priv_data;
        u32 response_code = 0;
+       unsigned long flags;
 
        mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
        scmd = _scsih_scsi_lookup_get_clear(ioc, smid);
@@ -4282,6 +4283,9 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
         * the failed direct I/O should be redirected to volume
         */
        if (_scsih_scsi_direct_io_get(ioc, smid)) {
+               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);
                memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
                mpi_request->DevHandle =
index c82b012..78f7e20 100644 (file)
@@ -3,7 +3,7 @@
 #
 # Copyright 2007 Red Hat, Inc.
 # Copyright 2008 Marvell. <kewei@marvell.com>
-# Copyright 2009-20011 Marvell. <yuxiangl@marvell.com>
+# Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
 #
 # This file is licensed under GPLv2.
 #
@@ -41,3 +41,10 @@ config SCSI_MVSAS_DEBUG
        help
                Compiles the 88SE64XX/88SE94XX driver in debug mode.  In debug mode,
                the driver prints some messages to the console.
+config SCSI_MVSAS_TASKLET
+       bool "Support for interrupt tasklet"
+       default n
+       depends on SCSI_MVSAS
+       help
+               Compiles the 88SE64xx/88SE94xx driver in interrupt tasklet mode.In this mode,
+               the interrupt will schedule a tasklet.
index 13c9604..8ba4722 100644 (file)
@@ -33,7 +33,6 @@ static void mvs_64xx_detect_porttype(struct mvs_info *mvi, int i)
        u32 reg;
        struct mvs_phy *phy = &mvi->phy[i];
 
-       /* TODO check & save device type */
        reg = mr32(MVS_GBL_PORT_TYPE);
        phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
        if (reg & MODE_SAS_SATA & (1 << i))
@@ -48,7 +47,7 @@ static void __devinit mvs_64xx_enable_xmt(struct mvs_info *mvi, int phy_id)
        u32 tmp;
 
        tmp = mr32(MVS_PCS);
-       if (mvi->chip->n_phy <= 4)
+       if (mvi->chip->n_phy <= MVS_SOC_PORTS)
                tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT);
        else
                tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT2);
@@ -58,24 +57,16 @@ static void __devinit mvs_64xx_enable_xmt(struct mvs_info *mvi, int phy_id)
 static void __devinit mvs_64xx_phy_hacks(struct mvs_info *mvi)
 {
        void __iomem *regs = mvi->regs;
+       int i;
 
        mvs_phy_hacks(mvi);
 
        if (!(mvi->flags & MVF_FLAG_SOC)) {
-               /* TEST - for phy decoding error, adjust voltage levels */
-               mw32(MVS_P0_VSR_ADDR + 0, 0x8);
-               mw32(MVS_P0_VSR_DATA + 0, 0x2F0);
-
-               mw32(MVS_P0_VSR_ADDR + 8, 0x8);
-               mw32(MVS_P0_VSR_DATA + 8, 0x2F0);
-
-               mw32(MVS_P0_VSR_ADDR + 16, 0x8);
-               mw32(MVS_P0_VSR_DATA + 16, 0x2F0);
-
-               mw32(MVS_P0_VSR_ADDR + 24, 0x8);
-               mw32(MVS_P0_VSR_DATA + 24, 0x2F0);
+               for (i = 0; i < MVS_SOC_PORTS; i++) {
+                       mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE8);
+                       mvs_write_port_vsr_data(mvi, i, 0x2F0);
+               }
        } else {
-               int i;
                /* disable auto port detection */
                mw32(MVS_GBL_PORT_TYPE, 0);
                for (i = 0; i < mvi->chip->n_phy; i++) {
@@ -95,7 +86,7 @@ static void mvs_64xx_stp_reset(struct mvs_info *mvi, u32 phy_id)
        u32 reg, tmp;
 
        if (!(mvi->flags & MVF_FLAG_SOC)) {
-               if (phy_id < 4)
+               if (phy_id < MVS_SOC_PORTS)
                        pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &reg);
                else
                        pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &reg);
@@ -104,13 +95,13 @@ static void mvs_64xx_stp_reset(struct mvs_info *mvi, u32 phy_id)
                reg = mr32(MVS_PHY_CTL);
 
        tmp = reg;
-       if (phy_id < 4)
+       if (phy_id < MVS_SOC_PORTS)
                tmp |= (1U << phy_id) << PCTL_LINK_OFFS;
        else
-               tmp |= (1U << (phy_id - 4)) << PCTL_LINK_OFFS;
+               tmp |= (1U << (phy_id - MVS_SOC_PORTS)) << PCTL_LINK_OFFS;
 
        if (!(mvi->flags & MVF_FLAG_SOC)) {
-               if (phy_id < 4) {
+               if (phy_id < MVS_SOC_PORTS) {
                        pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp);
                        mdelay(10);
                        pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, reg);
@@ -133,9 +124,9 @@ static void mvs_64xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard)
        tmp &= ~PHYEV_RDY_CH;
        mvs_write_port_irq_stat(mvi, phy_id, tmp);
        tmp = mvs_read_phy_ctl(mvi, phy_id);
-       if (hard == 1)
+       if (hard == MVS_HARD_RESET)
                tmp |= PHY_RST_HARD;
-       else if (hard == 0)
+       else if (hard == MVS_SOFT_RESET)
                tmp |= PHY_RST;
        mvs_write_phy_ctl(mvi, phy_id, tmp);
        if (hard) {
@@ -321,6 +312,11 @@ static int __devinit mvs_64xx_init(struct mvs_info *mvi)
        /* init phys */
        mvs_64xx_phy_hacks(mvi);
 
+       tmp = mvs_cr32(mvi, CMD_PHY_MODE_21);
+       tmp &= 0x0000ffff;
+       tmp |= 0x00fa0000;
+       mvs_cw32(mvi, CMD_PHY_MODE_21, tmp);
+
        /* enable auto port detection */
        mw32(MVS_GBL_PORT_TYPE, MODE_AUTO_DET_EN);
 
@@ -346,7 +342,7 @@ static int __devinit mvs_64xx_init(struct mvs_info *mvi)
 
                mvs_64xx_enable_xmt(mvi, i);
 
-               mvs_64xx_phy_reset(mvi, i, 1);
+               mvs_64xx_phy_reset(mvi, i, MVS_HARD_RESET);
                msleep(500);
                mvs_64xx_detect_porttype(mvi, i);
        }
@@ -377,13 +373,7 @@ static int __devinit mvs_64xx_init(struct mvs_info *mvi)
                mvs_update_phyinfo(mvi, i, 1);
        }
 
-       /* FIXME: update wide port bitmaps */
-
        /* little endian for open address and command table, etc. */
-       /*
-        * it seems that ( from the spec ) turning on big-endian won't
-        * do us any good on big-endian machines, need further confirmation
-        */
        cctl = mr32(MVS_CTL);
        cctl |= CCTL_ENDIAN_CMD;
        cctl |= CCTL_ENDIAN_DATA;
@@ -394,15 +384,19 @@ static int __devinit mvs_64xx_init(struct mvs_info *mvi)
        /* reset CMD queue */
        tmp = mr32(MVS_PCS);
        tmp |= PCS_CMD_RST;
+       tmp &= ~PCS_SELF_CLEAR;
        mw32(MVS_PCS, tmp);
-       /* interrupt coalescing may cause missing HW interrput in some case,
-        * and the max count is 0x1ff, while our max slot is 0x200,
+       /*
+        * the max count is 0x1ff, while our max slot is 0x200,
         * it will make count 0.
         */
        tmp = 0;
-       mw32(MVS_INT_COAL, tmp);
+       if (MVS_CHIP_SLOT_SZ > 0x1ff)
+               mw32(MVS_INT_COAL, 0x1ff | COAL_EN);
+       else
+               mw32(MVS_INT_COAL, MVS_CHIP_SLOT_SZ | COAL_EN);
 
-       tmp = 0x100;
+       tmp = 0x10000 | interrupt_coalescing;
        mw32(MVS_INT_COAL_TMOUT, tmp);
 
        /* ladies and gentlemen, start your engines */
@@ -477,13 +471,11 @@ static irqreturn_t mvs_64xx_isr(struct mvs_info *mvi, int irq, u32 stat)
 
        /* clear CMD_CMPLT ASAP */
        mw32_f(MVS_INT_STAT, CINT_DONE);
-#ifndef MVS_USE_TASKLET
+
        spin_lock(&mvi->lock);
-#endif
        mvs_int_full(mvi);
-#ifndef MVS_USE_TASKLET
        spin_unlock(&mvi->lock);
-#endif
+
        return IRQ_HANDLED;
 }
 
@@ -630,7 +622,6 @@ static void mvs_64xx_phy_work_around(struct mvs_info *mvi, int i)
 {
        u32 tmp;
        struct mvs_phy *phy = &mvi->phy[i];
-       /* workaround for HW phy decoding error on 1.5g disk drive */
        mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE6);
        tmp = mvs_read_port_vsr_data(mvi, i);
        if (((phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
@@ -661,7 +652,7 @@ void mvs_64xx_phy_set_link_rate(struct mvs_info *mvi, u32 phy_id,
                tmp |= lrmax;
        }
        mvs_write_phy_ctl(mvi, phy_id, tmp);
-       mvs_64xx_phy_reset(mvi, phy_id, 1);
+       mvs_64xx_phy_reset(mvi, phy_id, MVS_HARD_RESET);
 }
 
 static void mvs_64xx_clear_active_cmds(struct mvs_info *mvi)
@@ -744,11 +735,13 @@ int mvs_64xx_spi_waitdataready(struct mvs_info *mvi, u32 timeout)
        return -1;
 }
 
-#ifndef DISABLE_HOTPLUG_DMA_FIX
-void mvs_64xx_fix_dma(dma_addr_t buf_dma, int buf_len, int from, void *prd)
+void mvs_64xx_fix_dma(struct mvs_info *mvi, u32 phy_mask,
+                               int buf_len, int from, void *prd)
 {
        int i;
        struct mvs_prd *buf_prd = prd;
+       dma_addr_t buf_dma = mvi->bulk_buffer_dma;
+
        buf_prd += from;
        for (i = 0; i < MAX_SG_ENTRY - from; i++) {
                buf_prd->addr = cpu_to_le64(buf_dma);
@@ -756,7 +749,28 @@ void mvs_64xx_fix_dma(dma_addr_t buf_dma, int buf_len, int from, void *prd)
                ++buf_prd;
        }
 }
-#endif
+
+static void mvs_64xx_tune_interrupt(struct mvs_info *mvi, u32 time)
+{
+       void __iomem *regs = mvi->regs;
+       u32 tmp = 0;
+       /*
+        * the max count is 0x1ff, while our max slot is 0x200,
+        * it will make count 0.
+        */
+       if (time == 0) {
+               mw32(MVS_INT_COAL, 0);
+               mw32(MVS_INT_COAL_TMOUT, 0x10000);
+       } else {
+               if (MVS_CHIP_SLOT_SZ > 0x1ff)
+                       mw32(MVS_INT_COAL, 0x1ff|COAL_EN);
+               else
+                       mw32(MVS_INT_COAL, MVS_CHIP_SLOT_SZ|COAL_EN);
+
+               tmp = 0x10000 | time;
+               mw32(MVS_INT_COAL_TMOUT, tmp);
+       }
+}
 
 const struct mvs_dispatch mvs_64xx_dispatch = {
        "mv64xx",
@@ -780,7 +794,6 @@ const struct mvs_dispatch mvs_64xx_dispatch = {
        mvs_write_port_irq_stat,
        mvs_read_port_irq_mask,
        mvs_write_port_irq_mask,
-       mvs_get_sas_addr,
        mvs_64xx_command_active,
        mvs_64xx_clear_srs_irq,
        mvs_64xx_issue_stop,
@@ -808,8 +821,8 @@ const struct mvs_dispatch mvs_64xx_dispatch = {
        mvs_64xx_spi_buildcmd,
        mvs_64xx_spi_issuecmd,
        mvs_64xx_spi_waitdataready,
-#ifndef DISABLE_HOTPLUG_DMA_FIX
        mvs_64xx_fix_dma,
-#endif
+       mvs_64xx_tune_interrupt,
+       NULL,
 };
 
index 78162c3..3501291 100644 (file)
@@ -48,6 +48,216 @@ static void mvs_94xx_detect_porttype(struct mvs_info *mvi, int i)
        }
 }
 
+void set_phy_tuning(struct mvs_info *mvi, int phy_id,
+                       struct phy_tuning phy_tuning)
+{
+       u32 tmp, setting_0 = 0, setting_1 = 0;
+       u8 i;
+
+       /* Remap information for B0 chip:
+       *
+       * R0Ch -> R118h[15:0] (Adapted DFE F3 - F5 coefficient)
+       * R0Dh -> R118h[31:16] (Generation 1 Setting 0)
+       * R0Eh -> R11Ch[15:0]  (Generation 1 Setting 1)
+       * R0Fh -> R11Ch[31:16] (Generation 2 Setting 0)
+       * R10h -> R120h[15:0]  (Generation 2 Setting 1)
+       * R11h -> R120h[31:16] (Generation 3 Setting 0)
+       * R12h -> R124h[15:0]  (Generation 3 Setting 1)
+       * R13h -> R124h[31:16] (Generation 4 Setting 0 (Reserved))
+       */
+
+       /* A0 has a different set of registers */
+       if (mvi->pdev->revision == VANIR_A0_REV)
+               return;
+
+       for (i = 0; i < 3; i++) {
+               /* loop 3 times, set Gen 1, Gen 2, Gen 3 */
+               switch (i) {
+               case 0:
+                       setting_0 = GENERATION_1_SETTING;
+                       setting_1 = GENERATION_1_2_SETTING;
+                       break;
+               case 1:
+                       setting_0 = GENERATION_1_2_SETTING;
+                       setting_1 = GENERATION_2_3_SETTING;
+                       break;
+               case 2:
+                       setting_0 = GENERATION_2_3_SETTING;
+                       setting_1 = GENERATION_3_4_SETTING;
+                       break;
+               }
+
+               /* Set:
+               *
+               * Transmitter Emphasis Enable
+               * Transmitter Emphasis Amplitude
+               * Transmitter Amplitude
+               */
+               mvs_write_port_vsr_addr(mvi, phy_id, setting_0);
+               tmp = mvs_read_port_vsr_data(mvi, phy_id);
+               tmp &= ~(0xFBE << 16);
+               tmp |= (((phy_tuning.trans_emp_en << 11) |
+                       (phy_tuning.trans_emp_amp << 7) |
+                       (phy_tuning.trans_amp << 1)) << 16);
+               mvs_write_port_vsr_data(mvi, phy_id, tmp);
+
+               /* Set Transmitter Amplitude Adjust */
+               mvs_write_port_vsr_addr(mvi, phy_id, setting_1);
+               tmp = mvs_read_port_vsr_data(mvi, phy_id);
+               tmp &= ~(0xC000);
+               tmp |= (phy_tuning.trans_amp_adj << 14);
+               mvs_write_port_vsr_data(mvi, phy_id, tmp);
+       }
+}
+
+void set_phy_ffe_tuning(struct mvs_info *mvi, int phy_id,
+                               struct ffe_control ffe)
+{
+       u32 tmp;
+
+       /* Don't run this if A0/B0 */
+       if ((mvi->pdev->revision == VANIR_A0_REV)
+               || (mvi->pdev->revision == VANIR_B0_REV))
+               return;
+
+       /* FFE Resistor and Capacitor */
+       /* R10Ch DFE Resolution Control/Squelch and FFE Setting
+        *
+        * FFE_FORCE            [7]
+        * FFE_RES_SEL          [6:4]
+        * FFE_CAP_SEL          [3:0]
+        */
+       mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_FFE_CONTROL);
+       tmp = mvs_read_port_vsr_data(mvi, phy_id);
+       tmp &= ~0xFF;
+
+       /* Read from HBA_Info_Page */
+       tmp |= ((0x1 << 7) |
+               (ffe.ffe_rss_sel << 4) |
+               (ffe.ffe_cap_sel << 0));
+
+       mvs_write_port_vsr_data(mvi, phy_id, tmp);
+
+       /* R064h PHY Mode Register 1
+        *
+        * DFE_DIS              18
+        */
+       mvs_write_port_vsr_addr(mvi, phy_id, VSR_REF_CLOCK_CRTL);
+       tmp = mvs_read_port_vsr_data(mvi, phy_id);
+       tmp &= ~0x40001;
+       /* Hard coding */
+       /* No defines in HBA_Info_Page */
+       tmp |= (0 << 18);
+       mvs_write_port_vsr_data(mvi, phy_id, tmp);
+
+       /* R110h DFE F0-F1 Coefficient Control/DFE Update Control
+        *
+        * DFE_UPDATE_EN        [11:6]
+        * DFE_FX_FORCE         [5:0]
+        */
+       mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_DFE_UPDATE_CRTL);
+       tmp = mvs_read_port_vsr_data(mvi, phy_id);
+       tmp &= ~0xFFF;
+       /* Hard coding */
+       /* No defines in HBA_Info_Page */
+       tmp |= ((0x3F << 6) | (0x0 << 0));
+       mvs_write_port_vsr_data(mvi, phy_id, tmp);
+
+       /* R1A0h Interface and Digital Reference Clock Control/Reserved_50h
+        *
+        * FFE_TRAIN_EN         3
+        */
+       mvs_write_port_vsr_addr(mvi, phy_id, VSR_REF_CLOCK_CRTL);
+       tmp = mvs_read_port_vsr_data(mvi, phy_id);
+       tmp &= ~0x8;
+       /* Hard coding */
+       /* No defines in HBA_Info_Page */
+       tmp |= (0 << 3);
+       mvs_write_port_vsr_data(mvi, phy_id, tmp);
+}
+
+/*Notice: this function must be called when phy is disabled*/
+void set_phy_rate(struct mvs_info *mvi, int phy_id, u8 rate)
+{
+       union reg_phy_cfg phy_cfg, phy_cfg_tmp;
+       mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_MODE2);
+       phy_cfg_tmp.v = mvs_read_port_vsr_data(mvi, phy_id);
+       phy_cfg.v = 0;
+       phy_cfg.u.disable_phy = phy_cfg_tmp.u.disable_phy;
+       phy_cfg.u.sas_support = 1;
+       phy_cfg.u.sata_support = 1;
+       phy_cfg.u.sata_host_mode = 1;
+
+       switch (rate) {
+       case 0x0:
+               /* support 1.5 Gbps */
+               phy_cfg.u.speed_support = 1;
+               phy_cfg.u.snw_3_support = 0;
+               phy_cfg.u.tx_lnk_parity = 1;
+               phy_cfg.u.tx_spt_phs_lnk_rate = 0x30;
+               break;
+       case 0x1:
+
+               /* support 1.5, 3.0 Gbps */
+               phy_cfg.u.speed_support = 3;
+               phy_cfg.u.tx_spt_phs_lnk_rate = 0x3c;
+               phy_cfg.u.tx_lgcl_lnk_rate = 0x08;
+               break;
+       case 0x2:
+       default:
+               /* support 1.5, 3.0, 6.0 Gbps */
+               phy_cfg.u.speed_support = 7;
+               phy_cfg.u.snw_3_support = 1;
+               phy_cfg.u.tx_lnk_parity = 1;
+               phy_cfg.u.tx_spt_phs_lnk_rate = 0x3f;
+               phy_cfg.u.tx_lgcl_lnk_rate = 0x09;
+               break;
+       }
+       mvs_write_port_vsr_data(mvi, phy_id, phy_cfg.v);
+}
+
+static void __devinit
+mvs_94xx_config_reg_from_hba(struct mvs_info *mvi, int phy_id)
+{
+       u32 temp;
+       temp = (u32)(*(u32 *)&mvi->hba_info_param.phy_tuning[phy_id]);
+       if (temp == 0xFFFFFFFFL) {
+               mvi->hba_info_param.phy_tuning[phy_id].trans_emp_amp = 0x6;
+               mvi->hba_info_param.phy_tuning[phy_id].trans_amp = 0x1A;
+               mvi->hba_info_param.phy_tuning[phy_id].trans_amp_adj = 0x3;
+       }
+
+       temp = (u8)(*(u8 *)&mvi->hba_info_param.ffe_ctl[phy_id]);
+       if (temp == 0xFFL) {
+               switch (mvi->pdev->revision) {
+               case VANIR_A0_REV:
+               case VANIR_B0_REV:
+                       mvi->hba_info_param.ffe_ctl[phy_id].ffe_rss_sel = 0x7;
+                       mvi->hba_info_param.ffe_ctl[phy_id].ffe_cap_sel = 0x7;
+                       break;
+               case VANIR_C0_REV:
+               case VANIR_C1_REV:
+               case VANIR_C2_REV:
+               default:
+                       mvi->hba_info_param.ffe_ctl[phy_id].ffe_rss_sel = 0x7;
+                       mvi->hba_info_param.ffe_ctl[phy_id].ffe_cap_sel = 0xC;
+                       break;
+               }
+       }
+
+       temp = (u8)(*(u8 *)&mvi->hba_info_param.phy_rate[phy_id]);
+       if (temp == 0xFFL)
+               /*set default phy_rate = 6Gbps*/
+               mvi->hba_info_param.phy_rate[phy_id] = 0x2;
+
+       set_phy_tuning(mvi, phy_id,
+               mvi->hba_info_param.phy_tuning[phy_id]);
+       set_phy_ffe_tuning(mvi, phy_id,
+               mvi->hba_info_param.ffe_ctl[phy_id]);
+       set_phy_rate(mvi, phy_id,
+               mvi->hba_info_param.phy_rate[phy_id]);
+}
+
 static void __devinit mvs_94xx_enable_xmt(struct mvs_info *mvi, int phy_id)
 {
        void __iomem *regs = mvi->regs;
@@ -61,7 +271,14 @@ static void __devinit mvs_94xx_enable_xmt(struct mvs_info *mvi, int phy_id)
 static void mvs_94xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard)
 {
        u32 tmp;
-
+       u32 delay = 5000;
+       if (hard == MVS_PHY_TUNE) {
+               mvs_write_port_cfg_addr(mvi, phy_id, PHYR_SATA_CTL);
+               tmp = mvs_read_port_cfg_data(mvi, phy_id);
+               mvs_write_port_cfg_data(mvi, phy_id, tmp|0x20000000);
+               mvs_write_port_cfg_data(mvi, phy_id, tmp|0x100000);
+               return;
+       }
        tmp = mvs_read_port_irq_stat(mvi, phy_id);
        tmp &= ~PHYEV_RDY_CH;
        mvs_write_port_irq_stat(mvi, phy_id, tmp);
@@ -71,12 +288,15 @@ static void mvs_94xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard)
                mvs_write_phy_ctl(mvi, phy_id, tmp);
                do {
                        tmp = mvs_read_phy_ctl(mvi, phy_id);
-               } while (tmp & PHY_RST_HARD);
+                       udelay(10);
+                       delay--;
+               } while ((tmp & PHY_RST_HARD) && delay);
+               if (!delay)
+                       mv_dprintk("phy hard reset failed.\n");
        } else {
-               mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_STAT);
-               tmp = mvs_read_port_vsr_data(mvi, phy_id);
+               tmp = mvs_read_phy_ctl(mvi, phy_id);
                tmp |= PHY_RST;
-               mvs_write_port_vsr_data(mvi, phy_id, tmp);
+               mvs_write_phy_ctl(mvi, phy_id, tmp);
        }
 }
 
@@ -90,12 +310,25 @@ static void mvs_94xx_phy_disable(struct mvs_info *mvi, u32 phy_id)
 
 static void mvs_94xx_phy_enable(struct mvs_info *mvi, u32 phy_id)
 {
-       mvs_write_port_vsr_addr(mvi, phy_id, 0x1B4);
-       mvs_write_port_vsr_data(mvi, phy_id, 0x8300ffc1);
-       mvs_write_port_vsr_addr(mvi, phy_id, 0x104);
-       mvs_write_port_vsr_data(mvi, phy_id, 0x00018080);
+       u32 tmp;
+       u8 revision = 0;
+
+       revision = mvi->pdev->revision;
+       if (revision == VANIR_A0_REV) {
+               mvs_write_port_vsr_addr(mvi, phy_id, CMD_HOST_RD_DATA);
+               mvs_write_port_vsr_data(mvi, phy_id, 0x8300ffc1);
+       }
+       if (revision == VANIR_B0_REV) {
+               mvs_write_port_vsr_addr(mvi, phy_id, CMD_APP_MEM_CTL);
+               mvs_write_port_vsr_data(mvi, phy_id, 0x08001006);
+               mvs_write_port_vsr_addr(mvi, phy_id, CMD_HOST_RD_DATA);
+               mvs_write_port_vsr_data(mvi, phy_id, 0x0000705f);
+       }
+
        mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_MODE2);
-       mvs_write_port_vsr_data(mvi, phy_id, 0x00207fff);
+       tmp = mvs_read_port_vsr_data(mvi, phy_id);
+       tmp |= bit(0);
+       mvs_write_port_vsr_data(mvi, phy_id, tmp & 0xfd7fffff);
 }
 
 static int __devinit mvs_94xx_init(struct mvs_info *mvi)
@@ -103,7 +336,9 @@ static int __devinit mvs_94xx_init(struct mvs_info *mvi)
        void __iomem *regs = mvi->regs;
        int i;
        u32 tmp, cctl;
+       u8 revision;
 
+       revision = mvi->pdev->revision;
        mvs_show_pcie_usage(mvi);
        if (mvi->flags & MVF_FLAG_SOC) {
                tmp = mr32(MVS_PHY_CTL);
@@ -133,6 +368,28 @@ static int __devinit mvs_94xx_init(struct mvs_info *mvi)
                msleep(100);
        }
 
+       /* disable Multiplexing, enable phy implemented */
+       mw32(MVS_PORTS_IMP, 0xFF);
+
+       if (revision == VANIR_A0_REV) {
+               mw32(MVS_PA_VSR_ADDR, CMD_CMWK_OOB_DET);
+               mw32(MVS_PA_VSR_PORT, 0x00018080);
+       }
+       mw32(MVS_PA_VSR_ADDR, VSR_PHY_MODE2);
+       if (revision == VANIR_A0_REV || revision == VANIR_B0_REV)
+               /* set 6G/3G/1.5G, multiplexing, without SSC */
+               mw32(MVS_PA_VSR_PORT, 0x0084d4fe);
+       else
+               /* set 6G/3G/1.5G, multiplexing, with and without SSC */
+               mw32(MVS_PA_VSR_PORT, 0x0084fffe);
+
+       if (revision == VANIR_B0_REV) {
+               mw32(MVS_PA_VSR_ADDR, CMD_APP_MEM_CTL);
+               mw32(MVS_PA_VSR_PORT, 0x08001006);
+               mw32(MVS_PA_VSR_ADDR, CMD_HOST_RD_DATA);
+               mw32(MVS_PA_VSR_PORT, 0x0000705f);
+       }
+
        /* reset control */
        mw32(MVS_PCS, 0);               /* MVS_PCS */
        mw32(MVS_STP_REG_SET_0, 0);
@@ -141,17 +398,8 @@ static int __devinit mvs_94xx_init(struct mvs_info *mvi)
        /* init phys */
        mvs_phy_hacks(mvi);
 
-       /* disable Multiplexing, enable phy implemented */
-       mw32(MVS_PORTS_IMP, 0xFF);
-
-
-       mw32(MVS_PA_VSR_ADDR, 0x00000104);
-       mw32(MVS_PA_VSR_PORT, 0x00018080);
-       mw32(MVS_PA_VSR_ADDR, VSR_PHY_MODE8);
-       mw32(MVS_PA_VSR_PORT, 0x0084ffff);
-
        /* set LED blink when IO*/
-       mw32(MVS_PA_VSR_ADDR, 0x00000030);
+       mw32(MVS_PA_VSR_ADDR, VSR_PHY_ACT_LED);
        tmp = mr32(MVS_PA_VSR_PORT);
        tmp &= 0xFFFF00FF;
        tmp |= 0x00003300;
@@ -175,12 +423,13 @@ static int __devinit mvs_94xx_init(struct mvs_info *mvi)
                mvs_94xx_phy_disable(mvi, i);
                /* set phy local SAS address */
                mvs_set_sas_addr(mvi, i, CONFIG_ID_FRAME3, CONFIG_ID_FRAME4,
-                                               (mvi->phy[i].dev_sas_addr));
+                                               cpu_to_le64(mvi->phy[i].dev_sas_addr));
 
                mvs_94xx_enable_xmt(mvi, i);
+               mvs_94xx_config_reg_from_hba(mvi, i);
                mvs_94xx_phy_enable(mvi, i);
 
-               mvs_94xx_phy_reset(mvi, i, 1);
+               mvs_94xx_phy_reset(mvi, i, PHY_RST_HARD);
                msleep(500);
                mvs_94xx_detect_porttype(mvi, i);
        }
@@ -211,16 +460,9 @@ static int __devinit mvs_94xx_init(struct mvs_info *mvi)
                mvs_update_phyinfo(mvi, i, 1);
        }
 
-       /* FIXME: update wide port bitmaps */
-
        /* little endian for open address and command table, etc. */
-       /*
-        * it seems that ( from the spec ) turning on big-endian won't
-        * do us any good on big-endian machines, need further confirmation
-        */
        cctl = mr32(MVS_CTL);
        cctl |= CCTL_ENDIAN_CMD;
-       cctl |= CCTL_ENDIAN_DATA;
        cctl &= ~CCTL_ENDIAN_OPEN;
        cctl |= CCTL_ENDIAN_RSP;
        mw32_f(MVS_CTL, cctl);
@@ -228,15 +470,20 @@ static int __devinit mvs_94xx_init(struct mvs_info *mvi)
        /* reset CMD queue */
        tmp = mr32(MVS_PCS);
        tmp |= PCS_CMD_RST;
+       tmp &= ~PCS_SELF_CLEAR;
        mw32(MVS_PCS, tmp);
-       /* interrupt coalescing may cause missing HW interrput in some case,
-        * and the max count is 0x1ff, while our max slot is 0x200,
+       /*
+        * the max count is 0x1ff, while our max slot is 0x200,
         * it will make count 0.
         */
        tmp = 0;
-       mw32(MVS_INT_COAL, tmp);
+       if (MVS_CHIP_SLOT_SZ > 0x1ff)
+               mw32(MVS_INT_COAL, 0x1ff | COAL_EN);
+       else
+               mw32(MVS_INT_COAL, MVS_CHIP_SLOT_SZ | COAL_EN);
 
-       tmp = 0x100;
+       /* default interrupt coalescing time is 128us */
+       tmp = 0x10000 | interrupt_coalescing;
        mw32(MVS_INT_COAL_TMOUT, tmp);
 
        /* ladies and gentlemen, start your engines */
@@ -249,7 +496,7 @@ static int __devinit mvs_94xx_init(struct mvs_info *mvi)
 
        /* enable completion queue interrupt */
        tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM | CINT_SRS | CINT_CI_STOP |
-               CINT_DMA_PCIE);
+               CINT_DMA_PCIE | CINT_NON_SPEC_NCQ_ERROR);
        tmp |= CINT_PHY_MASK;
        mw32(MVS_INT_MASK, tmp);
 
@@ -332,13 +579,10 @@ static irqreturn_t mvs_94xx_isr(struct mvs_info *mvi, int irq, u32 stat)
        if (((stat & IRQ_SAS_A) && mvi->id == 0) ||
                        ((stat & IRQ_SAS_B) && mvi->id == 1)) {
                mw32_f(MVS_INT_STAT, CINT_DONE);
-       #ifndef MVS_USE_TASKLET
+
                spin_lock(&mvi->lock);
-       #endif
                mvs_int_full(mvi);
-       #ifndef MVS_USE_TASKLET
                spin_unlock(&mvi->lock);
-       #endif
        }
        return IRQ_HANDLED;
 }
@@ -346,10 +590,48 @@ static irqreturn_t mvs_94xx_isr(struct mvs_info *mvi, int irq, u32 stat)
 static void mvs_94xx_command_active(struct mvs_info *mvi, u32 slot_idx)
 {
        u32 tmp;
-       mvs_cw32(mvi, 0x300 + (slot_idx >> 3), 1 << (slot_idx % 32));
-       do {
-               tmp = mvs_cr32(mvi, 0x300 + (slot_idx >> 3));
-       } while (tmp & 1 << (slot_idx % 32));
+       tmp = mvs_cr32(mvi, MVS_COMMAND_ACTIVE+(slot_idx >> 3));
+       if (tmp && 1 << (slot_idx % 32)) {
+               mv_printk("command active %08X,  slot [%x].\n", tmp, slot_idx);
+               mvs_cw32(mvi, MVS_COMMAND_ACTIVE + (slot_idx >> 3),
+                       1 << (slot_idx % 32));
+               do {
+                       tmp = mvs_cr32(mvi,
+                               MVS_COMMAND_ACTIVE + (slot_idx >> 3));
+               } while (tmp & 1 << (slot_idx % 32));
+       }
+}
+
+void mvs_94xx_clear_srs_irq(struct mvs_info *mvi, u8 reg_set, u8 clear_all)
+{
+       void __iomem *regs = mvi->regs;
+       u32 tmp;
+
+       if (clear_all) {
+               tmp = mr32(MVS_INT_STAT_SRS_0);
+               if (tmp) {
+                       mv_dprintk("check SRS 0 %08X.\n", tmp);
+                       mw32(MVS_INT_STAT_SRS_0, tmp);
+               }
+               tmp = mr32(MVS_INT_STAT_SRS_1);
+               if (tmp) {
+                       mv_dprintk("check SRS 1 %08X.\n", tmp);
+                       mw32(MVS_INT_STAT_SRS_1, tmp);
+               }
+       } else {
+               if (reg_set > 31)
+                       tmp = mr32(MVS_INT_STAT_SRS_1);
+               else
+                       tmp = mr32(MVS_INT_STAT_SRS_0);
+
+               if (tmp & (1 << (reg_set % 32))) {
+                       mv_dprintk("register set 0x%x was stopped.\n", reg_set);
+                       if (reg_set > 31)
+                               mw32(MVS_INT_STAT_SRS_1, 1 << (reg_set % 32));
+                       else
+                               mw32(MVS_INT_STAT_SRS_0, 1 << (reg_set % 32));
+               }
+       }
 }
 
 static void mvs_94xx_issue_stop(struct mvs_info *mvi, enum mvs_port_type type,
@@ -357,37 +639,56 @@ static void mvs_94xx_issue_stop(struct mvs_info *mvi, enum mvs_port_type type,
 {
        void __iomem *regs = mvi->regs;
        u32 tmp;
+       mvs_94xx_clear_srs_irq(mvi, 0, 1);
 
-       if (type == PORT_TYPE_SATA) {
-               tmp = mr32(MVS_INT_STAT_SRS_0) | (1U << tfs);
-               mw32(MVS_INT_STAT_SRS_0, tmp);
-       }
-       mw32(MVS_INT_STAT, CINT_CI_STOP);
+       tmp = mr32(MVS_INT_STAT);
+       mw32(MVS_INT_STAT, tmp | CINT_CI_STOP);
        tmp = mr32(MVS_PCS) | 0xFF00;
        mw32(MVS_PCS, tmp);
 }
 
+static void mvs_94xx_non_spec_ncq_error(struct mvs_info *mvi)
+{
+       void __iomem *regs = mvi->regs;
+       u32 err_0, err_1;
+       u8 i;
+       struct mvs_device *device;
+
+       err_0 = mr32(MVS_NON_NCQ_ERR_0);
+       err_1 = mr32(MVS_NON_NCQ_ERR_1);
+
+       mv_dprintk("non specific ncq error err_0:%x,err_1:%x.\n",
+                       err_0, err_1);
+       for (i = 0; i < 32; i++) {
+               if (err_0 & bit(i)) {
+                       device = mvs_find_dev_by_reg_set(mvi, i);
+                       if (device)
+                               mvs_release_task(mvi, device->sas_device);
+               }
+               if (err_1 & bit(i)) {
+                       device = mvs_find_dev_by_reg_set(mvi, i+32);
+                       if (device)
+                               mvs_release_task(mvi, device->sas_device);
+               }
+       }
+
+       mw32(MVS_NON_NCQ_ERR_0, err_0);
+       mw32(MVS_NON_NCQ_ERR_1, err_1);
+}
+
 static void mvs_94xx_free_reg_set(struct mvs_info *mvi, u8 *tfs)
 {
        void __iomem *regs = mvi->regs;
-       u32 tmp;
        u8 reg_set = *tfs;
 
        if (*tfs == MVS_ID_NOT_MAPPED)
                return;
 
        mvi->sata_reg_set &= ~bit(reg_set);
-       if (reg_set < 32) {
+       if (reg_set < 32)
                w_reg_set_enable(reg_set, (u32)mvi->sata_reg_set);
-               tmp = mr32(MVS_INT_STAT_SRS_0) & (u32)mvi->sata_reg_set;
-               if (tmp)
-                       mw32(MVS_INT_STAT_SRS_0, tmp);
-       } else {
-               w_reg_set_enable(reg_set, mvi->sata_reg_set);
-               tmp = mr32(MVS_INT_STAT_SRS_1) & mvi->sata_reg_set;
-               if (tmp)
-                       mw32(MVS_INT_STAT_SRS_1, tmp);
-       }
+       else
+               w_reg_set_enable(reg_set, (u32)(mvi->sata_reg_set >> 32));
 
        *tfs = MVS_ID_NOT_MAPPED;
 
@@ -403,7 +704,7 @@ static u8 mvs_94xx_assign_reg_set(struct mvs_info *mvi, u8 *tfs)
                return 0;
 
        i = mv_ffc64(mvi->sata_reg_set);
-       if (i > 32) {
+       if (i >= 32) {
                mvi->sata_reg_set |= bit(i);
                w_reg_set_enable(i, (u32)(mvi->sata_reg_set >> 32));
                *tfs = i;
@@ -422,9 +723,12 @@ static void mvs_94xx_make_prd(struct scatterlist *scatter, int nr, void *prd)
        int i;
        struct scatterlist *sg;
        struct mvs_prd *buf_prd = prd;
+       struct mvs_prd_imt im_len;
+       *(u32 *)&im_len = 0;
        for_each_sg(scatter, sg, nr, i) {
                buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
-               buf_prd->im_len.len = cpu_to_le32(sg_dma_len(sg));
+               im_len.len = sg_dma_len(sg);
+               buf_prd->im_len = cpu_to_le32(*(u32 *)&im_len);
                buf_prd++;
        }
 }
@@ -433,7 +737,7 @@ static int mvs_94xx_oob_done(struct mvs_info *mvi, int i)
 {
        u32 phy_st;
        phy_st = mvs_read_phy_ctl(mvi, i);
-       if (phy_st & PHY_READY_MASK)    /* phy ready */
+       if (phy_st & PHY_READY_MASK)
                return 1;
        return 0;
 }
@@ -447,7 +751,7 @@ static void mvs_94xx_get_dev_identify_frame(struct mvs_info *mvi, int port_id,
        for (i = 0; i < 7; i++) {
                mvs_write_port_cfg_addr(mvi, port_id,
                                        CONFIG_ID_FRAME0 + i * 4);
-               id_frame[i] = mvs_read_port_cfg_data(mvi, port_id);
+               id_frame[i] = cpu_to_le32(mvs_read_port_cfg_data(mvi, port_id));
        }
        memcpy(id, id_frame, 28);
 }
@@ -458,15 +762,13 @@ static void mvs_94xx_get_att_identify_frame(struct mvs_info *mvi, int port_id,
        int i;
        u32 id_frame[7];
 
-       /* mvs_hexdump(28, (u8 *)id_frame, 0); */
        for (i = 0; i < 7; i++) {
                mvs_write_port_cfg_addr(mvi, port_id,
                                        CONFIG_ATT_ID_FRAME0 + i * 4);
-               id_frame[i] = mvs_read_port_cfg_data(mvi, port_id);
+               id_frame[i] = cpu_to_le32(mvs_read_port_cfg_data(mvi, port_id));
                mv_dprintk("94xx phy %d atta frame %d %x.\n",
                        port_id + mvi->id * mvi->chip->n_phy, i, id_frame[i]);
        }
-       /* mvs_hexdump(28, (u8 *)id_frame, 0); */
        memcpy(id, id_frame, 28);
 }
 
@@ -526,7 +828,18 @@ static void mvs_94xx_fix_phy_info(struct mvs_info *mvi, int i,
 void mvs_94xx_phy_set_link_rate(struct mvs_info *mvi, u32 phy_id,
                        struct sas_phy_linkrates *rates)
 {
-       /* TODO */
+       u32 lrmax = 0;
+       u32 tmp;
+
+       tmp = mvs_read_phy_ctl(mvi, phy_id);
+       lrmax = (rates->maximum_linkrate - SAS_LINK_RATE_1_5_GBPS) << 12;
+
+       if (lrmax) {
+               tmp &= ~(0x3 << 12);
+               tmp |= lrmax;
+       }
+       mvs_write_phy_ctl(mvi, phy_id, tmp);
+       mvs_94xx_phy_reset(mvi, phy_id, PHY_RST_HARD);
 }
 
 static void mvs_94xx_clear_active_cmds(struct mvs_info *mvi)
@@ -603,27 +916,59 @@ int mvs_94xx_spi_waitdataready(struct mvs_info *mvi, u32 timeout)
        return -1;
 }
 
-#ifndef DISABLE_HOTPLUG_DMA_FIX
-void mvs_94xx_fix_dma(dma_addr_t buf_dma, int buf_len, int from, void *prd)
+void mvs_94xx_fix_dma(struct mvs_info *mvi, u32 phy_mask,
+                               int buf_len, int from, void *prd)
 {
        int i;
        struct mvs_prd *buf_prd = prd;
+       dma_addr_t buf_dma;
+       struct mvs_prd_imt im_len;
+
+       *(u32 *)&im_len = 0;
        buf_prd += from;
-       for (i = 0; i < MAX_SG_ENTRY - from; i++) {
-               buf_prd->addr = cpu_to_le64(buf_dma);
-               buf_prd->im_len.len = cpu_to_le32(buf_len);
-               ++buf_prd;
+
+#define PRD_CHAINED_ENTRY 0x01
+       if ((mvi->pdev->revision == VANIR_A0_REV) ||
+                       (mvi->pdev->revision == VANIR_B0_REV))
+               buf_dma = (phy_mask <= 0x08) ?
+                               mvi->bulk_buffer_dma : mvi->bulk_buffer_dma1;
+       else
+               return;
+
+       for (i = from; i < MAX_SG_ENTRY; i++, ++buf_prd) {
+               if (i == MAX_SG_ENTRY - 1) {
+                       buf_prd->addr = cpu_to_le64(virt_to_phys(buf_prd - 1));
+                       im_len.len = 2;
+                       im_len.misc_ctl = PRD_CHAINED_ENTRY;
+               } else {
+                       buf_prd->addr = cpu_to_le64(buf_dma);
+                       im_len.len = buf_len;
+               }
+               buf_prd->im_len = cpu_to_le32(*(u32 *)&im_len);
        }
 }
-#endif
 
-/*
- * FIXME JEJB: temporary nop clear_srs_irq to make 94xx still work
- * with 64xx fixes
- */
-static void mvs_94xx_clear_srs_irq(struct mvs_info *mvi, u8 reg_set,
-                                  u8 clear_all)
+static void mvs_94xx_tune_interrupt(struct mvs_info *mvi, u32 time)
 {
+       void __iomem *regs = mvi->regs;
+       u32 tmp = 0;
+       /*
+        * the max count is 0x1ff, while our max slot is 0x200,
+        * it will make count 0.
+        */
+       if (time == 0) {
+               mw32(MVS_INT_COAL, 0);
+               mw32(MVS_INT_COAL_TMOUT, 0x10000);
+       } else {
+               if (MVS_CHIP_SLOT_SZ > 0x1ff)
+                       mw32(MVS_INT_COAL, 0x1ff|COAL_EN);
+               else
+                       mw32(MVS_INT_COAL, MVS_CHIP_SLOT_SZ|COAL_EN);
+
+               tmp = 0x10000 | time;
+               mw32(MVS_INT_COAL_TMOUT, tmp);
+       }
+
 }
 
 const struct mvs_dispatch mvs_94xx_dispatch = {
@@ -648,7 +993,6 @@ const struct mvs_dispatch mvs_94xx_dispatch = {
        mvs_write_port_irq_stat,
        mvs_read_port_irq_mask,
        mvs_write_port_irq_mask,
-       mvs_get_sas_addr,
        mvs_94xx_command_active,
        mvs_94xx_clear_srs_irq,
        mvs_94xx_issue_stop,
@@ -676,8 +1020,8 @@ const struct mvs_dispatch mvs_94xx_dispatch = {
        mvs_94xx_spi_buildcmd,
        mvs_94xx_spi_issuecmd,
        mvs_94xx_spi_waitdataready,
-#ifndef DISABLE_HOTPLUG_DMA_FIX
        mvs_94xx_fix_dma,
-#endif
+       mvs_94xx_tune_interrupt,
+       mvs_94xx_non_spec_ncq_error,
 };
 
index 8835bef..8f7eb4f 100644 (file)
 
 #define MAX_LINK_RATE          SAS_LINK_RATE_6_0_GBPS
 
+enum VANIR_REVISION_ID {
+       VANIR_A0_REV            = 0xA0,
+       VANIR_B0_REV            = 0x01,
+       VANIR_C0_REV            = 0x02,
+       VANIR_C1_REV            = 0x03,
+       VANIR_C2_REV            = 0xC2,
+};
+
 enum hw_registers {
        MVS_GBL_CTL             = 0x04,  /* global control */
        MVS_GBL_INT_STAT        = 0x00,  /* global irq status */
@@ -101,6 +109,7 @@ enum hw_registers {
        MVS_P4_VSR_DATA         = 0x254, /* phy4 VSR data */
        MVS_PA_VSR_ADDR         = 0x290, /* All port VSR addr */
        MVS_PA_VSR_PORT         = 0x294, /* All port VSR data */
+       MVS_COMMAND_ACTIVE      = 0x300,
 };
 
 enum pci_cfg_registers {
@@ -112,26 +121,29 @@ enum pci_cfg_registers {
 
 /*  SAS/SATA Vendor Specific Port Registers */
 enum sas_sata_vsp_regs {
-       VSR_PHY_STAT            = 0x00 * 4, /* Phy Status */
-       VSR_PHY_MODE1           = 0x01 * 4, /* phy tx */
-       VSR_PHY_MODE2           = 0x02 * 4, /* tx scc */
-       VSR_PHY_MODE3           = 0x03 * 4, /* pll */
-       VSR_PHY_MODE4           = 0x04 * 4, /* VCO */
-       VSR_PHY_MODE5           = 0x05 * 4, /* Rx */
-       VSR_PHY_MODE6           = 0x06 * 4, /* CDR */
-       VSR_PHY_MODE7           = 0x07 * 4, /* Impedance */
-       VSR_PHY_MODE8           = 0x08 * 4, /* Voltage */
-       VSR_PHY_MODE9           = 0x09 * 4, /* Test */
-       VSR_PHY_MODE10          = 0x0A * 4, /* Power */
-       VSR_PHY_MODE11          = 0x0B * 4, /* Phy Mode */
-       VSR_PHY_VS0             = 0x0C * 4, /* Vednor Specific 0 */
-       VSR_PHY_VS1             = 0x0D * 4, /* Vednor Specific 1 */
+       VSR_PHY_STAT            = 0x00 * 4, /* Phy Interrupt Status */
+       VSR_PHY_MODE1           = 0x01 * 4, /* phy Interrupt Enable */
+       VSR_PHY_MODE2           = 0x02 * 4, /* Phy Configuration */
+       VSR_PHY_MODE3           = 0x03 * 4, /* Phy Status */
+       VSR_PHY_MODE4           = 0x04 * 4, /* Phy Counter 0 */
+       VSR_PHY_MODE5           = 0x05 * 4, /* Phy Counter 1 */
+       VSR_PHY_MODE6           = 0x06 * 4, /* Event Counter Control */
+       VSR_PHY_MODE7           = 0x07 * 4, /* Event Counter Select */
+       VSR_PHY_MODE8           = 0x08 * 4, /* Event Counter 0 */
+       VSR_PHY_MODE9           = 0x09 * 4, /* Event Counter 1 */
+       VSR_PHY_MODE10          = 0x0A * 4, /* Event Counter 2 */
+       VSR_PHY_MODE11          = 0x0B * 4, /* Event Counter 3 */
+       VSR_PHY_ACT_LED         = 0x0C * 4, /* Activity LED control */
+
+       VSR_PHY_FFE_CONTROL     = 0x10C,
+       VSR_PHY_DFE_UPDATE_CRTL = 0x110,
+       VSR_REF_CLOCK_CRTL      = 0x1A0,
 };
 
 enum chip_register_bits {
        PHY_MIN_SPP_PHYS_LINK_RATE_MASK = (0x7 << 8),
-       PHY_MAX_SPP_PHYS_LINK_RATE_MASK = (0x7 << 8),
-       PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET = (12),
+       PHY_MAX_SPP_PHYS_LINK_RATE_MASK = (0x7 << 12),
+       PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET = (16),
        PHY_NEG_SPP_PHYS_LINK_RATE_MASK =
                        (0x3 << PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET),
 };
@@ -169,22 +181,75 @@ enum pci_interrupt_cause {
        IRQ_PCIE_ERR                   = (1 << 31),
 };
 
+union reg_phy_cfg {
+       u32 v;
+       struct {
+               u32 phy_reset:1;
+               u32 sas_support:1;
+               u32 sata_support:1;
+               u32 sata_host_mode:1;
+               /*
+                * bit 2: 6Gbps support
+                * bit 1: 3Gbps support
+                * bit 0: 1.5Gbps support
+                */
+               u32 speed_support:3;
+               u32 snw_3_support:1;
+               u32 tx_lnk_parity:1;
+               /*
+                * bit 5: G1 (1.5Gbps) Without SSC
+                * bit 4: G1 (1.5Gbps) with SSC
+                * bit 3: G2 (3.0Gbps) Without SSC
+                * bit 2: G2 (3.0Gbps) with SSC
+                * bit 1: G3 (6.0Gbps) without SSC
+                * bit 0: G3 (6.0Gbps) with SSC
+                */
+               u32 tx_spt_phs_lnk_rate:6;
+               /* 8h: 1.5Gbps 9h: 3Gbps Ah: 6Gbps */
+               u32 tx_lgcl_lnk_rate:4;
+               u32 tx_ssc_type:1;
+               u32 sata_spin_up_spt:1;
+               u32 sata_spin_up_en:1;
+               u32 bypass_oob:1;
+               u32 disable_phy:1;
+               u32 rsvd:8;
+       } u;
+};
+
 #define MAX_SG_ENTRY           255
 
 struct mvs_prd_imt {
+#ifndef __BIG_ENDIAN
        __le32                  len:22;
        u8                      _r_a:2;
        u8                      misc_ctl:4;
        u8                      inter_sel:4;
+#else
+       u32                     inter_sel:4;
+       u32                     misc_ctl:4;
+       u32                     _r_a:2;
+       u32                     len:22;
+#endif
 };
 
 struct mvs_prd {
        /* 64-bit buffer address */
        __le64                  addr;
        /* 22-bit length */
-       struct mvs_prd_imt      im_len;
+       __le32                  im_len;
 } __attribute__ ((packed));
 
+/*
+ * these registers are accessed through port vendor
+ * specific address/data registers
+ */
+enum sas_sata_phy_regs {
+       GENERATION_1_SETTING            = 0x118,
+       GENERATION_1_2_SETTING          = 0x11C,
+       GENERATION_2_3_SETTING          = 0x120,
+       GENERATION_3_4_SETTING          = 0x124,
+};
+
 #define SPI_CTRL_REG_94XX              0xc800
 #define SPI_ADDR_REG_94XX              0xc804
 #define SPI_WR_DATA_REG_94XX         0xc808
index 1753a6f..bcc4080 100644 (file)
@@ -164,7 +164,6 @@ static inline void __devinit mvs_phy_hacks(struct mvs_info *mvi)
 {
        u32 tmp;
 
-       /* workaround for SATA R-ERR, to ignore phy glitch */
        tmp = mvs_cr32(mvi, CMD_PHY_TIMER);
        tmp &= ~(1 << 9);
        tmp |= (1 << 10);
@@ -179,23 +178,10 @@ static inline void __devinit mvs_phy_hacks(struct mvs_info *mvi)
        tmp |= 0x3fff;
        mvs_cw32(mvi, CMD_SAS_CTL0, tmp);
 
-       /* workaround for WDTIMEOUT , set to 550 ms */
        mvs_cw32(mvi, CMD_WD_TIMER, 0x7a0000);
 
        /* not to halt for different port op during wideport link change */
        mvs_cw32(mvi, CMD_APP_ERR_CONFIG, 0xffefbf7d);
-
-       /* workaround for Seagate disk not-found OOB sequence, recv
-        * COMINIT before sending out COMWAKE */
-       tmp = mvs_cr32(mvi, CMD_PHY_MODE_21);
-       tmp &= 0x0000ffff;
-       tmp |= 0x00fa0000;
-       mvs_cw32(mvi, CMD_PHY_MODE_21, tmp);
-
-       tmp = mvs_cr32(mvi, CMD_PHY_TIMER);
-       tmp &= 0x1fffffff;
-       tmp |= (2U << 29);      /* 8 ms retry */
-       mvs_cw32(mvi, CMD_PHY_TIMER, tmp);
 }
 
 static inline void mvs_int_sata(struct mvs_info *mvi)
@@ -223,6 +209,9 @@ static inline void mvs_int_full(struct mvs_info *mvi)
                        mvs_int_port(mvi, i, tmp);
        }
 
+       if (stat & CINT_NON_SPEC_NCQ_ERROR)
+               MVS_CHIP_DISP->non_spec_ncq_error(mvi);
+
        if (stat & CINT_SRS)
                mvs_int_sata(mvi);
 
index bc00c94..dec7cad 100644 (file)
@@ -43,7 +43,6 @@ enum chip_flavors {
 
 /* driver compile-time configuration */
 enum driver_configuration {
-       MVS_SLOTS               = 512,  /* command slots */
        MVS_TX_RING_SZ          = 1024, /* TX ring size (12-bit) */
        MVS_RX_RING_SZ          = 1024, /* RX ring size (12-bit) */
                                        /* software requires power-of-2
@@ -56,8 +55,7 @@ enum driver_configuration {
        MVS_SSP_CMD_SZ          = 64,   /* SSP command table buffer size */
        MVS_ATA_CMD_SZ          = 96,   /* SATA command table buffer size */
        MVS_OAF_SZ              = 64,   /* Open address frame buffer size */
-       MVS_QUEUE_SIZE  = 32,   /* Support Queue depth */
-       MVS_CAN_QUEUE           = MVS_SLOTS - 2,        /* SCSI Queue depth */
+       MVS_QUEUE_SIZE          = 64,   /* Support Queue depth */
        MVS_SOC_CAN_QUEUE       = MVS_SOC_SLOTS - 2,
 };
 
@@ -144,6 +142,7 @@ enum hw_register_bits {
        CINT_DMA_PCIE           = (1U << 27),   /* DMA to PCIE timeout */
        CINT_MEM                = (1U << 26),   /* int mem parity err */
        CINT_I2C_SLAVE          = (1U << 25),   /* slave I2C event */
+       CINT_NON_SPEC_NCQ_ERROR = (1U << 25),   /* Non specific NCQ error */
        CINT_SRS                = (1U << 3),    /* SRS event */
        CINT_CI_STOP            = (1U << 1),    /* cmd issue stopped */
        CINT_DONE               = (1U << 0),    /* cmd completion */
@@ -161,7 +160,7 @@ enum hw_register_bits {
        TXQ_CMD_SSP             = 1,            /* SSP protocol */
        TXQ_CMD_SMP             = 2,            /* SMP protocol */
        TXQ_CMD_STP             = 3,            /* STP/SATA protocol */
-       TXQ_CMD_SSP_FREE_LIST   = 4,            /* add to SSP targ free list */
+       TXQ_CMD_SSP_FREE_LIST   = 4,            /* add to SSP target free list */
        TXQ_CMD_SLOT_RESET      = 7,            /* reset command slot */
        TXQ_MODE_I              = (1U << 28),   /* mode: 0=target,1=initiator */
        TXQ_MODE_TARGET         = 0,
@@ -391,15 +390,15 @@ enum sas_cmd_port_registers {
 };
 
 enum mvs_info_flags {
-       MVF_MSI         = (1U << 0),    /* MSI is enabled */
        MVF_PHY_PWR_FIX = (1U << 1),    /* bug workaround */
        MVF_FLAG_SOC            = (1U << 2),    /* SoC integrated controllers */
 };
 
 enum mvs_event_flags {
-       PHY_PLUG_EVENT  = (3U),
+       PHY_PLUG_EVENT          = (3U),
        PHY_PLUG_IN             = (1U << 0),    /* phy plug in */
        PHY_PLUG_OUT            = (1U << 1),    /* phy plug out */
+       EXP_BRCT_CHG            = (1U << 2),    /* broadcast change */
 };
 
 enum mvs_port_type {
index 90b6366..4e9af66 100644 (file)
@@ -34,22 +34,25 @@ MODULE_PARM_DESC(collector, "\n"
        "\tThe mvsas SAS LLDD supports both modes.\n"
        "\tDefault: 1 (Direct Mode).\n");
 
+int interrupt_coalescing = 0x80;
+
 static struct scsi_transport_template *mvs_stt;
 struct kmem_cache *mvs_task_list_cache;
 static const struct mvs_chip_info mvs_chips[] = {
-       [chip_6320] =   { 1, 2, 0x400, 17, 16,  9, &mvs_64xx_dispatch, },
-       [chip_6440] =   { 1, 4, 0x400, 17, 16,  9, &mvs_64xx_dispatch, },
-       [chip_6485] =   { 1, 8, 0x800, 33, 32, 10, &mvs_64xx_dispatch, },
-       [chip_9180] =   { 2, 4, 0x800, 17, 64,  9, &mvs_94xx_dispatch, },
-       [chip_9480] =   { 2, 4, 0x800, 17, 64,  9, &mvs_94xx_dispatch, },
-       [chip_9445] =   { 1, 4, 0x800, 17, 64, 11, &mvs_94xx_dispatch, },
-       [chip_9485] =   { 2, 4, 0x800, 17, 64, 11, &mvs_94xx_dispatch, },
-       [chip_1300] =   { 1, 4, 0x400, 17, 16,  9, &mvs_64xx_dispatch, },
-       [chip_1320] =   { 2, 4, 0x800, 17, 64,  9, &mvs_94xx_dispatch, },
+       [chip_6320] =   { 1, 2, 0x400, 17, 16, 6,  9, &mvs_64xx_dispatch, },
+       [chip_6440] =   { 1, 4, 0x400, 17, 16, 6,  9, &mvs_64xx_dispatch, },
+       [chip_6485] =   { 1, 8, 0x800, 33, 32, 6, 10, &mvs_64xx_dispatch, },
+       [chip_9180] =   { 2, 4, 0x800, 17, 64, 8,  9, &mvs_94xx_dispatch, },
+       [chip_9480] =   { 2, 4, 0x800, 17, 64, 8,  9, &mvs_94xx_dispatch, },
+       [chip_9445] =   { 1, 4, 0x800, 17, 64, 8, 11, &mvs_94xx_dispatch, },
+       [chip_9485] =   { 2, 4, 0x800, 17, 64, 8, 11, &mvs_94xx_dispatch, },
+       [chip_1300] =   { 1, 4, 0x400, 17, 16, 6,  9, &mvs_64xx_dispatch, },
+       [chip_1320] =   { 2, 4, 0x800, 17, 64, 8,  9, &mvs_94xx_dispatch, },
 };
 
+struct device_attribute *mvst_host_attrs[];
+
 #define SOC_SAS_NUM 2
-#define SG_MX 64
 
 static struct scsi_host_template mvs_sht = {
        .module                 = THIS_MODULE,
@@ -66,7 +69,7 @@ static struct scsi_host_template mvs_sht = {
        .can_queue              = 1,
        .cmd_per_lun            = 1,
        .this_id                = -1,
-       .sg_tablesize           = SG_MX,
+       .sg_tablesize           = SG_ALL,
        .max_sectors            = SCSI_DEFAULT_MAX_SECTORS,
        .use_clustering         = ENABLE_CLUSTERING,
        .eh_device_reset_handler = sas_eh_device_reset_handler,
@@ -74,6 +77,7 @@ static struct scsi_host_template mvs_sht = {
        .slave_alloc            = mvs_slave_alloc,
        .target_destroy         = sas_target_destroy,
        .ioctl                  = sas_ioctl,
+       .shost_attrs            = mvst_host_attrs,
 };
 
 static struct sas_domain_function_template mvs_transport_ops = {
@@ -100,6 +104,7 @@ static void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id)
        struct asd_sas_phy *sas_phy = &phy->sas_phy;
 
        phy->mvi = mvi;
+       phy->port = NULL;
        init_timer(&phy->timer);
        sas_phy->enabled = (phy_id < mvi->chip->n_phy) ? 1 : 0;
        sas_phy->class = SAS;
@@ -128,7 +133,7 @@ static void mvs_free(struct mvs_info *mvi)
        if (mvi->flags & MVF_FLAG_SOC)
                slot_nr = MVS_SOC_SLOTS;
        else
-               slot_nr = MVS_SLOTS;
+               slot_nr = MVS_CHIP_SLOT_SZ;
 
        if (mvi->dma_pool)
                pci_pool_destroy(mvi->dma_pool);
@@ -148,25 +153,26 @@ static void mvs_free(struct mvs_info *mvi)
                dma_free_coherent(mvi->dev,
                                  sizeof(*mvi->slot) * slot_nr,
                                  mvi->slot, mvi->slot_dma);
-#ifndef DISABLE_HOTPLUG_DMA_FIX
+
        if (mvi->bulk_buffer)
                dma_free_coherent(mvi->dev, TRASH_BUCKET_SIZE,
                                  mvi->bulk_buffer, mvi->bulk_buffer_dma);
-#endif
+       if (mvi->bulk_buffer1)
+               dma_free_coherent(mvi->dev, TRASH_BUCKET_SIZE,
+                                 mvi->bulk_buffer1, mvi->bulk_buffer_dma1);
 
        MVS_CHIP_DISP->chip_iounmap(mvi);
        if (mvi->shost)
                scsi_host_put(mvi->shost);
        list_for_each_entry(mwq, &mvi->wq_list, entry)
                cancel_delayed_work(&mwq->work_q);
+       kfree(mvi->tags);
        kfree(mvi);
 }
 
-#ifdef MVS_USE_TASKLET
-struct tasklet_struct  mv_tasklet;
+#ifdef CONFIG_SCSI_MVSAS_TASKLET
 static void mvs_tasklet(unsigned long opaque)
 {
-       unsigned long flags;
        u32 stat;
        u16 core_nr, i = 0;
 
@@ -179,35 +185,49 @@ static void mvs_tasklet(unsigned long opaque)
        if (unlikely(!mvi))
                BUG_ON(1);
 
+       stat = MVS_CHIP_DISP->isr_status(mvi, mvi->pdev->irq);
+       if (!stat)
+               goto out;
+
        for (i = 0; i < core_nr; i++) {
                mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i];
-               stat = MVS_CHIP_DISP->isr_status(mvi, mvi->irq);
-               if (stat)
-                       MVS_CHIP_DISP->isr(mvi, mvi->irq, stat);
+               MVS_CHIP_DISP->isr(mvi, mvi->pdev->irq, stat);
        }
+out:
+       MVS_CHIP_DISP->interrupt_enable(mvi);
 
 }
 #endif
 
 static irqreturn_t mvs_interrupt(int irq, void *opaque)
 {
-       u32 core_nr, i = 0;
+       u32 core_nr;
        u32 stat;
        struct mvs_info *mvi;
        struct sas_ha_struct *sha = opaque;
+#ifndef CONFIG_SCSI_MVSAS_TASKLET
+       u32 i;
+#endif
 
        core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host;
        mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0];
 
        if (unlikely(!mvi))
                return IRQ_NONE;
+#ifdef CONFIG_SCSI_MVSAS_TASKLET
+       MVS_CHIP_DISP->interrupt_disable(mvi);
+#endif
 
        stat = MVS_CHIP_DISP->isr_status(mvi, irq);
-       if (!stat)
+       if (!stat) {
+       #ifdef CONFIG_SCSI_MVSAS_TASKLET
+               MVS_CHIP_DISP->interrupt_enable(mvi);
+       #endif
                return IRQ_NONE;
+       }
 
-#ifdef MVS_USE_TASKLET
-       tasklet_schedule(&mv_tasklet);
+#ifdef CONFIG_SCSI_MVSAS_TASKLET
+       tasklet_schedule(&((struct mvs_prv_info *)sha->lldd_ha)->mv_tasklet);
 #else
        for (i = 0; i < core_nr; i++) {
                mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i];
@@ -225,7 +245,7 @@ static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost)
        if (mvi->flags & MVF_FLAG_SOC)
                slot_nr = MVS_SOC_SLOTS;
        else
-               slot_nr = MVS_SLOTS;
+               slot_nr = MVS_CHIP_SLOT_SZ;
 
        spin_lock_init(&mvi->lock);
        for (i = 0; i < mvi->chip->n_phy; i++) {
@@ -273,13 +293,18 @@ static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost)
                goto err_out;
        memset(mvi->slot, 0, sizeof(*mvi->slot) * slot_nr);
 
-#ifndef DISABLE_HOTPLUG_DMA_FIX
        mvi->bulk_buffer = dma_alloc_coherent(mvi->dev,
                                       TRASH_BUCKET_SIZE,
                                       &mvi->bulk_buffer_dma, GFP_KERNEL);
        if (!mvi->bulk_buffer)
                goto err_out;
-#endif
+
+       mvi->bulk_buffer1 = dma_alloc_coherent(mvi->dev,
+                                      TRASH_BUCKET_SIZE,
+                                      &mvi->bulk_buffer_dma1, GFP_KERNEL);
+       if (!mvi->bulk_buffer1)
+               goto err_out;
+
        sprintf(pool_name, "%s%d", "mvs_dma_pool", mvi->id);
        mvi->dma_pool = pci_pool_create(pool_name, mvi->pdev, MVS_SLOT_BUF_SZ, 16, 0);
        if (!mvi->dma_pool) {
@@ -354,11 +379,12 @@ static struct mvs_info *__devinit mvs_pci_alloc(struct pci_dev *pdev,
                                const struct pci_device_id *ent,
                                struct Scsi_Host *shost, unsigned int id)
 {
-       struct mvs_info *mvi;
+       struct mvs_info *mvi = NULL;
        struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
 
-       mvi = kzalloc(sizeof(*mvi) + MVS_SLOTS * sizeof(struct mvs_slot_info),
-                       GFP_KERNEL);
+       mvi = kzalloc(sizeof(*mvi) +
+               (1L << mvs_chips[ent->driver_data].slot_width) *
+               sizeof(struct mvs_slot_info), GFP_KERNEL);
        if (!mvi)
                return NULL;
 
@@ -367,7 +393,6 @@ static struct mvs_info *__devinit mvs_pci_alloc(struct pci_dev *pdev,
        mvi->chip_id = ent->driver_data;
        mvi->chip = &mvs_chips[mvi->chip_id];
        INIT_LIST_HEAD(&mvi->wq_list);
-       mvi->irq = pdev->irq;
 
        ((struct mvs_prv_info *)sha->lldd_ha)->mvi[id] = mvi;
        ((struct mvs_prv_info *)sha->lldd_ha)->n_phy = mvi->chip->n_phy;
@@ -375,9 +400,10 @@ static struct mvs_info *__devinit mvs_pci_alloc(struct pci_dev *pdev,
        mvi->id = id;
        mvi->sas = sha;
        mvi->shost = shost;
-#ifdef MVS_USE_TASKLET
-       tasklet_init(&mv_tasklet, mvs_tasklet, (unsigned long)sha);
-#endif
+
+       mvi->tags = kzalloc(MVS_CHIP_SLOT_SZ>>3, GFP_KERNEL);
+       if (!mvi->tags)
+               goto err_out;
 
        if (MVS_CHIP_DISP->chip_ioremap(mvi))
                goto err_out;
@@ -388,7 +414,6 @@ err_out:
        return NULL;
 }
 
-/* move to PCI layer or libata core? */
 static int pci_go_64(struct pci_dev *pdev)
 {
        int rc;
@@ -450,7 +475,7 @@ static int __devinit mvs_prep_sas_ha_init(struct Scsi_Host *shost,
        ((struct mvs_prv_info *)sha->lldd_ha)->n_host = core_nr;
 
        shost->transportt = mvs_stt;
-       shost->max_id = 128;
+       shost->max_id = MVS_MAX_DEVICES;
        shost->max_lun = ~0;
        shost->max_channel = 1;
        shost->max_cmd_len = 16;
@@ -493,11 +518,12 @@ static void  __devinit mvs_post_sas_ha_init(struct Scsi_Host *shost,
        if (mvi->flags & MVF_FLAG_SOC)
                can_queue = MVS_SOC_CAN_QUEUE;
        else
-               can_queue = MVS_CAN_QUEUE;
+               can_queue = MVS_CHIP_SLOT_SZ;
 
        sha->lldd_queue_size = can_queue;
+       shost->sg_tablesize = min_t(u16, SG_ALL, MVS_MAX_SG);
        shost->can_queue = can_queue;
-       mvi->shost->cmd_per_lun = MVS_SLOTS/sha->num_phys;
+       mvi->shost->cmd_per_lun = MVS_QUEUE_SIZE;
        sha->core.shost = mvi->shost;
 }
 
@@ -518,6 +544,7 @@ static int __devinit mvs_pci_init(struct pci_dev *pdev,
 {
        unsigned int rc, nhost = 0;
        struct mvs_info *mvi;
+       struct mvs_prv_info *mpi;
        irq_handler_t irq_handler = mvs_interrupt;
        struct Scsi_Host *shost = NULL;
        const struct mvs_chip_info *chip;
@@ -569,6 +596,9 @@ static int __devinit mvs_pci_init(struct pci_dev *pdev,
                        goto err_out_regions;
                }
 
+               memset(&mvi->hba_info_param, 0xFF,
+                       sizeof(struct hba_info_page));
+
                mvs_init_sas_add(mvi);
 
                mvi->instance = nhost;
@@ -579,8 +609,9 @@ static int __devinit mvs_pci_init(struct pci_dev *pdev,
                }
                nhost++;
        } while (nhost < chip->n_host);
-#ifdef MVS_USE_TASKLET
-       tasklet_init(&mv_tasklet, mvs_tasklet,
+       mpi = (struct mvs_prv_info *)(SHOST_TO_SAS_HA(shost)->lldd_ha);
+#ifdef CONFIG_SCSI_MVSAS_TASKLET
+       tasklet_init(&(mpi->mv_tasklet), mvs_tasklet,
                     (unsigned long)SHOST_TO_SAS_HA(shost));
 #endif
 
@@ -625,8 +656,8 @@ static void __devexit mvs_pci_remove(struct pci_dev *pdev)
        core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host;
        mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0];
 
-#ifdef MVS_USE_TASKLET
-       tasklet_kill(&mv_tasklet);
+#ifdef CONFIG_SCSI_MVSAS_TASKLET
+       tasklet_kill(&((struct mvs_prv_info *)sha->lldd_ha)->mv_tasklet);
 #endif
 
        pci_set_drvdata(pdev, NULL);
@@ -635,7 +666,7 @@ static void __devexit mvs_pci_remove(struct pci_dev *pdev)
        scsi_remove_host(mvi->shost);
 
        MVS_CHIP_DISP->interrupt_disable(mvi);
-       free_irq(mvi->irq, sha);
+       free_irq(mvi->pdev->irq, sha);
        for (i = 0; i < core_nr; i++) {
                mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i];
                mvs_free(mvi);
@@ -703,6 +734,70 @@ static struct pci_driver mvs_pci_driver = {
        .remove         = __devexit_p(mvs_pci_remove),
 };
 
+static ssize_t
+mvs_show_driver_version(struct device *cdev,
+               struct device_attribute *attr,  char *buffer)
+{
+       return snprintf(buffer, PAGE_SIZE, "%s\n", DRV_VERSION);
+}
+
+static DEVICE_ATTR(driver_version,
+                        S_IRUGO,
+                        mvs_show_driver_version,
+                        NULL);
+
+static ssize_t
+mvs_store_interrupt_coalescing(struct device *cdev,
+                       struct device_attribute *attr,
+                       const char *buffer, size_t size)
+{
+       int val = 0;
+       struct mvs_info *mvi = NULL;
+       struct Scsi_Host *shost = class_to_shost(cdev);
+       struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+       u8 i, core_nr;
+       if (buffer == NULL)
+               return size;
+
+       if (sscanf(buffer, "%d", &val) != 1)
+               return -EINVAL;
+
+       if (val >= 0x10000) {
+               mv_dprintk("interrupt coalescing timer %d us is"
+                       "too long\n", val);
+               return strlen(buffer);
+       }
+
+       interrupt_coalescing = val;
+
+       core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host;
+       mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0];
+
+       if (unlikely(!mvi))
+               return -EINVAL;
+
+       for (i = 0; i < core_nr; i++) {
+               mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i];
+               if (MVS_CHIP_DISP->tune_interrupt)
+                       MVS_CHIP_DISP->tune_interrupt(mvi,
+                               interrupt_coalescing);
+       }
+       mv_dprintk("set interrupt coalescing time to %d us\n",
+               interrupt_coalescing);
+       return strlen(buffer);
+}
+
+static ssize_t mvs_show_interrupt_coalescing(struct device *cdev,
+                       struct device_attribute *attr, char *buffer)
+{
+       return snprintf(buffer, PAGE_SIZE, "%d\n", interrupt_coalescing);
+}
+
+static DEVICE_ATTR(interrupt_coalescing,
+                        S_IRUGO|S_IWUSR,
+                        mvs_show_interrupt_coalescing,
+                        mvs_store_interrupt_coalescing);
+
 /* task handler */
 struct task_struct *mvs_th;
 static int __init mvs_init(void)
@@ -739,6 +834,12 @@ static void __exit mvs_exit(void)
        kmem_cache_destroy(mvs_task_list_cache);
 }
 
+struct device_attribute *mvst_host_attrs[] = {
+       &dev_attr_driver_version,
+       &dev_attr_interrupt_coalescing,
+       NULL,
+};
+
 module_init(mvs_init);
 module_exit(mvs_exit);
 
index 0ef2742..4958fef 100644 (file)
@@ -38,7 +38,7 @@ static int mvs_find_tag(struct mvs_info *mvi, struct sas_task *task, u32 *tag)
 
 void mvs_tag_clear(struct mvs_info *mvi, u32 tag)
 {
-       void *bitmap = &mvi->tags;
+       void *bitmap = mvi->tags;
        clear_bit(tag, bitmap);
 }
 
@@ -49,14 +49,14 @@ void mvs_tag_free(struct mvs_info *mvi, u32 tag)
 
 void mvs_tag_set(struct mvs_info *mvi, unsigned int tag)
 {
-       void *bitmap = &mvi->tags;
+       void *bitmap = mvi->tags;
        set_bit(tag, bitmap);
 }
 
 inline int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out)
 {
        unsigned int index, tag;
-       void *bitmap = &mvi->tags;
+       void *bitmap = mvi->tags;
 
        index = find_first_zero_bit(bitmap, mvi->tags_num);
        tag = index;
@@ -74,126 +74,6 @@ void mvs_tag_init(struct mvs_info *mvi)
                mvs_tag_clear(mvi, i);
 }
 
-void mvs_hexdump(u32 size, u8 *data, u32 baseaddr)
-{
-       u32 i;
-       u32 run;
-       u32 offset;
-
-       offset = 0;
-       while (size) {
-               printk(KERN_DEBUG"%08X : ", baseaddr + offset);
-               if (size >= 16)
-                       run = 16;
-               else
-                       run = size;
-               size -= run;
-               for (i = 0; i < 16; i++) {
-                       if (i < run)
-                               printk(KERN_DEBUG"%02X ", (u32)data[i]);
-                       else
-                               printk(KERN_DEBUG"   ");
-               }
-               printk(KERN_DEBUG": ");
-               for (i = 0; i < run; i++)
-                       printk(KERN_DEBUG"%c",
-                               isalnum(data[i]) ? data[i] : '.');
-               printk(KERN_DEBUG"\n");
-               data = &data[16];
-               offset += run;
-       }
-       printk(KERN_DEBUG"\n");
-}
-
-#if (_MV_DUMP > 1)
-static void mvs_hba_sb_dump(struct mvs_info *mvi, u32 tag,
-                                  enum sas_protocol proto)
-{
-       u32 offset;
-       struct mvs_slot_info *slot = &mvi->slot_info[tag];
-
-       offset = slot->cmd_size + MVS_OAF_SZ +
-           MVS_CHIP_DISP->prd_size() * slot->n_elem;
-       dev_printk(KERN_DEBUG, mvi->dev, "+---->Status buffer[%d] :\n",
-                       tag);
-       mvs_hexdump(32, (u8 *) slot->response,
-                   (u32) slot->buf_dma + offset);
-}
-#endif
-
-static void mvs_hba_memory_dump(struct mvs_info *mvi, u32 tag,
-                               enum sas_protocol proto)
-{
-#if (_MV_DUMP > 1)
-       u32 sz, w_ptr;
-       u64 addr;
-       struct mvs_slot_info *slot = &mvi->slot_info[tag];
-
-       /*Delivery Queue */
-       sz = MVS_CHIP_SLOT_SZ;
-       w_ptr = slot->tx;
-       addr = mvi->tx_dma;
-       dev_printk(KERN_DEBUG, mvi->dev,
-               "Delivery Queue Size=%04d , WRT_PTR=%04X\n", sz, w_ptr);
-       dev_printk(KERN_DEBUG, mvi->dev,
-               "Delivery Queue Base Address=0x%llX (PA)"
-               "(tx_dma=0x%llX), Entry=%04d\n",
-               addr, (unsigned long long)mvi->tx_dma, w_ptr);
-       mvs_hexdump(sizeof(u32), (u8 *)(&mvi->tx[mvi->tx_prod]),
-                       (u32) mvi->tx_dma + sizeof(u32) * w_ptr);
-       /*Command List */
-       addr = mvi->slot_dma;
-       dev_printk(KERN_DEBUG, mvi->dev,
-               "Command List Base Address=0x%llX (PA)"
-               "(slot_dma=0x%llX), Header=%03d\n",
-               addr, (unsigned long long)slot->buf_dma, tag);
-       dev_printk(KERN_DEBUG, mvi->dev, "Command Header[%03d]:\n", tag);
-       /*mvs_cmd_hdr */
-       mvs_hexdump(sizeof(struct mvs_cmd_hdr), (u8 *)(&mvi->slot[tag]),
-               (u32) mvi->slot_dma + tag * sizeof(struct mvs_cmd_hdr));
-       /*1.command table area */
-       dev_printk(KERN_DEBUG, mvi->dev, "+---->Command Table :\n");
-       mvs_hexdump(slot->cmd_size, (u8 *) slot->buf, (u32) slot->buf_dma);
-       /*2.open address frame area */
-       dev_printk(KERN_DEBUG, mvi->dev, "+---->Open Address Frame :\n");
-       mvs_hexdump(MVS_OAF_SZ, (u8 *) slot->buf + slot->cmd_size,
-                               (u32) slot->buf_dma + slot->cmd_size);
-       /*3.status buffer */
-       mvs_hba_sb_dump(mvi, tag, proto);
-       /*4.PRD table */
-       dev_printk(KERN_DEBUG, mvi->dev, "+---->PRD table :\n");
-       mvs_hexdump(MVS_CHIP_DISP->prd_size() * slot->n_elem,
-               (u8 *) slot->buf + slot->cmd_size + MVS_OAF_SZ,
-               (u32) slot->buf_dma + slot->cmd_size + MVS_OAF_SZ);
-#endif
-}
-
-static void mvs_hba_cq_dump(struct mvs_info *mvi)
-{
-#if (_MV_DUMP > 2)
-       u64 addr;
-       void __iomem *regs = mvi->regs;
-       u32 entry = mvi->rx_cons + 1;
-       u32 rx_desc = le32_to_cpu(mvi->rx[entry]);
-
-       /*Completion Queue */
-       addr = mr32(RX_HI) << 16 << 16 | mr32(RX_LO);
-       dev_printk(KERN_DEBUG, mvi->dev, "Completion Task = 0x%p\n",
-                  mvi->slot_info[rx_desc & RXQ_SLOT_MASK].task);
-       dev_printk(KERN_DEBUG, mvi->dev,
-               "Completion List Base Address=0x%llX (PA), "
-               "CQ_Entry=%04d, CQ_WP=0x%08X\n",
-               addr, entry - 1, mvi->rx[0]);
-       mvs_hexdump(sizeof(u32), (u8 *)(&rx_desc),
-                   mvi->rx_dma + sizeof(u32) * entry);
-#endif
-}
-
-void mvs_get_sas_addr(void *buf, u32 buflen)
-{
-       /*memcpy(buf, "\x50\x05\x04\x30\x11\xab\x64\x40", 8);*/
-}
-
 struct mvs_info *mvs_find_dev_mvi(struct domain_device *dev)
 {
        unsigned long i = 0, j = 0, hi = 0;
@@ -222,7 +102,6 @@ struct mvs_info *mvs_find_dev_mvi(struct domain_device *dev)
 
 }
 
-/* FIXME */
 int mvs_find_dev_phyno(struct domain_device *dev, int *phyno)
 {
        unsigned long i = 0, j = 0, n = 0, num = 0;
@@ -253,6 +132,20 @@ int mvs_find_dev_phyno(struct domain_device *dev, int *phyno)
        return num;
 }
 
+struct mvs_device *mvs_find_dev_by_reg_set(struct mvs_info *mvi,
+                                               u8 reg_set)
+{
+       u32 dev_no;
+       for (dev_no = 0; dev_no < MVS_MAX_DEVICES; dev_no++) {
+               if (mvi->devices[dev_no].taskfileset == MVS_ID_NOT_MAPPED)
+                       continue;
+
+               if (mvi->devices[dev_no].taskfileset == reg_set)
+                       return &mvi->devices[dev_no];
+       }
+       return NULL;
+}
+
 static inline void mvs_free_reg_set(struct mvs_info *mvi,
                                struct mvs_device *dev)
 {
@@ -283,7 +176,6 @@ void mvs_phys_reset(struct mvs_info *mvi, u32 phy_mask, int hard)
        }
 }
 
-/* FIXME: locking? */
 int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
                        void *funcdata)
 {
@@ -309,12 +201,12 @@ int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
                tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, phy_id);
                if (tmp & PHY_RST_HARD)
                        break;
-               MVS_CHIP_DISP->phy_reset(mvi, phy_id, 1);
+               MVS_CHIP_DISP->phy_reset(mvi, phy_id, MVS_HARD_RESET);
                break;
 
        case PHY_FUNC_LINK_RESET:
                MVS_CHIP_DISP->phy_enable(mvi, phy_id);
-               MVS_CHIP_DISP->phy_reset(mvi, phy_id, 0);
+               MVS_CHIP_DISP->phy_reset(mvi, phy_id, MVS_SOFT_RESET);
                break;
 
        case PHY_FUNC_DISABLE:
@@ -406,14 +298,10 @@ int mvs_slave_configure(struct scsi_device *sdev)
 
        if (ret)
                return ret;
-       if (dev_is_sata(dev)) {
-               /* may set PIO mode */
-       #if MV_DISABLE_NCQ
-               struct ata_port *ap = dev->sata_dev.ap;
-               struct ata_device *adev = ap->link.device;
-               adev->flags |= ATA_DFLAG_NCQ_OFF;
-               scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, 1);
-       #endif
+       if (!dev_is_sata(dev)) {
+               sas_change_queue_depth(sdev,
+                       MVS_QUEUE_SIZE,
+                       SCSI_QDEPTH_DEFAULT);
        }
        return 0;
 }
@@ -424,6 +312,7 @@ void mvs_scan_start(struct Scsi_Host *shost)
        unsigned short core_nr;
        struct mvs_info *mvi;
        struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+       struct mvs_prv_info *mvs_prv = sha->lldd_ha;
 
        core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host;
 
@@ -432,15 +321,17 @@ void mvs_scan_start(struct Scsi_Host *shost)
                for (i = 0; i < mvi->chip->n_phy; ++i)
                        mvs_bytes_dmaed(mvi, i);
        }
+       mvs_prv->scan_finished = 1;
 }
 
 int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time)
 {
-       /* give the phy enabling interrupt event time to come in (1s
-        * is empirically about all it takes) */
-       if (time < HZ)
+       struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+       struct mvs_prv_info *mvs_prv = sha->lldd_ha;
+
+       if (mvs_prv->scan_finished == 0)
                return 0;
-       /* Wait for discovery to finish */
+
        scsi_flush_work(shost);
        return 1;
 }
@@ -461,10 +352,7 @@ static int mvs_task_prep_smp(struct mvs_info *mvi,
        void *buf_prd;
        struct mvs_slot_info *slot = &mvi->slot_info[tag];
        u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
-#if _MV_DUMP
-       u8 *buf_cmd;
-       void *from;
-#endif
+
        /*
         * DMA-map SMP request, response buffers
         */
@@ -496,15 +384,7 @@ static int mvs_task_prep_smp(struct mvs_info *mvi,
        buf_tmp = slot->buf;
        buf_tmp_dma = slot->buf_dma;
 
-#if _MV_DUMP
-       buf_cmd = buf_tmp;
-       hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
-       buf_tmp += req_len;
-       buf_tmp_dma += req_len;
-       slot->cmd_size = req_len;
-#else
        hdr->cmd_tbl = cpu_to_le64(sg_dma_address(sg_req));
-#endif
 
        /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
        buf_oaf = buf_tmp;
@@ -553,12 +433,6 @@ static int mvs_task_prep_smp(struct mvs_info *mvi,
        /* fill in PRD (scatter/gather) table, if any */
        MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd);
 
-#if _MV_DUMP
-       /* copy cmd table */
-       from = kmap_atomic(sg_page(sg_req), KM_IRQ0);
-       memcpy(buf_cmd, from + sg_req->offset, req_len);
-       kunmap_atomic(from, KM_IRQ0);
-#endif
        return 0;
 
 err_out_2:
@@ -616,14 +490,11 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
                (mvi_dev->taskfileset << TXQ_SRS_SHIFT);
        mvi->tx[mvi->tx_prod] = cpu_to_le32(del_q);
 
-#ifndef DISABLE_HOTPLUG_DMA_FIX
        if (task->data_dir == DMA_FROM_DEVICE)
                flags = (MVS_CHIP_DISP->prd_count() << MCH_PRD_LEN_SHIFT);
        else
                flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
-#else
-       flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
-#endif
+
        if (task->ata_task.use_ncq)
                flags |= MCH_FPDMA;
        if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) {
@@ -631,11 +502,8 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
                        flags |= MCH_ATAPI;
        }
 
-       /* FIXME: fill in port multiplier number */
-
        hdr->flags = cpu_to_le32(flags);
 
-       /* FIXME: the low order order 5 bits for the TAG if enable NCQ */
        if (task->ata_task.use_ncq && mvs_get_ncq_tag(task, &hdr_tag))
                task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3);
        else
@@ -657,9 +525,6 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
 
        buf_tmp += MVS_ATA_CMD_SZ;
        buf_tmp_dma += MVS_ATA_CMD_SZ;
-#if _MV_DUMP
-       slot->cmd_size = MVS_ATA_CMD_SZ;
-#endif
 
        /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
        /* used for STP.  unused for SATA? */
@@ -682,9 +547,6 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
        buf_tmp_dma += i;
 
        /* region 4: status buffer (larger the PRD, smaller this buf) ****** */
-       /* FIXME: probably unused, for SATA.  kept here just in case
-        * we get a STP/SATA error information record
-        */
        slot->response = buf_tmp;
        hdr->status_buf = cpu_to_le64(buf_tmp_dma);
        if (mvi->flags & MVF_FLAG_SOC)
@@ -715,11 +577,11 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
 
        /* fill in PRD (scatter/gather) table, if any */
        MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd);
-#ifndef DISABLE_HOTPLUG_DMA_FIX
+
        if (task->data_dir == DMA_FROM_DEVICE)
-               MVS_CHIP_DISP->dma_fix(mvi->bulk_buffer_dma,
+               MVS_CHIP_DISP->dma_fix(mvi, sas_port->phy_mask,
                                TRASH_BUCKET_SIZE, tei->n_elem, buf_prd);
-#endif
+
        return 0;
 }
 
@@ -761,6 +623,9 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
        }
        if (is_tmf)
                flags |= (MCH_SSP_FR_TASK << MCH_SSP_FR_TYPE_SHIFT);
+       else
+               flags |= (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT);
+
        hdr->flags = cpu_to_le32(flags | (tei->n_elem << MCH_PRD_LEN_SHIFT));
        hdr->tags = cpu_to_le32(tag);
        hdr->data_len = cpu_to_le32(task->total_xfer_len);
@@ -777,9 +642,6 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
 
        buf_tmp += MVS_SSP_CMD_SZ;
        buf_tmp_dma += MVS_SSP_CMD_SZ;
-#if _MV_DUMP
-       slot->cmd_size = MVS_SSP_CMD_SZ;
-#endif
 
        /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
        buf_oaf = buf_tmp;
@@ -986,7 +848,6 @@ static int mvs_task_prep(struct sas_task *task, struct mvs_info *mvi, int is_tmf
        task->task_state_flags |= SAS_TASK_AT_INITIATOR;
        spin_unlock(&task->task_state_lock);
 
-       mvs_hba_memory_dump(mvi, tag, task->task_proto);
        mvi_dev->running_req++;
        ++(*pass);
        mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
@@ -1189,9 +1050,9 @@ static void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task,
        mvs_slot_free(mvi, slot_idx);
 }
 
-static void mvs_update_wideport(struct mvs_info *mvi, int i)
+static void mvs_update_wideport(struct mvs_info *mvi, int phy_no)
 {
-       struct mvs_phy *phy = &mvi->phy[i];
+       struct mvs_phy *phy = &mvi->phy[phy_no];
        struct mvs_port *port = phy->port;
        int j, no;
 
@@ -1246,18 +1107,17 @@ static void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf)
                return NULL;
 
        MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG3);
-       s[3] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i);
+       s[3] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i));
 
        MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG2);
-       s[2] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i);
+       s[2] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i));
 
        MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG1);
-       s[1] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i);
+       s[1] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i));
 
        MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG0);
-       s[0] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i);
+       s[0] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i));
 
-       /* Workaround: take some ATAPI devices for ATA */
        if (((s[1] & 0x00FFFFFF) == 0x00EB1401) && (*(u8 *)&s[3] == 0x01))
                s[1] = 0x00EB1401 | (*((u8 *)&s[1] + 3) & 0x10);
 
@@ -1269,6 +1129,13 @@ static u32 mvs_is_sig_fis_received(u32 irq_status)
        return irq_status & PHYEV_SIG_FIS;
 }
 
+static void mvs_sig_remove_timer(struct mvs_phy *phy)
+{
+       if (phy->timer.function)
+               del_timer(&phy->timer);
+       phy->timer.function = NULL;
+}
+
 void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st)
 {
        struct mvs_phy *phy = &mvi->phy[i];
@@ -1291,6 +1158,7 @@ void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st)
                if (phy->phy_type & PORT_TYPE_SATA) {
                        phy->identify.target_port_protocols = SAS_PROTOCOL_STP;
                        if (mvs_is_sig_fis_received(phy->irq_status)) {
+                               mvs_sig_remove_timer(phy);
                                phy->phy_attached = 1;
                                phy->att_dev_sas_addr =
                                        i + mvi->id * mvi->chip->n_phy;
@@ -1308,7 +1176,6 @@ void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st)
                                                tmp | PHYEV_SIG_FIS);
                                phy->phy_attached = 0;
                                phy->phy_type &= ~PORT_TYPE_SATA;
-                               MVS_CHIP_DISP->phy_reset(mvi, i, 0);
                                goto out_done;
                        }
                }       else if (phy->phy_type & PORT_TYPE_SAS
@@ -1334,9 +1201,9 @@ void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st)
                if (MVS_CHIP_DISP->phy_work_around)
                        MVS_CHIP_DISP->phy_work_around(mvi, i);
        }
-       mv_dprintk("port %d attach dev info is %x\n",
+       mv_dprintk("phy %d attach dev info is %x\n",
                i + mvi->id * mvi->chip->n_phy, phy->att_dev_info);
-       mv_dprintk("port %d attach sas addr is %llx\n",
+       mv_dprintk("phy %d attach sas addr is %llx\n",
                i + mvi->id * mvi->chip->n_phy, phy->att_dev_sas_addr);
 out_done:
        if (get_st)
@@ -1361,10 +1228,10 @@ static void mvs_port_notify_formed(struct asd_sas_phy *sas_phy, int lock)
        }
        hi = i/((struct mvs_prv_info *)sas_ha->lldd_ha)->n_phy;
        mvi = ((struct mvs_prv_info *)sas_ha->lldd_ha)->mvi[hi];
-       if (sas_port->id >= mvi->chip->n_phy)
-               port = &mvi->port[sas_port->id - mvi->chip->n_phy];
+       if (i >= mvi->chip->n_phy)
+               port = &mvi->port[i - mvi->chip->n_phy];
        else
-               port = &mvi->port[sas_port->id];
+               port = &mvi->port[i];
        if (lock)
                spin_lock_irqsave(&mvi->lock, flags);
        port->port_attached = 1;
@@ -1393,7 +1260,7 @@ static void mvs_port_notify_deformed(struct asd_sas_phy *sas_phy, int lock)
                        return;
        }
        list_for_each_entry(dev, &port->dev_list, dev_list_node)
-               mvs_do_release_task(phy->mvi, phy_no, NULL);
+               mvs_do_release_task(phy->mvi, phy_no, dev);
 
 }
 
@@ -1457,6 +1324,7 @@ int mvs_dev_found_notify(struct domain_device *dev, int lock)
        mvi_device->dev_status = MVS_DEV_NORMAL;
        mvi_device->dev_type = dev->dev_type;
        mvi_device->mvi_info = mvi;
+       mvi_device->sas_device = dev;
        if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) {
                int phy_id;
                u8 phy_num = parent_dev->ex_dev.num_phys;
@@ -1508,6 +1376,7 @@ void mvs_dev_gone_notify(struct domain_device *dev)
                mv_dprintk("found dev has gone.\n");
        }
        dev->lldd_dev = NULL;
+       mvi_dev->sas_device = NULL;
 
        spin_unlock_irqrestore(&mvi->lock, flags);
 }
@@ -1555,7 +1424,6 @@ static void mvs_tmf_timedout(unsigned long data)
        complete(&task->completion);
 }
 
-/* XXX */
 #define MVS_TASK_TIMEOUT 20
 static int mvs_exec_internal_tmf_task(struct domain_device *dev,
                        void *parameter, u32 para_len, struct mvs_tmf_task *tmf)
@@ -1588,7 +1456,7 @@ static int mvs_exec_internal_tmf_task(struct domain_device *dev,
                }
 
                wait_for_completion(&task->completion);
-               res = -TMF_RESP_FUNC_FAILED;
+               res = TMF_RESP_FUNC_FAILED;
                /* Even TMF timed out, return direct. */
                if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
                        if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
@@ -1638,11 +1506,10 @@ static int mvs_debug_issue_ssp_tmf(struct domain_device *dev,
                                u8 *lun, struct mvs_tmf_task *tmf)
 {
        struct sas_ssp_task ssp_task;
-       DECLARE_COMPLETION_ONSTACK(completion);
        if (!(dev->tproto & SAS_PROTOCOL_SSP))
                return TMF_RESP_FUNC_ESUPP;
 
-       strncpy((u8 *)&ssp_task.LUN, lun, 8);
+       memcpy(ssp_task.LUN, lun, 8);
 
        return mvs_exec_internal_tmf_task(dev, &ssp_task,
                                sizeof(ssp_task), tmf);
@@ -1666,7 +1533,7 @@ static int mvs_debug_I_T_nexus_reset(struct domain_device *dev)
 int mvs_lu_reset(struct domain_device *dev, u8 *lun)
 {
        unsigned long flags;
-       int i, phyno[WIDE_PORT_MAX_PHY], num , rc = TMF_RESP_FUNC_FAILED;
+       int rc = TMF_RESP_FUNC_FAILED;
        struct mvs_tmf_task tmf_task;
        struct mvs_device * mvi_dev = dev->lldd_dev;
        struct mvs_info *mvi = mvi_dev->mvi_info;
@@ -1675,10 +1542,8 @@ int mvs_lu_reset(struct domain_device *dev, u8 *lun)
        mvi_dev->dev_status = MVS_DEV_EH;
        rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task);
        if (rc == TMF_RESP_FUNC_COMPLETE) {
-               num = mvs_find_dev_phyno(dev, phyno);
                spin_lock_irqsave(&mvi->lock, flags);
-               for (i = 0; i < num; i++)
-                       mvs_release_task(mvi, dev);
+               mvs_release_task(mvi, dev);
                spin_unlock_irqrestore(&mvi->lock, flags);
        }
        /* If failed, fall-through I_T_Nexus reset */
@@ -1696,11 +1561,12 @@ int mvs_I_T_nexus_reset(struct domain_device *dev)
 
        if (mvi_dev->dev_status != MVS_DEV_EH)
                return TMF_RESP_FUNC_COMPLETE;
+       else
+               mvi_dev->dev_status = MVS_DEV_NORMAL;
        rc = mvs_debug_I_T_nexus_reset(dev);
        mv_printk("%s for device[%x]:rc= %d\n",
                __func__, mvi_dev->device_id, rc);
 
-       /* housekeeper */
        spin_lock_irqsave(&mvi->lock, flags);
        mvs_release_task(mvi, dev);
        spin_unlock_irqrestore(&mvi->lock, flags);
@@ -1739,9 +1605,6 @@ int mvs_query_task(struct sas_task *task)
                case TMF_RESP_FUNC_FAILED:
                case TMF_RESP_FUNC_COMPLETE:
                        break;
-               default:
-                       rc = TMF_RESP_FUNC_COMPLETE;
-                       break;
                }
        }
        mv_printk("%s:rc= %d\n", __func__, rc);
@@ -1761,8 +1624,8 @@ int mvs_abort_task(struct sas_task *task)
        u32 tag;
 
        if (!mvi_dev) {
-               mv_printk("%s:%d TMF_RESP_FUNC_FAILED\n", __func__, __LINE__);
-               rc = TMF_RESP_FUNC_FAILED;
+               mv_printk("Device has removed\n");
+               return TMF_RESP_FUNC_FAILED;
        }
 
        mvi = mvi_dev->mvi_info;
@@ -1807,25 +1670,17 @@ int mvs_abort_task(struct sas_task *task)
 
        } else if (task->task_proto & SAS_PROTOCOL_SATA ||
                task->task_proto & SAS_PROTOCOL_STP) {
-               /* to do free register_set */
                if (SATA_DEV == dev->dev_type) {
                        struct mvs_slot_info *slot = task->lldd_task;
-                       struct task_status_struct *tstat;
                        u32 slot_idx = (u32)(slot - mvi->slot_info);
-                       tstat = &task->task_status;
-                       mv_dprintk(KERN_DEBUG "mv_abort_task() mvi=%p task=%p "
+                       mv_dprintk("mvs_abort_task() mvi=%p task=%p "
                                   "slot=%p slot_idx=x%x\n",
                                   mvi, task, slot, slot_idx);
-                       tstat->stat = SAS_ABORTED_TASK;
-                       if (mvi_dev && mvi_dev->running_req)
-                               mvi_dev->running_req--;
-                       if (sas_protocol_ata(task->task_proto))
-                               mvs_free_reg_set(mvi, mvi_dev);
+                       mvs_tmf_timedout((unsigned long)task);
                        mvs_slot_task_free(mvi, task, slot, slot_idx);
-                       return -1;
+                       rc = TMF_RESP_FUNC_COMPLETE;
+                       goto out;
                }
-       } else {
-               /* SMP */
 
        }
 out:
@@ -1891,12 +1746,63 @@ static int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task,
        return stat;
 }
 
+void mvs_set_sense(u8 *buffer, int len, int d_sense,
+               int key, int asc, int ascq)
+{
+       memset(buffer, 0, len);
+
+       if (d_sense) {
+               /* Descriptor format */
+               if (len < 4) {
+                       mv_printk("Length %d of sense buffer too small to "
+                               "fit sense %x:%x:%x", len, key, asc, ascq);
+               }
+
+               buffer[0] = 0x72;               /* Response Code        */
+               if (len > 1)
+                       buffer[1] = key;        /* Sense Key */
+               if (len > 2)
+                       buffer[2] = asc;        /* ASC  */
+               if (len > 3)
+                       buffer[3] = ascq;       /* ASCQ */
+       } else {
+               if (len < 14) {
+                       mv_printk("Length %d of sense buffer too small to "
+                               "fit sense %x:%x:%x", len, key, asc, ascq);
+               }
+
+               buffer[0] = 0x70;               /* Response Code        */
+               if (len > 2)
+                       buffer[2] = key;        /* Sense Key */
+               if (len > 7)
+                       buffer[7] = 0x0a;       /* Additional Sense Length */
+               if (len > 12)
+                       buffer[12] = asc;       /* ASC */
+               if (len > 13)
+                       buffer[13] = ascq; /* ASCQ */
+       }
+
+       return;
+}
+
+void mvs_fill_ssp_resp_iu(struct ssp_response_iu *iu,
+                               u8 key, u8 asc, u8 asc_q)
+{
+       iu->datapres = 2;
+       iu->response_data_len = 0;
+       iu->sense_data_len = 17;
+       iu->status = 02;
+       mvs_set_sense(iu->sense_data, 17, 0,
+                       key, asc, asc_q);
+}
+
 static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
                         u32 slot_idx)
 {
        struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
        int stat;
-       u32 err_dw0 = le32_to_cpu(*(u32 *) (slot->response));
+       u32 err_dw0 = le32_to_cpu(*(u32 *)slot->response);
+       u32 err_dw1 = le32_to_cpu(*((u32 *)slot->response + 1));
        u32 tfs = 0;
        enum mvs_port_type type = PORT_TYPE_SAS;
 
@@ -1908,8 +1814,19 @@ static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
        stat = SAM_STAT_CHECK_CONDITION;
        switch (task->task_proto) {
        case SAS_PROTOCOL_SSP:
+       {
                stat = SAS_ABORTED_TASK;
+               if ((err_dw0 & NO_DEST) || err_dw1 & bit(31)) {
+                       struct ssp_response_iu *iu = slot->response +
+                               sizeof(struct mvs_err_info);
+                       mvs_fill_ssp_resp_iu(iu, NOT_READY, 0x04, 01);
+                       sas_ssp_task_response(mvi->dev, task, iu);
+                       stat = SAM_STAT_CHECK_CONDITION;
+               }
+               if (err_dw1 & bit(31))
+                       mv_printk("reuse same slot, retry command.\n");
                break;
+       }
        case SAS_PROTOCOL_SMP:
                stat = SAM_STAT_CHECK_CONDITION;
                break;
@@ -1918,10 +1835,8 @@ static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
        case SAS_PROTOCOL_STP:
        case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
        {
-               if (err_dw0 == 0x80400002)
-                       mv_printk("find reserved error, why?\n");
-
                task->ata_task.use_ncq = 0;
+               stat = SAS_PROTO_RESPONSE;
                mvs_sata_done(mvi, task, slot_idx, err_dw0);
        }
                break;
@@ -1945,8 +1860,6 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
        void *to;
        enum exec_status sts;
 
-       if (mvi->exp_req)
-               mvi->exp_req--;
        if (unlikely(!task || !task->lldd_task || !task->dev))
                return -1;
 
@@ -1954,8 +1867,6 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
        dev = task->dev;
        mvi_dev = dev->lldd_dev;
 
-       mvs_hba_cq_dump(mvi);
-
        spin_lock(&task->task_state_lock);
        task->task_state_flags &=
                ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
@@ -1978,6 +1889,7 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
                return -1;
        }
 
+       /* when no device attaching, go ahead and complete by error handling*/
        if (unlikely(!mvi_dev || flags)) {
                if (!mvi_dev)
                        mv_dprintk("port has not device.\n");
@@ -1987,6 +1899,9 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
 
        /* error info record present */
        if (unlikely((rx_desc & RXQ_ERR) && (*(u64 *) slot->response))) {
+               mv_dprintk("port %d slot %d rx_desc %X has error info"
+                       "%016llX.\n", slot->port->sas_port.id, slot_idx,
+                        rx_desc, (u64)(*(u64 *)slot->response));
                tstat->stat = mvs_slot_err(mvi, task, slot_idx);
                tstat->resp = SAS_TASK_COMPLETE;
                goto out;
@@ -2048,8 +1963,7 @@ out:
        spin_unlock(&mvi->lock);
        if (task->task_done)
                task->task_done(task);
-       else
-               mv_dprintk("why has not task_done.\n");
+
        spin_lock(&mvi->lock);
 
        return sts;
@@ -2092,7 +2006,6 @@ void mvs_release_task(struct mvs_info *mvi,
                      struct domain_device *dev)
 {
        int i, phyno[WIDE_PORT_MAX_PHY], num;
-       /* housekeeper */
        num = mvs_find_dev_phyno(dev, phyno);
        for (i = 0; i < num; i++)
                mvs_do_release_task(mvi, phyno[i], dev);
@@ -2111,13 +2024,13 @@ static void mvs_work_queue(struct work_struct *work)
        struct mvs_wq *mwq = container_of(dw, struct mvs_wq, work_q);
        struct mvs_info *mvi = mwq->mvi;
        unsigned long flags;
+       u32 phy_no = (unsigned long) mwq->data;
+       struct sas_ha_struct *sas_ha = mvi->sas;
+       struct mvs_phy *phy = &mvi->phy[phy_no];
+       struct asd_sas_phy *sas_phy = &phy->sas_phy;
 
        spin_lock_irqsave(&mvi->lock, flags);
        if (mwq->handler & PHY_PLUG_EVENT) {
-               u32 phy_no = (unsigned long) mwq->data;
-               struct sas_ha_struct *sas_ha = mvi->sas;
-               struct mvs_phy *phy = &mvi->phy[phy_no];
-               struct asd_sas_phy *sas_phy = &phy->sas_phy;
 
                if (phy->phy_event & PHY_PLUG_OUT) {
                        u32 tmp;
@@ -2139,6 +2052,11 @@ static void mvs_work_queue(struct work_struct *work)
                                mv_dprintk("phy%d Attached Device\n", phy_no);
                        }
                }
+       } else if (mwq->handler & EXP_BRCT_CHG) {
+               phy->phy_event &= ~EXP_BRCT_CHG;
+               sas_ha->notify_port_event(sas_phy,
+                               PORTE_BROADCAST_RCVD);
+               mv_dprintk("phy%d Got Broadcast Change\n", phy_no);
        }
        list_del(&mwq->entry);
        spin_unlock_irqrestore(&mvi->lock, flags);
@@ -2174,29 +2092,21 @@ static void mvs_sig_time_out(unsigned long tphy)
                if (&mvi->phy[phy_no] == phy) {
                        mv_dprintk("Get signature time out, reset phy %d\n",
                                phy_no+mvi->id*mvi->chip->n_phy);
-                       MVS_CHIP_DISP->phy_reset(mvi, phy_no, 1);
+                       MVS_CHIP_DISP->phy_reset(mvi, phy_no, MVS_HARD_RESET);
                }
        }
 }
 
-static void mvs_sig_remove_timer(struct mvs_phy *phy)
-{
-       if (phy->timer.function)
-               del_timer(&phy->timer);
-       phy->timer.function = NULL;
-}
-
 void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
 {
        u32 tmp;
-       struct sas_ha_struct *sas_ha = mvi->sas;
        struct mvs_phy *phy = &mvi->phy[phy_no];
-       struct asd_sas_phy *sas_phy = &phy->sas_phy;
 
        phy->irq_status = MVS_CHIP_DISP->read_port_irq_stat(mvi, phy_no);
-       mv_dprintk("port %d ctrl sts=0x%X.\n", phy_no+mvi->id*mvi->chip->n_phy,
+       MVS_CHIP_DISP->write_port_irq_stat(mvi, phy_no, phy->irq_status);
+       mv_dprintk("phy %d ctrl sts=0x%08X.\n", phy_no+mvi->id*mvi->chip->n_phy,
                MVS_CHIP_DISP->read_phy_ctl(mvi, phy_no));
-       mv_dprintk("Port %d irq sts = 0x%X\n", phy_no+mvi->id*mvi->chip->n_phy,
+       mv_dprintk("phy %d irq sts = 0x%08X\n", phy_no+mvi->id*mvi->chip->n_phy,
                phy->irq_status);
 
        /*
@@ -2205,11 +2115,12 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
        */
 
        if (phy->irq_status & PHYEV_DCDR_ERR) {
-               mv_dprintk("port %d STP decoding error.\n",
+               mv_dprintk("phy %d STP decoding error.\n",
                phy_no + mvi->id*mvi->chip->n_phy);
        }
 
        if (phy->irq_status & PHYEV_POOF) {
+               mdelay(500);
                if (!(phy->phy_event & PHY_PLUG_OUT)) {
                        int dev_sata = phy->phy_type & PORT_TYPE_SATA;
                        int ready;
@@ -2220,17 +2131,13 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
                                (void *)(unsigned long)phy_no,
                                PHY_PLUG_EVENT);
                        ready = mvs_is_phy_ready(mvi, phy_no);
-                       if (!ready)
-                               mv_dprintk("phy%d Unplug Notice\n",
-                                       phy_no +
-                                       mvi->id * mvi->chip->n_phy);
                        if (ready || dev_sata) {
                                if (MVS_CHIP_DISP->stp_reset)
                                        MVS_CHIP_DISP->stp_reset(mvi,
                                                        phy_no);
                                else
                                        MVS_CHIP_DISP->phy_reset(mvi,
-                                                       phy_no, 0);
+                                                       phy_no, MVS_SOFT_RESET);
                                return;
                        }
                }
@@ -2243,13 +2150,12 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
                if (phy->timer.function == NULL) {
                        phy->timer.data = (unsigned long)phy;
                        phy->timer.function = mvs_sig_time_out;
-                       phy->timer.expires = jiffies + 10*HZ;
+                       phy->timer.expires = jiffies + 5*HZ;
                        add_timer(&phy->timer);
                }
        }
        if (phy->irq_status & (PHYEV_SIG_FIS | PHYEV_ID_DONE)) {
                phy->phy_status = mvs_is_phy_ready(mvi, phy_no);
-               mvs_sig_remove_timer(phy);
                mv_dprintk("notify plug in on phy[%d]\n", phy_no);
                if (phy->phy_status) {
                        mdelay(10);
@@ -2263,14 +2169,14 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
                        }
                        mvs_update_phyinfo(mvi, phy_no, 0);
                        if (phy->phy_type & PORT_TYPE_SAS) {
-                               MVS_CHIP_DISP->phy_reset(mvi, phy_no, 2);
+                               MVS_CHIP_DISP->phy_reset(mvi, phy_no, MVS_PHY_TUNE);
                                mdelay(10);
                        }
 
                        mvs_bytes_dmaed(mvi, phy_no);
                        /* whether driver is going to handle hot plug */
                        if (phy->phy_event & PHY_PLUG_OUT) {
-                               mvs_port_notify_formed(sas_phy, 0);
+                               mvs_port_notify_formed(&phy->sas_phy, 0);
                                phy->phy_event &= ~PHY_PLUG_OUT;
                        }
                } else {
@@ -2278,13 +2184,11 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
                                phy_no + mvi->id*mvi->chip->n_phy);
                }
        } else if (phy->irq_status & PHYEV_BROAD_CH) {
-               mv_dprintk("port %d broadcast change.\n",
+               mv_dprintk("phy %d broadcast change.\n",
                        phy_no + mvi->id*mvi->chip->n_phy);
-               /* exception for Samsung disk drive*/
-               mdelay(1000);
-               sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD);
+               mvs_handle_event(mvi, (void *)(unsigned long)phy_no,
+                               EXP_BRCT_CHG);
        }
-       MVS_CHIP_DISP->write_port_irq_stat(mvi, phy_no, phy->irq_status);
 }
 
 int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
index 1367d8b..44d7885 100644 (file)
 
 #define DRV_NAME               "mvsas"
 #define DRV_VERSION            "0.8.2"
-#define _MV_DUMP               0
 #define MVS_ID_NOT_MAPPED      0x7f
-/* #define DISABLE_HOTPLUG_DMA_FIX */
-// #define MAX_EXP_RUNNING_REQ 2
 #define WIDE_PORT_MAX_PHY              4
-#define        MV_DISABLE_NCQ  0
 #define mv_printk(fmt, arg ...)        \
        printk(KERN_DEBUG"%s %d:" fmt, __FILE__, __LINE__, ## arg)
 #ifdef MV_DEBUG
@@ -64,6 +60,7 @@
 #endif
 #define MV_MAX_U32                     0xffffffff
 
+extern int interrupt_coalescing;
 extern struct mvs_tgt_initiator mvs_tgt;
 extern struct mvs_info *tgt_mvi;
 extern const struct mvs_dispatch mvs_64xx_dispatch;
@@ -99,6 +96,11 @@ enum dev_status {
        MVS_DEV_EH      = 0x1,
 };
 
+enum dev_reset {
+       MVS_SOFT_RESET  = 0,
+       MVS_HARD_RESET  = 1,
+       MVS_PHY_TUNE    = 2,
+};
 
 struct mvs_info;
 
@@ -130,7 +132,6 @@ struct mvs_dispatch {
        u32 (*read_port_irq_mask)(struct mvs_info *mvi, u32 port);
        void (*write_port_irq_mask)(struct mvs_info *mvi, u32 port, u32 val);
 
-       void (*get_sas_addr)(void *buf, u32 buflen);
        void (*command_active)(struct mvs_info *mvi, u32 slot_idx);
        void (*clear_srs_irq)(struct mvs_info *mvi, u8 reg_set, u8 clear_all);
        void (*issue_stop)(struct mvs_info *mvi, enum mvs_port_type type,
@@ -167,9 +168,10 @@ struct mvs_dispatch {
                                                );
        int (*spi_issuecmd)(struct mvs_info *mvi, u32 cmd);
        int (*spi_waitdataready)(struct mvs_info *mvi, u32 timeout);
-#ifndef DISABLE_HOTPLUG_DMA_FIX
-       void (*dma_fix)(dma_addr_t buf_dma, int buf_len, int from, void *prd);
-#endif
+       void (*dma_fix)(struct mvs_info *mvi, u32 phy_mask,
+                               int buf_len, int from, void *prd);
+       void (*tune_interrupt)(struct mvs_info *mvi, u32 time);
+       void (*non_spec_ncq_error)(struct mvs_info *mvi);
 
 };
 
@@ -179,9 +181,11 @@ struct mvs_chip_info {
        u32             fis_offs;
        u32             fis_count;
        u32             srs_sz;
+       u32             sg_width;
        u32             slot_width;
        const struct mvs_dispatch *dispatch;
 };
+#define MVS_MAX_SG             (1U << mvi->chip->sg_width)
 #define MVS_CHIP_SLOT_SZ       (1U << mvi->chip->slot_width)
 #define MVS_RX_FISL_SZ         \
        (mvi->chip->fis_offs + (mvi->chip->fis_count * 0x100))
@@ -249,6 +253,73 @@ struct mvs_device {
        u16 reserved;
 };
 
+/* Generate  PHY tunning parameters */
+struct phy_tuning {
+       /* 1 bit,  transmitter emphasis enable  */
+       u8      trans_emp_en:1;
+       /* 4 bits, transmitter emphasis amplitude */
+       u8      trans_emp_amp:4;
+       /* 3 bits, reserved space */
+       u8      Reserved_2bit_1:3;
+       /* 5 bits, transmitter amplitude */
+       u8      trans_amp:5;
+       /* 2 bits, transmitter amplitude adjust */
+       u8      trans_amp_adj:2;
+       /* 1 bit, reserved space */
+       u8      resv_2bit_2:1;
+       /* 2 bytes, reserved space */
+       u8      reserved[2];
+};
+
+struct ffe_control {
+       /* 4 bits,  FFE Capacitor Select  (value range 0~F)  */
+       u8 ffe_cap_sel:4;
+       /* 3 bits,  FFE Resistor Select (value range 0~7) */
+       u8 ffe_rss_sel:3;
+       /* 1 bit reserve*/
+       u8 reserved:1;
+};
+
+/*
+ * HBA_Info_Page is saved in Flash/NVRAM, total 256 bytes.
+ * The data area is valid only Signature="MRVL".
+ * If any member fills with 0xFF, the member is invalid.
+ */
+struct hba_info_page {
+       /* Dword 0 */
+       /* 4 bytes, structure signature,should be "MRVL" at first initial */
+       u8 signature[4];
+
+       /* Dword 1-13 */
+       u32 reserved1[13];
+
+       /* Dword 14-29 */
+       /* 64 bytes, SAS address for each port */
+       u64 sas_addr[8];
+
+       /* Dword 30-31 */
+       /* 8 bytes for vanir 8 port PHY FFE seeting
+        * BIT 0~3 : FFE Capacitor select(value range 0~F)
+        * BIT 4~6 : FFE Resistor select(value range 0~7)
+        * BIT 7: reserve.
+        */
+
+       struct ffe_control  ffe_ctl[8];
+       /* Dword 32 -43 */
+       u32 reserved2[12];
+
+       /* Dword 44-45 */
+       /* 8 bytes,  0:  1.5G, 1: 3.0G, should be 0x01 at first initial */
+       u8 phy_rate[8];
+
+       /* Dword 46-53 */
+       /* 32 bytes, PHY tuning parameters for each PHY*/
+       struct phy_tuning   phy_tuning[8];
+
+       /* Dword 54-63 */
+       u32 reserved3[10];
+};     /* total 256 bytes */
+
 struct mvs_slot_info {
        struct list_head entry;
        union {
@@ -264,9 +335,6 @@ struct mvs_slot_info {
         */
        void *buf;
        dma_addr_t buf_dma;
-#if _MV_DUMP
-       u32 cmd_size;
-#endif
        void *response;
        struct mvs_port *port;
        struct mvs_device       *device;
@@ -320,12 +388,10 @@ struct mvs_info {
        const struct mvs_chip_info *chip;
 
        int tags_num;
-       DECLARE_BITMAP(tags, MVS_SLOTS);
+       unsigned long *tags;
        /* further per-slot information */
        struct mvs_phy phy[MVS_MAX_PHYS];
        struct mvs_port port[MVS_MAX_PHYS];
-       u32 irq;
-       u32 exp_req;
        u32 id;
        u64 sata_reg_set;
        struct list_head *hba_list;
@@ -337,12 +403,13 @@ struct mvs_info {
        u32 flashsectSize;
 
        void *addon;
+       struct hba_info_page hba_info_param;
        struct mvs_device       devices[MVS_MAX_DEVICES];
-#ifndef DISABLE_HOTPLUG_DMA_FIX
        void *bulk_buffer;
        dma_addr_t bulk_buffer_dma;
+       void *bulk_buffer1;
+       dma_addr_t bulk_buffer_dma1;
 #define TRASH_BUCKET_SIZE      0x20000
-#endif
        void *dma_pool;
        struct mvs_slot_info slot_info[0];
 };
@@ -350,8 +417,10 @@ struct mvs_info {
 struct mvs_prv_info{
        u8 n_host;
        u8 n_phy;
-       u16 reserve;
+       u8 scan_finished;
+       u8 reserve;
        struct mvs_info *mvi[2];
+       struct tasklet_struct mv_tasklet;
 };
 
 struct mvs_wq {
@@ -415,6 +484,6 @@ void mvs_do_release_task(struct mvs_info *mvi, int phy_no,
 void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events);
 void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st);
 int mvs_int_rx(struct mvs_info *mvi, bool self_clear);
-void mvs_hexdump(u32 size, u8 *data, u32 baseaddr);
+struct mvs_device *mvs_find_dev_by_reg_set(struct mvs_info *mvi, u8 reg_set);
 #endif
 
index fca6a89..d079f9a 100644 (file)
@@ -3871,6 +3871,9 @@ static long pmcraid_ioctl_passthrough(
                        pmcraid_err("couldn't build passthrough ioadls\n");
                        goto out_free_buffer;
                }
+       } else if (request_size < 0) {
+               rc = -EINVAL;
+               goto out_free_buffer;
        }
 
        /* If data is being written into the device, copy the data from user
index 532313e..7836eb0 100644 (file)
@@ -42,8 +42,8 @@ qla2x00_sysfs_write_fw_dump(struct file *filp, struct kobject *kobj,
        int reading;
 
        if (IS_QLA82XX(ha)) {
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                       "Firmware dump not supported for ISP82xx\n"));
+               ql_dbg(ql_dbg_user, vha, 0x705b,
+                   "Firmware dump not supported for ISP82xx\n");
                return count;
        }
 
@@ -56,7 +56,7 @@ qla2x00_sysfs_write_fw_dump(struct file *filp, struct kobject *kobj,
                if (!ha->fw_dump_reading)
                        break;
 
-               qla_printk(KERN_INFO, ha,
+               ql_log(ql_log_info, vha, 0x705d,
                    "Firmware dump cleared on (%ld).\n", vha->host_no);
 
                ha->fw_dump_reading = 0;
@@ -66,7 +66,7 @@ qla2x00_sysfs_write_fw_dump(struct file *filp, struct kobject *kobj,
                if (ha->fw_dumped && !ha->fw_dump_reading) {
                        ha->fw_dump_reading = 1;
 
-                       qla_printk(KERN_INFO, ha,
+                       ql_log(ql_log_info, vha, 0x705e,
                            "Raw firmware dump ready for read on (%ld).\n",
                            vha->host_no);
                }
@@ -148,7 +148,7 @@ qla2x00_sysfs_write_nvram(struct file *filp, struct kobject *kobj,
        }
 
        if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x705f,
                    "HBA not online, failing NVRAM update.\n");
                return -EAGAIN;
        }
@@ -158,6 +158,8 @@ qla2x00_sysfs_write_nvram(struct file *filp, struct kobject *kobj,
        ha->isp_ops->read_nvram(vha, (uint8_t *)ha->nvram, ha->nvram_base,
            count);
 
+       ql_dbg(ql_dbg_user, vha, 0x7060,
+           "Setting ISP_ABORT_NEEDED\n");
        /* NVRAM settings take effect immediately. */
        set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
        qla2xxx_wake_dpc(vha);
@@ -255,9 +257,9 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
 
                ha->optrom_state = QLA_SWAITING;
 
-               DEBUG2(qla_printk(KERN_INFO, ha,
+               ql_dbg(ql_dbg_user, vha, 0x7061,
                    "Freeing flash region allocation -- 0x%x bytes.\n",
-                   ha->optrom_region_size));
+                   ha->optrom_region_size);
 
                vfree(ha->optrom_buffer);
                ha->optrom_buffer = NULL;
@@ -273,7 +275,7 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
                ha->optrom_state = QLA_SREADING;
                ha->optrom_buffer = vmalloc(ha->optrom_region_size);
                if (ha->optrom_buffer == NULL) {
-                       qla_printk(KERN_WARNING, ha,
+                       ql_log(ql_log_warn, vha, 0x7062,
                            "Unable to allocate memory for optrom retrieval "
                            "(%x).\n", ha->optrom_region_size);
 
@@ -282,14 +284,14 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
                }
 
                if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
-                       qla_printk(KERN_WARNING, ha,
-                               "HBA not online, failing NVRAM update.\n");
+                       ql_log(ql_log_warn, vha, 0x7063,
+                           "HBA not online, failing NVRAM update.\n");
                        return -EAGAIN;
                }
 
-               DEBUG2(qla_printk(KERN_INFO, ha,
+               ql_dbg(ql_dbg_user, vha, 0x7064,
                    "Reading flash region -- 0x%x/0x%x.\n",
-                   ha->optrom_region_start, ha->optrom_region_size));
+                   ha->optrom_region_start, ha->optrom_region_size);
 
                memset(ha->optrom_buffer, 0, ha->optrom_region_size);
                ha->isp_ops->read_optrom(vha, ha->optrom_buffer,
@@ -328,7 +330,7 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
                else if (IS_QLA25XX(ha) || IS_QLA8XXX_TYPE(ha))
                        valid = 1;
                if (!valid) {
-                       qla_printk(KERN_WARNING, ha,
+                       ql_log(ql_log_warn, vha, 0x7065,
                            "Invalid start region 0x%x/0x%x.\n", start, size);
                        return -EINVAL;
                }
@@ -340,17 +342,17 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
                ha->optrom_state = QLA_SWRITING;
                ha->optrom_buffer = vmalloc(ha->optrom_region_size);
                if (ha->optrom_buffer == NULL) {
-                       qla_printk(KERN_WARNING, ha,
+                       ql_log(ql_log_warn, vha, 0x7066,
                            "Unable to allocate memory for optrom update "
-                           "(%x).\n", ha->optrom_region_size);
+                           "(%x)\n", ha->optrom_region_size);
 
                        ha->optrom_state = QLA_SWAITING;
                        return count;
                }
 
-               DEBUG2(qla_printk(KERN_INFO, ha,
+               ql_dbg(ql_dbg_user, vha, 0x7067,
                    "Staging flash region write -- 0x%x/0x%x.\n",
-                   ha->optrom_region_start, ha->optrom_region_size));
+                   ha->optrom_region_start, ha->optrom_region_size);
 
                memset(ha->optrom_buffer, 0, ha->optrom_region_size);
                break;
@@ -359,14 +361,14 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
                        break;
 
                if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
-                       qla_printk(KERN_WARNING, ha,
+                       ql_log(ql_log_warn, vha, 0x7068,
                            "HBA not online, failing flash update.\n");
                        return -EAGAIN;
                }
 
-               DEBUG2(qla_printk(KERN_INFO, ha,
+               ql_dbg(ql_dbg_user, vha, 0x7069,
                    "Writing flash region -- 0x%x/0x%x.\n",
-                   ha->optrom_region_start, ha->optrom_region_size));
+                   ha->optrom_region_start, ha->optrom_region_size);
 
                ha->isp_ops->write_optrom(vha, ha->optrom_buffer,
                    ha->optrom_region_start, ha->optrom_region_size);
@@ -425,7 +427,7 @@ qla2x00_sysfs_write_vpd(struct file *filp, struct kobject *kobj,
                return 0;
 
        if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x706a,
                    "HBA not online, failing VPD update.\n");
                return -EAGAIN;
        }
@@ -440,7 +442,7 @@ qla2x00_sysfs_write_vpd(struct file *filp, struct kobject *kobj,
 
        tmp_data = vmalloc(256);
        if (!tmp_data) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x706b,
                    "Unable to allocate memory for VPD information update.\n");
                goto done;
        }
@@ -480,7 +482,7 @@ qla2x00_sysfs_read_sfp(struct file *filp, struct kobject *kobj,
        ha->sfp_data = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
            &ha->sfp_data_dma);
        if (!ha->sfp_data) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x706c,
                    "Unable to allocate memory for SFP read-data.\n");
                return 0;
        }
@@ -499,9 +501,10 @@ do_read:
                rval = qla2x00_read_sfp(vha, ha->sfp_data_dma, ha->sfp_data,
                    addr, offset, SFP_BLOCK_SIZE, 0);
                if (rval != QLA_SUCCESS) {
-                       qla_printk(KERN_WARNING, ha,
+                       ql_log(ql_log_warn, vha, 0x706d,
                            "Unable to read SFP data (%x/%x/%x).\n", rval,
                            addr, offset);
+
                        count = 0;
                        break;
                }
@@ -538,8 +541,8 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
        type = simple_strtol(buf, NULL, 10);
        switch (type) {
        case 0x2025c:
-               qla_printk(KERN_INFO, ha,
-                   "Issuing ISP reset on (%ld).\n", vha->host_no);
+               ql_log(ql_log_info, vha, 0x706e,
+                   "Issuing ISP reset.\n");
 
                scsi_block_requests(vha->host);
                set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
@@ -551,8 +554,8 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
                if (!IS_QLA81XX(ha))
                        break;
 
-               qla_printk(KERN_INFO, ha,
-                   "Issuing MPI reset on (%ld).\n", vha->host_no);
+               ql_log(ql_log_info, vha, 0x706f,
+                   "Issuing MPI reset.\n");
 
                /* Make sure FC side is not in reset */
                qla2x00_wait_for_hba_online(vha);
@@ -560,20 +563,19 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
                /* Issue MPI reset */
                scsi_block_requests(vha->host);
                if (qla81xx_restart_mpi_firmware(vha) != QLA_SUCCESS)
-                       qla_printk(KERN_WARNING, ha,
-                           "MPI reset failed on (%ld).\n", vha->host_no);
+                       ql_log(ql_log_warn, vha, 0x7070,
+                           "MPI reset failed.\n");
                scsi_unblock_requests(vha->host);
                break;
        case 0x2025e:
                if (!IS_QLA82XX(ha) || vha != base_vha) {
-                       qla_printk(KERN_INFO, ha,
-                           "FCoE ctx reset not supported for host%ld.\n",
-                           vha->host_no);
+                       ql_log(ql_log_info, vha, 0x7071,
+                           "FCoE ctx reset no supported.\n");
                        return count;
                }
 
-               qla_printk(KERN_INFO, ha,
-                   "Issuing FCoE CTX reset on host%ld.\n", vha->host_no);
+               ql_log(ql_log_info, vha, 0x7072,
+                   "Issuing FCoE ctx reset.\n");
                set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
                qla2xxx_wake_dpc(vha);
                qla2x00_wait_for_fcoe_ctx_reset(vha);
@@ -611,8 +613,8 @@ qla2x00_sysfs_write_edc(struct file *filp, struct kobject *kobj,
                ha->edc_data = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
                    &ha->edc_data_dma);
                if (!ha->edc_data) {
-                       DEBUG2(qla_printk(KERN_INFO, ha,
-                           "Unable to allocate memory for EDC write.\n"));
+                       ql_log(ql_log_warn, vha, 0x7073,
+                           "Unable to allocate memory for EDC write.\n");
                        return 0;
                }
        }
@@ -631,9 +633,9 @@ qla2x00_sysfs_write_edc(struct file *filp, struct kobject *kobj,
        rval = qla2x00_write_sfp(vha, ha->edc_data_dma, ha->edc_data,
            dev, adr, len, opt);
        if (rval != QLA_SUCCESS) {
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                   "Unable to write EDC (%x) %02x:%02x:%04x:%02x:%02x.\n",
-                   rval, dev, adr, opt, len, buf[8]));
+               ql_log(ql_log_warn, vha, 0x7074,
+                   "Unable to write EDC (%x) %02x:%04x:%02x:%02x\n",
+                   rval, dev, adr, opt, len, buf[8]);
                return 0;
        }
 
@@ -669,8 +671,8 @@ qla2x00_sysfs_write_edc_status(struct file *filp, struct kobject *kobj,
                ha->edc_data = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
                    &ha->edc_data_dma);
                if (!ha->edc_data) {
-                       DEBUG2(qla_printk(KERN_INFO, ha,
-                           "Unable to allocate memory for EDC status.\n"));
+                       ql_log(ql_log_warn, vha, 0x708c,
+                           "Unable to allocate memory for EDC status.\n");
                        return 0;
                }
        }
@@ -688,9 +690,9 @@ qla2x00_sysfs_write_edc_status(struct file *filp, struct kobject *kobj,
        rval = qla2x00_read_sfp(vha, ha->edc_data_dma, ha->edc_data,
                        dev, adr, len, opt);
        if (rval != QLA_SUCCESS) {
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                   "Unable to write EDC status (%x) %02x:%02x:%04x:%02x.\n",
-                   rval, dev, adr, opt, len));
+               ql_log(ql_log_info, vha, 0x7075,
+                   "Unable to write EDC status (%x) %02x:%04x:%02x.\n",
+                   rval, dev, adr, opt, len);
                return 0;
        }
 
@@ -749,7 +751,7 @@ qla2x00_sysfs_read_xgmac_stats(struct file *filp, struct kobject *kobj,
        ha->xgmac_data = dma_alloc_coherent(&ha->pdev->dev, XGMAC_DATA_SIZE,
            &ha->xgmac_data_dma, GFP_KERNEL);
        if (!ha->xgmac_data) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x7076,
                    "Unable to allocate memory for XGMAC read-data.\n");
                return 0;
        }
@@ -761,7 +763,7 @@ do_read:
        rval = qla2x00_get_xgmac_stats(vha, ha->xgmac_data_dma,
            XGMAC_DATA_SIZE, &actual_size);
        if (rval != QLA_SUCCESS) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x7077,
                    "Unable to read XGMAC data (%x).\n", rval);
                count = 0;
        }
@@ -801,7 +803,7 @@ qla2x00_sysfs_read_dcbx_tlv(struct file *filp, struct kobject *kobj,
        ha->dcbx_tlv = dma_alloc_coherent(&ha->pdev->dev, DCBX_TLV_DATA_SIZE,
            &ha->dcbx_tlv_dma, GFP_KERNEL);
        if (!ha->dcbx_tlv) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x7078,
                    "Unable to allocate memory for DCBX TLV read-data.\n");
                return 0;
        }
@@ -813,8 +815,8 @@ do_read:
        rval = qla2x00_get_dcbx_params(vha, ha->dcbx_tlv_dma,
            DCBX_TLV_DATA_SIZE);
        if (rval != QLA_SUCCESS) {
-               qla_printk(KERN_WARNING, ha,
-                   "Unable to read DCBX TLV data (%x).\n", rval);
+               ql_log(ql_log_warn, vha, 0x7079,
+                   "Unable to read DCBX TLV (%x).\n", rval);
                count = 0;
        }
 
@@ -869,9 +871,13 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *vha)
                ret = sysfs_create_bin_file(&host->shost_gendev.kobj,
                    iter->attr);
                if (ret)
-                       qla_printk(KERN_INFO, vha->hw,
-                           "Unable to create sysfs %s binary attribute "
-                           "(%d).\n", iter->name, ret);
+                       ql_log(ql_log_warn, vha, 0x00f3,
+                           "Unable to create sysfs %s binary attribute (%d).\n",
+                           iter->name, ret);
+               else
+                       ql_dbg(ql_dbg_init, vha, 0x00f4,
+                           "Successfully created sysfs %s binary attribure.\n",
+                           iter->name);
        }
 }
 
@@ -1126,7 +1132,7 @@ qla2x00_beacon_store(struct device *dev, struct device_attribute *attr,
                return -EPERM;
 
        if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x707a,
                    "Abort ISP active -- ignoring beacon request.\n");
                return -EBUSY;
        }
@@ -1322,9 +1328,8 @@ qla2x00_thermal_temp_show(struct device *dev,
        temp = frac = 0;
        if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
            test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags))
-               DEBUG2_3_11(printk(KERN_WARNING
-                   "%s(%ld): isp reset in progress.\n",
-                   __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x707b,
+                   "ISP reset active.\n");
        else if (!vha->hw->flags.eeh_busy)
                rval = qla2x00_get_thermal_temp(vha, &temp, &frac);
        if (rval != QLA_SUCCESS)
@@ -1343,8 +1348,8 @@ qla2x00_fw_state_show(struct device *dev, struct device_attribute *attr,
 
        if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
                test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags))
-               DEBUG2_3_11(printk("%s(%ld): isp reset in progress.\n",
-                       __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x707c,
+                   "ISP reset active.\n");
        else if (!vha->hw->flags.eeh_busy)
                rval = qla2x00_get_firmware_state(vha, state);
        if (rval != QLA_SUCCESS)
@@ -1645,8 +1650,8 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
 
        stats = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &stats_dma);
        if (stats == NULL) {
-               DEBUG2_3_11(printk("%s(%ld): Failed to allocate memory.\n",
-                   __func__, base_vha->host_no));
+               ql_log(ql_log_warn, vha, 0x707d,
+                   "Failed to allocate memory for stats.\n");
                goto done;
        }
        memset(stats, 0, DMA_POOL_SIZE);
@@ -1746,15 +1751,14 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
 
        ret = qla24xx_vport_create_req_sanity_check(fc_vport);
        if (ret) {
-               DEBUG15(printk("qla24xx_vport_create_req_sanity_check failed, "
-                   "status %x\n", ret));
+               ql_log(ql_log_warn, vha, 0x707e,
+                   "Vport sanity check failed, status %x\n", ret);
                return (ret);
        }
 
        vha = qla24xx_create_vhost(fc_vport);
        if (vha == NULL) {
-               DEBUG15(printk ("qla24xx_create_vhost failed, vha = %p\n",
-                   vha));
+               ql_log(ql_log_warn, vha, 0x707f, "Vport create host failed.\n");
                return FC_VPORT_FAILED;
        }
        if (disable) {
@@ -1764,8 +1768,8 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
                atomic_set(&vha->vp_state, VP_FAILED);
 
        /* ready to create vport */
-       qla_printk(KERN_INFO, vha->hw, "VP entry id %d assigned.\n",
-                                                       vha->vp_idx);
+       ql_log(ql_log_info, vha, 0x7080,
+           "VP entry id %d assigned.\n", vha->vp_idx);
 
        /* initialized vport states */
        atomic_set(&vha->loop_state, LOOP_DOWN);
@@ -1775,8 +1779,8 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
        if (atomic_read(&base_vha->loop_state) == LOOP_DOWN ||
            atomic_read(&base_vha->loop_state) == LOOP_DEAD) {
                /* Don't retry or attempt login of this virtual port */
-               DEBUG15(printk ("scsi(%ld): pport loop_state is not UP.\n",
-                   base_vha->host_no));
+               ql_dbg(ql_dbg_user, vha, 0x7081,
+                   "Vport loop state is not UP.\n");
                atomic_set(&vha->loop_state, LOOP_DEAD);
                if (!disable)
                        fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN);
@@ -1785,9 +1789,8 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
        if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif) {
                if (ha->fw_attributes & BIT_4) {
                        vha->flags.difdix_supported = 1;
-                       DEBUG18(qla_printk(KERN_INFO, ha,
-                           "Registering for DIF/DIX type 1 and 3"
-                           " protection.\n"));
+                       ql_dbg(ql_dbg_user, vha, 0x7082,
+                           "Registered for DIF/DIX type 1 and 3 protection.\n");
                        scsi_host_set_prot(vha->host,
                            SHOST_DIF_TYPE1_PROTECTION
                            | SHOST_DIF_TYPE2_PROTECTION
@@ -1802,8 +1805,8 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
 
        if (scsi_add_host_with_dma(vha->host, &fc_vport->dev,
                                   &ha->pdev->dev)) {
-               DEBUG15(printk("scsi(%ld): scsi_add_host failure for VP[%d].\n",
-                       vha->host_no, vha->vp_idx));
+               ql_dbg(ql_dbg_user, vha, 0x7083,
+                   "scsi_add_host failure for VP[%d].\n", vha->vp_idx);
                goto vport_create_failed_2;
        }
 
@@ -1820,6 +1823,10 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
 
        if (ha->flags.cpu_affinity_enabled) {
                req = ha->req_q_map[1];
+               ql_dbg(ql_dbg_multiq, vha, 0xc000,
+                   "Request queue %p attached with "
+                   "VP[%d], cpu affinity =%d\n",
+                   req, vha->vp_idx, ha->flags.cpu_affinity_enabled);
                goto vport_queue;
        } else if (ql2xmaxqueues == 1 || !ha->npiv_info)
                goto vport_queue;
@@ -1836,13 +1843,16 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
                ret = qla25xx_create_req_que(ha, options, vha->vp_idx, 0, 0,
                        qos);
                if (!ret)
-                       qla_printk(KERN_WARNING, ha,
-                       "Can't create request queue for vp_idx:%d\n",
-                       vha->vp_idx);
+                       ql_log(ql_log_warn, vha, 0x7084,
+                           "Can't create request queue for VP[%d]\n",
+                           vha->vp_idx);
                else {
-                       DEBUG2(qla_printk(KERN_INFO, ha,
-                       "Request Que:%d (QoS: %d) created for vp_idx:%d\n",
-                       ret, qos, vha->vp_idx));
+                       ql_dbg(ql_dbg_multiq, vha, 0xc001,
+                           "Request Que:%d Q0s: %d) created for VP[%d]\n",
+                           ret, qos, vha->vp_idx);
+                       ql_dbg(ql_dbg_user, vha, 0x7085,
+                           "Request Que:%d Q0s: %d) created for VP[%d]\n",
+                           ret, qos, vha->vp_idx);
                        req = ha->req_q_map[ret];
                }
        }
@@ -1882,12 +1892,13 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
 
        if (vha->timer_active) {
                qla2x00_vp_stop_timer(vha);
-               DEBUG15(printk(KERN_INFO "scsi(%ld): timer for the vport[%d]"
-               " = %p has stopped\n", vha->host_no, vha->vp_idx, vha));
+               ql_dbg(ql_dbg_user, vha, 0x7086,
+                   "Timer for the VP[%d] has stopped\n", vha->vp_idx);
        }
 
        /* No pending activities shall be there on the vha now */
-       DEBUG(msleep(random32()%10));  /* Just to see if something falls on
+       if (ql2xextended_error_logging & ql_dbg_user)
+               msleep(random32()%10);  /* Just to see if something falls on
                                        * the net we have placed below */
 
        BUG_ON(atomic_read(&vha->vref_count));
@@ -1901,12 +1912,12 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
 
        if (vha->req->id && !ha->flags.cpu_affinity_enabled) {
                if (qla25xx_delete_req_que(vha, vha->req) != QLA_SUCCESS)
-                       qla_printk(KERN_WARNING, ha,
-                               "Queue delete failed.\n");
+                       ql_log(ql_log_warn, vha, 0x7087,
+                           "Queue delete failed.\n");
        }
 
        scsi_host_put(vha->host);
-       qla_printk(KERN_INFO, ha, "vport %d deleted\n", id);
+       ql_log(ql_log_info, vha, 0x7088, "VP[%d] deleted.\n", id);
        return 0;
 }
 
index 8c10e2c..07d1767 100644 (file)
@@ -36,7 +36,8 @@ done:
 }
 
 int
-qla24xx_fcp_prio_cfg_valid(struct qla_fcp_prio_cfg *pri_cfg, uint8_t flag)
+qla24xx_fcp_prio_cfg_valid(scsi_qla_host_t *vha,
+       struct qla_fcp_prio_cfg *pri_cfg, uint8_t flag)
 {
        int i, ret, num_valid;
        uint8_t *bcode;
@@ -51,18 +52,17 @@ qla24xx_fcp_prio_cfg_valid(struct qla_fcp_prio_cfg *pri_cfg, uint8_t flag)
 
        if (bcode_val == 0xFFFFFFFF) {
                /* No FCP Priority config data in flash */
-               DEBUG2(printk(KERN_INFO
-                   "%s: No FCP priority config data.\n",
-                   __func__));
+               ql_dbg(ql_dbg_user, vha, 0x7051,
+                   "No FCP Priority config data.\n");
                return 0;
        }
 
        if (bcode[0] != 'H' || bcode[1] != 'Q' || bcode[2] != 'O' ||
                        bcode[3] != 'S') {
                /* Invalid FCP priority data header*/
-               DEBUG2(printk(KERN_ERR
-                   "%s: Invalid FCP Priority data header. bcode=0x%x\n",
-                   __func__, bcode_val));
+               ql_dbg(ql_dbg_user, vha, 0x7052,
+                   "Invalid FCP Priority data header. bcode=0x%x.\n",
+                   bcode_val);
                return 0;
        }
        if (flag != 1)
@@ -77,15 +77,14 @@ qla24xx_fcp_prio_cfg_valid(struct qla_fcp_prio_cfg *pri_cfg, uint8_t flag)
 
        if (num_valid == 0) {
                /* No valid FCP priority data entries */
-               DEBUG2(printk(KERN_ERR
-                   "%s: No valid FCP Priority data entries.\n",
-                   __func__));
+               ql_dbg(ql_dbg_user, vha, 0x7053,
+                   "No valid FCP Priority data entries.\n");
                ret = 0;
        } else {
                /* FCP priority data is valid */
-               DEBUG2(printk(KERN_INFO
-                   "%s: Valid FCP priority data. num entries = %d\n",
-                   __func__, num_valid));
+               ql_dbg(ql_dbg_user, vha, 0x7054,
+                   "Valid FCP priority data. num entries = %d.\n",
+                   num_valid);
        }
 
        return ret;
@@ -182,10 +181,9 @@ qla24xx_proc_fcp_prio_cfg_cmd(struct fc_bsg_job *bsg_job)
                if (!ha->fcp_prio_cfg) {
                        ha->fcp_prio_cfg = vmalloc(FCP_PRIO_CFG_SIZE);
                        if (!ha->fcp_prio_cfg) {
-                               qla_printk(KERN_WARNING, ha,
-                                       "Unable to allocate memory "
-                                       "for fcp prio config data (%x).\n",
-                                       FCP_PRIO_CFG_SIZE);
+                               ql_log(ql_log_warn, vha, 0x7050,
+                                   "Unable to allocate memory for fcp prio "
+                                   "config data (%x).\n", FCP_PRIO_CFG_SIZE);
                                bsg_job->reply->result = (DID_ERROR << 16);
                                ret = -ENOMEM;
                                goto exit_fcp_prio_cfg;
@@ -198,9 +196,9 @@ qla24xx_proc_fcp_prio_cfg_cmd(struct fc_bsg_job *bsg_job)
                        FCP_PRIO_CFG_SIZE);
 
                /* validate fcp priority data */
-               if (!qla24xx_fcp_prio_cfg_valid(
-                       (struct qla_fcp_prio_cfg *)
-                       ha->fcp_prio_cfg, 1)) {
+
+               if (!qla24xx_fcp_prio_cfg_valid(vha,
+                   (struct qla_fcp_prio_cfg *) ha->fcp_prio_cfg, 1)) {
                        bsg_job->reply->result = (DID_ERROR << 16);
                        ret = -EINVAL;
                        /* If buffer was invalidatic int
@@ -256,9 +254,8 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job)
 
        /* pass through is supported only for ISP 4Gb or higher */
        if (!IS_FWI2_CAPABLE(ha)) {
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                   "scsi(%ld):ELS passthru not supported for ISP23xx based "
-                   "adapters\n", vha->host_no));
+               ql_dbg(ql_dbg_user, vha, 0x7001,
+                   "ELS passthru not supported for ISP23xx based adapters.\n");
                rval = -EPERM;
                goto done;
        }
@@ -266,11 +263,11 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job)
        /*  Multiple SG's are not supported for ELS requests */
        if (bsg_job->request_payload.sg_cnt > 1 ||
                bsg_job->reply_payload.sg_cnt > 1) {
-               DEBUG2(printk(KERN_INFO
-                       "multiple SG's are not supported for ELS requests"
-                       " [request_sg_cnt: %x reply_sg_cnt: %x]\n",
-                       bsg_job->request_payload.sg_cnt,
-                       bsg_job->reply_payload.sg_cnt));
+               ql_dbg(ql_dbg_user, vha, 0x7002,
+                   "Multiple SG's are not suppored for ELS requests, "
+                   "request_sg_cnt=%x reply_sg_cnt=%x.\n",
+                   bsg_job->request_payload.sg_cnt,
+                   bsg_job->reply_payload.sg_cnt);
                rval = -EPERM;
                goto done;
        }
@@ -281,9 +278,9 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job)
                 * if not perform fabric login
                 */
                if (qla2x00_fabric_login(vha, fcport, &nextlid)) {
-                       DEBUG2(qla_printk(KERN_WARNING, ha,
-                       "failed to login port %06X for ELS passthru\n",
-                       fcport->d_id.b24));
+                       ql_dbg(ql_dbg_user, vha, 0x7003,
+                           "Failed to login port %06X for ELS passthru.\n",
+                           fcport->d_id.b24);
                        rval = -EIO;
                        goto done;
                }
@@ -314,8 +311,7 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job)
        }
 
        if (!vha->flags.online) {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-               "host not online\n"));
+               ql_log(ql_log_warn, vha, 0x7005, "Host not online.\n");
                rval = -EIO;
                goto done;
        }
@@ -337,12 +333,11 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job)
 
        if ((req_sg_cnt !=  bsg_job->request_payload.sg_cnt) ||
                (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) {
-               DEBUG2(printk(KERN_INFO
-                       "dma mapping resulted in different sg counts \
-                       [request_sg_cnt: %x dma_request_sg_cnt: %x\
-                       reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n",
-                       bsg_job->request_payload.sg_cnt, req_sg_cnt,
-                       bsg_job->reply_payload.sg_cnt, rsp_sg_cnt));
+               ql_log(ql_log_warn, vha, 0x7008,
+                   "dma mapping resulted in different sg counts, "
+                   "request_sg_cnt: %x dma_request_sg_cnt:%x reply_sg_cnt:%x "
+                   "dma_reply_sg_cnt:%x.\n", bsg_job->request_payload.sg_cnt,
+                   req_sg_cnt, bsg_job->reply_payload.sg_cnt, rsp_sg_cnt);
                rval = -EAGAIN;
                goto done_unmap_sg;
        }
@@ -363,15 +358,16 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job)
                "bsg_els_rpt" : "bsg_els_hst");
        els->u.bsg_job = bsg_job;
 
-       DEBUG2(qla_printk(KERN_INFO, ha,
-               "scsi(%ld:%x): bsg rqst type: %s els type: %x - loop-id=%x "
-               "portid=%02x%02x%02x.\n", vha->host_no, sp->handle, type,
-               bsg_job->request->rqst_data.h_els.command_code,
-               fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area,
-               fcport->d_id.b.al_pa));
+       ql_dbg(ql_dbg_user, vha, 0x700a,
+           "bsg rqst type: %s els type: %x - loop-id=%x "
+           "portid=%-2x%02x%02x.\n", type,
+           bsg_job->request->rqst_data.h_els.command_code, fcport->loop_id,
+           fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa);
 
        rval = qla2x00_start_sp(sp);
        if (rval != QLA_SUCCESS) {
+               ql_log(ql_log_warn, vha, 0x700e,
+                   "qla2x00_start_sp failed = %d\n", rval);
                kfree(sp->ctx);
                mempool_free(sp, ha->srb_mempool);
                rval = -EIO;
@@ -411,6 +407,8 @@ qla2x00_process_ct(struct fc_bsg_job *bsg_job)
                dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
                        bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
        if (!req_sg_cnt) {
+               ql_log(ql_log_warn, vha, 0x700f,
+                   "dma_map_sg return %d for request\n", req_sg_cnt);
                rval = -ENOMEM;
                goto done;
        }
@@ -418,24 +416,25 @@ qla2x00_process_ct(struct fc_bsg_job *bsg_job)
        rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
                bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
        if (!rsp_sg_cnt) {
+               ql_log(ql_log_warn, vha, 0x7010,
+                   "dma_map_sg return %d for reply\n", rsp_sg_cnt);
                rval = -ENOMEM;
                goto done;
        }
 
        if ((req_sg_cnt !=  bsg_job->request_payload.sg_cnt) ||
            (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-                   "[request_sg_cnt: %x dma_request_sg_cnt: %x\
-                   reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n",
-                   bsg_job->request_payload.sg_cnt, req_sg_cnt,
-                   bsg_job->reply_payload.sg_cnt, rsp_sg_cnt));
+               ql_log(ql_log_warn, vha, 0x7011,
+                   "request_sg_cnt: %x dma_request_sg_cnt: %x reply_sg_cnt:%x "
+                   "dma_reply_sg_cnt: %x\n", bsg_job->request_payload.sg_cnt,
+                   req_sg_cnt, bsg_job->reply_payload.sg_cnt, rsp_sg_cnt);
                rval = -EAGAIN;
                goto done_unmap_sg;
        }
 
        if (!vha->flags.online) {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-                       "host not online\n"));
+               ql_log(ql_log_warn, vha, 0x7012,
+                   "Host is not online.\n");
                rval = -EIO;
                goto done_unmap_sg;
        }
@@ -451,8 +450,8 @@ qla2x00_process_ct(struct fc_bsg_job *bsg_job)
                loop_id = vha->mgmt_svr_loop_id;
                break;
        default:
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                   "Unknown loop id: %x\n", loop_id));
+               ql_dbg(ql_dbg_user, vha, 0x7013,
+                   "Unknown loop id: %x.\n", loop_id);
                rval = -EINVAL;
                goto done_unmap_sg;
        }
@@ -464,6 +463,8 @@ qla2x00_process_ct(struct fc_bsg_job *bsg_job)
         */
        fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
        if (!fcport) {
+               ql_log(ql_log_warn, vha, 0x7014,
+                   "Failed to allocate fcport.\n");
                rval = -ENOMEM;
                goto done_unmap_sg;
        }
@@ -479,6 +480,8 @@ qla2x00_process_ct(struct fc_bsg_job *bsg_job)
        /* Alloc SRB structure */
        sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_ctx));
        if (!sp) {
+               ql_log(ql_log_warn, vha, 0x7015,
+                   "qla2x00_get_ctx_bsg_sp failed.\n");
                rval = -ENOMEM;
                goto done_free_fcport;
        }
@@ -488,15 +491,17 @@ qla2x00_process_ct(struct fc_bsg_job *bsg_job)
        ct->name = "bsg_ct";
        ct->u.bsg_job = bsg_job;
 
-       DEBUG2(qla_printk(KERN_INFO, ha,
-               "scsi(%ld:%x): bsg rqst type: %s els type: %x - loop-id=%x "
-               "portid=%02x%02x%02x.\n", vha->host_no, sp->handle, type,
-               (bsg_job->request->rqst_data.h_ct.preamble_word2 >> 16),
-               fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area,
-               fcport->d_id.b.al_pa));
+       ql_dbg(ql_dbg_user, vha, 0x7016,
+           "bsg rqst type: %s else type: %x - "
+           "loop-id=%x portid=%02x%02x%02x.\n", type,
+           (bsg_job->request->rqst_data.h_ct.preamble_word2 >> 16),
+           fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area,
+           fcport->d_id.b.al_pa);
 
        rval = qla2x00_start_sp(sp);
        if (rval != QLA_SUCCESS) {
+               ql_log(ql_log_warn, vha, 0x7017,
+                   "qla2x00_start_sp failed=%d.\n", rval);
                kfree(sp->ctx);
                mempool_free(sp, ha->srb_mempool);
                rval = -EIO;
@@ -535,9 +540,8 @@ qla81xx_set_internal_loopback(scsi_qla_host_t *vha, uint16_t *config,
        ha->notify_dcbx_comp = 1;
        ret = qla81xx_set_port_config(vha, new_config);
        if (ret != QLA_SUCCESS) {
-               DEBUG2(printk(KERN_ERR
-                   "%s(%lu): Set port config failed\n",
-                   __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x7021,
+                   "set port config failed.\n");
                ha->notify_dcbx_comp = 0;
                rval = -EINVAL;
                goto done_set_internal;
@@ -545,11 +549,11 @@ qla81xx_set_internal_loopback(scsi_qla_host_t *vha, uint16_t *config,
 
        /* Wait for DCBX complete event */
        if (!wait_for_completion_timeout(&ha->dcbx_comp, (20 * HZ))) {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-                   "State change notificaition not received.\n"));
+               ql_dbg(ql_dbg_user, vha, 0x7022,
+                   "State change notification not received.\n");
        } else
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                   "State change RECEIVED\n"));
+               ql_dbg(ql_dbg_user, vha, 0x7023,
+                   "State change received.\n");
 
        ha->notify_dcbx_comp = 0;
 
@@ -581,9 +585,8 @@ qla81xx_reset_internal_loopback(scsi_qla_host_t *vha, uint16_t *config,
                ha->notify_dcbx_comp = wait;
                ret = qla81xx_set_port_config(vha, new_config);
                if (ret != QLA_SUCCESS) {
-                       DEBUG2(printk(KERN_ERR
-                           "%s(%lu): Set port config failed\n",
-                            __func__, vha->host_no));
+                       ql_log(ql_log_warn, vha, 0x7025,
+                           "Set port config failed.\n");
                        ha->notify_dcbx_comp = 0;
                        rval = -EINVAL;
                        goto done_reset_internal;
@@ -592,14 +595,14 @@ qla81xx_reset_internal_loopback(scsi_qla_host_t *vha, uint16_t *config,
                /* Wait for DCBX complete event */
                if (wait && !wait_for_completion_timeout(&ha->dcbx_comp,
                        (20 * HZ))) {
-                       DEBUG2(qla_printk(KERN_WARNING, ha,
-                           "State change notificaition not received.\n"));
+                       ql_dbg(ql_dbg_user, vha, 0x7026,
+                           "State change notification not received.\n");
                        ha->notify_dcbx_comp = 0;
                        rval = -EINVAL;
                        goto done_reset_internal;
                } else
-                       DEBUG2(qla_printk(KERN_INFO, ha,
-                           "State change RECEIVED\n"));
+                       ql_dbg(ql_dbg_user, vha, 0x7027,
+                           "State change received.\n");
 
                ha->notify_dcbx_comp = 0;
        }
@@ -629,11 +632,13 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
 
        if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
                test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
-               test_bit(ISP_ABORT_RETRY, &vha->dpc_flags))
+               test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
+               ql_log(ql_log_warn, vha, 0x7018, "Abort active or needed.\n");
                return -EBUSY;
+       }
 
        if (!vha->flags.online) {
-               DEBUG2(qla_printk(KERN_WARNING, ha, "host not online\n"));
+               ql_log(ql_log_warn, vha, 0x7019, "Host is not online.\n");
                return -EIO;
        }
 
@@ -641,26 +646,31 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
                bsg_job->request_payload.sg_list, bsg_job->request_payload.sg_cnt,
                DMA_TO_DEVICE);
 
-       if (!elreq.req_sg_cnt)
+       if (!elreq.req_sg_cnt) {
+               ql_log(ql_log_warn, vha, 0x701a,
+                   "dma_map_sg returned %d for request.\n", elreq.req_sg_cnt);
                return -ENOMEM;
+       }
 
        elreq.rsp_sg_cnt = dma_map_sg(&ha->pdev->dev,
                bsg_job->reply_payload.sg_list, bsg_job->reply_payload.sg_cnt,
                DMA_FROM_DEVICE);
 
        if (!elreq.rsp_sg_cnt) {
+               ql_log(ql_log_warn, vha, 0x701b,
+                   "dma_map_sg returned %d for reply.\n", elreq.rsp_sg_cnt);
                rval = -ENOMEM;
                goto done_unmap_req_sg;
        }
 
        if ((elreq.req_sg_cnt !=  bsg_job->request_payload.sg_cnt) ||
                (elreq.rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) {
-               DEBUG2(printk(KERN_INFO
-                       "dma mapping resulted in different sg counts "
-                       "[request_sg_cnt: %x dma_request_sg_cnt: %x "
-                       "reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n",
-                       bsg_job->request_payload.sg_cnt, elreq.req_sg_cnt,
-                       bsg_job->reply_payload.sg_cnt, elreq.rsp_sg_cnt));
+               ql_log(ql_log_warn, vha, 0x701c,
+                   "dma mapping resulted in different sg counts, "
+                   "request_sg_cnt: %x dma_request_sg_cnt: %x "
+                   "reply_sg_cnt: %x dma_reply_sg_cnt: %x.\n",
+                   bsg_job->request_payload.sg_cnt, elreq.req_sg_cnt,
+                   bsg_job->reply_payload.sg_cnt, elreq.rsp_sg_cnt);
                rval = -EAGAIN;
                goto done_unmap_sg;
        }
@@ -668,8 +678,8 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
        req_data = dma_alloc_coherent(&ha->pdev->dev, req_data_len,
                &req_data_dma, GFP_KERNEL);
        if (!req_data) {
-               DEBUG2(printk(KERN_ERR "%s: dma alloc for req_data "
-                       "failed for host=%lu\n", __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x701d,
+                   "dma alloc failed for req_data.\n");
                rval = -ENOMEM;
                goto done_unmap_sg;
        }
@@ -677,8 +687,8 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
        rsp_data = dma_alloc_coherent(&ha->pdev->dev, rsp_data_len,
                &rsp_data_dma, GFP_KERNEL);
        if (!rsp_data) {
-               DEBUG2(printk(KERN_ERR "%s: dma alloc for rsp_data "
-                       "failed for host=%lu\n", __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x7004,
+                   "dma alloc failed for rsp_data.\n");
                rval = -ENOMEM;
                goto done_free_dma_req;
        }
@@ -699,8 +709,8 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
            && req_data_len == MAX_ELS_FRAME_PAYLOAD)) &&
                elreq.options == EXTERNAL_LOOPBACK) {
                type = "FC_BSG_HST_VENDOR_ECHO_DIAG";
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                       "scsi(%ld) bsg rqst type: %s\n", vha->host_no, type));
+               ql_dbg(ql_dbg_user, vha, 0x701e,
+                   "BSG request type: %s.\n", type);
                command_sent = INT_DEF_LB_ECHO_CMD;
                rval = qla2x00_echo_test(vha, &elreq, response);
        } else {
@@ -708,9 +718,8 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
                        memset(config, 0, sizeof(config));
                        memset(new_config, 0, sizeof(new_config));
                        if (qla81xx_get_port_config(vha, config)) {
-                               DEBUG2(printk(KERN_ERR
-                                       "%s(%lu): Get port config failed\n",
-                                       __func__, vha->host_no));
+                               ql_log(ql_log_warn, vha, 0x701f,
+                                   "Get port config failed.\n");
                                bsg_job->reply->reply_payload_rcv_len = 0;
                                bsg_job->reply->result = (DID_ERROR << 16);
                                rval = -EPERM;
@@ -718,11 +727,13 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
                        }
 
                        if (elreq.options != EXTERNAL_LOOPBACK) {
-                               DEBUG2(qla_printk(KERN_INFO, ha,
-                                       "Internal: current port config = %x\n",
-                                       config[0]));
+                               ql_dbg(ql_dbg_user, vha, 0x7020,
+                                   "Internal: curent port config = %x\n",
+                                   config[0]);
                                if (qla81xx_set_internal_loopback(vha, config,
                                        new_config)) {
+                                       ql_log(ql_log_warn, vha, 0x7024,
+                                           "Internal loopback failed.\n");
                                        bsg_job->reply->reply_payload_rcv_len =
                                                0;
                                        bsg_job->reply->result =
@@ -746,9 +757,8 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
                        }
 
                        type = "FC_BSG_HST_VENDOR_LOOPBACK";
-                       DEBUG2(qla_printk(KERN_INFO, ha,
-                               "scsi(%ld) bsg rqst type: %s\n",
-                               vha->host_no, type));
+                       ql_dbg(ql_dbg_user, vha, 0x7028,
+                           "BSG request type: %s.\n", type);
 
                        command_sent = INT_DEF_LB_LOOPBACK_CMD;
                        rval = qla2x00_loopback_test(vha, &elreq, response);
@@ -763,17 +773,16 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
 
                        if (response[0] == MBS_COMMAND_ERROR &&
                                        response[1] == MBS_LB_RESET) {
-                               DEBUG2(printk(KERN_ERR "%s(%ld): ABORTing "
-                                       "ISP\n", __func__, vha->host_no));
+                               ql_log(ql_log_warn, vha, 0x7029,
+                                   "MBX command error, Aborting ISP.\n");
                                set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                                qla2xxx_wake_dpc(vha);
                                qla2x00_wait_for_chip_reset(vha);
                                /* Also reset the MPI */
                                if (qla81xx_restart_mpi_firmware(vha) !=
                                    QLA_SUCCESS) {
-                                       qla_printk(KERN_INFO, ha,
-                                           "MPI reset failed for host%ld.\n",
-                                           vha->host_no);
+                                       ql_log(ql_log_warn, vha, 0x702a,
+                                           "MPI reset failed.\n");
                                }
 
                                bsg_job->reply->reply_payload_rcv_len = 0;
@@ -783,17 +792,16 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
                        }
                } else {
                        type = "FC_BSG_HST_VENDOR_LOOPBACK";
-                       DEBUG2(qla_printk(KERN_INFO, ha,
-                               "scsi(%ld) bsg rqst type: %s\n",
-                               vha->host_no, type));
+                       ql_dbg(ql_dbg_user, vha, 0x702b,
+                           "BSG request type: %s.\n", type);
                        command_sent = INT_DEF_LB_LOOPBACK_CMD;
                        rval = qla2x00_loopback_test(vha, &elreq, response);
                }
        }
 
        if (rval) {
-               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor "
-                   "request %s failed\n", vha->host_no, type));
+               ql_log(ql_log_warn, vha, 0x702c,
+                   "Vendor request %s failed.\n", type);
 
                fw_sts_ptr = ((uint8_t *)bsg_job->req->sense) +
                    sizeof(struct fc_bsg_reply);
@@ -805,8 +813,8 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
                bsg_job->reply->reply_payload_rcv_len = 0;
                bsg_job->reply->result = (DID_ERROR << 16);
        } else {
-               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor "
-                       "request %s completed\n", vha->host_no, type));
+               ql_dbg(ql_dbg_user, vha, 0x702d,
+                   "Vendor request %s completed.\n", type);
 
                bsg_job->reply_len = sizeof(struct fc_bsg_reply) +
                        sizeof(response) + sizeof(uint8_t);
@@ -851,12 +859,13 @@ qla84xx_reset(struct fc_bsg_job *bsg_job)
 
        if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
            test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
-           test_bit(ISP_ABORT_RETRY, &vha->dpc_flags))
+           test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
+               ql_log(ql_log_warn, vha, 0x702e, "Abort active or needed.\n");
                return -EBUSY;
+       }
 
        if (!IS_QLA84XX(ha)) {
-               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld): Not 84xx, "
-                  "exiting.\n", vha->host_no));
+               ql_dbg(ql_dbg_user, vha, 0x702f, "Not 84xx, exiting.\n");
                return -EINVAL;
        }
 
@@ -865,14 +874,14 @@ qla84xx_reset(struct fc_bsg_job *bsg_job)
        rval = qla84xx_reset_chip(vha, flag == A84_ISSUE_RESET_DIAG_FW);
 
        if (rval) {
-               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor "
-                   "request 84xx reset failed\n", vha->host_no));
+               ql_log(ql_log_warn, vha, 0x7030,
+                   "Vendor request 84xx reset failed.\n");
                rval = bsg_job->reply->reply_payload_rcv_len = 0;
                bsg_job->reply->result = (DID_ERROR << 16);
 
        } else {
-               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor "
-                   "request 84xx reset completed\n", vha->host_no));
+               ql_dbg(ql_dbg_user, vha, 0x7031,
+                   "Vendor request 84xx reset completed.\n");
                bsg_job->reply->result = DID_OK;
        }
 
@@ -902,21 +911,24 @@ qla84xx_updatefw(struct fc_bsg_job *bsg_job)
                return -EBUSY;
 
        if (!IS_QLA84XX(ha)) {
-               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld): Not 84xx, "
-                       "exiting.\n", vha->host_no));
+               ql_dbg(ql_dbg_user, vha, 0x7032,
+                   "Not 84xx, exiting.\n");
                return -EINVAL;
        }
 
        sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
                bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
-       if (!sg_cnt)
+       if (!sg_cnt) {
+               ql_log(ql_log_warn, vha, 0x7033,
+                   "dma_map_sg returned %d for request.\n", sg_cnt);
                return -ENOMEM;
+       }
 
        if (sg_cnt != bsg_job->request_payload.sg_cnt) {
-               DEBUG2(printk(KERN_INFO
-                       "dma mapping resulted in different sg counts "
-                       "request_sg_cnt: %x dma_request_sg_cnt: %x ",
-                       bsg_job->request_payload.sg_cnt, sg_cnt));
+               ql_log(ql_log_warn, vha, 0x7034,
+                   "DMA mapping resulted in different sg counts, "
+                   "request_sg_cnt: %x dma_request_sg_cnt: %x.\n",
+                   bsg_job->request_payload.sg_cnt, sg_cnt);
                rval = -EAGAIN;
                goto done_unmap_sg;
        }
@@ -925,8 +937,8 @@ qla84xx_updatefw(struct fc_bsg_job *bsg_job)
        fw_buf = dma_alloc_coherent(&ha->pdev->dev, data_len,
                &fw_dma, GFP_KERNEL);
        if (!fw_buf) {
-               DEBUG2(printk(KERN_ERR "%s: dma alloc for fw_buf "
-                       "failed for host=%lu\n", __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x7035,
+                   "DMA alloc failed for fw_buf.\n");
                rval = -ENOMEM;
                goto done_unmap_sg;
        }
@@ -936,8 +948,8 @@ qla84xx_updatefw(struct fc_bsg_job *bsg_job)
 
        mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma);
        if (!mn) {
-               DEBUG2(printk(KERN_ERR "%s: dma alloc for fw buffer "
-                       "failed for host=%lu\n", __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x7036,
+                   "DMA alloc failed for fw buffer.\n");
                rval = -ENOMEM;
                goto done_free_fw_buf;
        }
@@ -965,15 +977,15 @@ qla84xx_updatefw(struct fc_bsg_job *bsg_job)
        rval = qla2x00_issue_iocb_timeout(vha, mn, mn_dma, 0, 120);
 
        if (rval) {
-               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor "
-                       "request 84xx updatefw failed\n", vha->host_no));
+               ql_log(ql_log_warn, vha, 0x7037,
+                   "Vendor request 84xx updatefw failed.\n");
 
                rval = bsg_job->reply->reply_payload_rcv_len = 0;
                bsg_job->reply->result = (DID_ERROR << 16);
 
        } else {
-               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor "
-                       "request 84xx updatefw completed\n", vha->host_no));
+               ql_dbg(ql_dbg_user, vha, 0x7038,
+                   "Vendor request 84xx updatefw completed.\n");
 
                bsg_job->reply_len = sizeof(struct fc_bsg_reply);
                bsg_job->reply->result = DID_OK;
@@ -1009,27 +1021,30 @@ qla84xx_mgmt_cmd(struct fc_bsg_job *bsg_job)
 
        if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
                test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
-               test_bit(ISP_ABORT_RETRY, &vha->dpc_flags))
+               test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
+               ql_log(ql_log_warn, vha, 0x7039,
+                   "Abort active or needed.\n");
                return -EBUSY;
+       }
 
        if (!IS_QLA84XX(ha)) {
-               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld): Not 84xx, "
-                       "exiting.\n", vha->host_no));
+               ql_log(ql_log_warn, vha, 0x703a,
+                   "Not 84xx, exiting.\n");
                return -EINVAL;
        }
 
        ql84_mgmt = (struct qla_bsg_a84_mgmt *)((char *)bsg_job->request +
                sizeof(struct fc_bsg_request));
        if (!ql84_mgmt) {
-               DEBUG2(printk("%s(%ld): mgmt header not provided, exiting.\n",
-                       __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x703b,
+                   "MGMT header not provided, exiting.\n");
                return -EINVAL;
        }
 
        mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma);
        if (!mn) {
-               DEBUG2(printk(KERN_ERR "%s: dma alloc for fw buffer "
-                       "failed for host=%lu\n", __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x703c,
+                   "DMA alloc failed for fw buffer.\n");
                return -ENOMEM;
        }
 
@@ -1044,6 +1059,8 @@ qla84xx_mgmt_cmd(struct fc_bsg_job *bsg_job)
                        bsg_job->reply_payload.sg_list,
                        bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
                if (!sg_cnt) {
+                       ql_log(ql_log_warn, vha, 0x703d,
+                           "dma_map_sg returned %d for reply.\n", sg_cnt);
                        rval = -ENOMEM;
                        goto exit_mgmt;
                }
@@ -1051,10 +1068,10 @@ qla84xx_mgmt_cmd(struct fc_bsg_job *bsg_job)
                dma_direction = DMA_FROM_DEVICE;
 
                if (sg_cnt != bsg_job->reply_payload.sg_cnt) {
-                       DEBUG2(printk(KERN_INFO
-                               "dma mapping resulted in different sg counts "
-                               "reply_sg_cnt: %x dma_reply_sg_cnt: %x\n",
-                               bsg_job->reply_payload.sg_cnt, sg_cnt));
+                       ql_log(ql_log_warn, vha, 0x703e,
+                           "DMA mapping resulted in different sg counts, "
+                           "reply_sg_cnt: %x dma_reply_sg_cnt: %x.\n",
+                           bsg_job->reply_payload.sg_cnt, sg_cnt);
                        rval = -EAGAIN;
                        goto done_unmap_sg;
                }
@@ -1064,9 +1081,8 @@ qla84xx_mgmt_cmd(struct fc_bsg_job *bsg_job)
                mgmt_b = dma_alloc_coherent(&ha->pdev->dev, data_len,
                    &mgmt_dma, GFP_KERNEL);
                if (!mgmt_b) {
-                       DEBUG2(printk(KERN_ERR "%s: dma alloc for mgmt_b "
-                               "failed for host=%lu\n",
-                               __func__, vha->host_no));
+                       ql_log(ql_log_warn, vha, 0x703f,
+                           "DMA alloc failed for mgmt_b.\n");
                        rval = -ENOMEM;
                        goto done_unmap_sg;
                }
@@ -1094,6 +1110,8 @@ qla84xx_mgmt_cmd(struct fc_bsg_job *bsg_job)
                        bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
 
                if (!sg_cnt) {
+                       ql_log(ql_log_warn, vha, 0x7040,
+                           "dma_map_sg returned %d.\n", sg_cnt);
                        rval = -ENOMEM;
                        goto exit_mgmt;
                }
@@ -1101,10 +1119,10 @@ qla84xx_mgmt_cmd(struct fc_bsg_job *bsg_job)
                dma_direction = DMA_TO_DEVICE;
 
                if (sg_cnt != bsg_job->request_payload.sg_cnt) {
-                       DEBUG2(printk(KERN_INFO
-                               "dma mapping resulted in different sg counts "
-                               "request_sg_cnt: %x dma_request_sg_cnt: %x ",
-                               bsg_job->request_payload.sg_cnt, sg_cnt));
+                       ql_log(ql_log_warn, vha, 0x7041,
+                           "DMA mapping resulted in different sg counts, "
+                           "request_sg_cnt: %x dma_request_sg_cnt: %x.\n",
+                           bsg_job->request_payload.sg_cnt, sg_cnt);
                        rval = -EAGAIN;
                        goto done_unmap_sg;
                }
@@ -1113,9 +1131,8 @@ qla84xx_mgmt_cmd(struct fc_bsg_job *bsg_job)
                mgmt_b = dma_alloc_coherent(&ha->pdev->dev, data_len,
                        &mgmt_dma, GFP_KERNEL);
                if (!mgmt_b) {
-                       DEBUG2(printk(KERN_ERR "%s: dma alloc for mgmt_b "
-                               "failed for host=%lu\n",
-                               __func__, vha->host_no));
+                       ql_log(ql_log_warn, vha, 0x7042,
+                           "DMA alloc failed for mgmt_b.\n");
                        rval = -ENOMEM;
                        goto done_unmap_sg;
                }
@@ -1156,15 +1173,15 @@ qla84xx_mgmt_cmd(struct fc_bsg_job *bsg_job)
        rval = qla2x00_issue_iocb(vha, mn, mn_dma, 0);
 
        if (rval) {
-               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor "
-                       "request 84xx mgmt failed\n", vha->host_no));
+               ql_log(ql_log_warn, vha, 0x7043,
+                   "Vendor request 84xx mgmt failed.\n");
 
                rval = bsg_job->reply->reply_payload_rcv_len = 0;
                bsg_job->reply->result = (DID_ERROR << 16);
 
        } else {
-               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor "
-                       "request 84xx mgmt completed\n", vha->host_no));
+               ql_dbg(ql_dbg_user, vha, 0x7044,
+                   "Vendor request 84xx mgmt completed.\n");
 
                bsg_job->reply_len = sizeof(struct fc_bsg_reply);
                bsg_job->reply->result = DID_OK;
@@ -1204,7 +1221,6 @@ qla24xx_iidma(struct fc_bsg_job *bsg_job)
 {
        struct Scsi_Host *host = bsg_job->shost;
        scsi_qla_host_t *vha = shost_priv(host);
-       struct qla_hw_data *ha = vha->hw;
        int rval = 0;
        struct qla_port_param *port_param = NULL;
        fc_port_t *fcport = NULL;
@@ -1215,26 +1231,27 @@ qla24xx_iidma(struct fc_bsg_job *bsg_job)
 
        if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
                test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
-               test_bit(ISP_ABORT_RETRY, &vha->dpc_flags))
+               test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
+               ql_log(ql_log_warn, vha, 0x7045, "abort active or needed.\n");
                return -EBUSY;
+       }
 
        if (!IS_IIDMA_CAPABLE(vha->hw)) {
-               DEBUG2(qla_printk(KERN_WARNING, ha, "%s(%lu): iiDMA not "
-                       "supported\n",  __func__, vha->host_no));
+               ql_log(ql_log_info, vha, 0x7046, "iiDMA not supported.\n");
                return -EINVAL;
        }
 
        port_param = (struct qla_port_param *)((char *)bsg_job->request +
                sizeof(struct fc_bsg_request));
        if (!port_param) {
-               DEBUG2(printk("%s(%ld): port_param header not provided, "
-                       "exiting.\n", __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x7047,
+                   "port_param header not provided.\n");
                return -EINVAL;
        }
 
        if (port_param->fc_scsi_addr.dest_type != EXT_DEF_TYPE_WWPN) {
-               DEBUG2(printk(KERN_ERR "%s(%ld): Invalid destination type\n",
-                       __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x7048,
+                   "Invalid destination type.\n");
                return -EINVAL;
        }
 
@@ -1249,21 +1266,20 @@ qla24xx_iidma(struct fc_bsg_job *bsg_job)
        }
 
        if (!fcport) {
-               DEBUG2(printk(KERN_ERR "%s(%ld): Failed to find port\n",
-                       __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x7049,
+                   "Failed to find port.\n");
                return -EINVAL;
        }
 
        if (atomic_read(&fcport->state) != FCS_ONLINE) {
-               DEBUG2(printk(KERN_ERR "%s(%ld): Port not online\n",
-                       __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x704a,
+                   "Port is not online.\n");
                return -EINVAL;
        }
 
        if (fcport->flags & FCF_LOGIN_NEEDED) {
-               DEBUG2(printk(KERN_ERR "%s(%ld): Remote port not logged in, "
-                   "flags = 0x%x\n",
-                   __func__, vha->host_no, fcport->flags));
+               ql_log(ql_log_warn, vha, 0x704b,
+                   "Remote port not logged in flags = 0x%x.\n", fcport->flags);
                return -EINVAL;
        }
 
@@ -1275,15 +1291,13 @@ qla24xx_iidma(struct fc_bsg_job *bsg_job)
                        &port_param->speed, mb);
 
        if (rval) {
-               DEBUG16(printk(KERN_ERR "scsi(%ld): iIDMA cmd failed for "
-                       "%02x%02x%02x%02x%02x%02x%02x%02x -- "
-                       "%04x %x %04x %04x.\n",
-                       vha->host_no, fcport->port_name[0],
-                       fcport->port_name[1],
-                       fcport->port_name[2], fcport->port_name[3],
-                       fcport->port_name[4], fcport->port_name[5],
-                       fcport->port_name[6], fcport->port_name[7], rval,
-                       fcport->fp_speed, mb[0], mb[1]));
+               ql_log(ql_log_warn, vha, 0x704c,
+                   "iIDMA cmd failed for %02x%02x%02x%02x%02x%02x%02x%02x -- "
+                   "%04x %x %04x %04x.\n", fcport->port_name[0],
+                   fcport->port_name[1], fcport->port_name[2],
+                   fcport->port_name[3], fcport->port_name[4],
+                   fcport->port_name[5], fcport->port_name[6],
+                   fcport->port_name[7], rval, fcport->fp_speed, mb[0], mb[1]);
                rval = 0;
                bsg_job->reply->result = (DID_ERROR << 16);
 
@@ -1307,11 +1321,12 @@ qla24xx_iidma(struct fc_bsg_job *bsg_job)
 }
 
 static int
-qla2x00_optrom_setup(struct fc_bsg_job *bsg_job, struct qla_hw_data *ha,
+qla2x00_optrom_setup(struct fc_bsg_job *bsg_job, scsi_qla_host_t *vha,
        uint8_t is_update)
 {
        uint32_t start = 0;
        int valid = 0;
+       struct qla_hw_data *ha = vha->hw;
 
        bsg_job->reply->reply_payload_rcv_len = 0;
 
@@ -1319,14 +1334,20 @@ qla2x00_optrom_setup(struct fc_bsg_job *bsg_job, struct qla_hw_data *ha,
                return -EINVAL;
 
        start = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1];
-       if (start > ha->optrom_size)
+       if (start > ha->optrom_size) {
+               ql_log(ql_log_warn, vha, 0x7055,
+                   "start %d > optrom_size %d.\n", start, ha->optrom_size);
                return -EINVAL;
+       }
 
-       if (ha->optrom_state != QLA_SWAITING)
+       if (ha->optrom_state != QLA_SWAITING) {
+               ql_log(ql_log_info, vha, 0x7056,
+                   "optrom_state %d.\n", ha->optrom_state);
                return -EBUSY;
+       }
 
        ha->optrom_region_start = start;
-
+       ql_dbg(ql_dbg_user, vha, 0x7057, "is_update=%d.\n", is_update);
        if (is_update) {
                if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0)
                        valid = 1;
@@ -1337,9 +1358,9 @@ qla2x00_optrom_setup(struct fc_bsg_job *bsg_job, struct qla_hw_data *ha,
                    IS_QLA8XXX_TYPE(ha))
                        valid = 1;
                if (!valid) {
-                       qla_printk(KERN_WARNING, ha,
-                           "Invalid start region 0x%x/0x%x.\n",
-                           start, bsg_job->request_payload.payload_len);
+                       ql_log(ql_log_warn, vha, 0x7058,
+                           "Invalid start region 0x%x/0x%x.\n", start,
+                           bsg_job->request_payload.payload_len);
                        return -EINVAL;
                }
 
@@ -1358,9 +1379,9 @@ qla2x00_optrom_setup(struct fc_bsg_job *bsg_job, struct qla_hw_data *ha,
 
        ha->optrom_buffer = vmalloc(ha->optrom_region_size);
        if (!ha->optrom_buffer) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x7059,
                    "Read: Unable to allocate memory for optrom retrieval "
-                   "(%x).\n", ha->optrom_region_size);
+                   "(%x)\n", ha->optrom_region_size);
 
                ha->optrom_state = QLA_SWAITING;
                return -ENOMEM;
@@ -1378,7 +1399,7 @@ qla2x00_read_optrom(struct fc_bsg_job *bsg_job)
        struct qla_hw_data *ha = vha->hw;
        int rval = 0;
 
-       rval = qla2x00_optrom_setup(bsg_job, ha, 0);
+       rval = qla2x00_optrom_setup(bsg_job, vha, 0);
        if (rval)
                return rval;
 
@@ -1406,7 +1427,7 @@ qla2x00_update_optrom(struct fc_bsg_job *bsg_job)
        struct qla_hw_data *ha = vha->hw;
        int rval = 0;
 
-       rval = qla2x00_optrom_setup(bsg_job, ha, 1);
+       rval = qla2x00_optrom_setup(bsg_job, vha, 1);
        if (rval)
                return rval;
 
@@ -1464,6 +1485,23 @@ int
 qla24xx_bsg_request(struct fc_bsg_job *bsg_job)
 {
        int ret = -EINVAL;
+       struct fc_rport *rport;
+       fc_port_t *fcport = NULL;
+       struct Scsi_Host *host;
+       scsi_qla_host_t *vha;
+
+       if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) {
+               rport = bsg_job->rport;
+               fcport = *(fc_port_t **) rport->dd_data;
+               host = rport_to_shost(rport);
+               vha = shost_priv(host);
+       } else {
+               host = bsg_job->shost;
+               vha = shost_priv(host);
+       }
+
+       ql_dbg(ql_dbg_user, vha, 0x7000,
+           "Entered %s msgcode=%d.\n", __func__, bsg_job->request->msgcode);
 
        switch (bsg_job->request->msgcode) {
        case FC_BSG_RPT_ELS:
@@ -1480,7 +1518,7 @@ qla24xx_bsg_request(struct fc_bsg_job *bsg_job)
        case FC_BSG_HST_DEL_RPORT:
        case FC_BSG_RPT_CT:
        default:
-               DEBUG2(printk("qla2xxx: unsupported BSG request\n"));
+               ql_log(ql_log_warn, vha, 0x705a, "Unsupported BSG request.\n");
                break;
        }
        return ret;
@@ -1514,17 +1552,15 @@ qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job)
                                        && (sp_bsg->u.bsg_job == bsg_job)) {
                                        spin_unlock_irqrestore(&ha->hardware_lock, flags);
                                        if (ha->isp_ops->abort_command(sp)) {
-                                               DEBUG2(qla_printk(KERN_INFO, ha,
-                                                   "scsi(%ld): mbx "
-                                                   "abort_command failed\n",
-                                                   vha->host_no));
+                                               ql_log(ql_log_warn, vha, 0x7089,
+                                                   "mbx abort_command "
+                                                   "failed.\n");
                                                bsg_job->req->errors =
                                                bsg_job->reply->result = -EIO;
                                        } else {
-                                               DEBUG2(qla_printk(KERN_INFO, ha,
-                                                   "scsi(%ld): mbx "
-                                                   "abort_command success\n",
-                                                   vha->host_no));
+                                               ql_dbg(ql_dbg_user, vha, 0x708a,
+                                                   "mbx abort_command "
+                                                   "success.\n");
                                                bsg_job->req->errors =
                                                bsg_job->reply->result = 0;
                                        }
@@ -1535,8 +1571,7 @@ qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job)
                }
        }
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
-       DEBUG2(qla_printk(KERN_INFO, ha,
-               "scsi(%ld) SRB not found to abort\n", vha->host_no));
+       ql_log(ql_log_info, vha, 0x708b, "SRB not found to abort.\n");
        bsg_job->req->errors = bsg_job->reply->result = -ENXIO;
        return 0;
 
index c53719a..2155071 100644 (file)
@@ -4,10 +4,36 @@
  *
  * See LICENSE.qla2xxx for copyright and licensing details.
  */
+
+/*
+ * Table for showing the current message id in use for particular level
+ * Change this table for addition of log/debug messages.
+ * -----------------------------------------------------
+ * |             Level            |   Last Value Used  |
+ * -----------------------------------------------------
+ * | Module Init and Probe        |       0x0116       |
+ * | Mailbox commands             |       0x111e       |
+ * | Device Discovery             |       0x2083       |
+ * | Queue Command and IO tracing |       0x302e       |
+ * | DPC Thread                   |       0x401c       |
+ * | Async Events                 |       0x5059       |
+ * | Timer Routines               |       0x600d       |
+ * | User Space Interactions      |       0x709c       |
+ * | Task Management              |       0x8043       |
+ * | AER/EEH                      |       0x900f       |
+ * | Virtual Port                 |       0xa007       |
+ * | ISP82XX Specific             |       0xb027       |
+ * | MultiQ                       |       0xc00b       |
+ * | Misc                         |       0xd00b       |
+ * -----------------------------------------------------
+ */
+
 #include "qla_def.h"
 
 #include <linux/delay.h>
 
+static uint32_t ql_dbg_offset = 0x800;
+
 static inline void
 qla2xxx_prep_dump(struct qla_hw_data *ha, struct qla2xxx_fw_dump *fw_dump)
 {
@@ -383,11 +409,11 @@ qla2xxx_dump_post_process(scsi_qla_host_t *vha, int rval)
        struct qla_hw_data *ha = vha->hw;
 
        if (rval != QLA_SUCCESS) {
-               qla_printk(KERN_WARNING, ha,
-                   "Failed to dump firmware (%x)!!!\n", rval);
+               ql_log(ql_log_warn, vha, 0xd000,
+                   "Failed to dump firmware (%x).\n", rval);
                ha->fw_dumped = 0;
        } else {
-               qla_printk(KERN_INFO, ha,
+               ql_log(ql_log_info, vha, 0xd001,
                    "Firmware dump saved to temp buffer (%ld/%p).\n",
                    vha->host_no, ha->fw_dump);
                ha->fw_dumped = 1;
@@ -419,15 +445,16 @@ qla2300_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
                spin_lock_irqsave(&ha->hardware_lock, flags);
 
        if (!ha->fw_dump) {
-               qla_printk(KERN_WARNING, ha,
-                   "No buffer available for dump!!!\n");
+               ql_log(ql_log_warn, vha, 0xd002,
+                   "No buffer available for dump.\n");
                goto qla2300_fw_dump_failed;
        }
 
        if (ha->fw_dumped) {
-               qla_printk(KERN_WARNING, ha,
-                   "Firmware has been previously dumped (%p) -- ignoring "
-                   "request...\n", ha->fw_dump);
+               ql_log(ql_log_warn, vha, 0xd003,
+                   "Firmware has been previously dumped (%p) "
+                   "-- ignoring request.\n",
+                   ha->fw_dump);
                goto qla2300_fw_dump_failed;
        }
        fw = &ha->fw_dump->isp.isp23;
@@ -582,15 +609,16 @@ qla2100_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
                spin_lock_irqsave(&ha->hardware_lock, flags);
 
        if (!ha->fw_dump) {
-               qla_printk(KERN_WARNING, ha,
-                   "No buffer available for dump!!!\n");
+               ql_log(ql_log_warn, vha, 0xd004,
+                   "No buffer available for dump.\n");
                goto qla2100_fw_dump_failed;
        }
 
        if (ha->fw_dumped) {
-               qla_printk(KERN_WARNING, ha,
-                   "Firmware has been previously dumped (%p) -- ignoring "
-                   "request...\n", ha->fw_dump);
+               ql_log(ql_log_warn, vha, 0xd005,
+                   "Firmware has been previously dumped (%p) "
+                   "-- ignoring request.\n",
+                   ha->fw_dump);
                goto qla2100_fw_dump_failed;
        }
        fw = &ha->fw_dump->isp.isp21;
@@ -779,15 +807,16 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
                spin_lock_irqsave(&ha->hardware_lock, flags);
 
        if (!ha->fw_dump) {
-               qla_printk(KERN_WARNING, ha,
-                   "No buffer available for dump!!!\n");
+               ql_log(ql_log_warn, vha, 0xd006,
+                   "No buffer available for dump.\n");
                goto qla24xx_fw_dump_failed;
        }
 
        if (ha->fw_dumped) {
-               qla_printk(KERN_WARNING, ha,
-                   "Firmware has been previously dumped (%p) -- ignoring "
-                   "request...\n", ha->fw_dump);
+               ql_log(ql_log_warn, vha, 0xd007,
+                   "Firmware has been previously dumped (%p) "
+                   "-- ignoring request.\n",
+                   ha->fw_dump);
                goto qla24xx_fw_dump_failed;
        }
        fw = &ha->fw_dump->isp.isp24;
@@ -1017,15 +1046,16 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
                spin_lock_irqsave(&ha->hardware_lock, flags);
 
        if (!ha->fw_dump) {
-               qla_printk(KERN_WARNING, ha,
-                   "No buffer available for dump!!!\n");
+               ql_log(ql_log_warn, vha, 0xd008,
+                   "No buffer available for dump.\n");
                goto qla25xx_fw_dump_failed;
        }
 
        if (ha->fw_dumped) {
-               qla_printk(KERN_WARNING, ha,
-                   "Firmware has been previously dumped (%p) -- ignoring "
-                   "request...\n", ha->fw_dump);
+               ql_log(ql_log_warn, vha, 0xd009,
+                   "Firmware has been previously dumped (%p) "
+                   "-- ignoring request.\n",
+                   ha->fw_dump);
                goto qla25xx_fw_dump_failed;
        }
        fw = &ha->fw_dump->isp.isp25;
@@ -1328,15 +1358,16 @@ qla81xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
                spin_lock_irqsave(&ha->hardware_lock, flags);
 
        if (!ha->fw_dump) {
-               qla_printk(KERN_WARNING, ha,
-                   "No buffer available for dump!!!\n");
+               ql_log(ql_log_warn, vha, 0xd00a,
+                   "No buffer available for dump.\n");
                goto qla81xx_fw_dump_failed;
        }
 
        if (ha->fw_dumped) {
-               qla_printk(KERN_WARNING, ha,
-                   "Firmware has been previously dumped (%p) -- ignoring "
-                   "request...\n", ha->fw_dump);
+               ql_log(ql_log_warn, vha, 0xd00b,
+                   "Firmware has been previously dumped (%p) "
+                   "-- ignoring request.\n",
+                   ha->fw_dump);
                goto qla81xx_fw_dump_failed;
        }
        fw = &ha->fw_dump->isp.isp81;
@@ -1619,106 +1650,255 @@ qla81xx_fw_dump_failed:
 /****************************************************************************/
 /*                         Driver Debug Functions.                          */
 /****************************************************************************/
-
+/*
+ * This function is for formatting and logging debug information.
+ * It is to be used when vha is available. It formats the message
+ * and logs it to the messages file.
+ * parameters:
+ * level: The level of the debug messages to be printed.
+ *        If ql2xextended_error_logging value is correctly set,
+ *        this message will appear in the messages file.
+ * vha:   Pointer to the scsi_qla_host_t.
+ * id:    This is a unique identifier for the level. It identifies the
+ *        part of the code from where the message originated.
+ * msg:   The message to be displayed.
+ */
 void
-qla2x00_dump_regs(scsi_qla_host_t *vha)
-{
-       int i;
-       struct qla_hw_data *ha = vha->hw;
-       struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
-       struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
-       uint16_t __iomem *mbx_reg;
+ql_dbg(uint32_t level, scsi_qla_host_t *vha, int32_t id, char *msg, ...) {
+
+       char pbuf[QL_DBG_BUF_LEN];
+       va_list ap;
+       uint32_t len;
+       struct pci_dev *pdev = NULL;
+
+       memset(pbuf, 0, QL_DBG_BUF_LEN);
+
+       va_start(ap, msg);
+
+       if ((level & ql2xextended_error_logging) == level) {
+               if (vha != NULL) {
+                       pdev = vha->hw->pdev;
+                       /* <module-name> <pci-name> <msg-id>:<host> Message */
+                       sprintf(pbuf, "%s [%s]-%04x:%ld: ", QL_MSGHDR,
+                           dev_name(&(pdev->dev)), id + ql_dbg_offset,
+                           vha->host_no);
+               } else
+                       sprintf(pbuf, "%s [%s]-%04x: : ", QL_MSGHDR,
+                           "0000:00:00.0", id + ql_dbg_offset);
+
+               len = strlen(pbuf);
+               vsprintf(pbuf+len, msg, ap);
+               pr_warning("%s", pbuf);
+       }
 
-       mbx_reg = IS_FWI2_CAPABLE(ha) ? &reg24->mailbox0:
-           MAILBOX_REG(ha, reg, 0);
+       va_end(ap);
 
-       printk("Mailbox registers:\n");
-       for (i = 0; i < 6; i++)
-               printk("scsi(%ld): mbox %d 0x%04x \n", vha->host_no, i,
-                   RD_REG_WORD(mbx_reg++));
 }
 
-
+/*
+ * This function is for formatting and logging debug information.
+ * It is to be used when vha is not available and pci is availble,
+ * i.e., before host allocation. It formats the message and logs it
+ * to the messages file.
+ * parameters:
+ * level: The level of the debug messages to be printed.
+ *        If ql2xextended_error_logging value is correctly set,
+ *        this message will appear in the messages file.
+ * pdev:  Pointer to the struct pci_dev.
+ * id:    This is a unique id for the level. It identifies the part
+ *        of the code from where the message originated.
+ * msg:   The message to be displayed.
+ */
 void
-qla2x00_dump_buffer(uint8_t * b, uint32_t size)
-{
-       uint32_t cnt;
-       uint8_t c;
+ql_dbg_pci(uint32_t level, struct pci_dev *pdev, int32_t id, char *msg, ...) {
 
-       printk(" 0   1   2   3   4   5   6   7   8   9  "
-           "Ah  Bh  Ch  Dh  Eh  Fh\n");
-       printk("----------------------------------------"
-           "----------------------\n");
-
-       for (cnt = 0; cnt < size;) {
-               c = *b++;
-               printk("%02x",(uint32_t) c);
-               cnt++;
-               if (!(cnt % 16))
-                       printk("\n");
-               else
-                       printk("  ");
+       char pbuf[QL_DBG_BUF_LEN];
+       va_list ap;
+       uint32_t len;
+
+       if (pdev == NULL)
+               return;
+
+       memset(pbuf, 0, QL_DBG_BUF_LEN);
+
+       va_start(ap, msg);
+
+       if ((level & ql2xextended_error_logging) == level) {
+               /* <module-name> <dev-name>:<msg-id> Message */
+               sprintf(pbuf, "%s [%s]-%04x: : ", QL_MSGHDR,
+                   dev_name(&(pdev->dev)), id + ql_dbg_offset);
+
+               len = strlen(pbuf);
+               vsprintf(pbuf+len, msg, ap);
+               pr_warning("%s", pbuf);
        }
-       if (cnt % 16)
-               printk("\n");
+
+       va_end(ap);
+
 }
 
+/*
+ * This function is for formatting and logging log messages.
+ * It is to be used when vha is available. It formats the message
+ * and logs it to the messages file. All the messages will be logged
+ * irrespective of value of ql2xextended_error_logging.
+ * parameters:
+ * level: The level of the log messages to be printed in the
+ *        messages file.
+ * vha:   Pointer to the scsi_qla_host_t
+ * id:    This is a unique id for the level. It identifies the
+ *        part of the code from where the message originated.
+ * msg:   The message to be displayed.
+ */
 void
-qla2x00_dump_buffer_zipped(uint8_t *b, uint32_t size)
-{
-       uint32_t cnt;
-       uint8_t c;
-       uint8_t  last16[16], cur16[16];
-       uint32_t lc = 0, num_same16 = 0, j;
+ql_log(uint32_t level, scsi_qla_host_t *vha, int32_t id, char *msg, ...) {
 
-       printk(KERN_DEBUG " 0   1   2   3   4   5   6   7   8   9  "
-           "Ah  Bh  Ch  Dh  Eh  Fh\n");
-       printk(KERN_DEBUG "----------------------------------------"
-           "----------------------\n");
+       char pbuf[QL_DBG_BUF_LEN];
+       va_list ap;
+       uint32_t len;
+       struct pci_dev *pdev = NULL;
 
-       for (cnt = 0; cnt < size;) {
-               c = *b++;
+       memset(pbuf, 0, QL_DBG_BUF_LEN);
 
-               cur16[lc++] = c;
+       va_start(ap, msg);
 
-               cnt++;
-               if (cnt % 16)
-                       continue;
-
-               /* We have 16 now */
-               lc = 0;
-               if (num_same16 == 0) {
-                       memcpy(last16, cur16, 16);
-                       num_same16++;
-                       continue;
+       if (level <= ql_errlev) {
+               if (vha != NULL) {
+                       pdev = vha->hw->pdev;
+                       /* <module-name> <msg-id>:<host> Message */
+                       sprintf(pbuf, "%s [%s]-%04x:%ld: ", QL_MSGHDR,
+                           dev_name(&(pdev->dev)), id, vha->host_no);
+               } else
+                       sprintf(pbuf, "%s [%s]-%04x: : ", QL_MSGHDR,
+                           "0000:00:00.0", id);
+
+               len = strlen(pbuf);
+                       vsprintf(pbuf+len, msg, ap);
+
+               switch (level) {
+               case 0: /* FATAL LOG */
+                       pr_crit("%s", pbuf);
+                       break;
+               case 1:
+                       pr_err("%s", pbuf);
+                       break;
+               case 2:
+                       pr_warn("%s", pbuf);
+                       break;
+               default:
+                       pr_info("%s", pbuf);
+                       break;
                }
-               if (memcmp(cur16, last16, 16) == 0) {
-                       num_same16++;
-                       continue;
+       }
+
+       va_end(ap);
+}
+
+/*
+ * This function is for formatting and logging log messages.
+ * It is to be used when vha is not available and pci is availble,
+ * i.e., before host allocation. It formats the message and logs
+ * it to the messages file. All the messages are logged irrespective
+ * of the value of ql2xextended_error_logging.
+ * parameters:
+ * level: The level of the log messages to be printed in the
+ *        messages file.
+ * pdev:  Pointer to the struct pci_dev.
+ * id:    This is a unique id for the level. It identifies the
+ *        part of the code from where the message originated.
+ * msg:   The message to be displayed.
+ */
+void
+ql_log_pci(uint32_t level, struct pci_dev *pdev, int32_t id, char *msg, ...) {
+
+       char pbuf[QL_DBG_BUF_LEN];
+       va_list ap;
+       uint32_t len;
+
+       if (pdev == NULL)
+               return;
+
+       memset(pbuf, 0, QL_DBG_BUF_LEN);
+
+       va_start(ap, msg);
+
+       if (level <= ql_errlev) {
+               /* <module-name> <dev-name>:<msg-id> Message */
+               sprintf(pbuf, "%s [%s]-%04x: : ", QL_MSGHDR,
+                   dev_name(&(pdev->dev)), id);
+
+               len = strlen(pbuf);
+               vsprintf(pbuf+len, msg, ap);
+               switch (level) {
+               case 0: /* FATAL LOG */
+                       pr_crit("%s", pbuf);
+                       break;
+               case 1:
+                       pr_err("%s", pbuf);
+                       break;
+               case 2:
+                       pr_warn("%s", pbuf);
+                       break;
+               default:
+                       pr_info("%s", pbuf);
+                       break;
                }
-               for (j = 0; j < 16; j++)
-                       printk(KERN_DEBUG "%02x  ", (uint32_t)last16[j]);
-               printk(KERN_DEBUG "\n");
-
-               if (num_same16 > 1)
-                       printk(KERN_DEBUG "> prev pattern repeats (%u)"
-                           "more times\n", num_same16-1);
-               memcpy(last16, cur16, 16);
-               num_same16 = 1;
        }
 
-       if (num_same16) {
-               for (j = 0; j < 16; j++)
-                       printk(KERN_DEBUG "%02x  ", (uint32_t)last16[j]);
-               printk(KERN_DEBUG "\n");
+       va_end(ap);
+}
 
-               if (num_same16 > 1)
-                       printk(KERN_DEBUG "> prev pattern repeats (%u)"
-                           "more times\n", num_same16-1);
+void
+ql_dump_regs(uint32_t level, scsi_qla_host_t *vha, int32_t id)
+{
+       int i;
+       struct qla_hw_data *ha = vha->hw;
+       struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+       struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
+       struct device_reg_82xx __iomem *reg82 = &ha->iobase->isp82;
+       uint16_t __iomem *mbx_reg;
+
+       if ((level & ql2xextended_error_logging) == level) {
+
+               if (IS_QLA82XX(ha))
+                       mbx_reg = &reg82->mailbox_in[0];
+               else if (IS_FWI2_CAPABLE(ha))
+                       mbx_reg = &reg24->mailbox0;
+               else
+                       mbx_reg = MAILBOX_REG(ha, reg, 0);
+
+               ql_dbg(level, vha, id, "Mailbox registers:\n");
+               for (i = 0; i < 6; i++)
+                       ql_dbg(level, vha, id,
+                           "mbox[%d] 0x%04x\n", i, RD_REG_WORD(mbx_reg++));
        }
-       if (lc) {
-               for (j = 0; j < lc; j++)
-                       printk(KERN_DEBUG "%02x  ", (uint32_t)cur16[j]);
-               printk(KERN_DEBUG "\n");
+}
+
+
+void
+ql_dump_buffer(uint32_t level, scsi_qla_host_t *vha, int32_t id,
+       uint8_t *b, uint32_t size)
+{
+       uint32_t cnt;
+       uint8_t c;
+       if ((level & ql2xextended_error_logging) == level) {
+
+               ql_dbg(level, vha, id, " 0   1   2   3   4   5   6   7   8   "
+                   "9  Ah  Bh  Ch  Dh  Eh  Fh\n");
+               ql_dbg(level, vha, id, "----------------------------------"
+                   "----------------------------\n");
+
+               ql_dbg(level, vha, id, "");
+               for (cnt = 0; cnt < size;) {
+                       c = *b++;
+                       printk("%02x", (uint32_t) c);
+                       cnt++;
+                       if (!(cnt % 16))
+                               printk("\n");
+                       else
+                               printk("  ");
+               }
+               if (cnt % 16)
+                       ql_dbg(level, vha, id, "\n");
        }
 }
index 9304145..98a377b 100644 (file)
@@ -7,146 +7,6 @@
 
 #include "qla_def.h"
 
-/*
- * Driver debug definitions.
- */
-/* #define QL_DEBUG_LEVEL_1  */ /* Output register accesses to COM1 */
-/* #define QL_DEBUG_LEVEL_2  */ /* Output error msgs to COM1 */
-/* #define QL_DEBUG_LEVEL_3  */ /* Output function trace msgs to COM1 */
-/* #define QL_DEBUG_LEVEL_4  */ /* Output NVRAM trace msgs to COM1 */
-/* #define QL_DEBUG_LEVEL_5  */ /* Output ring trace msgs to COM1 */
-/* #define QL_DEBUG_LEVEL_6  */ /* Output WATCHDOG timer trace to COM1 */
-/* #define QL_DEBUG_LEVEL_7  */ /* Output RISC load trace msgs to COM1 */
-/* #define QL_DEBUG_LEVEL_8  */ /* Output ring saturation msgs to COM1 */
-/* #define QL_DEBUG_LEVEL_9  */ /* Output IOCTL trace msgs */
-/* #define QL_DEBUG_LEVEL_10 */ /* Output IOCTL error msgs */
-/* #define QL_DEBUG_LEVEL_11 */ /* Output Mbx Cmd trace msgs */
-/* #define QL_DEBUG_LEVEL_12 */ /* Output IP trace msgs */
-/* #define QL_DEBUG_LEVEL_13 */ /* Output fdmi function trace msgs */
-/* #define QL_DEBUG_LEVEL_14 */ /* Output RSCN trace msgs */
-/* #define QL_DEBUG_LEVEL_15 */ /* Output NPIV trace msgs */
-/* #define QL_DEBUG_LEVEL_16 */ /* Output ISP84XX trace msgs */
-/* #define QL_DEBUG_LEVEL_17 */ /* Output EEH trace messages */
-/* #define QL_DEBUG_LEVEL_18 */ /* Output T10 CRC trace messages */
-
-/*
-* Macros use for debugging the driver.
-*/
-
-#define DEBUG(x)       do { if (ql2xextended_error_logging) { x; } } while (0)
-
-#if defined(QL_DEBUG_LEVEL_1)
-#define DEBUG1(x)      do {x;} while (0)
-#else
-#define DEBUG1(x)      do {} while (0)
-#endif
-
-#define DEBUG2(x)      do { if (ql2xextended_error_logging) { x; } } while (0)
-#define DEBUG2_3(x)    do { if (ql2xextended_error_logging) { x; } } while (0)
-#define DEBUG2_3_11(x) do { if (ql2xextended_error_logging) { x; } } while (0)
-#define DEBUG2_9_10(x) do { if (ql2xextended_error_logging) { x; } } while (0)
-#define DEBUG2_11(x)   do { if (ql2xextended_error_logging) { x; } } while (0)
-#define DEBUG2_13(x)   do { if (ql2xextended_error_logging) { x; } } while (0)
-#define DEBUG2_16(x)   do { if (ql2xextended_error_logging) { x; } } while (0)
-#define DEBUG2_17(x)   do { if (ql2xextended_error_logging) { x; } } while (0)
-
-#if defined(QL_DEBUG_LEVEL_3)
-#define DEBUG3(x)      do {x;} while (0)
-#define DEBUG3_11(x)   do {x;} while (0)
-#else
-#define DEBUG3(x)      do {} while (0)
-#endif
-
-#if defined(QL_DEBUG_LEVEL_4)
-#define DEBUG4(x)      do {x;} while (0)
-#else
-#define DEBUG4(x)      do {} while (0)
-#endif
-
-#if defined(QL_DEBUG_LEVEL_5)
-#define DEBUG5(x)          do {x;} while (0)
-#else
-#define DEBUG5(x)      do {} while (0)
-#endif
-
-#if defined(QL_DEBUG_LEVEL_7)
-#define DEBUG7(x)          do {x;} while (0)
-#else
-#define DEBUG7(x)         do {} while (0)
-#endif
-
-#if defined(QL_DEBUG_LEVEL_9)
-#define DEBUG9(x)       do {x;} while (0)
-#define DEBUG9_10(x)    do {x;} while (0)
-#else
-#define DEBUG9(x)      do {} while (0)
-#endif
-
-#if defined(QL_DEBUG_LEVEL_10)
-#define DEBUG10(x)      do {x;} while (0)
-#define DEBUG9_10(x)   do {x;} while (0)
-#else
-#define DEBUG10(x)     do {} while (0)
-  #if !defined(DEBUG9_10)
-  #define DEBUG9_10(x) do {} while (0)
-  #endif
-#endif
-
-#if defined(QL_DEBUG_LEVEL_11)
-#define DEBUG11(x)      do{x;} while(0)
-#if !defined(DEBUG3_11)
-#define DEBUG3_11(x)    do{x;} while(0)
-#endif
-#else
-#define DEBUG11(x)     do{} while(0)
-  #if !defined(QL_DEBUG_LEVEL_3)
-  #define DEBUG3_11(x) do{} while(0)
-  #endif
-#endif
-
-#if defined(QL_DEBUG_LEVEL_12)
-#define DEBUG12(x)      do {x;} while (0)
-#else
-#define DEBUG12(x)     do {} while (0)
-#endif
-
-#if defined(QL_DEBUG_LEVEL_13)
-#define DEBUG13(x)      do {x;} while (0)
-#else
-#define DEBUG13(x)     do {} while (0)
-#endif
-
-#if defined(QL_DEBUG_LEVEL_14)
-#define DEBUG14(x)      do {x;} while (0)
-#else
-#define DEBUG14(x)     do {} while (0)
-#endif
-
-#if defined(QL_DEBUG_LEVEL_15)
-#define DEBUG15(x)      do {x;} while (0)
-#else
-#define DEBUG15(x)     do {} while (0)
-#endif
-
-#if defined(QL_DEBUG_LEVEL_16)
-#define DEBUG16(x)     do {x;} while (0)
-#else
-#define DEBUG16(x)     do {} while (0)
-#endif
-
-#if defined(QL_DEBUG_LEVEL_17)
-#define DEBUG17(x)     do {x;} while (0)
-#else
-#define DEBUG17(x)     do {} while (0)
-#endif
-
-#if defined(QL_DEBUG_LEVEL_18)
-#define DEBUG18(x)     do {if (ql2xextended_error_logging) x; } while (0)
-#else
-#define DEBUG18(x)     do {} while (0)
-#endif
-
-
 /*
  * Firmware Dump structure definition
  */
@@ -370,3 +230,50 @@ struct qla2xxx_fw_dump {
                struct qla81xx_fw_dump isp81;
        } isp;
 };
+
+#define QL_MSGHDR "qla2xxx"
+
+#define ql_log_fatal           0 /* display fatal errors */
+#define ql_log_warn            1 /* display critical errors */
+#define ql_log_info            2 /* display all recovered errors */
+#define ql_log_all             3 /* This value is only used by ql_errlev.
+                                  * No messages will use this value.
+                                  * This should be always highest value
+                                  * as compared to other log levels.
+                                  */
+
+extern int ql_errlev;
+
+void
+ql_dbg(uint32_t, scsi_qla_host_t *vha, int32_t, char *, ...);
+void
+ql_dbg_pci(uint32_t, struct pci_dev *pdev, int32_t, char *, ...);
+
+void
+ql_log(uint32_t, scsi_qla_host_t *vha, int32_t, char *, ...);
+void
+ql_log_pci(uint32_t, struct pci_dev *pdev, int32_t, char *, ...);
+
+/* Debug Levels */
+/* The 0x40000000 is the max value any debug level can have
+ * as ql2xextended_error_logging is of type signed int
+ */
+#define ql_dbg_init    0x40000000 /* Init Debug */
+#define ql_dbg_mbx     0x20000000 /* MBX Debug */
+#define ql_dbg_disc    0x10000000 /* Device Discovery Debug */
+#define ql_dbg_io      0x08000000 /* IO Tracing Debug */
+#define ql_dbg_dpc     0x04000000 /* DPC Thead Debug */
+#define ql_dbg_async   0x02000000 /* Async events Debug */
+#define ql_dbg_timer   0x01000000 /* Timer Debug */
+#define ql_dbg_user    0x00800000 /* User Space Interations Debug */
+#define ql_dbg_taskm   0x00400000 /* Task Management Debug */
+#define ql_dbg_aer     0x00200000 /* AER/EEH Debug */
+#define ql_dbg_multiq  0x00100000 /* MultiQ Debug */
+#define ql_dbg_p3p     0x00080000 /* P3P specific Debug */
+#define ql_dbg_vport   0x00040000 /* Virtual Port Debug */
+#define ql_dbg_buffer  0x00020000 /* For dumping the buffer/regs */
+#define ql_dbg_misc    0x00010000 /* For dumping everything that is not
+                                   * not covered by upper categories
+                                   */
+
+#define QL_DBG_BUF_LEN 512
index a5a4e12..0b4c2b7 100644 (file)
@@ -64,7 +64,7 @@ qla2x00_dfs_fce_open(struct inode *inode, struct file *file)
        /* Pause tracing to flush FCE buffers. */
        rval = qla2x00_disable_fce_trace(vha, &ha->fce_wr, &ha->fce_rd);
        if (rval)
-               qla_printk(KERN_WARNING, ha,
+               ql_dbg(ql_dbg_user, vha, 0x705c,
                    "DebugFS: Unable to disable FCE (%d).\n", rval);
 
        ha->flags.fce_enabled = 0;
@@ -92,7 +92,7 @@ qla2x00_dfs_fce_release(struct inode *inode, struct file *file)
        rval = qla2x00_enable_fce_trace(vha, ha->fce_dma, ha->fce_bufs,
            ha->fce_mb, &ha->fce_bufs);
        if (rval) {
-               qla_printk(KERN_WARNING, ha,
+               ql_dbg(ql_dbg_user, vha, 0x700d,
                    "DebugFS: Unable to reinitialize FCE (%d).\n", rval);
                ha->flags.fce_enabled = 0;
        }
@@ -125,8 +125,8 @@ qla2x00_dfs_setup(scsi_qla_host_t *vha)
        atomic_set(&qla2x00_dfs_root_count, 0);
        qla2x00_dfs_root = debugfs_create_dir(QLA2XXX_DRIVER_NAME, NULL);
        if (!qla2x00_dfs_root) {
-               qla_printk(KERN_NOTICE, ha,
-                   "DebugFS: Unable to create root directory.\n");
+               ql_log(ql_log_warn, vha, 0x00f7,
+                   "Unable to create debugfs root directory.\n");
                goto out;
        }
 
@@ -137,8 +137,8 @@ create_dir:
        mutex_init(&ha->fce_mutex);
        ha->dfs_dir = debugfs_create_dir(vha->host_str, qla2x00_dfs_root);
        if (!ha->dfs_dir) {
-               qla_printk(KERN_NOTICE, ha,
-                   "DebugFS: Unable to create ha directory.\n");
+               ql_log(ql_log_warn, vha, 0x00f8,
+                   "Unable to create debugfs ha directory.\n");
                goto out;
        }
 
@@ -148,8 +148,8 @@ create_nodes:
        ha->dfs_fce = debugfs_create_file("fce", S_IRUSR, ha->dfs_dir, vha,
            &dfs_fce_ops);
        if (!ha->dfs_fce) {
-               qla_printk(KERN_NOTICE, ha,
-                   "DebugFS: Unable to fce node.\n");
+               ql_log(ql_log_warn, vha, 0x00f9,
+                   "Unable to create debugfs fce node.\n");
                goto out;
        }
 out:
index 0b38122..29b1a3e 100644 (file)
@@ -185,7 +185,7 @@ extern int qla24xx_start_scsi(srb_t *sp);
 int qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *,
                                                uint16_t, uint16_t, uint8_t);
 extern int qla2x00_start_sp(srb_t *);
-extern uint16_t qla24xx_calc_iocbs(uint16_t);
+extern uint16_t qla24xx_calc_iocbs(scsi_qla_host_t *, uint16_t);
 extern void qla24xx_build_scsi_iocbs(srb_t *, struct cmd_type_7 *, uint16_t);
 extern int qla24xx_dif_start_scsi(srb_t *);
 
@@ -439,6 +439,9 @@ extern void qla81xx_fw_dump(scsi_qla_host_t *, int);
 extern void qla2x00_dump_regs(scsi_qla_host_t *);
 extern void qla2x00_dump_buffer(uint8_t *, uint32_t);
 extern void qla2x00_dump_buffer_zipped(uint8_t *, uint32_t);
+extern void ql_dump_regs(uint32_t, scsi_qla_host_t *, int32_t);
+extern void ql_dump_buffer(uint32_t, scsi_qla_host_t *, int32_t,
+       uint8_t *, uint32_t);
 
 /*
  * Global Function Prototypes in qla_gs.c source file.
@@ -478,7 +481,8 @@ extern int qla2x00_loopback_test(scsi_qla_host_t *, struct msg_echo_lb *, uint16
 extern int qla2x00_echo_test(scsi_qla_host_t *,
        struct msg_echo_lb *, uint16_t *);
 extern int qla24xx_update_all_fcp_prio(scsi_qla_host_t *);
-extern int qla24xx_fcp_prio_cfg_valid(struct qla_fcp_prio_cfg *, uint8_t);
+extern int qla24xx_fcp_prio_cfg_valid(scsi_qla_host_t *,
+       struct qla_fcp_prio_cfg *, uint8_t);
 
 /*
  * Global Function Prototypes in qla_dfs.c source file.
index 8cd9066..37937aa 100644 (file)
@@ -121,11 +121,10 @@ qla2x00_chk_ms_status(scsi_qla_host_t *vha, ms_iocb_entry_t *ms_pkt,
 
        rval = QLA_FUNCTION_FAILED;
        if (ms_pkt->entry_status != 0) {
-               DEBUG2_3(printk(KERN_WARNING "scsi(%ld): %s failed, error status "
-                   "(%x) on port_id: %02x%02x%02x.\n",
-                   vha->host_no, routine, ms_pkt->entry_status,
-                   vha->d_id.b.domain, vha->d_id.b.area,
-                   vha->d_id.b.al_pa));
+               ql_dbg(ql_dbg_disc, vha, 0x2031,
+                   "%s failed, error status (%x) on port_id: %02x%02x%02x.\n",
+                   routine, ms_pkt->entry_status, vha->d_id.b.domain,
+                   vha->d_id.b.area, vha->d_id.b.al_pa);
        } else {
                if (IS_FWI2_CAPABLE(ha))
                        comp_status = le16_to_cpu(
@@ -138,24 +137,24 @@ qla2x00_chk_ms_status(scsi_qla_host_t *vha, ms_iocb_entry_t *ms_pkt,
                case CS_DATA_OVERRUN:           /* Overrun? */
                        if (ct_rsp->header.response !=
                            __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) {
-                               DEBUG2_3(printk("scsi(%ld): %s failed, "
-                                   "rejected request on port_id: %02x%02x%02x\n",
-                                   vha->host_no, routine,
+                               ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x2077,
+                                   "%s failed rejected request on port_id: "
+                                   "%02x%02x%02x.\n", routine,
                                    vha->d_id.b.domain, vha->d_id.b.area,
-                                   vha->d_id.b.al_pa));
-                               DEBUG2_3(qla2x00_dump_buffer(
-                                   (uint8_t *)&ct_rsp->header,
-                                   sizeof(struct ct_rsp_hdr)));
+                                   vha->d_id.b.al_pa);
+                               ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha,
+                                   0x2078, (uint8_t *)&ct_rsp->header,
+                                   sizeof(struct ct_rsp_hdr));
                                rval = QLA_INVALID_COMMAND;
                        } else
                                rval = QLA_SUCCESS;
                        break;
                default:
-                       DEBUG2_3(printk("scsi(%ld): %s failed, completion "
-                           "status (%x) on port_id: %02x%02x%02x.\n",
-                           vha->host_no, routine, comp_status,
+                       ql_dbg(ql_dbg_disc, vha, 0x2033,
+                           "%s failed, completion status (%x) on port_id: "
+                           "%02x%02x%02x.\n", routine, comp_status,
                            vha->d_id.b.domain, vha->d_id.b.area,
-                           vha->d_id.b.al_pa));
+                           vha->d_id.b.al_pa);
                        break;
                }
        }
@@ -202,8 +201,8 @@ qla2x00_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport)
            sizeof(ms_iocb_entry_t));
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3(printk("scsi(%ld): GA_NXT issue IOCB failed (%d).\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x2062,
+                   "GA_NXT issue IOCB failed (%d).\n", rval);
        } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "GA_NXT") !=
            QLA_SUCCESS) {
                rval = QLA_FUNCTION_FAILED;
@@ -222,11 +221,10 @@ qla2x00_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport)
                    ct_rsp->rsp.ga_nxt.port_type != NS_NL_PORT_TYPE)
                        fcport->d_id.b.domain = 0xf0;
 
-               DEBUG2_3(printk("scsi(%ld): GA_NXT entry - "
-                   "nn %02x%02x%02x%02x%02x%02x%02x%02x "
+               ql_dbg(ql_dbg_disc, vha, 0x2063,
+                   "GA_NXT entry - nn %02x%02x%02x%02x%02x%02x%02x%02x "
                    "pn %02x%02x%02x%02x%02x%02x%02x%02x "
-                   "portid=%02x%02x%02x.\n",
-                   vha->host_no,
+                   "port_id=%02x%02x%02x.\n",
                    fcport->node_name[0], fcport->node_name[1],
                    fcport->node_name[2], fcport->node_name[3],
                    fcport->node_name[4], fcport->node_name[5],
@@ -236,7 +234,7 @@ qla2x00_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport)
                    fcport->port_name[4], fcport->port_name[5],
                    fcport->port_name[6], fcport->port_name[7],
                    fcport->d_id.b.domain, fcport->d_id.b.area,
-                   fcport->d_id.b.al_pa));
+                   fcport->d_id.b.al_pa);
        }
 
        return (rval);
@@ -287,8 +285,8 @@ qla2x00_gid_pt(scsi_qla_host_t *vha, sw_info_t *list)
            sizeof(ms_iocb_entry_t));
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3(printk("scsi(%ld): GID_PT issue IOCB failed (%d).\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x2055,
+                   "GID_PT issue IOCB failed (%d).\n", rval);
        } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "GID_PT") !=
            QLA_SUCCESS) {
                rval = QLA_FUNCTION_FAILED;
@@ -364,8 +362,8 @@ qla2x00_gpn_id(scsi_qla_host_t *vha, sw_info_t *list)
                    sizeof(ms_iocb_entry_t));
                if (rval != QLA_SUCCESS) {
                        /*EMPTY*/
-                       DEBUG2_3(printk("scsi(%ld): GPN_ID issue IOCB failed "
-                           "(%d).\n", vha->host_no, rval));
+                       ql_dbg(ql_dbg_disc, vha, 0x2056,
+                           "GPN_ID issue IOCB failed (%d).\n", rval);
                } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp,
                    "GPN_ID") != QLA_SUCCESS) {
                        rval = QLA_FUNCTION_FAILED;
@@ -424,8 +422,8 @@ qla2x00_gnn_id(scsi_qla_host_t *vha, sw_info_t *list)
                    sizeof(ms_iocb_entry_t));
                if (rval != QLA_SUCCESS) {
                        /*EMPTY*/
-                       DEBUG2_3(printk("scsi(%ld): GNN_ID issue IOCB failed "
-                           "(%d).\n", vha->host_no, rval));
+                       ql_dbg(ql_dbg_disc, vha, 0x2057,
+                           "GNN_ID issue IOCB failed (%d).\n", rval);
                } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp,
                    "GNN_ID") != QLA_SUCCESS) {
                        rval = QLA_FUNCTION_FAILED;
@@ -434,11 +432,10 @@ qla2x00_gnn_id(scsi_qla_host_t *vha, sw_info_t *list)
                        memcpy(list[i].node_name,
                            ct_rsp->rsp.gnn_id.node_name, WWN_SIZE);
 
-                       DEBUG2_3(printk("scsi(%ld): GID_PT entry - "
-                           "nn %02x%02x%02x%02x%02x%02x%02x%02x "
-                           "pn %02x%02x%02x%02x%02x%02x%02x%02x "
+                       ql_dbg(ql_dbg_disc, vha, 0x2058,
+                           "GID_PT entry - nn %02x%02x%02x%02x%02x%02x%02X%02x "
+                           "pn %02x%02x%02x%02x%02x%02x%02X%02x "
                            "portid=%02x%02x%02x.\n",
-                           vha->host_no,
                            list[i].node_name[0], list[i].node_name[1],
                            list[i].node_name[2], list[i].node_name[3],
                            list[i].node_name[4], list[i].node_name[5],
@@ -448,7 +445,7 @@ qla2x00_gnn_id(scsi_qla_host_t *vha, sw_info_t *list)
                            list[i].port_name[4], list[i].port_name[5],
                            list[i].port_name[6], list[i].port_name[7],
                            list[i].d_id.b.domain, list[i].d_id.b.area,
-                           list[i].d_id.b.al_pa));
+                           list[i].d_id.b.al_pa);
                }
 
                /* Last device exit. */
@@ -499,14 +496,14 @@ qla2x00_rft_id(scsi_qla_host_t *vha)
            sizeof(ms_iocb_entry_t));
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3(printk("scsi(%ld): RFT_ID issue IOCB failed (%d).\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x2043,
+                   "RFT_ID issue IOCB failed (%d).\n", rval);
        } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RFT_ID") !=
            QLA_SUCCESS) {
                rval = QLA_FUNCTION_FAILED;
        } else {
-               DEBUG2(printk("scsi(%ld): RFT_ID exiting normally.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x2044,
+                   "RFT_ID exiting normally.\n");
        }
 
        return (rval);
@@ -528,8 +525,8 @@ qla2x00_rff_id(scsi_qla_host_t *vha)
        struct ct_sns_rsp       *ct_rsp;
 
        if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
-               DEBUG2(printk("scsi(%ld): RFF_ID call unsupported on "
-                   "ISP2100/ISP2200.\n", vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x2046,
+                   "RFF_ID call not supported on ISP2100/ISP2200.\n");
                return (QLA_SUCCESS);
        }
 
@@ -556,14 +553,14 @@ qla2x00_rff_id(scsi_qla_host_t *vha)
            sizeof(ms_iocb_entry_t));
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3(printk("scsi(%ld): RFF_ID issue IOCB failed (%d).\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x2047,
+                   "RFF_ID issue IOCB failed (%d).\n", rval);
        } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RFF_ID") !=
            QLA_SUCCESS) {
                rval = QLA_FUNCTION_FAILED;
        } else {
-               DEBUG2(printk("scsi(%ld): RFF_ID exiting normally.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x2048,
+                   "RFF_ID exiting normally.\n");
        }
 
        return (rval);
@@ -609,14 +606,14 @@ qla2x00_rnn_id(scsi_qla_host_t *vha)
            sizeof(ms_iocb_entry_t));
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3(printk("scsi(%ld): RNN_ID issue IOCB failed (%d).\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x204d,
+                   "RNN_ID issue IOCB failed (%d).\n", rval);
        } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RNN_ID") !=
            QLA_SUCCESS) {
                rval = QLA_FUNCTION_FAILED;
        } else {
-               DEBUG2(printk("scsi(%ld): RNN_ID exiting normally.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x204e,
+                   "RNN_ID exiting normally.\n");
        }
 
        return (rval);
@@ -647,8 +644,8 @@ qla2x00_rsnn_nn(scsi_qla_host_t *vha)
        struct ct_sns_rsp       *ct_rsp;
 
        if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
-               DEBUG2(printk("scsi(%ld): RSNN_ID call unsupported on "
-                   "ISP2100/ISP2200.\n", vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x2050,
+                   "RSNN_ID call unsupported on ISP2100/ISP2200.\n");
                return (QLA_SUCCESS);
        }
 
@@ -682,14 +679,14 @@ qla2x00_rsnn_nn(scsi_qla_host_t *vha)
            sizeof(ms_iocb_entry_t));
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3(printk("scsi(%ld): RSNN_NN issue IOCB failed (%d).\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x2051,
+                   "RSNN_NN issue IOCB failed (%d).\n", rval);
        } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RSNN_NN") !=
            QLA_SUCCESS) {
                rval = QLA_FUNCTION_FAILED;
        } else {
-               DEBUG2(printk("scsi(%ld): RSNN_NN exiting normally.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x2052,
+                   "RSNN_NN exiting normally.\n");
        }
 
        return (rval);
@@ -757,13 +754,14 @@ qla2x00_sns_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport)
            sizeof(struct sns_cmd_pkt));
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3(printk("scsi(%ld): GA_NXT Send SNS failed (%d).\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x205f,
+                   "GA_NXT Send SNS failed (%d).\n", rval);
        } else if (sns_cmd->p.gan_data[8] != 0x80 ||
            sns_cmd->p.gan_data[9] != 0x02) {
-               DEBUG2_3(printk("scsi(%ld): GA_NXT failed, rejected request, "
-                   "ga_nxt_rsp:\n", vha->host_no));
-               DEBUG2_3(qla2x00_dump_buffer(sns_cmd->p.gan_data, 16));
+               ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x207d,
+                   "GA_NXT failed, rejected request ga_nxt_rsp:\n");
+               ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2074,
+                   sns_cmd->p.gan_data, 16);
                rval = QLA_FUNCTION_FAILED;
        } else {
                /* Populate fc_port_t entry. */
@@ -778,11 +776,10 @@ qla2x00_sns_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport)
                    sns_cmd->p.gan_data[16] != NS_NL_PORT_TYPE)
                        fcport->d_id.b.domain = 0xf0;
 
-               DEBUG2_3(printk("scsi(%ld): GA_NXT entry - "
-                   "nn %02x%02x%02x%02x%02x%02x%02x%02x "
+               ql_dbg(ql_dbg_disc, vha, 0x2061,
+                   "GA_NXT entry - nn %02x%02x%02x%02x%02x%02x%02x%02x "
                    "pn %02x%02x%02x%02x%02x%02x%02x%02x "
-                   "portid=%02x%02x%02x.\n",
-                   vha->host_no,
+                   "port_id=%02x%02x%02x.\n",
                    fcport->node_name[0], fcport->node_name[1],
                    fcport->node_name[2], fcport->node_name[3],
                    fcport->node_name[4], fcport->node_name[5],
@@ -792,7 +789,7 @@ qla2x00_sns_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport)
                    fcport->port_name[4], fcport->port_name[5],
                    fcport->port_name[6], fcport->port_name[7],
                    fcport->d_id.b.domain, fcport->d_id.b.area,
-                   fcport->d_id.b.al_pa));
+                   fcport->d_id.b.al_pa);
        }
 
        return (rval);
@@ -831,13 +828,14 @@ qla2x00_sns_gid_pt(scsi_qla_host_t *vha, sw_info_t *list)
            sizeof(struct sns_cmd_pkt));
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3(printk("scsi(%ld): GID_PT Send SNS failed (%d).\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x206d,
+                   "GID_PT Send SNS failed (%d).\n", rval);
        } else if (sns_cmd->p.gid_data[8] != 0x80 ||
            sns_cmd->p.gid_data[9] != 0x02) {
-               DEBUG2_3(printk("scsi(%ld): GID_PT failed, rejected request, "
-                   "gid_rsp:\n", vha->host_no));
-               DEBUG2_3(qla2x00_dump_buffer(sns_cmd->p.gid_data, 16));
+               ql_dbg(ql_dbg_disc, vha, 0x202f,
+                   "GID_PT failed, rejected request, gid_rsp:\n");
+               ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2081,
+                   sns_cmd->p.gid_data, 16);
                rval = QLA_FUNCTION_FAILED;
        } else {
                /* Set port IDs in switch info list. */
@@ -900,13 +898,14 @@ qla2x00_sns_gpn_id(scsi_qla_host_t *vha, sw_info_t *list)
                    GPN_ID_SNS_CMD_SIZE / 2, sizeof(struct sns_cmd_pkt));
                if (rval != QLA_SUCCESS) {
                        /*EMPTY*/
-                       DEBUG2_3(printk("scsi(%ld): GPN_ID Send SNS failed "
-                           "(%d).\n", vha->host_no, rval));
+                       ql_dbg(ql_dbg_disc, vha, 0x2032,
+                           "GPN_ID Send SNS failed (%d).\n", rval);
                } else if (sns_cmd->p.gpn_data[8] != 0x80 ||
                    sns_cmd->p.gpn_data[9] != 0x02) {
-                       DEBUG2_3(printk("scsi(%ld): GPN_ID failed, rejected "
-                           "request, gpn_rsp:\n", vha->host_no));
-                       DEBUG2_3(qla2x00_dump_buffer(sns_cmd->p.gpn_data, 16));
+                       ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x207e,
+                           "GPN_ID failed, rejected request, gpn_rsp:\n");
+                       ql_dump_buffer(ql_dbg_disc, vha, 0x207f,
+                           sns_cmd->p.gpn_data, 16);
                        rval = QLA_FUNCTION_FAILED;
                } else {
                        /* Save portname */
@@ -955,24 +954,24 @@ qla2x00_sns_gnn_id(scsi_qla_host_t *vha, sw_info_t *list)
                    GNN_ID_SNS_CMD_SIZE / 2, sizeof(struct sns_cmd_pkt));
                if (rval != QLA_SUCCESS) {
                        /*EMPTY*/
-                       DEBUG2_3(printk("scsi(%ld): GNN_ID Send SNS failed "
-                           "(%d).\n", vha->host_no, rval));
+                       ql_dbg(ql_dbg_disc, vha, 0x203f,
+                           "GNN_ID Send SNS failed (%d).\n", rval);
                } else if (sns_cmd->p.gnn_data[8] != 0x80 ||
                    sns_cmd->p.gnn_data[9] != 0x02) {
-                       DEBUG2_3(printk("scsi(%ld): GNN_ID failed, rejected "
-                           "request, gnn_rsp:\n", vha->host_no));
-                       DEBUG2_3(qla2x00_dump_buffer(sns_cmd->p.gnn_data, 16));
+                       ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x2082,
+                           "GNN_ID failed, rejected request, gnn_rsp:\n");
+                       ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x207a,
+                           sns_cmd->p.gnn_data, 16);
                        rval = QLA_FUNCTION_FAILED;
                } else {
                        /* Save nodename */
                        memcpy(list[i].node_name, &sns_cmd->p.gnn_data[16],
                            WWN_SIZE);
 
-                       DEBUG2_3(printk("scsi(%ld): GID_PT entry - "
-                           "nn %02x%02x%02x%02x%02x%02x%02x%02x "
+                       ql_dbg(ql_dbg_disc, vha, 0x206e,
+                           "GID_PT entry - nn %02x%02x%02x%02x%02x%02x%02x%02x "
                            "pn %02x%02x%02x%02x%02x%02x%02x%02x "
-                           "portid=%02x%02x%02x.\n",
-                           vha->host_no,
+                           "port_id=%02x%02x%02x.\n",
                            list[i].node_name[0], list[i].node_name[1],
                            list[i].node_name[2], list[i].node_name[3],
                            list[i].node_name[4], list[i].node_name[5],
@@ -982,7 +981,7 @@ qla2x00_sns_gnn_id(scsi_qla_host_t *vha, sw_info_t *list)
                            list[i].port_name[4], list[i].port_name[5],
                            list[i].port_name[6], list[i].port_name[7],
                            list[i].d_id.b.domain, list[i].d_id.b.area,
-                           list[i].d_id.b.al_pa));
+                           list[i].d_id.b.al_pa);
                }
 
                /* Last device exit. */
@@ -1025,17 +1024,18 @@ qla2x00_sns_rft_id(scsi_qla_host_t *vha)
            sizeof(struct sns_cmd_pkt));
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3(printk("scsi(%ld): RFT_ID Send SNS failed (%d).\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x2060,
+                   "RFT_ID Send SNS failed (%d).\n", rval);
        } else if (sns_cmd->p.rft_data[8] != 0x80 ||
            sns_cmd->p.rft_data[9] != 0x02) {
-               DEBUG2_3(printk("scsi(%ld): RFT_ID failed, rejected request, "
-                   "rft_rsp:\n", vha->host_no));
-               DEBUG2_3(qla2x00_dump_buffer(sns_cmd->p.rft_data, 16));
+               ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x2083,
+                   "RFT_ID failed, rejected request rft_rsp:\n");
+               ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2080,
+                   sns_cmd->p.rft_data, 16);
                rval = QLA_FUNCTION_FAILED;
        } else {
-               DEBUG2(printk("scsi(%ld): RFT_ID exiting normally.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x2073,
+                   "RFT_ID exiting normally.\n");
        }
 
        return (rval);
@@ -1081,17 +1081,18 @@ qla2x00_sns_rnn_id(scsi_qla_host_t *vha)
            sizeof(struct sns_cmd_pkt));
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3(printk("scsi(%ld): RNN_ID Send SNS failed (%d).\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x204a,
+                   "RNN_ID Send SNS failed (%d).\n", rval);
        } else if (sns_cmd->p.rnn_data[8] != 0x80 ||
            sns_cmd->p.rnn_data[9] != 0x02) {
-               DEBUG2_3(printk("scsi(%ld): RNN_ID failed, rejected request, "
-                   "rnn_rsp:\n", vha->host_no));
-               DEBUG2_3(qla2x00_dump_buffer(sns_cmd->p.rnn_data, 16));
+               ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x207b,
+                   "RNN_ID failed, rejected request, rnn_rsp:\n");
+               ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x207c,
+                   sns_cmd->p.rnn_data, 16);
                rval = QLA_FUNCTION_FAILED;
        } else {
-               DEBUG2(printk("scsi(%ld): RNN_ID exiting normally.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x204c,
+                   "RNN_ID exiting normally.\n");
        }
 
        return (rval);
@@ -1116,10 +1117,10 @@ qla2x00_mgmt_svr_login(scsi_qla_host_t *vha)
        ha->isp_ops->fabric_login(vha, vha->mgmt_svr_loop_id, 0xff, 0xff, 0xfa,
            mb, BIT_1|BIT_0);
        if (mb[0] != MBS_COMMAND_COMPLETE) {
-               DEBUG2_13(printk("%s(%ld): Failed MANAGEMENT_SERVER login: "
-                   "loop_id=%x mb[0]=%x mb[1]=%x mb[2]=%x mb[6]=%x mb[7]=%x\n",
-                   __func__, vha->host_no, vha->mgmt_svr_loop_id, mb[0], mb[1],
-                   mb[2], mb[6], mb[7]));
+               ql_dbg(ql_dbg_disc, vha, 0x2024,
+                   "Failed management_server login: loopid=%x mb[0]=%x "
+                   "mb[1]=%x mb[2]=%x mb[6]=%x mb[7]=%x.\n",
+                   vha->mgmt_svr_loop_id, mb[0], mb[1], mb[2], mb[6], mb[7]);
                ret = QLA_FUNCTION_FAILED;
        } else
                vha->flags.management_server_logged_in = 1;
@@ -1292,11 +1293,12 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
        memcpy(eiter->a.node_name, vha->node_name, WWN_SIZE);
        size += 4 + WWN_SIZE;
 
-       DEBUG13(printk("%s(%ld): NODENAME=%02x%02x%02x%02x%02x%02x%02x%02x.\n",
-           __func__, vha->host_no,
-           eiter->a.node_name[0], eiter->a.node_name[1], eiter->a.node_name[2],
-           eiter->a.node_name[3], eiter->a.node_name[4], eiter->a.node_name[5],
-           eiter->a.node_name[6], eiter->a.node_name[7]));
+       ql_dbg(ql_dbg_disc, vha, 0x2025,
+           "NodeName = %02x%02x%02x%02x%02x%02x%02x%02x.\n",
+           eiter->a.node_name[0], eiter->a.node_name[1],
+           eiter->a.node_name[2], eiter->a.node_name[3],
+           eiter->a.node_name[4], eiter->a.node_name[5],
+           eiter->a.node_name[6], eiter->a.node_name[7]);
 
        /* Manufacturer. */
        eiter = (struct ct_fdmi_hba_attr *) (entries + size);
@@ -1307,8 +1309,8 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
        eiter->len = cpu_to_be16(4 + alen);
        size += 4 + alen;
 
-       DEBUG13(printk("%s(%ld): MANUFACTURER=%s.\n", __func__, vha->host_no,
-           eiter->a.manufacturer));
+       ql_dbg(ql_dbg_disc, vha, 0x2026,
+           "Manufacturer = %s.\n", eiter->a.manufacturer);
 
        /* Serial number. */
        eiter = (struct ct_fdmi_hba_attr *) (entries + size);
@@ -1320,8 +1322,8 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
        eiter->len = cpu_to_be16(4 + alen);
        size += 4 + alen;
 
-       DEBUG13(printk("%s(%ld): SERIALNO=%s.\n", __func__, vha->host_no,
-           eiter->a.serial_num));
+       ql_dbg(ql_dbg_disc, vha, 0x2027,
+           "Serial no. = %s.\n", eiter->a.serial_num);
 
        /* Model name. */
        eiter = (struct ct_fdmi_hba_attr *) (entries + size);
@@ -1332,8 +1334,8 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
        eiter->len = cpu_to_be16(4 + alen);
        size += 4 + alen;
 
-       DEBUG13(printk("%s(%ld): MODEL_NAME=%s.\n", __func__, vha->host_no,
-           eiter->a.model));
+       ql_dbg(ql_dbg_disc, vha, 0x2028,
+           "Model Name = %s.\n", eiter->a.model);
 
        /* Model description. */
        eiter = (struct ct_fdmi_hba_attr *) (entries + size);
@@ -1345,8 +1347,8 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
        eiter->len = cpu_to_be16(4 + alen);
        size += 4 + alen;
 
-       DEBUG13(printk("%s(%ld): MODEL_DESC=%s.\n", __func__, vha->host_no,
-           eiter->a.model_desc));
+       ql_dbg(ql_dbg_disc, vha, 0x2029,
+           "Model Desc = %s.\n", eiter->a.model_desc);
 
        /* Hardware version. */
        eiter = (struct ct_fdmi_hba_attr *) (entries + size);
@@ -1357,8 +1359,8 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
        eiter->len = cpu_to_be16(4 + alen);
        size += 4 + alen;
 
-       DEBUG13(printk("%s(%ld): HARDWAREVER=%s.\n", __func__, vha->host_no,
-           eiter->a.hw_version));
+       ql_dbg(ql_dbg_disc, vha, 0x202a,
+           "Hardware ver = %s.\n", eiter->a.hw_version);
 
        /* Driver version. */
        eiter = (struct ct_fdmi_hba_attr *) (entries + size);
@@ -1369,8 +1371,8 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
        eiter->len = cpu_to_be16(4 + alen);
        size += 4 + alen;
 
-       DEBUG13(printk("%s(%ld): DRIVERVER=%s.\n", __func__, vha->host_no,
-           eiter->a.driver_version));
+       ql_dbg(ql_dbg_disc, vha, 0x202b,
+           "Driver ver = %s.\n", eiter->a.driver_version);
 
        /* Option ROM version. */
        eiter = (struct ct_fdmi_hba_attr *) (entries + size);
@@ -1381,8 +1383,8 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
        eiter->len = cpu_to_be16(4 + alen);
        size += 4 + alen;
 
-       DEBUG13(printk("%s(%ld): OPTROMVER=%s.\n", __func__, vha->host_no,
-           eiter->a.orom_version));
+       ql_dbg(ql_dbg_disc, vha , 0x202c,
+           "Optrom vers = %s.\n", eiter->a.orom_version);
 
        /* Firmware version */
        eiter = (struct ct_fdmi_hba_attr *) (entries + size);
@@ -1393,44 +1395,46 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
        eiter->len = cpu_to_be16(4 + alen);
        size += 4 + alen;
 
-       DEBUG13(printk("%s(%ld): FIRMWAREVER=%s.\n", __func__, vha->host_no,
-           eiter->a.fw_version));
+       ql_dbg(ql_dbg_disc, vha, 0x202d,
+           "Firmware vers = %s.\n", eiter->a.fw_version);
 
        /* Update MS request size. */
        qla2x00_update_ms_fdmi_iocb(vha, size + 16);
 
-       DEBUG13(printk("%s(%ld): RHBA identifier="
-           "%02x%02x%02x%02x%02x%02x%02x%02x size=%d.\n", __func__,
-           vha->host_no, ct_req->req.rhba.hba_identifier[0],
+       ql_dbg(ql_dbg_disc, vha, 0x202e,
+           "RHBA identifier = "
+           "%02x%02x%02x%02x%02x%02x%02x%02x size=%d.\n",
+           ct_req->req.rhba.hba_identifier[0],
            ct_req->req.rhba.hba_identifier[1],
            ct_req->req.rhba.hba_identifier[2],
            ct_req->req.rhba.hba_identifier[3],
            ct_req->req.rhba.hba_identifier[4],
            ct_req->req.rhba.hba_identifier[5],
            ct_req->req.rhba.hba_identifier[6],
-           ct_req->req.rhba.hba_identifier[7], size));
-       DEBUG13(qla2x00_dump_buffer(entries, size));
+           ct_req->req.rhba.hba_identifier[7], size);
+       ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2076,
+           entries, size);
 
        /* Execute MS IOCB */
        rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma,
            sizeof(ms_iocb_entry_t));
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3(printk("scsi(%ld): RHBA issue IOCB failed (%d).\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x2030,
+                   "RHBA issue IOCB failed (%d).\n", rval);
        } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RHBA") !=
            QLA_SUCCESS) {
                rval = QLA_FUNCTION_FAILED;
                if (ct_rsp->header.reason_code == CT_REASON_CANNOT_PERFORM &&
                    ct_rsp->header.explanation_code ==
                    CT_EXPL_ALREADY_REGISTERED) {
-                       DEBUG2_13(printk("%s(%ld): HBA already registered.\n",
-                           __func__, vha->host_no));
+                       ql_dbg(ql_dbg_disc, vha, 0x2034,
+                           "HBA already registered.\n");
                        rval = QLA_ALREADY_REGISTERED;
                }
        } else {
-               DEBUG2(printk("scsi(%ld): RHBA exiting normally.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x2035,
+                   "RHBA exiting normally.\n");
        }
 
        return rval;
@@ -1464,26 +1468,26 @@ qla2x00_fdmi_dhba(scsi_qla_host_t *vha)
        /* Prepare FDMI command arguments -- portname. */
        memcpy(ct_req->req.dhba.port_name, vha->port_name, WWN_SIZE);
 
-       DEBUG13(printk("%s(%ld): DHBA portname="
-           "%02x%02x%02x%02x%02x%02x%02x%02x.\n", __func__, vha->host_no,
+       ql_dbg(ql_dbg_disc, vha, 0x2036,
+           "DHBA portname = %02x%02x%02x%02x%02x%02x%02x%02x.\n",
            ct_req->req.dhba.port_name[0], ct_req->req.dhba.port_name[1],
            ct_req->req.dhba.port_name[2], ct_req->req.dhba.port_name[3],
            ct_req->req.dhba.port_name[4], ct_req->req.dhba.port_name[5],
-           ct_req->req.dhba.port_name[6], ct_req->req.dhba.port_name[7]));
+           ct_req->req.dhba.port_name[6], ct_req->req.dhba.port_name[7]);
 
        /* Execute MS IOCB */
        rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma,
            sizeof(ms_iocb_entry_t));
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3(printk("scsi(%ld): DHBA issue IOCB failed (%d).\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x2037,
+                   "DHBA issue IOCB failed (%d).\n", rval);
        } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "DHBA") !=
            QLA_SUCCESS) {
                rval = QLA_FUNCTION_FAILED;
        } else {
-               DEBUG2(printk("scsi(%ld): DHBA exiting normally.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x2038,
+                   "DHBA exiting normally.\n");
        }
 
        return rval;
@@ -1534,9 +1538,10 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha)
        eiter->a.fc4_types[2] = 0x01;
        size += 4 + 32;
 
-       DEBUG13(printk("%s(%ld): FC4_TYPES=%02x %02x.\n", __func__,
-               vha->host_no, eiter->a.fc4_types[2],
-               eiter->a.fc4_types[1]));
+       ql_dbg(ql_dbg_disc, vha, 0x2039,
+           "FC4_TYPES=%02x %02x.\n",
+           eiter->a.fc4_types[2],
+           eiter->a.fc4_types[1]);
 
        /* Supported speed. */
        eiter = (struct ct_fdmi_port_attr *) (entries + size);
@@ -1561,8 +1566,8 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha)
                    FDMI_PORT_SPEED_1GB);
        size += 4 + 4;
 
-       DEBUG13(printk("%s(%ld): SUPPORTED_SPEED=%x.\n", __func__, vha->host_no,
-           eiter->a.sup_speed));
+       ql_dbg(ql_dbg_disc, vha, 0x203a,
+           "Supported_Speed=%x.\n", eiter->a.sup_speed);
 
        /* Current speed. */
        eiter = (struct ct_fdmi_port_attr *) (entries + size);
@@ -1596,8 +1601,8 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha)
        }
        size += 4 + 4;
 
-       DEBUG13(printk("%s(%ld): CURRENT_SPEED=%x.\n", __func__, vha->host_no,
-           eiter->a.cur_speed));
+       ql_dbg(ql_dbg_disc, vha, 0x203b,
+           "Current_Speed=%x.\n", eiter->a.cur_speed);
 
        /* Max frame size. */
        eiter = (struct ct_fdmi_port_attr *) (entries + size);
@@ -1609,8 +1614,8 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha)
        eiter->a.max_frame_size = cpu_to_be32(max_frame_size);
        size += 4 + 4;
 
-       DEBUG13(printk("%s(%ld): MAX_FRAME_SIZE=%x.\n", __func__, vha->host_no,
-           eiter->a.max_frame_size));
+       ql_dbg(ql_dbg_disc, vha, 0x203c,
+           "Max_Frame_Size=%x.\n", eiter->a.max_frame_size);
 
        /* OS device name. */
        eiter = (struct ct_fdmi_port_attr *) (entries + size);
@@ -1621,8 +1626,8 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha)
        eiter->len = cpu_to_be16(4 + alen);
        size += 4 + alen;
 
-       DEBUG13(printk("%s(%ld): OS_DEVICE_NAME=%s.\n", __func__, vha->host_no,
-           eiter->a.os_dev_name));
+       ql_dbg(ql_dbg_disc, vha, 0x204b,
+           "OS_Device_Name=%s.\n", eiter->a.os_dev_name);
 
        /* Hostname. */
        if (strlen(fc_host_system_hostname(vha->host))) {
@@ -1637,35 +1642,36 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha)
                eiter->len = cpu_to_be16(4 + alen);
                size += 4 + alen;
 
-               DEBUG13(printk("%s(%ld): HOSTNAME=%s.\n", __func__,
-                   vha->host_no, eiter->a.host_name));
+               ql_dbg(ql_dbg_disc, vha, 0x203d,
+                   "HostName=%s.\n", eiter->a.host_name);
        }
 
        /* Update MS request size. */
        qla2x00_update_ms_fdmi_iocb(vha, size + 16);
 
-       DEBUG13(printk("%s(%ld): RPA portname="
-           "%02x%02x%02x%02x%02x%02x%02x%02x size=%d.\n", __func__,
-           vha->host_no, ct_req->req.rpa.port_name[0],
-           ct_req->req.rpa.port_name[1], ct_req->req.rpa.port_name[2],
-           ct_req->req.rpa.port_name[3], ct_req->req.rpa.port_name[4],
-           ct_req->req.rpa.port_name[5], ct_req->req.rpa.port_name[6],
-           ct_req->req.rpa.port_name[7], size));
-       DEBUG13(qla2x00_dump_buffer(entries, size));
+       ql_dbg(ql_dbg_disc, vha, 0x203e,
+           "RPA portname= %02x%02x%02x%02x%02X%02x%02x%02x size=%d.\n",
+           ct_req->req.rpa.port_name[0], ct_req->req.rpa.port_name[1],
+           ct_req->req.rpa.port_name[2], ct_req->req.rpa.port_name[3],
+           ct_req->req.rpa.port_name[4], ct_req->req.rpa.port_name[5],
+           ct_req->req.rpa.port_name[6], ct_req->req.rpa.port_name[7],
+           size);
+       ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2079,
+           entries, size);
 
        /* Execute MS IOCB */
        rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma,
            sizeof(ms_iocb_entry_t));
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3(printk("scsi(%ld): RPA issue IOCB failed (%d).\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x2040,
+                   "RPA issue IOCB failed (%d).\n", rval);
        } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RPA") !=
            QLA_SUCCESS) {
                rval = QLA_FUNCTION_FAILED;
        } else {
-               DEBUG2(printk("scsi(%ld): RPA exiting normally.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x2041,
+                   "RPA exiting nornally.\n");
        }
 
        return rval;
@@ -1749,8 +1755,8 @@ qla2x00_gfpn_id(scsi_qla_host_t *vha, sw_info_t *list)
                    sizeof(ms_iocb_entry_t));
                if (rval != QLA_SUCCESS) {
                        /*EMPTY*/
-                       DEBUG2_3(printk("scsi(%ld): GFPN_ID issue IOCB "
-                           "failed (%d).\n", vha->host_no, rval));
+                       ql_dbg(ql_dbg_disc, vha, 0x2023,
+                           "GFPN_ID issue IOCB failed (%d).\n", rval);
                } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp,
                    "GFPN_ID") != QLA_SUCCESS) {
                        rval = QLA_FUNCTION_FAILED;
@@ -1860,8 +1866,8 @@ qla2x00_gpsc(scsi_qla_host_t *vha, sw_info_t *list)
                    sizeof(ms_iocb_entry_t));
                if (rval != QLA_SUCCESS) {
                        /*EMPTY*/
-                       DEBUG2_3(printk("scsi(%ld): GPSC issue IOCB "
-                           "failed (%d).\n", vha->host_no, rval));
+                       ql_dbg(ql_dbg_disc, vha, 0x2059,
+                           "GPSC issue IOCB failed (%d).\n", rval);
                } else if ((rval = qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp,
                    "GPSC")) != QLA_SUCCESS) {
                        /* FM command unsupported? */
@@ -1870,9 +1876,9 @@ qla2x00_gpsc(scsi_qla_host_t *vha, sw_info_t *list)
                                CT_REASON_INVALID_COMMAND_CODE ||
                             ct_rsp->header.reason_code ==
                                CT_REASON_COMMAND_UNSUPPORTED)) {
-                               DEBUG2(printk("scsi(%ld): GPSC command "
-                                   "unsupported, disabling query...\n",
-                                   vha->host_no));
+                               ql_dbg(ql_dbg_disc, vha, 0x205a,
+                                   "GPSC command unsupported, disabling "
+                                   "query.\n");
                                ha->flags.gpsc_supported = 0;
                                rval = QLA_FUNCTION_FAILED;
                                break;
@@ -1898,9 +1904,10 @@ qla2x00_gpsc(scsi_qla_host_t *vha, sw_info_t *list)
                                break;
                        }
 
-                       DEBUG2_3(printk("scsi(%ld): GPSC ext entry - "
-                           "fpn %02x%02x%02x%02x%02x%02x%02x%02x speeds=%04x "
-                           "speed=%04x.\n", vha->host_no,
+                       ql_dbg(ql_dbg_disc, vha, 0x205b,
+                           "GPSC ext entry - fpn "
+                           "%02x%02x%02x%02x%02x%02x%02x%02x speeds=%04x "
+                           "speed=%04x.\n",
                            list[i].fabric_port_name[0],
                            list[i].fabric_port_name[1],
                            list[i].fabric_port_name[2],
@@ -1910,7 +1917,7 @@ qla2x00_gpsc(scsi_qla_host_t *vha, sw_info_t *list)
                            list[i].fabric_port_name[6],
                            list[i].fabric_port_name[7],
                            be16_to_cpu(ct_rsp->rsp.gpsc.speeds),
-                           be16_to_cpu(ct_rsp->rsp.gpsc.speed)));
+                           be16_to_cpu(ct_rsp->rsp.gpsc.speed));
                }
 
                /* Last device exit. */
@@ -1968,14 +1975,12 @@ qla2x00_gff_id(scsi_qla_host_t *vha, sw_info_t *list)
                   sizeof(ms_iocb_entry_t));
 
                if (rval != QLA_SUCCESS) {
-                       DEBUG2_3(printk(KERN_INFO
-                           "scsi(%ld): GFF_ID issue IOCB failed "
-                           "(%d).\n", vha->host_no, rval));
+                       ql_dbg(ql_dbg_disc, vha, 0x205c,
+                           "GFF_ID issue IOCB failed (%d).\n", rval);
                } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp,
                               "GFF_ID") != QLA_SUCCESS) {
-                       DEBUG2_3(printk(KERN_INFO
-                           "scsi(%ld): GFF_ID IOCB status had a "
-                           "failure status code\n", vha->host_no));
+                       ql_dbg(ql_dbg_disc, vha, 0x205d,
+                           "GFF_ID IOCB status had a failure status code.\n");
                } else {
                        fcp_scsi_features =
                           ct_rsp->rsp.gff_id.fc4_features[GFF_FCP_SCSI_OFFSET];
index 920b76b..def6942 100644 (file)
@@ -153,11 +153,10 @@ qla2x00_async_iocb_timeout(srb_t *sp)
        fc_port_t *fcport = sp->fcport;
        struct srb_ctx *ctx = sp->ctx;
 
-       DEBUG2(printk(KERN_WARNING
-               "scsi(%ld:%x): Async-%s timeout - portid=%02x%02x%02x.\n",
-               fcport->vha->host_no, sp->handle,
-               ctx->name, fcport->d_id.b.domain,
-               fcport->d_id.b.area, fcport->d_id.b.al_pa));
+       ql_dbg(ql_dbg_disc, fcport->vha, 0x2071,
+           "Async-%s timeout - portid=%02x%02x%02x.\n",
+           ctx->name, fcport->d_id.b.domain, fcport->d_id.b.area,
+           fcport->d_id.b.al_pa);
 
        fcport->flags &= ~FCF_ASYNC_SENT;
        if (ctx->type == SRB_LOGIN_CMD) {
@@ -211,11 +210,10 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
        if (rval != QLA_SUCCESS)
                goto done_free_sp;
 
-       DEBUG2(printk(KERN_DEBUG
-           "scsi(%ld:%x): Async-login - loop-id=%x portid=%02x%02x%02x "
-           "retries=%d.\n", fcport->vha->host_no, sp->handle, fcport->loop_id,
-           fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa,
-           fcport->login_retry));
+       ql_dbg(ql_dbg_disc, vha, 0x2072,
+           "Async-login - loopid=%x portid=%02x%02x%02x retries=%d.\n",
+           fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area,
+           fcport->d_id.b.al_pa, fcport->login_retry);
        return rval;
 
 done_free_sp:
@@ -259,10 +257,10 @@ qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport)
        if (rval != QLA_SUCCESS)
                goto done_free_sp;
 
-       DEBUG2(printk(KERN_DEBUG
-           "scsi(%ld:%x): Async-logout - loop-id=%x portid=%02x%02x%02x.\n",
-           fcport->vha->host_no, sp->handle, fcport->loop_id,
-           fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa));
+       ql_dbg(ql_dbg_disc, vha, 0x2070,
+           "Async-logout - loop-id=%x portid=%02x%02x%02x.\n",
+           fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area,
+           fcport->d_id.b.al_pa);
        return rval;
 
 done_free_sp:
@@ -309,11 +307,10 @@ qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport,
        if (rval != QLA_SUCCESS)
                goto done_free_sp;
 
-       DEBUG2(printk(KERN_DEBUG
-           "scsi(%ld:%x): Async-adisc - loop-id=%x portid=%02x%02x%02x.\n",
-           fcport->vha->host_no, sp->handle, fcport->loop_id,
-           fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa));
-
+       ql_dbg(ql_dbg_disc, vha, 0x206f,
+           "Async-adisc - loopid=%x portid=%02x%02x%02x.\n",
+           fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area,
+           fcport->d_id.b.al_pa);
        return rval;
 
 done_free_sp:
@@ -362,11 +359,10 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
        if (rval != QLA_SUCCESS)
                goto done_free_sp;
 
-       DEBUG2(printk(KERN_DEBUG
-           "scsi(%ld:%x): Async-tmf - loop-id=%x portid=%02x%02x%02x.\n",
-           fcport->vha->host_no, sp->handle, fcport->loop_id,
-           fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa));
-
+       ql_dbg(ql_dbg_taskm, vha, 0x802f,
+           "Async-tmf loop-id=%x portid=%02x%02x%02x.\n",
+           fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area,
+           fcport->d_id.b.al_pa);
        return rval;
 
 done_free_sp:
@@ -471,9 +467,8 @@ qla2x00_async_tm_cmd_done(struct scsi_qla_host *vha, fc_port_t *fcport,
                flags == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID);
 
        if ((rval != QLA_SUCCESS) || iocb->u.tmf.data) {
-               DEBUG2_3_11(printk(KERN_WARNING
-                       "%s(%ld): TM IOCB failed (%x).\n",
-                       __func__, vha->host_no, rval));
+               ql_dbg(ql_dbg_taskm, vha, 0x8030,
+                   "TM IOCB failed (%x).\n", rval);
        }
 
        return;
@@ -519,11 +514,12 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
        set_bit(0, ha->req_qid_map);
        set_bit(0, ha->rsp_qid_map);
 
-       qla_printk(KERN_INFO, ha, "Configuring PCI space...\n");
+       ql_log(ql_log_info, vha, 0x0040,
+           "Configuring PCI space...\n");
        rval = ha->isp_ops->pci_config(vha);
        if (rval) {
-               DEBUG2(printk("scsi(%ld): Unable to configure PCI space.\n",
-                   vha->host_no));
+               ql_log(ql_log_warn, vha, 0x0044,
+                   "Unable to configure PCI space.\n");
                return (rval);
        }
 
@@ -531,20 +527,21 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
 
        rval = qla2xxx_get_flash_info(vha);
        if (rval) {
-               DEBUG2(printk("scsi(%ld): Unable to validate FLASH data.\n",
-                   vha->host_no));
+               ql_log(ql_log_fatal, vha, 0x004f,
+                   "Unable to validate FLASH data.\n");
                return (rval);
        }
 
        ha->isp_ops->get_flash_version(vha, req->ring);
-
-       qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n");
+       ql_log(ql_log_info, vha, 0x0061,
+           "Configure NVRAM parameters...\n");
 
        ha->isp_ops->nvram_config(vha);
 
        if (ha->flags.disable_serdes) {
                /* Mask HBA via NVRAM settings? */
-               qla_printk(KERN_INFO, ha, "Masking HBA WWPN "
+               ql_log(ql_log_info, vha, 0x0077,
+                   "Masking HBA WWPN "
                    "%02x%02x%02x%02x%02x%02x%02x%02x (via NVRAM).\n",
                    vha->port_name[0], vha->port_name[1],
                    vha->port_name[2], vha->port_name[3],
@@ -553,7 +550,8 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
                return QLA_FUNCTION_FAILED;
        }
 
-       qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n");
+       ql_log(ql_log_info, vha, 0x0078,
+           "Verifying loaded RISC code...\n");
 
        if (qla2x00_isp_firmware(vha) != QLA_SUCCESS) {
                rval = ha->isp_ops->chip_diag(vha);
@@ -567,7 +565,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
        if (IS_QLA84XX(ha)) {
                ha->cs84xx = qla84xx_get_chip(vha);
                if (!ha->cs84xx) {
-                       qla_printk(KERN_ERR, ha,
+                       ql_log(ql_log_warn, vha, 0x00d0,
                            "Unable to configure ISP84XX.\n");
                        return QLA_FUNCTION_FAILED;
                }
@@ -579,8 +577,8 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
                /* Issue verify 84xx FW IOCB to complete 84xx initialization */
                rval = qla84xx_init_chip(vha);
                if (rval != QLA_SUCCESS) {
-                       qla_printk(KERN_ERR, ha,
-                               "Unable to initialize ISP84XX.\n");
+                       ql_log(ql_log_warn, vha, 0x00d4,
+                           "Unable to initialize ISP84XX.\n");
                qla84xx_put_chip(vha);
                }
        }
@@ -797,9 +795,7 @@ qla2x00_isp_firmware(scsi_qla_host_t *vha)
        rval = QLA_FUNCTION_FAILED;
 
        if (ha->flags.disable_risc_code_load) {
-               DEBUG2(printk("scsi(%ld): RISC CODE NOT loaded\n",
-                   vha->host_no));
-               qla_printk(KERN_INFO, ha, "RISC CODE NOT loaded\n");
+               ql_log(ql_log_info, vha, 0x0079, "RISC CODE NOT loaded.\n");
 
                /* Verify checksum of loaded RISC code. */
                rval = qla2x00_verify_checksum(vha, ha->fw_srisc_address);
@@ -810,10 +806,9 @@ qla2x00_isp_firmware(scsi_qla_host_t *vha)
                }
        }
 
-       if (rval) {
-               DEBUG2_3(printk("scsi(%ld): **** Load RISC code ****\n",
-                   vha->host_no));
-       }
+       if (rval)
+               ql_dbg(ql_dbg_init, vha, 0x007a,
+                   "**** Load RISC code ****.\n");
 
        return (rval);
 }
@@ -1105,8 +1100,8 @@ qla2x00_chip_diag(scsi_qla_host_t *vha)
        /* Assume a failed state */
        rval = QLA_FUNCTION_FAILED;
 
-       DEBUG3(printk("scsi(%ld): Testing device at %lx.\n",
-           vha->host_no, (u_long)&reg->flash_address));
+       ql_dbg(ql_dbg_init, vha, 0x007b,
+           "Testing device at %lx.\n", (u_long)&reg->flash_address);
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
 
@@ -1128,8 +1123,8 @@ qla2x00_chip_diag(scsi_qla_host_t *vha)
        if (!cnt)
                goto chip_diag_failed;
 
-       DEBUG3(printk("scsi(%ld): Reset register cleared by chip reset\n",
-           vha->host_no));
+       ql_dbg(ql_dbg_init, vha, 0x007c,
+           "Reset register cleared by chip reset.\n");
 
        /* Reset RISC processor. */
        WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
@@ -1150,7 +1145,7 @@ qla2x00_chip_diag(scsi_qla_host_t *vha)
                goto chip_diag_failed;
 
        /* Check product ID of chip */
-       DEBUG3(printk("scsi(%ld): Checking product ID of chip\n", vha->host_no));
+       ql_dbg(ql_dbg_init, vha, 0x007d, "Checking product Id of chip.\n");
 
        mb[1] = RD_MAILBOX_REG(ha, reg, 1);
        mb[2] = RD_MAILBOX_REG(ha, reg, 2);
@@ -1158,8 +1153,9 @@ qla2x00_chip_diag(scsi_qla_host_t *vha)
        mb[4] = qla2x00_debounce_register(MAILBOX_REG(ha, reg, 4));
        if (mb[1] != PROD_ID_1 || (mb[2] != PROD_ID_2 && mb[2] != PROD_ID_2a) ||
            mb[3] != PROD_ID_3) {
-               qla_printk(KERN_WARNING, ha,
-                   "Wrong product ID = 0x%x,0x%x,0x%x\n", mb[1], mb[2], mb[3]);
+               ql_log(ql_log_warn, vha, 0x0062,
+                   "Wrong product ID = 0x%x,0x%x,0x%x.\n",
+                   mb[1], mb[2], mb[3]);
 
                goto chip_diag_failed;
        }
@@ -1178,8 +1174,7 @@ qla2x00_chip_diag(scsi_qla_host_t *vha)
        if (IS_QLA2200(ha) &&
            RD_MAILBOX_REG(ha, reg, 7) == QLA2200A_RISC_ROM_VER) {
                /* Limit firmware transfer size with a 2200A */
-               DEBUG3(printk("scsi(%ld): Found QLA2200A chip.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_init, vha, 0x007e, "Found QLA2200A Chip.\n");
 
                ha->device_type |= DT_ISP2200A;
                ha->fw_transfer_size = 128;
@@ -1188,24 +1183,20 @@ qla2x00_chip_diag(scsi_qla_host_t *vha)
        /* Wrap Incoming Mailboxes Test. */
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
-       DEBUG3(printk("scsi(%ld): Checking mailboxes.\n", vha->host_no));
+       ql_dbg(ql_dbg_init, vha, 0x007f, "Checking mailboxes.\n");
        rval = qla2x00_mbx_reg_test(vha);
-       if (rval) {
-               DEBUG(printk("scsi(%ld): Failed mailbox send register test\n",
-                   vha->host_no));
-               qla_printk(KERN_WARNING, ha,
-                   "Failed mailbox send register test\n");
-       }
-       else {
+       if (rval)
+               ql_log(ql_log_warn, vha, 0x0080,
+                   "Failed mailbox send register test.\n");
+       else
                /* Flag a successful rval */
                rval = QLA_SUCCESS;
-       }
        spin_lock_irqsave(&ha->hardware_lock, flags);
 
 chip_diag_failed:
        if (rval)
-               DEBUG2_3(printk("scsi(%ld): Chip diagnostics **** FAILED "
-                   "****\n", vha->host_no));
+               ql_log(ql_log_info, vha, 0x0081,
+                   "Chip diagnostics **** FAILED ****.\n");
 
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
@@ -1232,10 +1223,8 @@ qla24xx_chip_diag(scsi_qla_host_t *vha)
 
        rval = qla2x00_mbx_reg_test(vha);
        if (rval) {
-               DEBUG(printk("scsi(%ld): Failed mailbox send register test\n",
-                   vha->host_no));
-               qla_printk(KERN_WARNING, ha,
-                   "Failed mailbox send register test\n");
+               ql_log(ql_log_warn, vha, 0x0082,
+                   "Failed mailbox send register test.\n");
        } else {
                /* Flag a successful rval */
                rval = QLA_SUCCESS;
@@ -1257,8 +1246,8 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
        struct rsp_que *rsp = ha->rsp_q_map[0];
 
        if (ha->fw_dump) {
-               qla_printk(KERN_WARNING, ha,
-                   "Firmware dump previously allocated.\n");
+               ql_dbg(ql_dbg_init, vha, 0x00bd,
+                   "Firmware dump already allocated.\n");
                return;
        }
 
@@ -1288,8 +1277,9 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
                tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma,
                    GFP_KERNEL);
                if (!tc) {
-                       qla_printk(KERN_WARNING, ha, "Unable to allocate "
-                           "(%d KB) for FCE.\n", FCE_SIZE / 1024);
+                       ql_log(ql_log_warn, vha, 0x00be,
+                           "Unable to allocate (%d KB) for FCE.\n",
+                           FCE_SIZE / 1024);
                        goto try_eft;
                }
 
@@ -1297,16 +1287,15 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
                rval = qla2x00_enable_fce_trace(vha, tc_dma, FCE_NUM_BUFFERS,
                    ha->fce_mb, &ha->fce_bufs);
                if (rval) {
-                       qla_printk(KERN_WARNING, ha, "Unable to initialize "
-                           "FCE (%d).\n", rval);
+                       ql_log(ql_log_warn, vha, 0x00bf,
+                           "Unable to initialize FCE (%d).\n", rval);
                        dma_free_coherent(&ha->pdev->dev, FCE_SIZE, tc,
                            tc_dma);
                        ha->flags.fce_enabled = 0;
                        goto try_eft;
                }
-
-               qla_printk(KERN_INFO, ha, "Allocated (%d KB) for FCE...\n",
-                   FCE_SIZE / 1024);
+               ql_log(ql_log_info, vha, 0x00c0,
+                   "Allocate (%d KB) for FCE...\n", FCE_SIZE / 1024);
 
                fce_size = sizeof(struct qla2xxx_fce_chain) + FCE_SIZE;
                ha->flags.fce_enabled = 1;
@@ -1317,23 +1306,23 @@ try_eft:
                tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma,
                    GFP_KERNEL);
                if (!tc) {
-                       qla_printk(KERN_WARNING, ha, "Unable to allocate "
-                           "(%d KB) for EFT.\n", EFT_SIZE / 1024);
+                       ql_log(ql_log_warn, vha, 0x00c1,
+                           "Unable to allocate (%d KB) for EFT.\n",
+                           EFT_SIZE / 1024);
                        goto cont_alloc;
                }
 
                memset(tc, 0, EFT_SIZE);
                rval = qla2x00_enable_eft_trace(vha, tc_dma, EFT_NUM_BUFFERS);
                if (rval) {
-                       qla_printk(KERN_WARNING, ha, "Unable to initialize "
-                           "EFT (%d).\n", rval);
+                       ql_log(ql_log_warn, vha, 0x00c2,
+                           "Unable to initialize EFT (%d).\n", rval);
                        dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc,
                            tc_dma);
                        goto cont_alloc;
                }
-
-               qla_printk(KERN_INFO, ha, "Allocated (%d KB) for EFT...\n",
-                   EFT_SIZE / 1024);
+               ql_log(ql_log_info, vha, 0x00c3,
+                   "Allocated (%d KB) EFT ...\n", EFT_SIZE / 1024);
 
                eft_size = EFT_SIZE;
                ha->eft_dma = tc_dma;
@@ -1350,8 +1339,9 @@ cont_alloc:
 
        ha->fw_dump = vmalloc(dump_size);
        if (!ha->fw_dump) {
-               qla_printk(KERN_WARNING, ha, "Unable to allocate (%d KB) for "
-                   "firmware dump!!!\n", dump_size / 1024);
+               ql_log(ql_log_warn, vha, 0x00c4,
+                   "Unable to allocate (%d KB) for firmware dump.\n",
+                   dump_size / 1024);
 
                if (ha->fce) {
                        dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce,
@@ -1368,8 +1358,8 @@ cont_alloc:
                }
                return;
        }
-       qla_printk(KERN_INFO, ha, "Allocated (%d KB) for firmware dump...\n",
-           dump_size / 1024);
+       ql_log(ql_log_info, vha, 0x00c5,
+           "Allocated (%d KB) for firmware dump.\n", dump_size / 1024);
 
        ha->fw_dump_len = dump_size;
        ha->fw_dump->signature[0] = 'Q';
@@ -1398,23 +1388,21 @@ qla81xx_mpi_sync(scsi_qla_host_t *vha)
        int rval;
        uint16_t dc;
        uint32_t dw;
-       struct qla_hw_data *ha = vha->hw;
 
        if (!IS_QLA81XX(vha->hw))
                return QLA_SUCCESS;
 
        rval = qla2x00_write_ram_word(vha, 0x7c00, 1);
        if (rval != QLA_SUCCESS) {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-                   "Sync-MPI: Unable to acquire semaphore.\n"));
+               ql_log(ql_log_warn, vha, 0x0105,
+                   "Unable to acquire semaphore.\n");
                goto done;
        }
 
        pci_read_config_word(vha->hw->pdev, 0x54, &dc);
        rval = qla2x00_read_ram_word(vha, 0x7a15, &dw);
        if (rval != QLA_SUCCESS) {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-                   "Sync-MPI: Unable to read sync.\n"));
+               ql_log(ql_log_warn, vha, 0x0067, "Unable to read sync.\n");
                goto done_release;
        }
 
@@ -1426,15 +1414,14 @@ qla81xx_mpi_sync(scsi_qla_host_t *vha)
        dw |= dc;
        rval = qla2x00_write_ram_word(vha, 0x7a15, dw);
        if (rval != QLA_SUCCESS) {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-                   "Sync-MPI: Unable to gain sync.\n"));
+               ql_log(ql_log_warn, vha, 0x0114, "Unable to gain sync.\n");
        }
 
 done_release:
        rval = qla2x00_write_ram_word(vha, 0x7c00, 0);
        if (rval != QLA_SUCCESS) {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-                   "Sync-MPI: Unable to release semaphore.\n"));
+               ql_log(ql_log_warn, vha, 0x006d,
+                   "Unable to release semaphore.\n");
        }
 
 done:
@@ -1479,14 +1466,14 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
        /* Load firmware sequences */
        rval = ha->isp_ops->load_risc(vha, &srisc_address);
        if (rval == QLA_SUCCESS) {
-               DEBUG(printk("scsi(%ld): Verifying Checksum of loaded RISC "
-                   "code.\n", vha->host_no));
+               ql_dbg(ql_dbg_init, vha, 0x00c9,
+                   "Verifying Checksum of loaded RISC code.\n");
 
                rval = qla2x00_verify_checksum(vha, srisc_address);
                if (rval == QLA_SUCCESS) {
                        /* Start firmware execution. */
-                       DEBUG(printk("scsi(%ld): Checksum OK, start "
-                           "firmware.\n", vha->host_no));
+                       ql_dbg(ql_dbg_init, vha, 0x00ca,
+                           "Starting firmware.\n");
 
                        rval = qla2x00_execute_fw(vha, srisc_address);
                        /* Retrieve firmware information. */
@@ -1522,9 +1509,9 @@ enable_82xx_npiv:
                                }
                        }
                } else {
-                       DEBUG2(printk(KERN_INFO
-                           "scsi(%ld): ISP Firmware failed checksum.\n",
-                           vha->host_no));
+                       ql_log(ql_log_fatal, vha, 0x00cd,
+                           "ISP Firmware failed checksum.\n");
+                       goto failed;
                }
        }
 
@@ -1549,7 +1536,7 @@ enable_82xx_npiv:
                        ha->flags.fac_supported = 1;
                        ha->fdt_block_size = size << 2;
                } else {
-                       qla_printk(KERN_ERR, ha,
+                       ql_log(ql_log_warn, vha, 0x00ce,
                            "Unsupported FAC firmware (%d.%02d.%02d).\n",
                            ha->fw_major_version, ha->fw_minor_version,
                            ha->fw_subminor_version);
@@ -1557,8 +1544,8 @@ enable_82xx_npiv:
        }
 failed:
        if (rval) {
-               DEBUG2_3(printk("scsi(%ld): Setup chip **** FAILED ****.\n",
-                   vha->host_no));
+               ql_log(ql_log_fatal, vha, 0x00cf,
+                   "Setup chip ****FAILED****.\n");
        }
 
        return (rval);
@@ -1608,10 +1595,11 @@ qla2x00_update_fw_options(scsi_qla_host_t *vha)
                return;
 
        /* Serial Link options. */
-       DEBUG3(printk("scsi(%ld): Serial link options:\n",
-           vha->host_no));
-       DEBUG3(qla2x00_dump_buffer((uint8_t *)&ha->fw_seriallink_options,
-           sizeof(ha->fw_seriallink_options)));
+       ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x0115,
+           "Serial link options.\n");
+       ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0109,
+           (uint8_t *)&ha->fw_seriallink_options,
+           sizeof(ha->fw_seriallink_options));
 
        ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING;
        if (ha->fw_seriallink_options[3] & BIT_2) {
@@ -1688,7 +1676,7 @@ qla24xx_update_fw_options(scsi_qla_host_t *vha)
            le16_to_cpu(ha->fw_seriallink_options24[2]),
            le16_to_cpu(ha->fw_seriallink_options24[3]));
        if (rval != QLA_SUCCESS) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x0104,
                    "Unable to update Serial Link options (%x).\n", rval);
        }
 }
@@ -1746,8 +1734,9 @@ qla24xx_config_rings(struct scsi_qla_host *vha)
                icb->rid = __constant_cpu_to_le16(rid);
                if (ha->flags.msix_enabled) {
                        msix = &ha->msix_entries[1];
-                       DEBUG2_17(printk(KERN_INFO
-                       "Registering vector 0x%x for base que\n", msix->entry));
+                       ql_dbg(ql_dbg_init, vha, 0x00fd,
+                           "Registering vector 0x%x for base que.\n",
+                           msix->entry);
                        icb->msix = cpu_to_le16(msix->entry);
                }
                /* Use alternate PCI bus number */
@@ -1764,8 +1753,8 @@ qla24xx_config_rings(struct scsi_qla_host *vha)
                        icb->firmware_options_2 &=
                                __constant_cpu_to_le32(~BIT_22);
                        ha->flags.disable_msix_handshake = 1;
-                       qla_printk(KERN_INFO, ha,
-                               "MSIX Handshake Disable Mode turned on\n");
+                       ql_dbg(ql_dbg_init, vha, 0x00fe,
+                           "MSIX Handshake Disable Mode turned on.\n");
                } else {
                        icb->firmware_options_2 |=
                                __constant_cpu_to_le32(BIT_22);
@@ -1850,7 +1839,7 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
        /* Update any ISP specific firmware options before initialization. */
        ha->isp_ops->update_fw_options(vha);
 
-       DEBUG(printk("scsi(%ld): Issue init firmware.\n", vha->host_no));
+       ql_dbg(ql_dbg_init, vha, 0x00d1, "Issue init firmware.\n");
 
        if (ha->flags.npiv_supported) {
                if (ha->operating_mode == LOOP)
@@ -1866,11 +1855,11 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
 
        rval = qla2x00_init_firmware(vha, ha->init_cb_size);
        if (rval) {
-               DEBUG2_3(printk("scsi(%ld): Init firmware **** FAILED ****.\n",
-                   vha->host_no));
+               ql_log(ql_log_fatal, vha, 0x00d2,
+                   "Init Firmware **** FAILED ****.\n");
        } else {
-               DEBUG3(printk("scsi(%ld): Init firmware -- success.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_init, vha, 0x00d3,
+                   "Init Firmware -- success.\n");
        }
 
        return (rval);
@@ -1913,10 +1902,8 @@ qla2x00_fw_ready(scsi_qla_host_t *vha)
 
        /* Wait for ISP to finish LIP */
        if (!vha->flags.init_done)
-               qla_printk(KERN_INFO, ha, "Waiting for LIP to complete...\n");
-
-       DEBUG3(printk("scsi(%ld): Waiting for LIP to complete...\n",
-           vha->host_no));
+               ql_log(ql_log_info, vha, 0x801e,
+                   "Waiting for LIP to complete.\n");
 
        do {
                rval = qla2x00_get_firmware_state(vha, state);
@@ -1925,30 +1912,35 @@ qla2x00_fw_ready(scsi_qla_host_t *vha)
                                vha->device_flags &= ~DFLG_NO_CABLE;
                        }
                        if (IS_QLA84XX(ha) && state[0] != FSTATE_READY) {
-                               DEBUG16(printk("scsi(%ld): fw_state=%x "
-                                   "84xx=%x.\n", vha->host_no, state[0],
-                                   state[2]));
+                               ql_dbg(ql_dbg_taskm, vha, 0x801f,
+                                   "fw_state=%x 84xx=%x.\n", state[0],
+                                   state[2]);
                                if ((state[2] & FSTATE_LOGGED_IN) &&
                                     (state[2] & FSTATE_WAITING_FOR_VERIFY)) {
-                                       DEBUG16(printk("scsi(%ld): Sending "
-                                           "verify iocb.\n", vha->host_no));
+                                       ql_dbg(ql_dbg_taskm, vha, 0x8028,
+                                           "Sending verify iocb.\n");
 
                                        cs84xx_time = jiffies;
                                        rval = qla84xx_init_chip(vha);
-                                       if (rval != QLA_SUCCESS)
+                                       if (rval != QLA_SUCCESS) {
+                                               ql_log(ql_log_warn,
+                                                   vha, 0x8043,
+                                                   "Init chip failed.\n");
                                                break;
+                                       }
 
                                        /* Add time taken to initialize. */
                                        cs84xx_time = jiffies - cs84xx_time;
                                        wtime += cs84xx_time;
                                        mtime += cs84xx_time;
-                                       DEBUG16(printk("scsi(%ld): Increasing "
-                                           "wait time by %ld. New time %ld\n",
-                                           vha->host_no, cs84xx_time, wtime));
+                                       ql_dbg(ql_dbg_taskm, vha, 0x8042,
+                                           "Increasing wait time by %ld. "
+                                           "New time %ld.\n", cs84xx_time,
+                                           wtime);
                                }
                        } else if (state[0] == FSTATE_READY) {
-                               DEBUG(printk("scsi(%ld): F/W Ready - OK \n",
-                                   vha->host_no));
+                               ql_dbg(ql_dbg_taskm, vha, 0x8037,
+                                   "F/W Ready - OK.\n");
 
                                qla2x00_get_retry_cnt(vha, &ha->retry_count,
                                    &ha->login_timeout, &ha->r_a_tov);
@@ -1965,7 +1957,7 @@ qla2x00_fw_ready(scsi_qla_host_t *vha)
                                 * other than Wait for Login.
                                 */
                                if (time_after_eq(jiffies, mtime)) {
-                                       qla_printk(KERN_INFO, ha,
+                                       ql_log(ql_log_info, vha, 0x8038,
                                            "Cable is unplugged...\n");
 
                                        vha->device_flags |= DFLG_NO_CABLE;
@@ -1985,17 +1977,17 @@ qla2x00_fw_ready(scsi_qla_host_t *vha)
                /* Delay for a while */
                msleep(500);
 
-               DEBUG3(printk("scsi(%ld): fw_state=%x curr time=%lx.\n",
-                   vha->host_no, state[0], jiffies));
+               ql_dbg(ql_dbg_taskm, vha, 0x8039,
+                   "fw_state=%x curr time=%lx.\n", state[0], jiffies);
        } while (1);
 
-       DEBUG(printk("scsi(%ld): fw_state=%x (%x, %x, %x, %x) curr time=%lx.\n",
-           vha->host_no, state[0], state[1], state[2], state[3], state[4],
-           jiffies));
+       ql_dbg(ql_dbg_taskm, vha, 0x803a,
+           "fw_state=%x (%x, %x, %x, %x) " "curr time=%lx.\n", state[0],
+           state[1], state[2], state[3], state[4], jiffies);
 
        if (rval) {
-               DEBUG2_3(printk("scsi(%ld): Firmware ready **** FAILED ****.\n",
-                   vha->host_no));
+               ql_log(ql_log_warn, vha, 0x803b,
+                   "Firmware ready **** FAILED ****.\n");
        }
 
        return (rval);
@@ -2034,19 +2026,19 @@ qla2x00_configure_hba(scsi_qla_host_t *vha)
                if (LOOP_TRANSITION(vha) || atomic_read(&ha->loop_down_timer) ||
                    IS_QLA8XXX_TYPE(ha) ||
                    (rval == QLA_COMMAND_ERROR && loop_id == 0x7)) {
-                       DEBUG2(printk("%s(%ld) Loop is in a transition state\n",
-                           __func__, vha->host_no));
+                       ql_dbg(ql_dbg_disc, vha, 0x2008,
+                           "Loop is in a transition state.\n");
                } else {
-                       qla_printk(KERN_WARNING, ha,
-                           "ERROR -- Unable to get host loop ID.\n");
+                       ql_log(ql_log_warn, vha, 0x2009,
+                           "Unable to get host loop ID.\n");
                        set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                }
                return (rval);
        }
 
        if (topo == 4) {
-               qla_printk(KERN_INFO, ha,
-                       "Cannot get topology - retrying.\n");
+               ql_log(ql_log_info, vha, 0x200a,
+                   "Cannot get topology - retrying.\n");
                return (QLA_FUNCTION_FAILED);
        }
 
@@ -2059,31 +2051,27 @@ qla2x00_configure_hba(scsi_qla_host_t *vha)
 
        switch (topo) {
        case 0:
-               DEBUG3(printk("scsi(%ld): HBA in NL topology.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x200b, "HBA in NL topology.\n");
                ha->current_topology = ISP_CFG_NL;
                strcpy(connect_type, "(Loop)");
                break;
 
        case 1:
-               DEBUG3(printk("scsi(%ld): HBA in FL topology.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x200c, "HBA in FL topology.\n");
                ha->switch_cap = sw_cap;
                ha->current_topology = ISP_CFG_FL;
                strcpy(connect_type, "(FL_Port)");
                break;
 
        case 2:
-               DEBUG3(printk("scsi(%ld): HBA in N P2P topology.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x200d, "HBA in N P2P topology.\n");
                ha->operating_mode = P2P;
                ha->current_topology = ISP_CFG_N;
                strcpy(connect_type, "(N_Port-to-N_Port)");
                break;
 
        case 3:
-               DEBUG3(printk("scsi(%ld): HBA in F P2P topology.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x200e, "HBA in F P2P topology.\n");
                ha->switch_cap = sw_cap;
                ha->operating_mode = P2P;
                ha->current_topology = ISP_CFG_F;
@@ -2091,9 +2079,8 @@ qla2x00_configure_hba(scsi_qla_host_t *vha)
                break;
 
        default:
-               DEBUG3(printk("scsi(%ld): HBA in unknown topology %x. "
-                   "Using NL.\n",
-                   vha->host_no, topo));
+               ql_dbg(ql_dbg_disc, vha, 0x200f,
+                   "HBA in unknown topology %x, using NL.\n", topo);
                ha->current_topology = ISP_CFG_NL;
                strcpy(connect_type, "(Loop)");
                break;
@@ -2106,14 +2093,16 @@ qla2x00_configure_hba(scsi_qla_host_t *vha)
        vha->d_id.b.al_pa = al_pa;
 
        if (!vha->flags.init_done)
-               qla_printk(KERN_INFO, ha,
-                   "Topology - %s, Host Loop address 0x%x\n",
+               ql_log(ql_log_info, vha, 0x2010,
+                   "Topology - %s, Host Loop address 0x%x.\n",
                    connect_type, vha->loop_id);
 
        if (rval) {
-               DEBUG2_3(printk("scsi(%ld): FAILED.\n", vha->host_no));
+               ql_log(ql_log_warn, vha, 0x2011,
+                   "%s FAILED\n", __func__);
        } else {
-               DEBUG3(printk("scsi(%ld): exiting normally.\n", vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x2012,
+                   "%s success\n", __func__);
        }
 
        return(rval);
@@ -2227,18 +2216,22 @@ qla2x00_nvram_config(scsi_qla_host_t *vha)
        for (cnt = 0, chksum = 0; cnt < ha->nvram_size; cnt++)
                chksum += *ptr++;
 
-       DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", vha->host_no));
-       DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
+       ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x010f,
+           "Contents of NVRAM.\n");
+       ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0110,
+           (uint8_t *)nv, ha->nvram_size);
 
        /* Bad NVRAM data, set defaults parameters. */
        if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' ||
            nv->id[2] != 'P' || nv->id[3] != ' ' || nv->nvram_version < 1) {
                /* Reset NVRAM data. */
-               qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
-                   "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
-                   nv->nvram_version);
-               qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
-                   "invalid -- WWPN) defaults.\n");
+               ql_log(ql_log_warn, vha, 0x0064,
+                   "Inconisistent NVRAM "
+                   "detected: checksum=0x%x id=%c version=0x%x.\n",
+                   chksum, nv->id[0], nv->nvram_version);
+               ql_log(ql_log_warn, vha, 0x0065,
+                   "Falling back to "
+                   "functioning (yet invalid -- WWPN) defaults.\n");
 
                /*
                 * Set default initialization control block.
@@ -2382,8 +2375,13 @@ qla2x00_nvram_config(scsi_qla_host_t *vha)
        /*
         * Set host adapter parameters.
         */
+
+       /*
+        * BIT_7 in the host-parameters section allows for modification to
+        * internal driver logging.
+        */
        if (nv->host_p[0] & BIT_7)
-               ql2xextended_error_logging = 1;
+               ql2xextended_error_logging = 0x7fffffff;
        ha->flags.disable_risc_code_load = ((nv->host_p[0] & BIT_4) ? 1 : 0);
        /* Always load RISC code on non ISP2[12]00 chips. */
        if (!IS_QLA2100(ha) && !IS_QLA2200(ha))
@@ -2488,10 +2486,7 @@ qla2x00_nvram_config(scsi_qla_host_t *vha)
                if (ha->zio_mode != QLA_ZIO_DISABLED) {
                        ha->zio_mode = QLA_ZIO_MODE_6;
 
-                       DEBUG2(printk("scsi(%ld): ZIO mode %d enabled; timer "
-                           "delay (%d us).\n", vha->host_no, ha->zio_mode,
-                           ha->zio_timer * 100));
-                       qla_printk(KERN_INFO, ha,
+                       ql_log(ql_log_info, vha, 0x0068,
                            "ZIO mode %d enabled; timer delay (%d us).\n",
                            ha->zio_mode, ha->zio_timer * 100);
 
@@ -2502,8 +2497,8 @@ qla2x00_nvram_config(scsi_qla_host_t *vha)
        }
 
        if (rval) {
-               DEBUG2_3(printk(KERN_WARNING
-                   "scsi(%ld): NVRAM configuration failed!\n", vha->host_no));
+               ql_log(ql_log_warn, vha, 0x0069,
+                   "NVRAM configuration failed.\n");
        }
        return (rval);
 }
@@ -2574,15 +2569,15 @@ qla2x00_configure_loop(scsi_qla_host_t *vha)
        if (test_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags)) {
                rval = qla2x00_configure_hba(vha);
                if (rval != QLA_SUCCESS) {
-                       DEBUG(printk("scsi(%ld): Unable to configure HBA.\n",
-                           vha->host_no));
+                       ql_dbg(ql_dbg_disc, vha, 0x2013,
+                           "Unable to configure HBA.\n");
                        return (rval);
                }
        }
 
        save_flags = flags = vha->dpc_flags;
-       DEBUG(printk("scsi(%ld): Configure loop -- dpc flags =0x%lx\n",
-           vha->host_no, flags));
+       ql_dbg(ql_dbg_disc, vha, 0x2014,
+           "Configure loop -- dpc flags = 0x%lx.\n", flags);
 
        /*
         * If we have both an RSCN and PORT UPDATE pending then handle them
@@ -2619,15 +2614,21 @@ qla2x00_configure_loop(scsi_qla_host_t *vha)
        }
 
        if (test_bit(LOCAL_LOOP_UPDATE, &flags)) {
-               if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
+               if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
+                       ql_dbg(ql_dbg_disc, vha, 0x2015,
+                           "Loop resync needed, failing.\n");
                        rval = QLA_FUNCTION_FAILED;
+               }
                else
                        rval = qla2x00_configure_local_loop(vha);
        }
 
        if (rval == QLA_SUCCESS && test_bit(RSCN_UPDATE, &flags)) {
-               if (LOOP_TRANSITION(vha))
+               if (LOOP_TRANSITION(vha)) {
+                       ql_dbg(ql_dbg_disc, vha, 0x201e,
+                           "Needs RSCN update and loop transition.\n");
                        rval = QLA_FUNCTION_FAILED;
+               }
                else
                        rval = qla2x00_configure_fabric(vha);
        }
@@ -2638,16 +2639,17 @@ qla2x00_configure_loop(scsi_qla_host_t *vha)
                        rval = QLA_FUNCTION_FAILED;
                } else {
                        atomic_set(&vha->loop_state, LOOP_READY);
-
-                       DEBUG(printk("scsi(%ld): LOOP READY\n", vha->host_no));
+                       ql_dbg(ql_dbg_disc, vha, 0x2069,
+                           "LOOP READY.\n");
                }
        }
 
        if (rval) {
-               DEBUG2_3(printk("%s(%ld): *** FAILED ***\n",
-                   __func__, vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x206a,
+                   "%s *** FAILED ***.\n", __func__);
        } else {
-               DEBUG3(printk("%s: exiting normally\n", __func__));
+               ql_dbg(ql_dbg_disc, vha, 0x206b,
+                   "%s: exiting normally.\n", __func__);
        }
 
        /* Restore state if a resync event occurred during processing */
@@ -2695,8 +2697,10 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)
        new_fcport = NULL;
        entries = MAX_FIBRE_DEVICES;
 
-       DEBUG3(printk("scsi(%ld): Getting FCAL position map\n", vha->host_no));
-       DEBUG3(qla2x00_get_fcal_position_map(vha, NULL));
+       ql_dbg(ql_dbg_disc, vha, 0x2016,
+           "Getting FCAL position map.\n");
+       if (ql2xextended_error_logging & ql_dbg_disc)
+               qla2x00_get_fcal_position_map(vha, NULL);
 
        /* Get list of logged in devices. */
        memset(ha->gid_list, 0, GID_LIST_SIZE);
@@ -2705,14 +2709,17 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)
        if (rval != QLA_SUCCESS)
                goto cleanup_allocation;
 
-       DEBUG3(printk("scsi(%ld): Entries in ID list (%d)\n",
-           vha->host_no, entries));
-       DEBUG3(qla2x00_dump_buffer((uint8_t *)ha->gid_list,
-           entries * sizeof(struct gid_list_info)));
+       ql_dbg(ql_dbg_disc, vha, 0x2017,
+           "Entries in ID list (%d).\n", entries);
+       ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2075,
+           (uint8_t *)ha->gid_list,
+           entries * sizeof(struct gid_list_info));
 
        /* Allocate temporary fcport for any new fcports discovered. */
        new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
        if (new_fcport == NULL) {
+               ql_log(ql_log_warn, vha, 0x2018,
+                   "Memory allocation failed for fcport.\n");
                rval = QLA_MEMORY_ALLOC_FAILED;
                goto cleanup_allocation;
        }
@@ -2726,9 +2733,9 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)
                    fcport->port_type != FCT_BROADCAST &&
                    (fcport->flags & FCF_FABRIC_DEVICE) == 0) {
 
-                       DEBUG(printk("scsi(%ld): Marking port lost, "
-                           "loop_id=0x%04x\n",
-                           vha->host_no, fcport->loop_id));
+                       ql_dbg(ql_dbg_disc, vha, 0x2019,
+                           "Marking port lost loop_id=0x%04x.\n",
+                           fcport->loop_id);
 
                        qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST);
                }
@@ -2769,12 +2776,12 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)
                new_fcport->vp_idx = vha->vp_idx;
                rval2 = qla2x00_get_port_database(vha, new_fcport, 0);
                if (rval2 != QLA_SUCCESS) {
-                       DEBUG2(printk("scsi(%ld): Failed to retrieve fcport "
-                           "information -- get_port_database=%x, "
-                           "loop_id=0x%04x\n",
-                           vha->host_no, rval2, new_fcport->loop_id));
-                       DEBUG2(printk("scsi(%ld): Scheduling resync...\n",
-                           vha->host_no));
+                       ql_dbg(ql_dbg_disc, vha, 0x201a,
+                           "Failed to retrieve fcport information "
+                           "-- get_port_database=%x, loop_id=0x%04x.\n",
+                           rval2, new_fcport->loop_id);
+                       ql_dbg(ql_dbg_disc, vha, 0x201b,
+                           "Scheduling resync.\n");
                        set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
                        continue;
                }
@@ -2810,6 +2817,8 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)
                        fcport = new_fcport;
                        new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
                        if (new_fcport == NULL) {
+                               ql_log(ql_log_warn, vha, 0x201c,
+                                   "Failed to allocate memory for fcport.\n");
                                rval = QLA_MEMORY_ALLOC_FAILED;
                                goto cleanup_allocation;
                        }
@@ -2828,8 +2837,8 @@ cleanup_allocation:
        kfree(new_fcport);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2(printk("scsi(%ld): Configure local loop error exit: "
-                   "rval=%x\n", vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x201d,
+                   "Configure local loop error exit: rval=%x.\n", rval);
        }
 
        return (rval);
@@ -2858,27 +2867,27 @@ qla2x00_iidma_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
        rval = qla2x00_set_idma_speed(vha, fcport->loop_id, fcport->fp_speed,
            mb);
        if (rval != QLA_SUCCESS) {
-               DEBUG2(printk("scsi(%ld): Unable to adjust iIDMA "
-                   "%02x%02x%02x%02x%02x%02x%02x%02x -- %04x %x %04x %04x.\n",
-                   vha->host_no, fcport->port_name[0], fcport->port_name[1],
+               ql_dbg(ql_dbg_disc, vha, 0x2004,
+                   "Unable to adjust iIDMA "
+                   "%02x%02x%02x%02x%02x%02x%02x%02x -- %04x %x %04x "
+                   "%04x.\n", fcport->port_name[0], fcport->port_name[1],
                    fcport->port_name[2], fcport->port_name[3],
                    fcport->port_name[4], fcport->port_name[5],
                    fcport->port_name[6], fcport->port_name[7], rval,
-                   fcport->fp_speed, mb[0], mb[1]));
+                   fcport->fp_speed, mb[0], mb[1]);
        } else {
                link_speed = link_speeds[LS_UNKNOWN];
                if (fcport->fp_speed < 5)
                        link_speed = link_speeds[fcport->fp_speed];
                else if (fcport->fp_speed == 0x13)
                        link_speed = link_speeds[5];
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                   "iIDMA adjusted to %s GB/s on "
-                   "%02x%02x%02x%02x%02x%02x%02x%02x.\n",
-                   link_speed, fcport->port_name[0],
-                   fcport->port_name[1], fcport->port_name[2],
-                   fcport->port_name[3], fcport->port_name[4],
-                   fcport->port_name[5], fcport->port_name[6],
-                   fcport->port_name[7]));
+               ql_dbg(ql_dbg_disc, vha, 0x2005,
+                   "iIDMA adjusted to %s GB/s "
+                   "on %02x%02x%02x%02x%02x%02x%02x%02x.\n", link_speed,
+                   fcport->port_name[0], fcport->port_name[1],
+                   fcport->port_name[2], fcport->port_name[3],
+                   fcport->port_name[4], fcport->port_name[5],
+                   fcport->port_name[6], fcport->port_name[7]);
        }
 }
 
@@ -2887,7 +2896,6 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport)
 {
        struct fc_rport_identifiers rport_ids;
        struct fc_rport *rport;
-       struct qla_hw_data *ha = vha->hw;
        unsigned long flags;
 
        qla2x00_rport_del(fcport);
@@ -2899,8 +2907,8 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport)
        rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
        fcport->rport = rport = fc_remote_port_add(vha->host, 0, &rport_ids);
        if (!rport) {
-               qla_printk(KERN_WARNING, ha,
-                   "Unable to allocate fc remote port!\n");
+               ql_log(ql_log_warn, vha, 0x2006,
+                   "Unable to allocate fc remote port.\n");
                return;
        }
        spin_lock_irqsave(fcport->vha->host->host_lock, flags);
@@ -2975,8 +2983,8 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
                loop_id = SNS_FL_PORT;
        rval = qla2x00_get_port_name(vha, loop_id, vha->fabric_node_name, 1);
        if (rval != QLA_SUCCESS) {
-               DEBUG2(printk("scsi(%ld): MBC_GET_PORT_NAME Failed, No FL "
-                   "Port\n", vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x201f,
+                   "MBX_GET_PORT_NAME failed, No FL Port.\n");
 
                vha->device_flags &= ~SWITCH_FOUND;
                return (QLA_SUCCESS);
@@ -3003,32 +3011,32 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
                ha->isp_ops->fabric_login(vha, loop_id, 0xff, 0xff,
                    0xfc, mb, BIT_1 | BIT_0);
                if (mb[0] != MBS_COMMAND_COMPLETE) {
-                       DEBUG2(qla_printk(KERN_INFO, ha,
-                           "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x "
-                           "mb[2]=%x mb[6]=%x mb[7]=%x\n", loop_id,
-                           mb[0], mb[1], mb[2], mb[6], mb[7]));
+                       ql_dbg(ql_dbg_disc, vha, 0x2042,
+                           "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x mb[2]=%x "
+                           "mb[6]=%x mb[7]=%x.\n", loop_id, mb[0], mb[1],
+                           mb[2], mb[6], mb[7]);
                        return (QLA_SUCCESS);
                }
 
                if (test_and_clear_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags)) {
                        if (qla2x00_rft_id(vha)) {
                                /* EMPTY */
-                               DEBUG2(printk("scsi(%ld): Register FC-4 "
-                                   "TYPE failed.\n", vha->host_no));
+                               ql_dbg(ql_dbg_disc, vha, 0x2045,
+                                   "Register FC-4 TYPE failed.\n");
                        }
                        if (qla2x00_rff_id(vha)) {
                                /* EMPTY */
-                               DEBUG2(printk("scsi(%ld): Register FC-4 "
-                                   "Features failed.\n", vha->host_no));
+                               ql_dbg(ql_dbg_disc, vha, 0x2049,
+                                   "Register FC-4 Features failed.\n");
                        }
                        if (qla2x00_rnn_id(vha)) {
                                /* EMPTY */
-                               DEBUG2(printk("scsi(%ld): Register Node Name "
-                                   "failed.\n", vha->host_no));
+                               ql_dbg(ql_dbg_disc, vha, 0x204f,
+                                   "Register Node Name failed.\n");
                        } else if (qla2x00_rsnn_nn(vha)) {
                                /* EMPTY */
-                               DEBUG2(printk("scsi(%ld): Register Symbolic "
-                                   "Node Name failed.\n", vha->host_no));
+                               ql_dbg(ql_dbg_disc, vha, 0x2053,
+                                   "Register Symobilic Node Name failed.\n");
                        }
                }
 
@@ -3132,8 +3140,8 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
        }
 
        if (rval) {
-               DEBUG2(printk("scsi(%ld): Configure fabric error exit: "
-                   "rval=%d\n", vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x2068,
+                   "Configure fabric error exit rval=%d.\n", rval);
        }
 
        return (rval);
@@ -3175,8 +3183,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
        swl = kcalloc(MAX_FIBRE_DEVICES, sizeof(sw_info_t), GFP_KERNEL);
        if (!swl) {
                /*EMPTY*/
-               DEBUG2(printk("scsi(%ld): GID_PT allocations failed, fallback "
-                   "on GA_NXT\n", vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x2054,
+                   "GID_PT allocations failed, fallback on GA_NXT.\n");
        } else {
                if (qla2x00_gid_pt(vha, swl) != QLA_SUCCESS) {
                        kfree(swl);
@@ -3201,6 +3209,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
        /* Allocate temporary fcport for any new fcports discovered. */
        new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
        if (new_fcport == NULL) {
+               ql_log(ql_log_warn, vha, 0x205e,
+                   "Failed to allocate memory for fcport.\n");
                kfree(swl);
                return (QLA_MEMORY_ALLOC_FAILED);
        }
@@ -3247,9 +3257,9 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
                        /* Send GA_NXT to the switch */
                        rval = qla2x00_ga_nxt(vha, new_fcport);
                        if (rval != QLA_SUCCESS) {
-                               qla_printk(KERN_WARNING, ha,
-                                   "SNS scan failed -- assuming zero-entry "
-                                   "result...\n");
+                               ql_log(ql_log_warn, vha, 0x2064,
+                                   "SNS scan failed -- assuming "
+                                   "zero-entry result.\n");
                                list_for_each_entry_safe(fcport, fcptemp,
                                    new_fcports, list) {
                                        list_del(&fcport->list);
@@ -3265,9 +3275,11 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
                        wrap.b24 = new_fcport->d_id.b24;
                        first_dev = 0;
                } else if (new_fcport->d_id.b24 == wrap.b24) {
-                       DEBUG2(printk("scsi(%ld): device wrap (%02x%02x%02x)\n",
-                           vha->host_no, new_fcport->d_id.b.domain,
-                           new_fcport->d_id.b.area, new_fcport->d_id.b.al_pa));
+                       ql_dbg(ql_dbg_disc, vha, 0x2065,
+                           "Device wrap (%02x%02x%02x).\n",
+                           new_fcport->d_id.b.domain,
+                           new_fcport->d_id.b.area,
+                           new_fcport->d_id.b.al_pa);
                        break;
                }
 
@@ -3372,6 +3384,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
                nxt_d_id.b24 = new_fcport->d_id.b24;
                new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
                if (new_fcport == NULL) {
+                       ql_log(ql_log_warn, vha, 0x2066,
+                           "Memory allocation failed for fcport.\n");
                        kfree(swl);
                        return (QLA_MEMORY_ALLOC_FAILED);
                }
@@ -3501,10 +3515,10 @@ qla2x00_device_resync(scsi_qla_host_t *vha)
                d_id.b.area = MSB(LSW(rscn_entry));
                d_id.b.al_pa = LSB(LSW(rscn_entry));
 
-               DEBUG(printk("scsi(%ld): RSCN queue entry[%d] = "
-                   "[%02x/%02x%02x%02x].\n",
-                   vha->host_no, vha->rscn_out_ptr, format, d_id.b.domain,
-                   d_id.b.area, d_id.b.al_pa));
+               ql_dbg(ql_dbg_disc, vha, 0x2020,
+                   "RSCN queue entry[%d] = [%02x/%02x%02x%02x].\n",
+                   vha->rscn_out_ptr, format, d_id.b.domain, d_id.b.area,
+                   d_id.b.al_pa);
 
                vha->rscn_out_ptr++;
                if (vha->rscn_out_ptr == MAX_RSCN_COUNT)
@@ -3520,17 +3534,17 @@ qla2x00_device_resync(scsi_qla_host_t *vha)
                        if (rscn_entry != vha->rscn_queue[rscn_out_iter])
                                break;
 
-                       DEBUG(printk("scsi(%ld): Skipping duplicate RSCN queue "
-                           "entry found at [%d].\n", vha->host_no,
-                           rscn_out_iter));
+                       ql_dbg(ql_dbg_disc, vha, 0x2021,
+                           "Skipping duplicate RSCN queue entry found at "
+                           "[%d].\n", rscn_out_iter);
 
                        vha->rscn_out_ptr = rscn_out_iter;
                }
 
                /* Queue overflow, set switch default case. */
                if (vha->flags.rscn_queue_overflow) {
-                       DEBUG(printk("scsi(%ld): device_resync: rscn "
-                           "overflow.\n", vha->host_no));
+                       ql_dbg(ql_dbg_disc, vha, 0x2022,
+                           "device_resync: rscn overflow.\n");
 
                        format = 3;
                        vha->flags.rscn_queue_overflow = 0;
@@ -3659,10 +3673,11 @@ qla2x00_fabric_login(scsi_qla_host_t *vha, fc_port_t *fcport,
        tmp_loopid = 0;
 
        for (;;) {
-               DEBUG(printk("scsi(%ld): Trying Fabric Login w/loop id 0x%04x "
-                   "for port %02x%02x%02x.\n",
-                   vha->host_no, fcport->loop_id, fcport->d_id.b.domain,
-                   fcport->d_id.b.area, fcport->d_id.b.al_pa));
+               ql_dbg(ql_dbg_disc, vha, 0x2000,
+                   "Trying Fabric Login w/loop id 0x%04x for port "
+                   "%02x%02x%02x.\n",
+                   fcport->loop_id, fcport->d_id.b.domain,
+                   fcport->d_id.b.area, fcport->d_id.b.al_pa);
 
                /* Login fcport on switch. */
                ha->isp_ops->fabric_login(vha, fcport->loop_id,
@@ -3680,10 +3695,11 @@ qla2x00_fabric_login(scsi_qla_host_t *vha, fc_port_t *fcport,
                        tmp_loopid = fcport->loop_id;
                        fcport->loop_id = mb[1];
 
-                       DEBUG(printk("Fabric Login: port in use - next "
-                           "loop id=0x%04x, port Id=%02x%02x%02x.\n",
+                       ql_dbg(ql_dbg_disc, vha, 0x2001,
+                           "Fabric Login: port in use - next loop "
+                           "id=0x%04x, port id= %02x%02x%02x.\n",
                            fcport->loop_id, fcport->d_id.b.domain,
-                           fcport->d_id.b.area, fcport->d_id.b.al_pa));
+                           fcport->d_id.b.area, fcport->d_id.b.al_pa);
 
                } else if (mb[0] == MBS_COMMAND_COMPLETE) {
                        /*
@@ -3744,11 +3760,11 @@ qla2x00_fabric_login(scsi_qla_host_t *vha, fc_port_t *fcport,
                        /*
                         * unrecoverable / not handled error
                         */
-                       DEBUG2(printk("%s(%ld): failed=%x port_id=%02x%02x%02x "
-                           "loop_id=%x jiffies=%lx.\n",
-                           __func__, vha->host_no, mb[0],
-                           fcport->d_id.b.domain, fcport->d_id.b.area,
-                           fcport->d_id.b.al_pa, fcport->loop_id, jiffies));
+                       ql_dbg(ql_dbg_disc, vha, 0x2002,
+                           "Failed=%x port_id=%02x%02x%02x loop_id=%x "
+                           "jiffies=%lx.\n", mb[0], fcport->d_id.b.domain,
+                           fcport->d_id.b.area, fcport->d_id.b.al_pa,
+                           fcport->loop_id, jiffies);
 
                        *next_loopid = fcport->loop_id;
                        ha->isp_ops->fabric_logout(vha, fcport->loop_id,
@@ -3852,7 +3868,8 @@ qla2x00_loop_resync(scsi_qla_host_t *vha)
                return (QLA_FUNCTION_FAILED);
 
        if (rval)
-               DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__));
+               ql_dbg(ql_dbg_disc, vha, 0x206c,
+                   "%s *** FAILED ***.\n", __func__);
 
        return (rval);
 }
@@ -3929,8 +3946,8 @@ qla82xx_quiescent_state_cleanup(scsi_qla_host_t *vha)
        struct qla_hw_data *ha = vha->hw;
        struct scsi_qla_host *vp;
 
-       qla_printk(KERN_INFO, ha,
-                       "Performing ISP error recovery - ha= %p.\n", ha);
+       ql_dbg(ql_dbg_p3p, vha, 0xb002,
+           "Performing ISP error recovery - ha=%p.\n", ha);
 
        atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
        if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
@@ -3964,8 +3981,8 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
        clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
        ha->qla_stats.total_isp_aborts++;
 
-       qla_printk(KERN_INFO, ha,
-           "Performing ISP error recovery - ha= %p.\n", ha);
+       ql_log(ql_log_info, vha, 0x00af,
+           "Performing ISP error recovery - ha=%p.\n", ha);
 
        /* For ISP82XX, reset_chip is just disabling interrupts.
         * Driver waits for the completion of the commands.
@@ -4016,6 +4033,8 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
                /* Make sure for ISP 82XX IO DMA is complete */
                if (IS_QLA82XX(ha)) {
                        qla82xx_chip_reset_cleanup(vha);
+                       ql_log(ql_log_info, vha, 0x00b4,
+                           "Done chip reset cleanup.\n");
 
                        /* Done waiting for pending commands.
                         * Reset the online flag.
@@ -4097,7 +4116,7 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
                                    ha->fce_dma, ha->fce_bufs, ha->fce_mb,
                                    &ha->fce_bufs);
                                if (rval) {
-                                       qla_printk(KERN_WARNING, ha,
+                                       ql_log(ql_log_warn, vha, 0x8033,
                                            "Unable to reinitialize FCE "
                                            "(%d).\n", rval);
                                        ha->flags.fce_enabled = 0;
@@ -4109,7 +4128,7 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
                                rval = qla2x00_enable_eft_trace(vha,
                                    ha->eft_dma, EFT_NUM_BUFFERS);
                                if (rval) {
-                                       qla_printk(KERN_WARNING, ha,
+                                       ql_log(ql_log_warn, vha, 0x8034,
                                            "Unable to reinitialize EFT "
                                            "(%d).\n", rval);
                                }
@@ -4118,9 +4137,9 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
                        vha->flags.online = 1;
                        if (test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
                                if (ha->isp_abort_cnt == 0) {
-                                       qla_printk(KERN_WARNING, ha,
-                                           "ISP error recovery failed - "
-                                           "board disabled\n");
+                                       ql_log(ql_log_fatal, vha, 0x8035,
+                                           "ISP error recover failed - "
+                                           "board disabled.\n");
                                        /*
                                         * The next call disables the board
                                         * completely.
@@ -4132,16 +4151,16 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
                                        status = 0;
                                } else { /* schedule another ISP abort */
                                        ha->isp_abort_cnt--;
-                                       DEBUG(printk("qla%ld: ISP abort - "
-                                           "retry remaining %d\n",
-                                           vha->host_no, ha->isp_abort_cnt));
+                                       ql_dbg(ql_dbg_taskm, vha, 0x8020,
+                                           "ISP abort - retry remaining %d.\n",
+                                           ha->isp_abort_cnt);
                                        status = 1;
                                }
                        } else {
                                ha->isp_abort_cnt = MAX_RETRIES_OF_ISP_ABORT;
-                               DEBUG(printk("qla2x00(%ld): ISP error recovery "
-                                   "- retrying (%d) more times\n",
-                                   vha->host_no, ha->isp_abort_cnt));
+                               ql_dbg(ql_dbg_taskm, vha, 0x8021,
+                                   "ISP error recovery - retrying (%d) "
+                                   "more times.\n", ha->isp_abort_cnt);
                                set_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
                                status = 1;
                        }
@@ -4150,9 +4169,7 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
        }
 
        if (!status) {
-               DEBUG(printk(KERN_INFO
-                               "qla2x00_abort_isp(%ld): succeeded.\n",
-                               vha->host_no));
+               ql_dbg(ql_dbg_taskm, vha, 0x8022, "%s succeeded.\n", __func__);
 
                spin_lock_irqsave(&ha->vport_slock, flags);
                list_for_each_entry(vp, &ha->vp_list, list) {
@@ -4169,8 +4186,7 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
                spin_unlock_irqrestore(&ha->vport_slock, flags);
 
        } else {
-               qla_printk(KERN_INFO, ha,
-                       "qla2x00_abort_isp: **** FAILED ****\n");
+               ql_log(ql_log_warn, vha, 0x8023, "%s **** FAILED ****.\n");
        }
 
        return(status);
@@ -4211,8 +4227,8 @@ qla2x00_restart_isp(scsi_qla_host_t *vha)
 
                status = qla2x00_fw_ready(vha);
                if (!status) {
-                       DEBUG(printk("%s(): Start configure loop, "
-                           "status = %d\n", __func__, status));
+                       ql_dbg(ql_dbg_taskm, vha, 0x8031,
+                           "Start configure loop status = %d.\n", status);
 
                        /* Issue a marker after FW becomes ready. */
                        qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL);
@@ -4234,9 +4250,8 @@ qla2x00_restart_isp(scsi_qla_host_t *vha)
                if ((vha->device_flags & DFLG_NO_CABLE))
                        status = 0;
 
-               DEBUG(printk("%s(): Configure loop done, status = 0x%x\n",
-                               __func__,
-                               status));
+               ql_dbg(ql_dbg_taskm, vha, 0x8032,
+                   "Configure loop done, status = 0x%x.\n", status);
        }
        return (status);
 }
@@ -4256,13 +4271,13 @@ qla25xx_init_queues(struct qla_hw_data *ha)
                        rsp->options &= ~BIT_0;
                        ret = qla25xx_init_rsp_que(base_vha, rsp);
                        if (ret != QLA_SUCCESS)
-                               DEBUG2_17(printk(KERN_WARNING
-                                       "%s Rsp que:%d init failed\n", __func__,
-                                               rsp->id));
+                               ql_dbg(ql_dbg_init, base_vha, 0x00ff,
+                                   "%s Rsp que: %d init failed.\n",
+                                   __func__, rsp->id);
                        else
-                               DEBUG2_17(printk(KERN_INFO
-                                       "%s Rsp que:%d inited\n", __func__,
-                                               rsp->id));
+                               ql_dbg(ql_dbg_init, base_vha, 0x0100,
+                                   "%s Rsp que: %d inited.\n",
+                                   __func__, rsp->id);
                }
        }
        for (i = 1; i < ha->max_req_queues; i++) {
@@ -4272,13 +4287,13 @@ qla25xx_init_queues(struct qla_hw_data *ha)
                        req->options &= ~BIT_0;
                        ret = qla25xx_init_req_que(base_vha, req);
                        if (ret != QLA_SUCCESS)
-                               DEBUG2_17(printk(KERN_WARNING
-                                       "%s Req que:%d init failed\n", __func__,
-                                               req->id));
+                               ql_dbg(ql_dbg_init, base_vha, 0x0101,
+                                   "%s Req que: %d init failed.\n",
+                                   __func__, req->id);
                        else
-                               DEBUG2_17(printk(KERN_WARNING
-                                       "%s Req que:%d inited\n", __func__,
-                                               req->id));
+                               ql_dbg(ql_dbg_init, base_vha, 0x0102,
+                                   "%s Req que: %d inited.\n",
+                                   __func__, req->id);
                }
        }
        return ret;
@@ -4397,19 +4412,22 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
        for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
                chksum += le32_to_cpu(*dptr++);
 
-       DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", vha->host_no));
-       DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
+       ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x006a,
+           "Contents of NVRAM\n");
+       ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x010d,
+           (uint8_t *)nv, ha->nvram_size);
 
        /* Bad NVRAM data, set defaults parameters. */
        if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P'
            || nv->id[3] != ' ' ||
            nv->nvram_version < __constant_cpu_to_le16(ICB_VERSION)) {
                /* Reset NVRAM data. */
-               qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
-                   "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
-                   le16_to_cpu(nv->nvram_version));
-               qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
-                   "invalid -- WWPN) defaults.\n");
+               ql_log(ql_log_warn, vha, 0x006b,
+                   "Inconisistent NVRAM detected: checksum=0x%x id=%c "
+                   "version=0x%x.\n", chksum, nv->id[0], nv->nvram_version);
+               ql_log(ql_log_warn, vha, 0x006c,
+                   "Falling back to functioning (yet invalid -- WWPN) "
+                   "defaults.\n");
 
                /*
                 * Set default initialization control block.
@@ -4587,10 +4605,7 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
        if (ha->zio_mode != QLA_ZIO_DISABLED) {
                ha->zio_mode = QLA_ZIO_MODE_6;
 
-               DEBUG2(printk("scsi(%ld): ZIO mode %d enabled; timer delay "
-                   "(%d us).\n", vha->host_no, ha->zio_mode,
-                   ha->zio_timer * 100));
-               qla_printk(KERN_INFO, ha,
+               ql_log(ql_log_info, vha, 0x006f,
                    "ZIO mode %d enabled; timer delay (%d us).\n",
                    ha->zio_mode, ha->zio_timer * 100);
 
@@ -4601,8 +4616,8 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
        }
 
        if (rval) {
-               DEBUG2_3(printk(KERN_WARNING
-                   "scsi(%ld): NVRAM configuration failed!\n", vha->host_no));
+               ql_log(ql_log_warn, vha, 0x0070,
+                   "NVRAM configuration failed.\n");
        }
        return (rval);
 }
@@ -4620,8 +4635,8 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
        struct qla_hw_data *ha = vha->hw;
        struct req_que *req = ha->req_q_map[0];
 
-       qla_printk(KERN_INFO, ha,
-           "FW: Loading from flash (%x)...\n", faddr);
+       ql_dbg(ql_dbg_init, vha, 0x008b,
+           "Loading firmware from flash (%x).\n", faddr);
 
        rval = QLA_SUCCESS;
 
@@ -4637,11 +4652,12 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
            dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) ||
            (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
                dcode[3] == 0)) {
-               qla_printk(KERN_WARNING, ha,
-                   "Unable to verify integrity of flash firmware image!\n");
-               qla_printk(KERN_WARNING, ha,
-                   "Firmware data: %08x %08x %08x %08x!\n", dcode[0],
-                   dcode[1], dcode[2], dcode[3]);
+               ql_log(ql_log_fatal, vha, 0x008c,
+                   "Unable to verify the integrity of flash firmware "
+                   "image.\n");
+               ql_log(ql_log_fatal, vha, 0x008d,
+                   "Firmware data: %08x %08x %08x %08x.\n",
+                   dcode[0], dcode[1], dcode[2], dcode[3]);
 
                return QLA_FUNCTION_FAILED;
        }
@@ -4660,9 +4676,10 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
                        if (dlen > risc_size)
                                dlen = risc_size;
 
-                       DEBUG7(printk("scsi(%ld): Loading risc segment@ risc "
-                           "addr %x, number of dwords 0x%x, offset 0x%x.\n",
-                           vha->host_no, risc_addr, dlen, faddr));
+                       ql_dbg(ql_dbg_init, vha, 0x008e,
+                           "Loading risc segment@ risc addr %x "
+                           "number of dwords 0x%x offset 0x%x.\n",
+                           risc_addr, dlen, faddr);
 
                        qla24xx_read_flash_data(vha, dcode, faddr, dlen);
                        for (i = 0; i < dlen; i++)
@@ -4671,12 +4688,9 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
                        rval = qla2x00_load_ram(vha, req->dma, risc_addr,
                            dlen);
                        if (rval) {
-                               DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
-                                   "segment %d of firmware\n", vha->host_no,
-                                   fragment));
-                               qla_printk(KERN_WARNING, ha,
-                                   "[ERROR] Failed to load segment %d of "
-                                   "firmware\n", fragment);
+                               ql_log(ql_log_fatal, vha, 0x008f,
+                                   "Failed to load segment %d of firmware.\n",
+                                   fragment);
                                break;
                        }
 
@@ -4709,9 +4723,10 @@ qla2x00_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
        /* Load firmware blob. */
        blob = qla2x00_request_firmware(vha);
        if (!blob) {
-               qla_printk(KERN_ERR, ha, "Firmware image unavailable.\n");
-               qla_printk(KERN_ERR, ha, "Firmware images can be retrieved "
-                   "from: " QLA_FW_URL ".\n");
+               ql_log(ql_log_info, vha, 0x0083,
+                   "Fimware image unavailable.\n");
+               ql_log(ql_log_info, vha, 0x0084,
+                   "Firmware images can be retrieved from: "QLA_FW_URL ".\n");
                return QLA_FUNCTION_FAILED;
        }
 
@@ -4724,8 +4739,8 @@ qla2x00_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
 
        /* Validate firmware image by checking version. */
        if (blob->fw->size < 8 * sizeof(uint16_t)) {
-               qla_printk(KERN_WARNING, ha,
-                   "Unable to verify integrity of firmware image (%Zd)!\n",
+               ql_log(ql_log_fatal, vha, 0x0085,
+                   "Unable to verify integrity of firmware image (%Zd).\n",
                    blob->fw->size);
                goto fail_fw_integrity;
        }
@@ -4734,11 +4749,11 @@ qla2x00_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
        if ((wcode[0] == 0xffff && wcode[1] == 0xffff && wcode[2] == 0xffff &&
            wcode[3] == 0xffff) || (wcode[0] == 0 && wcode[1] == 0 &&
                wcode[2] == 0 && wcode[3] == 0)) {
-               qla_printk(KERN_WARNING, ha,
-                   "Unable to verify integrity of firmware image!\n");
-               qla_printk(KERN_WARNING, ha,
-                   "Firmware data: %04x %04x %04x %04x!\n", wcode[0],
-                   wcode[1], wcode[2], wcode[3]);
+               ql_log(ql_log_fatal, vha, 0x0086,
+                   "Unable to verify integrity of firmware image.\n");
+               ql_log(ql_log_fatal, vha, 0x0087,
+                   "Firmware data: %04x %04x %04x %04x.\n",
+                   wcode[0], wcode[1], wcode[2], wcode[3]);
                goto fail_fw_integrity;
        }
 
@@ -4751,9 +4766,9 @@ qla2x00_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
                /* Validate firmware image size. */
                fwclen += risc_size * sizeof(uint16_t);
                if (blob->fw->size < fwclen) {
-                       qla_printk(KERN_WARNING, ha,
+                       ql_log(ql_log_fatal, vha, 0x0088,
                            "Unable to verify integrity of firmware image "
-                           "(%Zd)!\n", blob->fw->size);
+                           "(%Zd).\n", blob->fw->size);
                        goto fail_fw_integrity;
                }
 
@@ -4762,10 +4777,9 @@ qla2x00_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
                        wlen = (uint16_t)(ha->fw_transfer_size >> 1);
                        if (wlen > risc_size)
                                wlen = risc_size;
-
-                       DEBUG7(printk("scsi(%ld): Loading risc segment@ risc "
-                           "addr %x, number of words 0x%x.\n", vha->host_no,
-                           risc_addr, wlen));
+                       ql_dbg(ql_dbg_init, vha, 0x0089,
+                           "Loading risc segment@ risc addr %x number of "
+                           "words 0x%x.\n", risc_addr, wlen);
 
                        for (i = 0; i < wlen; i++)
                                wcode[i] = swab16(fwcode[i]);
@@ -4773,12 +4787,9 @@ qla2x00_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
                        rval = qla2x00_load_ram(vha, req->dma, risc_addr,
                            wlen);
                        if (rval) {
-                               DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
-                                   "segment %d of firmware\n", vha->host_no,
-                                   fragment));
-                               qla_printk(KERN_WARNING, ha,
-                                   "[ERROR] Failed to load segment %d of "
-                                   "firmware\n", fragment);
+                               ql_log(ql_log_fatal, vha, 0x008a,
+                                   "Failed to load segment %d of firmware.\n",
+                                   fragment);
                                break;
                        }
 
@@ -4814,15 +4825,17 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
        /* Load firmware blob. */
        blob = qla2x00_request_firmware(vha);
        if (!blob) {
-               qla_printk(KERN_ERR, ha, "Firmware image unavailable.\n");
-               qla_printk(KERN_ERR, ha, "Firmware images can be retrieved "
-                   "from: " QLA_FW_URL ".\n");
+               ql_log(ql_log_warn, vha, 0x0090,
+                   "Fimware image unavailable.\n");
+               ql_log(ql_log_warn, vha, 0x0091,
+                   "Firmware images can be retrieved from: "
+                   QLA_FW_URL ".\n");
 
                return QLA_FUNCTION_FAILED;
        }
 
-       qla_printk(KERN_INFO, ha,
-           "FW: Loading via request-firmware...\n");
+       ql_log(ql_log_info, vha, 0x0092,
+           "Loading via request-firmware.\n");
 
        rval = QLA_SUCCESS;
 
@@ -4834,8 +4847,8 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
 
        /* Validate firmware image by checking version. */
        if (blob->fw->size < 8 * sizeof(uint32_t)) {
-               qla_printk(KERN_WARNING, ha,
-                   "Unable to verify integrity of firmware image (%Zd)!\n",
+               ql_log(ql_log_fatal, vha, 0x0093,
+                   "Unable to verify integrity of firmware image (%Zd).\n",
                    blob->fw->size);
                goto fail_fw_integrity;
        }
@@ -4845,11 +4858,12 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
            dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) ||
            (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
                dcode[3] == 0)) {
-               qla_printk(KERN_WARNING, ha,
-                   "Unable to verify integrity of firmware image!\n");
-               qla_printk(KERN_WARNING, ha,
-                   "Firmware data: %08x %08x %08x %08x!\n", dcode[0],
-                   dcode[1], dcode[2], dcode[3]);
+               ql_log(ql_log_fatal, vha, 0x0094,
+                   "Unable to verify integrity of firmware image (%Zd).\n",
+                   blob->fw->size);
+               ql_log(ql_log_fatal, vha, 0x0095,
+                   "Firmware data: %08x %08x %08x %08x.\n",
+                   dcode[0], dcode[1], dcode[2], dcode[3]);
                goto fail_fw_integrity;
        }
 
@@ -4861,9 +4875,9 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
                /* Validate firmware image size. */
                fwclen += risc_size * sizeof(uint32_t);
                if (blob->fw->size < fwclen) {
-                       qla_printk(KERN_WARNING, ha,
+                       ql_log(ql_log_fatal, vha, 0x0096,
                            "Unable to verify integrity of firmware image "
-                           "(%Zd)!\n", blob->fw->size);
+                           "(%Zd).\n", blob->fw->size);
 
                        goto fail_fw_integrity;
                }
@@ -4874,9 +4888,9 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
                        if (dlen > risc_size)
                                dlen = risc_size;
 
-                       DEBUG7(printk("scsi(%ld): Loading risc segment@ risc "
-                           "addr %x, number of dwords 0x%x.\n", vha->host_no,
-                           risc_addr, dlen));
+                       ql_dbg(ql_dbg_init, vha, 0x0097,
+                           "Loading risc segment@ risc addr %x "
+                           "number of dwords 0x%x.\n", risc_addr, dlen);
 
                        for (i = 0; i < dlen; i++)
                                dcode[i] = swab32(fwcode[i]);
@@ -4884,12 +4898,9 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
                        rval = qla2x00_load_ram(vha, req->dma, risc_addr,
                            dlen);
                        if (rval) {
-                               DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
-                                   "segment %d of firmware\n", vha->host_no,
-                                   fragment));
-                               qla_printk(KERN_WARNING, ha,
-                                   "[ERROR] Failed to load segment %d of "
-                                   "firmware\n", fragment);
+                               ql_log(ql_log_fatal, vha, 0x0098,
+                                   "Failed to load segment %d of firmware.\n",
+                                   fragment);
                                break;
                        }
 
@@ -4953,14 +4964,13 @@ try_blob_fw:
        if (rval == QLA_SUCCESS || !ha->flt_region_gold_fw)
                return rval;
 
-       qla_printk(KERN_ERR, ha,
-           "FW: Attempting to fallback to golden firmware...\n");
+       ql_log(ql_log_info, vha, 0x0099,
+           "Attempting to fallback to golden firmware.\n");
        rval = qla24xx_load_risc_flash(vha, srisc_addr, ha->flt_region_gold_fw);
        if (rval != QLA_SUCCESS)
                return rval;
 
-       qla_printk(KERN_ERR, ha,
-           "FW: Please update operational firmware...\n");
+       ql_log(ql_log_info, vha, 0x009a, "Update operational firmware.\n");
        ha->flags.running_gold_fw = 1;
 
        return rval;
@@ -4987,8 +4997,8 @@ qla2x00_try_to_stop_firmware(scsi_qla_host_t *vha)
                        continue;
                if (qla2x00_setup_chip(vha) != QLA_SUCCESS)
                        continue;
-               qla_printk(KERN_INFO, ha,
-                   "Attempting retry of stop-firmware command...\n");
+               ql_log(ql_log_info, vha, 0x8015,
+                   "Attempting retry of stop-firmware command.\n");
                ret = qla2x00_stop_firmware(vha);
        }
 }
@@ -5023,10 +5033,10 @@ qla24xx_configure_vhba(scsi_qla_host_t *vha)
        /* Login to SNS first */
        ha->isp_ops->fabric_login(vha, NPH_SNS, 0xff, 0xff, 0xfc, mb, BIT_1);
        if (mb[0] != MBS_COMMAND_COMPLETE) {
-               DEBUG15(qla_printk(KERN_INFO, ha,
-                   "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x "
-                   "mb[2]=%x mb[6]=%x mb[7]=%x\n", NPH_SNS,
-                   mb[0], mb[1], mb[2], mb[6], mb[7]));
+               ql_dbg(ql_dbg_init, vha, 0x0103,
+                   "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x mb[2]=%x "
+                   "mb[6]=%x mb[7]=%x.\n",
+                   NPH_SNS, mb[0], mb[1], mb[2], mb[6], mb[7]);
                return (QLA_FUNCTION_FAILED);
        }
 
@@ -5146,19 +5156,23 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
        for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
                chksum += le32_to_cpu(*dptr++);
 
-       DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", vha->host_no));
-       DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
+       ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x0111,
+           "Contents of NVRAM:\n");
+       ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0112,
+           (uint8_t *)nv, ha->nvram_size);
 
        /* Bad NVRAM data, set defaults parameters. */
        if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P'
            || nv->id[3] != ' ' ||
            nv->nvram_version < __constant_cpu_to_le16(ICB_VERSION)) {
                /* Reset NVRAM data. */
-               qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
-                   "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
+               ql_log(ql_log_info, vha, 0x0073,
+                   "Inconisistent NVRAM detected: checksum=0x%x id=%c "
+                   "version=0x%x.\n", chksum, nv->id[0],
                    le16_to_cpu(nv->nvram_version));
-               qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
-                   "invalid -- WWPN) defaults.\n");
+               ql_log(ql_log_info, vha, 0x0074,
+                   "Falling back to functioning (yet invalid -- WWPN) "
+                   "defaults.\n");
 
                /*
                 * Set default initialization control block.
@@ -5350,12 +5364,10 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
        if (ha->zio_mode != QLA_ZIO_DISABLED) {
                ha->zio_mode = QLA_ZIO_MODE_6;
 
-               DEBUG2(printk("scsi(%ld): ZIO mode %d enabled; timer delay "
-                   "(%d us).\n", vha->host_no, ha->zio_mode,
-                   ha->zio_timer * 100));
-               qla_printk(KERN_INFO, ha,
+               ql_log(ql_log_info, vha, 0x0075,
                    "ZIO mode %d enabled; timer delay (%d us).\n",
-                   ha->zio_mode, ha->zio_timer * 100);
+                   ha->zio_mode,
+                   ha->zio_timer * 100);
 
                icb->firmware_options_2 |= cpu_to_le32(
                    (uint32_t)ha->zio_mode);
@@ -5364,8 +5376,8 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
        }
 
        if (rval) {
-               DEBUG2_3(printk(KERN_WARNING
-                   "scsi(%ld): NVRAM configuration failed!\n", vha->host_no));
+               ql_log(ql_log_warn, vha, 0x0076,
+                   "NVRAM configuration failed.\n");
        }
        return (rval);
 }
@@ -5388,9 +5400,8 @@ qla82xx_restart_isp(scsi_qla_host_t *vha)
 
                status = qla2x00_fw_ready(vha);
                if (!status) {
-                       qla_printk(KERN_INFO, ha,
-                       "%s(): Start configure loop, "
-                       "status = %d\n", __func__, status);
+                       ql_log(ql_log_info, vha, 0x803c,
+                           "Start configure loop, status =%d.\n", status);
 
                        /* Issue a marker after FW becomes ready. */
                        qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL);
@@ -5412,9 +5423,8 @@ qla82xx_restart_isp(scsi_qla_host_t *vha)
                if ((vha->device_flags & DFLG_NO_CABLE))
                        status = 0;
 
-               qla_printk(KERN_INFO, ha,
-                       "%s(): Configure loop done, status = 0x%x\n",
-                       __func__, status);
+               ql_log(ql_log_info, vha, 0x803d,
+                   "Configure loop done, status = 0x%x.\n", status);
        }
 
        if (!status) {
@@ -5450,9 +5460,9 @@ qla82xx_restart_isp(scsi_qla_host_t *vha)
                            ha->fce_dma, ha->fce_bufs, ha->fce_mb,
                            &ha->fce_bufs);
                        if (rval) {
-                               qla_printk(KERN_WARNING, ha,
-                                   "Unable to reinitialize FCE "
-                                   "(%d).\n", rval);
+                               ql_log(ql_log_warn, vha, 0x803e,
+                                   "Unable to reinitialize FCE (%d).\n",
+                                   rval);
                                ha->flags.fce_enabled = 0;
                        }
                }
@@ -5462,17 +5472,16 @@ qla82xx_restart_isp(scsi_qla_host_t *vha)
                        rval = qla2x00_enable_eft_trace(vha,
                            ha->eft_dma, EFT_NUM_BUFFERS);
                        if (rval) {
-                               qla_printk(KERN_WARNING, ha,
-                                   "Unable to reinitialize EFT "
-                                   "(%d).\n", rval);
+                               ql_log(ql_log_warn, vha, 0x803f,
+                                   "Unable to reinitialize EFT (%d).\n",
+                                   rval);
                        }
                }
        }
 
        if (!status) {
-               DEBUG(printk(KERN_INFO
-                       "qla82xx_restart_isp(%ld): succeeded.\n",
-                       vha->host_no));
+               ql_dbg(ql_dbg_taskm, vha, 0x8040,
+                   "qla82xx_restart_isp succeeded.\n");
 
                spin_lock_irqsave(&ha->vport_slock, flags);
                list_for_each_entry(vp, &ha->vp_list, list) {
@@ -5489,8 +5498,8 @@ qla82xx_restart_isp(scsi_qla_host_t *vha)
                spin_unlock_irqrestore(&ha->vport_slock, flags);
 
        } else {
-               qla_printk(KERN_INFO, ha,
-                       "qla82xx_restart_isp: **** FAILED ****\n");
+               ql_log(ql_log_warn, vha, 0x8041,
+                   "qla82xx_restart_isp **** FAILED ****.\n");
        }
 
        return status;
@@ -5640,9 +5649,8 @@ qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *vha, fc_port_t *fcport)
        if (ret == QLA_SUCCESS)
                fcport->fcp_prio = priority;
        else
-               DEBUG2(printk(KERN_WARNING
-                       "scsi(%ld): Unable to activate fcp priority, "
-                       " ret=0x%x\n", vha->host_no, ret));
+               ql_dbg(ql_dbg_user, vha, 0x704f,
+                   "Unable to activate fcp priority, ret=0x%x.\n", ret);
 
        return  ret;
 }
index 4c8167e..d2e904b 100644 (file)
@@ -94,11 +94,11 @@ qla2x00_set_fcport_state(fc_port_t *fcport, int state)
 
        /* Don't print state transitions during initial allocation of fcport */
        if (old_state && old_state != state) {
-               DEBUG(qla_printk(KERN_WARNING, fcport->vha->hw,
-                   "scsi(%ld): FCPort state transitioned from %s to %s - "
-                   "portid=%02x%02x%02x.\n", fcport->vha->host_no,
+               ql_dbg(ql_dbg_disc, fcport->vha, 0x207d,
+                   "FCPort state transitioned from %s to %s - "
+                   "portid=%02x%02x%02x.\n",
                    port_state_str[old_state], port_state_str[state],
                    fcport->d_id.b.domain, fcport->d_id.b.area,
-                   fcport->d_id.b.al_pa));
+                   fcport->d_id.b.al_pa);
        }
 }
index 7bac3cd..49d6906 100644 (file)
@@ -150,7 +150,8 @@ qla24xx_configure_prot_mode(srb_t *sp, uint16_t *fw_prot_opts)
 
        /* We only support T10 DIF right now */
        if (guard != SHOST_DIX_GUARD_CRC) {
-               DEBUG2(printk(KERN_ERR "Unsupported guard: %d\n", guard));
+               ql_dbg(ql_dbg_io, sp->fcport->vha, 0x3007,
+                   "Unsupported guard: %d for cmd=%p.\n", guard, sp->cmd);
                return 0;
        }
 
@@ -343,9 +344,10 @@ qla2x00_start_scsi(srb_t *sp)
 
        /* Send marker if required */
        if (vha->marker_needed != 0) {
-               if (qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL)
-                                                       != QLA_SUCCESS)
+               if (qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL) !=
+                   QLA_SUCCESS) {
                        return (QLA_FUNCTION_FAILED);
+               }
                vha->marker_needed = 0;
        }
 
@@ -490,8 +492,8 @@ __qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req,
        mrk24 = NULL;
        mrk = (mrk_entry_t *)qla2x00_alloc_iocbs(vha, 0);
        if (mrk == NULL) {
-               DEBUG2_3(printk("%s(%ld): failed to allocate Marker IOCB.\n",
-                   __func__, base_vha->host_no));
+               ql_log(ql_log_warn, base_vha, 0x3026,
+                   "Failed to allocate Marker IOCB.\n");
 
                return (QLA_FUNCTION_FAILED);
        }
@@ -547,9 +549,10 @@ qla2x00_isp_cmd(struct scsi_qla_host *vha, struct req_que *req)
        device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id);
        struct device_reg_2xxx __iomem *ioreg = &ha->iobase->isp;
 
-       DEBUG5(printk("%s(): IOCB data:\n", __func__));
-       DEBUG5(qla2x00_dump_buffer(
-           (uint8_t *)req->ring_ptr, REQUEST_ENTRY_SIZE));
+       ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x302d,
+           "IOCB data:\n");
+       ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302e,
+           (uint8_t *)req->ring_ptr, REQUEST_ENTRY_SIZE);
 
        /* Adjust ring index. */
        req->ring_index++;
@@ -604,7 +607,7 @@ qla2x00_isp_cmd(struct scsi_qla_host *vha, struct req_que *req)
  * Returns the number of IOCB entries needed to store @dsds.
  */
 inline uint16_t
-qla24xx_calc_iocbs(uint16_t dsds)
+qla24xx_calc_iocbs(scsi_qla_host_t *vha, uint16_t dsds)
 {
        uint16_t iocbs;
 
@@ -614,8 +617,6 @@ qla24xx_calc_iocbs(uint16_t dsds)
                if ((dsds - 1) % 5)
                        iocbs++;
        }
-       DEBUG3(printk(KERN_DEBUG "%s(): Required PKT(s) = %d\n",
-           __func__, iocbs));
        return iocbs;
 }
 
@@ -712,6 +713,7 @@ qla24xx_set_t10dif_tags(struct scsi_cmnd *cmd, struct fw_dif_context *pkt,
     unsigned int protcnt)
 {
        struct sd_dif_tuple *spt;
+       scsi_qla_host_t *vha = shost_priv(cmd->device->host);
        unsigned char op = scsi_get_prot_op(cmd);
 
        switch (scsi_get_prot_type(cmd)) {
@@ -768,9 +770,9 @@ qla24xx_set_t10dif_tags(struct scsi_cmnd *cmd, struct fw_dif_context *pkt,
                    op == SCSI_PROT_WRITE_PASS)) {
                        spt = page_address(sg_page(scsi_prot_sglist(cmd))) +
                            scsi_prot_sglist(cmd)[0].offset;
-                       DEBUG18(printk(KERN_DEBUG
-                           "%s(): LBA from user %p, lba = 0x%x\n",
-                           __func__, spt, (int)spt->ref_tag));
+                       ql_dbg(ql_dbg_io, vha, 0x3008,
+                           "LBA from user %p, lba = 0x%x for cmd=%p.\n",
+                           spt, (int)spt->ref_tag, cmd);
                        pkt->ref_tag = swab32(spt->ref_tag);
                        pkt->app_tag_mask[0] = 0x0;
                        pkt->app_tag_mask[1] = 0x0;
@@ -789,11 +791,11 @@ qla24xx_set_t10dif_tags(struct scsi_cmnd *cmd, struct fw_dif_context *pkt,
                break;
        }
 
-       DEBUG18(printk(KERN_DEBUG
-           "%s(): Setting protection Tags: (BIG) ref tag = 0x%x,"
-           " app tag = 0x%x, prot SG count %d , cmd lba 0x%x,"
-           " prot_type=%u\n", __func__, pkt->ref_tag, pkt->app_tag, protcnt,
-           (int)scsi_get_lba(cmd), scsi_get_prot_type(cmd)));
+       ql_dbg(ql_dbg_io, vha, 0x3009,
+           "Setting protection Tags: (BIG) ref tag = 0x%x, app tag = 0x%x, "
+           "prot SG count %d, cmd lba 0x%x, prot_type=%u cmd=%p.\n",
+           pkt->ref_tag, pkt->app_tag, protcnt, (int)scsi_get_lba(cmd),
+           scsi_get_prot_type(cmd), cmd);
 }
 
 
@@ -809,6 +811,7 @@ qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, uint32_t *dsd,
        uint32_t *cur_dsd = dsd;
        int     i;
        uint16_t        used_dsds = tot_dsds;
+       scsi_qla_host_t *vha = shost_priv(sp->cmd->device->host);
 
        uint8_t         *cp;
 
@@ -853,9 +856,10 @@ qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, uint32_t *dsd,
                        cur_dsd = (uint32_t *)next_dsd;
                }
                sle_dma = sg_dma_address(sg);
-               DEBUG18(printk("%s(): %p, sg entry %d - addr =0x%x 0x%x,"
-                   " len =%d\n", __func__ , cur_dsd, i, LSD(sle_dma),
-                   MSD(sle_dma), sg_dma_len(sg)));
+               ql_dbg(ql_dbg_io, vha, 0x300a,
+                   "sg entry %d - addr=0x%x 0x%x, " "len=%d for cmd=%p.\n",
+                   cur_dsd, i, LSD(sle_dma), MSD(sle_dma), sg_dma_len(sg),
+                   sp->cmd);
                *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
                *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
                *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
@@ -863,8 +867,8 @@ qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, uint32_t *dsd,
 
                if (scsi_get_prot_op(sp->cmd) == SCSI_PROT_WRITE_PASS) {
                        cp = page_address(sg_page(sg)) + sg->offset;
-                       DEBUG18(printk("%s(): User Data buffer= %p:\n",
-                           __func__ , cp));
+                       ql_dbg(ql_dbg_io, vha, 0x300b,
+                           "User data buffer=%p for cmd=%p.\n", cp, sp->cmd);
                }
        }
        /* Null termination */
@@ -888,7 +892,7 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp,
        struct scsi_cmnd *cmd;
        uint32_t *cur_dsd = dsd;
        uint16_t        used_dsds = tot_dsds;
-
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
        uint8_t         *cp;
 
 
@@ -935,10 +939,11 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp,
                }
                sle_dma = sg_dma_address(sg);
                if (scsi_get_prot_op(sp->cmd) == SCSI_PROT_WRITE_PASS) {
-                       DEBUG18(printk(KERN_DEBUG
-                           "%s(): %p, sg entry %d - addr =0x%x"
-                           "0x%x, len =%d\n", __func__ , cur_dsd, i,
-                           LSD(sle_dma), MSD(sle_dma), sg_dma_len(sg)));
+                       ql_dbg(ql_dbg_io, vha, 0x3027,
+                           "%s(): %p, sg_entry %d - "
+                           "addr=0x%x0x%x, len=%d.\n",
+                           __func__, cur_dsd, i,
+                           LSD(sle_dma), MSD(sle_dma), sg_dma_len(sg));
                }
                *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
                *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
@@ -946,8 +951,9 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp,
 
                if (scsi_get_prot_op(sp->cmd) == SCSI_PROT_WRITE_PASS) {
                        cp = page_address(sg_page(sg)) + sg->offset;
-                       DEBUG18(printk("%s(): Protection Data buffer = %p:\n",
-                           __func__ , cp));
+                       ql_dbg(ql_dbg_io, vha, 0x3028,
+                           "%s(): Protection Data buffer = %p.\n", __func__,
+                           cp);
                }
                avail_dsds--;
        }
@@ -996,22 +1002,16 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
        *((uint32_t *)(&cmd_pkt->entry_type)) =
            __constant_cpu_to_le32(COMMAND_TYPE_CRC_2);
 
+       vha = sp->fcport->vha;
+       ha = vha->hw;
+
        /* No data transfer */
        data_bytes = scsi_bufflen(cmd);
        if (!data_bytes || cmd->sc_data_direction == DMA_NONE) {
-               DEBUG18(printk(KERN_INFO "%s: Zero data bytes or DMA-NONE %d\n",
-                   __func__, data_bytes));
                cmd_pkt->byte_count = __constant_cpu_to_le32(0);
                return QLA_SUCCESS;
        }
 
-       vha = sp->fcport->vha;
-       ha = vha->hw;
-
-       DEBUG18(printk(KERN_DEBUG
-           "%s(%ld): Executing cmd sp %p, prot_op=%u.\n", __func__,
-           vha->host_no, sp, scsi_get_prot_op(sp->cmd)));
-
        cmd_pkt->vp_index = sp->fcport->vp_idx;
 
        /* Set transfer direction */
@@ -1056,8 +1056,6 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
 
        /* Determine SCSI command length -- align to 4 byte boundary */
        if (cmd->cmd_len > 16) {
-               DEBUG18(printk(KERN_INFO "%s(): **** SCSI CMD > 16\n",
-                   __func__));
                additional_fcpcdb_len = cmd->cmd_len - 16;
                if ((cmd->cmd_len % 4) != 0) {
                        /* SCSI cmd > 16 bytes must be multiple of 4 */
@@ -1108,11 +1106,6 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
 
        cmd_pkt->fcp_rsp_dseg_len = 0; /* Let response come in status iocb */
 
-       DEBUG18(printk(KERN_INFO "%s(%ld): Total SG(s) Entries %d, Data"
-           "entries %d, data bytes %d, Protection entries %d\n",
-           __func__, vha->host_no, tot_dsds, (tot_dsds-tot_prot_dsds),
-           data_bytes, tot_prot_dsds));
-
        /* Compute dif len and adjust data len to incude protection */
        total_bytes = data_bytes;
        dif_bytes = 0;
@@ -1150,14 +1143,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
            additional_fcpcdb_len);
        *fcp_dl = htonl(total_bytes);
 
-       DEBUG18(printk(KERN_INFO "%s(%ld): dif bytes = 0x%x (%d), total bytes"
-           " = 0x%x (%d), dat block size =0x%x (%d)\n", __func__,
-           vha->host_no, dif_bytes, dif_bytes, total_bytes, total_bytes,
-           crc_ctx_pkt->blk_size, crc_ctx_pkt->blk_size));
-
        if (!data_bytes || cmd->sc_data_direction == DMA_NONE) {
-               DEBUG18(printk(KERN_INFO "%s: Zero data bytes or DMA-NONE %d\n",
-                   __func__, data_bytes));
                cmd_pkt->byte_count = __constant_cpu_to_le32(0);
                return QLA_SUCCESS;
        }
@@ -1182,8 +1168,6 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
        return QLA_SUCCESS;
 
 crc_queuing_error:
-       DEBUG18(qla_printk(KERN_INFO, ha,
-           "CMD sent FAILED crc_q error:sp = %p\n", sp));
        /* Cleanup will be performed by the caller */
 
        return QLA_FUNCTION_FAILED;
@@ -1225,8 +1209,8 @@ qla24xx_start_scsi(srb_t *sp)
 
        /* Send marker if required */
        if (vha->marker_needed != 0) {
-               if (qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL)
-                                                       != QLA_SUCCESS)
+               if (qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL) !=
+                   QLA_SUCCESS)
                        return QLA_FUNCTION_FAILED;
                vha->marker_needed = 0;
        }
@@ -1243,8 +1227,9 @@ qla24xx_start_scsi(srb_t *sp)
                if (!req->outstanding_cmds[handle])
                        break;
        }
-       if (index == MAX_OUTSTANDING_COMMANDS)
+       if (index == MAX_OUTSTANDING_COMMANDS) {
                goto queuing_error;
+       }
 
        /* Map the sg table so we have an accurate count of sg entries needed */
        if (scsi_sg_count(cmd)) {
@@ -1256,8 +1241,7 @@ qla24xx_start_scsi(srb_t *sp)
                nseg = 0;
 
        tot_dsds = nseg;
-
-       req_cnt = qla24xx_calc_iocbs(tot_dsds);
+       req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
        if (req->cnt < (req_cnt + 2)) {
                cnt = RD_REG_DWORD_RELAXED(req->req_q_out);
 
@@ -1322,7 +1306,6 @@ qla24xx_start_scsi(srb_t *sp)
        /* Specify response queue number where completion should happen */
        cmd_pkt->entry_status = (uint8_t) rsp->id;
        wmb();
-
        /* Adjust ring index. */
        req->ring_index++;
        if (req->ring_index == req->length) {
@@ -1534,9 +1517,6 @@ queuing_error:
        /* Cleanup will be performed by the caller (queuecommand) */
 
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
-       DEBUG18(qla_printk(KERN_INFO, ha,
-           "CMD sent FAILED SCSI prot_op:%02x\n", scsi_get_prot_op(cmd)));
        return QLA_FUNCTION_FAILED;
 }
 
@@ -1581,8 +1561,11 @@ qla2x00_alloc_iocbs(scsi_qla_host_t *vha, srb_t *sp)
                if (!req->outstanding_cmds[handle])
                        break;
        }
-       if (index == MAX_OUTSTANDING_COMMANDS)
+       if (index == MAX_OUTSTANDING_COMMANDS) {
+               ql_log(ql_log_warn, vha, 0x700b,
+                   "No room on oustanding cmd array.\n");
                goto queuing_error;
+       }
 
        /* Prep command array. */
        req->current_outstanding_cmd = handle;
@@ -1999,8 +1982,11 @@ qla2x00_start_sp(srb_t *sp)
        rval = QLA_FUNCTION_FAILED;
        spin_lock_irqsave(&ha->hardware_lock, flags);
        pkt = qla2x00_alloc_iocbs(sp->fcport->vha, sp);
-       if (!pkt)
+       if (!pkt) {
+               ql_log(ql_log_warn, sp->fcport->vha, 0x700c,
+                   "qla2x00_alloc_iocbs failed.\n");
                goto done;
+       }
 
        rval = QLA_SUCCESS;
        switch (ctx->type) {
index ae8e298..b16b772 100644 (file)
@@ -45,7 +45,7 @@ qla2100_intr_handler(int irq, void *dev_id)
        rsp = (struct rsp_que *) dev_id;
        if (!rsp) {
                printk(KERN_INFO
-                   "%s(): NULL response queue pointer\n", __func__);
+                   "%s(): NULL response queue pointer.\n", __func__);
                return (IRQ_NONE);
        }
 
@@ -91,9 +91,9 @@ qla2100_intr_handler(int irq, void *dev_id)
                                qla2x00_async_event(vha, rsp, mb);
                        } else {
                                /*EMPTY*/
-                               DEBUG2(printk("scsi(%ld): Unrecognized "
-                                   "interrupt type (%d).\n",
-                                   vha->host_no, mb[0]));
+                               ql_dbg(ql_dbg_async, vha, 0x5025,
+                                   "Unrecognized interrupt type (%d).\n",
+                                   mb[0]);
                        }
                        /* Release mailbox registers. */
                        WRT_REG_WORD(&reg->semaphore, 0);
@@ -142,7 +142,7 @@ qla2300_intr_handler(int irq, void *dev_id)
        rsp = (struct rsp_que *) dev_id;
        if (!rsp) {
                printk(KERN_INFO
-                   "%s(): NULL response queue pointer\n", __func__);
+                   "%s(): NULL response queue pointer.\n", __func__);
                return (IRQ_NONE);
        }
 
@@ -160,11 +160,13 @@ qla2300_intr_handler(int irq, void *dev_id)
 
                        hccr = RD_REG_WORD(&reg->hccr);
                        if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8))
-                               qla_printk(KERN_INFO, ha, "Parity error -- "
-                                   "HCCR=%x, Dumping firmware!\n", hccr);
+                               ql_log(ql_log_warn, vha, 0x5026,
+                                   "Parity error -- HCCR=%x, Dumping "
+                                   "firmware.\n", hccr);
                        else
-                               qla_printk(KERN_INFO, ha, "RISC paused -- "
-                                   "HCCR=%x, Dumping firmware!\n", hccr);
+                               ql_log(ql_log_warn, vha, 0x5027,
+                                   "RISC paused -- HCCR=%x, Dumping "
+                                   "firmware.\n", hccr);
 
                        /*
                         * Issue a "HARD" reset in order for the RISC
@@ -213,9 +215,8 @@ qla2300_intr_handler(int irq, void *dev_id)
                        qla2x00_async_event(vha, rsp, mb);
                        break;
                default:
-                       DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
-                           "(%d).\n",
-                           vha->host_no, stat & 0xff));
+                       ql_dbg(ql_dbg_async, vha, 0x5028,
+                           "Unrecognized interrupt type (%d).\n", stat & 0xff);
                        break;
                }
                WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
@@ -262,11 +263,11 @@ qla2x00_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
        }
 
        if (ha->mcp) {
-               DEBUG3(printk("%s(%ld): Got mailbox completion. cmd=%x.\n",
-                   __func__, vha->host_no, ha->mcp->mb[0]));
+               ql_dbg(ql_dbg_async, vha, 0x5000,
+                   "Got mbx completion. cmd=%x.\n", ha->mcp->mb[0]);
        } else {
-               DEBUG2_3(printk("%s(%ld): MBX pointer ERROR!\n",
-                   __func__, vha->host_no));
+               ql_dbg(ql_dbg_async, vha, 0x5001,
+                   "MBX pointer ERROR.\n");
        }
 }
 
@@ -285,22 +286,24 @@ qla81xx_idc_event(scsi_qla_host_t *vha, uint16_t aen, uint16_t descr)
        for (cnt = 0; cnt < QLA_IDC_ACK_REGS; cnt++, wptr++)
                mb[cnt] = RD_REG_WORD(wptr);
 
-       DEBUG2(printk("scsi(%ld): Inter-Driver Commucation %s -- "
-           "%04x %04x %04x %04x %04x %04x %04x.\n", vha->host_no,
-           event[aen & 0xff],
-           mb[0], mb[1], mb[2], mb[3], mb[4], mb[5], mb[6]));
+       ql_dbg(ql_dbg_async, vha, 0x5021,
+           "Inter-Driver Commucation %s -- "
+           "%04x %04x %04x %04x %04x %04x %04x.\n",
+           event[aen & 0xff], mb[0], mb[1], mb[2], mb[3],
+           mb[4], mb[5], mb[6]);
 
        /* Acknowledgement needed? [Notify && non-zero timeout]. */
        timeout = (descr >> 8) & 0xf;
        if (aen != MBA_IDC_NOTIFY || !timeout)
                return;
 
-       DEBUG2(printk("scsi(%ld): Inter-Driver Commucation %s -- "
-           "ACK timeout=%d.\n", vha->host_no, event[aen & 0xff], timeout));
+       ql_dbg(ql_dbg_async, vha, 0x5022,
+           "Inter-Driver Commucation %s -- ACK timeout=%d.\n",
+           vha->host_no, event[aen & 0xff], timeout);
 
        rval = qla2x00_post_idc_ack_work(vha, mb);
        if (rval != QLA_SUCCESS)
-               qla_printk(KERN_WARNING, vha->hw,
+               ql_log(ql_log_warn, vha, 0x5023,
                    "IDC failed to post ACK.\n");
 }
 
@@ -393,15 +396,15 @@ skip_rio:
                break;
 
        case MBA_RESET:                 /* Reset */
-               DEBUG2(printk("scsi(%ld): Asynchronous RESET.\n",
-                       vha->host_no));
+               ql_dbg(ql_dbg_async, vha, 0x5002,
+                   "Asynchronous RESET.\n");
 
                set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
                break;
 
        case MBA_SYSTEM_ERR:            /* System Error */
                mbx = IS_QLA81XX(ha) ? RD_REG_WORD(&reg24->mailbox7) : 0;
-               qla_printk(KERN_INFO, ha,
+               ql_log(ql_log_warn, vha, 0x5003,
                    "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh "
                    "mbx7=%xh.\n", mb[1], mb[2], mb[3], mbx);
 
@@ -409,7 +412,7 @@ skip_rio:
 
                if (IS_FWI2_CAPABLE(ha)) {
                        if (mb[1] == 0 && mb[2] == 0) {
-                               qla_printk(KERN_ERR, ha,
+                               ql_log(ql_log_fatal, vha, 0x5004,
                                    "Unrecoverable Hardware Error: adapter "
                                    "marked OFFLINE!\n");
                                vha->flags.online = 0;
@@ -422,7 +425,7 @@ skip_rio:
                                set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                        }
                } else if (mb[1] == 0) {
-                       qla_printk(KERN_INFO, ha,
+                       ql_log(ql_log_fatal, vha, 0x5005,
                            "Unrecoverable Hardware Error: adapter marked "
                            "OFFLINE!\n");
                        vha->flags.online = 0;
@@ -431,31 +434,27 @@ skip_rio:
                break;
 
        case MBA_REQ_TRANSFER_ERR:      /* Request Transfer Error */
-               DEBUG2(printk("scsi(%ld): ISP Request Transfer Error (%x).\n",
-                   vha->host_no, mb[1]));
-               qla_printk(KERN_WARNING, ha,
-                   "ISP Request Transfer Error (%x).\n", mb[1]);
+               ql_log(ql_log_warn, vha, 0x5006,
+                   "ISP Request Transfer Error (%x).\n",  mb[1]);
 
                set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                break;
 
        case MBA_RSP_TRANSFER_ERR:      /* Response Transfer Error */
-               DEBUG2(printk("scsi(%ld): ISP Response Transfer Error.\n",
-                   vha->host_no));
-               qla_printk(KERN_WARNING, ha, "ISP Response Transfer Error.\n");
+               ql_log(ql_log_warn, vha, 0x5007,
+                   "ISP Response Transfer Error.\n");
 
                set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                break;
 
        case MBA_WAKEUP_THRES:          /* Request Queue Wake-up */
-               DEBUG2(printk("scsi(%ld): Asynchronous WAKEUP_THRES.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_async, vha, 0x5008,
+                   "Asynchronous WAKEUP_THRES.\n");
                break;
 
        case MBA_LIP_OCCURRED:          /* Loop Initialization Procedure */
-               DEBUG2(printk("scsi(%ld): LIP occurred (%x).\n", vha->host_no,
-                   mb[1]));
-               qla_printk(KERN_INFO, ha, "LIP occurred (%x).\n", mb[1]);
+               ql_log(ql_log_info, vha, 0x5009,
+                   "LIP occurred (%x).\n", mb[1]);
 
                if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
                        atomic_set(&vha->loop_state, LOOP_DOWN);
@@ -488,10 +487,8 @@ skip_rio:
                        ha->link_data_rate = mb[1];
                }
 
-               DEBUG2(printk("scsi(%ld): Asynchronous LOOP UP (%s Gbps).\n",
-                   vha->host_no, link_speed));
-               qla_printk(KERN_INFO, ha, "LOOP UP detected (%s Gbps).\n",
-                   link_speed);
+               ql_log(ql_log_info, vha, 0x500a,
+                   "LOOP UP detected (%s Gbps).\n", link_speed);
 
                vha->flags.management_server_logged_in = 0;
                qla2x00_post_aen_work(vha, FCH_EVT_LINKUP, ha->link_data_rate);
@@ -500,12 +497,9 @@ skip_rio:
        case MBA_LOOP_DOWN:             /* Loop Down Event */
                mbx = IS_QLA81XX(ha) ? RD_REG_WORD(&reg24->mailbox4) : 0;
                mbx = IS_QLA82XX(ha) ? RD_REG_WORD(&reg82->mailbox_out[4]) : mbx;
-               DEBUG2(printk("scsi(%ld): Asynchronous LOOP DOWN "
-                   "(%x %x %x %x).\n", vha->host_no, mb[1], mb[2], mb[3],
-                   mbx));
-               qla_printk(KERN_INFO, ha,
-                   "LOOP DOWN detected (%x %x %x %x).\n", mb[1], mb[2], mb[3],
-                   mbx);
+               ql_log(ql_log_info, vha, 0x500b,
+                   "LOOP DOWN detected (%x %x %x %x).\n",
+                   mb[1], mb[2], mb[3], mbx);
 
                if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
                        atomic_set(&vha->loop_state, LOOP_DOWN);
@@ -525,9 +519,7 @@ skip_rio:
                break;
 
        case MBA_LIP_RESET:             /* LIP reset occurred */
-               DEBUG2(printk("scsi(%ld): Asynchronous LIP RESET (%x).\n",
-                   vha->host_no, mb[1]));
-               qla_printk(KERN_INFO, ha,
+               ql_log(ql_log_info, vha, 0x500c,
                    "LIP reset occurred (%x).\n", mb[1]);
 
                if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
@@ -554,14 +546,15 @@ skip_rio:
                        break;
 
                if (IS_QLA8XXX_TYPE(ha)) {
-                       DEBUG2(printk("scsi(%ld): DCBX Completed -- %04x %04x "
-                           "%04x\n", vha->host_no, mb[1], mb[2], mb[3]));
+                       ql_dbg(ql_dbg_async, vha, 0x500d,
+                           "DCBX Completed -- %04x %04x %04x.\n",
+                           mb[1], mb[2], mb[3]);
                        if (ha->notify_dcbx_comp)
                                complete(&ha->dcbx_comp);
 
                } else
-                       DEBUG2(printk("scsi(%ld): Asynchronous P2P MODE "
-                           "received.\n", vha->host_no));
+                       ql_dbg(ql_dbg_async, vha, 0x500e,
+                           "Asynchronous P2P MODE received.\n");
 
                /*
                 * Until there's a transition from loop down to loop up, treat
@@ -594,10 +587,7 @@ skip_rio:
                if (IS_QLA2100(ha))
                        break;
 
-               DEBUG2(printk("scsi(%ld): Asynchronous Change In Connection "
-                   "received.\n",
-                   vha->host_no));
-               qla_printk(KERN_INFO, ha,
+               ql_log(ql_log_info, vha, 0x500f,
                    "Configuration change detected: value=%x.\n", mb[1]);
 
                if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
@@ -640,11 +630,9 @@ skip_rio:
 
                /* Global event -- port logout or port unavailable. */
                if (mb[1] == 0xffff && mb[2] == 0x7) {
-                       DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE.\n",
-                           vha->host_no));
-                       DEBUG(printk(KERN_INFO
-                           "scsi(%ld): Port unavailable %04x %04x %04x.\n",
-                           vha->host_no, mb[1], mb[2], mb[3]));
+                       ql_dbg(ql_dbg_async, vha, 0x5010,
+                           "Port unavailable %04x %04x %04x.\n",
+                           mb[1], mb[2], mb[3]);
 
                        if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
                                atomic_set(&vha->loop_state, LOOP_DOWN);
@@ -674,17 +662,15 @@ skip_rio:
                atomic_set(&vha->loop_down_timer, 0);
                if (atomic_read(&vha->loop_state) != LOOP_DOWN &&
                    atomic_read(&vha->loop_state) != LOOP_DEAD) {
-                       DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE "
-                           "ignored %04x/%04x/%04x.\n", vha->host_no, mb[1],
-                           mb[2], mb[3]));
+                       ql_dbg(ql_dbg_async, vha, 0x5011,
+                           "Asynchronous PORT UPDATE ignored %04x/%04x/%04x.\n",
+                           mb[1], mb[2], mb[3]);
                        break;
                }
 
-               DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE.\n",
-                   vha->host_no));
-               DEBUG(printk(KERN_INFO
-                   "scsi(%ld): Port database changed %04x %04x %04x.\n",
-                   vha->host_no, mb[1], mb[2], mb[3]));
+               ql_dbg(ql_dbg_async, vha, 0x5012,
+                   "Port database changed %04x %04x %04x.\n",
+                   mb[1], mb[2], mb[3]);
 
                /*
                 * Mark all devices as missing so we will login again.
@@ -707,20 +693,17 @@ skip_rio:
                if (ha->flags.npiv_supported && vha->vp_idx != (mb[3] & 0xff))
                        break;
 
-               DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n",
-                   vha->host_no));
-               DEBUG(printk(KERN_INFO
-                   "scsi(%ld): RSCN database changed -- %04x %04x %04x.\n",
-                   vha->host_no, mb[1], mb[2], mb[3]));
+               ql_dbg(ql_dbg_async, vha, 0x5013,
+                   "RSCN database changed -- %04x %04x %04x.\n",
+                   mb[1], mb[2], mb[3]);
 
                rscn_entry = ((mb[1] & 0xff) << 16) | mb[2];
                host_pid = (vha->d_id.b.domain << 16) | (vha->d_id.b.area << 8)
                                | vha->d_id.b.al_pa;
                if (rscn_entry == host_pid) {
-                       DEBUG(printk(KERN_INFO
-                           "scsi(%ld): Ignoring RSCN update to local host "
-                           "port ID (%06x)\n",
-                           vha->host_no, host_pid));
+                       ql_dbg(ql_dbg_async, vha, 0x5014,
+                           "Ignoring RSCN update to local host "
+                           "port ID (%06x).\n", host_pid);
                        break;
                }
 
@@ -747,8 +730,8 @@ skip_rio:
 
        /* case MBA_RIO_RESPONSE: */
        case MBA_ZIO_RESPONSE:
-               DEBUG3(printk("scsi(%ld): [R|Z]IO update completion.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_async, vha, 0x5015,
+                   "[R|Z]IO update completion.\n");
 
                if (IS_FWI2_CAPABLE(ha))
                        qla24xx_process_response_queue(vha, rsp);
@@ -757,61 +740,68 @@ skip_rio:
                break;
 
        case MBA_DISCARD_RND_FRAME:
-               DEBUG2(printk("scsi(%ld): Discard RND Frame -- %04x %04x "
-                   "%04x.\n", vha->host_no, mb[1], mb[2], mb[3]));
+               ql_dbg(ql_dbg_async, vha, 0x5016,
+                   "Discard RND Frame -- %04x %04x %04x.\n",
+                   mb[1], mb[2], mb[3]);
                break;
 
        case MBA_TRACE_NOTIFICATION:
-               DEBUG2(printk("scsi(%ld): Trace Notification -- %04x %04x.\n",
-               vha->host_no, mb[1], mb[2]));
+               ql_dbg(ql_dbg_async, vha, 0x5017,
+                   "Trace Notification -- %04x %04x.\n", mb[1], mb[2]);
                break;
 
        case MBA_ISP84XX_ALERT:
-               DEBUG2(printk("scsi(%ld): ISP84XX Alert Notification -- "
-                   "%04x %04x %04x\n", vha->host_no, mb[1], mb[2], mb[3]));
+               ql_dbg(ql_dbg_async, vha, 0x5018,
+                   "ISP84XX Alert Notification -- %04x %04x %04x.\n",
+                   mb[1], mb[2], mb[3]);
 
                spin_lock_irqsave(&ha->cs84xx->access_lock, flags);
                switch (mb[1]) {
                case A84_PANIC_RECOVERY:
-                       qla_printk(KERN_INFO, ha, "Alert 84XX: panic recovery "
-                           "%04x %04x\n", mb[2], mb[3]);
+                       ql_log(ql_log_info, vha, 0x5019,
+                           "Alert 84XX: panic recovery %04x %04x.\n",
+                           mb[2], mb[3]);
                        break;
                case A84_OP_LOGIN_COMPLETE:
                        ha->cs84xx->op_fw_version = mb[3] << 16 | mb[2];
-                       DEBUG2(qla_printk(KERN_INFO, ha, "Alert 84XX:"
-                           "firmware version %x\n", ha->cs84xx->op_fw_version));
+                       ql_log(ql_log_info, vha, 0x501a,
+                           "Alert 84XX: firmware version %x.\n",
+                           ha->cs84xx->op_fw_version);
                        break;
                case A84_DIAG_LOGIN_COMPLETE:
                        ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2];
-                       DEBUG2(qla_printk(KERN_INFO, ha, "Alert 84XX:"
-                           "diagnostic firmware version %x\n",
-                           ha->cs84xx->diag_fw_version));
+                       ql_log(ql_log_info, vha, 0x501b,
+                           "Alert 84XX: diagnostic firmware version %x.\n",
+                           ha->cs84xx->diag_fw_version);
                        break;
                case A84_GOLD_LOGIN_COMPLETE:
                        ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2];
                        ha->cs84xx->fw_update = 1;
-                       DEBUG2(qla_printk(KERN_INFO, ha, "Alert 84XX: gold "
-                           "firmware version %x\n",
-                           ha->cs84xx->gold_fw_version));
+                       ql_log(ql_log_info, vha, 0x501c,
+                           "Alert 84XX: gold firmware version %x.\n",
+                           ha->cs84xx->gold_fw_version);
                        break;
                default:
-                       qla_printk(KERN_ERR, ha,
-                           "Alert 84xx: Invalid Alert %04x %04x %04x\n",
+                       ql_log(ql_log_warn, vha, 0x501d,
+                           "Alert 84xx: Invalid Alert %04x %04x %04x.\n",
                            mb[1], mb[2], mb[3]);
                }
                spin_unlock_irqrestore(&ha->cs84xx->access_lock, flags);
                break;
        case MBA_DCBX_START:
-               DEBUG2(printk("scsi(%ld): DCBX Started -- %04x %04x %04x\n",
-                   vha->host_no, mb[1], mb[2], mb[3]));
+               ql_dbg(ql_dbg_async, vha, 0x501e,
+                   "DCBX Started -- %04x %04x %04x.\n",
+                   mb[1], mb[2], mb[3]);
                break;
        case MBA_DCBX_PARAM_UPDATE:
-               DEBUG2(printk("scsi(%ld): DCBX Parameters Updated -- "
-                   "%04x %04x %04x\n", vha->host_no, mb[1], mb[2], mb[3]));
+               ql_dbg(ql_dbg_async, vha, 0x501f,
+                   "DCBX Parameters Updated -- %04x %04x %04x.\n",
+                   mb[1], mb[2], mb[3]);
                break;
        case MBA_FCF_CONF_ERR:
-               DEBUG2(printk("scsi(%ld): FCF Configuration Error -- "
-                   "%04x %04x %04x\n", vha->host_no, mb[1], mb[2], mb[3]));
+               ql_dbg(ql_dbg_async, vha, 0x5020,
+                   "FCF Configuration Error -- %04x %04x %04x.\n",
+                   mb[1], mb[2], mb[3]);
                break;
        case MBA_IDC_COMPLETE:
        case MBA_IDC_NOTIFY:
@@ -838,10 +828,8 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha,
 
        /* Validate handle. */
        if (index >= MAX_OUTSTANDING_COMMANDS) {
-               DEBUG2(printk("scsi(%ld): Invalid SCSI completion handle %d.\n",
-                   vha->host_no, index));
-               qla_printk(KERN_WARNING, ha,
-                   "Invalid SCSI completion handle %d.\n", index);
+               ql_log(ql_log_warn, vha, 0x3014,
+                   "Invalid SCSI command index (%x).\n", index);
 
                if (IS_QLA82XX(ha))
                        set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
@@ -859,10 +847,7 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha,
                sp->cmd->result = DID_OK << 16;
                qla2x00_sp_compl(ha, sp);
        } else {
-               DEBUG2(printk("scsi(%ld) Req:%d: Invalid ISP SCSI completion"
-                       " handle(0x%x)\n", vha->host_no, req->id, index));
-               qla_printk(KERN_WARNING, ha,
-                   "Invalid ISP SCSI completion handle\n");
+               ql_log(ql_log_warn, vha, 0x3016, "Invalid SCSI SRB.\n");
 
                if (IS_QLA82XX(ha))
                        set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
@@ -882,8 +867,8 @@ qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
 
        index = LSW(pkt->handle);
        if (index >= MAX_OUTSTANDING_COMMANDS) {
-               qla_printk(KERN_WARNING, ha,
-                   "%s: Invalid completion handle (%x).\n", func, index);
+               ql_log(ql_log_warn, vha, 0x5031,
+                   "Invalid command index (%x).\n", index);
                if (IS_QLA82XX(ha))
                        set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
                else
@@ -892,15 +877,13 @@ qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
        }
        sp = req->outstanding_cmds[index];
        if (!sp) {
-               qla_printk(KERN_WARNING, ha,
-                   "%s: Invalid completion handle (%x) -- timed-out.\n", func,
-                   index);
+               ql_log(ql_log_warn, vha, 0x5032,
+                   "Invalid completion handle (%x) -- timed-out.\n", index);
                return sp;
        }
        if (sp->handle != index) {
-               qla_printk(KERN_WARNING, ha,
-                   "%s: SRB handle (%x) mismatch %x.\n", func, sp->handle,
-                   index);
+               ql_log(ql_log_warn, vha, 0x5033,
+                   "SRB handle (%x) mismatch %x.\n", sp->handle, index);
                return NULL;
        }
 
@@ -937,17 +920,17 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
        data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ?
            QLA_LOGIO_LOGIN_RETRIED : 0;
        if (mbx->entry_status) {
-               DEBUG2(printk(KERN_WARNING
-                   "scsi(%ld:%x): Async-%s error entry - portid=%02x%02x%02x "
+               ql_dbg(ql_dbg_async, vha, 0x5043,
+                   "Async-%s error entry - portid=%02x%02x%02x "
                    "entry-status=%x status=%x state-flag=%x "
                    "status-flags=%x.\n",
-                   fcport->vha->host_no, sp->handle, type,
-                   fcport->d_id.b.domain, fcport->d_id.b.area,
+                   type, fcport->d_id.b.domain, fcport->d_id.b.area,
                    fcport->d_id.b.al_pa, mbx->entry_status,
                    le16_to_cpu(mbx->status), le16_to_cpu(mbx->state_flags),
-                   le16_to_cpu(mbx->status_flags)));
+                   le16_to_cpu(mbx->status_flags));
 
-               DEBUG2(qla2x00_dump_buffer((uint8_t *)mbx, sizeof(*mbx)));
+               ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5057,
+                   (uint8_t *)mbx, sizeof(*mbx));
 
                goto logio_done;
        }
@@ -957,12 +940,10 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
            le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE)
                status = 0;
        if (!status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) {
-               DEBUG2(printk(KERN_DEBUG
-                   "scsi(%ld:%x): Async-%s complete - portid=%02x%02x%02x "
-                   "mbx1=%x.\n",
-                   fcport->vha->host_no, sp->handle, type,
-                   fcport->d_id.b.domain, fcport->d_id.b.area,
-                   fcport->d_id.b.al_pa, le16_to_cpu(mbx->mb1)));
+               ql_dbg(ql_dbg_async, vha, 0x5045,
+                   "Async-%s complete - portid=%02x%02x%02x mbx1=%x.\n",
+                   type, fcport->d_id.b.domain, fcport->d_id.b.area,
+                   fcport->d_id.b.al_pa, le16_to_cpu(mbx->mb1));
 
                data[0] = MBS_COMMAND_COMPLETE;
                if (ctx->type == SRB_LOGIN_CMD) {
@@ -987,14 +968,14 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
                break;
        }
 
-       DEBUG2(printk(KERN_WARNING
-           "scsi(%ld:%x): Async-%s failed - portid=%02x%02x%02x status=%x "
+       ql_log(ql_log_warn, vha, 0x5046,
+           "Async-%s failed - portid=%02x%02x%02x status=%x "
            "mb0=%x mb1=%x mb2=%x mb6=%x mb7=%x.\n",
-           fcport->vha->host_no, sp->handle, type, fcport->d_id.b.domain,
+           type, fcport->d_id.b.domain,
            fcport->d_id.b.area, fcport->d_id.b.al_pa, status,
            le16_to_cpu(mbx->mb0), le16_to_cpu(mbx->mb1),
            le16_to_cpu(mbx->mb2), le16_to_cpu(mbx->mb6),
-           le16_to_cpu(mbx->mb7)));
+           le16_to_cpu(mbx->mb7));
 
 logio_done:
        lio->done(sp);
@@ -1025,9 +1006,8 @@ qla2x00_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
                type = "ct pass-through";
                break;
        default:
-               qla_printk(KERN_WARNING, ha,
-                   "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp,
-                   sp_bsg->type);
+               ql_log(ql_log_warn, vha, 0x5047,
+                   "Unrecognized SRB: (%p) type=%d.\n", sp, sp_bsg->type);
                return;
        }
 
@@ -1045,20 +1025,20 @@ qla2x00_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
                        bsg_job->reply->reply_payload_rcv_len =
                            le16_to_cpu(((sts_entry_t *)pkt)->rsp_info_len);
 
-                       DEBUG2(qla_printk(KERN_WARNING, ha,
-                           "scsi(%ld): CT pass-through-%s error "
+                       ql_log(ql_log_warn, vha, 0x5048,
+                           "CT pass-through-%s error "
                            "comp_status-status=0x%x total_byte = 0x%x.\n",
-                           vha->host_no, type, comp_status,
-                           bsg_job->reply->reply_payload_rcv_len));
+                           type, comp_status,
+                           bsg_job->reply->reply_payload_rcv_len);
                } else {
-                       DEBUG2(qla_printk(KERN_WARNING, ha,
-                           "scsi(%ld): CT pass-through-%s error "
-                           "comp_status-status=0x%x.\n",
-                           vha->host_no, type, comp_status));
+                       ql_log(ql_log_warn, vha, 0x5049,
+                           "CT pass-through-%s error "
+                           "comp_status-status=0x%x.\n", type, comp_status);
                        bsg_job->reply->result = DID_ERROR << 16;
                        bsg_job->reply->reply_payload_rcv_len = 0;
                }
-               DEBUG2(qla2x00_dump_buffer((uint8_t *)pkt, sizeof(*pkt)));
+               ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5058,
+                   (uint8_t *)pkt, sizeof(*pkt));
        } else {
                bsg_job->reply->result =  DID_OK << 16;
                bsg_job->reply->reply_payload_rcv_len =
@@ -1110,9 +1090,8 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
                type = "ct pass-through";
                break;
        default:
-               qla_printk(KERN_WARNING, ha,
-                   "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp,
-                   sp_bsg->type);
+               ql_log(ql_log_warn, vha, 0x503e,
+                   "Unrecognized SRB: (%p) type=%d.\n", sp, sp_bsg->type);
                return;
        }
 
@@ -1132,27 +1111,31 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
                        bsg_job->reply->reply_payload_rcv_len =
                                le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->total_byte_count);
 
-                       DEBUG2(qla_printk(KERN_WARNING, ha,
-                           "scsi(%ld:0x%x): ELS-CT pass-through-%s error comp_status-status=0x%x "
+                       ql_log(ql_log_info, vha, 0x503f,
+                           "ELS-CT pass-through-%s error comp_status-status=0x%x "
                            "error subcode 1=0x%x error subcode 2=0x%x total_byte = 0x%x.\n",
-                               vha->host_no, sp->handle, type, comp_status, fw_status[1], fw_status[2],
-                               le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->total_byte_count)));
+                           type, comp_status, fw_status[1], fw_status[2],
+                           le16_to_cpu(((struct els_sts_entry_24xx *)
+                               pkt)->total_byte_count));
                        fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply);
                        memcpy( fw_sts_ptr, fw_status, sizeof(fw_status));
                }
                else {
-                       DEBUG2(qla_printk(KERN_WARNING, ha,
-                           "scsi(%ld:0x%x): ELS-CT pass-through-%s error comp_status-status=0x%x "
+                       ql_log(ql_log_info, vha, 0x5040,
+                           "ELS-CT pass-through-%s error comp_status-status=0x%x "
                            "error subcode 1=0x%x error subcode 2=0x%x.\n",
-                               vha->host_no, sp->handle, type, comp_status,
-                               le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_1),
-                               le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_2)));
+                           type, comp_status,
+                           le16_to_cpu(((struct els_sts_entry_24xx *)
+                               pkt)->error_subcode_1),
+                           le16_to_cpu(((struct els_sts_entry_24xx *)
+                                   pkt)->error_subcode_2));
                        bsg_job->reply->result = DID_ERROR << 16;
                        bsg_job->reply->reply_payload_rcv_len = 0;
                        fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply);
                        memcpy( fw_sts_ptr, fw_status, sizeof(fw_status));
                }
-               DEBUG2(qla2x00_dump_buffer((uint8_t *)pkt, sizeof(*pkt)));
+               ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5056,
+                               (uint8_t *)pkt, sizeof(*pkt));
        }
        else {
                bsg_job->reply->result =  DID_OK << 16;
@@ -1201,25 +1184,24 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
        data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ?
                QLA_LOGIO_LOGIN_RETRIED : 0;
        if (logio->entry_status) {
-               DEBUG2(printk(KERN_WARNING
-                   "scsi(%ld:%x): Async-%s error entry - "
+               ql_log(ql_log_warn, vha, 0x5034,
+                   "Async-%s error entry - "
                    "portid=%02x%02x%02x entry-status=%x.\n",
-                   fcport->vha->host_no, sp->handle, type,
-                   fcport->d_id.b.domain, fcport->d_id.b.area,
-                   fcport->d_id.b.al_pa, logio->entry_status));
-               DEBUG2(qla2x00_dump_buffer((uint8_t *)logio, sizeof(*logio)));
+                   type, fcport->d_id.b.domain, fcport->d_id.b.area,
+                   fcport->d_id.b.al_pa, logio->entry_status);
+               ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5059,
+                   (uint8_t *)logio, sizeof(*logio));
 
                goto logio_done;
        }
 
        if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) {
-               DEBUG2(printk(KERN_DEBUG
-                   "scsi(%ld:%x): Async-%s complete - portid=%02x%02x%02x "
+               ql_dbg(ql_dbg_async, vha, 0x5036,
+                   "Async-%s complete - portid=%02x%02x%02x "
                    "iop0=%x.\n",
-                   fcport->vha->host_no, sp->handle, type,
-                   fcport->d_id.b.domain, fcport->d_id.b.area,
+                   type, fcport->d_id.b.domain, fcport->d_id.b.area,
                    fcport->d_id.b.al_pa,
-                   le32_to_cpu(logio->io_parameter[0])));
+                   le32_to_cpu(logio->io_parameter[0]));
 
                data[0] = MBS_COMMAND_COMPLETE;
                if (ctx->type != SRB_LOGIN_CMD)
@@ -1256,14 +1238,14 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
                break;
        }
 
-       DEBUG2(printk(KERN_WARNING
-           "scsi(%ld:%x): Async-%s failed - portid=%02x%02x%02x comp=%x "
+       ql_dbg(ql_dbg_async, vha, 0x5037,
+           "Async-%s failed - portid=%02x%02x%02x comp=%x "
            "iop0=%x iop1=%x.\n",
-           fcport->vha->host_no, sp->handle, type, fcport->d_id.b.domain,
+           type, fcport->d_id.b.domain,
            fcport->d_id.b.area, fcport->d_id.b.al_pa,
            le16_to_cpu(logio->comp_status),
            le32_to_cpu(logio->io_parameter[0]),
-           le32_to_cpu(logio->io_parameter[1])));
+           le32_to_cpu(logio->io_parameter[1]));
 
 logio_done:
        lio->done(sp);
@@ -1292,38 +1274,34 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
        fcport = sp->fcport;
 
        if (sts->entry_status) {
-               DEBUG2(printk(KERN_WARNING
-                   "scsi(%ld:%x): Async-%s error - entry-status(%x).\n",
-                   fcport->vha->host_no, sp->handle, type,
-                   sts->entry_status));
+               ql_log(ql_log_warn, vha, 0x5038,
+                   "Async-%s error - entry-status(%x).\n",
+                   type, sts->entry_status);
        } else if (sts->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) {
-               DEBUG2(printk(KERN_WARNING
-                   "scsi(%ld:%x): Async-%s error - completion status(%x).\n",
-                   fcport->vha->host_no, sp->handle, type,
-                   sts->comp_status));
+               ql_log(ql_log_warn, vha, 0x5039,
+                   "Async-%s error - completion status(%x).\n",
+                   type, sts->comp_status);
        } else if (!(le16_to_cpu(sts->scsi_status) &
            SS_RESPONSE_INFO_LEN_VALID)) {
-               DEBUG2(printk(KERN_WARNING
-                   "scsi(%ld:%x): Async-%s error - no response info(%x).\n",
-                   fcport->vha->host_no, sp->handle, type,
-                   sts->scsi_status));
+               ql_log(ql_log_warn, vha, 0x503a,
+                   "Async-%s error - no response info(%x).\n",
+                   type, sts->scsi_status);
        } else if (le32_to_cpu(sts->rsp_data_len) < 4) {
-               DEBUG2(printk(KERN_WARNING
-                   "scsi(%ld:%x): Async-%s error - not enough response(%d).\n",
-                   fcport->vha->host_no, sp->handle, type,
-                   sts->rsp_data_len));
+               ql_log(ql_log_warn, vha, 0x503b,
+                   "Async-%s error - not enough response(%d).\n",
+                   type, sts->rsp_data_len);
        } else if (sts->data[3]) {
-               DEBUG2(printk(KERN_WARNING
-                   "scsi(%ld:%x): Async-%s error - response(%x).\n",
-                   fcport->vha->host_no, sp->handle, type,
-                   sts->data[3]));
+               ql_log(ql_log_warn, vha, 0x503c,
+                   "Async-%s error - response(%x).\n",
+                   type, sts->data[3]);
        } else {
                error = 0;
        }
 
        if (error) {
                iocb->u.tmf.data = error;
-               DEBUG2(qla2x00_dump_buffer((uint8_t *)sts, sizeof(*sts)));
+               ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5055,
+                   (uint8_t *)sts, sizeof(*sts));
        }
 
        iocb->done(sp);
@@ -1360,8 +1338,8 @@ qla2x00_process_response_queue(struct rsp_que *rsp)
                }
 
                if (pkt->entry_status != 0) {
-                       DEBUG3(printk(KERN_INFO
-                           "scsi(%ld): Process error entry.\n", vha->host_no));
+                       ql_log(ql_log_warn, vha, 0x5035,
+                           "Process error entry.\n");
 
                        qla2x00_error_entry(vha, rsp, pkt);
                        ((response_t *)pkt)->signature = RESPONSE_PROCESSED;
@@ -1399,10 +1377,10 @@ qla2x00_process_response_queue(struct rsp_que *rsp)
                        break;
                default:
                        /* Type Not Supported. */
-                       DEBUG4(printk(KERN_WARNING
-                           "scsi(%ld): Received unknown response pkt type %x "
+                       ql_log(ql_log_warn, vha, 0x504a,
+                           "Received unknown response pkt type %x "
                            "entry status=%x.\n",
-                           vha->host_no, pkt->entry_type, pkt->entry_status));
+                           pkt->entry_type, pkt->entry_status);
                        break;
                }
                ((response_t *)pkt)->signature = RESPONSE_PROCESSED;
@@ -1418,6 +1396,7 @@ static inline void
 qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len,
     uint32_t sense_len, struct rsp_que *rsp)
 {
+       struct scsi_qla_host *vha = sp->fcport->vha;
        struct scsi_cmnd *cp = sp->cmd;
 
        if (sense_len >= SCSI_SENSE_BUFFERSIZE)
@@ -1435,11 +1414,13 @@ qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len,
        if (sp->request_sense_length != 0)
                rsp->status_srb = sp;
 
-       DEBUG5(printk("%s(): Check condition Sense data, scsi(%ld:%d:%d:%d) "
-           "cmd=%p\n", __func__, sp->fcport->vha->host_no,
-           cp->device->channel, cp->device->id, cp->device->lun, cp));
+       ql_dbg(ql_dbg_io, vha, 0x301c,
+           "Check condition Sense data, scsi(%ld:%d:%d:%d) cmd=%p.\n",
+           sp->fcport->vha->host_no, cp->device->channel, cp->device->id,
+           cp->device->lun, cp);
        if (sense_len)
-               DEBUG5(qla2x00_dump_buffer(cp->sense_buffer, sense_len));
+               ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302b,
+                   cp->sense_buffer, sense_len);
 }
 
 struct scsi_dif_tuple {
@@ -1457,6 +1438,7 @@ struct scsi_dif_tuple {
 static inline void
 qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24)
 {
+       struct scsi_qla_host *vha = sp->fcport->vha;
        struct scsi_cmnd *cmd = sp->cmd;
        struct scsi_dif_tuple   *ep =
                        (struct scsi_dif_tuple *)&sts24->data[20];
@@ -1473,15 +1455,15 @@ qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24)
        e_guard = be16_to_cpu(ep->guard);
        a_guard = be16_to_cpu(ap->guard);
 
-       DEBUG18(printk(KERN_DEBUG
-           "%s(): iocb(s) %p Returned STATUS\n", __func__, sts24));
+       ql_dbg(ql_dbg_io, vha, 0x3023,
+           "iocb(s) %p Returned STATUS.\n", sts24);
 
-       DEBUG18(printk(KERN_ERR "DIF ERROR in cmd 0x%x lba 0x%llx act ref"
+       ql_dbg(ql_dbg_io, vha, 0x3024,
+           "DIF ERROR in cmd 0x%x lba 0x%llx act ref"
            " tag=0x%x, exp ref_tag=0x%x, act app tag=0x%x, exp app"
-           " tag=0x%x, act guard=0x%x, exp guard=0x%x\n",
+           " tag=0x%x, act guard=0x%x, exp guard=0x%x.\n",
            cmd->cmnd[0], (u64)scsi_get_lba(cmd), a_ref_tag, e_ref_tag,
-           a_app_tag, e_app_tag, a_guard, e_guard));
-
+           a_app_tag, e_app_tag, a_guard, e_guard);
 
        /* check guard */
        if (e_guard != a_guard) {
@@ -1569,9 +1551,8 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                sp = NULL;
 
        if (sp == NULL) {
-               qla_printk(KERN_WARNING, ha,
-                   "scsi(%ld): Invalid status handle (0x%x).\n", vha->host_no,
-                   sts->handle);
+               ql_log(ql_log_warn, vha, 0x3017,
+                   "Invalid status handle (0x%x).\n", sts->handle);
 
                if (IS_QLA82XX(ha))
                        set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
@@ -1582,9 +1563,9 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
        }
        cp = sp->cmd;
        if (cp == NULL) {
-               qla_printk(KERN_WARNING, ha,
-                   "scsi(%ld): Command already returned (0x%x/%p).\n",
-                   vha->host_no, sts->handle, sp);
+               ql_log(ql_log_warn, vha, 0x3018,
+                   "Command already returned (0x%x/%p).\n",
+                   sts->handle, sp);
 
                return;
        }
@@ -1629,10 +1610,9 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                        par_sense_len -= rsp_info_len;
                }
                if (rsp_info_len > 3 && rsp_info[3]) {
-                       DEBUG2(qla_printk(KERN_INFO, ha,
-                           "scsi(%ld:%d:%d): FCP I/O protocol failure "
-                           "(0x%x/0x%x).\n", vha->host_no, cp->device->id,
-                           cp->device->lun, rsp_info_len, rsp_info[3]));
+                       ql_log(ql_log_warn, vha, 0x3019,
+                           "FCP I/O protocol failure (0x%x/0x%x).\n",
+                           rsp_info_len, rsp_info[3]);
 
                        cp->result = DID_BUS_BUSY << 16;
                        goto out;
@@ -1661,11 +1641,10 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                        if (!lscsi_status &&
                            ((unsigned)(scsi_bufflen(cp) - resid) <
                             cp->underflow)) {
-                               qla_printk(KERN_INFO, ha,
-                                   "scsi(%ld:%d:%d): Mid-layer underflow "
+                               ql_log(ql_log_warn, vha, 0x301a,
+                                   "Mid-layer underflow "
                                    "detected (0x%x of 0x%x bytes).\n",
-                                   vha->host_no, cp->device->id,
-                                   cp->device->lun, resid, scsi_bufflen(cp));
+                                   resid, scsi_bufflen(cp));
 
                                cp->result = DID_ERROR << 16;
                                break;
@@ -1674,9 +1653,8 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                cp->result = DID_OK << 16 | lscsi_status;
 
                if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
-                       DEBUG2(qla_printk(KERN_INFO, ha,
-                           "scsi(%ld:%d:%d) QUEUE FULL detected.\n",
-                           vha->host_no, cp->device->id, cp->device->lun));
+                       ql_log(ql_log_warn, vha, 0x301b,
+                           "QUEUE FULL detected.\n");
                        break;
                }
                logit = 0;
@@ -1697,11 +1675,10 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                scsi_set_resid(cp, resid);
                if (scsi_status & SS_RESIDUAL_UNDER) {
                        if (IS_FWI2_CAPABLE(ha) && fw_resid_len != resid_len) {
-                               DEBUG2(qla_printk(KERN_INFO, ha,
-                                   "scsi(%ld:%d:%d) Dropped frame(s) detected "
-                                   "(0x%x of 0x%x bytes).\n", vha->host_no,
-                                   cp->device->id, cp->device->lun, resid,
-                                   scsi_bufflen(cp)));
+                               ql_log(ql_log_warn, vha, 0x301d,
+                                   "Dropped frame(s) detected "
+                                   "(0x%x of 0x%x bytes).\n",
+                                   resid, scsi_bufflen(cp));
 
                                cp->result = DID_ERROR << 16 | lscsi_status;
                                break;
@@ -1710,20 +1687,18 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                        if (!lscsi_status &&
                            ((unsigned)(scsi_bufflen(cp) - resid) <
                            cp->underflow)) {
-                               qla_printk(KERN_INFO, ha,
-                                   "scsi(%ld:%d:%d): Mid-layer underflow "
+                               ql_log(ql_log_warn, vha, 0x301e,
+                                   "Mid-layer underflow "
                                    "detected (0x%x of 0x%x bytes).\n",
-                                   vha->host_no, cp->device->id,
-                                   cp->device->lun, resid, scsi_bufflen(cp));
+                                   resid, scsi_bufflen(cp));
 
                                cp->result = DID_ERROR << 16;
                                break;
                        }
                } else {
-                       DEBUG2(qla_printk(KERN_INFO, ha,
-                           "scsi(%ld:%d:%d) Dropped frame(s) detected (0x%x "
-                           "of 0x%x bytes).\n", vha->host_no, cp->device->id,
-                           cp->device->lun, resid, scsi_bufflen(cp)));
+                       ql_log(ql_log_warn, vha, 0x301f,
+                           "Dropped frame(s) detected (0x%x "
+                           "of 0x%x bytes).\n", resid, scsi_bufflen(cp));
 
                        cp->result = DID_ERROR << 16 | lscsi_status;
                        goto check_scsi_status;
@@ -1739,10 +1714,8 @@ check_scsi_status:
                 */
                if (lscsi_status != 0) {
                        if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
-                               DEBUG2(qla_printk(KERN_INFO, ha,
-                                   "scsi(%ld:%d:%d) QUEUE FULL detected.\n",
-                                   vha->host_no, cp->device->id,
-                                   cp->device->lun));
+                               ql_log(ql_log_warn, vha, 0x3020,
+                                   "QUEUE FULL detected.\n");
                                logit = 1;
                                break;
                        }
@@ -1781,10 +1754,9 @@ check_scsi_status:
                                break;
                }
 
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                       "scsi(%ld:%d:%d) Port down status: port-state=0x%x\n",
-                       vha->host_no, cp->device->id, cp->device->lun,
-                       atomic_read(&fcport->state)));
+               ql_dbg(ql_dbg_io, vha, 0x3021,
+                   "Port down status: port-state=0x%x.\n",
+                   atomic_read(&fcport->state));
 
                if (atomic_read(&fcport->state) == FCS_ONLINE)
                        qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
@@ -1804,15 +1776,13 @@ check_scsi_status:
 
 out:
        if (logit)
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                   "scsi(%ld:%d:%d) FCP command status: 0x%x-0x%x (0x%x) "
-                   "portid=%02x%02x%02x oxid=0x%x cdb=%02x%02x%02x len=0x%x "
-                   "rsp_info=0x%x resid=0x%x fw_resid=0x%x\n", vha->host_no,
-                   cp->device->id, cp->device->lun, comp_status, scsi_status,
-                   cp->result, fcport->d_id.b.domain, fcport->d_id.b.area,
-                   fcport->d_id.b.al_pa, ox_id, cp->cmnd[0], cp->cmnd[1],
-                   cp->cmnd[2], scsi_bufflen(cp), rsp_info_len, resid_len,
-                   fw_resid_len));
+               ql_dbg(ql_dbg_io, vha, 0x3022,
+                   "FCP command status: 0x%x-0x%x (0x%x) "
+                   "oxid=0x%x cdb=%02x%02x%02x len=0x%x "
+                   "rsp_info=0x%x resid=0x%x fw_resid=0x%x.\n",
+                   comp_status, scsi_status, cp->result, ox_id, cp->cmnd[0],
+                   cp->cmnd[1], cp->cmnd[2], scsi_bufflen(cp), rsp_info_len,
+                   resid_len, fw_resid_len);
 
        if (rsp->status_srb == NULL)
                qla2x00_sp_compl(ha, sp);
@@ -1830,16 +1800,15 @@ qla2x00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt)
 {
        uint8_t         sense_sz = 0;
        struct qla_hw_data *ha = rsp->hw;
+       struct scsi_qla_host *vha = pci_get_drvdata(ha->pdev);
        srb_t           *sp = rsp->status_srb;
        struct scsi_cmnd *cp;
 
        if (sp != NULL && sp->request_sense_length != 0) {
                cp = sp->cmd;
                if (cp == NULL) {
-                       DEBUG2(printk("%s(): Cmd already returned back to OS "
-                           "sp=%p.\n", __func__, sp));
-                       qla_printk(KERN_INFO, ha,
-                           "cmd is NULL: already returned to OS (sp=%p)\n",
+                       ql_log(ql_log_warn, vha, 0x3025,
+                           "cmd is NULL: already returned to OS (sp=%p).\n",
                            sp);
 
                        rsp->status_srb = NULL;
@@ -1856,7 +1825,8 @@ qla2x00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt)
                if (IS_FWI2_CAPABLE(ha))
                        host_to_fcp_swap(pkt->data, sizeof(pkt->data));
                memcpy(sp->request_sense_ptr, pkt->data, sense_sz);
-               DEBUG5(qla2x00_dump_buffer(sp->request_sense_ptr, sense_sz));
+               ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302c,
+                       sp->request_sense_ptr, sense_sz);
 
                sp->request_sense_ptr += sense_sz;
                sp->request_sense_length -= sense_sz;
@@ -1882,21 +1852,25 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
        uint32_t handle = LSW(pkt->handle);
        uint16_t que = MSW(pkt->handle);
        struct req_que *req = ha->req_q_map[que];
-#if defined(QL_DEBUG_LEVEL_2)
+
        if (pkt->entry_status & RF_INV_E_ORDER)
-               qla_printk(KERN_ERR, ha, "%s: Invalid Entry Order\n", __func__);
+               ql_dbg(ql_dbg_async, vha, 0x502a,
+                   "Invalid Entry Order.\n");
        else if (pkt->entry_status & RF_INV_E_COUNT)
-               qla_printk(KERN_ERR, ha, "%s: Invalid Entry Count\n", __func__);
+               ql_dbg(ql_dbg_async, vha, 0x502b,
+                   "Invalid Entry Count.\n");
        else if (pkt->entry_status & RF_INV_E_PARAM)
-               qla_printk(KERN_ERR, ha,
-                   "%s: Invalid Entry Parameter\n", __func__);
+               ql_dbg(ql_dbg_async, vha, 0x502c,
+                   "Invalid Entry Parameter.\n");
        else if (pkt->entry_status & RF_INV_E_TYPE)
-               qla_printk(KERN_ERR, ha, "%s: Invalid Entry Type\n", __func__);
+               ql_dbg(ql_dbg_async, vha, 0x502d,
+                   "Invalid Entry Type.\n");
        else if (pkt->entry_status & RF_BUSY)
-               qla_printk(KERN_ERR, ha, "%s: Busy\n", __func__);
+               ql_dbg(ql_dbg_async, vha, 0x502e,
+                   "Busy.\n");
        else
-               qla_printk(KERN_ERR, ha, "%s: UNKNOWN flag error\n", __func__);
-#endif
+               ql_dbg(ql_dbg_async, vha, 0x502f,
+                   "UNKNOWN flag error.\n");
 
        /* Validate handle. */
        if (handle < MAX_OUTSTANDING_COMMANDS)
@@ -1923,10 +1897,8 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
        } else if (pkt->entry_type == COMMAND_A64_TYPE || pkt->entry_type ==
                COMMAND_TYPE || pkt->entry_type == COMMAND_TYPE_7
                || pkt->entry_type == COMMAND_TYPE_6) {
-               DEBUG2(printk("scsi(%ld): Error entry - invalid handle\n",
-                       vha->host_no));
-               qla_printk(KERN_WARNING, ha,
-                       "Error entry - invalid handle\n");
+               ql_log(ql_log_warn, vha, 0x5030,
+                   "Error entry - invalid handle.\n");
 
                if (IS_QLA82XX(ha))
                        set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
@@ -1960,11 +1932,11 @@ qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
        }
 
        if (ha->mcp) {
-               DEBUG3(printk("%s(%ld): Got mailbox completion. cmd=%x.\n",
-                   __func__, vha->host_no, ha->mcp->mb[0]));
+               ql_dbg(ql_dbg_async, vha, 0x504d,
+                   "Got mailbox completion. cmd=%x.\n", ha->mcp->mb[0]);
        } else {
-               DEBUG2_3(printk("%s(%ld): MBX pointer ERROR!\n",
-                   __func__, vha->host_no));
+               ql_dbg(ql_dbg_async, vha, 0x504e,
+                   "MBX pointer ERROR.\n");
        }
 }
 
@@ -1993,8 +1965,8 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
                }
 
                if (pkt->entry_status != 0) {
-                       DEBUG3(printk(KERN_INFO
-                           "scsi(%ld): Process error entry.\n", vha->host_no));
+                       ql_dbg(ql_dbg_async, vha, 0x5029,
+                           "Process error entry.\n");
 
                        qla2x00_error_entry(vha, rsp, (sts_entry_t *) pkt);
                        ((response_t *)pkt)->signature = RESPONSE_PROCESSED;
@@ -2030,10 +2002,10 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
                        break;
                default:
                        /* Type Not Supported. */
-                       DEBUG4(printk(KERN_WARNING
-                           "scsi(%ld): Received unknown response pkt type %x "
+                       ql_dbg(ql_dbg_async, vha, 0x5042,
+                           "Received unknown response pkt type %x "
                            "entry status=%x.\n",
-                           vha->host_no, pkt->entry_type, pkt->entry_status));
+                           pkt->entry_type, pkt->entry_status);
                        break;
                }
                ((response_t *)pkt)->signature = RESPONSE_PROCESSED;
@@ -2088,7 +2060,8 @@ qla2xxx_check_risc_status(scsi_qla_host_t *vha)
 
 next_test:
        if (RD_REG_DWORD(&reg->iobase_c8) & BIT_3)
-               qla_printk(KERN_INFO, ha, "Additional code -- 0x55AA.\n");
+               ql_log(ql_log_info, vha, 0x504c,
+                   "Additional code -- 0x55AA.\n");
 
 done:
        WRT_REG_DWORD(&reg->iobase_window, 0x0000);
@@ -2121,7 +2094,7 @@ qla24xx_intr_handler(int irq, void *dev_id)
        rsp = (struct rsp_que *) dev_id;
        if (!rsp) {
                printk(KERN_INFO
-                   "%s(): NULL response queue pointer\n", __func__);
+                   "%s(): NULL response queue pointer.\n", __func__);
                return IRQ_NONE;
        }
 
@@ -2142,8 +2115,9 @@ qla24xx_intr_handler(int irq, void *dev_id)
 
                        hccr = RD_REG_DWORD(&reg->hccr);
 
-                       qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
-                           "Dumping firmware!\n", hccr);
+                       ql_log(ql_log_warn, vha, 0x504b,
+                           "RISC paused -- HCCR=%x, Dumping firmware.\n",
+                           hccr);
 
                        qla2xxx_check_risc_status(vha);
 
@@ -2174,9 +2148,8 @@ qla24xx_intr_handler(int irq, void *dev_id)
                        qla24xx_process_response_queue(vha, rsp);
                        break;
                default:
-                       DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
-                           "(%d).\n",
-                           vha->host_no, stat & 0xff));
+                       ql_dbg(ql_dbg_async, vha, 0x504f,
+                           "Unrecognized interrupt type (%d).\n", stat * 0xff);
                        break;
                }
                WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
@@ -2205,7 +2178,7 @@ qla24xx_msix_rsp_q(int irq, void *dev_id)
        rsp = (struct rsp_que *) dev_id;
        if (!rsp) {
                printk(KERN_INFO
-               "%s(): NULL response queue pointer\n", __func__);
+               "%s(): NULL response queue pointer.\n", __func__);
                return IRQ_NONE;
        }
        ha = rsp->hw;
@@ -2235,7 +2208,7 @@ qla25xx_msix_rsp_q(int irq, void *dev_id)
        rsp = (struct rsp_que *) dev_id;
        if (!rsp) {
                printk(KERN_INFO
-                       "%s(): NULL response queue pointer\n", __func__);
+                       "%s(): NULL response queue pointer.\n", __func__);
                return IRQ_NONE;
        }
        ha = rsp->hw;
@@ -2268,8 +2241,8 @@ qla24xx_msix_default(int irq, void *dev_id)
 
        rsp = (struct rsp_que *) dev_id;
        if (!rsp) {
-               DEBUG(printk(
-               "%s(): NULL response queue pointer\n", __func__));
+               printk(KERN_INFO
+                       "%s(): NULL response queue pointer.\n", __func__);
                return IRQ_NONE;
        }
        ha = rsp->hw;
@@ -2286,8 +2259,9 @@ qla24xx_msix_default(int irq, void *dev_id)
 
                        hccr = RD_REG_DWORD(&reg->hccr);
 
-                       qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
-                           "Dumping firmware!\n", hccr);
+                       ql_log(ql_log_info, vha, 0x5050,
+                           "RISC paused -- HCCR=%x, Dumping firmware.\n",
+                           hccr);
 
                        qla2xxx_check_risc_status(vha);
 
@@ -2318,9 +2292,8 @@ qla24xx_msix_default(int irq, void *dev_id)
                        qla24xx_process_response_queue(vha, rsp);
                        break;
                default:
-                       DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
-                           "(%d).\n",
-                           vha->host_no, stat & 0xff));
+                       ql_dbg(ql_dbg_async, vha, 0x5051,
+                           "Unrecognized interrupt type (%d).\n", stat & 0xff);
                        break;
                }
                WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
@@ -2358,6 +2331,7 @@ qla24xx_disable_msix(struct qla_hw_data *ha)
 {
        int i;
        struct qla_msix_entry *qentry;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        for (i = 0; i < ha->msix_count; i++) {
                qentry = &ha->msix_entries[i];
@@ -2368,6 +2342,8 @@ qla24xx_disable_msix(struct qla_hw_data *ha)
        kfree(ha->msix_entries);
        ha->msix_entries = NULL;
        ha->flags.msix_enabled = 0;
+       ql_dbg(ql_dbg_init, vha, 0x0042,
+           "Disabled the MSI.\n");
 }
 
 static int
@@ -2377,11 +2353,15 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
        int i, ret;
        struct msix_entry *entries;
        struct qla_msix_entry *qentry;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        entries = kzalloc(sizeof(struct msix_entry) * ha->msix_count,
                        GFP_KERNEL);
-       if (!entries)
+       if (!entries) {
+               ql_log(ql_log_warn, vha, 0x00bc,
+                   "Failed to allocate memory for msix_entry.\n");
                return -ENOMEM;
+       }
 
        for (i = 0; i < ha->msix_count; i++)
                entries[i].entry = i;
@@ -2391,16 +2371,18 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
                if (ret < MIN_MSIX_COUNT)
                        goto msix_failed;
 
-               qla_printk(KERN_WARNING, ha,
-                       "MSI-X: Failed to enable support -- %d/%d\n"
-                       " Retry with %d vectors\n", ha->msix_count, ret, ret);
+               ql_log(ql_log_warn, vha, 0x00c6,
+                   "MSI-X: Failed to enable support "
+                   "-- %d/%d\n Retry with %d vectors.\n",
+                   ha->msix_count, ret, ret);
                ha->msix_count = ret;
                ret = pci_enable_msix(ha->pdev, entries, ha->msix_count);
                if (ret) {
 msix_failed:
-                       qla_printk(KERN_WARNING, ha, "MSI-X: Failed to enable"
-                               " support, giving up -- %d/%d\n",
-                               ha->msix_count, ret);
+                       ql_log(ql_log_fatal, vha, 0x00c7,
+                           "MSI-X: Failed to enable support, "
+                           "giving   up -- %d/%d.\n",
+                           ha->msix_count, ret);
                        goto msix_out;
                }
                ha->max_rsp_queues = ha->msix_count - 1;
@@ -2408,6 +2390,8 @@ msix_failed:
        ha->msix_entries = kzalloc(sizeof(struct qla_msix_entry) *
                                ha->msix_count, GFP_KERNEL);
        if (!ha->msix_entries) {
+               ql_log(ql_log_fatal, vha, 0x00c8,
+                   "Failed to allocate memory for ha->msix_entries.\n");
                ret = -ENOMEM;
                goto msix_out;
        }
@@ -2434,9 +2418,9 @@ msix_failed:
                                0, msix_entries[i].name, rsp);
                }
                if (ret) {
-                       qla_printk(KERN_WARNING, ha,
-                       "MSI-X: Unable to register handler -- %x/%d.\n",
-                       qentry->vector, ret);
+                       ql_log(ql_log_fatal, vha, 0x00cb,
+                           "MSI-X: unable to register handler -- %x/%d.\n",
+                           qentry->vector, ret);
                        qla24xx_disable_msix(ha);
                        ha->mqenable = 0;
                        goto msix_out;
@@ -2449,6 +2433,12 @@ msix_failed:
        /* Enable MSI-X vector for response queue update for queue 0 */
        if (ha->mqiobase &&  (ha->max_rsp_queues > 1 || ha->max_req_queues > 1))
                ha->mqenable = 1;
+       ql_dbg(ql_dbg_multiq, vha, 0xc005,
+           "mqiobase=%p, max_rsp_queues=%d, max_req_queues=%d.\n",
+           ha->mqiobase, ha->max_rsp_queues, ha->max_req_queues);
+       ql_dbg(ql_dbg_init, vha, 0x0055,
+           "mqiobase=%p, max_rsp_queues=%d, max_req_queues=%d.\n",
+           ha->mqiobase, ha->max_rsp_queues, ha->max_req_queues);
 
 msix_out:
        kfree(entries);
@@ -2460,6 +2450,7 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
 {
        int ret;
        device_reg_t __iomem *reg = ha->iobase;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        /* If possible, enable MSI-X. */
        if (!IS_QLA2432(ha) && !IS_QLA2532(ha) &&
@@ -2470,30 +2461,30 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
                (ha->pdev->subsystem_device == 0x7040 ||
                ha->pdev->subsystem_device == 0x7041 ||
                ha->pdev->subsystem_device == 0x1705)) {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-                       "MSI-X: Unsupported ISP2432 SSVID/SSDID (0x%X,0x%X).\n",
+               ql_log(ql_log_warn, vha, 0x0034,
+                   "MSI-X: Unsupported ISP 2432 SSVID/SSDID (0x%X,0x%X).\n",
                        ha->pdev->subsystem_vendor,
-                       ha->pdev->subsystem_device));
+                       ha->pdev->subsystem_device);
                goto skip_msi;
        }
 
        if (IS_QLA2432(ha) && (ha->pdev->revision < QLA_MSIX_CHIP_REV_24XX ||
                !QLA_MSIX_FW_MODE_1(ha->fw_attributes))) {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-               "MSI-X: Unsupported ISP2432 (0x%X, 0x%X).\n",
-                       ha->pdev->revision, ha->fw_attributes));
+               ql_log(ql_log_warn, vha, 0x0035,
+                   "MSI-X; Unsupported ISP2432 (0x%X, 0x%X).\n",
+                   ha->pdev->revision, ha->fw_attributes);
                goto skip_msix;
        }
 
        ret = qla24xx_enable_msix(ha, rsp);
        if (!ret) {
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                   "MSI-X: Enabled (0x%X, 0x%X).\n", ha->chip_revision,
-                   ha->fw_attributes));
+               ql_dbg(ql_dbg_init, vha, 0x0036,
+                   "MSI-X: Enabled (0x%X, 0x%X).\n",
+                   ha->chip_revision, ha->fw_attributes);
                goto clear_risc_ints;
        }
-       qla_printk(KERN_WARNING, ha,
-           "MSI-X: Falling back-to MSI mode -- %d.\n", ret);
+       ql_log(ql_log_info, vha, 0x0037,
+           "MSI-X Falling back-to MSI mode -%d.\n", ret);
 skip_msix:
 
        if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
@@ -2502,18 +2493,19 @@ skip_msix:
 
        ret = pci_enable_msi(ha->pdev);
        if (!ret) {
-               DEBUG2(qla_printk(KERN_INFO, ha, "MSI: Enabled.\n"));
+               ql_dbg(ql_dbg_init, vha, 0x0038,
+                   "MSI: Enabled.\n");
                ha->flags.msi_enabled = 1;
        } else
-               qla_printk(KERN_WARNING, ha,
-                   "MSI-X: Falling back-to INTa mode -- %d.\n", ret);
+               ql_log(ql_log_warn, vha, 0x0039,
+                   "MSI-X; Falling back-to INTa mode -- %d.\n", ret);
 skip_msi:
 
        ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,
            ha->flags.msi_enabled ? 0 : IRQF_SHARED,
            QLA2XXX_DRIVER_NAME, rsp);
        if (ret) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x003a,
                    "Failed to reserve interrupt %d already in use.\n",
                    ha->pdev->irq);
                goto fail;
@@ -2563,13 +2555,14 @@ int qla25xx_request_irq(struct rsp_que *rsp)
        struct qla_hw_data *ha = rsp->hw;
        struct qla_init_msix_entry *intr = &msix_entries[2];
        struct qla_msix_entry *msix = rsp->msix;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
        int ret;
 
        ret = request_irq(msix->vector, intr->handler, 0, intr->name, rsp);
        if (ret) {
-               qla_printk(KERN_WARNING, ha,
-                       "MSI-X: Unable to register handler -- %x/%d.\n",
-                       msix->vector, ret);
+               ql_log(ql_log_fatal, vha, 0x00e6,
+                   "MSI-X: Unable to register handler -- %x/%d.\n",
+                   msix->vector, ret);
                return ret;
        }
        msix->have_irq = 1;
index c26f0ac..f7604ea 100644 (file)
@@ -46,14 +46,18 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
        struct qla_hw_data *ha = vha->hw;
        scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
 
-       if (ha->pdev->error_state > pci_channel_io_frozen)
+       ql_dbg(ql_dbg_mbx, base_vha, 0x1000, "Entered %s.\n", __func__);
+
+       if (ha->pdev->error_state > pci_channel_io_frozen) {
+               ql_log(ql_log_warn, base_vha, 0x1001,
+                   "error_state is greater than pci_channel_io_frozen, "
+                   "exiting.\n");
                return QLA_FUNCTION_TIMEOUT;
+       }
 
        if (vha->device_flags & DFLG_DEV_FAILED) {
-               DEBUG2_3_11(qla_printk(KERN_WARNING, ha,
-                       "%s(%ld): Device in failed state, "
-                       "timeout MBX Exiting.\n",
-                       __func__, base_vha->host_no));
+               ql_log(ql_log_warn, base_vha, 0x1002,
+                   "Device in failed state, exiting.\n");
                return QLA_FUNCTION_TIMEOUT;
        }
 
@@ -63,17 +67,18 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
        rval = QLA_SUCCESS;
        abort_active = test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, base_vha->host_no));
 
        if (ha->flags.pci_channel_io_perm_failure) {
-               DEBUG(printk("%s(%ld): Perm failure on EEH, timeout MBX "
-                            "Exiting.\n", __func__, vha->host_no));
+               ql_log(ql_log_warn, base_vha, 0x1003,
+                   "Perm failure on EEH timeout MBX, exiting.\n");
                return QLA_FUNCTION_TIMEOUT;
        }
 
        if (ha->flags.isp82xx_fw_hung) {
                /* Setting Link-Down error */
                mcp->mb[0] = MBS_LINK_DOWN_ERROR;
+               ql_log(ql_log_warn, base_vha, 0x1004,
+                   "FW hung = %d.\n", ha->flags.isp82xx_fw_hung);
                rval = QLA_FUNCTION_FAILED;
                goto premature_exit;
        }
@@ -85,8 +90,8 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
         */
        if (!wait_for_completion_timeout(&ha->mbx_cmd_comp, mcp->tov * HZ)) {
                /* Timeout occurred. Return error. */
-               DEBUG2_3_11(printk("%s(%ld): cmd access timeout. "
-                   "Exiting.\n", __func__, base_vha->host_no));
+               ql_log(ql_log_warn, base_vha, 0x1005,
+                   "Cmd access timeout, Exiting.\n");
                return QLA_FUNCTION_TIMEOUT;
        }
 
@@ -94,8 +99,8 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
        /* Save mailbox command for debug */
        ha->mcp = mcp;
 
-       DEBUG11(printk("scsi(%ld): prepare to issue mbox cmd=0x%x.\n",
-           base_vha->host_no, mcp->mb[0]));
+       ql_dbg(ql_dbg_mbx, base_vha, 0x1006,
+           "Prepare to issue mbox cmd=0x%x.\n", mcp->mb[0]);
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
 
@@ -123,27 +128,30 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
                iptr++;
        }
 
-#if defined(QL_DEBUG_LEVEL_1)
-       printk("%s(%ld): Loaded MBX registers (displayed in bytes) = \n",
-           __func__, base_vha->host_no);
-       qla2x00_dump_buffer((uint8_t *)mcp->mb, 16);
-       printk("\n");
-       qla2x00_dump_buffer(((uint8_t *)mcp->mb + 0x10), 16);
-       printk("\n");
-       qla2x00_dump_buffer(((uint8_t *)mcp->mb + 0x20), 8);
-       printk("\n");
-       printk("%s(%ld): I/O address = %p.\n", __func__, base_vha->host_no,
-               optr);
-       qla2x00_dump_regs(base_vha);
-#endif
+       ql_dbg(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x1111,
+           "Loaded MBX registers (displayed in bytes) =.\n");
+       ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x1112,
+           (uint8_t *)mcp->mb, 16);
+       ql_dbg(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x1113,
+           ".\n");
+       ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x1114,
+           ((uint8_t *)mcp->mb + 0x10), 16);
+       ql_dbg(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x1115,
+           ".\n");
+       ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x1116,
+           ((uint8_t *)mcp->mb + 0x20), 8);
+       ql_dbg(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x1117,
+           "I/O Address = %p.\n", optr);
+       ql_dump_regs(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x100e);
 
        /* Issue set host interrupt command to send cmd out. */
        ha->flags.mbox_int = 0;
        clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
 
        /* Unlock mbx registers and wait for interrupt */
-       DEBUG11(printk("%s(%ld): going to unlock irq & waiting for interrupt. "
-           "jiffies=%lx.\n", __func__, base_vha->host_no, jiffies));
+       ql_dbg(ql_dbg_mbx, base_vha, 0x100f,
+           "Going to unlock irq & waiting for interrupts. "
+           "jiffies=%lx.\n", jiffies);
 
        /* Wait for mbx cmd completion until timeout */
 
@@ -155,9 +163,8 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
                                HINT_MBX_INT_PENDING) {
                                spin_unlock_irqrestore(&ha->hardware_lock,
                                        flags);
-                               DEBUG2_3_11(printk(KERN_INFO
-                                   "%s(%ld): Pending Mailbox timeout. "
-                                   "Exiting.\n", __func__, base_vha->host_no));
+                               ql_dbg(ql_dbg_mbx, base_vha, 0x1010,
+                                   "Pending mailbox timeout, exiting.\n");
                                rval = QLA_FUNCTION_TIMEOUT;
                                goto premature_exit;
                        }
@@ -173,17 +180,16 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
                clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
 
        } else {
-               DEBUG3_11(printk("%s(%ld): cmd=%x POLLING MODE.\n", __func__,
-                   base_vha->host_no, command));
+               ql_dbg(ql_dbg_mbx, base_vha, 0x1011,
+                   "Cmd=%x Polling Mode.\n", command);
 
                if (IS_QLA82XX(ha)) {
                        if (RD_REG_DWORD(&reg->isp82.hint) &
                                HINT_MBX_INT_PENDING) {
                                spin_unlock_irqrestore(&ha->hardware_lock,
                                        flags);
-                               DEBUG2_3_11(printk(KERN_INFO
-                                   "%s(%ld): Pending Mailbox timeout. "
-                                   "Exiting.\n", __func__, base_vha->host_no));
+                               ql_dbg(ql_dbg_mbx, base_vha, 0x1012,
+                                   "Pending mailbox timeout, exiting.\n");
                                rval = QLA_FUNCTION_TIMEOUT;
                                goto premature_exit;
                        }
@@ -207,17 +213,17 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
                            command == MBC_LOAD_RISC_RAM_EXTENDED))
                                msleep(10);
                } /* while */
-               DEBUG17(qla_printk(KERN_WARNING, ha,
-                       "Waited %d sec\n",
-                       (uint)((jiffies - (wait_time - (mcp->tov * HZ)))/HZ)));
+               ql_dbg(ql_dbg_mbx, base_vha, 0x1013,
+                   "Waited %d sec.\n",
+                   (uint)((jiffies - (wait_time - (mcp->tov * HZ)))/HZ));
        }
 
        /* Check whether we timed out */
        if (ha->flags.mbox_int) {
                uint16_t *iptr2;
 
-               DEBUG3_11(printk("%s(%ld): cmd %x completed.\n", __func__,
-                   base_vha->host_no, command));
+               ql_dbg(ql_dbg_mbx, base_vha, 0x1014,
+                   "Cmd=%x completed.\n", command);
 
                /* Got interrupt. Clear the flag. */
                ha->flags.mbox_int = 0;
@@ -229,6 +235,8 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
                        mcp->mb[0] = MBS_LINK_DOWN_ERROR;
                        ha->mcp = NULL;
                        rval = QLA_FUNCTION_FAILED;
+                       ql_log(ql_log_warn, base_vha, 0x1015,
+                           "FW hung = %d.\n", ha->flags.isp82xx_fw_hung);
                        goto premature_exit;
                }
 
@@ -249,8 +257,6 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
                }
        } else {
 
-#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) || \
-               defined(QL_DEBUG_LEVEL_11)
                uint16_t mb0;
                uint32_t ictrl;
 
@@ -261,14 +267,13 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
                        mb0 = RD_MAILBOX_REG(ha, &reg->isp, 0);
                        ictrl = RD_REG_WORD(&reg->isp.ictrl);
                }
-               printk("%s(%ld): **** MB Command Timeout for cmd %x ****\n",
-                   __func__, base_vha->host_no, command);
-               printk("%s(%ld): icontrol=%x jiffies=%lx\n", __func__,
-                   base_vha->host_no, ictrl, jiffies);
-               printk("%s(%ld): *** mailbox[0] = 0x%x ***\n", __func__,
-                   base_vha->host_no, mb0);
-               qla2x00_dump_regs(base_vha);
-#endif
+               ql_dbg(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x1119,
+                   "MBX Command timeout for cmd %x.\n", command);
+               ql_dbg(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x111a,
+                   "iocontrol=%x jiffies=%lx.\n", ictrl, jiffies);
+               ql_dbg(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x111b,
+                   "mb[0] = 0x%x.\n", mb0);
+               ql_dump_regs(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x1019);
 
                rval = QLA_FUNCTION_TIMEOUT;
        }
@@ -279,8 +284,8 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
        ha->mcp = NULL;
 
        if ((abort_active || !io_lock_on) && !IS_NOPOLLING_TYPE(ha)) {
-               DEBUG11(printk("%s(%ld): checking for additional resp "
-                   "interrupt.\n", __func__, base_vha->host_no));
+               ql_dbg(ql_dbg_mbx, base_vha, 0x101a,
+                   "Checking for additional resp interrupt.\n");
 
                /* polling mode for non isp_abort commands. */
                qla2x00_poll(ha->rsp_q_map[0]);
@@ -291,38 +296,32 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
                if (!io_lock_on || (mcp->flags & IOCTL_CMD) ||
                    ha->flags.eeh_busy) {
                        /* not in dpc. schedule it for dpc to take over. */
-                       DEBUG(printk("%s(%ld): timeout schedule "
-                       "isp_abort_needed.\n", __func__,
-                       base_vha->host_no));
-                       DEBUG2_3_11(printk("%s(%ld): timeout schedule "
-                       "isp_abort_needed.\n", __func__,
-                       base_vha->host_no));
+                       ql_dbg(ql_dbg_mbx, base_vha, 0x101b,
+                           "Timeout, schedule isp_abort_needed.\n");
 
                        if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) &&
                            !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) &&
                            !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
 
-                               qla_printk(KERN_WARNING, ha,
-                                   "Mailbox command timeout occurred. "
-                                   "Scheduling ISP " "abort. eeh_busy: 0x%x\n",
-                                   ha->flags.eeh_busy);
+                               ql_log(ql_log_info, base_vha, 0x101c,
+                                   "Mailbox cmd timeout occured. "
+                                   "Scheduling ISP abort eeh_busy=0x%x.\n",
+                                       ha->flags.eeh_busy);
                                set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                                qla2xxx_wake_dpc(vha);
                        }
                } else if (!abort_active) {
                        /* call abort directly since we are in the DPC thread */
-                       DEBUG(printk("%s(%ld): timeout calling abort_isp\n",
-                           __func__, base_vha->host_no));
-                       DEBUG2_3_11(printk("%s(%ld): timeout calling "
-                           "abort_isp\n", __func__, base_vha->host_no));
+                       ql_dbg(ql_dbg_mbx, base_vha, 0x101d,
+                           "Timeout, calling abort_isp.\n");
 
                        if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) &&
                            !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) &&
                            !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
 
-                               qla_printk(KERN_WARNING, ha,
-                                   "Mailbox command timeout occurred. "
-                                   "Issuing ISP abort.\n");
+                               ql_log(ql_log_info, base_vha, 0x101e,
+                                   "Mailbox cmd timeout occured. "
+                                   "Scheduling ISP abort.\n");
 
                                set_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags);
                                clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
@@ -332,11 +331,8 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
                                            &vha->dpc_flags);
                                }
                                clear_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags);
-                               DEBUG(printk("%s(%ld): finished abort_isp\n",
-                                   __func__, vha->host_no));
-                               DEBUG2_3_11(printk(
-                                   "%s(%ld): finished abort_isp\n",
-                                   __func__, vha->host_no));
+                               ql_dbg(ql_dbg_mbx, base_vha, 0x101f,
+                                   "Finished abort_isp.\n");
                        }
                }
        }
@@ -346,12 +342,11 @@ premature_exit:
        complete(&ha->mbx_cmd_comp);
 
        if (rval) {
-               DEBUG2_3_11(printk("%s(%ld): **** FAILED. mbx0=%x, mbx1=%x, "
-                   "mbx2=%x, cmd=%x ****\n", __func__, base_vha->host_no,
-                   mcp->mb[0], mcp->mb[1], mcp->mb[2], command));
+               ql_dbg(ql_dbg_mbx, base_vha, 0x1020,
+                   "**** Failed mbx[0]=%x, mb[1]=%x, mb[2]=%x, cmd=%x ****.\n",
+                   mcp->mb[0], mcp->mb[1], mcp->mb[2], command);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__,
-               base_vha->host_no));
+               ql_dbg(ql_dbg_mbx, base_vha, 0x1021, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -366,7 +361,7 @@ qla2x00_load_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t risc_addr,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1022, "Entered %s.\n", __func__);
 
        if (MSW(risc_addr) || IS_FWI2_CAPABLE(ha)) {
                mcp->mb[0] = MBC_LOAD_RISC_RAM_EXTENDED;
@@ -397,10 +392,10 @@ qla2x00_load_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t risc_addr,
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x.\n", __func__,
-                   vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x1023,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1024, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -430,7 +425,7 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1025, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_EXECUTE_FIRMWARE;
        mcp->out_mb = MBX_0;
@@ -461,15 +456,14 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x.\n", __func__,
-                   vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x1026,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
                if (IS_FWI2_CAPABLE(ha)) {
-                       DEBUG11(printk("%s(%ld): done exchanges=%x.\n",
-                           __func__, vha->host_no, mcp->mb[1]));
+                       ql_dbg(ql_dbg_mbx, vha, 0x1027,
+                           "Done exchanges=%x.\n", mcp->mb[1]);
                } else {
-                       DEBUG11(printk("%s(%ld): done.\n", __func__,
-                           vha->host_no));
+                       ql_dbg(ql_dbg_mbx, vha, 0x1028, "Done %s.\n", __func__);
                }
        }
 
@@ -501,7 +495,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha, uint16_t *major, uint16_t *minor,
        mbx_cmd_t       mc;
        mbx_cmd_t       *mcp = &mc;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1029, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_GET_FIRMWARE_VERSION;
        mcp->out_mb = MBX_0;
@@ -535,11 +529,10 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha, uint16_t *major, uint16_t *minor,
 failed:
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x102a, "Failed=%x.\n", rval);
        } else {
                /*EMPTY*/
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x102b, "Done %s.\n", __func__);
        }
        return rval;
 }
@@ -565,7 +558,7 @@ qla2x00_get_fw_options(scsi_qla_host_t *vha, uint16_t *fwopts)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x102c, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_GET_FIRMWARE_OPTION;
        mcp->out_mb = MBX_0;
@@ -576,15 +569,14 @@ qla2x00_get_fw_options(scsi_qla_host_t *vha, uint16_t *fwopts)
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x102d, "Failed=%x.\n", rval);
        } else {
                fwopts[0] = mcp->mb[0];
                fwopts[1] = mcp->mb[1];
                fwopts[2] = mcp->mb[2];
                fwopts[3] = mcp->mb[3];
 
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x102e, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -612,7 +604,7 @@ qla2x00_set_fw_options(scsi_qla_host_t *vha, uint16_t *fwopts)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x102f, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_SET_FIRMWARE_OPTION;
        mcp->mb[1] = fwopts[1];
@@ -636,11 +628,11 @@ qla2x00_set_fw_options(scsi_qla_host_t *vha, uint16_t *fwopts)
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("%s(%ld): failed=%x (%x/%x).\n", __func__,
-                   vha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x1030,
+                   "Failed=%x (%x/%x).\n", rval, mcp->mb[0], mcp->mb[1]);
        } else {
                /*EMPTY*/
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1031, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -668,7 +660,7 @@ qla2x00_mbx_reg_test(scsi_qla_host_t *vha)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("qla2x00_mbx_reg_test(%ld): entered.\n", vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1032, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_MAILBOX_REGISTER_TEST;
        mcp->mb[1] = 0xAAAA;
@@ -695,12 +687,10 @@ qla2x00_mbx_reg_test(scsi_qla_host_t *vha)
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("qla2x00_mbx_reg_test(%ld): failed=%x.\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x1033, "Failed=%x.\n", rval);
        } else {
                /*EMPTY*/
-               DEBUG11(printk("qla2x00_mbx_reg_test(%ld): done.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1034, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -728,7 +718,7 @@ qla2x00_verify_checksum(scsi_qla_host_t *vha, uint32_t risc_addr)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1035, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_VERIFY_CHECKSUM;
        mcp->out_mb = MBX_0;
@@ -749,11 +739,11 @@ qla2x00_verify_checksum(scsi_qla_host_t *vha, uint32_t risc_addr)
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x chk sum=%x.\n", __func__,
-                   vha->host_no, rval, IS_FWI2_CAPABLE(vha->hw) ?
-                   (mcp->mb[2] << 16) | mcp->mb[1]: mcp->mb[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x1036,
+                   "Failed=%x chm sum=%x.\n", rval, IS_FWI2_CAPABLE(vha->hw) ?
+                   (mcp->mb[2] << 16) | mcp->mb[1] : mcp->mb[1]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1037, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -785,6 +775,8 @@ qla2x00_issue_iocb_timeout(scsi_qla_host_t *vha, void *buffer,
        mbx_cmd_t       mc;
        mbx_cmd_t       *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x1038, "Entered %s.\n", __func__);
+
        mcp->mb[0] = MBC_IOCB_COMMAND_A64;
        mcp->mb[1] = 0;
        mcp->mb[2] = MSW(phys_addr);
@@ -799,14 +791,14 @@ qla2x00_issue_iocb_timeout(scsi_qla_host_t *vha, void *buffer,
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG(printk("qla2x00_issue_iocb(%ld): failed rval 0x%x\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x1039, "Failed=%x.\n", rval);
        } else {
                sts_entry_t *sts_entry = (sts_entry_t *) buffer;
 
                /* Mask reserved bits. */
                sts_entry->entry_status &=
                    IS_FWI2_CAPABLE(vha->hw) ? RF_MASK_24XX : RF_MASK;
+               ql_dbg(ql_dbg_mbx, vha, 0x103a, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -847,7 +839,7 @@ qla2x00_abort_command(srb_t *sp)
        struct qla_hw_data *ha = vha->hw;
        struct req_que *req = vha->req;
 
-       DEBUG11(printk("qla2x00_abort_command(%ld): entered.\n", vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x103b, "Entered %s.\n", __func__);
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
        for (handle = 1; handle < MAX_OUTSTANDING_COMMANDS; handle++) {
@@ -876,11 +868,9 @@ qla2x00_abort_command(srb_t *sp)
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("qla2x00_abort_command(%ld): failed=%x.\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x103c, "Failed=%x.\n", rval);
        } else {
-               DEBUG11(printk("qla2x00_abort_command(%ld): done.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x103d, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -896,10 +886,11 @@ qla2x00_abort_target(struct fc_port *fcport, unsigned int l, int tag)
        struct req_que *req;
        struct rsp_que *rsp;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->vha->host_no));
-
        l = l;
        vha = fcport->vha;
+
+       ql_dbg(ql_dbg_mbx, vha, 0x103e, "Entered %s.\n", __func__);
+
        req = vha->hw->req_q_map[0];
        rsp = req->rsp;
        mcp->mb[0] = MBC_ABORT_TARGET;
@@ -919,18 +910,17 @@ qla2x00_abort_target(struct fc_port *fcport, unsigned int l, int tag)
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(vha, mcp);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x103f, "Failed=%x.\n", rval);
        }
 
        /* Issue marker IOCB. */
        rval2 = qla2x00_marker(vha, req, rsp, fcport->loop_id, 0,
                                                        MK_SYNC_ID);
        if (rval2 != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed to issue Marker IOCB "
-                   "(%x).\n", __func__, vha->host_no, rval2));
+               ql_dbg(ql_dbg_mbx, vha, 0x1040,
+                   "Failed to issue marker IOCB (%x).\n", rval2);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1041, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -946,9 +936,10 @@ qla2x00_lun_reset(struct fc_port *fcport, unsigned int l, int tag)
        struct req_que *req;
        struct rsp_que *rsp;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->vha->host_no));
-
        vha = fcport->vha;
+
+       ql_dbg(ql_dbg_mbx, vha, 0x1042, "Entered %s.\n", __func__);
+
        req = vha->hw->req_q_map[0];
        rsp = req->rsp;
        mcp->mb[0] = MBC_LUN_RESET;
@@ -966,18 +957,17 @@ qla2x00_lun_reset(struct fc_port *fcport, unsigned int l, int tag)
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(vha, mcp);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x1043, "Failed=%x.\n", rval);
        }
 
        /* Issue marker IOCB. */
        rval2 = qla2x00_marker(vha, req, rsp, fcport->loop_id, l,
                                                                MK_SYNC_ID_LUN);
        if (rval2 != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed to issue Marker IOCB "
-                   "(%x).\n", __func__, vha->host_no, rval2));
+               ql_dbg(ql_dbg_mbx, vha, 0x1044,
+                   "Failed to issue marker IOCB (%x).\n", rval2);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1045, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -1011,8 +1001,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("qla2x00_get_adapter_id(%ld): entered.\n",
-           vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1046, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_GET_ADAPTER_LOOP_ID;
        mcp->mb[9] = vha->vp_idx;
@@ -1038,11 +1027,9 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa,
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("qla2x00_get_adapter_id(%ld): failed=%x.\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x1047, "Failed=%x.\n", rval);
        } else {
-               DEBUG11(printk("qla2x00_get_adapter_id(%ld): done.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1048, "Done %s.\n", __func__);
 
                if (IS_QLA8XXX_TYPE(vha->hw)) {
                        vha->fcoe_vlan_id = mcp->mb[9] & 0xfff;
@@ -1083,8 +1070,7 @@ qla2x00_get_retry_cnt(scsi_qla_host_t *vha, uint8_t *retry_cnt, uint8_t *tov,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("qla2x00_get_retry_cnt(%ld): entered.\n",
-                       vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1049, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_GET_RETRY_COUNT;
        mcp->out_mb = MBX_0;
@@ -1095,8 +1081,8 @@ qla2x00_get_retry_cnt(scsi_qla_host_t *vha, uint8_t *retry_cnt, uint8_t *tov,
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("qla2x00_get_retry_cnt(%ld): failed = %x.\n",
-                   vha->host_no, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x104a,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
                /* Convert returned data and check our values. */
                *r_a_tov = mcp->mb[3] / 2;
@@ -1107,8 +1093,8 @@ qla2x00_get_retry_cnt(scsi_qla_host_t *vha, uint8_t *retry_cnt, uint8_t *tov,
                        *tov = ratov;
                }
 
-               DEBUG11(printk("qla2x00_get_retry_cnt(%ld): done. mb3=%d "
-                   "ratov=%d.\n", vha->host_no, mcp->mb[3], ratov));
+               ql_dbg(ql_dbg_mbx, vha, 0x104b,
+                   "Done %s mb3=%d ratov=%d.\n", __func__, mcp->mb[3], ratov);
        }
 
        return rval;
@@ -1139,8 +1125,7 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size)
        mbx_cmd_t *mcp = &mc;
        struct qla_hw_data *ha = vha->hw;
 
-       DEBUG11(printk("qla2x00_init_firmware(%ld): entered.\n",
-           vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x104c, "Entered %s.\n", __func__);
 
        if (IS_QLA82XX(ha) && ql2xdbwr)
                qla82xx_wr_32(ha, ha->nxdb_wr_ptr,
@@ -1174,13 +1159,11 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size)
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("qla2x00_init_firmware(%ld): failed=%x "
-                   "mb0=%x.\n",
-                   vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x104d,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
                /*EMPTY*/
-               DEBUG11(printk("qla2x00_init_firmware(%ld): done.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x104e, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -1213,13 +1196,13 @@ qla2x00_get_port_database(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t opt)
        dma_addr_t pd_dma;
        struct qla_hw_data *ha = vha->hw;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x104f, "Entered %s.\n", __func__);
 
        pd24 = NULL;
        pd = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &pd_dma);
        if (pd  == NULL) {
-               DEBUG2_3(printk("%s(%ld): failed to allocate Port Database "
-                   "structure.\n", __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x1050,
+                   "Failed to allocate port database structure.\n");
                return QLA_MEMORY_ALLOC_FAILED;
        }
        memset(pd, 0, max(PORT_DATABASE_SIZE, PORT_DATABASE_24XX_SIZE));
@@ -1261,12 +1244,10 @@ qla2x00_get_port_database(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t opt)
                /* Check for logged in state. */
                if (pd24->current_login_state != PDS_PRLI_COMPLETE &&
                    pd24->last_login_state != PDS_PRLI_COMPLETE) {
-                       DEBUG2(qla_printk(KERN_WARNING, ha,
-                          "scsi(%ld): Unable to verify login-state (%x/%x) "
-                          " - portid=%02x%02x%02x.\n", vha->host_no,
-                          pd24->current_login_state, pd24->last_login_state,
-                          fcport->d_id.b.domain, fcport->d_id.b.area,
-                          fcport->d_id.b.al_pa));
+                       ql_dbg(ql_dbg_mbx, vha, 0x1051,
+                           "Unable to verify login-state (%x/%x) for "
+                           "loop_id %x.\n", pd24->current_login_state,
+                           pd24->last_login_state, fcport->loop_id);
                        rval = QLA_FUNCTION_FAILED;
                        goto gpd_error_out;
                }
@@ -1290,12 +1271,11 @@ qla2x00_get_port_database(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t opt)
                /* Check for logged in state. */
                if (pd->master_state != PD_STATE_PORT_LOGGED_IN &&
                    pd->slave_state != PD_STATE_PORT_LOGGED_IN) {
-                       DEBUG2(qla_printk(KERN_WARNING, ha,
-                          "scsi(%ld): Unable to verify login-state (%x/%x) "
-                          " - portid=%02x%02x%02x.\n", vha->host_no,
-                          pd->master_state, pd->slave_state,
-                          fcport->d_id.b.domain, fcport->d_id.b.area,
-                          fcport->d_id.b.al_pa));
+                       ql_dbg(ql_dbg_mbx, vha, 0x100a,
+                           "Unable to verify login-state (%x/%x) - "
+                           "portid=%02x%02x%02x.\n", pd->master_state,
+                           pd->slave_state, fcport->d_id.b.domain,
+                           fcport->d_id.b.area, fcport->d_id.b.al_pa);
                        rval = QLA_FUNCTION_FAILED;
                        goto gpd_error_out;
                }
@@ -1325,10 +1305,11 @@ gpd_error_out:
        dma_pool_free(ha->s_dma_pool, pd, pd_dma);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
-                   __func__, vha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x1052,
+                   "Failed=%x mb[0]=%x mb[1]=%x.\n", rval,
+                   mcp->mb[0], mcp->mb[1]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1053, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -1357,8 +1338,7 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("qla2x00_get_firmware_state(%ld): entered.\n",
-           vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1054, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_GET_FIRMWARE_STATE;
        mcp->out_mb = MBX_0;
@@ -1381,12 +1361,10 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states)
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("qla2x00_get_firmware_state(%ld): "
-                   "failed=%x.\n", vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x1055, "Failed=%x.\n", rval);
        } else {
                /*EMPTY*/
-               DEBUG11(printk("qla2x00_get_firmware_state(%ld): done.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1056, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -1418,8 +1396,7 @@ qla2x00_get_port_name(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t *name,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("qla2x00_get_port_name(%ld): entered.\n",
-           vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1057, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_GET_PORT_NAME;
        mcp->mb[9] = vha->vp_idx;
@@ -1439,8 +1416,7 @@ qla2x00_get_port_name(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t *name,
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("qla2x00_get_port_name(%ld): failed=%x.\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x1058, "Failed=%x.\n", rval);
        } else {
                if (name != NULL) {
                        /* This function returns name in big endian. */
@@ -1454,8 +1430,7 @@ qla2x00_get_port_name(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t *name,
                        name[7] = LSB(mcp->mb[7]);
                }
 
-               DEBUG11(printk("qla2x00_get_port_name(%ld): done.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1059, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -1483,7 +1458,7 @@ qla2x00_lip_reset(scsi_qla_host_t *vha)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x105a, "Entered %s.\n", __func__);
 
        if (IS_QLA8XXX_TYPE(vha->hw)) {
                /* Logout across all FCFs. */
@@ -1517,11 +1492,10 @@ qla2x00_lip_reset(scsi_qla_host_t *vha)
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n",
-                   __func__, vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x105b, "Failed=%x.\n", rval);
        } else {
                /*EMPTY*/
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x105c, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -1553,12 +1527,11 @@ qla2x00_send_sns(scsi_qla_host_t *vha, dma_addr_t sns_phys_address,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("qla2x00_send_sns(%ld): entered.\n",
-           vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x105d, "Entered %s.\n", __func__);
 
-       DEBUG11(printk("qla2x00_send_sns: retry cnt=%d ratov=%d total "
-               "tov=%d.\n", vha->hw->retry_count, vha->hw->login_timeout,
-               mcp->tov));
+       ql_dbg(ql_dbg_mbx, vha, 0x105e,
+           "Retry cnt=%d ratov=%d total tov=%d.\n",
+           vha->hw->retry_count, vha->hw->login_timeout, mcp->tov);
 
        mcp->mb[0] = MBC_SEND_SNS_COMMAND;
        mcp->mb[1] = cmd_size;
@@ -1575,13 +1548,12 @@ qla2x00_send_sns(scsi_qla_host_t *vha, dma_addr_t sns_phys_address,
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG(printk("qla2x00_send_sns(%ld): failed=%x mb[0]=%x "
-                   "mb[1]=%x.\n", vha->host_no, rval, mcp->mb[0], mcp->mb[1]));
-               DEBUG2_3_11(printk("qla2x00_send_sns(%ld): failed=%x mb[0]=%x "
-                   "mb[1]=%x.\n", vha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x105f,
+                   "Failed=%x mb[0]=%x mb[1]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1]);
        } else {
                /*EMPTY*/
-               DEBUG11(printk("qla2x00_send_sns(%ld): done.\n", vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1060, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -1600,7 +1572,7 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
        struct req_que *req;
        struct rsp_que *rsp;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1061, "Entered %s.\n", __func__);
 
        if (ha->flags.cpu_affinity_enabled)
                req = ha->req_q_map[0];
@@ -1610,8 +1582,8 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
 
        lg = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma);
        if (lg == NULL) {
-               DEBUG2_3(printk("%s(%ld): failed to allocate Login IOCB.\n",
-                   __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x1062,
+                   "Failed to allocate login IOCB.\n");
                return QLA_MEMORY_ALLOC_FAILED;
        }
        memset(lg, 0, sizeof(struct logio_entry_24xx));
@@ -1631,21 +1603,21 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
        lg->vp_index = vha->vp_idx;
        rval = qla2x00_issue_iocb(vha, lg, lg_dma, 0);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed to issue Login IOCB "
-                   "(%x).\n", __func__, vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x1063,
+                   "Failed to issue login IOCB (%x).\n", rval);
        } else if (lg->entry_status != 0) {
-               DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
-                   "-- error status (%x).\n", __func__, vha->host_no,
-                   lg->entry_status));
+               ql_dbg(ql_dbg_mbx, vha, 0x1064,
+                   "Failed to complete IOCB -- error status (%x).\n",
+                   lg->entry_status);
                rval = QLA_FUNCTION_FAILED;
        } else if (lg->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) {
                iop[0] = le32_to_cpu(lg->io_parameter[0]);
                iop[1] = le32_to_cpu(lg->io_parameter[1]);
 
-               DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
-                   "-- completion status (%x)  ioparam=%x/%x.\n", __func__,
-                   vha->host_no, le16_to_cpu(lg->comp_status), iop[0],
-                   iop[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x1065,
+                   "Failed to complete IOCB -- completion  status (%x) "
+                   "ioparam=%x/%x.\n", le16_to_cpu(lg->comp_status),
+                   iop[0], iop[1]);
 
                switch (iop[0]) {
                case LSC_SCODE_PORTID_USED:
@@ -1673,7 +1645,7 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
                        break;
                }
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1066, "Done %s.\n", __func__);
 
                iop[0] = le32_to_cpu(lg->io_parameter[0]);
 
@@ -1728,7 +1700,7 @@ qla2x00_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
        mbx_cmd_t *mcp = &mc;
        struct qla_hw_data *ha = vha->hw;
 
-       DEBUG11(printk("qla2x00_login_fabric(%ld): entered.\n", vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1067, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_LOGIN_FABRIC_PORT;
        mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0;
@@ -1771,13 +1743,12 @@ qla2x00_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
                        rval = QLA_SUCCESS;
 
                /*EMPTY*/
-               DEBUG2_3_11(printk("qla2x00_login_fabric(%ld): failed=%x "
-                   "mb[0]=%x mb[1]=%x mb[2]=%x.\n", vha->host_no, rval,
-                   mcp->mb[0], mcp->mb[1], mcp->mb[2]));
+               ql_dbg(ql_dbg_mbx, vha, 0x1068,
+                   "Failed=%x mb[0]=%x mb[1]=%x mb[2]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1], mcp->mb[2]);
        } else {
                /*EMPTY*/
-               DEBUG11(printk("qla2x00_login_fabric(%ld): done.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1069, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -1808,13 +1779,13 @@ qla2x00_login_local_device(scsi_qla_host_t *vha, fc_port_t *fcport,
        mbx_cmd_t *mcp = &mc;
        struct qla_hw_data *ha = vha->hw;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x106a, "Entered %s.\n", __func__);
+
        if (IS_FWI2_CAPABLE(ha))
                return qla24xx_login_fabric(vha, fcport->loop_id,
                    fcport->d_id.b.domain, fcport->d_id.b.area,
                    fcport->d_id.b.al_pa, mb_ret, opt);
 
-       DEBUG3(printk("%s(%ld): entered.\n", __func__, vha->host_no));
-
        mcp->mb[0] = MBC_LOGIN_LOOP_PORT;
        if (HAS_EXTENDED_IDS(ha))
                mcp->mb[1] = fcport->loop_id;
@@ -1845,15 +1816,12 @@ qla2x00_login_local_device(scsi_qla_host_t *vha, fc_port_t *fcport,
                if (mcp->mb[0] == 0x4005 || mcp->mb[0] == 0x4006)
                        rval = QLA_SUCCESS;
 
-               DEBUG(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x "
-                   "mb[6]=%x mb[7]=%x.\n", __func__, vha->host_no, rval,
-                   mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7]));
-               DEBUG2_3(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x "
-                   "mb[6]=%x mb[7]=%x.\n", __func__, vha->host_no, rval,
-                   mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7]));
+               ql_dbg(ql_dbg_mbx, vha, 0x106b,
+                   "Failed=%x mb[0]=%x mb[1]=%x mb[6]=%x mb[7]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7]);
        } else {
                /*EMPTY*/
-               DEBUG3(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x106c, "Done %s.\n", __func__);
        }
 
        return (rval);
@@ -1870,12 +1838,12 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
        struct req_que *req;
        struct rsp_que *rsp;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x106d, "Entered %s.\n", __func__);
 
        lg = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma);
        if (lg == NULL) {
-               DEBUG2_3(printk("%s(%ld): failed to allocate Logout IOCB.\n",
-                   __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x106e,
+                   "Failed to allocate logout IOCB.\n");
                return QLA_MEMORY_ALLOC_FAILED;
        }
        memset(lg, 0, sizeof(struct logio_entry_24xx));
@@ -1899,22 +1867,22 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
 
        rval = qla2x00_issue_iocb(vha, lg, lg_dma, 0);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed to issue Logout IOCB "
-                   "(%x).\n", __func__, vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x106f,
+                   "Failed to issue logout IOCB (%x).\n", rval);
        } else if (lg->entry_status != 0) {
-               DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
-                   "-- error status (%x).\n", __func__, vha->host_no,
-                   lg->entry_status));
+               ql_dbg(ql_dbg_mbx, vha, 0x1070,
+                   "Failed to complete IOCB -- error status (%x).\n",
+                   lg->entry_status);
                rval = QLA_FUNCTION_FAILED;
        } else if (lg->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) {
-               DEBUG2_3_11(printk("%s(%ld %d): failed to complete IOCB "
-                   "-- completion status (%x)  ioparam=%x/%x.\n", __func__,
-                   vha->host_no, vha->vp_idx, le16_to_cpu(lg->comp_status),
+               ql_dbg(ql_dbg_mbx, vha, 0x1071,
+                   "Failed to complete IOCB -- completion status (%x) "
+                   "ioparam=%x/%x.\n", le16_to_cpu(lg->comp_status),
                    le32_to_cpu(lg->io_parameter[0]),
-                   le32_to_cpu(lg->io_parameter[1])));
+                   le32_to_cpu(lg->io_parameter[1]));
        } else {
                /*EMPTY*/
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1072, "Done %s.\n", __func__);
        }
 
        dma_pool_free(ha->s_dma_pool, lg, lg_dma);
@@ -1946,8 +1914,7 @@ qla2x00_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("qla2x00_fabric_logout(%ld): entered.\n",
-           vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1073, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_LOGOUT_FABRIC_PORT;
        mcp->out_mb = MBX_1|MBX_0;
@@ -1966,12 +1933,11 @@ qla2x00_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("qla2x00_fabric_logout(%ld): failed=%x "
-                   "mbx1=%x.\n", vha->host_no, rval, mcp->mb[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x1074,
+                   "Failed=%x mb[1]=%x.\n", rval, mcp->mb[1]);
        } else {
                /*EMPTY*/
-               DEBUG11(printk("qla2x00_fabric_logout(%ld): done.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1075, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -1999,8 +1965,7 @@ qla2x00_full_login_lip(scsi_qla_host_t *vha)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("qla2x00_full_login_lip(%ld): entered.\n",
-           vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1076, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_LIP_FULL_LOGIN;
        mcp->mb[1] = IS_FWI2_CAPABLE(vha->hw) ? BIT_3 : 0;
@@ -2014,12 +1979,10 @@ qla2x00_full_login_lip(scsi_qla_host_t *vha)
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("qla2x00_full_login_lip(%ld): failed=%x.\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x1077, "Failed=%x.\n", rval);
        } else {
                /*EMPTY*/
-               DEBUG11(printk("qla2x00_full_login_lip(%ld): done.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1078, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -2045,8 +2008,7 @@ qla2x00_get_id_list(scsi_qla_host_t *vha, void *id_list, dma_addr_t id_list_dma,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("qla2x00_get_id_list(%ld): entered.\n",
-           vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1079, "Entered %s.\n", __func__);
 
        if (id_list == NULL)
                return QLA_FUNCTION_FAILED;
@@ -2075,12 +2037,10 @@ qla2x00_get_id_list(scsi_qla_host_t *vha, void *id_list, dma_addr_t id_list_dma,
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("qla2x00_get_id_list(%ld): failed=%x.\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x107a, "Failed=%x.\n", rval);
        } else {
                *entries = mcp->mb[1];
-               DEBUG11(printk("qla2x00_get_id_list(%ld): done.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x107b, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -2108,7 +2068,7 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha, uint16_t *cur_xchg_cnt,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x107c, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_GET_RESOURCE_COUNTS;
        mcp->out_mb = MBX_0;
@@ -2121,14 +2081,14 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha, uint16_t *cur_xchg_cnt,
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("%s(%ld): failed = %x.\n", __func__,
-                   vha->host_no, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x107d,
+                   "Failed mb[0]=%x.\n", mcp->mb[0]);
        } else {
-               DEBUG11(printk("%s(%ld): done. mb1=%x mb2=%x mb3=%x mb6=%x "
-                   "mb7=%x mb10=%x mb11=%x mb12=%x.\n", __func__,
-                   vha->host_no, mcp->mb[1], mcp->mb[2], mcp->mb[3],
-                   mcp->mb[6], mcp->mb[7], mcp->mb[10], mcp->mb[11],
-                   mcp->mb[12]));
+               ql_dbg(ql_dbg_mbx, vha, 0x107e,
+                   "Done %s mb1=%x mb2=%x mb3=%x mb6=%x mb7=%x mb10=%x "
+                   "mb11=%x mb12=%x.\n", __func__, mcp->mb[1], mcp->mb[2],
+                   mcp->mb[3], mcp->mb[6], mcp->mb[7], mcp->mb[10],
+                   mcp->mb[11], mcp->mb[12]);
 
                if (cur_xchg_cnt)
                        *cur_xchg_cnt = mcp->mb[3];
@@ -2147,7 +2107,6 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha, uint16_t *cur_xchg_cnt,
        return (rval);
 }
 
-#if defined(QL_DEBUG_LEVEL_3)
 /*
  * qla2x00_get_fcal_position_map
  *     Get FCAL (LILP) position map using mailbox command
@@ -2172,10 +2131,12 @@ qla2x00_get_fcal_position_map(scsi_qla_host_t *vha, char *pos_map)
        dma_addr_t pmap_dma;
        struct qla_hw_data *ha = vha->hw;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x107f, "Entered %s.\n", __func__);
+
        pmap = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &pmap_dma);
        if (pmap  == NULL) {
-               DEBUG2_3_11(printk("%s(%ld): **** Mem Alloc Failed ****",
-                   __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x1080,
+                   "Memory alloc failed.\n");
                return QLA_MEMORY_ALLOC_FAILED;
        }
        memset(pmap, 0, FCAL_MAP_SIZE);
@@ -2193,10 +2154,11 @@ qla2x00_get_fcal_position_map(scsi_qla_host_t *vha, char *pos_map)
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval == QLA_SUCCESS) {
-               DEBUG11(printk("%s(%ld): (mb0=%x/mb1=%x) FC/AL Position Map "
-                   "size (%x)\n", __func__, vha->host_no, mcp->mb[0],
-                   mcp->mb[1], (unsigned)pmap[0]));
-               DEBUG11(qla2x00_dump_buffer(pmap, pmap[0] + 1));
+               ql_dbg(ql_dbg_mbx, vha, 0x1081,
+                   "mb0/mb1=%x/%X FC/AL position map size (%x).\n",
+                   mcp->mb[0], mcp->mb[1], (unsigned)pmap[0]);
+               ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x111d,
+                   pmap, pmap[0] + 1);
 
                if (pos_map)
                        memcpy(pos_map, pmap, FCAL_MAP_SIZE);
@@ -2204,15 +2166,13 @@ qla2x00_get_fcal_position_map(scsi_qla_host_t *vha, char *pos_map)
        dma_pool_free(ha->s_dma_pool, pmap, pmap_dma);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x1082, "Failed=%x.\n", rval);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1083, "Done %s.\n", __func__);
        }
 
        return rval;
 }
-#endif
 
 /*
  * qla2x00_get_link_status
@@ -2237,7 +2197,7 @@ qla2x00_get_link_status(scsi_qla_host_t *vha, uint16_t loop_id,
        uint32_t *siter, *diter, dwords;
        struct qla_hw_data *ha = vha->hw;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1084, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_GET_LINK_STATUS;
        mcp->mb[2] = MSW(stats_dma);
@@ -2266,11 +2226,12 @@ qla2x00_get_link_status(scsi_qla_host_t *vha, uint16_t loop_id,
 
        if (rval == QLA_SUCCESS) {
                if (mcp->mb[0] != MBS_COMMAND_COMPLETE) {
-                       DEBUG2_3_11(printk("%s(%ld): cmd failed. mbx0=%x.\n",
-                           __func__, vha->host_no, mcp->mb[0]));
+                       ql_dbg(ql_dbg_mbx, vha, 0x1085,
+                           "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
                        rval = QLA_FUNCTION_FAILED;
                } else {
                        /* Copy over data -- firmware data is LE. */
+                       ql_dbg(ql_dbg_mbx, vha, 0x1086, "Done %s.\n", __func__);
                        dwords = offsetof(struct link_statistics, unused1) / 4;
                        siter = diter = &stats->link_fail_cnt;
                        while (dwords--)
@@ -2278,8 +2239,7 @@ qla2x00_get_link_status(scsi_qla_host_t *vha, uint16_t loop_id,
                }
        } else {
                /* Failed. */
-               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x1087, "Failed=%x.\n", rval);
        }
 
        return rval;
@@ -2294,7 +2254,7 @@ qla24xx_get_isp_stats(scsi_qla_host_t *vha, struct link_statistics *stats,
        mbx_cmd_t *mcp = &mc;
        uint32_t *siter, *diter, dwords;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1088, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_GET_LINK_PRIV_STATS;
        mcp->mb[2] = MSW(stats_dma);
@@ -2312,10 +2272,11 @@ qla24xx_get_isp_stats(scsi_qla_host_t *vha, struct link_statistics *stats,
 
        if (rval == QLA_SUCCESS) {
                if (mcp->mb[0] != MBS_COMMAND_COMPLETE) {
-                       DEBUG2_3_11(printk("%s(%ld): cmd failed. mbx0=%x.\n",
-                           __func__, vha->host_no, mcp->mb[0]));
+                       ql_dbg(ql_dbg_mbx, vha, 0x1089,
+                           "Failed mb[0]=%x.\n", mcp->mb[0]);
                        rval = QLA_FUNCTION_FAILED;
                } else {
+                       ql_dbg(ql_dbg_mbx, vha, 0x108a, "Done %s.\n", __func__);
                        /* Copy over data -- firmware data is LE. */
                        dwords = sizeof(struct link_statistics) / 4;
                        siter = diter = &stats->link_fail_cnt;
@@ -2324,8 +2285,7 @@ qla24xx_get_isp_stats(scsi_qla_host_t *vha, struct link_statistics *stats,
                }
        } else {
                /* Failed. */
-               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x108b, "Failed=%x.\n", rval);
        }
 
        return rval;
@@ -2345,7 +2305,7 @@ qla24xx_abort_command(srb_t *sp)
        struct qla_hw_data *ha = vha->hw;
        struct req_que *req = vha->req;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x108c, "Entered %s.\n", __func__);
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
        for (handle = 1; handle < MAX_OUTSTANDING_COMMANDS; handle++) {
@@ -2360,8 +2320,8 @@ qla24xx_abort_command(srb_t *sp)
 
        abt = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &abt_dma);
        if (abt == NULL) {
-               DEBUG2_3(printk("%s(%ld): failed to allocate Abort IOCB.\n",
-                   __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x108d,
+                   "Failed to allocate abort IOCB.\n");
                return QLA_MEMORY_ALLOC_FAILED;
        }
        memset(abt, 0, sizeof(struct abort_entry_24xx));
@@ -2380,20 +2340,20 @@ qla24xx_abort_command(srb_t *sp)
 
        rval = qla2x00_issue_iocb(vha, abt, abt_dma, 0);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed to issue IOCB (%x).\n",
-                   __func__, vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x108e,
+                   "Failed to issue IOCB (%x).\n", rval);
        } else if (abt->entry_status != 0) {
-               DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
-                   "-- error status (%x).\n", __func__, vha->host_no,
-                   abt->entry_status));
+               ql_dbg(ql_dbg_mbx, vha, 0x108f,
+                   "Failed to complete IOCB -- error status (%x).\n",
+                   abt->entry_status);
                rval = QLA_FUNCTION_FAILED;
        } else if (abt->nport_handle != __constant_cpu_to_le16(0)) {
-               DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
-                   "-- completion status (%x).\n", __func__, vha->host_no,
-                   le16_to_cpu(abt->nport_handle)));
+               ql_dbg(ql_dbg_mbx, vha, 0x1090,
+                   "Failed to complete IOCB -- completion status (%x).\n",
+                   le16_to_cpu(abt->nport_handle));
                rval = QLA_FUNCTION_FAILED;
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1091, "Done %s.\n", __func__);
        }
 
        dma_pool_free(ha->s_dma_pool, abt, abt_dma);
@@ -2421,19 +2381,20 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport,
        struct req_que *req;
        struct rsp_que *rsp;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->vha->host_no));
-
        vha = fcport->vha;
        ha = vha->hw;
        req = vha->req;
+
+       ql_dbg(ql_dbg_mbx, vha, 0x1092, "Entered %s.\n", __func__);
+
        if (ha->flags.cpu_affinity_enabled)
                rsp = ha->rsp_q_map[tag + 1];
        else
                rsp = req->rsp;
        tsk = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &tsk_dma);
        if (tsk == NULL) {
-               DEBUG2_3(printk("%s(%ld): failed to allocate Task Management "
-                   "IOCB.\n", __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x1093,
+                   "Failed to allocate task management IOCB.\n");
                return QLA_MEMORY_ALLOC_FAILED;
        }
        memset(tsk, 0, sizeof(struct tsk_mgmt_cmd));
@@ -2457,30 +2418,30 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport,
        sts = &tsk->p.sts;
        rval = qla2x00_issue_iocb(vha, tsk, tsk_dma, 0);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed to issue %s Reset IOCB "
-                   "(%x).\n", __func__, vha->host_no, name, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x1094,
+                   "Failed to issue %s reset IOCB (%x).\n", name, rval);
        } else if (sts->entry_status != 0) {
-               DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
-                   "-- error status (%x).\n", __func__, vha->host_no,
-                   sts->entry_status));
+               ql_dbg(ql_dbg_mbx, vha, 0x1095,
+                   "Failed to complete IOCB -- error status (%x).\n",
+                   sts->entry_status);
                rval = QLA_FUNCTION_FAILED;
        } else if (sts->comp_status !=
            __constant_cpu_to_le16(CS_COMPLETE)) {
-               DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
-                   "-- completion status (%x).\n", __func__,
-                   vha->host_no, le16_to_cpu(sts->comp_status)));
+               ql_dbg(ql_dbg_mbx, vha, 0x1096,
+                   "Failed to complete IOCB -- completion status (%x).\n",
+                   le16_to_cpu(sts->comp_status));
                rval = QLA_FUNCTION_FAILED;
        } else if (le16_to_cpu(sts->scsi_status) &
            SS_RESPONSE_INFO_LEN_VALID) {
                if (le32_to_cpu(sts->rsp_data_len) < 4) {
-                       DEBUG2_3_11(printk("%s(%ld): ignoring inconsistent "
-                           "data length -- not enough response info (%d).\n",
-                           __func__, vha->host_no,
-                           le32_to_cpu(sts->rsp_data_len)));
+                       ql_dbg(ql_dbg_mbx, vha, 0x1097,
+                           "Ignoring inconsistent data length -- not enough "
+                           "response info (%d).\n",
+                           le32_to_cpu(sts->rsp_data_len));
                } else if (sts->data[3]) {
-                       DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
-                           "-- response (%x).\n", __func__,
-                           vha->host_no, sts->data[3]));
+                       ql_dbg(ql_dbg_mbx, vha, 0x1098,
+                           "Failed to complete IOCB -- response (%x).\n",
+                           sts->data[3]);
                        rval = QLA_FUNCTION_FAILED;
                }
        }
@@ -2489,10 +2450,10 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport,
        rval2 = qla2x00_marker(vha, req, rsp, fcport->loop_id, l,
            type == TCF_LUN_RESET ? MK_SYNC_ID_LUN: MK_SYNC_ID);
        if (rval2 != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed to issue Marker IOCB "
-                   "(%x).\n", __func__, vha->host_no, rval2));
+               ql_dbg(ql_dbg_mbx, vha, 0x1099,
+                   "Failed to issue marker IOCB (%x).\n", rval2);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x109a, "Done %s.\n", __func__);
        }
 
        dma_pool_free(ha->s_dma_pool, tsk, tsk_dma);
@@ -2533,7 +2494,7 @@ qla2x00_system_error(scsi_qla_host_t *vha)
        if (!IS_QLA23XX(ha) && !IS_FWI2_CAPABLE(ha))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x109b, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_GEN_SYSTEM_ERROR;
        mcp->out_mb = MBX_0;
@@ -2543,10 +2504,9 @@ qla2x00_system_error(scsi_qla_host_t *vha)
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x109c, "Failed=%x.\n", rval);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x109d, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -2566,7 +2526,7 @@ qla2x00_set_serdes_params(scsi_qla_host_t *vha, uint16_t sw_em_1g,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x109e, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_SERDES_PARAMS;
        mcp->mb[1] = BIT_0;
@@ -2581,11 +2541,11 @@ qla2x00_set_serdes_params(scsi_qla_host_t *vha, uint16_t sw_em_1g,
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
-                   vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x109f,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
                /*EMPTY*/
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10a0, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -2601,7 +2561,7 @@ qla2x00_stop_firmware(scsi_qla_host_t *vha)
        if (!IS_FWI2_CAPABLE(vha->hw))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x10a1, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_STOP_FIRMWARE;
        mcp->out_mb = MBX_0;
@@ -2611,12 +2571,11 @@ qla2x00_stop_firmware(scsi_qla_host_t *vha)
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x10a2, "Failed=%x.\n", rval);
                if (mcp->mb[0] == MBS_INVALID_COMMAND)
                        rval = QLA_INVALID_COMMAND;
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10a3, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -2630,14 +2589,14 @@ qla2x00_enable_eft_trace(scsi_qla_host_t *vha, dma_addr_t eft_dma,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10a4, "Entered %s.\n", __func__);
+
        if (!IS_FWI2_CAPABLE(vha->hw))
                return QLA_FUNCTION_FAILED;
 
        if (unlikely(pci_channel_offline(vha->hw->pdev)))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
-
        mcp->mb[0] = MBC_TRACE_CONTROL;
        mcp->mb[1] = TC_EFT_ENABLE;
        mcp->mb[2] = LSW(eft_dma);
@@ -2652,10 +2611,11 @@ qla2x00_enable_eft_trace(scsi_qla_host_t *vha, dma_addr_t eft_dma,
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(vha, mcp);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
-                   __func__, vha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10a5,
+                   "Failed=%x mb[0]=%x mb[1]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10a6, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -2668,14 +2628,14 @@ qla2x00_disable_eft_trace(scsi_qla_host_t *vha)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10a7, "Entered %s.\n", __func__);
+
        if (!IS_FWI2_CAPABLE(vha->hw))
                return QLA_FUNCTION_FAILED;
 
        if (unlikely(pci_channel_offline(vha->hw->pdev)))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
-
        mcp->mb[0] = MBC_TRACE_CONTROL;
        mcp->mb[1] = TC_EFT_DISABLE;
        mcp->out_mb = MBX_1|MBX_0;
@@ -2684,10 +2644,11 @@ qla2x00_disable_eft_trace(scsi_qla_host_t *vha)
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(vha, mcp);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
-                   __func__, vha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10a8,
+                   "Failed=%x mb[0]=%x mb[1]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10a9, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -2701,14 +2662,14 @@ qla2x00_enable_fce_trace(scsi_qla_host_t *vha, dma_addr_t fce_dma,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10aa, "Entered %s.\n", __func__);
+
        if (!IS_QLA25XX(vha->hw) && !IS_QLA81XX(vha->hw))
                return QLA_FUNCTION_FAILED;
 
        if (unlikely(pci_channel_offline(vha->hw->pdev)))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
-
        mcp->mb[0] = MBC_TRACE_CONTROL;
        mcp->mb[1] = TC_FCE_ENABLE;
        mcp->mb[2] = LSW(fce_dma);
@@ -2727,10 +2688,11 @@ qla2x00_enable_fce_trace(scsi_qla_host_t *vha, dma_addr_t fce_dma,
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(vha, mcp);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
-                   __func__, vha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10ab,
+                   "Failed=%x mb[0]=%x mb[1]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10ac, "Done %s.\n", __func__);
 
                if (mb)
                        memcpy(mb, mcp->mb, 8 * sizeof(*mb));
@@ -2748,14 +2710,14 @@ qla2x00_disable_fce_trace(scsi_qla_host_t *vha, uint64_t *wr, uint64_t *rd)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10ad, "Entered %s.\n", __func__);
+
        if (!IS_FWI2_CAPABLE(vha->hw))
                return QLA_FUNCTION_FAILED;
 
        if (unlikely(pci_channel_offline(vha->hw->pdev)))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
-
        mcp->mb[0] = MBC_TRACE_CONTROL;
        mcp->mb[1] = TC_FCE_DISABLE;
        mcp->mb[2] = TC_FCE_DISABLE_TRACE;
@@ -2766,10 +2728,11 @@ qla2x00_disable_fce_trace(scsi_qla_host_t *vha, uint64_t *wr, uint64_t *rd)
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(vha, mcp);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
-                   __func__, vha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10ae,
+                   "Failed=%x mb[0]=%x mb[1]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10af, "Done %s.\n", __func__);
 
                if (wr)
                        *wr = (uint64_t) mcp->mb[5] << 48 |
@@ -2794,11 +2757,11 @@ qla2x00_get_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10b0, "Entered %s.\n", __func__);
+
        if (!IS_IIDMA_CAPABLE(vha->hw))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
-
        mcp->mb[0] = MBC_PORT_PARAMS;
        mcp->mb[1] = loop_id;
        mcp->mb[2] = mcp->mb[3] = 0;
@@ -2817,10 +2780,9 @@ qla2x00_get_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id,
        }
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x10b1, "Failed=%x.\n", rval);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10b2, "Done %s.\n", __func__);
                if (port_speed)
                        *port_speed = mcp->mb[3];
        }
@@ -2836,11 +2798,11 @@ qla2x00_set_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10b3, "Entered %s.\n", __func__);
+
        if (!IS_IIDMA_CAPABLE(vha->hw))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
-
        mcp->mb[0] = MBC_PORT_PARAMS;
        mcp->mb[1] = loop_id;
        mcp->mb[2] = BIT_0;
@@ -2863,10 +2825,9 @@ qla2x00_set_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id,
        }
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x10b4, "Failed=%x.\n", rval);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10b5, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -2882,33 +2843,36 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
        scsi_qla_host_t *vp;
        unsigned long   flags;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10b6, "Entered %s.\n", __func__);
+
        if (rptid_entry->entry_status != 0)
                return;
 
        if (rptid_entry->format == 0) {
-               DEBUG15(printk("%s:format 0 : scsi(%ld) number of VPs setup %d,"
-                       " number of VPs acquired %d\n", __func__, vha->host_no,
-                       MSB(le16_to_cpu(rptid_entry->vp_count)),
-                       LSB(le16_to_cpu(rptid_entry->vp_count))));
-               DEBUG15(printk("%s primary port id %02x%02x%02x\n", __func__,
-                       rptid_entry->port_id[2], rptid_entry->port_id[1],
-                       rptid_entry->port_id[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10b7,
+                   "Format 0 : Number of VPs setup %d, number of "
+                   "VPs acquired %d.\n",
+                   MSB(le16_to_cpu(rptid_entry->vp_count)),
+                   LSB(le16_to_cpu(rptid_entry->vp_count)));
+               ql_dbg(ql_dbg_mbx, vha, 0x10b8,
+                   "Primary port id %02x%02x%02x.\n",
+                   rptid_entry->port_id[2], rptid_entry->port_id[1],
+                   rptid_entry->port_id[0]);
        } else if (rptid_entry->format == 1) {
                vp_idx = LSB(stat);
-               DEBUG15(printk("%s:format 1: scsi(%ld): VP[%d] enabled "
-                   "- status %d - "
-                   "with port id %02x%02x%02x\n", __func__, vha->host_no,
-                   vp_idx, MSB(stat),
+               ql_dbg(ql_dbg_mbx, vha, 0x10b9,
+                   "Format 1: VP[%d] enabled - status %d - with "
+                   "port id %02x%02x%02x.\n", vp_idx, MSB(stat),
                    rptid_entry->port_id[2], rptid_entry->port_id[1],
-                   rptid_entry->port_id[0]));
+                   rptid_entry->port_id[0]);
 
                vp = vha;
                if (vp_idx == 0 && (MSB(stat) != 1))
                        goto reg_needed;
 
                if (MSB(stat) == 1) {
-                       DEBUG2(printk("scsi(%ld): Could not acquire ID for "
-                           "VP[%d].\n", vha->host_no, vp_idx));
+                       ql_dbg(ql_dbg_mbx, vha, 0x10ba,
+                           "Could not acquire ID for VP[%d].\n", vp_idx);
                        return;
                }
 
@@ -2963,10 +2927,12 @@ qla24xx_modify_vp_config(scsi_qla_host_t *vha)
 
        /* This can be called by the parent */
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10bb, "Entered %s.\n", __func__);
+
        vpmod = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &vpmod_dma);
        if (!vpmod) {
-               DEBUG2_3(printk("%s(%ld): failed to allocate Modify VP "
-                   "IOCB.\n", __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x10bc,
+                   "Failed to allocate modify VP IOCB.\n");
                return QLA_MEMORY_ALLOC_FAILED;
        }
 
@@ -2983,22 +2949,21 @@ qla24xx_modify_vp_config(scsi_qla_host_t *vha)
 
        rval = qla2x00_issue_iocb(base_vha, vpmod, vpmod_dma, 0);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed to issue VP config IOCB"
-                       "(%x).\n", __func__, base_vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x10bd,
+                   "Failed to issue VP config IOCB (%x).\n", rval);
        } else if (vpmod->comp_status != 0) {
-               DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
-                       "-- error status (%x).\n", __func__, base_vha->host_no,
-                       vpmod->comp_status));
+               ql_dbg(ql_dbg_mbx, vha, 0x10be,
+                   "Failed to complete IOCB -- error status (%x).\n",
+                   vpmod->comp_status);
                rval = QLA_FUNCTION_FAILED;
        } else if (vpmod->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) {
-               DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
-                   "-- completion status (%x).\n", __func__, base_vha->host_no,
-                   le16_to_cpu(vpmod->comp_status)));
+               ql_dbg(ql_dbg_mbx, vha, 0x10bf,
+                   "Failed to complete IOCB -- completion status (%x).\n",
+                   le16_to_cpu(vpmod->comp_status));
                rval = QLA_FUNCTION_FAILED;
        } else {
                /* EMPTY */
-               DEBUG11(printk("%s(%ld): done.\n", __func__,
-                                                       base_vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10c0, "Done %s.\n", __func__);
                fc_vport_set_state(vha->fc_vport, FC_VPORT_INITIALIZING);
        }
        dma_pool_free(ha->s_dma_pool, vpmod, vpmod_dma);
@@ -3032,17 +2997,16 @@ qla24xx_control_vp(scsi_qla_host_t *vha, int cmd)
        int     vp_index = vha->vp_idx;
        struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
 
-       DEBUG11(printk("%s(%ld): entered. Enabling index %d\n", __func__,
-           vha->host_no, vp_index));
+       ql_dbg(ql_dbg_mbx, vha, 0x10c1,
+           "Entered %s enabling index %d.\n", __func__, vp_index);
 
        if (vp_index == 0 || vp_index >= ha->max_npiv_vports)
                return QLA_PARAMETER_ERROR;
 
        vce = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &vce_dma);
        if (!vce) {
-               DEBUG2_3(printk("%s(%ld): "
-                   "failed to allocate VP Control IOCB.\n", __func__,
-                   base_vha->host_no));
+               ql_log(ql_log_warn, vha, 0x10c2,
+                   "Failed to allocate VP control IOCB.\n");
                return QLA_MEMORY_ALLOC_FAILED;
        }
        memset(vce, 0, sizeof(struct vp_ctrl_entry_24xx));
@@ -3063,28 +3027,20 @@ qla24xx_control_vp(scsi_qla_host_t *vha, int cmd)
 
        rval = qla2x00_issue_iocb(base_vha, vce, vce_dma, 0);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed to issue VP control IOCB"
-                   "(%x).\n", __func__, base_vha->host_no, rval));
-               printk("%s(%ld): failed to issue VP control IOCB"
-                   "(%x).\n", __func__, base_vha->host_no, rval);
+               ql_dbg(ql_dbg_mbx, vha, 0x10c3,
+                   "Failed to issue VP control IOCB (%x).\n", rval);
        } else if (vce->entry_status != 0) {
-               DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
-                   "-- error status (%x).\n", __func__, base_vha->host_no,
-                   vce->entry_status));
-               printk("%s(%ld): failed to complete IOCB "
-                   "-- error status (%x).\n", __func__, base_vha->host_no,
+               ql_dbg(ql_dbg_mbx, vha, 0x10c4,
+                   "Failed to complete IOCB -- error status (%x).\n",
                    vce->entry_status);
                rval = QLA_FUNCTION_FAILED;
        } else if (vce->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) {
-               DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
-                   "-- completion status (%x).\n", __func__, base_vha->host_no,
-                   le16_to_cpu(vce->comp_status)));
-               printk("%s(%ld): failed to complete IOCB "
-                   "-- completion status (%x).\n", __func__, base_vha->host_no,
+               ql_dbg(ql_dbg_mbx, vha, 0x10c5,
+                   "Failed to complet IOCB -- completion status (%x).\n",
                    le16_to_cpu(vce->comp_status));
                rval = QLA_FUNCTION_FAILED;
        } else {
-               DEBUG2(printk("%s(%ld): done.\n", __func__, base_vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10c6, "Done %s.\n", __func__);
        }
 
        dma_pool_free(ha->s_dma_pool, vce, vce_dma);
@@ -3121,6 +3077,8 @@ qla2x00_send_change_request(scsi_qla_host_t *vha, uint16_t format,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10c7, "Entered %s.\n", __func__);
+
        /*
         * This command is implicitly executed by firmware during login for the
         * physical hosts
@@ -3155,7 +3113,7 @@ qla2x00_dump_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t addr,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1009, "Entered %s.\n", __func__);
 
        if (MSW(addr) || IS_FWI2_CAPABLE(vha->hw)) {
                mcp->mb[0] = MBC_DUMP_RISC_RAM_EXTENDED;
@@ -3186,10 +3144,10 @@ qla2x00_dump_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t addr,
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x.\n", __func__,
-                   vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x1008,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1007, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -3214,12 +3172,10 @@ qla84xx_verify_chip(struct scsi_qla_host *vha, uint16_t *status)
        unsigned long flags;
        struct qla_hw_data *ha = vha->hw;
 
-       DEBUG16(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x10c8, "Entered %s.\n", __func__);
 
        mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma);
        if (mn == NULL) {
-               DEBUG2_3(printk("%s(%ld): failed to allocate Verify ISP84XX "
-                   "IOCB.\n", __func__, vha->host_no));
                return QLA_MEMORY_ALLOC_FAILED;
        }
 
@@ -3237,43 +3193,43 @@ qla84xx_verify_chip(struct scsi_qla_host *vha, uint16_t *status)
                mn->p.req.entry_count = 1;
                mn->p.req.options = cpu_to_le16(options);
 
-               DEBUG16(printk("%s(%ld): Dump of Verify Request.\n", __func__,
-                   vha->host_no));
-               DEBUG16(qla2x00_dump_buffer((uint8_t *)mn,
-                   sizeof(*mn)));
+               ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x111c,
+                   "Dump of Verify Request.\n");
+               ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x111e,
+                   (uint8_t *)mn, sizeof(*mn));
 
                rval = qla2x00_issue_iocb_timeout(vha, mn, mn_dma, 0, 120);
                if (rval != QLA_SUCCESS) {
-                       DEBUG2_16(printk("%s(%ld): failed to issue Verify "
-                           "IOCB (%x).\n", __func__, vha->host_no, rval));
+                       ql_dbg(ql_dbg_mbx, vha, 0x10cb,
+                           "Failed to issue verify IOCB (%x).\n", rval);
                        goto verify_done;
                }
 
-               DEBUG16(printk("%s(%ld): Dump of Verify Response.\n", __func__,
-                   vha->host_no));
-               DEBUG16(qla2x00_dump_buffer((uint8_t *)mn,
-                   sizeof(*mn)));
+               ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1110,
+                   "Dump of Verify Response.\n");
+               ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1118,
+                   (uint8_t *)mn, sizeof(*mn));
 
                status[0] = le16_to_cpu(mn->p.rsp.comp_status);
                status[1] = status[0] == CS_VCS_CHIP_FAILURE ?
                    le16_to_cpu(mn->p.rsp.failure_code) : 0;
-               DEBUG2_16(printk("%s(%ld): cs=%x fc=%x\n", __func__,
-                   vha->host_no, status[0], status[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10ce,
+                   "cs=%x fc=%x.\n", status[0], status[1]);
 
                if (status[0] != CS_COMPLETE) {
                        rval = QLA_FUNCTION_FAILED;
                        if (!(options & VCO_DONT_UPDATE_FW)) {
-                               DEBUG2_16(printk("%s(%ld): Firmware update "
-                                   "failed. Retrying without update "
-                                   "firmware.\n", __func__, vha->host_no));
+                               ql_dbg(ql_dbg_mbx, vha, 0x10cf,
+                                   "Firmware update failed. Retrying "
+                                   "without update firmware.\n");
                                options |= VCO_DONT_UPDATE_FW;
                                options &= ~VCO_FORCE_UPDATE;
                                retry = 1;
                        }
                } else {
-                       DEBUG2_16(printk("%s(%ld): firmware updated to %x.\n",
-                           __func__, vha->host_no,
-                           le32_to_cpu(mn->p.rsp.fw_ver)));
+                       ql_dbg(ql_dbg_mbx, vha, 0x10d0,
+                           "Firmware updated to %x.\n",
+                           le32_to_cpu(mn->p.rsp.fw_ver));
 
                        /* NOTE: we only update OP firmware. */
                        spin_lock_irqsave(&ha->cs84xx->access_lock, flags);
@@ -3288,10 +3244,9 @@ verify_done:
        dma_pool_free(ha->s_dma_pool, mn, mn_dma);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_16(printk("%s(%ld): failed=%x.\n", __func__,
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x10d1, "Failed=%x.\n", rval);
        } else {
-               DEBUG16(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10d2, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -3307,6 +3262,8 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req)
        struct device_reg_25xxmq __iomem *reg;
        struct qla_hw_data *ha = vha->hw;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10d3, "Entered %s.\n", __func__);
+
        mcp->mb[0] = MBC_INITIALIZE_MULTIQ;
        mcp->mb[1] = req->options;
        mcp->mb[2] = MSW(LSD(req->dma));
@@ -3344,9 +3301,13 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req)
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
        rval = qla2x00_mailbox_command(vha, mcp);
-       if (rval != QLA_SUCCESS)
-               DEBUG2_3_11(printk(KERN_WARNING "%s(%ld): failed=%x mb0=%x.\n",
-                       __func__, vha->host_no, rval, mcp->mb[0]));
+       if (rval != QLA_SUCCESS) {
+               ql_dbg(ql_dbg_mbx, vha, 0x10d4,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
+       } else {
+               ql_dbg(ql_dbg_mbx, vha, 0x10d5, "Done %s.\n", __func__);
+       }
+
        return rval;
 }
 
@@ -3360,6 +3321,8 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
        struct device_reg_25xxmq __iomem *reg;
        struct qla_hw_data *ha = vha->hw;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10d6, "Entered %s.\n", __func__);
+
        mcp->mb[0] = MBC_INITIALIZE_MULTIQ;
        mcp->mb[1] = rsp->options;
        mcp->mb[2] = MSW(LSD(rsp->dma));
@@ -3393,10 +3356,13 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
        rval = qla2x00_mailbox_command(vha, mcp);
-       if (rval != QLA_SUCCESS)
-               DEBUG2_3_11(printk(KERN_WARNING "%s(%ld): failed=%x "
-                       "mb0=%x.\n", __func__,
-                       vha->host_no, rval, mcp->mb[0]));
+       if (rval != QLA_SUCCESS) {
+               ql_dbg(ql_dbg_mbx, vha, 0x10d7,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
+       } else {
+               ql_dbg(ql_dbg_mbx, vha, 0x10d8, "Done %s.\n", __func__);
+       }
+
        return rval;
 }
 
@@ -3407,7 +3373,7 @@ qla81xx_idc_ack(scsi_qla_host_t *vha, uint16_t *mb)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x10d9, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_IDC_ACK;
        memcpy(&mcp->mb[1], mb, QLA_IDC_ACK_REGS * sizeof(uint16_t));
@@ -3418,10 +3384,10 @@ qla81xx_idc_ack(scsi_qla_host_t *vha, uint16_t *mb)
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
-                   vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10da,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10db, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -3434,11 +3400,11 @@ qla81xx_fac_get_sector_size(scsi_qla_host_t *vha, uint32_t *sector_size)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10dc, "Entered %s.\n", __func__);
+
        if (!IS_QLA81XX(vha->hw))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
-
        mcp->mb[0] = MBC_FLASH_ACCESS_CTRL;
        mcp->mb[1] = FAC_OPT_CMD_GET_SECTOR_SIZE;
        mcp->out_mb = MBX_1|MBX_0;
@@ -3448,10 +3414,11 @@ qla81xx_fac_get_sector_size(scsi_qla_host_t *vha, uint32_t *sector_size)
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
-                   __func__, vha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10dd,
+                   "Failed=%x mb[0]=%x mb[1]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10de, "Done %s.\n", __func__);
                *sector_size = mcp->mb[1];
        }
 
@@ -3468,7 +3435,7 @@ qla81xx_fac_do_write_enable(scsi_qla_host_t *vha, int enable)
        if (!IS_QLA81XX(vha->hw))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x10df, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_FLASH_ACCESS_CTRL;
        mcp->mb[1] = enable ? FAC_OPT_CMD_WRITE_ENABLE :
@@ -3480,10 +3447,11 @@ qla81xx_fac_do_write_enable(scsi_qla_host_t *vha, int enable)
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
-                   __func__, vha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10e0,
+                   "Failed=%x mb[0]=%x mb[1]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10e1, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -3499,7 +3467,7 @@ qla81xx_fac_erase_sector(scsi_qla_host_t *vha, uint32_t start, uint32_t finish)
        if (!IS_QLA81XX(vha->hw))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x10e2, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_FLASH_ACCESS_CTRL;
        mcp->mb[1] = FAC_OPT_CMD_ERASE_SECTOR;
@@ -3514,11 +3482,11 @@ qla81xx_fac_erase_sector(scsi_qla_host_t *vha, uint32_t start, uint32_t finish)
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x "
-                   "mb[2]=%x.\n", __func__, vha->host_no, rval, mcp->mb[0],
-                   mcp->mb[1], mcp->mb[2]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10e3,
+                   "Failed=%x mb[0]=%x mb[1]=%x mb[2]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1], mcp->mb[2]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10e4, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -3531,7 +3499,7 @@ qla81xx_restart_mpi_firmware(scsi_qla_host_t *vha)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x10e5, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_RESTART_MPI_FW;
        mcp->out_mb = MBX_0;
@@ -3541,10 +3509,11 @@ qla81xx_restart_mpi_firmware(scsi_qla_host_t *vha)
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=0x%x mb[1]=0x%x.\n",
-                   __func__, vha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10e6,
+                   "Failed=%x mb[0]=%x mb[1]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10e7, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -3559,11 +3528,11 @@ qla2x00_read_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint8_t *sfp,
        mbx_cmd_t *mcp = &mc;
        struct qla_hw_data *ha = vha->hw;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10e8, "Entered %s.\n", __func__);
+
        if (!IS_FWI2_CAPABLE(ha))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
-
        if (len == 1)
                opt |= BIT_0;
 
@@ -3586,10 +3555,10 @@ qla2x00_read_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint8_t *sfp,
                *sfp = mcp->mb[1];
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
-                   vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10e9,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10ea, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -3604,11 +3573,11 @@ qla2x00_write_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint8_t *sfp,
        mbx_cmd_t *mcp = &mc;
        struct qla_hw_data *ha = vha->hw;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10eb, "Entered %s.\n", __func__);
+
        if (!IS_FWI2_CAPABLE(ha))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
-
        if (len == 1)
                opt |= BIT_0;
 
@@ -3631,10 +3600,10 @@ qla2x00_write_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint8_t *sfp,
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
-                   vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10ec,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10ed, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -3648,11 +3617,11 @@ qla2x00_get_xgmac_stats(scsi_qla_host_t *vha, dma_addr_t stats_dma,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10ee, "Entered %s.\n", __func__);
+
        if (!IS_QLA8XXX_TYPE(vha->hw))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
-
        mcp->mb[0] = MBC_GET_XGMAC_STATS;
        mcp->mb[2] = MSW(stats_dma);
        mcp->mb[3] = LSW(stats_dma);
@@ -3666,11 +3635,12 @@ qla2x00_get_xgmac_stats(scsi_qla_host_t *vha, dma_addr_t stats_dma,
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=0x%x "
-                   "mb[1]=0x%x mb[2]=0x%x.\n", __func__, vha->host_no, rval,
-                   mcp->mb[0], mcp->mb[1], mcp->mb[2]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10ef,
+                   "Failed=%x mb[0]=%x mb[1]=%x mb[2]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1], mcp->mb[2]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10f0, "Done %s.\n", __func__);
+
 
                *actual_size = mcp->mb[2] << 2;
        }
@@ -3686,11 +3656,11 @@ qla2x00_get_dcbx_params(scsi_qla_host_t *vha, dma_addr_t tlv_dma,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10f1, "Entered %s.\n", __func__);
+
        if (!IS_QLA8XXX_TYPE(vha->hw))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
-
        mcp->mb[0] = MBC_GET_DCBX_PARAMS;
        mcp->mb[1] = 0;
        mcp->mb[2] = MSW(tlv_dma);
@@ -3705,11 +3675,11 @@ qla2x00_get_dcbx_params(scsi_qla_host_t *vha, dma_addr_t tlv_dma,
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=0x%x "
-                   "mb[1]=0x%x mb[2]=0x%x.\n", __func__, vha->host_no, rval,
-                   mcp->mb[0], mcp->mb[1], mcp->mb[2]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10f2,
+                   "Failed=%x mb[0]=%x mb[1]=%x mb[2]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1], mcp->mb[2]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10f3, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -3722,11 +3692,11 @@ qla2x00_read_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t *data)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10f4, "Entered %s.\n", __func__);
+
        if (!IS_FWI2_CAPABLE(vha->hw))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
-
        mcp->mb[0] = MBC_READ_RAM_EXTENDED;
        mcp->mb[1] = LSW(risc_addr);
        mcp->mb[8] = MSW(risc_addr);
@@ -3736,10 +3706,10 @@ qla2x00_read_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t *data)
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(vha, mcp);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x.\n", __func__,
-                   vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10f5,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10f6, "Done %s.\n", __func__);
                *data = mcp->mb[3] << 16 | mcp->mb[2];
        }
 
@@ -3755,7 +3725,7 @@ qla2x00_loopback_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq,
        mbx_cmd_t *mcp = &mc;
        uint32_t iter_cnt = 0x1;
 
-       DEBUG11(printk("scsi(%ld): entered.\n", vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x10f7, "Entered %s.\n", __func__);
 
        memset(mcp->mb, 0 , sizeof(mcp->mb));
        mcp->mb[0] = MBC_DIAGNOSTIC_LOOP_BACK;
@@ -3794,15 +3764,12 @@ qla2x00_loopback_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq,
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2(printk(KERN_WARNING
-                       "(%ld): failed=%x mb[0]=0x%x "
-                       "mb[1]=0x%x mb[2]=0x%x mb[3]=0x%x mb[18]=0x%x "
-                       "mb[19]=0x%x.\n",
-                       vha->host_no, rval, mcp->mb[0], mcp->mb[1], mcp->mb[2],
-                       mcp->mb[3], mcp->mb[18], mcp->mb[19]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10f8,
+                   "Failed=%x mb[0]=%x mb[1]=%x mb[2]=%x mb[3]=%x mb[18]=%x "
+                   "mb[19]=%x.\n", rval, mcp->mb[0], mcp->mb[1], mcp->mb[2],
+                   mcp->mb[3], mcp->mb[18], mcp->mb[19]);
        } else {
-               DEBUG2(printk(KERN_WARNING
-                   "scsi(%ld): done.\n", vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10f9, "Done %s.\n", __func__);
        }
 
        /* Copy mailbox information */
@@ -3819,7 +3786,7 @@ qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq,
        mbx_cmd_t *mcp = &mc;
        struct qla_hw_data *ha = vha->hw;
 
-       DEBUG11(printk("scsi(%ld): entered.\n", vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x10fa, "Entered %s.\n", __func__);
 
        memset(mcp->mb, 0 , sizeof(mcp->mb));
        mcp->mb[0] = MBC_DIAGNOSTIC_ECHO;
@@ -3858,12 +3825,11 @@ qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq,
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2(printk(KERN_WARNING
-                   "(%ld): failed=%x mb[0]=0x%x mb[1]=0x%x.\n",
-                   vha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10fb,
+                   "Failed=%x mb[0]=%x mb[1]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1]);
        } else {
-               DEBUG2(printk(KERN_WARNING
-                   "scsi(%ld): done.\n", vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10fc, "Done %s.\n", __func__);
        }
 
        /* Copy mailbox information */
@@ -3872,14 +3838,14 @@ qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq,
 }
 
 int
-qla84xx_reset_chip(scsi_qla_host_t *ha, uint16_t enable_diagnostic)
+qla84xx_reset_chip(scsi_qla_host_t *vha, uint16_t enable_diagnostic)
 {
        int rval;
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG16(printk("%s(%ld): enable_diag=%d entered.\n", __func__,
-               ha->host_no, enable_diagnostic));
+       ql_dbg(ql_dbg_mbx, vha, 0x10fd,
+           "Entered %s enable_diag=%d.\n", __func__, enable_diagnostic);
 
        mcp->mb[0] = MBC_ISP84XX_RESET;
        mcp->mb[1] = enable_diagnostic;
@@ -3887,13 +3853,12 @@ qla84xx_reset_chip(scsi_qla_host_t *ha, uint16_t enable_diagnostic)
        mcp->in_mb = MBX_1|MBX_0;
        mcp->tov = MBX_TOV_SECONDS;
        mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD;
-       rval = qla2x00_mailbox_command(ha, mcp);
+       rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS)
-               DEBUG16(printk("%s(%ld): failed=%x.\n", __func__, ha->host_no,
-                       rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x10fe, "Failed=%x.\n", rval);
        else
-               DEBUG16(printk("%s(%ld): done.\n", __func__, ha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10ff, "Done %s.\n", __func__);
 
        return rval;
 }
@@ -3905,11 +3870,11 @@ qla2x00_write_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t data)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x1100, "Entered %s.\n", __func__);
+
        if (!IS_FWI2_CAPABLE(vha->hw))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
-
        mcp->mb[0] = MBC_WRITE_RAM_WORD_EXTENDED;
        mcp->mb[1] = LSW(risc_addr);
        mcp->mb[2] = LSW(data);
@@ -3921,10 +3886,10 @@ qla2x00_write_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t data)
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(vha, mcp);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x.\n", __func__,
-                   vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x1101,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1102, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -3941,8 +3906,7 @@ qla81xx_write_mpi_register(scsi_qla_host_t *vha, uint16_t *mb)
 
        rval = QLA_SUCCESS;
 
-       DEBUG11(qla_printk(KERN_INFO, ha,
-           "%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1103, "Entered %s.\n", __func__);
 
        clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
 
@@ -3982,11 +3946,10 @@ qla81xx_write_mpi_register(scsi_qla_host_t *vha, uint16_t *mb)
                rval = QLA_FUNCTION_FAILED;
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk(KERN_INFO "%s(%ld): failed=%x mb[0]=%x.\n",
-                   __func__, vha->host_no, rval, mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x1104,
+                   "Failed=%x mb[0]=%x.\n", rval, mb[0]);
        } else {
-               DEBUG11(printk(KERN_INFO
-                   "%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1105, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -3999,12 +3962,11 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha)
        mbx_cmd_t *mcp = &mc;
        struct qla_hw_data *ha = vha->hw;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x1106, "Entered %s.\n", __func__);
+
        if (!IS_FWI2_CAPABLE(ha))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(qla_printk(KERN_INFO, ha,
-               "%s(%ld): entered.\n", __func__, vha->host_no));
-
        mcp->mb[0] = MBC_DATA_RATE;
        mcp->mb[1] = 0;
        mcp->out_mb = MBX_1|MBX_0;
@@ -4013,11 +3975,10 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha)
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(vha, mcp);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk(KERN_INFO "%s(%ld): failed=%x mb[0]=%x.\n",
-                   __func__, vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x1107,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
-               DEBUG11(printk(KERN_INFO
-                   "%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1108, "Done %s.\n", __func__);
                if (mcp->mb[1] != 0x7)
                        ha->link_data_rate = mcp->mb[1];
        }
@@ -4033,8 +3994,7 @@ qla81xx_get_port_config(scsi_qla_host_t *vha, uint16_t *mb)
        mbx_cmd_t *mcp = &mc;
        struct qla_hw_data *ha = vha->hw;
 
-       DEBUG11(printk(KERN_INFO
-           "%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1109, "Entered %s.\n", __func__);
 
        if (!IS_QLA81XX(ha))
                return QLA_FUNCTION_FAILED;
@@ -4047,15 +4007,13 @@ qla81xx_get_port_config(scsi_qla_host_t *vha, uint16_t *mb)
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk(KERN_WARNING
-                   "%s(%ld): failed=%x (%x).\n", __func__,
-                   vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x110a,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
                /* Copy all bits to preserve original value */
                memcpy(mb, &mcp->mb[1], sizeof(uint16_t) * 4);
 
-               DEBUG11(printk(KERN_INFO
-                   "%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x110b, "Done %s.\n", __func__);
        }
        return rval;
 }
@@ -4067,8 +4025,7 @@ qla81xx_set_port_config(scsi_qla_host_t *vha, uint16_t *mb)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk(KERN_INFO
-           "%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x110c, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_SET_PORT_CONFIG;
        /* Copy all bits to preserve original setting */
@@ -4080,12 +4037,10 @@ qla81xx_set_port_config(scsi_qla_host_t *vha, uint16_t *mb)
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk(KERN_WARNING
-                   "%s(%ld): failed=%x (%x).\n", __func__,
-                   vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x110d,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else
-               DEBUG11(printk(KERN_INFO
-                   "%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x110e, "Done %s.\n", __func__);
 
        return rval;
 }
@@ -4100,12 +4055,11 @@ qla24xx_set_fcp_prio(scsi_qla_host_t *vha, uint16_t loop_id, uint16_t priority,
        mbx_cmd_t *mcp = &mc;
        struct qla_hw_data *ha = vha->hw;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x110f, "Entered %s.\n", __func__);
+
        if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk(KERN_INFO
-           "%s(%ld): entered.\n", __func__, vha->host_no));
-
        mcp->mb[0] = MBC_PORT_PARAMS;
        mcp->mb[1] = loop_id;
        if (ha->flags.fcp_prio_enabled)
@@ -4127,12 +4081,9 @@ qla24xx_set_fcp_prio(scsi_qla_host_t *vha, uint16_t loop_id, uint16_t priority,
        }
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk(KERN_WARNING
-                   "%s(%ld): failed=%x.\n", __func__,
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x10cd, "Failed=%x.\n", rval);
        } else {
-               DEBUG11(printk(KERN_INFO
-                   "%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10cc, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -4145,13 +4096,12 @@ qla2x00_get_thermal_temp(scsi_qla_host_t *vha, uint16_t *temp, uint16_t *frac)
        uint8_t byte;
        struct qla_hw_data *ha = vha->hw;
 
-       DEBUG11(printk(KERN_INFO "%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x10ca, "Entered %s.\n", __func__);
 
        /* Integer part */
        rval = qla2x00_read_sfp(vha, 0, &byte, 0x98, 0x01, 1, BIT_13|BIT_0);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk(KERN_WARNING
-                   "%s(%ld): failed=%x.\n", __func__, vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x10c9, "Failed=%x.\n", rval);
                ha->flags.thermal_supported = 0;
                goto fail;
        }
@@ -4160,14 +4110,13 @@ qla2x00_get_thermal_temp(scsi_qla_host_t *vha, uint16_t *temp, uint16_t *frac)
        /* Fraction part */
        rval = qla2x00_read_sfp(vha, 0, &byte, 0x98, 0x10, 1, BIT_13|BIT_0);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk(KERN_WARNING
-                   "%s(%ld): failed=%x.\n", __func__, vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x1019, "Failed=%x.\n", rval);
                ha->flags.thermal_supported = 0;
                goto fail;
        }
        *frac = (byte >> 6) * 25;
 
-       DEBUG11(printk(KERN_INFO "%s(%ld): done.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1018, "Done %s.\n", __func__);
 fail:
        return rval;
 }
@@ -4180,12 +4129,11 @@ qla82xx_mbx_intr_enable(scsi_qla_host_t *vha)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x1017, "Entered %s.\n", __func__);
+
        if (!IS_FWI2_CAPABLE(ha))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(qla_printk(KERN_INFO, ha,
-               "%s(%ld): entered.\n", __func__, vha->host_no));
-
        memset(mcp, 0, sizeof(mbx_cmd_t));
        mcp->mb[0] = MBC_TOGGLE_INTERRUPT;
        mcp->mb[1] = 1;
@@ -4197,12 +4145,10 @@ qla82xx_mbx_intr_enable(scsi_qla_host_t *vha)
 
        rval = qla2x00_mailbox_command(vha, mcp);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(qla_printk(KERN_WARNING, ha,
-                       "%s(%ld): failed=%x mb[0]=%x.\n", __func__,
-                       vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x1016,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
-               DEBUG11(qla_printk(KERN_INFO, ha,
-                       "%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x100e, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -4216,12 +4162,11 @@ qla82xx_mbx_intr_disable(scsi_qla_host_t *vha)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x100d, "Entered %s.\n", __func__);
+
        if (!IS_QLA82XX(ha))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(qla_printk(KERN_INFO, ha,
-               "%s(%ld): entered.\n", __func__, vha->host_no));
-
        memset(mcp, 0, sizeof(mbx_cmd_t));
        mcp->mb[0] = MBC_TOGGLE_INTERRUPT;
        mcp->mb[1] = 0;
@@ -4233,12 +4178,10 @@ qla82xx_mbx_intr_disable(scsi_qla_host_t *vha)
 
        rval = qla2x00_mailbox_command(vha, mcp);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(qla_printk(KERN_WARNING, ha,
-                       "%s(%ld): failed=%x mb[0]=%x.\n", __func__,
-                       vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x100c,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
-               DEBUG11(qla_printk(KERN_INFO, ha,
-                       "%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x100b, "Done %s.\n", __func__);
        }
 
        return rval;
index 5e34391..c706ed3 100644 (file)
@@ -36,8 +36,9 @@ qla24xx_allocate_vp_id(scsi_qla_host_t *vha)
        mutex_lock(&ha->vport_lock);
        vp_id = find_first_zero_bit(ha->vp_idx_map, ha->max_npiv_vports + 1);
        if (vp_id > ha->max_npiv_vports) {
-               DEBUG15(printk ("vp_id %d is bigger than max-supported %d.\n",
-                   vp_id, ha->max_npiv_vports));
+               ql_dbg(ql_dbg_vport, vha, 0xa000,
+                   "vp_id %d is bigger than max-supported %d.\n",
+                   vp_id, ha->max_npiv_vports);
                mutex_unlock(&ha->vport_lock);
                return vp_id;
        }
@@ -131,9 +132,9 @@ qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha)
        fc_port_t *fcport;
 
        list_for_each_entry(fcport, &vha->vp_fcports, list) {
-               DEBUG15(printk("scsi(%ld): Marking port dead, "
-                   "loop_id=0x%04x :%x\n",
-                   vha->host_no, fcport->loop_id, fcport->vp_idx));
+               ql_dbg(ql_dbg_vport, vha, 0xa001,
+                   "Marking port dead, loop_id=0x%04x : %x.\n",
+                   fcport->loop_id, fcport->vp_idx);
 
                qla2x00_mark_device_lost(vha, fcport, 0, 0);
                qla2x00_set_fcport_state(fcport, FCS_UNCONFIGURED);
@@ -187,13 +188,13 @@ qla24xx_enable_vp(scsi_qla_host_t *vha)
                goto enable_failed;
        }
 
-       DEBUG15(qla_printk(KERN_INFO, ha,
-           "Virtual port with id: %d - Enabled\n", vha->vp_idx));
+       ql_dbg(ql_dbg_taskm, vha, 0x801a,
+           "Virtual port with id: %d - Enabled.\n", vha->vp_idx);
        return 0;
 
 enable_failed:
-       DEBUG15(qla_printk(KERN_INFO, ha,
-           "Virtual port with id: %d - Disabled\n", vha->vp_idx));
+       ql_dbg(ql_dbg_taskm, vha, 0x801b,
+           "Virtual port with id: %d - Disabled.\n", vha->vp_idx);
        return 1;
 }
 
@@ -205,12 +206,12 @@ qla24xx_configure_vp(scsi_qla_host_t *vha)
 
        fc_vport = vha->fc_vport;
 
-       DEBUG15(printk("scsi(%ld): %s: change request #3 for this host.\n",
-           vha->host_no, __func__));
+       ql_dbg(ql_dbg_vport, vha, 0xa002,
+           "%s: change request #3.\n", __func__);
        ret = qla2x00_send_change_request(vha, 0x3, vha->vp_idx);
        if (ret != QLA_SUCCESS) {
-               DEBUG15(qla_printk(KERN_ERR, vha->hw, "Failed to enable "
-                   "receiving of RSCN requests: 0x%x\n", ret));
+               ql_dbg(ql_dbg_vport, vha, 0xa003, "Failed to enable "
+                   "receiving of RSCN requests: 0x%x.\n", ret);
                return;
        } else {
                /* Corresponds to SCR enabled */
@@ -248,9 +249,9 @@ qla2x00_alert_all_vps(struct rsp_que *rsp, uint16_t *mb)
                        case MBA_CHG_IN_CONNECTION:
                        case MBA_PORT_UPDATE:
                        case MBA_RSCN_UPDATE:
-                               DEBUG15(printk("scsi(%ld)%s: Async_event for"
-                               " VP[%d], mb = 0x%x, vha=%p\n",
-                               vha->host_no, __func__, i, *mb, vha));
+                               ql_dbg(ql_dbg_async, vha, 0x5024,
+                                   "Async_event for VP[%d], mb=0x%x vha=%p.\n",
+                                   i, *mb, vha);
                                qla2x00_async_event(vha, rsp, mb);
                                break;
                        }
@@ -286,37 +287,49 @@ qla2x00_vp_abort_isp(scsi_qla_host_t *vha)
        if (!test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags))
                qla24xx_control_vp(vha, VCE_COMMAND_DISABLE_VPS_LOGO_ALL);
 
-       DEBUG15(printk("scsi(%ld): Scheduling enable of Vport %d...\n",
-           vha->host_no, vha->vp_idx));
+       ql_dbg(ql_dbg_taskm, vha, 0x801d,
+           "Scheduling enable of Vport %d.\n", vha->vp_idx);
        return qla24xx_enable_vp(vha);
 }
 
 static int
 qla2x00_do_dpc_vp(scsi_qla_host_t *vha)
 {
+       ql_dbg(ql_dbg_dpc, vha, 0x4012,
+           "Entering %s.\n", __func__);
+       ql_dbg(ql_dbg_dpc, vha, 0x4013,
+           "vp_flags: 0x%lx.\n", vha->vp_flags);
+
        qla2x00_do_work(vha);
 
        if (test_and_clear_bit(VP_IDX_ACQUIRED, &vha->vp_flags)) {
                /* VP acquired. complete port configuration */
+               ql_dbg(ql_dbg_dpc, vha, 0x4014,
+                   "Configure VP scheduled.\n");
                qla24xx_configure_vp(vha);
+               ql_dbg(ql_dbg_dpc, vha, 0x4015,
+                   "Configure VP end.\n");
                return 0;
        }
 
        if (test_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags)) {
+               ql_dbg(ql_dbg_dpc, vha, 0x4016,
+                   "FCPort update scheduled.\n");
                qla2x00_update_fcports(vha);
                clear_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags);
+               ql_dbg(ql_dbg_dpc, vha, 0x4017,
+                   "FCPort update end.\n");
        }
 
        if ((test_and_clear_bit(RELOGIN_NEEDED, &vha->dpc_flags)) &&
                !test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags) &&
                atomic_read(&vha->loop_state) != LOOP_DOWN) {
 
-               DEBUG(printk("scsi(%ld): qla2x00_port_login()\n",
-                                               vha->host_no));
+               ql_dbg(ql_dbg_dpc, vha, 0x4018,
+                   "Relogin needed scheduled.\n");
                qla2x00_relogin(vha);
-
-               DEBUG(printk("scsi(%ld): qla2x00_port_login - end\n",
-                                                       vha->host_no));
+               ql_dbg(ql_dbg_dpc, vha, 0x4019,
+                   "Relogin needed end.\n");
        }
 
        if (test_and_clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags) &&
@@ -326,11 +339,17 @@ qla2x00_do_dpc_vp(scsi_qla_host_t *vha)
 
        if (test_and_clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
                if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags))) {
+                       ql_dbg(ql_dbg_dpc, vha, 0x401a,
+                           "Loop resync scheduled.\n");
                        qla2x00_loop_resync(vha);
                        clear_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags);
+                       ql_dbg(ql_dbg_dpc, vha, 0x401b,
+                           "Loop resync end.\n");
                }
        }
 
+       ql_dbg(ql_dbg_dpc, vha, 0x401c,
+           "Exiting %s.\n", __func__);
        return 0;
 }
 
@@ -396,9 +415,10 @@ qla24xx_vport_create_req_sanity_check(struct fc_vport *fc_vport)
 
        /* Check up max-npiv-supports */
        if (ha->num_vhosts > ha->max_npiv_vports) {
-               DEBUG15(printk("scsi(%ld): num_vhosts %ud is bigger than "
-                   "max_npv_vports %ud.\n", base_vha->host_no,
-                   ha->num_vhosts, ha->max_npiv_vports));
+               ql_dbg(ql_dbg_vport, vha, 0xa004,
+                   "num_vhosts %ud is bigger "
+                   "than max_npiv_vports %ud.\n",
+                   ha->num_vhosts, ha->max_npiv_vports);
                return VPCERR_UNSUPPORTED;
        }
        return 0;
@@ -415,7 +435,8 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
 
        vha = qla2x00_create_host(sht, ha);
        if (!vha) {
-               DEBUG(printk("qla2xxx: scsi_host_alloc() failed for vport\n"));
+               ql_log(ql_log_warn, vha, 0xa005,
+                   "scsi_host_alloc() failed for vport.\n");
                return(NULL);
        }
 
@@ -429,8 +450,8 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
        vha->device_flags = 0;
        vha->vp_idx = qla24xx_allocate_vp_id(vha);
        if (vha->vp_idx > ha->max_npiv_vports) {
-               DEBUG15(printk("scsi(%ld): Couldn't allocate vp_id.\n",
-                       vha->host_no));
+               ql_dbg(ql_dbg_vport, vha, 0xa006,
+                   "Couldn't allocate vp_id.\n");
                goto create_vhost_failed;
        }
        vha->mgmt_svr_loop_id = 10 + vha->vp_idx;
@@ -461,8 +482,9 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
        host->max_id = MAX_TARGETS_2200;
        host->transportt = qla2xxx_transport_vport_template;
 
-       DEBUG15(printk("DEBUG: detect vport hba %ld at address = %p\n",
-           vha->host_no, vha));
+       ql_dbg(ql_dbg_vport, vha, 0xa007,
+           "Detect vport hba %ld at address = %p.\n",
+           vha->host_no, vha);
 
        vha->flags.init_done = 1;
 
@@ -567,9 +589,9 @@ qla25xx_delete_queues(struct scsi_qla_host *vha)
                if (req) {
                        ret = qla25xx_delete_req_que(vha, req);
                        if (ret != QLA_SUCCESS) {
-                               qla_printk(KERN_WARNING, ha,
-                               "Couldn't delete req que %d\n",
-                               req->id);
+                               ql_log(ql_log_warn, vha, 0x00ea,
+                                   "Couldn't delete req que %d.\n",
+                                   req->id);
                                return ret;
                        }
                }
@@ -581,9 +603,9 @@ qla25xx_delete_queues(struct scsi_qla_host *vha)
                if (rsp) {
                        ret = qla25xx_delete_rsp_que(vha, rsp);
                        if (ret != QLA_SUCCESS) {
-                               qla_printk(KERN_WARNING, ha,
-                               "Couldn't delete rsp que %d\n",
-                               rsp->id);
+                               ql_log(ql_log_warn, vha, 0x00eb,
+                                   "Couldn't delete rsp que %d.\n",
+                                   rsp->id);
                                return ret;
                        }
                }
@@ -604,8 +626,8 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
 
        req = kzalloc(sizeof(struct req_que), GFP_KERNEL);
        if (req == NULL) {
-               qla_printk(KERN_WARNING, ha, "could not allocate memory"
-                       "for request que\n");
+               ql_log(ql_log_fatal, base_vha, 0x00d9,
+                   "Failed to allocate memory for request queue.\n");
                goto failed;
        }
 
@@ -614,8 +636,8 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
                        (req->length + 1) * sizeof(request_t),
                        &req->dma, GFP_KERNEL);
        if (req->ring == NULL) {
-               qla_printk(KERN_WARNING, ha,
-               "Memory Allocation failed - request_ring\n");
+               ql_log(ql_log_fatal, base_vha, 0x00da,
+                   "Failed to allocte memory for request_ring.\n");
                goto que_failed;
        }
 
@@ -623,8 +645,8 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
        que_id = find_first_zero_bit(ha->req_qid_map, ha->max_req_queues);
        if (que_id >= ha->max_req_queues) {
                mutex_unlock(&ha->vport_lock);
-               qla_printk(KERN_INFO, ha, "No resources to create "
-                        "additional request queue\n");
+               ql_log(ql_log_warn, base_vha, 0x00db,
+                   "No resources to create additional request queue.\n");
                goto que_failed;
        }
        set_bit(que_id, ha->req_qid_map);
@@ -633,6 +655,12 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
        req->vp_idx = vp_idx;
        req->qos = qos;
 
+       ql_dbg(ql_dbg_multiq, base_vha, 0xc002,
+           "queue_id=%d rid=%d vp_idx=%d qos=%d.\n",
+           que_id, req->rid, req->vp_idx, req->qos);
+       ql_dbg(ql_dbg_init, base_vha, 0x00dc,
+           "queue_id=%d rid=%d vp_idx=%d qos=%d.\n",
+           que_id, req->rid, req->vp_idx, req->qos);
        if (rsp_que < 0)
                req->rsp = NULL;
        else
@@ -645,6 +673,10 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
                options |= BIT_5;
        req->options = options;
 
+       ql_dbg(ql_dbg_multiq, base_vha, 0xc003,
+           "options=0x%x.\n", req->options);
+       ql_dbg(ql_dbg_init, base_vha, 0x00dd,
+           "options=0x%x.\n", req->options);
        for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++)
                req->outstanding_cmds[cnt] = NULL;
        req->current_outstanding_cmd = 1;
@@ -656,10 +688,21 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
        reg = ISP_QUE_REG(ha, que_id);
        req->max_q_depth = ha->req_q_map[0]->max_q_depth;
        mutex_unlock(&ha->vport_lock);
+       ql_dbg(ql_dbg_multiq, base_vha, 0xc004,
+           "ring_ptr=%p ring_index=%d, "
+           "cnt=%d id=%d max_q_depth=%d.\n",
+           req->ring_ptr, req->ring_index,
+           req->cnt, req->id, req->max_q_depth);
+       ql_dbg(ql_dbg_init, base_vha, 0x00de,
+           "ring_ptr=%p ring_index=%d, "
+           "cnt=%d id=%d max_q_depth=%d.\n",
+           req->ring_ptr, req->ring_index, req->cnt,
+           req->id, req->max_q_depth);
 
        ret = qla25xx_init_req_que(base_vha, req);
        if (ret != QLA_SUCCESS) {
-               qla_printk(KERN_WARNING, ha, "%s failed\n", __func__);
+               ql_log(ql_log_fatal, base_vha, 0x00df,
+                   "%s failed.\n", __func__);
                mutex_lock(&ha->vport_lock);
                clear_bit(que_id, ha->req_qid_map);
                mutex_unlock(&ha->vport_lock);
@@ -700,8 +743,8 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
 
        rsp = kzalloc(sizeof(struct rsp_que), GFP_KERNEL);
        if (rsp == NULL) {
-               qla_printk(KERN_WARNING, ha, "could not allocate memory for"
-                               " response que\n");
+               ql_log(ql_log_warn, base_vha, 0x0066,
+                   "Failed to allocate memory for response queue.\n");
                goto failed;
        }
 
@@ -710,8 +753,8 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
                        (rsp->length + 1) * sizeof(response_t),
                        &rsp->dma, GFP_KERNEL);
        if (rsp->ring == NULL) {
-               qla_printk(KERN_WARNING, ha,
-               "Memory Allocation failed - response_ring\n");
+               ql_log(ql_log_warn, base_vha, 0x00e1,
+                   "Failed to allocate memory for response ring.\n");
                goto que_failed;
        }
 
@@ -719,8 +762,8 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
        que_id = find_first_zero_bit(ha->rsp_qid_map, ha->max_rsp_queues);
        if (que_id >= ha->max_rsp_queues) {
                mutex_unlock(&ha->vport_lock);
-               qla_printk(KERN_INFO, ha, "No resources to create "
-                        "additional response queue\n");
+               ql_log(ql_log_warn, base_vha, 0x00e2,
+                   "No resources to create additional request queue.\n");
                goto que_failed;
        }
        set_bit(que_id, ha->rsp_qid_map);
@@ -728,12 +771,16 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
        if (ha->flags.msix_enabled)
                rsp->msix = &ha->msix_entries[que_id + 1];
        else
-               qla_printk(KERN_WARNING, ha, "msix not enabled\n");
+               ql_log(ql_log_warn, base_vha, 0x00e3,
+                   "MSIX not enalbled.\n");
 
        ha->rsp_q_map[que_id] = rsp;
        rsp->rid = rid;
        rsp->vp_idx = vp_idx;
        rsp->hw = ha;
+       ql_dbg(ql_dbg_init, base_vha, 0x00e4,
+           "queue_id=%d rid=%d vp_idx=%d hw=%p.\n",
+           que_id, rsp->rid, rsp->vp_idx, rsp->hw);
        /* Use alternate PCI bus number */
        if (MSB(rsp->rid))
                options |= BIT_4;
@@ -750,6 +797,14 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
        rsp->rsp_q_in = &reg->isp25mq.rsp_q_in;
        rsp->rsp_q_out = &reg->isp25mq.rsp_q_out;
        mutex_unlock(&ha->vport_lock);
+       ql_dbg(ql_dbg_multiq, base_vha, 0xc00b,
+           "options=%x id=%d rsp_q_in=%p rsp_q_out=%p",
+           rsp->options, rsp->id, rsp->rsp_q_in,
+           rsp->rsp_q_out);
+       ql_dbg(ql_dbg_init, base_vha, 0x00e5,
+           "options=%x id=%d rsp_q_in=%p rsp_q_out=%p",
+           rsp->options, rsp->id, rsp->rsp_q_in,
+           rsp->rsp_q_out);
 
        ret = qla25xx_request_irq(rsp);
        if (ret)
@@ -757,7 +812,8 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
 
        ret = qla25xx_init_rsp_que(base_vha, rsp);
        if (ret != QLA_SUCCESS) {
-               qla_printk(KERN_WARNING, ha, "%s failed\n", __func__);
+               ql_log(ql_log_fatal, base_vha, 0x00e7,
+                   "%s failed.\n", __func__);
                mutex_lock(&ha->vport_lock);
                clear_bit(que_id, ha->rsp_qid_map);
                mutex_unlock(&ha->vport_lock);
index e1138bc..5cbf33a 100644 (file)
@@ -348,6 +348,7 @@ static void
 qla82xx_pci_set_crbwindow_2M(struct qla_hw_data *ha, ulong *off)
 {
        u32 win_read;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        ha->crb_win = CRB_HI(*off);
        writel(ha->crb_win,
@@ -358,9 +359,10 @@ qla82xx_pci_set_crbwindow_2M(struct qla_hw_data *ha, ulong *off)
         */
        win_read = RD_REG_DWORD((void *)(CRB_WINDOW_2M + ha->nx_pcibase));
        if (win_read != ha->crb_win) {
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                   "%s: Written crbwin (0x%x) != Read crbwin (0x%x), "
-                   "off=0x%lx\n", __func__, ha->crb_win, win_read, *off));
+               ql_dbg(ql_dbg_p3p, vha, 0xb000,
+                   "%s: Written crbwin (0x%x) "
+                   "!= Read crbwin (0x%x), off=0x%lx.\n",
+                   ha->crb_win, win_read, *off);
        }
        *off = (*off & MASK(16)) + CRB_INDIRECT_2M + ha->nx_pcibase;
 }
@@ -368,6 +370,7 @@ qla82xx_pci_set_crbwindow_2M(struct qla_hw_data *ha, ulong *off)
 static inline unsigned long
 qla82xx_pci_set_crbwindow(struct qla_hw_data *ha, u64 off)
 {
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
        /* See if we are currently pointing to the region we want to use next */
        if ((off >= QLA82XX_CRB_PCIX_HOST) && (off < QLA82XX_CRB_DDR_NET)) {
                /* No need to change window. PCIX and PCIEregs are in both
@@ -398,9 +401,10 @@ qla82xx_pci_set_crbwindow(struct qla_hw_data *ha, u64 off)
                        return off;
        }
        /* strange address given */
-       qla_printk(KERN_WARNING, ha,
-               "%s: Warning: unm_nic_pci_set_crbwindow called with"
-               " an unknown address(%llx)\n", QLA2XXX_DRIVER_NAME, off);
+       ql_dbg(ql_dbg_p3p, vha, 0xb001,
+           "%x: Warning: unm_nic_pci_set_crbwindow "
+           "called with an unknown address(%llx).\n",
+           QLA2XXX_DRIVER_NAME, off);
        return off;
 }
 
@@ -563,6 +567,7 @@ qla82xx_pci_set_window(struct qla_hw_data *ha, unsigned long long addr)
 {
        int window;
        u32 win_read;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_DDR_NET,
                QLA82XX_ADDR_DDR_NET_MAX)) {
@@ -574,8 +579,8 @@ qla82xx_pci_set_window(struct qla_hw_data *ha, unsigned long long addr)
                win_read = qla82xx_rd_32(ha,
                        ha->mn_win_crb | QLA82XX_PCI_CRBSPACE);
                if ((win_read << 17) != window) {
-                       qla_printk(KERN_WARNING, ha,
-                           "%s: Written MNwin (0x%x) != Read MNwin (0x%x)\n",
+                       ql_dbg(ql_dbg_p3p, vha, 0xb003,
+                           "%s: Written MNwin (0x%x) != Read MNwin (0x%x).\n",
                            __func__, window, win_read);
                }
                addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_DDR_NET;
@@ -583,7 +588,7 @@ qla82xx_pci_set_window(struct qla_hw_data *ha, unsigned long long addr)
                QLA82XX_ADDR_OCM0_MAX)) {
                unsigned int temp1;
                if ((addr & 0x00ff800) == 0xff800) {
-                       qla_printk(KERN_WARNING, ha,
+                       ql_log(ql_log_warn, vha, 0xb004,
                            "%s: QM access not handled.\n", __func__);
                        addr = -1UL;
                }
@@ -596,8 +601,8 @@ qla82xx_pci_set_window(struct qla_hw_data *ha, unsigned long long addr)
                temp1 = ((window & 0x1FF) << 7) |
                    ((window & 0x0FFFE0000) >> 17);
                if (win_read != temp1) {
-                       qla_printk(KERN_WARNING, ha,
-                           "%s: Written OCMwin (0x%x) != Read OCMwin (0x%x)\n",
+                       ql_log(ql_log_warn, vha, 0xb005,
+                           "%s: Written OCMwin (0x%x) != Read OCMwin (0x%x).\n",
                            __func__, temp1, win_read);
                }
                addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_OCM0_2M;
@@ -612,8 +617,8 @@ qla82xx_pci_set_window(struct qla_hw_data *ha, unsigned long long addr)
                win_read = qla82xx_rd_32(ha,
                        ha->ms_win_crb | QLA82XX_PCI_CRBSPACE);
                if (win_read != window) {
-                       qla_printk(KERN_WARNING, ha,
-                           "%s: Written MSwin (0x%x) != Read MSwin (0x%x)\n",
+                       ql_log(ql_log_warn, vha, 0xb006,
+                           "%s: Written MSwin (0x%x) != Read MSwin (0x%x).\n",
                            __func__, window, win_read);
                }
                addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_QDR_NET;
@@ -624,9 +629,9 @@ qla82xx_pci_set_window(struct qla_hw_data *ha, unsigned long long addr)
                 */
                if ((qla82xx_pci_set_window_warning_count++ < 8) ||
                    (qla82xx_pci_set_window_warning_count%64 == 0)) {
-                       qla_printk(KERN_WARNING, ha,
-                           "%s: Warning:%s Unknown address range!\n", __func__,
-                           QLA2XXX_DRIVER_NAME);
+                       ql_log(ql_log_warn, vha, 0xb007,
+                           "%s: Warning:%s Unknown address range!.\n",
+                           __func__, QLA2XXX_DRIVER_NAME);
                }
                addr = -1UL;
        }
@@ -671,6 +676,7 @@ static int qla82xx_pci_mem_read_direct(struct qla_hw_data *ha,
        uint8_t         *mem_ptr = NULL;
        unsigned long   mem_base;
        unsigned long   mem_page;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        write_lock_irqsave(&ha->hw_lock, flags);
 
@@ -682,9 +688,10 @@ static int qla82xx_pci_mem_read_direct(struct qla_hw_data *ha,
        if ((start == -1UL) ||
                (qla82xx_pci_is_same_window(ha, off + size - 1) == 0)) {
                write_unlock_irqrestore(&ha->hw_lock, flags);
-               qla_printk(KERN_ERR, ha,
-                       "%s out of bound pci memory access. "
-                       "offset is 0x%llx\n", QLA2XXX_DRIVER_NAME, off);
+               ql_log(ql_log_fatal, vha, 0xb008,
+                   "%s out of bound pci memory "
+                   "access, offset is 0x%llx.\n",
+                   QLA2XXX_DRIVER_NAME, off);
                return -1;
        }
 
@@ -741,6 +748,7 @@ qla82xx_pci_mem_write_direct(struct qla_hw_data *ha,
        uint8_t         *mem_ptr = NULL;
        unsigned long   mem_base;
        unsigned long   mem_page;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        write_lock_irqsave(&ha->hw_lock, flags);
 
@@ -752,9 +760,10 @@ qla82xx_pci_mem_write_direct(struct qla_hw_data *ha,
        if ((start == -1UL) ||
                (qla82xx_pci_is_same_window(ha, off + size - 1) == 0)) {
                write_unlock_irqrestore(&ha->hw_lock, flags);
-               qla_printk(KERN_ERR, ha,
-                       "%s out of bound pci memory access. "
-                       "offset is 0x%llx\n", QLA2XXX_DRIVER_NAME, off);
+               ql_log(ql_log_fatal, vha, 0xb009,
+                   "%s out of bount memory "
+                   "access, offset is 0x%llx.\n",
+                   QLA2XXX_DRIVER_NAME, off);
                return -1;
        }
 
@@ -855,15 +864,16 @@ qla82xx_wait_rom_busy(struct qla_hw_data *ha)
 {
        long timeout = 0;
        long done = 0 ;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        while (done == 0) {
                done = qla82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_STATUS);
                done &= 4;
                timeout++;
                if (timeout >= rom_max_timeout) {
-                       DEBUG(qla_printk(KERN_INFO, ha,
-                               "%s: Timeout reached waiting for rom busy",
-                               QLA2XXX_DRIVER_NAME));
+                       ql_dbg(ql_dbg_p3p, vha, 0xb00a,
+                           "%s: Timeout reached waiting for rom busy.\n",
+                           QLA2XXX_DRIVER_NAME);
                        return -1;
                }
        }
@@ -875,15 +885,16 @@ qla82xx_wait_rom_done(struct qla_hw_data *ha)
 {
        long timeout = 0;
        long done = 0 ;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        while (done == 0) {
                done = qla82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_STATUS);
                done &= 2;
                timeout++;
                if (timeout >= rom_max_timeout) {
-                       DEBUG(qla_printk(KERN_INFO, ha,
-                               "%s: Timeout reached  waiting for rom done",
-                               QLA2XXX_DRIVER_NAME));
+                       ql_dbg(ql_dbg_p3p, vha, 0xb00b,
+                           "%s: Timeout reached waiting for rom done.\n",
+                           QLA2XXX_DRIVER_NAME);
                        return -1;
                }
        }
@@ -893,15 +904,16 @@ qla82xx_wait_rom_done(struct qla_hw_data *ha)
 static int
 qla82xx_do_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp)
 {
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
+
        qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ADDRESS, addr);
        qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
        qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 3);
        qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, 0xb);
        qla82xx_wait_rom_busy(ha);
        if (qla82xx_wait_rom_done(ha)) {
-               qla_printk(KERN_WARNING, ha,
-                       "%s: Error waiting for rom done\n",
-                       QLA2XXX_DRIVER_NAME);
+               ql_log(ql_log_fatal, vha, 0x00ba,
+                   "Error waiting for rom done.\n");
                return -1;
        }
        /* Reset abyte_cnt and dummy_byte_cnt */
@@ -917,6 +929,7 @@ static int
 qla82xx_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp)
 {
        int ret, loops = 0;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        while ((qla82xx_rom_lock(ha) != 0) && (loops < 50000)) {
                udelay(100);
@@ -924,9 +937,8 @@ qla82xx_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp)
                loops++;
        }
        if (loops >= 50000) {
-               qla_printk(KERN_INFO, ha,
-                       "%s: qla82xx_rom_lock failed\n",
-                       QLA2XXX_DRIVER_NAME);
+               ql_log(ql_log_fatal, vha, 0x00b9,
+                   "Failed to aquire SEM2 lock.\n");
                return -1;
        }
        ret = qla82xx_do_rom_fast_read(ha, addr, valp);
@@ -937,11 +949,12 @@ qla82xx_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp)
 static int
 qla82xx_read_status_reg(struct qla_hw_data *ha, uint32_t *val)
 {
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
        qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_RDSR);
        qla82xx_wait_rom_busy(ha);
        if (qla82xx_wait_rom_done(ha)) {
-               qla_printk(KERN_WARNING, ha,
-                   "Error waiting for rom done\n");
+               ql_log(ql_log_warn, vha, 0xb00c,
+                   "Error waiting for rom done.\n");
                return -1;
        }
        *val = qla82xx_rd_32(ha, QLA82XX_ROMUSB_ROM_RDATA);
@@ -955,6 +968,7 @@ qla82xx_flash_wait_write_finish(struct qla_hw_data *ha)
        uint32_t done = 1 ;
        uint32_t val;
        int ret = 0;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 0);
        while ((done != 0) && (ret == 0)) {
@@ -964,8 +978,8 @@ qla82xx_flash_wait_write_finish(struct qla_hw_data *ha)
                udelay(10);
                cond_resched();
                if (timeout >= 50000) {
-                       qla_printk(KERN_WARNING, ha,
-                           "Timeout reached  waiting for write finish");
+                       ql_log(ql_log_warn, vha, 0xb00d,
+                           "Timeout reached waiting for write finish.\n");
                        return -1;
                }
        }
@@ -992,13 +1006,14 @@ qla82xx_flash_set_write_enable(struct qla_hw_data *ha)
 static int
 qla82xx_write_status_reg(struct qla_hw_data *ha, uint32_t val)
 {
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
        if (qla82xx_flash_set_write_enable(ha))
                return -1;
        qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_WDATA, val);
        qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, 0x1);
        if (qla82xx_wait_rom_done(ha)) {
-               qla_printk(KERN_WARNING, ha,
-                   "Error waiting for rom done\n");
+               ql_log(ql_log_warn, vha, 0xb00e,
+                   "Error waiting for rom done.\n");
                return -1;
        }
        return qla82xx_flash_wait_write_finish(ha);
@@ -1007,10 +1022,11 @@ qla82xx_write_status_reg(struct qla_hw_data *ha, uint32_t val)
 static int
 qla82xx_write_disable_flash(struct qla_hw_data *ha)
 {
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
        qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_WRDI);
        if (qla82xx_wait_rom_done(ha)) {
-               qla_printk(KERN_WARNING, ha,
-                   "Error waiting for rom done\n");
+               ql_log(ql_log_warn, vha, 0xb00f,
+                   "Error waiting for rom done.\n");
                return -1;
        }
        return 0;
@@ -1020,13 +1036,16 @@ static int
 ql82xx_rom_lock_d(struct qla_hw_data *ha)
 {
        int loops = 0;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
+
        while ((qla82xx_rom_lock(ha) != 0) && (loops < 50000)) {
                udelay(100);
                cond_resched();
                loops++;
        }
        if (loops >= 50000) {
-               qla_printk(KERN_WARNING, ha, "ROM lock failed\n");
+               ql_log(ql_log_warn, vha, 0xb010,
+                   "ROM lock failed.\n");
                return -1;
        }
        return 0;;
@@ -1037,10 +1056,12 @@ qla82xx_write_flash_dword(struct qla_hw_data *ha, uint32_t flashaddr,
        uint32_t data)
 {
        int ret = 0;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        ret = ql82xx_rom_lock_d(ha);
        if (ret < 0) {
-               qla_printk(KERN_WARNING, ha, "ROM Lock failed\n");
+               ql_log(ql_log_warn, vha, 0xb011,
+                   "ROM lock failed.\n");
                return ret;
        }
 
@@ -1053,8 +1074,8 @@ qla82xx_write_flash_dword(struct qla_hw_data *ha, uint32_t flashaddr,
        qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_PP);
        qla82xx_wait_rom_busy(ha);
        if (qla82xx_wait_rom_done(ha)) {
-               qla_printk(KERN_WARNING, ha,
-                       "Error waiting for rom done\n");
+               ql_log(ql_log_warn, vha, 0xb012,
+                   "Error waiting for rom done.\n");
                ret = -1;
                goto done_write;
        }
@@ -1159,8 +1180,8 @@ qla82xx_pinit_from_rom(scsi_qla_host_t *vha)
         */
        if (qla82xx_rom_fast_read(ha, 0, &n) != 0 || n != 0xcafecafeUL ||
            qla82xx_rom_fast_read(ha, 4, &n) != 0) {
-               qla_printk(KERN_WARNING, ha,
-                   "[ERROR] Reading crb_init area: n: %08x\n", n);
+               ql_log(ql_log_fatal, vha, 0x006e,
+                   "Error Reading crb_init area: n: %08x.\n", n);
                return -1;
        }
 
@@ -1172,20 +1193,18 @@ qla82xx_pinit_from_rom(scsi_qla_host_t *vha)
 
        /* number of addr/value pair should not exceed 1024 enteries */
        if (n  >= 1024) {
-               qla_printk(KERN_WARNING, ha,
-                   "%s: %s:n=0x%x [ERROR] Card flash not initialized.\n",
-                   QLA2XXX_DRIVER_NAME, __func__, n);
+               ql_log(ql_log_fatal, vha, 0x0071,
+                   "Card flash not initialized:n=0x%x.\n", n);
                return -1;
        }
 
-       qla_printk(KERN_INFO, ha,
-           "%s: %d CRB init values found in ROM.\n", QLA2XXX_DRIVER_NAME, n);
+       ql_log(ql_log_info, vha, 0x0072,
+           "%d CRB init values found in ROM.\n", n);
 
        buf = kmalloc(n * sizeof(struct crb_addr_pair), GFP_KERNEL);
        if (buf == NULL) {
-               qla_printk(KERN_WARNING, ha,
-                   "%s: [ERROR] Unable to malloc memory.\n",
-                   QLA2XXX_DRIVER_NAME);
+               ql_log(ql_log_fatal, vha, 0x010c,
+                   "Unable to allocate memory.\n");
                return -1;
        }
 
@@ -1236,9 +1255,8 @@ qla82xx_pinit_from_rom(scsi_qla_host_t *vha)
                        continue;
 
                if (off == ADDR_ERROR) {
-                       qla_printk(KERN_WARNING, ha,
-                           "%s: [ERROR] Unknown addr: 0x%08lx\n",
-                           QLA2XXX_DRIVER_NAME, buf[i].addr);
+                       ql_log(ql_log_fatal, vha, 0x0116,
+                           "Unknow addr: 0x%08lx.\n", buf[i].addr);
                        continue;
                }
 
@@ -1370,7 +1388,7 @@ qla82xx_pci_mem_write_2M(struct qla_hw_data *ha,
                if (j >= MAX_CTL_CHECK) {
                        if (printk_ratelimit())
                                dev_err(&ha->pdev->dev,
-                                   "failed to write through agent\n");
+                                   "failed to write through agent.\n");
                        ret = -1;
                        break;
                }
@@ -1460,7 +1478,7 @@ qla82xx_pci_mem_read_2M(struct qla_hw_data *ha,
                if (j >= MAX_CTL_CHECK) {
                        if (printk_ratelimit())
                                dev_err(&ha->pdev->dev,
-                                   "failed to read through agent\n");
+                                   "failed to read through agent.\n");
                        break;
                }
 
@@ -1633,17 +1651,15 @@ qla82xx_iospace_config(struct qla_hw_data *ha)
        uint32_t len = 0;
 
        if (pci_request_regions(ha->pdev, QLA2XXX_DRIVER_NAME)) {
-               qla_printk(KERN_WARNING, ha,
-                       "Failed to reserve selected regions (%s)\n",
-                       pci_name(ha->pdev));
+               ql_log_pci(ql_log_fatal, ha->pdev, 0x000c,
+                   "Failed to reserver selected regions.\n");
                goto iospace_error_exit;
        }
 
        /* Use MMIO operations for all accesses. */
        if (!(pci_resource_flags(ha->pdev, 0) & IORESOURCE_MEM)) {
-               qla_printk(KERN_ERR, ha,
-                       "region #0 not an MMIO resource (%s), aborting\n",
-                       pci_name(ha->pdev));
+               ql_log_pci(ql_log_fatal, ha->pdev, 0x000d,
+                   "Region #0 not an MMIO resource, aborting.\n");
                goto iospace_error_exit;
        }
 
@@ -1651,9 +1667,8 @@ qla82xx_iospace_config(struct qla_hw_data *ha)
        ha->nx_pcibase =
            (unsigned long)ioremap(pci_resource_start(ha->pdev, 0), len);
        if (!ha->nx_pcibase) {
-               qla_printk(KERN_ERR, ha,
-                   "cannot remap pcibase MMIO (%s), aborting\n",
-                   pci_name(ha->pdev));
+               ql_log_pci(ql_log_fatal, ha->pdev, 0x000e,
+                   "Cannot remap pcibase MMIO, aborting.\n");
                pci_release_regions(ha->pdev);
                goto iospace_error_exit;
        }
@@ -1667,9 +1682,8 @@ qla82xx_iospace_config(struct qla_hw_data *ha)
                    (unsigned long)ioremap((pci_resource_start(ha->pdev, 4) +
                    (ha->pdev->devfn << 12)), 4);
                if (!ha->nxdb_wr_ptr) {
-                       qla_printk(KERN_ERR, ha,
-                           "cannot remap MMIO (%s), aborting\n",
-                           pci_name(ha->pdev));
+                       ql_log_pci(ql_log_fatal, ha->pdev, 0x000f,
+                           "Cannot remap MMIO, aborting.\n");
                        pci_release_regions(ha->pdev);
                        goto iospace_error_exit;
                }
@@ -1687,6 +1701,16 @@ qla82xx_iospace_config(struct qla_hw_data *ha)
 
        ha->max_req_queues = ha->max_rsp_queues = 1;
        ha->msix_count = ha->max_rsp_queues + 1;
+       ql_dbg_pci(ql_dbg_multiq, ha->pdev, 0xc006,
+           "nx_pci_base=%p iobase=%p "
+           "max_req_queues=%d msix_count=%d.\n",
+           ha->nx_pcibase, ha->iobase,
+           ha->max_req_queues, ha->msix_count);
+       ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0010,
+           "nx_pci_base=%p iobase=%p "
+           "max_req_queues=%d msix_count=%d.\n",
+           ha->nx_pcibase, ha->iobase,
+           ha->max_req_queues, ha->msix_count);
        return 0;
 
 iospace_error_exit:
@@ -1712,6 +1736,9 @@ qla82xx_pci_config(scsi_qla_host_t *vha)
        pci_set_master(ha->pdev);
        ret = pci_set_mwi(ha->pdev);
        ha->chip_revision = ha->pdev->revision;
+       ql_dbg(ql_dbg_init, vha, 0x0043,
+           "Chip revision:%ld.\n",
+           ha->chip_revision);
        return 0;
 }
 
@@ -1877,6 +1904,7 @@ qla82xx_check_cmdpeg_state(struct qla_hw_data *ha)
 {
        u32 val = 0;
        int retries = 60;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        do {
                read_lock(&ha->hw_lock);
@@ -1892,15 +1920,15 @@ qla82xx_check_cmdpeg_state(struct qla_hw_data *ha)
                default:
                        break;
                }
-               qla_printk(KERN_WARNING, ha,
-                       "CRB_CMDPEG_STATE: 0x%x and retries: 0x%x\n",
-                       val, retries);
+               ql_log(ql_log_info, vha, 0x00a8,
+                   "CRB_CMDPEG_STATE: 0x%x and retries:0x%x.\n",
+                   val, retries);
 
                msleep(500);
 
        } while (--retries);
 
-       qla_printk(KERN_INFO, ha,
+       ql_log(ql_log_fatal, vha, 0x00a9,
            "Cmd Peg initialization failed: 0x%x.\n", val);
 
        val = qla82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_PEGTUNE_DONE);
@@ -1915,6 +1943,7 @@ qla82xx_check_rcvpeg_state(struct qla_hw_data *ha)
 {
        u32 val = 0;
        int retries = 60;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        do {
                read_lock(&ha->hw_lock);
@@ -1930,17 +1959,16 @@ qla82xx_check_rcvpeg_state(struct qla_hw_data *ha)
                default:
                        break;
                }
-
-               qla_printk(KERN_WARNING, ha,
-                       "CRB_RCVPEG_STATE: 0x%x and retries: 0x%x\n",
-                       val, retries);
+               ql_log(ql_log_info, vha, 0x00ab,
+                   "CRB_RCVPEG_STATE: 0x%x and retries: 0x%x.\n",
+                   val, retries);
 
                msleep(500);
 
        } while (--retries);
 
-       qla_printk(KERN_INFO, ha,
-               "Rcv Peg initialization failed: 0x%x.\n", val);
+       ql_log(ql_log_fatal, vha, 0x00ac,
+           "Rcv Peg initializatin failed: 0x%x.\n", val);
        read_lock(&ha->hw_lock);
        qla82xx_wr_32(ha, CRB_RCVPEG_STATE, PHAN_INITIALIZE_FAILED);
        read_unlock(&ha->hw_lock);
@@ -1989,13 +2017,11 @@ qla82xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
        }
 
        if (ha->mcp) {
-               DEBUG3_11(printk(KERN_INFO "%s(%ld): "
-                       "Got mailbox completion. cmd=%x.\n",
-                       __func__, vha->host_no, ha->mcp->mb[0]));
+               ql_dbg(ql_dbg_async, vha, 0x5052,
+                   "Got mailbox completion. cmd=%x.\n", ha->mcp->mb[0]);
        } else {
-               qla_printk(KERN_INFO, ha,
-                       "%s(%ld): MBX pointer ERROR!\n",
-                       __func__, vha->host_no);
+               ql_dbg(ql_dbg_async, vha, 0x5053,
+                   "MBX pointer ERROR.\n");
        }
 }
 
@@ -2019,13 +2045,13 @@ qla82xx_intr_handler(int irq, void *dev_id)
        int status = 0, status1 = 0;
        unsigned long   flags;
        unsigned long   iter;
-       uint32_t        stat;
+       uint32_t        stat = 0;
        uint16_t        mb[4];
 
        rsp = (struct rsp_que *) dev_id;
        if (!rsp) {
                printk(KERN_INFO
-                       "%s(): NULL response queue pointer\n", __func__);
+                       "%s(): NULL response queue pointer.\n", __func__);
                return IRQ_NONE;
        }
        ha = rsp->hw;
@@ -2075,9 +2101,9 @@ qla82xx_intr_handler(int irq, void *dev_id)
                                qla24xx_process_response_queue(vha, rsp);
                                break;
                        default:
-                               DEBUG2(printk("scsi(%ld): "
-                                       " Unrecognized interrupt type (%d).\n",
-                                       vha->host_no, stat & 0xff));
+                               ql_dbg(ql_dbg_async, vha, 0x5054,
+                                   "Unrecognized interrupt type (%d).\n",
+                                   stat & 0xff);
                                break;
                        }
                }
@@ -2089,8 +2115,8 @@ qla82xx_intr_handler(int irq, void *dev_id)
 
 #ifdef QL_DEBUG_LEVEL_17
        if (!irq && ha->flags.eeh_busy)
-               qla_printk(KERN_WARNING, ha,
-                   "isr: status %x, cmd_flags %lx, mbox_int %x, stat %x\n",
+               ql_log(ql_log_warn, vha, 0x503d,
+                   "isr:status %x, cmd_flags %lx, mbox_int %x, stat %x.\n",
                    status, ha->mbx_cmd_flags, ha->flags.mbox_int, stat);
 #endif
 
@@ -2111,13 +2137,13 @@ qla82xx_msix_default(int irq, void *dev_id)
        struct device_reg_82xx __iomem *reg;
        int status = 0;
        unsigned long flags;
-       uint32_t stat;
+       uint32_t stat = 0;
        uint16_t mb[4];
 
        rsp = (struct rsp_que *) dev_id;
        if (!rsp) {
                printk(KERN_INFO
-                       "%s(): NULL response queue pointer\n", __func__);
+                       "%s(): NULL response queue pointer.\n", __func__);
                return IRQ_NONE;
        }
        ha = rsp->hw;
@@ -2149,9 +2175,9 @@ qla82xx_msix_default(int irq, void *dev_id)
                                qla24xx_process_response_queue(vha, rsp);
                                break;
                        default:
-                               DEBUG2(printk("scsi(%ld): "
-                                       " Unrecognized interrupt type (%d).\n",
-                                       vha->host_no, stat & 0xff));
+                               ql_dbg(ql_dbg_async, vha, 0x5041,
+                                   "Unrecognized interrupt type (%d).\n",
+                                   stat & 0xff);
                                break;
                        }
                }
@@ -2162,9 +2188,9 @@ qla82xx_msix_default(int irq, void *dev_id)
 
 #ifdef QL_DEBUG_LEVEL_17
        if (!irq && ha->flags.eeh_busy)
-               qla_printk(KERN_WARNING, ha,
-                       "isr: status %x, cmd_flags %lx, mbox_int %x, stat %x\n",
-                       status, ha->mbx_cmd_flags, ha->flags.mbox_int, stat);
+               ql_log(ql_log_warn, vha, 0x5044,
+                   "isr:status %x, cmd_flags %lx, mbox_int %x, stat %x.\n",
+                   status, ha->mbx_cmd_flags, ha->flags.mbox_int, stat);
 #endif
 
        if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
@@ -2186,7 +2212,7 @@ qla82xx_msix_rsp_q(int irq, void *dev_id)
        rsp = (struct rsp_que *) dev_id;
        if (!rsp) {
                printk(KERN_INFO
-                       "%s(): NULL response queue pointer\n", __func__);
+                       "%s(): NULL response queue pointer.\n", __func__);
                return IRQ_NONE;
        }
 
@@ -2215,7 +2241,7 @@ qla82xx_poll(int irq, void *dev_id)
        rsp = (struct rsp_que *) dev_id;
        if (!rsp) {
                printk(KERN_INFO
-                       "%s(): NULL response queue pointer\n", __func__);
+                       "%s(): NULL response queue pointer.\n", __func__);
                return;
        }
        ha = rsp->hw;
@@ -2245,9 +2271,9 @@ qla82xx_poll(int irq, void *dev_id)
                        qla24xx_process_response_queue(vha, rsp);
                        break;
                default:
-                       DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
-                               "(%d).\n",
-                               vha->host_no, stat & 0xff));
+                       ql_dbg(ql_dbg_p3p, vha, 0xb013,
+                           "Unrecognized interrupt type (%d).\n",
+                           stat * 0xff);
                        break;
                }
        }
@@ -2347,9 +2373,8 @@ qla82xx_set_rst_ready(struct qla_hw_data *ha)
                drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
        }
        drv_state |= (QLA82XX_DRVST_RST_RDY << (ha->portnum * 4));
-       qla_printk(KERN_INFO, ha,
-               "%s(%ld):drv_state = 0x%x\n",
-               __func__, vha->host_no, drv_state);
+       ql_log(ql_log_info, vha, 0x00bb,
+           "drv_state = 0x%x.\n", drv_state);
        qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state);
 }
 
@@ -2392,8 +2417,8 @@ qla82xx_load_fw(scsi_qla_host_t *vha)
        struct qla_hw_data *ha = vha->hw;
 
        if (qla82xx_pinit_from_rom(vha) != QLA_SUCCESS) {
-               qla_printk(KERN_ERR, ha,
-                       "%s: Error during CRB Initialization\n", __func__);
+               ql_log(ql_log_fatal, vha, 0x009f,
+                   "Error during CRB initialization.\n");
                return QLA_FUNCTION_FAILED;
        }
        udelay(500);
@@ -2411,27 +2436,27 @@ qla82xx_load_fw(scsi_qla_host_t *vha)
        if (ql2xfwloadbin == 2)
                goto try_blob_fw;
 
-       qla_printk(KERN_INFO, ha,
-               "Attempting to load firmware from flash\n");
+       ql_log(ql_log_info, vha, 0x00a0,
+           "Attempting to load firmware from flash.\n");
 
        if (qla82xx_fw_load_from_flash(ha) == QLA_SUCCESS) {
-               qla_printk(KERN_ERR, ha,
-                   "Firmware loaded successfully from flash\n");
+               ql_log(ql_log_info, vha, 0x00a1,
+                   "Firmware loaded successully from flash.\n");
                return QLA_SUCCESS;
        } else {
-               qla_printk(KERN_ERR, ha,
-                   "Firmware load from flash failed\n");
+               ql_log(ql_log_warn, vha, 0x0108,
+                   "Firmware load from flash failed.\n");
        }
 
 try_blob_fw:
-       qla_printk(KERN_INFO, ha,
-           "Attempting to load firmware from blob\n");
+       ql_log(ql_log_info, vha, 0x00a2,
+           "Attempting to load firmware from blob.\n");
 
        /* Load firmware blob. */
        blob = ha->hablob = qla2x00_request_firmware(vha);
        if (!blob) {
-               qla_printk(KERN_ERR, ha,
-                       "Firmware image not present.\n");
+               ql_log(ql_log_fatal, vha, 0x00a3,
+                   "Firmware image not preset.\n");
                goto fw_load_failed;
        }
 
@@ -2441,20 +2466,19 @@ try_blob_fw:
                /* Fallback to URI format */
                if (qla82xx_validate_firmware_blob(vha,
                        QLA82XX_UNIFIED_ROMIMAGE)) {
-                       qla_printk(KERN_ERR, ha,
-                               "No valid firmware image found!!!");
+                       ql_log(ql_log_fatal, vha, 0x00a4,
+                           "No valid firmware image found.\n");
                        return QLA_FUNCTION_FAILED;
                }
        }
 
        if (qla82xx_fw_load_from_blob(ha) == QLA_SUCCESS) {
-               qla_printk(KERN_ERR, ha,
-                       "%s: Firmware loaded successfully "
-                       " from binary blob\n", __func__);
+               ql_log(ql_log_info, vha, 0x00a5,
+                   "Firmware loaded successfully from binary blob.\n");
                return QLA_SUCCESS;
        } else {
-               qla_printk(KERN_ERR, ha,
-                   "Firmware load failed from binary blob\n");
+               ql_log(ql_log_fatal, vha, 0x00a6,
+                   "Firmware load failed for binary blob.\n");
                blob->fw = NULL;
                blob = NULL;
                goto fw_load_failed;
@@ -2486,15 +2510,15 @@ qla82xx_start_firmware(scsi_qla_host_t *vha)
        qla82xx_wr_32(ha, QLA82XX_PEG_HALT_STATUS2, 0);
 
        if (qla82xx_load_fw(vha) != QLA_SUCCESS) {
-               qla_printk(KERN_INFO, ha,
-                       "%s: Error trying to start fw!\n", __func__);
+               ql_log(ql_log_fatal, vha, 0x00a7,
+                   "Error trying to start fw.\n");
                return QLA_FUNCTION_FAILED;
        }
 
        /* Handshake with the card before we register the devices. */
        if (qla82xx_check_cmdpeg_state(ha) != QLA_SUCCESS) {
-               qla_printk(KERN_INFO, ha,
-                       "%s: Error during card handshake!\n", __func__);
+               ql_log(ql_log_fatal, vha, 0x00aa,
+                   "Error during card handshake.\n");
                return QLA_FUNCTION_FAILED;
        }
 
@@ -2663,8 +2687,11 @@ qla82xx_start_scsi(srb_t *sp)
        /* Send marker if required */
        if (vha->marker_needed != 0) {
                if (qla2x00_marker(vha, req,
-                       rsp, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS)
+                       rsp, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) {
+                       ql_log(ql_log_warn, vha, 0x300c,
+                           "qla2x00_marker failed for cmd=%p.\n", cmd);
                        return QLA_FUNCTION_FAILED;
+               }
                vha->marker_needed = 0;
        }
 
@@ -2701,8 +2728,13 @@ qla82xx_start_scsi(srb_t *sp)
                uint16_t i;
 
                more_dsd_lists = qla82xx_calc_dsd_lists(tot_dsds);
-               if ((more_dsd_lists + ha->gbl_dsd_inuse) >= NUM_DSD_CHAIN)
+               if ((more_dsd_lists + ha->gbl_dsd_inuse) >= NUM_DSD_CHAIN) {
+                       ql_dbg(ql_dbg_io, vha, 0x300d,
+                           "Num of DSD list %d is than %d for cmd=%p.\n",
+                           more_dsd_lists + ha->gbl_dsd_inuse, NUM_DSD_CHAIN,
+                           cmd);
                        goto queuing_error;
+               }
 
                if (more_dsd_lists <= ha->gbl_dsd_avail)
                        goto sufficient_dsds;
@@ -2711,13 +2743,20 @@ qla82xx_start_scsi(srb_t *sp)
 
                for (i = 0; i < more_dsd_lists; i++) {
                        dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC);
-                       if (!dsd_ptr)
+                       if (!dsd_ptr) {
+                               ql_log(ql_log_fatal, vha, 0x300e,
+                                   "Failed to allocate memory for dsd_dma "
+                                   "for cmd=%p.\n", cmd);
                                goto queuing_error;
+                       }
 
                        dsd_ptr->dsd_addr = dma_pool_alloc(ha->dl_dma_pool,
                                GFP_ATOMIC, &dsd_ptr->dsd_list_dma);
                        if (!dsd_ptr->dsd_addr) {
                                kfree(dsd_ptr);
+                               ql_log(ql_log_fatal, vha, 0x300f,
+                                   "Failed to allocate memory for dsd_addr "
+                                   "for cmd=%p.\n", cmd);
                                goto queuing_error;
                        }
                        list_add_tail(&dsd_ptr->list, &ha->gbl_dsd_list);
@@ -2742,17 +2781,16 @@ sufficient_dsds:
 
                ctx = sp->ctx = mempool_alloc(ha->ctx_mempool, GFP_ATOMIC);
                if (!sp->ctx) {
-                       DEBUG(printk(KERN_INFO
-                               "%s(%ld): failed to allocate"
-                               " ctx.\n", __func__, vha->host_no));
+                       ql_log(ql_log_fatal, vha, 0x3010,
+                           "Failed to allocate ctx for cmd=%p.\n", cmd);
                        goto queuing_error;
                }
                memset(ctx, 0, sizeof(struct ct6_dsd));
                ctx->fcp_cmnd = dma_pool_alloc(ha->fcp_cmnd_dma_pool,
                        GFP_ATOMIC, &ctx->fcp_cmnd_dma);
                if (!ctx->fcp_cmnd) {
-                       DEBUG2_3(printk("%s(%ld): failed to allocate"
-                               " fcp_cmnd.\n", __func__, vha->host_no));
+                       ql_log(ql_log_fatal, vha, 0x3011,
+                           "Failed to allocate fcp_cmnd for cmd=%p.\n", cmd);
                        goto queuing_error_fcp_cmnd;
                }
 
@@ -2766,6 +2804,9 @@ sufficient_dsds:
                                /* SCSI command bigger than 16 bytes must be
                                 * multiple of 4
                                 */
+                               ql_log(ql_log_warn, vha, 0x3012,
+                                   "scsi cmd len %d not multiple of 4 "
+                                   "for cmd=%p.\n", cmd->cmd_len, cmd);
                                goto queuing_error_fcp_cmnd;
                        }
                        ctx->fcp_cmnd_len = 12 + cmd->cmd_len + 4;
@@ -2845,7 +2886,7 @@ sufficient_dsds:
                cmd_pkt->entry_status = (uint8_t) rsp->id;
        } else {
                struct cmd_type_7 *cmd_pkt;
-               req_cnt = qla24xx_calc_iocbs(tot_dsds);
+               req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
                if (req->cnt < (req_cnt + 2)) {
                        cnt = (uint16_t)RD_REG_DWORD_RELAXED(
                            &reg->req_q_out[0]);
@@ -2979,8 +3020,8 @@ qla82xx_read_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
        /* Dword reads to flash. */
        for (i = 0; i < length/4; i++, faddr += 4) {
                if (qla82xx_rom_fast_read(ha, faddr, &val)) {
-                       qla_printk(KERN_WARNING, ha,
-                           "Do ROM fast read failed\n");
+                       ql_log(ql_log_warn, vha, 0x0106,
+                           "Do ROM fast read failed.\n");
                        goto done_read;
                }
                dwptr[i] = __constant_cpu_to_le32(val);
@@ -2994,10 +3035,12 @@ qla82xx_unprotect_flash(struct qla_hw_data *ha)
 {
        int ret;
        uint32_t val;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        ret = ql82xx_rom_lock_d(ha);
        if (ret < 0) {
-               qla_printk(KERN_WARNING, ha, "ROM Lock failed\n");
+               ql_log(ql_log_warn, vha, 0xb014,
+                   "ROM Lock failed.\n");
                return ret;
        }
 
@@ -3013,7 +3056,8 @@ qla82xx_unprotect_flash(struct qla_hw_data *ha)
        }
 
        if (qla82xx_write_disable_flash(ha) != 0)
-               qla_printk(KERN_WARNING, ha, "Write disable failed\n");
+               ql_log(ql_log_warn, vha, 0xb015,
+                   "Write disable failed.\n");
 
 done_unprotect:
        qla82xx_rom_unlock(ha);
@@ -3025,10 +3069,12 @@ qla82xx_protect_flash(struct qla_hw_data *ha)
 {
        int ret;
        uint32_t val;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        ret = ql82xx_rom_lock_d(ha);
        if (ret < 0) {
-               qla_printk(KERN_WARNING, ha, "ROM Lock failed\n");
+               ql_log(ql_log_warn, vha, 0xb016,
+                   "ROM Lock failed.\n");
                return ret;
        }
 
@@ -3040,10 +3086,12 @@ qla82xx_protect_flash(struct qla_hw_data *ha)
        /* LOCK all sectors */
        ret = qla82xx_write_status_reg(ha, val);
        if (ret < 0)
-               qla_printk(KERN_WARNING, ha, "Write status register failed\n");
+               ql_log(ql_log_warn, vha, 0xb017,
+                   "Write status register failed.\n");
 
        if (qla82xx_write_disable_flash(ha) != 0)
-               qla_printk(KERN_WARNING, ha, "Write disable failed\n");
+               ql_log(ql_log_warn, vha, 0xb018,
+                   "Write disable failed.\n");
 done_protect:
        qla82xx_rom_unlock(ha);
        return ret;
@@ -3053,10 +3101,12 @@ static int
 qla82xx_erase_sector(struct qla_hw_data *ha, int addr)
 {
        int ret = 0;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        ret = ql82xx_rom_lock_d(ha);
        if (ret < 0) {
-               qla_printk(KERN_WARNING, ha, "ROM Lock failed\n");
+               ql_log(ql_log_warn, vha, 0xb019,
+                   "ROM Lock failed.\n");
                return ret;
        }
 
@@ -3066,8 +3116,8 @@ qla82xx_erase_sector(struct qla_hw_data *ha, int addr)
        qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_SE);
 
        if (qla82xx_wait_rom_done(ha)) {
-               qla_printk(KERN_WARNING, ha,
-                   "Error waiting for rom done\n");
+               ql_log(ql_log_warn, vha, 0xb01a,
+                   "Error waiting for rom done.\n");
                ret = -1;
                goto done;
        }
@@ -3110,10 +3160,10 @@ qla82xx_write_flash_data(struct scsi_qla_host *vha, uint32_t *dwptr,
                optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
                    &optrom_dma, GFP_KERNEL);
                if (!optrom) {
-                       qla_printk(KERN_DEBUG, ha,
-                               "Unable to allocate memory for optrom "
-                               "burst write (%x KB).\n",
-                               OPTROM_BURST_SIZE / 1024);
+                       ql_log(ql_log_warn, vha, 0xb01b,
+                           "Unable to allocate memory "
+                           "for optron burst write (%x KB).\n",
+                           OPTROM_BURST_SIZE / 1024);
                }
        }
 
@@ -3122,8 +3172,8 @@ qla82xx_write_flash_data(struct scsi_qla_host *vha, uint32_t *dwptr,
 
        ret = qla82xx_unprotect_flash(ha);
        if (ret) {
-               qla_printk(KERN_WARNING, ha,
-                       "Unable to unprotect flash for update.\n");
+               ql_log(ql_log_warn, vha, 0xb01c,
+                   "Unable to unprotect flash for update.\n");
                goto write_done;
        }
 
@@ -3133,9 +3183,9 @@ qla82xx_write_flash_data(struct scsi_qla_host *vha, uint32_t *dwptr,
 
                        ret = qla82xx_erase_sector(ha, faddr);
                        if (ret) {
-                               DEBUG9(qla_printk(KERN_ERR, ha,
-                                   "Unable to erase sector: "
-                                   "address=%x.\n", faddr));
+                               ql_log(ql_log_warn, vha, 0xb01d,
+                                   "Unable to erase sector: address=%x.\n",
+                                   faddr);
                                break;
                        }
                }
@@ -3149,12 +3199,12 @@ qla82xx_write_flash_data(struct scsi_qla_host *vha, uint32_t *dwptr,
                            (ha->flash_data_off | faddr),
                            OPTROM_BURST_DWORDS);
                        if (ret != QLA_SUCCESS) {
-                               qla_printk(KERN_WARNING, ha,
+                               ql_log(ql_log_warn, vha, 0xb01e,
                                    "Unable to burst-write optrom segment "
                                    "(%x/%x/%llx).\n", ret,
                                    (ha->flash_data_off | faddr),
                                    (unsigned long long)optrom_dma);
-                               qla_printk(KERN_WARNING, ha,
+                               ql_log(ql_log_warn, vha, 0xb01f,
                                    "Reverting to slow-write.\n");
 
                                dma_free_coherent(&ha->pdev->dev,
@@ -3171,16 +3221,16 @@ qla82xx_write_flash_data(struct scsi_qla_host *vha, uint32_t *dwptr,
                ret = qla82xx_write_flash_dword(ha, faddr,
                    cpu_to_le32(*dwptr));
                if (ret) {
-                       DEBUG9(printk(KERN_DEBUG "%s(%ld) Unable to program"
-                           "flash address=%x data=%x.\n", __func__,
-                           ha->host_no, faddr, *dwptr));
+                       ql_dbg(ql_dbg_p3p, vha, 0xb020,
+                           "Unable to program flash address=%x data=%x.\n",
+                           faddr, *dwptr);
                        break;
                }
        }
 
        ret = qla82xx_protect_flash(ha);
        if (ret)
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0xb021,
                    "Unable to protect flash after update.\n");
 write_done:
        if (optrom)
@@ -3244,9 +3294,12 @@ qla82xx_start_iocbs(srb_t *sp)
 
 void qla82xx_rom_lock_recovery(struct qla_hw_data *ha)
 {
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
+
        if (qla82xx_rom_lock(ha))
                /* Someone else is holding the lock. */
-               qla_printk(KERN_INFO, ha, "Resetting rom_lock\n");
+               ql_log(ql_log_info, vha, 0xb022,
+                   "Resetting rom_lock.\n");
 
        /*
         * Either we got the lock, or someone
@@ -3313,7 +3366,8 @@ qla82xx_device_bootstrap(scsi_qla_host_t *vha)
 
 dev_initialize:
        /* set to DEV_INITIALIZING */
-       qla_printk(KERN_INFO, ha, "HW State: INITIALIZING\n");
+       ql_log(ql_log_info, vha, 0x009e,
+           "HW State: INITIALIZING.\n");
        qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_INITIALIZING);
 
        /* Driver that sets device state to initializating sets IDC version */
@@ -3324,14 +3378,16 @@ dev_initialize:
        qla82xx_idc_lock(ha);
 
        if (rval != QLA_SUCCESS) {
-               qla_printk(KERN_INFO, ha, "HW State: FAILED\n");
+               ql_log(ql_log_fatal, vha, 0x00ad,
+                   "HW State: FAILED.\n");
                qla82xx_clear_drv_active(ha);
                qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_FAILED);
                return rval;
        }
 
 dev_ready:
-       qla_printk(KERN_INFO, ha, "HW State: READY\n");
+       ql_log(ql_log_info, vha, 0x00ae,
+           "HW State: READY.\n");
        qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_READY);
 
        return QLA_SUCCESS;
@@ -3376,15 +3432,15 @@ qla82xx_need_qsnt_handler(scsi_qla_host_t *vha)
                        /* quiescence timeout, other functions didn't ack
                         * changing the state to DEV_READY
                         */
-                       qla_printk(KERN_INFO, ha,
-                           "%s: QUIESCENT TIMEOUT\n", QLA2XXX_DRIVER_NAME);
-                       qla_printk(KERN_INFO, ha,
-                           "DRV_ACTIVE:%d DRV_STATE:%d\n", drv_active,
-                           drv_state);
+                       ql_log(ql_log_info, vha, 0xb023,
+                           "%s : QUIESCENT TIMEOUT.\n", QLA2XXX_DRIVER_NAME);
+                       ql_log(ql_log_info, vha, 0xb024,
+                           "DRV_ACTIVE:%d DRV_STATE:%d.\n",
+                           drv_active, drv_state);
                        qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
-                                               QLA82XX_DEV_READY);
-                       qla_printk(KERN_INFO, ha,
-                           "HW State: DEV_READY\n");
+                           QLA82XX_DEV_READY);
+                       ql_log(ql_log_info, vha, 0xb025,
+                           "HW State: DEV_READY.\n");
                        qla82xx_idc_unlock(ha);
                        qla2x00_perform_loop_resync(vha);
                        qla82xx_idc_lock(ha);
@@ -3404,7 +3460,8 @@ qla82xx_need_qsnt_handler(scsi_qla_host_t *vha)
        dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
        /* everyone acked so set the state to DEV_QUIESCENCE */
        if (dev_state == QLA82XX_DEV_NEED_QUIESCENT) {
-               qla_printk(KERN_INFO, ha, "HW State: DEV_QUIESCENT\n");
+               ql_log(ql_log_info, vha, 0xb026,
+                   "HW State: DEV_QUIESCENT.\n");
                qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_QUIESCENT);
        }
 }
@@ -3441,7 +3498,8 @@ qla82xx_dev_failed_handler(scsi_qla_host_t *vha)
        struct qla_hw_data *ha = vha->hw;
 
        /* Disable the board */
-       qla_printk(KERN_INFO, ha, "Disabling the board\n");
+       ql_log(ql_log_fatal, vha, 0x00b8,
+           "Disabling the board.\n");
 
        qla82xx_idc_lock(ha);
        qla82xx_clear_drv_active(ha);
@@ -3492,8 +3550,8 @@ qla82xx_need_reset_handler(scsi_qla_host_t *vha)
 
        while (drv_state != drv_active) {
                if (time_after_eq(jiffies, reset_timeout)) {
-                       qla_printk(KERN_INFO, ha,
-                               "%s: RESET TIMEOUT!\n", QLA2XXX_DRIVER_NAME);
+                       ql_log(ql_log_warn, vha, 0x00b5,
+                           "Reset timeout.\n");
                        break;
                }
                qla82xx_idc_unlock(ha);
@@ -3504,12 +3562,15 @@ qla82xx_need_reset_handler(scsi_qla_host_t *vha)
        }
 
        dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
-       qla_printk(KERN_INFO, ha, "3:Device state is 0x%x = %s\n", dev_state,
-               dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown");
+       ql_log(ql_log_info, vha, 0x00b6,
+           "Device state is 0x%x = %s.\n",
+           dev_state,
+           dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown");
 
        /* Force to DEV_COLD unless someone else is starting a reset */
        if (dev_state != QLA82XX_DEV_INITIALIZING) {
-               qla_printk(KERN_INFO, ha, "HW State: COLD/RE-INIT\n");
+               ql_log(ql_log_info, vha, 0x00b7,
+                   "HW State: COLD/RE-INIT.\n");
                qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_COLD);
        }
 }
@@ -3523,8 +3584,12 @@ qla82xx_check_fw_alive(scsi_qla_host_t *vha)
        fw_heartbeat_counter = qla82xx_rd_32(vha->hw,
                QLA82XX_PEG_ALIVE_COUNTER);
        /* all 0xff, assume AER/EEH in progress, ignore */
-       if (fw_heartbeat_counter == 0xffffffff)
+       if (fw_heartbeat_counter == 0xffffffff) {
+               ql_dbg(ql_dbg_timer, vha, 0x6003,
+                   "FW heartbeat counter is 0xffffffff, "
+                   "returning status=%d.\n", status);
                return status;
+       }
        if (vha->fw_heartbeat_counter == fw_heartbeat_counter) {
                vha->seconds_since_last_heartbeat++;
                /* FW not alive after 2 seconds */
@@ -3535,6 +3600,9 @@ qla82xx_check_fw_alive(scsi_qla_host_t *vha)
        } else
                vha->seconds_since_last_heartbeat = 0;
        vha->fw_heartbeat_counter = fw_heartbeat_counter;
+       if (status)
+               ql_dbg(ql_dbg_timer, vha, 0x6004,
+                   "Returning status=%d.\n", status);
        return status;
 }
 
@@ -3565,8 +3633,10 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha)
 
        dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
        old_dev_state = dev_state;
-       qla_printk(KERN_INFO, ha, "1:Device state is 0x%x = %s\n", dev_state,
-               dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown");
+       ql_log(ql_log_info, vha, 0x009b,
+           "Device state is 0x%x = %s.\n",
+           dev_state,
+           dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown");
 
        /* wait for 30 seconds for device to go ready */
        dev_init_timeout = jiffies + (ha->nx_dev_init_timeout * HZ);
@@ -3574,9 +3644,8 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha)
        while (1) {
 
                if (time_after_eq(jiffies, dev_init_timeout)) {
-                       DEBUG(qla_printk(KERN_INFO, ha,
-                               "%s: device init failed!\n",
-                               QLA2XXX_DRIVER_NAME));
+                       ql_log(ql_log_fatal, vha, 0x009c,
+                           "Device init failed.\n");
                        rval = QLA_FUNCTION_FAILED;
                        break;
                }
@@ -3586,10 +3655,11 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha)
                        old_dev_state = dev_state;
                }
                if (loopcount < 5) {
-                       qla_printk(KERN_INFO, ha,
-                           "2:Device state is 0x%x = %s\n", dev_state,
-                           dev_state < MAX_STATES ?
-                           qdev_state[dev_state] : "Unknown");
+                       ql_log(ql_log_info, vha, 0x009d,
+                           "Device state is 0x%x = %s.\n",
+                           dev_state,
+                           dev_state < MAX_STATES ? qdev_state[dev_state] :
+                           "Unknown");
                }
 
                switch (dev_state) {
@@ -3656,29 +3726,26 @@ void qla82xx_watchdog(scsi_qla_host_t *vha)
                dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
                if (dev_state == QLA82XX_DEV_NEED_RESET &&
                    !test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) {
-                       qla_printk(KERN_WARNING, ha,
-                           "scsi(%ld) %s: Adapter reset needed!\n",
-                               vha->host_no, __func__);
+                       ql_log(ql_log_warn, vha, 0x6001,
+                           "Adapter reset needed.\n");
                        set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                        qla2xxx_wake_dpc(vha);
                } else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT &&
                        !test_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags)) {
-                       DEBUG(qla_printk(KERN_INFO, ha,
-                               "scsi(%ld) %s - detected quiescence needed\n",
-                               vha->host_no, __func__));
+                       ql_log(ql_log_warn, vha, 0x6002,
+                           "Quiescent needed.\n");
                        set_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags);
                        qla2xxx_wake_dpc(vha);
                } else {
                        if (qla82xx_check_fw_alive(vha)) {
                                halt_status = qla82xx_rd_32(ha,
                                    QLA82XX_PEG_HALT_STATUS1);
-                               qla_printk(KERN_INFO, ha,
-                                   "scsi(%ld): %s, Dumping hw/fw registers:\n "
-                                   " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,\n "
-                                   " PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,\n "
-                                   " PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n "
-                                   " PEG_NET_4_PC: 0x%x\n",
-                                   vha->host_no, __func__, halt_status,
+                               ql_dbg(ql_dbg_timer, vha, 0x6005,
+                                   "dumping hw/fw registers:.\n "
+                                   " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,.\n "
+                                   " PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,.\n "
+                                   " PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,.\n "
+                                   " PEG_NET_4_PC: 0x%x.\n", halt_status,
                                    qla82xx_rd_32(ha, QLA82XX_PEG_HALT_STATUS2),
                                    qla82xx_rd_32(ha,
                                            QLA82XX_CRB_PEG_NET_0 + 0x3c),
@@ -3694,9 +3761,8 @@ void qla82xx_watchdog(scsi_qla_host_t *vha)
                                        set_bit(ISP_UNRECOVERABLE,
                                            &vha->dpc_flags);
                                } else {
-                                       qla_printk(KERN_INFO, ha,
-                                           "scsi(%ld): %s - detect abort needed\n",
-                                           vha->host_no, __func__);
+                                       ql_log(ql_log_info, vha, 0x6006,
+                                           "Detect abort  needed.\n");
                                        set_bit(ISP_ABORT_NEEDED,
                                            &vha->dpc_flags);
                                }
@@ -3704,10 +3770,10 @@ void qla82xx_watchdog(scsi_qla_host_t *vha)
                                ha->flags.isp82xx_fw_hung = 1;
                                if (ha->flags.mbox_busy) {
                                        ha->flags.mbox_int = 1;
-                                       DEBUG2(qla_printk(KERN_ERR, ha,
-                                           "scsi(%ld) Due to fw hung, doing "
+                                       ql_log(ql_log_warn, vha, 0x6007,
+                                           "Due to FW hung, doing "
                                            "premature completion of mbx "
-                                           "command\n", vha->host_no));
+                                           "command.\n");
                                        if (test_bit(MBX_INTR_WAIT,
                                            &ha->mbx_cmd_flags))
                                                complete(&ha->mbx_intr_comp);
@@ -3742,9 +3808,8 @@ qla82xx_abort_isp(scsi_qla_host_t *vha)
        uint32_t dev_state;
 
        if (vha->device_flags & DFLG_DEV_FAILED) {
-               qla_printk(KERN_WARNING, ha,
-                       "%s(%ld): Device in failed state, "
-                       "Exiting.\n", __func__, vha->host_no);
+               ql_log(ql_log_warn, vha, 0x8024,
+                   "Device in failed state, exiting.\n");
                return QLA_SUCCESS;
        }
        ha->flags.isp82xx_reset_hdlr_active = 1;
@@ -3752,13 +3817,14 @@ qla82xx_abort_isp(scsi_qla_host_t *vha)
        qla82xx_idc_lock(ha);
        dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
        if (dev_state == QLA82XX_DEV_READY) {
-               qla_printk(KERN_INFO, ha, "HW State: NEED RESET\n");
+               ql_log(ql_log_info, vha, 0x8025,
+                   "HW State: NEED RESET.\n");
                qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
                        QLA82XX_DEV_NEED_RESET);
        } else
-               qla_printk(KERN_INFO, ha, "HW State: %s\n",
-                       dev_state < MAX_STATES ?
-                       qdev_state[dev_state] : "Unknown");
+               ql_log(ql_log_info, vha, 0x8026,
+                   "Hw State: %s.\n", dev_state < MAX_STATES ?
+                   qdev_state[dev_state] : "Unknown");
        qla82xx_idc_unlock(ha);
 
        rval = qla82xx_device_state_handler(vha);
@@ -3777,9 +3843,9 @@ qla82xx_abort_isp(scsi_qla_host_t *vha)
                vha->flags.online = 1;
                if (test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
                        if (ha->isp_abort_cnt == 0) {
-                               qla_printk(KERN_WARNING, ha,
-                                   "ISP error recovery failed - "
-                                   "board disabled\n");
+                               ql_log(ql_log_warn, vha, 0x8027,
+                                   "ISP error recover failed - board "
+                                   "disabled.\n");
                                /*
                                 * The next call disables the board
                                 * completely.
@@ -3791,16 +3857,16 @@ qla82xx_abort_isp(scsi_qla_host_t *vha)
                                rval = QLA_SUCCESS;
                        } else { /* schedule another ISP abort */
                                ha->isp_abort_cnt--;
-                               DEBUG(qla_printk(KERN_INFO, ha,
-                                   "qla%ld: ISP abort - retry remaining %d\n",
-                                   vha->host_no, ha->isp_abort_cnt));
+                               ql_log(ql_log_warn, vha, 0x8036,
+                                   "ISP abort - retry remaining %d.\n",
+                                   ha->isp_abort_cnt);
                                rval = QLA_FUNCTION_FAILED;
                        }
                } else {
                        ha->isp_abort_cnt = MAX_RETRIES_OF_ISP_ABORT;
-                       DEBUG(qla_printk(KERN_INFO, ha,
-                           "(%ld): ISP error recovery - retrying (%d) "
-                           "more times\n", vha->host_no, ha->isp_abort_cnt));
+                       ql_dbg(ql_dbg_taskm, vha, 0x8029,
+                           "ISP error recovery - retrying (%d) more times.\n",
+                           ha->isp_abort_cnt);
                        set_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
                        rval = QLA_FUNCTION_FAILED;
                }
@@ -3872,8 +3938,8 @@ int qla2x00_wait_for_fcoe_ctx_reset(scsi_qla_host_t *vha)
                        break;
                }
        }
-       DEBUG2(printk(KERN_INFO
-           "%s status=%d\n", __func__, status));
+       ql_dbg(ql_dbg_p3p, vha, 0xb027,
+           "%s status=%d.\n", status);
 
        return status;
 }
@@ -3902,6 +3968,9 @@ qla82xx_chip_reset_cleanup(scsi_qla_host_t *vha)
                        }
                }
        }
+       ql_dbg(ql_dbg_init, vha, 0x00b0,
+           "Entered %s fw_hung=%d.\n",
+           __func__, ha->flags.isp82xx_fw_hung);
 
        /* Abort all commands gracefully if fw NOT hung */
        if (!ha->flags.isp82xx_fw_hung) {
@@ -3922,13 +3991,13 @@ qla82xx_chip_reset_cleanup(scsi_qla_host_t *vha)
                                                spin_unlock_irqrestore(
                                                    &ha->hardware_lock, flags);
                                                if (ha->isp_ops->abort_command(sp)) {
-                                                       qla_printk(KERN_INFO, ha,
-                                                           "scsi(%ld): mbx abort command failed in %s\n",
-                                                           vha->host_no, __func__);
+                                                       ql_log(ql_log_info, vha,
+                                                           0x00b1,
+                                                           "mbx abort failed.\n");
                                                } else {
-                                                       qla_printk(KERN_INFO, ha,
-                                                           "scsi(%ld): mbx abort command success in %s\n",
-                                                           vha->host_no, __func__);
+                                                       ql_log(ql_log_info, vha,
+                                                           0x00b2,
+                                                           "mbx abort success.\n");
                                                }
                                                spin_lock_irqsave(&ha->hardware_lock, flags);
                                        }
@@ -3940,8 +4009,9 @@ qla82xx_chip_reset_cleanup(scsi_qla_host_t *vha)
                /* Wait for pending cmds (physical and virtual) to complete */
                if (!qla2x00_eh_wait_for_pending_commands(vha, 0, 0,
                    WAIT_HOST) == QLA_SUCCESS) {
-                       DEBUG2(qla_printk(KERN_INFO, ha,
-                           "Done wait for pending commands\n"));
+                       ql_dbg(ql_dbg_init, vha, 0x00b3,
+                           "Done wait for "
+                           "pending commands.\n");
                }
        }
 }
index f461925..e02df27 100644 (file)
@@ -35,6 +35,10 @@ static struct kmem_cache *srb_cachep;
  * CT6 CTX allocation cache
  */
 static struct kmem_cache *ctx_cachep;
+/*
+ * error level for logging
+ */
+int ql_errlev = ql_log_all;
 
 int ql2xlogintimeout = 20;
 module_param(ql2xlogintimeout, int, S_IRUGO);
@@ -69,8 +73,17 @@ MODULE_PARM_DESC(ql2xallocfwdump,
 int ql2xextended_error_logging;
 module_param(ql2xextended_error_logging, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(ql2xextended_error_logging,
-               "Option to enable extended error logging, "
-               "Default is 0 - no logging. 1 - log errors.");
+               "Option to enable extended error logging,\n"
+               "\t\tDefault is 0 - no logging.  0x40000000 - Module Init & Probe.\n"
+               "\t\t0x20000000 - Mailbox Cmnds. 0x10000000 - Device Discovery.\n"
+               "\t\t0x08000000 - IO tracing.    0x04000000 - DPC Thread.\n"
+               "\t\t0x02000000 - Async events.  0x01000000 - Timer routines.\n"
+               "\t\t0x00800000 - User space.    0x00400000 - Task Management.\n"
+               "\t\t0x00200000 - AER/EEH.       0x00100000 - Multi Q.\n"
+               "\t\t0x00080000 - P3P Specific.  0x00040000 - Virtual Port.\n"
+               "\t\t0x00020000 - Buffer Dump.   0x00010000 - Misc.\n"
+               "\t\t0x7fffffff - For enabling all logs, can be too many logs.\n"
+               "\t\tDo LOGICAL OR of the value to enable more than one level");
 
 int ql2xshiftctondsd = 6;
 module_param(ql2xshiftctondsd, int, S_IRUGO);
@@ -128,8 +141,8 @@ MODULE_PARM_DESC(ql2xmultique_tag,
 int ql2xfwloadbin;
 module_param(ql2xfwloadbin, int, S_IRUGO);
 MODULE_PARM_DESC(ql2xfwloadbin,
-               "Option to specify location from which to load ISP firmware:\n"
-               " 2 -- load firmware via the request_firmware() (hotplug)\n"
+               "Option to specify location from which to load ISP firmware:.\n"
+               " 2 -- load firmware via the request_firmware() (hotplug).\n"
                "      interface.\n"
                " 1 -- load firmware from flash.\n"
                " 0 -- use default semantics.\n");
@@ -143,7 +156,7 @@ MODULE_PARM_DESC(ql2xetsenable,
 int ql2xdbwr = 1;
 module_param(ql2xdbwr, int, S_IRUGO);
 MODULE_PARM_DESC(ql2xdbwr,
-       "Option to specify scheme for request queue posting\n"
+       "Option to specify scheme for request queue posting.\n"
        " 0 -- Regular doorbell.\n"
        " 1 -- CAMRAM doorbell (faster).\n");
 
@@ -168,7 +181,7 @@ MODULE_PARM_DESC(ql2xasynctmfenable,
 int ql2xdontresethba;
 module_param(ql2xdontresethba, int, S_IRUGO);
 MODULE_PARM_DESC(ql2xdontresethba,
-       "Option to specify reset behaviour\n"
+       "Option to specify reset behaviour.\n"
        " 0 (Default) -- Reset on failure.\n"
        " 1 -- Do not reset on failure.\n");
 
@@ -247,8 +260,11 @@ static inline void
 qla2x00_restart_timer(scsi_qla_host_t *vha, unsigned long interval)
 {
        /* Currently used for 82XX only. */
-       if (vha->device_flags & DFLG_DEV_FAILED)
+       if (vha->device_flags & DFLG_DEV_FAILED) {
+               ql_dbg(ql_dbg_timer, vha, 0x600d,
+                   "Device in a failed state, returning.\n");
                return;
+       }
 
        mod_timer(&vha->timer, jiffies + interval * HZ);
 }
@@ -273,19 +289,20 @@ static void qla2x00_sp_free_dma(srb_t *);
 /* -------------------------------------------------------------------------- */
 static int qla2x00_alloc_queues(struct qla_hw_data *ha)
 {
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
        ha->req_q_map = kzalloc(sizeof(struct req_que *) * ha->max_req_queues,
                                GFP_KERNEL);
        if (!ha->req_q_map) {
-               qla_printk(KERN_WARNING, ha,
-                       "Unable to allocate memory for request queue ptrs\n");
+               ql_log(ql_log_fatal, vha, 0x003b,
+                   "Unable to allocate memory for request queue ptrs.\n");
                goto fail_req_map;
        }
 
        ha->rsp_q_map = kzalloc(sizeof(struct rsp_que *) * ha->max_rsp_queues,
                                GFP_KERNEL);
        if (!ha->rsp_q_map) {
-               qla_printk(KERN_WARNING, ha,
-                       "Unable to allocate memory for response queue ptrs\n");
+               ql_log(ql_log_fatal, vha, 0x003c,
+                   "Unable to allocate memory for response queue ptrs.\n");
                goto fail_rsp_map;
        }
        set_bit(0, ha->rsp_qid_map);
@@ -349,8 +366,8 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha)
        struct qla_hw_data *ha = vha->hw;
 
        if (!(ha->fw_attributes & BIT_6)) {
-               qla_printk(KERN_INFO, ha,
-                       "Firmware is not multi-queue capable\n");
+               ql_log(ql_log_warn, vha, 0x00d8,
+                   "Firmware is not multi-queue capable.\n");
                goto fail;
        }
        if (ql2xmultique_tag) {
@@ -359,8 +376,8 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha)
                req = qla25xx_create_req_que(ha, options, 0, 0, -1,
                        QLA_DEFAULT_QUE_QOS);
                if (!req) {
-                       qla_printk(KERN_WARNING, ha,
-                               "Can't create request queue\n");
+                       ql_log(ql_log_warn, vha, 0x00e0,
+                           "Failed to create request queue.\n");
                        goto fail;
                }
                ha->wq = alloc_workqueue("qla2xxx_wq", WQ_MEM_RECLAIM, 1);
@@ -369,17 +386,20 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha)
                for (ques = 1; ques < ha->max_rsp_queues; ques++) {
                        ret = qla25xx_create_rsp_que(ha, options, 0, 0, req);
                        if (!ret) {
-                               qla_printk(KERN_WARNING, ha,
-                                       "Response Queue create failed\n");
+                               ql_log(ql_log_warn, vha, 0x00e8,
+                                   "Failed to create response queue.\n");
                                goto fail2;
                        }
                }
                ha->flags.cpu_affinity_enabled = 1;
-
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                       "CPU affinity mode enabled, no. of response"
-                       " queues:%d, no. of request queues:%d\n",
-                       ha->max_rsp_queues, ha->max_req_queues));
+               ql_dbg(ql_dbg_multiq, vha, 0xc007,
+                   "CPU affinity mode enalbed, "
+                   "no. of response queues:%d no. of request queues:%d.\n",
+                   ha->max_rsp_queues, ha->max_req_queues);
+               ql_dbg(ql_dbg_init, vha, 0x00e9,
+                   "CPU affinity mode enalbed, "
+                   "no. of response queues:%d no. of request queues:%d.\n",
+                   ha->max_rsp_queues, ha->max_req_queues);
        }
        return 0;
 fail2:
@@ -526,8 +546,11 @@ qla2x00_get_new_sp(scsi_qla_host_t *vha, fc_port_t *fcport,
        struct qla_hw_data *ha = vha->hw;
 
        sp = mempool_alloc(ha->srb_mempool, GFP_ATOMIC);
-       if (!sp)
+       if (!sp) {
+               ql_log(ql_log_warn, vha, 0x3006,
+                   "Memory allocation failed for sp.\n");
                return sp;
+       }
 
        atomic_set(&sp->ref_count, 1);
        sp->fcport = fcport;
@@ -551,30 +574,43 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
        int rval;
 
        if (ha->flags.eeh_busy) {
-               if (ha->flags.pci_channel_io_perm_failure)
+               if (ha->flags.pci_channel_io_perm_failure) {
+                       ql_dbg(ql_dbg_io, vha, 0x3001,
+                           "PCI Channel IO permanent failure, exiting "
+                           "cmd=%p.\n", cmd);
                        cmd->result = DID_NO_CONNECT << 16;
-               else
+               } else {
+                       ql_dbg(ql_dbg_io, vha, 0x3002,
+                           "EEH_Busy, Requeuing the cmd=%p.\n", cmd);
                        cmd->result = DID_REQUEUE << 16;
+               }
                goto qc24_fail_command;
        }
 
        rval = fc_remote_port_chkready(rport);
        if (rval) {
                cmd->result = rval;
+               ql_dbg(ql_dbg_io, vha, 0x3003,
+                   "fc_remote_port_chkready failed for cmd=%p, rval=0x%x.\n",
+                   cmd, rval);
                goto qc24_fail_command;
        }
 
        if (!vha->flags.difdix_supported &&
                scsi_get_prot_op(cmd) != SCSI_PROT_NORMAL) {
-                       DEBUG2(qla_printk(KERN_ERR, ha,
-                           "DIF Cap Not Reg, fail DIF capable cmd's:%x\n",
-                           cmd->cmnd[0]));
+                       ql_dbg(ql_dbg_io, vha, 0x3004,
+                           "DIF Cap not reg, fail DIF capable cmd's:%p.\n",
+                           cmd);
                        cmd->result = DID_NO_CONNECT << 16;
                        goto qc24_fail_command;
        }
        if (atomic_read(&fcport->state) != FCS_ONLINE) {
                if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
                        atomic_read(&base_vha->loop_state) == LOOP_DEAD) {
+                       ql_dbg(ql_dbg_io, vha, 0x3005,
+                           "Returning DNC, fcport_state=%d loop_state=%d.\n",
+                           atomic_read(&fcport->state),
+                           atomic_read(&base_vha->loop_state));
                        cmd->result = DID_NO_CONNECT << 16;
                        goto qc24_fail_command;
                }
@@ -586,8 +622,11 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
                goto qc24_host_busy;
 
        rval = ha->isp_ops->start_scsi(sp);
-       if (rval != QLA_SUCCESS)
+       if (rval != QLA_SUCCESS) {
+               ql_dbg(ql_dbg_io, vha, 0x3013,
+                   "Start scsi failed rval=%d for cmd=%p.\n", rval, cmd);
                goto qc24_host_busy_free_sp;
+       }
 
        return 0;
 
@@ -630,7 +669,8 @@ qla2x00_eh_wait_on_command(struct scsi_cmnd *cmd)
        int ret = QLA_SUCCESS;
 
        if (unlikely(pci_channel_offline(ha->pdev)) || ha->flags.eeh_busy) {
-               DEBUG17(qla_printk(KERN_WARNING, ha, "return:eh_wait\n"));
+               ql_dbg(ql_dbg_taskm, vha, 0x8005,
+                   "Return:eh_wait.\n");
                return ret;
        }
 
@@ -723,7 +763,8 @@ qla2x00_wait_for_reset_ready(scsi_qla_host_t *vha)
        else
                return_status = QLA_FUNCTION_FAILED;
 
-       DEBUG2(printk("%s return_status=%d\n", __func__, return_status));
+       ql_dbg(ql_dbg_taskm, vha, 0x8019,
+           "%s return status=%d.\n", __func__, return_status);
 
        return return_status;
 }
@@ -831,10 +872,14 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
        int wait = 0;
        struct qla_hw_data *ha = vha->hw;
 
+       ql_dbg(ql_dbg_taskm, vha, 0x8000,
+           "Entered %s for cmd=%p.\n", __func__, cmd);
        if (!CMD_SP(cmd))
                return SUCCESS;
 
        ret = fc_block_scsi_eh(cmd);
+       ql_dbg(ql_dbg_taskm, vha, 0x8001,
+           "Return value of fc_block_scsi_eh=%d.\n", ret);
        if (ret != 0)
                return ret;
        ret = SUCCESS;
@@ -849,20 +894,19 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
                return SUCCESS;
        }
 
-       DEBUG2(printk("%s(%ld): aborting sp %p from RISC.",
-           __func__, vha->host_no, sp));
+       ql_dbg(ql_dbg_taskm, vha, 0x8002,
+           "Aborting sp=%p cmd=%p from RISC ", sp, cmd);
 
        /* Get a reference to the sp and drop the lock.*/
        sp_get(sp);
 
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
        if (ha->isp_ops->abort_command(sp)) {
-               DEBUG2(printk("%s(%ld): abort_command "
-               "mbx failed.\n", __func__, vha->host_no));
-               ret = FAILED;
+               ql_dbg(ql_dbg_taskm, vha, 0x8003,
+                   "Abort command mbx failed for cmd=%p.\n", cmd);
        } else {
-               DEBUG3(printk("%s(%ld): abort_command "
-               "mbx success.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_taskm, vha, 0x8004,
+                   "Abort command mbx success.\n");
                wait = 1;
        }
        qla2x00_sp_compl(ha, sp);
@@ -870,16 +914,14 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
        /* Wait for the command to be returned. */
        if (wait) {
                if (qla2x00_eh_wait_on_command(cmd) != QLA_SUCCESS) {
-                       qla_printk(KERN_ERR, ha,
-                           "scsi(%ld:%d:%d): Abort handler timed out -- %x.\n",
-                           vha->host_no, id, lun, ret);
+                       ql_log(ql_log_warn, vha, 0x8006,
+                           "Abort handler timed out for cmd=%p.\n", cmd);
                        ret = FAILED;
                }
        }
 
-       qla_printk(KERN_INFO, ha,
-           "scsi(%ld:%d:%d): Abort command issued -- %d %x.\n",
-           vha->host_no, id, lun, wait, ret);
+       ql_log(ql_log_info, vha, 0x801c,
+           "Abort command issued --  %d %x.\n", wait, ret);
 
        return ret;
 }
@@ -947,40 +989,59 @@ __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type,
        fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
        int err;
 
-       if (!fcport)
+       if (!fcport) {
+               ql_log(ql_log_warn, vha, 0x8007,
+                   "fcport is NULL.\n");
                return FAILED;
+       }
 
        err = fc_block_scsi_eh(cmd);
+       ql_dbg(ql_dbg_taskm, vha, 0x8008,
+           "fc_block_scsi_eh ret=%d.\n", err);
        if (err != 0)
                return err;
 
-       qla_printk(KERN_INFO, vha->hw, "scsi(%ld:%d:%d): %s RESET ISSUED.\n",
-           vha->host_no, cmd->device->id, cmd->device->lun, name);
+       ql_log(ql_log_info, vha, 0x8009,
+           "%s RESET ISSUED for id %d lun %d cmd=%p.\n", name,
+           cmd->device->id, cmd->device->lun, cmd);
 
        err = 0;
-       if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS)
+       if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
+               ql_log(ql_log_warn, vha, 0x800a,
+                   "Wait for hba online failed for cmd=%p.\n", cmd);
                goto eh_reset_failed;
+       }
        err = 1;
-       if (qla2x00_wait_for_loop_ready(vha) != QLA_SUCCESS)
+       if (qla2x00_wait_for_loop_ready(vha) != QLA_SUCCESS) {
+               ql_log(ql_log_warn, vha, 0x800b,
+                   "Wait for loop ready failed for cmd=%p.\n", cmd);
                goto eh_reset_failed;
+       }
        err = 2;
        if (do_reset(fcport, cmd->device->lun, cmd->request->cpu + 1)
-               != QLA_SUCCESS)
+               != QLA_SUCCESS) {
+               ql_log(ql_log_warn, vha, 0x800c,
+                   "do_reset failed for cmd=%p.\n", cmd);
                goto eh_reset_failed;
+       }
        err = 3;
        if (qla2x00_eh_wait_for_pending_commands(vha, cmd->device->id,
-           cmd->device->lun, type) != QLA_SUCCESS)
+           cmd->device->lun, type) != QLA_SUCCESS) {
+               ql_log(ql_log_warn, vha, 0x800d,
+                   "wait for peding cmds failed for cmd=%p.\n", cmd);
                goto eh_reset_failed;
+       }
 
-       qla_printk(KERN_INFO, vha->hw, "scsi(%ld:%d:%d): %s RESET SUCCEEDED.\n",
-           vha->host_no, cmd->device->id, cmd->device->lun, name);
+       ql_log(ql_log_info, vha, 0x800e,
+           "%s RESET SUCCEEDED for id %d lun %d cmd=%p.\n", name,
+           cmd->device->id, cmd->device->lun, cmd);
 
        return SUCCESS;
 
 eh_reset_failed:
-       qla_printk(KERN_INFO, vha->hw, "scsi(%ld:%d:%d): %s RESET FAILED: %s.\n"
-           , vha->host_no, cmd->device->id, cmd->device->lun, name,
-           reset_errors[err]);
+       ql_log(ql_log_info, vha, 0x800f,
+           "%s RESET FAILED: %s for id %d lun %d cmd=%p.\n", name,
+           reset_errors[err], cmd->device->id, cmd->device->lun);
        return FAILED;
 }
 
@@ -1030,19 +1091,25 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
        id = cmd->device->id;
        lun = cmd->device->lun;
 
-       if (!fcport)
+       if (!fcport) {
+               ql_log(ql_log_warn, vha, 0x8010,
+                   "fcport is NULL.\n");
                return ret;
+       }
 
        ret = fc_block_scsi_eh(cmd);
+       ql_dbg(ql_dbg_taskm, vha, 0x8011,
+           "fc_block_scsi_eh ret=%d.\n", ret);
        if (ret != 0)
                return ret;
        ret = FAILED;
 
-       qla_printk(KERN_INFO, vha->hw,
-           "scsi(%ld:%d:%d): BUS RESET ISSUED.\n", vha->host_no, id, lun);
+       ql_log(ql_log_info, vha, 0x8012,
+           "BUS RESET ISSUED for id %d lun %d.\n", id, lun);
 
        if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
-               DEBUG2(printk("%s failed:board disabled\n",__func__));
+               ql_log(ql_log_fatal, vha, 0x8013,
+                   "Wait for hba online failed board disabled.\n");
                goto eh_bus_reset_done;
        }
 
@@ -1055,12 +1122,15 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
 
        /* Flush outstanding commands. */
        if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, WAIT_HOST) !=
-           QLA_SUCCESS)
+           QLA_SUCCESS) {
+               ql_log(ql_log_warn, vha, 0x8014,
+                   "Wait for pending commands failed.\n");
                ret = FAILED;
+       }
 
 eh_bus_reset_done:
-       qla_printk(KERN_INFO, vha->hw, "%s: reset %s\n", __func__,
-           (ret == FAILED) ? "failed" : "succeeded");
+       ql_log(ql_log_warn, vha, 0x802b,
+           "BUS RESET %s.\n", (ret == FAILED) ? "FAILED" : "SUCCEDED");
 
        return ret;
 }
@@ -1093,16 +1163,21 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
        id = cmd->device->id;
        lun = cmd->device->lun;
 
-       if (!fcport)
+       if (!fcport) {
+               ql_log(ql_log_warn, vha, 0x8016,
+                   "fcport is NULL.\n");
                return ret;
+       }
 
        ret = fc_block_scsi_eh(cmd);
+       ql_dbg(ql_dbg_taskm, vha, 0x8017,
+           "fc_block_scsi_eh ret=%d.\n", ret);
        if (ret != 0)
                return ret;
        ret = FAILED;
 
-       qla_printk(KERN_INFO, ha,
-           "scsi(%ld:%d:%d): ADAPTER RESET ISSUED.\n", vha->host_no, id, lun);
+       ql_log(ql_log_info, vha, 0x8018,
+           "ADAPTER RESET ISSUED for id %d lun %d.\n", id, lun);
 
        if (qla2x00_wait_for_reset_ready(vha) != QLA_SUCCESS)
                goto eh_host_reset_lock;
@@ -1137,8 +1212,11 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
                        /* failed. schedule dpc to try */
                        set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
 
-                       if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS)
+                       if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
+                               ql_log(ql_log_warn, vha, 0x802a,
+                                   "wait for hba online failed.\n");
                                goto eh_host_reset_lock;
+                       }
                }
                clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
        }
@@ -1149,7 +1227,7 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
                ret = SUCCESS;
 
 eh_host_reset_lock:
-       qla_printk(KERN_INFO, ha, "%s: reset %s\n", __func__,
+       qla_printk(KERN_INFO, ha, "%s: reset %s.\n", __func__,
            (ret == FAILED) ? "failed" : "succeeded");
 
        return ret;
@@ -1179,9 +1257,9 @@ qla2x00_loop_reset(scsi_qla_host_t *vha)
 
                        ret = ha->isp_ops->target_reset(fcport, 0, 0);
                        if (ret != QLA_SUCCESS) {
-                               DEBUG2_3(printk("%s(%ld): bus_reset failed: "
-                                   "target_reset=%d d_id=%x.\n", __func__,
-                                   vha->host_no, ret, fcport->d_id.b24));
+                               ql_dbg(ql_dbg_taskm, vha, 0x802c,
+                                   "Bus Reset failed: Target Reset=%d "
+                                   "d_id=%x.\n", ret, fcport->d_id.b24);
                        }
                }
        }
@@ -1189,9 +1267,8 @@ qla2x00_loop_reset(scsi_qla_host_t *vha)
        if (ha->flags.enable_lip_full_login && !IS_QLA8XXX_TYPE(ha)) {
                ret = qla2x00_full_login_lip(vha);
                if (ret != QLA_SUCCESS) {
-                       DEBUG2_3(printk("%s(%ld): failed: "
-                           "full_login_lip=%d.\n", __func__, vha->host_no,
-                           ret));
+                       ql_dbg(ql_dbg_taskm, vha, 0x802d,
+                           "full_login_lip=%d.\n", ret);
                }
                atomic_set(&vha->loop_state, LOOP_DOWN);
                atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
@@ -1202,8 +1279,8 @@ qla2x00_loop_reset(scsi_qla_host_t *vha)
        if (ha->flags.enable_lip_reset) {
                ret = qla2x00_lip_reset(vha);
                if (ret != QLA_SUCCESS) {
-                       DEBUG2_3(printk("%s(%ld): failed: "
-                           "lip_reset=%d.\n", __func__, vha->host_no, ret));
+                       ql_dbg(ql_dbg_taskm, vha, 0x802e,
+                           "lip_reset failed (%d).\n", ret);
                } else
                        qla2x00_wait_for_loop_ready(vha);
        }
@@ -1302,17 +1379,17 @@ static void qla2x00_handle_queue_full(struct scsi_device *sdev, int qdepth)
        if (!scsi_track_queue_full(sdev, qdepth))
                return;
 
-       DEBUG2(qla_printk(KERN_INFO, fcport->vha->hw,
-               "scsi(%ld:%d:%d:%d): Queue depth adjusted-down to %d.\n",
-               fcport->vha->host_no, sdev->channel, sdev->id, sdev->lun,
-               sdev->queue_depth));
+       ql_dbg(ql_dbg_io, fcport->vha, 0x3029,
+           "Queue depth adjusted-down "
+           "to %d for scsi(%ld:%d:%d:%d).\n",
+           sdev->queue_depth, fcport->vha->host_no,
+           sdev->channel, sdev->id, sdev->lun);
 }
 
 static void qla2x00_adjust_sdev_qdepth_up(struct scsi_device *sdev, int qdepth)
 {
        fc_port_t *fcport = sdev->hostdata;
        struct scsi_qla_host *vha = fcport->vha;
-       struct qla_hw_data *ha = vha->hw;
        struct req_que *req = NULL;
 
        req = vha->req;
@@ -1327,10 +1404,11 @@ static void qla2x00_adjust_sdev_qdepth_up(struct scsi_device *sdev, int qdepth)
        else
                scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, qdepth);
 
-       DEBUG2(qla_printk(KERN_INFO, ha,
-              "scsi(%ld:%d:%d:%d): Queue depth adjusted-up to %d.\n",
-              fcport->vha->host_no, sdev->channel, sdev->id, sdev->lun,
-              sdev->queue_depth));
+       ql_dbg(ql_dbg_io, vha, 0x302a,
+           "Queue depth adjusted-up to %d for "
+           "scsi(%ld:%d:%d:%d).\n",
+           sdev->queue_depth, fcport->vha->host_no,
+           sdev->channel, sdev->id, sdev->lun);
 }
 
 static int
@@ -1776,6 +1854,9 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
                ha->flags.port0 = 1;
        else
                ha->flags.port0 = 0;
+       ql_dbg_pci(ql_dbg_init, ha->pdev, 0x000b,
+           "device_type=0x%x port=%d fw_srisc_address=%p.\n",
+           ha->device_type, ha->flags.port0, ha->fw_srisc_address);
 }
 
 static int
@@ -1790,10 +1871,9 @@ qla2x00_iospace_config(struct qla_hw_data *ha)
 
        if (pci_request_selected_regions(ha->pdev, ha->bars,
            QLA2XXX_DRIVER_NAME)) {
-               qla_printk(KERN_WARNING, ha,
-                   "Failed to reserve PIO/MMIO regions (%s)\n",
+               ql_log_pci(ql_log_fatal, ha->pdev, 0x0011,
+                   "Failed to reserve PIO/MMIO regions (%s), aborting.\n",
                    pci_name(ha->pdev));
-
                goto iospace_error_exit;
        }
        if (!(ha->bars & 1))
@@ -1803,39 +1883,42 @@ qla2x00_iospace_config(struct qla_hw_data *ha)
        pio = pci_resource_start(ha->pdev, 0);
        if (pci_resource_flags(ha->pdev, 0) & IORESOURCE_IO) {
                if (pci_resource_len(ha->pdev, 0) < MIN_IOBASE_LEN) {
-                       qla_printk(KERN_WARNING, ha,
-                           "Invalid PCI I/O region size (%s)...\n",
-                               pci_name(ha->pdev));
+                       ql_log_pci(ql_log_warn, ha->pdev, 0x0012,
+                           "Invalid pci I/O region size (%s).\n",
+                           pci_name(ha->pdev));
                        pio = 0;
                }
        } else {
-               qla_printk(KERN_WARNING, ha,
-                   "region #0 not a PIO resource (%s)...\n",
+               ql_log_pci(ql_log_warn, ha->pdev, 0x0013,
+                   "Region #0 no a PIO resource (%s).\n",
                    pci_name(ha->pdev));
                pio = 0;
        }
        ha->pio_address = pio;
+       ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0014,
+           "PIO address=%p.\n",
+           ha->pio_address);
 
 skip_pio:
        /* Use MMIO operations for all accesses. */
        if (!(pci_resource_flags(ha->pdev, 1) & IORESOURCE_MEM)) {
-               qla_printk(KERN_ERR, ha,
-                   "region #1 not an MMIO resource (%s), aborting\n",
+               ql_log_pci(ql_log_fatal, ha->pdev, 0x0015,
+                   "Region #1 not an MMIO resource (%s), aborting.\n",
                    pci_name(ha->pdev));
                goto iospace_error_exit;
        }
        if (pci_resource_len(ha->pdev, 1) < MIN_IOBASE_LEN) {
-               qla_printk(KERN_ERR, ha,
-                   "Invalid PCI mem region size (%s), aborting\n",
-                       pci_name(ha->pdev));
+               ql_log_pci(ql_log_fatal, ha->pdev, 0x0016,
+                   "Invalid PCI mem region size (%s), aborting.\n",
+                   pci_name(ha->pdev));
                goto iospace_error_exit;
        }
 
        ha->iobase = ioremap(pci_resource_start(ha->pdev, 1), MIN_IOBASE_LEN);
        if (!ha->iobase) {
-               qla_printk(KERN_ERR, ha,
-                   "cannot remap MMIO (%s), aborting\n", pci_name(ha->pdev));
-
+               ql_log_pci(ql_log_fatal, ha->pdev, 0x0017,
+                   "Cannot remap MMIO (%s), aborting.\n",
+                   pci_name(ha->pdev));
                goto iospace_error_exit;
        }
 
@@ -1849,6 +1932,8 @@ skip_pio:
        ha->mqiobase = ioremap(pci_resource_start(ha->pdev, 3),
                        pci_resource_len(ha->pdev, 3));
        if (ha->mqiobase) {
+               ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0018,
+                   "MQIO Base=%p.\n", ha->mqiobase);
                /* Read MSIX vector size of the board */
                pci_read_config_word(ha->pdev, QLA_PCI_MSIX_CONTROL, &msix);
                ha->msix_count = msix;
@@ -1861,17 +1946,24 @@ skip_pio:
                        ha->max_req_queues = 2;
                } else if (ql2xmaxqueues > 1) {
                        ha->max_req_queues = ql2xmaxqueues > QLA_MQ_SIZE ?
-                                               QLA_MQ_SIZE : ql2xmaxqueues;
-                       DEBUG2(qla_printk(KERN_INFO, ha, "QoS mode set, max no"
-                       " of request queues:%d\n", ha->max_req_queues));
+                           QLA_MQ_SIZE : ql2xmaxqueues;
+                       ql_dbg_pci(ql_dbg_multiq, ha->pdev, 0xc008,
+                           "QoS mode set, max no of request queues:%d.\n",
+                           ha->max_req_queues);
+                       ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0019,
+                           "QoS mode set, max no of request queues:%d.\n",
+                           ha->max_req_queues);
                }
-               qla_printk(KERN_INFO, ha,
-                       "MSI-X vector count: %d\n", msix);
+               ql_log_pci(ql_log_info, ha->pdev, 0x001a,
+                   "MSI-X vector count: %d.\n", msix);
        } else
-               qla_printk(KERN_INFO, ha, "BAR 3 not enabled\n");
+               ql_log_pci(ql_log_info, ha->pdev, 0x001b,
+                   "BAR 3 not enabled.\n");
 
 mqiobase_exit:
        ha->msix_count = ha->max_rsp_queues + 1;
+       ql_dbg_pci(ql_dbg_init, ha->pdev, 0x001c,
+           "MSIX Count:%d.\n", ha->msix_count);
        return (0);
 
 iospace_error_exit:
@@ -1935,7 +2027,11 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
            pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8021) {
                bars = pci_select_bars(pdev, IORESOURCE_MEM);
                mem_only = 1;
+               ql_dbg_pci(ql_dbg_init, pdev, 0x0007,
+                   "Mem only adapter.\n");
        }
+       ql_dbg_pci(ql_dbg_init, pdev, 0x0008,
+           "Bars=%d.\n", bars);
 
        if (mem_only) {
                if (pci_enable_device_mem(pdev))
@@ -1950,9 +2046,12 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
        ha = kzalloc(sizeof(struct qla_hw_data), GFP_KERNEL);
        if (!ha) {
-               DEBUG(printk("Unable to allocate memory for ha\n"));
+               ql_log_pci(ql_log_fatal, pdev, 0x0009,
+                   "Unable to allocate memory for ha.\n");
                goto probe_out;
        }
+       ql_dbg_pci(ql_dbg_init, pdev, 0x000a,
+           "Memory allocated for ha=%p.\n", ha);
        ha->pdev = pdev;
 
        /* Clear our data area */
@@ -1974,10 +2073,9 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        if (ret)
                goto probe_hw_failed;
 
-       qla_printk(KERN_INFO, ha,
-           "Found an ISP%04X, irq %d, iobase 0x%p\n", pdev->device, pdev->irq,
-           ha->iobase);
-
+       ql_log_pci(ql_log_info, pdev, 0x001d,
+           "Found an ISP%04X irq %d iobase 0x%p.\n",
+           pdev->device, pdev->irq, ha->iobase);
        ha->prev_topology = 0;
        ha->init_cb_size = sizeof(init_cb_t);
        ha->link_data_rate = PORT_SPEED_UNKNOWN;
@@ -2078,7 +2176,18 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
                ha->nvram_conf_off = FARX_ACCESS_NVRAM_CONF;
                ha->nvram_data_off = FARX_ACCESS_NVRAM_DATA;
        }
-
+       ql_dbg_pci(ql_dbg_init, pdev, 0x001e,
+           "mbx_count=%d, req_length=%d, "
+           "rsp_length=%d, max_loop_id=%d, init_cb_size=%d, "
+           "gid_list_info_size=%d, optrom_size=%d, nvram_npiv_size=%d, .\n",
+           ha->mbx_count, req_length, rsp_length, ha->max_loop_id,
+           ha->init_cb_size, ha->gid_list_info_size, ha->optrom_size,
+           ha->nvram_npiv_size);
+       ql_dbg_pci(ql_dbg_init, pdev, 0x001f,
+           "isp_ops=%p, flash_conf_off=%d, "
+           "flash_data_off=%d, nvram_conf_off=%d, nvram_data_off=%d.\n",
+           ha->isp_ops, ha->flash_conf_off, ha->flash_data_off,
+           ha->nvram_conf_off, ha->nvram_data_off);
        mutex_init(&ha->vport_lock);
        init_completion(&ha->mbx_cmd_comp);
        complete(&ha->mbx_cmd_comp);
@@ -2088,10 +2197,14 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        set_bit(0, (unsigned long *) ha->vp_idx_map);
 
        qla2x00_config_dma_addressing(ha);
+       ql_dbg_pci(ql_dbg_init, pdev, 0x0020,
+           "64 Bit addressing is %s.\n",
+           ha->flags.enable_64bit_addressing ? "enable" :
+           "disable");
        ret = qla2x00_mem_alloc(ha, req_length, rsp_length, &req, &rsp);
        if (!ret) {
-               qla_printk(KERN_WARNING, ha,
-                   "[ERROR] Failed to allocate memory for adapter\n");
+               ql_log_pci(ql_log_fatal, pdev, 0x0031,
+                   "Failed to allocate memory for adapter, aborting.\n");
 
                goto probe_hw_failed;
        }
@@ -2103,9 +2216,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
        base_vha = qla2x00_create_host(sht, ha);
        if (!base_vha) {
-               qla_printk(KERN_WARNING, ha,
-                   "[ERROR] Failed to allocate memory for scsi_host\n");
-
                ret = -ENOMEM;
                qla2x00_mem_free(ha);
                qla2x00_free_req_que(ha, req);
@@ -2132,7 +2242,11 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
                if (!IS_QLA82XX(ha))
                        host->sg_tablesize = QLA_SG_ALL;
        }
-
+       ql_dbg(ql_dbg_init, base_vha, 0x0032,
+           "can_queue=%d, req=%p, "
+           "mgmt_svr_loop_id=%d, sg_tablesize=%d.\n",
+           host->can_queue, base_vha->req,
+           base_vha->mgmt_svr_loop_id, host->sg_tablesize);
        host->max_id = max_id;
        host->this_id = 255;
        host->cmd_per_lun = 3;
@@ -2146,6 +2260,14 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        host->transportt = qla2xxx_transport_template;
        sht->vendor_id = (SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC);
 
+       ql_dbg(ql_dbg_init, base_vha, 0x0033,
+           "max_id=%d this_id=%d "
+           "cmd_per_len=%d unique_id=%d max_cmd_len=%d max_channel=%d "
+           "max_lun=%d transportt=%p, vendor_id=%d.\n", host->max_id,
+           host->this_id, host->cmd_per_lun, host->unique_id,
+           host->max_cmd_len, host->max_channel, host->max_lun,
+           host->transportt, sht->vendor_id);
+
        /* Set up the irqs */
        ret = qla2x00_request_irqs(ha, rsp);
        if (ret)
@@ -2156,9 +2278,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        /* Alloc arrays of request and response ring ptrs */
 que_init:
        if (!qla2x00_alloc_queues(ha)) {
-               qla_printk(KERN_WARNING, ha,
-               "[ERROR] Failed to allocate memory for queue"
-               " pointers\n");
+               ql_log(ql_log_fatal, base_vha, 0x003d,
+                   "Failed to allocate memory for queue pointers.. aborting.\n");
                goto probe_init_failed;
        }
 
@@ -2186,20 +2307,33 @@ que_init:
                rsp->rsp_q_out = &ha->iobase->isp82.rsp_q_out[0];
        }
 
-       if (qla2x00_initialize_adapter(base_vha)) {
-               qla_printk(KERN_WARNING, ha,
-                   "Failed to initialize adapter\n");
+       ql_dbg(ql_dbg_multiq, base_vha, 0xc009,
+           "rsp_q_map=%p req_q_map=%p rsp->req=%p req->rsp=%p.\n",
+           ha->rsp_q_map, ha->req_q_map, rsp->req, req->rsp);
+       ql_dbg(ql_dbg_multiq, base_vha, 0xc00a,
+           "req->req_q_in=%p req->req_q_out=%p "
+           "rsp->rsp_q_in=%p rsp->rsp_q_out=%p.\n",
+           req->req_q_in, req->req_q_out,
+           rsp->rsp_q_in, rsp->rsp_q_out);
+       ql_dbg(ql_dbg_init, base_vha, 0x003e,
+           "rsp_q_map=%p req_q_map=%p rsp->req=%p req->rsp=%p.\n",
+           ha->rsp_q_map, ha->req_q_map, rsp->req, req->rsp);
+       ql_dbg(ql_dbg_init, base_vha, 0x003f,
+           "req->req_q_in=%p req->req_q_out=%p rsp->rsp_q_in=%p rsp->rsp_q_out=%p.\n",
+           req->req_q_in, req->req_q_out, rsp->rsp_q_in, rsp->rsp_q_out);
 
-               DEBUG2(printk("scsi(%ld): Failed to initialize adapter - "
-                   "Adapter flags %x.\n",
-                   base_vha->host_no, base_vha->device_flags));
+       if (qla2x00_initialize_adapter(base_vha)) {
+               ql_log(ql_log_fatal, base_vha, 0x00d6,
+                   "Failed to initialize adapter - Adapter flags %x.\n",
+                   base_vha->device_flags);
 
                if (IS_QLA82XX(ha)) {
                        qla82xx_idc_lock(ha);
                        qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
                                QLA82XX_DEV_FAILED);
                        qla82xx_idc_unlock(ha);
-                       qla_printk(KERN_INFO, ha, "HW State: FAILED\n");
+                       ql_log(ql_log_fatal, base_vha, 0x00d7,
+                           "HW State: FAILED.\n");
                }
 
                ret = -ENODEV;
@@ -2208,9 +2342,8 @@ que_init:
 
        if (ha->mqenable) {
                if (qla25xx_setup_mode(base_vha)) {
-                       qla_printk(KERN_WARNING, ha,
-                               "Can't create queues, falling back to single"
-                               " queue mode\n");
+                       ql_log(ql_log_warn, base_vha, 0x00ec,
+                           "Failed to create queues, falling back to single queue mode.\n");
                        goto que_init;
                }
        }
@@ -2222,13 +2355,15 @@ que_init:
         * Startup the kernel thread for this host adapter
         */
        ha->dpc_thread = kthread_create(qla2x00_do_dpc, ha,
-                       "%s_dpc", base_vha->host_str);
+           "%s_dpc", base_vha->host_str);
        if (IS_ERR(ha->dpc_thread)) {
-               qla_printk(KERN_WARNING, ha,
-                   "Unable to start DPC thread!\n");
+               ql_log(ql_log_fatal, base_vha, 0x00ed,
+                   "Failed to start DPC thread.\n");
                ret = PTR_ERR(ha->dpc_thread);
                goto probe_failed;
        }
+       ql_dbg(ql_dbg_init, base_vha, 0x00ee,
+           "DPC thread started successfully.\n");
 
 skip_dpc:
        list_add_tail(&base_vha->list, &ha->vp_list);
@@ -2236,16 +2371,18 @@ skip_dpc:
 
        /* Initialized the timer */
        qla2x00_start_timer(base_vha, qla2x00_timer, WATCH_INTERVAL);
-
-       DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n",
-           base_vha->host_no, ha));
+       ql_dbg(ql_dbg_init, base_vha, 0x00ef,
+           "Started qla2x00_timer with "
+           "interval=%d.\n", WATCH_INTERVAL);
+       ql_dbg(ql_dbg_init, base_vha, 0x00f0,
+           "Detected hba at address=%p.\n",
+           ha);
 
        if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif) {
                if (ha->fw_attributes & BIT_4) {
                        base_vha->flags.difdix_supported = 1;
-                       DEBUG18(qla_printk(KERN_INFO, ha,
-                           "Registering for DIF/DIX type 1 and 3"
-                           " protection.\n"));
+                       ql_dbg(ql_dbg_init, base_vha, 0x00f1,
+                           "Registering for DIF/DIX type 1 and 3 protection.\n");
                        scsi_host_set_prot(host,
                            SHOST_DIF_TYPE1_PROTECTION
                            | SHOST_DIF_TYPE2_PROTECTION
@@ -2267,6 +2404,9 @@ skip_dpc:
        base_vha->flags.init_done = 1;
        base_vha->flags.online = 1;
 
+       ql_dbg(ql_dbg_init, base_vha, 0x00f2,
+           "Init done and hba is online.\n");
+
        scsi_scan_host(host);
 
        qla2x00_alloc_sysfs_attr(base_vha);
@@ -2275,14 +2415,17 @@ skip_dpc:
 
        qla2x00_dfs_setup(base_vha);
 
-       qla_printk(KERN_INFO, ha, "\n"
-           " QLogic Fibre Channel HBA Driver: %s\n"
-           "  QLogic %s - %s\n"
-           "  ISP%04X: %s @ %s hdma%c, host#=%ld, fw=%s\n",
-           qla2x00_version_str, ha->model_number,
-           ha->model_desc ? ha->model_desc : "", pdev->device,
-           ha->isp_ops->pci_info_str(base_vha, pci_info), pci_name(pdev),
-           ha->flags.enable_64bit_addressing ? '+' : '-', base_vha->host_no,
+       ql_log(ql_log_info, base_vha, 0x00fa,
+           "QLogic Fibre Channed HBA Driver: %s.\n",
+           qla2x00_version_str);
+       ql_log(ql_log_info, base_vha, 0x00fb,
+           "QLogic %s - %s.\n",
+           ha->model_number, ha->model_desc ? ha->model_desc : "");
+       ql_log(ql_log_info, base_vha, 0x00fc,
+           "ISP%04X: %s @ %s hdma%c host#=%ld fw=%s.\n",
+           pdev->device, ha->isp_ops->pci_info_str(base_vha, pci_info),
+           pci_name(pdev), ha->flags.enable_64bit_addressing ? '+' : '-',
+           base_vha->host_no,
            ha->isp_ops->fw_version_str(base_vha, fw_str));
 
        return 0;
@@ -2580,20 +2723,15 @@ void qla2x00_mark_device_lost(scsi_qla_host_t *vha, fc_port_t *fcport,
                fcport->login_retry = vha->hw->login_retry_count;
                set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
 
-               DEBUG(printk("scsi(%ld): Port login retry: "
+               ql_dbg(ql_dbg_disc, vha, 0x2067,
+                   "Port login retry "
                    "%02x%02x%02x%02x%02x%02x%02x%02x, "
-                   "id = 0x%04x retry cnt=%d\n",
-                   vha->host_no,
-                   fcport->port_name[0],
-                   fcport->port_name[1],
-                   fcport->port_name[2],
-                   fcport->port_name[3],
-                   fcport->port_name[4],
-                   fcport->port_name[5],
-                   fcport->port_name[6],
-                   fcport->port_name[7],
-                   fcport->loop_id,
-                   fcport->login_retry));
+                   "id = 0x%04x retry cnt=%d.\n",
+                   fcport->port_name[0], fcport->port_name[1],
+                   fcport->port_name[2], fcport->port_name[3],
+                   fcport->port_name[4], fcport->port_name[5],
+                   fcport->port_name[6], fcport->port_name[7],
+                   fcport->loop_id, fcport->login_retry);
        }
 }
 
@@ -2676,6 +2814,9 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
                        ctx_cachep);
                if (!ha->ctx_mempool)
                        goto fail_free_srb_mempool;
+               ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0021,
+                   "ctx_cachep=%p ctx_mempool=%p.\n",
+                   ctx_cachep, ha->ctx_mempool);
        }
 
        /* Get memory for cached NVRAM */
@@ -2690,22 +2831,29 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
        if (!ha->s_dma_pool)
                goto fail_free_nvram;
 
+       ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0022,
+           "init_cb=%p gid_list=%p, srb_mempool=%p s_dma_pool=%p.\n",
+           ha->init_cb, ha->gid_list, ha->srb_mempool, ha->s_dma_pool);
+
        if (IS_QLA82XX(ha) || ql2xenabledif) {
                ha->dl_dma_pool = dma_pool_create(name, &ha->pdev->dev,
                        DSD_LIST_DMA_POOL_SIZE, 8, 0);
                if (!ha->dl_dma_pool) {
-                       qla_printk(KERN_WARNING, ha,
-                           "Memory Allocation failed - dl_dma_pool\n");
+                       ql_log_pci(ql_log_fatal, ha->pdev, 0x0023,
+                           "Failed to allocate memory for dl_dma_pool.\n");
                        goto fail_s_dma_pool;
                }
 
                ha->fcp_cmnd_dma_pool = dma_pool_create(name, &ha->pdev->dev,
                        FCP_CMND_DMA_POOL_SIZE, 8, 0);
                if (!ha->fcp_cmnd_dma_pool) {
-                       qla_printk(KERN_WARNING, ha,
-                           "Memory Allocation failed - fcp_cmnd_dma_pool\n");
+                       ql_log_pci(ql_log_fatal, ha->pdev, 0x0024,
+                           "Failed to allocate memory for fcp_cmnd_dma_pool.\n");
                        goto fail_dl_dma_pool;
                }
+               ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0025,
+                   "dl_dma_pool=%p fcp_cmnd_dma_pool=%p.\n",
+                   ha->dl_dma_pool, ha->fcp_cmnd_dma_pool);
        }
 
        /* Allocate memory for SNS commands */
@@ -2715,6 +2863,8 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
                sizeof(struct sns_cmd_pkt), &ha->sns_cmd_dma, GFP_KERNEL);
                if (!ha->sns_cmd)
                        goto fail_dma_pool;
+               ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0026,
+                   "sns_cmd.\n", ha->sns_cmd);
        } else {
        /* Get consistent memory allocated for MS IOCB */
                ha->ms_iocb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
@@ -2726,12 +2876,16 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
                        sizeof(struct ct_sns_pkt), &ha->ct_sns_dma, GFP_KERNEL);
                if (!ha->ct_sns)
                        goto fail_free_ms_iocb;
+               ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0027,
+                   "ms_iocb=%p ct_sns=%p.\n",
+                   ha->ms_iocb, ha->ct_sns);
        }
 
        /* Allocate memory for request ring */
        *req = kzalloc(sizeof(struct req_que), GFP_KERNEL);
        if (!*req) {
-               DEBUG(printk("Unable to allocate memory for req\n"));
+               ql_log_pci(ql_log_fatal, ha->pdev, 0x0028,
+                   "Failed to allocate memory for req.\n");
                goto fail_req;
        }
        (*req)->length = req_len;
@@ -2739,14 +2893,15 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
                ((*req)->length + 1) * sizeof(request_t),
                &(*req)->dma, GFP_KERNEL);
        if (!(*req)->ring) {
-               DEBUG(printk("Unable to allocate memory for req_ring\n"));
+               ql_log_pci(ql_log_fatal, ha->pdev, 0x0029,
+                   "Failed to allocate memory for req_ring.\n");
                goto fail_req_ring;
        }
        /* Allocate memory for response ring */
        *rsp = kzalloc(sizeof(struct rsp_que), GFP_KERNEL);
        if (!*rsp) {
-               qla_printk(KERN_WARNING, ha,
-                       "Unable to allocate memory for rsp\n");
+               ql_log_pci(ql_log_fatal, ha->pdev, 0x002a,
+                   "Failed to allocate memory for rsp.\n");
                goto fail_rsp;
        }
        (*rsp)->hw = ha;
@@ -2755,19 +2910,24 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
                ((*rsp)->length + 1) * sizeof(response_t),
                &(*rsp)->dma, GFP_KERNEL);
        if (!(*rsp)->ring) {
-               qla_printk(KERN_WARNING, ha,
-                       "Unable to allocate memory for rsp_ring\n");
+               ql_log_pci(ql_log_fatal, ha->pdev, 0x002b,
+                   "Failed to allocate memory for rsp_ring.\n");
                goto fail_rsp_ring;
        }
        (*req)->rsp = *rsp;
        (*rsp)->req = *req;
+       ql_dbg_pci(ql_dbg_init, ha->pdev, 0x002c,
+           "req=%p req->length=%d req->ring=%p rsp=%p "
+           "rsp->length=%d rsp->ring=%p.\n",
+           *req, (*req)->length, (*req)->ring, *rsp, (*rsp)->length,
+           (*rsp)->ring);
        /* Allocate memory for NVRAM data for vports */
        if (ha->nvram_npiv_size) {
                ha->npiv_info = kzalloc(sizeof(struct qla_npiv_entry) *
-                                       ha->nvram_npiv_size, GFP_KERNEL);
+                   ha->nvram_npiv_size, GFP_KERNEL);
                if (!ha->npiv_info) {
-                       qla_printk(KERN_WARNING, ha,
-                               "Unable to allocate memory for npiv info\n");
+                       ql_log_pci(ql_log_fatal, ha->pdev, 0x002d,
+                           "Failed to allocate memory for npiv_info.\n");
                        goto fail_npiv_info;
                }
        } else
@@ -2779,6 +2939,8 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
                    &ha->ex_init_cb_dma);
                if (!ha->ex_init_cb)
                        goto fail_ex_init_cb;
+               ql_dbg_pci(ql_dbg_init, ha->pdev, 0x002e,
+                   "ex_init_cb=%p.\n", ha->ex_init_cb);
        }
 
        INIT_LIST_HEAD(&ha->gbl_dsd_list);
@@ -2789,6 +2951,8 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
                        &ha->async_pd_dma);
                if (!ha->async_pd)
                        goto fail_async_pd;
+               ql_dbg_pci(ql_dbg_init, ha->pdev, 0x002f,
+                   "async_pd=%p.\n", ha->async_pd);
        }
 
        INIT_LIST_HEAD(&ha->vp_list);
@@ -2854,7 +3018,8 @@ fail_free_init_cb:
        ha->init_cb = NULL;
        ha->init_cb_dma = 0;
 fail:
-       DEBUG(printk("%s: Memory allocation failure\n", __func__));
+       ql_log(ql_log_fatal, NULL, 0x0030,
+           "Memory allocation failure.\n");
        return -ENOMEM;
 }
 
@@ -3003,8 +3168,8 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
 
        host = scsi_host_alloc(sht, sizeof(scsi_qla_host_t));
        if (host == NULL) {
-               printk(KERN_WARNING
-               "qla2xxx: Couldn't allocate host from scsi layer!\n");
+               ql_log_pci(ql_log_fatal, ha->pdev, 0x0107,
+                   "Failed to allocate host from the scsi layer, aborting.\n");
                goto fail;
        }
 
@@ -3023,6 +3188,11 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
        spin_lock_init(&vha->work_lock);
 
        sprintf(vha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, vha->host_no);
+       ql_dbg(ql_dbg_init, vha, 0x0041,
+           "Allocated the host=%p hw=%p vha=%p dev_name=%s",
+           vha->host, vha->hw, vha,
+           dev_name(&(ha->pdev->dev)));
+
        return vha;
 
 fail:
@@ -3264,18 +3434,18 @@ void qla2x00_relogin(struct scsi_qla_host *vha)
                        if (status == QLA_SUCCESS) {
                                fcport->old_loop_id = fcport->loop_id;
 
-                               DEBUG(printk("scsi(%ld): port login OK: logged "
-                               "in ID 0x%x\n", vha->host_no, fcport->loop_id));
+                               ql_dbg(ql_dbg_disc, vha, 0x2003,
+                                   "Port login OK: logged in ID 0x%x.\n",
+                                   fcport->loop_id);
 
                                qla2x00_update_fcport(vha, fcport);
 
                        } else if (status == 1) {
                                set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
                                /* retry the login again */
-                               DEBUG(printk("scsi(%ld): Retrying"
-                               " %d login again loop_id 0x%x\n",
-                               vha->host_no, fcport->login_retry,
-                                               fcport->loop_id));
+                               ql_dbg(ql_dbg_disc, vha, 0x2007,
+                                   "Retrying %d login again loop_id 0x%x.\n",
+                                   fcport->login_retry, fcport->loop_id);
                        } else {
                                fcport->login_retry = 0;
                        }
@@ -3315,26 +3485,27 @@ qla2x00_do_dpc(void *data)
 
        set_current_state(TASK_INTERRUPTIBLE);
        while (!kthread_should_stop()) {
-               DEBUG3(printk("qla2x00: DPC handler sleeping\n"));
+               ql_dbg(ql_dbg_dpc, base_vha, 0x4000,
+                   "DPC handler sleeping.\n");
 
                schedule();
                __set_current_state(TASK_RUNNING);
 
-               DEBUG3(printk("qla2x00: DPC handler waking up\n"));
+               ql_dbg(ql_dbg_dpc, base_vha, 0x4001,
+                   "DPC handler waking up.\n");
+               ql_dbg(ql_dbg_dpc, base_vha, 0x4002,
+                   "dpc_flags=0x%lx.\n", base_vha->dpc_flags);
 
                /* Initialization not yet finished. Don't do anything yet. */
                if (!base_vha->flags.init_done)
                        continue;
 
                if (ha->flags.eeh_busy) {
-                       DEBUG17(qla_printk(KERN_WARNING, ha,
-                           "qla2x00_do_dpc: dpc_flags: %lx\n",
-                           base_vha->dpc_flags));
+                       ql_dbg(ql_dbg_dpc, base_vha, 0x4003,
+                           "eeh_busy=%d.\n", ha->flags.eeh_busy);
                        continue;
                }
 
-               DEBUG3(printk("scsi(%ld): DPC handler\n", base_vha->host_no));
-
                ha->dpc_active = 1;
 
                if (ha->flags.mbox_busy) {
@@ -3351,8 +3522,8 @@ qla2x00_do_dpc(void *data)
                                qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
                                        QLA82XX_DEV_FAILED);
                                qla82xx_idc_unlock(ha);
-                               qla_printk(KERN_INFO, ha,
-                                       "HW State: FAILED\n");
+                               ql_log(ql_log_info, base_vha, 0x4004,
+                                   "HW State: FAILED.\n");
                                qla82xx_device_state_handler(base_vha);
                                continue;
                        }
@@ -3360,10 +3531,8 @@ qla2x00_do_dpc(void *data)
                        if (test_and_clear_bit(FCOE_CTX_RESET_NEEDED,
                                &base_vha->dpc_flags)) {
 
-                               DEBUG(printk(KERN_INFO
-                                       "scsi(%ld): dpc: sched "
-                                       "qla82xx_fcoe_ctx_reset ha = %p\n",
-                                       base_vha->host_no, ha));
+                               ql_dbg(ql_dbg_dpc, base_vha, 0x4005,
+                                   "FCoE context reset scheduled.\n");
                                if (!(test_and_set_bit(ABORT_ISP_ACTIVE,
                                        &base_vha->dpc_flags))) {
                                        if (qla82xx_fcoe_ctx_reset(base_vha)) {
@@ -3377,18 +3546,16 @@ qla2x00_do_dpc(void *data)
                                                &base_vha->dpc_flags);
                                }
 
-                               DEBUG(printk("scsi(%ld): dpc:"
-                                       " qla82xx_fcoe_ctx_reset end\n",
-                                       base_vha->host_no));
+                               ql_dbg(ql_dbg_dpc, base_vha, 0x4006,
+                                   "FCoE context reset end.\n");
                        }
                }
 
                if (test_and_clear_bit(ISP_ABORT_NEEDED,
                                                &base_vha->dpc_flags)) {
 
-                       DEBUG(printk("scsi(%ld): dpc: sched "
-                           "qla2x00_abort_isp ha = %p\n",
-                           base_vha->host_no, ha));
+                       ql_dbg(ql_dbg_dpc, base_vha, 0x4007,
+                           "ISP abort scheduled.\n");
                        if (!(test_and_set_bit(ABORT_ISP_ACTIVE,
                            &base_vha->dpc_flags))) {
 
@@ -3401,8 +3568,8 @@ qla2x00_do_dpc(void *data)
                                                &base_vha->dpc_flags);
                        }
 
-                       DEBUG(printk("scsi(%ld): dpc: qla2x00_abort_isp end\n",
-                           base_vha->host_no));
+                       ql_dbg(ql_dbg_dpc, base_vha, 0x4008,
+                           "ISP abort end.\n");
                }
 
                if (test_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags)) {
@@ -3411,9 +3578,8 @@ qla2x00_do_dpc(void *data)
                }
 
                if (test_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags)) {
-                       DEBUG(printk(KERN_INFO "scsi(%ld): dpc: sched "
-                           "qla2x00_quiesce_needed ha = %p\n",
-                           base_vha->host_no, ha));
+                       ql_dbg(ql_dbg_dpc, base_vha, 0x4009,
+                           "Quiescence mode scheduled.\n");
                        qla82xx_device_state_handler(base_vha);
                        clear_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags);
                        if (!ha->flags.quiesce_owner) {
@@ -3423,17 +3589,20 @@ qla2x00_do_dpc(void *data)
                                qla82xx_clear_qsnt_ready(base_vha);
                                qla82xx_idc_unlock(ha);
                        }
+                       ql_dbg(ql_dbg_dpc, base_vha, 0x400a,
+                           "Quiescence mode end.\n");
                }
 
                if (test_and_clear_bit(RESET_MARKER_NEEDED,
                                                        &base_vha->dpc_flags) &&
                    (!(test_and_set_bit(RESET_ACTIVE, &base_vha->dpc_flags)))) {
 
-                       DEBUG(printk("scsi(%ld): qla2x00_reset_marker()\n",
-                           base_vha->host_no));
-
+                       ql_dbg(ql_dbg_dpc, base_vha, 0x400b,
+                           "Reset marker scheduled.\n");
                        qla2x00_rst_aen(base_vha);
                        clear_bit(RESET_ACTIVE, &base_vha->dpc_flags);
+                       ql_dbg(ql_dbg_dpc, base_vha, 0x400c,
+                           "Reset marker end.\n");
                }
 
                /* Retry each device up to login retry count */
@@ -3442,19 +3611,18 @@ qla2x00_do_dpc(void *data)
                    !test_bit(LOOP_RESYNC_NEEDED, &base_vha->dpc_flags) &&
                    atomic_read(&base_vha->loop_state) != LOOP_DOWN) {
 
-                       DEBUG(printk("scsi(%ld): qla2x00_port_login()\n",
-                                       base_vha->host_no));
+                       ql_dbg(ql_dbg_dpc, base_vha, 0x400d,
+                           "Relogin scheduled.\n");
                        qla2x00_relogin(base_vha);
-
-                       DEBUG(printk("scsi(%ld): qla2x00_port_login - end\n",
-                           base_vha->host_no));
+                       ql_dbg(ql_dbg_dpc, base_vha, 0x400e,
+                           "Relogin end.\n");
                }
 
                if (test_and_clear_bit(LOOP_RESYNC_NEEDED,
                                                        &base_vha->dpc_flags)) {
 
-                       DEBUG(printk("scsi(%ld): qla2x00_loop_resync()\n",
-                               base_vha->host_no));
+                       ql_dbg(ql_dbg_dpc, base_vha, 0x400f,
+                           "Loop resync scheduled.\n");
 
                        if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE,
                            &base_vha->dpc_flags))) {
@@ -3465,8 +3633,8 @@ qla2x00_do_dpc(void *data)
                                                &base_vha->dpc_flags);
                        }
 
-                       DEBUG(printk("scsi(%ld): qla2x00_loop_resync - end\n",
-                           base_vha->host_no));
+                       ql_dbg(ql_dbg_dpc, base_vha, 0x4010,
+                           "Loop resync end.\n");
                }
 
                if (test_bit(NPIV_CONFIG_NEEDED, &base_vha->dpc_flags) &&
@@ -3489,7 +3657,8 @@ qla2x00_do_dpc(void *data)
        } /* End of while(1) */
        __set_current_state(TASK_RUNNING);
 
-       DEBUG(printk("scsi(%ld): DPC handler exiting\n", base_vha->host_no));
+       ql_dbg(ql_dbg_dpc, base_vha, 0x4011,
+           "DPC handler exiting.\n");
 
        /*
         * Make sure that nobody tries to wake us up again.
@@ -3596,9 +3765,11 @@ void
 qla2x00_sp_compl(struct qla_hw_data *ha, srb_t *sp)
 {
        if (atomic_read(&sp->ref_count) == 0) {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-                   "SP reference-count to ZERO -- sp=%p\n", sp));
-               DEBUG2(BUG());
+               ql_dbg(ql_dbg_io, sp->fcport->vha, 0x3015,
+                   "SP reference-count to ZERO -- sp=%p cmd=%p.\n",
+                   sp, sp->cmd);
+               if (ql2xextended_error_logging & ql_dbg_io)
+                       BUG();
                return;
        }
        if (!atomic_dec_and_test(&sp->ref_count))
@@ -3626,6 +3797,9 @@ qla2x00_timer(scsi_qla_host_t *vha)
        struct req_que *req;
 
        if (ha->flags.eeh_busy) {
+               ql_dbg(ql_dbg_timer, vha, 0x6000,
+                   "EEH = %d, restarting timer.\n",
+                   ha->flags.eeh_busy);
                qla2x00_restart_timer(vha, WATCH_INTERVAL);
                return;
        }
@@ -3650,9 +3824,8 @@ qla2x00_timer(scsi_qla_host_t *vha)
                if (atomic_read(&vha->loop_down_timer) ==
                    vha->loop_down_abort_time) {
 
-                       DEBUG(printk("scsi(%ld): Loop Down - aborting the "
-                           "queues before time expire\n",
-                           vha->host_no));
+                       ql_log(ql_log_info, vha, 0x6008,
+                           "Loop down - aborting the queues before time expires.\n");
 
                        if (!IS_QLA2100(ha) && vha->link_down_timeout)
                                atomic_set(&vha->loop_state, LOOP_DEAD);
@@ -3697,10 +3870,7 @@ qla2x00_timer(scsi_qla_host_t *vha)
                /* if the loop has been down for 4 minutes, reinit adapter */
                if (atomic_dec_and_test(&vha->loop_down_timer) != 0) {
                        if (!(vha->device_flags & DFLG_NO_CABLE)) {
-                               DEBUG(printk("scsi(%ld): Loop down - "
-                                   "aborting ISP.\n",
-                                   vha->host_no));
-                               qla_printk(KERN_WARNING, ha,
+                               ql_log(ql_log_warn, vha, 0x6009,
                                    "Loop down - aborting ISP.\n");
 
                                if (IS_QLA82XX(ha))
@@ -3711,9 +3881,9 @@ qla2x00_timer(scsi_qla_host_t *vha)
                                                &vha->dpc_flags);
                        }
                }
-               DEBUG3(printk("scsi(%ld): Loop Down - seconds remaining %d\n",
-                   vha->host_no,
-                   atomic_read(&vha->loop_down_timer)));
+               ql_dbg(ql_dbg_timer, vha, 0x600a,
+                   "Loop down - seconds remaining %d.\n",
+                   atomic_read(&vha->loop_down_timer));
        }
 
        /* Check if beacon LED needs to be blinked for physical host only */
@@ -3736,8 +3906,27 @@ qla2x00_timer(scsi_qla_host_t *vha)
            test_bit(ISP_UNRECOVERABLE, &vha->dpc_flags) ||
            test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags) ||
            test_bit(VP_DPC_NEEDED, &vha->dpc_flags) ||
-           test_bit(RELOGIN_NEEDED, &vha->dpc_flags)))
+           test_bit(RELOGIN_NEEDED, &vha->dpc_flags))) {
+               ql_dbg(ql_dbg_timer, vha, 0x600b,
+                   "isp_abort_needed=%d loop_resync_needed=%d "
+                   "fcport_update_needed=%d start_dpc=%d "
+                   "reset_marker_needed=%d",
+                   test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags),
+                   test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags),
+                   test_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags),
+                   start_dpc,
+                   test_bit(RESET_MARKER_NEEDED, &vha->dpc_flags));
+               ql_dbg(ql_dbg_timer, vha, 0x600c,
+                   "beacon_blink_needed=%d isp_unrecoverable=%d "
+                   "fcoe_ctx_reset_needed=%d vp_dpc_needed=%d "
+                   "relogin_needed=%d.\n",
+                   test_bit(BEACON_BLINK_NEEDED, &vha->dpc_flags),
+                   test_bit(ISP_UNRECOVERABLE, &vha->dpc_flags),
+                   test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags),
+                   test_bit(VP_DPC_NEEDED, &vha->dpc_flags),
+                   test_bit(RELOGIN_NEEDED, &vha->dpc_flags));
                qla2xxx_wake_dpc(vha);
+       }
 
        qla2x00_restart_timer(vha, WATCH_INTERVAL);
 }
@@ -3806,8 +3995,8 @@ qla2x00_request_firmware(scsi_qla_host_t *vha)
                goto out;
 
        if (request_firmware(&blob->fw, blob->name, &ha->pdev->dev)) {
-               DEBUG2(printk("scsi(%ld): Failed to load firmware image "
-                   "(%s).\n", vha->host_no, blob->name));
+               ql_log(ql_log_warn, vha, 0x0063,
+                   "Failed to load firmware image (%s).\n", blob->name);
                blob->fw = NULL;
                blob = NULL;
                goto out;
@@ -3836,8 +4025,8 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
        scsi_qla_host_t *vha = pci_get_drvdata(pdev);
        struct qla_hw_data *ha = vha->hw;
 
-       DEBUG2(qla_printk(KERN_WARNING, ha, "error_detected:state %x\n",
-           state));
+       ql_dbg(ql_dbg_aer, vha, 0x9000,
+           "PCI error detected, state %x.\n", state);
 
        switch (state) {
        case pci_channel_io_normal:
@@ -3850,9 +4039,9 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
                        ha->flags.isp82xx_fw_hung = 1;
                        if (ha->flags.mbox_busy) {
                                ha->flags.mbox_int = 1;
-                               DEBUG2(qla_printk(KERN_ERR, ha,
-                                       "Due to pci channel io frozen, doing premature "
-                                       "completion of mbx command\n"));
+                               ql_dbg(ql_dbg_aer, vha, 0x9001,
+                                   "Due to pci channel io frozen, doing premature "
+                                   "completion of mbx command.\n");
                                complete(&ha->mbx_intr_comp);
                        }
                }
@@ -3900,8 +4089,8 @@ qla2xxx_pci_mmio_enabled(struct pci_dev *pdev)
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
        if (risc_paused) {
-               qla_printk(KERN_INFO, ha, "RISC paused -- mmio_enabled, "
-                   "Dumping firmware!\n");
+               ql_log(ql_log_info, base_vha, 0x9003,
+                   "RISC paused -- mmio_enabled, Dumping firmware.\n");
                ha->isp_ops->fw_dump(base_vha, 0);
 
                return PCI_ERS_RESULT_NEED_RESET;
@@ -3917,8 +4106,8 @@ uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha)
        int fn;
        struct pci_dev *other_pdev = NULL;
 
-       DEBUG17(qla_printk(KERN_INFO, ha,
-           "scsi(%ld): In qla82xx_error_recovery\n", base_vha->host_no));
+       ql_dbg(ql_dbg_aer, base_vha, 0x9006,
+           "Entered %s.\n", __func__);
 
        set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
 
@@ -3932,8 +4121,8 @@ uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha)
        fn = PCI_FUNC(ha->pdev->devfn);
        while (fn > 0) {
                fn--;
-               DEBUG17(qla_printk(KERN_INFO, ha,
-                   "Finding pci device at function = 0x%x\n", fn));
+               ql_dbg(ql_dbg_aer, base_vha, 0x9007,
+                   "Finding pci device at function = 0x%x.\n", fn);
                other_pdev =
                    pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus),
                    ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn),
@@ -3942,9 +4131,9 @@ uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha)
                if (!other_pdev)
                        continue;
                if (atomic_read(&other_pdev->enable_cnt)) {
-                       DEBUG17(qla_printk(KERN_INFO, ha,
-                           "Found PCI func available and enabled at 0x%x\n",
-                           fn));
+                       ql_dbg(ql_dbg_aer, base_vha, 0x9008,
+                           "Found PCI func available and enable at 0x%x.\n",
+                           fn);
                        pci_dev_put(other_pdev);
                        break;
                }
@@ -3953,8 +4142,9 @@ uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha)
 
        if (!fn) {
                /* Reset owner */
-               DEBUG17(qla_printk(KERN_INFO, ha,
-                   "This devfn is reset owner = 0x%x\n", ha->pdev->devfn));
+               ql_dbg(ql_dbg_aer, base_vha, 0x9009,
+                   "This devfn is reset owner = 0x%x.\n",
+                   ha->pdev->devfn);
                qla82xx_idc_lock(ha);
 
                qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
@@ -3964,8 +4154,8 @@ uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha)
                    QLA82XX_IDC_VERSION);
 
                drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
-               DEBUG17(qla_printk(KERN_INFO, ha,
-                   "drv_active = 0x%x\n", drv_active));
+               ql_dbg(ql_dbg_aer, base_vha, 0x900a,
+                   "drv_active = 0x%x.\n", drv_active);
 
                qla82xx_idc_unlock(ha);
                /* Reset if device is not already reset
@@ -3978,12 +4168,14 @@ uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha)
                qla82xx_idc_lock(ha);
 
                if (rval != QLA_SUCCESS) {
-                       qla_printk(KERN_INFO, ha, "HW State: FAILED\n");
+                       ql_log(ql_log_info, base_vha, 0x900b,
+                           "HW State: FAILED.\n");
                        qla82xx_clear_drv_active(ha);
                        qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
                            QLA82XX_DEV_FAILED);
                } else {
-                       qla_printk(KERN_INFO, ha, "HW State: READY\n");
+                       ql_log(ql_log_info, base_vha, 0x900c,
+                           "HW State: READY.\n");
                        qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
                            QLA82XX_DEV_READY);
                        qla82xx_idc_unlock(ha);
@@ -3996,8 +4188,9 @@ uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha)
                }
                qla82xx_idc_unlock(ha);
        } else {
-               DEBUG17(qla_printk(KERN_INFO, ha,
-                   "This devfn is not reset owner = 0x%x\n", ha->pdev->devfn));
+               ql_dbg(ql_dbg_aer, base_vha, 0x900d,
+                   "This devfn is not reset owner = 0x%x.\n",
+                   ha->pdev->devfn);
                if ((qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE) ==
                    QLA82XX_DEV_READY)) {
                        ha->flags.isp82xx_fw_hung = 0;
@@ -4021,7 +4214,8 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev)
        struct rsp_que *rsp;
        int rc, retries = 10;
 
-       DEBUG17(qla_printk(KERN_WARNING, ha, "slot_reset\n"));
+       ql_dbg(ql_dbg_aer, base_vha, 0x9004,
+           "Slot Reset.\n");
 
        /* Workaround: qla2xxx driver which access hardware earlier
         * needs error state to be pci_channel_io_online.
@@ -4042,7 +4236,7 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev)
                rc = pci_enable_device(pdev);
 
        if (rc) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, base_vha, 0x9005,
                    "Can't re-enable PCI device after reset.\n");
                goto exit_slot_reset;
        }
@@ -4072,8 +4266,8 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev)
 
 
 exit_slot_reset:
-       DEBUG17(qla_printk(KERN_WARNING, ha,
-           "slot_reset-return:ret=%x\n", ret));
+       ql_dbg(ql_dbg_aer, base_vha, 0x900e,
+           "slot_reset return %x.\n", ret);
 
        return ret;
 }
@@ -4085,13 +4279,13 @@ qla2xxx_pci_resume(struct pci_dev *pdev)
        struct qla_hw_data *ha = base_vha->hw;
        int ret;
 
-       DEBUG17(qla_printk(KERN_WARNING, ha, "pci_resume\n"));
+       ql_dbg(ql_dbg_aer, base_vha, 0x900f,
+           "pci_resume.\n");
 
        ret = qla2x00_wait_for_hba_online(base_vha);
        if (ret != QLA_SUCCESS) {
-               qla_printk(KERN_ERR, ha,
-                   "the device failed to resume I/O "
-                   "from slot/link_reset");
+               ql_log(ql_log_fatal, base_vha, 0x9002,
+                   "The device failed to resume I/O from slot/link_reset.\n");
        }
 
        pci_cleanup_aer_uncorrect_error_status(pdev);
@@ -4155,8 +4349,8 @@ qla2x00_module_init(void)
        srb_cachep = kmem_cache_create("qla2xxx_srbs", sizeof(srb_t), 0,
            SLAB_HWCACHE_ALIGN, NULL);
        if (srb_cachep == NULL) {
-               printk(KERN_ERR
-                   "qla2xxx: Unable to allocate SRB cache...Failing load!\n");
+               ql_log(ql_log_fatal, NULL, 0x0001,
+                   "Unable to allocate SRB cache...Failing load!.\n");
                return -ENOMEM;
        }
 
@@ -4169,13 +4363,15 @@ qla2x00_module_init(void)
            fc_attach_transport(&qla2xxx_transport_functions);
        if (!qla2xxx_transport_template) {
                kmem_cache_destroy(srb_cachep);
+               ql_log(ql_log_fatal, NULL, 0x0002,
+                   "fc_attach_transport failed...Failing load!.\n");
                return -ENODEV;
        }
 
        apidev_major = register_chrdev(0, QLA2XXX_APIDEV, &apidev_fops);
        if (apidev_major < 0) {
-               printk(KERN_WARNING "qla2xxx: Unable to register char device "
-                   "%s\n", QLA2XXX_APIDEV);
+               ql_log(ql_log_fatal, NULL, 0x0003,
+                   "Unable to register char device %s.\n", QLA2XXX_APIDEV);
        }
 
        qla2xxx_transport_vport_template =
@@ -4183,16 +4379,21 @@ qla2x00_module_init(void)
        if (!qla2xxx_transport_vport_template) {
                kmem_cache_destroy(srb_cachep);
                fc_release_transport(qla2xxx_transport_template);
+               ql_log(ql_log_fatal, NULL, 0x0004,
+                   "fc_attach_transport vport failed...Failing load!.\n");
                return -ENODEV;
        }
-
-       printk(KERN_INFO "QLogic Fibre Channel HBA Driver: %s\n",
+       ql_log(ql_log_info, NULL, 0x0005,
+           "QLogic Fibre Channel HBA Driver: %s.\n",
            qla2x00_version_str);
        ret = pci_register_driver(&qla2xxx_pci_driver);
        if (ret) {
                kmem_cache_destroy(srb_cachep);
                fc_release_transport(qla2xxx_transport_template);
                fc_release_transport(qla2xxx_transport_vport_template);
+               ql_log(ql_log_fatal, NULL, 0x0006,
+                   "pci_register_driver failed...ret=%d Failing load!.\n",
+                   ret);
        }
        return ret;
 }
index 6936476..eff1356 100644 (file)
@@ -189,6 +189,7 @@ qla2x00_write_nvram_word(struct qla_hw_data *ha, uint32_t addr, uint16_t data)
        uint16_t word;
        uint32_t nv_cmd, wait_cnt;
        struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        qla2x00_nv_write(ha, NVR_DATA_OUT);
        qla2x00_nv_write(ha, 0);
@@ -220,8 +221,8 @@ qla2x00_write_nvram_word(struct qla_hw_data *ha, uint32_t addr, uint16_t data)
        wait_cnt = NVR_WAIT_CNT;
        do {
                if (!--wait_cnt) {
-                       DEBUG9_10(qla_printk(KERN_WARNING, ha,
-                           "NVRAM didn't go ready...\n"));
+                       ql_dbg(ql_dbg_user, vha, 0x708d,
+                           "NVRAM didn't go ready...\n");
                        break;
                }
                NVRAM_DELAY();
@@ -308,6 +309,7 @@ qla2x00_clear_nvram_protection(struct qla_hw_data *ha)
        struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
        uint32_t word, wait_cnt;
        uint16_t wprot, wprot_old;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        /* Clear NVRAM write protection. */
        ret = QLA_FUNCTION_FAILED;
@@ -350,8 +352,8 @@ qla2x00_clear_nvram_protection(struct qla_hw_data *ha)
                wait_cnt = NVR_WAIT_CNT;
                do {
                        if (!--wait_cnt) {
-                               DEBUG9_10(qla_printk(KERN_WARNING, ha,
-                                   "NVRAM didn't go ready...\n"));
+                               ql_dbg(ql_dbg_user, vha, 0x708e,
+                                   "NVRAM didn't go ready...\n");
                                break;
                        }
                        NVRAM_DELAY();
@@ -371,6 +373,7 @@ qla2x00_set_nvram_protection(struct qla_hw_data *ha, int stat)
 {
        struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
        uint32_t word, wait_cnt;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        if (stat != QLA_SUCCESS)
                return;
@@ -409,8 +412,8 @@ qla2x00_set_nvram_protection(struct qla_hw_data *ha, int stat)
        wait_cnt = NVR_WAIT_CNT;
        do {
                if (!--wait_cnt) {
-                       DEBUG9_10(qla_printk(KERN_WARNING, ha,
-                           "NVRAM didn't go ready...\n"));
+                       ql_dbg(ql_dbg_user, vha, 0x708f,
+                           "NVRAM didn't go ready...\n");
                        break;
                }
                NVRAM_DELAY();
@@ -607,9 +610,10 @@ qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start)
        for (chksum = 0; cnt; cnt--)
                chksum += le16_to_cpu(*wptr++);
        if (chksum) {
-               qla_printk(KERN_ERR, ha,
+               ql_log(ql_log_fatal, vha, 0x0045,
                    "Inconsistent FLTL detected: checksum=0x%x.\n", chksum);
-               qla2x00_dump_buffer(buf, sizeof(struct qla_flt_location));
+               ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x010e,
+                   buf, sizeof(struct qla_flt_location));
                return QLA_FUNCTION_FAILED;
        }
 
@@ -618,7 +622,9 @@ qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start)
        *start = (le16_to_cpu(fltl->start_hi) << 16 |
            le16_to_cpu(fltl->start_lo)) >> 2;
 end:
-       DEBUG2(qla_printk(KERN_DEBUG, ha, "FLTL[%s] = 0x%x.\n", loc, *start));
+       ql_dbg(ql_dbg_init, vha, 0x0046,
+           "FLTL[%s] = 0x%x.\n",
+           loc, *start);
        return QLA_SUCCESS;
 }
 
@@ -685,10 +691,10 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
        if (*wptr == __constant_cpu_to_le16(0xffff))
                goto no_flash_data;
        if (flt->version != __constant_cpu_to_le16(1)) {
-               DEBUG2(qla_printk(KERN_INFO, ha, "Unsupported FLT detected: "
-                   "version=0x%x length=0x%x checksum=0x%x.\n",
+               ql_log(ql_log_warn, vha, 0x0047,
+                   "Unsupported FLT detected: version=0x%x length=0x%x checksum=0x%x.\n",
                    le16_to_cpu(flt->version), le16_to_cpu(flt->length),
-                   le16_to_cpu(flt->checksum)));
+                   le16_to_cpu(flt->checksum));
                goto no_flash_data;
        }
 
@@ -696,10 +702,10 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
        for (chksum = 0; cnt; cnt--)
                chksum += le16_to_cpu(*wptr++);
        if (chksum) {
-               DEBUG2(qla_printk(KERN_INFO, ha, "Inconsistent FLT detected: "
-                   "version=0x%x length=0x%x checksum=0x%x.\n",
+               ql_log(ql_log_fatal, vha, 0x0048,
+                   "Inconsistent FLT detected: version=0x%x length=0x%x checksum=0x%x.\n",
                    le16_to_cpu(flt->version), le16_to_cpu(flt->length),
-                   chksum));
+                   le16_to_cpu(flt->checksum));
                goto no_flash_data;
        }
 
@@ -708,10 +714,11 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
        for ( ; cnt; cnt--, region++) {
                /* Store addresses as DWORD offsets. */
                start = le32_to_cpu(region->start) >> 2;
-
-               DEBUG3(qla_printk(KERN_DEBUG, ha, "FLT[%02x]: start=0x%x "
-                   "end=0x%x size=0x%x.\n", le32_to_cpu(region->code), start,
-                   le32_to_cpu(region->end) >> 2, le32_to_cpu(region->size)));
+               ql_dbg(ql_dbg_init, vha, 0x0049,
+                   "FLT[%02x]: start=0x%x "
+                   "end=0x%x size=0x%x.\n", le32_to_cpu(region->code),
+                   start, le32_to_cpu(region->end) >> 2,
+                   le32_to_cpu(region->size));
 
                switch (le32_to_cpu(region->code) & 0xff) {
                case FLT_REG_FW:
@@ -796,12 +803,16 @@ no_flash_data:
        ha->flt_region_npiv_conf = ha->flags.port0 ?
            def_npiv_conf0[def] : def_npiv_conf1[def];
 done:
-       DEBUG2(qla_printk(KERN_DEBUG, ha, "FLT[%s]: boot=0x%x fw=0x%x "
-           "vpd_nvram=0x%x vpd=0x%x nvram=0x%x fdt=0x%x flt=0x%x "
-           "npiv=0x%x. fcp_prio_cfg=0x%x\n", loc, ha->flt_region_boot,
-           ha->flt_region_fw, ha->flt_region_vpd_nvram, ha->flt_region_vpd,
-           ha->flt_region_nvram, ha->flt_region_fdt, ha->flt_region_flt,
-           ha->flt_region_npiv_conf, ha->flt_region_fcp_prio));
+       ql_dbg(ql_dbg_init, vha, 0x004a,
+           "FLT[%s]: boot=0x%x fw=0x%x vpd_nvram=0x%x vpd=0x%x.\n",
+           loc, ha->flt_region_boot,
+           ha->flt_region_fw, ha->flt_region_vpd_nvram,
+           ha->flt_region_vpd);
+       ql_dbg(ql_dbg_init, vha, 0x004b,
+           "nvram=0x%x fdt=0x%x flt=0x%x npiv=0x%x fcp_prif_cfg=0x%x.\n",
+           ha->flt_region_nvram,
+           ha->flt_region_fdt, ha->flt_region_flt,
+           ha->flt_region_npiv_conf, ha->flt_region_fcp_prio);
 }
 
 static void
@@ -833,10 +844,12 @@ qla2xxx_get_fdt_info(scsi_qla_host_t *vha)
            cnt++)
                chksum += le16_to_cpu(*wptr++);
        if (chksum) {
-               DEBUG2(qla_printk(KERN_INFO, ha, "Inconsistent FDT detected: "
-                   "checksum=0x%x id=%c version=0x%x.\n", chksum, fdt->sig[0],
-                   le16_to_cpu(fdt->version)));
-               DEBUG9(qla2x00_dump_buffer((uint8_t *)fdt, sizeof(*fdt)));
+               ql_dbg(ql_dbg_init, vha, 0x004c,
+                   "Inconsistent FDT detected:"
+                   " checksum=0x%x id=%c version0x%x.\n", chksum,
+                   fdt->sig[0], le16_to_cpu(fdt->version));
+               ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0113,
+                   (uint8_t *)fdt, sizeof(*fdt));
                goto no_flash_data;
        }
 
@@ -890,11 +903,12 @@ no_flash_data:
                break;
        }
 done:
-       DEBUG2(qla_printk(KERN_DEBUG, ha, "FDT[%s]: (0x%x/0x%x) erase=0x%x "
-           "pro=%x upro=%x wrtd=0x%x blk=0x%x.\n", loc, mid, fid,
+       ql_dbg(ql_dbg_init, vha, 0x004d,
+           "FDT[%x]: (0x%x/0x%x) erase=0x%x "
+           "pr=%x upro=%x wrtd=0x%x blk=0x%x.\n", loc, mid, fid,
            ha->fdt_erase_cmd, ha->fdt_protect_sec_cmd,
-           ha->fdt_unprotect_sec_cmd, ha->fdt_wrt_disable,
-           ha->fdt_block_size));
+           ha->fdt_wrt_disable, ha->fdt_block_size);
+
 }
 
 static void
@@ -919,6 +933,10 @@ qla2xxx_get_idc_param(scsi_qla_host_t *vha)
                ha->nx_dev_init_timeout = le32_to_cpu(*wptr++);
                ha->nx_reset_timeout = le32_to_cpu(*wptr);
        }
+       ql_dbg(ql_dbg_init, vha, 0x004e,
+           "nx_dev_init_timeout=%d "
+           "nx_reset_timeout=%d.\n", ha->nx_dev_init_timeout,
+           ha->nx_reset_timeout);
        return;
 }
 
@@ -963,17 +981,18 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha)
        if (hdr.version == __constant_cpu_to_le16(0xffff))
                return;
        if (hdr.version != __constant_cpu_to_le16(1)) {
-               DEBUG2(qla_printk(KERN_INFO, ha, "Unsupported NPIV-Config "
+               ql_dbg(ql_dbg_user, vha, 0x7090,
+                   "Unsupported NPIV-Config "
                    "detected: version=0x%x entries=0x%x checksum=0x%x.\n",
                    le16_to_cpu(hdr.version), le16_to_cpu(hdr.entries),
-                   le16_to_cpu(hdr.checksum)));
+                   le16_to_cpu(hdr.checksum));
                return;
        }
 
        data = kmalloc(NPIV_CONFIG_SIZE, GFP_KERNEL);
        if (!data) {
-               DEBUG2(qla_printk(KERN_INFO, ha, "NPIV-Config: Unable to "
-                   "allocate memory.\n"));
+               ql_log(ql_log_warn, vha, 0x7091,
+                   "Unable to allocate memory for data.\n");
                return;
        }
 
@@ -985,10 +1004,11 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha)
        for (wptr = data, chksum = 0; cnt; cnt--)
                chksum += le16_to_cpu(*wptr++);
        if (chksum) {
-               DEBUG2(qla_printk(KERN_INFO, ha, "Inconsistent NPIV-Config "
+               ql_dbg(ql_dbg_user, vha, 0x7092,
+                   "Inconsistent NPIV-Config "
                    "detected: version=0x%x entries=0x%x checksum=0x%x.\n",
                    le16_to_cpu(hdr.version), le16_to_cpu(hdr.entries),
-                   chksum));
+                   le16_to_cpu(hdr.checksum));
                goto done;
        }
 
@@ -1014,21 +1034,22 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha)
                vid.port_name = wwn_to_u64(entry->port_name);
                vid.node_name = wwn_to_u64(entry->node_name);
 
-               DEBUG2(qla_printk(KERN_INFO, ha, "NPIV[%02x]: wwpn=%llx "
-                       "wwnn=%llx vf_id=0x%x Q_qos=0x%x F_qos=0x%x.\n", cnt,
-                       (unsigned long long)vid.port_name,
-                       (unsigned long long)vid.node_name,
-                       le16_to_cpu(entry->vf_id),
-                       entry->q_qos, entry->f_qos));
+               ql_dbg(ql_dbg_user, vha, 0x7093,
+                   "NPIV[%02x]: wwpn=%llx "
+                   "wwnn=%llx vf_id=0x%x Q_qos=0x%x F_qos=0x%x.\n", cnt,
+                   (unsigned long long)vid.port_name,
+                   (unsigned long long)vid.node_name,
+                   le16_to_cpu(entry->vf_id),
+                   entry->q_qos, entry->f_qos);
 
                if (i < QLA_PRECONFIG_VPORTS) {
                        vport = fc_vport_create(vha->host, 0, &vid);
                        if (!vport)
-                               qla_printk(KERN_INFO, ha,
-                               "NPIV-Config: Failed to create vport [%02x]: "
-                               "wwpn=%llx wwnn=%llx.\n", cnt,
-                               (unsigned long long)vid.port_name,
-                               (unsigned long long)vid.node_name);
+                               ql_log(ql_log_warn, vha, 0x7094,
+                                   "NPIV-Config Failed to create vport [%02x]: "
+                                   "wwpn=%llx wwnn=%llx.\n", cnt,
+                                   (unsigned long long)vid.port_name,
+                                   (unsigned long long)vid.node_name);
                }
        }
 done:
@@ -1127,9 +1148,10 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
                optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
                    &optrom_dma, GFP_KERNEL);
                if (!optrom) {
-                       qla_printk(KERN_DEBUG, ha,
-                           "Unable to allocate memory for optrom burst write "
-                           "(%x KB).\n", OPTROM_BURST_SIZE / 1024);
+                       ql_log(ql_log_warn, vha, 0x7095,
+                           "Unable to allocate "
+                           "memory for optrom burst write (%x KB).\n",
+                           OPTROM_BURST_SIZE / 1024);
                }
        }
 
@@ -1138,7 +1160,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
 
        ret = qla24xx_unprotect_flash(vha);
        if (ret != QLA_SUCCESS) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x7096,
                    "Unable to unprotect flash for update.\n");
                goto done;
        }
@@ -1156,9 +1178,9 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
                                    0xff0000) | ((fdata >> 16) & 0xff));
                        ret = qla24xx_erase_sector(vha, fdata);
                        if (ret != QLA_SUCCESS) {
-                               DEBUG9(qla_printk(KERN_WARNING, ha,
-                                   "Unable to erase sector: address=%x.\n",
-                                   faddr));
+                               ql_dbg(ql_dbg_user, vha, 0x7007,
+                                   "Unable to erase erase sector: address=%x.\n",
+                                   faddr);
                                break;
                        }
                }
@@ -1172,12 +1194,12 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
                            flash_data_addr(ha, faddr),
                            OPTROM_BURST_DWORDS);
                        if (ret != QLA_SUCCESS) {
-                               qla_printk(KERN_WARNING, ha,
+                               ql_log(ql_log_warn, vha, 0x7097,
                                    "Unable to burst-write optrom segment "
                                    "(%x/%x/%llx).\n", ret,
                                    flash_data_addr(ha, faddr),
                                    (unsigned long long)optrom_dma);
-                               qla_printk(KERN_WARNING, ha,
+                               ql_log(ql_log_warn, vha, 0x7098,
                                    "Reverting to slow-write.\n");
 
                                dma_free_coherent(&ha->pdev->dev,
@@ -1194,9 +1216,9 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
                ret = qla24xx_write_flash_dword(ha,
                    flash_data_addr(ha, faddr), cpu_to_le32(*dwptr));
                if (ret != QLA_SUCCESS) {
-                       DEBUG9(printk("%s(%ld) Unable to program flash "
-                           "address=%x data=%x.\n", __func__,
-                           vha->host_no, faddr, *dwptr));
+                       ql_dbg(ql_dbg_user, vha, 0x7006,
+                           "Unable to program flash address=%x data=%x.\n",
+                           faddr, *dwptr);
                        break;
                }
 
@@ -1211,7 +1233,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
 
        ret = qla24xx_protect_flash(vha);
        if (ret != QLA_SUCCESS)
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x7099,
                    "Unable to protect flash after update.\n");
 done:
        if (optrom)
@@ -1324,9 +1346,9 @@ qla24xx_write_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr,
                ret = qla24xx_write_flash_dword(ha,
                    nvram_data_addr(ha, naddr), cpu_to_le32(*dwptr));
                if (ret != QLA_SUCCESS) {
-                       DEBUG9(qla_printk(KERN_WARNING, ha,
+                       ql_dbg(ql_dbg_user, vha, 0x709a,
                            "Unable to program nvram address=%x data=%x.\n",
-                           naddr, *dwptr));
+                           naddr, *dwptr);
                        break;
                }
        }
@@ -1476,7 +1498,7 @@ qla2x00_beacon_on(struct scsi_qla_host *vha)
        ha->fw_options[1] |= FO1_DISABLE_GPIO6_7;
 
        if (qla2x00_set_fw_options(vha, ha->fw_options) != QLA_SUCCESS) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x709b,
                    "Unable to update fw options (beacon on).\n");
                return QLA_FUNCTION_FAILED;
        }
@@ -1541,7 +1563,7 @@ qla2x00_beacon_off(struct scsi_qla_host *vha)
 
        rval = qla2x00_set_fw_options(vha, ha->fw_options);
        if (rval != QLA_SUCCESS)
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x709c,
                    "Unable to update fw options (beacon off).\n");
        return rval;
 }
@@ -1616,7 +1638,7 @@ qla24xx_beacon_on(struct scsi_qla_host *vha)
 
                if (qla2x00_get_fw_options(vha, ha->fw_options) !=
                    QLA_SUCCESS) {
-                       qla_printk(KERN_WARNING, ha,
+                       ql_log(ql_log_warn, vha, 0x7009,
                            "Unable to update fw options (beacon on).\n");
                        return QLA_FUNCTION_FAILED;
                }
@@ -1670,14 +1692,14 @@ qla24xx_beacon_off(struct scsi_qla_host *vha)
        ha->fw_options[1] &= ~ADD_FO1_DISABLE_GPIO_LED_CTRL;
 
        if (qla2x00_set_fw_options(vha, ha->fw_options) != QLA_SUCCESS) {
-               qla_printk(KERN_WARNING, ha,
-                   "Unable to update fw options (beacon off).\n");
+               ql_log(ql_log_warn, vha, 0x704d,
+                   "Unable to update fw options (beacon on).\n");
                return QLA_FUNCTION_FAILED;
        }
 
        if (qla2x00_get_fw_options(vha, ha->fw_options) != QLA_SUCCESS) {
-               qla_printk(KERN_WARNING, ha,
-                   "Unable to get fw options (beacon off).\n");
+               ql_log(ql_log_warn, vha, 0x704e,
+                   "Unable to update fw options (beacon on).\n");
                return QLA_FUNCTION_FAILED;
        }
 
@@ -2389,10 +2411,9 @@ try_fast:
        optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
            &optrom_dma, GFP_KERNEL);
        if (!optrom) {
-               qla_printk(KERN_DEBUG, ha,
-                   "Unable to allocate memory for optrom burst read "
-                   "(%x KB).\n", OPTROM_BURST_SIZE / 1024);
-
+               ql_log(ql_log_warn, vha, 0x00cc,
+                   "Unable to allocate memory for optrom burst read (%x KB).\n",
+                   OPTROM_BURST_SIZE / 1024);
                goto slow_read;
        }
 
@@ -2407,12 +2428,11 @@ try_fast:
                rval = qla2x00_dump_ram(vha, optrom_dma,
                    flash_data_addr(ha, faddr), burst);
                if (rval) {
-                       qla_printk(KERN_WARNING, ha,
-                           "Unable to burst-read optrom segment "
-                           "(%x/%x/%llx).\n", rval,
-                           flash_data_addr(ha, faddr),
+                       ql_log(ql_log_warn, vha, 0x00f5,
+                           "Unable to burst-read optrom segment (%x/%x/%llx).\n",
+                           rval, flash_data_addr(ha, faddr),
                            (unsigned long long)optrom_dma);
-                       qla_printk(KERN_WARNING, ha,
+                       ql_log(ql_log_warn, vha, 0x00f6,
                            "Reverting to slow-read.\n");
 
                        dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
@@ -2556,8 +2576,8 @@ qla2x00_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
                if (qla2x00_read_flash_byte(ha, pcihdr) != 0x55 ||
                    qla2x00_read_flash_byte(ha, pcihdr + 0x01) != 0xaa) {
                        /* No signature */
-                       DEBUG2(qla_printk(KERN_DEBUG, ha, "No matching ROM "
-                           "signature.\n"));
+                       ql_log(ql_log_fatal, vha, 0x0050,
+                           "No matching ROM signature.\n");
                        ret = QLA_FUNCTION_FAILED;
                        break;
                }
@@ -2573,8 +2593,8 @@ qla2x00_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
                    qla2x00_read_flash_byte(ha, pcids + 0x2) != 'I' ||
                    qla2x00_read_flash_byte(ha, pcids + 0x3) != 'R') {
                        /* Incorrect header. */
-                       DEBUG2(qla_printk(KERN_INFO, ha, "PCI data struct not "
-                           "found pcir_adr=%x.\n", pcids));
+                       ql_log(ql_log_fatal, vha, 0x0051,
+                           "PCI data struct not found pcir_adr=%x.\n", pcids);
                        ret = QLA_FUNCTION_FAILED;
                        break;
                }
@@ -2588,8 +2608,9 @@ qla2x00_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
                            qla2x00_read_flash_byte(ha, pcids + 0x12);
                        ha->bios_revision[1] =
                            qla2x00_read_flash_byte(ha, pcids + 0x13);
-                       DEBUG3(qla_printk(KERN_DEBUG, ha, "read BIOS %d.%d.\n",
-                           ha->bios_revision[1], ha->bios_revision[0]));
+                       ql_dbg(ql_dbg_init, vha, 0x0052,
+                           "Read BIOS %d.%d.\n",
+                           ha->bios_revision[1], ha->bios_revision[0]);
                        break;
                case ROM_CODE_TYPE_FCODE:
                        /* Open Firmware standard for PCI (FCode). */
@@ -2602,12 +2623,14 @@ qla2x00_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
                            qla2x00_read_flash_byte(ha, pcids + 0x12);
                        ha->efi_revision[1] =
                            qla2x00_read_flash_byte(ha, pcids + 0x13);
-                       DEBUG3(qla_printk(KERN_DEBUG, ha, "read EFI %d.%d.\n",
-                           ha->efi_revision[1], ha->efi_revision[0]));
+                       ql_dbg(ql_dbg_init, vha, 0x0053,
+                           "Read EFI %d.%d.\n",
+                           ha->efi_revision[1], ha->efi_revision[0]);
                        break;
                default:
-                       DEBUG2(qla_printk(KERN_INFO, ha, "Unrecognized code "
-                           "type %x at pcids %x.\n", code_type, pcids));
+                       ql_log(ql_log_warn, vha, 0x0054,
+                           "Unrecognized code type %x at pcids %x.\n",
+                           code_type, pcids);
                        break;
                }
 
@@ -2627,21 +2650,28 @@ qla2x00_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
 
                qla2x00_read_flash_data(ha, dbyte, ha->flt_region_fw * 4 + 10,
                    8);
-               DEBUG3(qla_printk(KERN_DEBUG, ha, "dumping fw ver from "
-                   "flash:\n"));
-               DEBUG3(qla2x00_dump_buffer((uint8_t *)dbyte, 8));
+               ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x010a,
+                   "Dumping fw "
+                   "ver from flash:.\n");
+               ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x010b,
+                   (uint8_t *)dbyte, 8);
 
                if ((dcode[0] == 0xffff && dcode[1] == 0xffff &&
                    dcode[2] == 0xffff && dcode[3] == 0xffff) ||
                    (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
                    dcode[3] == 0)) {
-                       DEBUG2(qla_printk(KERN_INFO, ha, "Unrecognized fw "
-                           "revision at %x.\n", ha->flt_region_fw * 4));
+                       ql_log(ql_log_warn, vha, 0x0057,
+                           "Unrecognized fw revision at %x.\n",
+                           ha->flt_region_fw * 4);
                } else {
                        /* values are in big endian */
                        ha->fw_revision[0] = dbyte[0] << 16 | dbyte[1];
                        ha->fw_revision[1] = dbyte[2] << 16 | dbyte[3];
                        ha->fw_revision[2] = dbyte[4] << 16 | dbyte[5];
+                       ql_dbg(ql_dbg_init, vha, 0x0058,
+                           "FW Version: "
+                           "%d.%d.%d.\n", ha->fw_revision[0],
+                           ha->fw_revision[1], ha->fw_revision[2]);
                }
        }
 
@@ -2683,8 +2713,8 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
                bcode = mbuf + (pcihdr % 4);
                if (bcode[0x0] != 0x55 || bcode[0x1] != 0xaa) {
                        /* No signature */
-                       DEBUG2(qla_printk(KERN_DEBUG, ha, "No matching ROM "
-                           "signature.\n"));
+                       ql_log(ql_log_fatal, vha, 0x0059,
+                           "No matching ROM signature.\n");
                        ret = QLA_FUNCTION_FAILED;
                        break;
                }
@@ -2699,8 +2729,8 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
                if (bcode[0x0] != 'P' || bcode[0x1] != 'C' ||
                    bcode[0x2] != 'I' || bcode[0x3] != 'R') {
                        /* Incorrect header. */
-                       DEBUG2(qla_printk(KERN_INFO, ha, "PCI data struct not "
-                           "found pcir_adr=%x.\n", pcids));
+                       ql_log(ql_log_fatal, vha, 0x005a,
+                           "PCI data struct not found pcir_adr=%x.\n", pcids);
                        ret = QLA_FUNCTION_FAILED;
                        break;
                }
@@ -2712,26 +2742,30 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
                        /* Intel x86, PC-AT compatible. */
                        ha->bios_revision[0] = bcode[0x12];
                        ha->bios_revision[1] = bcode[0x13];
-                       DEBUG3(qla_printk(KERN_DEBUG, ha, "read BIOS %d.%d.\n",
-                           ha->bios_revision[1], ha->bios_revision[0]));
+                       ql_dbg(ql_dbg_init, vha, 0x005b,
+                           "Read BIOS %d.%d.\n",
+                           ha->bios_revision[1], ha->bios_revision[0]);
                        break;
                case ROM_CODE_TYPE_FCODE:
                        /* Open Firmware standard for PCI (FCode). */
                        ha->fcode_revision[0] = bcode[0x12];
                        ha->fcode_revision[1] = bcode[0x13];
-                       DEBUG3(qla_printk(KERN_DEBUG, ha, "read FCODE %d.%d.\n",
-                           ha->fcode_revision[1], ha->fcode_revision[0]));
+                       ql_dbg(ql_dbg_init, vha, 0x005c,
+                           "Read FCODE %d.%d.\n",
+                           ha->fcode_revision[1], ha->fcode_revision[0]);
                        break;
                case ROM_CODE_TYPE_EFI:
                        /* Extensible Firmware Interface (EFI). */
                        ha->efi_revision[0] = bcode[0x12];
                        ha->efi_revision[1] = bcode[0x13];
-                       DEBUG3(qla_printk(KERN_DEBUG, ha, "read EFI %d.%d.\n",
-                           ha->efi_revision[1], ha->efi_revision[0]));
+                       ql_dbg(ql_dbg_init, vha, 0x005d,
+                           "Read EFI %d.%d.\n",
+                           ha->efi_revision[1], ha->efi_revision[0]);
                        break;
                default:
-                       DEBUG2(qla_printk(KERN_INFO, ha, "Unrecognized code "
-                           "type %x at pcids %x.\n", code_type, pcids));
+                       ql_log(ql_log_warn, vha, 0x005e,
+                           "Unrecognized code type %x at pcids %x.\n",
+                           code_type, pcids);
                        break;
                }
 
@@ -2753,13 +2787,18 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
            dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) ||
            (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
            dcode[3] == 0)) {
-               DEBUG2(qla_printk(KERN_INFO, ha, "Unrecognized fw "
-                   "revision at %x.\n", ha->flt_region_fw * 4));
+               ql_log(ql_log_warn, vha, 0x005f,
+                   "Unrecognized fw revision at %x.\n",
+                   ha->flt_region_fw * 4);
        } else {
                ha->fw_revision[0] = dcode[0];
                ha->fw_revision[1] = dcode[1];
                ha->fw_revision[2] = dcode[2];
                ha->fw_revision[3] = dcode[3];
+               ql_dbg(ql_dbg_init, vha, 0x0060,
+                   "Firmware revision %d.%d.%d.%d.\n",
+                   ha->fw_revision[0], ha->fw_revision[1],
+                   ha->fw_revision[2], ha->fw_revision[3]);
        }
 
        /* Check for golden firmware and get version if available */
@@ -2775,9 +2814,9 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
 
        if (dcode[4] == 0xFFFFFFFF && dcode[5] == 0xFFFFFFFF &&
            dcode[6] == 0xFFFFFFFF && dcode[7] == 0xFFFFFFFF) {
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                   "%s(%ld): Unrecognized golden fw at 0x%x.\n",
-                   __func__, vha->host_no, ha->flt_region_gold_fw * 4));
+               ql_log(ql_log_warn, vha, 0x0056,
+                   "Unrecognized golden fw at 0x%x.\n",
+                   ha->flt_region_gold_fw * 4);
                return ret;
        }
 
@@ -2843,9 +2882,9 @@ qla24xx_read_fcp_prio_cfg(scsi_qla_host_t *vha)
        if (!ha->fcp_prio_cfg) {
                ha->fcp_prio_cfg = vmalloc(FCP_PRIO_CFG_SIZE);
                if (!ha->fcp_prio_cfg) {
-                       qla_printk(KERN_WARNING, ha,
-                       "Unable to allocate memory for fcp priority data "
-                                       "(%x).\n", FCP_PRIO_CFG_SIZE);
+                       ql_log(ql_log_warn, vha, 0x00d5,
+                           "Unable to allocate memory for fcp priorty data (%x).\n",
+                           FCP_PRIO_CFG_SIZE);
                        return QLA_FUNCTION_FAILED;
                }
        }
@@ -2857,7 +2896,7 @@ qla24xx_read_fcp_prio_cfg(scsi_qla_host_t *vha)
        ha->isp_ops->read_optrom(vha, (uint8_t *)ha->fcp_prio_cfg,
                        fcp_prio_addr << 2, FCP_PRIO_CFG_HDR_SIZE);
 
-       if (!qla24xx_fcp_prio_cfg_valid(ha->fcp_prio_cfg, 0))
+       if (!qla24xx_fcp_prio_cfg_valid(vha, ha->fcp_prio_cfg, 0))
                goto fail;
 
        /* read remaining FCP CMD config data from flash */
@@ -2869,7 +2908,7 @@ qla24xx_read_fcp_prio_cfg(scsi_qla_host_t *vha)
                        fcp_prio_addr << 2, (len < max_len ? len : max_len));
 
        /* revalidate the entire FCP priority config data, including entries */
-       if (!qla24xx_fcp_prio_cfg_valid(ha->fcp_prio_cfg, 1))
+       if (!qla24xx_fcp_prio_cfg_valid(vha, ha->fcp_prio_cfg, 1))
                goto fail;
 
        ha->flags.fcp_prio_enabled = 1;
index 28d9c9d..fc3f168 100644 (file)
@@ -137,6 +137,7 @@ static int __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, int unbusy)
                host->host_blocked = host->max_host_blocked;
                break;
        case SCSI_MLQUEUE_DEVICE_BUSY:
+       case SCSI_MLQUEUE_EH_RETRY:
                device->device_blocked = device->max_device_blocked;
                break;
        case SCSI_MLQUEUE_TARGET_BUSY:
index 8a172d4..5fbeadd 100644 (file)
@@ -597,6 +597,28 @@ static DEVICE_ATTR(signalling, S_IRUGO,
                   show_spi_host_signalling,
                   store_spi_host_signalling);
 
+static ssize_t show_spi_host_width(struct device *cdev,
+                                     struct device_attribute *attr,
+                                     char *buf)
+{
+       struct Scsi_Host *shost = transport_class_to_shost(cdev);
+
+       return sprintf(buf, "%s\n", shost->max_id == 16 ? "wide" : "narrow");
+}
+static DEVICE_ATTR(host_width, S_IRUGO,
+                  show_spi_host_width, NULL);
+
+static ssize_t show_spi_host_hba_id(struct device *cdev,
+                                   struct device_attribute *attr,
+                                   char *buf)
+{
+       struct Scsi_Host *shost = transport_class_to_shost(cdev);
+
+       return sprintf(buf, "%d\n", shost->this_id);
+}
+static DEVICE_ATTR(hba_id, S_IRUGO,
+                  show_spi_host_hba_id, NULL);
+
 #define DV_SET(x, y)                   \
        if(i->f->set_##x)               \
                i->f->set_##x(sdev->sdev_target, y)
@@ -1380,6 +1402,8 @@ static DECLARE_ANON_TRANSPORT_CLASS(spi_device_class,
 
 static struct attribute *host_attributes[] = {
        &dev_attr_signalling.attr,
+       &dev_attr_host_width.attr,
+       &dev_attr_hba_id.attr,
        NULL
 };
 
index d6702e5..dc8d022 100644 (file)
@@ -34,6 +34,9 @@ static LIST_HEAD(clock_list);
 static DEFINE_SPINLOCK(clock_lock);
 static DEFINE_MUTEX(clock_list_sem);
 
+/* clock disable operations are not passed on to hardware during boot */
+static int allow_disable;
+
 void clk_rate_table_build(struct clk *clk,
                          struct cpufreq_frequency_table *freq_table,
                          int nr_freqs,
@@ -228,7 +231,7 @@ static void __clk_disable(struct clk *clk)
                return;
 
        if (!(--clk->usecount)) {
-               if (likely(clk->ops && clk->ops->disable))
+               if (likely(allow_disable && clk->ops && clk->ops->disable))
                        clk->ops->disable(clk);
                if (likely(clk->parent))
                        __clk_disable(clk->parent);
@@ -393,7 +396,7 @@ int clk_register(struct clk *clk)
 {
        int ret;
 
-       if (clk == NULL || IS_ERR(clk))
+       if (IS_ERR_OR_NULL(clk))
                return -EINVAL;
 
        /*
@@ -744,3 +747,25 @@ err_out:
        return err;
 }
 late_initcall(clk_debugfs_init);
+
+static int __init clk_late_init(void)
+{
+       unsigned long flags;
+       struct clk *clk;
+
+       /* disable all clocks with zero use count */
+       mutex_lock(&clock_list_sem);
+       spin_lock_irqsave(&clock_lock, flags);
+
+       list_for_each_entry(clk, &clock_list, node)
+               if (!clk->usecount && clk->ops && clk->ops->disable)
+                       clk->ops->disable(clk);
+
+       /* from now on allow clock disable operations */
+       allow_disable = 1;
+
+       spin_unlock_irqrestore(&clock_lock, flags);
+       mutex_unlock(&clock_list_sem);
+       return 0;
+}
+late_initcall(clk_late_init);
index eba88c7..730b4a3 100644 (file)
@@ -2267,17 +2267,13 @@ static int __devexit
 pl022_remove(struct amba_device *adev)
 {
        struct pl022 *pl022 = amba_get_drvdata(adev);
-       int status = 0;
+
        if (!pl022)
                return 0;
 
        /* Remove the queue */
-       status = destroy_queue(pl022);
-       if (status != 0) {
-               dev_err(&adev->dev,
-                       "queue remove failed (%d)\n", status);
-               return status;
-       }
+       if (destroy_queue(pl022) != 0)
+               dev_err(&adev->dev, "queue remove failed\n");
        load_ssp_default_config(pl022);
        pl022_dma_remove(pl022);
        free_irq(adev->irq[0], pl022);
@@ -2289,7 +2285,6 @@ pl022_remove(struct amba_device *adev)
        spi_unregister_master(pl022->master);
        spi_master_put(pl022->master);
        amba_set_drvdata(adev, NULL);
-       dev_dbg(&adev->dev, "remove succeeded\n");
        return 0;
 }
 
index c01c0cb..b99a11a 100644 (file)
@@ -812,7 +812,7 @@ int AthCreateCommandList(struct ps_cmd_packet **HciPacketList, u32 *numPackets)
     for(count = 0; count < Patch_Count; count++) {
 
         AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Freeing Patch Buffer %d \r\n",count));
-        kfree(RamPatch[Patch_Count].Data);
+       kfree(RamPatch[count].Data);
     }
 
     for(count = 0; count < Tag_Count; count++) {
index 9d638c3..b48aefd 100644 (file)
@@ -1,9 +1,10 @@
 config DVB_CXD2099
-        tristate "CXD2099AR Common Interface driver"
-        depends on DVB_CORE && PCI && I2C && DVB_NGENE
-        ---help---
-          Support for the CI module found on cineS2 DVB-S2, supported by
-         the Micronas PCIe device driver (ngene).
+       tristate "CXD2099AR Common Interface driver"
+       depends on DVB_CORE && PCI && I2C
+       ---help---
+         Support for the CI module found on cards based on
+         - Micronas ngene PCIe bridge: cineS2 etc.
+         - Digital Devices PCIe bridge: Octopus series
 
          For now, data is passed through '/dev/dvb/adapterX/sec0':
            - Encrypted data must be written to 'sec0'.
index 55b1c4a..1c04185 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * cxd2099.c: Driver for the CXD2099AR Common Interface Controller
  *
- * Copyright (C) 2010 DigitalDevices UG
+ * Copyright (C) 2010-2011 Digital Devices GmbH
  *
  *
  * This program is free software; you can redistribute it and/or
@@ -41,13 +41,13 @@ struct cxd {
        struct dvb_ca_en50221 en;
 
        struct i2c_adapter *i2c;
-       u8     adr;
+       struct cxd2099_cfg cfg;
+
        u8     regs[0x23];
        u8     lastaddress;
        u8     clk_reg_f;
        u8     clk_reg_b;
        int    mode;
-       u32    bitrate;
        int    ready;
        int    dr;
        int    slot_stat;
@@ -89,9 +89,9 @@ static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr,
                        u8 reg, u8 *val)
 {
        struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
-                                  .buf = &reg, .len = 1 },
+                                  .buf = &reg, .len = 1},
                                  {.addr = adr, .flags = I2C_M_RD,
-                                  .buf = val, .len = 1 } };
+                                  .buf = val, .len = 1} };
 
        if (i2c_transfer(adapter, msgs, 2) != 2) {
                printk(KERN_ERR "error in i2c_read_reg\n");
@@ -104,9 +104,9 @@ static int i2c_read(struct i2c_adapter *adapter, u8 adr,
                    u8 reg, u8 *data, u8 n)
 {
        struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
-                                  .buf = &reg, .len = 1 },
-                                 {.addr = adr, .flags = I2C_M_RD,
-                                  .buf = data, .len = n } };
+                                .buf = &reg, .len = 1},
+                               {.addr = adr, .flags = I2C_M_RD,
+                                .buf = data, .len = n} };
 
        if (i2c_transfer(adapter, msgs, 2) != 2) {
                printk(KERN_ERR "error in i2c_read\n");
@@ -119,10 +119,10 @@ static int read_block(struct cxd *ci, u8 adr, u8 *data, u8 n)
 {
        int status;
 
-       status = i2c_write_reg(ci->i2c, ci->adr, 0, adr);
+       status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr);
        if (!status) {
                ci->lastaddress = adr;
-               status = i2c_read(ci->i2c, ci->adr, 1, data, n);
+               status = i2c_read(ci->i2c, ci->cfg.adr, 1, data, n);
        }
        return status;
 }
@@ -136,24 +136,24 @@ static int read_reg(struct cxd *ci, u8 reg, u8 *val)
 static int read_pccard(struct cxd *ci, u16 address, u8 *data, u8 n)
 {
        int status;
-       u8 addr[3] = { 2, address&0xff, address>>8 };
+       u8 addr[3] = {2, address & 0xff, address >> 8};
 
-       status = i2c_write(ci->i2c, ci->adr, addr, 3);
+       status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
        if (!status)
-               status = i2c_read(ci->i2c, ci->adr, 3, data, n);
+               status = i2c_read(ci->i2c, ci->cfg.adr, 3, data, n);
        return status;
 }
 
 static int write_pccard(struct cxd *ci, u16 address, u8 *data, u8 n)
 {
        int status;
-       u8 addr[3] = { 2, address&0xff, address>>8 };
+       u8 addr[3] = {2, address & 0xff, address >> 8};
 
-       status = i2c_write(ci->i2c, ci->adr, addr, 3);
+       status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
        if (!status) {
                u8 buf[256] = {3};
                memcpy(buf+1, data, n);
-               status = i2c_write(ci->i2c, ci->adr, buf, n+1);
+               status = i2c_write(ci->i2c, ci->cfg.adr, buf, n+1);
        }
        return status;
 }
@@ -161,39 +161,64 @@ static int write_pccard(struct cxd *ci, u16 address, u8 *data, u8 n)
 static int read_io(struct cxd *ci, u16 address, u8 *val)
 {
        int status;
-       u8 addr[3] = { 2, address&0xff, address>>8 };
+       u8 addr[3] = {2, address & 0xff, address >> 8};
 
-       status = i2c_write(ci->i2c, ci->adr, addr, 3);
+       status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
        if (!status)
-               status = i2c_read(ci->i2c, ci->adr, 3, val, 1);
+               status = i2c_read(ci->i2c, ci->cfg.adr, 3, val, 1);
        return status;
 }
 
 static int write_io(struct cxd *ci, u16 address, u8 val)
 {
        int status;
-       u8 addr[3] = { 2, address&0xff, address>>8 };
-       u8 buf[2] = { 3, val };
+       u8 addr[3] = {2, address & 0xff, address >> 8};
+       u8 buf[2] = {3, val};
 
-       status = i2c_write(ci->i2c, ci->adr, addr, 3);
+       status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
        if (!status)
-               status = i2c_write(ci->i2c, ci->adr, buf, 2);
-
+               status = i2c_write(ci->i2c, ci->cfg.adr, buf, 2);
        return status;
 }
 
+#if 0
+static int read_io_data(struct cxd *ci, u8 *data, u8 n)
+{
+       int status;
+       u8 addr[3] = { 2, 0, 0 };
+
+       status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
+       if (!status)
+               status = i2c_read(ci->i2c, ci->cfg.adr, 3, data, n);
+       return 0;
+}
+
+static int write_io_data(struct cxd *ci, u8 *data, u8 n)
+{
+       int status;
+       u8 addr[3] = {2, 0, 0};
+
+       status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
+       if (!status) {
+               u8 buf[256] = {3};
+               memcpy(buf+1, data, n);
+               status = i2c_write(ci->i2c, ci->cfg.adr, buf, n + 1);
+       }
+       return 0;
+}
+#endif
 
 static int write_regm(struct cxd *ci, u8 reg, u8 val, u8 mask)
 {
        int status;
 
-       status = i2c_write_reg(ci->i2c, ci->adr, 0, reg);
+       status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, reg);
        if (!status && reg >= 6 && reg <= 8 && mask != 0xff)
-               status = i2c_read_reg(ci->i2c, ci->adr, 1, &ci->regs[reg]);
-       ci->regs[reg] = (ci->regs[reg]&(~mask))|val;
+               status = i2c_read_reg(ci->i2c, ci->cfg.adr, 1, &ci->regs[reg]);
+       ci->regs[reg] = (ci->regs[reg] & (~mask)) | val;
        if (!status) {
                ci->lastaddress = reg;
-               status = i2c_write_reg(ci->i2c, ci->adr, 1, ci->regs[reg]);
+               status = i2c_write_reg(ci->i2c, ci->cfg.adr, 1, ci->regs[reg]);
        }
        if (reg == 0x20)
                ci->regs[reg] &= 0x7f;
@@ -211,11 +236,11 @@ static int write_block(struct cxd *ci, u8 adr, u8 *data, int n)
        int status;
        u8 buf[256] = {1};
 
-       status = i2c_write_reg(ci->i2c, ci->adr, 0, adr);
+       status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr);
        if (!status) {
                ci->lastaddress = adr;
-               memcpy(buf+1, data, n);
-               status = i2c_write(ci->i2c, ci->adr, buf, n+1);
+               memcpy(buf + 1, data, n);
+               status = i2c_write(ci->i2c, ci->cfg.adr, buf, n + 1);
        }
        return status;
 }
@@ -249,12 +274,16 @@ static void cam_mode(struct cxd *ci, int mode)
                write_regm(ci, 0x20, 0x80, 0x80);
                break;
        case 0x01:
+#ifdef BUFFER_MODE
+               if (!ci->en.read_data)
+                       return;
                printk(KERN_INFO "enable cam buffer mode\n");
                /* write_reg(ci, 0x0d, 0x00); */
                /* write_reg(ci, 0x0e, 0x01); */
                write_regm(ci, 0x08, 0x40, 0x40);
                /* read_reg(ci, 0x12, &dummy); */
                write_regm(ci, 0x08, 0x80, 0x80);
+#endif
                break;
        default:
                break;
@@ -264,8 +293,6 @@ static void cam_mode(struct cxd *ci, int mode)
 
 
 
-#define CHK_ERROR(s) if ((status = s)) break
-
 static int init(struct cxd *ci)
 {
        int status;
@@ -273,63 +300,160 @@ static int init(struct cxd *ci)
        mutex_lock(&ci->lock);
        ci->mode = -1;
        do {
-               CHK_ERROR(write_reg(ci, 0x00, 0x00));
-               CHK_ERROR(write_reg(ci, 0x01, 0x00));
-               CHK_ERROR(write_reg(ci, 0x02, 0x10));
-               CHK_ERROR(write_reg(ci, 0x03, 0x00));
-               CHK_ERROR(write_reg(ci, 0x05, 0xFF));
-               CHK_ERROR(write_reg(ci, 0x06, 0x1F));
-               CHK_ERROR(write_reg(ci, 0x07, 0x1F));
-               CHK_ERROR(write_reg(ci, 0x08, 0x28));
-               CHK_ERROR(write_reg(ci, 0x14, 0x20));
-
-               CHK_ERROR(write_reg(ci, 0x09, 0x4D)); /* Input Mode C, BYPass Serial, TIVAL = low, MSB */
-               CHK_ERROR(write_reg(ci, 0x0A, 0xA7)); /* TOSTRT = 8, Mode B (gated clock), falling Edge, Serial, POL=HIGH, MSB */
-
-               /* Sync detector */
-               CHK_ERROR(write_reg(ci, 0x0B, 0x33));
-               CHK_ERROR(write_reg(ci, 0x0C, 0x33));
-
-               CHK_ERROR(write_regm(ci, 0x14, 0x00, 0x0F));
-               CHK_ERROR(write_reg(ci, 0x15, ci->clk_reg_b));
-               CHK_ERROR(write_regm(ci, 0x16, 0x00, 0x0F));
-               CHK_ERROR(write_reg(ci, 0x17, ci->clk_reg_f));
-
-               CHK_ERROR(write_reg(ci, 0x20, 0x28)); /* Integer Divider, Falling Edge, Internal Sync, */
-               CHK_ERROR(write_reg(ci, 0x21, 0x00)); /* MCLKI = TICLK/8 */
-               CHK_ERROR(write_reg(ci, 0x22, 0x07)); /* MCLKI = TICLK/8 */
-
-
-               CHK_ERROR(write_regm(ci, 0x20, 0x80, 0x80)); /* Reset CAM state machine */
-
-               CHK_ERROR(write_regm(ci, 0x03, 0x02, 02));  /* Enable IREQA Interrupt */
-               CHK_ERROR(write_reg(ci, 0x01, 0x04));  /* Enable CD Interrupt */
-               CHK_ERROR(write_reg(ci, 0x00, 0x31));  /* Enable TS1,Hot Swap,Slot A */
-               CHK_ERROR(write_regm(ci, 0x09, 0x08, 0x08));  /* Put TS in bypass */
+               status = write_reg(ci, 0x00, 0x00);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x01, 0x00);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x02, 0x10);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x03, 0x00);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x05, 0xFF);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x06, 0x1F);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x07, 0x1F);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x08, 0x28);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x14, 0x20);
+               if (status < 0)
+                       break;
+
+#if 0
+               status = write_reg(ci, 0x09, 0x4D); /* Input Mode C, BYPass Serial, TIVAL = low, MSB */
+               if (status < 0)
+                       break;
+#endif
+               status = write_reg(ci, 0x0A, 0xA7); /* TOSTRT = 8, Mode B (gated clock), falling Edge, Serial, POL=HIGH, MSB */
+               if (status < 0)
+                       break;
+
+               status = write_reg(ci, 0x0B, 0x33);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x0C, 0x33);
+               if (status < 0)
+                       break;
+
+               status = write_regm(ci, 0x14, 0x00, 0x0F);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x15, ci->clk_reg_b);
+               if (status < 0)
+                       break;
+               status = write_regm(ci, 0x16, 0x00, 0x0F);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x17, ci->clk_reg_f);
+               if (status < 0)
+                       break;
+
+               if (ci->cfg.clock_mode) {
+                       if (ci->cfg.polarity) {
+                               status = write_reg(ci, 0x09, 0x6f);
+                               if (status < 0)
+                                       break;
+                       } else {
+                               status = write_reg(ci, 0x09, 0x6d);
+                               if (status < 0)
+                                       break;
+                       }
+                       status = write_reg(ci, 0x20, 0x68);
+                       if (status < 0)
+                               break;
+                       status = write_reg(ci, 0x21, 0x00);
+                       if (status < 0)
+                               break;
+                       status = write_reg(ci, 0x22, 0x02);
+                       if (status < 0)
+                               break;
+               } else {
+                       if (ci->cfg.polarity) {
+                               status = write_reg(ci, 0x09, 0x4f);
+                               if (status < 0)
+                                       break;
+                       } else {
+                               status = write_reg(ci, 0x09, 0x4d);
+                               if (status < 0)
+                                       break;
+                       }
+
+                       status = write_reg(ci, 0x20, 0x28);
+                       if (status < 0)
+                               break;
+                       status = write_reg(ci, 0x21, 0x00);
+                       if (status < 0)
+                               break;
+                       status = write_reg(ci, 0x22, 0x07);
+                       if (status < 0)
+                               break;
+               }
+
+               status = write_regm(ci, 0x20, 0x80, 0x80);
+               if (status < 0)
+                       break;
+               status = write_regm(ci, 0x03, 0x02, 0x02);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x01, 0x04);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x00, 0x31);
+               if (status < 0)
+                       break;
+
+               /* Put TS in bypass */
+               status = write_regm(ci, 0x09, 0x08, 0x08);
+               if (status < 0)
+                       break;
                ci->cammode = -1;
-#ifdef BUFFER_MODE
                cam_mode(ci, 0);
-#endif
        } while (0);
        mutex_unlock(&ci->lock);
 
        return 0;
 }
 
-
 static int read_attribute_mem(struct dvb_ca_en50221 *ca,
                              int slot, int address)
 {
        struct cxd *ci = ca->data;
+#if 0
+       if (ci->amem_read) {
+               if (address <= 0 || address > 1024)
+                       return -EIO;
+               return ci->amem[address];
+       }
+
+       mutex_lock(&ci->lock);
+       write_regm(ci, 0x06, 0x00, 0x05);
+       read_pccard(ci, 0, &ci->amem[0], 128);
+       read_pccard(ci, 128, &ci->amem[0], 128);
+       read_pccard(ci, 256, &ci->amem[0], 128);
+       read_pccard(ci, 384, &ci->amem[0], 128);
+       write_regm(ci, 0x06, 0x05, 0x05);
+       mutex_unlock(&ci->lock);
+       return ci->amem[address];
+#else
        u8 val;
        mutex_lock(&ci->lock);
        set_mode(ci, 1);
        read_pccard(ci, address, &val, 1);
        mutex_unlock(&ci->lock);
+       /* printk(KERN_INFO "%02x:%02x\n", address,val); */
        return val;
+#endif
 }
 
-
 static int write_attribute_mem(struct dvb_ca_en50221 *ca, int slot,
                               int address, u8 value)
 {
@@ -372,6 +496,15 @@ static int slot_reset(struct dvb_ca_en50221 *ca, int slot)
        struct cxd *ci = ca->data;
 
        mutex_lock(&ci->lock);
+#if 0
+       write_reg(ci, 0x00, 0x21);
+       write_reg(ci, 0x06, 0x1F);
+       write_reg(ci, 0x00, 0x31);
+#else
+#if 0
+       write_reg(ci, 0x06, 0x1F);
+       write_reg(ci, 0x06, 0x2F);
+#else
        cam_mode(ci, 0);
        write_reg(ci, 0x00, 0x21);
        write_reg(ci, 0x06, 0x1F);
@@ -379,13 +512,25 @@ static int slot_reset(struct dvb_ca_en50221 *ca, int slot)
        write_regm(ci, 0x20, 0x80, 0x80);
        write_reg(ci, 0x03, 0x02);
        ci->ready = 0;
+#endif
+#endif
        ci->mode = -1;
        {
                int i;
+#if 0
+               u8 val;
+#endif
                for (i = 0; i < 100; i++) {
                        msleep(10);
+#if 0
+                       read_reg(ci, 0x06, &val);
+                       printk(KERN_INFO "%d:%02x\n", i, val);
+                       if (!(val&0x10))
+                               break;
+#else
                        if (ci->ready)
                                break;
+#endif
                }
        }
        mutex_unlock(&ci->lock);
@@ -399,12 +544,12 @@ static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
 
        printk(KERN_INFO "slot_shutdown\n");
        mutex_lock(&ci->lock);
-       /* write_regm(ci, 0x09, 0x08, 0x08); */
-       write_regm(ci, 0x20, 0x80, 0x80);
-       write_regm(ci, 0x06, 0x07, 0x07);
+       write_regm(ci, 0x09, 0x08, 0x08);
+       write_regm(ci, 0x20, 0x80, 0x80); /* Reset CAM Mode */
+       write_regm(ci, 0x06, 0x07, 0x07); /* Clear IO Mode */
        ci->mode = -1;
        mutex_unlock(&ci->lock);
-       return 0; /* shutdown(ci); */
+       return 0;
 }
 
 static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
@@ -459,7 +604,6 @@ static int campoll(struct cxd *ci)
                if (istat&8 && ci->slot_stat == DVB_CA_EN50221_POLL_CAM_PRESENT) {
                        ci->ready = 1;
                        ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_READY;
-                       printk(KERN_INFO "READY\n");
                }
        }
        return 0;
@@ -510,7 +654,7 @@ static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
        struct cxd *ci = ca->data;
 
        mutex_lock(&ci->lock);
-       printk(KERN_INFO "write_data %d\n", ecount);
+       printk(kern_INFO "write_data %d\n", ecount);
        write_reg(ci, 0x0d, ecount>>8);
        write_reg(ci, 0x0e, ecount&0xff);
        write_block(ci, 0x11, ebuf, ecount);
@@ -535,15 +679,15 @@ static struct dvb_ca_en50221 en_templ = {
 
 };
 
-struct dvb_ca_en50221 *cxd2099_attach(u8 adr, void *priv,
+struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg,
+                                     void *priv,
                                      struct i2c_adapter *i2c)
 {
        struct cxd *ci = 0;
-       u32 bitrate = 62000000;
        u8 val;
 
-       if (i2c_read_reg(i2c, adr, 0, &val) < 0) {
-               printk(KERN_ERR "No CXD2099 detected at %02x\n", adr);
+       if (i2c_read_reg(i2c, cfg->adr, 0, &val) < 0) {
+               printk(KERN_INFO "No CXD2099 detected at %02x\n", cfg->adr);
                return 0;
        }
 
@@ -553,21 +697,20 @@ struct dvb_ca_en50221 *cxd2099_attach(u8 adr, void *priv,
        memset(ci, 0, sizeof(*ci));
 
        mutex_init(&ci->lock);
+       memcpy(&ci->cfg, cfg, sizeof(struct cxd2099_cfg));
        ci->i2c = i2c;
-       ci->adr = adr;
        ci->lastaddress = 0xff;
        ci->clk_reg_b = 0x4a;
        ci->clk_reg_f = 0x1b;
-       ci->bitrate = bitrate;
 
        memcpy(&ci->en, &en_templ, sizeof(en_templ));
        ci->en.data = ci;
        init(ci);
-       printk(KERN_INFO "Attached CXD2099AR at %02x\n", ci->adr);
+       printk(KERN_INFO "Attached CXD2099AR at %02x\n", ci->cfg.adr);
        return &ci->en;
 }
 EXPORT_SYMBOL(cxd2099_attach);
 
 MODULE_DESCRIPTION("cxd2099");
-MODULE_AUTHOR("Ralph Metzler <rjkm@metzlerbros.de>");
+MODULE_AUTHOR("Ralph Metzler");
 MODULE_LICENSE("GPL");
index bed54ff..19c588a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * cxd2099.h: Driver for the CXD2099AR Common Interface Controller
  *
- * Copyright (C) 2010 DigitalDevices UG
+ * Copyright (C) 2010-2011 Digital Devices GmbH
  *
  *
  * This program is free software; you can redistribute it and/or
 
 #include <dvb_ca_en50221.h>
 
+struct cxd2099_cfg {
+       u32 bitrate;
+       u8  adr;
+       u8  polarity:1;
+       u8  clock_mode:1;
+};
+
 #if defined(CONFIG_DVB_CXD2099) || \
-        (defined(CONFIG_DVB_CXD2099_MODULE) && defined(MODULE))
-struct dvb_ca_en50221 *cxd2099_attach(u8 adr, void *priv, struct i2c_adapter *i2c);
+       (defined(CONFIG_DVB_CXD2099_MODULE) && defined(MODULE))
+struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg,
+                                     void *priv, struct i2c_adapter *i2c);
 #else
-static inline struct dvb_ca_en50221 *cxd2099_attach(u8 adr, void *priv, struct i2c_adapter *i2c)
+
+static inline struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg,
+                                       void *priv, struct i2c_adapter *i2c)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return NULL;
index fe02d22..05aa41c 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/stringify.h>
 #include <linux/delay.h>
 #include <linux/kthread.h>
+#include <linux/slab.h>
 #include <media/v4l2-dev.h>
 #include <media/v4l2-ioctl.h>
 #include <media/videobuf2-dma-contig.h>
index 627a98b..9e728b3 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/string.h>
 #include <linux/vmalloc.h>
 #include <linux/netdevice.h>
+#include <asm/io.h>
 #include <asm/uaccess.h>
 #include "ft1000.h"
 
index 779ac1a..daac121 100644 (file)
 #include <drm/drmP.h>
 #include <drm/drm.h>
 
-/**
- * Initialize an already allocated GEM object of the specified size with
- * no GEM provided backing store. Instead the caller is responsible for
- * backing the object and handling it.
- */
-int drm_gem_private_object_init(struct drm_device *dev,
-                       struct drm_gem_object *obj, size_t size)
-{
-       BUG_ON((size & (PAGE_SIZE - 1)) != 0);
-
-       obj->dev = dev;
-       obj->filp = NULL;
-
-       kref_init(&obj->refcount);
-       atomic_set(&obj->handle_count, 0);
-       obj->size = size;
-
-       return 0;
-}
-
 void drm_gem_object_release_wrap(struct drm_gem_object *obj)
 {
        /* Remove the list map if one is present */
@@ -51,8 +31,7 @@ void drm_gem_object_release_wrap(struct drm_gem_object *obj)
                kfree(list->map);
                list->map = NULL;
        }
-       if (obj->filp)
-               drm_gem_object_release(obj);
+       drm_gem_object_release(obj);
 }
 
 /**
index a0f2bc4..ce5ce30 100644 (file)
@@ -1,4 +1,2 @@
 extern void drm_gem_object_release_wrap(struct drm_gem_object *obj);
-extern int drm_gem_private_object_init(struct drm_device *dev,
-                       struct drm_gem_object *obj, size_t size);
 extern int gem_create_mmap_offset(struct drm_gem_object *obj);
index 02e17c9..fd211f3 100644 (file)
@@ -711,10 +711,11 @@ struct mdfld_dsi_encoder *mdfld_dsi_dbi_init(struct drm_device *dev,
        /* Create drm encoder object */
        connector = &dsi_connector->base.base;
        encoder = &dbi_output->base.base;
+       /* Review this if we ever get MIPI-HDMI bridges or similar */
        drm_encoder_init(dev,
                        encoder,
                        p_funcs->encoder_funcs,
-                       DRM_MODE_ENCODER_MIPI);
+                       DRM_MODE_ENCODER_LVDS);
        drm_encoder_helper_add(encoder, p_funcs->encoder_helper_funcs);
 
        /* Attach to given connector */
index dc6242c..f0fa986 100644 (file)
@@ -42,9 +42,6 @@
 #include "mdfld_dsi_output.h"
 #include "mdfld_output.h"
 
-#define DRM_MODE_ENCODER_MIPI  5
-
-
 /*
  * DBI encoder which inherits from mdfld_dsi_encoder
  */
index 6e03a91..e685f12 100644 (file)
@@ -777,10 +777,15 @@ struct mdfld_dsi_encoder *mdfld_dsi_dpi_init(struct drm_device *dev,
        /* Create drm encoder object */
        connector = &dsi_connector->base.base;
        encoder = &dpi_output->base.base;
+       /*
+        * On existing hardware this will be a panel of some form,
+        * if future devices also have HDMI bridges this will need
+        * revisiting
+        */
        drm_encoder_init(dev,
                        encoder,
                        p_funcs->encoder_funcs,
-                       DRM_MODE_ENCODER_MIPI);
+                       DRM_MODE_ENCODER_LVDS);
        drm_encoder_helper_add(encoder,
                                p_funcs->encoder_helper_funcs);
        
index 7536095..9050c0f 100644 (file)
@@ -955,7 +955,9 @@ void mdfld_dsi_output_init(struct drm_device *dev,
        psb_output->type = (pipe == 0) ? INTEL_OUTPUT_MIPI : INTEL_OUTPUT_MIPI2;
 
        connector = &psb_output->base;
-       drm_connector_init(dev, connector, &mdfld_dsi_connector_funcs, DRM_MODE_CONNECTOR_MIPI);
+       /* Revisit type if MIPI/HDMI bridges ever appear on Medfield */
+       drm_connector_init(dev, connector, &mdfld_dsi_connector_funcs,
+                                               DRM_MODE_CONNECTOR_LVDS);
        drm_connector_helper_add(connector, &mdfld_dsi_connector_helper_funcs);
        
        connector->display_info.subpixel_order = SubPixelHorizontalRGB;
index 38165e8..09e9687 100644 (file)
@@ -21,8 +21,6 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-#define DRM_MODE_ENCODER_MIPI  5
-
 /* Medfield DSI controller registers */
 
 #define MIPIA_DEVICE_READY_REG                         0xb000
index 72f487a..fd4732d 100644 (file)
@@ -35,7 +35,6 @@
 
 /* Append new drm mode definition here, align with libdrm definition */
 #define DRM_MODE_SCALE_NO_SCALE        2
-#define DRM_MODE_CONNECTOR_MIPI         15
 
 enum {
        CHIP_PSB_8108 = 0,              /* Poulsbo */
index 3612574..d286b22 100644 (file)
@@ -325,7 +325,7 @@ static int blkvsc_do_operation(struct block_device_context *blkdev,
 
        page_buf = alloc_page(GFP_KERNEL);
        if (!page_buf) {
-               kmem_cache_free(blkvsc_req->dev->request_pool, blkvsc_req);
+               kmem_cache_free(blkdev->request_pool, blkvsc_req);
                return -ENOMEM;
        }
 
@@ -422,7 +422,7 @@ cleanup:
 
        __free_page(page_buf);
 
-       kmem_cache_free(blkvsc_req->dev->request_pool, blkvsc_req);
+       kmem_cache_free(blkdev->request_pool, blkvsc_req);
 
        return ret;
 }
index bf19888..cf5d15d 100644 (file)
@@ -311,13 +311,17 @@ static int adis16203_read_raw(struct iio_dev *indio_dev,
                mutex_lock(&indio_dev->mlock);
                addr = adis16203_addresses[chan->address][0];
                ret = adis16203_spi_read_reg_16(indio_dev, addr, &val16);
-               if (ret)
+               if (ret) {
+                       mutex_unlock(&indio_dev->mlock);
                        return ret;
+               }
 
                if (val16 & ADIS16203_ERROR_ACTIVE) {
                        ret = adis16203_check_status(indio_dev);
-                       if (ret)
+                       if (ret) {
+                               mutex_unlock(&indio_dev->mlock);
                                return ret;
+                       }
                }
                val16 = val16 & ((1 << chan->scan_type.realbits) - 1);
                if (chan->scan_type.sign == 's')
index cfd09b3..3e2b626 100644 (file)
@@ -341,13 +341,17 @@ static int adis16204_read_raw(struct iio_dev *indio_dev,
                mutex_lock(&indio_dev->mlock);
                addr = adis16204_addresses[chan->address][0];
                ret = adis16204_spi_read_reg_16(indio_dev, addr, &val16);
-               if (ret)
+               if (ret) {
+                       mutex_unlock(&indio_dev->mlock);
                        return ret;
+               }
 
                if (val16 & ADIS16204_ERROR_ACTIVE) {
                        ret = adis16204_check_status(indio_dev);
-                       if (ret)
+                       if (ret) {
+                               mutex_unlock(&indio_dev->mlock);
                                return ret;
+                       }
                }
                val16 = val16 & ((1 << chan->scan_type.realbits) - 1);
                if (chan->scan_type.sign == 's')
index 55f3a7b..bec1fa8 100644 (file)
@@ -337,13 +337,17 @@ static int adis16209_read_raw(struct iio_dev *indio_dev,
                mutex_lock(&indio_dev->mlock);
                addr = adis16209_addresses[chan->address][0];
                ret = adis16209_spi_read_reg_16(indio_dev, addr, &val16);
-               if (ret)
+               if (ret) {
+                       mutex_unlock(&indio_dev->mlock);
                        return ret;
+               }
 
                if (val16 & ADIS16209_ERROR_ACTIVE) {
                        ret = adis16209_check_status(indio_dev);
-                       if (ret)
+                       if (ret) {
+                               mutex_unlock(&indio_dev->mlock);
                                return ret;
+                       }
                }
                val16 = val16 & ((1 << chan->scan_type.realbits) - 1);
                if (chan->scan_type.sign == 's')
index 4a4eafc..aee8b69 100644 (file)
@@ -370,13 +370,17 @@ static int adis16240_read_raw(struct iio_dev *indio_dev,
                mutex_lock(&indio_dev->mlock);
                addr = adis16240_addresses[chan->address][0];
                ret = adis16240_spi_read_reg_16(indio_dev, addr, &val16);
-               if (ret)
+               if (ret) {
+                       mutex_unlock(&indio_dev->mlock);
                        return ret;
+               }
 
                if (val16 & ADIS16240_ERROR_ACTIVE) {
                        ret = adis16240_check_status(indio_dev);
-                       if (ret)
+                       if (ret) {
+                               mutex_unlock(&indio_dev->mlock);
                                return ret;
+                       }
                }
                val16 = val16 & ((1 << chan->scan_type.realbits) - 1);
                if (chan->scan_type.sign == 's')
index 05797f4..f2d43cf 100644 (file)
@@ -446,13 +446,17 @@ static int adis16260_read_raw(struct iio_dev *indio_dev,
                mutex_lock(&indio_dev->mlock);
                addr = adis16260_addresses[chan->address][0];
                ret = adis16260_spi_read_reg_16(indio_dev, addr, &val16);
-               if (ret)
+               if (ret) {
+                       mutex_unlock(&indio_dev->mlock);
                        return ret;
+               }
 
                if (val16 & ADIS16260_ERROR_ACTIVE) {
                        ret = adis16260_check_status(indio_dev);
-                       if (ret)
+                       if (ret) {
+                               mutex_unlock(&indio_dev->mlock);
                                return ret;
+                       }
                }
                val16 = val16 & ((1 << chan->scan_type.realbits) - 1);
                if (chan->scan_type.sign == 's')
index 77b47f7..649d6b7 100644 (file)
@@ -4,5 +4,7 @@ ToDo list (incomplete, unordered)
        - add compile as module support
        - move nvec devices to mfd cells?
        - adjust to kernel style
-
-
+       - fix clk usage
+         should not be using clk_get_sys(), but clk_get(&pdev->dev, conn)
+         where conn is either NULL if the device only has one clock, or
+         the device specific name if it has multiple clocks.
index 6766f46..4bb5fff 100644 (file)
@@ -399,10 +399,7 @@ download_firmware_fail:
 
 }
 
-
-
-
-
-
-
+MODULE_FIRMWARE("RTL8192U/boot.img");
+MODULE_FIRMWARE("RTL8192U/main.img");
+MODULE_FIRMWARE("RTL8192U/data.img");
 
index 5ff59f2..16c73fb 100644 (file)
@@ -66,12 +66,6 @@ static int msi_en;
 module_param(msi_en, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(msi_en, "enable msi");
 
-/* These are used to make sure the module doesn't unload before all the
- * threads have exited.
- */
-static atomic_t total_threads = ATOMIC_INIT(0);
-static DECLARE_COMPLETION(threads_gone);
-
 static irqreturn_t rtsx_interrupt(int irq, void *dev_id);
 
 /***********************************************************************
@@ -192,7 +186,7 @@ static int queuecommand_lck(struct scsi_cmnd *srb,
        /* enqueue the command and wake up the control thread */
        srb->scsi_done = done;
        chip->srb = srb;
-       up(&(dev->sema));
+       complete(&dev->cmnd_ready);
 
        return 0;
 }
@@ -475,7 +469,7 @@ static int rtsx_control_thread(void *__dev)
        current->flags |= PF_NOFREEZE;
 
        for (;;) {
-               if (down_interruptible(&dev->sema))
+               if (wait_for_completion_interruptible(&dev->cmnd_ready))
                        break;
 
                /* lock the device pointers */
@@ -557,8 +551,6 @@ SkipForAbort:
                mutex_unlock(&dev->dev_mutex);
        } /* for (;;) */
 
-       scsi_host_put(host);
-
        /* notify the exit routine that we're actually exiting now
         *
         * complete()/wait_for_completion() is similar to up()/down(),
@@ -573,7 +565,7 @@ SkipForAbort:
         * This is important in preemption kernels, which transfer the flow
         * of execution immediately upon a complete().
         */
-       complete_and_exit(&threads_gone, 0);
+       complete_and_exit(&dev->control_exit, 0);
 }
 
 
@@ -581,7 +573,6 @@ static int rtsx_polling_thread(void *__dev)
 {
        struct rtsx_dev *dev = (struct rtsx_dev *)__dev;
        struct rtsx_chip *chip = dev->chip;
-       struct Scsi_Host *host = rtsx_to_host(dev);
        struct sd_info *sd_card = &(chip->sd_card);
        struct xd_info *xd_card = &(chip->xd_card);
        struct ms_info *ms_card = &(chip->ms_card);
@@ -621,8 +612,7 @@ static int rtsx_polling_thread(void *__dev)
                mutex_unlock(&dev->dev_mutex);
        }
 
-       scsi_host_put(host);
-       complete_and_exit(&threads_gone, 0);
+       complete_and_exit(&dev->polling_exit, 0);
 }
 
 /*
@@ -699,29 +689,38 @@ static void rtsx_release_resources(struct rtsx_dev *dev)
 {
        printk(KERN_INFO "-- %s\n", __func__);
 
+       /* Tell the control thread to exit.  The SCSI host must
+        * already have been removed so it won't try to queue
+        * any more commands.
+        */
+       printk(KERN_INFO "-- sending exit command to thread\n");
+       complete(&dev->cmnd_ready);
+       if (dev->ctl_thread)
+               wait_for_completion(&dev->control_exit);
+       if (dev->polling_thread)
+               wait_for_completion(&dev->polling_exit);
+
+       wait_timeout(200);
+
        if (dev->rtsx_resv_buf) {
-               dma_free_coherent(&(dev->pci->dev), HOST_CMDS_BUF_LEN,
+               dma_free_coherent(&(dev->pci->dev), RTSX_RESV_BUF_LEN,
                                dev->rtsx_resv_buf, dev->rtsx_resv_buf_addr);
                dev->chip->host_cmds_ptr = NULL;
                dev->chip->host_sg_tbl_ptr = NULL;
        }
 
-       pci_disable_device(dev->pci);
-       pci_release_regions(dev->pci);
-
-       if (dev->irq > 0) {
+       if (dev->irq > 0)
                free_irq(dev->irq, (void *)dev);
-       }
-       if (dev->chip->msi_en) {
+       if (dev->chip->msi_en)
                pci_disable_msi(dev->pci);
-       }
+       if (dev->remap_addr)
+               iounmap(dev->remap_addr);
 
-       /* Tell the control thread to exit.  The SCSI host must
-        * already have been removed so it won't try to queue
-        * any more commands.
-        */
-       printk(KERN_INFO "-- sending exit command to thread\n");
-       up(&dev->sema);
+       pci_disable_device(dev->pci);
+       pci_release_regions(dev->pci);
+
+       rtsx_release_chip(dev->chip);
+       kfree(dev->chip);
 }
 
 /* First stage of disconnect processing: stop all commands and remove
@@ -739,6 +738,7 @@ static void quiesce_and_remove_host(struct rtsx_dev *dev)
        scsi_unlock(host);
        mutex_unlock(&dev->dev_mutex);
        wake_up(&dev->delay_wait);
+       wait_for_completion(&dev->scanning_done);
 
        /* Wait some time to let other threads exist */
        wait_timeout(100);
@@ -793,8 +793,7 @@ static int rtsx_scan_thread(void *__dev)
                /* Should we unbind if no devices were detected? */
        }
 
-       scsi_host_put(rtsx_to_host(dev));
-       complete_and_exit(&threads_gone, 0);
+       complete_and_exit(&dev->scanning_done, 0);
 }
 
 static void rtsx_init_options(struct rtsx_chip *chip)
@@ -941,8 +940,11 @@ static int __devinit rtsx_probe(struct pci_dev *pci, const struct pci_device_id
 
        spin_lock_init(&dev->reg_lock);
        mutex_init(&(dev->dev_mutex));
-       sema_init(&(dev->sema), 0);
+       init_completion(&dev->cmnd_ready);
+       init_completion(&dev->control_exit);
+       init_completion(&dev->polling_exit);
        init_completion(&(dev->notify));
+       init_completion(&dev->scanning_done);
        init_waitqueue_head(&dev->delay_wait);
 
        dev->pci = pci;
@@ -992,28 +994,22 @@ static int __devinit rtsx_probe(struct pci_dev *pci, const struct pci_device_id
        pci_set_master(pci);
        synchronize_irq(dev->irq);
 
-       err = scsi_add_host(host, &pci->dev);
-       if (err) {
-               printk(KERN_ERR "Unable to add the scsi host\n");
-               goto errout;
-       }
-
        rtsx_init_chip(dev->chip);
 
        /* Start up our control thread */
-       th = kthread_create(rtsx_control_thread, dev, CR_DRIVER_NAME);
+       th = kthread_run(rtsx_control_thread, dev, CR_DRIVER_NAME);
        if (IS_ERR(th)) {
                printk(KERN_ERR "Unable to start control thread\n");
                err = PTR_ERR(th);
                goto errout;
        }
+       dev->ctl_thread = th;
 
-       /* Take a reference to the host for the control thread and
-        * count it among all the threads we have launched.  Then
-        * start it up. */
-       scsi_host_get(rtsx_to_host(dev));
-       atomic_inc(&total_threads);
-       wake_up_process(th);
+       err = scsi_add_host(host, &pci->dev);
+       if (err) {
+               printk(KERN_ERR "Unable to add the scsi host\n");
+               goto errout;
+       }
 
        /* Start up the thread for delayed SCSI-device scanning */
        th = kthread_create(rtsx_scan_thread, dev, "rtsx-scan");
@@ -1024,28 +1020,17 @@ static int __devinit rtsx_probe(struct pci_dev *pci, const struct pci_device_id
                goto errout;
        }
 
-       /* Take a reference to the host for the scanning thread and
-        * count it among all the threads we have launched.  Then
-        * start it up. */
-       scsi_host_get(rtsx_to_host(dev));
-       atomic_inc(&total_threads);
        wake_up_process(th);
 
        /* Start up the thread for polling thread */
-       th = kthread_create(rtsx_polling_thread, dev, "rtsx-polling");
+       th = kthread_run(rtsx_polling_thread, dev, "rtsx-polling");
        if (IS_ERR(th)) {
                printk(KERN_ERR "Unable to start the device-polling thread\n");
                quiesce_and_remove_host(dev);
                err = PTR_ERR(th);
                goto errout;
        }
-
-       /* Take a reference to the host for the polling thread and
-        * count it among all the threads we have launched.  Then
-        * start it up. */
-       scsi_host_get(rtsx_to_host(dev));
-       atomic_inc(&total_threads);
-       wake_up_process(th);
+       dev->polling_thread = th;
 
        pci_set_drvdata(pci, dev);
 
@@ -1108,16 +1093,6 @@ static void __exit rtsx_exit(void)
 
        pci_unregister_driver(&driver);
 
-       /* Don't return until all of our control and scanning threads
-        * have exited.  Since each thread signals threads_gone as its
-        * last act, we have to call wait_for_completion the right number
-        * of times.
-        */
-       while (atomic_read(&total_threads) > 0) {
-               wait_for_completion(&threads_gone);
-               atomic_dec(&total_threads);
-       }
-
        printk(KERN_INFO "%s module exit\n", CR_DRIVER_NAME);
 }
 
index 247615b..86e47c2 100644 (file)
@@ -112,9 +112,16 @@ struct rtsx_dev {
        /* locks */
        spinlock_t              reg_lock;
 
+       struct task_struct      *ctl_thread;     /* the control thread   */
+       struct task_struct      *polling_thread; /* the polling thread   */
+
        /* mutual exclusion and synchronization structures */
-       struct semaphore        sema;            /* to sleep thread on      */
+       struct completion       cmnd_ready;      /* to sleep thread on      */
+       struct completion       control_exit;    /* control thread exit     */
+       struct completion       polling_exit;    /* polling thread exit     */
        struct completion       notify;          /* thread begin/end        */
+       struct completion       scanning_done;   /* wait for scan thread    */
+
        wait_queue_head_t       delay_wait;      /* wait during scan, reset */
        struct mutex            dev_mutex;
 
index 7677994..f974f64 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
+#include <linux/slab.h>
 #include <linux/videodev2.h>
 #include "solo6x10.h"
 #include "tw28.h"
index 285f7f3..de50259 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/slab.h>
 #include "solo6x10.h"
 #include "osd-font.h"
 
index bd8eb92..59274bf 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/mempool.h>
 #include <linux/poll.h>
 #include <linux/kthread.h>
+#include <linux/slab.h>
 #include <linux/freezer.h>
 #include <sound/core.h>
 #include <sound/initval.h>
index 5717eab..56210f0 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/slab.h>
 #include <linux/scatterlist.h>
 #include "solo6x10.h"
 
index 17c06bd..abee721 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/list.h>
 #include <linux/wait.h>
 #include <linux/delay.h>
+#include <linux/slab.h>
 #include <asm/io.h>
 #include <linux/atomic.h>
 #include <linux/videodev2.h>
index 39dc586..940769e 100644 (file)
@@ -18,13 +18,14 @@ static ssize_t speakup_file_write(struct file *fp, const char *buffer,
 {
        size_t count = nbytes;
        const char *ptr = buffer;
-       int bytes;
+       size_t bytes;
        unsigned long flags;
        u_char buf[256];
+
        if (synth == NULL)
                return -ENODEV;
        while (count > 0) {
-               bytes = min_t(size_t, count, sizeof(buf));
+               bytes = min(count, sizeof(buf));
                if (copy_from_user(buf, ptr, bytes))
                        return -EFAULT;
                count -= bytes;
index ddfd7c3..bd5fa89 100644 (file)
@@ -84,7 +84,6 @@ static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip)
 
        tm6000_set_audio_bitrate(core, 48000);
 
-
        return 0;
 }
 
@@ -123,6 +122,7 @@ static int dsp_buffer_alloc(struct snd_pcm_substream *substream, int size)
        if (substream->runtime->dma_area) {
                if (substream->runtime->dma_bytes > size)
                        return 0;
+
                dsp_buffer_free(substream);
        }
 
@@ -152,9 +152,9 @@ static struct snd_pcm_hardware snd_tm6000_digital_hw = {
                SNDRV_PCM_INFO_MMAP_VALID,
        .formats = SNDRV_PCM_FMTBIT_S16_LE,
 
-       .rates =                SNDRV_PCM_RATE_CONTINUOUS,
-       .rate_min =             48000,
-       .rate_max =             48000,
+       .rates = SNDRV_PCM_RATE_CONTINUOUS,
+       .rate_min = 48000,
+       .rate_max = 48000,
        .channels_min = 2,
        .channels_max = 2,
        .period_bytes_min = 64,
@@ -254,9 +254,7 @@ static int tm6000_fillbuf(struct tm6000_core *core, char *buf, int size)
                memcpy(runtime->dma_area + buf_pos * stride, buf,
                        length * stride);
 
-#ifndef NO_PCM_LOCK
        snd_pcm_stream_lock(substream);
-#endif
 
        chip->buf_pos += length;
        if (chip->buf_pos >= runtime->buffer_size)
@@ -268,9 +266,7 @@ static int tm6000_fillbuf(struct tm6000_core *core, char *buf, int size)
                period_elapsed = 1;
        }
 
-#ifndef NO_PCM_LOCK
        snd_pcm_stream_unlock(substream);
-#endif
 
        if (period_elapsed)
                snd_pcm_period_elapsed(substream);
index f5ec64f..60daa27 100644 (file)
@@ -1,3 +1,3 @@
-zcache-y       :=      tmem.o
+zcache-y       :=      zcache-main.o tmem.o
 
 obj-$(CONFIG_ZCACHE)   +=      zcache.o
similarity index 99%
rename from drivers/staging/zcache/zcache.c
rename to drivers/staging/zcache/zcache-main.c
index 65a81a0..855a5bb 100644 (file)
@@ -19,6 +19,7 @@
  *   http://marc.info/?l=linux-mm&m=127811271605009
  */
 
+#include <linux/module.h>
 #include <linux/cpu.h>
 #include <linux/highmem.h>
 #include <linux/list.h>
@@ -27,6 +28,7 @@
 #include <linux/spinlock.h>
 #include <linux/types.h>
 #include <linux/atomic.h>
+#include <linux/math64.h>
 #include "tmem.h"
 
 #include "../zram/xvmalloc.h" /* if built in drivers/staging */
@@ -53,6 +55,9 @@
 
 #define MAX_CLIENTS 16
 #define LOCAL_CLIENT ((uint16_t)-1)
+
+MODULE_LICENSE("GPL");
+
 struct zcache_client {
        struct tmem_pool *tmem_pools[MAX_POOLS_PER_CLIENT];
        struct xv_pool *xvpool;
@@ -1158,6 +1163,7 @@ static void *zcache_pampd_create(char *data, size_t size, bool raw, int eph,
        uint16_t client_id = get_client_id_from_client(cli);
        unsigned long zv_mean_zsize;
        unsigned long curr_pers_pampd_count;
+       u64 total_zsize;
 
        if (eph) {
                ret = zcache_compress(page, &cdata, &clen);
@@ -1190,8 +1196,9 @@ static void *zcache_pampd_create(char *data, size_t size, bool raw, int eph,
                }
                /* reject if mean compression is too poor */
                if ((clen > zv_max_mean_zsize) && (curr_pers_pampd_count > 0)) {
-                       zv_mean_zsize = xv_get_total_size_bytes(cli->xvpool) /
-                                               curr_pers_pampd_count;
+                       total_zsize = xv_get_total_size_bytes(cli->xvpool);
+                       zv_mean_zsize = div_u64(total_zsize,
+                                               curr_pers_pampd_count);
                        if (zv_mean_zsize > zv_max_mean_zsize) {
                                zcache_mean_compress_poor++;
                                goto out;
@@ -1929,9 +1936,9 @@ __setup("nofrontswap", no_frontswap);
 
 static int __init zcache_init(void)
 {
-#ifdef CONFIG_SYSFS
        int ret = 0;
 
+#ifdef CONFIG_SYSFS
        ret = sysfs_create_group(mm_kobj, &zcache_attr_group);
        if (ret) {
                pr_err("zcache: can't create sysfs\n");
index 564ff4e..8345fb4 100644 (file)
@@ -1,5 +1,6 @@
 config ISCSI_TARGET
        tristate "Linux-iSCSI.org iSCSI Target Mode Stack"
+       depends on NET
        select CRYPTO
        select CRYPTO_CRC32C
        select CRYPTO_CRC32C_INTEL if X86
index 14c81c4..c24fb10 100644 (file)
@@ -120,7 +120,7 @@ struct iscsi_tiqn *iscsit_add_tiqn(unsigned char *buf)
        struct iscsi_tiqn *tiqn = NULL;
        int ret;
 
-       if (strlen(buf) > ISCSI_IQN_LEN) {
+       if (strlen(buf) >= ISCSI_IQN_LEN) {
                pr_err("Target IQN exceeds %d bytes\n",
                                ISCSI_IQN_LEN);
                return ERR_PTR(-EINVAL);
@@ -1857,7 +1857,7 @@ static int iscsit_handle_text_cmd(
        char *text_ptr, *text_in;
        int cmdsn_ret, niov = 0, rx_got, rx_size;
        u32 checksum = 0, data_crc = 0, payload_length;
-       u32 padding = 0, text_length = 0;
+       u32 padding = 0, pad_bytes = 0, text_length = 0;
        struct iscsi_cmd *cmd;
        struct kvec iov[3];
        struct iscsi_text *hdr;
@@ -1896,7 +1896,7 @@ static int iscsit_handle_text_cmd(
 
                padding = ((-payload_length) & 3);
                if (padding != 0) {
-                       iov[niov].iov_base = cmd->pad_bytes;
+                       iov[niov].iov_base = &pad_bytes;
                        iov[niov++].iov_len  = padding;
                        rx_size += padding;
                        pr_debug("Receiving %u additional bytes"
@@ -1917,7 +1917,7 @@ static int iscsit_handle_text_cmd(
                if (conn->conn_ops->DataDigest) {
                        iscsit_do_crypto_hash_buf(&conn->conn_rx_hash,
                                        text_in, text_length,
-                                       padding, cmd->pad_bytes,
+                                       padding, (u8 *)&pad_bytes,
                                        (u8 *)&data_crc);
 
                        if (checksum != data_crc) {
@@ -3468,7 +3468,12 @@ static inline void iscsit_thread_check_cpumask(
 }
 
 #else
-#define iscsit_thread_get_cpumask(X) ({})
+
+void iscsit_thread_get_cpumask(struct iscsi_conn *conn)
+{
+       return;
+}
+
 #define iscsit_thread_check_cpumask(X, Y, Z) ({})
 #endif /* CONFIG_SMP */
 
index 32bb92c..f095e65 100644 (file)
@@ -181,7 +181,7 @@ struct se_tpg_np *lio_target_call_addnptotpg(
                return ERR_PTR(-EOVERFLOW);
        }
        memset(buf, 0, MAX_PORTAL_LEN + 1);
-       snprintf(buf, MAX_PORTAL_LEN, "%s", name);
+       snprintf(buf, MAX_PORTAL_LEN + 1, "%s", name);
 
        memset(&sockaddr, 0, sizeof(struct __kernel_sockaddr_storage));
 
index 713a4d2..4d087ac 100644 (file)
@@ -978,7 +978,7 @@ struct iscsi_login *iscsi_target_init_negotiation(
                pr_err("Unable to allocate memory for struct iscsi_login.\n");
                iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
                                ISCSI_LOGIN_STATUS_NO_RESOURCES);
-               goto out;
+               return NULL;
        }
 
        login->req = kzalloc(ISCSI_HDR_LEN, GFP_KERNEL);
index c75a01a..8976032 100644 (file)
@@ -1747,6 +1747,8 @@ int transport_generic_handle_cdb(
 }
 EXPORT_SYMBOL(transport_generic_handle_cdb);
 
+static void transport_generic_request_failure(struct se_cmd *,
+                       struct se_device *, int, int);
 /*
  * Used by fabric module frontends to queue tasks directly.
  * Many only be used from process context only
@@ -1754,6 +1756,8 @@ EXPORT_SYMBOL(transport_generic_handle_cdb);
 int transport_handle_cdb_direct(
        struct se_cmd *cmd)
 {
+       int ret;
+
        if (!cmd->se_lun) {
                dump_stack();
                pr_err("cmd->se_lun is NULL\n");
@@ -1765,8 +1769,31 @@ int transport_handle_cdb_direct(
                                " from interrupt context\n");
                return -EINVAL;
        }
-
-       return transport_generic_new_cmd(cmd);
+       /*
+        * Set TRANSPORT_NEW_CMD state and cmd->t_transport_active=1 following
+        * transport_generic_handle_cdb*() -> transport_add_cmd_to_queue()
+        * in existing usage to ensure that outstanding descriptors are handled
+        * correctly during shutdown via transport_generic_wait_for_tasks()
+        *
+        * Also, we don't take cmd->t_state_lock here as we only expect
+        * this to be called for initial descriptor submission.
+        */
+       cmd->t_state = TRANSPORT_NEW_CMD;
+       atomic_set(&cmd->t_transport_active, 1);
+       /*
+        * transport_generic_new_cmd() is already handling QUEUE_FULL,
+        * so follow TRANSPORT_NEW_CMD processing thread context usage
+        * and call transport_generic_request_failure() if necessary..
+        */
+       ret = transport_generic_new_cmd(cmd);
+       if (ret == -EAGAIN)
+               return 0;
+       else if (ret < 0) {
+               cmd->transport_error_status = ret;
+               transport_generic_request_failure(cmd, NULL, 0,
+                               (cmd->data_direction != DMA_TO_DEVICE));
+       }
+       return 0;
 }
 EXPORT_SYMBOL(transport_handle_cdb_direct);
 
@@ -3324,7 +3351,7 @@ static int transport_generic_cmd_sequencer(
                        goto out_invalid_cdb_field;
                }
 
-               cmd->t_task_lba = get_unaligned_be16(&cdb[2]);
+               cmd->t_task_lba = get_unaligned_be64(&cdb[2]);
                passthrough = (dev->transport->transport_type ==
                                TRANSPORT_PLUGIN_PHBA_PDEV);
                /*
index f7fff7e..bd4fe21 100644 (file)
@@ -187,4 +187,9 @@ void ft_dump_cmd(struct ft_cmd *, const char *caller);
 
 ssize_t ft_format_wwn(char *, size_t, u64);
 
+/*
+ * Underlying HW specific helper function
+ */
+void ft_invl_hw_context(struct ft_cmd *);
+
 #endif /* __TCM_FC_H__ */
index 09df38b..5654dc2 100644 (file)
@@ -320,6 +320,7 @@ static void ft_recv_seq(struct fc_seq *sp, struct fc_frame *fp, void *arg)
        default:
                pr_debug("%s: unhandled frame r_ctl %x\n",
                       __func__, fh->fh_r_ctl);
+               ft_invl_hw_context(cmd);
                fc_frame_free(fp);
                transport_generic_free_cmd(&cmd->se_cmd, 0, 0);
                break;
index 8e2a46d..c37f4cd 100644 (file)
@@ -213,62 +213,49 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp)
        if (!(ntoh24(fh->fh_f_ctl) & FC_FC_REL_OFF))
                goto drop;
 
+       f_ctl = ntoh24(fh->fh_f_ctl);
+       ep = fc_seq_exch(seq);
+       lport = ep->lp;
+       if (cmd->was_ddp_setup) {
+               BUG_ON(!ep);
+               BUG_ON(!lport);
+       }
+
        /*
-        * Doesn't expect even single byte of payload. Payload
+        * Doesn't expect payload if DDP is setup. Payload
         * is expected to be copied directly to user buffers
-        * due to DDP (Large Rx offload) feature, hence
-        * BUG_ON if BUF is non-NULL
+        * due to DDP (Large Rx offload),
         */
        buf = fc_frame_payload_get(fp, 1);
-       if (cmd->was_ddp_setup && buf) {
-               pr_debug("%s: When DDP was setup, not expected to"
-                                "receive frame with payload, Payload shall be"
-                                "copied directly to buffer instead of coming "
-                                "via. legacy receive queues\n", __func__);
-               BUG_ON(buf);
-       }
+       if (buf)
+               pr_err("%s: xid 0x%x, f_ctl 0x%x, cmd->sg %p, "
+                               "cmd->sg_cnt 0x%x. DDP was setup"
+                               " hence not expected to receive frame with "
+                               "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);
+       /*
+        * Invalidate HW DDP context if it was setup for respective
+        * command. Invalidation of HW DDP context is requited in both
+        * situation (success and error). 
+        */
+       ft_invl_hw_context(cmd);
 
        /*
-        * If ft_cmd indicated 'ddp_setup', in that case only the last frame
-        * should come with 'TSI bit being set'. If 'TSI bit is not set and if
-        * data frame appears here, means error condition. In both the cases
-        * release the DDP context (ddp_put) and in error case, as well
-        * initiate error recovery mechanism.
+        * If "Sequence Initiative (TSI)" bit set in f_ctl, means last
+        * write data frame is received successfully where payload is
+        * posted directly to user buffer and only the last frame's
+        * header is posted in receive queue.
+        *
+        * If "Sequence Initiative (TSI)" bit is not set, means error
+        * condition w.r.t. DDP, hence drop the packet and let explict
+        * ABORTS from other end of exchange timer trigger the recovery.
         */
-       ep = fc_seq_exch(seq);
-       if (cmd->was_ddp_setup) {
-               BUG_ON(!ep);
-               lport = ep->lp;
-               BUG_ON(!lport);
-       }
-       if (cmd->was_ddp_setup && ep->xid != FC_XID_UNKNOWN) {
-               f_ctl = ntoh24(fh->fh_f_ctl);
-               /*
-                * If TSI bit set in f_ctl, means last write data frame is
-                * received successfully where payload is posted directly
-                * to user buffer and only the last frame's header is posted
-                * in legacy receive queue
-                */
-               if (f_ctl & FC_FC_SEQ_INIT) { /* TSI bit set in FC frame */
-                       cmd->write_data_len = lport->tt.ddp_done(lport,
-                                                               ep->xid);
-                       goto last_frame;
-               } else {
-                       /*
-                        * Updating the write_data_len may be meaningless at
-                        * this point, but just in case if required in future
-                        * for debugging or any other purpose
-                        */
-                       pr_err("%s: Received frame with TSI bit not"
-                                       " being SET, dropping the frame, "
-                                       "cmd->sg <%p>, cmd->sg_cnt <0x%x>\n",
-                                       __func__, cmd->sg, cmd->sg_cnt);
-                       cmd->write_data_len = lport->tt.ddp_done(lport,
-                                                             ep->xid);
-                       lport->tt.seq_exch_abort(cmd->seq, 0);
-                       goto drop;
-               }
-       }
+       if (f_ctl & FC_FC_SEQ_INIT)
+               goto last_frame;
+       else
+               goto drop;
 
        rel_off = ntohl(fh->fh_parm_offset);
        frame_len = fr_len(fp);
@@ -331,3 +318,39 @@ last_frame:
 drop:
        fc_frame_free(fp);
 }
+
+/*
+ * Handle and cleanup any HW specific resources if
+ * received ABORTS, errors, timeouts.
+ */
+void ft_invl_hw_context(struct ft_cmd *cmd)
+{
+       struct fc_seq *seq = cmd->seq;
+       struct fc_exch *ep = NULL;
+       struct fc_lport *lport = NULL;
+
+       BUG_ON(!cmd);
+
+       /* Cleanup the DDP context in HW if DDP was setup */
+       if (cmd->was_ddp_setup && seq) {
+               ep = fc_seq_exch(seq);
+               if (ep) {
+                       lport = ep->lp;
+                       if (lport && (ep->xid <= lport->lro_xid))
+                               /*
+                                * "ddp_done" trigger invalidation of HW
+                                * specific DDP context
+                                */
+                               cmd->write_data_len = lport->tt.ddp_done(lport,
+                                                                     ep->xid);
+
+                               /*
+                                * Resetting same variable to indicate HW's
+                                * DDP context has been invalidated to avoid
+                                * re_invalidation of same context (context is
+                                * identified using ep->xid)
+                                */
+                               cmd->was_ddp_setup = 0;
+               }
+       }
+}
index bf7c687..f7f71b2 100644 (file)
@@ -14,11 +14,7 @@ menuconfig THERMAL
          If you want this support, you should say Y or M here.
 
 config THERMAL_HWMON
-       bool "Hardware monitoring support"
+       bool
        depends on THERMAL
        depends on HWMON=y || HWMON=THERMAL
-       help
-         The generic thermal sysfs driver's hardware monitoring support
-         requires a 2.10.7/3.0.2 or later lm-sensors userspace.
-
-         Say Y if your user-space is new enough.
+       default y
index 0b1c82a..708f8e9 100644 (file)
@@ -420,6 +420,29 @@ thermal_cooling_device_trip_point_show(struct device *dev,
 
 /* hwmon sys I/F */
 #include <linux/hwmon.h>
+
+/* thermal zone devices with the same type share one hwmon device */
+struct thermal_hwmon_device {
+       char type[THERMAL_NAME_LENGTH];
+       struct device *device;
+       int count;
+       struct list_head tz_list;
+       struct list_head node;
+};
+
+struct thermal_hwmon_attr {
+       struct device_attribute attr;
+       char name[16];
+};
+
+/* one temperature input for each thermal zone */
+struct thermal_hwmon_temp {
+       struct list_head hwmon_node;
+       struct thermal_zone_device *tz;
+       struct thermal_hwmon_attr temp_input;   /* hwmon sys attr */
+       struct thermal_hwmon_attr temp_crit;    /* hwmon sys attr */
+};
+
 static LIST_HEAD(thermal_hwmon_list);
 
 static ssize_t
@@ -437,9 +460,10 @@ temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
        int ret;
        struct thermal_hwmon_attr *hwmon_attr
                        = container_of(attr, struct thermal_hwmon_attr, attr);
-       struct thermal_zone_device *tz
-                       = container_of(hwmon_attr, struct thermal_zone_device,
+       struct thermal_hwmon_temp *temp
+                       = container_of(hwmon_attr, struct thermal_hwmon_temp,
                                       temp_input);
+       struct thermal_zone_device *tz = temp->tz;
 
        ret = tz->ops->get_temp(tz, &temperature);
 
@@ -455,9 +479,10 @@ temp_crit_show(struct device *dev, struct device_attribute *attr,
 {
        struct thermal_hwmon_attr *hwmon_attr
                        = container_of(attr, struct thermal_hwmon_attr, attr);
-       struct thermal_zone_device *tz
-                       = container_of(hwmon_attr, struct thermal_zone_device,
+       struct thermal_hwmon_temp *temp
+                       = container_of(hwmon_attr, struct thermal_hwmon_temp,
                                       temp_crit);
+       struct thermal_zone_device *tz = temp->tz;
        long temperature;
        int ret;
 
@@ -469,22 +494,54 @@ temp_crit_show(struct device *dev, struct device_attribute *attr,
 }
 
 
-static int
-thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
+static struct thermal_hwmon_device *
+thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz)
 {
        struct thermal_hwmon_device *hwmon;
-       int new_hwmon_device = 1;
-       int result;
 
        mutex_lock(&thermal_list_lock);
        list_for_each_entry(hwmon, &thermal_hwmon_list, node)
                if (!strcmp(hwmon->type, tz->type)) {
-                       new_hwmon_device = 0;
                        mutex_unlock(&thermal_list_lock);
-                       goto register_sys_interface;
+                       return hwmon;
+               }
+       mutex_unlock(&thermal_list_lock);
+
+       return NULL;
+}
+
+/* Find the temperature input matching a given thermal zone */
+static struct thermal_hwmon_temp *
+thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon,
+                         const struct thermal_zone_device *tz)
+{
+       struct thermal_hwmon_temp *temp;
+
+       mutex_lock(&thermal_list_lock);
+       list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
+               if (temp->tz == tz) {
+                       mutex_unlock(&thermal_list_lock);
+                       return temp;
                }
        mutex_unlock(&thermal_list_lock);
 
+       return NULL;
+}
+
+static int
+thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
+{
+       struct thermal_hwmon_device *hwmon;
+       struct thermal_hwmon_temp *temp;
+       int new_hwmon_device = 1;
+       int result;
+
+       hwmon = thermal_hwmon_lookup_by_type(tz);
+       if (hwmon) {
+               new_hwmon_device = 0;
+               goto register_sys_interface;
+       }
+
        hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL);
        if (!hwmon)
                return -ENOMEM;
@@ -502,30 +559,36 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
                goto free_mem;
 
  register_sys_interface:
-       tz->hwmon = hwmon;
+       temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL);
+       if (!temp) {
+               result = -ENOMEM;
+               goto unregister_name;
+       }
+
+       temp->tz = tz;
        hwmon->count++;
 
-       snprintf(tz->temp_input.name, THERMAL_NAME_LENGTH,
+       snprintf(temp->temp_input.name, THERMAL_NAME_LENGTH,
                 "temp%d_input", hwmon->count);
-       tz->temp_input.attr.attr.name = tz->temp_input.name;
-       tz->temp_input.attr.attr.mode = 0444;
-       tz->temp_input.attr.show = temp_input_show;
-       sysfs_attr_init(&tz->temp_input.attr.attr);
-       result = device_create_file(hwmon->device, &tz->temp_input.attr);
+       temp->temp_input.attr.attr.name = temp->temp_input.name;
+       temp->temp_input.attr.attr.mode = 0444;
+       temp->temp_input.attr.show = temp_input_show;
+       sysfs_attr_init(&temp->temp_input.attr.attr);
+       result = device_create_file(hwmon->device, &temp->temp_input.attr);
        if (result)
-               goto unregister_name;
+               goto free_temp_mem;
 
        if (tz->ops->get_crit_temp) {
                unsigned long temperature;
                if (!tz->ops->get_crit_temp(tz, &temperature)) {
-                       snprintf(tz->temp_crit.name, THERMAL_NAME_LENGTH,
+                       snprintf(temp->temp_crit.name, THERMAL_NAME_LENGTH,
                                "temp%d_crit", hwmon->count);
-                       tz->temp_crit.attr.attr.name = tz->temp_crit.name;
-                       tz->temp_crit.attr.attr.mode = 0444;
-                       tz->temp_crit.attr.show = temp_crit_show;
-                       sysfs_attr_init(&tz->temp_crit.attr.attr);
+                       temp->temp_crit.attr.attr.name = temp->temp_crit.name;
+                       temp->temp_crit.attr.attr.mode = 0444;
+                       temp->temp_crit.attr.show = temp_crit_show;
+                       sysfs_attr_init(&temp->temp_crit.attr.attr);
                        result = device_create_file(hwmon->device,
-                                                   &tz->temp_crit.attr);
+                                                   &temp->temp_crit.attr);
                        if (result)
                                goto unregister_input;
                }
@@ -534,13 +597,15 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
        mutex_lock(&thermal_list_lock);
        if (new_hwmon_device)
                list_add_tail(&hwmon->node, &thermal_hwmon_list);
-       list_add_tail(&tz->hwmon_node, &hwmon->tz_list);
+       list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
        mutex_unlock(&thermal_list_lock);
 
        return 0;
 
  unregister_input:
-       device_remove_file(hwmon->device, &tz->temp_input.attr);
+       device_remove_file(hwmon->device, &temp->temp_input.attr);
+ free_temp_mem:
+       kfree(temp);
  unregister_name:
        if (new_hwmon_device) {
                device_remove_file(hwmon->device, &dev_attr_name);
@@ -556,15 +621,30 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
 static void
 thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
 {
-       struct thermal_hwmon_device *hwmon = tz->hwmon;
+       struct thermal_hwmon_device *hwmon;
+       struct thermal_hwmon_temp *temp;
+
+       hwmon = thermal_hwmon_lookup_by_type(tz);
+       if (unlikely(!hwmon)) {
+               /* Should never happen... */
+               dev_dbg(&tz->device, "hwmon device lookup failed!\n");
+               return;
+       }
+
+       temp = thermal_hwmon_lookup_temp(hwmon, tz);
+       if (unlikely(!temp)) {
+               /* Should never happen... */
+               dev_dbg(&tz->device, "temperature input lookup failed!\n");
+               return;
+       }
 
-       tz->hwmon = NULL;
-       device_remove_file(hwmon->device, &tz->temp_input.attr);
+       device_remove_file(hwmon->device, &temp->temp_input.attr);
        if (tz->ops->get_crit_temp)
-               device_remove_file(hwmon->device, &tz->temp_crit.attr);
+               device_remove_file(hwmon->device, &temp->temp_crit.attr);
 
        mutex_lock(&thermal_list_lock);
-       list_del(&tz->hwmon_node);
+       list_del(&temp->hwmon_node);
+       kfree(temp);
        if (!list_empty(&hwmon->tz_list)) {
                mutex_unlock(&thermal_list_lock);
                return;
index cb40b82..4dcb37b 100644 (file)
@@ -959,7 +959,7 @@ config SERIAL_IP22_ZILOG_CONSOLE
 
 config SERIAL_SH_SCI
        tristate "SuperH SCI(F) serial port support"
-       depends on HAVE_CLK && (SUPERH || H8300 || ARCH_SHMOBILE)
+       depends on HAVE_CLK && (SUPERH || ARCH_SHMOBILE)
        select SERIAL_CORE
 
 config SERIAL_SH_SCI_NR_UARTS
index 22fe801..7e91b3d 100644 (file)
 #include <linux/delay.h>
 #include <linux/rational.h>
 #include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <mach/hardware.h>
 #include <mach/imx-uart.h>
 
 /* Register definitions */
@@ -66,8 +67,9 @@
 #define UBIR  0xa4 /* BRM Incremental Register */
 #define UBMR  0xa8 /* BRM Modulator Register */
 #define UBRC  0xac /* Baud Rate Count Register */
-#define MX2_ONEMS 0xb0 /* One Millisecond register */
-#define UTS (cpu_is_mx1() ? 0xd0 : 0xb4) /* UART Test Register */
+#define IMX21_ONEMS 0xb0 /* One Millisecond register */
+#define IMX1_UTS 0xd0 /* UART Test Register on i.mx1 */
+#define IMX21_UTS 0xb4 /* UART Test Register on all other i.mx*/
 
 /* UART Control Register Bit Fields.*/
 #define  URXD_CHARRDY    (1<<15)
@@ -87,7 +89,7 @@
 #define  UCR1_RTSDEN     (1<<5)         /* RTS delta interrupt enable */
 #define  UCR1_SNDBRK     (1<<4)         /* Send break */
 #define  UCR1_TDMAEN     (1<<3)         /* Transmitter ready DMA enable */
-#define  MX1_UCR1_UARTCLKEN  (1<<2)     /* UART clock enabled, mx1 only */
+#define  IMX1_UCR1_UARTCLKEN  (1<<2)  /* UART clock enabled, i.mx1 only */
 #define  UCR1_DOZE       (1<<1)         /* Doze */
 #define  UCR1_UARTEN     (1<<0)         /* UART enabled */
 #define  UCR2_ESCI              (1<<15) /* Escape seq interrupt enable */
 #define  UCR3_RXDSEN    (1<<6)  /* Receive status interrupt enable */
 #define  UCR3_AIRINTEN   (1<<5)  /* Async IR wake interrupt enable */
 #define  UCR3_AWAKEN    (1<<4)  /* Async wake interrupt enable */
-#define  MX1_UCR3_REF25         (1<<3)  /* Ref freq 25 MHz, only on mx1 */
-#define  MX1_UCR3_REF30         (1<<2)  /* Ref Freq 30 MHz, only on mx1 */
-#define  MX2_UCR3_RXDMUXSEL     (1<<2)  /* RXD Muxed Input Select, on mx2/mx3 */
+#define  IMX21_UCR3_RXDMUXSEL   (1<<2)  /* RXD Muxed Input Select */
 #define  UCR3_INVT      (1<<1)  /* Inverted Infrared transmission */
 #define  UCR3_BPEN      (1<<0)  /* Preset registers enable */
 #define  UCR4_CTSTL_SHF  10      /* CTS trigger level shift */
 
 #define UART_NR 8
 
+/* i.mx21 type uart runs on all i.mx except i.mx1 */
+enum imx_uart_type {
+       IMX1_UART,
+       IMX21_UART,
+};
+
+/* device type dependent stuff */
+struct imx_uart_data {
+       unsigned uts_reg;
+       enum imx_uart_type devtype;
+};
+
 struct imx_port {
        struct uart_port        port;
        struct timer_list       timer;
@@ -192,6 +204,7 @@ struct imx_port {
        unsigned int            irda_inv_tx:1;
        unsigned short          trcv_delay; /* transceiver delay */
        struct clk              *clk;
+       struct imx_uart_data    *devdata;
 };
 
 #ifdef CONFIG_IRDA
@@ -200,6 +213,52 @@ struct imx_port {
 #define USE_IRDA(sport)        (0)
 #endif
 
+static struct imx_uart_data imx_uart_devdata[] = {
+       [IMX1_UART] = {
+               .uts_reg = IMX1_UTS,
+               .devtype = IMX1_UART,
+       },
+       [IMX21_UART] = {
+               .uts_reg = IMX21_UTS,
+               .devtype = IMX21_UART,
+       },
+};
+
+static struct platform_device_id imx_uart_devtype[] = {
+       {
+               .name = "imx1-uart",
+               .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX1_UART],
+       }, {
+               .name = "imx21-uart",
+               .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX21_UART],
+       }, {
+               /* sentinel */
+       }
+};
+MODULE_DEVICE_TABLE(platform, imx_uart_devtype);
+
+static struct of_device_id imx_uart_dt_ids[] = {
+       { .compatible = "fsl,imx1-uart", .data = &imx_uart_devdata[IMX1_UART], },
+       { .compatible = "fsl,imx21-uart", .data = &imx_uart_devdata[IMX21_UART], },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_uart_dt_ids);
+
+static inline unsigned uts_reg(struct imx_port *sport)
+{
+       return sport->devdata->uts_reg;
+}
+
+static inline int is_imx1_uart(struct imx_port *sport)
+{
+       return sport->devdata->devtype == IMX1_UART;
+}
+
+static inline int is_imx21_uart(struct imx_port *sport)
+{
+       return sport->devdata->devtype == IMX21_UART;
+}
+
 /*
  * Handle any change of modem status signal since we were last called.
  */
@@ -326,7 +385,8 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
        struct circ_buf *xmit = &sport->port.state->xmit;
 
        while (!uart_circ_empty(xmit) &&
-                       !(readl(sport->port.membase + UTS) & UTS_TXFULL)) {
+                       !(readl(sport->port.membase + uts_reg(sport))
+                               & UTS_TXFULL)) {
                /* send xmit->buf[xmit->tail]
                 * out the port here */
                writel(xmit->buf[xmit->tail], sport->port.membase + URTX0);
@@ -373,7 +433,7 @@ static void imx_start_tx(struct uart_port *port)
                writel(temp, sport->port.membase + UCR4);
        }
 
-       if (readl(sport->port.membase + UTS) & UTS_TXEMPTY)
+       if (readl(sport->port.membase + uts_reg(sport)) & UTS_TXEMPTY)
                imx_transmit_buffer(sport);
 }
 
@@ -689,9 +749,9 @@ static int imx_startup(struct uart_port *port)
                }
        }
 
-       if (!cpu_is_mx1()) {
+       if (is_imx21_uart(sport)) {
                temp = readl(sport->port.membase + UCR3);
-               temp |= MX2_UCR3_RXDMUXSEL;
+               temp |= IMX21_UCR3_RXDMUXSEL;
                writel(temp, sport->port.membase + UCR3);
        }
 
@@ -923,9 +983,9 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
        writel(num, sport->port.membase + UBIR);
        writel(denom, sport->port.membase + UBMR);
 
-       if (!cpu_is_mx1())
+       if (is_imx21_uart(sport))
                writel(sport->port.uartclk / div / 1000,
-                               sport->port.membase + MX2_ONEMS);
+                               sport->port.membase + IMX21_ONEMS);
 
        writel(old_ucr1, sport->port.membase + UCR1);
 
@@ -1041,7 +1101,7 @@ static void imx_console_putchar(struct uart_port *port, int ch)
 {
        struct imx_port *sport = (struct imx_port *)port;
 
-       while (readl(sport->port.membase + UTS) & UTS_TXFULL)
+       while (readl(sport->port.membase + uts_reg(sport)) & UTS_TXFULL)
                barrier();
 
        writel(ch, sport->port.membase + URTX0);
@@ -1062,8 +1122,8 @@ imx_console_write(struct console *co, const char *s, unsigned int count)
        ucr1 = old_ucr1 = readl(sport->port.membase + UCR1);
        old_ucr2 = readl(sport->port.membase + UCR2);
 
-       if (cpu_is_mx1())
-               ucr1 |= MX1_UCR1_UARTCLKEN;
+       if (is_imx1_uart(sport))
+               ucr1 |= IMX1_UCR1_UARTCLKEN;
        ucr1 |= UCR1_UARTEN;
        ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN);
 
@@ -1222,6 +1282,58 @@ static int serial_imx_resume(struct platform_device *dev)
        return 0;
 }
 
+#ifdef CONFIG_OF
+static int serial_imx_probe_dt(struct imx_port *sport,
+               struct platform_device *pdev)
+{
+       static int portnum = 0;
+       struct device_node *np = pdev->dev.of_node;
+       const struct of_device_id *of_id =
+                       of_match_device(imx_uart_dt_ids, &pdev->dev);
+
+       if (!np)
+               return -ENODEV;
+
+       sport->port.line = portnum++;
+       if (sport->port.line >= UART_NR)
+               return -EINVAL;
+
+       if (of_get_property(np, "fsl,uart-has-rtscts", NULL))
+               sport->have_rtscts = 1;
+
+       if (of_get_property(np, "fsl,irda-mode", NULL))
+               sport->use_irda = 1;
+
+       sport->devdata = of_id->data;
+
+       return 0;
+}
+#else
+static inline int serial_imx_probe_dt(struct imx_port *sport,
+               struct platform_device *pdev)
+{
+       return -ENODEV;
+}
+#endif
+
+static void serial_imx_probe_pdata(struct imx_port *sport,
+               struct platform_device *pdev)
+{
+       struct imxuart_platform_data *pdata = pdev->dev.platform_data;
+
+       sport->port.line = pdev->id;
+       sport->devdata = (struct imx_uart_data  *) pdev->id_entry->driver_data;
+
+       if (!pdata)
+               return;
+
+       if (pdata->flags & IMXUART_HAVE_RTSCTS)
+               sport->have_rtscts = 1;
+
+       if (pdata->flags & IMXUART_IRDA)
+               sport->use_irda = 1;
+}
+
 static int serial_imx_probe(struct platform_device *pdev)
 {
        struct imx_port *sport;
@@ -1234,6 +1346,10 @@ static int serial_imx_probe(struct platform_device *pdev)
        if (!sport)
                return -ENOMEM;
 
+       ret = serial_imx_probe_dt(sport, pdev);
+       if (ret == -ENODEV)
+               serial_imx_probe_pdata(sport, pdev);
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
                ret = -ENODEV;
@@ -1258,7 +1374,6 @@ static int serial_imx_probe(struct platform_device *pdev)
        sport->port.fifosize = 32;
        sport->port.ops = &imx_pops;
        sport->port.flags = UPF_BOOT_AUTOCONF;
-       sport->port.line = pdev->id;
        init_timer(&sport->timer);
        sport->timer.function = imx_timeout;
        sport->timer.data     = (unsigned long)sport;
@@ -1272,17 +1387,9 @@ static int serial_imx_probe(struct platform_device *pdev)
 
        sport->port.uartclk = clk_get_rate(sport->clk);
 
-       imx_ports[pdev->id] = sport;
+       imx_ports[sport->port.line] = sport;
 
        pdata = pdev->dev.platform_data;
-       if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS))
-               sport->have_rtscts = 1;
-
-#ifdef CONFIG_IRDA
-       if (pdata && (pdata->flags & IMXUART_IRDA))
-               sport->use_irda = 1;
-#endif
-
        if (pdata && pdata->init) {
                ret = pdata->init(pdev);
                if (ret)
@@ -1340,9 +1447,11 @@ static struct platform_driver serial_imx_driver = {
 
        .suspend        = serial_imx_suspend,
        .resume         = serial_imx_resume,
+       .id_table       = imx_uart_devtype,
        .driver         = {
                .name   = "imx-uart",
                .owner  = THIS_MODULE,
+               .of_match_table = imx_uart_dt_ids,
        },
 };
 
index ebd8629..2ec57b2 100644 (file)
 #include <asm/sh_bios.h>
 #endif
 
-#ifdef CONFIG_H8300
-#include <asm/gpio.h>
-#endif
-
 #include "sh-sci.h"
 
 struct sci_port {
@@ -66,12 +62,6 @@ struct sci_port {
        /* Platform configuration */
        struct plat_sci_port    *cfg;
 
-       /* Port enable callback */
-       void                    (*enable)(struct uart_port *port);
-
-       /* Port disable callback */
-       void                    (*disable)(struct uart_port *port);
-
        /* Break timer */
        struct timer_list       break_timer;
        int                     break_flag;
@@ -81,6 +71,8 @@ struct sci_port {
        /* Function clock */
        struct clk              *fclk;
 
+       char                    *irqstr[SCIx_NR_IRQS];
+
        struct dma_chan                 *chan_tx;
        struct dma_chan                 *chan_rx;
 
@@ -121,6 +113,278 @@ to_sci_port(struct uart_port *uart)
        return container_of(uart, struct sci_port, port);
 }
 
+struct plat_sci_reg {
+       u8 offset, size;
+};
+
+/* Helper for invalidating specific entries of an inherited map. */
+#define sci_reg_invalid        { .offset = 0, .size = 0 }
+
+static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
+       [SCIx_PROBE_REGTYPE] = {
+               [0 ... SCIx_NR_REGS - 1] = sci_reg_invalid,
+       },
+
+       /*
+        * Common SCI definitions, dependent on the port's regshift
+        * value.
+        */
+       [SCIx_SCI_REGTYPE] = {
+               [SCSMR]         = { 0x00,  8 },
+               [SCBRR]         = { 0x01,  8 },
+               [SCSCR]         = { 0x02,  8 },
+               [SCxTDR]        = { 0x03,  8 },
+               [SCxSR]         = { 0x04,  8 },
+               [SCxRDR]        = { 0x05,  8 },
+               [SCFCR]         = sci_reg_invalid,
+               [SCFDR]         = sci_reg_invalid,
+               [SCTFDR]        = sci_reg_invalid,
+               [SCRFDR]        = sci_reg_invalid,
+               [SCSPTR]        = sci_reg_invalid,
+               [SCLSR]         = sci_reg_invalid,
+       },
+
+       /*
+        * Common definitions for legacy IrDA ports, dependent on
+        * regshift value.
+        */
+       [SCIx_IRDA_REGTYPE] = {
+               [SCSMR]         = { 0x00,  8 },
+               [SCBRR]         = { 0x01,  8 },
+               [SCSCR]         = { 0x02,  8 },
+               [SCxTDR]        = { 0x03,  8 },
+               [SCxSR]         = { 0x04,  8 },
+               [SCxRDR]        = { 0x05,  8 },
+               [SCFCR]         = { 0x06,  8 },
+               [SCFDR]         = { 0x07, 16 },
+               [SCTFDR]        = sci_reg_invalid,
+               [SCRFDR]        = sci_reg_invalid,
+               [SCSPTR]        = sci_reg_invalid,
+               [SCLSR]         = sci_reg_invalid,
+       },
+
+       /*
+        * Common SCIFA definitions.
+        */
+       [SCIx_SCIFA_REGTYPE] = {
+               [SCSMR]         = { 0x00, 16 },
+               [SCBRR]         = { 0x04,  8 },
+               [SCSCR]         = { 0x08, 16 },
+               [SCxTDR]        = { 0x20,  8 },
+               [SCxSR]         = { 0x14, 16 },
+               [SCxRDR]        = { 0x24,  8 },
+               [SCFCR]         = { 0x18, 16 },
+               [SCFDR]         = { 0x1c, 16 },
+               [SCTFDR]        = sci_reg_invalid,
+               [SCRFDR]        = sci_reg_invalid,
+               [SCSPTR]        = sci_reg_invalid,
+               [SCLSR]         = sci_reg_invalid,
+       },
+
+       /*
+        * Common SCIFB definitions.
+        */
+       [SCIx_SCIFB_REGTYPE] = {
+               [SCSMR]         = { 0x00, 16 },
+               [SCBRR]         = { 0x04,  8 },
+               [SCSCR]         = { 0x08, 16 },
+               [SCxTDR]        = { 0x40,  8 },
+               [SCxSR]         = { 0x14, 16 },
+               [SCxRDR]        = { 0x60,  8 },
+               [SCFCR]         = { 0x18, 16 },
+               [SCFDR]         = { 0x1c, 16 },
+               [SCTFDR]        = sci_reg_invalid,
+               [SCRFDR]        = sci_reg_invalid,
+               [SCSPTR]        = sci_reg_invalid,
+               [SCLSR]         = sci_reg_invalid,
+       },
+
+       /*
+        * Common SH-3 SCIF definitions.
+        */
+       [SCIx_SH3_SCIF_REGTYPE] = {
+               [SCSMR]         = { 0x00,  8 },
+               [SCBRR]         = { 0x02,  8 },
+               [SCSCR]         = { 0x04,  8 },
+               [SCxTDR]        = { 0x06,  8 },
+               [SCxSR]         = { 0x08, 16 },
+               [SCxRDR]        = { 0x0a,  8 },
+               [SCFCR]         = { 0x0c,  8 },
+               [SCFDR]         = { 0x0e, 16 },
+               [SCTFDR]        = sci_reg_invalid,
+               [SCRFDR]        = sci_reg_invalid,
+               [SCSPTR]        = sci_reg_invalid,
+               [SCLSR]         = sci_reg_invalid,
+       },
+
+       /*
+        * Common SH-4(A) SCIF(B) definitions.
+        */
+       [SCIx_SH4_SCIF_REGTYPE] = {
+               [SCSMR]         = { 0x00, 16 },
+               [SCBRR]         = { 0x04,  8 },
+               [SCSCR]         = { 0x08, 16 },
+               [SCxTDR]        = { 0x0c,  8 },
+               [SCxSR]         = { 0x10, 16 },
+               [SCxRDR]        = { 0x14,  8 },
+               [SCFCR]         = { 0x18, 16 },
+               [SCFDR]         = { 0x1c, 16 },
+               [SCTFDR]        = sci_reg_invalid,
+               [SCRFDR]        = sci_reg_invalid,
+               [SCSPTR]        = { 0x20, 16 },
+               [SCLSR]         = { 0x24, 16 },
+       },
+
+       /*
+        * Common SH-4(A) SCIF(B) definitions for ports without an SCSPTR
+        * register.
+        */
+       [SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE] = {
+               [SCSMR]         = { 0x00, 16 },
+               [SCBRR]         = { 0x04,  8 },
+               [SCSCR]         = { 0x08, 16 },
+               [SCxTDR]        = { 0x0c,  8 },
+               [SCxSR]         = { 0x10, 16 },
+               [SCxRDR]        = { 0x14,  8 },
+               [SCFCR]         = { 0x18, 16 },
+               [SCFDR]         = { 0x1c, 16 },
+               [SCTFDR]        = sci_reg_invalid,
+               [SCRFDR]        = sci_reg_invalid,
+               [SCSPTR]        = sci_reg_invalid,
+               [SCLSR]         = { 0x24, 16 },
+       },
+
+       /*
+        * Common SH-4(A) SCIF(B) definitions for ports with FIFO data
+        * count registers.
+        */
+       [SCIx_SH4_SCIF_FIFODATA_REGTYPE] = {
+               [SCSMR]         = { 0x00, 16 },
+               [SCBRR]         = { 0x04,  8 },
+               [SCSCR]         = { 0x08, 16 },
+               [SCxTDR]        = { 0x0c,  8 },
+               [SCxSR]         = { 0x10, 16 },
+               [SCxRDR]        = { 0x14,  8 },
+               [SCFCR]         = { 0x18, 16 },
+               [SCFDR]         = { 0x1c, 16 },
+               [SCTFDR]        = { 0x1c, 16 }, /* aliased to SCFDR */
+               [SCRFDR]        = { 0x20, 16 },
+               [SCSPTR]        = { 0x24, 16 },
+               [SCLSR]         = { 0x28, 16 },
+       },
+
+       /*
+        * SH7705-style SCIF(B) ports, lacking both SCSPTR and SCLSR
+        * registers.
+        */
+       [SCIx_SH7705_SCIF_REGTYPE] = {
+               [SCSMR]         = { 0x00, 16 },
+               [SCBRR]         = { 0x04,  8 },
+               [SCSCR]         = { 0x08, 16 },
+               [SCxTDR]        = { 0x20,  8 },
+               [SCxSR]         = { 0x14, 16 },
+               [SCxRDR]        = { 0x24,  8 },
+               [SCFCR]         = { 0x18, 16 },
+               [SCFDR]         = { 0x1c, 16 },
+               [SCTFDR]        = sci_reg_invalid,
+               [SCRFDR]        = sci_reg_invalid,
+               [SCSPTR]        = sci_reg_invalid,
+               [SCLSR]         = sci_reg_invalid,
+       },
+};
+
+#define sci_getreg(up, offset)         (sci_regmap[to_sci_port(up)->cfg->regtype] + offset)
+
+/*
+ * The "offset" here is rather misleading, in that it refers to an enum
+ * value relative to the port mapping rather than the fixed offset
+ * itself, which needs to be manually retrieved from the platform's
+ * register map for the given port.
+ */
+static unsigned int sci_serial_in(struct uart_port *p, int offset)
+{
+       struct plat_sci_reg *reg = sci_getreg(p, offset);
+
+       if (reg->size == 8)
+               return ioread8(p->membase + (reg->offset << p->regshift));
+       else if (reg->size == 16)
+               return ioread16(p->membase + (reg->offset << p->regshift));
+       else
+               WARN(1, "Invalid register access\n");
+
+       return 0;
+}
+
+static void sci_serial_out(struct uart_port *p, int offset, int value)
+{
+       struct plat_sci_reg *reg = sci_getreg(p, offset);
+
+       if (reg->size == 8)
+               iowrite8(value, p->membase + (reg->offset << p->regshift));
+       else if (reg->size == 16)
+               iowrite16(value, p->membase + (reg->offset << p->regshift));
+       else
+               WARN(1, "Invalid register access\n");
+}
+
+#define sci_in(up, offset)             (up->serial_in(up, offset))
+#define sci_out(up, offset, value)     (up->serial_out(up, offset, value))
+
+static int sci_probe_regmap(struct plat_sci_port *cfg)
+{
+       switch (cfg->type) {
+       case PORT_SCI:
+               cfg->regtype = SCIx_SCI_REGTYPE;
+               break;
+       case PORT_IRDA:
+               cfg->regtype = SCIx_IRDA_REGTYPE;
+               break;
+       case PORT_SCIFA:
+               cfg->regtype = SCIx_SCIFA_REGTYPE;
+               break;
+       case PORT_SCIFB:
+               cfg->regtype = SCIx_SCIFB_REGTYPE;
+               break;
+       case PORT_SCIF:
+               /*
+                * The SH-4 is a bit of a misnomer here, although that's
+                * where this particular port layout originated. This
+                * configuration (or some slight variation thereof)
+                * remains the dominant model for all SCIFs.
+                */
+               cfg->regtype = SCIx_SH4_SCIF_REGTYPE;
+               break;
+       default:
+               printk(KERN_ERR "Can't probe register map for given port\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void sci_port_enable(struct sci_port *sci_port)
+{
+       if (!sci_port->port.dev)
+               return;
+
+       pm_runtime_get_sync(sci_port->port.dev);
+
+       clk_enable(sci_port->iclk);
+       sci_port->port.uartclk = clk_get_rate(sci_port->iclk);
+       clk_enable(sci_port->fclk);
+}
+
+static void sci_port_disable(struct sci_port *sci_port)
+{
+       if (!sci_port->port.dev)
+               return;
+
+       clk_disable(sci_port->fclk);
+       clk_disable(sci_port->iclk);
+
+       pm_runtime_put_sync(sci_port->port.dev);
+}
+
 #if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
 
 #ifdef CONFIG_CONSOLE_POLL
@@ -164,223 +428,76 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c)
 }
 #endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */
 
-#if defined(__H8300H__) || defined(__H8300S__)
 static void sci_init_pins(struct uart_port *port, unsigned int cflag)
 {
-       int ch = (port->mapbase - SMR0) >> 3;
-
-       /* set DDR regs */
-       H8300_GPIO_DDR(h8300_sci_pins[ch].port,
-                      h8300_sci_pins[ch].rx,
-                      H8300_GPIO_INPUT);
-       H8300_GPIO_DDR(h8300_sci_pins[ch].port,
-                      h8300_sci_pins[ch].tx,
-                      H8300_GPIO_OUTPUT);
-
-       /* tx mark output*/
-       H8300_SCI_DR(ch) |= h8300_sci_pins[ch].tx;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       if (port->mapbase == 0xA4400000) {
-               __raw_writew(__raw_readw(PACR) & 0xffc0, PACR);
-               __raw_writew(__raw_readw(PBCR) & 0x0fff, PBCR);
-       } else if (port->mapbase == 0xA4410000)
-               __raw_writew(__raw_readw(PBCR) & 0xf003, PBCR);
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || defined(CONFIG_CPU_SUBTYPE_SH7721)
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       unsigned short data;
-
-       if (cflag & CRTSCTS) {
-               /* enable RTS/CTS */
-               if (port->mapbase == 0xa4430000) { /* SCIF0 */
-                       /* Clear PTCR bit 9-2; enable all scif pins but sck */
-                       data = __raw_readw(PORT_PTCR);
-                       __raw_writew((data & 0xfc03), PORT_PTCR);
-               } else if (port->mapbase == 0xa4438000) { /* SCIF1 */
-                       /* Clear PVCR bit 9-2 */
-                       data = __raw_readw(PORT_PVCR);
-                       __raw_writew((data & 0xfc03), PORT_PVCR);
-               }
-       } else {
-               if (port->mapbase == 0xa4430000) { /* SCIF0 */
-                       /* Clear PTCR bit 5-2; enable only tx and rx  */
-                       data = __raw_readw(PORT_PTCR);
-                       __raw_writew((data & 0xffc3), PORT_PTCR);
-               } else if (port->mapbase == 0xa4438000) { /* SCIF1 */
-                       /* Clear PVCR bit 5-2 */
-                       data = __raw_readw(PORT_PVCR);
-                       __raw_writew((data & 0xffc3), PORT_PVCR);
-               }
-       }
-}
-#elif defined(CONFIG_CPU_SH3)
-/* For SH7705, SH7706, SH7707, SH7709, SH7709A, SH7729 */
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       unsigned short data;
-
-       /* We need to set SCPCR to enable RTS/CTS */
-       data = __raw_readw(SCPCR);
-       /* Clear out SCP7MD1,0, SCP6MD1,0, SCP4MD1,0*/
-       __raw_writew(data & 0x0fcf, SCPCR);
-
-       if (!(cflag & CRTSCTS)) {
-               /* We need to set SCPCR to enable RTS/CTS */
-               data = __raw_readw(SCPCR);
-               /* Clear out SCP7MD1,0, SCP4MD1,0,
-                  Set SCP6MD1,0 = {01} (output)  */
-               __raw_writew((data & 0x0fcf) | 0x1000, SCPCR);
+       struct sci_port *s = to_sci_port(port);
+       struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR;
 
-               data = __raw_readb(SCPDR);
-               /* Set /RTS2 (bit6) = 0 */
-               __raw_writeb(data & 0xbf, SCPDR);
+       /*
+        * Use port-specific handler if provided.
+        */
+       if (s->cfg->ops && s->cfg->ops->init_pins) {
+               s->cfg->ops->init_pins(port, cflag);
+               return;
        }
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       unsigned short data;
 
-       if (port->mapbase == 0xffe00000) {
-               data = __raw_readw(PSCR);
-               data &= ~0x03cf;
-               if (!(cflag & CRTSCTS))
-                       data |= 0x0340;
+       /*
+        * For the generic path SCSPTR is necessary. Bail out if that's
+        * unavailable, too.
+        */
+       if (!reg->size)
+               return;
 
-               __raw_writew(data, PSCR);
-       }
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7757) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7763) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7780) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7785) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7786) || \
-      defined(CONFIG_CPU_SUBTYPE_SHX3)
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
        if (!(cflag & CRTSCTS))
-               __raw_writew(0x0080, SCSPTR0); /* Set RTS = 1 */
+               sci_out(port, SCSPTR, 0x0080); /* Set RTS = 1 */
 }
-#elif defined(CONFIG_CPU_SH4) && !defined(CONFIG_CPU_SH4A)
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       if (!(cflag & CRTSCTS))
-               __raw_writew(0x0080, SCSPTR2); /* Set RTS = 1 */
-}
-#else
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       /* Nothing to do */
-}
-#endif
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7760) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7780) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7785) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7786)
-static int scif_txfill(struct uart_port *port)
-{
-       return sci_in(port, SCTFDR) & 0xff;
-}
-
-static int scif_txroom(struct uart_port *port)
+static int sci_txfill(struct uart_port *port)
 {
-       return SCIF_TXROOM_MAX - scif_txfill(port);
-}
+       struct plat_sci_reg *reg;
 
-static int scif_rxfill(struct uart_port *port)
-{
-       return sci_in(port, SCRFDR) & 0xff;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
-static int scif_txfill(struct uart_port *port)
-{
-       if (port->mapbase == 0xffe00000 ||
-           port->mapbase == 0xffe08000)
-               /* SCIF0/1*/
+       reg = sci_getreg(port, SCTFDR);
+       if (reg->size)
                return sci_in(port, SCTFDR) & 0xff;
-       else
-               /* SCIF2 */
+
+       reg = sci_getreg(port, SCFDR);
+       if (reg->size)
                return sci_in(port, SCFDR) >> 8;
-}
 
-static int scif_txroom(struct uart_port *port)
-{
-       if (port->mapbase == 0xffe00000 ||
-           port->mapbase == 0xffe08000)
-               /* SCIF0/1*/
-               return SCIF_TXROOM_MAX - scif_txfill(port);
-       else
-               /* SCIF2 */
-               return SCIF2_TXROOM_MAX - scif_txfill(port);
+       return !(sci_in(port, SCxSR) & SCI_TDRE);
 }
 
-static int scif_rxfill(struct uart_port *port)
-{
-       if ((port->mapbase == 0xffe00000) ||
-           (port->mapbase == 0xffe08000)) {
-               /* SCIF0/1*/
-               return sci_in(port, SCRFDR) & 0xff;
-       } else {
-               /* SCIF2 */
-               return sci_in(port, SCFDR) & SCIF2_RFDC_MASK;
-       }
-}
-#elif defined(CONFIG_ARCH_SH7372)
-static int scif_txfill(struct uart_port *port)
+static int sci_txroom(struct uart_port *port)
 {
-       if (port->type == PORT_SCIFA)
-               return sci_in(port, SCFDR) >> 8;
-       else
-               return sci_in(port, SCTFDR);
+       return port->fifosize - sci_txfill(port);
 }
 
-static int scif_txroom(struct uart_port *port)
+static int sci_rxfill(struct uart_port *port)
 {
-       return port->fifosize - scif_txfill(port);
-}
+       struct plat_sci_reg *reg;
 
-static int scif_rxfill(struct uart_port *port)
-{
-       if (port->type == PORT_SCIFA)
-               return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
-       else
-               return sci_in(port, SCRFDR);
-}
-#else
-static int scif_txfill(struct uart_port *port)
-{
-       return sci_in(port, SCFDR) >> 8;
-}
+       reg = sci_getreg(port, SCRFDR);
+       if (reg->size)
+               return sci_in(port, SCRFDR) & 0xff;
 
-static int scif_txroom(struct uart_port *port)
-{
-       return SCIF_TXROOM_MAX - scif_txfill(port);
-}
+       reg = sci_getreg(port, SCFDR);
+       if (reg->size)
+               return sci_in(port, SCFDR) & ((port->fifosize << 1) - 1);
 
-static int scif_rxfill(struct uart_port *port)
-{
-       return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
+       return (sci_in(port, SCxSR) & SCxSR_RDxF(port)) != 0;
 }
-#endif
 
-static int sci_txfill(struct uart_port *port)
+/*
+ * SCI helper for checking the state of the muxed port/RXD pins.
+ */
+static inline int sci_rxd_in(struct uart_port *port)
 {
-       return !(sci_in(port, SCxSR) & SCI_TDRE);
-}
+       struct sci_port *s = to_sci_port(port);
 
-static int sci_txroom(struct uart_port *port)
-{
-       return !sci_txfill(port);
-}
+       if (s->cfg->port_reg <= 0)
+               return 1;
 
-static int sci_rxfill(struct uart_port *port)
-{
-       return (sci_in(port, SCxSR) & SCxSR_RDxF(port)) != 0;
+       return !!__raw_readb(s->cfg->port_reg);
 }
 
 /* ********************************************************************** *
@@ -406,10 +523,7 @@ static void sci_transmit_chars(struct uart_port *port)
                return;
        }
 
-       if (port->type == PORT_SCI)
-               count = sci_txroom(port);
-       else
-               count = scif_txroom(port);
+       count = sci_txroom(port);
 
        do {
                unsigned char c;
@@ -464,13 +578,8 @@ static void sci_receive_chars(struct uart_port *port)
                return;
 
        while (1) {
-               if (port->type == PORT_SCI)
-                       count = sci_rxfill(port);
-               else
-                       count = scif_rxfill(port);
-
                /* Don't copy more bytes than there is room for in the buffer */
-               count = tty_buffer_request_room(tty, count);
+               count = tty_buffer_request_room(tty, sci_rxfill(port));
 
                /* If for any reason we can't copy more data, we're done! */
                if (count == 0)
@@ -561,8 +670,7 @@ static void sci_break_timer(unsigned long data)
 {
        struct sci_port *port = (struct sci_port *)data;
 
-       if (port->enable)
-               port->enable(&port->port);
+       sci_port_enable(port);
 
        if (sci_rxd_in(&port->port) == 0) {
                port->break_flag = 1;
@@ -574,8 +682,7 @@ static void sci_break_timer(unsigned long data)
        } else
                port->break_flag = 0;
 
-       if (port->disable)
-               port->disable(&port->port);
+       sci_port_disable(port);
 }
 
 static int sci_handle_errors(struct uart_port *port)
@@ -583,13 +690,19 @@ static int sci_handle_errors(struct uart_port *port)
        int copied = 0;
        unsigned short status = sci_in(port, SCxSR);
        struct tty_struct *tty = port->state->port.tty;
+       struct sci_port *s = to_sci_port(port);
 
-       if (status & SCxSR_ORER(port)) {
-               /* overrun error */
-               if (tty_insert_flip_char(tty, 0, TTY_OVERRUN))
-                       copied++;
+       /*
+        * Handle overruns, if supported.
+        */
+       if (s->cfg->overrun_bit != SCIx_NOT_SUPPORTED) {
+               if (status & (1 << s->cfg->overrun_bit)) {
+                       /* overrun error */
+                       if (tty_insert_flip_char(tty, 0, TTY_OVERRUN))
+                               copied++;
 
-               dev_notice(port->dev, "overrun error");
+                       dev_notice(port->dev, "overrun error");
+               }
        }
 
        if (status & SCxSR_FER(port)) {
@@ -637,12 +750,15 @@ static int sci_handle_errors(struct uart_port *port)
 static int sci_handle_fifo_overrun(struct uart_port *port)
 {
        struct tty_struct *tty = port->state->port.tty;
+       struct sci_port *s = to_sci_port(port);
+       struct plat_sci_reg *reg;
        int copied = 0;
 
-       if (port->type != PORT_SCIF)
+       reg = sci_getreg(port, SCLSR);
+       if (!reg->size)
                return 0;
 
-       if ((sci_in(port, SCLSR) & SCIF_ORER) != 0) {
+       if ((sci_in(port, SCLSR) & (1 << s->cfg->overrun_bit))) {
                sci_out(port, SCLSR, 0);
 
                tty_insert_flip_char(tty, 0, TTY_OVERRUN);
@@ -840,74 +956,102 @@ static int sci_notifier(struct notifier_block *self,
        return NOTIFY_OK;
 }
 
-static void sci_clk_enable(struct uart_port *port)
-{
-       struct sci_port *sci_port = to_sci_port(port);
-
-       pm_runtime_get_sync(port->dev);
+static struct sci_irq_desc {
+       const char      *desc;
+       irq_handler_t   handler;
+} sci_irq_desc[] = {
+       /*
+        * Split out handlers, the default case.
+        */
+       [SCIx_ERI_IRQ] = {
+               .desc = "rx err",
+               .handler = sci_er_interrupt,
+       },
 
-       clk_enable(sci_port->iclk);
-       sci_port->port.uartclk = clk_get_rate(sci_port->iclk);
-       clk_enable(sci_port->fclk);
-}
+       [SCIx_RXI_IRQ] = {
+               .desc = "rx full",
+               .handler = sci_rx_interrupt,
+       },
 
-static void sci_clk_disable(struct uart_port *port)
-{
-       struct sci_port *sci_port = to_sci_port(port);
+       [SCIx_TXI_IRQ] = {
+               .desc = "tx empty",
+               .handler = sci_tx_interrupt,
+       },
 
-       clk_disable(sci_port->fclk);
-       clk_disable(sci_port->iclk);
+       [SCIx_BRI_IRQ] = {
+               .desc = "break",
+               .handler = sci_br_interrupt,
+       },
 
-       pm_runtime_put_sync(port->dev);
-}
+       /*
+        * Special muxed handler.
+        */
+       [SCIx_MUX_IRQ] = {
+               .desc = "mux",
+               .handler = sci_mpxed_interrupt,
+       },
+};
 
 static int sci_request_irq(struct sci_port *port)
 {
-       int i;
-       irqreturn_t (*handlers[4])(int irq, void *ptr) = {
-               sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt,
-               sci_br_interrupt,
-       };
-       const char *desc[] = { "SCI Receive Error", "SCI Receive Data Full",
-                              "SCI Transmit Data Empty", "SCI Break" };
-
-       if (port->cfg->irqs[0] == port->cfg->irqs[1]) {
-               if (unlikely(!port->cfg->irqs[0]))
-                       return -ENODEV;
-
-               if (request_irq(port->cfg->irqs[0], sci_mpxed_interrupt,
-                               IRQF_DISABLED, "sci", port)) {
-                       dev_err(port->port.dev, "Can't allocate IRQ\n");
-                       return -ENODEV;
+       struct uart_port *up = &port->port;
+       int i, j, ret = 0;
+
+       for (i = j = 0; i < SCIx_NR_IRQS; i++, j++) {
+               struct sci_irq_desc *desc;
+               unsigned int irq;
+
+               if (SCIx_IRQ_IS_MUXED(port)) {
+                       i = SCIx_MUX_IRQ;
+                       irq = up->irq;
+               } else
+                       irq = port->cfg->irqs[i];
+
+               desc = sci_irq_desc + i;
+               port->irqstr[j] = kasprintf(GFP_KERNEL, "%s:%s",
+                                           dev_name(up->dev), desc->desc);
+               if (!port->irqstr[j]) {
+                       dev_err(up->dev, "Failed to allocate %s IRQ string\n",
+                               desc->desc);
+                       goto out_nomem;
                }
-       } else {
-               for (i = 0; i < ARRAY_SIZE(handlers); i++) {
-                       if (unlikely(!port->cfg->irqs[i]))
-                               continue;
-
-                       if (request_irq(port->cfg->irqs[i], handlers[i],
-                                       IRQF_DISABLED, desc[i], port)) {
-                               dev_err(port->port.dev, "Can't allocate IRQ\n");
-                               return -ENODEV;
-                       }
+
+               ret = request_irq(irq, desc->handler, up->irqflags,
+                                 port->irqstr[j], port);
+               if (unlikely(ret)) {
+                       dev_err(up->dev, "Can't allocate %s IRQ\n", desc->desc);
+                       goto out_noirq;
                }
        }
 
        return 0;
+
+out_noirq:
+       while (--i >= 0)
+               free_irq(port->cfg->irqs[i], port);
+
+out_nomem:
+       while (--j >= 0)
+               kfree(port->irqstr[j]);
+
+       return ret;
 }
 
 static void sci_free_irq(struct sci_port *port)
 {
        int i;
 
-       if (port->cfg->irqs[0] == port->cfg->irqs[1])
-               free_irq(port->cfg->irqs[0], port);
-       else {
-               for (i = 0; i < ARRAY_SIZE(port->cfg->irqs); i++) {
-                       if (!port->cfg->irqs[i])
-                               continue;
+       /*
+        * Intentionally in reverse order so we iterate over the muxed
+        * IRQ first.
+        */
+       for (i = 0; i < SCIx_NR_IRQS; i++) {
+               free_irq(port->cfg->irqs[i], port);
+               kfree(port->irqstr[i]);
 
-                       free_irq(port->cfg->irqs[i], port);
+               if (SCIx_IRQ_IS_MUXED(port)) {
+                       /* If there's only one IRQ, we're done. */
+                       return;
                }
        }
 }
@@ -915,7 +1059,7 @@ static void sci_free_irq(struct sci_port *port)
 static unsigned int sci_tx_empty(struct uart_port *port)
 {
        unsigned short status = sci_in(port, SCxSR);
-       unsigned short in_tx_fifo = scif_txfill(port);
+       unsigned short in_tx_fifo = sci_txfill(port);
 
        return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0;
 }
@@ -1438,8 +1582,7 @@ static int sci_startup(struct uart_port *port)
 
        dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
 
-       if (s->enable)
-               s->enable(port);
+       sci_port_enable(s);
 
        ret = sci_request_irq(s);
        if (unlikely(ret < 0))
@@ -1465,8 +1608,7 @@ static void sci_shutdown(struct uart_port *port)
        sci_free_dma(port);
        sci_free_irq(s);
 
-       if (s->disable)
-               s->disable(port);
+       sci_port_disable(s);
 }
 
 static unsigned int sci_scbrr_calc(unsigned int algo_id, unsigned int bps,
@@ -1513,8 +1655,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
        if (likely(baud && port->uartclk))
                t = sci_scbrr_calc(s->cfg->scbrr_algo_id, baud, port->uartclk);
 
-       if (s->enable)
-               s->enable(port);
+       sci_port_enable(s);
 
        do {
                status = sci_in(port, SCxSR);
@@ -1584,8 +1725,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
        if ((termios->c_cflag & CREAD) != 0)
                sci_start_rx(port);
 
-       if (s->disable)
-               s->disable(port);
+       sci_port_disable(s);
 }
 
 static const char *sci_type(struct uart_port *port)
@@ -1726,6 +1866,7 @@ static int __devinit sci_init_single(struct platform_device *dev,
                                     struct plat_sci_port *p)
 {
        struct uart_port *port = &sci_port->port;
+       int ret;
 
        port->ops       = &sci_uart_ops;
        port->iotype    = UPIO_MEM;
@@ -1746,6 +1887,12 @@ static int __devinit sci_init_single(struct platform_device *dev,
                break;
        }
 
+       if (p->regtype == SCIx_PROBE_REGTYPE) {
+               ret = sci_probe_regmap(p);
+               if (unlikely(ret))
+                       return ret;
+       }
+
        if (dev) {
                sci_port->iclk = clk_get(&dev->dev, "sci_ick");
                if (IS_ERR(sci_port->iclk)) {
@@ -1764,8 +1911,6 @@ static int __devinit sci_init_single(struct platform_device *dev,
                if (IS_ERR(sci_port->fclk))
                        sci_port->fclk = NULL;
 
-               sci_port->enable = sci_clk_enable;
-               sci_port->disable = sci_clk_disable;
                port->dev = &dev->dev;
 
                pm_runtime_enable(&dev->dev);
@@ -1775,20 +1920,51 @@ static int __devinit sci_init_single(struct platform_device *dev,
        sci_port->break_timer.function = sci_break_timer;
        init_timer(&sci_port->break_timer);
 
+       /*
+        * Establish some sensible defaults for the error detection.
+        */
+       if (!p->error_mask)
+               p->error_mask = (p->type == PORT_SCI) ?
+                       SCI_DEFAULT_ERROR_MASK : SCIF_DEFAULT_ERROR_MASK;
+
+       /*
+        * Establish sensible defaults for the overrun detection, unless
+        * the part has explicitly disabled support for it.
+        */
+       if (p->overrun_bit != SCIx_NOT_SUPPORTED) {
+               if (p->type == PORT_SCI)
+                       p->overrun_bit = 5;
+               else if (p->scbrr_algo_id == SCBRR_ALGO_4)
+                       p->overrun_bit = 9;
+               else
+                       p->overrun_bit = 0;
+
+               /*
+                * Make the error mask inclusive of overrun detection, if
+                * supported.
+                */
+               p->error_mask |= (1 << p->overrun_bit);
+       }
+
        sci_port->cfg           = p;
 
        port->mapbase           = p->mapbase;
        port->type              = p->type;
        port->flags             = p->flags;
+       port->regshift          = p->regshift;
 
        /*
-        * The UART port needs an IRQ value, so we peg this to the TX IRQ
+        * The UART port needs an IRQ value, so we peg this to the RX IRQ
         * for the multi-IRQ ports, which is where we are primarily
         * concerned with the shutdown path synchronization.
         *
         * For the muxed case there's nothing more to do.
         */
        port->irq               = p->irqs[SCIx_RXI_IRQ];
+       port->irqflags          = IRQF_DISABLED;
+
+       port->serial_in         = sci_serial_in;
+       port->serial_out        = sci_serial_out;
 
        if (p->dma_dev)
                dev_dbg(port->dev, "DMA device %p, tx %d, rx %d\n",
@@ -1814,8 +1990,7 @@ static void serial_console_write(struct console *co, const char *s,
        struct uart_port *port = &sci_port->port;
        unsigned short bits;
 
-       if (sci_port->enable)
-               sci_port->enable(port);
+       sci_port_enable(sci_port);
 
        uart_console_write(port, s, count, serial_console_putchar);
 
@@ -1824,8 +1999,7 @@ static void serial_console_write(struct console *co, const char *s,
        while ((sci_in(port, SCxSR) & bits) != bits)
                cpu_relax();
 
-       if (sci_port->disable)
-               sci_port->disable(port);
+       sci_port_disable(sci_port);
 }
 
 static int __devinit serial_console_setup(struct console *co, char *options)
@@ -1857,20 +2031,13 @@ static int __devinit serial_console_setup(struct console *co, char *options)
        if (unlikely(ret != 0))
                return ret;
 
-       if (sci_port->enable)
-               sci_port->enable(port);
+       sci_port_enable(sci_port);
 
        if (options)
                uart_parse_options(options, &baud, &parity, &bits, &flow);
 
-       ret = uart_set_options(port, co, baud, parity, bits, flow);
-#if defined(__H8300H__) || defined(__H8300S__)
-       /* disable rx interrupt */
-       if (ret == 0)
-               sci_stop_rx(port);
-#endif
        /* TODO: disable clock */
-       return ret;
+       return uart_set_options(port, co, baud, parity, bits, flow);
 }
 
 static struct console serial_console = {
@@ -2081,3 +2248,5 @@ module_exit(sci_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:sh-sci");
+MODULE_AUTHOR("Paul Mundt");
+MODULE_DESCRIPTION("SuperH SCI(F) serial driver");
index b04d937..e9bed03 100644 (file)
 #include <linux/io.h>
 #include <linux/gpio.h>
 
-#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
-#include <asm/regs306x.h>
-#endif
-#if defined(CONFIG_H8S2678)
-#include <asm/regs267x.h>
-#endif
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7707) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7708) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7709)
-# define SCPCR  0xA4000116 /* 16 bit SCI and SCIF */
-# define SCPDR  0xA4000136 /* 8  bit SCI and SCIF */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
-# define SCIF0         0xA4400000
-# define SCIF2         0xA4410000
-# define SCPCR 0xA4000116
-# define SCPDR 0xA4000136
-#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7721) || \
-      defined(CONFIG_ARCH_SH73A0) || \
-      defined(CONFIG_ARCH_SH7367) || \
-      defined(CONFIG_ARCH_SH7377) || \
-      defined(CONFIG_ARCH_SH7372)
-# define PORT_PTCR        0xA405011EUL
-# define PORT_PVCR        0xA4050122UL
-# define SCIF_ORER        0x0200   /* overrun error bit */
-#elif defined(CONFIG_SH_RTS7751R2D)
-# define SCSPTR1 0xFFE0001C /* 8 bit SCIF */
-# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001   /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7750)  || \
-      defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7091)  || \
-      defined(CONFIG_CPU_SUBTYPE_SH7751)  || \
-      defined(CONFIG_CPU_SUBTYPE_SH7751R)
-# define SCSPTR1 0xffe0001c /* 8  bit SCI */
-# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001   /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7760)
-# define SCSPTR0 0xfe600024 /* 16 bit SCIF */
-# define SCSPTR1 0xfe610024 /* 16 bit SCIF */
-# define SCSPTR2 0xfe620024 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001  /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
-# define SCSPTR0 0xA4400000      /* 16 bit SCIF */
-# define SCIF_ORER 0x0001   /* overrun error bit */
-# define PACR 0xa4050100
-# define PBCR 0xa4050102
-#elif defined(CONFIG_CPU_SUBTYPE_SH7343)
-# define SCSPTR0 0xffe00010    /* 16 bit SCIF */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
-# define PADR                  0xA4050120
-# define PSDR                  0xA405013e
-# define PWDR                  0xA4050166
-# define PSCR                  0xA405011E
-# define SCIF_ORER             0x0001  /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7366)
-# define SCPDR0                        0xA405013E      /* 16 bit SCIF0 PSDR */
-# define SCSPTR0               SCPDR0
-# define SCIF_ORER             0x0001  /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7723)
-# define SCSPTR0                0xa4050160
-# define SCIF_ORER              0x0001  /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7724)
-# define SCIF_ORER              0x0001  /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH4_202)
-# define SCSPTR2 0xffe80020 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001   /* overrun error bit */
-#elif defined(CONFIG_H83007) || defined(CONFIG_H83068)
-# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
-#elif defined(CONFIG_H8S2678)
-# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7757)
-# define SCSPTR0 0xfe4b0020
-# define SCIF_ORER 0x0001
-#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
-# define SCSPTR0 0xffe00024 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001  /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7770)
-# define SCSPTR0 0xff923020 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001  /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
-# define SCSPTR0       0xffe00024      /* 16 bit SCIF */
-# define SCIF_ORER     0x0001          /* Overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7785) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7786)
-# define SCSPTR0       0xffea0024      /* 16 bit SCIF */
-# define SCIF_ORER     0x0001          /* Overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7201) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7203) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7206) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7263)
-# define SCSPTR0 0xfffe8020 /* 16 bit SCIF */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7619)
-# define SCSPTR0 0xf8400020 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001  /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SHX3)
-# define SCSPTR0 0xffc30020            /* 16 bit SCIF */
-# define SCIF_ORER 0x0001              /* Overrun error bit */
-#else
-# error CPU subtype not defined
-#endif
-
-/* SCxSR SCI */
-#define SCI_TDRE  0x80 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-#define SCI_RDRF  0x40 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-#define SCI_ORER  0x20 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-#define SCI_FER   0x10 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-#define SCI_PER   0x08 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-#define SCI_TEND  0x04 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-/*      SCI_MPB   0x02  * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-/*      SCI_MPBT  0x01  * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-
-#define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ORER)
-
-/* SCxSR SCIF */
-#define SCIF_ER    0x0080 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_TEND  0x0040 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_TDFE  0x0020 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_BRK   0x0010 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_FER   0x0008 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_PER   0x0004 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_RDF   0x0002 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_DR    0x0001 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7721) || \
-    defined(CONFIG_ARCH_SH73A0) || \
-    defined(CONFIG_ARCH_SH7367) || \
-    defined(CONFIG_ARCH_SH7377) || \
-    defined(CONFIG_ARCH_SH7372)
-# define SCIF_ORER    0x0200
-# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK | SCIF_ORER)
-# define SCIF_RFDC_MASK 0x007f
-# define SCIF_TXROOM_MAX 64
-#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
-# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK )
-# define SCIF_RFDC_MASK 0x007f
-# define SCIF_TXROOM_MAX 64
-/* SH7763 SCIF2 support */
-# define SCIF2_RFDC_MASK 0x001f
-# define SCIF2_TXROOM_MAX 16
-#else
-# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK)
-# define SCIF_RFDC_MASK 0x001f
-# define SCIF_TXROOM_MAX 16
-#endif
-
-#ifndef SCIF_ORER
-#define SCIF_ORER      0x0000
-#endif
-
 #define SCxSR_TEND(port)       (((port)->type == PORT_SCI) ? SCI_TEND   : SCIF_TEND)
-#define SCxSR_ERRORS(port)     (((port)->type == PORT_SCI) ? SCI_ERRORS : SCIF_ERRORS)
 #define SCxSR_RDxF(port)       (((port)->type == PORT_SCI) ? SCI_RDRF   : SCIF_RDF)
 #define SCxSR_TDxE(port)       (((port)->type == PORT_SCI) ? SCI_TDRE   : SCIF_TDFE)
 #define SCxSR_FER(port)                (((port)->type == PORT_SCI) ? SCI_FER    : SCIF_FER)
 #define SCxSR_PER(port)                (((port)->type == PORT_SCI) ? SCI_PER    : SCIF_PER)
 #define SCxSR_BRK(port)                (((port)->type == PORT_SCI) ? 0x00       : SCIF_BRK)
-#define SCxSR_ORER(port)       (((port)->type == PORT_SCI) ? SCI_ORER   : SCIF_ORER)
+
+#define SCxSR_ERRORS(port)     (to_sci_port(port)->cfg->error_mask)
 
 #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
     defined(CONFIG_CPU_SUBTYPE_SH7720) || \
 
 #define SCI_MAJOR              204
 #define SCI_MINOR_START                8
-
-#define SCI_IN(size, offset)                                   \
-  if ((size) == 8) {                                           \
-    return ioread8(port->membase + (offset));                  \
-  } else {                                                     \
-    return ioread16(port->membase + (offset));                 \
-  }
-#define SCI_OUT(size, offset, value)                           \
-  if ((size) == 8) {                                           \
-    iowrite8(value, port->membase + (offset));                 \
-  } else if ((size) == 16) {                                   \
-    iowrite16(value, port->membase + (offset));                        \
-  }
-
-#define CPU_SCIx_FNS(name, sci_offset, sci_size, scif_offset, scif_size)\
-  static inline unsigned int sci_##name##_in(struct uart_port *port)   \
-  {                                                                    \
-    if (port->type == PORT_SCIF || port->type == PORT_SCIFB) {         \
-      SCI_IN(scif_size, scif_offset)                                   \
-    } else {   /* PORT_SCI or PORT_SCIFA */                            \
-      SCI_IN(sci_size, sci_offset);                                    \
-    }                                                                  \
-  }                                                                    \
-  static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
-  {                                                                    \
-    if (port->type == PORT_SCIF || port->type == PORT_SCIFB) {         \
-      SCI_OUT(scif_size, scif_offset, value)                           \
-    } else {   /* PORT_SCI or PORT_SCIFA */                            \
-      SCI_OUT(sci_size, sci_offset, value);                            \
-    }                                                                  \
-  }
-
-#ifdef CONFIG_H8300
-/* h8300 don't have SCIF */
-#define CPU_SCIF_FNS(name)                                             \
-  static inline unsigned int sci_##name##_in(struct uart_port *port)   \
-  {                                                                    \
-    return 0;                                                          \
-  }                                                                    \
-  static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
-  {                                                                    \
-  }
-#else
-#define CPU_SCIF_FNS(name, scif_offset, scif_size)                     \
-  static inline unsigned int sci_##name##_in(struct uart_port *port)   \
-  {                                                                    \
-    SCI_IN(scif_size, scif_offset);                                    \
-  }                                                                    \
-  static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
-  {                                                                    \
-    SCI_OUT(scif_size, scif_offset, value);                            \
-  }
-#endif
-
-#define CPU_SCI_FNS(name, sci_offset, sci_size)                                \
-  static inline unsigned int sci_##name##_in(struct uart_port* port)   \
-  {                                                                    \
-    SCI_IN(sci_size, sci_offset);                                      \
-  }                                                                    \
-  static inline void sci_##name##_out(struct uart_port* port, unsigned int value) \
-  {                                                                    \
-    SCI_OUT(sci_size, sci_offset, value);                              \
-  }
-
-#if defined(CONFIG_CPU_SH3) || \
-    defined(CONFIG_ARCH_SH73A0) || \
-    defined(CONFIG_ARCH_SH7367) || \
-    defined(CONFIG_ARCH_SH7377) || \
-    defined(CONFIG_ARCH_SH7372)
-#if defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
-#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
-                               sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
-                                h8_sci_offset, h8_sci_size) \
-  CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size)
-#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
-         CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7720) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7721) || \
-      defined(CONFIG_ARCH_SH7367)
-#define SCIF_FNS(name, scif_offset, scif_size) \
-  CPU_SCIF_FNS(name, scif_offset, scif_size)
-#elif defined(CONFIG_ARCH_SH7377) || \
-      defined(CONFIG_ARCH_SH7372) || \
-      defined(CONFIG_ARCH_SH73A0)
-#define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scifb_offset, sh4_scifb_size) \
-  CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scifb_offset, sh4_scifb_size)
-#define SCIF_FNS(name, scif_offset, scif_size) \
-  CPU_SCIF_FNS(name, scif_offset, scif_size)
-#else
-#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
-                sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
-                 h8_sci_offset, h8_sci_size) \
-  CPU_SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh3_scif_offset, sh3_scif_size)
-#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
-  CPU_SCIF_FNS(name, sh3_scif_offset, sh3_scif_size)
-#endif
-#elif defined(__H8300H__) || defined(__H8300S__)
-#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
-                sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
-                 h8_sci_offset, h8_sci_size) \
-  CPU_SCI_FNS(name, h8_sci_offset, h8_sci_size)
-#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
-  CPU_SCIF_FNS(name)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\
-      defined(CONFIG_CPU_SUBTYPE_SH7724)
-        #define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size) \
-                CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size)
-        #define SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) \
-                CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
-#else
-#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
-                sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
-                h8_sci_offset, h8_sci_size) \
-  CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size)
-#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
-  CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
-#endif
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7721) || \
-    defined(CONFIG_ARCH_SH7367)
-
-SCIF_FNS(SCSMR,  0x00, 16)
-SCIF_FNS(SCBRR,  0x04,  8)
-SCIF_FNS(SCSCR,  0x08, 16)
-SCIF_FNS(SCxSR,  0x14, 16)
-SCIF_FNS(SCFCR,  0x18, 16)
-SCIF_FNS(SCFDR,  0x1c, 16)
-SCIF_FNS(SCxTDR, 0x20,  8)
-SCIF_FNS(SCxRDR, 0x24,  8)
-SCIF_FNS(SCLSR,  0x00,  0)
-#elif defined(CONFIG_ARCH_SH7377) || \
-      defined(CONFIG_ARCH_SH7372) || \
-      defined(CONFIG_ARCH_SH73A0)
-SCIF_FNS(SCSMR,  0x00, 16)
-SCIF_FNS(SCBRR,  0x04,  8)
-SCIF_FNS(SCSCR,  0x08, 16)
-SCIF_FNS(SCTDSR, 0x0c, 16)
-SCIF_FNS(SCFER,  0x10, 16)
-SCIF_FNS(SCxSR,  0x14, 16)
-SCIF_FNS(SCFCR,  0x18, 16)
-SCIF_FNS(SCFDR,  0x1c, 16)
-SCIF_FNS(SCTFDR, 0x38, 16)
-SCIF_FNS(SCRFDR, 0x3c, 16)
-SCIx_FNS(SCxTDR, 0x20,  8, 0x40,  8)
-SCIx_FNS(SCxRDR, 0x24,  8, 0x60,  8)
-SCIF_FNS(SCLSR,  0x00,  0)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\
-      defined(CONFIG_CPU_SUBTYPE_SH7724)
-SCIx_FNS(SCSMR,  0x00, 16, 0x00, 16)
-SCIx_FNS(SCBRR,  0x04,  8, 0x04,  8)
-SCIx_FNS(SCSCR,  0x08, 16, 0x08, 16)
-SCIx_FNS(SCxTDR, 0x20,  8, 0x0c,  8)
-SCIx_FNS(SCxSR,  0x14, 16, 0x10, 16)
-SCIx_FNS(SCxRDR, 0x24,  8, 0x14,  8)
-SCIx_FNS(SCSPTR, 0,     0,    0,  0)
-SCIF_FNS(SCFCR,  0x18, 16)
-SCIF_FNS(SCFDR,  0x1c, 16)
-SCIF_FNS(SCLSR,  0x24, 16)
-#else
-/*      reg      SCI/SH3   SCI/SH4  SCIF/SH3   SCIF/SH4  SCI/H8*/
-/*      name     off  sz   off  sz   off  sz   off  sz   off  sz*/
-SCIx_FNS(SCSMR,  0x00,  8, 0x00,  8, 0x00,  8, 0x00, 16, 0x00,  8)
-SCIx_FNS(SCBRR,  0x02,  8, 0x04,  8, 0x02,  8, 0x04,  8, 0x01,  8)
-SCIx_FNS(SCSCR,  0x04,  8, 0x08,  8, 0x04,  8, 0x08, 16, 0x02,  8)
-SCIx_FNS(SCxTDR, 0x06,  8, 0x0c,  8, 0x06,  8, 0x0C,  8, 0x03,  8)
-SCIx_FNS(SCxSR,  0x08,  8, 0x10,  8, 0x08, 16, 0x10, 16, 0x04,  8)
-SCIx_FNS(SCxRDR, 0x0a,  8, 0x14,  8, 0x0A,  8, 0x14,  8, 0x05,  8)
-SCIF_FNS(SCFCR,                      0x0c,  8, 0x18, 16)
-#if defined(CONFIG_CPU_SUBTYPE_SH7760) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7780) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7785) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7786)
-SCIF_FNS(SCFDR,                             0x0e, 16, 0x1C, 16)
-SCIF_FNS(SCTFDR,                    0x0e, 16, 0x1C, 16)
-SCIF_FNS(SCRFDR,                    0x0e, 16, 0x20, 16)
-SCIF_FNS(SCSPTR,                       0,  0, 0x24, 16)
-SCIF_FNS(SCLSR,                                0,  0, 0x28, 16)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
-SCIF_FNS(SCFDR,                                0,  0, 0x1C, 16)
-SCIF_FNS(SCTFDR,                    0x0e, 16, 0x1C, 16)
-SCIF_FNS(SCRFDR,                    0x0e, 16, 0x20, 16)
-SCIF_FNS(SCSPTR,                       0,  0, 0x24, 16)
-SCIF_FNS(SCLSR,                                0,  0, 0x28, 16)
-#else
-SCIF_FNS(SCFDR,                      0x0e, 16, 0x1C, 16)
-#if defined(CONFIG_CPU_SUBTYPE_SH7722)
-SCIF_FNS(SCSPTR,                        0,  0, 0, 0)
-#else
-SCIF_FNS(SCSPTR,                        0,  0, 0x20, 16)
-#endif
-SCIF_FNS(SCLSR,                         0,  0, 0x24, 16)
-#endif
-#endif
-#define sci_in(port, reg) sci_##reg##_in(port)
-#define sci_out(port, reg, value) sci_##reg##_out(port, value)
-
-/* H8/300 series SCI pins assignment */
-#if defined(__H8300H__) || defined(__H8300S__)
-static const struct __attribute__((packed)) {
-       int port;             /* GPIO port no */
-       unsigned short rx,tx; /* GPIO bit no */
-} h8300_sci_pins[] = {
-#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
-       {    /* SCI0 */
-               .port = H8300_GPIO_P9,
-               .rx   = H8300_GPIO_B2,
-               .tx   = H8300_GPIO_B0,
-       },
-       {    /* SCI1 */
-               .port = H8300_GPIO_P9,
-               .rx   = H8300_GPIO_B3,
-               .tx   = H8300_GPIO_B1,
-       },
-       {    /* SCI2 */
-               .port = H8300_GPIO_PB,
-               .rx   = H8300_GPIO_B7,
-               .tx   = H8300_GPIO_B6,
-       }
-#elif defined(CONFIG_H8S2678)
-       {    /* SCI0 */
-               .port = H8300_GPIO_P3,
-               .rx   = H8300_GPIO_B2,
-               .tx   = H8300_GPIO_B0,
-       },
-       {    /* SCI1 */
-               .port = H8300_GPIO_P3,
-               .rx   = H8300_GPIO_B3,
-               .tx   = H8300_GPIO_B1,
-       },
-       {    /* SCI2 */
-               .port = H8300_GPIO_P5,
-               .rx   = H8300_GPIO_B1,
-               .tx   = H8300_GPIO_B0,
-       }
-#endif
-};
-#endif
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7707) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7708) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7709)
-static inline int sci_rxd_in(struct uart_port *port)
-{
-       if (port->mapbase == 0xfffffe80)
-               return __raw_readb(SCPDR)&0x01 ? 1 : 0; /* SCI */
-       return 1;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7750)  || \
-      defined(CONFIG_CPU_SUBTYPE_SH7751)  || \
-      defined(CONFIG_CPU_SUBTYPE_SH7751R) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7091)
-static inline int sci_rxd_in(struct uart_port *port)
-{
-       if (port->mapbase == 0xffe00000)
-               return __raw_readb(SCSPTR1)&0x01 ? 1 : 0; /* SCI */
-       return 1;
-}
-#elif defined(__H8300H__) || defined(__H8300S__)
-static inline int sci_rxd_in(struct uart_port *port)
-{
-       int ch = (port->mapbase - SMR0) >> 3;
-       return (H8300_SCI_DR(ch) & h8300_sci_pins[ch].rx) ? 1 : 0;
-}
-#else /* default case for non-SCI processors */
-static inline int sci_rxd_in(struct uart_port *port)
-{
-       return 1;
-}
-#endif
index 385acb8..3f94ac3 100644 (file)
@@ -268,7 +268,7 @@ usbtmc_abort_bulk_in_status:
                                dev_err(dev, "usb_bulk_msg returned %d\n", rv);
                                goto exit;
                        }
-               } while ((actual = max_size) &&
+               } while ((actual == max_size) &&
                         (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN));
 
        if (actual == max_size) {
index c962608..26678ca 100644 (file)
@@ -123,10 +123,11 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
        }
 
        if (usb_endpoint_xfer_isoc(&ep->desc))
-               max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1) *
-                       (desc->bmAttributes + 1);
+               max_tx = (desc->bMaxBurst + 1) * (desc->bmAttributes + 1) *
+                       le16_to_cpu(ep->desc.wMaxPacketSize);
        else if (usb_endpoint_xfer_int(&ep->desc))
-               max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1);
+               max_tx = le16_to_cpu(ep->desc.wMaxPacketSize) *
+                       (desc->bMaxBurst + 1);
        else
                max_tx = 999999;
        if (le16_to_cpu(desc->wBytesPerInterval) > max_tx) {
@@ -134,10 +135,10 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
                                "config %d interface %d altsetting %d ep %d: "
                                "setting to %d\n",
                                usb_endpoint_xfer_isoc(&ep->desc) ? "Isoc" : "Int",
-                               desc->wBytesPerInterval,
+                               le16_to_cpu(desc->wBytesPerInterval),
                                cfgno, inum, asnum, ep->desc.bEndpointAddress,
                                max_tx);
-               ep->ss_ep_comp.wBytesPerInterval = max_tx;
+               ep->ss_ep_comp.wBytesPerInterval = cpu_to_le16(max_tx);
        }
 }
 
index 44b6b40..5a084b9 100644 (file)
@@ -310,7 +310,7 @@ config USB_PXA_U2O
 # musb builds in ../musb along with host support
 config USB_GADGET_MUSB_HDRC
        tristate "Inventra HDRC USB Peripheral (TI, ADI, ...)"
-       depends on USB_MUSB_HDRC && (USB_MUSB_PERIPHERAL || USB_MUSB_OTG)
+       depends on USB_MUSB_HDRC
        select USB_GADGET_DUALSPEED
        help
          This OTG-capable silicon IP is used in dual designs including
index 98cbc06..ddb118a 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/list.h>
 #include <linux/interrupt.h>
 #include <linux/proc_fs.h>
+#include <linux/prefetch.h>
 #include <linux/clk.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
index 5ef8779..aef4741 100644 (file)
@@ -1079,10 +1079,12 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                        cdev->desc.bMaxPacketSize0 =
                                cdev->gadget->ep0->maxpacket;
                        if (gadget_is_superspeed(gadget)) {
-                               if (gadget->speed >= USB_SPEED_SUPER)
+                               if (gadget->speed >= USB_SPEED_SUPER) {
                                        cdev->desc.bcdUSB = cpu_to_le16(0x0300);
-                               else
+                                       cdev->desc.bMaxPacketSize0 = 9;
+                               } else {
                                        cdev->desc.bcdUSB = cpu_to_le16(0x0210);
+                               }
                        }
 
                        value = min(w_length, (u16) sizeof cdev->desc);
index 403a48b..83a266b 100644 (file)
@@ -367,6 +367,13 @@ static int hidg_setup(struct usb_function *f,
        case ((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8
                  | USB_REQ_GET_DESCRIPTOR):
                switch (value >> 8) {
+               case HID_DT_HID:
+                       VDBG(cdev, "USB_REQ_GET_DESCRIPTOR: HID\n");
+                       length = min_t(unsigned short, length,
+                                                  hidg_desc.bLength);
+                       memcpy(req->buf, &hidg_desc, length);
+                       goto respond;
+                       break;
                case HID_DT_REPORT:
                        VDBG(cdev, "USB_REQ_GET_DESCRIPTOR: REPORT\n");
                        length = min_t(unsigned short, length,
index 24a9243..4ec888f 100644 (file)
@@ -609,107 +609,6 @@ void fusb300_rdcxf(struct fusb300 *fusb300,
        }
 }
 
-#if 0
-static void fusb300_dbg_fifo(struct fusb300_ep *ep,
-                               u8 entry, u16 length)
-{
-       u32 reg;
-       u32 i = 0;
-       u32 j = 0;
-
-       reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_GTM);
-       reg &= ~(FUSB300_GTM_TST_EP_ENTRY(0xF) |
-               FUSB300_GTM_TST_EP_NUM(0xF) | FUSB300_GTM_TST_FIFO_DEG);
-       reg |= (FUSB300_GTM_TST_EP_ENTRY(entry) |
-               FUSB300_GTM_TST_EP_NUM(ep->epnum) | FUSB300_GTM_TST_FIFO_DEG);
-       iowrite32(reg, ep->fusb300->reg + FUSB300_OFFSET_GTM);
-
-       for (i = 0; i < (length >> 2); i++) {
-               if (i * 4 == 1024)
-                       break;
-               reg = ioread32(ep->fusb300->reg +
-                       FUSB300_OFFSET_BUFDBG_START + i * 4);
-               printk(KERN_DEBUG"  0x%-8x", reg);
-               j++;
-               if ((j % 4)  == 0)
-                       printk(KERN_DEBUG "\n");
-       }
-
-       if (length % 4) {
-               reg = ioread32(ep->fusb300->reg +
-                       FUSB300_OFFSET_BUFDBG_START + i * 4);
-               printk(KERN_DEBUG "  0x%x\n", reg);
-       }
-
-       if ((j % 4)  != 0)
-               printk(KERN_DEBUG "\n");
-
-       fusb300_disable_bit(ep->fusb300, FUSB300_OFFSET_GTM,
-               FUSB300_GTM_TST_FIFO_DEG);
-}
-
-static void fusb300_cmp_dbg_fifo(struct fusb300_ep *ep,
-                               u8 entry, u16 length, u8 *golden)
-{
-       u32 reg;
-       u32 i = 0;
-       u32 golden_value;
-       u8 *tmp;
-
-       tmp = golden;
-
-       printk(KERN_DEBUG "fusb300_cmp_dbg_fifo (entry %d) : start\n", entry);
-
-       reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_GTM);
-       reg &= ~(FUSB300_GTM_TST_EP_ENTRY(0xF) |
-               FUSB300_GTM_TST_EP_NUM(0xF) | FUSB300_GTM_TST_FIFO_DEG);
-       reg |= (FUSB300_GTM_TST_EP_ENTRY(entry) |
-               FUSB300_GTM_TST_EP_NUM(ep->epnum) | FUSB300_GTM_TST_FIFO_DEG);
-       iowrite32(reg, ep->fusb300->reg + FUSB300_OFFSET_GTM);
-
-       for (i = 0; i < (length >> 2); i++) {
-               if (i * 4 == 1024)
-                       break;
-               golden_value = *tmp | *(tmp + 1) << 8 |
-                               *(tmp + 2) << 16 | *(tmp + 3) << 24;
-
-               reg = ioread32(ep->fusb300->reg +
-                       FUSB300_OFFSET_BUFDBG_START + i*4);
-
-               if (reg != golden_value) {
-                       printk(KERN_DEBUG "0x%x  :  ", (u32)(ep->fusb300->reg +
-                               FUSB300_OFFSET_BUFDBG_START + i*4));
-                       printk(KERN_DEBUG "    golden = 0x%x, reg = 0x%x\n",
-                               golden_value, reg);
-               }
-               tmp += 4;
-       }
-
-       switch (length % 4) {
-       case 1:
-               golden_value = *tmp;
-       case 2:
-               golden_value = *tmp | *(tmp + 1) << 8;
-       case 3:
-               golden_value = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16;
-       default:
-               break;
-
-       reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_BUFDBG_START + i*4);
-       if (reg != golden_value) {
-               printk(KERN_DEBUG "0x%x:", (u32)(ep->fusb300->reg +
-                       FUSB300_OFFSET_BUFDBG_START + i*4));
-               printk(KERN_DEBUG "  golden = 0x%x, reg = 0x%x\n",
-                       golden_value, reg);
-       }
-       }
-
-       printk(KERN_DEBUG "fusb300_cmp_dbg_fifo : end\n");
-       fusb300_disable_bit(ep->fusb300, FUSB300_OFFSET_GTM,
-               FUSB300_GTM_TST_FIFO_DEG);
-}
-#endif
-
 static void fusb300_rdfifo(struct fusb300_ep *ep,
                          struct fusb300_request *req,
                          u32 length)
index 7c7b0e1..ab98ea9 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/ioport.h>
-#include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/pci.h>
 #include <linux/platform_device.h>
+#include <linux/prefetch.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/timer.h>
index 85c1b0d..8d31848 100644 (file)
@@ -2060,6 +2060,7 @@ static int s3c2410_udc_resume(struct platform_device *pdev)
 static const struct platform_device_id s3c_udc_ids[] = {
        { "s3c2410-usbgadget", },
        { "s3c2440-usbgadget", },
+       { }
 };
 MODULE_DEVICE_TABLE(platform, s3c_udc_ids);
 
index 5e807f0..52f8f9e 100644 (file)
@@ -124,24 +124,12 @@ uvc_v4l2_open(struct file *file)
        struct video_device *vdev = video_devdata(file);
        struct uvc_device *uvc = video_get_drvdata(vdev);
        struct uvc_file_handle *handle;
-       int ret;
 
        handle = kzalloc(sizeof(*handle), GFP_KERNEL);
        if (handle == NULL)
                return -ENOMEM;
 
-       ret = v4l2_fh_init(&handle->vfh, vdev);
-       if (ret < 0)
-               goto error;
-
-       ret = v4l2_event_init(&handle->vfh);
-       if (ret < 0)
-               goto error;
-
-       ret = v4l2_event_alloc(&handle->vfh, 8);
-       if (ret < 0)
-               goto error;
-
+       v4l2_fh_init(&handle->vfh, vdev);
        v4l2_fh_add(&handle->vfh);
 
        handle->device = &uvc->video;
@@ -149,10 +137,6 @@ uvc_v4l2_open(struct file *file)
 
        uvc_function_connect(uvc);
        return 0;
-
-error:
-       v4l2_fh_exit(&handle->vfh);
-       return ret;
 }
 
 static int
@@ -314,7 +298,7 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST)
                        return -EINVAL;
 
-               return v4l2_event_subscribe(&handle->vfh, arg);
+               return v4l2_event_subscribe(&handle->vfh, arg, 2);
        }
 
        case VIDIOC_UNSUBSCRIBE_EVENT:
@@ -354,7 +338,7 @@ uvc_v4l2_poll(struct file *file, poll_table *wait)
        struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data);
        unsigned int mask = 0;
 
-       poll_wait(file, &handle->vfh.events->wait, wait);
+       poll_wait(file, &handle->vfh.wait, wait);
        if (v4l2_event_pending(&handle->vfh))
                mask |= POLLPRI;
 
index bf2c8f6..e051b30 100644 (file)
@@ -1046,7 +1046,19 @@ static int ehci_hub_control (
                        if (!selector || selector > 5)
                                goto error;
                        ehci_quiesce(ehci);
+
+                       /* Put all enabled ports into suspend */
+                       while (ports--) {
+                               u32 __iomem *sreg =
+                                               &ehci->regs->port_status[ports];
+
+                               temp = ehci_readl(ehci, sreg) & ~PORT_RWC_BITS;
+                               if (temp & PORT_PE)
+                                       ehci_writel(ehci, temp | PORT_SUSPEND,
+                                                       sreg);
+                       }
                        ehci_halt(ehci);
+                       temp = ehci_readl(ehci, status_reg);
                        temp |= selector << 16;
                        ehci_writel(ehci, temp, status_reg);
                        break;
index 0c058be..555a73c 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/usb/ulpi.h>
 #include <linux/slab.h>
 
+#include <mach/hardware.h>
 #include <mach/mxc_ehci.h>
 
 #include <asm/mach-types.h>
index 55a57c2..4524032 100644 (file)
@@ -98,6 +98,18 @@ static void omap_ehci_soft_phy_reset(struct platform_device *pdev, u8 port)
        }
 }
 
+static void disable_put_regulator(
+               struct ehci_hcd_omap_platform_data *pdata)
+{
+       int i;
+
+       for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) {
+               if (pdata->regulator[i]) {
+                       regulator_disable(pdata->regulator[i]);
+                       regulator_put(pdata->regulator[i]);
+               }
+       }
+}
 
 /* configure so an HC device and id are always provided */
 /* always called with process context; sleeping is OK */
@@ -231,9 +243,11 @@ err_add_hcd:
        omap_usbhs_disable(dev);
 
 err_enable:
+       disable_put_regulator(pdata);
        usb_put_hcd(hcd);
 
 err_io:
+       iounmap(regs);
        return ret;
 }
 
@@ -253,6 +267,8 @@ static int ehci_hcd_omap_remove(struct platform_device *pdev)
 
        usb_remove_hcd(hcd);
        omap_usbhs_disable(dev);
+       disable_put_regulator(dev->platform_data);
+       iounmap(hcd->regs);
        usb_put_hcd(hcd);
        return 0;
 }
index 55d3d58..840beda 100644 (file)
@@ -1583,6 +1583,9 @@ static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
        int retval = 0;
 
        spin_lock_irqsave(&priv->lock, spinflags);
+       retval = usb_hcd_check_unlink_urb(hcd, urb, status);
+       if (retval)
+               goto out;
 
        qh = urb->ep->hcpriv;
        if (!qh) {
index a9d3159..629a968 100644 (file)
@@ -535,7 +535,7 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
        iounmap(base);
 }
 
-static const struct dmi_system_id __initconst ehci_dmi_nohandoff_table[] = {
+static const struct dmi_system_id __devinitconst ehci_dmi_nohandoff_table[] = {
        {
                /*  Pegatron Lucid (ExoPC) */
                .matches = {
@@ -817,7 +817,7 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
 
        /* If the BIOS owns the HC, signal that the OS wants it, and wait */
        if (val & XHCI_HC_BIOS_OWNED) {
-               writel(val & XHCI_HC_OS_OWNED, base + ext_cap_offset);
+               writel(val | XHCI_HC_OS_OWNED, base + ext_cap_offset);
 
                /* Wait for 5 seconds with 10 microsecond polling interval */
                timeout = handshake(base + ext_cap_offset, XHCI_HC_BIOS_OWNED,
index 763f484..1c4432d 100644 (file)
@@ -345,7 +345,8 @@ static void xhci_event_ring_work(unsigned long arg)
        spin_lock_irqsave(&xhci->lock, flags);
        temp = xhci_readl(xhci, &xhci->op_regs->status);
        xhci_dbg(xhci, "op reg status = 0x%x\n", temp);
-       if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING)) {
+       if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING) ||
+                       (xhci->xhc_state & XHCI_STATE_HALTED)) {
                xhci_dbg(xhci, "HW died, polling stopped.\n");
                spin_unlock_irqrestore(&xhci->lock, flags);
                return;
@@ -939,8 +940,11 @@ static int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev,
                return 0;
        }
 
+       xhci = hcd_to_xhci(hcd);
+       if (xhci->xhc_state & XHCI_STATE_HALTED)
+               return -ENODEV;
+
        if (check_virt_dev) {
-               xhci = hcd_to_xhci(hcd);
                if (!udev->slot_id || !xhci->devs
                        || !xhci->devs[udev->slot_id]) {
                        printk(KERN_DEBUG "xHCI %s called with unaddressed "
@@ -1242,7 +1246,8 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
                xhci_urb_free_priv(xhci, urb_priv);
                return ret;
        }
-       if (xhci->xhc_state & XHCI_STATE_DYING) {
+       if ((xhci->xhc_state & XHCI_STATE_DYING) ||
+                       (xhci->xhc_state & XHCI_STATE_HALTED)) {
                xhci_dbg(xhci, "Ep 0x%x: URB %p to be canceled on "
                                "non-responsive xHCI host.\n",
                                urb->ep->desc.bEndpointAddress, urb);
@@ -2665,7 +2670,10 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
        int i, ret;
 
        ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__);
-       if (ret <= 0)
+       /* If the host is halted due to driver unload, we still need to free the
+        * device.
+        */
+       if (ret <= 0 && ret != -ENODEV)
                return;
 
        virt_dev = xhci->devs[udev->slot_id];
@@ -2679,7 +2687,8 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
        spin_lock_irqsave(&xhci->lock, flags);
        /* Don't disable the slot if the host controller is dead. */
        state = xhci_readl(xhci, &xhci->op_regs->status);
-       if (state == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING)) {
+       if (state == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING) ||
+                       (xhci->xhc_state & XHCI_STATE_HALTED)) {
                xhci_free_virt_device(xhci, udev->slot_id);
                spin_unlock_irqrestore(&xhci->lock, flags);
                return;
index 6192b45..fc34b8b 100644 (file)
@@ -3,9 +3,6 @@
 # for silicon based on Mentor Graphics INVENTRA designs
 #
 
-comment "Enable Host or Gadget support to see Inventra options"
-       depends on !USB && USB_GADGET=n
-
 # (M)HDRC = (Multipoint) Highspeed Dual-Role Controller
 config USB_MUSB_HDRC
        depends on USB && USB_GADGET
index b67a062..8c41a2e 100644 (file)
@@ -1698,6 +1698,8 @@ static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on)
 
        is_on = !!is_on;
 
+       pm_runtime_get_sync(musb->controller);
+
        /* NOTE: this assumes we are sensing vbus; we'd rather
         * not pullup unless the B-session is active.
         */
@@ -1707,6 +1709,9 @@ static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on)
                musb_pullup(musb, is_on);
        }
        spin_unlock_irqrestore(&musb->lock, flags);
+
+       pm_runtime_put(musb->controller);
+
        return 0;
 }
 
index c784e6c..07c8a73 100644 (file)
@@ -89,7 +89,7 @@ static inline int tusb_omap_use_shared_dmareq(struct tusb_omap_dma_ch *chdat)
        u32             reg = musb_readl(chdat->tbase, TUSB_DMA_EP_MAP);
 
        if (reg != 0) {
-               dev_dbg(musb->controller, "ep%i dmareq0 is busy for ep%i\n",
+               dev_dbg(chdat->musb->controller, "ep%i dmareq0 is busy for ep%i\n",
                        chdat->epnum, reg & 0xf);
                return -EAGAIN;
        }
index ba79dbf..cb2d451 100644 (file)
@@ -14,6 +14,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
+#include <linux/dma-mapping.h>
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
@@ -76,7 +77,7 @@ struct usbhsg_recip_handle {
                struct usbhsg_gpriv, mod)
 
 #define __usbhsg_for_each_uep(start, pos, g, i)        \
-       for (i = start, pos = (g)->uep;         \
+       for (i = start, pos = (g)->uep + i;     \
             i < (g)->uep_size;                 \
             i++, pos = (g)->uep + i)
 
index 2e06b90..78a2cf9 100644 (file)
@@ -151,6 +151,7 @@ static struct ftdi_sio_quirk ftdi_stmclite_quirk = {
  * /sys/bus/usb/ftdi_sio/new_id, then send patch/report!
  */
 static struct usb_device_id id_table_combined [] = {
+       { USB_DEVICE(FTDI_VID, FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_CTI_MINI_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_CTI_NANO_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) },
@@ -1171,7 +1172,7 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty,
        case FT2232H: /* FT2232H chip */
        case FT4232H: /* FT4232H chip */
        case FT232H:  /* FT232H chip */
-               if ((baud <= 12000000) & (baud >= 1200)) {
+               if ((baud <= 12000000) && (baud >= 1200)) {
                        div_value = ftdi_2232h_baud_to_divisor(baud);
                } else if (baud < 1200) {
                        div_value = ftdi_232bm_baud_to_divisor(baud);
@@ -1205,7 +1206,10 @@ static int change_speed(struct tty_struct *tty, struct usb_serial_port *port)
        urb_index_value = get_ftdi_divisor(tty, port);
        urb_value = (__u16)urb_index_value;
        urb_index = (__u16)(urb_index_value >> 16);
-       if (priv->interface) {  /* FT2232C */
+       if ((priv->chip_type == FT2232C) || (priv->chip_type == FT2232H) ||
+               (priv->chip_type == FT4232H) || (priv->chip_type == FT232H)) {
+               /* Probably the BM type needs the MSB of the encoded fractional
+                * divider also moved like for the chips above. Any infos? */
                urb_index = (__u16)((urb_index << 8) | priv->interface);
        }
 
index 19156d1..bf5227a 100644 (file)
 /* USB-Nano-485*/
 #define FTDI_CTI_NANO_PID      0xF60B
 
-
+/*
+ * ZeitControl cardsystems GmbH rfid-readers http://zeitconrol.de
+ */
+/* TagTracer MIFARE*/
+#define FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID   0xF7C0
index 60b25d8..8156561 100644 (file)
@@ -148,6 +148,10 @@ static void option_instat_callback(struct urb *urb);
 #define HUAWEI_PRODUCT_K4505                   0x1464
 #define HUAWEI_PRODUCT_K3765                   0x1465
 #define HUAWEI_PRODUCT_E14AC                   0x14AC
+#define HUAWEI_PRODUCT_K3770                   0x14C9
+#define HUAWEI_PRODUCT_K3771                   0x14CA
+#define HUAWEI_PRODUCT_K4510                   0x14CB
+#define HUAWEI_PRODUCT_K4511                   0x14CC
 #define HUAWEI_PRODUCT_ETS1220                 0x1803
 #define HUAWEI_PRODUCT_E353                    0x1506
 
@@ -547,6 +551,14 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ETS1220, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E14AC, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3770, 0xff, 0x02, 0x31) },
+       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3770, 0xff, 0x02, 0x32) },
+       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3771, 0xff, 0x02, 0x31) },
+       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3771, 0xff, 0x02, 0x32) },
+       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4510, 0xff, 0x01, 0x31) },
+       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4510, 0xff, 0x01, 0x32) },
+       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x31) },
+       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x32) },
        { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x01) },
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) },
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) },
index 54a9dab..aeccc7f 100644 (file)
@@ -45,6 +45,7 @@ static const struct usb_device_id id_table[] = {
        {USB_DEVICE(0x05c6, 0x9203)},   /* Generic Gobi Modem device */
        {USB_DEVICE(0x05c6, 0x9222)},   /* Generic Gobi Modem device */
        {USB_DEVICE(0x05c6, 0x9008)},   /* Generic Gobi QDL device */
+       {USB_DEVICE(0x05c6, 0x9009)},   /* Generic Gobi Modem device */
        {USB_DEVICE(0x05c6, 0x9201)},   /* Generic Gobi QDL device */
        {USB_DEVICE(0x05c6, 0x9221)},   /* Generic Gobi QDL device */
        {USB_DEVICE(0x05c6, 0x9231)},   /* Generic Gobi QDL device */
@@ -78,6 +79,7 @@ static const struct usb_device_id id_table[] = {
        {USB_DEVICE(0x1199, 0x9008)},   /* Sierra Wireless Gobi 2000 Modem device (VT773) */
        {USB_DEVICE(0x1199, 0x9009)},   /* Sierra Wireless Gobi 2000 Modem device (VT773) */
        {USB_DEVICE(0x1199, 0x900a)},   /* Sierra Wireless Gobi 2000 Modem device (VT773) */
+       {USB_DEVICE(0x1199, 0x9011)},   /* Sierra Wireless Gobi 2000 Modem device (MC8305) */
        {USB_DEVICE(0x16d8, 0x8001)},   /* CMDTech Gobi 2000 QDL device (VU922) */
        {USB_DEVICE(0x16d8, 0x8002)},   /* CMDTech Gobi 2000 Modem device (VU922) */
        {USB_DEVICE(0x05c6, 0x9204)},   /* Gobi 2000 QDL device */
index ccff348..3041a97 100644 (file)
@@ -1988,6 +1988,16 @@ UNUSUAL_DEV(  0x4146, 0xba01, 0x0100, 0x0100,
                "Micro Mini 1GB",
                USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ),
 
+/*
+ * Nick Bowler <nbowler@elliptictech.com>
+ * SCSI stack spams (otherwise harmless) error messages.
+ */
+UNUSUAL_DEV(  0xc251, 0x4003, 0x0100, 0x0100,
+               "Keil Software, Inc.",
+               "V2M MotherBoard",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_NOT_LOCKABLE),
+
 /* Reported by Andrew Simmons <andrew.simmons@gmail.com> */
 UNUSUAL_DEV(  0xed06, 0x4500, 0x0001, 0x0001,
                "DataStor",
index 1e54b8b..278aeaa 100644 (file)
@@ -335,6 +335,13 @@ config BACKLIGHT_PCF50633
          If you have a backlight driven by a NXP PCF50633 MFD, say Y here to
          enable its driver.
 
+config BACKLIGHT_AAT2870
+       tristate "AnalogicTech AAT2870 Backlight"
+       depends on BACKLIGHT_CLASS_DEVICE && MFD_AAT2870_CORE
+       help
+         If you have a AnalogicTech AAT2870 say Y to enable the
+         backlight driver.
+
 endif # BACKLIGHT_CLASS_DEVICE
 
 endif # BACKLIGHT_LCD_SUPPORT
index bf1dd92..fdd1fc4 100644 (file)
@@ -38,4 +38,5 @@ obj-$(CONFIG_BACKLIGHT_ADP8860)       += adp8860_bl.o
 obj-$(CONFIG_BACKLIGHT_ADP8870)        += adp8870_bl.o
 obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o
 obj-$(CONFIG_BACKLIGHT_PCF50633)       += pcf50633-backlight.o
+obj-$(CONFIG_BACKLIGHT_AAT2870) += aat2870_bl.o
 
diff --git a/drivers/video/backlight/aat2870_bl.c b/drivers/video/backlight/aat2870_bl.c
new file mode 100644 (file)
index 0000000..331f1ef
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * linux/drivers/video/backlight/aat2870_bl.c
+ *
+ * Copyright (c) 2011, NVIDIA Corporation.
+ * Author: Jin Park <jinyoungp@nvidia.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
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+#include <linux/mfd/aat2870.h>
+
+struct aat2870_bl_driver_data {
+       struct platform_device *pdev;
+       struct backlight_device *bd;
+
+       int channels;
+       int max_current;
+       int brightness; /* current brightness */
+};
+
+static inline int aat2870_brightness(struct aat2870_bl_driver_data *aat2870_bl,
+                                    int brightness)
+{
+       struct backlight_device *bd = aat2870_bl->bd;
+       int val;
+
+       val = brightness * (aat2870_bl->max_current - 1);
+       val /= bd->props.max_brightness;
+
+       return val;
+}
+
+static inline int aat2870_bl_enable(struct aat2870_bl_driver_data *aat2870_bl)
+{
+       struct aat2870_data *aat2870
+                       = dev_get_drvdata(aat2870_bl->pdev->dev.parent);
+
+       return aat2870->write(aat2870, AAT2870_BL_CH_EN,
+                             (u8)aat2870_bl->channels);
+}
+
+static inline int aat2870_bl_disable(struct aat2870_bl_driver_data *aat2870_bl)
+{
+       struct aat2870_data *aat2870
+                       = dev_get_drvdata(aat2870_bl->pdev->dev.parent);
+
+       return aat2870->write(aat2870, AAT2870_BL_CH_EN, 0x0);
+}
+
+static int aat2870_bl_get_brightness(struct backlight_device *bd)
+{
+       return bd->props.brightness;
+}
+
+static int aat2870_bl_update_status(struct backlight_device *bd)
+{
+       struct aat2870_bl_driver_data *aat2870_bl = dev_get_drvdata(&bd->dev);
+       struct aat2870_data *aat2870 =
+                       dev_get_drvdata(aat2870_bl->pdev->dev.parent);
+       int brightness = bd->props.brightness;
+       int ret;
+
+       if ((brightness < 0) || (bd->props.max_brightness < brightness)) {
+               dev_err(&bd->dev, "invalid brightness, %d\n", brightness);
+               return -EINVAL;
+       }
+
+       dev_dbg(&bd->dev, "brightness=%d, power=%d, state=%d\n",
+                bd->props.brightness, bd->props.power, bd->props.state);
+
+       if ((bd->props.power != FB_BLANK_UNBLANK) ||
+                       (bd->props.state & BL_CORE_FBBLANK) ||
+                       (bd->props.state & BL_CORE_SUSPENDED))
+               brightness = 0;
+
+       ret = aat2870->write(aat2870, AAT2870_BLM,
+                            (u8)aat2870_brightness(aat2870_bl, brightness));
+       if (ret < 0)
+               return ret;
+
+       if (brightness == 0) {
+               ret = aat2870_bl_disable(aat2870_bl);
+               if (ret < 0)
+                       return ret;
+       } else if (aat2870_bl->brightness == 0) {
+               ret = aat2870_bl_enable(aat2870_bl);
+               if (ret < 0)
+                       return ret;
+       }
+
+       aat2870_bl->brightness = brightness;
+
+       return 0;
+}
+
+static int aat2870_bl_check_fb(struct backlight_device *bd, struct fb_info *fi)
+{
+       return 1;
+}
+
+static const struct backlight_ops aat2870_bl_ops = {
+       .options = BL_CORE_SUSPENDRESUME,
+       .get_brightness = aat2870_bl_get_brightness,
+       .update_status = aat2870_bl_update_status,
+       .check_fb = aat2870_bl_check_fb,
+};
+
+static int aat2870_bl_probe(struct platform_device *pdev)
+{
+       struct aat2870_bl_platform_data *pdata = pdev->dev.platform_data;
+       struct aat2870_bl_driver_data *aat2870_bl;
+       struct backlight_device *bd;
+       struct backlight_properties props;
+       int ret = 0;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "No platform data\n");
+               ret = -ENXIO;
+               goto out;
+       }
+
+       if (pdev->id != AAT2870_ID_BL) {
+               dev_err(&pdev->dev, "Invalid device ID, %d\n", pdev->id);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       aat2870_bl = kzalloc(sizeof(struct aat2870_bl_driver_data), GFP_KERNEL);
+       if (!aat2870_bl) {
+               dev_err(&pdev->dev,
+                       "Failed to allocate memory for aat2870 backlight\n");
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       memset(&props, 0, sizeof(struct backlight_properties));
+
+       props.type = BACKLIGHT_RAW;
+       bd = backlight_device_register("aat2870-backlight", &pdev->dev,
+                                      aat2870_bl, &aat2870_bl_ops, &props);
+       if (IS_ERR(bd)) {
+               dev_err(&pdev->dev,
+                       "Failed allocate memory for backlight device\n");
+               ret = PTR_ERR(bd);
+               goto out_kfree;
+       }
+
+       aat2870_bl->pdev = pdev;
+       platform_set_drvdata(pdev, aat2870_bl);
+
+       aat2870_bl->bd = bd;
+
+       if (pdata->channels > 0)
+               aat2870_bl->channels = pdata->channels;
+       else
+               aat2870_bl->channels = AAT2870_BL_CH_ALL;
+
+       if (pdata->max_current > 0)
+               aat2870_bl->max_current = pdata->max_current;
+       else
+               aat2870_bl->max_current = AAT2870_CURRENT_27_9;
+
+       if (pdata->max_brightness > 0)
+               bd->props.max_brightness = pdata->max_brightness;
+       else
+               bd->props.max_brightness = 255;
+
+       aat2870_bl->brightness = 0;
+       bd->props.power = FB_BLANK_UNBLANK;
+       bd->props.brightness = bd->props.max_brightness;
+
+       ret = aat2870_bl_update_status(bd);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to initialize\n");
+               goto out_bl_dev_unregister;
+       }
+
+       return 0;
+
+out_bl_dev_unregister:
+       backlight_device_unregister(bd);
+out_kfree:
+       kfree(aat2870_bl);
+out:
+       return ret;
+}
+
+static int aat2870_bl_remove(struct platform_device *pdev)
+{
+       struct aat2870_bl_driver_data *aat2870_bl = platform_get_drvdata(pdev);
+       struct backlight_device *bd = aat2870_bl->bd;
+
+       bd->props.power = FB_BLANK_POWERDOWN;
+       bd->props.brightness = 0;
+       backlight_update_status(bd);
+
+       backlight_device_unregister(bd);
+       kfree(aat2870_bl);
+
+       return 0;
+}
+
+static struct platform_driver aat2870_bl_driver = {
+       .driver = {
+               .name   = "aat2870-backlight",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = aat2870_bl_probe,
+       .remove         = aat2870_bl_remove,
+};
+
+static int __init aat2870_bl_init(void)
+{
+       return platform_driver_register(&aat2870_bl_driver);
+}
+subsys_initcall(aat2870_bl_init);
+
+static void __exit aat2870_bl_exit(void)
+{
+       platform_driver_unregister(&aat2870_bl_driver);
+}
+module_exit(aat2870_bl_exit);
+
+MODULE_DESCRIPTION("AnalogicTech AAT2870 Backlight");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jin Park <jinyoungp@nvidia.com>");
index fdd5d4a..4e888ac 100644 (file)
@@ -504,14 +504,18 @@ static int taal_exit_ulps(struct omap_dss_device *dssdev)
                return 0;
 
        r = omapdss_dsi_display_enable(dssdev);
-       if (r)
-               goto err;
+       if (r) {
+               dev_err(&dssdev->dev, "failed to enable DSI\n");
+               goto err1;
+       }
 
        omapdss_dsi_vc_enable_hs(dssdev, td->channel, true);
 
        r = _taal_enable_te(dssdev, true);
-       if (r)
-               goto err;
+       if (r) {
+               dev_err(&dssdev->dev, "failed to re-enable TE");
+               goto err2;
+       }
 
        enable_irq(gpio_to_irq(panel_data->ext_te_gpio));
 
@@ -521,13 +525,15 @@ static int taal_exit_ulps(struct omap_dss_device *dssdev)
 
        return 0;
 
-err:
-       dev_err(&dssdev->dev, "exit ULPS failed");
-       r = taal_panel_reset(dssdev);
-
-       enable_irq(gpio_to_irq(panel_data->ext_te_gpio));
-       td->ulps_enabled = false;
+err2:
+       dev_err(&dssdev->dev, "failed to exit ULPS");
 
+       r = taal_panel_reset(dssdev);
+       if (!r) {
+               enable_irq(gpio_to_irq(panel_data->ext_te_gpio));
+               td->ulps_enabled = false;
+       }
+err1:
        taal_queue_ulps_work(dssdev);
 
        return r;
@@ -1241,11 +1247,8 @@ static void taal_power_off(struct omap_dss_device *dssdev)
        int r;
 
        r = taal_dcs_write_0(td, DCS_DISPLAY_OFF);
-       if (!r) {
+       if (!r)
                r = taal_sleep_in(td);
-               /* HACK: wait a bit so that the message goes through */
-               msleep(10);
-       }
 
        if (r) {
                dev_err(&dssdev->dev,
@@ -1317,8 +1320,11 @@ static void taal_disable(struct omap_dss_device *dssdev)
        dsi_bus_lock(dssdev);
 
        if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
-               taal_wake_up(dssdev);
-               taal_power_off(dssdev);
+               int r;
+
+               r = taal_wake_up(dssdev);
+               if (!r)
+                       taal_power_off(dssdev);
        }
 
        dsi_bus_unlock(dssdev);
@@ -1897,20 +1903,6 @@ err:
        mutex_unlock(&td->lock);
 }
 
-static int taal_set_update_mode(struct omap_dss_device *dssdev,
-               enum omap_dss_update_mode mode)
-{
-       if (mode != OMAP_DSS_UPDATE_MANUAL)
-               return -EINVAL;
-       return 0;
-}
-
-static enum omap_dss_update_mode taal_get_update_mode(
-               struct omap_dss_device *dssdev)
-{
-       return OMAP_DSS_UPDATE_MANUAL;
-}
-
 static struct omap_dss_driver taal_driver = {
        .probe          = taal_probe,
        .remove         = __exit_p(taal_remove),
@@ -1920,9 +1912,6 @@ static struct omap_dss_driver taal_driver = {
        .suspend        = taal_suspend,
        .resume         = taal_resume,
 
-       .set_update_mode = taal_set_update_mode,
-       .get_update_mode = taal_get_update_mode,
-
        .update         = taal_update,
        .sync           = taal_sync,
 
index 6b3e2da..0d12524 100644 (file)
@@ -117,18 +117,6 @@ config OMAP2_DSS_MIN_FCK_PER_PCK
          Max FCK is 173MHz, so this doesn't work if your PCK
          is very high.
 
-config OMAP2_DSS_SLEEP_BEFORE_RESET
-       bool "Sleep 50ms before DSS reset"
-       default y
-       help
-         For some unknown reason we may get SYNC_LOST errors from the display
-         subsystem at initialization time if we don't sleep before resetting
-         the DSS. See the source (dss.c) for more comments.
-
-         However, 50ms is quite long time to sleep, and with some
-         configurations the SYNC_LOST may never happen, so the sleep can
-         be disabled here.
-
 config OMAP2_DSS_SLEEP_AFTER_VENC_RESET
        bool "Sleep 20ms after VENC reset"
        default y
index 3da4267..76821fe 100644 (file)
@@ -183,8 +183,11 @@ static int omap_dss_probe(struct platform_device *pdev)
                goto err_dss;
        }
 
-       /* keep clocks enabled to prevent context saves/restores during init */
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
+       r = dispc_init_platform_driver();
+       if (r) {
+               DSSERR("Failed to initialize dispc platform driver\n");
+               goto err_dispc;
+       }
 
        r = rfbi_init_platform_driver();
        if (r) {
@@ -192,12 +195,6 @@ static int omap_dss_probe(struct platform_device *pdev)
                goto err_rfbi;
        }
 
-       r = dispc_init_platform_driver();
-       if (r) {
-               DSSERR("Failed to initialize dispc platform driver\n");
-               goto err_dispc;
-       }
-
        r = venc_init_platform_driver();
        if (r) {
                DSSERR("Failed to initialize venc platform driver\n");
@@ -238,8 +235,6 @@ static int omap_dss_probe(struct platform_device *pdev)
                        pdata->default_device = dssdev;
        }
 
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
-
        return 0;
 
 err_register:
@@ -268,11 +263,11 @@ static int omap_dss_remove(struct platform_device *pdev)
 
        dss_uninitialize_debugfs();
 
+       hdmi_uninit_platform_driver();
+       dsi_uninit_platform_driver();
        venc_uninit_platform_driver();
-       dispc_uninit_platform_driver();
        rfbi_uninit_platform_driver();
-       dsi_uninit_platform_driver();
-       hdmi_uninit_platform_driver();
+       dispc_uninit_platform_driver();
        dss_uninit_platform_driver();
 
        dss_uninit_overlays(pdev);
index 7a9a2e7..0f3961a 100644 (file)
@@ -33,6 +33,8 @@
 #include <linux/workqueue.h>
 #include <linux/hardirq.h>
 #include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 
 #include <plat/sram.h>
 #include <plat/clock.h>
@@ -77,6 +79,12 @@ struct dispc_v_coef {
        s8 vc00;
 };
 
+enum omap_burst_size {
+       BURST_SIZE_X2 = 0,
+       BURST_SIZE_X4 = 1,
+       BURST_SIZE_X8 = 2,
+};
+
 #define REG_GET(idx, start, end) \
        FLD_GET(dispc_read_reg(idx), start, end)
 
@@ -92,7 +100,11 @@ struct dispc_irq_stats {
 static struct {
        struct platform_device *pdev;
        void __iomem    *base;
+
+       int             ctx_loss_cnt;
+
        int irq;
+       struct clk *dss_clk;
 
        u32     fifo_size[3];
 
@@ -102,6 +114,7 @@ static struct {
        u32 error_irqs;
        struct work_struct error_work;
 
+       bool            ctx_valid;
        u32             ctx[DISPC_SZ_REGS / sizeof(u32)];
 
 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
@@ -134,18 +147,34 @@ static inline u32 dispc_read_reg(const u16 idx)
        return __raw_readl(dispc.base + idx);
 }
 
+static int dispc_get_ctx_loss_count(void)
+{
+       struct device *dev = &dispc.pdev->dev;
+       struct omap_display_platform_data *pdata = dev->platform_data;
+       struct omap_dss_board_info *board_data = pdata->board_data;
+       int cnt;
+
+       if (!board_data->get_context_loss_count)
+               return -ENOENT;
+
+       cnt = board_data->get_context_loss_count(dev);
+
+       WARN_ONCE(cnt < 0, "get_context_loss_count failed: %d\n", cnt);
+
+       return cnt;
+}
+
 #define SR(reg) \
        dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
 #define RR(reg) \
        dispc_write_reg(DISPC_##reg, dispc.ctx[DISPC_##reg / sizeof(u32)])
 
-void dispc_save_context(void)
+static void dispc_save_context(void)
 {
        int i;
-       if (cpu_is_omap24xx())
-               return;
 
-       SR(SYSCONFIG);
+       DSSDBG("dispc_save_context\n");
+
        SR(IRQENABLE);
        SR(CONTROL);
        SR(CONFIG);
@@ -158,7 +187,8 @@ void dispc_save_context(void)
        SR(TIMING_V(OMAP_DSS_CHANNEL_LCD));
        SR(POL_FREQ(OMAP_DSS_CHANNEL_LCD));
        SR(DIVISORo(OMAP_DSS_CHANNEL_LCD));
-       SR(GLOBAL_ALPHA);
+       if (dss_has_feature(FEAT_GLOBAL_ALPHA))
+               SR(GLOBAL_ALPHA);
        SR(SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT));
        SR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD));
        if (dss_has_feature(FEAT_MGR_LCD2)) {
@@ -188,20 +218,25 @@ void dispc_save_context(void)
        SR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD));
        SR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD));
 
-       SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD));
-       SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD));
-       SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD));
+       if (dss_has_feature(FEAT_CPR)) {
+               SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD));
+               SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD));
+               SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD));
+       }
        if (dss_has_feature(FEAT_MGR_LCD2)) {
-               SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2));
-               SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2));
-               SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2));
+               if (dss_has_feature(FEAT_CPR)) {
+                       SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2));
+                       SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2));
+                       SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2));
+               }
 
                SR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2));
                SR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2));
                SR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2));
        }
 
-       SR(OVL_PRELOAD(OMAP_DSS_GFX));
+       if (dss_has_feature(FEAT_PRELOAD))
+               SR(OVL_PRELOAD(OMAP_DSS_GFX));
 
        /* VID1 */
        SR(OVL_BA0(OMAP_DSS_VIDEO1));
@@ -226,8 +261,10 @@ void dispc_save_context(void)
        for (i = 0; i < 5; i++)
                SR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i));
 
-       for (i = 0; i < 8; i++)
-               SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i));
+       if (dss_has_feature(FEAT_FIR_COEF_V)) {
+               for (i = 0; i < 8; i++)
+                       SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i));
+       }
 
        if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
                SR(OVL_BA0_UV(OMAP_DSS_VIDEO1));
@@ -248,7 +285,8 @@ void dispc_save_context(void)
        if (dss_has_feature(FEAT_ATTR2))
                SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1));
 
-       SR(OVL_PRELOAD(OMAP_DSS_VIDEO1));
+       if (dss_has_feature(FEAT_PRELOAD))
+               SR(OVL_PRELOAD(OMAP_DSS_VIDEO1));
 
        /* VID2 */
        SR(OVL_BA0(OMAP_DSS_VIDEO2));
@@ -273,8 +311,10 @@ void dispc_save_context(void)
        for (i = 0; i < 5; i++)
                SR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i));
 
-       for (i = 0; i < 8; i++)
-               SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i));
+       if (dss_has_feature(FEAT_FIR_COEF_V)) {
+               for (i = 0; i < 8; i++)
+                       SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i));
+       }
 
        if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
                SR(OVL_BA0_UV(OMAP_DSS_VIDEO2));
@@ -295,16 +335,35 @@ void dispc_save_context(void)
        if (dss_has_feature(FEAT_ATTR2))
                SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2));
 
-       SR(OVL_PRELOAD(OMAP_DSS_VIDEO2));
+       if (dss_has_feature(FEAT_PRELOAD))
+               SR(OVL_PRELOAD(OMAP_DSS_VIDEO2));
 
        if (dss_has_feature(FEAT_CORE_CLK_DIV))
                SR(DIVISOR);
+
+       dispc.ctx_loss_cnt = dispc_get_ctx_loss_count();
+       dispc.ctx_valid = true;
+
+       DSSDBG("context saved, ctx_loss_count %d\n", dispc.ctx_loss_cnt);
 }
 
-void dispc_restore_context(void)
+static void dispc_restore_context(void)
 {
-       int i;
-       RR(SYSCONFIG);
+       int i, ctx;
+
+       DSSDBG("dispc_restore_context\n");
+
+       if (!dispc.ctx_valid)
+               return;
+
+       ctx = dispc_get_ctx_loss_count();
+
+       if (ctx >= 0 && ctx == dispc.ctx_loss_cnt)
+               return;
+
+       DSSDBG("ctx_loss_count: saved %d, current %d\n",
+                       dispc.ctx_loss_cnt, ctx);
+
        /*RR(IRQENABLE);*/
        /*RR(CONTROL);*/
        RR(CONFIG);
@@ -317,7 +376,8 @@ void dispc_restore_context(void)
        RR(TIMING_V(OMAP_DSS_CHANNEL_LCD));
        RR(POL_FREQ(OMAP_DSS_CHANNEL_LCD));
        RR(DIVISORo(OMAP_DSS_CHANNEL_LCD));
-       RR(GLOBAL_ALPHA);
+       if (dss_has_feature(FEAT_GLOBAL_ALPHA))
+               RR(GLOBAL_ALPHA);
        RR(SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT));
        RR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD));
        if (dss_has_feature(FEAT_MGR_LCD2)) {
@@ -347,20 +407,25 @@ void dispc_restore_context(void)
        RR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD));
        RR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD));
 
-       RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD));
-       RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD));
-       RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD));
+       if (dss_has_feature(FEAT_CPR)) {
+               RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD));
+               RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD));
+               RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD));
+       }
        if (dss_has_feature(FEAT_MGR_LCD2)) {
                RR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2));
                RR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2));
                RR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2));
 
-               RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2));
-               RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2));
-               RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2));
+               if (dss_has_feature(FEAT_CPR)) {
+                       RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2));
+                       RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2));
+                       RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2));
+               }
        }
 
-       RR(OVL_PRELOAD(OMAP_DSS_GFX));
+       if (dss_has_feature(FEAT_PRELOAD))
+               RR(OVL_PRELOAD(OMAP_DSS_GFX));
 
        /* VID1 */
        RR(OVL_BA0(OMAP_DSS_VIDEO1));
@@ -385,8 +450,10 @@ void dispc_restore_context(void)
        for (i = 0; i < 5; i++)
                RR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i));
 
-       for (i = 0; i < 8; i++)
-               RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i));
+       if (dss_has_feature(FEAT_FIR_COEF_V)) {
+               for (i = 0; i < 8; i++)
+                       RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i));
+       }
 
        if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
                RR(OVL_BA0_UV(OMAP_DSS_VIDEO1));
@@ -407,7 +474,8 @@ void dispc_restore_context(void)
        if (dss_has_feature(FEAT_ATTR2))
                RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1));
 
-       RR(OVL_PRELOAD(OMAP_DSS_VIDEO1));
+       if (dss_has_feature(FEAT_PRELOAD))
+               RR(OVL_PRELOAD(OMAP_DSS_VIDEO1));
 
        /* VID2 */
        RR(OVL_BA0(OMAP_DSS_VIDEO2));
@@ -432,8 +500,10 @@ void dispc_restore_context(void)
        for (i = 0; i < 5; i++)
                RR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i));
 
-       for (i = 0; i < 8; i++)
-               RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i));
+       if (dss_has_feature(FEAT_FIR_COEF_V)) {
+               for (i = 0; i < 8; i++)
+                       RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i));
+       }
 
        if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
                RR(OVL_BA0_UV(OMAP_DSS_VIDEO2));
@@ -454,7 +524,8 @@ void dispc_restore_context(void)
        if (dss_has_feature(FEAT_ATTR2))
                RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2));
 
-       RR(OVL_PRELOAD(OMAP_DSS_VIDEO2));
+       if (dss_has_feature(FEAT_PRELOAD))
+               RR(OVL_PRELOAD(OMAP_DSS_VIDEO2));
 
        if (dss_has_feature(FEAT_CORE_CLK_DIV))
                RR(DIVISOR);
@@ -471,19 +542,35 @@ void dispc_restore_context(void)
         * the context is fully restored
         */
        RR(IRQENABLE);
+
+       DSSDBG("context restored\n");
 }
 
 #undef SR
 #undef RR
 
-static inline void enable_clocks(bool enable)
+int dispc_runtime_get(void)
 {
-       if (enable)
-               dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
-       else
-               dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
+       int r;
+
+       DSSDBG("dispc_runtime_get\n");
+
+       r = pm_runtime_get_sync(&dispc.pdev->dev);
+       WARN_ON(r < 0);
+       return r < 0 ? r : 0;
 }
 
+void dispc_runtime_put(void)
+{
+       int r;
+
+       DSSDBG("dispc_runtime_put\n");
+
+       r = pm_runtime_put(&dispc.pdev->dev);
+       WARN_ON(r < 0);
+}
+
+
 bool dispc_go_busy(enum omap_channel channel)
 {
        int bit;
@@ -505,8 +592,6 @@ void dispc_go(enum omap_channel channel)
        int bit;
        bool enable_bit, go_bit;
 
-       enable_clocks(1);
-
        if (channel == OMAP_DSS_CHANNEL_LCD ||
                        channel == OMAP_DSS_CHANNEL_LCD2)
                bit = 0; /* LCDENABLE */
@@ -520,7 +605,7 @@ void dispc_go(enum omap_channel channel)
                enable_bit = REG_GET(DISPC_CONTROL, bit, bit) == 1;
 
        if (!enable_bit)
-               goto end;
+               return;
 
        if (channel == OMAP_DSS_CHANNEL_LCD ||
                        channel == OMAP_DSS_CHANNEL_LCD2)
@@ -535,7 +620,7 @@ void dispc_go(enum omap_channel channel)
 
        if (go_bit) {
                DSSERR("GO bit not down for channel %d\n", channel);
-               goto end;
+               return;
        }
 
        DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" :
@@ -545,8 +630,6 @@ void dispc_go(enum omap_channel channel)
                REG_FLD_MOD(DISPC_CONTROL2, 1, bit, bit);
        else
                REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit);
-end:
-       enable_clocks(0);
 }
 
 static void _dispc_write_firh_reg(enum omap_plane plane, int reg, u32 value)
@@ -920,7 +1003,7 @@ static void _dispc_set_color_mode(enum omap_plane plane,
        REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1);
 }
 
-static void _dispc_set_channel_out(enum omap_plane plane,
+void dispc_set_channel_out(enum omap_plane plane,
                enum omap_channel channel)
 {
        int shift;
@@ -967,13 +1050,10 @@ static void _dispc_set_channel_out(enum omap_plane plane,
        dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
 }
 
-void dispc_set_burst_size(enum omap_plane plane,
+static void dispc_set_burst_size(enum omap_plane plane,
                enum omap_burst_size burst_size)
 {
        int shift;
-       u32 val;
-
-       enable_clocks(1);
 
        switch (plane) {
        case OMAP_DSS_GFX:
@@ -988,11 +1068,24 @@ void dispc_set_burst_size(enum omap_plane plane,
                return;
        }
 
-       val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
-       val = FLD_MOD(val, burst_size, shift+1, shift);
-       dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
+       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), burst_size, shift + 1, shift);
+}
 
-       enable_clocks(0);
+static void dispc_configure_burst_sizes(void)
+{
+       int i;
+       const int burst_size = BURST_SIZE_X8;
+
+       /* Configure burst size always to maximum size */
+       for (i = 0; i < omap_dss_get_num_overlays(); ++i)
+               dispc_set_burst_size(i, burst_size);
+}
+
+u32 dispc_get_burst_size(enum omap_plane plane)
+{
+       unsigned unit = dss_feat_get_burst_size_unit();
+       /* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */
+       return unit * 8;
 }
 
 void dispc_enable_gamma_table(bool enable)
@@ -1009,6 +1102,40 @@ void dispc_enable_gamma_table(bool enable)
        REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9);
 }
 
+void dispc_enable_cpr(enum omap_channel channel, bool enable)
+{
+       u16 reg;
+
+       if (channel == OMAP_DSS_CHANNEL_LCD)
+               reg = DISPC_CONFIG;
+       else if (channel == OMAP_DSS_CHANNEL_LCD2)
+               reg = DISPC_CONFIG2;
+       else
+               return;
+
+       REG_FLD_MOD(reg, enable, 15, 15);
+}
+
+void dispc_set_cpr_coef(enum omap_channel channel,
+               struct omap_dss_cpr_coefs *coefs)
+{
+       u32 coef_r, coef_g, coef_b;
+
+       if (channel != OMAP_DSS_CHANNEL_LCD && channel != OMAP_DSS_CHANNEL_LCD2)
+               return;
+
+       coef_r = FLD_VAL(coefs->rr, 31, 22) | FLD_VAL(coefs->rg, 20, 11) |
+               FLD_VAL(coefs->rb, 9, 0);
+       coef_g = FLD_VAL(coefs->gr, 31, 22) | FLD_VAL(coefs->gg, 20, 11) |
+               FLD_VAL(coefs->gb, 9, 0);
+       coef_b = FLD_VAL(coefs->br, 31, 22) | FLD_VAL(coefs->bg, 20, 11) |
+               FLD_VAL(coefs->bb, 9, 0);
+
+       dispc_write_reg(DISPC_CPR_COEF_R(channel), coef_r);
+       dispc_write_reg(DISPC_CPR_COEF_G(channel), coef_g);
+       dispc_write_reg(DISPC_CPR_COEF_B(channel), coef_b);
+}
+
 static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable)
 {
        u32 val;
@@ -1029,9 +1156,7 @@ void dispc_enable_replication(enum omap_plane plane, bool enable)
        else
                bit = 10;
 
-       enable_clocks(1);
        REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit);
-       enable_clocks(0);
 }
 
 void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height)
@@ -1039,9 +1164,7 @@ void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height)
        u32 val;
        BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
        val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
-       enable_clocks(1);
        dispc_write_reg(DISPC_SIZE_MGR(channel), val);
-       enable_clocks(0);
 }
 
 void dispc_set_digit_size(u16 width, u16 height)
@@ -1049,9 +1172,7 @@ void dispc_set_digit_size(u16 width, u16 height)
        u32 val;
        BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
        val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
-       enable_clocks(1);
        dispc_write_reg(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT), val);
-       enable_clocks(0);
 }
 
 static void dispc_read_plane_fifo_sizes(void)
@@ -1059,18 +1180,17 @@ static void dispc_read_plane_fifo_sizes(void)
        u32 size;
        int plane;
        u8 start, end;
+       u32 unit;
 
-       enable_clocks(1);
+       unit = dss_feat_get_buffer_size_unit();
 
        dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end);
 
        for (plane = 0; plane < ARRAY_SIZE(dispc.fifo_size); ++plane) {
-               size = FLD_GET(dispc_read_reg(DISPC_OVL_FIFO_SIZE_STATUS(plane)),
-                       start, end);
+               size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(plane), start, end);
+               size *= unit;
                dispc.fifo_size[plane] = size;
        }
-
-       enable_clocks(0);
 }
 
 u32 dispc_get_plane_fifo_size(enum omap_plane plane)
@@ -1078,15 +1198,22 @@ u32 dispc_get_plane_fifo_size(enum omap_plane plane)
        return dispc.fifo_size[plane];
 }
 
-void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high)
+void dispc_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high)
 {
        u8 hi_start, hi_end, lo_start, lo_end;
+       u32 unit;
+
+       unit = dss_feat_get_buffer_size_unit();
+
+       WARN_ON(low % unit != 0);
+       WARN_ON(high % unit != 0);
+
+       low /= unit;
+       high /= unit;
 
        dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end);
        dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end);
 
-       enable_clocks(1);
-
        DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n",
                        plane,
                        REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane),
@@ -1098,18 +1225,12 @@ void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high)
        dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane),
                        FLD_VAL(high, hi_start, hi_end) |
                        FLD_VAL(low, lo_start, lo_end));
-
-       enable_clocks(0);
 }
 
 void dispc_enable_fifomerge(bool enable)
 {
-       enable_clocks(1);
-
        DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled");
        REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14);
-
-       enable_clocks(0);
 }
 
 static void _dispc_set_fir(enum omap_plane plane,
@@ -1729,14 +1850,7 @@ static unsigned long calc_fclk(enum omap_channel channel, u16 width,
        return dispc_pclk_rate(channel) * vf * hf;
 }
 
-void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel_out)
-{
-       enable_clocks(1);
-       _dispc_set_channel_out(plane, channel_out);
-       enable_clocks(0);
-}
-
-static int _dispc_setup_plane(enum omap_plane plane,
+int dispc_setup_plane(enum omap_plane plane,
                u32 paddr, u16 screen_width,
                u16 pos_x, u16 pos_y,
                u16 width, u16 height,
@@ -1744,7 +1858,7 @@ static int _dispc_setup_plane(enum omap_plane plane,
                enum omap_color_mode color_mode,
                bool ilace,
                enum omap_dss_rotation_type rotation_type,
-               u8 rotation, int mirror,
+               u8 rotation, bool mirror,
                u8 global_alpha, u8 pre_mult_alpha,
                enum omap_channel channel, u32 puv_addr)
 {
@@ -1758,6 +1872,14 @@ static int _dispc_setup_plane(enum omap_plane plane,
        u16 frame_height = height;
        unsigned int field_offset = 0;
 
+       DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d,%d, %dx%d -> "
+              "%dx%d, ilace %d, cmode %x, rot %d, mir %d chan %d\n",
+              plane, paddr, screen_width, pos_x, pos_y,
+              width, height,
+              out_width, out_height,
+              ilace, color_mode,
+              rotation, mirror, channel);
+
        if (paddr == 0)
                return -EINVAL;
 
@@ -1903,9 +2025,13 @@ static int _dispc_setup_plane(enum omap_plane plane,
        return 0;
 }
 
-static void _dispc_enable_plane(enum omap_plane plane, bool enable)
+int dispc_enable_plane(enum omap_plane plane, bool enable)
 {
+       DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
+
        REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0);
+
+       return 0;
 }
 
 static void dispc_disable_isr(void *data, u32 mask)
@@ -1929,8 +2055,6 @@ static void dispc_enable_lcd_out(enum omap_channel channel, bool enable)
        int r;
        u32 irq;
 
-       enable_clocks(1);
-
        /* When we disable LCD output, we need to wait until frame is done.
         * Otherwise the DSS is still working, and turning off the clocks
         * prevents DSS from going to OFF mode */
@@ -1964,8 +2088,6 @@ static void dispc_enable_lcd_out(enum omap_channel channel, bool enable)
                if (r)
                        DSSERR("failed to unregister FRAMEDONE isr\n");
        }
-
-       enable_clocks(0);
 }
 
 static void _enable_digit_out(bool enable)
@@ -1978,12 +2100,8 @@ static void dispc_enable_digit_out(bool enable)
        struct completion frame_done_completion;
        int r;
 
-       enable_clocks(1);
-
-       if (REG_GET(DISPC_CONTROL, 1, 1) == enable) {
-               enable_clocks(0);
+       if (REG_GET(DISPC_CONTROL, 1, 1) == enable)
                return;
-       }
 
        if (enable) {
                unsigned long flags;
@@ -2035,8 +2153,6 @@ static void dispc_enable_digit_out(bool enable)
                _omap_dispc_set_irqs();
                spin_unlock_irqrestore(&dispc.irq_lock, flags);
        }
-
-       enable_clocks(0);
 }
 
 bool dispc_is_channel_enabled(enum omap_channel channel)
@@ -2067,9 +2183,7 @@ void dispc_lcd_enable_signal_polarity(bool act_high)
        if (!dss_has_feature(FEAT_LCDENABLEPOL))
                return;
 
-       enable_clocks(1);
        REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29);
-       enable_clocks(0);
 }
 
 void dispc_lcd_enable_signal(bool enable)
@@ -2077,9 +2191,7 @@ void dispc_lcd_enable_signal(bool enable)
        if (!dss_has_feature(FEAT_LCDENABLESIGNAL))
                return;
 
-       enable_clocks(1);
        REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28);
-       enable_clocks(0);
 }
 
 void dispc_pck_free_enable(bool enable)
@@ -2087,19 +2199,15 @@ void dispc_pck_free_enable(bool enable)
        if (!dss_has_feature(FEAT_PCKFREEENABLE))
                return;
 
-       enable_clocks(1);
        REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27);
-       enable_clocks(0);
 }
 
 void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable)
 {
-       enable_clocks(1);
        if (channel == OMAP_DSS_CHANNEL_LCD2)
                REG_FLD_MOD(DISPC_CONFIG2, enable ? 1 : 0, 16, 16);
        else
                REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16);
-       enable_clocks(0);
 }
 
 
@@ -2122,27 +2230,21 @@ void dispc_set_lcd_display_type(enum omap_channel channel,
                return;
        }
 
-       enable_clocks(1);
        if (channel == OMAP_DSS_CHANNEL_LCD2)
                REG_FLD_MOD(DISPC_CONTROL2, mode, 3, 3);
        else
                REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3);
-       enable_clocks(0);
 }
 
 void dispc_set_loadmode(enum omap_dss_load_mode mode)
 {
-       enable_clocks(1);
        REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1);
-       enable_clocks(0);
 }
 
 
 void dispc_set_default_color(enum omap_channel channel, u32 color)
 {
-       enable_clocks(1);
        dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color);
-       enable_clocks(0);
 }
 
 u32 dispc_get_default_color(enum omap_channel channel)
@@ -2153,9 +2255,7 @@ u32 dispc_get_default_color(enum omap_channel channel)
                channel != OMAP_DSS_CHANNEL_LCD &&
                channel != OMAP_DSS_CHANNEL_LCD2);
 
-       enable_clocks(1);
        l = dispc_read_reg(DISPC_DEFAULT_COLOR(channel));
-       enable_clocks(0);
 
        return l;
 }
@@ -2164,7 +2264,6 @@ void dispc_set_trans_key(enum omap_channel ch,
                enum omap_dss_trans_key_type type,
                u32 trans_key)
 {
-       enable_clocks(1);
        if (ch == OMAP_DSS_CHANNEL_LCD)
                REG_FLD_MOD(DISPC_CONFIG, type, 11, 11);
        else if (ch == OMAP_DSS_CHANNEL_DIGIT)
@@ -2173,14 +2272,12 @@ void dispc_set_trans_key(enum omap_channel ch,
                REG_FLD_MOD(DISPC_CONFIG2, type, 11, 11);
 
        dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key);
-       enable_clocks(0);
 }
 
 void dispc_get_trans_key(enum omap_channel ch,
                enum omap_dss_trans_key_type *type,
                u32 *trans_key)
 {
-       enable_clocks(1);
        if (type) {
                if (ch == OMAP_DSS_CHANNEL_LCD)
                        *type = REG_GET(DISPC_CONFIG, 11, 11);
@@ -2194,33 +2291,28 @@ void dispc_get_trans_key(enum omap_channel ch,
 
        if (trans_key)
                *trans_key = dispc_read_reg(DISPC_TRANS_COLOR(ch));
-       enable_clocks(0);
 }
 
 void dispc_enable_trans_key(enum omap_channel ch, bool enable)
 {
-       enable_clocks(1);
        if (ch == OMAP_DSS_CHANNEL_LCD)
                REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10);
        else if (ch == OMAP_DSS_CHANNEL_DIGIT)
                REG_FLD_MOD(DISPC_CONFIG, enable, 12, 12);
        else /* OMAP_DSS_CHANNEL_LCD2 */
                REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10);
-       enable_clocks(0);
 }
 void dispc_enable_alpha_blending(enum omap_channel ch, bool enable)
 {
        if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
                return;
 
-       enable_clocks(1);
        if (ch == OMAP_DSS_CHANNEL_LCD)
                REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18);
        else if (ch == OMAP_DSS_CHANNEL_DIGIT)
                REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
        else /* OMAP_DSS_CHANNEL_LCD2 */
                REG_FLD_MOD(DISPC_CONFIG2, enable, 18, 18);
-       enable_clocks(0);
 }
 bool dispc_alpha_blending_enabled(enum omap_channel ch)
 {
@@ -2229,7 +2321,6 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch)
        if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
                return false;
 
-       enable_clocks(1);
        if (ch == OMAP_DSS_CHANNEL_LCD)
                enabled = REG_GET(DISPC_CONFIG, 18, 18);
        else if (ch == OMAP_DSS_CHANNEL_DIGIT)
@@ -2238,7 +2329,6 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch)
                enabled = REG_GET(DISPC_CONFIG2, 18, 18);
        else
                BUG();
-       enable_clocks(0);
 
        return enabled;
 }
@@ -2248,7 +2338,6 @@ bool dispc_trans_key_enabled(enum omap_channel ch)
 {
        bool enabled;
 
-       enable_clocks(1);
        if (ch == OMAP_DSS_CHANNEL_LCD)
                enabled = REG_GET(DISPC_CONFIG, 10, 10);
        else if (ch == OMAP_DSS_CHANNEL_DIGIT)
@@ -2257,7 +2346,6 @@ bool dispc_trans_key_enabled(enum omap_channel ch)
                enabled = REG_GET(DISPC_CONFIG2, 10, 10);
        else
                BUG();
-       enable_clocks(0);
 
        return enabled;
 }
@@ -2285,12 +2373,10 @@ void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines)
                return;
        }
 
-       enable_clocks(1);
        if (channel == OMAP_DSS_CHANNEL_LCD2)
                REG_FLD_MOD(DISPC_CONTROL2, code, 9, 8);
        else
                REG_FLD_MOD(DISPC_CONTROL, code, 9, 8);
-       enable_clocks(0);
 }
 
 void dispc_set_parallel_interface_mode(enum omap_channel channel,
@@ -2322,8 +2408,6 @@ void dispc_set_parallel_interface_mode(enum omap_channel channel,
                return;
        }
 
-       enable_clocks(1);
-
        if (channel == OMAP_DSS_CHANNEL_LCD2) {
                l = dispc_read_reg(DISPC_CONTROL2);
                l = FLD_MOD(l, stallmode, 11, 11);
@@ -2335,8 +2419,6 @@ void dispc_set_parallel_interface_mode(enum omap_channel channel,
                l = FLD_MOD(l, gpout1, 16, 16);
                dispc_write_reg(DISPC_CONTROL, l);
        }
-
-       enable_clocks(0);
 }
 
 static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
@@ -2389,10 +2471,8 @@ static void _dispc_set_lcd_timings(enum omap_channel channel, int hsw,
                        FLD_VAL(vbp, 31, 20);
        }
 
-       enable_clocks(1);
        dispc_write_reg(DISPC_TIMING_H(channel), timing_h);
        dispc_write_reg(DISPC_TIMING_V(channel), timing_v);
-       enable_clocks(0);
 }
 
 /* change name to mode? */
@@ -2435,10 +2515,8 @@ static void dispc_set_lcd_divisor(enum omap_channel channel, u16 lck_div,
        BUG_ON(lck_div < 1);
        BUG_ON(pck_div < 2);
 
-       enable_clocks(1);
        dispc_write_reg(DISPC_DIVISORo(channel),
                        FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
-       enable_clocks(0);
 }
 
 static void dispc_get_lcd_divisor(enum omap_channel channel, int *lck_div,
@@ -2457,7 +2535,7 @@ unsigned long dispc_fclk_rate(void)
 
        switch (dss_get_dispc_clk_source()) {
        case OMAP_DSS_CLK_SRC_FCK:
-               r = dss_clk_get_rate(DSS_CLK_FCK);
+               r = clk_get_rate(dispc.dss_clk);
                break;
        case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
                dsidev = dsi_get_dsidev_from_id(0);
@@ -2487,7 +2565,7 @@ unsigned long dispc_lclk_rate(enum omap_channel channel)
 
        switch (dss_get_lcd_clk_source(channel)) {
        case OMAP_DSS_CLK_SRC_FCK:
-               r = dss_clk_get_rate(DSS_CLK_FCK);
+               r = clk_get_rate(dispc.dss_clk);
                break;
        case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
                dsidev = dsi_get_dsidev_from_id(0);
@@ -2526,7 +2604,8 @@ void dispc_dump_clocks(struct seq_file *s)
        enum omap_dss_clk_source dispc_clk_src = dss_get_dispc_clk_source();
        enum omap_dss_clk_source lcd_clk_src;
 
-       enable_clocks(1);
+       if (dispc_runtime_get())
+               return;
 
        seq_printf(s, "- DISPC -\n");
 
@@ -2574,7 +2653,8 @@ void dispc_dump_clocks(struct seq_file *s)
                seq_printf(s, "pck\t\t%-16lupck div\t%u\n",
                                dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD2), pcd);
        }
-       enable_clocks(0);
+
+       dispc_runtime_put();
 }
 
 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
@@ -2629,7 +2709,8 @@ void dispc_dump_regs(struct seq_file *s)
 {
 #define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r))
 
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
+       if (dispc_runtime_get())
+               return;
 
        DUMPREG(DISPC_REVISION);
        DUMPREG(DISPC_SYSCONFIG);
@@ -2649,7 +2730,8 @@ void dispc_dump_regs(struct seq_file *s)
        DUMPREG(DISPC_TIMING_V(OMAP_DSS_CHANNEL_LCD));
        DUMPREG(DISPC_POL_FREQ(OMAP_DSS_CHANNEL_LCD));
        DUMPREG(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD));
-       DUMPREG(DISPC_GLOBAL_ALPHA);
+       if (dss_has_feature(FEAT_GLOBAL_ALPHA))
+               DUMPREG(DISPC_GLOBAL_ALPHA);
        DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT));
        DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_LCD));
        if (dss_has_feature(FEAT_MGR_LCD2)) {
@@ -2680,20 +2762,25 @@ void dispc_dump_regs(struct seq_file *s)
        DUMPREG(DISPC_DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD));
        DUMPREG(DISPC_DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD));
 
-       DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD));
-       DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD));
-       DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD));
+       if (dss_has_feature(FEAT_CPR)) {
+               DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD));
+               DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD));
+               DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD));
+       }
        if (dss_has_feature(FEAT_MGR_LCD2)) {
                DUMPREG(DISPC_DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2));
                DUMPREG(DISPC_DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2));
                DUMPREG(DISPC_DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2));
 
-               DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2));
-               DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2));
-               DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2));
+               if (dss_has_feature(FEAT_CPR)) {
+                       DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2));
+                       DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2));
+                       DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2));
+               }
        }
 
-       DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_GFX));
+       if (dss_has_feature(FEAT_PRELOAD))
+               DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_GFX));
 
        DUMPREG(DISPC_OVL_BA0(OMAP_DSS_VIDEO1));
        DUMPREG(DISPC_OVL_BA1(OMAP_DSS_VIDEO1));
@@ -2744,14 +2831,16 @@ void dispc_dump_regs(struct seq_file *s)
        DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 2));
        DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 3));
        DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 4));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 0));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 1));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 2));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 3));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 4));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 5));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 6));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 7));
+       if (dss_has_feature(FEAT_FIR_COEF_V)) {
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 0));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 1));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 2));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 3));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 4));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 5));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 6));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 7));
+       }
 
        if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
                DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO1));
@@ -2812,14 +2901,17 @@ void dispc_dump_regs(struct seq_file *s)
        DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 2));
        DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 3));
        DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 4));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 0));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 1));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 2));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 3));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 4));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 5));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 6));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 7));
+
+       if (dss_has_feature(FEAT_FIR_COEF_V)) {
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 0));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 1));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 2));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 3));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 4));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 5));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 6));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 7));
+       }
 
        if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
                DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO2));
@@ -2858,10 +2950,12 @@ void dispc_dump_regs(struct seq_file *s)
        if (dss_has_feature(FEAT_ATTR2))
                DUMPREG(DISPC_OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2));
 
-       DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO1));
-       DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO2));
+       if (dss_has_feature(FEAT_PRELOAD)) {
+               DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO1));
+               DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO2));
+       }
 
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
+       dispc_runtime_put();
 #undef DUMPREG
 }
 
@@ -2882,9 +2976,7 @@ static void _dispc_set_pol_freq(enum omap_channel channel, bool onoff, bool rf,
        l |= FLD_VAL(acbi, 11, 8);
        l |= FLD_VAL(acb, 7, 0);
 
-       enable_clocks(1);
        dispc_write_reg(DISPC_POL_FREQ(channel), l);
-       enable_clocks(0);
 }
 
 void dispc_set_pol_freq(enum omap_channel channel,
@@ -3005,15 +3097,11 @@ static void _omap_dispc_set_irqs(void)
                mask |= isr_data->mask;
        }
 
-       enable_clocks(1);
-
        old_mask = dispc_read_reg(DISPC_IRQENABLE);
        /* clear the irqstatus for newly enabled irqs */
        dispc_write_reg(DISPC_IRQSTATUS, (mask ^ old_mask) & mask);
 
        dispc_write_reg(DISPC_IRQENABLE, mask);
-
-       enable_clocks(0);
 }
 
 int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
@@ -3522,13 +3610,6 @@ static void _omap_dispc_initial_config(void)
 {
        u32 l;
 
-       l = dispc_read_reg(DISPC_SYSCONFIG);
-       l = FLD_MOD(l, 2, 13, 12);      /* MIDLEMODE: smart standby */
-       l = FLD_MOD(l, 2, 4, 3);        /* SIDLEMODE: smart idle */
-       l = FLD_MOD(l, 1, 2, 2);        /* ENWAKEUP */
-       l = FLD_MOD(l, 1, 0, 0);        /* AUTOIDLE */
-       dispc_write_reg(DISPC_SYSCONFIG, l);
-
        /* Exclusively enable DISPC_CORE_CLK and set divider to 1 */
        if (dss_has_feature(FEAT_CORE_CLK_DIV)) {
                l = dispc_read_reg(DISPC_DIVISOR);
@@ -3552,58 +3633,8 @@ static void _omap_dispc_initial_config(void)
        dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY);
 
        dispc_read_plane_fifo_sizes();
-}
 
-int dispc_enable_plane(enum omap_plane plane, bool enable)
-{
-       DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
-
-       enable_clocks(1);
-       _dispc_enable_plane(plane, enable);
-       enable_clocks(0);
-
-       return 0;
-}
-
-int dispc_setup_plane(enum omap_plane plane,
-                      u32 paddr, u16 screen_width,
-                      u16 pos_x, u16 pos_y,
-                      u16 width, u16 height,
-                      u16 out_width, u16 out_height,
-                      enum omap_color_mode color_mode,
-                      bool ilace,
-                      enum omap_dss_rotation_type rotation_type,
-                      u8 rotation, bool mirror, u8 global_alpha,
-                      u8 pre_mult_alpha, enum omap_channel channel,
-                      u32 puv_addr)
-{
-       int r = 0;
-
-       DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d, %d, %dx%d -> "
-              "%dx%d, ilace %d, cmode %x, rot %d, mir %d chan %d\n",
-              plane, paddr, screen_width, pos_x, pos_y,
-              width, height,
-              out_width, out_height,
-              ilace, color_mode,
-              rotation, mirror, channel);
-
-       enable_clocks(1);
-
-       r = _dispc_setup_plane(plane,
-                          paddr, screen_width,
-                          pos_x, pos_y,
-                          width, height,
-                          out_width, out_height,
-                          color_mode, ilace,
-                          rotation_type,
-                          rotation, mirror,
-                          global_alpha,
-                          pre_mult_alpha,
-                          channel, puv_addr);
-
-       enable_clocks(0);
-
-       return r;
+       dispc_configure_burst_sizes();
 }
 
 /* DISPC HW IP initialisation */
@@ -3612,9 +3643,19 @@ static int omap_dispchw_probe(struct platform_device *pdev)
        u32 rev;
        int r = 0;
        struct resource *dispc_mem;
+       struct clk *clk;
 
        dispc.pdev = pdev;
 
+       clk = clk_get(&pdev->dev, "fck");
+       if (IS_ERR(clk)) {
+               DSSERR("can't get fck\n");
+               r = PTR_ERR(clk);
+               goto err_get_clk;
+       }
+
+       dispc.dss_clk = clk;
+
        spin_lock_init(&dispc.irq_lock);
 
 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
@@ -3628,62 +3669,103 @@ static int omap_dispchw_probe(struct platform_device *pdev)
        if (!dispc_mem) {
                DSSERR("can't get IORESOURCE_MEM DISPC\n");
                r = -EINVAL;
-               goto fail0;
+               goto err_ioremap;
        }
        dispc.base = ioremap(dispc_mem->start, resource_size(dispc_mem));
        if (!dispc.base) {
                DSSERR("can't ioremap DISPC\n");
                r = -ENOMEM;
-               goto fail0;
+               goto err_ioremap;
        }
        dispc.irq = platform_get_irq(dispc.pdev, 0);
        if (dispc.irq < 0) {
                DSSERR("platform_get_irq failed\n");
                r = -ENODEV;
-               goto fail1;
+               goto err_irq;
        }
 
        r = request_irq(dispc.irq, omap_dispc_irq_handler, IRQF_SHARED,
                "OMAP DISPC", dispc.pdev);
        if (r < 0) {
                DSSERR("request_irq failed\n");
-               goto fail1;
+               goto err_irq;
        }
 
-       enable_clocks(1);
+       pm_runtime_enable(&pdev->dev);
+
+       r = dispc_runtime_get();
+       if (r)
+               goto err_runtime_get;
 
        _omap_dispc_initial_config();
 
        _omap_dispc_initialize_irq();
 
-       dispc_save_context();
-
        rev = dispc_read_reg(DISPC_REVISION);
        dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n",
               FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
 
-       enable_clocks(0);
+       dispc_runtime_put();
 
        return 0;
-fail1:
+
+err_runtime_get:
+       pm_runtime_disable(&pdev->dev);
+       free_irq(dispc.irq, dispc.pdev);
+err_irq:
        iounmap(dispc.base);
-fail0:
+err_ioremap:
+       clk_put(dispc.dss_clk);
+err_get_clk:
        return r;
 }
 
 static int omap_dispchw_remove(struct platform_device *pdev)
 {
+       pm_runtime_disable(&pdev->dev);
+
+       clk_put(dispc.dss_clk);
+
        free_irq(dispc.irq, dispc.pdev);
        iounmap(dispc.base);
        return 0;
 }
 
+static int dispc_runtime_suspend(struct device *dev)
+{
+       dispc_save_context();
+       clk_disable(dispc.dss_clk);
+       dss_runtime_put();
+
+       return 0;
+}
+
+static int dispc_runtime_resume(struct device *dev)
+{
+       int r;
+
+       r = dss_runtime_get();
+       if (r < 0)
+               return r;
+
+       clk_enable(dispc.dss_clk);
+       dispc_restore_context();
+
+       return 0;
+}
+
+static const struct dev_pm_ops dispc_pm_ops = {
+       .runtime_suspend = dispc_runtime_suspend,
+       .runtime_resume = dispc_runtime_resume,
+};
+
 static struct platform_driver omap_dispchw_driver = {
        .probe          = omap_dispchw_probe,
        .remove         = omap_dispchw_remove,
        .driver         = {
                .name   = "omapdss_dispc",
                .owner  = THIS_MODULE,
+               .pm     = &dispc_pm_ops,
        },
 };
 
index c2dfc8c..94495e4 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <video/omapdss.h>
 #include "dss.h"
+#include "dss_features.h"
 
 static ssize_t display_enabled_show(struct device *dev,
                struct device_attribute *attr, char *buf)
@@ -65,48 +66,6 @@ static ssize_t display_enabled_store(struct device *dev,
        return size;
 }
 
-static ssize_t display_upd_mode_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct omap_dss_device *dssdev = to_dss_device(dev);
-       enum omap_dss_update_mode mode = OMAP_DSS_UPDATE_AUTO;
-       if (dssdev->driver->get_update_mode)
-               mode = dssdev->driver->get_update_mode(dssdev);
-       return snprintf(buf, PAGE_SIZE, "%d\n", mode);
-}
-
-static ssize_t display_upd_mode_store(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf, size_t size)
-{
-       struct omap_dss_device *dssdev = to_dss_device(dev);
-       int val, r;
-       enum omap_dss_update_mode mode;
-
-       if (!dssdev->driver->set_update_mode)
-               return -EINVAL;
-
-       r = kstrtoint(buf, 0, &val);
-       if (r)
-               return r;
-
-       switch (val) {
-       case OMAP_DSS_UPDATE_DISABLED:
-       case OMAP_DSS_UPDATE_AUTO:
-       case OMAP_DSS_UPDATE_MANUAL:
-               mode = (enum omap_dss_update_mode)val;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       r = dssdev->driver->set_update_mode(dssdev, mode);
-       if (r)
-               return r;
-
-       return size;
-}
-
 static ssize_t display_tear_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
@@ -294,8 +253,6 @@ static ssize_t display_wss_store(struct device *dev,
 
 static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR,
                display_enabled_show, display_enabled_store);
-static DEVICE_ATTR(update_mode, S_IRUGO|S_IWUSR,
-               display_upd_mode_show, display_upd_mode_store);
 static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR,
                display_tear_show, display_tear_store);
 static DEVICE_ATTR(timings, S_IRUGO|S_IWUSR,
@@ -309,7 +266,6 @@ static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR,
 
 static struct device_attribute *display_sysfs_attrs[] = {
        &dev_attr_enabled,
-       &dev_attr_update_mode,
        &dev_attr_tear_elim,
        &dev_attr_timings,
        &dev_attr_rotate,
@@ -327,16 +283,13 @@ void omapdss_default_get_resolution(struct omap_dss_device *dssdev,
 EXPORT_SYMBOL(omapdss_default_get_resolution);
 
 void default_get_overlay_fifo_thresholds(enum omap_plane plane,
-               u32 fifo_size, enum omap_burst_size *burst_size,
+               u32 fifo_size, u32 burst_size,
                u32 *fifo_low, u32 *fifo_high)
 {
-       unsigned burst_size_bytes;
-
-       *burst_size = OMAP_DSS_BURST_16x32;
-       burst_size_bytes = 16 * 32 / 8;
+       unsigned buf_unit = dss_feat_get_buffer_size_unit();
 
-       *fifo_high = fifo_size - 1;
-       *fifo_low = fifo_size - burst_size_bytes;
+       *fifo_high = fifo_size - buf_unit;
+       *fifo_low = fifo_size - burst_size;
 }
 
 int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev)
index ff6bd30..f053b18 100644 (file)
@@ -23,7 +23,6 @@
 #define DSS_SUBSYS_NAME "DPI"
 
 #include <linux/kernel.h>
-#include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/errno.h>
@@ -130,8 +129,6 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
        bool is_tft;
        int r = 0;
 
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
-
        dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config,
                        dssdev->panel.acbi, dssdev->panel.acb);
 
@@ -144,7 +141,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
                r = dpi_set_dispc_clk(dssdev, is_tft, t->pixel_clock * 1000,
                                &fck, &lck_div, &pck_div);
        if (r)
-               goto err0;
+               return r;
 
        pck = fck / lck_div / pck_div / 1000;
 
@@ -158,12 +155,10 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
 
        dispc_set_lcd_timings(dssdev->manager->id, t);
 
-err0:
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
-       return r;
+       return 0;
 }
 
-static int dpi_basic_init(struct omap_dss_device *dssdev)
+static void dpi_basic_init(struct omap_dss_device *dssdev)
 {
        bool is_tft;
 
@@ -175,8 +170,6 @@ static int dpi_basic_init(struct omap_dss_device *dssdev)
                        OMAP_DSS_LCD_DISPLAY_TFT : OMAP_DSS_LCD_DISPLAY_STN);
        dispc_set_tft_data_lines(dssdev->manager->id,
                        dssdev->phy.dpi.data_lines);
-
-       return 0;
 }
 
 int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
@@ -186,31 +179,38 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
        r = omap_dss_start_device(dssdev);
        if (r) {
                DSSERR("failed to start device\n");
-               goto err0;
+               goto err_start_dev;
        }
 
        if (cpu_is_omap34xx()) {
                r = regulator_enable(dpi.vdds_dsi_reg);
                if (r)
-                       goto err1;
+                       goto err_reg_enable;
        }
 
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
+       r = dss_runtime_get();
+       if (r)
+               goto err_get_dss;
 
-       r = dpi_basic_init(dssdev);
+       r = dispc_runtime_get();
        if (r)
-               goto err2;
+               goto err_get_dispc;
+
+       dpi_basic_init(dssdev);
 
        if (dpi_use_dsi_pll(dssdev)) {
-               dss_clk_enable(DSS_CLK_SYSCK);
+               r = dsi_runtime_get(dpi.dsidev);
+               if (r)
+                       goto err_get_dsi;
+
                r = dsi_pll_init(dpi.dsidev, 0, 1);
                if (r)
-                       goto err3;
+                       goto err_dsi_pll_init;
        }
 
        r = dpi_set_mode(dssdev);
        if (r)
-               goto err4;
+               goto err_set_mode;
 
        mdelay(2);
 
@@ -218,19 +218,22 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
 
        return 0;
 
-err4:
+err_set_mode:
        if (dpi_use_dsi_pll(dssdev))
                dsi_pll_uninit(dpi.dsidev, true);
-err3:
+err_dsi_pll_init:
        if (dpi_use_dsi_pll(dssdev))
-               dss_clk_disable(DSS_CLK_SYSCK);
-err2:
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
+               dsi_runtime_put(dpi.dsidev);
+err_get_dsi:
+       dispc_runtime_put();
+err_get_dispc:
+       dss_runtime_put();
+err_get_dss:
        if (cpu_is_omap34xx())
                regulator_disable(dpi.vdds_dsi_reg);
-err1:
+err_reg_enable:
        omap_dss_stop_device(dssdev);
-err0:
+err_start_dev:
        return r;
 }
 EXPORT_SYMBOL(omapdss_dpi_display_enable);
@@ -242,10 +245,11 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
        if (dpi_use_dsi_pll(dssdev)) {
                dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
                dsi_pll_uninit(dpi.dsidev, true);
-               dss_clk_disable(DSS_CLK_SYSCK);
+               dsi_runtime_put(dpi.dsidev);
        }
 
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
+       dispc_runtime_put();
+       dss_runtime_put();
 
        if (cpu_is_omap34xx())
                regulator_disable(dpi.vdds_dsi_reg);
@@ -257,11 +261,26 @@ EXPORT_SYMBOL(omapdss_dpi_display_disable);
 void dpi_set_timings(struct omap_dss_device *dssdev,
                        struct omap_video_timings *timings)
 {
+       int r;
+
        DSSDBG("dpi_set_timings\n");
        dssdev->panel.timings = *timings;
        if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
+               r = dss_runtime_get();
+               if (r)
+                       return;
+
+               r = dispc_runtime_get();
+               if (r) {
+                       dss_runtime_put();
+                       return;
+               }
+
                dpi_set_mode(dssdev);
                dispc_go(dssdev->manager->id);
+
+               dispc_runtime_put();
+               dss_runtime_put();
        }
 }
 EXPORT_SYMBOL(dpi_set_timings);
index 345757c..7adbbeb 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/debugfs.h>
+#include <linux/pm_runtime.h>
 
 #include <video/omapdss.h>
 #include <plat/clock.h>
@@ -267,8 +268,12 @@ struct dsi_isr_tables {
 struct dsi_data {
        struct platform_device *pdev;
        void __iomem    *base;
+
        int irq;
 
+       struct clk *dss_clk;
+       struct clk *sys_clk;
+
        void (*dsi_mux_pads)(bool enable);
 
        struct dsi_clock_info current_cinfo;
@@ -389,15 +394,6 @@ static inline u32 dsi_read_reg(struct platform_device *dsidev,
        return __raw_readl(dsi->base + idx.idx);
 }
 
-
-void dsi_save_context(void)
-{
-}
-
-void dsi_restore_context(void)
-{
-}
-
 void dsi_bus_lock(struct omap_dss_device *dssdev)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
@@ -493,9 +489,18 @@ static void dsi_perf_show(struct platform_device *dsidev, const char *name)
                        total_bytes * 1000 / total_us);
 }
 #else
-#define dsi_perf_mark_setup(x)
-#define dsi_perf_mark_start(x)
-#define dsi_perf_show(x, y)
+static inline void dsi_perf_mark_setup(struct platform_device *dsidev)
+{
+}
+
+static inline void dsi_perf_mark_start(struct platform_device *dsidev)
+{
+}
+
+static inline void dsi_perf_show(struct platform_device *dsidev,
+               const char *name)
+{
+}
 #endif
 
 static void print_irq_status(u32 status)
@@ -1039,13 +1044,27 @@ static u32 dsi_get_errors(struct platform_device *dsidev)
        return e;
 }
 
-/* DSI func clock. this could also be dsi_pll_hsdiv_dsi_clk */
-static inline void enable_clocks(bool enable)
+int dsi_runtime_get(struct platform_device *dsidev)
 {
-       if (enable)
-               dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
-       else
-               dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
+       int r;
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       DSSDBG("dsi_runtime_get\n");
+
+       r = pm_runtime_get_sync(&dsi->pdev->dev);
+       WARN_ON(r < 0);
+       return r < 0 ? r : 0;
+}
+
+void dsi_runtime_put(struct platform_device *dsidev)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       int r;
+
+       DSSDBG("dsi_runtime_put\n");
+
+       r = pm_runtime_put(&dsi->pdev->dev);
+       WARN_ON(r < 0);
 }
 
 /* source clock for DSI PLL. this could also be PCLKFREE */
@@ -1055,9 +1074,9 @@ static inline void dsi_enable_pll_clock(struct platform_device *dsidev,
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
        if (enable)
-               dss_clk_enable(DSS_CLK_SYSCK);
+               clk_enable(dsi->sys_clk);
        else
-               dss_clk_disable(DSS_CLK_SYSCK);
+               clk_disable(dsi->sys_clk);
 
        if (enable && dsi->pll_locked) {
                if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1)
@@ -1150,10 +1169,11 @@ static unsigned long dsi_fclk_rate(struct platform_device *dsidev)
 {
        unsigned long r;
        int dsi_module = dsi_get_dsidev_id(dsidev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
        if (dss_get_dsi_clk_source(dsi_module) == OMAP_DSS_CLK_SRC_FCK) {
                /* DSI FCLK source is DSS_CLK_FCK */
-               r = dss_clk_get_rate(DSS_CLK_FCK);
+               r = clk_get_rate(dsi->dss_clk);
        } else {
                /* DSI FCLK source is dsi_pll_hsdiv_dsi_clk */
                r = dsi_get_pll_hsdiv_dsi_rate(dsidev);
@@ -1262,7 +1282,7 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev,
                return -EINVAL;
 
        if (cinfo->use_sys_clk) {
-               cinfo->clkin = dss_clk_get_rate(DSS_CLK_SYSCK);
+               cinfo->clkin = clk_get_rate(dsi->sys_clk);
                /* XXX it is unclear if highfreq should be used
                 * with DSS_SYS_CLK source also */
                cinfo->highfreq = 0;
@@ -1311,7 +1331,7 @@ int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, bool is_tft,
        int match = 0;
        unsigned long dss_sys_clk, max_dss_fck;
 
-       dss_sys_clk = dss_clk_get_rate(DSS_CLK_SYSCK);
+       dss_sys_clk = clk_get_rate(dsi->sys_clk);
 
        max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
 
@@ -1601,7 +1621,6 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
                dsi->vdds_dsi_reg = vdds_dsi;
        }
 
-       enable_clocks(1);
        dsi_enable_pll_clock(dsidev, 1);
        /*
         * Note: SCP CLK is not required on OMAP3, but it is required on OMAP4.
@@ -1653,7 +1672,6 @@ err1:
        }
 err0:
        dsi_disable_scp_clk(dsidev);
-       enable_clocks(0);
        dsi_enable_pll_clock(dsidev, 0);
        return r;
 }
@@ -1671,7 +1689,6 @@ void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes)
        }
 
        dsi_disable_scp_clk(dsidev);
-       enable_clocks(0);
        dsi_enable_pll_clock(dsidev, 0);
 
        DSSDBG("PLL uninit done\n");
@@ -1688,7 +1705,8 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev,
        dispc_clk_src = dss_get_dispc_clk_source();
        dsi_clk_src = dss_get_dsi_clk_source(dsi_module);
 
-       enable_clocks(1);
+       if (dsi_runtime_get(dsidev))
+               return;
 
        seq_printf(s,   "- DSI%d PLL -\n", dsi_module + 1);
 
@@ -1731,7 +1749,7 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev,
 
        seq_printf(s,   "LP_CLK\t\t%lu\n", cinfo->lp_clk);
 
-       enable_clocks(0);
+       dsi_runtime_put(dsidev);
 }
 
 void dsi_dump_clocks(struct seq_file *s)
@@ -1873,7 +1891,8 @@ static void dsi_dump_dsidev_regs(struct platform_device *dsidev,
 {
 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(dsidev, r))
 
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
+       if (dsi_runtime_get(dsidev))
+               return;
        dsi_enable_scp_clk(dsidev);
 
        DUMPREG(DSI_REVISION);
@@ -1947,7 +1966,7 @@ static void dsi_dump_dsidev_regs(struct platform_device *dsidev,
        DUMPREG(DSI_PLL_CONFIGURATION2);
 
        dsi_disable_scp_clk(dsidev);
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
+       dsi_runtime_put(dsidev);
 #undef DUMPREG
 }
 
@@ -2463,28 +2482,6 @@ static void dsi_cio_uninit(struct platform_device *dsidev)
                dsi->dsi_mux_pads(false);
 }
 
-static int _dsi_wait_reset(struct platform_device *dsidev)
-{
-       int t = 0;
-
-       while (REG_GET(dsidev, DSI_SYSSTATUS, 0, 0) == 0) {
-               if (++t > 5) {
-                       DSSERR("soft reset failed\n");
-                       return -ENODEV;
-               }
-               udelay(1);
-       }
-
-       return 0;
-}
-
-static int _dsi_reset(struct platform_device *dsidev)
-{
-       /* Soft reset */
-       REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 1, 1);
-       return _dsi_wait_reset(dsidev);
-}
-
 static void dsi_config_tx_fifo(struct platform_device *dsidev,
                enum fifo_size size1, enum fifo_size size2,
                enum fifo_size size3, enum fifo_size size4)
@@ -3386,6 +3383,10 @@ static int dsi_enter_ulps(struct platform_device *dsidev)
        dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion,
                        DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
 
+       /* Reset LANEx_ULPS_SIG2 */
+       REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, (0 << 0) | (0 << 1) | (0 << 2),
+               7, 5);
+
        dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS);
 
        dsi_if_enable(dsidev, false);
@@ -4198,22 +4199,6 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev,
        dsi_pll_uninit(dsidev, disconnect_lanes);
 }
 
-static int dsi_core_init(struct platform_device *dsidev)
-{
-       /* Autoidle */
-       REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 0, 0);
-
-       /* ENWAKEUP */
-       REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 2, 2);
-
-       /* SIDLEMODE smart-idle */
-       REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 2, 4, 3);
-
-       _dsi_initialize_irq(dsidev);
-
-       return 0;
-}
-
 int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
@@ -4229,37 +4214,37 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
        r = omap_dss_start_device(dssdev);
        if (r) {
                DSSERR("failed to start device\n");
-               goto err0;
+               goto err_start_dev;
        }
 
-       enable_clocks(1);
-       dsi_enable_pll_clock(dsidev, 1);
-
-       r = _dsi_reset(dsidev);
+       r = dsi_runtime_get(dsidev);
        if (r)
-               goto err1;
+               goto err_get_dsi;
 
-       dsi_core_init(dsidev);
+       dsi_enable_pll_clock(dsidev, 1);
+
+       _dsi_initialize_irq(dsidev);
 
        r = dsi_display_init_dispc(dssdev);
        if (r)
-               goto err1;
+               goto err_init_dispc;
 
        r = dsi_display_init_dsi(dssdev);
        if (r)
-               goto err2;
+               goto err_init_dsi;
 
        mutex_unlock(&dsi->lock);
 
        return 0;
 
-err2:
+err_init_dsi:
        dsi_display_uninit_dispc(dssdev);
-err1:
-       enable_clocks(0);
+err_init_dispc:
        dsi_enable_pll_clock(dsidev, 0);
+       dsi_runtime_put(dsidev);
+err_get_dsi:
        omap_dss_stop_device(dssdev);
-err0:
+err_start_dev:
        mutex_unlock(&dsi->lock);
        DSSDBG("dsi_display_enable FAILED\n");
        return r;
@@ -4278,11 +4263,16 @@ void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,
 
        mutex_lock(&dsi->lock);
 
+       dsi_sync_vc(dsidev, 0);
+       dsi_sync_vc(dsidev, 1);
+       dsi_sync_vc(dsidev, 2);
+       dsi_sync_vc(dsidev, 3);
+
        dsi_display_uninit_dispc(dssdev);
 
        dsi_display_uninit_dsi(dssdev, disconnect_lanes, enter_ulps);
 
-       enable_clocks(0);
+       dsi_runtime_put(dsidev);
        dsi_enable_pll_clock(dsidev, 0);
 
        omap_dss_stop_device(dssdev);
@@ -4302,16 +4292,11 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
 EXPORT_SYMBOL(omapdss_dsi_enable_te);
 
 void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
-               u32 fifo_size, enum omap_burst_size *burst_size,
+               u32 fifo_size, u32 burst_size,
                u32 *fifo_low, u32 *fifo_high)
 {
-       unsigned burst_size_bytes;
-
-       *burst_size = OMAP_DSS_BURST_16x32;
-       burst_size_bytes = 16 * 32 / 8;
-
-       *fifo_high = fifo_size - burst_size_bytes;
-       *fifo_low = fifo_size - burst_size_bytes * 2;
+       *fifo_high = fifo_size - burst_size;
+       *fifo_low = fifo_size - burst_size * 2;
 }
 
 int dsi_init_display(struct omap_dss_device *dssdev)
@@ -4437,7 +4422,47 @@ static void dsi_calc_clock_param_ranges(struct platform_device *dsidev)
        dsi->lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV);
 }
 
-static int dsi_init(struct platform_device *dsidev)
+static int dsi_get_clocks(struct platform_device *dsidev)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       struct clk *clk;
+
+       clk = clk_get(&dsidev->dev, "fck");
+       if (IS_ERR(clk)) {
+               DSSERR("can't get fck\n");
+               return PTR_ERR(clk);
+       }
+
+       dsi->dss_clk = clk;
+
+       if (cpu_is_omap34xx() || cpu_is_omap3630())
+               clk = clk_get(&dsidev->dev, "dss2_alwon_fck");
+       else
+               clk = clk_get(&dsidev->dev, "sys_clk");
+       if (IS_ERR(clk)) {
+               DSSERR("can't get sys_clk\n");
+               clk_put(dsi->dss_clk);
+               dsi->dss_clk = NULL;
+               return PTR_ERR(clk);
+       }
+
+       dsi->sys_clk = clk;
+
+       return 0;
+}
+
+static void dsi_put_clocks(struct platform_device *dsidev)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       if (dsi->dss_clk)
+               clk_put(dsi->dss_clk);
+       if (dsi->sys_clk)
+               clk_put(dsi->sys_clk);
+}
+
+/* DSI1 HW IP initialisation */
+static int omap_dsi1hw_probe(struct platform_device *dsidev)
 {
        struct omap_display_platform_data *dss_plat_data;
        struct omap_dss_board_info *board_info;
@@ -4449,7 +4474,7 @@ static int dsi_init(struct platform_device *dsidev)
        dsi = kzalloc(sizeof(*dsi), GFP_KERNEL);
        if (!dsi) {
                r = -ENOMEM;
-               goto err0;
+               goto err_alloc;
        }
 
        dsi->pdev = dsidev;
@@ -4472,6 +4497,12 @@ static int dsi_init(struct platform_device *dsidev)
        mutex_init(&dsi->lock);
        sema_init(&dsi->bus_lock, 1);
 
+       r = dsi_get_clocks(dsidev);
+       if (r)
+               goto err_get_clk;
+
+       pm_runtime_enable(&dsidev->dev);
+
        INIT_DELAYED_WORK_DEFERRABLE(&dsi->framedone_timeout_work,
                        dsi_framedone_timeout_work_callback);
 
@@ -4484,26 +4515,26 @@ static int dsi_init(struct platform_device *dsidev)
        if (!dsi_mem) {
                DSSERR("can't get IORESOURCE_MEM DSI\n");
                r = -EINVAL;
-               goto err1;
+               goto err_ioremap;
        }
        dsi->base = ioremap(dsi_mem->start, resource_size(dsi_mem));
        if (!dsi->base) {
                DSSERR("can't ioremap DSI\n");
                r = -ENOMEM;
-               goto err1;
+               goto err_ioremap;
        }
        dsi->irq = platform_get_irq(dsi->pdev, 0);
        if (dsi->irq < 0) {
                DSSERR("platform_get_irq failed\n");
                r = -ENODEV;
-               goto err2;
+               goto err_get_irq;
        }
 
        r = request_irq(dsi->irq, omap_dsi_irq_handler, IRQF_SHARED,
                dev_name(&dsidev->dev), dsi->pdev);
        if (r < 0) {
                DSSERR("request_irq failed\n");
-               goto err2;
+               goto err_get_irq;
        }
 
        /* DSI VCs initialization */
@@ -4515,7 +4546,9 @@ static int dsi_init(struct platform_device *dsidev)
 
        dsi_calc_clock_param_ranges(dsidev);
 
-       enable_clocks(1);
+       r = dsi_runtime_get(dsidev);
+       if (r)
+               goto err_get_dsi;
 
        rev = dsi_read_reg(dsidev, DSI_REVISION);
        dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n",
@@ -4523,21 +4556,32 @@ static int dsi_init(struct platform_device *dsidev)
 
        dsi->num_data_lanes = dsi_get_num_data_lanes(dsidev);
 
-       enable_clocks(0);
+       dsi_runtime_put(dsidev);
 
        return 0;
-err2:
+
+err_get_dsi:
+       free_irq(dsi->irq, dsi->pdev);
+err_get_irq:
        iounmap(dsi->base);
-err1:
+err_ioremap:
+       pm_runtime_disable(&dsidev->dev);
+err_get_clk:
        kfree(dsi);
-err0:
+err_alloc:
        return r;
 }
 
-static void dsi_exit(struct platform_device *dsidev)
+static int omap_dsi1hw_remove(struct platform_device *dsidev)
 {
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
+       WARN_ON(dsi->scp_clk_refcount > 0);
+
+       pm_runtime_disable(&dsidev->dev);
+
+       dsi_put_clocks(dsidev);
+
        if (dsi->vdds_dsi_reg != NULL) {
                if (dsi->vdds_dsi_enabled) {
                        regulator_disable(dsi->vdds_dsi_reg);
@@ -4553,38 +4597,56 @@ static void dsi_exit(struct platform_device *dsidev)
 
        kfree(dsi);
 
-       DSSDBG("omap_dsi_exit\n");
+       return 0;
 }
 
-/* DSI1 HW IP initialisation */
-static int omap_dsi1hw_probe(struct platform_device *dsidev)
+static int dsi_runtime_suspend(struct device *dev)
 {
-       int r;
+       struct dsi_data *dsi = dsi_get_dsidrv_data(to_platform_device(dev));
 
-       r = dsi_init(dsidev);
-       if (r) {
-               DSSERR("Failed to initialize DSI\n");
-               goto err_dsi;
-       }
-err_dsi:
-       return r;
+       clk_disable(dsi->dss_clk);
+
+       dispc_runtime_put();
+       dss_runtime_put();
+
+       return 0;
 }
 
-static int omap_dsi1hw_remove(struct platform_device *dsidev)
+static int dsi_runtime_resume(struct device *dev)
 {
-       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(to_platform_device(dev));
+       int r;
+
+       r = dss_runtime_get();
+       if (r)
+               goto err_get_dss;
+
+       r = dispc_runtime_get();
+       if (r)
+               goto err_get_dispc;
+
+       clk_enable(dsi->dss_clk);
 
-       dsi_exit(dsidev);
-       WARN_ON(dsi->scp_clk_refcount > 0);
        return 0;
+
+err_get_dispc:
+       dss_runtime_put();
+err_get_dss:
+       return r;
 }
 
+static const struct dev_pm_ops dsi_pm_ops = {
+       .runtime_suspend = dsi_runtime_suspend,
+       .runtime_resume = dsi_runtime_resume,
+};
+
 static struct platform_driver omap_dsi1hw_driver = {
        .probe          = omap_dsi1hw_probe,
        .remove         = omap_dsi1hw_remove,
        .driver         = {
                .name   = "omapdss_dsi1",
                .owner  = THIS_MODULE,
+               .pm     = &dsi_pm_ops,
        },
 };
 
index d9489d5..0f9c3a6 100644 (file)
@@ -28,6 +28,8 @@
 #include <linux/delay.h>
 #include <linux/seq_file.h>
 #include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 
 #include <video/omapdss.h>
 #include <plat/clock.h>
@@ -59,15 +61,9 @@ struct dss_reg {
 static struct {
        struct platform_device *pdev;
        void __iomem    *base;
-       int             ctx_id;
 
        struct clk      *dpll4_m4_ck;
-       struct clk      *dss_ick;
-       struct clk      *dss_fck;
-       struct clk      *dss_sys_clk;
-       struct clk      *dss_tv_fck;
-       struct clk      *dss_video_fck;
-       unsigned        num_clks_enabled;
+       struct clk      *dss_clk;
 
        unsigned long   cache_req_pck;
        unsigned long   cache_prate;
@@ -78,6 +74,7 @@ static struct {
        enum omap_dss_clk_source dispc_clk_source;
        enum omap_dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS];
 
+       bool            ctx_valid;
        u32             ctx[DSS_SZ_REGS / sizeof(u32)];
 } dss;
 
@@ -87,13 +84,6 @@ static const char * const dss_generic_clk_source_names[] = {
        [OMAP_DSS_CLK_SRC_FCK]                  = "DSS_FCK",
 };
 
-static void dss_clk_enable_all_no_ctx(void);
-static void dss_clk_disable_all_no_ctx(void);
-static void dss_clk_enable_no_ctx(enum dss_clock clks);
-static void dss_clk_disable_no_ctx(enum dss_clock clks);
-
-static int _omap_dss_wait_reset(void);
-
 static inline void dss_write_reg(const struct dss_reg idx, u32 val)
 {
        __raw_writel(val, dss.base + idx.idx);
@@ -109,12 +99,10 @@ static inline u32 dss_read_reg(const struct dss_reg idx)
 #define RR(reg) \
        dss_write_reg(DSS_##reg, dss.ctx[(DSS_##reg).idx / sizeof(u32)])
 
-void dss_save_context(void)
+static void dss_save_context(void)
 {
-       if (cpu_is_omap24xx())
-               return;
+       DSSDBG("dss_save_context\n");
 
-       SR(SYSCONFIG);
        SR(CONTROL);
 
        if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
@@ -122,14 +110,19 @@ void dss_save_context(void)
                SR(SDI_CONTROL);
                SR(PLL_CONTROL);
        }
+
+       dss.ctx_valid = true;
+
+       DSSDBG("context saved\n");
 }
 
-void dss_restore_context(void)
+static void dss_restore_context(void)
 {
-       if (_omap_dss_wait_reset())
-               DSSERR("DSS not coming out of reset after sleep\n");
+       DSSDBG("dss_restore_context\n");
+
+       if (!dss.ctx_valid)
+               return;
 
-       RR(SYSCONFIG);
        RR(CONTROL);
 
        if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
@@ -137,6 +130,8 @@ void dss_restore_context(void)
                RR(SDI_CONTROL);
                RR(PLL_CONTROL);
        }
+
+       DSSDBG("context restored\n");
 }
 
 #undef SR
@@ -234,6 +229,7 @@ const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src)
        return dss_generic_clk_source_names[clk_src];
 }
 
+
 void dss_dump_clocks(struct seq_file *s)
 {
        unsigned long dpll4_ck_rate;
@@ -241,13 +237,14 @@ void dss_dump_clocks(struct seq_file *s)
        const char *fclk_name, *fclk_real_name;
        unsigned long fclk_rate;
 
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
+       if (dss_runtime_get())
+               return;
 
        seq_printf(s, "- DSS -\n");
 
        fclk_name = dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
        fclk_real_name = dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
-       fclk_rate = dss_clk_get_rate(DSS_CLK_FCK);
+       fclk_rate = clk_get_rate(dss.dss_clk);
 
        if (dss.dpll4_m4_ck) {
                dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
@@ -273,14 +270,15 @@ void dss_dump_clocks(struct seq_file *s)
                                fclk_rate);
        }
 
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
+       dss_runtime_put();
 }
 
 void dss_dump_regs(struct seq_file *s)
 {
 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r))
 
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
+       if (dss_runtime_get())
+               return;
 
        DUMPREG(DSS_REVISION);
        DUMPREG(DSS_SYSCONFIG);
@@ -294,7 +292,7 @@ void dss_dump_regs(struct seq_file *s)
                DUMPREG(DSS_SDI_STATUS);
        }
 
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
+       dss_runtime_put();
 #undef DUMPREG
 }
 
@@ -437,7 +435,7 @@ int dss_calc_clock_rates(struct dss_clock_info *cinfo)
        } else {
                if (cinfo->fck_div != 0)
                        return -EINVAL;
-               cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK);
+               cinfo->fck = clk_get_rate(dss.dss_clk);
        }
 
        return 0;
@@ -467,7 +465,7 @@ int dss_set_clock_div(struct dss_clock_info *cinfo)
 
 int dss_get_clock_div(struct dss_clock_info *cinfo)
 {
-       cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK);
+       cinfo->fck = clk_get_rate(dss.dss_clk);
 
        if (dss.dpll4_m4_ck) {
                unsigned long prate;
@@ -512,7 +510,7 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
 
        max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
 
-       fck = dss_clk_get_rate(DSS_CLK_FCK);
+       fck = clk_get_rate(dss.dss_clk);
        if (req_pck == dss.cache_req_pck &&
                        ((cpu_is_omap34xx() && prate == dss.cache_prate) ||
                         dss.cache_dss_cinfo.fck == fck)) {
@@ -539,7 +537,7 @@ retry:
        if (dss.dpll4_m4_ck == NULL) {
                struct dispc_clock_info cur_dispc;
                /* XXX can we change the clock on omap2? */
-               fck = dss_clk_get_rate(DSS_CLK_FCK);
+               fck = clk_get_rate(dss.dss_clk);
                fck_div = 1;
 
                dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc);
@@ -616,28 +614,6 @@ found:
        return 0;
 }
 
-static int _omap_dss_wait_reset(void)
-{
-       int t = 0;
-
-       while (REG_GET(DSS_SYSSTATUS, 0, 0) == 0) {
-               if (++t > 1000) {
-                       DSSERR("soft reset failed\n");
-                       return -ENODEV;
-               }
-               udelay(1);
-       }
-
-       return 0;
-}
-
-static int _omap_dss_reset(void)
-{
-       /* Soft reset */
-       REG_FLD_MOD(DSS_SYSCONFIG, 1, 1, 1);
-       return _omap_dss_wait_reset();
-}
-
 void dss_set_venc_output(enum omap_dss_venc_type type)
 {
        int l = 0;
@@ -663,424 +639,88 @@ void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select hdmi)
        REG_FLD_MOD(DSS_CONTROL, hdmi, 15, 15); /* VENC_HDMI_SWITCH */
 }
 
-static int dss_init(void)
+static int dss_get_clocks(void)
 {
+       struct clk *clk;
        int r;
-       u32 rev;
-       struct resource *dss_mem;
-       struct clk *dpll4_m4_ck;
 
-       dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0);
-       if (!dss_mem) {
-               DSSERR("can't get IORESOURCE_MEM DSS\n");
-               r = -EINVAL;
-               goto fail0;
-       }
-       dss.base = ioremap(dss_mem->start, resource_size(dss_mem));
-       if (!dss.base) {
-               DSSERR("can't ioremap DSS\n");
-               r = -ENOMEM;
-               goto fail0;
+       clk = clk_get(&dss.pdev->dev, "fck");
+       if (IS_ERR(clk)) {
+               DSSERR("can't get clock fck\n");
+               r = PTR_ERR(clk);
+               goto err;
        }
 
-       /* disable LCD and DIGIT output. This seems to fix the synclost
-        * problem that we get, if the bootloader starts the DSS and
-        * the kernel resets it */
-       omap_writel(omap_readl(0x48050440) & ~0x3, 0x48050440);
-
-#ifdef CONFIG_OMAP2_DSS_SLEEP_BEFORE_RESET
-       /* We need to wait here a bit, otherwise we sometimes start to
-        * get synclost errors, and after that only power cycle will
-        * restore DSS functionality. I have no idea why this happens.
-        * And we have to wait _before_ resetting the DSS, but after
-        * enabling clocks.
-        *
-        * This bug was at least present on OMAP3430. It's unknown
-        * if it happens on OMAP2 or OMAP3630.
-        */
-       msleep(50);
-#endif
-
-       _omap_dss_reset();
+       dss.dss_clk = clk;
 
-       /* autoidle */
-       REG_FLD_MOD(DSS_SYSCONFIG, 1, 0, 0);
-
-       /* Select DPLL */
-       REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
-
-#ifdef CONFIG_OMAP2_DSS_VENC
-       REG_FLD_MOD(DSS_CONTROL, 1, 4, 4);      /* venc dac demen */
-       REG_FLD_MOD(DSS_CONTROL, 1, 3, 3);      /* venc clock 4x enable */
-       REG_FLD_MOD(DSS_CONTROL, 0, 2, 2);      /* venc clock mode = normal */
-#endif
        if (cpu_is_omap34xx()) {
-               dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck");
-               if (IS_ERR(dpll4_m4_ck)) {
+               clk = clk_get(NULL, "dpll4_m4_ck");
+               if (IS_ERR(clk)) {
                        DSSERR("Failed to get dpll4_m4_ck\n");
-                       r = PTR_ERR(dpll4_m4_ck);
-                       goto fail1;
+                       r = PTR_ERR(clk);
+                       goto err;
                }
        } else if (cpu_is_omap44xx()) {
-               dpll4_m4_ck = clk_get(NULL, "dpll_per_m5x2_ck");
-               if (IS_ERR(dpll4_m4_ck)) {
-                       DSSERR("Failed to get dpll4_m4_ck\n");
-                       r = PTR_ERR(dpll4_m4_ck);
-                       goto fail1;
+               clk = clk_get(NULL, "dpll_per_m5x2_ck");
+               if (IS_ERR(clk)) {
+                       DSSERR("Failed to get dpll_per_m5x2_ck\n");
+                       r = PTR_ERR(clk);
+                       goto err;
                }
        } else { /* omap24xx */
-               dpll4_m4_ck = NULL;
+               clk = NULL;
        }
 
-       dss.dpll4_m4_ck = dpll4_m4_ck;
-
-       dss.dsi_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
-       dss.dsi_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
-       dss.dispc_clk_source = OMAP_DSS_CLK_SRC_FCK;
-       dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
-       dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
-
-       dss_save_context();
-
-       rev = dss_read_reg(DSS_REVISION);
-       printk(KERN_INFO "OMAP DSS rev %d.%d\n",
-                       FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
+       dss.dpll4_m4_ck = clk;
 
        return 0;
 
-fail1:
-       iounmap(dss.base);
-fail0:
-       return r;
-}
-
-static void dss_exit(void)
-{
+err:
+       if (dss.dss_clk)
+               clk_put(dss.dss_clk);
        if (dss.dpll4_m4_ck)
                clk_put(dss.dpll4_m4_ck);
 
-       iounmap(dss.base);
-}
-
-/* CONTEXT */
-static int dss_get_ctx_id(void)
-{
-       struct omap_display_platform_data *pdata = dss.pdev->dev.platform_data;
-       int r;
-
-       if (!pdata->board_data->get_last_off_on_transaction_id)
-               return 0;
-       r = pdata->board_data->get_last_off_on_transaction_id(&dss.pdev->dev);
-       if (r < 0) {
-               dev_err(&dss.pdev->dev, "getting transaction ID failed, "
-                               "will force context restore\n");
-               r = -1;
-       }
-       return r;
-}
-
-int dss_need_ctx_restore(void)
-{
-       int id = dss_get_ctx_id();
-
-       if (id < 0 || id != dss.ctx_id) {
-               DSSDBG("ctx id %d -> id %d\n",
-                               dss.ctx_id, id);
-               dss.ctx_id = id;
-               return 1;
-       } else {
-               return 0;
-       }
-}
-
-static void save_all_ctx(void)
-{
-       DSSDBG("save context\n");
-
-       dss_clk_enable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK);
-
-       dss_save_context();
-       dispc_save_context();
-#ifdef CONFIG_OMAP2_DSS_DSI
-       dsi_save_context();
-#endif
-
-       dss_clk_disable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK);
-}
-
-static void restore_all_ctx(void)
-{
-       DSSDBG("restore context\n");
-
-       dss_clk_enable_all_no_ctx();
-
-       dss_restore_context();
-       dispc_restore_context();
-#ifdef CONFIG_OMAP2_DSS_DSI
-       dsi_restore_context();
-#endif
-
-       dss_clk_disable_all_no_ctx();
-}
-
-static int dss_get_clock(struct clk **clock, const char *clk_name)
-{
-       struct clk *clk;
-
-       clk = clk_get(&dss.pdev->dev, clk_name);
-
-       if (IS_ERR(clk)) {
-               DSSERR("can't get clock %s", clk_name);
-               return PTR_ERR(clk);
-       }
-
-       *clock = clk;
-
-       DSSDBG("clk %s, rate %ld\n", clk_name, clk_get_rate(clk));
-
-       return 0;
-}
-
-static int dss_get_clocks(void)
-{
-       int r;
-       struct omap_display_platform_data *pdata = dss.pdev->dev.platform_data;
-
-       dss.dss_ick = NULL;
-       dss.dss_fck = NULL;
-       dss.dss_sys_clk = NULL;
-       dss.dss_tv_fck = NULL;
-       dss.dss_video_fck = NULL;
-
-       r = dss_get_clock(&dss.dss_ick, "ick");
-       if (r)
-               goto err;
-
-       r = dss_get_clock(&dss.dss_fck, "fck");
-       if (r)
-               goto err;
-
-       if (!pdata->opt_clock_available) {
-               r = -ENODEV;
-               goto err;
-       }
-
-       if (pdata->opt_clock_available("sys_clk")) {
-               r = dss_get_clock(&dss.dss_sys_clk, "sys_clk");
-               if (r)
-                       goto err;
-       }
-
-       if (pdata->opt_clock_available("tv_clk")) {
-               r = dss_get_clock(&dss.dss_tv_fck, "tv_clk");
-               if (r)
-                       goto err;
-       }
-
-       if (pdata->opt_clock_available("video_clk")) {
-               r = dss_get_clock(&dss.dss_video_fck, "video_clk");
-               if (r)
-                       goto err;
-       }
-
-       return 0;
-
-err:
-       if (dss.dss_ick)
-               clk_put(dss.dss_ick);
-       if (dss.dss_fck)
-               clk_put(dss.dss_fck);
-       if (dss.dss_sys_clk)
-               clk_put(dss.dss_sys_clk);
-       if (dss.dss_tv_fck)
-               clk_put(dss.dss_tv_fck);
-       if (dss.dss_video_fck)
-               clk_put(dss.dss_video_fck);
-
        return r;
 }
 
 static void dss_put_clocks(void)
 {
-       if (dss.dss_video_fck)
-               clk_put(dss.dss_video_fck);
-       if (dss.dss_tv_fck)
-               clk_put(dss.dss_tv_fck);
-       if (dss.dss_sys_clk)
-               clk_put(dss.dss_sys_clk);
-       clk_put(dss.dss_fck);
-       clk_put(dss.dss_ick);
-}
-
-unsigned long dss_clk_get_rate(enum dss_clock clk)
-{
-       switch (clk) {
-       case DSS_CLK_ICK:
-               return clk_get_rate(dss.dss_ick);
-       case DSS_CLK_FCK:
-               return clk_get_rate(dss.dss_fck);
-       case DSS_CLK_SYSCK:
-               return clk_get_rate(dss.dss_sys_clk);
-       case DSS_CLK_TVFCK:
-               return clk_get_rate(dss.dss_tv_fck);
-       case DSS_CLK_VIDFCK:
-               return clk_get_rate(dss.dss_video_fck);
-       }
-
-       BUG();
-       return 0;
-}
-
-static unsigned count_clk_bits(enum dss_clock clks)
-{
-       unsigned num_clks = 0;
-
-       if (clks & DSS_CLK_ICK)
-               ++num_clks;
-       if (clks & DSS_CLK_FCK)
-               ++num_clks;
-       if (clks & DSS_CLK_SYSCK)
-               ++num_clks;
-       if (clks & DSS_CLK_TVFCK)
-               ++num_clks;
-       if (clks & DSS_CLK_VIDFCK)
-               ++num_clks;
-
-       return num_clks;
-}
-
-static void dss_clk_enable_no_ctx(enum dss_clock clks)
-{
-       unsigned num_clks = count_clk_bits(clks);
-
-       if (clks & DSS_CLK_ICK)
-               clk_enable(dss.dss_ick);
-       if (clks & DSS_CLK_FCK)
-               clk_enable(dss.dss_fck);
-       if ((clks & DSS_CLK_SYSCK) && dss.dss_sys_clk)
-               clk_enable(dss.dss_sys_clk);
-       if ((clks & DSS_CLK_TVFCK) && dss.dss_tv_fck)
-               clk_enable(dss.dss_tv_fck);
-       if ((clks & DSS_CLK_VIDFCK) && dss.dss_video_fck)
-               clk_enable(dss.dss_video_fck);
-
-       dss.num_clks_enabled += num_clks;
-}
-
-void dss_clk_enable(enum dss_clock clks)
-{
-       bool check_ctx = dss.num_clks_enabled == 0;
-
-       dss_clk_enable_no_ctx(clks);
-
-       /*
-        * HACK: On omap4 the registers may not be accessible right after
-        * enabling the clocks. At some point this will be handled by
-        * pm_runtime, but for the time begin this should make things work.
-        */
-       if (cpu_is_omap44xx() && check_ctx)
-               udelay(10);
-
-       if (check_ctx && cpu_is_omap34xx() && dss_need_ctx_restore())
-               restore_all_ctx();
+       if (dss.dpll4_m4_ck)
+               clk_put(dss.dpll4_m4_ck);
+       clk_put(dss.dss_clk);
 }
 
-static void dss_clk_disable_no_ctx(enum dss_clock clks)
+struct clk *dss_get_ick(void)
 {
-       unsigned num_clks = count_clk_bits(clks);
-
-       if (clks & DSS_CLK_ICK)
-               clk_disable(dss.dss_ick);
-       if (clks & DSS_CLK_FCK)
-               clk_disable(dss.dss_fck);
-       if ((clks & DSS_CLK_SYSCK) && dss.dss_sys_clk)
-               clk_disable(dss.dss_sys_clk);
-       if ((clks & DSS_CLK_TVFCK) && dss.dss_tv_fck)
-               clk_disable(dss.dss_tv_fck);
-       if ((clks & DSS_CLK_VIDFCK) && dss.dss_video_fck)
-               clk_disable(dss.dss_video_fck);
-
-       dss.num_clks_enabled -= num_clks;
+       return clk_get(&dss.pdev->dev, "ick");
 }
 
-void dss_clk_disable(enum dss_clock clks)
+int dss_runtime_get(void)
 {
-       if (cpu_is_omap34xx()) {
-               unsigned num_clks = count_clk_bits(clks);
-
-               BUG_ON(dss.num_clks_enabled < num_clks);
+       int r;
 
-               if (dss.num_clks_enabled == num_clks)
-                       save_all_ctx();
-       }
+       DSSDBG("dss_runtime_get\n");
 
-       dss_clk_disable_no_ctx(clks);
+       r = pm_runtime_get_sync(&dss.pdev->dev);
+       WARN_ON(r < 0);
+       return r < 0 ? r : 0;
 }
 
-static void dss_clk_enable_all_no_ctx(void)
+void dss_runtime_put(void)
 {
-       enum dss_clock clks;
-
-       clks = DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_SYSCK | DSS_CLK_TVFCK;
-       if (cpu_is_omap34xx())
-               clks |= DSS_CLK_VIDFCK;
-       dss_clk_enable_no_ctx(clks);
-}
-
-static void dss_clk_disable_all_no_ctx(void)
-{
-       enum dss_clock clks;
+       int r;
 
-       clks = DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_SYSCK | DSS_CLK_TVFCK;
-       if (cpu_is_omap34xx())
-               clks |= DSS_CLK_VIDFCK;
-       dss_clk_disable_no_ctx(clks);
-}
+       DSSDBG("dss_runtime_put\n");
 
-#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
-/* CLOCKS */
-static void core_dump_clocks(struct seq_file *s)
-{
-       int i;
-       struct clk *clocks[5] = {
-               dss.dss_ick,
-               dss.dss_fck,
-               dss.dss_sys_clk,
-               dss.dss_tv_fck,
-               dss.dss_video_fck
-       };
-
-       const char *names[5] = {
-               "ick",
-               "fck",
-               "sys_clk",
-               "tv_fck",
-               "video_fck"
-       };
-
-       seq_printf(s, "- CORE -\n");
-
-       seq_printf(s, "internal clk count\t\t%u\n", dss.num_clks_enabled);
-
-       for (i = 0; i < 5; i++) {
-               if (!clocks[i])
-                       continue;
-               seq_printf(s, "%s (%s)%*s\t%lu\t%d\n",
-                               names[i],
-                               clocks[i]->name,
-                               24 - strlen(names[i]) - strlen(clocks[i]->name),
-                               "",
-                               clk_get_rate(clocks[i]),
-                               clocks[i]->usecount);
-       }
+       r = pm_runtime_put(&dss.pdev->dev);
+       WARN_ON(r < 0);
 }
-#endif /* defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) */
 
 /* DEBUGFS */
 #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
 void dss_debug_dump_clocks(struct seq_file *s)
 {
-       core_dump_clocks(s);
        dss_dump_clocks(s);
        dispc_dump_clocks(s);
 #ifdef CONFIG_OMAP2_DSS_DSI
@@ -1089,28 +729,51 @@ void dss_debug_dump_clocks(struct seq_file *s)
 }
 #endif
 
-
 /* DSS HW IP initialisation */
 static int omap_dsshw_probe(struct platform_device *pdev)
 {
+       struct resource *dss_mem;
+       u32 rev;
        int r;
 
        dss.pdev = pdev;
 
+       dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0);
+       if (!dss_mem) {
+               DSSERR("can't get IORESOURCE_MEM DSS\n");
+               r = -EINVAL;
+               goto err_ioremap;
+       }
+       dss.base = ioremap(dss_mem->start, resource_size(dss_mem));
+       if (!dss.base) {
+               DSSERR("can't ioremap DSS\n");
+               r = -ENOMEM;
+               goto err_ioremap;
+       }
+
        r = dss_get_clocks();
        if (r)
                goto err_clocks;
 
-       dss_clk_enable_all_no_ctx();
+       pm_runtime_enable(&pdev->dev);
 
-       dss.ctx_id = dss_get_ctx_id();
-       DSSDBG("initial ctx id %u\n", dss.ctx_id);
+       r = dss_runtime_get();
+       if (r)
+               goto err_runtime_get;
 
-       r = dss_init();
-       if (r) {
-               DSSERR("Failed to initialize DSS\n");
-               goto err_dss;
-       }
+       /* Select DPLL */
+       REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
+
+#ifdef CONFIG_OMAP2_DSS_VENC
+       REG_FLD_MOD(DSS_CONTROL, 1, 4, 4);      /* venc dac demen */
+       REG_FLD_MOD(DSS_CONTROL, 1, 3, 3);      /* venc clock 4x enable */
+       REG_FLD_MOD(DSS_CONTROL, 0, 2, 2);      /* venc clock mode = normal */
+#endif
+       dss.dsi_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
+       dss.dsi_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
+       dss.dispc_clk_source = OMAP_DSS_CLK_SRC_FCK;
+       dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
+       dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
 
        r = dpi_init();
        if (r) {
@@ -1124,42 +787,66 @@ static int omap_dsshw_probe(struct platform_device *pdev)
                goto err_sdi;
        }
 
-       dss_clk_disable_all_no_ctx();
+       rev = dss_read_reg(DSS_REVISION);
+       printk(KERN_INFO "OMAP DSS rev %d.%d\n",
+                       FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
+
+       dss_runtime_put();
+
        return 0;
 err_sdi:
        dpi_exit();
 err_dpi:
-       dss_exit();
-err_dss:
-       dss_clk_disable_all_no_ctx();
+       dss_runtime_put();
+err_runtime_get:
+       pm_runtime_disable(&pdev->dev);
        dss_put_clocks();
 err_clocks:
+       iounmap(dss.base);
+err_ioremap:
        return r;
 }
 
 static int omap_dsshw_remove(struct platform_device *pdev)
 {
+       dpi_exit();
+       sdi_exit();
 
-       dss_exit();
+       iounmap(dss.base);
 
-       /*
-        * As part of hwmod changes, DSS is not the only controller of dss
-        * clocks; hwmod framework itself will also enable clocks during hwmod
-        * init for dss, and autoidle is set in h/w for DSS. Hence, there's no
-        * need to disable clocks if their usecounts > 1.
-        */
-       WARN_ON(dss.num_clks_enabled > 0);
+       pm_runtime_disable(&pdev->dev);
 
        dss_put_clocks();
+
+       return 0;
+}
+
+static int dss_runtime_suspend(struct device *dev)
+{
+       dss_save_context();
+       clk_disable(dss.dss_clk);
        return 0;
 }
 
+static int dss_runtime_resume(struct device *dev)
+{
+       clk_enable(dss.dss_clk);
+       dss_restore_context();
+       return 0;
+}
+
+static const struct dev_pm_ops dss_pm_ops = {
+       .runtime_suspend = dss_runtime_suspend,
+       .runtime_resume = dss_runtime_resume,
+};
+
 static struct platform_driver omap_dsshw_driver = {
        .probe          = omap_dsshw_probe,
        .remove         = omap_dsshw_remove,
        .driver         = {
                .name   = "omapdss_dss",
                .owner  = THIS_MODULE,
+               .pm     = &dss_pm_ops,
        },
 };
 
index 8ab6d43..9c94b11 100644 (file)
@@ -97,26 +97,12 @@ extern unsigned int dss_debug;
 #define FLD_MOD(orig, val, start, end) \
        (((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end))
 
-enum omap_burst_size {
-       OMAP_DSS_BURST_4x32 = 0,
-       OMAP_DSS_BURST_8x32 = 1,
-       OMAP_DSS_BURST_16x32 = 2,
-};
-
 enum omap_parallel_interface_mode {
        OMAP_DSS_PARALLELMODE_BYPASS,           /* MIPI DPI */
        OMAP_DSS_PARALLELMODE_RFBI,             /* MIPI DBI */
        OMAP_DSS_PARALLELMODE_DSI,
 };
 
-enum dss_clock {
-       DSS_CLK_ICK     = 1 << 0,       /* DSS_L3_ICLK and DSS_L4_ICLK */
-       DSS_CLK_FCK     = 1 << 1,       /* DSS1_ALWON_FCLK */
-       DSS_CLK_SYSCK   = 1 << 2,       /* DSS2_ALWON_FCLK */
-       DSS_CLK_TVFCK   = 1 << 3,       /* DSS_TV_FCLK */
-       DSS_CLK_VIDFCK  = 1 << 4,       /* DSS_96M_FCLK*/
-};
-
 enum dss_hdmi_venc_clk_source_select {
        DSS_VENC_TV_CLK = 0,
        DSS_HDMI_M_PCLK = 1,
@@ -194,7 +180,7 @@ void dss_uninit_device(struct platform_device *pdev,
 bool dss_use_replication(struct omap_dss_device *dssdev,
                enum omap_color_mode mode);
 void default_get_overlay_fifo_thresholds(enum omap_plane plane,
-               u32 fifo_size, enum omap_burst_size *burst_size,
+               u32 fifo_size, u32 burst_size,
                u32 *fifo_low, u32 *fifo_high);
 
 /* manager */
@@ -220,13 +206,12 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force);
 int dss_init_platform_driver(void);
 void dss_uninit_platform_driver(void);
 
+int dss_runtime_get(void);
+void dss_runtime_put(void);
+
+struct clk *dss_get_ick(void);
+
 void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select);
-void dss_save_context(void);
-void dss_restore_context(void);
-void dss_clk_enable(enum dss_clock clks);
-void dss_clk_disable(enum dss_clock clks);
-unsigned long dss_clk_get_rate(enum dss_clock clk);
-int dss_need_ctx_restore(void);
 const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src);
 void dss_dump_clocks(struct seq_file *s);
 
@@ -283,15 +268,15 @@ struct file_operations;
 int dsi_init_platform_driver(void);
 void dsi_uninit_platform_driver(void);
 
+int dsi_runtime_get(struct platform_device *dsidev);
+void dsi_runtime_put(struct platform_device *dsidev);
+
 void dsi_dump_clocks(struct seq_file *s);
 void dsi_create_debugfs_files_irq(struct dentry *debugfs_dir,
                const struct file_operations *debug_fops);
 void dsi_create_debugfs_files_reg(struct dentry *debugfs_dir,
                const struct file_operations *debug_fops);
 
-void dsi_save_context(void);
-void dsi_restore_context(void);
-
 int dsi_init_display(struct omap_dss_device *display);
 void dsi_irq_handler(void);
 unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev);
@@ -304,7 +289,7 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
                bool enable_hsdiv);
 void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes);
 void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
-               u32 fifo_size, enum omap_burst_size *burst_size,
+               u32 fifo_size, u32 burst_size,
                u32 *fifo_low, u32 *fifo_high);
 void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev);
 void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev);
@@ -317,6 +302,13 @@ static inline int dsi_init_platform_driver(void)
 static inline void dsi_uninit_platform_driver(void)
 {
 }
+static inline int dsi_runtime_get(struct platform_device *dsidev)
+{
+       return 0;
+}
+static inline void dsi_runtime_put(struct platform_device *dsidev)
+{
+}
 static inline unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev)
 {
        WARN("%s: DSI not compiled in, returning rate as 0\n", __func__);
@@ -384,8 +376,8 @@ void dispc_dump_regs(struct seq_file *s);
 void dispc_irq_handler(void);
 void dispc_fake_vsync_irq(void);
 
-void dispc_save_context(void);
-void dispc_restore_context(void);
+int dispc_runtime_get(void);
+void dispc_runtime_put(void);
 
 void dispc_enable_sidle(void);
 void dispc_disable_sidle(void);
@@ -398,10 +390,12 @@ void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable);
 void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height);
 void dispc_set_digit_size(u16 width, u16 height);
 u32 dispc_get_plane_fifo_size(enum omap_plane plane);
-void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high);
+void dispc_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high);
 void dispc_enable_fifomerge(bool enable);
-void dispc_set_burst_size(enum omap_plane plane,
-               enum omap_burst_size burst_size);
+u32 dispc_get_burst_size(enum omap_plane plane);
+void dispc_enable_cpr(enum omap_channel channel, bool enable);
+void dispc_set_cpr_coef(enum omap_channel channel,
+               struct omap_dss_cpr_coefs *coefs);
 
 void dispc_set_plane_ba0(enum omap_plane plane, u32 paddr);
 void dispc_set_plane_ba1(enum omap_plane plane, u32 paddr);
index 1c18888..b415c4e 100644 (file)
@@ -49,6 +49,9 @@ struct omap_dss_features {
        const enum omap_color_mode *supported_color_modes;
        const char * const *clksrc_names;
        const struct dss_param_range *dss_params;
+
+       const u32 buffer_size_unit;
+       const u32 burst_size_unit;
 };
 
 /* This struct is assigned to one of the below during initialization */
@@ -274,6 +277,8 @@ static const struct omap_dss_features omap2_dss_features = {
        .supported_color_modes = omap2_dss_supported_color_modes,
        .clksrc_names = omap2_dss_clk_source_names,
        .dss_params = omap2_dss_param_range,
+       .buffer_size_unit = 1,
+       .burst_size_unit = 8,
 };
 
 /* OMAP3 DSS Features */
@@ -286,7 +291,9 @@ static const struct omap_dss_features omap3430_dss_features = {
                FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
                FEAT_FUNCGATED | FEAT_ROWREPEATENABLE |
                FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF |
-               FEAT_DSI_PLL_FREQSEL | FEAT_DSI_REVERSE_TXCLKESC,
+               FEAT_DSI_PLL_FREQSEL | FEAT_DSI_REVERSE_TXCLKESC |
+               FEAT_VENC_REQUIRES_TV_DAC_CLK | FEAT_CPR | FEAT_PRELOAD |
+               FEAT_FIR_COEF_V,
 
        .num_mgrs = 2,
        .num_ovls = 3,
@@ -294,6 +301,8 @@ static const struct omap_dss_features omap3430_dss_features = {
        .supported_color_modes = omap3_dss_supported_color_modes,
        .clksrc_names = omap3_dss_clk_source_names,
        .dss_params = omap3_dss_param_range,
+       .buffer_size_unit = 1,
+       .burst_size_unit = 8,
 };
 
 static const struct omap_dss_features omap3630_dss_features = {
@@ -306,7 +315,8 @@ static const struct omap_dss_features omap3630_dss_features = {
                FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED |
                FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT |
                FEAT_RESIZECONF | FEAT_DSI_PLL_PWR_BUG |
-               FEAT_DSI_PLL_FREQSEL,
+               FEAT_DSI_PLL_FREQSEL | FEAT_CPR | FEAT_PRELOAD |
+               FEAT_FIR_COEF_V,
 
        .num_mgrs = 2,
        .num_ovls = 3,
@@ -314,6 +324,8 @@ static const struct omap_dss_features omap3630_dss_features = {
        .supported_color_modes = omap3_dss_supported_color_modes,
        .clksrc_names = omap3_dss_clk_source_names,
        .dss_params = omap3_dss_param_range,
+       .buffer_size_unit = 1,
+       .burst_size_unit = 8,
 };
 
 /* OMAP4 DSS Features */
@@ -327,7 +339,8 @@ static const struct omap_dss_features omap4430_es1_0_dss_features  = {
                FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1 |
                FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC |
                FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH |
-               FEAT_DSI_GNQ | FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2,
+               FEAT_DSI_GNQ | FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2 |
+               FEAT_CPR | FEAT_PRELOAD | FEAT_FIR_COEF_V,
 
        .num_mgrs = 3,
        .num_ovls = 3,
@@ -335,6 +348,8 @@ static const struct omap_dss_features omap4430_es1_0_dss_features  = {
        .supported_color_modes = omap4_dss_supported_color_modes,
        .clksrc_names = omap4_dss_clk_source_names,
        .dss_params = omap4_dss_param_range,
+       .buffer_size_unit = 16,
+       .burst_size_unit = 16,
 };
 
 /* For all the other OMAP4 versions */
@@ -348,7 +363,8 @@ static const struct omap_dss_features omap4_dss_features = {
                FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC |
                FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH |
                FEAT_DSI_GNQ | FEAT_HDMI_CTS_SWMODE |
-               FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2,
+               FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2 | FEAT_CPR |
+               FEAT_PRELOAD | FEAT_FIR_COEF_V,
 
        .num_mgrs = 3,
        .num_ovls = 3,
@@ -356,6 +372,8 @@ static const struct omap_dss_features omap4_dss_features = {
        .supported_color_modes = omap4_dss_supported_color_modes,
        .clksrc_names = omap4_dss_clk_source_names,
        .dss_params = omap4_dss_param_range,
+       .buffer_size_unit = 16,
+       .burst_size_unit = 16,
 };
 
 /* Functions returning values related to a DSS feature */
@@ -401,6 +419,16 @@ const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id)
        return omap_current_dss_features->clksrc_names[id];
 }
 
+u32 dss_feat_get_buffer_size_unit(void)
+{
+       return omap_current_dss_features->buffer_size_unit;
+}
+
+u32 dss_feat_get_burst_size_unit(void)
+{
+       return omap_current_dss_features->burst_size_unit;
+}
+
 /* DSS has_feature check */
 bool dss_has_feature(enum dss_feat_id id)
 {
index 07b346f..b7398cb 100644 (file)
@@ -51,6 +51,10 @@ enum dss_feat_id {
        FEAT_HDMI_CTS_SWMODE            = 1 << 19,
        FEAT_HANDLE_UV_SEPARATE         = 1 << 20,
        FEAT_ATTR2                      = 1 << 21,
+       FEAT_VENC_REQUIRES_TV_DAC_CLK   = 1 << 22,
+       FEAT_CPR                        = 1 << 23,
+       FEAT_PRELOAD                    = 1 << 24,
+       FEAT_FIR_COEF_V                 = 1 << 25,
 };
 
 /* DSS register field id */
@@ -90,6 +94,9 @@ bool dss_feat_color_mode_supported(enum omap_plane plane,
                enum omap_color_mode color_mode);
 const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id);
 
+u32 dss_feat_get_buffer_size_unit(void);       /* in bytes */
+u32 dss_feat_get_burst_size_unit(void);                /* in bytes */
+
 bool dss_has_feature(enum dss_feat_id id);
 void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end);
 void dss_features_init(void);
index b0555f4..256f27a 100644 (file)
@@ -29,6 +29,9 @@
 #include <linux/mutex.h>
 #include <linux/delay.h>
 #include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
 #include <video/omapdss.h>
 #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
        defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
@@ -51,6 +54,9 @@ static struct {
        u8 edid_set;
        bool custom_set;
        struct hdmi_config cfg;
+
+       struct clk *sys_clk;
+       struct clk *hdmi_clk;
 } hdmi;
 
 /*
@@ -162,6 +168,27 @@ static inline int hdmi_wait_for_bit_change(const struct hdmi_reg idx,
        return val;
 }
 
+static int hdmi_runtime_get(void)
+{
+       int r;
+
+       DSSDBG("hdmi_runtime_get\n");
+
+       r = pm_runtime_get_sync(&hdmi.pdev->dev);
+       WARN_ON(r < 0);
+       return r < 0 ? r : 0;
+}
+
+static void hdmi_runtime_put(void)
+{
+       int r;
+
+       DSSDBG("hdmi_runtime_put\n");
+
+       r = pm_runtime_put(&hdmi.pdev->dev);
+       WARN_ON(r < 0);
+}
+
 int hdmi_init_display(struct omap_dss_device *dssdev)
 {
        DSSDBG("init_display\n");
@@ -311,30 +338,11 @@ static int hdmi_phy_init(void)
        return 0;
 }
 
-static int hdmi_wait_softreset(void)
-{
-       /* reset W1 */
-       REG_FLD_MOD(HDMI_WP_SYSCONFIG, 0x1, 0, 0);
-
-       /* wait till SOFTRESET == 0 */
-       if (hdmi_wait_for_bit_change(HDMI_WP_SYSCONFIG, 0, 0, 0) != 0) {
-               DSSERR("sysconfig reset failed\n");
-               return -ETIMEDOUT;
-       }
-
-       return 0;
-}
-
 static int hdmi_pll_program(struct hdmi_pll_info *fmt)
 {
        u16 r = 0;
        enum hdmi_clk_refsel refsel;
 
-       /* wait for wrapper reset */
-       r = hdmi_wait_softreset();
-       if (r)
-               return r;
-
        r = hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF);
        if (r)
                return r;
@@ -1064,7 +1072,7 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
        unsigned long clkin, refclk;
        u32 mf;
 
-       clkin = dss_clk_get_rate(DSS_CLK_SYSCK) / 10000;
+       clkin = clk_get_rate(hdmi.sys_clk) / 10000;
        /*
         * Input clock is predivided by N + 1
         * out put of which is reference clk
@@ -1098,16 +1106,6 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
        DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
 }
 
-static void hdmi_enable_clocks(int enable)
-{
-       if (enable)
-               dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK |
-                               DSS_CLK_SYSCK | DSS_CLK_VIDFCK);
-       else
-               dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK |
-                               DSS_CLK_SYSCK | DSS_CLK_VIDFCK);
-}
-
 static int hdmi_power_on(struct omap_dss_device *dssdev)
 {
        int r, code = 0;
@@ -1115,7 +1113,9 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
        struct omap_video_timings *p;
        unsigned long phy;
 
-       hdmi_enable_clocks(1);
+       r = hdmi_runtime_get();
+       if (r)
+               return r;
 
        dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 0);
 
@@ -1180,7 +1180,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
 
        return 0;
 err:
-       hdmi_enable_clocks(0);
+       hdmi_runtime_put();
        return -EIO;
 }
 
@@ -1191,7 +1191,7 @@ static void hdmi_power_off(struct omap_dss_device *dssdev)
        hdmi_wp_video_start(0);
        hdmi_phy_off();
        hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF);
-       hdmi_enable_clocks(0);
+       hdmi_runtime_put();
 
        hdmi.edid_set = 0;
 }
@@ -1686,14 +1686,43 @@ static struct snd_soc_dai_driver hdmi_codec_dai_drv = {
 };
 #endif
 
+static int hdmi_get_clocks(struct platform_device *pdev)
+{
+       struct clk *clk;
+
+       clk = clk_get(&pdev->dev, "sys_clk");
+       if (IS_ERR(clk)) {
+               DSSERR("can't get sys_clk\n");
+               return PTR_ERR(clk);
+       }
+
+       hdmi.sys_clk = clk;
+
+       clk = clk_get(&pdev->dev, "dss_48mhz_clk");
+       if (IS_ERR(clk)) {
+               DSSERR("can't get hdmi_clk\n");
+               clk_put(hdmi.sys_clk);
+               return PTR_ERR(clk);
+       }
+
+       hdmi.hdmi_clk = clk;
+
+       return 0;
+}
+
+static void hdmi_put_clocks(void)
+{
+       if (hdmi.sys_clk)
+               clk_put(hdmi.sys_clk);
+       if (hdmi.hdmi_clk)
+               clk_put(hdmi.hdmi_clk);
+}
+
 /* HDMI HW IP initialisation */
 static int omapdss_hdmihw_probe(struct platform_device *pdev)
 {
        struct resource *hdmi_mem;
-#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
-       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
-       int ret;
-#endif
+       int r;
 
        hdmi.pdata = pdev->dev.platform_data;
        hdmi.pdev = pdev;
@@ -1713,17 +1742,25 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       r = hdmi_get_clocks(pdev);
+       if (r) {
+               iounmap(hdmi.base_wp);
+               return r;
+       }
+
+       pm_runtime_enable(&pdev->dev);
+
        hdmi_panel_init();
 
 #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
        defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
 
        /* Register ASoC codec DAI */
-       ret = snd_soc_register_codec(&pdev->dev, &hdmi_audio_codec_drv,
+       r = snd_soc_register_codec(&pdev->dev, &hdmi_audio_codec_drv,
                                        &hdmi_codec_dai_drv, 1);
-       if (ret) {
+       if (r) {
                DSSERR("can't register ASoC HDMI audio codec\n");
-               return ret;
+               return r;
        }
 #endif
        return 0;
@@ -1738,17 +1775,62 @@ static int omapdss_hdmihw_remove(struct platform_device *pdev)
        snd_soc_unregister_codec(&pdev->dev);
 #endif
 
+       pm_runtime_disable(&pdev->dev);
+
+       hdmi_put_clocks();
+
        iounmap(hdmi.base_wp);
 
        return 0;
 }
 
+static int hdmi_runtime_suspend(struct device *dev)
+{
+       clk_disable(hdmi.hdmi_clk);
+       clk_disable(hdmi.sys_clk);
+
+       dispc_runtime_put();
+       dss_runtime_put();
+
+       return 0;
+}
+
+static int hdmi_runtime_resume(struct device *dev)
+{
+       int r;
+
+       r = dss_runtime_get();
+       if (r < 0)
+               goto err_get_dss;
+
+       r = dispc_runtime_get();
+       if (r < 0)
+               goto err_get_dispc;
+
+
+       clk_enable(hdmi.sys_clk);
+       clk_enable(hdmi.hdmi_clk);
+
+       return 0;
+
+err_get_dispc:
+       dss_runtime_put();
+err_get_dss:
+       return r;
+}
+
+static const struct dev_pm_ops hdmi_pm_ops = {
+       .runtime_suspend = hdmi_runtime_suspend,
+       .runtime_resume = hdmi_runtime_resume,
+};
+
 static struct platform_driver omapdss_hdmihw_driver = {
        .probe          = omapdss_hdmihw_probe,
        .remove         = omapdss_hdmihw_remove,
        .driver         = {
                .name   = "omapdss_hdmi",
                .owner  = THIS_MODULE,
+               .pm     = &hdmi_pm_ops,
        },
 };
 
index 9aeea50..13d72d5 100644 (file)
@@ -275,6 +275,108 @@ static ssize_t manager_alpha_blending_enabled_store(
        return size;
 }
 
+static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr,
+               char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.cpr_enable);
+}
+
+static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr,
+               const char *buf, size_t size)
+{
+       struct omap_overlay_manager_info info;
+       int v;
+       int r;
+       bool enable;
+
+       if (!dss_has_feature(FEAT_CPR))
+               return -ENODEV;
+
+       r = kstrtoint(buf, 0, &v);
+       if (r)
+               return r;
+
+       enable = !!v;
+
+       mgr->get_manager_info(mgr, &info);
+
+       if (info.cpr_enable == enable)
+               return size;
+
+       info.cpr_enable = enable;
+
+       r = mgr->set_manager_info(mgr, &info);
+       if (r)
+               return r;
+
+       r = mgr->apply(mgr);
+       if (r)
+               return r;
+
+       return size;
+}
+
+static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr,
+               char *buf)
+{
+       struct omap_overlay_manager_info info;
+
+       mgr->get_manager_info(mgr, &info);
+
+       return snprintf(buf, PAGE_SIZE,
+                       "%d %d %d %d %d %d %d %d %d\n",
+                       info.cpr_coefs.rr,
+                       info.cpr_coefs.rg,
+                       info.cpr_coefs.rb,
+                       info.cpr_coefs.gr,
+                       info.cpr_coefs.gg,
+                       info.cpr_coefs.gb,
+                       info.cpr_coefs.br,
+                       info.cpr_coefs.bg,
+                       info.cpr_coefs.bb);
+}
+
+static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr,
+               const char *buf, size_t size)
+{
+       struct omap_overlay_manager_info info;
+       struct omap_dss_cpr_coefs coefs;
+       int r, i;
+       s16 *arr;
+
+       if (!dss_has_feature(FEAT_CPR))
+               return -ENODEV;
+
+       if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd",
+                               &coefs.rr, &coefs.rg, &coefs.rb,
+                               &coefs.gr, &coefs.gg, &coefs.gb,
+                               &coefs.br, &coefs.bg, &coefs.bb) != 9)
+               return -EINVAL;
+
+       arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb,
+               coefs.gr, coefs.gg, coefs.gb,
+               coefs.br, coefs.bg, coefs.bb };
+
+       for (i = 0; i < 9; ++i) {
+               if (arr[i] < -512 || arr[i] > 511)
+                       return -EINVAL;
+       }
+
+       mgr->get_manager_info(mgr, &info);
+
+       info.cpr_coefs = coefs;
+
+       r = mgr->set_manager_info(mgr, &info);
+       if (r)
+               return r;
+
+       r = mgr->apply(mgr);
+       if (r)
+               return r;
+
+       return size;
+}
+
 struct manager_attribute {
        struct attribute attr;
        ssize_t (*show)(struct omap_overlay_manager *, char *);
@@ -300,6 +402,12 @@ static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR,
 static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR,
                manager_alpha_blending_enabled_show,
                manager_alpha_blending_enabled_store);
+static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR,
+               manager_cpr_enable_show,
+               manager_cpr_enable_store);
+static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR,
+               manager_cpr_coef_show,
+               manager_cpr_coef_store);
 
 
 static struct attribute *manager_sysfs_attrs[] = {
@@ -310,6 +418,8 @@ static struct attribute *manager_sysfs_attrs[] = {
        &manager_attr_trans_key_value.attr,
        &manager_attr_trans_key_enabled.attr,
        &manager_attr_alpha_blending_enabled.attr,
+       &manager_attr_cpr_enable.attr,
+       &manager_attr_cpr_coef.attr,
        NULL
 };
 
@@ -391,33 +501,14 @@ struct overlay_cache_data {
 
        bool enabled;
 
-       u32 paddr;
-       void __iomem *vaddr;
-       u32 p_uv_addr; /* relevant for NV12 format only */
-       u16 screen_width;
-       u16 width;
-       u16 height;
-       enum omap_color_mode color_mode;
-       u8 rotation;
-       enum omap_dss_rotation_type rotation_type;
-       bool mirror;
-
-       u16 pos_x;
-       u16 pos_y;
-       u16 out_width;  /* if 0, out_width == width */
-       u16 out_height; /* if 0, out_height == height */
-       u8 global_alpha;
-       u8 pre_mult_alpha;
+       struct omap_overlay_info info;
 
        enum omap_channel channel;
        bool replication;
        bool ilace;
 
-       enum omap_burst_size burst_size;
        u32 fifo_low;
        u32 fifo_high;
-
-       bool manual_update;
 };
 
 struct manager_cache_data {
@@ -429,15 +520,8 @@ struct manager_cache_data {
         * VSYNC/EVSYNC */
        bool shadow_dirty;
 
-       u32 default_color;
-
-       enum omap_dss_trans_key_type trans_key_type;
-       u32 trans_key;
-       bool trans_enabled;
-
-       bool alpha_enabled;
+       struct omap_overlay_manager_info info;
 
-       bool manual_upd_display;
        bool manual_update;
        bool do_manual_update;
 
@@ -539,24 +623,15 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
        if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
                return 0;
 
+       if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
+               return 0;
+
        if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
                        || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
                irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
        } else {
-               if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
-                       enum omap_dss_update_mode mode;
-                       mode = dssdev->driver->get_update_mode(dssdev);
-                       if (mode != OMAP_DSS_UPDATE_AUTO)
-                               return 0;
-
-                       irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
-                               DISPC_IRQ_FRAMEDONE
-                               : DISPC_IRQ_FRAMEDONE2;
-               } else {
-                       irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
-                               DISPC_IRQ_VSYNC
-                               : DISPC_IRQ_VSYNC2;
-               }
+               irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
+                       DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2;
        }
 
        mc = &dss_cache.manager_cache[mgr->id];
@@ -617,24 +692,15 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
        if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
                return 0;
 
+       if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
+               return 0;
+
        if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
                        || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
                irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
        } else {
-               if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
-                       enum omap_dss_update_mode mode;
-                       mode = dssdev->driver->get_update_mode(dssdev);
-                       if (mode != OMAP_DSS_UPDATE_AUTO)
-                               return 0;
-
-                       irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
-                               DISPC_IRQ_FRAMEDONE
-                               : DISPC_IRQ_FRAMEDONE2;
-               } else {
-                       irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
-                               DISPC_IRQ_VSYNC
-                               : DISPC_IRQ_VSYNC2;
-               }
+               irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
+                       DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2;
        }
 
        oc = &dss_cache.overlay_cache[ovl->id];
@@ -720,10 +786,12 @@ static bool rectangle_intersects(int x1, int y1, int w1, int h1,
 
 static bool dispc_is_overlay_scaled(struct overlay_cache_data *oc)
 {
-       if (oc->out_width != 0 && oc->width != oc->out_width)
+       struct omap_overlay_info *oi = &oc->info;
+
+       if (oi->out_width != 0 && oi->width != oi->out_width)
                return true;
 
-       if (oc->out_height != 0 && oc->height != oc->out_height)
+       if (oi->out_height != 0 && oi->height != oi->out_height)
                return true;
 
        return false;
@@ -733,6 +801,8 @@ static int configure_overlay(enum omap_plane plane)
 {
        struct overlay_cache_data *c;
        struct manager_cache_data *mc;
+       struct omap_overlay_info *oi;
+       struct omap_overlay_manager_info *mi;
        u16 outw, outh;
        u16 x, y, w, h;
        u32 paddr;
@@ -742,6 +812,7 @@ static int configure_overlay(enum omap_plane plane)
        DSSDBGF("%d", plane);
 
        c = &dss_cache.overlay_cache[plane];
+       oi = &c->info;
 
        if (!c->enabled) {
                dispc_enable_plane(plane, 0);
@@ -749,21 +820,22 @@ static int configure_overlay(enum omap_plane plane)
        }
 
        mc = &dss_cache.manager_cache[c->channel];
+       mi = &mc->info;
 
-       x = c->pos_x;
-       y = c->pos_y;
-       w = c->width;
-       h = c->height;
-       outw = c->out_width == 0 ? c->width : c->out_width;
-       outh = c->out_height == 0 ? c->height : c->out_height;
-       paddr = c->paddr;
+       x = oi->pos_x;
+       y = oi->pos_y;
+       w = oi->width;
+       h = oi->height;
+       outw = oi->out_width == 0 ? oi->width : oi->out_width;
+       outh = oi->out_height == 0 ? oi->height : oi->out_height;
+       paddr = oi->paddr;
 
        orig_w = w;
        orig_h = h;
        orig_outw = outw;
        orig_outh = outh;
 
-       if (c->manual_update && mc->do_manual_update) {
+       if (mc->manual_update && mc->do_manual_update) {
                unsigned bpp;
                unsigned scale_x_m = w, scale_x_d = outw;
                unsigned scale_y_m = h, scale_y_d = outh;
@@ -775,7 +847,7 @@ static int configure_overlay(enum omap_plane plane)
                        return 0;
                }
 
-               switch (c->color_mode) {
+               switch (oi->color_mode) {
                case OMAP_DSS_COLOR_NV12:
                        bpp = 8;
                        break;
@@ -805,23 +877,23 @@ static int configure_overlay(enum omap_plane plane)
                        BUG();
                }
 
-               if (mc->x > c->pos_x) {
+               if (mc->x > oi->pos_x) {
                        x = 0;
-                       outw -= (mc->x - c->pos_x);
-                       paddr += (mc->x - c->pos_x) *
+                       outw -= (mc->x - oi->pos_x);
+                       paddr += (mc->x - oi->pos_x) *
                                scale_x_m / scale_x_d * bpp / 8;
                } else {
-                       x = c->pos_x - mc->x;
+                       x = oi->pos_x - mc->x;
                }
 
-               if (mc->y > c->pos_y) {
+               if (mc->y > oi->pos_y) {
                        y = 0;
-                       outh -= (mc->y - c->pos_y);
-                       paddr += (mc->y - c->pos_y) *
+                       outh -= (mc->y - oi->pos_y);
+                       paddr += (mc->y - oi->pos_y) *
                                scale_y_m / scale_y_d *
-                               c->screen_width * bpp / 8;
+                               oi->screen_width * bpp / 8;
                } else {
-                       y = c->pos_y - mc->y;
+                       y = oi->pos_y - mc->y;
                }
 
                if (mc->w < (x + outw))
@@ -840,8 +912,8 @@ static int configure_overlay(enum omap_plane plane)
                 * the width if the original width was bigger.
                 */
                if ((w & 1) &&
-                               (c->color_mode == OMAP_DSS_COLOR_YUV2 ||
-                                c->color_mode == OMAP_DSS_COLOR_UYVY)) {
+                               (oi->color_mode == OMAP_DSS_COLOR_YUV2 ||
+                                oi->color_mode == OMAP_DSS_COLOR_UYVY)) {
                        if (orig_w > w)
                                w += 1;
                        else
@@ -851,19 +923,19 @@ static int configure_overlay(enum omap_plane plane)
 
        r = dispc_setup_plane(plane,
                        paddr,
-                       c->screen_width,
+                       oi->screen_width,
                        x, y,
                        w, h,
                        outw, outh,
-                       c->color_mode,
+                       oi->color_mode,
                        c->ilace,
-                       c->rotation_type,
-                       c->rotation,
-                       c->mirror,
-                       c->global_alpha,
-                       c->pre_mult_alpha,
+                       oi->rotation_type,
+                       oi->rotation,
+                       oi->mirror,
+                       oi->global_alpha,
+                       oi->pre_mult_alpha,
                        c->channel,
-                       c->p_uv_addr);
+                       oi->p_uv_addr);
 
        if (r) {
                /* this shouldn't happen */
@@ -874,8 +946,7 @@ static int configure_overlay(enum omap_plane plane)
 
        dispc_enable_replication(plane, c->replication);
 
-       dispc_set_burst_size(plane, c->burst_size);
-       dispc_setup_plane_fifo(plane, c->fifo_low, c->fifo_high);
+       dispc_set_fifo_threshold(plane, c->fifo_low, c->fifo_high);
 
        dispc_enable_plane(plane, 1);
 
@@ -884,16 +955,21 @@ static int configure_overlay(enum omap_plane plane)
 
 static void configure_manager(enum omap_channel channel)
 {
-       struct manager_cache_data *c;
+       struct omap_overlay_manager_info *mi;
 
        DSSDBGF("%d", channel);
 
-       c = &dss_cache.manager_cache[channel];
+       /* picking info from the cache */
+       mi = &dss_cache.manager_cache[channel].info;
 
-       dispc_set_default_color(channel, c->default_color);
-       dispc_set_trans_key(channel, c->trans_key_type, c->trans_key);
-       dispc_enable_trans_key(channel, c->trans_enabled);
-       dispc_enable_alpha_blending(channel, c->alpha_enabled);
+       dispc_set_default_color(channel, mi->default_color);
+       dispc_set_trans_key(channel, mi->trans_key_type, mi->trans_key);
+       dispc_enable_trans_key(channel, mi->trans_enabled);
+       dispc_enable_alpha_blending(channel, mi->alpha_enabled);
+       if (dss_has_feature(FEAT_CPR)) {
+               dispc_enable_cpr(channel, mi->cpr_enable);
+               dispc_set_cpr_coef(channel, &mi->cpr_coefs);
+       }
 }
 
 /* configure_dispc() tries to write values from cache to shadow registers.
@@ -928,7 +1004,7 @@ static int configure_dispc(void)
                if (!oc->dirty)
                        continue;
 
-               if (oc->manual_update && !mc->do_manual_update)
+               if (mc->manual_update && !mc->do_manual_update)
                        continue;
 
                if (mgr_busy[oc->channel]) {
@@ -976,7 +1052,7 @@ static int configure_dispc(void)
                /* We don't need GO with manual update display. LCD iface will
                 * always be turned off after frame, and new settings will be
                 * taken in to use at next update */
-               if (!mc->manual_upd_display)
+               if (!mc->manual_update)
                        dispc_go(i);
        }
 
@@ -1011,6 +1087,7 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev,
 {
        struct overlay_cache_data *oc;
        struct manager_cache_data *mc;
+       struct omap_overlay_info *oi;
        const int num_ovls = dss_feat_get_num_ovls();
        struct omap_overlay_manager *mgr;
        int i;
@@ -1053,6 +1130,7 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev,
                        unsigned outw, outh;
 
                        oc = &dss_cache.overlay_cache[i];
+                       oi = &oc->info;
 
                        if (oc->channel != mgr->id)
                                continue;
@@ -1068,39 +1146,39 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev,
                        if (!dispc_is_overlay_scaled(oc))
                                continue;
 
-                       outw = oc->out_width == 0 ?
-                               oc->width : oc->out_width;
-                       outh = oc->out_height == 0 ?
-                               oc->height : oc->out_height;
+                       outw = oi->out_width == 0 ?
+                               oi->width : oi->out_width;
+                       outh = oi->out_height == 0 ?
+                               oi->height : oi->out_height;
 
                        /* is the overlay outside the update region? */
                        if (!rectangle_intersects(x, y, w, h,
-                                               oc->pos_x, oc->pos_y,
+                                               oi->pos_x, oi->pos_y,
                                                outw, outh))
                                continue;
 
                        /* if the overlay totally inside the update region? */
-                       if (rectangle_subset(oc->pos_x, oc->pos_y, outw, outh,
+                       if (rectangle_subset(oi->pos_x, oi->pos_y, outw, outh,
                                                x, y, w, h))
                                continue;
 
-                       if (x > oc->pos_x)
-                               x1 = oc->pos_x;
+                       if (x > oi->pos_x)
+                               x1 = oi->pos_x;
                        else
                                x1 = x;
 
-                       if (y > oc->pos_y)
-                               y1 = oc->pos_y;
+                       if (y > oi->pos_y)
+                               y1 = oi->pos_y;
                        else
                                y1 = y;
 
-                       if ((x + w) < (oc->pos_x + outw))
-                               x2 = oc->pos_x + outw;
+                       if ((x + w) < (oi->pos_x + outw))
+                               x2 = oi->pos_x + outw;
                        else
                                x2 = x + w;
 
-                       if ((y + h) < (oc->pos_y + outh))
-                               y2 = oc->pos_y + outh;
+                       if ((y + h) < (oi->pos_y + outh))
+                               y2 = oi->pos_y + outh;
                        else
                                y2 = y + h;
 
@@ -1236,6 +1314,10 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
 
        DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
 
+       r = dispc_runtime_get();
+       if (r)
+               return r;
+
        spin_lock_irqsave(&dss_cache.lock, flags);
 
        /* Configure overlays */
@@ -1275,23 +1357,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
 
                ovl->info_dirty = false;
                oc->dirty = true;
-
-               oc->paddr = ovl->info.paddr;
-               oc->vaddr = ovl->info.vaddr;
-               oc->p_uv_addr = ovl->info.p_uv_addr;
-               oc->screen_width = ovl->info.screen_width;
-               oc->width = ovl->info.width;
-               oc->height = ovl->info.height;
-               oc->color_mode = ovl->info.color_mode;
-               oc->rotation = ovl->info.rotation;
-               oc->rotation_type = ovl->info.rotation_type;
-               oc->mirror = ovl->info.mirror;
-               oc->pos_x = ovl->info.pos_x;
-               oc->pos_y = ovl->info.pos_y;
-               oc->out_width = ovl->info.out_width;
-               oc->out_height = ovl->info.out_height;
-               oc->global_alpha = ovl->info.global_alpha;
-               oc->pre_mult_alpha = ovl->info.pre_mult_alpha;
+               oc->info = ovl->info;
 
                oc->replication =
                        dss_use_replication(dssdev, ovl->info.color_mode);
@@ -1302,11 +1368,6 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
 
                oc->enabled = true;
 
-               oc->manual_update =
-                       dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
-                       dssdev->driver->get_update_mode(dssdev) !=
-                               OMAP_DSS_UPDATE_AUTO;
-
                ++num_planes_enabled;
        }
 
@@ -1334,20 +1395,10 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
 
                mgr->info_dirty = false;
                mc->dirty = true;
-
-               mc->default_color = mgr->info.default_color;
-               mc->trans_key_type = mgr->info.trans_key_type;
-               mc->trans_key = mgr->info.trans_key;
-               mc->trans_enabled = mgr->info.trans_enabled;
-               mc->alpha_enabled = mgr->info.alpha_enabled;
-
-               mc->manual_upd_display =
-                       dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
+               mc->info = mgr->info;
 
                mc->manual_update =
-                       dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
-                       dssdev->driver->get_update_mode(dssdev) !=
-                               OMAP_DSS_UPDATE_AUTO;
+                       dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
        }
 
        /* XXX TODO: Try to get fifomerge working. The problem is that it
@@ -1368,7 +1419,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
        /* Configure overlay fifos */
        for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
                struct omap_dss_device *dssdev;
-               u32 size;
+               u32 size, burst_size;
 
                ovl = omap_dss_get_overlay(i);
 
@@ -1386,6 +1437,8 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
                if (use_fifomerge)
                        size *= 3;
 
+               burst_size = dispc_get_burst_size(ovl->id);
+
                switch (dssdev->type) {
                case OMAP_DISPLAY_TYPE_DPI:
                case OMAP_DISPLAY_TYPE_DBI:
@@ -1393,13 +1446,13 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
                case OMAP_DISPLAY_TYPE_VENC:
                case OMAP_DISPLAY_TYPE_HDMI:
                        default_get_overlay_fifo_thresholds(ovl->id, size,
-                                       &oc->burst_size, &oc->fifo_low,
+                                       burst_size, &oc->fifo_low,
                                        &oc->fifo_high);
                        break;
 #ifdef CONFIG_OMAP2_DSS_DSI
                case OMAP_DISPLAY_TYPE_DSI:
                        dsi_get_overlay_fifo_thresholds(ovl->id, size,
-                                       &oc->burst_size, &oc->fifo_low,
+                                       burst_size, &oc->fifo_low,
                                        &oc->fifo_high);
                        break;
 #endif
@@ -1409,7 +1462,6 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
        }
 
        r = 0;
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
        if (!dss_cache.irq_enabled) {
                u32 mask;
 
@@ -1422,10 +1474,11 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
                dss_cache.irq_enabled = true;
        }
        configure_dispc();
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 
        spin_unlock_irqrestore(&dss_cache.lock, flags);
 
+       dispc_runtime_put();
+
        return r;
 }
 
index 0f08025..c84380c 100644 (file)
@@ -84,32 +84,42 @@ static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
 
        old_mgr = ovl->manager;
 
+       r = dispc_runtime_get();
+       if (r)
+               return r;
+
        /* detach old manager */
        if (old_mgr) {
                r = ovl->unset_manager(ovl);
                if (r) {
                        DSSERR("detach failed\n");
-                       return r;
+                       goto err;
                }
 
                r = old_mgr->apply(old_mgr);
                if (r)
-                       return r;
+                       goto err;
        }
 
        if (mgr) {
                r = ovl->set_manager(ovl, mgr);
                if (r) {
                        DSSERR("Failed to attach overlay\n");
-                       return r;
+                       goto err;
                }
 
                r = mgr->apply(mgr);
                if (r)
-                       return r;
+                       goto err;
        }
 
+       dispc_runtime_put();
+
        return size;
+
+err:
+       dispc_runtime_put();
+       return r;
 }
 
 static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf)
@@ -238,6 +248,9 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
        u8 alpha;
        struct omap_overlay_info info;
 
+       if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
+               return -ENODEV;
+
        r = kstrtou8(buf, 0, &alpha);
        if (r)
                return r;
@@ -504,7 +517,6 @@ static int omap_dss_set_manager(struct omap_overlay *ovl,
 
        ovl->manager = mgr;
 
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
        /* XXX: When there is an overlay on a DSI manual update display, and
         * the overlay is first disabled, then moved to tv, and enabled, we
         * seem to get SYNC_LOST_DIGIT error.
@@ -518,7 +530,6 @@ static int omap_dss_set_manager(struct omap_overlay *ovl,
         * the overlay, but before moving the overlay to TV.
         */
        dispc_set_channel_out(ovl->id, mgr->id);
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 
        return 0;
 }
@@ -719,6 +730,8 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
        }
 
        if (mgr) {
+               dispc_runtime_get();
+
                for (i = 0; i < dss_feat_get_num_ovls(); i++) {
                        struct omap_overlay *ovl;
                        ovl = omap_dss_get_overlay(i);
@@ -728,6 +741,8 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
                                omap_dss_set_manager(ovl, mgr);
                        }
                }
+
+               dispc_runtime_put();
        }
 }
 
index c06fbe0..39f4c59 100644 (file)
@@ -33,6 +33,8 @@
 #include <linux/hrtimer.h>
 #include <linux/seq_file.h>
 #include <linux/semaphore.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 
 #include <video/omapdss.h>
 #include "dss.h"
@@ -120,12 +122,25 @@ static inline u32 rfbi_read_reg(const struct rfbi_reg idx)
        return __raw_readl(rfbi.base + idx.idx);
 }
 
-static void rfbi_enable_clocks(bool enable)
+static int rfbi_runtime_get(void)
 {
-       if (enable)
-               dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
-       else
-               dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
+       int r;
+
+       DSSDBG("rfbi_runtime_get\n");
+
+       r = pm_runtime_get_sync(&rfbi.pdev->dev);
+       WARN_ON(r < 0);
+       return r < 0 ? r : 0;
+}
+
+static void rfbi_runtime_put(void)
+{
+       int r;
+
+       DSSDBG("rfbi_runtime_put\n");
+
+       r = pm_runtime_put(&rfbi.pdev->dev);
+       WARN_ON(r < 0);
 }
 
 void rfbi_bus_lock(void)
@@ -805,7 +820,8 @@ void rfbi_dump_regs(struct seq_file *s)
 {
 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r))
 
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
+       if (rfbi_runtime_get())
+               return;
 
        DUMPREG(RFBI_REVISION);
        DUMPREG(RFBI_SYSCONFIG);
@@ -836,7 +852,7 @@ void rfbi_dump_regs(struct seq_file *s)
        DUMPREG(RFBI_VSYNC_WIDTH);
        DUMPREG(RFBI_HSYNC_WIDTH);
 
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
+       rfbi_runtime_put();
 #undef DUMPREG
 }
 
@@ -844,7 +860,9 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
 {
        int r;
 
-       rfbi_enable_clocks(1);
+       r = rfbi_runtime_get();
+       if (r)
+               return r;
 
        r = omap_dss_start_device(dssdev);
        if (r) {
@@ -879,6 +897,7 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
 err1:
        omap_dss_stop_device(dssdev);
 err0:
+       rfbi_runtime_put();
        return r;
 }
 EXPORT_SYMBOL(omapdss_rfbi_display_enable);
@@ -889,7 +908,7 @@ void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev)
                        DISPC_IRQ_FRAMEDONE);
        omap_dss_stop_device(dssdev);
 
-       rfbi_enable_clocks(0);
+       rfbi_runtime_put();
 }
 EXPORT_SYMBOL(omapdss_rfbi_display_disable);
 
@@ -904,8 +923,9 @@ int rfbi_init_display(struct omap_dss_device *dssdev)
 static int omap_rfbihw_probe(struct platform_device *pdev)
 {
        u32 rev;
-       u32 l;
        struct resource *rfbi_mem;
+       struct clk *clk;
+       int r;
 
        rfbi.pdev = pdev;
 
@@ -914,46 +934,102 @@ static int omap_rfbihw_probe(struct platform_device *pdev)
        rfbi_mem = platform_get_resource(rfbi.pdev, IORESOURCE_MEM, 0);
        if (!rfbi_mem) {
                DSSERR("can't get IORESOURCE_MEM RFBI\n");
-               return -EINVAL;
+               r = -EINVAL;
+               goto err_ioremap;
        }
        rfbi.base = ioremap(rfbi_mem->start, resource_size(rfbi_mem));
        if (!rfbi.base) {
                DSSERR("can't ioremap RFBI\n");
-               return -ENOMEM;
+               r = -ENOMEM;
+               goto err_ioremap;
        }
 
-       rfbi_enable_clocks(1);
+       pm_runtime_enable(&pdev->dev);
+
+       r = rfbi_runtime_get();
+       if (r)
+               goto err_get_rfbi;
 
        msleep(10);
 
-       rfbi.l4_khz = dss_clk_get_rate(DSS_CLK_ICK) / 1000;
+       if (cpu_is_omap24xx() || cpu_is_omap34xx() || cpu_is_omap3630())
+               clk = dss_get_ick();
+       else
+               clk = clk_get(&pdev->dev, "ick");
+       if (IS_ERR(clk)) {
+               DSSERR("can't get ick\n");
+               r = PTR_ERR(clk);
+               goto err_get_ick;
+       }
+
+       rfbi.l4_khz = clk_get_rate(clk) / 1000;
 
-       /* Enable autoidle and smart-idle */
-       l = rfbi_read_reg(RFBI_SYSCONFIG);
-       l |= (1 << 0) | (2 << 3);
-       rfbi_write_reg(RFBI_SYSCONFIG, l);
+       clk_put(clk);
 
        rev = rfbi_read_reg(RFBI_REVISION);
        dev_dbg(&pdev->dev, "OMAP RFBI rev %d.%d\n",
               FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
 
-       rfbi_enable_clocks(0);
+       rfbi_runtime_put();
 
        return 0;
+
+err_get_ick:
+       rfbi_runtime_put();
+err_get_rfbi:
+       pm_runtime_disable(&pdev->dev);
+       iounmap(rfbi.base);
+err_ioremap:
+       return r;
 }
 
 static int omap_rfbihw_remove(struct platform_device *pdev)
 {
+       pm_runtime_disable(&pdev->dev);
        iounmap(rfbi.base);
        return 0;
 }
 
+static int rfbi_runtime_suspend(struct device *dev)
+{
+       dispc_runtime_put();
+       dss_runtime_put();
+
+       return 0;
+}
+
+static int rfbi_runtime_resume(struct device *dev)
+{
+       int r;
+
+       r = dss_runtime_get();
+       if (r < 0)
+               goto err_get_dss;
+
+       r = dispc_runtime_get();
+       if (r < 0)
+               goto err_get_dispc;
+
+       return 0;
+
+err_get_dispc:
+       dss_runtime_put();
+err_get_dss:
+       return r;
+}
+
+static const struct dev_pm_ops rfbi_pm_ops = {
+       .runtime_suspend = rfbi_runtime_suspend,
+       .runtime_resume = rfbi_runtime_resume,
+};
+
 static struct platform_driver omap_rfbihw_driver = {
        .probe          = omap_rfbihw_probe,
        .remove         = omap_rfbihw_remove,
        .driver         = {
                .name   = "omapdss_rfbi",
                .owner  = THIS_MODULE,
+               .pm     = &rfbi_pm_ops,
        },
 };
 
index 0bd4b03..3a688c8 100644 (file)
 #define DSS_SUBSYS_NAME "SDI"
 
 #include <linux/kernel.h>
-#include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/regulator/consumer.h>
 
 #include <video/omapdss.h>
-#include <plat/cpu.h>
 #include "dss.h"
 
 static struct {
@@ -60,14 +58,20 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
        r = omap_dss_start_device(dssdev);
        if (r) {
                DSSERR("failed to start device\n");
-               goto err0;
+               goto err_start_dev;
        }
 
        r = regulator_enable(sdi.vdds_sdi_reg);
        if (r)
-               goto err1;
+               goto err_reg_enable;
 
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
+       r = dss_runtime_get();
+       if (r)
+               goto err_get_dss;
+
+       r = dispc_runtime_get();
+       if (r)
+               goto err_get_dispc;
 
        sdi_basic_init(dssdev);
 
@@ -80,7 +84,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
        r = dss_calc_clock_div(1, t->pixel_clock * 1000,
                        &dss_cinfo, &dispc_cinfo);
        if (r)
-               goto err2;
+               goto err_calc_clock_div;
 
        fck = dss_cinfo.fck;
        lck_div = dispc_cinfo.lck_div;
@@ -101,27 +105,34 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
 
        r = dss_set_clock_div(&dss_cinfo);
        if (r)
-               goto err2;
+               goto err_set_dss_clock_div;
 
        r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
        if (r)
-               goto err2;
+               goto err_set_dispc_clock_div;
 
        dss_sdi_init(dssdev->phy.sdi.datapairs);
        r = dss_sdi_enable();
        if (r)
-               goto err1;
+               goto err_sdi_enable;
        mdelay(2);
 
        dssdev->manager->enable(dssdev->manager);
 
        return 0;
-err2:
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
+
+err_sdi_enable:
+err_set_dispc_clock_div:
+err_set_dss_clock_div:
+err_calc_clock_div:
+       dispc_runtime_put();
+err_get_dispc:
+       dss_runtime_put();
+err_get_dss:
        regulator_disable(sdi.vdds_sdi_reg);
-err1:
+err_reg_enable:
        omap_dss_stop_device(dssdev);
-err0:
+err_start_dev:
        return r;
 }
 EXPORT_SYMBOL(omapdss_sdi_display_enable);
@@ -132,7 +143,8 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
 
        dss_sdi_disable();
 
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
+       dispc_runtime_put();
+       dss_runtime_put();
 
        regulator_disable(sdi.vdds_sdi_reg);
 
index 980f919..173c664 100644 (file)
 #include <linux/seq_file.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
 
 #include <video/omapdss.h>
 #include <plat/cpu.h>
 
 #include "dss.h"
+#include "dss_features.h"
 
 /* Venc registers */
 #define VENC_REV_ID                            0x00
@@ -292,6 +294,9 @@ static struct {
        struct mutex venc_lock;
        u32 wss_data;
        struct regulator *vdda_dac_reg;
+
+       struct clk      *tv_clk;
+       struct clk      *tv_dac_clk;
 } venc;
 
 static inline void venc_write_reg(int idx, u32 val)
@@ -380,14 +385,25 @@ static void venc_reset(void)
 #endif
 }
 
-static void venc_enable_clocks(int enable)
+static int venc_runtime_get(void)
+{
+       int r;
+
+       DSSDBG("venc_runtime_get\n");
+
+       r = pm_runtime_get_sync(&venc.pdev->dev);
+       WARN_ON(r < 0);
+       return r < 0 ? r : 0;
+}
+
+static void venc_runtime_put(void)
 {
-       if (enable)
-               dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_TVFCK |
-                               DSS_CLK_VIDFCK);
-       else
-               dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_TVFCK |
-                               DSS_CLK_VIDFCK);
+       int r;
+
+       DSSDBG("venc_runtime_put\n");
+
+       r = pm_runtime_put(&venc.pdev->dev);
+       WARN_ON(r < 0);
 }
 
 static const struct venc_config *venc_timings_to_config(
@@ -406,8 +422,6 @@ static void venc_power_on(struct omap_dss_device *dssdev)
 {
        u32 l;
 
-       venc_enable_clocks(1);
-
        venc_reset();
        venc_write_config(venc_timings_to_config(&dssdev->panel.timings));
 
@@ -448,8 +462,6 @@ static void venc_power_off(struct omap_dss_device *dssdev)
                dssdev->platform_disable(dssdev);
 
        regulator_disable(venc.vdda_dac_reg);
-
-       venc_enable_clocks(0);
 }
 
 
@@ -487,6 +499,10 @@ static int venc_panel_enable(struct omap_dss_device *dssdev)
                goto err1;
        }
 
+       r = venc_runtime_get();
+       if (r)
+               goto err1;
+
        venc_power_on(dssdev);
 
        venc.wss_data = 0;
@@ -520,6 +536,8 @@ static void venc_panel_disable(struct omap_dss_device *dssdev)
 
        venc_power_off(dssdev);
 
+       venc_runtime_put();
+
        dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 
        omap_dss_stop_device(dssdev);
@@ -538,20 +556,6 @@ static int venc_panel_resume(struct omap_dss_device *dssdev)
        return venc_panel_enable(dssdev);
 }
 
-static enum omap_dss_update_mode venc_get_update_mode(
-               struct omap_dss_device *dssdev)
-{
-       return OMAP_DSS_UPDATE_AUTO;
-}
-
-static int venc_set_update_mode(struct omap_dss_device *dssdev,
-               enum omap_dss_update_mode mode)
-{
-       if (mode != OMAP_DSS_UPDATE_AUTO)
-               return -EINVAL;
-       return 0;
-}
-
 static void venc_get_timings(struct omap_dss_device *dssdev,
                        struct omap_video_timings *timings)
 {
@@ -598,6 +602,7 @@ static u32 venc_get_wss(struct omap_dss_device *dssdev)
 static int venc_set_wss(struct omap_dss_device *dssdev,        u32 wss)
 {
        const struct venc_config *config;
+       int r;
 
        DSSDBG("venc_set_wss\n");
 
@@ -608,16 +613,19 @@ static int venc_set_wss(struct omap_dss_device *dssdev,   u32 wss)
        /* Invert due to VENC_L21_WC_CTL:INV=1 */
        venc.wss_data = (wss ^ 0xfffff) << 8;
 
-       venc_enable_clocks(1);
+       r = venc_runtime_get();
+       if (r)
+               goto err;
 
        venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
                        venc.wss_data);
 
-       venc_enable_clocks(0);
+       venc_runtime_put();
 
+err:
        mutex_unlock(&venc.venc_lock);
 
-       return 0;
+       return r;
 }
 
 static struct omap_dss_driver venc_driver = {
@@ -632,9 +640,6 @@ static struct omap_dss_driver venc_driver = {
        .get_resolution = omapdss_default_get_resolution,
        .get_recommended_bpp = omapdss_default_get_recommended_bpp,
 
-       .set_update_mode = venc_set_update_mode,
-       .get_update_mode = venc_get_update_mode,
-
        .get_timings    = venc_get_timings,
        .set_timings    = venc_set_timings,
        .check_timings  = venc_check_timings,
@@ -673,7 +678,8 @@ void venc_dump_regs(struct seq_file *s)
 {
 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r))
 
-       venc_enable_clocks(1);
+       if (venc_runtime_get())
+               return;
 
        DUMPREG(VENC_F_CONTROL);
        DUMPREG(VENC_VIDOUT_CTRL);
@@ -717,16 +723,56 @@ void venc_dump_regs(struct seq_file *s)
        DUMPREG(VENC_OUTPUT_CONTROL);
        DUMPREG(VENC_OUTPUT_TEST);
 
-       venc_enable_clocks(0);
+       venc_runtime_put();
 
 #undef DUMPREG
 }
 
+static int venc_get_clocks(struct platform_device *pdev)
+{
+       struct clk *clk;
+
+       clk = clk_get(&pdev->dev, "fck");
+       if (IS_ERR(clk)) {
+               DSSERR("can't get fck\n");
+               return PTR_ERR(clk);
+       }
+
+       venc.tv_clk = clk;
+
+       if (dss_has_feature(FEAT_VENC_REQUIRES_TV_DAC_CLK)) {
+               if (cpu_is_omap34xx() || cpu_is_omap3630())
+                       clk = clk_get(&pdev->dev, "dss_96m_fck");
+               else
+                       clk = clk_get(&pdev->dev, "tv_dac_clk");
+               if (IS_ERR(clk)) {
+                       DSSERR("can't get tv_dac_clk\n");
+                       clk_put(venc.tv_clk);
+                       return PTR_ERR(clk);
+               }
+       } else {
+               clk = NULL;
+       }
+
+       venc.tv_dac_clk = clk;
+
+       return 0;
+}
+
+static void venc_put_clocks(void)
+{
+       if (venc.tv_clk)
+               clk_put(venc.tv_clk);
+       if (venc.tv_dac_clk)
+               clk_put(venc.tv_dac_clk);
+}
+
 /* VENC HW IP initialisation */
 static int omap_venchw_probe(struct platform_device *pdev)
 {
        u8 rev_id;
        struct resource *venc_mem;
+       int r;
 
        venc.pdev = pdev;
 
@@ -737,22 +783,40 @@ static int omap_venchw_probe(struct platform_device *pdev)
        venc_mem = platform_get_resource(venc.pdev, IORESOURCE_MEM, 0);
        if (!venc_mem) {
                DSSERR("can't get IORESOURCE_MEM VENC\n");
-               return -EINVAL;
+               r = -EINVAL;
+               goto err_ioremap;
        }
        venc.base = ioremap(venc_mem->start, resource_size(venc_mem));
        if (!venc.base) {
                DSSERR("can't ioremap VENC\n");
-               return -ENOMEM;
+               r = -ENOMEM;
+               goto err_ioremap;
        }
 
-       venc_enable_clocks(1);
+       r = venc_get_clocks(pdev);
+       if (r)
+               goto err_get_clk;
+
+       pm_runtime_enable(&pdev->dev);
+
+       r = venc_runtime_get();
+       if (r)
+               goto err_get_venc;
 
        rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
        dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id);
 
-       venc_enable_clocks(0);
+       venc_runtime_put();
 
        return omap_dss_register_driver(&venc_driver);
+
+err_get_venc:
+       pm_runtime_disable(&pdev->dev);
+       venc_put_clocks();
+err_get_clk:
+       iounmap(venc.base);
+err_ioremap:
+       return r;
 }
 
 static int omap_venchw_remove(struct platform_device *pdev)
@@ -763,16 +827,61 @@ static int omap_venchw_remove(struct platform_device *pdev)
        }
        omap_dss_unregister_driver(&venc_driver);
 
+       pm_runtime_disable(&pdev->dev);
+       venc_put_clocks();
+
        iounmap(venc.base);
        return 0;
 }
 
+static int venc_runtime_suspend(struct device *dev)
+{
+       if (venc.tv_dac_clk)
+               clk_disable(venc.tv_dac_clk);
+       clk_disable(venc.tv_clk);
+
+       dispc_runtime_put();
+       dss_runtime_put();
+
+       return 0;
+}
+
+static int venc_runtime_resume(struct device *dev)
+{
+       int r;
+
+       r = dss_runtime_get();
+       if (r < 0)
+               goto err_get_dss;
+
+       r = dispc_runtime_get();
+       if (r < 0)
+               goto err_get_dispc;
+
+       clk_enable(venc.tv_clk);
+       if (venc.tv_dac_clk)
+               clk_enable(venc.tv_dac_clk);
+
+       return 0;
+
+err_get_dispc:
+       dss_runtime_put();
+err_get_dss:
+       return r;
+}
+
+static const struct dev_pm_ops venc_pm_ops = {
+       .runtime_suspend = venc_runtime_suspend,
+       .runtime_resume = venc_runtime_resume,
+};
+
 static struct platform_driver omap_venchw_driver = {
        .probe          = omap_venchw_probe,
        .remove         = omap_venchw_remove,
        .driver         = {
                .name   = "omapdss_venc",
                .owner  = THIS_MODULE,
+               .pm     = &venc_pm_ops,
        },
 };
 
index cff4503..6b1ac23 100644 (file)
@@ -316,67 +316,67 @@ int omapfb_update_window(struct fb_info *fbi,
 }
 EXPORT_SYMBOL(omapfb_update_window);
 
-static int omapfb_set_update_mode(struct fb_info *fbi,
+int omapfb_set_update_mode(struct fb_info *fbi,
                                   enum omapfb_update_mode mode)
 {
        struct omap_dss_device *display = fb2display(fbi);
-       enum omap_dss_update_mode um;
+       struct omapfb_info *ofbi = FB2OFB(fbi);
+       struct omapfb2_device *fbdev = ofbi->fbdev;
+       struct omapfb_display_data *d;
        int r;
 
-       if (!display || !display->driver->set_update_mode)
+       if (!display)
                return -EINVAL;
 
-       switch (mode) {
-       case OMAPFB_UPDATE_DISABLED:
-               um = OMAP_DSS_UPDATE_DISABLED;
-               break;
+       if (mode != OMAPFB_AUTO_UPDATE && mode != OMAPFB_MANUAL_UPDATE)
+               return -EINVAL;
 
-       case OMAPFB_AUTO_UPDATE:
-               um = OMAP_DSS_UPDATE_AUTO;
-               break;
+       omapfb_lock(fbdev);
 
-       case OMAPFB_MANUAL_UPDATE:
-               um = OMAP_DSS_UPDATE_MANUAL;
-               break;
+       d = get_display_data(fbdev, display);
 
-       default:
-               return -EINVAL;
+       if (d->update_mode == mode) {
+               omapfb_unlock(fbdev);
+               return 0;
        }
 
-       r = display->driver->set_update_mode(display, um);
+       r = 0;
+
+       if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
+               if (mode == OMAPFB_AUTO_UPDATE)
+                       omapfb_start_auto_update(fbdev, display);
+               else /* MANUAL_UPDATE */
+                       omapfb_stop_auto_update(fbdev, display);
+
+               d->update_mode = mode;
+       } else { /* AUTO_UPDATE */
+               if (mode == OMAPFB_MANUAL_UPDATE)
+                       r = -EINVAL;
+       }
+
+       omapfb_unlock(fbdev);
 
        return r;
 }
 
-static int omapfb_get_update_mode(struct fb_info *fbi,
+int omapfb_get_update_mode(struct fb_info *fbi,
                enum omapfb_update_mode *mode)
 {
        struct omap_dss_device *display = fb2display(fbi);
-       enum omap_dss_update_mode m;
+       struct omapfb_info *ofbi = FB2OFB(fbi);
+       struct omapfb2_device *fbdev = ofbi->fbdev;
+       struct omapfb_display_data *d;
 
        if (!display)
                return -EINVAL;
 
-       if (!display->driver->get_update_mode) {
-               *mode = OMAPFB_AUTO_UPDATE;
-               return 0;
-       }
+       omapfb_lock(fbdev);
 
-       m = display->driver->get_update_mode(display);
+       d = get_display_data(fbdev, display);
 
-       switch (m) {
-       case OMAP_DSS_UPDATE_DISABLED:
-               *mode = OMAPFB_UPDATE_DISABLED;
-               break;
-       case OMAP_DSS_UPDATE_AUTO:
-               *mode = OMAPFB_AUTO_UPDATE;
-               break;
-       case OMAP_DSS_UPDATE_MANUAL:
-               *mode = OMAPFB_MANUAL_UPDATE;
-               break;
-       default:
-               BUG();
-       }
+       *mode = d->update_mode;
+
+       omapfb_unlock(fbdev);
 
        return 0;
 }
index 505bc12..602b71a 100644 (file)
@@ -46,6 +46,10 @@ static char *def_vram;
 static int def_vrfb;
 static int def_rotate;
 static int def_mirror;
+static bool auto_update;
+static unsigned int auto_update_freq;
+module_param(auto_update, bool, 0);
+module_param(auto_update_freq, uint, 0644);
 
 #ifdef DEBUG
 unsigned int omapfb_debug;
@@ -1242,6 +1246,7 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
        struct omapfb_info *ofbi = FB2OFB(fbi);
        struct omapfb2_device *fbdev = ofbi->fbdev;
        struct omap_dss_device *display = fb2display(fbi);
+       struct omapfb_display_data *d;
        int r = 0;
 
        if (!display)
@@ -1249,6 +1254,8 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
 
        omapfb_lock(fbdev);
 
+       d = get_display_data(fbdev, display);
+
        switch (blank) {
        case FB_BLANK_UNBLANK:
                if (display->state != OMAP_DSS_DISPLAY_SUSPENDED)
@@ -1257,6 +1264,11 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
                if (display->driver->resume)
                        r = display->driver->resume(display);
 
+               if ((display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) &&
+                               d->update_mode == OMAPFB_AUTO_UPDATE &&
+                               !d->auto_update_work_enabled)
+                       omapfb_start_auto_update(fbdev, display);
+
                break;
 
        case FB_BLANK_NORMAL:
@@ -1268,6 +1280,9 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
                if (display->state != OMAP_DSS_DISPLAY_ACTIVE)
                        goto exit;
 
+               if (d->auto_update_work_enabled)
+                       omapfb_stop_auto_update(fbdev, display);
+
                if (display->driver->suspend)
                        r = display->driver->suspend(display);
 
@@ -1724,6 +1739,78 @@ err:
        return r;
 }
 
+static void omapfb_auto_update_work(struct work_struct *work)
+{
+       struct omap_dss_device *dssdev;
+       struct omap_dss_driver *dssdrv;
+       struct omapfb_display_data *d;
+       u16 w, h;
+       unsigned int freq;
+       struct omapfb2_device *fbdev;
+
+       d = container_of(work, struct omapfb_display_data,
+                       auto_update_work.work);
+
+       dssdev = d->dssdev;
+       dssdrv = dssdev->driver;
+       fbdev = d->fbdev;
+
+       if (!dssdrv || !dssdrv->update)
+               return;
+
+       if (dssdrv->sync)
+               dssdrv->sync(dssdev);
+
+       dssdrv->get_resolution(dssdev, &w, &h);
+       dssdrv->update(dssdev, 0, 0, w, h);
+
+       freq = auto_update_freq;
+       if (freq == 0)
+               freq = 20;
+       queue_delayed_work(fbdev->auto_update_wq,
+                       &d->auto_update_work, HZ / freq);
+}
+
+void omapfb_start_auto_update(struct omapfb2_device *fbdev,
+               struct omap_dss_device *display)
+{
+       struct omapfb_display_data *d;
+
+       if (fbdev->auto_update_wq == NULL) {
+               struct workqueue_struct *wq;
+
+               wq = create_singlethread_workqueue("omapfb_auto_update");
+
+               if (wq == NULL) {
+                       dev_err(fbdev->dev, "Failed to create workqueue for "
+                                       "auto-update\n");
+                       return;
+               }
+
+               fbdev->auto_update_wq = wq;
+       }
+
+       d = get_display_data(fbdev, display);
+
+       INIT_DELAYED_WORK(&d->auto_update_work, omapfb_auto_update_work);
+
+       d->auto_update_work_enabled = true;
+
+       omapfb_auto_update_work(&d->auto_update_work.work);
+}
+
+void omapfb_stop_auto_update(struct omapfb2_device *fbdev,
+               struct omap_dss_device *display)
+{
+       struct omapfb_display_data *d;
+
+       d = get_display_data(fbdev, display);
+
+       cancel_delayed_work_sync(&d->auto_update_work);
+
+       d->auto_update_work_enabled = false;
+}
+
 /* initialize fb_info, var, fix to something sane based on the display */
 static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
 {
@@ -1858,10 +1945,21 @@ static void omapfb_free_resources(struct omapfb2_device *fbdev)
        }
 
        for (i = 0; i < fbdev->num_displays; i++) {
-               if (fbdev->displays[i]->state != OMAP_DSS_DISPLAY_DISABLED)
-                       fbdev->displays[i]->driver->disable(fbdev->displays[i]);
+               struct omap_dss_device *dssdev = fbdev->displays[i].dssdev;
+
+               if (fbdev->displays[i].auto_update_work_enabled)
+                       omapfb_stop_auto_update(fbdev, dssdev);
+
+               if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)
+                       dssdev->driver->disable(dssdev);
+
+               omap_dss_put_device(dssdev);
+       }
 
-               omap_dss_put_device(fbdev->displays[i]);
+       if (fbdev->auto_update_wq != NULL) {
+               flush_workqueue(fbdev->auto_update_wq);
+               destroy_workqueue(fbdev->auto_update_wq);
+               fbdev->auto_update_wq = NULL;
        }
 
        dev_set_drvdata(fbdev->dev, NULL);
@@ -2084,14 +2182,14 @@ static int omapfb_set_def_mode(struct omapfb2_device *fbdev,
        int r;
        u8 bpp;
        struct omap_video_timings timings, temp_timings;
+       struct omapfb_display_data *d;
 
        r = omapfb_mode_to_timings(mode_str, &timings, &bpp);
        if (r)
                return r;
 
-       fbdev->bpp_overrides[fbdev->num_bpp_overrides].dssdev = display;
-       fbdev->bpp_overrides[fbdev->num_bpp_overrides].bpp = bpp;
-       ++fbdev->num_bpp_overrides;
+       d = get_display_data(fbdev, display);
+       d->bpp_override = bpp;
 
        if (display->driver->check_timings) {
                r = display->driver->check_timings(display, &timings);
@@ -2117,14 +2215,14 @@ static int omapfb_set_def_mode(struct omapfb2_device *fbdev,
 static int omapfb_get_recommended_bpp(struct omapfb2_device *fbdev,
                struct omap_dss_device *dssdev)
 {
-       int i;
+       struct omapfb_display_data *d;
 
        BUG_ON(dssdev->driver->get_recommended_bpp == NULL);
 
-       for (i = 0; i < fbdev->num_bpp_overrides; ++i) {
-               if (dssdev == fbdev->bpp_overrides[i].dssdev)
-                       return fbdev->bpp_overrides[i].bpp;
-       }
+       d = get_display_data(fbdev, dssdev);
+
+       if (d->bpp_override != 0)
+               return d->bpp_override;
 
        return dssdev->driver->get_recommended_bpp(dssdev);
 }
@@ -2156,9 +2254,9 @@ static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
 
                display = NULL;
                for (i = 0; i < fbdev->num_displays; ++i) {
-                       if (strcmp(fbdev->displays[i]->name,
+                       if (strcmp(fbdev->displays[i].dssdev->name,
                                                display_str) == 0) {
-                               display = fbdev->displays[i];
+                               display = fbdev->displays[i].dssdev;
                                break;
                        }
                }
@@ -2182,6 +2280,7 @@ static int omapfb_init_display(struct omapfb2_device *fbdev,
                struct omap_dss_device *dssdev)
 {
        struct omap_dss_driver *dssdrv = dssdev->driver;
+       struct omapfb_display_data *d;
        int r;
 
        r = dssdrv->enable(dssdev);
@@ -2191,8 +2290,20 @@ static int omapfb_init_display(struct omapfb2_device *fbdev,
                return r;
        }
 
+       d = get_display_data(fbdev, dssdev);
+
+       d->fbdev = fbdev;
+
        if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
                u16 w, h;
+
+               if (auto_update) {
+                       omapfb_start_auto_update(fbdev, dssdev);
+                       d->update_mode = OMAPFB_AUTO_UPDATE;
+               } else {
+                       d->update_mode = OMAPFB_MANUAL_UPDATE;
+               }
+
                if (dssdrv->enable_te) {
                        r = dssdrv->enable_te(dssdev, 1);
                        if (r) {
@@ -2201,16 +2312,6 @@ static int omapfb_init_display(struct omapfb2_device *fbdev,
                        }
                }
 
-               if (dssdrv->set_update_mode) {
-                       r = dssdrv->set_update_mode(dssdev,
-                                       OMAP_DSS_UPDATE_MANUAL);
-                       if (r) {
-                               dev_err(fbdev->dev,
-                                               "Failed to set update mode\n");
-                               return r;
-                       }
-               }
-
                dssdrv->get_resolution(dssdev, &w, &h);
                r = dssdrv->update(dssdev, 0, 0, w, h);
                if (r) {
@@ -2219,15 +2320,7 @@ static int omapfb_init_display(struct omapfb2_device *fbdev,
                        return r;
                }
        } else {
-               if (dssdrv->set_update_mode) {
-                       r = dssdrv->set_update_mode(dssdev,
-                                       OMAP_DSS_UPDATE_AUTO);
-                       if (r) {
-                               dev_err(fbdev->dev,
-                                               "Failed to set update mode\n");
-                               return r;
-                       }
-               }
+               d->update_mode = OMAPFB_AUTO_UPDATE;
        }
 
        return 0;
@@ -2275,6 +2368,8 @@ static int omapfb_probe(struct platform_device *pdev)
        fbdev->num_displays = 0;
        dssdev = NULL;
        for_each_dss_dev(dssdev) {
+               struct omapfb_display_data *d;
+
                omap_dss_get_device(dssdev);
 
                if (!dssdev->driver) {
@@ -2282,7 +2377,12 @@ static int omapfb_probe(struct platform_device *pdev)
                        r = -ENODEV;
                }
 
-               fbdev->displays[fbdev->num_displays++] = dssdev;
+               d = &fbdev->displays[fbdev->num_displays++];
+               d->dssdev = dssdev;
+               if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
+                       d->update_mode = OMAPFB_MANUAL_UPDATE;
+               else
+                       d->update_mode = OMAPFB_AUTO_UPDATE;
        }
 
        if (r)
index 2f5e817..153bf1a 100644 (file)
@@ -518,6 +518,39 @@ static ssize_t show_virt(struct device *dev,
        return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region->vaddr);
 }
 
+static ssize_t show_upd_mode(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct fb_info *fbi = dev_get_drvdata(dev);
+       enum omapfb_update_mode mode;
+       int r;
+
+       r = omapfb_get_update_mode(fbi, &mode);
+
+       if (r)
+               return r;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", (unsigned)mode);
+}
+
+static ssize_t store_upd_mode(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct fb_info *fbi = dev_get_drvdata(dev);
+       unsigned mode;
+       int r;
+
+       r = kstrtouint(buf, 0, &mode);
+       if (r)
+               return r;
+
+       r = omapfb_set_update_mode(fbi, mode);
+       if (r)
+               return r;
+
+       return count;
+}
+
 static struct device_attribute omapfb_attrs[] = {
        __ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type,
                        store_rotate_type),
@@ -528,6 +561,7 @@ static struct device_attribute omapfb_attrs[] = {
                        store_overlays_rotate),
        __ATTR(phys_addr, S_IRUGO, show_phys, NULL),
        __ATTR(virt_addr, S_IRUGO, show_virt, NULL),
+       __ATTR(update_mode, S_IRUGO | S_IWUSR, show_upd_mode, store_upd_mode),
 };
 
 int omapfb_create_sysfs(struct omapfb2_device *fbdev)
index aa1b1d9..fdf0ede 100644 (file)
@@ -73,6 +73,15 @@ struct omapfb_info {
        bool mirror;
 };
 
+struct omapfb_display_data {
+       struct omapfb2_device *fbdev;
+       struct omap_dss_device *dssdev;
+       u8 bpp_override;
+       enum omapfb_update_mode update_mode;
+       bool auto_update_work_enabled;
+       struct delayed_work auto_update_work;
+};
+
 struct omapfb2_device {
        struct device *dev;
        struct mutex  mtx;
@@ -86,17 +95,13 @@ struct omapfb2_device {
        struct omapfb2_mem_region regions[10];
 
        unsigned num_displays;
-       struct omap_dss_device *displays[10];
+       struct omapfb_display_data displays[10];
        unsigned num_overlays;
        struct omap_overlay *overlays[10];
        unsigned num_managers;
        struct omap_overlay_manager *managers[10];
 
-       unsigned num_bpp_overrides;
-       struct {
-               struct omap_dss_device *dssdev;
-               u8 bpp;
-       } bpp_overrides[10];
+       struct workqueue_struct *auto_update_wq;
 };
 
 struct omapfb_colormode {
@@ -128,6 +133,13 @@ int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
 int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
                u16 posx, u16 posy, u16 outw, u16 outh);
 
+void omapfb_start_auto_update(struct omapfb2_device *fbdev,
+               struct omap_dss_device *display);
+void omapfb_stop_auto_update(struct omapfb2_device *fbdev,
+               struct omap_dss_device *display);
+int omapfb_get_update_mode(struct fb_info *fbi, enum omapfb_update_mode *mode);
+int omapfb_set_update_mode(struct fb_info *fbi, enum omapfb_update_mode mode);
+
 /* find the display connected to this fb, if any */
 static inline struct omap_dss_device *fb2display(struct fb_info *fbi)
 {
@@ -143,6 +155,19 @@ static inline struct omap_dss_device *fb2display(struct fb_info *fbi)
        return NULL;
 }
 
+static inline struct omapfb_display_data *get_display_data(
+               struct omapfb2_device *fbdev, struct omap_dss_device *dssdev)
+{
+       int i;
+
+       for (i = 0; i < fbdev->num_displays; ++i)
+               if (fbdev->displays[i].dssdev == dssdev)
+                       return &fbdev->displays[i];
+
+       /* This should never happen */
+       BUG();
+}
+
 static inline void omapfb_lock(struct omapfb2_device *fbdev)
 {
        mutex_lock(&fbdev->mtx);
index 32549d1..dcaab90 100644 (file)
@@ -55,7 +55,7 @@
 
 #define S3_SAVAGE3D_SERIES(chip)  ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE_MX))
 
-#define S3_SAVAGE4_SERIES(chip)   ((chip>=S3_SAVAGE4) || (chip<=S3_PROSAVAGEDDR))
+#define S3_SAVAGE4_SERIES(chip)   ((chip>=S3_SAVAGE4) && (chip<=S3_PROSAVAGEDDR))
 
 #define S3_SAVAGE_MOBILE_SERIES(chip)  ((chip==S3_SAVAGE_MX) || (chip==S3_SUPERSAVAGE))
 
index 21d816e..86b0735 100644 (file)
@@ -28,6 +28,14 @@ menuconfig WATCHDOG
 
 if WATCHDOG
 
+config WATCHDOG_CORE
+       bool "WatchDog Timer Driver Core"
+       ---help---
+         Say Y here if you want to use the new watchdog timer driver core.
+         This driver provides a framework for all watchdog timer drivers
+         and gives them the /dev/watchdog interface (and later also the
+         sysfs interface).
+
 config WATCHDOG_NOWAYOUT
        bool "Disable watchdog shutdown on close"
        help
@@ -186,6 +194,15 @@ config SA1100_WATCHDOG
          To compile this driver as a module, choose M here: the
          module will be called sa1100_wdt.
 
+config DW_WATCHDOG
+       tristate "Synopsys DesignWare watchdog"
+       depends on ARM && HAVE_CLK
+       help
+         Say Y here if to include support for the Synopsys DesignWare
+         watchdog timer found in many ARM chips.
+         To compile this driver as a module, choose M here: the
+         module will be called dw_wdt.
+
 config MPCORE_WATCHDOG
        tristate "MPcore watchdog"
        depends on HAVE_ARM_TWD
@@ -321,7 +338,7 @@ config MAX63XX_WATCHDOG
 
 config IMX2_WDT
        tristate "IMX2+ Watchdog"
-       depends on ARCH_MX2 || ARCH_MX25 || ARCH_MX3 || ARCH_MX5
+       depends on IMX_HAVE_PLATFORM_IMX2_WDT
        help
          This is the driver for the hardware watchdog
          on the Freescale IMX2 and later processors.
@@ -879,6 +896,20 @@ config M54xx_WATCHDOG
          To compile this driver as a module, choose M here: the
          module will be called m54xx_wdt.
 
+# MicroBlaze Architecture
+
+config XILINX_WATCHDOG
+       tristate "Xilinx Watchdog timer"
+       depends on MICROBLAZE
+       ---help---
+         Watchdog driver for the xps_timebase_wdt ip core.
+
+         IMPORTANT: The xps_timebase_wdt parent must have the property
+         "clock-frequency" at device tree.
+
+         To compile this driver as a module, choose M here: the
+         module will be called of_xilinx_wdt.
+
 # MIPS Architecture
 
 config ATH79_WDT
index ed26f70..55bd574 100644 (file)
@@ -2,6 +2,10 @@
 # Makefile for the WatchDog device drivers.
 #
 
+# The WatchDog Timer Driver Core.
+watchdog-objs  += watchdog_core.o watchdog_dev.o
+obj-$(CONFIG_WATCHDOG_CORE)    += watchdog.o
+
 # Only one watchdog can succeed. We probe the ISA/PCI/USB based
 # watchdog-cards first, then the architecture specific watchdog
 # drivers and then the architecture independent "softdog" driver.
@@ -37,6 +41,7 @@ obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
 obj-$(CONFIG_KS8695_WATCHDOG) += ks8695_wdt.o
 obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
 obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
+obj-$(CONFIG_DW_WATCHDOG) += dw_wdt.o
 obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
 obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
 obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
@@ -109,6 +114,9 @@ obj-$(CONFIG_INTEL_SCU_WATCHDOG) += intel_scu_watchdog.o
 # M68K Architecture
 obj-$(CONFIG_M54xx_WATCHDOG) += m54xx_wdt.o
 
+# MicroBlaze Architecture
+obj-$(CONFIG_XILINX_WATCHDOG) += of_xilinx_wdt.o
+
 # MIPS Architecture
 obj-$(CONFIG_ATH79_WDT) += ath79_wdt.o
 obj-$(CONFIG_BCM47XX_WDT) += bcm47xx_wdt.o
index eac2602..87445b2 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/bitops.h>
 #include <linux/uaccess.h>
 
-#include <mach/at91_wdt.h>
+#include "at91sam9_wdt.h"
 
 #define DRV_NAME "AT91SAM9 Watchdog"
 
@@ -284,27 +284,8 @@ static int __exit at91wdt_remove(struct platform_device *pdev)
        return res;
 }
 
-#ifdef CONFIG_PM
-
-static int at91wdt_suspend(struct platform_device *pdev, pm_message_t message)
-{
-       return 0;
-}
-
-static int at91wdt_resume(struct platform_device *pdev)
-{
-       return 0;
-}
-
-#else
-#define at91wdt_suspend        NULL
-#define at91wdt_resume NULL
-#endif
-
 static struct platform_driver at91wdt_driver = {
        .remove         = __exit_p(at91wdt_remove),
-       .suspend        = at91wdt_suspend,
-       .resume         = at91wdt_resume,
        .driver         = {
                .name   = "at91_wdt",
                .owner  = THIS_MODULE,
similarity index 96%
rename from arch/arm/mach-at91/include/mach/at91_wdt.h
rename to drivers/watchdog/at91sam9_wdt.h
index fecc2e9..757f9ca 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * arch/arm/mach-at91/include/mach/at91_wdt.h
+ * drivers/watchdog/at91sam9_wdt.h
  *
  * Copyright (C) 2007 Andrew Victor
  * Copyright (C) 2007 Atmel Corporation.
diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c
new file mode 100644 (file)
index 0000000..f10f8c0
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2010-2011 Picochip Ltd., Jamie Iles
+ * http://www.picochip.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 file implements a driver for the Synopsys DesignWare watchdog device
+ * in the many ARM subsystems. The watchdog has 16 different timeout periods
+ * and these are a function of the input clock frequency.
+ *
+ * The DesignWare watchdog cannot be stopped once it has been started so we
+ * use a software timer to implement a ping that will keep the watchdog alive.
+ * If we receive an expected close for the watchdog then we keep the timer
+ * running, otherwise the timer is stopped and the watchdog will expire.
+ */
+#define pr_fmt(fmt) "dw_wdt: " fmt
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/uaccess.h>
+#include <linux/watchdog.h>
+
+#define WDOG_CONTROL_REG_OFFSET                    0x00
+#define WDOG_CONTROL_REG_WDT_EN_MASK       0x01
+#define WDOG_TIMEOUT_RANGE_REG_OFFSET      0x04
+#define WDOG_CURRENT_COUNT_REG_OFFSET      0x08
+#define WDOG_COUNTER_RESTART_REG_OFFSET     0x0c
+#define WDOG_COUNTER_RESTART_KICK_VALUE            0x76
+
+/* The maximum TOP (timeout period) value that can be set in the watchdog. */
+#define DW_WDT_MAX_TOP         15
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
+                "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+#define WDT_TIMEOUT            (HZ / 2)
+
+static struct {
+       spinlock_t              lock;
+       void __iomem            *regs;
+       struct clk              *clk;
+       unsigned long           in_use;
+       unsigned long           next_heartbeat;
+       struct timer_list       timer;
+       int                     expect_close;
+} dw_wdt;
+
+static inline int dw_wdt_is_enabled(void)
+{
+       return readl(dw_wdt.regs + WDOG_CONTROL_REG_OFFSET) &
+               WDOG_CONTROL_REG_WDT_EN_MASK;
+}
+
+static inline int dw_wdt_top_in_seconds(unsigned top)
+{
+       /*
+        * There are 16 possible timeout values in 0..15 where the number of
+        * cycles is 2 ^ (16 + i) and the watchdog counts down.
+        */
+       return (1 << (16 + top)) / clk_get_rate(dw_wdt.clk);
+}
+
+static int dw_wdt_get_top(void)
+{
+       int top = readl(dw_wdt.regs + WDOG_TIMEOUT_RANGE_REG_OFFSET) & 0xF;
+
+       return dw_wdt_top_in_seconds(top);
+}
+
+static inline void dw_wdt_set_next_heartbeat(void)
+{
+       dw_wdt.next_heartbeat = jiffies + dw_wdt_get_top() * HZ;
+}
+
+static int dw_wdt_set_top(unsigned top_s)
+{
+       int i, top_val = DW_WDT_MAX_TOP;
+
+       /*
+        * Iterate over the timeout values until we find the closest match. We
+        * always look for >=.
+        */
+       for (i = 0; i <= DW_WDT_MAX_TOP; ++i)
+               if (dw_wdt_top_in_seconds(i) >= top_s) {
+                       top_val = i;
+                       break;
+               }
+
+       /* Set the new value in the watchdog. */
+       writel(top_val, dw_wdt.regs + WDOG_TIMEOUT_RANGE_REG_OFFSET);
+
+       dw_wdt_set_next_heartbeat();
+
+       return dw_wdt_top_in_seconds(top_val);
+}
+
+static void dw_wdt_keepalive(void)
+{
+       writel(WDOG_COUNTER_RESTART_KICK_VALUE, dw_wdt.regs +
+              WDOG_COUNTER_RESTART_REG_OFFSET);
+}
+
+static void dw_wdt_ping(unsigned long data)
+{
+       if (time_before(jiffies, dw_wdt.next_heartbeat) ||
+           (!nowayout && !dw_wdt.in_use)) {
+               dw_wdt_keepalive();
+               mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT);
+       } else
+               pr_crit("keepalive missed, machine will reset\n");
+}
+
+static int dw_wdt_open(struct inode *inode, struct file *filp)
+{
+       if (test_and_set_bit(0, &dw_wdt.in_use))
+               return -EBUSY;
+
+       /* Make sure we don't get unloaded. */
+       __module_get(THIS_MODULE);
+
+       spin_lock(&dw_wdt.lock);
+       if (!dw_wdt_is_enabled()) {
+               /*
+                * The watchdog is not currently enabled. Set the timeout to
+                * the maximum and then start it.
+                */
+               dw_wdt_set_top(DW_WDT_MAX_TOP);
+               writel(WDOG_CONTROL_REG_WDT_EN_MASK,
+                      dw_wdt.regs + WDOG_CONTROL_REG_OFFSET);
+       }
+
+       dw_wdt_set_next_heartbeat();
+
+       spin_unlock(&dw_wdt.lock);
+
+       return nonseekable_open(inode, filp);
+}
+
+ssize_t dw_wdt_write(struct file *filp, const char __user *buf, size_t len,
+                    loff_t *offset)
+{
+       if (!len)
+               return 0;
+
+       if (!nowayout) {
+               size_t i;
+
+               dw_wdt.expect_close = 0;
+
+               for (i = 0; i < len; ++i) {
+                       char c;
+
+                       if (get_user(c, buf + i))
+                               return -EFAULT;
+
+                       if (c == 'V') {
+                               dw_wdt.expect_close = 1;
+                               break;
+                       }
+               }
+       }
+
+       dw_wdt_set_next_heartbeat();
+       mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT);
+
+       return len;
+}
+
+static u32 dw_wdt_time_left(void)
+{
+       return readl(dw_wdt.regs + WDOG_CURRENT_COUNT_REG_OFFSET) /
+               clk_get_rate(dw_wdt.clk);
+}
+
+static const struct watchdog_info dw_wdt_ident = {
+       .options        = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
+                         WDIOF_MAGICCLOSE,
+       .identity       = "Synopsys DesignWare Watchdog",
+};
+
+static long dw_wdt_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+       unsigned long val;
+       int timeout;
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               return copy_to_user((struct watchdog_info *)arg, &dw_wdt_ident,
+                                   sizeof(dw_wdt_ident)) ? -EFAULT : 0;
+
+       case WDIOC_GETSTATUS:
+       case WDIOC_GETBOOTSTATUS:
+               return put_user(0, (int *)arg);
+
+       case WDIOC_KEEPALIVE:
+               dw_wdt_set_next_heartbeat();
+               return 0;
+
+       case WDIOC_SETTIMEOUT:
+               if (get_user(val, (int __user *)arg))
+                       return -EFAULT;
+               timeout = dw_wdt_set_top(val);
+               return put_user(timeout , (int __user *)arg);
+
+       case WDIOC_GETTIMEOUT:
+               return put_user(dw_wdt_get_top(), (int __user *)arg);
+
+       case WDIOC_GETTIMELEFT:
+               /* Get the time left until expiry. */
+               if (get_user(val, (int __user *)arg))
+                       return -EFAULT;
+               return put_user(dw_wdt_time_left(), (int __user *)arg);
+
+       default:
+               return -ENOTTY;
+       }
+}
+
+static int dw_wdt_release(struct inode *inode, struct file *filp)
+{
+       clear_bit(0, &dw_wdt.in_use);
+
+       if (!dw_wdt.expect_close) {
+               del_timer(&dw_wdt.timer);
+
+               if (!nowayout)
+                       pr_crit("unexpected close, system will reboot soon\n");
+               else
+                       pr_crit("watchdog cannot be disabled, system will reboot soon\n");
+       }
+
+       dw_wdt.expect_close = 0;
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int dw_wdt_suspend(struct device *dev)
+{
+       clk_disable(dw_wdt.clk);
+
+       return 0;
+}
+
+static int dw_wdt_resume(struct device *dev)
+{
+       int err = clk_enable(dw_wdt.clk);
+
+       if (err)
+               return err;
+
+       dw_wdt_keepalive();
+
+       return 0;
+}
+
+static const struct dev_pm_ops dw_wdt_pm_ops = {
+       .suspend        = dw_wdt_suspend,
+       .resume         = dw_wdt_resume,
+};
+#endif /* CONFIG_PM */
+
+static const struct file_operations wdt_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .open           = dw_wdt_open,
+       .write          = dw_wdt_write,
+       .unlocked_ioctl = dw_wdt_ioctl,
+       .release        = dw_wdt_release
+};
+
+static struct miscdevice dw_wdt_miscdev = {
+       .fops           = &wdt_fops,
+       .name           = "watchdog",
+       .minor          = WATCHDOG_MINOR,
+};
+
+static int __devinit dw_wdt_drv_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       if (!mem)
+               return -EINVAL;
+
+       if (!devm_request_mem_region(&pdev->dev, mem->start, resource_size(mem),
+                                    "dw_wdt"))
+               return -ENOMEM;
+
+       dw_wdt.regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
+       if (!dw_wdt.regs)
+               return -ENOMEM;
+
+       dw_wdt.clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(dw_wdt.clk))
+               return PTR_ERR(dw_wdt.clk);
+
+       ret = clk_enable(dw_wdt.clk);
+       if (ret)
+               goto out_put_clk;
+
+       spin_lock_init(&dw_wdt.lock);
+
+       ret = misc_register(&dw_wdt_miscdev);
+       if (ret)
+               goto out_disable_clk;
+
+       dw_wdt_set_next_heartbeat();
+       setup_timer(&dw_wdt.timer, dw_wdt_ping, 0);
+       mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT);
+
+       return 0;
+
+out_disable_clk:
+       clk_disable(dw_wdt.clk);
+out_put_clk:
+       clk_put(dw_wdt.clk);
+
+       return ret;
+}
+
+static int __devexit dw_wdt_drv_remove(struct platform_device *pdev)
+{
+       misc_deregister(&dw_wdt_miscdev);
+
+       clk_disable(dw_wdt.clk);
+       clk_put(dw_wdt.clk);
+
+       return 0;
+}
+
+static struct platform_driver dw_wdt_driver = {
+       .probe          = dw_wdt_drv_probe,
+       .remove         = __devexit_p(dw_wdt_drv_remove),
+       .driver         = {
+               .name   = "dw_wdt",
+               .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     = &dw_wdt_pm_ops,
+#endif /* CONFIG_PM */
+       },
+};
+
+static int __init dw_wdt_watchdog_init(void)
+{
+       return platform_driver_register(&dw_wdt_driver);
+}
+module_init(dw_wdt_watchdog_init);
+
+static void __exit dw_wdt_watchdog_exit(void)
+{
+       platform_driver_unregister(&dw_wdt_driver);
+}
+module_exit(dw_wdt_watchdog_exit);
+
+MODULE_AUTHOR("Jamie Iles");
+MODULE_DESCRIPTION("Synopsys DesignWare Watchdog Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index 8cb2685..410fba4 100644 (file)
@@ -36,7 +36,7 @@
 #include <asm/cacheflush.h>
 #endif /* CONFIG_HPWDT_NMI_DECODING */
 
-#define HPWDT_VERSION                  "1.2.0"
+#define HPWDT_VERSION                  "1.3.0"
 #define SECS_TO_TICKS(secs)            ((secs) * 1000 / 128)
 #define TICKS_TO_SECS(ticks)           ((ticks) * 128 / 1000)
 #define HPWDT_MAX_TIMER                        TICKS_TO_SECS(65535)
@@ -87,6 +87,19 @@ struct smbios_cru64_info {
 };
 #define SMBIOS_CRU64_INFORMATION       212
 
+/* type 219 */
+struct smbios_proliant_info {
+       u8 type;
+       u8 byte_length;
+       u16 handle;
+       u32 power_features;
+       u32 omega_features;
+       u32 reserved;
+       u32 misc_features;
+};
+#define SMBIOS_ICRU_INFORMATION                219
+
+
 struct cmn_registers {
        union {
                struct {
@@ -132,6 +145,7 @@ 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;
 static struct cmn_registers cmn_regs;
@@ -476,19 +490,22 @@ static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason,
                goto out;
 
        spin_lock_irqsave(&rom_lock, rom_pl);
-       if (!die_nmi_called)
+       if (!die_nmi_called && !is_icru)
                asminline_call(&cmn_regs, cru_rom_addr);
        die_nmi_called = 1;
        spin_unlock_irqrestore(&rom_lock, rom_pl);
-       if (cmn_regs.u1.ral == 0) {
-               printk(KERN_WARNING "hpwdt: An NMI occurred, "
-                       "but unable to determine source.\n");
-       } else {
-               if (allow_kdump)
-                       hpwdt_stop();
-               panic("An NMI occurred, please see the Integrated "
-                       "Management Log for details.\n");
+       if (!is_icru) {
+               if (cmn_regs.u1.ral == 0) {
+                       printk(KERN_WARNING "hpwdt: An NMI occurred, "
+                               "but unable to determine source.\n");
+               }
        }
+
+       if (allow_kdump)
+               hpwdt_stop();
+       panic("An NMI occurred, please see the Integrated "
+               "Management Log for details.\n");
+
 out:
        return NOTIFY_OK;
 }
@@ -659,30 +676,63 @@ static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev)
 }
 #endif /* CONFIG_X86_LOCAL_APIC */
 
+/*
+ *     dmi_find_icru
+ *
+ *     Routine Description:
+ *     This function checks whether or not we are on an iCRU-based server.
+ *     This check is independent of architecture and needs to be made for
+ *     any ProLiant system.
+ */
+static void __devinit dmi_find_icru(const struct dmi_header *dm, void *dummy)
+{
+       struct smbios_proliant_info *smbios_proliant_ptr;
+
+       if (dm->type == SMBIOS_ICRU_INFORMATION) {
+               smbios_proliant_ptr = (struct smbios_proliant_info *) dm;
+               if (smbios_proliant_ptr->misc_features & 0x01)
+                       is_icru = 1;
+       }
+}
+
 static int __devinit hpwdt_init_nmi_decoding(struct pci_dev *dev)
 {
        int retval;
 
        /*
-        * We need to map the ROM to get the CRU service.
-        * For 32 bit Operating Systems we need to go through the 32 Bit
-        * BIOS Service Directory
-        * For 64 bit Operating Systems we get that service through SMBIOS.
+        * On typical CRU-based systems we need to map that service in
+        * the BIOS. For 32 bit Operating Systems we need to go through
+        * the 32 Bit BIOS Service Directory. For 64 bit Operating
+        * Systems we get that service through SMBIOS.
+        *
+        * On systems that support the new iCRU service all we need to
+        * do is call dmi_walk to get the supported flag value and skip
+        * the old cru detect code.
         */
-       retval = detect_cru_service();
-       if (retval < 0) {
-               dev_warn(&dev->dev,
-                       "Unable to detect the %d Bit CRU Service.\n",
-                       HPWDT_ARCH);
-               return retval;
-       }
+       dmi_walk(dmi_find_icru, NULL);
+       if (!is_icru) {
+
+               /*
+               * We need to map the ROM to get the CRU service.
+               * For 32 bit Operating Systems we need to go through the 32 Bit
+               * BIOS Service Directory
+               * For 64 bit Operating Systems we get that service through SMBIOS.
+               */
+               retval = detect_cru_service();
+               if (retval < 0) {
+                       dev_warn(&dev->dev,
+                               "Unable to detect the %d Bit CRU Service.\n",
+                               HPWDT_ARCH);
+                       return retval;
+               }
 
-       /*
-        * We know this is the only CRU call we need to make so lets keep as
-        * few instructions as possible once the NMI comes in.
-        */
-       cmn_regs.u1.rah = 0x0D;
-       cmn_regs.u1.ral = 0x02;
+               /*
+               * We know this is the only CRU call we need to make so lets keep as
+               * few instructions as possible once the NMI comes in.
+               */
+               cmn_regs.u1.rah = 0x0D;
+               cmn_regs.u1.ral = 0x02;
+       }
 
        /*
         * If the priority is set to 1, then we will be put first on the
index 5fd020d..751a591 100644 (file)
@@ -120,72 +120,12 @@ enum iTCO_chipsets {
        TCO_3420,       /* 3420 */
        TCO_3450,       /* 3450 */
        TCO_EP80579,    /* EP80579 */
-       TCO_CPT1,       /* Cougar Point */
-       TCO_CPT2,       /* Cougar Point Desktop */
-       TCO_CPT3,       /* Cougar Point Mobile */
-       TCO_CPT4,       /* Cougar Point */
-       TCO_CPT5,       /* Cougar Point */
-       TCO_CPT6,       /* Cougar Point */
-       TCO_CPT7,       /* Cougar Point */
-       TCO_CPT8,       /* Cougar Point */
-       TCO_CPT9,       /* Cougar Point */
-       TCO_CPT10,      /* Cougar Point */
-       TCO_CPT11,      /* Cougar Point */
-       TCO_CPT12,      /* Cougar Point */
-       TCO_CPT13,      /* Cougar Point */
-       TCO_CPT14,      /* Cougar Point */
-       TCO_CPT15,      /* Cougar Point */
-       TCO_CPT16,      /* Cougar Point */
-       TCO_CPT17,      /* Cougar Point */
-       TCO_CPT18,      /* Cougar Point */
-       TCO_CPT19,      /* Cougar Point */
-       TCO_CPT20,      /* Cougar Point */
-       TCO_CPT21,      /* Cougar Point */
-       TCO_CPT22,      /* Cougar Point */
-       TCO_CPT23,      /* Cougar Point */
-       TCO_CPT24,      /* Cougar Point */
-       TCO_CPT25,      /* Cougar Point */
-       TCO_CPT26,      /* Cougar Point */
-       TCO_CPT27,      /* Cougar Point */
-       TCO_CPT28,      /* Cougar Point */
-       TCO_CPT29,      /* Cougar Point */
-       TCO_CPT30,      /* Cougar Point */
-       TCO_CPT31,      /* Cougar Point */
-       TCO_PBG1,       /* Patsburg */
-       TCO_PBG2,       /* Patsburg */
+       TCO_CPT,        /* Cougar Point */
+       TCO_CPTD,       /* Cougar Point Desktop */
+       TCO_CPTM,       /* Cougar Point Mobile */
+       TCO_PBG,        /* Patsburg */
        TCO_DH89XXCC,   /* DH89xxCC */
-       TCO_PPT0,       /* Panther Point */
-       TCO_PPT1,       /* Panther Point */
-       TCO_PPT2,       /* Panther Point */
-       TCO_PPT3,       /* Panther Point */
-       TCO_PPT4,       /* Panther Point */
-       TCO_PPT5,       /* Panther Point */
-       TCO_PPT6,       /* Panther Point */
-       TCO_PPT7,       /* Panther Point */
-       TCO_PPT8,       /* Panther Point */
-       TCO_PPT9,       /* Panther Point */
-       TCO_PPT10,      /* Panther Point */
-       TCO_PPT11,      /* Panther Point */
-       TCO_PPT12,      /* Panther Point */
-       TCO_PPT13,      /* Panther Point */
-       TCO_PPT14,      /* Panther Point */
-       TCO_PPT15,      /* Panther Point */
-       TCO_PPT16,      /* Panther Point */
-       TCO_PPT17,      /* Panther Point */
-       TCO_PPT18,      /* Panther Point */
-       TCO_PPT19,      /* Panther Point */
-       TCO_PPT20,      /* Panther Point */
-       TCO_PPT21,      /* Panther Point */
-       TCO_PPT22,      /* Panther Point */
-       TCO_PPT23,      /* Panther Point */
-       TCO_PPT24,      /* Panther Point */
-       TCO_PPT25,      /* Panther Point */
-       TCO_PPT26,      /* Panther Point */
-       TCO_PPT27,      /* Panther Point */
-       TCO_PPT28,      /* Panther Point */
-       TCO_PPT29,      /* Panther Point */
-       TCO_PPT30,      /* Panther Point */
-       TCO_PPT31,      /* Panther Point */
+       TCO_PPT,        /* Panther Point */
 };
 
 static struct {
@@ -244,83 +184,14 @@ static struct {
        {"3450", 2},
        {"EP80579", 2},
        {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Patsburg", 2},
+       {"Cougar Point Desktop", 2},
+       {"Cougar Point Mobile", 2},
        {"Patsburg", 2},
        {"DH89xxCC", 2},
        {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
        {NULL, 0}
 };
 
-#define ITCO_PCI_DEVICE(dev, data) \
-       .vendor = PCI_VENDOR_ID_INTEL,  \
-       .device = dev,                  \
-       .subvendor = PCI_ANY_ID,        \
-       .subdevice = PCI_ANY_ID,        \
-       .class = 0,                     \
-       .class_mask = 0,                \
-       .driver_data = data
-
 /*
  * This data only exists for exporting the supported PCI ids
  * via MODULE_DEVICE_TABLE.  We do not actually register a
@@ -328,138 +199,138 @@ static struct {
  * functions that probably will be registered by other drivers.
  */
 static DEFINE_PCI_DEVICE_TABLE(iTCO_wdt_pci_tbl) = {
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AA_0,        TCO_ICH)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AB_0,        TCO_ICH0)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_0,        TCO_ICH2)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_10,       TCO_ICH2M)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_0,        TCO_ICH3)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_12,       TCO_ICH3M)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_0,        TCO_ICH4)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_12,       TCO_ICH4M)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801E_0,         TCO_CICH)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801EB_0,        TCO_ICH5)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB_1,            TCO_6300ESB)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_0,           TCO_ICH6)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_1,           TCO_ICH6M)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_2,           TCO_ICH6W)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB2_0,           TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x2671,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x2672,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x2673,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x2674,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x2675,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x2676,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x2677,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x2678,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x2679,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x267a,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x267b,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x267c,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x267d,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x267e,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x267f,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_0,           TCO_ICH7)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_30,          TCO_ICH7DH)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_1,           TCO_ICH7M)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_31,          TCO_ICH7MDH)},
-       { ITCO_PCI_DEVICE(0x27bc,                               TCO_NM10)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_0,           TCO_ICH8)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_2,           TCO_ICH8DH)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_3,           TCO_ICH8DO)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_4,           TCO_ICH8M)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_1,           TCO_ICH8ME)},
-       { ITCO_PCI_DEVICE(0x2918,                               TCO_ICH9)},
-       { ITCO_PCI_DEVICE(0x2916,                               TCO_ICH9R)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_2,           TCO_ICH9DH)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_4,           TCO_ICH9DO)},
-       { ITCO_PCI_DEVICE(0x2919,                               TCO_ICH9M)},
-       { ITCO_PCI_DEVICE(0x2917,                               TCO_ICH9ME)},
-       { ITCO_PCI_DEVICE(0x3a18,                               TCO_ICH10)},
-       { ITCO_PCI_DEVICE(0x3a16,                               TCO_ICH10R)},
-       { ITCO_PCI_DEVICE(0x3a1a,                               TCO_ICH10D)},
-       { ITCO_PCI_DEVICE(0x3a14,                               TCO_ICH10DO)},
-       { ITCO_PCI_DEVICE(0x3b00,                               TCO_PCH)},
-       { ITCO_PCI_DEVICE(0x3b01,                               TCO_PCHM)},
-       { ITCO_PCI_DEVICE(0x3b02,                               TCO_P55)},
-       { ITCO_PCI_DEVICE(0x3b03,                               TCO_PM55)},
-       { ITCO_PCI_DEVICE(0x3b06,                               TCO_H55)},
-       { ITCO_PCI_DEVICE(0x3b07,                               TCO_QM57)},
-       { ITCO_PCI_DEVICE(0x3b08,                               TCO_H57)},
-       { ITCO_PCI_DEVICE(0x3b09,                               TCO_HM55)},
-       { ITCO_PCI_DEVICE(0x3b0a,                               TCO_Q57)},
-       { ITCO_PCI_DEVICE(0x3b0b,                               TCO_HM57)},
-       { ITCO_PCI_DEVICE(0x3b0d,                               TCO_PCHMSFF)},
-       { ITCO_PCI_DEVICE(0x3b0f,                               TCO_QS57)},
-       { ITCO_PCI_DEVICE(0x3b12,                               TCO_3400)},
-       { ITCO_PCI_DEVICE(0x3b14,                               TCO_3420)},
-       { ITCO_PCI_DEVICE(0x3b16,                               TCO_3450)},
-       { ITCO_PCI_DEVICE(0x5031,                               TCO_EP80579)},
-       { ITCO_PCI_DEVICE(0x1c41,                               TCO_CPT1)},
-       { ITCO_PCI_DEVICE(0x1c42,                               TCO_CPT2)},
-       { ITCO_PCI_DEVICE(0x1c43,                               TCO_CPT3)},
-       { ITCO_PCI_DEVICE(0x1c44,                               TCO_CPT4)},
-       { ITCO_PCI_DEVICE(0x1c45,                               TCO_CPT5)},
-       { ITCO_PCI_DEVICE(0x1c46,                               TCO_CPT6)},
-       { ITCO_PCI_DEVICE(0x1c47,                               TCO_CPT7)},
-       { ITCO_PCI_DEVICE(0x1c48,                               TCO_CPT8)},
-       { ITCO_PCI_DEVICE(0x1c49,                               TCO_CPT9)},
-       { ITCO_PCI_DEVICE(0x1c4a,                               TCO_CPT10)},
-       { ITCO_PCI_DEVICE(0x1c4b,                               TCO_CPT11)},
-       { ITCO_PCI_DEVICE(0x1c4c,                               TCO_CPT12)},
-       { ITCO_PCI_DEVICE(0x1c4d,                               TCO_CPT13)},
-       { ITCO_PCI_DEVICE(0x1c4e,                               TCO_CPT14)},
-       { ITCO_PCI_DEVICE(0x1c4f,                               TCO_CPT15)},
-       { ITCO_PCI_DEVICE(0x1c50,                               TCO_CPT16)},
-       { ITCO_PCI_DEVICE(0x1c51,                               TCO_CPT17)},
-       { ITCO_PCI_DEVICE(0x1c52,                               TCO_CPT18)},
-       { ITCO_PCI_DEVICE(0x1c53,                               TCO_CPT19)},
-       { ITCO_PCI_DEVICE(0x1c54,                               TCO_CPT20)},
-       { ITCO_PCI_DEVICE(0x1c55,                               TCO_CPT21)},
-       { ITCO_PCI_DEVICE(0x1c56,                               TCO_CPT22)},
-       { ITCO_PCI_DEVICE(0x1c57,                               TCO_CPT23)},
-       { ITCO_PCI_DEVICE(0x1c58,                               TCO_CPT24)},
-       { ITCO_PCI_DEVICE(0x1c59,                               TCO_CPT25)},
-       { ITCO_PCI_DEVICE(0x1c5a,                               TCO_CPT26)},
-       { ITCO_PCI_DEVICE(0x1c5b,                               TCO_CPT27)},
-       { ITCO_PCI_DEVICE(0x1c5c,                               TCO_CPT28)},
-       { ITCO_PCI_DEVICE(0x1c5d,                               TCO_CPT29)},
-       { ITCO_PCI_DEVICE(0x1c5e,                               TCO_CPT30)},
-       { ITCO_PCI_DEVICE(0x1c5f,                               TCO_CPT31)},
-       { ITCO_PCI_DEVICE(0x1d40,                               TCO_PBG1)},
-       { ITCO_PCI_DEVICE(0x1d41,                               TCO_PBG2)},
-       { ITCO_PCI_DEVICE(0x2310,                               TCO_DH89XXCC)},
-       { ITCO_PCI_DEVICE(0x1e40,                               TCO_PPT0)},
-       { ITCO_PCI_DEVICE(0x1e41,                               TCO_PPT1)},
-       { ITCO_PCI_DEVICE(0x1e42,                               TCO_PPT2)},
-       { ITCO_PCI_DEVICE(0x1e43,                               TCO_PPT3)},
-       { ITCO_PCI_DEVICE(0x1e44,                               TCO_PPT4)},
-       { ITCO_PCI_DEVICE(0x1e45,                               TCO_PPT5)},
-       { ITCO_PCI_DEVICE(0x1e46,                               TCO_PPT6)},
-       { ITCO_PCI_DEVICE(0x1e47,                               TCO_PPT7)},
-       { ITCO_PCI_DEVICE(0x1e48,                               TCO_PPT8)},
-       { ITCO_PCI_DEVICE(0x1e49,                               TCO_PPT9)},
-       { ITCO_PCI_DEVICE(0x1e4a,                               TCO_PPT10)},
-       { ITCO_PCI_DEVICE(0x1e4b,                               TCO_PPT11)},
-       { ITCO_PCI_DEVICE(0x1e4c,                               TCO_PPT12)},
-       { ITCO_PCI_DEVICE(0x1e4d,                               TCO_PPT13)},
-       { ITCO_PCI_DEVICE(0x1e4e,                               TCO_PPT14)},
-       { ITCO_PCI_DEVICE(0x1e4f,                               TCO_PPT15)},
-       { ITCO_PCI_DEVICE(0x1e50,                               TCO_PPT16)},
-       { ITCO_PCI_DEVICE(0x1e51,                               TCO_PPT17)},
-       { ITCO_PCI_DEVICE(0x1e52,                               TCO_PPT18)},
-       { ITCO_PCI_DEVICE(0x1e53,                               TCO_PPT19)},
-       { ITCO_PCI_DEVICE(0x1e54,                               TCO_PPT20)},
-       { ITCO_PCI_DEVICE(0x1e55,                               TCO_PPT21)},
-       { ITCO_PCI_DEVICE(0x1e56,                               TCO_PPT22)},
-       { ITCO_PCI_DEVICE(0x1e57,                               TCO_PPT23)},
-       { ITCO_PCI_DEVICE(0x1e58,                               TCO_PPT24)},
-       { ITCO_PCI_DEVICE(0x1e59,                               TCO_PPT25)},
-       { ITCO_PCI_DEVICE(0x1e5a,                               TCO_PPT26)},
-       { ITCO_PCI_DEVICE(0x1e5b,                               TCO_PPT27)},
-       { ITCO_PCI_DEVICE(0x1e5c,                               TCO_PPT28)},
-       { ITCO_PCI_DEVICE(0x1e5d,                               TCO_PPT29)},
-       { ITCO_PCI_DEVICE(0x1e5e,                               TCO_PPT30)},
-       { ITCO_PCI_DEVICE(0x1e5f,                               TCO_PPT31)},
+       { PCI_VDEVICE(INTEL, 0x2410), TCO_ICH},
+       { PCI_VDEVICE(INTEL, 0x2420), TCO_ICH0},
+       { PCI_VDEVICE(INTEL, 0x2440), TCO_ICH2},
+       { PCI_VDEVICE(INTEL, 0x244c), TCO_ICH2M},
+       { PCI_VDEVICE(INTEL, 0x2480), TCO_ICH3},
+       { PCI_VDEVICE(INTEL, 0x248c), TCO_ICH3M},
+       { PCI_VDEVICE(INTEL, 0x24c0), TCO_ICH4},
+       { PCI_VDEVICE(INTEL, 0x24cc), TCO_ICH4M},
+       { PCI_VDEVICE(INTEL, 0x2450), TCO_CICH},
+       { PCI_VDEVICE(INTEL, 0x24d0), TCO_ICH5},
+       { PCI_VDEVICE(INTEL, 0x25a1), TCO_6300ESB},
+       { PCI_VDEVICE(INTEL, 0x2640), TCO_ICH6},
+       { PCI_VDEVICE(INTEL, 0x2641), TCO_ICH6M},
+       { PCI_VDEVICE(INTEL, 0x2642), TCO_ICH6W},
+       { PCI_VDEVICE(INTEL, 0x2670), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x2671), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x2672), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x2673), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x2674), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x2675), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x2676), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x2677), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x2678), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x2679), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x267a), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x267b), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x267c), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x267d), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x267e), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x267f), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x27b8), TCO_ICH7},
+       { PCI_VDEVICE(INTEL, 0x27b0), TCO_ICH7DH},
+       { PCI_VDEVICE(INTEL, 0x27b9), TCO_ICH7M},
+       { PCI_VDEVICE(INTEL, 0x27bd), TCO_ICH7MDH},
+       { PCI_VDEVICE(INTEL, 0x27bc), TCO_NM10},
+       { PCI_VDEVICE(INTEL, 0x2810), TCO_ICH8},
+       { PCI_VDEVICE(INTEL, 0x2812), TCO_ICH8DH},
+       { PCI_VDEVICE(INTEL, 0x2814), TCO_ICH8DO},
+       { PCI_VDEVICE(INTEL, 0x2815), TCO_ICH8M},
+       { PCI_VDEVICE(INTEL, 0x2811), TCO_ICH8ME},
+       { PCI_VDEVICE(INTEL, 0x2918), TCO_ICH9},
+       { PCI_VDEVICE(INTEL, 0x2916), TCO_ICH9R},
+       { PCI_VDEVICE(INTEL, 0x2912), TCO_ICH9DH},
+       { PCI_VDEVICE(INTEL, 0x2914), TCO_ICH9DO},
+       { PCI_VDEVICE(INTEL, 0x2919), TCO_ICH9M},
+       { PCI_VDEVICE(INTEL, 0x2917), TCO_ICH9ME},
+       { PCI_VDEVICE(INTEL, 0x3a18), TCO_ICH10},
+       { PCI_VDEVICE(INTEL, 0x3a16), TCO_ICH10R},
+       { PCI_VDEVICE(INTEL, 0x3a1a), TCO_ICH10D},
+       { PCI_VDEVICE(INTEL, 0x3a14), TCO_ICH10DO},
+       { PCI_VDEVICE(INTEL, 0x3b00), TCO_PCH},
+       { PCI_VDEVICE(INTEL, 0x3b01), TCO_PCHM},
+       { PCI_VDEVICE(INTEL, 0x3b02), TCO_P55},
+       { PCI_VDEVICE(INTEL, 0x3b03), TCO_PM55},
+       { PCI_VDEVICE(INTEL, 0x3b06), TCO_H55},
+       { PCI_VDEVICE(INTEL, 0x3b07), TCO_QM57},
+       { PCI_VDEVICE(INTEL, 0x3b08), TCO_H57},
+       { PCI_VDEVICE(INTEL, 0x3b09), TCO_HM55},
+       { PCI_VDEVICE(INTEL, 0x3b0a), TCO_Q57},
+       { PCI_VDEVICE(INTEL, 0x3b0b), TCO_HM57},
+       { PCI_VDEVICE(INTEL, 0x3b0d), TCO_PCHMSFF},
+       { PCI_VDEVICE(INTEL, 0x3b0f), TCO_QS57},
+       { PCI_VDEVICE(INTEL, 0x3b12), TCO_3400},
+       { PCI_VDEVICE(INTEL, 0x3b14), TCO_3420},
+       { PCI_VDEVICE(INTEL, 0x3b16), TCO_3450},
+       { PCI_VDEVICE(INTEL, 0x5031), TCO_EP80579},
+       { PCI_VDEVICE(INTEL, 0x1c41), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c42), TCO_CPTD},
+       { PCI_VDEVICE(INTEL, 0x1c43), TCO_CPTM},
+       { PCI_VDEVICE(INTEL, 0x1c44), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c45), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c46), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c47), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c48), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c49), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c4a), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c4b), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c4c), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c4d), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c4e), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c4f), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c50), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c51), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c52), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c53), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c54), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c55), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c56), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c57), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c58), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c59), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c5a), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c5b), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c5c), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c5d), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c5e), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c5f), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1d40), TCO_PBG},
+       { PCI_VDEVICE(INTEL, 0x1d41), TCO_PBG},
+       { PCI_VDEVICE(INTEL, 0x2310), TCO_DH89XXCC},
+       { PCI_VDEVICE(INTEL, 0x1e40), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e41), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e42), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e43), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e44), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e45), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e46), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e47), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e48), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e49), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e4a), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e4b), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e4c), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e4d), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e4e), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e4f), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e50), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e51), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e52), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e53), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e54), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e55), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e56), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e57), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e58), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e59), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e5a), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e5b), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e5c), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e5d), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e5e), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e5f), TCO_PPT},
        { 0, },                 /* End of list */
 };
 MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl);
@@ -1052,15 +923,10 @@ static void iTCO_wdt_shutdown(struct platform_device *dev)
        iTCO_wdt_stop();
 }
 
-#define iTCO_wdt_suspend NULL
-#define iTCO_wdt_resume  NULL
-
 static struct platform_driver iTCO_wdt_driver = {
        .probe          = iTCO_wdt_probe,
        .remove         = __devexit_p(iTCO_wdt_remove),
        .shutdown       = iTCO_wdt_shutdown,
-       .suspend        = iTCO_wdt_suspend,
-       .resume         = iTCO_wdt_resume,
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = DRV_NAME,
index 86f7cac..b8ef2c6 100644 (file)
@@ -329,12 +329,18 @@ static void imx2_wdt_shutdown(struct platform_device *pdev)
        }
 }
 
+static const struct of_device_id imx2_wdt_dt_ids[] = {
+       { .compatible = "fsl,imx21-wdt", },
+       { /* sentinel */ }
+};
+
 static struct platform_driver imx2_wdt_driver = {
        .remove         = __exit_p(imx2_wdt_remove),
        .shutdown       = imx2_wdt_shutdown,
        .driver         = {
                .name   = DRIVER_NAME,
                .owner  = THIS_MODULE,
+               .of_match_table = imx2_wdt_dt_ids,
        },
 };
 
index 6143f52..8d2d850 100644 (file)
 #include <linux/notifier.h>
 #include <linux/reboot.h>
 #include <linux/fs.h>
-#include <linux/pci.h>
 #include <linux/spinlock.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
+#include <linux/ioport.h>
 
 #define NAME "it8712f_wdt"
 
@@ -51,7 +51,6 @@ MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
 
 static unsigned long wdt_open;
 static unsigned expect_close;
-static spinlock_t io_lock;
 static unsigned char revision;
 
 /* Dog Food address - We use the game port address */
@@ -121,20 +120,26 @@ static inline void superio_select(int ldn)
        outb(ldn, VAL);
 }
 
-static inline void superio_enter(void)
+static inline int superio_enter(void)
 {
-       spin_lock(&io_lock);
+       /*
+        * Try to reserve REG and REG + 1 for exclusive access.
+        */
+       if (!request_muxed_region(REG, 2, NAME))
+               return -EBUSY;
+
        outb(0x87, REG);
        outb(0x01, REG);
        outb(0x55, REG);
        outb(0x55, REG);
+       return 0;
 }
 
 static inline void superio_exit(void)
 {
        outb(0x02, REG);
        outb(0x02, VAL);
-       spin_unlock(&io_lock);
+       release_region(REG, 2);
 }
 
 static inline void it8712f_wdt_ping(void)
@@ -173,10 +178,13 @@ static int it8712f_wdt_get_status(void)
                return 0;
 }
 
-static void it8712f_wdt_enable(void)
+static int it8712f_wdt_enable(void)
 {
+       int ret = superio_enter();
+       if (ret)
+               return ret;
+
        printk(KERN_DEBUG NAME ": enabling watchdog timer\n");
-       superio_enter();
        superio_select(LDN_GPIO);
 
        superio_outb(wdt_control_reg, WDT_CONTROL);
@@ -186,13 +194,17 @@ static void it8712f_wdt_enable(void)
        superio_exit();
 
        it8712f_wdt_ping();
+
+       return 0;
 }
 
-static void it8712f_wdt_disable(void)
+static int it8712f_wdt_disable(void)
 {
-       printk(KERN_DEBUG NAME ": disabling watchdog timer\n");
+       int ret = superio_enter();
+       if (ret)
+               return ret;
 
-       superio_enter();
+       printk(KERN_DEBUG NAME ": disabling watchdog timer\n");
        superio_select(LDN_GPIO);
 
        superio_outb(0, WDT_CONFIG);
@@ -202,6 +214,7 @@ static void it8712f_wdt_disable(void)
        superio_outb(0, WDT_TIMEOUT);
 
        superio_exit();
+       return 0;
 }
 
 static int it8712f_wdt_notify(struct notifier_block *this,
@@ -252,6 +265,7 @@ static long it8712f_wdt_ioctl(struct file *file, unsigned int cmd,
                                                WDIOF_MAGICCLOSE,
        };
        int value;
+       int ret;
 
        switch (cmd) {
        case WDIOC_GETSUPPORT:
@@ -259,7 +273,9 @@ static long it8712f_wdt_ioctl(struct file *file, unsigned int cmd,
                        return -EFAULT;
                return 0;
        case WDIOC_GETSTATUS:
-               superio_enter();
+               ret = superio_enter();
+               if (ret)
+                       return ret;
                superio_select(LDN_GPIO);
 
                value = it8712f_wdt_get_status();
@@ -280,7 +296,9 @@ static long it8712f_wdt_ioctl(struct file *file, unsigned int cmd,
                if (value > (max_units * 60))
                        return -EINVAL;
                margin = value;
-               superio_enter();
+               ret = superio_enter();
+               if (ret)
+                       return ret;
                superio_select(LDN_GPIO);
 
                it8712f_wdt_update_margin();
@@ -299,10 +317,14 @@ static long it8712f_wdt_ioctl(struct file *file, unsigned int cmd,
 
 static int it8712f_wdt_open(struct inode *inode, struct file *file)
 {
+       int ret;
        /* only allow one at a time */
        if (test_and_set_bit(0, &wdt_open))
                return -EBUSY;
-       it8712f_wdt_enable();
+
+       ret = it8712f_wdt_enable();
+       if (ret)
+               return ret;
        return nonseekable_open(inode, file);
 }
 
@@ -313,7 +335,8 @@ static int it8712f_wdt_release(struct inode *inode, struct file *file)
                        ": watchdog device closed unexpectedly, will not"
                        " disable the watchdog timer\n");
        } else if (!nowayout) {
-               it8712f_wdt_disable();
+               if (it8712f_wdt_disable())
+                       printk(KERN_WARNING NAME "Watchdog disable failed\n");
        }
        expect_close = 0;
        clear_bit(0, &wdt_open);
@@ -340,8 +363,10 @@ static int __init it8712f_wdt_find(unsigned short *address)
 {
        int err = -ENODEV;
        int chip_type;
+       int ret = superio_enter();
+       if (ret)
+               return ret;
 
-       superio_enter();
        chip_type = superio_inw(DEVID);
        if (chip_type != IT8712F_DEVID)
                goto exit;
@@ -382,8 +407,6 @@ static int __init it8712f_wdt_init(void)
 {
        int err = 0;
 
-       spin_lock_init(&io_lock);
-
        if (it8712f_wdt_find(&address))
                return -ENODEV;
 
@@ -392,7 +415,11 @@ static int __init it8712f_wdt_init(void)
                return -EBUSY;
        }
 
-       it8712f_wdt_disable();
+       err = it8712f_wdt_disable();
+       if (err) {
+               printk(KERN_ERR NAME ": unable to disable watchdog timer.\n");
+               goto out;
+       }
 
        err = register_reboot_notifier(&it8712f_wdt_notifier);
        if (err) {
index b1bc72f..a2d9a12 100644 (file)
 
 static unsigned int base, gpact, ciract, max_units, chip_type;
 static unsigned long wdt_status;
-static DEFINE_SPINLOCK(spinlock);
 
 static int nogameport = DEFAULT_NOGAMEPORT;
 static int exclusive  = DEFAULT_EXCLUSIVE;
@@ -163,18 +162,26 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started, default="
 
 /* Superio Chip */
 
-static inline void superio_enter(void)
+static inline int superio_enter(void)
 {
+       /*
+        * Try to reserve REG and REG + 1 for exclusive access.
+        */
+       if (!request_muxed_region(REG, 2, WATCHDOG_NAME))
+               return -EBUSY;
+
        outb(0x87, REG);
        outb(0x01, REG);
        outb(0x55, REG);
        outb(0x55, REG);
+       return 0;
 }
 
 static inline void superio_exit(void)
 {
        outb(0x02, REG);
        outb(0x02, VAL);
+       release_region(REG, 2);
 }
 
 static inline void superio_select(int ldn)
@@ -255,12 +262,11 @@ static void wdt_keepalive(void)
        set_bit(WDTS_KEEPALIVE, &wdt_status);
 }
 
-static void wdt_start(void)
+static int wdt_start(void)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&spinlock, flags);
-       superio_enter();
+       int ret = superio_enter();
+       if (ret)
+               return ret;
 
        superio_select(GPIO);
        if (test_bit(WDTS_USE_GP, &wdt_status))
@@ -270,15 +276,15 @@ static void wdt_start(void)
        wdt_update_timeout();
 
        superio_exit();
-       spin_unlock_irqrestore(&spinlock, flags);
+
+       return 0;
 }
 
-static void wdt_stop(void)
+static int wdt_stop(void)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&spinlock, flags);
-       superio_enter();
+       int ret = superio_enter();
+       if (ret)
+               return ret;
 
        superio_select(GPIO);
        superio_outb(0x00, WDTCTRL);
@@ -288,7 +294,7 @@ static void wdt_stop(void)
                superio_outb(0x00, WDTVALMSB);
 
        superio_exit();
-       spin_unlock_irqrestore(&spinlock, flags);
+       return 0;
 }
 
 /**
@@ -303,8 +309,6 @@ static void wdt_stop(void)
 
 static int wdt_set_timeout(int t)
 {
-       unsigned long flags;
-
        if (t < 1 || t > max_units * 60)
                return -EINVAL;
 
@@ -313,14 +317,15 @@ static int wdt_set_timeout(int t)
        else
                timeout = t;
 
-       spin_lock_irqsave(&spinlock, flags);
        if (test_bit(WDTS_TIMER_RUN, &wdt_status)) {
-               superio_enter();
+               int ret = superio_enter();
+               if (ret)
+                       return ret;
+
                superio_select(GPIO);
                wdt_update_timeout();
                superio_exit();
        }
-       spin_unlock_irqrestore(&spinlock, flags);
        return 0;
 }
 
@@ -339,12 +344,12 @@ static int wdt_set_timeout(int t)
 
 static int wdt_get_status(int *status)
 {
-       unsigned long flags;
-
        *status = 0;
        if (testmode) {
-               spin_lock_irqsave(&spinlock, flags);
-               superio_enter();
+               int ret = superio_enter();
+               if (ret)
+                       return ret;
+
                superio_select(GPIO);
                if (superio_inb(WDTCTRL) & WDT_ZERO) {
                        superio_outb(0x00, WDTCTRL);
@@ -353,7 +358,6 @@ static int wdt_get_status(int *status)
                }
 
                superio_exit();
-               spin_unlock_irqrestore(&spinlock, flags);
        }
        if (test_and_clear_bit(WDTS_KEEPALIVE, &wdt_status))
                *status |= WDIOF_KEEPALIVEPING;
@@ -379,9 +383,17 @@ static int wdt_open(struct inode *inode, struct file *file)
        if (exclusive && test_and_set_bit(WDTS_DEV_OPEN, &wdt_status))
                return -EBUSY;
        if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status)) {
+               int ret;
                if (nowayout && !test_and_set_bit(WDTS_LOCKED, &wdt_status))
                        __module_get(THIS_MODULE);
-               wdt_start();
+
+               ret = wdt_start();
+               if (ret) {
+                       clear_bit(WDTS_LOCKED, &wdt_status);
+                       clear_bit(WDTS_TIMER_RUN, &wdt_status);
+                       clear_bit(WDTS_DEV_OPEN, &wdt_status);
+                       return ret;
+               }
        }
        return nonseekable_open(inode, file);
 }
@@ -403,7 +415,16 @@ static int wdt_release(struct inode *inode, struct file *file)
 {
        if (test_bit(WDTS_TIMER_RUN, &wdt_status)) {
                if (test_and_clear_bit(WDTS_EXPECTED, &wdt_status)) {
-                       wdt_stop();
+                       int ret = wdt_stop();
+                       if (ret) {
+                               /*
+                                * Stop failed. Just keep the watchdog alive
+                                * and hope nothing bad happens.
+                                */
+                               set_bit(WDTS_EXPECTED, &wdt_status);
+                               wdt_keepalive();
+                               return ret;
+                       }
                        clear_bit(WDTS_TIMER_RUN, &wdt_status);
                } else {
                        wdt_keepalive();
@@ -484,7 +505,9 @@ static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                                    &ident, sizeof(ident)) ? -EFAULT : 0;
 
        case WDIOC_GETSTATUS:
-               wdt_get_status(&status);
+               rc = wdt_get_status(&status);
+               if (rc)
+                       return rc;
                return put_user(status, uarg.i);
 
        case WDIOC_GETBOOTSTATUS:
@@ -500,14 +523,22 @@ static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
                switch (new_options) {
                case WDIOS_DISABLECARD:
-                       if (test_bit(WDTS_TIMER_RUN, &wdt_status))
-                               wdt_stop();
+                       if (test_bit(WDTS_TIMER_RUN, &wdt_status)) {
+                               rc = wdt_stop();
+                               if (rc)
+                                       return rc;
+                       }
                        clear_bit(WDTS_TIMER_RUN, &wdt_status);
                        return 0;
 
                case WDIOS_ENABLECARD:
-                       if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status))
-                               wdt_start();
+                       if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status)) {
+                               rc = wdt_start();
+                               if (rc) {
+                                       clear_bit(WDTS_TIMER_RUN, &wdt_status);
+                                       return rc;
+                               }
+                       }
                        return 0;
 
                default:
@@ -560,16 +591,17 @@ static int __init it87_wdt_init(void)
        int rc = 0;
        int try_gameport = !nogameport;
        u8  chip_rev;
-       unsigned long flags;
+       int gp_rreq_fail = 0;
 
        wdt_status = 0;
 
-       spin_lock_irqsave(&spinlock, flags);
-       superio_enter();
+       rc = superio_enter();
+       if (rc)
+               return rc;
+
        chip_type = superio_inw(CHIPID);
        chip_rev  = superio_inb(CHIPREV) & 0x0f;
        superio_exit();
-       spin_unlock_irqrestore(&spinlock, flags);
 
        switch (chip_type) {
        case IT8702_ID:
@@ -603,8 +635,9 @@ static int __init it87_wdt_init(void)
                return -ENODEV;
        }
 
-       spin_lock_irqsave(&spinlock, flags);
-       superio_enter();
+       rc = superio_enter();
+       if (rc)
+               return rc;
 
        superio_select(GPIO);
        superio_outb(WDT_TOV1, WDTCFG);
@@ -620,21 +653,16 @@ static int __init it87_wdt_init(void)
                }
                gpact = superio_inb(ACTREG);
                superio_outb(0x01, ACTREG);
-               superio_exit();
-               spin_unlock_irqrestore(&spinlock, flags);
                if (request_region(base, 1, WATCHDOG_NAME))
                        set_bit(WDTS_USE_GP, &wdt_status);
                else
-                       rc = -EIO;
-       } else {
-               superio_exit();
-               spin_unlock_irqrestore(&spinlock, flags);
+                       gp_rreq_fail = 1;
        }
 
        /* If we haven't Gameport support, try to get CIR support */
        if (!test_bit(WDTS_USE_GP, &wdt_status)) {
                if (!request_region(CIR_BASE, 8, WATCHDOG_NAME)) {
-                       if (rc == -EIO)
+                       if (gp_rreq_fail)
                                printk(KERN_ERR PFX
                                        "I/O Address 0x%04x and 0x%04x"
                                        " already in use\n", base, CIR_BASE);
@@ -646,21 +674,16 @@ static int __init it87_wdt_init(void)
                        goto err_out;
                }
                base = CIR_BASE;
-               spin_lock_irqsave(&spinlock, flags);
-               superio_enter();
 
                superio_select(CIR);
                superio_outw(base, BASEREG);
                superio_outb(0x00, CIR_ILS);
                ciract = superio_inb(ACTREG);
                superio_outb(0x01, ACTREG);
-               if (rc == -EIO) {
+               if (gp_rreq_fail) {
                        superio_select(GAMEPORT);
                        superio_outb(gpact, ACTREG);
                }
-
-               superio_exit();
-               spin_unlock_irqrestore(&spinlock, flags);
        }
 
        if (timeout < 1 || timeout > max_units * 60) {
@@ -704,6 +727,7 @@ static int __init it87_wdt_init(void)
                "nogameport=%d)\n", chip_type, chip_rev, timeout,
                nowayout, testmode, exclusive, nogameport);
 
+       superio_exit();
        return 0;
 
 err_out_reboot:
@@ -711,49 +735,37 @@ err_out_reboot:
 err_out_region:
        release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8);
        if (!test_bit(WDTS_USE_GP, &wdt_status)) {
-               spin_lock_irqsave(&spinlock, flags);
-               superio_enter();
                superio_select(CIR);
                superio_outb(ciract, ACTREG);
-               superio_exit();
-               spin_unlock_irqrestore(&spinlock, flags);
        }
 err_out:
        if (try_gameport) {
-               spin_lock_irqsave(&spinlock, flags);
-               superio_enter();
                superio_select(GAMEPORT);
                superio_outb(gpact, ACTREG);
-               superio_exit();
-               spin_unlock_irqrestore(&spinlock, flags);
        }
 
+       superio_exit();
        return rc;
 }
 
 static void __exit it87_wdt_exit(void)
 {
-       unsigned long flags;
-       int nolock;
-
-       nolock = !spin_trylock_irqsave(&spinlock, flags);
-       superio_enter();
-       superio_select(GPIO);
-       superio_outb(0x00, WDTCTRL);
-       superio_outb(0x00, WDTCFG);
-       superio_outb(0x00, WDTVALLSB);
-       if (max_units > 255)
-               superio_outb(0x00, WDTVALMSB);
-       if (test_bit(WDTS_USE_GP, &wdt_status)) {
-               superio_select(GAMEPORT);
-               superio_outb(gpact, ACTREG);
-       } else {
-               superio_select(CIR);
-               superio_outb(ciract, ACTREG);
+       if (superio_enter() == 0) {
+               superio_select(GPIO);
+               superio_outb(0x00, WDTCTRL);
+               superio_outb(0x00, WDTCFG);
+               superio_outb(0x00, WDTVALLSB);
+               if (max_units > 255)
+                       superio_outb(0x00, WDTVALMSB);
+               if (test_bit(WDTS_USE_GP, &wdt_status)) {
+                       superio_select(GAMEPORT);
+                       superio_outb(gpact, ACTREG);
+               } else {
+                       superio_select(CIR);
+                       superio_outb(ciract, ACTREG);
+               }
+               superio_exit();
        }
-       superio_exit();
-       if (!nolock)
-               spin_unlock_irqrestore(&spinlock, flags);
 
        misc_deregister(&wdt_miscdev);
        unregister_reboot_notifier(&wdt_notifier);
index 2b4af22..4dc3102 100644 (file)
@@ -407,12 +407,35 @@ static int __devexit mpcore_wdt_remove(struct platform_device *dev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int mpcore_wdt_suspend(struct platform_device *dev, pm_message_t msg)
+{
+       struct mpcore_wdt *wdt = platform_get_drvdata(dev);
+       mpcore_wdt_stop(wdt);           /* Turn the WDT off */
+       return 0;
+}
+
+static int mpcore_wdt_resume(struct platform_device *dev)
+{
+       struct mpcore_wdt *wdt = platform_get_drvdata(dev);
+       /* re-activate timer */
+       if (test_bit(0, &wdt->timer_alive))
+               mpcore_wdt_start(wdt);
+       return 0;
+}
+#else
+#define mpcore_wdt_suspend     NULL
+#define mpcore_wdt_resume      NULL
+#endif
+
 /* work with hotplug and coldplug */
 MODULE_ALIAS("platform:mpcore_wdt");
 
 static struct platform_driver mpcore_wdt_driver = {
        .probe          = mpcore_wdt_probe,
        .remove         = __devexit_p(mpcore_wdt_remove),
+       .suspend        = mpcore_wdt_suspend,
+       .resume         = mpcore_wdt_resume,
        .shutdown       = mpcore_wdt_shutdown,
        .driver         = {
                .owner  = THIS_MODULE,
index 0430e09..ac37bb8 100644 (file)
@@ -225,11 +225,11 @@ static int __devinit mtx1_wdt_probe(struct platform_device *pdev)
 
        ret = misc_register(&mtx1_wdt_misc);
        if (ret < 0) {
-               printk(KERN_ERR " mtx-1_wdt : failed to register\n");
+               dev_err(&pdev->dev, "failed to register\n");
                return ret;
        }
        mtx1_wdt_start();
-       printk(KERN_INFO "MTX-1 Watchdog driver\n");
+       dev_info(&pdev->dev, "MTX-1 Watchdog driver\n");
        return 0;
 }
 
index afa78a5..809f41c 100644 (file)
@@ -458,7 +458,15 @@ static int __devexit nv_tco_remove(struct platform_device *dev)
 
 static void nv_tco_shutdown(struct platform_device *dev)
 {
+       u32 val;
+
        tco_timer_stop();
+
+       /* Some BIOSes fail the POST (once) if the NO_REBOOT flag is not
+        * unset during shutdown. */
+       pci_read_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, &val);
+       val &= ~MCP51_SMBUS_SETUP_B_TCO_REBOOT;
+       pci_write_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, val);
 }
 
 static struct platform_driver nv_tco_driver = {
diff --git a/drivers/watchdog/of_xilinx_wdt.c b/drivers/watchdog/of_xilinx_wdt.c
new file mode 100644 (file)
index 0000000..4ec741a
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+*   of_xilinx_wdt.c  1.01  A Watchdog Device Driver for Xilinx xps_timebase_wdt
+*
+*   (C) Copyright 2011 (Alejandro Cabrera <aldaya@gmail.com>)
+*
+*       -----------------------
+*
+*   This program is free software; you can redistribute it and/or
+*   modify it under the terms of the GNU General Public License
+*   as published by the Free Software Foundation; either version
+*   2 of the License, or (at your option) any later version.
+*
+*       -----------------------
+*      30-May-2011 Alejandro Cabrera <aldaya@gmail.com>
+*              - If "xlnx,wdt-enable-once" wasn't found on device tree the
+*                module will use CONFIG_WATCHDOG_NOWAYOUT
+*              - If the device tree parameters ("clock-frequency" and
+*                "xlnx,wdt-interval") wasn't found the driver won't
+*                know the wdt reset interval
+*/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/watchdog.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+
+/* Register offsets for the Wdt device */
+#define XWT_TWCSR0_OFFSET   0x0 /* Control/Status Register0 */
+#define XWT_TWCSR1_OFFSET   0x4 /* Control/Status Register1 */
+#define XWT_TBR_OFFSET      0x8 /* Timebase Register Offset */
+
+/* Control/Status Register Masks  */
+#define XWT_CSR0_WRS_MASK   0x00000008 /* Reset status */
+#define XWT_CSR0_WDS_MASK   0x00000004 /* Timer state  */
+#define XWT_CSR0_EWDT1_MASK 0x00000002 /* Enable bit 1 */
+
+/* Control/Status Register 0/1 bits  */
+#define XWT_CSRX_EWDT2_MASK 0x00000001 /* Enable bit 2 */
+
+/* SelfTest constants */
+#define XWT_MAX_SELFTEST_LOOP_COUNT 0x00010000
+#define XWT_TIMER_FAILED            0xFFFFFFFF
+
+#define WATCHDOG_NAME     "Xilinx Watchdog"
+#define PFX WATCHDOG_NAME ": "
+
+struct xwdt_device {
+       struct resource  res;
+       void __iomem *base;
+       u32 nowayout;
+       u32 wdt_interval;
+       u32 boot_status;
+};
+
+static struct xwdt_device xdev;
+
+static  u32 timeout;
+static  u32 control_status_reg;
+static  u8  expect_close;
+static  u8  no_timeout;
+static unsigned long driver_open;
+
+static  DEFINE_SPINLOCK(spinlock);
+
+static void xwdt_start(void)
+{
+       spin_lock(&spinlock);
+
+       /* Clean previous status and enable the watchdog timer */
+       control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
+       control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK);
+
+       iowrite32((control_status_reg | XWT_CSR0_EWDT1_MASK),
+                               xdev.base + XWT_TWCSR0_OFFSET);
+
+       iowrite32(XWT_CSRX_EWDT2_MASK, xdev.base + XWT_TWCSR1_OFFSET);
+
+       spin_unlock(&spinlock);
+}
+
+static void xwdt_stop(void)
+{
+       spin_lock(&spinlock);
+
+       control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
+
+       iowrite32((control_status_reg & ~XWT_CSR0_EWDT1_MASK),
+                               xdev.base + XWT_TWCSR0_OFFSET);
+
+       iowrite32(0, xdev.base + XWT_TWCSR1_OFFSET);
+
+       spin_unlock(&spinlock);
+       printk(KERN_INFO PFX "Stopped!\n");
+}
+
+static void xwdt_keepalive(void)
+{
+       spin_lock(&spinlock);
+
+       control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
+       control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK);
+       iowrite32(control_status_reg, xdev.base + XWT_TWCSR0_OFFSET);
+
+       spin_unlock(&spinlock);
+}
+
+static void xwdt_get_status(int *status)
+{
+       int new_status;
+
+       spin_lock(&spinlock);
+
+       control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
+       new_status = ((control_status_reg &
+                       (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK)) != 0);
+       spin_unlock(&spinlock);
+
+       *status = 0;
+       if (new_status & 1)
+               *status |= WDIOF_CARDRESET;
+}
+
+static u32 xwdt_selftest(void)
+{
+       int i;
+       u32 timer_value1;
+       u32 timer_value2;
+
+       spin_lock(&spinlock);
+
+       timer_value1 = ioread32(xdev.base + XWT_TBR_OFFSET);
+       timer_value2 = ioread32(xdev.base + XWT_TBR_OFFSET);
+
+       for (i = 0;
+               ((i <= XWT_MAX_SELFTEST_LOOP_COUNT) &&
+                       (timer_value2 == timer_value1)); i++) {
+               timer_value2 = ioread32(xdev.base + XWT_TBR_OFFSET);
+       }
+
+       spin_unlock(&spinlock);
+
+       if (timer_value2 != timer_value1)
+               return ~XWT_TIMER_FAILED;
+       else
+               return XWT_TIMER_FAILED;
+}
+
+static int xwdt_open(struct inode *inode, struct file *file)
+{
+       /* Only one process can handle the wdt at a time */
+       if (test_and_set_bit(0, &driver_open))
+               return -EBUSY;
+
+       /* Make sure that the module are always loaded...*/
+       if (xdev.nowayout)
+               __module_get(THIS_MODULE);
+
+       xwdt_start();
+       printk(KERN_INFO PFX "Started...\n");
+
+       return nonseekable_open(inode, file);
+}
+
+static int xwdt_release(struct inode *inode, struct file *file)
+{
+       if (expect_close == 42) {
+               xwdt_stop();
+       } else {
+               printk(KERN_CRIT PFX
+                       "Unexpected close, not stopping watchdog!\n");
+               xwdt_keepalive();
+       }
+
+       clear_bit(0, &driver_open);
+       expect_close = 0;
+       return 0;
+}
+
+/*
+ *      xwdt_write:
+ *      @file: file handle to the watchdog
+ *      @buf: buffer to write (unused as data does not matter here
+ *      @count: count of bytes
+ *      @ppos: pointer to the position to write. No seeks allowed
+ *
+ *      A write to a watchdog device is defined as a keepalive signal. Any
+ *      write of data will do, as we don't define content meaning.
+ */
+static ssize_t xwdt_write(struct file *file, const char __user *buf,
+                                               size_t len, loff_t *ppos)
+{
+       if (len) {
+               if (!xdev.nowayout) {
+                       size_t i;
+
+                       /* In case it was set long ago */
+                       expect_close = 0;
+
+                       for (i = 0; i != len; i++) {
+                               char c;
+
+                               if (get_user(c, buf + i))
+                                       return -EFAULT;
+                               if (c == 'V')
+                                       expect_close = 42;
+                       }
+               }
+               xwdt_keepalive();
+       }
+       return len;
+}
+
+static const struct watchdog_info ident = {
+       .options =  WDIOF_MAGICCLOSE |
+                   WDIOF_KEEPALIVEPING,
+       .firmware_version =     1,
+       .identity =     WATCHDOG_NAME,
+};
+
+/*
+ *      xwdt_ioctl:
+ *      @file: file handle to the device
+ *      @cmd: watchdog command
+ *      @arg: argument pointer
+ *
+ *      The watchdog API defines a common set of functions for all watchdogs
+ *      according to their available features.
+ */
+static long xwdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       int status;
+
+       union {
+               struct watchdog_info __user *ident;
+               int __user *i;
+       } uarg;
+
+       uarg.i = (int __user *)arg;
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               return copy_to_user(uarg.ident, &ident,
+                                       sizeof(ident)) ? -EFAULT : 0;
+
+       case WDIOC_GETBOOTSTATUS:
+               return put_user(xdev.boot_status, uarg.i);
+
+       case WDIOC_GETSTATUS:
+               xwdt_get_status(&status);
+               return put_user(status, uarg.i);
+
+       case WDIOC_KEEPALIVE:
+               xwdt_keepalive();
+               return 0;
+
+       case WDIOC_GETTIMEOUT:
+               if (no_timeout)
+                       return -ENOTTY;
+               else
+                       return put_user(timeout, uarg.i);
+
+       default:
+               return -ENOTTY;
+       }
+}
+
+static const struct file_operations xwdt_fops = {
+       .owner      = THIS_MODULE,
+       .llseek     = no_llseek,
+       .write      = xwdt_write,
+       .open       = xwdt_open,
+       .release    = xwdt_release,
+       .unlocked_ioctl = xwdt_ioctl,
+};
+
+static struct miscdevice xwdt_miscdev = {
+       .minor      = WATCHDOG_MINOR,
+       .name       = "watchdog",
+       .fops       = &xwdt_fops,
+};
+
+static int __devinit xwdt_probe(struct platform_device *pdev)
+{
+       int rc;
+       u32 *tmptr;
+       u32 *pfreq;
+
+       no_timeout = 0;
+
+       pfreq = (u32 *)of_get_property(pdev->dev.of_node->parent,
+                                       "clock-frequency", NULL);
+
+       if (pfreq == NULL) {
+               printk(KERN_WARNING PFX
+                       "The watchdog clock frequency cannot be obtained!\n");
+               no_timeout = 1;
+       }
+
+       rc = of_address_to_resource(pdev->dev.of_node, 0, &xdev.res);
+       if (rc) {
+               printk(KERN_WARNING PFX "invalid address!\n");
+               return rc;
+       }
+
+       tmptr = (u32 *)of_get_property(pdev->dev.of_node,
+                                       "xlnx,wdt-interval", NULL);
+       if (tmptr == NULL) {
+               printk(KERN_WARNING PFX "Parameter \"xlnx,wdt-interval\""
+                                       " not found in device tree!\n");
+               no_timeout = 1;
+       } else {
+               xdev.wdt_interval = *tmptr;
+       }
+
+       tmptr = (u32 *)of_get_property(pdev->dev.of_node,
+                                       "xlnx,wdt-enable-once", NULL);
+       if (tmptr == NULL) {
+               printk(KERN_WARNING PFX "Parameter \"xlnx,wdt-enable-once\""
+                                       " not found in device tree!\n");
+               xdev.nowayout = WATCHDOG_NOWAYOUT;
+       }
+
+/*
+ *  Twice of the 2^wdt_interval / freq  because the first wdt overflow is
+ *  ignored (interrupt), reset is only generated at second wdt overflow
+ */
+       if (!no_timeout)
+               timeout = 2 * ((1<<xdev.wdt_interval) / *pfreq);
+
+       if (!request_mem_region(xdev.res.start,
+                       xdev.res.end - xdev.res.start + 1, WATCHDOG_NAME)) {
+               rc = -ENXIO;
+               printk(KERN_ERR PFX "memory request failure!\n");
+               goto err_out;
+       }
+
+       xdev.base = ioremap(xdev.res.start, xdev.res.end - xdev.res.start + 1);
+       if (xdev.base == NULL) {
+               rc = -ENOMEM;
+               printk(KERN_ERR PFX "ioremap failure!\n");
+               goto release_mem;
+       }
+
+       rc = xwdt_selftest();
+       if (rc == XWT_TIMER_FAILED) {
+               printk(KERN_ERR PFX "SelfTest routine error!\n");
+               goto unmap_io;
+       }
+
+       xwdt_get_status(&xdev.boot_status);
+
+       rc = misc_register(&xwdt_miscdev);
+       if (rc) {
+               printk(KERN_ERR PFX
+                       "cannot register miscdev on minor=%d (err=%d)\n",
+                                               xwdt_miscdev.minor, rc);
+               goto unmap_io;
+       }
+
+       if (no_timeout)
+               printk(KERN_INFO PFX
+                       "driver loaded (timeout=? sec, nowayout=%d)\n",
+                                                   xdev.nowayout);
+       else
+               printk(KERN_INFO PFX
+                       "driver loaded (timeout=%d sec, nowayout=%d)\n",
+                                       timeout, xdev.nowayout);
+
+       expect_close = 0;
+       clear_bit(0, &driver_open);
+
+       return 0;
+
+unmap_io:
+       iounmap(xdev.base);
+release_mem:
+       release_mem_region(xdev.res.start, resource_size(&xdev.res));
+err_out:
+       return rc;
+}
+
+static int __devexit xwdt_remove(struct platform_device *dev)
+{
+       misc_deregister(&xwdt_miscdev);
+       iounmap(xdev.base);
+       release_mem_region(xdev.res.start, resource_size(&xdev.res));
+
+       return 0;
+}
+
+/* Match table for of_platform binding */
+static struct of_device_id __devinitdata xwdt_of_match[] = {
+       { .compatible = "xlnx,xps-timebase-wdt-1.01.a", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, xwdt_of_match);
+
+static struct platform_driver xwdt_driver = {
+       .probe       = xwdt_probe,
+       .remove      = __devexit_p(xwdt_remove),
+       .driver = {
+               .owner = THIS_MODULE,
+               .name  = WATCHDOG_NAME,
+               .of_match_table = xwdt_of_match,
+       },
+};
+
+static int __init xwdt_init(void)
+{
+       return platform_driver_register(&xwdt_driver);
+}
+
+static void __exit xwdt_exit(void)
+{
+       platform_driver_unregister(&xwdt_driver);
+}
+
+module_init(xwdt_init);
+module_exit(xwdt_exit);
+
+MODULE_AUTHOR("Alejandro Cabrera <aldaya@gmail.com>");
+MODULE_DESCRIPTION("Xilinx Watchdog driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index b7c1390..e78d899 100644 (file)
@@ -56,6 +56,7 @@
 #define IO_DEFAULT     0x2E            /* Address used on Portwell Boards */
 
 static int io = IO_DEFAULT;
+static int swc_base_addr = -1;
 
 static int timeout = DEFAULT_TIMEOUT;  /* timeout value */
 static unsigned long timer_enabled;    /* is the timer enabled? */
@@ -116,9 +117,8 @@ static inline void pc87413_enable_swc(void)
 
 /* Read SWC I/O base address */
 
-static inline unsigned int pc87413_get_swc_base(void)
+static void pc87413_get_swc_base_addr(void)
 {
-       unsigned int  swc_base_addr = 0;
        unsigned char addr_l, addr_h = 0;
 
        /* Step 3: Read SWC I/O Base Address */
@@ -136,12 +136,11 @@ static inline unsigned int pc87413_get_swc_base(void)
                "Read SWC I/O Base Address: low %d, high %d, res %d\n",
                                                addr_l, addr_h, swc_base_addr);
 #endif
-       return swc_base_addr;
 }
 
 /* Select Bank 3 of SWC */
 
-static inline void pc87413_swc_bank3(unsigned int swc_base_addr)
+static inline void pc87413_swc_bank3(void)
 {
        /* Step 4: Select Bank3 of SWC */
        outb_p(inb(swc_base_addr + 0x0f) | 0x03, swc_base_addr + 0x0f);
@@ -152,8 +151,7 @@ static inline void pc87413_swc_bank3(unsigned int swc_base_addr)
 
 /* Set watchdog timeout to x minutes */
 
-static inline void pc87413_programm_wdto(unsigned int swc_base_addr,
-                                        char pc87413_time)
+static inline void pc87413_programm_wdto(char pc87413_time)
 {
        /* Step 5: Programm WDTO, Twd. */
        outb_p(pc87413_time, swc_base_addr + WDTO);
@@ -164,7 +162,7 @@ static inline void pc87413_programm_wdto(unsigned int swc_base_addr,
 
 /* Enable WDEN */
 
-static inline void pc87413_enable_wden(unsigned int swc_base_addr)
+static inline void pc87413_enable_wden(void)
 {
        /* Step 6: Enable WDEN */
        outb_p(inb(swc_base_addr + WDCTL) | 0x01, swc_base_addr + WDCTL);
@@ -174,7 +172,7 @@ static inline void pc87413_enable_wden(unsigned int swc_base_addr)
 }
 
 /* Enable SW_WD_TREN */
-static inline void pc87413_enable_sw_wd_tren(unsigned int swc_base_addr)
+static inline void pc87413_enable_sw_wd_tren(void)
 {
        /* Enable SW_WD_TREN */
        outb_p(inb(swc_base_addr + WDCFG) | 0x80, swc_base_addr + WDCFG);
@@ -185,7 +183,7 @@ static inline void pc87413_enable_sw_wd_tren(unsigned int swc_base_addr)
 
 /* Disable SW_WD_TREN */
 
-static inline void pc87413_disable_sw_wd_tren(unsigned int swc_base_addr)
+static inline void pc87413_disable_sw_wd_tren(void)
 {
        /* Disable SW_WD_TREN */
        outb_p(inb(swc_base_addr + WDCFG) & 0x7f, swc_base_addr + WDCFG);
@@ -196,7 +194,7 @@ static inline void pc87413_disable_sw_wd_tren(unsigned int swc_base_addr)
 
 /* Enable SW_WD_TRG */
 
-static inline void pc87413_enable_sw_wd_trg(unsigned int swc_base_addr)
+static inline void pc87413_enable_sw_wd_trg(void)
 {
        /* Enable SW_WD_TRG */
        outb_p(inb(swc_base_addr + WDCTL) | 0x80, swc_base_addr + WDCTL);
@@ -207,7 +205,7 @@ static inline void pc87413_enable_sw_wd_trg(unsigned int swc_base_addr)
 
 /* Disable SW_WD_TRG */
 
-static inline void pc87413_disable_sw_wd_trg(unsigned int swc_base_addr)
+static inline void pc87413_disable_sw_wd_trg(void)
 {
        /* Disable SW_WD_TRG */
        outb_p(inb(swc_base_addr + WDCTL) & 0x7f, swc_base_addr + WDCTL);
@@ -222,18 +220,13 @@ static inline void pc87413_disable_sw_wd_trg(unsigned int swc_base_addr)
 
 static void pc87413_enable(void)
 {
-       unsigned int swc_base_addr;
-
        spin_lock(&io_lock);
 
-       pc87413_select_wdt_out();
-       pc87413_enable_swc();
-       swc_base_addr = pc87413_get_swc_base();
-       pc87413_swc_bank3(swc_base_addr);
-       pc87413_programm_wdto(swc_base_addr, timeout);
-       pc87413_enable_wden(swc_base_addr);
-       pc87413_enable_sw_wd_tren(swc_base_addr);
-       pc87413_enable_sw_wd_trg(swc_base_addr);
+       pc87413_swc_bank3();
+       pc87413_programm_wdto(timeout);
+       pc87413_enable_wden();
+       pc87413_enable_sw_wd_tren();
+       pc87413_enable_sw_wd_trg();
 
        spin_unlock(&io_lock);
 }
@@ -242,17 +235,12 @@ static void pc87413_enable(void)
 
 static void pc87413_disable(void)
 {
-       unsigned int swc_base_addr;
-
        spin_lock(&io_lock);
 
-       pc87413_select_wdt_out();
-       pc87413_enable_swc();
-       swc_base_addr = pc87413_get_swc_base();
-       pc87413_swc_bank3(swc_base_addr);
-       pc87413_disable_sw_wd_tren(swc_base_addr);
-       pc87413_disable_sw_wd_trg(swc_base_addr);
-       pc87413_programm_wdto(swc_base_addr, 0);
+       pc87413_swc_bank3();
+       pc87413_disable_sw_wd_tren();
+       pc87413_disable_sw_wd_trg();
+       pc87413_programm_wdto(0);
 
        spin_unlock(&io_lock);
 }
@@ -261,20 +249,15 @@ static void pc87413_disable(void)
 
 static void pc87413_refresh(void)
 {
-       unsigned int swc_base_addr;
-
        spin_lock(&io_lock);
 
-       pc87413_select_wdt_out();
-       pc87413_enable_swc();
-       swc_base_addr = pc87413_get_swc_base();
-       pc87413_swc_bank3(swc_base_addr);
-       pc87413_disable_sw_wd_tren(swc_base_addr);
-       pc87413_disable_sw_wd_trg(swc_base_addr);
-       pc87413_programm_wdto(swc_base_addr, timeout);
-       pc87413_enable_wden(swc_base_addr);
-       pc87413_enable_sw_wd_tren(swc_base_addr);
-       pc87413_enable_sw_wd_trg(swc_base_addr);
+       pc87413_swc_bank3();
+       pc87413_disable_sw_wd_tren();
+       pc87413_disable_sw_wd_trg();
+       pc87413_programm_wdto(timeout);
+       pc87413_enable_wden();
+       pc87413_enable_sw_wd_tren();
+       pc87413_enable_sw_wd_trg();
 
        spin_unlock(&io_lock);
 }
@@ -528,7 +511,8 @@ static int __init pc87413_init(void)
        printk(KERN_INFO PFX "Version " VERSION " at io 0x%X\n",
                                                        WDT_INDEX_IO_PORT);
 
-       /* request_region(io, 2, "pc87413"); */
+       if (!request_muxed_region(io, 2, MODNAME))
+               return -EBUSY;
 
        ret = register_reboot_notifier(&pc87413_notifier);
        if (ret != 0) {
@@ -541,12 +525,32 @@ static int __init pc87413_init(void)
                printk(KERN_ERR PFX
                        "cannot register miscdev on minor=%d (err=%d)\n",
                        WATCHDOG_MINOR, ret);
-               unregister_reboot_notifier(&pc87413_notifier);
-               return ret;
+               goto reboot_unreg;
        }
        printk(KERN_INFO PFX "initialized. timeout=%d min \n", timeout);
+
+       pc87413_select_wdt_out();
+       pc87413_enable_swc();
+       pc87413_get_swc_base_addr();
+
+       if (!request_region(swc_base_addr, 0x20, MODNAME)) {
+               printk(KERN_ERR PFX
+                       "cannot request SWC region at 0x%x\n", swc_base_addr);
+               ret = -EBUSY;
+               goto misc_unreg;
+       }
+
        pc87413_enable();
+
+       release_region(io, 2);
        return 0;
+
+misc_unreg:
+       misc_deregister(&pc87413_miscdev);
+reboot_unreg:
+       unregister_reboot_notifier(&pc87413_notifier);
+       release_region(io, 2);
+       return ret;
 }
 
 /**
@@ -569,7 +573,7 @@ static void __exit pc87413_exit(void)
 
        misc_deregister(&pc87413_miscdev);
        unregister_reboot_notifier(&pc87413_notifier);
-       /* release_region(io, 2); */
+       release_region(swc_base_addr, 0x20);
 
        printk(KERN_INFO MODNAME " watchdog component driver removed.\n");
 }
index f7f5aa0..30da88f 100644 (file)
@@ -589,6 +589,15 @@ static int s3c2410wdt_resume(struct platform_device *dev)
 #define s3c2410wdt_resume  NULL
 #endif /* CONFIG_PM */
 
+#ifdef CONFIG_OF
+static const struct of_device_id s3c2410_wdt_match[] = {
+       { .compatible = "samsung,s3c2410-wdt" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, s3c2410_wdt_match);
+#else
+#define s3c2410_wdt_match NULL
+#endif
 
 static struct platform_driver s3c2410wdt_driver = {
        .probe          = s3c2410wdt_probe,
@@ -599,6 +608,7 @@ static struct platform_driver s3c2410wdt_driver = {
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = "s3c2410-wdt",
+               .of_match_table = s3c2410_wdt_match,
        },
 };
 
index c7cf4b0..029467e 100644 (file)
@@ -472,15 +472,10 @@ static void sch311x_wdt_shutdown(struct platform_device *dev)
        sch311x_wdt_stop();
 }
 
-#define sch311x_wdt_suspend NULL
-#define sch311x_wdt_resume  NULL
-
 static struct platform_driver sch311x_wdt_driver = {
        .probe          = sch311x_wdt_probe,
        .remove         = __devexit_p(sch311x_wdt_remove),
        .shutdown       = sch311x_wdt_shutdown,
-       .suspend        = sch311x_wdt_suspend,
-       .resume         = sch311x_wdt_resume,
        .driver         = {
                .owner = THIS_MODULE,
                .name = DRV_NAME,
index db84f23..a267dc0 100644 (file)
@@ -64,7 +64,7 @@
  * misses its deadline, the kernel timer will allow the WDT to overflow.
  */
 static int clock_division_ratio = WTCSR_CKS_4096;
-#define next_ping_period(cks)  msecs_to_jiffies(cks - 4)
+#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;
index 0d80e08..cc2cfbe 100644 (file)
@@ -134,6 +134,8 @@ static void wdt_enable(void)
        writel(INT_ENABLE | RESET_ENABLE, wdt->base + WDTCONTROL);
        writel(LOCK, wdt->base + WDTLOCK);
 
+       /* Flush posted writes. */
+       readl(wdt->base + WDTLOCK);
        spin_unlock(&wdt->lock);
 }
 
@@ -144,9 +146,10 @@ static void wdt_disable(void)
 
        writel(UNLOCK, wdt->base + WDTLOCK);
        writel(0, wdt->base + WDTCONTROL);
-       writel(0, wdt->base + WDTLOAD);
        writel(LOCK, wdt->base + WDTLOCK);
 
+       /* Flush posted writes. */
+       readl(wdt->base + WDTLOCK);
        spin_unlock(&wdt->lock);
 }
 
diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c
new file mode 100644 (file)
index 0000000..cfa1a15
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ *     watchdog_core.c
+ *
+ *     (c) Copyright 2008-2011 Alan Cox <alan@lxorguk.ukuu.org.uk>,
+ *                                             All Rights Reserved.
+ *
+ *     (c) Copyright 2008-2011 Wim Van Sebroeck <wim@iguana.be>.
+ *
+ *     This source code is part of the generic code that can be used
+ *     by all the watchdog timer drivers.
+ *
+ *     Based on source code of the following authors:
+ *       Matt Domsch <Matt_Domsch@dell.com>,
+ *       Rob Radez <rob@osinvestor.com>,
+ *       Rusty Lynch <rusty@linux.co.intel.com>
+ *       Satyam Sharma <satyam@infradead.org>
+ *       Randy Dunlap <randy.dunlap@oracle.com>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *
+ *     Neither Alan Cox, CymruNet Ltd., Wim Van Sebroeck nor Iguana vzw.
+ *     admit liability nor provide warranty for any of this software.
+ *     This material is provided "AS-IS" and at no charge.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>      /* For EXPORT_SYMBOL/module stuff/... */
+#include <linux/types.h>       /* For standard types */
+#include <linux/errno.h>       /* For the -ENODEV/... values */
+#include <linux/kernel.h>      /* For printk/panic/... */
+#include <linux/watchdog.h>    /* For watchdog specific items */
+#include <linux/init.h>                /* For __init/__exit/... */
+
+#include "watchdog_dev.h"      /* For watchdog_dev_register/... */
+
+/**
+ * watchdog_register_device() - register a watchdog device
+ * @wdd: watchdog device
+ *
+ * Register a watchdog device with the kernel so that the
+ * watchdog timer can be accessed from userspace.
+ *
+ * A zero is returned on success and a negative errno code for
+ * failure.
+ */
+int watchdog_register_device(struct watchdog_device *wdd)
+{
+       int ret;
+
+       if (wdd == NULL || wdd->info == NULL || wdd->ops == NULL)
+               return -EINVAL;
+
+       /* Mandatory operations need to be supported */
+       if (wdd->ops->start == NULL || wdd->ops->stop == NULL)
+               return -EINVAL;
+
+       /*
+        * Check that we have valid min and max timeout values, if
+        * not reset them both to 0 (=not used or unknown)
+        */
+       if (wdd->min_timeout > wdd->max_timeout) {
+               pr_info("Invalid min and max timeout values, resetting to 0!\n");
+               wdd->min_timeout = 0;
+               wdd->max_timeout = 0;
+       }
+
+       /*
+        * Note: now that all watchdog_device data has been verified, we
+        * will not check this anymore in other functions. If data gets
+        * corrupted in a later stage then we expect a kernel panic!
+        */
+
+       /* We only support 1 watchdog device via the /dev/watchdog interface */
+       ret = watchdog_dev_register(wdd);
+       if (ret) {
+               pr_err("error registering /dev/watchdog (err=%d).\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(watchdog_register_device);
+
+/**
+ * watchdog_unregister_device() - unregister a watchdog device
+ * @wdd: watchdog device to unregister
+ *
+ * Unregister a watchdog device that was previously successfully
+ * registered with watchdog_register_device().
+ */
+void watchdog_unregister_device(struct watchdog_device *wdd)
+{
+       int ret;
+
+       if (wdd == NULL)
+               return;
+
+       ret = watchdog_dev_unregister(wdd);
+       if (ret)
+               pr_err("error unregistering /dev/watchdog (err=%d).\n", ret);
+}
+EXPORT_SYMBOL_GPL(watchdog_unregister_device);
+
+MODULE_AUTHOR("Alan Cox <alan@lxorguk.ukuu.org.uk>");
+MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>");
+MODULE_DESCRIPTION("WatchDog Timer Driver Core");
+MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
new file mode 100644 (file)
index 0000000..d33520d
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ *     watchdog_dev.c
+ *
+ *     (c) Copyright 2008-2011 Alan Cox <alan@lxorguk.ukuu.org.uk>,
+ *                                             All Rights Reserved.
+ *
+ *     (c) Copyright 2008-2011 Wim Van Sebroeck <wim@iguana.be>.
+ *
+ *
+ *     This source code is part of the generic code that can be used
+ *     by all the watchdog timer drivers.
+ *
+ *     This part of the generic code takes care of the following
+ *     misc device: /dev/watchdog.
+ *
+ *     Based on source code of the following authors:
+ *       Matt Domsch <Matt_Domsch@dell.com>,
+ *       Rob Radez <rob@osinvestor.com>,
+ *       Rusty Lynch <rusty@linux.co.intel.com>
+ *       Satyam Sharma <satyam@infradead.org>
+ *       Randy Dunlap <randy.dunlap@oracle.com>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *
+ *     Neither Alan Cox, CymruNet Ltd., Wim Van Sebroeck nor Iguana vzw.
+ *     admit liability nor provide warranty for any of this software.
+ *     This material is provided "AS-IS" and at no charge.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>      /* For module stuff/... */
+#include <linux/types.h>       /* For standard types (like size_t) */
+#include <linux/errno.h>       /* For the -ENODEV/... values */
+#include <linux/kernel.h>      /* For printk/panic/... */
+#include <linux/fs.h>          /* For file operations */
+#include <linux/watchdog.h>    /* For watchdog specific items */
+#include <linux/miscdevice.h>  /* For handling misc devices */
+#include <linux/init.h>                /* For __init/__exit/... */
+#include <linux/uaccess.h>     /* For copy_to_user/put_user/... */
+
+/* make sure we only register one /dev/watchdog device */
+static unsigned long watchdog_dev_busy;
+/* the watchdog device behind /dev/watchdog */
+static struct watchdog_device *wdd;
+
+/*
+ *     watchdog_ping: ping the watchdog.
+ *     @wddev: the watchdog device to ping
+ *
+ *     If the watchdog has no own ping operation then it needs to be
+ *     restarted via the start operation. This wrapper function does
+ *     exactly that.
+ *     We only ping when the watchdog device is running.
+ */
+
+static int watchdog_ping(struct watchdog_device *wddev)
+{
+       if (test_bit(WDOG_ACTIVE, &wdd->status)) {
+               if (wddev->ops->ping)
+                       return wddev->ops->ping(wddev);  /* ping the watchdog */
+               else
+                       return wddev->ops->start(wddev); /* restart watchdog */
+       }
+       return 0;
+}
+
+/*
+ *     watchdog_start: wrapper to start the watchdog.
+ *     @wddev: the watchdog device to start
+ *
+ *     Start the watchdog if it is not active and mark it active.
+ *     This function returns zero on success or a negative errno code for
+ *     failure.
+ */
+
+static int watchdog_start(struct watchdog_device *wddev)
+{
+       int err;
+
+       if (!test_bit(WDOG_ACTIVE, &wdd->status)) {
+               err = wddev->ops->start(wddev);
+               if (err < 0)
+                       return err;
+
+               set_bit(WDOG_ACTIVE, &wdd->status);
+       }
+       return 0;
+}
+
+/*
+ *     watchdog_stop: wrapper to stop the watchdog.
+ *     @wddev: the watchdog device to stop
+ *
+ *     Stop the watchdog if it is still active and unmark it active.
+ *     This function returns zero on success or a negative errno code for
+ *     failure.
+ *     If the 'nowayout' feature was set, the watchdog cannot be stopped.
+ */
+
+static int watchdog_stop(struct watchdog_device *wddev)
+{
+       int err = -EBUSY;
+
+       if (test_bit(WDOG_NO_WAY_OUT, &wdd->status)) {
+               pr_info("%s: nowayout prevents watchdog to be stopped!\n",
+                                                       wdd->info->identity);
+               return err;
+       }
+
+       if (test_bit(WDOG_ACTIVE, &wdd->status)) {
+               err = wddev->ops->stop(wddev);
+               if (err < 0)
+                       return err;
+
+               clear_bit(WDOG_ACTIVE, &wdd->status);
+       }
+       return 0;
+}
+
+/*
+ *     watchdog_write: writes to the watchdog.
+ *     @file: file from VFS
+ *     @data: user address of data
+ *     @len: length of data
+ *     @ppos: pointer to the file offset
+ *
+ *     A write to a watchdog device is defined as a keepalive ping.
+ *     Writing the magic 'V' sequence allows the next close to turn
+ *     off the watchdog (if 'nowayout' is not set).
+ */
+
+static ssize_t watchdog_write(struct file *file, const char __user *data,
+                                               size_t len, loff_t *ppos)
+{
+       size_t i;
+       char c;
+
+       if (len == 0)
+               return 0;
+
+       /*
+        * Note: just in case someone wrote the magic character
+        * five months ago...
+        */
+       clear_bit(WDOG_ALLOW_RELEASE, &wdd->status);
+
+       /* scan to see whether or not we got the magic character */
+       for (i = 0; i != len; i++) {
+               if (get_user(c, data + i))
+                       return -EFAULT;
+               if (c == 'V')
+                       set_bit(WDOG_ALLOW_RELEASE, &wdd->status);
+       }
+
+       /* someone wrote to us, so we send the watchdog a keepalive ping */
+       watchdog_ping(wdd);
+
+       return len;
+}
+
+/*
+ *     watchdog_ioctl: handle the different ioctl's for the watchdog device.
+ *     @file: file handle to the device
+ *     @cmd: watchdog command
+ *     @arg: argument pointer
+ *
+ *     The watchdog API defines a common set of functions for all watchdogs
+ *     according to their available features.
+ */
+
+static long watchdog_ioctl(struct file *file, unsigned int cmd,
+                                                       unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+       int __user *p = argp;
+       unsigned int val;
+       int err;
+
+       if (wdd->ops->ioctl) {
+               err = wdd->ops->ioctl(wdd, cmd, arg);
+               if (err != -ENOIOCTLCMD)
+                       return err;
+       }
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               return copy_to_user(argp, wdd->info,
+                       sizeof(struct watchdog_info)) ? -EFAULT : 0;
+       case WDIOC_GETSTATUS:
+               val = wdd->ops->status ? wdd->ops->status(wdd) : 0;
+               return put_user(val, p);
+       case WDIOC_GETBOOTSTATUS:
+               return put_user(wdd->bootstatus, p);
+       case WDIOC_SETOPTIONS:
+               if (get_user(val, p))
+                       return -EFAULT;
+               if (val & WDIOS_DISABLECARD) {
+                       err = watchdog_stop(wdd);
+                       if (err < 0)
+                               return err;
+               }
+               if (val & WDIOS_ENABLECARD) {
+                       err = watchdog_start(wdd);
+                       if (err < 0)
+                               return err;
+               }
+               return 0;
+       case WDIOC_KEEPALIVE:
+               if (!(wdd->info->options & WDIOF_KEEPALIVEPING))
+                       return -EOPNOTSUPP;
+               watchdog_ping(wdd);
+               return 0;
+       case WDIOC_SETTIMEOUT:
+               if ((wdd->ops->set_timeout == NULL) ||
+                   !(wdd->info->options & WDIOF_SETTIMEOUT))
+                       return -EOPNOTSUPP;
+               if (get_user(val, p))
+                       return -EFAULT;
+               if ((wdd->max_timeout != 0) &&
+                   (val < wdd->min_timeout || val > wdd->max_timeout))
+                               return -EINVAL;
+               err = wdd->ops->set_timeout(wdd, val);
+               if (err < 0)
+                       return err;
+               wdd->timeout = val;
+               /* If the watchdog is active then we send a keepalive ping
+                * to make sure that the watchdog keep's running (and if
+                * possible that it takes the new timeout) */
+               watchdog_ping(wdd);
+               /* Fall */
+       case WDIOC_GETTIMEOUT:
+               /* timeout == 0 means that we don't know the timeout */
+               if (wdd->timeout == 0)
+                       return -EOPNOTSUPP;
+               return put_user(wdd->timeout, p);
+       default:
+               return -ENOTTY;
+       }
+}
+
+/*
+ *     watchdog_open: open the /dev/watchdog device.
+ *     @inode: inode of device
+ *     @file: file handle to device
+ *
+ *     When the /dev/watchdog device gets opened, we start the watchdog.
+ *     Watch out: the /dev/watchdog device is single open, so we make sure
+ *     it can only be opened once.
+ */
+
+static int watchdog_open(struct inode *inode, struct file *file)
+{
+       int err = -EBUSY;
+
+       /* the watchdog is single open! */
+       if (test_and_set_bit(WDOG_DEV_OPEN, &wdd->status))
+               return -EBUSY;
+
+       /*
+        * If the /dev/watchdog device is open, we don't want the module
+        * to be unloaded.
+        */
+       if (!try_module_get(wdd->ops->owner))
+               goto out;
+
+       err = watchdog_start(wdd);
+       if (err < 0)
+               goto out_mod;
+
+       /* dev/watchdog is a virtual (and thus non-seekable) filesystem */
+       return nonseekable_open(inode, file);
+
+out_mod:
+       module_put(wdd->ops->owner);
+out:
+       clear_bit(WDOG_DEV_OPEN, &wdd->status);
+       return err;
+}
+
+/*
+ *      watchdog_release: release the /dev/watchdog device.
+ *      @inode: inode of device
+ *      @file: file handle to device
+ *
+ *     This is the code for when /dev/watchdog gets closed. We will only
+ *     stop the watchdog when we have received the magic char (and nowayout
+ *     was not set), else the watchdog will keep running.
+ */
+
+static int watchdog_release(struct inode *inode, struct file *file)
+{
+       int err = -EBUSY;
+
+       /*
+        * We only stop the watchdog if we received the magic character
+        * or if WDIOF_MAGICCLOSE is not set. If nowayout was set then
+        * watchdog_stop will fail.
+        */
+       if (test_and_clear_bit(WDOG_ALLOW_RELEASE, &wdd->status) ||
+           !(wdd->info->options & WDIOF_MAGICCLOSE))
+               err = watchdog_stop(wdd);
+
+       /* If the watchdog was not stopped, send a keepalive ping */
+       if (err < 0) {
+               pr_crit("%s: watchdog did not stop!\n", wdd->info->identity);
+               watchdog_ping(wdd);
+       }
+
+       /* Allow the owner module to be unloaded again */
+       module_put(wdd->ops->owner);
+
+       /* make sure that /dev/watchdog can be re-opened */
+       clear_bit(WDOG_DEV_OPEN, &wdd->status);
+
+       return 0;
+}
+
+static const struct file_operations watchdog_fops = {
+       .owner          = THIS_MODULE,
+       .write          = watchdog_write,
+       .unlocked_ioctl = watchdog_ioctl,
+       .open           = watchdog_open,
+       .release        = watchdog_release,
+};
+
+static struct miscdevice watchdog_miscdev = {
+       .minor          = WATCHDOG_MINOR,
+       .name           = "watchdog",
+       .fops           = &watchdog_fops,
+};
+
+/*
+ *     watchdog_dev_register:
+ *     @watchdog: watchdog device
+ *
+ *     Register a watchdog device as /dev/watchdog. /dev/watchdog
+ *     is actually a miscdevice and thus we set it up like that.
+ */
+
+int watchdog_dev_register(struct watchdog_device *watchdog)
+{
+       int err;
+
+       /* Only one device can register for /dev/watchdog */
+       if (test_and_set_bit(0, &watchdog_dev_busy)) {
+               pr_err("only one watchdog can use /dev/watchdog.\n");
+               return -EBUSY;
+       }
+
+       wdd = watchdog;
+
+       err = misc_register(&watchdog_miscdev);
+       if (err != 0) {
+               pr_err("%s: cannot register miscdev on minor=%d (err=%d).\n",
+                       watchdog->info->identity, WATCHDOG_MINOR, err);
+               goto out;
+       }
+
+       return 0;
+
+out:
+       wdd = NULL;
+       clear_bit(0, &watchdog_dev_busy);
+       return err;
+}
+
+/*
+ *     watchdog_dev_unregister:
+ *     @watchdog: watchdog device
+ *
+ *     Deregister the /dev/watchdog device.
+ */
+
+int watchdog_dev_unregister(struct watchdog_device *watchdog)
+{
+       /* Check that a watchdog device was registered in the past */
+       if (!test_bit(0, &watchdog_dev_busy) || !wdd)
+               return -ENODEV;
+
+       /* We can only unregister the watchdog device that was registered */
+       if (watchdog != wdd) {
+               pr_err("%s: watchdog was not registered as /dev/watchdog.\n",
+                       watchdog->info->identity);
+               return -ENODEV;
+       }
+
+       misc_deregister(&watchdog_miscdev);
+       wdd = NULL;
+       clear_bit(0, &watchdog_dev_busy);
+       return 0;
+}
diff --git a/drivers/watchdog/watchdog_dev.h b/drivers/watchdog/watchdog_dev.h
new file mode 100644 (file)
index 0000000..bc7612b
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ *     watchdog_core.h
+ *
+ *     (c) Copyright 2008-2011 Alan Cox <alan@lxorguk.ukuu.org.uk>,
+ *                                             All Rights Reserved.
+ *
+ *     (c) Copyright 2008-2011 Wim Van Sebroeck <wim@iguana.be>.
+ *
+ *     This source code is part of the generic code that can be used
+ *     by all the watchdog timer drivers.
+ *
+ *     Based on source code of the following authors:
+ *       Matt Domsch <Matt_Domsch@dell.com>,
+ *       Rob Radez <rob@osinvestor.com>,
+ *       Rusty Lynch <rusty@linux.co.intel.com>
+ *       Satyam Sharma <satyam@infradead.org>
+ *       Randy Dunlap <randy.dunlap@oracle.com>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *
+ *     Neither Alan Cox, CymruNet Ltd., Wim Van Sebroeck nor Iguana vzw.
+ *     admit liability nor provide warranty for any of this software.
+ *     This material is provided "AS-IS" and at no charge.
+ */
+
+/*
+ *     Functions/procedures to be called by the core
+ */
+int watchdog_dev_register(struct watchdog_device *);
+int watchdog_dev_unregister(struct watchdog_device *);
index f815283..5f7ff8e 100644 (file)
@@ -11,7 +11,7 @@ config XEN_BALLOON
 
 config XEN_SELFBALLOONING
        bool "Dynamically self-balloon kernel memory to target"
-       depends on XEN && XEN_BALLOON && CLEANCACHE && SWAP
+       depends on XEN && XEN_BALLOON && CLEANCACHE && SWAP && XEN_TMEM
        default n
        help
          Self-ballooning dynamically balloons available kernel memory driven
index fd725cd..4f44b34 100644 (file)
@@ -82,7 +82,7 @@ static inline grant_ref_t *__gnttab_entry(grant_ref_t entry)
 static int get_free_entries(unsigned count)
 {
        unsigned long flags;
-       int ref, rc;
+       int ref, rc = 0;
        grant_ref_t head;
 
        spin_lock_irqsave(&gnttab_list_lock, flags);
index 206c4ce..978d2c6 100644 (file)
@@ -11,7 +11,6 @@
 #include <xen/xenbus.h>
 #include <xen/events.h>
 #include <asm/xen/pci.h>
-#include <linux/workqueue.h>
 #include "pciback.h"
 
 #define        DRV_NAME        "xen-pciback"
index 010937b..6ea852e 100644 (file)
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
-
+#include <linux/module.h>
+#include <linux/workqueue.h>
 #include <xen/balloon.h>
-
 #include <xen/tmem.h>
+#include <xen/xen.h>
 
 /* Enable/disable with sysfs. */
 static int xen_selfballooning_enabled __read_mostly;
index e9cb57f..9a1d426 100644 (file)
@@ -182,11 +182,11 @@ int v9fs_set_create_acl(struct dentry *dentry,
        return 0;
 }
 
-int v9fs_acl_mode(struct inode *dir, mode_t *modep,
+int v9fs_acl_mode(struct inode *dir, umode_t *modep,
                  struct posix_acl **dpacl, struct posix_acl **pacl)
 {
        int retval = 0;
-       mode_t mode = *modep;
+       umode_t mode = *modep;
        struct posix_acl *acl = NULL;
 
        if (!S_ISLNK(mode)) {
@@ -319,7 +319,7 @@ static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name,
        case ACL_TYPE_ACCESS:
                name = POSIX_ACL_XATTR_ACCESS;
                if (acl) {
-                       mode_t mode = inode->i_mode;
+                       umode_t mode = inode->i_mode;
                        retval = posix_acl_equiv_mode(acl, &mode);
                        if (retval < 0)
                                goto err_out;
index ddb7ae1..5595564 100644 (file)
@@ -20,7 +20,7 @@ extern struct posix_acl *v9fs_iop_get_acl(struct inode *inode, int type);
 extern int v9fs_acl_chmod(struct dentry *);
 extern int v9fs_set_create_acl(struct dentry *,
                               struct posix_acl **, struct posix_acl **);
-extern int v9fs_acl_mode(struct inode *dir, mode_t *modep,
+extern int v9fs_acl_mode(struct inode *dir, umode_t *modep,
                         struct posix_acl **dpacl, struct posix_acl **pacl);
 #else
 #define v9fs_iop_get_acl NULL
@@ -38,7 +38,7 @@ static inline int v9fs_set_create_acl(struct dentry *dentry,
 {
        return 0;
 }
-static inline int v9fs_acl_mode(struct inode *dir, mode_t *modep,
+static inline int v9fs_acl_mode(struct inode *dir, umode_t *modep,
                                struct posix_acl **dpacl,
                                struct posix_acl **pacl)
 {
index 9a26dce..b6c8ed2 100644 (file)
@@ -206,7 +206,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
        int err = 0;
        gid_t gid;
        int flags;
-       mode_t mode;
+       umode_t mode;
        char *name = NULL;
        struct file *filp;
        struct p9_qid qid;
@@ -348,7 +348,7 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir,
        struct p9_fid *fid = NULL, *dfid = NULL;
        gid_t gid;
        char *name;
-       mode_t mode;
+       umode_t mode;
        struct inode *inode;
        struct p9_qid qid;
        struct dentry *dir_dentry;
@@ -751,7 +751,7 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode,
        int err;
        gid_t gid;
        char *name;
-       mode_t mode;
+       umode_t mode;
        struct v9fs_session_info *v9ses;
        struct p9_fid *fid = NULL, *dfid = NULL;
        struct inode *inode;
index 19891aa..9fe0b34 100644 (file)
@@ -127,14 +127,21 @@ config TMPFS_POSIX_ACL
        select TMPFS_XATTR
        select GENERIC_ACL
        help
-         POSIX Access Control Lists (ACLs) support permissions for users and
-         groups beyond the owner/group/world scheme.
+         POSIX Access Control Lists (ACLs) support additional access rights
+         for users and groups beyond the standard owner/group/world scheme,
+         and this option selects support for ACLs specifically for tmpfs
+         filesystems.
+
+         If you've selected TMPFS, it's possible that you'll also need
+         this option as there are a number of Linux distros that require
+         POSIX ACL support under /dev for certain features to work properly.
+         For example, some distros need this feature for ALSA-related /dev
+         files for sound to work properly.  In short, if you're not sure,
+         say Y.
 
          To learn more about Access Control Lists, visit the POSIX ACLs for
          Linux website <http://acl.bestbits.at/>.
 
-         If you don't know what Access Control Lists are, say N.
-
 config TMPFS_XATTR
        bool "Tmpfs extended attributes"
        depends on TMPFS
index 475f9c5..326dc08 100644 (file)
 
 /* #define DEBUG */
 
-#ifdef DEBUG
-#define DPRINTK(fmt, args...)                          \
-do {                                                   \
-       printk(KERN_DEBUG "pid %d: %s: " fmt "\n",      \
-               current->pid, __func__, ##args);        \
-} while (0)
-#else
-#define DPRINTK(fmt, args...) do {} while (0)
-#endif
-
-#define AUTOFS_WARN(fmt, args...)                      \
-do {                                                   \
+#define DPRINTK(fmt, ...)                              \
+       pr_debug("pid %d: %s: " fmt "\n",               \
+               current->pid, __func__, ##__VA_ARGS__)
+
+#define AUTOFS_WARN(fmt, ...)                          \
        printk(KERN_WARNING "pid %d: %s: " fmt "\n",    \
-               current->pid, __func__, ##args);        \
-} while (0)
+               current->pid, __func__, ##__VA_ARGS__)
 
-#define AUTOFS_ERROR(fmt, args...)                     \
-do {                                                   \
+#define AUTOFS_ERROR(fmt, ...)                         \
        printk(KERN_ERR "pid %d: %s: " fmt "\n",        \
-               current->pid, __func__, ##args);        \
-} while (0)
+               current->pid, __func__, ##__VA_ARGS__)
 
 /* Unified info structure.  This is pointed to by both the dentry and
    inode structures.  Each file in the filesystem has an instance of this
index 2543598..e1fbdee 100644 (file)
@@ -104,7 +104,7 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi,
        size_t pktsz;
 
        DPRINTK("wait id = 0x%08lx, name = %.*s, type=%d",
-               wq->wait_queue_token, wq->name.len, wq->name.name, type);
+               (unsigned long) wq->wait_queue_token, wq->name.len, wq->name.name, type);
 
        memset(&pkt,0,sizeof pkt); /* For security reasons */
 
index 54b8c28..720d885 100644 (file)
@@ -474,17 +474,22 @@ befs_follow_link(struct dentry *dentry, struct nameidata *nd)
                befs_data_stream *data = &befs_ino->i_data.ds;
                befs_off_t len = data->size;
 
-               befs_debug(sb, "Follow long symlink");
-
-               link = kmalloc(len, GFP_NOFS);
-               if (!link) {
-                       link = ERR_PTR(-ENOMEM);
-               } else if (befs_read_lsymlink(sb, data, link, len) != len) {
-                       kfree(link);
-                       befs_error(sb, "Failed to read entire long symlink");
+               if (len == 0) {
+                       befs_error(sb, "Long symlink with illegal length");
                        link = ERR_PTR(-EIO);
                } else {
-                       link[len - 1] = '\0';
+                       befs_debug(sb, "Follow long symlink");
+
+                       link = kmalloc(len, GFP_NOFS);
+                       if (!link) {
+                               link = ERR_PTR(-ENOMEM);
+                       } else if (befs_read_lsymlink(sb, data, link, len) != len) {
+                               kfree(link);
+                               befs_error(sb, "Failed to read entire long symlink");
+                               link = ERR_PTR(-EIO);
+                       } else {
+                               link[len - 1] = '\0';
+                       }
                }
        } else {
                link = befs_ino->i_data.symlink;
index f55aad4..ff77262 100644 (file)
@@ -387,6 +387,10 @@ int blkdev_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
        struct inode *bd_inode = filp->f_mapping->host;
        struct block_device *bdev = I_BDEV(bd_inode);
        int error;
+       
+       error = filemap_write_and_wait_range(filp->f_mapping, start, end);
+       if (error)
+               return error;
 
        /*
         * There is no need to serialise calls to blkdev_issue_flush with
@@ -552,6 +556,7 @@ struct block_device *bdget(dev_t dev)
 
        if (inode->i_state & I_NEW) {
                bdev->bd_contains = NULL;
+               bdev->bd_super = NULL;
                bdev->bd_inode = inode;
                bdev->bd_block_size = (1 << inode->i_blkbits);
                bdev->bd_part_count = 0;
index 9b72dcf..40e6ac0 100644 (file)
@@ -6,5 +6,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
           transaction.o inode.o file.o tree-defrag.o \
           extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \
           extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
-          export.o tree-log.o acl.o free-space-cache.o zlib.o lzo.o \
+          export.o tree-log.o free-space-cache.o zlib.o lzo.o \
           compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o
+
+btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
index 65a735d..eb159aa 100644 (file)
@@ -28,8 +28,6 @@
 #include "btrfs_inode.h"
 #include "xattr.h"
 
-#ifdef CONFIG_BTRFS_FS_POSIX_ACL
-
 struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
 {
        int size;
@@ -111,7 +109,6 @@ static int btrfs_set_acl(struct btrfs_trans_handle *trans,
        int ret, size = 0;
        const char *name;
        char *value = NULL;
-       mode_t mode;
 
        if (acl) {
                ret = posix_acl_valid(acl);
@@ -122,13 +119,11 @@ static int btrfs_set_acl(struct btrfs_trans_handle *trans,
 
        switch (type) {
        case ACL_TYPE_ACCESS:
-               mode = inode->i_mode;
                name = POSIX_ACL_XATTR_ACCESS;
                if (acl) {
-                       ret = posix_acl_equiv_mode(acl, &mode);
+                       ret = posix_acl_equiv_mode(acl, &inode->i_mode);
                        if (ret < 0)
                                return ret;
-                       inode->i_mode = mode;
                }
                ret = 0;
                break;
@@ -222,19 +217,16 @@ int btrfs_init_acl(struct btrfs_trans_handle *trans,
        }
 
        if (IS_POSIXACL(dir) && acl) {
-               mode_t mode = inode->i_mode;
-
                if (S_ISDIR(inode->i_mode)) {
                        ret = btrfs_set_acl(trans, inode, acl,
                                            ACL_TYPE_DEFAULT);
                        if (ret)
                                goto failed;
                }
-               ret = posix_acl_create(&acl, GFP_NOFS, &mode);
+               ret = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
                if (ret < 0)
                        return ret;
 
-               inode->i_mode = mode;
                if (ret > 0) {
                        /* we need an acl */
                        ret = btrfs_set_acl(trans, inode, acl, ACL_TYPE_ACCESS);
@@ -282,18 +274,3 @@ const struct xattr_handler btrfs_xattr_acl_access_handler = {
        .get    = btrfs_xattr_acl_get,
        .set    = btrfs_xattr_acl_set,
 };
-
-#else /* CONFIG_BTRFS_FS_POSIX_ACL */
-
-int btrfs_acl_chmod(struct inode *inode)
-{
-       return 0;
-}
-
-int btrfs_init_acl(struct btrfs_trans_handle *trans,
-                  struct inode *inode, struct inode *dir)
-{
-       return 0;
-}
-
-#endif /* CONFIG_BTRFS_FS_POSIX_ACL */
index bfe42b0..8ec5d86 100644 (file)
@@ -338,6 +338,7 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,
        u64 first_byte = disk_start;
        struct block_device *bdev;
        int ret;
+       int skip_sum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
 
        WARN_ON(start & ((u64)PAGE_CACHE_SIZE - 1));
        cb = kmalloc(compressed_bio_size(root, compressed_len), GFP_NOFS);
@@ -392,8 +393,11 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,
                        ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0);
                        BUG_ON(ret);
 
-                       ret = btrfs_csum_one_bio(root, inode, bio, start, 1);
-                       BUG_ON(ret);
+                       if (!skip_sum) {
+                               ret = btrfs_csum_one_bio(root, inode, bio,
+                                                        start, 1);
+                               BUG_ON(ret);
+                       }
 
                        ret = btrfs_map_bio(root, WRITE, bio, 0, 1);
                        BUG_ON(ret);
@@ -418,8 +422,10 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,
        ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0);
        BUG_ON(ret);
 
-       ret = btrfs_csum_one_bio(root, inode, bio, start, 1);
-       BUG_ON(ret);
+       if (!skip_sum) {
+               ret = btrfs_csum_one_bio(root, inode, bio, start, 1);
+               BUG_ON(ret);
+       }
 
        ret = btrfs_map_bio(root, WRITE, bio, 0, 1);
        BUG_ON(ret);
index 365c4e1..03912c5 100644 (file)
@@ -1415,17 +1415,15 @@ void btrfs_set_##name(struct extent_buffer *eb, type *s, u##bits val);
 #define BTRFS_SETGET_HEADER_FUNCS(name, type, member, bits)            \
 static inline u##bits btrfs_##name(struct extent_buffer *eb)           \
 {                                                                      \
-       type *p = kmap_atomic(eb->first_page, KM_USER0);                \
+       type *p = page_address(eb->first_page);                         \
        u##bits res = le##bits##_to_cpu(p->member);                     \
-       kunmap_atomic(p, KM_USER0);                                     \
        return res;                                                     \
 }                                                                      \
 static inline void btrfs_set_##name(struct extent_buffer *eb,          \
                                    u##bits val)                        \
 {                                                                      \
-       type *p = kmap_atomic(eb->first_page, KM_USER0);                \
+       type *p = page_address(eb->first_page);                         \
        p->member = cpu_to_le##bits(val);                               \
-       kunmap_atomic(p, KM_USER0);                                     \
 }
 
 #define BTRFS_SETGET_STACK_FUNCS(name, type, member, bits)             \
@@ -2367,8 +2365,8 @@ static inline int btrfs_insert_empty_item(struct btrfs_trans_handle *trans,
 int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path);
 int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path);
 int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf);
-int btrfs_drop_snapshot(struct btrfs_root *root,
-                       struct btrfs_block_rsv *block_rsv, int update_ref);
+void btrfs_drop_snapshot(struct btrfs_root *root,
+                        struct btrfs_block_rsv *block_rsv, int update_ref);
 int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
                        struct btrfs_root *root,
                        struct extent_buffer *node,
@@ -2406,8 +2404,8 @@ int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct
                         btrfs_root_item *item, struct btrfs_key *key);
 int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid);
 int btrfs_find_orphan_roots(struct btrfs_root *tree_root);
-int btrfs_set_root_node(struct btrfs_root_item *item,
-                       struct extent_buffer *node);
+void btrfs_set_root_node(struct btrfs_root_item *item,
+                        struct extent_buffer *node);
 void btrfs_check_and_init_root_item(struct btrfs_root_item *item);
 
 /* dir-item.c */
@@ -2523,6 +2521,14 @@ struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *pag
 #define PageChecked PageFsMisc
 #endif
 
+/* This forces readahead on a given range of bytes in an inode */
+static inline void btrfs_force_ra(struct address_space *mapping,
+                                 struct file_ra_state *ra, struct file *file,
+                                 pgoff_t offset, unsigned long req_size)
+{
+       page_cache_sync_readahead(mapping, ra, file, offset, req_size);
+}
+
 struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry);
 int btrfs_set_inode_index(struct inode *dir, u64 *index);
 int btrfs_unlink_inode(struct btrfs_trans_handle *trans,
@@ -2551,9 +2557,6 @@ int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
 int btrfs_merge_bio_hook(struct page *page, unsigned long offset,
                         size_t size, struct bio *bio, unsigned long bio_flags);
 
-unsigned long btrfs_force_ra(struct address_space *mapping,
-                             struct file_ra_state *ra, struct file *file,
-                             pgoff_t offset, pgoff_t last_index);
 int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf);
 int btrfs_readpage(struct file *file, struct page *page);
 void btrfs_evict_inode(struct inode *inode);
@@ -2648,12 +2651,21 @@ do {                                                            \
 /* acl.c */
 #ifdef CONFIG_BTRFS_FS_POSIX_ACL
 struct posix_acl *btrfs_get_acl(struct inode *inode, int type);
-#else
-#define btrfs_get_acl NULL
-#endif
 int btrfs_init_acl(struct btrfs_trans_handle *trans,
                   struct inode *inode, struct inode *dir);
 int btrfs_acl_chmod(struct inode *inode);
+#else
+#define btrfs_get_acl NULL
+static inline int btrfs_init_acl(struct btrfs_trans_handle *trans,
+                                struct inode *inode, struct inode *dir)
+{
+       return 0;
+}
+static inline int btrfs_acl_chmod(struct inode *inode)
+{
+       return 0;
+}
+#endif
 
 /* relocation.c */
 int btrfs_relocate_block_group(struct btrfs_root *root, u64 group_start);
index c360a84..31d84e7 100644 (file)
@@ -198,8 +198,6 @@ struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
        struct btrfs_key key;
        int ins_len = mod < 0 ? -1 : 0;
        int cow = mod != 0;
-       struct btrfs_key found_key;
-       struct extent_buffer *leaf;
 
        key.objectid = dir;
        btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
@@ -209,18 +207,7 @@ struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
        ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
        if (ret < 0)
                return ERR_PTR(ret);
-       if (ret > 0) {
-               if (path->slots[0] == 0)
-                       return NULL;
-               path->slots[0]--;
-       }
-
-       leaf = path->nodes[0];
-       btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
-
-       if (found_key.objectid != dir ||
-           btrfs_key_type(&found_key) != BTRFS_DIR_ITEM_KEY ||
-           found_key.offset != key.offset)
+       if (ret > 0)
                return NULL;
 
        return btrfs_match_dir_item_name(root, path, name, name_len);
@@ -315,8 +302,6 @@ struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
        struct btrfs_key key;
        int ins_len = mod < 0 ? -1 : 0;
        int cow = mod != 0;
-       struct btrfs_key found_key;
-       struct extent_buffer *leaf;
 
        key.objectid = dir;
        btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
@@ -324,18 +309,7 @@ struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
        ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
        if (ret < 0)
                return ERR_PTR(ret);
-       if (ret > 0) {
-               if (path->slots[0] == 0)
-                       return NULL;
-               path->slots[0]--;
-       }
-
-       leaf = path->nodes[0];
-       btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
-
-       if (found_key.objectid != dir ||
-           btrfs_key_type(&found_key) != BTRFS_XATTR_ITEM_KEY ||
-           found_key.offset != key.offset)
+       if (ret > 0)
                return NULL;
 
        return btrfs_match_dir_item_name(root, path, name, name_len);
index 4d08ed7..f5be06a 100644 (file)
@@ -663,7 +663,9 @@ int btrfs_lookup_extent(struct btrfs_root *root, u64 start, u64 len)
        struct btrfs_path *path;
 
        path = btrfs_alloc_path();
-       BUG_ON(!path);
+       if (!path)
+               return -ENOMEM;
+
        key.objectid = start;
        key.offset = len;
        btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
@@ -1780,6 +1782,9 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
 
 
                for (i = 0; i < multi->num_stripes; i++, stripe++) {
+                       if (!stripe->dev->can_discard)
+                               continue;
+
                        ret = btrfs_issue_discard(stripe->dev->bdev,
                                                  stripe->physical,
                                                  stripe->length);
@@ -1787,11 +1792,16 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
                                discarded_bytes += stripe->length;
                        else if (ret != -EOPNOTSUPP)
                                break;
+
+                       /*
+                        * Just in case we get back EOPNOTSUPP for some reason,
+                        * just ignore the return value so we don't screw up
+                        * people calling discard_extent.
+                        */
+                       ret = 0;
                }
                kfree(multi);
        }
-       if (discarded_bytes && ret == -EOPNOTSUPP)
-               ret = 0;
 
        if (actual_bytes)
                *actual_bytes = discarded_bytes;
@@ -3272,6 +3282,9 @@ again:
        }
 
        ret = btrfs_alloc_chunk(trans, extent_root, flags);
+       if (ret < 0 && ret != -ENOSPC)
+               goto out;
+
        spin_lock(&space_info->lock);
        if (ret)
                space_info->full = 1;
@@ -3281,6 +3294,7 @@ again:
        space_info->force_alloc = CHUNK_ALLOC_NO_FORCE;
        space_info->chunk_alloc = 0;
        spin_unlock(&space_info->lock);
+out:
        mutex_unlock(&extent_root->fs_info->chunk_mutex);
        return ret;
 }
@@ -4456,7 +4470,9 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                                printk(KERN_ERR "umm, got %d back from search"
                                       ", was looking for %llu\n", ret,
                                       (unsigned long long)bytenr);
-                               btrfs_print_leaf(extent_root, path->nodes[0]);
+                               if (ret > 0)
+                                       btrfs_print_leaf(extent_root,
+                                                        path->nodes[0]);
                        }
                        BUG_ON(ret);
                        extent_slot = path->slots[0];
@@ -5073,7 +5089,9 @@ have_block_group:
                         * group is does point to and try again
                         */
                        if (!last_ptr_loop && last_ptr->block_group &&
-                           last_ptr->block_group != block_group) {
+                           last_ptr->block_group != block_group &&
+                           index <=
+                                get_block_group_index(last_ptr->block_group)) {
 
                                btrfs_put_block_group(block_group);
                                block_group = last_ptr->block_group;
@@ -5501,7 +5519,8 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
        u32 size = sizeof(*extent_item) + sizeof(*block_info) + sizeof(*iref);
 
        path = btrfs_alloc_path();
-       BUG_ON(!path);
+       if (!path)
+               return -ENOMEM;
 
        path->leave_spinning = 1;
        ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path,
@@ -6258,8 +6277,8 @@ static noinline int walk_up_tree(struct btrfs_trans_handle *trans,
  * also make sure backrefs for the shared block and all lower level
  * blocks are properly updated.
  */
-int btrfs_drop_snapshot(struct btrfs_root *root,
-                       struct btrfs_block_rsv *block_rsv, int update_ref)
+void btrfs_drop_snapshot(struct btrfs_root *root,
+                        struct btrfs_block_rsv *block_rsv, int update_ref)
 {
        struct btrfs_path *path;
        struct btrfs_trans_handle *trans;
@@ -6272,10 +6291,17 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
        int level;
 
        path = btrfs_alloc_path();
-       BUG_ON(!path);
+       if (!path) {
+               err = -ENOMEM;
+               goto out;
+       }
 
        wc = kzalloc(sizeof(*wc), GFP_NOFS);
-       BUG_ON(!wc);
+       if (!wc) {
+               btrfs_free_path(path);
+               err = -ENOMEM;
+               goto out;
+       }
 
        trans = btrfs_start_transaction(tree_root, 0);
        BUG_ON(IS_ERR(trans));
@@ -6303,7 +6329,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
                path->lowest_level = 0;
                if (ret < 0) {
                        err = ret;
-                       goto out;
+                       goto out_free;
                }
                WARN_ON(ret > 0);
 
@@ -6410,11 +6436,14 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
                free_extent_buffer(root->commit_root);
                kfree(root);
        }
-out:
+out_free:
        btrfs_end_transaction_throttle(trans, tree_root);
        kfree(wc);
        btrfs_free_path(path);
-       return err;
+out:
+       if (err)
+               btrfs_std_error(root->fs_info, err);
+       return;
 }
 
 /*
@@ -6538,8 +6567,6 @@ static int set_block_group_ro(struct btrfs_block_group_cache *cache, int force)
        u64 min_allocable_bytes;
        int ret = -ENOSPC;
 
-       if (cache->ro)
-               return 0;
 
        /*
         * We need some metadata space and system metadata space for
@@ -6555,6 +6582,12 @@ static int set_block_group_ro(struct btrfs_block_group_cache *cache, int force)
 
        spin_lock(&sinfo->lock);
        spin_lock(&cache->lock);
+
+       if (cache->ro) {
+               ret = 0;
+               goto out;
+       }
+
        num_bytes = cache->key.offset - cache->reserved - cache->pinned -
                    cache->bytes_super - btrfs_block_group_used(&cache->item);
 
@@ -6568,7 +6601,7 @@ static int set_block_group_ro(struct btrfs_block_group_cache *cache, int force)
                cache->ro = 1;
                ret = 0;
        }
-
+out:
        spin_unlock(&cache->lock);
        spin_unlock(&sinfo->lock);
        return ret;
@@ -6701,6 +6734,10 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
        struct btrfs_space_info *space_info;
        struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;
        struct btrfs_device *device;
+       u64 min_free;
+       u64 dev_min = 1;
+       u64 dev_nr = 0;
+       int index;
        int full = 0;
        int ret = 0;
 
@@ -6710,8 +6747,10 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
        if (!block_group)
                return -1;
 
+       min_free = btrfs_block_group_used(&block_group->item);
+
        /* no bytes used, we're good */
-       if (!btrfs_block_group_used(&block_group->item))
+       if (!min_free)
                goto out;
 
        space_info = block_group->space_info;
@@ -6727,10 +6766,9 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
         * all of the extents from this block group.  If we can, we're good
         */
        if ((space_info->total_bytes != block_group->key.offset) &&
-          (space_info->bytes_used + space_info->bytes_reserved +
-           space_info->bytes_pinned + space_info->bytes_readonly +
-           btrfs_block_group_used(&block_group->item) <
-           space_info->total_bytes)) {
+           (space_info->bytes_used + space_info->bytes_reserved +
+            space_info->bytes_pinned + space_info->bytes_readonly +
+            min_free < space_info->total_bytes)) {
                spin_unlock(&space_info->lock);
                goto out;
        }
@@ -6747,9 +6785,31 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
        if (full)
                goto out;
 
+       /*
+        * index:
+        *      0: raid10
+        *      1: raid1
+        *      2: dup
+        *      3: raid0
+        *      4: single
+        */
+       index = get_block_group_index(block_group);
+       if (index == 0) {
+               dev_min = 4;
+               /* Divide by 2 */
+               min_free >>= 1;
+       } else if (index == 1) {
+               dev_min = 2;
+       } else if (index == 2) {
+               /* Multiply by 2 */
+               min_free <<= 1;
+       } else if (index == 3) {
+               dev_min = fs_devices->rw_devices;
+               do_div(min_free, dev_min);
+       }
+
        mutex_lock(&root->fs_info->chunk_mutex);
        list_for_each_entry(device, &fs_devices->alloc_list, dev_alloc_list) {
-               u64 min_free = btrfs_block_group_used(&block_group->item);
                u64 dev_offset;
 
                /*
@@ -6760,7 +6820,11 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
                        ret = find_free_dev_extent(NULL, device, min_free,
                                                   &dev_offset, NULL);
                        if (!ret)
+                               dev_nr++;
+
+                       if (dev_nr >= dev_min)
                                break;
+
                        ret = -1;
                }
        }
@@ -7183,11 +7247,15 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
        spin_unlock(&cluster->refill_lock);
 
        path = btrfs_alloc_path();
-       BUG_ON(!path);
+       if (!path) {
+               ret = -ENOMEM;
+               goto out;
+       }
 
        inode = lookup_free_space_inode(root, block_group, path);
        if (!IS_ERR(inode)) {
-               btrfs_orphan_add(trans, inode);
+               ret = btrfs_orphan_add(trans, inode);
+               BUG_ON(ret);
                clear_nlink(inode);
                /* One for the block groups ref */
                spin_lock(&block_group->lock);
index 067b174..d418164 100644 (file)
@@ -254,14 +254,14 @@ static void merge_cb(struct extent_io_tree *tree, struct extent_state *new,
  *
  * This should be called with the tree lock held.
  */
-static int merge_state(struct extent_io_tree *tree,
-                      struct extent_state *state)
+static void merge_state(struct extent_io_tree *tree,
+                       struct extent_state *state)
 {
        struct extent_state *other;
        struct rb_node *other_node;
 
        if (state->state & (EXTENT_IOBITS | EXTENT_BOUNDARY))
-               return 0;
+               return;
 
        other_node = rb_prev(&state->rb_node);
        if (other_node) {
@@ -287,19 +287,13 @@ static int merge_state(struct extent_io_tree *tree,
                        free_extent_state(other);
                }
        }
-
-       return 0;
 }
 
-static int set_state_cb(struct extent_io_tree *tree,
+static void set_state_cb(struct extent_io_tree *tree,
                         struct extent_state *state, int *bits)
 {
-       if (tree->ops && tree->ops->set_bit_hook) {
-               return tree->ops->set_bit_hook(tree->mapping->host,
-                                              state, bits);
-       }
-
-       return 0;
+       if (tree->ops && tree->ops->set_bit_hook)
+               tree->ops->set_bit_hook(tree->mapping->host, state, bits);
 }
 
 static void clear_state_cb(struct extent_io_tree *tree,
@@ -309,6 +303,9 @@ static void clear_state_cb(struct extent_io_tree *tree,
                tree->ops->clear_bit_hook(tree->mapping->host, state, bits);
 }
 
+static void set_state_bits(struct extent_io_tree *tree,
+                          struct extent_state *state, int *bits);
+
 /*
  * insert an extent_state struct into the tree.  'bits' are set on the
  * struct before it is inserted.
@@ -324,8 +321,6 @@ static int insert_state(struct extent_io_tree *tree,
                        int *bits)
 {
        struct rb_node *node;
-       int bits_to_set = *bits & ~EXTENT_CTLBITS;
-       int ret;
 
        if (end < start) {
                printk(KERN_ERR "btrfs end < start %llu %llu\n",
@@ -335,13 +330,9 @@ static int insert_state(struct extent_io_tree *tree,
        }
        state->start = start;
        state->end = end;
-       ret = set_state_cb(tree, state, bits);
-       if (ret)
-               return ret;
 
-       if (bits_to_set & EXTENT_DIRTY)
-               tree->dirty_bytes += end - start + 1;
-       state->state |= bits_to_set;
+       set_state_bits(tree, state, bits);
+
        node = tree_insert(&tree->state, end, &state->rb_node);
        if (node) {
                struct extent_state *found;
@@ -357,13 +348,11 @@ static int insert_state(struct extent_io_tree *tree,
        return 0;
 }
 
-static int split_cb(struct extent_io_tree *tree, struct extent_state *orig,
+static void split_cb(struct extent_io_tree *tree, struct extent_state *orig,
                     u64 split)
 {
        if (tree->ops && tree->ops->split_extent_hook)
-               return tree->ops->split_extent_hook(tree->mapping->host,
-                                                   orig, split);
-       return 0;
+               tree->ops->split_extent_hook(tree->mapping->host, orig, split);
 }
 
 /*
@@ -659,34 +648,25 @@ again:
                if (start > end)
                        break;
 
-               if (need_resched()) {
-                       spin_unlock(&tree->lock);
-                       cond_resched();
-                       spin_lock(&tree->lock);
-               }
+               cond_resched_lock(&tree->lock);
        }
 out:
        spin_unlock(&tree->lock);
        return 0;
 }
 
-static int set_state_bits(struct extent_io_tree *tree,
+static void set_state_bits(struct extent_io_tree *tree,
                           struct extent_state *state,
                           int *bits)
 {
-       int ret;
        int bits_to_set = *bits & ~EXTENT_CTLBITS;
 
-       ret = set_state_cb(tree, state, bits);
-       if (ret)
-               return ret;
+       set_state_cb(tree, state, bits);
        if ((bits_to_set & EXTENT_DIRTY) && !(state->state & EXTENT_DIRTY)) {
                u64 range = state->end - state->start + 1;
                tree->dirty_bytes += range;
        }
        state->state |= bits_to_set;
-
-       return 0;
 }
 
 static void cache_state(struct extent_state *state,
@@ -779,9 +759,7 @@ hit_next:
                        goto out;
                }
 
-               err = set_state_bits(tree, state, &bits);
-               if (err)
-                       goto out;
+               set_state_bits(tree, state, &bits);
 
                cache_state(state, cached_state);
                merge_state(tree, state);
@@ -830,9 +808,7 @@ hit_next:
                if (err)
                        goto out;
                if (state->end <= end) {
-                       err = set_state_bits(tree, state, &bits);
-                       if (err)
-                               goto out;
+                       set_state_bits(tree, state, &bits);
                        cache_state(state, cached_state);
                        merge_state(tree, state);
                        if (last_end == (u64)-1)
@@ -893,11 +869,7 @@ hit_next:
                err = split_state(tree, state, prealloc, end + 1);
                BUG_ON(err == -EEXIST);
 
-               err = set_state_bits(tree, prealloc, &bits);
-               if (err) {
-                       prealloc = NULL;
-                       goto out;
-               }
+               set_state_bits(tree, prealloc, &bits);
                cache_state(prealloc, cached_state);
                merge_state(tree, prealloc);
                prealloc = NULL;
@@ -1059,46 +1031,6 @@ static int set_range_writeback(struct extent_io_tree *tree, u64 start, u64 end)
        return 0;
 }
 
-/*
- * find the first offset in the io tree with 'bits' set. zero is
- * returned if we find something, and *start_ret and *end_ret are
- * set to reflect the state struct that was found.
- *
- * If nothing was found, 1 is returned, < 0 on error
- */
-int find_first_extent_bit(struct extent_io_tree *tree, u64 start,
-                         u64 *start_ret, u64 *end_ret, int bits)
-{
-       struct rb_node *node;
-       struct extent_state *state;
-       int ret = 1;
-
-       spin_lock(&tree->lock);
-       /*
-        * this search will find all the extents that end after
-        * our range starts.
-        */
-       node = tree_search(tree, start);
-       if (!node)
-               goto out;
-
-       while (1) {
-               state = rb_entry(node, struct extent_state, rb_node);
-               if (state->end >= start && (state->state & bits)) {
-                       *start_ret = state->start;
-                       *end_ret = state->end;
-                       ret = 0;
-                       break;
-               }
-               node = rb_next(node);
-               if (!node)
-                       break;
-       }
-out:
-       spin_unlock(&tree->lock);
-       return ret;
-}
-
 /* find the first state struct with 'bits' set after 'start', and
  * return it.  tree->lock must be held.  NULL will returned if
  * nothing was found after 'start'
@@ -1130,6 +1062,30 @@ out:
        return NULL;
 }
 
+/*
+ * find the first offset in the io tree with 'bits' set. zero is
+ * returned if we find something, and *start_ret and *end_ret are
+ * set to reflect the state struct that was found.
+ *
+ * If nothing was found, 1 is returned, < 0 on error
+ */
+int find_first_extent_bit(struct extent_io_tree *tree, u64 start,
+                         u64 *start_ret, u64 *end_ret, int bits)
+{
+       struct extent_state *state;
+       int ret = 1;
+
+       spin_lock(&tree->lock);
+       state = find_first_extent_bit_state(tree, start, bits);
+       if (state) {
+               *start_ret = state->start;
+               *end_ret = state->end;
+               ret = 0;
+       }
+       spin_unlock(&tree->lock);
+       return ret;
+}
+
 /*
  * find a contiguous range of bytes in the file marked as delalloc, not
  * more than 'max_bytes'.  start and end are used to return the range,
@@ -2546,7 +2502,6 @@ int extent_write_full_page(struct extent_io_tree *tree, struct page *page,
                          struct writeback_control *wbc)
 {
        int ret;
-       struct address_space *mapping = page->mapping;
        struct extent_page_data epd = {
                .bio = NULL,
                .tree = tree,
@@ -2554,17 +2509,9 @@ int extent_write_full_page(struct extent_io_tree *tree, struct page *page,
                .extent_locked = 0,
                .sync_io = wbc->sync_mode == WB_SYNC_ALL,
        };
-       struct writeback_control wbc_writepages = {
-               .sync_mode      = wbc->sync_mode,
-               .nr_to_write    = 64,
-               .range_start    = page_offset(page) + PAGE_CACHE_SIZE,
-               .range_end      = (loff_t)-1,
-       };
 
        ret = __extent_writepage(page, wbc, &epd);
 
-       extent_write_cache_pages(tree, mapping, &wbc_writepages,
-                                __extent_writepage, &epd, flush_write_bio);
        flush_epd_write_bio(&epd);
        return ret;
 }
index 21a7ca9..7b2f0c3 100644 (file)
@@ -76,15 +76,15 @@ struct extent_io_ops {
                                    struct extent_state *state);
        int (*writepage_end_io_hook)(struct page *page, u64 start, u64 end,
                                      struct extent_state *state, int uptodate);
-       int (*set_bit_hook)(struct inode *inode, struct extent_state *state,
-                           int *bits);
-       int (*clear_bit_hook)(struct inode *inode, struct extent_state *state,
-                             int *bits);
-       int (*merge_extent_hook)(struct inode *inode,
-                                struct extent_state *new,
-                                struct extent_state *other);
-       int (*split_extent_hook)(struct inode *inode,
-                                struct extent_state *orig, u64 split);
+       void (*set_bit_hook)(struct inode *inode, struct extent_state *state,
+                            int *bits);
+       void (*clear_bit_hook)(struct inode *inode, struct extent_state *state,
+                              int *bits);
+       void (*merge_extent_hook)(struct inode *inode,
+                                 struct extent_state *new,
+                                 struct extent_state *other);
+       void (*split_extent_hook)(struct inode *inode,
+                                 struct extent_state *orig, u64 split);
        int (*write_cache_pages_lock_hook)(struct page *page);
 };
 
@@ -108,8 +108,6 @@ struct extent_state {
        wait_queue_head_t wq;
        atomic_t refs;
        unsigned long state;
-       u64 split_start;
-       u64 split_end;
 
        /* for use by the FS */
        u64 private;
index 2d04103..7c97b33 100644 (file)
@@ -183,22 +183,10 @@ static int mergable_maps(struct extent_map *prev, struct extent_map *next)
        return 0;
 }
 
-int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len)
+static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em)
 {
-       int ret = 0;
        struct extent_map *merge = NULL;
        struct rb_node *rb;
-       struct extent_map *em;
-
-       write_lock(&tree->lock);
-       em = lookup_extent_mapping(tree, start, len);
-
-       WARN_ON(!em || em->start != start);
-
-       if (!em)
-               goto out;
-
-       clear_bit(EXTENT_FLAG_PINNED, &em->flags);
 
        if (em->start != 0) {
                rb = rb_prev(&em->rb_node);
@@ -225,6 +213,24 @@ int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len)
                merge->in_tree = 0;
                free_extent_map(merge);
        }
+}
+
+int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len)
+{
+       int ret = 0;
+       struct extent_map *em;
+
+       write_lock(&tree->lock);
+       em = lookup_extent_mapping(tree, start, len);
+
+       WARN_ON(!em || em->start != start);
+
+       if (!em)
+               goto out;
+
+       clear_bit(EXTENT_FLAG_PINNED, &em->flags);
+
+       try_merge_map(tree, em);
 
        free_extent_map(em);
 out:
@@ -247,7 +253,6 @@ int add_extent_mapping(struct extent_map_tree *tree,
                       struct extent_map *em)
 {
        int ret = 0;
-       struct extent_map *merge = NULL;
        struct rb_node *rb;
        struct extent_map *exist;
 
@@ -263,30 +268,8 @@ int add_extent_mapping(struct extent_map_tree *tree,
                goto out;
        }
        atomic_inc(&em->refs);
-       if (em->start != 0) {
-               rb = rb_prev(&em->rb_node);
-               if (rb)
-                       merge = rb_entry(rb, struct extent_map, rb_node);
-               if (rb && mergable_maps(merge, em)) {
-                       em->start = merge->start;
-                       em->len += merge->len;
-                       em->block_len += merge->block_len;
-                       em->block_start = merge->block_start;
-                       merge->in_tree = 0;
-                       rb_erase(&merge->rb_node, &tree->map);
-                       free_extent_map(merge);
-               }
-        }
-       rb = rb_next(&em->rb_node);
-       if (rb)
-               merge = rb_entry(rb, struct extent_map, rb_node);
-       if (rb && mergable_maps(em, merge)) {
-               em->len += merge->len;
-               em->block_len += merge->len;
-               rb_erase(&merge->rb_node, &tree->map);
-               merge->in_tree = 0;
-               free_extent_map(merge);
-       }
+
+       try_merge_map(tree, em);
 out:
        return ret;
 }
@@ -299,19 +282,8 @@ static u64 range_end(u64 start, u64 len)
        return start + len;
 }
 
-/**
- * lookup_extent_mapping - lookup extent_map
- * @tree:      tree to lookup in
- * @start:     byte offset to start the search
- * @len:       length of the lookup range
- *
- * Find and return the first extent_map struct in @tree that intersects the
- * [start, len] range.  There may be additional objects in the tree that
- * intersect, so check the object returned carefully to make sure that no
- * additional lookups are needed.
- */
-struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree,
-                                        u64 start, u64 len)
+struct extent_map *__lookup_extent_mapping(struct extent_map_tree *tree,
+                                          u64 start, u64 len, int strict)
 {
        struct extent_map *em;
        struct rb_node *rb_node;
@@ -320,37 +292,41 @@ struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree,
        u64 end = range_end(start, len);
 
        rb_node = __tree_search(&tree->map, start, &prev, &next);
-       if (!rb_node && prev) {
-               em = rb_entry(prev, struct extent_map, rb_node);
-               if (end > em->start && start < extent_map_end(em))
-                       goto found;
-       }
-       if (!rb_node && next) {
-               em = rb_entry(next, struct extent_map, rb_node);
-               if (end > em->start && start < extent_map_end(em))
-                       goto found;
-       }
        if (!rb_node) {
-               em = NULL;
-               goto out;
-       }
-       if (IS_ERR(rb_node)) {
-               em = ERR_CAST(rb_node);
-               goto out;
+               if (prev)
+                       rb_node = prev;
+               else if (next)
+                       rb_node = next;
+               else
+                       return NULL;
        }
+
        em = rb_entry(rb_node, struct extent_map, rb_node);
-       if (end > em->start && start < extent_map_end(em))
-               goto found;
 
-       em = NULL;
-       goto out;
+       if (strict && !(end > em->start && start < extent_map_end(em)))
+               return NULL;
 
-found:
        atomic_inc(&em->refs);
-out:
        return em;
 }
 
+/**
+ * lookup_extent_mapping - lookup extent_map
+ * @tree:      tree to lookup in
+ * @start:     byte offset to start the search
+ * @len:       length of the lookup range
+ *
+ * Find and return the first extent_map struct in @tree that intersects the
+ * [start, len] range.  There may be additional objects in the tree that
+ * intersect, so check the object returned carefully to make sure that no
+ * additional lookups are needed.
+ */
+struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree,
+                                        u64 start, u64 len)
+{
+       return __lookup_extent_mapping(tree, start, len, 1);
+}
+
 /**
  * search_extent_mapping - find a nearby extent map
  * @tree:      tree to lookup in
@@ -365,38 +341,7 @@ out:
 struct extent_map *search_extent_mapping(struct extent_map_tree *tree,
                                         u64 start, u64 len)
 {
-       struct extent_map *em;
-       struct rb_node *rb_node;
-       struct rb_node *prev = NULL;
-       struct rb_node *next = NULL;
-
-       rb_node = __tree_search(&tree->map, start, &prev, &next);
-       if (!rb_node && prev) {
-               em = rb_entry(prev, struct extent_map, rb_node);
-               goto found;
-       }
-       if (!rb_node && next) {
-               em = rb_entry(next, struct extent_map, rb_node);
-               goto found;
-       }
-       if (!rb_node) {
-               em = NULL;
-               goto out;
-       }
-       if (IS_ERR(rb_node)) {
-               em = ERR_CAST(rb_node);
-               goto out;
-       }
-       em = rb_entry(rb_node, struct extent_map, rb_node);
-       goto found;
-
-       em = NULL;
-       goto out;
-
-found:
-       atomic_inc(&em->refs);
-out:
-       return em;
+       return __lookup_extent_mapping(tree, start, len, 0);
 }
 
 /**
index 08bcfa9..b910694 100644 (file)
@@ -291,7 +291,8 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
        u16 csum_size = btrfs_super_csum_size(&root->fs_info->super_copy);
 
        path = btrfs_alloc_path();
-       BUG_ON(!path);
+       if (!path)
+               return -ENOMEM;
 
        if (search_commit) {
                path->skip_locking = 1;
@@ -677,7 +678,9 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
                btrfs_super_csum_size(&root->fs_info->super_copy);
 
        path = btrfs_alloc_path();
-       BUG_ON(!path);
+       if (!path)
+               return -ENOMEM;
+
        sector_sum = sums->sums;
 again:
        next_offset = (u64)-1;
index a35e51c..e7872e4 100644 (file)
@@ -74,7 +74,7 @@ struct inode_defrag {
  * If an existing record is found the defrag item you
  * pass in is freed
  */
-static int __btrfs_add_inode_defrag(struct inode *inode,
+static void __btrfs_add_inode_defrag(struct inode *inode,
                                    struct inode_defrag *defrag)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
@@ -106,11 +106,11 @@ static int __btrfs_add_inode_defrag(struct inode *inode,
        BTRFS_I(inode)->in_defrag = 1;
        rb_link_node(&defrag->rb_node, parent, p);
        rb_insert_color(&defrag->rb_node, &root->fs_info->defrag_inodes);
-       return 0;
+       return;
 
 exists:
        kfree(defrag);
-       return 0;
+       return;
 
 }
 
@@ -123,7 +123,6 @@ int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans,
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct inode_defrag *defrag;
-       int ret = 0;
        u64 transid;
 
        if (!btrfs_test_opt(root, AUTO_DEFRAG))
@@ -150,9 +149,11 @@ int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans,
 
        spin_lock(&root->fs_info->defrag_inodes_lock);
        if (!BTRFS_I(inode)->in_defrag)
-               ret = __btrfs_add_inode_defrag(inode, defrag);
+               __btrfs_add_inode_defrag(inode, defrag);
+       else
+               kfree(defrag);
        spin_unlock(&root->fs_info->defrag_inodes_lock);
-       return ret;
+       return 0;
 }
 
 /*
@@ -855,7 +856,8 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
        btrfs_drop_extent_cache(inode, start, end - 1, 0);
 
        path = btrfs_alloc_path();
-       BUG_ON(!path);
+       if (!path)
+               return -ENOMEM;
 again:
        recow = 0;
        split = start;
@@ -1059,7 +1061,7 @@ static int prepare_uptodate_page(struct page *page, u64 pos)
 static noinline int prepare_pages(struct btrfs_root *root, struct file *file,
                         struct page **pages, size_t num_pages,
                         loff_t pos, unsigned long first_index,
-                        unsigned long last_index, size_t write_bytes)
+                        size_t write_bytes)
 {
        struct extent_state *cached_state = NULL;
        int i;
@@ -1159,7 +1161,6 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct page **pages = NULL;
        unsigned long first_index;
-       unsigned long last_index;
        size_t num_written = 0;
        int nrptrs;
        int ret = 0;
@@ -1172,7 +1173,6 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
                return -ENOMEM;
 
        first_index = pos >> PAGE_CACHE_SHIFT;
-       last_index = (pos + iov_iter_count(i)) >> PAGE_CACHE_SHIFT;
 
        while (iov_iter_count(i) > 0) {
                size_t offset = pos & (PAGE_CACHE_SIZE - 1);
@@ -1206,8 +1206,7 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
                 * contents of pages from loop to loop
                 */
                ret = prepare_pages(root, file, pages, num_pages,
-                                   pos, first_index, last_index,
-                                   write_bytes);
+                                   pos, first_index, write_bytes);
                if (ret) {
                        btrfs_delalloc_release_space(inode,
                                        num_pages << PAGE_CACHE_SHIFT);
@@ -1641,11 +1640,15 @@ static long btrfs_fallocate(struct file *file, int mode,
 
        cur_offset = alloc_start;
        while (1) {
+               u64 actual_end;
+
                em = btrfs_get_extent(inode, NULL, 0, cur_offset,
                                      alloc_end - cur_offset, 0);
                BUG_ON(IS_ERR_OR_NULL(em));
                last_byte = min(extent_map_end(em), alloc_end);
+               actual_end = min_t(u64, extent_map_end(em), offset + len);
                last_byte = (last_byte + mask) & ~mask;
+
                if (em->block_start == EXTENT_MAP_HOLE ||
                    (cur_offset >= inode->i_size &&
                     !test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) {
@@ -1658,6 +1661,16 @@ static long btrfs_fallocate(struct file *file, int mode,
                                free_extent_map(em);
                                break;
                        }
+               } else if (actual_end > inode->i_size &&
+                          !(mode & FALLOC_FL_KEEP_SIZE)) {
+                       /*
+                        * We didn't need to allocate any more space, but we
+                        * still extended the size of the file so we need to
+                        * update i_size.
+                        */
+                       inode->i_ctime = CURRENT_TIME;
+                       i_size_write(inode, actual_end);
+                       btrfs_ordered_update_i_size(inode, actual_end, NULL);
                }
                free_extent_map(em);
 
@@ -1807,10 +1820,14 @@ static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int origin)
                }
        }
 
-       if (offset < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET))
-               return -EINVAL;
-       if (offset > inode->i_sb->s_maxbytes)
-               return -EINVAL;
+       if (offset < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET)) {
+               ret = -EINVAL;
+               goto out;
+       }
+       if (offset > inode->i_sb->s_maxbytes) {
+               ret = -EINVAL;
+               goto out;
+       }
 
        /* Special lock needed here? */
        if (offset != file->f_pos) {
index 6377713..6a265b9 100644 (file)
@@ -1168,9 +1168,9 @@ static void recalculate_thresholds(struct btrfs_free_space_ctl *ctl)
                div64_u64(extent_bytes, (sizeof(struct btrfs_free_space)));
 }
 
-static void bitmap_clear_bits(struct btrfs_free_space_ctl *ctl,
-                             struct btrfs_free_space *info, u64 offset,
-                             u64 bytes)
+static inline void __bitmap_clear_bits(struct btrfs_free_space_ctl *ctl,
+                                      struct btrfs_free_space *info,
+                                      u64 offset, u64 bytes)
 {
        unsigned long start, count;
 
@@ -1181,6 +1181,13 @@ static void bitmap_clear_bits(struct btrfs_free_space_ctl *ctl,
        bitmap_clear(info->bitmap, start, count);
 
        info->bytes -= bytes;
+}
+
+static void bitmap_clear_bits(struct btrfs_free_space_ctl *ctl,
+                             struct btrfs_free_space *info, u64 offset,
+                             u64 bytes)
+{
+       __bitmap_clear_bits(ctl, info, offset, bytes);
        ctl->free_space -= bytes;
 }
 
@@ -1984,7 +1991,7 @@ static u64 btrfs_alloc_from_bitmap(struct btrfs_block_group_cache *block_group,
                return 0;
 
        ret = search_start;
-       bitmap_clear_bits(ctl, entry, ret, bytes);
+       __bitmap_clear_bits(ctl, entry, ret, bytes);
 
        return ret;
 }
@@ -2039,7 +2046,6 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group,
                                continue;
                        }
                } else {
-
                        ret = entry->offset;
 
                        entry->offset += bytes;
index 13e6255..0ccc743 100644 (file)
@@ -1061,7 +1061,8 @@ static noinline int run_delalloc_nocow(struct inode *inode,
        u64 ino = btrfs_ino(inode);
 
        path = btrfs_alloc_path();
-       BUG_ON(!path);
+       if (!path)
+               return -ENOMEM;
 
        nolock = btrfs_is_free_space_inode(root, inode);
 
@@ -1282,17 +1283,16 @@ static int run_delalloc_range(struct inode *inode, struct page *locked_page,
        return ret;
 }
 
-static int btrfs_split_extent_hook(struct inode *inode,
-                                  struct extent_state *orig, u64 split)
+static void btrfs_split_extent_hook(struct inode *inode,
+                                   struct extent_state *orig, u64 split)
 {
        /* not delalloc, ignore it */
        if (!(orig->state & EXTENT_DELALLOC))
-               return 0;
+               return;
 
        spin_lock(&BTRFS_I(inode)->lock);
        BTRFS_I(inode)->outstanding_extents++;
        spin_unlock(&BTRFS_I(inode)->lock);
-       return 0;
 }
 
 /*
@@ -1301,18 +1301,17 @@ static int btrfs_split_extent_hook(struct inode *inode,
  * extents, such as when we are doing sequential writes, so we can properly
  * account for the metadata space we'll need.
  */
-static int btrfs_merge_extent_hook(struct inode *inode,
-                                  struct extent_state *new,
-                                  struct extent_state *other)
+static void btrfs_merge_extent_hook(struct inode *inode,
+                                   struct extent_state *new,
+                                   struct extent_state *other)
 {
        /* not delalloc, ignore it */
        if (!(other->state & EXTENT_DELALLOC))
-               return 0;
+               return;
 
        spin_lock(&BTRFS_I(inode)->lock);
        BTRFS_I(inode)->outstanding_extents--;
        spin_unlock(&BTRFS_I(inode)->lock);
-       return 0;
 }
 
 /*
@@ -1320,8 +1319,8 @@ static int btrfs_merge_extent_hook(struct inode *inode,
  * bytes in this file, and to maintain the list of inodes that
  * have pending delalloc work to be done.
  */
-static int btrfs_set_bit_hook(struct inode *inode,
-                             struct extent_state *state, int *bits)
+static void btrfs_set_bit_hook(struct inode *inode,
+                              struct extent_state *state, int *bits)
 {
 
        /*
@@ -1351,14 +1350,13 @@ static int btrfs_set_bit_hook(struct inode *inode,
                }
                spin_unlock(&root->fs_info->delalloc_lock);
        }
-       return 0;
 }
 
 /*
  * extent_io.c clear_bit_hook, see set_bit_hook for why
  */
-static int btrfs_clear_bit_hook(struct inode *inode,
-                               struct extent_state *state, int *bits)
+static void btrfs_clear_bit_hook(struct inode *inode,
+                                struct extent_state *state, int *bits)
 {
        /*
         * set_bit and clear bit hooks normally require _irqsave/restore
@@ -1395,7 +1393,6 @@ static int btrfs_clear_bit_hook(struct inode *inode,
                }
                spin_unlock(&root->fs_info->delalloc_lock);
        }
-       return 0;
 }
 
 /*
@@ -1645,7 +1642,8 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
        int ret;
 
        path = btrfs_alloc_path();
-       BUG_ON(!path);
+       if (!path)
+               return -ENOMEM;
 
        path->leave_spinning = 1;
 
@@ -2215,7 +2213,8 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode)
 
        if (!root->orphan_block_rsv) {
                block_rsv = btrfs_alloc_block_rsv(root);
-               BUG_ON(!block_rsv);
+               if (!block_rsv)
+                       return -ENOMEM;
        }
 
        spin_lock(&root->orphan_lock);
@@ -2517,7 +2516,9 @@ static void btrfs_read_locked_inode(struct inode *inode)
                filled = true;
 
        path = btrfs_alloc_path();
-       BUG_ON(!path);
+       if (!path)
+               goto make_bad;
+
        path->leave_spinning = 1;
        memcpy(&location, &BTRFS_I(inode)->location, sizeof(location));
 
@@ -2998,13 +2999,16 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry)
 
        ret = btrfs_unlink_inode(trans, root, dir, dentry->d_inode,
                                 dentry->d_name.name, dentry->d_name.len);
-       BUG_ON(ret);
+       if (ret)
+               goto out;
 
        if (inode->i_nlink == 0) {
                ret = btrfs_orphan_add(trans, inode);
-               BUG_ON(ret);
+               if (ret)
+                       goto out;
        }
 
+out:
        nr = trans->blocks_used;
        __unlink_end_trans(trans, root);
        btrfs_btree_balance_dirty(root, nr);
@@ -3147,6 +3151,11 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
 
        BUG_ON(new_size > 0 && min_type != BTRFS_EXTENT_DATA_KEY);
 
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+       path->reada = -1;
+
        if (root->ref_cows || root == root->fs_info->tree_root)
                btrfs_drop_extent_cache(inode, new_size & (~mask), (u64)-1, 0);
 
@@ -3159,10 +3168,6 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
        if (min_type == 0 && root == BTRFS_I(inode)->root)
                btrfs_kill_delayed_inode_items(inode);
 
-       path = btrfs_alloc_path();
-       BUG_ON(!path);
-       path->reada = -1;
-
        key.objectid = ino;
        key.offset = (u64)-1;
        key.type = (u8)-1;
@@ -3690,7 +3695,8 @@ static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry,
        int ret = 0;
 
        path = btrfs_alloc_path();
-       BUG_ON(!path);
+       if (!path)
+               return -ENOMEM;
 
        di = btrfs_lookup_dir_item(NULL, root, path, btrfs_ino(dir), name,
                                    namelen, 0);
@@ -3946,6 +3952,7 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
                         struct btrfs_root *root, int *new)
 {
        struct inode *inode;
+       int bad_inode = 0;
 
        inode = btrfs_iget_locked(s, location->objectid, root);
        if (!inode)
@@ -3955,10 +3962,19 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
                BTRFS_I(inode)->root = root;
                memcpy(&BTRFS_I(inode)->location, location, sizeof(*location));
                btrfs_read_locked_inode(inode);
-               inode_tree_add(inode);
-               unlock_new_inode(inode);
-               if (new)
-                       *new = 1;
+               if (!is_bad_inode(inode)) {
+                       inode_tree_add(inode);
+                       unlock_new_inode(inode);
+                       if (new)
+                               *new = 1;
+               } else {
+                       bad_inode = 1;
+               }
+       }
+
+       if (bad_inode) {
+               iput(inode);
+               inode = ERR_PTR(-ESTALE);
        }
 
        return inode;
@@ -3993,12 +4009,19 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
        struct btrfs_root *sub_root = root;
        struct btrfs_key location;
        int index;
-       int ret;
+       int ret = 0;
 
        if (dentry->d_name.len > BTRFS_NAME_LEN)
                return ERR_PTR(-ENAMETOOLONG);
 
-       ret = btrfs_inode_by_name(dir, dentry, &location);
+       if (unlikely(d_need_lookup(dentry))) {
+               memcpy(&location, dentry->d_fsdata, sizeof(struct btrfs_key));
+               kfree(dentry->d_fsdata);
+               dentry->d_fsdata = NULL;
+               d_clear_need_lookup(dentry);
+       } else {
+               ret = btrfs_inode_by_name(dir, dentry, &location);
+       }
 
        if (ret < 0)
                return ERR_PTR(ret);
@@ -4053,6 +4076,12 @@ static int btrfs_dentry_delete(const struct dentry *dentry)
        return 0;
 }
 
+static void btrfs_dentry_release(struct dentry *dentry)
+{
+       if (dentry->d_fsdata)
+               kfree(dentry->d_fsdata);
+}
+
 static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
                                   struct nameidata *nd)
 {
@@ -4075,6 +4104,7 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
        struct btrfs_path *path;
        struct list_head ins_list;
        struct list_head del_list;
+       struct qstr q;
        int ret;
        struct extent_buffer *leaf;
        int slot;
@@ -4164,6 +4194,7 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
 
                while (di_cur < di_total) {
                        struct btrfs_key location;
+                       struct dentry *tmp;
 
                        if (verify_dir_item(root, leaf, di))
                                break;
@@ -4184,6 +4215,33 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
                        d_type = btrfs_filetype_table[btrfs_dir_type(leaf, di)];
                        btrfs_dir_item_key_to_cpu(leaf, di, &location);
 
+                       q.name = name_ptr;
+                       q.len = name_len;
+                       q.hash = full_name_hash(q.name, q.len);
+                       tmp = d_lookup(filp->f_dentry, &q);
+                       if (!tmp) {
+                               struct btrfs_key *newkey;
+
+                               newkey = kzalloc(sizeof(struct btrfs_key),
+                                                GFP_NOFS);
+                               if (!newkey)
+                                       goto no_dentry;
+                               tmp = d_alloc(filp->f_dentry, &q);
+                               if (!tmp) {
+                                       kfree(newkey);
+                                       dput(tmp);
+                                       goto no_dentry;
+                               }
+                               memcpy(newkey, &location,
+                                      sizeof(struct btrfs_key));
+                               tmp->d_fsdata = newkey;
+                               tmp->d_flags |= DCACHE_NEED_LOOKUP;
+                               d_rehash(tmp);
+                               dput(tmp);
+                       } else {
+                               dput(tmp);
+                       }
+no_dentry:
                        /* is this a reference to our own snapshot? If so
                         * skip it
                         */
@@ -4409,7 +4467,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
        int owner;
 
        path = btrfs_alloc_path();
-       BUG_ON(!path);
+       if (!path)
+               return ERR_PTR(-ENOMEM);
 
        inode = new_inode(root->fs_info->sb);
        if (!inode) {
@@ -6669,19 +6728,6 @@ int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
        return 0;
 }
 
-/* helper function for file defrag and space balancing.  This
- * forces readahead on a given range of bytes in an inode
- */
-unsigned long btrfs_force_ra(struct address_space *mapping,
-                             struct file_ra_state *ra, struct file *file,
-                             pgoff_t offset, pgoff_t last_index)
-{
-       pgoff_t req_size = last_index - offset + 1;
-
-       page_cache_sync_readahead(mapping, ra, file, offset, req_size);
-       return offset + req_size;
-}
-
 struct inode *btrfs_alloc_inode(struct super_block *sb)
 {
        struct btrfs_inode *ei;
@@ -7164,7 +7210,11 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
                goto out_unlock;
 
        path = btrfs_alloc_path();
-       BUG_ON(!path);
+       if (!path) {
+               err = -ENOMEM;
+               drop_inode = 1;
+               goto out_unlock;
+       }
        key.objectid = btrfs_ino(inode);
        key.offset = 0;
        btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY);
@@ -7304,11 +7354,15 @@ static int btrfs_set_page_dirty(struct page *page)
 static int btrfs_permission(struct inode *inode, int mask)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
+       umode_t mode = inode->i_mode;
 
-       if (btrfs_root_readonly(root) && (mask & MAY_WRITE))
-               return -EROFS;
-       if ((BTRFS_I(inode)->flags & BTRFS_INODE_READONLY) && (mask & MAY_WRITE))
-               return -EACCES;
+       if (mask & MAY_WRITE &&
+           (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) {
+               if (btrfs_root_readonly(root))
+                       return -EROFS;
+               if (BTRFS_I(inode)->flags & BTRFS_INODE_READONLY)
+                       return -EACCES;
+       }
        return generic_permission(inode, mask);
 }
 
@@ -7430,4 +7484,5 @@ static const struct inode_operations btrfs_symlink_inode_operations = {
 
 const struct dentry_operations btrfs_dentry_operations = {
        .d_delete       = btrfs_dentry_delete,
+       .d_release      = btrfs_dentry_release,
 };
index 0b980af..970977a 100644 (file)
@@ -1749,11 +1749,10 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info,
                key.objectid = key.offset;
                key.offset = (u64)-1;
                dirid = key.objectid;
-
        }
        if (ptr < name)
                goto out;
-       memcpy(name, ptr, total_len);
+       memmove(name, ptr, total_len);
        name[total_len]='\0';
        ret = 0;
 out:
@@ -2237,6 +2236,10 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                btrfs_wait_ordered_range(src, off, len);
        }
 
+       /* truncate page cache pages from target inode range */
+       truncate_inode_pages_range(&inode->i_data, off,
+                                  ALIGN(off + len, PAGE_CACHE_SIZE) - 1);
+
        /* clone data */
        key.objectid = btrfs_ino(src);
        key.type = BTRFS_EXTENT_DATA_KEY;
diff --git a/fs/btrfs/ref-cache.c b/fs/btrfs/ref-cache.c
deleted file mode 100644 (file)
index 82d569c..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2008 Oracle.  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 v2 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 021110-1307, USA.
- */
-
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/sort.h>
-#include "ctree.h"
-#include "ref-cache.h"
-#include "transaction.h"
-
-static struct rb_node *tree_insert(struct rb_root *root, u64 bytenr,
-                                  struct rb_node *node)
-{
-       struct rb_node **p = &root->rb_node;
-       struct rb_node *parent = NULL;
-       struct btrfs_leaf_ref *entry;
-
-       while (*p) {
-               parent = *p;
-               entry = rb_entry(parent, struct btrfs_leaf_ref, rb_node);
-
-               if (bytenr < entry->bytenr)
-                       p = &(*p)->rb_left;
-               else if (bytenr > entry->bytenr)
-                       p = &(*p)->rb_right;
-               else
-                       return parent;
-       }
-
-       entry = rb_entry(node, struct btrfs_leaf_ref, rb_node);
-       rb_link_node(node, parent, p);
-       rb_insert_color(node, root);
-       return NULL;
-}
-
-static struct rb_node *tree_search(struct rb_root *root, u64 bytenr)
-{
-       struct rb_node *n = root->rb_node;
-       struct btrfs_leaf_ref *entry;
-
-       while (n) {
-               entry = rb_entry(n, struct btrfs_leaf_ref, rb_node);
-               WARN_ON(!entry->in_tree);
-
-               if (bytenr < entry->bytenr)
-                       n = n->rb_left;
-               else if (bytenr > entry->bytenr)
-                       n = n->rb_right;
-               else
-                       return n;
-       }
-       return NULL;
-}
diff --git a/fs/btrfs/ref-cache.h b/fs/btrfs/ref-cache.h
deleted file mode 100644 (file)
index 24f7001..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2008 Oracle.  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 v2 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 021110-1307, USA.
- */
-#ifndef __REFCACHE__
-#define __REFCACHE__
-
-struct btrfs_extent_info {
-       /* bytenr and num_bytes find the extent in the extent allocation tree */
-       u64 bytenr;
-       u64 num_bytes;
-
-       /* objectid and offset find the back reference for the file */
-       u64 objectid;
-       u64 offset;
-};
-
-struct btrfs_leaf_ref {
-       struct rb_node rb_node;
-       struct btrfs_leaf_ref_tree *tree;
-       int in_tree;
-       atomic_t usage;
-
-       u64 root_gen;
-       u64 bytenr;
-       u64 owner;
-       u64 generation;
-       int nritems;
-
-       struct list_head list;
-       struct btrfs_extent_info extents[];
-};
-
-static inline size_t btrfs_leaf_ref_size(int nr_extents)
-{
-       return sizeof(struct btrfs_leaf_ref) +
-              sizeof(struct btrfs_extent_info) * nr_extents;
-}
-#endif
index ebe4544..f409990 100644 (file)
@@ -71,13 +71,12 @@ out:
        return ret;
 }
 
-int btrfs_set_root_node(struct btrfs_root_item *item,
-                       struct extent_buffer *node)
+void btrfs_set_root_node(struct btrfs_root_item *item,
+                        struct extent_buffer *node)
 {
        btrfs_set_root_bytenr(item, node->start);
        btrfs_set_root_level(item, btrfs_header_level(node));
        btrfs_set_root_generation(item, btrfs_header_generation(node));
-       return 0;
 }
 
 /*
index eb55863..7dc36fa 100644 (file)
@@ -216,17 +216,11 @@ static void wait_current_trans(struct btrfs_root *root)
        spin_lock(&root->fs_info->trans_lock);
        cur_trans = root->fs_info->running_transaction;
        if (cur_trans && cur_trans->blocked) {
-               DEFINE_WAIT(wait);
                atomic_inc(&cur_trans->use_count);
                spin_unlock(&root->fs_info->trans_lock);
-               while (1) {
-                       prepare_to_wait(&root->fs_info->transaction_wait, &wait,
-                                       TASK_UNINTERRUPTIBLE);
-                       if (!cur_trans->blocked)
-                               break;
-                       schedule();
-               }
-               finish_wait(&root->fs_info->transaction_wait, &wait);
+
+               wait_event(root->fs_info->transaction_wait,
+                          !cur_trans->blocked);
                put_transaction(cur_trans);
        } else {
                spin_unlock(&root->fs_info->trans_lock);
@@ -357,19 +351,10 @@ struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *root
 }
 
 /* wait for a transaction commit to be fully complete */
-static noinline int wait_for_commit(struct btrfs_root *root,
+static noinline void wait_for_commit(struct btrfs_root *root,
                                    struct btrfs_transaction *commit)
 {
-       DEFINE_WAIT(wait);
-       while (!commit->commit_done) {
-               prepare_to_wait(&commit->commit_wait, &wait,
-                               TASK_UNINTERRUPTIBLE);
-               if (commit->commit_done)
-                       break;
-               schedule();
-       }
-       finish_wait(&commit->commit_wait, &wait);
-       return 0;
+       wait_event(commit->commit_wait, commit->commit_done);
 }
 
 int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid)
@@ -1085,22 +1070,7 @@ int btrfs_transaction_blocked(struct btrfs_fs_info *info)
 static void wait_current_trans_commit_start(struct btrfs_root *root,
                                            struct btrfs_transaction *trans)
 {
-       DEFINE_WAIT(wait);
-
-       if (trans->in_commit)
-               return;
-
-       while (1) {
-               prepare_to_wait(&root->fs_info->transaction_blocked_wait, &wait,
-                               TASK_UNINTERRUPTIBLE);
-               if (trans->in_commit) {
-                       finish_wait(&root->fs_info->transaction_blocked_wait,
-                                   &wait);
-                       break;
-               }
-               schedule();
-               finish_wait(&root->fs_info->transaction_blocked_wait, &wait);
-       }
+       wait_event(root->fs_info->transaction_blocked_wait, trans->in_commit);
 }
 
 /*
@@ -1110,24 +1080,8 @@ static void wait_current_trans_commit_start(struct btrfs_root *root,
 static void wait_current_trans_commit_start_and_unblock(struct btrfs_root *root,
                                         struct btrfs_transaction *trans)
 {
-       DEFINE_WAIT(wait);
-
-       if (trans->commit_done || (trans->in_commit && !trans->blocked))
-               return;
-
-       while (1) {
-               prepare_to_wait(&root->fs_info->transaction_wait, &wait,
-                               TASK_UNINTERRUPTIBLE);
-               if (trans->commit_done ||
-                   (trans->in_commit && !trans->blocked)) {
-                       finish_wait(&root->fs_info->transaction_wait,
-                                   &wait);
-                       break;
-               }
-               schedule();
-               finish_wait(&root->fs_info->transaction_wait,
-                           &wait);
-       }
+       wait_event(root->fs_info->transaction_wait,
+                  trans->commit_done || (trans->in_commit && !trans->blocked));
 }
 
 /*
@@ -1234,8 +1188,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
                atomic_inc(&cur_trans->use_count);
                btrfs_end_transaction(trans, root);
 
-               ret = wait_for_commit(root, cur_trans);
-               BUG_ON(ret);
+               wait_for_commit(root, cur_trans);
 
                put_transaction(cur_trans);
 
index ac278dd..786639f 100644 (file)
@@ -799,14 +799,15 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
                                  struct extent_buffer *eb, int slot,
                                  struct btrfs_key *key)
 {
-       struct inode *dir;
-       int ret;
        struct btrfs_inode_ref *ref;
+       struct btrfs_dir_item *di;
+       struct inode *dir;
        struct inode *inode;
-       char *name;
-       int namelen;
        unsigned long ref_ptr;
        unsigned long ref_end;
+       char *name;
+       int namelen;
+       int ret;
        int search_done = 0;
 
        /*
@@ -909,6 +910,25 @@ again:
        }
        btrfs_release_path(path);
 
+       /* look for a conflicting sequence number */
+       di = btrfs_lookup_dir_index_item(trans, root, path, btrfs_ino(dir),
+                                        btrfs_inode_ref_index(eb, ref),
+                                        name, namelen, 0);
+       if (di && !IS_ERR(di)) {
+               ret = drop_one_dir_item(trans, root, path, dir, di);
+               BUG_ON(ret);
+       }
+       btrfs_release_path(path);
+
+       /* look for a conflicing name */
+       di = btrfs_lookup_dir_item(trans, root, path, btrfs_ino(dir),
+                                  name, namelen, 0);
+       if (di && !IS_ERR(di)) {
+               ret = drop_one_dir_item(trans, root, path, dir, di);
+               BUG_ON(ret);
+       }
+       btrfs_release_path(path);
+
 insert:
        /* insert our name */
        ret = btrfs_add_link(trans, dir, inode, name, namelen, 0,
@@ -1617,7 +1637,8 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
                return 0;
 
        path = btrfs_alloc_path();
-       BUG_ON(!path);
+       if (!path)
+               return -ENOMEM;
 
        nritems = btrfs_header_nritems(eb);
        for (i = 0; i < nritems; i++) {
@@ -1723,7 +1744,9 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
                        return -ENOMEM;
 
                if (*level == 1) {
-                       wc->process_func(root, next, wc, ptr_gen);
+                       ret = wc->process_func(root, next, wc, ptr_gen);
+                       if (ret)
+                               return ret;
 
                        path->slots[*level]++;
                        if (wc->free) {
@@ -1788,8 +1811,11 @@ static noinline int walk_up_log_tree(struct btrfs_trans_handle *trans,
                                parent = path->nodes[*level + 1];
 
                        root_owner = btrfs_header_owner(parent);
-                       wc->process_func(root, path->nodes[*level], wc,
+                       ret = wc->process_func(root, path->nodes[*level], wc,
                                 btrfs_header_generation(path->nodes[*level]));
+                       if (ret)
+                               return ret;
+
                        if (wc->free) {
                                struct extent_buffer *next;
 
index b89e372..f2a4cc7 100644 (file)
@@ -142,6 +142,7 @@ static noinline int run_scheduled_bios(struct btrfs_device *device)
        unsigned long limit;
        unsigned long last_waited = 0;
        int force_reg = 0;
+       int sync_pending = 0;
        struct blk_plug plug;
 
        /*
@@ -229,6 +230,22 @@ loop_lock:
 
                BUG_ON(atomic_read(&cur->bi_cnt) == 0);
 
+               /*
+                * if we're doing the sync list, record that our
+                * plug has some sync requests on it
+                *
+                * If we're doing the regular list and there are
+                * sync requests sitting around, unplug before
+                * we add more
+                */
+               if (pending_bios == &device->pending_sync_bios) {
+                       sync_pending = 1;
+               } else if (sync_pending) {
+                       blk_finish_plug(&plug);
+                       blk_start_plug(&plug);
+                       sync_pending = 0;
+               }
+
                submit_bio(cur->bi_rw, cur);
                num_run++;
                batch_run++;
@@ -500,6 +517,9 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
                        fs_devices->rw_devices--;
                }
 
+               if (device->can_discard)
+                       fs_devices->num_can_discard--;
+
                new_device = kmalloc(sizeof(*new_device), GFP_NOFS);
                BUG_ON(!new_device);
                memcpy(new_device, device, sizeof(*new_device));
@@ -508,6 +528,7 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
                new_device->bdev = NULL;
                new_device->writeable = 0;
                new_device->in_fs_metadata = 0;
+               new_device->can_discard = 0;
                list_replace_rcu(&device->dev_list, &new_device->dev_list);
 
                call_rcu(&device->rcu, free_device);
@@ -547,6 +568,7 @@ int btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
 static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
                                fmode_t flags, void *holder)
 {
+       struct request_queue *q;
        struct block_device *bdev;
        struct list_head *head = &fs_devices->devices;
        struct btrfs_device *device;
@@ -603,6 +625,12 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
                        seeding = 0;
                }
 
+               q = bdev_get_queue(bdev);
+               if (blk_queue_discard(q)) {
+                       device->can_discard = 1;
+                       fs_devices->num_can_discard++;
+               }
+
                device->bdev = bdev;
                device->in_fs_metadata = 0;
                device->mode = flags;
@@ -835,6 +863,7 @@ int find_free_dev_extent(struct btrfs_trans_handle *trans,
 
        max_hole_start = search_start;
        max_hole_size = 0;
+       hole_size = 0;
 
        if (search_start >= search_end) {
                ret = -ENOSPC;
@@ -917,7 +946,14 @@ next:
                cond_resched();
        }
 
-       hole_size = search_end- search_start;
+       /*
+        * At this point, search_start should be the end of
+        * allocated dev extents, and when shrinking the device,
+        * search_end may be smaller than search_start.
+        */
+       if (search_end > search_start)
+               hole_size = search_end - search_start;
+
        if (hole_size > max_hole_size) {
                max_hole_start = search_start;
                max_hole_size = hole_size;
@@ -1037,7 +1073,8 @@ static noinline int find_next_chunk(struct btrfs_root *root,
        struct btrfs_key found_key;
 
        path = btrfs_alloc_path();
-       BUG_ON(!path);
+       if (!path)
+               return -ENOMEM;
 
        key.objectid = objectid;
        key.offset = (u64)-1;
@@ -1542,6 +1579,7 @@ error:
 
 int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
 {
+       struct request_queue *q;
        struct btrfs_trans_handle *trans;
        struct btrfs_device *device;
        struct block_device *bdev;
@@ -1611,6 +1649,9 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
 
        lock_chunks(root);
 
+       q = bdev_get_queue(bdev);
+       if (blk_queue_discard(q))
+               device->can_discard = 1;
        device->writeable = 1;
        device->work.func = pending_bios_fn;
        generate_random_uuid(device->uuid);
@@ -1646,6 +1687,8 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
        root->fs_info->fs_devices->num_devices++;
        root->fs_info->fs_devices->open_devices++;
        root->fs_info->fs_devices->rw_devices++;
+       if (device->can_discard)
+               root->fs_info->fs_devices->num_can_discard++;
        root->fs_info->fs_devices->total_rw_bytes += device->total_bytes;
 
        if (!blk_queue_nonrot(bdev_get_queue(bdev)))
@@ -2061,8 +2104,10 @@ int btrfs_balance(struct btrfs_root *dev_root)
 
        /* step two, relocate all the chunks */
        path = btrfs_alloc_path();
-       BUG_ON(!path);
-
+       if (!path) {
+               ret = -ENOMEM;
+               goto error;
+       }
        key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
        key.offset = (u64)-1;
        key.type = BTRFS_CHUNK_ITEM_KEY;
@@ -2410,9 +2455,10 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
                        total_avail = device->total_bytes - device->bytes_used;
                else
                        total_avail = 0;
-               /* avail is off by max(alloc_start, 1MB), but that is the same
-                * for all devices, so it doesn't hurt the sorting later on
-                */
+
+               /* If there is no space on this device, skip it. */
+               if (total_avail == 0)
+                       continue;
 
                ret = find_free_dev_extent(trans, device,
                                           max_stripe_size * dev_stripes,
@@ -2661,7 +2707,8 @@ static noinline int init_first_rw_device(struct btrfs_trans_handle *trans,
 
        ret = find_next_chunk(fs_info->chunk_root,
                              BTRFS_FIRST_CHUNK_TREE_OBJECTID, &chunk_offset);
-       BUG_ON(ret);
+       if (ret)
+               return ret;
 
        alloc_profile = BTRFS_BLOCK_GROUP_METADATA |
                        (fs_info->metadata_alloc_profile &
index 7c12d61..6d866db 100644 (file)
@@ -48,6 +48,7 @@ struct btrfs_device {
        int writeable;
        int in_fs_metadata;
        int missing;
+       int can_discard;
 
        spinlock_t io_lock;
 
@@ -104,6 +105,7 @@ struct btrfs_fs_devices {
        u64 rw_devices;
        u64 missing_devices;
        u64 total_rw_bytes;
+       u64 num_can_discard;
        struct block_device *latest_bdev;
 
        /* all of the devices in the FS, protected by a mutex
index 2fe3cf1..6d40656 100644 (file)
@@ -176,7 +176,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
 
 #ifdef CONFIG_CIFS_STATS2
                        seq_printf(m, " In Send: %d In MaxReq Wait: %d",
-                               atomic_read(&server->inSend),
+                               atomic_read(&server->in_send),
                                atomic_read(&server->num_waiters));
 #endif
 
index 8d8f28c..6873bb6 100644 (file)
@@ -141,10 +141,11 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
 
        rc = dns_resolve_server_name_to_ip(*devname, &srvIP);
        if (rc < 0) {
-               cERROR(1, "%s: Failed to resolve server part of %s to IP: %d",
-                         __func__, *devname, rc);
+               cFYI(1, "%s: Failed to resolve server part of %s to IP: %d",
+                       __func__, *devname, rc);
                goto compose_mount_options_err;
        }
+
        /* md_len = strlen(...) + 12 for 'sep+prefixpath='
         * assuming that we have 'unc=' and 'ip=' in
         * the original sb_mountdata
index 21de1d6..d0f59fa 100644 (file)
@@ -991,24 +991,6 @@ struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
        return pntsd;
 }
 
-static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid,
-               struct cifs_ntsd *pnntsd, u32 acllen)
-{
-       int xid, rc;
-       struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
-
-       if (IS_ERR(tlink))
-               return PTR_ERR(tlink);
-
-       xid = GetXid();
-       rc = CIFSSMBSetCIFSACL(xid, tlink_tcon(tlink), fid, pnntsd, acllen);
-       FreeXid(xid);
-       cifs_put_tlink(tlink);
-
-       cFYI(DBG2, "SetCIFSACL rc = %d", rc);
-       return rc;
-}
-
 static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
                struct cifs_ntsd *pnntsd, u32 acllen)
 {
@@ -1047,18 +1029,10 @@ int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
                                struct inode *inode, const char *path)
 {
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-       struct cifsFileInfo *open_file;
-       int rc;
 
        cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode);
 
-       open_file = find_readable_file(CIFS_I(inode), true);
-       if (!open_file)
-               return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);
-
-       rc = set_cifs_acl_by_fid(cifs_sb, open_file->netfid, pnntsd, acllen);
-       cifsFileInfo_put(open_file);
-       return rc;
+       return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);
 }
 
 /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
index 259991b..e76bfeb 100644 (file)
@@ -87,9 +87,15 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
        if ((cifs_pdu == NULL) || (server == NULL))
                return -EINVAL;
 
-       if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
+       if (!(cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) ||
+           server->tcpStatus == CifsNeedNegotiate)
                return rc;
 
+       if (!server->session_estab) {
+               strncpy(cifs_pdu->Signature.SecuritySignature, "BSRSPYL", 8);
+               return rc;
+       }
+
        cifs_pdu->Signature.Sequence.SequenceNumber =
                        cpu_to_le32(server->sequence_number);
        cifs_pdu->Signature.Sequence.Reserved = 0;
@@ -178,9 +184,15 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
        if ((cifs_pdu == NULL) || (server == NULL))
                return -EINVAL;
 
-       if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
+       if (!(cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) ||
+           server->tcpStatus == CifsNeedNegotiate)
                return rc;
 
+       if (!server->session_estab) {
+               strncpy(cifs_pdu->Signature.SecuritySignature, "BSRSPYL", 8);
+               return rc;
+       }
+
        cifs_pdu->Signature.Sequence.SequenceNumber =
                                cpu_to_le32(server->sequence_number);
        cifs_pdu->Signature.Sequence.Reserved = 0;
index 8655174..f93eb94 100644 (file)
@@ -86,24 +86,6 @@ extern mempool_t *cifs_sm_req_poolp;
 extern mempool_t *cifs_req_poolp;
 extern mempool_t *cifs_mid_poolp;
 
-void
-cifs_sb_active(struct super_block *sb)
-{
-       struct cifs_sb_info *server = CIFS_SB(sb);
-
-       if (atomic_inc_return(&server->active) == 1)
-               atomic_inc(&sb->s_active);
-}
-
-void
-cifs_sb_deactive(struct super_block *sb)
-{
-       struct cifs_sb_info *server = CIFS_SB(sb);
-
-       if (atomic_dec_and_test(&server->active))
-               deactivate_super(sb);
-}
-
 static int
 cifs_read_super(struct super_block *sb)
 {
@@ -581,6 +563,10 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
                mutex_unlock(&dir->i_mutex);
                dput(dentry);
                dentry = child;
+               if (!dentry->d_inode) {
+                       dput(dentry);
+                       dentry = ERR_PTR(-ENOENT);
+               }
        } while (!IS_ERR(dentry));
        _FreeXid(xid);
        kfree(full_path);
index fbd050c..95da802 100644 (file)
@@ -41,10 +41,6 @@ extern struct file_system_type cifs_fs_type;
 extern const struct address_space_operations cifs_addr_ops;
 extern const struct address_space_operations cifs_addr_ops_smallbuf;
 
-/* Functions related to super block operations */
-extern void cifs_sb_active(struct super_block *sb);
-extern void cifs_sb_deactive(struct super_block *sb);
-
 /* Functions related to inodes */
 extern const struct inode_operations cifs_dir_inode_ops;
 extern struct inode *cifs_root_iget(struct super_block *);
@@ -129,5 +125,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
 extern const struct export_operations cifs_export_ops;
 #endif /* CIFS_NFSD_EXPORT */
 
-#define CIFS_VERSION   "1.74"
+#define CIFS_VERSION   "1.75"
 #endif                         /* _CIFSFS_H */
index 1fcf4e5..95dad9d 100644 (file)
@@ -291,7 +291,7 @@ struct TCP_Server_Info {
        struct fscache_cookie   *fscache; /* client index cache cookie */
 #endif
 #ifdef CONFIG_CIFS_STATS2
-       atomic_t inSend; /* requests trying to send */
+       atomic_t in_send; /* requests trying to send */
        atomic_t num_waiters;   /* blocked waiting to get in sendrecv */
 #endif
 };
@@ -672,12 +672,54 @@ struct mid_q_entry {
        bool multiEnd:1;        /* both received */
 };
 
-struct oplock_q_entry {
-       struct list_head qhead;
-       struct inode *pinode;
-       struct cifs_tcon *tcon;
-       __u16 netfid;
-};
+/*     Make code in transport.c a little cleaner by moving
+       update of optional stats into function below */
+#ifdef CONFIG_CIFS_STATS2
+
+static inline void cifs_in_send_inc(struct TCP_Server_Info *server)
+{
+       atomic_inc(&server->in_send);
+}
+
+static inline void cifs_in_send_dec(struct TCP_Server_Info *server)
+{
+       atomic_dec(&server->in_send);
+}
+
+static inline void cifs_num_waiters_inc(struct TCP_Server_Info *server)
+{
+       atomic_inc(&server->num_waiters);
+}
+
+static inline void cifs_num_waiters_dec(struct TCP_Server_Info *server)
+{
+       atomic_dec(&server->num_waiters);
+}
+
+static inline void cifs_save_when_sent(struct mid_q_entry *mid)
+{
+       mid->when_sent = jiffies;
+}
+#else
+static inline void cifs_in_send_inc(struct TCP_Server_Info *server)
+{
+}
+static inline void cifs_in_send_dec(struct TCP_Server_Info *server)
+{
+}
+
+static inline void cifs_num_waiters_inc(struct TCP_Server_Info *server)
+{
+}
+
+static inline void cifs_num_waiters_dec(struct TCP_Server_Info *server)
+{
+}
+
+static inline void cifs_save_when_sent(struct mid_q_entry *mid)
+{
+}
+#endif
 
 /* for pending dnotify requests */
 struct dir_notify_req {
@@ -942,8 +984,6 @@ GLOBAL_EXTERN spinlock_t siduidlock;
 GLOBAL_EXTERN spinlock_t sidgidlock;
 
 void cifs_oplock_break(struct work_struct *work);
-void cifs_oplock_break_get(struct cifsFileInfo *cfile);
-void cifs_oplock_break_put(struct cifsFileInfo *cfile);
 
 extern const struct slow_work_ops cifs_oplock_break_ops;
 
index 1a9fe7f..aac37d9 100644 (file)
@@ -107,7 +107,7 @@ static void mark_open_files_invalid(struct cifs_tcon *pTcon)
 static int
 cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
 {
-       int rc = 0;
+       int rc;
        struct cifs_ses *ses;
        struct TCP_Server_Info *server;
        struct nls_table *nls_codepage;
@@ -5720,6 +5720,7 @@ CIFSSMBQAllEAs(const int xid, struct cifs_tcon *tcon,
        char *temp_ptr;
        char *end_of_smb;
        __u16 params, byte_count, data_offset;
+       unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
 
        cFYI(1, "In Query All EAs path %s", searchName);
 QAllEAsRetry:
@@ -5837,7 +5838,8 @@ QAllEAsRetry:
                }
 
                if (ea_name) {
-                       if (strncmp(ea_name, temp_ptr, name_len) == 0) {
+                       if (ea_name_len == name_len &&
+                           strncmp(ea_name, temp_ptr, name_len) == 0) {
                                temp_ptr += name_len + 1;
                                rc = value_len;
                                if (buf_size == 0)
index e66297b..633c246 100644 (file)
@@ -319,25 +319,328 @@ requeue_echo:
        queue_delayed_work(system_nrt_wq, &server->echo, SMB_ECHO_INTERVAL);
 }
 
+static bool
+allocate_buffers(char **bigbuf, char **smallbuf, unsigned int size,
+                bool is_large_buf)
+{
+       char *bbuf = *bigbuf, *sbuf = *smallbuf;
+
+       if (bbuf == NULL) {
+               bbuf = (char *)cifs_buf_get();
+               if (!bbuf) {
+                       cERROR(1, "No memory for large SMB response");
+                       msleep(3000);
+                       /* retry will check if exiting */
+                       return false;
+               }
+       } else if (is_large_buf) {
+               /* we are reusing a dirty large buf, clear its start */
+               memset(bbuf, 0, size);
+       }
+
+       if (sbuf == NULL) {
+               sbuf = (char *)cifs_small_buf_get();
+               if (!sbuf) {
+                       cERROR(1, "No memory for SMB response");
+                       msleep(1000);
+                       /* retry will check if exiting */
+                       return false;
+               }
+               /* beginning of smb buffer is cleared in our buf_get */
+       } else {
+               /* if existing small buf clear beginning */
+               memset(sbuf, 0, size);
+       }
+
+       *bigbuf = bbuf;
+       *smallbuf = sbuf;
+
+       return true;
+}
+
+static int
+read_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg,
+                struct kvec *iov, unsigned int to_read,
+                unsigned int *ptotal_read, bool is_header_read)
+{
+       int length, rc = 0;
+       unsigned int total_read;
+       char *buf = iov->iov_base;
+
+       for (total_read = 0; total_read < to_read; total_read += length) {
+               length = kernel_recvmsg(server->ssocket, smb_msg, iov, 1,
+                                       to_read - total_read, 0);
+               if (server->tcpStatus == CifsExiting) {
+                       /* then will exit */
+                       rc = 2;
+                       break;
+               } else if (server->tcpStatus == CifsNeedReconnect) {
+                       cifs_reconnect(server);
+                       /* Reconnect wakes up rspns q */
+                       /* Now we will reread sock */
+                       rc = 1;
+                       break;
+               } else if (length == -ERESTARTSYS ||
+                          length == -EAGAIN ||
+                          length == -EINTR) {
+                       /*
+                        * Minimum sleep to prevent looping, allowing socket
+                        * to clear and app threads to set tcpStatus
+                        * CifsNeedReconnect if server hung.
+                        */
+                       usleep_range(1000, 2000);
+                       length = 0;
+                       if (!is_header_read)
+                               continue;
+                       /* Special handling for header read */
+                       if (total_read) {
+                               iov->iov_base = (to_read - total_read) +
+                                               buf;
+                               iov->iov_len = to_read - total_read;
+                               smb_msg->msg_control = NULL;
+                               smb_msg->msg_controllen = 0;
+                               rc = 3;
+                       } else
+                               rc = 1;
+                       break;
+               } else if (length <= 0) {
+                       cERROR(1, "Received no data, expecting %d",
+                              to_read - total_read);
+                       cifs_reconnect(server);
+                       rc = 1;
+                       break;
+               }
+       }
+
+       *ptotal_read = total_read;
+       return rc;
+}
+
+static bool
+check_rfc1002_header(struct TCP_Server_Info *server, char *buf)
+{
+       char temp = *buf;
+       unsigned int pdu_length = be32_to_cpu(
+                               ((struct smb_hdr *)buf)->smb_buf_length);
+
+       /*
+        * The first byte big endian of the length field,
+        * is actually not part of the length but the type
+        * with the most common, zero, as regular data.
+        */
+       if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
+               return false;
+       } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
+               cFYI(1, "Good RFC 1002 session rsp");
+               return false;
+       } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
+               /*
+                * We get this from Windows 98 instead of an error on
+                * SMB negprot response.
+                */
+               cFYI(1, "Negative RFC1002 Session Response Error 0x%x)",
+                       pdu_length);
+               /* give server a second to clean up */
+               msleep(1000);
+               /*
+                * Always try 445 first on reconnect since we get NACK
+                * on some if we ever connected to port 139 (the NACK
+                * is since we do not begin with RFC1001 session
+                * initialize frame).
+                */
+               cifs_set_port((struct sockaddr *)
+                               &server->dstaddr, CIFS_PORT);
+               cifs_reconnect(server);
+               wake_up(&server->response_q);
+               return false;
+       } else if (temp != (char) 0) {
+               cERROR(1, "Unknown RFC 1002 frame");
+               cifs_dump_mem(" Received Data: ", buf, 4);
+               cifs_reconnect(server);
+               return false;
+       }
+
+       /* else we have an SMB response */
+       if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
+           (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
+               cERROR(1, "Invalid size SMB length %d pdu_length %d",
+                      4, pdu_length+4);
+               cifs_reconnect(server);
+               wake_up(&server->response_q);
+               return false;
+       }
+
+       return true;
+}
+
+static struct mid_q_entry *
+find_cifs_mid(struct TCP_Server_Info *server, struct smb_hdr *buf,
+             int *length, bool is_large_buf, bool *is_multi_rsp, char **bigbuf)
+{
+       struct mid_q_entry *mid = NULL, *tmp_mid, *ret = NULL;
+
+       spin_lock(&GlobalMid_Lock);
+       list_for_each_entry_safe(mid, tmp_mid, &server->pending_mid_q, qhead) {
+               if (mid->mid != buf->Mid ||
+                   mid->midState != MID_REQUEST_SUBMITTED ||
+                   mid->command != buf->Command)
+                       continue;
+
+               if (*length == 0 && check2ndT2(buf, server->maxBuf) > 0) {
+                       /* We have a multipart transact2 resp */
+                       *is_multi_rsp = true;
+                       if (mid->resp_buf) {
+                               /* merge response - fix up 1st*/
+                               *length = coalesce_t2(buf, mid->resp_buf);
+                               if (*length > 0) {
+                                       *length = 0;
+                                       mid->multiRsp = true;
+                                       break;
+                               }
+                               /* All parts received or packet is malformed. */
+                               mid->multiEnd = true;
+                               goto multi_t2_fnd;
+                       }
+                       if (!is_large_buf) {
+                               /*FIXME: switch to already allocated largebuf?*/
+                               cERROR(1, "1st trans2 resp needs bigbuf");
+                       } else {
+                               /* Have first buffer */
+                               mid->resp_buf = buf;
+                               mid->largeBuf = true;
+                               *bigbuf = NULL;
+                       }
+                       break;
+               }
+               mid->resp_buf = buf;
+               mid->largeBuf = is_large_buf;
+multi_t2_fnd:
+               if (*length == 0)
+                       mid->midState = MID_RESPONSE_RECEIVED;
+               else
+                       mid->midState = MID_RESPONSE_MALFORMED;
+#ifdef CONFIG_CIFS_STATS2
+               mid->when_received = jiffies;
+#endif
+               list_del_init(&mid->qhead);
+               ret = mid;
+               break;
+       }
+       spin_unlock(&GlobalMid_Lock);
+
+       return ret;
+}
+
+static void clean_demultiplex_info(struct TCP_Server_Info *server)
+{
+       int length;
+
+       /* take it off the list, if it's not already */
+       spin_lock(&cifs_tcp_ses_lock);
+       list_del_init(&server->tcp_ses_list);
+       spin_unlock(&cifs_tcp_ses_lock);
+
+       spin_lock(&GlobalMid_Lock);
+       server->tcpStatus = CifsExiting;
+       spin_unlock(&GlobalMid_Lock);
+       wake_up_all(&server->response_q);
+
+       /*
+        * Check if we have blocked requests that need to free. Note that
+        * cifs_max_pending is normally 50, but can be set at module install
+        * time to as little as two.
+        */
+       spin_lock(&GlobalMid_Lock);
+       if (atomic_read(&server->inFlight) >= cifs_max_pending)
+               atomic_set(&server->inFlight, cifs_max_pending - 1);
+       /*
+        * We do not want to set the max_pending too low or we could end up
+        * with the counter going negative.
+        */
+       spin_unlock(&GlobalMid_Lock);
+       /*
+        * Although there should not be any requests blocked on this queue it
+        * can not hurt to be paranoid and try to wake up requests that may
+        * haven been blocked when more than 50 at time were on the wire to the
+        * same server - they now will see the session is in exit state and get
+        * out of SendReceive.
+        */
+       wake_up_all(&server->request_q);
+       /* give those requests time to exit */
+       msleep(125);
+
+       if (server->ssocket) {
+               sock_release(server->ssocket);
+               server->ssocket = NULL;
+       }
+
+       if (!list_empty(&server->pending_mid_q)) {
+               struct list_head dispose_list;
+               struct mid_q_entry *mid_entry;
+               struct list_head *tmp, *tmp2;
+
+               INIT_LIST_HEAD(&dispose_list);
+               spin_lock(&GlobalMid_Lock);
+               list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
+                       mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
+                       cFYI(1, "Clearing mid 0x%x", mid_entry->mid);
+                       mid_entry->midState = MID_SHUTDOWN;
+                       list_move(&mid_entry->qhead, &dispose_list);
+               }
+               spin_unlock(&GlobalMid_Lock);
+
+               /* now walk dispose list and issue callbacks */
+               list_for_each_safe(tmp, tmp2, &dispose_list) {
+                       mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
+                       cFYI(1, "Callback mid 0x%x", mid_entry->mid);
+                       list_del_init(&mid_entry->qhead);
+                       mid_entry->callback(mid_entry);
+               }
+               /* 1/8th of sec is more than enough time for them to exit */
+               msleep(125);
+       }
+
+       if (!list_empty(&server->pending_mid_q)) {
+               /*
+                * mpx threads have not exited yet give them at least the smb
+                * send timeout time for long ops.
+                *
+                * Due to delays on oplock break requests, we need to wait at
+                * least 45 seconds before giving up on a request getting a
+                * response and going ahead and killing cifsd.
+                */
+               cFYI(1, "Wait for exit from demultiplex thread");
+               msleep(46000);
+               /*
+                * If threads still have not exited they are probably never
+                * coming home not much else we can do but free the memory.
+                */
+       }
+
+       kfree(server->hostname);
+       kfree(server);
+
+       length = atomic_dec_return(&tcpSesAllocCount);
+       if (length > 0)
+               mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
+                               GFP_KERNEL);
+}
+
 static int
 cifs_demultiplex_thread(void *p)
 {
        int length;
        struct TCP_Server_Info *server = p;
        unsigned int pdu_length, total_read;
+       char *buf = NULL, *bigbuf = NULL, *smallbuf = NULL;
        struct smb_hdr *smb_buffer = NULL;
-       struct smb_hdr *bigbuf = NULL;
-       struct smb_hdr *smallbuf = NULL;
        struct msghdr smb_msg;
        struct kvec iov;
-       struct socket *csocket = server->ssocket;
-       struct list_head *tmp, *tmp2;
        struct task_struct *task_to_wake = NULL;
        struct mid_q_entry *mid_entry;
-       char temp;
        bool isLargeBuf = false;
-       bool isMultiRsp;
-       int reconnect;
+       bool isMultiRsp = false;
+       int rc;
 
        current->flags |= PF_MEMALLOC;
        cFYI(1, "Demultiplex PID: %d", task_pid_nr(current));
@@ -351,35 +654,16 @@ cifs_demultiplex_thread(void *p)
        while (server->tcpStatus != CifsExiting) {
                if (try_to_freeze())
                        continue;
-               if (bigbuf == NULL) {
-                       bigbuf = cifs_buf_get();
-                       if (!bigbuf) {
-                               cERROR(1, "No memory for large SMB response");
-                               msleep(3000);
-                               /* retry will check if exiting */
-                               continue;
-                       }
-               } else if (isLargeBuf) {
-                       /* we are reusing a dirty large buf, clear its start */
-                       memset(bigbuf, 0, sizeof(struct smb_hdr));
-               }
 
-               if (smallbuf == NULL) {
-                       smallbuf = cifs_small_buf_get();
-                       if (!smallbuf) {
-                               cERROR(1, "No memory for SMB response");
-                               msleep(1000);
-                               /* retry will check if exiting */
-                               continue;
-                       }
-                       /* beginning of smb buffer is cleared in our buf_get */
-               } else /* if existing small buf clear beginning */
-                       memset(smallbuf, 0, sizeof(struct smb_hdr));
+               if (!allocate_buffers(&bigbuf, &smallbuf,
+                                     sizeof(struct smb_hdr), isLargeBuf))
+                       continue;
 
                isLargeBuf = false;
                isMultiRsp = false;
-               smb_buffer = smallbuf;
-               iov.iov_base = smb_buffer;
+               smb_buffer = (struct smb_hdr *)smallbuf;
+               buf = smallbuf;
+               iov.iov_base = buf;
                iov.iov_len = 4;
                smb_msg.msg_control = NULL;
                smb_msg.msg_controllen = 0;
@@ -393,158 +677,50 @@ incomplete_rcv:
                                  "Reconnecting...", server->hostname,
                                  (echo_retries * SMB_ECHO_INTERVAL / HZ));
                        cifs_reconnect(server);
-                       csocket = server->ssocket;
                        wake_up(&server->response_q);
                        continue;
                }
 
-               length =
-                   kernel_recvmsg(csocket, &smb_msg,
-                               &iov, 1, pdu_length, 0 /* BB other flags? */);
-
-               if (server->tcpStatus == CifsExiting) {
+               rc = read_from_socket(server, &smb_msg, &iov, pdu_length,
+                                     &total_read, true /* header read */);
+               if (rc == 3)
+                       goto incomplete_rcv;
+               else if (rc == 2)
                        break;
-               } else if (server->tcpStatus == CifsNeedReconnect) {
-                       cFYI(1, "Reconnect after server stopped responding");
-                       cifs_reconnect(server);
-                       cFYI(1, "call to reconnect done");
-                       csocket = server->ssocket;
-                       continue;
-               } else if (length == -ERESTARTSYS ||
-                          length == -EAGAIN ||
-                          length == -EINTR) {
-                       msleep(1); /* minimum sleep to prevent looping
-                               allowing socket to clear and app threads to set
-                               tcpStatus CifsNeedReconnect if server hung */
-                       if (pdu_length < 4) {
-                               iov.iov_base = (4 - pdu_length) +
-                                                       (char *)smb_buffer;
-                               iov.iov_len = pdu_length;
-                               smb_msg.msg_control = NULL;
-                               smb_msg.msg_controllen = 0;
-                               goto incomplete_rcv;
-                       } else
-                               continue;
-               } else if (length <= 0) {
-                       cFYI(1, "Reconnect after unexpected peek error %d",
-                               length);
-                       cifs_reconnect(server);
-                       csocket = server->ssocket;
-                       wake_up(&server->response_q);
+               else if (rc == 1)
                        continue;
-               } else if (length < pdu_length) {
-                       cFYI(1, "requested %d bytes but only got %d bytes",
-                                 pdu_length, length);
-                       pdu_length -= length;
-                       msleep(1);
-                       goto incomplete_rcv;
-               }
-
-               /* The right amount was read from socket - 4 bytes */
-               /* so we can now interpret the length field */
 
-               /* the first byte big endian of the length field,
-               is actually not part of the length but the type
-               with the most common, zero, as regular data */
-               temp = *((char *) smb_buffer);
+               /*
+                * The right amount was read from socket - 4 bytes,
+                * so we can now interpret the length field.
+                */
 
-               /* Note that FC 1001 length is big endian on the wire,
-               but we convert it here so it is always manipulated
-               as host byte order */
+               /*
+                * Note that RFC 1001 length is big endian on the wire,
+                * but we convert it here so it is always manipulated
+                * as host byte order.
+                */
                pdu_length = be32_to_cpu(smb_buffer->smb_buf_length);
 
                cFYI(1, "rfc1002 length 0x%x", pdu_length+4);
-
-               if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
-                       continue;
-               } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
-                       cFYI(1, "Good RFC 1002 session rsp");
-                       continue;
-               } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
-                       /* we get this from Windows 98 instead of
-                          an error on SMB negprot response */
-                       cFYI(1, "Negative RFC1002 Session Response Error 0x%x)",
-                               pdu_length);
-                       /* give server a second to clean up  */
-                       msleep(1000);
-                       /* always try 445 first on reconnect since we get NACK
-                        * on some if we ever connected to port 139 (the NACK
-                        * is since we do not begin with RFC1001 session
-                        * initialize frame)
-                        */
-                       cifs_set_port((struct sockaddr *)
-                                       &server->dstaddr, CIFS_PORT);
-                       cifs_reconnect(server);
-                       csocket = server->ssocket;
-                       wake_up(&server->response_q);
-                       continue;
-               } else if (temp != (char) 0) {
-                       cERROR(1, "Unknown RFC 1002 frame");
-                       cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
-                                     length);
-                       cifs_reconnect(server);
-                       csocket = server->ssocket;
+               if (!check_rfc1002_header(server, buf))
                        continue;
-               }
-
-               /* else we have an SMB response */
-               if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
-                           (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
-                       cERROR(1, "Invalid size SMB length %d pdu_length %d",
-                                       length, pdu_length+4);
-                       cifs_reconnect(server);
-                       csocket = server->ssocket;
-                       wake_up(&server->response_q);
-                       continue;
-               }
 
                /* else length ok */
-               reconnect = 0;
-
                if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
                        isLargeBuf = true;
                        memcpy(bigbuf, smallbuf, 4);
-                       smb_buffer = bigbuf;
+                       smb_buffer = (struct smb_hdr *)bigbuf;
+                       buf = bigbuf;
                }
-               length = 0;
-               iov.iov_base = 4 + (char *)smb_buffer;
+
+               iov.iov_base = 4 + buf;
                iov.iov_len = pdu_length;
-               for (total_read = 0; total_read < pdu_length;
-                    total_read += length) {
-                       length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
-                                               pdu_length - total_read, 0);
-                       if (server->tcpStatus == CifsExiting) {
-                               /* then will exit */
-                               reconnect = 2;
-                               break;
-                       } else if (server->tcpStatus == CifsNeedReconnect) {
-                               cifs_reconnect(server);
-                               csocket = server->ssocket;
-                               /* Reconnect wakes up rspns q */
-                               /* Now we will reread sock */
-                               reconnect = 1;
-                               break;
-                       } else if (length == -ERESTARTSYS ||
-                                  length == -EAGAIN ||
-                                  length == -EINTR) {
-                               msleep(1); /* minimum sleep to prevent looping,
-                                             allowing socket to clear and app
-                                             threads to set tcpStatus
-                                             CifsNeedReconnect if server hung*/
-                               length = 0;
-                               continue;
-                       } else if (length <= 0) {
-                               cERROR(1, "Received no data, expecting %d",
-                                             pdu_length - total_read);
-                               cifs_reconnect(server);
-                               csocket = server->ssocket;
-                               reconnect = 1;
-                               break;
-                       }
-               }
-               if (reconnect == 2)
+               rc = read_from_socket(server, &smb_msg, &iov, pdu_length,
+                                     &total_read, false);
+               if (rc == 2)
                        break;
-               else if (reconnect == 1)
+               else if (rc == 1)
                        continue;
 
                total_read += 4; /* account for rfc1002 hdr */
@@ -562,75 +738,13 @@ incomplete_rcv:
                 */
                length = checkSMB(smb_buffer, smb_buffer->Mid, total_read);
                if (length != 0)
-                       cifs_dump_mem("Bad SMB: ", smb_buffer,
-                                       min_t(unsigned int, total_read, 48));
+                       cifs_dump_mem("Bad SMB: ", buf,
+                                     min_t(unsigned int, total_read, 48));
 
-               mid_entry = NULL;
                server->lstrp = jiffies;
 
-               spin_lock(&GlobalMid_Lock);
-               list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
-                       mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
-
-                       if (mid_entry->mid != smb_buffer->Mid ||
-                           mid_entry->midState != MID_REQUEST_SUBMITTED ||
-                           mid_entry->command != smb_buffer->Command) {
-                               mid_entry = NULL;
-                               continue;
-                       }
-
-                       if (length == 0 &&
-                           check2ndT2(smb_buffer, server->maxBuf) > 0) {
-                               /* We have a multipart transact2 resp */
-                               isMultiRsp = true;
-                               if (mid_entry->resp_buf) {
-                                       /* merge response - fix up 1st*/
-                                       length = coalesce_t2(smb_buffer,
-                                                       mid_entry->resp_buf);
-                                       if (length > 0) {
-                                               length = 0;
-                                               mid_entry->multiRsp = true;
-                                               break;
-                                       } else {
-                                               /* all parts received or
-                                                * packet is malformed
-                                                */
-                                               mid_entry->multiEnd = true;
-                                               goto multi_t2_fnd;
-                                       }
-                               } else {
-                                       if (!isLargeBuf) {
-                                               /*
-                                                * FIXME: switch to already
-                                                *        allocated largebuf?
-                                                */
-                                               cERROR(1, "1st trans2 resp "
-                                                         "needs bigbuf");
-                                       } else {
-                                               /* Have first buffer */
-                                               mid_entry->resp_buf =
-                                                        smb_buffer;
-                                               mid_entry->largeBuf = true;
-                                               bigbuf = NULL;
-                                       }
-                               }
-                               break;
-                       }
-                       mid_entry->resp_buf = smb_buffer;
-                       mid_entry->largeBuf = isLargeBuf;
-multi_t2_fnd:
-                       if (length == 0)
-                               mid_entry->midState = MID_RESPONSE_RECEIVED;
-                       else
-                               mid_entry->midState = MID_RESPONSE_MALFORMED;
-#ifdef CONFIG_CIFS_STATS2
-                       mid_entry->when_received = jiffies;
-#endif
-                       list_del_init(&mid_entry->qhead);
-                       break;
-               }
-               spin_unlock(&GlobalMid_Lock);
-
+               mid_entry = find_cifs_mid(server, smb_buffer, &length,
+                                         isLargeBuf, &isMultiRsp, &bigbuf);
                if (mid_entry != NULL) {
                        mid_entry->callback(mid_entry);
                        /* Was previous buf put in mpx struct for multi-rsp? */
@@ -648,7 +762,7 @@ multi_t2_fnd:
                           !isMultiRsp) {
                        cERROR(1, "No task to wake, unknown frame received! "
                                   "NumMids %d", atomic_read(&midCount));
-                       cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
+                       cifs_dump_mem("Received Data is: ", buf,
                                      sizeof(struct smb_hdr));
 #ifdef CONFIG_CIFS_DEBUG2
                        cifs_dump_detail(smb_buffer);
@@ -658,88 +772,13 @@ multi_t2_fnd:
                }
        } /* end while !EXITING */
 
-       /* take it off the list, if it's not already */
-       spin_lock(&cifs_tcp_ses_lock);
-       list_del_init(&server->tcp_ses_list);
-       spin_unlock(&cifs_tcp_ses_lock);
-
-       spin_lock(&GlobalMid_Lock);
-       server->tcpStatus = CifsExiting;
-       spin_unlock(&GlobalMid_Lock);
-       wake_up_all(&server->response_q);
-
-       /* check if we have blocked requests that need to free */
-       /* Note that cifs_max_pending is normally 50, but
-       can be set at module install time to as little as two */
-       spin_lock(&GlobalMid_Lock);
-       if (atomic_read(&server->inFlight) >= cifs_max_pending)
-               atomic_set(&server->inFlight, cifs_max_pending - 1);
-       /* We do not want to set the max_pending too low or we
-       could end up with the counter going negative */
-       spin_unlock(&GlobalMid_Lock);
-       /* Although there should not be any requests blocked on
-       this queue it can not hurt to be paranoid and try to wake up requests
-       that may haven been blocked when more than 50 at time were on the wire
-       to the same server - they now will see the session is in exit state
-       and get out of SendReceive.  */
-       wake_up_all(&server->request_q);
-       /* give those requests time to exit */
-       msleep(125);
-
-       if (server->ssocket) {
-               sock_release(csocket);
-               server->ssocket = NULL;
-       }
        /* buffer usually freed in free_mid - need to free it here on exit */
        cifs_buf_release(bigbuf);
        if (smallbuf) /* no sense logging a debug message if NULL */
                cifs_small_buf_release(smallbuf);
 
-       if (!list_empty(&server->pending_mid_q)) {
-               struct list_head dispose_list;
-
-               INIT_LIST_HEAD(&dispose_list);
-               spin_lock(&GlobalMid_Lock);
-               list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
-                       mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
-                       cFYI(1, "Clearing mid 0x%x", mid_entry->mid);
-                       mid_entry->midState = MID_SHUTDOWN;
-                       list_move(&mid_entry->qhead, &dispose_list);
-               }
-               spin_unlock(&GlobalMid_Lock);
-
-               /* now walk dispose list and issue callbacks */
-               list_for_each_safe(tmp, tmp2, &dispose_list) {
-                       mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
-                       cFYI(1, "Callback mid 0x%x", mid_entry->mid);
-                       list_del_init(&mid_entry->qhead);
-                       mid_entry->callback(mid_entry);
-               }
-               /* 1/8th of sec is more than enough time for them to exit */
-               msleep(125);
-       }
-
-       if (!list_empty(&server->pending_mid_q)) {
-               /* mpx threads have not exited yet give them
-               at least the smb send timeout time for long ops */
-               /* due to delays on oplock break requests, we need
-               to wait at least 45 seconds before giving up
-               on a request getting a response and going ahead
-               and killing cifsd */
-               cFYI(1, "Wait for exit from demultiplex thread");
-               msleep(46000);
-               /* if threads still have not exited they are probably never
-               coming home not much else we can do but free the memory */
-       }
-
-       kfree(server->hostname);
        task_to_wake = xchg(&server->tsk, NULL);
-       kfree(server);
-
-       length = atomic_dec_return(&tcpSesAllocCount);
-       if (length  > 0)
-               mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
-                               GFP_KERNEL);
+       clean_demultiplex_info(server);
 
        /* if server->tsk was NULL then wait for a signal before exiting */
        if (!task_to_wake) {
@@ -2839,7 +2878,8 @@ cleanup_volume_info_contents(struct smb_vol *volume_info)
        kfree(volume_info->username);
        kzfree(volume_info->password);
        kfree(volume_info->UNC);
-       kfree(volume_info->UNCip);
+       if (volume_info->UNCip != volume_info->UNC + 2)
+               kfree(volume_info->UNCip);
        kfree(volume_info->domainname);
        kfree(volume_info->iocharset);
        kfree(volume_info->prepath);
@@ -3193,15 +3233,9 @@ mount_fail_check:
                else
                        cifs_put_tcp_session(srvTcp);
                bdi_destroy(&cifs_sb->bdi);
-               goto out;
        }
 
-       /* volume_info->password is freed above when existing session found
-       (in which case it is not needed anymore) but when new sesion is created
-       the password ptr is put in the new session structure (in which case the
-       password will be freed at unmount time) */
 out:
-       /* zero out password before freeing */
        FreeXid(xid);
        return rc;
 }
index ae576fb..72d448b 100644 (file)
@@ -105,8 +105,8 @@ cifs_bp_rename_retry:
        }
        rcu_read_unlock();
        if (namelen != dfsplen || read_seqretry(&rename_lock, seq)) {
-               cERROR(1, "did not end path lookup where expected namelen is %d",
-                       namelen);
+               cFYI(1, "did not end path lookup where expected. namelen=%d "
+                       "dfsplen=%d", namelen, dfsplen);
                /* presumably this is only possible if racing with a rename
                of one of the parent directories  (we can not lock the dentries
                above us to prevent this, but retrying should be harmless) */
index 548f062..1d2d91d 100644 (file)
@@ -79,8 +79,8 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
        /* Perform the upcall */
        rc = dns_query(NULL, hostname, len, NULL, ip_addr, NULL);
        if (rc < 0)
-               cERROR(1, "%s: unable to resolve: %*.*s",
-                      __func__, len, len, hostname);
+               cFYI(1, "%s: unable to resolve: %*.*s",
+                       __func__, len, len, hostname);
        else
                cFYI(1, "%s: resolved: %*.*s to %s",
                     __func__, len, len, hostname, *ip_addr);
index 378acda..9f41a10 100644 (file)
@@ -314,6 +314,8 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
        }
        spin_unlock(&cifs_file_list_lock);
 
+       cancel_work_sync(&cifs_file->oplock_break);
+
        if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
                int xid, rc;
 
@@ -2418,31 +2420,6 @@ void cifs_oplock_break(struct work_struct *work)
                                 cinode->clientCanCacheRead ? 1 : 0);
                cFYI(1, "Oplock release rc = %d", rc);
        }
-
-       /*
-        * We might have kicked in before is_valid_oplock_break()
-        * finished grabbing reference for us.  Make sure it's done by
-        * waiting for cifs_file_list_lock.
-        */
-       spin_lock(&cifs_file_list_lock);
-       spin_unlock(&cifs_file_list_lock);
-
-       cifs_oplock_break_put(cfile);
-}
-
-/* must be called while holding cifs_file_list_lock */
-void cifs_oplock_break_get(struct cifsFileInfo *cfile)
-{
-       cifs_sb_active(cfile->dentry->d_sb);
-       cifsFileInfo_get(cfile);
-}
-
-void cifs_oplock_break_put(struct cifsFileInfo *cfile)
-{
-       struct super_block *sb = cfile->dentry->d_sb;
-
-       cifsFileInfo_put(cfile);
-       cifs_sb_deactive(sb);
 }
 
 const struct address_space_operations cifs_addr_ops = {
index 9b018c8..a7b2dcd 100644 (file)
@@ -764,20 +764,10 @@ char *cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
        if (full_path == NULL)
                return full_path;
 
-       if (dfsplen) {
+       if (dfsplen)
                strncpy(full_path, tcon->treeName, dfsplen);
-               /* switch slash direction in prepath depending on whether
-                * windows or posix style path names
-                */
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
-                       int i;
-                       for (i = 0; i < dfsplen; i++) {
-                               if (full_path[i] == '\\')
-                                       full_path[i] = '/';
-                       }
-               }
-       }
        strncpy(full_path + dfsplen, vol->prepath, pplen);
+       convert_delimiter(full_path, CIFS_DIR_SEP(cifs_sb));
        full_path[dfsplen + pplen] = 0; /* add trailing null */
        return full_path;
 }
index 03a1f49..7c16933 100644 (file)
@@ -585,15 +585,8 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
 
                                cifs_set_oplock_level(pCifsInode,
                                        pSMB->OplockLevel ? OPLOCK_READ : 0);
-                               /*
-                                * cifs_oplock_break_put() can't be called
-                                * from here.  Get reference after queueing
-                                * succeeded.  cifs_oplock_break() will
-                                * synchronize using cifs_file_list_lock.
-                                */
-                               if (queue_work(system_nrt_wq,
-                                              &netfile->oplock_break))
-                                       cifs_oplock_break_get(netfile);
+                               queue_work(system_nrt_wq,
+                                          &netfile->oplock_break);
                                netfile->oplock_break_cancelled = false;
 
                                spin_unlock(&cifs_file_list_lock);
index 147aa22..10ca6b2 100644 (file)
@@ -266,15 +266,11 @@ static int wait_for_free_request(struct TCP_Server_Info *server,
        while (1) {
                if (atomic_read(&server->inFlight) >= cifs_max_pending) {
                        spin_unlock(&GlobalMid_Lock);
-#ifdef CONFIG_CIFS_STATS2
-                       atomic_inc(&server->num_waiters);
-#endif
+                       cifs_num_waiters_inc(server);
                        wait_event(server->request_q,
                                   atomic_read(&server->inFlight)
                                     < cifs_max_pending);
-#ifdef CONFIG_CIFS_STATS2
-                       atomic_dec(&server->num_waiters);
-#endif
+                       cifs_num_waiters_dec(server);
                        spin_lock(&GlobalMid_Lock);
                } else {
                        if (server->tcpStatus == CifsExiting) {
@@ -362,6 +358,8 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
        mid = AllocMidQEntry(hdr, server);
        if (mid == NULL) {
                mutex_unlock(&server->srv_mutex);
+               atomic_dec(&server->inFlight);
+               wake_up(&server->request_q);
                return -ENOMEM;
        }
 
@@ -379,15 +377,13 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
        mid->callback = callback;
        mid->callback_data = cbdata;
        mid->midState = MID_REQUEST_SUBMITTED;
-#ifdef CONFIG_CIFS_STATS2
-       atomic_inc(&server->inSend);
-#endif
+
+       cifs_in_send_inc(server);
        rc = smb_sendv(server, iov, nvec);
-#ifdef CONFIG_CIFS_STATS2
-       atomic_dec(&server->inSend);
-       mid->when_sent = jiffies;
-#endif
+       cifs_in_send_dec(server);
+       cifs_save_when_sent(mid);
        mutex_unlock(&server->srv_mutex);
+
        if (rc)
                goto out_err;
 
@@ -573,14 +569,10 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
        }
 
        midQ->midState = MID_REQUEST_SUBMITTED;
-#ifdef CONFIG_CIFS_STATS2
-       atomic_inc(&ses->server->inSend);
-#endif
+       cifs_in_send_inc(ses->server);
        rc = smb_sendv(ses->server, iov, n_vec);
-#ifdef CONFIG_CIFS_STATS2
-       atomic_dec(&ses->server->inSend);
-       midQ->when_sent = jiffies;
-#endif
+       cifs_in_send_dec(ses->server);
+       cifs_save_when_sent(midQ);
 
        mutex_unlock(&ses->server->srv_mutex);
 
@@ -701,14 +693,11 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
        }
 
        midQ->midState = MID_REQUEST_SUBMITTED;
-#ifdef CONFIG_CIFS_STATS2
-       atomic_inc(&ses->server->inSend);
-#endif
+
+       cifs_in_send_inc(ses->server);
        rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
-#ifdef CONFIG_CIFS_STATS2
-       atomic_dec(&ses->server->inSend);
-       midQ->when_sent = jiffies;
-#endif
+       cifs_in_send_dec(ses->server);
+       cifs_save_when_sent(midQ);
        mutex_unlock(&ses->server->srv_mutex);
 
        if (rc < 0)
@@ -841,14 +830,10 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
        }
 
        midQ->midState = MID_REQUEST_SUBMITTED;
-#ifdef CONFIG_CIFS_STATS2
-       atomic_inc(&ses->server->inSend);
-#endif
+       cifs_in_send_inc(ses->server);
        rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
-#ifdef CONFIG_CIFS_STATS2
-       atomic_dec(&ses->server->inSend);
-       midQ->when_sent = jiffies;
-#endif
+       cifs_in_send_dec(ses->server);
+       cifs_save_when_sent(midQ);
        mutex_unlock(&ses->server->srv_mutex);
 
        if (rc < 0) {
index 8be086e..51352de 100644 (file)
@@ -1003,6 +1003,7 @@ COMPATIBLE_IOCTL(PPPIOCCONNECT)
 COMPATIBLE_IOCTL(PPPIOCDISCONN)
 COMPATIBLE_IOCTL(PPPIOCATTCHAN)
 COMPATIBLE_IOCTL(PPPIOCGCHAN)
+COMPATIBLE_IOCTL(PPPIOCGL2TPSTATS)
 /* PPPOX */
 COMPATIBLE_IOCTL(PPPOEIOCSFWD)
 COMPATIBLE_IOCTL(PPPOEIOCDFWD)
index b05aac3..a88948b 100644 (file)
@@ -301,6 +301,27 @@ static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent)
        return parent;
 }
 
+/*
+ * Unhash a dentry without inserting an RCU walk barrier or checking that
+ * dentry->d_lock is locked.  The caller must take care of that, if
+ * appropriate.
+ */
+static void __d_shrink(struct dentry *dentry)
+{
+       if (!d_unhashed(dentry)) {
+               struct hlist_bl_head *b;
+               if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED))
+                       b = &dentry->d_sb->s_anon;
+               else
+                       b = d_hash(dentry->d_parent, dentry->d_name.hash);
+
+               hlist_bl_lock(b);
+               __hlist_bl_del(&dentry->d_hash);
+               dentry->d_hash.pprev = NULL;
+               hlist_bl_unlock(b);
+       }
+}
+
 /**
  * d_drop - drop a dentry
  * @dentry: dentry to drop
@@ -319,17 +340,7 @@ static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent)
 void __d_drop(struct dentry *dentry)
 {
        if (!d_unhashed(dentry)) {
-               struct hlist_bl_head *b;
-               if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED))
-                       b = &dentry->d_sb->s_anon;
-               else
-                       b = d_hash(dentry->d_parent, dentry->d_name.hash);
-
-               hlist_bl_lock(b);
-               __hlist_bl_del(&dentry->d_hash);
-               dentry->d_hash.pprev = NULL;
-               hlist_bl_unlock(b);
-
+               __d_shrink(dentry);
                dentry_rcuwalk_barrier(dentry);
        }
 }
@@ -784,6 +795,7 @@ relock:
 
 /**
  * prune_dcache_sb - shrink the dcache
+ * @sb: superblock
  * @nr_to_scan: number of entries to try to free
  *
  * Attempt to shrink the superblock dcache LRU by @nr_to_scan entries. This is
@@ -828,44 +840,24 @@ EXPORT_SYMBOL(shrink_dcache_sb);
 static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
 {
        struct dentry *parent;
-       unsigned detached = 0;
 
        BUG_ON(!IS_ROOT(dentry));
 
-       /* detach this root from the system */
-       spin_lock(&dentry->d_lock);
-       dentry_lru_del(dentry);
-       __d_drop(dentry);
-       spin_unlock(&dentry->d_lock);
-
        for (;;) {
                /* descend to the first leaf in the current subtree */
-               while (!list_empty(&dentry->d_subdirs)) {
-                       struct dentry *loop;
-
-                       /* this is a branch with children - detach all of them
-                        * from the system in one go */
-                       spin_lock(&dentry->d_lock);
-                       list_for_each_entry(loop, &dentry->d_subdirs,
-                                           d_u.d_child) {
-                               spin_lock_nested(&loop->d_lock,
-                                               DENTRY_D_LOCK_NESTED);
-                               dentry_lru_del(loop);
-                               __d_drop(loop);
-                               spin_unlock(&loop->d_lock);
-                       }
-                       spin_unlock(&dentry->d_lock);
-
-                       /* move to the first child */
+               while (!list_empty(&dentry->d_subdirs))
                        dentry = list_entry(dentry->d_subdirs.next,
                                            struct dentry, d_u.d_child);
-               }
 
                /* consume the dentries from this leaf up through its parents
                 * until we find one with children or run out altogether */
                do {
                        struct inode *inode;
 
+                       /* detach from the system */
+                       dentry_lru_del(dentry);
+                       __d_shrink(dentry);
+
                        if (dentry->d_count != 0) {
                                printk(KERN_ERR
                                       "BUG: Dentry %p{i=%lx,n=%s}"
@@ -886,14 +878,10 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
                                list_del(&dentry->d_u.d_child);
                        } else {
                                parent = dentry->d_parent;
-                               spin_lock(&parent->d_lock);
                                parent->d_count--;
                                list_del(&dentry->d_u.d_child);
-                               spin_unlock(&parent->d_lock);
                        }
 
-                       detached++;
-
                        inode = dentry->d_inode;
                        if (inode) {
                                dentry->d_inode = NULL;
@@ -938,9 +926,7 @@ void shrink_dcache_for_umount(struct super_block *sb)
 
        dentry = sb->s_root;
        sb->s_root = NULL;
-       spin_lock(&dentry->d_lock);
        dentry->d_count--;
-       spin_unlock(&dentry->d_lock);
        shrink_dcache_for_umount_subtree(dentry);
 
        while (!hlist_bl_empty(&sb->s_anon)) {
@@ -1743,7 +1729,7 @@ seqretry:
                 */
                if (read_seqcount_retry(&dentry->d_seq, *seq))
                        goto seqretry;
-               if (parent->d_flags & DCACHE_OP_COMPARE) {
+               if (unlikely(parent->d_flags & DCACHE_OP_COMPARE)) {
                        if (parent->d_op->d_compare(parent, *inode,
                                                dentry, i,
                                                tlen, tname, name))
index 1cd6d9d..cc16562 100644 (file)
@@ -1,6 +1,6 @@
 config ECRYPT_FS
        tristate "eCrypt filesystem layer support (EXPERIMENTAL)"
-       depends on EXPERIMENTAL && KEYS && CRYPTO
+       depends on EXPERIMENTAL && KEYS && CRYPTO && (ENCRYPTED_KEYS || ENCRYPTED_KEYS=n)
        select CRYPTO_ECB
        select CRYPTO_CBC
        select CRYPTO_MD5
index 340c657..11f8582 100644 (file)
@@ -69,6 +69,7 @@ static int ecryptfs_inode_set(struct inode *inode, void *opaque)
        inode->i_ino = lower_inode->i_ino;
        inode->i_version++;
        inode->i_mapping->a_ops = &ecryptfs_aops;
+       inode->i_mapping->backing_dev_info = inode->i_sb->s_bdi;
 
        if (S_ISLNK(inode->i_mode))
                inode->i_op = &ecryptfs_symlink_iops;
index c472533..ac1ad48 100644 (file)
@@ -1871,11 +1871,6 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
         * just one will be sufficient to decrypt to get the FEK. */
 find_next_matching_auth_tok:
        found_auth_tok = 0;
-       if (auth_tok_key) {
-               up_write(&(auth_tok_key->sem));
-               key_put(auth_tok_key);
-               auth_tok_key = NULL;
-       }
        list_for_each_entry(auth_tok_list_item, &auth_tok_list, list) {
                candidate_auth_tok = &auth_tok_list_item->auth_tok;
                if (unlikely(ecryptfs_verbosity > 0)) {
@@ -1912,14 +1907,22 @@ found_matching_auth_tok:
                memcpy(&(candidate_auth_tok->token.private_key),
                       &(matching_auth_tok->token.private_key),
                       sizeof(struct ecryptfs_private_key));
+               up_write(&(auth_tok_key->sem));
+               key_put(auth_tok_key);
                rc = decrypt_pki_encrypted_session_key(candidate_auth_tok,
                                                       crypt_stat);
        } else if (candidate_auth_tok->token_type == ECRYPTFS_PASSWORD) {
                memcpy(&(candidate_auth_tok->token.password),
                       &(matching_auth_tok->token.password),
                       sizeof(struct ecryptfs_password));
+               up_write(&(auth_tok_key->sem));
+               key_put(auth_tok_key);
                rc = decrypt_passphrase_encrypted_session_key(
                        candidate_auth_tok, crypt_stat);
+       } else {
+               up_write(&(auth_tok_key->sem));
+               key_put(auth_tok_key);
+               rc = -EINVAL;
        }
        if (rc) {
                struct ecryptfs_auth_tok_list_item *auth_tok_list_item_tmp;
@@ -1959,21 +1962,18 @@ found_matching_auth_tok:
 out_wipe_list:
        wipe_auth_tok_list(&auth_tok_list);
 out:
-       if (auth_tok_key) {
-               up_write(&(auth_tok_key->sem));
-               key_put(auth_tok_key);
-       }
        return rc;
 }
 
 static int
-pki_encrypt_session_key(struct ecryptfs_auth_tok *auth_tok,
+pki_encrypt_session_key(struct key *auth_tok_key,
+                       struct ecryptfs_auth_tok *auth_tok,
                        struct ecryptfs_crypt_stat *crypt_stat,
                        struct ecryptfs_key_record *key_rec)
 {
        struct ecryptfs_msg_ctx *msg_ctx = NULL;
        char *payload = NULL;
-       size_t payload_len;
+       size_t payload_len = 0;
        struct ecryptfs_message *msg;
        int rc;
 
@@ -1982,6 +1982,8 @@ pki_encrypt_session_key(struct ecryptfs_auth_tok *auth_tok,
                                         crypt_stat->cipher,
                                         crypt_stat->key_size),
                                 crypt_stat, &payload, &payload_len);
+       up_write(&(auth_tok_key->sem));
+       key_put(auth_tok_key);
        if (rc) {
                ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet\n");
                goto out;
@@ -2011,6 +2013,8 @@ out:
  * write_tag_1_packet - Write an RFC2440-compatible tag 1 (public key) packet
  * @dest: Buffer into which to write the packet
  * @remaining_bytes: Maximum number of bytes that can be writtn
+ * @auth_tok_key: The authentication token key to unlock and put when done with
+ *                @auth_tok
  * @auth_tok: The authentication token used for generating the tag 1 packet
  * @crypt_stat: The cryptographic context
  * @key_rec: The key record struct for the tag 1 packet
@@ -2021,7 +2025,7 @@ out:
  */
 static int
 write_tag_1_packet(char *dest, size_t *remaining_bytes,
-                  struct ecryptfs_auth_tok *auth_tok,
+                  struct key *auth_tok_key, struct ecryptfs_auth_tok *auth_tok,
                   struct ecryptfs_crypt_stat *crypt_stat,
                   struct ecryptfs_key_record *key_rec, size_t *packet_size)
 {
@@ -2042,12 +2046,15 @@ write_tag_1_packet(char *dest, size_t *remaining_bytes,
                memcpy(key_rec->enc_key,
                       auth_tok->session_key.encrypted_key,
                       auth_tok->session_key.encrypted_key_size);
+               up_write(&(auth_tok_key->sem));
+               key_put(auth_tok_key);
                goto encrypted_session_key_set;
        }
        if (auth_tok->session_key.encrypted_key_size == 0)
                auth_tok->session_key.encrypted_key_size =
                        auth_tok->token.private_key.key_size;
-       rc = pki_encrypt_session_key(auth_tok, crypt_stat, key_rec);
+       rc = pki_encrypt_session_key(auth_tok_key, auth_tok, crypt_stat,
+                                    key_rec);
        if (rc) {
                printk(KERN_ERR "Failed to encrypt session key via a key "
                       "module; rc = [%d]\n", rc);
@@ -2424,6 +2431,8 @@ ecryptfs_generate_key_packet_set(char *dest_base,
                                                &max, auth_tok,
                                                crypt_stat, key_rec,
                                                &written);
+                       up_write(&(auth_tok_key->sem));
+                       key_put(auth_tok_key);
                        if (rc) {
                                ecryptfs_printk(KERN_WARNING, "Error "
                                                "writing tag 3 packet\n");
@@ -2441,8 +2450,8 @@ ecryptfs_generate_key_packet_set(char *dest_base,
                        }
                        (*len) += written;
                } else if (auth_tok->token_type == ECRYPTFS_PRIVATE_KEY) {
-                       rc = write_tag_1_packet(dest_base + (*len),
-                                               &max, auth_tok,
+                       rc = write_tag_1_packet(dest_base + (*len), &max,
+                                               auth_tok_key, auth_tok,
                                                crypt_stat, key_rec, &written);
                        if (rc) {
                                ecryptfs_printk(KERN_WARNING, "Error "
@@ -2451,14 +2460,13 @@ ecryptfs_generate_key_packet_set(char *dest_base,
                        }
                        (*len) += written;
                } else {
+                       up_write(&(auth_tok_key->sem));
+                       key_put(auth_tok_key);
                        ecryptfs_printk(KERN_WARNING, "Unsupported "
                                        "authentication token type\n");
                        rc = -EINVAL;
                        goto out_free;
                }
-               up_write(&(auth_tok_key->sem));
-               key_put(auth_tok_key);
-               auth_tok_key = NULL;
        }
        if (likely(max > 0)) {
                dest_base[(*len)] = 0x00;
@@ -2471,11 +2479,6 @@ out_free:
 out:
        if (rc)
                (*len) = 0;
-       if (auth_tok_key) {
-               up_write(&(auth_tok_key->sem));
-               key_put(auth_tok_key);
-       }
-
        mutex_unlock(&crypt_stat->keysig_list_mutex);
        return rc;
 }
index 9f1bb74..b4a6bef 100644 (file)
@@ -175,6 +175,7 @@ enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig,
        ecryptfs_opt_encrypted_view, ecryptfs_opt_fnek_sig,
        ecryptfs_opt_fn_cipher, ecryptfs_opt_fn_cipher_key_bytes,
        ecryptfs_opt_unlink_sigs, ecryptfs_opt_mount_auth_tok_only,
+       ecryptfs_opt_check_dev_ruid,
        ecryptfs_opt_err };
 
 static const match_table_t tokens = {
@@ -191,6 +192,7 @@ static const match_table_t tokens = {
        {ecryptfs_opt_fn_cipher_key_bytes, "ecryptfs_fn_key_bytes=%u"},
        {ecryptfs_opt_unlink_sigs, "ecryptfs_unlink_sigs"},
        {ecryptfs_opt_mount_auth_tok_only, "ecryptfs_mount_auth_tok_only"},
+       {ecryptfs_opt_check_dev_ruid, "ecryptfs_check_dev_ruid"},
        {ecryptfs_opt_err, NULL}
 };
 
@@ -236,6 +238,7 @@ static void ecryptfs_init_mount_crypt_stat(
  * ecryptfs_parse_options
  * @sb: The ecryptfs super block
  * @options: The options passed to the kernel
+ * @check_ruid: set to 1 if device uid should be checked against the ruid
  *
  * Parse mount options:
  * debug=N        - ecryptfs_verbosity level for debug output
@@ -251,7 +254,8 @@ static void ecryptfs_init_mount_crypt_stat(
  *
  * Returns zero on success; non-zero on error
  */
-static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options)
+static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options,
+                                 uid_t *check_ruid)
 {
        char *p;
        int rc = 0;
@@ -276,6 +280,8 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options)
        char *cipher_key_bytes_src;
        char *fn_cipher_key_bytes_src;
 
+       *check_ruid = 0;
+
        if (!options) {
                rc = -EINVAL;
                goto out;
@@ -380,6 +386,9 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options)
                        mount_crypt_stat->flags |=
                                ECRYPTFS_GLOBAL_MOUNT_AUTH_TOK_ONLY;
                        break;
+               case ecryptfs_opt_check_dev_ruid:
+                       *check_ruid = 1;
+                       break;
                case ecryptfs_opt_err:
                default:
                        printk(KERN_WARNING
@@ -475,6 +484,7 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags
        const char *err = "Getting sb failed";
        struct inode *inode;
        struct path path;
+       uid_t check_ruid;
        int rc;
 
        sbi = kmem_cache_zalloc(ecryptfs_sb_info_cache, GFP_KERNEL);
@@ -483,7 +493,7 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags
                goto out;
        }
 
-       rc = ecryptfs_parse_options(sbi, raw_data);
+       rc = ecryptfs_parse_options(sbi, raw_data, &check_ruid);
        if (rc) {
                err = "Error parsing options";
                goto out;
@@ -521,6 +531,15 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags
                        "known incompatibilities\n");
                goto out_free;
        }
+
+       if (check_ruid && path.dentry->d_inode->i_uid != current_uid()) {
+               rc = -EPERM;
+               printk(KERN_ERR "Mount of device (uid: %d) not owned by "
+                      "requested user (uid: %d)\n",
+                      path.dentry->d_inode->i_uid, current_uid());
+               goto out_free;
+       }
+
        ecryptfs_set_superblock_lower(s, path.dentry->d_sb);
        s->s_maxbytes = path.dentry->d_sb->s_maxbytes;
        s->s_blocksize = path.dentry->d_sb->s_blocksize;
index 85d4309..3745f7c 100644 (file)
 int ecryptfs_write_lower(struct inode *ecryptfs_inode, char *data,
                         loff_t offset, size_t size)
 {
-       struct ecryptfs_inode_info *inode_info;
+       struct file *lower_file;
        mm_segment_t fs_save;
        ssize_t rc;
 
-       inode_info = ecryptfs_inode_to_private(ecryptfs_inode);
-       BUG_ON(!inode_info->lower_file);
+       lower_file = ecryptfs_inode_to_private(ecryptfs_inode)->lower_file;
+       if (!lower_file)
+               return -EIO;
        fs_save = get_fs();
        set_fs(get_ds());
-       rc = vfs_write(inode_info->lower_file, data, size, &offset);
+       rc = vfs_write(lower_file, data, size, &offset);
        set_fs(fs_save);
        mark_inode_dirty_sync(ecryptfs_inode);
        return rc;
@@ -225,15 +226,16 @@ out:
 int ecryptfs_read_lower(char *data, loff_t offset, size_t size,
                        struct inode *ecryptfs_inode)
 {
-       struct ecryptfs_inode_info *inode_info =
-               ecryptfs_inode_to_private(ecryptfs_inode);
+       struct file *lower_file;
        mm_segment_t fs_save;
        ssize_t rc;
 
-       BUG_ON(!inode_info->lower_file);
+       lower_file = ecryptfs_inode_to_private(ecryptfs_inode)->lower_file;
+       if (!lower_file)
+               return -EIO;
        fs_save = get_fs();
        set_fs(get_ds());
-       rc = vfs_read(inode_info->lower_file, data, size, &offset);
+       rc = vfs_read(lower_file, data, size, &offset);
        set_fs(fs_save);
        return rc;
 }
index da80612..25dcbe5 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1459,6 +1459,23 @@ static int do_execve_common(const char *filename,
        struct files_struct *displaced;
        bool clear_in_exec;
        int retval;
+       const struct cred *cred = current_cred();
+
+       /*
+        * We move the actual failure in case of RLIMIT_NPROC excess from
+        * set*uid() to execve() because too many poorly written programs
+        * don't check setuid() return code.  Here we additionally recheck
+        * whether NPROC limit is still exceeded.
+        */
+       if ((current->flags & PF_NPROC_EXCEEDED) &&
+           atomic_read(&cred->user->processes) > rlimit(RLIMIT_NPROC)) {
+               retval = -EAGAIN;
+               goto out_ret;
+       }
+
+       /* We're below the limit (still or again), so we don't want to make
+        * further execve() calls fail. */
+       current->flags &= ~PF_NPROC_EXCEEDED;
 
        retval = unshare_files(&displaced);
        if (retval)
index 2d0f757..c5a5855 100644 (file)
@@ -12,5 +12,8 @@
 # Kbuild - Gets included from the Kernels Makefile and build system
 #
 
-exofs-y := ios.o inode.o file.o symlink.o namei.o dir.o super.o
+# ore module library
+obj-$(CONFIG_ORE) += ore.o
+
+exofs-y := inode.o file.o symlink.o namei.o dir.o super.o
 obj-$(CONFIG_EXOFS_FS) += exofs.o
index 86194b2..70bae41 100644 (file)
@@ -1,6 +1,10 @@
+config ORE
+       tristate
+
 config EXOFS_FS
        tristate "exofs: OSD based file system support"
        depends on SCSI_OSD_ULD
+       select ORE
        help
          EXOFS is a file system that uses an OSD storage device,
          as its backing storage.
index c965806..f4e442e 100644 (file)
 #include <linux/fs.h>
 #include <linux/time.h>
 #include <linux/backing-dev.h>
-#include "common.h"
+#include <scsi/osd_ore.h>
 
-/* FIXME: Remove once pnfs hits mainline
- * #include <linux/exportfs/pnfs_osd_xdr.h>
- */
-#include "pnfs.h"
+#include "common.h"
 
 #define EXOFS_ERR(fmt, a...) printk(KERN_ERR "exofs: " fmt, ##a)
 
 /* u64 has problems with printk this will cast it to unsigned long long */
 #define _LLU(x) (unsigned long long)(x)
 
-struct exofs_layout {
-       osd_id          s_pid;                  /* partition ID of file system*/
-
-       /* Our way of looking at the data_map */
-       unsigned stripe_unit;
-       unsigned mirrors_p1;
-
-       unsigned group_width;
-       u64      group_depth;
-       unsigned group_count;
-
-       enum exofs_inode_layout_gen_functions lay_func;
-
-       unsigned        s_numdevs;              /* Num of devices in array    */
-       struct osd_dev  *s_ods[0];              /* Variable length            */
-};
-
 /*
  * our extension to the in-memory superblock
  */
 struct exofs_sb_info {
+       struct backing_dev_info bdi;            /* register our bdi with VFS  */
        struct exofs_sb_stats s_ess;            /* Written often, pre-allocate*/
        int             s_timeout;              /* timeout for OSD operations */
        uint64_t        s_nextid;               /* highest object ID used     */
@@ -84,16 +65,13 @@ struct exofs_sb_info {
        spinlock_t      s_next_gen_lock;        /* spinlock for gen # update  */
        u32             s_next_generation;      /* next gen # to use          */
        atomic_t        s_curr_pending;         /* number of pending commands */
-       uint8_t         s_cred[OSD_CAP_LEN];    /* credential for the fscb    */
-       struct          backing_dev_info bdi;   /* register our bdi with VFS  */
 
        struct pnfs_osd_data_map data_map;      /* Default raid to use
                                                 * FIXME: Needed ?
                                                 */
-/*     struct exofs_layout     dir_layout;*/   /* Default dir layout */
-       struct exofs_layout     layout;         /* Default files layout,
-                                                * contains the variable osd_dev
-                                                * array. Keep last */
+       struct ore_layout       layout;         /* Default files layout       */
+       struct ore_comp one_comp;               /* id & cred of partition id=0*/
+       struct ore_components comps;            /* comps for the partition    */
        struct osd_dev  *_min_one_dev[1];       /* Place holder for one dev   */
 };
 
@@ -107,7 +85,8 @@ struct exofs_i_info {
        uint32_t       i_data[EXOFS_IDATA];/*short symlink names and device #s*/
        uint32_t       i_dir_start_lookup; /* which page to start lookup      */
        uint64_t       i_commit_size;      /* the object's written length     */
-       uint8_t        i_cred[OSD_CAP_LEN];/* all-powerful credential         */
+       struct ore_comp one_comp;          /* same component for all devices  */
+       struct ore_components comps;       /* inode view of the device table  */
 };
 
 static inline osd_id exofs_oi_objno(struct exofs_i_info *oi)
@@ -115,52 +94,6 @@ static inline osd_id exofs_oi_objno(struct exofs_i_info *oi)
        return oi->vfs_inode.i_ino + EXOFS_OBJ_OFF;
 }
 
-struct exofs_io_state;
-typedef void (*exofs_io_done_fn)(struct exofs_io_state *or, void *private);
-
-struct exofs_io_state {
-       struct kref             kref;
-
-       void                    *private;
-       exofs_io_done_fn        done;
-
-       struct exofs_layout     *layout;
-       struct osd_obj_id       obj;
-       u8                      *cred;
-
-       /* Global read/write IO*/
-       loff_t                  offset;
-       unsigned long           length;
-       void                    *kern_buff;
-
-       struct page             **pages;
-       unsigned                nr_pages;
-       unsigned                pgbase;
-       unsigned                pages_consumed;
-
-       /* Attributes */
-       unsigned                in_attr_len;
-       struct osd_attr         *in_attr;
-       unsigned                out_attr_len;
-       struct osd_attr         *out_attr;
-
-       /* Variable array of size numdevs */
-       unsigned numdevs;
-       struct exofs_per_dev_state {
-               struct osd_request *or;
-               struct bio *bio;
-               loff_t offset;
-               unsigned length;
-               unsigned dev;
-       } per_dev[];
-};
-
-static inline unsigned exofs_io_state_size(unsigned numdevs)
-{
-       return sizeof(struct exofs_io_state) +
-               sizeof(struct exofs_per_dev_state) * numdevs;
-}
-
 /*
  * our inode flags
  */
@@ -204,12 +137,6 @@ static inline struct exofs_i_info *exofs_i(struct inode *inode)
        return container_of(inode, struct exofs_i_info, vfs_inode);
 }
 
-/*
- * Given a layout, object_number and stripe_index return the associated global
- * dev_index
- */
-unsigned exofs_layout_od_id(struct exofs_layout *layout,
-                           osd_id obj_no, unsigned layout_index);
 /*
  * Maximum count of links to a file
  */
@@ -219,44 +146,8 @@ unsigned exofs_layout_od_id(struct exofs_layout *layout,
  * function declarations *
  *************************/
 
-/* ios.c */
-void exofs_make_credential(u8 cred_a[OSD_CAP_LEN],
-                          const struct osd_obj_id *obj);
-int exofs_read_kern(struct osd_dev *od, u8 *cred, struct osd_obj_id *obj,
-                   u64 offset, void *p, unsigned length);
-
-int  exofs_get_io_state(struct exofs_layout *layout,
-                       struct exofs_io_state **ios);
-void exofs_put_io_state(struct exofs_io_state *ios);
-
-int exofs_check_io(struct exofs_io_state *ios, u64 *resid);
-
-int exofs_sbi_create(struct exofs_io_state *ios);
-int exofs_sbi_remove(struct exofs_io_state *ios);
-int exofs_sbi_write(struct exofs_io_state *ios);
-int exofs_sbi_read(struct exofs_io_state *ios);
-
-int extract_attr_from_ios(struct exofs_io_state *ios, struct osd_attr *attr);
-
-int exofs_oi_truncate(struct exofs_i_info *oi, u64 new_len);
-static inline int exofs_oi_write(struct exofs_i_info *oi,
-                                struct exofs_io_state *ios)
-{
-       ios->obj.id = exofs_oi_objno(oi);
-       ios->cred = oi->i_cred;
-       return exofs_sbi_write(ios);
-}
-
-static inline int exofs_oi_read(struct exofs_i_info *oi,
-                               struct exofs_io_state *ios)
-{
-       ios->obj.id = exofs_oi_objno(oi);
-       ios->cred = oi->i_cred;
-       return exofs_sbi_read(ios);
-}
-
 /* inode.c               */
-unsigned exofs_max_io_pages(struct exofs_layout *layout,
+unsigned exofs_max_io_pages(struct ore_layout *layout,
                            unsigned expected_pages);
 int exofs_setattr(struct dentry *, struct iattr *);
 int exofs_write_begin(struct file *file, struct address_space *mapping,
@@ -281,6 +172,8 @@ int exofs_set_link(struct inode *, struct exofs_dir_entry *, struct page *,
                    struct inode *);
 
 /* super.c               */
+void exofs_make_credential(u8 cred_a[OSD_CAP_LEN],
+                          const struct osd_obj_id *obj);
 int exofs_sbi_write_stats(struct exofs_sb_info *sbi);
 
 /*********************
@@ -295,7 +188,6 @@ extern const struct file_operations exofs_file_operations;
 
 /* inode.c           */
 extern const struct address_space_operations exofs_aops;
-extern const struct osd_attr g_attr_logical_length;
 
 /* namei.c           */
 extern const struct inode_operations exofs_dir_inode_operations;
@@ -305,4 +197,33 @@ extern const struct inode_operations exofs_special_inode_operations;
 extern const struct inode_operations exofs_symlink_inode_operations;
 extern const struct inode_operations exofs_fast_symlink_inode_operations;
 
+/* exofs_init_comps will initialize an ore_components device array
+ * pointing to a single ore_comp struct, and a round-robin view
+ * of the device table.
+ * The first device of each inode is the [inode->ino % num_devices]
+ * and the rest of the devices sequentially following where the
+ * first device is after the last device.
+ * It is assumed that the global device array at @sbi is twice
+ * bigger and that the device table repeats twice.
+ * See: exofs_read_lookup_dev_table()
+ */
+static inline void exofs_init_comps(struct ore_components *comps,
+                                   struct ore_comp *one_comp,
+                                   struct exofs_sb_info *sbi, osd_id oid)
+{
+       unsigned dev_mod = (unsigned)oid, first_dev;
+
+       one_comp->obj.partition = sbi->one_comp.obj.partition;
+       one_comp->obj.id = oid;
+       exofs_make_credential(one_comp->cred, &one_comp->obj);
+
+       comps->numdevs = sbi->comps.numdevs;
+       comps->single_comp = EC_SINGLE_COMP;
+       comps->comps = one_comp;
+
+       /* Round robin device view of the table */
+       first_dev = (dev_mod * sbi->layout.mirrors_p1) % sbi->comps.numdevs;
+       comps->ods = sbi->comps.ods + first_dev;
+}
+
 #endif
index 8472c09..f39a38f 100644 (file)
@@ -43,7 +43,7 @@ enum { BIO_MAX_PAGES_KMALLOC =
                PAGE_SIZE / sizeof(struct page *),
 };
 
-unsigned exofs_max_io_pages(struct exofs_layout *layout,
+unsigned exofs_max_io_pages(struct ore_layout *layout,
                            unsigned expected_pages)
 {
        unsigned pages = min_t(unsigned, expected_pages, MAX_PAGES_KMALLOC);
@@ -58,7 +58,7 @@ struct page_collect {
        struct exofs_sb_info *sbi;
        struct inode *inode;
        unsigned expected_pages;
-       struct exofs_io_state *ios;
+       struct ore_io_state *ios;
 
        struct page **pages;
        unsigned alloc_pages;
@@ -110,13 +110,6 @@ static int pcol_try_alloc(struct page_collect *pcol)
 {
        unsigned pages;
 
-       if (!pcol->ios) { /* First time allocate io_state */
-               int ret = exofs_get_io_state(&pcol->sbi->layout, &pcol->ios);
-
-               if (ret)
-                       return ret;
-       }
-
        /* TODO: easily support bio chaining */
        pages =  exofs_max_io_pages(&pcol->sbi->layout, pcol->expected_pages);
 
@@ -140,7 +133,7 @@ static void pcol_free(struct page_collect *pcol)
        pcol->pages = NULL;
 
        if (pcol->ios) {
-               exofs_put_io_state(pcol->ios);
+               ore_put_io_state(pcol->ios);
                pcol->ios = NULL;
        }
 }
@@ -200,7 +193,7 @@ static int __readpages_done(struct page_collect *pcol)
        u64 resid;
        u64 good_bytes;
        u64 length = 0;
-       int ret = exofs_check_io(pcol->ios, &resid);
+       int ret = ore_check_io(pcol->ios, &resid);
 
        if (likely(!ret))
                good_bytes = pcol->length;
@@ -241,7 +234,7 @@ static int __readpages_done(struct page_collect *pcol)
 }
 
 /* callback of async reads */
-static void readpages_done(struct exofs_io_state *ios, void *p)
+static void readpages_done(struct ore_io_state *ios, void *p)
 {
        struct page_collect *pcol = p;
 
@@ -269,20 +262,28 @@ static void _unlock_pcol_pages(struct page_collect *pcol, int ret, int rw)
 static int read_exec(struct page_collect *pcol)
 {
        struct exofs_i_info *oi = exofs_i(pcol->inode);
-       struct exofs_io_state *ios = pcol->ios;
+       struct ore_io_state *ios;
        struct page_collect *pcol_copy = NULL;
        int ret;
 
        if (!pcol->pages)
                return 0;
 
+       if (!pcol->ios) {
+               int ret = ore_get_rw_state(&pcol->sbi->layout, &oi->comps, true,
+                                            pcol->pg_first << PAGE_CACHE_SHIFT,
+                                            pcol->length, &pcol->ios);
+
+               if (ret)
+                       return ret;
+       }
+
+       ios = pcol->ios;
        ios->pages = pcol->pages;
        ios->nr_pages = pcol->nr_pages;
-       ios->length = pcol->length;
-       ios->offset = pcol->pg_first << PAGE_CACHE_SHIFT;
 
        if (pcol->read_4_write) {
-               exofs_oi_read(oi, pcol->ios);
+               ore_read(pcol->ios);
                return __readpages_done(pcol);
        }
 
@@ -295,14 +296,14 @@ static int read_exec(struct page_collect *pcol)
        *pcol_copy = *pcol;
        ios->done = readpages_done;
        ios->private = pcol_copy;
-       ret = exofs_oi_read(oi, ios);
+       ret = ore_read(ios);
        if (unlikely(ret))
                goto err;
 
        atomic_inc(&pcol->sbi->s_curr_pending);
 
        EXOFS_DBGMSG2("read_exec obj=0x%llx start=0x%llx length=0x%lx\n",
-                 ios->obj.id, _LLU(ios->offset), pcol->length);
+                 oi->one_comp.obj.id, _LLU(ios->offset), pcol->length);
 
        /* pages ownership was passed to pcol_copy */
        _pcol_reset(pcol);
@@ -457,14 +458,14 @@ static int exofs_readpage(struct file *file, struct page *page)
 }
 
 /* Callback for osd_write. All writes are asynchronous */
-static void writepages_done(struct exofs_io_state *ios, void *p)
+static void writepages_done(struct ore_io_state *ios, void *p)
 {
        struct page_collect *pcol = p;
        int i;
        u64 resid;
        u64  good_bytes;
        u64  length = 0;
-       int ret = exofs_check_io(ios, &resid);
+       int ret = ore_check_io(ios, &resid);
 
        atomic_dec(&pcol->sbi->s_curr_pending);
 
@@ -507,13 +508,21 @@ static void writepages_done(struct exofs_io_state *ios, void *p)
 static int write_exec(struct page_collect *pcol)
 {
        struct exofs_i_info *oi = exofs_i(pcol->inode);
-       struct exofs_io_state *ios = pcol->ios;
+       struct ore_io_state *ios;
        struct page_collect *pcol_copy = NULL;
        int ret;
 
        if (!pcol->pages)
                return 0;
 
+       BUG_ON(pcol->ios);
+       ret = ore_get_rw_state(&pcol->sbi->layout, &oi->comps, false,
+                                pcol->pg_first << PAGE_CACHE_SHIFT,
+                                pcol->length, &pcol->ios);
+
+       if (unlikely(ret))
+               goto err;
+
        pcol_copy = kmalloc(sizeof(*pcol_copy), GFP_KERNEL);
        if (!pcol_copy) {
                EXOFS_ERR("write_exec: Failed to kmalloc(pcol)\n");
@@ -523,16 +532,15 @@ static int write_exec(struct page_collect *pcol)
 
        *pcol_copy = *pcol;
 
+       ios = pcol->ios;
        ios->pages = pcol_copy->pages;
        ios->nr_pages = pcol_copy->nr_pages;
-       ios->offset = pcol_copy->pg_first << PAGE_CACHE_SHIFT;
-       ios->length = pcol_copy->length;
        ios->done = writepages_done;
        ios->private = pcol_copy;
 
-       ret = exofs_oi_write(oi, ios);
+       ret = ore_write(ios);
        if (unlikely(ret)) {
-               EXOFS_ERR("write_exec: exofs_oi_write() Failed\n");
+               EXOFS_ERR("write_exec: ore_write() Failed\n");
                goto err;
        }
 
@@ -844,17 +852,15 @@ static inline int exofs_inode_is_fast_symlink(struct inode *inode)
        return S_ISLNK(inode->i_mode) && (oi->i_data[0] != 0);
 }
 
-const struct osd_attr g_attr_logical_length = ATTR_DEF(
-       OSD_APAGE_OBJECT_INFORMATION, OSD_ATTR_OI_LOGICAL_LENGTH, 8);
-
 static int _do_truncate(struct inode *inode, loff_t newsize)
 {
        struct exofs_i_info *oi = exofs_i(inode);
+       struct exofs_sb_info *sbi = inode->i_sb->s_fs_info;
        int ret;
 
        inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 
-       ret = exofs_oi_truncate(oi, (u64)newsize);
+       ret = ore_truncate(&sbi->layout, &oi->comps, (u64)newsize);
        if (likely(!ret))
                truncate_setsize(inode, newsize);
 
@@ -917,30 +923,26 @@ static int exofs_get_inode(struct super_block *sb, struct exofs_i_info *oi,
                [1] = g_attr_inode_file_layout,
                [2] = g_attr_inode_dir_layout,
        };
-       struct exofs_io_state *ios;
+       struct ore_io_state *ios;
        struct exofs_on_disk_inode_layout *layout;
        int ret;
 
-       ret = exofs_get_io_state(&sbi->layout, &ios);
+       ret = ore_get_io_state(&sbi->layout, &oi->comps, &ios);
        if (unlikely(ret)) {
-               EXOFS_ERR("%s: exofs_get_io_state failed.\n", __func__);
+               EXOFS_ERR("%s: ore_get_io_state failed.\n", __func__);
                return ret;
        }
 
-       ios->obj.id = exofs_oi_objno(oi);
-       exofs_make_credential(oi->i_cred, &ios->obj);
-       ios->cred = oi->i_cred;
-
-       attrs[1].len = exofs_on_disk_inode_layout_size(sbi->layout.s_numdevs);
-       attrs[2].len = exofs_on_disk_inode_layout_size(sbi->layout.s_numdevs);
+       attrs[1].len = exofs_on_disk_inode_layout_size(sbi->comps.numdevs);
+       attrs[2].len = exofs_on_disk_inode_layout_size(sbi->comps.numdevs);
 
        ios->in_attr = attrs;
        ios->in_attr_len = ARRAY_SIZE(attrs);
 
-       ret = exofs_sbi_read(ios);
+       ret = ore_read(ios);
        if (unlikely(ret)) {
                EXOFS_ERR("object(0x%llx) corrupted, return empty file=>%d\n",
-                         _LLU(ios->obj.id), ret);
+                         _LLU(oi->one_comp.obj.id), ret);
                memset(inode, 0, sizeof(*inode));
                inode->i_mode = 0040000 | (0777 & ~022);
                /* If object is lost on target we might as well enable it's
@@ -990,7 +992,7 @@ static int exofs_get_inode(struct super_block *sb, struct exofs_i_info *oi,
        }
 
 out:
-       exofs_put_io_state(ios);
+       ore_put_io_state(ios);
        return ret;
 }
 
@@ -1016,6 +1018,8 @@ struct inode *exofs_iget(struct super_block *sb, unsigned long ino)
                return inode;
        oi = exofs_i(inode);
        __oi_init(oi);
+       exofs_init_comps(&oi->comps, &oi->one_comp, sb->s_fs_info,
+                        exofs_oi_objno(oi));
 
        /* read the inode from the osd */
        ret = exofs_get_inode(sb, oi, &fcb);
@@ -1107,21 +1111,22 @@ int __exofs_wait_obj_created(struct exofs_i_info *oi)
  * set the obj_created flag so that other methods know that the object exists on
  * the OSD.
  */
-static void create_done(struct exofs_io_state *ios, void *p)
+static void create_done(struct ore_io_state *ios, void *p)
 {
        struct inode *inode = p;
        struct exofs_i_info *oi = exofs_i(inode);
        struct exofs_sb_info *sbi = inode->i_sb->s_fs_info;
        int ret;
 
-       ret = exofs_check_io(ios, NULL);
-       exofs_put_io_state(ios);
+       ret = ore_check_io(ios, NULL);
+       ore_put_io_state(ios);
 
        atomic_dec(&sbi->s_curr_pending);
 
        if (unlikely(ret)) {
                EXOFS_ERR("object=0x%llx creation failed in pid=0x%llx",
-                         _LLU(exofs_oi_objno(oi)), _LLU(sbi->layout.s_pid));
+                         _LLU(exofs_oi_objno(oi)),
+                         _LLU(oi->one_comp.obj.partition));
                /*TODO: When FS is corrupted creation can fail, object already
                 * exist. Get rid of this asynchronous creation, if exist
                 * increment the obj counter and try the next object. Until we
@@ -1140,14 +1145,13 @@ static void create_done(struct exofs_io_state *ios, void *p)
  */
 struct inode *exofs_new_inode(struct inode *dir, int mode)
 {
-       struct super_block *sb;
+       struct super_block *sb = dir->i_sb;
+       struct exofs_sb_info *sbi = sb->s_fs_info;
        struct inode *inode;
        struct exofs_i_info *oi;
-       struct exofs_sb_info *sbi;
-       struct exofs_io_state *ios;
+       struct ore_io_state *ios;
        int ret;
 
-       sb = dir->i_sb;
        inode = new_inode(sb);
        if (!inode)
                return ERR_PTR(-ENOMEM);
@@ -1157,8 +1161,6 @@ struct inode *exofs_new_inode(struct inode *dir, int mode)
 
        set_obj_2bcreated(oi);
 
-       sbi = sb->s_fs_info;
-
        inode->i_mapping->backing_dev_info = sb->s_bdi;
        inode_init_owner(inode, dir, mode);
        inode->i_ino = sbi->s_nextid++;
@@ -1170,25 +1172,24 @@ struct inode *exofs_new_inode(struct inode *dir, int mode)
        spin_unlock(&sbi->s_next_gen_lock);
        insert_inode_hash(inode);
 
+       exofs_init_comps(&oi->comps, &oi->one_comp, sb->s_fs_info,
+                        exofs_oi_objno(oi));
        exofs_sbi_write_stats(sbi); /* Make sure new sbi->s_nextid is on disk */
 
        mark_inode_dirty(inode);
 
-       ret = exofs_get_io_state(&sbi->layout, &ios);
+       ret = ore_get_io_state(&sbi->layout, &oi->comps, &ios);
        if (unlikely(ret)) {
-               EXOFS_ERR("exofs_new_inode: exofs_get_io_state failed\n");
+               EXOFS_ERR("exofs_new_inode: ore_get_io_state failed\n");
                return ERR_PTR(ret);
        }
 
-       ios->obj.id = exofs_oi_objno(oi);
-       exofs_make_credential(oi->i_cred, &ios->obj);
-
        ios->done = create_done;
        ios->private = inode;
-       ios->cred = oi->i_cred;
-       ret = exofs_sbi_create(ios);
+
+       ret = ore_create(ios);
        if (ret) {
-               exofs_put_io_state(ios);
+               ore_put_io_state(ios);
                return ERR_PTR(ret);
        }
        atomic_inc(&sbi->s_curr_pending);
@@ -1207,11 +1208,11 @@ struct updatei_args {
 /*
  * Callback function from exofs_update_inode().
  */
-static void updatei_done(struct exofs_io_state *ios, void *p)
+static void updatei_done(struct ore_io_state *ios, void *p)
 {
        struct updatei_args *args = p;
 
-       exofs_put_io_state(ios);
+       ore_put_io_state(ios);
 
        atomic_dec(&args->sbi->s_curr_pending);
 
@@ -1227,7 +1228,7 @@ static int exofs_update_inode(struct inode *inode, int do_sync)
        struct exofs_i_info *oi = exofs_i(inode);
        struct super_block *sb = inode->i_sb;
        struct exofs_sb_info *sbi = sb->s_fs_info;
-       struct exofs_io_state *ios;
+       struct ore_io_state *ios;
        struct osd_attr attr;
        struct exofs_fcb *fcb;
        struct updatei_args *args;
@@ -1266,9 +1267,9 @@ static int exofs_update_inode(struct inode *inode, int do_sync)
        } else
                memcpy(fcb->i_data, oi->i_data, sizeof(fcb->i_data));
 
-       ret = exofs_get_io_state(&sbi->layout, &ios);
+       ret = ore_get_io_state(&sbi->layout, &oi->comps, &ios);
        if (unlikely(ret)) {
-               EXOFS_ERR("%s: exofs_get_io_state failed.\n", __func__);
+               EXOFS_ERR("%s: ore_get_io_state failed.\n", __func__);
                goto free_args;
        }
 
@@ -1285,13 +1286,13 @@ static int exofs_update_inode(struct inode *inode, int do_sync)
                ios->private = args;
        }
 
-       ret = exofs_oi_write(oi, ios);
+       ret = ore_write(ios);
        if (!do_sync && !ret) {
                atomic_inc(&sbi->s_curr_pending);
                goto out; /* deallocation in updatei_done */
        }
 
-       exofs_put_io_state(ios);
+       ore_put_io_state(ios);
 free_args:
        kfree(args);
 out:
@@ -1310,11 +1311,11 @@ int exofs_write_inode(struct inode *inode, struct writeback_control *wbc)
  * Callback function from exofs_delete_inode() - don't have much cleaning up to
  * do.
  */
-static void delete_done(struct exofs_io_state *ios, void *p)
+static void delete_done(struct ore_io_state *ios, void *p)
 {
        struct exofs_sb_info *sbi = p;
 
-       exofs_put_io_state(ios);
+       ore_put_io_state(ios);
 
        atomic_dec(&sbi->s_curr_pending);
 }
@@ -1329,7 +1330,7 @@ void exofs_evict_inode(struct inode *inode)
        struct exofs_i_info *oi = exofs_i(inode);
        struct super_block *sb = inode->i_sb;
        struct exofs_sb_info *sbi = sb->s_fs_info;
-       struct exofs_io_state *ios;
+       struct ore_io_state *ios;
        int ret;
 
        truncate_inode_pages(&inode->i_data, 0);
@@ -1349,20 +1350,19 @@ void exofs_evict_inode(struct inode *inode)
        /* ignore the error, attempt a remove anyway */
 
        /* Now Remove the OSD objects */
-       ret = exofs_get_io_state(&sbi->layout, &ios);
+       ret = ore_get_io_state(&sbi->layout, &oi->comps, &ios);
        if (unlikely(ret)) {
-               EXOFS_ERR("%s: exofs_get_io_state failed\n", __func__);
+               EXOFS_ERR("%s: ore_get_io_state failed\n", __func__);
                return;
        }
 
-       ios->obj.id = exofs_oi_objno(oi);
        ios->done = delete_done;
        ios->private = sbi;
-       ios->cred = oi->i_cred;
-       ret = exofs_sbi_remove(ios);
+
+       ret = ore_remove(ios);
        if (ret) {
-               EXOFS_ERR("%s: exofs_sbi_remove failed\n", __func__);
-               exofs_put_io_state(ios);
+               EXOFS_ERR("%s: ore_remove failed\n", __func__);
+               ore_put_io_state(ios);
                return;
        }
        atomic_inc(&sbi->s_curr_pending);
similarity index 61%
rename from fs/exofs/ios.c
rename to fs/exofs/ore.c
index f74a2ec..25305af 100644 (file)
  */
 
 #include <linux/slab.h>
-#include <scsi/scsi_device.h>
 #include <asm/div64.h>
 
-#include "exofs.h"
+#include <scsi/osd_ore.h>
 
-#define EXOFS_DBGMSG2(M...) do {} while (0)
-/* #define EXOFS_DBGMSG2 EXOFS_DBGMSG */
+#define ORE_ERR(fmt, a...) printk(KERN_ERR "ore: " fmt, ##a)
 
-void exofs_make_credential(u8 cred_a[OSD_CAP_LEN], const struct osd_obj_id *obj)
-{
-       osd_sec_init_nosec_doall_caps(cred_a, obj, false, true);
-}
+#ifdef CONFIG_EXOFS_DEBUG
+#define ORE_DBGMSG(fmt, a...) \
+       printk(KERN_NOTICE "ore @%s:%d: " fmt, __func__, __LINE__, ##a)
+#else
+#define ORE_DBGMSG(fmt, a...) \
+       do { if (0) printk(fmt, ##a); } while (0)
+#endif
 
-int exofs_read_kern(struct osd_dev *od, u8 *cred, struct osd_obj_id *obj,
-                   u64 offset, void *p, unsigned length)
-{
-       struct osd_request *or = osd_start_request(od, GFP_KERNEL);
-/*     struct osd_sense_info osi = {.key = 0};*/
-       int ret;
+/* u64 has problems with printk this will cast it to unsigned long long */
+#define _LLU(x) (unsigned long long)(x)
 
-       if (unlikely(!or)) {
-               EXOFS_DBGMSG("%s: osd_start_request failed.\n", __func__);
-               return -ENOMEM;
-       }
-       ret = osd_req_read_kern(or, obj, offset, p, length);
-       if (unlikely(ret)) {
-               EXOFS_DBGMSG("%s: osd_req_read_kern failed.\n", __func__);
-               goto out;
-       }
+#define ORE_DBGMSG2(M...) do {} while (0)
+/* #define ORE_DBGMSG2 ORE_DBGMSG */
 
-       ret = osd_finalize_request(or, 0, cred, NULL);
-       if (unlikely(ret)) {
-               EXOFS_DBGMSG("Failed to osd_finalize_request() => %d\n", ret);
-               goto out;
-       }
+MODULE_AUTHOR("Boaz Harrosh <bharrosh@panasas.com>");
+MODULE_DESCRIPTION("Objects Raid Engine ore.ko");
+MODULE_LICENSE("GPL");
 
-       ret = osd_execute_request(or);
-       if (unlikely(ret))
-               EXOFS_DBGMSG("osd_execute_request() => %d\n", ret);
-       /* osd_req_decode_sense(or, ret); */
+static u8 *_ios_cred(struct ore_io_state *ios, unsigned index)
+{
+       return ios->comps->comps[index & ios->comps->single_comp].cred;
+}
 
-out:
-       osd_end_request(or);
-       return ret;
+static struct osd_obj_id *_ios_obj(struct ore_io_state *ios, unsigned index)
+{
+       return &ios->comps->comps[index & ios->comps->single_comp].obj;
 }
 
-int exofs_get_io_state(struct exofs_layout *layout,
-                      struct exofs_io_state **pios)
+static struct osd_dev *_ios_od(struct ore_io_state *ios, unsigned index)
 {
-       struct exofs_io_state *ios;
+       return ios->comps->ods[index];
+}
+
+int  ore_get_rw_state(struct ore_layout *layout, struct ore_components *comps,
+                     bool is_reading, u64 offset, u64 length,
+                     struct ore_io_state **pios)
+{
+       struct ore_io_state *ios;
 
        /*TODO: Maybe use kmem_cach per sbi of size
         * exofs_io_state_size(layout->s_numdevs)
         */
-       ios = kzalloc(exofs_io_state_size(layout->s_numdevs), GFP_KERNEL);
+       ios = kzalloc(ore_io_state_size(comps->numdevs), GFP_KERNEL);
        if (unlikely(!ios)) {
-               EXOFS_DBGMSG("Failed kzalloc bytes=%d\n",
-                            exofs_io_state_size(layout->s_numdevs));
+               ORE_DBGMSG("Failed kzalloc bytes=%d\n",
+                            ore_io_state_size(comps->numdevs));
                *pios = NULL;
                return -ENOMEM;
        }
 
        ios->layout = layout;
-       ios->obj.partition = layout->s_pid;
+       ios->comps = comps;
+       ios->offset = offset;
+       ios->length = length;
+       ios->reading = is_reading;
+
        *pios = ios;
        return 0;
 }
+EXPORT_SYMBOL(ore_get_rw_state);
+
+int  ore_get_io_state(struct ore_layout *layout, struct ore_components *comps,
+                     struct ore_io_state **ios)
+{
+       return ore_get_rw_state(layout, comps, true, 0, 0, ios);
+}
+EXPORT_SYMBOL(ore_get_io_state);
 
-void exofs_put_io_state(struct exofs_io_state *ios)
+void ore_put_io_state(struct ore_io_state *ios)
 {
        if (ios) {
                unsigned i;
 
                for (i = 0; i < ios->numdevs; i++) {
-                       struct exofs_per_dev_state *per_dev = &ios->per_dev[i];
+                       struct ore_per_dev_state *per_dev = &ios->per_dev[i];
 
                        if (per_dev->or)
                                osd_end_request(per_dev->or);
@@ -108,31 +114,9 @@ void exofs_put_io_state(struct exofs_io_state *ios)
                kfree(ios);
        }
 }
+EXPORT_SYMBOL(ore_put_io_state);
 
-unsigned exofs_layout_od_id(struct exofs_layout *layout,
-                           osd_id obj_no, unsigned layout_index)
-{
-/*     switch (layout->lay_func) {
-       case LAYOUT_MOVING_WINDOW:
-       {*/
-               unsigned dev_mod = obj_no;
-
-               return (layout_index + dev_mod * layout->mirrors_p1) %
-                                                             layout->s_numdevs;
-/*     }
-       case LAYOUT_FUNC_IMPLICT:
-               return layout->devs[layout_index];
-       }*/
-}
-
-static inline struct osd_dev *exofs_ios_od(struct exofs_io_state *ios,
-                                          unsigned layout_index)
-{
-       return ios->layout->s_ods[
-               exofs_layout_od_id(ios->layout, ios->obj.id, layout_index)];
-}
-
-static void _sync_done(struct exofs_io_state *ios, void *p)
+static void _sync_done(struct ore_io_state *ios, void *p)
 {
        struct completion *waiting = p;
 
@@ -141,20 +125,20 @@ static void _sync_done(struct exofs_io_state *ios, void *p)
 
 static void _last_io(struct kref *kref)
 {
-       struct exofs_io_state *ios = container_of(
-                                       kref, struct exofs_io_state, kref);
+       struct ore_io_state *ios = container_of(
+                                       kref, struct ore_io_state, kref);
 
        ios->done(ios, ios->private);
 }
 
 static void _done_io(struct osd_request *or, void *p)
 {
-       struct exofs_io_state *ios = p;
+       struct ore_io_state *ios = p;
 
        kref_put(&ios->kref, _last_io);
 }
 
-static int exofs_io_execute(struct exofs_io_state *ios)
+static int ore_io_execute(struct ore_io_state *ios)
 {
        DECLARE_COMPLETION_ONSTACK(wait);
        bool sync = (ios->done == NULL);
@@ -170,9 +154,9 @@ static int exofs_io_execute(struct exofs_io_state *ios)
                if (unlikely(!or))
                        continue;
 
-               ret = osd_finalize_request(or, 0, ios->cred, NULL);
+               ret = osd_finalize_request(or, 0, _ios_cred(ios, i), NULL);
                if (unlikely(ret)) {
-                       EXOFS_DBGMSG("Failed to osd_finalize_request() => %d\n",
+                       ORE_DBGMSG("Failed to osd_finalize_request() => %d\n",
                                     ret);
                        return ret;
                }
@@ -194,7 +178,7 @@ static int exofs_io_execute(struct exofs_io_state *ios)
 
        if (sync) {
                wait_for_completion(&wait);
-               ret = exofs_check_io(ios, NULL);
+               ret = ore_check_io(ios, NULL);
        }
        return ret;
 }
@@ -214,7 +198,7 @@ static void _clear_bio(struct bio *bio)
        }
 }
 
-int exofs_check_io(struct exofs_io_state *ios, u64 *resid)
+int ore_check_io(struct ore_io_state *ios, u64 *resid)
 {
        enum osd_err_priority acumulated_osd_err = 0;
        int acumulated_lin_err = 0;
@@ -235,7 +219,7 @@ int exofs_check_io(struct exofs_io_state *ios, u64 *resid)
                if (OSD_ERR_PRI_CLEAR_PAGES == osi.osd_err_pri) {
                        /* start read offset passed endof file */
                        _clear_bio(ios->per_dev[i].bio);
-                       EXOFS_DBGMSG("start read offset passed end of file "
+                       ORE_DBGMSG("start read offset passed end of file "
                                "offset=0x%llx, length=0x%llx\n",
                                _LLU(ios->per_dev[i].offset),
                                _LLU(ios->per_dev[i].length));
@@ -259,6 +243,7 @@ int exofs_check_io(struct exofs_io_state *ios, u64 *resid)
 
        return acumulated_lin_err;
 }
+EXPORT_SYMBOL(ore_check_io);
 
 /*
  * L - logical offset into the file
@@ -305,20 +290,21 @@ int exofs_check_io(struct exofs_io_state *ios, u64 *resid)
 struct _striping_info {
        u64 obj_offset;
        u64 group_length;
+       u64 M; /* for truncate */
        unsigned dev;
        unsigned unit_off;
 };
 
-static void _calc_stripe_info(struct exofs_io_state *ios, u64 file_offset,
+static void _calc_stripe_info(struct ore_layout *layout, u64 file_offset,
                              struct _striping_info *si)
 {
-       u32     stripe_unit = ios->layout->stripe_unit;
-       u32     group_width = ios->layout->group_width;
-       u64     group_depth = ios->layout->group_depth;
+       u32     stripe_unit = layout->stripe_unit;
+       u32     group_width = layout->group_width;
+       u64     group_depth = layout->group_depth;
 
        u32     U = stripe_unit * group_width;
        u64     T = U * group_depth;
-       u64     S = T * ios->layout->group_count;
+       u64     S = T * layout->group_count;
        u64     M = div64_u64(file_offset, S);
 
        /*
@@ -333,7 +319,7 @@ static void _calc_stripe_info(struct exofs_io_state *ios, u64 file_offset,
 
        /* "H - (N * U)" is just "H % U" so it's bound to u32 */
        si->dev = (u32)(H - (N * U)) / stripe_unit + G * group_width;
-       si->dev *= ios->layout->mirrors_p1;
+       si->dev *= layout->mirrors_p1;
 
        div_u64_rem(file_offset, stripe_unit, &si->unit_off);
 
@@ -341,15 +327,16 @@ static void _calc_stripe_info(struct exofs_io_state *ios, u64 file_offset,
                                  (M * group_depth * stripe_unit);
 
        si->group_length = T - H;
+       si->M = M;
 }
 
-static int _add_stripe_unit(struct exofs_io_state *ios,  unsigned *cur_pg,
-               unsigned pgbase, struct exofs_per_dev_state *per_dev,
+static int _add_stripe_unit(struct ore_io_state *ios,  unsigned *cur_pg,
+               unsigned pgbase, struct ore_per_dev_state *per_dev,
                int cur_len)
 {
        unsigned pg = *cur_pg;
        struct request_queue *q =
-                       osd_request_queue(exofs_ios_od(ios, per_dev->dev));
+                       osd_request_queue(_ios_od(ios, per_dev->dev));
 
        per_dev->length += cur_len;
 
@@ -361,7 +348,7 @@ static int _add_stripe_unit(struct exofs_io_state *ios,  unsigned *cur_pg,
 
                per_dev->bio = bio_kmalloc(GFP_KERNEL, bio_size);
                if (unlikely(!per_dev->bio)) {
-                       EXOFS_DBGMSG("Failed to allocate BIO size=%u\n",
+                       ORE_DBGMSG("Failed to allocate BIO size=%u\n",
                                     bio_size);
                        return -ENOMEM;
                }
@@ -387,7 +374,7 @@ static int _add_stripe_unit(struct exofs_io_state *ios,  unsigned *cur_pg,
        return 0;
 }
 
-static int _prepare_one_group(struct exofs_io_state *ios, u64 length,
+static int _prepare_one_group(struct ore_io_state *ios, u64 length,
                              struct _striping_info *si)
 {
        unsigned stripe_unit = ios->layout->stripe_unit;
@@ -400,7 +387,7 @@ static int _prepare_one_group(struct exofs_io_state *ios, u64 length,
        int ret = 0;
 
        while (length) {
-               struct exofs_per_dev_state *per_dev = &ios->per_dev[dev];
+               struct ore_per_dev_state *per_dev = &ios->per_dev[dev];
                unsigned cur_len, page_off = 0;
 
                if (!per_dev->length) {
@@ -443,7 +430,7 @@ out:
        return ret;
 }
 
-static int _prepare_for_striping(struct exofs_io_state *ios)
+static int _prepare_for_striping(struct ore_io_state *ios)
 {
        u64 length = ios->length;
        u64 offset = ios->offset;
@@ -452,9 +439,9 @@ static int _prepare_for_striping(struct exofs_io_state *ios)
 
        if (!ios->pages) {
                if (ios->kern_buff) {
-                       struct exofs_per_dev_state *per_dev = &ios->per_dev[0];
+                       struct ore_per_dev_state *per_dev = &ios->per_dev[0];
 
-                       _calc_stripe_info(ios, ios->offset, &si);
+                       _calc_stripe_info(ios->layout, ios->offset, &si);
                        per_dev->offset = si.obj_offset;
                        per_dev->dev = si.dev;
 
@@ -468,7 +455,7 @@ static int _prepare_for_striping(struct exofs_io_state *ios)
        }
 
        while (length) {
-               _calc_stripe_info(ios, offset, &si);
+               _calc_stripe_info(ios->layout, offset, &si);
 
                if (length < si.group_length)
                        si.group_length = length;
@@ -485,57 +472,59 @@ out:
        return ret;
 }
 
-int exofs_sbi_create(struct exofs_io_state *ios)
+int ore_create(struct ore_io_state *ios)
 {
        int i, ret;
 
-       for (i = 0; i < ios->layout->s_numdevs; i++) {
+       for (i = 0; i < ios->comps->numdevs; i++) {
                struct osd_request *or;
 
-               or = osd_start_request(exofs_ios_od(ios, i), GFP_KERNEL);
+               or = osd_start_request(_ios_od(ios, i), GFP_KERNEL);
                if (unlikely(!or)) {
-                       EXOFS_ERR("%s: osd_start_request failed\n", __func__);
+                       ORE_ERR("%s: osd_start_request failed\n", __func__);
                        ret = -ENOMEM;
                        goto out;
                }
                ios->per_dev[i].or = or;
                ios->numdevs++;
 
-               osd_req_create_object(or, &ios->obj);
+               osd_req_create_object(or, _ios_obj(ios, i));
        }
-       ret = exofs_io_execute(ios);
+       ret = ore_io_execute(ios);
 
 out:
        return ret;
 }
+EXPORT_SYMBOL(ore_create);
 
-int exofs_sbi_remove(struct exofs_io_state *ios)
+int ore_remove(struct ore_io_state *ios)
 {
        int i, ret;
 
-       for (i = 0; i < ios->layout->s_numdevs; i++) {
+       for (i = 0; i < ios->comps->numdevs; i++) {
                struct osd_request *or;
 
-               or = osd_start_request(exofs_ios_od(ios, i), GFP_KERNEL);
+               or = osd_start_request(_ios_od(ios, i), GFP_KERNEL);
                if (unlikely(!or)) {
-                       EXOFS_ERR("%s: osd_start_request failed\n", __func__);
+                       ORE_ERR("%s: osd_start_request failed\n", __func__);
                        ret = -ENOMEM;
                        goto out;
                }
                ios->per_dev[i].or = or;
                ios->numdevs++;
 
-               osd_req_remove_object(or, &ios->obj);
+               osd_req_remove_object(or, _ios_obj(ios, i));
        }
-       ret = exofs_io_execute(ios);
+       ret = ore_io_execute(ios);
 
 out:
        return ret;
 }
+EXPORT_SYMBOL(ore_remove);
 
-static int _sbi_write_mirror(struct exofs_io_state *ios, int cur_comp)
+static int _write_mirror(struct ore_io_state *ios, int cur_comp)
 {
-       struct exofs_per_dev_state *master_dev = &ios->per_dev[cur_comp];
+       struct ore_per_dev_state *master_dev = &ios->per_dev[cur_comp];
        unsigned dev = ios->per_dev[cur_comp].dev;
        unsigned last_comp = cur_comp + ios->layout->mirrors_p1;
        int ret = 0;
@@ -544,12 +533,12 @@ static int _sbi_write_mirror(struct exofs_io_state *ios, int cur_comp)
                return 0; /* Just an empty slot */
 
        for (; cur_comp < last_comp; ++cur_comp, ++dev) {
-               struct exofs_per_dev_state *per_dev = &ios->per_dev[cur_comp];
+               struct ore_per_dev_state *per_dev = &ios->per_dev[cur_comp];
                struct osd_request *or;
 
-               or = osd_start_request(exofs_ios_od(ios, dev), GFP_KERNEL);
+               or = osd_start_request(_ios_od(ios, dev), GFP_KERNEL);
                if (unlikely(!or)) {
-                       EXOFS_ERR("%s: osd_start_request failed\n", __func__);
+                       ORE_ERR("%s: osd_start_request failed\n", __func__);
                        ret = -ENOMEM;
                        goto out;
                }
@@ -563,7 +552,7 @@ static int _sbi_write_mirror(struct exofs_io_state *ios, int cur_comp)
                                bio = bio_kmalloc(GFP_KERNEL,
                                                  master_dev->bio->bi_max_vecs);
                                if (unlikely(!bio)) {
-                                       EXOFS_DBGMSG(
+                                       ORE_DBGMSG(
                                              "Failed to allocate BIO size=%u\n",
                                              master_dev->bio->bi_max_vecs);
                                        ret = -ENOMEM;
@@ -582,25 +571,29 @@ static int _sbi_write_mirror(struct exofs_io_state *ios, int cur_comp)
                                bio->bi_rw |= REQ_WRITE;
                        }
 
-                       osd_req_write(or, &ios->obj, per_dev->offset, bio,
-                                     per_dev->length);
-                       EXOFS_DBGMSG("write(0x%llx) offset=0x%llx "
+                       osd_req_write(or, _ios_obj(ios, dev), per_dev->offset,
+                                     bio, per_dev->length);
+                       ORE_DBGMSG("write(0x%llx) offset=0x%llx "
                                      "length=0x%llx dev=%d\n",
-                                    _LLU(ios->obj.id), _LLU(per_dev->offset),
+                                    _LLU(_ios_obj(ios, dev)->id),
+                                    _LLU(per_dev->offset),
                                     _LLU(per_dev->length), dev);
                } else if (ios->kern_buff) {
-                       ret = osd_req_write_kern(or, &ios->obj, per_dev->offset,
-                                          ios->kern_buff, ios->length);
+                       ret = osd_req_write_kern(or, _ios_obj(ios, dev),
+                                                per_dev->offset,
+                                                ios->kern_buff, ios->length);
                        if (unlikely(ret))
                                goto out;
-                       EXOFS_DBGMSG2("write_kern(0x%llx) offset=0x%llx "
+                       ORE_DBGMSG2("write_kern(0x%llx) offset=0x%llx "
                                      "length=0x%llx dev=%d\n",
-                                    _LLU(ios->obj.id), _LLU(per_dev->offset),
+                                    _LLU(_ios_obj(ios, dev)->id),
+                                    _LLU(per_dev->offset),
                                     _LLU(ios->length), dev);
                } else {
-                       osd_req_set_attributes(or, &ios->obj);
-                       EXOFS_DBGMSG2("obj(0x%llx) set_attributes=%d dev=%d\n",
-                                    _LLU(ios->obj.id), ios->out_attr_len, dev);
+                       osd_req_set_attributes(or, _ios_obj(ios, dev));
+                       ORE_DBGMSG2("obj(0x%llx) set_attributes=%d dev=%d\n",
+                                    _LLU(_ios_obj(ios, dev)->id),
+                                    ios->out_attr_len, dev);
                }
 
                if (ios->out_attr)
@@ -616,7 +609,7 @@ out:
        return ret;
 }
 
-int exofs_sbi_write(struct exofs_io_state *ios)
+int ore_write(struct ore_io_state *ios)
 {
        int i;
        int ret;
@@ -626,52 +619,55 @@ int exofs_sbi_write(struct exofs_io_state *ios)
                return ret;
 
        for (i = 0; i < ios->numdevs; i += ios->layout->mirrors_p1) {
-               ret = _sbi_write_mirror(ios, i);
+               ret = _write_mirror(ios, i);
                if (unlikely(ret))
                        return ret;
        }
 
-       ret = exofs_io_execute(ios);
+       ret = ore_io_execute(ios);
        return ret;
 }
+EXPORT_SYMBOL(ore_write);
 
-static int _sbi_read_mirror(struct exofs_io_state *ios, unsigned cur_comp)
+static int _read_mirror(struct ore_io_state *ios, unsigned cur_comp)
 {
        struct osd_request *or;
-       struct exofs_per_dev_state *per_dev = &ios->per_dev[cur_comp];
-       unsigned first_dev = (unsigned)ios->obj.id;
+       struct ore_per_dev_state *per_dev = &ios->per_dev[cur_comp];
+       struct osd_obj_id *obj = _ios_obj(ios, cur_comp);
+       unsigned first_dev = (unsigned)obj->id;
 
        if (ios->pages && !per_dev->length)
                return 0; /* Just an empty slot */
 
        first_dev = per_dev->dev + first_dev % ios->layout->mirrors_p1;
-       or = osd_start_request(exofs_ios_od(ios, first_dev), GFP_KERNEL);
+       or = osd_start_request(_ios_od(ios, first_dev), GFP_KERNEL);
        if (unlikely(!or)) {
-               EXOFS_ERR("%s: osd_start_request failed\n", __func__);
+               ORE_ERR("%s: osd_start_request failed\n", __func__);
                return -ENOMEM;
        }
        per_dev->or = or;
 
        if (ios->pages) {
-               osd_req_read(or, &ios->obj, per_dev->offset,
+               osd_req_read(or, obj, per_dev->offset,
                                per_dev->bio, per_dev->length);
-               EXOFS_DBGMSG("read(0x%llx) offset=0x%llx length=0x%llx"
-                            " dev=%d\n", _LLU(ios->obj.id),
+               ORE_DBGMSG("read(0x%llx) offset=0x%llx length=0x%llx"
+                            " dev=%d\n", _LLU(obj->id),
                             _LLU(per_dev->offset), _LLU(per_dev->length),
                             first_dev);
        } else if (ios->kern_buff) {
-               int ret = osd_req_read_kern(or, &ios->obj, per_dev->offset,
+               int ret = osd_req_read_kern(or, obj, per_dev->offset,
                                            ios->kern_buff, ios->length);
-               EXOFS_DBGMSG2("read_kern(0x%llx) offset=0x%llx "
+               ORE_DBGMSG2("read_kern(0x%llx) offset=0x%llx "
                              "length=0x%llx dev=%d ret=>%d\n",
-                             _LLU(ios->obj.id), _LLU(per_dev->offset),
+                             _LLU(obj->id), _LLU(per_dev->offset),
                              _LLU(ios->length), first_dev, ret);
                if (unlikely(ret))
                        return ret;
        } else {
-               osd_req_get_attributes(or, &ios->obj);
-               EXOFS_DBGMSG2("obj(0x%llx) get_attributes=%d dev=%d\n",
-                             _LLU(ios->obj.id), ios->in_attr_len, first_dev);
+               osd_req_get_attributes(or, obj);
+               ORE_DBGMSG2("obj(0x%llx) get_attributes=%d dev=%d\n",
+                             _LLU(obj->id),
+                             ios->in_attr_len, first_dev);
        }
        if (ios->out_attr)
                osd_req_add_set_attr_list(or, ios->out_attr, ios->out_attr_len);
@@ -682,7 +678,7 @@ static int _sbi_read_mirror(struct exofs_io_state *ios, unsigned cur_comp)
        return 0;
 }
 
-int exofs_sbi_read(struct exofs_io_state *ios)
+int ore_read(struct ore_io_state *ios)
 {
        int i;
        int ret;
@@ -692,16 +688,17 @@ int exofs_sbi_read(struct exofs_io_state *ios)
                return ret;
 
        for (i = 0; i < ios->numdevs; i += ios->layout->mirrors_p1) {
-               ret = _sbi_read_mirror(ios, i);
+               ret = _read_mirror(ios, i);
                if (unlikely(ret))
                        return ret;
        }
 
-       ret = exofs_io_execute(ios);
+       ret = ore_io_execute(ios);
        return ret;
 }
+EXPORT_SYMBOL(ore_read);
 
-int extract_attr_from_ios(struct exofs_io_state *ios, struct osd_attr *attr)
+int extract_attr_from_ios(struct ore_io_state *ios, struct osd_attr *attr)
 {
        struct osd_attr cur_attr = {.attr_page = 0}; /* start with zeros */
        void *iter = NULL;
@@ -721,83 +718,118 @@ int extract_attr_from_ios(struct exofs_io_state *ios, struct osd_attr *attr)
 
        return -EIO;
 }
+EXPORT_SYMBOL(extract_attr_from_ios);
 
-static int _truncate_mirrors(struct exofs_io_state *ios, unsigned cur_comp,
+static int _truncate_mirrors(struct ore_io_state *ios, unsigned cur_comp,
                             struct osd_attr *attr)
 {
        int last_comp = cur_comp + ios->layout->mirrors_p1;
 
        for (; cur_comp < last_comp; ++cur_comp) {
-               struct exofs_per_dev_state *per_dev = &ios->per_dev[cur_comp];
+               struct ore_per_dev_state *per_dev = &ios->per_dev[cur_comp];
                struct osd_request *or;
 
-               or = osd_start_request(exofs_ios_od(ios, cur_comp), GFP_KERNEL);
+               or = osd_start_request(_ios_od(ios, cur_comp), GFP_KERNEL);
                if (unlikely(!or)) {
-                       EXOFS_ERR("%s: osd_start_request failed\n", __func__);
+                       ORE_ERR("%s: osd_start_request failed\n", __func__);
                        return -ENOMEM;
                }
                per_dev->or = or;
 
-               osd_req_set_attributes(or, &ios->obj);
+               osd_req_set_attributes(or, _ios_obj(ios, cur_comp));
                osd_req_add_set_attr_list(or, attr, 1);
        }
 
        return 0;
 }
 
-int exofs_oi_truncate(struct exofs_i_info *oi, u64 size)
+struct _trunc_info {
+       struct _striping_info si;
+       u64 prev_group_obj_off;
+       u64 next_group_obj_off;
+
+       unsigned first_group_dev;
+       unsigned nex_group_dev;
+       unsigned max_devs;
+};
+
+void _calc_trunk_info(struct ore_layout *layout, u64 file_offset,
+                      struct _trunc_info *ti)
+{
+       unsigned stripe_unit = layout->stripe_unit;
+
+       _calc_stripe_info(layout, file_offset, &ti->si);
+
+       ti->prev_group_obj_off = ti->si.M * stripe_unit;
+       ti->next_group_obj_off = ti->si.M ? (ti->si.M - 1) * stripe_unit : 0;
+
+       ti->first_group_dev = ti->si.dev - (ti->si.dev % layout->group_width);
+       ti->nex_group_dev = ti->first_group_dev + layout->group_width;
+       ti->max_devs = layout->group_width * layout->group_count;
+}
+
+int ore_truncate(struct ore_layout *layout, struct ore_components *comps,
+                  u64 size)
 {
-       struct exofs_sb_info *sbi = oi->vfs_inode.i_sb->s_fs_info;
-       struct exofs_io_state *ios;
+       struct ore_io_state *ios;
        struct exofs_trunc_attr {
                struct osd_attr attr;
                __be64 newsize;
        } *size_attrs;
-       struct _striping_info si;
+       struct _trunc_info ti;
        int i, ret;
 
-       ret = exofs_get_io_state(&sbi->layout, &ios);
+       ret = ore_get_io_state(layout, comps, &ios);
        if (unlikely(ret))
                return ret;
 
-       size_attrs = kcalloc(ios->layout->group_width, sizeof(*size_attrs),
+       _calc_trunk_info(ios->layout, size, &ti);
+
+       size_attrs = kcalloc(ti.max_devs, sizeof(*size_attrs),
                             GFP_KERNEL);
        if (unlikely(!size_attrs)) {
                ret = -ENOMEM;
                goto out;
        }
 
-       ios->obj.id = exofs_oi_objno(oi);
-       ios->cred = oi->i_cred;
+       ios->numdevs = ios->comps->numdevs;
 
-       ios->numdevs = ios->layout->s_numdevs;
-       _calc_stripe_info(ios, size, &si);
-
-       for (i = 0; i < ios->layout->group_width; ++i) {
+       for (i = 0; i < ti.max_devs; ++i) {
                struct exofs_trunc_attr *size_attr = &size_attrs[i];
                u64 obj_size;
 
-               if (i < si.dev)
-                       obj_size = si.obj_offset +
-                                       ios->layout->stripe_unit - si.unit_off;
-               else if (i == si.dev)
-                       obj_size = si.obj_offset;
-               else /* i > si.dev */
-                       obj_size = si.obj_offset - si.unit_off;
+               if (i < ti.first_group_dev)
+                       obj_size = ti.prev_group_obj_off;
+               else if (i >= ti.nex_group_dev)
+                       obj_size = ti.next_group_obj_off;
+               else if (i < ti.si.dev) /* dev within this group */
+                       obj_size = ti.si.obj_offset +
+                                     ios->layout->stripe_unit - ti.si.unit_off;
+               else if (i == ti.si.dev)
+                       obj_size = ti.si.obj_offset;
+               else /* i > ti.dev */
+                       obj_size = ti.si.obj_offset - ti.si.unit_off;
 
                size_attr->newsize = cpu_to_be64(obj_size);
                size_attr->attr = g_attr_logical_length;
                size_attr->attr.val_ptr = &size_attr->newsize;
 
+               ORE_DBGMSG("trunc(0x%llx) obj_offset=0x%llx dev=%d\n",
+                            _LLU(comps->comps->obj.id), _LLU(obj_size), i);
                ret = _truncate_mirrors(ios, i * ios->layout->mirrors_p1,
                                        &size_attr->attr);
                if (unlikely(ret))
                        goto out;
        }
-       ret = exofs_io_execute(ios);
+       ret = ore_io_execute(ios);
 
 out:
        kfree(size_attrs);
-       exofs_put_io_state(ios);
+       ore_put_io_state(ios);
        return ret;
 }
+EXPORT_SYMBOL(ore_truncate);
+
+const struct osd_attr g_attr_logical_length = ATTR_DEF(
+       OSD_APAGE_OBJECT_INFORMATION, OSD_ATTR_OI_LOGICAL_LENGTH, 8);
+EXPORT_SYMBOL(g_attr_logical_length);
diff --git a/fs/exofs/pnfs.h b/fs/exofs/pnfs.h
deleted file mode 100644 (file)
index c52e988..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2008, 2009
- * Boaz Harrosh <bharrosh@panasas.com>
- *
- * This file is part of exofs.
- *
- * exofs 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.
- *
- */
-
-/* FIXME: Remove this file once pnfs hits mainline */
-
-#ifndef __EXOFS_PNFS_H__
-#define __EXOFS_PNFS_H__
-
-#if ! defined(__PNFS_OSD_XDR_H__)
-
-enum pnfs_iomode {
-       IOMODE_READ = 1,
-       IOMODE_RW = 2,
-       IOMODE_ANY = 3,
-};
-
-/* Layout Structure */
-enum pnfs_osd_raid_algorithm4 {
-       PNFS_OSD_RAID_0         = 1,
-       PNFS_OSD_RAID_4         = 2,
-       PNFS_OSD_RAID_5         = 3,
-       PNFS_OSD_RAID_PQ        = 4     /* Reed-Solomon P+Q */
-};
-
-struct pnfs_osd_data_map {
-       u32     odm_num_comps;
-       u64     odm_stripe_unit;
-       u32     odm_group_width;
-       u32     odm_group_depth;
-       u32     odm_mirror_cnt;
-       u32     odm_raid_algorithm;
-};
-
-#endif /* ! defined(__PNFS_OSD_XDR_H__) */
-
-#endif /* __EXOFS_PNFS_H__ */
index c57bedd..2748940 100644 (file)
@@ -40,6 +40,8 @@
 
 #include "exofs.h"
 
+#define EXOFS_DBGMSG2(M...) do {} while (0)
+
 /******************************************************************************
  * MOUNT OPTIONS
  *****************************************************************************/
@@ -208,10 +210,48 @@ static void destroy_inodecache(void)
 }
 
 /******************************************************************************
- * SUPERBLOCK FUNCTIONS
+ * Some osd helpers
  *****************************************************************************/
-static const struct super_operations exofs_sops;
-static const struct export_operations exofs_export_ops;
+void exofs_make_credential(u8 cred_a[OSD_CAP_LEN], const struct osd_obj_id *obj)
+{
+       osd_sec_init_nosec_doall_caps(cred_a, obj, false, true);
+}
+
+static int exofs_read_kern(struct osd_dev *od, u8 *cred, struct osd_obj_id *obj,
+                   u64 offset, void *p, unsigned length)
+{
+       struct osd_request *or = osd_start_request(od, GFP_KERNEL);
+/*     struct osd_sense_info osi = {.key = 0};*/
+       int ret;
+
+       if (unlikely(!or)) {
+               EXOFS_DBGMSG("%s: osd_start_request failed.\n", __func__);
+               return -ENOMEM;
+       }
+       ret = osd_req_read_kern(or, obj, offset, p, length);
+       if (unlikely(ret)) {
+               EXOFS_DBGMSG("%s: osd_req_read_kern failed.\n", __func__);
+               goto out;
+       }
+
+       ret = osd_finalize_request(or, 0, cred, NULL);
+       if (unlikely(ret)) {
+               EXOFS_DBGMSG("Failed to osd_finalize_request() => %d\n", ret);
+               goto out;
+       }
+
+       ret = osd_execute_request(or);
+       if (unlikely(ret))
+               EXOFS_DBGMSG("osd_execute_request() => %d\n", ret);
+       /* osd_req_decode_sense(or, ret); */
+
+out:
+       osd_end_request(or);
+       EXOFS_DBGMSG2("read_kern(0x%llx) offset=0x%llx "
+                     "length=0x%llx dev=%p ret=>%d\n",
+                     _LLU(obj->id), _LLU(offset), _LLU(length), od, ret);
+       return ret;
+}
 
 static const struct osd_attr g_attr_sb_stats = ATTR_DEF(
        EXOFS_APAGE_SB_DATA,
@@ -223,21 +263,19 @@ static int __sbi_read_stats(struct exofs_sb_info *sbi)
        struct osd_attr attrs[] = {
                [0] = g_attr_sb_stats,
        };
-       struct exofs_io_state *ios;
+       struct ore_io_state *ios;
        int ret;
 
-       ret = exofs_get_io_state(&sbi->layout, &ios);
+       ret = ore_get_io_state(&sbi->layout, &sbi->comps, &ios);
        if (unlikely(ret)) {
-               EXOFS_ERR("%s: exofs_get_io_state failed.\n", __func__);
+               EXOFS_ERR("%s: ore_get_io_state failed.\n", __func__);
                return ret;
        }
 
-       ios->cred = sbi->s_cred;
-
        ios->in_attr = attrs;
        ios->in_attr_len = ARRAY_SIZE(attrs);
 
-       ret = exofs_sbi_read(ios);
+       ret = ore_read(ios);
        if (unlikely(ret)) {
                EXOFS_ERR("Error reading super_block stats => %d\n", ret);
                goto out;
@@ -264,13 +302,13 @@ static int __sbi_read_stats(struct exofs_sb_info *sbi)
        }
 
 out:
-       exofs_put_io_state(ios);
+       ore_put_io_state(ios);
        return ret;
 }
 
-static void stats_done(struct exofs_io_state *ios, void *p)
+static void stats_done(struct ore_io_state *ios, void *p)
 {
-       exofs_put_io_state(ios);
+       ore_put_io_state(ios);
        /* Good thanks nothing to do anymore */
 }
 
@@ -280,12 +318,12 @@ int exofs_sbi_write_stats(struct exofs_sb_info *sbi)
        struct osd_attr attrs[] = {
                [0] = g_attr_sb_stats,
        };
-       struct exofs_io_state *ios;
+       struct ore_io_state *ios;
        int ret;
 
-       ret = exofs_get_io_state(&sbi->layout, &ios);
+       ret = ore_get_io_state(&sbi->layout, &sbi->comps, &ios);
        if (unlikely(ret)) {
-               EXOFS_ERR("%s: exofs_get_io_state failed.\n", __func__);
+               EXOFS_ERR("%s: ore_get_io_state failed.\n", __func__);
                return ret;
        }
 
@@ -293,21 +331,27 @@ int exofs_sbi_write_stats(struct exofs_sb_info *sbi)
        sbi->s_ess.s_numfiles = cpu_to_le64(sbi->s_numfiles);
        attrs[0].val_ptr = &sbi->s_ess;
 
-       ios->cred = sbi->s_cred;
+
        ios->done = stats_done;
        ios->private = sbi;
        ios->out_attr = attrs;
        ios->out_attr_len = ARRAY_SIZE(attrs);
 
-       ret = exofs_sbi_write(ios);
+       ret = ore_write(ios);
        if (unlikely(ret)) {
-               EXOFS_ERR("%s: exofs_sbi_write failed.\n", __func__);
-               exofs_put_io_state(ios);
+               EXOFS_ERR("%s: ore_write failed.\n", __func__);
+               ore_put_io_state(ios);
        }
 
        return ret;
 }
 
+/******************************************************************************
+ * SUPERBLOCK FUNCTIONS
+ *****************************************************************************/
+static const struct super_operations exofs_sops;
+static const struct export_operations exofs_export_ops;
+
 /*
  * Write the superblock to the OSD
  */
@@ -315,7 +359,9 @@ int exofs_sync_fs(struct super_block *sb, int wait)
 {
        struct exofs_sb_info *sbi;
        struct exofs_fscb *fscb;
-       struct exofs_io_state *ios;
+       struct ore_comp one_comp;
+       struct ore_components comps;
+       struct ore_io_state *ios;
        int ret = -ENOMEM;
 
        fscb = kmalloc(sizeof(*fscb), GFP_KERNEL);
@@ -331,7 +377,10 @@ int exofs_sync_fs(struct super_block *sb, int wait)
         * version). Otherwise the exofs_fscb is read-only from mkfs time. All
         * the writeable info is set in exofs_sbi_write_stats() above.
         */
-       ret = exofs_get_io_state(&sbi->layout, &ios);
+
+       exofs_init_comps(&comps, &one_comp, sbi, EXOFS_SUPER_ID);
+
+       ret = ore_get_io_state(&sbi->layout, &comps, &ios);
        if (unlikely(ret))
                goto out;
 
@@ -345,14 +394,12 @@ int exofs_sync_fs(struct super_block *sb, int wait)
        fscb->s_newfs = 0;
        fscb->s_version = EXOFS_FSCB_VER;
 
-       ios->obj.id = EXOFS_SUPER_ID;
        ios->offset = 0;
        ios->kern_buff = fscb;
-       ios->cred = sbi->s_cred;
 
-       ret = exofs_sbi_write(ios);
+       ret = ore_write(ios);
        if (unlikely(ret))
-               EXOFS_ERR("%s: exofs_sbi_write failed.\n", __func__);
+               EXOFS_ERR("%s: ore_write failed.\n", __func__);
        else
                sb->s_dirt = 0;
 
@@ -360,7 +407,7 @@ int exofs_sync_fs(struct super_block *sb, int wait)
        unlock_super(sb);
 out:
        EXOFS_DBGMSG("s_nextid=0x%llx ret=%d\n", _LLU(sbi->s_nextid), ret);
-       exofs_put_io_state(ios);
+       ore_put_io_state(ios);
        kfree(fscb);
        return ret;
 }
@@ -384,15 +431,17 @@ static void _exofs_print_device(const char *msg, const char *dev_path,
 
 void exofs_free_sbi(struct exofs_sb_info *sbi)
 {
-       while (sbi->layout.s_numdevs) {
-               int i = --sbi->layout.s_numdevs;
-               struct osd_dev *od = sbi->layout.s_ods[i];
+       while (sbi->comps.numdevs) {
+               int i = --sbi->comps.numdevs;
+               struct osd_dev *od = sbi->comps.ods[i];
 
                if (od) {
-                       sbi->layout.s_ods[i] = NULL;
+                       sbi->comps.ods[i] = NULL;
                        osduld_put_device(od);
                }
        }
+       if (sbi->comps.ods != sbi->_min_one_dev)
+               kfree(sbi->comps.ods);
        kfree(sbi);
 }
 
@@ -419,8 +468,8 @@ static void exofs_put_super(struct super_block *sb)
                                  msecs_to_jiffies(100));
        }
 
-       _exofs_print_device("Unmounting", NULL, sbi->layout.s_ods[0],
-                           sbi->layout.s_pid);
+       _exofs_print_device("Unmounting", NULL, sbi->comps.ods[0],
+                           sbi->one_comp.obj.partition);
 
        bdi_destroy(&sbi->bdi);
        exofs_free_sbi(sbi);
@@ -501,10 +550,19 @@ static int _read_and_match_data_map(struct exofs_sb_info *sbi, unsigned numdevs,
                return -EINVAL;
        }
 
+       EXOFS_DBGMSG("exofs: layout: "
+               "num_comps=%u stripe_unit=0x%x group_width=%u "
+               "group_depth=0x%llx mirrors_p1=%u raid_algorithm=%u\n",
+               numdevs,
+               sbi->layout.stripe_unit,
+               sbi->layout.group_width,
+               _LLU(sbi->layout.group_depth),
+               sbi->layout.mirrors_p1,
+               sbi->data_map.odm_raid_algorithm);
        return 0;
 }
 
-static unsigned __ra_pages(struct exofs_layout *layout)
+static unsigned __ra_pages(struct ore_layout *layout)
 {
        const unsigned _MIN_RA = 32; /* min 128K read-ahead */
        unsigned ra_pages = layout->group_width * layout->stripe_unit /
@@ -547,13 +605,11 @@ static int exofs_devs_2_odi(struct exofs_dt_device_info *dt_dev,
        return !(odi->systemid_len || odi->osdname_len);
 }
 
-static int exofs_read_lookup_dev_table(struct exofs_sb_info **psbi,
+static int exofs_read_lookup_dev_table(struct exofs_sb_info *sbi,
+                                      struct osd_dev *fscb_od,
                                       unsigned table_count)
 {
-       struct exofs_sb_info *sbi = *psbi;
-       struct osd_dev *fscb_od;
-       struct osd_obj_id obj = {.partition = sbi->layout.s_pid,
-                                .id = EXOFS_DEVTABLE_ID};
+       struct ore_comp comp;
        struct exofs_device_table *dt;
        unsigned table_bytes = table_count * sizeof(dt->dt_dev_table[0]) +
                                             sizeof(*dt);
@@ -567,10 +623,14 @@ static int exofs_read_lookup_dev_table(struct exofs_sb_info **psbi,
                return -ENOMEM;
        }
 
-       fscb_od = sbi->layout.s_ods[0];
-       sbi->layout.s_ods[0] = NULL;
-       sbi->layout.s_numdevs = 0;
-       ret = exofs_read_kern(fscb_od, sbi->s_cred, &obj, 0, dt, table_bytes);
+       sbi->comps.numdevs = 0;
+
+       comp.obj.partition = sbi->one_comp.obj.partition;
+       comp.obj.id = EXOFS_DEVTABLE_ID;
+       exofs_make_credential(comp.cred, &comp.obj);
+
+       ret = exofs_read_kern(fscb_od, comp.cred, &comp.obj, 0, dt,
+                             table_bytes);
        if (unlikely(ret)) {
                EXOFS_ERR("ERROR: reading device table\n");
                goto out;
@@ -588,16 +648,18 @@ static int exofs_read_lookup_dev_table(struct exofs_sb_info **psbi,
                goto out;
 
        if (likely(numdevs > 1)) {
-               unsigned size = numdevs * sizeof(sbi->layout.s_ods[0]);
+               unsigned size = numdevs * sizeof(sbi->comps.ods[0]);
 
-               sbi = krealloc(sbi, sizeof(*sbi) + size, GFP_KERNEL);
-               if (unlikely(!sbi)) {
+               /* Twice bigger table: See exofs_init_comps() and below
+                * comment
+                */
+               sbi->comps.ods = kzalloc(size + size - 1, GFP_KERNEL);
+               if (unlikely(!sbi->comps.ods)) {
+                       EXOFS_ERR("ERROR: faild allocating Device array[%d]\n",
+                                 numdevs);
                        ret = -ENOMEM;
                        goto out;
                }
-               memset(&sbi->layout.s_ods[1], 0,
-                      size - sizeof(sbi->layout.s_ods[0]));
-               *psbi = sbi;
        }
 
        for (i = 0; i < numdevs; i++) {
@@ -619,8 +681,8 @@ static int exofs_read_lookup_dev_table(struct exofs_sb_info **psbi,
                 * line. We always keep them in device-table order.
                 */
                if (fscb_od && osduld_device_same(fscb_od, &odi)) {
-                       sbi->layout.s_ods[i] = fscb_od;
-                       ++sbi->layout.s_numdevs;
+                       sbi->comps.ods[i] = fscb_od;
+                       ++sbi->comps.numdevs;
                        fscb_od = NULL;
                        continue;
                }
@@ -633,13 +695,13 @@ static int exofs_read_lookup_dev_table(struct exofs_sb_info **psbi,
                        goto out;
                }
 
-               sbi->layout.s_ods[i] = od;
-               ++sbi->layout.s_numdevs;
+               sbi->comps.ods[i] = od;
+               ++sbi->comps.numdevs;
 
                /* Read the fscb of the other devices to make sure the FS
                 * partition is there.
                 */
-               ret = exofs_read_kern(od, sbi->s_cred, &obj, 0, &fscb,
+               ret = exofs_read_kern(od, comp.cred, &comp.obj, 0, &fscb,
                                      sizeof(fscb));
                if (unlikely(ret)) {
                        EXOFS_ERR("ERROR: Malformed participating device "
@@ -656,13 +718,22 @@ static int exofs_read_lookup_dev_table(struct exofs_sb_info **psbi,
 
 out:
        kfree(dt);
-       if (unlikely(!ret && fscb_od)) {
-               EXOFS_ERR(
-                     "ERROR: Bad device-table container device not present\n");
-               osduld_put_device(fscb_od);
-               ret = -EINVAL;
-       }
+       if (likely(!ret)) {
+               unsigned numdevs = sbi->comps.numdevs;
 
+               if (unlikely(fscb_od)) {
+                       EXOFS_ERR("ERROR: Bad device-table container device not present\n");
+                       osduld_put_device(fscb_od);
+                       return -EINVAL;
+               }
+               /* exofs round-robins the device table view according to inode
+                * number. We hold a: twice bigger table hence inodes can point
+                * to any device and have a sequential view of the table
+                * starting at this device. See exofs_init_comps()
+                */
+               for (i = 0; i < numdevs - 1; ++i)
+                       sbi->comps.ods[i + numdevs] = sbi->comps.ods[i];
+       }
        return ret;
 }
 
@@ -676,7 +747,7 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent)
        struct exofs_sb_info *sbi;      /*extended info                  */
        struct osd_dev *od;             /* Master device                 */
        struct exofs_fscb fscb;         /*on-disk superblock info        */
-       struct osd_obj_id obj;
+       struct ore_comp comp;
        unsigned table_count;
        int ret;
 
@@ -684,10 +755,6 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent)
        if (!sbi)
                return -ENOMEM;
 
-       ret = bdi_setup_and_register(&sbi->bdi, "exofs", BDI_CAP_MAP_COPY);
-       if (ret)
-               goto free_bdi;
-
        /* use mount options to fill superblock */
        if (opts->is_osdname) {
                struct osd_dev_info odi = {.systemid_len = 0};
@@ -695,6 +762,8 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent)
                odi.osdname_len = strlen(opts->dev_name);
                odi.osdname = (u8 *)opts->dev_name;
                od = osduld_info_lookup(&odi);
+               kfree(opts->dev_name);
+               opts->dev_name = NULL;
        } else {
                od = osduld_path_lookup(opts->dev_name);
        }
@@ -709,11 +778,16 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent)
        sbi->layout.group_width = 1;
        sbi->layout.group_depth = -1;
        sbi->layout.group_count = 1;
-       sbi->layout.s_ods[0] = od;
-       sbi->layout.s_numdevs = 1;
-       sbi->layout.s_pid = opts->pid;
        sbi->s_timeout = opts->timeout;
 
+       sbi->one_comp.obj.partition = opts->pid;
+       sbi->one_comp.obj.id = 0;
+       exofs_make_credential(sbi->one_comp.cred, &sbi->one_comp.obj);
+       sbi->comps.numdevs = 1;
+       sbi->comps.single_comp = EC_SINGLE_COMP;
+       sbi->comps.comps = &sbi->one_comp;
+       sbi->comps.ods = sbi->_min_one_dev;
+
        /* fill in some other data by hand */
        memset(sb->s_id, 0, sizeof(sb->s_id));
        strcpy(sb->s_id, "exofs");
@@ -724,11 +798,11 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_bdev = NULL;
        sb->s_dev = 0;
 
-       obj.partition = sbi->layout.s_pid;
-       obj.id = EXOFS_SUPER_ID;
-       exofs_make_credential(sbi->s_cred, &obj);
+       comp.obj.partition = sbi->one_comp.obj.partition;
+       comp.obj.id = EXOFS_SUPER_ID;
+       exofs_make_credential(comp.cred, &comp.obj);
 
-       ret = exofs_read_kern(od, sbi->s_cred, &obj, 0, &fscb, sizeof(fscb));
+       ret = exofs_read_kern(od, comp.cred, &comp.obj, 0, &fscb, sizeof(fscb));
        if (unlikely(ret))
                goto free_sbi;
 
@@ -757,9 +831,11 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent)
 
        table_count = le64_to_cpu(fscb.s_dev_table_count);
        if (table_count) {
-               ret = exofs_read_lookup_dev_table(&sbi, table_count);
+               ret = exofs_read_lookup_dev_table(sbi, od, table_count);
                if (unlikely(ret))
                        goto free_sbi;
+       } else {
+               sbi->comps.ods[0] = od;
        }
 
        __sbi_read_stats(sbi);
@@ -793,20 +869,20 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent)
                goto free_sbi;
        }
 
-       _exofs_print_device("Mounting", opts->dev_name, sbi->layout.s_ods[0],
-                           sbi->layout.s_pid);
-       if (opts->is_osdname)
-               kfree(opts->dev_name);
+       ret = bdi_setup_and_register(&sbi->bdi, "exofs", BDI_CAP_MAP_COPY);
+       if (ret) {
+               EXOFS_DBGMSG("Failed to bdi_setup_and_register\n");
+               goto free_sbi;
+       }
+
+       _exofs_print_device("Mounting", opts->dev_name, sbi->comps.ods[0],
+                           sbi->one_comp.obj.partition);
        return 0;
 
 free_sbi:
-       bdi_destroy(&sbi->bdi);
-free_bdi:
        EXOFS_ERR("Unable to mount exofs on %s pid=0x%llx err=%d\n",
-                 opts->dev_name, sbi->layout.s_pid, ret);
+                 opts->dev_name, sbi->one_comp.obj.partition, ret);
        exofs_free_sbi(sbi);
-       if (opts->is_osdname)
-               kfree(opts->dev_name);
        return ret;
 }
 
@@ -837,7 +913,7 @@ static int exofs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
        struct exofs_sb_info *sbi = sb->s_fs_info;
-       struct exofs_io_state *ios;
+       struct ore_io_state *ios;
        struct osd_attr attrs[] = {
                ATTR_DEF(OSD_APAGE_PARTITION_QUOTAS,
                        OSD_ATTR_PQ_CAPACITY_QUOTA, sizeof(__be64)),
@@ -846,21 +922,18 @@ static int exofs_statfs(struct dentry *dentry, struct kstatfs *buf)
        };
        uint64_t capacity = ULLONG_MAX;
        uint64_t used = ULLONG_MAX;
-       uint8_t cred_a[OSD_CAP_LEN];
        int ret;
 
-       ret = exofs_get_io_state(&sbi->layout, &ios);
+       ret = ore_get_io_state(&sbi->layout, &sbi->comps, &ios);
        if (ret) {
-               EXOFS_DBGMSG("exofs_get_io_state failed.\n");
+               EXOFS_DBGMSG("ore_get_io_state failed.\n");
                return ret;
        }
 
-       exofs_make_credential(cred_a, &ios->obj);
-       ios->cred = sbi->s_cred;
        ios->in_attr = attrs;
        ios->in_attr_len = ARRAY_SIZE(attrs);
 
-       ret = exofs_sbi_read(ios);
+       ret = ore_read(ios);
        if (unlikely(ret))
                goto out;
 
@@ -889,7 +962,7 @@ static int exofs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_namelen = EXOFS_NAME_LEN;
 
 out:
-       exofs_put_io_state(ios);
+       ore_put_io_state(ios);
        return ret;
 }
 
index 52c0537..35d6a3c 100644 (file)
@@ -194,12 +194,10 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
                case ACL_TYPE_ACCESS:
                        name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
                        if (acl) {
-                               mode_t mode = inode->i_mode;
-                               error = posix_acl_equiv_mode(acl, &mode);
+                               error = posix_acl_equiv_mode(acl, &inode->i_mode);
                                if (error < 0)
                                        return error;
                                else {
-                                       inode->i_mode = mode;
                                        inode->i_ctime = CURRENT_TIME_SEC;
                                        mark_inode_dirty(inode);
                                        if (error == 0)
@@ -253,16 +251,14 @@ ext2_init_acl(struct inode *inode, struct inode *dir)
                        inode->i_mode &= ~current_umask();
        }
        if (test_opt(inode->i_sb, POSIX_ACL) && acl) {
-               mode_t mode = inode->i_mode;
                if (S_ISDIR(inode->i_mode)) {
                        error = ext2_set_acl(inode, ACL_TYPE_DEFAULT, acl);
                        if (error)
                                goto cleanup;
                }
-               error = posix_acl_create(&acl, GFP_KERNEL, &mode);
+               error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode);
                if (error < 0)
                        return error;
-               inode->i_mode = mode;
                if (error > 0) {
                        /* This is an extended ACL */
                        error = ext2_set_acl(inode, ACL_TYPE_ACCESS, acl);
index 5c0a6a4..503bfb0 100644 (file)
@@ -61,7 +61,6 @@ extern int ext2_init_acl (struct inode *, struct inode *);
 #else
 #include <linux/sched.h>
 #define ext2_get_acl   NULL
-#define ext2_get_acl   NULL
 #define ext2_set_acl   NULL
 
 static inline int
index 6c29bf0..3091f62 100644 (file)
@@ -199,12 +199,10 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type,
                case ACL_TYPE_ACCESS:
                        name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS;
                        if (acl) {
-                               mode_t mode = inode->i_mode;
-                               error = posix_acl_equiv_mode(acl, &mode);
+                               error = posix_acl_equiv_mode(acl, &inode->i_mode);
                                if (error < 0)
                                        return error;
                                else {
-                                       inode->i_mode = mode;
                                        inode->i_ctime = CURRENT_TIME_SEC;
                                        ext3_mark_inode_dirty(handle, inode);
                                        if (error == 0)
@@ -261,19 +259,16 @@ ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
                        inode->i_mode &= ~current_umask();
        }
        if (test_opt(inode->i_sb, POSIX_ACL) && acl) {
-               mode_t mode = inode->i_mode;
-
                if (S_ISDIR(inode->i_mode)) {
                        error = ext3_set_acl(handle, inode,
                                             ACL_TYPE_DEFAULT, acl);
                        if (error)
                                goto cleanup;
                }
-               error = posix_acl_create(&acl, GFP_NOFS, &mode);
+               error = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
                if (error < 0)
                        return error;
 
-               inode->i_mode = mode;
                if (error > 0) {
                        /* This is an extended ACL */
                        error = ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, acl);
index 6e18a0b..5571708 100644 (file)
@@ -2209,9 +2209,11 @@ static int ext3_symlink (struct inode * dir,
                /*
                 * For non-fast symlinks, we just allocate inode and put it on
                 * orphan list in the first transaction => we need bitmap,
-                * group descriptor, sb, inode block, quota blocks.
+                * group descriptor, sb, inode block, quota blocks, and
+                * possibly selinux xattr blocks.
                 */
-               credits = 4 + EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb);
+               credits = 4 + EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb) +
+                         EXT3_XATTR_TRANS_BLOCKS;
        } else {
                /*
                 * Fast symlink. We have to add entry to directory
index 0410946..56fd8f8 100644 (file)
@@ -7,7 +7,7 @@ obj-$(CONFIG_EXT4_FS) += ext4.o
 ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o page-io.o \
                ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o \
                ext4_jbd2.o migrate.o mballoc.o block_validity.o move_extent.o \
-               mmp.o
+               mmp.o indirect.o
 
 ext4-$(CONFIG_EXT4_FS_XATTR)           += xattr.o xattr_user.o xattr_trusted.o
 ext4-$(CONFIG_EXT4_FS_POSIX_ACL)       += acl.o
index dca2d1d..a5c29bb 100644 (file)
@@ -198,12 +198,10 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type,
        case ACL_TYPE_ACCESS:
                name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
                if (acl) {
-                       mode_t mode = inode->i_mode;
-                       error = posix_acl_equiv_mode(acl, &mode);
+                       error = posix_acl_equiv_mode(acl, &inode->i_mode);
                        if (error < 0)
                                return error;
                        else {
-                               inode->i_mode = mode;
                                inode->i_ctime = ext4_current_time(inode);
                                ext4_mark_inode_dirty(handle, inode);
                                if (error == 0)
@@ -259,19 +257,16 @@ ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
                        inode->i_mode &= ~current_umask();
        }
        if (test_opt(inode->i_sb, POSIX_ACL) && acl) {
-               mode_t mode = inode->i_mode;
-
                if (S_ISDIR(inode->i_mode)) {
                        error = ext4_set_acl(handle, inode,
                                             ACL_TYPE_DEFAULT, acl);
                        if (error)
                                goto cleanup;
                }
-               error = posix_acl_create(&acl, GFP_NOFS, &mode);
+               error = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
                if (error < 0)
                        return error;
 
-               inode->i_mode = mode;
                if (error > 0) {
                        /* This is an extended ACL */
                        error = ext4_set_acl(handle, inode, ACL_TYPE_ACCESS, acl);
index 264f694..f8224ad 100644 (file)
@@ -620,3 +620,51 @@ unsigned long ext4_bg_num_gdb(struct super_block *sb, ext4_group_t group)
 
 }
 
+/**
+ *     ext4_inode_to_goal_block - return a hint for block allocation
+ *     @inode: inode for block allocation
+ *
+ *     Return the ideal location to start allocating blocks for a
+ *     newly created inode.
+ */
+ext4_fsblk_t ext4_inode_to_goal_block(struct inode *inode)
+{
+       struct ext4_inode_info *ei = EXT4_I(inode);
+       ext4_group_t block_group;
+       ext4_grpblk_t colour;
+       int flex_size = ext4_flex_bg_size(EXT4_SB(inode->i_sb));
+       ext4_fsblk_t bg_start;
+       ext4_fsblk_t last_block;
+
+       block_group = ei->i_block_group;
+       if (flex_size >= EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME) {
+               /*
+                * If there are at least EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME
+                * block groups per flexgroup, reserve the first block
+                * group for directories and special files.  Regular
+                * files will start at the second block group.  This
+                * tends to speed up directory access and improves
+                * fsck times.
+                */
+               block_group &= ~(flex_size-1);
+               if (S_ISREG(inode->i_mode))
+                       block_group++;
+       }
+       bg_start = ext4_group_first_block_no(inode->i_sb, block_group);
+       last_block = ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es) - 1;
+
+       /*
+        * If we are doing delayed allocation, we don't need take
+        * colour into account.
+        */
+       if (test_opt(inode->i_sb, DELALLOC))
+               return bg_start;
+
+       if (bg_start + EXT4_BLOCKS_PER_GROUP(inode->i_sb) <= last_block)
+               colour = (current->pid % 16) *
+                       (EXT4_BLOCKS_PER_GROUP(inode->i_sb) / 16);
+       else
+               colour = (current->pid % 16) * ((last_block - bg_start) / 16);
+       return bg_start + colour;
+}
+
index fac90f3..8efb2f0 100644 (file)
@@ -246,3 +246,24 @@ int ext4_data_block_valid(struct ext4_sb_info *sbi, ext4_fsblk_t start_blk,
        return 1;
 }
 
+int ext4_check_blockref(const char *function, unsigned int line,
+                       struct inode *inode, __le32 *p, unsigned int max)
+{
+       struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
+       __le32 *bref = p;
+       unsigned int blk;
+
+       while (bref < p+max) {
+               blk = le32_to_cpu(*bref++);
+               if (blk &&
+                   unlikely(!ext4_data_block_valid(EXT4_SB(inode->i_sb),
+                                                   blk, 1))) {
+                       es->s_last_error_block = cpu_to_le64(blk);
+                       ext4_error_inode(inode, function, line, blk,
+                                        "invalid block");
+                       return -EIO;
+               }
+       }
+       return 0;
+}
+
index fa44df8..e717dfd 100644 (file)
@@ -526,6 +526,7 @@ struct ext4_new_group_data {
 #define EXT4_FREE_BLOCKS_METADATA      0x0001
 #define EXT4_FREE_BLOCKS_FORGET                0x0002
 #define EXT4_FREE_BLOCKS_VALIDATED     0x0004
+#define EXT4_FREE_BLOCKS_NO_QUOT_UPDATE        0x0008
 
 /*
  * ioctl commands
@@ -939,6 +940,8 @@ struct ext4_inode_info {
 #define ext4_find_next_zero_bit                find_next_zero_bit_le
 #define ext4_find_next_bit             find_next_bit_le
 
+extern void ext4_set_bits(void *bm, int cur, int len);
+
 /*
  * Maximal mount counts between two filesystem checks
  */
@@ -1126,7 +1129,8 @@ struct ext4_sb_info {
        struct journal_s *s_journal;
        struct list_head s_orphan;
        struct mutex s_orphan_lock;
-       struct mutex s_resize_lock;
+       unsigned long s_resize_flags;           /* Flags indicating if there
+                                                  is a resizer */
        unsigned long s_commit_interval;
        u32 s_max_batch_time;
        u32 s_min_batch_time;
@@ -1214,6 +1218,9 @@ struct ext4_sb_info {
 
        /* Kernel thread for multiple mount protection */
        struct task_struct *s_mmp_tsk;
+
+       /* record the last minlen when FITRIM is called. */
+       atomic_t s_last_trim_minblks;
 };
 
 static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb)
@@ -1743,6 +1750,7 @@ extern unsigned ext4_init_block_bitmap(struct super_block *sb,
                                       struct ext4_group_desc *desc);
 #define ext4_free_blocks_after_init(sb, group, desc)                   \
                ext4_init_block_bitmap(sb, NULL, group, desc)
+ext4_fsblk_t ext4_inode_to_goal_block(struct inode *);
 
 /* dir.c */
 extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *,
@@ -1793,7 +1801,7 @@ extern void ext4_free_blocks(handle_t *handle, struct inode *inode,
                             unsigned long count, int flags);
 extern int ext4_mb_add_groupinfo(struct super_block *sb,
                ext4_group_t i, struct ext4_group_desc *desc);
-extern void ext4_add_groupblocks(handle_t *handle, struct super_block *sb,
+extern int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,
                                ext4_fsblk_t block, unsigned long count);
 extern int ext4_trim_fs(struct super_block *, struct fstrim_range *);
 
@@ -1834,6 +1842,17 @@ extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf);
 extern qsize_t *ext4_get_reserved_space(struct inode *inode);
 extern void ext4_da_update_reserve_space(struct inode *inode,
                                        int used, int quota_claim);
+
+/* indirect.c */
+extern int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
+                               struct ext4_map_blocks *map, int flags);
+extern ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb,
+                               const struct iovec *iov, loff_t offset,
+                               unsigned long nr_segs);
+extern int ext4_ind_calc_metadata_amount(struct inode *inode, sector_t lblock);
+extern int ext4_ind_trans_blocks(struct inode *inode, int nrblocks, int chunk);
+extern void ext4_ind_truncate(struct inode *inode);
+
 /* ioctl.c */
 extern long ext4_ioctl(struct file *, unsigned int, unsigned long);
 extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long);
@@ -1855,6 +1874,9 @@ extern int ext4_group_extend(struct super_block *sb,
                                ext4_fsblk_t n_blocks_count);
 
 /* super.c */
+extern void *ext4_kvmalloc(size_t size, gfp_t flags);
+extern void *ext4_kvzalloc(size_t size, gfp_t flags);
+extern void ext4_kvfree(void *ptr);
 extern void __ext4_error(struct super_block *, const char *, unsigned int,
                         const char *, ...)
        __attribute__ ((format (printf, 4, 5)));
@@ -2067,11 +2089,19 @@ struct ext4_group_info {
                                         * 5 free 8-block regions. */
 };
 
-#define EXT4_GROUP_INFO_NEED_INIT_BIT  0
+#define EXT4_GROUP_INFO_NEED_INIT_BIT          0
+#define EXT4_GROUP_INFO_WAS_TRIMMED_BIT                1
 
 #define EXT4_MB_GRP_NEED_INIT(grp)     \
        (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state)))
 
+#define EXT4_MB_GRP_WAS_TRIMMED(grp)   \
+       (test_bit(EXT4_GROUP_INFO_WAS_TRIMMED_BIT, &((grp)->bb_state)))
+#define EXT4_MB_GRP_SET_TRIMMED(grp)   \
+       (set_bit(EXT4_GROUP_INFO_WAS_TRIMMED_BIT, &((grp)->bb_state)))
+#define EXT4_MB_GRP_CLEAR_TRIMMED(grp) \
+       (clear_bit(EXT4_GROUP_INFO_WAS_TRIMMED_BIT, &((grp)->bb_state)))
+
 #define EXT4_MAX_CONTENTION            8
 #define EXT4_CONTENTION_THRESHOLD      2
 
@@ -2122,6 +2152,19 @@ static inline void ext4_mark_super_dirty(struct super_block *sb)
                sb->s_dirt =1;
 }
 
+/*
+ * Block validity checking
+ */
+#define ext4_check_indirect_blockref(inode, bh)                                \
+       ext4_check_blockref(__func__, __LINE__, inode,                  \
+                           (__le32 *)(bh)->b_data,                     \
+                           EXT4_ADDR_PER_BLOCK((inode)->i_sb))
+
+#define ext4_ind_check_inode(inode)                                    \
+       ext4_check_blockref(__func__, __LINE__, inode,                  \
+                           EXT4_I(inode)->i_data,                      \
+                           EXT4_NDIR_BLOCKS)
+
 /*
  * Inodes and files operations
  */
@@ -2151,6 +2194,8 @@ extern void ext4_exit_system_zone(void);
 extern int ext4_data_block_valid(struct ext4_sb_info *sbi,
                                 ext4_fsblk_t start_blk,
                                 unsigned int count);
+extern int ext4_check_blockref(const char *, unsigned int,
+                              struct inode *, __le32 *, unsigned int);
 
 /* extents.c */
 extern int ext4_ext_tree_init(handle_t *handle, struct inode *);
@@ -2230,6 +2275,10 @@ static inline void set_bitmap_uptodate(struct buffer_head *bh)
 extern wait_queue_head_t ext4__ioend_wq[EXT4_WQ_HASH_SZ];
 extern struct mutex ext4__aio_mutex[EXT4_WQ_HASH_SZ];
 
+#define EXT4_RESIZING  0
+extern int ext4_resize_begin(struct super_block *sb);
+extern void ext4_resize_end(struct super_block *sb);
+
 #endif /* __KERNEL__ */
 
 #endif /* _EXT4_H */
index bb85757..5802fa1 100644 (file)
@@ -289,10 +289,10 @@ static inline int ext4_should_order_data(struct inode *inode)
 
 static inline int ext4_should_writeback_data(struct inode *inode)
 {
-       if (!S_ISREG(inode->i_mode))
-               return 0;
        if (EXT4_JOURNAL(inode) == NULL)
                return 1;
+       if (!S_ISREG(inode->i_mode))
+               return 0;
        if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA))
                return 0;
        if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
index f815cc8..57cf568 100644 (file)
@@ -114,12 +114,6 @@ static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode,
                              struct ext4_ext_path *path,
                              ext4_lblk_t block)
 {
-       struct ext4_inode_info *ei = EXT4_I(inode);
-       ext4_fsblk_t bg_start;
-       ext4_fsblk_t last_block;
-       ext4_grpblk_t colour;
-       ext4_group_t block_group;
-       int flex_size = ext4_flex_bg_size(EXT4_SB(inode->i_sb));
        int depth;
 
        if (path) {
@@ -161,36 +155,7 @@ static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode,
        }
 
        /* OK. use inode's group */
-       block_group = ei->i_block_group;
-       if (flex_size >= EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME) {
-               /*
-                * If there are at least EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME
-                * block groups per flexgroup, reserve the first block
-                * group for directories and special files.  Regular
-                * files will start at the second block group.  This
-                * tends to speed up directory access and improves
-                * fsck times.
-                */
-               block_group &= ~(flex_size-1);
-               if (S_ISREG(inode->i_mode))
-                       block_group++;
-       }
-       bg_start = ext4_group_first_block_no(inode->i_sb, block_group);
-       last_block = ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es) - 1;
-
-       /*
-        * If we are doing delayed allocation, we don't need take
-        * colour into account.
-        */
-       if (test_opt(inode->i_sb, DELALLOC))
-               return bg_start;
-
-       if (bg_start + EXT4_BLOCKS_PER_GROUP(inode->i_sb) <= last_block)
-               colour = (current->pid % 16) *
-                       (EXT4_BLOCKS_PER_GROUP(inode->i_sb) / 16);
-       else
-               colour = (current->pid % 16) * ((last_block - bg_start) / 16);
-       return bg_start + colour + block;
+       return ext4_inode_to_goal_block(inode);
 }
 
 /*
@@ -776,6 +741,16 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode,
                                 logical, le32_to_cpu(curp->p_idx->ei_block));
                return -EIO;
        }
+
+       if (unlikely(le16_to_cpu(curp->p_hdr->eh_entries)
+                            >= le16_to_cpu(curp->p_hdr->eh_max))) {
+               EXT4_ERROR_INODE(inode,
+                                "eh_entries %d >= eh_max %d!",
+                                le16_to_cpu(curp->p_hdr->eh_entries),
+                                le16_to_cpu(curp->p_hdr->eh_max));
+               return -EIO;
+       }
+
        len = EXT_MAX_INDEX(curp->p_hdr) - curp->p_idx;
        if (logical > le32_to_cpu(curp->p_idx->ei_block)) {
                /* insert after */
@@ -805,13 +780,6 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode,
        ext4_idx_store_pblock(ix, ptr);
        le16_add_cpu(&curp->p_hdr->eh_entries, 1);
 
-       if (unlikely(le16_to_cpu(curp->p_hdr->eh_entries)
-                            > le16_to_cpu(curp->p_hdr->eh_max))) {
-               EXT4_ERROR_INODE(inode,
-                                "logical %d == ei_block %d!",
-                                logical, le32_to_cpu(curp->p_idx->ei_block));
-               return -EIO;
-       }
        if (unlikely(ix > EXT_LAST_INDEX(curp->p_hdr))) {
                EXT4_ERROR_INODE(inode, "ix > EXT_LAST_INDEX!");
                return -EIO;
@@ -1446,8 +1414,7 @@ ext4_ext_next_allocated_block(struct ext4_ext_path *path)
  * ext4_ext_next_leaf_block:
  * returns first allocated block from next leaf or EXT_MAX_BLOCKS
  */
-static ext4_lblk_t ext4_ext_next_leaf_block(struct inode *inode,
-                                       struct ext4_ext_path *path)
+static ext4_lblk_t ext4_ext_next_leaf_block(struct ext4_ext_path *path)
 {
        int depth;
 
@@ -1757,7 +1724,6 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
                goto merge;
        }
 
-repeat:
        depth = ext_depth(inode);
        eh = path[depth].p_hdr;
        if (le16_to_cpu(eh->eh_entries) < le16_to_cpu(eh->eh_max))
@@ -1765,9 +1731,10 @@ repeat:
 
        /* probably next leaf has space for us? */
        fex = EXT_LAST_EXTENT(eh);
-       next = ext4_ext_next_leaf_block(inode, path);
-       if (le32_to_cpu(newext->ee_block) > le32_to_cpu(fex->ee_block)
-           && next != EXT_MAX_BLOCKS) {
+       next = EXT_MAX_BLOCKS;
+       if (le32_to_cpu(newext->ee_block) > le32_to_cpu(fex->ee_block))
+               next = ext4_ext_next_leaf_block(path);
+       if (next != EXT_MAX_BLOCKS) {
                ext_debug("next leaf block - %d\n", next);
                BUG_ON(npath != NULL);
                npath = ext4_ext_find_extent(inode, next, NULL);
@@ -1779,7 +1746,7 @@ repeat:
                        ext_debug("next leaf isn't full(%d)\n",
                                  le16_to_cpu(eh->eh_entries));
                        path = npath;
-                       goto repeat;
+                       goto has_space;
                }
                ext_debug("next leaf has no free space(%d,%d)\n",
                          le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max));
@@ -1839,7 +1806,7 @@ has_space:
                                ext4_ext_pblock(newext),
                                ext4_ext_is_uninitialized(newext),
                                ext4_ext_get_actual_len(newext),
-                               nearex, len, nearex + 1, nearex + 2);
+                               nearex, len, nearex, nearex + 1);
                memmove(nearex + 1, nearex, len);
                path[depth].p_ext = nearex;
        }
@@ -2052,7 +2019,7 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,
 }
 
 /*
- * ext4_ext_in_cache()
+ * ext4_ext_check_cache()
  * Checks to see if the given block is in the cache.
  * If it is, the cached extent is stored in the given
  * cache extent pointer.  If the cached extent is a hole,
@@ -2134,8 +2101,6 @@ ext4_ext_in_cache(struct inode *inode, ext4_lblk_t block,
 /*
  * ext4_ext_rm_idx:
  * removes index from the index block.
- * It's used in truncate case only, thus all requests are for
- * last index in the block only.
  */
 static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode,
                        struct ext4_ext_path *path)
@@ -2153,6 +2118,13 @@ static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode,
        err = ext4_ext_get_access(handle, inode, path);
        if (err)
                return err;
+
+       if (path->p_idx != EXT_LAST_INDEX(path->p_hdr)) {
+               int len = EXT_LAST_INDEX(path->p_hdr) - path->p_idx;
+               len *= sizeof(struct ext4_extent_idx);
+               memmove(path->p_idx, path->p_idx + 1, len);
+       }
+
        le16_add_cpu(&path->p_hdr->eh_entries, -1);
        err = ext4_ext_dirty(handle, inode, path);
        if (err)
@@ -2534,8 +2506,7 @@ ext4_ext_more_to_rm(struct ext4_ext_path *path)
        return 1;
 }
 
-static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start,
-                               ext4_lblk_t end)
+static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
 {
        struct super_block *sb = inode->i_sb;
        int depth = ext_depth(inode);
@@ -2575,7 +2546,7 @@ again:
                if (i == depth) {
                        /* this is leaf block */
                        err = ext4_ext_rm_leaf(handle, inode, path,
-                                       start, end);
+                                       start, EXT_MAX_BLOCKS - 1);
                        /* root level has p_bh == NULL, brelse() eats this */
                        brelse(path[i].p_bh);
                        path[i].p_bh = NULL;
@@ -3107,12 +3078,10 @@ static int ext4_convert_unwritten_extents_endio(handle_t *handle,
                                              struct ext4_ext_path *path)
 {
        struct ext4_extent *ex;
-       struct ext4_extent_header *eh;
        int depth;
        int err = 0;
 
        depth = ext_depth(inode);
-       eh = path[depth].p_hdr;
        ex = path[depth].p_ext;
 
        ext_debug("ext4_convert_unwritten_extents_endio: inode %lu, logical"
@@ -3357,8 +3326,8 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
        trace_ext4_ext_map_blocks_enter(inode, map->m_lblk, map->m_len, flags);
 
        /* check in cache */
-       if (ext4_ext_in_cache(inode, map->m_lblk, &newex) &&
-               ((flags & EXT4_GET_BLOCKS_PUNCH_OUT_EXT) == 0)) {
+       if (!(flags & EXT4_GET_BLOCKS_PUNCH_OUT_EXT) &&
+               ext4_ext_in_cache(inode, map->m_lblk, &newex)) {
                if (!newex.ee_start_lo && !newex.ee_start_hi) {
                        if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) {
                                /*
@@ -3497,8 +3466,27 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
 
                        ext4_ext_mark_uninitialized(ex);
 
-                       err = ext4_ext_remove_space(inode, map->m_lblk,
-                               map->m_lblk + punched_out);
+                       ext4_ext_invalidate_cache(inode);
+
+                       err = ext4_ext_rm_leaf(handle, inode, path,
+                               map->m_lblk, map->m_lblk + punched_out);
+
+                       if (!err && path->p_hdr->eh_entries == 0) {
+                               /*
+                                * Punch hole freed all of this sub tree,
+                                * so we need to correct eh_depth
+                                */
+                               err = ext4_ext_get_access(handle, inode, path);
+                               if (err == 0) {
+                                       ext_inode_hdr(inode)->eh_depth = 0;
+                                       ext_inode_hdr(inode)->eh_max =
+                                       cpu_to_le16(ext4_ext_space_root(
+                                               inode, 0));
+
+                                       err = ext4_ext_dirty(
+                                               handle, inode, path);
+                               }
+                       }
 
                        goto out2;
                }
@@ -3596,17 +3584,18 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
        }
 
        err = check_eofblocks_fl(handle, inode, map->m_lblk, path, ar.len);
-       if (err)
-               goto out2;
-
-       err = ext4_ext_insert_extent(handle, inode, path, &newex, flags);
+       if (!err)
+               err = ext4_ext_insert_extent(handle, inode, path,
+                                            &newex, flags);
        if (err) {
+               int fb_flags = flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE ?
+                       EXT4_FREE_BLOCKS_NO_QUOT_UPDATE : 0;
                /* free data blocks we just allocated */
                /* not a good idea to call discard here directly,
                 * but otherwise we'd need to call it every free() */
                ext4_discard_preallocations(inode);
                ext4_free_blocks(handle, inode, NULL, ext4_ext_pblock(&newex),
-                                ext4_ext_get_actual_len(&newex), 0);
+                                ext4_ext_get_actual_len(&newex), fb_flags);
                goto out2;
        }
 
@@ -3699,7 +3688,7 @@ void ext4_ext_truncate(struct inode *inode)
 
        last_block = (inode->i_size + sb->s_blocksize - 1)
                        >> EXT4_BLOCK_SIZE_BITS(sb);
-       err = ext4_ext_remove_space(inode, last_block, EXT_MAX_BLOCKS - 1);
+       err = ext4_ext_remove_space(inode, last_block);
 
        /* In a multi-transaction truncate, we only make the final
         * transaction synchronous.
@@ -3835,7 +3824,7 @@ retry:
                                                blkbits) >> blkbits))
                        new_size = offset + len;
                else
-                       new_size = (map.m_lblk + ret) << blkbits;
+                       new_size = ((loff_t) map.m_lblk + ret) << blkbits;
 
                ext4_falloc_update_inode(inode, mode, new_size,
                                         (map.m_flags & EXT4_MAP_NEW));
index da3bed3..036f78f 100644 (file)
@@ -129,15 +129,30 @@ static int ext4_sync_parent(struct inode *inode)
 {
        struct writeback_control wbc;
        struct dentry *dentry = NULL;
+       struct inode *next;
        int ret = 0;
 
-       while (inode && ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) {
+       if (!ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY))
+               return 0;
+       inode = igrab(inode);
+       while (ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) {
                ext4_clear_inode_state(inode, EXT4_STATE_NEWENTRY);
-               dentry = list_entry(inode->i_dentry.next,
-                                   struct dentry, d_alias);
-               if (!dentry || !dentry->d_parent || !dentry->d_parent->d_inode)
+               dentry = NULL;
+               spin_lock(&inode->i_lock);
+               if (!list_empty(&inode->i_dentry)) {
+                       dentry = list_first_entry(&inode->i_dentry,
+                                                 struct dentry, d_alias);
+                       dget(dentry);
+               }
+               spin_unlock(&inode->i_lock);
+               if (!dentry)
                        break;
-               inode = dentry->d_parent->d_inode;
+               next = igrab(dentry->d_parent->d_inode);
+               dput(dentry);
+               if (!next)
+                       break;
+               iput(inode);
+               inode = next;
                ret = sync_mapping_buffers(inode->i_mapping);
                if (ret)
                        break;
@@ -148,6 +163,7 @@ static int ext4_sync_parent(struct inode *inode)
                if (ret)
                        break;
        }
+       iput(inode);
        return ret;
 }
 
index 21bb2f6..9c63f27 100644 (file)
@@ -1287,7 +1287,7 @@ extern int ext4_init_inode_table(struct super_block *sb, ext4_group_t group,
                           group, used_blks,
                           ext4_itable_unused_count(sb, gdp));
                ret = 1;
-               goto out;
+               goto err_out;
        }
 
        blk = ext4_inode_table(sb, gdp) + used_blks;
diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c
new file mode 100644 (file)
index 0000000..0962642
--- /dev/null
@@ -0,0 +1,1487 @@
+/*
+ *  linux/fs/ext4/indirect.c
+ *
+ *  from
+ *
+ *  linux/fs/ext4/inode.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ *  from
+ *
+ *  linux/fs/minix/inode.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  Goal-directed block allocation by Stephen Tweedie
+ *     (sct@redhat.com), 1993, 1998
+ */
+
+#include <linux/module.h>
+#include "ext4_jbd2.h"
+#include "truncate.h"
+
+#include <trace/events/ext4.h>
+
+typedef struct {
+       __le32  *p;
+       __le32  key;
+       struct buffer_head *bh;
+} Indirect;
+
+static inline void add_chain(Indirect *p, struct buffer_head *bh, __le32 *v)
+{
+       p->key = *(p->p = v);
+       p->bh = bh;
+}
+
+/**
+ *     ext4_block_to_path - parse the block number into array of offsets
+ *     @inode: inode in question (we are only interested in its superblock)
+ *     @i_block: block number to be parsed
+ *     @offsets: array to store the offsets in
+ *     @boundary: set this non-zero if the referred-to block is likely to be
+ *            followed (on disk) by an indirect block.
+ *
+ *     To store the locations of file's data ext4 uses a data structure common
+ *     for UNIX filesystems - tree of pointers anchored in the inode, with
+ *     data blocks at leaves and indirect blocks in intermediate nodes.
+ *     This function translates the block number into path in that tree -
+ *     return value is the path length and @offsets[n] is the offset of
+ *     pointer to (n+1)th node in the nth one. If @block is out of range
+ *     (negative or too large) warning is printed and zero returned.
+ *
+ *     Note: function doesn't find node addresses, so no IO is needed. All
+ *     we need to know is the capacity of indirect blocks (taken from the
+ *     inode->i_sb).
+ */
+
+/*
+ * Portability note: the last comparison (check that we fit into triple
+ * indirect block) is spelled differently, because otherwise on an
+ * architecture with 32-bit longs and 8Kb pages we might get into trouble
+ * if our filesystem had 8Kb blocks. We might use long long, but that would
+ * kill us on x86. Oh, well, at least the sign propagation does not matter -
+ * i_block would have to be negative in the very beginning, so we would not
+ * get there at all.
+ */
+
+static int ext4_block_to_path(struct inode *inode,
+                             ext4_lblk_t i_block,
+                             ext4_lblk_t offsets[4], int *boundary)
+{
+       int ptrs = EXT4_ADDR_PER_BLOCK(inode->i_sb);
+       int ptrs_bits = EXT4_ADDR_PER_BLOCK_BITS(inode->i_sb);
+       const long direct_blocks = EXT4_NDIR_BLOCKS,
+               indirect_blocks = ptrs,
+               double_blocks = (1 << (ptrs_bits * 2));
+       int n = 0;
+       int final = 0;
+
+       if (i_block < direct_blocks) {
+               offsets[n++] = i_block;
+               final = direct_blocks;
+       } else if ((i_block -= direct_blocks) < indirect_blocks) {
+               offsets[n++] = EXT4_IND_BLOCK;
+               offsets[n++] = i_block;
+               final = ptrs;
+       } else if ((i_block -= indirect_blocks) < double_blocks) {
+               offsets[n++] = EXT4_DIND_BLOCK;
+               offsets[n++] = i_block >> ptrs_bits;
+               offsets[n++] = i_block & (ptrs - 1);
+               final = ptrs;
+       } else if (((i_block -= double_blocks) >> (ptrs_bits * 2)) < ptrs) {
+               offsets[n++] = EXT4_TIND_BLOCK;
+               offsets[n++] = i_block >> (ptrs_bits * 2);
+               offsets[n++] = (i_block >> ptrs_bits) & (ptrs - 1);
+               offsets[n++] = i_block & (ptrs - 1);
+               final = ptrs;
+       } else {
+               ext4_warning(inode->i_sb, "block %lu > max in inode %lu",
+                            i_block + direct_blocks +
+                            indirect_blocks + double_blocks, inode->i_ino);
+       }
+       if (boundary)
+               *boundary = final - 1 - (i_block & (ptrs - 1));
+       return n;
+}
+
+/**
+ *     ext4_get_branch - read the chain of indirect blocks leading to data
+ *     @inode: inode in question
+ *     @depth: depth of the chain (1 - direct pointer, etc.)
+ *     @offsets: offsets of pointers in inode/indirect blocks
+ *     @chain: place to store the result
+ *     @err: here we store the error value
+ *
+ *     Function fills the array of triples <key, p, bh> and returns %NULL
+ *     if everything went OK or the pointer to the last filled triple
+ *     (incomplete one) otherwise. Upon the return chain[i].key contains
+ *     the number of (i+1)-th block in the chain (as it is stored in memory,
+ *     i.e. little-endian 32-bit), chain[i].p contains the address of that
+ *     number (it points into struct inode for i==0 and into the bh->b_data
+ *     for i>0) and chain[i].bh points to the buffer_head of i-th indirect
+ *     block for i>0 and NULL for i==0. In other words, it holds the block
+ *     numbers of the chain, addresses they were taken from (and where we can
+ *     verify that chain did not change) and buffer_heads hosting these
+ *     numbers.
+ *
+ *     Function stops when it stumbles upon zero pointer (absent block)
+ *             (pointer to last triple returned, *@err == 0)
+ *     or when it gets an IO error reading an indirect block
+ *             (ditto, *@err == -EIO)
+ *     or when it reads all @depth-1 indirect blocks successfully and finds
+ *     the whole chain, all way to the data (returns %NULL, *err == 0).
+ *
+ *      Need to be called with
+ *      down_read(&EXT4_I(inode)->i_data_sem)
+ */
+static Indirect *ext4_get_branch(struct inode *inode, int depth,
+                                ext4_lblk_t  *offsets,
+                                Indirect chain[4], int *err)
+{
+       struct super_block *sb = inode->i_sb;
+       Indirect *p = chain;
+       struct buffer_head *bh;
+
+       *err = 0;
+       /* i_data is not going away, no lock needed */
+       add_chain(chain, NULL, EXT4_I(inode)->i_data + *offsets);
+       if (!p->key)
+               goto no_block;
+       while (--depth) {
+               bh = sb_getblk(sb, le32_to_cpu(p->key));
+               if (unlikely(!bh))
+                       goto failure;
+
+               if (!bh_uptodate_or_lock(bh)) {
+                       if (bh_submit_read(bh) < 0) {
+                               put_bh(bh);
+                               goto failure;
+                       }
+                       /* validate block references */
+                       if (ext4_check_indirect_blockref(inode, bh)) {
+                               put_bh(bh);
+                               goto failure;
+                       }
+               }
+
+               add_chain(++p, bh, (__le32 *)bh->b_data + *++offsets);
+               /* Reader: end */
+               if (!p->key)
+                       goto no_block;
+       }
+       return NULL;
+
+failure:
+       *err = -EIO;
+no_block:
+       return p;
+}
+
+/**
+ *     ext4_find_near - find a place for allocation with sufficient locality
+ *     @inode: owner
+ *     @ind: descriptor of indirect block.
+ *
+ *     This function returns the preferred place for block allocation.
+ *     It is used when heuristic for sequential allocation fails.
+ *     Rules are:
+ *       + if there is a block to the left of our position - allocate near it.
+ *       + if pointer will live in indirect block - allocate near that block.
+ *       + if pointer will live in inode - allocate in the same
+ *         cylinder group.
+ *
+ * In the latter case we colour the starting block by the callers PID to
+ * prevent it from clashing with concurrent allocations for a different inode
+ * in the same block group.   The PID is used here so that functionally related
+ * files will be close-by on-disk.
+ *
+ *     Caller must make sure that @ind is valid and will stay that way.
+ */
+static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind)
+{
+       struct ext4_inode_info *ei = EXT4_I(inode);
+       __le32 *start = ind->bh ? (__le32 *) ind->bh->b_data : ei->i_data;
+       __le32 *p;
+
+       /* Try to find previous block */
+       for (p = ind->p - 1; p >= start; p--) {
+               if (*p)
+                       return le32_to_cpu(*p);
+       }
+
+       /* No such thing, so let's try location of indirect block */
+       if (ind->bh)
+               return ind->bh->b_blocknr;
+
+       /*
+        * It is going to be referred to from the inode itself? OK, just put it
+        * into the same cylinder group then.
+        */
+       return ext4_inode_to_goal_block(inode);
+}
+
+/**
+ *     ext4_find_goal - find a preferred place for allocation.
+ *     @inode: owner
+ *     @block:  block we want
+ *     @partial: pointer to the last triple within a chain
+ *
+ *     Normally this function find the preferred place for block allocation,
+ *     returns it.
+ *     Because this is only used for non-extent files, we limit the block nr
+ *     to 32 bits.
+ */
+static ext4_fsblk_t ext4_find_goal(struct inode *inode, ext4_lblk_t block,
+                                  Indirect *partial)
+{
+       ext4_fsblk_t goal;
+
+       /*
+        * XXX need to get goal block from mballoc's data structures
+        */
+
+       goal = ext4_find_near(inode, partial);
+       goal = goal & EXT4_MAX_BLOCK_FILE_PHYS;
+       return goal;
+}
+
+/**
+ *     ext4_blks_to_allocate - Look up the block map and count the number
+ *     of direct blocks need to be allocated for the given branch.
+ *
+ *     @branch: chain of indirect blocks
+ *     @k: number of blocks need for indirect blocks
+ *     @blks: number of data blocks to be mapped.
+ *     @blocks_to_boundary:  the offset in the indirect block
+ *
+ *     return the total number of blocks to be allocate, including the
+ *     direct and indirect blocks.
+ */
+static int ext4_blks_to_allocate(Indirect *branch, int k, unsigned int blks,
+                                int blocks_to_boundary)
+{
+       unsigned int count = 0;
+
+       /*
+        * Simple case, [t,d]Indirect block(s) has not allocated yet
+        * then it's clear blocks on that path have not allocated
+        */
+       if (k > 0) {
+               /* right now we don't handle cross boundary allocation */
+               if (blks < blocks_to_boundary + 1)
+                       count += blks;
+               else
+                       count += blocks_to_boundary + 1;
+               return count;
+       }
+
+       count++;
+       while (count < blks && count <= blocks_to_boundary &&
+               le32_to_cpu(*(branch[0].p + count)) == 0) {
+               count++;
+       }
+       return count;
+}
+
+/**
+ *     ext4_alloc_blocks: multiple allocate blocks needed for a branch
+ *     @handle: handle for this transaction
+ *     @inode: inode which needs allocated blocks
+ *     @iblock: the logical block to start allocated at
+ *     @goal: preferred physical block of allocation
+ *     @indirect_blks: the number of blocks need to allocate for indirect
+ *                     blocks
+ *     @blks: number of desired blocks
+ *     @new_blocks: on return it will store the new block numbers for
+ *     the indirect blocks(if needed) and the first direct block,
+ *     @err: on return it will store the error code
+ *
+ *     This function will return the number of blocks allocated as
+ *     requested by the passed-in parameters.
+ */
+static int ext4_alloc_blocks(handle_t *handle, struct inode *inode,
+                            ext4_lblk_t iblock, ext4_fsblk_t goal,
+                            int indirect_blks, int blks,
+                            ext4_fsblk_t new_blocks[4], int *err)
+{
+       struct ext4_allocation_request ar;
+       int target, i;
+       unsigned long count = 0, blk_allocated = 0;
+       int index = 0;
+       ext4_fsblk_t current_block = 0;
+       int ret = 0;
+
+       /*
+        * Here we try to allocate the requested multiple blocks at once,
+        * on a best-effort basis.
+        * To build a branch, we should allocate blocks for
+        * the indirect blocks(if not allocated yet), and at least
+        * the first direct block of this branch.  That's the
+        * minimum number of blocks need to allocate(required)
+        */
+       /* first we try to allocate the indirect blocks */
+       target = indirect_blks;
+       while (target > 0) {
+               count = target;
+               /* allocating blocks for indirect blocks and direct blocks */
+               current_block = ext4_new_meta_blocks(handle, inode, goal,
+                                                    0, &count, err);
+               if (*err)
+                       goto failed_out;
+
+               if (unlikely(current_block + count > EXT4_MAX_BLOCK_FILE_PHYS)) {
+                       EXT4_ERROR_INODE(inode,
+                                        "current_block %llu + count %lu > %d!",
+                                        current_block, count,
+                                        EXT4_MAX_BLOCK_FILE_PHYS);
+                       *err = -EIO;
+                       goto failed_out;
+               }
+
+               target -= count;
+               /* allocate blocks for indirect blocks */
+               while (index < indirect_blks && count) {
+                       new_blocks[index++] = current_block++;
+                       count--;
+               }
+               if (count > 0) {
+                       /*
+                        * save the new block number
+                        * for the first direct block
+                        */
+                       new_blocks[index] = current_block;
+                       printk(KERN_INFO "%s returned more blocks than "
+                                               "requested\n", __func__);
+                       WARN_ON(1);
+                       break;
+               }
+       }
+
+       target = blks - count ;
+       blk_allocated = count;
+       if (!target)
+               goto allocated;
+       /* Now allocate data blocks */
+       memset(&ar, 0, sizeof(ar));
+       ar.inode = inode;
+       ar.goal = goal;
+       ar.len = target;
+       ar.logical = iblock;
+       if (S_ISREG(inode->i_mode))
+               /* enable in-core preallocation only for regular files */
+               ar.flags = EXT4_MB_HINT_DATA;
+
+       current_block = ext4_mb_new_blocks(handle, &ar, err);
+       if (unlikely(current_block + ar.len > EXT4_MAX_BLOCK_FILE_PHYS)) {
+               EXT4_ERROR_INODE(inode,
+                                "current_block %llu + ar.len %d > %d!",
+                                current_block, ar.len,
+                                EXT4_MAX_BLOCK_FILE_PHYS);
+               *err = -EIO;
+               goto failed_out;
+       }
+
+       if (*err && (target == blks)) {
+               /*
+                * if the allocation failed and we didn't allocate
+                * any blocks before
+                */
+               goto failed_out;
+       }
+       if (!*err) {
+               if (target == blks) {
+                       /*
+                        * save the new block number
+                        * for the first direct block
+                        */
+                       new_blocks[index] = current_block;
+               }
+               blk_allocated += ar.len;
+       }
+allocated:
+       /* total number of blocks allocated for direct blocks */
+       ret = blk_allocated;
+       *err = 0;
+       return ret;
+failed_out:
+       for (i = 0; i < index; i++)
+               ext4_free_blocks(handle, inode, NULL, new_blocks[i], 1, 0);
+       return ret;
+}
+
+/**
+ *     ext4_alloc_branch - allocate and set up a chain of blocks.
+ *     @handle: handle for this transaction
+ *     @inode: owner
+ *     @indirect_blks: number of allocated indirect blocks
+ *     @blks: number of allocated direct blocks
+ *     @goal: preferred place for allocation
+ *     @offsets: offsets (in the blocks) to store the pointers to next.
+ *     @branch: place to store the chain in.
+ *
+ *     This function allocates blocks, zeroes out all but the last one,
+ *     links them into chain and (if we are synchronous) writes them to disk.
+ *     In other words, it prepares a branch that can be spliced onto the
+ *     inode. It stores the information about that chain in the branch[], in
+ *     the same format as ext4_get_branch() would do. We are calling it after
+ *     we had read the existing part of chain and partial points to the last
+ *     triple of that (one with zero ->key). Upon the exit we have the same
+ *     picture as after the successful ext4_get_block(), except that in one
+ *     place chain is disconnected - *branch->p is still zero (we did not
+ *     set the last link), but branch->key contains the number that should
+ *     be placed into *branch->p to fill that gap.
+ *
+ *     If allocation fails we free all blocks we've allocated (and forget
+ *     their buffer_heads) and return the error value the from failed
+ *     ext4_alloc_block() (normally -ENOSPC). Otherwise we set the chain
+ *     as described above and return 0.
+ */
+static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
+                            ext4_lblk_t iblock, int indirect_blks,
+                            int *blks, ext4_fsblk_t goal,
+                            ext4_lblk_t *offsets, Indirect *branch)
+{
+       int blocksize = inode->i_sb->s_blocksize;
+       int i, n = 0;
+       int err = 0;
+       struct buffer_head *bh;
+       int num;
+       ext4_fsblk_t new_blocks[4];
+       ext4_fsblk_t current_block;
+
+       num = ext4_alloc_blocks(handle, inode, iblock, goal, indirect_blks,
+                               *blks, new_blocks, &err);
+       if (err)
+               return err;
+
+       branch[0].key = cpu_to_le32(new_blocks[0]);
+       /*
+        * metadata blocks and data blocks are allocated.
+        */
+       for (n = 1; n <= indirect_blks;  n++) {
+               /*
+                * Get buffer_head for parent block, zero it out
+                * and set the pointer to new one, then send
+                * parent to disk.
+                */
+               bh = sb_getblk(inode->i_sb, new_blocks[n-1]);
+               if (unlikely(!bh)) {
+                       err = -EIO;
+                       goto failed;
+               }
+
+               branch[n].bh = bh;
+               lock_buffer(bh);
+               BUFFER_TRACE(bh, "call get_create_access");
+               err = ext4_journal_get_create_access(handle, bh);
+               if (err) {
+                       /* Don't brelse(bh) here; it's done in
+                        * ext4_journal_forget() below */
+                       unlock_buffer(bh);
+                       goto failed;
+               }
+
+               memset(bh->b_data, 0, blocksize);
+               branch[n].p = (__le32 *) bh->b_data + offsets[n];
+               branch[n].key = cpu_to_le32(new_blocks[n]);
+               *branch[n].p = branch[n].key;
+               if (n == indirect_blks) {
+                       current_block = new_blocks[n];
+                       /*
+                        * End of chain, update the last new metablock of
+                        * the chain to point to the new allocated
+                        * data blocks numbers
+                        */
+                       for (i = 1; i < num; i++)
+                               *(branch[n].p + i) = cpu_to_le32(++current_block);
+               }
+               BUFFER_TRACE(bh, "marking uptodate");
+               set_buffer_uptodate(bh);
+               unlock_buffer(bh);
+
+               BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
+               err = ext4_handle_dirty_metadata(handle, inode, bh);
+               if (err)
+                       goto failed;
+       }
+       *blks = num;
+       return err;
+failed:
+       /* Allocation failed, free what we already allocated */
+       ext4_free_blocks(handle, inode, NULL, new_blocks[0], 1, 0);
+       for (i = 1; i <= n ; i++) {
+               /*
+                * branch[i].bh is newly allocated, so there is no
+                * need to revoke the block, which is why we don't
+                * need to set EXT4_FREE_BLOCKS_METADATA.
+                */
+               ext4_free_blocks(handle, inode, NULL, new_blocks[i], 1,
+                                EXT4_FREE_BLOCKS_FORGET);
+       }
+       for (i = n+1; i < indirect_blks; i++)
+               ext4_free_blocks(handle, inode, NULL, new_blocks[i], 1, 0);
+
+       ext4_free_blocks(handle, inode, NULL, new_blocks[i], num, 0);
+
+       return err;
+}
+
+/**
+ * ext4_splice_branch - splice the allocated branch onto inode.
+ * @handle: handle for this transaction
+ * @inode: owner
+ * @block: (logical) number of block we are adding
+ * @chain: chain of indirect blocks (with a missing link - see
+ *     ext4_alloc_branch)
+ * @where: location of missing link
+ * @num:   number of indirect blocks we are adding
+ * @blks:  number of direct blocks we are adding
+ *
+ * This function fills the missing link and does all housekeeping needed in
+ * inode (->i_blocks, etc.). In case of success we end up with the full
+ * chain to new block and return 0.
+ */
+static int ext4_splice_branch(handle_t *handle, struct inode *inode,
+                             ext4_lblk_t block, Indirect *where, int num,
+                             int blks)
+{
+       int i;
+       int err = 0;
+       ext4_fsblk_t current_block;
+
+       /*
+        * If we're splicing into a [td]indirect block (as opposed to the
+        * inode) then we need to get write access to the [td]indirect block
+        * before the splice.
+        */
+       if (where->bh) {
+               BUFFER_TRACE(where->bh, "get_write_access");
+               err = ext4_journal_get_write_access(handle, where->bh);
+               if (err)
+                       goto err_out;
+       }
+       /* That's it */
+
+       *where->p = where->key;
+
+       /*
+        * Update the host buffer_head or inode to point to more just allocated
+        * direct blocks blocks
+        */
+       if (num == 0 && blks > 1) {
+               current_block = le32_to_cpu(where->key) + 1;
+               for (i = 1; i < blks; i++)
+                       *(where->p + i) = cpu_to_le32(current_block++);
+       }
+
+       /* We are done with atomic stuff, now do the rest of housekeeping */
+       /* had we spliced it onto indirect block? */
+       if (where->bh) {
+               /*
+                * If we spliced it onto an indirect block, we haven't
+                * altered the inode.  Note however that if it is being spliced
+                * onto an indirect block at the very end of the file (the
+                * file is growing) then we *will* alter the inode to reflect
+                * the new i_size.  But that is not done here - it is done in
+                * generic_commit_write->__mark_inode_dirty->ext4_dirty_inode.
+                */
+               jbd_debug(5, "splicing indirect only\n");
+               BUFFER_TRACE(where->bh, "call ext4_handle_dirty_metadata");
+               err = ext4_handle_dirty_metadata(handle, inode, where->bh);
+               if (err)
+                       goto err_out;
+       } else {
+               /*
+                * OK, we spliced it into the inode itself on a direct block.
+                */
+               ext4_mark_inode_dirty(handle, inode);
+               jbd_debug(5, "splicing direct\n");
+       }
+       return err;
+
+err_out:
+       for (i = 1; i <= num; i++) {
+               /*
+                * branch[i].bh is newly allocated, so there is no
+                * need to revoke the block, which is why we don't
+                * need to set EXT4_FREE_BLOCKS_METADATA.
+                */
+               ext4_free_blocks(handle, inode, where[i].bh, 0, 1,
+                                EXT4_FREE_BLOCKS_FORGET);
+       }
+       ext4_free_blocks(handle, inode, NULL, le32_to_cpu(where[num].key),
+                        blks, 0);
+
+       return err;
+}
+
+/*
+ * The ext4_ind_map_blocks() function handles non-extents inodes
+ * (i.e., using the traditional indirect/double-indirect i_blocks
+ * scheme) for ext4_map_blocks().
+ *
+ * Allocation strategy is simple: if we have to allocate something, we will
+ * have to go the whole way to leaf. So let's do it before attaching anything
+ * to tree, set linkage between the newborn blocks, write them if sync is
+ * required, recheck the path, free and repeat if check fails, otherwise
+ * set the last missing link (that will protect us from any truncate-generated
+ * removals - all blocks on the path are immune now) and possibly force the
+ * write on the parent block.
+ * That has a nice additional property: no special recovery from the failed
+ * allocations is needed - we simply release blocks and do not touch anything
+ * reachable from inode.
+ *
+ * `handle' can be NULL if create == 0.
+ *
+ * return > 0, # of blocks mapped or allocated.
+ * return = 0, if plain lookup failed.
+ * return < 0, error case.
+ *
+ * The ext4_ind_get_blocks() function should be called with
+ * down_write(&EXT4_I(inode)->i_data_sem) if allocating filesystem
+ * blocks (i.e., flags has EXT4_GET_BLOCKS_CREATE set) or
+ * down_read(&EXT4_I(inode)->i_data_sem) if not allocating file system
+ * blocks.
+ */
+int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
+                       struct ext4_map_blocks *map,
+                       int flags)
+{
+       int err = -EIO;
+       ext4_lblk_t offsets[4];
+       Indirect chain[4];
+       Indirect *partial;
+       ext4_fsblk_t goal;
+       int indirect_blks;
+       int blocks_to_boundary = 0;
+       int depth;
+       int count = 0;
+       ext4_fsblk_t first_block = 0;
+
+       trace_ext4_ind_map_blocks_enter(inode, map->m_lblk, map->m_len, flags);
+       J_ASSERT(!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)));
+       J_ASSERT(handle != NULL || (flags & EXT4_GET_BLOCKS_CREATE) == 0);
+       depth = ext4_block_to_path(inode, map->m_lblk, offsets,
+                                  &blocks_to_boundary);
+
+       if (depth == 0)
+               goto out;
+
+       partial = ext4_get_branch(inode, depth, offsets, chain, &err);
+
+       /* Simplest case - block found, no allocation needed */
+       if (!partial) {
+               first_block = le32_to_cpu(chain[depth - 1].key);
+               count++;
+               /*map more blocks*/
+               while (count < map->m_len && count <= blocks_to_boundary) {
+                       ext4_fsblk_t blk;
+
+                       blk = le32_to_cpu(*(chain[depth-1].p + count));
+
+                       if (blk == first_block + count)
+                               count++;
+                       else
+                               break;
+               }
+               goto got_it;
+       }
+
+       /* Next simple case - plain lookup or failed read of indirect block */
+       if ((flags & EXT4_GET_BLOCKS_CREATE) == 0 || err == -EIO)
+               goto cleanup;
+
+       /*
+        * Okay, we need to do block allocation.
+       */
+       goal = ext4_find_goal(inode, map->m_lblk, partial);
+
+       /* the number of blocks need to allocate for [d,t]indirect blocks */
+       indirect_blks = (chain + depth) - partial - 1;
+
+       /*
+        * Next look up the indirect map to count the totoal number of
+        * direct blocks to allocate for this branch.
+        */
+       count = ext4_blks_to_allocate(partial, indirect_blks,
+                                     map->m_len, blocks_to_boundary);
+       /*
+        * Block out ext4_truncate while we alter the tree
+        */
+       err = ext4_alloc_branch(handle, inode, map->m_lblk, indirect_blks,
+                               &count, goal,
+                               offsets + (partial - chain), partial);
+
+       /*
+        * The ext4_splice_branch call will free and forget any buffers
+        * on the new chain if there is a failure, but that risks using
+        * up transaction credits, especially for bitmaps where the
+        * credits cannot be returned.  Can we handle this somehow?  We
+        * may need to return -EAGAIN upwards in the worst case.  --sct
+        */
+       if (!err)
+               err = ext4_splice_branch(handle, inode, map->m_lblk,
+                                        partial, indirect_blks, count);
+       if (err)
+               goto cleanup;
+
+       map->m_flags |= EXT4_MAP_NEW;
+
+       ext4_update_inode_fsync_trans(handle, inode, 1);
+got_it:
+       map->m_flags |= EXT4_MAP_MAPPED;
+       map->m_pblk = le32_to_cpu(chain[depth-1].key);
+       map->m_len = count;
+       if (count > blocks_to_boundary)
+               map->m_flags |= EXT4_MAP_BOUNDARY;
+       err = count;
+       /* Clean up and exit */
+       partial = chain + depth - 1;    /* the whole chain */
+cleanup:
+       while (partial > chain) {
+               BUFFER_TRACE(partial->bh, "call brelse");
+               brelse(partial->bh);
+               partial--;
+       }
+out:
+       trace_ext4_ind_map_blocks_exit(inode, map->m_lblk,
+                               map->m_pblk, map->m_len, err);
+       return err;
+}
+
+/*
+ * O_DIRECT for ext3 (or indirect map) based files
+ *
+ * If the O_DIRECT write will extend the file then add this inode to the
+ * orphan list.  So recovery will truncate it back to the original size
+ * if the machine crashes during the write.
+ *
+ * If the O_DIRECT write is intantiating holes inside i_size and the machine
+ * crashes then stale disk data _may_ be exposed inside the file. But current
+ * VFS code falls back into buffered path in that case so we are safe.
+ */
+ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb,
+                          const struct iovec *iov, loff_t offset,
+                          unsigned long nr_segs)
+{
+       struct file *file = iocb->ki_filp;
+       struct inode *inode = file->f_mapping->host;
+       struct ext4_inode_info *ei = EXT4_I(inode);
+       handle_t *handle;
+       ssize_t ret;
+       int orphan = 0;
+       size_t count = iov_length(iov, nr_segs);
+       int retries = 0;
+
+       if (rw == WRITE) {
+               loff_t final_size = offset + count;
+
+               if (final_size > inode->i_size) {
+                       /* Credits for sb + inode write */
+                       handle = ext4_journal_start(inode, 2);
+                       if (IS_ERR(handle)) {
+                               ret = PTR_ERR(handle);
+                               goto out;
+                       }
+                       ret = ext4_orphan_add(handle, inode);
+                       if (ret) {
+                               ext4_journal_stop(handle);
+                               goto out;
+                       }
+                       orphan = 1;
+                       ei->i_disksize = inode->i_size;
+                       ext4_journal_stop(handle);
+               }
+       }
+
+retry:
+       if (rw == READ && ext4_should_dioread_nolock(inode)) {
+               if (unlikely(!list_empty(&ei->i_completed_io_list))) {
+                       mutex_lock(&inode->i_mutex);
+                       ext4_flush_completed_IO(inode);
+                       mutex_unlock(&inode->i_mutex);
+               }
+               ret = __blockdev_direct_IO(rw, iocb, inode,
+                                inode->i_sb->s_bdev, iov,
+                                offset, nr_segs,
+                                ext4_get_block, NULL, NULL, 0);
+       } else {
+               ret = blockdev_direct_IO(rw, iocb, inode, iov,
+                                offset, nr_segs, ext4_get_block);
+
+               if (unlikely((rw & WRITE) && ret < 0)) {
+                       loff_t isize = i_size_read(inode);
+                       loff_t end = offset + iov_length(iov, nr_segs);
+
+                       if (end > isize)
+                               ext4_truncate_failed_write(inode);
+               }
+       }
+       if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
+               goto retry;
+
+       if (orphan) {
+               int err;
+
+               /* Credits for sb + inode write */
+               handle = ext4_journal_start(inode, 2);
+               if (IS_ERR(handle)) {
+                       /* This is really bad luck. We've written the data
+                        * but cannot extend i_size. Bail out and pretend
+                        * the write failed... */
+                       ret = PTR_ERR(handle);
+                       if (inode->i_nlink)
+                               ext4_orphan_del(NULL, inode);
+
+                       goto out;
+               }
+               if (inode->i_nlink)
+                       ext4_orphan_del(handle, inode);
+               if (ret > 0) {
+                       loff_t end = offset + ret;
+                       if (end > inode->i_size) {
+                               ei->i_disksize = end;
+                               i_size_write(inode, end);
+                               /*
+                                * We're going to return a positive `ret'
+                                * here due to non-zero-length I/O, so there's
+                                * no way of reporting error returns from
+                                * ext4_mark_inode_dirty() to userspace.  So
+                                * ignore it.
+                                */
+                               ext4_mark_inode_dirty(handle, inode);
+                       }
+               }
+               err = ext4_journal_stop(handle);
+               if (ret == 0)
+                       ret = err;
+       }
+out:
+       return ret;
+}
+
+/*
+ * Calculate the number of metadata blocks need to reserve
+ * to allocate a new block at @lblocks for non extent file based file
+ */
+int ext4_ind_calc_metadata_amount(struct inode *inode, sector_t lblock)
+{
+       struct ext4_inode_info *ei = EXT4_I(inode);
+       sector_t dind_mask = ~((sector_t)EXT4_ADDR_PER_BLOCK(inode->i_sb) - 1);
+       int blk_bits;
+
+       if (lblock < EXT4_NDIR_BLOCKS)
+               return 0;
+
+       lblock -= EXT4_NDIR_BLOCKS;
+
+       if (ei->i_da_metadata_calc_len &&
+           (lblock & dind_mask) == ei->i_da_metadata_calc_last_lblock) {
+               ei->i_da_metadata_calc_len++;
+               return 0;
+       }
+       ei->i_da_metadata_calc_last_lblock = lblock & dind_mask;
+       ei->i_da_metadata_calc_len = 1;
+       blk_bits = order_base_2(lblock);
+       return (blk_bits / EXT4_ADDR_PER_BLOCK_BITS(inode->i_sb)) + 1;
+}
+
+int ext4_ind_trans_blocks(struct inode *inode, int nrblocks, int chunk)
+{
+       int indirects;
+
+       /* if nrblocks are contiguous */
+       if (chunk) {
+               /*
+                * With N contiguous data blocks, we need at most
+                * N/EXT4_ADDR_PER_BLOCK(inode->i_sb) + 1 indirect blocks,
+                * 2 dindirect blocks, and 1 tindirect block
+                */
+               return DIV_ROUND_UP(nrblocks,
+                                   EXT4_ADDR_PER_BLOCK(inode->i_sb)) + 4;
+       }
+       /*
+        * if nrblocks are not contiguous, worse case, each block touch
+        * a indirect block, and each indirect block touch a double indirect
+        * block, plus a triple indirect block
+        */
+       indirects = nrblocks * 2 + 1;
+       return indirects;
+}
+
+/*
+ * Truncate transactions can be complex and absolutely huge.  So we need to
+ * be able to restart the transaction at a conventient checkpoint to make
+ * sure we don't overflow the journal.
+ *
+ * start_transaction gets us a new handle for a truncate transaction,
+ * and extend_transaction tries to extend the existing one a bit.  If
+ * extend fails, we need to propagate the failure up and restart the
+ * transaction in the top-level truncate loop. --sct
+ */
+static handle_t *start_transaction(struct inode *inode)
+{
+       handle_t *result;
+
+       result = ext4_journal_start(inode, ext4_blocks_for_truncate(inode));
+       if (!IS_ERR(result))
+               return result;
+
+       ext4_std_error(inode->i_sb, PTR_ERR(result));
+       return result;
+}
+
+/*
+ * Try to extend this transaction for the purposes of truncation.
+ *
+ * Returns 0 if we managed to create more room.  If we can't create more
+ * room, and the transaction must be restarted we return 1.
+ */
+static int try_to_extend_transaction(handle_t *handle, struct inode *inode)
+{
+       if (!ext4_handle_valid(handle))
+               return 0;
+       if (ext4_handle_has_enough_credits(handle, EXT4_RESERVE_TRANS_BLOCKS+1))
+               return 0;
+       if (!ext4_journal_extend(handle, ext4_blocks_for_truncate(inode)))
+               return 0;
+       return 1;
+}
+
+/*
+ * Probably it should be a library function... search for first non-zero word
+ * or memcmp with zero_page, whatever is better for particular architecture.
+ * Linus?
+ */
+static inline int all_zeroes(__le32 *p, __le32 *q)
+{
+       while (p < q)
+               if (*p++)
+                       return 0;
+       return 1;
+}
+
+/**
+ *     ext4_find_shared - find the indirect blocks for partial truncation.
+ *     @inode:   inode in question
+ *     @depth:   depth of the affected branch
+ *     @offsets: offsets of pointers in that branch (see ext4_block_to_path)
+ *     @chain:   place to store the pointers to partial indirect blocks
+ *     @top:     place to the (detached) top of branch
+ *
+ *     This is a helper function used by ext4_truncate().
+ *
+ *     When we do truncate() we may have to clean the ends of several
+ *     indirect blocks but leave the blocks themselves alive. Block is
+ *     partially truncated if some data below the new i_size is referred
+ *     from it (and it is on the path to the first completely truncated
+ *     data block, indeed).  We have to free the top of that path along
+ *     with everything to the right of the path. Since no allocation
+ *     past the truncation point is possible until ext4_truncate()
+ *     finishes, we may safely do the latter, but top of branch may
+ *     require special attention - pageout below the truncation point
+ *     might try to populate it.
+ *
+ *     We atomically detach the top of branch from the tree, store the
+ *     block number of its root in *@top, pointers to buffer_heads of
+ *     partially truncated blocks - in @chain[].bh and pointers to
+ *     their last elements that should not be removed - in
+ *     @chain[].p. Return value is the pointer to last filled element
+ *     of @chain.
+ *
+ *     The work left to caller to do the actual freeing of subtrees:
+ *             a) free the subtree starting from *@top
+ *             b) free the subtrees whose roots are stored in
+ *                     (@chain[i].p+1 .. end of @chain[i].bh->b_data)
+ *             c) free the subtrees growing from the inode past the @chain[0].
+ *                     (no partially truncated stuff there).  */
+
+static Indirect *ext4_find_shared(struct inode *inode, int depth,
+                                 ext4_lblk_t offsets[4], Indirect chain[4],
+                                 __le32 *top)
+{
+       Indirect *partial, *p;
+       int k, err;
+
+       *top = 0;
+       /* Make k index the deepest non-null offset + 1 */
+       for (k = depth; k > 1 && !offsets[k-1]; k--)
+               ;
+       partial = ext4_get_branch(inode, k, offsets, chain, &err);
+       /* Writer: pointers */
+       if (!partial)
+               partial = chain + k-1;
+       /*
+        * If the branch acquired continuation since we've looked at it -
+        * fine, it should all survive and (new) top doesn't belong to us.
+        */
+       if (!partial->key && *partial->p)
+               /* Writer: end */
+               goto no_top;
+       for (p = partial; (p > chain) && all_zeroes((__le32 *) p->bh->b_data, p->p); p--)
+               ;
+       /*
+        * OK, we've found the last block that must survive. The rest of our
+        * branch should be detached before unlocking. However, if that rest
+        * of branch is all ours and does not grow immediately from the inode
+        * it's easier to cheat and just decrement partial->p.
+        */
+       if (p == chain + k - 1 && p > chain) {
+               p->p--;
+       } else {
+               *top = *p->p;
+               /* Nope, don't do this in ext4.  Must leave the tree intact */
+#if 0
+               *p->p = 0;
+#endif
+       }
+       /* Writer: end */
+
+       while (partial > p) {
+               brelse(partial->bh);
+               partial--;
+       }
+no_top:
+       return partial;
+}
+
+/*
+ * Zero a number of block pointers in either an inode or an indirect block.
+ * If we restart the transaction we must again get write access to the
+ * indirect block for further modification.
+ *
+ * We release `count' blocks on disk, but (last - first) may be greater
+ * than `count' because there can be holes in there.
+ *
+ * Return 0 on success, 1 on invalid block range
+ * and < 0 on fatal error.
+ */
+static int ext4_clear_blocks(handle_t *handle, struct inode *inode,
+                            struct buffer_head *bh,
+                            ext4_fsblk_t block_to_free,
+                            unsigned long count, __le32 *first,
+                            __le32 *last)
+{
+       __le32 *p;
+       int     flags = EXT4_FREE_BLOCKS_FORGET | EXT4_FREE_BLOCKS_VALIDATED;
+       int     err;
+
+       if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
+               flags |= EXT4_FREE_BLOCKS_METADATA;
+
+       if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), block_to_free,
+                                  count)) {
+               EXT4_ERROR_INODE(inode, "attempt to clear invalid "
+                                "blocks %llu len %lu",
+                                (unsigned long long) block_to_free, count);
+               return 1;
+       }
+
+       if (try_to_extend_transaction(handle, inode)) {
+               if (bh) {
+                       BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
+                       err = ext4_handle_dirty_metadata(handle, inode, bh);
+                       if (unlikely(err))
+                               goto out_err;
+               }
+               err = ext4_mark_inode_dirty(handle, inode);
+               if (unlikely(err))
+                       goto out_err;
+               err = ext4_truncate_restart_trans(handle, inode,
+                                       ext4_blocks_for_truncate(inode));
+               if (unlikely(err))
+                       goto out_err;
+               if (bh) {
+                       BUFFER_TRACE(bh, "retaking write access");
+                       err = ext4_journal_get_write_access(handle, bh);
+                       if (unlikely(err))
+                               goto out_err;
+               }
+       }
+
+       for (p = first; p < last; p++)
+               *p = 0;
+
+       ext4_free_blocks(handle, inode, NULL, block_to_free, count, flags);
+       return 0;
+out_err:
+       ext4_std_error(inode->i_sb, err);
+       return err;
+}
+
+/**
+ * ext4_free_data - free a list of data blocks
+ * @handle:    handle for this transaction
+ * @inode:     inode we are dealing with
+ * @this_bh:   indirect buffer_head which contains *@first and *@last
+ * @first:     array of block numbers
+ * @last:      points immediately past the end of array
+ *
+ * We are freeing all blocks referred from that array (numbers are stored as
+ * little-endian 32-bit) and updating @inode->i_blocks appropriately.
+ *
+ * We accumulate contiguous runs of blocks to free.  Conveniently, if these
+ * blocks are contiguous then releasing them at one time will only affect one
+ * or two bitmap blocks (+ group descriptor(s) and superblock) and we won't
+ * actually use a lot of journal space.
+ *
+ * @this_bh will be %NULL if @first and @last point into the inode's direct
+ * block pointers.
+ */
+static void ext4_free_data(handle_t *handle, struct inode *inode,
+                          struct buffer_head *this_bh,
+                          __le32 *first, __le32 *last)
+{
+       ext4_fsblk_t block_to_free = 0;    /* Starting block # of a run */
+       unsigned long count = 0;            /* Number of blocks in the run */
+       __le32 *block_to_free_p = NULL;     /* Pointer into inode/ind
+                                              corresponding to
+                                              block_to_free */
+       ext4_fsblk_t nr;                    /* Current block # */
+       __le32 *p;                          /* Pointer into inode/ind
+                                              for current block */
+       int err = 0;
+
+       if (this_bh) {                          /* For indirect block */
+               BUFFER_TRACE(this_bh, "get_write_access");
+               err = ext4_journal_get_write_access(handle, this_bh);
+               /* Important: if we can't update the indirect pointers
+                * to the blocks, we can't free them. */
+               if (err)
+                       return;
+       }
+
+       for (p = first; p < last; p++) {
+               nr = le32_to_cpu(*p);
+               if (nr) {
+                       /* accumulate blocks to free if they're contiguous */
+                       if (count == 0) {
+                               block_to_free = nr;
+                               block_to_free_p = p;
+                               count = 1;
+                       } else if (nr == block_to_free + count) {
+                               count++;
+                       } else {
+                               err = ext4_clear_blocks(handle, inode, this_bh,
+                                                       block_to_free, count,
+                                                       block_to_free_p, p);
+                               if (err)
+                                       break;
+                               block_to_free = nr;
+                               block_to_free_p = p;
+                               count = 1;
+                       }
+               }
+       }
+
+       if (!err && count > 0)
+               err = ext4_clear_blocks(handle, inode, this_bh, block_to_free,
+                                       count, block_to_free_p, p);
+       if (err < 0)
+               /* fatal error */
+               return;
+
+       if (this_bh) {
+               BUFFER_TRACE(this_bh, "call ext4_handle_dirty_metadata");
+
+               /*
+                * The buffer head should have an attached journal head at this
+                * point. However, if the data is corrupted and an indirect
+                * block pointed to itself, it would have been detached when
+                * the block was cleared. Check for this instead of OOPSing.
+                */
+               if ((EXT4_JOURNAL(inode) == NULL) || bh2jh(this_bh))
+                       ext4_handle_dirty_metadata(handle, inode, this_bh);
+               else
+                       EXT4_ERROR_INODE(inode,
+                                        "circular indirect block detected at "
+                                        "block %llu",
+                               (unsigned long long) this_bh->b_blocknr);
+       }
+}
+
+/**
+ *     ext4_free_branches - free an array of branches
+ *     @handle: JBD handle for this transaction
+ *     @inode: inode we are dealing with
+ *     @parent_bh: the buffer_head which contains *@first and *@last
+ *     @first: array of block numbers
+ *     @last:  pointer immediately past the end of array
+ *     @depth: depth of the branches to free
+ *
+ *     We are freeing all blocks referred from these branches (numbers are
+ *     stored as little-endian 32-bit) and updating @inode->i_blocks
+ *     appropriately.
+ */
+static void ext4_free_branches(handle_t *handle, struct inode *inode,
+                              struct buffer_head *parent_bh,
+                              __le32 *first, __le32 *last, int depth)
+{
+       ext4_fsblk_t nr;
+       __le32 *p;
+
+       if (ext4_handle_is_aborted(handle))
+               return;
+
+       if (depth--) {
+               struct buffer_head *bh;
+               int addr_per_block = EXT4_ADDR_PER_BLOCK(inode->i_sb);
+               p = last;
+               while (--p >= first) {
+                       nr = le32_to_cpu(*p);
+                       if (!nr)
+                               continue;               /* A hole */
+
+                       if (!ext4_data_block_valid(EXT4_SB(inode->i_sb),
+                                                  nr, 1)) {
+                               EXT4_ERROR_INODE(inode,
+                                                "invalid indirect mapped "
+                                                "block %lu (level %d)",
+                                                (unsigned long) nr, depth);
+                               break;
+                       }
+
+                       /* Go read the buffer for the next level down */
+                       bh = sb_bread(inode->i_sb, nr);
+
+                       /*
+                        * A read failure? Report error and clear slot
+                        * (should be rare).
+                        */
+                       if (!bh) {
+                               EXT4_ERROR_INODE_BLOCK(inode, nr,
+                                                      "Read failure");
+                               continue;
+                       }
+
+                       /* This zaps the entire block.  Bottom up. */
+                       BUFFER_TRACE(bh, "free child branches");
+                       ext4_free_branches(handle, inode, bh,
+                                       (__le32 *) bh->b_data,
+                                       (__le32 *) bh->b_data + addr_per_block,
+                                       depth);
+                       brelse(bh);
+
+                       /*
+                        * Everything below this this pointer has been
+                        * released.  Now let this top-of-subtree go.
+                        *
+                        * We want the freeing of this indirect block to be
+                        * atomic in the journal with the updating of the
+                        * bitmap block which owns it.  So make some room in
+                        * the journal.
+                        *
+                        * We zero the parent pointer *after* freeing its
+                        * pointee in the bitmaps, so if extend_transaction()
+                        * for some reason fails to put the bitmap changes and
+                        * the release into the same transaction, recovery
+                        * will merely complain about releasing a free block,
+                        * rather than leaking blocks.
+                        */
+                       if (ext4_handle_is_aborted(handle))
+                               return;
+                       if (try_to_extend_transaction(handle, inode)) {
+                               ext4_mark_inode_dirty(handle, inode);
+                               ext4_truncate_restart_trans(handle, inode,
+                                           ext4_blocks_for_truncate(inode));
+                       }
+
+                       /*
+                        * The forget flag here is critical because if
+                        * we are journaling (and not doing data
+                        * journaling), we have to make sure a revoke
+                        * record is written to prevent the journal
+                        * replay from overwriting the (former)
+                        * indirect block if it gets reallocated as a
+                        * data block.  This must happen in the same
+                        * transaction where the data blocks are
+                        * actually freed.
+                        */
+                       ext4_free_blocks(handle, inode, NULL, nr, 1,
+                                        EXT4_FREE_BLOCKS_METADATA|
+                                        EXT4_FREE_BLOCKS_FORGET);
+
+                       if (parent_bh) {
+                               /*
+                                * The block which we have just freed is
+                                * pointed to by an indirect block: journal it
+                                */
+                               BUFFER_TRACE(parent_bh, "get_write_access");
+                               if (!ext4_journal_get_write_access(handle,
+                                                                  parent_bh)){
+                                       *p = 0;
+                                       BUFFER_TRACE(parent_bh,
+                                       "call ext4_handle_dirty_metadata");
+                                       ext4_handle_dirty_metadata(handle,
+                                                                  inode,
+                                                                  parent_bh);
+                               }
+                       }
+               }
+       } else {
+               /* We have reached the bottom of the tree. */
+               BUFFER_TRACE(parent_bh, "free data blocks");
+               ext4_free_data(handle, inode, parent_bh, first, last);
+       }
+}
+
+void ext4_ind_truncate(struct inode *inode)
+{
+       handle_t *handle;
+       struct ext4_inode_info *ei = EXT4_I(inode);
+       __le32 *i_data = ei->i_data;
+       int addr_per_block = EXT4_ADDR_PER_BLOCK(inode->i_sb);
+       struct address_space *mapping = inode->i_mapping;
+       ext4_lblk_t offsets[4];
+       Indirect chain[4];
+       Indirect *partial;
+       __le32 nr = 0;
+       int n = 0;
+       ext4_lblk_t last_block, max_block;
+       unsigned blocksize = inode->i_sb->s_blocksize;
+
+       handle = start_transaction(inode);
+       if (IS_ERR(handle))
+               return;         /* AKPM: return what? */
+
+       last_block = (inode->i_size + blocksize-1)
+                                       >> EXT4_BLOCK_SIZE_BITS(inode->i_sb);
+       max_block = (EXT4_SB(inode->i_sb)->s_bitmap_maxbytes + blocksize-1)
+                                       >> EXT4_BLOCK_SIZE_BITS(inode->i_sb);
+
+       if (inode->i_size & (blocksize - 1))
+               if (ext4_block_truncate_page(handle, mapping, inode->i_size))
+                       goto out_stop;
+
+       if (last_block != max_block) {
+               n = ext4_block_to_path(inode, last_block, offsets, NULL);
+               if (n == 0)
+                       goto out_stop;  /* error */
+       }
+
+       /*
+        * OK.  This truncate is going to happen.  We add the inode to the
+        * orphan list, so that if this truncate spans multiple transactions,
+        * and we crash, we will resume the truncate when the filesystem
+        * recovers.  It also marks the inode dirty, to catch the new size.
+        *
+        * Implication: the file must always be in a sane, consistent
+        * truncatable state while each transaction commits.
+        */
+       if (ext4_orphan_add(handle, inode))
+               goto out_stop;
+
+       /*
+        * From here we block out all ext4_get_block() callers who want to
+        * modify the block allocation tree.
+        */
+       down_write(&ei->i_data_sem);
+
+       ext4_discard_preallocations(inode);
+
+       /*
+        * The orphan list entry will now protect us from any crash which
+        * occurs before the truncate completes, so it is now safe to propagate
+        * the new, shorter inode size (held for now in i_size) into the
+        * on-disk inode. We do this via i_disksize, which is the value which
+        * ext4 *really* writes onto the disk inode.
+        */
+       ei->i_disksize = inode->i_size;
+
+       if (last_block == max_block) {
+               /*
+                * It is unnecessary to free any data blocks if last_block is
+                * equal to the indirect block limit.
+                */
+               goto out_unlock;
+       } else if (n == 1) {            /* direct blocks */
+               ext4_free_data(handle, inode, NULL, i_data+offsets[0],
+                              i_data + EXT4_NDIR_BLOCKS);
+               goto do_indirects;
+       }
+
+       partial = ext4_find_shared(inode, n, offsets, chain, &nr);
+       /* Kill the top of shared branch (not detached) */
+       if (nr) {
+               if (partial == chain) {
+                       /* Shared branch grows from the inode */
+                       ext4_free_branches(handle, inode, NULL,
+                                          &nr, &nr+1, (chain+n-1) - partial);
+                       *partial->p = 0;
+                       /*
+                        * We mark the inode dirty prior to restart,
+                        * and prior to stop.  No need for it here.
+                        */
+               } else {
+                       /* Shared branch grows from an indirect block */
+                       BUFFER_TRACE(partial->bh, "get_write_access");
+                       ext4_free_branches(handle, inode, partial->bh,
+                                       partial->p,
+                                       partial->p+1, (chain+n-1) - partial);
+               }
+       }
+       /* Clear the ends of indirect blocks on the shared branch */
+       while (partial > chain) {
+               ext4_free_branches(handle, inode, partial->bh, partial->p + 1,
+                                  (__le32*)partial->bh->b_data+addr_per_block,
+                                  (chain+n-1) - partial);
+               BUFFER_TRACE(partial->bh, "call brelse");
+               brelse(partial->bh);
+               partial--;
+       }
+do_indirects:
+       /* Kill the remaining (whole) subtrees */
+       switch (offsets[0]) {
+       default:
+               nr = i_data[EXT4_IND_BLOCK];
+               if (nr) {
+                       ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 1);
+                       i_data[EXT4_IND_BLOCK] = 0;
+               }
+       case EXT4_IND_BLOCK:
+               nr = i_data[EXT4_DIND_BLOCK];
+               if (nr) {
+                       ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 2);
+                       i_data[EXT4_DIND_BLOCK] = 0;
+               }
+       case EXT4_DIND_BLOCK:
+               nr = i_data[EXT4_TIND_BLOCK];
+               if (nr) {
+                       ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 3);
+                       i_data[EXT4_TIND_BLOCK] = 0;
+               }
+       case EXT4_TIND_BLOCK:
+               ;
+       }
+
+out_unlock:
+       up_write(&ei->i_data_sem);
+       inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
+       ext4_mark_inode_dirty(handle, inode);
+
+       /*
+        * In a multi-transaction truncate, we only make the final transaction
+        * synchronous
+        */
+       if (IS_SYNC(inode))
+               ext4_handle_sync(handle);
+out_stop:
+       /*
+        * If this was a simple ftruncate(), and the file will remain alive
+        * then we need to clear up the orphan record which we created above.
+        * However, if this was a real unlink then we were called by
+        * ext4_delete_inode(), and we allow that function to clean up the
+        * orphan info for us.
+        */
+       if (inode->i_nlink)
+               ext4_orphan_del(handle, inode);
+
+       ext4_journal_stop(handle);
+       trace_ext4_truncate_exit(inode);
+}
+
index 3e5191f..c4da98a 100644 (file)
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *
- *  Goal-directed block allocation by Stephen Tweedie
- *     (sct@redhat.com), 1993, 1998
- *  Big-endian to little-endian byte-swapping/bitmaps by
- *        David S. Miller (davem@caip.rutgers.edu), 1995
  *  64-bit file support on 64-bit platforms by Jakub Jelinek
  *     (jj@sunsite.ms.mff.cuni.cz)
  *
@@ -47,6 +43,7 @@
 #include "xattr.h"
 #include "acl.h"
 #include "ext4_extents.h"
+#include "truncate.h"
 
 #include <trace/events/ext4.h>
 
@@ -88,72 +85,6 @@ static int ext4_inode_is_fast_symlink(struct inode *inode)
        return (S_ISLNK(inode->i_mode) && inode->i_blocks - ea_blocks == 0);
 }
 
-/*
- * Work out how many blocks we need to proceed with the next chunk of a
- * truncate transaction.
- */
-static unsigned long blocks_for_truncate(struct inode *inode)
-{
-       ext4_lblk_t needed;
-
-       needed = inode->i_blocks >> (inode->i_sb->s_blocksize_bits - 9);
-
-       /* Give ourselves just enough room to cope with inodes in which
-        * i_blocks is corrupt: we've seen disk corruptions in the past
-        * which resulted in random data in an inode which looked enough
-        * like a regular file for ext4 to try to delete it.  Things
-        * will go a bit crazy if that happens, but at least we should
-        * try not to panic the whole kernel. */
-       if (needed < 2)
-               needed = 2;
-
-       /* But we need to bound the transaction so we don't overflow the
-        * journal. */
-       if (needed > EXT4_MAX_TRANS_DATA)
-               needed = EXT4_MAX_TRANS_DATA;
-
-       return EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + needed;
-}
-
-/*
- * Truncate transactions can be complex and absolutely huge.  So we need to
- * be able to restart the transaction at a conventient checkpoint to make
- * sure we don't overflow the journal.
- *
- * start_transaction gets us a new handle for a truncate transaction,
- * and extend_transaction tries to extend the existing one a bit.  If
- * extend fails, we need to propagate the failure up and restart the
- * transaction in the top-level truncate loop. --sct
- */
-static handle_t *start_transaction(struct inode *inode)
-{
-       handle_t *result;
-
-       result = ext4_journal_start(inode, blocks_for_truncate(inode));
-       if (!IS_ERR(result))
-               return result;
-
-       ext4_std_error(inode->i_sb, PTR_ERR(result));
-       return result;
-}
-
-/*
- * Try to extend this transaction for the purposes of truncation.
- *
- * Returns 0 if we managed to create more room.  If we can't create more
- * room, and the transaction must be restarted we return 1.
- */
-static int try_to_extend_transaction(handle_t *handle, struct inode *inode)
-{
-       if (!ext4_handle_valid(handle))
-               return 0;
-       if (ext4_handle_has_enough_credits(handle, EXT4_RESERVE_TRANS_BLOCKS+1))
-               return 0;
-       if (!ext4_journal_extend(handle, blocks_for_truncate(inode)))
-               return 0;
-       return 1;
-}
-
 /*
  * Restart the transaction associated with *handle.  This does a commit,
  * so before we call here everything must be consistently dirtied against
@@ -189,7 +120,40 @@ void ext4_evict_inode(struct inode *inode)
        int err;
 
        trace_ext4_evict_inode(inode);
+
+       mutex_lock(&inode->i_mutex);
+       ext4_flush_completed_IO(inode);
+       mutex_unlock(&inode->i_mutex);
+       ext4_ioend_wait(inode);
+
        if (inode->i_nlink) {
+               /*
+                * When journalling data dirty buffers are tracked only in the
+                * journal. So although mm thinks everything is clean and
+                * ready for reaping the inode might still have some pages to
+                * write in the running transaction or waiting to be
+                * checkpointed. Thus calling jbd2_journal_invalidatepage()
+                * (via truncate_inode_pages()) to discard these buffers can
+                * cause data loss. Also even if we did not discard these
+                * buffers, we would have no way to find them after the inode
+                * is reaped and thus user could see stale data if he tries to
+                * read them before the transaction is checkpointed. So be
+                * careful and force everything to disk here... We use
+                * ei->i_datasync_tid to store the newest transaction
+                * containing inode's data.
+                *
+                * Note that directories do not have this problem because they
+                * don't use page cache.
+                */
+               if (ext4_should_journal_data(inode) &&
+                   (S_ISLNK(inode->i_mode) || S_ISREG(inode->i_mode))) {
+                       journal_t *journal = EXT4_SB(inode->i_sb)->s_journal;
+                       tid_t commit_tid = EXT4_I(inode)->i_datasync_tid;
+
+                       jbd2_log_start_commit(journal, commit_tid);
+                       jbd2_log_wait_commit(journal, commit_tid);
+                       filemap_write_and_wait(&inode->i_data);
+               }
                truncate_inode_pages(&inode->i_data, 0);
                goto no_delete;
        }
@@ -204,7 +168,7 @@ void ext4_evict_inode(struct inode *inode)
        if (is_bad_inode(inode))
                goto no_delete;
 
-       handle = ext4_journal_start(inode, blocks_for_truncate(inode)+3);
+       handle = ext4_journal_start(inode, ext4_blocks_for_truncate(inode)+3);
        if (IS_ERR(handle)) {
                ext4_std_error(inode->i_sb, PTR_ERR(handle));
                /*
@@ -277,793 +241,6 @@ no_delete:
        ext4_clear_inode(inode);        /* We must guarantee clearing of inode... */
 }
 
-typedef struct {
-       __le32  *p;
-       __le32  key;
-       struct buffer_head *bh;
-} Indirect;
-
-static inline void add_chain(Indirect *p, struct buffer_head *bh, __le32 *v)
-{
-       p->key = *(p->p = v);
-       p->bh = bh;
-}
-
-/**
- *     ext4_block_to_path - parse the block number into array of offsets
- *     @inode: inode in question (we are only interested in its superblock)
- *     @i_block: block number to be parsed
- *     @offsets: array to store the offsets in
- *     @boundary: set this non-zero if the referred-to block is likely to be
- *            followed (on disk) by an indirect block.
- *
- *     To store the locations of file's data ext4 uses a data structure common
- *     for UNIX filesystems - tree of pointers anchored in the inode, with
- *     data blocks at leaves and indirect blocks in intermediate nodes.
- *     This function translates the block number into path in that tree -
- *     return value is the path length and @offsets[n] is the offset of
- *     pointer to (n+1)th node in the nth one. If @block is out of range
- *     (negative or too large) warning is printed and zero returned.
- *
- *     Note: function doesn't find node addresses, so no IO is needed. All
- *     we need to know is the capacity of indirect blocks (taken from the
- *     inode->i_sb).
- */
-
-/*
- * Portability note: the last comparison (check that we fit into triple
- * indirect block) is spelled differently, because otherwise on an
- * architecture with 32-bit longs and 8Kb pages we might get into trouble
- * if our filesystem had 8Kb blocks. We might use long long, but that would
- * kill us on x86. Oh, well, at least the sign propagation does not matter -
- * i_block would have to be negative in the very beginning, so we would not
- * get there at all.
- */
-
-static int ext4_block_to_path(struct inode *inode,
-                             ext4_lblk_t i_block,
-                             ext4_lblk_t offsets[4], int *boundary)
-{
-       int ptrs = EXT4_ADDR_PER_BLOCK(inode->i_sb);
-       int ptrs_bits = EXT4_ADDR_PER_BLOCK_BITS(inode->i_sb);
-       const long direct_blocks = EXT4_NDIR_BLOCKS,
-               indirect_blocks = ptrs,
-               double_blocks = (1 << (ptrs_bits * 2));
-       int n = 0;
-       int final = 0;
-
-       if (i_block < direct_blocks) {
-               offsets[n++] = i_block;
-               final = direct_blocks;
-       } else if ((i_block -= direct_blocks) < indirect_blocks) {
-               offsets[n++] = EXT4_IND_BLOCK;
-               offsets[n++] = i_block;
-               final = ptrs;
-       } else if ((i_block -= indirect_blocks) < double_blocks) {
-               offsets[n++] = EXT4_DIND_BLOCK;
-               offsets[n++] = i_block >> ptrs_bits;
-               offsets[n++] = i_block & (ptrs - 1);
-               final = ptrs;
-       } else if (((i_block -= double_blocks) >> (ptrs_bits * 2)) < ptrs) {
-               offsets[n++] = EXT4_TIND_BLOCK;
-               offsets[n++] = i_block >> (ptrs_bits * 2);
-               offsets[n++] = (i_block >> ptrs_bits) & (ptrs - 1);
-               offsets[n++] = i_block & (ptrs - 1);
-               final = ptrs;
-       } else {
-               ext4_warning(inode->i_sb, "block %lu > max in inode %lu",
-                            i_block + direct_blocks +
-                            indirect_blocks + double_blocks, inode->i_ino);
-       }
-       if (boundary)
-               *boundary = final - 1 - (i_block & (ptrs - 1));
-       return n;
-}
-
-static int __ext4_check_blockref(const char *function, unsigned int line,
-                                struct inode *inode,
-                                __le32 *p, unsigned int max)
-{
-       struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
-       __le32 *bref = p;
-       unsigned int blk;
-
-       while (bref < p+max) {
-               blk = le32_to_cpu(*bref++);
-               if (blk &&
-                   unlikely(!ext4_data_block_valid(EXT4_SB(inode->i_sb),
-                                                   blk, 1))) {
-                       es->s_last_error_block = cpu_to_le64(blk);
-                       ext4_error_inode(inode, function, line, blk,
-                                        "invalid block");
-                       return -EIO;
-               }
-       }
-       return 0;
-}
-
-
-#define ext4_check_indirect_blockref(inode, bh)                         \
-       __ext4_check_blockref(__func__, __LINE__, inode,                \
-                             (__le32 *)(bh)->b_data,                   \
-                             EXT4_ADDR_PER_BLOCK((inode)->i_sb))
-
-#define ext4_check_inode_blockref(inode)                                \
-       __ext4_check_blockref(__func__, __LINE__, inode,                \
-                             EXT4_I(inode)->i_data,                    \
-                             EXT4_NDIR_BLOCKS)
-
-/**
- *     ext4_get_branch - read the chain of indirect blocks leading to data
- *     @inode: inode in question
- *     @depth: depth of the chain (1 - direct pointer, etc.)
- *     @offsets: offsets of pointers in inode/indirect blocks
- *     @chain: place to store the result
- *     @err: here we store the error value
- *
- *     Function fills the array of triples <key, p, bh> and returns %NULL
- *     if everything went OK or the pointer to the last filled triple
- *     (incomplete one) otherwise. Upon the return chain[i].key contains
- *     the number of (i+1)-th block in the chain (as it is stored in memory,
- *     i.e. little-endian 32-bit), chain[i].p contains the address of that
- *     number (it points into struct inode for i==0 and into the bh->b_data
- *     for i>0) and chain[i].bh points to the buffer_head of i-th indirect
- *     block for i>0 and NULL for i==0. In other words, it holds the block
- *     numbers of the chain, addresses they were taken from (and where we can
- *     verify that chain did not change) and buffer_heads hosting these
- *     numbers.
- *
- *     Function stops when it stumbles upon zero pointer (absent block)
- *             (pointer to last triple returned, *@err == 0)
- *     or when it gets an IO error reading an indirect block
- *             (ditto, *@err == -EIO)
- *     or when it reads all @depth-1 indirect blocks successfully and finds
- *     the whole chain, all way to the data (returns %NULL, *err == 0).
- *
- *      Need to be called with
- *      down_read(&EXT4_I(inode)->i_data_sem)
- */
-static Indirect *ext4_get_branch(struct inode *inode, int depth,
-                                ext4_lblk_t  *offsets,
-                                Indirect chain[4], int *err)
-{
-       struct super_block *sb = inode->i_sb;
-       Indirect *p = chain;
-       struct buffer_head *bh;
-
-       *err = 0;
-       /* i_data is not going away, no lock needed */
-       add_chain(chain, NULL, EXT4_I(inode)->i_data + *offsets);
-       if (!p->key)
-               goto no_block;
-       while (--depth) {
-               bh = sb_getblk(sb, le32_to_cpu(p->key));
-               if (unlikely(!bh))
-                       goto failure;
-
-               if (!bh_uptodate_or_lock(bh)) {
-                       if (bh_submit_read(bh) < 0) {
-                               put_bh(bh);
-                               goto failure;
-                       }
-                       /* validate block references */
-                       if (ext4_check_indirect_blockref(inode, bh)) {
-                               put_bh(bh);
-                               goto failure;
-                       }
-               }
-
-               add_chain(++p, bh, (__le32 *)bh->b_data + *++offsets);
-               /* Reader: end */
-               if (!p->key)
-                       goto no_block;
-       }
-       return NULL;
-
-failure:
-       *err = -EIO;
-no_block:
-       return p;
-}
-
-/**
- *     ext4_find_near - find a place for allocation with sufficient locality
- *     @inode: owner
- *     @ind: descriptor of indirect block.
- *
- *     This function returns the preferred place for block allocation.
- *     It is used when heuristic for sequential allocation fails.
- *     Rules are:
- *       + if there is a block to the left of our position - allocate near it.
- *       + if pointer will live in indirect block - allocate near that block.
- *       + if pointer will live in inode - allocate in the same
- *         cylinder group.
- *
- * In the latter case we colour the starting block by the callers PID to
- * prevent it from clashing with concurrent allocations for a different inode
- * in the same block group.   The PID is used here so that functionally related
- * files will be close-by on-disk.
- *
- *     Caller must make sure that @ind is valid and will stay that way.
- */
-static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind)
-{
-       struct ext4_inode_info *ei = EXT4_I(inode);
-       __le32 *start = ind->bh ? (__le32 *) ind->bh->b_data : ei->i_data;
-       __le32 *p;
-       ext4_fsblk_t bg_start;
-       ext4_fsblk_t last_block;
-       ext4_grpblk_t colour;
-       ext4_group_t block_group;
-       int flex_size = ext4_flex_bg_size(EXT4_SB(inode->i_sb));
-
-       /* Try to find previous block */
-       for (p = ind->p - 1; p >= start; p--) {
-               if (*p)
-                       return le32_to_cpu(*p);
-       }
-
-       /* No such thing, so let's try location of indirect block */
-       if (ind->bh)
-               return ind->bh->b_blocknr;
-
-       /*
-        * It is going to be referred to from the inode itself? OK, just put it
-        * into the same cylinder group then.
-        */
-       block_group = ei->i_block_group;
-       if (flex_size >= EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME) {
-               block_group &= ~(flex_size-1);
-               if (S_ISREG(inode->i_mode))
-                       block_group++;
-       }
-       bg_start = ext4_group_first_block_no(inode->i_sb, block_group);
-       last_block = ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es) - 1;
-
-       /*
-        * If we are doing delayed allocation, we don't need take
-        * colour into account.
-        */
-       if (test_opt(inode->i_sb, DELALLOC))
-               return bg_start;
-
-       if (bg_start + EXT4_BLOCKS_PER_GROUP(inode->i_sb) <= last_block)
-               colour = (current->pid % 16) *
-                       (EXT4_BLOCKS_PER_GROUP(inode->i_sb) / 16);
-       else
-               colour = (current->pid % 16) * ((last_block - bg_start) / 16);
-       return bg_start + colour;
-}
-
-/**
- *     ext4_find_goal - find a preferred place for allocation.
- *     @inode: owner
- *     @block:  block we want
- *     @partial: pointer to the last triple within a chain
- *
- *     Normally this function find the preferred place for block allocation,
- *     returns it.
- *     Because this is only used for non-extent files, we limit the block nr
- *     to 32 bits.
- */
-static ext4_fsblk_t ext4_find_goal(struct inode *inode, ext4_lblk_t block,
-                                  Indirect *partial)
-{
-       ext4_fsblk_t goal;
-
-       /*
-        * XXX need to get goal block from mballoc's data structures
-        */
-
-       goal = ext4_find_near(inode, partial);
-       goal = goal & EXT4_MAX_BLOCK_FILE_PHYS;
-       return goal;
-}
-
-/**
- *     ext4_blks_to_allocate - Look up the block map and count the number
- *     of direct blocks need to be allocated for the given branch.
- *
- *     @branch: chain of indirect blocks
- *     @k: number of blocks need for indirect blocks
- *     @blks: number of data blocks to be mapped.
- *     @blocks_to_boundary:  the offset in the indirect block
- *
- *     return the total number of blocks to be allocate, including the
- *     direct and indirect blocks.
- */
-static int ext4_blks_to_allocate(Indirect *branch, int k, unsigned int blks,
-                                int blocks_to_boundary)
-{
-       unsigned int count = 0;
-
-       /*
-        * Simple case, [t,d]Indirect block(s) has not allocated yet
-        * then it's clear blocks on that path have not allocated
-        */
-       if (k > 0) {
-               /* right now we don't handle cross boundary allocation */
-               if (blks < blocks_to_boundary + 1)
-                       count += blks;
-               else
-                       count += blocks_to_boundary + 1;
-               return count;
-       }
-
-       count++;
-       while (count < blks && count <= blocks_to_boundary &&
-               le32_to_cpu(*(branch[0].p + count)) == 0) {
-               count++;
-       }
-       return count;
-}
-
-/**
- *     ext4_alloc_blocks: multiple allocate blocks needed for a branch
- *     @handle: handle for this transaction
- *     @inode: inode which needs allocated blocks
- *     @iblock: the logical block to start allocated at
- *     @goal: preferred physical block of allocation
- *     @indirect_blks: the number of blocks need to allocate for indirect
- *                     blocks
- *     @blks: number of desired blocks
- *     @new_blocks: on return it will store the new block numbers for
- *     the indirect blocks(if needed) and the first direct block,
- *     @err: on return it will store the error code
- *
- *     This function will return the number of blocks allocated as
- *     requested by the passed-in parameters.
- */
-static int ext4_alloc_blocks(handle_t *handle, struct inode *inode,
-                            ext4_lblk_t iblock, ext4_fsblk_t goal,
-                            int indirect_blks, int blks,
-                            ext4_fsblk_t new_blocks[4], int *err)
-{
-       struct ext4_allocation_request ar;
-       int target, i;
-       unsigned long count = 0, blk_allocated = 0;
-       int index = 0;
-       ext4_fsblk_t current_block = 0;
-       int ret = 0;
-
-       /*
-        * Here we try to allocate the requested multiple blocks at once,
-        * on a best-effort basis.
-        * To build a branch, we should allocate blocks for
-        * the indirect blocks(if not allocated yet), and at least
-        * the first direct block of this branch.  That's the
-        * minimum number of blocks need to allocate(required)
-        */
-       /* first we try to allocate the indirect blocks */
-       target = indirect_blks;
-       while (target > 0) {
-               count = target;
-               /* allocating blocks for indirect blocks and direct blocks */
-               current_block = ext4_new_meta_blocks(handle, inode, goal,
-                                                    0, &count, err);
-               if (*err)
-                       goto failed_out;
-
-               if (unlikely(current_block + count > EXT4_MAX_BLOCK_FILE_PHYS)) {
-                       EXT4_ERROR_INODE(inode,
-                                        "current_block %llu + count %lu > %d!",
-                                        current_block, count,
-                                        EXT4_MAX_BLOCK_FILE_PHYS);
-                       *err = -EIO;
-                       goto failed_out;
-               }
-
-               target -= count;
-               /* allocate blocks for indirect blocks */
-               while (index < indirect_blks && count) {
-                       new_blocks[index++] = current_block++;
-                       count--;
-               }
-               if (count > 0) {
-                       /*
-                        * save the new block number
-                        * for the first direct block
-                        */
-                       new_blocks[index] = current_block;
-                       printk(KERN_INFO "%s returned more blocks than "
-                                               "requested\n", __func__);
-                       WARN_ON(1);
-                       break;
-               }
-       }
-
-       target = blks - count ;
-       blk_allocated = count;
-       if (!target)
-               goto allocated;
-       /* Now allocate data blocks */
-       memset(&ar, 0, sizeof(ar));
-       ar.inode = inode;
-       ar.goal = goal;
-       ar.len = target;
-       ar.logical = iblock;
-       if (S_ISREG(inode->i_mode))
-               /* enable in-core preallocation only for regular files */
-               ar.flags = EXT4_MB_HINT_DATA;
-
-       current_block = ext4_mb_new_blocks(handle, &ar, err);
-       if (unlikely(current_block + ar.len > EXT4_MAX_BLOCK_FILE_PHYS)) {
-               EXT4_ERROR_INODE(inode,
-                                "current_block %llu + ar.len %d > %d!",
-                                current_block, ar.len,
-                                EXT4_MAX_BLOCK_FILE_PHYS);
-               *err = -EIO;
-               goto failed_out;
-       }
-
-       if (*err && (target == blks)) {
-               /*
-                * if the allocation failed and we didn't allocate
-                * any blocks before
-                */
-               goto failed_out;
-       }
-       if (!*err) {
-               if (target == blks) {
-                       /*
-                        * save the new block number
-                        * for the first direct block
-                        */
-                       new_blocks[index] = current_block;
-               }
-               blk_allocated += ar.len;
-       }
-allocated:
-       /* total number of blocks allocated for direct blocks */
-       ret = blk_allocated;
-       *err = 0;
-       return ret;
-failed_out:
-       for (i = 0; i < index; i++)
-               ext4_free_blocks(handle, inode, NULL, new_blocks[i], 1, 0);
-       return ret;
-}
-
-/**
- *     ext4_alloc_branch - allocate and set up a chain of blocks.
- *     @handle: handle for this transaction
- *     @inode: owner
- *     @indirect_blks: number of allocated indirect blocks
- *     @blks: number of allocated direct blocks
- *     @goal: preferred place for allocation
- *     @offsets: offsets (in the blocks) to store the pointers to next.
- *     @branch: place to store the chain in.
- *
- *     This function allocates blocks, zeroes out all but the last one,
- *     links them into chain and (if we are synchronous) writes them to disk.
- *     In other words, it prepares a branch that can be spliced onto the
- *     inode. It stores the information about that chain in the branch[], in
- *     the same format as ext4_get_branch() would do. We are calling it after
- *     we had read the existing part of chain and partial points to the last
- *     triple of that (one with zero ->key). Upon the exit we have the same
- *     picture as after the successful ext4_get_block(), except that in one
- *     place chain is disconnected - *branch->p is still zero (we did not
- *     set the last link), but branch->key contains the number that should
- *     be placed into *branch->p to fill that gap.
- *
- *     If allocation fails we free all blocks we've allocated (and forget
- *     their buffer_heads) and return the error value the from failed
- *     ext4_alloc_block() (normally -ENOSPC). Otherwise we set the chain
- *     as described above and return 0.
- */
-static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
-                            ext4_lblk_t iblock, int indirect_blks,
-                            int *blks, ext4_fsblk_t goal,
-                            ext4_lblk_t *offsets, Indirect *branch)
-{
-       int blocksize = inode->i_sb->s_blocksize;
-       int i, n = 0;
-       int err = 0;
-       struct buffer_head *bh;
-       int num;
-       ext4_fsblk_t new_blocks[4];
-       ext4_fsblk_t current_block;
-
-       num = ext4_alloc_blocks(handle, inode, iblock, goal, indirect_blks,
-                               *blks, new_blocks, &err);
-       if (err)
-               return err;
-
-       branch[0].key = cpu_to_le32(new_blocks[0]);
-       /*
-        * metadata blocks and data blocks are allocated.
-        */
-       for (n = 1; n <= indirect_blks;  n++) {
-               /*
-                * Get buffer_head for parent block, zero it out
-                * and set the pointer to new one, then send
-                * parent to disk.
-                */
-               bh = sb_getblk(inode->i_sb, new_blocks[n-1]);
-               if (unlikely(!bh)) {
-                       err = -EIO;
-                       goto failed;
-               }
-
-               branch[n].bh = bh;
-               lock_buffer(bh);
-               BUFFER_TRACE(bh, "call get_create_access");
-               err = ext4_journal_get_create_access(handle, bh);
-               if (err) {
-                       /* Don't brelse(bh) here; it's done in
-                        * ext4_journal_forget() below */
-                       unlock_buffer(bh);
-                       goto failed;
-               }
-
-               memset(bh->b_data, 0, blocksize);
-               branch[n].p = (__le32 *) bh->b_data + offsets[n];
-               branch[n].key = cpu_to_le32(new_blocks[n]);
-               *branch[n].p = branch[n].key;
-               if (n == indirect_blks) {
-                       current_block = new_blocks[n];
-                       /*
-                        * End of chain, update the last new metablock of
-                        * the chain to point to the new allocated
-                        * data blocks numbers
-                        */
-                       for (i = 1; i < num; i++)
-                               *(branch[n].p + i) = cpu_to_le32(++current_block);
-               }
-               BUFFER_TRACE(bh, "marking uptodate");
-               set_buffer_uptodate(bh);
-               unlock_buffer(bh);
-
-               BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
-               err = ext4_handle_dirty_metadata(handle, inode, bh);
-               if (err)
-                       goto failed;
-       }
-       *blks = num;
-       return err;
-failed:
-       /* Allocation failed, free what we already allocated */
-       ext4_free_blocks(handle, inode, NULL, new_blocks[0], 1, 0);
-       for (i = 1; i <= n ; i++) {
-               /*
-                * branch[i].bh is newly allocated, so there is no
-                * need to revoke the block, which is why we don't
-                * need to set EXT4_FREE_BLOCKS_METADATA.
-                */
-               ext4_free_blocks(handle, inode, NULL, new_blocks[i], 1,
-                                EXT4_FREE_BLOCKS_FORGET);
-       }
-       for (i = n+1; i < indirect_blks; i++)
-               ext4_free_blocks(handle, inode, NULL, new_blocks[i], 1, 0);
-
-       ext4_free_blocks(handle, inode, NULL, new_blocks[i], num, 0);
-
-       return err;
-}
-
-/**
- * ext4_splice_branch - splice the allocated branch onto inode.
- * @handle: handle for this transaction
- * @inode: owner
- * @block: (logical) number of block we are adding
- * @chain: chain of indirect blocks (with a missing link - see
- *     ext4_alloc_branch)
- * @where: location of missing link
- * @num:   number of indirect blocks we are adding
- * @blks:  number of direct blocks we are adding
- *
- * This function fills the missing link and does all housekeeping needed in
- * inode (->i_blocks, etc.). In case of success we end up with the full
- * chain to new block and return 0.
- */
-static int ext4_splice_branch(handle_t *handle, struct inode *inode,
-                             ext4_lblk_t block, Indirect *where, int num,
-                             int blks)
-{
-       int i;
-       int err = 0;
-       ext4_fsblk_t current_block;
-
-       /*
-        * If we're splicing into a [td]indirect block (as opposed to the
-        * inode) then we need to get write access to the [td]indirect block
-        * before the splice.
-        */
-       if (where->bh) {
-               BUFFER_TRACE(where->bh, "get_write_access");
-               err = ext4_journal_get_write_access(handle, where->bh);
-               if (err)
-                       goto err_out;
-       }
-       /* That's it */
-
-       *where->p = where->key;
-
-       /*
-        * Update the host buffer_head or inode to point to more just allocated
-        * direct blocks blocks
-        */
-       if (num == 0 && blks > 1) {
-               current_block = le32_to_cpu(where->key) + 1;
-               for (i = 1; i < blks; i++)
-                       *(where->p + i) = cpu_to_le32(current_block++);
-       }
-
-       /* We are done with atomic stuff, now do the rest of housekeeping */
-       /* had we spliced it onto indirect block? */
-       if (where->bh) {
-               /*
-                * If we spliced it onto an indirect block, we haven't
-                * altered the inode.  Note however that if it is being spliced
-                * onto an indirect block at the very end of the file (the
-                * file is growing) then we *will* alter the inode to reflect
-                * the new i_size.  But that is not done here - it is done in
-                * generic_commit_write->__mark_inode_dirty->ext4_dirty_inode.
-                */
-               jbd_debug(5, "splicing indirect only\n");
-               BUFFER_TRACE(where->bh, "call ext4_handle_dirty_metadata");
-               err = ext4_handle_dirty_metadata(handle, inode, where->bh);
-               if (err)
-                       goto err_out;
-       } else {
-               /*
-                * OK, we spliced it into the inode itself on a direct block.
-                */
-               ext4_mark_inode_dirty(handle, inode);
-               jbd_debug(5, "splicing direct\n");
-       }
-       return err;
-
-err_out:
-       for (i = 1; i <= num; i++) {
-               /*
-                * branch[i].bh is newly allocated, so there is no
-                * need to revoke the block, which is why we don't
-                * need to set EXT4_FREE_BLOCKS_METADATA.
-                */
-               ext4_free_blocks(handle, inode, where[i].bh, 0, 1,
-                                EXT4_FREE_BLOCKS_FORGET);
-       }
-       ext4_free_blocks(handle, inode, NULL, le32_to_cpu(where[num].key),
-                        blks, 0);
-
-       return err;
-}
-
-/*
- * The ext4_ind_map_blocks() function handles non-extents inodes
- * (i.e., using the traditional indirect/double-indirect i_blocks
- * scheme) for ext4_map_blocks().
- *
- * Allocation strategy is simple: if we have to allocate something, we will
- * have to go the whole way to leaf. So let's do it before attaching anything
- * to tree, set linkage between the newborn blocks, write them if sync is
- * required, recheck the path, free and repeat if check fails, otherwise
- * set the last missing link (that will protect us from any truncate-generated
- * removals - all blocks on the path are immune now) and possibly force the
- * write on the parent block.
- * That has a nice additional property: no special recovery from the failed
- * allocations is needed - we simply release blocks and do not touch anything
- * reachable from inode.
- *
- * `handle' can be NULL if create == 0.
- *
- * return > 0, # of blocks mapped or allocated.
- * return = 0, if plain lookup failed.
- * return < 0, error case.
- *
- * The ext4_ind_get_blocks() function should be called with
- * down_write(&EXT4_I(inode)->i_data_sem) if allocating filesystem
- * blocks (i.e., flags has EXT4_GET_BLOCKS_CREATE set) or
- * down_read(&EXT4_I(inode)->i_data_sem) if not allocating file system
- * blocks.
- */
-static int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
-                              struct ext4_map_blocks *map,
-                              int flags)
-{
-       int err = -EIO;
-       ext4_lblk_t offsets[4];
-       Indirect chain[4];
-       Indirect *partial;
-       ext4_fsblk_t goal;
-       int indirect_blks;
-       int blocks_to_boundary = 0;
-       int depth;
-       int count = 0;
-       ext4_fsblk_t first_block = 0;
-
-       trace_ext4_ind_map_blocks_enter(inode, map->m_lblk, map->m_len, flags);
-       J_ASSERT(!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)));
-       J_ASSERT(handle != NULL || (flags & EXT4_GET_BLOCKS_CREATE) == 0);
-       depth = ext4_block_to_path(inode, map->m_lblk, offsets,
-                                  &blocks_to_boundary);
-
-       if (depth == 0)
-               goto out;
-
-       partial = ext4_get_branch(inode, depth, offsets, chain, &err);
-
-       /* Simplest case - block found, no allocation needed */
-       if (!partial) {
-               first_block = le32_to_cpu(chain[depth - 1].key);
-               count++;
-               /*map more blocks*/
-               while (count < map->m_len && count <= blocks_to_boundary) {
-                       ext4_fsblk_t blk;
-
-                       blk = le32_to_cpu(*(chain[depth-1].p + count));
-
-                       if (blk == first_block + count)
-                               count++;
-                       else
-                               break;
-               }
-               goto got_it;
-       }
-
-       /* Next simple case - plain lookup or failed read of indirect block */
-       if ((flags & EXT4_GET_BLOCKS_CREATE) == 0 || err == -EIO)
-               goto cleanup;
-
-       /*
-        * Okay, we need to do block allocation.
-       */
-       goal = ext4_find_goal(inode, map->m_lblk, partial);
-
-       /* the number of blocks need to allocate for [d,t]indirect blocks */
-       indirect_blks = (chain + depth) - partial - 1;
-
-       /*
-        * Next look up the indirect map to count the totoal number of
-        * direct blocks to allocate for this branch.
-        */
-       count = ext4_blks_to_allocate(partial, indirect_blks,
-                                     map->m_len, blocks_to_boundary);
-       /*
-        * Block out ext4_truncate while we alter the tree
-        */
-       err = ext4_alloc_branch(handle, inode, map->m_lblk, indirect_blks,
-                               &count, goal,
-                               offsets + (partial - chain), partial);
-
-       /*
-        * The ext4_splice_branch call will free and forget any buffers
-        * on the new chain if there is a failure, but that risks using
-        * up transaction credits, especially for bitmaps where the
-        * credits cannot be returned.  Can we handle this somehow?  We
-        * may need to return -EAGAIN upwards in the worst case.  --sct
-        */
-       if (!err)
-               err = ext4_splice_branch(handle, inode, map->m_lblk,
-                                        partial, indirect_blks, count);
-       if (err)
-               goto cleanup;
-
-       map->m_flags |= EXT4_MAP_NEW;
-
-       ext4_update_inode_fsync_trans(handle, inode, 1);
-got_it:
-       map->m_flags |= EXT4_MAP_MAPPED;
-       map->m_pblk = le32_to_cpu(chain[depth-1].key);
-       map->m_len = count;
-       if (count > blocks_to_boundary)
-               map->m_flags |= EXT4_MAP_BOUNDARY;
-       err = count;
-       /* Clean up and exit */
-       partial = chain + depth - 1;    /* the whole chain */
-cleanup:
-       while (partial > chain) {
-               BUFFER_TRACE(partial->bh, "call brelse");
-               brelse(partial->bh);
-               partial--;
-       }
-out:
-       trace_ext4_ind_map_blocks_exit(inode, map->m_lblk,
-                               map->m_pblk, map->m_len, err);
-       return err;
-}
-
 #ifdef CONFIG_QUOTA
 qsize_t *ext4_get_reserved_space(struct inode *inode)
 {
@@ -1071,33 +248,6 @@ qsize_t *ext4_get_reserved_space(struct inode *inode)
 }
 #endif
 
-/*
- * Calculate the number of metadata blocks need to reserve
- * to allocate a new block at @lblocks for non extent file based file
- */
-static int ext4_indirect_calc_metadata_amount(struct inode *inode,
-                                             sector_t lblock)
-{
-       struct ext4_inode_info *ei = EXT4_I(inode);
-       sector_t dind_mask = ~((sector_t)EXT4_ADDR_PER_BLOCK(inode->i_sb) - 1);
-       int blk_bits;
-
-       if (lblock < EXT4_NDIR_BLOCKS)
-               return 0;
-
-       lblock -= EXT4_NDIR_BLOCKS;
-
-       if (ei->i_da_metadata_calc_len &&
-           (lblock & dind_mask) == ei->i_da_metadata_calc_last_lblock) {
-               ei->i_da_metadata_calc_len++;
-               return 0;
-       }
-       ei->i_da_metadata_calc_last_lblock = lblock & dind_mask;
-       ei->i_da_metadata_calc_len = 1;
-       blk_bits = order_base_2(lblock);
-       return (blk_bits / EXT4_ADDR_PER_BLOCK_BITS(inode->i_sb)) + 1;
-}
-
 /*
  * Calculate the number of metadata blocks need to reserve
  * to allocate a block located at @lblock
@@ -1107,7 +257,7 @@ static int ext4_calc_metadata_amount(struct inode *inode, ext4_lblk_t lblock)
        if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
                return ext4_ext_calc_metadata_amount(inode, lblock);
 
-       return ext4_indirect_calc_metadata_amount(inode, lblock);
+       return ext4_ind_calc_metadata_amount(inode, lblock);
 }
 
 /*
@@ -1589,16 +739,6 @@ static int do_journal_get_write_access(handle_t *handle,
        return ret;
 }
 
-/*
- * Truncate blocks that were not used by write. We have to truncate the
- * pagecache as well so that corresponding buffers get properly unmapped.
- */
-static void ext4_truncate_failed_write(struct inode *inode)
-{
-       truncate_inode_pages(inode->i_mapping, inode->i_size);
-       ext4_truncate(inode);
-}
-
 static int ext4_get_block_write(struct inode *inode, sector_t iblock,
                   struct buffer_head *bh_result, int create);
 static int ext4_write_begin(struct file *file, struct address_space *mapping,
@@ -1849,6 +989,8 @@ static int ext4_journalled_write_end(struct file *file,
        from = pos & (PAGE_CACHE_SIZE - 1);
        to = from + len;
 
+       BUG_ON(!ext4_handle_valid(handle));
+
        if (copied < len) {
                if (!PageUptodate(page))
                        copied = 0;
@@ -1863,6 +1005,7 @@ static int ext4_journalled_write_end(struct file *file,
        if (new_i_size > inode->i_size)
                i_size_write(inode, pos+copied);
        ext4_set_inode_state(inode, EXT4_STATE_JDATA);
+       EXT4_I(inode)->i_datasync_tid = handle->h_transaction->t_tid;
        if (new_i_size > EXT4_I(inode)->i_disksize) {
                ext4_update_i_disksize(inode, new_i_size);
                ret2 = ext4_mark_inode_dirty(handle, inode);
@@ -2148,7 +1291,12 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd,
                        else if (test_opt(inode->i_sb, MBLK_IO_SUBMIT))
                                err = ext4_bio_write_page(&io_submit, page,
                                                          len, mpd->wbc);
-                       else
+                       else if (buffer_uninit(page_bufs)) {
+                               ext4_set_bh_endio(page_bufs, inode);
+                               err = block_write_full_page_endio(page,
+                                       noalloc_get_block_write,
+                                       mpd->wbc, ext4_end_io_buffer_write);
+                       } else
                                err = block_write_full_page(page,
                                        noalloc_get_block_write, mpd->wbc);
 
@@ -2564,6 +1712,8 @@ static int __ext4_journalled_writepage(struct page *page,
                goto out;
        }
 
+       BUG_ON(!ext4_handle_valid(handle));
+
        ret = walk_page_buffers(handle, page_bufs, 0, len, NULL,
                                do_journal_get_write_access);
 
@@ -2571,6 +1721,7 @@ static int __ext4_journalled_writepage(struct page *page,
                                write_end_fn);
        if (ret == 0)
                ret = err;
+       EXT4_I(inode)->i_datasync_tid = handle->h_transaction->t_tid;
        err = ext4_journal_stop(handle);
        if (!ret)
                ret = err;
@@ -3449,112 +2600,6 @@ static int ext4_releasepage(struct page *page, gfp_t wait)
                return try_to_free_buffers(page);
 }
 
-/*
- * O_DIRECT for ext3 (or indirect map) based files
- *
- * If the O_DIRECT write will extend the file then add this inode to the
- * orphan list.  So recovery will truncate it back to the original size
- * if the machine crashes during the write.
- *
- * If the O_DIRECT write is intantiating holes inside i_size and the machine
- * crashes then stale disk data _may_ be exposed inside the file. But current
- * VFS code falls back into buffered path in that case so we are safe.
- */
-static ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb,
-                             const struct iovec *iov, loff_t offset,
-                             unsigned long nr_segs)
-{
-       struct file *file = iocb->ki_filp;
-       struct inode *inode = file->f_mapping->host;
-       struct ext4_inode_info *ei = EXT4_I(inode);
-       handle_t *handle;
-       ssize_t ret;
-       int orphan = 0;
-       size_t count = iov_length(iov, nr_segs);
-       int retries = 0;
-
-       if (rw == WRITE) {
-               loff_t final_size = offset + count;
-
-               if (final_size > inode->i_size) {
-                       /* Credits for sb + inode write */
-                       handle = ext4_journal_start(inode, 2);
-                       if (IS_ERR(handle)) {
-                               ret = PTR_ERR(handle);
-                               goto out;
-                       }
-                       ret = ext4_orphan_add(handle, inode);
-                       if (ret) {
-                               ext4_journal_stop(handle);
-                               goto out;
-                       }
-                       orphan = 1;
-                       ei->i_disksize = inode->i_size;
-                       ext4_journal_stop(handle);
-               }
-       }
-
-retry:
-       if (rw == READ && ext4_should_dioread_nolock(inode))
-               ret = __blockdev_direct_IO(rw, iocb, inode,
-                                inode->i_sb->s_bdev, iov,
-                                offset, nr_segs,
-                                ext4_get_block, NULL, NULL, 0);
-       else {
-               ret = blockdev_direct_IO(rw, iocb, inode, iov,
-                                offset, nr_segs, ext4_get_block);
-
-               if (unlikely((rw & WRITE) && ret < 0)) {
-                       loff_t isize = i_size_read(inode);
-                       loff_t end = offset + iov_length(iov, nr_segs);
-
-                       if (end > isize)
-                               ext4_truncate_failed_write(inode);
-               }
-       }
-       if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
-               goto retry;
-
-       if (orphan) {
-               int err;
-
-               /* Credits for sb + inode write */
-               handle = ext4_journal_start(inode, 2);
-               if (IS_ERR(handle)) {
-                       /* This is really bad luck. We've written the data
-                        * but cannot extend i_size. Bail out and pretend
-                        * the write failed... */
-                       ret = PTR_ERR(handle);
-                       if (inode->i_nlink)
-                               ext4_orphan_del(NULL, inode);
-
-                       goto out;
-               }
-               if (inode->i_nlink)
-                       ext4_orphan_del(handle, inode);
-               if (ret > 0) {
-                       loff_t end = offset + ret;
-                       if (end > inode->i_size) {
-                               ei->i_disksize = end;
-                               i_size_write(inode, end);
-                               /*
-                                * We're going to return a positive `ret'
-                                * here due to non-zero-length I/O, so there's
-                                * no way of reporting error returns from
-                                * ext4_mark_inode_dirty() to userspace.  So
-                                * ignore it.
-                                */
-                               ext4_mark_inode_dirty(handle, inode);
-                       }
-               }
-               err = ext4_journal_stop(handle);
-               if (ret == 0)
-                       ret = err;
-       }
-out:
-       return ret;
-}
-
 /*
  * ext4_get_block used when preparing for a DIO write or buffer write.
  * We allocate an uinitialized extent if blocks haven't been allocated.
@@ -3638,8 +2683,15 @@ static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate)
                goto out;
        }
 
-       io_end->flag = EXT4_IO_END_UNWRITTEN;
+       /*
+        * It may be over-defensive here to check EXT4_IO_END_UNWRITTEN now,
+        * but being more careful is always safe for the future change.
+        */
        inode = io_end->inode;
+       if (!(io_end->flag & EXT4_IO_END_UNWRITTEN)) {
+               io_end->flag |= EXT4_IO_END_UNWRITTEN;
+               atomic_inc(&EXT4_I(inode)->i_aiodio_unwritten);
+       }
 
        /* Add the io_end to per-inode completed io list*/
        spin_lock_irqsave(&EXT4_I(inode)->i_completed_io_lock, flags);
@@ -4033,383 +3085,6 @@ unlock:
        return err;
 }
 
-/*
- * Probably it should be a library function... search for first non-zero word
- * or memcmp with zero_page, whatever is better for particular architecture.
- * Linus?
- */
-static inline int all_zeroes(__le32 *p, __le32 *q)
-{
-       while (p < q)
-               if (*p++)
-                       return 0;
-       return 1;
-}
-
-/**
- *     ext4_find_shared - find the indirect blocks for partial truncation.
- *     @inode:   inode in question
- *     @depth:   depth of the affected branch
- *     @offsets: offsets of pointers in that branch (see ext4_block_to_path)
- *     @chain:   place to store the pointers to partial indirect blocks
- *     @top:     place to the (detached) top of branch
- *
- *     This is a helper function used by ext4_truncate().
- *
- *     When we do truncate() we may have to clean the ends of several
- *     indirect blocks but leave the blocks themselves alive. Block is
- *     partially truncated if some data below the new i_size is referred
- *     from it (and it is on the path to the first completely truncated
- *     data block, indeed).  We have to free the top of that path along
- *     with everything to the right of the path. Since no allocation
- *     past the truncation point is possible until ext4_truncate()
- *     finishes, we may safely do the latter, but top of branch may
- *     require special attention - pageout below the truncation point
- *     might try to populate it.
- *
- *     We atomically detach the top of branch from the tree, store the
- *     block number of its root in *@top, pointers to buffer_heads of
- *     partially truncated blocks - in @chain[].bh and pointers to
- *     their last elements that should not be removed - in
- *     @chain[].p. Return value is the pointer to last filled element
- *     of @chain.
- *
- *     The work left to caller to do the actual freeing of subtrees:
- *             a) free the subtree starting from *@top
- *             b) free the subtrees whose roots are stored in
- *                     (@chain[i].p+1 .. end of @chain[i].bh->b_data)
- *             c) free the subtrees growing from the inode past the @chain[0].
- *                     (no partially truncated stuff there).  */
-
-static Indirect *ext4_find_shared(struct inode *inode, int depth,
-                                 ext4_lblk_t offsets[4], Indirect chain[4],
-                                 __le32 *top)
-{
-       Indirect *partial, *p;
-       int k, err;
-
-       *top = 0;
-       /* Make k index the deepest non-null offset + 1 */
-       for (k = depth; k > 1 && !offsets[k-1]; k--)
-               ;
-       partial = ext4_get_branch(inode, k, offsets, chain, &err);
-       /* Writer: pointers */
-       if (!partial)
-               partial = chain + k-1;
-       /*
-        * If the branch acquired continuation since we've looked at it -
-        * fine, it should all survive and (new) top doesn't belong to us.
-        */
-       if (!partial->key && *partial->p)
-               /* Writer: end */
-               goto no_top;
-       for (p = partial; (p > chain) && all_zeroes((__le32 *) p->bh->b_data, p->p); p--)
-               ;
-       /*
-        * OK, we've found the last block that must survive. The rest of our
-        * branch should be detached before unlocking. However, if that rest
-        * of branch is all ours and does not grow immediately from the inode
-        * it's easier to cheat and just decrement partial->p.
-        */
-       if (p == chain + k - 1 && p > chain) {
-               p->p--;
-       } else {
-               *top = *p->p;
-               /* Nope, don't do this in ext4.  Must leave the tree intact */
-#if 0
-               *p->p = 0;
-#endif
-       }
-       /* Writer: end */
-
-       while (partial > p) {
-               brelse(partial->bh);
-               partial--;
-       }
-no_top:
-       return partial;
-}
-
-/*
- * Zero a number of block pointers in either an inode or an indirect block.
- * If we restart the transaction we must again get write access to the
- * indirect block for further modification.
- *
- * We release `count' blocks on disk, but (last - first) may be greater
- * than `count' because there can be holes in there.
- *
- * Return 0 on success, 1 on invalid block range
- * and < 0 on fatal error.
- */
-static int ext4_clear_blocks(handle_t *handle, struct inode *inode,
-                            struct buffer_head *bh,
-                            ext4_fsblk_t block_to_free,
-                            unsigned long count, __le32 *first,
-                            __le32 *last)
-{
-       __le32 *p;
-       int     flags = EXT4_FREE_BLOCKS_FORGET | EXT4_FREE_BLOCKS_VALIDATED;
-       int     err;
-
-       if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
-               flags |= EXT4_FREE_BLOCKS_METADATA;
-
-       if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), block_to_free,
-                                  count)) {
-               EXT4_ERROR_INODE(inode, "attempt to clear invalid "
-                                "blocks %llu len %lu",
-                                (unsigned long long) block_to_free, count);
-               return 1;
-       }
-
-       if (try_to_extend_transaction(handle, inode)) {
-               if (bh) {
-                       BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
-                       err = ext4_handle_dirty_metadata(handle, inode, bh);
-                       if (unlikely(err))
-                               goto out_err;
-               }
-               err = ext4_mark_inode_dirty(handle, inode);
-               if (unlikely(err))
-                       goto out_err;
-               err = ext4_truncate_restart_trans(handle, inode,
-                                                 blocks_for_truncate(inode));
-               if (unlikely(err))
-                       goto out_err;
-               if (bh) {
-                       BUFFER_TRACE(bh, "retaking write access");
-                       err = ext4_journal_get_write_access(handle, bh);
-                       if (unlikely(err))
-                               goto out_err;
-               }
-       }
-
-       for (p = first; p < last; p++)
-               *p = 0;
-
-       ext4_free_blocks(handle, inode, NULL, block_to_free, count, flags);
-       return 0;
-out_err:
-       ext4_std_error(inode->i_sb, err);
-       return err;
-}
-
-/**
- * ext4_free_data - free a list of data blocks
- * @handle:    handle for this transaction
- * @inode:     inode we are dealing with
- * @this_bh:   indirect buffer_head which contains *@first and *@last
- * @first:     array of block numbers
- * @last:      points immediately past the end of array
- *
- * We are freeing all blocks referred from that array (numbers are stored as
- * little-endian 32-bit) and updating @inode->i_blocks appropriately.
- *
- * We accumulate contiguous runs of blocks to free.  Conveniently, if these
- * blocks are contiguous then releasing them at one time will only affect one
- * or two bitmap blocks (+ group descriptor(s) and superblock) and we won't
- * actually use a lot of journal space.
- *
- * @this_bh will be %NULL if @first and @last point into the inode's direct
- * block pointers.
- */
-static void ext4_free_data(handle_t *handle, struct inode *inode,
-                          struct buffer_head *this_bh,
-                          __le32 *first, __le32 *last)
-{
-       ext4_fsblk_t block_to_free = 0;    /* Starting block # of a run */
-       unsigned long count = 0;            /* Number of blocks in the run */
-       __le32 *block_to_free_p = NULL;     /* Pointer into inode/ind
-                                              corresponding to
-                                              block_to_free */
-       ext4_fsblk_t nr;                    /* Current block # */
-       __le32 *p;                          /* Pointer into inode/ind
-                                              for current block */
-       int err = 0;
-
-       if (this_bh) {                          /* For indirect block */
-               BUFFER_TRACE(this_bh, "get_write_access");
-               err = ext4_journal_get_write_access(handle, this_bh);
-               /* Important: if we can't update the indirect pointers
-                * to the blocks, we can't free them. */
-               if (err)
-                       return;
-       }
-
-       for (p = first; p < last; p++) {
-               nr = le32_to_cpu(*p);
-               if (nr) {
-                       /* accumulate blocks to free if they're contiguous */
-                       if (count == 0) {
-                               block_to_free = nr;
-                               block_to_free_p = p;
-                               count = 1;
-                       } else if (nr == block_to_free + count) {
-                               count++;
-                       } else {
-                               err = ext4_clear_blocks(handle, inode, this_bh,
-                                                       block_to_free, count,
-                                                       block_to_free_p, p);
-                               if (err)
-                                       break;
-                               block_to_free = nr;
-                               block_to_free_p = p;
-                               count = 1;
-                       }
-               }
-       }
-
-       if (!err && count > 0)
-               err = ext4_clear_blocks(handle, inode, this_bh, block_to_free,
-                                       count, block_to_free_p, p);
-       if (err < 0)
-               /* fatal error */
-               return;
-
-       if (this_bh) {
-               BUFFER_TRACE(this_bh, "call ext4_handle_dirty_metadata");
-
-               /*
-                * The buffer head should have an attached journal head at this
-                * point. However, if the data is corrupted and an indirect
-                * block pointed to itself, it would have been detached when
-                * the block was cleared. Check for this instead of OOPSing.
-                */
-               if ((EXT4_JOURNAL(inode) == NULL) || bh2jh(this_bh))
-                       ext4_handle_dirty_metadata(handle, inode, this_bh);
-               else
-                       EXT4_ERROR_INODE(inode,
-                                        "circular indirect block detected at "
-                                        "block %llu",
-                               (unsigned long long) this_bh->b_blocknr);
-       }
-}
-
-/**
- *     ext4_free_branches - free an array of branches
- *     @handle: JBD handle for this transaction
- *     @inode: inode we are dealing with
- *     @parent_bh: the buffer_head which contains *@first and *@last
- *     @first: array of block numbers
- *     @last:  pointer immediately past the end of array
- *     @depth: depth of the branches to free
- *
- *     We are freeing all blocks referred from these branches (numbers are
- *     stored as little-endian 32-bit) and updating @inode->i_blocks
- *     appropriately.
- */
-static void ext4_free_branches(handle_t *handle, struct inode *inode,
-                              struct buffer_head *parent_bh,
-                              __le32 *first, __le32 *last, int depth)
-{
-       ext4_fsblk_t nr;
-       __le32 *p;
-
-       if (ext4_handle_is_aborted(handle))
-               return;
-
-       if (depth--) {
-               struct buffer_head *bh;
-               int addr_per_block = EXT4_ADDR_PER_BLOCK(inode->i_sb);
-               p = last;
-               while (--p >= first) {
-                       nr = le32_to_cpu(*p);
-                       if (!nr)
-                               continue;               /* A hole */
-
-                       if (!ext4_data_block_valid(EXT4_SB(inode->i_sb),
-                                                  nr, 1)) {
-                               EXT4_ERROR_INODE(inode,
-                                                "invalid indirect mapped "
-                                                "block %lu (level %d)",
-                                                (unsigned long) nr, depth);
-                               break;
-                       }
-
-                       /* Go read the buffer for the next level down */
-                       bh = sb_bread(inode->i_sb, nr);
-
-                       /*
-                        * A read failure? Report error and clear slot
-                        * (should be rare).
-                        */
-                       if (!bh) {
-                               EXT4_ERROR_INODE_BLOCK(inode, nr,
-                                                      "Read failure");
-                               continue;
-                       }
-
-                       /* This zaps the entire block.  Bottom up. */
-                       BUFFER_TRACE(bh, "free child branches");
-                       ext4_free_branches(handle, inode, bh,
-                                       (__le32 *) bh->b_data,
-                                       (__le32 *) bh->b_data + addr_per_block,
-                                       depth);
-                       brelse(bh);
-
-                       /*
-                        * Everything below this this pointer has been
-                        * released.  Now let this top-of-subtree go.
-                        *
-                        * We want the freeing of this indirect block to be
-                        * atomic in the journal with the updating of the
-                        * bitmap block which owns it.  So make some room in
-                        * the journal.
-                        *
-                        * We zero the parent pointer *after* freeing its
-                        * pointee in the bitmaps, so if extend_transaction()
-                        * for some reason fails to put the bitmap changes and
-                        * the release into the same transaction, recovery
-                        * will merely complain about releasing a free block,
-                        * rather than leaking blocks.
-                        */
-                       if (ext4_handle_is_aborted(handle))
-                               return;
-                       if (try_to_extend_transaction(handle, inode)) {
-                               ext4_mark_inode_dirty(handle, inode);
-                               ext4_truncate_restart_trans(handle, inode,
-                                           blocks_for_truncate(inode));
-                       }
-
-                       /*
-                        * The forget flag here is critical because if
-                        * we are journaling (and not doing data
-                        * journaling), we have to make sure a revoke
-                        * record is written to prevent the journal
-                        * replay from overwriting the (former)
-                        * indirect block if it gets reallocated as a
-                        * data block.  This must happen in the same
-                        * transaction where the data blocks are
-                        * actually freed.
-                        */
-                       ext4_free_blocks(handle, inode, NULL, nr, 1,
-                                        EXT4_FREE_BLOCKS_METADATA|
-                                        EXT4_FREE_BLOCKS_FORGET);
-
-                       if (parent_bh) {
-                               /*
-                                * The block which we have just freed is
-                                * pointed to by an indirect block: journal it
-                                */
-                               BUFFER_TRACE(parent_bh, "get_write_access");
-                               if (!ext4_journal_get_write_access(handle,
-                                                                  parent_bh)){
-                                       *p = 0;
-                                       BUFFER_TRACE(parent_bh,
-                                       "call ext4_handle_dirty_metadata");
-                                       ext4_handle_dirty_metadata(handle,
-                                                                  inode,
-                                                                  parent_bh);
-                               }
-                       }
-               }
-       } else {
-               /* We have reached the bottom of the tree. */
-               BUFFER_TRACE(parent_bh, "free data blocks");
-               ext4_free_data(handle, inode, parent_bh, first, last);
-       }
-}
-
 int ext4_can_truncate(struct inode *inode)
 {
        if (S_ISREG(inode->i_mode))
@@ -4476,19 +3151,6 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
  */
 void ext4_truncate(struct inode *inode)
 {
-       handle_t *handle;
-       struct ext4_inode_info *ei = EXT4_I(inode);
-       __le32 *i_data = ei->i_data;
-       int addr_per_block = EXT4_ADDR_PER_BLOCK(inode->i_sb);
-       struct address_space *mapping = inode->i_mapping;
-       ext4_lblk_t offsets[4];
-       Indirect chain[4];
-       Indirect *partial;
-       __le32 nr = 0;
-       int n = 0;
-       ext4_lblk_t last_block, max_block;
-       unsigned blocksize = inode->i_sb->s_blocksize;
-
        trace_ext4_truncate_enter(inode);
 
        if (!ext4_can_truncate(inode))
@@ -4499,149 +3161,11 @@ void ext4_truncate(struct inode *inode)
        if (inode->i_size == 0 && !test_opt(inode->i_sb, NO_AUTO_DA_ALLOC))
                ext4_set_inode_state(inode, EXT4_STATE_DA_ALLOC_CLOSE);
 
-       if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
+       if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
                ext4_ext_truncate(inode);
-               trace_ext4_truncate_exit(inode);
-               return;
-       }
-
-       handle = start_transaction(inode);
-       if (IS_ERR(handle))
-               return;         /* AKPM: return what? */
-
-       last_block = (inode->i_size + blocksize-1)
-                                       >> EXT4_BLOCK_SIZE_BITS(inode->i_sb);
-       max_block = (EXT4_SB(inode->i_sb)->s_bitmap_maxbytes + blocksize-1)
-                                       >> EXT4_BLOCK_SIZE_BITS(inode->i_sb);
-
-       if (inode->i_size & (blocksize - 1))
-               if (ext4_block_truncate_page(handle, mapping, inode->i_size))
-                       goto out_stop;
-
-       if (last_block != max_block) {
-               n = ext4_block_to_path(inode, last_block, offsets, NULL);
-               if (n == 0)
-                       goto out_stop;  /* error */
-       }
-
-       /*
-        * OK.  This truncate is going to happen.  We add the inode to the
-        * orphan list, so that if this truncate spans multiple transactions,
-        * and we crash, we will resume the truncate when the filesystem
-        * recovers.  It also marks the inode dirty, to catch the new size.
-        *
-        * Implication: the file must always be in a sane, consistent
-        * truncatable state while each transaction commits.
-        */
-       if (ext4_orphan_add(handle, inode))
-               goto out_stop;
-
-       /*
-        * From here we block out all ext4_get_block() callers who want to
-        * modify the block allocation tree.
-        */
-       down_write(&ei->i_data_sem);
-
-       ext4_discard_preallocations(inode);
-
-       /*
-        * The orphan list entry will now protect us from any crash which
-        * occurs before the truncate completes, so it is now safe to propagate
-        * the new, shorter inode size (held for now in i_size) into the
-        * on-disk inode. We do this via i_disksize, which is the value which
-        * ext4 *really* writes onto the disk inode.
-        */
-       ei->i_disksize = inode->i_size;
-
-       if (last_block == max_block) {
-               /*
-                * It is unnecessary to free any data blocks if last_block is
-                * equal to the indirect block limit.
-                */
-               goto out_unlock;
-       } else if (n == 1) {            /* direct blocks */
-               ext4_free_data(handle, inode, NULL, i_data+offsets[0],
-                              i_data + EXT4_NDIR_BLOCKS);
-               goto do_indirects;
-       }
-
-       partial = ext4_find_shared(inode, n, offsets, chain, &nr);
-       /* Kill the top of shared branch (not detached) */
-       if (nr) {
-               if (partial == chain) {
-                       /* Shared branch grows from the inode */
-                       ext4_free_branches(handle, inode, NULL,
-                                          &nr, &nr+1, (chain+n-1) - partial);
-                       *partial->p = 0;
-                       /*
-                        * We mark the inode dirty prior to restart,
-                        * and prior to stop.  No need for it here.
-                        */
-               } else {
-                       /* Shared branch grows from an indirect block */
-                       BUFFER_TRACE(partial->bh, "get_write_access");
-                       ext4_free_branches(handle, inode, partial->bh,
-                                       partial->p,
-                                       partial->p+1, (chain+n-1) - partial);
-               }
-       }
-       /* Clear the ends of indirect blocks on the shared branch */
-       while (partial > chain) {
-               ext4_free_branches(handle, inode, partial->bh, partial->p + 1,
-                                  (__le32*)partial->bh->b_data+addr_per_block,
-                                  (chain+n-1) - partial);
-               BUFFER_TRACE(partial->bh, "call brelse");
-               brelse(partial->bh);
-               partial--;
-       }
-do_indirects:
-       /* Kill the remaining (whole) subtrees */
-       switch (offsets[0]) {
-       default:
-               nr = i_data[EXT4_IND_BLOCK];
-               if (nr) {
-                       ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 1);
-                       i_data[EXT4_IND_BLOCK] = 0;
-               }
-       case EXT4_IND_BLOCK:
-               nr = i_data[EXT4_DIND_BLOCK];
-               if (nr) {
-                       ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 2);
-                       i_data[EXT4_DIND_BLOCK] = 0;
-               }
-       case EXT4_DIND_BLOCK:
-               nr = i_data[EXT4_TIND_BLOCK];
-               if (nr) {
-                       ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 3);
-                       i_data[EXT4_TIND_BLOCK] = 0;
-               }
-       case EXT4_TIND_BLOCK:
-               ;
-       }
-
-out_unlock:
-       up_write(&ei->i_data_sem);
-       inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
-       ext4_mark_inode_dirty(handle, inode);
-
-       /*
-        * In a multi-transaction truncate, we only make the final transaction
-        * synchronous
-        */
-       if (IS_SYNC(inode))
-               ext4_handle_sync(handle);
-out_stop:
-       /*
-        * If this was a simple ftruncate(), and the file will remain alive
-        * then we need to clear up the orphan record which we created above.
-        * However, if this was a real unlink then we were called by
-        * ext4_delete_inode(), and we allow that function to clean up the
-        * orphan info for us.
-        */
-       if (inode->i_nlink)
-               ext4_orphan_del(handle, inode);
+       else
+               ext4_ind_truncate(inode);
 
-       ext4_journal_stop(handle);
        trace_ext4_truncate_exit(inode);
 }
 
@@ -5012,7 +3536,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
                   (S_ISLNK(inode->i_mode) &&
                    !ext4_inode_is_fast_symlink(inode))) {
                /* Validate block references which are part of inode */
-               ret = ext4_check_inode_blockref(inode);
+               ret = ext4_ind_check_inode(inode);
        }
        if (ret)
                goto bad_inode;
@@ -5459,34 +3983,10 @@ int ext4_getattr(struct vfsmount *mnt, struct dentry *dentry,
        return 0;
 }
 
-static int ext4_indirect_trans_blocks(struct inode *inode, int nrblocks,
-                                     int chunk)
-{
-       int indirects;
-
-       /* if nrblocks are contiguous */
-       if (chunk) {
-               /*
-                * With N contiguous data blocks, we need at most
-                * N/EXT4_ADDR_PER_BLOCK(inode->i_sb) + 1 indirect blocks,
-                * 2 dindirect blocks, and 1 tindirect block
-                */
-               return DIV_ROUND_UP(nrblocks,
-                                   EXT4_ADDR_PER_BLOCK(inode->i_sb)) + 4;
-       }
-       /*
-        * if nrblocks are not contiguous, worse case, each block touch
-        * a indirect block, and each indirect block touch a double indirect
-        * block, plus a triple indirect block
-        */
-       indirects = nrblocks * 2 + 1;
-       return indirects;
-}
-
 static int ext4_index_trans_blocks(struct inode *inode, int nrblocks, int chunk)
 {
        if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
-               return ext4_indirect_trans_blocks(inode, nrblocks, chunk);
+               return ext4_ind_trans_blocks(inode, nrblocks, chunk);
        return ext4_ext_index_trans_blocks(inode, nrblocks, chunk);
 }
 
index 808c554..f18bfe3 100644 (file)
@@ -202,8 +202,9 @@ setversion_out:
                struct super_block *sb = inode->i_sb;
                int err, err2=0;
 
-               if (!capable(CAP_SYS_RESOURCE))
-                       return -EPERM;
+               err = ext4_resize_begin(sb);
+               if (err)
+                       return err;
 
                if (get_user(n_blocks_count, (__u32 __user *)arg))
                        return -EFAULT;
@@ -221,6 +222,7 @@ setversion_out:
                if (err == 0)
                        err = err2;
                mnt_drop_write(filp->f_path.mnt);
+               ext4_resize_end(sb);
 
                return err;
        }
@@ -271,8 +273,9 @@ mext_out:
                struct super_block *sb = inode->i_sb;
                int err, err2=0;
 
-               if (!capable(CAP_SYS_RESOURCE))
-                       return -EPERM;
+               err = ext4_resize_begin(sb);
+               if (err)
+                       return err;
 
                if (copy_from_user(&input, (struct ext4_new_group_input __user *)arg,
                                sizeof(input)))
@@ -291,6 +294,7 @@ mext_out:
                if (err == 0)
                        err = err2;
                mnt_drop_write(filp->f_path.mnt);
+               ext4_resize_end(sb);
 
                return err;
        }
index 6ed859d..17a5a57 100644 (file)
@@ -75,8 +75,8 @@
  *
  * The inode preallocation space is used looking at the _logical_ start
  * block. If only the logical file block falls within the range of prealloc
- * space we will consume the particular prealloc space. This make sure that
- * that the we have contiguous physical blocks representing the file blocks
+ * space we will consume the particular prealloc space. This makes sure that
+ * we have contiguous physical blocks representing the file blocks
  *
  * The important thing to be noted in case of inode prealloc space is that
  * we don't modify the values associated to inode prealloc space except
@@ -84,7 +84,7 @@
  *
  * If we are not able to find blocks in the inode prealloc space and if we
  * have the group allocation flag set then we look at the locality group
- * prealloc space. These are per CPU prealloc list repreasented as
+ * prealloc space. These are per CPU prealloc list represented as
  *
  * ext4_sb_info.s_locality_groups[smp_processor_id()]
  *
  * we are doing a group prealloc we try to normalize the request to
  * sbi->s_mb_group_prealloc. Default value of s_mb_group_prealloc is
  * 512 blocks. This can be tuned via
- * /sys/fs/ext4/<partition/mb_group_prealloc. The value is represented in
+ * /sys/fs/ext4/<partition>/mb_group_prealloc. The value is represented in
  * terms of number of blocks. If we have mounted the file system with -O
  * stripe=<value> option the group prealloc request is normalized to the
- * stripe value (sbi->s_stripe)
+ * the smallest multiple of the stripe value (sbi->s_stripe) which is
+ * greater than the default mb_group_prealloc.
  *
- * The regular allocator(using the buddy cache) supports few tunables.
+ * The regular allocator (using the buddy cache) supports a few tunables.
  *
  * /sys/fs/ext4/<partition>/mb_min_to_scan
  * /sys/fs/ext4/<partition>/mb_max_to_scan
  * best extent in the found extents. Searching for the blocks starts with
  * the group specified as the goal value in allocation context via
  * ac_g_ex. Each group is first checked based on the criteria whether it
- * can used for allocation. ext4_mb_good_group explains how the groups are
+ * can be used for allocation. ext4_mb_good_group explains how the groups are
  * checked.
  *
  * Both the prealloc space are getting populated as above. So for the first
@@ -492,10 +493,11 @@ static void mb_cmp_bitmaps(struct ext4_buddy *e4b, void *bitmap)
                b2 = (unsigned char *) bitmap;
                for (i = 0; i < e4b->bd_sb->s_blocksize; i++) {
                        if (b1[i] != b2[i]) {
-                               printk(KERN_ERR "corruption in group %u "
-                                      "at byte %u(%u): %x in copy != %x "
-                                      "on disk/prealloc\n",
-                                      e4b->bd_group, i, i * 8, b1[i], b2[i]);
+                               ext4_msg(e4b->bd_sb, KERN_ERR,
+                                        "corruption in group %u "
+                                        "at byte %u(%u): %x in copy != %x "
+                                        "on disk/prealloc",
+                                        e4b->bd_group, i, i * 8, b1[i], b2[i]);
                                BUG();
                        }
                }
@@ -1125,7 +1127,7 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
        grp = ext4_get_group_info(sb, group);
 
        e4b->bd_blkbits = sb->s_blocksize_bits;
-       e4b->bd_info = ext4_get_group_info(sb, group);
+       e4b->bd_info = grp;
        e4b->bd_sb = sb;
        e4b->bd_group = group;
        e4b->bd_buddy_page = NULL;
@@ -1281,7 +1283,7 @@ static void mb_clear_bits(void *bm, int cur, int len)
        }
 }
 
-static void mb_set_bits(void *bm, int cur, int len)
+void ext4_set_bits(void *bm, int cur, int len)
 {
        __u32 *addr;
 
@@ -1510,7 +1512,7 @@ static int mb_mark_used(struct ext4_buddy *e4b, struct ext4_free_extent *ex)
        }
        mb_set_largest_free_order(e4b->bd_sb, e4b->bd_info);
 
-       mb_set_bits(EXT4_MB_BITMAP(e4b), ex->fe_start, len0);
+       ext4_set_bits(EXT4_MB_BITMAP(e4b), ex->fe_start, len0);
        mb_check_buddy(e4b);
 
        return ret;
@@ -2223,8 +2225,8 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group,
                        EXT4_DESC_PER_BLOCK_BITS(sb);
                meta_group_info = kmalloc(metalen, GFP_KERNEL);
                if (meta_group_info == NULL) {
-                       printk(KERN_ERR "EXT4-fs: can't allocate mem for a "
-                              "buddy group\n");
+                       ext4_msg(sb, KERN_ERR, "EXT4-fs: can't allocate mem "
+                                "for a buddy group");
                        goto exit_meta_group_info;
                }
                sbi->s_group_info[group >> EXT4_DESC_PER_BLOCK_BITS(sb)] =
@@ -2237,7 +2239,7 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group,
 
        meta_group_info[i] = kmem_cache_alloc(cachep, GFP_KERNEL);
        if (meta_group_info[i] == NULL) {
-               printk(KERN_ERR "EXT4-fs: can't allocate buddy mem\n");
+               ext4_msg(sb, KERN_ERR, "EXT4-fs: can't allocate buddy mem");
                goto exit_group_info;
        }
        memset(meta_group_info[i], 0, kmem_cache_size(cachep));
@@ -2279,8 +2281,10 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group,
 
 exit_group_info:
        /* If a meta_group_info table has been allocated, release it now */
-       if (group % EXT4_DESC_PER_BLOCK(sb) == 0)
+       if (group % EXT4_DESC_PER_BLOCK(sb) == 0) {
                kfree(sbi->s_group_info[group >> EXT4_DESC_PER_BLOCK_BITS(sb)]);
+               sbi->s_group_info[group >> EXT4_DESC_PER_BLOCK_BITS(sb)] = NULL;
+       }
 exit_meta_group_info:
        return -ENOMEM;
 } /* ext4_mb_add_groupinfo */
@@ -2328,23 +2332,26 @@ static int ext4_mb_init_backend(struct super_block *sb)
        /* An 8TB filesystem with 64-bit pointers requires a 4096 byte
         * kmalloc. A 128kb malloc should suffice for a 256TB filesystem.
         * So a two level scheme suffices for now. */
-       sbi->s_group_info = kzalloc(array_size, GFP_KERNEL);
+       sbi->s_group_info = ext4_kvzalloc(array_size, GFP_KERNEL);
        if (sbi->s_group_info == NULL) {
-               printk(KERN_ERR "EXT4-fs: can't allocate buddy meta group\n");
+               ext4_msg(sb, KERN_ERR, "can't allocate buddy meta group");
                return -ENOMEM;
        }
        sbi->s_buddy_cache = new_inode(sb);
        if (sbi->s_buddy_cache == NULL) {
-               printk(KERN_ERR "EXT4-fs: can't get new inode\n");
+               ext4_msg(sb, KERN_ERR, "can't get new inode");
                goto err_freesgi;
        }
-       sbi->s_buddy_cache->i_ino = get_next_ino();
+       /* To avoid potentially colliding with an valid on-disk inode number,
+        * use EXT4_BAD_INO for the buddy cache inode number.  This inode is
+        * not in the inode hash, so it should never be found by iget(), but
+        * this will avoid confusion if it ever shows up during debugging. */
+       sbi->s_buddy_cache->i_ino = EXT4_BAD_INO;
        EXT4_I(sbi->s_buddy_cache)->i_disksize = 0;
        for (i = 0; i < ngroups; i++) {
                desc = ext4_get_group_desc(sb, i, NULL);
                if (desc == NULL) {
-                       printk(KERN_ERR
-                               "EXT4-fs: can't read descriptor %u\n", i);
+                       ext4_msg(sb, KERN_ERR, "can't read descriptor %u", i);
                        goto err_freebuddy;
                }
                if (ext4_mb_add_groupinfo(sb, i, desc) != 0)
@@ -2362,7 +2369,7 @@ err_freebuddy:
                kfree(sbi->s_group_info[i]);
        iput(sbi->s_buddy_cache);
 err_freesgi:
-       kfree(sbi->s_group_info);
+       ext4_kvfree(sbi->s_group_info);
        return -ENOMEM;
 }
 
@@ -2404,14 +2411,15 @@ static int ext4_groupinfo_create_slab(size_t size)
                                        slab_size, 0, SLAB_RECLAIM_ACCOUNT,
                                        NULL);
 
+       ext4_groupinfo_caches[cache_index] = cachep;
+
        mutex_unlock(&ext4_grpinfo_slab_create_mutex);
        if (!cachep) {
-               printk(KERN_EMERG "EXT4: no memory for groupinfo slab cache\n");
+               printk(KERN_EMERG
+                      "EXT4-fs: no memory for groupinfo slab cache\n");
                return -ENOMEM;
        }
 
-       ext4_groupinfo_caches[cache_index] = cachep;
-
        return 0;
 }
 
@@ -2457,12 +2465,6 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
                i++;
        } while (i <= sb->s_blocksize_bits + 1);
 
-       /* init file for buddy data */
-       ret = ext4_mb_init_backend(sb);
-       if (ret != 0) {
-               goto out;
-       }
-
        spin_lock_init(&sbi->s_md_lock);
        spin_lock_init(&sbi->s_bal_lock);
 
@@ -2472,6 +2474,18 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
        sbi->s_mb_stream_request = MB_DEFAULT_STREAM_THRESHOLD;
        sbi->s_mb_order2_reqs = MB_DEFAULT_ORDER2_REQS;
        sbi->s_mb_group_prealloc = MB_DEFAULT_GROUP_PREALLOC;
+       /*
+        * If there is a s_stripe > 1, then we set the s_mb_group_prealloc
+        * to the lowest multiple of s_stripe which is bigger than
+        * the s_mb_group_prealloc as determined above. We want
+        * the preallocation size to be an exact multiple of the
+        * RAID stripe size so that preallocations don't fragment
+        * the stripes.
+        */
+       if (sbi->s_stripe > 1) {
+               sbi->s_mb_group_prealloc = roundup(
+                       sbi->s_mb_group_prealloc, sbi->s_stripe);
+       }
 
        sbi->s_locality_groups = alloc_percpu(struct ext4_locality_group);
        if (sbi->s_locality_groups == NULL) {
@@ -2487,6 +2501,12 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
                spin_lock_init(&lg->lg_prealloc_lock);
        }
 
+       /* init file for buddy data */
+       ret = ext4_mb_init_backend(sb);
+       if (ret != 0) {
+               goto out;
+       }
+
        if (sbi->s_proc)
                proc_create_data("mb_groups", S_IRUGO, sbi->s_proc,
                                 &ext4_mb_seq_groups_fops, sb);
@@ -2544,32 +2564,32 @@ int ext4_mb_release(struct super_block *sb)
                        EXT4_DESC_PER_BLOCK_BITS(sb);
                for (i = 0; i < num_meta_group_infos; i++)
                        kfree(sbi->s_group_info[i]);
-               kfree(sbi->s_group_info);
+               ext4_kvfree(sbi->s_group_info);
        }
        kfree(sbi->s_mb_offsets);
        kfree(sbi->s_mb_maxs);
        if (sbi->s_buddy_cache)
                iput(sbi->s_buddy_cache);
        if (sbi->s_mb_stats) {
-               printk(KERN_INFO
-                      "EXT4-fs: mballoc: %u blocks %u reqs (%u success)\n",
+               ext4_msg(sb, KERN_INFO,
+                      "mballoc: %u blocks %u reqs (%u success)",
                                atomic_read(&sbi->s_bal_allocated),
                                atomic_read(&sbi->s_bal_reqs),
                                atomic_read(&sbi->s_bal_success));
-               printk(KERN_INFO
-                     "EXT4-fs: mballoc: %u extents scanned, %u goal hits, "
-                               "%u 2^N hits, %u breaks, %u lost\n",
+               ext4_msg(sb, KERN_INFO,
+                     "mballoc: %u extents scanned, %u goal hits, "
+                               "%u 2^N hits, %u breaks, %u lost",
                                atomic_read(&sbi->s_bal_ex_scanned),
                                atomic_read(&sbi->s_bal_goals),
                                atomic_read(&sbi->s_bal_2orders),
                                atomic_read(&sbi->s_bal_breaks),
                                atomic_read(&sbi->s_mb_lost_chunks));
-               printk(KERN_INFO
-                      "EXT4-fs: mballoc: %lu generated and it took %Lu\n",
-                               sbi->s_mb_buddies_generated++,
+               ext4_msg(sb, KERN_INFO,
+                      "mballoc: %lu generated and it took %Lu",
+                               sbi->s_mb_buddies_generated,
                                sbi->s_mb_generation_time);
-               printk(KERN_INFO
-                      "EXT4-fs: mballoc: %u preallocated, %u discarded\n",
+               ext4_msg(sb, KERN_INFO,
+                      "mballoc: %u preallocated, %u discarded",
                                atomic_read(&sbi->s_mb_preallocated),
                                atomic_read(&sbi->s_mb_discarded));
        }
@@ -2628,6 +2648,15 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn)
                rb_erase(&entry->node, &(db->bb_free_root));
                mb_free_blocks(NULL, &e4b, entry->start_blk, entry->count);
 
+               /*
+                * Clear the trimmed flag for the group so that the next
+                * ext4_trim_fs can trim it.
+                * If the volume is mounted with -o discard, online discard
+                * is supported and the free blocks will be trimmed online.
+                */
+               if (!test_opt(sb, DISCARD))
+                       EXT4_MB_GRP_CLEAR_TRIMMED(db);
+
                if (!db->bb_free_root.rb_node) {
                        /* No more items in the per group rb tree
                         * balance refcounts from ext4_mb_free_metadata()
@@ -2771,8 +2800,8 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
                 * We leak some of the blocks here.
                 */
                ext4_lock_group(sb, ac->ac_b_ex.fe_group);
-               mb_set_bits(bitmap_bh->b_data, ac->ac_b_ex.fe_start,
-                           ac->ac_b_ex.fe_len);
+               ext4_set_bits(bitmap_bh->b_data, ac->ac_b_ex.fe_start,
+                             ac->ac_b_ex.fe_len);
                ext4_unlock_group(sb, ac->ac_b_ex.fe_group);
                err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
                if (!err)
@@ -2790,7 +2819,8 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
                }
        }
 #endif
-       mb_set_bits(bitmap_bh->b_data, ac->ac_b_ex.fe_start,ac->ac_b_ex.fe_len);
+       ext4_set_bits(bitmap_bh->b_data, ac->ac_b_ex.fe_start,
+                     ac->ac_b_ex.fe_len);
        if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
                gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
                ext4_free_blks_set(sb, gdp,
@@ -2830,8 +2860,9 @@ out_err:
 
 /*
  * here we normalize request for locality group
- * Group request are normalized to s_strip size if we set the same via mount
- * option. If not we set it to s_mb_group_prealloc which can be configured via
+ * Group request are normalized to s_mb_group_prealloc, which goes to
+ * s_strip if we set the same via mount option.
+ * s_mb_group_prealloc can be configured via
  * /sys/fs/ext4/<partition>/mb_group_prealloc
  *
  * XXX: should we try to preallocate more than the group has now?
@@ -2842,10 +2873,7 @@ static void ext4_mb_normalize_group_request(struct ext4_allocation_context *ac)
        struct ext4_locality_group *lg = ac->ac_lg;
 
        BUG_ON(lg == NULL);
-       if (EXT4_SB(sb)->s_stripe)
-               ac->ac_g_ex.fe_len = EXT4_SB(sb)->s_stripe;
-       else
-               ac->ac_g_ex.fe_len = EXT4_SB(sb)->s_mb_group_prealloc;
+       ac->ac_g_ex.fe_len = EXT4_SB(sb)->s_mb_group_prealloc;
        mb_debug(1, "#%u: goal %u blocks for locality group\n",
                current->pid, ac->ac_g_ex.fe_len);
 }
@@ -3001,9 +3029,10 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac,
 
        if (start + size <= ac->ac_o_ex.fe_logical &&
                        start > ac->ac_o_ex.fe_logical) {
-               printk(KERN_ERR "start %lu, size %lu, fe_logical %lu\n",
-                       (unsigned long) start, (unsigned long) size,
-                       (unsigned long) ac->ac_o_ex.fe_logical);
+               ext4_msg(ac->ac_sb, KERN_ERR,
+                        "start %lu, size %lu, fe_logical %lu",
+                        (unsigned long) start, (unsigned long) size,
+                        (unsigned long) ac->ac_o_ex.fe_logical);
        }
        BUG_ON(start + size <= ac->ac_o_ex.fe_logical &&
                        start > ac->ac_o_ex.fe_logical);
@@ -3262,7 +3291,7 @@ static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap,
 
        while (n) {
                entry = rb_entry(n, struct ext4_free_data, node);
-               mb_set_bits(bitmap, entry->start_blk, entry->count);
+               ext4_set_bits(bitmap, entry->start_blk, entry->count);
                n = rb_next(n);
        }
        return;
@@ -3304,7 +3333,7 @@ void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
                if (unlikely(len == 0))
                        continue;
                BUG_ON(groupnr != group);
-               mb_set_bits(bitmap, start, len);
+               ext4_set_bits(bitmap, start, len);
                preallocated += len;
                count++;
        }
@@ -3584,10 +3613,11 @@ ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh,
                bit = next + 1;
        }
        if (free != pa->pa_free) {
-               printk(KERN_CRIT "pa %p: logic %lu, phys. %lu, len %lu\n",
-                       pa, (unsigned long) pa->pa_lstart,
-                       (unsigned long) pa->pa_pstart,
-                       (unsigned long) pa->pa_len);
+               ext4_msg(e4b->bd_sb, KERN_CRIT,
+                        "pa %p: logic %lu, phys. %lu, len %lu",
+                        pa, (unsigned long) pa->pa_lstart,
+                        (unsigned long) pa->pa_pstart,
+                        (unsigned long) pa->pa_len);
                ext4_grp_locked_error(sb, group, 0, 0, "free %u, pa_free %u",
                                        free, pa->pa_free);
                /*
@@ -3775,7 +3805,8 @@ repeat:
                         * use preallocation while we're discarding it */
                        spin_unlock(&pa->pa_lock);
                        spin_unlock(&ei->i_prealloc_lock);
-                       printk(KERN_ERR "uh-oh! used pa while discarding\n");
+                       ext4_msg(sb, KERN_ERR,
+                                "uh-oh! used pa while discarding");
                        WARN_ON(1);
                        schedule_timeout_uninterruptible(HZ);
                        goto repeat;
@@ -3852,12 +3883,13 @@ static void ext4_mb_show_ac(struct ext4_allocation_context *ac)
            (EXT4_SB(sb)->s_mount_flags & EXT4_MF_FS_ABORTED))
                return;
 
-       printk(KERN_ERR "EXT4-fs: Can't allocate:"
-                       " Allocation context details:\n");
-       printk(KERN_ERR "EXT4-fs: status %d flags %d\n",
+       ext4_msg(ac->ac_sb, KERN_ERR, "EXT4-fs: Can't allocate:"
+                       " Allocation context details:");
+       ext4_msg(ac->ac_sb, KERN_ERR, "EXT4-fs: status %d flags %d",
                        ac->ac_status, ac->ac_flags);
-       printk(KERN_ERR "EXT4-fs: orig %lu/%lu/%lu@%lu, goal %lu/%lu/%lu@%lu, "
-                       "best %lu/%lu/%lu@%lu cr %d\n",
+       ext4_msg(ac->ac_sb, KERN_ERR, "EXT4-fs: orig %lu/%lu/%lu@%lu, "
+                       "goal %lu/%lu/%lu@%lu, "
+                       "best %lu/%lu/%lu@%lu cr %d",
                        (unsigned long)ac->ac_o_ex.fe_group,
                        (unsigned long)ac->ac_o_ex.fe_start,
                        (unsigned long)ac->ac_o_ex.fe_len,
@@ -3871,9 +3903,9 @@ static void ext4_mb_show_ac(struct ext4_allocation_context *ac)
                        (unsigned long)ac->ac_b_ex.fe_len,
                        (unsigned long)ac->ac_b_ex.fe_logical,
                        (int)ac->ac_criteria);
-       printk(KERN_ERR "EXT4-fs: %lu scanned, %d found\n", ac->ac_ex_scanned,
-               ac->ac_found);
-       printk(KERN_ERR "EXT4-fs: groups: \n");
+       ext4_msg(ac->ac_sb, KERN_ERR, "EXT4-fs: %lu scanned, %d found",
+                ac->ac_ex_scanned, ac->ac_found);
+       ext4_msg(ac->ac_sb, KERN_ERR, "EXT4-fs: groups: ");
        ngroups = ext4_get_groups_count(sb);
        for (i = 0; i < ngroups; i++) {
                struct ext4_group_info *grp = ext4_get_group_info(sb, i);
@@ -4637,7 +4669,7 @@ do_more:
        }
        ext4_mark_super_dirty(sb);
 error_return:
-       if (freed)
+       if (freed && !(flags & EXT4_FREE_BLOCKS_NO_QUOT_UPDATE))
                dquot_free_block(inode, freed);
        brelse(bitmap_bh);
        ext4_std_error(sb, err);
@@ -4645,7 +4677,7 @@ error_return:
 }
 
 /**
- * ext4_add_groupblocks() -- Add given blocks to an existing group
+ * ext4_group_add_blocks() -- Add given blocks to an existing group
  * @handle:                    handle to this transaction
  * @sb:                                super block
  * @block:                     start physcial block to add to the block group
@@ -4653,7 +4685,7 @@ error_return:
  *
  * This marks the blocks as free in the bitmap and buddy.
  */
-void ext4_add_groupblocks(handle_t *handle, struct super_block *sb,
+int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,
                         ext4_fsblk_t block, unsigned long count)
 {
        struct buffer_head *bitmap_bh = NULL;
@@ -4666,25 +4698,35 @@ void ext4_add_groupblocks(handle_t *handle, struct super_block *sb,
        struct ext4_buddy e4b;
        int err = 0, ret, blk_free_count;
        ext4_grpblk_t blocks_freed;
-       struct ext4_group_info *grp;
 
        ext4_debug("Adding block(s) %llu-%llu\n", block, block + count - 1);
 
+       if (count == 0)
+               return 0;
+
        ext4_get_group_no_and_offset(sb, block, &block_group, &bit);
-       grp = ext4_get_group_info(sb, block_group);
        /*
         * Check to see if we are freeing blocks across a group
         * boundary.
         */
-       if (bit + count > EXT4_BLOCKS_PER_GROUP(sb))
+       if (bit + count > EXT4_BLOCKS_PER_GROUP(sb)) {
+               ext4_warning(sb, "too much blocks added to group %u\n",
+                            block_group);
+               err = -EINVAL;
                goto error_return;
+       }
 
        bitmap_bh = ext4_read_block_bitmap(sb, block_group);
-       if (!bitmap_bh)
+       if (!bitmap_bh) {
+               err = -EIO;
                goto error_return;
+       }
+
        desc = ext4_get_group_desc(sb, block_group, &gd_bh);
-       if (!desc)
+       if (!desc) {
+               err = -EIO;
                goto error_return;
+       }
 
        if (in_range(ext4_block_bitmap(sb, desc), block, count) ||
            in_range(ext4_inode_bitmap(sb, desc), block, count) ||
@@ -4694,6 +4736,7 @@ void ext4_add_groupblocks(handle_t *handle, struct super_block *sb,
                ext4_error(sb, "Adding blocks in system zones - "
                           "Block = %llu, count = %lu",
                           block, count);
+               err = -EINVAL;
                goto error_return;
        }
 
@@ -4762,7 +4805,7 @@ void ext4_add_groupblocks(handle_t *handle, struct super_block *sb,
 error_return:
        brelse(bitmap_bh);
        ext4_std_error(sb, err);
-       return;
+       return err;
 }
 
 /**
@@ -4782,6 +4825,8 @@ static void ext4_trim_extent(struct super_block *sb, int start, int count,
 {
        struct ext4_free_extent ex;
 
+       trace_ext4_trim_extent(sb, group, start, count);
+
        assert_spin_locked(ext4_group_lock_ptr(sb, group));
 
        ex.fe_start = start;
@@ -4802,7 +4847,7 @@ static void ext4_trim_extent(struct super_block *sb, int start, int count,
 /**
  * ext4_trim_all_free -- function to trim all free space in alloc. group
  * @sb:                        super block for file system
- * @e4b:               ext4 buddy
+ * @group:             group to be trimmed
  * @start:             first group block to examine
  * @max:               last group block to examine
  * @minblocks:         minimum extent block count
@@ -4823,10 +4868,12 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
                   ext4_grpblk_t minblocks)
 {
        void *bitmap;
-       ext4_grpblk_t next, count = 0;
+       ext4_grpblk_t next, count = 0, free_count = 0;
        struct ext4_buddy e4b;
        int ret;
 
+       trace_ext4_trim_all_free(sb, group, start, max);
+
        ret = ext4_mb_load_buddy(sb, group, &e4b);
        if (ret) {
                ext4_error(sb, "Error in loading buddy "
@@ -4836,6 +4883,10 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
        bitmap = e4b.bd_bitmap;
 
        ext4_lock_group(sb, group);
+       if (EXT4_MB_GRP_WAS_TRIMMED(e4b.bd_info) &&
+           minblocks >= atomic_read(&EXT4_SB(sb)->s_last_trim_minblks))
+               goto out;
+
        start = (e4b.bd_info->bb_first_free > start) ?
                e4b.bd_info->bb_first_free : start;
 
@@ -4850,6 +4901,7 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
                                         next - start, group, &e4b);
                        count += next - start;
                }
+               free_count += next - start;
                start = next + 1;
 
                if (fatal_signal_pending(current)) {
@@ -4863,9 +4915,13 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
                        ext4_lock_group(sb, group);
                }
 
-               if ((e4b.bd_info->bb_free - count) < minblocks)
+               if ((e4b.bd_info->bb_free - free_count) < minblocks)
                        break;
        }
+
+       if (!ret)
+               EXT4_MB_GRP_SET_TRIMMED(e4b.bd_info);
+out:
        ext4_unlock_group(sb, group);
        ext4_mb_unload_buddy(&e4b);
 
@@ -4904,6 +4960,8 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
 
        if (unlikely(minlen > EXT4_BLOCKS_PER_GROUP(sb)))
                return -EINVAL;
+       if (start + len <= first_data_blk)
+               goto out;
        if (start < first_data_blk) {
                len -= first_data_blk - start;
                start = first_data_blk;
@@ -4952,5 +5010,9 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
        }
        range->len = trimmed * sb->s_blocksize;
 
+       if (!ret)
+               atomic_set(&EXT4_SB(sb)->s_last_trim_minblks, minlen);
+
+out:
        return ret;
 }
index 20b5e7b..9d4a636 100644 (file)
@@ -187,7 +187,6 @@ struct ext4_allocation_context {
        __u16 ac_flags;         /* allocation hints */
        __u8 ac_status;
        __u8 ac_criteria;
-       __u8 ac_repeats;
        __u8 ac_2order;         /* if request is to allocate 2^N blocks and
                                 * N > 0, the field stores N, otherwise 0 */
        __u8 ac_op;             /* operation, for history only */
index 8c9baba..f8068c7 100644 (file)
@@ -289,7 +289,7 @@ static struct stats dx_show_leaf(struct dx_hash_info *hinfo, struct ext4_dir_ent
                                while (len--) printk("%c", *name++);
                                ext4fs_dirhash(de->name, de->name_len, &h);
                                printk(":%x.%u ", h.hash,
-                                      ((char *) de - base));
+                                      (unsigned) ((char *) de - base));
                        }
                        space += EXT4_DIR_REC_LEN(de->name_len);
                        names++;
@@ -1013,7 +1013,7 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir, const struct q
 
        *err = -ENOENT;
 errout:
-       dxtrace(printk(KERN_DEBUG "%s not found\n", name));
+       dxtrace(printk(KERN_DEBUG "%s not found\n", d_name->name));
        dx_release (frames);
        return NULL;
 }
@@ -1985,18 +1985,11 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode)
        if (!list_empty(&EXT4_I(inode)->i_orphan))
                goto out_unlock;
 
-       /* Orphan handling is only valid for files with data blocks
-        * being truncated, or files being unlinked. */
-
-       /* @@@ FIXME: Observation from aviro:
-        * I think I can trigger J_ASSERT in ext4_orphan_add().  We block
-        * here (on s_orphan_lock), so race with ext4_link() which might bump
-        * ->i_nlink. For, say it, character device. Not a regular file,
-        * not a directory, not a symlink and ->i_nlink > 0.
-        *
-        * tytso, 4/25/2009: I'm not sure how that could happen;
-        * shouldn't the fs core protect us from these sort of
-        * unlink()/link() races?
+       /*
+        * Orphan handling is only valid for files with data blocks
+        * being truncated, or files being unlinked. Note that we either
+        * hold i_mutex, or the inode can not be referenced from outside,
+        * so i_nlink should not be bumped due to race
         */
        J_ASSERT((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
                  S_ISLNK(inode->i_mode)) || inode->i_nlink == 0);
@@ -2260,9 +2253,11 @@ static int ext4_symlink(struct inode *dir,
                /*
                 * For non-fast symlinks, we just allocate inode and put it on
                 * orphan list in the first transaction => we need bitmap,
-                * group descriptor, sb, inode block, quota blocks.
+                * group descriptor, sb, inode block, quota blocks, and
+                * possibly selinux xattr blocks.
                 */
-               credits = 4 + EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb);
+               credits = 4 + EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb) +
+                         EXT4_XATTR_TRANS_BLOCKS;
        } else {
                /*
                 * Fast symlink. We have to add entry to directory
index 7bb8f76..78839af 100644 (file)
@@ -285,11 +285,7 @@ static int io_submit_init(struct ext4_io_submit *io,
        io_end = ext4_init_io_end(inode, GFP_NOFS);
        if (!io_end)
                return -ENOMEM;
-       do {
-               bio = bio_alloc(GFP_NOIO, nvecs);
-               nvecs >>= 1;
-       } while (bio == NULL);
-
+       bio = bio_alloc(GFP_NOIO, min(nvecs, BIO_MAX_PAGES));
        bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9);
        bio->bi_bdev = bh->b_bdev;
        bio->bi_private = io->io_end = io_end;
@@ -338,8 +334,10 @@ submit_and_retry:
        if ((io_end->num_io_pages >= MAX_IO_PAGES) &&
            (io_end->pages[io_end->num_io_pages-1] != io_page))
                goto submit_and_retry;
-       if (buffer_uninit(bh))
-               io->io_end->flag |= EXT4_IO_END_UNWRITTEN;
+       if (buffer_uninit(bh) && !(io_end->flag & EXT4_IO_END_UNWRITTEN)) {
+               io_end->flag |= EXT4_IO_END_UNWRITTEN;
+               atomic_inc(&EXT4_I(inode)->i_aiodio_unwritten);
+       }
        io->io_end->size += bh->b_size;
        io->io_next_block++;
        ret = bio_add_page(io->io_bio, bh->b_page, bh->b_size, bh_offset(bh));
index 80bbc9c..707d3f1 100644 (file)
 
 #include "ext4_jbd2.h"
 
+int ext4_resize_begin(struct super_block *sb)
+{
+       int ret = 0;
+
+       if (!capable(CAP_SYS_RESOURCE))
+               return -EPERM;
+
+       /*
+        * We are not allowed to do online-resizing on a filesystem mounted
+        * with error, because it can destroy the filesystem easily.
+        */
+       if (EXT4_SB(sb)->s_mount_state & EXT4_ERROR_FS) {
+               ext4_warning(sb, "There are errors in the filesystem, "
+                            "so online resizing is not allowed\n");
+               return -EPERM;
+       }
+
+       if (test_and_set_bit_lock(EXT4_RESIZING, &EXT4_SB(sb)->s_resize_flags))
+               ret = -EBUSY;
+
+       return ret;
+}
+
+void ext4_resize_end(struct super_block *sb)
+{
+       clear_bit_unlock(EXT4_RESIZING, &EXT4_SB(sb)->s_resize_flags);
+       smp_mb__after_clear_bit();
+}
+
 #define outside(b, first, last)        ((b) < (first) || (b) >= (last))
 #define inside(b, first, last) ((b) >= (first) && (b) < (last))
 
@@ -118,10 +147,8 @@ static struct buffer_head *bclean(handle_t *handle, struct super_block *sb,
                brelse(bh);
                bh = ERR_PTR(err);
        } else {
-               lock_buffer(bh);
                memset(bh->b_data, 0, sb->s_blocksize);
                set_buffer_uptodate(bh);
-               unlock_buffer(bh);
        }
 
        return bh;
@@ -132,8 +159,7 @@ static struct buffer_head *bclean(handle_t *handle, struct super_block *sb,
  * If that fails, restart the transaction & regain write access for the
  * buffer head which is used for block_bitmap modifications.
  */
-static int extend_or_restart_transaction(handle_t *handle, int thresh,
-                                        struct buffer_head *bh)
+static int extend_or_restart_transaction(handle_t *handle, int thresh)
 {
        int err;
 
@@ -144,9 +170,8 @@ static int extend_or_restart_transaction(handle_t *handle, int thresh,
        if (err < 0)
                return err;
        if (err) {
-               if ((err = ext4_journal_restart(handle, EXT4_MAX_TRANS_DATA)))
-                       return err;
-               if ((err = ext4_journal_get_write_access(handle, bh)))
+               err = ext4_journal_restart(handle, EXT4_MAX_TRANS_DATA);
+               if (err)
                        return err;
        }
 
@@ -181,21 +206,7 @@ static int setup_new_group_blocks(struct super_block *sb,
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
-       mutex_lock(&sbi->s_resize_lock);
-       if (input->group != sbi->s_groups_count) {
-               err = -EBUSY;
-               goto exit_journal;
-       }
-
-       if (IS_ERR(bh = bclean(handle, sb, input->block_bitmap))) {
-               err = PTR_ERR(bh);
-               goto exit_journal;
-       }
-
-       if (ext4_bg_has_super(sb, input->group)) {
-               ext4_debug("mark backup superblock %#04llx (+0)\n", start);
-               ext4_set_bit(0, bh->b_data);
-       }
+       BUG_ON(input->group != sbi->s_groups_count);
 
        /* Copy all of the GDT blocks into the backup in this group */
        for (i = 0, bit = 1, block = start + 1;
@@ -203,29 +214,26 @@ static int setup_new_group_blocks(struct super_block *sb,
                struct buffer_head *gdb;
 
                ext4_debug("update backup group %#04llx (+%d)\n", block, bit);
-
-               if ((err = extend_or_restart_transaction(handle, 1, bh)))
-                       goto exit_bh;
+               err = extend_or_restart_transaction(handle, 1);
+               if (err)
+                       goto exit_journal;
 
                gdb = sb_getblk(sb, block);
                if (!gdb) {
                        err = -EIO;
-                       goto exit_bh;
+                       goto exit_journal;
                }
                if ((err = ext4_journal_get_write_access(handle, gdb))) {
                        brelse(gdb);
-                       goto exit_bh;
+                       goto exit_journal;
                }
-               lock_buffer(gdb);
                memcpy(gdb->b_data, sbi->s_group_desc[i]->b_data, gdb->b_size);
                set_buffer_uptodate(gdb);
-               unlock_buffer(gdb);
                err = ext4_handle_dirty_metadata(handle, NULL, gdb);
                if (unlikely(err)) {
                        brelse(gdb);
-                       goto exit_bh;
+                       goto exit_journal;
                }
-               ext4_set_bit(bit, bh->b_data);
                brelse(gdb);
        }
 
@@ -235,9 +243,22 @@ static int setup_new_group_blocks(struct super_block *sb,
        err = sb_issue_zeroout(sb, gdblocks + start + 1, reserved_gdb,
                               GFP_NOFS);
        if (err)
-               goto exit_bh;
-       for (i = 0, bit = gdblocks + 1; i < reserved_gdb; i++, bit++)
-               ext4_set_bit(bit, bh->b_data);
+               goto exit_journal;
+
+       err = extend_or_restart_transaction(handle, 2);
+       if (err)
+               goto exit_journal;
+
+       bh = bclean(handle, sb, input->block_bitmap);
+       if (IS_ERR(bh)) {
+               err = PTR_ERR(bh);
+               goto exit_journal;
+       }
+
+       if (ext4_bg_has_super(sb, input->group)) {
+               ext4_debug("mark backup group tables %#04llx (+0)\n", start);
+               ext4_set_bits(bh->b_data, 0, gdblocks + reserved_gdb + 1);
+       }
 
        ext4_debug("mark block bitmap %#04llx (+%llu)\n", input->block_bitmap,
                   input->block_bitmap - start);
@@ -253,12 +274,9 @@ static int setup_new_group_blocks(struct super_block *sb,
        err = sb_issue_zeroout(sb, block, sbi->s_itb_per_group, GFP_NOFS);
        if (err)
                goto exit_bh;
-       for (i = 0, bit = input->inode_table - start;
-            i < sbi->s_itb_per_group; i++, bit++)
-               ext4_set_bit(bit, bh->b_data);
+       ext4_set_bits(bh->b_data, input->inode_table - start,
+                     sbi->s_itb_per_group);
 
-       if ((err = extend_or_restart_transaction(handle, 2, bh)))
-               goto exit_bh;
 
        ext4_mark_bitmap_end(input->blocks_count, sb->s_blocksize * 8,
                             bh->b_data);
@@ -285,7 +303,6 @@ exit_bh:
        brelse(bh);
 
 exit_journal:
-       mutex_unlock(&sbi->s_resize_lock);
        if ((err2 = ext4_journal_stop(handle)) && !err)
                err = err2;
 
@@ -377,15 +394,15 @@ static int verify_reserved_gdb(struct super_block *sb,
  * fail once we start modifying the data on disk, because JBD has no rollback.
  */
 static int add_new_gdb(handle_t *handle, struct inode *inode,
-                      struct ext4_new_group_data *input,
-                      struct buffer_head **primary)
+                      ext4_group_t group)
 {
        struct super_block *sb = inode->i_sb;
        struct ext4_super_block *es = EXT4_SB(sb)->s_es;
-       unsigned long gdb_num = input->group / EXT4_DESC_PER_BLOCK(sb);
+       unsigned long gdb_num = group / EXT4_DESC_PER_BLOCK(sb);
        ext4_fsblk_t gdblock = EXT4_SB(sb)->s_sbh->b_blocknr + 1 + gdb_num;
        struct buffer_head **o_group_desc, **n_group_desc;
        struct buffer_head *dind;
+       struct buffer_head *gdb_bh;
        int gdbackups;
        struct ext4_iloc iloc;
        __le32 *data;
@@ -408,11 +425,12 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
                return -EPERM;
        }
 
-       *primary = sb_bread(sb, gdblock);
-       if (!*primary)
+       gdb_bh = sb_bread(sb, gdblock);
+       if (!gdb_bh)
                return -EIO;
 
-       if ((gdbackups = verify_reserved_gdb(sb, *primary)) < 0) {
+       gdbackups = verify_reserved_gdb(sb, gdb_bh);
+       if (gdbackups < 0) {
                err = gdbackups;
                goto exit_bh;
        }
@@ -427,7 +445,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
        data = (__le32 *)dind->b_data;
        if (le32_to_cpu(data[gdb_num % EXT4_ADDR_PER_BLOCK(sb)]) != gdblock) {
                ext4_warning(sb, "new group %u GDT block %llu not reserved",
-                            input->group, gdblock);
+                            group, gdblock);
                err = -EINVAL;
                goto exit_dind;
        }
@@ -436,7 +454,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
        if (unlikely(err))
                goto exit_dind;
 
-       err = ext4_journal_get_write_access(handle, *primary);
+       err = ext4_journal_get_write_access(handle, gdb_bh);
        if (unlikely(err))
                goto exit_sbh;
 
@@ -449,12 +467,13 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
        if (unlikely(err))
                goto exit_dindj;
 
-       n_group_desc = kmalloc((gdb_num + 1) * sizeof(struct buffer_head *),
-                       GFP_NOFS);
+       n_group_desc = ext4_kvmalloc((gdb_num + 1) *
+                                    sizeof(struct buffer_head *),
+                                    GFP_NOFS);
        if (!n_group_desc) {
                err = -ENOMEM;
-               ext4_warning(sb,
-                             "not enough memory for %lu groups", gdb_num + 1);
+               ext4_warning(sb, "not enough memory for %lu groups",
+                            gdb_num + 1);
                goto exit_inode;
        }
 
@@ -475,8 +494,8 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
        }
        inode->i_blocks -= (gdbackups + 1) * sb->s_blocksize >> 9;
        ext4_mark_iloc_dirty(handle, inode, &iloc);
-       memset((*primary)->b_data, 0, sb->s_blocksize);
-       err = ext4_handle_dirty_metadata(handle, NULL, *primary);
+       memset(gdb_bh->b_data, 0, sb->s_blocksize);
+       err = ext4_handle_dirty_metadata(handle, NULL, gdb_bh);
        if (unlikely(err)) {
                ext4_std_error(sb, err);
                goto exit_inode;
@@ -486,10 +505,10 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
        o_group_desc = EXT4_SB(sb)->s_group_desc;
        memcpy(n_group_desc, o_group_desc,
               EXT4_SB(sb)->s_gdb_count * sizeof(struct buffer_head *));
-       n_group_desc[gdb_num] = *primary;
+       n_group_desc[gdb_num] = gdb_bh;
        EXT4_SB(sb)->s_group_desc = n_group_desc;
        EXT4_SB(sb)->s_gdb_count++;
-       kfree(o_group_desc);
+       ext4_kvfree(o_group_desc);
 
        le16_add_cpu(&es->s_reserved_gdt_blocks, -1);
        err = ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh);
@@ -499,6 +518,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
        return err;
 
 exit_inode:
+       ext4_kvfree(n_group_desc);
        /* ext4_handle_release_buffer(handle, iloc.bh); */
        brelse(iloc.bh);
 exit_dindj:
@@ -508,7 +528,7 @@ exit_sbh:
 exit_dind:
        brelse(dind);
 exit_bh:
-       brelse(*primary);
+       brelse(gdb_bh);
 
        ext4_debug("leaving with error %d\n", err);
        return err;
@@ -528,7 +548,7 @@ exit_bh:
  * backup GDT blocks are stored in their reserved primary GDT block.
  */
 static int reserve_backup_gdb(handle_t *handle, struct inode *inode,
-                             struct ext4_new_group_data *input)
+                             ext4_group_t group)
 {
        struct super_block *sb = inode->i_sb;
        int reserved_gdb =le16_to_cpu(EXT4_SB(sb)->s_es->s_reserved_gdt_blocks);
@@ -599,7 +619,7 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode,
         * Finally we can add each of the reserved backup GDT blocks from
         * the new group to its reserved primary GDT block.
         */
-       blk = input->group * EXT4_BLOCKS_PER_GROUP(sb);
+       blk = group * EXT4_BLOCKS_PER_GROUP(sb);
        for (i = 0; i < reserved_gdb; i++) {
                int err2;
                data = (__le32 *)primary[i]->b_data;
@@ -799,13 +819,6 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
                goto exit_put;
        }
 
-       mutex_lock(&sbi->s_resize_lock);
-       if (input->group != sbi->s_groups_count) {
-               ext4_warning(sb, "multiple resizers run on filesystem!");
-               err = -EBUSY;
-               goto exit_journal;
-       }
-
        if ((err = ext4_journal_get_write_access(handle, sbi->s_sbh)))
                goto exit_journal;
 
@@ -820,16 +833,25 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
                if ((err = ext4_journal_get_write_access(handle, primary)))
                        goto exit_journal;
 
-               if (reserved_gdb && ext4_bg_num_gdb(sb, input->group) &&
-                   (err = reserve_backup_gdb(handle, inode, input)))
+               if (reserved_gdb && ext4_bg_num_gdb(sb, input->group)) {
+                       err = reserve_backup_gdb(handle, inode, input->group);
+                       if (err)
+                               goto exit_journal;
+               }
+       } else {
+               /*
+                * Note that we can access new group descriptor block safely
+                * only if add_new_gdb() succeeds.
+                */
+               err = add_new_gdb(handle, inode, input->group);
+               if (err)
                        goto exit_journal;
-       } else if ((err = add_new_gdb(handle, inode, input, &primary)))
-               goto exit_journal;
+               primary = sbi->s_group_desc[gdb_num];
+       }
 
         /*
          * OK, now we've set up the new group.  Time to make it active.
          *
-         * We do not lock all allocations via s_resize_lock
          * so we have to be safe wrt. concurrent accesses the group
          * data.  So we need to be careful to set all of the relevant
          * group descriptor data etc. *before* we enable the group.
@@ -886,13 +908,9 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
         *
         * The precise rules we use are:
         *
-        * * Writers of s_groups_count *must* hold s_resize_lock
-        * AND
         * * Writers must perform a smp_wmb() after updating all dependent
         *   data and before modifying the groups count
         *
-        * * Readers must hold s_resize_lock over the access
-        * OR
         * * Readers must perform an smp_rmb() after reading the groups count
         *   and before reading any dependent data.
         *
@@ -937,10 +955,9 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
        ext4_handle_dirty_super(handle, sb);
 
 exit_journal:
-       mutex_unlock(&sbi->s_resize_lock);
        if ((err2 = ext4_journal_stop(handle)) && !err)
                err = err2;
-       if (!err) {
+       if (!err && primary) {
                update_backups(sb, sbi->s_sbh->b_blocknr, (char *)es,
                               sizeof(struct ext4_super_block));
                update_backups(sb, primary->b_blocknr, primary->b_data,
@@ -969,16 +986,13 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
        ext4_grpblk_t add;
        struct buffer_head *bh;
        handle_t *handle;
-       int err;
+       int err, err2;
        ext4_group_t group;
 
-       /* We don't need to worry about locking wrt other resizers just
-        * yet: we're going to revalidate es->s_blocks_count after
-        * taking the s_resize_lock below. */
        o_blocks_count = ext4_blocks_count(es);
 
        if (test_opt(sb, DEBUG))
-               printk(KERN_DEBUG "EXT4-fs: extending last group from %llu uto %llu blocks\n",
+               printk(KERN_DEBUG "EXT4-fs: extending last group from %llu to %llu blocks\n",
                       o_blocks_count, n_blocks_count);
 
        if (n_blocks_count == 0 || n_blocks_count == o_blocks_count)
@@ -995,7 +1009,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
 
        if (n_blocks_count < o_blocks_count) {
                ext4_warning(sb, "can't shrink FS - resize aborted");
-               return -EBUSY;
+               return -EINVAL;
        }
 
        /* Handle the remaining blocks in the last group only. */
@@ -1038,32 +1052,25 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
                goto exit_put;
        }
 
-       mutex_lock(&EXT4_SB(sb)->s_resize_lock);
-       if (o_blocks_count != ext4_blocks_count(es)) {
-               ext4_warning(sb, "multiple resizers run on filesystem!");
-               mutex_unlock(&EXT4_SB(sb)->s_resize_lock);
-               ext4_journal_stop(handle);
-               err = -EBUSY;
-               goto exit_put;
-       }
-
        if ((err = ext4_journal_get_write_access(handle,
                                                 EXT4_SB(sb)->s_sbh))) {
                ext4_warning(sb, "error %d on journal write access", err);
-               mutex_unlock(&EXT4_SB(sb)->s_resize_lock);
                ext4_journal_stop(handle);
                goto exit_put;
        }
        ext4_blocks_count_set(es, o_blocks_count + add);
-       mutex_unlock(&EXT4_SB(sb)->s_resize_lock);
        ext4_debug("freeing blocks %llu through %llu\n", o_blocks_count,
                   o_blocks_count + add);
        /* We add the blocks to the bitmap and set the group need init bit */
-       ext4_add_groupblocks(handle, sb, o_blocks_count, add);
+       err = ext4_group_add_blocks(handle, sb, o_blocks_count, add);
        ext4_handle_dirty_super(handle, sb);
        ext4_debug("freed blocks %llu through %llu\n", o_blocks_count,
                   o_blocks_count + add);
-       if ((err = ext4_journal_stop(handle)))
+       err2 = ext4_journal_stop(handle);
+       if (!err && err2)
+               err = err2;
+
+       if (err)
                goto exit_put;
 
        if (test_opt(sb, DEBUG))
index 9ea71aa..44d0c8d 100644 (file)
@@ -110,6 +110,35 @@ static struct file_system_type ext3_fs_type = {
 #define IS_EXT3_SB(sb) (0)
 #endif
 
+void *ext4_kvmalloc(size_t size, gfp_t flags)
+{
+       void *ret;
+
+       ret = kmalloc(size, flags);
+       if (!ret)
+               ret = __vmalloc(size, flags, PAGE_KERNEL);
+       return ret;
+}
+
+void *ext4_kvzalloc(size_t size, gfp_t flags)
+{
+       void *ret;
+
+       ret = kzalloc(size, flags);
+       if (!ret)
+               ret = __vmalloc(size, flags | __GFP_ZERO, PAGE_KERNEL);
+       return ret;
+}
+
+void ext4_kvfree(void *ptr)
+{
+       if (is_vmalloc_addr(ptr))
+               vfree(ptr);
+       else
+               kfree(ptr);
+
+}
+
 ext4_fsblk_t ext4_block_bitmap(struct super_block *sb,
                               struct ext4_group_desc *bg)
 {
@@ -269,6 +298,7 @@ handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks)
        journal_t *journal;
        handle_t  *handle;
 
+       trace_ext4_journal_start(sb, nblocks, _RET_IP_);
        if (sb->s_flags & MS_RDONLY)
                return ERR_PTR(-EROFS);
 
@@ -789,11 +819,8 @@ static void ext4_put_super(struct super_block *sb)
 
        for (i = 0; i < sbi->s_gdb_count; i++)
                brelse(sbi->s_group_desc[i]);
-       kfree(sbi->s_group_desc);
-       if (is_vmalloc_addr(sbi->s_flex_groups))
-               vfree(sbi->s_flex_groups);
-       else
-               kfree(sbi->s_flex_groups);
+       ext4_kvfree(sbi->s_group_desc);
+       ext4_kvfree(sbi->s_flex_groups);
        percpu_counter_destroy(&sbi->s_freeblocks_counter);
        percpu_counter_destroy(&sbi->s_freeinodes_counter);
        percpu_counter_destroy(&sbi->s_dirs_counter);
@@ -892,7 +919,6 @@ static void ext4_i_callback(struct rcu_head *head)
 
 static void ext4_destroy_inode(struct inode *inode)
 {
-       ext4_ioend_wait(inode);
        if (!list_empty(&(EXT4_I(inode)->i_orphan))) {
                ext4_msg(inode->i_sb, KERN_ERR,
                         "Inode %lu (%p): orphan list check failed!",
@@ -1976,15 +2002,11 @@ static int ext4_fill_flex_info(struct super_block *sb)
                        ((le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) + 1) <<
                              EXT4_DESC_PER_BLOCK_BITS(sb))) / groups_per_flex;
        size = flex_group_count * sizeof(struct flex_groups);
-       sbi->s_flex_groups = kzalloc(size, GFP_KERNEL);
+       sbi->s_flex_groups = ext4_kvzalloc(size, GFP_KERNEL);
        if (sbi->s_flex_groups == NULL) {
-               sbi->s_flex_groups = vzalloc(size);
-               if (sbi->s_flex_groups == NULL) {
-                       ext4_msg(sb, KERN_ERR,
-                                "not enough memory for %u flex groups",
-                                flex_group_count);
-                       goto failed;
-               }
+               ext4_msg(sb, KERN_ERR, "not enough memory for %u flex groups",
+                        flex_group_count);
+               goto failed;
        }
 
        for (i = 0; i < sbi->s_groups_count; i++) {
@@ -2383,17 +2405,25 @@ static unsigned long ext4_get_stripe_size(struct ext4_sb_info *sbi)
        unsigned long stride = le16_to_cpu(sbi->s_es->s_raid_stride);
        unsigned long stripe_width =
                        le32_to_cpu(sbi->s_es->s_raid_stripe_width);
+       int ret;
 
        if (sbi->s_stripe && sbi->s_stripe <= sbi->s_blocks_per_group)
-               return sbi->s_stripe;
-
-       if (stripe_width <= sbi->s_blocks_per_group)
-               return stripe_width;
+               ret = sbi->s_stripe;
+       else if (stripe_width <= sbi->s_blocks_per_group)
+               ret = stripe_width;
+       else if (stride <= sbi->s_blocks_per_group)
+               ret = stride;
+       else
+               ret = 0;
 
-       if (stride <= sbi->s_blocks_per_group)
-               return stride;
+       /*
+        * If the stripe width is 1, this makes no sense and
+        * we set it to 0 to turn off stripe handling code.
+        */
+       if (ret <= 1)
+               ret = 0;
 
-       return 0;
+       return ret;
 }
 
 /* sysfs supprt */
@@ -3408,8 +3438,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                        (EXT4_MAX_BLOCK_FILE_PHYS / EXT4_BLOCKS_PER_GROUP(sb)));
        db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) /
                   EXT4_DESC_PER_BLOCK(sb);
-       sbi->s_group_desc = kmalloc(db_count * sizeof(struct buffer_head *),
-                                   GFP_KERNEL);
+       sbi->s_group_desc = ext4_kvmalloc(db_count *
+                                         sizeof(struct buffer_head *),
+                                         GFP_KERNEL);
        if (sbi->s_group_desc == NULL) {
                ext4_msg(sb, KERN_ERR, "not enough memory");
                goto failed_mount;
@@ -3491,7 +3522,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 
        INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */
        mutex_init(&sbi->s_orphan_lock);
-       mutex_init(&sbi->s_resize_lock);
+       sbi->s_resize_flags = 0;
 
        sb->s_root = NULL;
 
@@ -3741,12 +3772,8 @@ failed_mount_wq:
        }
 failed_mount3:
        del_timer(&sbi->s_err_report);
-       if (sbi->s_flex_groups) {
-               if (is_vmalloc_addr(sbi->s_flex_groups))
-                       vfree(sbi->s_flex_groups);
-               else
-                       kfree(sbi->s_flex_groups);
-       }
+       if (sbi->s_flex_groups)
+               ext4_kvfree(sbi->s_flex_groups);
        percpu_counter_destroy(&sbi->s_freeblocks_counter);
        percpu_counter_destroy(&sbi->s_freeinodes_counter);
        percpu_counter_destroy(&sbi->s_dirs_counter);
@@ -3756,7 +3783,7 @@ failed_mount3:
 failed_mount2:
        for (i = 0; i < db_count; i++)
                brelse(sbi->s_group_desc[i]);
-       kfree(sbi->s_group_desc);
+       ext4_kvfree(sbi->s_group_desc);
 failed_mount:
        if (sbi->s_proc) {
                remove_proc_entry(sb->s_id, ext4_proc_root);
diff --git a/fs/ext4/truncate.h b/fs/ext4/truncate.h
new file mode 100644 (file)
index 0000000..011ba66
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * linux/fs/ext4/truncate.h
+ *
+ * Common inline functions needed for truncate support
+ */
+
+/*
+ * Truncate blocks that were not used by write. We have to truncate the
+ * pagecache as well so that corresponding buffers get properly unmapped.
+ */
+static inline void ext4_truncate_failed_write(struct inode *inode)
+{
+       truncate_inode_pages(inode->i_mapping, inode->i_size);
+       ext4_truncate(inode);
+}
+
+/*
+ * Work out how many blocks we need to proceed with the next chunk of a
+ * truncate transaction.
+ */
+static inline unsigned long ext4_blocks_for_truncate(struct inode *inode)
+{
+       ext4_lblk_t needed;
+
+       needed = inode->i_blocks >> (inode->i_sb->s_blocksize_bits - 9);
+
+       /* Give ourselves just enough room to cope with inodes in which
+        * i_blocks is corrupt: we've seen disk corruptions in the past
+        * which resulted in random data in an inode which looked enough
+        * like a regular file for ext4 to try to delete it.  Things
+        * will go a bit crazy if that happens, but at least we should
+        * try not to panic the whole kernel. */
+       if (needed < 2)
+               needed = 2;
+
+       /* But we need to bound the transaction so we don't overflow the
+        * journal. */
+       if (needed > EXT4_MAX_TRANS_DATA)
+               needed = EXT4_MAX_TRANS_DATA;
+
+       return EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + needed;
+}
+
index 4ad6473..5efbd5d 100644 (file)
@@ -1231,7 +1231,7 @@ int fat_add_entries(struct inode *dir, void *slots, int nr_slots,
        struct super_block *sb = dir->i_sb;
        struct msdos_sb_info *sbi = MSDOS_SB(sb);
        struct buffer_head *bh, *prev, *bhs[3]; /* 32*slots (672bytes) */
-       struct msdos_dir_entry *de;
+       struct msdos_dir_entry *uninitialized_var(de);
        int err, free_slots, i, nr_bhs;
        loff_t pos, i_pos;
 
index 5942fec..1726d73 100644 (file)
@@ -1188,9 +1188,9 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat,
 out:
        /* UTF-8 doesn't provide FAT semantics */
        if (!strcmp(opts->iocharset, "utf8")) {
-               fat_msg(sb, KERN_ERR, "utf8 is not a recommended IO charset"
+               fat_msg(sb, KERN_WARNING, "utf8 is not a recommended IO charset"
                       " for FAT filesystems, filesystem will be "
-                      "case sensitive!\n");
+                      "case sensitive!");
        }
 
        /* If user doesn't specify allow_utime, it's initialized from dmask. */
@@ -1367,6 +1367,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
        sbi->free_clusters = -1;        /* Don't know yet */
        sbi->free_clus_valid = 0;
        sbi->prev_free = FAT_START_ENT;
+       sb->s_maxbytes = 0xffffffff;
 
        if (!sbi->fat_length && b->fat32_length) {
                struct fat_boot_fsinfo *fsinfo;
@@ -1377,8 +1378,6 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
                sbi->fat_length = le32_to_cpu(b->fat32_length);
                sbi->root_cluster = le32_to_cpu(b->root_cluster);
 
-               sb->s_maxbytes = 0xffffffff;
-
                /* MC - if info_sector is 0, don't multiply by 0 */
                sbi->fsinfo_sector = le16_to_cpu(b->info_sector);
                if (sbi->fsinfo_sector == 0)
index 1599aa9..04cf3b9 100644 (file)
@@ -618,7 +618,12 @@ static long __writeback_inodes_wb(struct bdi_writeback *wb,
                struct super_block *sb = inode->i_sb;
 
                if (!grab_super_passive(sb)) {
-                       requeue_io(inode, wb);
+                       /*
+                        * grab_super_passive() may fail consistently due to
+                        * s_umount being grabbed by someone else. Don't use
+                        * requeue_io() to avoid busy retrying the inode/sb.
+                        */
+                       redirty_tail(inode, wb);
                        continue;
                }
                wrote += writeback_sb_inodes(sb, wb, work);
index 640fc22..168a80f 100644 (file)
@@ -1358,6 +1358,10 @@ static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size,
        if (outarg.namelen > FUSE_NAME_MAX)
                goto err;
 
+       err = -EINVAL;
+       if (size != sizeof(outarg) + outarg.namelen + 1)
+               goto err;
+
        name.name = buf;
        name.len = outarg.namelen;
        err = fuse_copy_one(cs, buf, outarg.namelen + 1);
index d480d9a..594f07a 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/sched.h>
 #include <linux/module.h>
 #include <linux/compat.h>
+#include <linux/swap.h>
 
 static const struct file_operations fuse_direct_io_file_operations;
 
@@ -245,6 +246,12 @@ void fuse_release_common(struct file *file, int opcode)
        req = ff->reserved_req;
        fuse_prepare_release(ff, file->f_flags, opcode);
 
+       if (ff->flock) {
+               struct fuse_release_in *inarg = &req->misc.release.in;
+               inarg->release_flags |= FUSE_RELEASE_FLOCK_UNLOCK;
+               inarg->lock_owner = fuse_lock_owner_id(ff->fc,
+                                                      (fl_owner_t) file);
+       }
        /* Hold vfsmount and dentry until release is finished */
        path_get(&file->f_path);
        req->misc.release.path = file->f_path;
@@ -755,18 +762,6 @@ static size_t fuse_send_write(struct fuse_req *req, struct file *file,
        return req->misc.write.out.size;
 }
 
-static int fuse_write_begin(struct file *file, struct address_space *mapping,
-                       loff_t pos, unsigned len, unsigned flags,
-                       struct page **pagep, void **fsdata)
-{
-       pgoff_t index = pos >> PAGE_CACHE_SHIFT;
-
-       *pagep = grab_cache_page_write_begin(mapping, index, flags);
-       if (!*pagep)
-               return -ENOMEM;
-       return 0;
-}
-
 void fuse_write_update_size(struct inode *inode, loff_t pos)
 {
        struct fuse_conn *fc = get_fuse_conn(inode);
@@ -779,62 +774,6 @@ void fuse_write_update_size(struct inode *inode, loff_t pos)
        spin_unlock(&fc->lock);
 }
 
-static int fuse_buffered_write(struct file *file, struct inode *inode,
-                              loff_t pos, unsigned count, struct page *page)
-{
-       int err;
-       size_t nres;
-       struct fuse_conn *fc = get_fuse_conn(inode);
-       unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
-       struct fuse_req *req;
-
-       if (is_bad_inode(inode))
-               return -EIO;
-
-       /*
-        * Make sure writepages on the same page are not mixed up with
-        * plain writes.
-        */
-       fuse_wait_on_page_writeback(inode, page->index);
-
-       req = fuse_get_req(fc);
-       if (IS_ERR(req))
-               return PTR_ERR(req);
-
-       req->in.argpages = 1;
-       req->num_pages = 1;
-       req->pages[0] = page;
-       req->page_offset = offset;
-       nres = fuse_send_write(req, file, pos, count, NULL);
-       err = req->out.h.error;
-       fuse_put_request(fc, req);
-       if (!err && !nres)
-               err = -EIO;
-       if (!err) {
-               pos += nres;
-               fuse_write_update_size(inode, pos);
-               if (count == PAGE_CACHE_SIZE)
-                       SetPageUptodate(page);
-       }
-       fuse_invalidate_attr(inode);
-       return err ? err : nres;
-}
-
-static int fuse_write_end(struct file *file, struct address_space *mapping,
-                       loff_t pos, unsigned len, unsigned copied,
-                       struct page *page, void *fsdata)
-{
-       struct inode *inode = mapping->host;
-       int res = 0;
-
-       if (copied)
-               res = fuse_buffered_write(file, inode, pos, copied, page);
-
-       unlock_page(page);
-       page_cache_release(page);
-       return res;
-}
-
 static size_t fuse_send_write_pages(struct fuse_req *req, struct file *file,
                                    struct inode *inode, loff_t pos,
                                    size_t count)
@@ -908,6 +847,8 @@ static ssize_t fuse_fill_write_pages(struct fuse_req *req,
                pagefault_enable();
                flush_dcache_page(page);
 
+               mark_page_accessed(page);
+
                if (!tmp) {
                        unlock_page(page);
                        page_cache_release(page);
@@ -1559,11 +1500,14 @@ static int fuse_file_flock(struct file *file, int cmd, struct file_lock *fl)
        struct fuse_conn *fc = get_fuse_conn(inode);
        int err;
 
-       if (fc->no_lock) {
+       if (fc->no_flock) {
                err = flock_lock_file_wait(file, fl);
        } else {
+               struct fuse_file *ff = file->private_data;
+
                /* emulate flock with POSIX locks */
                fl->fl_owner = (fl_owner_t) file;
+               ff->flock = true;
                err = fuse_setlk(file, fl, 1);
        }
 
@@ -2201,8 +2145,6 @@ static const struct address_space_operations fuse_file_aops  = {
        .readpage       = fuse_readpage,
        .writepage      = fuse_writepage,
        .launder_page   = fuse_launder_page,
-       .write_begin    = fuse_write_begin,
-       .write_end      = fuse_write_end,
        .readpages      = fuse_readpages,
        .set_page_dirty = __set_page_dirty_nobuffers,
        .bmap           = fuse_bmap,
index c6aa2d4..cf6db0a 100644 (file)
@@ -135,6 +135,9 @@ struct fuse_file {
 
        /** Wait queue head for poll */
        wait_queue_head_t poll_wait;
+
+       /** Has flock been performed on this file? */
+       bool flock:1;
 };
 
 /** One input argument of a request */
@@ -448,7 +451,7 @@ struct fuse_conn {
        /** Is removexattr not implemented by fs? */
        unsigned no_removexattr:1;
 
-       /** Are file locking primitives not implemented by fs? */
+       /** Are posix file locking primitives not implemented by fs? */
        unsigned no_lock:1;
 
        /** Is access not implemented by fs? */
@@ -472,6 +475,9 @@ struct fuse_conn {
        /** Don't apply umask to creation modes */
        unsigned dont_mask:1;
 
+       /** Are BSD file locking primitives not implemented by fs? */
+       unsigned no_flock:1;
+
        /** The number of requests waiting for completion */
        atomic_t num_waiting;
 
index 38f84cd..12b5029 100644 (file)
@@ -71,7 +71,7 @@ struct fuse_mount_data {
        unsigned blksize;
 };
 
-struct fuse_forget_link *fuse_alloc_forget()
+struct fuse_forget_link *fuse_alloc_forget(void)
 {
        return kzalloc(sizeof(struct fuse_forget_link), GFP_KERNEL);
 }
@@ -809,6 +809,10 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
                                fc->async_read = 1;
                        if (!(arg->flags & FUSE_POSIX_LOCKS))
                                fc->no_lock = 1;
+                       if (arg->minor >= 17) {
+                               if (!(arg->flags & FUSE_FLOCK_LOCKS))
+                                       fc->no_flock = 1;
+                       }
                        if (arg->flags & FUSE_ATOMIC_O_TRUNC)
                                fc->atomic_o_trunc = 1;
                        if (arg->minor >= 9) {
@@ -823,6 +827,7 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
                } else {
                        ra_pages = fc->max_read / PAGE_CACHE_SIZE;
                        fc->no_lock = 1;
+                       fc->no_flock = 1;
                }
 
                fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages);
@@ -843,7 +848,8 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
        arg->minor = FUSE_KERNEL_MINOR_VERSION;
        arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE;
        arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC |
-               FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK;
+               FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK |
+               FUSE_FLOCK_LOCKS;
        req->in.h.opcode = FUSE_INIT;
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(*arg);
index d5e33a0..d0dddac 100644 (file)
@@ -82,18 +82,14 @@ generic_acl_set(struct dentry *dentry, const char *name, const void *value,
                        return PTR_ERR(acl);
        }
        if (acl) {
-               mode_t mode;
-
                error = posix_acl_valid(acl);
                if (error)
                        goto failed;
                switch (type) {
                case ACL_TYPE_ACCESS:
-                       mode = inode->i_mode;
-                       error = posix_acl_equiv_mode(acl, &mode);
+                       error = posix_acl_equiv_mode(acl, &inode->i_mode);
                        if (error < 0)
                                goto failed;
-                       inode->i_mode = mode;
                        inode->i_ctime = CURRENT_TIME;
                        if (error == 0) {
                                posix_acl_release(acl);
@@ -125,21 +121,20 @@ int
 generic_acl_init(struct inode *inode, struct inode *dir)
 {
        struct posix_acl *acl = NULL;
-       mode_t mode = inode->i_mode;
        int error;
 
-       inode->i_mode = mode & ~current_umask();
        if (!S_ISLNK(inode->i_mode))
                acl = get_cached_acl(dir, ACL_TYPE_DEFAULT);
        if (acl) {
                if (S_ISDIR(inode->i_mode))
                        set_cached_acl(inode, ACL_TYPE_DEFAULT, acl);
-               error = posix_acl_create(&acl, GFP_KERNEL, &mode);
+               error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode);
                if (error < 0)
                        return error;
-               inode->i_mode = mode;
                if (error > 0)
                        set_cached_acl(inode, ACL_TYPE_ACCESS, acl);
+       } else {
+               inode->i_mode &= ~current_umask();
        }
        error = 0;
 
index 884c9af..34501b6 100644 (file)
@@ -72,7 +72,7 @@ struct posix_acl *gfs2_get_acl(struct inode *inode, int type)
        return gfs2_acl_get(GFS2_I(inode), type);
 }
 
-static int gfs2_set_mode(struct inode *inode, mode_t mode)
+static int gfs2_set_mode(struct inode *inode, umode_t mode)
 {
        int error = 0;
 
@@ -117,7 +117,7 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
        struct posix_acl *acl;
-       mode_t mode = inode->i_mode;
+       umode_t mode = inode->i_mode;
        int error = 0;
 
        if (!sdp->sd_args.ar_posix_acl)
@@ -276,7 +276,7 @@ static int gfs2_xattr_system_set(struct dentry *dentry, const char *name,
                goto out_release;
 
        if (type == ACL_TYPE_ACCESS) {
-               mode_t mode = inode->i_mode;
+               umode_t mode = inode->i_mode;
                error = posix_acl_equiv_mode(acl, &mode);
 
                if (error <= 0) {
index 8635be5..970ea98 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/statfs.h>
 #include <linux/types.h>
 #include <linux/pid_namespace.h>
+#include <linux/namei.h>
 #include <asm/uaccess.h>
 #include "os.h"
 
index d0c72ff..73920d5 100644 (file)
@@ -143,6 +143,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
        inode->i_op = &empty_iops;
        inode->i_fop = &empty_fops;
        inode->i_nlink = 1;
+       inode->i_opflags = 0;
        inode->i_uid = 0;
        inode->i_gid = 0;
        atomic_set(&inode->i_writecount, 0);
@@ -399,12 +400,12 @@ void __insert_inode_hash(struct inode *inode, unsigned long hashval)
 EXPORT_SYMBOL(__insert_inode_hash);
 
 /**
- *     remove_inode_hash - remove an inode from the hash
+ *     __remove_inode_hash - remove an inode from the hash
  *     @inode: inode to unhash
  *
  *     Remove an inode from the superblock.
  */
-void remove_inode_hash(struct inode *inode)
+void __remove_inode_hash(struct inode *inode)
 {
        spin_lock(&inode_hash_lock);
        spin_lock(&inode->i_lock);
@@ -412,7 +413,7 @@ void remove_inode_hash(struct inode *inode)
        spin_unlock(&inode->i_lock);
        spin_unlock(&inode_hash_lock);
 }
-EXPORT_SYMBOL(remove_inode_hash);
+EXPORT_SYMBOL(__remove_inode_hash);
 
 void end_writeback(struct inode *inode)
 {
@@ -454,7 +455,9 @@ static void evict(struct inode *inode)
        BUG_ON(!(inode->i_state & I_FREEING));
        BUG_ON(!list_empty(&inode->i_lru));
 
-       inode_wb_list_del(inode);
+       if (!list_empty(&inode->i_wb_list))
+               inode_wb_list_del(inode);
+
        inode_sb_list_del(inode);
 
        if (op->evict_inode) {
@@ -1328,7 +1331,8 @@ static void iput_final(struct inode *inode)
        }
 
        inode->i_state |= I_FREEING;
-       inode_lru_list_del(inode);
+       if (!list_empty(&inode->i_lru))
+               inode_lru_list_del(inode);
        spin_unlock(&inode->i_lock);
 
        evict(inode);
index 2c62c5a..16a698b 100644 (file)
@@ -257,9 +257,12 @@ static void
 __flush_batch(journal_t *journal, int *batch_count)
 {
        int i;
+       struct blk_plug plug;
 
+       blk_start_plug(&plug);
        for (i = 0; i < *batch_count; i++)
-               write_dirty_buffer(journal->j_chkpt_bhs[i], WRITE);
+               write_dirty_buffer(journal->j_chkpt_bhs[i], WRITE_SYNC);
+       blk_finish_plug(&plug);
 
        for (i = 0; i < *batch_count; i++) {
                struct buffer_head *bh = journal->j_chkpt_bhs[i];
index 0dfa5b5..f24df13 100644 (file)
@@ -2390,73 +2390,6 @@ static void __exit journal_exit(void)
        jbd2_journal_destroy_caches();
 }
 
-/* 
- * jbd2_dev_to_name is a utility function used by the jbd2 and ext4 
- * tracing infrastructure to map a dev_t to a device name.
- *
- * The caller should use rcu_read_lock() in order to make sure the
- * device name stays valid until its done with it.  We use
- * rcu_read_lock() as well to make sure we're safe in case the caller
- * gets sloppy, and because rcu_read_lock() is cheap and can be safely
- * nested.
- */
-struct devname_cache {
-       struct rcu_head rcu;
-       dev_t           device;
-       char            devname[BDEVNAME_SIZE];
-};
-#define CACHE_SIZE_BITS 6
-static struct devname_cache *devcache[1 << CACHE_SIZE_BITS];
-static DEFINE_SPINLOCK(devname_cache_lock);
-
-static void free_devcache(struct rcu_head *rcu)
-{
-       kfree(rcu);
-}
-
-const char *jbd2_dev_to_name(dev_t device)
-{
-       int     i = hash_32(device, CACHE_SIZE_BITS);
-       char    *ret;
-       struct block_device *bd;
-       static struct devname_cache *new_dev;
-
-       rcu_read_lock();
-       if (devcache[i] && devcache[i]->device == device) {
-               ret = devcache[i]->devname;
-               rcu_read_unlock();
-               return ret;
-       }
-       rcu_read_unlock();
-
-       new_dev = kmalloc(sizeof(struct devname_cache), GFP_KERNEL);
-       if (!new_dev)
-               return "NODEV-ALLOCFAILURE"; /* Something non-NULL */
-       bd = bdget(device);
-       spin_lock(&devname_cache_lock);
-       if (devcache[i]) {
-               if (devcache[i]->device == device) {
-                       kfree(new_dev);
-                       bdput(bd);
-                       ret = devcache[i]->devname;
-                       spin_unlock(&devname_cache_lock);
-                       return ret;
-               }
-               call_rcu(&devcache[i]->rcu, free_devcache);
-       }
-       devcache[i] = new_dev;
-       devcache[i]->device = device;
-       if (bd) {
-               bdevname(bd, devcache[i]->devname);
-               bdput(bd);
-       } else
-               __bdevname(device, devcache[i]->devname);
-       ret = devcache[i]->devname;
-       spin_unlock(&devname_cache_lock);
-       return ret;
-}
-EXPORT_SYMBOL(jbd2_dev_to_name);
-
 MODULE_LICENSE("GPL");
 module_init(journal_init);
 module_exit(journal_exit);
index 27c511a..926d020 100644 (file)
@@ -227,7 +227,7 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
        case ACL_TYPE_ACCESS:
                xprefix = JFFS2_XPREFIX_ACL_ACCESS;
                if (acl) {
-                       mode_t mode = inode->i_mode;
+                       umode_t mode = inode->i_mode;
                        rc = posix_acl_equiv_mode(acl, &mode);
                        if (rc < 0)
                                return rc;
@@ -259,7 +259,7 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
        return rc;
 }
 
-int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, mode_t *i_mode)
+int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, umode_t *i_mode)
 {
        struct posix_acl *acl;
        int rc;
index b3421c7..9b47724 100644 (file)
@@ -28,7 +28,7 @@ struct jffs2_acl_header {
 
 struct posix_acl *jffs2_get_acl(struct inode *inode, int type);
 extern int jffs2_acl_chmod(struct inode *);
-extern int jffs2_init_acl_pre(struct inode *, struct inode *, mode_t *);
+extern int jffs2_init_acl_pre(struct inode *, struct inode *, umode_t *);
 extern int jffs2_init_acl_post(struct inode *);
 
 extern const struct xattr_handler jffs2_acl_access_xattr_handler;
index b81b35d..bbcb975 100644 (file)
@@ -406,7 +406,7 @@ int jffs2_remount_fs (struct super_block *sb, int *flags, char *data)
 
 /* jffs2_new_inode: allocate a new inode and inocache, add it to the hash,
    fill in the raw_inode while you're at it. */
-struct inode *jffs2_new_inode (struct inode *dir_i, mode_t mode, struct jffs2_raw_inode *ri)
+struct inode *jffs2_new_inode (struct inode *dir_i, umode_t mode, struct jffs2_raw_inode *ri)
 {
        struct inode *inode;
        struct super_block *sb = dir_i->i_sb;
index 526979c..6c1755c 100644 (file)
@@ -173,7 +173,7 @@ int jffs2_do_setattr (struct inode *, struct iattr *);
 struct inode *jffs2_iget(struct super_block *, unsigned long);
 void jffs2_evict_inode (struct inode *);
 void jffs2_dirty_inode(struct inode *inode, int flags);
-struct inode *jffs2_new_inode (struct inode *dir_i, mode_t mode,
+struct inode *jffs2_new_inode (struct inode *dir_i, umode_t mode,
                               struct jffs2_raw_inode *ri);
 int jffs2_statfs (struct dentry *, struct kstatfs *);
 int jffs2_remount_fs (struct super_block *, int *, char *);
index b3a32ca..45559dc 100644 (file)
@@ -127,16 +127,14 @@ int jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir)
                return PTR_ERR(acl);
 
        if (acl) {
-               mode_t mode = inode->i_mode;
                if (S_ISDIR(inode->i_mode)) {
                        rc = jfs_set_acl(tid, inode, ACL_TYPE_DEFAULT, acl);
                        if (rc)
                                goto cleanup;
                }
-               rc = posix_acl_create(&acl, GFP_KERNEL, &mode);
+               rc = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode);
                if (rc < 0)
                        goto cleanup; /* posix_acl_release(NULL) is no-op */
-               inode->i_mode = mode;
                if (rc > 0)
                        rc = jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, acl);
 cleanup:
index adcf92d..7971f37 100644 (file)
@@ -68,7 +68,7 @@ int jfs_umount(struct super_block *sb)
                /*
                 * Wait for outstanding transactions to be written to log:
                 */
-               jfs_flush_journal(log, 1);
+               jfs_flush_journal(log, 2);
 
        /*
         * close fileset inode allocation map (aka fileset inode)
@@ -146,7 +146,7 @@ int jfs_umount_rw(struct super_block *sb)
         *
         * remove file system from log active file system list.
         */
-       jfs_flush_journal(log, 1);
+       jfs_flush_journal(log, 2);
 
        /*
         * Make sure all metadata makes it to disk
index 24838f1..e87fede 100644 (file)
@@ -693,8 +693,7 @@ static int can_set_system_xattr(struct inode *inode, const char *name,
                        return rc;
                }
                if (acl) {
-                       mode_t mode = inode->i_mode;
-                       rc = posix_acl_equiv_mode(acl, &mode);
+                       rc = posix_acl_equiv_mode(acl, &inode->i_mode);
                        posix_acl_release(acl);
                        if (rc < 0) {
                                printk(KERN_ERR
@@ -702,7 +701,6 @@ static int can_set_system_xattr(struct inode *inode, const char *name,
                                       rc);
                                return rc;
                        }
-                       inode->i_mode = mode;
                        mark_inode_dirty(inode);
                }
                /*
index f8c69d3..2826db3 100644 (file)
@@ -179,19 +179,14 @@ static int check_acl(struct inode *inode, int mask)
 #ifdef CONFIG_FS_POSIX_ACL
        struct posix_acl *acl;
 
-       /*
-        * Under RCU walk, we cannot even do a "get_cached_acl()",
-        * because that involves locking and getting a refcount on
-        * a cached ACL.
-        *
-        * So the only case we handle during RCU walking is the
-        * case of a cached "no ACL at all", which needs no locks
-        * or refcounts.
-        */
        if (mask & MAY_NOT_BLOCK) {
-               if (negative_cached_acl(inode, ACL_TYPE_ACCESS))
+               acl = get_cached_acl_rcu(inode, ACL_TYPE_ACCESS);
+               if (!acl)
                        return -EAGAIN;
-               return -ECHILD;
+               /* no ->get_acl() calls in RCU mode... */
+               if (acl == ACL_NOT_CACHED)
+                       return -ECHILD;
+               return posix_acl_permission(inode, acl, mask & ~MAY_NOT_BLOCK);
        }
 
        acl = get_cached_acl(inode, ACL_TYPE_ACCESS);
@@ -313,6 +308,26 @@ int generic_permission(struct inode *inode, int mask)
        return -EACCES;
 }
 
+/*
+ * We _really_ want to just do "generic_permission()" without
+ * even looking at the inode->i_op values. So we keep a cache
+ * flag in inode->i_opflags, that says "this has not special
+ * permission function, use the fast case".
+ */
+static inline int do_inode_permission(struct inode *inode, int mask)
+{
+       if (unlikely(!(inode->i_opflags & IOP_FASTPERM))) {
+               if (likely(inode->i_op->permission))
+                       return inode->i_op->permission(inode, mask);
+
+               /* This gets set once for the inode lifetime */
+               spin_lock(&inode->i_lock);
+               inode->i_opflags |= IOP_FASTPERM;
+               spin_unlock(&inode->i_lock);
+       }
+       return generic_permission(inode, mask);
+}
+
 /**
  * inode_permission  -  check for access rights to a given inode
  * @inode:     inode to check permission on
@@ -327,7 +342,7 @@ int inode_permission(struct inode *inode, int mask)
 {
        int retval;
 
-       if (mask & MAY_WRITE) {
+       if (unlikely(mask & MAY_WRITE)) {
                umode_t mode = inode->i_mode;
 
                /*
@@ -344,11 +359,7 @@ int inode_permission(struct inode *inode, int mask)
                        return -EACCES;
        }
 
-       if (inode->i_op->permission)
-               retval = inode->i_op->permission(inode, mask);
-       else
-               retval = generic_permission(inode, mask);
-
+       retval = do_inode_permission(inode, mask);
        if (retval)
                return retval;
 
@@ -716,19 +727,25 @@ static int follow_automount(struct path *path, unsigned flags,
        if ((flags & LOOKUP_NO_AUTOMOUNT) && !(flags & LOOKUP_PARENT))
                return -EISDIR; /* we actually want to stop here */
 
-       /* We want to mount if someone is trying to open/create a file of any
-        * type under the mountpoint, wants to traverse through the mountpoint
-        * or wants to open the mounted directory.
-        *
+       /*
         * We don't want to mount if someone's just doing a stat and they've
         * set AT_SYMLINK_NOFOLLOW - unless they're stat'ing a directory and
         * appended a '/' to the name.
         */
-       if (!(flags & LOOKUP_FOLLOW) &&
-           !(flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY |
-                      LOOKUP_OPEN | LOOKUP_CREATE)))
-               return -EISDIR;
-
+       if (!(flags & LOOKUP_FOLLOW)) {
+               /* We do, however, want to mount if someone wants to open or
+                * create a file of any type under the mountpoint, wants to
+                * traverse through the mountpoint or wants to open the mounted
+                * directory.
+                * Also, autofs may mark negative dentries as being automount
+                * points.  These will need the attentions of the daemon to
+                * instantiate them before they can be used.
+                */
+               if (!(flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY |
+                            LOOKUP_OPEN | LOOKUP_CREATE)) &&
+                   path->dentry->d_inode)
+                       return -EISDIR;
+       }
        current->total_link_count++;
        if (current->total_link_count >= 40)
                return -ELOOP;
@@ -1244,6 +1261,26 @@ static void terminate_walk(struct nameidata *nd)
        }
 }
 
+/*
+ * Do we need to follow links? We _really_ want to be able
+ * to do this check without having to look at inode->i_op,
+ * so we keep a cache of "no, this doesn't need follow_link"
+ * for the common case.
+ */
+static inline int should_follow_link(struct inode *inode, int follow)
+{
+       if (unlikely(!(inode->i_opflags & IOP_NOFOLLOW))) {
+               if (likely(inode->i_op->follow_link))
+                       return follow;
+
+               /* This gets set once for the inode lifetime */
+               spin_lock(&inode->i_lock);
+               inode->i_opflags |= IOP_NOFOLLOW;
+               spin_unlock(&inode->i_lock);
+       }
+       return 0;
+}
+
 static inline int walk_component(struct nameidata *nd, struct path *path,
                struct qstr *name, int type, int follow)
 {
@@ -1266,7 +1303,7 @@ static inline int walk_component(struct nameidata *nd, struct path *path,
                terminate_walk(nd);
                return -ENOENT;
        }
-       if (unlikely(inode->i_op->follow_link) && follow) {
+       if (should_follow_link(inode, follow)) {
                if (nd->flags & LOOKUP_RCU) {
                        if (unlikely(unlazy_walk(nd, path->dentry))) {
                                terminate_walk(nd);
@@ -1318,6 +1355,26 @@ static inline int nested_symlink(struct path *path, struct nameidata *nd)
        return res;
 }
 
+/*
+ * We really don't want to look at inode->i_op->lookup
+ * when we don't have to. So we keep a cache bit in
+ * the inode ->i_opflags field that says "yes, we can
+ * do lookup on this inode".
+ */
+static inline int can_lookup(struct inode *inode)
+{
+       if (likely(inode->i_opflags & IOP_LOOKUP))
+               return 1;
+       if (likely(!inode->i_op->lookup))
+               return 0;
+
+       /* We do this once for the lifetime of the inode */
+       spin_lock(&inode->i_lock);
+       inode->i_opflags |= IOP_LOOKUP;
+       spin_unlock(&inode->i_lock);
+       return 1;
+}
+
 /*
  * Name resolution.
  * This is the basic name resolution function, turning a pathname into
@@ -1397,10 +1454,10 @@ static int link_path_walk(const char *name, struct nameidata *nd)
                        if (err)
                                return err;
                }
+               if (can_lookup(nd->inode))
+                       continue;
                err = -ENOTDIR; 
-               if (!nd->inode->i_op->lookup)
-                       break;
-               continue;
+               break;
                /* here ends the main loop */
 
 last_component:
index 2cde5d9..dbcd821 100644 (file)
@@ -88,15 +88,15 @@ config NFS_V4_1
 config PNFS_FILE_LAYOUT
        tristate
 
+config PNFS_BLOCK
+       tristate
+       depends on NFS_FS && NFS_V4_1 && BLK_DEV_DM
+       default m
+
 config PNFS_OBJLAYOUT
-       tristate "Provide support for the pNFS Objects Layout Driver for NFSv4.1 pNFS (EXPERIMENTAL)"
+       tristate
        depends on NFS_FS && NFS_V4_1 && SCSI_OSD_ULD
-       help
-         Say M here if you want your pNFS client to support the Objects Layout Driver.
-         Requires the SCSI osd initiator library (SCSI_OSD_INITIATOR) and
-         upper level driver (SCSI_OSD_ULD).
-
-         If unsure, say N.
+       default m
 
 config ROOT_NFS
        bool "Root file system on NFS"
index 6a34f7d..b58613d 100644 (file)
@@ -23,3 +23,4 @@ obj-$(CONFIG_PNFS_FILE_LAYOUT) += nfs_layout_nfsv41_files.o
 nfs_layout_nfsv41_files-y := nfs4filelayout.o nfs4filelayoutdev.o
 
 obj-$(CONFIG_PNFS_OBJLAYOUT) += objlayout/
+obj-$(CONFIG_PNFS_BLOCK) += blocklayout/
diff --git a/fs/nfs/blocklayout/Makefile b/fs/nfs/blocklayout/Makefile
new file mode 100644 (file)
index 0000000..d581550
--- /dev/null
@@ -0,0 +1,5 @@
+#
+# Makefile for the pNFS block layout driver kernel module
+#
+obj-$(CONFIG_PNFS_BLOCK) += blocklayoutdriver.o
+blocklayoutdriver-objs := blocklayout.o extents.o blocklayoutdev.o blocklayoutdm.o
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c
new file mode 100644 (file)
index 0000000..9561c8f
--- /dev/null
@@ -0,0 +1,1020 @@
+/*
+ *  linux/fs/nfs/blocklayout/blocklayout.c
+ *
+ *  Module for the NFSv4.1 pNFS block layout driver.
+ *
+ *  Copyright (c) 2006 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson <andros@citi.umich.edu>
+ *  Fred Isaman <iisaman@umich.edu>
+ *
+ * permission is granted to use, copy, create derivative works and
+ * redistribute this software and such derivative works for any purpose,
+ * so long as the name of the university of michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization.  if
+ * the above copyright notice or any other identification of the
+ * university of michigan is included in any copy of any portion of
+ * this software, then the disclaimer below must also be included.
+ *
+ * this software is provided as is, without representation from the
+ * university of michigan as to its fitness for any purpose, and without
+ * warranty by the university of michigan of any kind, either express
+ * or implied, including without limitation the implied warranties of
+ * merchantability and fitness for a particular purpose.  the regents
+ * of the university of michigan shall not be liable for any damages,
+ * including special, indirect, incidental, or consequential damages,
+ * with respect to any claim arising out or in connection with the use
+ * of the software, even if it has been or is hereafter advised of the
+ * possibility of such damages.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/bio.h>         /* struct bio */
+#include <linux/buffer_head.h> /* various write calls */
+#include <linux/prefetch.h>
+
+#include "blocklayout.h"
+
+#define NFSDBG_FACILITY        NFSDBG_PNFS_LD
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Andy Adamson <andros@citi.umich.edu>");
+MODULE_DESCRIPTION("The NFSv4.1 pNFS Block layout driver");
+
+struct dentry *bl_device_pipe;
+wait_queue_head_t bl_wq;
+
+static void print_page(struct page *page)
+{
+       dprintk("PRINTPAGE page %p\n", page);
+       dprintk("       PagePrivate %d\n", PagePrivate(page));
+       dprintk("       PageUptodate %d\n", PageUptodate(page));
+       dprintk("       PageError %d\n", PageError(page));
+       dprintk("       PageDirty %d\n", PageDirty(page));
+       dprintk("       PageReferenced %d\n", PageReferenced(page));
+       dprintk("       PageLocked %d\n", PageLocked(page));
+       dprintk("       PageWriteback %d\n", PageWriteback(page));
+       dprintk("       PageMappedToDisk %d\n", PageMappedToDisk(page));
+       dprintk("\n");
+}
+
+/* Given the be associated with isect, determine if page data needs to be
+ * initialized.
+ */
+static int is_hole(struct pnfs_block_extent *be, sector_t isect)
+{
+       if (be->be_state == PNFS_BLOCK_NONE_DATA)
+               return 1;
+       else if (be->be_state != PNFS_BLOCK_INVALID_DATA)
+               return 0;
+       else
+               return !bl_is_sector_init(be->be_inval, isect);
+}
+
+/* Given the be associated with isect, determine if page data can be
+ * written to disk.
+ */
+static int is_writable(struct pnfs_block_extent *be, sector_t isect)
+{
+       return (be->be_state == PNFS_BLOCK_READWRITE_DATA ||
+               be->be_state == PNFS_BLOCK_INVALID_DATA);
+}
+
+/* The data we are handed might be spread across several bios.  We need
+ * to track when the last one is finished.
+ */
+struct parallel_io {
+       struct kref refcnt;
+       struct rpc_call_ops call_ops;
+       void (*pnfs_callback) (void *data);
+       void *data;
+};
+
+static inline struct parallel_io *alloc_parallel(void *data)
+{
+       struct parallel_io *rv;
+
+       rv  = kmalloc(sizeof(*rv), GFP_NOFS);
+       if (rv) {
+               rv->data = data;
+               kref_init(&rv->refcnt);
+       }
+       return rv;
+}
+
+static inline void get_parallel(struct parallel_io *p)
+{
+       kref_get(&p->refcnt);
+}
+
+static void destroy_parallel(struct kref *kref)
+{
+       struct parallel_io *p = container_of(kref, struct parallel_io, refcnt);
+
+       dprintk("%s enter\n", __func__);
+       p->pnfs_callback(p->data);
+       kfree(p);
+}
+
+static inline void put_parallel(struct parallel_io *p)
+{
+       kref_put(&p->refcnt, destroy_parallel);
+}
+
+static struct bio *
+bl_submit_bio(int rw, struct bio *bio)
+{
+       if (bio) {
+               get_parallel(bio->bi_private);
+               dprintk("%s submitting %s bio %u@%llu\n", __func__,
+                       rw == READ ? "read" : "write",
+                       bio->bi_size, (unsigned long long)bio->bi_sector);
+               submit_bio(rw, bio);
+       }
+       return NULL;
+}
+
+static struct bio *bl_alloc_init_bio(int npg, sector_t isect,
+                                    struct pnfs_block_extent *be,
+                                    void (*end_io)(struct bio *, int err),
+                                    struct parallel_io *par)
+{
+       struct bio *bio;
+
+       bio = bio_alloc(GFP_NOIO, npg);
+       if (!bio)
+               return NULL;
+
+       bio->bi_sector = isect - be->be_f_offset + be->be_v_offset;
+       bio->bi_bdev = be->be_mdev;
+       bio->bi_end_io = end_io;
+       bio->bi_private = par;
+       return bio;
+}
+
+static struct bio *bl_add_page_to_bio(struct bio *bio, int npg, int rw,
+                                     sector_t isect, struct page *page,
+                                     struct pnfs_block_extent *be,
+                                     void (*end_io)(struct bio *, int err),
+                                     struct parallel_io *par)
+{
+retry:
+       if (!bio) {
+               bio = bl_alloc_init_bio(npg, isect, be, end_io, par);
+               if (!bio)
+                       return ERR_PTR(-ENOMEM);
+       }
+       if (bio_add_page(bio, page, PAGE_CACHE_SIZE, 0) < PAGE_CACHE_SIZE) {
+               bio = bl_submit_bio(rw, bio);
+               goto retry;
+       }
+       return bio;
+}
+
+static void bl_set_lo_fail(struct pnfs_layout_segment *lseg)
+{
+       if (lseg->pls_range.iomode == IOMODE_RW) {
+               dprintk("%s Setting layout IOMODE_RW fail bit\n", __func__);
+               set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags);
+       } else {
+               dprintk("%s Setting layout IOMODE_READ fail bit\n", __func__);
+               set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
+       }
+}
+
+/* This is basically copied from mpage_end_io_read */
+static void bl_end_io_read(struct bio *bio, int err)
+{
+       struct parallel_io *par = bio->bi_private;
+       const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+       struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
+       struct nfs_read_data *rdata = (struct nfs_read_data *)par->data;
+
+       do {
+               struct page *page = bvec->bv_page;
+
+               if (--bvec >= bio->bi_io_vec)
+                       prefetchw(&bvec->bv_page->flags);
+               if (uptodate)
+                       SetPageUptodate(page);
+       } while (bvec >= bio->bi_io_vec);
+       if (!uptodate) {
+               if (!rdata->pnfs_error)
+                       rdata->pnfs_error = -EIO;
+               bl_set_lo_fail(rdata->lseg);
+       }
+       bio_put(bio);
+       put_parallel(par);
+}
+
+static void bl_read_cleanup(struct work_struct *work)
+{
+       struct rpc_task *task;
+       struct nfs_read_data *rdata;
+       dprintk("%s enter\n", __func__);
+       task = container_of(work, struct rpc_task, u.tk_work);
+       rdata = container_of(task, struct nfs_read_data, task);
+       pnfs_ld_read_done(rdata);
+}
+
+static void
+bl_end_par_io_read(void *data)
+{
+       struct nfs_read_data *rdata = data;
+
+       INIT_WORK(&rdata->task.u.tk_work, bl_read_cleanup);
+       schedule_work(&rdata->task.u.tk_work);
+}
+
+/* We don't want normal .rpc_call_done callback used, so we replace it
+ * with this stub.
+ */
+static void bl_rpc_do_nothing(struct rpc_task *task, void *calldata)
+{
+       return;
+}
+
+static enum pnfs_try_status
+bl_read_pagelist(struct nfs_read_data *rdata)
+{
+       int i, hole;
+       struct bio *bio = NULL;
+       struct pnfs_block_extent *be = NULL, *cow_read = NULL;
+       sector_t isect, extent_length = 0;
+       struct parallel_io *par;
+       loff_t f_offset = rdata->args.offset;
+       size_t count = rdata->args.count;
+       struct page **pages = rdata->args.pages;
+       int pg_index = rdata->args.pgbase >> PAGE_CACHE_SHIFT;
+
+       dprintk("%s enter nr_pages %u offset %lld count %Zd\n", __func__,
+              rdata->npages, f_offset, count);
+
+       par = alloc_parallel(rdata);
+       if (!par)
+               goto use_mds;
+       par->call_ops = *rdata->mds_ops;
+       par->call_ops.rpc_call_done = bl_rpc_do_nothing;
+       par->pnfs_callback = bl_end_par_io_read;
+       /* At this point, we can no longer jump to use_mds */
+
+       isect = (sector_t) (f_offset >> SECTOR_SHIFT);
+       /* Code assumes extents are page-aligned */
+       for (i = pg_index; i < rdata->npages; i++) {
+               if (!extent_length) {
+                       /* We've used up the previous extent */
+                       bl_put_extent(be);
+                       bl_put_extent(cow_read);
+                       bio = bl_submit_bio(READ, bio);
+                       /* Get the next one */
+                       be = bl_find_get_extent(BLK_LSEG2EXT(rdata->lseg),
+                                            isect, &cow_read);
+                       if (!be) {
+                               rdata->pnfs_error = -EIO;
+                               goto out;
+                       }
+                       extent_length = be->be_length -
+                               (isect - be->be_f_offset);
+                       if (cow_read) {
+                               sector_t cow_length = cow_read->be_length -
+                                       (isect - cow_read->be_f_offset);
+                               extent_length = min(extent_length, cow_length);
+                       }
+               }
+               hole = is_hole(be, isect);
+               if (hole && !cow_read) {
+                       bio = bl_submit_bio(READ, bio);
+                       /* Fill hole w/ zeroes w/o accessing device */
+                       dprintk("%s Zeroing page for hole\n", __func__);
+                       zero_user_segment(pages[i], 0, PAGE_CACHE_SIZE);
+                       print_page(pages[i]);
+                       SetPageUptodate(pages[i]);
+               } else {
+                       struct pnfs_block_extent *be_read;
+
+                       be_read = (hole && cow_read) ? cow_read : be;
+                       bio = bl_add_page_to_bio(bio, rdata->npages - i, READ,
+                                                isect, pages[i], be_read,
+                                                bl_end_io_read, par);
+                       if (IS_ERR(bio)) {
+                               rdata->pnfs_error = PTR_ERR(bio);
+                               goto out;
+                       }
+               }
+               isect += PAGE_CACHE_SECTORS;
+               extent_length -= PAGE_CACHE_SECTORS;
+       }
+       if ((isect << SECTOR_SHIFT) >= rdata->inode->i_size) {
+               rdata->res.eof = 1;
+               rdata->res.count = rdata->inode->i_size - f_offset;
+       } else {
+               rdata->res.count = (isect << SECTOR_SHIFT) - f_offset;
+       }
+out:
+       bl_put_extent(be);
+       bl_put_extent(cow_read);
+       bl_submit_bio(READ, bio);
+       put_parallel(par);
+       return PNFS_ATTEMPTED;
+
+ use_mds:
+       dprintk("Giving up and using normal NFS\n");
+       return PNFS_NOT_ATTEMPTED;
+}
+
+static void mark_extents_written(struct pnfs_block_layout *bl,
+                                __u64 offset, __u32 count)
+{
+       sector_t isect, end;
+       struct pnfs_block_extent *be;
+
+       dprintk("%s(%llu, %u)\n", __func__, offset, count);
+       if (count == 0)
+               return;
+       isect = (offset & (long)(PAGE_CACHE_MASK)) >> SECTOR_SHIFT;
+       end = (offset + count + PAGE_CACHE_SIZE - 1) & (long)(PAGE_CACHE_MASK);
+       end >>= SECTOR_SHIFT;
+       while (isect < end) {
+               sector_t len;
+               be = bl_find_get_extent(bl, isect, NULL);
+               BUG_ON(!be); /* FIXME */
+               len = min(end, be->be_f_offset + be->be_length) - isect;
+               if (be->be_state == PNFS_BLOCK_INVALID_DATA)
+                       bl_mark_for_commit(be, isect, len); /* What if fails? */
+               isect += len;
+               bl_put_extent(be);
+       }
+}
+
+static void bl_end_io_write_zero(struct bio *bio, int err)
+{
+       struct parallel_io *par = bio->bi_private;
+       const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+       struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
+       struct nfs_write_data *wdata = (struct nfs_write_data *)par->data;
+
+       do {
+               struct page *page = bvec->bv_page;
+
+               if (--bvec >= bio->bi_io_vec)
+                       prefetchw(&bvec->bv_page->flags);
+               /* This is the zeroing page we added */
+               end_page_writeback(page);
+               page_cache_release(page);
+       } while (bvec >= bio->bi_io_vec);
+       if (!uptodate) {
+               if (!wdata->pnfs_error)
+                       wdata->pnfs_error = -EIO;
+               bl_set_lo_fail(wdata->lseg);
+       }
+       bio_put(bio);
+       put_parallel(par);
+}
+
+/* This is basically copied from mpage_end_io_read */
+static void bl_end_io_write(struct bio *bio, int err)
+{
+       struct parallel_io *par = bio->bi_private;
+       const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+       struct nfs_write_data *wdata = (struct nfs_write_data *)par->data;
+
+       if (!uptodate) {
+               if (!wdata->pnfs_error)
+                       wdata->pnfs_error = -EIO;
+               bl_set_lo_fail(wdata->lseg);
+       }
+       bio_put(bio);
+       put_parallel(par);
+}
+
+/* Function scheduled for call during bl_end_par_io_write,
+ * it marks sectors as written and extends the commitlist.
+ */
+static void bl_write_cleanup(struct work_struct *work)
+{
+       struct rpc_task *task;
+       struct nfs_write_data *wdata;
+       dprintk("%s enter\n", __func__);
+       task = container_of(work, struct rpc_task, u.tk_work);
+       wdata = container_of(task, struct nfs_write_data, task);
+       if (!wdata->pnfs_error) {
+               /* Marks for LAYOUTCOMMIT */
+               mark_extents_written(BLK_LSEG2EXT(wdata->lseg),
+                                    wdata->args.offset, wdata->args.count);
+       }
+       pnfs_ld_write_done(wdata);
+}
+
+/* Called when last of bios associated with a bl_write_pagelist call finishes */
+static void bl_end_par_io_write(void *data)
+{
+       struct nfs_write_data *wdata = data;
+
+       wdata->task.tk_status = 0;
+       wdata->verf.committed = NFS_FILE_SYNC;
+       INIT_WORK(&wdata->task.u.tk_work, bl_write_cleanup);
+       schedule_work(&wdata->task.u.tk_work);
+}
+
+/* FIXME STUB - mark intersection of layout and page as bad, so is not
+ * used again.
+ */
+static void mark_bad_read(void)
+{
+       return;
+}
+
+/*
+ * map_block:  map a requested I/0 block (isect) into an offset in the LVM
+ * block_device
+ */
+static void
+map_block(struct buffer_head *bh, sector_t isect, struct pnfs_block_extent *be)
+{
+       dprintk("%s enter be=%p\n", __func__, be);
+
+       set_buffer_mapped(bh);
+       bh->b_bdev = be->be_mdev;
+       bh->b_blocknr = (isect - be->be_f_offset + be->be_v_offset) >>
+           (be->be_mdev->bd_inode->i_blkbits - SECTOR_SHIFT);
+
+       dprintk("%s isect %llu, bh->b_blocknr %ld, using bsize %Zd\n",
+               __func__, (unsigned long long)isect, (long)bh->b_blocknr,
+               bh->b_size);
+       return;
+}
+
+/* Given an unmapped page, zero it or read in page for COW, page is locked
+ * by caller.
+ */
+static int
+init_page_for_write(struct page *page, struct pnfs_block_extent *cow_read)
+{
+       struct buffer_head *bh = NULL;
+       int ret = 0;
+       sector_t isect;
+
+       dprintk("%s enter, %p\n", __func__, page);
+       BUG_ON(PageUptodate(page));
+       if (!cow_read) {
+               zero_user_segment(page, 0, PAGE_SIZE);
+               SetPageUptodate(page);
+               goto cleanup;
+       }
+
+       bh = alloc_page_buffers(page, PAGE_CACHE_SIZE, 0);
+       if (!bh) {
+               ret = -ENOMEM;
+               goto cleanup;
+       }
+
+       isect = (sector_t) page->index << PAGE_CACHE_SECTOR_SHIFT;
+       map_block(bh, isect, cow_read);
+       if (!bh_uptodate_or_lock(bh))
+               ret = bh_submit_read(bh);
+       if (ret)
+               goto cleanup;
+       SetPageUptodate(page);
+
+cleanup:
+       bl_put_extent(cow_read);
+       if (bh)
+               free_buffer_head(bh);
+       if (ret) {
+               /* Need to mark layout with bad read...should now
+                * just use nfs4 for reads and writes.
+                */
+               mark_bad_read();
+       }
+       return ret;
+}
+
+static enum pnfs_try_status
+bl_write_pagelist(struct nfs_write_data *wdata, int sync)
+{
+       int i, ret, npg_zero, pg_index, last = 0;
+       struct bio *bio = NULL;
+       struct pnfs_block_extent *be = NULL, *cow_read = NULL;
+       sector_t isect, last_isect = 0, extent_length = 0;
+       struct parallel_io *par;
+       loff_t offset = wdata->args.offset;
+       size_t count = wdata->args.count;
+       struct page **pages = wdata->args.pages;
+       struct page *page;
+       pgoff_t index;
+       u64 temp;
+       int npg_per_block =
+           NFS_SERVER(wdata->inode)->pnfs_blksize >> PAGE_CACHE_SHIFT;
+
+       dprintk("%s enter, %Zu@%lld\n", __func__, count, offset);
+       /* At this point, wdata->pages is a (sequential) list of nfs_pages.
+        * We want to write each, and if there is an error set pnfs_error
+        * to have it redone using nfs.
+        */
+       par = alloc_parallel(wdata);
+       if (!par)
+               return PNFS_NOT_ATTEMPTED;
+       par->call_ops = *wdata->mds_ops;
+       par->call_ops.rpc_call_done = bl_rpc_do_nothing;
+       par->pnfs_callback = bl_end_par_io_write;
+       /* At this point, have to be more careful with error handling */
+
+       isect = (sector_t) ((offset & (long)PAGE_CACHE_MASK) >> SECTOR_SHIFT);
+       be = bl_find_get_extent(BLK_LSEG2EXT(wdata->lseg), isect, &cow_read);
+       if (!be || !is_writable(be, isect)) {
+               dprintk("%s no matching extents!\n", __func__);
+               wdata->pnfs_error = -EINVAL;
+               goto out;
+       }
+
+       /* First page inside INVALID extent */
+       if (be->be_state == PNFS_BLOCK_INVALID_DATA) {
+               temp = offset >> PAGE_CACHE_SHIFT;
+               npg_zero = do_div(temp, npg_per_block);
+               isect = (sector_t) (((offset - npg_zero * PAGE_CACHE_SIZE) &
+                                    (long)PAGE_CACHE_MASK) >> SECTOR_SHIFT);
+               extent_length = be->be_length - (isect - be->be_f_offset);
+
+fill_invalid_ext:
+               dprintk("%s need to zero %d pages\n", __func__, npg_zero);
+               for (;npg_zero > 0; npg_zero--) {
+                       /* page ref released in bl_end_io_write_zero */
+                       index = isect >> PAGE_CACHE_SECTOR_SHIFT;
+                       dprintk("%s zero %dth page: index %lu isect %llu\n",
+                               __func__, npg_zero, index,
+                               (unsigned long long)isect);
+                       page =
+                           find_or_create_page(wdata->inode->i_mapping, index,
+                                               GFP_NOFS);
+                       if (!page) {
+                               dprintk("%s oom\n", __func__);
+                               wdata->pnfs_error = -ENOMEM;
+                               goto out;
+                       }
+
+                       /* PageDirty: Other will write this out
+                        * PageWriteback: Other is writing this out
+                        * PageUptodate: It was read before
+                        * sector_initialized: already written out
+                        */
+                       if (PageDirty(page) || PageWriteback(page) ||
+                           bl_is_sector_init(be->be_inval, isect)) {
+                               print_page(page);
+                               unlock_page(page);
+                               page_cache_release(page);
+                               goto next_page;
+                       }
+                       if (!PageUptodate(page)) {
+                               /* New page, readin or zero it */
+                               init_page_for_write(page, cow_read);
+                       }
+                       set_page_writeback(page);
+                       unlock_page(page);
+
+                       ret = bl_mark_sectors_init(be->be_inval, isect,
+                                                      PAGE_CACHE_SECTORS,
+                                                      NULL);
+                       if (unlikely(ret)) {
+                               dprintk("%s bl_mark_sectors_init fail %d\n",
+                                       __func__, ret);
+                               end_page_writeback(page);
+                               page_cache_release(page);
+                               wdata->pnfs_error = ret;
+                               goto out;
+                       }
+                       bio = bl_add_page_to_bio(bio, npg_zero, WRITE,
+                                                isect, page, be,
+                                                bl_end_io_write_zero, par);
+                       if (IS_ERR(bio)) {
+                               wdata->pnfs_error = PTR_ERR(bio);
+                               goto out;
+                       }
+                       /* FIXME: This should be done in bi_end_io */
+                       mark_extents_written(BLK_LSEG2EXT(wdata->lseg),
+                                            page->index << PAGE_CACHE_SHIFT,
+                                            PAGE_CACHE_SIZE);
+next_page:
+                       isect += PAGE_CACHE_SECTORS;
+                       extent_length -= PAGE_CACHE_SECTORS;
+               }
+               if (last)
+                       goto write_done;
+       }
+       bio = bl_submit_bio(WRITE, bio);
+
+       /* Middle pages */
+       pg_index = wdata->args.pgbase >> PAGE_CACHE_SHIFT;
+       for (i = pg_index; i < wdata->npages; i++) {
+               if (!extent_length) {
+                       /* We've used up the previous extent */
+                       bl_put_extent(be);
+                       bio = bl_submit_bio(WRITE, bio);
+                       /* Get the next one */
+                       be = bl_find_get_extent(BLK_LSEG2EXT(wdata->lseg),
+                                            isect, NULL);
+                       if (!be || !is_writable(be, isect)) {
+                               wdata->pnfs_error = -EINVAL;
+                               goto out;
+                       }
+                       extent_length = be->be_length -
+                           (isect - be->be_f_offset);
+               }
+               if (be->be_state == PNFS_BLOCK_INVALID_DATA) {
+                       ret = bl_mark_sectors_init(be->be_inval, isect,
+                                                      PAGE_CACHE_SECTORS,
+                                                      NULL);
+                       if (unlikely(ret)) {
+                               dprintk("%s bl_mark_sectors_init fail %d\n",
+                                       __func__, ret);
+                               wdata->pnfs_error = ret;
+                               goto out;
+                       }
+               }
+               bio = bl_add_page_to_bio(bio, wdata->npages - i, WRITE,
+                                        isect, pages[i], be,
+                                        bl_end_io_write, par);
+               if (IS_ERR(bio)) {
+                       wdata->pnfs_error = PTR_ERR(bio);
+                       goto out;
+               }
+               isect += PAGE_CACHE_SECTORS;
+               last_isect = isect;
+               extent_length -= PAGE_CACHE_SECTORS;
+       }
+
+       /* Last page inside INVALID extent */
+       if (be->be_state == PNFS_BLOCK_INVALID_DATA) {
+               bio = bl_submit_bio(WRITE, bio);
+               temp = last_isect >> PAGE_CACHE_SECTOR_SHIFT;
+               npg_zero = npg_per_block - do_div(temp, npg_per_block);
+               if (npg_zero < npg_per_block) {
+                       last = 1;
+                       goto fill_invalid_ext;
+               }
+       }
+
+write_done:
+       wdata->res.count = (last_isect << SECTOR_SHIFT) - (offset);
+       if (count < wdata->res.count) {
+               wdata->res.count = count;
+       }
+out:
+       bl_put_extent(be);
+       bl_submit_bio(WRITE, bio);
+       put_parallel(par);
+       return PNFS_ATTEMPTED;
+}
+
+/* FIXME - range ignored */
+static void
+release_extents(struct pnfs_block_layout *bl, struct pnfs_layout_range *range)
+{
+       int i;
+       struct pnfs_block_extent *be;
+
+       spin_lock(&bl->bl_ext_lock);
+       for (i = 0; i < EXTENT_LISTS; i++) {
+               while (!list_empty(&bl->bl_extents[i])) {
+                       be = list_first_entry(&bl->bl_extents[i],
+                                             struct pnfs_block_extent,
+                                             be_node);
+                       list_del(&be->be_node);
+                       bl_put_extent(be);
+               }
+       }
+       spin_unlock(&bl->bl_ext_lock);
+}
+
+static void
+release_inval_marks(struct pnfs_inval_markings *marks)
+{
+       struct pnfs_inval_tracking *pos, *temp;
+
+       list_for_each_entry_safe(pos, temp, &marks->im_tree.mtt_stub, it_link) {
+               list_del(&pos->it_link);
+               kfree(pos);
+       }
+       return;
+}
+
+static void bl_free_layout_hdr(struct pnfs_layout_hdr *lo)
+{
+       struct pnfs_block_layout *bl = BLK_LO2EXT(lo);
+
+       dprintk("%s enter\n", __func__);
+       release_extents(bl, NULL);
+       release_inval_marks(&bl->bl_inval);
+       kfree(bl);
+}
+
+static struct pnfs_layout_hdr *bl_alloc_layout_hdr(struct inode *inode,
+                                                  gfp_t gfp_flags)
+{
+       struct pnfs_block_layout *bl;
+
+       dprintk("%s enter\n", __func__);
+       bl = kzalloc(sizeof(*bl), gfp_flags);
+       if (!bl)
+               return NULL;
+       spin_lock_init(&bl->bl_ext_lock);
+       INIT_LIST_HEAD(&bl->bl_extents[0]);
+       INIT_LIST_HEAD(&bl->bl_extents[1]);
+       INIT_LIST_HEAD(&bl->bl_commit);
+       INIT_LIST_HEAD(&bl->bl_committing);
+       bl->bl_count = 0;
+       bl->bl_blocksize = NFS_SERVER(inode)->pnfs_blksize >> SECTOR_SHIFT;
+       BL_INIT_INVAL_MARKS(&bl->bl_inval, bl->bl_blocksize);
+       return &bl->bl_layout;
+}
+
+static void bl_free_lseg(struct pnfs_layout_segment *lseg)
+{
+       dprintk("%s enter\n", __func__);
+       kfree(lseg);
+}
+
+/* We pretty much ignore lseg, and store all data layout wide, so we
+ * can correctly merge.
+ */
+static struct pnfs_layout_segment *bl_alloc_lseg(struct pnfs_layout_hdr *lo,
+                                                struct nfs4_layoutget_res *lgr,
+                                                gfp_t gfp_flags)
+{
+       struct pnfs_layout_segment *lseg;
+       int status;
+
+       dprintk("%s enter\n", __func__);
+       lseg = kzalloc(sizeof(*lseg), gfp_flags);
+       if (!lseg)
+               return ERR_PTR(-ENOMEM);
+       status = nfs4_blk_process_layoutget(lo, lgr, gfp_flags);
+       if (status) {
+               /* We don't want to call the full-blown bl_free_lseg,
+                * since on error extents were not touched.
+                */
+               kfree(lseg);
+               return ERR_PTR(status);
+       }
+       return lseg;
+}
+
+static void
+bl_encode_layoutcommit(struct pnfs_layout_hdr *lo, struct xdr_stream *xdr,
+                      const struct nfs4_layoutcommit_args *arg)
+{
+       dprintk("%s enter\n", __func__);
+       encode_pnfs_block_layoutupdate(BLK_LO2EXT(lo), xdr, arg);
+}
+
+static void
+bl_cleanup_layoutcommit(struct nfs4_layoutcommit_data *lcdata)
+{
+       struct pnfs_layout_hdr *lo = NFS_I(lcdata->args.inode)->layout;
+
+       dprintk("%s enter\n", __func__);
+       clean_pnfs_block_layoutupdate(BLK_LO2EXT(lo), &lcdata->args, lcdata->res.status);
+}
+
+static void free_blk_mountid(struct block_mount_id *mid)
+{
+       if (mid) {
+               struct pnfs_block_dev *dev;
+               spin_lock(&mid->bm_lock);
+               while (!list_empty(&mid->bm_devlist)) {
+                       dev = list_first_entry(&mid->bm_devlist,
+                                              struct pnfs_block_dev,
+                                              bm_node);
+                       list_del(&dev->bm_node);
+                       bl_free_block_dev(dev);
+               }
+               spin_unlock(&mid->bm_lock);
+               kfree(mid);
+       }
+}
+
+/* This is mostly copied from the filelayout's get_device_info function.
+ * It seems much of this should be at the generic pnfs level.
+ */
+static struct pnfs_block_dev *
+nfs4_blk_get_deviceinfo(struct nfs_server *server, const struct nfs_fh *fh,
+                       struct nfs4_deviceid *d_id)
+{
+       struct pnfs_device *dev;
+       struct pnfs_block_dev *rv = NULL;
+       u32 max_resp_sz;
+       int max_pages;
+       struct page **pages = NULL;
+       int i, rc;
+
+       /*
+        * Use the session max response size as the basis for setting
+        * GETDEVICEINFO's maxcount
+        */
+       max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
+       max_pages = max_resp_sz >> PAGE_SHIFT;
+       dprintk("%s max_resp_sz %u max_pages %d\n",
+               __func__, max_resp_sz, max_pages);
+
+       dev = kmalloc(sizeof(*dev), GFP_NOFS);
+       if (!dev) {
+               dprintk("%s kmalloc failed\n", __func__);
+               return NULL;
+       }
+
+       pages = kzalloc(max_pages * sizeof(struct page *), GFP_NOFS);
+       if (pages == NULL) {
+               kfree(dev);
+               return NULL;
+       }
+       for (i = 0; i < max_pages; i++) {
+               pages[i] = alloc_page(GFP_NOFS);
+               if (!pages[i])
+                       goto out_free;
+       }
+
+       memcpy(&dev->dev_id, d_id, sizeof(*d_id));
+       dev->layout_type = LAYOUT_BLOCK_VOLUME;
+       dev->pages = pages;
+       dev->pgbase = 0;
+       dev->pglen = PAGE_SIZE * max_pages;
+       dev->mincount = 0;
+
+       dprintk("%s: dev_id: %s\n", __func__, dev->dev_id.data);
+       rc = nfs4_proc_getdeviceinfo(server, dev);
+       dprintk("%s getdevice info returns %d\n", __func__, rc);
+       if (rc)
+               goto out_free;
+
+       rv = nfs4_blk_decode_device(server, dev);
+ out_free:
+       for (i = 0; i < max_pages; i++)
+               __free_page(pages[i]);
+       kfree(pages);
+       kfree(dev);
+       return rv;
+}
+
+static int
+bl_set_layoutdriver(struct nfs_server *server, const struct nfs_fh *fh)
+{
+       struct block_mount_id *b_mt_id = NULL;
+       struct pnfs_devicelist *dlist = NULL;
+       struct pnfs_block_dev *bdev;
+       LIST_HEAD(block_disklist);
+       int status = 0, i;
+
+       dprintk("%s enter\n", __func__);
+
+       if (server->pnfs_blksize == 0) {
+               dprintk("%s Server did not return blksize\n", __func__);
+               return -EINVAL;
+       }
+       b_mt_id = kzalloc(sizeof(struct block_mount_id), GFP_NOFS);
+       if (!b_mt_id) {
+               status = -ENOMEM;
+               goto out_error;
+       }
+       /* Initialize nfs4 block layout mount id */
+       spin_lock_init(&b_mt_id->bm_lock);
+       INIT_LIST_HEAD(&b_mt_id->bm_devlist);
+
+       dlist = kmalloc(sizeof(struct pnfs_devicelist), GFP_NOFS);
+       if (!dlist) {
+               status = -ENOMEM;
+               goto out_error;
+       }
+       dlist->eof = 0;
+       while (!dlist->eof) {
+               status = nfs4_proc_getdevicelist(server, fh, dlist);
+               if (status)
+                       goto out_error;
+               dprintk("%s GETDEVICELIST numdevs=%i, eof=%i\n",
+                       __func__, dlist->num_devs, dlist->eof);
+               for (i = 0; i < dlist->num_devs; i++) {
+                       bdev = nfs4_blk_get_deviceinfo(server, fh,
+                                                      &dlist->dev_id[i]);
+                       if (!bdev) {
+                               status = -ENODEV;
+                               goto out_error;
+                       }
+                       spin_lock(&b_mt_id->bm_lock);
+                       list_add(&bdev->bm_node, &b_mt_id->bm_devlist);
+                       spin_unlock(&b_mt_id->bm_lock);
+               }
+       }
+       dprintk("%s SUCCESS\n", __func__);
+       server->pnfs_ld_data = b_mt_id;
+
+ out_return:
+       kfree(dlist);
+       return status;
+
+ out_error:
+       free_blk_mountid(b_mt_id);
+       goto out_return;
+}
+
+static int
+bl_clear_layoutdriver(struct nfs_server *server)
+{
+       struct block_mount_id *b_mt_id = server->pnfs_ld_data;
+
+       dprintk("%s enter\n", __func__);
+       free_blk_mountid(b_mt_id);
+       dprintk("%s RETURNS\n", __func__);
+       return 0;
+}
+
+static const struct nfs_pageio_ops bl_pg_read_ops = {
+       .pg_init = pnfs_generic_pg_init_read,
+       .pg_test = pnfs_generic_pg_test,
+       .pg_doio = pnfs_generic_pg_readpages,
+};
+
+static const struct nfs_pageio_ops bl_pg_write_ops = {
+       .pg_init = pnfs_generic_pg_init_write,
+       .pg_test = pnfs_generic_pg_test,
+       .pg_doio = pnfs_generic_pg_writepages,
+};
+
+static struct pnfs_layoutdriver_type blocklayout_type = {
+       .id                             = LAYOUT_BLOCK_VOLUME,
+       .name                           = "LAYOUT_BLOCK_VOLUME",
+       .read_pagelist                  = bl_read_pagelist,
+       .write_pagelist                 = bl_write_pagelist,
+       .alloc_layout_hdr               = bl_alloc_layout_hdr,
+       .free_layout_hdr                = bl_free_layout_hdr,
+       .alloc_lseg                     = bl_alloc_lseg,
+       .free_lseg                      = bl_free_lseg,
+       .encode_layoutcommit            = bl_encode_layoutcommit,
+       .cleanup_layoutcommit           = bl_cleanup_layoutcommit,
+       .set_layoutdriver               = bl_set_layoutdriver,
+       .clear_layoutdriver             = bl_clear_layoutdriver,
+       .pg_read_ops                    = &bl_pg_read_ops,
+       .pg_write_ops                   = &bl_pg_write_ops,
+};
+
+static const struct rpc_pipe_ops bl_upcall_ops = {
+       .upcall         = bl_pipe_upcall,
+       .downcall       = bl_pipe_downcall,
+       .destroy_msg    = bl_pipe_destroy_msg,
+};
+
+static int __init nfs4blocklayout_init(void)
+{
+       struct vfsmount *mnt;
+       struct path path;
+       int ret;
+
+       dprintk("%s: NFSv4 Block Layout Driver Registering...\n", __func__);
+
+       ret = pnfs_register_layoutdriver(&blocklayout_type);
+       if (ret)
+               goto out;
+
+       init_waitqueue_head(&bl_wq);
+
+       mnt = rpc_get_mount();
+       if (IS_ERR(mnt)) {
+               ret = PTR_ERR(mnt);
+               goto out_remove;
+       }
+
+       ret = vfs_path_lookup(mnt->mnt_root,
+                             mnt,
+                             NFS_PIPE_DIRNAME, 0, &path);
+       if (ret)
+               goto out_remove;
+
+       bl_device_pipe = rpc_mkpipe(path.dentry, "blocklayout", NULL,
+                                   &bl_upcall_ops, 0);
+       if (IS_ERR(bl_device_pipe)) {
+               ret = PTR_ERR(bl_device_pipe);
+               goto out_remove;
+       }
+out:
+       return ret;
+
+out_remove:
+       pnfs_unregister_layoutdriver(&blocklayout_type);
+       return ret;
+}
+
+static void __exit nfs4blocklayout_exit(void)
+{
+       dprintk("%s: NFSv4 Block Layout Driver Unregistering...\n",
+              __func__);
+
+       pnfs_unregister_layoutdriver(&blocklayout_type);
+       rpc_unlink(bl_device_pipe);
+}
+
+MODULE_ALIAS("nfs-layouttype4-3");
+
+module_init(nfs4blocklayout_init);
+module_exit(nfs4blocklayout_exit);
diff --git a/fs/nfs/blocklayout/blocklayout.h b/fs/nfs/blocklayout/blocklayout.h
new file mode 100644 (file)
index 0000000..f27d827
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ *  linux/fs/nfs/blocklayout/blocklayout.h
+ *
+ *  Module for the NFSv4.1 pNFS block layout driver.
+ *
+ *  Copyright (c) 2006 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson <andros@citi.umich.edu>
+ *  Fred Isaman <iisaman@umich.edu>
+ *
+ * permission is granted to use, copy, create derivative works and
+ * redistribute this software and such derivative works for any purpose,
+ * so long as the name of the university of michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization.  if
+ * the above copyright notice or any other identification of the
+ * university of michigan is included in any copy of any portion of
+ * this software, then the disclaimer below must also be included.
+ *
+ * this software is provided as is, without representation from the
+ * university of michigan as to its fitness for any purpose, and without
+ * warranty by the university of michigan of any kind, either express
+ * or implied, including without limitation the implied warranties of
+ * merchantability and fitness for a particular purpose.  the regents
+ * of the university of michigan shall not be liable for any damages,
+ * including special, indirect, incidental, or consequential damages,
+ * with respect to any claim arising out or in connection with the use
+ * of the software, even if it has been or is hereafter advised of the
+ * possibility of such damages.
+ */
+#ifndef FS_NFS_NFS4BLOCKLAYOUT_H
+#define FS_NFS_NFS4BLOCKLAYOUT_H
+
+#include <linux/device-mapper.h>
+#include <linux/nfs_fs.h>
+#include <linux/sunrpc/rpc_pipe_fs.h>
+
+#include "../pnfs.h"
+
+#define PAGE_CACHE_SECTORS (PAGE_CACHE_SIZE >> SECTOR_SHIFT)
+#define PAGE_CACHE_SECTOR_SHIFT (PAGE_CACHE_SHIFT - SECTOR_SHIFT)
+
+struct block_mount_id {
+       spinlock_t                      bm_lock;    /* protects list */
+       struct list_head                bm_devlist; /* holds pnfs_block_dev */
+};
+
+struct pnfs_block_dev {
+       struct list_head                bm_node;
+       struct nfs4_deviceid            bm_mdevid;    /* associated devid */
+       struct block_device             *bm_mdev;     /* meta device itself */
+};
+
+enum exstate4 {
+       PNFS_BLOCK_READWRITE_DATA       = 0,
+       PNFS_BLOCK_READ_DATA            = 1,
+       PNFS_BLOCK_INVALID_DATA         = 2, /* mapped, but data is invalid */
+       PNFS_BLOCK_NONE_DATA            = 3  /* unmapped, it's a hole */
+};
+
+#define MY_MAX_TAGS (15) /* tag bitnums used must be less than this */
+
+struct my_tree {
+       sector_t                mtt_step_size;  /* Internal sector alignment */
+       struct list_head        mtt_stub; /* Should be a radix tree */
+};
+
+struct pnfs_inval_markings {
+       spinlock_t      im_lock;
+       struct my_tree  im_tree;        /* Sectors that need LAYOUTCOMMIT */
+       sector_t        im_block_size;  /* Server blocksize in sectors */
+};
+
+struct pnfs_inval_tracking {
+       struct list_head it_link;
+       int              it_sector;
+       int              it_tags;
+};
+
+/* sector_t fields are all in 512-byte sectors */
+struct pnfs_block_extent {
+       struct kref     be_refcnt;
+       struct list_head be_node;       /* link into lseg list */
+       struct nfs4_deviceid be_devid;  /* FIXME: could use device cache instead */
+       struct block_device *be_mdev;
+       sector_t        be_f_offset;    /* the starting offset in the file */
+       sector_t        be_length;      /* the size of the extent */
+       sector_t        be_v_offset;    /* the starting offset in the volume */
+       enum exstate4   be_state;       /* the state of this extent */
+       struct pnfs_inval_markings *be_inval; /* tracks INVAL->RW transition */
+};
+
+/* Shortened extent used by LAYOUTCOMMIT */
+struct pnfs_block_short_extent {
+       struct list_head bse_node;
+       struct nfs4_deviceid bse_devid;
+       struct block_device *bse_mdev;
+       sector_t        bse_f_offset;   /* the starting offset in the file */
+       sector_t        bse_length;     /* the size of the extent */
+};
+
+static inline void
+BL_INIT_INVAL_MARKS(struct pnfs_inval_markings *marks, sector_t blocksize)
+{
+       spin_lock_init(&marks->im_lock);
+       INIT_LIST_HEAD(&marks->im_tree.mtt_stub);
+       marks->im_block_size = blocksize;
+       marks->im_tree.mtt_step_size = min((sector_t)PAGE_CACHE_SECTORS,
+                                          blocksize);
+}
+
+enum extentclass4 {
+       RW_EXTENT       = 0, /* READWRTE and INVAL */
+       RO_EXTENT       = 1, /* READ and NONE */
+       EXTENT_LISTS    = 2,
+};
+
+static inline int bl_choose_list(enum exstate4 state)
+{
+       if (state == PNFS_BLOCK_READ_DATA || state == PNFS_BLOCK_NONE_DATA)
+               return RO_EXTENT;
+       else
+               return RW_EXTENT;
+}
+
+struct pnfs_block_layout {
+       struct pnfs_layout_hdr bl_layout;
+       struct pnfs_inval_markings bl_inval; /* tracks INVAL->RW transition */
+       spinlock_t              bl_ext_lock;   /* Protects list manipulation */
+       struct list_head        bl_extents[EXTENT_LISTS]; /* R and RW extents */
+       struct list_head        bl_commit;      /* Needs layout commit */
+       struct list_head        bl_committing;  /* Layout committing */
+       unsigned int            bl_count;       /* entries in bl_commit */
+       sector_t                bl_blocksize;  /* Server blocksize in sectors */
+};
+
+#define BLK_ID(lo) ((struct block_mount_id *)(NFS_SERVER(lo->plh_inode)->pnfs_ld_data))
+
+static inline struct pnfs_block_layout *
+BLK_LO2EXT(struct pnfs_layout_hdr *lo)
+{
+       return container_of(lo, struct pnfs_block_layout, bl_layout);
+}
+
+static inline struct pnfs_block_layout *
+BLK_LSEG2EXT(struct pnfs_layout_segment *lseg)
+{
+       return BLK_LO2EXT(lseg->pls_layout);
+}
+
+struct bl_dev_msg {
+       int status;
+       uint32_t major, minor;
+};
+
+struct bl_msg_hdr {
+       u8  type;
+       u16 totallen; /* length of entire message, including hdr itself */
+};
+
+extern struct dentry *bl_device_pipe;
+extern wait_queue_head_t bl_wq;
+
+#define BL_DEVICE_UMOUNT               0x0 /* Umount--delete devices */
+#define BL_DEVICE_MOUNT                0x1 /* Mount--create devices*/
+#define BL_DEVICE_REQUEST_INIT         0x0 /* Start request */
+#define BL_DEVICE_REQUEST_PROC         0x1 /* User level process succeeds */
+#define BL_DEVICE_REQUEST_ERR          0x2 /* User level process fails */
+
+/* blocklayoutdev.c */
+ssize_t bl_pipe_upcall(struct file *, struct rpc_pipe_msg *,
+                      char __user *, size_t);
+ssize_t bl_pipe_downcall(struct file *, const char __user *, size_t);
+void bl_pipe_destroy_msg(struct rpc_pipe_msg *);
+struct block_device *nfs4_blkdev_get(dev_t dev);
+int nfs4_blkdev_put(struct block_device *bdev);
+struct pnfs_block_dev *nfs4_blk_decode_device(struct nfs_server *server,
+                                               struct pnfs_device *dev);
+int nfs4_blk_process_layoutget(struct pnfs_layout_hdr *lo,
+                               struct nfs4_layoutget_res *lgr, gfp_t gfp_flags);
+
+/* blocklayoutdm.c */
+void bl_free_block_dev(struct pnfs_block_dev *bdev);
+
+/* extents.c */
+struct pnfs_block_extent *
+bl_find_get_extent(struct pnfs_block_layout *bl, sector_t isect,
+               struct pnfs_block_extent **cow_read);
+int bl_mark_sectors_init(struct pnfs_inval_markings *marks,
+                            sector_t offset, sector_t length,
+                            sector_t **pages);
+void bl_put_extent(struct pnfs_block_extent *be);
+struct pnfs_block_extent *bl_alloc_extent(void);
+int bl_is_sector_init(struct pnfs_inval_markings *marks, sector_t isect);
+int encode_pnfs_block_layoutupdate(struct pnfs_block_layout *bl,
+                                  struct xdr_stream *xdr,
+                                  const struct nfs4_layoutcommit_args *arg);
+void clean_pnfs_block_layoutupdate(struct pnfs_block_layout *bl,
+                                  const struct nfs4_layoutcommit_args *arg,
+                                  int status);
+int bl_add_merge_extent(struct pnfs_block_layout *bl,
+                        struct pnfs_block_extent *new);
+int bl_mark_for_commit(struct pnfs_block_extent *be,
+                       sector_t offset, sector_t length);
+
+#endif /* FS_NFS_NFS4BLOCKLAYOUT_H */
diff --git a/fs/nfs/blocklayout/blocklayoutdev.c b/fs/nfs/blocklayout/blocklayoutdev.c
new file mode 100644 (file)
index 0000000..a83b393
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ *  linux/fs/nfs/blocklayout/blocklayoutdev.c
+ *
+ *  Device operations for the pnfs nfs4 file layout driver.
+ *
+ *  Copyright (c) 2006 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson <andros@citi.umich.edu>
+ *  Fred Isaman <iisaman@umich.edu>
+ *
+ * permission is granted to use, copy, create derivative works and
+ * redistribute this software and such derivative works for any purpose,
+ * so long as the name of the university of michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization.  if
+ * the above copyright notice or any other identification of the
+ * university of michigan is included in any copy of any portion of
+ * this software, then the disclaimer below must also be included.
+ *
+ * this software is provided as is, without representation from the
+ * university of michigan as to its fitness for any purpose, and without
+ * warranty by the university of michigan of any kind, either express
+ * or implied, including without limitation the implied warranties of
+ * merchantability and fitness for a particular purpose.  the regents
+ * of the university of michigan shall not be liable for any damages,
+ * including special, indirect, incidental, or consequential damages,
+ * with respect to any claim arising out or in connection with the use
+ * of the software, even if it has been or is hereafter advised of the
+ * possibility of such damages.
+ */
+#include <linux/module.h>
+#include <linux/buffer_head.h> /* __bread */
+
+#include <linux/genhd.h>
+#include <linux/blkdev.h>
+#include <linux/hash.h>
+
+#include "blocklayout.h"
+
+#define NFSDBG_FACILITY         NFSDBG_PNFS_LD
+
+static int decode_sector_number(__be32 **rp, sector_t *sp)
+{
+       uint64_t s;
+
+       *rp = xdr_decode_hyper(*rp, &s);
+       if (s & 0x1ff) {
+               printk(KERN_WARNING "%s: sector not aligned\n", __func__);
+               return -1;
+       }
+       *sp = s >> SECTOR_SHIFT;
+       return 0;
+}
+
+/* Open a block_device by device number. */
+struct block_device *nfs4_blkdev_get(dev_t dev)
+{
+       struct block_device *bd;
+
+       dprintk("%s enter\n", __func__);
+       bd = blkdev_get_by_dev(dev, FMODE_READ, NULL);
+       if (IS_ERR(bd))
+               goto fail;
+       return bd;
+fail:
+       dprintk("%s failed to open device : %ld\n",
+                       __func__, PTR_ERR(bd));
+       return NULL;
+}
+
+/*
+ * Release the block device
+ */
+int nfs4_blkdev_put(struct block_device *bdev)
+{
+       dprintk("%s for device %d:%d\n", __func__, MAJOR(bdev->bd_dev),
+                       MINOR(bdev->bd_dev));
+       return blkdev_put(bdev, FMODE_READ);
+}
+
+/*
+ * Shouldn't there be a rpc_generic_upcall() to do this for us?
+ */
+ssize_t bl_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg,
+                      char __user *dst, size_t buflen)
+{
+       char *data = (char *)msg->data + msg->copied;
+       size_t mlen = min(msg->len - msg->copied, buflen);
+       unsigned long left;
+
+       left = copy_to_user(dst, data, mlen);
+       if (left == mlen) {
+               msg->errno = -EFAULT;
+               return -EFAULT;
+       }
+
+       mlen -= left;
+       msg->copied += mlen;
+       msg->errno = 0;
+       return mlen;
+}
+
+static struct bl_dev_msg bl_mount_reply;
+
+ssize_t bl_pipe_downcall(struct file *filp, const char __user *src,
+                        size_t mlen)
+{
+       if (mlen != sizeof (struct bl_dev_msg))
+               return -EINVAL;
+
+       if (copy_from_user(&bl_mount_reply, src, mlen) != 0)
+               return -EFAULT;
+
+       wake_up(&bl_wq);
+
+       return mlen;
+}
+
+void bl_pipe_destroy_msg(struct rpc_pipe_msg *msg)
+{
+       if (msg->errno >= 0)
+               return;
+       wake_up(&bl_wq);
+}
+
+/*
+ * Decodes pnfs_block_deviceaddr4 which is XDR encoded in dev->dev_addr_buf.
+ */
+struct pnfs_block_dev *
+nfs4_blk_decode_device(struct nfs_server *server,
+                      struct pnfs_device *dev)
+{
+       struct pnfs_block_dev *rv = NULL;
+       struct block_device *bd = NULL;
+       struct rpc_pipe_msg msg;
+       struct bl_msg_hdr bl_msg = {
+               .type = BL_DEVICE_MOUNT,
+               .totallen = dev->mincount,
+       };
+       uint8_t *dataptr;
+       DECLARE_WAITQUEUE(wq, current);
+       struct bl_dev_msg *reply = &bl_mount_reply;
+       int offset, len, i;
+
+       dprintk("%s CREATING PIPEFS MESSAGE\n", __func__);
+       dprintk("%s: deviceid: %s, mincount: %d\n", __func__, dev->dev_id.data,
+               dev->mincount);
+
+       memset(&msg, 0, sizeof(msg));
+       msg.data = kzalloc(sizeof(bl_msg) + dev->mincount, GFP_NOFS);
+       if (!msg.data) {
+               rv = ERR_PTR(-ENOMEM);
+               goto out;
+       }
+
+       memcpy(msg.data, &bl_msg, sizeof(bl_msg));
+       dataptr = (uint8_t *) msg.data;
+       len = dev->mincount;
+       offset = sizeof(bl_msg);
+       for (i = 0; len > 0; i++) {
+               memcpy(&dataptr[offset], page_address(dev->pages[i]),
+                               len < PAGE_CACHE_SIZE ? len : PAGE_CACHE_SIZE);
+               len -= PAGE_CACHE_SIZE;
+               offset += PAGE_CACHE_SIZE;
+       }
+       msg.len = sizeof(bl_msg) + dev->mincount;
+
+       dprintk("%s CALLING USERSPACE DAEMON\n", __func__);
+       add_wait_queue(&bl_wq, &wq);
+       if (rpc_queue_upcall(bl_device_pipe->d_inode, &msg) < 0) {
+               remove_wait_queue(&bl_wq, &wq);
+               goto out;
+       }
+
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       schedule();
+       __set_current_state(TASK_RUNNING);
+       remove_wait_queue(&bl_wq, &wq);
+
+       if (reply->status != BL_DEVICE_REQUEST_PROC) {
+               dprintk("%s failed to open device: %d\n",
+                       __func__, reply->status);
+               rv = ERR_PTR(-EINVAL);
+               goto out;
+       }
+
+       bd = nfs4_blkdev_get(MKDEV(reply->major, reply->minor));
+       if (IS_ERR(bd)) {
+               dprintk("%s failed to open device : %ld\n",
+                       __func__, PTR_ERR(bd));
+               goto out;
+       }
+
+       rv = kzalloc(sizeof(*rv), GFP_NOFS);
+       if (!rv) {
+               rv = ERR_PTR(-ENOMEM);
+               goto out;
+       }
+
+       rv->bm_mdev = bd;
+       memcpy(&rv->bm_mdevid, &dev->dev_id, sizeof(struct nfs4_deviceid));
+       dprintk("%s Created device %s with bd_block_size %u\n",
+               __func__,
+               bd->bd_disk->disk_name,
+               bd->bd_block_size);
+
+out:
+       kfree(msg.data);
+       return rv;
+}
+
+/* Map deviceid returned by the server to constructed block_device */
+static struct block_device *translate_devid(struct pnfs_layout_hdr *lo,
+                                           struct nfs4_deviceid *id)
+{
+       struct block_device *rv = NULL;
+       struct block_mount_id *mid;
+       struct pnfs_block_dev *dev;
+
+       dprintk("%s enter, lo=%p, id=%p\n", __func__, lo, id);
+       mid = BLK_ID(lo);
+       spin_lock(&mid->bm_lock);
+       list_for_each_entry(dev, &mid->bm_devlist, bm_node) {
+               if (memcmp(id->data, dev->bm_mdevid.data,
+                          NFS4_DEVICEID4_SIZE) == 0) {
+                       rv = dev->bm_mdev;
+                       goto out;
+               }
+       }
+ out:
+       spin_unlock(&mid->bm_lock);
+       dprintk("%s returning %p\n", __func__, rv);
+       return rv;
+}
+
+/* Tracks info needed to ensure extents in layout obey constraints of spec */
+struct layout_verification {
+       u32 mode;       /* R or RW */
+       u64 start;      /* Expected start of next non-COW extent */
+       u64 inval;      /* Start of INVAL coverage */
+       u64 cowread;    /* End of COW read coverage */
+};
+
+/* Verify the extent meets the layout requirements of the pnfs-block draft,
+ * section 2.3.1.
+ */
+static int verify_extent(struct pnfs_block_extent *be,
+                        struct layout_verification *lv)
+{
+       if (lv->mode == IOMODE_READ) {
+               if (be->be_state == PNFS_BLOCK_READWRITE_DATA ||
+                   be->be_state == PNFS_BLOCK_INVALID_DATA)
+                       return -EIO;
+               if (be->be_f_offset != lv->start)
+                       return -EIO;
+               lv->start += be->be_length;
+               return 0;
+       }
+       /* lv->mode == IOMODE_RW */
+       if (be->be_state == PNFS_BLOCK_READWRITE_DATA) {
+               if (be->be_f_offset != lv->start)
+                       return -EIO;
+               if (lv->cowread > lv->start)
+                       return -EIO;
+               lv->start += be->be_length;
+               lv->inval = lv->start;
+               return 0;
+       } else if (be->be_state == PNFS_BLOCK_INVALID_DATA) {
+               if (be->be_f_offset != lv->start)
+                       return -EIO;
+               lv->start += be->be_length;
+               return 0;
+       } else if (be->be_state == PNFS_BLOCK_READ_DATA) {
+               if (be->be_f_offset > lv->start)
+                       return -EIO;
+               if (be->be_f_offset < lv->inval)
+                       return -EIO;
+               if (be->be_f_offset < lv->cowread)
+                       return -EIO;
+               /* It looks like you might want to min this with lv->start,
+                * but you really don't.
+                */
+               lv->inval = lv->inval + be->be_length;
+               lv->cowread = be->be_f_offset + be->be_length;
+               return 0;
+       } else
+               return -EIO;
+}
+
+/* XDR decode pnfs_block_layout4 structure */
+int
+nfs4_blk_process_layoutget(struct pnfs_layout_hdr *lo,
+                          struct nfs4_layoutget_res *lgr, gfp_t gfp_flags)
+{
+       struct pnfs_block_layout *bl = BLK_LO2EXT(lo);
+       int i, status = -EIO;
+       uint32_t count;
+       struct pnfs_block_extent *be = NULL, *save;
+       struct xdr_stream stream;
+       struct xdr_buf buf;
+       struct page *scratch;
+       __be32 *p;
+       struct layout_verification lv = {
+               .mode = lgr->range.iomode,
+               .start = lgr->range.offset >> SECTOR_SHIFT,
+               .inval = lgr->range.offset >> SECTOR_SHIFT,
+               .cowread = lgr->range.offset >> SECTOR_SHIFT,
+       };
+       LIST_HEAD(extents);
+
+       dprintk("---> %s\n", __func__);
+
+       scratch = alloc_page(gfp_flags);
+       if (!scratch)
+               return -ENOMEM;
+
+       xdr_init_decode_pages(&stream, &buf, lgr->layoutp->pages, lgr->layoutp->len);
+       xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE);
+
+       p = xdr_inline_decode(&stream, 4);
+       if (unlikely(!p))
+               goto out_err;
+
+       count = be32_to_cpup(p++);
+
+       dprintk("%s enter, number of extents %i\n", __func__, count);
+       p = xdr_inline_decode(&stream, (28 + NFS4_DEVICEID4_SIZE) * count);
+       if (unlikely(!p))
+               goto out_err;
+
+       /* Decode individual extents, putting them in temporary
+        * staging area until whole layout is decoded to make error
+        * recovery easier.
+        */
+       for (i = 0; i < count; i++) {
+               be = bl_alloc_extent();
+               if (!be) {
+                       status = -ENOMEM;
+                       goto out_err;
+               }
+               memcpy(&be->be_devid, p, NFS4_DEVICEID4_SIZE);
+               p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE);
+               be->be_mdev = translate_devid(lo, &be->be_devid);
+               if (!be->be_mdev)
+                       goto out_err;
+
+               /* The next three values are read in as bytes,
+                * but stored as 512-byte sector lengths
+                */
+               if (decode_sector_number(&p, &be->be_f_offset) < 0)
+                       goto out_err;
+               if (decode_sector_number(&p, &be->be_length) < 0)
+                       goto out_err;
+               if (decode_sector_number(&p, &be->be_v_offset) < 0)
+                       goto out_err;
+               be->be_state = be32_to_cpup(p++);
+               if (be->be_state == PNFS_BLOCK_INVALID_DATA)
+                       be->be_inval = &bl->bl_inval;
+               if (verify_extent(be, &lv)) {
+                       dprintk("%s verify failed\n", __func__);
+                       goto out_err;
+               }
+               list_add_tail(&be->be_node, &extents);
+       }
+       if (lgr->range.offset + lgr->range.length !=
+                       lv.start << SECTOR_SHIFT) {
+               dprintk("%s Final length mismatch\n", __func__);
+               be = NULL;
+               goto out_err;
+       }
+       if (lv.start < lv.cowread) {
+               dprintk("%s Final uncovered COW extent\n", __func__);
+               be = NULL;
+               goto out_err;
+       }
+       /* Extents decoded properly, now try to merge them in to
+        * existing layout extents.
+        */
+       spin_lock(&bl->bl_ext_lock);
+       list_for_each_entry_safe(be, save, &extents, be_node) {
+               list_del(&be->be_node);
+               status = bl_add_merge_extent(bl, be);
+               if (status) {
+                       spin_unlock(&bl->bl_ext_lock);
+                       /* This is a fairly catastrophic error, as the
+                        * entire layout extent lists are now corrupted.
+                        * We should have some way to distinguish this.
+                        */
+                       be = NULL;
+                       goto out_err;
+               }
+       }
+       spin_unlock(&bl->bl_ext_lock);
+       status = 0;
+ out:
+       __free_page(scratch);
+       dprintk("%s returns %i\n", __func__, status);
+       return status;
+
+ out_err:
+       bl_put_extent(be);
+       while (!list_empty(&extents)) {
+               be = list_first_entry(&extents, struct pnfs_block_extent,
+                                     be_node);
+               list_del(&be->be_node);
+               bl_put_extent(be);
+       }
+       goto out;
+}
diff --git a/fs/nfs/blocklayout/blocklayoutdm.c b/fs/nfs/blocklayout/blocklayoutdm.c
new file mode 100644 (file)
index 0000000..d055c75
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ *  linux/fs/nfs/blocklayout/blocklayoutdm.c
+ *
+ *  Module for the NFSv4.1 pNFS block layout driver.
+ *
+ *  Copyright (c) 2007 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Fred Isaman <iisaman@umich.edu>
+ *  Andy Adamson <andros@citi.umich.edu>
+ *
+ * permission is granted to use, copy, create derivative works and
+ * redistribute this software and such derivative works for any purpose,
+ * so long as the name of the university of michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization.  if
+ * the above copyright notice or any other identification of the
+ * university of michigan is included in any copy of any portion of
+ * this software, then the disclaimer below must also be included.
+ *
+ * this software is provided as is, without representation from the
+ * university of michigan as to its fitness for any purpose, and without
+ * warranty by the university of michigan of any kind, either express
+ * or implied, including without limitation the implied warranties of
+ * merchantability and fitness for a particular purpose.  the regents
+ * of the university of michigan shall not be liable for any damages,
+ * including special, indirect, incidental, or consequential damages,
+ * with respect to any claim arising out or in connection with the use
+ * of the software, even if it has been or is hereafter advised of the
+ * possibility of such damages.
+ */
+
+#include <linux/genhd.h> /* gendisk - used in a dprintk*/
+#include <linux/sched.h>
+#include <linux/hash.h>
+
+#include "blocklayout.h"
+
+#define NFSDBG_FACILITY         NFSDBG_PNFS_LD
+
+static void dev_remove(dev_t dev)
+{
+       struct rpc_pipe_msg msg;
+       struct bl_dev_msg bl_umount_request;
+       struct bl_msg_hdr bl_msg = {
+               .type = BL_DEVICE_UMOUNT,
+               .totallen = sizeof(bl_umount_request),
+       };
+       uint8_t *dataptr;
+       DECLARE_WAITQUEUE(wq, current);
+
+       dprintk("Entering %s\n", __func__);
+
+       memset(&msg, 0, sizeof(msg));
+       msg.data = kzalloc(1 + sizeof(bl_umount_request), GFP_NOFS);
+       if (!msg.data)
+               goto out;
+
+       memset(&bl_umount_request, 0, sizeof(bl_umount_request));
+       bl_umount_request.major = MAJOR(dev);
+       bl_umount_request.minor = MINOR(dev);
+
+       memcpy(msg.data, &bl_msg, sizeof(bl_msg));
+       dataptr = (uint8_t *) msg.data;
+       memcpy(&dataptr[sizeof(bl_msg)], &bl_umount_request, sizeof(bl_umount_request));
+       msg.len = sizeof(bl_msg) + bl_msg.totallen;
+
+       add_wait_queue(&bl_wq, &wq);
+       if (rpc_queue_upcall(bl_device_pipe->d_inode, &msg) < 0) {
+               remove_wait_queue(&bl_wq, &wq);
+               goto out;
+       }
+
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       schedule();
+       __set_current_state(TASK_RUNNING);
+       remove_wait_queue(&bl_wq, &wq);
+
+out:
+       kfree(msg.data);
+}
+
+/*
+ * Release meta device
+ */
+static void nfs4_blk_metadev_release(struct pnfs_block_dev *bdev)
+{
+       int rv;
+
+       dprintk("%s Releasing\n", __func__);
+       rv = nfs4_blkdev_put(bdev->bm_mdev);
+       if (rv)
+               printk(KERN_ERR "%s nfs4_blkdev_put returns %d\n",
+                               __func__, rv);
+
+       dev_remove(bdev->bm_mdev->bd_dev);
+}
+
+void bl_free_block_dev(struct pnfs_block_dev *bdev)
+{
+       if (bdev) {
+               if (bdev->bm_mdev) {
+                       dprintk("%s Removing DM device: %d:%d\n",
+                               __func__,
+                               MAJOR(bdev->bm_mdev->bd_dev),
+                               MINOR(bdev->bm_mdev->bd_dev));
+                       nfs4_blk_metadev_release(bdev);
+               }
+               kfree(bdev);
+       }
+}
diff --git a/fs/nfs/blocklayout/extents.c b/fs/nfs/blocklayout/extents.c
new file mode 100644 (file)
index 0000000..19fa7b0
--- /dev/null
@@ -0,0 +1,935 @@
+/*
+ *  linux/fs/nfs/blocklayout/blocklayout.h
+ *
+ *  Module for the NFSv4.1 pNFS block layout driver.
+ *
+ *  Copyright (c) 2006 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson <andros@citi.umich.edu>
+ *  Fred Isaman <iisaman@umich.edu>
+ *
+ * permission is granted to use, copy, create derivative works and
+ * redistribute this software and such derivative works for any purpose,
+ * so long as the name of the university of michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization.  if
+ * the above copyright notice or any other identification of the
+ * university of michigan is included in any copy of any portion of
+ * this software, then the disclaimer below must also be included.
+ *
+ * this software is provided as is, without representation from the
+ * university of michigan as to its fitness for any purpose, and without
+ * warranty by the university of michigan of any kind, either express
+ * or implied, including without limitation the implied warranties of
+ * merchantability and fitness for a particular purpose.  the regents
+ * of the university of michigan shall not be liable for any damages,
+ * including special, indirect, incidental, or consequential damages,
+ * with respect to any claim arising out or in connection with the use
+ * of the software, even if it has been or is hereafter advised of the
+ * possibility of such damages.
+ */
+
+#include "blocklayout.h"
+#define NFSDBG_FACILITY         NFSDBG_PNFS_LD
+
+/* Bit numbers */
+#define EXTENT_INITIALIZED 0
+#define EXTENT_WRITTEN     1
+#define EXTENT_IN_COMMIT   2
+#define INTERNAL_EXISTS    MY_MAX_TAGS
+#define INTERNAL_MASK      ((1 << INTERNAL_EXISTS) - 1)
+
+/* Returns largest t<=s s.t. t%base==0 */
+static inline sector_t normalize(sector_t s, int base)
+{
+       sector_t tmp = s; /* Since do_div modifies its argument */
+       return s - do_div(tmp, base);
+}
+
+static inline sector_t normalize_up(sector_t s, int base)
+{
+       return normalize(s + base - 1, base);
+}
+
+/* Complete stub using list while determine API wanted */
+
+/* Returns tags, or negative */
+static int32_t _find_entry(struct my_tree *tree, u64 s)
+{
+       struct pnfs_inval_tracking *pos;
+
+       dprintk("%s(%llu) enter\n", __func__, s);
+       list_for_each_entry_reverse(pos, &tree->mtt_stub, it_link) {
+               if (pos->it_sector > s)
+                       continue;
+               else if (pos->it_sector == s)
+                       return pos->it_tags & INTERNAL_MASK;
+               else
+                       break;
+       }
+       return -ENOENT;
+}
+
+static inline
+int _has_tag(struct my_tree *tree, u64 s, int32_t tag)
+{
+       int32_t tags;
+
+       dprintk("%s(%llu, %i) enter\n", __func__, s, tag);
+       s = normalize(s, tree->mtt_step_size);
+       tags = _find_entry(tree, s);
+       if ((tags < 0) || !(tags & (1 << tag)))
+               return 0;
+       else
+               return 1;
+}
+
+/* Creates entry with tag, or if entry already exists, unions tag to it.
+ * If storage is not NULL, newly created entry will use it.
+ * Returns number of entries added, or negative on error.
+ */
+static int _add_entry(struct my_tree *tree, u64 s, int32_t tag,
+                     struct pnfs_inval_tracking *storage)
+{
+       int found = 0;
+       struct pnfs_inval_tracking *pos;
+
+       dprintk("%s(%llu, %i, %p) enter\n", __func__, s, tag, storage);
+       list_for_each_entry_reverse(pos, &tree->mtt_stub, it_link) {
+               if (pos->it_sector > s)
+                       continue;
+               else if (pos->it_sector == s) {
+                       found = 1;
+                       break;
+               } else
+                       break;
+       }
+       if (found) {
+               pos->it_tags |= (1 << tag);
+               return 0;
+       } else {
+               struct pnfs_inval_tracking *new;
+               if (storage)
+                       new = storage;
+               else {
+                       new = kmalloc(sizeof(*new), GFP_NOFS);
+                       if (!new)
+                               return -ENOMEM;
+               }
+               new->it_sector = s;
+               new->it_tags = (1 << tag);
+               list_add(&new->it_link, &pos->it_link);
+               return 1;
+       }
+}
+
+/* XXXX Really want option to not create */
+/* Over range, unions tag with existing entries, else creates entry with tag */
+static int _set_range(struct my_tree *tree, int32_t tag, u64 s, u64 length)
+{
+       u64 i;
+
+       dprintk("%s(%i, %llu, %llu) enter\n", __func__, tag, s, length);
+       for (i = normalize(s, tree->mtt_step_size); i < s + length;
+            i += tree->mtt_step_size)
+               if (_add_entry(tree, i, tag, NULL))
+                       return -ENOMEM;
+       return 0;
+}
+
+/* Ensure that future operations on given range of tree will not malloc */
+static int _preload_range(struct my_tree *tree, u64 offset, u64 length)
+{
+       u64 start, end, s;
+       int count, i, used = 0, status = -ENOMEM;
+       struct pnfs_inval_tracking **storage;
+
+       dprintk("%s(%llu, %llu) enter\n", __func__, offset, length);
+       start = normalize(offset, tree->mtt_step_size);
+       end = normalize_up(offset + length, tree->mtt_step_size);
+       count = (int)(end - start) / (int)tree->mtt_step_size;
+
+       /* Pre-malloc what memory we might need */
+       storage = kmalloc(sizeof(*storage) * count, GFP_NOFS);
+       if (!storage)
+               return -ENOMEM;
+       for (i = 0; i < count; i++) {
+               storage[i] = kmalloc(sizeof(struct pnfs_inval_tracking),
+                                    GFP_NOFS);
+               if (!storage[i])
+                       goto out_cleanup;
+       }
+
+       /* Now need lock - HOW??? */
+
+       for (s = start; s < end; s += tree->mtt_step_size)
+               used += _add_entry(tree, s, INTERNAL_EXISTS, storage[used]);
+
+       /* Unlock - HOW??? */
+       status = 0;
+
+ out_cleanup:
+       for (i = used; i < count; i++) {
+               if (!storage[i])
+                       break;
+               kfree(storage[i]);
+       }
+       kfree(storage);
+       return status;
+}
+
+static void set_needs_init(sector_t *array, sector_t offset)
+{
+       sector_t *p = array;
+
+       dprintk("%s enter\n", __func__);
+       if (!p)
+               return;
+       while (*p < offset)
+               p++;
+       if (*p == offset)
+               return;
+       else if (*p == ~0) {
+               *p++ = offset;
+               *p = ~0;
+               return;
+       } else {
+               sector_t *save = p;
+               dprintk("%s Adding %llu\n", __func__, (u64)offset);
+               while (*p != ~0)
+                       p++;
+               p++;
+               memmove(save + 1, save, (char *)p - (char *)save);
+               *save = offset;
+               return;
+       }
+}
+
+/* We are relying on page lock to serialize this */
+int bl_is_sector_init(struct pnfs_inval_markings *marks, sector_t isect)
+{
+       int rv;
+
+       spin_lock(&marks->im_lock);
+       rv = _has_tag(&marks->im_tree, isect, EXTENT_INITIALIZED);
+       spin_unlock(&marks->im_lock);
+       return rv;
+}
+
+/* Assume start, end already sector aligned */
+static int
+_range_has_tag(struct my_tree *tree, u64 start, u64 end, int32_t tag)
+{
+       struct pnfs_inval_tracking *pos;
+       u64 expect = 0;
+
+       dprintk("%s(%llu, %llu, %i) enter\n", __func__, start, end, tag);
+       list_for_each_entry_reverse(pos, &tree->mtt_stub, it_link) {
+               if (pos->it_sector >= end)
+                       continue;
+               if (!expect) {
+                       if ((pos->it_sector == end - tree->mtt_step_size) &&
+                           (pos->it_tags & (1 << tag))) {
+                               expect = pos->it_sector - tree->mtt_step_size;
+                               if (pos->it_sector < tree->mtt_step_size || expect < start)
+                                       return 1;
+                               continue;
+                       } else {
+                               return 0;
+                       }
+               }
+               if (pos->it_sector != expect || !(pos->it_tags & (1 << tag)))
+                       return 0;
+               expect -= tree->mtt_step_size;
+               if (expect < start)
+                       return 1;
+       }
+       return 0;
+}
+
+static int is_range_written(struct pnfs_inval_markings *marks,
+                           sector_t start, sector_t end)
+{
+       int rv;
+
+       spin_lock(&marks->im_lock);
+       rv = _range_has_tag(&marks->im_tree, start, end, EXTENT_WRITTEN);
+       spin_unlock(&marks->im_lock);
+       return rv;
+}
+
+/* Marks sectors in [offest, offset_length) as having been initialized.
+ * All lengths are step-aligned, where step is min(pagesize, blocksize).
+ * Notes where partial block is initialized, and helps prepare it for
+ * complete initialization later.
+ */
+/* Currently assumes offset is page-aligned */
+int bl_mark_sectors_init(struct pnfs_inval_markings *marks,
+                            sector_t offset, sector_t length,
+                            sector_t **pages)
+{
+       sector_t s, start, end;
+       sector_t *array = NULL; /* Pages to mark */
+
+       dprintk("%s(offset=%llu,len=%llu) enter\n",
+               __func__, (u64)offset, (u64)length);
+       s = max((sector_t) 3,
+               2 * (marks->im_block_size / (PAGE_CACHE_SECTORS)));
+       dprintk("%s set max=%llu\n", __func__, (u64)s);
+       if (pages) {
+               array = kmalloc(s * sizeof(sector_t), GFP_NOFS);
+               if (!array)
+                       goto outerr;
+               array[0] = ~0;
+       }
+
+       start = normalize(offset, marks->im_block_size);
+       end = normalize_up(offset + length, marks->im_block_size);
+       if (_preload_range(&marks->im_tree, start, end - start))
+               goto outerr;
+
+       spin_lock(&marks->im_lock);
+
+       for (s = normalize_up(start, PAGE_CACHE_SECTORS);
+            s < offset; s += PAGE_CACHE_SECTORS) {
+               dprintk("%s pre-area pages\n", __func__);
+               /* Portion of used block is not initialized */
+               if (!_has_tag(&marks->im_tree, s, EXTENT_INITIALIZED))
+                       set_needs_init(array, s);
+       }
+       if (_set_range(&marks->im_tree, EXTENT_INITIALIZED, offset, length))
+               goto out_unlock;
+       for (s = normalize_up(offset + length, PAGE_CACHE_SECTORS);
+            s < end; s += PAGE_CACHE_SECTORS) {
+               dprintk("%s post-area pages\n", __func__);
+               if (!_has_tag(&marks->im_tree, s, EXTENT_INITIALIZED))
+                       set_needs_init(array, s);
+       }
+
+       spin_unlock(&marks->im_lock);
+
+       if (pages) {
+               if (array[0] == ~0) {
+                       kfree(array);
+                       *pages = NULL;
+               } else
+                       *pages = array;
+       }
+       return 0;
+
+ out_unlock:
+       spin_unlock(&marks->im_lock);
+ outerr:
+       if (pages) {
+               kfree(array);
+               *pages = NULL;
+       }
+       return -ENOMEM;
+}
+
+/* Marks sectors in [offest, offset+length) as having been written to disk.
+ * All lengths should be block aligned.
+ */
+static int mark_written_sectors(struct pnfs_inval_markings *marks,
+                               sector_t offset, sector_t length)
+{
+       int status;
+
+       dprintk("%s(offset=%llu,len=%llu) enter\n", __func__,
+               (u64)offset, (u64)length);
+       spin_lock(&marks->im_lock);
+       status = _set_range(&marks->im_tree, EXTENT_WRITTEN, offset, length);
+       spin_unlock(&marks->im_lock);
+       return status;
+}
+
+static void print_short_extent(struct pnfs_block_short_extent *be)
+{
+       dprintk("PRINT SHORT EXTENT extent %p\n", be);
+       if (be) {
+               dprintk("        be_f_offset %llu\n", (u64)be->bse_f_offset);
+               dprintk("        be_length   %llu\n", (u64)be->bse_length);
+       }
+}
+
+static void print_clist(struct list_head *list, unsigned int count)
+{
+       struct pnfs_block_short_extent *be;
+       unsigned int i = 0;
+
+       ifdebug(FACILITY) {
+               printk(KERN_DEBUG "****************\n");
+               printk(KERN_DEBUG "Extent list looks like:\n");
+               list_for_each_entry(be, list, bse_node) {
+                       i++;
+                       print_short_extent(be);
+               }
+               if (i != count)
+                       printk(KERN_DEBUG "\n\nExpected %u entries\n\n\n", count);
+               printk(KERN_DEBUG "****************\n");
+       }
+}
+
+/* Note: In theory, we should do more checking that devid's match between
+ * old and new, but if they don't, the lists are too corrupt to salvage anyway.
+ */
+/* Note this is very similar to bl_add_merge_extent */
+static void add_to_commitlist(struct pnfs_block_layout *bl,
+                             struct pnfs_block_short_extent *new)
+{
+       struct list_head *clist = &bl->bl_commit;
+       struct pnfs_block_short_extent *old, *save;
+       sector_t end = new->bse_f_offset + new->bse_length;
+
+       dprintk("%s enter\n", __func__);
+       print_short_extent(new);
+       print_clist(clist, bl->bl_count);
+       bl->bl_count++;
+       /* Scan for proper place to insert, extending new to the left
+        * as much as possible.
+        */
+       list_for_each_entry_safe(old, save, clist, bse_node) {
+               if (new->bse_f_offset < old->bse_f_offset)
+                       break;
+               if (end <= old->bse_f_offset + old->bse_length) {
+                       /* Range is already in list */
+                       bl->bl_count--;
+                       kfree(new);
+                       return;
+               } else if (new->bse_f_offset <=
+                               old->bse_f_offset + old->bse_length) {
+                       /* new overlaps or abuts existing be */
+                       if (new->bse_mdev == old->bse_mdev) {
+                               /* extend new to fully replace old */
+                               new->bse_length += new->bse_f_offset -
+                                               old->bse_f_offset;
+                               new->bse_f_offset = old->bse_f_offset;
+                               list_del(&old->bse_node);
+                               bl->bl_count--;
+                               kfree(old);
+                       }
+               }
+       }
+       /* Note that if we never hit the above break, old will not point to a
+        * valid extent.  However, in that case &old->bse_node==list.
+        */
+       list_add_tail(&new->bse_node, &old->bse_node);
+       /* Scan forward for overlaps.  If we find any, extend new and
+        * remove the overlapped extent.
+        */
+       old = list_prepare_entry(new, clist, bse_node);
+       list_for_each_entry_safe_continue(old, save, clist, bse_node) {
+               if (end < old->bse_f_offset)
+                       break;
+               /* new overlaps or abuts old */
+               if (new->bse_mdev == old->bse_mdev) {
+                       if (end < old->bse_f_offset + old->bse_length) {
+                               /* extend new to fully cover old */
+                               end = old->bse_f_offset + old->bse_length;
+                               new->bse_length = end - new->bse_f_offset;
+                       }
+                       list_del(&old->bse_node);
+                       bl->bl_count--;
+                       kfree(old);
+               }
+       }
+       dprintk("%s: after merging\n", __func__);
+       print_clist(clist, bl->bl_count);
+}
+
+/* Note the range described by offset, length is guaranteed to be contained
+ * within be.
+ */
+int bl_mark_for_commit(struct pnfs_block_extent *be,
+                   sector_t offset, sector_t length)
+{
+       sector_t new_end, end = offset + length;
+       struct pnfs_block_short_extent *new;
+       struct pnfs_block_layout *bl = container_of(be->be_inval,
+                                                   struct pnfs_block_layout,
+                                                   bl_inval);
+
+       new = kmalloc(sizeof(*new), GFP_NOFS);
+       if (!new)
+               return -ENOMEM;
+
+       mark_written_sectors(be->be_inval, offset, length);
+       /* We want to add the range to commit list, but it must be
+        * block-normalized, and verified that the normalized range has
+        * been entirely written to disk.
+        */
+       new->bse_f_offset = offset;
+       offset = normalize(offset, bl->bl_blocksize);
+       if (offset < new->bse_f_offset) {
+               if (is_range_written(be->be_inval, offset, new->bse_f_offset))
+                       new->bse_f_offset = offset;
+               else
+                       new->bse_f_offset = offset + bl->bl_blocksize;
+       }
+       new_end = normalize_up(end, bl->bl_blocksize);
+       if (end < new_end) {
+               if (is_range_written(be->be_inval, end, new_end))
+                       end = new_end;
+               else
+                       end = new_end - bl->bl_blocksize;
+       }
+       if (end <= new->bse_f_offset) {
+               kfree(new);
+               return 0;
+       }
+       new->bse_length = end - new->bse_f_offset;
+       new->bse_devid = be->be_devid;
+       new->bse_mdev = be->be_mdev;
+
+       spin_lock(&bl->bl_ext_lock);
+       /* new will be freed, either by add_to_commitlist if it decides not
+        * to use it, or after LAYOUTCOMMIT uses it in the commitlist.
+        */
+       add_to_commitlist(bl, new);
+       spin_unlock(&bl->bl_ext_lock);
+       return 0;
+}
+
+static void print_bl_extent(struct pnfs_block_extent *be)
+{
+       dprintk("PRINT EXTENT extent %p\n", be);
+       if (be) {
+               dprintk("        be_f_offset %llu\n", (u64)be->be_f_offset);
+               dprintk("        be_length   %llu\n", (u64)be->be_length);
+               dprintk("        be_v_offset %llu\n", (u64)be->be_v_offset);
+               dprintk("        be_state    %d\n", be->be_state);
+       }
+}
+
+static void
+destroy_extent(struct kref *kref)
+{
+       struct pnfs_block_extent *be;
+
+       be = container_of(kref, struct pnfs_block_extent, be_refcnt);
+       dprintk("%s be=%p\n", __func__, be);
+       kfree(be);
+}
+
+void
+bl_put_extent(struct pnfs_block_extent *be)
+{
+       if (be) {
+               dprintk("%s enter %p (%i)\n", __func__, be,
+                       atomic_read(&be->be_refcnt.refcount));
+               kref_put(&be->be_refcnt, destroy_extent);
+       }
+}
+
+struct pnfs_block_extent *bl_alloc_extent(void)
+{
+       struct pnfs_block_extent *be;
+
+       be = kmalloc(sizeof(struct pnfs_block_extent), GFP_NOFS);
+       if (!be)
+               return NULL;
+       INIT_LIST_HEAD(&be->be_node);
+       kref_init(&be->be_refcnt);
+       be->be_inval = NULL;
+       return be;
+}
+
+static void print_elist(struct list_head *list)
+{
+       struct pnfs_block_extent *be;
+       dprintk("****************\n");
+       dprintk("Extent list looks like:\n");
+       list_for_each_entry(be, list, be_node) {
+               print_bl_extent(be);
+       }
+       dprintk("****************\n");
+}
+
+static inline int
+extents_consistent(struct pnfs_block_extent *old, struct pnfs_block_extent *new)
+{
+       /* Note this assumes new->be_f_offset >= old->be_f_offset */
+       return (new->be_state == old->be_state) &&
+               ((new->be_state == PNFS_BLOCK_NONE_DATA) ||
+                ((new->be_v_offset - old->be_v_offset ==
+                  new->be_f_offset - old->be_f_offset) &&
+                 new->be_mdev == old->be_mdev));
+}
+
+/* Adds new to appropriate list in bl, modifying new and removing existing
+ * extents as appropriate to deal with overlaps.
+ *
+ * See bl_find_get_extent for list constraints.
+ *
+ * Refcount on new is already set.  If end up not using it, or error out,
+ * need to put the reference.
+ *
+ * bl->bl_ext_lock is held by caller.
+ */
+int
+bl_add_merge_extent(struct pnfs_block_layout *bl,
+                    struct pnfs_block_extent *new)
+{
+       struct pnfs_block_extent *be, *tmp;
+       sector_t end = new->be_f_offset + new->be_length;
+       struct list_head *list;
+
+       dprintk("%s enter with be=%p\n", __func__, new);
+       print_bl_extent(new);
+       list = &bl->bl_extents[bl_choose_list(new->be_state)];
+       print_elist(list);
+
+       /* Scan for proper place to insert, extending new to the left
+        * as much as possible.
+        */
+       list_for_each_entry_safe_reverse(be, tmp, list, be_node) {
+               if (new->be_f_offset >= be->be_f_offset + be->be_length)
+                       break;
+               if (new->be_f_offset >= be->be_f_offset) {
+                       if (end <= be->be_f_offset + be->be_length) {
+                               /* new is a subset of existing be*/
+                               if (extents_consistent(be, new)) {
+                                       dprintk("%s: new is subset, ignoring\n",
+                                               __func__);
+                                       bl_put_extent(new);
+                                       return 0;
+                               } else {
+                                       goto out_err;
+                               }
+                       } else {
+                               /* |<--   be   -->|
+                                *          |<--   new   -->| */
+                               if (extents_consistent(be, new)) {
+                                       /* extend new to fully replace be */
+                                       new->be_length += new->be_f_offset -
+                                               be->be_f_offset;
+                                       new->be_f_offset = be->be_f_offset;
+                                       new->be_v_offset = be->be_v_offset;
+                                       dprintk("%s: removing %p\n", __func__, be);
+                                       list_del(&be->be_node);
+                                       bl_put_extent(be);
+                               } else {
+                                       goto out_err;
+                               }
+                       }
+               } else if (end >= be->be_f_offset + be->be_length) {
+                       /* new extent overlap existing be */
+                       if (extents_consistent(be, new)) {
+                               /* extend new to fully replace be */
+                               dprintk("%s: removing %p\n", __func__, be);
+                               list_del(&be->be_node);
+                               bl_put_extent(be);
+                       } else {
+                               goto out_err;
+                       }
+               } else if (end > be->be_f_offset) {
+                       /*           |<--   be   -->|
+                        *|<--   new   -->| */
+                       if (extents_consistent(new, be)) {
+                               /* extend new to fully replace be */
+                               new->be_length += be->be_f_offset + be->be_length -
+                                       new->be_f_offset - new->be_length;
+                               dprintk("%s: removing %p\n", __func__, be);
+                               list_del(&be->be_node);
+                               bl_put_extent(be);
+                       } else {
+                               goto out_err;
+                       }
+               }
+       }
+       /* Note that if we never hit the above break, be will not point to a
+        * valid extent.  However, in that case &be->be_node==list.
+        */
+       list_add(&new->be_node, &be->be_node);
+       dprintk("%s: inserting new\n", __func__);
+       print_elist(list);
+       /* FIXME - The per-list consistency checks have all been done,
+        * should now check cross-list consistency.
+        */
+       return 0;
+
+ out_err:
+       bl_put_extent(new);
+       return -EIO;
+}
+
+/* Returns extent, or NULL.  If a second READ extent exists, it is returned
+ * in cow_read, if given.
+ *
+ * The extents are kept in two seperate ordered lists, one for READ and NONE,
+ * one for READWRITE and INVALID.  Within each list, we assume:
+ * 1. Extents are ordered by file offset.
+ * 2. For any given isect, there is at most one extents that matches.
+ */
+struct pnfs_block_extent *
+bl_find_get_extent(struct pnfs_block_layout *bl, sector_t isect,
+           struct pnfs_block_extent **cow_read)
+{
+       struct pnfs_block_extent *be, *cow, *ret;
+       int i;
+
+       dprintk("%s enter with isect %llu\n", __func__, (u64)isect);
+       cow = ret = NULL;
+       spin_lock(&bl->bl_ext_lock);
+       for (i = 0; i < EXTENT_LISTS; i++) {
+               list_for_each_entry_reverse(be, &bl->bl_extents[i], be_node) {
+                       if (isect >= be->be_f_offset + be->be_length)
+                               break;
+                       if (isect >= be->be_f_offset) {
+                               /* We have found an extent */
+                               dprintk("%s Get %p (%i)\n", __func__, be,
+                                       atomic_read(&be->be_refcnt.refcount));
+                               kref_get(&be->be_refcnt);
+                               if (!ret)
+                                       ret = be;
+                               else if (be->be_state != PNFS_BLOCK_READ_DATA)
+                                       bl_put_extent(be);
+                               else
+                                       cow = be;
+                               break;
+                       }
+               }
+               if (ret &&
+                   (!cow_read || ret->be_state != PNFS_BLOCK_INVALID_DATA))
+                       break;
+       }
+       spin_unlock(&bl->bl_ext_lock);
+       if (cow_read)
+               *cow_read = cow;
+       print_bl_extent(ret);
+       return ret;
+}
+
+/* Similar to bl_find_get_extent, but called with lock held, and ignores cow */
+static struct pnfs_block_extent *
+bl_find_get_extent_locked(struct pnfs_block_layout *bl, sector_t isect)
+{
+       struct pnfs_block_extent *be, *ret = NULL;
+       int i;
+
+       dprintk("%s enter with isect %llu\n", __func__, (u64)isect);
+       for (i = 0; i < EXTENT_LISTS; i++) {
+               if (ret)
+                       break;
+               list_for_each_entry_reverse(be, &bl->bl_extents[i], be_node) {
+                       if (isect >= be->be_f_offset + be->be_length)
+                               break;
+                       if (isect >= be->be_f_offset) {
+                               /* We have found an extent */
+                               dprintk("%s Get %p (%i)\n", __func__, be,
+                                       atomic_read(&be->be_refcnt.refcount));
+                               kref_get(&be->be_refcnt);
+                               ret = be;
+                               break;
+                       }
+               }
+       }
+       print_bl_extent(ret);
+       return ret;
+}
+
+int
+encode_pnfs_block_layoutupdate(struct pnfs_block_layout *bl,
+                              struct xdr_stream *xdr,
+                              const struct nfs4_layoutcommit_args *arg)
+{
+       struct pnfs_block_short_extent *lce, *save;
+       unsigned int count = 0;
+       __be32 *p, *xdr_start;
+
+       dprintk("%s enter\n", __func__);
+       /* BUG - creation of bl_commit is buggy - need to wait for
+        * entire block to be marked WRITTEN before it can be added.
+        */
+       spin_lock(&bl->bl_ext_lock);
+       /* Want to adjust for possible truncate */
+       /* We now want to adjust argument range */
+
+       /* XDR encode the ranges found */
+       xdr_start = xdr_reserve_space(xdr, 8);
+       if (!xdr_start)
+               goto out;
+       list_for_each_entry_safe(lce, save, &bl->bl_commit, bse_node) {
+               p = xdr_reserve_space(xdr, 7 * 4 + sizeof(lce->bse_devid.data));
+               if (!p)
+                       break;
+               p = xdr_encode_opaque_fixed(p, lce->bse_devid.data, NFS4_DEVICEID4_SIZE);
+               p = xdr_encode_hyper(p, lce->bse_f_offset << SECTOR_SHIFT);
+               p = xdr_encode_hyper(p, lce->bse_length << SECTOR_SHIFT);
+               p = xdr_encode_hyper(p, 0LL);
+               *p++ = cpu_to_be32(PNFS_BLOCK_READWRITE_DATA);
+               list_del(&lce->bse_node);
+               list_add_tail(&lce->bse_node, &bl->bl_committing);
+               bl->bl_count--;
+               count++;
+       }
+       xdr_start[0] = cpu_to_be32((xdr->p - xdr_start - 1) * 4);
+       xdr_start[1] = cpu_to_be32(count);
+out:
+       spin_unlock(&bl->bl_ext_lock);
+       dprintk("%s found %i ranges\n", __func__, count);
+       return 0;
+}
+
+/* Helper function to set_to_rw that initialize a new extent */
+static void
+_prep_new_extent(struct pnfs_block_extent *new,
+                struct pnfs_block_extent *orig,
+                sector_t offset, sector_t length, int state)
+{
+       kref_init(&new->be_refcnt);
+       /* don't need to INIT_LIST_HEAD(&new->be_node) */
+       memcpy(&new->be_devid, &orig->be_devid, sizeof(struct nfs4_deviceid));
+       new->be_mdev = orig->be_mdev;
+       new->be_f_offset = offset;
+       new->be_length = length;
+       new->be_v_offset = orig->be_v_offset - orig->be_f_offset + offset;
+       new->be_state = state;
+       new->be_inval = orig->be_inval;
+}
+
+/* Tries to merge be with extent in front of it in list.
+ * Frees storage if not used.
+ */
+static struct pnfs_block_extent *
+_front_merge(struct pnfs_block_extent *be, struct list_head *head,
+            struct pnfs_block_extent *storage)
+{
+       struct pnfs_block_extent *prev;
+
+       if (!storage)
+               goto no_merge;
+       if (&be->be_node == head || be->be_node.prev == head)
+               goto no_merge;
+       prev = list_entry(be->be_node.prev, struct pnfs_block_extent, be_node);
+       if ((prev->be_f_offset + prev->be_length != be->be_f_offset) ||
+           !extents_consistent(prev, be))
+               goto no_merge;
+       _prep_new_extent(storage, prev, prev->be_f_offset,
+                        prev->be_length + be->be_length, prev->be_state);
+       list_replace(&prev->be_node, &storage->be_node);
+       bl_put_extent(prev);
+       list_del(&be->be_node);
+       bl_put_extent(be);
+       return storage;
+
+ no_merge:
+       kfree(storage);
+       return be;
+}
+
+static u64
+set_to_rw(struct pnfs_block_layout *bl, u64 offset, u64 length)
+{
+       u64 rv = offset + length;
+       struct pnfs_block_extent *be, *e1, *e2, *e3, *new, *old;
+       struct pnfs_block_extent *children[3];
+       struct pnfs_block_extent *merge1 = NULL, *merge2 = NULL;
+       int i = 0, j;
+
+       dprintk("%s(%llu, %llu)\n", __func__, offset, length);
+       /* Create storage for up to three new extents e1, e2, e3 */
+       e1 = kmalloc(sizeof(*e1), GFP_ATOMIC);
+       e2 = kmalloc(sizeof(*e2), GFP_ATOMIC);
+       e3 = kmalloc(sizeof(*e3), GFP_ATOMIC);
+       /* BUG - we are ignoring any failure */
+       if (!e1 || !e2 || !e3)
+               goto out_nosplit;
+
+       spin_lock(&bl->bl_ext_lock);
+       be = bl_find_get_extent_locked(bl, offset);
+       rv = be->be_f_offset + be->be_length;
+       if (be->be_state != PNFS_BLOCK_INVALID_DATA) {
+               spin_unlock(&bl->bl_ext_lock);
+               goto out_nosplit;
+       }
+       /* Add e* to children, bumping e*'s krefs */
+       if (be->be_f_offset != offset) {
+               _prep_new_extent(e1, be, be->be_f_offset,
+                                offset - be->be_f_offset,
+                                PNFS_BLOCK_INVALID_DATA);
+               children[i++] = e1;
+               print_bl_extent(e1);
+       } else
+               merge1 = e1;
+       _prep_new_extent(e2, be, offset,
+                        min(length, be->be_f_offset + be->be_length - offset),
+                        PNFS_BLOCK_READWRITE_DATA);
+       children[i++] = e2;
+       print_bl_extent(e2);
+       if (offset + length < be->be_f_offset + be->be_length) {
+               _prep_new_extent(e3, be, e2->be_f_offset + e2->be_length,
+                                be->be_f_offset + be->be_length -
+                                offset - length,
+                                PNFS_BLOCK_INVALID_DATA);
+               children[i++] = e3;
+               print_bl_extent(e3);
+       } else
+               merge2 = e3;
+
+       /* Remove be from list, and insert the e* */
+       /* We don't get refs on e*, since this list is the base reference
+        * set when init'ed.
+        */
+       if (i < 3)
+               children[i] = NULL;
+       new = children[0];
+       list_replace(&be->be_node, &new->be_node);
+       bl_put_extent(be);
+       new = _front_merge(new, &bl->bl_extents[RW_EXTENT], merge1);
+       for (j = 1; j < i; j++) {
+               old = new;
+               new = children[j];
+               list_add(&new->be_node, &old->be_node);
+       }
+       if (merge2) {
+               /* This is a HACK, should just create a _back_merge function */
+               new = list_entry(new->be_node.next,
+                                struct pnfs_block_extent, be_node);
+               new = _front_merge(new, &bl->bl_extents[RW_EXTENT], merge2);
+       }
+       spin_unlock(&bl->bl_ext_lock);
+
+       /* Since we removed the base reference above, be is now scheduled for
+        * destruction.
+        */
+       bl_put_extent(be);
+       dprintk("%s returns %llu after split\n", __func__, rv);
+       return rv;
+
+ out_nosplit:
+       kfree(e1);
+       kfree(e2);
+       kfree(e3);
+       dprintk("%s returns %llu without splitting\n", __func__, rv);
+       return rv;
+}
+
+void
+clean_pnfs_block_layoutupdate(struct pnfs_block_layout *bl,
+                             const struct nfs4_layoutcommit_args *arg,
+                             int status)
+{
+       struct pnfs_block_short_extent *lce, *save;
+
+       dprintk("%s status %d\n", __func__, status);
+       list_for_each_entry_safe(lce, save, &bl->bl_committing, bse_node) {
+               if (likely(!status)) {
+                       u64 offset = lce->bse_f_offset;
+                       u64 end = offset + lce->bse_length;
+
+                       do {
+                               offset = set_to_rw(bl, offset, end - offset);
+                       } while (offset < end);
+                       list_del(&lce->bse_node);
+
+                       kfree(lce);
+               } else {
+                       list_del(&lce->bse_node);
+                       spin_lock(&bl->bl_ext_lock);
+                       add_to_commitlist(bl, lce);
+                       spin_unlock(&bl->bl_ext_lock);
+               }
+       }
+}
index b257383..07df5f1 100644 (file)
@@ -38,6 +38,7 @@ enum nfs4_callback_opnum {
 struct cb_process_state {
        __be32                  drc_status;
        struct nfs_client       *clp;
+       int                     slotid;
 };
 
 struct cb_compound_hdr_arg {
@@ -166,7 +167,6 @@ extern unsigned nfs4_callback_layoutrecall(
        void *dummy, struct cb_process_state *cps);
 
 extern void nfs4_check_drain_bc_complete(struct nfs4_session *ses);
-extern void nfs4_cb_take_slot(struct nfs_client *clp);
 
 struct cb_devicenotifyitem {
        uint32_t                cbd_notify_type;
index 74780f9..43926ad 100644 (file)
@@ -348,7 +348,7 @@ validate_seqid(struct nfs4_slot_table *tbl, struct cb_sequenceargs * args)
        /* Normal */
        if (likely(args->csa_sequenceid == slot->seq_nr + 1)) {
                slot->seq_nr++;
-               return htonl(NFS4_OK);
+               goto out_ok;
        }
 
        /* Replay */
@@ -367,11 +367,14 @@ validate_seqid(struct nfs4_slot_table *tbl, struct cb_sequenceargs * args)
        /* Wraparound */
        if (args->csa_sequenceid == 1 && (slot->seq_nr + 1) == 0) {
                slot->seq_nr = 1;
-               return htonl(NFS4_OK);
+               goto out_ok;
        }
 
        /* Misordered request */
        return htonl(NFS4ERR_SEQ_MISORDERED);
+out_ok:
+       tbl->highest_used_slotid = args->csa_slotid;
+       return htonl(NFS4_OK);
 }
 
 /*
@@ -433,26 +436,37 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
                              struct cb_sequenceres *res,
                              struct cb_process_state *cps)
 {
+       struct nfs4_slot_table *tbl;
        struct nfs_client *clp;
        int i;
        __be32 status = htonl(NFS4ERR_BADSESSION);
 
-       cps->clp = NULL;
-
        clp = nfs4_find_client_sessionid(args->csa_addr, &args->csa_sessionid);
        if (clp == NULL)
                goto out;
 
+       tbl = &clp->cl_session->bc_slot_table;
+
+       spin_lock(&tbl->slot_tbl_lock);
        /* state manager is resetting the session */
        if (test_bit(NFS4_SESSION_DRAINING, &clp->cl_session->session_state)) {
-               status = NFS4ERR_DELAY;
+               spin_unlock(&tbl->slot_tbl_lock);
+               status = htonl(NFS4ERR_DELAY);
+               /* Return NFS4ERR_BADSESSION if we're draining the session
+                * in order to reset it.
+                */
+               if (test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state))
+                       status = htonl(NFS4ERR_BADSESSION);
                goto out;
        }
 
        status = validate_seqid(&clp->cl_session->bc_slot_table, args);
+       spin_unlock(&tbl->slot_tbl_lock);
        if (status)
                goto out;
 
+       cps->slotid = args->csa_slotid;
+
        /*
         * Check for pending referring calls.  If a match is found, a
         * related callback was received before the response to the original
@@ -469,7 +483,6 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
        res->csr_slotid = args->csa_slotid;
        res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
        res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
-       nfs4_cb_take_slot(clp);
 
 out:
        cps->clp = clp; /* put in nfs4_callback_compound */
index c6c86a7..918ad64 100644 (file)
@@ -754,26 +754,15 @@ static void nfs4_callback_free_slot(struct nfs4_session *session)
         * Let the state manager know callback processing done.
         * A single slot, so highest used slotid is either 0 or -1
         */
-       tbl->highest_used_slotid--;
+       tbl->highest_used_slotid = -1;
        nfs4_check_drain_bc_complete(session);
        spin_unlock(&tbl->slot_tbl_lock);
 }
 
-static void nfs4_cb_free_slot(struct nfs_client *clp)
+static void nfs4_cb_free_slot(struct cb_process_state *cps)
 {
-       if (clp && clp->cl_session)
-               nfs4_callback_free_slot(clp->cl_session);
-}
-
-/* A single slot, so highest used slotid is either 0 or -1 */
-void nfs4_cb_take_slot(struct nfs_client *clp)
-{
-       struct nfs4_slot_table *tbl = &clp->cl_session->bc_slot_table;
-
-       spin_lock(&tbl->slot_tbl_lock);
-       tbl->highest_used_slotid++;
-       BUG_ON(tbl->highest_used_slotid != 0);
-       spin_unlock(&tbl->slot_tbl_lock);
+       if (cps->slotid != -1)
+               nfs4_callback_free_slot(cps->clp->cl_session);
 }
 
 #else /* CONFIG_NFS_V4_1 */
@@ -784,7 +773,7 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op)
        return htonl(NFS4ERR_MINOR_VERS_MISMATCH);
 }
 
-static void nfs4_cb_free_slot(struct nfs_client *clp)
+static void nfs4_cb_free_slot(struct cb_process_state *cps)
 {
 }
 #endif /* CONFIG_NFS_V4_1 */
@@ -866,6 +855,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
        struct cb_process_state cps = {
                .drc_status = 0,
                .clp = NULL,
+               .slotid = -1,
        };
        unsigned int nops = 0;
 
@@ -906,7 +896,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
 
        *hdr_res.status = status;
        *hdr_res.nops = htonl(nops);
-       nfs4_cb_free_slot(cps.clp);
+       nfs4_cb_free_slot(&cps);
        nfs_put_client(cps.clp);
        dprintk("%s: done, status = %u\n", __func__, ntohl(status));
        return rpc_success;
index 19ea7d9..5833fbb 100644 (file)
@@ -105,7 +105,7 @@ struct rpc_program nfs_program = {
        .nrvers                 = ARRAY_SIZE(nfs_version),
        .version                = nfs_version,
        .stats                  = &nfs_rpcstat,
-       .pipe_dir_name          = "/nfs",
+       .pipe_dir_name          = NFS_PIPE_DIRNAME,
 };
 
 struct rpc_stat nfs_rpcstat = {
@@ -904,7 +904,9 @@ error:
 /*
  * Load up the server record from information gained in an fsinfo record
  */
-static void nfs_server_set_fsinfo(struct nfs_server *server, struct nfs_fsinfo *fsinfo)
+static void nfs_server_set_fsinfo(struct nfs_server *server,
+                                 struct nfs_fh *mntfh,
+                                 struct nfs_fsinfo *fsinfo)
 {
        unsigned long max_rpc_payload;
 
@@ -934,7 +936,8 @@ static void nfs_server_set_fsinfo(struct nfs_server *server, struct nfs_fsinfo *
        if (server->wsize > NFS_MAX_FILE_IO_SIZE)
                server->wsize = NFS_MAX_FILE_IO_SIZE;
        server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-       set_pnfs_layoutdriver(server, fsinfo->layouttype);
+       server->pnfs_blksize = fsinfo->blksize;
+       set_pnfs_layoutdriver(server, mntfh, fsinfo->layouttype);
 
        server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL);
 
@@ -980,7 +983,7 @@ static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, str
        if (error < 0)
                goto out_error;
 
-       nfs_server_set_fsinfo(server, &fsinfo);
+       nfs_server_set_fsinfo(server, mntfh, &fsinfo);
 
        /* Get some general file system info */
        if (server->namelen == 0) {
index 57f578e..b238d95 100644 (file)
@@ -134,18 +134,19 @@ const struct inode_operations nfs4_dir_inode_operations = {
 
 #endif /* CONFIG_NFS_V4 */
 
-static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct rpc_cred *cred)
+static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir, struct rpc_cred *cred)
 {
        struct nfs_open_dir_context *ctx;
        ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
        if (ctx != NULL) {
                ctx->duped = 0;
+               ctx->attr_gencount = NFS_I(dir)->attr_gencount;
                ctx->dir_cookie = 0;
                ctx->dup_cookie = 0;
                ctx->cred = get_rpccred(cred);
-       } else
-               ctx = ERR_PTR(-ENOMEM);
-       return ctx;
+               return ctx;
+       }
+       return  ERR_PTR(-ENOMEM);
 }
 
 static void put_nfs_open_dir_context(struct nfs_open_dir_context *ctx)
@@ -173,7 +174,7 @@ nfs_opendir(struct inode *inode, struct file *filp)
        cred = rpc_lookup_cred();
        if (IS_ERR(cred))
                return PTR_ERR(cred);
-       ctx = alloc_nfs_open_dir_context(cred);
+       ctx = alloc_nfs_open_dir_context(inode, cred);
        if (IS_ERR(ctx)) {
                res = PTR_ERR(ctx);
                goto out;
@@ -323,7 +324,6 @@ int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descri
 {
        loff_t diff = desc->file->f_pos - desc->current_index;
        unsigned int index;
-       struct nfs_open_dir_context *ctx = desc->file->private_data;
 
        if (diff < 0)
                goto out_eof;
@@ -336,7 +336,6 @@ int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descri
        index = (unsigned int)diff;
        *desc->dir_cookie = array->array[index].cookie;
        desc->cache_entry_index = index;
-       ctx->duped = 0;
        return 0;
 out_eof:
        desc->eof = 1;
@@ -349,14 +348,34 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des
        int i;
        loff_t new_pos;
        int status = -EAGAIN;
-       struct nfs_open_dir_context *ctx = desc->file->private_data;
 
        for (i = 0; i < array->size; i++) {
                if (array->array[i].cookie == *desc->dir_cookie) {
+                       struct nfs_inode *nfsi = NFS_I(desc->file->f_path.dentry->d_inode);
+                       struct nfs_open_dir_context *ctx = desc->file->private_data;
+
                        new_pos = desc->current_index + i;
-                       if (new_pos < desc->file->f_pos) {
+                       if (ctx->attr_gencount != nfsi->attr_gencount
+                           || (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA))) {
+                               ctx->duped = 0;
+                               ctx->attr_gencount = nfsi->attr_gencount;
+                       } else if (new_pos < desc->file->f_pos) {
+                               if (ctx->duped > 0
+                                   && ctx->dup_cookie == *desc->dir_cookie) {
+                                       if (printk_ratelimit()) {
+                                               pr_notice("NFS: directory %s/%s contains a readdir loop."
+                                                               "Please contact your server vendor.  "
+                                                               "The file: %s has duplicate cookie %llu\n",
+                                                               desc->file->f_dentry->d_parent->d_name.name,
+                                                               desc->file->f_dentry->d_name.name,
+                                                               array->array[i].string.name,
+                                                               *desc->dir_cookie);
+                                       }
+                                       status = -ELOOP;
+                                       goto out;
+                               }
                                ctx->dup_cookie = *desc->dir_cookie;
-                               ctx->duped = 1;
+                               ctx->duped = -1;
                        }
                        desc->file->f_pos = new_pos;
                        desc->cache_entry_index = i;
@@ -368,6 +387,7 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des
                if (*desc->dir_cookie == array->last_cookie)
                        desc->eof = 1;
        }
+out:
        return status;
 }
 
@@ -740,19 +760,6 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
        struct nfs_cache_array *array = NULL;
        struct nfs_open_dir_context *ctx = file->private_data;
 
-       if (ctx->duped != 0 && ctx->dup_cookie == *desc->dir_cookie) {
-               if (printk_ratelimit()) {
-                       pr_notice("NFS: directory %s/%s contains a readdir loop.  "
-                               "Please contact your server vendor.  "
-                               "Offending cookie: %llu\n",
-                               file->f_dentry->d_parent->d_name.name,
-                               file->f_dentry->d_name.name,
-                               *desc->dir_cookie);
-               }
-               res = -ELOOP;
-               goto out;
-       }
-
        array = nfs_readdir_get_array(desc->page);
        if (IS_ERR(array)) {
                res = PTR_ERR(array);
@@ -774,6 +781,8 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
                        *desc->dir_cookie = array->array[i+1].cookie;
                else
                        *desc->dir_cookie = array->last_cookie;
+               if (ctx->duped != 0)
+                       ctx->duped = 1;
        }
        if (array->eof_index >= 0)
                desc->eof = 1;
@@ -805,6 +814,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
        struct page     *page = NULL;
        int             status;
        struct inode *inode = desc->file->f_path.dentry->d_inode;
+       struct nfs_open_dir_context *ctx = desc->file->private_data;
 
        dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for cookie %Lu\n",
                        (unsigned long long)*desc->dir_cookie);
@@ -818,6 +828,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
        desc->page_index = 0;
        desc->last_cookie = *desc->dir_cookie;
        desc->page = page;
+       ctx->duped = 0;
 
        status = nfs_readdir_xdr_to_array(desc, page, inode);
        if (status < 0)
index e49e731..7ef2397 100644 (file)
@@ -415,7 +415,7 @@ fail:
 }
 
 int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode,
-               mode_t mode)
+               umode_t mode)
 {
        struct posix_acl *dfacl, *acl;
        int error = 0;
index 38053d8..85f1690 100644 (file)
@@ -316,7 +316,7 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
                 int flags, struct nfs_open_context *ctx)
 {
        struct nfs3_createdata *data;
-       mode_t mode = sattr->ia_mode;
+       umode_t mode = sattr->ia_mode;
        int status = -ENOMEM;
 
        dprintk("NFS call  create %s\n", dentry->d_name.name);
@@ -562,7 +562,7 @@ static int
 nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
 {
        struct nfs3_createdata *data;
-       int mode = sattr->ia_mode;
+       umode_t mode = sattr->ia_mode;
        int status = -ENOMEM;
 
        dprintk("NFS call  mkdir %s\n", dentry->d_name.name);
@@ -681,7 +681,7 @@ nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
                dev_t rdev)
 {
        struct nfs3_createdata *data;
-       mode_t mode = sattr->ia_mode;
+       umode_t mode = sattr->ia_mode;
        int status = -ENOMEM;
 
        dprintk("NFS call  mknod %s %u:%u\n", dentry->d_name.name,
index 1909ee8..1ec1a85 100644 (file)
@@ -318,7 +318,7 @@ extern const struct nfs4_minor_version_ops *nfs_v4_minor_ops[];
 extern const u32 nfs4_fattr_bitmap[2];
 extern const u32 nfs4_statfs_bitmap[2];
 extern const u32 nfs4_pathconf_bitmap[2];
-extern const u32 nfs4_fsinfo_bitmap[2];
+extern const u32 nfs4_fsinfo_bitmap[3];
 extern const u32 nfs4_fs_locations_bitmap[2];
 
 /* nfs4renewd.c */
index be93a62..e8915d4 100644 (file)
@@ -170,7 +170,7 @@ filelayout_set_layoutcommit(struct nfs_write_data *wdata)
 
        pnfs_set_layoutcommit(wdata);
        dprintk("%s ionde %lu pls_end_pos %lu\n", __func__, wdata->inode->i_ino,
-               (unsigned long) wdata->lseg->pls_end_pos);
+               (unsigned long) NFS_I(wdata->inode)->layout->plh_lwb);
 }
 
 /*
index 079614d..8c77039 100644 (file)
@@ -140,12 +140,13 @@ const u32 nfs4_pathconf_bitmap[2] = {
        0
 };
 
-const u32 nfs4_fsinfo_bitmap[2] = { FATTR4_WORD0_MAXFILESIZE
+const u32 nfs4_fsinfo_bitmap[3] = { FATTR4_WORD0_MAXFILESIZE
                        | FATTR4_WORD0_MAXREAD
                        | FATTR4_WORD0_MAXWRITE
                        | FATTR4_WORD0_LEASE_TIME,
                        FATTR4_WORD1_TIME_DELTA
-                       | FATTR4_WORD1_FS_LAYOUT_TYPES
+                       | FATTR4_WORD1_FS_LAYOUT_TYPES,
+                       FATTR4_WORD2_LAYOUT_BLKSIZE
 };
 
 const u32 nfs4_fs_locations_bitmap[2] = {
@@ -5834,6 +5835,54 @@ int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp)
        return status;
 }
 
+/*
+ * Retrieve the list of Data Server devices from the MDS.
+ */
+static int _nfs4_getdevicelist(struct nfs_server *server,
+                                   const struct nfs_fh *fh,
+                                   struct pnfs_devicelist *devlist)
+{
+       struct nfs4_getdevicelist_args args = {
+               .fh = fh,
+               .layoutclass = server->pnfs_curr_ld->id,
+       };
+       struct nfs4_getdevicelist_res res = {
+               .devlist = devlist,
+       };
+       struct rpc_message msg = {
+               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETDEVICELIST],
+               .rpc_argp = &args,
+               .rpc_resp = &res,
+       };
+       int status;
+
+       dprintk("--> %s\n", __func__);
+       status = nfs4_call_sync(server->client, server, &msg, &args.seq_args,
+                               &res.seq_res, 0);
+       dprintk("<-- %s status=%d\n", __func__, status);
+       return status;
+}
+
+int nfs4_proc_getdevicelist(struct nfs_server *server,
+                           const struct nfs_fh *fh,
+                           struct pnfs_devicelist *devlist)
+{
+       struct nfs4_exception exception = { };
+       int err;
+
+       do {
+               err = nfs4_handle_exception(server,
+                               _nfs4_getdevicelist(server, fh, devlist),
+                               &exception);
+       } while (exception.retry);
+
+       dprintk("%s: err=%d, num_devs=%u\n", __func__,
+               err, devlist->num_devs);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(nfs4_proc_getdevicelist);
+
 static int
 _nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev)
 {
@@ -5912,9 +5961,16 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata)
 static void nfs4_layoutcommit_release(void *calldata)
 {
        struct nfs4_layoutcommit_data *data = calldata;
+       struct pnfs_layout_segment *lseg, *tmp;
 
+       pnfs_cleanup_layoutcommit(data);
        /* Matched by references in pnfs_set_layoutcommit */
-       put_lseg(data->lseg);
+       list_for_each_entry_safe(lseg, tmp, &data->lseg_list, pls_lc_list) {
+               list_del_init(&lseg->pls_lc_list);
+               if (test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT,
+                                      &lseg->pls_flags))
+                       put_lseg(lseg);
+       }
        put_rpccred(data->cred);
        kfree(data);
 }
index c191a9b..1dce12f 100644 (file)
@@ -113,7 +113,11 @@ static int nfs4_stat_to_errno(int);
 #define encode_restorefh_maxsz  (op_encode_hdr_maxsz)
 #define decode_restorefh_maxsz  (op_decode_hdr_maxsz)
 #define encode_fsinfo_maxsz    (encode_getattr_maxsz)
-#define decode_fsinfo_maxsz    (op_decode_hdr_maxsz + 15)
+/* The 5 accounts for the PNFS attributes, and assumes that at most three
+ * layout types will be returned.
+ */
+#define decode_fsinfo_maxsz    (op_decode_hdr_maxsz + \
+                                nfs4_fattr_bitmap_maxsz + 4 + 8 + 5)
 #define encode_renew_maxsz     (op_encode_hdr_maxsz + 3)
 #define decode_renew_maxsz     (op_decode_hdr_maxsz)
 #define encode_setclientid_maxsz \
@@ -314,6 +318,17 @@ static int nfs4_stat_to_errno(int);
                                XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5)
 #define encode_reclaim_complete_maxsz  (op_encode_hdr_maxsz + 4)
 #define decode_reclaim_complete_maxsz  (op_decode_hdr_maxsz + 4)
+#define encode_getdevicelist_maxsz (op_encode_hdr_maxsz + 4 + \
+                               encode_verifier_maxsz)
+#define decode_getdevicelist_maxsz (op_decode_hdr_maxsz + \
+                               2 /* nfs_cookie4 gdlr_cookie */ + \
+                               decode_verifier_maxsz \
+                                 /* verifier4 gdlr_verifier */ + \
+                               1 /* gdlr_deviceid_list count */ + \
+                               XDR_QUADLEN(NFS4_PNFS_GETDEVLIST_MAXNUM * \
+                                           NFS4_DEVICEID4_SIZE) \
+                                 /* gdlr_deviceid_list */ + \
+                               1 /* bool gdlr_eof */)
 #define encode_getdeviceinfo_maxsz (op_encode_hdr_maxsz + 4 + \
                                XDR_QUADLEN(NFS4_DEVICEID4_SIZE))
 #define decode_getdeviceinfo_maxsz (op_decode_hdr_maxsz + \
@@ -748,6 +763,14 @@ static int nfs4_stat_to_errno(int);
 #define NFS4_dec_reclaim_complete_sz   (compound_decode_hdr_maxsz + \
                                         decode_sequence_maxsz + \
                                         decode_reclaim_complete_maxsz)
+#define NFS4_enc_getdevicelist_sz (compound_encode_hdr_maxsz + \
+                               encode_sequence_maxsz + \
+                               encode_putfh_maxsz + \
+                               encode_getdevicelist_maxsz)
+#define NFS4_dec_getdevicelist_sz (compound_decode_hdr_maxsz + \
+                               decode_sequence_maxsz + \
+                               decode_putfh_maxsz + \
+                               decode_getdevicelist_maxsz)
 #define NFS4_enc_getdeviceinfo_sz (compound_encode_hdr_maxsz +    \
                                encode_sequence_maxsz +\
                                encode_getdeviceinfo_maxsz)
@@ -1104,6 +1127,35 @@ static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm
        hdr->replen += decode_getattr_maxsz;
 }
 
+static void
+encode_getattr_three(struct xdr_stream *xdr,
+                    uint32_t bm0, uint32_t bm1, uint32_t bm2,
+                    struct compound_hdr *hdr)
+{
+       __be32 *p;
+
+       p = reserve_space(xdr, 4);
+       *p = cpu_to_be32(OP_GETATTR);
+       if (bm2) {
+               p = reserve_space(xdr, 16);
+               *p++ = cpu_to_be32(3);
+               *p++ = cpu_to_be32(bm0);
+               *p++ = cpu_to_be32(bm1);
+               *p = cpu_to_be32(bm2);
+       } else if (bm1) {
+               p = reserve_space(xdr, 12);
+               *p++ = cpu_to_be32(2);
+               *p++ = cpu_to_be32(bm0);
+               *p = cpu_to_be32(bm1);
+       } else {
+               p = reserve_space(xdr, 8);
+               *p++ = cpu_to_be32(1);
+               *p = cpu_to_be32(bm0);
+       }
+       hdr->nops++;
+       hdr->replen += decode_getattr_maxsz;
+}
+
 static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
 {
        encode_getattr_two(xdr, bitmask[0] & nfs4_fattr_bitmap[0],
@@ -1112,8 +1164,11 @@ static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct c
 
 static void encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
 {
-       encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0],
-                          bitmask[1] & nfs4_fsinfo_bitmap[1], hdr);
+       encode_getattr_three(xdr,
+                            bitmask[0] & nfs4_fsinfo_bitmap[0],
+                            bitmask[1] & nfs4_fsinfo_bitmap[1],
+                            bitmask[2] & nfs4_fsinfo_bitmap[2],
+                            hdr);
 }
 
 static void encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
@@ -1854,6 +1909,26 @@ static void encode_sequence(struct xdr_stream *xdr,
 }
 
 #ifdef CONFIG_NFS_V4_1
+static void
+encode_getdevicelist(struct xdr_stream *xdr,
+                    const struct nfs4_getdevicelist_args *args,
+                    struct compound_hdr *hdr)
+{
+       __be32 *p;
+       nfs4_verifier dummy = {
+               .data = "dummmmmy",
+       };
+
+       p = reserve_space(xdr, 20);
+       *p++ = cpu_to_be32(OP_GETDEVICELIST);
+       *p++ = cpu_to_be32(args->layoutclass);
+       *p++ = cpu_to_be32(NFS4_PNFS_GETDEVLIST_MAXNUM);
+       xdr_encode_hyper(p, 0ULL);                          /* cookie */
+       encode_nfs4_verifier(xdr, &dummy);
+       hdr->nops++;
+       hdr->replen += decode_getdevicelist_maxsz;
+}
+
 static void
 encode_getdeviceinfo(struct xdr_stream *xdr,
                     const struct nfs4_getdeviceinfo_args *args,
@@ -1916,7 +1991,7 @@ encode_layoutcommit(struct xdr_stream *xdr,
        *p++ = cpu_to_be32(OP_LAYOUTCOMMIT);
        /* Only whole file layouts */
        p = xdr_encode_hyper(p, 0); /* offset */
-       p = xdr_encode_hyper(p, NFS4_MAX_UINT64); /* length */
+       p = xdr_encode_hyper(p, args->lastbytewritten + 1);     /* length */
        *p++ = cpu_to_be32(0); /* reclaim */
        p = xdr_encode_opaque_fixed(p, args->stateid.data, NFS4_STATEID_SIZE);
        *p++ = cpu_to_be32(1); /* newoffset = TRUE */
@@ -2604,7 +2679,7 @@ static void nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req,
        struct compound_hdr hdr = {
                .nops   = 0,
        };
-       const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 };
+       const u32 lease_bitmap[3] = { FATTR4_WORD0_LEASE_TIME };
 
        encode_compound_hdr(xdr, req, &hdr);
        encode_setclientid_confirm(xdr, arg, &hdr);
@@ -2748,7 +2823,7 @@ static void nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req,
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->la_seq_args),
        };
-       const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 };
+       const u32 lease_bitmap[3] = { FATTR4_WORD0_LEASE_TIME };
 
        encode_compound_hdr(xdr, req, &hdr);
        encode_sequence(xdr, &args->la_seq_args, &hdr);
@@ -2774,6 +2849,24 @@ static void nfs4_xdr_enc_reclaim_complete(struct rpc_rqst *req,
        encode_nops(&hdr);
 }
 
+/*
+ * Encode GETDEVICELIST request
+ */
+static void nfs4_xdr_enc_getdevicelist(struct rpc_rqst *req,
+                                      struct xdr_stream *xdr,
+                                      struct nfs4_getdevicelist_args *args)
+{
+       struct compound_hdr hdr = {
+               .minorversion = nfs4_xdr_minorversion(&args->seq_args),
+       };
+
+       encode_compound_hdr(xdr, req, &hdr);
+       encode_sequence(xdr, &args->seq_args, &hdr);
+       encode_putfh(xdr, args->fh, &hdr);
+       encode_getdevicelist(xdr, args, &hdr);
+       encode_nops(&hdr);
+}
+
 /*
  * Encode GETDEVICEINFO request
  */
@@ -3011,14 +3104,17 @@ static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
                goto out_overflow;
        bmlen = be32_to_cpup(p);
 
-       bitmap[0] = bitmap[1] = 0;
+       bitmap[0] = bitmap[1] = bitmap[2] = 0;
        p = xdr_inline_decode(xdr, (bmlen << 2));
        if (unlikely(!p))
                goto out_overflow;
        if (bmlen > 0) {
                bitmap[0] = be32_to_cpup(p++);
-               if (bmlen > 1)
-                       bitmap[1] = be32_to_cpup(p);
+               if (bmlen > 1) {
+                       bitmap[1] = be32_to_cpup(p++);
+                       if (bmlen > 2)
+                               bitmap[2] = be32_to_cpup(p);
+               }
        }
        return 0;
 out_overflow:
@@ -3050,8 +3146,9 @@ static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint3
                        return ret;
                bitmap[0] &= ~FATTR4_WORD0_SUPPORTED_ATTRS;
        } else
-               bitmask[0] = bitmask[1] = 0;
-       dprintk("%s: bitmask=%08x:%08x\n", __func__, bitmask[0], bitmask[1]);
+               bitmask[0] = bitmask[1] = bitmask[2] = 0;
+       dprintk("%s: bitmask=%08x:%08x:%08x\n", __func__,
+               bitmask[0], bitmask[1], bitmask[2]);
        return 0;
 }
 
@@ -4105,7 +4202,7 @@ out_overflow:
 static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res)
 {
        __be32 *savep;
-       uint32_t attrlen, bitmap[2] = {0};
+       uint32_t attrlen, bitmap[3] = {0};
        int status;
 
        if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
@@ -4131,7 +4228,7 @@ xdr_error:
 static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat)
 {
        __be32 *savep;
-       uint32_t attrlen, bitmap[2] = {0};
+       uint32_t attrlen, bitmap[3] = {0};
        int status;
 
        if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
@@ -4163,7 +4260,7 @@ xdr_error:
 static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf)
 {
        __be32 *savep;
-       uint32_t attrlen, bitmap[2] = {0};
+       uint32_t attrlen, bitmap[3] = {0};
        int status;
 
        if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
@@ -4303,7 +4400,7 @@ static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fat
 {
        __be32 *savep;
        uint32_t attrlen,
-                bitmap[2] = {0};
+                bitmap[3] = {0};
        int status;
 
        status = decode_op_hdr(xdr, OP_GETATTR);
@@ -4389,10 +4486,32 @@ static int decode_attr_pnfstype(struct xdr_stream *xdr, uint32_t *bitmap,
        return status;
 }
 
+/*
+ * The prefered block size for layout directed io
+ */
+static int decode_attr_layout_blksize(struct xdr_stream *xdr, uint32_t *bitmap,
+                                     uint32_t *res)
+{
+       __be32 *p;
+
+       dprintk("%s: bitmap is %x\n", __func__, bitmap[2]);
+       *res = 0;
+       if (bitmap[2] & FATTR4_WORD2_LAYOUT_BLKSIZE) {
+               p = xdr_inline_decode(xdr, 4);
+               if (unlikely(!p)) {
+                       print_overflow_msg(__func__, xdr);
+                       return -EIO;
+               }
+               *res = be32_to_cpup(p);
+               bitmap[2] &= ~FATTR4_WORD2_LAYOUT_BLKSIZE;
+       }
+       return 0;
+}
+
 static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
 {
        __be32 *savep;
-       uint32_t attrlen, bitmap[2];
+       uint32_t attrlen, bitmap[3];
        int status;
 
        if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
@@ -4420,6 +4539,9 @@ static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
        status = decode_attr_pnfstype(xdr, bitmap, &fsinfo->layouttype);
        if (status != 0)
                goto xdr_error;
+       status = decode_attr_layout_blksize(xdr, bitmap, &fsinfo->blksize);
+       if (status)
+               goto xdr_error;
 
        status = verify_attr_len(xdr, savep, attrlen);
 xdr_error:
@@ -4839,7 +4961,7 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
 {
        __be32 *savep;
        uint32_t attrlen,
-                bitmap[2] = {0};
+                bitmap[3] = {0};
        struct kvec *iov = req->rq_rcv_buf.head;
        int status;
 
@@ -5268,6 +5390,53 @@ out_overflow:
 }
 
 #if defined(CONFIG_NFS_V4_1)
+/*
+ * TODO: Need to handle case when EOF != true;
+ */
+static int decode_getdevicelist(struct xdr_stream *xdr,
+                               struct pnfs_devicelist *res)
+{
+       __be32 *p;
+       int status, i;
+       struct nfs_writeverf verftemp;
+
+       status = decode_op_hdr(xdr, OP_GETDEVICELIST);
+       if (status)
+               return status;
+
+       p = xdr_inline_decode(xdr, 8 + 8 + 4);
+       if (unlikely(!p))
+               goto out_overflow;
+
+       /* TODO: Skip cookie for now */
+       p += 2;
+
+       /* Read verifier */
+       p = xdr_decode_opaque_fixed(p, verftemp.verifier, 8);
+
+       res->num_devs = be32_to_cpup(p);
+
+       dprintk("%s: num_dev %d\n", __func__, res->num_devs);
+
+       if (res->num_devs > NFS4_PNFS_GETDEVLIST_MAXNUM) {
+               printk(KERN_ERR "%s too many result dev_num %u\n",
+                               __func__, res->num_devs);
+               return -EIO;
+       }
+
+       p = xdr_inline_decode(xdr,
+                             res->num_devs * NFS4_DEVICEID4_SIZE + 4);
+       if (unlikely(!p))
+               goto out_overflow;
+       for (i = 0; i < res->num_devs; i++)
+               p = xdr_decode_opaque_fixed(p, res->dev_id[i].data,
+                                           NFS4_DEVICEID4_SIZE);
+       res->eof = be32_to_cpup(p);
+       return 0;
+out_overflow:
+       print_overflow_msg(__func__, xdr);
+       return -EIO;
+}
 
 static int decode_getdeviceinfo(struct xdr_stream *xdr,
                                struct pnfs_device *pdev)
@@ -5430,6 +5599,7 @@ static int decode_layoutcommit(struct xdr_stream *xdr,
        int status;
 
        status = decode_op_hdr(xdr, OP_LAYOUTCOMMIT);
+       res->status = status;
        if (status)
                return status;
 
@@ -6541,6 +6711,32 @@ static int nfs4_xdr_dec_reclaim_complete(struct rpc_rqst *rqstp,
        return status;
 }
 
+/*
+ * Decode GETDEVICELIST response
+ */
+static int nfs4_xdr_dec_getdevicelist(struct rpc_rqst *rqstp,
+                                     struct xdr_stream *xdr,
+                                     struct nfs4_getdevicelist_res *res)
+{
+       struct compound_hdr hdr;
+       int status;
+
+       dprintk("encoding getdevicelist!\n");
+
+       status = decode_compound_hdr(xdr, &hdr);
+       if (status != 0)
+               goto out;
+       status = decode_sequence(xdr, &res->seq_res, rqstp);
+       if (status != 0)
+               goto out;
+       status = decode_putfh(xdr);
+       if (status != 0)
+               goto out;
+       status = decode_getdevicelist(xdr, res->devlist);
+out:
+       return status;
+}
+
 /*
  * Decode GETDEVINFO response
  */
@@ -6722,7 +6918,7 @@ out:
 int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
                       int plus)
 {
-       uint32_t bitmap[2] = {0};
+       uint32_t bitmap[3] = {0};
        uint32_t len;
        __be32 *p = xdr_inline_decode(xdr, 4);
        if (unlikely(!p))
@@ -6908,6 +7104,7 @@ struct rpc_procinfo       nfs4_procedures[] = {
        PROC(SECINFO_NO_NAME,   enc_secinfo_no_name,    dec_secinfo_no_name),
        PROC(TEST_STATEID,      enc_test_stateid,       dec_test_stateid),
        PROC(FREE_STATEID,      enc_free_stateid,       dec_free_stateid),
+       PROC(GETDEVICELIST,     enc_getdevicelist,      dec_getdevicelist),
 #endif /* CONFIG_NFS_V4_1 */
 };
 
index 9383ca7..d0cda12 100644 (file)
@@ -479,7 +479,6 @@ static int _io_check(struct objio_state *ios, bool is_write)
        for (i = 0; i <  ios->numdevs; i++) {
                struct osd_sense_info osi;
                struct osd_request *or = ios->per_dev[i].or;
-               unsigned dev;
                int ret;
 
                if (!or)
@@ -500,9 +499,8 @@ static int _io_check(struct objio_state *ios, bool is_write)
 
                        continue; /* we recovered */
                }
-               dev = ios->per_dev[i].dev;
-               objlayout_io_set_result(&ios->ol_state, dev,
-                                       &ios->layout->comps[dev].oc_object_id,
+               objlayout_io_set_result(&ios->ol_state, i,
+                                       &ios->layout->comps[i].oc_object_id,
                                        osd_pri_2_pnfs_err(osi.osd_err_pri),
                                        ios->per_dev[i].offset,
                                        ios->per_dev[i].length,
@@ -589,22 +587,19 @@ static void _calc_stripe_info(struct objio_state *ios, u64 file_offset,
 }
 
 static int _add_stripe_unit(struct objio_state *ios,  unsigned *cur_pg,
-               unsigned pgbase, struct _objio_per_comp *per_dev, int cur_len,
+               unsigned pgbase, struct _objio_per_comp *per_dev, int len,
                gfp_t gfp_flags)
 {
        unsigned pg = *cur_pg;
+       int cur_len = len;
        struct request_queue *q =
                        osd_request_queue(_io_od(ios, per_dev->dev));
 
-       per_dev->length += cur_len;
-
        if (per_dev->bio == NULL) {
-               unsigned stripes = ios->layout->num_comps /
-                                                    ios->layout->mirrors_p1;
-               unsigned pages_in_stripe = stripes *
+               unsigned pages_in_stripe = ios->layout->group_width *
                                      (ios->layout->stripe_unit / PAGE_SIZE);
                unsigned bio_size = (ios->ol_state.nr_pages + pages_in_stripe) /
-                                   stripes;
+                                   ios->layout->group_width;
 
                if (BIO_MAX_PAGES_KMALLOC < bio_size)
                        bio_size = BIO_MAX_PAGES_KMALLOC;
@@ -632,6 +627,7 @@ static int _add_stripe_unit(struct objio_state *ios,  unsigned *cur_pg,
        }
        BUG_ON(cur_len);
 
+       per_dev->length += len;
        *cur_pg = pg;
        return 0;
 }
@@ -650,7 +646,7 @@ static int _prepare_one_group(struct objio_state *ios, u64 length,
        int ret = 0;
 
        while (length) {
-               struct _objio_per_comp *per_dev = &ios->per_dev[dev];
+               struct _objio_per_comp *per_dev = &ios->per_dev[dev - first_dev];
                unsigned cur_len, page_off = 0;
 
                if (!per_dev->length) {
@@ -670,8 +666,8 @@ static int _prepare_one_group(struct objio_state *ios, u64 length,
                                cur_len = stripe_unit;
                        }
 
-                       if (max_comp < dev)
-                               max_comp = dev;
+                       if (max_comp < dev - first_dev)
+                               max_comp = dev - first_dev;
                } else {
                        cur_len = stripe_unit;
                }
@@ -806,7 +802,7 @@ static int _read_mirrors(struct objio_state *ios, unsigned cur_comp)
        struct _objio_per_comp *per_dev = &ios->per_dev[cur_comp];
        unsigned dev = per_dev->dev;
        struct pnfs_osd_object_cred *cred =
-                       &ios->layout->comps[dev];
+                       &ios->layout->comps[cur_comp];
        struct osd_obj_id obj = {
                .partition = cred->oc_object_id.oid_partition_id,
                .id = cred->oc_object_id.oid_object_id,
@@ -904,7 +900,7 @@ static int _write_mirrors(struct objio_state *ios, unsigned cur_comp)
        for (; cur_comp < last_comp; ++cur_comp, ++dev) {
                struct osd_request *or = NULL;
                struct pnfs_osd_object_cred *cred =
-                                       &ios->layout->comps[dev];
+                                       &ios->layout->comps[cur_comp];
                struct osd_obj_id obj = {
                        .partition = cred->oc_object_id.oid_partition_id,
                        .id = cred->oc_object_id.oid_object_id,
index 16fc758..b3918f7 100644 (file)
@@ -170,6 +170,9 @@ int pnfs_osd_xdr_decode_layout_map(struct pnfs_osd_layout *layout,
        p = _osd_xdr_decode_data_map(p, &layout->olo_map);
        layout->olo_comps_index = be32_to_cpup(p++);
        layout->olo_num_comps = be32_to_cpup(p++);
+       dprintk("%s: olo_comps_index=%d olo_num_comps=%d\n", __func__,
+               layout->olo_comps_index, layout->olo_num_comps);
+
        iter->total_comps = layout->olo_num_comps;
        return 0;
 }
index 38e5508..e550e88 100644 (file)
@@ -76,8 +76,11 @@ find_pnfs_driver(u32 id)
 void
 unset_pnfs_layoutdriver(struct nfs_server *nfss)
 {
-       if (nfss->pnfs_curr_ld)
+       if (nfss->pnfs_curr_ld) {
+               if (nfss->pnfs_curr_ld->clear_layoutdriver)
+                       nfss->pnfs_curr_ld->clear_layoutdriver(nfss);
                module_put(nfss->pnfs_curr_ld->owner);
+       }
        nfss->pnfs_curr_ld = NULL;
 }
 
@@ -88,7 +91,8 @@ unset_pnfs_layoutdriver(struct nfs_server *nfss)
  * @id layout type. Zero (illegal layout type) indicates pNFS not in use.
  */
 void
-set_pnfs_layoutdriver(struct nfs_server *server, u32 id)
+set_pnfs_layoutdriver(struct nfs_server *server, const struct nfs_fh *mntfh,
+                     u32 id)
 {
        struct pnfs_layoutdriver_type *ld_type = NULL;
 
@@ -115,6 +119,13 @@ set_pnfs_layoutdriver(struct nfs_server *server, u32 id)
                goto out_no_driver;
        }
        server->pnfs_curr_ld = ld_type;
+       if (ld_type->set_layoutdriver
+           && ld_type->set_layoutdriver(server, mntfh)) {
+               printk(KERN_ERR "%s: Error initializing pNFS layout driver %u.\n",
+                               __func__, id);
+               module_put(ld_type->owner);
+               goto out_no_driver;
+       }
 
        dprintk("%s: pNFS module for %u set\n", __func__, id);
        return;
@@ -190,6 +201,7 @@ static void
 pnfs_free_layout_hdr(struct pnfs_layout_hdr *lo)
 {
        struct pnfs_layoutdriver_type *ld = NFS_SERVER(lo->plh_inode)->pnfs_curr_ld;
+       put_rpccred(lo->plh_lc_cred);
        return ld->alloc_layout_hdr ? ld->free_layout_hdr(lo) : kfree(lo);
 }
 
@@ -224,6 +236,7 @@ static void
 init_lseg(struct pnfs_layout_hdr *lo, struct pnfs_layout_segment *lseg)
 {
        INIT_LIST_HEAD(&lseg->pls_list);
+       INIT_LIST_HEAD(&lseg->pls_lc_list);
        atomic_set(&lseg->pls_refcount, 1);
        smp_mb();
        set_bit(NFS_LSEG_VALID, &lseg->pls_flags);
@@ -816,7 +829,9 @@ out:
 }
 
 static struct pnfs_layout_hdr *
-alloc_init_layout_hdr(struct inode *ino, gfp_t gfp_flags)
+alloc_init_layout_hdr(struct inode *ino,
+                     struct nfs_open_context *ctx,
+                     gfp_t gfp_flags)
 {
        struct pnfs_layout_hdr *lo;
 
@@ -828,11 +843,14 @@ alloc_init_layout_hdr(struct inode *ino, gfp_t gfp_flags)
        INIT_LIST_HEAD(&lo->plh_segs);
        INIT_LIST_HEAD(&lo->plh_bulk_recall);
        lo->plh_inode = ino;
+       lo->plh_lc_cred = get_rpccred(ctx->state->owner->so_cred);
        return lo;
 }
 
 static struct pnfs_layout_hdr *
-pnfs_find_alloc_layout(struct inode *ino, gfp_t gfp_flags)
+pnfs_find_alloc_layout(struct inode *ino,
+                      struct nfs_open_context *ctx,
+                      gfp_t gfp_flags)
 {
        struct nfs_inode *nfsi = NFS_I(ino);
        struct pnfs_layout_hdr *new = NULL;
@@ -847,7 +865,7 @@ pnfs_find_alloc_layout(struct inode *ino, gfp_t gfp_flags)
                        return nfsi->layout;
        }
        spin_unlock(&ino->i_lock);
-       new = alloc_init_layout_hdr(ino, gfp_flags);
+       new = alloc_init_layout_hdr(ino, ctx, gfp_flags);
        spin_lock(&ino->i_lock);
 
        if (likely(nfsi->layout == NULL))       /* Won the race? */
@@ -940,7 +958,7 @@ pnfs_update_layout(struct inode *ino,
        if (!pnfs_enabled_sb(NFS_SERVER(ino)))
                return NULL;
        spin_lock(&ino->i_lock);
-       lo = pnfs_find_alloc_layout(ino, gfp_flags);
+       lo = pnfs_find_alloc_layout(ino, ctx, gfp_flags);
        if (lo == NULL) {
                dprintk("%s ERROR: can't get pnfs_layout_hdr\n", __func__);
                goto out_unlock;
@@ -1350,16 +1368,17 @@ pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc)
 EXPORT_SYMBOL_GPL(pnfs_generic_pg_readpages);
 
 /*
- * Currently there is only one (whole file) write lseg.
+ * There can be multiple RW segments.
  */
-static struct pnfs_layout_segment *pnfs_list_write_lseg(struct inode *inode)
+static void pnfs_list_write_lseg(struct inode *inode, struct list_head *listp)
 {
-       struct pnfs_layout_segment *lseg, *rv = NULL;
+       struct pnfs_layout_segment *lseg;
 
-       list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list)
-               if (lseg->pls_range.iomode == IOMODE_RW)
-                       rv = lseg;
-       return rv;
+       list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) {
+               if (lseg->pls_range.iomode == IOMODE_RW &&
+                   test_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags))
+                       list_add(&lseg->pls_lc_list, listp);
+       }
 }
 
 void
@@ -1371,17 +1390,19 @@ pnfs_set_layoutcommit(struct nfs_write_data *wdata)
 
        spin_lock(&nfsi->vfs_inode.i_lock);
        if (!test_and_set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) {
-               /* references matched in nfs4_layoutcommit_release */
-               get_lseg(wdata->lseg);
-               wdata->lseg->pls_lc_cred =
-                       get_rpccred(wdata->args.context->state->owner->so_cred);
                mark_as_dirty = true;
                dprintk("%s: Set layoutcommit for inode %lu ",
                        __func__, wdata->inode->i_ino);
        }
-       if (end_pos > wdata->lseg->pls_end_pos)
-               wdata->lseg->pls_end_pos = end_pos;
+       if (!test_and_set_bit(NFS_LSEG_LAYOUTCOMMIT, &wdata->lseg->pls_flags)) {
+               /* references matched in nfs4_layoutcommit_release */
+               get_lseg(wdata->lseg);
+       }
+       if (end_pos > nfsi->layout->plh_lwb)
+               nfsi->layout->plh_lwb = end_pos;
        spin_unlock(&nfsi->vfs_inode.i_lock);
+       dprintk("%s: lseg %p end_pos %llu\n",
+               __func__, wdata->lseg, nfsi->layout->plh_lwb);
 
        /* if pnfs_layoutcommit_inode() runs between inode locks, the next one
         * will be a noop because NFS_INO_LAYOUTCOMMIT will not be set */
@@ -1390,6 +1411,14 @@ pnfs_set_layoutcommit(struct nfs_write_data *wdata)
 }
 EXPORT_SYMBOL_GPL(pnfs_set_layoutcommit);
 
+void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data)
+{
+       struct nfs_server *nfss = NFS_SERVER(data->args.inode);
+
+       if (nfss->pnfs_curr_ld->cleanup_layoutcommit)
+               nfss->pnfs_curr_ld->cleanup_layoutcommit(data);
+}
+
 /*
  * For the LAYOUT4_NFSV4_1_FILES layout type, NFS_DATA_SYNC WRITEs and
  * NFS_UNSTABLE WRITEs with a COMMIT to data servers must store enough
@@ -1403,8 +1432,6 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
 {
        struct nfs4_layoutcommit_data *data;
        struct nfs_inode *nfsi = NFS_I(inode);
-       struct pnfs_layout_segment *lseg;
-       struct rpc_cred *cred;
        loff_t end_pos;
        int status = 0;
 
@@ -1421,30 +1448,25 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
                goto out;
        }
 
+       INIT_LIST_HEAD(&data->lseg_list);
        spin_lock(&inode->i_lock);
        if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) {
                spin_unlock(&inode->i_lock);
                kfree(data);
                goto out;
        }
-       /*
-        * Currently only one (whole file) write lseg which is referenced
-        * in pnfs_set_layoutcommit and will be found.
-        */
-       lseg = pnfs_list_write_lseg(inode);
 
-       end_pos = lseg->pls_end_pos;
-       cred = lseg->pls_lc_cred;
-       lseg->pls_end_pos = 0;
-       lseg->pls_lc_cred = NULL;
+       pnfs_list_write_lseg(inode, &data->lseg_list);
+
+       end_pos = nfsi->layout->plh_lwb;
+       nfsi->layout->plh_lwb = 0;
 
        memcpy(&data->args.stateid.data, nfsi->layout->plh_stateid.data,
                sizeof(nfsi->layout->plh_stateid.data));
        spin_unlock(&inode->i_lock);
 
        data->args.inode = inode;
-       data->lseg = lseg;
-       data->cred = cred;
+       data->cred = get_rpccred(nfsi->layout->plh_lc_cred);
        nfs_fattr_init(&data->fattr);
        data->args.bitmask = NFS_SERVER(inode)->cache_consistency_bitmask;
        data->res.fattr = &data->fattr;
index 078670d..01cbfd5 100644 (file)
 enum {
        NFS_LSEG_VALID = 0,     /* cleared when lseg is recalled/returned */
        NFS_LSEG_ROC,           /* roc bit received from server */
+       NFS_LSEG_LAYOUTCOMMIT,  /* layoutcommit bit set for layoutcommit */
 };
 
 struct pnfs_layout_segment {
        struct list_head pls_list;
+       struct list_head pls_lc_list;
        struct pnfs_layout_range pls_range;
        atomic_t pls_refcount;
        unsigned long pls_flags;
        struct pnfs_layout_hdr *pls_layout;
-       struct rpc_cred *pls_lc_cred; /* LAYOUTCOMMIT credential */
-       loff_t pls_end_pos; /* LAYOUTCOMMIT write end */
 };
 
 enum pnfs_try_status {
@@ -80,6 +80,9 @@ struct pnfs_layoutdriver_type {
        struct module *owner;
        unsigned flags;
 
+       int (*set_layoutdriver) (struct nfs_server *, const struct nfs_fh *);
+       int (*clear_layoutdriver) (struct nfs_server *);
+
        struct pnfs_layout_hdr * (*alloc_layout_hdr) (struct inode *inode, gfp_t gfp_flags);
        void (*free_layout_hdr) (struct pnfs_layout_hdr *);
 
@@ -110,6 +113,8 @@ struct pnfs_layoutdriver_type {
                                     struct xdr_stream *xdr,
                                     const struct nfs4_layoutreturn_args *args);
 
+       void (*cleanup_layoutcommit) (struct nfs4_layoutcommit_data *data);
+
        void (*encode_layoutcommit) (struct pnfs_layout_hdr *layoutid,
                                     struct xdr_stream *xdr,
                                     const struct nfs4_layoutcommit_args *args);
@@ -125,6 +130,8 @@ struct pnfs_layout_hdr {
        unsigned long           plh_block_lgets; /* block LAYOUTGET if >0 */
        u32                     plh_barrier; /* ignore lower seqids */
        unsigned long           plh_flags;
+       loff_t                  plh_lwb; /* last write byte for layoutcommit */
+       struct rpc_cred         *plh_lc_cred; /* layoutcommit cred */
        struct inode            *plh_inode;
 };
 
@@ -137,10 +144,21 @@ struct pnfs_device {
        unsigned int  pglen;
 };
 
+#define NFS4_PNFS_GETDEVLIST_MAXNUM 16
+
+struct pnfs_devicelist {
+       unsigned int            eof;
+       unsigned int            num_devs;
+       struct nfs4_deviceid    dev_id[NFS4_PNFS_GETDEVLIST_MAXNUM];
+};
+
 extern int pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *);
 extern void pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *);
 
 /* nfs4proc.c */
+extern int nfs4_proc_getdevicelist(struct nfs_server *server,
+                                  const struct nfs_fh *fh,
+                                  struct pnfs_devicelist *devlist);
 extern int nfs4_proc_getdeviceinfo(struct nfs_server *server,
                                   struct pnfs_device *dev);
 extern int nfs4_proc_layoutget(struct nfs4_layoutget *lgp);
@@ -153,7 +171,7 @@ void put_lseg(struct pnfs_layout_segment *lseg);
 bool pnfs_pageio_init_read(struct nfs_pageio_descriptor *, struct inode *);
 bool pnfs_pageio_init_write(struct nfs_pageio_descriptor *, struct inode *, int);
 
-void set_pnfs_layoutdriver(struct nfs_server *, u32 id);
+void set_pnfs_layoutdriver(struct nfs_server *, const struct nfs_fh *, u32);
 void unset_pnfs_layoutdriver(struct nfs_server *);
 void pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *, struct nfs_page *);
 int pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc);
@@ -179,6 +197,7 @@ void pnfs_roc_release(struct inode *ino);
 void pnfs_roc_set_barrier(struct inode *ino, u32 barrier);
 bool pnfs_roc_drain(struct inode *ino, u32 *barrier);
 void pnfs_set_layoutcommit(struct nfs_write_data *wdata);
+void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data);
 int pnfs_layoutcommit_inode(struct inode *inode, bool sync);
 int _pnfs_return_layout(struct inode *);
 int pnfs_ld_write_done(struct nfs_write_data *);
@@ -360,7 +379,8 @@ pnfs_roc_drain(struct inode *ino, u32 *barrier)
        return false;
 }
 
-static inline void set_pnfs_layoutdriver(struct nfs_server *s, u32 id)
+static inline void set_pnfs_layoutdriver(struct nfs_server *s,
+                                        const struct nfs_fh *mntfh, u32 id)
 {
 }
 
index 783c58d..a721907 100644 (file)
@@ -247,7 +247,7 @@ static int ocfs2_set_acl(handle_t *handle,
        case ACL_TYPE_ACCESS:
                name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
                if (acl) {
-                       mode_t mode = inode->i_mode;
+                       umode_t mode = inode->i_mode;
                        ret = posix_acl_equiv_mode(acl, &mode);
                        if (ret < 0)
                                return ret;
@@ -351,7 +351,7 @@ int ocfs2_init_acl(handle_t *handle,
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
        struct posix_acl *acl = NULL;
        int ret = 0, ret2;
-       mode_t mode;
+       umode_t mode;
 
        if (!S_ISLNK(inode->i_mode)) {
                if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) {
index d43729a..10027b4 100644 (file)
@@ -149,10 +149,10 @@ posix_acl_valid(const struct posix_acl *acl)
  * file mode permission bits, or else 1. Returns -E... on error.
  */
 int
-posix_acl_equiv_mode(const struct posix_acl *acl, mode_t *mode_p)
+posix_acl_equiv_mode(const struct posix_acl *acl, umode_t *mode_p)
 {
        const struct posix_acl_entry *pa, *pe;
-       mode_t mode = 0;
+       umode_t mode = 0;
        int not_equiv = 0;
 
        FOREACH_ACL_ENTRY(pa, acl, pe) {
@@ -188,7 +188,7 @@ posix_acl_equiv_mode(const struct posix_acl *acl, mode_t *mode_p)
  * Create an ACL representing the file mode permission bits of an inode.
  */
 struct posix_acl *
-posix_acl_from_mode(mode_t mode, gfp_t flags)
+posix_acl_from_mode(umode_t mode, gfp_t flags)
 {
        struct posix_acl *acl = posix_acl_alloc(3, flags);
        if (!acl)
@@ -279,11 +279,11 @@ check_perm:
  * system calls. All permissions that are not granted by the acl are removed.
  * The permissions in the acl are changed to reflect the mode_p parameter.
  */
-static int posix_acl_create_masq(struct posix_acl *acl, mode_t *mode_p)
+static int posix_acl_create_masq(struct posix_acl *acl, umode_t *mode_p)
 {
        struct posix_acl_entry *pa, *pe;
        struct posix_acl_entry *group_obj = NULL, *mask_obj = NULL;
-       mode_t mode = *mode_p;
+       umode_t mode = *mode_p;
        int not_equiv = 0;
 
        /* assert(atomic_read(acl->a_refcount) == 1); */
@@ -336,7 +336,7 @@ static int posix_acl_create_masq(struct posix_acl *acl, mode_t *mode_p)
 /*
  * Modify the ACL for the chmod syscall.
  */
-static int posix_acl_chmod_masq(struct posix_acl *acl, mode_t mode)
+static int posix_acl_chmod_masq(struct posix_acl *acl, umode_t mode)
 {
        struct posix_acl_entry *group_obj = NULL, *mask_obj = NULL;
        struct posix_acl_entry *pa, *pe;
@@ -382,7 +382,7 @@ static int posix_acl_chmod_masq(struct posix_acl *acl, mode_t mode)
 }
 
 int
-posix_acl_create(struct posix_acl **acl, gfp_t gfp, mode_t *mode_p)
+posix_acl_create(struct posix_acl **acl, gfp_t gfp, umode_t *mode_p)
 {
        struct posix_acl *clone = posix_acl_clone(*acl, gfp);
        int err = -ENOMEM;
@@ -400,7 +400,7 @@ posix_acl_create(struct posix_acl **acl, gfp_t gfp, mode_t *mode_p)
 EXPORT_SYMBOL(posix_acl_create);
 
 int
-posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, mode_t mode)
+posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, umode_t mode)
 {
        struct posix_acl *clone = posix_acl_clone(*acl, gfp);
        int err = -ENOMEM;
index 08e3ecc..5eb0206 100644 (file)
@@ -1118,7 +1118,7 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
         * Warn that /proc/pid/oom_adj is deprecated, see
         * Documentation/feature-removal-schedule.txt.
         */
-       WARN_ONCE(1, "%s (%d): /proc/%d/oom_adj is deprecated, please use /proc/%d/oom_score_adj instead.\n",
+       printk_once(KERN_WARNING "%s (%d): /proc/%d/oom_adj is deprecated, please use /proc/%d/oom_score_adj instead.\n",
                  current->comm, task_pid_nr(current), task_pid_nr(task),
                  task_pid_nr(task));
        task->signal->oom_adj = oom_adjust;
@@ -1919,6 +1919,14 @@ static int proc_fd_info(struct inode *inode, struct path *path, char *info)
                spin_lock(&files->file_lock);
                file = fcheck_files(files, fd);
                if (file) {
+                       unsigned int f_flags;
+                       struct fdtable *fdt;
+
+                       fdt = files_fdtable(files);
+                       f_flags = file->f_flags & ~O_CLOEXEC;
+                       if (FD_ISSET(fd, fdt->close_on_exec))
+                               f_flags |= O_CLOEXEC;
+
                        if (path) {
                                *path = file->f_path;
                                path_get(&file->f_path);
@@ -1928,7 +1936,7 @@ static int proc_fd_info(struct inode *inode, struct path *path, char *info)
                                         "pos:\t%lli\n"
                                         "flags:\t0%o\n",
                                         (long long) file->f_pos,
-                                        file->f_flags);
+                                        f_flags);
                        spin_unlock(&files->file_lock);
                        put_files_struct(files);
                        return 0;
index 977ed27..893b961 100644 (file)
@@ -39,8 +39,9 @@
 #define        PSTORE_NAMELEN  64
 
 struct pstore_private {
+       struct pstore_info *psi;
+       enum pstore_type_id type;
        u64     id;
-       int     (*erase)(u64);
        ssize_t size;
        char    data[];
 };
@@ -73,7 +74,7 @@ static int pstore_unlink(struct inode *dir, struct dentry *dentry)
 {
        struct pstore_private *p = dentry->d_inode->i_private;
 
-       p->erase(p->id);
+       p->psi->erase(p->type, p->id, p->psi);
 
        return simple_unlink(dir, dentry);
 }
@@ -175,8 +176,8 @@ int pstore_is_mounted(void)
  * Set the mtime & ctime to the date that this record was originally stored.
  */
 int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id,
-                             char *data, size_t size,
-                             struct timespec time, int (*erase)(u64))
+                 char *data, size_t size, struct timespec time,
+                 struct pstore_info *psi)
 {
        struct dentry           *root = pstore_sb->s_root;
        struct dentry           *dentry;
@@ -192,8 +193,9 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id,
        private = kmalloc(sizeof *private + size, GFP_KERNEL);
        if (!private)
                goto fail_alloc;
+       private->type = type;
        private->id = id;
-       private->erase = erase;
+       private->psi = psi;
 
        switch (type) {
        case PSTORE_TYPE_DMESG:
index 8c9f23e..611c1b3 100644 (file)
@@ -2,5 +2,5 @@ extern void     pstore_set_kmsg_bytes(int);
 extern void    pstore_get_records(void);
 extern int     pstore_mkfile(enum pstore_type_id, char *psname, u64 id,
                              char *data, size_t size,
-                             struct timespec time, int (*erase)(u64));
+                             struct timespec time, struct pstore_info *psi);
 extern int     pstore_is_mounted(void);
index f2c3ff2..c5300ec 100644 (file)
@@ -37,6 +37,8 @@
 static DEFINE_SPINLOCK(pstore_lock);
 static struct pstore_info *psinfo;
 
+static char *backend;
+
 /* How much of the console log to snapshot */
 static unsigned long kmsg_bytes = 10240;
 
@@ -67,7 +69,8 @@ static void pstore_dump(struct kmsg_dumper *dumper,
        unsigned long   size, total = 0;
        char            *dst, *why;
        u64             id;
-       int             hsize, part = 1;
+       int             hsize;
+       unsigned int    part = 1;
 
        if (reason < ARRAY_SIZE(reason_str))
                why = reason_str[reason];
@@ -78,7 +81,7 @@ static void pstore_dump(struct kmsg_dumper *dumper,
        oopscount++;
        while (total < kmsg_bytes) {
                dst = psinfo->buf;
-               hsize = sprintf(dst, "%s#%d Part%d\n", why, oopscount, part++);
+               hsize = sprintf(dst, "%s#%d Part%d\n", why, oopscount, part);
                size = psinfo->bufsize - hsize;
                dst += hsize;
 
@@ -94,14 +97,16 @@ static void pstore_dump(struct kmsg_dumper *dumper,
                memcpy(dst, s1 + s1_start, l1_cpy);
                memcpy(dst + l1_cpy, s2 + s2_start, l2_cpy);
 
-               id = psinfo->write(PSTORE_TYPE_DMESG, hsize + l1_cpy + l2_cpy);
+               id = psinfo->write(PSTORE_TYPE_DMESG, part,
+                                  hsize + l1_cpy + l2_cpy, psinfo);
                if (reason == KMSG_DUMP_OOPS && pstore_is_mounted())
                        pstore_mkfile(PSTORE_TYPE_DMESG, psinfo->name, id,
                                      psinfo->buf, hsize + l1_cpy + l2_cpy,
-                                     CURRENT_TIME, psinfo->erase);
+                                     CURRENT_TIME, psinfo);
                l1 -= l1_cpy;
                l2 -= l2_cpy;
                total += l1_cpy + l2_cpy;
+               part++;
        }
        mutex_unlock(&psinfo->buf_mutex);
 }
@@ -128,6 +133,12 @@ int pstore_register(struct pstore_info *psi)
                spin_unlock(&pstore_lock);
                return -EBUSY;
        }
+
+       if (backend && strcmp(backend, psi->name)) {
+               spin_unlock(&pstore_lock);
+               return -EINVAL;
+       }
+
        psinfo = psi;
        spin_unlock(&pstore_lock);
 
@@ -166,9 +177,9 @@ void pstore_get_records(void)
        if (rc)
                goto out;
 
-       while ((size = psi->read(&id, &type, &time)) > 0) {
+       while ((size = psi->read(&id, &type, &time, psi)) > 0) {
                if (pstore_mkfile(type, psi->name, id, psi->buf, (size_t)size,
-                                 time, psi->erase))
+                                 time, psi))
                        failed++;
        }
        psi->close(psi);
@@ -196,12 +207,15 @@ int pstore_write(enum pstore_type_id type, char *buf, size_t size)
 
        mutex_lock(&psinfo->buf_mutex);
        memcpy(psinfo->buf, buf, size);
-       id = psinfo->write(type, size);
+       id = psinfo->write(type, 0, size, psinfo);
        if (pstore_is_mounted())
                pstore_mkfile(PSTORE_TYPE_DMESG, psinfo->name, id, psinfo->buf,
-                             size, CURRENT_TIME, psinfo->erase);
+                             size, CURRENT_TIME, psinfo);
        mutex_unlock(&psinfo->buf_mutex);
 
        return 0;
 }
 EXPORT_SYMBOL_GPL(pstore_write);
+
+module_param(backend, charp, 0444);
+MODULE_PARM_DESC(backend, "Pstore backend to use");
index 7362cf4..6da0396 100644 (file)
@@ -272,12 +272,10 @@ reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
        case ACL_TYPE_ACCESS:
                name = POSIX_ACL_XATTR_ACCESS;
                if (acl) {
-                       mode_t mode = inode->i_mode;
-                       error = posix_acl_equiv_mode(acl, &mode);
+                       error = posix_acl_equiv_mode(acl, &inode->i_mode);
                        if (error < 0)
                                return error;
                        else {
-                               inode->i_mode = mode;
                                if (error == 0)
                                        acl = NULL;
                        }
@@ -354,8 +352,6 @@ reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
                return PTR_ERR(acl);
 
        if (acl) {
-               mode_t mode = inode->i_mode;
-
                /* Copy the default ACL to the default ACL of a new directory */
                if (S_ISDIR(inode->i_mode)) {
                        err = reiserfs_set_acl(th, inode, ACL_TYPE_DEFAULT,
@@ -366,12 +362,10 @@ reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
 
                /* Now we reconcile the new ACL and the mode,
                   potentially modifying both */
-               err = posix_acl_create(&acl, GFP_NOFS, &mode);
+               err = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
                if (err < 0)
                        return err;
 
-               inode->i_mode = mode;
-
                /* If we need an ACL.. */
                if (err > 0)
                        err = reiserfs_set_acl(th, inode, ACL_TYPE_ACCESS, acl);
index 4a6f7f4..b4f2ab4 100644 (file)
@@ -29,10 +29,7 @@ void fsstack_copy_inode_size(struct inode *dst, struct inode *src)
         *
         * We don't actually know what locking is used at the lower level;
         * but if it's a filesystem that supports quotas, it will be using
-        * i_lock as in inode_add_bytes().  tmpfs uses other locking, and
-        * its 32-bit is (just) able to exceed 2TB i_size with the aid of
-        * holes; but its i_blocks cannot carry into the upper long without
-        * almost 2TB swap - let's ignore that case.
+        * i_lock as in inode_add_bytes().
         */
        if (sizeof(i_blocks) > sizeof(long))
                spin_lock(&src->i_lock);
index 9610391..ba5316f 100644 (file)
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -27,12 +27,12 @@ void generic_fillattr(struct inode *inode, struct kstat *stat)
        stat->uid = inode->i_uid;
        stat->gid = inode->i_gid;
        stat->rdev = inode->i_rdev;
+       stat->size = i_size_read(inode);
        stat->atime = inode->i_atime;
        stat->mtime = inode->i_mtime;
        stat->ctime = inode->i_ctime;
-       stat->size = i_size_read(inode);
-       stat->blocks = inode->i_blocks;
        stat->blksize = (1 << inode->i_blkbits);
+       stat->blocks = inode->i_blocks;
 }
 
 EXPORT_SYMBOL(generic_fillattr);
index 75bb316..427a4e8 100644 (file)
 # Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #
 
-ccflags-y := -I$(src) -I$(src)/linux-2.6
-ccflags-$(CONFIG_XFS_DEBUG) += -g
+ccflags-y += -I$(src)                  # needed for trace events
 
-XFS_LINUX := linux-2.6
+ccflags-$(CONFIG_XFS_DEBUG) += -g
 
 obj-$(CONFIG_XFS_FS)           += xfs.o
 
-xfs-y                          += linux-2.6/xfs_trace.o
-
-xfs-$(CONFIG_XFS_QUOTA)                += $(addprefix quota/, \
-                                  xfs_dquot.o \
-                                  xfs_dquot_item.o \
-                                  xfs_trans_dquot.o \
-                                  xfs_qm_syscalls.o \
-                                  xfs_qm_bhv.o \
-                                  xfs_qm.o)
-xfs-$(CONFIG_XFS_QUOTA)                += linux-2.6/xfs_quotaops.o
-
-ifeq ($(CONFIG_XFS_QUOTA),y)
-xfs-$(CONFIG_PROC_FS)          += quota/xfs_qm_stats.o
-endif
-
-xfs-$(CONFIG_XFS_RT)           += xfs_rtalloc.o
-xfs-$(CONFIG_XFS_POSIX_ACL)    += $(XFS_LINUX)/xfs_acl.o
-xfs-$(CONFIG_PROC_FS)          += $(XFS_LINUX)/xfs_stats.o
-xfs-$(CONFIG_SYSCTL)           += $(XFS_LINUX)/xfs_sysctl.o
-xfs-$(CONFIG_COMPAT)           += $(XFS_LINUX)/xfs_ioctl32.o
+# this one should be compiled first, as the tracing macros can easily blow up
+xfs-y                          += xfs_trace.o
 
+# highlevel code
+xfs-y                          += xfs_aops.o \
+                                  xfs_bit.o \
+                                  xfs_buf.o \
+                                  xfs_dfrag.o \
+                                  xfs_discard.o \
+                                  xfs_error.o \
+                                  xfs_export.o \
+                                  xfs_file.o \
+                                  xfs_filestream.o \
+                                  xfs_fsops.o \
+                                  xfs_fs_subr.o \
+                                  xfs_globals.o \
+                                  xfs_iget.o \
+                                  xfs_ioctl.o \
+                                  xfs_iomap.o \
+                                  xfs_iops.o \
+                                  xfs_itable.o \
+                                  xfs_message.o \
+                                  xfs_mru_cache.o \
+                                  xfs_super.o \
+                                  xfs_sync.o \
+                                  xfs_xattr.o \
+                                  xfs_rename.o \
+                                  xfs_rw.o \
+                                  xfs_utils.o \
+                                  xfs_vnodeops.o \
+                                  kmem.o \
+                                  uuid.o
 
+# code shared with libxfs
 xfs-y                          += xfs_alloc.o \
                                   xfs_alloc_btree.o \
                                   xfs_attr.o \
                                   xfs_attr_leaf.o \
-                                  xfs_bit.o \
                                   xfs_bmap.o \
                                   xfs_bmap_btree.o \
                                   xfs_btree.o \
-                                  xfs_buf_item.o \
                                   xfs_da_btree.o \
                                   xfs_dir2.o \
                                   xfs_dir2_block.o \
@@ -61,49 +70,37 @@ xfs-y                               += xfs_alloc.o \
                                   xfs_dir2_leaf.o \
                                   xfs_dir2_node.o \
                                   xfs_dir2_sf.o \
-                                  xfs_error.o \
-                                  xfs_extfree_item.o \
-                                  xfs_filestream.o \
-                                  xfs_fsops.o \
                                   xfs_ialloc.o \
                                   xfs_ialloc_btree.o \
-                                  xfs_iget.o \
                                   xfs_inode.o \
-                                  xfs_inode_item.o \
-                                  xfs_iomap.o \
-                                  xfs_itable.o \
-                                  xfs_dfrag.o \
-                                  xfs_log.o \
-                                  xfs_log_cil.o \
                                   xfs_log_recover.o \
                                   xfs_mount.o \
-                                  xfs_mru_cache.o \
-                                  xfs_rename.o \
-                                  xfs_trans.o \
+                                  xfs_trans.o
+
+# low-level transaction/log code
+xfs-y                          += xfs_log.o \
+                                  xfs_log_cil.o \
+                                  xfs_buf_item.o \
+                                  xfs_extfree_item.o \
+                                  xfs_inode_item.o \
                                   xfs_trans_ail.o \
                                   xfs_trans_buf.o \
                                   xfs_trans_extfree.o \
                                   xfs_trans_inode.o \
-                                  xfs_utils.o \
-                                  xfs_vnodeops.o \
-                                  xfs_rw.o
-
-# Objects in linux/
-xfs-y                          += $(addprefix $(XFS_LINUX)/, \
-                                  kmem.o \
-                                  xfs_aops.o \
-                                  xfs_buf.o \
-                                  xfs_discard.o \
-                                  xfs_export.o \
-                                  xfs_file.o \
-                                  xfs_fs_subr.o \
-                                  xfs_globals.o \
-                                  xfs_ioctl.o \
-                                  xfs_iops.o \
-                                  xfs_message.o \
-                                  xfs_super.o \
-                                  xfs_sync.o \
-                                  xfs_xattr.o)
 
-# Objects in support/
-xfs-y                          += support/uuid.o
+# optional features
+xfs-$(CONFIG_XFS_QUOTA)                += xfs_dquot.o \
+                                  xfs_dquot_item.o \
+                                  xfs_trans_dquot.o \
+                                  xfs_qm_syscalls.o \
+                                  xfs_qm_bhv.o \
+                                  xfs_qm.o \
+                                  xfs_quotaops.o
+ifeq ($(CONFIG_XFS_QUOTA),y)
+xfs-$(CONFIG_PROC_FS)          += xfs_qm_stats.o
+endif
+xfs-$(CONFIG_XFS_RT)           += xfs_rtalloc.o
+xfs-$(CONFIG_XFS_POSIX_ACL)    += xfs_acl.o
+xfs-$(CONFIG_PROC_FS)          += xfs_stats.o
+xfs-$(CONFIG_SYSCTL)           += xfs_sysctl.o
+xfs-$(CONFIG_COMPAT)           += xfs_ioctl32.o
similarity index 100%
rename from fs/xfs/linux-2.6/kmem.c
rename to fs/xfs/kmem.c
similarity index 100%
rename from fs/xfs/linux-2.6/kmem.h
rename to fs/xfs/kmem.h
similarity index 100%
rename from fs/xfs/linux-2.6/mrlock.h
rename to fs/xfs/mrlock.h
similarity index 100%
rename from fs/xfs/linux-2.6/time.h
rename to fs/xfs/time.h
similarity index 100%
rename from fs/xfs/support/uuid.c
rename to fs/xfs/uuid.c
similarity index 100%
rename from fs/xfs/support/uuid.h
rename to fs/xfs/uuid.h
index 53ec3ea..d8b11b7 100644 (file)
@@ -24,5 +24,6 @@
 #define XFS_BUF_LOCK_TRACKING 1
 #endif
 
-#include <linux-2.6/xfs_linux.h>
+#include "xfs_linux.h"
+
 #endif /* __XFS_H__ */
similarity index 98%
rename from fs/xfs/linux-2.6/xfs_acl.c
rename to fs/xfs/xfs_acl.c
index 44ce516..b6c4b37 100644 (file)
@@ -221,7 +221,7 @@ xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
 }
 
 static int
-xfs_set_mode(struct inode *inode, mode_t mode)
+xfs_set_mode(struct inode *inode, umode_t mode)
 {
        int error = 0;
 
@@ -267,7 +267,7 @@ posix_acl_default_exists(struct inode *inode)
 int
 xfs_inherit_acl(struct inode *inode, struct posix_acl *acl)
 {
-       mode_t mode = inode->i_mode;
+       umode_t mode = inode->i_mode;
        int error = 0, inherit = 0;
 
        if (S_ISDIR(inode->i_mode)) {
@@ -381,7 +381,7 @@ xfs_xattr_acl_set(struct dentry *dentry, const char *name,
                goto out_release;
 
        if (type == ACL_TYPE_ACCESS) {
-               mode_t mode = inode->i_mode;
+               umode_t mode = inode->i_mode;
                error = posix_acl_equiv_mode(acl, &mode);
 
                if (error <= 0) {
index 2c656ef..39632d9 100644 (file)
@@ -51,7 +51,10 @@ extern int posix_acl_default_exists(struct inode *inode);
 extern const struct xattr_handler xfs_xattr_acl_access_handler;
 extern const struct xattr_handler xfs_xattr_acl_default_handler;
 #else
-# define xfs_get_acl(inode, type)                      NULL
+static inline struct posix_acl *xfs_get_acl(struct inode *inode, int type)
+{
+       return NULL;
+}
 # define xfs_inherit_acl(inode, default_acl)           0
 # define xfs_acl_chmod(inode)                          0
 # define posix_acl_access_exists(inode)                        0
index 6530769..4805f00 100644 (file)
@@ -103,7 +103,7 @@ typedef struct xfs_agf {
 /* disk block (xfs_daddr_t) in the AG */
 #define XFS_AGF_DADDR(mp)      ((xfs_daddr_t)(1 << (mp)->m_sectbb_log))
 #define        XFS_AGF_BLOCK(mp)       XFS_HDR_BLOCK(mp, XFS_AGF_DADDR(mp))
-#define        XFS_BUF_TO_AGF(bp)      ((xfs_agf_t *)XFS_BUF_PTR(bp))
+#define        XFS_BUF_TO_AGF(bp)      ((xfs_agf_t *)((bp)->b_addr))
 
 extern int xfs_read_agf(struct xfs_mount *mp, struct xfs_trans *tp,
                        xfs_agnumber_t agno, int flags, struct xfs_buf **bpp);
@@ -156,7 +156,7 @@ typedef struct xfs_agi {
 /* disk block (xfs_daddr_t) in the AG */
 #define XFS_AGI_DADDR(mp)      ((xfs_daddr_t)(2 << (mp)->m_sectbb_log))
 #define        XFS_AGI_BLOCK(mp)       XFS_HDR_BLOCK(mp, XFS_AGI_DADDR(mp))
-#define        XFS_BUF_TO_AGI(bp)      ((xfs_agi_t *)XFS_BUF_PTR(bp))
+#define        XFS_BUF_TO_AGI(bp)      ((xfs_agi_t *)((bp)->b_addr))
 
 extern int xfs_read_agi(struct xfs_mount *mp, struct xfs_trans *tp,
                                xfs_agnumber_t agno, struct xfs_buf **bpp);
@@ -168,7 +168,7 @@ extern int xfs_read_agi(struct xfs_mount *mp, struct xfs_trans *tp,
 #define XFS_AGFL_DADDR(mp)     ((xfs_daddr_t)(3 << (mp)->m_sectbb_log))
 #define        XFS_AGFL_BLOCK(mp)      XFS_HDR_BLOCK(mp, XFS_AGFL_DADDR(mp))
 #define XFS_AGFL_SIZE(mp)      ((mp)->m_sb.sb_sectsize / sizeof(xfs_agblock_t))
-#define        XFS_BUF_TO_AGFL(bp)     ((xfs_agfl_t *)XFS_BUF_PTR(bp))
+#define        XFS_BUF_TO_AGFL(bp)     ((xfs_agfl_t *)((bp)->b_addr))
 
 typedef struct xfs_agfl {
        __be32          agfl_bno[1];    /* actually XFS_AGFL_SIZE(mp) */
index 1e00b3e..bdd9cb5 100644 (file)
@@ -451,8 +451,7 @@ xfs_alloc_read_agfl(
                        XFS_FSS_TO_BB(mp, 1), 0, &bp);
        if (error)
                return error;
-       ASSERT(bp);
-       ASSERT(!XFS_BUF_GETERROR(bp));
+       ASSERT(!xfs_buf_geterror(bp));
        XFS_BUF_SET_VTYPE_REF(bp, B_FS_AGFL, XFS_AGFL_REF);
        *bpp = bp;
        return 0;
@@ -2116,7 +2115,7 @@ xfs_read_agf(
        if (!*bpp)
                return 0;
 
-       ASSERT(!XFS_BUF_GETERROR(*bpp));
+       ASSERT(!(*bpp)->b_error);
        agf = XFS_BUF_TO_AGF(*bpp);
 
        /*
@@ -2168,7 +2167,7 @@ xfs_alloc_read_agf(
                return error;
        if (!*bpp)
                return 0;
-       ASSERT(!XFS_BUF_GETERROR(*bpp));
+       ASSERT(!(*bpp)->b_error);
 
        agf = XFS_BUF_TO_AGF(*bpp);
        pag = xfs_perag_get(mp, agno);
index cbae424..160bcdc 100644 (file)
@@ -2121,8 +2121,7 @@ xfs_attr_rmtval_set(xfs_da_args_t *args)
 
                bp = xfs_buf_get(mp->m_ddev_targp, dblkno, blkcnt,
                                 XBF_LOCK | XBF_DONT_BLOCK);
-               ASSERT(bp);
-               ASSERT(!XFS_BUF_GETERROR(bp));
+               ASSERT(!xfs_buf_geterror(bp));
 
                tmp = (valuelen < XFS_BUF_SIZE(bp)) ? valuelen :
                                                        XFS_BUF_SIZE(bp);
index ab3e5c6..452a291 100644 (file)
@@ -3383,8 +3383,7 @@ xfs_bmap_local_to_extents(
                ASSERT(args.len == 1);
                *firstblock = args.fsbno;
                bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0);
-               memcpy((char *)XFS_BUF_PTR(bp), ifp->if_u1.if_data,
-                       ifp->if_bytes);
+               memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes);
                xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
                xfs_bmap_forkoff_reset(args.mp, ip, whichfork);
                xfs_idata_realloc(ip, -ifp->if_bytes, whichfork);
index cabf4b5..2b9fd38 100644 (file)
@@ -275,8 +275,7 @@ xfs_btree_dup_cursor(
                                return error;
                        }
                        new->bc_bufs[i] = bp;
-                       ASSERT(bp);
-                       ASSERT(!XFS_BUF_GETERROR(bp));
+                       ASSERT(!xfs_buf_geterror(bp));
                } else
                        new->bc_bufs[i] = NULL;
        }
@@ -467,8 +466,7 @@ xfs_btree_get_bufl(
        ASSERT(fsbno != NULLFSBLOCK);
        d = XFS_FSB_TO_DADDR(mp, fsbno);
        bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, lock);
-       ASSERT(bp);
-       ASSERT(!XFS_BUF_GETERROR(bp));
+       ASSERT(!xfs_buf_geterror(bp));
        return bp;
 }
 
@@ -491,8 +489,7 @@ xfs_btree_get_bufs(
        ASSERT(agbno != NULLAGBLOCK);
        d = XFS_AGB_TO_DADDR(mp, agno, agbno);
        bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, lock);
-       ASSERT(bp);
-       ASSERT(!XFS_BUF_GETERROR(bp));
+       ASSERT(!xfs_buf_geterror(bp));
        return bp;
 }
 
@@ -632,7 +629,7 @@ xfs_btree_read_bufl(
                        mp->m_bsize, lock, &bp))) {
                return error;
        }
-       ASSERT(!bp || !XFS_BUF_GETERROR(bp));
+       ASSERT(!xfs_buf_geterror(bp));
        if (bp)
                XFS_BUF_SET_VTYPE_REF(bp, B_FS_MAP, refval);
        *bpp = bp;
@@ -973,8 +970,7 @@ xfs_btree_get_buf_block(
        *bpp = xfs_trans_get_buf(cur->bc_tp, mp->m_ddev_targp, d,
                                 mp->m_bsize, flags);
 
-       ASSERT(*bpp);
-       ASSERT(!XFS_BUF_GETERROR(*bpp));
+       ASSERT(!xfs_buf_geterror(*bpp));
 
        *block = XFS_BUF_TO_BLOCK(*bpp);
        return 0;
@@ -1006,8 +1002,7 @@ xfs_btree_read_buf_block(
        if (error)
                return error;
 
-       ASSERT(*bpp != NULL);
-       ASSERT(!XFS_BUF_GETERROR(*bpp));
+       ASSERT(!xfs_buf_geterror(*bpp));
 
        xfs_btree_set_refs(cur, *bpp);
        *block = XFS_BUF_TO_BLOCK(*bpp);
index 8d05a6a..5b240de 100644 (file)
@@ -262,7 +262,7 @@ typedef struct xfs_btree_cur
 /*
  * Convert from buffer to btree block header.
  */
-#define        XFS_BUF_TO_BLOCK(bp)    ((struct xfs_btree_block *)XFS_BUF_PTR(bp))
+#define        XFS_BUF_TO_BLOCK(bp)    ((struct xfs_btree_block *)((bp)->b_addr))
 
 
 /*
similarity index 99%
rename from fs/xfs/linux-2.6/xfs_buf.c
rename to fs/xfs/xfs_buf.c
index d1fe745..c57836d 100644 (file)
@@ -596,7 +596,7 @@ _xfs_buf_read(
        bp->b_flags |= flags & (XBF_READ | XBF_ASYNC | XBF_READ_AHEAD);
 
        status = xfs_buf_iorequest(bp);
-       if (status || XFS_BUF_ISERROR(bp) || (flags & XBF_ASYNC))
+       if (status || bp->b_error || (flags & XBF_ASYNC))
                return status;
        return xfs_buf_iowait(bp);
 }
@@ -679,7 +679,6 @@ xfs_buf_read_uncached(
        /* set up the buffer for a read IO */
        XFS_BUF_SET_ADDR(bp, daddr);
        XFS_BUF_READ(bp);
-       XFS_BUF_BUSY(bp);
 
        xfsbdstrat(mp, bp);
        error = xfs_buf_iowait(bp);
@@ -1069,7 +1068,7 @@ xfs_bioerror(
        /*
         * No need to wait until the buffer is unpinned, we aren't flushing it.
         */
-       XFS_BUF_ERROR(bp, EIO);
+       xfs_buf_ioerror(bp, EIO);
 
        /*
         * We're calling xfs_buf_ioend, so delete XBF_DONE flag.
@@ -1094,7 +1093,7 @@ STATIC int
 xfs_bioerror_relse(
        struct xfs_buf  *bp)
 {
-       int64_t         fl = XFS_BUF_BFLAGS(bp);
+       int64_t         fl = bp->b_flags;
        /*
         * No need to wait until the buffer is unpinned.
         * We aren't flushing it.
@@ -1115,7 +1114,7 @@ xfs_bioerror_relse(
                 * There's no reason to mark error for
                 * ASYNC buffers.
                 */
-               XFS_BUF_ERROR(bp, EIO);
+               xfs_buf_ioerror(bp, EIO);
                XFS_BUF_FINISH_IOWAIT(bp);
        } else {
                xfs_buf_relse(bp);
@@ -1324,7 +1323,7 @@ xfs_buf_offset(
        struct page             *page;
 
        if (bp->b_flags & XBF_MAPPED)
-               return XFS_BUF_PTR(bp) + offset;
+               return bp->b_addr + offset;
 
        offset += bp->b_offset;
        page = bp->b_pages[offset >> PAGE_SHIFT];
@@ -1484,7 +1483,7 @@ xfs_setsize_buftarg_flags(
        if (set_blocksize(btp->bt_bdev, sectorsize)) {
                xfs_warn(btp->bt_mount,
                        "Cannot set_blocksize to %u on device %s\n",
-                       sectorsize, XFS_BUFTARG_NAME(btp));
+                       sectorsize, xfs_buf_target_name(btp));
                return EINVAL;
        }
 
@@ -1681,7 +1680,7 @@ xfs_buf_delwri_split(
        list_for_each_entry_safe(bp, n, dwq, b_list) {
                ASSERT(bp->b_flags & XBF_DELWRI);
 
-               if (!XFS_BUF_ISPINNED(bp) && xfs_buf_trylock(bp)) {
+               if (!xfs_buf_ispinned(bp) && xfs_buf_trylock(bp)) {
                        if (!force &&
                            time_before(jiffies, bp->b_queuetime + age)) {
                                xfs_buf_unlock(bp);
similarity index 92%
rename from fs/xfs/linux-2.6/xfs_buf.h
rename to fs/xfs/xfs_buf.h
index 6a83b46..620972b 100644 (file)
@@ -228,11 +228,15 @@ extern void xfs_buf_delwri_promote(xfs_buf_t *);
 extern int xfs_buf_init(void);
 extern void xfs_buf_terminate(void);
 
-#define xfs_buf_target_name(target)    \
-       ({ char __b[BDEVNAME_SIZE]; bdevname((target)->bt_bdev, __b); __b; })
+static inline const char *
+xfs_buf_target_name(struct xfs_buftarg *target)
+{
+       static char __b[BDEVNAME_SIZE];
+
+       return bdevname(target->bt_bdev, __b);
+}
 
 
-#define XFS_BUF_BFLAGS(bp)     ((bp)->b_flags)
 #define XFS_BUF_ZEROFLAGS(bp) \
        ((bp)->b_flags &= ~(XBF_READ|XBF_WRITE|XBF_ASYNC|XBF_DELWRI| \
                            XBF_SYNCIO|XBF_FUA|XBF_FLUSH))
@@ -251,23 +255,14 @@ void xfs_buf_stale(struct xfs_buf *bp);
 #define XFS_BUF_UNDELAYWRITE(bp)       xfs_buf_delwri_dequeue(bp)
 #define XFS_BUF_ISDELAYWRITE(bp)       ((bp)->b_flags & XBF_DELWRI)
 
-#define XFS_BUF_ERROR(bp,no)   xfs_buf_ioerror(bp,no)
-#define XFS_BUF_GETERROR(bp)   xfs_buf_geterror(bp)
-#define XFS_BUF_ISERROR(bp)    (xfs_buf_geterror(bp) ? 1 : 0)
-
 #define XFS_BUF_DONE(bp)       ((bp)->b_flags |= XBF_DONE)
 #define XFS_BUF_UNDONE(bp)     ((bp)->b_flags &= ~XBF_DONE)
 #define XFS_BUF_ISDONE(bp)     ((bp)->b_flags & XBF_DONE)
 
-#define XFS_BUF_BUSY(bp)       do { } while (0)
-#define XFS_BUF_UNBUSY(bp)     do { } while (0)
-#define XFS_BUF_ISBUSY(bp)     (1)
-
 #define XFS_BUF_ASYNC(bp)      ((bp)->b_flags |= XBF_ASYNC)
 #define XFS_BUF_UNASYNC(bp)    ((bp)->b_flags &= ~XBF_ASYNC)
 #define XFS_BUF_ISASYNC(bp)    ((bp)->b_flags & XBF_ASYNC)
 
-#define XFS_BUF_HOLD(bp)       xfs_buf_hold(bp)
 #define XFS_BUF_READ(bp)       ((bp)->b_flags |= XBF_READ)
 #define XFS_BUF_UNREAD(bp)     ((bp)->b_flags &= ~XBF_READ)
 #define XFS_BUF_ISREAD(bp)     ((bp)->b_flags & XBF_READ)
@@ -276,10 +271,6 @@ void xfs_buf_stale(struct xfs_buf *bp);
 #define XFS_BUF_UNWRITE(bp)    ((bp)->b_flags &= ~XBF_WRITE)
 #define XFS_BUF_ISWRITE(bp)    ((bp)->b_flags & XBF_WRITE)
 
-#define XFS_BUF_SET_START(bp)                  do { } while (0)
-
-#define XFS_BUF_PTR(bp)                        (xfs_caddr_t)((bp)->b_addr)
-#define XFS_BUF_SET_PTR(bp, val, cnt)  xfs_buf_associate_memory(bp, val, cnt)
 #define XFS_BUF_ADDR(bp)               ((bp)->b_bn)
 #define XFS_BUF_SET_ADDR(bp, bno)      ((bp)->b_bn = (xfs_daddr_t)(bno))
 #define XFS_BUF_OFFSET(bp)             ((bp)->b_file_offset)
@@ -299,14 +290,13 @@ xfs_buf_set_ref(
 #define XFS_BUF_SET_VTYPE_REF(bp, type, ref)   xfs_buf_set_ref(bp, ref)
 #define XFS_BUF_SET_VTYPE(bp, type)            do { } while (0)
 
-#define XFS_BUF_ISPINNED(bp)   atomic_read(&((bp)->b_pin_count))
+static inline int xfs_buf_ispinned(struct xfs_buf *bp)
+{
+       return atomic_read(&bp->b_pin_count);
+}
 
 #define XFS_BUF_FINISH_IOWAIT(bp)      complete(&bp->b_iowait);
 
-#define XFS_BUF_SET_TARGET(bp, target) ((bp)->b_target = (target))
-#define XFS_BUF_TARGET(bp)             ((bp)->b_target)
-#define XFS_BUFTARG_NAME(target)       xfs_buf_target_name(target)
-
 static inline void xfs_buf_relse(xfs_buf_t *bp)
 {
        xfs_buf_unlock(bp);
index 8849291..cac2ecf 100644 (file)
@@ -124,9 +124,9 @@ xfs_buf_item_log_check(
 
        bp = bip->bli_buf;
        ASSERT(XFS_BUF_COUNT(bp) > 0);
-       ASSERT(XFS_BUF_PTR(bp) != NULL);
+       ASSERT(bp->b_addr != NULL);
        orig = bip->bli_orig;
-       buffer = XFS_BUF_PTR(bp);
+       buffer = bp->b_addr;
        for (x = 0; x < XFS_BUF_COUNT(bp); x++) {
                if (orig[x] != buffer[x] && !btst(bip->bli_logged, x)) {
                        xfs_emerg(bp->b_mount,
@@ -371,7 +371,6 @@ xfs_buf_item_pin(
 {
        struct xfs_buf_log_item *bip = BUF_ITEM(lip);
 
-       ASSERT(XFS_BUF_ISBUSY(bip->bli_buf));
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
        ASSERT((bip->bli_flags & XFS_BLI_LOGGED) ||
               (bip->bli_flags & XFS_BLI_STALE));
@@ -479,13 +478,13 @@ xfs_buf_item_trylock(
        struct xfs_buf_log_item *bip = BUF_ITEM(lip);
        struct xfs_buf          *bp = bip->bli_buf;
 
-       if (XFS_BUF_ISPINNED(bp))
+       if (xfs_buf_ispinned(bp))
                return XFS_ITEM_PINNED;
        if (!xfs_buf_trylock(bp))
                return XFS_ITEM_LOCKED;
 
        /* take a reference to the buffer.  */
-       XFS_BUF_HOLD(bp);
+       xfs_buf_hold(bp);
 
        ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
        trace_xfs_buf_item_trylock(bip);
@@ -726,7 +725,7 @@ xfs_buf_item_init(
         * to have logged.
         */
        bip->bli_orig = (char *)kmem_alloc(XFS_BUF_COUNT(bp), KM_SLEEP);
-       memcpy(bip->bli_orig, XFS_BUF_PTR(bp), XFS_BUF_COUNT(bp));
+       memcpy(bip->bli_orig, bp->b_addr, XFS_BUF_COUNT(bp));
        bip->bli_logged = (char *)kmem_zalloc(XFS_BUF_COUNT(bp) / NBBY, KM_SLEEP);
 #endif
 
@@ -895,7 +894,6 @@ xfs_buf_attach_iodone(
 {
        xfs_log_item_t  *head_lip;
 
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(xfs_buf_islocked(bp));
 
        lip->li_cb = cb;
@@ -960,7 +958,7 @@ xfs_buf_iodone_callbacks(
        static ulong            lasttime;
        static xfs_buftarg_t    *lasttarg;
 
-       if (likely(!XFS_BUF_GETERROR(bp)))
+       if (likely(!xfs_buf_geterror(bp)))
                goto do_callbacks;
 
        /*
@@ -973,14 +971,14 @@ xfs_buf_iodone_callbacks(
                goto do_callbacks;
        }
 
-       if (XFS_BUF_TARGET(bp) != lasttarg ||
+       if (bp->b_target != lasttarg ||
            time_after(jiffies, (lasttime + 5*HZ))) {
                lasttime = jiffies;
                xfs_alert(mp, "Device %s: metadata write error block 0x%llx",
-                       XFS_BUFTARG_NAME(XFS_BUF_TARGET(bp)),
+                       xfs_buf_target_name(bp->b_target),
                      (__uint64_t)XFS_BUF_ADDR(bp));
        }
-       lasttarg = XFS_BUF_TARGET(bp);
+       lasttarg = bp->b_target;
 
        /*
         * If the write was asynchronous then no one will be looking for the
@@ -991,12 +989,11 @@ xfs_buf_iodone_callbacks(
         * around.
         */
        if (XFS_BUF_ISASYNC(bp)) {
-               XFS_BUF_ERROR(bp, 0); /* errno of 0 unsets the flag */
+               xfs_buf_ioerror(bp, 0); /* errno of 0 unsets the flag */
 
                if (!XFS_BUF_ISSTALE(bp)) {
                        XFS_BUF_DELAYWRITE(bp);
                        XFS_BUF_DONE(bp);
-                       XFS_BUF_SET_START(bp);
                }
                ASSERT(bp->b_iodone != NULL);
                trace_xfs_buf_item_iodone_async(bp, _RET_IP_);
@@ -1013,7 +1010,6 @@ xfs_buf_iodone_callbacks(
        XFS_BUF_UNDELAYWRITE(bp);
 
        trace_xfs_buf_error_relse(bp, _RET_IP_);
-       xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
 
 do_callbacks:
        xfs_buf_do_callbacks(bp);
index 5bfcb87..ee9d542 100644 (file)
@@ -2050,7 +2050,7 @@ xfs_da_do_buf(
                case 0:
                        bp = xfs_trans_get_buf(trans, mp->m_ddev_targp,
                                mappedbno, nmapped, 0);
-                       error = bp ? XFS_BUF_GETERROR(bp) : XFS_ERROR(EIO);
+                       error = bp ? bp->b_error : XFS_ERROR(EIO);
                        break;
                case 1:
                case 2:
@@ -2268,7 +2268,7 @@ xfs_da_buf_make(int nbuf, xfs_buf_t **bps)
                dabuf->nbuf = 1;
                bp = bps[0];
                dabuf->bbcount = (short)BTOBB(XFS_BUF_COUNT(bp));
-               dabuf->data = XFS_BUF_PTR(bp);
+               dabuf->data = bp->b_addr;
                dabuf->bps[0] = bp;
        } else {
                dabuf->nbuf = nbuf;
@@ -2279,7 +2279,7 @@ xfs_da_buf_make(int nbuf, xfs_buf_t **bps)
                dabuf->data = kmem_alloc(BBTOB(dabuf->bbcount), KM_SLEEP);
                for (i = off = 0; i < nbuf; i++, off += XFS_BUF_COUNT(bp)) {
                        bp = bps[i];
-                       memcpy((char *)dabuf->data + off, XFS_BUF_PTR(bp),
+                       memcpy((char *)dabuf->data + off, bp->b_addr,
                                XFS_BUF_COUNT(bp));
                }
        }
@@ -2302,8 +2302,8 @@ xfs_da_buf_clean(xfs_dabuf_t *dabuf)
                for (i = off = 0; i < dabuf->nbuf;
                                i++, off += XFS_BUF_COUNT(bp)) {
                        bp = dabuf->bps[i];
-                       memcpy(XFS_BUF_PTR(bp), (char *)dabuf->data + off,
-                               XFS_BUF_COUNT(bp));
+                       memcpy(bp->b_addr, dabuf->data + off,
+                                               XFS_BUF_COUNT(bp));
                }
        }
 }
@@ -2340,7 +2340,7 @@ xfs_da_log_buf(xfs_trans_t *tp, xfs_dabuf_t *dabuf, uint first, uint last)
 
        ASSERT(dabuf->nbuf && dabuf->data && dabuf->bbcount && dabuf->bps[0]);
        if (dabuf->nbuf == 1) {
-               ASSERT(dabuf->data == (void *)XFS_BUF_PTR(dabuf->bps[0]));
+               ASSERT(dabuf->data == dabuf->bps[0]->b_addr);
                xfs_trans_log_buf(tp, dabuf->bps[0], first, last);
                return;
        }
index dffba9b..a372163 100644 (file)
@@ -148,7 +148,7 @@ typedef enum xfs_dinode_fmt {
                be32_to_cpu((dip)->di_nextents) : \
                be16_to_cpu((dip)->di_anextents))
 
-#define        XFS_BUF_TO_DINODE(bp)   ((xfs_dinode_t *)XFS_BUF_PTR(bp))
+#define        XFS_BUF_TO_DINODE(bp)   ((xfs_dinode_t *)((bp)->b_addr))
 
 /*
  * For block and character special files the 32bit dev_t is stored at the
similarity index 98%
rename from fs/xfs/quota/xfs_dquot.c
rename to fs/xfs/xfs_dquot.c
index 837f311..db62959 100644 (file)
@@ -318,10 +318,9 @@ xfs_qm_init_dquot_blk(
        int             curid, i;
 
        ASSERT(tp);
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(xfs_buf_islocked(bp));
 
-       d = (xfs_dqblk_t *)XFS_BUF_PTR(bp);
+       d = bp->b_addr;
 
        /*
         * ID of the first dquot in the block - id's are zero based.
@@ -403,7 +402,7 @@ xfs_qm_dqalloc(
                               dqp->q_blkno,
                               mp->m_quotainfo->qi_dqchunklen,
                               0);
-       if (!bp || (error = XFS_BUF_GETERROR(bp)))
+       if (!bp || (error = xfs_buf_geterror(bp)))
                goto error1;
        /*
         * Make a chunk of dquots out of this buffer and log
@@ -534,13 +533,12 @@ xfs_qm_dqtobp(
                        return XFS_ERROR(error);
        }
 
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(xfs_buf_islocked(bp));
 
        /*
         * calculate the location of the dquot inside the buffer.
         */
-       ddq = (struct xfs_disk_dquot *)(XFS_BUF_PTR(bp) + dqp->q_bufoffset);
+       ddq = bp->b_addr + dqp->q_bufoffset;
 
        /*
         * A simple sanity check in case we got a corrupted dquot...
@@ -553,7 +551,6 @@ xfs_qm_dqtobp(
                        xfs_trans_brelse(tp, bp);
                        return XFS_ERROR(EIO);
                }
-               XFS_BUF_BUSY(bp); /* We dirtied this */
        }
 
        *O_bpp = bp;
@@ -622,7 +619,6 @@ xfs_qm_dqread(
         * this particular dquot was repaired. We still aren't afraid to
         * brelse it because we have the changes incore.
         */
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(xfs_buf_islocked(bp));
        xfs_trans_brelse(tp, bp);
 
@@ -1204,7 +1200,7 @@ xfs_qm_dqflush(
        /*
         * Calculate the location of the dquot inside the buffer.
         */
-       ddqp = (struct xfs_disk_dquot *)(XFS_BUF_PTR(bp) + dqp->q_bufoffset);
+       ddqp = bp->b_addr + dqp->q_bufoffset;
 
        /*
         * A simple sanity check in case we got a corrupted dquot..
@@ -1240,7 +1236,7 @@ xfs_qm_dqflush(
         * If the buffer is pinned then push on the log so we won't
         * get stuck waiting in the write for too long.
         */
-       if (XFS_BUF_ISPINNED(bp)) {
+       if (xfs_buf_ispinned(bp)) {
                trace_xfs_dqflush_force(dqp);
                xfs_log_force(mp, 0);
        }
@@ -1447,7 +1443,7 @@ xfs_qm_dqflock_pushbuf_wait(
                goto out_lock;
 
        if (XFS_BUF_ISDELAYWRITE(bp)) {
-               if (XFS_BUF_ISPINNED(bp))
+               if (xfs_buf_ispinned(bp))
                        xfs_log_force(mp, 0);
                xfs_buf_delwri_promote(bp);
                wake_up_process(bp->b_target->bt_task);
similarity index 100%
rename from fs/xfs/quota/xfs_dquot.h
rename to fs/xfs/xfs_dquot.h
index dd5628b..9f24ec2 100644 (file)
@@ -202,8 +202,7 @@ xfs_ialloc_inode_init(
                fbuf = xfs_trans_get_buf(tp, mp->m_ddev_targp, d,
                                         mp->m_bsize * blks_per_cluster,
                                         XBF_LOCK);
-               ASSERT(fbuf);
-               ASSERT(!XFS_BUF_GETERROR(fbuf));
+               ASSERT(!xfs_buf_geterror(fbuf));
 
                /*
                 * Initialize all inodes in this buffer and then log them.
@@ -1486,7 +1485,7 @@ xfs_read_agi(
        if (error)
                return error;
 
-       ASSERT(*bpp && !XFS_BUF_GETERROR(*bpp));
+       ASSERT(!xfs_buf_geterror(*bpp));
        agi = XFS_BUF_TO_AGI(*bpp);
 
        /*
index 2fcca4b..0239a7c 100644 (file)
@@ -2473,7 +2473,7 @@ cluster_corrupt_out:
                if (bp->b_iodone) {
                        XFS_BUF_UNDONE(bp);
                        XFS_BUF_STALE(bp);
-                       XFS_BUF_ERROR(bp,EIO);
+                       xfs_buf_ioerror(bp, EIO);
                        xfs_buf_ioend(bp, 0);
                } else {
                        XFS_BUF_STALE(bp);
@@ -2585,7 +2585,7 @@ xfs_iflush(
         * If the buffer is pinned then push on the log now so we won't
         * get stuck waiting in the write for too long.
         */
-       if (XFS_BUF_ISPINNED(bp))
+       if (xfs_buf_ispinned(bp))
                xfs_log_force(mp, 0);
 
        /*
similarity index 96%
rename from fs/xfs/linux-2.6/xfs_linux.h
rename to fs/xfs/xfs_linux.h
index d42f814..1e8a45e 100644 (file)
 # define XFS_BIG_INUMS 0
 #endif
 
-#include <xfs_types.h>
+#include "xfs_types.h"
 
-#include <kmem.h>
-#include <mrlock.h>
-#include <time.h>
-
-#include <support/uuid.h>
+#include "kmem.h"
+#include "mrlock.h"
+#include "time.h"
+#include "uuid.h"
 
 #include <linux/semaphore.h>
 #include <linux/mm.h>
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
 
-#include <xfs_vnode.h>
-#include <xfs_stats.h>
-#include <xfs_sysctl.h>
-#include <xfs_iops.h>
-#include <xfs_aops.h>
-#include <xfs_super.h>
-#include <xfs_buf.h>
-#include <xfs_message.h>
+#include "xfs_vnode.h"
+#include "xfs_stats.h"
+#include "xfs_sysctl.h"
+#include "xfs_iops.h"
+#include "xfs_aops.h"
+#include "xfs_super.h"
+#include "xfs_buf.h"
+#include "xfs_message.h"
 
 #ifdef __BIG_ENDIAN
 #define XFS_NATIVE_HOST 1
index 06ff843..3a8d4f6 100644 (file)
@@ -878,7 +878,7 @@ xlog_iodone(xfs_buf_t *bp)
        /*
         * Race to shutdown the filesystem if we see an error.
         */
-       if (XFS_TEST_ERROR((XFS_BUF_GETERROR(bp)), l->l_mp,
+       if (XFS_TEST_ERROR((xfs_buf_geterror(bp)), l->l_mp,
                        XFS_ERRTAG_IODONE_IOERR, XFS_RANDOM_IODONE_IOERR)) {
                xfs_ioerror_alert("xlog_iodone", l->l_mp, bp, XFS_BUF_ADDR(bp));
                XFS_BUF_STALE(bp);
@@ -1051,7 +1051,6 @@ xlog_alloc_log(xfs_mount_t        *mp,
        if (!bp)
                goto out_free_log;
        bp->b_iodone = xlog_iodone;
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(xfs_buf_islocked(bp));
        log->l_xbuf = bp;
 
@@ -1108,7 +1107,6 @@ xlog_alloc_log(xfs_mount_t        *mp,
                iclog->ic_callback_tail = &(iclog->ic_callback);
                iclog->ic_datap = (char *)iclog->ic_data + log->l_iclog_hsize;
 
-               ASSERT(XFS_BUF_ISBUSY(iclog->ic_bp));
                ASSERT(xfs_buf_islocked(iclog->ic_bp));
                init_waitqueue_head(&iclog->ic_force_wait);
                init_waitqueue_head(&iclog->ic_write_wait);
@@ -1248,7 +1246,7 @@ xlog_bdstrat(
        struct xlog_in_core     *iclog = bp->b_fspriv;
 
        if (iclog->ic_state & XLOG_STATE_IOERROR) {
-               XFS_BUF_ERROR(bp, EIO);
+               xfs_buf_ioerror(bp, EIO);
                XFS_BUF_STALE(bp);
                xfs_buf_ioend(bp, 0);
                /*
@@ -1355,7 +1353,6 @@ xlog_sync(xlog_t          *log,
        XFS_BUF_SET_COUNT(bp, count);
        bp->b_fspriv = iclog;
        XFS_BUF_ZEROFLAGS(bp);
-       XFS_BUF_BUSY(bp);
        XFS_BUF_ASYNC(bp);
        bp->b_flags |= XBF_SYNCIO;
 
@@ -1398,16 +1395,15 @@ xlog_sync(xlog_t                *log,
        if (split) {
                bp = iclog->ic_log->l_xbuf;
                XFS_BUF_SET_ADDR(bp, 0);             /* logical 0 */
-               XFS_BUF_SET_PTR(bp, (xfs_caddr_t)((__psint_t)&(iclog->ic_header)+
-                                           (__psint_t)count), split);
+               xfs_buf_associate_memory(bp,
+                               (char *)&iclog->ic_header + count, split);
                bp->b_fspriv = iclog;
                XFS_BUF_ZEROFLAGS(bp);
-               XFS_BUF_BUSY(bp);
                XFS_BUF_ASYNC(bp);
                bp->b_flags |= XBF_SYNCIO;
                if (log->l_mp->m_flags & XFS_MOUNT_BARRIER)
                        bp->b_flags |= XBF_FUA;
-               dptr = XFS_BUF_PTR(bp);
+               dptr = bp->b_addr;
                /*
                 * Bump the cycle numbers at the start of each block
                 * since this part of the buffer is at the start of
index 052a2c0..a199dbc 100644 (file)
@@ -147,7 +147,7 @@ xlog_align(
        xfs_daddr_t     offset = blk_no & ((xfs_daddr_t)log->l_sectBBsize - 1);
 
        ASSERT(BBTOB(offset + nbblks) <= XFS_BUF_SIZE(bp));
-       return XFS_BUF_PTR(bp) + BBTOB(offset);
+       return bp->b_addr + BBTOB(offset);
 }
 
 
@@ -178,9 +178,7 @@ xlog_bread_noalign(
 
        XFS_BUF_SET_ADDR(bp, log->l_logBBstart + blk_no);
        XFS_BUF_READ(bp);
-       XFS_BUF_BUSY(bp);
        XFS_BUF_SET_COUNT(bp, BBTOB(nbblks));
-       XFS_BUF_SET_TARGET(bp, log->l_mp->m_logdev_targp);
 
        xfsbdstrat(log->l_mp, bp);
        error = xfs_buf_iowait(bp);
@@ -220,18 +218,18 @@ xlog_bread_offset(
        xfs_buf_t       *bp,
        xfs_caddr_t     offset)
 {
-       xfs_caddr_t     orig_offset = XFS_BUF_PTR(bp);
+       xfs_caddr_t     orig_offset = bp->b_addr;
        int             orig_len = bp->b_buffer_length;
        int             error, error2;
 
-       error = XFS_BUF_SET_PTR(bp, offset, BBTOB(nbblks));
+       error = xfs_buf_associate_memory(bp, offset, BBTOB(nbblks));
        if (error)
                return error;
 
        error = xlog_bread_noalign(log, blk_no, nbblks, bp);
 
        /* must reset buffer pointer even on error */
-       error2 = XFS_BUF_SET_PTR(bp, orig_offset, orig_len);
+       error2 = xfs_buf_associate_memory(bp, orig_offset, orig_len);
        if (error)
                return error;
        return error2;
@@ -266,11 +264,9 @@ xlog_bwrite(
 
        XFS_BUF_SET_ADDR(bp, log->l_logBBstart + blk_no);
        XFS_BUF_ZEROFLAGS(bp);
-       XFS_BUF_BUSY(bp);
-       XFS_BUF_HOLD(bp);
+       xfs_buf_hold(bp);
        xfs_buf_lock(bp);
        XFS_BUF_SET_COUNT(bp, BBTOB(nbblks));
-       XFS_BUF_SET_TARGET(bp, log->l_mp->m_logdev_targp);
 
        if ((error = xfs_bwrite(log->l_mp, bp)))
                xfs_ioerror_alert("xlog_bwrite", log->l_mp,
@@ -360,7 +356,7 @@ STATIC void
 xlog_recover_iodone(
        struct xfs_buf  *bp)
 {
-       if (XFS_BUF_GETERROR(bp)) {
+       if (bp->b_error) {
                /*
                 * We're not going to bother about retrying
                 * this during recovery. One strike!
@@ -1262,7 +1258,7 @@ xlog_write_log_records(
                 */
                ealign = round_down(end_block, sectbb);
                if (j == 0 && (start_block + endcount > ealign)) {
-                       offset = XFS_BUF_PTR(bp) + BBTOB(ealign - start_block);
+                       offset = bp->b_addr + BBTOB(ealign - start_block);
                        error = xlog_bread_offset(log, ealign, sectbb,
                                                        bp, offset);
                        if (error)
@@ -2135,15 +2131,16 @@ xlog_recover_buffer_pass2(
 
        bp = xfs_buf_read(mp->m_ddev_targp, buf_f->blf_blkno, buf_f->blf_len,
                          buf_flags);
-       if (XFS_BUF_ISERROR(bp)) {
+       if (!bp)
+               return XFS_ERROR(ENOMEM);
+       error = bp->b_error;
+       if (error) {
                xfs_ioerror_alert("xlog_recover_do..(read#1)", mp,
                                  bp, buf_f->blf_blkno);
-               error = XFS_BUF_GETERROR(bp);
                xfs_buf_relse(bp);
                return error;
        }
 
-       error = 0;
        if (buf_f->blf_flags & XFS_BLF_INODE_BUF) {
                error = xlog_recover_do_inode_buffer(mp, item, bp, buf_f);
        } else if (buf_f->blf_flags &
@@ -2227,14 +2224,17 @@ xlog_recover_inode_pass2(
 
        bp = xfs_buf_read(mp->m_ddev_targp, in_f->ilf_blkno, in_f->ilf_len,
                          XBF_LOCK);
-       if (XFS_BUF_ISERROR(bp)) {
+       if (!bp) {
+               error = ENOMEM;
+               goto error;
+       }
+       error = bp->b_error;
+       if (error) {
                xfs_ioerror_alert("xlog_recover_do..(read#2)", mp,
                                  bp, in_f->ilf_blkno);
-               error = XFS_BUF_GETERROR(bp);
                xfs_buf_relse(bp);
                goto error;
        }
-       error = 0;
        ASSERT(in_f->ilf_fields & XFS_ILOG_CORE);
        dip = (xfs_dinode_t *)xfs_buf_offset(bp, in_f->ilf_boffset);
 
@@ -3437,7 +3437,7 @@ xlog_do_recovery_pass(
                        /*
                         * Check for header wrapping around physical end-of-log
                         */
-                       offset = XFS_BUF_PTR(hbp);
+                       offset = hbp->b_addr;
                        split_hblks = 0;
                        wrapped_hblks = 0;
                        if (blk_no + hblks <= log->l_logBBsize) {
@@ -3497,7 +3497,7 @@ xlog_do_recovery_pass(
                        } else {
                                /* This log record is split across the
                                 * physical end of log */
-                               offset = XFS_BUF_PTR(dbp);
+                               offset = dbp->b_addr;
                                split_bblks = 0;
                                if (blk_no != log->l_logBBsize) {
                                        /* some data is before the physical
index 092e16a..0081657 100644 (file)
@@ -1615,7 +1615,7 @@ xfs_unmountfs_writesb(xfs_mount_t *mp)
                XFS_BUF_UNDELAYWRITE(sbp);
                XFS_BUF_WRITE(sbp);
                XFS_BUF_UNASYNC(sbp);
-               ASSERT(XFS_BUF_TARGET(sbp) == mp->m_ddev_targp);
+               ASSERT(sbp->b_target == mp->m_ddev_targp);
                xfsbdstrat(mp, sbp);
                error = xfs_buf_iowait(sbp);
                if (error)
@@ -1938,7 +1938,7 @@ xfs_getsb(
                xfs_buf_lock(bp);
        }
 
-       XFS_BUF_HOLD(bp);
+       xfs_buf_hold(bp);
        ASSERT(XFS_BUF_ISDONE(bp));
        return bp;
 }
similarity index 99%
rename from fs/xfs/quota/xfs_qm.c
rename to fs/xfs/xfs_qm.c
index 46e54ad..9a0aa76 100644 (file)
@@ -1240,7 +1240,7 @@ xfs_qm_reset_dqcounts(
        do_div(j, sizeof(xfs_dqblk_t));
        ASSERT(mp->m_quotainfo->qi_dqperchunk == j);
 #endif
-       ddq = (xfs_disk_dquot_t *)XFS_BUF_PTR(bp);
+       ddq = bp->b_addr;
        for (j = 0; j < mp->m_quotainfo->qi_dqperchunk; j++) {
                /*
                 * Do a sanity check, and if needed, repair the dqblk. Don't
similarity index 100%
rename from fs/xfs/quota/xfs_qm.h
rename to fs/xfs/xfs_qm.h
similarity index 99%
rename from fs/xfs/linux-2.6/xfs_quotaops.c
rename to fs/xfs/xfs_quotaops.c
index 29b9d64..7e76f53 100644 (file)
@@ -25,7 +25,7 @@
 #include "xfs_trans.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_inode.h"
-#include "quota/xfs_qm.h"
+#include "xfs_qm.h"
 #include <linux/quota.h>
 
 
index 8f76fdf..35561a5 100644 (file)
@@ -168,7 +168,7 @@ error_cancel:
                                xfs_trans_cancel(tp, cancelflags);
                                goto error;
                        }
-                       memset(XFS_BUF_PTR(bp), 0, mp->m_sb.sb_blocksize);
+                       memset(bp->b_addr, 0, mp->m_sb.sb_blocksize);
                        xfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1);
                        /*
                         * Commit the transaction.
@@ -883,7 +883,7 @@ xfs_rtbuf_get(
        if (error) {
                return error;
        }
-       ASSERT(bp && !XFS_BUF_GETERROR(bp));
+       ASSERT(!xfs_buf_geterror(bp));
        *bpp = bp;
        return 0;
 }
@@ -943,7 +943,7 @@ xfs_rtcheck_range(
        if (error) {
                return error;
        }
-       bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp);
+       bufp = bp->b_addr;
        /*
         * Compute the starting word's address, and starting bit.
         */
@@ -994,7 +994,7 @@ xfs_rtcheck_range(
                        if (error) {
                                return error;
                        }
-                       b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp);
+                       b = bufp = bp->b_addr;
                        word = 0;
                } else {
                        /*
@@ -1040,7 +1040,7 @@ xfs_rtcheck_range(
                        if (error) {
                                return error;
                        }
-                       b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp);
+                       b = bufp = bp->b_addr;
                        word = 0;
                } else {
                        /*
@@ -1158,7 +1158,7 @@ xfs_rtfind_back(
        if (error) {
                return error;
        }
-       bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp);
+       bufp = bp->b_addr;
        /*
         * Get the first word's index & point to it.
         */
@@ -1210,7 +1210,7 @@ xfs_rtfind_back(
                        if (error) {
                                return error;
                        }
-                       bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp);
+                       bufp = bp->b_addr;
                        word = XFS_BLOCKWMASK(mp);
                        b = &bufp[word];
                } else {
@@ -1256,7 +1256,7 @@ xfs_rtfind_back(
                        if (error) {
                                return error;
                        }
-                       bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp);
+                       bufp = bp->b_addr;
                        word = XFS_BLOCKWMASK(mp);
                        b = &bufp[word];
                } else {
@@ -1333,7 +1333,7 @@ xfs_rtfind_forw(
        if (error) {
                return error;
        }
-       bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp);
+       bufp = bp->b_addr;
        /*
         * Get the first word's index & point to it.
         */
@@ -1384,7 +1384,7 @@ xfs_rtfind_forw(
                        if (error) {
                                return error;
                        }
-                       b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp);
+                       b = bufp = bp->b_addr;
                        word = 0;
                } else {
                        /*
@@ -1429,7 +1429,7 @@ xfs_rtfind_forw(
                        if (error) {
                                return error;
                        }
-                       b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp);
+                       b = bufp = bp->b_addr;
                        word = 0;
                } else {
                        /*
@@ -1649,7 +1649,7 @@ xfs_rtmodify_range(
        if (error) {
                return error;
        }
-       bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp);
+       bufp = bp->b_addr;
        /*
         * Compute the starting word's address, and starting bit.
         */
@@ -1694,7 +1694,7 @@ xfs_rtmodify_range(
                        if (error) {
                                return error;
                        }
-                       first = b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp);
+                       first = b = bufp = bp->b_addr;
                        word = 0;
                } else {
                        /*
@@ -1734,7 +1734,7 @@ xfs_rtmodify_range(
                        if (error) {
                                return error;
                        }
-                       first = b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp);
+                       first = b = bufp = bp->b_addr;
                        word = 0;
                } else {
                        /*
@@ -1832,8 +1832,8 @@ xfs_rtmodify_summary(
         */
        sp = XFS_SUMPTR(mp, bp, so);
        *sp += delta;
-       xfs_trans_log_buf(tp, bp, (uint)((char *)sp - (char *)XFS_BUF_PTR(bp)),
-               (uint)((char *)sp - (char *)XFS_BUF_PTR(bp) + sizeof(*sp) - 1));
+       xfs_trans_log_buf(tp, bp, (uint)((char *)sp - (char *)bp->b_addr),
+               (uint)((char *)sp - (char *)bp->b_addr + sizeof(*sp) - 1));
        return 0;
 }
 
index 09e1f4f..f7f3a35 100644 (file)
@@ -47,7 +47,7 @@ struct xfs_trans;
 #define        XFS_SUMOFFSTOBLOCK(mp,s)        \
        (((s) * (uint)sizeof(xfs_suminfo_t)) >> (mp)->m_sb.sb_blocklog)
 #define        XFS_SUMPTR(mp,bp,so)    \
-       ((xfs_suminfo_t *)((char *)XFS_BUF_PTR(bp) + \
+       ((xfs_suminfo_t *)((bp)->b_addr + \
                (((so) * (uint)sizeof(xfs_suminfo_t)) & XFS_BLOCKMASK(mp))))
 
 #define        XFS_BITTOBLOCK(mp,bi)   ((bi) >> (mp)->m_blkbit_log)
index d6d6fdf..c96a8a0 100644 (file)
@@ -104,9 +104,9 @@ xfs_ioerror_alert(
        xfs_alert(mp,
                 "I/O error occurred: meta-data dev %s block 0x%llx"
                 "       (\"%s\") error %d buf count %zd",
-               XFS_BUFTARG_NAME(XFS_BUF_TARGET(bp)),
+               xfs_buf_target_name(bp->b_target),
                (__uint64_t)blkno, func,
-               XFS_BUF_GETERROR(bp), XFS_BUF_COUNT(bp));
+               bp->b_error, XFS_BUF_COUNT(bp));
 }
 
 /*
@@ -137,8 +137,8 @@ xfs_read_buf(
        bp = xfs_buf_read(target, blkno, len, flags);
        if (!bp)
                return XFS_ERROR(EIO);
-       error = XFS_BUF_GETERROR(bp);
-       if (bp && !error && !XFS_FORCED_SHUTDOWN(mp)) {
+       error = bp->b_error;
+       if (!error && !XFS_FORCED_SHUTDOWN(mp)) {
                *bpp = bp;
        } else {
                *bpp = NULL;
index 1eb2ba5..cb6ae71 100644 (file)
@@ -509,7 +509,7 @@ static inline int xfs_sb_version_hasprojid32bit(xfs_sb_t *sbp)
 
 #define XFS_SB_DADDR           ((xfs_daddr_t)0) /* daddr in filesystem/ag */
 #define        XFS_SB_BLOCK(mp)        XFS_HDR_BLOCK(mp, XFS_SB_DADDR)
-#define XFS_BUF_TO_SBP(bp)     ((xfs_dsb_t *)XFS_BUF_PTR(bp))
+#define XFS_BUF_TO_SBP(bp)     ((xfs_dsb_t *)((bp)->b_addr))
 
 #define        XFS_HDR_BLOCK(mp,d)     ((xfs_agblock_t)XFS_BB_TO_FSBT(mp,d))
 #define        XFS_DADDR_TO_FSB(mp,d)  XFS_AGB_TO_FSB(mp, \
similarity index 99%
rename from fs/xfs/linux-2.6/xfs_sync.c
rename to fs/xfs/xfs_sync.c
index e4c938a..4604f90 100644 (file)
@@ -332,7 +332,7 @@ xfs_sync_fsdata(
         * between there and here.
         */
        bp = xfs_getsb(mp, 0);
-       if (XFS_BUF_ISPINNED(bp))
+       if (xfs_buf_ispinned(bp))
                xfs_log_force(mp, 0);
 
        return xfs_bwrite(mp, bp);
similarity index 96%
rename from fs/xfs/linux-2.6/xfs_trace.c
rename to fs/xfs/xfs_trace.c
index 88d25d4..9010ce8 100644 (file)
@@ -43,8 +43,8 @@
 #include "xfs_quota.h"
 #include "xfs_iomap.h"
 #include "xfs_aops.h"
-#include "quota/xfs_dquot_item.h"
-#include "quota/xfs_dquot.h"
+#include "xfs_dquot_item.h"
+#include "xfs_dquot.h"
 #include "xfs_log_recover.h"
 #include "xfs_inode_item.h"
 
index 43233e9..c15aa29 100644 (file)
@@ -299,7 +299,7 @@ xfs_trans_ail_cursor_last(
  * Splice the log item list into the AIL at the given LSN. We splice to the
  * tail of the given LSN to maintain insert order for push traversals. The
  * cursor is optional, allowing repeated updates to the same LSN to avoid
- * repeated traversals.
+ * repeated traversals.  This should not be called with an empty list.
  */
 static void
 xfs_ail_splice(
@@ -308,50 +308,39 @@ xfs_ail_splice(
        struct list_head        *list,
        xfs_lsn_t               lsn)
 {
-       struct xfs_log_item     *lip = cur ? cur->item : NULL;
-       struct xfs_log_item     *next_lip;
+       struct xfs_log_item     *lip;
+
+       ASSERT(!list_empty(list));
 
        /*
-        * Get a new cursor if we don't have a placeholder or the existing one
-        * has been invalidated.
+        * Use the cursor to determine the insertion point if one is
+        * provided.  If not, or if the one we got is not valid,
+        * find the place in the AIL where the items belong.
         */
-       if (!lip || (__psint_t)lip & 1) {
+       lip = cur ? cur->item : NULL;
+       if (!lip || (__psint_t) lip & 1)
                lip = __xfs_trans_ail_cursor_last(ailp, lsn);
 
-               if (!lip) {
-                       /* The list is empty, so just splice and return.  */
-                       if (cur)
-                               cur->item = NULL;
-                       list_splice(list, &ailp->xa_ail);
-                       return;
-               }
-       }
+       /*
+        * If a cursor is provided, we know we're processing the AIL
+        * in lsn order, and future items to be spliced in will
+        * follow the last one being inserted now.  Update the
+        * cursor to point to that last item, now while we have a
+        * reliable pointer to it.
+        */
+       if (cur)
+               cur->item = list_entry(list->prev, struct xfs_log_item, li_ail);
 
        /*
-        * Our cursor points to the item we want to insert _after_, so we have
-        * to update the cursor to point to the end of the list we are splicing
-        * in so that it points to the correct location for the next splice.
-        * i.e. before the splice
-        *
-        *  lsn -> lsn -> lsn + x -> lsn + x ...
-        *          ^
-        *          | cursor points here
-        *
-        * After the splice we have:
-        *
-        *  lsn -> lsn -> lsn -> lsn -> .... -> lsn -> lsn + x -> lsn + x ...
-        *          ^                            ^
-        *          | cursor points here         | needs to move here
-        *
-        * So we set the cursor to the last item in the list to be spliced
-        * before we execute the splice, resulting in the cursor pointing to
-        * the correct item after the splice occurs.
+        * Finally perform the splice.  Unless the AIL was empty,
+        * lip points to the item in the AIL _after_ which the new
+        * items should go.  If lip is null the AIL was empty, so
+        * the new items go at the head of the AIL.
         */
-       if (cur) {
-               next_lip = list_entry(list->prev, struct xfs_log_item, li_ail);
-               cur->item = next_lip;
-       }
-       list_splice(list, &lip->li_ail);
+       if (lip)
+               list_splice(list, &lip->li_ail);
+       else
+               list_splice(list, &ailp->xa_ail);
 }
 
 /*
@@ -682,6 +671,7 @@ xfs_trans_ail_update_bulk(
        int                     i;
        LIST_HEAD(tmp);
 
+       ASSERT(nr_items > 0);           /* Not required, but true. */
        mlip = xfs_ail_min(ailp);
 
        for (i = 0; i < nr_items; i++) {
@@ -701,7 +691,8 @@ xfs_trans_ail_update_bulk(
                list_add(&lip->li_ail, &tmp);
        }
 
-       xfs_ail_splice(ailp, cur, &tmp, lsn);
+       if (!list_empty(&tmp))
+               xfs_ail_splice(ailp, cur, &tmp, lsn);
 
        if (!mlip_changed) {
                spin_unlock(&ailp->xa_lock);
index 15584fc..137e2b9 100644 (file)
@@ -54,7 +54,7 @@ xfs_trans_buf_item_match(
        list_for_each_entry(lidp, &tp->t_items, lid_trans) {
                blip = (struct xfs_buf_log_item *)lidp->lid_item;
                if (blip->bli_item.li_type == XFS_LI_BUF &&
-                   XFS_BUF_TARGET(blip->bli_buf) == target &&
+                   blip->bli_buf->b_target == target &&
                    XFS_BUF_ADDR(blip->bli_buf) == blkno &&
                    XFS_BUF_COUNT(blip->bli_buf) == len)
                        return blip->bli_buf;
@@ -80,7 +80,6 @@ _xfs_trans_bjoin(
 {
        struct xfs_buf_log_item *bip;
 
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(bp->b_transp == NULL);
 
        /*
@@ -194,7 +193,7 @@ xfs_trans_get_buf(xfs_trans_t       *tp,
                return NULL;
        }
 
-       ASSERT(!XFS_BUF_GETERROR(bp));
+       ASSERT(!bp->b_error);
 
        _xfs_trans_bjoin(tp, bp, 1);
        trace_xfs_trans_get_buf(bp->b_fspriv);
@@ -293,10 +292,10 @@ xfs_trans_read_buf(
                        return (flags & XBF_TRYLOCK) ?
                                        EAGAIN : XFS_ERROR(ENOMEM);
 
-               if (XFS_BUF_GETERROR(bp) != 0) {
+               if (bp->b_error) {
+                       error = bp->b_error;
                        xfs_ioerror_alert("xfs_trans_read_buf", mp,
                                          bp, blkno);
-                       error = XFS_BUF_GETERROR(bp);
                        xfs_buf_relse(bp);
                        return error;
                }
@@ -330,7 +329,7 @@ xfs_trans_read_buf(
                ASSERT(xfs_buf_islocked(bp));
                ASSERT(bp->b_transp == tp);
                ASSERT(bp->b_fspriv != NULL);
-               ASSERT((XFS_BUF_ISERROR(bp)) == 0);
+               ASSERT(!bp->b_error);
                if (!(XFS_BUF_ISDONE(bp))) {
                        trace_xfs_trans_read_buf_io(bp, _RET_IP_);
                        ASSERT(!XFS_BUF_ISASYNC(bp));
@@ -386,10 +385,9 @@ xfs_trans_read_buf(
                return (flags & XBF_TRYLOCK) ?
                                        0 : XFS_ERROR(ENOMEM);
        }
-       if (XFS_BUF_GETERROR(bp) != 0) {
-           XFS_BUF_SUPER_STALE(bp);
-               error = XFS_BUF_GETERROR(bp);
-
+       if (bp->b_error) {
+               error = bp->b_error;
+               XFS_BUF_SUPER_STALE(bp);
                xfs_ioerror_alert("xfs_trans_read_buf", mp,
                                  bp, blkno);
                if (tp->t_flags & XFS_TRANS_DIRTY)
@@ -430,7 +428,7 @@ shutdown_abort:
        if (XFS_BUF_ISSTALE(bp) && XFS_BUF_ISDELAYWRITE(bp))
                xfs_notice(mp, "about to pop assert, bp == 0x%p", bp);
 #endif
-       ASSERT((XFS_BUF_BFLAGS(bp) & (XBF_STALE|XBF_DELWRI)) !=
+       ASSERT((bp->b_flags & (XBF_STALE|XBF_DELWRI)) !=
                                     (XBF_STALE|XBF_DELWRI));
 
        trace_xfs_trans_read_buf_shut(bp, _RET_IP_);
@@ -581,7 +579,6 @@ xfs_trans_bhold(xfs_trans_t *tp,
 {
        xfs_buf_log_item_t      *bip = bp->b_fspriv;
 
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(bp->b_transp == tp);
        ASSERT(bip != NULL);
        ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
@@ -602,7 +599,6 @@ xfs_trans_bhold_release(xfs_trans_t *tp,
 {
        xfs_buf_log_item_t      *bip = bp->b_fspriv;
 
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(bp->b_transp == tp);
        ASSERT(bip != NULL);
        ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
@@ -631,7 +627,6 @@ xfs_trans_log_buf(xfs_trans_t       *tp,
 {
        xfs_buf_log_item_t      *bip = bp->b_fspriv;
 
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(bp->b_transp == tp);
        ASSERT(bip != NULL);
        ASSERT((first <= last) && (last < XFS_BUF_COUNT(bp)));
@@ -702,7 +697,6 @@ xfs_trans_binval(
 {
        xfs_buf_log_item_t      *bip = bp->b_fspriv;
 
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(bp->b_transp == tp);
        ASSERT(bip != NULL);
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
@@ -774,7 +768,6 @@ xfs_trans_inode_buf(
 {
        xfs_buf_log_item_t      *bip = bp->b_fspriv;
 
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(bp->b_transp == tp);
        ASSERT(bip != NULL);
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
@@ -798,7 +791,6 @@ xfs_trans_stale_inode_buf(
 {
        xfs_buf_log_item_t      *bip = bp->b_fspriv;
 
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(bp->b_transp == tp);
        ASSERT(bip != NULL);
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
@@ -823,7 +815,6 @@ xfs_trans_inode_alloc_buf(
 {
        xfs_buf_log_item_t      *bip = bp->b_fspriv;
 
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(bp->b_transp == tp);
        ASSERT(bip != NULL);
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
@@ -851,7 +842,6 @@ xfs_trans_dquot_buf(
 {
        xfs_buf_log_item_t      *bip = bp->b_fspriv;
 
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(bp->b_transp == tp);
        ASSERT(bip != NULL);
        ASSERT(type == XFS_BLF_UDQUOT_BUF ||
index 9322e13..51fc429 100644 (file)
@@ -83,7 +83,9 @@ xfs_readlink_bmap(
 
                bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt),
                                  XBF_LOCK | XBF_MAPPED | XBF_DONT_BLOCK);
-               error = XFS_BUF_GETERROR(bp);
+               if (!bp)
+                       return XFS_ERROR(ENOMEM);
+               error = bp->b_error;
                if (error) {
                        xfs_ioerror_alert("xfs_readlink",
                                  ip->i_mount, bp, XFS_BUF_ADDR(bp));
@@ -94,7 +96,7 @@ xfs_readlink_bmap(
                        byte_cnt = pathlen;
                pathlen -= byte_cnt;
 
-               memcpy(link, XFS_BUF_PTR(bp), byte_cnt);
+               memcpy(link, bp->b_addr, byte_cnt);
                xfs_buf_relse(bp);
        }
 
@@ -1648,13 +1650,13 @@ xfs_symlink(
                        byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
                        bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d,
                                               BTOBB(byte_cnt), 0);
-                       ASSERT(bp && !XFS_BUF_GETERROR(bp));
+                       ASSERT(!xfs_buf_geterror(bp));
                        if (pathlen < byte_cnt) {
                                byte_cnt = pathlen;
                        }
                        pathlen -= byte_cnt;
 
-                       memcpy(XFS_BUF_PTR(bp), cur_chunk, byte_cnt);
+                       memcpy(bp->b_addr, cur_chunk, byte_cnt);
                        cur_chunk += byte_cnt;
 
                        xfs_trans_log_buf(tp, bp, 0, byte_cnt - 1);
@@ -1999,7 +2001,7 @@ xfs_zero_remaining_bytes(
                                          mp, bp, XFS_BUF_ADDR(bp));
                        break;
                }
-               memset(XFS_BUF_PTR(bp) +
+               memset(bp->b_addr +
                        (offset - XFS_FSB_TO_B(mp, imap.br_startoff)),
                      0, lastoffset - offset + 1);
                XFS_BUF_UNDONE(bp);
index 3090471..e49c36d 100644 (file)
@@ -128,7 +128,7 @@ extern int is_dock_device(acpi_handle handle);
 extern int register_dock_notifier(struct notifier_block *nb);
 extern void unregister_dock_notifier(struct notifier_block *nb);
 extern int register_hotplug_dock_device(acpi_handle handle,
-                                       struct acpi_dock_ops *ops,
+                                       const struct acpi_dock_ops *ops,
                                        void *context);
 extern void unregister_hotplug_dock_device(acpi_handle handle);
 #else
index 2ed0a84..f554a93 100644 (file)
@@ -47,7 +47,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20110413
+#define ACPI_CA_VERSION                 0x20110623
 
 #include "actypes.h"
 #include "actbl.h"
@@ -69,6 +69,7 @@ extern u32 acpi_gbl_trace_flags;
 extern u32 acpi_gbl_enable_aml_debug_object;
 extern u8 acpi_gbl_copy_dsdt_locally;
 extern u8 acpi_gbl_truncate_io_addresses;
+extern u8 acpi_gbl_disable_auto_repair;
 
 extern u32 acpi_current_gpe_count;
 extern struct acpi_table_fadt acpi_gbl_FADT;
index e67b523..51a527d 100644 (file)
 
 extern int hest_disable;
 extern int erst_disable;
+#ifdef CONFIG_ACPI_APEI_GHES
+extern int ghes_disable;
+#else
+#define ghes_disable 1
+#endif
 
 #ifdef CONFIG_ACPI_APEI
 void __init acpi_hest_init(void);
index ba4928c..67055f1 100644 (file)
@@ -337,7 +337,7 @@ extern struct cpuidle_driver acpi_idle_driver;
 
 /* in processor_thermal.c */
 int acpi_processor_get_limit_info(struct acpi_processor *pr);
-extern struct thermal_cooling_device_ops processor_cooling_ops;
+extern const struct thermal_cooling_device_ops processor_cooling_ops;
 #ifdef CONFIG_CPU_FREQ
 void acpi_thermal_cpufreq_init(void);
 void acpi_thermal_cpufreq_exit(void);
index fb2d63f..aea9e45 100644 (file)
@@ -39,7 +39,7 @@
 })
 
 #define __page_to_pfn(pg)                                              \
-({     struct page *__pg = (pg);                                       \
+({     const struct page *__pg = (pg);                                 \
        struct pglist_data *__pgdat = NODE_DATA(page_to_nid(__pg));     \
        (unsigned long)(__pg - __pgdat->node_mem_map) +                 \
         __pgdat->node_start_pfn;                                       \
@@ -57,7 +57,7 @@
  * section[i].section_mem_map == mem_map's address - start_pfn;
  */
 #define __page_to_pfn(pg)                                      \
-({     struct page *__pg = (pg);                               \
+({     const struct page *__pg = (pg);                         \
        int __sec = page_to_section(__pg);                      \
        (unsigned long)(__pg - __section_mem_map_addr(__nr_to_section(__sec))); \
 })
index 33d12f8..44335e5 100644 (file)
@@ -205,6 +205,8 @@ struct drm_display_info {
        enum subpixel_order subpixel_order;
        u32 color_formats;
 
+       u8 cea_rev;
+
        char *raw_edid; /* if any */
 };
 
@@ -802,6 +804,7 @@ extern struct drm_display_mode *drm_gtf_mode_complex(struct drm_device *dev,
 extern int drm_add_modes_noedid(struct drm_connector *connector,
                                int hdisplay, int vdisplay);
 
+extern int drm_edid_header_is_valid(const u8 *raw_edid);
 extern bool drm_edid_is_valid(struct edid *edid);
 struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
                                           int hsize, int vsize, int fresh);
index c4d6dbf..28c0d11 100644 (file)
@@ -237,7 +237,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_GEM_GET_APERTURE        DRM_IOR  (DRM_COMMAND_BASE + DRM_I915_GEM_GET_APERTURE, struct drm_i915_gem_get_aperture)
 #define DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GET_PIPE_FROM_CRTC_ID, struct drm_i915_get_pipe_from_crtc_id)
 #define DRM_IOCTL_I915_GEM_MADVISE     DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MADVISE, struct drm_i915_gem_madvise)
-#define DRM_IOCTL_I915_OVERLAY_PUT_IMAGE       DRM_IOW(DRM_COMMAND_BASE + DRM_IOCTL_I915_OVERLAY_ATTRS, struct drm_intel_overlay_put_image)
+#define DRM_IOCTL_I915_OVERLAY_PUT_IMAGE       DRM_IOW(DRM_COMMAND_BASE + DRM_I915_OVERLAY_PUT_IMAGE, struct drm_intel_overlay_put_image)
 #define DRM_IOCTL_I915_OVERLAY_ATTRS   DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_OVERLAY_ATTRS, struct drm_intel_overlay_attrs)
 
 /* Allow drivers to submit batchbuffers directly to hardware, relying
index 1deb2a7..6001b4d 100644 (file)
@@ -238,7 +238,6 @@ extern int acpi_paddr_to_node(u64 start_addr, u64 size);
 extern int pnpacpi_disabled;
 
 #define PXM_INVAL      (-1)
-#define NID_INVAL      (-1)
 
 int acpi_check_resource_conflict(const struct resource *res);
 
@@ -280,6 +279,8 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context);
 #define OSC_SB_CPUHP_OST_SUPPORT       8
 #define OSC_SB_APEI_SUPPORT            16
 
+extern bool osc_sb_apei_support_acked;
+
 /* PCI defined _OSC bits */
 /* _OSC DW1 Definition (OS Support Fields) */
 #define OSC_EXT_PCI_CONFIG_SUPPORT             1
index 8414de2..544abdb 100644 (file)
@@ -51,5 +51,8 @@ static inline int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev)
 
 extern void cper_print_aer(const char *prefix, int cper_severity,
                           struct aer_capability_regs *aer);
+extern int cper_severity_to_aer(int cper_severity);
+extern void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn,
+                             int severity);
 #endif //_AER_H_
 
index 3111385..e6e28f3 100644 (file)
@@ -172,8 +172,11 @@ struct pl08x_dma_chan {
        int phychan_hold;
        struct tasklet_struct tasklet;
        char *name;
-       struct pl08x_channel_data *cd;
-       dma_addr_t runtime_addr;
+       const struct pl08x_channel_data *cd;
+       dma_addr_t src_addr;
+       dma_addr_t dst_addr;
+       u32 src_cctl;
+       u32 dst_cctl;
        enum dma_data_direction runtime_direction;
        dma_cookie_t lc;
        struct list_head pend_list;
@@ -202,7 +205,7 @@ struct pl08x_dma_chan {
  * @mem_buses: buses which memory can be accessed from: PL08X_AHB1 | PL08X_AHB2
  */
 struct pl08x_platform_data {
-       struct pl08x_channel_data *slave_channels;
+       const struct pl08x_channel_data *slave_channels;
        unsigned int num_slave_channels;
        struct pl08x_channel_data memcpy_channel;
        int (*get_signal)(struct pl08x_dma_chan *);
index 3bac44c..7ad6345 100644 (file)
@@ -146,6 +146,7 @@ extern int bitmap_allocate_region(unsigned long *bitmap, int pos, int order);
 extern void bitmap_copy_le(void *dst, const unsigned long *src, int nbits);
 extern int bitmap_ord_to_pos(const unsigned long *bitmap, int n, int bits);
 
+#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) % BITS_PER_LONG))
 #define BITMAP_LAST_WORD_MASK(nbits)                                   \
 (                                                                      \
        ((nbits) % BITS_PER_LONG) ?                                     \
index 6395692..32f0076 100644 (file)
@@ -125,7 +125,11 @@ enum rq_flag_bits {
        __REQ_SYNC,             /* request is sync (sync write or read) */
        __REQ_META,             /* metadata io request */
        __REQ_DISCARD,          /* request to discard sectors */
+       __REQ_SECURE,           /* secure discard (used with __REQ_DISCARD) */
+
        __REQ_NOIDLE,           /* don't anticipate more IO after this one */
+       __REQ_FUA,              /* forced unit access */
+       __REQ_FLUSH,            /* request for cache flush */
 
        /* bio only flags */
        __REQ_RAHEAD,           /* read ahead, can fail anytime */
@@ -135,7 +139,6 @@ enum rq_flag_bits {
        /* request only flags */
        __REQ_SORTED,           /* elevator knows about this request */
        __REQ_SOFTBARRIER,      /* may not be passed by ioscheduler */
-       __REQ_FUA,              /* forced unit access */
        __REQ_NOMERGE,          /* don't touch this for merging */
        __REQ_STARTED,          /* drive already may have started this one */
        __REQ_DONTPREP,         /* don't call prep for this one */
@@ -146,11 +149,9 @@ enum rq_flag_bits {
        __REQ_PREEMPT,          /* set for "ide_preempt" requests */
        __REQ_ALLOCED,          /* request came from our alloc pool */
        __REQ_COPY_USER,        /* contains copies of user pages */
-       __REQ_FLUSH,            /* request for cache flush */
        __REQ_FLUSH_SEQ,        /* request for flush sequence */
        __REQ_IO_STAT,          /* account I/O stat */
        __REQ_MIXED_MERGE,      /* merge of different types, fail separately */
-       __REQ_SECURE,           /* secure discard (used with __REQ_DISCARD) */
        __REQ_NR_BITS,          /* stops here */
 };
 
index 0e67c45..84b15d5 100644 (file)
@@ -30,6 +30,7 @@ struct request_pm_state;
 struct blk_trace;
 struct request;
 struct sg_io_hdr;
+struct bsg_job;
 
 #define BLKDEV_MIN_RQ  4
 #define BLKDEV_MAX_RQ  128     /* Default maximum */
@@ -117,6 +118,7 @@ struct request {
                struct {
                        unsigned int            seq;
                        struct list_head        list;
+                       rq_end_io_fn            *saved_end_io;
                } flush;
        };
 
@@ -209,6 +211,7 @@ typedef int (merge_bvec_fn) (struct request_queue *, struct bvec_merge_data *,
 typedef void (softirq_done_fn)(struct request *);
 typedef int (dma_drain_needed_fn)(struct request *);
 typedef int (lld_busy_fn) (struct request_queue *q);
+typedef int (bsg_job_fn) (struct bsg_job *);
 
 enum blk_eh_timer_return {
        BLK_EH_NOT_HANDLED,
@@ -375,6 +378,8 @@ struct request_queue {
        struct mutex            sysfs_lock;
 
 #if defined(CONFIG_BLK_DEV_BSG)
+       bsg_job_fn              *bsg_job_fn;
+       int                     bsg_job_size;
        struct bsg_class_device bsg_dev;
 #endif
 
index 8c7c2de..8e9e4bc 100644 (file)
@@ -14,7 +14,7 @@
 enum blktrace_cat {
        BLK_TC_READ     = 1 << 0,       /* reads */
        BLK_TC_WRITE    = 1 << 1,       /* writes */
-       BLK_TC_BARRIER  = 1 << 2,       /* barrier */
+       BLK_TC_FLUSH    = 1 << 2,       /* flush */
        BLK_TC_SYNC     = 1 << 3,       /* sync IO */
        BLK_TC_SYNCIO   = BLK_TC_SYNC,
        BLK_TC_QUEUE    = 1 << 4,       /* queueing/merging */
@@ -28,8 +28,9 @@ enum blktrace_cat {
        BLK_TC_META     = 1 << 12,      /* metadata */
        BLK_TC_DISCARD  = 1 << 13,      /* discard requests */
        BLK_TC_DRV_DATA = 1 << 14,      /* binary per-driver data */
+       BLK_TC_FUA      = 1 << 15,      /* fua requests */
 
-       BLK_TC_END      = 1 << 15,      /* only 16-bits, reminder */
+       BLK_TC_END      = 1 << 15,      /* we've run out of bits! */
 };
 
 #define BLK_TC_SHIFT           (16)
diff --git a/include/linux/bsg-lib.h b/include/linux/bsg-lib.h
new file mode 100644 (file)
index 0000000..f55ab8c
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ *  BSG helper library
+ *
+ *  Copyright (C) 2008   James Smart, Emulex Corporation
+ *  Copyright (C) 2011   Red Hat, Inc.  All rights reserved.
+ *  Copyright (C) 2011   Mike Christie
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef _BLK_BSG_
+#define _BLK_BSG_
+
+#include <linux/blkdev.h>
+
+struct request;
+struct device;
+struct scatterlist;
+struct request_queue;
+
+struct bsg_buffer {
+       unsigned int payload_len;
+       int sg_cnt;
+       struct scatterlist *sg_list;
+};
+
+struct bsg_job {
+       struct device *dev;
+       struct request *req;
+
+       /* Transport/driver specific request/reply structs */
+       void *request;
+       void *reply;
+
+       unsigned int request_len;
+       unsigned int reply_len;
+       /*
+        * On entry : reply_len indicates the buffer size allocated for
+        * the reply.
+        *
+        * Upon completion : the message handler must set reply_len
+        *  to indicates the size of the reply to be returned to the
+        *  caller.
+        */
+
+       /* DMA payloads for the request/response */
+       struct bsg_buffer request_payload;
+       struct bsg_buffer reply_payload;
+
+       void *dd_data;          /* Used for driver-specific storage */
+};
+
+void bsg_job_done(struct bsg_job *job, int result,
+                 unsigned int reply_payload_rcv_len);
+int bsg_setup_queue(struct device *dev, struct request_queue *q, char *name,
+                   bsg_job_fn *job_fn, int dd_job_size);
+void bsg_request_fn(struct request_queue *q);
+void bsg_remove_queue(struct request_queue *q);
+void bsg_goose_queue(struct request_queue *q);
+
+#endif
index 36719ea..b51629e 100644 (file)
@@ -122,6 +122,8 @@ struct cpuidle_driver {
 };
 
 #ifdef CONFIG_CPU_IDLE
+extern void disable_cpuidle(void);
+extern int cpuidle_idle_call(void);
 
 extern int cpuidle_register_driver(struct cpuidle_driver *drv);
 struct cpuidle_driver *cpuidle_get_driver(void);
@@ -135,6 +137,8 @@ extern int cpuidle_enable_device(struct cpuidle_device *dev);
 extern void cpuidle_disable_device(struct cpuidle_device *dev);
 
 #else
+static inline void disable_cpuidle(void) { }
+static inline int cpuidle_idle_call(void) { return -ENODEV; }
 
 static inline int cpuidle_register_driver(struct cpuidle_driver *drv)
 {return -ENODEV; }
index 48e82af..4030896 100644 (file)
@@ -265,10 +265,11 @@ static inline void put_cred(const struct cred *_cred)
 /**
  * current_cred - Access the current task's subjective credentials
  *
- * Access the subjective credentials of the current task.
+ * Access the subjective credentials of the current task.  RCU-safe,
+ * since nobody else can modify it.
  */
 #define current_cred() \
-       (current->cred)
+       rcu_dereference_protected(current->cred, 1)
 
 /**
  * __task_cred - Access a task's objective credentials
@@ -306,8 +307,8 @@ static inline void put_cred(const struct cred *_cred)
 #define get_current_user()                             \
 ({                                                     \
        struct user_struct *__u;                        \
-       struct cred *__cred;                            \
-       __cred = (struct cred *) current_cred();        \
+       const struct cred *__cred;                      \
+       __cred = current_cred();                        \
        __u = get_uid(__cred->user);                    \
        __u;                                            \
 })
@@ -321,8 +322,8 @@ static inline void put_cred(const struct cred *_cred)
 #define get_current_groups()                           \
 ({                                                     \
        struct group_info *__groups;                    \
-       struct cred *__cred;                            \
-       __cred = (struct cred *) current_cred();        \
+       const struct cred *__cred;                      \
+       __cred = current_cred();                        \
        __groups = get_group_info(__cred->group_info);  \
        __groups;                                       \
 })
@@ -341,7 +342,7 @@ static inline void put_cred(const struct cred *_cred)
 
 #define current_cred_xxx(xxx)                  \
 ({                                             \
-       current->cred->xxx;                     \
+       current_cred()->xxx;                    \
 })
 
 #define current_uid()          (current_cred_xxx(uid))
index ec78a4b..2cd9f1c 100644 (file)
@@ -3,11 +3,16 @@
 
 #define SHA_DIGEST_WORDS 5
 #define SHA_MESSAGE_BYTES (512 /*bits*/ / 8)
-#define SHA_WORKSPACE_WORDS 80
+#define SHA_WORKSPACE_WORDS 16
 
 void sha_init(__u32 *buf);
 void sha_transform(__u32 *digest, const char *data, __u32 *W);
 
+#define MD5_DIGEST_WORDS 4
+#define MD5_MESSAGE_BYTES 64
+
+void md5_transform(__u32 *hash, __u32 const *in);
+
 __u32 half_md4_transform(__u32 buf[4], __u32 const in[8]);
 
 #endif
index d37d2a7..62157c0 100644 (file)
@@ -180,12 +180,12 @@ struct dentry_operations {
  */
 
 /* d_flags entries */
-#define DCACHE_AUTOFS_PENDING 0x0001    /* autofs: "under construction" */
-#define DCACHE_NFSFS_RENAMED  0x0002
-     /* this dentry has been "silly renamed" and has to be deleted on the last
-      * dput() */
+#define DCACHE_OP_HASH         0x0001
+#define DCACHE_OP_COMPARE      0x0002
+#define DCACHE_OP_REVALIDATE   0x0004
+#define DCACHE_OP_DELETE       0x0008
 
-#define        DCACHE_DISCONNECTED     0x0004
+#define        DCACHE_DISCONNECTED     0x0010
      /* This dentry is possibly not currently connected to the dcache tree, in
       * which case its parent will either be itself, or will have this flag as
       * well.  nfsd will not use a dentry with this bit set, but will first
@@ -196,22 +196,18 @@ struct dentry_operations {
       * dentry into place and return that dentry rather than the passed one,
       * typically using d_splice_alias. */
 
-#define DCACHE_REFERENCED      0x0008  /* Recently used, don't discard. */
-#define DCACHE_RCUACCESS       0x0010  /* Entry has ever been RCU-visible */
-#define DCACHE_INOTIFY_PARENT_WATCHED 0x0020
-     /* Parent inode is watched by inotify */
-
-#define DCACHE_COOKIE          0x0040  /* For use by dcookie subsystem */
-#define DCACHE_FSNOTIFY_PARENT_WATCHED 0x0080
-     /* Parent inode is watched by some fsnotify listener */
+#define DCACHE_REFERENCED      0x0020  /* Recently used, don't discard. */
+#define DCACHE_RCUACCESS       0x0040  /* Entry has ever been RCU-visible */
 
 #define DCACHE_CANT_MOUNT      0x0100
 #define DCACHE_GENOCIDE                0x0200
 
-#define DCACHE_OP_HASH         0x1000
-#define DCACHE_OP_COMPARE      0x2000
-#define DCACHE_OP_REVALIDATE   0x4000
-#define DCACHE_OP_DELETE       0x8000
+#define DCACHE_NFSFS_RENAMED   0x1000
+     /* this dentry has been "silly renamed" and has to be deleted on the last
+      * dput() */
+#define DCACHE_COOKIE          0x2000  /* For use by dcookie subsystem */
+#define DCACHE_FSNOTIFY_PARENT_WATCHED 0x4000
+     /* Parent inode is watched by some fsnotify listener */
 
 #define DCACHE_MOUNTED         0x10000 /* is a mountpoint */
 #define DCACHE_NEED_AUTOMOUNT  0x20000 /* handle automount on this dir */
index 4427e04..3fa1f3d 100644 (file)
@@ -208,6 +208,49 @@ struct dm_target_callbacks {
 int dm_register_target(struct target_type *t);
 void dm_unregister_target(struct target_type *t);
 
+/*
+ * Target argument parsing.
+ */
+struct dm_arg_set {
+       unsigned argc;
+       char **argv;
+};
+
+/*
+ * The minimum and maximum value of a numeric argument, together with
+ * the error message to use if the number is found to be outside that range.
+ */
+struct dm_arg {
+       unsigned min;
+       unsigned max;
+       char *error;
+};
+
+/*
+ * Validate the next argument, either returning it as *value or, if invalid,
+ * returning -EINVAL and setting *error.
+ */
+int dm_read_arg(struct dm_arg *arg, struct dm_arg_set *arg_set,
+               unsigned *value, char **error);
+
+/*
+ * Process the next argument as the start of a group containing between
+ * arg->min and arg->max further arguments. Either return the size as
+ * *num_args or, if invalid, return -EINVAL and set *error.
+ */
+int dm_read_arg_group(struct dm_arg *arg, struct dm_arg_set *arg_set,
+                     unsigned *num_args, char **error);
+
+/*
+ * Return the current argument and shift to the next.
+ */
+const char *dm_shift_arg(struct dm_arg_set *as);
+
+/*
+ * Move through num_args arguments.
+ */
+void dm_consume_args(struct dm_arg_set *as, unsigned num_args);
+
 /*-----------------------------------------------------------------
  * Functions for creating and manipulating mapped devices.
  * Drop the reference with dm_put when you finish with the object.
index 3708455..0cb8eff 100644 (file)
@@ -267,9 +267,9 @@ enum {
 #define DM_DEV_SET_GEOMETRY    _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
 
 #define DM_VERSION_MAJOR       4
-#define DM_VERSION_MINOR       20
+#define DM_VERSION_MINOR       21
 #define DM_VERSION_PATCHLEVEL  0
-#define DM_VERSION_EXTRA       "-ioctl (2011-02-02)"
+#define DM_VERSION_EXTRA       "-ioctl (2011-07-06)"
 
 /* Status bits */
 #define DM_READONLY_FLAG       (1 << 0) /* In/Out */
index 298d587..5e54458 100644 (file)
@@ -42,5 +42,20 @@ int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
                   unsigned num_dests, struct dm_io_region *dests,
                   unsigned flags, dm_kcopyd_notify_fn fn, void *context);
 
+/*
+ * Prepare a callback and submit it via the kcopyd thread.
+ *
+ * dm_kcopyd_prepare_callback allocates a callback structure and returns it.
+ * It must not be called from interrupt context.
+ * The returned value should be passed into dm_kcopyd_do_callback.
+ *
+ * dm_kcopyd_do_callback submits the callback.
+ * It may be called from interrupt context.
+ * The callback is issued from the kcopyd thread.
+ */
+void *dm_kcopyd_prepare_callback(struct dm_kcopyd_client *kc,
+                                dm_kcopyd_notify_fn fn, void *context);
+void dm_kcopyd_do_callback(void *job, int read_err, unsigned long write_err);
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_DM_KCOPYD_H */
index fec66bd..d47bccd 100644 (file)
@@ -67,7 +67,7 @@ typedef struct audio_status {
 
 
 typedef
-struct audio_karaoke{  /* if Vocal1 or Vocal2 are non-zero, they get mixed  */
+struct audio_karaoke {  /* if Vocal1 or Vocal2 are non-zero, they get mixed  */
        int vocal1;    /* into left and right t at 70% each */
        int vocal2;    /* if both, Vocal1 and Vocal2 are non-zero, Vocal1 gets*/
        int melody;    /* mixed into the left channel and */
index ec25726..2362a0b 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/rtc.h>
 #include <linux/ioport.h>
 #include <linux/pfn.h>
+#include <linux/pstore.h>
 
 #include <asm/page.h>
 #include <asm/system.h>
@@ -232,6 +233,9 @@ typedef efi_status_t efi_query_capsule_caps_t(efi_capsule_header_t **capsules,
 #define UV_SYSTEM_TABLE_GUID \
     EFI_GUID(  0x3b13a7d4, 0x633e, 0x11dd, 0x93, 0xec, 0xda, 0x25, 0x56, 0xd8, 0x95, 0x93 )
 
+#define LINUX_EFI_CRASH_GUID \
+    EFI_GUID(  0xcfc8fc79, 0xbe2e, 0x4ddc, 0x97, 0xf0, 0x9f, 0x98, 0xbf, 0xe2, 0x98, 0xa0 )
+
 typedef struct {
        efi_guid_t guid;
        unsigned long table;
@@ -458,6 +462,8 @@ struct efivars {
        struct kset *kset;
        struct bin_attribute *new_var, *del_var;
        const struct efivar_operations *ops;
+       struct efivar_entry *walk_entry;
+       struct pstore_info efi_pstore_info;
 };
 
 int register_efivars(struct efivars *efivars,
index 3ff060a..c6f996f 100644 (file)
@@ -25,10 +25,6 @@ struct fault_attr {
        unsigned long reject_end;
 
        unsigned long count;
-
-#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
-       struct dentry *dir;
-#endif
 };
 
 #define FAULT_ATTR_INITIALIZER {                               \
@@ -45,19 +41,15 @@ bool should_fail(struct fault_attr *attr, ssize_t size);
 
 #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
 
-int init_fault_attr_dentries(struct fault_attr *attr, const char *name);
-void cleanup_fault_attr_dentries(struct fault_attr *attr);
+struct dentry *fault_create_debugfs_attr(const char *name,
+                       struct dentry *parent, struct fault_attr *attr);
 
 #else /* CONFIG_FAULT_INJECTION_DEBUG_FS */
 
-static inline int init_fault_attr_dentries(struct fault_attr *attr,
-                                         const char *name)
-{
-       return -ENODEV;
-}
-
-static inline void cleanup_fault_attr_dentries(struct fault_attr *attr)
+static inline struct dentry *fault_create_debugfs_attr(const char *name,
+                       struct dentry *parent, struct fault_attr *attr)
 {
+       return ERR_PTR(-ENODEV);
 }
 
 #endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
index f23bcb7..178cdb4 100644 (file)
@@ -738,22 +738,54 @@ static inline int mapping_writably_mapped(struct address_space *mapping)
 struct posix_acl;
 #define ACL_NOT_CACHED ((void *)(-1))
 
+#define IOP_FASTPERM   0x0001
+#define IOP_LOOKUP     0x0002
+#define IOP_NOFOLLOW   0x0004
+
+/*
+ * Keep mostly read-only and often accessed (especially for
+ * the RCU path lookup and 'stat' data) fields at the beginning
+ * of the 'struct inode'
+ */
 struct inode {
-       /* RCU path lookup touches following: */
        umode_t                 i_mode;
+       unsigned short          i_opflags;
        uid_t                   i_uid;
        gid_t                   i_gid;
+       unsigned int            i_flags;
+
+#ifdef CONFIG_FS_POSIX_ACL
+       struct posix_acl        *i_acl;
+       struct posix_acl        *i_default_acl;
+#endif
+
        const struct inode_operations   *i_op;
        struct super_block      *i_sb;
+       struct address_space    *i_mapping;
 
-       spinlock_t              i_lock; /* i_blocks, i_bytes, maybe i_size */
-       unsigned int            i_flags;
-       unsigned long           i_state;
 #ifdef CONFIG_SECURITY
        void                    *i_security;
 #endif
-       struct mutex            i_mutex;
 
+       /* Stat data, not accessed from path walking */
+       unsigned long           i_ino;
+       unsigned int            i_nlink;
+       dev_t                   i_rdev;
+       loff_t                  i_size;
+       struct timespec         i_atime;
+       struct timespec         i_mtime;
+       struct timespec         i_ctime;
+       unsigned int            i_blkbits;
+       blkcnt_t                i_blocks;
+
+#ifdef __NEED_I_SIZE_ORDERED
+       seqcount_t              i_size_seqcount;
+#endif
+
+       /* Misc */
+       unsigned long           i_state;
+       spinlock_t              i_lock; /* i_blocks, i_bytes, maybe i_size */
+       struct mutex            i_mutex;
 
        unsigned long           dirtied_when;   /* jiffies of first dirtying */
 
@@ -765,25 +797,12 @@ struct inode {
                struct list_head        i_dentry;
                struct rcu_head         i_rcu;
        };
-       unsigned long           i_ino;
        atomic_t                i_count;
-       unsigned int            i_nlink;
-       dev_t                   i_rdev;
-       unsigned int            i_blkbits;
        u64                     i_version;
-       loff_t                  i_size;
-#ifdef __NEED_I_SIZE_ORDERED
-       seqcount_t              i_size_seqcount;
-#endif
-       struct timespec         i_atime;
-       struct timespec         i_mtime;
-       struct timespec         i_ctime;
-       blkcnt_t                i_blocks;
        unsigned short          i_bytes;
        atomic_t                i_dio_count;
        const struct file_operations    *i_fop; /* former ->i_op->default_file_ops */
        struct file_lock        *i_flock;
-       struct address_space    *i_mapping;
        struct address_space    i_data;
 #ifdef CONFIG_QUOTA
        struct dquot            *i_dquot[MAXQUOTAS];
@@ -806,10 +825,6 @@ struct inode {
        atomic_t                i_readcount; /* struct files open RO */
 #endif
        atomic_t                i_writecount;
-#ifdef CONFIG_FS_POSIX_ACL
-       struct posix_acl        *i_acl;
-       struct posix_acl        *i_default_acl;
-#endif
        void                    *i_private; /* fs or device private pointer */
 };
 
@@ -2317,11 +2332,18 @@ extern int should_remove_suid(struct dentry *);
 extern int file_remove_suid(struct file *);
 
 extern void __insert_inode_hash(struct inode *, unsigned long hashval);
-extern void remove_inode_hash(struct inode *);
 static inline void insert_inode_hash(struct inode *inode)
 {
        __insert_inode_hash(inode, inode->i_ino);
 }
+
+extern void __remove_inode_hash(struct inode *);
+static inline void remove_inode_hash(struct inode *inode)
+{
+       if (!inode_unhashed(inode))
+               __remove_inode_hash(inode);
+}
+
 extern void inode_sb_list_add(struct inode *inode);
 
 #ifdef CONFIG_BLOCK
index d464de5..464cff5 100644 (file)
@@ -47,6 +47,9 @@
  *  - FUSE_IOCTL_UNRESTRICTED shall now return with array of 'struct
  *    fuse_ioctl_iovec' instead of ambiguous 'struct iovec'
  *  - add FUSE_IOCTL_32BIT flag
+ *
+ * 7.17
+ *  - add FUSE_FLOCK_LOCKS and FUSE_RELEASE_FLOCK_UNLOCK
  */
 
 #ifndef _LINUX_FUSE_H
@@ -78,7 +81,7 @@
 #define FUSE_KERNEL_VERSION 7
 
 /** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 16
+#define FUSE_KERNEL_MINOR_VERSION 17
 
 /** The node ID of the root inode */
 #define FUSE_ROOT_ID 1
@@ -153,8 +156,10 @@ struct fuse_file_lock {
 /**
  * INIT request/reply flags
  *
+ * FUSE_POSIX_LOCKS: remote locking for POSIX file locks
  * FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
  * FUSE_DONT_MASK: don't apply umask to file mode on create operations
+ * FUSE_FLOCK_LOCKS: remote locking for BSD style file locks
  */
 #define FUSE_ASYNC_READ                (1 << 0)
 #define FUSE_POSIX_LOCKS       (1 << 1)
@@ -163,6 +168,7 @@ struct fuse_file_lock {
 #define FUSE_EXPORT_SUPPORT    (1 << 4)
 #define FUSE_BIG_WRITES                (1 << 5)
 #define FUSE_DONT_MASK         (1 << 6)
+#define FUSE_FLOCK_LOCKS       (1 << 10)
 
 /**
  * CUSE INIT request/reply flags
@@ -175,6 +181,7 @@ struct fuse_file_lock {
  * Release flags
  */
 #define FUSE_RELEASE_FLUSH     (1 << 0)
+#define FUSE_RELEASE_FLOCK_UNLOCK      (1 << 1)
 
 /**
  * Getattr flags
index 5bbebda..5e98eeb 100644 (file)
@@ -1,8 +1,26 @@
 /*
- * Basic general purpose allocator for managing special purpose memory
- * not managed by the regular kmalloc/kfree interface.
- * Uses for this includes on-device special memory, uncached memory
- * etc.
+ * Basic general purpose allocator for managing special purpose
+ * memory, for example, memory that is not managed by the regular
+ * kmalloc/kfree interface.  Uses for this includes on-device special
+ * memory, uncached memory etc.
+ *
+ * It is safe to use the allocator in NMI handlers and other special
+ * unblockable contexts that could otherwise deadlock on locks.  This
+ * is implemented by using atomic operations and retries on any
+ * conflicts.  The disadvantage is that there may be livelocks in
+ * extreme cases.  For better scalability, one allocator can be used
+ * for each CPU.
+ *
+ * The lockless operation only works if there is enough memory
+ * available.  If new memory is added to the pool a lock has to be
+ * still taken.  So any user relying on locklessness has to ensure
+ * that sufficient memory is preallocated.
+ *
+ * The basic atomic operation of this allocator is cmpxchg on long.
+ * On architectures that don't have NMI-safe cmpxchg implementation,
+ * the allocator can NOT be used in NMI handler.  So code uses the
+ * allocator in NMI handler should depend on
+ * CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG.
  *
  * This source code is licensed under the GNU General Public License,
  * Version 2.  See the file COPYING for more details.
@@ -15,7 +33,7 @@
  *  General purpose special memory pool descriptor.
  */
 struct gen_pool {
-       rwlock_t lock;
+       spinlock_t lock;
        struct list_head chunks;        /* list of chunks in this pool */
        int min_alloc_order;            /* minimum allocation order */
 };
@@ -24,8 +42,8 @@ struct gen_pool {
  *  General purpose special memory pool chunk descriptor.
  */
 struct gen_pool_chunk {
-       spinlock_t lock;
        struct list_head next_chunk;    /* next chunk in pool */
+       atomic_t avail;
        phys_addr_t phys_addr;          /* physical starting address of memory chunk */
        unsigned long start_addr;       /* starting address of memory chunk */
        unsigned long end_addr;         /* ending address of memory chunk */
@@ -56,4 +74,8 @@ static inline int gen_pool_add(struct gen_pool *pool, unsigned long addr,
 extern void gen_pool_destroy(struct gen_pool *);
 extern unsigned long gen_pool_alloc(struct gen_pool *, size_t);
 extern void gen_pool_free(struct gen_pool *, unsigned long, size_t);
+extern void gen_pool_for_each_chunk(struct gen_pool *,
+       void (*)(struct gen_pool *, struct gen_pool_chunk *, void *), void *);
+extern size_t gen_pool_avail(struct gen_pool *);
+extern size_t gen_pool_size(struct gen_pool *);
 #endif /* __GENALLOC_H__ */
index cb40892..3a76faf 100644 (file)
@@ -92,7 +92,7 @@ struct vm_area_struct;
  */
 #define __GFP_NOTRACK_FALSE_POSITIVE (__GFP_NOTRACK)
 
-#define __GFP_BITS_SHIFT 23    /* Room for 23 __GFP_FOO bits */
+#define __GFP_BITS_SHIFT 24    /* Room for N __GFP_FOO bits */
 #define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1))
 
 /* This equals 0, but use constants in case they ever change */
index 06d25c1..b80506b 100644 (file)
@@ -63,7 +63,7 @@ static inline u32 hash_32(u32 val, unsigned int bits)
        return hash >> (32 - bits);
 }
 
-static inline unsigned long hash_ptr(void *ptr, unsigned int bits)
+static inline unsigned long hash_ptr(const void *ptr, unsigned int bits)
 {
        return hash_long((unsigned long)ptr, bits);
 }
index 13a801f..255491c 100644 (file)
@@ -146,6 +146,10 @@ void ida_remove(struct ida *ida, int id);
 void ida_destroy(struct ida *ida);
 void ida_init(struct ida *ida);
 
+int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end,
+                  gfp_t gfp_mask);
+void ida_simple_remove(struct ida *ida, unsigned int id);
+
 void __init idr_init_cache(void);
 
 #endif /* __IDR_H__ */
index 068784e..a637e78 100644 (file)
@@ -438,6 +438,8 @@ struct input_keymap_entry {
 #define KEY_WIMAX              246
 #define KEY_RFKILL             247     /* Key that controls all radios */
 
+#define KEY_MICMUTE            248     /* Mute / unmute the microphone */
+
 /* Code 255 is reserved for special needs of AT keyboard driver */
 
 #define BTN_MISC               0x100
index c2ebfe6..9d57a71 100644 (file)
@@ -162,6 +162,7 @@ extern int allocate_resource(struct resource *root, struct resource *new,
                                                       resource_size_t,
                                                       resource_size_t),
                             void *alignf_data);
+struct resource *lookup_resource(struct resource *root, resource_size_t start);
 int adjust_resource(struct resource *res, resource_size_t start,
                    resource_size_t size);
 resource_size_t resource_alignment(struct resource *res);
index 5f69504..5951730 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/errno.h>
 #include <linux/topology.h>
 #include <linux/wait.h>
+#include <linux/module.h>
 
 #include <asm/irq.h>
 #include <asm/ptrace.h>
@@ -108,14 +109,18 @@ enum {
 };
 
 struct msi_desc;
+struct irq_domain;
 
 /**
  * struct irq_data - per irq and irq chip data passed down to chip functions
  * @irq:               interrupt number
+ * @hwirq:             hardware interrupt number, local to the interrupt domain
  * @node:              node index useful for balancing
  * @state_use_accessors: status information for irq chip functions.
  *                     Use accessor functions to deal with it
  * @chip:              low level interrupt hardware access
+ * @domain:            Interrupt translation domain; responsible for mapping
+ *                     between hwirq number and linux irq number.
  * @handler_data:      per-IRQ data for the irq_chip methods
  * @chip_data:         platform-specific per-chip private data for the chip
  *                     methods, to allow shared chip implementations
@@ -128,9 +133,11 @@ struct msi_desc;
  */
 struct irq_data {
        unsigned int            irq;
+       unsigned long           hwirq;
        unsigned int            node;
        unsigned int            state_use_accessors;
        struct irq_chip         *chip;
+       struct irq_domain       *domain;
        void                    *handler_data;
        void                    *chip_data;
        struct msi_desc         *msi_desc;
@@ -541,7 +548,15 @@ static inline struct msi_desc *irq_data_get_msi(struct irq_data *d)
        return d->msi_desc;
 }
 
-int irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node);
+int __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
+               struct module *owner);
+
+static inline int irq_alloc_descs(int irq, unsigned int from, unsigned int cnt,
+               int node)
+{
+       return __irq_alloc_descs(irq, from, cnt, node, THIS_MODULE);
+}
+
 void irq_free_descs(unsigned int irq, unsigned int cnt);
 int irq_reserve_irqs(unsigned int from, unsigned int cnt);
 
index 2d921b3..150134a 100644 (file)
@@ -66,6 +66,7 @@ struct irq_desc {
 #ifdef CONFIG_PROC_FS
        struct proc_dir_entry   *dir;
 #endif
+       struct module           *owner;
        const char              *name;
 } ____cacheline_internodealigned_in_smp;
 
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
new file mode 100644 (file)
index 0000000..e807ad6
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * irq_domain - IRQ translation domains
+ *
+ * Translation infrastructure between hw and linux irq numbers.  This is
+ * helpful for interrupt controllers to implement mapping between hardware
+ * irq numbers and the Linux irq number space.
+ *
+ * irq_domains also have a hook for translating device tree interrupt
+ * representation into a hardware irq number that can be mapped back to a
+ * Linux irq number without any extra platform support code.
+ *
+ * irq_domain is expected to be embedded in an interrupt controller's private
+ * data structure.
+ */
+#ifndef _LINUX_IRQDOMAIN_H
+#define _LINUX_IRQDOMAIN_H
+
+#include <linux/irq.h>
+#include <linux/mod_devicetable.h>
+
+#ifdef CONFIG_IRQ_DOMAIN
+struct device_node;
+struct irq_domain;
+
+/**
+ * struct irq_domain_ops - Methods for irq_domain objects
+ * @to_irq: (optional) given a local hardware irq number, return the linux
+ *          irq number.  If to_irq is not implemented, then the irq_domain
+ *          will use this translation: irq = (domain->irq_base + hwirq)
+ * @dt_translate: Given a device tree node and interrupt specifier, decode
+ *                the hardware irq number and linux irq type value.
+ */
+struct irq_domain_ops {
+       unsigned int (*to_irq)(struct irq_domain *d, unsigned long hwirq);
+
+#ifdef CONFIG_OF
+       int (*dt_translate)(struct irq_domain *d, struct device_node *node,
+                           const u32 *intspec, unsigned int intsize,
+                           unsigned long *out_hwirq, unsigned int *out_type);
+#endif /* CONFIG_OF */
+};
+
+/**
+ * struct irq_domain - Hardware interrupt number translation object
+ * @list: Element in global irq_domain list.
+ * @irq_base: Start of irq_desc range assigned to the irq_domain.  The creator
+ *            of the irq_domain is responsible for allocating the array of
+ *            irq_desc structures.
+ * @nr_irq: Number of irqs managed by the irq domain
+ * @ops: pointer to irq_domain methods
+ * @priv: private data pointer for use by owner.  Not touched by irq_domain
+ *        core code.
+ * @of_node: (optional) Pointer to device tree nodes associated with the
+ *           irq_domain.  Used when decoding device tree interrupt specifiers.
+ */
+struct irq_domain {
+       struct list_head list;
+       unsigned int irq_base;
+       unsigned int nr_irq;
+       const struct irq_domain_ops *ops;
+       void *priv;
+       struct device_node *of_node;
+};
+
+/**
+ * irq_domain_to_irq() - Translate from a hardware irq to a linux irq number
+ *
+ * Returns the linux irq number associated with a hardware irq.  By default,
+ * the mapping is irq == domain->irq_base + hwirq, but this mapping can
+ * be overridden if the irq_domain implements a .to_irq() hook.
+ */
+static inline unsigned int irq_domain_to_irq(struct irq_domain *d,
+                                            unsigned long hwirq)
+{
+       return d->ops->to_irq ? d->ops->to_irq(d, hwirq) : d->irq_base + hwirq;
+}
+
+extern void irq_domain_add(struct irq_domain *domain);
+extern void irq_domain_del(struct irq_domain *domain);
+#endif /* CONFIG_IRQ_DOMAIN */
+
+#if defined(CONFIG_IRQ_DOMAIN) && defined(CONFIG_OF_IRQ)
+extern void irq_domain_add_simple(struct device_node *controller, int irq_base);
+extern void irq_domain_generate_simple(const struct of_device_id *match,
+                                       u64 phys_base, unsigned int irq_start);
+#else /* CONFIG_IRQ_DOMAIN && CONFIG_OF_IRQ */
+static inline void irq_domain_generate_simple(const struct of_device_id *match,
+                                       u64 phys_base, unsigned int irq_start) { }
+#endif /* CONFIG_IRQ_DOMAIN && CONFIG_OF_IRQ */
+
+#endif /* _LINUX_IRQDOMAIN_H */
index d087c2e..38f307b 100644 (file)
@@ -1329,12 +1329,6 @@ extern int jbd_blocks_per_page(struct inode *inode);
 #define BUFFER_TRACE2(bh, bh2, info)   do {} while (0)
 #define JBUFFER_TRACE(jh, info)        do {} while (0)
 
-/* 
- * jbd2_dev_to_name is a utility function used by the jbd2 and ext4 
- * tracing infrastructure to map a dev_t to a device name.
- */
-extern const char *jbd2_dev_to_name(dev_t device);
-
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_JBD2_H */
diff --git a/include/linux/kconfig.h b/include/linux/kconfig.h
new file mode 100644 (file)
index 0000000..067eda0
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef __LINUX_KCONFIG_H
+#define __LINUX_KCONFIG_H
+
+#include <generated/autoconf.h>
+
+/*
+ * Helper macros to use CONFIG_ options in C expressions. Note that
+ * these only work with boolean and tristate options.
+ */
+
+/*
+ * IS_ENABLED(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y' or 'm',
+ * 0 otherwise.
+ *
+ */
+#define IS_ENABLED(option) \
+       (__enabled_ ## option || __enabled_ ## option ## _MODULE)
+
+/*
+ * IS_BUILTIN(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y', 0
+ * otherwise. For boolean options, this is equivalent to
+ * IS_ENABLED(CONFIG_FOO).
+ */
+#define IS_BUILTIN(option) __enabled_ ## option
+
+/*
+ * IS_MODULE(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'm', 0
+ * otherwise.
+ */
+#define IS_MODULE(option) __enabled_ ## option ## _MODULE
+
+#endif /* __LINUX_KCONFIG_H */
diff --git a/include/linux/llist.h b/include/linux/llist.h
new file mode 100644 (file)
index 0000000..aa0c8b5
--- /dev/null
@@ -0,0 +1,126 @@
+#ifndef LLIST_H
+#define LLIST_H
+/*
+ * Lock-less NULL terminated single linked list
+ *
+ * If there are multiple producers and multiple consumers, llist_add
+ * can be used in producers and llist_del_all can be used in
+ * consumers.  They can work simultaneously without lock.  But
+ * llist_del_first can not be used here.  Because llist_del_first
+ * depends on list->first->next does not changed if list->first is not
+ * changed during its operation, but llist_del_first, llist_add,
+ * llist_add (or llist_del_all, llist_add, llist_add) sequence in
+ * another consumer may violate that.
+ *
+ * If there are multiple producers and one consumer, llist_add can be
+ * used in producers and llist_del_all or llist_del_first can be used
+ * in the consumer.
+ *
+ * This can be summarized as follow:
+ *
+ *           |   add    | del_first |  del_all
+ * add       |    -     |     -     |     -
+ * del_first |          |     L     |     L
+ * del_all   |          |           |     -
+ *
+ * Where "-" stands for no lock is needed, while "L" stands for lock
+ * is needed.
+ *
+ * The list entries deleted via llist_del_all can be traversed with
+ * traversing function such as llist_for_each etc.  But the list
+ * entries can not be traversed safely before deleted from the list.
+ * The order of deleted entries is from the newest to the oldest added
+ * one.  If you want to traverse from the oldest to the newest, you
+ * must reverse the order by yourself before traversing.
+ *
+ * The basic atomic operation of this list is cmpxchg on long.  On
+ * architectures that don't have NMI-safe cmpxchg implementation, the
+ * list can NOT be used in NMI handler.  So code uses the list in NMI
+ * handler should depend on CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG.
+ */
+
+struct llist_head {
+       struct llist_node *first;
+};
+
+struct llist_node {
+       struct llist_node *next;
+};
+
+#define LLIST_HEAD_INIT(name)  { NULL }
+#define LLIST_HEAD(name)       struct llist_head name = LLIST_HEAD_INIT(name)
+
+/**
+ * init_llist_head - initialize lock-less list head
+ * @head:      the head for your lock-less list
+ */
+static inline void init_llist_head(struct llist_head *list)
+{
+       list->first = NULL;
+}
+
+/**
+ * llist_entry - get the struct of this entry
+ * @ptr:       the &struct llist_node pointer.
+ * @type:      the type of the struct this is embedded in.
+ * @member:    the name of the llist_node within the struct.
+ */
+#define llist_entry(ptr, type, member)         \
+       container_of(ptr, type, member)
+
+/**
+ * llist_for_each - iterate over some deleted entries of a lock-less list
+ * @pos:       the &struct llist_node to use as a loop cursor
+ * @node:      the first entry of deleted list entries
+ *
+ * In general, some entries of the lock-less list can be traversed
+ * safely only after being deleted from list, so start with an entry
+ * instead of list head.
+ *
+ * If being used on entries deleted from lock-less list directly, the
+ * traverse order is from the newest to the oldest added entry.  If
+ * you want to traverse from the oldest to the newest, you must
+ * reverse the order by yourself before traversing.
+ */
+#define llist_for_each(pos, node)                      \
+       for ((pos) = (node); pos; (pos) = (pos)->next)
+
+/**
+ * llist_for_each_entry - iterate over some deleted entries of lock-less list of given type
+ * @pos:       the type * to use as a loop cursor.
+ * @node:      the fist entry of deleted list entries.
+ * @member:    the name of the llist_node with the struct.
+ *
+ * In general, some entries of the lock-less list can be traversed
+ * safely only after being removed from list, so start with an entry
+ * instead of list head.
+ *
+ * If being used on entries deleted from lock-less list directly, the
+ * traverse order is from the newest to the oldest added entry.  If
+ * you want to traverse from the oldest to the newest, you must
+ * reverse the order by yourself before traversing.
+ */
+#define llist_for_each_entry(pos, node, member)                                \
+       for ((pos) = llist_entry((node), typeof(*(pos)), member);       \
+            &(pos)->member != NULL;                                    \
+            (pos) = llist_entry((pos)->member.next, typeof(*(pos)), member))
+
+/**
+ * llist_empty - tests whether a lock-less list is empty
+ * @head:      the list to test
+ *
+ * Not guaranteed to be accurate or up to date.  Just a quick way to
+ * test whether the list is empty without deleting something from the
+ * list.
+ */
+static inline int llist_empty(const struct llist_head *head)
+{
+       return ACCESS_ONCE(head->first) == NULL;
+}
+
+void llist_add(struct llist_node *new, struct llist_head *head);
+void llist_add_batch(struct llist_node *new_first, struct llist_node *new_last,
+                    struct llist_head *head);
+struct llist_node *llist_del_first(struct llist_head *head);
+struct llist_node *llist_del_all(struct llist_head *head);
+#endif /* LLIST_H */
index 66c194e..683d698 100644 (file)
@@ -64,7 +64,6 @@ struct loop_device {
 
        struct request_queue    *lo_queue;
        struct gendisk          *lo_disk;
-       struct list_head        lo_list;
 };
 
 #endif /* __KERNEL__ */
@@ -161,4 +160,8 @@ int loop_unregister_transfer(int number);
 #define LOOP_CHANGE_FD         0x4C06
 #define LOOP_SET_CAPACITY      0x4C07
 
+/* /dev/loop-control interface */
+#define LOOP_CTL_ADD           0x4C80
+#define LOOP_CTL_REMOVE                0x4C81
+#define LOOP_CTL_GET_FREE      0x4C82
 #endif
index b966007..3b535db 100644 (file)
@@ -86,8 +86,6 @@ extern void mem_cgroup_uncharge_end(void);
 
 extern void mem_cgroup_uncharge_page(struct page *page);
 extern void mem_cgroup_uncharge_cache_page(struct page *page);
-extern int mem_cgroup_shmem_charge_fallback(struct page *page,
-                       struct mm_struct *mm, gfp_t gfp_mask);
 
 extern void mem_cgroup_out_of_memory(struct mem_cgroup *mem, gfp_t gfp_mask);
 int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *mem);
@@ -225,12 +223,6 @@ static inline void mem_cgroup_uncharge_cache_page(struct page *page)
 {
 }
 
-static inline int mem_cgroup_shmem_charge_fallback(struct page *page,
-                       struct mm_struct *mm, gfp_t gfp_mask)
-{
-       return 0;
-}
-
 static inline void mem_cgroup_add_lru_list(struct page *page, int lru)
 {
 }
diff --git a/include/linux/mfd/aat2870.h b/include/linux/mfd/aat2870.h
new file mode 100644 (file)
index 0000000..f7316c2
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * linux/include/linux/mfd/aat2870.h
+ *
+ * Copyright (c) 2011, NVIDIA Corporation.
+ * Author: Jin Park <jinyoungp@nvidia.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
+ */
+
+#ifndef __LINUX_MFD_AAT2870_H
+#define __LINUX_MFD_AAT2870_H
+
+#include <linux/debugfs.h>
+#include <linux/i2c.h>
+
+/* Register offsets */
+#define AAT2870_BL_CH_EN       0x00
+#define AAT2870_BLM            0x01
+#define AAT2870_BLS            0x02
+#define AAT2870_BL1            0x03
+#define AAT2870_BL2            0x04
+#define AAT2870_BL3            0x05
+#define AAT2870_BL4            0x06
+#define AAT2870_BL5            0x07
+#define AAT2870_BL6            0x08
+#define AAT2870_BL7            0x09
+#define AAT2870_BL8            0x0A
+#define AAT2870_FLR            0x0B
+#define AAT2870_FM             0x0C
+#define AAT2870_FS             0x0D
+#define AAT2870_ALS_CFG0       0x0E
+#define AAT2870_ALS_CFG1       0x0F
+#define AAT2870_ALS_CFG2       0x10
+#define AAT2870_AMB            0x11
+#define AAT2870_ALS0           0x12
+#define AAT2870_ALS1           0x13
+#define AAT2870_ALS2           0x14
+#define AAT2870_ALS3           0x15
+#define AAT2870_ALS4           0x16
+#define AAT2870_ALS5           0x17
+#define AAT2870_ALS6           0x18
+#define AAT2870_ALS7           0x19
+#define AAT2870_ALS8           0x1A
+#define AAT2870_ALS9           0x1B
+#define AAT2870_ALSA           0x1C
+#define AAT2870_ALSB           0x1D
+#define AAT2870_ALSC           0x1E
+#define AAT2870_ALSD           0x1F
+#define AAT2870_ALSE           0x20
+#define AAT2870_ALSF           0x21
+#define AAT2870_SUB_SET                0x22
+#define AAT2870_SUB_CTRL       0x23
+#define AAT2870_LDO_AB         0x24
+#define AAT2870_LDO_CD         0x25
+#define AAT2870_LDO_EN         0x26
+#define AAT2870_REG_NUM                0x27
+
+/* Device IDs */
+enum aat2870_id {
+       AAT2870_ID_BL,
+       AAT2870_ID_LDOA,
+       AAT2870_ID_LDOB,
+       AAT2870_ID_LDOC,
+       AAT2870_ID_LDOD
+};
+
+/* Backlight channels */
+#define AAT2870_BL_CH1         0x01
+#define AAT2870_BL_CH2         0x02
+#define AAT2870_BL_CH3         0x04
+#define AAT2870_BL_CH4         0x08
+#define AAT2870_BL_CH5         0x10
+#define AAT2870_BL_CH6         0x20
+#define AAT2870_BL_CH7         0x40
+#define AAT2870_BL_CH8         0x80
+#define AAT2870_BL_CH_ALL      0xFF
+
+/* Backlight current magnitude (mA) */
+enum aat2870_current {
+       AAT2870_CURRENT_0_45 = 1,
+       AAT2870_CURRENT_0_90,
+       AAT2870_CURRENT_1_80,
+       AAT2870_CURRENT_2_70,
+       AAT2870_CURRENT_3_60,
+       AAT2870_CURRENT_4_50,
+       AAT2870_CURRENT_5_40,
+       AAT2870_CURRENT_6_30,
+       AAT2870_CURRENT_7_20,
+       AAT2870_CURRENT_8_10,
+       AAT2870_CURRENT_9_00,
+       AAT2870_CURRENT_9_90,
+       AAT2870_CURRENT_10_8,
+       AAT2870_CURRENT_11_7,
+       AAT2870_CURRENT_12_6,
+       AAT2870_CURRENT_13_5,
+       AAT2870_CURRENT_14_4,
+       AAT2870_CURRENT_15_3,
+       AAT2870_CURRENT_16_2,
+       AAT2870_CURRENT_17_1,
+       AAT2870_CURRENT_18_0,
+       AAT2870_CURRENT_18_9,
+       AAT2870_CURRENT_19_8,
+       AAT2870_CURRENT_20_7,
+       AAT2870_CURRENT_21_6,
+       AAT2870_CURRENT_22_5,
+       AAT2870_CURRENT_23_4,
+       AAT2870_CURRENT_24_3,
+       AAT2870_CURRENT_25_2,
+       AAT2870_CURRENT_26_1,
+       AAT2870_CURRENT_27_0,
+       AAT2870_CURRENT_27_9
+};
+
+struct aat2870_register {
+       bool readable;
+       bool writeable;
+       u8 value;
+};
+
+struct aat2870_data {
+       struct device *dev;
+       struct i2c_client *client;
+
+       struct mutex io_lock;
+       struct aat2870_register *reg_cache; /* register cache */
+       int en_pin; /* enable GPIO pin (if < 0, ignore this value) */
+       bool is_enable;
+
+       /* init and uninit for platform specified */
+       int (*init)(struct aat2870_data *aat2870);
+       void (*uninit)(struct aat2870_data *aat2870);
+
+       /* i2c io funcntions */
+       int (*read)(struct aat2870_data *aat2870, u8 addr, u8 *val);
+       int (*write)(struct aat2870_data *aat2870, u8 addr, u8 val);
+       int (*update)(struct aat2870_data *aat2870, u8 addr, u8 mask, u8 val);
+
+       /* for debugfs */
+       struct dentry *dentry_root;
+       struct dentry *dentry_reg;
+};
+
+struct aat2870_subdev_info {
+       int id;
+       const char *name;
+       void *platform_data;
+};
+
+struct aat2870_platform_data {
+       int en_pin; /* enable GPIO pin (if < 0, ignore this value) */
+
+       struct aat2870_subdev_info *subdevs;
+       int num_subdevs;
+
+       /* init and uninit for platform specified */
+       int (*init)(struct aat2870_data *aat2870);
+       void (*uninit)(struct aat2870_data *aat2870);
+};
+
+struct aat2870_bl_platform_data {
+       /* backlight channels, default is AAT2870_BL_CH_ALL */
+       int channels;
+       /* backlight current magnitude, default is AAT2870_CURRENT_27_9 */
+       int max_current;
+       /* maximum brightness, default is 255 */
+       int max_brightness;
+};
+
+#endif /* __LINUX_MFD_AAT2870_H */
index b318430..838c6b4 100644 (file)
@@ -28,6 +28,7 @@
 #define AB8500_INTERRUPT       0xE
 #define AB8500_RTC             0xF
 #define AB8500_MISC            0x10
+#define AB8500_DEVELOPMENT     0x11
 #define AB8500_DEBUG           0x12
 #define AB8500_PROD_TEST       0x13
 #define AB8500_OTP_EMUL                0x15
 #define AB8500_INT_ACC_DETECT_21DB_F   37
 #define AB8500_INT_ACC_DETECT_21DB_R   38
 #define AB8500_INT_GP_SW_ADC_CONV_END  39
-#define AB8500_INT_ACC_DETECT_1DB_F    33
-#define AB8500_INT_ACC_DETECT_1DB_R    34
-#define AB8500_INT_ACC_DETECT_22DB_F   35
-#define AB8500_INT_ACC_DETECT_22DB_R   36
-#define AB8500_INT_ACC_DETECT_21DB_F   37
-#define AB8500_INT_ACC_DETECT_21DB_R   38
-#define AB8500_INT_GP_SW_ADC_CONV_END  39
 #define AB8500_INT_GPIO6R              40
 #define AB8500_INT_GPIO7R              41
 #define AB8500_INT_GPIO8R              42
index 60931d0..0bbd13d 100644 (file)
@@ -107,11 +107,16 @@ struct max8997_platform_data {
        unsigned int buck5_voltage[8];
        bool buck5_gpiodvs;
 
+       /* ---- Charger control ---- */
+       /* eoc stands for 'end of charge' */
+       int eoc_mA; /* 50 ~ 200mA by 10mA step */
+       /* charge Full Timeout */
+       int timeout; /* 0 (no timeout), 5, 6, 7 hours */
+
        /* MUIC: Not implemented */
        /* HAPTIC: Not implemented */
        /* RTC: Not implemented */
        /* Flash: Not implemented */
-       /* Charger control: Not implemented */
 };
 
 #endif /* __LINUX_MFD_MAX8998_H */
index 61daa16..f4f0dfa 100644 (file)
@@ -87,6 +87,15 @@ struct max8998_regulator_data {
  * @wakeup: Allow to wake up from suspend
  * @rtc_delay: LP3974 RTC chip bug that requires delay after a register
  * write before reading it.
+ * @eoc: End of Charge Level in percent: 10% ~ 45% by 5% step
+ *   If it equals 0, leave it unchanged.
+ *   Otherwise, it is a invalid value.
+ * @restart: Restart Level in mV: 100, 150, 200, and -1 for disable.
+ *   If it equals 0, leave it unchanged.
+ *   Otherwise, it is a invalid value.
+ * @timeout: Full Timeout in hours: 5, 6, 7, and -1 for disable.
+ *   If it equals 0, leave it unchanged.
+ *   Otherwise, leave it unchanged.
  */
 struct max8998_platform_data {
        struct max8998_regulator_data   *regulators;
@@ -107,6 +116,9 @@ struct max8998_platform_data {
        int                             buck2_default_idx;
        bool                            wakeup;
        bool                            rtc_delay;
+       int                             eoc;
+       int                             restart;
+       int                             timeout;
 };
 
 #endif /*  __LINUX_MFD_MAX8998_H */
index e762c27..be1af7c 100644 (file)
@@ -57,6 +57,7 @@ struct stmpe_variant_info;
  * @irq_lock: IRQ bus lock
  * @dev: device, mostly for dev_dbg()
  * @i2c: i2c client
+ * @partnum: part number
  * @variant: the detected STMPE model number
  * @regs: list of addresses of registers which are at different addresses on
  *       different variants.  Indexed by one of STMPE_IDX_*.
@@ -121,6 +122,8 @@ struct stmpe_keypad_platform_data {
  * @norequest_mask: bitmask specifying which GPIOs should _not_ be
  *                 requestable due to different usage (e.g. touch, keypad)
  *                 STMPE_GPIO_NOREQ_* macros can be used here.
+ * @setup: board specific setup callback.
+ * @remove: board specific remove callback
  */
 struct stmpe_gpio_platform_data {
        int gpio_base;
index 73572c6..82b4c88 100644 (file)
@@ -791,6 +791,7 @@ int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask);
 void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base);
 int tps65910_irq_init(struct tps65910 *tps65910, int irq,
                struct tps65910_platform_data *pdata);
+int tps65910_irq_exit(struct tps65910 *tps65910);
 
 static inline int tps65910_chip_id(struct tps65910 *tps65910)
 {
diff --git a/include/linux/mfd/tps65912.h b/include/linux/mfd/tps65912.h
new file mode 100644 (file)
index 0000000..aaceab4
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * tps65912.h  --  TI TPS6591x
+ *
+ * Copyright 2011 Texas Instruments Inc.
+ *
+ * Author: Margarita Olaya <magi@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.
+ *
+ */
+
+#ifndef __LINUX_MFD_TPS65912_H
+#define __LINUX_MFD_TPS65912_H
+
+/* TPS regulator type list */
+#define REGULATOR_LDO          0
+#define REGULATOR_DCDC         1
+
+/*
+ * List of registers for TPS65912
+ */
+
+#define TPS65912_DCDC1_CTRL            0x00
+#define TPS65912_DCDC2_CTRL            0x01
+#define TPS65912_DCDC3_CTRL            0x02
+#define TPS65912_DCDC4_CTRL            0x03
+#define TPS65912_DCDC1_OP              0x04
+#define TPS65912_DCDC1_AVS             0x05
+#define TPS65912_DCDC1_LIMIT           0x06
+#define TPS65912_DCDC2_OP              0x07
+#define TPS65912_DCDC2_AVS             0x08
+#define TPS65912_DCDC2_LIMIT           0x09
+#define TPS65912_DCDC3_OP              0x0A
+#define TPS65912_DCDC3_AVS             0x0B
+#define TPS65912_DCDC3_LIMIT           0x0C
+#define TPS65912_DCDC4_OP              0x0D
+#define TPS65912_DCDC4_AVS             0x0E
+#define TPS65912_DCDC4_LIMIT           0x0F
+#define TPS65912_LDO1_OP               0x10
+#define TPS65912_LDO1_AVS              0x11
+#define TPS65912_LDO1_LIMIT            0x12
+#define TPS65912_LDO2_OP               0x13
+#define TPS65912_LDO2_AVS              0x14
+#define TPS65912_LDO2_LIMIT            0x15
+#define TPS65912_LDO3_OP               0x16
+#define TPS65912_LDO3_AVS              0x17
+#define TPS65912_LDO3_LIMIT            0x18
+#define TPS65912_LDO4_OP               0x19
+#define TPS65912_LDO4_AVS              0x1A
+#define TPS65912_LDO4_LIMIT            0x1B
+#define TPS65912_LDO5                  0x1C
+#define TPS65912_LDO6                  0x1D
+#define TPS65912_LDO7                  0x1E
+#define TPS65912_LDO8                  0x1F
+#define TPS65912_LDO9                  0x20
+#define TPS65912_LDO10                 0x21
+#define TPS65912_THRM                  0x22
+#define TPS65912_CLK32OUT              0x23
+#define TPS65912_DEVCTRL               0x24
+#define TPS65912_DEVCTRL2              0x25
+#define TPS65912_I2C_SPI_CFG           0x26
+#define TPS65912_KEEP_ON               0x27
+#define TPS65912_KEEP_ON2              0x28
+#define TPS65912_SET_OFF1              0x29
+#define TPS65912_SET_OFF2              0x2A
+#define TPS65912_DEF_VOLT              0x2B
+#define TPS65912_DEF_VOLT_MAPPING      0x2C
+#define TPS65912_DISCHARGE             0x2D
+#define TPS65912_DISCHARGE2            0x2E
+#define TPS65912_EN1_SET1              0x2F
+#define TPS65912_EN1_SET2              0x30
+#define TPS65912_EN2_SET1              0x31
+#define TPS65912_EN2_SET2              0x32
+#define TPS65912_EN3_SET1              0x33
+#define TPS65912_EN3_SET2              0x34
+#define TPS65912_EN4_SET1              0x35
+#define TPS65912_EN4_SET2              0x36
+#define TPS65912_PGOOD                 0x37
+#define TPS65912_PGOOD2                        0x38
+#define TPS65912_INT_STS               0x39
+#define TPS65912_INT_MSK               0x3A
+#define TPS65912_INT_STS2              0x3B
+#define TPS65912_INT_MSK2              0x3C
+#define TPS65912_INT_STS3              0x3D
+#define TPS65912_INT_MSK3              0x3E
+#define TPS65912_INT_STS4              0x3F
+#define TPS65912_INT_MSK4              0x40
+#define TPS65912_GPIO1                 0x41
+#define TPS65912_GPIO2                 0x42
+#define TPS65912_GPIO3                 0x43
+#define TPS65912_GPIO4                 0x44
+#define TPS65912_GPIO5                 0x45
+#define TPS65912_VMON                  0x46
+#define TPS65912_LEDA_CTRL1            0x47
+#define TPS65912_LEDA_CTRL2            0x48
+#define TPS65912_LEDA_CTRL3            0x49
+#define TPS65912_LEDA_CTRL4            0x4A
+#define TPS65912_LEDA_CTRL5            0x4B
+#define TPS65912_LEDA_CTRL6            0x4C
+#define TPS65912_LEDA_CTRL7            0x4D
+#define TPS65912_LEDA_CTRL8            0x4E
+#define TPS65912_LEDB_CTRL1            0x4F
+#define TPS65912_LEDB_CTRL2            0x50
+#define TPS65912_LEDB_CTRL3            0x51
+#define TPS65912_LEDB_CTRL4            0x52
+#define TPS65912_LEDB_CTRL5            0x53
+#define TPS65912_LEDB_CTRL6            0x54
+#define TPS65912_LEDB_CTRL7            0x55
+#define TPS65912_LEDB_CTRL8            0x56
+#define TPS65912_LEDC_CTRL1            0x57
+#define TPS65912_LEDC_CTRL2            0x58
+#define TPS65912_LEDC_CTRL3            0x59
+#define TPS65912_LEDC_CTRL4            0x5A
+#define TPS65912_LEDC_CTRL5            0x5B
+#define TPS65912_LEDC_CTRL6            0x5C
+#define TPS65912_LEDC_CTRL7            0x5D
+#define TPS65912_LEDC_CTRL8            0x5E
+#define TPS65912_LED_RAMP_UP_TIME      0x5F
+#define TPS65912_LED_RAMP_DOWN_TIME    0x60
+#define TPS65912_LED_SEQ_EN            0x61
+#define TPS65912_LOADSWITCH            0x62
+#define TPS65912_SPARE                 0x63
+#define TPS65912_VERNUM                        0x64
+#define TPS6591X_MAX_REGISTER          0x64
+
+/* IRQ Definitions */
+#define TPS65912_IRQ_PWRHOLD_F         0
+#define TPS65912_IRQ_VMON              1
+#define TPS65912_IRQ_PWRON             2
+#define TPS65912_IRQ_PWRON_LP          3
+#define TPS65912_IRQ_PWRHOLD_R         4
+#define TPS65912_IRQ_HOTDIE            5
+#define TPS65912_IRQ_GPIO1_R           6
+#define TPS65912_IRQ_GPIO1_F           7
+#define TPS65912_IRQ_GPIO2_R           8
+#define TPS65912_IRQ_GPIO2_F           9
+#define TPS65912_IRQ_GPIO3_R           10
+#define TPS65912_IRQ_GPIO3_F           11
+#define TPS65912_IRQ_GPIO4_R           12
+#define TPS65912_IRQ_GPIO4_F           13
+#define TPS65912_IRQ_GPIO5_R           14
+#define TPS65912_IRQ_GPIO5_F           15
+#define TPS65912_IRQ_PGOOD_DCDC1       16
+#define TPS65912_IRQ_PGOOD_DCDC2       17
+#define TPS65912_IRQ_PGOOD_DCDC3       18
+#define TPS65912_IRQ_PGOOD_DCDC4       19
+#define TPS65912_IRQ_PGOOD_LDO1                20
+#define TPS65912_IRQ_PGOOD_LDO2                21
+#define TPS65912_IRQ_PGOOD_LDO3                22
+#define TPS65912_IRQ_PGOOD_LDO4                23
+#define TPS65912_IRQ_PGOOD_LDO5                24
+#define TPS65912_IRQ_PGOOD_LDO6                25
+#define TPS65912_IRQ_PGOOD_LDO7                26
+#define TPS65912_IRQ_PGOOD_LD08                27
+#define TPS65912_IRQ_PGOOD_LDO9                28
+#define TPS65912_IRQ_PGOOD_LDO10       29
+
+#define TPS65912_NUM_IRQ               30
+
+/* GPIO 1 and 2 Register Definitions */
+#define GPIO_SLEEP_MASK                        0x80
+#define GPIO_SLEEP_SHIFT               7
+#define GPIO_DEB_MASK                  0x10
+#define GPIO_DEB_SHIFT                 4
+#define GPIO_CFG_MASK                  0x04
+#define GPIO_CFG_SHIFT                 2
+#define GPIO_STS_MASK                  0x02
+#define GPIO_STS_SHIFT                 1
+#define GPIO_SET_MASK                  0x01
+#define GPIO_SET_SHIFT                 0
+
+/* GPIO 3 Register Definitions */
+#define GPIO3_SLEEP_MASK               0x80
+#define GPIO3_SLEEP_SHIFT              7
+#define GPIO3_SEL_MASK                 0x40
+#define GPIO3_SEL_SHIFT                        6
+#define GPIO3_ODEN_MASK                        0x20
+#define GPIO3_ODEN_SHIFT               5
+#define GPIO3_DEB_MASK                 0x10
+#define GPIO3_DEB_SHIFT                        4
+#define GPIO3_PDEN_MASK                        0x08
+#define GPIO3_PDEN_SHIFT               3
+#define GPIO3_CFG_MASK                 0x04
+#define GPIO3_CFG_SHIFT                        2
+#define GPIO3_STS_MASK                 0x02
+#define GPIO3_STS_SHIFT                        1
+#define GPIO3_SET_MASK                 0x01
+#define GPIO3_SET_SHIFT                        0
+
+/* GPIO 4 Register Definitions */
+#define GPIO4_SLEEP_MASK               0x80
+#define GPIO4_SLEEP_SHIFT              7
+#define GPIO4_SEL_MASK                 0x40
+#define GPIO4_SEL_SHIFT                        6
+#define GPIO4_ODEN_MASK                        0x20
+#define GPIO4_ODEN_SHIFT               5
+#define GPIO4_DEB_MASK                 0x10
+#define GPIO4_DEB_SHIFT                        4
+#define GPIO4_PDEN_MASK                        0x08
+#define GPIO4_PDEN_SHIFT               3
+#define GPIO4_CFG_MASK                 0x04
+#define GPIO4_CFG_SHIFT                        2
+#define GPIO4_STS_MASK                 0x02
+#define GPIO4_STS_SHIFT                        1
+#define GPIO4_SET_MASK                 0x01
+#define GPIO4_SET_SHIFT                        0
+
+/* Register THERM  (0x80) register.RegisterDescription */
+#define THERM_THERM_HD_MASK            0x20
+#define THERM_THERM_HD_SHIFT           5
+#define THERM_THERM_TS_MASK            0x10
+#define THERM_THERM_TS_SHIFT           4
+#define THERM_THERM_HDSEL_MASK         0x0C
+#define THERM_THERM_HDSEL_SHIFT                2
+#define THERM_RSVD1_MASK               0x02
+#define THERM_RSVD1_SHIFT              1
+#define THERM_THERM_STATE_MASK         0x01
+#define THERM_THERM_STATE_SHIFT                0
+
+/* Register DCDCCTRL1 register.RegisterDescription */
+#define DCDCCTRL_VCON_ENABLE_MASK      0x80
+#define DCDCCTRL_VCON_ENABLE_SHIFT     7
+#define DCDCCTRL_VCON_RANGE1_MASK      0x40
+#define DCDCCTRL_VCON_RANGE1_SHIFT     6
+#define DCDCCTRL_VCON_RANGE0_MASK      0x20
+#define DCDCCTRL_VCON_RANGE0_SHIFT     5
+#define DCDCCTRL_TSTEP2_MASK           0x10
+#define DCDCCTRL_TSTEP2_SHIFT          4
+#define DCDCCTRL_TSTEP1_MASK           0x08
+#define DCDCCTRL_TSTEP1_SHIFT          3
+#define DCDCCTRL_TSTEP0_MASK           0x04
+#define DCDCCTRL_TSTEP0_SHIFT          2
+#define DCDCCTRL_DCDC1_MODE_MASK       0x02
+#define DCDCCTRL_DCDC1_MODE_SHIFT      1
+
+/* Register DCDCCTRL2 and DCDCCTRL3 register.RegisterDescription */
+#define DCDCCTRL_TSTEP2_MASK           0x10
+#define DCDCCTRL_TSTEP2_SHIFT          4
+#define DCDCCTRL_TSTEP1_MASK           0x08
+#define DCDCCTRL_TSTEP1_SHIFT          3
+#define DCDCCTRL_TSTEP0_MASK           0x04
+#define DCDCCTRL_TSTEP0_SHIFT          2
+#define DCDCCTRL_DCDC_MODE_MASK                0x02
+#define DCDCCTRL_DCDC_MODE_SHIFT       1
+#define DCDCCTRL_RSVD0_MASK            0x01
+#define DCDCCTRL_RSVD0_SHIFT           0
+
+/* Register DCDCCTRL4 register.RegisterDescription */
+#define DCDCCTRL_RAMP_TIME_MASK                0x01
+#define DCDCCTRL_RAMP_TIME_SHIFT       0
+
+/* Register DCDCx_AVS */
+#define DCDC_AVS_ENABLE_MASK           0x80
+#define DCDC_AVS_ENABLE_SHIFT          7
+#define DCDC_AVS_ECO_MASK              0x40
+#define DCDC_AVS_ECO_SHIFT             6
+
+/* Register DCDCx_LIMIT */
+#define DCDC_LIMIT_RANGE_MASK          0xC0
+#define DCDC_LIMIT_RANGE_SHIFT         6
+#define DCDC_LIMIT_MAX_SEL_MASK                0x3F
+#define DCDC_LIMIT_MAX_SEL_SHIFT       0
+
+/**
+ * struct tps65912_board
+ * Board platform dat may be used to initialize regulators.
+ */
+struct tps65912_board {
+       int is_dcdc1_avs;
+       int is_dcdc2_avs;
+       int is_dcdc3_avs;
+       int is_dcdc4_avs;
+       int irq;
+       int irq_base;
+       int gpio_base;
+       struct regulator_init_data *tps65912_pmic_init_data;
+};
+
+/**
+ * struct tps65912 - tps65912 sub-driver chip access routines
+ */
+
+struct tps65912 {
+       struct device *dev;
+       /* for read/write acces */
+       struct mutex io_mutex;
+
+       /* For device IO interfaces: I2C or SPI */
+       void *control_data;
+
+       int (*read)(struct tps65912 *tps65912, u8 reg, int size, void *dest);
+       int (*write)(struct tps65912 *tps65912, u8 reg, int size, void *src);
+
+       /* Client devices */
+       struct tps65912_pmic *pmic;
+
+       /* GPIO Handling */
+       struct gpio_chip gpio;
+
+       /* IRQ Handling */
+       struct mutex irq_lock;
+       int chip_irq;
+       int irq_base;
+       int irq_num;
+       u32 irq_mask;
+};
+
+struct tps65912_platform_data {
+       int irq;
+       int irq_base;
+};
+
+unsigned int tps_chip(void);
+
+int tps65912_set_bits(struct tps65912 *tps65912, u8 reg, u8 mask);
+int tps65912_clear_bits(struct tps65912 *tps65912, u8 reg, u8 mask);
+int tps65912_reg_read(struct tps65912 *tps65912, u8 reg);
+int tps65912_reg_write(struct tps65912 *tps65912, u8 reg, u8 val);
+int tps65912_device_init(struct tps65912 *tps65912);
+void tps65912_device_exit(struct tps65912 *tps65912);
+int tps65912_irq_init(struct tps65912 *tps65912, int irq,
+                       struct tps65912_platform_data *pdata);
+
+#endif /*  __LINUX_MFD_TPS65912_H */
index 0d515ee..8dda8de 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/completion.h>
 #include <linux/interrupt.h>
+#include <linux/list.h>
 
 /*
  * Register values.
 #define WM831X_ON_PIN_TO_SHIFT                       0  /* ON_PIN_TO - [1:0] */
 #define WM831X_ON_PIN_TO_WIDTH                       2  /* ON_PIN_TO - [1:0] */
 
+/*
+ * R16528 (0x4090) - Clock Control 1
+ */
+#define WM831X_CLKOUT_ENA                       0x8000  /* CLKOUT_ENA */
+#define WM831X_CLKOUT_ENA_MASK                  0x8000  /* CLKOUT_ENA */
+#define WM831X_CLKOUT_ENA_SHIFT                     15  /* CLKOUT_ENA */
+#define WM831X_CLKOUT_ENA_WIDTH                      1  /* CLKOUT_ENA */
+#define WM831X_CLKOUT_OD                        0x2000  /* CLKOUT_OD */
+#define WM831X_CLKOUT_OD_MASK                   0x2000  /* CLKOUT_OD */
+#define WM831X_CLKOUT_OD_SHIFT                      13  /* CLKOUT_OD */
+#define WM831X_CLKOUT_OD_WIDTH                       1  /* CLKOUT_OD */
+#define WM831X_CLKOUT_SLOT_MASK                 0x0700  /* CLKOUT_SLOT - [10:8] */
+#define WM831X_CLKOUT_SLOT_SHIFT                     8  /* CLKOUT_SLOT - [10:8] */
+#define WM831X_CLKOUT_SLOT_WIDTH                     3  /* CLKOUT_SLOT - [10:8] */
+#define WM831X_CLKOUT_SLPSLOT_MASK              0x0070  /* CLKOUT_SLPSLOT - [6:4] */
+#define WM831X_CLKOUT_SLPSLOT_SHIFT                  4  /* CLKOUT_SLPSLOT - [6:4] */
+#define WM831X_CLKOUT_SLPSLOT_WIDTH                  3  /* CLKOUT_SLPSLOT - [6:4] */
+#define WM831X_CLKOUT_SRC                       0x0001  /* CLKOUT_SRC */
+#define WM831X_CLKOUT_SRC_MASK                  0x0001  /* CLKOUT_SRC */
+#define WM831X_CLKOUT_SRC_SHIFT                      0  /* CLKOUT_SRC */
+#define WM831X_CLKOUT_SRC_WIDTH                      1  /* CLKOUT_SRC */
+
+/*
+ * R16529 (0x4091) - Clock Control 2
+ */
+#define WM831X_XTAL_INH                         0x8000  /* XTAL_INH */
+#define WM831X_XTAL_INH_MASK                    0x8000  /* XTAL_INH */
+#define WM831X_XTAL_INH_SHIFT                       15  /* XTAL_INH */
+#define WM831X_XTAL_INH_WIDTH                        1  /* XTAL_INH */
+#define WM831X_XTAL_ENA                         0x2000  /* XTAL_ENA */
+#define WM831X_XTAL_ENA_MASK                    0x2000  /* XTAL_ENA */
+#define WM831X_XTAL_ENA_SHIFT                       13  /* XTAL_ENA */
+#define WM831X_XTAL_ENA_WIDTH                        1  /* XTAL_ENA */
+#define WM831X_XTAL_BKUPENA                     0x1000  /* XTAL_BKUPENA */
+#define WM831X_XTAL_BKUPENA_MASK                0x1000  /* XTAL_BKUPENA */
+#define WM831X_XTAL_BKUPENA_SHIFT                   12  /* XTAL_BKUPENA */
+#define WM831X_XTAL_BKUPENA_WIDTH                    1  /* XTAL_BKUPENA */
+#define WM831X_FLL_AUTO                         0x0080  /* FLL_AUTO */
+#define WM831X_FLL_AUTO_MASK                    0x0080  /* FLL_AUTO */
+#define WM831X_FLL_AUTO_SHIFT                        7  /* FLL_AUTO */
+#define WM831X_FLL_AUTO_WIDTH                        1  /* FLL_AUTO */
+#define WM831X_FLL_AUTO_FREQ_MASK               0x0007  /* FLL_AUTO_FREQ - [2:0] */
+#define WM831X_FLL_AUTO_FREQ_SHIFT                   0  /* FLL_AUTO_FREQ - [2:0] */
+#define WM831X_FLL_AUTO_FREQ_WIDTH                   3  /* FLL_AUTO_FREQ - [2:0] */
+
+/*
+ * R16530 (0x4092) - FLL Control 1
+ */
+#define WM831X_FLL_FRAC                         0x0004  /* FLL_FRAC */
+#define WM831X_FLL_FRAC_MASK                    0x0004  /* FLL_FRAC */
+#define WM831X_FLL_FRAC_SHIFT                        2  /* FLL_FRAC */
+#define WM831X_FLL_FRAC_WIDTH                        1  /* FLL_FRAC */
+#define WM831X_FLL_OSC_ENA                      0x0002  /* FLL_OSC_ENA */
+#define WM831X_FLL_OSC_ENA_MASK                 0x0002  /* FLL_OSC_ENA */
+#define WM831X_FLL_OSC_ENA_SHIFT                     1  /* FLL_OSC_ENA */
+#define WM831X_FLL_OSC_ENA_WIDTH                     1  /* FLL_OSC_ENA */
+#define WM831X_FLL_ENA                          0x0001  /* FLL_ENA */
+#define WM831X_FLL_ENA_MASK                     0x0001  /* FLL_ENA */
+#define WM831X_FLL_ENA_SHIFT                         0  /* FLL_ENA */
+#define WM831X_FLL_ENA_WIDTH                         1  /* FLL_ENA */
+
+/*
+ * R16531 (0x4093) - FLL Control 2
+ */
+#define WM831X_FLL_OUTDIV_MASK                  0x3F00  /* FLL_OUTDIV - [13:8] */
+#define WM831X_FLL_OUTDIV_SHIFT                      8  /* FLL_OUTDIV - [13:8] */
+#define WM831X_FLL_OUTDIV_WIDTH                      6  /* FLL_OUTDIV - [13:8] */
+#define WM831X_FLL_CTRL_RATE_MASK               0x0070  /* FLL_CTRL_RATE - [6:4] */
+#define WM831X_FLL_CTRL_RATE_SHIFT                   4  /* FLL_CTRL_RATE - [6:4] */
+#define WM831X_FLL_CTRL_RATE_WIDTH                   3  /* FLL_CTRL_RATE - [6:4] */
+#define WM831X_FLL_FRATIO_MASK                  0x0007  /* FLL_FRATIO - [2:0] */
+#define WM831X_FLL_FRATIO_SHIFT                      0  /* FLL_FRATIO - [2:0] */
+#define WM831X_FLL_FRATIO_WIDTH                      3  /* FLL_FRATIO - [2:0] */
+
+/*
+ * R16532 (0x4094) - FLL Control 3
+ */
+#define WM831X_FLL_K_MASK                       0xFFFF  /* FLL_K - [15:0] */
+#define WM831X_FLL_K_SHIFT                           0  /* FLL_K - [15:0] */
+#define WM831X_FLL_K_WIDTH                          16  /* FLL_K - [15:0] */
+
+/*
+ * R16533 (0x4095) - FLL Control 4
+ */
+#define WM831X_FLL_N_MASK                       0x7FE0  /* FLL_N - [14:5] */
+#define WM831X_FLL_N_SHIFT                           5  /* FLL_N - [14:5] */
+#define WM831X_FLL_N_WIDTH                          10  /* FLL_N - [14:5] */
+#define WM831X_FLL_GAIN_MASK                    0x000F  /* FLL_GAIN - [3:0] */
+#define WM831X_FLL_GAIN_SHIFT                        0  /* FLL_GAIN - [3:0] */
+#define WM831X_FLL_GAIN_WIDTH                        4  /* FLL_GAIN - [3:0] */
+
+/*
+ * R16534 (0x4096) - FLL Control 5
+ */
+#define WM831X_FLL_CLK_REF_DIV_MASK             0x0018  /* FLL_CLK_REF_DIV - [4:3] */
+#define WM831X_FLL_CLK_REF_DIV_SHIFT                 3  /* FLL_CLK_REF_DIV - [4:3] */
+#define WM831X_FLL_CLK_REF_DIV_WIDTH                 2  /* FLL_CLK_REF_DIV - [4:3] */
+#define WM831X_FLL_CLK_SRC_MASK                 0x0003  /* FLL_CLK_SRC - [1:0] */
+#define WM831X_FLL_CLK_SRC_SHIFT                     0  /* FLL_CLK_SRC - [1:0] */
+#define WM831X_FLL_CLK_SRC_WIDTH                     2  /* FLL_CLK_SRC - [1:0] */
+
 struct regulator_dev;
 
 #define WM831X_NUM_IRQ_REGS 5
+#define WM831X_NUM_GPIO_REGS 16
 
 enum wm831x_parent {
        WM8310 = 0x8310,
@@ -248,6 +351,12 @@ enum wm831x_parent {
        WM8326 = 0x8326,
 };
 
+struct wm831x;
+enum wm831x_auxadc;
+
+typedef int (*wm831x_auxadc_read_fn)(struct wm831x *wm831x,
+                                    enum wm831x_auxadc input);
+
 struct wm831x {
        struct mutex io_lock;
 
@@ -261,7 +370,7 @@ struct wm831x {
 
        int irq;  /* Our chip IRQ */
        struct mutex irq_lock;
-       unsigned int irq_base;
+       int irq_base;
        int irq_masks_cur[WM831X_NUM_IRQ_REGS];   /* Currently active value */
        int irq_masks_cache[WM831X_NUM_IRQ_REGS]; /* Cached hardware value */
 
@@ -272,8 +381,13 @@ struct wm831x {
 
        int num_gpio;
 
+       /* Used by the interrupt controller code to post writes */
+       int gpio_update[WM831X_NUM_GPIO_REGS];
+
        struct mutex auxadc_lock;
-       struct completion auxadc_done;
+       struct list_head auxadc_pending;
+       u16 auxadc_active;
+       wm831x_auxadc_read_fn auxadc_read;
 
        /* The WM831x has a security key blocking access to certain
         * registers.  The mutex is taken by the accessors for locking
@@ -300,5 +414,6 @@ void wm831x_device_exit(struct wm831x *wm831x);
 int wm831x_device_suspend(struct wm831x *wm831x);
 int wm831x_irq_init(struct wm831x *wm831x, int irq);
 void wm831x_irq_exit(struct wm831x *wm831x);
+void wm831x_auxadc_init(struct wm831x *wm831x);
 
 #endif
index ff42d70..0ba2459 100644 (file)
@@ -120,6 +120,9 @@ struct wm831x_pdata {
        /** Put the /IRQ line into CMOS mode */
        bool irq_cmos;
 
+       /** Disable the touchscreen */
+       bool disable_touch;
+
        int irq_base;
        int gpio_base;
        int gpio_defaults[WM831X_GPIO_NUM];
index 18fd130..c309b1e 100644 (file)
@@ -40,6 +40,7 @@
 #define BTRFS_MINOR            234
 #define AUTOFS_MINOR           235
 #define MAPPER_CTRL_MINOR      236
+#define LOOP_CTRL_MINOR                237
 #define MISC_DYNAMIC_MINOR     255
 
 struct device;
index 3172a1c..7438071 100644 (file)
@@ -685,7 +685,7 @@ static inline void set_page_section(struct page *page, unsigned long section)
        page->flags |= (section & SECTIONS_MASK) << SECTIONS_PGSHIFT;
 }
 
-static inline unsigned long page_to_section(struct page *page)
+static inline unsigned long page_to_section(const struct page *page)
 {
        return (page->flags >> SECTIONS_PGSHIFT) & SECTIONS_MASK;
 }
@@ -720,7 +720,7 @@ static inline void set_page_links(struct page *page, enum zone_type zone,
 
 static __always_inline void *lowmem_page_address(const struct page *page)
 {
-       return __va(PFN_PHYS(page_to_pfn((struct page *)page)));
+       return __va(PFN_PHYS(page_to_pfn(page)));
 }
 
 #if defined(CONFIG_HIGHMEM) && !defined(WANT_PAGE_VIRTUAL)
@@ -737,7 +737,7 @@ static __always_inline void *lowmem_page_address(const struct page *page)
 #endif
 
 #if defined(HASHED_PAGE_VIRTUAL)
-void *page_address(struct page *page);
+void *page_address(const struct page *page);
 void set_page_address(struct page *page, void *virtual);
 void page_address_init(void);
 #endif
@@ -962,6 +962,8 @@ int invalidate_inode_page(struct page *page);
 #ifdef CONFIG_MMU
 extern int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                        unsigned long address, unsigned int flags);
+extern int fixup_user_fault(struct task_struct *tsk, struct mm_struct *mm,
+                           unsigned long address, unsigned int fault_flags);
 #else
 static inline int handle_mm_fault(struct mm_struct *mm,
                        struct vm_area_struct *vma, unsigned long address,
@@ -971,6 +973,14 @@ static inline int handle_mm_fault(struct mm_struct *mm,
        BUG();
        return VM_FAULT_SIGBUS;
 }
+static inline int fixup_user_fault(struct task_struct *tsk,
+               struct mm_struct *mm, unsigned long address,
+               unsigned int fault_flags)
+{
+       /* should never happen if there's no MMU */
+       BUG();
+       return -EFAULT;
+}
 #endif
 
 extern int make_pages_present(unsigned long addr, unsigned long end);
@@ -988,8 +998,6 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
 int get_user_pages_fast(unsigned long start, int nr_pages, int write,
                        struct page **pages);
 struct page *get_dump_page(unsigned long addr);
-extern int fixup_user_fault(struct task_struct *tsk, struct mm_struct *mm,
-                           unsigned long address, unsigned int fault_flags);
 
 extern int try_to_release_page(struct page * page, gfp_t gfp_mask);
 extern void do_invalidatepage(struct page *page, unsigned long offset);
@@ -1600,6 +1608,7 @@ enum mf_flags {
 };
 extern void memory_failure(unsigned long pfn, int trapno);
 extern int __memory_failure(unsigned long pfn, int trapno, int flags);
+extern void memory_failure_queue(unsigned long pfn, int trapno, int flags);
 extern int unpoison_memory(unsigned long pfn);
 extern int sysctl_memory_failure_early_kill;
 extern int sysctl_memory_failure_recovery;
index 027935c..774b895 100644 (file)
@@ -30,23 +30,61 @@ struct address_space;
  * moment. Note that we have no way to track which tasks are using
  * a page, though if it is a pagecache page, rmap structures can tell us
  * who is mapping it.
+ *
+ * The objects in struct page are organized in double word blocks in
+ * order to allows us to use atomic double word operations on portions
+ * of struct page. That is currently only used by slub but the arrangement
+ * allows the use of atomic double word operations on the flags/mapping
+ * and lru list pointers also.
  */
 struct page {
+       /* First double word block */
        unsigned long flags;            /* Atomic flags, some possibly
                                         * updated asynchronously */
-       atomic_t _count;                /* Usage count, see below. */
-       union {
-               atomic_t _mapcount;     /* Count of ptes mapped in mms,
-                                        * to show when page is mapped
-                                        * & limit reverse map searches.
+       struct address_space *mapping;  /* If low bit clear, points to
+                                        * inode address_space, or NULL.
+                                        * If page mapped as anonymous
+                                        * memory, low bit is set, and
+                                        * it points to anon_vma object:
+                                        * see PAGE_MAPPING_ANON below.
                                         */
-               struct {                /* SLUB */
-                       u16 inuse;
-                       u16 objects;
+       /* Second double word */
+       struct {
+               union {
+                       pgoff_t index;          /* Our offset within mapping. */
+                       void *freelist;         /* slub first free object */
+               };
+
+               union {
+                       /* Used for cmpxchg_double in slub */
+                       unsigned long counters;
+
+                       struct {
+
+                               union {
+                                       atomic_t _mapcount;     /* Count of ptes mapped in mms,
+                                                        * to show when page is mapped
+                                                        * & limit reverse map searches.
+                                                        */
+
+                                       struct {
+                                               unsigned inuse:16;
+                                               unsigned objects:15;
+                                               unsigned frozen:1;
+                                       };
+                               };
+                               atomic_t _count;                /* Usage count, see below. */
+                       };
                };
        };
+
+       /* Third double word block */
+       struct list_head lru;           /* Pageout list, eg. active_list
+                                        * protected by zone->lru_lock !
+                                        */
+
+       /* Remainder is not double word aligned */
        union {
-           struct {
                unsigned long private;          /* Mapping-private opaque data:
                                                 * usually used for buffer_heads
                                                 * if PagePrivate set; used for
@@ -54,27 +92,13 @@ struct page {
                                                 * indicates order in the buddy
                                                 * system if PG_buddy is set.
                                                 */
-               struct address_space *mapping;  /* If low bit clear, points to
-                                                * inode address_space, or NULL.
-                                                * If page mapped as anonymous
-                                                * memory, low bit is set, and
-                                                * it points to anon_vma object:
-                                                * see PAGE_MAPPING_ANON below.
-                                                */
-           };
 #if USE_SPLIT_PTLOCKS
-           spinlock_t ptl;
+               spinlock_t ptl;
 #endif
-           struct kmem_cache *slab;    /* SLUB: Pointer to slab */
-           struct page *first_page;    /* Compound tail pages */
-       };
-       union {
-               pgoff_t index;          /* Our offset within mapping. */
-               void *freelist;         /* SLUB: freelist req. slab lock */
+               struct kmem_cache *slab;        /* SLUB: Pointer to slab */
+               struct page *first_page;        /* Compound tail pages */
        };
-       struct list_head lru;           /* Pageout list, eg. active_list
-                                        * protected by zone->lru_lock !
-                                        */
+
        /*
         * On machines where all RAM is mapped into kernel address space,
         * we can simply calculate the virtual address. On machines with
@@ -100,7 +124,16 @@ struct page {
         */
        void *shadow;
 #endif
-};
+}
+/*
+ * If another subsystem starts using the double word pairing for atomic
+ * operations on struct page then it must change the #if to ensure
+ * proper alignment of the page struct.
+ */
+#if defined(CONFIG_SLUB) && defined(CONFIG_CMPXCHG_LOCAL)
+       __attribute__((__aligned__(2*sizeof(unsigned long))))
+#endif
+;
 
 typedef unsigned long __nocast vm_flags_t;
 
index 0f83858..1d09562 100644 (file)
@@ -56,8 +56,6 @@ struct mmc_ios {
 #define MMC_TIMING_UHS_SDR104  4
 #define MMC_TIMING_UHS_DDR50   5
 
-       unsigned char   ddr;                    /* dual data rate used */
-
 #define MMC_SDR_MODE           0
 #define MMC_1_2V_DDR_MODE      1
 #define MMC_1_8V_DDR_MODE      2
index 2e17c5d..180540a 100644 (file)
@@ -29,7 +29,7 @@
 #define MAX_LINKS 32           
 
 struct sockaddr_nl {
-       sa_family_t     nl_family;      /* AF_NETLINK   */
+       __kernel_sa_family_t    nl_family;      /* AF_NETLINK   */
        unsigned short  nl_pad;         /* zero         */
        __u32           nl_pid;         /* port ID      */
                __u32           nl_groups;      /* multicast groups mask */
index f387919..8c6ee44 100644 (file)
@@ -29,6 +29,8 @@
 #define NFS_MNT_VERSION                1
 #define NFS_MNT3_VERSION       3
 
+#define NFS_PIPE_DIRNAME "/nfs"
+
 /*
  * NFS stats. The good thing with these values is that NFSv3 errors are
  * a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which
index a3c4bc8..76f99e8 100644 (file)
@@ -566,6 +566,7 @@ enum {
        NFSPROC4_CLNT_SECINFO_NO_NAME,
        NFSPROC4_CLNT_TEST_STATEID,
        NFSPROC4_CLNT_FREE_STATEID,
+       NFSPROC4_CLNT_GETDEVICELIST,
 };
 
 /* nfs41 types */
index 8b579be..eaac770 100644 (file)
@@ -99,9 +99,10 @@ struct nfs_open_context {
 
 struct nfs_open_dir_context {
        struct rpc_cred *cred;
+       unsigned long attr_gencount;
        __u64 dir_cookie;
        __u64 dup_cookie;
-       int duped;
+       signed char duped;
 };
 
 /*
@@ -568,12 +569,12 @@ extern struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type);
 extern int nfs3_proc_setacl(struct inode *inode, int type,
                            struct posix_acl *acl);
 extern int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode,
-               mode_t mode);
+               umode_t mode);
 extern void nfs3_forget_cached_acls(struct inode *inode);
 #else
 static inline int nfs3_proc_set_default_acl(struct inode *dir,
                                            struct inode *inode,
-                                           mode_t mode)
+                                           umode_t mode)
 {
        return 0;
 }
index 50a661f..b5479df 100644 (file)
@@ -131,8 +131,9 @@ struct nfs_server {
        struct fscache_cookie   *fscache;       /* superblock cookie */
 #endif
 
+       u32                     pnfs_blksize;   /* layout_blksize attr */
 #ifdef CONFIG_NFS_V4
-       u32                     attr_bitmask[2];/* V4 bitmask representing the set
+       u32                     attr_bitmask[3];/* V4 bitmask representing the set
                                                   of attributes supported on this
                                                   filesystem */
        u32                     cache_consistency_bitmask[2];
@@ -145,6 +146,7 @@ struct nfs_server {
                                                   filesystem */
        struct pnfs_layoutdriver_type  *pnfs_curr_ld; /* Active layout driver */
        struct rpc_wait_queue   roc_rpcwaitq;
+       void                    *pnfs_ld_data;  /* per mount point data */
 
        /* the following fields are protected by nfs_client->cl_lock */
        struct rb_root          state_owners;
index 5b11595..abd615d 100644 (file)
@@ -122,6 +122,7 @@ struct nfs_fsinfo {
        struct timespec         time_delta; /* server time granularity */
        __u32                   lease_time; /* in seconds */
        __u32                   layouttype; /* supported pnfs layout driver */
+       __u32                   blksize; /* preferred pnfs io block size */
 };
 
 struct nfs_fsstat {
@@ -235,6 +236,17 @@ struct nfs4_layoutget {
        gfp_t gfp_flags;
 };
 
+struct nfs4_getdevicelist_args {
+       const struct nfs_fh *fh;
+       u32 layoutclass;
+       struct nfs4_sequence_args seq_args;
+};
+
+struct nfs4_getdevicelist_res {
+       struct pnfs_devicelist *devlist;
+       struct nfs4_sequence_res seq_res;
+};
+
 struct nfs4_getdeviceinfo_args {
        struct pnfs_device *pdev;
        struct nfs4_sequence_args seq_args;
@@ -257,12 +269,13 @@ struct nfs4_layoutcommit_res {
        struct nfs_fattr *fattr;
        const struct nfs_server *server;
        struct nfs4_sequence_res seq_res;
+       int status;
 };
 
 struct nfs4_layoutcommit_data {
        struct rpc_task task;
        struct nfs_fattr fattr;
-       struct pnfs_layout_segment *lseg;
+       struct list_head lseg_list;
        struct rpc_cred *cred;
        struct nfs4_layoutcommit_args args;
        struct nfs4_layoutcommit_res res;
@@ -760,6 +773,11 @@ struct nfs3_getaclres {
        struct posix_acl *      acl_default;
 };
 
+struct nfs4_string {
+       unsigned int len;
+       char *data;
+};
+
 #ifdef CONFIG_NFS_V4
 
 typedef u64 clientid4;
@@ -943,18 +961,13 @@ struct nfs4_server_caps_arg {
 };
 
 struct nfs4_server_caps_res {
-       u32                             attr_bitmask[2];
+       u32                             attr_bitmask[3];
        u32                             acl_bitmask;
        u32                             has_links;
        u32                             has_symlinks;
        struct nfs4_sequence_res        seq_res;
 };
 
-struct nfs4_string {
-       unsigned int len;
-       char *data;
-};
-
 #define NFS4_PATHNAME_MAXCOMPONENTS 512
 struct nfs4_pathname {
        unsigned int ncomponents;
index bd716f8..9180dc5 100644 (file)
@@ -196,12 +196,13 @@ extern struct property *of_find_property(const struct device_node *np,
                                         const char *name,
                                         int *lenp);
 extern int of_property_read_u32_array(const struct device_node *np,
-                                     char *propname,
+                                     const char *propname,
                                      u32 *out_values,
                                      size_t sz);
 
-extern int of_property_read_string(struct device_node *np, char *propname,
-                                       const char **out_string);
+extern int of_property_read_string(struct device_node *np,
+                                  const char *propname,
+                                  const char **out_string);
 extern int of_device_is_compatible(const struct device_node *device,
                                   const char *);
 extern int of_device_is_available(const struct device_node *device);
@@ -242,21 +243,30 @@ static inline bool of_have_populated_dt(void)
 }
 
 static inline int of_property_read_u32_array(const struct device_node *np,
-                               char *propname, u32 *out_values, size_t sz)
+                                            const char *propname,
+                                            u32 *out_values, size_t sz)
 {
        return -ENOSYS;
 }
 
 static inline int of_property_read_string(struct device_node *np,
-                               char *propname, const char **out_string)
+                                         const char *propname,
+                                         const char **out_string)
 {
        return -ENOSYS;
 }
 
+static inline const void *of_get_property(const struct device_node *node,
+                               const char *name,
+                               int *lenp)
+{
+       return NULL;
+}
+
 #endif /* CONFIG_OF */
 
 static inline int of_property_read_u32(const struct device_node *np,
-                                      char *propname,
+                                      const char *propname,
                                       u32 *out_value)
 {
        return of_property_read_u32_array(np, propname, out_value, 1);
index aec8025..52280a2 100644 (file)
@@ -57,6 +57,8 @@ extern int of_mm_gpiochip_add(struct device_node *np,
 extern void of_gpiochip_add(struct gpio_chip *gc);
 extern void of_gpiochip_remove(struct gpio_chip *gc);
 extern struct gpio_chip *of_node_to_gpiochip(struct device_node *np);
+extern int of_gpio_simple_xlate(struct gpio_chip *gc, struct device_node *np,
+                               const void *gpio_spec, u32 *flags);
 
 #else /* CONFIG_OF_GPIO */
 
@@ -72,6 +74,13 @@ static inline unsigned int of_gpio_count(struct device_node *np)
        return 0;
 }
 
+static inline int of_gpio_simple_xlate(struct gpio_chip *gc,
+                                      struct device_node *np,
+                                      const void *gpio_spec, u32 *flags)
+{
+       return -ENOSYS;
+}
+
 static inline void of_gpiochip_add(struct gpio_chip *gc) { }
 static inline void of_gpiochip_remove(struct gpio_chip *gc) { }
 
index e6955f5..cd2e61c 100644 (file)
@@ -63,6 +63,9 @@ extern int of_irq_map_one(struct device_node *device, int index,
 extern unsigned int irq_create_of_mapping(struct device_node *controller,
                                          const u32 *intspec,
                                          unsigned int intsize);
+#ifdef CONFIG_IRQ_DOMAIN
+extern void irq_dispose_mapping(unsigned int irq);
+#endif
 extern int of_irq_to_resource(struct device_node *dev, int index,
                              struct resource *r);
 extern int of_irq_count(struct device_node *dev);
@@ -70,6 +73,7 @@ extern int of_irq_to_resource_table(struct device_node *dev,
                struct resource *res, int nr_irqs);
 extern struct device_node *of_irq_find_parent(struct device_node *child);
 
+
 #endif /* CONFIG_OF_IRQ */
 #endif /* CONFIG_OF */
 #endif /* __OF_IRQ_H */
index e913081..f474641 100644 (file)
@@ -9,6 +9,7 @@
 
 #ifdef CONFIG_OF_NET
 #include <linux/of.h>
+extern const int of_get_phy_mode(struct device_node *np);
 extern const void *of_get_mac_address(struct device_node *np);
 #endif
 
index 3e5a1b1..e90a673 100644 (file)
@@ -124,9 +124,6 @@ enum pageflags {
 
        /* SLOB */
        PG_slob_free = PG_private,
-
-       /* SLUB */
-       PG_slub_frozen = PG_active,
 };
 
 #ifndef __GENERATING_BOUNDS_H
@@ -212,8 +209,6 @@ PAGEFLAG(SwapBacked, swapbacked) __CLEARPAGEFLAG(SwapBacked, swapbacked)
 
 __PAGEFLAG(SlobFree, slob_free)
 
-__PAGEFLAG(SlubFrozen, slub_frozen)
-
 /*
  * Private page markings that may be used by the filesystem that owns the page
  * for its own purposes.
index 3a5626d..8c230cb 100644 (file)
@@ -251,7 +251,8 @@ struct pci_dev {
        u8              revision;       /* PCI revision, low byte of class word */
        u8              hdr_type;       /* PCI header type (`multi' flag masked out) */
        u8              pcie_cap;       /* PCI-E capability offset */
-       u8              pcie_type;      /* PCI-E device/port type */
+       u8              pcie_type:4;    /* PCI-E device/port type */
+       u8              pcie_mpss:3;    /* PCI-E Max Payload Size Supported */
        u8              rom_base_reg;   /* which config register controls the ROM */
        u8              pin;            /* which interrupt pin this device uses */
 
@@ -617,6 +618,16 @@ struct pci_driver {
 /* these external functions are only available when PCI support is enabled */
 #ifdef CONFIG_PCI
 
+extern void pcie_bus_configure_settings(struct pci_bus *bus, u8 smpss);
+
+enum pcie_bus_config_types {
+       PCIE_BUS_PERFORMANCE,
+       PCIE_BUS_SAFE,
+       PCIE_BUS_PEER2PEER,
+};
+
+extern enum pcie_bus_config_types pcie_bus_config;
+
 extern struct bus_type pci_bus_type;
 
 /* Do NOT directly access these two variables, unless you are arch specific pci
@@ -796,10 +807,13 @@ int pcix_get_mmrbc(struct pci_dev *dev);
 int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc);
 int pcie_get_readrq(struct pci_dev *dev);
 int pcie_set_readrq(struct pci_dev *dev, int rq);
+int pcie_get_mps(struct pci_dev *dev);
+int pcie_set_mps(struct pci_dev *dev, int mps);
 int __pci_reset_function(struct pci_dev *dev);
 int pci_reset_function(struct pci_dev *dev);
 void pci_update_resource(struct pci_dev *dev, int resno);
 int __must_check pci_assign_resource(struct pci_dev *dev, int i);
+int __must_check pci_reassign_resource(struct pci_dev *dev, int i, resource_size_t add_size, resource_size_t align);
 int pci_select_bars(struct pci_dev *dev, unsigned long flags);
 
 /* ROM control related routines */
@@ -843,8 +857,8 @@ void pci_enable_ido(struct pci_dev *dev, unsigned long type);
 void pci_disable_ido(struct pci_dev *dev, unsigned long type);
 
 enum pci_obff_signal_type {
-       PCI_EXP_OBFF_SIGNAL_L0,
-       PCI_EXP_OBFF_SIGNAL_ALWAYS,
+       PCI_EXP_OBFF_SIGNAL_L0 = 0,
+       PCI_EXP_OBFF_SIGNAL_ALWAYS = 1,
 };
 int pci_enable_obff(struct pci_dev *dev, enum pci_obff_signal_type);
 void pci_disable_obff(struct pci_dev *dev);
@@ -879,7 +893,7 @@ void pdev_enable_device(struct pci_dev *);
 void pdev_sort_resources(struct pci_dev *, struct resource_list *);
 int pci_enable_resources(struct pci_dev *, int mask);
 void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
-                   int (*)(struct pci_dev *, u8, u8));
+                   int (*)(const struct pci_dev *, u8, u8));
 #define HAVE_PCI_REQ_REGIONS   2
 int __must_check pci_request_regions(struct pci_dev *, const char *);
 int __must_check pci_request_regions_exclusive(struct pci_dev *, const char *);
index b00c4ec..ae96bbe 100644 (file)
 #define PCI_DEVICE_ID_INTEL_ICH10_5    0x3a60
 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MIN      0x3b00
 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MAX      0x3b1f
+#define PCI_DEVICE_ID_INTEL_IOAT_SNB0  0x3c20
+#define PCI_DEVICE_ID_INTEL_IOAT_SNB1  0x3c21
+#define PCI_DEVICE_ID_INTEL_IOAT_SNB2  0x3c22
+#define PCI_DEVICE_ID_INTEL_IOAT_SNB3  0x3c23
+#define PCI_DEVICE_ID_INTEL_IOAT_SNB4  0x3c24
+#define PCI_DEVICE_ID_INTEL_IOAT_SNB5  0x3c25
+#define PCI_DEVICE_ID_INTEL_IOAT_SNB6  0x3c26
+#define PCI_DEVICE_ID_INTEL_IOAT_SNB7  0x3c27
+#define PCI_DEVICE_ID_INTEL_IOAT_SNB8  0x3c2e
+#define PCI_DEVICE_ID_INTEL_IOAT_SNB9  0x3c2f
 #define PCI_DEVICE_ID_INTEL_IOAT_SNB   0x402f
 #define PCI_DEVICE_ID_INTEL_5100_16    0x65f0
 #define PCI_DEVICE_ID_INTEL_5100_21    0x65f5
index ad51863..54fc413 100644 (file)
@@ -53,6 +53,7 @@
 
 /* Interface Mode definitions */
 typedef enum {
+       PHY_INTERFACE_MODE_NA,
        PHY_INTERFACE_MODE_MII,
        PHY_INTERFACE_MODE_GMII,
        PHY_INTERFACE_MODE_SGMII,
@@ -62,7 +63,8 @@ typedef enum {
        PHY_INTERFACE_MODE_RGMII_ID,
        PHY_INTERFACE_MODE_RGMII_RXID,
        PHY_INTERFACE_MODE_RGMII_TXID,
-       PHY_INTERFACE_MODE_RTBI
+       PHY_INTERFACE_MODE_RTBI,
+       PHY_INTERFACE_MODE_SMII,
 } phy_interface_t;
 
 
diff --git a/include/linux/platform_data/ntc_thermistor.h b/include/linux/platform_data/ntc_thermistor.h
new file mode 100644 (file)
index 0000000..abd2862
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * ntc_thermistor.h - NTC Thermistors
+ *
+ *  Copyright (C) 2010 Samsung Electronics
+ *  MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef _LINUX_NTC_H
+#define _LINUX_NTC_H
+
+enum ntc_thermistor_type {
+       TYPE_NCPXXWB473,
+       TYPE_NCPXXWL333,
+};
+
+struct ntc_thermistor_platform_data {
+       /*
+        * One (not both) of read_uV and read_ohm should be provided and only
+        * one of the two should be provided.
+        * Both functions should return negative value for an error case.
+        *
+        * pullup_uV, pullup_ohm, pulldown_ohm, and connect are required to use
+        * read_uV()
+        *
+        * How to setup pullup_ohm, pulldown_ohm, and connect is
+        * described at Documentation/hwmon/ntc
+        *
+        * pullup/down_ohm: 0 for infinite / not-connected
+        */
+       int (*read_uV)(void);
+       unsigned int pullup_uV;
+
+       unsigned int pullup_ohm;
+       unsigned int pulldown_ohm;
+       enum { NTC_CONNECTED_POSITIVE, NTC_CONNECTED_GROUND } connect;
+
+       int (*read_ohm)(void);
+};
+
+#endif /* _LINUX_NTC_H */
index 21097cb..f9ec173 100644 (file)
@@ -72,8 +72,6 @@ extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
 extern void pm_genpd_init(struct generic_pm_domain *genpd,
                          struct dev_power_governor *gov, bool is_off);
 extern int pm_genpd_poweron(struct generic_pm_domain *genpd);
-extern void pm_genpd_poweroff_unused(void);
-extern void genpd_queue_power_off_work(struct generic_pm_domain *genpd);
 #else
 static inline int pm_genpd_add_device(struct generic_pm_domain *genpd,
                                      struct device *dev)
@@ -101,8 +99,14 @@ static inline int pm_genpd_poweron(struct generic_pm_domain *genpd)
 {
        return -ENOSYS;
 }
-static inline void pm_genpd_poweroff_unused(void) {}
+#endif
+
+#ifdef CONFIG_PM_GENERIC_DOMAINS_RUNTIME
+extern void genpd_queue_power_off_work(struct generic_pm_domain *genpd);
+extern void pm_genpd_poweroff_unused(void);
+#else
 static inline void genpd_queue_power_off_work(struct generic_pm_domain *gpd) {}
+static inline void pm_genpd_poweroff_unused(void) {}
 #endif
 
 #endif /* _LINUX_PM_DOMAIN_H */
index 9a53b99..b768110 100644 (file)
@@ -9,6 +9,7 @@
 #define __LINUX_POSIX_ACL_H
 
 #include <linux/slab.h>
+#include <linux/rcupdate.h>
 
 #define ACL_UNDEFINED_ID       (-1)
 
@@ -38,7 +39,10 @@ struct posix_acl_entry {
 };
 
 struct posix_acl {
-       atomic_t                a_refcount;
+       union {
+               atomic_t                a_refcount;
+               struct rcu_head         a_rcu;
+       };
        unsigned int            a_count;
        struct posix_acl_entry  a_entries[0];
 };
@@ -65,7 +69,7 @@ static inline void
 posix_acl_release(struct posix_acl *acl)
 {
        if (acl && atomic_dec_and_test(&acl->a_refcount))
-               kfree(acl);
+               kfree_rcu(acl, a_rcu);
 }
 
 
@@ -75,29 +79,31 @@ extern void posix_acl_init(struct posix_acl *, int);
 extern struct posix_acl *posix_acl_alloc(int, gfp_t);
 extern int posix_acl_valid(const struct posix_acl *);
 extern int posix_acl_permission(struct inode *, const struct posix_acl *, int);
-extern struct posix_acl *posix_acl_from_mode(mode_t, gfp_t);
-extern int posix_acl_equiv_mode(const struct posix_acl *, mode_t *);
-extern int posix_acl_create(struct posix_acl **, gfp_t, mode_t *);
-extern int posix_acl_chmod(struct posix_acl **, gfp_t, mode_t);
+extern struct posix_acl *posix_acl_from_mode(umode_t, gfp_t);
+extern int posix_acl_equiv_mode(const struct posix_acl *, umode_t *);
+extern int posix_acl_create(struct posix_acl **, gfp_t, umode_t *);
+extern int posix_acl_chmod(struct posix_acl **, gfp_t, umode_t);
 
 extern struct posix_acl *get_posix_acl(struct inode *, int);
 extern int set_posix_acl(struct inode *, int, struct posix_acl *);
 
 #ifdef CONFIG_FS_POSIX_ACL
-static inline struct posix_acl *get_cached_acl(struct inode *inode, int type)
+static inline struct posix_acl **acl_by_type(struct inode *inode, int type)
 {
-       struct posix_acl **p, *acl;
        switch (type) {
        case ACL_TYPE_ACCESS:
-               p = &inode->i_acl;
-               break;
+               return &inode->i_acl;
        case ACL_TYPE_DEFAULT:
-               p = &inode->i_default_acl;
-               break;
+               return &inode->i_default_acl;
        default:
-               return ERR_PTR(-EINVAL);
+               BUG();
        }
-       acl = ACCESS_ONCE(*p);
+}
+
+static inline struct posix_acl *get_cached_acl(struct inode *inode, int type)
+{
+       struct posix_acl **p = acl_by_type(inode, type);
+       struct posix_acl *acl = ACCESS_ONCE(*p);
        if (acl) {
                spin_lock(&inode->i_lock);
                acl = *p;
@@ -108,41 +114,20 @@ static inline struct posix_acl *get_cached_acl(struct inode *inode, int type)
        return acl;
 }
 
-static inline int negative_cached_acl(struct inode *inode, int type)
+static inline struct posix_acl *get_cached_acl_rcu(struct inode *inode, int type)
 {
-       struct posix_acl **p, *acl;
-       switch (type) {
-       case ACL_TYPE_ACCESS:
-               p = &inode->i_acl;
-               break;
-       case ACL_TYPE_DEFAULT:
-               p = &inode->i_default_acl;
-               break;
-       default:
-               BUG();
-       }
-       acl = ACCESS_ONCE(*p);
-       if (acl)
-               return 0;
-       return 1;
+       return rcu_dereference(*acl_by_type(inode, type));
 }
 
 static inline void set_cached_acl(struct inode *inode,
                                  int type,
                                  struct posix_acl *acl)
 {
-       struct posix_acl *old = NULL;
+       struct posix_acl **p = acl_by_type(inode, type);
+       struct posix_acl *old;
        spin_lock(&inode->i_lock);
-       switch (type) {
-       case ACL_TYPE_ACCESS:
-               old = inode->i_acl;
-               inode->i_acl = posix_acl_dup(acl);
-               break;
-       case ACL_TYPE_DEFAULT:
-               old = inode->i_default_acl;
-               inode->i_default_acl = posix_acl_dup(acl);
-               break;
-       }
+       old = *p;
+       rcu_assign_pointer(*p, posix_acl_dup(acl));
        spin_unlock(&inode->i_lock);
        if (old != ACL_NOT_CACHED)
                posix_acl_release(old);
@@ -150,18 +135,11 @@ static inline void set_cached_acl(struct inode *inode,
 
 static inline void forget_cached_acl(struct inode *inode, int type)
 {
-       struct posix_acl *old = NULL;
+       struct posix_acl **p = acl_by_type(inode, type);
+       struct posix_acl *old;
        spin_lock(&inode->i_lock);
-       switch (type) {
-       case ACL_TYPE_ACCESS:
-               old = inode->i_acl;
-               inode->i_acl = ACL_NOT_CACHED;
-               break;
-       case ACL_TYPE_DEFAULT:
-               old = inode->i_default_acl;
-               inode->i_default_acl = ACL_NOT_CACHED;
-               break;
-       }
+       old = *p;
+       *p = ACL_NOT_CACHED;
        spin_unlock(&inode->i_lock);
        if (old != ACL_NOT_CACHED)
                posix_acl_release(old);
index b0843b6..1398eb0 100644 (file)
  * @battery_detect:            GPIO which is used to detect battery presence
  * @battery_detect_present:    gpio state when battery is present (0 / 1)
  * @i2c_retry_count:           # of times to retry on i2c IO failure
+ * @poll_retry_count:          # of times to retry looking for new status after
+ *                             external change notification
  */
 struct bq20z75_platform_data {
        int battery_detect;
        int battery_detect_present;
        int i2c_retry_count;
+       int poll_retry_count;
 };
 
 #endif
index 7995deb..fe99211 100644 (file)
 #ifndef __MAX17042_BATTERY_H_
 #define __MAX17042_BATTERY_H_
 
+#define MAX17042_STATUS_BattAbsent     (1 << 3)
+#define MAX17042_BATTERY_FULL  (100)
+#define MAX17042_DEFAULT_SNS_RESISTOR  (10000)
+
+enum max17042_register {
+       MAX17042_STATUS         = 0x00,
+       MAX17042_VALRT_Th       = 0x01,
+       MAX17042_TALRT_Th       = 0x02,
+       MAX17042_SALRT_Th       = 0x03,
+       MAX17042_AtRate         = 0x04,
+       MAX17042_RepCap         = 0x05,
+       MAX17042_RepSOC         = 0x06,
+       MAX17042_Age            = 0x07,
+       MAX17042_TEMP           = 0x08,
+       MAX17042_VCELL          = 0x09,
+       MAX17042_Current        = 0x0A,
+       MAX17042_AvgCurrent     = 0x0B,
+       MAX17042_Qresidual      = 0x0C,
+       MAX17042_SOC            = 0x0D,
+       MAX17042_AvSOC          = 0x0E,
+       MAX17042_RemCap         = 0x0F,
+       MAX17402_FullCAP        = 0x10,
+       MAX17042_TTE            = 0x11,
+       MAX17042_V_empty        = 0x12,
+
+       MAX17042_RSLOW          = 0x14,
+
+       MAX17042_AvgTA          = 0x16,
+       MAX17042_Cycles         = 0x17,
+       MAX17042_DesignCap      = 0x18,
+       MAX17042_AvgVCELL       = 0x19,
+       MAX17042_MinMaxTemp     = 0x1A,
+       MAX17042_MinMaxVolt     = 0x1B,
+       MAX17042_MinMaxCurr     = 0x1C,
+       MAX17042_CONFIG         = 0x1D,
+       MAX17042_ICHGTerm       = 0x1E,
+       MAX17042_AvCap          = 0x1F,
+       MAX17042_ManName        = 0x20,
+       MAX17042_DevName        = 0x21,
+       MAX17042_DevChem        = 0x22,
+
+       MAX17042_TempNom        = 0x24,
+       MAX17042_TempCold       = 0x25,
+       MAX17042_TempHot        = 0x26,
+       MAX17042_AIN            = 0x27,
+       MAX17042_LearnCFG       = 0x28,
+       MAX17042_SHFTCFG        = 0x29,
+       MAX17042_RelaxCFG       = 0x2A,
+       MAX17042_MiscCFG        = 0x2B,
+       MAX17042_TGAIN          = 0x2C,
+       MAx17042_TOFF           = 0x2D,
+       MAX17042_CGAIN          = 0x2E,
+       MAX17042_COFF           = 0x2F,
+
+       MAX17042_Q_empty        = 0x33,
+       MAX17042_T_empty        = 0x34,
+
+       MAX17042_RCOMP0         = 0x38,
+       MAX17042_TempCo         = 0x39,
+       MAX17042_Rx             = 0x3A,
+       MAX17042_T_empty0       = 0x3B,
+       MAX17042_TaskPeriod     = 0x3C,
+       MAX17042_FSTAT          = 0x3D,
+
+       MAX17042_SHDNTIMER      = 0x3F,
+
+       MAX17042_VFRemCap       = 0x4A,
+
+       MAX17042_QH             = 0x4D,
+       MAX17042_QL             = 0x4E,
+};
+
+/*
+ * used for setting a register to a desired value
+ * addr : address for a register
+ * data : setting value for the register
+ */
+struct max17042_reg_data {
+       u8 addr;
+       u16 data;
+};
+
 struct max17042_platform_data {
+       struct max17042_reg_data *init_data;
+       int num_init_data; /* Number of enties in init_data array */
        bool enable_current_sense;
+
+       /*
+        * R_sns in micro-ohms.
+        * default 10000 (if r_sns = 0) as it is the recommended value by
+        * the datasheet although it can be changed by board designers.
+        */
+       unsigned int r_sns;
 };
 
 #endif /* __MAX17042_BATTERY_H_ */
index 2455ef2..cc03bbf 100644 (file)
@@ -38,9 +38,12 @@ struct pstore_info {
        int             (*open)(struct pstore_info *psi);
        int             (*close)(struct pstore_info *psi);
        ssize_t         (*read)(u64 *id, enum pstore_type_id *type,
-                       struct timespec *time);
-       u64             (*write)(enum pstore_type_id type, size_t size);
-       int             (*erase)(u64 id);
+                       struct timespec *time, struct pstore_info *psi);
+       u64             (*write)(enum pstore_type_id type, unsigned int part,
+                       size_t size, struct pstore_info *psi);
+       int             (*erase)(enum pstore_type_id type, u64 id,
+                       struct pstore_info *psi);
+       void            *data;
 };
 
 #ifdef CONFIG_PSTORE
index 23241c2..9d4539c 100644 (file)
  * when it is shrunk, before we rcu free the node. See shrink code for
  * details.
  */
-#define RADIX_TREE_INDIRECT_PTR        1
+#define RADIX_TREE_INDIRECT_PTR                1
+/*
+ * A common use of the radix tree is to store pointers to struct pages;
+ * but shmem/tmpfs needs also to store swap entries in the same tree:
+ * those are marked as exceptional entries to distinguish them.
+ * EXCEPTIONAL_ENTRY tests the bit, EXCEPTIONAL_SHIFT shifts content past it.
+ */
+#define RADIX_TREE_EXCEPTIONAL_ENTRY   2
+#define RADIX_TREE_EXCEPTIONAL_SHIFT   2
 
 #define radix_tree_indirect_to_ptr(ptr) \
        radix_tree_indirect_to_ptr((void __force *)(ptr))
@@ -173,6 +181,28 @@ static inline int radix_tree_deref_retry(void *arg)
        return unlikely((unsigned long)arg & RADIX_TREE_INDIRECT_PTR);
 }
 
+/**
+ * radix_tree_exceptional_entry        - radix_tree_deref_slot gave exceptional entry?
+ * @arg:       value returned by radix_tree_deref_slot
+ * Returns:    0 if well-aligned pointer, non-0 if exceptional entry.
+ */
+static inline int radix_tree_exceptional_entry(void *arg)
+{
+       /* Not unlikely because radix_tree_exception often tested first */
+       return (unsigned long)arg & RADIX_TREE_EXCEPTIONAL_ENTRY;
+}
+
+/**
+ * radix_tree_exception        - radix_tree_deref_slot returned either exception?
+ * @arg:       value returned by radix_tree_deref_slot
+ * Returns:    0 if well-aligned pointer, non-0 if either kind of exception.
+ */
+static inline int radix_tree_exception(void *arg)
+{
+       return unlikely((unsigned long)arg &
+               (RADIX_TREE_INDIRECT_PTR | RADIX_TREE_EXCEPTIONAL_ENTRY));
+}
+
 /**
  * radix_tree_replace_slot     - replace item in a slot
  * @pslot:     pointer to slot, returned by radix_tree_lookup_slot
@@ -194,8 +224,8 @@ void *radix_tree_delete(struct radix_tree_root *, unsigned long);
 unsigned int
 radix_tree_gang_lookup(struct radix_tree_root *root, void **results,
                        unsigned long first_index, unsigned int max_items);
-unsigned int
-radix_tree_gang_lookup_slot(struct radix_tree_root *root, void ***results,
+unsigned int radix_tree_gang_lookup_slot(struct radix_tree_root *root,
+                       void ***results, unsigned long *indices,
                        unsigned long first_index, unsigned int max_items);
 unsigned long radix_tree_next_hole(struct radix_tree_root *root,
                                unsigned long index, unsigned long max_scan);
@@ -222,6 +252,7 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root,
                unsigned long nr_to_tag,
                unsigned int fromtag, unsigned int totag);
 int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag);
+unsigned long radix_tree_locate_item(struct radix_tree_root *root, void *item);
 
 static inline void radix_tree_preload_end(void)
 {
index ce29a04..d13059f 100644 (file)
@@ -57,18 +57,6 @@ extern void add_interrupt_randomness(int irq);
 extern void get_random_bytes(void *buf, int nbytes);
 void generate_random_uuid(unsigned char uuid_out[16]);
 
-extern __u32 secure_ip_id(__be32 daddr);
-extern __u32 secure_ipv6_id(const __be32 daddr[4]);
-extern u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport);
-extern u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
-                                     __be16 dport);
-extern __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
-                                       __be16 sport, __be16 dport);
-extern __u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr,
-                                         __be16 sport, __be16 dport);
-extern u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
-                                      __be16 sport, __be16 dport);
-
 #ifndef MODULE
 extern const struct file_operations random_fops, urandom_fops;
 #endif
index 9e87c1c..26f6ea4 100644 (file)
@@ -122,6 +122,9 @@ struct regulator;
 struct regulator_bulk_data {
        const char *supply;
        struct regulator *consumer;
+
+       /* Internal use */
+       int ret;
 };
 
 #if defined(CONFIG_REGULATOR)
index 6c433b8..1a80bc7 100644 (file)
@@ -188,18 +188,16 @@ struct regulator_dev {
 
        /* lists we belong to */
        struct list_head list; /* list of all regulators */
-       struct list_head slist; /* list of supplied regulators */
 
        /* lists we own */
        struct list_head consumer_list; /* consumers we supply */
-       struct list_head supply_list; /* regulators we supply */
 
        struct blocking_notifier_head notifier;
        struct mutex mutex; /* consumer lock */
        struct module *owner;
        struct device dev;
        struct regulation_constraints *constraints;
-       struct regulator_dev *supply;   /* for tree */
+       struct regulator *supply;       /* for tree */
 
        void *reg_data;         /* regulator_dev data */
 
index b27ebea..93f4d03 100644 (file)
@@ -97,6 +97,9 @@ struct rtc_pll_info {
 #define RTC_AF 0x20    /* Alarm interrupt */
 #define RTC_UF 0x10    /* Update interrupt for 1Hz RTC */
 
+
+#define RTC_MAX_FREQ   8192
+
 #ifdef __KERNEL__
 
 #include <linux/types.h>
index 20b03bf..4ac2c05 100644 (file)
@@ -1767,6 +1767,7 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *
 #define PF_DUMPCORE    0x00000200      /* dumped core */
 #define PF_SIGNALED    0x00000400      /* killed by a signal */
 #define PF_MEMALLOC    0x00000800      /* Allocating memory */
+#define PF_NPROC_EXCEEDED 0x00001000   /* set_user noticed that RLIMIT_NPROC was exceeded */
 #define PF_USED_MATH   0x00002000      /* if unset the fpu must be initialized before use */
 #define PF_FREEZING    0x00004000      /* freeze in progress. do not account to load */
 #define PF_NOFREEZE    0x00008000      /* this thread should not be frozen */
index a2afc9f..8bffe9a 100644 (file)
@@ -8,6 +8,8 @@
  * Generic header for SuperH SCI(F) (used by sh/sh64/h8300 and related parts)
  */
 
+#define SCIx_NOT_SUPPORTED     (-1)
+
 enum {
        SCBRR_ALGO_1,           /* ((clk + 16 * bps) / (16 * bps) - 1) */
        SCBRR_ALGO_2,           /* ((clk + 16 * bps) / (32 * bps) - 1) */
@@ -25,6 +27,28 @@ enum {
 #define SCSCR_CKE1     (1 << 1)
 #define SCSCR_CKE0     (1 << 0)
 
+/* SCxSR SCI */
+#define SCI_TDRE  0x80
+#define SCI_RDRF  0x40
+#define SCI_ORER  0x20
+#define SCI_FER   0x10
+#define SCI_PER   0x08
+#define SCI_TEND  0x04
+
+#define SCI_DEFAULT_ERROR_MASK (SCI_PER | SCI_FER)
+
+/* SCxSR SCIF */
+#define SCIF_ER    0x0080
+#define SCIF_TEND  0x0040
+#define SCIF_TDFE  0x0020
+#define SCIF_BRK   0x0010
+#define SCIF_FER   0x0008
+#define SCIF_PER   0x0004
+#define SCIF_RDF   0x0002
+#define SCIF_DR    0x0001
+
+#define SCIF_DEFAULT_ERROR_MASK (SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK)
+
 /* Offsets into the sci_port->irqs array */
 enum {
        SCIx_ERI_IRQ,
@@ -32,6 +56,24 @@ enum {
        SCIx_TXI_IRQ,
        SCIx_BRI_IRQ,
        SCIx_NR_IRQS,
+
+       SCIx_MUX_IRQ = SCIx_NR_IRQS,    /* special case */
+};
+
+enum {
+       SCIx_PROBE_REGTYPE,
+
+       SCIx_SCI_REGTYPE,
+       SCIx_IRDA_REGTYPE,
+       SCIx_SCIFA_REGTYPE,
+       SCIx_SCIFB_REGTYPE,
+       SCIx_SH3_SCIF_REGTYPE,
+       SCIx_SH4_SCIF_REGTYPE,
+       SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
+       SCIx_SH4_SCIF_FIFODATA_REGTYPE,
+       SCIx_SH7705_SCIF_REGTYPE,
+
+       SCIx_NR_REGTYPES,
 };
 
 #define SCIx_IRQ_MUXED(irq)            \
@@ -42,8 +84,29 @@ enum {
        [SCIx_BRI_IRQ]  = (irq),        \
 }
 
+#define SCIx_IRQ_IS_MUXED(port)                        \
+       ((port)->cfg->irqs[SCIx_ERI_IRQ] ==     \
+        (port)->cfg->irqs[SCIx_RXI_IRQ]) ||    \
+       ((port)->cfg->irqs[SCIx_ERI_IRQ] &&     \
+        !(port)->cfg->irqs[SCIx_RXI_IRQ])
+/*
+ * SCI register subset common for all port types.
+ * Not all registers will exist on all parts.
+ */
+enum {
+       SCSMR, SCBRR, SCSCR, SCxSR,
+       SCFCR, SCFDR, SCxTDR, SCxRDR,
+       SCLSR, SCTFDR, SCRFDR, SCSPTR,
+
+       SCIx_NR_REGS,
+};
+
 struct device;
 
+struct plat_sci_port_ops {
+       void (*init_pins)(struct uart_port *, unsigned int cflag);
+};
+
 /*
  * Platform device specific platform_data struct
  */
@@ -56,6 +119,18 @@ struct plat_sci_port {
        unsigned int    scbrr_algo_id;          /* SCBRR calculation algo */
        unsigned int    scscr;                  /* SCSCR initialization */
 
+       /*
+        * Platform overrides if necessary, defaults otherwise.
+        */
+       int             overrun_bit;
+       unsigned int    error_mask;
+
+       int             port_reg;
+       unsigned char   regshift;
+       unsigned char   regtype;
+
+       struct plat_sci_port_ops        *ops;
+
        struct device   *dma_dev;
 
        unsigned int    dma_slave_tx;
index 9a52f72..3ccf186 100644 (file)
@@ -147,4 +147,8 @@ int sh_clk_div4_reparent_register(struct clk *clks, int nr,
 int sh_clk_div6_register(struct clk *clks, int nr);
 int sh_clk_div6_reparent_register(struct clk *clks, int nr);
 
+#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
+#define CLKDEV_DEV_ID(_id, _clk) { .dev_id = _id, .clk = _clk }
+#define CLKDEV_ICK_ID(_cid, _did, _clk) { .con_id = _cid, .dev_id = _did, .clk = _clk }
+
 #endif /* __SH_CLOCK_H */
index b08cd4e..cb2dd11 100644 (file)
@@ -62,6 +62,12 @@ struct sh_dmae_pdata {
        const unsigned int *ts_shift;
        int ts_shift_num;
        u16 dmaor_init;
+       unsigned int chcr_offset;
+       u32 chcr_ie_bit;
+
+       unsigned int dmaor_is_32bit:1;
+       unsigned int needs_tend_set:1;
+       unsigned int no_dmars:1;
 };
 
 /* DMA register */
@@ -71,6 +77,8 @@ struct sh_dmae_pdata {
 #define CHCR   0x0C
 #define DMAOR  0x40
 
+#define TEND   0x18 /* USB-DMAC */
+
 /* DMAOR definitions */
 #define DMAOR_AE       0x00000004
 #define DMAOR_NMIF     0x00000002
index 7d27ffd..92808b8 100644 (file)
@@ -95,6 +95,9 @@ struct shmid_kernel /* private to the kernel */
        pid_t                   shm_cprid;
        pid_t                   shm_lprid;
        struct user_struct      *mlock_user;
+
+       /* The task created the shm object.  NULL if the task is dead. */
+       struct task_struct      *shm_creator;
 };
 
 /* shm_mode upper byte flags */
index aa08fa8..9291ac3 100644 (file)
@@ -8,22 +8,15 @@
 
 /* inode in-kernel data */
 
-#define SHMEM_NR_DIRECT 16
-
-#define SHMEM_SYMLINK_INLINE_LEN (SHMEM_NR_DIRECT * sizeof(swp_entry_t))
-
 struct shmem_inode_info {
        spinlock_t              lock;
        unsigned long           flags;
        unsigned long           alloced;        /* data pages alloced to file */
-       unsigned long           swapped;        /* subtotal assigned to swap */
-       unsigned long           next_index;     /* highest alloced index + 1 */
-       struct shared_policy    policy;         /* NUMA memory alloc policy */
-       struct page             *i_indirect;    /* top indirect blocks page */
        union {
-               swp_entry_t     i_direct[SHMEM_NR_DIRECT]; /* first blocks */
-               char            inline_symlink[SHMEM_SYMLINK_INLINE_LEN];
+               unsigned long   swapped;        /* subtotal assigned to swap */
+               char            *symlink;       /* unswappable short symlink */
        };
+       struct shared_policy    policy;         /* NUMA memory alloc policy */
        struct list_head        swaplist;       /* chain of maybes on swap */
        struct list_head        xattr_list;     /* list of shmem_xattr */
        struct inode            vfs_inode;
@@ -49,7 +42,7 @@ static inline struct shmem_inode_info *SHMEM_I(struct inode *inode)
 /*
  * Functions in mm/shmem.c called directly from elsewhere:
  */
-extern int init_tmpfs(void);
+extern int shmem_init(void);
 extern int shmem_fill_super(struct super_block *sb, void *data, int silent);
 extern struct file *shmem_file_setup(const char *name,
                                        loff_t size, unsigned long flags);
@@ -59,8 +52,6 @@ extern struct page *shmem_read_mapping_page_gfp(struct address_space *mapping,
                                        pgoff_t index, gfp_t gfp_mask);
 extern void shmem_truncate_range(struct inode *inode, loff_t start, loff_t end);
 extern int shmem_unuse(swp_entry_t entry, struct page *page);
-extern void mem_cgroup_get_shmem_target(struct inode *inode, pgoff_t pgoff,
-                                       struct page **pagep, swp_entry_t *ent);
 
 static inline struct page *shmem_read_mapping_page(
                                struct address_space *mapping, pgoff_t index)
index 7b996ed..8bd383c 100644 (file)
@@ -524,6 +524,7 @@ static inline struct sk_buff *alloc_skb_fclone(unsigned int size,
 extern bool skb_recycle_check(struct sk_buff *skb, int skb_size);
 
 extern struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src);
+extern int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask);
 extern struct sk_buff *skb_clone(struct sk_buff *skb,
                                 gfp_t priority);
 extern struct sk_buff *skb_copy(const struct sk_buff *skb,
index 4b35c06..f58d641 100644 (file)
@@ -24,6 +24,7 @@ enum stat_item {
        ALLOC_FROM_PARTIAL,     /* Cpu slab acquired from partial list */
        ALLOC_SLAB,             /* Cpu slab acquired from page allocator */
        ALLOC_REFILL,           /* Refill cpu slab from slab freelist */
+       ALLOC_NODE_MISMATCH,    /* Switching cpu slab */
        FREE_SLAB,              /* Slab freed to the page allocator */
        CPUSLAB_FLUSH,          /* Abandoning of the cpu slab */
        DEACTIVATE_FULL,        /* Cpu slab was full when deactivated */
@@ -31,8 +32,10 @@ enum stat_item {
        DEACTIVATE_TO_HEAD,     /* Cpu slab was moved to the head of partials */
        DEACTIVATE_TO_TAIL,     /* Cpu slab was moved to the tail of partials */
        DEACTIVATE_REMOTE_FREES,/* Slab contained remotely freed objects */
+       DEACTIVATE_BYPASS,      /* Implicit deactivation */
        ORDER_FALLBACK,         /* Number of times fallback was necessary */
        CMPXCHG_DOUBLE_CPU_FAIL,/* Failure of this_cpu_cmpxchg_double */
+       CMPXCHG_DOUBLE_FAIL,    /* Number of times that cmpxchg double did not match */
        NR_SLUB_STAT_ITEMS };
 
 struct kmem_cache_cpu {
index 12b2b18..e16557a 100644 (file)
@@ -231,6 +231,8 @@ enum
        LINUX_MIB_TCPDEFERACCEPTDROP,
        LINUX_MIB_IPRPFILTER, /* IP Reverse Path Filter (rp_filter) */
        LINUX_MIB_TCPTIMEWAITOVERFLOW,          /* TCPTimeWaitOverflow */
+       LINUX_MIB_TCPREQQFULLDOCOOKIES,         /* TCPReqQFullDoCookies */
+       LINUX_MIB_TCPREQQFULLDROP,              /* TCPReqQFullDrop */
        __LINUX_MIB_MAX
 };
 
index e17f822..d0e77f6 100644 (file)
@@ -8,8 +8,10 @@
 #define _K_SS_ALIGNSIZE        (__alignof__ (struct sockaddr *))
                                /* Implementation specific desired alignment */
 
+typedef unsigned short __kernel_sa_family_t;
+
 struct __kernel_sockaddr_storage {
-       unsigned short  ss_family;              /* address family */
+       __kernel_sa_family_t    ss_family;              /* address family */
        /* Following field(s) are implementation specific */
        char            __data[_K_SS_MAXSIZE - sizeof(unsigned short)];
                                /* space to achieve desired size, */
@@ -35,7 +37,7 @@ struct seq_file;
 extern void socket_seq_show(struct seq_file *seq);
 #endif
 
-typedef unsigned short sa_family_t;
+typedef __kernel_sa_family_t   sa_family_t;
 
 /*
  *     1003.1g requires sa_family_t and that sa_data is char.
index cd42e30..2189d3f 100644 (file)
@@ -1,3 +1,8 @@
+#ifndef _LINUX_SWAPOPS_H
+#define _LINUX_SWAPOPS_H
+
+#include <linux/radix-tree.h>
+
 /*
  * swapcache pages are stored in the swapper_space radix tree.  We want to
  * get good packing density in that tree, so the index should be dense in
@@ -76,6 +81,22 @@ static inline pte_t swp_entry_to_pte(swp_entry_t entry)
        return __swp_entry_to_pte(arch_entry);
 }
 
+static inline swp_entry_t radix_to_swp_entry(void *arg)
+{
+       swp_entry_t entry;
+
+       entry.val = (unsigned long)arg >> RADIX_TREE_EXCEPTIONAL_SHIFT;
+       return entry;
+}
+
+static inline void *swp_to_radix_entry(swp_entry_t entry)
+{
+       unsigned long value;
+
+       value = entry.val << RADIX_TREE_EXCEPTIONAL_SHIFT;
+       return (void *)(value | RADIX_TREE_EXCEPTIONAL_ENTRY);
+}
+
 #ifdef CONFIG_MIGRATION
 static inline swp_entry_t make_migration_entry(struct page *page, int write)
 {
@@ -169,3 +190,5 @@ static inline int non_swap_entry(swp_entry_t entry)
        return 0;
 }
 #endif
+
+#endif /* _LINUX_SWAPOPS_H */
index d3ec89f..47b4a27 100644 (file)
@@ -85,22 +85,6 @@ struct thermal_cooling_device {
                                ((long)t-2732+5)/10 : ((long)t-2732-5)/10)
 #define CELSIUS_TO_KELVIN(t)   ((t)*10+2732)
 
-#if defined(CONFIG_THERMAL_HWMON)
-/* thermal zone devices with the same type share one hwmon device */
-struct thermal_hwmon_device {
-       char type[THERMAL_NAME_LENGTH];
-       struct device *device;
-       int count;
-       struct list_head tz_list;
-       struct list_head node;
-};
-
-struct thermal_hwmon_attr {
-       struct device_attribute attr;
-       char name[16];
-};
-#endif
-
 struct thermal_zone_device {
        int id;
        char type[THERMAL_NAME_LENGTH];
@@ -120,12 +104,6 @@ struct thermal_zone_device {
        struct mutex lock;      /* protect cooling devices list */
        struct list_head node;
        struct delayed_work poll_queue;
-#if defined(CONFIG_THERMAL_HWMON)
-       struct list_head hwmon_node;
-       struct thermal_hwmon_device *hwmon;
-       struct thermal_hwmon_attr temp_input;   /* hwmon sys attr */
-       struct thermal_hwmon_attr temp_crit;    /* hwmon sys attr */
-#endif
 };
 /* Adding event notification support elements */
 #define THERMAL_GENL_FAMILY_NAME                "thermal_event"
index 8a4c309..fca24cc 100644 (file)
@@ -376,7 +376,16 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_MJPEG    v4l2_fourcc('M', 'J', 'P', 'G') /* Motion-JPEG   */
 #define V4L2_PIX_FMT_JPEG     v4l2_fourcc('J', 'P', 'E', 'G') /* JFIF JPEG     */
 #define V4L2_PIX_FMT_DV       v4l2_fourcc('d', 'v', 's', 'd') /* 1394          */
-#define V4L2_PIX_FMT_MPEG     v4l2_fourcc('M', 'P', 'E', 'G') /* MPEG-1/2/4    */
+#define V4L2_PIX_FMT_MPEG     v4l2_fourcc('M', 'P', 'E', 'G') /* MPEG-1/2/4 Multiplexed */
+#define V4L2_PIX_FMT_H264     v4l2_fourcc('H', '2', '6', '4') /* H264 with start codes */
+#define V4L2_PIX_FMT_H264_NO_SC v4l2_fourcc('A', 'V', 'C', '1') /* H264 without start codes */
+#define V4L2_PIX_FMT_H263     v4l2_fourcc('H', '2', '6', '3') /* H263          */
+#define V4L2_PIX_FMT_MPEG1    v4l2_fourcc('M', 'P', 'G', '1') /* MPEG-1 ES     */
+#define V4L2_PIX_FMT_MPEG2    v4l2_fourcc('M', 'P', 'G', '2') /* MPEG-2 ES     */
+#define V4L2_PIX_FMT_MPEG4    v4l2_fourcc('M', 'P', 'G', '4') /* MPEG-4 ES     */
+#define V4L2_PIX_FMT_XVID     v4l2_fourcc('X', 'V', 'I', 'D') /* Xvid           */
+#define V4L2_PIX_FMT_VC1_ANNEX_G v4l2_fourcc('V', 'C', '1', 'G') /* SMPTE 421M Annex G compliant stream */
+#define V4L2_PIX_FMT_VC1_ANNEX_L v4l2_fourcc('V', 'C', '1', 'L') /* SMPTE 421M Annex L compliant stream */
 
 /*  Vendor-specific formats   */
 #define V4L2_PIX_FMT_CPIA1    v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */
@@ -402,6 +411,7 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_CIT_YYVYUY v4l2_fourcc('C', 'I', 'T', 'V') /* one line of Y then 1 line of VYUY */
 #define V4L2_PIX_FMT_KONICA420  v4l2_fourcc('K', 'O', 'N', 'I') /* YUV420 planar in blocks of 256 pixels */
 #define V4L2_PIX_FMT_JPGL      v4l2_fourcc('J', 'P', 'G', 'L') /* JPEG-Lite */
+#define V4L2_PIX_FMT_SE401      v4l2_fourcc('S', '4', '0', '1') /* se401 janggu compressed rgb */
 
 /*
  *     F O R M A T   E N U M E R A T I O N
@@ -1026,6 +1036,7 @@ struct v4l2_ext_controls {
 #define V4L2_CTRL_CLASS_MPEG 0x00990000        /* MPEG-compression controls */
 #define V4L2_CTRL_CLASS_CAMERA 0x009a0000      /* Camera class controls */
 #define V4L2_CTRL_CLASS_FM_TX 0x009b0000       /* FM Modulator control class */
+#define V4L2_CTRL_CLASS_FLASH 0x009c0000       /* Camera flash controls */
 
 #define V4L2_CTRL_ID_MASK                (0x0fffffff)
 #define V4L2_CTRL_ID2CLASS(id)    ((id) & 0x0fff0000UL)
@@ -1039,6 +1050,7 @@ enum v4l2_ctrl_type {
        V4L2_CTRL_TYPE_INTEGER64     = 5,
        V4L2_CTRL_TYPE_CTRL_CLASS    = 6,
        V4L2_CTRL_TYPE_STRING        = 7,
+       V4L2_CTRL_TYPE_BITMASK       = 8,
 };
 
 /*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
@@ -1144,14 +1156,19 @@ enum v4l2_colorfx {
 #define V4L2_CID_ILLUMINATORS_1                        (V4L2_CID_BASE+37)
 #define V4L2_CID_ILLUMINATORS_2                        (V4L2_CID_BASE+38)
 
+#define V4L2_CID_MIN_BUFFERS_FOR_CAPTURE       (V4L2_CID_BASE+39)
+#define V4L2_CID_MIN_BUFFERS_FOR_OUTPUT                (V4L2_CID_BASE+40)
+
 /* last CID + 1 */
-#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+39)
+#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+41)
+
+/* Minimum number of buffer neede by the device */
 
 /*  MPEG-class control IDs defined by V4L2 */
 #define V4L2_CID_MPEG_BASE                     (V4L2_CTRL_CLASS_MPEG | 0x900)
 #define V4L2_CID_MPEG_CLASS                    (V4L2_CTRL_CLASS_MPEG | 1)
 
-/*  MPEG streams */
+/*  MPEG streams, specific to multiplexed streams */
 #define V4L2_CID_MPEG_STREAM_TYPE              (V4L2_CID_MPEG_BASE+0)
 enum v4l2_mpeg_stream_type {
        V4L2_MPEG_STREAM_TYPE_MPEG2_PS   = 0, /* MPEG-2 program stream */
@@ -1173,7 +1190,7 @@ enum v4l2_mpeg_stream_vbi_fmt {
        V4L2_MPEG_STREAM_VBI_FMT_IVTV = 1,  /* VBI in private packets, IVTV format */
 };
 
-/*  MPEG audio */
+/*  MPEG audio controls specific to multiplexed streams  */
 #define V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ      (V4L2_CID_MPEG_BASE+100)
 enum v4l2_mpeg_audio_sampling_freq {
        V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100 = 0,
@@ -1289,7 +1306,7 @@ enum v4l2_mpeg_audio_ac3_bitrate {
        V4L2_MPEG_AUDIO_AC3_BITRATE_640K = 18,
 };
 
-/*  MPEG video */
+/*  MPEG video controls specific to multiplexed streams */
 #define V4L2_CID_MPEG_VIDEO_ENCODING           (V4L2_CID_MPEG_BASE+200)
 enum v4l2_mpeg_video_encoding {
        V4L2_MPEG_VIDEO_ENCODING_MPEG_1     = 0,
@@ -1317,6 +1334,141 @@ enum v4l2_mpeg_video_bitrate_mode {
 #define V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION (V4L2_CID_MPEG_BASE+209)
 #define V4L2_CID_MPEG_VIDEO_MUTE               (V4L2_CID_MPEG_BASE+210)
 #define V4L2_CID_MPEG_VIDEO_MUTE_YUV           (V4L2_CID_MPEG_BASE+211)
+#define V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE            (V4L2_CID_MPEG_BASE+212)
+#define V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER       (V4L2_CID_MPEG_BASE+213)
+#define V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB            (V4L2_CID_MPEG_BASE+214)
+#define V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE                    (V4L2_CID_MPEG_BASE+215)
+#define V4L2_CID_MPEG_VIDEO_HEADER_MODE                                (V4L2_CID_MPEG_BASE+216)
+enum v4l2_mpeg_video_header_mode {
+       V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE                    = 0,
+       V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME       = 1,
+
+};
+#define V4L2_CID_MPEG_VIDEO_MAX_REF_PIC                        (V4L2_CID_MPEG_BASE+217)
+#define V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE               (V4L2_CID_MPEG_BASE+218)
+#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES      (V4L2_CID_MPEG_BASE+219)
+#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB         (V4L2_CID_MPEG_BASE+220)
+#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE           (V4L2_CID_MPEG_BASE+221)
+enum v4l2_mpeg_video_multi_slice_mode {
+       V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE         = 0,
+       V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB          = 1,
+       V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES       = 2,
+};
+#define V4L2_CID_MPEG_VIDEO_VBV_SIZE                   (V4L2_CID_MPEG_BASE+222)
+#define V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP            (V4L2_CID_MPEG_BASE+300)
+#define V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP            (V4L2_CID_MPEG_BASE+301)
+#define V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP            (V4L2_CID_MPEG_BASE+302)
+#define V4L2_CID_MPEG_VIDEO_H263_MIN_QP                        (V4L2_CID_MPEG_BASE+303)
+#define V4L2_CID_MPEG_VIDEO_H263_MAX_QP                        (V4L2_CID_MPEG_BASE+304)
+#define V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP            (V4L2_CID_MPEG_BASE+350)
+#define V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP            (V4L2_CID_MPEG_BASE+351)
+#define V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP            (V4L2_CID_MPEG_BASE+352)
+#define V4L2_CID_MPEG_VIDEO_H264_MIN_QP                        (V4L2_CID_MPEG_BASE+353)
+#define V4L2_CID_MPEG_VIDEO_H264_MAX_QP                        (V4L2_CID_MPEG_BASE+354)
+#define V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM         (V4L2_CID_MPEG_BASE+355)
+#define V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE              (V4L2_CID_MPEG_BASE+356)
+#define V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE          (V4L2_CID_MPEG_BASE+357)
+enum v4l2_mpeg_video_h264_entropy_mode {
+       V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC = 0,
+       V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC = 1,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_I_PERIOD              (V4L2_CID_MPEG_BASE+358)
+#define V4L2_CID_MPEG_VIDEO_H264_LEVEL                 (V4L2_CID_MPEG_BASE+359)
+enum v4l2_mpeg_video_h264_level {
+       V4L2_MPEG_VIDEO_H264_LEVEL_1_0  = 0,
+       V4L2_MPEG_VIDEO_H264_LEVEL_1B   = 1,
+       V4L2_MPEG_VIDEO_H264_LEVEL_1_1  = 2,
+       V4L2_MPEG_VIDEO_H264_LEVEL_1_2  = 3,
+       V4L2_MPEG_VIDEO_H264_LEVEL_1_3  = 4,
+       V4L2_MPEG_VIDEO_H264_LEVEL_2_0  = 5,
+       V4L2_MPEG_VIDEO_H264_LEVEL_2_1  = 6,
+       V4L2_MPEG_VIDEO_H264_LEVEL_2_2  = 7,
+       V4L2_MPEG_VIDEO_H264_LEVEL_3_0  = 8,
+       V4L2_MPEG_VIDEO_H264_LEVEL_3_1  = 9,
+       V4L2_MPEG_VIDEO_H264_LEVEL_3_2  = 10,
+       V4L2_MPEG_VIDEO_H264_LEVEL_4_0  = 11,
+       V4L2_MPEG_VIDEO_H264_LEVEL_4_1  = 12,
+       V4L2_MPEG_VIDEO_H264_LEVEL_4_2  = 13,
+       V4L2_MPEG_VIDEO_H264_LEVEL_5_0  = 14,
+       V4L2_MPEG_VIDEO_H264_LEVEL_5_1  = 15,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA     (V4L2_CID_MPEG_BASE+360)
+#define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA      (V4L2_CID_MPEG_BASE+361)
+#define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE      (V4L2_CID_MPEG_BASE+362)
+enum v4l2_mpeg_video_h264_loop_filter_mode {
+       V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED                           = 0,
+       V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED                          = 1,
+       V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY        = 2,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_PROFILE               (V4L2_CID_MPEG_BASE+363)
+enum v4l2_mpeg_video_h264_profile {
+       V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE                   = 0,
+       V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE       = 1,
+       V4L2_MPEG_VIDEO_H264_PROFILE_MAIN                       = 2,
+       V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED                   = 3,
+       V4L2_MPEG_VIDEO_H264_PROFILE_HIGH                       = 4,
+       V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10                    = 5,
+       V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422                   = 6,
+       V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE        = 7,
+       V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10_INTRA              = 8,
+       V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA             = 9,
+       V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_INTRA             = 10,
+       V4L2_MPEG_VIDEO_H264_PROFILE_CAVLC_444_INTRA            = 11,
+       V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE          = 12,
+       V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH              = 13,
+       V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA        = 14,
+       V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH                = 15,
+       V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH             = 16,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT    (V4L2_CID_MPEG_BASE+364)
+#define V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH     (V4L2_CID_MPEG_BASE+365)
+#define V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE                (V4L2_CID_MPEG_BASE+366)
+#define V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC           (V4L2_CID_MPEG_BASE+367)
+enum v4l2_mpeg_video_h264_vui_sar_idc {
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED    = 0,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1            = 1,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_12x11          = 2,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_10x11          = 3,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_16x11          = 4,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_40x33          = 5,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_24x11          = 6,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_20x11          = 7,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_32x11          = 8,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_80x33          = 9,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_18x11          = 10,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_15x11          = 11,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_64x33          = 12,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_160x99         = 13,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_4x3            = 14,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_3x2            = 15,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1            = 16,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED       = 17,
+};
+#define V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP   (V4L2_CID_MPEG_BASE+400)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP   (V4L2_CID_MPEG_BASE+401)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP   (V4L2_CID_MPEG_BASE+402)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP       (V4L2_CID_MPEG_BASE+403)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP       (V4L2_CID_MPEG_BASE+404)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL                (V4L2_CID_MPEG_BASE+405)
+enum v4l2_mpeg_video_mpeg4_level {
+       V4L2_MPEG_VIDEO_MPEG4_LEVEL_0   = 0,
+       V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B  = 1,
+       V4L2_MPEG_VIDEO_MPEG4_LEVEL_1   = 2,
+       V4L2_MPEG_VIDEO_MPEG4_LEVEL_2   = 3,
+       V4L2_MPEG_VIDEO_MPEG4_LEVEL_3   = 4,
+       V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B  = 5,
+       V4L2_MPEG_VIDEO_MPEG4_LEVEL_4   = 6,
+       V4L2_MPEG_VIDEO_MPEG4_LEVEL_5   = 7,
+};
+#define V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE      (V4L2_CID_MPEG_BASE+406)
+enum v4l2_mpeg_video_mpeg4_profile {
+       V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE                            = 0,
+       V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE                   = 1,
+       V4L2_MPEG_VIDEO_MPEG4_PROFILE_CORE                              = 2,
+       V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE_SCALABLE                   = 3,
+       V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY        = 4,
+};
+#define V4L2_CID_MPEG_VIDEO_MPEG4_QPEL         (V4L2_CID_MPEG_BASE+407)
 
 /*  MPEG-class control IDs specific to the CX2341x driver as defined by V4L2 */
 #define V4L2_CID_MPEG_CX2341X_BASE                             (V4L2_CTRL_CLASS_MPEG | 0x1000)
@@ -1359,6 +1511,33 @@ enum v4l2_mpeg_cx2341x_video_median_filter_type {
 #define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP   (V4L2_CID_MPEG_CX2341X_BASE+10)
 #define V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS        (V4L2_CID_MPEG_CX2341X_BASE+11)
 
+/*  MPEG-class control IDs specific to the Samsung MFC 5.1 driver as defined by V4L2 */
+#define V4L2_CID_MPEG_MFC51_BASE                               (V4L2_CTRL_CLASS_MPEG | 0x1100)
+
+#define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY           (V4L2_CID_MPEG_MFC51_BASE+0)
+#define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE    (V4L2_CID_MPEG_MFC51_BASE+1)
+#define V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE                      (V4L2_CID_MPEG_MFC51_BASE+2)
+enum v4l2_mpeg_mfc51_video_frame_skip_mode {
+       V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED          = 0,
+       V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT       = 1,
+       V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT         = 2,
+};
+#define V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE                     (V4L2_CID_MPEG_MFC51_BASE+3)
+enum v4l2_mpeg_mfc51_video_force_frame_type {
+       V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED         = 0,
+       V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME          = 1,
+       V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_NOT_CODED        = 2,
+};
+#define V4L2_CID_MPEG_MFC51_VIDEO_PADDING                              (V4L2_CID_MPEG_MFC51_BASE+4)
+#define V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV                          (V4L2_CID_MPEG_MFC51_BASE+5)
+#define V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT                  (V4L2_CID_MPEG_MFC51_BASE+6)
+#define V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF                    (V4L2_CID_MPEG_MFC51_BASE+7)
+#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY            (V4L2_CID_MPEG_MFC51_BASE+50)
+#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK                        (V4L2_CID_MPEG_MFC51_BASE+51)
+#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH              (V4L2_CID_MPEG_MFC51_BASE+52)
+#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC              (V4L2_CID_MPEG_MFC51_BASE+53)
+#define V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P               (V4L2_CID_MPEG_MFC51_BASE+54)
+
 /*  Camera class control IDs */
 #define V4L2_CID_CAMERA_CLASS_BASE     (V4L2_CTRL_CLASS_CAMERA | 0x900)
 #define V4L2_CID_CAMERA_CLASS          (V4L2_CTRL_CLASS_CAMERA | 1)
@@ -1427,6 +1606,41 @@ enum v4l2_preemphasis {
 #define V4L2_CID_TUNE_POWER_LEVEL              (V4L2_CID_FM_TX_CLASS_BASE + 113)
 #define V4L2_CID_TUNE_ANTENNA_CAPACITOR                (V4L2_CID_FM_TX_CLASS_BASE + 114)
 
+/* Flash and privacy (indicator) light controls */
+#define V4L2_CID_FLASH_CLASS_BASE              (V4L2_CTRL_CLASS_FLASH | 0x900)
+#define V4L2_CID_FLASH_CLASS                   (V4L2_CTRL_CLASS_FLASH | 1)
+
+#define V4L2_CID_FLASH_LED_MODE                        (V4L2_CID_FLASH_CLASS_BASE + 1)
+enum v4l2_flash_led_mode {
+       V4L2_FLASH_LED_MODE_NONE,
+       V4L2_FLASH_LED_MODE_FLASH,
+       V4L2_FLASH_LED_MODE_TORCH,
+};
+
+#define V4L2_CID_FLASH_STROBE_SOURCE           (V4L2_CID_FLASH_CLASS_BASE + 2)
+enum v4l2_flash_strobe_source {
+       V4L2_FLASH_STROBE_SOURCE_SOFTWARE,
+       V4L2_FLASH_STROBE_SOURCE_EXTERNAL,
+};
+
+#define V4L2_CID_FLASH_STROBE                  (V4L2_CID_FLASH_CLASS_BASE + 3)
+#define V4L2_CID_FLASH_STROBE_STOP             (V4L2_CID_FLASH_CLASS_BASE + 4)
+#define V4L2_CID_FLASH_STROBE_STATUS           (V4L2_CID_FLASH_CLASS_BASE + 5)
+
+#define V4L2_CID_FLASH_TIMEOUT                 (V4L2_CID_FLASH_CLASS_BASE + 6)
+#define V4L2_CID_FLASH_INTENSITY               (V4L2_CID_FLASH_CLASS_BASE + 7)
+#define V4L2_CID_FLASH_TORCH_INTENSITY         (V4L2_CID_FLASH_CLASS_BASE + 8)
+#define V4L2_CID_FLASH_INDICATOR_INTENSITY     (V4L2_CID_FLASH_CLASS_BASE + 9)
+
+#define V4L2_CID_FLASH_FAULT                   (V4L2_CID_FLASH_CLASS_BASE + 10)
+#define V4L2_FLASH_FAULT_OVER_VOLTAGE          (1 << 0)
+#define V4L2_FLASH_FAULT_TIMEOUT               (1 << 1)
+#define V4L2_FLASH_FAULT_OVER_TEMPERATURE      (1 << 2)
+#define V4L2_FLASH_FAULT_SHORT_CIRCUIT         (1 << 3)
+
+#define V4L2_CID_FLASH_CHARGE                  (V4L2_CID_FLASH_CLASS_BASE + 11)
+#define V4L2_CID_FLASH_READY                   (V4L2_CID_FLASH_CLASS_BASE + 12)
+
 /*
  *     T U N I N G
  */
@@ -1791,6 +2005,7 @@ struct v4l2_streamparm {
 #define V4L2_EVENT_ALL                         0
 #define V4L2_EVENT_VSYNC                       1
 #define V4L2_EVENT_EOS                         2
+#define V4L2_EVENT_CTRL                                3
 #define V4L2_EVENT_PRIVATE_START               0x08000000
 
 /* Payload for V4L2_EVENT_VSYNC */
@@ -1799,21 +2014,46 @@ struct v4l2_event_vsync {
        __u8 field;
 } __attribute__ ((packed));
 
+/* Payload for V4L2_EVENT_CTRL */
+#define V4L2_EVENT_CTRL_CH_VALUE               (1 << 0)
+#define V4L2_EVENT_CTRL_CH_FLAGS               (1 << 1)
+
+struct v4l2_event_ctrl {
+       __u32 changes;
+       __u32 type;
+       union {
+               __s32 value;
+               __s64 value64;
+       };
+       __u32 flags;
+       __s32 minimum;
+       __s32 maximum;
+       __s32 step;
+       __s32 default_value;
+};
+
 struct v4l2_event {
        __u32                           type;
        union {
                struct v4l2_event_vsync vsync;
+               struct v4l2_event_ctrl  ctrl;
                __u8                    data[64];
        } u;
        __u32                           pending;
        __u32                           sequence;
        struct timespec                 timestamp;
-       __u32                           reserved[9];
+       __u32                           id;
+       __u32                           reserved[8];
 };
 
+#define V4L2_EVENT_SUB_FL_SEND_INITIAL         (1 << 0)
+#define V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK       (1 << 1)
+
 struct v4l2_event_subscription {
        __u32                           type;
-       __u32                           reserved[7];
+       __u32                           id;
+       __u32                           flags;
+       __u32                           reserved[5];
 };
 
 /*
index 011bcfe..111843f 100644 (file)
@@ -59,6 +59,84 @@ struct watchdog_info {
 #define WATCHDOG_NOWAYOUT      0
 #endif
 
+struct watchdog_ops;
+struct watchdog_device;
+
+/** struct watchdog_ops - The watchdog-devices operations
+ *
+ * @owner:     The module owner.
+ * @start:     The routine for starting the watchdog device.
+ * @stop:      The routine for stopping the watchdog device.
+ * @ping:      The routine that sends a keepalive ping to the watchdog device.
+ * @status:    The routine that shows the status of the watchdog device.
+ * @set_timeout:The routine for setting the watchdog devices timeout value.
+ * @ioctl:     The routines that handles extra ioctl calls.
+ *
+ * The watchdog_ops structure contains a list of low-level operations
+ * that control a watchdog device. It also contains the module that owns
+ * these operations. The start and stop function are mandatory, all other
+ * functions are optonal.
+ */
+struct watchdog_ops {
+       struct module *owner;
+       /* mandatory operations */
+       int (*start)(struct watchdog_device *);
+       int (*stop)(struct watchdog_device *);
+       /* optional operations */
+       int (*ping)(struct watchdog_device *);
+       unsigned int (*status)(struct watchdog_device *);
+       int (*set_timeout)(struct watchdog_device *, unsigned int);
+       long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
+};
+
+/** struct watchdog_device - The structure that defines a watchdog device
+ *
+ * @info:      Pointer to a watchdog_info structure.
+ * @ops:       Pointer to the list of watchdog operations.
+ * @bootstatus:        Status of the watchdog device at boot.
+ * @timeout:   The watchdog devices timeout value.
+ * @min_timeout:The watchdog devices minimum timeout value.
+ * @max_timeout:The watchdog devices maximum timeout value.
+ * @driver-data:Pointer to the drivers private data.
+ * @status:    Field that contains the devices internal status bits.
+ *
+ * The watchdog_device structure contains all information about a
+ * watchdog timer device.
+ *
+ * The driver-data field may not be accessed directly. It must be accessed
+ * via the watchdog_set_drvdata and watchdog_get_drvdata helpers.
+ */
+struct watchdog_device {
+       const struct watchdog_info *info;
+       const struct watchdog_ops *ops;
+       unsigned int bootstatus;
+       unsigned int timeout;
+       unsigned int min_timeout;
+       unsigned int max_timeout;
+       void *driver_data;
+       unsigned long status;
+/* Bit numbers for status flags */
+#define WDOG_ACTIVE            0       /* Is the watchdog running/active */
+#define WDOG_DEV_OPEN          1       /* Opened via /dev/watchdog ? */
+#define WDOG_ALLOW_RELEASE     2       /* Did we receive the magic char ? */
+#define WDOG_NO_WAY_OUT                3       /* Is 'nowayout' feature set ? */
+};
+
+/* Use the following functions to manipulate watchdog driver specific data */
+static inline void watchdog_set_drvdata(struct watchdog_device *wdd, void *data)
+{
+       wdd->driver_data = data;
+}
+
+static inline void *watchdog_get_drvdata(struct watchdog_device *wdd)
+{
+       return wdd->driver_data;
+}
+
+/* drivers/watchdog/core/watchdog_core.c */
+extern int watchdog_register_device(struct watchdog_device *);
+extern void watchdog_unregister_device(struct watchdog_device *);
+
 #endif /* __KERNEL__ */
 
 #endif  /* ifndef _LINUX_WATCHDOG_H */
diff --git a/include/media/adp1653.h b/include/media/adp1653.h
new file mode 100644 (file)
index 0000000..50a1af8
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * include/media/adp1653.h
+ *
+ * Copyright (C) 2008--2011 Nokia Corporation
+ *
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * Contributors:
+ *     Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *     Tuukka Toivonen <tuukkat76@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
+ *
+ */
+
+#ifndef ADP1653_H
+#define ADP1653_H
+
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+
+#define ADP1653_NAME                           "adp1653"
+#define ADP1653_I2C_ADDR                       (0x60 >> 1)
+
+/* Register definitions */
+#define ADP1653_REG_OUT_SEL                    0x00
+#define ADP1653_REG_OUT_SEL_HPLED_TORCH_MIN    0x01
+#define ADP1653_REG_OUT_SEL_HPLED_TORCH_MAX    0x0b
+#define ADP1653_REG_OUT_SEL_HPLED_FLASH_MIN    0x0c
+#define ADP1653_REG_OUT_SEL_HPLED_FLASH_MAX    0x1f
+#define ADP1653_REG_OUT_SEL_HPLED_SHIFT                3
+#define ADP1653_REG_OUT_SEL_ILED_MAX           0x07
+#define ADP1653_REG_OUT_SEL_ILED_SHIFT         0
+
+#define ADP1653_REG_CONFIG                     0x01
+#define ADP1653_REG_CONFIG_TMR_CFG             (1 << 4)
+#define ADP1653_REG_CONFIG_TMR_SET_MAX         0x0f
+#define ADP1653_REG_CONFIG_TMR_SET_SHIFT       0
+
+#define ADP1653_REG_SW_STROBE                  0x02
+#define ADP1653_REG_SW_STROBE_SW_STROBE                (1 << 0)
+
+#define ADP1653_REG_FAULT                      0x03
+#define ADP1653_REG_FAULT_FLT_SCP              (1 << 3)
+#define ADP1653_REG_FAULT_FLT_OT               (1 << 2)
+#define ADP1653_REG_FAULT_FLT_TMR              (1 << 1)
+#define ADP1653_REG_FAULT_FLT_OV               (1 << 0)
+
+#define ADP1653_INDICATOR_INTENSITY_MIN                0
+#define ADP1653_INDICATOR_INTENSITY_STEP       2500
+#define ADP1653_INDICATOR_INTENSITY_MAX                \
+       (ADP1653_REG_OUT_SEL_ILED_MAX * ADP1653_INDICATOR_INTENSITY_STEP)
+#define ADP1653_INDICATOR_INTENSITY_uA_TO_REG(a) \
+       ((a) / ADP1653_INDICATOR_INTENSITY_STEP)
+#define ADP1653_INDICATOR_INTENSITY_REG_TO_uA(a) \
+       ((a) * ADP1653_INDICATOR_INTENSITY_STEP)
+
+#define ADP1653_FLASH_INTENSITY_BASE           35
+#define ADP1653_FLASH_INTENSITY_STEP           15
+#define ADP1653_FLASH_INTENSITY_MIN                                    \
+       (ADP1653_FLASH_INTENSITY_BASE                                   \
+        + ADP1653_REG_OUT_SEL_HPLED_FLASH_MIN * ADP1653_FLASH_INTENSITY_STEP)
+#define ADP1653_FLASH_INTENSITY_MAX                    \
+       (ADP1653_FLASH_INTENSITY_MIN +                  \
+        (ADP1653_REG_OUT_SEL_HPLED_FLASH_MAX -         \
+         ADP1653_REG_OUT_SEL_HPLED_FLASH_MIN + 1) *    \
+        ADP1653_FLASH_INTENSITY_STEP)
+
+#define ADP1653_FLASH_INTENSITY_mA_TO_REG(a)                           \
+       ((a) < ADP1653_FLASH_INTENSITY_BASE ? 0 :                       \
+        (((a) - ADP1653_FLASH_INTENSITY_BASE) / ADP1653_FLASH_INTENSITY_STEP))
+#define ADP1653_FLASH_INTENSITY_REG_TO_mA(a)           \
+       ((a) * ADP1653_FLASH_INTENSITY_STEP + ADP1653_FLASH_INTENSITY_BASE)
+
+#define ADP1653_TORCH_INTENSITY_MIN                                    \
+       (ADP1653_FLASH_INTENSITY_BASE                                   \
+        + ADP1653_REG_OUT_SEL_HPLED_TORCH_MIN * ADP1653_FLASH_INTENSITY_STEP)
+#define ADP1653_TORCH_INTENSITY_MAX                    \
+       (ADP1653_TORCH_INTENSITY_MIN +                  \
+        (ADP1653_REG_OUT_SEL_HPLED_TORCH_MAX -         \
+         ADP1653_REG_OUT_SEL_HPLED_TORCH_MIN + 1) *    \
+        ADP1653_FLASH_INTENSITY_STEP)
+
+struct adp1653_platform_data {
+       int (*power)(struct v4l2_subdev *sd, int on);
+
+       u32 max_flash_timeout;          /* flash light timeout in us */
+       u32 max_flash_intensity;        /* led intensity, flash mode */
+       u32 max_torch_intensity;        /* led intensity, torch mode */
+       u32 max_indicator_intensity;    /* indicator led intensity */
+};
+
+#define to_adp1653_flash(sd)   container_of(sd, struct adp1653_flash, subdev)
+
+struct adp1653_flash {
+       struct v4l2_subdev subdev;
+       struct adp1653_platform_data *platform_data;
+
+       struct v4l2_ctrl_handler ctrls;
+       struct v4l2_ctrl *led_mode;
+       struct v4l2_ctrl *flash_timeout;
+       struct v4l2_ctrl *flash_intensity;
+       struct v4l2_ctrl *torch_intensity;
+       struct v4l2_ctrl *indicator_intensity;
+
+       struct mutex power_lock;
+       int power_count;
+       int fault;
+};
+
+#endif /* ADP1653_H */
diff --git a/include/media/atmel-isi.h b/include/media/atmel-isi.h
new file mode 100644 (file)
index 0000000..26cece5
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Register definitions for the Atmel Image Sensor Interface.
+ *
+ * Copyright (C) 2011 Atmel Corporation
+ * Josh Wu, <josh.wu@atmel.com>
+ *
+ * Based on previous work by Lars Haring, <lars.haring@atmel.com>
+ * and Sedji Gaouaou
+ *
+ * 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 __ATMEL_ISI_H__
+#define __ATMEL_ISI_H__
+
+#include <linux/types.h>
+
+/* ISI_V2 register offsets */
+#define ISI_CFG1                               0x0000
+#define ISI_CFG2                               0x0004
+#define ISI_PSIZE                              0x0008
+#define ISI_PDECF                              0x000c
+#define ISI_Y2R_SET0                           0x0010
+#define ISI_Y2R_SET1                           0x0014
+#define ISI_R2Y_SET0                           0x0018
+#define ISI_R2Y_SET1                           0x001C
+#define ISI_R2Y_SET2                           0x0020
+#define ISI_CTRL                               0x0024
+#define ISI_STATUS                             0x0028
+#define ISI_INTEN                              0x002C
+#define ISI_INTDIS                             0x0030
+#define ISI_INTMASK                            0x0034
+#define ISI_DMA_CHER                           0x0038
+#define ISI_DMA_CHDR                           0x003C
+#define ISI_DMA_CHSR                           0x0040
+#define ISI_DMA_P_ADDR                         0x0044
+#define ISI_DMA_P_CTRL                         0x0048
+#define ISI_DMA_P_DSCR                         0x004C
+#define ISI_DMA_C_ADDR                         0x0050
+#define ISI_DMA_C_CTRL                         0x0054
+#define ISI_DMA_C_DSCR                         0x0058
+
+/* Bitfields in CFG1 */
+#define ISI_CFG1_HSYNC_POL_ACTIVE_LOW          (1 << 2)
+#define ISI_CFG1_VSYNC_POL_ACTIVE_LOW          (1 << 3)
+#define ISI_CFG1_PIXCLK_POL_ACTIVE_FALLING     (1 << 4)
+#define ISI_CFG1_EMB_SYNC                      (1 << 6)
+#define ISI_CFG1_CRC_SYNC                      (1 << 7)
+/* Constants for FRATE(ISI_V2) */
+#define                ISI_CFG1_FRATE_CAPTURE_ALL      (0 << 8)
+#define                ISI_CFG1_FRATE_DIV_2            (1 << 8)
+#define                ISI_CFG1_FRATE_DIV_3            (2 << 8)
+#define                ISI_CFG1_FRATE_DIV_4            (3 << 8)
+#define                ISI_CFG1_FRATE_DIV_5            (4 << 8)
+#define                ISI_CFG1_FRATE_DIV_6            (5 << 8)
+#define                ISI_CFG1_FRATE_DIV_7            (6 << 8)
+#define                ISI_CFG1_FRATE_DIV_8            (7 << 8)
+#define ISI_CFG1_DISCR                         (1 << 11)
+#define ISI_CFG1_FULL_MODE                     (1 << 12)
+
+/* Bitfields in CFG2 */
+#define ISI_CFG2_GRAYSCALE                     (1 << 13)
+/* Constants for YCC_SWAP(ISI_V2) */
+#define                ISI_CFG2_YCC_SWAP_DEFAULT       (0 << 28)
+#define                ISI_CFG2_YCC_SWAP_MODE_1        (1 << 28)
+#define                ISI_CFG2_YCC_SWAP_MODE_2        (2 << 28)
+#define                ISI_CFG2_YCC_SWAP_MODE_3        (3 << 28)
+#define ISI_CFG2_IM_VSIZE_OFFSET               0
+#define ISI_CFG2_IM_HSIZE_OFFSET               16
+#define ISI_CFG2_IM_VSIZE_MASK         (0x7FF << ISI_CFG2_IM_VSIZE_OFFSET)
+#define ISI_CFG2_IM_HSIZE_MASK         (0x7FF << ISI_CFG2_IM_HSIZE_OFFSET)
+
+/* Bitfields in CTRL */
+/* Also using in SR(ISI_V2) */
+#define ISI_CTRL_EN                            (1 << 0)
+#define ISI_CTRL_CDC                           (1 << 8)
+/* Also using in SR/IER/IDR/IMR(ISI_V2) */
+#define ISI_CTRL_DIS                           (1 << 1)
+#define ISI_CTRL_SRST                          (1 << 2)
+
+/* Bitfields in SR */
+#define ISI_SR_SIP                             (1 << 19)
+/* Also using in SR/IER/IDR/IMR */
+#define ISI_SR_VSYNC                           (1 << 10)
+#define ISI_SR_PXFR_DONE                       (1 << 16)
+#define ISI_SR_CXFR_DONE                       (1 << 17)
+#define ISI_SR_P_OVR                           (1 << 24)
+#define ISI_SR_C_OVR                           (1 << 25)
+#define ISI_SR_CRC_ERR                         (1 << 26)
+#define ISI_SR_FR_OVR                          (1 << 27)
+
+/* Bitfields in DMA_C_CTRL & in DMA_P_CTRL */
+#define ISI_DMA_CTRL_FETCH                     (1 << 0)
+#define ISI_DMA_CTRL_WB                                (1 << 1)
+#define ISI_DMA_CTRL_IEN                       (1 << 2)
+#define ISI_DMA_CTRL_DONE                      (1 << 3)
+
+/* Bitfields in DMA_CHSR/CHER/CHDR */
+#define ISI_DMA_CHSR_P_CH                      (1 << 0)
+#define ISI_DMA_CHSR_C_CH                      (1 << 1)
+
+/* Definition for isi_platform_data */
+#define ISI_DATAWIDTH_8                                0x01
+#define ISI_DATAWIDTH_10                       0x02
+
+struct isi_platform_data {
+       u8 has_emb_sync;
+       u8 emb_crc_sync;
+       u8 hsync_act_low;
+       u8 vsync_act_low;
+       u8 pclk_act_falling;
+       u8 isi_full_mode;
+       u32 data_width_flags;
+       /* Using for ISI_CFG1 */
+       u32 frate;
+};
+
+#endif /* __ATMEL_ISI_H__ */
diff --git a/include/media/davinci/vpbe.h b/include/media/davinci/vpbe.h
new file mode 100644 (file)
index 0000000..8b11fb0
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2010 Texas Instruments 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _VPBE_H
+#define _VPBE_H
+
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/davinci/vpbe_osd.h>
+#include <media/davinci/vpbe_venc.h>
+#include <media/davinci/vpbe_types.h>
+
+/* OSD configuration info */
+struct osd_config_info {
+       char module_name[32];
+};
+
+struct vpbe_output {
+       struct v4l2_output output;
+       /*
+        * If output capabilities include dv_preset, list supported presets
+        * below
+        */
+       char *subdev_name;
+       /*
+        * defualt_mode identifies the default timings set at the venc or
+        * external encoder.
+        */
+       char *default_mode;
+       /*
+        * Fields below are used for supporting multiple modes. For example,
+        * LCD panel might support different modes and they are listed here.
+        * Similarly for supporting external encoders, lcd controller port
+        * requires a set of non-standard timing values to be listed here for
+        * each supported mode since venc is used in non-standard timing mode
+        * for interfacing with external encoder similar to configuring lcd
+        * panel timings
+        */
+       unsigned int num_modes;
+       struct vpbe_enc_mode_info *modes;
+       /*
+        * Bus configuration goes here for external encoders. Some encoders
+        * may require multiple interface types for each of the output. For
+        * example, SD modes would use YCC8 where as HD mode would use YCC16.
+        * Not sure if this is needed on a per mode basis instead of per
+        * output basis. If per mode is needed, we may have to move this to
+        * mode_info structure
+        */
+};
+
+/* encoder configuration info */
+struct encoder_config_info {
+       char module_name[32];
+       /* Is this an i2c device ? */
+       unsigned int is_i2c:1;
+       /* i2c subdevice board info */
+       struct i2c_board_info board_info;
+};
+
+/* structure for defining vpbe display subsystem components */
+struct vpbe_config {
+       char module_name[32];
+       /* i2c bus adapter no */
+       int i2c_adapter_id;
+       struct osd_config_info osd;
+       struct encoder_config_info venc;
+       /* external encoder information goes here */
+       int num_ext_encoders;
+       struct encoder_config_info *ext_encoders;
+       int num_outputs;
+       /* Order is venc outputs followed by LCD and then external encoders */
+       struct vpbe_output *outputs;
+};
+
+struct vpbe_device;
+
+struct vpbe_device_ops {
+       /* crop cap for the display */
+       int (*g_cropcap)(struct vpbe_device *vpbe_dev,
+                        struct v4l2_cropcap *cropcap);
+
+       /* Enumerate the outputs */
+       int (*enum_outputs)(struct vpbe_device *vpbe_dev,
+                           struct v4l2_output *output);
+
+       /* Set output to the given index */
+       int (*set_output)(struct vpbe_device *vpbe_dev,
+                        int index);
+
+       /* Get current output */
+       unsigned int (*get_output)(struct vpbe_device *vpbe_dev);
+
+       /* Set DV preset at current output */
+       int (*s_dv_preset)(struct vpbe_device *vpbe_dev,
+                          struct v4l2_dv_preset *dv_preset);
+
+       /* Get DV presets supported at the output */
+       int (*g_dv_preset)(struct vpbe_device *vpbe_dev,
+                          struct v4l2_dv_preset *dv_preset);
+
+       /* Enumerate the DV Presets supported at the output */
+       int (*enum_dv_presets)(struct vpbe_device *vpbe_dev,
+                              struct v4l2_dv_enum_preset *preset_info);
+
+       /* Set std at the output */
+       int (*s_std)(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id);
+
+       /* Get the current std at the output */
+       int (*g_std)(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id);
+
+       /* initialize the device */
+       int (*initialize)(struct device *dev, struct vpbe_device *vpbe_dev);
+
+       /* De-initialize the device */
+       void (*deinitialize)(struct device *dev, struct vpbe_device *vpbe_dev);
+
+       /* Get the current mode info */
+       int (*get_mode_info)(struct vpbe_device *vpbe_dev,
+                            struct vpbe_enc_mode_info*);
+
+       /*
+        * Set the current mode in the encoder. Alternate way of setting
+        * standard or DV preset or custom timings in the encoder
+        */
+       int (*set_mode)(struct vpbe_device *vpbe_dev,
+                       struct vpbe_enc_mode_info*);
+       /* Power management operations */
+       int (*suspend)(struct vpbe_device *vpbe_dev);
+       int (*resume)(struct vpbe_device *vpbe_dev);
+};
+
+/* struct for vpbe device */
+struct vpbe_device {
+       /* V4l2 device */
+       struct v4l2_device v4l2_dev;
+       /* vpbe dispay controller cfg */
+       struct vpbe_config *cfg;
+       /* parent device */
+       struct device *pdev;
+       /* external encoder v4l2 sub devices */
+       struct v4l2_subdev **encoders;
+       /* current encoder index */
+       int current_sd_index;
+       struct mutex lock;
+       /* device initialized */
+       int initialized;
+       /* vpbe dac clock */
+       struct clk *dac_clk;
+       /* osd_device pointer */
+       struct osd_state *osd_device;
+       /*
+        * fields below are accessed by users of vpbe_device. Not the
+        * ones above
+        */
+
+       /* current output */
+       int current_out_index;
+       /* lock used by caller to do atomic operation on vpbe device */
+       /* current timings set in the controller */
+       struct vpbe_enc_mode_info current_timings;
+       /* venc sub device */
+       struct v4l2_subdev *venc;
+       /* device operations below */
+       struct vpbe_device_ops ops;
+};
+
+#endif
diff --git a/include/media/davinci/vpbe_display.h b/include/media/davinci/vpbe_display.h
new file mode 100644 (file)
index 0000000..dbf6b37
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef VPBE_DISPLAY_H
+#define VPBE_DISPLAY_H
+
+/* Header files */
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/videobuf-dma-contig.h>
+#include <media/davinci/vpbe_types.h>
+#include <media/davinci/vpbe_osd.h>
+#include <media/davinci/vpbe.h>
+
+#define VPBE_DISPLAY_MAX_DEVICES 2
+
+enum vpbe_display_device_id {
+       VPBE_DISPLAY_DEVICE_0,
+       VPBE_DISPLAY_DEVICE_1
+};
+
+#define VPBE_DISPLAY_DRV_NAME  "vpbe-display"
+
+#define VPBE_DISPLAY_MAJOR_RELEASE              1
+#define VPBE_DISPLAY_MINOR_RELEASE              0
+#define VPBE_DISPLAY_BUILD                      1
+#define VPBE_DISPLAY_VERSION_CODE ((VPBE_DISPLAY_MAJOR_RELEASE << 16) | \
+       (VPBE_DISPLAY_MINOR_RELEASE << 8)  | \
+       VPBE_DISPLAY_BUILD)
+
+#define VPBE_DISPLAY_VALID_FIELD(field)   ((V4L2_FIELD_NONE == field) || \
+        (V4L2_FIELD_ANY == field) || (V4L2_FIELD_INTERLACED == field))
+
+/* Exp ratio numerator and denominator constants */
+#define VPBE_DISPLAY_H_EXP_RATIO_N     9
+#define VPBE_DISPLAY_H_EXP_RATIO_D     8
+#define VPBE_DISPLAY_V_EXP_RATIO_N     6
+#define VPBE_DISPLAY_V_EXP_RATIO_D     5
+
+/* Zoom multiplication factor */
+#define VPBE_DISPLAY_ZOOM_4X   4
+#define VPBE_DISPLAY_ZOOM_2X   2
+
+/* Structures */
+struct display_layer_info {
+       int enable;
+       /* Layer ID used by Display Manager */
+       enum osd_layer id;
+       struct osd_layer_config config;
+       enum osd_zoom_factor h_zoom;
+       enum osd_zoom_factor v_zoom;
+       enum osd_h_exp_ratio h_exp;
+       enum osd_v_exp_ratio v_exp;
+};
+
+/* vpbe display object structure */
+struct vpbe_layer {
+       /* number of buffers in fbuffers */
+       unsigned int numbuffers;
+       /* Pointer to the vpbe_display */
+       struct vpbe_display *disp_dev;
+       /* Pointer pointing to current v4l2_buffer */
+       struct videobuf_buffer *cur_frm;
+       /* Pointer pointing to next v4l2_buffer */
+       struct videobuf_buffer *next_frm;
+       /* videobuf specific parameters
+        * Buffer queue used in video-buf
+        */
+       struct videobuf_queue buffer_queue;
+       /* Queue of filled frames */
+       struct list_head dma_queue;
+       /* Used in video-buf */
+       spinlock_t irqlock;
+       /* V4l2 specific parameters */
+       /* Identifies video device for this layer */
+       struct video_device video_dev;
+       /* This field keeps track of type of buffer exchange mechanism user
+        * has selected
+        */
+       enum v4l2_memory memory;
+       /* Used to keep track of state of the priority */
+       struct v4l2_prio_state prio;
+       /* Used to store pixel format */
+       struct v4l2_pix_format pix_fmt;
+       enum v4l2_field buf_field;
+       /* Video layer configuration params */
+       struct display_layer_info layer_info;
+       /* vpbe specific parameters
+        * enable window for display
+        */
+       unsigned char window_enable;
+       /* number of open instances of the layer */
+       unsigned int usrs;
+       /* number of users performing IO */
+       unsigned int io_usrs;
+       /* Indicates id of the field which is being displayed */
+       unsigned int field_id;
+       /* Indicates whether streaming started */
+       unsigned char started;
+       /* Identifies device object */
+       enum vpbe_display_device_id device_id;
+       /* facilitation of ioctl ops lock by v4l2*/
+       struct mutex opslock;
+       u8 layer_first_int;
+};
+
+/* vpbe device structure */
+struct vpbe_display {
+       /* layer specific parameters */
+       /* lock for isr updates to buf layers*/
+       spinlock_t dma_queue_lock;
+       /* C-Plane offset from start of y-plane */
+       unsigned int cbcr_ofst;
+       struct vpbe_layer *dev[VPBE_DISPLAY_MAX_DEVICES];
+       struct vpbe_device *vpbe_dev;
+       struct osd_state *osd_device;
+};
+
+/* File handle structure */
+struct vpbe_fh {
+       /* vpbe device structure */
+       struct vpbe_display *disp_dev;
+       /* pointer to layer object for opened device */
+       struct vpbe_layer *layer;
+       /* Indicates whether this file handle is doing IO */
+       unsigned char io_allowed;
+       /* Used to keep track priority of this instance */
+       enum v4l2_priority prio;
+};
+
+struct buf_config_params {
+       unsigned char min_numbuffers;
+       unsigned char numbuffers[VPBE_DISPLAY_MAX_DEVICES];
+       unsigned int min_bufsize[VPBE_DISPLAY_MAX_DEVICES];
+       unsigned int layer_bufsize[VPBE_DISPLAY_MAX_DEVICES];
+};
+
+#endif /* VPBE_DISPLAY_H */
diff --git a/include/media/davinci/vpbe_osd.h b/include/media/davinci/vpbe_osd.h
new file mode 100644 (file)
index 0000000..d7e397a
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * Copyright (C) 2007-2009 Texas Instruments Inc
+ * Copyright (C) 2007 MontaVista Software, Inc.
+ *
+ * Andy Lowe (alowe@mvista.com), MontaVista Software
+ * - Initial version
+ * Murali Karicheri (mkaricheri@gmail.com), Texas Instruments Ltd.
+ * - ported to sub device interface
+ *
+ * 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..
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef _OSD_H
+#define _OSD_H
+
+#include <media/davinci/vpbe_types.h>
+
+#define VPBE_OSD_SUBDEV_NAME "vpbe-osd"
+
+/**
+ * enum osd_layer
+ * @WIN_OSD0: On-Screen Display Window 0
+ * @WIN_VID0: Video Window 0
+ * @WIN_OSD1: On-Screen Display Window 1
+ * @WIN_VID1: Video Window 1
+ *
+ * Description:
+ * An enumeration of the osd display layers.
+ */
+enum osd_layer {
+       WIN_OSD0,
+       WIN_VID0,
+       WIN_OSD1,
+       WIN_VID1,
+};
+
+/**
+ * enum osd_win_layer
+ * @OSDWIN_OSD0: On-Screen Display Window 0
+ * @OSDWIN_OSD1: On-Screen Display Window 1
+ *
+ * Description:
+ * An enumeration of the OSD Window layers.
+ */
+enum osd_win_layer {
+       OSDWIN_OSD0,
+       OSDWIN_OSD1,
+};
+
+/**
+ * enum osd_pix_format
+ * @PIXFMT_1BPP: 1-bit-per-pixel bitmap
+ * @PIXFMT_2BPP: 2-bits-per-pixel bitmap
+ * @PIXFMT_4BPP: 4-bits-per-pixel bitmap
+ * @PIXFMT_8BPP: 8-bits-per-pixel bitmap
+ * @PIXFMT_RGB565: 16-bits-per-pixel RGB565
+ * @PIXFMT_YCbCrI: YUV 4:2:2
+ * @PIXFMT_RGB888: 24-bits-per-pixel RGB888
+ * @PIXFMT_YCrCbI: YUV 4:2:2 with chroma swap
+ * @PIXFMT_NV12: YUV 4:2:0 planar
+ * @PIXFMT_OSD_ATTR: OSD Attribute Window pixel format (4bpp)
+ *
+ * Description:
+ * An enumeration of the DaVinci pixel formats.
+ */
+enum osd_pix_format {
+       PIXFMT_1BPP = 0,
+       PIXFMT_2BPP,
+       PIXFMT_4BPP,
+       PIXFMT_8BPP,
+       PIXFMT_RGB565,
+       PIXFMT_YCbCrI,
+       PIXFMT_RGB888,
+       PIXFMT_YCrCbI,
+       PIXFMT_NV12,
+       PIXFMT_OSD_ATTR,
+};
+
+/**
+ * enum osd_h_exp_ratio
+ * @H_EXP_OFF: no expansion (1/1)
+ * @H_EXP_9_OVER_8: 9/8 expansion ratio
+ * @H_EXP_3_OVER_2: 3/2 expansion ratio
+ *
+ * Description:
+ * An enumeration of the available horizontal expansion ratios.
+ */
+enum osd_h_exp_ratio {
+       H_EXP_OFF,
+       H_EXP_9_OVER_8,
+       H_EXP_3_OVER_2,
+};
+
+/**
+ * enum osd_v_exp_ratio
+ * @V_EXP_OFF: no expansion (1/1)
+ * @V_EXP_6_OVER_5: 6/5 expansion ratio
+ *
+ * Description:
+ * An enumeration of the available vertical expansion ratios.
+ */
+enum osd_v_exp_ratio {
+       V_EXP_OFF,
+       V_EXP_6_OVER_5,
+};
+
+/**
+ * enum osd_zoom_factor
+ * @ZOOM_X1: no zoom (x1)
+ * @ZOOM_X2: x2 zoom
+ * @ZOOM_X4: x4 zoom
+ *
+ * Description:
+ * An enumeration of the available zoom factors.
+ */
+enum osd_zoom_factor {
+       ZOOM_X1,
+       ZOOM_X2,
+       ZOOM_X4,
+};
+
+/**
+ * enum osd_clut
+ * @ROM_CLUT: ROM CLUT
+ * @RAM_CLUT: RAM CLUT
+ *
+ * Description:
+ * An enumeration of the available Color Lookup Tables (CLUTs).
+ */
+enum osd_clut {
+       ROM_CLUT,
+       RAM_CLUT,
+};
+
+/**
+ * enum osd_rom_clut
+ * @ROM_CLUT0: Macintosh CLUT
+ * @ROM_CLUT1: CLUT from DM270 and prior devices
+ *
+ * Description:
+ * An enumeration of the ROM Color Lookup Table (CLUT) options.
+ */
+enum osd_rom_clut {
+       ROM_CLUT0,
+       ROM_CLUT1,
+};
+
+/**
+ * enum osd_blending_factor
+ * @OSD_0_VID_8: OSD pixels are fully transparent
+ * @OSD_1_VID_7: OSD pixels contribute 1/8, video pixels contribute 7/8
+ * @OSD_2_VID_6: OSD pixels contribute 2/8, video pixels contribute 6/8
+ * @OSD_3_VID_5: OSD pixels contribute 3/8, video pixels contribute 5/8
+ * @OSD_4_VID_4: OSD pixels contribute 4/8, video pixels contribute 4/8
+ * @OSD_5_VID_3: OSD pixels contribute 5/8, video pixels contribute 3/8
+ * @OSD_6_VID_2: OSD pixels contribute 6/8, video pixels contribute 2/8
+ * @OSD_8_VID_0: OSD pixels are fully opaque
+ *
+ * Description:
+ * An enumeration of the DaVinci pixel blending factor options.
+ */
+enum osd_blending_factor {
+       OSD_0_VID_8,
+       OSD_1_VID_7,
+       OSD_2_VID_6,
+       OSD_3_VID_5,
+       OSD_4_VID_4,
+       OSD_5_VID_3,
+       OSD_6_VID_2,
+       OSD_8_VID_0,
+};
+
+/**
+ * enum osd_blink_interval
+ * @BLINK_X1: blink interval is 1 vertical refresh cycle
+ * @BLINK_X2: blink interval is 2 vertical refresh cycles
+ * @BLINK_X3: blink interval is 3 vertical refresh cycles
+ * @BLINK_X4: blink interval is 4 vertical refresh cycles
+ *
+ * Description:
+ * An enumeration of the DaVinci pixel blinking interval options.
+ */
+enum osd_blink_interval {
+       BLINK_X1,
+       BLINK_X2,
+       BLINK_X3,
+       BLINK_X4,
+};
+
+/**
+ * enum osd_cursor_h_width
+ * @H_WIDTH_1: horizontal line width is 1 pixel
+ * @H_WIDTH_4: horizontal line width is 4 pixels
+ * @H_WIDTH_8: horizontal line width is 8 pixels
+ * @H_WIDTH_12: horizontal line width is 12 pixels
+ * @H_WIDTH_16: horizontal line width is 16 pixels
+ * @H_WIDTH_20: horizontal line width is 20 pixels
+ * @H_WIDTH_24: horizontal line width is 24 pixels
+ * @H_WIDTH_28: horizontal line width is 28 pixels
+ */
+enum osd_cursor_h_width {
+       H_WIDTH_1,
+       H_WIDTH_4,
+       H_WIDTH_8,
+       H_WIDTH_12,
+       H_WIDTH_16,
+       H_WIDTH_20,
+       H_WIDTH_24,
+       H_WIDTH_28,
+};
+
+/**
+ * enum davinci_cursor_v_width
+ * @V_WIDTH_1: vertical line width is 1 line
+ * @V_WIDTH_2: vertical line width is 2 lines
+ * @V_WIDTH_4: vertical line width is 4 lines
+ * @V_WIDTH_6: vertical line width is 6 lines
+ * @V_WIDTH_8: vertical line width is 8 lines
+ * @V_WIDTH_10: vertical line width is 10 lines
+ * @V_WIDTH_12: vertical line width is 12 lines
+ * @V_WIDTH_14: vertical line width is 14 lines
+ */
+enum osd_cursor_v_width {
+       V_WIDTH_1,
+       V_WIDTH_2,
+       V_WIDTH_4,
+       V_WIDTH_6,
+       V_WIDTH_8,
+       V_WIDTH_10,
+       V_WIDTH_12,
+       V_WIDTH_14,
+};
+
+/**
+ * struct osd_cursor_config
+ * @xsize: horizontal size in pixels
+ * @ysize: vertical size in lines
+ * @xpos: horizontal offset in pixels from the left edge of the display
+ * @ypos: vertical offset in lines from the top of the display
+ * @interlaced: Non-zero if the display is interlaced, or zero otherwise
+ * @h_width: horizontal line width
+ * @v_width: vertical line width
+ * @clut: the CLUT selector (ROM or RAM) for the cursor color
+ * @clut_index: an index into the CLUT for the cursor color
+ *
+ * Description:
+ * A structure describing the configuration parameters of the hardware
+ * rectangular cursor.
+ */
+struct osd_cursor_config {
+       unsigned xsize;
+       unsigned ysize;
+       unsigned xpos;
+       unsigned ypos;
+       int interlaced;
+       enum osd_cursor_h_width h_width;
+       enum osd_cursor_v_width v_width;
+       enum osd_clut clut;
+       unsigned char clut_index;
+};
+
+/**
+ * struct osd_layer_config
+ * @pixfmt: pixel format
+ * @line_length: offset in bytes between start of each line in memory
+ * @xsize: number of horizontal pixels displayed per line
+ * @ysize: number of lines displayed
+ * @xpos: horizontal offset in pixels from the left edge of the display
+ * @ypos: vertical offset in lines from the top of the display
+ * @interlaced: Non-zero if the display is interlaced, or zero otherwise
+ *
+ * Description:
+ * A structure describing the configuration parameters of an On-Screen Display
+ * (OSD) or video layer related to how the image is stored in memory.
+ * @line_length must be a multiple of the cache line size (32 bytes).
+ */
+struct osd_layer_config {
+       enum osd_pix_format pixfmt;
+       unsigned line_length;
+       unsigned xsize;
+       unsigned ysize;
+       unsigned xpos;
+       unsigned ypos;
+       int interlaced;
+};
+
+/* parameters that apply on a per-window (OSD or video) basis */
+struct osd_window_state {
+       int is_allocated;
+       int is_enabled;
+       unsigned long fb_base_phys;
+       enum osd_zoom_factor h_zoom;
+       enum osd_zoom_factor v_zoom;
+       struct osd_layer_config lconfig;
+};
+
+/* parameters that apply on a per-OSD-window basis */
+struct osd_osdwin_state {
+       enum osd_clut clut;
+       enum osd_blending_factor blend;
+       int colorkey_blending;
+       unsigned colorkey;
+       int rec601_attenuation;
+       /* index is pixel value */
+       unsigned char palette_map[16];
+};
+
+/* hardware rectangular cursor parameters */
+struct osd_cursor_state {
+       int is_enabled;
+       struct osd_cursor_config config;
+};
+
+struct osd_state;
+
+struct vpbe_osd_ops {
+       int (*initialize)(struct osd_state *sd);
+       int (*request_layer)(struct osd_state *sd, enum osd_layer layer);
+       void (*release_layer)(struct osd_state *sd, enum osd_layer layer);
+       int (*enable_layer)(struct osd_state *sd, enum osd_layer layer,
+                           int otherwin);
+       void (*disable_layer)(struct osd_state *sd, enum osd_layer layer);
+       int (*set_layer_config)(struct osd_state *sd, enum osd_layer layer,
+                               struct osd_layer_config *lconfig);
+       void (*get_layer_config)(struct osd_state *sd, enum osd_layer layer,
+                                struct osd_layer_config *lconfig);
+       void (*start_layer)(struct osd_state *sd, enum osd_layer layer,
+                           unsigned long fb_base_phys,
+                           unsigned long cbcr_ofst);
+       void (*set_left_margin)(struct osd_state *sd, u32 val);
+       void (*set_top_margin)(struct osd_state *sd, u32 val);
+       void (*set_interpolation_filter)(struct osd_state *sd, int filter);
+       int (*set_vid_expansion)(struct osd_state *sd,
+                                       enum osd_h_exp_ratio h_exp,
+                                       enum osd_v_exp_ratio v_exp);
+       void (*get_vid_expansion)(struct osd_state *sd,
+                                       enum osd_h_exp_ratio *h_exp,
+                                       enum osd_v_exp_ratio *v_exp);
+       void (*set_zoom)(struct osd_state *sd, enum osd_layer layer,
+                               enum osd_zoom_factor h_zoom,
+                               enum osd_zoom_factor v_zoom);
+};
+
+struct osd_state {
+       enum vpbe_version vpbe_type;
+       spinlock_t lock;
+       struct device *dev;
+       dma_addr_t osd_base_phys;
+       unsigned long osd_base;
+       unsigned long osd_size;
+       /* 1-->the isr will toggle the VID0 ping-pong buffer */
+       int pingpong;
+       int interpolation_filter;
+       int field_inversion;
+       enum osd_h_exp_ratio osd_h_exp;
+       enum osd_v_exp_ratio osd_v_exp;
+       enum osd_h_exp_ratio vid_h_exp;
+       enum osd_v_exp_ratio vid_v_exp;
+       enum osd_clut backg_clut;
+       unsigned backg_clut_index;
+       enum osd_rom_clut rom_clut;
+       int is_blinking;
+       /* attribute window blinking enabled */
+       enum osd_blink_interval blink;
+       /* YCbCrI or YCrCbI */
+       enum osd_pix_format yc_pixfmt;
+       /* columns are Y, Cb, Cr */
+       unsigned char clut_ram[256][3];
+       struct osd_cursor_state cursor;
+       /* OSD0, VID0, OSD1, VID1 */
+       struct osd_window_state win[4];
+       /* OSD0, OSD1 */
+       struct osd_osdwin_state osdwin[2];
+       /* OSD device Operations */
+       struct vpbe_osd_ops ops;
+};
+
+struct osd_platform_data {
+       enum vpbe_version vpbe_type;
+       int  field_inv_wa_enable;
+};
+
+#endif
diff --git a/include/media/davinci/vpbe_types.h b/include/media/davinci/vpbe_types.h
new file mode 100644 (file)
index 0000000..727f551
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2010 Texas Instruments 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _VPBE_TYPES_H
+#define _VPBE_TYPES_H
+
+enum vpbe_version {
+       VPBE_VERSION_1 = 1,
+       VPBE_VERSION_2,
+       VPBE_VERSION_3,
+};
+
+/* vpbe_timing_type - Timing types used in vpbe device */
+enum vpbe_enc_timings_type {
+       VPBE_ENC_STD = 0x1,
+       VPBE_ENC_DV_PRESET = 0x2,
+       VPBE_ENC_CUSTOM_TIMINGS = 0x4,
+       /* Used when set timings through FB device interface */
+       VPBE_ENC_TIMINGS_INVALID = 0x8,
+};
+
+union vpbe_timings {
+       v4l2_std_id std_id;
+       unsigned int dv_preset;
+};
+
+/*
+ * struct vpbe_enc_mode_info
+ * @name: ptr to name string of the standard, "NTSC", "PAL" etc
+ * @std: standard or non-standard mode. 1 - standard, 0 - nonstandard
+ * @interlaced: 1 - interlaced, 0 - non interlaced/progressive
+ * @xres: x or horizontal resolution of the display
+ * @yres: y or vertical resolution of the display
+ * @fps: frame per second
+ * @left_margin: left margin of the display
+ * @right_margin: right margin of the display
+ * @upper_margin: upper margin of the display
+ * @lower_margin: lower margin of the display
+ * @hsync_len: h-sync length
+ * @vsync_len: v-sync length
+ * @flags: bit field: bit usage is documented below
+ *
+ * Description:
+ *  Structure holding timing and resolution information of a standard.
+ * Used by vpbe_device to set required non-standard timing in the
+ * venc when lcd controller output is connected to a external encoder.
+ * A table of timings is maintained in vpbe device to set this in
+ * venc when external encoder is connected to lcd controller output.
+ * Encoder may provide a g_dv_timings() API to override these values
+ * as needed.
+ *
+ *  Notes
+ *  ------
+ *  if_type should be used only by encoder manager and encoder.
+ *  flags usage
+ *     b0 (LSB) - hsync polarity, 0 - negative, 1 - positive
+ *     b1       - vsync polarity, 0 - negative, 1 - positive
+ *     b2       - field id polarity, 0 - negative, 1  - positive
+ */
+struct vpbe_enc_mode_info {
+       unsigned char *name;
+       enum vpbe_enc_timings_type timings_type;
+       union vpbe_timings timings;
+       unsigned int interlaced;
+       unsigned int xres;
+       unsigned int yres;
+       struct v4l2_fract aspect;
+       struct v4l2_fract fps;
+       unsigned int left_margin;
+       unsigned int right_margin;
+       unsigned int upper_margin;
+       unsigned int lower_margin;
+       unsigned int hsync_len;
+       unsigned int vsync_len;
+       unsigned int flags;
+};
+
+#endif
diff --git a/include/media/davinci/vpbe_venc.h b/include/media/davinci/vpbe_venc.h
new file mode 100644 (file)
index 0000000..426c205
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010 Texas Instruments 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _VPBE_VENC_H
+#define _VPBE_VENC_H
+
+#include <media/v4l2-subdev.h>
+#include <media/davinci/vpbe_types.h>
+
+#define VPBE_VENC_SUBDEV_NAME "vpbe-venc"
+
+/* venc events */
+#define VENC_END_OF_FRAME      BIT(0)
+#define VENC_FIRST_FIELD       BIT(1)
+#define VENC_SECOND_FIELD      BIT(2)
+
+struct venc_platform_data {
+       enum vpbe_version venc_type;
+       int (*setup_clock)(enum vpbe_enc_timings_type type,
+                          unsigned int mode);
+       /* Number of LCD outputs supported */
+       int num_lcd_outputs;
+};
+
+enum venc_ioctls {
+       VENC_GET_FLD = 1,
+};
+
+/* exported functions */
+struct v4l2_subdev *venc_sub_dev_init(struct v4l2_device *v4l2_dev,
+               const char *venc_name);
+#endif
diff --git a/include/media/mmp-camera.h b/include/media/mmp-camera.h
new file mode 100644 (file)
index 0000000..7611963
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * Information for the Marvell Armada MMP camera
+ */
+
+struct mmp_camera_platform_data {
+       struct platform_device *i2c_device;
+       int sensor_power_gpio;
+       int sensor_reset_gpio;
+};
index 60536c7..b1f19b7 100644 (file)
@@ -117,7 +117,7 @@ struct rc_dev {
        int                             (*s_tx_carrier)(struct rc_dev *dev, u32 carrier);
        int                             (*s_tx_duty_cycle)(struct rc_dev *dev, u32 duty_cycle);
        int                             (*s_rx_carrier_range)(struct rc_dev *dev, u32 min, u32 max);
-       int                             (*tx_ir)(struct rc_dev *dev, int *txbuf, u32 n);
+       int                             (*tx_ir)(struct rc_dev *dev, unsigned *txbuf, unsigned n);
        void                            (*s_idle)(struct rc_dev *dev, bool enable);
        int                             (*s_learning_mode)(struct rc_dev *dev, int enable);
        int                             (*s_carrier_report) (struct rc_dev *dev, int enable);
index 4e1409e..17c9759 100644 (file)
 #define RC_TYPE_JVC    (1  << 3)       /* JVC protocol */
 #define RC_TYPE_SONY   (1  << 4)       /* Sony12/15/20 protocol */
 #define RC_TYPE_RC5_SZ (1  << 5)       /* RC5 variant used by Streamzap */
+#define RC_TYPE_MCE_KBD        (1  << 29)      /* RC6-ish MCE keyboard/mouse */
 #define RC_TYPE_LIRC   (1  << 30)      /* Pass raw IR to lirc userspace */
 #define RC_TYPE_OTHER  (1u << 31)
 
 #define RC_TYPE_ALL (RC_TYPE_RC5 | RC_TYPE_NEC  | RC_TYPE_RC6  | \
                     RC_TYPE_JVC | RC_TYPE_SONY | RC_TYPE_LIRC | \
-                    RC_TYPE_RC5_SZ | RC_TYPE_OTHER)
+                    RC_TYPE_RC5_SZ | RC_TYPE_MCE_KBD | RC_TYPE_OTHER)
 
 struct rc_map_table {
        u32     scancode;
index 80346a6..48413b4 100644 (file)
@@ -7,10 +7,18 @@
 #define SH_CEU_FLAG_VSYNC_LOW          (1 << 3) /* default High if possible */
 
 struct device;
+struct resource;
+
+struct sh_mobile_ceu_companion {
+       u32             num_resources;
+       struct resource *resource;
+       int             id;
+       void            *platform_data;
+};
 
 struct sh_mobile_ceu_info {
        unsigned long flags;
-       struct device *csi2_dev;
+       struct sh_mobile_ceu_companion *csi2;
 };
 
 #endif /* __ASM_SH_MOBILE_CEU_H__ */
index 4d26151..c586c4f 100644 (file)
@@ -11,6 +11,8 @@
 #ifndef SH_MIPI_CSI
 #define SH_MIPI_CSI
 
+#include <linux/list.h>
+
 enum sh_csi2_phy {
        SH_CSI2_PHY_MAIN,
        SH_CSI2_PHY_SUB,
@@ -33,14 +35,14 @@ struct sh_csi2_client_config {
        struct platform_device *pdev;   /* client platform device */
 };
 
+struct v4l2_device;
+
 struct sh_csi2_pdata {
        enum sh_csi2_type type;
        unsigned int flags;
        struct sh_csi2_client_config *clients;
        int num_clients;
+       struct v4l2_device *v4l2_dev;
 };
 
-struct device;
-struct v4l2_device;
-
 #endif
index 238bd33..7582952 100644 (file)
 #include <media/videobuf2-core.h>
 #include <media/v4l2-device.h>
 
-extern struct bus_type soc_camera_bus_type;
-
 struct file;
+struct soc_camera_link;
 
 struct soc_camera_device {
-       struct list_head list;
-       struct device dev;
+       struct list_head list;          /* list of all registered devices */
+       struct soc_camera_link *link;
        struct device *pdev;            /* Platform device */
+       struct device *parent;          /* Camera host device */
+       struct device *control;         /* E.g., the i2c client */
        s32 user_width;
        s32 user_height;
        u32 bytesperline;               /* for padding, zero if unused */
@@ -66,8 +67,6 @@ struct soc_camera_host_ops {
        struct module *owner;
        int (*add)(struct soc_camera_device *);
        void (*remove)(struct soc_camera_device *);
-       int (*suspend)(struct soc_camera_device *, pm_message_t);
-       int (*resume)(struct soc_camera_device *);
        /*
         * .get_formats() is called for each client device format, but
         * .put_formats() is only called once. Further, if any of the calls to
@@ -109,12 +108,6 @@ struct soc_camera_host_ops {
 #define SOCAM_SENSOR_INVERT_HSYNC      (1 << 2)
 #define SOCAM_SENSOR_INVERT_VSYNC      (1 << 3)
 #define SOCAM_SENSOR_INVERT_DATA       (1 << 4)
-#define SOCAM_MIPI_1LANE               (1 << 5)
-#define SOCAM_MIPI_2LANE               (1 << 6)
-#define SOCAM_MIPI_3LANE               (1 << 7)
-#define SOCAM_MIPI_4LANE               (1 << 8)
-#define SOCAM_MIPI     (SOCAM_MIPI_1LANE | SOCAM_MIPI_2LANE | \
-                       SOCAM_MIPI_3LANE | SOCAM_MIPI_4LANE)
 
 struct i2c_board_info;
 struct regulator_bulk_data;
@@ -134,11 +127,11 @@ struct soc_camera_link {
        int num_regulators;
 
        /*
-        * For non-I2C devices platform platform has to provide methods to
-        * add a device to the system and to remove
+        * For non-I2C devices platform has to provide methods to add a device
+        * to the system and to remove it
         */
-       int (*add_device)(struct soc_camera_link *, struct device *);
-       void (*del_device)(struct soc_camera_link *);
+       int (*add_device)(struct soc_camera_device *);
+       void (*del_device)(struct soc_camera_device *);
        /* Optional callbacks to power on or off and reset the sensor */
        int (*power)(struct device *, int);
        int (*reset)(struct device *);
@@ -152,12 +145,6 @@ struct soc_camera_link {
        void (*free_bus)(struct soc_camera_link *);
 };
 
-static inline struct soc_camera_device *to_soc_camera_dev(
-       const struct device *dev)
-{
-       return container_of(dev, struct soc_camera_device, dev);
-}
-
 static inline struct soc_camera_host *to_soc_camera_host(
        const struct device *dev)
 {
@@ -169,13 +156,13 @@ static inline struct soc_camera_host *to_soc_camera_host(
 static inline struct soc_camera_link *to_soc_camera_link(
        const struct soc_camera_device *icd)
 {
-       return icd->dev.platform_data;
+       return icd->link;
 }
 
 static inline struct device *to_soc_camera_control(
        const struct soc_camera_device *icd)
 {
-       return dev_get_drvdata(&icd->dev);
+       return icd->control;
 }
 
 static inline struct v4l2_subdev *soc_camera_to_subdev(
@@ -207,11 +194,8 @@ struct soc_camera_format_xlate {
 };
 
 struct soc_camera_ops {
-       int (*suspend)(struct soc_camera_device *, pm_message_t state);
-       int (*resume)(struct soc_camera_device *);
        unsigned long (*query_bus_param)(struct soc_camera_device *);
        int (*set_bus_param)(struct soc_camera_device *, unsigned long);
-       int (*enum_input)(struct soc_camera_device *, struct v4l2_input *);
        const struct v4l2_queryctrl *controls;
        int num_controls;
 };
@@ -270,6 +254,12 @@ static inline struct v4l2_queryctrl const *soc_camera_find_qctrl(
 #define SOCAM_PCLK_SAMPLE_FALLING      (1 << 13)
 #define SOCAM_DATA_ACTIVE_HIGH         (1 << 14)
 #define SOCAM_DATA_ACTIVE_LOW          (1 << 15)
+#define SOCAM_MIPI_1LANE               (1 << 16)
+#define SOCAM_MIPI_2LANE               (1 << 17)
+#define SOCAM_MIPI_3LANE               (1 << 18)
+#define SOCAM_MIPI_4LANE               (1 << 19)
+#define SOCAM_MIPI     (SOCAM_MIPI_1LANE | SOCAM_MIPI_2LANE | \
+                       SOCAM_MIPI_3LANE | SOCAM_MIPI_4LANE)
 
 #define SOCAM_DATAWIDTH_MASK (SOCAM_DATAWIDTH_4 | SOCAM_DATAWIDTH_8 | \
                              SOCAM_DATAWIDTH_9 | SOCAM_DATAWIDTH_10 | \
index 6d7a4fd..74f0fa1 100644 (file)
@@ -21,7 +21,7 @@ struct soc_camera_platform_info {
        unsigned long format_depth;
        struct v4l2_mbus_framefmt format;
        unsigned long bus_param;
-       struct device *dev;
+       struct soc_camera_device *icd;
        int (*set_capture)(struct soc_camera_platform_info *info, int enable);
 };
 
@@ -30,8 +30,7 @@ static inline void soc_camera_platform_release(struct platform_device **pdev)
        *pdev = NULL;
 }
 
-static inline int soc_camera_platform_add(const struct soc_camera_link *icl,
-                                         struct device *dev,
+static inline int soc_camera_platform_add(struct soc_camera_device *icd,
                                          struct platform_device **pdev,
                                          struct soc_camera_link *plink,
                                          void (*release)(struct device *dev),
@@ -40,7 +39,7 @@ static inline int soc_camera_platform_add(const struct soc_camera_link *icl,
        struct soc_camera_platform_info *info = plink->priv;
        int ret;
 
-       if (icl != plink)
+       if (icd->link != plink)
                return -ENODEV;
 
        if (*pdev)
@@ -50,7 +49,7 @@ static inline int soc_camera_platform_add(const struct soc_camera_link *icl,
        if (!*pdev)
                return -ENOMEM;
 
-       info->dev = dev;
+       info->icd = icd;
 
        (*pdev)->dev.platform_data = info;
        (*pdev)->dev.release = release;
@@ -59,17 +58,17 @@ static inline int soc_camera_platform_add(const struct soc_camera_link *icl,
        if (ret < 0) {
                platform_device_put(*pdev);
                *pdev = NULL;
-               info->dev = NULL;
+               info->icd = NULL;
        }
 
        return ret;
 }
 
-static inline void soc_camera_platform_del(const struct soc_camera_link *icl,
+static inline void soc_camera_platform_del(const struct soc_camera_device *icd,
                                           struct platform_device *pdev,
                                           const struct soc_camera_link *plink)
 {
-       if (icl != plink || !pdev)
+       if (icd->link != plink || !pdev)
                return;
 
        platform_device_unregister(pdev);
index a59a848..a40a6a3 100644 (file)
 
 struct timb_radio_platform_data {
        int i2c_adapter; /* I2C adapter where the tuner and dsp are attached */
-       struct {
-               struct i2c_board_info *info;
-       } tuner;
-       struct {
-               const char *module_name;
-               struct i2c_board_info *info;
-       } dsp;
+       struct i2c_board_info *tuner;
+       struct i2c_board_info *dsp;
 };
 
 #endif
index 963e334..89c290b 100644 (file)
 #define TUNER_PHILIPS_FMD1216MEX_MK3   78
 #define TUNER_PHILIPS_FM1216MK5                79
 #define TUNER_PHILIPS_FQ1216LME_MK3    80      /* Active loopthrough, no FM */
+#define TUNER_XC4000                   81      /* Xceive Silicon Tuner */
+
 #define TUNER_PARTSNIC_PTI_5NF05       81
 #define TUNER_PHILIPS_CU1216L           82
 #define TUNER_NXP_TDA18271             83
index b3edb67..63fd9d3 100644 (file)
@@ -76,6 +76,7 @@ enum {
        V4L2_IDENT_OV6650 = 258,
        V4L2_IDENT_OV2640 = 259,
        V4L2_IDENT_OV9740 = 260,
+       V4L2_IDENT_OV5642 = 261,
 
        /* module saa7146: reserved range 300-309 */
        V4L2_IDENT_SAA7146 = 300,
@@ -185,8 +186,9 @@ enum {
        /* module wm8775: just ident 8775 */
        V4L2_IDENT_WM8775 = 8775,
 
-       /* module cafe_ccic, just ident 8801 */
+       /* Marvell controllers starting at 8801 */
        V4L2_IDENT_CAFE = 8801,
+       V4L2_IDENT_ARMADA610 = 8802,
 
        /* AKM AK8813/AK8814 */
        V4L2_IDENT_AK8813 = 8813,
index 97d0638..13fe4d7 100644 (file)
 
 /* forward references */
 struct v4l2_ctrl_handler;
+struct v4l2_ctrl_helper;
 struct v4l2_ctrl;
 struct video_device;
 struct v4l2_subdev;
+struct v4l2_subscribed_event;
+struct v4l2_fh;
 
 /** struct v4l2_ctrl_ops - The control operations that the driver has to provide.
   * @g_volatile_ctrl: Get a new value for this control. Generally only relevant
@@ -51,6 +54,7 @@ struct v4l2_ctrl_ops {
 
 /** struct v4l2_ctrl - The control structure.
   * @node:     The list node.
+  * @ev_subs:  The list of control event subscriptions.
   * @handler:  The handler that owns the control.
   * @cluster:  Point to start of cluster array.
   * @ncontrols:        Number of controls in cluster array.
@@ -65,6 +69,15 @@ struct v4l2_ctrl_ops {
   *            control's current value cannot be cached and needs to be
   *            retrieved through the g_volatile_ctrl op. Drivers can set
   *            this flag.
+  * @is_auto:   If set, then this control selects whether the other cluster
+  *            members are in 'automatic' mode or 'manual' mode. This is
+  *            used for autogain/gain type clusters. Drivers should never
+  *            set this flag directly.
+  * @manual_mode_value: If the is_auto flag is set, then this is the value
+  *            of the auto control that determines if that control is in
+  *            manual mode. So if the value of the auto control equals this
+  *            value, then the whole cluster is in manual mode. Drivers should
+  *            never set this flag directly.
   * @ops:      The control ops.
   * @id:       The control ID.
   * @name:     The control name.
@@ -97,6 +110,7 @@ struct v4l2_ctrl_ops {
 struct v4l2_ctrl {
        /* Administrative fields */
        struct list_head node;
+       struct list_head ev_subs;
        struct v4l2_ctrl_handler *handler;
        struct v4l2_ctrl **cluster;
        unsigned ncontrols;
@@ -105,6 +119,8 @@ struct v4l2_ctrl {
        unsigned int is_new:1;
        unsigned int is_private:1;
        unsigned int is_volatile:1;
+       unsigned int is_auto:1;
+       unsigned int manual_mode_value:8;
 
        const struct v4l2_ctrl_ops *ops;
        u32 id;
@@ -134,6 +150,7 @@ struct v4l2_ctrl {
   * @node:     List node for the sorted list.
   * @next:     Single-link list node for the hash.
   * @ctrl:     The actual control information.
+  * @helper:   Pointer to helper struct. Used internally in prepare_ext_ctrls().
   *
   * Each control handler has a list of these refs. The list_head is used to
   * keep a sorted-by-control-ID list of all controls, while the next pointer
@@ -143,6 +160,7 @@ struct v4l2_ctrl_ref {
        struct list_head node;
        struct v4l2_ctrl_ref *next;
        struct v4l2_ctrl *ctrl;
+       struct v4l2_ctrl_helper *helper;
 };
 
 /** struct v4l2_ctrl_handler - The control handler keeps track of all the
@@ -363,6 +381,40 @@ int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
 void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls);
 
 
+/** v4l2_ctrl_auto_cluster() - Mark all controls in the cluster as belonging to
+  * that cluster and set it up for autofoo/foo-type handling.
+  * @ncontrols:        The number of controls in this cluster.
+  * @controls: The cluster control array of size @ncontrols. The first control
+  *            must be the 'auto' control (e.g. autogain, autoexposure, etc.)
+  * @manual_val: The value for the first control in the cluster that equals the
+  *            manual setting.
+  * @set_volatile: If true, then all controls except the first auto control will
+  *            have is_volatile set to true. If false, then is_volatile will not
+  *            be touched.
+  *
+  * Use for control groups where one control selects some automatic feature and
+  * the other controls are only active whenever the automatic feature is turned
+  * off (manual mode). Typical examples: autogain vs gain, auto-whitebalance vs
+  * red and blue balance, etc.
+  *
+  * The behavior of such controls is as follows:
+  *
+  * When the autofoo control is set to automatic, then any manual controls
+  * are set to inactive and any reads will call g_volatile_ctrl (if the control
+  * was marked volatile).
+  *
+  * When the autofoo control is set to manual, then any manual controls will
+  * be marked active, and any reads will just return the current value without
+  * going through g_volatile_ctrl.
+  *
+  * In addition, this function will set the V4L2_CTRL_FLAG_UPDATE flag
+  * on the autofoo control and V4L2_CTRL_FLAG_INACTIVE on the foo control(s)
+  * if autofoo is in auto mode.
+  */
+void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls,
+                       u8 manual_val, bool set_volatile);
+
+
 /** v4l2_ctrl_find() - Find a control with the given ID.
   * @hdl:      The control handler.
   * @id:       The control ID to find.
@@ -379,9 +431,9 @@ struct v4l2_ctrl *v4l2_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id);
   * This sets or clears the V4L2_CTRL_FLAG_INACTIVE flag atomically.
   * Does nothing if @ctrl == NULL.
   * This will usually be called from within the s_ctrl op.
+  * The V4L2_EVENT_CTRL event will be generated afterwards.
   *
-  * This function can be called regardless of whether the control handler
-  * is locked or not.
+  * This function assumes that the control handler is locked.
   */
 void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active);
 
@@ -391,11 +443,12 @@ void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active);
   *
   * This sets or clears the V4L2_CTRL_FLAG_GRABBED flag atomically.
   * Does nothing if @ctrl == NULL.
+  * The V4L2_EVENT_CTRL event will be generated afterwards.
   * This will usually be called when starting or stopping streaming in the
   * driver.
   *
-  * This function can be called regardless of whether the control handler
-  * is locked or not.
+  * This function assumes that the control handler is not locked and will
+  * take the lock itself.
   */
 void v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed);
 
@@ -440,15 +493,22 @@ s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl);
   */
 int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val);
 
+/* Internal helper functions that deal with control events. */
+void v4l2_ctrl_add_event(struct v4l2_ctrl *ctrl,
+               struct v4l2_subscribed_event *sev);
+void v4l2_ctrl_del_event(struct v4l2_ctrl *ctrl,
+               struct v4l2_subscribed_event *sev);
 
 /* Helpers for ioctl_ops. If hdl == NULL then they will all return -EINVAL. */
 int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc);
 int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm);
 int v4l2_g_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *ctrl);
-int v4l2_s_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *ctrl);
+int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
+                                               struct v4l2_control *ctrl);
 int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *c);
 int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *c);
-int v4l2_s_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *c);
+int v4l2_s_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
+                                               struct v4l2_ext_controls *c);
 
 /* Helpers for subdevices. If the associated ctrl_handler == NULL then they
    will all return -EINVAL. */
index 3b86177..5f14e88 100644 (file)
 #include <linux/videodev2.h>
 #include <linux/wait.h>
 
+/*
+ * Overview:
+ *
+ * Events are subscribed per-filehandle. An event specification consists of a
+ * type and is optionally associated with an object identified through the
+ * 'id' field. So an event is uniquely identified by the (type, id) tuple.
+ *
+ * The v4l2-fh struct has a list of subscribed events. The v4l2_subscribed_event
+ * struct is added to that list, one for every subscribed event.
+ *
+ * Each v4l2_subscribed_event struct ends with an array of v4l2_kevent structs.
+ * This array (ringbuffer, really) is used to store any events raised by the
+ * driver. The v4l2_kevent struct links into the 'available' list of the
+ * v4l2_fh struct so VIDIOC_DQEVENT will know which event to dequeue first.
+ *
+ * Finally, if the event subscription is associated with a particular object
+ * such as a V4L2 control, then that object needs to know about that as well
+ * so that an event can be raised by that object. So the 'node' field can
+ * be used to link the v4l2_subscribed_event struct into a list of that
+ * object.
+ *
+ * So to summarize:
+ *
+ * struct v4l2_fh has two lists: one of the subscribed events, and one of the
+ * pending events.
+ *
+ * struct v4l2_subscribed_event has a ringbuffer of raised (pending) events of
+ * that particular type.
+ *
+ * If struct v4l2_subscribed_event is associated with a specific object, then
+ * that object will have an internal list of struct v4l2_subscribed_event so
+ * it knows who subscribed an event to that object.
+ */
+
 struct v4l2_fh;
+struct v4l2_subscribed_event;
 struct video_device;
 
+/** struct v4l2_kevent - Internal kernel event struct.
+  * @list:     List node for the v4l2_fh->available list.
+  * @sev:      Pointer to parent v4l2_subscribed_event.
+  * @event:    The event itself.
+  */
 struct v4l2_kevent {
        struct list_head        list;
+       struct v4l2_subscribed_event *sev;
        struct v4l2_event       event;
 };
 
+/** struct v4l2_subscribed_event - Internal struct representing a subscribed event.
+  * @list:     List node for the v4l2_fh->subscribed list.
+  * @type:     Event type.
+  * @id:       Associated object ID (e.g. control ID). 0 if there isn't any.
+  * @flags:    Copy of v4l2_event_subscription->flags.
+  * @fh:       Filehandle that subscribed to this event.
+  * @node:     List node that hooks into the object's event list (if there is one).
+  * @replace:  Optional callback that can replace event 'old' with event 'new'.
+  * @merge:    Optional callback that can merge event 'old' into event 'new'.
+  * @elems:    The number of elements in the events array.
+  * @first:    The index of the events containing the oldest available event.
+  * @in_use:   The number of queued events.
+  * @events:   An array of @elems events.
+  */
 struct v4l2_subscribed_event {
        struct list_head        list;
        u32                     type;
+       u32                     id;
+       u32                     flags;
+       struct v4l2_fh          *fh;
+       struct list_head        node;
+       void                    (*replace)(struct v4l2_event *old,
+                                          const struct v4l2_event *new);
+       void                    (*merge)(const struct v4l2_event *old,
+                                        struct v4l2_event *new);
+       unsigned                elems;
+       unsigned                first;
+       unsigned                in_use;
+       struct v4l2_kevent      events[];
 };
 
-struct v4l2_events {
-       wait_queue_head_t       wait;
-       struct list_head        subscribed; /* Subscribed events */
-       struct list_head        free; /* Events ready for use */
-       struct list_head        available; /* Dequeueable event */
-       unsigned int            navailable;
-       unsigned int            nallocated; /* Number of allocated events */
-       u32                     sequence;
-};
-
-int v4l2_event_init(struct v4l2_fh *fh);
-int v4l2_event_alloc(struct v4l2_fh *fh, unsigned int n);
-void v4l2_event_free(struct v4l2_fh *fh);
 int v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event,
                       int nonblocking);
 void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev);
+void v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *ev);
 int v4l2_event_pending(struct v4l2_fh *fh);
 int v4l2_event_subscribe(struct v4l2_fh *fh,
-                        struct v4l2_event_subscription *sub);
+                        struct v4l2_event_subscription *sub, unsigned elems);
 int v4l2_event_unsubscribe(struct v4l2_fh *fh,
                           struct v4l2_event_subscription *sub);
+void v4l2_event_unsubscribe_all(struct v4l2_fh *fh);
 
 #endif /* V4L2_EVENT_H */
index 0206aa5..52513c2 100644 (file)
 #include <linux/list.h>
 
 struct video_device;
-struct v4l2_events;
+struct v4l2_ctrl_handler;
 
 struct v4l2_fh {
        struct list_head        list;
        struct video_device     *vdev;
-       struct v4l2_events      *events; /* events, pending and subscribed */
+       struct v4l2_ctrl_handler *ctrl_handler;
        enum v4l2_priority      prio;
+
+       /* Events */
+       wait_queue_head_t       wait;
+       struct list_head        subscribed; /* Subscribed events */
+       struct list_head        available; /* Dequeueable event */
+       unsigned int            navailable;
+       u32                     sequence;
 };
 
 /*
@@ -44,7 +51,7 @@ struct v4l2_fh {
  * from driver's v4l2_file_operations->open() handler if the driver
  * uses v4l2_fh.
  */
-int v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev);
+void v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev);
 /*
  * Add the fh to the list of file handles on a video_device. The file
  * handle must be initialised first.
index 971c7fa..6114007 100644 (file)
 
 #include <linux/v4l2-mediabus.h>
 
+/* Parallel flags */
+/*
+ * Can the client run in master or in slave mode. By "Master mode" an operation
+ * mode is meant, when the client (e.g., a camera sensor) is producing
+ * horizontal and vertical synchronisation. In "Slave mode" the host is
+ * providing these signals to the slave.
+ */
+#define V4L2_MBUS_MASTER                       (1 << 0)
+#define V4L2_MBUS_SLAVE                                (1 << 1)
+/* Which signal polarities it supports */
+/* Note: in BT.656 mode HSYNC and VSYNC are unused */
+#define V4L2_MBUS_HSYNC_ACTIVE_HIGH            (1 << 2)
+#define V4L2_MBUS_HSYNC_ACTIVE_LOW             (1 << 3)
+#define V4L2_MBUS_VSYNC_ACTIVE_HIGH            (1 << 4)
+#define V4L2_MBUS_VSYNC_ACTIVE_LOW             (1 << 5)
+#define V4L2_MBUS_PCLK_SAMPLE_RISING           (1 << 6)
+#define V4L2_MBUS_PCLK_SAMPLE_FALLING          (1 << 7)
+#define V4L2_MBUS_DATA_ACTIVE_HIGH             (1 << 8)
+#define V4L2_MBUS_DATA_ACTIVE_LOW              (1 << 9)
+
+/* Serial flags */
+/* How many lanes the client can use */
+#define V4L2_MBUS_CSI2_1_LANE                  (1 << 0)
+#define V4L2_MBUS_CSI2_2_LANE                  (1 << 1)
+#define V4L2_MBUS_CSI2_3_LANE                  (1 << 2)
+#define V4L2_MBUS_CSI2_4_LANE                  (1 << 3)
+/* On which channels it can send video data */
+#define V4L2_MBUS_CSI2_CHANNEL_0               (1 << 4)
+#define V4L2_MBUS_CSI2_CHANNEL_1               (1 << 5)
+#define V4L2_MBUS_CSI2_CHANNEL_2               (1 << 6)
+#define V4L2_MBUS_CSI2_CHANNEL_3               (1 << 7)
+/* Does it support only continuous or also non-continuous clock mode */
+#define V4L2_MBUS_CSI2_CONTINUOUS_CLOCK                (1 << 8)
+#define V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK     (1 << 9)
+
+#define V4L2_MBUS_CSI2_LANES           (V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_2_LANE | \
+                                        V4L2_MBUS_CSI2_3_LANE | V4L2_MBUS_CSI2_4_LANE)
+#define V4L2_MBUS_CSI2_CHANNELS                (V4L2_MBUS_CSI2_CHANNEL_0 | V4L2_MBUS_CSI2_CHANNEL_1 | \
+                                        V4L2_MBUS_CSI2_CHANNEL_2 | V4L2_MBUS_CSI2_CHANNEL_3)
+
+/**
+ * v4l2_mbus_type - media bus type
+ * @V4L2_MBUS_PARALLEL:        parallel interface with hsync and vsync
+ * @V4L2_MBUS_BT656:   parallel interface with embedded synchronisation, can
+ *                     also be used for BT.1120
+ * @V4L2_MBUS_CSI2:    MIPI CSI-2 serial interface
+ */
+enum v4l2_mbus_type {
+       V4L2_MBUS_PARALLEL,
+       V4L2_MBUS_BT656,
+       V4L2_MBUS_CSI2,
+};
+
+/**
+ * v4l2_mbus_config - media bus configuration
+ * @type:      in: interface type
+ * @flags:     in / out: configuration flags, depending on @type
+ */
+struct v4l2_mbus_config {
+       enum v4l2_mbus_type type;
+       unsigned int flags;
+};
+
 static inline void v4l2_fill_pix_format(struct v4l2_pix_format *pix_fmt,
                                const struct v4l2_mbus_framefmt *mbus_fmt)
 {
index 2884e3e..257da1a 100644 (file)
@@ -229,6 +229,12 @@ struct v4l2_subdev_audio_ops {
    s_std_output: set v4l2_std_id for video OUTPUT devices. This is ignored by
        video input devices.
 
+   g_std_output: get current standard for video OUTPUT devices. This is ignored
+       by video input devices.
+
+   g_tvnorms_output: get v4l2_std_id with all standards supported by video
+       OUTPUT device. This is ignored by video input devices.
+
    s_crystal_freq: sets the frequency of the crystal used to generate the
        clocks in Hz. An extra flags field allows device specific configuration
        regarding clock frequency dividers, etc. If not used, then set flags
@@ -243,6 +249,8 @@ struct v4l2_subdev_audio_ops {
    s_dv_preset: set dv (Digital Video) preset in the sub device. Similar to
        s_std()
 
+   g_dv_preset: get current dv (Digital Video) preset in the sub device.
+
    query_dv_preset: query dv preset in the sub device. This is similar to
        querystd()
 
@@ -259,12 +267,20 @@ struct v4l2_subdev_audio_ops {
    try_mbus_fmt: try to set a pixel format on a video data source
 
    s_mbus_fmt: set a pixel format on a video data source
+
+   g_mbus_config: get supported mediabus configurations
+
+   s_mbus_config: set a certain mediabus configuration. This operation is added
+       for compatibility with soc-camera drivers and should not be used by new
+       software.
  */
 struct v4l2_subdev_video_ops {
        int (*s_routing)(struct v4l2_subdev *sd, u32 input, u32 output, u32 config);
        int (*s_crystal_freq)(struct v4l2_subdev *sd, u32 freq, u32 flags);
        int (*s_std_output)(struct v4l2_subdev *sd, v4l2_std_id std);
+       int (*g_std_output)(struct v4l2_subdev *sd, v4l2_std_id *std);
        int (*querystd)(struct v4l2_subdev *sd, v4l2_std_id *std);
+       int (*g_tvnorms_output)(struct v4l2_subdev *sd, v4l2_std_id *std);
        int (*g_input_status)(struct v4l2_subdev *sd, u32 *status);
        int (*s_stream)(struct v4l2_subdev *sd, int enable);
        int (*cropcap)(struct v4l2_subdev *sd, struct v4l2_cropcap *cc);
@@ -282,6 +298,8 @@ struct v4l2_subdev_video_ops {
                        struct v4l2_dv_enum_preset *preset);
        int (*s_dv_preset)(struct v4l2_subdev *sd,
                        struct v4l2_dv_preset *preset);
+       int (*g_dv_preset)(struct v4l2_subdev *sd,
+                       struct v4l2_dv_preset *preset);
        int (*query_dv_preset)(struct v4l2_subdev *sd,
                        struct v4l2_dv_preset *preset);
        int (*s_dv_timings)(struct v4l2_subdev *sd,
@@ -298,6 +316,10 @@ struct v4l2_subdev_video_ops {
                            struct v4l2_mbus_framefmt *fmt);
        int (*s_mbus_fmt)(struct v4l2_subdev *sd,
                          struct v4l2_mbus_framefmt *fmt);
+       int (*g_mbus_config)(struct v4l2_subdev *sd,
+                            struct v4l2_mbus_config *cfg);
+       int (*s_mbus_config)(struct v4l2_subdev *sd,
+                            const struct v4l2_mbus_config *cfg);
 };
 
 /*
@@ -513,8 +535,6 @@ struct v4l2_subdev {
        void *host_priv;
        /* subdev device node */
        struct video_device devnode;
-       /* number of events to be allocated on open */
-       unsigned int nevents;
 };
 
 #define media_entity_to_v4l2_subdev(ent) \
index 3b93874..9808877 100644 (file)
@@ -8,7 +8,7 @@
  * have chosen to adopt the protocol and over the years it has become a
  * de-facto standard for labeled networking.
  *
- * Author: Paul Moore <paul.moore@hp.com>
+ * Author: Paul Moore <paul@paul-moore.com>
  *
  */
 
index 29e2557..13d507d 100644 (file)
@@ -37,7 +37,7 @@ struct dst_entry {
        unsigned long           _metrics;
        unsigned long           expires;
        struct dst_entry        *path;
-       struct neighbour        *_neighbour;
+       struct neighbour __rcu  *_neighbour;
 #ifdef CONFIG_XFRM
        struct xfrm_state       *xfrm;
 #else
@@ -88,12 +88,17 @@ struct dst_entry {
 
 static inline struct neighbour *dst_get_neighbour(struct dst_entry *dst)
 {
-       return dst->_neighbour;
+       return rcu_dereference(dst->_neighbour);
+}
+
+static inline struct neighbour *dst_get_neighbour_raw(struct dst_entry *dst)
+{
+       return rcu_dereference_raw(dst->_neighbour);
 }
 
 static inline void dst_set_neighbour(struct dst_entry *dst, struct neighbour *neigh)
 {
-       dst->_neighbour = neigh;
+       rcu_assign_pointer(dst->_neighbour, neigh);
 }
 
 extern u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old);
@@ -382,8 +387,12 @@ static inline void dst_rcu_free(struct rcu_head *head)
 static inline void dst_confirm(struct dst_entry *dst)
 {
        if (dst) {
-               struct neighbour *n = dst_get_neighbour(dst);
+               struct neighbour *n;
+
+               rcu_read_lock();
+               n = dst_get_neighbour(dst);
                neigh_confirm(n);
+               rcu_read_unlock();
        }
 }
 
index caaff5f..b897d6e 100644 (file)
@@ -238,7 +238,7 @@ static inline __u8 inet_sk_flowi_flags(const struct sock *sk)
 {
        __u8 flags = 0;
 
-       if (inet_sk(sk)->transparent)
+       if (inet_sk(sk)->transparent || inet_sk(sk)->hdrincl)
                flags |= FLOWI_FLAG_ANYSRC;
        if (sk->sk_protocol == IPPROTO_TCP)
                flags |= FLOWI_FLAG_PRECOW_METRICS;
index f21a16e..f674409 100644 (file)
@@ -4,7 +4,7 @@
  * The NetLabel system manages static and dynamic label mappings for network
  * protocols such as CIPSO and RIPSO.
  *
- * Author: Paul Moore <paul.moore@hp.com>
+ * Author: Paul Moore <paul@paul-moore.com>
  *
  */
 
index 99e6e19..4c0766e 100644 (file)
@@ -96,7 +96,8 @@ extern int sysctl_max_syn_backlog;
  */
 struct listen_sock {
        u8                      max_qlen_log;
-       /* 3 bytes hole, try to use */
+       u8                      synflood_warned;
+       /* 2 bytes hole, try to use */
        int                     qlen;
        int                     qlen_young;
        int                     clock_hand;
diff --git a/include/net/secure_seq.h b/include/net/secure_seq.h
new file mode 100644 (file)
index 0000000..d97f689
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _NET_SECURE_SEQ
+#define _NET_SECURE_SEQ
+
+#include <linux/types.h>
+
+extern __u32 secure_ip_id(__be32 daddr);
+extern __u32 secure_ipv6_id(const __be32 daddr[4]);
+extern u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport);
+extern u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
+                                     __be16 dport);
+extern __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
+                                       __be16 sport, __be16 dport);
+extern __u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr,
+                                         __be16 sport, __be16 dport);
+extern u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
+                                      __be16 sport, __be16 dport);
+extern u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,
+                                        __be16 sport, __be16 dport);
+
+#endif /* _NET_SECURE_SEQ */
index 149a415..e9b48b0 100644 (file)
@@ -460,6 +460,9 @@ extern int tcp_write_wakeup(struct sock *);
 extern void tcp_send_fin(struct sock *sk);
 extern void tcp_send_active_reset(struct sock *sk, gfp_t priority);
 extern int tcp_send_synack(struct sock *);
+extern int tcp_syn_flood_action(struct sock *sk,
+                               const struct sk_buff *skb,
+                               const char *proto);
 extern void tcp_push_one(struct sock *, unsigned int mss_now);
 extern void tcp_send_ack(struct sock *sk);
 extern void tcp_send_delayed_ack(struct sock *sk);
index 63e5b8f..00dbfac 100644 (file)
        .prod_id = { (v1), NULL, NULL, NULL }, \
        .prod_id_hash = { (vh1), 0, 0, 0 }, }
 
+#define PCMCIA_DEVICE_MANF_CARD_PROD_ID3(manf, card, v3, vh3) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_MANF_ID| \
+                       PCMCIA_DEV_ID_MATCH_CARD_ID| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID3, \
+       .manf_id = (manf), \
+       .card_id = (card), \
+       .prod_id = { NULL, NULL, (v3), NULL }, \
+       .prod_id_hash = { 0, 0, (vh3), 0 }, }
+
 
 /* multi-function devices */
 
index 4ad0204..8225d80 100644 (file)
@@ -78,7 +78,6 @@ struct fc_frame {
 };
 
 struct fcoe_rcv_info {
-       struct packet_type  *ptype;
        struct fc_lport *fr_dev;        /* transport layer private pointer */
        struct fc_seq   *fr_seq;        /* for use with exchange manager */
        struct fc_fcp_pkt *fr_fsp;      /* for the corresponding fcp I/O */
diff --git a/include/scsi/osd_ore.h b/include/scsi/osd_ore.h
new file mode 100644 (file)
index 0000000..c5c5e00
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2011
+ * Boaz Harrosh <bharrosh@panasas.com>
+ *
+ * Public Declarations of the ORE API
+ *
+ * This file is part of the ORE (Object Raid Engine) library.
+ *
+ * ORE 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. (GPL v2)
+ *
+ * ORE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 ORE; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#ifndef __ORE_H__
+#define __ORE_H__
+
+#include <scsi/osd_initiator.h>
+#include <scsi/osd_attributes.h>
+#include <scsi/osd_sec.h>
+#include <linux/pnfs_osd_xdr.h>
+
+struct ore_comp {
+       struct osd_obj_id       obj;
+       u8                      cred[OSD_CAP_LEN];
+};
+
+struct ore_layout {
+       /* Our way of looking at the data_map */
+       unsigned stripe_unit;
+       unsigned mirrors_p1;
+
+       unsigned group_width;
+       u64      group_depth;
+       unsigned group_count;
+};
+
+struct ore_components {
+       unsigned        numdevs;                /* Num of devices in array    */
+       /* If @single_comp == EC_SINGLE_COMP, @comps points to a single
+        * component. else there are @numdevs components
+        */
+       enum EC_COMP_USAGE {
+               EC_SINGLE_COMP = 0, EC_MULTPLE_COMPS = 0xffffffff
+       }               single_comp;
+       struct ore_comp *comps;
+       struct osd_dev  **ods;                  /* osd_dev array              */
+};
+
+struct ore_io_state;
+typedef void (*ore_io_done_fn)(struct ore_io_state *ios, void *private);
+
+struct ore_io_state {
+       struct kref             kref;
+
+       void                    *private;
+       ore_io_done_fn  done;
+
+       struct ore_layout       *layout;
+       struct ore_components   *comps;
+
+       /* Global read/write IO*/
+       loff_t                  offset;
+       unsigned long           length;
+       void                    *kern_buff;
+
+       struct page             **pages;
+       unsigned                nr_pages;
+       unsigned                pgbase;
+       unsigned                pages_consumed;
+
+       /* Attributes */
+       unsigned                in_attr_len;
+       struct osd_attr         *in_attr;
+       unsigned                out_attr_len;
+       struct osd_attr         *out_attr;
+
+       bool                    reading;
+
+       /* Variable array of size numdevs */
+       unsigned numdevs;
+       struct ore_per_dev_state {
+               struct osd_request *or;
+               struct bio *bio;
+               loff_t offset;
+               unsigned length;
+               unsigned dev;
+       } per_dev[];
+};
+
+static inline unsigned ore_io_state_size(unsigned numdevs)
+{
+       return sizeof(struct ore_io_state) +
+               sizeof(struct ore_per_dev_state) * numdevs;
+}
+
+/* ore.c */
+int ore_get_rw_state(struct ore_layout *layout, struct ore_components *comps,
+                    bool is_reading, u64 offset, u64 length,
+                    struct ore_io_state **ios);
+int ore_get_io_state(struct ore_layout *layout, struct ore_components *comps,
+                    struct ore_io_state **ios);
+void ore_put_io_state(struct ore_io_state *ios);
+
+int ore_check_io(struct ore_io_state *ios, u64 *resid);
+
+int ore_create(struct ore_io_state *ios);
+int ore_remove(struct ore_io_state *ios);
+int ore_write(struct ore_io_state *ios);
+int ore_read(struct ore_io_state *ios);
+int ore_truncate(struct ore_layout *layout, struct ore_components *comps,
+                u64 size);
+
+int extract_attr_from_ios(struct ore_io_state *ios, struct osd_attr *attr);
+
+extern const struct osd_attr g_attr_logical_length;
+
+#endif
index d2ea112..726e947 100644 (file)
@@ -23,8 +23,8 @@
  */
 
 #include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
 #include <media/v4l2-dev.h>
-#include <media/v4l2-ioctl.h>
 
 #define TEA575X_FMIF   10700
 
@@ -42,18 +42,20 @@ struct snd_tea575x_ops {
 };
 
 struct snd_tea575x {
-       struct video_device *vd;        /* video device */
+       struct video_device vd;         /* video device */
        bool tea5759;                   /* 5759 chip is present */
        bool mute;                      /* Device is muted? */
        bool stereo;                    /* receiving stereo */
        bool tuned;                     /* tuned to a station */
        unsigned int val;               /* hw value */
        unsigned long freq;             /* frequency */
-       unsigned long in_use;           /* set if the device is in use */
+       struct mutex mutex;
        struct snd_tea575x_ops *ops;
        void *private_data;
        u8 card[32];
        u8 bus_info[32];
+       struct v4l2_ctrl_handler ctrl_handler;
+       int (*ext_init)(struct snd_tea575x *tea);
 };
 
 int snd_tea575x_init(struct snd_tea575x *tea);
index 99e0308..ffd9bc7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Platform data for Texas Instruments TLV320AIC3x codec
  *
- * Author: Jarkko Nikula <jhnikula@gmail.com>
+ * Author: Jarkko Nikula <jarkko.nikula@bitmer.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
similarity index 63%
rename from include/sound/wm8915.h
rename to include/sound/wm8996.h
index 5817d76..ea4d88f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/sound/wm8915.h -- Platform data for WM8915
+ * linux/sound/wm8996.h -- Platform data for WM8996
  *
  * Copyright 2011 Wolfson Microelectronics. PLC.
  *
@@ -8,14 +8,14 @@
  * published by the Free Software Foundation.
  */
 
-#ifndef __LINUX_SND_WM8903_H
-#define __LINUX_SND_WM8903_H
+#ifndef __LINUX_SND_WM8996_H
+#define __LINUX_SND_WM8996_H
 
-enum wm8915_inmode {
-       WM8915_DIFFERRENTIAL_1 = 0,   /* IN1xP - IN1xN */
-       WM8915_INVERTING = 1,         /* IN1xN */
-       WM8915_NON_INVERTING = 2,     /* IN1xP */
-       WM8915_DIFFERENTIAL_2 = 3,    /* IN2xP - IN2xP */
+enum wm8996_inmode {
+       WM8996_DIFFERRENTIAL_1 = 0,   /* IN1xP - IN1xN */
+       WM8996_INVERTING = 1,         /* IN1xN */
+       WM8996_NON_INVERTING = 2,     /* IN1xP */
+       WM8996_DIFFERENTIAL_2 = 3,    /* IN2xP - IN2xP */
 };
 
 /**
@@ -25,23 +25,23 @@ enum wm8915_inmode {
  * Configurations are expected to be generated using the ReTune Mobile
  * control panel in WISCE - see http://www.wolfsonmicro.com/wisce/
  */
-struct wm8915_retune_mobile_config {
+struct wm8996_retune_mobile_config {
        const char *name;
        int rate;
        u16 regs[20];
 };
 
-#define WM8915_SET_DEFAULT 0x10000
+#define WM8996_SET_DEFAULT 0x10000
 
-struct wm8915_pdata {
+struct wm8996_pdata {
        int irq_flags;  /** Set IRQ trigger flags; default active low */
 
        int ldo_ena;  /** GPIO for LDO1; -1 for none */
 
        int micdet_def;  /** Default MICDET_SRC/HP1FB_SRC/MICD_BIAS */
 
-       enum wm8915_inmode inl_mode;
-       enum wm8915_inmode inr_mode;
+       enum wm8996_inmode inl_mode;
+       enum wm8996_inmode inr_mode;
 
        u32 spkmute_seq;  /** Value for register 0x802 */
 
@@ -49,7 +49,7 @@ struct wm8915_pdata {
        u32 gpio_default[5];
 
        int num_retune_mobile_cfgs;
-       struct wm8915_retune_mobile_config *retune_mobile_cfgs;
+       struct wm8996_retune_mobile_config *retune_mobile_cfgs;
 };
 
 #endif
index bf36654..05c5e61 100644 (file)
@@ -8,6 +8,8 @@
 #include <linux/blkdev.h>
 #include <linux/tracepoint.h>
 
+#define RWBS_LEN       8
+
 DECLARE_EVENT_CLASS(block_rq_with_error,
 
        TP_PROTO(struct request_queue *q, struct request *rq),
@@ -19,7 +21,7 @@ DECLARE_EVENT_CLASS(block_rq_with_error,
                __field(  sector_t,     sector                  )
                __field(  unsigned int, nr_sector               )
                __field(  int,          errors                  )
-               __array(  char,         rwbs,   6               )
+               __array(  char,         rwbs,   RWBS_LEN        )
                __dynamic_array( char,  cmd,    blk_cmd_buf_len(rq)     )
        ),
 
@@ -104,7 +106,7 @@ DECLARE_EVENT_CLASS(block_rq,
                __field(  sector_t,     sector                  )
                __field(  unsigned int, nr_sector               )
                __field(  unsigned int, bytes                   )
-               __array(  char,         rwbs,   6               )
+               __array(  char,         rwbs,   RWBS_LEN        )
                __array(  char,         comm,   TASK_COMM_LEN   )
                __dynamic_array( char,  cmd,    blk_cmd_buf_len(rq)     )
        ),
@@ -183,7 +185,7 @@ TRACE_EVENT(block_bio_bounce,
                __field( dev_t,         dev                     )
                __field( sector_t,      sector                  )
                __field( unsigned int,  nr_sector               )
-               __array( char,          rwbs,   6               )
+               __array( char,          rwbs,   RWBS_LEN        )
                __array( char,          comm,   TASK_COMM_LEN   )
        ),
 
@@ -222,7 +224,7 @@ TRACE_EVENT(block_bio_complete,
                __field( sector_t,      sector          )
                __field( unsigned,      nr_sector       )
                __field( int,           error           )
-               __array( char,          rwbs,   6       )
+               __array( char,          rwbs,   RWBS_LEN)
        ),
 
        TP_fast_assign(
@@ -249,7 +251,7 @@ DECLARE_EVENT_CLASS(block_bio,
                __field( dev_t,         dev                     )
                __field( sector_t,      sector                  )
                __field( unsigned int,  nr_sector               )
-               __array( char,          rwbs,   6               )
+               __array( char,          rwbs,   RWBS_LEN        )
                __array( char,          comm,   TASK_COMM_LEN   )
        ),
 
@@ -321,7 +323,7 @@ DECLARE_EVENT_CLASS(block_get_rq,
                __field( dev_t,         dev                     )
                __field( sector_t,      sector                  )
                __field( unsigned int,  nr_sector               )
-               __array( char,          rwbs,   6               )
+               __array( char,          rwbs,   RWBS_LEN        )
                __array( char,          comm,   TASK_COMM_LEN   )
         ),
 
@@ -456,7 +458,7 @@ TRACE_EVENT(block_split,
                __field( dev_t,         dev                             )
                __field( sector_t,      sector                          )
                __field( sector_t,      new_sector                      )
-               __array( char,          rwbs,           6               )
+               __array( char,          rwbs,           RWBS_LEN        )
                __array( char,          comm,           TASK_COMM_LEN   )
        ),
 
@@ -498,7 +500,7 @@ TRACE_EVENT(block_bio_remap,
                __field( unsigned int,  nr_sector       )
                __field( dev_t,         old_dev         )
                __field( sector_t,      old_sector      )
-               __array( char,          rwbs,   6       )
+               __array( char,          rwbs,   RWBS_LEN)
        ),
 
        TP_fast_assign(
@@ -542,7 +544,7 @@ TRACE_EVENT(block_rq_remap,
                __field( unsigned int,  nr_sector       )
                __field( dev_t,         old_dev         )
                __field( sector_t,      old_sector      )
-               __array( char,          rwbs,   6       )
+               __array( char,          rwbs,   RWBS_LEN)
        ),
 
        TP_fast_assign(
index 6363193..b50a547 100644 (file)
@@ -23,7 +23,7 @@ TRACE_EVENT(ext4_free_inode,
        TP_STRUCT__entry(
                __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
-               __field(        umode_t, mode                   )
+               __field(        __u16, mode                     )
                __field(        uid_t,  uid                     )
                __field(        gid_t,  gid                     )
                __field(        __u64, blocks                   )
@@ -52,7 +52,7 @@ TRACE_EVENT(ext4_request_inode,
        TP_STRUCT__entry(
                __field(        dev_t,  dev                     )
                __field(        ino_t,  dir                     )
-               __field(        umode_t, mode                   )
+               __field(        __u16, mode                     )
        ),
 
        TP_fast_assign(
@@ -75,7 +75,7 @@ TRACE_EVENT(ext4_allocate_inode,
                __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
                __field(        ino_t,  dir                     )
-               __field(        umode_t, mode                   )
+               __field(        __u16,  mode                    )
        ),
 
        TP_fast_assign(
@@ -725,7 +725,7 @@ TRACE_EVENT(ext4_free_blocks,
        TP_STRUCT__entry(
                __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
-               __field(        umode_t, mode                   )
+               __field(        __u16,  mode                    )
                __field(        __u64,  block                   )
                __field(        unsigned long,  count           )
                __field(        int,    flags                   )
@@ -1012,7 +1012,7 @@ TRACE_EVENT(ext4_forget,
        TP_STRUCT__entry(
                __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
-               __field(        umode_t, mode                   )
+               __field(        __u16,  mode                    )
                __field(        int,    is_metadata             )
                __field(        __u64,  block                   )
        ),
@@ -1039,7 +1039,7 @@ TRACE_EVENT(ext4_da_update_reserve_space,
        TP_STRUCT__entry(
                __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
-               __field(        umode_t, mode                   )
+               __field(        __u16,  mode                    )
                __field(        __u64,  i_blocks                )
                __field(        int,    used_blocks             )
                __field(        int,    reserved_data_blocks    )
@@ -1076,7 +1076,7 @@ TRACE_EVENT(ext4_da_reserve_space,
        TP_STRUCT__entry(
                __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
-               __field(        umode_t, mode                   )
+               __field(        __u16,  mode                    )
                __field(        __u64,  i_blocks                )
                __field(        int,    md_needed               )
                __field(        int,    reserved_data_blocks    )
@@ -1110,7 +1110,7 @@ TRACE_EVENT(ext4_da_release_space,
        TP_STRUCT__entry(
                __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
-               __field(        umode_t, mode                   )
+               __field(        __u16,  mode                    )
                __field(        __u64,  i_blocks                )
                __field(        int,    freed_blocks            )
                __field(        int,    reserved_data_blocks    )
@@ -1518,6 +1518,77 @@ TRACE_EVENT(ext4_load_inode,
                  (unsigned long) __entry->ino)
 );
 
+TRACE_EVENT(ext4_journal_start,
+       TP_PROTO(struct super_block *sb, int nblocks, unsigned long IP),
+
+       TP_ARGS(sb, nblocks, IP),
+
+       TP_STRUCT__entry(
+               __field(        dev_t,  dev                     )
+               __field(          int,  nblocks                 )
+               __field(unsigned long,  ip                      )
+       ),
+
+       TP_fast_assign(
+               __entry->dev     = sb->s_dev;
+               __entry->nblocks = nblocks;
+               __entry->ip      = IP;
+       ),
+
+       TP_printk("dev %d,%d nblocks %d caller %pF",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->nblocks, (void *)__entry->ip)
+);
+
+DECLARE_EVENT_CLASS(ext4__trim,
+       TP_PROTO(struct super_block *sb,
+                ext4_group_t group,
+                ext4_grpblk_t start,
+                ext4_grpblk_t len),
+
+       TP_ARGS(sb, group, start, len),
+
+       TP_STRUCT__entry(
+               __field(        int,    dev_major               )
+               __field(        int,    dev_minor               )
+               __field(        __u32,  group                   )
+               __field(        int,    start                   )
+               __field(        int,    len                     )
+       ),
+
+       TP_fast_assign(
+               __entry->dev_major      = MAJOR(sb->s_dev);
+               __entry->dev_minor      = MINOR(sb->s_dev);
+               __entry->group          = group;
+               __entry->start          = start;
+               __entry->len            = len;
+       ),
+
+       TP_printk("dev %d,%d group %u, start %d, len %d",
+                 __entry->dev_major, __entry->dev_minor,
+                 __entry->group, __entry->start, __entry->len)
+);
+
+DEFINE_EVENT(ext4__trim, ext4_trim_extent,
+
+       TP_PROTO(struct super_block *sb,
+                ext4_group_t group,
+                ext4_grpblk_t start,
+                ext4_grpblk_t len),
+
+       TP_ARGS(sb, group, start, len)
+);
+
+DEFINE_EVENT(ext4__trim, ext4_trim_all_free,
+
+       TP_PROTO(struct super_block *sb,
+                ext4_group_t group,
+                ext4_grpblk_t start,
+                ext4_grpblk_t len),
+
+       TP_ARGS(sb, group, start, len)
+);
+
 #endif /* _TRACE_EXT4_H */
 
 /* This part must be outside protection */
index bf16545..7596441 100644 (file)
@@ -26,8 +26,8 @@ TRACE_EVENT(jbd2_checkpoint,
                __entry->result         = result;
        ),
 
-       TP_printk("dev %s result %d",
-                 jbd2_dev_to_name(__entry->dev), __entry->result)
+       TP_printk("dev %d,%d result %d",
+                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->result)
 );
 
 DECLARE_EVENT_CLASS(jbd2_commit,
@@ -48,9 +48,9 @@ DECLARE_EVENT_CLASS(jbd2_commit,
                __entry->transaction    = commit_transaction->t_tid;
        ),
 
-       TP_printk("dev %s transaction %d sync %d",
-                 jbd2_dev_to_name(__entry->dev), __entry->transaction,
-                 __entry->sync_commit)
+       TP_printk("dev %d,%d transaction %d sync %d",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->transaction, __entry->sync_commit)
 );
 
 DEFINE_EVENT(jbd2_commit, jbd2_start_commit,
@@ -100,9 +100,9 @@ TRACE_EVENT(jbd2_end_commit,
                __entry->head           = journal->j_tail_sequence;
        ),
 
-       TP_printk("dev %s transaction %d sync %d head %d",
-                 jbd2_dev_to_name(__entry->dev), __entry->transaction,
-                 __entry->sync_commit, __entry->head)
+       TP_printk("dev %d,%d transaction %d sync %d head %d",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->transaction, __entry->sync_commit, __entry->head)
 );
 
 TRACE_EVENT(jbd2_submit_inode_data,
@@ -120,8 +120,9 @@ TRACE_EVENT(jbd2_submit_inode_data,
                __entry->ino    = inode->i_ino;
        ),
 
-       TP_printk("dev %s ino %lu",
-                 jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino)
+       TP_printk("dev %d,%d ino %lu",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 (unsigned long) __entry->ino)
 );
 
 TRACE_EVENT(jbd2_run_stats,
@@ -156,9 +157,9 @@ TRACE_EVENT(jbd2_run_stats,
                __entry->blocks_logged  = stats->rs_blocks_logged;
        ),
 
-       TP_printk("dev %s tid %lu wait %u running %u locked %u flushing %u "
+       TP_printk("dev %d,%d tid %lu wait %u running %u locked %u flushing %u "
                  "logging %u handle_count %u blocks %u blocks_logged %u",
-                 jbd2_dev_to_name(__entry->dev), __entry->tid,
+                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->tid,
                  jiffies_to_msecs(__entry->wait),
                  jiffies_to_msecs(__entry->running),
                  jiffies_to_msecs(__entry->locked),
@@ -192,9 +193,9 @@ TRACE_EVENT(jbd2_checkpoint_stats,
                __entry->dropped        = stats->cs_dropped;
        ),
 
-       TP_printk("dev %s tid %lu chp_time %u forced_to_close %u "
+       TP_printk("dev %d,%d tid %lu chp_time %u forced_to_close %u "
                  "written %u dropped %u",
-                 jbd2_dev_to_name(__entry->dev), __entry->tid,
+                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->tid,
                  jiffies_to_msecs(__entry->chp_time),
                  __entry->forced_to_close, __entry->written, __entry->dropped)
 );
@@ -222,9 +223,10 @@ TRACE_EVENT(jbd2_cleanup_journal_tail,
                __entry->freed          = freed;
        ),
 
-       TP_printk("dev %s from %u to %u offset %lu freed %lu",
-                 jbd2_dev_to_name(__entry->dev), __entry->tail_sequence,
-                 __entry->first_tid, __entry->block_nr, __entry->freed)
+       TP_printk("dev %d,%d from %u to %u offset %lu freed %lu",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->tail_sequence, __entry->first_tid,
+                 __entry->block_nr, __entry->freed)
 );
 
 #endif /* _TRACE_JBD2_H */
index 44d8dec..92f1a79 100644 (file)
@@ -8,6 +8,8 @@
 #include <asm/paravirt_types.h>
 #include <asm/xen/trace_types.h>
 
+struct multicall_entry;
+
 /* Multicalls */
 DECLARE_EVENT_CLASS(xen_mc__batch,
            TP_PROTO(enum paravirt_lazy_mode mode),
index 892b97f..3b55ef2 100644 (file)
@@ -21,8 +21,6 @@
 #include <linux/list.h>
 #include <linux/kobject.h>
 #include <linux/device.h>
-#include <linux/platform_device.h>
-#include <asm/atomic.h>
 
 #define DISPC_IRQ_FRAMEDONE            (1 << 0)
 #define DISPC_IRQ_VSYNC                        (1 << 1)
@@ -136,12 +134,6 @@ enum omap_display_caps {
        OMAP_DSS_DISPLAY_CAP_TEAR_ELIM          = 1 << 1,
 };
 
-enum omap_dss_update_mode {
-       OMAP_DSS_UPDATE_DISABLED = 0,
-       OMAP_DSS_UPDATE_AUTO,
-       OMAP_DSS_UPDATE_MANUAL,
-};
-
 enum omap_dss_display_state {
        OMAP_DSS_DISPLAY_DISABLED = 0,
        OMAP_DSS_DISPLAY_ACTIVE,
@@ -246,7 +238,7 @@ int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel);
 
 /* Board specific data */
 struct omap_dss_board_info {
-       int (*get_last_off_on_transaction_id)(struct device *dev);
+       int (*get_context_loss_count)(struct device *dev);
        int num_devices;
        struct omap_dss_device **devices;
        struct omap_dss_device *default_device;
@@ -266,8 +258,6 @@ static inline int omap_display_init(struct omap_dss_board_info *board_data)
 struct omap_display_platform_data {
        struct omap_dss_board_info *board_data;
        /* TODO: Additional members to be added when PM is considered */
-
-       bool (*opt_clock_available)(const char *clk_role);
 };
 
 struct omap_video_timings {
@@ -300,6 +290,12 @@ extern const struct omap_video_timings omap_dss_pal_timings;
 extern const struct omap_video_timings omap_dss_ntsc_timings;
 #endif
 
+struct omap_dss_cpr_coefs {
+       s16 rr, rg, rb;
+       s16 gr, gg, gb;
+       s16 br, bg, bb;
+};
+
 struct omap_overlay_info {
        bool enabled;
 
@@ -359,6 +355,9 @@ struct omap_overlay_manager_info {
        bool trans_enabled;
 
        bool alpha_enabled;
+
+       bool cpr_enable;
+       struct omap_dss_cpr_coefs cpr_coefs;
 };
 
 struct omap_overlay_manager {
@@ -526,11 +525,6 @@ struct omap_dss_driver {
        int (*resume)(struct omap_dss_device *display);
        int (*run_test)(struct omap_dss_device *display, int test);
 
-       int (*set_update_mode)(struct omap_dss_device *dssdev,
-                       enum omap_dss_update_mode);
-       enum omap_dss_update_mode (*get_update_mode)(
-                       struct omap_dss_device *dssdev);
-
        int (*update)(struct omap_dss_device *dssdev,
                               u16 x, u16 y, u16 w, u16 h);
        int (*sync)(struct omap_dss_device *dssdev);
index d7211fa..9c51ee7 100644 (file)
@@ -369,9 +369,12 @@ static noinline void __init_refok rest_init(void)
        init_idle_bootup_task(current);
        preempt_enable_no_resched();
        schedule();
-       preempt_disable();
+
+       /* At this point, we can enable user mode helper functionality */
+       usermodehelper_enable();
 
        /* Call into cpu_idle with preempt disabled */
+       preempt_disable();
        cpu_idle();
 }
 
@@ -715,7 +718,7 @@ static void __init do_basic_setup(void)
 {
        cpuset_init_smp();
        usermodehelper_init();
-       init_tmpfs();
+       shmem_init();
        driver_init();
        init_irq_proc();
        do_ctors();
index 3f5b143..02ecf2c 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -105,9 +105,16 @@ void shm_exit_ns(struct ipc_namespace *ns)
 }
 #endif
 
-void __init shm_init (void)
+static int __init ipc_ns_init(void)
 {
        shm_init_ns(&init_ipc_ns);
+       return 0;
+}
+
+pure_initcall(ipc_ns_init);
+
+void __init shm_init (void)
+{
        ipc_init_proc_interface("sysvipc/shm",
 #if BITS_PER_LONG <= 32
                                "       key      shmid perms       size  cpid  lpid nattch   uid   gid  cuid  cgid      atime      dtime      ctime        rss       swap\n",
@@ -131,6 +138,12 @@ static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
        return container_of(ipcp, struct shmid_kernel, shm_perm);
 }
 
+static inline void shm_lock_by_ptr(struct shmid_kernel *ipcp)
+{
+       rcu_read_lock();
+       spin_lock(&ipcp->shm_perm.lock);
+}
+
 static inline struct shmid_kernel *shm_lock_check(struct ipc_namespace *ns,
                                                int id)
 {
@@ -231,76 +244,80 @@ static void shm_close(struct vm_area_struct *vma)
        up_write(&shm_ids(ns).rw_mutex);
 }
 
+/* Called with ns->shm_ids(ns).rw_mutex locked */
 static int shm_try_destroy_current(int id, void *p, void *data)
 {
        struct ipc_namespace *ns = data;
-       struct shmid_kernel *shp = shm_lock(ns, id);
+       struct kern_ipc_perm *ipcp = p;
+       struct shmid_kernel *shp = container_of(ipcp, struct shmid_kernel, shm_perm);
 
-       if (IS_ERR(shp))
+       if (shp->shm_creator != current)
                return 0;
 
-       if (shp->shm_cprid != task_tgid_vnr(current)) {
-               shm_unlock(shp);
+       /*
+        * Mark it as orphaned to destroy the segment when
+        * kernel.shm_rmid_forced is changed.
+        * It is noop if the following shm_may_destroy() returns true.
+        */
+       shp->shm_creator = NULL;
+
+       /*
+        * Don't even try to destroy it.  If shm_rmid_forced=0 and IPC_RMID
+        * is not set, it shouldn't be deleted here.
+        */
+       if (!ns->shm_rmid_forced)
                return 0;
-       }
 
-       if (shm_may_destroy(ns, shp))
+       if (shm_may_destroy(ns, shp)) {
+               shm_lock_by_ptr(shp);
                shm_destroy(ns, shp);
-       else
-               shm_unlock(shp);
+       }
        return 0;
 }
 
+/* Called with ns->shm_ids(ns).rw_mutex locked */
 static int shm_try_destroy_orphaned(int id, void *p, void *data)
 {
        struct ipc_namespace *ns = data;
-       struct shmid_kernel *shp = shm_lock(ns, id);
-       struct task_struct *task;
-
-       if (IS_ERR(shp))
-               return 0;
+       struct kern_ipc_perm *ipcp = p;
+       struct shmid_kernel *shp = container_of(ipcp, struct shmid_kernel, shm_perm);
 
        /*
         * We want to destroy segments without users and with already
         * exit'ed originating process.
         *
-        * XXX: the originating process may exist in another pid namespace.
+        * As shp->* are changed under rw_mutex, it's safe to skip shp locking.
         */
-       task = find_task_by_vpid(shp->shm_cprid);
-       if (task != NULL) {
-               shm_unlock(shp);
+       if (shp->shm_creator != NULL)
                return 0;
-       }
 
-       if (shm_may_destroy(ns, shp))
+       if (shm_may_destroy(ns, shp)) {
+               shm_lock_by_ptr(shp);
                shm_destroy(ns, shp);
-       else
-               shm_unlock(shp);
+       }
        return 0;
 }
 
 void shm_destroy_orphaned(struct ipc_namespace *ns)
 {
        down_write(&shm_ids(ns).rw_mutex);
-       idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_orphaned, ns);
+       if (shm_ids(ns).in_use)
+               idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_orphaned, ns);
        up_write(&shm_ids(ns).rw_mutex);
 }
 
 
 void exit_shm(struct task_struct *task)
 {
-       struct nsproxy *nsp = task->nsproxy;
-       struct ipc_namespace *ns;
+       struct ipc_namespace *ns = task->nsproxy->ipc_ns;
 
-       if (!nsp)
-               return;
-       ns = nsp->ipc_ns;
-       if (!ns || !ns->shm_rmid_forced)
+       if (shm_ids(ns).in_use == 0)
                return;
 
        /* Destroy all already created segments, but not mapped yet */
        down_write(&shm_ids(ns).rw_mutex);
-       idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_current, ns);
+       if (shm_ids(ns).in_use)
+               idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_current, ns);
        up_write(&shm_ids(ns).rw_mutex);
 }
 
@@ -494,6 +511,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
        shp->shm_segsz = size;
        shp->shm_nattch = 0;
        shp->shm_file = file;
+       shp->shm_creator = current;
        /*
         * shmid gets reported as "inode#" in /proc/pid/maps.
         * proc-ps tools use this. Changing this will break them.
index d06467f..eca595e 100644 (file)
@@ -10,7 +10,7 @@ obj-y     = sched.o fork.o exec_domain.o panic.o printk.o \
            kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
            hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \
            notifier.o ksysfs.o pm_qos_params.o sched_clock.o cred.o \
-           async.o range.o jump_label.o
+           async.o range.o
 obj-y += groups.o
 
 ifdef CONFIG_FUNCTION_TRACER
@@ -107,6 +107,7 @@ obj-$(CONFIG_PERF_EVENTS) += events/
 obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o
 obj-$(CONFIG_PADATA) += padata.o
 obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
+obj-$(CONFIG_JUMP_LABEL) += jump_label.o
 
 ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
index 616c781..e2435ee 100644 (file)
@@ -158,6 +158,7 @@ int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user
                        __put_user(ts->tv_sec, &cts->tv_sec) ||
                        __put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
 }
+EXPORT_SYMBOL_GPL(put_compat_timespec);
 
 static long compat_nanosleep_restart(struct restart_block *restart)
 {
index 174fa84..8ef31f5 100644 (file)
@@ -508,10 +508,8 @@ int commit_creds(struct cred *new)
                key_fsgid_changed(task);
 
        /* do it
-        * - What if a process setreuid()'s and this brings the
-        *   new uid over his NPROC rlimit?  We can check this now
-        *   cheaply with the new uid cache, so if it matters
-        *   we should be checking for it.  -DaveM
+        * RLIMIT_NPROC limits on user->processes have already been checked
+        * in set_user().
         */
        alter_cred_subscribers(new, 2);
        if (new->user != old->user)
index a11db95..3487248 100644 (file)
@@ -42,6 +42,8 @@
 /* Our I/O buffers. */
 static char                    remcom_in_buffer[BUFMAX];
 static char                    remcom_out_buffer[BUFMAX];
+static int                     gdbstub_use_prev_in_buf;
+static int                     gdbstub_prev_in_buf_pos;
 
 /* Storage for the registers, in GDB format. */
 static unsigned long           gdb_regs[(NUMREGBYTES +
@@ -58,6 +60,13 @@ static int gdbstub_read_wait(void)
        int ret = -1;
        int i;
 
+       if (unlikely(gdbstub_use_prev_in_buf)) {
+               if (gdbstub_prev_in_buf_pos < gdbstub_use_prev_in_buf)
+                       return remcom_in_buffer[gdbstub_prev_in_buf_pos++];
+               else
+                       gdbstub_use_prev_in_buf = 0;
+       }
+
        /* poll any additional I/O interfaces that are defined */
        while (ret < 0)
                for (i = 0; kdb_poll_funcs[i] != NULL; i++) {
@@ -109,7 +118,6 @@ static void get_packet(char *buffer)
                        buffer[count] = ch;
                        count = count + 1;
                }
-               buffer[count] = 0;
 
                if (ch == '#') {
                        xmitcsum = hex_to_bin(gdbstub_read_wait()) << 4;
@@ -124,6 +132,7 @@ static void get_packet(char *buffer)
                        if (dbg_io_ops->flush)
                                dbg_io_ops->flush();
                }
+               buffer[count] = 0;
        } while (checksum != xmitcsum);
 }
 
@@ -1082,12 +1091,11 @@ int gdbstub_state(struct kgdb_state *ks, char *cmd)
        case 'c':
                strcpy(remcom_in_buffer, cmd);
                return 0;
-       case '?':
-               gdb_cmd_status(ks);
-               break;
-       case '\0':
-               strcpy(remcom_out_buffer, "");
-               break;
+       case '$':
+               strcpy(remcom_in_buffer, cmd);
+               gdbstub_use_prev_in_buf = strlen(remcom_in_buffer);
+               gdbstub_prev_in_buf_pos = 0;
+               return 0;
        }
        dbg_io_ops->write_char('+');
        put_packet(remcom_out_buffer);
index 2f62fe8..7179eac 100644 (file)
@@ -112,9 +112,8 @@ kdb_bt(int argc, const char **argv)
        unsigned long addr;
        long offset;
 
-       kdbgetintenv("BTARGS", &argcount);      /* Arguments to print */
-       kdbgetintenv("BTAPROMPT", &btaprompt);  /* Prompt after each
-                                                * proc in bta */
+       /* Prompt after each proc in bta */
+       kdbgetintenv("BTAPROMPT", &btaprompt);
 
        if (strcmp(argv[0], "bta") == 0) {
                struct task_struct *g, *p;
index 56c88e4..9834ad3 100644 (file)
@@ -18,16 +18,12 @@ defcmd dumpcommon "" "Common kdb debugging"
 endefcmd
 
 defcmd dumpall "" "First line debugging"
-  set BTSYMARG 1
-  set BTARGS 9
   pid R
   -dumpcommon
   -bta
 endefcmd
 
 defcmd dumpcpu "" "Same as dumpall but only tasks on cpus"
-  set BTSYMARG 1
-  set BTARGS 9
   pid R
   -dumpcommon
   -btc
index dd0b1b7..d9ca9aa 100644 (file)
@@ -30,6 +30,8 @@ EXPORT_SYMBOL_GPL(kdb_poll_funcs);
 int kdb_poll_idx = 1;
 EXPORT_SYMBOL_GPL(kdb_poll_idx);
 
+static struct kgdb_state *kdb_ks;
+
 int kdb_stub(struct kgdb_state *ks)
 {
        int error = 0;
@@ -39,6 +41,7 @@ int kdb_stub(struct kgdb_state *ks)
        kdb_dbtrap_t db_result = KDB_DB_NOBPT;
        int i;
 
+       kdb_ks = ks;
        if (KDB_STATE(REENTRY)) {
                reason = KDB_REASON_SWITCH;
                KDB_STATE_CLEAR(REENTRY);
@@ -123,20 +126,8 @@ int kdb_stub(struct kgdb_state *ks)
        KDB_STATE_CLEAR(PAGER);
        kdbnearsym_cleanup();
        if (error == KDB_CMD_KGDB) {
-               if (KDB_STATE(DOING_KGDB) || KDB_STATE(DOING_KGDB2)) {
-       /*
-        * This inteface glue which allows kdb to transition in into
-        * the gdb stub.  In order to do this the '?' or '' gdb serial
-        * packet response is processed here.  And then control is
-        * passed to the gdbstub.
-        */
-                       if (KDB_STATE(DOING_KGDB))
-                               gdbstub_state(ks, "?");
-                       else
-                               gdbstub_state(ks, "");
+               if (KDB_STATE(DOING_KGDB))
                        KDB_STATE_CLEAR(DOING_KGDB);
-                       KDB_STATE_CLEAR(DOING_KGDB2);
-               }
                return DBG_PASS_EVENT;
        }
        kdb_bp_install(ks->linux_regs);
@@ -166,3 +157,7 @@ int kdb_stub(struct kgdb_state *ks)
        return kgdb_info[ks->cpu].ret_state;
 }
 
+void kdb_gdb_state_pass(char *buf)
+{
+       gdbstub_state(kdb_ks, buf);
+}
index 96fdaac..4802eb5 100644 (file)
@@ -31,15 +31,21 @@ char kdb_prompt_str[CMD_BUFLEN];
 
 int kdb_trap_printk;
 
-static void kgdb_transition_check(char *buffer)
+static int kgdb_transition_check(char *buffer)
 {
-       int slen = strlen(buffer);
-       if (strncmp(buffer, "$?#3f", slen) != 0 &&
-           strncmp(buffer, "$qSupported#37", slen) != 0 &&
-           strncmp(buffer, "+$qSupported#37", slen) != 0) {
+       if (buffer[0] != '+' && buffer[0] != '$') {
                KDB_STATE_SET(KGDB_TRANS);
                kdb_printf("%s", buffer);
+       } else {
+               int slen = strlen(buffer);
+               if (slen > 3 && buffer[slen - 3] == '#') {
+                       kdb_gdb_state_pass(buffer);
+                       strcpy(buffer, "kgdb");
+                       KDB_STATE_SET(DOING_KGDB);
+                       return 1;
+               }
        }
+       return 0;
 }
 
 static int kdb_read_get_key(char *buffer, size_t bufsize)
@@ -251,6 +257,10 @@ poll_again:
        case 13: /* enter */
                *lastchar++ = '\n';
                *lastchar++ = '\0';
+               if (!KDB_STATE(KGDB_TRANS)) {
+                       KDB_STATE_SET(KGDB_TRANS);
+                       kdb_printf("%s", buffer);
+               }
                kdb_printf("\n");
                return buffer;
        case 4: /* Del */
@@ -382,22 +392,26 @@ poll_again:
                                 * printed characters if we think that
                                 * kgdb is connecting, until the check
                                 * fails */
-                               if (!KDB_STATE(KGDB_TRANS))
-                                       kgdb_transition_check(buffer);
-                               else
+                               if (!KDB_STATE(KGDB_TRANS)) {
+                                       if (kgdb_transition_check(buffer))
+                                               return buffer;
+                               } else {
                                        kdb_printf("%c", key);
+                               }
                        }
                        /* Special escape to kgdb */
                        if (lastchar - buffer >= 5 &&
                            strcmp(lastchar - 5, "$?#3f") == 0) {
+                               kdb_gdb_state_pass(lastchar - 5);
                                strcpy(buffer, "kgdb");
                                KDB_STATE_SET(DOING_KGDB);
                                return buffer;
                        }
-                       if (lastchar - buffer >= 14 &&
-                           strcmp(lastchar - 14, "$qSupported#37") == 0) {
+                       if (lastchar - buffer >= 11 &&
+                           strcmp(lastchar - 11, "$qSupported") == 0) {
+                               kdb_gdb_state_pass(lastchar - 11);
                                strcpy(buffer, "kgdb");
-                               KDB_STATE_SET(DOING_KGDB2);
+                               KDB_STATE_SET(DOING_KGDB);
                                return buffer;
                        }
                }
index be14779..63786e7 100644 (file)
@@ -145,7 +145,6 @@ static char *__env[] = {
 #endif
  "RADIX=16",
  "MDCOUNT=8",                  /* lines of md output */
- "BTARGS=9",                   /* 9 possible args in bt */
  KDB_PLATFORM_ENV,
  "DTABCOUNT=30",
  "NOSECT=1",
@@ -172,6 +171,7 @@ static char *__env[] = {
  (char *)0,
  (char *)0,
  (char *)0,
+ (char *)0,
 };
 
 static const int __nenv = (sizeof(__env) / sizeof(char *));
@@ -1386,7 +1386,7 @@ int kdb_main_loop(kdb_reason_t reason, kdb_reason_t reason2, int error,
                }
 
                if (result == KDB_CMD_KGDB) {
-                       if (!(KDB_STATE(DOING_KGDB) || KDB_STATE(DOING_KGDB2)))
+                       if (!KDB_STATE(DOING_KGDB))
                                kdb_printf("Entering please attach debugger "
                                           "or use $D#44+ or $3#33\n");
                        break;
index 35d69ed..e381d10 100644 (file)
@@ -21,7 +21,6 @@
 #define KDB_CMD_SS     (-1003)
 #define KDB_CMD_SSB    (-1004)
 #define KDB_CMD_KGDB (-1005)
-#define KDB_CMD_KGDB2 (-1006)
 
 /* Internal debug flags */
 #define KDB_DEBUG_FLAG_BP      0x0002  /* Breakpoint subsystem debug */
@@ -146,7 +145,6 @@ extern int kdb_state;
                                                 * keyboard on this cpu */
 #define KDB_STATE_KEXEC                0x00040000      /* kexec issued */
 #define KDB_STATE_DOING_KGDB   0x00080000      /* kgdb enter now issued */
-#define KDB_STATE_DOING_KGDB2  0x00100000      /* kgdb enter now issued */
 #define KDB_STATE_KGDB_TRANS   0x00200000      /* Transition to kgdb */
 #define KDB_STATE_ARCH         0xff000000      /* Reserved for arch
                                                 * specific use */
@@ -218,6 +216,7 @@ extern void kdb_print_nameval(const char *name, unsigned long val);
 extern void kdb_send_sig_info(struct task_struct *p, struct siginfo *info);
 extern void kdb_meminfo_proc_show(void);
 extern char *kdb_getstr(char *, size_t, char *);
+extern void kdb_gdb_state_pass(char *buf);
 
 /* Defines for kdb_symbol_print */
 #define KDB_SP_SPACEB  0x0001          /* Space before string */
index e7ceaca..8e6b6f4 100644 (file)
@@ -1111,6 +1111,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                    p->real_cred->user != INIT_USER)
                        goto bad_fork_free;
        }
+       current->flags &= ~PF_NPROC_EXCEEDED;
 
        retval = copy_creds(p, clone_flags);
        if (retval < 0)
index 0a30897..11cbe05 100644 (file)
@@ -218,6 +218,8 @@ static void drop_futex_key_refs(union futex_key *key)
  * @uaddr:     virtual address of the futex
  * @fshared:   0 for a PROCESS_PRIVATE futex, 1 for PROCESS_SHARED
  * @key:       address where result is stored.
+ * @rw:                mapping needs to be read/write (values: VERIFY_READ,
+ *              VERIFY_WRITE)
  *
  * Returns a negative error code or 0
  * The key words are stored in *key on success.
@@ -229,12 +231,12 @@ static void drop_futex_key_refs(union futex_key *key)
  * lock_page() might sleep, the caller should not hold a spinlock.
  */
 static int
-get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key)
+get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw)
 {
        unsigned long address = (unsigned long)uaddr;
        struct mm_struct *mm = current->mm;
        struct page *page, *page_head;
-       int err;
+       int err, ro = 0;
 
        /*
         * The futex address must be "naturally" aligned.
@@ -262,8 +264,18 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key)
 
 again:
        err = get_user_pages_fast(address, 1, 1, &page);
+       /*
+        * If write access is not required (eg. FUTEX_WAIT), try
+        * and get read-only access.
+        */
+       if (err == -EFAULT && rw == VERIFY_READ) {
+               err = get_user_pages_fast(address, 1, 0, &page);
+               ro = 1;
+       }
        if (err < 0)
                return err;
+       else
+               err = 0;
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
        page_head = page;
@@ -305,6 +317,13 @@ again:
        if (!page_head->mapping) {
                unlock_page(page_head);
                put_page(page_head);
+               /*
+               * ZERO_PAGE pages don't have a mapping. Avoid a busy loop
+               * trying to find one. RW mapping would have COW'd (and thus
+               * have a mapping) so this page is RO and won't ever change.
+               */
+               if ((page_head == ZERO_PAGE(address)))
+                       return -EFAULT;
                goto again;
        }
 
@@ -316,6 +335,15 @@ again:
         * the object not the particular process.
         */
        if (PageAnon(page_head)) {
+               /*
+                * A RO anonymous page will never change and thus doesn't make
+                * sense for futex operations.
+                */
+               if (ro) {
+                       err = -EFAULT;
+                       goto out;
+               }
+
                key->both.offset |= FUT_OFF_MMSHARED; /* ref taken on mm */
                key->private.mm = mm;
                key->private.address = address;
@@ -327,9 +355,10 @@ again:
 
        get_futex_key_refs(key);
 
+out:
        unlock_page(page_head);
        put_page(page_head);
-       return 0;
+       return err;
 }
 
 static inline void put_futex_key(union futex_key *key)
@@ -940,7 +969,7 @@ futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset)
        if (!bitset)
                return -EINVAL;
 
-       ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key);
+       ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key, VERIFY_READ);
        if (unlikely(ret != 0))
                goto out;
 
@@ -986,10 +1015,10 @@ futex_wake_op(u32 __user *uaddr1, unsigned int flags, u32 __user *uaddr2,
        int ret, op_ret;
 
 retry:
-       ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1);
+       ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, VERIFY_READ);
        if (unlikely(ret != 0))
                goto out;
-       ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2);
+       ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2, VERIFY_WRITE);
        if (unlikely(ret != 0))
                goto out_put_key1;
 
@@ -1243,10 +1272,11 @@ retry:
                pi_state = NULL;
        }
 
-       ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1);
+       ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, VERIFY_READ);
        if (unlikely(ret != 0))
                goto out;
-       ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2);
+       ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2,
+                           requeue_pi ? VERIFY_WRITE : VERIFY_READ);
        if (unlikely(ret != 0))
                goto out_put_key1;
 
@@ -1790,7 +1820,7 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,
         * while the syscall executes.
         */
 retry:
-       ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q->key);
+       ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q->key, VERIFY_READ);
        if (unlikely(ret != 0))
                return ret;
 
@@ -1941,7 +1971,7 @@ static int futex_lock_pi(u32 __user *uaddr, unsigned int flags, int detect,
        }
 
 retry:
-       ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q.key);
+       ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q.key, VERIFY_WRITE);
        if (unlikely(ret != 0))
                goto out;
 
@@ -2060,7 +2090,7 @@ retry:
        if ((uval & FUTEX_TID_MASK) != vpid)
                return -EPERM;
 
-       ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key);
+       ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key, VERIFY_WRITE);
        if (unlikely(ret != 0))
                goto out;
 
@@ -2249,7 +2279,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
        debug_rt_mutex_init_waiter(&rt_waiter);
        rt_waiter.task = NULL;
 
-       ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2);
+       ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2, VERIFY_WRITE);
        if (unlikely(ret != 0))
                goto out;
 
index d1d051b..5a38bf4 100644 (file)
@@ -52,6 +52,10 @@ config IRQ_EDGE_EOI_HANDLER
 config GENERIC_IRQ_CHIP
        bool
 
+# Generic irq_domain hw <--> linux irq number translation
+config IRQ_DOMAIN
+       bool
+
 # Support forced irq threading
 config IRQ_FORCED_THREADING
        bool
index 7329005..fff1738 100644 (file)
@@ -2,6 +2,7 @@
 obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o
 obj-$(CONFIG_GENERIC_IRQ_CHIP) += generic-chip.o
 obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o
+obj-$(CONFIG_IRQ_DOMAIN) += irqdomain.o
 obj-$(CONFIG_PROC_FS) += proc.o
 obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o
 obj-$(CONFIG_PM_SLEEP) += pm.o
index 3a2cab4..e38544d 100644 (file)
@@ -246,7 +246,7 @@ void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk,
                gc->mask_cache = irq_reg_readl(gc->reg_base + ct->regs.mask);
 
        for (i = gc->irq_base; msk; msk >>= 1, i++) {
-               if (!msk & 0x01)
+               if (!(msk & 0x01))
                        continue;
 
                if (flags & IRQ_GC_INIT_NESTED_LOCK)
@@ -301,7 +301,7 @@ void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk,
        raw_spin_unlock(&gc_lock);
 
        for (; msk; msk >>= 1, i++) {
-               if (!msk & 0x01)
+               if (!(msk & 0x01))
                        continue;
 
                /* Remove handler first. That will mask the irq line */
index 4c60a50..039b889 100644 (file)
@@ -70,7 +70,8 @@ static inline void desc_smp_init(struct irq_desc *desc, int node) { }
 static inline int desc_node(struct irq_desc *desc) { return 0; }
 #endif
 
-static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node)
+static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node,
+               struct module *owner)
 {
        int cpu;
 
@@ -86,6 +87,7 @@ static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node)
        desc->irq_count = 0;
        desc->irqs_unhandled = 0;
        desc->name = NULL;
+       desc->owner = owner;
        for_each_possible_cpu(cpu)
                *per_cpu_ptr(desc->kstat_irqs, cpu) = 0;
        desc_smp_init(desc, node);
@@ -128,7 +130,7 @@ static void free_masks(struct irq_desc *desc)
 static inline void free_masks(struct irq_desc *desc) { }
 #endif
 
-static struct irq_desc *alloc_desc(int irq, int node)
+static struct irq_desc *alloc_desc(int irq, int node, struct module *owner)
 {
        struct irq_desc *desc;
        gfp_t gfp = GFP_KERNEL;
@@ -147,7 +149,7 @@ static struct irq_desc *alloc_desc(int irq, int node)
        raw_spin_lock_init(&desc->lock);
        lockdep_set_class(&desc->lock, &irq_desc_lock_class);
 
-       desc_set_defaults(irq, desc, node);
+       desc_set_defaults(irq, desc, node, owner);
 
        return desc;
 
@@ -173,13 +175,14 @@ static void free_desc(unsigned int irq)
        kfree(desc);
 }
 
-static int alloc_descs(unsigned int start, unsigned int cnt, int node)
+static int alloc_descs(unsigned int start, unsigned int cnt, int node,
+                      struct module *owner)
 {
        struct irq_desc *desc;
        int i;
 
        for (i = 0; i < cnt; i++) {
-               desc = alloc_desc(start + i, node);
+               desc = alloc_desc(start + i, node, owner);
                if (!desc)
                        goto err;
                mutex_lock(&sparse_irq_lock);
@@ -227,7 +230,7 @@ int __init early_irq_init(void)
                nr_irqs = initcnt;
 
        for (i = 0; i < initcnt; i++) {
-               desc = alloc_desc(i, node);
+               desc = alloc_desc(i, node, NULL);
                set_bit(i, allocated_irqs);
                irq_insert_desc(i, desc);
        }
@@ -261,7 +264,7 @@ int __init early_irq_init(void)
                alloc_masks(&desc[i], GFP_KERNEL, node);
                raw_spin_lock_init(&desc[i].lock);
                lockdep_set_class(&desc[i].lock, &irq_desc_lock_class);
-               desc_set_defaults(i, &desc[i], node);
+               desc_set_defaults(i, &desc[i], node, NULL);
        }
        return arch_early_irq_init();
 }
@@ -276,8 +279,16 @@ static void free_desc(unsigned int irq)
        dynamic_irq_cleanup(irq);
 }
 
-static inline int alloc_descs(unsigned int start, unsigned int cnt, int node)
+static inline int alloc_descs(unsigned int start, unsigned int cnt, int node,
+                             struct module *owner)
 {
+       u32 i;
+
+       for (i = 0; i < cnt; i++) {
+               struct irq_desc *desc = irq_to_desc(start + i);
+
+               desc->owner = owner;
+       }
        return start;
 }
 
@@ -333,11 +344,13 @@ EXPORT_SYMBOL_GPL(irq_free_descs);
  * @from:      Start the search from this irq number
  * @cnt:       Number of consecutive irqs to allocate.
  * @node:      Preferred node on which the irq descriptor should be allocated
+ * @owner:     Owning module (can be NULL)
  *
  * Returns the first irq number or error code
  */
 int __ref
-irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node)
+__irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
+                 struct module *owner)
 {
        int start, ret;
 
@@ -366,13 +379,13 @@ irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node)
 
        bitmap_set(allocated_irqs, start, cnt);
        mutex_unlock(&sparse_irq_lock);
-       return alloc_descs(start, cnt, node);
+       return alloc_descs(start, cnt, node, owner);
 
 err:
        mutex_unlock(&sparse_irq_lock);
        return ret;
 }
-EXPORT_SYMBOL_GPL(irq_alloc_descs);
+EXPORT_SYMBOL_GPL(__irq_alloc_descs);
 
 /**
  * irq_reserve_irqs - mark irqs allocated
@@ -440,7 +453,7 @@ void dynamic_irq_cleanup(unsigned int irq)
        unsigned long flags;
 
        raw_spin_lock_irqsave(&desc->lock, flags);
-       desc_set_defaults(irq, desc, desc_node(desc));
+       desc_set_defaults(irq, desc, desc_node(desc), NULL);
        raw_spin_unlock_irqrestore(&desc->lock, flags);
 }
 
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
new file mode 100644 (file)
index 0000000..d5828da
--- /dev/null
@@ -0,0 +1,180 @@
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+
+static LIST_HEAD(irq_domain_list);
+static DEFINE_MUTEX(irq_domain_mutex);
+
+/**
+ * irq_domain_add() - Register an irq_domain
+ * @domain: ptr to initialized irq_domain structure
+ *
+ * Registers an irq_domain structure.  The irq_domain must at a minimum be
+ * initialized with an ops structure pointer, and either a ->to_irq hook or
+ * a valid irq_base value.  Everything else is optional.
+ */
+void irq_domain_add(struct irq_domain *domain)
+{
+       struct irq_data *d;
+       int hwirq;
+
+       /*
+        * This assumes that the irq_domain owner has already allocated
+        * the irq_descs.  This block will be removed when support for dynamic
+        * allocation of irq_descs is added to irq_domain.
+        */
+       for (hwirq = 0; hwirq < domain->nr_irq; hwirq++) {
+               d = irq_get_irq_data(irq_domain_to_irq(domain, hwirq));
+               if (d || d->domain) {
+                       /* things are broken; just report, don't clean up */
+                       WARN(1, "error: irq_desc already assigned to a domain");
+                       return;
+               }
+               d->domain = domain;
+               d->hwirq = hwirq;
+       }
+
+       mutex_lock(&irq_domain_mutex);
+       list_add(&domain->list, &irq_domain_list);
+       mutex_unlock(&irq_domain_mutex);
+}
+
+/**
+ * irq_domain_del() - Unregister an irq_domain
+ * @domain: ptr to registered irq_domain.
+ */
+void irq_domain_del(struct irq_domain *domain)
+{
+       struct irq_data *d;
+       int hwirq;
+
+       mutex_lock(&irq_domain_mutex);
+       list_del(&domain->list);
+       mutex_unlock(&irq_domain_mutex);
+
+       /* Clear the irq_domain assignments */
+       for (hwirq = 0; hwirq < domain->nr_irq; hwirq++) {
+               d = irq_get_irq_data(irq_domain_to_irq(domain, hwirq));
+               d->domain = NULL;
+       }
+}
+
+#if defined(CONFIG_OF_IRQ)
+/**
+ * irq_create_of_mapping() - Map a linux irq number from a DT interrupt spec
+ *
+ * Used by the device tree interrupt mapping code to translate a device tree
+ * interrupt specifier to a valid linux irq number.  Returns either a valid
+ * linux IRQ number or 0.
+ *
+ * When the caller no longer need the irq number returned by this function it
+ * should arrange to call irq_dispose_mapping().
+ */
+unsigned int irq_create_of_mapping(struct device_node *controller,
+                                  const u32 *intspec, unsigned int intsize)
+{
+       struct irq_domain *domain;
+       unsigned long hwirq;
+       unsigned int irq, type;
+       int rc = -EINVAL;
+
+       /* Find a domain which can translate the irq spec */
+       mutex_lock(&irq_domain_mutex);
+       list_for_each_entry(domain, &irq_domain_list, list) {
+               if (!domain->ops->dt_translate)
+                       continue;
+               rc = domain->ops->dt_translate(domain, controller,
+                                       intspec, intsize, &hwirq, &type);
+               if (rc == 0)
+                       break;
+       }
+       mutex_unlock(&irq_domain_mutex);
+
+       if (rc != 0)
+               return 0;
+
+       irq = irq_domain_to_irq(domain, hwirq);
+       if (type != IRQ_TYPE_NONE)
+               irq_set_irq_type(irq, type);
+       pr_debug("%s: mapped hwirq=%i to irq=%i, flags=%x\n",
+                controller->full_name, (int)hwirq, irq, type);
+       return irq;
+}
+EXPORT_SYMBOL_GPL(irq_create_of_mapping);
+
+/**
+ * irq_dispose_mapping() - Discard a mapping created by irq_create_of_mapping()
+ * @irq: linux irq number to be discarded
+ *
+ * Calling this function indicates the caller no longer needs a reference to
+ * the linux irq number returned by a prior call to irq_create_of_mapping().
+ */
+void irq_dispose_mapping(unsigned int irq)
+{
+       /*
+        * nothing yet; will be filled when support for dynamic allocation of
+        * irq_descs is added to irq_domain
+        */
+}
+EXPORT_SYMBOL_GPL(irq_dispose_mapping);
+
+int irq_domain_simple_dt_translate(struct irq_domain *d,
+                           struct device_node *controller,
+                           const u32 *intspec, unsigned int intsize,
+                           unsigned long *out_hwirq, unsigned int *out_type)
+{
+       if (d->of_node != controller)
+               return -EINVAL;
+       if (intsize < 1)
+               return -EINVAL;
+
+       *out_hwirq = intspec[0];
+       *out_type = IRQ_TYPE_NONE;
+       if (intsize > 1)
+               *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
+       return 0;
+}
+
+struct irq_domain_ops irq_domain_simple_ops = {
+       .dt_translate = irq_domain_simple_dt_translate,
+};
+EXPORT_SYMBOL_GPL(irq_domain_simple_ops);
+
+/**
+ * irq_domain_create_simple() - Set up a 'simple' translation range
+ */
+void irq_domain_add_simple(struct device_node *controller, int irq_base)
+{
+       struct irq_domain *domain;
+
+       domain = kzalloc(sizeof(*domain), GFP_KERNEL);
+       if (!domain) {
+               WARN_ON(1);
+               return;
+       }
+
+       domain->irq_base = irq_base;
+       domain->of_node = of_node_get(controller);
+       domain->ops = &irq_domain_simple_ops;
+       irq_domain_add(domain);
+}
+EXPORT_SYMBOL_GPL(irq_domain_add_simple);
+
+void irq_domain_generate_simple(const struct of_device_id *match,
+                               u64 phys_base, unsigned int irq_start)
+{
+       struct device_node *node;
+       pr_info("looking for phys_base=%llx, irq_start=%i\n",
+               (unsigned long long) phys_base, (int) irq_start);
+       node = of_find_matching_node_by_address(NULL, match, phys_base);
+       if (node)
+               irq_domain_add_simple(node, irq_start);
+       else
+               pr_info("no node found\n");
+}
+EXPORT_SYMBOL_GPL(irq_domain_generate_simple);
+#endif /* CONFIG_OF_IRQ */
index 0a7840a..9b956fa 100644 (file)
@@ -883,6 +883,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
 
        if (desc->irq_data.chip == &no_irq_chip)
                return -ENOSYS;
+       if (!try_module_get(desc->owner))
+               return -ENODEV;
        /*
         * Some drivers like serial.c use request_irq() heavily,
         * so we have to be careful not to interfere with a
@@ -906,8 +908,10 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
         */
        nested = irq_settings_is_nested_thread(desc);
        if (nested) {
-               if (!new->thread_fn)
-                       return -EINVAL;
+               if (!new->thread_fn) {
+                       ret = -EINVAL;
+                       goto out_mput;
+               }
                /*
                 * Replace the primary handler which was provided from
                 * the driver for non nested interrupt handling by the
@@ -929,8 +933,10 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
 
                t = kthread_create(irq_thread, new, "irq/%d-%s", irq,
                                   new->name);
-               if (IS_ERR(t))
-                       return PTR_ERR(t);
+               if (IS_ERR(t)) {
+                       ret = PTR_ERR(t);
+                       goto out_mput;
+               }
                /*
                 * We keep the reference to the task struct even if
                 * the thread dies to avoid that the interrupt code
@@ -1095,6 +1101,8 @@ out_thread:
                        kthread_stop(t);
                put_task_struct(t);
        }
+out_mput:
+       module_put(desc->owner);
        return ret;
 }
 
@@ -1203,6 +1211,7 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
                put_task_struct(action->thread);
        }
 
+       module_put(desc->owner);
        return action;
 }
 
index 47613df..ddc7644 100644 (file)
@@ -274,7 +274,7 @@ static void __call_usermodehelper(struct work_struct *work)
  * (used for preventing user land processes from being created after the user
  * land has been frozen during a system-wide hibernation or suspend operation).
  */
-static int usermodehelper_disabled;
+static int usermodehelper_disabled = 1;
 
 /* Number of helpers running */
 static atomic_t running_helpers = ATOMIC_INIT(0);
index 3956f51..91d67ce 100644 (file)
@@ -2468,7 +2468,7 @@ mark_held_locks(struct task_struct *curr, enum mark_type mark)
 
                BUG_ON(usage_bit >= LOCK_USAGE_STATES);
 
-               if (hlock_class(hlock)->key == &__lockdep_no_validate__)
+               if (hlock_class(hlock)->key == __lockdep_no_validate__.subkeys)
                        continue;
 
                if (!mark_lock(curr, hlock, usage_bit))
@@ -2485,23 +2485,9 @@ static void __trace_hardirqs_on_caller(unsigned long ip)
 {
        struct task_struct *curr = current;
 
-       if (DEBUG_LOCKS_WARN_ON(unlikely(early_boot_irqs_disabled)))
-               return;
-
-       if (unlikely(curr->hardirqs_enabled)) {
-               /*
-                * Neither irq nor preemption are disabled here
-                * so this is racy by nature but losing one hit
-                * in a stat is not a big deal.
-                */
-               __debug_atomic_inc(redundant_hardirqs_on);
-               return;
-       }
        /* we'll do an OFF -> ON transition: */
        curr->hardirqs_enabled = 1;
 
-       if (DEBUG_LOCKS_WARN_ON(current->hardirq_context))
-               return;
        /*
         * We are going to turn hardirqs on, so set the
         * usage bit for all held locks:
@@ -2529,9 +2515,25 @@ void trace_hardirqs_on_caller(unsigned long ip)
        if (unlikely(!debug_locks || current->lockdep_recursion))
                return;
 
+       if (unlikely(current->hardirqs_enabled)) {
+               /*
+                * Neither irq nor preemption are disabled here
+                * so this is racy by nature but losing one hit
+                * in a stat is not a big deal.
+                */
+               __debug_atomic_inc(redundant_hardirqs_on);
+               return;
+       }
+
        if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
                return;
 
+       if (DEBUG_LOCKS_WARN_ON(unlikely(early_boot_irqs_disabled)))
+               return;
+
+       if (DEBUG_LOCKS_WARN_ON(current->hardirq_context))
+               return;
+
        current->lockdep_recursion = 1;
        __trace_hardirqs_on_caller(ip);
        current->lockdep_recursion = 0;
@@ -2872,10 +2874,7 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this,
 void lockdep_init_map(struct lockdep_map *lock, const char *name,
                      struct lock_class_key *key, int subclass)
 {
-       int i;
-
-       for (i = 0; i < NR_LOCKDEP_CACHING_CLASSES; i++)
-               lock->class_cache[i] = NULL;
+       memset(lock, 0, sizeof(*lock));
 
 #ifdef CONFIG_LOCK_STAT
        lock->cpu = raw_smp_processor_id();
@@ -3112,7 +3111,13 @@ static int match_held_lock(struct held_lock *hlock, struct lockdep_map *lock)
                if (!class)
                        class = look_up_lock_class(lock, 0);
 
-               if (DEBUG_LOCKS_WARN_ON(!class))
+               /*
+                * If look_up_lock_class() failed to find a class, we're trying
+                * to test if we hold a lock that has never yet been acquired.
+                * Clearly if the lock hasn't been acquired _ever_, we're not
+                * holding it either, so report failure.
+                */
+               if (!class)
                        return 0;
 
                if (DEBUG_LOCKS_WARN_ON(!hlock->nest_lock))
index b1914cb..3744c59 100644 (file)
@@ -231,3 +231,7 @@ config PM_CLK
 config PM_GENERIC_DOMAINS
        bool
        depends on PM
+
+config PM_GENERIC_DOMAINS_RUNTIME
+       def_bool y
+       depends on PM_RUNTIME && PM_GENERIC_DOMAINS
index 37dff34..836a2ae 100644 (file)
@@ -318,8 +318,10 @@ static int check_syslog_permissions(int type, bool from_file)
                        return 0;
                /* For historical reasons, accept CAP_SYS_ADMIN too, with a warning */
                if (capable(CAP_SYS_ADMIN)) {
-                       WARN_ONCE(1, "Attempt to access syslog with CAP_SYS_ADMIN "
-                                "but no CAP_SYSLOG (deprecated).\n");
+                       printk_once(KERN_WARNING "%s (%d): "
+                                "Attempt to access syslog with CAP_SYS_ADMIN "
+                                "but no CAP_SYSLOG (deprecated).\n",
+                                current->comm, task_pid_nr(current));
                        return 0;
                }
                return -EPERM;
index 3ff4017..3b3cedc 100644 (file)
@@ -553,6 +553,27 @@ int allocate_resource(struct resource *root, struct resource *new,
 
 EXPORT_SYMBOL(allocate_resource);
 
+/**
+ * lookup_resource - find an existing resource by a resource start address
+ * @root: root resource descriptor
+ * @start: resource start address
+ *
+ * Returns a pointer to the resource if found, NULL otherwise
+ */
+struct resource *lookup_resource(struct resource *root, resource_size_t start)
+{
+       struct resource *res;
+
+       read_lock(&resource_lock);
+       for (res = root->child; res; res = res->sibling) {
+               if (res->start == start)
+                       break;
+       }
+       read_unlock(&resource_lock);
+
+       return res;
+}
+
 /*
  * Insert a resource into the resource tree. If successful, return NULL,
  * otherwise return the conflicting resource (compare to __request_resource())
index a101ba3..dd948a1 100644 (file)
@@ -621,11 +621,18 @@ static int set_user(struct cred *new)
        if (!new_user)
                return -EAGAIN;
 
+       /*
+        * We don't fail in case of NPROC limit excess here because too many
+        * poorly written programs don't check set*uid() return code, assuming
+        * it never fails if called by root.  We may still enforce NPROC limit
+        * for programs doing set*uid()+execve() by harmlessly deferring the
+        * failure to the execve() stage.
+        */
        if (atomic_read(&new_user->processes) >= rlimit(RLIMIT_NPROC) &&
-                       new_user != INIT_USER) {
-               free_uid(new_user);
-               return -EAGAIN;
-       }
+                       new_user != INIT_USER)
+               current->flags |= PF_NPROC_EXCEEDED;
+       else
+               current->flags &= ~PF_NPROC_EXCEEDED;
 
        free_uid(new->user);
        new->user = new_user;
index 3b8e028..e8bffbe 100644 (file)
@@ -1,6 +1,6 @@
 #include <linux/stat.h>
 #include <linux/sysctl.h>
-#include "../fs/xfs/linux-2.6/xfs_sysctl.h"
+#include "../fs/xfs/xfs_sysctl.h"
 #include <linux/sunrpc/debug.h>
 #include <linux/string.h>
 #include <net/ip_vs.h>
index 4e4932a..362da65 100644 (file)
@@ -1,6 +1,6 @@
 #include <linux/stat.h>
 #include <linux/sysctl.h>
-#include "../fs/xfs/linux-2.6/xfs_sysctl.h"
+#include "../fs/xfs/xfs_sysctl.h"
 #include <linux/sunrpc/debug.h>
 #include <linux/string.h>
 #include <net/ip_vs.h>
index d1db288..e19ce14 100644 (file)
@@ -291,30 +291,28 @@ static int add_del_listener(pid_t pid, const struct cpumask *mask, int isadd)
        if (!cpumask_subset(mask, cpu_possible_mask))
                return -EINVAL;
 
-       s = NULL;
        if (isadd == REGISTER) {
                for_each_cpu(cpu, mask) {
-                       if (!s)
-                               s = kmalloc_node(sizeof(struct listener),
-                                                GFP_KERNEL, cpu_to_node(cpu));
+                       s = kmalloc_node(sizeof(struct listener),
+                                       GFP_KERNEL, cpu_to_node(cpu));
                        if (!s)
                                goto cleanup;
+
                        s->pid = pid;
-                       INIT_LIST_HEAD(&s->list);
                        s->valid = 1;
 
                        listeners = &per_cpu(listener_array, cpu);
                        down_write(&listeners->sem);
-                       list_for_each_entry_safe(s2, tmp, &listeners->list, list) {
-                               if (s2->pid == pid)
-                                       goto next_cpu;
+                       list_for_each_entry(s2, &listeners->list, list) {
+                               if (s2->pid == pid && s2->valid)
+                                       goto exists;
                        }
                        list_add(&s->list, &listeners->list);
                        s = NULL;
-next_cpu:
+exists:
                        up_write(&listeners->sem);
+                       kfree(s); /* nop if NULL */
                }
-               kfree(s);
                return 0;
        }
 
index 2ad39e5..cd31345 100644 (file)
@@ -82,7 +82,7 @@ config EVENT_POWER_TRACING_DEPRECATED
          power:power_frequency
          This is for userspace compatibility
          and will vanish after 5 kernel iterations,
-         namely 2.6.41.
+         namely 3.1.
 
 config CONTEXT_SWITCH_TRACER
        bool
index 6957aa2..7c910a5 100644 (file)
@@ -206,6 +206,8 @@ static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,
        what |= MASK_TC_BIT(rw, RAHEAD);
        what |= MASK_TC_BIT(rw, META);
        what |= MASK_TC_BIT(rw, DISCARD);
+       what |= MASK_TC_BIT(rw, FLUSH);
+       what |= MASK_TC_BIT(rw, FUA);
 
        pid = tsk->pid;
        if (act_log_check(bt, what, sector, pid))
@@ -1054,6 +1056,9 @@ static void fill_rwbs(char *rwbs, const struct blk_io_trace *t)
                goto out;
        }
 
+       if (tc & BLK_TC_FLUSH)
+               rwbs[i++] = 'F';
+
        if (tc & BLK_TC_DISCARD)
                rwbs[i++] = 'D';
        else if (tc & BLK_TC_WRITE)
@@ -1063,10 +1068,10 @@ static void fill_rwbs(char *rwbs, const struct blk_io_trace *t)
        else
                rwbs[i++] = 'N';
 
+       if (tc & BLK_TC_FUA)
+               rwbs[i++] = 'F';
        if (tc & BLK_TC_AHEAD)
                rwbs[i++] = 'A';
-       if (tc & BLK_TC_BARRIER)
-               rwbs[i++] = 'B';
        if (tc & BLK_TC_SYNC)
                rwbs[i++] = 'S';
        if (tc & BLK_TC_META)
@@ -1132,7 +1137,7 @@ typedef int (blk_log_action_t) (struct trace_iterator *iter, const char *act);
 
 static int blk_log_action_classic(struct trace_iterator *iter, const char *act)
 {
-       char rwbs[6];
+       char rwbs[RWBS_LEN];
        unsigned long long ts  = iter->ts;
        unsigned long nsec_rem = do_div(ts, NSEC_PER_SEC);
        unsigned secs          = (unsigned long)ts;
@@ -1148,7 +1153,7 @@ static int blk_log_action_classic(struct trace_iterator *iter, const char *act)
 
 static int blk_log_action(struct trace_iterator *iter, const char *act)
 {
-       char rwbs[6];
+       char rwbs[RWBS_LEN];
        const struct blk_io_trace *t = te_blk_io_trace(iter->ent);
 
        fill_rwbs(rwbs, t);
@@ -1561,7 +1566,7 @@ static const struct {
 } mask_maps[] = {
        { BLK_TC_READ,          "read"          },
        { BLK_TC_WRITE,         "write"         },
-       { BLK_TC_BARRIER,       "barrier"       },
+       { BLK_TC_FLUSH,         "flush"         },
        { BLK_TC_SYNC,          "sync"          },
        { BLK_TC_QUEUE,         "queue"         },
        { BLK_TC_REQUEUE,       "requeue"       },
@@ -1573,6 +1578,7 @@ static const struct {
        { BLK_TC_META,          "meta"          },
        { BLK_TC_DISCARD,       "discard"       },
        { BLK_TC_DRV_DATA,      "drv_data"      },
+       { BLK_TC_FUA,           "fua"           },
 };
 
 static int blk_trace_str2mask(const char *str)
@@ -1788,6 +1794,9 @@ void blk_fill_rwbs(char *rwbs, u32 rw, int bytes)
 {
        int i = 0;
 
+       if (rw & REQ_FLUSH)
+               rwbs[i++] = 'F';
+
        if (rw & WRITE)
                rwbs[i++] = 'W';
        else if (rw & REQ_DISCARD)
@@ -1797,6 +1806,8 @@ void blk_fill_rwbs(char *rwbs, u32 rw, int bytes)
        else
                rwbs[i++] = 'N';
 
+       if (rw & REQ_FUA)
+               rwbs[i++] = 'F';
        if (rw & REQ_RAHEAD)
                rwbs[i++] = 'A';
        if (rw & REQ_SYNC)
index 32f3e5a..6c695ff 100644 (file)
@@ -276,4 +276,7 @@ config CORDIC
          so its calculations are in fixed point. Modules can select this
          when they require this function. Module will be called cordic.
 
+config LLIST
+       bool
+
 endmenu
index 892f4e2..d5d175c 100644 (file)
@@ -10,7 +10,7 @@ endif
 lib-y := ctype.o string.o vsprintf.o cmdline.o \
         rbtree.o radix-tree.o dump_stack.o timerqueue.o\
         idr.o int_sqrt.o extable.o prio_tree.o \
-        sha1.o irq_regs.o reciprocal_div.o argv_split.o \
+        sha1.o md5.o irq_regs.o reciprocal_div.o argv_split.o \
         proportions.o prio_heap.o ratelimit.o show_mem.o \
         is_single_threaded.o plist.o decompress.o find_next_bit.o
 
@@ -115,6 +115,8 @@ obj-$(CONFIG_CPU_RMAP) += cpu_rmap.o
 
 obj-$(CONFIG_CORDIC) += cordic.o
 
+obj-$(CONFIG_LLIST) += llist.o
+
 hostprogs-y    := gen_crc32table
 clean-files    := crc32table.h
 
index 37ef4b0..2f4412e 100644 (file)
@@ -271,8 +271,6 @@ int __bitmap_weight(const unsigned long *bitmap, int bits)
 }
 EXPORT_SYMBOL(__bitmap_weight);
 
-#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) % BITS_PER_LONG))
-
 void bitmap_set(unsigned long *map, int start, int nr)
 {
        unsigned long *p = map + BIT_WORD(start);
index 2577b12..f193b77 100644 (file)
@@ -197,21 +197,15 @@ static struct dentry *debugfs_create_atomic_t(const char *name, mode_t mode,
        return debugfs_create_file(name, mode, parent, value, &fops_atomic_t);
 }
 
-void cleanup_fault_attr_dentries(struct fault_attr *attr)
-{
-       debugfs_remove_recursive(attr->dir);
-}
-
-int init_fault_attr_dentries(struct fault_attr *attr, const char *name)
+struct dentry *fault_create_debugfs_attr(const char *name,
+                       struct dentry *parent, struct fault_attr *attr)
 {
        mode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
        struct dentry *dir;
 
-       dir = debugfs_create_dir(name, NULL);
+       dir = debugfs_create_dir(name, parent);
        if (!dir)
-               return -ENOMEM;
-
-       attr->dir = dir;
+               return ERR_PTR(-ENOMEM);
 
        if (!debugfs_create_ul("probability", mode, dir, &attr->probability))
                goto fail;
@@ -243,11 +237,11 @@ int init_fault_attr_dentries(struct fault_attr *attr, const char *name)
 
 #endif /* CONFIG_FAULT_INJECTION_STACKTRACE_FILTER */
 
-       return 0;
+       return dir;
 fail:
-       debugfs_remove_recursive(attr->dir);
+       debugfs_remove_recursive(dir);
 
-       return -ENOMEM;
+       return ERR_PTR(-ENOMEM);
 }
 
 #endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
index 577ddf8..f352cc4 100644 (file)
@@ -1,8 +1,26 @@
 /*
- * Basic general purpose allocator for managing special purpose memory
- * not managed by the regular kmalloc/kfree interface.
- * Uses for this includes on-device special memory, uncached memory
- * etc.
+ * Basic general purpose allocator for managing special purpose
+ * memory, for example, memory that is not managed by the regular
+ * kmalloc/kfree interface.  Uses for this includes on-device special
+ * memory, uncached memory etc.
+ *
+ * It is safe to use the allocator in NMI handlers and other special
+ * unblockable contexts that could otherwise deadlock on locks.  This
+ * is implemented by using atomic operations and retries on any
+ * conflicts.  The disadvantage is that there may be livelocks in
+ * extreme cases.  For better scalability, one allocator can be used
+ * for each CPU.
+ *
+ * The lockless operation only works if there is enough memory
+ * available.  If new memory is added to the pool a lock has to be
+ * still taken.  So any user relying on locklessness has to ensure
+ * that sufficient memory is preallocated.
+ *
+ * The basic atomic operation of this allocator is cmpxchg on long.
+ * On architectures that don't have NMI-safe cmpxchg implementation,
+ * the allocator can NOT be used in NMI handler.  So code uses the
+ * allocator in NMI handler should depend on
+ * CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG.
  *
  * Copyright 2005 (C) Jes Sorensen <jes@trained-monkey.org>
  *
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/bitmap.h>
+#include <linux/rculist.h>
+#include <linux/interrupt.h>
 #include <linux/genalloc.h>
 
+static int set_bits_ll(unsigned long *addr, unsigned long mask_to_set)
+{
+       unsigned long val, nval;
+
+       nval = *addr;
+       do {
+               val = nval;
+               if (val & mask_to_set)
+                       return -EBUSY;
+               cpu_relax();
+       } while ((nval = cmpxchg(addr, val, val | mask_to_set)) != val);
+
+       return 0;
+}
+
+static int clear_bits_ll(unsigned long *addr, unsigned long mask_to_clear)
+{
+       unsigned long val, nval;
+
+       nval = *addr;
+       do {
+               val = nval;
+               if ((val & mask_to_clear) != mask_to_clear)
+                       return -EBUSY;
+               cpu_relax();
+       } while ((nval = cmpxchg(addr, val, val & ~mask_to_clear)) != val);
+
+       return 0;
+}
+
+/*
+ * bitmap_set_ll - set the specified number of bits at the specified position
+ * @map: pointer to a bitmap
+ * @start: a bit position in @map
+ * @nr: number of bits to set
+ *
+ * Set @nr bits start from @start in @map lock-lessly. Several users
+ * can set/clear the same bitmap simultaneously without lock. If two
+ * users set the same bit, one user will return remain bits, otherwise
+ * return 0.
+ */
+static int bitmap_set_ll(unsigned long *map, int start, int nr)
+{
+       unsigned long *p = map + BIT_WORD(start);
+       const int size = start + nr;
+       int bits_to_set = BITS_PER_LONG - (start % BITS_PER_LONG);
+       unsigned long mask_to_set = BITMAP_FIRST_WORD_MASK(start);
+
+       while (nr - bits_to_set >= 0) {
+               if (set_bits_ll(p, mask_to_set))
+                       return nr;
+               nr -= bits_to_set;
+               bits_to_set = BITS_PER_LONG;
+               mask_to_set = ~0UL;
+               p++;
+       }
+       if (nr) {
+               mask_to_set &= BITMAP_LAST_WORD_MASK(size);
+               if (set_bits_ll(p, mask_to_set))
+                       return nr;
+       }
+
+       return 0;
+}
+
+/*
+ * bitmap_clear_ll - clear the specified number of bits at the specified position
+ * @map: pointer to a bitmap
+ * @start: a bit position in @map
+ * @nr: number of bits to set
+ *
+ * Clear @nr bits start from @start in @map lock-lessly. Several users
+ * can set/clear the same bitmap simultaneously without lock. If two
+ * users clear the same bit, one user will return remain bits,
+ * otherwise return 0.
+ */
+static int bitmap_clear_ll(unsigned long *map, int start, int nr)
+{
+       unsigned long *p = map + BIT_WORD(start);
+       const int size = start + nr;
+       int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG);
+       unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start);
+
+       while (nr - bits_to_clear >= 0) {
+               if (clear_bits_ll(p, mask_to_clear))
+                       return nr;
+               nr -= bits_to_clear;
+               bits_to_clear = BITS_PER_LONG;
+               mask_to_clear = ~0UL;
+               p++;
+       }
+       if (nr) {
+               mask_to_clear &= BITMAP_LAST_WORD_MASK(size);
+               if (clear_bits_ll(p, mask_to_clear))
+                       return nr;
+       }
+
+       return 0;
+}
 
 /**
  * gen_pool_create - create a new special memory pool
@@ -30,7 +149,7 @@ struct gen_pool *gen_pool_create(int min_alloc_order, int nid)
 
        pool = kmalloc_node(sizeof(struct gen_pool), GFP_KERNEL, nid);
        if (pool != NULL) {
-               rwlock_init(&pool->lock);
+               spin_lock_init(&pool->lock);
                INIT_LIST_HEAD(&pool->chunks);
                pool->min_alloc_order = min_alloc_order;
        }
@@ -63,14 +182,14 @@ int gen_pool_add_virt(struct gen_pool *pool, unsigned long virt, phys_addr_t phy
        if (unlikely(chunk == NULL))
                return -ENOMEM;
 
-       spin_lock_init(&chunk->lock);
        chunk->phys_addr = phys;
        chunk->start_addr = virt;
        chunk->end_addr = virt + size;
+       atomic_set(&chunk->avail, size);
 
-       write_lock(&pool->lock);
-       list_add(&chunk->next_chunk, &pool->chunks);
-       write_unlock(&pool->lock);
+       spin_lock(&pool->lock);
+       list_add_rcu(&chunk->next_chunk, &pool->chunks);
+       spin_unlock(&pool->lock);
 
        return 0;
 }
@@ -85,19 +204,19 @@ EXPORT_SYMBOL(gen_pool_add_virt);
  */
 phys_addr_t gen_pool_virt_to_phys(struct gen_pool *pool, unsigned long addr)
 {
-       struct list_head *_chunk;
        struct gen_pool_chunk *chunk;
+       phys_addr_t paddr = -1;
 
-       read_lock(&pool->lock);
-       list_for_each(_chunk, &pool->chunks) {
-               chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk);
-
-               if (addr >= chunk->start_addr && addr < chunk->end_addr)
-                       return chunk->phys_addr + addr - chunk->start_addr;
+       rcu_read_lock();
+       list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) {
+               if (addr >= chunk->start_addr && addr < chunk->end_addr) {
+                       paddr = chunk->phys_addr + (addr - chunk->start_addr);
+                       break;
+               }
        }
-       read_unlock(&pool->lock);
+       rcu_read_unlock();
 
-       return -1;
+       return paddr;
 }
 EXPORT_SYMBOL(gen_pool_virt_to_phys);
 
@@ -115,7 +234,6 @@ void gen_pool_destroy(struct gen_pool *pool)
        int order = pool->min_alloc_order;
        int bit, end_bit;
 
-
        list_for_each_safe(_chunk, _next_chunk, &pool->chunks) {
                chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk);
                list_del(&chunk->next_chunk);
@@ -137,44 +255,50 @@ EXPORT_SYMBOL(gen_pool_destroy);
  * @size: number of bytes to allocate from the pool
  *
  * Allocate the requested number of bytes from the specified pool.
- * Uses a first-fit algorithm.
+ * Uses a first-fit algorithm. Can not be used in NMI handler on
+ * architectures without NMI-safe cmpxchg implementation.
  */
 unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size)
 {
-       struct list_head *_chunk;
        struct gen_pool_chunk *chunk;
-       unsigned long addr, flags;
+       unsigned long addr = 0;
        int order = pool->min_alloc_order;
-       int nbits, start_bit, end_bit;
+       int nbits, start_bit = 0, end_bit, remain;
+
+#ifndef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
+       BUG_ON(in_nmi());
+#endif
 
        if (size == 0)
                return 0;
 
        nbits = (size + (1UL << order) - 1) >> order;
-
-       read_lock(&pool->lock);
-       list_for_each(_chunk, &pool->chunks) {
-               chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk);
+       rcu_read_lock();
+       list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) {
+               if (size > atomic_read(&chunk->avail))
+                       continue;
 
                end_bit = (chunk->end_addr - chunk->start_addr) >> order;
-
-               spin_lock_irqsave(&chunk->lock, flags);
-               start_bit = bitmap_find_next_zero_area(chunk->bits, end_bit, 0,
-                                               nbits, 0);
-               if (start_bit >= end_bit) {
-                       spin_unlock_irqrestore(&chunk->lock, flags);
+retry:
+               start_bit = bitmap_find_next_zero_area(chunk->bits, end_bit,
+                                                      start_bit, nbits, 0);
+               if (start_bit >= end_bit)
                        continue;
+               remain = bitmap_set_ll(chunk->bits, start_bit, nbits);
+               if (remain) {
+                       remain = bitmap_clear_ll(chunk->bits, start_bit,
+                                                nbits - remain);
+                       BUG_ON(remain);
+                       goto retry;
                }
 
                addr = chunk->start_addr + ((unsigned long)start_bit << order);
-
-               bitmap_set(chunk->bits, start_bit, nbits);
-               spin_unlock_irqrestore(&chunk->lock, flags);
-               read_unlock(&pool->lock);
-               return addr;
+               size = nbits << order;
+               atomic_sub(size, &chunk->avail);
+               break;
        }
-       read_unlock(&pool->lock);
-       return 0;
+       rcu_read_unlock();
+       return addr;
 }
 EXPORT_SYMBOL(gen_pool_alloc);
 
@@ -184,33 +308,95 @@ EXPORT_SYMBOL(gen_pool_alloc);
  * @addr: starting address of memory to free back to pool
  * @size: size in bytes of memory to free
  *
- * Free previously allocated special memory back to the specified pool.
+ * Free previously allocated special memory back to the specified
+ * pool.  Can not be used in NMI handler on architectures without
+ * NMI-safe cmpxchg implementation.
  */
 void gen_pool_free(struct gen_pool *pool, unsigned long addr, size_t size)
 {
-       struct list_head *_chunk;
        struct gen_pool_chunk *chunk;
-       unsigned long flags;
        int order = pool->min_alloc_order;
-       int bit, nbits;
+       int start_bit, nbits, remain;
 
-       nbits = (size + (1UL << order) - 1) >> order;
-
-       read_lock(&pool->lock);
-       list_for_each(_chunk, &pool->chunks) {
-               chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk);
+#ifndef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
+       BUG_ON(in_nmi());
+#endif
 
+       nbits = (size + (1UL << order) - 1) >> order;
+       rcu_read_lock();
+       list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) {
                if (addr >= chunk->start_addr && addr < chunk->end_addr) {
                        BUG_ON(addr + size > chunk->end_addr);
-                       spin_lock_irqsave(&chunk->lock, flags);
-                       bit = (addr - chunk->start_addr) >> order;
-                       while (nbits--)
-                               __clear_bit(bit++, chunk->bits);
-                       spin_unlock_irqrestore(&chunk->lock, flags);
-                       break;
+                       start_bit = (addr - chunk->start_addr) >> order;
+                       remain = bitmap_clear_ll(chunk->bits, start_bit, nbits);
+                       BUG_ON(remain);
+                       size = nbits << order;
+                       atomic_add(size, &chunk->avail);
+                       rcu_read_unlock();
+                       return;
                }
        }
-       BUG_ON(nbits > 0);
-       read_unlock(&pool->lock);
+       rcu_read_unlock();
+       BUG();
 }
 EXPORT_SYMBOL(gen_pool_free);
+
+/**
+ * gen_pool_for_each_chunk - call func for every chunk of generic memory pool
+ * @pool:      the generic memory pool
+ * @func:      func to call
+ * @data:      additional data used by @func
+ *
+ * Call @func for every chunk of generic memory pool.  The @func is
+ * called with rcu_read_lock held.
+ */
+void gen_pool_for_each_chunk(struct gen_pool *pool,
+       void (*func)(struct gen_pool *pool, struct gen_pool_chunk *chunk, void *data),
+       void *data)
+{
+       struct gen_pool_chunk *chunk;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(chunk, &(pool)->chunks, next_chunk)
+               func(pool, chunk, data);
+       rcu_read_unlock();
+}
+EXPORT_SYMBOL(gen_pool_for_each_chunk);
+
+/**
+ * gen_pool_avail - get available free space of the pool
+ * @pool: pool to get available free space
+ *
+ * Return available free space of the specified pool.
+ */
+size_t gen_pool_avail(struct gen_pool *pool)
+{
+       struct gen_pool_chunk *chunk;
+       size_t avail = 0;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk)
+               avail += atomic_read(&chunk->avail);
+       rcu_read_unlock();
+       return avail;
+}
+EXPORT_SYMBOL_GPL(gen_pool_avail);
+
+/**
+ * gen_pool_size - get size in bytes of memory managed by the pool
+ * @pool: pool to get size
+ *
+ * Return size in bytes of memory managed by the pool.
+ */
+size_t gen_pool_size(struct gen_pool *pool)
+{
+       struct gen_pool_chunk *chunk;
+       size_t size = 0;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk)
+               size += chunk->end_addr - chunk->start_addr;
+       rcu_read_unlock();
+       return size;
+}
+EXPORT_SYMBOL_GPL(gen_pool_size);
index e15502e..db040ce 100644 (file)
--- a/lib/idr.c
+++ b/lib/idr.c
 #include <linux/err.h>
 #include <linux/string.h>
 #include <linux/idr.h>
+#include <linux/spinlock.h>
 
 static struct kmem_cache *idr_layer_cache;
+static DEFINE_SPINLOCK(simple_ida_lock);
 
 static struct idr_layer *get_from_free_list(struct idr *idp)
 {
@@ -925,6 +927,71 @@ void ida_destroy(struct ida *ida)
 }
 EXPORT_SYMBOL(ida_destroy);
 
+/**
+ * ida_simple_get - get a new id.
+ * @ida: the (initialized) ida.
+ * @start: the minimum id (inclusive, < 0x8000000)
+ * @end: the maximum id (exclusive, < 0x8000000 or 0)
+ * @gfp_mask: memory allocation flags
+ *
+ * Allocates an id in the range start <= id < end, or returns -ENOSPC.
+ * On memory allocation failure, returns -ENOMEM.
+ *
+ * Use ida_simple_remove() to get rid of an id.
+ */
+int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end,
+                  gfp_t gfp_mask)
+{
+       int ret, id;
+       unsigned int max;
+
+       BUG_ON((int)start < 0);
+       BUG_ON((int)end < 0);
+
+       if (end == 0)
+               max = 0x80000000;
+       else {
+               BUG_ON(end < start);
+               max = end - 1;
+       }
+
+again:
+       if (!ida_pre_get(ida, gfp_mask))
+               return -ENOMEM;
+
+       spin_lock(&simple_ida_lock);
+       ret = ida_get_new_above(ida, start, &id);
+       if (!ret) {
+               if (id > max) {
+                       ida_remove(ida, id);
+                       ret = -ENOSPC;
+               } else {
+                       ret = id;
+               }
+       }
+       spin_unlock(&simple_ida_lock);
+
+       if (unlikely(ret == -EAGAIN))
+               goto again;
+
+       return ret;
+}
+EXPORT_SYMBOL(ida_simple_get);
+
+/**
+ * ida_simple_remove - remove an allocated id.
+ * @ida: the (initialized) ida.
+ * @id: the id returned by ida_simple_get.
+ */
+void ida_simple_remove(struct ida *ida, unsigned int id)
+{
+       BUG_ON((int)id < 0);
+       spin_lock(&simple_ida_lock);
+       ida_remove(ida, id);
+       spin_unlock(&simple_ida_lock);
+}
+EXPORT_SYMBOL(ida_simple_remove);
+
 /**
  * ida_init - initialize ida handle
  * @ida:       ida handle
diff --git a/lib/llist.c b/lib/llist.c
new file mode 100644 (file)
index 0000000..da44572
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Lock-less NULL terminated single linked list
+ *
+ * The basic atomic operation of this list is cmpxchg on long.  On
+ * architectures that don't have NMI-safe cmpxchg implementation, the
+ * list can NOT be used in NMI handler.  So code uses the list in NMI
+ * handler should depend on CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG.
+ *
+ * Copyright 2010,2011 Intel Corp.
+ *   Author: Huang Ying <ying.huang@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/llist.h>
+
+#include <asm/system.h>
+
+/**
+ * llist_add - add a new entry
+ * @new:       new entry to be added
+ * @head:      the head for your lock-less list
+ */
+void llist_add(struct llist_node *new, struct llist_head *head)
+{
+       struct llist_node *entry, *old_entry;
+
+#ifndef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
+       BUG_ON(in_nmi());
+#endif
+
+       entry = head->first;
+       do {
+               old_entry = entry;
+               new->next = entry;
+               cpu_relax();
+       } while ((entry = cmpxchg(&head->first, old_entry, new)) != old_entry);
+}
+EXPORT_SYMBOL_GPL(llist_add);
+
+/**
+ * llist_add_batch - add several linked entries in batch
+ * @new_first: first entry in batch to be added
+ * @new_last:  last entry in batch to be added
+ * @head:      the head for your lock-less list
+ */
+void llist_add_batch(struct llist_node *new_first, struct llist_node *new_last,
+                    struct llist_head *head)
+{
+       struct llist_node *entry, *old_entry;
+
+#ifndef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
+       BUG_ON(in_nmi());
+#endif
+
+       entry = head->first;
+       do {
+               old_entry = entry;
+               new_last->next = entry;
+               cpu_relax();
+       } while ((entry = cmpxchg(&head->first, old_entry, new_first)) != old_entry);
+}
+EXPORT_SYMBOL_GPL(llist_add_batch);
+
+/**
+ * llist_del_first - delete the first entry of lock-less list
+ * @head:      the head for your lock-less list
+ *
+ * If list is empty, return NULL, otherwise, return the first entry
+ * deleted, this is the newest added one.
+ *
+ * Only one llist_del_first user can be used simultaneously with
+ * multiple llist_add users without lock.  Because otherwise
+ * llist_del_first, llist_add, llist_add (or llist_del_all, llist_add,
+ * llist_add) sequence in another user may change @head->first->next,
+ * but keep @head->first.  If multiple consumers are needed, please
+ * use llist_del_all or use lock between consumers.
+ */
+struct llist_node *llist_del_first(struct llist_head *head)
+{
+       struct llist_node *entry, *old_entry, *next;
+
+#ifndef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
+       BUG_ON(in_nmi());
+#endif
+
+       entry = head->first;
+       do {
+               if (entry == NULL)
+                       return NULL;
+               old_entry = entry;
+               next = entry->next;
+               cpu_relax();
+       } while ((entry = cmpxchg(&head->first, old_entry, next)) != old_entry);
+
+       return entry;
+}
+EXPORT_SYMBOL_GPL(llist_del_first);
+
+/**
+ * llist_del_all - delete all entries from lock-less list
+ * @head:      the head of lock-less list to delete all entries
+ *
+ * If list is empty, return NULL, otherwise, delete all entries and
+ * return the pointer to the first entry.  The order of entries
+ * deleted is from the newest to the oldest added one.
+ */
+struct llist_node *llist_del_all(struct llist_head *head)
+{
+#ifndef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
+       BUG_ON(in_nmi());
+#endif
+
+       return xchg(&head->first, NULL);
+}
+EXPORT_SYMBOL_GPL(llist_del_all);
diff --git a/lib/md5.c b/lib/md5.c
new file mode 100644 (file)
index 0000000..c777180
--- /dev/null
+++ b/lib/md5.c
@@ -0,0 +1,95 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/cryptohash.h>
+
+#define F1(x, y, z)    (z ^ (x & (y ^ z)))
+#define F2(x, y, z)    F1(z, x, y)
+#define F3(x, y, z)    (x ^ y ^ z)
+#define F4(x, y, z)    (y ^ (x | ~z))
+
+#define MD5STEP(f, w, x, y, z, in, s) \
+       (w += f(x, y, z) + in, w = (w<<s | w>>(32-s)) + x)
+
+void md5_transform(__u32 *hash, __u32 const *in)
+{
+       u32 a, b, c, d;
+
+       a = hash[0];
+       b = hash[1];
+       c = hash[2];
+       d = hash[3];
+
+       MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+       MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+       MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+       MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+       MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+       MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+       MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+       MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+       MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+       MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+       MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+       MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+       MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+       MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+       MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+       MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+       MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+       MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+       MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+       MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+       MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+       MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+       MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+       MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+       MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+       MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+       MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+       MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+       MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+       MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+       MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+       MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+       MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+       MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+       MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+       MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+       MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+       MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+       MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+       MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+       MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+       MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+       MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+       MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+       MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+       MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+       MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+       MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+       MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+       MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+       MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+       MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+       MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+       MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+       MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+       MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+       MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+       MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+       MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+       MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+       MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+       MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+       MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+       MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+       hash[0] += a;
+       hash[1] += b;
+       hash[2] += c;
+       hash[3] += d;
+}
+EXPORT_SYMBOL(md5_transform);
index 7ea2e03..a2f9da5 100644 (file)
@@ -823,8 +823,8 @@ unsigned long radix_tree_prev_hole(struct radix_tree_root *root,
 EXPORT_SYMBOL(radix_tree_prev_hole);
 
 static unsigned int
-__lookup(struct radix_tree_node *slot, void ***results, unsigned long index,
-       unsigned int max_items, unsigned long *next_index)
+__lookup(struct radix_tree_node *slot, void ***results, unsigned long *indices,
+       unsigned long index, unsigned int max_items, unsigned long *next_index)
 {
        unsigned int nr_found = 0;
        unsigned int shift, height;
@@ -857,12 +857,16 @@ __lookup(struct radix_tree_node *slot, void ***results, unsigned long index,
 
        /* Bottom level: grab some items */
        for (i = index & RADIX_TREE_MAP_MASK; i < RADIX_TREE_MAP_SIZE; i++) {
-               index++;
                if (slot->slots[i]) {
-                       results[nr_found++] = &(slot->slots[i]);
-                       if (nr_found == max_items)
+                       results[nr_found] = &(slot->slots[i]);
+                       if (indices)
+                               indices[nr_found] = index;
+                       if (++nr_found == max_items) {
+                               index++;
                                goto out;
+                       }
                }
+               index++;
        }
 out:
        *next_index = index;
@@ -918,8 +922,8 @@ radix_tree_gang_lookup(struct radix_tree_root *root, void **results,
 
                if (cur_index > max_index)
                        break;
-               slots_found = __lookup(node, (void ***)results + ret, cur_index,
-                                       max_items - ret, &next_index);
+               slots_found = __lookup(node, (void ***)results + ret, NULL,
+                               cur_index, max_items - ret, &next_index);
                nr_found = 0;
                for (i = 0; i < slots_found; i++) {
                        struct radix_tree_node *slot;
@@ -944,6 +948,7 @@ EXPORT_SYMBOL(radix_tree_gang_lookup);
  *     radix_tree_gang_lookup_slot - perform multiple slot lookup on radix tree
  *     @root:          radix tree root
  *     @results:       where the results of the lookup are placed
+ *     @indices:       where their indices should be placed (but usually NULL)
  *     @first_index:   start the lookup from this key
  *     @max_items:     place up to this many items at *results
  *
@@ -958,7 +963,8 @@ EXPORT_SYMBOL(radix_tree_gang_lookup);
  *     protection, radix_tree_deref_slot may fail requiring a retry.
  */
 unsigned int
-radix_tree_gang_lookup_slot(struct radix_tree_root *root, void ***results,
+radix_tree_gang_lookup_slot(struct radix_tree_root *root,
+                       void ***results, unsigned long *indices,
                        unsigned long first_index, unsigned int max_items)
 {
        unsigned long max_index;
@@ -974,6 +980,8 @@ radix_tree_gang_lookup_slot(struct radix_tree_root *root, void ***results,
                if (first_index > 0)
                        return 0;
                results[0] = (void **)&root->rnode;
+               if (indices)
+                       indices[0] = 0;
                return 1;
        }
        node = indirect_to_ptr(node);
@@ -987,8 +995,9 @@ radix_tree_gang_lookup_slot(struct radix_tree_root *root, void ***results,
 
                if (cur_index > max_index)
                        break;
-               slots_found = __lookup(node, results + ret, cur_index,
-                                       max_items - ret, &next_index);
+               slots_found = __lookup(node, results + ret,
+                               indices ? indices + ret : NULL,
+                               cur_index, max_items - ret, &next_index);
                ret += slots_found;
                if (next_index == 0)
                        break;
@@ -1194,6 +1203,98 @@ radix_tree_gang_lookup_tag_slot(struct radix_tree_root *root, void ***results,
 }
 EXPORT_SYMBOL(radix_tree_gang_lookup_tag_slot);
 
+#if defined(CONFIG_SHMEM) && defined(CONFIG_SWAP)
+#include <linux/sched.h> /* for cond_resched() */
+
+/*
+ * This linear search is at present only useful to shmem_unuse_inode().
+ */
+static unsigned long __locate(struct radix_tree_node *slot, void *item,
+                             unsigned long index, unsigned long *found_index)
+{
+       unsigned int shift, height;
+       unsigned long i;
+
+       height = slot->height;
+       shift = (height-1) * RADIX_TREE_MAP_SHIFT;
+
+       for ( ; height > 1; height--) {
+               i = (index >> shift) & RADIX_TREE_MAP_MASK;
+               for (;;) {
+                       if (slot->slots[i] != NULL)
+                               break;
+                       index &= ~((1UL << shift) - 1);
+                       index += 1UL << shift;
+                       if (index == 0)
+                               goto out;       /* 32-bit wraparound */
+                       i++;
+                       if (i == RADIX_TREE_MAP_SIZE)
+                               goto out;
+               }
+
+               shift -= RADIX_TREE_MAP_SHIFT;
+               slot = rcu_dereference_raw(slot->slots[i]);
+               if (slot == NULL)
+                       goto out;
+       }
+
+       /* Bottom level: check items */
+       for (i = 0; i < RADIX_TREE_MAP_SIZE; i++) {
+               if (slot->slots[i] == item) {
+                       *found_index = index + i;
+                       index = 0;
+                       goto out;
+               }
+       }
+       index += RADIX_TREE_MAP_SIZE;
+out:
+       return index;
+}
+
+/**
+ *     radix_tree_locate_item - search through radix tree for item
+ *     @root:          radix tree root
+ *     @item:          item to be found
+ *
+ *     Returns index where item was found, or -1 if not found.
+ *     Caller must hold no lock (since this time-consuming function needs
+ *     to be preemptible), and must check afterwards if item is still there.
+ */
+unsigned long radix_tree_locate_item(struct radix_tree_root *root, void *item)
+{
+       struct radix_tree_node *node;
+       unsigned long max_index;
+       unsigned long cur_index = 0;
+       unsigned long found_index = -1;
+
+       do {
+               rcu_read_lock();
+               node = rcu_dereference_raw(root->rnode);
+               if (!radix_tree_is_indirect_ptr(node)) {
+                       rcu_read_unlock();
+                       if (node == item)
+                               found_index = 0;
+                       break;
+               }
+
+               node = indirect_to_ptr(node);
+               max_index = radix_tree_maxindex(node->height);
+               if (cur_index > max_index)
+                       break;
+
+               cur_index = __locate(node, item, cur_index, &found_index);
+               rcu_read_unlock();
+               cond_resched();
+       } while (cur_index != 0 && cur_index <= max_index);
+
+       return found_index;
+}
+#else
+unsigned long radix_tree_locate_item(struct radix_tree_root *root, void *item)
+{
+       return -1;
+}
+#endif /* CONFIG_SHMEM && CONFIG_SWAP */
 
 /**
  *     radix_tree_shrink    -    shrink height of a radix tree to minimal
index 4c45fd5..f33271d 100644 (file)
@@ -1,31 +1,72 @@
 /*
- * SHA transform algorithm, originally taken from code written by
- * Peter Gutmann, and placed in the public domain.
+ * SHA1 routine optimized to do word accesses rather than byte accesses,
+ * and to avoid unnecessary copies into the context array.
+ *
+ * This was based on the git SHA1 implementation.
  */
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/cryptohash.h>
+#include <linux/bitops.h>
+#include <asm/unaligned.h>
 
-/* The SHA f()-functions.  */
+/*
+ * If you have 32 registers or more, the compiler can (and should)
+ * try to change the array[] accesses into registers. However, on
+ * machines with less than ~25 registers, that won't really work,
+ * and at least gcc will make an unholy mess of it.
+ *
+ * So to avoid that mess which just slows things down, we force
+ * the stores to memory to actually happen (we might be better off
+ * with a 'W(t)=(val);asm("":"+m" (W(t))' there instead, as
+ * suggested by Artur Skawina - that will also make gcc unable to
+ * try to do the silly "optimize away loads" part because it won't
+ * see what the value will be).
+ *
+ * Ben Herrenschmidt reports that on PPC, the C version comes close
+ * to the optimized asm with this (ie on PPC you don't want that
+ * 'volatile', since there are lots of registers).
+ *
+ * On ARM we get the best code generation by forcing a full memory barrier
+ * between each SHA_ROUND, otherwise gcc happily get wild with spilling and
+ * the stack frame size simply explode and performance goes down the drain.
+ */
 
-#define f1(x,y,z)   (z ^ (x & (y ^ z)))                /* x ? y : z */
-#define f2(x,y,z)   (x ^ y ^ z)                        /* XOR */
-#define f3(x,y,z)   ((x & y) + (z & (x ^ y)))  /* majority */
+#ifdef CONFIG_X86
+  #define setW(x, val) (*(volatile __u32 *)&W(x) = (val))
+#elif defined(CONFIG_ARM)
+  #define setW(x, val) do { W(x) = (val); __asm__("":::"memory"); } while (0)
+#else
+  #define setW(x, val) (W(x) = (val))
+#endif
 
-/* The SHA Mysterious Constants */
+/* This "rolls" over the 512-bit array */
+#define W(x) (array[(x)&15])
 
-#define K1  0x5A827999L                        /* Rounds  0-19: sqrt(2) * 2^30 */
-#define K2  0x6ED9EBA1L                        /* Rounds 20-39: sqrt(3) * 2^30 */
-#define K3  0x8F1BBCDCL                        /* Rounds 40-59: sqrt(5) * 2^30 */
-#define K4  0xCA62C1D6L                        /* Rounds 60-79: sqrt(10) * 2^30 */
+/*
+ * Where do we get the source from? The first 16 iterations get it from
+ * the input data, the next mix it from the 512-bit array.
+ */
+#define SHA_SRC(t) get_unaligned_be32((__u32 *)data + t)
+#define SHA_MIX(t) rol32(W(t+13) ^ W(t+8) ^ W(t+2) ^ W(t), 1)
+
+#define SHA_ROUND(t, input, fn, constant, A, B, C, D, E) do { \
+       __u32 TEMP = input(t); setW(t, TEMP); \
+       E += TEMP + rol32(A,5) + (fn) + (constant); \
+       B = ror32(B, 2); } while (0)
+
+#define T_0_15(t, A, B, C, D, E)  SHA_ROUND(t, SHA_SRC, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E )
+#define T_16_19(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E )
+#define T_20_39(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0x6ed9eba1, A, B, C, D, E )
+#define T_40_59(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, ((B&C)+(D&(B^C))) , 0x8f1bbcdc, A, B, C, D, E )
+#define T_60_79(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) ,  0xca62c1d6, A, B, C, D, E )
 
 /**
  * sha_transform - single block SHA1 transform
  *
  * @digest: 160 bit digest to update
  * @data:   512 bits of data to hash
- * @W:      80 words of workspace (see note)
+ * @array:  16 words of workspace (see note)
  *
  * This function generates a SHA1 digest for a single 512-bit block.
  * Be warned, it does not handle padding and message digest, do not
  * to clear the workspace. This is left to the caller to avoid
  * unnecessary clears between chained hashing operations.
  */
-void sha_transform(__u32 *digest, const char *in, __u32 *W)
+void sha_transform(__u32 *digest, const char *data, __u32 *array)
 {
-       __u32 a, b, c, d, e, t, i;
-
-       for (i = 0; i < 16; i++)
-               W[i] = be32_to_cpu(((const __be32 *)in)[i]);
-
-       for (i = 0; i < 64; i++)
-               W[i+16] = rol32(W[i+13] ^ W[i+8] ^ W[i+2] ^ W[i], 1);
-
-       a = digest[0];
-       b = digest[1];
-       c = digest[2];
-       d = digest[3];
-       e = digest[4];
-
-       for (i = 0; i < 20; i++) {
-               t = f1(b, c, d) + K1 + rol32(a, 5) + e + W[i];
-               e = d; d = c; c = rol32(b, 30); b = a; a = t;
-       }
-
-       for (; i < 40; i ++) {
-               t = f2(b, c, d) + K2 + rol32(a, 5) + e + W[i];
-               e = d; d = c; c = rol32(b, 30); b = a; a = t;
-       }
-
-       for (; i < 60; i ++) {
-               t = f3(b, c, d) + K3 + rol32(a, 5) + e + W[i];
-               e = d; d = c; c = rol32(b, 30); b = a; a = t;
-       }
-
-       for (; i < 80; i ++) {
-               t = f2(b, c, d) + K4 + rol32(a, 5) + e + W[i];
-               e = d; d = c; c = rol32(b, 30); b = a; a = t;
-       }
-
-       digest[0] += a;
-       digest[1] += b;
-       digest[2] += c;
-       digest[3] += d;
-       digest[4] += e;
+       __u32 A, B, C, D, E;
+
+       A = digest[0];
+       B = digest[1];
+       C = digest[2];
+       D = digest[3];
+       E = digest[4];
+
+       /* Round 1 - iterations 0-16 take their input from 'data' */
+       T_0_15( 0, A, B, C, D, E);
+       T_0_15( 1, E, A, B, C, D);
+       T_0_15( 2, D, E, A, B, C);
+       T_0_15( 3, C, D, E, A, B);
+       T_0_15( 4, B, C, D, E, A);
+       T_0_15( 5, A, B, C, D, E);
+       T_0_15( 6, E, A, B, C, D);
+       T_0_15( 7, D, E, A, B, C);
+       T_0_15( 8, C, D, E, A, B);
+       T_0_15( 9, B, C, D, E, A);
+       T_0_15(10, A, B, C, D, E);
+       T_0_15(11, E, A, B, C, D);
+       T_0_15(12, D, E, A, B, C);
+       T_0_15(13, C, D, E, A, B);
+       T_0_15(14, B, C, D, E, A);
+       T_0_15(15, A, B, C, D, E);
+
+       /* Round 1 - tail. Input from 512-bit mixing array */
+       T_16_19(16, E, A, B, C, D);
+       T_16_19(17, D, E, A, B, C);
+       T_16_19(18, C, D, E, A, B);
+       T_16_19(19, B, C, D, E, A);
+
+       /* Round 2 */
+       T_20_39(20, A, B, C, D, E);
+       T_20_39(21, E, A, B, C, D);
+       T_20_39(22, D, E, A, B, C);
+       T_20_39(23, C, D, E, A, B);
+       T_20_39(24, B, C, D, E, A);
+       T_20_39(25, A, B, C, D, E);
+       T_20_39(26, E, A, B, C, D);
+       T_20_39(27, D, E, A, B, C);
+       T_20_39(28, C, D, E, A, B);
+       T_20_39(29, B, C, D, E, A);
+       T_20_39(30, A, B, C, D, E);
+       T_20_39(31, E, A, B, C, D);
+       T_20_39(32, D, E, A, B, C);
+       T_20_39(33, C, D, E, A, B);
+       T_20_39(34, B, C, D, E, A);
+       T_20_39(35, A, B, C, D, E);
+       T_20_39(36, E, A, B, C, D);
+       T_20_39(37, D, E, A, B, C);
+       T_20_39(38, C, D, E, A, B);
+       T_20_39(39, B, C, D, E, A);
+
+       /* Round 3 */
+       T_40_59(40, A, B, C, D, E);
+       T_40_59(41, E, A, B, C, D);
+       T_40_59(42, D, E, A, B, C);
+       T_40_59(43, C, D, E, A, B);
+       T_40_59(44, B, C, D, E, A);
+       T_40_59(45, A, B, C, D, E);
+       T_40_59(46, E, A, B, C, D);
+       T_40_59(47, D, E, A, B, C);
+       T_40_59(48, C, D, E, A, B);
+       T_40_59(49, B, C, D, E, A);
+       T_40_59(50, A, B, C, D, E);
+       T_40_59(51, E, A, B, C, D);
+       T_40_59(52, D, E, A, B, C);
+       T_40_59(53, C, D, E, A, B);
+       T_40_59(54, B, C, D, E, A);
+       T_40_59(55, A, B, C, D, E);
+       T_40_59(56, E, A, B, C, D);
+       T_40_59(57, D, E, A, B, C);
+       T_40_59(58, C, D, E, A, B);
+       T_40_59(59, B, C, D, E, A);
+
+       /* Round 4 */
+       T_60_79(60, A, B, C, D, E);
+       T_60_79(61, E, A, B, C, D);
+       T_60_79(62, D, E, A, B, C);
+       T_60_79(63, C, D, E, A, B);
+       T_60_79(64, B, C, D, E, A);
+       T_60_79(65, A, B, C, D, E);
+       T_60_79(66, E, A, B, C, D);
+       T_60_79(67, D, E, A, B, C);
+       T_60_79(68, C, D, E, A, B);
+       T_60_79(69, B, C, D, E, A);
+       T_60_79(70, A, B, C, D, E);
+       T_60_79(71, E, A, B, C, D);
+       T_60_79(72, D, E, A, B, C);
+       T_60_79(73, C, D, E, A, B);
+       T_60_79(74, B, C, D, E, A);
+       T_60_79(75, A, B, C, D, E);
+       T_60_79(76, E, A, B, C, D);
+       T_60_79(77, D, E, A, B, C);
+       T_60_79(78, C, D, E, A, B);
+       T_60_79(79, B, C, D, E, A);
+
+       digest[0] += A;
+       digest[1] += B;
+       digest[2] += C;
+       digest[3] += D;
+       digest[4] += E;
 }
 EXPORT_SYMBOL(sha_transform);
 
@@ -92,4 +197,3 @@ void sha_init(__u32 *buf)
        buf[3] = 0x10325476;
        buf[4] = 0xc3d2e1f0;
 }
-
index 1ce58c2..0dd7b8f 100644 (file)
@@ -34,23 +34,23 @@ __setup("failslab=", setup_failslab);
 #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
 static int __init failslab_debugfs_init(void)
 {
+       struct dentry *dir;
        mode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
-       int err;
 
-       err = init_fault_attr_dentries(&failslab.attr, "failslab");
-       if (err)
-               return err;
+       dir = fault_create_debugfs_attr("failslab", NULL, &failslab.attr);
+       if (IS_ERR(dir))
+               return PTR_ERR(dir);
 
-       if (!debugfs_create_bool("ignore-gfp-wait", mode, failslab.attr.dir,
+       if (!debugfs_create_bool("ignore-gfp-wait", mode, dir,
                                &failslab.ignore_gfp_wait))
                goto fail;
-       if (!debugfs_create_bool("cache-filter", mode, failslab.attr.dir,
+       if (!debugfs_create_bool("cache-filter", mode, dir,
                                &failslab.cache_filter))
                goto fail;
 
        return 0;
 fail:
-       cleanup_fault_attr_dentries(&failslab.attr);
+       debugfs_remove_recursive(dir);
 
        return -ENOMEM;
 }
index 867d402..645a080 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/cpuset.h>
 #include <linux/hardirq.h> /* for BUG_ON(!in_atomic()) only */
 #include <linux/memcontrol.h>
-#include <linux/mm_inline.h> /* for page_is_file_cache() */
 #include <linux/cleancache.h>
 #include "internal.h"
 
@@ -462,6 +461,7 @@ int add_to_page_cache_locked(struct page *page, struct address_space *mapping,
        int error;
 
        VM_BUG_ON(!PageLocked(page));
+       VM_BUG_ON(PageSwapBacked(page));
 
        error = mem_cgroup_cache_charge(page, current->mm,
                                        gfp_mask & GFP_RECLAIM_MASK);
@@ -479,8 +479,6 @@ int add_to_page_cache_locked(struct page *page, struct address_space *mapping,
                if (likely(!error)) {
                        mapping->nrpages++;
                        __inc_zone_page_state(page, NR_FILE_PAGES);
-                       if (PageSwapBacked(page))
-                               __inc_zone_page_state(page, NR_SHMEM);
                        spin_unlock_irq(&mapping->tree_lock);
                } else {
                        page->mapping = NULL;
@@ -502,22 +500,9 @@ int add_to_page_cache_lru(struct page *page, struct address_space *mapping,
 {
        int ret;
 
-       /*
-        * Splice_read and readahead add shmem/tmpfs pages into the page cache
-        * before shmem_readpage has a chance to mark them as SwapBacked: they
-        * need to go on the anon lru below, and mem_cgroup_cache_charge
-        * (called in add_to_page_cache) needs to know where they're going too.
-        */
-       if (mapping_cap_swap_backed(mapping))
-               SetPageSwapBacked(page);
-
        ret = add_to_page_cache(page, mapping, offset, gfp_mask);
-       if (ret == 0) {
-               if (page_is_file_cache(page))
-                       lru_cache_add_file(page);
-               else
-                       lru_cache_add_anon(page);
-       }
+       if (ret == 0)
+               lru_cache_add_file(page);
        return ret;
 }
 EXPORT_SYMBOL_GPL(add_to_page_cache_lru);
@@ -714,9 +699,16 @@ repeat:
                page = radix_tree_deref_slot(pagep);
                if (unlikely(!page))
                        goto out;
-               if (radix_tree_deref_retry(page))
-                       goto repeat;
-
+               if (radix_tree_exception(page)) {
+                       if (radix_tree_deref_retry(page))
+                               goto repeat;
+                       /*
+                        * Otherwise, shmem/tmpfs must be storing a swap entry
+                        * here as an exceptional entry: so return it without
+                        * attempting to raise page count.
+                        */
+                       goto out;
+               }
                if (!page_cache_get_speculative(page))
                        goto repeat;
 
@@ -753,7 +745,7 @@ struct page *find_lock_page(struct address_space *mapping, pgoff_t offset)
 
 repeat:
        page = find_get_page(mapping, offset);
-       if (page) {
+       if (page && !radix_tree_exception(page)) {
                lock_page(page);
                /* Has the page been truncated? */
                if (unlikely(page->mapping != mapping)) {
@@ -840,7 +832,7 @@ unsigned find_get_pages(struct address_space *mapping, pgoff_t start,
        rcu_read_lock();
 restart:
        nr_found = radix_tree_gang_lookup_slot(&mapping->page_tree,
-                               (void ***)pages, start, nr_pages);
+                               (void ***)pages, NULL, start, nr_pages);
        ret = 0;
        for (i = 0; i < nr_found; i++) {
                struct page *page;
@@ -849,13 +841,22 @@ repeat:
                if (unlikely(!page))
                        continue;
 
-               /*
-                * This can only trigger when the entry at index 0 moves out
-                * of or back to the root: none yet gotten, safe to restart.
-                */
-               if (radix_tree_deref_retry(page)) {
-                       WARN_ON(start | i);
-                       goto restart;
+               if (radix_tree_exception(page)) {
+                       if (radix_tree_deref_retry(page)) {
+                               /*
+                                * Transient condition which can only trigger
+                                * when entry at index 0 moves out of or back
+                                * to root: none yet gotten, safe to restart.
+                                */
+                               WARN_ON(start | i);
+                               goto restart;
+                       }
+                       /*
+                        * Otherwise, shmem/tmpfs must be storing a swap entry
+                        * here as an exceptional entry: so skip over it -
+                        * we only reach this from invalidate_mapping_pages().
+                        */
+                       continue;
                }
 
                if (!page_cache_get_speculative(page))
@@ -903,7 +904,7 @@ unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t index,
        rcu_read_lock();
 restart:
        nr_found = radix_tree_gang_lookup_slot(&mapping->page_tree,
-                               (void ***)pages, index, nr_pages);
+                               (void ***)pages, NULL, index, nr_pages);
        ret = 0;
        for (i = 0; i < nr_found; i++) {
                struct page *page;
@@ -912,12 +913,22 @@ repeat:
                if (unlikely(!page))
                        continue;
 
-               /*
-                * This can only trigger when the entry at index 0 moves out
-                * of or back to the root: none yet gotten, safe to restart.
-                */
-               if (radix_tree_deref_retry(page))
-                       goto restart;
+               if (radix_tree_exception(page)) {
+                       if (radix_tree_deref_retry(page)) {
+                               /*
+                                * Transient condition which can only trigger
+                                * when entry at index 0 moves out of or back
+                                * to root: none yet gotten, safe to restart.
+                                */
+                               goto restart;
+                       }
+                       /*
+                        * Otherwise, shmem/tmpfs must be storing a swap entry
+                        * here as an exceptional entry: so stop looking for
+                        * contiguous pages.
+                        */
+                       break;
+               }
 
                if (!page_cache_get_speculative(page))
                        goto repeat;
@@ -977,12 +988,21 @@ repeat:
                if (unlikely(!page))
                        continue;
 
-               /*
-                * This can only trigger when the entry at index 0 moves out
-                * of or back to the root: none yet gotten, safe to restart.
-                */
-               if (radix_tree_deref_retry(page))
-                       goto restart;
+               if (radix_tree_exception(page)) {
+                       if (radix_tree_deref_retry(page)) {
+                               /*
+                                * Transient condition which can only trigger
+                                * when entry at index 0 moves out of or back
+                                * to root: none yet gotten, safe to restart.
+                                */
+                               goto restart;
+                       }
+                       /*
+                        * This function is never used on a shmem/tmpfs
+                        * mapping, so a swap entry won't be found here.
+                        */
+                       BUG();
+               }
 
                if (!page_cache_get_speculative(page))
                        goto repeat;
index 693394d..5ef672c 100644 (file)
@@ -326,7 +326,7 @@ static struct page_address_slot {
        spinlock_t lock;                        /* Protect this bucket's list */
 } ____cacheline_aligned_in_smp page_address_htable[1<<PA_HASH_ORDER];
 
-static struct page_address_slot *page_slot(struct page *page)
+static struct page_address_slot *page_slot(const struct page *page)
 {
        return &page_address_htable[hash_ptr(page, PA_HASH_ORDER)];
 }
@@ -337,7 +337,7 @@ static struct page_address_slot *page_slot(struct page *page)
  *
  * Returns the page's virtual address.
  */
-void *page_address(struct page *page)
+void *page_address(const struct page *page)
 {
        unsigned long flags;
        void *ret;
index 5f84d23..930de94 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/limits.h>
 #include <linux/mutex.h>
 #include <linux/rbtree.h>
-#include <linux/shmem_fs.h>
 #include <linux/slab.h>
 #include <linux/swap.h>
 #include <linux/swapops.h>
@@ -2092,6 +2091,7 @@ struct memcg_stock_pcp {
 #define FLUSHING_CACHED_CHARGE (0)
 };
 static DEFINE_PER_CPU(struct memcg_stock_pcp, memcg_stock);
+static DEFINE_MUTEX(percpu_charge_mutex);
 
 /*
  * Try to consume stocked charge on this cpu. If success, one page is consumed
@@ -2198,8 +2198,7 @@ static void drain_all_stock(struct mem_cgroup *root_mem, bool sync)
 
        for_each_online_cpu(cpu) {
                struct memcg_stock_pcp *stock = &per_cpu(memcg_stock, cpu);
-               if (mem_cgroup_same_or_subtree(root_mem, stock->cached) &&
-                               test_bit(FLUSHING_CACHED_CHARGE, &stock->flags))
+               if (test_bit(FLUSHING_CACHED_CHARGE, &stock->flags))
                        flush_work(&stock->work);
        }
 out:
@@ -2214,14 +2213,22 @@ out:
  */
 static void drain_all_stock_async(struct mem_cgroup *root_mem)
 {
+       /*
+        * If someone calls draining, avoid adding more kworker runs.
+        */
+       if (!mutex_trylock(&percpu_charge_mutex))
+               return;
        drain_all_stock(root_mem, false);
+       mutex_unlock(&percpu_charge_mutex);
 }
 
 /* This is a synchronous drain interface. */
 static void drain_all_stock_sync(struct mem_cgroup *root_mem)
 {
        /* called when force_empty is called */
+       mutex_lock(&percpu_charge_mutex);
        drain_all_stock(root_mem, true);
+       mutex_unlock(&percpu_charge_mutex);
 }
 
 /*
@@ -2873,30 +2880,6 @@ int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
                return 0;
        if (PageCompound(page))
                return 0;
-       /*
-        * Corner case handling. This is called from add_to_page_cache()
-        * in usual. But some FS (shmem) precharges this page before calling it
-        * and call add_to_page_cache() with GFP_NOWAIT.
-        *
-        * For GFP_NOWAIT case, the page may be pre-charged before calling
-        * add_to_page_cache(). (See shmem.c) check it here and avoid to call
-        * charge twice. (It works but has to pay a bit larger cost.)
-        * And when the page is SwapCache, it should take swap information
-        * into account. This is under lock_page() now.
-        */
-       if (!(gfp_mask & __GFP_WAIT)) {
-               struct page_cgroup *pc;
-
-               pc = lookup_page_cgroup(page);
-               if (!pc)
-                       return 0;
-               lock_page_cgroup(pc);
-               if (PageCgroupUsed(pc)) {
-                       unlock_page_cgroup(pc);
-                       return 0;
-               }
-               unlock_page_cgroup(pc);
-       }
 
        if (unlikely(!mm))
                mm = &init_mm;
@@ -3486,31 +3469,6 @@ void mem_cgroup_end_migration(struct mem_cgroup *mem,
        cgroup_release_and_wakeup_rmdir(&mem->css);
 }
 
-/*
- * A call to try to shrink memory usage on charge failure at shmem's swapin.
- * Calling hierarchical_reclaim is not enough because we should update
- * last_oom_jiffies to prevent pagefault_out_of_memory from invoking global OOM.
- * Moreover considering hierarchy, we should reclaim from the mem_over_limit,
- * not from the memcg which this page would be charged to.
- * try_charge_swapin does all of these works properly.
- */
-int mem_cgroup_shmem_charge_fallback(struct page *page,
-                           struct mm_struct *mm,
-                           gfp_t gfp_mask)
-{
-       struct mem_cgroup *mem;
-       int ret;
-
-       if (mem_cgroup_disabled())
-               return 0;
-
-       ret = mem_cgroup_try_charge_swapin(mm, page, gfp_mask, &mem);
-       if (!ret)
-               mem_cgroup_cancel_charge_swapin(mem); /* it does !mem check */
-
-       return ret;
-}
-
 #ifdef CONFIG_DEBUG_VM
 static struct page_cgroup *lookup_page_cgroup_used(struct page *page)
 {
@@ -5330,15 +5288,17 @@ static struct page *mc_handle_file_pte(struct vm_area_struct *vma,
                pgoff = pte_to_pgoff(ptent);
 
        /* page is moved even if it's not RSS of this task(page-faulted). */
-       if (!mapping_cap_swap_backed(mapping)) { /* normal file */
-               page = find_get_page(mapping, pgoff);
-       } else { /* shmem/tmpfs file. we should take account of swap too. */
-               swp_entry_t ent;
-               mem_cgroup_get_shmem_target(inode, pgoff, &page, &ent);
+       page = find_get_page(mapping, pgoff);
+
+#ifdef CONFIG_SWAP
+       /* shmem/tmpfs may report page out on swap: account for that too. */
+       if (radix_tree_exceptional_entry(page)) {
+               swp_entry_t swap = radix_to_swp_entry(page);
                if (do_swap_account)
-                       entry->val = ent.val;
+                       *entry = swap;
+               page = find_get_page(&swapper_space, swap.val);
        }
-
+#endif
        return page;
 }
 
index 740c4f5..2b43ba0 100644 (file)
@@ -53,6 +53,7 @@
 #include <linux/hugetlb.h>
 #include <linux/memory_hotplug.h>
 #include <linux/mm_inline.h>
+#include <linux/kfifo.h>
 #include "internal.h"
 
 int sysctl_memory_failure_early_kill __read_mostly = 0;
@@ -1178,6 +1179,97 @@ void memory_failure(unsigned long pfn, int trapno)
        __memory_failure(pfn, trapno, 0);
 }
 
+#define MEMORY_FAILURE_FIFO_ORDER      4
+#define MEMORY_FAILURE_FIFO_SIZE       (1 << MEMORY_FAILURE_FIFO_ORDER)
+
+struct memory_failure_entry {
+       unsigned long pfn;
+       int trapno;
+       int flags;
+};
+
+struct memory_failure_cpu {
+       DECLARE_KFIFO(fifo, struct memory_failure_entry,
+                     MEMORY_FAILURE_FIFO_SIZE);
+       spinlock_t lock;
+       struct work_struct work;
+};
+
+static DEFINE_PER_CPU(struct memory_failure_cpu, memory_failure_cpu);
+
+/**
+ * memory_failure_queue - Schedule handling memory failure of a page.
+ * @pfn: Page Number of the corrupted page
+ * @trapno: Trap number reported in the signal to user space.
+ * @flags: Flags for memory failure handling
+ *
+ * This function is called by the low level hardware error handler
+ * when it detects hardware memory corruption of a page. It schedules
+ * the recovering of error page, including dropping pages, killing
+ * processes etc.
+ *
+ * The function is primarily of use for corruptions that
+ * happen outside the current execution context (e.g. when
+ * detected by a background scrubber)
+ *
+ * Can run in IRQ context.
+ */
+void memory_failure_queue(unsigned long pfn, int trapno, int flags)
+{
+       struct memory_failure_cpu *mf_cpu;
+       unsigned long proc_flags;
+       struct memory_failure_entry entry = {
+               .pfn =          pfn,
+               .trapno =       trapno,
+               .flags =        flags,
+       };
+
+       mf_cpu = &get_cpu_var(memory_failure_cpu);
+       spin_lock_irqsave(&mf_cpu->lock, proc_flags);
+       if (kfifo_put(&mf_cpu->fifo, &entry))
+               schedule_work_on(smp_processor_id(), &mf_cpu->work);
+       else
+               pr_err("Memory failure: buffer overflow when queuing memory failure at 0x%#lx\n",
+                      pfn);
+       spin_unlock_irqrestore(&mf_cpu->lock, proc_flags);
+       put_cpu_var(memory_failure_cpu);
+}
+EXPORT_SYMBOL_GPL(memory_failure_queue);
+
+static void memory_failure_work_func(struct work_struct *work)
+{
+       struct memory_failure_cpu *mf_cpu;
+       struct memory_failure_entry entry = { 0, };
+       unsigned long proc_flags;
+       int gotten;
+
+       mf_cpu = &__get_cpu_var(memory_failure_cpu);
+       for (;;) {
+               spin_lock_irqsave(&mf_cpu->lock, proc_flags);
+               gotten = kfifo_get(&mf_cpu->fifo, &entry);
+               spin_unlock_irqrestore(&mf_cpu->lock, proc_flags);
+               if (!gotten)
+                       break;
+               __memory_failure(entry.pfn, entry.trapno, entry.flags);
+       }
+}
+
+static int __init memory_failure_init(void)
+{
+       struct memory_failure_cpu *mf_cpu;
+       int cpu;
+
+       for_each_possible_cpu(cpu) {
+               mf_cpu = &per_cpu(memory_failure_cpu, cpu);
+               spin_lock_init(&mf_cpu->lock);
+               INIT_KFIFO(mf_cpu->fifo);
+               INIT_WORK(&mf_cpu->work, memory_failure_work_func);
+       }
+
+       return 0;
+}
+core_initcall(memory_failure_init);
+
 /**
  * unpoison_memory - Unpoison a previously poisoned page
  * @pfn: Page number of the to be unpoisoned page
index a4e6b9d..636a868 100644 (file)
@@ -69,12 +69,15 @@ static unsigned char mincore_page(struct address_space *mapping, pgoff_t pgoff)
         * file will not get a swp_entry_t in its pte, but rather it is like
         * any other file mapping (ie. marked !present and faulted in with
         * tmpfs's .fault). So swapped out tmpfs mappings are tested here.
-        *
-        * However when tmpfs moves the page from pagecache and into swapcache,
-        * it is still in core, but the find_get_page below won't find it.
-        * No big deal, but make a note of it.
         */
        page = find_get_page(mapping, pgoff);
+#ifdef CONFIG_SWAP
+       /* shmem/tmpfs may return swap: account for swapcache page too. */
+       if (radix_tree_exceptional_entry(page)) {
+               swp_entry_t swap = radix_to_swp_entry(page);
+               page = find_get_page(&swapper_space, swap.val);
+       }
+#endif
        if (page) {
                present = PageUptodate(page);
                page_cache_release(page);
index eafff89..626303b 100644 (file)
@@ -303,7 +303,7 @@ static struct task_struct *select_bad_process(unsigned int *ppoints,
        do_each_thread(g, p) {
                unsigned int points;
 
-               if (!p->mm)
+               if (p->exit_state)
                        continue;
                if (oom_unkillable_task(p, mem, nodemask))
                        continue;
@@ -319,6 +319,8 @@ static struct task_struct *select_bad_process(unsigned int *ppoints,
                 */
                if (test_tsk_thread_flag(p, TIF_MEMDIE))
                        return ERR_PTR(-1UL);
+               if (!p->mm)
+                       continue;
 
                if (p->flags & PF_EXITING) {
                        /*
index 1dbcf88..6e8ecb6 100644 (file)
@@ -1409,14 +1409,11 @@ static int __init fail_page_alloc_debugfs(void)
 {
        mode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
        struct dentry *dir;
-       int err;
 
-       err = init_fault_attr_dentries(&fail_page_alloc.attr,
-                                      "fail_page_alloc");
-       if (err)
-               return err;
-
-       dir = fail_page_alloc.attr.dir;
+       dir = fault_create_debugfs_attr("fail_page_alloc", NULL,
+                                       &fail_page_alloc.attr);
+       if (IS_ERR(dir))
+               return PTR_ERR(dir);
 
        if (!debugfs_create_bool("ignore-gfp-wait", mode, dir,
                                &fail_page_alloc.ignore_gfp_wait))
@@ -1430,7 +1427,7 @@ static int __init fail_page_alloc_debugfs(void)
 
        return 0;
 fail:
-       cleanup_fault_attr_dentries(&fail_page_alloc.attr);
+       debugfs_remove_recursive(dir);
 
        return -ENOMEM;
 }
index 5cc21f8..32f6763 100644 (file)
@@ -6,7 +6,8 @@
  *              2000-2001 Christoph Rohland
  *              2000-2001 SAP AG
  *              2002 Red Hat Inc.
- * Copyright (C) 2002-2005 Hugh Dickins.
+ * Copyright (C) 2002-2011 Hugh Dickins.
+ * Copyright (C) 2011 Google Inc.
  * Copyright (C) 2002-2005 VERITAS Software Corporation.
  * Copyright (C) 2004 Andi Kleen, SuSE Labs
  *
@@ -28,7 +29,6 @@
 #include <linux/file.h>
 #include <linux/mm.h>
 #include <linux/module.h>
-#include <linux/percpu_counter.h>
 #include <linux/swap.h>
 
 static struct vfsmount *shm_mnt;
@@ -51,6 +51,8 @@ static struct vfsmount *shm_mnt;
 #include <linux/shmem_fs.h>
 #include <linux/writeback.h>
 #include <linux/blkdev.h>
+#include <linux/pagevec.h>
+#include <linux/percpu_counter.h>
 #include <linux/splice.h>
 #include <linux/security.h>
 #include <linux/swapops.h>
@@ -63,43 +65,17 @@ static struct vfsmount *shm_mnt;
 #include <linux/magic.h>
 
 #include <asm/uaccess.h>
-#include <asm/div64.h>
 #include <asm/pgtable.h>
 
-/*
- * The maximum size of a shmem/tmpfs file is limited by the maximum size of
- * its triple-indirect swap vector - see illustration at shmem_swp_entry().
- *
- * With 4kB page size, maximum file size is just over 2TB on a 32-bit kernel,
- * but one eighth of that on a 64-bit kernel.  With 8kB page size, maximum
- * file size is just over 4TB on a 64-bit kernel, but 16TB on a 32-bit kernel,
- * MAX_LFS_FILESIZE being then more restrictive than swap vector layout.
- *
- * We use / and * instead of shifts in the definitions below, so that the swap
- * vector can be tested with small even values (e.g. 20) for ENTRIES_PER_PAGE.
- */
-#define ENTRIES_PER_PAGE (PAGE_CACHE_SIZE/sizeof(unsigned long))
-#define ENTRIES_PER_PAGEPAGE ((unsigned long long)ENTRIES_PER_PAGE*ENTRIES_PER_PAGE)
-
-#define SHMSWP_MAX_INDEX (SHMEM_NR_DIRECT + (ENTRIES_PER_PAGEPAGE/2) * (ENTRIES_PER_PAGE+1))
-#define SHMSWP_MAX_BYTES (SHMSWP_MAX_INDEX << PAGE_CACHE_SHIFT)
-
-#define SHMEM_MAX_BYTES  min_t(unsigned long long, SHMSWP_MAX_BYTES, MAX_LFS_FILESIZE)
-#define SHMEM_MAX_INDEX  ((unsigned long)((SHMEM_MAX_BYTES+1) >> PAGE_CACHE_SHIFT))
-
 #define BLOCKS_PER_PAGE  (PAGE_CACHE_SIZE/512)
 #define VM_ACCT(size)    (PAGE_CACHE_ALIGN(size) >> PAGE_SHIFT)
 
-/* info->flags needs VM_flags to handle pagein/truncate races efficiently */
-#define SHMEM_PAGEIN    VM_READ
-#define SHMEM_TRUNCATE  VM_WRITE
-
-/* Definition to limit shmem_truncate's steps between cond_rescheds */
-#define LATENCY_LIMIT   64
-
 /* Pretend that each entry is of this size in directory's i_size */
 #define BOGO_DIRENT_SIZE 20
 
+/* Symlink up to this size is kmalloc'ed instead of using a swappable page */
+#define SHORT_SYMLINK_LEN 128
+
 struct shmem_xattr {
        struct list_head list;  /* anchored by shmem_inode_info->xattr_list */
        char *name;             /* xattr name */
@@ -107,7 +83,7 @@ struct shmem_xattr {
        char value[0];
 };
 
-/* Flag allocation requirements to shmem_getpage and shmem_swp_alloc */
+/* Flag allocation requirements to shmem_getpage */
 enum sgp_type {
        SGP_READ,       /* don't exceed i_size, don't allocate page */
        SGP_CACHE,      /* don't exceed i_size, may allocate page */
@@ -137,56 +113,6 @@ static inline int shmem_getpage(struct inode *inode, pgoff_t index,
                        mapping_gfp_mask(inode->i_mapping), fault_type);
 }
 
-static inline struct page *shmem_dir_alloc(gfp_t gfp_mask)
-{
-       /*
-        * The above definition of ENTRIES_PER_PAGE, and the use of
-        * BLOCKS_PER_PAGE on indirect pages, assume PAGE_CACHE_SIZE:
-        * might be reconsidered if it ever diverges from PAGE_SIZE.
-        *
-        * Mobility flags are masked out as swap vectors cannot move
-        */
-       return alloc_pages((gfp_mask & ~GFP_MOVABLE_MASK) | __GFP_ZERO,
-                               PAGE_CACHE_SHIFT-PAGE_SHIFT);
-}
-
-static inline void shmem_dir_free(struct page *page)
-{
-       __free_pages(page, PAGE_CACHE_SHIFT-PAGE_SHIFT);
-}
-
-static struct page **shmem_dir_map(struct page *page)
-{
-       return (struct page **)kmap_atomic(page, KM_USER0);
-}
-
-static inline void shmem_dir_unmap(struct page **dir)
-{
-       kunmap_atomic(dir, KM_USER0);
-}
-
-static swp_entry_t *shmem_swp_map(struct page *page)
-{
-       return (swp_entry_t *)kmap_atomic(page, KM_USER1);
-}
-
-static inline void shmem_swp_balance_unmap(void)
-{
-       /*
-        * When passing a pointer to an i_direct entry, to code which
-        * also handles indirect entries and so will shmem_swp_unmap,
-        * we must arrange for the preempt count to remain in balance.
-        * What kmap_atomic of a lowmem page does depends on config
-        * and architecture, so pretend to kmap_atomic some lowmem page.
-        */
-       (void) kmap_atomic(ZERO_PAGE(0), KM_USER1);
-}
-
-static inline void shmem_swp_unmap(swp_entry_t *entry)
-{
-       kunmap_atomic(entry, KM_USER1);
-}
-
 static inline struct shmem_sb_info *SHMEM_SB(struct super_block *sb)
 {
        return sb->s_fs_info;
@@ -244,15 +170,6 @@ static struct backing_dev_info shmem_backing_dev_info  __read_mostly = {
 static LIST_HEAD(shmem_swaplist);
 static DEFINE_MUTEX(shmem_swaplist_mutex);
 
-static void shmem_free_blocks(struct inode *inode, long pages)
-{
-       struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
-       if (sbinfo->max_blocks) {
-               percpu_counter_add(&sbinfo->used_blocks, -pages);
-               inode->i_blocks -= pages*BLOCKS_PER_PAGE;
-       }
-}
-
 static int shmem_reserve_inode(struct super_block *sb)
 {
        struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
@@ -279,7 +196,7 @@ static void shmem_free_inode(struct super_block *sb)
 }
 
 /**
- * shmem_recalc_inode - recalculate the size of an inode
+ * shmem_recalc_inode - recalculate the block usage of an inode
  * @inode: inode to recalc
  *
  * We have to calculate the free blocks since the mm can drop
@@ -297,474 +214,297 @@ static void shmem_recalc_inode(struct inode *inode)
 
        freed = info->alloced - info->swapped - inode->i_mapping->nrpages;
        if (freed > 0) {
+               struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
+               if (sbinfo->max_blocks)
+                       percpu_counter_add(&sbinfo->used_blocks, -freed);
                info->alloced -= freed;
+               inode->i_blocks -= freed * BLOCKS_PER_PAGE;
                shmem_unacct_blocks(info->flags, freed);
-               shmem_free_blocks(inode, freed);
        }
 }
 
-/**
- * shmem_swp_entry - find the swap vector position in the info structure
- * @info:  info structure for the inode
- * @index: index of the page to find
- * @page:  optional page to add to the structure. Has to be preset to
- *         all zeros
- *
- * If there is no space allocated yet it will return NULL when
- * page is NULL, else it will use the page for the needed block,
- * setting it to NULL on return to indicate that it has been used.
- *
- * The swap vector is organized the following way:
- *
- * There are SHMEM_NR_DIRECT entries directly stored in the
- * shmem_inode_info structure. So small files do not need an addional
- * allocation.
- *
- * For pages with index > SHMEM_NR_DIRECT there is the pointer
- * i_indirect which points to a page which holds in the first half
- * doubly indirect blocks, in the second half triple indirect blocks:
- *
- * For an artificial ENTRIES_PER_PAGE = 4 this would lead to the
- * following layout (for SHMEM_NR_DIRECT == 16):
- *
- * i_indirect -> dir --> 16-19
- *           |      +-> 20-23
- *           |
- *           +-->dir2 --> 24-27
- *           |        +-> 28-31
- *           |        +-> 32-35
- *           |        +-> 36-39
- *           |
- *           +-->dir3 --> 40-43
- *                    +-> 44-47
- *                    +-> 48-51
- *                    +-> 52-55
+/*
+ * Replace item expected in radix tree by a new item, while holding tree lock.
  */
-static swp_entry_t *shmem_swp_entry(struct shmem_inode_info *info, unsigned long index, struct page **page)
-{
-       unsigned long offset;
-       struct page **dir;
-       struct page *subdir;
-
-       if (index < SHMEM_NR_DIRECT) {
-               shmem_swp_balance_unmap();
-               return info->i_direct+index;
-       }
-       if (!info->i_indirect) {
-               if (page) {
-                       info->i_indirect = *page;
-                       *page = NULL;
-               }
-               return NULL;                    /* need another page */
-       }
-
-       index -= SHMEM_NR_DIRECT;
-       offset = index % ENTRIES_PER_PAGE;
-       index /= ENTRIES_PER_PAGE;
-       dir = shmem_dir_map(info->i_indirect);
-
-       if (index >= ENTRIES_PER_PAGE/2) {
-               index -= ENTRIES_PER_PAGE/2;
-               dir += ENTRIES_PER_PAGE/2 + index/ENTRIES_PER_PAGE;
-               index %= ENTRIES_PER_PAGE;
-               subdir = *dir;
-               if (!subdir) {
-                       if (page) {
-                               *dir = *page;
-                               *page = NULL;
-                       }
-                       shmem_dir_unmap(dir);
-                       return NULL;            /* need another page */
-               }
-               shmem_dir_unmap(dir);
-               dir = shmem_dir_map(subdir);
-       }
+static int shmem_radix_tree_replace(struct address_space *mapping,
+                       pgoff_t index, void *expected, void *replacement)
+{
+       void **pslot;
+       void *item = NULL;
+
+       VM_BUG_ON(!expected);
+       pslot = radix_tree_lookup_slot(&mapping->page_tree, index);
+       if (pslot)
+               item = radix_tree_deref_slot_protected(pslot,
+                                                       &mapping->tree_lock);
+       if (item != expected)
+               return -ENOENT;
+       if (replacement)
+               radix_tree_replace_slot(pslot, replacement);
+       else
+               radix_tree_delete(&mapping->page_tree, index);
+       return 0;
+}
 
-       dir += index;
-       subdir = *dir;
-       if (!subdir) {
-               if (!page || !(subdir = *page)) {
-                       shmem_dir_unmap(dir);
-                       return NULL;            /* need a page */
+/*
+ * Like add_to_page_cache_locked, but error if expected item has gone.
+ */
+static int shmem_add_to_page_cache(struct page *page,
+                                  struct address_space *mapping,
+                                  pgoff_t index, gfp_t gfp, void *expected)
+{
+       int error = 0;
+
+       VM_BUG_ON(!PageLocked(page));
+       VM_BUG_ON(!PageSwapBacked(page));
+
+       if (!expected)
+               error = radix_tree_preload(gfp & GFP_RECLAIM_MASK);
+       if (!error) {
+               page_cache_get(page);
+               page->mapping = mapping;
+               page->index = index;
+
+               spin_lock_irq(&mapping->tree_lock);
+               if (!expected)
+                       error = radix_tree_insert(&mapping->page_tree,
+                                                       index, page);
+               else
+                       error = shmem_radix_tree_replace(mapping, index,
+                                                       expected, page);
+               if (!error) {
+                       mapping->nrpages++;
+                       __inc_zone_page_state(page, NR_FILE_PAGES);
+                       __inc_zone_page_state(page, NR_SHMEM);
+                       spin_unlock_irq(&mapping->tree_lock);
+               } else {
+                       page->mapping = NULL;
+                       spin_unlock_irq(&mapping->tree_lock);
+                       page_cache_release(page);
                }
-               *dir = subdir;
-               *page = NULL;
+               if (!expected)
+                       radix_tree_preload_end();
        }
-       shmem_dir_unmap(dir);
-       return shmem_swp_map(subdir) + offset;
+       if (error)
+               mem_cgroup_uncharge_cache_page(page);
+       return error;
 }
 
-static void shmem_swp_set(struct shmem_inode_info *info, swp_entry_t *entry, unsigned long value)
+/*
+ * Like delete_from_page_cache, but substitutes swap for page.
+ */
+static void shmem_delete_from_page_cache(struct page *page, void *radswap)
 {
-       long incdec = value? 1: -1;
+       struct address_space *mapping = page->mapping;
+       int error;
 
-       entry->val = value;
-       info->swapped += incdec;
-       if ((unsigned long)(entry - info->i_direct) >= SHMEM_NR_DIRECT) {
-               struct page *page = kmap_atomic_to_page(entry);
-               set_page_private(page, page_private(page) + incdec);
-       }
+       spin_lock_irq(&mapping->tree_lock);
+       error = shmem_radix_tree_replace(mapping, page->index, page, radswap);
+       page->mapping = NULL;
+       mapping->nrpages--;
+       __dec_zone_page_state(page, NR_FILE_PAGES);
+       __dec_zone_page_state(page, NR_SHMEM);
+       spin_unlock_irq(&mapping->tree_lock);
+       page_cache_release(page);
+       BUG_ON(error);
 }
 
-/**
- * shmem_swp_alloc - get the position of the swap entry for the page.
- * @info:      info structure for the inode
- * @index:     index of the page to find
- * @sgp:       check and recheck i_size? skip allocation?
- * @gfp:       gfp mask to use for any page allocation
- *
- * If the entry does not exist, allocate it.
+/*
+ * Like find_get_pages, but collecting swap entries as well as pages.
  */
-static swp_entry_t *shmem_swp_alloc(struct shmem_inode_info *info,
-                       unsigned long index, enum sgp_type sgp, gfp_t gfp)
-{
-       struct inode *inode = &info->vfs_inode;
-       struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
-       struct page *page = NULL;
-       swp_entry_t *entry;
-
-       if (sgp != SGP_WRITE &&
-           ((loff_t) index << PAGE_CACHE_SHIFT) >= i_size_read(inode))
-               return ERR_PTR(-EINVAL);
-
-       while (!(entry = shmem_swp_entry(info, index, &page))) {
-               if (sgp == SGP_READ)
-                       return shmem_swp_map(ZERO_PAGE(0));
-               /*
-                * Test used_blocks against 1 less max_blocks, since we have 1 data
-                * page (and perhaps indirect index pages) yet to allocate:
-                * a waste to allocate index if we cannot allocate data.
-                */
-               if (sbinfo->max_blocks) {
-                       if (percpu_counter_compare(&sbinfo->used_blocks,
-                                               sbinfo->max_blocks - 1) >= 0)
-                               return ERR_PTR(-ENOSPC);
-                       percpu_counter_inc(&sbinfo->used_blocks);
-                       inode->i_blocks += BLOCKS_PER_PAGE;
+static unsigned shmem_find_get_pages_and_swap(struct address_space *mapping,
+                                       pgoff_t start, unsigned int nr_pages,
+                                       struct page **pages, pgoff_t *indices)
+{
+       unsigned int i;
+       unsigned int ret;
+       unsigned int nr_found;
+
+       rcu_read_lock();
+restart:
+       nr_found = radix_tree_gang_lookup_slot(&mapping->page_tree,
+                               (void ***)pages, indices, start, nr_pages);
+       ret = 0;
+       for (i = 0; i < nr_found; i++) {
+               struct page *page;
+repeat:
+               page = radix_tree_deref_slot((void **)pages[i]);
+               if (unlikely(!page))
+                       continue;
+               if (radix_tree_exception(page)) {
+                       if (radix_tree_deref_retry(page))
+                               goto restart;
+                       /*
+                        * Otherwise, we must be storing a swap entry
+                        * here as an exceptional entry: so return it
+                        * without attempting to raise page count.
+                        */
+                       goto export;
                }
+               if (!page_cache_get_speculative(page))
+                       goto repeat;
 
-               spin_unlock(&info->lock);
-               page = shmem_dir_alloc(gfp);
-               spin_lock(&info->lock);
-
-               if (!page) {
-                       shmem_free_blocks(inode, 1);
-                       return ERR_PTR(-ENOMEM);
-               }
-               if (sgp != SGP_WRITE &&
-                   ((loff_t) index << PAGE_CACHE_SHIFT) >= i_size_read(inode)) {
-                       entry = ERR_PTR(-EINVAL);
-                       break;
+               /* Has the page moved? */
+               if (unlikely(page != *((void **)pages[i]))) {
+                       page_cache_release(page);
+                       goto repeat;
                }
-               if (info->next_index <= index)
-                       info->next_index = index + 1;
-       }
-       if (page) {
-               /* another task gave its page, or truncated the file */
-               shmem_free_blocks(inode, 1);
-               shmem_dir_free(page);
-       }
-       if (info->next_index <= index && !IS_ERR(entry))
-               info->next_index = index + 1;
-       return entry;
+export:
+               indices[ret] = indices[i];
+               pages[ret] = page;
+               ret++;
+       }
+       if (unlikely(!ret && nr_found))
+               goto restart;
+       rcu_read_unlock();
+       return ret;
 }
 
-/**
- * shmem_free_swp - free some swap entries in a directory
- * @dir:        pointer to the directory
- * @edir:       pointer after last entry of the directory
- * @punch_lock: pointer to spinlock when needed for the holepunch case
+/*
+ * Remove swap entry from radix tree, free the swap and its page cache.
  */
-static int shmem_free_swp(swp_entry_t *dir, swp_entry_t *edir,
-                                               spinlock_t *punch_lock)
-{
-       spinlock_t *punch_unlock = NULL;
-       swp_entry_t *ptr;
-       int freed = 0;
-
-       for (ptr = dir; ptr < edir; ptr++) {
-               if (ptr->val) {
-                       if (unlikely(punch_lock)) {
-                               punch_unlock = punch_lock;
-                               punch_lock = NULL;
-                               spin_lock(punch_unlock);
-                               if (!ptr->val)
-                                       continue;
-                       }
-                       free_swap_and_cache(*ptr);
-                       *ptr = (swp_entry_t){0};
-                       freed++;
-               }
-       }
-       if (punch_unlock)
-               spin_unlock(punch_unlock);
-       return freed;
-}
-
-static int shmem_map_and_free_swp(struct page *subdir, int offset,
-               int limit, struct page ***dir, spinlock_t *punch_lock)
-{
-       swp_entry_t *ptr;
-       int freed = 0;
-
-       ptr = shmem_swp_map(subdir);
-       for (; offset < limit; offset += LATENCY_LIMIT) {
-               int size = limit - offset;
-               if (size > LATENCY_LIMIT)
-                       size = LATENCY_LIMIT;
-               freed += shmem_free_swp(ptr+offset, ptr+offset+size,
-                                                       punch_lock);
-               if (need_resched()) {
-                       shmem_swp_unmap(ptr);
-                       if (*dir) {
-                               shmem_dir_unmap(*dir);
-                               *dir = NULL;
-                       }
-                       cond_resched();
-                       ptr = shmem_swp_map(subdir);
-               }
-       }
-       shmem_swp_unmap(ptr);
-       return freed;
+static int shmem_free_swap(struct address_space *mapping,
+                          pgoff_t index, void *radswap)
+{
+       int error;
+
+       spin_lock_irq(&mapping->tree_lock);
+       error = shmem_radix_tree_replace(mapping, index, radswap, NULL);
+       spin_unlock_irq(&mapping->tree_lock);
+       if (!error)
+               free_swap_and_cache(radix_to_swp_entry(radswap));
+       return error;
 }
 
-static void shmem_free_pages(struct list_head *next)
+/*
+ * Pagevec may contain swap entries, so shuffle up pages before releasing.
+ */
+static void shmem_pagevec_release(struct pagevec *pvec)
 {
-       struct page *page;
-       int freed = 0;
-
-       do {
-               page = container_of(next, struct page, lru);
-               next = next->next;
-               shmem_dir_free(page);
-               freed++;
-               if (freed >= LATENCY_LIMIT) {
-                       cond_resched();
-                       freed = 0;
-               }
-       } while (next);
+       int i, j;
+
+       for (i = 0, j = 0; i < pagevec_count(pvec); i++) {
+               struct page *page = pvec->pages[i];
+               if (!radix_tree_exceptional_entry(page))
+                       pvec->pages[j++] = page;
+       }
+       pvec->nr = j;
+       pagevec_release(pvec);
 }
 
-void shmem_truncate_range(struct inode *inode, loff_t start, loff_t end)
+/*
+ * Remove range of pages and swap entries from radix tree, and free them.
+ */
+void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend)
 {
+       struct address_space *mapping = inode->i_mapping;
        struct shmem_inode_info *info = SHMEM_I(inode);
-       unsigned long idx;
-       unsigned long size;
-       unsigned long limit;
-       unsigned long stage;
-       unsigned long diroff;
-       struct page **dir;
-       struct page *topdir;
-       struct page *middir;
-       struct page *subdir;
-       swp_entry_t *ptr;
-       LIST_HEAD(pages_to_free);
-       long nr_pages_to_free = 0;
+       pgoff_t start = (lstart + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+       unsigned partial = lstart & (PAGE_CACHE_SIZE - 1);
+       pgoff_t end = (lend >> PAGE_CACHE_SHIFT);
+       struct pagevec pvec;
+       pgoff_t indices[PAGEVEC_SIZE];
        long nr_swaps_freed = 0;
-       int offset;
-       int freed;
-       int punch_hole;
-       spinlock_t *needs_lock;
-       spinlock_t *punch_lock;
-       unsigned long upper_limit;
+       pgoff_t index;
+       int i;
 
-       truncate_inode_pages_range(inode->i_mapping, start, end);
+       BUG_ON((lend & (PAGE_CACHE_SIZE - 1)) != (PAGE_CACHE_SIZE - 1));
 
-       inode->i_ctime = inode->i_mtime = CURRENT_TIME;
-       idx = (start + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-       if (idx >= info->next_index)
-               return;
+       pagevec_init(&pvec, 0);
+       index = start;
+       while (index <= end) {
+               pvec.nr = shmem_find_get_pages_and_swap(mapping, index,
+                       min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1,
+                                                       pvec.pages, indices);
+               if (!pvec.nr)
+                       break;
+               mem_cgroup_uncharge_start();
+               for (i = 0; i < pagevec_count(&pvec); i++) {
+                       struct page *page = pvec.pages[i];
 
-       spin_lock(&info->lock);
-       info->flags |= SHMEM_TRUNCATE;
-       if (likely(end == (loff_t) -1)) {
-               limit = info->next_index;
-               upper_limit = SHMEM_MAX_INDEX;
-               info->next_index = idx;
-               needs_lock = NULL;
-               punch_hole = 0;
-       } else {
-               if (end + 1 >= inode->i_size) { /* we may free a little more */
-                       limit = (inode->i_size + PAGE_CACHE_SIZE - 1) >>
-                                                       PAGE_CACHE_SHIFT;
-                       upper_limit = SHMEM_MAX_INDEX;
-               } else {
-                       limit = (end + 1) >> PAGE_CACHE_SHIFT;
-                       upper_limit = limit;
-               }
-               needs_lock = &info->lock;
-               punch_hole = 1;
-       }
+                       index = indices[i];
+                       if (index > end)
+                               break;
+
+                       if (radix_tree_exceptional_entry(page)) {
+                               nr_swaps_freed += !shmem_free_swap(mapping,
+                                                               index, page);
+                               continue;
+                       }
 
-       topdir = info->i_indirect;
-       if (topdir && idx <= SHMEM_NR_DIRECT && !punch_hole) {
-               info->i_indirect = NULL;
-               nr_pages_to_free++;
-               list_add(&topdir->lru, &pages_to_free);
+                       if (!trylock_page(page))
+                               continue;
+                       if (page->mapping == mapping) {
+                               VM_BUG_ON(PageWriteback(page));
+                               truncate_inode_page(mapping, page);
+                       }
+                       unlock_page(page);
+               }
+               shmem_pagevec_release(&pvec);
+               mem_cgroup_uncharge_end();
+               cond_resched();
+               index++;
        }
-       spin_unlock(&info->lock);
 
-       if (info->swapped && idx < SHMEM_NR_DIRECT) {
-               ptr = info->i_direct;
-               size = limit;
-               if (size > SHMEM_NR_DIRECT)
-                       size = SHMEM_NR_DIRECT;
-               nr_swaps_freed = shmem_free_swp(ptr+idx, ptr+size, needs_lock);
+       if (partial) {
+               struct page *page = NULL;
+               shmem_getpage(inode, start - 1, &page, SGP_READ, NULL);
+               if (page) {
+                       zero_user_segment(page, partial, PAGE_CACHE_SIZE);
+                       set_page_dirty(page);
+                       unlock_page(page);
+                       page_cache_release(page);
+               }
        }
 
-       /*
-        * If there are no indirect blocks or we are punching a hole
-        * below indirect blocks, nothing to be done.
-        */
-       if (!topdir || limit <= SHMEM_NR_DIRECT)
-               goto done2;
+       index = start;
+       for ( ; ; ) {
+               cond_resched();
+               pvec.nr = shmem_find_get_pages_and_swap(mapping, index,
+                       min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1,
+                                                       pvec.pages, indices);
+               if (!pvec.nr) {
+                       if (index == start)
+                               break;
+                       index = start;
+                       continue;
+               }
+               if (index == start && indices[0] > end) {
+                       shmem_pagevec_release(&pvec);
+                       break;
+               }
+               mem_cgroup_uncharge_start();
+               for (i = 0; i < pagevec_count(&pvec); i++) {
+                       struct page *page = pvec.pages[i];
 
-       /*
-        * The truncation case has already dropped info->lock, and we're safe
-        * because i_size and next_index have already been lowered, preventing
-        * access beyond.  But in the punch_hole case, we still need to take
-        * the lock when updating the swap directory, because there might be
-        * racing accesses by shmem_getpage(SGP_CACHE), shmem_unuse_inode or
-        * shmem_writepage.  However, whenever we find we can remove a whole
-        * directory page (not at the misaligned start or end of the range),
-        * we first NULLify its pointer in the level above, and then have no
-        * need to take the lock when updating its contents: needs_lock and
-        * punch_lock (either pointing to info->lock or NULL) manage this.
-        */
+                       index = indices[i];
+                       if (index > end)
+                               break;
 
-       upper_limit -= SHMEM_NR_DIRECT;
-       limit -= SHMEM_NR_DIRECT;
-       idx = (idx > SHMEM_NR_DIRECT)? (idx - SHMEM_NR_DIRECT): 0;
-       offset = idx % ENTRIES_PER_PAGE;
-       idx -= offset;
-
-       dir = shmem_dir_map(topdir);
-       stage = ENTRIES_PER_PAGEPAGE/2;
-       if (idx < ENTRIES_PER_PAGEPAGE/2) {
-               middir = topdir;
-               diroff = idx/ENTRIES_PER_PAGE;
-       } else {
-               dir += ENTRIES_PER_PAGE/2;
-               dir += (idx - ENTRIES_PER_PAGEPAGE/2)/ENTRIES_PER_PAGEPAGE;
-               while (stage <= idx)
-                       stage += ENTRIES_PER_PAGEPAGE;
-               middir = *dir;
-               if (*dir) {
-                       diroff = ((idx - ENTRIES_PER_PAGEPAGE/2) %
-                               ENTRIES_PER_PAGEPAGE) / ENTRIES_PER_PAGE;
-                       if (!diroff && !offset && upper_limit >= stage) {
-                               if (needs_lock) {
-                                       spin_lock(needs_lock);
-                                       *dir = NULL;
-                                       spin_unlock(needs_lock);
-                                       needs_lock = NULL;
-                               } else
-                                       *dir = NULL;
-                               nr_pages_to_free++;
-                               list_add(&middir->lru, &pages_to_free);
+                       if (radix_tree_exceptional_entry(page)) {
+                               nr_swaps_freed += !shmem_free_swap(mapping,
+                                                               index, page);
+                               continue;
                        }
-                       shmem_dir_unmap(dir);
-                       dir = shmem_dir_map(middir);
-               } else {
-                       diroff = 0;
-                       offset = 0;
-                       idx = stage;
-               }
-       }
 
-       for (; idx < limit; idx += ENTRIES_PER_PAGE, diroff++) {
-               if (unlikely(idx == stage)) {
-                       shmem_dir_unmap(dir);
-                       dir = shmem_dir_map(topdir) +
-                           ENTRIES_PER_PAGE/2 + idx/ENTRIES_PER_PAGEPAGE;
-                       while (!*dir) {
-                               dir++;
-                               idx += ENTRIES_PER_PAGEPAGE;
-                               if (idx >= limit)
-                                       goto done1;
-                       }
-                       stage = idx + ENTRIES_PER_PAGEPAGE;
-                       middir = *dir;
-                       if (punch_hole)
-                               needs_lock = &info->lock;
-                       if (upper_limit >= stage) {
-                               if (needs_lock) {
-                                       spin_lock(needs_lock);
-                                       *dir = NULL;
-                                       spin_unlock(needs_lock);
-                                       needs_lock = NULL;
-                               } else
-                                       *dir = NULL;
-                               nr_pages_to_free++;
-                               list_add(&middir->lru, &pages_to_free);
+                       lock_page(page);
+                       if (page->mapping == mapping) {
+                               VM_BUG_ON(PageWriteback(page));
+                               truncate_inode_page(mapping, page);
                        }
-                       shmem_dir_unmap(dir);
-                       cond_resched();
-                       dir = shmem_dir_map(middir);
-                       diroff = 0;
-               }
-               punch_lock = needs_lock;
-               subdir = dir[diroff];
-               if (subdir && !offset && upper_limit-idx >= ENTRIES_PER_PAGE) {
-                       if (needs_lock) {
-                               spin_lock(needs_lock);
-                               dir[diroff] = NULL;
-                               spin_unlock(needs_lock);
-                               punch_lock = NULL;
-                       } else
-                               dir[diroff] = NULL;
-                       nr_pages_to_free++;
-                       list_add(&subdir->lru, &pages_to_free);
-               }
-               if (subdir && page_private(subdir) /* has swap entries */) {
-                       size = limit - idx;
-                       if (size > ENTRIES_PER_PAGE)
-                               size = ENTRIES_PER_PAGE;
-                       freed = shmem_map_and_free_swp(subdir,
-                                       offset, size, &dir, punch_lock);
-                       if (!dir)
-                               dir = shmem_dir_map(middir);
-                       nr_swaps_freed += freed;
-                       if (offset || punch_lock) {
-                               spin_lock(&info->lock);
-                               set_page_private(subdir,
-                                       page_private(subdir) - freed);
-                               spin_unlock(&info->lock);
-                       } else
-                               BUG_ON(page_private(subdir) != freed);
+                       unlock_page(page);
                }
-               offset = 0;
-       }
-done1:
-       shmem_dir_unmap(dir);
-done2:
-       if (inode->i_mapping->nrpages && (info->flags & SHMEM_PAGEIN)) {
-               /*
-                * Call truncate_inode_pages again: racing shmem_unuse_inode
-                * may have swizzled a page in from swap since
-                * truncate_pagecache or generic_delete_inode did it, before we
-                * lowered next_index.  Also, though shmem_getpage checks
-                * i_size before adding to cache, no recheck after: so fix the
-                * narrow window there too.
-                */
-               truncate_inode_pages_range(inode->i_mapping, start, end);
+               shmem_pagevec_release(&pvec);
+               mem_cgroup_uncharge_end();
+               index++;
        }
 
        spin_lock(&info->lock);
-       info->flags &= ~SHMEM_TRUNCATE;
        info->swapped -= nr_swaps_freed;
-       if (nr_pages_to_free)
-               shmem_free_blocks(inode, nr_pages_to_free);
        shmem_recalc_inode(inode);
        spin_unlock(&info->lock);
 
-       /*
-        * Empty swap vector directory pages to be freed?
-        */
-       if (!list_empty(&pages_to_free)) {
-               pages_to_free.prev->next = NULL;
-               shmem_free_pages(pages_to_free.next);
-       }
+       inode->i_ctime = inode->i_mtime = CURRENT_TIME;
 }
 EXPORT_SYMBOL_GPL(shmem_truncate_range);
 
@@ -780,37 +520,7 @@ static int shmem_setattr(struct dentry *dentry, struct iattr *attr)
        if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) {
                loff_t oldsize = inode->i_size;
                loff_t newsize = attr->ia_size;
-               struct page *page = NULL;
 
-               if (newsize < oldsize) {
-                       /*
-                        * If truncating down to a partial page, then
-                        * if that page is already allocated, hold it
-                        * in memory until the truncation is over, so
-                        * truncate_partial_page cannot miss it were
-                        * it assigned to swap.
-                        */
-                       if (newsize & (PAGE_CACHE_SIZE-1)) {
-                               (void) shmem_getpage(inode,
-                                       newsize >> PAGE_CACHE_SHIFT,
-                                               &page, SGP_READ, NULL);
-                               if (page)
-                                       unlock_page(page);
-                       }
-                       /*
-                        * Reset SHMEM_PAGEIN flag so that shmem_truncate can
-                        * detect if any pages might have been added to cache
-                        * after truncate_inode_pages.  But we needn't bother
-                        * if it's being fully truncated to zero-length: the
-                        * nrpages check is efficient enough in that case.
-                        */
-                       if (newsize) {
-                               struct shmem_inode_info *info = SHMEM_I(inode);
-                               spin_lock(&info->lock);
-                               info->flags &= ~SHMEM_PAGEIN;
-                               spin_unlock(&info->lock);
-                       }
-               }
                if (newsize != oldsize) {
                        i_size_write(inode, newsize);
                        inode->i_ctime = inode->i_mtime = CURRENT_TIME;
@@ -822,8 +532,6 @@ static int shmem_setattr(struct dentry *dentry, struct iattr *attr)
                        /* unmap again to remove racily COWed private pages */
                        unmap_mapping_range(inode->i_mapping, holebegin, 0, 1);
                }
-               if (page)
-                       page_cache_release(page);
        }
 
        setattr_copy(inode, attr);
@@ -848,7 +556,8 @@ static void shmem_evict_inode(struct inode *inode)
                        list_del_init(&info->swaplist);
                        mutex_unlock(&shmem_swaplist_mutex);
                }
-       }
+       } else
+               kfree(info->symlink);
 
        list_for_each_entry_safe(xattr, nxattr, &info->xattr_list, list) {
                kfree(xattr->name);
@@ -859,106 +568,27 @@ static void shmem_evict_inode(struct inode *inode)
        end_writeback(inode);
 }
 
-static inline int shmem_find_swp(swp_entry_t entry, swp_entry_t *dir, swp_entry_t *edir)
-{
-       swp_entry_t *ptr;
-
-       for (ptr = dir; ptr < edir; ptr++) {
-               if (ptr->val == entry.val)
-                       return ptr - dir;
-       }
-       return -1;
-}
-
-static int shmem_unuse_inode(struct shmem_inode_info *info, swp_entry_t entry, struct page *page)
+/*
+ * If swap found in inode, free it and move page from swapcache to filecache.
+ */
+static int shmem_unuse_inode(struct shmem_inode_info *info,
+                            swp_entry_t swap, struct page *page)
 {
-       struct address_space *mapping;
-       unsigned long idx;
-       unsigned long size;
-       unsigned long limit;
-       unsigned long stage;
-       struct page **dir;
-       struct page *subdir;
-       swp_entry_t *ptr;
-       int offset;
+       struct address_space *mapping = info->vfs_inode.i_mapping;
+       void *radswap;
+       pgoff_t index;
        int error;
 
-       idx = 0;
-       ptr = info->i_direct;
-       spin_lock(&info->lock);
-       if (!info->swapped) {
-               list_del_init(&info->swaplist);
-               goto lost2;
-       }
-       limit = info->next_index;
-       size = limit;
-       if (size > SHMEM_NR_DIRECT)
-               size = SHMEM_NR_DIRECT;
-       offset = shmem_find_swp(entry, ptr, ptr+size);
-       if (offset >= 0) {
-               shmem_swp_balance_unmap();
-               goto found;
-       }
-       if (!info->i_indirect)
-               goto lost2;
-
-       dir = shmem_dir_map(info->i_indirect);
-       stage = SHMEM_NR_DIRECT + ENTRIES_PER_PAGEPAGE/2;
-
-       for (idx = SHMEM_NR_DIRECT; idx < limit; idx += ENTRIES_PER_PAGE, dir++) {
-               if (unlikely(idx == stage)) {
-                       shmem_dir_unmap(dir-1);
-                       if (cond_resched_lock(&info->lock)) {
-                               /* check it has not been truncated */
-                               if (limit > info->next_index) {
-                                       limit = info->next_index;
-                                       if (idx >= limit)
-                                               goto lost2;
-                               }
-                       }
-                       dir = shmem_dir_map(info->i_indirect) +
-                           ENTRIES_PER_PAGE/2 + idx/ENTRIES_PER_PAGEPAGE;
-                       while (!*dir) {
-                               dir++;
-                               idx += ENTRIES_PER_PAGEPAGE;
-                               if (idx >= limit)
-                                       goto lost1;
-                       }
-                       stage = idx + ENTRIES_PER_PAGEPAGE;
-                       subdir = *dir;
-                       shmem_dir_unmap(dir);
-                       dir = shmem_dir_map(subdir);
-               }
-               subdir = *dir;
-               if (subdir && page_private(subdir)) {
-                       ptr = shmem_swp_map(subdir);
-                       size = limit - idx;
-                       if (size > ENTRIES_PER_PAGE)
-                               size = ENTRIES_PER_PAGE;
-                       offset = shmem_find_swp(entry, ptr, ptr+size);
-                       shmem_swp_unmap(ptr);
-                       if (offset >= 0) {
-                               shmem_dir_unmap(dir);
-                               ptr = shmem_swp_map(subdir);
-                               goto found;
-                       }
-               }
-       }
-lost1:
-       shmem_dir_unmap(dir-1);
-lost2:
-       spin_unlock(&info->lock);
-       return 0;
-found:
-       idx += offset;
-       ptr += offset;
+       radswap = swp_to_radix_entry(swap);
+       index = radix_tree_locate_item(&mapping->page_tree, radswap);
+       if (index == -1)
+               return 0;
 
        /*
         * Move _head_ to start search for next from here.
         * But be careful: shmem_evict_inode checks list_empty without taking
         * mutex, and there's an instant in list_move_tail when info->swaplist
-        * would appear empty, if it were the only one on shmem_swaplist.  We
-        * could avoid doing it if inode NULL; or use this minor optimization.
+        * would appear empty, if it were the only one on shmem_swaplist.
         */
        if (shmem_swaplist.next != &info->swaplist)
                list_move_tail(&shmem_swaplist, &info->swaplist);
@@ -968,29 +598,34 @@ found:
         * but also to hold up shmem_evict_inode(): so inode cannot be freed
         * beneath us (pagelock doesn't help until the page is in pagecache).
         */
-       mapping = info->vfs_inode.i_mapping;
-       error = add_to_page_cache_locked(page, mapping, idx, GFP_NOWAIT);
+       error = shmem_add_to_page_cache(page, mapping, index,
+                                               GFP_NOWAIT, radswap);
        /* which does mem_cgroup_uncharge_cache_page on error */
 
        if (error != -ENOMEM) {
+               /*
+                * Truncation and eviction use free_swap_and_cache(), which
+                * only does trylock page: if we raced, best clean up here.
+                */
                delete_from_swap_cache(page);
                set_page_dirty(page);
-               info->flags |= SHMEM_PAGEIN;
-               shmem_swp_set(info, ptr, 0);
-               swap_free(entry);
+               if (!error) {
+                       spin_lock(&info->lock);
+                       info->swapped--;
+                       spin_unlock(&info->lock);
+                       swap_free(swap);
+               }
                error = 1;      /* not an error, but entry was found */
        }
-       shmem_swp_unmap(ptr);
-       spin_unlock(&info->lock);
        return error;
 }
 
 /*
- * shmem_unuse() search for an eventually swapped out shmem page.
+ * Search through swapped inodes to find and replace swap by page.
  */
-int shmem_unuse(swp_entry_t entry, struct page *page)
+int shmem_unuse(swp_entry_t swap, struct page *page)
 {
-       struct list_head *p, *next;
+       struct list_head *this, *next;
        struct shmem_inode_info *info;
        int found = 0;
        int error;
@@ -999,32 +634,25 @@ int shmem_unuse(swp_entry_t entry, struct page *page)
         * Charge page using GFP_KERNEL while we can wait, before taking
         * the shmem_swaplist_mutex which might hold up shmem_writepage().
         * Charged back to the user (not to caller) when swap account is used.
-        * add_to_page_cache() will be called with GFP_NOWAIT.
         */
        error = mem_cgroup_cache_charge(page, current->mm, GFP_KERNEL);
        if (error)
                goto out;
-       /*
-        * Try to preload while we can wait, to not make a habit of
-        * draining atomic reserves; but don't latch on to this cpu,
-        * it's okay if sometimes we get rescheduled after this.
-        */
-       error = radix_tree_preload(GFP_KERNEL);
-       if (error)
-               goto uncharge;
-       radix_tree_preload_end();
+       /* No radix_tree_preload: swap entry keeps a place for page in tree */
 
        mutex_lock(&shmem_swaplist_mutex);
-       list_for_each_safe(p, next, &shmem_swaplist) {
-               info = list_entry(p, struct shmem_inode_info, swaplist);
-               found = shmem_unuse_inode(info, entry, page);
+       list_for_each_safe(this, next, &shmem_swaplist) {
+               info = list_entry(this, struct shmem_inode_info, swaplist);
+               if (info->swapped)
+                       found = shmem_unuse_inode(info, swap, page);
+               else
+                       list_del_init(&info->swaplist);
                cond_resched();
                if (found)
                        break;
        }
        mutex_unlock(&shmem_swaplist_mutex);
 
-uncharge:
        if (!found)
                mem_cgroup_uncharge_cache_page(page);
        if (found < 0)
@@ -1041,10 +669,10 @@ out:
 static int shmem_writepage(struct page *page, struct writeback_control *wbc)
 {
        struct shmem_inode_info *info;
-       swp_entry_t *entry, swap;
        struct address_space *mapping;
-       unsigned long index;
        struct inode *inode;
+       swp_entry_t swap;
+       pgoff_t index;
 
        BUG_ON(!PageLocked(page));
        mapping = page->mapping;
@@ -1073,50 +701,32 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
 
        /*
         * Add inode to shmem_unuse()'s list of swapped-out inodes,
-        * if it's not already there.  Do it now because we cannot take
-        * mutex while holding spinlock, and must do so before the page
-        * is moved to swap cache, when its pagelock no longer protects
+        * if it's not already there.  Do it now before the page is
+        * moved to swap cache, when its pagelock no longer protects
         * the inode from eviction.  But don't unlock the mutex until
-        * we've taken the spinlock, because shmem_unuse_inode() will
-        * prune a !swapped inode from the swaplist under both locks.
+        * we've incremented swapped, because shmem_unuse_inode() will
+        * prune a !swapped inode from the swaplist under this mutex.
         */
        mutex_lock(&shmem_swaplist_mutex);
        if (list_empty(&info->swaplist))
                list_add_tail(&info->swaplist, &shmem_swaplist);
 
-       spin_lock(&info->lock);
-       mutex_unlock(&shmem_swaplist_mutex);
-
-       if (index >= info->next_index) {
-               BUG_ON(!(info->flags & SHMEM_TRUNCATE));
-               goto unlock;
-       }
-       entry = shmem_swp_entry(info, index, NULL);
-       if (entry->val) {
-               WARN_ON_ONCE(1);        /* Still happens? Tell us about it! */
-               free_swap_and_cache(*entry);
-               shmem_swp_set(info, entry, 0);
-       }
-       shmem_recalc_inode(inode);
-
        if (add_to_swap_cache(page, swap, GFP_ATOMIC) == 0) {
-               delete_from_page_cache(page);
-               shmem_swp_set(info, entry, swap.val);
-               shmem_swp_unmap(entry);
                swap_shmem_alloc(swap);
+               shmem_delete_from_page_cache(page, swp_to_radix_entry(swap));
+
+               spin_lock(&info->lock);
+               info->swapped++;
+               shmem_recalc_inode(inode);
                spin_unlock(&info->lock);
+
+               mutex_unlock(&shmem_swaplist_mutex);
                BUG_ON(page_mapped(page));
                swap_writepage(page, wbc);
                return 0;
        }
 
-       shmem_swp_unmap(entry);
-unlock:
-       spin_unlock(&info->lock);
-       /*
-        * add_to_swap_cache() doesn't return -EEXIST, so we can safely
-        * clear SWAP_HAS_CACHE flag.
-        */
+       mutex_unlock(&shmem_swaplist_mutex);
        swapcache_free(swap, NULL);
 redirty:
        set_page_dirty(page);
@@ -1153,35 +763,33 @@ static struct mempolicy *shmem_get_sbmpol(struct shmem_sb_info *sbinfo)
 }
 #endif /* CONFIG_TMPFS */
 
-static struct page *shmem_swapin(swp_entry_t entry, gfp_t gfp,
-                       struct shmem_inode_info *info, unsigned long idx)
+static struct page *shmem_swapin(swp_entry_t swap, gfp_t gfp,
+                       struct shmem_inode_info *info, pgoff_t index)
 {
        struct mempolicy mpol, *spol;
        struct vm_area_struct pvma;
-       struct page *page;
 
        spol = mpol_cond_copy(&mpol,
-                               mpol_shared_policy_lookup(&info->policy, idx));
+                       mpol_shared_policy_lookup(&info->policy, index));
 
        /* Create a pseudo vma that just contains the policy */
        pvma.vm_start = 0;
-       pvma.vm_pgoff = idx;
+       pvma.vm_pgoff = index;
        pvma.vm_ops = NULL;
        pvma.vm_policy = spol;
-       page = swapin_readahead(entry, gfp, &pvma, 0);
-       return page;
+       return swapin_readahead(swap, gfp, &pvma, 0);
 }
 
 static struct page *shmem_alloc_page(gfp_t gfp,
-                       struct shmem_inode_info *info, unsigned long idx)
+                       struct shmem_inode_info *info, pgoff_t index)
 {
        struct vm_area_struct pvma;
 
        /* Create a pseudo vma that just contains the policy */
        pvma.vm_start = 0;
-       pvma.vm_pgoff = idx;
+       pvma.vm_pgoff = index;
        pvma.vm_ops = NULL;
-       pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, idx);
+       pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, index);
 
        /*
         * alloc_page_vma() will drop the shared policy reference
@@ -1190,19 +798,19 @@ static struct page *shmem_alloc_page(gfp_t gfp,
 }
 #else /* !CONFIG_NUMA */
 #ifdef CONFIG_TMPFS
-static inline void shmem_show_mpol(struct seq_file *seq, struct mempolicy *p)
+static inline void shmem_show_mpol(struct seq_file *seq, struct mempolicy *mpol)
 {
 }
 #endif /* CONFIG_TMPFS */
 
-static inline struct page *shmem_swapin(swp_entry_t entry, gfp_t gfp,
-                       struct shmem_inode_info *info, unsigned long idx)
+static inline struct page *shmem_swapin(swp_entry_t swap, gfp_t gfp,
+                       struct shmem_inode_info *info, pgoff_t index)
 {
-       return swapin_readahead(entry, gfp, NULL, 0);
+       return swapin_readahead(swap, gfp, NULL, 0);
 }
 
 static inline struct page *shmem_alloc_page(gfp_t gfp,
-                       struct shmem_inode_info *info, unsigned long idx)
+                       struct shmem_inode_info *info, pgoff_t index)
 {
        return alloc_page(gfp);
 }
@@ -1222,243 +830,190 @@ static inline struct mempolicy *shmem_get_sbmpol(struct shmem_sb_info *sbinfo)
  * vm. If we swap it in we mark it dirty since we also free the swap
  * entry since a page cannot live in both the swap and page cache
  */
-static int shmem_getpage_gfp(struct inode *inode, pgoff_t idx,
+static int shmem_getpage_gfp(struct inode *inode, pgoff_t index,
        struct page **pagep, enum sgp_type sgp, gfp_t gfp, int *fault_type)
 {
        struct address_space *mapping = inode->i_mapping;
-       struct shmem_inode_info *info = SHMEM_I(inode);
+       struct shmem_inode_info *info;
        struct shmem_sb_info *sbinfo;
        struct page *page;
-       struct page *prealloc_page = NULL;
-       swp_entry_t *entry;
        swp_entry_t swap;
        int error;
-       int ret;
+       int once = 0;
 
-       if (idx >= SHMEM_MAX_INDEX)
+       if (index > (MAX_LFS_FILESIZE >> PAGE_CACHE_SHIFT))
                return -EFBIG;
 repeat:
-       page = find_lock_page(mapping, idx);
-       if (page) {
+       swap.val = 0;
+       page = find_lock_page(mapping, index);
+       if (radix_tree_exceptional_entry(page)) {
+               swap = radix_to_swp_entry(page);
+               page = NULL;
+       }
+
+       if (sgp != SGP_WRITE &&
+           ((loff_t)index << PAGE_CACHE_SHIFT) >= i_size_read(inode)) {
+               error = -EINVAL;
+               goto failed;
+       }
+
+       if (page || (sgp == SGP_READ && !swap.val)) {
                /*
                 * Once we can get the page lock, it must be uptodate:
                 * if there were an error in reading back from swap,
                 * the page would not be inserted into the filecache.
                 */
-               BUG_ON(!PageUptodate(page));
-               goto done;
+               BUG_ON(page && !PageUptodate(page));
+               *pagep = page;
+               return 0;
        }
 
        /*
-        * Try to preload while we can wait, to not make a habit of
-        * draining atomic reserves; but don't latch on to this cpu.
+        * Fast cache lookup did not find it:
+        * bring it back from swap or allocate.
         */
-       error = radix_tree_preload(gfp & GFP_RECLAIM_MASK);
-       if (error)
-               goto out;
-       radix_tree_preload_end();
-
-       if (sgp != SGP_READ && !prealloc_page) {
-               prealloc_page = shmem_alloc_page(gfp, info, idx);
-               if (prealloc_page) {
-                       SetPageSwapBacked(prealloc_page);
-                       if (mem_cgroup_cache_charge(prealloc_page,
-                                       current->mm, GFP_KERNEL)) {
-                               page_cache_release(prealloc_page);
-                               prealloc_page = NULL;
-                       }
-               }
-       }
-
-       spin_lock(&info->lock);
-       shmem_recalc_inode(inode);
-       entry = shmem_swp_alloc(info, idx, sgp, gfp);
-       if (IS_ERR(entry)) {
-               spin_unlock(&info->lock);
-               error = PTR_ERR(entry);
-               goto out;
-       }
-       swap = *entry;
+       info = SHMEM_I(inode);
+       sbinfo = SHMEM_SB(inode->i_sb);
 
        if (swap.val) {
                /* Look it up and read it in.. */
                page = lookup_swap_cache(swap);
                if (!page) {
-                       shmem_swp_unmap(entry);
-                       spin_unlock(&info->lock);
                        /* here we actually do the io */
                        if (fault_type)
                                *fault_type |= VM_FAULT_MAJOR;
-                       page = shmem_swapin(swap, gfp, info, idx);
+                       page = shmem_swapin(swap, gfp, info, index);
                        if (!page) {
-                               spin_lock(&info->lock);
-                               entry = shmem_swp_alloc(info, idx, sgp, gfp);
-                               if (IS_ERR(entry))
-                                       error = PTR_ERR(entry);
-                               else {
-                                       if (entry->val == swap.val)
-                                               error = -ENOMEM;
-                                       shmem_swp_unmap(entry);
-                               }
-                               spin_unlock(&info->lock);
-                               if (error)
-                                       goto out;
-                               goto repeat;
+                               error = -ENOMEM;
+                               goto failed;
                        }
-                       wait_on_page_locked(page);
-                       page_cache_release(page);
-                       goto repeat;
                }
 
                /* We have to do this with page locked to prevent races */
-               if (!trylock_page(page)) {
-                       shmem_swp_unmap(entry);
-                       spin_unlock(&info->lock);
-                       wait_on_page_locked(page);
-                       page_cache_release(page);
-                       goto repeat;
-               }
-               if (PageWriteback(page)) {
-                       shmem_swp_unmap(entry);
-                       spin_unlock(&info->lock);
-                       wait_on_page_writeback(page);
-                       unlock_page(page);
-                       page_cache_release(page);
-                       goto repeat;
-               }
+               lock_page(page);
                if (!PageUptodate(page)) {
-                       shmem_swp_unmap(entry);
-                       spin_unlock(&info->lock);
-                       unlock_page(page);
-                       page_cache_release(page);
                        error = -EIO;
-                       goto out;
+                       goto failed;
                }
-
-               error = add_to_page_cache_locked(page, mapping,
-                                                idx, GFP_NOWAIT);
-               if (error) {
-                       shmem_swp_unmap(entry);
-                       spin_unlock(&info->lock);
-                       if (error == -ENOMEM) {
-                               /*
-                                * reclaim from proper memory cgroup and
-                                * call memcg's OOM if needed.
-                                */
-                               error = mem_cgroup_shmem_charge_fallback(
-                                               page, current->mm, gfp);
-                               if (error) {
-                                       unlock_page(page);
-                                       page_cache_release(page);
-                                       goto out;
-                               }
-                       }
-                       unlock_page(page);
-                       page_cache_release(page);
-                       goto repeat;
+               wait_on_page_writeback(page);
+
+               /* Someone may have already done it for us */
+               if (page->mapping) {
+                       if (page->mapping == mapping &&
+                           page->index == index)
+                               goto done;
+                       error = -EEXIST;
+                       goto failed;
                }
 
-               info->flags |= SHMEM_PAGEIN;
-               shmem_swp_set(info, entry, 0);
-               shmem_swp_unmap(entry);
-               delete_from_swap_cache(page);
+               error = mem_cgroup_cache_charge(page, current->mm,
+                                               gfp & GFP_RECLAIM_MASK);
+               if (!error)
+                       error = shmem_add_to_page_cache(page, mapping, index,
+                                               gfp, swp_to_radix_entry(swap));
+               if (error)
+                       goto failed;
+
+               spin_lock(&info->lock);
+               info->swapped--;
+               shmem_recalc_inode(inode);
                spin_unlock(&info->lock);
+
+               delete_from_swap_cache(page);
                set_page_dirty(page);
                swap_free(swap);
 
-       } else if (sgp == SGP_READ) {
-               shmem_swp_unmap(entry);
-               page = find_get_page(mapping, idx);
-               if (page && !trylock_page(page)) {
-                       spin_unlock(&info->lock);
-                       wait_on_page_locked(page);
-                       page_cache_release(page);
-                       goto repeat;
+       } else {
+               if (shmem_acct_block(info->flags)) {
+                       error = -ENOSPC;
+                       goto failed;
                }
-               spin_unlock(&info->lock);
-
-       } else if (prealloc_page) {
-               shmem_swp_unmap(entry);
-               sbinfo = SHMEM_SB(inode->i_sb);
                if (sbinfo->max_blocks) {
                        if (percpu_counter_compare(&sbinfo->used_blocks,
-                                               sbinfo->max_blocks) >= 0 ||
-                           shmem_acct_block(info->flags))
-                               goto nospace;
+                                               sbinfo->max_blocks) >= 0) {
+                               error = -ENOSPC;
+                               goto unacct;
+                       }
                        percpu_counter_inc(&sbinfo->used_blocks);
-                       inode->i_blocks += BLOCKS_PER_PAGE;
-               } else if (shmem_acct_block(info->flags))
-                       goto nospace;
-
-               page = prealloc_page;
-               prealloc_page = NULL;
-
-               entry = shmem_swp_alloc(info, idx, sgp, gfp);
-               if (IS_ERR(entry))
-                       error = PTR_ERR(entry);
-               else {
-                       swap = *entry;
-                       shmem_swp_unmap(entry);
                }
-               ret = error || swap.val;
-               if (ret)
-                       mem_cgroup_uncharge_cache_page(page);
-               else
-                       ret = add_to_page_cache_lru(page, mapping,
-                                               idx, GFP_NOWAIT);
-               /*
-                * At add_to_page_cache_lru() failure,
-                * uncharge will be done automatically.
-                */
-               if (ret) {
-                       shmem_unacct_blocks(info->flags, 1);
-                       shmem_free_blocks(inode, 1);
-                       spin_unlock(&info->lock);
-                       page_cache_release(page);
-                       if (error)
-                               goto out;
-                       goto repeat;
+
+               page = shmem_alloc_page(gfp, info, index);
+               if (!page) {
+                       error = -ENOMEM;
+                       goto decused;
                }
 
-               info->flags |= SHMEM_PAGEIN;
+               SetPageSwapBacked(page);
+               __set_page_locked(page);
+               error = mem_cgroup_cache_charge(page, current->mm,
+                                               gfp & GFP_RECLAIM_MASK);
+               if (!error)
+                       error = shmem_add_to_page_cache(page, mapping, index,
+                                               gfp, NULL);
+               if (error)
+                       goto decused;
+               lru_cache_add_anon(page);
+
+               spin_lock(&info->lock);
                info->alloced++;
+               inode->i_blocks += BLOCKS_PER_PAGE;
+               shmem_recalc_inode(inode);
                spin_unlock(&info->lock);
+
                clear_highpage(page);
                flush_dcache_page(page);
                SetPageUptodate(page);
                if (sgp == SGP_DIRTY)
                        set_page_dirty(page);
-
-       } else {
-               spin_unlock(&info->lock);
-               error = -ENOMEM;
-               goto out;
        }
 done:
-       *pagep = page;
-       error = 0;
-out:
-       if (prealloc_page) {
-               mem_cgroup_uncharge_cache_page(prealloc_page);
-               page_cache_release(prealloc_page);
+       /* Perhaps the file has been truncated since we checked */
+       if (sgp != SGP_WRITE &&
+           ((loff_t)index << PAGE_CACHE_SHIFT) >= i_size_read(inode)) {
+               error = -EINVAL;
+               goto trunc;
        }
-       return error;
+       *pagep = page;
+       return 0;
 
-nospace:
        /*
-        * Perhaps the page was brought in from swap between find_lock_page
-        * and taking info->lock?  We allow for that at add_to_page_cache_lru,
-        * but must also avoid reporting a spurious ENOSPC while working on a
-        * full tmpfs.
+        * Error recovery.
         */
-       page = find_get_page(mapping, idx);
+trunc:
+       ClearPageDirty(page);
+       delete_from_page_cache(page);
+       spin_lock(&info->lock);
+       info->alloced--;
+       inode->i_blocks -= BLOCKS_PER_PAGE;
        spin_unlock(&info->lock);
+decused:
+       if (sbinfo->max_blocks)
+               percpu_counter_add(&sbinfo->used_blocks, -1);
+unacct:
+       shmem_unacct_blocks(info->flags, 1);
+failed:
+       if (swap.val && error != -EINVAL) {
+               struct page *test = find_get_page(mapping, index);
+               if (test && !radix_tree_exceptional_entry(test))
+                       page_cache_release(test);
+               /* Have another try if the entry has changed */
+               if (test != swp_to_radix_entry(swap))
+                       error = -EEXIST;
+       }
        if (page) {
+               unlock_page(page);
                page_cache_release(page);
+       }
+       if (error == -ENOSPC && !once++) {
+               info = SHMEM_I(inode);
+               spin_lock(&info->lock);
+               shmem_recalc_inode(inode);
+               spin_unlock(&info->lock);
                goto repeat;
        }
-       error = -ENOSPC;
-       goto out;
+       if (error == -EEXIST)
+               goto repeat;
+       return error;
 }
 
 static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
@@ -1467,9 +1022,6 @@ static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
        int error;
        int ret = VM_FAULT_LOCKED;
 
-       if (((loff_t)vmf->pgoff << PAGE_CACHE_SHIFT) >= i_size_read(inode))
-               return VM_FAULT_SIGBUS;
-
        error = shmem_getpage(inode, vmf->pgoff, &vmf->page, SGP_CACHE, &ret);
        if (error)
                return ((error == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS);
@@ -1482,20 +1034,20 @@ static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 }
 
 #ifdef CONFIG_NUMA
-static int shmem_set_policy(struct vm_area_struct *vma, struct mempolicy *new)
+static int shmem_set_policy(struct vm_area_struct *vma, struct mempolicy *mpol)
 {
-       struct inode *i = vma->vm_file->f_path.dentry->d_inode;
-       return mpol_set_shared_policy(&SHMEM_I(i)->policy, vma, new);
+       struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
+       return mpol_set_shared_policy(&SHMEM_I(inode)->policy, vma, mpol);
 }
 
 static struct mempolicy *shmem_get_policy(struct vm_area_struct *vma,
                                          unsigned long addr)
 {
-       struct inode *i = vma->vm_file->f_path.dentry->d_inode;
-       unsigned long idx;
+       struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
+       pgoff_t index;
 
-       idx = ((addr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
-       return mpol_shared_policy_lookup(&SHMEM_I(i)->policy, idx);
+       index = ((addr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
+       return mpol_shared_policy_lookup(&SHMEM_I(inode)->policy, index);
 }
 #endif
 
@@ -1593,7 +1145,7 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode
 
 #ifdef CONFIG_TMPFS
 static const struct inode_operations shmem_symlink_inode_operations;
-static const struct inode_operations shmem_symlink_inline_operations;
+static const struct inode_operations shmem_short_symlink_operations;
 
 static int
 shmem_write_begin(struct file *file, struct address_space *mapping,
@@ -1626,7 +1178,8 @@ static void do_shmem_file_read(struct file *filp, loff_t *ppos, read_descriptor_
 {
        struct inode *inode = filp->f_path.dentry->d_inode;
        struct address_space *mapping = inode->i_mapping;
-       unsigned long index, offset;
+       pgoff_t index;
+       unsigned long offset;
        enum sgp_type sgp = SGP_READ;
 
        /*
@@ -1642,7 +1195,8 @@ static void do_shmem_file_read(struct file *filp, loff_t *ppos, read_descriptor_
 
        for (;;) {
                struct page *page = NULL;
-               unsigned long end_index, nr, ret;
+               pgoff_t end_index;
+               unsigned long nr, ret;
                loff_t i_size = i_size_read(inode);
 
                end_index = i_size >> PAGE_CACHE_SHIFT;
@@ -1880,8 +1434,9 @@ static int shmem_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_namelen = NAME_MAX;
        if (sbinfo->max_blocks) {
                buf->f_blocks = sbinfo->max_blocks;
-               buf->f_bavail = buf->f_bfree =
-                               sbinfo->max_blocks - percpu_counter_sum(&sbinfo->used_blocks);
+               buf->f_bavail =
+               buf->f_bfree  = sbinfo->max_blocks -
+                               percpu_counter_sum(&sbinfo->used_blocks);
        }
        if (sbinfo->max_inodes) {
                buf->f_files = sbinfo->max_inodes;
@@ -2055,10 +1610,13 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
 
        info = SHMEM_I(inode);
        inode->i_size = len-1;
-       if (len <= SHMEM_SYMLINK_INLINE_LEN) {
-               /* do it inline */
-               memcpy(info->inline_symlink, symname, len);
-               inode->i_op = &shmem_symlink_inline_operations;
+       if (len <= SHORT_SYMLINK_LEN) {
+               info->symlink = kmemdup(symname, len, GFP_KERNEL);
+               if (!info->symlink) {
+                       iput(inode);
+                       return -ENOMEM;
+               }
+               inode->i_op = &shmem_short_symlink_operations;
        } else {
                error = shmem_getpage(inode, 0, &page, SGP_WRITE, NULL);
                if (error) {
@@ -2081,17 +1639,17 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
        return 0;
 }
 
-static void *shmem_follow_link_inline(struct dentry *dentry, struct nameidata *nd)
+static void *shmem_follow_short_symlink(struct dentry *dentry, struct nameidata *nd)
 {
-       nd_set_link(nd, SHMEM_I(dentry->d_inode)->inline_symlink);
+       nd_set_link(nd, SHMEM_I(dentry->d_inode)->symlink);
        return NULL;
 }
 
 static void *shmem_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
        struct page *page = NULL;
-       int res = shmem_getpage(dentry->d_inode, 0, &page, SGP_READ, NULL);
-       nd_set_link(nd, res ? ERR_PTR(res) : kmap(page));
+       int error = shmem_getpage(dentry->d_inode, 0, &page, SGP_READ, NULL);
+       nd_set_link(nd, error ? ERR_PTR(error) : kmap(page));
        if (page)
                unlock_page(page);
        return page;
@@ -2202,7 +1760,6 @@ out:
        return err;
 }
 
-
 static const struct xattr_handler *shmem_xattr_handlers[] = {
 #ifdef CONFIG_TMPFS_POSIX_ACL
        &generic_acl_access_handler,
@@ -2332,9 +1889,9 @@ static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size)
 }
 #endif /* CONFIG_TMPFS_XATTR */
 
-static const struct inode_operations shmem_symlink_inline_operations = {
+static const struct inode_operations shmem_short_symlink_operations = {
        .readlink       = generic_readlink,
-       .follow_link    = shmem_follow_link_inline,
+       .follow_link    = shmem_follow_short_symlink,
 #ifdef CONFIG_TMPFS_XATTR
        .setxattr       = shmem_setxattr,
        .getxattr       = shmem_getxattr,
@@ -2534,8 +2091,7 @@ static int shmem_remount_fs(struct super_block *sb, int *flags, char *data)
        if (config.max_inodes < inodes)
                goto out;
        /*
-        * Those tests also disallow limited->unlimited while any are in
-        * use, so i_blocks will always be zero when max_blocks is zero;
+        * Those tests disallow limited->unlimited while any are in use;
         * but we must separately disallow unlimited->limited, because
         * in that case we have no record of how much is already in use.
         */
@@ -2627,7 +2183,7 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent)
                goto failed;
        sbinfo->free_inodes = sbinfo->max_inodes;
 
-       sb->s_maxbytes = SHMEM_MAX_BYTES;
+       sb->s_maxbytes = MAX_LFS_FILESIZE;
        sb->s_blocksize = PAGE_CACHE_SIZE;
        sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
        sb->s_magic = TMPFS_MAGIC;
@@ -2662,14 +2218,14 @@ static struct kmem_cache *shmem_inode_cachep;
 
 static struct inode *shmem_alloc_inode(struct super_block *sb)
 {
-       struct shmem_inode_info *p;
-       p = (struct shmem_inode_info *)kmem_cache_alloc(shmem_inode_cachep, GFP_KERNEL);
-       if (!p)
+       struct shmem_inode_info *info;
+       info = kmem_cache_alloc(shmem_inode_cachep, GFP_KERNEL);
+       if (!info)
                return NULL;
-       return &p->vfs_inode;
+       return &info->vfs_inode;
 }
 
-static void shmem_i_callback(struct rcu_head *head)
+static void shmem_destroy_callback(struct rcu_head *head)
 {
        struct inode *inode = container_of(head, struct inode, i_rcu);
        INIT_LIST_HEAD(&inode->i_dentry);
@@ -2678,29 +2234,26 @@ static void shmem_i_callback(struct rcu_head *head)
 
 static void shmem_destroy_inode(struct inode *inode)
 {
-       if ((inode->i_mode & S_IFMT) == S_IFREG) {
-               /* only struct inode is valid if it's an inline symlink */
+       if ((inode->i_mode & S_IFMT) == S_IFREG)
                mpol_free_shared_policy(&SHMEM_I(inode)->policy);
-       }
-       call_rcu(&inode->i_rcu, shmem_i_callback);
+       call_rcu(&inode->i_rcu, shmem_destroy_callback);
 }
 
-static void init_once(void *foo)
+static void shmem_init_inode(void *foo)
 {
-       struct shmem_inode_info *p = (struct shmem_inode_info *) foo;
-
-       inode_init_once(&p->vfs_inode);
+       struct shmem_inode_info *info = foo;
+       inode_init_once(&info->vfs_inode);
 }
 
-static int init_inodecache(void)
+static int shmem_init_inodecache(void)
 {
        shmem_inode_cachep = kmem_cache_create("shmem_inode_cache",
                                sizeof(struct shmem_inode_info),
-                               0, SLAB_PANIC, init_once);
+                               0, SLAB_PANIC, shmem_init_inode);
        return 0;
 }
 
-static void destroy_inodecache(void)
+static void shmem_destroy_inodecache(void)
 {
        kmem_cache_destroy(shmem_inode_cachep);
 }
@@ -2797,21 +2350,20 @@ static const struct vm_operations_struct shmem_vm_ops = {
 #endif
 };
 
-
 static struct dentry *shmem_mount(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *data)
 {
        return mount_nodev(fs_type, flags, data, shmem_fill_super);
 }
 
-static struct file_system_type tmpfs_fs_type = {
+static struct file_system_type shmem_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "tmpfs",
        .mount          = shmem_mount,
        .kill_sb        = kill_litter_super,
 };
 
-int __init init_tmpfs(void)
+int __init shmem_init(void)
 {
        int error;
 
@@ -2819,18 +2371,18 @@ int __init init_tmpfs(void)
        if (error)
                goto out4;
 
-       error = init_inodecache();
+       error = shmem_init_inodecache();
        if (error)
                goto out3;
 
-       error = register_filesystem(&tmpfs_fs_type);
+       error = register_filesystem(&shmem_fs_type);
        if (error) {
                printk(KERN_ERR "Could not register tmpfs\n");
                goto out2;
        }
 
-       shm_mnt = vfs_kern_mount(&tmpfs_fs_type, MS_NOUSER,
-                               tmpfs_fs_type.name, NULL);
+       shm_mnt = vfs_kern_mount(&shmem_fs_type, MS_NOUSER,
+                                shmem_fs_type.name, NULL);
        if (IS_ERR(shm_mnt)) {
                error = PTR_ERR(shm_mnt);
                printk(KERN_ERR "Could not kern_mount tmpfs\n");
@@ -2839,9 +2391,9 @@ int __init init_tmpfs(void)
        return 0;
 
 out1:
-       unregister_filesystem(&tmpfs_fs_type);
+       unregister_filesystem(&shmem_fs_type);
 out2:
-       destroy_inodecache();
+       shmem_destroy_inodecache();
 out3:
        bdi_destroy(&shmem_backing_dev_info);
 out4:
@@ -2849,45 +2401,6 @@ out4:
        return error;
 }
 
-#ifdef CONFIG_CGROUP_MEM_RES_CTLR
-/**
- * mem_cgroup_get_shmem_target - find a page or entry assigned to the shmem file
- * @inode: the inode to be searched
- * @pgoff: the offset to be searched
- * @pagep: the pointer for the found page to be stored
- * @ent: the pointer for the found swap entry to be stored
- *
- * If a page is found, refcount of it is incremented. Callers should handle
- * these refcount.
- */
-void mem_cgroup_get_shmem_target(struct inode *inode, pgoff_t pgoff,
-                                       struct page **pagep, swp_entry_t *ent)
-{
-       swp_entry_t entry = { .val = 0 }, *ptr;
-       struct page *page = NULL;
-       struct shmem_inode_info *info = SHMEM_I(inode);
-
-       if ((pgoff << PAGE_CACHE_SHIFT) >= i_size_read(inode))
-               goto out;
-
-       spin_lock(&info->lock);
-       ptr = shmem_swp_entry(info, pgoff, NULL);
-#ifdef CONFIG_SWAP
-       if (ptr && ptr->val) {
-               entry.val = ptr->val;
-               page = find_get_page(&swapper_space, entry.val);
-       } else
-#endif
-               page = find_get_page(inode->i_mapping, pgoff);
-       if (ptr)
-               shmem_swp_unmap(ptr);
-       spin_unlock(&info->lock);
-out:
-       *pagep = page;
-       *ent = entry;
-}
-#endif
-
 #else /* !CONFIG_SHMEM */
 
 /*
@@ -2901,23 +2414,23 @@ out:
 
 #include <linux/ramfs.h>
 
-static struct file_system_type tmpfs_fs_type = {
+static struct file_system_type shmem_fs_type = {
        .name           = "tmpfs",
        .mount          = ramfs_mount,
        .kill_sb        = kill_litter_super,
 };
 
-int __init init_tmpfs(void)
+int __init shmem_init(void)
 {
-       BUG_ON(register_filesystem(&tmpfs_fs_type) != 0);
+       BUG_ON(register_filesystem(&shmem_fs_type) != 0);
 
-       shm_mnt = kern_mount(&tmpfs_fs_type);
+       shm_mnt = kern_mount(&shmem_fs_type);
        BUG_ON(IS_ERR(shm_mnt));
 
        return 0;
 }
 
-int shmem_unuse(swp_entry_t entry, struct page *page)
+int shmem_unuse(swp_entry_t swap, struct page *page)
 {
        return 0;
 }
@@ -2927,43 +2440,17 @@ int shmem_lock(struct file *file, int lock, struct user_struct *user)
        return 0;
 }
 
-void shmem_truncate_range(struct inode *inode, loff_t start, loff_t end)
+void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend)
 {
-       truncate_inode_pages_range(inode->i_mapping, start, end);
+       truncate_inode_pages_range(inode->i_mapping, lstart, lend);
 }
 EXPORT_SYMBOL_GPL(shmem_truncate_range);
 
-#ifdef CONFIG_CGROUP_MEM_RES_CTLR
-/**
- * mem_cgroup_get_shmem_target - find a page or entry assigned to the shmem file
- * @inode: the inode to be searched
- * @pgoff: the offset to be searched
- * @pagep: the pointer for the found page to be stored
- * @ent: the pointer for the found swap entry to be stored
- *
- * If a page is found, refcount of it is incremented. Callers should handle
- * these refcount.
- */
-void mem_cgroup_get_shmem_target(struct inode *inode, pgoff_t pgoff,
-                                       struct page **pagep, swp_entry_t *ent)
-{
-       struct page *page = NULL;
-
-       if ((pgoff << PAGE_CACHE_SHIFT) >= i_size_read(inode))
-               goto out;
-       page = find_get_page(inode->i_mapping, pgoff);
-out:
-       *pagep = page;
-       *ent = (swp_entry_t){ .val = 0 };
-}
-#endif
-
 #define shmem_vm_ops                           generic_file_vm_ops
 #define shmem_file_operations                  ramfs_file_operations
 #define shmem_get_inode(sb, dir, mode, dev, flags)     ramfs_get_inode(sb, dir, mode, dev)
 #define shmem_acct_size(flags, size)           0
 #define shmem_unacct_size(flags, size)         do {} while (0)
-#define SHMEM_MAX_BYTES                                MAX_LFS_FILESIZE
 
 #endif /* CONFIG_SHMEM */
 
@@ -2987,7 +2474,7 @@ struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags
        if (IS_ERR(shm_mnt))
                return (void *)shm_mnt;
 
-       if (size < 0 || size > SHMEM_MAX_BYTES)
+       if (size < 0 || size > MAX_LFS_FILESIZE)
                return ERR_PTR(-EINVAL);
 
        if (shmem_acct_size(flags, size))
index 1e523ed..6d90a09 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -622,6 +622,51 @@ int slab_is_available(void)
 static struct lock_class_key on_slab_l3_key;
 static struct lock_class_key on_slab_alc_key;
 
+static struct lock_class_key debugobj_l3_key;
+static struct lock_class_key debugobj_alc_key;
+
+static void slab_set_lock_classes(struct kmem_cache *cachep,
+               struct lock_class_key *l3_key, struct lock_class_key *alc_key,
+               int q)
+{
+       struct array_cache **alc;
+       struct kmem_list3 *l3;
+       int r;
+
+       l3 = cachep->nodelists[q];
+       if (!l3)
+               return;
+
+       lockdep_set_class(&l3->list_lock, l3_key);
+       alc = l3->alien;
+       /*
+        * FIXME: This check for BAD_ALIEN_MAGIC
+        * should go away when common slab code is taught to
+        * work even without alien caches.
+        * Currently, non NUMA code returns BAD_ALIEN_MAGIC
+        * for alloc_alien_cache,
+        */
+       if (!alc || (unsigned long)alc == BAD_ALIEN_MAGIC)
+               return;
+       for_each_node(r) {
+               if (alc[r])
+                       lockdep_set_class(&alc[r]->lock, alc_key);
+       }
+}
+
+static void slab_set_debugobj_lock_classes_node(struct kmem_cache *cachep, int node)
+{
+       slab_set_lock_classes(cachep, &debugobj_l3_key, &debugobj_alc_key, node);
+}
+
+static void slab_set_debugobj_lock_classes(struct kmem_cache *cachep)
+{
+       int node;
+
+       for_each_online_node(node)
+               slab_set_debugobj_lock_classes_node(cachep, node);
+}
+
 static void init_node_lock_keys(int q)
 {
        struct cache_sizes *s = malloc_sizes;
@@ -630,29 +675,14 @@ static void init_node_lock_keys(int q)
                return;
 
        for (s = malloc_sizes; s->cs_size != ULONG_MAX; s++) {
-               struct array_cache **alc;
                struct kmem_list3 *l3;
-               int r;
 
                l3 = s->cs_cachep->nodelists[q];
                if (!l3 || OFF_SLAB(s->cs_cachep))
                        continue;
-               lockdep_set_class(&l3->list_lock, &on_slab_l3_key);
-               alc = l3->alien;
-               /*
-                * FIXME: This check for BAD_ALIEN_MAGIC
-                * should go away when common slab code is taught to
-                * work even without alien caches.
-                * Currently, non NUMA code returns BAD_ALIEN_MAGIC
-                * for alloc_alien_cache,
-                */
-               if (!alc || (unsigned long)alc == BAD_ALIEN_MAGIC)
-                       continue;
-               for_each_node(r) {
-                       if (alc[r])
-                               lockdep_set_class(&alc[r]->lock,
-                                       &on_slab_alc_key);
-               }
+
+               slab_set_lock_classes(s->cs_cachep, &on_slab_l3_key,
+                               &on_slab_alc_key, q);
        }
 }
 
@@ -671,6 +701,14 @@ static void init_node_lock_keys(int q)
 static inline void init_lock_keys(void)
 {
 }
+
+static void slab_set_debugobj_lock_classes_node(struct kmem_cache *cachep, int node)
+{
+}
+
+static void slab_set_debugobj_lock_classes(struct kmem_cache *cachep)
+{
+}
 #endif
 
 /*
@@ -1264,6 +1302,8 @@ static int __cpuinit cpuup_prepare(long cpu)
                spin_unlock_irq(&l3->list_lock);
                kfree(shared);
                free_alien_cache(alien);
+               if (cachep->flags & SLAB_DEBUG_OBJECTS)
+                       slab_set_debugobj_lock_classes_node(cachep, node);
        }
        init_node_lock_keys(node);
 
@@ -1626,6 +1666,9 @@ void __init kmem_cache_init_late(void)
 {
        struct kmem_cache *cachep;
 
+       /* Annotate slab for lockdep -- annotate the malloc caches */
+       init_lock_keys();
+
        /* 6) resize the head arrays to their final sizes */
        mutex_lock(&cache_chain_mutex);
        list_for_each_entry(cachep, &cache_chain, next)
@@ -1636,9 +1679,6 @@ void __init kmem_cache_init_late(void)
        /* Done! */
        g_cpucache_up = FULL;
 
-       /* Annotate slab for lockdep -- annotate the malloc caches */
-       init_lock_keys();
-
        /*
         * Register a cpu startup notifier callback that initializes
         * cpu_cache_get for all new cpus
@@ -2426,6 +2466,16 @@ kmem_cache_create (const char *name, size_t size, size_t align,
                goto oops;
        }
 
+       if (flags & SLAB_DEBUG_OBJECTS) {
+               /*
+                * Would deadlock through slab_destroy()->call_rcu()->
+                * debug_object_activate()->kmem_cache_alloc().
+                */
+               WARN_ON_ONCE(flags & SLAB_DESTROY_BY_RCU);
+
+               slab_set_debugobj_lock_classes(cachep);
+       }
+
        /* cache setup completed, link it into the list */
        list_add(&cachep->next, &cache_chain);
 oops:
@@ -3403,7 +3453,7 @@ __cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid,
        cache_alloc_debugcheck_before(cachep, flags);
        local_irq_save(save_flags);
 
-       if (nodeid == -1)
+       if (nodeid == NUMA_NO_NODE)
                nodeid = slab_node;
 
        if (unlikely(!cachep->nodelists[nodeid])) {
@@ -3934,7 +3984,7 @@ fail:
 
 struct ccupdate_struct {
        struct kmem_cache *cachep;
-       struct array_cache *new[NR_CPUS];
+       struct array_cache *new[0];
 };
 
 static void do_ccupdate_local(void *info)
@@ -3956,7 +4006,8 @@ static int do_tune_cpucache(struct kmem_cache *cachep, int limit,
        struct ccupdate_struct *new;
        int i;
 
-       new = kzalloc(sizeof(*new), gfp);
+       new = kzalloc(sizeof(*new) + nr_cpu_ids * sizeof(struct array_cache *),
+                     gfp);
        if (!new)
                return -ENOMEM;
 
index f8f5e8e..9f662d7 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -2,10 +2,11 @@
  * SLUB: A slab allocator that limits cache line use instead of queuing
  * objects in per cpu and per node lists.
  *
- * The allocator synchronizes using per slab locks and only
- * uses a centralized lock to manage a pool of partial slabs.
+ * The allocator synchronizes using per slab locks or atomic operatios
+ * and only uses a centralized lock to manage a pool of partial slabs.
  *
  * (C) 2007 SGI, Christoph Lameter
+ * (C) 2011 Linux Foundation, Christoph Lameter
  */
 
 #include <linux/mm.h>
 
 /*
  * Lock order:
- *   1. slab_lock(page)
- *   2. slab->list_lock
+ *   1. slub_lock (Global Semaphore)
+ *   2. node->list_lock
+ *   3. slab_lock(page) (Only on some arches and for debugging)
  *
- *   The slab_lock protects operations on the object of a particular
- *   slab and its metadata in the page struct. If the slab lock
- *   has been taken then no allocations nor frees can be performed
- *   on the objects in the slab nor can the slab be added or removed
- *   from the partial or full lists since this would mean modifying
- *   the page_struct of the slab.
+ *   slub_lock
+ *
+ *   The role of the slub_lock is to protect the list of all the slabs
+ *   and to synchronize major metadata changes to slab cache structures.
+ *
+ *   The slab_lock is only used for debugging and on arches that do not
+ *   have the ability to do a cmpxchg_double. It only protects the second
+ *   double word in the page struct. Meaning
+ *     A. page->freelist       -> List of object free in a page
+ *     B. page->counters       -> Counters of objects
+ *     C. page->frozen         -> frozen state
+ *
+ *   If a slab is frozen then it is exempt from list management. It is not
+ *   on any list. The processor that froze the slab is the one who can
+ *   perform list operations on the page. Other processors may put objects
+ *   onto the freelist but the processor that froze the slab is the only
+ *   one that can retrieve the objects from the page's freelist.
  *
  *   The list_lock protects the partial and full list on each node and
  *   the partial slab counter. If taken then no new slabs may be added or
  *   slabs, operations can continue without any centralized lock. F.e.
  *   allocating a long series of objects that fill up slabs does not require
  *   the list lock.
- *
- *   The lock order is sometimes inverted when we are trying to get a slab
- *   off a list. We take the list_lock and then look for a page on the list
- *   to use. While we do that objects in the slabs may be freed. We can
- *   only operate on the slab if we have also taken the slab_lock. So we use
- *   a slab_trylock() on the slab. If trylock was successful then no frees
- *   can occur anymore and we can use the slab for allocations etc. If the
- *   slab_trylock() does not succeed then frees are in progress in the slab and
- *   we must stay away from it for a while since we may cause a bouncing
- *   cacheline if we try to acquire the lock. So go onto the next slab.
- *   If all pages are busy then we may allocate a new slab instead of reusing
- *   a partial slab. A new slab has no one operating on it and thus there is
- *   no danger of cacheline contention.
- *
  *   Interrupts are disabled during allocation and deallocation in order to
  *   make the slab allocator safe to use in the context of an irq. In addition
  *   interrupts are disabled to ensure that the processor does not change
@@ -132,6 +131,9 @@ static inline int kmem_cache_debug(struct kmem_cache *s)
 /* Enable to test recovery from slab corruption on boot */
 #undef SLUB_RESILIENCY_TEST
 
+/* Enable to log cmpxchg failures */
+#undef SLUB_DEBUG_CMPXCHG
+
 /*
  * Mininum number of partial slabs. These will be left on the partial
  * lists even if they are empty. kmem_cache_shrink may reclaim them.
@@ -167,10 +169,11 @@ static inline int kmem_cache_debug(struct kmem_cache *s)
 
 #define OO_SHIFT       16
 #define OO_MASK                ((1 << OO_SHIFT) - 1)
-#define MAX_OBJS_PER_PAGE      65535 /* since page.objects is u16 */
+#define MAX_OBJS_PER_PAGE      32767 /* since page.objects is u15 */
 
 /* Internal SLUB flags */
 #define __OBJECT_POISON                0x80000000UL /* Poison object */
+#define __CMPXCHG_DOUBLE       0x40000000UL /* Use cmpxchg_double */
 
 static int kmem_size = sizeof(struct kmem_cache);
 
@@ -343,11 +346,99 @@ static inline int oo_objects(struct kmem_cache_order_objects x)
        return x.x & OO_MASK;
 }
 
+/*
+ * Per slab locking using the pagelock
+ */
+static __always_inline void slab_lock(struct page *page)
+{
+       bit_spin_lock(PG_locked, &page->flags);
+}
+
+static __always_inline void slab_unlock(struct page *page)
+{
+       __bit_spin_unlock(PG_locked, &page->flags);
+}
+
+/* Interrupts must be disabled (for the fallback code to work right) */
+static inline bool __cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
+               void *freelist_old, unsigned long counters_old,
+               void *freelist_new, unsigned long counters_new,
+               const char *n)
+{
+       VM_BUG_ON(!irqs_disabled());
+#ifdef CONFIG_CMPXCHG_DOUBLE
+       if (s->flags & __CMPXCHG_DOUBLE) {
+               if (cmpxchg_double(&page->freelist,
+                       freelist_old, counters_old,
+                       freelist_new, counters_new))
+               return 1;
+       } else
+#endif
+       {
+               slab_lock(page);
+               if (page->freelist == freelist_old && page->counters == counters_old) {
+                       page->freelist = freelist_new;
+                       page->counters = counters_new;
+                       slab_unlock(page);
+                       return 1;
+               }
+               slab_unlock(page);
+       }
+
+       cpu_relax();
+       stat(s, CMPXCHG_DOUBLE_FAIL);
+
+#ifdef SLUB_DEBUG_CMPXCHG
+       printk(KERN_INFO "%s %s: cmpxchg double redo ", n, s->name);
+#endif
+
+       return 0;
+}
+
+static inline bool cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
+               void *freelist_old, unsigned long counters_old,
+               void *freelist_new, unsigned long counters_new,
+               const char *n)
+{
+#ifdef CONFIG_CMPXCHG_DOUBLE
+       if (s->flags & __CMPXCHG_DOUBLE) {
+               if (cmpxchg_double(&page->freelist,
+                       freelist_old, counters_old,
+                       freelist_new, counters_new))
+               return 1;
+       } else
+#endif
+       {
+               unsigned long flags;
+
+               local_irq_save(flags);
+               slab_lock(page);
+               if (page->freelist == freelist_old && page->counters == counters_old) {
+                       page->freelist = freelist_new;
+                       page->counters = counters_new;
+                       slab_unlock(page);
+                       local_irq_restore(flags);
+                       return 1;
+               }
+               slab_unlock(page);
+               local_irq_restore(flags);
+       }
+
+       cpu_relax();
+       stat(s, CMPXCHG_DOUBLE_FAIL);
+
+#ifdef SLUB_DEBUG_CMPXCHG
+       printk(KERN_INFO "%s %s: cmpxchg double redo ", n, s->name);
+#endif
+
+       return 0;
+}
+
 #ifdef CONFIG_SLUB_DEBUG
 /*
  * Determine a map of object in use on a page.
  *
- * Slab lock or node listlock must be held to guarantee that the page does
+ * Node listlock must be held to guarantee that the page does
  * not vanish from under us.
  */
 static void get_map(struct kmem_cache *s, struct page *page, unsigned long *map)
@@ -610,7 +701,7 @@ static u8 *check_bytes(u8 *start, u8 value, unsigned int bytes)
                return check_bytes8(start, value, bytes);
 
        value64 = value | value << 8 | value << 16 | value << 24;
-       value64 = value64 | value64 << 32;
+       value64 = (value64 & 0xffffffff) | value64 << 32;
        prefix = 8 - ((unsigned long)start) % 8;
 
        if (prefix) {
@@ -838,10 +929,11 @@ static int check_slab(struct kmem_cache *s, struct page *page)
 static int on_freelist(struct kmem_cache *s, struct page *page, void *search)
 {
        int nr = 0;
-       void *fp = page->freelist;
+       void *fp;
        void *object = NULL;
        unsigned long max_objects;
 
+       fp = page->freelist;
        while (fp && nr <= page->objects) {
                if (fp == search)
                        return 1;
@@ -946,26 +1038,27 @@ static inline void slab_free_hook(struct kmem_cache *s, void *x)
 
 /*
  * Tracking of fully allocated slabs for debugging purposes.
+ *
+ * list_lock must be held.
  */
-static void add_full(struct kmem_cache_node *n, struct page *page)
+static void add_full(struct kmem_cache *s,
+       struct kmem_cache_node *n, struct page *page)
 {
-       spin_lock(&n->list_lock);
+       if (!(s->flags & SLAB_STORE_USER))
+               return;
+
        list_add(&page->lru, &n->full);
-       spin_unlock(&n->list_lock);
 }
 
+/*
+ * list_lock must be held.
+ */
 static void remove_full(struct kmem_cache *s, struct page *page)
 {
-       struct kmem_cache_node *n;
-
        if (!(s->flags & SLAB_STORE_USER))
                return;
 
-       n = get_node(s, page_to_nid(page));
-
-       spin_lock(&n->list_lock);
        list_del(&page->lru);
-       spin_unlock(&n->list_lock);
 }
 
 /* Tracking of the number of slabs for debugging purposes */
@@ -1021,11 +1114,6 @@ static noinline int alloc_debug_processing(struct kmem_cache *s, struct page *pa
        if (!check_slab(s, page))
                goto bad;
 
-       if (!on_freelist(s, page, object)) {
-               object_err(s, page, object, "Object already allocated");
-               goto bad;
-       }
-
        if (!check_valid_pointer(s, page, object)) {
                object_err(s, page, object, "Freelist Pointer check fails");
                goto bad;
@@ -1058,6 +1146,12 @@ bad:
 static noinline int free_debug_processing(struct kmem_cache *s,
                 struct page *page, void *object, unsigned long addr)
 {
+       unsigned long flags;
+       int rc = 0;
+
+       local_irq_save(flags);
+       slab_lock(page);
+
        if (!check_slab(s, page))
                goto fail;
 
@@ -1072,7 +1166,7 @@ static noinline int free_debug_processing(struct kmem_cache *s,
        }
 
        if (!check_object(s, page, object, SLUB_RED_ACTIVE))
-               return 0;
+               goto out;
 
        if (unlikely(s != page->slab)) {
                if (!PageSlab(page)) {
@@ -1089,18 +1183,19 @@ static noinline int free_debug_processing(struct kmem_cache *s,
                goto fail;
        }
 
-       /* Special debug activities for freeing objects */
-       if (!PageSlubFrozen(page) && !page->freelist)
-               remove_full(s, page);
        if (s->flags & SLAB_STORE_USER)
                set_track(s, object, TRACK_FREE, addr);
        trace(s, page, object, 0);
        init_object(s, object, SLUB_RED_INACTIVE);
-       return 1;
+       rc = 1;
+out:
+       slab_unlock(page);
+       local_irq_restore(flags);
+       return rc;
 
 fail:
        slab_fix(s, "Object at 0x%p not freed", object);
-       return 0;
+       goto out;
 }
 
 static int __init setup_slub_debug(char *str)
@@ -1200,7 +1295,9 @@ static inline int slab_pad_check(struct kmem_cache *s, struct page *page)
                        { return 1; }
 static inline int check_object(struct kmem_cache *s, struct page *page,
                        void *object, u8 val) { return 1; }
-static inline void add_full(struct kmem_cache_node *n, struct page *page) {}
+static inline void add_full(struct kmem_cache *s, struct kmem_cache_node *n,
+                                       struct page *page) {}
+static inline void remove_full(struct kmem_cache *s, struct page *page) {}
 static inline unsigned long kmem_cache_flags(unsigned long objsize,
        unsigned long flags, const char *name,
        void (*ctor)(void *))
@@ -1252,6 +1349,11 @@ static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
        struct kmem_cache_order_objects oo = s->oo;
        gfp_t alloc_gfp;
 
+       flags &= gfp_allowed_mask;
+
+       if (flags & __GFP_WAIT)
+               local_irq_enable();
+
        flags |= s->allocflags;
 
        /*
@@ -1268,12 +1370,17 @@ static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
                 * Try a lower order alloc if possible
                 */
                page = alloc_slab_page(flags, node, oo);
-               if (!page)
-                       return NULL;
 
-               stat(s, ORDER_FALLBACK);
+               if (page)
+                       stat(s, ORDER_FALLBACK);
        }
 
+       if (flags & __GFP_WAIT)
+               local_irq_disable();
+
+       if (!page)
+               return NULL;
+
        if (kmemcheck_enabled
                && !(s->flags & (SLAB_NOTRACK | DEBUG_DEFAULT_FLAGS))) {
                int pages = 1 << oo_order(oo);
@@ -1341,6 +1448,7 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
 
        page->freelist = start;
        page->inuse = 0;
+       page->frozen = 1;
 out:
        return page;
 }
@@ -1418,77 +1526,87 @@ static void discard_slab(struct kmem_cache *s, struct page *page)
 }
 
 /*
- * Per slab locking using the pagelock
- */
-static __always_inline void slab_lock(struct page *page)
-{
-       bit_spin_lock(PG_locked, &page->flags);
-}
-
-static __always_inline void slab_unlock(struct page *page)
-{
-       __bit_spin_unlock(PG_locked, &page->flags);
-}
-
-static __always_inline int slab_trylock(struct page *page)
-{
-       int rc = 1;
-
-       rc = bit_spin_trylock(PG_locked, &page->flags);
-       return rc;
-}
-
-/*
- * Management of partially allocated slabs
+ * Management of partially allocated slabs.
+ *
+ * list_lock must be held.
  */
-static void add_partial(struct kmem_cache_node *n,
+static inline void add_partial(struct kmem_cache_node *n,
                                struct page *page, int tail)
 {
-       spin_lock(&n->list_lock);
        n->nr_partial++;
        if (tail)
                list_add_tail(&page->lru, &n->partial);
        else
                list_add(&page->lru, &n->partial);
-       spin_unlock(&n->list_lock);
 }
 
-static inline void __remove_partial(struct kmem_cache_node *n,
+/*
+ * list_lock must be held.
+ */
+static inline void remove_partial(struct kmem_cache_node *n,
                                        struct page *page)
 {
        list_del(&page->lru);
        n->nr_partial--;
 }
 
-static void remove_partial(struct kmem_cache *s, struct page *page)
-{
-       struct kmem_cache_node *n = get_node(s, page_to_nid(page));
-
-       spin_lock(&n->list_lock);
-       __remove_partial(n, page);
-       spin_unlock(&n->list_lock);
-}
-
 /*
- * Lock slab and remove from the partial list.
+ * Lock slab, remove from the partial list and put the object into the
+ * per cpu freelist.
  *
  * Must hold list_lock.
  */
-static inline int lock_and_freeze_slab(struct kmem_cache_node *n,
-                                                       struct page *page)
+static inline int acquire_slab(struct kmem_cache *s,
+               struct kmem_cache_node *n, struct page *page)
 {
-       if (slab_trylock(page)) {
-               __remove_partial(n, page);
-               __SetPageSlubFrozen(page);
+       void *freelist;
+       unsigned long counters;
+       struct page new;
+
+       /*
+        * Zap the freelist and set the frozen bit.
+        * The old freelist is the list of objects for the
+        * per cpu allocation list.
+        */
+       do {
+               freelist = page->freelist;
+               counters = page->counters;
+               new.counters = counters;
+               new.inuse = page->objects;
+
+               VM_BUG_ON(new.frozen);
+               new.frozen = 1;
+
+       } while (!__cmpxchg_double_slab(s, page,
+                       freelist, counters,
+                       NULL, new.counters,
+                       "lock and freeze"));
+
+       remove_partial(n, page);
+
+       if (freelist) {
+               /* Populate the per cpu freelist */
+               this_cpu_write(s->cpu_slab->freelist, freelist);
+               this_cpu_write(s->cpu_slab->page, page);
+               this_cpu_write(s->cpu_slab->node, page_to_nid(page));
                return 1;
+       } else {
+               /*
+                * Slab page came from the wrong list. No object to allocate
+                * from. Put it onto the correct list and continue partial
+                * scan.
+                */
+               printk(KERN_ERR "SLUB: %s : Page without available objects on"
+                       " partial list\n", s->name);
+               return 0;
        }
-       return 0;
 }
 
 /*
  * Try to allocate a partial slab from a specific node.
  */
-static struct page *get_partial_node(struct kmem_cache_node *n)
+static struct page *get_partial_node(struct kmem_cache *s,
+                                       struct kmem_cache_node *n)
 {
        struct page *page;
 
@@ -1503,7 +1621,7 @@ static struct page *get_partial_node(struct kmem_cache_node *n)
 
        spin_lock(&n->list_lock);
        list_for_each_entry(page, &n->partial, lru)
-               if (lock_and_freeze_slab(n, page))
+               if (acquire_slab(s, n, page))
                        goto out;
        page = NULL;
 out:
@@ -1554,7 +1672,7 @@ static struct page *get_any_partial(struct kmem_cache *s, gfp_t flags)
 
                if (n && cpuset_zone_allowed_hardwall(zone, flags) &&
                                n->nr_partial > s->min_partial) {
-                       page = get_partial_node(n);
+                       page = get_partial_node(s, n);
                        if (page) {
                                put_mems_allowed();
                                return page;
@@ -1574,60 +1692,13 @@ static struct page *get_partial(struct kmem_cache *s, gfp_t flags, int node)
        struct page *page;
        int searchnode = (node == NUMA_NO_NODE) ? numa_node_id() : node;
 
-       page = get_partial_node(get_node(s, searchnode));
+       page = get_partial_node(s, get_node(s, searchnode));
        if (page || node != NUMA_NO_NODE)
                return page;
 
        return get_any_partial(s, flags);
 }
 
-/*
- * Move a page back to the lists.
- *
- * Must be called with the slab lock held.
- *
- * On exit the slab lock will have been dropped.
- */
-static void unfreeze_slab(struct kmem_cache *s, struct page *page, int tail)
-       __releases(bitlock)
-{
-       struct kmem_cache_node *n = get_node(s, page_to_nid(page));
-
-       __ClearPageSlubFrozen(page);
-       if (page->inuse) {
-
-               if (page->freelist) {
-                       add_partial(n, page, tail);
-                       stat(s, tail ? DEACTIVATE_TO_TAIL : DEACTIVATE_TO_HEAD);
-               } else {
-                       stat(s, DEACTIVATE_FULL);
-                       if (kmem_cache_debug(s) && (s->flags & SLAB_STORE_USER))
-                               add_full(n, page);
-               }
-               slab_unlock(page);
-       } else {
-               stat(s, DEACTIVATE_EMPTY);
-               if (n->nr_partial < s->min_partial) {
-                       /*
-                        * Adding an empty slab to the partial slabs in order
-                        * to avoid page allocator overhead. This slab needs
-                        * to come after the other slabs with objects in
-                        * so that the others get filled first. That way the
-                        * size of the partial list stays small.
-                        *
-                        * kmem_cache_shrink can reclaim any empty slabs from
-                        * the partial list.
-                        */
-                       add_partial(n, page, 1);
-                       slab_unlock(page);
-               } else {
-                       slab_unlock(page);
-                       stat(s, FREE_SLAB);
-                       discard_slab(s, page);
-               }
-       }
-}
-
 #ifdef CONFIG_PREEMPT
 /*
  * Calculate the next globally unique transaction for disambiguiation
@@ -1694,45 +1765,164 @@ void init_kmem_cache_cpus(struct kmem_cache *s)
        for_each_possible_cpu(cpu)
                per_cpu_ptr(s->cpu_slab, cpu)->tid = init_tid(cpu);
 }
+/*
+ * Remove the cpu slab
+ */
+
 /*
  * Remove the cpu slab
  */
 static void deactivate_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
-       __releases(bitlock)
 {
+       enum slab_modes { M_NONE, M_PARTIAL, M_FULL, M_FREE };
        struct page *page = c->page;
-       int tail = 1;
-
-       if (page->freelist)
+       struct kmem_cache_node *n = get_node(s, page_to_nid(page));
+       int lock = 0;
+       enum slab_modes l = M_NONE, m = M_NONE;
+       void *freelist;
+       void *nextfree;
+       int tail = 0;
+       struct page new;
+       struct page old;
+
+       if (page->freelist) {
                stat(s, DEACTIVATE_REMOTE_FREES);
+               tail = 1;
+       }
+
+       c->tid = next_tid(c->tid);
+       c->page = NULL;
+       freelist = c->freelist;
+       c->freelist = NULL;
+
        /*
-        * Merge cpu freelist into slab freelist. Typically we get here
-        * because both freelists are empty. So this is unlikely
-        * to occur.
+        * Stage one: Free all available per cpu objects back
+        * to the page freelist while it is still frozen. Leave the
+        * last one.
+        *
+        * There is no need to take the list->lock because the page
+        * is still frozen.
+        */
+       while (freelist && (nextfree = get_freepointer(s, freelist))) {
+               void *prior;
+               unsigned long counters;
+
+               do {
+                       prior = page->freelist;
+                       counters = page->counters;
+                       set_freepointer(s, freelist, prior);
+                       new.counters = counters;
+                       new.inuse--;
+                       VM_BUG_ON(!new.frozen);
+
+               } while (!__cmpxchg_double_slab(s, page,
+                       prior, counters,
+                       freelist, new.counters,
+                       "drain percpu freelist"));
+
+               freelist = nextfree;
+       }
+
+       /*
+        * Stage two: Ensure that the page is unfrozen while the
+        * list presence reflects the actual number of objects
+        * during unfreeze.
+        *
+        * We setup the list membership and then perform a cmpxchg
+        * with the count. If there is a mismatch then the page
+        * is not unfrozen but the page is on the wrong list.
+        *
+        * Then we restart the process which may have to remove
+        * the page from the list that we just put it on again
+        * because the number of objects in the slab may have
+        * changed.
         */
-       while (unlikely(c->freelist)) {
-               void **object;
+redo:
 
-               tail = 0;       /* Hot objects. Put the slab first */
+       old.freelist = page->freelist;
+       old.counters = page->counters;
+       VM_BUG_ON(!old.frozen);
 
-               /* Retrieve object from cpu_freelist */
-               object = c->freelist;
-               c->freelist = get_freepointer(s, c->freelist);
+       /* Determine target state of the slab */
+       new.counters = old.counters;
+       if (freelist) {
+               new.inuse--;
+               set_freepointer(s, freelist, old.freelist);
+               new.freelist = freelist;
+       } else
+               new.freelist = old.freelist;
 
-               /* And put onto the regular freelist */
-               set_freepointer(s, object, page->freelist);
-               page->freelist = object;
-               page->inuse--;
+       new.frozen = 0;
+
+       if (!new.inuse && n->nr_partial > s->min_partial)
+               m = M_FREE;
+       else if (new.freelist) {
+               m = M_PARTIAL;
+               if (!lock) {
+                       lock = 1;
+                       /*
+                        * Taking the spinlock removes the possiblity
+                        * that acquire_slab() will see a slab page that
+                        * is frozen
+                        */
+                       spin_lock(&n->list_lock);
+               }
+       } else {
+               m = M_FULL;
+               if (kmem_cache_debug(s) && !lock) {
+                       lock = 1;
+                       /*
+                        * This also ensures that the scanning of full
+                        * slabs from diagnostic functions will not see
+                        * any frozen slabs.
+                        */
+                       spin_lock(&n->list_lock);
+               }
+       }
+
+       if (l != m) {
+
+               if (l == M_PARTIAL)
+
+                       remove_partial(n, page);
+
+               else if (l == M_FULL)
+
+                       remove_full(s, page);
+
+               if (m == M_PARTIAL) {
+
+                       add_partial(n, page, tail);
+                       stat(s, tail ? DEACTIVATE_TO_TAIL : DEACTIVATE_TO_HEAD);
+
+               } else if (m == M_FULL) {
+
+                       stat(s, DEACTIVATE_FULL);
+                       add_full(s, n, page);
+
+               }
+       }
+
+       l = m;
+       if (!__cmpxchg_double_slab(s, page,
+                               old.freelist, old.counters,
+                               new.freelist, new.counters,
+                               "unfreezing slab"))
+               goto redo;
+
+       if (lock)
+               spin_unlock(&n->list_lock);
+
+       if (m == M_FREE) {
+               stat(s, DEACTIVATE_EMPTY);
+               discard_slab(s, page);
+               stat(s, FREE_SLAB);
        }
-       c->page = NULL;
-       c->tid = next_tid(c->tid);
-       unfreeze_slab(s, page, tail);
 }
 
 static inline void flush_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
 {
        stat(s, CPUSLAB_FLUSH);
-       slab_lock(c->page);
        deactivate_slab(s, c);
 }
 
@@ -1861,6 +2051,8 @@ static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
        void **object;
        struct page *page;
        unsigned long flags;
+       struct page new;
+       unsigned long counters;
 
        local_irq_save(flags);
 #ifdef CONFIG_PREEMPT
@@ -1879,72 +2071,97 @@ static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
        if (!page)
                goto new_slab;
 
-       slab_lock(page);
-       if (unlikely(!node_match(c, node)))
-               goto another_slab;
+       if (unlikely(!node_match(c, node))) {
+               stat(s, ALLOC_NODE_MISMATCH);
+               deactivate_slab(s, c);
+               goto new_slab;
+       }
+
+       stat(s, ALLOC_SLOWPATH);
+
+       do {
+               object = page->freelist;
+               counters = page->counters;
+               new.counters = counters;
+               VM_BUG_ON(!new.frozen);
+
+               /*
+                * If there is no object left then we use this loop to
+                * deactivate the slab which is simple since no objects
+                * are left in the slab and therefore we do not need to
+                * put the page back onto the partial list.
+                *
+                * If there are objects left then we retrieve them
+                * and use them to refill the per cpu queue.
+               */
+
+               new.inuse = page->objects;
+               new.frozen = object != NULL;
+
+       } while (!__cmpxchg_double_slab(s, page,
+                       object, counters,
+                       NULL, new.counters,
+                       "__slab_alloc"));
+
+       if (unlikely(!object)) {
+               c->page = NULL;
+               stat(s, DEACTIVATE_BYPASS);
+               goto new_slab;
+       }
 
        stat(s, ALLOC_REFILL);
 
 load_freelist:
-       object = page->freelist;
-       if (unlikely(!object))
-               goto another_slab;
-       if (kmem_cache_debug(s))
-               goto debug;
-
+       VM_BUG_ON(!page->frozen);
        c->freelist = get_freepointer(s, object);
-       page->inuse = page->objects;
-       page->freelist = NULL;
-
-       slab_unlock(page);
        c->tid = next_tid(c->tid);
        local_irq_restore(flags);
-       stat(s, ALLOC_SLOWPATH);
        return object;
 
-another_slab:
-       deactivate_slab(s, c);
-
 new_slab:
        page = get_partial(s, gfpflags, node);
        if (page) {
                stat(s, ALLOC_FROM_PARTIAL);
-               c->node = page_to_nid(page);
-               c->page = page;
+               object = c->freelist;
+
+               if (kmem_cache_debug(s))
+                       goto debug;
                goto load_freelist;
        }
 
-       gfpflags &= gfp_allowed_mask;
-       if (gfpflags & __GFP_WAIT)
-               local_irq_enable();
-
        page = new_slab(s, gfpflags, node);
 
-       if (gfpflags & __GFP_WAIT)
-               local_irq_disable();
-
        if (page) {
                c = __this_cpu_ptr(s->cpu_slab);
-               stat(s, ALLOC_SLAB);
                if (c->page)
                        flush_slab(s, c);
 
-               slab_lock(page);
-               __SetPageSlubFrozen(page);
+               /*
+                * No other reference to the page yet so we can
+                * muck around with it freely without cmpxchg
+                */
+               object = page->freelist;
+               page->freelist = NULL;
+               page->inuse = page->objects;
+
+               stat(s, ALLOC_SLAB);
                c->node = page_to_nid(page);
                c->page = page;
+
+               if (kmem_cache_debug(s))
+                       goto debug;
                goto load_freelist;
        }
        if (!(gfpflags & __GFP_NOWARN) && printk_ratelimit())
                slab_out_of_memory(s, gfpflags, node);
        local_irq_restore(flags);
        return NULL;
+
 debug:
-       if (!alloc_debug_processing(s, page, object, addr))
-               goto another_slab;
+       if (!object || !alloc_debug_processing(s, page, object, addr))
+               goto new_slab;
 
-       page->inuse++;
-       page->freelist = get_freepointer(s, object);
+       c->freelist = get_freepointer(s, object);
        deactivate_slab(s, c);
        c->page = NULL;
        c->node = NUMA_NO_NODE;
@@ -2096,52 +2313,89 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
 {
        void *prior;
        void **object = (void *)x;
-       unsigned long flags;
+       int was_frozen;
+       int inuse;
+       struct page new;
+       unsigned long counters;
+       struct kmem_cache_node *n = NULL;
+       unsigned long uninitialized_var(flags);
 
-       local_irq_save(flags);
-       slab_lock(page);
        stat(s, FREE_SLOWPATH);
 
        if (kmem_cache_debug(s) && !free_debug_processing(s, page, x, addr))
-               goto out_unlock;
+               return;
 
-       prior = page->freelist;
-       set_freepointer(s, object, prior);
-       page->freelist = object;
-       page->inuse--;
+       do {
+               prior = page->freelist;
+               counters = page->counters;
+               set_freepointer(s, object, prior);
+               new.counters = counters;
+               was_frozen = new.frozen;
+               new.inuse--;
+               if ((!new.inuse || !prior) && !was_frozen && !n) {
+                        n = get_node(s, page_to_nid(page));
+                       /*
+                        * Speculatively acquire the list_lock.
+                        * If the cmpxchg does not succeed then we may
+                        * drop the list_lock without any processing.
+                        *
+                        * Otherwise the list_lock will synchronize with
+                        * other processors updating the list of slabs.
+                        */
+                        spin_lock_irqsave(&n->list_lock, flags);
+               }
+               inuse = new.inuse;
 
-       if (unlikely(PageSlubFrozen(page))) {
-               stat(s, FREE_FROZEN);
-               goto out_unlock;
-       }
+       } while (!cmpxchg_double_slab(s, page,
+               prior, counters,
+               object, new.counters,
+               "__slab_free"));
 
-       if (unlikely(!page->inuse))
-               goto slab_empty;
+       if (likely(!n)) {
+                /*
+                * The list lock was not taken therefore no list
+                * activity can be necessary.
+                */
+                if (was_frozen)
+                        stat(s, FREE_FROZEN);
+                return;
+        }
 
        /*
-        * Objects left in the slab. If it was not on the partial list before
-        * then add it.
+        * was_frozen may have been set after we acquired the list_lock in
+        * an earlier loop. So we need to check it here again.
         */
-       if (unlikely(!prior)) {
-               add_partial(get_node(s, page_to_nid(page)), page, 1);
-               stat(s, FREE_ADD_PARTIAL);
-       }
+       if (was_frozen)
+               stat(s, FREE_FROZEN);
+       else {
+               if (unlikely(!inuse && n->nr_partial > s->min_partial))
+                        goto slab_empty;
 
-out_unlock:
-       slab_unlock(page);
-       local_irq_restore(flags);
+               /*
+                * Objects left in the slab. If it was not on the partial list before
+                * then add it.
+                */
+               if (unlikely(!prior)) {
+                       remove_full(s, page);
+                       add_partial(n, page, 0);
+                       stat(s, FREE_ADD_PARTIAL);
+               }
+       }
+       spin_unlock_irqrestore(&n->list_lock, flags);
        return;
 
 slab_empty:
        if (prior) {
                /*
-                * Slab still on the partial list.
+                * Slab on the partial list.
                 */
-               remove_partial(s, page);
+               remove_partial(n, page);
                stat(s, FREE_REMOVE_PARTIAL);
-       }
-       slab_unlock(page);
-       local_irq_restore(flags);
+       } else
+               /* Slab must be on the full list */
+               remove_full(s, page);
+
+       spin_unlock_irqrestore(&n->list_lock, flags);
        stat(s, FREE_SLAB);
        discard_slab(s, page);
 }
@@ -2415,7 +2669,6 @@ static void early_kmem_cache_node_alloc(int node)
 {
        struct page *page;
        struct kmem_cache_node *n;
-       unsigned long flags;
 
        BUG_ON(kmem_cache_node->size < sizeof(struct kmem_cache_node));
 
@@ -2433,6 +2686,7 @@ static void early_kmem_cache_node_alloc(int node)
        BUG_ON(!n);
        page->freelist = get_freepointer(kmem_cache_node, n);
        page->inuse++;
+       page->frozen = 0;
        kmem_cache_node->node[node] = n;
 #ifdef CONFIG_SLUB_DEBUG
        init_object(kmem_cache_node, n, SLUB_RED_ACTIVE);
@@ -2441,14 +2695,7 @@ static void early_kmem_cache_node_alloc(int node)
        init_kmem_cache_node(n, kmem_cache_node);
        inc_slabs_node(kmem_cache_node, node, page->objects);
 
-       /*
-        * lockdep requires consistent irq usage for each lock
-        * so even though there cannot be a race this early in
-        * the boot sequence, we still disable irqs.
-        */
-       local_irq_save(flags);
        add_partial(n, page, 0);
-       local_irq_restore(flags);
 }
 
 static void free_kmem_cache_nodes(struct kmem_cache *s)
@@ -2654,6 +2901,12 @@ static int kmem_cache_open(struct kmem_cache *s,
                }
        }
 
+#ifdef CONFIG_CMPXCHG_DOUBLE
+       if (system_has_cmpxchg_double() && (s->flags & SLAB_DEBUG_FLAGS) == 0)
+               /* Enable fast mode */
+               s->flags |= __CMPXCHG_DOUBLE;
+#endif
+
        /*
         * The larger the object size is, the more pages we want on the partial
         * list to avoid pounding the page allocator excessively.
@@ -2726,7 +2979,7 @@ static void free_partial(struct kmem_cache *s, struct kmem_cache_node *n)
        spin_lock_irqsave(&n->list_lock, flags);
        list_for_each_entry_safe(page, h, &n->partial, lru) {
                if (!page->inuse) {
-                       __remove_partial(n, page);
+                       remove_partial(n, page);
                        discard_slab(s, page);
                } else {
                        list_slab_objects(s, page,
@@ -3094,14 +3347,8 @@ int kmem_cache_shrink(struct kmem_cache *s)
                 * list_lock. page->inuse here is the upper limit.
                 */
                list_for_each_entry_safe(page, t, &n->partial, lru) {
-                       if (!page->inuse && slab_trylock(page)) {
-                               /*
-                                * Must hold slab lock here because slab_free
-                                * may have freed the last object and be
-                                * waiting to release the slab.
-                                */
-                               __remove_partial(n, page);
-                               slab_unlock(page);
+                       if (!page->inuse) {
+                               remove_partial(n, page);
                                discard_slab(s, page);
                        } else {
                                list_move(&page->lru,
@@ -3689,12 +3936,9 @@ static int validate_slab(struct kmem_cache *s, struct page *page,
 static void validate_slab_slab(struct kmem_cache *s, struct page *page,
                                                unsigned long *map)
 {
-       if (slab_trylock(page)) {
-               validate_slab(s, page, map);
-               slab_unlock(page);
-       } else
-               printk(KERN_INFO "SLUB %s: Skipped busy slab 0x%p\n",
-                       s->name, page);
+       slab_lock(page);
+       validate_slab(s, page, map);
+       slab_unlock(page);
 }
 
 static int validate_slab_node(struct kmem_cache *s,
@@ -4342,8 +4586,10 @@ static ssize_t sanity_checks_store(struct kmem_cache *s,
                                const char *buf, size_t length)
 {
        s->flags &= ~SLAB_DEBUG_FREE;
-       if (buf[0] == '1')
+       if (buf[0] == '1') {
+               s->flags &= ~__CMPXCHG_DOUBLE;
                s->flags |= SLAB_DEBUG_FREE;
+       }
        return length;
 }
 SLAB_ATTR(sanity_checks);
@@ -4357,8 +4603,10 @@ static ssize_t trace_store(struct kmem_cache *s, const char *buf,
                                                        size_t length)
 {
        s->flags &= ~SLAB_TRACE;
-       if (buf[0] == '1')
+       if (buf[0] == '1') {
+               s->flags &= ~__CMPXCHG_DOUBLE;
                s->flags |= SLAB_TRACE;
+       }
        return length;
 }
 SLAB_ATTR(trace);
@@ -4375,8 +4623,10 @@ static ssize_t red_zone_store(struct kmem_cache *s,
                return -EBUSY;
 
        s->flags &= ~SLAB_RED_ZONE;
-       if (buf[0] == '1')
+       if (buf[0] == '1') {
+               s->flags &= ~__CMPXCHG_DOUBLE;
                s->flags |= SLAB_RED_ZONE;
+       }
        calculate_sizes(s, -1);
        return length;
 }
@@ -4394,8 +4644,10 @@ static ssize_t poison_store(struct kmem_cache *s,
                return -EBUSY;
 
        s->flags &= ~SLAB_POISON;
-       if (buf[0] == '1')
+       if (buf[0] == '1') {
+               s->flags &= ~__CMPXCHG_DOUBLE;
                s->flags |= SLAB_POISON;
+       }
        calculate_sizes(s, -1);
        return length;
 }
@@ -4413,8 +4665,10 @@ static ssize_t store_user_store(struct kmem_cache *s,
                return -EBUSY;
 
        s->flags &= ~SLAB_STORE_USER;
-       if (buf[0] == '1')
+       if (buf[0] == '1') {
+               s->flags &= ~__CMPXCHG_DOUBLE;
                s->flags |= SLAB_STORE_USER;
+       }
        calculate_sizes(s, -1);
        return length;
 }
@@ -4579,6 +4833,7 @@ STAT_ATTR(FREE_REMOVE_PARTIAL, free_remove_partial);
 STAT_ATTR(ALLOC_FROM_PARTIAL, alloc_from_partial);
 STAT_ATTR(ALLOC_SLAB, alloc_slab);
 STAT_ATTR(ALLOC_REFILL, alloc_refill);
+STAT_ATTR(ALLOC_NODE_MISMATCH, alloc_node_mismatch);
 STAT_ATTR(FREE_SLAB, free_slab);
 STAT_ATTR(CPUSLAB_FLUSH, cpuslab_flush);
 STAT_ATTR(DEACTIVATE_FULL, deactivate_full);
@@ -4586,7 +4841,10 @@ STAT_ATTR(DEACTIVATE_EMPTY, deactivate_empty);
 STAT_ATTR(DEACTIVATE_TO_HEAD, deactivate_to_head);
 STAT_ATTR(DEACTIVATE_TO_TAIL, deactivate_to_tail);
 STAT_ATTR(DEACTIVATE_REMOTE_FREES, deactivate_remote_frees);
+STAT_ATTR(DEACTIVATE_BYPASS, deactivate_bypass);
 STAT_ATTR(ORDER_FALLBACK, order_fallback);
+STAT_ATTR(CMPXCHG_DOUBLE_CPU_FAIL, cmpxchg_double_cpu_fail);
+STAT_ATTR(CMPXCHG_DOUBLE_FAIL, cmpxchg_double_fail);
 #endif
 
 static struct attribute *slab_attrs[] = {
@@ -4636,6 +4894,7 @@ static struct attribute *slab_attrs[] = {
        &alloc_from_partial_attr.attr,
        &alloc_slab_attr.attr,
        &alloc_refill_attr.attr,
+       &alloc_node_mismatch_attr.attr,
        &free_slab_attr.attr,
        &cpuslab_flush_attr.attr,
        &deactivate_full_attr.attr,
@@ -4643,7 +4902,10 @@ static struct attribute *slab_attrs[] = {
        &deactivate_to_head_attr.attr,
        &deactivate_to_tail_attr.attr,
        &deactivate_remote_frees_attr.attr,
+       &deactivate_bypass_attr.attr,
        &order_fallback_attr.attr,
+       &cmpxchg_double_fail_attr.attr,
+       &cmpxchg_double_cpu_fail_attr.attr,
 #endif
 #ifdef CONFIG_FAILSLAB
        &failslab_attr.attr,
index 1b8c339..17bc224 100644 (file)
@@ -1924,20 +1924,24 @@ static unsigned long read_swap_header(struct swap_info_struct *p,
 
        /*
         * Find out how many pages are allowed for a single swap
-        * device. There are two limiting factors: 1) the number of
-        * bits for the swap offset in the swp_entry_t type and
-        * 2) the number of bits in the a swap pte as defined by
-        * the different architectures. In order to find the
-        * largest possible bit mask a swap entry with swap type 0
+        * device. There are three limiting factors: 1) the number
+        * of bits for the swap offset in the swp_entry_t type, and
+        * 2) the number of bits in the swap pte as defined by the
+        * the different architectures, and 3) the number of free bits
+        * in an exceptional radix_tree entry. In order to find the
+        * largest possible bit mask, a swap entry with swap type 0
         * and swap offset ~0UL is created, encoded to a swap pte,
-        * decoded to a swp_entry_t again and finally the swap
+        * decoded to a swp_entry_t again, and finally the swap
         * offset is extracted. This will mask all the bits from
         * the initial ~0UL mask that can't be encoded in either
         * the swp_entry_t or the architecture definition of a
-        * swap pte.
+        * swap pte.  Then the same is done for a radix_tree entry.
         */
        maxpages = swp_offset(pte_to_swp_entry(
-                       swp_entry_to_pte(swp_entry(0, ~0UL)))) + 1;
+                       swp_entry_to_pte(swp_entry(0, ~0UL))));
+       maxpages = swp_offset(radix_to_swp_entry(
+                       swp_to_radix_entry(swp_entry(0, maxpages)))) + 1;
+
        if (maxpages > swap_header->info.last_page) {
                maxpages = swap_header->info.last_page + 1;
                /* p->max is an unsigned int: don't overflow it */
index 232eb27..b40ac6d 100644 (file)
@@ -336,6 +336,14 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping,
        unsigned long count = 0;
        int i;
 
+       /*
+        * Note: this function may get called on a shmem/tmpfs mapping:
+        * pagevec_lookup() might then return 0 prematurely (because it
+        * got a gangful of swap entries); but it's hardly worth worrying
+        * about - it can rarely have anything to free from such a mapping
+        * (most pages are dirty), and already skips over any difficulties.
+        */
+
        pagevec_init(&pvec, 0);
        while (index <= end && pagevec_lookup(&pvec, mapping, index,
                        min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1)) {
index 464621d..7ef0903 100644 (file)
@@ -725,9 +725,10 @@ static void free_unmap_vmap_area_addr(unsigned long addr)
 #define VMAP_BBMAP_BITS_MIN    (VMAP_MAX_ALLOC*2)
 #define VMAP_MIN(x, y)         ((x) < (y) ? (x) : (y)) /* can't use min() */
 #define VMAP_MAX(x, y)         ((x) > (y) ? (x) : (y)) /* can't use max() */
-#define VMAP_BBMAP_BITS                VMAP_MIN(VMAP_BBMAP_BITS_MAX,           \
-                                       VMAP_MAX(VMAP_BBMAP_BITS_MIN,   \
-                                               VMALLOC_PAGES / NR_CPUS / 16))
+#define VMAP_BBMAP_BITS                \
+               VMAP_MIN(VMAP_BBMAP_BITS_MAX,   \
+               VMAP_MAX(VMAP_BBMAP_BITS_MIN,   \
+                       VMALLOC_PAGES / roundup_pow_of_two(NR_CPUS) / 16))
 
 #define VMAP_BLOCK_SIZE                (VMAP_BBMAP_BITS * PAGE_SIZE)
 
index 5f27f8e..f1f2f7b 100644 (file)
@@ -167,6 +167,8 @@ struct sk_buff *vlan_untag(struct sk_buff *skb)
        if (unlikely(!skb))
                goto err_free;
 
+       skb_reset_network_header(skb);
+       skb_reset_transport_header(skb);
        return skb;
 
 err_free:
index 2252c20..d07223c 100644 (file)
@@ -242,8 +242,6 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct net_device *dev,
                if (brdev->payload == p_bridged) {
                        skb_push(skb, 2);
                        memset(skb->data, 0, 2);
-               } else { /* p_routed */
-                       skb_pull(skb, ETH_HLEN);
                }
        }
        skb_debug(skb);
@@ -560,12 +558,13 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)
        spin_unlock_irqrestore(&rq->lock, flags);
 
        skb_queue_walk_safe(&queue, skb, tmp) {
-               struct net_device *dev = skb->dev;
+               struct net_device *dev;
+
+               br2684_push(atmvcc, skb);
+               dev = skb->dev;
 
                dev->stats.rx_bytes -= skb->len;
                dev->stats.rx_packets--;
-
-               br2684_push(atmvcc, skb);
        }
 
        /* initialize netdev carrier state */
index 3176e2e..e738154 100644 (file)
@@ -231,6 +231,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br,
 int br_add_bridge(struct net *net, const char *name)
 {
        struct net_device *dev;
+       int res;
 
        dev = alloc_netdev(sizeof(struct net_bridge), name,
                           br_dev_setup);
@@ -240,7 +241,10 @@ int br_add_bridge(struct net *net, const char *name)
 
        dev_net_set(dev, net);
 
-       return register_netdev(dev);
+       res = register_netdev(dev);
+       if (res)
+               free_netdev(dev);
+       return res;
 }
 
 int br_del_bridge(struct net *net, const char *name)
@@ -417,6 +421,7 @@ put_back:
 int br_del_if(struct net_bridge *br, struct net_device *dev)
 {
        struct net_bridge_port *p;
+       bool changed_addr;
 
        p = br_port_get_rtnl(dev);
        if (!p || p->br != br)
@@ -425,9 +430,12 @@ int br_del_if(struct net_bridge *br, struct net_device *dev)
        del_nbp(p);
 
        spin_lock_bh(&br->lock);
-       br_stp_recalculate_bridge_id(br);
+       changed_addr = br_stp_recalculate_bridge_id(br);
        spin_unlock_bh(&br->lock);
 
+       if (changed_addr)
+               call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev);
+
        netdev_update_features(br->dev);
 
        return 0;
index 2d85ca7..995cbe0 100644 (file)
@@ -1456,7 +1456,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
 {
        struct sk_buff *skb2;
        const struct ipv6hdr *ip6h;
-       struct icmp6hdr *icmp6h;
+       u8 icmp6_type;
        u8 nexthdr;
        unsigned len;
        int offset;
@@ -1502,9 +1502,9 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
        __skb_pull(skb2, offset);
        skb_reset_transport_header(skb2);
 
-       icmp6h = icmp6_hdr(skb2);
+       icmp6_type = icmp6_hdr(skb2)->icmp6_type;
 
-       switch (icmp6h->icmp6_type) {
+       switch (icmp6_type) {
        case ICMPV6_MGM_QUERY:
        case ICMPV6_MGM_REPORT:
        case ICMPV6_MGM_REDUCTION:
@@ -1520,16 +1520,23 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
                err = pskb_trim_rcsum(skb2, len);
                if (err)
                        goto out;
+               err = -EINVAL;
        }
 
+       ip6h = ipv6_hdr(skb2);
+
        switch (skb2->ip_summed) {
        case CHECKSUM_COMPLETE:
-               if (!csum_fold(skb2->csum))
+               if (!csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, skb2->len,
+                                       IPPROTO_ICMPV6, skb2->csum))
                        break;
                /*FALLTHROUGH*/
        case CHECKSUM_NONE:
-               skb2->csum = 0;
-               if (skb_checksum_complete(skb2))
+               skb2->csum = ~csum_unfold(csum_ipv6_magic(&ip6h->saddr,
+                                                       &ip6h->daddr,
+                                                       skb2->len,
+                                                       IPPROTO_ICMPV6, 0));
+               if (__skb_checksum_complete(skb2))
                        goto out;
        }
 
@@ -1537,7 +1544,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
 
        BR_INPUT_SKB_CB(skb)->igmp = 1;
 
-       switch (icmp6h->icmp6_type) {
+       switch (icmp6_type) {
        case ICMPV6_MGM_REPORT:
            {
                struct mld_msg *mld;
index 6545ee9..a76b621 100644 (file)
@@ -34,6 +34,7 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
        struct net_device *dev = ptr;
        struct net_bridge_port *p;
        struct net_bridge *br;
+       bool changed_addr;
        int err;
 
        /* register of bridge completed, add sysfs entries */
@@ -57,8 +58,12 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
        case NETDEV_CHANGEADDR:
                spin_lock_bh(&br->lock);
                br_fdb_changeaddr(p, dev->dev_addr);
-               br_stp_recalculate_bridge_id(br);
+               changed_addr = br_stp_recalculate_bridge_id(br);
                spin_unlock_bh(&br->lock);
+
+               if (changed_addr)
+                       call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev);
+
                break;
 
        case NETDEV_CHANGE:
index 2b5ca1a..5864cc4 100644 (file)
@@ -1198,7 +1198,8 @@ ebt_register_table(struct net *net, const struct ebt_table *input_table)
 
        if (table->check && table->check(newinfo, table->valid_hooks)) {
                BUGPRINT("The table doesn't like its own initial data, lol\n");
-               return ERR_PTR(-EINVAL);
+               ret = -EINVAL;
+               goto free_chainstack;
        }
 
        table->private = newinfo;
index 8ce926d..9b0c32a 100644 (file)
@@ -857,7 +857,7 @@ static __exit void can_exit(void)
        struct net_device *dev;
 
        if (stats_timer)
-               del_timer(&can_stattimer);
+               del_timer_sync(&can_stattimer);
 
        can_remove_proc();
 
index 8a04dd2..0d357b1 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 obj-y := sock.o request_sock.o skbuff.o iovec.o datagram.o stream.o scm.o \
-        gen_stats.o gen_estimator.o net_namespace.o
+        gen_stats.o gen_estimator.o net_namespace.o secure_seq.o
 
 obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
 
index 17d67b5..b10ff0a 100644 (file)
@@ -1515,6 +1515,14 @@ static inline bool is_skb_forwardable(struct net_device *dev,
  */
 int dev_forward_skb(struct net_device *dev, struct sk_buff *skb)
 {
+       if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
+               if (skb_copy_ubufs(skb, GFP_ATOMIC)) {
+                       atomic_long_inc(&dev->rx_dropped);
+                       kfree_skb(skb);
+                       return NET_RX_DROP;
+               }
+       }
+
        skb_orphan(skb);
        nf_reset(skb);
 
index bf32c33..47b6d26 100644 (file)
@@ -30,6 +30,7 @@ struct flow_cache_entry {
                struct hlist_node       hlist;
                struct list_head        gc_list;
        } u;
+       struct net                      *net;
        u16                             family;
        u8                              dir;
        u32                             genid;
@@ -232,7 +233,8 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir,
 
        hash = flow_hash_code(fc, fcp, key);
        hlist_for_each_entry(tfle, entry, &fcp->hash_table[hash], u.hlist) {
-               if (tfle->family == family &&
+               if (tfle->net == net &&
+                   tfle->family == family &&
                    tfle->dir == dir &&
                    flow_key_compare(key, &tfle->key) == 0) {
                        fle = tfle;
@@ -246,6 +248,7 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir,
 
                fle = kmem_cache_alloc(flow_cachep, GFP_ATOMIC);
                if (fle) {
+                       fle->net = net;
                        fle->family = family;
                        fle->dir = dir;
                        memcpy(&fle->key, key, sizeof(*key));
index 8fab9b0..1334d7e 100644 (file)
@@ -1319,11 +1319,15 @@ static void neigh_proxy_process(unsigned long arg)
 
                if (tdif <= 0) {
                        struct net_device *dev = skb->dev;
+
                        __skb_unlink(skb, &tbl->proxy_queue);
-                       if (tbl->proxy_redo && netif_running(dev))
+                       if (tbl->proxy_redo && netif_running(dev)) {
+                               rcu_read_lock();
                                tbl->proxy_redo(skb);
-                       else
+                               rcu_read_unlock();
+                       } else {
                                kfree_skb(skb);
+                       }
 
                        dev_put(dev);
                } else if (!sched_next || tdif < sched_next)
index adf84dd..5262251 100644 (file)
@@ -558,13 +558,14 @@ int __netpoll_rx(struct sk_buff *skb)
        if (skb_shared(skb))
                goto out;
 
-       iph = (struct iphdr *)skb->data;
        if (!pskb_may_pull(skb, sizeof(struct iphdr)))
                goto out;
+       iph = (struct iphdr *)skb->data;
        if (iph->ihl < 5 || iph->version != 4)
                goto out;
        if (!pskb_may_pull(skb, iph->ihl*4))
                goto out;
+       iph = (struct iphdr *)skb->data;
        if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
                goto out;
 
@@ -579,6 +580,7 @@ int __netpoll_rx(struct sk_buff *skb)
        if (pskb_trim_rcsum(skb, len))
                goto out;
 
+       iph = (struct iphdr *)skb->data;
        if (iph->protocol != IPPROTO_UDP)
                goto out;
 
index 4c1ef02..811b53f 100644 (file)
@@ -192,7 +192,7 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
                                        goto error;
 
                                cred->uid = cred->euid = p->creds.uid;
-                               cred->gid = cred->egid = p->creds.uid;
+                               cred->gid = cred->egid = p->creds.gid;
                                put_cred(p->cred);
                                p->cred = cred;
                        }
diff --git a/net/core/secure_seq.c b/net/core/secure_seq.c
new file mode 100644 (file)
index 0000000..45329d7
--- /dev/null
@@ -0,0 +1,184 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/cryptohash.h>
+#include <linux/module.h>
+#include <linux/cache.h>
+#include <linux/random.h>
+#include <linux/hrtimer.h>
+#include <linux/ktime.h>
+#include <linux/string.h>
+
+#include <net/secure_seq.h>
+
+static u32 net_secret[MD5_MESSAGE_BYTES / 4] ____cacheline_aligned;
+
+static int __init net_secret_init(void)
+{
+       get_random_bytes(net_secret, sizeof(net_secret));
+       return 0;
+}
+late_initcall(net_secret_init);
+
+static u32 seq_scale(u32 seq)
+{
+       /*
+        *      As close as possible to RFC 793, which
+        *      suggests using a 250 kHz clock.
+        *      Further reading shows this assumes 2 Mb/s networks.
+        *      For 10 Mb/s Ethernet, a 1 MHz clock is appropriate.
+        *      For 10 Gb/s Ethernet, a 1 GHz clock should be ok, but
+        *      we also need to limit the resolution so that the u32 seq
+        *      overlaps less than one time per MSL (2 minutes).
+        *      Choosing a clock of 64 ns period is OK. (period of 274 s)
+        */
+       return seq + (ktime_to_ns(ktime_get_real()) >> 6);
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+__u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr,
+                                  __be16 sport, __be16 dport)
+{
+       u32 secret[MD5_MESSAGE_BYTES / 4];
+       u32 hash[MD5_DIGEST_WORDS];
+       u32 i;
+
+       memcpy(hash, saddr, 16);
+       for (i = 0; i < 4; i++)
+               secret[i] = net_secret[i] + daddr[i];
+       secret[4] = net_secret[4] +
+               (((__force u16)sport << 16) + (__force u16)dport);
+       for (i = 5; i < MD5_MESSAGE_BYTES / 4; i++)
+               secret[i] = net_secret[i];
+
+       md5_transform(hash, secret);
+
+       return seq_scale(hash[0]);
+}
+EXPORT_SYMBOL(secure_tcpv6_sequence_number);
+
+u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
+                              __be16 dport)
+{
+       u32 secret[MD5_MESSAGE_BYTES / 4];
+       u32 hash[MD5_DIGEST_WORDS];
+       u32 i;
+
+       memcpy(hash, saddr, 16);
+       for (i = 0; i < 4; i++)
+               secret[i] = net_secret[i] + (__force u32) daddr[i];
+       secret[4] = net_secret[4] + (__force u32)dport;
+       for (i = 5; i < MD5_MESSAGE_BYTES / 4; i++)
+               secret[i] = net_secret[i];
+
+       md5_transform(hash, secret);
+
+       return hash[0];
+}
+#endif
+
+#ifdef CONFIG_INET
+__u32 secure_ip_id(__be32 daddr)
+{
+       u32 hash[MD5_DIGEST_WORDS];
+
+       hash[0] = (__force __u32) daddr;
+       hash[1] = net_secret[13];
+       hash[2] = net_secret[14];
+       hash[3] = net_secret[15];
+
+       md5_transform(hash, net_secret);
+
+       return hash[0];
+}
+
+__u32 secure_ipv6_id(const __be32 daddr[4])
+{
+       __u32 hash[4];
+
+       memcpy(hash, daddr, 16);
+       md5_transform(hash, net_secret);
+
+       return hash[0];
+}
+
+__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
+                                __be16 sport, __be16 dport)
+{
+       u32 hash[MD5_DIGEST_WORDS];
+
+       hash[0] = (__force u32)saddr;
+       hash[1] = (__force u32)daddr;
+       hash[2] = ((__force u16)sport << 16) + (__force u16)dport;
+       hash[3] = net_secret[15];
+
+       md5_transform(hash, net_secret);
+
+       return seq_scale(hash[0]);
+}
+
+u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport)
+{
+       u32 hash[MD5_DIGEST_WORDS];
+
+       hash[0] = (__force u32)saddr;
+       hash[1] = (__force u32)daddr;
+       hash[2] = (__force u32)dport ^ net_secret[14];
+       hash[3] = net_secret[15];
+
+       md5_transform(hash, net_secret);
+
+       return hash[0];
+}
+EXPORT_SYMBOL_GPL(secure_ipv4_port_ephemeral);
+#endif
+
+#if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE)
+u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
+                               __be16 sport, __be16 dport)
+{
+       u32 hash[MD5_DIGEST_WORDS];
+       u64 seq;
+
+       hash[0] = (__force u32)saddr;
+       hash[1] = (__force u32)daddr;
+       hash[2] = ((__force u16)sport << 16) + (__force u16)dport;
+       hash[3] = net_secret[15];
+
+       md5_transform(hash, net_secret);
+
+       seq = hash[0] | (((u64)hash[1]) << 32);
+       seq += ktime_to_ns(ktime_get_real());
+       seq &= (1ull << 48) - 1;
+
+       return seq;
+}
+EXPORT_SYMBOL(secure_dccp_sequence_number);
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,
+                                 __be16 sport, __be16 dport)
+{
+       u32 secret[MD5_MESSAGE_BYTES / 4];
+       u32 hash[MD5_DIGEST_WORDS];
+       u64 seq;
+       u32 i;
+
+       memcpy(hash, saddr, 16);
+       for (i = 0; i < 4; i++)
+               secret[i] = net_secret[i] + daddr[i];
+       secret[4] = net_secret[4] +
+               (((__force u16)sport << 16) + (__force u16)dport);
+       for (i = 5; i < MD5_MESSAGE_BYTES / 4; i++)
+               secret[i] = net_secret[i];
+
+       md5_transform(hash, secret);
+
+       seq = hash[0] | (((u64)hash[1]) << 32);
+       seq += ktime_to_ns(ktime_get_real());
+       seq &= (1ull << 48) - 1;
+
+       return seq;
+}
+EXPORT_SYMBOL(secure_dccpv6_sequence_number);
+#endif
+#endif
index 2beda82..387703f 100644 (file)
@@ -611,8 +611,21 @@ struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src)
 }
 EXPORT_SYMBOL_GPL(skb_morph);
 
-/* skb frags copy userspace buffers to kernel */
-static int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
+/*     skb_copy_ubufs  -       copy userspace skb frags buffers to kernel
+ *     @skb: the skb to modify
+ *     @gfp_mask: allocation priority
+ *
+ *     This must be called on SKBTX_DEV_ZEROCOPY skb.
+ *     It will copy all frags into kernel and drop the reference
+ *     to userspace pages.
+ *
+ *     If this function is called from an interrupt gfp_mask() must be
+ *     %GFP_ATOMIC.
+ *
+ *     Returns 0 on success or a negative error code on failure
+ *     to allocate kernel memory to copy to.
+ */
+int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
 {
        int i;
        int num_frags = skb_shinfo(skb)->nr_frags;
@@ -652,6 +665,8 @@ static int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
                skb_shinfo(skb)->frags[i - 1].page = head;
                head = (struct page *)head->private;
        }
+
+       skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY;
        return 0;
 }
 
@@ -677,7 +692,6 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
        if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
                if (skb_copy_ubufs(skb, gfp_mask))
                        return NULL;
-               skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY;
        }
 
        n = skb + 1;
@@ -803,7 +817,6 @@ struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask)
                                n = NULL;
                                goto out;
                        }
-                       skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY;
                }
                for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
                        skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i];
@@ -896,7 +909,6 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
                if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
                        if (skb_copy_ubufs(skb, gfp_mask))
                                goto nofrags;
-                       skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY;
                }
                for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
                        get_page(skb_shinfo(skb)->frags[i].page);
@@ -1369,8 +1381,21 @@ pull_pages:
 }
 EXPORT_SYMBOL(__pskb_pull_tail);
 
-/* Copy some data bits from skb to kernel buffer. */
-
+/**
+ *     skb_copy_bits - copy bits from skb to kernel buffer
+ *     @skb: source skb
+ *     @offset: offset in source
+ *     @to: destination buffer
+ *     @len: number of bytes to copy
+ *
+ *     Copy the specified number of bytes from the source skb to the
+ *     destination buffer.
+ *
+ *     CAUTION ! :
+ *             If its prototype is ever changed,
+ *             check arch/{*}/net/{*}.S files,
+ *             since it is called from BPF assembly code.
+ */
 int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)
 {
        int start = skb_headlen(skb);
index 8c36adf..332639b 100644 (file)
@@ -26,6 +26,7 @@
 #include <net/timewait_sock.h>
 #include <net/tcp_states.h>
 #include <net/xfrm.h>
+#include <net/secure_seq.h>
 
 #include "ackvec.h"
 #include "ccid.h"
index 8dc4348..b74f761 100644 (file)
@@ -29,6 +29,7 @@
 #include <net/transp_v6.h>
 #include <net/ip6_checksum.h>
 #include <net/xfrm.h>
+#include <net/secure_seq.h>
 
 #include "dccp.h"
 #include "ipv6.h"
@@ -69,13 +70,7 @@ static inline void dccp_v6_send_check(struct sock *sk, struct sk_buff *skb)
        dh->dccph_checksum = dccp_v6_csum_finish(skb, &np->saddr, &np->daddr);
 }
 
-static inline __u32 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,
-                                                 __be16 sport, __be16 dport   )
-{
-       return secure_tcpv6_sequence_number(saddr, daddr, sport, dport);
-}
-
-static inline __u32 dccp_v6_init_sequence(struct sk_buff *skb)
+static inline __u64 dccp_v6_init_sequence(struct sk_buff *skb)
 {
        return secure_dccpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
                                             ipv6_hdr(skb)->saddr.s6_addr32,
index 27997d3..a246836 100644 (file)
@@ -340,7 +340,7 @@ void ether_setup(struct net_device *dev)
        dev->addr_len           = ETH_ALEN;
        dev->tx_queue_len       = 1000; /* Ethernet wants good queues */
        dev->flags              = IFF_BROADCAST|IFF_MULTICAST;
-       dev->priv_flags         = IFF_TX_SKB_SHARING;
+       dev->priv_flags         |= IFF_TX_SKB_SHARING;
 
        memset(dev->broadcast, 0xFF, ETH_ALEN);
 
index f1d27f6..d577199 100644 (file)
@@ -767,7 +767,7 @@ static int igmp_xmarksources(struct ip_mc_list *pmc, int nsrcs, __be32 *srcs)
                        break;
                for (i=0; i<nsrcs; i++) {
                        /* skip inactive filters */
-                       if (pmc->sfcount[MCAST_INCLUDE] ||
+                       if (psf->sf_count[MCAST_INCLUDE] ||
                            pmc->sfcount[MCAST_EXCLUDE] !=
                            psf->sf_count[MCAST_EXCLUDE])
                                continue;
@@ -1718,7 +1718,7 @@ static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
 
                pmc->sfcount[sfmode]--;
                for (j=0; j<i; j++)
-                       (void) ip_mc_del1_src(pmc, sfmode, &psfsrc[i]);
+                       (void) ip_mc_del1_src(pmc, sfmode, &psfsrc[j]);
        } else if (isexclude != (pmc->sfcount[MCAST_EXCLUDE] != 0)) {
 #ifdef CONFIG_IP_MULTICAST
                struct ip_sf_list *psf;
index 3c0369a..984ec65 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <net/inet_connection_sock.h>
 #include <net/inet_hashtables.h>
+#include <net/secure_seq.h>
 #include <net/ip.h>
 
 /*
index e382138..86f13c6 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/net.h>
 #include <net/ip.h>
 #include <net/inetpeer.h>
+#include <net/secure_seq.h>
 
 /*
  *  Theory of operations.
index ccaaa85..8c65633 100644 (file)
@@ -122,6 +122,7 @@ static int ip_dev_loopback_xmit(struct sk_buff *newskb)
        newskb->pkt_type = PACKET_LOOPBACK;
        newskb->ip_summed = CHECKSUM_UNNECESSARY;
        WARN_ON(!skb_dst(newskb));
+       skb_dst_force(newskb);
        netif_rx_ni(newskb);
        return 0;
 }
@@ -204,9 +205,15 @@ static inline int ip_finish_output2(struct sk_buff *skb)
                skb = skb2;
        }
 
+       rcu_read_lock();
        neigh = dst_get_neighbour(dst);
-       if (neigh)
-               return neigh_output(neigh, skb);
+       if (neigh) {
+               int res = neigh_output(neigh, skb);
+
+               rcu_read_unlock();
+               return res;
+       }
+       rcu_read_unlock();
 
        if (net_ratelimit())
                printk(KERN_DEBUG "ip_finish_output2: No header cache and no neighbour!\n");
index ab0c9ef..8905e92 100644 (file)
@@ -1067,7 +1067,7 @@ EXPORT_SYMBOL(compat_ip_setsockopt);
  */
 
 static int do_ip_getsockopt(struct sock *sk, int level, int optname,
-                           char __user *optval, int __user *optlen)
+                           char __user *optval, int __user *optlen, unsigned flags)
 {
        struct inet_sock *inet = inet_sk(sk);
        int val;
@@ -1240,7 +1240,7 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
 
                msg.msg_control = optval;
                msg.msg_controllen = len;
-               msg.msg_flags = 0;
+               msg.msg_flags = flags;
 
                if (inet->cmsg_flags & IP_CMSG_PKTINFO) {
                        struct in_pktinfo info;
@@ -1294,7 +1294,7 @@ int ip_getsockopt(struct sock *sk, int level,
 {
        int err;
 
-       err = do_ip_getsockopt(sk, level, optname, optval, optlen);
+       err = do_ip_getsockopt(sk, level, optname, optval, optlen, 0);
 #ifdef CONFIG_NETFILTER
        /* we need to exclude all possible ENOPROTOOPTs except default case */
        if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS &&
@@ -1327,7 +1327,8 @@ int compat_ip_getsockopt(struct sock *sk, int level, int optname,
                return compat_mc_getsockopt(sk, level, optname, optval, optlen,
                        ip_getsockopt);
 
-       err = do_ip_getsockopt(sk, level, optname, optval, optlen);
+       err = do_ip_getsockopt(sk, level, optname, optval, optlen,
+               MSG_CMSG_COMPAT);
 
 #ifdef CONFIG_NETFILTER
        /* we need to exclude all possible ENOPROTOOPTs except default case */
index 2e97e3e..929b27b 100644 (file)
@@ -18,17 +18,15 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type)
        struct rtable *rt;
        struct flowi4 fl4 = {};
        __be32 saddr = iph->saddr;
-       __u8 flags = 0;
+       __u8 flags = skb->sk ? inet_sk_flowi_flags(skb->sk) : 0;
        unsigned int hh_len;
 
-       if (!skb->sk && addr_type != RTN_LOCAL) {
-               if (addr_type == RTN_UNSPEC)
-                       addr_type = inet_addr_type(net, saddr);
-               if (addr_type == RTN_LOCAL || addr_type == RTN_UNICAST)
-                       flags |= FLOWI_FLAG_ANYSRC;
-               else
-                       saddr = 0;
-       }
+       if (addr_type == RTN_UNSPEC)
+               addr_type = inet_addr_type(net, saddr);
+       if (addr_type == RTN_LOCAL || addr_type == RTN_UNICAST)
+               flags |= FLOWI_FLAG_ANYSRC;
+       else
+               saddr = 0;
 
        /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause
         * packets with foreign saddr to appear on the NF_INET_LOCAL_OUT hook.
@@ -38,7 +36,7 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type)
        fl4.flowi4_tos = RT_TOS(iph->tos);
        fl4.flowi4_oif = skb->sk ? skb->sk->sk_bound_dev_if : 0;
        fl4.flowi4_mark = skb->mark;
-       fl4.flowi4_flags = skb->sk ? inet_sk_flowi_flags(skb->sk) : flags;
+       fl4.flowi4_flags = flags;
        rt = ip_route_output_key(net, &fl4);
        if (IS_ERR(rt))
                return -1;
index 3e61faf..f52d41e 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/ip.h>
 
 #include <linux/netfilter.h>
+#include <net/secure_seq.h>
 #include <net/netfilter/nf_nat.h>
 #include <net/netfilter/nf_nat_core.h>
 #include <net/netfilter/nf_nat_rule.h>
index b14ec7d..4bfad5d 100644 (file)
@@ -254,6 +254,8 @@ static const struct snmp_mib snmp4_net_list[] = {
        SNMP_MIB_ITEM("TCPDeferAcceptDrop", LINUX_MIB_TCPDEFERACCEPTDROP),
        SNMP_MIB_ITEM("IPReversePathFilter", LINUX_MIB_IPRPFILTER),
        SNMP_MIB_ITEM("TCPTimeWaitOverflow", LINUX_MIB_TCPTIMEWAITOVERFLOW),
+       SNMP_MIB_ITEM("TCPReqQFullDoCookies", LINUX_MIB_TCPREQQFULLDOCOOKIES),
+       SNMP_MIB_ITEM("TCPReqQFullDrop", LINUX_MIB_TCPREQQFULLDROP),
        SNMP_MIB_SENTINEL
 };
 
index 1457acb..61714bd 100644 (file)
@@ -563,7 +563,8 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos,
                           RT_SCOPE_UNIVERSE,
                           inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol,
-                          FLOWI_FLAG_CAN_SLEEP, daddr, saddr, 0, 0);
+                          inet_sk_flowi_flags(sk) | FLOWI_FLAG_CAN_SLEEP,
+                          daddr, saddr, 0, 0);
 
        if (!inet->hdrincl) {
                err = raw_probe_proto_opt(&fl4, msg);
index 1730689..075212e 100644 (file)
 #include <linux/sysctl.h>
 #endif
 #include <net/atmclip.h>
+#include <net/secure_seq.h>
 
 #define RT_FL_TOS(oldflp4) \
     ((u32)(oldflp4->flowi4_tos & (IPTOS_RT_MASK | RTO_ONLINK)))
@@ -721,7 +722,7 @@ static inline bool compare_hash_inputs(const struct rtable *rt1,
 {
        return ((((__force u32)rt1->rt_key_dst ^ (__force u32)rt2->rt_key_dst) |
                ((__force u32)rt1->rt_key_src ^ (__force u32)rt2->rt_key_src) |
-               (rt1->rt_iif ^ rt2->rt_iif)) == 0);
+               (rt1->rt_route_iif ^ rt2->rt_route_iif)) == 0);
 }
 
 static inline int compare_keys(struct rtable *rt1, struct rtable *rt2)
@@ -730,8 +731,8 @@ static inline int compare_keys(struct rtable *rt1, struct rtable *rt2)
                ((__force u32)rt1->rt_key_src ^ (__force u32)rt2->rt_key_src) |
                (rt1->rt_mark ^ rt2->rt_mark) |
                (rt1->rt_key_tos ^ rt2->rt_key_tos) |
-               (rt1->rt_oif ^ rt2->rt_oif) |
-               (rt1->rt_iif ^ rt2->rt_iif)) == 0;
+               (rt1->rt_route_iif ^ rt2->rt_route_iif) |
+               (rt1->rt_oif ^ rt2->rt_oif)) == 0;
 }
 
 static inline int compare_netns(struct rtable *rt1, struct rtable *rt2)
@@ -1628,16 +1629,18 @@ static int check_peer_redir(struct dst_entry *dst, struct inet_peer *peer)
 {
        struct rtable *rt = (struct rtable *) dst;
        __be32 orig_gw = rt->rt_gateway;
-       struct neighbour *n;
+       struct neighbour *n, *old_n;
 
        dst_confirm(&rt->dst);
 
-       neigh_release(dst_get_neighbour(&rt->dst));
-       dst_set_neighbour(&rt->dst, NULL);
-
        rt->rt_gateway = peer->redirect_learned.a4;
-       rt_bind_neighbour(rt);
-       n = dst_get_neighbour(&rt->dst);
+
+       n = ipv4_neigh_lookup(&rt->dst, &rt->rt_gateway);
+       if (IS_ERR(n))
+               return PTR_ERR(n);
+       old_n = xchg(&rt->dst._neighbour, n);
+       if (old_n)
+               neigh_release(old_n);
        if (!n || !(n->nud_state & NUD_VALID)) {
                if (n)
                        neigh_event_send(n, NULL);
@@ -2317,8 +2320,7 @@ int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr,
             rth = rcu_dereference(rth->dst.rt_next)) {
                if ((((__force u32)rth->rt_key_dst ^ (__force u32)daddr) |
                     ((__force u32)rth->rt_key_src ^ (__force u32)saddr) |
-                    (rth->rt_iif ^ iif) |
-                    rth->rt_oif |
+                    (rth->rt_route_iif ^ iif) |
                     (rth->rt_key_tos ^ tos)) == 0 &&
                    rth->rt_mark == skb->mark &&
                    net_eq(dev_net(rth->dst.dev), net) &&
index 92bb943..3bc5c8f 100644 (file)
@@ -276,7 +276,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
        int mss;
        struct rtable *rt;
        __u8 rcv_wscale;
-       bool ecn_ok;
+       bool ecn_ok = false;
 
        if (!sysctl_tcp_syncookies || !th->ack || th->rst)
                goto out;
index 955b8e6..c34f015 100644 (file)
@@ -72,6 +72,7 @@
 #include <net/timewait_sock.h>
 #include <net/xfrm.h>
 #include <net/netdma.h>
+#include <net/secure_seq.h>
 
 #include <linux/inet.h>
 #include <linux/ipv6.h>
@@ -807,20 +808,38 @@ static void tcp_v4_reqsk_destructor(struct request_sock *req)
        kfree(inet_rsk(req)->opt);
 }
 
-static void syn_flood_warning(const struct sk_buff *skb)
+/*
+ * Return 1 if a syncookie should be sent
+ */
+int tcp_syn_flood_action(struct sock *sk,
+                        const struct sk_buff *skb,
+                        const char *proto)
 {
-       const char *msg;
+       const char *msg = "Dropping request";
+       int want_cookie = 0;
+       struct listen_sock *lopt;
+
+
 
 #ifdef CONFIG_SYN_COOKIES
-       if (sysctl_tcp_syncookies)
+       if (sysctl_tcp_syncookies) {
                msg = "Sending cookies";
-       else
+               want_cookie = 1;
+               NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPREQQFULLDOCOOKIES);
+       } else
 #endif
-               msg = "Dropping request";
+               NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPREQQFULLDROP);
 
-       pr_info("TCP: Possible SYN flooding on port %d. %s.\n",
-                               ntohs(tcp_hdr(skb)->dest), msg);
+       lopt = inet_csk(sk)->icsk_accept_queue.listen_opt;
+       if (!lopt->synflood_warned) {
+               lopt->synflood_warned = 1;
+               pr_info("%s: Possible SYN flooding on port %d. %s. "
+                       " Check SNMP counters.\n",
+                       proto, ntohs(tcp_hdr(skb)->dest), msg);
+       }
+       return want_cookie;
 }
+EXPORT_SYMBOL(tcp_syn_flood_action);
 
 /*
  * Save and compile IPv4 options into the request_sock if needed.
@@ -1234,11 +1253,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
        __be32 saddr = ip_hdr(skb)->saddr;
        __be32 daddr = ip_hdr(skb)->daddr;
        __u32 isn = TCP_SKB_CB(skb)->when;
-#ifdef CONFIG_SYN_COOKIES
        int want_cookie = 0;
-#else
-#define want_cookie 0 /* Argh, why doesn't gcc optimize this :( */
-#endif
 
        /* Never answer to SYNs send to broadcast or multicast */
        if (skb_rtable(skb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
@@ -1249,14 +1264,9 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
         * evidently real one.
         */
        if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
-               if (net_ratelimit())
-                       syn_flood_warning(skb);
-#ifdef CONFIG_SYN_COOKIES
-               if (sysctl_tcp_syncookies) {
-                       want_cookie = 1;
-               } else
-#endif
-               goto drop;
+               want_cookie = tcp_syn_flood_action(sk, skb, "TCP");
+               if (!want_cookie)
+                       goto drop;
        }
 
        /* Accept backlog is full. If we have already queued enough
@@ -1302,9 +1312,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
                while (l-- > 0)
                        *c++ ^= *hash_location++;
 
-#ifdef CONFIG_SYN_COOKIES
                want_cookie = 0;        /* not our kind of cookie */
-#endif
                tmp_ext.cookie_out_never = 0; /* false */
                tmp_ext.cookie_plus = tmp_opt.cookie_plus;
        } else if (!tp->rx_opt.cookie_in_always) {
index a55500c..f012ebd 100644 (file)
@@ -656,7 +656,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
         * layer address of our nexhop router
         */
 
-       if (dst_get_neighbour(&rt->dst) == NULL)
+       if (dst_get_neighbour_raw(&rt->dst) == NULL)
                ifa->flags &= ~IFA_F_OPTIMISTIC;
 
        ifa->idev = idev;
index 1656033..9ef1831 100644 (file)
 #include <linux/errqueue.h>
 #include <asm/uaccess.h>
 
+static inline int ipv6_mapped_addr_any(const struct in6_addr *a)
+{
+       return (ipv6_addr_v4mapped(a) && (a->s6_addr32[3] == 0));
+}
+
 int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 {
        struct sockaddr_in6     *usin = (struct sockaddr_in6 *) uaddr;
@@ -102,10 +107,12 @@ ipv4_connected:
 
                ipv6_addr_set_v4mapped(inet->inet_daddr, &np->daddr);
 
-               if (ipv6_addr_any(&np->saddr))
+               if (ipv6_addr_any(&np->saddr) ||
+                   ipv6_mapped_addr_any(&np->saddr))
                        ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr);
 
-               if (ipv6_addr_any(&np->rcv_saddr)) {
+               if (ipv6_addr_any(&np->rcv_saddr) ||
+                   ipv6_mapped_addr_any(&np->rcv_saddr)) {
                        ipv6_addr_set_v4mapped(inet->inet_rcv_saddr,
                                               &np->rcv_saddr);
                        if (sk->sk_prot->rehash)
index b531972..73f1a00 100644 (file)
@@ -20,6 +20,7 @@
 #include <net/inet_connection_sock.h>
 #include <net/inet_hashtables.h>
 #include <net/inet6_hashtables.h>
+#include <net/secure_seq.h>
 #include <net/ip.h>
 
 int __inet6_hash(struct sock *sk, struct inet_timewait_sock *tw)
index 54a4678..320d91d 100644 (file)
@@ -1455,7 +1455,7 @@ static int fib6_age(struct rt6_info *rt, void *arg)
                        RT6_TRACE("aging clone %p\n", rt);
                        return -1;
                } else if ((rt->rt6i_flags & RTF_GATEWAY) &&
-                          (!(dst_get_neighbour(&rt->dst)->flags & NTF_ROUTER))) {
+                          (!(dst_get_neighbour_raw(&rt->dst)->flags & NTF_ROUTER))) {
                        RT6_TRACE("purging route %p via non-router but gateway\n",
                                  rt);
                        return -1;
index 32e5339..4c882cf 100644 (file)
@@ -135,10 +135,15 @@ static int ip6_finish_output2(struct sk_buff *skb)
                                skb->len);
        }
 
+       rcu_read_lock();
        neigh = dst_get_neighbour(dst);
-       if (neigh)
-               return neigh_output(neigh, skb);
+       if (neigh) {
+               int res = neigh_output(neigh, skb);
 
+               rcu_read_unlock();
+               return res;
+       }
+       rcu_read_unlock();
        IP6_INC_STATS_BH(dev_net(dst->dev),
                         ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
        kfree_skb(skb);
@@ -975,12 +980,14 @@ static int ip6_dst_lookup_tail(struct sock *sk,
         * dst entry and replace it instead with the
         * dst entry of the nexthop router
         */
+       rcu_read_lock();
        n = dst_get_neighbour(*dst);
        if (n && !(n->nud_state & NUD_VALID)) {
                struct inet6_ifaddr *ifp;
                struct flowi6 fl_gw6;
                int redirect;
 
+               rcu_read_unlock();
                ifp = ipv6_get_ifaddr(net, &fl6->saddr,
                                      (*dst)->dev, 1);
 
@@ -1000,6 +1007,8 @@ static int ip6_dst_lookup_tail(struct sock *sk,
                        if ((err = (*dst)->error))
                                goto out_err_release;
                }
+       } else {
+               rcu_read_unlock();
        }
 #endif
 
index 9cb191e..147ede3 100644 (file)
@@ -913,7 +913,7 @@ static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt,
 }
 
 static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
-                   char __user *optval, int __user *optlen)
+                   char __user *optval, int __user *optlen, unsigned flags)
 {
        struct ipv6_pinfo *np = inet6_sk(sk);
        int len;
@@ -962,7 +962,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
 
                msg.msg_control = optval;
                msg.msg_controllen = len;
-               msg.msg_flags = 0;
+               msg.msg_flags = flags;
 
                lock_sock(sk);
                skb = np->pktoptions;
@@ -1222,7 +1222,7 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname,
        if(level != SOL_IPV6)
                return -ENOPROTOOPT;
 
-       err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);
+       err = do_ipv6_getsockopt(sk, level, optname, optval, optlen, 0);
 #ifdef CONFIG_NETFILTER
        /* we need to exclude all possible ENOPROTOOPTs except default case */
        if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) {
@@ -1264,7 +1264,8 @@ int compat_ipv6_getsockopt(struct sock *sk, int level, int optname,
                return compat_mc_getsockopt(sk, level, optname, optval, optlen,
                        ipv6_getsockopt);
 
-       err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);
+       err = do_ipv6_getsockopt(sk, level, optname, optval, optlen,
+                                MSG_CMSG_COMPAT);
 #ifdef CONFIG_NETFILTER
        /* we need to exclude all possible ENOPROTOOPTs except default case */
        if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) {
index 3e6ebcd..ee7839f 100644 (file)
@@ -1059,7 +1059,7 @@ static int mld_xmarksources(struct ifmcaddr6 *pmc, int nsrcs,
                        break;
                for (i=0; i<nsrcs; i++) {
                        /* skip inactive filters */
-                       if (pmc->mca_sfcount[MCAST_INCLUDE] ||
+                       if (psf->sf_count[MCAST_INCLUDE] ||
                            pmc->mca_sfcount[MCAST_EXCLUDE] !=
                            psf->sf_count[MCAST_EXCLUDE])
                                continue;
index e8987da..9e69eb0 100644 (file)
@@ -364,7 +364,7 @@ out:
 #ifdef CONFIG_IPV6_ROUTER_PREF
 static void rt6_probe(struct rt6_info *rt)
 {
-       struct neighbour *neigh = rt ? dst_get_neighbour(&rt->dst) : NULL;
+       struct neighbour *neigh;
        /*
         * Okay, this does not seem to be appropriate
         * for now, however, we need to check if it
@@ -373,8 +373,10 @@ static void rt6_probe(struct rt6_info *rt)
         * Router Reachability Probe MUST be rate-limited
         * to no more than one per minute.
         */
+       rcu_read_lock();
+       neigh = rt ? dst_get_neighbour(&rt->dst) : NULL;
        if (!neigh || (neigh->nud_state & NUD_VALID))
-               return;
+               goto out;
        read_lock_bh(&neigh->lock);
        if (!(neigh->nud_state & NUD_VALID) &&
            time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) {
@@ -387,8 +389,11 @@ static void rt6_probe(struct rt6_info *rt)
                target = (struct in6_addr *)&neigh->primary_key;
                addrconf_addr_solict_mult(target, &mcaddr);
                ndisc_send_ns(rt->rt6i_dev, NULL, target, &mcaddr, NULL);
-       } else
+       } else {
                read_unlock_bh(&neigh->lock);
+       }
+out:
+       rcu_read_unlock();
 }
 #else
 static inline void rt6_probe(struct rt6_info *rt)
@@ -412,8 +417,11 @@ static inline int rt6_check_dev(struct rt6_info *rt, int oif)
 
 static inline int rt6_check_neigh(struct rt6_info *rt)
 {
-       struct neighbour *neigh = dst_get_neighbour(&rt->dst);
+       struct neighbour *neigh;
        int m;
+
+       rcu_read_lock();
+       neigh = dst_get_neighbour(&rt->dst);
        if (rt->rt6i_flags & RTF_NONEXTHOP ||
            !(rt->rt6i_flags & RTF_GATEWAY))
                m = 1;
@@ -430,6 +438,7 @@ static inline int rt6_check_neigh(struct rt6_info *rt)
                read_unlock_bh(&neigh->lock);
        } else
                m = 0;
+       rcu_read_unlock();
        return m;
 }
 
@@ -769,7 +778,7 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort,
                rt->rt6i_dst.plen = 128;
                rt->rt6i_flags |= RTF_CACHE;
                rt->dst.flags |= DST_HOST;
-               dst_set_neighbour(&rt->dst, neigh_clone(dst_get_neighbour(&ort->dst)));
+               dst_set_neighbour(&rt->dst, neigh_clone(dst_get_neighbour_raw(&ort->dst)));
        }
        return rt;
 }
@@ -803,7 +812,7 @@ restart:
        dst_hold(&rt->dst);
        read_unlock_bh(&table->tb6_lock);
 
-       if (!dst_get_neighbour(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP))
+       if (!dst_get_neighbour_raw(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP))
                nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr);
        else if (!(rt->dst.flags & DST_HOST))
                nrt = rt6_alloc_clone(rt, &fl6->daddr);
@@ -1587,7 +1596,7 @@ void rt6_redirect(const struct in6_addr *dest, const struct in6_addr *src,
        dst_confirm(&rt->dst);
 
        /* Duplicate redirect: silently ignore. */
-       if (neigh == dst_get_neighbour(&rt->dst))
+       if (neigh == dst_get_neighbour_raw(&rt->dst))
                goto out;
 
        nrt = ip6_rt_copy(rt, dest);
@@ -1682,7 +1691,7 @@ again:
           1. It is connected route. Action: COW
           2. It is gatewayed route or NONEXTHOP route. Action: clone it.
         */
-       if (!dst_get_neighbour(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP))
+       if (!dst_get_neighbour_raw(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP))
                nrt = rt6_alloc_cow(rt, daddr, saddr);
        else
                nrt = rt6_alloc_clone(rt, daddr);
@@ -2326,6 +2335,7 @@ static int rt6_fill_node(struct net *net,
        struct nlmsghdr *nlh;
        long expires;
        u32 table;
+       struct neighbour *n;
 
        if (prefix) {   /* user wants prefix routes only */
                if (!(rt->rt6i_flags & RTF_PREFIX_RT)) {
@@ -2414,8 +2424,11 @@ static int rt6_fill_node(struct net *net,
        if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
                goto nla_put_failure;
 
-       if (dst_get_neighbour(&rt->dst))
-               NLA_PUT(skb, RTA_GATEWAY, 16, &dst_get_neighbour(&rt->dst)->primary_key);
+       rcu_read_lock();
+       n = dst_get_neighbour(&rt->dst);
+       if (n)
+               NLA_PUT(skb, RTA_GATEWAY, 16, &n->primary_key);
+       rcu_read_unlock();
 
        if (rt->dst.dev)
                NLA_PUT_U32(skb, RTA_OIF, rt->rt6i_dev->ifindex);
@@ -2608,12 +2621,14 @@ static int rt6_info_route(struct rt6_info *rt, void *p_arg)
 #else
        seq_puts(m, "00000000000000000000000000000000 00 ");
 #endif
+       rcu_read_lock();
        n = dst_get_neighbour(&rt->dst);
        if (n) {
                seq_printf(m, "%pi6", n->primary_key);
        } else {
                seq_puts(m, "00000000000000000000000000000000");
        }
+       rcu_read_unlock();
        seq_printf(m, " %08x %08x %08x %08x %8s\n",
                   rt->rt6i_metric, atomic_read(&rt->dst.__refcnt),
                   rt->dst.__use, rt->rt6i_flags,
index 07bf108..00b15ac 100644 (file)
@@ -672,6 +672,9 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
        if (skb->protocol != htons(ETH_P_IPV6))
                goto tx_error;
 
+       if (tos == 1)
+               tos = ipv6_get_dsfield(iph6);
+
        /* ISATAP (RFC4214) - must come before 6to4 */
        if (dev->priv_flags & IFF_ISATAP) {
                struct neighbour *neigh = NULL;
index 89d5bf8..ac83896 100644 (file)
@@ -165,7 +165,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
        int mss;
        struct dst_entry *dst;
        __u8 rcv_wscale;
-       bool ecn_ok;
+       bool ecn_ok = false;
 
        if (!sysctl_tcp_syncookies || !th->ack || th->rst)
                goto out;
index 78aa534..3c9fa61 100644 (file)
@@ -61,6 +61,7 @@
 #include <net/timewait_sock.h>
 #include <net/netdma.h>
 #include <net/inet_common.h>
+#include <net/secure_seq.h>
 
 #include <asm/uaccess.h>
 
@@ -530,20 +531,6 @@ static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req,
        return tcp_v6_send_synack(sk, req, rvp);
 }
 
-static inline void syn_flood_warning(struct sk_buff *skb)
-{
-#ifdef CONFIG_SYN_COOKIES
-       if (sysctl_tcp_syncookies)
-               printk(KERN_INFO
-                      "TCPv6: Possible SYN flooding on port %d. "
-                      "Sending cookies.\n", ntohs(tcp_hdr(skb)->dest));
-       else
-#endif
-               printk(KERN_INFO
-                      "TCPv6: Possible SYN flooding on port %d. "
-                      "Dropping request.\n", ntohs(tcp_hdr(skb)->dest));
-}
-
 static void tcp_v6_reqsk_destructor(struct request_sock *req)
 {
        kfree_skb(inet6_rsk(req)->pktopts);
@@ -1178,11 +1165,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
        struct tcp_sock *tp = tcp_sk(sk);
        __u32 isn = TCP_SKB_CB(skb)->when;
        struct dst_entry *dst = NULL;
-#ifdef CONFIG_SYN_COOKIES
        int want_cookie = 0;
-#else
-#define want_cookie 0
-#endif
 
        if (skb->protocol == htons(ETH_P_IP))
                return tcp_v4_conn_request(sk, skb);
@@ -1191,14 +1174,9 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
                goto drop;
 
        if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
-               if (net_ratelimit())
-                       syn_flood_warning(skb);
-#ifdef CONFIG_SYN_COOKIES
-               if (sysctl_tcp_syncookies)
-                       want_cookie = 1;
-               else
-#endif
-               goto drop;
+               want_cookie = tcp_syn_flood_action(sk, skb, "TCPv6");
+               if (!want_cookie)
+                       goto drop;
        }
 
        if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
@@ -1248,9 +1226,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
                while (l-- > 0)
                        *c++ ^= *hash_location++;
 
-#ifdef CONFIG_SYN_COOKIES
                want_cookie = 0;        /* not our kind of cookie */
-#endif
                tmp_ext.cookie_out_never = 0; /* false */
                tmp_ext.cookie_plus = tmp_opt.cookie_plus;
        } else if (!tp->rx_opt.cookie_in_always) {
index be43fd8..2b771dc 100644 (file)
@@ -3771,6 +3771,7 @@ err_sock:
 void ip_vs_control_cleanup(void)
 {
        EnterFunction(2);
+       unregister_netdevice_notifier(&ip_vs_dst_notifier);
        ip_vs_genl_unregister();
        nf_unregister_sockopt(&ip_vs_sockopts);
        LeaveFunction(2);
index 5b466cd..84d0fd4 100644 (file)
@@ -312,6 +312,7 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
                }
                break;
        case NF_STOLEN:
+               break;
        default:
                kfree_skb(skb);
        }
index ea750e9..d2732fc 100644 (file)
@@ -1,8 +1,6 @@
 #
 # Makefile for the NetLabel subsystem.
 #
-# Feb 9, 2006, Paul Moore <paul.moore@hp.com>
-#
 
 # base objects
 obj-y  := netlabel_user.o netlabel_kapi.o
index c051913..96b749d 100644 (file)
@@ -6,7 +6,7 @@
  * system manages static and dynamic label mappings for network protocols such
  * as CIPSO and RIPSO.
  *
- * Author: Paul Moore <paul.moore@hp.com>
+ * Author: Paul Moore <paul@paul-moore.com>
  *
  */
 
index 2b9644e..fdbc1d2 100644 (file)
@@ -6,7 +6,7 @@
  * system manages static and dynamic label mappings for network protocols such
  * as CIPSO and RIPSO.
  *
- * Author: Paul Moore <paul.moore@hp.com>
+ * Author: Paul Moore <paul@paul-moore.com>
  *
  */
 
index dd53a36..6bf8783 100644 (file)
@@ -5,7 +5,7 @@
  * NetLabel system manages static and dynamic label mappings for network
  * protocols such as CIPSO and RIPSO.
  *
- * Author: Paul Moore <paul.moore@hp.com>
+ * Author: Paul Moore <paul@paul-moore.com>
  *
  */
 
index af7f335..d24d774 100644 (file)
@@ -5,7 +5,7 @@
  * NetLabel system manages static and dynamic label mappings for network
  * protocols such as CIPSO and RIPSO.
  *
- * Author: Paul Moore <paul.moore@hp.com>
+ * Author: Paul Moore <paul@paul-moore.com>
  *
  */
 
index 2aa975e..7d8083c 100644 (file)
@@ -6,7 +6,7 @@
  * system manages static and dynamic label mappings for network protocols such
  * as CIPSO and RIPSO.
  *
- * Author: Paul Moore <paul.moore@hp.com>
+ * Author: Paul Moore <paul@paul-moore.com>
  *
  */
 
index 0261dda..bfcc0f7 100644 (file)
@@ -6,7 +6,7 @@
  * system manages static and dynamic label mappings for network protocols such
  * as CIPSO and RIPSO.
  *
- * Author: Paul Moore <paul.moore@hp.com>
+ * Author: Paul Moore <paul@paul-moore.com>
  *
  */
 
index b528dd9..9c24de1 100644 (file)
@@ -5,7 +5,7 @@
  * system manages static and dynamic label mappings for network protocols such
  * as CIPSO and RIPSO.
  *
- * Author: Paul Moore <paul.moore@hp.com>
+ * Author: Paul Moore <paul@paul-moore.com>
  *
  */
 
@@ -341,11 +341,11 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
 
        entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
        if (entry == NULL)
-               return -ENOMEM;
+               goto out_entry;
        if (domain != NULL) {
                entry->domain = kstrdup(domain, GFP_ATOMIC);
                if (entry->domain == NULL)
-                       goto cfg_cipsov4_map_add_failure;
+                       goto out_domain;
        }
 
        if (addr == NULL && mask == NULL) {
@@ -354,13 +354,13 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
        } else if (addr != NULL && mask != NULL) {
                addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC);
                if (addrmap == NULL)
-                       goto cfg_cipsov4_map_add_failure;
+                       goto out_addrmap;
                INIT_LIST_HEAD(&addrmap->list4);
                INIT_LIST_HEAD(&addrmap->list6);
 
                addrinfo = kzalloc(sizeof(*addrinfo), GFP_ATOMIC);
                if (addrinfo == NULL)
-                       goto cfg_cipsov4_map_add_failure;
+                       goto out_addrinfo;
                addrinfo->type_def.cipsov4 = doi_def;
                addrinfo->type = NETLBL_NLTYPE_CIPSOV4;
                addrinfo->list.addr = addr->s_addr & mask->s_addr;
@@ -374,7 +374,7 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
                entry->type = NETLBL_NLTYPE_ADDRSELECT;
        } else {
                ret_val = -EINVAL;
-               goto cfg_cipsov4_map_add_failure;
+               goto out_addrmap;
        }
 
        ret_val = netlbl_domhsh_add(entry, audit_info);
@@ -384,11 +384,15 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
        return 0;
 
 cfg_cipsov4_map_add_failure:
-       cipso_v4_doi_putdef(doi_def);
+       kfree(addrinfo);
+out_addrinfo:
+       kfree(addrmap);
+out_addrmap:
        kfree(entry->domain);
+out_domain:
        kfree(entry);
-       kfree(addrmap);
-       kfree(addrinfo);
+out_entry:
+       cipso_v4_doi_putdef(doi_def);
        return ret_val;
 }
 
index dff8a08..bfa5558 100644 (file)
@@ -5,7 +5,7 @@
  * NetLabel system manages static and dynamic label mappings for network
  * protocols such as CIPSO and RIPSO.
  *
- * Author: Paul Moore <paul.moore@hp.com>
+ * Author: Paul Moore <paul@paul-moore.com>
  *
  */
 
index 8db37f4..5a9f31c 100644 (file)
@@ -5,7 +5,7 @@
  * NetLabel system manages static and dynamic label mappings for network
  * protocols such as CIPSO and RIPSO.
  *
- * Author: Paul Moore <paul.moore@hp.com>
+ * Author: Paul Moore <paul@paul-moore.com>
  *
  */
 
index f1ecf84..e6e8236 100644 (file)
@@ -5,7 +5,7 @@
  * NetLabel system.  The NetLabel system manages static and dynamic label
  * mappings for network protocols such as CIPSO and RIPSO.
  *
- * Author: Paul Moore <paul.moore@hp.com>
+ * Author: Paul Moore <paul@paul-moore.com>
  *
  */
 
index 0bc8dc3..700af49 100644 (file)
@@ -5,7 +5,7 @@
  * NetLabel system.  The NetLabel system manages static and dynamic label
  * mappings for network protocols such as CIPSO and RIPSO.
  *
- * Author: Paul Moore <paul.moore@hp.com>
+ * Author: Paul Moore <paul@paul-moore.com>
  *
  */
 
index a3fd75a..9fae63f 100644 (file)
@@ -5,7 +5,7 @@
  * NetLabel system manages static and dynamic label mappings for network
  * protocols such as CIPSO and RIPSO.
  *
- * Author: Paul Moore <paul.moore@hp.com>
+ * Author: Paul Moore <paul@paul-moore.com>
  *
  */
 
index f4fc4c9..8196978 100644 (file)
@@ -5,7 +5,7 @@
  * NetLabel system manages static and dynamic label mappings for network
  * protocols such as CIPSO and RIPSO.
  *
- * Author: Paul Moore <paul.moore@hp.com>
+ * Author: Paul Moore <paul@paul-moore.com>
  *
  */
 
index 102fc21..e051398 100644 (file)
@@ -196,8 +196,7 @@ static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a,
 
        skb2->skb_iif = skb->dev->ifindex;
        skb2->dev = dev;
-       dev_queue_xmit(skb2);
-       err = 0;
+       err = dev_queue_xmit(skb2);
 
 out:
        if (err) {
index be4505e..b014279 100644 (file)
@@ -425,7 +425,7 @@ static int rsvp_change(struct tcf_proto *tp, unsigned long base,
        struct rsvp_filter *f, **fp;
        struct rsvp_session *s, **sp;
        struct tc_rsvp_pinfo *pinfo = NULL;
-       struct nlattr *opt = tca[TCA_OPTIONS-1];
+       struct nlattr *opt = tca[TCA_OPTIONS];
        struct nlattr *tb[TCA_RSVP_MAX + 1];
        struct tcf_exts e;
        unsigned int h1, h2;
@@ -439,7 +439,7 @@ static int rsvp_change(struct tcf_proto *tp, unsigned long base,
        if (err < 0)
                return err;
 
-       err = tcf_exts_validate(tp, tb, tca[TCA_RATE-1], &e, &rsvp_ext_map);
+       err = tcf_exts_validate(tp, tb, tca[TCA_RATE], &e, &rsvp_ext_map);
        if (err < 0)
                return err;
 
@@ -449,8 +449,8 @@ static int rsvp_change(struct tcf_proto *tp, unsigned long base,
 
                if (f->handle != handle && handle)
                        goto errout2;
-               if (tb[TCA_RSVP_CLASSID-1]) {
-                       f->res.classid = nla_get_u32(tb[TCA_RSVP_CLASSID-1]);
+               if (tb[TCA_RSVP_CLASSID]) {
+                       f->res.classid = nla_get_u32(tb[TCA_RSVP_CLASSID]);
                        tcf_bind_filter(tp, &f->res, base);
                }
 
@@ -462,7 +462,7 @@ static int rsvp_change(struct tcf_proto *tp, unsigned long base,
        err = -EINVAL;
        if (handle)
                goto errout2;
-       if (tb[TCA_RSVP_DST-1] == NULL)
+       if (tb[TCA_RSVP_DST] == NULL)
                goto errout2;
 
        err = -ENOBUFS;
@@ -471,19 +471,19 @@ static int rsvp_change(struct tcf_proto *tp, unsigned long base,
                goto errout2;
 
        h2 = 16;
-       if (tb[TCA_RSVP_SRC-1]) {
-               memcpy(f->src, nla_data(tb[TCA_RSVP_SRC-1]), sizeof(f->src));
+       if (tb[TCA_RSVP_SRC]) {
+               memcpy(f->src, nla_data(tb[TCA_RSVP_SRC]), sizeof(f->src));
                h2 = hash_src(f->src);
        }
-       if (tb[TCA_RSVP_PINFO-1]) {
-               pinfo = nla_data(tb[TCA_RSVP_PINFO-1]);
+       if (tb[TCA_RSVP_PINFO]) {
+               pinfo = nla_data(tb[TCA_RSVP_PINFO]);
                f->spi = pinfo->spi;
                f->tunnelhdr = pinfo->tunnelhdr;
        }
-       if (tb[TCA_RSVP_CLASSID-1])
-               f->res.classid = nla_get_u32(tb[TCA_RSVP_CLASSID-1]);
+       if (tb[TCA_RSVP_CLASSID])
+               f->res.classid = nla_get_u32(tb[TCA_RSVP_CLASSID]);
 
-       dst = nla_data(tb[TCA_RSVP_DST-1]);
+       dst = nla_data(tb[TCA_RSVP_DST]);
        h1 = hash_dst(dst, pinfo ? pinfo->protocol : 0, pinfo ? pinfo->tunnelid : 0);
 
        err = -ENOMEM;
@@ -642,8 +642,7 @@ nla_put_failure:
        return -1;
 }
 
-static struct tcf_proto_ops RSVP_OPS = {
-       .next           =       NULL,
+static struct tcf_proto_ops RSVP_OPS __read_mostly = {
        .kind           =       RSVP_ID,
        .classify       =       rsvp_classify,
        .init           =       rsvp_init,
index 2a318f2..b5d56a2 100644 (file)
@@ -112,7 +112,7 @@ static struct sk_buff *prio_dequeue(struct Qdisc *sch)
 
        for (prio = 0; prio < q->bands; prio++) {
                struct Qdisc *qdisc = q->queues[prio];
-               struct sk_buff *skb = qdisc->dequeue(qdisc);
+               struct sk_buff *skb = qdisc_dequeue_peeked(qdisc);
                if (skb) {
                        qdisc_bstats_update(sch, skb);
                        sch->q.qlen--;
index 4536ee6..4f5510e 100644 (file)
@@ -410,7 +410,12 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        /* Return Congestion Notification only if we dropped a packet
         * from this flow.
         */
-       return (qlen != slot->qlen) ? NET_XMIT_CN : NET_XMIT_SUCCESS;
+       if (qlen != slot->qlen)
+               return NET_XMIT_CN;
+
+       /* As we dropped a packet, better let upper stack know this */
+       qdisc_tree_decrease_qlen(sch, 1);
+       return NET_XMIT_SUCCESS;
 }
 
 static struct sk_buff *
index b1cbbcd..ffe92ca 100644 (file)
@@ -1871,8 +1871,14 @@ SYSCALL_DEFINE2(shutdown, int, fd, int, how)
 #define COMPAT_NAMELEN(msg)    COMPAT_MSG(msg, msg_namelen)
 #define COMPAT_FLAGS(msg)      COMPAT_MSG(msg, msg_flags)
 
+struct used_address {
+       struct sockaddr_storage name;
+       unsigned int name_len;
+};
+
 static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
-                        struct msghdr *msg_sys, unsigned flags, int nosec)
+                        struct msghdr *msg_sys, unsigned flags,
+                        struct used_address *used_address)
 {
        struct compat_msghdr __user *msg_compat =
            (struct compat_msghdr __user *)msg;
@@ -1953,8 +1959,30 @@ static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
 
        if (sock->file->f_flags & O_NONBLOCK)
                msg_sys->msg_flags |= MSG_DONTWAIT;
-       err = (nosec ? sock_sendmsg_nosec : sock_sendmsg)(sock, msg_sys,
-                                                         total_len);
+       /*
+        * If this is sendmmsg() and current destination address is same as
+        * previously succeeded address, omit asking LSM's decision.
+        * used_address->name_len is initialized to UINT_MAX so that the first
+        * destination address never matches.
+        */
+       if (used_address && msg_sys->msg_name &&
+           used_address->name_len == msg_sys->msg_namelen &&
+           !memcmp(&used_address->name, msg_sys->msg_name,
+                   used_address->name_len)) {
+               err = sock_sendmsg_nosec(sock, msg_sys, total_len);
+               goto out_freectl;
+       }
+       err = sock_sendmsg(sock, msg_sys, total_len);
+       /*
+        * If this is sendmmsg() and sending to current destination address was
+        * successful, remember it.
+        */
+       if (used_address && err >= 0) {
+               used_address->name_len = msg_sys->msg_namelen;
+               if (msg_sys->msg_name)
+                       memcpy(&used_address->name, msg_sys->msg_name,
+                              used_address->name_len);
+       }
 
 out_freectl:
        if (ctl_buf != ctl)
@@ -1979,7 +2007,7 @@ SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned, flags)
        if (!sock)
                goto out;
 
-       err = __sys_sendmsg(sock, msg, &msg_sys, flags, 0);
+       err = __sys_sendmsg(sock, msg, &msg_sys, flags, NULL);
 
        fput_light(sock->file, fput_needed);
 out:
@@ -1998,6 +2026,10 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
        struct mmsghdr __user *entry;
        struct compat_mmsghdr __user *compat_entry;
        struct msghdr msg_sys;
+       struct used_address used_address;
+
+       if (vlen > UIO_MAXIOV)
+               vlen = UIO_MAXIOV;
 
        datagrams = 0;
 
@@ -2005,27 +2037,22 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
        if (!sock)
                return err;
 
-       err = sock_error(sock->sk);
-       if (err)
-               goto out_put;
-
+       used_address.name_len = UINT_MAX;
        entry = mmsg;
        compat_entry = (struct compat_mmsghdr __user *)mmsg;
+       err = 0;
 
        while (datagrams < vlen) {
-               /*
-                * No need to ask LSM for more than the first datagram.
-                */
                if (MSG_CMSG_COMPAT & flags) {
                        err = __sys_sendmsg(sock, (struct msghdr __user *)compat_entry,
-                                           &msg_sys, flags, datagrams);
+                                           &msg_sys, flags, &used_address);
                        if (err < 0)
                                break;
                        err = __put_user(err, &compat_entry->msg_len);
                        ++compat_entry;
                } else {
                        err = __sys_sendmsg(sock, (struct msghdr __user *)entry,
-                                           &msg_sys, flags, datagrams);
+                                           &msg_sys, flags, &used_address);
                        if (err < 0)
                                break;
                        err = put_user(err, &entry->msg_len);
@@ -2037,29 +2064,11 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
                ++datagrams;
        }
 
-out_put:
        fput_light(sock->file, fput_needed);
 
-       if (err == 0)
-               return datagrams;
-
-       if (datagrams != 0) {
-               /*
-                * We may send less entries than requested (vlen) if the
-                * sock is non blocking...
-                */
-               if (err != -EAGAIN) {
-                       /*
-                        * ... or if sendmsg returns an error after we
-                        * send some datagrams, where we record the
-                        * error to return on the next call or if the
-                        * app asks about it using getsockopt(SO_ERROR).
-                        */
-                       sock->sk->sk_err = -err;
-               }
-
+       /* We only return an error if no datagrams were able to be sent */
+       if (datagrams != 0)
                return datagrams;
-       }
 
        return err;
 }
index 9b6a4d1..f4385e4 100644 (file)
@@ -187,6 +187,7 @@ EXPORT_SYMBOL_GPL(xprt_load_transport);
 /**
  * xprt_reserve_xprt - serialize write access to transports
  * @task: task that is requesting access to the transport
+ * @xprt: pointer to the target transport
  *
  * This prevents mixing the payload of separate requests, and prevents
  * transport connects from colliding with writes.  No congestion control
index 58064d9..791ab2e 100644 (file)
@@ -462,8 +462,8 @@ static struct xfrm_algo_desc ealg_list[] = {
        .desc = {
                .sadb_alg_id = SADB_X_EALG_AESCTR,
                .sadb_alg_ivlen = 8,
-               .sadb_alg_minbits = 128,
-               .sadb_alg_maxbits = 256
+               .sadb_alg_minbits = 160,
+               .sadb_alg_maxbits = 288
        }
 },
 };
index 0b4276c..82d2eb2 100644 (file)
@@ -170,8 +170,8 @@ mconf-objs     := mconf.o zconf.tab.o $(lxdialog)
 nconf-objs     := nconf.o zconf.tab.o nconf.gui.o
 kxgettext-objs := kxgettext.o zconf.tab.o
 qconf-cxxobjs  := qconf.o
-qconf-objs     := kconfig_load.o zconf.tab.o
-gconf-objs     := gconf.o kconfig_load.o zconf.tab.o
+qconf-objs     := zconf.tab.o
+gconf-objs     := gconf.o zconf.tab.o
 
 hostprogs-y := conf
 
@@ -203,7 +203,7 @@ ifeq ($(gconf-target),1)
        hostprogs-y += gconf
 endif
 
-clean-files    := lkc_defs.h qconf.moc .tmp_qtcheck .tmp_gtkcheck
+clean-files    := qconf.moc .tmp_qtcheck .tmp_gtkcheck
 clean-files    += zconf.tab.c zconf.lex.c zconf.hash.c gconf.glade.h
 clean-files     += mconf qconf gconf nconf
 clean-files     += config.pot linux.pot
@@ -226,12 +226,12 @@ HOSTCFLAGS_zconf.tab.o    := -I$(src)
 LEX_PREFIX_zconf       := zconf
 YACC_PREFIX_zconf      := zconf
 
-HOSTLOADLIBES_qconf    = $(KC_QT_LIBS) -ldl
-HOSTCXXFLAGS_qconf.o   = $(KC_QT_CFLAGS) -D LKC_DIRECT_LINK
+HOSTLOADLIBES_qconf    = $(KC_QT_LIBS)
+HOSTCXXFLAGS_qconf.o   = $(KC_QT_CFLAGS)
 
-HOSTLOADLIBES_gconf    = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0` -ldl
+HOSTLOADLIBES_gconf    = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0`
 HOSTCFLAGS_gconf.o     = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \
-                          -D LKC_DIRECT_LINK
+                          -Wno-missing-prototypes
 
 HOSTLOADLIBES_mconf   = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC))
 
@@ -321,18 +321,11 @@ endif
 
 $(obj)/zconf.tab.o: $(obj)/zconf.lex.c $(obj)/zconf.hash.c
 
-$(obj)/kconfig_load.o: $(obj)/lkc_defs.h
-
-$(obj)/qconf.o: $(obj)/qconf.moc $(obj)/lkc_defs.h
-
-$(obj)/gconf.o: $(obj)/lkc_defs.h
+$(obj)/qconf.o: $(obj)/qconf.moc
 
 $(obj)/%.moc: $(src)/%.h
        $(KC_QT_MOC) -i $< -o $@
 
-$(obj)/lkc_defs.h: $(src)/lkc_proto.h
-       $(Q)sed < $< > $@ 's/P(\([^,]*\),.*/#define \1 (\*\1_p)/'
-
 # Extract gconf menu items for I18N support
 $(obj)/gconf.glade.h: $(obj)/gconf.glade
        $(Q)intltool-extract --type=gettext/glade --srcdir=$(srctree) \
index 006ad81..f208f90 100644 (file)
 #include <sys/stat.h>
 #include <sys/time.h>
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 
 static void conf(struct menu *menu);
 static void check_conf(struct menu *menu);
+static void xfgets(char *str, int size, FILE *in);
 
 enum input_mode {
        oldaskconfig,
@@ -35,8 +35,6 @@ enum input_mode {
        oldnoconfig,
 } input_mode = oldaskconfig;
 
-char *defconfig_file;
-
 static int indent = 1;
 static int valid_stdin = 1;
 static int sync_kconfig;
@@ -106,6 +104,7 @@ static int conf_askvalue(struct symbol *sym, const char *def)
                        return 0;
                }
                check_stdin();
+               /* fall through */
        case oldaskconfig:
                fflush(stdout);
                xfgets(line, 128, stdin);
@@ -150,6 +149,7 @@ static int conf_string(struct menu *menu)
                                def = NULL;
                                break;
                        }
+                       /* fall through */
                default:
                        line[strlen(line)-1] = 0;
                        def = line;
@@ -304,6 +304,7 @@ static int conf_choice(struct menu *menu)
                                break;
                        }
                        check_stdin();
+                       /* fall through */
                case oldaskconfig:
                        fflush(stdout);
                        xfgets(line, 128, stdin);
@@ -369,6 +370,7 @@ static void conf(struct menu *menu)
                                check_conf(menu);
                                return;
                        }
+                       /* fall through */
                case P_COMMENT:
                        prompt = menu_get_prompt(menu);
                        if (prompt)
@@ -456,10 +458,30 @@ static struct option long_opts[] = {
        {NULL, 0, NULL, 0}
 };
 
+static void conf_usage(const char *progname)
+{
+
+       printf("Usage: %s [option] <kconfig-file>\n", progname);
+       printf("[option] is _one_ of the following:\n");
+       printf("  --listnewconfig         List new options\n");
+       printf("  --oldaskconfig          Start a new configuration using a line-oriented program\n");
+       printf("  --oldconfig             Update a configuration using a provided .config as base\n");
+       printf("  --silentoldconfig       Same as oldconfig, but quietly, additionally update deps\n");
+       printf("  --oldnoconfig           Same as silentoldconfig but set new symbols to no\n");
+       printf("  --defconfig <file>      New config with default defined in <file>\n");
+       printf("  --savedefconfig <file>  Save the minimal current configuration to <file>\n");
+       printf("  --allnoconfig           New config where all options are answered with no\n");
+       printf("  --allyesconfig          New config where all options are answered with yes\n");
+       printf("  --allmodconfig          New config where all options are answered with mod\n");
+       printf("  --alldefconfig          New config with all symbols set to default\n");
+       printf("  --randconfig            New config with random answer to all options\n");
+}
+
 int main(int ac, char **av)
 {
+       const char *progname = av[0];
        int opt;
-       const char *name;
+       const char *name, *defconfig_file = NULL /* gcc uninit */;
        struct stat tmpstat;
 
        setlocale(LC_ALL, "");
@@ -491,14 +513,24 @@ int main(int ac, char **av)
                        srand(seed);
                        break;
                }
+               case oldaskconfig:
+               case oldconfig:
+               case allnoconfig:
+               case allyesconfig:
+               case allmodconfig:
+               case alldefconfig:
+               case listnewconfig:
+               case oldnoconfig:
+                       break;
                case '?':
-                       fprintf(stderr, _("See README for usage info\n"));
+                       conf_usage(progname);
                        exit(1);
                        break;
                }
        }
        if (ac == optind) {
                printf(_("%s: Kconfig file missing\n"), av[0]);
+               conf_usage(progname);
                exit(1);
        }
        name = av[optind];
@@ -641,13 +673,11 @@ int main(int ac, char **av)
        }
        return 0;
 }
+
 /*
  * Helper function to facilitate fgets() by Jean Sacren.
  */
-void xfgets(str, size, in)
-       char *str;
-       int size;
-       FILE *in;
+void xfgets(char *str, int size, FILE *in)
 {
        if (fgets(str, size, in) == NULL)
                fprintf(stderr, "\nError in reading or end of file.\n");
index 2bafd9a..59b667c 100644 (file)
@@ -7,13 +7,13 @@
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 
 static void conf_warning(const char *fmt, ...)
@@ -128,6 +128,7 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
                        sym->flags |= def_flags;
                        break;
                }
+               /* fall through */
        case S_BOOLEAN:
                if (p[0] == 'y') {
                        sym->def[def].tri = yes;
@@ -140,7 +141,7 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
                        break;
                }
                conf_warning("symbol value '%s' invalid for %s", p, sym->name);
-               break;
+               return 1;
        case S_OTHER:
                if (*p != '"') {
                        for (p2 = p; *p2 && !isspace(*p2); p2++)
@@ -148,6 +149,7 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
                        sym->type = S_STRING;
                        goto done;
                }
+               /* fall through */
        case S_STRING:
                if (*p++ != '"')
                        break;
@@ -162,6 +164,7 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
                        conf_warning("invalid string found");
                        return 1;
                }
+               /* fall through */
        case S_INT:
        case S_HEX:
        done:
@@ -237,6 +240,7 @@ load:
                case S_STRING:
                        if (sym->def[def].val)
                                free(sym->def[def].val);
+                       /* fall through */
                default:
                        sym->def[def].val = NULL;
                        sym->def[def].tri = no;
@@ -363,6 +367,7 @@ int conf_read(const char *name)
                                        break;
                                if (!sym_is_choice(sym))
                                        goto sym_ok;
+                               /* fall through */
                        default:
                                if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
                                        goto sym_ok;
@@ -417,64 +422,202 @@ int conf_read(const char *name)
        return 0;
 }
 
-/* Write a S_STRING */
-static void conf_write_string(bool headerfile, const char *name,
-                              const char *str, FILE *out)
+/*
+ * Kconfig configuration printer
+ *
+ * This printer is used when generating the resulting configuration after
+ * kconfig invocation and `defconfig' files. Unset symbol might be omitted by
+ * passing a non-NULL argument to the printer.
+ *
+ */
+static void
+kconfig_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
 {
-       int l;
-       if (headerfile)
-               fprintf(out, "#define %s%s \"", CONFIG_, name);
-       else
-               fprintf(out, "%s%s=\"", CONFIG_, name);
-
-       while (1) {
-               l = strcspn(str, "\"\\");
+
+       switch (sym->type) {
+       case S_BOOLEAN:
+       case S_TRISTATE:
+               if (*value == 'n') {
+                       bool skip_unset = (arg != NULL);
+
+                       if (!skip_unset)
+                               fprintf(fp, "# %s%s is not set\n",
+                                   CONFIG_, sym->name);
+                       return;
+               }
+               break;
+       default:
+               break;
+       }
+
+       fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value);
+}
+
+static void
+kconfig_print_comment(FILE *fp, const char *value, void *arg)
+{
+       const char *p = value;
+       size_t l;
+
+       for (;;) {
+               l = strcspn(p, "\n");
+               fprintf(fp, "#");
                if (l) {
-                       xfwrite(str, l, 1, out);
-                       str += l;
+                       fprintf(fp, " ");
+                       fwrite(p, l, 1, fp);
+                       p += l;
                }
-               if (!*str)
+               fprintf(fp, "\n");
+               if (*p++ == '\0')
                        break;
-               fprintf(out, "\\%c", *str++);
        }
-       fputs("\"\n", out);
 }
 
-static void conf_write_symbol(struct symbol *sym, FILE *out, bool write_no)
+static struct conf_printer kconfig_printer_cb =
+{
+       .print_symbol = kconfig_print_symbol,
+       .print_comment = kconfig_print_comment,
+};
+
+/*
+ * Header printer
+ *
+ * This printer is used when generating the `include/generated/autoconf.h' file.
+ */
+static void
+header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
 {
-       const char *str;
 
        switch (sym->type) {
        case S_BOOLEAN:
-       case S_TRISTATE:
-               switch (sym_get_tristate_value(sym)) {
-               case no:
-                       if (write_no)
-                               fprintf(out, "# %s%s is not set\n",
-                                   CONFIG_, sym->name);
-                       break;
-               case mod:
-                       fprintf(out, "%s%s=m\n", CONFIG_, sym->name);
-                       break;
-               case yes:
-                       fprintf(out, "%s%s=y\n", CONFIG_, sym->name);
+       case S_TRISTATE: {
+               const char *suffix = "";
+
+               switch (*value) {
+               case 'n':
                        break;
+               case 'm':
+                       suffix = "_MODULE";
+                       /* fall through */
+               default:
+                       fprintf(fp, "#define %s%s%s 1\n",
+                           CONFIG_, sym->name, suffix);
                }
+               /*
+                * Generate the __enabled_CONFIG_* and
+                * __enabled_CONFIG_*_MODULE macros for use by the
+                * IS_{ENABLED,BUILTIN,MODULE} macros. The _MODULE variant is
+                * generated even for booleans so that the IS_ENABLED() macro
+                * works.
+                */
+               fprintf(fp, "#define __enabled_" CONFIG_ "%s %d\n",
+                               sym->name, (*value == 'y'));
+               fprintf(fp, "#define __enabled_" CONFIG_ "%s_MODULE %d\n",
+                               sym->name, (*value == 'm'));
                break;
-       case S_STRING:
-               conf_write_string(false, sym->name, sym_get_string_value(sym), out);
+       }
+       case S_HEX: {
+               const char *prefix = "";
+
+               if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X'))
+                       prefix = "0x";
+               fprintf(fp, "#define %s%s %s%s\n",
+                   CONFIG_, sym->name, prefix, value);
                break;
-       case S_HEX:
+       }
+       case S_STRING:
        case S_INT:
-               str = sym_get_string_value(sym);
-               fprintf(out, "%s%s=%s\n", CONFIG_, sym->name, str);
+               fprintf(fp, "#define %s%s %s\n",
+                   CONFIG_, sym->name, value);
+               break;
+       default:
                break;
+       }
+
+}
+
+static void
+header_print_comment(FILE *fp, const char *value, void *arg)
+{
+       const char *p = value;
+       size_t l;
+
+       fprintf(fp, "/*\n");
+       for (;;) {
+               l = strcspn(p, "\n");
+               fprintf(fp, " *");
+               if (l) {
+                       fprintf(fp, " ");
+                       fwrite(p, l, 1, fp);
+                       p += l;
+               }
+               fprintf(fp, "\n");
+               if (*p++ == '\0')
+                       break;
+       }
+       fprintf(fp, " */\n");
+}
+
+static struct conf_printer header_printer_cb =
+{
+       .print_symbol = header_print_symbol,
+       .print_comment = header_print_comment,
+};
+
+/*
+ * Tristate printer
+ *
+ * This printer is used when generating the `include/config/tristate.conf' file.
+ */
+static void
+tristate_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
+{
+
+       if (sym->type == S_TRISTATE && *value != 'n')
+               fprintf(fp, "%s%s=%c\n", CONFIG_, sym->name, (char)toupper(*value));
+}
+
+static struct conf_printer tristate_printer_cb =
+{
+       .print_symbol = tristate_print_symbol,
+       .print_comment = kconfig_print_comment,
+};
+
+static void conf_write_symbol(FILE *fp, struct symbol *sym,
+                             struct conf_printer *printer, void *printer_arg)
+{
+       const char *str;
+
+       switch (sym->type) {
        case S_OTHER:
        case S_UNKNOWN:
                break;
+       case S_STRING:
+               str = sym_get_string_value(sym);
+               str = sym_escape_string_value(str);
+               printer->print_symbol(fp, sym, str, printer_arg);
+               free((void *)str);
+               break;
+       default:
+               str = sym_get_string_value(sym);
+               printer->print_symbol(fp, sym, str, printer_arg);
        }
 }
 
+static void
+conf_write_heading(FILE *fp, struct conf_printer *printer, void *printer_arg)
+{
+       char buf[256];
+
+       snprintf(buf, sizeof(buf),
+           "\n"
+           "Automatically generated file; DO NOT EDIT.\n"
+           "%s\n",
+           rootmenu.prompt->text);
+
+       printer->print_comment(fp, buf, printer_arg);
+}
+
 /*
  * Write out a minimal config.
  * All values that has default values are skipped as this is redundant.
@@ -531,7 +674,7 @@ int conf_write_defconfig(const char *filename)
                                                goto next_menu;
                                }
                        }
-                       conf_write_symbol(sym, out, true);
+                       conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
                }
 next_menu:
                if (menu->list != NULL) {
@@ -596,11 +739,7 @@ int conf_write(const char *name)
        if (!out)
                return 1;
 
-       fprintf(out, _("#\n"
-                      "# Automatically generated make config: don't edit\n"
-                      "# %s\n"
-                      "#\n"),
-                    rootmenu.prompt->text);
+       conf_write_heading(out, &kconfig_printer_cb, NULL);
 
        if (!conf_get_changed())
                sym_clear_all_valid();
@@ -621,8 +760,8 @@ int conf_write(const char *name)
                        if (!(sym->flags & SYMBOL_WRITE))
                                goto next;
                        sym->flags &= ~SYMBOL_WRITE;
-                       /* Write config symbol to file */
-                       conf_write_symbol(sym, out, true);
+
+                       conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
                }
 
 next:
@@ -771,7 +910,6 @@ out:
 int conf_write_autoconf(void)
 {
        struct symbol *sym;
-       const char *str;
        const char *name;
        FILE *out, *tristate, *out_h;
        int i;
@@ -800,68 +938,23 @@ int conf_write_autoconf(void)
                return 1;
        }
 
-       fprintf(out, "#\n"
-                    "# Automatically generated make config: don't edit\n"
-                    "# %s\n"
-                    "#\n",
-                    rootmenu.prompt->text);
-       fprintf(tristate, "#\n"
-                         "# Automatically generated - do not edit\n"
-                         "\n");
-       fprintf(out_h, "/*\n"
-                      " * Automatically generated C config: don't edit\n"
-                      " * %s\n"
-                      " */\n",
-                      rootmenu.prompt->text);
+       conf_write_heading(out, &kconfig_printer_cb, NULL);
+
+       conf_write_heading(tristate, &tristate_printer_cb, NULL);
+
+       conf_write_heading(out_h, &header_printer_cb, NULL);
 
        for_all_symbols(i, sym) {
                sym_calc_value(sym);
                if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
                        continue;
 
-               /* write symbol to config file */
-               conf_write_symbol(sym, out, false);
+               /* write symbol to auto.conf, tristate and header files */
+               conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1);
 
-               /* update autoconf and tristate files */
-               switch (sym->type) {
-               case S_BOOLEAN:
-               case S_TRISTATE:
-                       switch (sym_get_tristate_value(sym)) {
-                       case no:
-                               break;
-                       case mod:
-                               fprintf(tristate, "%s%s=M\n",
-                                   CONFIG_, sym->name);
-                               fprintf(out_h, "#define %s%s_MODULE 1\n",
-                                   CONFIG_, sym->name);
-                               break;
-                       case yes:
-                               if (sym->type == S_TRISTATE)
-                                       fprintf(tristate,"%s%s=Y\n",
-                                           CONFIG_, sym->name);
-                               fprintf(out_h, "#define %s%s 1\n",
-                                   CONFIG_, sym->name);
-                               break;
-                       }
-                       break;
-               case S_STRING:
-                       conf_write_string(true, sym->name, sym_get_string_value(sym), out_h);
-                       break;
-               case S_HEX:
-                       str = sym_get_string_value(sym);
-                       if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
-                               fprintf(out_h, "#define %s%s 0x%s\n",
-                                   CONFIG_, sym->name, str);
-                               break;
-                       }
-               case S_INT:
-                       str = sym_get_string_value(sym);
-                       fprintf(out_h, "#define %s%s %s\n",
-                           CONFIG_, sym->name, str);
-                       break;
-               default:
-                       break;
-               }
+               conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1);
+
+               conf_write_symbol(out_h, sym, &header_printer_cb, NULL);
        }
        fclose(out);
        fclose(tristate);
index 0010034..290ce41 100644 (file)
@@ -7,15 +7,13 @@
 #include <stdlib.h>
 #include <string.h>
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 
 #define DEBUG_EXPR     0
 
 struct expr *expr_alloc_symbol(struct symbol *sym)
 {
-       struct expr *e = malloc(sizeof(*e));
-       memset(e, 0, sizeof(*e));
+       struct expr *e = calloc(1, sizeof(*e));
        e->type = E_SYMBOL;
        e->left.sym = sym;
        return e;
@@ -23,8 +21,7 @@ struct expr *expr_alloc_symbol(struct symbol *sym)
 
 struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
 {
-       struct expr *e = malloc(sizeof(*e));
-       memset(e, 0, sizeof(*e));
+       struct expr *e = calloc(1, sizeof(*e));
        e->type = type;
        e->left.expr = ce;
        return e;
@@ -32,8 +29,7 @@ struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
 
 struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2)
 {
-       struct expr *e = malloc(sizeof(*e));
-       memset(e, 0, sizeof(*e));
+       struct expr *e = calloc(1, sizeof(*e));
        e->type = type;
        e->left.expr = e1;
        e->right.expr = e2;
@@ -42,8 +38,7 @@ struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e
 
 struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2)
 {
-       struct expr *e = malloc(sizeof(*e));
-       memset(e, 0, sizeof(*e));
+       struct expr *e = calloc(1, sizeof(*e));
        e->type = type;
        e->left.sym = s1;
        e->right.sym = s2;
index 16bfae2..80fce57 100644 (file)
@@ -172,8 +172,6 @@ struct menu {
 #define MENU_CHANGED           0x0001
 #define MENU_ROOT              0x0002
 
-#ifndef SWIG
-
 extern struct file *file_list;
 extern struct file *current_file;
 struct file *lookup_file(const char *name);
@@ -218,7 +216,6 @@ static inline int expr_is_no(struct expr *e)
 {
        return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no);
 }
-#endif
 
 #ifdef __cplusplus
 }
index a11d5f7..9f44380 100644 (file)
@@ -285,8 +285,6 @@ void init_left_tree(void)
 static void renderer_edited(GtkCellRendererText * cell,
                            const gchar * path_string,
                            const gchar * new_text, gpointer user_data);
-static void renderer_toggled(GtkCellRendererToggle * cellrenderertoggle,
-                            gchar * arg1, gpointer user_data);
 
 void init_right_tree(void)
 {
@@ -320,8 +318,6 @@ void init_right_tree(void)
                                            "inconsistent", COL_BTNINC,
                                            "visible", COL_BTNVIS,
                                            "radio", COL_BTNRAD, NULL);
-       /*g_signal_connect(G_OBJECT(renderer), "toggled",
-          G_CALLBACK(renderer_toggled), NULL); */
        renderer = gtk_cell_renderer_text_new();
        gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
                                        renderer, FALSE);
@@ -888,35 +884,6 @@ static void toggle_sym_value(struct menu *menu)
                display_tree_part();    //fixme: keep exp/coll
 }
 
-static void renderer_toggled(GtkCellRendererToggle * cell,
-                            gchar * path_string, gpointer user_data)
-{
-       GtkTreePath *path, *sel_path = NULL;
-       GtkTreeIter iter, sel_iter;
-       GtkTreeSelection *sel;
-       struct menu *menu;
-
-       path = gtk_tree_path_new_from_string(path_string);
-       if (!gtk_tree_model_get_iter(model2, &iter, path))
-               return;
-
-       sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w));
-       if (gtk_tree_selection_get_selected(sel, NULL, &sel_iter))
-               sel_path = gtk_tree_model_get_path(model2, &sel_iter);
-       if (!sel_path)
-               goto out1;
-       if (gtk_tree_path_compare(path, sel_path))
-               goto out2;
-
-       gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
-       toggle_sym_value(menu);
-
-      out2:
-       gtk_tree_path_free(sel_path);
-      out1:
-       gtk_tree_path_free(path);
-}
-
 static gint column2index(GtkTreeViewColumn * column)
 {
        gint i;
@@ -1172,6 +1139,7 @@ static gchar **fill_row(struct menu *menu)
                        row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
                if (sym_is_choice(sym))
                        break;
+               /* fall through */
        case S_TRISTATE:
                val = sym_get_tristate_value(sym);
                switch (val) {
@@ -1506,10 +1474,6 @@ int main(int ac, char *av[])
        char *env;
        gchar *glade_file;
 
-#ifndef LKC_DIRECT_LINK
-       kconfig_load();
-#endif
-
        bindtextdomain(PACKAGE, LOCALEDIR);
        bind_textdomain_codeset(PACKAGE, "UTF-8");
        textdomain(PACKAGE);
diff --git a/scripts/kconfig/kconfig_load.c b/scripts/kconfig/kconfig_load.c
deleted file mode 100644 (file)
index dbdcaad..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#include <dlfcn.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "lkc.h"
-
-#define P(name,type,arg)       type (*name ## _p) arg
-#include "lkc_proto.h"
-#undef P
-
-void kconfig_load(void)
-{
-       void *handle;
-       char *error;
-
-       handle = dlopen("./libkconfig.so", RTLD_LAZY);
-       if (!handle) {
-               handle = dlopen("./scripts/kconfig/libkconfig.so", RTLD_LAZY);
-               if (!handle) {
-                       fprintf(stderr, "%s\n", dlerror());
-                       exit(1);
-               }
-       }
-
-#define P(name,type,arg)                       \
-{                                              \
-       name ## _p = dlsym(handle, #name);      \
-        if ((error = dlerror()))  {            \
-                fprintf(stderr, "%s\n", error);        \
-               exit(1);                        \
-       }                                       \
-}
-#include "lkc_proto.h"
-#undef P
-}
index e9d8e79..2858738 100644 (file)
@@ -7,7 +7,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 
 static char *escape(const char* text, char *bf, int len)
index f34a0a9..b633bdb 100644 (file)
@@ -21,12 +21,7 @@ static inline char *bind_textdomain_codeset(const char *dn, char *c) { return c;
 extern "C" {
 #endif
 
-#ifdef LKC_DIRECT_LINK
 #define P(name,type,arg)       extern type name arg
-#else
-#include "lkc_defs.h"
-#define P(name,type,arg)       extern type (*name ## _p) arg
-#endif
 #include "lkc_proto.h"
 #undef P
 
@@ -79,9 +74,6 @@ void zconf_nextfile(const char *name);
 int zconf_lineno(void);
 const char *zconf_curname(void);
 
-/* conf.c */
-void xfgets(char *str, int size, FILE *in);
-
 /* confdata.c */
 const char *conf_get_configname(void);
 const char *conf_get_autoconfig_name(void);
@@ -90,6 +82,11 @@ void sym_set_change_count(int count);
 void sym_add_change_count(int count);
 void conf_set_all_new_symbols(enum conf_def_mode mode);
 
+struct conf_printer {
+       void (*print_symbol)(FILE *, struct symbol *, const char *, void *);
+       void (*print_comment)(FILE *, const char *, void *);
+};
+
 /* confdata.c and expr.c */
 static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
 {
@@ -97,9 +94,6 @@ static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
                fprintf(stderr, "\nError in writing or end of file.\n");
 }
 
-/* kconfig_load.c */
-void kconfig_load(void);
-
 /* menu.c */
 void _menu_init(void);
 void menu_warn(struct menu *menu, const char *fmt, ...);
index 17342fe..47fe9c3 100644 (file)
@@ -31,6 +31,7 @@ P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]);
 P(sym_lookup,struct symbol *,(const char *name, int flags));
 P(sym_find,struct symbol *,(const char *name));
 P(sym_expand_string_value,const char *,(const char *in));
+P(sym_escape_string_value, const char *,(const char *in));
 P(sym_re_search,struct symbol **,(const char *pattern));
 P(sym_type_name,const char *,(enum symbol_type type));
 P(sym_calc_value,void,(struct symbol *sym));
index d433c7a..820d2b6 100644 (file)
@@ -18,7 +18,6 @@
 #include <unistd.h>
 #include <locale.h>
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 #include "lxdialog/dialog.h"
 
@@ -845,6 +844,7 @@ int main(int ac, char **av)
                                "\n\n"));
                        return 1;
                }
+               /* fall through */
        case -1:
                printf(_("\n\n"
                        "*** End of the configuration.\n"
index 5fdf10d..d660086 100644 (file)
@@ -3,10 +3,11 @@
  * Released under the terms of the GNU GPL v2.0.
  */
 
+#include <ctype.h>
+#include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 
 static const char nohelp_text[] = N_(
@@ -350,7 +351,7 @@ void menu_finalize(struct menu *parent)
                        last_menu->next = NULL;
                }
 
-               sym->dir_dep.expr = parent->dep;
+               sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep);
        }
        for (menu = parent->list; menu; menu = menu->next) {
                if (sym && sym_is_choice(sym) &&
index 488dd74..39ca1f1 100644 (file)
@@ -7,7 +7,7 @@
  */
 #define _GNU_SOURCE
 #include <string.h>
-#define LKC_DIRECT_LINK
+
 #include "lkc.h"
 #include "nconf.h"
 #include <ctype.h>
@@ -1067,7 +1067,6 @@ static void conf(struct menu *menu)
        struct menu *submenu = 0;
        const char *prompt = menu_get_prompt(menu);
        struct symbol *sym;
-       struct menu *active_menu = NULL;
        int res;
        int current_index = 0;
        int last_top_row = 0;
@@ -1152,13 +1151,9 @@ static void conf(struct menu *menu)
                        continue;
 
                submenu = (struct menu *) item_data();
-               active_menu = (struct menu *)item_data();
                if (!submenu || !menu_is_visible(submenu))
                        continue;
-               if (submenu)
-                       sym = submenu->sym;
-               else
-                       sym = NULL;
+               sym = submenu->sym;
 
                switch (res) {
                case ' ':
@@ -1222,20 +1217,13 @@ static void conf_message_callback(const char *fmt, va_list ap)
 
 static void show_help(struct menu *menu)
 {
-       struct gstr help = str_new();
-
-       if (menu && menu->sym && menu_has_help(menu)) {
-               if (menu->sym->name) {
-                       str_printf(&help, "%s%s:\n\n", CONFIG_, menu->sym->name);
-                       str_append(&help, _(menu_get_help(menu)));
-                       str_append(&help, "\n");
-                       get_symbol_str(&help, menu->sym);
-               } else {
-                       str_append(&help, _(menu_get_help(menu)));
-               }
-       } else {
-               str_append(&help, nohelp_text);
-       }
+       struct gstr help;
+
+       if (!menu)
+               return;
+
+       help = str_new();
+       menu_get_ext_help(menu, &help);
        show_scroll_win(main_window, _(menu_get_prompt(menu)), str_get(&help));
        str_free(&help);
 }
index c2796b8..df274fe 100644 (file)
@@ -1478,10 +1478,13 @@ void ConfigMainWindow::loadConfig(void)
        ConfigView::updateListAll();
 }
 
-void ConfigMainWindow::saveConfig(void)
+bool ConfigMainWindow::saveConfig(void)
 {
-       if (conf_write(NULL))
+       if (conf_write(NULL)) {
                QMessageBox::information(this, "qconf", _("Unable to save configuration!"));
+               return false;
+       }
+       return true;
 }
 
 void ConfigMainWindow::saveConfigAs(void)
@@ -1642,7 +1645,11 @@ void ConfigMainWindow::closeEvent(QCloseEvent* e)
        mb.setButtonText(QMessageBox::Cancel, _("Cancel Exit"));
        switch (mb.exec()) {
        case QMessageBox::Yes:
-               saveConfig();
+               if (saveConfig())
+                       e->accept();
+               else
+                       e->ignore();
+               break;
        case QMessageBox::No:
                e->accept();
                break;
@@ -1745,10 +1752,6 @@ int main(int ac, char** av)
        bindtextdomain(PACKAGE, LOCALEDIR);
        textdomain(PACKAGE);
 
-#ifndef LKC_DIRECT_LINK
-       kconfig_load();
-#endif
-
        progname = av[0];
        configApp = new QApplication(ac, av);
        if (ac > 1 && av[1][0] == '-') {
index 91677d9..3715b3e 100644 (file)
@@ -311,7 +311,7 @@ public slots:
        void listFocusChanged(void);
        void goBack(void);
        void loadConfig(void);
-       void saveConfig(void);
+       bool saveConfig(void);
        void saveConfigAs(void);
        void searchConfig(void);
        void showSingleView(void);
index a796c95..071f00c 100644 (file)
@@ -9,7 +9,6 @@
 #include <regex.h>
 #include <sys/utsname.h>
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 
 struct symbol symbol_yes = {
@@ -751,7 +750,8 @@ const char *sym_get_string_value(struct symbol *sym)
                case no:
                        return "n";
                case mod:
-                       return "m";
+                       sym_calc_value(modules_sym);
+                       return (modules_sym->curr.tri == no) ? "n" : "m";
                case yes:
                        return "y";
                }
@@ -893,6 +893,49 @@ const char *sym_expand_string_value(const char *in)
        return res;
 }
 
+const char *sym_escape_string_value(const char *in)
+{
+       const char *p;
+       size_t reslen;
+       char *res;
+       size_t l;
+
+       reslen = strlen(in) + strlen("\"\"") + 1;
+
+       p = in;
+       for (;;) {
+               l = strcspn(p, "\"\\");
+               p += l;
+
+               if (p[0] == '\0')
+                       break;
+
+               reslen++;
+               p++;
+       }
+
+       res = malloc(reslen);
+       res[0] = '\0';
+
+       strcat(res, "\"");
+
+       p = in;
+       for (;;) {
+               l = strcspn(p, "\"\\");
+               strncat(res, p, l);
+               p += l;
+
+               if (p[0] == '\0')
+                       break;
+
+               strcat(res, "\\");
+               strncat(res, p++, 1);
+       }
+
+       strcat(res, "\"");
+       return res;
+}
+
 struct symbol **sym_re_search(const char *pattern)
 {
        struct symbol *sym, **sym_arr = NULL;
index 6330cc8..d0b8b23 100644 (file)
@@ -5,6 +5,8 @@
  * Released under the terms of the GNU GPL v2.0.
  */
 
+#include <stdarg.h>
+#include <stdlib.h>
 #include <string.h>
 #include "lkc.h"
 
index ddee5fc..00f9d3a 100644 (file)
@@ -14,7 +14,6 @@
 #include <string.h>
 #include <unistd.h>
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 
 #define START_STRSIZE  16
index 906c099..c32b1a4 100644 (file)
@@ -776,7 +776,6 @@ char *zconftext;
 #include <string.h>
 #include <unistd.h>
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 
 #define START_STRSIZE  16
index 211e1a2..f636141 100644 (file)
@@ -87,7 +87,6 @@
 #include <string.h>
 #include <stdbool.h>
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 
 #define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
index c38cc5a..864da07 100644 (file)
@@ -11,7 +11,6 @@
 #include <string.h>
 #include <stdbool.h>
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 
 #define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
index a38316b..266a229 100644 (file)
@@ -14,7 +14,7 @@
  *  Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
  *                         <dgoeddel@trustedcs.com>
  *  Copyright (C) 2006, 2007, 2009 Hewlett-Packard Development Company, L.P.
- *     Paul Moore <paul.moore@hp.com>
+ *     Paul Moore <paul@paul-moore.com>
  *  Copyright (C) 2007 Hitachi Software Engineering Co., Ltd.
  *                    Yuichi Nakamura <ynakam@hitachisoft.jp>
  *
index ce23edd..43d5072 100644 (file)
@@ -8,7 +8,7 @@
  *
  * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
  * Copyright (C) 2007 Hewlett-Packard Development Company, L.P.
- *                    Paul Moore, <paul.moore@hp.com>
+ *                    Paul Moore <paul@paul-moore.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,
index cf2f628..8c59b8f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * SELinux interface to the NetLabel subsystem
  *
- * Author : Paul Moore <paul.moore@hp.com>
+ * Author: Paul Moore <paul@paul-moore.com>
  *
  */
 
index 1b94450..df7a5ed 100644 (file)
@@ -6,7 +6,7 @@
  * needed to reduce the lookup overhead since most of these queries happen on
  * a per-packet basis.
  *
- * Author: Paul Moore <paul.moore@hp.com>
+ * Author: Paul Moore <paul@paul-moore.com>
  *
  */
 
index 8991752..4d965b8 100644 (file)
@@ -5,7 +5,7 @@
  * mapping is maintained as part of the normal policy but a fast cache is
  * needed to reduce the lookup overhead.
  *
- * Author: Paul Moore <paul.moore@hp.com>
+ * Author: Paul Moore <paul@paul-moore.com>
  *
  */
 
index 58cc481..326f22c 100644 (file)
@@ -8,7 +8,7 @@
  *
  * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
  * Copyright (C) 2007 Hewlett-Packard Development Company, L.P.
- *                   Paul Moore <paul.moore@hp.com>
+ *                   Paul Moore <paul@paul-moore.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,
index c3bf3ed..da4b8b2 100644 (file)
@@ -4,7 +4,7 @@
  * This file provides the necessary glue to tie NetLabel into the SELinux
  * subsystem.
  *
- * Author: Paul Moore <paul.moore@hp.com>
+ * Author: Paul Moore <paul@paul-moore.com>
  *
  */
 
index 8b691a8..3bf46ab 100644 (file)
@@ -6,7 +6,7 @@
  * needed to reduce the lookup overhead since most of these queries happen on
  * a per-packet basis.
  *
- * Author: Paul Moore <paul.moore@hp.com>
+ * Author: Paul Moore <paul@paul-moore.com>
  *
  * This code is heavily based on the "netif" concept originally developed by
  * James Morris <jmorris@redhat.com>
index ae76e29..0b62bd1 100644 (file)
@@ -5,7 +5,7 @@
  * mapping is maintained as part of the normal policy but a fast cache is
  * needed to reduce the lookup overhead.
  *
- * Author: Paul Moore <paul.moore@hp.com>
+ * Author: Paul Moore <paul@paul-moore.com>
  *
  * This code is heavily based on the "netif" concept originally developed by
  * James Morris <jmorris@redhat.com>
index de7900e..55d92cb 100644 (file)
@@ -2,7 +2,7 @@
  *
  *     Added conditional policy language extensions
  *
- *  Updated: Hewlett-Packard <paul.moore@hp.com>
+ *  Updated: Hewlett-Packard <paul@paul-moore.com>
  *
  *     Added support for the policy capability bitmap
  *
index d42951f..30f119b 100644 (file)
@@ -4,7 +4,7 @@
  * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
  */
 /*
- * Updated: Hewlett-Packard <paul.moore@hp.com>
+ * Updated: Hewlett-Packard <paul@paul-moore.com>
  *
  *      Added support to import/export the NetLabel category bitmap
  *
index e961742..fbf9c58 100644 (file)
@@ -11,7 +11,7 @@
  * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
  */
 /*
- * Updated: Hewlett-Packard <paul.moore@hp.com>
+ * Updated: Hewlett-Packard <paul@paul-moore.com>
  *
  *      Added support to import/export the MLS label from NetLabel
  *
index 037bf9d..e4369e3 100644 (file)
@@ -11,7 +11,7 @@
  * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
  */
 /*
- * Updated: Hewlett-Packard <paul.moore@hp.com>
+ * Updated: Hewlett-Packard <paul@paul-moore.com>
  *
  *     Added support to import/export the MLS label from NetLabel
  *
index d246aca..2381d0d 100644 (file)
@@ -13,7 +13,7 @@
  *
  *     Added conditional policy language extensions
  *
- * Updated: Hewlett-Packard <paul.moore@hp.com>
+ * Updated: Hewlett-Packard <paul@paul-moore.com>
  *
  *      Added support for the policy capability bitmap
  *
index 973e00e..f6917bc 100644 (file)
@@ -13,7 +13,7 @@
  *
  *     Added conditional policy language extensions
  *
- * Updated: Hewlett-Packard <paul.moore@hp.com>
+ * Updated: Hewlett-Packard <paul@paul-moore.com>
  *
  *      Added support for NetLabel
  *      Added support for the policy capability bitmap
index f375eb2..b9c5e14 100644 (file)
@@ -9,7 +9,7 @@
  *
  *  Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com>
  *  Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
- *                Paul Moore <paul.moore@hp.com>
+ *                Paul Moore <paul@paul-moore.com>
  *  Copyright (C) 2010 Nokia Corporation
  *
  *     This program is free software; you can redistribute it and/or modify
index c8439cf..2e43aec 100644 (file)
@@ -710,8 +710,10 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head)
                      head->r.index++)
                        if (ns->profile_ptr[head->r.index])
                                break;
-               if (head->r.index == TOMOYO_MAX_PROFILES)
+               if (head->r.index == TOMOYO_MAX_PROFILES) {
+                       head->r.eof = true;
                        return;
+               }
                head->r.step++;
                break;
        case 2:
@@ -723,6 +725,7 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head)
                        tomoyo_io_printf(head, "%u-COMMENT=", index);
                        tomoyo_set_string(head, comment ? comment->name : "");
                        tomoyo_set_lf(head);
+                       tomoyo_print_namespace(head);
                        tomoyo_io_printf(head, "%u-PREFERENCE={ ", index);
                        for (i = 0; i < TOMOYO_MAX_PREF; i++)
                                tomoyo_io_printf(head, "%s=%u ",
index 3fd1a7e..552b97a 100644 (file)
@@ -1073,10 +1073,10 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
        sdev->pcmid = -1;
        list_del(&ldev->list);
        layouts_list_items--;
+       kfree(ldev);
  outnodev:
        of_node_put(sound);
        layout_device = NULL;
-       kfree(ldev);
        return -ENODEV;
 }
 
index 5fb2e28..91cdf94 100644 (file)
@@ -342,7 +342,7 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
                        kfree(bufs);
                        return -EFAULT;
                }
-               bufs[ch] = compat_ptr(ptr);
+               bufs[i] = compat_ptr(ptr);
                bufptr++;
        }
        if (dir == SNDRV_PCM_STREAM_PLAYBACK)
index 0851cd1..e85e72b 100644 (file)
@@ -22,7 +22,7 @@
 
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
 #include <linux/log2.h>
 #include <sound/core.h>
 #include <sound/timer.h>
index 7c1cbf0..67ebf1c 100644 (file)
@@ -328,6 +328,8 @@ int snd_timer_close(struct snd_timer_instance *timeri)
                mutex_unlock(&register_mutex);
        } else {
                timer = timeri->timer;
+               if (snd_BUG_ON(!timer))
+                       goto out;
                /* wait, until the active callback is finished */
                spin_lock_irq(&timer->lock);
                while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) {
@@ -353,6 +355,7 @@ int snd_timer_close(struct snd_timer_instance *timeri)
                }
                mutex_unlock(&register_mutex);
        }
+ out:
        if (timeri->private_free)
                timeri->private_free(timeri);
        kfree(timeri->owner);
@@ -531,6 +534,8 @@ int snd_timer_stop(struct snd_timer_instance *timeri)
        if (err < 0)
                return err;
        timer = timeri->timer;
+       if (!timer)
+               return -EINVAL;
        spin_lock_irqsave(&timer->lock, flags);
        timeri->cticks = timeri->ticks;
        timeri->pticks = 0;
index 4831800..484a35b 100644 (file)
 
 #include <asm/io.h>
 #include <linux/delay.h>
-#include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/version.h>
-#include <sound/core.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
 #include <sound/tea575x-tuner.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
@@ -62,17 +62,6 @@ module_param(radio_nr, int, 0);
 #define TEA575X_BIT_DUMMY      (1<<15)         /* buffer */
 #define TEA575X_BIT_FREQ_MASK  0x7fff
 
-static struct v4l2_queryctrl radio_qctrl[] = {
-       {
-               .id            = V4L2_CID_AUDIO_MUTE,
-               .name          = "Mute",
-               .minimum       = 0,
-               .maximum       = 1,
-               .default_value = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       }
-};
-
 /*
  * lowlevel part
  */
@@ -266,83 +255,23 @@ static int vidioc_s_audio(struct file *file, void *priv,
        return 0;
 }
 
-static int vidioc_queryctrl(struct file *file, void *priv,
-                                       struct v4l2_queryctrl *qc)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
-               if (qc->id && qc->id == radio_qctrl[i].id) {
-                       memcpy(qc, &(radio_qctrl[i]),
-                                               sizeof(*qc));
-                       return 0;
-               }
-       }
-       return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-                                       struct v4l2_control *ctrl)
+static int tea575x_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-       struct snd_tea575x *tea = video_drvdata(file);
+       struct snd_tea575x *tea = container_of(ctrl->handler, struct snd_tea575x, ctrl_handler);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
-               ctrl->value = tea->mute;
+               tea->mute = ctrl->val;
+               snd_tea575x_set_freq(tea);
                return 0;
        }
-       return -EINVAL;
-}
 
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                                       struct v4l2_control *ctrl)
-{
-       struct snd_tea575x *tea = video_drvdata(file);
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               if (tea->mute != ctrl->value) {
-                       tea->mute = ctrl->value;
-                       snd_tea575x_set_freq(tea);
-               }
-               return 0;
-       }
        return -EINVAL;
 }
 
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-       *i = 0;
-       return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-       if (i != 0)
-               return -EINVAL;
-       return 0;
-}
-
-static int snd_tea575x_exclusive_open(struct file *file)
-{
-       struct snd_tea575x *tea = video_drvdata(file);
-
-       return test_and_set_bit(0, &tea->in_use) ? -EBUSY : 0;
-}
-
-static int snd_tea575x_exclusive_release(struct file *file)
-{
-       struct snd_tea575x *tea = video_drvdata(file);
-
-       clear_bit(0, &tea->in_use);
-       return 0;
-}
-
 static const struct v4l2_file_operations tea575x_fops = {
        .owner          = THIS_MODULE,
-       .open           = snd_tea575x_exclusive_open,
-       .release        = snd_tea575x_exclusive_release,
-       .ioctl          = video_ioctl2,
+       .unlocked_ioctl = video_ioctl2,
 };
 
 static const struct v4l2_ioctl_ops tea575x_ioctl_ops = {
@@ -351,20 +280,19 @@ static const struct v4l2_ioctl_ops tea575x_ioctl_ops = {
        .vidioc_s_tuner     = vidioc_s_tuner,
        .vidioc_g_audio     = vidioc_g_audio,
        .vidioc_s_audio     = vidioc_s_audio,
-       .vidioc_g_input     = vidioc_g_input,
-       .vidioc_s_input     = vidioc_s_input,
        .vidioc_g_frequency = vidioc_g_frequency,
        .vidioc_s_frequency = vidioc_s_frequency,
-       .vidioc_queryctrl   = vidioc_queryctrl,
-       .vidioc_g_ctrl      = vidioc_g_ctrl,
-       .vidioc_s_ctrl      = vidioc_s_ctrl,
 };
 
 static struct video_device tea575x_radio = {
        .name           = "tea575x-tuner",
        .fops           = &tea575x_fops,
        .ioctl_ops      = &tea575x_ioctl_ops,
-       .release        = video_device_release,
+       .release        = video_device_release_empty,
+};
+
+static const struct v4l2_ctrl_ops tea575x_ctrl_ops = {
+       .s_ctrl = tea575x_s_ctrl,
 };
 
 /*
@@ -373,7 +301,6 @@ static struct video_device tea575x_radio = {
 int snd_tea575x_init(struct snd_tea575x *tea)
 {
        int retval;
-       struct video_device *tea575x_radio_inst;
 
        tea->mute = 1;
 
@@ -381,43 +308,49 @@ int snd_tea575x_init(struct snd_tea575x *tea)
        if (snd_tea575x_read(tea) != 0x55AA)
                return -ENODEV;
 
-       tea->in_use = 0;
        tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40;
        tea->freq = 90500 * 16;         /* 90.5Mhz default */
+       snd_tea575x_set_freq(tea);
 
-       tea575x_radio_inst = video_device_alloc();
-       if (tea575x_radio_inst == NULL) {
-               printk(KERN_ERR "tea575x-tuner: not enough memory\n");
-               return -ENOMEM;
-       }
+       tea->vd = tea575x_radio;
+       video_set_drvdata(&tea->vd, tea);
+       mutex_init(&tea->mutex);
+       tea->vd.lock = &tea->mutex;
 
-       memcpy(tea575x_radio_inst, &tea575x_radio, sizeof(tea575x_radio));
+       v4l2_ctrl_handler_init(&tea->ctrl_handler, 1);
+       tea->vd.ctrl_handler = &tea->ctrl_handler;
+       v4l2_ctrl_new_std(&tea->ctrl_handler, &tea575x_ctrl_ops, V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+       retval = tea->ctrl_handler.error;
+       if (retval) {
+               printk(KERN_ERR "tea575x-tuner: can't initialize controls\n");
+               v4l2_ctrl_handler_free(&tea->ctrl_handler);
+               return retval;
+       }
 
-       strcpy(tea575x_radio.name, tea->tea5759 ?
-                                  "TEA5759 radio" : "TEA5757 radio");
+       if (tea->ext_init) {
+               retval = tea->ext_init(tea);
+               if (retval) {
+                       v4l2_ctrl_handler_free(&tea->ctrl_handler);
+                       return retval;
+               }
+       }
 
-       video_set_drvdata(tea575x_radio_inst, tea);
+       v4l2_ctrl_handler_setup(&tea->ctrl_handler);
 
-       retval = video_register_device(tea575x_radio_inst,
-                                      VFL_TYPE_RADIO, radio_nr);
+       retval = video_register_device(&tea->vd, VFL_TYPE_RADIO, radio_nr);
        if (retval) {
                printk(KERN_ERR "tea575x-tuner: can't register video device!\n");
-               kfree(tea575x_radio_inst);
+               v4l2_ctrl_handler_free(&tea->ctrl_handler);
                return retval;
        }
 
-       snd_tea575x_set_freq(tea);
-       tea->vd = tea575x_radio_inst;
-
        return 0;
 }
 
 void snd_tea575x_exit(struct snd_tea575x *tea)
 {
-       if (tea->vd) {
-               video_unregister_device(tea->vd);
-               tea->vd = NULL;
-       }
+       video_unregister_device(&tea->vd);
+       v4l2_ctrl_handler_free(&tea->ctrl_handler);
 }
 
 static int __init alsa_tea575x_module_init(void)
index 8f7d175..6f13ab4 100644 (file)
@@ -63,13 +63,13 @@ static int pcm_set_speed(int arg)
 
        if (pcm_channels & 2)
        {
-               foo = ((CLOCK_TICK_RATE / 2) + (arg / 2)) / arg;
-               arg = ((CLOCK_TICK_RATE / 2) + (foo / 2)) / foo;
+               foo = ((PIT_TICK_RATE / 2) + (arg / 2)) / arg;
+               arg = ((PIT_TICK_RATE / 2) + (foo / 2)) / foo;
        }
        else
        {
-               foo = (CLOCK_TICK_RATE + (arg / 2)) / arg;
-               arg = (CLOCK_TICK_RATE + (foo / 2)) / foo;
+               foo = (PIT_TICK_RATE + (arg / 2)) / arg;
+               arg = (PIT_TICK_RATE + (foo / 2)) / foo;
        }
 
        pcm_speed = arg;
index 9b800ce..2fc0624 100644 (file)
@@ -673,7 +673,8 @@ static void configure_nonsound_components(void)
 
        if (pss_cdrom_port == -1) {     /* If cdrom port enablation wasn't requested */
                printk(KERN_INFO "PSS: CDROM port not enabled.\n");
-       } else if (check_region(pss_cdrom_port, 2)) {
+       } else if (!request_region(pss_cdrom_port, 2, "PSS CDROM")) {
+               pss_cdrom_port = -1;
                printk(KERN_ERR "PSS: CDROM I/O port conflict.\n");
        } else {
                set_io_base(devc, CONF_CDROM, pss_cdrom_port);
@@ -1232,7 +1233,8 @@ static void __exit cleanup_pss(void)
                if(pssmpu)
                        unload_pss_mpu(&cfg_mpu);
                unload_pss(&cfg);
-       }
+       } else if (pss_cdrom_port != -1)
+               release_region(pss_cdrom_port, 2);
 
        if(!pss_keep_settings)  /* Keep hardware settings if asked */
        {
index e90d103..8816804 100644 (file)
@@ -1,5 +1,10 @@
 # ALSA PCI drivers
 
+config SND_TEA575X
+       tristate
+       depends on SND_FM801_TEA575X_BOOL || SND_ES1968_RADIO || RADIO_SF16FMR2
+       default SND_FM801 || SND_ES1968 || RADIO_SF16FMR2
+
 menuconfig SND_PCI
        bool "PCI sound devices"
        depends on PCI
@@ -563,11 +568,6 @@ config SND_FM801_TEA575X_BOOL
          FM801 chip with a TEA5757 tuner (MediaForte SF256-PCS, SF256-PCP and
          SF64-PCR) into the snd-fm801 driver.
 
-config SND_TEA575X
-       tristate
-       depends on SND_FM801_TEA575X_BOOL || SND_ES1968_RADIO
-       default SND_FM801 || SND_ES1968
-
 source "sound/pci/hda/Kconfig"
 
 config SND_HDSP
index 200c9a1..a872d0a 100644 (file)
@@ -1909,6 +1909,7 @@ static unsigned int ad1981_jacks_whitelist[] = {
        0x103c0944, /* HP nc6220 */
        0x103c0934, /* HP nc8220 */
        0x103c006d, /* HP nx9105 */
+       0x103c300d, /* HP Compaq dc5100 SFF(PT003AW) */
        0x17340088, /* FSC Scenic-W */
        0 /* end */
 };
index 65b7ca1..bd47521 100644 (file)
@@ -631,13 +631,12 @@ struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count,
        if (!p_cache)
                return NULL;
 
-       p_cache->p_info =
-               kmalloc(sizeof(*p_cache->p_info) * control_count, GFP_KERNEL);
+       p_cache->p_info = kzalloc(sizeof(*p_cache->p_info) * control_count,
+                                 GFP_KERNEL);
        if (!p_cache->p_info) {
                kfree(p_cache);
                return NULL;
        }
-       memset(p_cache->p_info, 0, sizeof(*p_cache->p_info) * control_count);
        p_cache->cache_size_in_bytes = size_in_bytes;
        p_cache->control_count = control_count;
        p_cache->p_cache = p_dsp_control_buffer;
index 3a7afa3..71d32c8 100644 (file)
@@ -43,6 +43,7 @@ short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code,
        struct pci_dev *dev = os_data;
        struct code_header header;
        char fw_name[20];
+       short err_ret = HPI_ERROR_DSP_FILE_NOT_FOUND;
        int err;
 
        sprintf(fw_name, "asihpi/dsp%04x.bin", adapter);
@@ -85,8 +86,10 @@ short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code,
 
        HPI_DEBUG_LOG(DEBUG, "dsp code %s opened\n", fw_name);
        dsp_code->pvt = kmalloc(sizeof(*dsp_code->pvt), GFP_KERNEL);
-       if (!dsp_code->pvt)
-               return HPI_ERROR_MEMORY_ALLOC;
+       if (!dsp_code->pvt) {
+               err_ret = HPI_ERROR_MEMORY_ALLOC;
+               goto error2;
+       }
 
        dsp_code->pvt->dev = dev;
        dsp_code->pvt->firmware = firmware;
@@ -99,7 +102,7 @@ error2:
        release_firmware(firmware);
 error1:
        dsp_code->block_length = 0;
-       return HPI_ERROR_DSP_FILE_NOT_FOUND;
+       return err_ret;
 }
 
 /*-------------------------------------------------------------------*/
index 9683f84..a32502e 100644 (file)
@@ -177,16 +177,21 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        } else {
                u16 __user *ptr = NULL;
                u32 size = 0;
-
+               u32 adapter_present;
                /* -1=no data 0=read from user mem, 1=write to user mem */
                int wrflag = -1;
-               u32 adapter = hm->h.adapter_index;
-               struct hpi_adapter *pa = &adapters[adapter];
+               struct hpi_adapter *pa;
+
+               if (hm->h.adapter_index < HPI_MAX_ADAPTERS) {
+                       pa = &adapters[hm->h.adapter_index];
+                       adapter_present = pa->type;
+               } else {
+                       adapter_present = 0;
+               }
 
-               if ((adapter >= HPI_MAX_ADAPTERS) || (!pa->type)) {
-                       hpi_init_response(&hr->r0, HPI_OBJ_ADAPTER,
-                               HPI_ADAPTER_OPEN,
-                               HPI_ERROR_BAD_ADAPTER_NUMBER);
+               if (!adapter_present) {
+                       hpi_init_response(&hr->r0, hm->h.object,
+                               hm->h.function, HPI_ERROR_BAD_ADAPTER_NUMBER);
 
                        uncopied_bytes =
                                copy_to_user(puhr, hr, sizeof(hr->h));
index e4d76a2..579fc0d 100644 (file)
@@ -2625,16 +2625,19 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
        int err;
 
        snd_azf3328_dbgcallenter();
-       if (dev >= SNDRV_CARDS)
-               return -ENODEV;
+       if (dev >= SNDRV_CARDS) {
+               err = -ENODEV;
+               goto out;
+       }
        if (!enable[dev]) {
                dev++;
-               return -ENOENT;
+               err = -ENOENT;
+               goto out;
        }
 
        err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
        if (err < 0)
-               return err;
+               goto out;
 
        strcpy(card->driver, "AZF3328");
        strcpy(card->shortname, "Aztech AZF3328 (PCI168)");
index be58bf2..2e5876c 100644 (file)
@@ -476,8 +476,8 @@ static const struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
 
 static const struct alc_config_preset alc268_presets[] = {
        [ALC267_QUANTA_IL1] = {
-               .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
-                           alc268_capture_nosrc_mixer },
+               .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer },
+               .cap_mixer = alc268_capture_nosrc_mixer,
                .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
                                alc267_quanta_il1_verbs },
                .num_dacs = ARRAY_SIZE(alc268_dac_nids),
@@ -492,8 +492,8 @@ static const struct alc_config_preset alc268_presets[] = {
                .init_hook = alc_inithook,
        },
        [ALC268_3ST] = {
-               .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
-                           alc268_beep_mixer },
+               .mixers = { alc268_base_mixer, alc268_beep_mixer },
+               .cap_mixer = alc268_capture_alt_mixer,
                .init_verbs = { alc268_base_init_verbs },
                .num_dacs = ARRAY_SIZE(alc268_dac_nids),
                .dac_nids = alc268_dac_nids,
@@ -507,8 +507,8 @@ static const struct alc_config_preset alc268_presets[] = {
                .input_mux = &alc268_capture_source,
        },
        [ALC268_TOSHIBA] = {
-               .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
-                           alc268_beep_mixer },
+               .mixers = { alc268_toshiba_mixer, alc268_beep_mixer },
+               .cap_mixer = alc268_capture_alt_mixer,
                .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
                                alc268_toshiba_verbs },
                .num_dacs = ARRAY_SIZE(alc268_dac_nids),
@@ -525,8 +525,8 @@ static const struct alc_config_preset alc268_presets[] = {
                .init_hook = alc_inithook,
        },
        [ALC268_ACER] = {
-               .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
-                           alc268_beep_mixer },
+               .mixers = { alc268_acer_mixer, alc268_beep_mixer },
+               .cap_mixer = alc268_capture_alt_mixer,
                .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
                                alc268_acer_verbs },
                .num_dacs = ARRAY_SIZE(alc268_dac_nids),
@@ -543,8 +543,8 @@ static const struct alc_config_preset alc268_presets[] = {
                .init_hook = alc_inithook,
        },
        [ALC268_ACER_DMIC] = {
-               .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
-                           alc268_beep_mixer },
+               .mixers = { alc268_acer_dmic_mixer, alc268_beep_mixer },
+               .cap_mixer = alc268_capture_alt_mixer,
                .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
                                alc268_acer_verbs },
                .num_dacs = ARRAY_SIZE(alc268_dac_nids),
@@ -561,9 +561,8 @@ static const struct alc_config_preset alc268_presets[] = {
                .init_hook = alc_inithook,
        },
        [ALC268_ACER_ASPIRE_ONE] = {
-               .mixers = { alc268_acer_aspire_one_mixer,
-                           alc268_beep_mixer,
-                           alc268_capture_nosrc_mixer },
+               .mixers = { alc268_acer_aspire_one_mixer, alc268_beep_mixer},
+               .cap_mixer = alc268_capture_nosrc_mixer,
                .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
                                alc268_acer_aspire_one_verbs },
                .num_dacs = ARRAY_SIZE(alc268_dac_nids),
@@ -579,8 +578,8 @@ static const struct alc_config_preset alc268_presets[] = {
                .init_hook = alc_inithook,
        },
        [ALC268_DELL] = {
-               .mixers = { alc268_dell_mixer, alc268_beep_mixer,
-                           alc268_capture_nosrc_mixer },
+               .mixers = { alc268_dell_mixer, alc268_beep_mixer},
+               .cap_mixer = alc268_capture_nosrc_mixer,
                .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
                                alc268_dell_verbs },
                .num_dacs = ARRAY_SIZE(alc268_dac_nids),
@@ -596,8 +595,8 @@ static const struct alc_config_preset alc268_presets[] = {
                .init_hook = alc_inithook,
        },
        [ALC268_ZEPTO] = {
-               .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
-                           alc268_beep_mixer },
+               .mixers = { alc268_base_mixer, alc268_beep_mixer },
+               .cap_mixer = alc268_capture_alt_mixer,
                .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
                                alc268_toshiba_verbs },
                .num_dacs = ARRAY_SIZE(alc268_dac_nids),
@@ -616,7 +615,8 @@ static const struct alc_config_preset alc268_presets[] = {
        },
 #ifdef CONFIG_SND_DEBUG
        [ALC268_TEST] = {
-               .mixers = { alc268_test_mixer, alc268_capture_mixer },
+               .mixers = { alc268_test_mixer },
+               .cap_mixer = alc268_capture_mixer,
                .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
                                alc268_volume_init_verbs,
                                alc268_beep_init_verbs },
index 14fdcf2..5ac0e21 100644 (file)
@@ -531,17 +531,10 @@ static const struct snd_pci_quirk alc269_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC),
        SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC),
        SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC),
        SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC),
        SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC),
        SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC),
        SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
-                     ALC269_DMIC),
-       SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
-                     ALC269_DMIC),
-       SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC),
-       SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC),
        SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO),
        SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
        SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC),
index 28ce17d..c34f730 100644 (file)
@@ -144,25 +144,17 @@ static int cea_sampling_frequencies[8] = {
        SNDRV_PCM_RATE_192000,  /* 7: 192000Hz */
 };
 
-static unsigned char hdmi_get_eld_byte(struct hda_codec *codec, hda_nid_t nid,
+static unsigned int hdmi_get_eld_data(struct hda_codec *codec, hda_nid_t nid,
                                        int byte_index)
 {
        unsigned int val;
 
        val = snd_hda_codec_read(codec, nid, 0,
                                        AC_VERB_GET_HDMI_ELDD, byte_index);
-
 #ifdef BE_PARANOID
        printk(KERN_INFO "HDMI: ELD data byte %d: 0x%x\n", byte_index, val);
 #endif
-
-       if ((val & AC_ELDD_ELD_VALID) == 0) {
-               snd_printd(KERN_INFO "HDMI: invalid ELD data byte %d\n",
-                                                               byte_index);
-               val = 0;
-       }
-
-       return val & AC_ELDD_ELD_DATA;
+       return val;
 }
 
 #define GRAB_BITS(buf, byte, lowbit, bits)             \
@@ -344,11 +336,26 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
        if (!buf)
                return -ENOMEM;
 
-       for (i = 0; i < size; i++)
-               buf[i] = hdmi_get_eld_byte(codec, nid, i);
+       for (i = 0; i < size; i++) {
+               unsigned int val = hdmi_get_eld_data(codec, nid, i);
+               if (!(val & AC_ELDD_ELD_VALID)) {
+                       if (!i) {
+                               snd_printd(KERN_INFO
+                                          "HDMI: invalid ELD data\n");
+                               ret = -EINVAL;
+                               goto error;
+                       }
+                       snd_printd(KERN_INFO
+                                 "HDMI: invalid ELD data byte %d\n", i);
+                       val = 0;
+               } else
+                       val &= AC_ELDD_ELD_DATA;
+               buf[i] = val;
+       }
 
        ret = hdmi_update_eld(eld, buf, size);
 
+error:
        kfree(buf);
        return ret;
 }
index 47d6ffc..d6c93d9 100644 (file)
@@ -375,7 +375,7 @@ static int is_ext_mic(struct hda_codec *codec, unsigned int idx)
 static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin,
                         unsigned int *idxp)
 {
-       int i;
+       int i, idx;
        hda_nid_t nid;
 
        nid = codec->start_nid;
@@ -384,9 +384,11 @@ static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin,
                type = get_wcaps_type(get_wcaps(codec, nid));
                if (type != AC_WID_AUD_IN)
                        continue;
-               *idxp = snd_hda_get_conn_index(codec, nid, pin, false);
-               if (*idxp >= 0)
+               idx = snd_hda_get_conn_index(codec, nid, pin, false);
+               if (idx >= 0) {
+                       *idxp = idx;
                        return nid;
+               }
        }
        return 0;
 }
index e125c60..fcb11af 100644 (file)
@@ -1784,6 +1784,7 @@ static const char * const alc_slave_vols[] = {
        "Speaker Playback Volume",
        "Mono Playback Volume",
        "Line-Out Playback Volume",
+       "PCM Playback Volume",
        NULL,
 };
 
@@ -1798,6 +1799,7 @@ static const char * const alc_slave_sws[] = {
        "Mono Playback Switch",
        "IEC958 Playback Switch",
        "Line-Out Playback Switch",
+       "PCM Playback Switch",
        NULL,
 };
 
@@ -4484,6 +4486,22 @@ static void alc269_fixup_pcm_44k(struct hda_codec *codec,
        spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
 }
 
+static void alc269_fixup_stereo_dmic(struct hda_codec *codec,
+                                    const struct alc_fixup *fix, int action)
+{
+       int coef;
+
+       if (action != ALC_FIXUP_ACT_INIT)
+               return;
+       /* The digital-mic unit sends PDM (differential signal) instead of
+        * the standard PCM, thus you can't record a valid mono stream as is.
+        * Below is a workaround specific to ALC269 to control the dmic
+        * signal source as mono.
+        */
+       coef = alc_read_coef_idx(codec, 0x07);
+       alc_write_coef_idx(codec, 0x07, coef | 0x80);
+}
+
 enum {
        ALC269_FIXUP_SONY_VAIO,
        ALC275_FIXUP_SONY_VAIO_GPIO2,
@@ -4494,6 +4512,7 @@ enum {
        ALC275_FIXUP_SONY_HWEQ,
        ALC271_FIXUP_DMIC,
        ALC269_FIXUP_PCM_44K,
+       ALC269_FIXUP_STEREO_DMIC,
 };
 
 static const struct alc_fixup alc269_fixups[] = {
@@ -4556,10 +4575,19 @@ static const struct alc_fixup alc269_fixups[] = {
                .type = ALC_FIXUP_FUNC,
                .v.func = alc269_fixup_pcm_44k,
        },
+       [ALC269_FIXUP_STEREO_DMIC] = {
+               .type = ALC_FIXUP_FUNC,
+               .v.func = alc269_fixup_stereo_dmic,
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
+       SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
        SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
        SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
index aa376b5..5145b66 100644 (file)
@@ -673,6 +673,7 @@ static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
+#ifdef CONFIG_SND_HDA_POWER_SAVE
 static int stac_vrefout_set(struct hda_codec *codec,
                                        hda_nid_t nid, unsigned int new_vref)
 {
@@ -696,6 +697,7 @@ static int stac_vrefout_set(struct hda_codec *codec,
 
        return 1;
 }
+#endif
 
 static unsigned int stac92xx_vref_set(struct hda_codec *codec,
                                        hda_nid_t nid, unsigned int new_vref)
index 84d8798..4ebfbd8 100644 (file)
@@ -2084,7 +2084,7 @@ static int via_auto_create_speaker_ctls(struct hda_codec *codec)
        struct via_spec *spec = codec->spec;
        struct nid_path *path;
        bool check_dac;
-       hda_nid_t pin, dac;
+       hda_nid_t pin, dac = 0;
        int err;
 
        pin = spec->autocfg.speaker_pins[0];
index af130ee..493e394 100644 (file)
@@ -521,6 +521,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
 #define HDSPM_DMA_AREA_KILOBYTES (HDSPM_DMA_AREA_BYTES/1024)
 
 /* revisions >= 230 indicate AES32 card */
+#define HDSPM_MADI_ANCIENT_REV 204
 #define HDSPM_MADI_OLD_REV     207
 #define HDSPM_MADI_REV         210
 #define HDSPM_RAYDAT_REV       211
@@ -1217,6 +1218,22 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm)
                                rate = 0;
                                break;
                        }
+
+                       /* QS and DS rates normally can not be detected
+                        * automatically by the card. Only exception is MADI
+                        * in 96k frame mode.
+                        *
+                        * So if we read SS values (32 .. 48k), check for
+                        * user-provided DS/QS bits in the control register
+                        * and multiply the base frequency accordingly.
+                        */
+                       if (rate <= 48000) {
+                               if (hdspm->control_register & HDSPM_QuadSpeed)
+                                       rate *= 4;
+                               else if (hdspm->control_register &
+                                               HDSPM_DoubleSpeed)
+                                       rate *= 2;
+                       }
                }
                break;
        }
@@ -1322,6 +1339,10 @@ static u64 hdspm_calc_dds_value(struct hdspm *hdspm, u64 period)
                break;
        case MADIface:
                freq_const = 131072000000000ULL;
+               break;
+       default:
+               snd_BUG();
+               return 0;
        }
 
        return div_u64(freq_const, period);
@@ -1339,16 +1360,19 @@ static void hdspm_set_dds_value(struct hdspm *hdspm, int rate)
 
        switch (hdspm->io_type) {
        case MADIface:
-         n = 131072000000000ULL;  /* 125 MHz */
-         break;
+               n = 131072000000000ULL;  /* 125 MHz */
+               break;
        case MADI:
        case AES32:
-         n = 110069313433624ULL;  /* 105 MHz */
-         break;
+               n = 110069313433624ULL;  /* 105 MHz */
+               break;
        case RayDAT:
        case AIO:
-         n = 104857600000000ULL;  /* 100 MHz */
-         break;
+               n = 104857600000000ULL;  /* 100 MHz */
+               break;
+       default:
+               snd_BUG();
+               return;
        }
 
        n = div_u64(n, rate);
@@ -3415,6 +3439,91 @@ static int snd_hdspm_put_qs_wire(struct snd_kcontrol *kcontrol,
        return change;
 }
 
+#define HDSPM_MADI_SPEEDMODE(xname, xindex) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = xname, \
+       .index = xindex, \
+       .info = snd_hdspm_info_madi_speedmode, \
+       .get = snd_hdspm_get_madi_speedmode, \
+       .put = snd_hdspm_put_madi_speedmode \
+}
+
+static int hdspm_madi_speedmode(struct hdspm *hdspm)
+{
+       if (hdspm->control_register & HDSPM_QuadSpeed)
+               return 2;
+       if (hdspm->control_register & HDSPM_DoubleSpeed)
+               return 1;
+       return 0;
+}
+
+static int hdspm_set_madi_speedmode(struct hdspm *hdspm, int mode)
+{
+       hdspm->control_register &= ~(HDSPM_DoubleSpeed | HDSPM_QuadSpeed);
+       switch (mode) {
+       case 0:
+               break;
+       case 1:
+               hdspm->control_register |= HDSPM_DoubleSpeed;
+               break;
+       case 2:
+               hdspm->control_register |= HDSPM_QuadSpeed;
+               break;
+       }
+       hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+
+       return 0;
+}
+
+static int snd_hdspm_info_madi_speedmode(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_info *uinfo)
+{
+       static char *texts[] = { "Single", "Double", "Quad" };
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = 3;
+
+       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+               uinfo->value.enumerated.item =
+                   uinfo->value.enumerated.items - 1;
+       strcpy(uinfo->value.enumerated.name,
+              texts[uinfo->value.enumerated.item]);
+
+       return 0;
+}
+
+static int snd_hdspm_get_madi_speedmode(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+       spin_lock_irq(&hdspm->lock);
+       ucontrol->value.enumerated.item[0] = hdspm_madi_speedmode(hdspm);
+       spin_unlock_irq(&hdspm->lock);
+       return 0;
+}
+
+static int snd_hdspm_put_madi_speedmode(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+       int change;
+       int val;
+
+       if (!snd_hdspm_use_is_exclusive(hdspm))
+               return -EBUSY;
+       val = ucontrol->value.integer.value[0];
+       if (val < 0)
+               val = 0;
+       if (val > 2)
+               val = 2;
+       spin_lock_irq(&hdspm->lock);
+       change = val != hdspm_madi_speedmode(hdspm);
+       hdspm_set_madi_speedmode(hdspm, val);
+       spin_unlock_irq(&hdspm->lock);
+       return change;
+}
 
 #define HDSPM_MIXER(xname, xindex) \
 { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
@@ -4289,7 +4398,8 @@ static struct snd_kcontrol_new snd_hdspm_controls_madi[] = {
        HDSPM_TX_64("TX 64 channels mode", 0),
        HDSPM_C_TMS("Clear Track Marker", 0),
        HDSPM_SAFE_MODE("Safe Mode", 0),
-       HDSPM_INPUT_SELECT("Input Select", 0)
+       HDSPM_INPUT_SELECT("Input Select", 0),
+       HDSPM_MADI_SPEEDMODE("MADI Speed Mode", 0)
 };
 
 
@@ -4302,7 +4412,8 @@ static struct snd_kcontrol_new snd_hdspm_controls_madiface[] = {
        HDSPM_SYNC_CHECK("MADI SyncCheck", 0),
        HDSPM_TX_64("TX 64 channels mode", 0),
        HDSPM_C_TMS("Clear Track Marker", 0),
-       HDSPM_SAFE_MODE("Safe Mode", 0)
+       HDSPM_SAFE_MODE("Safe Mode", 0),
+       HDSPM_MADI_SPEEDMODE("MADI Speed Mode", 0)
 };
 
 static struct snd_kcontrol_new snd_hdspm_controls_aio[] = {
@@ -6381,6 +6492,7 @@ static int __devinit snd_hdspm_create(struct snd_card *card,
        switch (hdspm->firmware_rev) {
        case HDSPM_MADI_REV:
        case HDSPM_MADI_OLD_REV:
+       case HDSPM_MADI_ANCIENT_REV:
                hdspm->io_type = MADI;
                hdspm->card_name = "RME MADI";
                hdspm->midiPorts = 3;
index 379b2e3..665d924 100644 (file)
@@ -78,7 +78,6 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_WM8900 if I2C
        select SND_SOC_WM8903 if I2C
        select SND_SOC_WM8904 if I2C
-       select SND_SOC_WM8915 if I2C
        select SND_SOC_WM8940 if I2C
        select SND_SOC_WM8955 if I2C
        select SND_SOC_WM8960 if I2C
@@ -95,6 +94,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_WM8993 if I2C
        select SND_SOC_WM8994 if MFD_WM8994
        select SND_SOC_WM8995 if SND_SOC_I2C_AND_SPI
+       select SND_SOC_WM8996 if I2C
        select SND_SOC_WM9081 if I2C
        select SND_SOC_WM9090 if I2C
        select SND_SOC_WM9705 if SND_SOC_AC97_BUS
@@ -329,9 +329,6 @@ config SND_SOC_WM8903
 config SND_SOC_WM8904
        tristate
 
-config SND_SOC_WM8915
-       tristate
-
 config SND_SOC_WM8940
         tristate
 
@@ -380,6 +377,9 @@ config SND_SOC_WM8994
 config SND_SOC_WM8995
        tristate
 
+config SND_SOC_WM8996
+       tristate
+
 config SND_SOC_WM9081
        tristate
 
index da9990f..5119a7e 100644 (file)
@@ -63,7 +63,7 @@ snd-soc-wm8804-objs := wm8804.o
 snd-soc-wm8900-objs := wm8900.o
 snd-soc-wm8903-objs := wm8903.o
 snd-soc-wm8904-objs := wm8904.o
-snd-soc-wm8915-objs := wm8915.o
+snd-soc-wm8996-objs := wm8996.o
 snd-soc-wm8940-objs := wm8940.o
 snd-soc-wm8955-objs := wm8955.o
 snd-soc-wm8960-objs := wm8960.o
@@ -160,7 +160,7 @@ obj-$(CONFIG_SND_SOC_WM8804)        += snd-soc-wm8804.o
 obj-$(CONFIG_SND_SOC_WM8900)   += snd-soc-wm8900.o
 obj-$(CONFIG_SND_SOC_WM8903)   += snd-soc-wm8903.o
 obj-$(CONFIG_SND_SOC_WM8904)   += snd-soc-wm8904.o
-obj-$(CONFIG_SND_SOC_WM8915)   += snd-soc-wm8915.o
+obj-$(CONFIG_SND_SOC_WM8996)   += snd-soc-wm8996.o
 obj-$(CONFIG_SND_SOC_WM8940)   += snd-soc-wm8940.o
 obj-$(CONFIG_SND_SOC_WM8955)   += snd-soc-wm8955.o
 obj-$(CONFIG_SND_SOC_WM8960)   += snd-soc-wm8960.o
index 76258f2..7e4066e 100644 (file)
 #define SGTL5000_DAP_REG_OFFSET        0x0100
 #define SGTL5000_MAX_REG_OFFSET        0x013A
 
-/* default value of sgtl5000 registers except DAP */
-static const u16 sgtl5000_regs[SGTL5000_MAX_REG_OFFSET >> 1] =  {
-       0xa011, /* 0x0000, CHIP_ID. 11 stand for revison 17 */
-       0x0000, /* 0x0002, CHIP_DIG_POWER. */
-       0x0008, /* 0x0004, CHIP_CKL_CTRL */
-       0x0010, /* 0x0006, CHIP_I2S_CTRL */
-       0x0000, /* 0x0008, reserved */
-       0x0008, /* 0x000A, CHIP_SSS_CTRL */
-       0x0000, /* 0x000C, reserved */
-       0x020c, /* 0x000E, CHIP_ADCDAC_CTRL */
-       0x3c3c, /* 0x0010, CHIP_DAC_VOL */
-       0x0000, /* 0x0012, reserved */
-       0x015f, /* 0x0014, CHIP_PAD_STRENGTH */
-       0x0000, /* 0x0016, reserved */
-       0x0000, /* 0x0018, reserved */
-       0x0000, /* 0x001A, reserved */
-       0x0000, /* 0x001E, reserved */
-       0x0000, /* 0x0020, CHIP_ANA_ADC_CTRL */
-       0x1818, /* 0x0022, CHIP_ANA_HP_CTRL */
-       0x0111, /* 0x0024, CHIP_ANN_CTRL */
-       0x0000, /* 0x0026, CHIP_LINREG_CTRL */
-       0x0000, /* 0x0028, CHIP_REF_CTRL */
-       0x0000, /* 0x002A, CHIP_MIC_CTRL */
-       0x0000, /* 0x002C, CHIP_LINE_OUT_CTRL */
-       0x0404, /* 0x002E, CHIP_LINE_OUT_VOL */
-       0x7060, /* 0x0030, CHIP_ANA_POWER */
-       0x5000, /* 0x0032, CHIP_PLL_CTRL */
-       0x0000, /* 0x0034, CHIP_CLK_TOP_CTRL */
-       0x0000, /* 0x0036, CHIP_ANA_STATUS */
-       0x0000, /* 0x0038, reserved */
-       0x0000, /* 0x003A, CHIP_ANA_TEST2 */
-       0x0000, /* 0x003C, CHIP_SHORT_CTRL */
-       0x0000, /* reserved */
-};
-
-/* default value of dap registers */
-static const u16 sgtl5000_dap_regs[] = {
-       0x0000, /* 0x0100, DAP_CONTROL */
-       0x0000, /* 0x0102, DAP_PEQ */
-       0x0040, /* 0x0104, DAP_BASS_ENHANCE */
-       0x051f, /* 0x0106, DAP_BASS_ENHANCE_CTRL */
-       0x0000, /* 0x0108, DAP_AUDIO_EQ */
-       0x0040, /* 0x010A, DAP_SGTL_SURROUND */
-       0x0000, /* 0x010C, DAP_FILTER_COEF_ACCESS */
-       0x0000, /* 0x010E, DAP_COEF_WR_B0_MSB */
-       0x0000, /* 0x0110, DAP_COEF_WR_B0_LSB */
-       0x0000, /* 0x0112, reserved */
-       0x0000, /* 0x0114, reserved */
-       0x002f, /* 0x0116, DAP_AUDIO_EQ_BASS_BAND0 */
-       0x002f, /* 0x0118, DAP_AUDIO_EQ_BAND0 */
-       0x002f, /* 0x011A, DAP_AUDIO_EQ_BAND2 */
-       0x002f, /* 0x011C, DAP_AUDIO_EQ_BAND3 */
-       0x002f, /* 0x011E, DAP_AUDIO_EQ_TREBLE_BAND4 */
-       0x8000, /* 0x0120, DAP_MAIN_CHAN */
-       0x0000, /* 0x0122, DAP_MIX_CHAN */
-       0x0510, /* 0x0124, DAP_AVC_CTRL */
-       0x1473, /* 0x0126, DAP_AVC_THRESHOLD */
-       0x0028, /* 0x0128, DAP_AVC_ATTACK */
-       0x0050, /* 0x012A, DAP_AVC_DECAY */
-       0x0000, /* 0x012C, DAP_COEF_WR_B1_MSB */
-       0x0000, /* 0x012E, DAP_COEF_WR_B1_LSB */
-       0x0000, /* 0x0130, DAP_COEF_WR_B2_MSB */
-       0x0000, /* 0x0132, DAP_COEF_WR_B2_LSB */
-       0x0000, /* 0x0134, DAP_COEF_WR_A1_MSB */
-       0x0000, /* 0x0136, DAP_COEF_WR_A1_LSB */
-       0x0000, /* 0x0138, DAP_COEF_WR_A2_MSB */
-       0x0000, /* 0x013A, DAP_COEF_WR_A2_LSB */
+/* default value of sgtl5000 registers */
+static const u16 sgtl5000_regs[SGTL5000_MAX_REG_OFFSET] =  {
+       [SGTL5000_CHIP_CLK_CTRL] = 0x0008,
+       [SGTL5000_CHIP_I2S_CTRL] = 0x0010,
+       [SGTL5000_CHIP_SSS_CTRL] = 0x0008,
+       [SGTL5000_CHIP_DAC_VOL] = 0x3c3c,
+       [SGTL5000_CHIP_PAD_STRENGTH] = 0x015f,
+       [SGTL5000_CHIP_ANA_HP_CTRL] = 0x1818,
+       [SGTL5000_CHIP_ANA_CTRL] = 0x0111,
+       [SGTL5000_CHIP_LINE_OUT_VOL] = 0x0404,
+       [SGTL5000_CHIP_ANA_POWER] = 0x7060,
+       [SGTL5000_CHIP_PLL_CTRL] = 0x5000,
+       [SGTL5000_DAP_BASS_ENHANCE] = 0x0040,
+       [SGTL5000_DAP_BASS_ENHANCE_CTRL] = 0x051f,
+       [SGTL5000_DAP_SURROUND] = 0x0040,
+       [SGTL5000_DAP_EQ_BASS_BAND0] = 0x002f,
+       [SGTL5000_DAP_EQ_BASS_BAND1] = 0x002f,
+       [SGTL5000_DAP_EQ_BASS_BAND2] = 0x002f,
+       [SGTL5000_DAP_EQ_BASS_BAND3] = 0x002f,
+       [SGTL5000_DAP_EQ_BASS_BAND4] = 0x002f,
+       [SGTL5000_DAP_MAIN_CHAN] = 0x8000,
+       [SGTL5000_DAP_AVC_CTRL] = 0x0510,
+       [SGTL5000_DAP_AVC_THRESHOLD] = 0x1473,
+       [SGTL5000_DAP_AVC_ATTACK] = 0x0028,
+       [SGTL5000_DAP_AVC_DECAY] = 0x0050,
 };
 
 /* regulator supplies for sgtl5000, VDDD is an optional external supply */
@@ -1023,12 +981,10 @@ static int sgtl5000_suspend(struct snd_soc_codec *codec, pm_message_t state)
 static int sgtl5000_restore_regs(struct snd_soc_codec *codec)
 {
        u16 *cache = codec->reg_cache;
-       int i;
-       int regular_regs = SGTL5000_CHIP_SHORT_CTRL >> 1;
+       u16 reg;
 
        /* restore regular registers */
-       for (i = 0; i < regular_regs; i++) {
-               int reg = i << 1;
+       for (reg = 0; reg <= SGTL5000_CHIP_SHORT_CTRL; reg += 2) {
 
                /* this regs depends on the others */
                if (reg == SGTL5000_CHIP_ANA_POWER ||
@@ -1038,35 +994,31 @@ static int sgtl5000_restore_regs(struct snd_soc_codec *codec)
                        reg == SGTL5000_CHIP_CLK_CTRL)
                        continue;
 
-               snd_soc_write(codec, reg, cache[i]);
+               snd_soc_write(codec, reg, cache[reg]);
        }
 
        /* restore dap registers */
-       for (i = SGTL5000_DAP_REG_OFFSET >> 1;
-                       i < SGTL5000_MAX_REG_OFFSET >> 1; i++) {
-               int reg = i << 1;
-
-               snd_soc_write(codec, reg, cache[i]);
-       }
+       for (reg = SGTL5000_DAP_REG_OFFSET; reg < SGTL5000_MAX_REG_OFFSET; reg += 2)
+               snd_soc_write(codec, reg, cache[reg]);
 
        /*
         * restore power and other regs according
         * to set_power() and set_clock()
         */
        snd_soc_write(codec, SGTL5000_CHIP_LINREG_CTRL,
-                       cache[SGTL5000_CHIP_LINREG_CTRL >> 1]);
+                       cache[SGTL5000_CHIP_LINREG_CTRL]);
 
        snd_soc_write(codec, SGTL5000_CHIP_ANA_POWER,
-                       cache[SGTL5000_CHIP_ANA_POWER >> 1]);
+                       cache[SGTL5000_CHIP_ANA_POWER]);
 
        snd_soc_write(codec, SGTL5000_CHIP_CLK_CTRL,
-                       cache[SGTL5000_CHIP_CLK_CTRL >> 1]);
+                       cache[SGTL5000_CHIP_CLK_CTRL]);
 
        snd_soc_write(codec, SGTL5000_CHIP_REF_CTRL,
-                       cache[SGTL5000_CHIP_REF_CTRL >> 1]);
+                       cache[SGTL5000_CHIP_REF_CTRL]);
 
        snd_soc_write(codec, SGTL5000_CHIP_LINE_OUT_CTRL,
-                       cache[SGTL5000_CHIP_LINE_OUT_CTRL >> 1]);
+                       cache[SGTL5000_CHIP_LINE_OUT_CTRL]);
        return 0;
 }
 
@@ -1454,16 +1406,6 @@ static __devinit int sgtl5000_i2c_probe(struct i2c_client *client,
        if (!sgtl5000)
                return -ENOMEM;
 
-       /*
-        * copy DAP default values to default value array.
-        * sgtl5000 register space has a big hole, merge it
-        * at init phase makes life easy.
-        * FIXME: should we drop 'const' of sgtl5000_regs?
-        */
-       memcpy((void *)(&sgtl5000_regs[0] + (SGTL5000_DAP_REG_OFFSET >> 1)),
-                       sgtl5000_dap_regs,
-                       SGTL5000_MAX_REG_OFFSET - SGTL5000_DAP_REG_OFFSET);
-
        i2c_set_clientdata(client, sgtl5000);
 
        ret = snd_soc_register_codec(&client->dev,
index 38f38fd..d0003cc 100644 (file)
@@ -778,11 +778,19 @@ static int __devexit wm8750_spi_remove(struct spi_device *spi)
        return 0;
 }
 
+static const struct spi_device_id wm8750_spi_ids[] = {
+       { "wm8750", 0 },
+       { "wm8987", 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(spi, wm8750_spi_ids);
+
 static struct spi_driver wm8750_spi_driver = {
        .driver = {
                .name   = "wm8750-codec",
                .owner  = THIS_MODULE,
        },
+       .id_table       = wm8750_spi_ids,
        .probe          = wm8750_spi_probe,
        .remove         = __devexit_p(wm8750_spi_remove),
 };
index 43e3d76..4ad8ebd 100644 (file)
@@ -2046,8 +2046,13 @@ static int wm8903_probe(struct snd_soc_codec *codec)
 /* power down chip */
 static int wm8903_remove(struct snd_soc_codec *codec)
 {
+       struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
+
        wm8903_free_gpio(codec);
        wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       if (wm8903->irq)
+               free_irq(wm8903->irq, codec);
+
        return 0;
 }
 
diff --git a/sound/soc/codecs/wm8915.c b/sound/soc/codecs/wm8915.c
deleted file mode 100644 (file)
index 423baa9..0000000
+++ /dev/null
@@ -1,2995 +0,0 @@
-/*
- * wm8915.c - WM8915 audio codec interface
- *
- * Copyright 2011 Wolfson Microelectronics PLC.
- * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/completion.h>
-#include <linux/delay.h>
-#include <linux/pm.h>
-#include <linux/gcd.h>
-#include <linux/gpio.h>
-#include <linux/i2c.h>
-#include <linux/regulator/consumer.h>
-#include <linux/slab.h>
-#include <linux/workqueue.h>
-#include <sound/core.h>
-#include <sound/jack.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/initval.h>
-#include <sound/tlv.h>
-#include <trace/events/asoc.h>
-
-#include <sound/wm8915.h>
-#include "wm8915.h"
-
-#define WM8915_AIFS 2
-
-#define HPOUT1L 1
-#define HPOUT1R 2
-#define HPOUT2L 4
-#define HPOUT2R 8
-
-#define WM8915_NUM_SUPPLIES 4
-static const char *wm8915_supply_names[WM8915_NUM_SUPPLIES] = {
-       "DBVDD",
-       "AVDD1",
-       "AVDD2",
-       "CPVDD",
-};
-
-struct wm8915_priv {
-       struct snd_soc_codec *codec;
-
-       int ldo1ena;
-
-       int sysclk;
-       int sysclk_src;
-
-       int fll_src;
-       int fll_fref;
-       int fll_fout;
-
-       struct completion fll_lock;
-
-       u16 dcs_pending;
-       struct completion dcs_done;
-
-       u16 hpout_ena;
-       u16 hpout_pending;
-
-       struct regulator_bulk_data supplies[WM8915_NUM_SUPPLIES];
-       struct notifier_block disable_nb[WM8915_NUM_SUPPLIES];
-
-       struct wm8915_pdata pdata;
-
-       int rx_rate[WM8915_AIFS];
-       int bclk_rate[WM8915_AIFS];
-
-       /* Platform dependant ReTune mobile configuration */
-       int num_retune_mobile_texts;
-       const char **retune_mobile_texts;
-       int retune_mobile_cfg[2];
-       struct soc_enum retune_mobile_enum;
-
-       struct snd_soc_jack *jack;
-       bool detecting;
-       bool jack_mic;
-       wm8915_polarity_fn polarity_cb;
-
-#ifdef CONFIG_GPIOLIB
-       struct gpio_chip gpio_chip;
-#endif
-};
-
-/* We can't use the same notifier block for more than one supply and
- * there's no way I can see to get from a callback to the caller
- * except container_of().
- */
-#define WM8915_REGULATOR_EVENT(n) \
-static int wm8915_regulator_event_##n(struct notifier_block *nb, \
-                                   unsigned long event, void *data)    \
-{ \
-       struct wm8915_priv *wm8915 = container_of(nb, struct wm8915_priv, \
-                                                 disable_nb[n]); \
-       if (event & REGULATOR_EVENT_DISABLE) { \
-               wm8915->codec->cache_sync = 1; \
-       } \
-       return 0; \
-}
-
-WM8915_REGULATOR_EVENT(0)
-WM8915_REGULATOR_EVENT(1)
-WM8915_REGULATOR_EVENT(2)
-WM8915_REGULATOR_EVENT(3)
-
-static const u16 wm8915_reg[WM8915_MAX_REGISTER] = {
-       [WM8915_SOFTWARE_RESET] = 0x8915,
-       [WM8915_POWER_MANAGEMENT_7] = 0x10,
-       [WM8915_DAC1_HPOUT1_VOLUME] = 0x88,
-       [WM8915_DAC2_HPOUT2_VOLUME] = 0x88,
-       [WM8915_DAC1_LEFT_VOLUME] = 0x2c0,
-       [WM8915_DAC1_RIGHT_VOLUME] = 0x2c0,
-       [WM8915_DAC2_LEFT_VOLUME] = 0x2c0,
-       [WM8915_DAC2_RIGHT_VOLUME] = 0x2c0,
-       [WM8915_OUTPUT1_LEFT_VOLUME] = 0x80,
-       [WM8915_OUTPUT1_RIGHT_VOLUME] = 0x80,
-       [WM8915_OUTPUT2_LEFT_VOLUME] = 0x80,
-       [WM8915_OUTPUT2_RIGHT_VOLUME] = 0x80,
-       [WM8915_MICBIAS_1] = 0x39,
-       [WM8915_MICBIAS_2] = 0x39,
-       [WM8915_LDO_1] = 0x3,
-       [WM8915_LDO_2] = 0x13,
-       [WM8915_ACCESSORY_DETECT_MODE_1] = 0x4,
-       [WM8915_HEADPHONE_DETECT_1] = 0x20,
-       [WM8915_MIC_DETECT_1] = 0x7600,
-       [WM8915_MIC_DETECT_2] = 0xbf,
-       [WM8915_CHARGE_PUMP_1] = 0x1f25,
-       [WM8915_CHARGE_PUMP_2] = 0xab19,
-       [WM8915_DC_SERVO_5] = 0x2a2a,
-       [WM8915_CONTROL_INTERFACE_1] = 0x8004,
-       [WM8915_CLOCKING_1] = 0x10,
-       [WM8915_AIF_RATE] = 0x83,
-       [WM8915_FLL_CONTROL_4] = 0x5dc0,
-       [WM8915_FLL_CONTROL_5] = 0xc84,
-       [WM8915_FLL_EFS_2] = 0x2,
-       [WM8915_AIF1_TX_LRCLK_1] = 0x80,
-       [WM8915_AIF1_TX_LRCLK_2] = 0x8,
-       [WM8915_AIF1_RX_LRCLK_1] = 0x80,
-       [WM8915_AIF1TX_DATA_CONFIGURATION_1] = 0x1818,
-       [WM8915_AIF1RX_DATA_CONFIGURATION] = 0x1818,
-       [WM8915_AIF1TX_TEST] = 0x7,
-       [WM8915_AIF2_TX_LRCLK_1] = 0x80,
-       [WM8915_AIF2_TX_LRCLK_2] = 0x8,
-       [WM8915_AIF2_RX_LRCLK_1] = 0x80,
-       [WM8915_AIF2TX_DATA_CONFIGURATION_1] = 0x1818,
-       [WM8915_AIF2RX_DATA_CONFIGURATION] = 0x1818,
-       [WM8915_AIF2TX_TEST] = 0x1,
-       [WM8915_DSP1_TX_LEFT_VOLUME] = 0xc0,
-       [WM8915_DSP1_TX_RIGHT_VOLUME] = 0xc0,
-       [WM8915_DSP1_RX_LEFT_VOLUME] = 0xc0,
-       [WM8915_DSP1_RX_RIGHT_VOLUME] = 0xc0,
-       [WM8915_DSP1_TX_FILTERS] = 0x2000,
-       [WM8915_DSP1_RX_FILTERS_1] = 0x200,
-       [WM8915_DSP1_RX_FILTERS_2] = 0x10,
-       [WM8915_DSP1_DRC_1] = 0x98,
-       [WM8915_DSP1_DRC_2] = 0x845,
-       [WM8915_DSP1_RX_EQ_GAINS_1] = 0x6318,
-       [WM8915_DSP1_RX_EQ_GAINS_2] = 0x6300,
-       [WM8915_DSP1_RX_EQ_BAND_1_A] = 0xfca,
-       [WM8915_DSP1_RX_EQ_BAND_1_B] = 0x400,
-       [WM8915_DSP1_RX_EQ_BAND_1_PG] = 0xd8,
-       [WM8915_DSP1_RX_EQ_BAND_2_A] = 0x1eb5,
-       [WM8915_DSP1_RX_EQ_BAND_2_B] = 0xf145,
-       [WM8915_DSP1_RX_EQ_BAND_2_C] = 0xb75,
-       [WM8915_DSP1_RX_EQ_BAND_2_PG] = 0x1c5,
-       [WM8915_DSP1_RX_EQ_BAND_3_A] = 0x1c58,
-       [WM8915_DSP1_RX_EQ_BAND_3_B] = 0xf373,
-       [WM8915_DSP1_RX_EQ_BAND_3_C] = 0xa54,
-       [WM8915_DSP1_RX_EQ_BAND_3_PG] = 0x558,
-       [WM8915_DSP1_RX_EQ_BAND_4_A] = 0x168e,
-       [WM8915_DSP1_RX_EQ_BAND_4_B] = 0xf829,
-       [WM8915_DSP1_RX_EQ_BAND_4_C] = 0x7ad,
-       [WM8915_DSP1_RX_EQ_BAND_4_PG] = 0x1103,
-       [WM8915_DSP1_RX_EQ_BAND_5_A] = 0x564,
-       [WM8915_DSP1_RX_EQ_BAND_5_B] = 0x559,
-       [WM8915_DSP1_RX_EQ_BAND_5_PG] = 0x4000,
-       [WM8915_DSP2_TX_LEFT_VOLUME] = 0xc0,
-       [WM8915_DSP2_TX_RIGHT_VOLUME] = 0xc0,
-       [WM8915_DSP2_RX_LEFT_VOLUME] = 0xc0,
-       [WM8915_DSP2_RX_RIGHT_VOLUME] = 0xc0,
-       [WM8915_DSP2_TX_FILTERS] = 0x2000,
-       [WM8915_DSP2_RX_FILTERS_1] = 0x200,
-       [WM8915_DSP2_RX_FILTERS_2] = 0x10,
-       [WM8915_DSP2_DRC_1] = 0x98,
-       [WM8915_DSP2_DRC_2] = 0x845,
-       [WM8915_DSP2_RX_EQ_GAINS_1] = 0x6318,
-       [WM8915_DSP2_RX_EQ_GAINS_2] = 0x6300,
-       [WM8915_DSP2_RX_EQ_BAND_1_A] = 0xfca,
-       [WM8915_DSP2_RX_EQ_BAND_1_B] = 0x400,
-       [WM8915_DSP2_RX_EQ_BAND_1_PG] = 0xd8,
-       [WM8915_DSP2_RX_EQ_BAND_2_A] = 0x1eb5,
-       [WM8915_DSP2_RX_EQ_BAND_2_B] = 0xf145,
-       [WM8915_DSP2_RX_EQ_BAND_2_C] = 0xb75,
-       [WM8915_DSP2_RX_EQ_BAND_2_PG] = 0x1c5,
-       [WM8915_DSP2_RX_EQ_BAND_3_A] = 0x1c58,
-       [WM8915_DSP2_RX_EQ_BAND_3_B] = 0xf373,
-       [WM8915_DSP2_RX_EQ_BAND_3_C] = 0xa54,
-       [WM8915_DSP2_RX_EQ_BAND_3_PG] = 0x558,
-       [WM8915_DSP2_RX_EQ_BAND_4_A] = 0x168e,
-       [WM8915_DSP2_RX_EQ_BAND_4_B] = 0xf829,
-       [WM8915_DSP2_RX_EQ_BAND_4_C] = 0x7ad,
-       [WM8915_DSP2_RX_EQ_BAND_4_PG] = 0x1103,
-       [WM8915_DSP2_RX_EQ_BAND_5_A] = 0x564,
-       [WM8915_DSP2_RX_EQ_BAND_5_B] = 0x559,
-       [WM8915_DSP2_RX_EQ_BAND_5_PG] = 0x4000,
-       [WM8915_OVERSAMPLING] = 0xd,
-       [WM8915_SIDETONE] = 0x1040,
-       [WM8915_GPIO_1] = 0xa101,
-       [WM8915_GPIO_2] = 0xa101,
-       [WM8915_GPIO_3] = 0xa101,
-       [WM8915_GPIO_4] = 0xa101,
-       [WM8915_GPIO_5] = 0xa101,
-       [WM8915_PULL_CONTROL_2] = 0x140,
-       [WM8915_INTERRUPT_STATUS_1_MASK] = 0x1f,
-       [WM8915_INTERRUPT_STATUS_2_MASK] = 0x1ecf,
-       [WM8915_RIGHT_PDM_SPEAKER] = 0x1,
-       [WM8915_PDM_SPEAKER_MUTE_SEQUENCE] = 0x69,
-       [WM8915_PDM_SPEAKER_VOLUME] = 0x66,
-       [WM8915_WRITE_SEQUENCER_0] = 0x1,
-       [WM8915_WRITE_SEQUENCER_1] = 0x1,
-       [WM8915_WRITE_SEQUENCER_3] = 0x6,
-       [WM8915_WRITE_SEQUENCER_4] = 0x40,
-       [WM8915_WRITE_SEQUENCER_5] = 0x1,
-       [WM8915_WRITE_SEQUENCER_6] = 0xf,
-       [WM8915_WRITE_SEQUENCER_7] = 0x6,
-       [WM8915_WRITE_SEQUENCER_8] = 0x1,
-       [WM8915_WRITE_SEQUENCER_9] = 0x3,
-       [WM8915_WRITE_SEQUENCER_10] = 0x104,
-       [WM8915_WRITE_SEQUENCER_12] = 0x60,
-       [WM8915_WRITE_SEQUENCER_13] = 0x11,
-       [WM8915_WRITE_SEQUENCER_14] = 0x401,
-       [WM8915_WRITE_SEQUENCER_16] = 0x50,
-       [WM8915_WRITE_SEQUENCER_17] = 0x3,
-       [WM8915_WRITE_SEQUENCER_18] = 0x100,
-       [WM8915_WRITE_SEQUENCER_20] = 0x51,
-       [WM8915_WRITE_SEQUENCER_21] = 0x3,
-       [WM8915_WRITE_SEQUENCER_22] = 0x104,
-       [WM8915_WRITE_SEQUENCER_23] = 0xa,
-       [WM8915_WRITE_SEQUENCER_24] = 0x60,
-       [WM8915_WRITE_SEQUENCER_25] = 0x3b,
-       [WM8915_WRITE_SEQUENCER_26] = 0x502,
-       [WM8915_WRITE_SEQUENCER_27] = 0x100,
-       [WM8915_WRITE_SEQUENCER_28] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_32] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_36] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_40] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_44] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_48] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_52] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_56] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_60] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_64] = 0x1,
-       [WM8915_WRITE_SEQUENCER_65] = 0x1,
-       [WM8915_WRITE_SEQUENCER_67] = 0x6,
-       [WM8915_WRITE_SEQUENCER_68] = 0x40,
-       [WM8915_WRITE_SEQUENCER_69] = 0x1,
-       [WM8915_WRITE_SEQUENCER_70] = 0xf,
-       [WM8915_WRITE_SEQUENCER_71] = 0x6,
-       [WM8915_WRITE_SEQUENCER_72] = 0x1,
-       [WM8915_WRITE_SEQUENCER_73] = 0x3,
-       [WM8915_WRITE_SEQUENCER_74] = 0x104,
-       [WM8915_WRITE_SEQUENCER_76] = 0x60,
-       [WM8915_WRITE_SEQUENCER_77] = 0x11,
-       [WM8915_WRITE_SEQUENCER_78] = 0x401,
-       [WM8915_WRITE_SEQUENCER_80] = 0x50,
-       [WM8915_WRITE_SEQUENCER_81] = 0x3,
-       [WM8915_WRITE_SEQUENCER_82] = 0x100,
-       [WM8915_WRITE_SEQUENCER_84] = 0x60,
-       [WM8915_WRITE_SEQUENCER_85] = 0x3b,
-       [WM8915_WRITE_SEQUENCER_86] = 0x502,
-       [WM8915_WRITE_SEQUENCER_87] = 0x100,
-       [WM8915_WRITE_SEQUENCER_88] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_92] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_96] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_100] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_104] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_108] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_112] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_116] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_120] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_124] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_128] = 0x1,
-       [WM8915_WRITE_SEQUENCER_129] = 0x1,
-       [WM8915_WRITE_SEQUENCER_131] = 0x6,
-       [WM8915_WRITE_SEQUENCER_132] = 0x40,
-       [WM8915_WRITE_SEQUENCER_133] = 0x1,
-       [WM8915_WRITE_SEQUENCER_134] = 0xf,
-       [WM8915_WRITE_SEQUENCER_135] = 0x6,
-       [WM8915_WRITE_SEQUENCER_136] = 0x1,
-       [WM8915_WRITE_SEQUENCER_137] = 0x3,
-       [WM8915_WRITE_SEQUENCER_138] = 0x106,
-       [WM8915_WRITE_SEQUENCER_140] = 0x61,
-       [WM8915_WRITE_SEQUENCER_141] = 0x11,
-       [WM8915_WRITE_SEQUENCER_142] = 0x401,
-       [WM8915_WRITE_SEQUENCER_144] = 0x50,
-       [WM8915_WRITE_SEQUENCER_145] = 0x3,
-       [WM8915_WRITE_SEQUENCER_146] = 0x102,
-       [WM8915_WRITE_SEQUENCER_148] = 0x51,
-       [WM8915_WRITE_SEQUENCER_149] = 0x3,
-       [WM8915_WRITE_SEQUENCER_150] = 0x106,
-       [WM8915_WRITE_SEQUENCER_151] = 0xa,
-       [WM8915_WRITE_SEQUENCER_152] = 0x61,
-       [WM8915_WRITE_SEQUENCER_153] = 0x3b,
-       [WM8915_WRITE_SEQUENCER_154] = 0x502,
-       [WM8915_WRITE_SEQUENCER_155] = 0x100,
-       [WM8915_WRITE_SEQUENCER_156] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_160] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_164] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_168] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_172] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_176] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_180] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_184] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_188] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_192] = 0x1,
-       [WM8915_WRITE_SEQUENCER_193] = 0x1,
-       [WM8915_WRITE_SEQUENCER_195] = 0x6,
-       [WM8915_WRITE_SEQUENCER_196] = 0x40,
-       [WM8915_WRITE_SEQUENCER_197] = 0x1,
-       [WM8915_WRITE_SEQUENCER_198] = 0xf,
-       [WM8915_WRITE_SEQUENCER_199] = 0x6,
-       [WM8915_WRITE_SEQUENCER_200] = 0x1,
-       [WM8915_WRITE_SEQUENCER_201] = 0x3,
-       [WM8915_WRITE_SEQUENCER_202] = 0x106,
-       [WM8915_WRITE_SEQUENCER_204] = 0x61,
-       [WM8915_WRITE_SEQUENCER_205] = 0x11,
-       [WM8915_WRITE_SEQUENCER_206] = 0x401,
-       [WM8915_WRITE_SEQUENCER_208] = 0x50,
-       [WM8915_WRITE_SEQUENCER_209] = 0x3,
-       [WM8915_WRITE_SEQUENCER_210] = 0x102,
-       [WM8915_WRITE_SEQUENCER_212] = 0x61,
-       [WM8915_WRITE_SEQUENCER_213] = 0x3b,
-       [WM8915_WRITE_SEQUENCER_214] = 0x502,
-       [WM8915_WRITE_SEQUENCER_215] = 0x100,
-       [WM8915_WRITE_SEQUENCER_216] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_220] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_224] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_228] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_232] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_236] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_240] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_244] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_248] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_252] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_256] = 0x60,
-       [WM8915_WRITE_SEQUENCER_258] = 0x601,
-       [WM8915_WRITE_SEQUENCER_260] = 0x50,
-       [WM8915_WRITE_SEQUENCER_262] = 0x100,
-       [WM8915_WRITE_SEQUENCER_264] = 0x1,
-       [WM8915_WRITE_SEQUENCER_266] = 0x104,
-       [WM8915_WRITE_SEQUENCER_267] = 0x100,
-       [WM8915_WRITE_SEQUENCER_268] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_272] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_276] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_280] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_284] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_288] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_292] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_296] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_300] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_304] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_308] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_312] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_316] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_320] = 0x61,
-       [WM8915_WRITE_SEQUENCER_322] = 0x601,
-       [WM8915_WRITE_SEQUENCER_324] = 0x50,
-       [WM8915_WRITE_SEQUENCER_326] = 0x102,
-       [WM8915_WRITE_SEQUENCER_328] = 0x1,
-       [WM8915_WRITE_SEQUENCER_330] = 0x106,
-       [WM8915_WRITE_SEQUENCER_331] = 0x100,
-       [WM8915_WRITE_SEQUENCER_332] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_336] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_340] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_344] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_348] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_352] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_356] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_360] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_364] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_368] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_372] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_376] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_380] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_384] = 0x60,
-       [WM8915_WRITE_SEQUENCER_386] = 0x601,
-       [WM8915_WRITE_SEQUENCER_388] = 0x61,
-       [WM8915_WRITE_SEQUENCER_390] = 0x601,
-       [WM8915_WRITE_SEQUENCER_392] = 0x50,
-       [WM8915_WRITE_SEQUENCER_394] = 0x300,
-       [WM8915_WRITE_SEQUENCER_396] = 0x1,
-       [WM8915_WRITE_SEQUENCER_398] = 0x304,
-       [WM8915_WRITE_SEQUENCER_400] = 0x40,
-       [WM8915_WRITE_SEQUENCER_402] = 0xf,
-       [WM8915_WRITE_SEQUENCER_404] = 0x1,
-       [WM8915_WRITE_SEQUENCER_407] = 0x100,
-};
-
-static const DECLARE_TLV_DB_SCALE(inpga_tlv, 0, 100, 0);
-static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 150, 0);
-static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
-static const DECLARE_TLV_DB_SCALE(out_digital_tlv, -1200, 150, 0);
-static const DECLARE_TLV_DB_SCALE(out_tlv, -900, 75, 0);
-static const DECLARE_TLV_DB_SCALE(spk_tlv, -900, 150, 0);
-static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
-
-static const char *sidetone_hpf_text[] = {
-       "2.9kHz", "1.5kHz", "735Hz", "403Hz", "196Hz", "98Hz", "49Hz"
-};
-
-static const struct soc_enum sidetone_hpf =
-       SOC_ENUM_SINGLE(WM8915_SIDETONE, 7, 6, sidetone_hpf_text);
-
-static const char *hpf_mode_text[] = {
-       "HiFi", "Custom", "Voice"
-};
-
-static const struct soc_enum dsp1tx_hpf_mode =
-       SOC_ENUM_SINGLE(WM8915_DSP1_TX_FILTERS, 3, 3, hpf_mode_text);
-
-static const struct soc_enum dsp2tx_hpf_mode =
-       SOC_ENUM_SINGLE(WM8915_DSP2_TX_FILTERS, 3, 3, hpf_mode_text);
-
-static const char *hpf_cutoff_text[] = {
-       "50Hz", "75Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"
-};
-
-static const struct soc_enum dsp1tx_hpf_cutoff =
-       SOC_ENUM_SINGLE(WM8915_DSP1_TX_FILTERS, 0, 7, hpf_cutoff_text);
-
-static const struct soc_enum dsp2tx_hpf_cutoff =
-       SOC_ENUM_SINGLE(WM8915_DSP2_TX_FILTERS, 0, 7, hpf_cutoff_text);
-
-static void wm8915_set_retune_mobile(struct snd_soc_codec *codec, int block)
-{
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       struct wm8915_pdata *pdata = &wm8915->pdata;
-       int base, best, best_val, save, i, cfg, iface;
-
-       if (!wm8915->num_retune_mobile_texts)
-               return;
-
-       switch (block) {
-       case 0:
-               base = WM8915_DSP1_RX_EQ_GAINS_1;
-               if (snd_soc_read(codec, WM8915_POWER_MANAGEMENT_8) &
-                   WM8915_DSP1RX_SRC)
-                       iface = 1;
-               else
-                       iface = 0;
-               break;
-       case 1:
-               base = WM8915_DSP1_RX_EQ_GAINS_2;
-               if (snd_soc_read(codec, WM8915_POWER_MANAGEMENT_8) &
-                   WM8915_DSP2RX_SRC)
-                       iface = 1;
-               else
-                       iface = 0;
-               break;
-       default:
-               return;
-       }
-
-       /* Find the version of the currently selected configuration
-        * with the nearest sample rate. */
-       cfg = wm8915->retune_mobile_cfg[block];
-       best = 0;
-       best_val = INT_MAX;
-       for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
-               if (strcmp(pdata->retune_mobile_cfgs[i].name,
-                          wm8915->retune_mobile_texts[cfg]) == 0 &&
-                   abs(pdata->retune_mobile_cfgs[i].rate
-                       - wm8915->rx_rate[iface]) < best_val) {
-                       best = i;
-                       best_val = abs(pdata->retune_mobile_cfgs[i].rate
-                                      - wm8915->rx_rate[iface]);
-               }
-       }
-
-       dev_dbg(codec->dev, "ReTune Mobile %d %s/%dHz for %dHz sample rate\n",
-               block,
-               pdata->retune_mobile_cfgs[best].name,
-               pdata->retune_mobile_cfgs[best].rate,
-               wm8915->rx_rate[iface]);
-
-       /* The EQ will be disabled while reconfiguring it, remember the
-        * current configuration. 
-        */
-       save = snd_soc_read(codec, base);
-       save &= WM8915_DSP1RX_EQ_ENA;
-
-       for (i = 0; i < ARRAY_SIZE(pdata->retune_mobile_cfgs[best].regs); i++)
-               snd_soc_update_bits(codec, base + i, 0xffff,
-                                   pdata->retune_mobile_cfgs[best].regs[i]);
-
-       snd_soc_update_bits(codec, base, WM8915_DSP1RX_EQ_ENA, save);
-}
-
-/* Icky as hell but saves code duplication */
-static int wm8915_get_retune_mobile_block(const char *name)
-{
-       if (strcmp(name, "DSP1 EQ Mode") == 0)
-               return 0;
-       if (strcmp(name, "DSP2 EQ Mode") == 0)
-               return 1;
-       return -EINVAL;
-}
-
-static int wm8915_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
-                                        struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       struct wm8915_pdata *pdata = &wm8915->pdata;
-       int block = wm8915_get_retune_mobile_block(kcontrol->id.name);
-       int value = ucontrol->value.integer.value[0];
-
-       if (block < 0)
-               return block;
-
-       if (value >= pdata->num_retune_mobile_cfgs)
-               return -EINVAL;
-
-       wm8915->retune_mobile_cfg[block] = value;
-
-       wm8915_set_retune_mobile(codec, block);
-
-       return 0;
-}
-
-static int wm8915_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
-                                        struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       int block = wm8915_get_retune_mobile_block(kcontrol->id.name);
-
-       ucontrol->value.enumerated.item[0] = wm8915->retune_mobile_cfg[block];
-
-       return 0;
-}
-
-static const struct snd_kcontrol_new wm8915_snd_controls[] = {
-SOC_DOUBLE_R_TLV("Capture Volume", WM8915_LEFT_LINE_INPUT_VOLUME,
-                WM8915_RIGHT_LINE_INPUT_VOLUME, 0, 31, 0, inpga_tlv),
-SOC_DOUBLE_R("Capture ZC Switch", WM8915_LEFT_LINE_INPUT_VOLUME,
-            WM8915_RIGHT_LINE_INPUT_VOLUME, 5, 1, 0),
-
-SOC_DOUBLE_TLV("DAC1 Sidetone Volume", WM8915_DAC1_MIXER_VOLUMES,
-              0, 5, 24, 0, sidetone_tlv),
-SOC_DOUBLE_TLV("DAC2 Sidetone Volume", WM8915_DAC2_MIXER_VOLUMES,
-              0, 5, 24, 0, sidetone_tlv),
-SOC_SINGLE("Sidetone LPF Switch", WM8915_SIDETONE, 12, 1, 0),
-SOC_ENUM("Sidetone HPF Cut-off", sidetone_hpf),
-SOC_SINGLE("Sidetone HPF Switch", WM8915_SIDETONE, 6, 1, 0),
-
-SOC_DOUBLE_R_TLV("DSP1 Capture Volume", WM8915_DSP1_TX_LEFT_VOLUME,
-                WM8915_DSP1_TX_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
-SOC_DOUBLE_R_TLV("DSP2 Capture Volume", WM8915_DSP2_TX_LEFT_VOLUME,
-                WM8915_DSP2_TX_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
-
-SOC_SINGLE("DSP1 Capture Notch Filter Switch", WM8915_DSP1_TX_FILTERS,
-          13, 1, 0),
-SOC_DOUBLE("DSP1 Capture HPF Switch", WM8915_DSP1_TX_FILTERS, 12, 11, 1, 0),
-SOC_ENUM("DSP1 Capture HPF Mode", dsp1tx_hpf_mode),
-SOC_ENUM("DSP1 Capture HPF Cutoff", dsp1tx_hpf_cutoff),
-
-SOC_SINGLE("DSP2 Capture Notch Filter Switch", WM8915_DSP2_TX_FILTERS,
-          13, 1, 0),
-SOC_DOUBLE("DSP2 Capture HPF Switch", WM8915_DSP2_TX_FILTERS, 12, 11, 1, 0),
-SOC_ENUM("DSP2 Capture HPF Mode", dsp2tx_hpf_mode),
-SOC_ENUM("DSP2 Capture HPF Cutoff", dsp2tx_hpf_cutoff),
-
-SOC_DOUBLE_R_TLV("DSP1 Playback Volume", WM8915_DSP1_RX_LEFT_VOLUME,
-                WM8915_DSP1_RX_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
-SOC_SINGLE("DSP1 Playback Switch", WM8915_DSP1_RX_FILTERS_1, 9, 1, 1),
-
-SOC_DOUBLE_R_TLV("DSP2 Playback Volume", WM8915_DSP2_RX_LEFT_VOLUME,
-                WM8915_DSP2_RX_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
-SOC_SINGLE("DSP2 Playback Switch", WM8915_DSP2_RX_FILTERS_1, 9, 1, 1),
-
-SOC_DOUBLE_R_TLV("DAC1 Volume", WM8915_DAC1_LEFT_VOLUME,
-                WM8915_DAC1_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
-SOC_DOUBLE_R("DAC1 Switch", WM8915_DAC1_LEFT_VOLUME,
-            WM8915_DAC1_RIGHT_VOLUME, 9, 1, 1),
-
-SOC_DOUBLE_R_TLV("DAC2 Volume", WM8915_DAC2_LEFT_VOLUME,
-                WM8915_DAC2_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
-SOC_DOUBLE_R("DAC2 Switch", WM8915_DAC2_LEFT_VOLUME,
-            WM8915_DAC2_RIGHT_VOLUME, 9, 1, 1),
-
-SOC_SINGLE("Speaker High Performance Switch", WM8915_OVERSAMPLING, 3, 1, 0),
-SOC_SINGLE("DMIC High Performance Switch", WM8915_OVERSAMPLING, 2, 1, 0),
-SOC_SINGLE("ADC High Performance Switch", WM8915_OVERSAMPLING, 1, 1, 0),
-SOC_SINGLE("DAC High Performance Switch", WM8915_OVERSAMPLING, 0, 1, 0),
-
-SOC_SINGLE("DAC Soft Mute Switch", WM8915_DAC_SOFTMUTE, 1, 1, 0),
-SOC_SINGLE("DAC Slow Soft Mute Switch", WM8915_DAC_SOFTMUTE, 0, 1, 0),
-
-SOC_DOUBLE_TLV("Digital Output 1 Volume", WM8915_DAC1_HPOUT1_VOLUME, 0, 4,
-              8, 0, out_digital_tlv),
-SOC_DOUBLE_TLV("Digital Output 2 Volume", WM8915_DAC2_HPOUT2_VOLUME, 0, 4,
-              8, 0, out_digital_tlv),
-
-SOC_DOUBLE_R_TLV("Output 1 Volume", WM8915_OUTPUT1_LEFT_VOLUME,
-                WM8915_OUTPUT1_RIGHT_VOLUME, 0, 12, 0, out_tlv),
-SOC_DOUBLE_R("Output 1 ZC Switch",  WM8915_OUTPUT1_LEFT_VOLUME,
-            WM8915_OUTPUT1_RIGHT_VOLUME, 7, 1, 0),
-
-SOC_DOUBLE_R_TLV("Output 2 Volume", WM8915_OUTPUT2_LEFT_VOLUME,
-                WM8915_OUTPUT2_RIGHT_VOLUME, 0, 12, 0, out_tlv),
-SOC_DOUBLE_R("Output 2 ZC Switch",  WM8915_OUTPUT2_LEFT_VOLUME,
-            WM8915_OUTPUT2_RIGHT_VOLUME, 7, 1, 0),
-
-SOC_DOUBLE_TLV("Speaker Volume", WM8915_PDM_SPEAKER_VOLUME, 0, 4, 8, 0,
-              spk_tlv),
-SOC_DOUBLE_R("Speaker Switch", WM8915_LEFT_PDM_SPEAKER,
-            WM8915_RIGHT_PDM_SPEAKER, 3, 1, 1),
-SOC_DOUBLE_R("Speaker ZC Switch", WM8915_LEFT_PDM_SPEAKER,
-            WM8915_RIGHT_PDM_SPEAKER, 2, 1, 0),
-
-SOC_SINGLE("DSP1 EQ Switch", WM8915_DSP1_RX_EQ_GAINS_1, 0, 1, 0),
-SOC_SINGLE("DSP2 EQ Switch", WM8915_DSP2_RX_EQ_GAINS_1, 0, 1, 0),
-};
-
-static const struct snd_kcontrol_new wm8915_eq_controls[] = {
-SOC_SINGLE_TLV("DSP1 EQ B1 Volume", WM8915_DSP1_RX_EQ_GAINS_1, 11, 31, 0,
-              eq_tlv),
-SOC_SINGLE_TLV("DSP1 EQ B2 Volume", WM8915_DSP1_RX_EQ_GAINS_1, 6, 31, 0,
-              eq_tlv),
-SOC_SINGLE_TLV("DSP1 EQ B3 Volume", WM8915_DSP1_RX_EQ_GAINS_1, 1, 31, 0,
-              eq_tlv),
-SOC_SINGLE_TLV("DSP1 EQ B4 Volume", WM8915_DSP1_RX_EQ_GAINS_2, 11, 31, 0,
-              eq_tlv),
-SOC_SINGLE_TLV("DSP1 EQ B5 Volume", WM8915_DSP1_RX_EQ_GAINS_2, 6, 31, 0,
-              eq_tlv),
-
-SOC_SINGLE_TLV("DSP2 EQ B1 Volume", WM8915_DSP2_RX_EQ_GAINS_1, 11, 31, 0,
-              eq_tlv),
-SOC_SINGLE_TLV("DSP2 EQ B2 Volume", WM8915_DSP2_RX_EQ_GAINS_1, 6, 31, 0,
-              eq_tlv),
-SOC_SINGLE_TLV("DSP2 EQ B3 Volume", WM8915_DSP2_RX_EQ_GAINS_1, 1, 31, 0,
-              eq_tlv),
-SOC_SINGLE_TLV("DSP2 EQ B4 Volume", WM8915_DSP2_RX_EQ_GAINS_2, 11, 31, 0,
-              eq_tlv),
-SOC_SINGLE_TLV("DSP2 EQ B5 Volume", WM8915_DSP2_RX_EQ_GAINS_2, 6, 31, 0,
-              eq_tlv),
-};
-
-static int cp_event(struct snd_soc_dapm_widget *w,
-                   struct snd_kcontrol *kcontrol, int event)
-{
-       switch (event) {
-       case SND_SOC_DAPM_POST_PMU:
-               msleep(5);
-               break;
-       default:
-               BUG();
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int rmv_short_event(struct snd_soc_dapm_widget *w,
-                          struct snd_kcontrol *kcontrol, int event)
-{
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(w->codec);
-
-       /* Record which outputs we enabled */
-       switch (event) {
-       case SND_SOC_DAPM_PRE_PMD:
-               wm8915->hpout_pending &= ~w->shift;
-               break;
-       case SND_SOC_DAPM_PRE_PMU:
-               wm8915->hpout_pending |= w->shift;
-               break;
-       default:
-               BUG();
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static void wait_for_dc_servo(struct snd_soc_codec *codec, u16 mask)
-{
-       struct i2c_client *i2c = to_i2c_client(codec->dev);
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       int i, ret;
-       unsigned long timeout = 200;
-
-       snd_soc_write(codec, WM8915_DC_SERVO_2, mask);
-
-       /* Use the interrupt if possible */
-       do {
-               if (i2c->irq) {
-                       timeout = wait_for_completion_timeout(&wm8915->dcs_done,
-                                                             msecs_to_jiffies(200));
-                       if (timeout == 0)
-                               dev_err(codec->dev, "DC servo timed out\n");
-
-               } else {
-                       msleep(1);
-                       if (--i) {
-                               timeout = 0;
-                               break;
-                       }
-               }
-
-               ret = snd_soc_read(codec, WM8915_DC_SERVO_2);
-               dev_dbg(codec->dev, "DC servo state: %x\n", ret);
-       } while (ret & mask);
-
-       if (timeout == 0)
-               dev_err(codec->dev, "DC servo timed out for %x\n", mask);
-       else
-               dev_dbg(codec->dev, "DC servo complete for %x\n", mask);
-}
-
-static void wm8915_seq_notifier(struct snd_soc_dapm_context *dapm,
-                               enum snd_soc_dapm_type event, int subseq)
-{
-       struct snd_soc_codec *codec = container_of(dapm,
-                                                  struct snd_soc_codec, dapm);
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       u16 val, mask;
-
-       /* Complete any pending DC servo starts */
-       if (wm8915->dcs_pending) {
-               dev_dbg(codec->dev, "Starting DC servo for %x\n",
-                       wm8915->dcs_pending);
-
-               /* Trigger a startup sequence */
-               wait_for_dc_servo(codec, wm8915->dcs_pending
-                                        << WM8915_DCS_TRIG_STARTUP_0_SHIFT);
-
-               wm8915->dcs_pending = 0;
-       }
-
-       if (wm8915->hpout_pending != wm8915->hpout_ena) {
-               dev_dbg(codec->dev, "Applying RMV_SHORTs %x->%x\n",
-                       wm8915->hpout_ena, wm8915->hpout_pending);
-
-               val = 0;
-               mask = 0;
-               if (wm8915->hpout_pending & HPOUT1L) {
-                       val |= WM8915_HPOUT1L_RMV_SHORT;
-                       mask |= WM8915_HPOUT1L_RMV_SHORT;
-               } else {
-                       mask |= WM8915_HPOUT1L_RMV_SHORT |
-                               WM8915_HPOUT1L_OUTP |
-                               WM8915_HPOUT1L_DLY;
-               }
-
-               if (wm8915->hpout_pending & HPOUT1R) {
-                       val |= WM8915_HPOUT1R_RMV_SHORT;
-                       mask |= WM8915_HPOUT1R_RMV_SHORT;
-               } else {
-                       mask |= WM8915_HPOUT1R_RMV_SHORT |
-                               WM8915_HPOUT1R_OUTP |
-                               WM8915_HPOUT1R_DLY;
-               }
-
-               snd_soc_update_bits(codec, WM8915_ANALOGUE_HP_1, mask, val);
-
-               val = 0;
-               mask = 0;
-               if (wm8915->hpout_pending & HPOUT2L) {
-                       val |= WM8915_HPOUT2L_RMV_SHORT;
-                       mask |= WM8915_HPOUT2L_RMV_SHORT;
-               } else {
-                       mask |= WM8915_HPOUT2L_RMV_SHORT |
-                               WM8915_HPOUT2L_OUTP |
-                               WM8915_HPOUT2L_DLY;
-               }
-
-               if (wm8915->hpout_pending & HPOUT2R) {
-                       val |= WM8915_HPOUT2R_RMV_SHORT;
-                       mask |= WM8915_HPOUT2R_RMV_SHORT;
-               } else {
-                       mask |= WM8915_HPOUT2R_RMV_SHORT |
-                               WM8915_HPOUT2R_OUTP |
-                               WM8915_HPOUT2R_DLY;
-               }
-
-               snd_soc_update_bits(codec, WM8915_ANALOGUE_HP_2, mask, val);
-
-               wm8915->hpout_ena = wm8915->hpout_pending;
-       }
-}
-
-static int dcs_start(struct snd_soc_dapm_widget *w,
-                    struct snd_kcontrol *kcontrol, int event)
-{
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(w->codec);
-
-       switch (event) {
-       case SND_SOC_DAPM_POST_PMU:
-               wm8915->dcs_pending |= 1 << w->shift;
-               break;
-       default:
-               BUG();
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static const char *sidetone_text[] = {
-       "IN1", "IN2",
-};
-
-static const struct soc_enum left_sidetone_enum =
-       SOC_ENUM_SINGLE(WM8915_SIDETONE, 0, 2, sidetone_text);
-
-static const struct snd_kcontrol_new left_sidetone =
-       SOC_DAPM_ENUM("Left Sidetone", left_sidetone_enum);
-
-static const struct soc_enum right_sidetone_enum =
-       SOC_ENUM_SINGLE(WM8915_SIDETONE, 1, 2, sidetone_text);
-
-static const struct snd_kcontrol_new right_sidetone =
-       SOC_DAPM_ENUM("Right Sidetone", right_sidetone_enum);
-
-static const char *spk_text[] = {
-       "DAC1L", "DAC1R", "DAC2L", "DAC2R"
-};
-
-static const struct soc_enum spkl_enum =
-       SOC_ENUM_SINGLE(WM8915_LEFT_PDM_SPEAKER, 0, 4, spk_text);
-
-static const struct snd_kcontrol_new spkl_mux =
-       SOC_DAPM_ENUM("SPKL", spkl_enum);
-
-static const struct soc_enum spkr_enum =
-       SOC_ENUM_SINGLE(WM8915_RIGHT_PDM_SPEAKER, 0, 4, spk_text);
-
-static const struct snd_kcontrol_new spkr_mux =
-       SOC_DAPM_ENUM("SPKR", spkr_enum);
-
-static const char *dsp1rx_text[] = {
-       "AIF1", "AIF2"
-};
-
-static const struct soc_enum dsp1rx_enum =
-       SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_8, 0, 2, dsp1rx_text);
-
-static const struct snd_kcontrol_new dsp1rx =
-       SOC_DAPM_ENUM("DSP1RX", dsp1rx_enum);
-
-static const char *dsp2rx_text[] = {
-        "AIF2", "AIF1"
-};
-
-static const struct soc_enum dsp2rx_enum =
-       SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_8, 4, 2, dsp2rx_text);
-
-static const struct snd_kcontrol_new dsp2rx =
-       SOC_DAPM_ENUM("DSP2RX", dsp2rx_enum);
-
-static const char *aif2tx_text[] = {
-       "DSP2", "DSP1", "AIF1"
-};
-
-static const struct soc_enum aif2tx_enum =
-       SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_8, 6, 3, aif2tx_text);
-
-static const struct snd_kcontrol_new aif2tx =
-       SOC_DAPM_ENUM("AIF2TX", aif2tx_enum);
-
-static const char *inmux_text[] = {
-       "ADC", "DMIC1", "DMIC2"
-};
-
-static const struct soc_enum in1_enum =
-       SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_7, 0, 3, inmux_text);
-
-static const struct snd_kcontrol_new in1_mux =
-       SOC_DAPM_ENUM("IN1 Mux", in1_enum);
-
-static const struct soc_enum in2_enum =
-       SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_7, 4, 3, inmux_text);
-
-static const struct snd_kcontrol_new in2_mux =
-       SOC_DAPM_ENUM("IN2 Mux", in2_enum);
-
-static const struct snd_kcontrol_new dac2r_mix[] = {
-SOC_DAPM_SINGLE("Right Sidetone Switch", WM8915_DAC2_RIGHT_MIXER_ROUTING,
-               5, 1, 0),
-SOC_DAPM_SINGLE("Left Sidetone Switch", WM8915_DAC2_RIGHT_MIXER_ROUTING,
-               4, 1, 0),
-SOC_DAPM_SINGLE("DSP2 Switch", WM8915_DAC2_RIGHT_MIXER_ROUTING, 1, 1, 0),
-SOC_DAPM_SINGLE("DSP1 Switch", WM8915_DAC2_RIGHT_MIXER_ROUTING, 0, 1, 0),
-};
-
-static const struct snd_kcontrol_new dac2l_mix[] = {
-SOC_DAPM_SINGLE("Right Sidetone Switch", WM8915_DAC2_LEFT_MIXER_ROUTING,
-               5, 1, 0),
-SOC_DAPM_SINGLE("Left Sidetone Switch", WM8915_DAC2_LEFT_MIXER_ROUTING,
-               4, 1, 0),
-SOC_DAPM_SINGLE("DSP2 Switch", WM8915_DAC2_LEFT_MIXER_ROUTING, 1, 1, 0),
-SOC_DAPM_SINGLE("DSP1 Switch", WM8915_DAC2_LEFT_MIXER_ROUTING, 0, 1, 0),
-};
-
-static const struct snd_kcontrol_new dac1r_mix[] = {
-SOC_DAPM_SINGLE("Right Sidetone Switch", WM8915_DAC1_RIGHT_MIXER_ROUTING,
-               5, 1, 0),
-SOC_DAPM_SINGLE("Left Sidetone Switch", WM8915_DAC1_RIGHT_MIXER_ROUTING,
-               4, 1, 0),
-SOC_DAPM_SINGLE("DSP2 Switch", WM8915_DAC1_RIGHT_MIXER_ROUTING, 1, 1, 0),
-SOC_DAPM_SINGLE("DSP1 Switch", WM8915_DAC1_RIGHT_MIXER_ROUTING, 0, 1, 0),
-};
-
-static const struct snd_kcontrol_new dac1l_mix[] = {
-SOC_DAPM_SINGLE("Right Sidetone Switch", WM8915_DAC1_LEFT_MIXER_ROUTING,
-               5, 1, 0),
-SOC_DAPM_SINGLE("Left Sidetone Switch", WM8915_DAC1_LEFT_MIXER_ROUTING,
-               4, 1, 0),
-SOC_DAPM_SINGLE("DSP2 Switch", WM8915_DAC1_LEFT_MIXER_ROUTING, 1, 1, 0),
-SOC_DAPM_SINGLE("DSP1 Switch", WM8915_DAC1_LEFT_MIXER_ROUTING, 0, 1, 0),
-};
-
-static const struct snd_kcontrol_new dsp1txl[] = {
-SOC_DAPM_SINGLE("IN1 Switch", WM8915_DSP1_TX_LEFT_MIXER_ROUTING,
-               1, 1, 0),
-SOC_DAPM_SINGLE("DAC Switch", WM8915_DSP1_TX_LEFT_MIXER_ROUTING,
-               0, 1, 0),
-};
-
-static const struct snd_kcontrol_new dsp1txr[] = {
-SOC_DAPM_SINGLE("IN1 Switch", WM8915_DSP1_TX_RIGHT_MIXER_ROUTING,
-               1, 1, 0),
-SOC_DAPM_SINGLE("DAC Switch", WM8915_DSP1_TX_RIGHT_MIXER_ROUTING,
-               0, 1, 0),
-};
-
-static const struct snd_kcontrol_new dsp2txl[] = {
-SOC_DAPM_SINGLE("IN1 Switch", WM8915_DSP2_TX_LEFT_MIXER_ROUTING,
-               1, 1, 0),
-SOC_DAPM_SINGLE("DAC Switch", WM8915_DSP2_TX_LEFT_MIXER_ROUTING,
-               0, 1, 0),
-};
-
-static const struct snd_kcontrol_new dsp2txr[] = {
-SOC_DAPM_SINGLE("IN1 Switch", WM8915_DSP2_TX_RIGHT_MIXER_ROUTING,
-               1, 1, 0),
-SOC_DAPM_SINGLE("DAC Switch", WM8915_DSP2_TX_RIGHT_MIXER_ROUTING,
-               0, 1, 0),
-};
-
-
-static const struct snd_soc_dapm_widget wm8915_dapm_widgets[] = {
-SND_SOC_DAPM_INPUT("IN1LN"),
-SND_SOC_DAPM_INPUT("IN1LP"),
-SND_SOC_DAPM_INPUT("IN1RN"),
-SND_SOC_DAPM_INPUT("IN1RP"),
-
-SND_SOC_DAPM_INPUT("IN2LN"),
-SND_SOC_DAPM_INPUT("IN2LP"),
-SND_SOC_DAPM_INPUT("IN2RN"),
-SND_SOC_DAPM_INPUT("IN2RP"),
-
-SND_SOC_DAPM_INPUT("DMIC1DAT"),
-SND_SOC_DAPM_INPUT("DMIC2DAT"),
-
-SND_SOC_DAPM_SUPPLY_S("SYSCLK", 1, WM8915_AIF_CLOCKING_1, 0, 0, NULL, 0),
-SND_SOC_DAPM_SUPPLY_S("SYSDSPCLK", 2, WM8915_CLOCKING_1, 1, 0, NULL, 0),
-SND_SOC_DAPM_SUPPLY_S("AIFCLK", 2, WM8915_CLOCKING_1, 2, 0, NULL, 0),
-SND_SOC_DAPM_SUPPLY_S("Charge Pump", 2, WM8915_CHARGE_PUMP_1, 15, 0, cp_event,
-                     SND_SOC_DAPM_POST_PMU),
-
-SND_SOC_DAPM_SUPPLY("LDO2", WM8915_POWER_MANAGEMENT_2, 1, 0, NULL, 0),
-SND_SOC_DAPM_MICBIAS("MICB2", WM8915_POWER_MANAGEMENT_1, 9, 0),
-SND_SOC_DAPM_MICBIAS("MICB1", WM8915_POWER_MANAGEMENT_1, 8, 0),
-
-SND_SOC_DAPM_PGA("IN1L PGA", WM8915_POWER_MANAGEMENT_2, 5, 0, NULL, 0),
-SND_SOC_DAPM_PGA("IN1R PGA", WM8915_POWER_MANAGEMENT_2, 4, 0, NULL, 0),
-
-SND_SOC_DAPM_MUX("IN1L Mux", SND_SOC_NOPM, 0, 0, &in1_mux),
-SND_SOC_DAPM_MUX("IN1R Mux", SND_SOC_NOPM, 0, 0, &in1_mux),
-SND_SOC_DAPM_MUX("IN2L Mux", SND_SOC_NOPM, 0, 0, &in2_mux),
-SND_SOC_DAPM_MUX("IN2R Mux", SND_SOC_NOPM, 0, 0, &in2_mux),
-
-SND_SOC_DAPM_PGA("IN1L", WM8915_POWER_MANAGEMENT_7, 2, 0, NULL, 0),
-SND_SOC_DAPM_PGA("IN1R", WM8915_POWER_MANAGEMENT_7, 3, 0, NULL, 0),
-SND_SOC_DAPM_PGA("IN2L", WM8915_POWER_MANAGEMENT_7, 6, 0, NULL, 0),
-SND_SOC_DAPM_PGA("IN2R", WM8915_POWER_MANAGEMENT_7, 7, 0, NULL, 0),
-
-SND_SOC_DAPM_SUPPLY("DMIC2", WM8915_POWER_MANAGEMENT_7, 9, 0, NULL, 0),
-SND_SOC_DAPM_SUPPLY("DMIC1", WM8915_POWER_MANAGEMENT_7, 8, 0, NULL, 0),
-
-SND_SOC_DAPM_ADC("DMIC2L", NULL, WM8915_POWER_MANAGEMENT_3, 5, 0),
-SND_SOC_DAPM_ADC("DMIC2R", NULL, WM8915_POWER_MANAGEMENT_3, 4, 0),
-SND_SOC_DAPM_ADC("DMIC1L", NULL, WM8915_POWER_MANAGEMENT_3, 3, 0),
-SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8915_POWER_MANAGEMENT_3, 2, 0),
-
-SND_SOC_DAPM_ADC("ADCL", NULL, WM8915_POWER_MANAGEMENT_3, 1, 0),
-SND_SOC_DAPM_ADC("ADCR", NULL, WM8915_POWER_MANAGEMENT_3, 0, 0),
-
-SND_SOC_DAPM_MUX("Left Sidetone", SND_SOC_NOPM, 0, 0, &left_sidetone),
-SND_SOC_DAPM_MUX("Right Sidetone", SND_SOC_NOPM, 0, 0, &right_sidetone),
-
-SND_SOC_DAPM_AIF_IN("DSP2RXL", NULL, 0, WM8915_POWER_MANAGEMENT_3, 11, 0),
-SND_SOC_DAPM_AIF_IN("DSP2RXR", NULL, 1, WM8915_POWER_MANAGEMENT_3, 10, 0),
-SND_SOC_DAPM_AIF_IN("DSP1RXL", NULL, 0, WM8915_POWER_MANAGEMENT_3, 9, 0),
-SND_SOC_DAPM_AIF_IN("DSP1RXR", NULL, 1, WM8915_POWER_MANAGEMENT_3, 8, 0),
-
-SND_SOC_DAPM_MIXER("DSP2TXL", WM8915_POWER_MANAGEMENT_5, 11, 0,
-                  dsp2txl, ARRAY_SIZE(dsp2txl)),
-SND_SOC_DAPM_MIXER("DSP2TXR", WM8915_POWER_MANAGEMENT_5, 10, 0,
-                  dsp2txr, ARRAY_SIZE(dsp2txr)),
-SND_SOC_DAPM_MIXER("DSP1TXL", WM8915_POWER_MANAGEMENT_5, 9, 0,
-                  dsp1txl, ARRAY_SIZE(dsp1txl)),
-SND_SOC_DAPM_MIXER("DSP1TXR", WM8915_POWER_MANAGEMENT_5, 8, 0,
-                  dsp1txr, ARRAY_SIZE(dsp1txr)),
-
-SND_SOC_DAPM_MIXER("DAC2L Mixer", SND_SOC_NOPM, 0, 0,
-                  dac2l_mix, ARRAY_SIZE(dac2l_mix)),
-SND_SOC_DAPM_MIXER("DAC2R Mixer", SND_SOC_NOPM, 0, 0,
-                  dac2r_mix, ARRAY_SIZE(dac2r_mix)),
-SND_SOC_DAPM_MIXER("DAC1L Mixer", SND_SOC_NOPM, 0, 0,
-                  dac1l_mix, ARRAY_SIZE(dac1l_mix)),
-SND_SOC_DAPM_MIXER("DAC1R Mixer", SND_SOC_NOPM, 0, 0,
-                  dac1r_mix, ARRAY_SIZE(dac1r_mix)),
-
-SND_SOC_DAPM_DAC("DAC2L", NULL, WM8915_POWER_MANAGEMENT_5, 3, 0),
-SND_SOC_DAPM_DAC("DAC2R", NULL, WM8915_POWER_MANAGEMENT_5, 2, 0),
-SND_SOC_DAPM_DAC("DAC1L", NULL, WM8915_POWER_MANAGEMENT_5, 1, 0),
-SND_SOC_DAPM_DAC("DAC1R", NULL, WM8915_POWER_MANAGEMENT_5, 0, 0),
-
-SND_SOC_DAPM_AIF_IN("AIF2RX1", "AIF2 Playback", 1,
-                   WM8915_POWER_MANAGEMENT_4, 9, 0),
-SND_SOC_DAPM_AIF_IN("AIF2RX0", "AIF2 Playback", 2,
-                   WM8915_POWER_MANAGEMENT_4, 8, 0),
-
-SND_SOC_DAPM_AIF_IN("AIF2TX1", "AIF2 Capture", 1,
-                   WM8915_POWER_MANAGEMENT_6, 9, 0),
-SND_SOC_DAPM_AIF_IN("AIF2TX0", "AIF2 Capture", 2,
-                   WM8915_POWER_MANAGEMENT_6, 8, 0),
-
-SND_SOC_DAPM_AIF_IN("AIF1RX5", "AIF1 Playback", 5,
-                   WM8915_POWER_MANAGEMENT_4, 5, 0),
-SND_SOC_DAPM_AIF_IN("AIF1RX4", "AIF1 Playback", 4,
-                   WM8915_POWER_MANAGEMENT_4, 4, 0),
-SND_SOC_DAPM_AIF_IN("AIF1RX3", "AIF1 Playback", 3,
-                   WM8915_POWER_MANAGEMENT_4, 3, 0),
-SND_SOC_DAPM_AIF_IN("AIF1RX2", "AIF1 Playback", 2,
-                   WM8915_POWER_MANAGEMENT_4, 2, 0),
-SND_SOC_DAPM_AIF_IN("AIF1RX1", "AIF1 Playback", 1,
-                   WM8915_POWER_MANAGEMENT_4, 1, 0),
-SND_SOC_DAPM_AIF_IN("AIF1RX0", "AIF1 Playback", 0,
-                   WM8915_POWER_MANAGEMENT_4, 0, 0),
-
-SND_SOC_DAPM_AIF_OUT("AIF1TX5", "AIF1 Capture", 5,
-                    WM8915_POWER_MANAGEMENT_6, 5, 0),
-SND_SOC_DAPM_AIF_OUT("AIF1TX4", "AIF1 Capture", 4,
-                    WM8915_POWER_MANAGEMENT_6, 4, 0),
-SND_SOC_DAPM_AIF_OUT("AIF1TX3", "AIF1 Capture", 3,
-                    WM8915_POWER_MANAGEMENT_6, 3, 0),
-SND_SOC_DAPM_AIF_OUT("AIF1TX2", "AIF1 Capture", 2,
-                    WM8915_POWER_MANAGEMENT_6, 2, 0),
-SND_SOC_DAPM_AIF_OUT("AIF1TX1", "AIF1 Capture", 1,
-                    WM8915_POWER_MANAGEMENT_6, 1, 0),
-SND_SOC_DAPM_AIF_OUT("AIF1TX0", "AIF1 Capture", 0,
-                    WM8915_POWER_MANAGEMENT_6, 0, 0),
-
-/* We route as stereo pairs so define some dummy widgets to squash
- * things down for now.  RXA = 0,1, RXB = 2,3 and so on */
-SND_SOC_DAPM_PGA("AIF1RXA", SND_SOC_NOPM, 0, 0, NULL, 0),
-SND_SOC_DAPM_PGA("AIF1RXB", SND_SOC_NOPM, 0, 0, NULL, 0),
-SND_SOC_DAPM_PGA("AIF1RXC", SND_SOC_NOPM, 0, 0, NULL, 0),
-SND_SOC_DAPM_PGA("AIF2RX", SND_SOC_NOPM, 0, 0, NULL, 0),
-SND_SOC_DAPM_PGA("DSP2TX", SND_SOC_NOPM, 0, 0, NULL, 0),
-
-SND_SOC_DAPM_MUX("DSP1RX", SND_SOC_NOPM, 0, 0, &dsp1rx),
-SND_SOC_DAPM_MUX("DSP2RX", SND_SOC_NOPM, 0, 0, &dsp2rx),
-SND_SOC_DAPM_MUX("AIF2TX", SND_SOC_NOPM, 0, 0, &aif2tx),
-
-SND_SOC_DAPM_MUX("SPKL", SND_SOC_NOPM, 0, 0, &spkl_mux),
-SND_SOC_DAPM_MUX("SPKR", SND_SOC_NOPM, 0, 0, &spkr_mux),
-SND_SOC_DAPM_PGA("SPKL PGA", WM8915_LEFT_PDM_SPEAKER, 4, 0, NULL, 0),
-SND_SOC_DAPM_PGA("SPKR PGA", WM8915_RIGHT_PDM_SPEAKER, 4, 0, NULL, 0),
-
-SND_SOC_DAPM_PGA_S("HPOUT2L PGA", 0, WM8915_POWER_MANAGEMENT_1, 7, 0, NULL, 0),
-SND_SOC_DAPM_PGA_S("HPOUT2L_DLY", 1, WM8915_ANALOGUE_HP_2, 5, 0, NULL, 0),
-SND_SOC_DAPM_PGA_S("HPOUT2L_DCS", 2, WM8915_DC_SERVO_1, 2, 0, dcs_start,
-                  SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA_S("HPOUT2L_OUTP", 3, WM8915_ANALOGUE_HP_2, 6, 0, NULL, 0),
-SND_SOC_DAPM_PGA_S("HPOUT2L_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT2L, 0,
-                  rmv_short_event,
-                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
-
-SND_SOC_DAPM_PGA_S("HPOUT2R PGA", 0, WM8915_POWER_MANAGEMENT_1, 6, 0,NULL, 0),
-SND_SOC_DAPM_PGA_S("HPOUT2R_DLY", 1, WM8915_ANALOGUE_HP_2, 1, 0, NULL, 0),
-SND_SOC_DAPM_PGA_S("HPOUT2R_DCS", 2, WM8915_DC_SERVO_1, 3, 0, dcs_start,
-                  SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA_S("HPOUT2R_OUTP", 3, WM8915_ANALOGUE_HP_2, 2, 0, NULL, 0),
-SND_SOC_DAPM_PGA_S("HPOUT2R_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT2R, 0,
-                  rmv_short_event,
-                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
-
-SND_SOC_DAPM_PGA_S("HPOUT1L PGA", 0, WM8915_POWER_MANAGEMENT_1, 5, 0, NULL, 0),
-SND_SOC_DAPM_PGA_S("HPOUT1L_DLY", 1, WM8915_ANALOGUE_HP_1, 5, 0, NULL, 0),
-SND_SOC_DAPM_PGA_S("HPOUT1L_DCS", 2, WM8915_DC_SERVO_1, 0, 0, dcs_start,
-                  SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA_S("HPOUT1L_OUTP", 3, WM8915_ANALOGUE_HP_1, 6, 0, NULL, 0),
-SND_SOC_DAPM_PGA_S("HPOUT1L_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT1L, 0,
-                  rmv_short_event,
-                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
-
-SND_SOC_DAPM_PGA_S("HPOUT1R PGA", 0, WM8915_POWER_MANAGEMENT_1, 4, 0, NULL, 0),
-SND_SOC_DAPM_PGA_S("HPOUT1R_DLY", 1, WM8915_ANALOGUE_HP_1, 1, 0, NULL, 0),
-SND_SOC_DAPM_PGA_S("HPOUT1R_DCS", 2, WM8915_DC_SERVO_1, 1, 0, dcs_start,
-                  SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA_S("HPOUT1R_OUTP", 3, WM8915_ANALOGUE_HP_1, 2, 0, NULL, 0),
-SND_SOC_DAPM_PGA_S("HPOUT1R_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT1R, 0,
-                  rmv_short_event,
-                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
-
-SND_SOC_DAPM_OUTPUT("HPOUT1L"),
-SND_SOC_DAPM_OUTPUT("HPOUT1R"),
-SND_SOC_DAPM_OUTPUT("HPOUT2L"),
-SND_SOC_DAPM_OUTPUT("HPOUT2R"),
-SND_SOC_DAPM_OUTPUT("SPKDAT"),
-};
-
-static const struct snd_soc_dapm_route wm8915_dapm_routes[] = {
-       { "AIFCLK", NULL, "SYSCLK" },
-       { "SYSDSPCLK", NULL, "SYSCLK" },
-       { "Charge Pump", NULL, "SYSCLK" },
-
-       { "MICB1", NULL, "LDO2" },
-       { "MICB2", NULL, "LDO2" },
-
-       { "IN1L PGA", NULL, "IN2LN" },
-       { "IN1L PGA", NULL, "IN2LP" },
-       { "IN1L PGA", NULL, "IN1LN" },
-       { "IN1L PGA", NULL, "IN1LP" },
-
-       { "IN1R PGA", NULL, "IN2RN" },
-       { "IN1R PGA", NULL, "IN2RP" },
-       { "IN1R PGA", NULL, "IN1RN" },
-       { "IN1R PGA", NULL, "IN1RP" },
-
-       { "ADCL", NULL, "IN1L PGA" },
-
-       { "ADCR", NULL, "IN1R PGA" },
-
-       { "DMIC1L", NULL, "DMIC1DAT" },
-       { "DMIC1R", NULL, "DMIC1DAT" },
-       { "DMIC2L", NULL, "DMIC2DAT" },
-       { "DMIC2R", NULL, "DMIC2DAT" },
-
-       { "DMIC2L", NULL, "DMIC2" },
-       { "DMIC2R", NULL, "DMIC2" },
-       { "DMIC1L", NULL, "DMIC1" },
-       { "DMIC1R", NULL, "DMIC1" },
-
-       { "IN1L Mux", "ADC", "ADCL" },
-       { "IN1L Mux", "DMIC1", "DMIC1L" },
-       { "IN1L Mux", "DMIC2", "DMIC2L" },
-
-       { "IN1R Mux", "ADC", "ADCR" },
-       { "IN1R Mux", "DMIC1", "DMIC1R" },
-       { "IN1R Mux", "DMIC2", "DMIC2R" },
-
-       { "IN2L Mux", "ADC", "ADCL" },
-       { "IN2L Mux", "DMIC1", "DMIC1L" },
-       { "IN2L Mux", "DMIC2", "DMIC2L" },
-
-       { "IN2R Mux", "ADC", "ADCR" },
-       { "IN2R Mux", "DMIC1", "DMIC1R" },
-       { "IN2R Mux", "DMIC2", "DMIC2R" },
-
-       { "Left Sidetone", "IN1", "IN1L Mux" },
-       { "Left Sidetone", "IN2", "IN2L Mux" },
-
-       { "Right Sidetone", "IN1", "IN1R Mux" },
-       { "Right Sidetone", "IN2", "IN2R Mux" },
-
-       { "DSP1TXL", "IN1 Switch", "IN1L Mux" },
-       { "DSP1TXR", "IN1 Switch", "IN1R Mux" },
-
-       { "DSP2TXL", "IN1 Switch", "IN2L Mux" },
-       { "DSP2TXR", "IN1 Switch", "IN2R Mux" },
-
-       { "AIF1TX0", NULL, "DSP1TXL" },
-       { "AIF1TX1", NULL, "DSP1TXR" },
-       { "AIF1TX2", NULL, "DSP2TXL" },
-       { "AIF1TX3", NULL, "DSP2TXR" },
-       { "AIF1TX4", NULL, "AIF2RX0" },
-       { "AIF1TX5", NULL, "AIF2RX1" },
-
-       { "AIF1RX0", NULL, "AIFCLK" },
-       { "AIF1RX1", NULL, "AIFCLK" },
-       { "AIF1RX2", NULL, "AIFCLK" },
-       { "AIF1RX3", NULL, "AIFCLK" },
-       { "AIF1RX4", NULL, "AIFCLK" },
-       { "AIF1RX5", NULL, "AIFCLK" },
-
-       { "AIF2RX0", NULL, "AIFCLK" },
-       { "AIF2RX1", NULL, "AIFCLK" },
-
-       { "DSP1RXL", NULL, "SYSDSPCLK" },
-       { "DSP1RXR", NULL, "SYSDSPCLK" },
-       { "DSP2RXL", NULL, "SYSDSPCLK" },
-       { "DSP2RXR", NULL, "SYSDSPCLK" },
-       { "DSP1TXL", NULL, "SYSDSPCLK" },
-       { "DSP1TXR", NULL, "SYSDSPCLK" },
-       { "DSP2TXL", NULL, "SYSDSPCLK" },
-       { "DSP2TXR", NULL, "SYSDSPCLK" },
-
-       { "AIF1RXA", NULL, "AIF1RX0" },
-       { "AIF1RXA", NULL, "AIF1RX1" },
-       { "AIF1RXB", NULL, "AIF1RX2" },
-       { "AIF1RXB", NULL, "AIF1RX3" },
-       { "AIF1RXC", NULL, "AIF1RX4" },
-       { "AIF1RXC", NULL, "AIF1RX5" },
-
-       { "AIF2RX", NULL, "AIF2RX0" },
-       { "AIF2RX", NULL, "AIF2RX1" },
-
-       { "AIF2TX", "DSP2", "DSP2TX" },
-       { "AIF2TX", "DSP1", "DSP1RX" },
-       { "AIF2TX", "AIF1", "AIF1RXC" },
-
-       { "DSP1RXL", NULL, "DSP1RX" },
-       { "DSP1RXR", NULL, "DSP1RX" },
-       { "DSP2RXL", NULL, "DSP2RX" },
-       { "DSP2RXR", NULL, "DSP2RX" },
-
-       { "DSP2TX", NULL, "DSP2TXL" },
-       { "DSP2TX", NULL, "DSP2TXR" },
-
-       { "DSP1RX", "AIF1", "AIF1RXA" },
-       { "DSP1RX", "AIF2", "AIF2RX" },
-
-       { "DSP2RX", "AIF1", "AIF1RXB" },
-       { "DSP2RX", "AIF2", "AIF2RX" },
-
-       { "DAC2L Mixer", "DSP2 Switch", "DSP2RXL" },
-       { "DAC2L Mixer", "DSP1 Switch", "DSP1RXL" },
-       { "DAC2L Mixer", "Right Sidetone Switch", "Right Sidetone" },
-       { "DAC2L Mixer", "Left Sidetone Switch", "Left Sidetone" },
-
-       { "DAC2R Mixer", "DSP2 Switch", "DSP2RXR" },
-       { "DAC2R Mixer", "DSP1 Switch", "DSP1RXR" },
-       { "DAC2R Mixer", "Right Sidetone Switch", "Right Sidetone" },
-       { "DAC2R Mixer", "Left Sidetone Switch", "Left Sidetone" },
-
-       { "DAC1L Mixer", "DSP2 Switch", "DSP2RXL" },
-       { "DAC1L Mixer", "DSP1 Switch", "DSP1RXL" },
-       { "DAC1L Mixer", "Right Sidetone Switch", "Right Sidetone" },
-       { "DAC1L Mixer", "Left Sidetone Switch", "Left Sidetone" },
-
-       { "DAC1R Mixer", "DSP2 Switch", "DSP2RXR" },
-       { "DAC1R Mixer", "DSP1 Switch", "DSP1RXR" },
-       { "DAC1R Mixer", "Right Sidetone Switch", "Right Sidetone" },
-       { "DAC1R Mixer", "Left Sidetone Switch", "Left Sidetone" },
-
-       { "DAC1L", NULL, "DAC1L Mixer" },
-       { "DAC1R", NULL, "DAC1R Mixer" },
-       { "DAC2L", NULL, "DAC2L Mixer" },
-       { "DAC2R", NULL, "DAC2R Mixer" },
-
-       { "HPOUT2L PGA", NULL, "Charge Pump" },
-       { "HPOUT2L PGA", NULL, "DAC2L" },
-       { "HPOUT2L_DLY", NULL, "HPOUT2L PGA" },
-       { "HPOUT2L_DCS", NULL, "HPOUT2L_DLY" },
-       { "HPOUT2L_OUTP", NULL, "HPOUT2L_DCS" },
-       { "HPOUT2L_RMV_SHORT", NULL, "HPOUT2L_OUTP" },
-
-       { "HPOUT2R PGA", NULL, "Charge Pump" },
-       { "HPOUT2R PGA", NULL, "DAC2R" },
-       { "HPOUT2R_DLY", NULL, "HPOUT2R PGA" },
-       { "HPOUT2R_DCS", NULL, "HPOUT2R_DLY" },
-       { "HPOUT2R_OUTP", NULL, "HPOUT2R_DCS" },
-       { "HPOUT2R_RMV_SHORT", NULL, "HPOUT2R_OUTP" },
-
-       { "HPOUT1L PGA", NULL, "Charge Pump" },
-       { "HPOUT1L PGA", NULL, "DAC1L" },
-       { "HPOUT1L_DLY", NULL, "HPOUT1L PGA" },
-       { "HPOUT1L_DCS", NULL, "HPOUT1L_DLY" },
-       { "HPOUT1L_OUTP", NULL, "HPOUT1L_DCS" },
-       { "HPOUT1L_RMV_SHORT", NULL, "HPOUT1L_OUTP" },
-
-       { "HPOUT1R PGA", NULL, "Charge Pump" },
-       { "HPOUT1R PGA", NULL, "DAC1R" },
-       { "HPOUT1R_DLY", NULL, "HPOUT1R PGA" },
-       { "HPOUT1R_DCS", NULL, "HPOUT1R_DLY" },
-       { "HPOUT1R_OUTP", NULL, "HPOUT1R_DCS" },
-       { "HPOUT1R_RMV_SHORT", NULL, "HPOUT1R_OUTP" },
-
-       { "HPOUT2L", NULL, "HPOUT2L_RMV_SHORT" },
-       { "HPOUT2R", NULL, "HPOUT2R_RMV_SHORT" },
-       { "HPOUT1L", NULL, "HPOUT1L_RMV_SHORT" },
-       { "HPOUT1R", NULL, "HPOUT1R_RMV_SHORT" },
-
-       { "SPKL", "DAC1L", "DAC1L" },
-       { "SPKL", "DAC1R", "DAC1R" },
-       { "SPKL", "DAC2L", "DAC2L" },
-       { "SPKL", "DAC2R", "DAC2R" },
-
-       { "SPKR", "DAC1L", "DAC1L" },
-       { "SPKR", "DAC1R", "DAC1R" },
-       { "SPKR", "DAC2L", "DAC2L" },
-       { "SPKR", "DAC2R", "DAC2R" },
-
-       { "SPKL PGA", NULL, "SPKL" },
-       { "SPKR PGA", NULL, "SPKR" },
-
-       { "SPKDAT", NULL, "SPKL PGA" },
-       { "SPKDAT", NULL, "SPKR PGA" },
-};
-
-static int wm8915_readable_register(struct snd_soc_codec *codec,
-                                   unsigned int reg)
-{
-       /* Due to the sparseness of the register map the compiler
-        * output from an explicit switch statement ends up being much
-        * more efficient than a table.
-        */
-       switch (reg) {
-       case WM8915_SOFTWARE_RESET:
-       case WM8915_POWER_MANAGEMENT_1:
-       case WM8915_POWER_MANAGEMENT_2:
-       case WM8915_POWER_MANAGEMENT_3:
-       case WM8915_POWER_MANAGEMENT_4:
-       case WM8915_POWER_MANAGEMENT_5:
-       case WM8915_POWER_MANAGEMENT_6:
-       case WM8915_POWER_MANAGEMENT_7:
-       case WM8915_POWER_MANAGEMENT_8:
-       case WM8915_LEFT_LINE_INPUT_VOLUME:
-       case WM8915_RIGHT_LINE_INPUT_VOLUME:
-       case WM8915_LINE_INPUT_CONTROL:
-       case WM8915_DAC1_HPOUT1_VOLUME:
-       case WM8915_DAC2_HPOUT2_VOLUME:
-       case WM8915_DAC1_LEFT_VOLUME:
-       case WM8915_DAC1_RIGHT_VOLUME:
-       case WM8915_DAC2_LEFT_VOLUME:
-       case WM8915_DAC2_RIGHT_VOLUME:
-       case WM8915_OUTPUT1_LEFT_VOLUME:
-       case WM8915_OUTPUT1_RIGHT_VOLUME:
-       case WM8915_OUTPUT2_LEFT_VOLUME:
-       case WM8915_OUTPUT2_RIGHT_VOLUME:
-       case WM8915_MICBIAS_1:
-       case WM8915_MICBIAS_2:
-       case WM8915_LDO_1:
-       case WM8915_LDO_2:
-       case WM8915_ACCESSORY_DETECT_MODE_1:
-       case WM8915_ACCESSORY_DETECT_MODE_2:
-       case WM8915_HEADPHONE_DETECT_1:
-       case WM8915_HEADPHONE_DETECT_2:
-       case WM8915_MIC_DETECT_1:
-       case WM8915_MIC_DETECT_2:
-       case WM8915_MIC_DETECT_3:
-       case WM8915_CHARGE_PUMP_1:
-       case WM8915_CHARGE_PUMP_2:
-       case WM8915_DC_SERVO_1:
-       case WM8915_DC_SERVO_2:
-       case WM8915_DC_SERVO_3:
-       case WM8915_DC_SERVO_5:
-       case WM8915_DC_SERVO_6:
-       case WM8915_DC_SERVO_7:
-       case WM8915_DC_SERVO_READBACK_0:
-       case WM8915_ANALOGUE_HP_1:
-       case WM8915_ANALOGUE_HP_2:
-       case WM8915_CHIP_REVISION:
-       case WM8915_CONTROL_INTERFACE_1:
-       case WM8915_WRITE_SEQUENCER_CTRL_1:
-       case WM8915_WRITE_SEQUENCER_CTRL_2:
-       case WM8915_AIF_CLOCKING_1:
-       case WM8915_AIF_CLOCKING_2:
-       case WM8915_CLOCKING_1:
-       case WM8915_CLOCKING_2:
-       case WM8915_AIF_RATE:
-       case WM8915_FLL_CONTROL_1:
-       case WM8915_FLL_CONTROL_2:
-       case WM8915_FLL_CONTROL_3:
-       case WM8915_FLL_CONTROL_4:
-       case WM8915_FLL_CONTROL_5:
-       case WM8915_FLL_CONTROL_6:
-       case WM8915_FLL_EFS_1:
-       case WM8915_FLL_EFS_2:
-       case WM8915_AIF1_CONTROL:
-       case WM8915_AIF1_BCLK:
-       case WM8915_AIF1_TX_LRCLK_1:
-       case WM8915_AIF1_TX_LRCLK_2:
-       case WM8915_AIF1_RX_LRCLK_1:
-       case WM8915_AIF1_RX_LRCLK_2:
-       case WM8915_AIF1TX_DATA_CONFIGURATION_1:
-       case WM8915_AIF1TX_DATA_CONFIGURATION_2:
-       case WM8915_AIF1RX_DATA_CONFIGURATION:
-       case WM8915_AIF1TX_CHANNEL_0_CONFIGURATION:
-       case WM8915_AIF1TX_CHANNEL_1_CONFIGURATION:
-       case WM8915_AIF1TX_CHANNEL_2_CONFIGURATION:
-       case WM8915_AIF1TX_CHANNEL_3_CONFIGURATION:
-       case WM8915_AIF1TX_CHANNEL_4_CONFIGURATION:
-       case WM8915_AIF1TX_CHANNEL_5_CONFIGURATION:
-       case WM8915_AIF1RX_CHANNEL_0_CONFIGURATION:
-       case WM8915_AIF1RX_CHANNEL_1_CONFIGURATION:
-       case WM8915_AIF1RX_CHANNEL_2_CONFIGURATION:
-       case WM8915_AIF1RX_CHANNEL_3_CONFIGURATION:
-       case WM8915_AIF1RX_CHANNEL_4_CONFIGURATION:
-       case WM8915_AIF1RX_CHANNEL_5_CONFIGURATION:
-       case WM8915_AIF1RX_MONO_CONFIGURATION:
-       case WM8915_AIF1TX_TEST:
-       case WM8915_AIF2_CONTROL:
-       case WM8915_AIF2_BCLK:
-       case WM8915_AIF2_TX_LRCLK_1:
-       case WM8915_AIF2_TX_LRCLK_2:
-       case WM8915_AIF2_RX_LRCLK_1:
-       case WM8915_AIF2_RX_LRCLK_2:
-       case WM8915_AIF2TX_DATA_CONFIGURATION_1:
-       case WM8915_AIF2TX_DATA_CONFIGURATION_2:
-       case WM8915_AIF2RX_DATA_CONFIGURATION:
-       case WM8915_AIF2TX_CHANNEL_0_CONFIGURATION:
-       case WM8915_AIF2TX_CHANNEL_1_CONFIGURATION:
-       case WM8915_AIF2RX_CHANNEL_0_CONFIGURATION:
-       case WM8915_AIF2RX_CHANNEL_1_CONFIGURATION:
-       case WM8915_AIF2RX_MONO_CONFIGURATION:
-       case WM8915_AIF2TX_TEST:
-       case WM8915_DSP1_TX_LEFT_VOLUME:
-       case WM8915_DSP1_TX_RIGHT_VOLUME:
-       case WM8915_DSP1_RX_LEFT_VOLUME:
-       case WM8915_DSP1_RX_RIGHT_VOLUME:
-       case WM8915_DSP1_TX_FILTERS:
-       case WM8915_DSP1_RX_FILTERS_1:
-       case WM8915_DSP1_RX_FILTERS_2:
-       case WM8915_DSP1_DRC_1:
-       case WM8915_DSP1_DRC_2:
-       case WM8915_DSP1_DRC_3:
-       case WM8915_DSP1_DRC_4:
-       case WM8915_DSP1_DRC_5:
-       case WM8915_DSP1_RX_EQ_GAINS_1:
-       case WM8915_DSP1_RX_EQ_GAINS_2:
-       case WM8915_DSP1_RX_EQ_BAND_1_A:
-       case WM8915_DSP1_RX_EQ_BAND_1_B:
-       case WM8915_DSP1_RX_EQ_BAND_1_PG:
-       case WM8915_DSP1_RX_EQ_BAND_2_A:
-       case WM8915_DSP1_RX_EQ_BAND_2_B:
-       case WM8915_DSP1_RX_EQ_BAND_2_C:
-       case WM8915_DSP1_RX_EQ_BAND_2_PG:
-       case WM8915_DSP1_RX_EQ_BAND_3_A:
-       case WM8915_DSP1_RX_EQ_BAND_3_B:
-       case WM8915_DSP1_RX_EQ_BAND_3_C:
-       case WM8915_DSP1_RX_EQ_BAND_3_PG:
-       case WM8915_DSP1_RX_EQ_BAND_4_A:
-       case WM8915_DSP1_RX_EQ_BAND_4_B:
-       case WM8915_DSP1_RX_EQ_BAND_4_C:
-       case WM8915_DSP1_RX_EQ_BAND_4_PG:
-       case WM8915_DSP1_RX_EQ_BAND_5_A:
-       case WM8915_DSP1_RX_EQ_BAND_5_B:
-       case WM8915_DSP1_RX_EQ_BAND_5_PG:
-       case WM8915_DSP2_TX_LEFT_VOLUME:
-       case WM8915_DSP2_TX_RIGHT_VOLUME:
-       case WM8915_DSP2_RX_LEFT_VOLUME:
-       case WM8915_DSP2_RX_RIGHT_VOLUME:
-       case WM8915_DSP2_TX_FILTERS:
-       case WM8915_DSP2_RX_FILTERS_1:
-       case WM8915_DSP2_RX_FILTERS_2:
-       case WM8915_DSP2_DRC_1:
-       case WM8915_DSP2_DRC_2:
-       case WM8915_DSP2_DRC_3:
-       case WM8915_DSP2_DRC_4:
-       case WM8915_DSP2_DRC_5:
-       case WM8915_DSP2_RX_EQ_GAINS_1:
-       case WM8915_DSP2_RX_EQ_GAINS_2:
-       case WM8915_DSP2_RX_EQ_BAND_1_A:
-       case WM8915_DSP2_RX_EQ_BAND_1_B:
-       case WM8915_DSP2_RX_EQ_BAND_1_PG:
-       case WM8915_DSP2_RX_EQ_BAND_2_A:
-       case WM8915_DSP2_RX_EQ_BAND_2_B:
-       case WM8915_DSP2_RX_EQ_BAND_2_C:
-       case WM8915_DSP2_RX_EQ_BAND_2_PG:
-       case WM8915_DSP2_RX_EQ_BAND_3_A:
-       case WM8915_DSP2_RX_EQ_BAND_3_B:
-       case WM8915_DSP2_RX_EQ_BAND_3_C:
-       case WM8915_DSP2_RX_EQ_BAND_3_PG:
-       case WM8915_DSP2_RX_EQ_BAND_4_A:
-       case WM8915_DSP2_RX_EQ_BAND_4_B:
-       case WM8915_DSP2_RX_EQ_BAND_4_C:
-       case WM8915_DSP2_RX_EQ_BAND_4_PG:
-       case WM8915_DSP2_RX_EQ_BAND_5_A:
-       case WM8915_DSP2_RX_EQ_BAND_5_B:
-       case WM8915_DSP2_RX_EQ_BAND_5_PG:
-       case WM8915_DAC1_MIXER_VOLUMES:
-       case WM8915_DAC1_LEFT_MIXER_ROUTING:
-       case WM8915_DAC1_RIGHT_MIXER_ROUTING:
-       case WM8915_DAC2_MIXER_VOLUMES:
-       case WM8915_DAC2_LEFT_MIXER_ROUTING:
-       case WM8915_DAC2_RIGHT_MIXER_ROUTING:
-       case WM8915_DSP1_TX_LEFT_MIXER_ROUTING:
-       case WM8915_DSP1_TX_RIGHT_MIXER_ROUTING:
-       case WM8915_DSP2_TX_LEFT_MIXER_ROUTING:
-       case WM8915_DSP2_TX_RIGHT_MIXER_ROUTING:
-       case WM8915_DSP_TX_MIXER_SELECT:
-       case WM8915_DAC_SOFTMUTE:
-       case WM8915_OVERSAMPLING:
-       case WM8915_SIDETONE:
-       case WM8915_GPIO_1:
-       case WM8915_GPIO_2:
-       case WM8915_GPIO_3:
-       case WM8915_GPIO_4:
-       case WM8915_GPIO_5:
-       case WM8915_PULL_CONTROL_1:
-       case WM8915_PULL_CONTROL_2:
-       case WM8915_INTERRUPT_STATUS_1:
-       case WM8915_INTERRUPT_STATUS_2:
-       case WM8915_INTERRUPT_RAW_STATUS_2:
-       case WM8915_INTERRUPT_STATUS_1_MASK:
-       case WM8915_INTERRUPT_STATUS_2_MASK:
-       case WM8915_INTERRUPT_CONTROL:
-       case WM8915_LEFT_PDM_SPEAKER:
-       case WM8915_RIGHT_PDM_SPEAKER:
-       case WM8915_PDM_SPEAKER_MUTE_SEQUENCE:
-       case WM8915_PDM_SPEAKER_VOLUME:
-               return 1;
-       default:
-               return 0;
-       }
-}
-
-static int wm8915_volatile_register(struct snd_soc_codec *codec,
-                                   unsigned int reg)
-{
-       switch (reg) {
-       case WM8915_SOFTWARE_RESET:
-       case WM8915_CHIP_REVISION:
-       case WM8915_LDO_1:
-       case WM8915_LDO_2:
-       case WM8915_INTERRUPT_STATUS_1:
-       case WM8915_INTERRUPT_STATUS_2:
-       case WM8915_INTERRUPT_RAW_STATUS_2:
-       case WM8915_DC_SERVO_READBACK_0:
-       case WM8915_DC_SERVO_2:
-       case WM8915_DC_SERVO_6:
-       case WM8915_DC_SERVO_7:
-       case WM8915_FLL_CONTROL_6:
-       case WM8915_MIC_DETECT_3:
-       case WM8915_HEADPHONE_DETECT_1:
-       case WM8915_HEADPHONE_DETECT_2:
-               return 1;
-       default:
-               return 0;
-       }
-}
-
-static int wm8915_reset(struct snd_soc_codec *codec)
-{
-       return snd_soc_write(codec, WM8915_SOFTWARE_RESET, 0x8915);
-}
-
-static const int bclk_divs[] = {
-       1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96
-};
-
-static void wm8915_update_bclk(struct snd_soc_codec *codec)
-{
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       int aif, best, cur_val, bclk_rate, bclk_reg, i;
-
-       /* Don't bother if we're in a low frequency idle mode that
-        * can't support audio.
-        */
-       if (wm8915->sysclk < 64000)
-               return;
-
-       for (aif = 0; aif < WM8915_AIFS; aif++) {
-               switch (aif) {
-               case 0:
-                       bclk_reg = WM8915_AIF1_BCLK;
-                       break;
-               case 1:
-                       bclk_reg = WM8915_AIF2_BCLK;
-                       break;
-               }
-
-               bclk_rate = wm8915->bclk_rate[aif];
-
-               /* Pick a divisor for BCLK as close as we can get to ideal */
-               best = 0;
-               for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
-                       cur_val = (wm8915->sysclk / bclk_divs[i]) - bclk_rate;
-                       if (cur_val < 0) /* BCLK table is sorted */
-                               break;
-                       best = i;
-               }
-               bclk_rate = wm8915->sysclk / bclk_divs[best];
-               dev_dbg(codec->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n",
-                       bclk_divs[best], bclk_rate);
-
-               snd_soc_update_bits(codec, bclk_reg,
-                                   WM8915_AIF1_BCLK_DIV_MASK, best);
-       }
-}
-
-static int wm8915_set_bias_level(struct snd_soc_codec *codec,
-                                enum snd_soc_bias_level level)
-{
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       int ret;
-
-       switch (level) {
-       case SND_SOC_BIAS_ON:
-               break;
-
-       case SND_SOC_BIAS_PREPARE:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
-                       snd_soc_update_bits(codec, WM8915_POWER_MANAGEMENT_1,
-                                           WM8915_BG_ENA, WM8915_BG_ENA);
-                       msleep(2);
-               }
-               break;
-
-       case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
-                       ret = regulator_bulk_enable(ARRAY_SIZE(wm8915->supplies),
-                                                   wm8915->supplies);
-                       if (ret != 0) {
-                               dev_err(codec->dev,
-                                       "Failed to enable supplies: %d\n",
-                                       ret);
-                               return ret;
-                       }
-
-                       if (wm8915->pdata.ldo_ena >= 0) {
-                               gpio_set_value_cansleep(wm8915->pdata.ldo_ena,
-                                                       1);
-                               msleep(5);
-                       }
-
-                       codec->cache_only = false;
-                       snd_soc_cache_sync(codec);
-               }
-
-               snd_soc_update_bits(codec, WM8915_POWER_MANAGEMENT_1,
-                                   WM8915_BG_ENA, 0);
-               break;
-
-       case SND_SOC_BIAS_OFF:
-               codec->cache_only = true;
-               if (wm8915->pdata.ldo_ena >= 0)
-                       gpio_set_value_cansleep(wm8915->pdata.ldo_ena, 0);
-               regulator_bulk_disable(ARRAY_SIZE(wm8915->supplies),
-                                      wm8915->supplies);
-               break;
-       }
-
-       codec->dapm.bias_level = level;
-
-       return 0;
-}
-
-static int wm8915_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
-{
-       struct snd_soc_codec *codec = dai->codec;
-       int aifctrl = 0;
-       int bclk = 0;
-       int lrclk_tx = 0;
-       int lrclk_rx = 0;
-       int aifctrl_reg, bclk_reg, lrclk_tx_reg, lrclk_rx_reg;
-
-       switch (dai->id) {
-       case 0:
-               aifctrl_reg = WM8915_AIF1_CONTROL;
-               bclk_reg = WM8915_AIF1_BCLK;
-               lrclk_tx_reg = WM8915_AIF1_TX_LRCLK_2;
-               lrclk_rx_reg = WM8915_AIF1_RX_LRCLK_2;
-               break;
-       case 1:
-               aifctrl_reg = WM8915_AIF2_CONTROL;
-               bclk_reg = WM8915_AIF2_BCLK;
-               lrclk_tx_reg = WM8915_AIF2_TX_LRCLK_2;
-               lrclk_rx_reg = WM8915_AIF2_RX_LRCLK_2;
-               break;
-       default:
-               BUG();
-               return -EINVAL;
-       }
-
-       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-       case SND_SOC_DAIFMT_NB_NF:
-               break;
-       case SND_SOC_DAIFMT_IB_NF:
-               bclk |= WM8915_AIF1_BCLK_INV;
-               break;
-       case SND_SOC_DAIFMT_NB_IF:
-               lrclk_tx |= WM8915_AIF1TX_LRCLK_INV;
-               lrclk_rx |= WM8915_AIF1RX_LRCLK_INV;
-               break;
-       case SND_SOC_DAIFMT_IB_IF:
-               bclk |= WM8915_AIF1_BCLK_INV;
-               lrclk_tx |= WM8915_AIF1TX_LRCLK_INV;
-               lrclk_rx |= WM8915_AIF1RX_LRCLK_INV;
-               break;
-       }
-
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
-               break;
-       case SND_SOC_DAIFMT_CBS_CFM:
-               lrclk_tx |= WM8915_AIF1TX_LRCLK_MSTR;
-               lrclk_rx |= WM8915_AIF1RX_LRCLK_MSTR;
-               break;
-       case SND_SOC_DAIFMT_CBM_CFS:
-               bclk |= WM8915_AIF1_BCLK_MSTR;
-               break;
-       case SND_SOC_DAIFMT_CBM_CFM:
-               bclk |= WM8915_AIF1_BCLK_MSTR;
-               lrclk_tx |= WM8915_AIF1TX_LRCLK_MSTR;
-               lrclk_rx |= WM8915_AIF1RX_LRCLK_MSTR;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-       case SND_SOC_DAIFMT_DSP_A:
-               break;
-       case SND_SOC_DAIFMT_DSP_B:
-               aifctrl |= 1;
-               break;
-       case SND_SOC_DAIFMT_I2S:
-               aifctrl |= 2;
-               break;
-       case SND_SOC_DAIFMT_LEFT_J:
-               aifctrl |= 3;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       snd_soc_update_bits(codec, aifctrl_reg, WM8915_AIF1_FMT_MASK, aifctrl);
-       snd_soc_update_bits(codec, bclk_reg,
-                           WM8915_AIF1_BCLK_INV | WM8915_AIF1_BCLK_MSTR,
-                           bclk);
-       snd_soc_update_bits(codec, lrclk_tx_reg,
-                           WM8915_AIF1TX_LRCLK_INV |
-                           WM8915_AIF1TX_LRCLK_MSTR,
-                           lrclk_tx);
-       snd_soc_update_bits(codec, lrclk_rx_reg,
-                           WM8915_AIF1RX_LRCLK_INV |
-                           WM8915_AIF1RX_LRCLK_MSTR,
-                           lrclk_rx);
-
-       return 0;
-}
-
-static const int dsp_divs[] = {
-       48000, 32000, 16000, 8000
-};
-
-static int wm8915_hw_params(struct snd_pcm_substream *substream,
-                           struct snd_pcm_hw_params *params,
-                           struct snd_soc_dai *dai)
-{
-       struct snd_soc_codec *codec = dai->codec;
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       int bits, i, bclk_rate;
-       int aifdata = 0;
-       int lrclk = 0;
-       int dsp = 0;
-       int aifdata_reg, lrclk_reg, dsp_shift;
-
-       switch (dai->id) {
-       case 0:
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
-                   (snd_soc_read(codec, WM8915_GPIO_1)) & WM8915_GP1_FN_MASK) {
-                       aifdata_reg = WM8915_AIF1RX_DATA_CONFIGURATION;
-                       lrclk_reg = WM8915_AIF1_RX_LRCLK_1;
-               } else {
-                       aifdata_reg = WM8915_AIF1TX_DATA_CONFIGURATION_1;
-                       lrclk_reg = WM8915_AIF1_TX_LRCLK_1;
-               }
-               dsp_shift = 0;
-               break;
-       case 1:
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
-                   (snd_soc_read(codec, WM8915_GPIO_2)) & WM8915_GP2_FN_MASK) {
-                       aifdata_reg = WM8915_AIF2RX_DATA_CONFIGURATION;
-                       lrclk_reg = WM8915_AIF2_RX_LRCLK_1;
-               } else {
-                       aifdata_reg = WM8915_AIF2TX_DATA_CONFIGURATION_1;
-                       lrclk_reg = WM8915_AIF2_TX_LRCLK_1;
-               }
-               dsp_shift = WM8915_DSP2_DIV_SHIFT;
-               break;
-       default:
-               BUG();
-               return -EINVAL;
-       }
-
-       bclk_rate = snd_soc_params_to_bclk(params);
-       if (bclk_rate < 0) {
-               dev_err(codec->dev, "Unsupported BCLK rate: %d\n", bclk_rate);
-               return bclk_rate;
-       }
-
-       wm8915->bclk_rate[dai->id] = bclk_rate;
-       wm8915->rx_rate[dai->id] = params_rate(params);
-
-       /* Needs looking at for TDM */
-       bits = snd_pcm_format_width(params_format(params));
-       if (bits < 0)
-               return bits;
-       aifdata |= (bits << WM8915_AIF1TX_WL_SHIFT) | bits;
-
-       for (i = 0; i < ARRAY_SIZE(dsp_divs); i++) {
-               if (dsp_divs[i] == params_rate(params))
-                       break;
-       }
-       if (i == ARRAY_SIZE(dsp_divs)) {
-               dev_err(codec->dev, "Unsupported sample rate %dHz\n",
-                       params_rate(params));
-               return -EINVAL;
-       }
-       dsp |= i << dsp_shift;
-
-       wm8915_update_bclk(codec);
-
-       lrclk = bclk_rate / params_rate(params);
-       dev_dbg(dai->dev, "Using LRCLK rate %d for actual LRCLK %dHz\n",
-               lrclk, bclk_rate / lrclk);
-
-       snd_soc_update_bits(codec, aifdata_reg,
-                           WM8915_AIF1TX_WL_MASK |
-                           WM8915_AIF1TX_SLOT_LEN_MASK,
-                           aifdata);
-       snd_soc_update_bits(codec, lrclk_reg, WM8915_AIF1RX_RATE_MASK,
-                           lrclk);
-       snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_2,
-                           WM8915_DSP1_DIV_SHIFT << dsp_shift, dsp);
-
-       return 0;
-}
-
-static int wm8915_set_sysclk(struct snd_soc_dai *dai,
-               int clk_id, unsigned int freq, int dir)
-{
-       struct snd_soc_codec *codec = dai->codec;
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       int lfclk = 0;
-       int ratediv = 0;
-       int src;
-       int old;
-
-       if (freq == wm8915->sysclk && clk_id == wm8915->sysclk_src)
-               return 0;
-
-       /* Disable SYSCLK while we reconfigure */
-       old = snd_soc_read(codec, WM8915_AIF_CLOCKING_1) & WM8915_SYSCLK_ENA;
-       snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1,
-                           WM8915_SYSCLK_ENA, 0);
-
-       switch (clk_id) {
-       case WM8915_SYSCLK_MCLK1:
-               wm8915->sysclk = freq;
-               src = 0;
-               break;
-       case WM8915_SYSCLK_MCLK2:
-               wm8915->sysclk = freq;
-               src = 1;
-               break;
-       case WM8915_SYSCLK_FLL:
-               wm8915->sysclk = freq;
-               src = 2;
-               break;
-       default:
-               dev_err(codec->dev, "Unsupported clock source %d\n", clk_id);
-               return -EINVAL;
-       }
-
-       switch (wm8915->sysclk) {
-       case 6144000:
-               snd_soc_update_bits(codec, WM8915_AIF_RATE,
-                                   WM8915_SYSCLK_RATE, 0);
-               break;
-       case 24576000:
-               ratediv = WM8915_SYSCLK_DIV;
-       case 12288000:
-               snd_soc_update_bits(codec, WM8915_AIF_RATE,
-                                   WM8915_SYSCLK_RATE, WM8915_SYSCLK_RATE);
-               break;
-       case 32000:
-       case 32768:
-               lfclk = WM8915_LFCLK_ENA;
-               break;
-       default:
-               dev_warn(codec->dev, "Unsupported clock rate %dHz\n",
-                        wm8915->sysclk);
-               return -EINVAL;
-       }
-
-       wm8915_update_bclk(codec);
-
-       snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1,
-                           WM8915_SYSCLK_SRC_MASK | WM8915_SYSCLK_DIV_MASK,
-                           src << WM8915_SYSCLK_SRC_SHIFT | ratediv);
-       snd_soc_update_bits(codec, WM8915_CLOCKING_1, WM8915_LFCLK_ENA, lfclk);
-       snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1,
-                           WM8915_SYSCLK_ENA, old);
-
-       wm8915->sysclk_src = clk_id;
-
-       return 0;
-}
-
-struct _fll_div {
-       u16 fll_fratio;
-       u16 fll_outdiv;
-       u16 fll_refclk_div;
-       u16 fll_loop_gain;
-       u16 fll_ref_freq;
-       u16 n;
-       u16 theta;
-       u16 lambda;
-};
-
-static struct {
-       unsigned int min;
-       unsigned int max;
-       u16 fll_fratio;
-       int ratio;
-} fll_fratios[] = {
-       {       0,    64000, 4, 16 },
-       {   64000,   128000, 3,  8 },
-       {  128000,   256000, 2,  4 },
-       {  256000,  1000000, 1,  2 },
-       { 1000000, 13500000, 0,  1 },
-};
-
-static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
-                      unsigned int Fout)
-{
-       unsigned int target;
-       unsigned int div;
-       unsigned int fratio, gcd_fll;
-       int i;
-
-       /* Fref must be <=13.5MHz */
-       div = 1;
-       fll_div->fll_refclk_div = 0;
-       while ((Fref / div) > 13500000) {
-               div *= 2;
-               fll_div->fll_refclk_div++;
-
-               if (div > 8) {
-                       pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
-                              Fref);
-                       return -EINVAL;
-               }
-       }
-
-       pr_debug("FLL Fref=%u Fout=%u\n", Fref, Fout);
-
-       /* Apply the division for our remaining calculations */
-       Fref /= div;
-
-       if (Fref >= 3000000)
-               fll_div->fll_loop_gain = 5;
-       else
-               fll_div->fll_loop_gain = 0;
-
-       if (Fref >= 48000)
-               fll_div->fll_ref_freq = 0;
-       else
-               fll_div->fll_ref_freq = 1;
-
-       /* Fvco should be 90-100MHz; don't check the upper bound */
-       div = 2;
-       while (Fout * div < 90000000) {
-               div++;
-               if (div > 64) {
-                       pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
-                              Fout);
-                       return -EINVAL;
-               }
-       }
-       target = Fout * div;
-       fll_div->fll_outdiv = div - 1;
-
-       pr_debug("FLL Fvco=%dHz\n", target);
-
-       /* Find an appropraite FLL_FRATIO and factor it out of the target */
-       for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
-               if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
-                       fll_div->fll_fratio = fll_fratios[i].fll_fratio;
-                       fratio = fll_fratios[i].ratio;
-                       break;
-               }
-       }
-       if (i == ARRAY_SIZE(fll_fratios)) {
-               pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
-               return -EINVAL;
-       }
-
-       fll_div->n = target / (fratio * Fref);
-
-       if (target % Fref == 0) {
-               fll_div->theta = 0;
-               fll_div->lambda = 0;
-       } else {
-               gcd_fll = gcd(target, fratio * Fref);
-
-               fll_div->theta = (target - (fll_div->n * fratio * Fref))
-                       / gcd_fll;
-               fll_div->lambda = (fratio * Fref) / gcd_fll;
-       }
-
-       pr_debug("FLL N=%x THETA=%x LAMBDA=%x\n",
-                fll_div->n, fll_div->theta, fll_div->lambda);
-       pr_debug("FLL_FRATIO=%x FLL_OUTDIV=%x FLL_REFCLK_DIV=%x\n",
-                fll_div->fll_fratio, fll_div->fll_outdiv,
-                fll_div->fll_refclk_div);
-
-       return 0;
-}
-
-static int wm8915_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
-                         unsigned int Fref, unsigned int Fout)
-{
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       struct i2c_client *i2c = to_i2c_client(codec->dev);
-       struct _fll_div fll_div;
-       unsigned long timeout;
-       int ret, reg;
-
-       /* Any change? */
-       if (source == wm8915->fll_src && Fref == wm8915->fll_fref &&
-           Fout == wm8915->fll_fout)
-               return 0;
-
-       if (Fout == 0) {
-               dev_dbg(codec->dev, "FLL disabled\n");
-
-               wm8915->fll_fref = 0;
-               wm8915->fll_fout = 0;
-
-               snd_soc_update_bits(codec, WM8915_FLL_CONTROL_1,
-                                   WM8915_FLL_ENA, 0);
-
-               return 0;
-       }
-
-       ret = fll_factors(&fll_div, Fref, Fout);
-       if (ret != 0)
-               return ret;
-
-       switch (source) {
-       case WM8915_FLL_MCLK1:
-               reg = 0;
-               break;
-       case WM8915_FLL_MCLK2:
-               reg = 1;
-               break;
-       case WM8915_FLL_DACLRCLK1:
-               reg = 2;
-               break;
-       case WM8915_FLL_BCLK1:
-               reg = 3;
-               break;
-       default:
-               dev_err(codec->dev, "Unknown FLL source %d\n", ret);
-               return -EINVAL;
-       }
-
-       reg |= fll_div.fll_refclk_div << WM8915_FLL_REFCLK_DIV_SHIFT;
-       reg |= fll_div.fll_ref_freq << WM8915_FLL_REF_FREQ_SHIFT;
-
-       snd_soc_update_bits(codec, WM8915_FLL_CONTROL_5,
-                           WM8915_FLL_REFCLK_DIV_MASK | WM8915_FLL_REF_FREQ |
-                           WM8915_FLL_REFCLK_SRC_MASK, reg);
-
-       reg = 0;
-       if (fll_div.theta || fll_div.lambda)
-               reg |= WM8915_FLL_EFS_ENA | (3 << WM8915_FLL_LFSR_SEL_SHIFT);
-       else
-               reg |= 1 << WM8915_FLL_LFSR_SEL_SHIFT;
-       snd_soc_write(codec, WM8915_FLL_EFS_2, reg);
-
-       snd_soc_update_bits(codec, WM8915_FLL_CONTROL_2,
-                           WM8915_FLL_OUTDIV_MASK |
-                           WM8915_FLL_FRATIO_MASK,
-                           (fll_div.fll_outdiv << WM8915_FLL_OUTDIV_SHIFT) |
-                           (fll_div.fll_fratio));
-
-       snd_soc_write(codec, WM8915_FLL_CONTROL_3, fll_div.theta);
-
-       snd_soc_update_bits(codec, WM8915_FLL_CONTROL_4,
-                           WM8915_FLL_N_MASK | WM8915_FLL_LOOP_GAIN_MASK,
-                           (fll_div.n << WM8915_FLL_N_SHIFT) |
-                           fll_div.fll_loop_gain);
-
-       snd_soc_write(codec, WM8915_FLL_EFS_1, fll_div.lambda);
-
-       snd_soc_update_bits(codec, WM8915_FLL_CONTROL_1,
-                           WM8915_FLL_ENA, WM8915_FLL_ENA);
-
-       /* The FLL supports live reconfiguration - kick that in case we were
-        * already enabled.
-        */
-       snd_soc_write(codec, WM8915_FLL_CONTROL_6, WM8915_FLL_SWITCH_CLK);
-
-       /* Wait for the FLL to lock, using the interrupt if possible */
-       if (Fref > 1000000)
-               timeout = usecs_to_jiffies(300);
-       else
-               timeout = msecs_to_jiffies(2);
-
-       /* Allow substantially longer if we've actually got the IRQ */
-       if (i2c->irq)
-               timeout *= 1000;
-
-       ret = wait_for_completion_timeout(&wm8915->fll_lock, timeout);
-
-       if (ret == 0 && i2c->irq) {
-               dev_err(codec->dev, "Timed out waiting for FLL\n");
-               ret = -ETIMEDOUT;
-       } else {
-               ret = 0;
-       }
-
-       dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
-
-       wm8915->fll_fref = Fref;
-       wm8915->fll_fout = Fout;
-       wm8915->fll_src = source;
-
-       return ret;
-}
-
-#ifdef CONFIG_GPIOLIB
-static inline struct wm8915_priv *gpio_to_wm8915(struct gpio_chip *chip)
-{
-       return container_of(chip, struct wm8915_priv, gpio_chip);
-}
-
-static void wm8915_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
-{
-       struct wm8915_priv *wm8915 = gpio_to_wm8915(chip);
-       struct snd_soc_codec *codec = wm8915->codec;
-
-       snd_soc_update_bits(codec, WM8915_GPIO_1 + offset,
-                           WM8915_GP1_LVL, !!value << WM8915_GP1_LVL_SHIFT);
-}
-
-static int wm8915_gpio_direction_out(struct gpio_chip *chip,
-                                    unsigned offset, int value)
-{
-       struct wm8915_priv *wm8915 = gpio_to_wm8915(chip);
-       struct snd_soc_codec *codec = wm8915->codec;
-       int val;
-
-       val = (1 << WM8915_GP1_FN_SHIFT) | (!!value << WM8915_GP1_LVL_SHIFT);
-
-       return snd_soc_update_bits(codec, WM8915_GPIO_1 + offset,
-                                  WM8915_GP1_FN_MASK | WM8915_GP1_DIR |
-                                  WM8915_GP1_LVL, val);
-}
-
-static int wm8915_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
-       struct wm8915_priv *wm8915 = gpio_to_wm8915(chip);
-       struct snd_soc_codec *codec = wm8915->codec;
-       int ret;
-
-       ret = snd_soc_read(codec, WM8915_GPIO_1 + offset);
-       if (ret < 0)
-               return ret;
-
-       return (ret & WM8915_GP1_LVL) != 0;
-}
-
-static int wm8915_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
-{
-       struct wm8915_priv *wm8915 = gpio_to_wm8915(chip);
-       struct snd_soc_codec *codec = wm8915->codec;
-
-       return snd_soc_update_bits(codec, WM8915_GPIO_1 + offset,
-                                  WM8915_GP1_FN_MASK | WM8915_GP1_DIR,
-                                  (1 << WM8915_GP1_FN_SHIFT) |
-                                  (1 << WM8915_GP1_DIR_SHIFT));
-}
-
-static struct gpio_chip wm8915_template_chip = {
-       .label                  = "wm8915",
-       .owner                  = THIS_MODULE,
-       .direction_output       = wm8915_gpio_direction_out,
-       .set                    = wm8915_gpio_set,
-       .direction_input        = wm8915_gpio_direction_in,
-       .get                    = wm8915_gpio_get,
-       .can_sleep              = 1,
-};
-
-static void wm8915_init_gpio(struct snd_soc_codec *codec)
-{
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       int ret;
-
-       wm8915->gpio_chip = wm8915_template_chip;
-       wm8915->gpio_chip.ngpio = 5;
-       wm8915->gpio_chip.dev = codec->dev;
-
-       if (wm8915->pdata.gpio_base)
-               wm8915->gpio_chip.base = wm8915->pdata.gpio_base;
-       else
-               wm8915->gpio_chip.base = -1;
-
-       ret = gpiochip_add(&wm8915->gpio_chip);
-       if (ret != 0)
-               dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
-}
-
-static void wm8915_free_gpio(struct snd_soc_codec *codec)
-{
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       int ret;
-
-       ret = gpiochip_remove(&wm8915->gpio_chip);
-       if (ret != 0)
-               dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret);
-}
-#else
-static void wm8915_init_gpio(struct snd_soc_codec *codec)
-{
-}
-
-static void wm8915_free_gpio(struct snd_soc_codec *codec)
-{
-}
-#endif
-
-/**
- * wm8915_detect - Enable default WM8915 jack detection
- *
- * The WM8915 has advanced accessory detection support for headsets.
- * This function provides a default implementation which integrates
- * the majority of this functionality with minimal user configuration.
- *
- * This will detect headset, headphone and short circuit button and
- * will also detect inverted microphone ground connections and update
- * the polarity of the connections.
- */
-int wm8915_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
-                 wm8915_polarity_fn polarity_cb)
-{
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-
-       wm8915->jack = jack;
-       wm8915->detecting = true;
-       wm8915->polarity_cb = polarity_cb;
-
-       if (wm8915->polarity_cb)
-               wm8915->polarity_cb(codec, 0);
-
-       /* Clear discarge to avoid noise during detection */
-       snd_soc_update_bits(codec, WM8915_MICBIAS_1,
-                           WM8915_MICB1_DISCH, 0);
-       snd_soc_update_bits(codec, WM8915_MICBIAS_2,
-                           WM8915_MICB2_DISCH, 0);
-
-       /* LDO2 powers the microphones, SYSCLK clocks detection */
-       snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
-       snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK");
-
-       /* We start off just enabling microphone detection - even a
-        * plain headphone will trigger detection.
-        */
-       snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
-                           WM8915_MICD_ENA, WM8915_MICD_ENA);
-
-       /* Slowest detection rate, gives debounce for initial detection */
-       snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
-                           WM8915_MICD_RATE_MASK,
-                           WM8915_MICD_RATE_MASK);
-
-       /* Enable interrupts and we're off */
-       snd_soc_update_bits(codec, WM8915_INTERRUPT_STATUS_2_MASK,
-                           WM8915_IM_MICD_EINT, 0);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(wm8915_detect);
-
-static void wm8915_micd(struct snd_soc_codec *codec)
-{
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       int val, reg;
-
-       val = snd_soc_read(codec, WM8915_MIC_DETECT_3);
-
-       dev_dbg(codec->dev, "Microphone event: %x\n", val);
-
-       if (!(val & WM8915_MICD_VALID)) {
-               dev_warn(codec->dev, "Microphone detection state invalid\n");
-               return;
-       }
-
-       /* No accessory, reset everything and report removal */
-       if (!(val & WM8915_MICD_STS)) {
-               dev_dbg(codec->dev, "Jack removal detected\n");
-               wm8915->jack_mic = false;
-               wm8915->detecting = true;
-               snd_soc_jack_report(wm8915->jack, 0,
-                                   SND_JACK_HEADSET | SND_JACK_BTN_0);
-               snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
-                                   WM8915_MICD_RATE_MASK,
-                                   WM8915_MICD_RATE_MASK);
-               return;
-       }
-
-       /* If the measurement is very high we've got a microphone but
-        * do a little debounce to account for mechanical issues.
-        */
-       if (val & 0x400) {
-               dev_dbg(codec->dev, "Microphone detected\n");
-               snd_soc_jack_report(wm8915->jack, SND_JACK_HEADSET,
-                                   SND_JACK_HEADSET | SND_JACK_BTN_0);
-               wm8915->jack_mic = true;
-               wm8915->detecting = false;
-
-               /* Increase poll rate to give better responsiveness
-                * for buttons */
-               snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
-                                   WM8915_MICD_RATE_MASK,
-                                   5 << WM8915_MICD_RATE_SHIFT);
-       }
-
-       /* If we detected a lower impedence during initial startup
-        * then we probably have the wrong polarity, flip it.  Don't
-        * do this for the lowest impedences to speed up detection of
-        * plain headphones.
-        */
-       if (wm8915->detecting && (val & 0x3f0)) {
-               reg = snd_soc_read(codec, WM8915_ACCESSORY_DETECT_MODE_2);
-               reg ^= WM8915_HPOUT1FB_SRC | WM8915_MICD_SRC |
-                       WM8915_MICD_BIAS_SRC;
-               snd_soc_update_bits(codec, WM8915_ACCESSORY_DETECT_MODE_2,
-                                   WM8915_HPOUT1FB_SRC | WM8915_MICD_SRC |
-                                   WM8915_MICD_BIAS_SRC, reg);
-
-               if (wm8915->polarity_cb)
-                       wm8915->polarity_cb(codec,
-                                           (reg & WM8915_MICD_SRC) != 0);
-
-               dev_dbg(codec->dev, "Set microphone polarity to %d\n",
-                       (reg & WM8915_MICD_SRC) != 0);
-
-               return;
-       }
-
-       /* Don't distinguish between buttons, just report any low
-        * impedence as BTN_0.
-        */
-       if (val & 0x3fc) {
-               if (wm8915->jack_mic) {
-                       dev_dbg(codec->dev, "Mic button detected\n");
-                       snd_soc_jack_report(wm8915->jack,
-                                           SND_JACK_HEADSET | SND_JACK_BTN_0,
-                                           SND_JACK_HEADSET | SND_JACK_BTN_0);
-               } else {
-                       dev_dbg(codec->dev, "Headphone detected\n");
-                       snd_soc_jack_report(wm8915->jack,
-                                           SND_JACK_HEADPHONE,
-                                           SND_JACK_HEADSET |
-                                           SND_JACK_BTN_0);
-
-                       /* Increase the detection rate a bit for
-                        * responsiveness.
-                        */
-                       snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
-                                           WM8915_MICD_RATE_MASK,
-                                           7 << WM8915_MICD_RATE_SHIFT);
-
-                       wm8915->detecting = false;
-               }
-       }
-}
-
-static irqreturn_t wm8915_irq(int irq, void *data)
-{
-       struct snd_soc_codec *codec = data;
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       int irq_val;
-
-       irq_val = snd_soc_read(codec, WM8915_INTERRUPT_STATUS_2);
-       if (irq_val < 0) {
-               dev_err(codec->dev, "Failed to read IRQ status: %d\n",
-                       irq_val);
-               return IRQ_NONE;
-       }
-       irq_val &= ~snd_soc_read(codec, WM8915_INTERRUPT_STATUS_2_MASK);
-
-       if (irq_val & (WM8915_DCS_DONE_01_EINT | WM8915_DCS_DONE_23_EINT)) {
-               dev_dbg(codec->dev, "DC servo IRQ\n");
-               complete(&wm8915->dcs_done);
-       }
-
-       if (irq_val & WM8915_FIFOS_ERR_EINT)
-               dev_err(codec->dev, "Digital core FIFO error\n");
-
-       if (irq_val & WM8915_FLL_LOCK_EINT) {
-               dev_dbg(codec->dev, "FLL locked\n");
-               complete(&wm8915->fll_lock);
-       }
-
-       if (irq_val & WM8915_MICD_EINT)
-               wm8915_micd(codec);
-
-       if (irq_val) {
-               snd_soc_write(codec, WM8915_INTERRUPT_STATUS_2, irq_val);
-
-               return IRQ_HANDLED;
-       } else {
-               return IRQ_NONE;
-       }
-}
-
-static irqreturn_t wm8915_edge_irq(int irq, void *data)
-{
-       irqreturn_t ret = IRQ_NONE;
-       irqreturn_t val;
-
-       do {
-               val = wm8915_irq(irq, data);
-               if (val != IRQ_NONE)
-                       ret = val;
-       } while (val != IRQ_NONE);
-
-       return ret;
-}
-
-static void wm8915_retune_mobile_pdata(struct snd_soc_codec *codec)
-{
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       struct wm8915_pdata *pdata = &wm8915->pdata;
-
-       struct snd_kcontrol_new controls[] = {
-               SOC_ENUM_EXT("DSP1 EQ Mode",
-                            wm8915->retune_mobile_enum,
-                            wm8915_get_retune_mobile_enum,
-                            wm8915_put_retune_mobile_enum),
-               SOC_ENUM_EXT("DSP2 EQ Mode",
-                            wm8915->retune_mobile_enum,
-                            wm8915_get_retune_mobile_enum,
-                            wm8915_put_retune_mobile_enum),
-       };
-       int ret, i, j;
-       const char **t;
-
-       /* We need an array of texts for the enum API but the number
-        * of texts is likely to be less than the number of
-        * configurations due to the sample rate dependency of the
-        * configurations. */
-       wm8915->num_retune_mobile_texts = 0;
-       wm8915->retune_mobile_texts = NULL;
-       for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
-               for (j = 0; j < wm8915->num_retune_mobile_texts; j++) {
-                       if (strcmp(pdata->retune_mobile_cfgs[i].name,
-                                  wm8915->retune_mobile_texts[j]) == 0)
-                               break;
-               }
-
-               if (j != wm8915->num_retune_mobile_texts)
-                       continue;
-
-               /* Expand the array... */
-               t = krealloc(wm8915->retune_mobile_texts,
-                            sizeof(char *) * 
-                            (wm8915->num_retune_mobile_texts + 1),
-                            GFP_KERNEL);
-               if (t == NULL)
-                       continue;
-
-               /* ...store the new entry... */
-               t[wm8915->num_retune_mobile_texts] = 
-                       pdata->retune_mobile_cfgs[i].name;
-
-               /* ...and remember the new version. */
-               wm8915->num_retune_mobile_texts++;
-               wm8915->retune_mobile_texts = t;
-       }
-
-       dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n",
-               wm8915->num_retune_mobile_texts);
-
-       wm8915->retune_mobile_enum.max = wm8915->num_retune_mobile_texts;
-       wm8915->retune_mobile_enum.texts = wm8915->retune_mobile_texts;
-
-       ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls));
-       if (ret != 0)
-               dev_err(codec->dev,
-                       "Failed to add ReTune Mobile controls: %d\n", ret);
-}
-
-static int wm8915_probe(struct snd_soc_codec *codec)
-{
-       int ret;
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       struct i2c_client *i2c = to_i2c_client(codec->dev);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-       int i, irq_flags;
-
-       wm8915->codec = codec;
-
-       init_completion(&wm8915->dcs_done);
-       init_completion(&wm8915->fll_lock);
-
-       dapm->idle_bias_off = true;
-       dapm->bias_level = SND_SOC_BIAS_OFF;
-
-       ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_I2C);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(wm8915->supplies); i++)
-               wm8915->supplies[i].supply = wm8915_supply_names[i];
-
-       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8915->supplies),
-                                wm8915->supplies);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-               goto err;
-       }
-
-       wm8915->disable_nb[0].notifier_call = wm8915_regulator_event_0;
-       wm8915->disable_nb[1].notifier_call = wm8915_regulator_event_1;
-       wm8915->disable_nb[2].notifier_call = wm8915_regulator_event_2;
-       wm8915->disable_nb[3].notifier_call = wm8915_regulator_event_3;
-
-       /* This should really be moved into the regulator core */
-       for (i = 0; i < ARRAY_SIZE(wm8915->supplies); i++) {
-               ret = regulator_register_notifier(wm8915->supplies[i].consumer,
-                                                 &wm8915->disable_nb[i]);
-               if (ret != 0) {
-                       dev_err(codec->dev,
-                               "Failed to register regulator notifier: %d\n",
-                               ret);
-               }
-       }
-
-       ret = regulator_bulk_enable(ARRAY_SIZE(wm8915->supplies),
-                                   wm8915->supplies);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
-               goto err_get;
-       }
-
-       if (wm8915->pdata.ldo_ena >= 0) {
-               gpio_set_value_cansleep(wm8915->pdata.ldo_ena, 1);
-               msleep(5);
-       }
-
-       ret = snd_soc_read(codec, WM8915_SOFTWARE_RESET);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to read ID register: %d\n", ret);
-               goto err_enable;
-       }
-       if (ret != 0x8915) {
-               dev_err(codec->dev, "Device is not a WM8915, ID %x\n", ret);
-               ret = -EINVAL;
-               goto err_enable;
-       }
-
-       ret = snd_soc_read(codec, WM8915_CHIP_REVISION);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to read device revision: %d\n",
-                       ret);
-               goto err_enable;
-       }
-       
-       dev_info(codec->dev, "revision %c\n",
-                (ret & WM8915_CHIP_REV_MASK) + 'A');
-
-       if (wm8915->pdata.ldo_ena >= 0) {
-               gpio_set_value_cansleep(wm8915->pdata.ldo_ena, 0);
-       } else {
-               ret = wm8915_reset(codec);
-               if (ret < 0) {
-                       dev_err(codec->dev, "Failed to issue reset\n");
-                       goto err_enable;
-               }
-       }
-
-       codec->cache_only = true;
-
-       /* Apply platform data settings */
-       snd_soc_update_bits(codec, WM8915_LINE_INPUT_CONTROL,
-                           WM8915_INL_MODE_MASK | WM8915_INR_MODE_MASK,
-                           wm8915->pdata.inl_mode << WM8915_INL_MODE_SHIFT |
-                           wm8915->pdata.inr_mode);
-
-       for (i = 0; i < ARRAY_SIZE(wm8915->pdata.gpio_default); i++) {
-               if (!wm8915->pdata.gpio_default[i])
-                       continue;
-
-               snd_soc_write(codec, WM8915_GPIO_1 + i,
-                             wm8915->pdata.gpio_default[i] & 0xffff);
-       }
-
-       if (wm8915->pdata.spkmute_seq)
-               snd_soc_update_bits(codec, WM8915_PDM_SPEAKER_MUTE_SEQUENCE,
-                                   WM8915_SPK_MUTE_ENDIAN |
-                                   WM8915_SPK_MUTE_SEQ1_MASK,
-                                   wm8915->pdata.spkmute_seq);
-
-       snd_soc_update_bits(codec, WM8915_ACCESSORY_DETECT_MODE_2,
-                           WM8915_MICD_BIAS_SRC | WM8915_HPOUT1FB_SRC |
-                           WM8915_MICD_SRC, wm8915->pdata.micdet_def);
-
-       /* Latch volume update bits */
-       snd_soc_update_bits(codec, WM8915_LEFT_LINE_INPUT_VOLUME,
-                           WM8915_IN1_VU, WM8915_IN1_VU);
-       snd_soc_update_bits(codec, WM8915_RIGHT_LINE_INPUT_VOLUME,
-                           WM8915_IN1_VU, WM8915_IN1_VU);
-
-       snd_soc_update_bits(codec, WM8915_DAC1_LEFT_VOLUME,
-                           WM8915_DAC1_VU, WM8915_DAC1_VU);
-       snd_soc_update_bits(codec, WM8915_DAC1_RIGHT_VOLUME,
-                           WM8915_DAC1_VU, WM8915_DAC1_VU);
-       snd_soc_update_bits(codec, WM8915_DAC2_LEFT_VOLUME,
-                           WM8915_DAC2_VU, WM8915_DAC2_VU);
-       snd_soc_update_bits(codec, WM8915_DAC2_RIGHT_VOLUME,
-                           WM8915_DAC2_VU, WM8915_DAC2_VU);
-
-       snd_soc_update_bits(codec, WM8915_OUTPUT1_LEFT_VOLUME,
-                           WM8915_DAC1_VU, WM8915_DAC1_VU);
-       snd_soc_update_bits(codec, WM8915_OUTPUT1_RIGHT_VOLUME,
-                           WM8915_DAC1_VU, WM8915_DAC1_VU);
-       snd_soc_update_bits(codec, WM8915_OUTPUT2_LEFT_VOLUME,
-                           WM8915_DAC2_VU, WM8915_DAC2_VU);
-       snd_soc_update_bits(codec, WM8915_OUTPUT2_RIGHT_VOLUME,
-                           WM8915_DAC2_VU, WM8915_DAC2_VU);
-
-       snd_soc_update_bits(codec, WM8915_DSP1_TX_LEFT_VOLUME,
-                           WM8915_DSP1TX_VU, WM8915_DSP1TX_VU);
-       snd_soc_update_bits(codec, WM8915_DSP1_TX_RIGHT_VOLUME,
-                           WM8915_DSP1TX_VU, WM8915_DSP1TX_VU);
-       snd_soc_update_bits(codec, WM8915_DSP2_TX_LEFT_VOLUME,
-                           WM8915_DSP2TX_VU, WM8915_DSP2TX_VU);
-       snd_soc_update_bits(codec, WM8915_DSP2_TX_RIGHT_VOLUME,
-                           WM8915_DSP2TX_VU, WM8915_DSP2TX_VU);
-
-       snd_soc_update_bits(codec, WM8915_DSP1_RX_LEFT_VOLUME,
-                           WM8915_DSP1RX_VU, WM8915_DSP1RX_VU);
-       snd_soc_update_bits(codec, WM8915_DSP1_RX_RIGHT_VOLUME,
-                           WM8915_DSP1RX_VU, WM8915_DSP1RX_VU);
-       snd_soc_update_bits(codec, WM8915_DSP2_RX_LEFT_VOLUME,
-                           WM8915_DSP2RX_VU, WM8915_DSP2RX_VU);
-       snd_soc_update_bits(codec, WM8915_DSP2_RX_RIGHT_VOLUME,
-                           WM8915_DSP2RX_VU, WM8915_DSP2RX_VU);
-
-       /* No support currently for the underclocked TDM modes and
-        * pick a default TDM layout with each channel pair working with
-        * slots 0 and 1. */
-       snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_0_CONFIGURATION,
-                           WM8915_AIF1RX_CHAN0_SLOTS_MASK |
-                           WM8915_AIF1RX_CHAN0_START_SLOT_MASK,
-                           1 << WM8915_AIF1RX_CHAN0_SLOTS_SHIFT | 0);
-       snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_1_CONFIGURATION,
-                           WM8915_AIF1RX_CHAN1_SLOTS_MASK |
-                           WM8915_AIF1RX_CHAN1_START_SLOT_MASK,
-                           1 << WM8915_AIF1RX_CHAN1_SLOTS_SHIFT | 1);
-       snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_2_CONFIGURATION,
-                           WM8915_AIF1RX_CHAN2_SLOTS_MASK |
-                           WM8915_AIF1RX_CHAN2_START_SLOT_MASK,
-                           1 << WM8915_AIF1RX_CHAN2_SLOTS_SHIFT | 0);
-       snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_3_CONFIGURATION,
-                           WM8915_AIF1RX_CHAN3_SLOTS_MASK |
-                           WM8915_AIF1RX_CHAN0_START_SLOT_MASK,
-                           1 << WM8915_AIF1RX_CHAN3_SLOTS_SHIFT | 1);
-       snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_4_CONFIGURATION,
-                           WM8915_AIF1RX_CHAN4_SLOTS_MASK |
-                           WM8915_AIF1RX_CHAN0_START_SLOT_MASK,
-                           1 << WM8915_AIF1RX_CHAN4_SLOTS_SHIFT | 0);
-       snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_5_CONFIGURATION,
-                           WM8915_AIF1RX_CHAN5_SLOTS_MASK |
-                           WM8915_AIF1RX_CHAN0_START_SLOT_MASK,
-                           1 << WM8915_AIF1RX_CHAN5_SLOTS_SHIFT | 1);
-
-       snd_soc_update_bits(codec, WM8915_AIF2RX_CHANNEL_0_CONFIGURATION,
-                           WM8915_AIF2RX_CHAN0_SLOTS_MASK |
-                           WM8915_AIF2RX_CHAN0_START_SLOT_MASK,
-                           1 << WM8915_AIF2RX_CHAN0_SLOTS_SHIFT | 0);
-       snd_soc_update_bits(codec, WM8915_AIF2RX_CHANNEL_1_CONFIGURATION,
-                           WM8915_AIF2RX_CHAN1_SLOTS_MASK |
-                           WM8915_AIF2RX_CHAN1_START_SLOT_MASK,
-                           1 << WM8915_AIF2RX_CHAN1_SLOTS_SHIFT | 1);
-
-       snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_0_CONFIGURATION,
-                           WM8915_AIF1TX_CHAN0_SLOTS_MASK |
-                           WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
-                           1 << WM8915_AIF1TX_CHAN0_SLOTS_SHIFT | 0);
-       snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_1_CONFIGURATION,
-                           WM8915_AIF1TX_CHAN1_SLOTS_MASK |
-                           WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
-                           1 << WM8915_AIF1TX_CHAN1_SLOTS_SHIFT | 1);
-       snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_2_CONFIGURATION,
-                           WM8915_AIF1TX_CHAN2_SLOTS_MASK |
-                           WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
-                           1 << WM8915_AIF1TX_CHAN2_SLOTS_SHIFT | 0);
-       snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_3_CONFIGURATION,
-                           WM8915_AIF1TX_CHAN3_SLOTS_MASK |
-                           WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
-                           1 << WM8915_AIF1TX_CHAN3_SLOTS_SHIFT | 1);
-       snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_4_CONFIGURATION,
-                           WM8915_AIF1TX_CHAN4_SLOTS_MASK |
-                           WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
-                           1 << WM8915_AIF1TX_CHAN4_SLOTS_SHIFT | 0);
-       snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_5_CONFIGURATION,
-                           WM8915_AIF1TX_CHAN5_SLOTS_MASK |
-                           WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
-                           1 << WM8915_AIF1TX_CHAN5_SLOTS_SHIFT | 1);
-
-       snd_soc_update_bits(codec, WM8915_AIF2TX_CHANNEL_0_CONFIGURATION,
-                           WM8915_AIF2TX_CHAN0_SLOTS_MASK |
-                           WM8915_AIF2TX_CHAN0_START_SLOT_MASK,
-                           1 << WM8915_AIF2TX_CHAN0_SLOTS_SHIFT | 0);
-       snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_1_CONFIGURATION,
-                           WM8915_AIF2TX_CHAN1_SLOTS_MASK |
-                           WM8915_AIF2TX_CHAN1_START_SLOT_MASK,
-                           1 << WM8915_AIF1TX_CHAN1_SLOTS_SHIFT | 1);
-
-       if (wm8915->pdata.num_retune_mobile_cfgs)
-               wm8915_retune_mobile_pdata(codec);
-       else
-               snd_soc_add_controls(codec, wm8915_eq_controls,
-                                    ARRAY_SIZE(wm8915_eq_controls));
-
-       /* If the TX LRCLK pins are not in LRCLK mode configure the
-        * AIFs to source their clocks from the RX LRCLKs.
-        */
-       if ((snd_soc_read(codec, WM8915_GPIO_1)))
-               snd_soc_update_bits(codec, WM8915_AIF1_TX_LRCLK_2,
-                                   WM8915_AIF1TX_LRCLK_MODE,
-                                   WM8915_AIF1TX_LRCLK_MODE);
-
-       if ((snd_soc_read(codec, WM8915_GPIO_2)))
-               snd_soc_update_bits(codec, WM8915_AIF2_TX_LRCLK_2,
-                                   WM8915_AIF2TX_LRCLK_MODE,
-                                   WM8915_AIF2TX_LRCLK_MODE);
-
-       regulator_bulk_disable(ARRAY_SIZE(wm8915->supplies), wm8915->supplies);
-
-       wm8915_init_gpio(codec);
-
-       if (i2c->irq) {
-               if (wm8915->pdata.irq_flags)
-                       irq_flags = wm8915->pdata.irq_flags;
-               else
-                       irq_flags = IRQF_TRIGGER_LOW;
-
-               irq_flags |= IRQF_ONESHOT;
-
-               if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
-                       ret = request_threaded_irq(i2c->irq, NULL,
-                                                  wm8915_edge_irq,
-                                                  irq_flags, "wm8915", codec);
-               else
-                       ret = request_threaded_irq(i2c->irq, NULL, wm8915_irq,
-                                                  irq_flags, "wm8915", codec);
-
-               if (ret == 0) {
-                       /* Unmask the interrupt */
-                       snd_soc_update_bits(codec, WM8915_INTERRUPT_CONTROL,
-                                           WM8915_IM_IRQ, 0);
-
-                       /* Enable error reporting and DC servo status */
-                       snd_soc_update_bits(codec,
-                                           WM8915_INTERRUPT_STATUS_2_MASK,
-                                           WM8915_IM_DCS_DONE_23_EINT |
-                                           WM8915_IM_DCS_DONE_01_EINT |
-                                           WM8915_IM_FLL_LOCK_EINT |
-                                           WM8915_IM_FIFOS_ERR_EINT,
-                                           0);
-               } else {
-                       dev_err(codec->dev, "Failed to request IRQ: %d\n",
-                               ret);
-               }
-       }
-
-       return 0;
-
-err_enable:
-       if (wm8915->pdata.ldo_ena >= 0)
-               gpio_set_value_cansleep(wm8915->pdata.ldo_ena, 0);
-
-       regulator_bulk_disable(ARRAY_SIZE(wm8915->supplies), wm8915->supplies);
-err_get:
-       regulator_bulk_free(ARRAY_SIZE(wm8915->supplies), wm8915->supplies);
-err:
-       return ret;
-}
-
-static int wm8915_remove(struct snd_soc_codec *codec)
-{
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       struct i2c_client *i2c = to_i2c_client(codec->dev);
-       int i;
-
-       snd_soc_update_bits(codec, WM8915_INTERRUPT_CONTROL,
-                           WM8915_IM_IRQ, WM8915_IM_IRQ);
-
-       if (i2c->irq)
-               free_irq(i2c->irq, codec);
-
-       wm8915_free_gpio(codec);
-
-       for (i = 0; i < ARRAY_SIZE(wm8915->supplies); i++)
-               regulator_unregister_notifier(wm8915->supplies[i].consumer,
-                                             &wm8915->disable_nb[i]);
-       regulator_bulk_free(ARRAY_SIZE(wm8915->supplies), wm8915->supplies);
-
-       return 0;
-}
-
-static struct snd_soc_codec_driver soc_codec_dev_wm8915 = {
-       .probe =        wm8915_probe,
-       .remove =       wm8915_remove,
-       .set_bias_level = wm8915_set_bias_level,
-       .seq_notifier = wm8915_seq_notifier,
-       .reg_cache_size = WM8915_MAX_REGISTER + 1,
-       .reg_word_size = sizeof(u16),
-       .reg_cache_default = wm8915_reg,
-       .volatile_register = wm8915_volatile_register,
-       .readable_register = wm8915_readable_register,
-       .compress_type = SND_SOC_RBTREE_COMPRESSION,
-       .controls = wm8915_snd_controls,
-       .num_controls = ARRAY_SIZE(wm8915_snd_controls),
-       .dapm_widgets = wm8915_dapm_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(wm8915_dapm_widgets),
-       .dapm_routes = wm8915_dapm_routes,
-       .num_dapm_routes = ARRAY_SIZE(wm8915_dapm_routes),
-       .set_pll = wm8915_set_fll,
-};
-
-#define WM8915_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
-                     SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
-#define WM8915_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
-                       SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE |\
-                       SNDRV_PCM_FMTBIT_S32_LE)
-
-static struct snd_soc_dai_ops wm8915_dai_ops = {
-       .set_fmt = wm8915_set_fmt,
-       .hw_params = wm8915_hw_params,
-       .set_sysclk = wm8915_set_sysclk,
-};
-
-static struct snd_soc_dai_driver wm8915_dai[] = {
-       {
-               .name = "wm8915-aif1",
-               .playback = {
-                       .stream_name = "AIF1 Playback",
-                       .channels_min = 1,
-                       .channels_max = 6,
-                       .rates = WM8915_RATES,
-                       .formats = WM8915_FORMATS,
-               },
-               .capture = {
-                        .stream_name = "AIF1 Capture",
-                        .channels_min = 1,
-                        .channels_max = 6,
-                        .rates = WM8915_RATES,
-                        .formats = WM8915_FORMATS,
-                },
-               .ops = &wm8915_dai_ops,
-       },
-       {
-               .name = "wm8915-aif2",
-               .playback = {
-                       .stream_name = "AIF2 Playback",
-                       .channels_min = 1,
-                       .channels_max = 2,
-                       .rates = WM8915_RATES,
-                       .formats = WM8915_FORMATS,
-               },
-               .capture = {
-                        .stream_name = "AIF2 Capture",
-                        .channels_min = 1,
-                        .channels_max = 2,
-                        .rates = WM8915_RATES,
-                        .formats = WM8915_FORMATS,
-                },
-               .ops = &wm8915_dai_ops,
-       },
-};
-
-static __devinit int wm8915_i2c_probe(struct i2c_client *i2c,
-                                     const struct i2c_device_id *id)
-{
-       struct wm8915_priv *wm8915;
-       int ret;
-
-       wm8915 = kzalloc(sizeof(struct wm8915_priv), GFP_KERNEL);
-       if (wm8915 == NULL)
-               return -ENOMEM;
-
-       i2c_set_clientdata(i2c, wm8915);
-
-       if (dev_get_platdata(&i2c->dev))
-               memcpy(&wm8915->pdata, dev_get_platdata(&i2c->dev),
-                      sizeof(wm8915->pdata));
-
-       if (wm8915->pdata.ldo_ena > 0) {
-               ret = gpio_request_one(wm8915->pdata.ldo_ena,
-                                      GPIOF_OUT_INIT_LOW, "WM8915 ENA");
-               if (ret < 0) {
-                       dev_err(&i2c->dev, "Failed to request GPIO %d: %d\n",
-                               wm8915->pdata.ldo_ena, ret);
-                       goto err;
-               }
-       }
-
-       ret = snd_soc_register_codec(&i2c->dev,
-                                    &soc_codec_dev_wm8915, wm8915_dai,
-                                    ARRAY_SIZE(wm8915_dai));
-       if (ret < 0)
-               goto err_gpio;
-
-       return ret;
-
-err_gpio:
-       if (wm8915->pdata.ldo_ena > 0)
-               gpio_free(wm8915->pdata.ldo_ena);
-err:
-       kfree(wm8915);
-
-       return ret;
-}
-
-static __devexit int wm8915_i2c_remove(struct i2c_client *client)
-{
-       struct wm8915_priv *wm8915 = i2c_get_clientdata(client);
-
-       snd_soc_unregister_codec(&client->dev);
-       if (wm8915->pdata.ldo_ena > 0)
-               gpio_free(wm8915->pdata.ldo_ena);
-       kfree(i2c_get_clientdata(client));
-       return 0;
-}
-
-static const struct i2c_device_id wm8915_i2c_id[] = {
-       { "wm8915", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, wm8915_i2c_id);
-
-static struct i2c_driver wm8915_i2c_driver = {
-       .driver = {
-               .name = "wm8915",
-               .owner = THIS_MODULE,
-       },
-       .probe =    wm8915_i2c_probe,
-       .remove =   __devexit_p(wm8915_i2c_remove),
-       .id_table = wm8915_i2c_id,
-};
-
-static int __init wm8915_modinit(void)
-{
-       int ret;
-
-       ret = i2c_add_driver(&wm8915_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register WM8915 I2C driver: %d\n",
-                      ret);
-       }
-
-       return ret;
-}
-module_init(wm8915_modinit);
-
-static void __exit wm8915_exit(void)
-{
-       i2c_del_driver(&wm8915_i2c_driver);
-}
-module_exit(wm8915_exit);
-
-MODULE_DESCRIPTION("ASoC WM8915 driver");
-MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8915.h b/sound/soc/codecs/wm8915.h
deleted file mode 100644 (file)
index 200ffd7..0000000
+++ /dev/null
@@ -1,3717 +0,0 @@
-/*
- * wm8915.h - WM8915 audio codec interface
- *
- * Copyright 2011 Wolfson Microelectronics PLC.
- * Author: Mark Brown <broonie@opensource.wolfsonmicro.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.
- */
-
-#ifndef _WM8915_H
-#define _WM8915_H
-
-#define WM8915_SYSCLK_MCLK1 1
-#define WM8915_SYSCLK_MCLK2 2
-#define WM8915_SYSCLK_FLL   3
-
-#define WM8915_FLL_MCLK1      1
-#define WM8915_FLL_MCLK2      2
-#define WM8915_FLL_DACLRCLK1  3
-#define WM8915_FLL_BCLK1      4
-
-typedef void (*wm8915_polarity_fn)(struct snd_soc_codec *codec, int polarity);
-
-int wm8915_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
-                 wm8915_polarity_fn polarity_cb);
-
-/*
- * Register values.
- */
-#define WM8915_SOFTWARE_RESET                   0x00
-#define WM8915_POWER_MANAGEMENT_1               0x01
-#define WM8915_POWER_MANAGEMENT_2               0x02
-#define WM8915_POWER_MANAGEMENT_3               0x03
-#define WM8915_POWER_MANAGEMENT_4               0x04
-#define WM8915_POWER_MANAGEMENT_5               0x05
-#define WM8915_POWER_MANAGEMENT_6               0x06
-#define WM8915_POWER_MANAGEMENT_7               0x07
-#define WM8915_POWER_MANAGEMENT_8               0x08
-#define WM8915_LEFT_LINE_INPUT_VOLUME           0x10
-#define WM8915_RIGHT_LINE_INPUT_VOLUME          0x11
-#define WM8915_LINE_INPUT_CONTROL               0x12
-#define WM8915_DAC1_HPOUT1_VOLUME               0x15
-#define WM8915_DAC2_HPOUT2_VOLUME               0x16
-#define WM8915_DAC1_LEFT_VOLUME                 0x18
-#define WM8915_DAC1_RIGHT_VOLUME                0x19
-#define WM8915_DAC2_LEFT_VOLUME                 0x1A
-#define WM8915_DAC2_RIGHT_VOLUME                0x1B
-#define WM8915_OUTPUT1_LEFT_VOLUME              0x1C
-#define WM8915_OUTPUT1_RIGHT_VOLUME             0x1D
-#define WM8915_OUTPUT2_LEFT_VOLUME              0x1E
-#define WM8915_OUTPUT2_RIGHT_VOLUME             0x1F
-#define WM8915_MICBIAS_1                        0x20
-#define WM8915_MICBIAS_2                        0x21
-#define WM8915_LDO_1                            0x28
-#define WM8915_LDO_2                            0x29
-#define WM8915_ACCESSORY_DETECT_MODE_1          0x30
-#define WM8915_ACCESSORY_DETECT_MODE_2          0x31
-#define WM8915_HEADPHONE_DETECT_1               0x34
-#define WM8915_HEADPHONE_DETECT_2               0x35
-#define WM8915_MIC_DETECT_1                     0x38
-#define WM8915_MIC_DETECT_2                     0x39
-#define WM8915_MIC_DETECT_3                     0x3A
-#define WM8915_CHARGE_PUMP_1                    0x40
-#define WM8915_CHARGE_PUMP_2                    0x41
-#define WM8915_DC_SERVO_1                       0x50
-#define WM8915_DC_SERVO_2                       0x51
-#define WM8915_DC_SERVO_3                       0x52
-#define WM8915_DC_SERVO_5                       0x54
-#define WM8915_DC_SERVO_6                       0x55
-#define WM8915_DC_SERVO_7                       0x56
-#define WM8915_DC_SERVO_READBACK_0              0x57
-#define WM8915_ANALOGUE_HP_1                    0x60
-#define WM8915_ANALOGUE_HP_2                    0x61
-#define WM8915_CHIP_REVISION                    0x100
-#define WM8915_CONTROL_INTERFACE_1              0x101
-#define WM8915_WRITE_SEQUENCER_CTRL_1           0x110
-#define WM8915_WRITE_SEQUENCER_CTRL_2           0x111
-#define WM8915_AIF_CLOCKING_1                   0x200
-#define WM8915_AIF_CLOCKING_2                   0x201
-#define WM8915_CLOCKING_1                       0x208
-#define WM8915_CLOCKING_2                       0x209
-#define WM8915_AIF_RATE                         0x210
-#define WM8915_FLL_CONTROL_1                    0x220
-#define WM8915_FLL_CONTROL_2                    0x221
-#define WM8915_FLL_CONTROL_3                    0x222
-#define WM8915_FLL_CONTROL_4                    0x223
-#define WM8915_FLL_CONTROL_5                    0x224
-#define WM8915_FLL_CONTROL_6                    0x225
-#define WM8915_FLL_EFS_1                        0x226
-#define WM8915_FLL_EFS_2                        0x227
-#define WM8915_AIF1_CONTROL                     0x300
-#define WM8915_AIF1_BCLK                        0x301
-#define WM8915_AIF1_TX_LRCLK_1                  0x302
-#define WM8915_AIF1_TX_LRCLK_2                  0x303
-#define WM8915_AIF1_RX_LRCLK_1                  0x304
-#define WM8915_AIF1_RX_LRCLK_2                  0x305
-#define WM8915_AIF1TX_DATA_CONFIGURATION_1      0x306
-#define WM8915_AIF1TX_DATA_CONFIGURATION_2      0x307
-#define WM8915_AIF1RX_DATA_CONFIGURATION        0x308
-#define WM8915_AIF1TX_CHANNEL_0_CONFIGURATION   0x309
-#define WM8915_AIF1TX_CHANNEL_1_CONFIGURATION   0x30A
-#define WM8915_AIF1TX_CHANNEL_2_CONFIGURATION   0x30B
-#define WM8915_AIF1TX_CHANNEL_3_CONFIGURATION   0x30C
-#define WM8915_AIF1TX_CHANNEL_4_CONFIGURATION   0x30D
-#define WM8915_AIF1TX_CHANNEL_5_CONFIGURATION   0x30E
-#define WM8915_AIF1RX_CHANNEL_0_CONFIGURATION   0x30F
-#define WM8915_AIF1RX_CHANNEL_1_CONFIGURATION   0x310
-#define WM8915_AIF1RX_CHANNEL_2_CONFIGURATION   0x311
-#define WM8915_AIF1RX_CHANNEL_3_CONFIGURATION   0x312
-#define WM8915_AIF1RX_CHANNEL_4_CONFIGURATION   0x313
-#define WM8915_AIF1RX_CHANNEL_5_CONFIGURATION   0x314
-#define WM8915_AIF1RX_MONO_CONFIGURATION        0x315
-#define WM8915_AIF1TX_TEST                      0x31A
-#define WM8915_AIF2_CONTROL                     0x320
-#define WM8915_AIF2_BCLK                        0x321
-#define WM8915_AIF2_TX_LRCLK_1                  0x322
-#define WM8915_AIF2_TX_LRCLK_2                  0x323
-#define WM8915_AIF2_RX_LRCLK_1                  0x324
-#define WM8915_AIF2_RX_LRCLK_2                  0x325
-#define WM8915_AIF2TX_DATA_CONFIGURATION_1      0x326
-#define WM8915_AIF2TX_DATA_CONFIGURATION_2      0x327
-#define WM8915_AIF2RX_DATA_CONFIGURATION        0x328
-#define WM8915_AIF2TX_CHANNEL_0_CONFIGURATION   0x329
-#define WM8915_AIF2TX_CHANNEL_1_CONFIGURATION   0x32A
-#define WM8915_AIF2RX_CHANNEL_0_CONFIGURATION   0x32B
-#define WM8915_AIF2RX_CHANNEL_1_CONFIGURATION   0x32C
-#define WM8915_AIF2RX_MONO_CONFIGURATION        0x32D
-#define WM8915_AIF2TX_TEST                      0x32F
-#define WM8915_DSP1_TX_LEFT_VOLUME              0x400
-#define WM8915_DSP1_TX_RIGHT_VOLUME             0x401
-#define WM8915_DSP1_RX_LEFT_VOLUME              0x402
-#define WM8915_DSP1_RX_RIGHT_VOLUME             0x403
-#define WM8915_DSP1_TX_FILTERS                  0x410
-#define WM8915_DSP1_RX_FILTERS_1                0x420
-#define WM8915_DSP1_RX_FILTERS_2                0x421
-#define WM8915_DSP1_DRC_1                       0x440
-#define WM8915_DSP1_DRC_2                       0x441
-#define WM8915_DSP1_DRC_3                       0x442
-#define WM8915_DSP1_DRC_4                       0x443
-#define WM8915_DSP1_DRC_5                       0x444
-#define WM8915_DSP1_RX_EQ_GAINS_1               0x480
-#define WM8915_DSP1_RX_EQ_GAINS_2               0x481
-#define WM8915_DSP1_RX_EQ_BAND_1_A              0x482
-#define WM8915_DSP1_RX_EQ_BAND_1_B              0x483
-#define WM8915_DSP1_RX_EQ_BAND_1_PG             0x484
-#define WM8915_DSP1_RX_EQ_BAND_2_A              0x485
-#define WM8915_DSP1_RX_EQ_BAND_2_B              0x486
-#define WM8915_DSP1_RX_EQ_BAND_2_C              0x487
-#define WM8915_DSP1_RX_EQ_BAND_2_PG             0x488
-#define WM8915_DSP1_RX_EQ_BAND_3_A              0x489
-#define WM8915_DSP1_RX_EQ_BAND_3_B              0x48A
-#define WM8915_DSP1_RX_EQ_BAND_3_C              0x48B
-#define WM8915_DSP1_RX_EQ_BAND_3_PG             0x48C
-#define WM8915_DSP1_RX_EQ_BAND_4_A              0x48D
-#define WM8915_DSP1_RX_EQ_BAND_4_B              0x48E
-#define WM8915_DSP1_RX_EQ_BAND_4_C              0x48F
-#define WM8915_DSP1_RX_EQ_BAND_4_PG             0x490
-#define WM8915_DSP1_RX_EQ_BAND_5_A              0x491
-#define WM8915_DSP1_RX_EQ_BAND_5_B              0x492
-#define WM8915_DSP1_RX_EQ_BAND_5_PG             0x493
-#define WM8915_DSP2_TX_LEFT_VOLUME              0x500
-#define WM8915_DSP2_TX_RIGHT_VOLUME             0x501
-#define WM8915_DSP2_RX_LEFT_VOLUME              0x502
-#define WM8915_DSP2_RX_RIGHT_VOLUME             0x503
-#define WM8915_DSP2_TX_FILTERS                  0x510
-#define WM8915_DSP2_RX_FILTERS_1                0x520
-#define WM8915_DSP2_RX_FILTERS_2                0x521
-#define WM8915_DSP2_DRC_1                       0x540
-#define WM8915_DSP2_DRC_2                       0x541
-#define WM8915_DSP2_DRC_3                       0x542
-#define WM8915_DSP2_DRC_4                       0x543
-#define WM8915_DSP2_DRC_5                       0x544
-#define WM8915_DSP2_RX_EQ_GAINS_1               0x580
-#define WM8915_DSP2_RX_EQ_GAINS_2               0x581
-#define WM8915_DSP2_RX_EQ_BAND_1_A              0x582
-#define WM8915_DSP2_RX_EQ_BAND_1_B              0x583
-#define WM8915_DSP2_RX_EQ_BAND_1_PG             0x584
-#define WM8915_DSP2_RX_EQ_BAND_2_A              0x585
-#define WM8915_DSP2_RX_EQ_BAND_2_B              0x586
-#define WM8915_DSP2_RX_EQ_BAND_2_C              0x587
-#define WM8915_DSP2_RX_EQ_BAND_2_PG             0x588
-#define WM8915_DSP2_RX_EQ_BAND_3_A              0x589
-#define WM8915_DSP2_RX_EQ_BAND_3_B              0x58A
-#define WM8915_DSP2_RX_EQ_BAND_3_C              0x58B
-#define WM8915_DSP2_RX_EQ_BAND_3_PG             0x58C
-#define WM8915_DSP2_RX_EQ_BAND_4_A              0x58D
-#define WM8915_DSP2_RX_EQ_BAND_4_B              0x58E
-#define WM8915_DSP2_RX_EQ_BAND_4_C              0x58F
-#define WM8915_DSP2_RX_EQ_BAND_4_PG             0x590
-#define WM8915_DSP2_RX_EQ_BAND_5_A              0x591
-#define WM8915_DSP2_RX_EQ_BAND_5_B              0x592
-#define WM8915_DSP2_RX_EQ_BAND_5_PG             0x593
-#define WM8915_DAC1_MIXER_VOLUMES               0x600
-#define WM8915_DAC1_LEFT_MIXER_ROUTING          0x601
-#define WM8915_DAC1_RIGHT_MIXER_ROUTING         0x602
-#define WM8915_DAC2_MIXER_VOLUMES               0x603
-#define WM8915_DAC2_LEFT_MIXER_ROUTING          0x604
-#define WM8915_DAC2_RIGHT_MIXER_ROUTING         0x605
-#define WM8915_DSP1_TX_LEFT_MIXER_ROUTING       0x606
-#define WM8915_DSP1_TX_RIGHT_MIXER_ROUTING      0x607
-#define WM8915_DSP2_TX_LEFT_MIXER_ROUTING       0x608
-#define WM8915_DSP2_TX_RIGHT_MIXER_ROUTING      0x609
-#define WM8915_DSP_TX_MIXER_SELECT              0x60A
-#define WM8915_DAC_SOFTMUTE                     0x610
-#define WM8915_OVERSAMPLING                     0x620
-#define WM8915_SIDETONE                         0x621
-#define WM8915_GPIO_1                           0x700
-#define WM8915_GPIO_2                           0x701
-#define WM8915_GPIO_3                           0x702
-#define WM8915_GPIO_4                           0x703
-#define WM8915_GPIO_5                           0x704
-#define WM8915_PULL_CONTROL_1                   0x720
-#define WM8915_PULL_CONTROL_2                   0x721
-#define WM8915_INTERRUPT_STATUS_1               0x730
-#define WM8915_INTERRUPT_STATUS_2               0x731
-#define WM8915_INTERRUPT_RAW_STATUS_2           0x732
-#define WM8915_INTERRUPT_STATUS_1_MASK          0x738
-#define WM8915_INTERRUPT_STATUS_2_MASK          0x739
-#define WM8915_INTERRUPT_CONTROL                0x740
-#define WM8915_LEFT_PDM_SPEAKER                 0x800
-#define WM8915_RIGHT_PDM_SPEAKER                0x801
-#define WM8915_PDM_SPEAKER_MUTE_SEQUENCE        0x802
-#define WM8915_PDM_SPEAKER_VOLUME               0x803
-#define WM8915_WRITE_SEQUENCER_0                0x3000
-#define WM8915_WRITE_SEQUENCER_1                0x3001
-#define WM8915_WRITE_SEQUENCER_2                0x3002
-#define WM8915_WRITE_SEQUENCER_3                0x3003
-#define WM8915_WRITE_SEQUENCER_4                0x3004
-#define WM8915_WRITE_SEQUENCER_5                0x3005
-#define WM8915_WRITE_SEQUENCER_6                0x3006
-#define WM8915_WRITE_SEQUENCER_7                0x3007
-#define WM8915_WRITE_SEQUENCER_8                0x3008
-#define WM8915_WRITE_SEQUENCER_9                0x3009
-#define WM8915_WRITE_SEQUENCER_10               0x300A
-#define WM8915_WRITE_SEQUENCER_11               0x300B
-#define WM8915_WRITE_SEQUENCER_12               0x300C
-#define WM8915_WRITE_SEQUENCER_13               0x300D
-#define WM8915_WRITE_SEQUENCER_14               0x300E
-#define WM8915_WRITE_SEQUENCER_15               0x300F
-#define WM8915_WRITE_SEQUENCER_16               0x3010
-#define WM8915_WRITE_SEQUENCER_17               0x3011
-#define WM8915_WRITE_SEQUENCER_18               0x3012
-#define WM8915_WRITE_SEQUENCER_19               0x3013
-#define WM8915_WRITE_SEQUENCER_20               0x3014
-#define WM8915_WRITE_SEQUENCER_21               0x3015
-#define WM8915_WRITE_SEQUENCER_22               0x3016
-#define WM8915_WRITE_SEQUENCER_23               0x3017
-#define WM8915_WRITE_SEQUENCER_24               0x3018
-#define WM8915_WRITE_SEQUENCER_25               0x3019
-#define WM8915_WRITE_SEQUENCER_26               0x301A
-#define WM8915_WRITE_SEQUENCER_27               0x301B
-#define WM8915_WRITE_SEQUENCER_28               0x301C
-#define WM8915_WRITE_SEQUENCER_29               0x301D
-#define WM8915_WRITE_SEQUENCER_30               0x301E
-#define WM8915_WRITE_SEQUENCER_31               0x301F
-#define WM8915_WRITE_SEQUENCER_32               0x3020
-#define WM8915_WRITE_SEQUENCER_33               0x3021
-#define WM8915_WRITE_SEQUENCER_34               0x3022
-#define WM8915_WRITE_SEQUENCER_35               0x3023
-#define WM8915_WRITE_SEQUENCER_36               0x3024
-#define WM8915_WRITE_SEQUENCER_37               0x3025
-#define WM8915_WRITE_SEQUENCER_38               0x3026
-#define WM8915_WRITE_SEQUENCER_39               0x3027
-#define WM8915_WRITE_SEQUENCER_40               0x3028
-#define WM8915_WRITE_SEQUENCER_41               0x3029
-#define WM8915_WRITE_SEQUENCER_42               0x302A
-#define WM8915_WRITE_SEQUENCER_43               0x302B
-#define WM8915_WRITE_SEQUENCER_44               0x302C
-#define WM8915_WRITE_SEQUENCER_45               0x302D
-#define WM8915_WRITE_SEQUENCER_46               0x302E
-#define WM8915_WRITE_SEQUENCER_47               0x302F
-#define WM8915_WRITE_SEQUENCER_48               0x3030
-#define WM8915_WRITE_SEQUENCER_49               0x3031
-#define WM8915_WRITE_SEQUENCER_50               0x3032
-#define WM8915_WRITE_SEQUENCER_51               0x3033
-#define WM8915_WRITE_SEQUENCER_52               0x3034
-#define WM8915_WRITE_SEQUENCER_53               0x3035
-#define WM8915_WRITE_SEQUENCER_54               0x3036
-#define WM8915_WRITE_SEQUENCER_55               0x3037
-#define WM8915_WRITE_SEQUENCER_56               0x3038
-#define WM8915_WRITE_SEQUENCER_57               0x3039
-#define WM8915_WRITE_SEQUENCER_58               0x303A
-#define WM8915_WRITE_SEQUENCER_59               0x303B
-#define WM8915_WRITE_SEQUENCER_60               0x303C
-#define WM8915_WRITE_SEQUENCER_61               0x303D
-#define WM8915_WRITE_SEQUENCER_62               0x303E
-#define WM8915_WRITE_SEQUENCER_63               0x303F
-#define WM8915_WRITE_SEQUENCER_64               0x3040
-#define WM8915_WRITE_SEQUENCER_65               0x3041
-#define WM8915_WRITE_SEQUENCER_66               0x3042
-#define WM8915_WRITE_SEQUENCER_67               0x3043
-#define WM8915_WRITE_SEQUENCER_68               0x3044
-#define WM8915_WRITE_SEQUENCER_69               0x3045
-#define WM8915_WRITE_SEQUENCER_70               0x3046
-#define WM8915_WRITE_SEQUENCER_71               0x3047
-#define WM8915_WRITE_SEQUENCER_72               0x3048
-#define WM8915_WRITE_SEQUENCER_73               0x3049
-#define WM8915_WRITE_SEQUENCER_74               0x304A
-#define WM8915_WRITE_SEQUENCER_75               0x304B
-#define WM8915_WRITE_SEQUENCER_76               0x304C
-#define WM8915_WRITE_SEQUENCER_77               0x304D
-#define WM8915_WRITE_SEQUENCER_78               0x304E
-#define WM8915_WRITE_SEQUENCER_79               0x304F
-#define WM8915_WRITE_SEQUENCER_80               0x3050
-#define WM8915_WRITE_SEQUENCER_81               0x3051
-#define WM8915_WRITE_SEQUENCER_82               0x3052
-#define WM8915_WRITE_SEQUENCER_83               0x3053
-#define WM8915_WRITE_SEQUENCER_84               0x3054
-#define WM8915_WRITE_SEQUENCER_85               0x3055
-#define WM8915_WRITE_SEQUENCER_86               0x3056
-#define WM8915_WRITE_SEQUENCER_87               0x3057
-#define WM8915_WRITE_SEQUENCER_88               0x3058
-#define WM8915_WRITE_SEQUENCER_89               0x3059
-#define WM8915_WRITE_SEQUENCER_90               0x305A
-#define WM8915_WRITE_SEQUENCER_91               0x305B
-#define WM8915_WRITE_SEQUENCER_92               0x305C
-#define WM8915_WRITE_SEQUENCER_93               0x305D
-#define WM8915_WRITE_SEQUENCER_94               0x305E
-#define WM8915_WRITE_SEQUENCER_95               0x305F
-#define WM8915_WRITE_SEQUENCER_96               0x3060
-#define WM8915_WRITE_SEQUENCER_97               0x3061
-#define WM8915_WRITE_SEQUENCER_98               0x3062
-#define WM8915_WRITE_SEQUENCER_99               0x3063
-#define WM8915_WRITE_SEQUENCER_100              0x3064
-#define WM8915_WRITE_SEQUENCER_101              0x3065
-#define WM8915_WRITE_SEQUENCER_102              0x3066
-#define WM8915_WRITE_SEQUENCER_103              0x3067
-#define WM8915_WRITE_SEQUENCER_104              0x3068
-#define WM8915_WRITE_SEQUENCER_105              0x3069
-#define WM8915_WRITE_SEQUENCER_106              0x306A
-#define WM8915_WRITE_SEQUENCER_107              0x306B
-#define WM8915_WRITE_SEQUENCER_108              0x306C
-#define WM8915_WRITE_SEQUENCER_109              0x306D
-#define WM8915_WRITE_SEQUENCER_110              0x306E
-#define WM8915_WRITE_SEQUENCER_111              0x306F
-#define WM8915_WRITE_SEQUENCER_112              0x3070
-#define WM8915_WRITE_SEQUENCER_113              0x3071
-#define WM8915_WRITE_SEQUENCER_114              0x3072
-#define WM8915_WRITE_SEQUENCER_115              0x3073
-#define WM8915_WRITE_SEQUENCER_116              0x3074
-#define WM8915_WRITE_SEQUENCER_117              0x3075
-#define WM8915_WRITE_SEQUENCER_118              0x3076
-#define WM8915_WRITE_SEQUENCER_119              0x3077
-#define WM8915_WRITE_SEQUENCER_120              0x3078
-#define WM8915_WRITE_SEQUENCER_121              0x3079
-#define WM8915_WRITE_SEQUENCER_122              0x307A
-#define WM8915_WRITE_SEQUENCER_123              0x307B
-#define WM8915_WRITE_SEQUENCER_124              0x307C
-#define WM8915_WRITE_SEQUENCER_125              0x307D
-#define WM8915_WRITE_SEQUENCER_126              0x307E
-#define WM8915_WRITE_SEQUENCER_127              0x307F
-#define WM8915_WRITE_SEQUENCER_128              0x3080
-#define WM8915_WRITE_SEQUENCER_129              0x3081
-#define WM8915_WRITE_SEQUENCER_130              0x3082
-#define WM8915_WRITE_SEQUENCER_131              0x3083
-#define WM8915_WRITE_SEQUENCER_132              0x3084
-#define WM8915_WRITE_SEQUENCER_133              0x3085
-#define WM8915_WRITE_SEQUENCER_134              0x3086
-#define WM8915_WRITE_SEQUENCER_135              0x3087
-#define WM8915_WRITE_SEQUENCER_136              0x3088
-#define WM8915_WRITE_SEQUENCER_137              0x3089
-#define WM8915_WRITE_SEQUENCER_138              0x308A
-#define WM8915_WRITE_SEQUENCER_139              0x308B
-#define WM8915_WRITE_SEQUENCER_140              0x308C
-#define WM8915_WRITE_SEQUENCER_141              0x308D
-#define WM8915_WRITE_SEQUENCER_142              0x308E
-#define WM8915_WRITE_SEQUENCER_143              0x308F
-#define WM8915_WRITE_SEQUENCER_144              0x3090
-#define WM8915_WRITE_SEQUENCER_145              0x3091
-#define WM8915_WRITE_SEQUENCER_146              0x3092
-#define WM8915_WRITE_SEQUENCER_147              0x3093
-#define WM8915_WRITE_SEQUENCER_148              0x3094
-#define WM8915_WRITE_SEQUENCER_149              0x3095
-#define WM8915_WRITE_SEQUENCER_150              0x3096
-#define WM8915_WRITE_SEQUENCER_151              0x3097
-#define WM8915_WRITE_SEQUENCER_152              0x3098
-#define WM8915_WRITE_SEQUENCER_153              0x3099
-#define WM8915_WRITE_SEQUENCER_154              0x309A
-#define WM8915_WRITE_SEQUENCER_155              0x309B
-#define WM8915_WRITE_SEQUENCER_156              0x309C
-#define WM8915_WRITE_SEQUENCER_157              0x309D
-#define WM8915_WRITE_SEQUENCER_158              0x309E
-#define WM8915_WRITE_SEQUENCER_159              0x309F
-#define WM8915_WRITE_SEQUENCER_160              0x30A0
-#define WM8915_WRITE_SEQUENCER_161              0x30A1
-#define WM8915_WRITE_SEQUENCER_162              0x30A2
-#define WM8915_WRITE_SEQUENCER_163              0x30A3
-#define WM8915_WRITE_SEQUENCER_164              0x30A4
-#define WM8915_WRITE_SEQUENCER_165              0x30A5
-#define WM8915_WRITE_SEQUENCER_166              0x30A6
-#define WM8915_WRITE_SEQUENCER_167              0x30A7
-#define WM8915_WRITE_SEQUENCER_168              0x30A8
-#define WM8915_WRITE_SEQUENCER_169              0x30A9
-#define WM8915_WRITE_SEQUENCER_170              0x30AA
-#define WM8915_WRITE_SEQUENCER_171              0x30AB
-#define WM8915_WRITE_SEQUENCER_172              0x30AC
-#define WM8915_WRITE_SEQUENCER_173              0x30AD
-#define WM8915_WRITE_SEQUENCER_174              0x30AE
-#define WM8915_WRITE_SEQUENCER_175              0x30AF
-#define WM8915_WRITE_SEQUENCER_176              0x30B0
-#define WM8915_WRITE_SEQUENCER_177              0x30B1
-#define WM8915_WRITE_SEQUENCER_178              0x30B2
-#define WM8915_WRITE_SEQUENCER_179              0x30B3
-#define WM8915_WRITE_SEQUENCER_180              0x30B4
-#define WM8915_WRITE_SEQUENCER_181              0x30B5
-#define WM8915_WRITE_SEQUENCER_182              0x30B6
-#define WM8915_WRITE_SEQUENCER_183              0x30B7
-#define WM8915_WRITE_SEQUENCER_184              0x30B8
-#define WM8915_WRITE_SEQUENCER_185              0x30B9
-#define WM8915_WRITE_SEQUENCER_186              0x30BA
-#define WM8915_WRITE_SEQUENCER_187              0x30BB
-#define WM8915_WRITE_SEQUENCER_188              0x30BC
-#define WM8915_WRITE_SEQUENCER_189              0x30BD
-#define WM8915_WRITE_SEQUENCER_190              0x30BE
-#define WM8915_WRITE_SEQUENCER_191              0x30BF
-#define WM8915_WRITE_SEQUENCER_192              0x30C0
-#define WM8915_WRITE_SEQUENCER_193              0x30C1
-#define WM8915_WRITE_SEQUENCER_194              0x30C2
-#define WM8915_WRITE_SEQUENCER_195              0x30C3
-#define WM8915_WRITE_SEQUENCER_196              0x30C4
-#define WM8915_WRITE_SEQUENCER_197              0x30C5
-#define WM8915_WRITE_SEQUENCER_198              0x30C6
-#define WM8915_WRITE_SEQUENCER_199              0x30C7
-#define WM8915_WRITE_SEQUENCER_200              0x30C8
-#define WM8915_WRITE_SEQUENCER_201              0x30C9
-#define WM8915_WRITE_SEQUENCER_202              0x30CA
-#define WM8915_WRITE_SEQUENCER_203              0x30CB
-#define WM8915_WRITE_SEQUENCER_204              0x30CC
-#define WM8915_WRITE_SEQUENCER_205              0x30CD
-#define WM8915_WRITE_SEQUENCER_206              0x30CE
-#define WM8915_WRITE_SEQUENCER_207              0x30CF
-#define WM8915_WRITE_SEQUENCER_208              0x30D0
-#define WM8915_WRITE_SEQUENCER_209              0x30D1
-#define WM8915_WRITE_SEQUENCER_210              0x30D2
-#define WM8915_WRITE_SEQUENCER_211              0x30D3
-#define WM8915_WRITE_SEQUENCER_212              0x30D4
-#define WM8915_WRITE_SEQUENCER_213              0x30D5
-#define WM8915_WRITE_SEQUENCER_214              0x30D6
-#define WM8915_WRITE_SEQUENCER_215              0x30D7
-#define WM8915_WRITE_SEQUENCER_216              0x30D8
-#define WM8915_WRITE_SEQUENCER_217              0x30D9
-#define WM8915_WRITE_SEQUENCER_218              0x30DA
-#define WM8915_WRITE_SEQUENCER_219              0x30DB
-#define WM8915_WRITE_SEQUENCER_220              0x30DC
-#define WM8915_WRITE_SEQUENCER_221              0x30DD
-#define WM8915_WRITE_SEQUENCER_222              0x30DE
-#define WM8915_WRITE_SEQUENCER_223              0x30DF
-#define WM8915_WRITE_SEQUENCER_224              0x30E0
-#define WM8915_WRITE_SEQUENCER_225              0x30E1
-#define WM8915_WRITE_SEQUENCER_226              0x30E2
-#define WM8915_WRITE_SEQUENCER_227              0x30E3
-#define WM8915_WRITE_SEQUENCER_228              0x30E4
-#define WM8915_WRITE_SEQUENCER_229              0x30E5
-#define WM8915_WRITE_SEQUENCER_230              0x30E6
-#define WM8915_WRITE_SEQUENCER_231              0x30E7
-#define WM8915_WRITE_SEQUENCER_232              0x30E8
-#define WM8915_WRITE_SEQUENCER_233              0x30E9
-#define WM8915_WRITE_SEQUENCER_234              0x30EA
-#define WM8915_WRITE_SEQUENCER_235              0x30EB
-#define WM8915_WRITE_SEQUENCER_236              0x30EC
-#define WM8915_WRITE_SEQUENCER_237              0x30ED
-#define WM8915_WRITE_SEQUENCER_238              0x30EE
-#define WM8915_WRITE_SEQUENCER_239              0x30EF
-#define WM8915_WRITE_SEQUENCER_240              0x30F0
-#define WM8915_WRITE_SEQUENCER_241              0x30F1
-#define WM8915_WRITE_SEQUENCER_242              0x30F2
-#define WM8915_WRITE_SEQUENCER_243              0x30F3
-#define WM8915_WRITE_SEQUENCER_244              0x30F4
-#define WM8915_WRITE_SEQUENCER_245              0x30F5
-#define WM8915_WRITE_SEQUENCER_246              0x30F6
-#define WM8915_WRITE_SEQUENCER_247              0x30F7
-#define WM8915_WRITE_SEQUENCER_248              0x30F8
-#define WM8915_WRITE_SEQUENCER_249              0x30F9
-#define WM8915_WRITE_SEQUENCER_250              0x30FA
-#define WM8915_WRITE_SEQUENCER_251              0x30FB
-#define WM8915_WRITE_SEQUENCER_252              0x30FC
-#define WM8915_WRITE_SEQUENCER_253              0x30FD
-#define WM8915_WRITE_SEQUENCER_254              0x30FE
-#define WM8915_WRITE_SEQUENCER_255              0x30FF
-#define WM8915_WRITE_SEQUENCER_256              0x3100
-#define WM8915_WRITE_SEQUENCER_257              0x3101
-#define WM8915_WRITE_SEQUENCER_258              0x3102
-#define WM8915_WRITE_SEQUENCER_259              0x3103
-#define WM8915_WRITE_SEQUENCER_260              0x3104
-#define WM8915_WRITE_SEQUENCER_261              0x3105
-#define WM8915_WRITE_SEQUENCER_262              0x3106
-#define WM8915_WRITE_SEQUENCER_263              0x3107
-#define WM8915_WRITE_SEQUENCER_264              0x3108
-#define WM8915_WRITE_SEQUENCER_265              0x3109
-#define WM8915_WRITE_SEQUENCER_266              0x310A
-#define WM8915_WRITE_SEQUENCER_267              0x310B
-#define WM8915_WRITE_SEQUENCER_268              0x310C
-#define WM8915_WRITE_SEQUENCER_269              0x310D
-#define WM8915_WRITE_SEQUENCER_270              0x310E
-#define WM8915_WRITE_SEQUENCER_271              0x310F
-#define WM8915_WRITE_SEQUENCER_272              0x3110
-#define WM8915_WRITE_SEQUENCER_273              0x3111
-#define WM8915_WRITE_SEQUENCER_274              0x3112
-#define WM8915_WRITE_SEQUENCER_275              0x3113
-#define WM8915_WRITE_SEQUENCER_276              0x3114
-#define WM8915_WRITE_SEQUENCER_277              0x3115
-#define WM8915_WRITE_SEQUENCER_278              0x3116
-#define WM8915_WRITE_SEQUENCER_279              0x3117
-#define WM8915_WRITE_SEQUENCER_280              0x3118
-#define WM8915_WRITE_SEQUENCER_281              0x3119
-#define WM8915_WRITE_SEQUENCER_282              0x311A
-#define WM8915_WRITE_SEQUENCER_283              0x311B
-#define WM8915_WRITE_SEQUENCER_284              0x311C
-#define WM8915_WRITE_SEQUENCER_285              0x311D
-#define WM8915_WRITE_SEQUENCER_286              0x311E
-#define WM8915_WRITE_SEQUENCER_287              0x311F
-#define WM8915_WRITE_SEQUENCER_288              0x3120
-#define WM8915_WRITE_SEQUENCER_289              0x3121
-#define WM8915_WRITE_SEQUENCER_290              0x3122
-#define WM8915_WRITE_SEQUENCER_291              0x3123
-#define WM8915_WRITE_SEQUENCER_292              0x3124
-#define WM8915_WRITE_SEQUENCER_293              0x3125
-#define WM8915_WRITE_SEQUENCER_294              0x3126
-#define WM8915_WRITE_SEQUENCER_295              0x3127
-#define WM8915_WRITE_SEQUENCER_296              0x3128
-#define WM8915_WRITE_SEQUENCER_297              0x3129
-#define WM8915_WRITE_SEQUENCER_298              0x312A
-#define WM8915_WRITE_SEQUENCER_299              0x312B
-#define WM8915_WRITE_SEQUENCER_300              0x312C
-#define WM8915_WRITE_SEQUENCER_301              0x312D
-#define WM8915_WRITE_SEQUENCER_302              0x312E
-#define WM8915_WRITE_SEQUENCER_303              0x312F
-#define WM8915_WRITE_SEQUENCER_304              0x3130
-#define WM8915_WRITE_SEQUENCER_305              0x3131
-#define WM8915_WRITE_SEQUENCER_306              0x3132
-#define WM8915_WRITE_SEQUENCER_307              0x3133
-#define WM8915_WRITE_SEQUENCER_308              0x3134
-#define WM8915_WRITE_SEQUENCER_309              0x3135
-#define WM8915_WRITE_SEQUENCER_310              0x3136
-#define WM8915_WRITE_SEQUENCER_311              0x3137
-#define WM8915_WRITE_SEQUENCER_312              0x3138
-#define WM8915_WRITE_SEQUENCER_313              0x3139
-#define WM8915_WRITE_SEQUENCER_314              0x313A
-#define WM8915_WRITE_SEQUENCER_315              0x313B
-#define WM8915_WRITE_SEQUENCER_316              0x313C
-#define WM8915_WRITE_SEQUENCER_317              0x313D
-#define WM8915_WRITE_SEQUENCER_318              0x313E
-#define WM8915_WRITE_SEQUENCER_319              0x313F
-#define WM8915_WRITE_SEQUENCER_320              0x3140
-#define WM8915_WRITE_SEQUENCER_321              0x3141
-#define WM8915_WRITE_SEQUENCER_322              0x3142
-#define WM8915_WRITE_SEQUENCER_323              0x3143
-#define WM8915_WRITE_SEQUENCER_324              0x3144
-#define WM8915_WRITE_SEQUENCER_325              0x3145
-#define WM8915_WRITE_SEQUENCER_326              0x3146
-#define WM8915_WRITE_SEQUENCER_327              0x3147
-#define WM8915_WRITE_SEQUENCER_328              0x3148
-#define WM8915_WRITE_SEQUENCER_329              0x3149
-#define WM8915_WRITE_SEQUENCER_330              0x314A
-#define WM8915_WRITE_SEQUENCER_331              0x314B
-#define WM8915_WRITE_SEQUENCER_332              0x314C
-#define WM8915_WRITE_SEQUENCER_333              0x314D
-#define WM8915_WRITE_SEQUENCER_334              0x314E
-#define WM8915_WRITE_SEQUENCER_335              0x314F
-#define WM8915_WRITE_SEQUENCER_336              0x3150
-#define WM8915_WRITE_SEQUENCER_337              0x3151
-#define WM8915_WRITE_SEQUENCER_338              0x3152
-#define WM8915_WRITE_SEQUENCER_339              0x3153
-#define WM8915_WRITE_SEQUENCER_340              0x3154
-#define WM8915_WRITE_SEQUENCER_341              0x3155
-#define WM8915_WRITE_SEQUENCER_342              0x3156
-#define WM8915_WRITE_SEQUENCER_343              0x3157
-#define WM8915_WRITE_SEQUENCER_344              0x3158
-#define WM8915_WRITE_SEQUENCER_345              0x3159
-#define WM8915_WRITE_SEQUENCER_346              0x315A
-#define WM8915_WRITE_SEQUENCER_347              0x315B
-#define WM8915_WRITE_SEQUENCER_348              0x315C
-#define WM8915_WRITE_SEQUENCER_349              0x315D
-#define WM8915_WRITE_SEQUENCER_350              0x315E
-#define WM8915_WRITE_SEQUENCER_351              0x315F
-#define WM8915_WRITE_SEQUENCER_352              0x3160
-#define WM8915_WRITE_SEQUENCER_353              0x3161
-#define WM8915_WRITE_SEQUENCER_354              0x3162
-#define WM8915_WRITE_SEQUENCER_355              0x3163
-#define WM8915_WRITE_SEQUENCER_356              0x3164
-#define WM8915_WRITE_SEQUENCER_357              0x3165
-#define WM8915_WRITE_SEQUENCER_358              0x3166
-#define WM8915_WRITE_SEQUENCER_359              0x3167
-#define WM8915_WRITE_SEQUENCER_360              0x3168
-#define WM8915_WRITE_SEQUENCER_361              0x3169
-#define WM8915_WRITE_SEQUENCER_362              0x316A
-#define WM8915_WRITE_SEQUENCER_363              0x316B
-#define WM8915_WRITE_SEQUENCER_364              0x316C
-#define WM8915_WRITE_SEQUENCER_365              0x316D
-#define WM8915_WRITE_SEQUENCER_366              0x316E
-#define WM8915_WRITE_SEQUENCER_367              0x316F
-#define WM8915_WRITE_SEQUENCER_368              0x3170
-#define WM8915_WRITE_SEQUENCER_369              0x3171
-#define WM8915_WRITE_SEQUENCER_370              0x3172
-#define WM8915_WRITE_SEQUENCER_371              0x3173
-#define WM8915_WRITE_SEQUENCER_372              0x3174
-#define WM8915_WRITE_SEQUENCER_373              0x3175
-#define WM8915_WRITE_SEQUENCER_374              0x3176
-#define WM8915_WRITE_SEQUENCER_375              0x3177
-#define WM8915_WRITE_SEQUENCER_376              0x3178
-#define WM8915_WRITE_SEQUENCER_377              0x3179
-#define WM8915_WRITE_SEQUENCER_378              0x317A
-#define WM8915_WRITE_SEQUENCER_379              0x317B
-#define WM8915_WRITE_SEQUENCER_380              0x317C
-#define WM8915_WRITE_SEQUENCER_381              0x317D
-#define WM8915_WRITE_SEQUENCER_382              0x317E
-#define WM8915_WRITE_SEQUENCER_383              0x317F
-#define WM8915_WRITE_SEQUENCER_384              0x3180
-#define WM8915_WRITE_SEQUENCER_385              0x3181
-#define WM8915_WRITE_SEQUENCER_386              0x3182
-#define WM8915_WRITE_SEQUENCER_387              0x3183
-#define WM8915_WRITE_SEQUENCER_388              0x3184
-#define WM8915_WRITE_SEQUENCER_389              0x3185
-#define WM8915_WRITE_SEQUENCER_390              0x3186
-#define WM8915_WRITE_SEQUENCER_391              0x3187
-#define WM8915_WRITE_SEQUENCER_392              0x3188
-#define WM8915_WRITE_SEQUENCER_393              0x3189
-#define WM8915_WRITE_SEQUENCER_394              0x318A
-#define WM8915_WRITE_SEQUENCER_395              0x318B
-#define WM8915_WRITE_SEQUENCER_396              0x318C
-#define WM8915_WRITE_SEQUENCER_397              0x318D
-#define WM8915_WRITE_SEQUENCER_398              0x318E
-#define WM8915_WRITE_SEQUENCER_399              0x318F
-#define WM8915_WRITE_SEQUENCER_400              0x3190
-#define WM8915_WRITE_SEQUENCER_401              0x3191
-#define WM8915_WRITE_SEQUENCER_402              0x3192
-#define WM8915_WRITE_SEQUENCER_403              0x3193
-#define WM8915_WRITE_SEQUENCER_404              0x3194
-#define WM8915_WRITE_SEQUENCER_405              0x3195
-#define WM8915_WRITE_SEQUENCER_406              0x3196
-#define WM8915_WRITE_SEQUENCER_407              0x3197
-#define WM8915_WRITE_SEQUENCER_408              0x3198
-#define WM8915_WRITE_SEQUENCER_409              0x3199
-#define WM8915_WRITE_SEQUENCER_410              0x319A
-#define WM8915_WRITE_SEQUENCER_411              0x319B
-#define WM8915_WRITE_SEQUENCER_412              0x319C
-#define WM8915_WRITE_SEQUENCER_413              0x319D
-#define WM8915_WRITE_SEQUENCER_414              0x319E
-#define WM8915_WRITE_SEQUENCER_415              0x319F
-#define WM8915_WRITE_SEQUENCER_416              0x31A0
-#define WM8915_WRITE_SEQUENCER_417              0x31A1
-#define WM8915_WRITE_SEQUENCER_418              0x31A2
-#define WM8915_WRITE_SEQUENCER_419              0x31A3
-#define WM8915_WRITE_SEQUENCER_420              0x31A4
-#define WM8915_WRITE_SEQUENCER_421              0x31A5
-#define WM8915_WRITE_SEQUENCER_422              0x31A6
-#define WM8915_WRITE_SEQUENCER_423              0x31A7
-#define WM8915_WRITE_SEQUENCER_424              0x31A8
-#define WM8915_WRITE_SEQUENCER_425              0x31A9
-#define WM8915_WRITE_SEQUENCER_426              0x31AA
-#define WM8915_WRITE_SEQUENCER_427              0x31AB
-#define WM8915_WRITE_SEQUENCER_428              0x31AC
-#define WM8915_WRITE_SEQUENCER_429              0x31AD
-#define WM8915_WRITE_SEQUENCER_430              0x31AE
-#define WM8915_WRITE_SEQUENCER_431              0x31AF
-#define WM8915_WRITE_SEQUENCER_432              0x31B0
-#define WM8915_WRITE_SEQUENCER_433              0x31B1
-#define WM8915_WRITE_SEQUENCER_434              0x31B2
-#define WM8915_WRITE_SEQUENCER_435              0x31B3
-#define WM8915_WRITE_SEQUENCER_436              0x31B4
-#define WM8915_WRITE_SEQUENCER_437              0x31B5
-#define WM8915_WRITE_SEQUENCER_438              0x31B6
-#define WM8915_WRITE_SEQUENCER_439              0x31B7
-#define WM8915_WRITE_SEQUENCER_440              0x31B8
-#define WM8915_WRITE_SEQUENCER_441              0x31B9
-#define WM8915_WRITE_SEQUENCER_442              0x31BA
-#define WM8915_WRITE_SEQUENCER_443              0x31BB
-#define WM8915_WRITE_SEQUENCER_444              0x31BC
-#define WM8915_WRITE_SEQUENCER_445              0x31BD
-#define WM8915_WRITE_SEQUENCER_446              0x31BE
-#define WM8915_WRITE_SEQUENCER_447              0x31BF
-#define WM8915_WRITE_SEQUENCER_448              0x31C0
-#define WM8915_WRITE_SEQUENCER_449              0x31C1
-#define WM8915_WRITE_SEQUENCER_450              0x31C2
-#define WM8915_WRITE_SEQUENCER_451              0x31C3
-#define WM8915_WRITE_SEQUENCER_452              0x31C4
-#define WM8915_WRITE_SEQUENCER_453              0x31C5
-#define WM8915_WRITE_SEQUENCER_454              0x31C6
-#define WM8915_WRITE_SEQUENCER_455              0x31C7
-#define WM8915_WRITE_SEQUENCER_456              0x31C8
-#define WM8915_WRITE_SEQUENCER_457              0x31C9
-#define WM8915_WRITE_SEQUENCER_458              0x31CA
-#define WM8915_WRITE_SEQUENCER_459              0x31CB
-#define WM8915_WRITE_SEQUENCER_460              0x31CC
-#define WM8915_WRITE_SEQUENCER_461              0x31CD
-#define WM8915_WRITE_SEQUENCER_462              0x31CE
-#define WM8915_WRITE_SEQUENCER_463              0x31CF
-#define WM8915_WRITE_SEQUENCER_464              0x31D0
-#define WM8915_WRITE_SEQUENCER_465              0x31D1
-#define WM8915_WRITE_SEQUENCER_466              0x31D2
-#define WM8915_WRITE_SEQUENCER_467              0x31D3
-#define WM8915_WRITE_SEQUENCER_468              0x31D4
-#define WM8915_WRITE_SEQUENCER_469              0x31D5
-#define WM8915_WRITE_SEQUENCER_470              0x31D6
-#define WM8915_WRITE_SEQUENCER_471              0x31D7
-#define WM8915_WRITE_SEQUENCER_472              0x31D8
-#define WM8915_WRITE_SEQUENCER_473              0x31D9
-#define WM8915_WRITE_SEQUENCER_474              0x31DA
-#define WM8915_WRITE_SEQUENCER_475              0x31DB
-#define WM8915_WRITE_SEQUENCER_476              0x31DC
-#define WM8915_WRITE_SEQUENCER_477              0x31DD
-#define WM8915_WRITE_SEQUENCER_478              0x31DE
-#define WM8915_WRITE_SEQUENCER_479              0x31DF
-#define WM8915_WRITE_SEQUENCER_480              0x31E0
-#define WM8915_WRITE_SEQUENCER_481              0x31E1
-#define WM8915_WRITE_SEQUENCER_482              0x31E2
-#define WM8915_WRITE_SEQUENCER_483              0x31E3
-#define WM8915_WRITE_SEQUENCER_484              0x31E4
-#define WM8915_WRITE_SEQUENCER_485              0x31E5
-#define WM8915_WRITE_SEQUENCER_486              0x31E6
-#define WM8915_WRITE_SEQUENCER_487              0x31E7
-#define WM8915_WRITE_SEQUENCER_488              0x31E8
-#define WM8915_WRITE_SEQUENCER_489              0x31E9
-#define WM8915_WRITE_SEQUENCER_490              0x31EA
-#define WM8915_WRITE_SEQUENCER_491              0x31EB
-#define WM8915_WRITE_SEQUENCER_492              0x31EC
-#define WM8915_WRITE_SEQUENCER_493              0x31ED
-#define WM8915_WRITE_SEQUENCER_494              0x31EE
-#define WM8915_WRITE_SEQUENCER_495              0x31EF
-#define WM8915_WRITE_SEQUENCER_496              0x31F0
-#define WM8915_WRITE_SEQUENCER_497              0x31F1
-#define WM8915_WRITE_SEQUENCER_498              0x31F2
-#define WM8915_WRITE_SEQUENCER_499              0x31F3
-#define WM8915_WRITE_SEQUENCER_500              0x31F4
-#define WM8915_WRITE_SEQUENCER_501              0x31F5
-#define WM8915_WRITE_SEQUENCER_502              0x31F6
-#define WM8915_WRITE_SEQUENCER_503              0x31F7
-#define WM8915_WRITE_SEQUENCER_504              0x31F8
-#define WM8915_WRITE_SEQUENCER_505              0x31F9
-#define WM8915_WRITE_SEQUENCER_506              0x31FA
-#define WM8915_WRITE_SEQUENCER_507              0x31FB
-#define WM8915_WRITE_SEQUENCER_508              0x31FC
-#define WM8915_WRITE_SEQUENCER_509              0x31FD
-#define WM8915_WRITE_SEQUENCER_510              0x31FE
-#define WM8915_WRITE_SEQUENCER_511              0x31FF
-
-#define WM8915_REGISTER_COUNT                   706
-#define WM8915_MAX_REGISTER                     0x31FF
-
-/*
- * Field Definitions.
- */
-
-/*
- * R0 (0x00) - Software Reset
- */
-#define WM8915_SW_RESET_MASK                    0xFFFF  /* SW_RESET - [15:0] */
-#define WM8915_SW_RESET_SHIFT                        0  /* SW_RESET - [15:0] */
-#define WM8915_SW_RESET_WIDTH                       16  /* SW_RESET - [15:0] */
-
-/*
- * R1 (0x01) - Power Management (1)
- */
-#define WM8915_MICB2_ENA                        0x0200  /* MICB2_ENA */
-#define WM8915_MICB2_ENA_MASK                   0x0200  /* MICB2_ENA */
-#define WM8915_MICB2_ENA_SHIFT                       9  /* MICB2_ENA */
-#define WM8915_MICB2_ENA_WIDTH                       1  /* MICB2_ENA */
-#define WM8915_MICB1_ENA                        0x0100  /* MICB1_ENA */
-#define WM8915_MICB1_ENA_MASK                   0x0100  /* MICB1_ENA */
-#define WM8915_MICB1_ENA_SHIFT                       8  /* MICB1_ENA */
-#define WM8915_MICB1_ENA_WIDTH                       1  /* MICB1_ENA */
-#define WM8915_HPOUT2L_ENA                      0x0080  /* HPOUT2L_ENA */
-#define WM8915_HPOUT2L_ENA_MASK                 0x0080  /* HPOUT2L_ENA */
-#define WM8915_HPOUT2L_ENA_SHIFT                     7  /* HPOUT2L_ENA */
-#define WM8915_HPOUT2L_ENA_WIDTH                     1  /* HPOUT2L_ENA */
-#define WM8915_HPOUT2R_ENA                      0x0040  /* HPOUT2R_ENA */
-#define WM8915_HPOUT2R_ENA_MASK                 0x0040  /* HPOUT2R_ENA */
-#define WM8915_HPOUT2R_ENA_SHIFT                     6  /* HPOUT2R_ENA */
-#define WM8915_HPOUT2R_ENA_WIDTH                     1  /* HPOUT2R_ENA */
-#define WM8915_HPOUT1L_ENA                      0x0020  /* HPOUT1L_ENA */
-#define WM8915_HPOUT1L_ENA_MASK                 0x0020  /* HPOUT1L_ENA */
-#define WM8915_HPOUT1L_ENA_SHIFT                     5  /* HPOUT1L_ENA */
-#define WM8915_HPOUT1L_ENA_WIDTH                     1  /* HPOUT1L_ENA */
-#define WM8915_HPOUT1R_ENA                      0x0010  /* HPOUT1R_ENA */
-#define WM8915_HPOUT1R_ENA_MASK                 0x0010  /* HPOUT1R_ENA */
-#define WM8915_HPOUT1R_ENA_SHIFT                     4  /* HPOUT1R_ENA */
-#define WM8915_HPOUT1R_ENA_WIDTH                     1  /* HPOUT1R_ENA */
-#define WM8915_BG_ENA                           0x0001  /* BG_ENA */
-#define WM8915_BG_ENA_MASK                      0x0001  /* BG_ENA */
-#define WM8915_BG_ENA_SHIFT                          0  /* BG_ENA */
-#define WM8915_BG_ENA_WIDTH                          1  /* BG_ENA */
-
-/*
- * R2 (0x02) - Power Management (2)
- */
-#define WM8915_OPCLK_ENA                        0x0800  /* OPCLK_ENA */
-#define WM8915_OPCLK_ENA_MASK                   0x0800  /* OPCLK_ENA */
-#define WM8915_OPCLK_ENA_SHIFT                      11  /* OPCLK_ENA */
-#define WM8915_OPCLK_ENA_WIDTH                       1  /* OPCLK_ENA */
-#define WM8915_INL_ENA                          0x0020  /* INL_ENA */
-#define WM8915_INL_ENA_MASK                     0x0020  /* INL_ENA */
-#define WM8915_INL_ENA_SHIFT                         5  /* INL_ENA */
-#define WM8915_INL_ENA_WIDTH                         1  /* INL_ENA */
-#define WM8915_INR_ENA                          0x0010  /* INR_ENA */
-#define WM8915_INR_ENA_MASK                     0x0010  /* INR_ENA */
-#define WM8915_INR_ENA_SHIFT                         4  /* INR_ENA */
-#define WM8915_INR_ENA_WIDTH                         1  /* INR_ENA */
-#define WM8915_LDO2_ENA                         0x0002  /* LDO2_ENA */
-#define WM8915_LDO2_ENA_MASK                    0x0002  /* LDO2_ENA */
-#define WM8915_LDO2_ENA_SHIFT                        1  /* LDO2_ENA */
-#define WM8915_LDO2_ENA_WIDTH                        1  /* LDO2_ENA */
-
-/*
- * R3 (0x03) - Power Management (3)
- */
-#define WM8915_DSP2RXL_ENA                      0x0800  /* DSP2RXL_ENA */
-#define WM8915_DSP2RXL_ENA_MASK                 0x0800  /* DSP2RXL_ENA */
-#define WM8915_DSP2RXL_ENA_SHIFT                    11  /* DSP2RXL_ENA */
-#define WM8915_DSP2RXL_ENA_WIDTH                     1  /* DSP2RXL_ENA */
-#define WM8915_DSP2RXR_ENA                      0x0400  /* DSP2RXR_ENA */
-#define WM8915_DSP2RXR_ENA_MASK                 0x0400  /* DSP2RXR_ENA */
-#define WM8915_DSP2RXR_ENA_SHIFT                    10  /* DSP2RXR_ENA */
-#define WM8915_DSP2RXR_ENA_WIDTH                     1  /* DSP2RXR_ENA */
-#define WM8915_DSP1RXL_ENA                      0x0200  /* DSP1RXL_ENA */
-#define WM8915_DSP1RXL_ENA_MASK                 0x0200  /* DSP1RXL_ENA */
-#define WM8915_DSP1RXL_ENA_SHIFT                     9  /* DSP1RXL_ENA */
-#define WM8915_DSP1RXL_ENA_WIDTH                     1  /* DSP1RXL_ENA */
-#define WM8915_DSP1RXR_ENA                      0x0100  /* DSP1RXR_ENA */
-#define WM8915_DSP1RXR_ENA_MASK                 0x0100  /* DSP1RXR_ENA */
-#define WM8915_DSP1RXR_ENA_SHIFT                     8  /* DSP1RXR_ENA */
-#define WM8915_DSP1RXR_ENA_WIDTH                     1  /* DSP1RXR_ENA */
-#define WM8915_DMIC2L_ENA                       0x0020  /* DMIC2L_ENA */
-#define WM8915_DMIC2L_ENA_MASK                  0x0020  /* DMIC2L_ENA */
-#define WM8915_DMIC2L_ENA_SHIFT                      5  /* DMIC2L_ENA */
-#define WM8915_DMIC2L_ENA_WIDTH                      1  /* DMIC2L_ENA */
-#define WM8915_DMIC2R_ENA                       0x0010  /* DMIC2R_ENA */
-#define WM8915_DMIC2R_ENA_MASK                  0x0010  /* DMIC2R_ENA */
-#define WM8915_DMIC2R_ENA_SHIFT                      4  /* DMIC2R_ENA */
-#define WM8915_DMIC2R_ENA_WIDTH                      1  /* DMIC2R_ENA */
-#define WM8915_DMIC1L_ENA                       0x0008  /* DMIC1L_ENA */
-#define WM8915_DMIC1L_ENA_MASK                  0x0008  /* DMIC1L_ENA */
-#define WM8915_DMIC1L_ENA_SHIFT                      3  /* DMIC1L_ENA */
-#define WM8915_DMIC1L_ENA_WIDTH                      1  /* DMIC1L_ENA */
-#define WM8915_DMIC1R_ENA                       0x0004  /* DMIC1R_ENA */
-#define WM8915_DMIC1R_ENA_MASK                  0x0004  /* DMIC1R_ENA */
-#define WM8915_DMIC1R_ENA_SHIFT                      2  /* DMIC1R_ENA */
-#define WM8915_DMIC1R_ENA_WIDTH                      1  /* DMIC1R_ENA */
-#define WM8915_ADCL_ENA                         0x0002  /* ADCL_ENA */
-#define WM8915_ADCL_ENA_MASK                    0x0002  /* ADCL_ENA */
-#define WM8915_ADCL_ENA_SHIFT                        1  /* ADCL_ENA */
-#define WM8915_ADCL_ENA_WIDTH                        1  /* ADCL_ENA */
-#define WM8915_ADCR_ENA                         0x0001  /* ADCR_ENA */
-#define WM8915_ADCR_ENA_MASK                    0x0001  /* ADCR_ENA */
-#define WM8915_ADCR_ENA_SHIFT                        0  /* ADCR_ENA */
-#define WM8915_ADCR_ENA_WIDTH                        1  /* ADCR_ENA */
-
-/*
- * R4 (0x04) - Power Management (4)
- */
-#define WM8915_AIF2RX_CHAN1_ENA                 0x0200  /* AIF2RX_CHAN1_ENA */
-#define WM8915_AIF2RX_CHAN1_ENA_MASK            0x0200  /* AIF2RX_CHAN1_ENA */
-#define WM8915_AIF2RX_CHAN1_ENA_SHIFT                9  /* AIF2RX_CHAN1_ENA */
-#define WM8915_AIF2RX_CHAN1_ENA_WIDTH                1  /* AIF2RX_CHAN1_ENA */
-#define WM8915_AIF2RX_CHAN0_ENA                 0x0100  /* AIF2RX_CHAN0_ENA */
-#define WM8915_AIF2RX_CHAN0_ENA_MASK            0x0100  /* AIF2RX_CHAN0_ENA */
-#define WM8915_AIF2RX_CHAN0_ENA_SHIFT                8  /* AIF2RX_CHAN0_ENA */
-#define WM8915_AIF2RX_CHAN0_ENA_WIDTH                1  /* AIF2RX_CHAN0_ENA */
-#define WM8915_AIF1RX_CHAN5_ENA                 0x0020  /* AIF1RX_CHAN5_ENA */
-#define WM8915_AIF1RX_CHAN5_ENA_MASK            0x0020  /* AIF1RX_CHAN5_ENA */
-#define WM8915_AIF1RX_CHAN5_ENA_SHIFT                5  /* AIF1RX_CHAN5_ENA */
-#define WM8915_AIF1RX_CHAN5_ENA_WIDTH                1  /* AIF1RX_CHAN5_ENA */
-#define WM8915_AIF1RX_CHAN4_ENA                 0x0010  /* AIF1RX_CHAN4_ENA */
-#define WM8915_AIF1RX_CHAN4_ENA_MASK            0x0010  /* AIF1RX_CHAN4_ENA */
-#define WM8915_AIF1RX_CHAN4_ENA_SHIFT                4  /* AIF1RX_CHAN4_ENA */
-#define WM8915_AIF1RX_CHAN4_ENA_WIDTH                1  /* AIF1RX_CHAN4_ENA */
-#define WM8915_AIF1RX_CHAN3_ENA                 0x0008  /* AIF1RX_CHAN3_ENA */
-#define WM8915_AIF1RX_CHAN3_ENA_MASK            0x0008  /* AIF1RX_CHAN3_ENA */
-#define WM8915_AIF1RX_CHAN3_ENA_SHIFT                3  /* AIF1RX_CHAN3_ENA */
-#define WM8915_AIF1RX_CHAN3_ENA_WIDTH                1  /* AIF1RX_CHAN3_ENA */
-#define WM8915_AIF1RX_CHAN2_ENA                 0x0004  /* AIF1RX_CHAN2_ENA */
-#define WM8915_AIF1RX_CHAN2_ENA_MASK            0x0004  /* AIF1RX_CHAN2_ENA */
-#define WM8915_AIF1RX_CHAN2_ENA_SHIFT                2  /* AIF1RX_CHAN2_ENA */
-#define WM8915_AIF1RX_CHAN2_ENA_WIDTH                1  /* AIF1RX_CHAN2_ENA */
-#define WM8915_AIF1RX_CHAN1_ENA                 0x0002  /* AIF1RX_CHAN1_ENA */
-#define WM8915_AIF1RX_CHAN1_ENA_MASK            0x0002  /* AIF1RX_CHAN1_ENA */
-#define WM8915_AIF1RX_CHAN1_ENA_SHIFT                1  /* AIF1RX_CHAN1_ENA */
-#define WM8915_AIF1RX_CHAN1_ENA_WIDTH                1  /* AIF1RX_CHAN1_ENA */
-#define WM8915_AIF1RX_CHAN0_ENA                 0x0001  /* AIF1RX_CHAN0_ENA */
-#define WM8915_AIF1RX_CHAN0_ENA_MASK            0x0001  /* AIF1RX_CHAN0_ENA */
-#define WM8915_AIF1RX_CHAN0_ENA_SHIFT                0  /* AIF1RX_CHAN0_ENA */
-#define WM8915_AIF1RX_CHAN0_ENA_WIDTH                1  /* AIF1RX_CHAN0_ENA */
-
-/*
- * R5 (0x05) - Power Management (5)
- */
-#define WM8915_DSP2TXL_ENA                      0x0800  /* DSP2TXL_ENA */
-#define WM8915_DSP2TXL_ENA_MASK                 0x0800  /* DSP2TXL_ENA */
-#define WM8915_DSP2TXL_ENA_SHIFT                    11  /* DSP2TXL_ENA */
-#define WM8915_DSP2TXL_ENA_WIDTH                     1  /* DSP2TXL_ENA */
-#define WM8915_DSP2TXR_ENA                      0x0400  /* DSP2TXR_ENA */
-#define WM8915_DSP2TXR_ENA_MASK                 0x0400  /* DSP2TXR_ENA */
-#define WM8915_DSP2TXR_ENA_SHIFT                    10  /* DSP2TXR_ENA */
-#define WM8915_DSP2TXR_ENA_WIDTH                     1  /* DSP2TXR_ENA */
-#define WM8915_DSP1TXL_ENA                      0x0200  /* DSP1TXL_ENA */
-#define WM8915_DSP1TXL_ENA_MASK                 0x0200  /* DSP1TXL_ENA */
-#define WM8915_DSP1TXL_ENA_SHIFT                     9  /* DSP1TXL_ENA */
-#define WM8915_DSP1TXL_ENA_WIDTH                     1  /* DSP1TXL_ENA */
-#define WM8915_DSP1TXR_ENA                      0x0100  /* DSP1TXR_ENA */
-#define WM8915_DSP1TXR_ENA_MASK                 0x0100  /* DSP1TXR_ENA */
-#define WM8915_DSP1TXR_ENA_SHIFT                     8  /* DSP1TXR_ENA */
-#define WM8915_DSP1TXR_ENA_WIDTH                     1  /* DSP1TXR_ENA */
-#define WM8915_DAC2L_ENA                        0x0008  /* DAC2L_ENA */
-#define WM8915_DAC2L_ENA_MASK                   0x0008  /* DAC2L_ENA */
-#define WM8915_DAC2L_ENA_SHIFT                       3  /* DAC2L_ENA */
-#define WM8915_DAC2L_ENA_WIDTH                       1  /* DAC2L_ENA */
-#define WM8915_DAC2R_ENA                        0x0004  /* DAC2R_ENA */
-#define WM8915_DAC2R_ENA_MASK                   0x0004  /* DAC2R_ENA */
-#define WM8915_DAC2R_ENA_SHIFT                       2  /* DAC2R_ENA */
-#define WM8915_DAC2R_ENA_WIDTH                       1  /* DAC2R_ENA */
-#define WM8915_DAC1L_ENA                        0x0002  /* DAC1L_ENA */
-#define WM8915_DAC1L_ENA_MASK                   0x0002  /* DAC1L_ENA */
-#define WM8915_DAC1L_ENA_SHIFT                       1  /* DAC1L_ENA */
-#define WM8915_DAC1L_ENA_WIDTH                       1  /* DAC1L_ENA */
-#define WM8915_DAC1R_ENA                        0x0001  /* DAC1R_ENA */
-#define WM8915_DAC1R_ENA_MASK                   0x0001  /* DAC1R_ENA */
-#define WM8915_DAC1R_ENA_SHIFT                       0  /* DAC1R_ENA */
-#define WM8915_DAC1R_ENA_WIDTH                       1  /* DAC1R_ENA */
-
-/*
- * R6 (0x06) - Power Management (6)
- */
-#define WM8915_AIF2TX_CHAN1_ENA                 0x0200  /* AIF2TX_CHAN1_ENA */
-#define WM8915_AIF2TX_CHAN1_ENA_MASK            0x0200  /* AIF2TX_CHAN1_ENA */
-#define WM8915_AIF2TX_CHAN1_ENA_SHIFT                9  /* AIF2TX_CHAN1_ENA */
-#define WM8915_AIF2TX_CHAN1_ENA_WIDTH                1  /* AIF2TX_CHAN1_ENA */
-#define WM8915_AIF2TX_CHAN0_ENA                 0x0100  /* AIF2TX_CHAN0_ENA */
-#define WM8915_AIF2TX_CHAN0_ENA_MASK            0x0100  /* AIF2TX_CHAN0_ENA */
-#define WM8915_AIF2TX_CHAN0_ENA_SHIFT                8  /* AIF2TX_CHAN0_ENA */
-#define WM8915_AIF2TX_CHAN0_ENA_WIDTH                1  /* AIF2TX_CHAN0_ENA */
-#define WM8915_AIF1TX_CHAN5_ENA                 0x0020  /* AIF1TX_CHAN5_ENA */
-#define WM8915_AIF1TX_CHAN5_ENA_MASK            0x0020  /* AIF1TX_CHAN5_ENA */
-#define WM8915_AIF1TX_CHAN5_ENA_SHIFT                5  /* AIF1TX_CHAN5_ENA */
-#define WM8915_AIF1TX_CHAN5_ENA_WIDTH                1  /* AIF1TX_CHAN5_ENA */
-#define WM8915_AIF1TX_CHAN4_ENA                 0x0010  /* AIF1TX_CHAN4_ENA */
-#define WM8915_AIF1TX_CHAN4_ENA_MASK            0x0010  /* AIF1TX_CHAN4_ENA */
-#define WM8915_AIF1TX_CHAN4_ENA_SHIFT                4  /* AIF1TX_CHAN4_ENA */
-#define WM8915_AIF1TX_CHAN4_ENA_WIDTH                1  /* AIF1TX_CHAN4_ENA */
-#define WM8915_AIF1TX_CHAN3_ENA                 0x0008  /* AIF1TX_CHAN3_ENA */
-#define WM8915_AIF1TX_CHAN3_ENA_MASK            0x0008  /* AIF1TX_CHAN3_ENA */
-#define WM8915_AIF1TX_CHAN3_ENA_SHIFT                3  /* AIF1TX_CHAN3_ENA */
-#define WM8915_AIF1TX_CHAN3_ENA_WIDTH                1  /* AIF1TX_CHAN3_ENA */
-#define WM8915_AIF1TX_CHAN2_ENA                 0x0004  /* AIF1TX_CHAN2_ENA */
-#define WM8915_AIF1TX_CHAN2_ENA_MASK            0x0004  /* AIF1TX_CHAN2_ENA */
-#define WM8915_AIF1TX_CHAN2_ENA_SHIFT                2  /* AIF1TX_CHAN2_ENA */
-#define WM8915_AIF1TX_CHAN2_ENA_WIDTH                1  /* AIF1TX_CHAN2_ENA */
-#define WM8915_AIF1TX_CHAN1_ENA                 0x0002  /* AIF1TX_CHAN1_ENA */
-#define WM8915_AIF1TX_CHAN1_ENA_MASK            0x0002  /* AIF1TX_CHAN1_ENA */
-#define WM8915_AIF1TX_CHAN1_ENA_SHIFT                1  /* AIF1TX_CHAN1_ENA */
-#define WM8915_AIF1TX_CHAN1_ENA_WIDTH                1  /* AIF1TX_CHAN1_ENA */
-#define WM8915_AIF1TX_CHAN0_ENA                 0x0001  /* AIF1TX_CHAN0_ENA */
-#define WM8915_AIF1TX_CHAN0_ENA_MASK            0x0001  /* AIF1TX_CHAN0_ENA */
-#define WM8915_AIF1TX_CHAN0_ENA_SHIFT                0  /* AIF1TX_CHAN0_ENA */
-#define WM8915_AIF1TX_CHAN0_ENA_WIDTH                1  /* AIF1TX_CHAN0_ENA */
-
-/*
- * R7 (0x07) - Power Management (7)
- */
-#define WM8915_DMIC2_FN                         0x0200  /* DMIC2_FN */
-#define WM8915_DMIC2_FN_MASK                    0x0200  /* DMIC2_FN */
-#define WM8915_DMIC2_FN_SHIFT                        9  /* DMIC2_FN */
-#define WM8915_DMIC2_FN_WIDTH                        1  /* DMIC2_FN */
-#define WM8915_DMIC1_FN                         0x0100  /* DMIC1_FN */
-#define WM8915_DMIC1_FN_MASK                    0x0100  /* DMIC1_FN */
-#define WM8915_DMIC1_FN_SHIFT                        8  /* DMIC1_FN */
-#define WM8915_DMIC1_FN_WIDTH                        1  /* DMIC1_FN */
-#define WM8915_ADC_DMIC_DSP2R_ENA               0x0080  /* ADC_DMIC_DSP2R_ENA */
-#define WM8915_ADC_DMIC_DSP2R_ENA_MASK          0x0080  /* ADC_DMIC_DSP2R_ENA */
-#define WM8915_ADC_DMIC_DSP2R_ENA_SHIFT              7  /* ADC_DMIC_DSP2R_ENA */
-#define WM8915_ADC_DMIC_DSP2R_ENA_WIDTH              1  /* ADC_DMIC_DSP2R_ENA */
-#define WM8915_ADC_DMIC_DSP2L_ENA               0x0040  /* ADC_DMIC_DSP2L_ENA */
-#define WM8915_ADC_DMIC_DSP2L_ENA_MASK          0x0040  /* ADC_DMIC_DSP2L_ENA */
-#define WM8915_ADC_DMIC_DSP2L_ENA_SHIFT              6  /* ADC_DMIC_DSP2L_ENA */
-#define WM8915_ADC_DMIC_DSP2L_ENA_WIDTH              1  /* ADC_DMIC_DSP2L_ENA */
-#define WM8915_ADC_DMIC_SRC2_MASK               0x0030  /* ADC_DMIC_SRC2 - [5:4] */
-#define WM8915_ADC_DMIC_SRC2_SHIFT                   4  /* ADC_DMIC_SRC2 - [5:4] */
-#define WM8915_ADC_DMIC_SRC2_WIDTH                   2  /* ADC_DMIC_SRC2 - [5:4] */
-#define WM8915_ADC_DMIC_DSP1R_ENA               0x0008  /* ADC_DMIC_DSP1R_ENA */
-#define WM8915_ADC_DMIC_DSP1R_ENA_MASK          0x0008  /* ADC_DMIC_DSP1R_ENA */
-#define WM8915_ADC_DMIC_DSP1R_ENA_SHIFT              3  /* ADC_DMIC_DSP1R_ENA */
-#define WM8915_ADC_DMIC_DSP1R_ENA_WIDTH              1  /* ADC_DMIC_DSP1R_ENA */
-#define WM8915_ADC_DMIC_DSP1L_ENA               0x0004  /* ADC_DMIC_DSP1L_ENA */
-#define WM8915_ADC_DMIC_DSP1L_ENA_MASK          0x0004  /* ADC_DMIC_DSP1L_ENA */
-#define WM8915_ADC_DMIC_DSP1L_ENA_SHIFT              2  /* ADC_DMIC_DSP1L_ENA */
-#define WM8915_ADC_DMIC_DSP1L_ENA_WIDTH              1  /* ADC_DMIC_DSP1L_ENA */
-#define WM8915_ADC_DMIC_SRC1_MASK               0x0003  /* ADC_DMIC_SRC1 - [1:0] */
-#define WM8915_ADC_DMIC_SRC1_SHIFT                   0  /* ADC_DMIC_SRC1 - [1:0] */
-#define WM8915_ADC_DMIC_SRC1_WIDTH                   2  /* ADC_DMIC_SRC1 - [1:0] */
-
-/*
- * R8 (0x08) - Power Management (8)
- */
-#define WM8915_AIF2TX_SRC_MASK                  0x00C0  /* AIF2TX_SRC - [7:6] */
-#define WM8915_AIF2TX_SRC_SHIFT                      6  /* AIF2TX_SRC - [7:6] */
-#define WM8915_AIF2TX_SRC_WIDTH                      2  /* AIF2TX_SRC - [7:6] */
-#define WM8915_DSP2RX_SRC                       0x0010  /* DSP2RX_SRC */
-#define WM8915_DSP2RX_SRC_MASK                  0x0010  /* DSP2RX_SRC */
-#define WM8915_DSP2RX_SRC_SHIFT                      4  /* DSP2RX_SRC */
-#define WM8915_DSP2RX_SRC_WIDTH                      1  /* DSP2RX_SRC */
-#define WM8915_DSP1RX_SRC                       0x0001  /* DSP1RX_SRC */
-#define WM8915_DSP1RX_SRC_MASK                  0x0001  /* DSP1RX_SRC */
-#define WM8915_DSP1RX_SRC_SHIFT                      0  /* DSP1RX_SRC */
-#define WM8915_DSP1RX_SRC_WIDTH                      1  /* DSP1RX_SRC */
-
-/*
- * R16 (0x10) - Left Line Input Volume
- */
-#define WM8915_IN1_VU                           0x0080  /* IN1_VU */
-#define WM8915_IN1_VU_MASK                      0x0080  /* IN1_VU */
-#define WM8915_IN1_VU_SHIFT                          7  /* IN1_VU */
-#define WM8915_IN1_VU_WIDTH                          1  /* IN1_VU */
-#define WM8915_IN1L_ZC                          0x0020  /* IN1L_ZC */
-#define WM8915_IN1L_ZC_MASK                     0x0020  /* IN1L_ZC */
-#define WM8915_IN1L_ZC_SHIFT                         5  /* IN1L_ZC */
-#define WM8915_IN1L_ZC_WIDTH                         1  /* IN1L_ZC */
-#define WM8915_IN1L_VOL_MASK                    0x001F  /* IN1L_VOL - [4:0] */
-#define WM8915_IN1L_VOL_SHIFT                        0  /* IN1L_VOL - [4:0] */
-#define WM8915_IN1L_VOL_WIDTH                        5  /* IN1L_VOL - [4:0] */
-
-/*
- * R17 (0x11) - Right Line Input Volume
- */
-#define WM8915_IN1_VU                           0x0080  /* IN1_VU */
-#define WM8915_IN1_VU_MASK                      0x0080  /* IN1_VU */
-#define WM8915_IN1_VU_SHIFT                          7  /* IN1_VU */
-#define WM8915_IN1_VU_WIDTH                          1  /* IN1_VU */
-#define WM8915_IN1R_ZC                          0x0020  /* IN1R_ZC */
-#define WM8915_IN1R_ZC_MASK                     0x0020  /* IN1R_ZC */
-#define WM8915_IN1R_ZC_SHIFT                         5  /* IN1R_ZC */
-#define WM8915_IN1R_ZC_WIDTH                         1  /* IN1R_ZC */
-#define WM8915_IN1R_VOL_MASK                    0x001F  /* IN1R_VOL - [4:0] */
-#define WM8915_IN1R_VOL_SHIFT                        0  /* IN1R_VOL - [4:0] */
-#define WM8915_IN1R_VOL_WIDTH                        5  /* IN1R_VOL - [4:0] */
-
-/*
- * R18 (0x12) - Line Input Control
- */
-#define WM8915_INL_MODE_MASK                    0x000C  /* INL_MODE - [3:2] */
-#define WM8915_INL_MODE_SHIFT                        2  /* INL_MODE - [3:2] */
-#define WM8915_INL_MODE_WIDTH                        2  /* INL_MODE - [3:2] */
-#define WM8915_INR_MODE_MASK                    0x0003  /* INR_MODE - [1:0] */
-#define WM8915_INR_MODE_SHIFT                        0  /* INR_MODE - [1:0] */
-#define WM8915_INR_MODE_WIDTH                        2  /* INR_MODE - [1:0] */
-
-/*
- * R21 (0x15) - DAC1 HPOUT1 Volume
- */
-#define WM8915_DAC1R_HPOUT1R_VOL_MASK           0x00F0  /* DAC1R_HPOUT1R_VOL - [7:4] */
-#define WM8915_DAC1R_HPOUT1R_VOL_SHIFT               4  /* DAC1R_HPOUT1R_VOL - [7:4] */
-#define WM8915_DAC1R_HPOUT1R_VOL_WIDTH               4  /* DAC1R_HPOUT1R_VOL - [7:4] */
-#define WM8915_DAC1L_HPOUT1L_VOL_MASK           0x000F  /* DAC1L_HPOUT1L_VOL - [3:0] */
-#define WM8915_DAC1L_HPOUT1L_VOL_SHIFT               0  /* DAC1L_HPOUT1L_VOL - [3:0] */
-#define WM8915_DAC1L_HPOUT1L_VOL_WIDTH               4  /* DAC1L_HPOUT1L_VOL - [3:0] */
-
-/*
- * R22 (0x16) - DAC2 HPOUT2 Volume
- */
-#define WM8915_DAC2R_HPOUT2R_VOL_MASK           0x00F0  /* DAC2R_HPOUT2R_VOL - [7:4] */
-#define WM8915_DAC2R_HPOUT2R_VOL_SHIFT               4  /* DAC2R_HPOUT2R_VOL - [7:4] */
-#define WM8915_DAC2R_HPOUT2R_VOL_WIDTH               4  /* DAC2R_HPOUT2R_VOL - [7:4] */
-#define WM8915_DAC2L_HPOUT2L_VOL_MASK           0x000F  /* DAC2L_HPOUT2L_VOL - [3:0] */
-#define WM8915_DAC2L_HPOUT2L_VOL_SHIFT               0  /* DAC2L_HPOUT2L_VOL - [3:0] */
-#define WM8915_DAC2L_HPOUT2L_VOL_WIDTH               4  /* DAC2L_HPOUT2L_VOL - [3:0] */
-
-/*
- * R24 (0x18) - DAC1 Left Volume
- */
-#define WM8915_DAC1L_MUTE                       0x0200  /* DAC1L_MUTE */
-#define WM8915_DAC1L_MUTE_MASK                  0x0200  /* DAC1L_MUTE */
-#define WM8915_DAC1L_MUTE_SHIFT                      9  /* DAC1L_MUTE */
-#define WM8915_DAC1L_MUTE_WIDTH                      1  /* DAC1L_MUTE */
-#define WM8915_DAC1_VU                          0x0100  /* DAC1_VU */
-#define WM8915_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
-#define WM8915_DAC1_VU_SHIFT                         8  /* DAC1_VU */
-#define WM8915_DAC1_VU_WIDTH                         1  /* DAC1_VU */
-#define WM8915_DAC1L_VOL_MASK                   0x00FF  /* DAC1L_VOL - [7:0] */
-#define WM8915_DAC1L_VOL_SHIFT                       0  /* DAC1L_VOL - [7:0] */
-#define WM8915_DAC1L_VOL_WIDTH                       8  /* DAC1L_VOL - [7:0] */
-
-/*
- * R25 (0x19) - DAC1 Right Volume
- */
-#define WM8915_DAC1R_MUTE                       0x0200  /* DAC1R_MUTE */
-#define WM8915_DAC1R_MUTE_MASK                  0x0200  /* DAC1R_MUTE */
-#define WM8915_DAC1R_MUTE_SHIFT                      9  /* DAC1R_MUTE */
-#define WM8915_DAC1R_MUTE_WIDTH                      1  /* DAC1R_MUTE */
-#define WM8915_DAC1_VU                          0x0100  /* DAC1_VU */
-#define WM8915_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
-#define WM8915_DAC1_VU_SHIFT                         8  /* DAC1_VU */
-#define WM8915_DAC1_VU_WIDTH                         1  /* DAC1_VU */
-#define WM8915_DAC1R_VOL_MASK                   0x00FF  /* DAC1R_VOL - [7:0] */
-#define WM8915_DAC1R_VOL_SHIFT                       0  /* DAC1R_VOL - [7:0] */
-#define WM8915_DAC1R_VOL_WIDTH                       8  /* DAC1R_VOL - [7:0] */
-
-/*
- * R26 (0x1A) - DAC2 Left Volume
- */
-#define WM8915_DAC2L_MUTE                       0x0200  /* DAC2L_MUTE */
-#define WM8915_DAC2L_MUTE_MASK                  0x0200  /* DAC2L_MUTE */
-#define WM8915_DAC2L_MUTE_SHIFT                      9  /* DAC2L_MUTE */
-#define WM8915_DAC2L_MUTE_WIDTH                      1  /* DAC2L_MUTE */
-#define WM8915_DAC2_VU                          0x0100  /* DAC2_VU */
-#define WM8915_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
-#define WM8915_DAC2_VU_SHIFT                         8  /* DAC2_VU */
-#define WM8915_DAC2_VU_WIDTH                         1  /* DAC2_VU */
-#define WM8915_DAC2L_VOL_MASK                   0x00FF  /* DAC2L_VOL - [7:0] */
-#define WM8915_DAC2L_VOL_SHIFT                       0  /* DAC2L_VOL - [7:0] */
-#define WM8915_DAC2L_VOL_WIDTH                       8  /* DAC2L_VOL - [7:0] */
-
-/*
- * R27 (0x1B) - DAC2 Right Volume
- */
-#define WM8915_DAC2R_MUTE                       0x0200  /* DAC2R_MUTE */
-#define WM8915_DAC2R_MUTE_MASK                  0x0200  /* DAC2R_MUTE */
-#define WM8915_DAC2R_MUTE_SHIFT                      9  /* DAC2R_MUTE */
-#define WM8915_DAC2R_MUTE_WIDTH                      1  /* DAC2R_MUTE */
-#define WM8915_DAC2_VU                          0x0100  /* DAC2_VU */
-#define WM8915_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
-#define WM8915_DAC2_VU_SHIFT                         8  /* DAC2_VU */
-#define WM8915_DAC2_VU_WIDTH                         1  /* DAC2_VU */
-#define WM8915_DAC2R_VOL_MASK                   0x00FF  /* DAC2R_VOL - [7:0] */
-#define WM8915_DAC2R_VOL_SHIFT                       0  /* DAC2R_VOL - [7:0] */
-#define WM8915_DAC2R_VOL_WIDTH                       8  /* DAC2R_VOL - [7:0] */
-
-/*
- * R28 (0x1C) - Output1 Left Volume
- */
-#define WM8915_DAC1_VU                          0x0100  /* DAC1_VU */
-#define WM8915_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
-#define WM8915_DAC1_VU_SHIFT                         8  /* DAC1_VU */
-#define WM8915_DAC1_VU_WIDTH                         1  /* DAC1_VU */
-#define WM8915_HPOUT1L_ZC                       0x0080  /* HPOUT1L_ZC */
-#define WM8915_HPOUT1L_ZC_MASK                  0x0080  /* HPOUT1L_ZC */
-#define WM8915_HPOUT1L_ZC_SHIFT                      7  /* HPOUT1L_ZC */
-#define WM8915_HPOUT1L_ZC_WIDTH                      1  /* HPOUT1L_ZC */
-#define WM8915_HPOUT1L_VOL_MASK                 0x000F  /* HPOUT1L_VOL - [3:0] */
-#define WM8915_HPOUT1L_VOL_SHIFT                     0  /* HPOUT1L_VOL - [3:0] */
-#define WM8915_HPOUT1L_VOL_WIDTH                     4  /* HPOUT1L_VOL - [3:0] */
-
-/*
- * R29 (0x1D) - Output1 Right Volume
- */
-#define WM8915_DAC1_VU                          0x0100  /* DAC1_VU */
-#define WM8915_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
-#define WM8915_DAC1_VU_SHIFT                         8  /* DAC1_VU */
-#define WM8915_DAC1_VU_WIDTH                         1  /* DAC1_VU */
-#define WM8915_HPOUT1R_ZC                       0x0080  /* HPOUT1R_ZC */
-#define WM8915_HPOUT1R_ZC_MASK                  0x0080  /* HPOUT1R_ZC */
-#define WM8915_HPOUT1R_ZC_SHIFT                      7  /* HPOUT1R_ZC */
-#define WM8915_HPOUT1R_ZC_WIDTH                      1  /* HPOUT1R_ZC */
-#define WM8915_HPOUT1R_VOL_MASK                 0x000F  /* HPOUT1R_VOL - [3:0] */
-#define WM8915_HPOUT1R_VOL_SHIFT                     0  /* HPOUT1R_VOL - [3:0] */
-#define WM8915_HPOUT1R_VOL_WIDTH                     4  /* HPOUT1R_VOL - [3:0] */
-
-/*
- * R30 (0x1E) - Output2 Left Volume
- */
-#define WM8915_DAC2_VU                          0x0100  /* DAC2_VU */
-#define WM8915_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
-#define WM8915_DAC2_VU_SHIFT                         8  /* DAC2_VU */
-#define WM8915_DAC2_VU_WIDTH                         1  /* DAC2_VU */
-#define WM8915_HPOUT2L_ZC                       0x0080  /* HPOUT2L_ZC */
-#define WM8915_HPOUT2L_ZC_MASK                  0x0080  /* HPOUT2L_ZC */
-#define WM8915_HPOUT2L_ZC_SHIFT                      7  /* HPOUT2L_ZC */
-#define WM8915_HPOUT2L_ZC_WIDTH                      1  /* HPOUT2L_ZC */
-#define WM8915_HPOUT2L_VOL_MASK                 0x000F  /* HPOUT2L_VOL - [3:0] */
-#define WM8915_HPOUT2L_VOL_SHIFT                     0  /* HPOUT2L_VOL - [3:0] */
-#define WM8915_HPOUT2L_VOL_WIDTH                     4  /* HPOUT2L_VOL - [3:0] */
-
-/*
- * R31 (0x1F) - Output2 Right Volume
- */
-#define WM8915_DAC2_VU                          0x0100  /* DAC2_VU */
-#define WM8915_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
-#define WM8915_DAC2_VU_SHIFT                         8  /* DAC2_VU */
-#define WM8915_DAC2_VU_WIDTH                         1  /* DAC2_VU */
-#define WM8915_HPOUT2R_ZC                       0x0080  /* HPOUT2R_ZC */
-#define WM8915_HPOUT2R_ZC_MASK                  0x0080  /* HPOUT2R_ZC */
-#define WM8915_HPOUT2R_ZC_SHIFT                      7  /* HPOUT2R_ZC */
-#define WM8915_HPOUT2R_ZC_WIDTH                      1  /* HPOUT2R_ZC */
-#define WM8915_HPOUT2R_VOL_MASK                 0x000F  /* HPOUT2R_VOL - [3:0] */
-#define WM8915_HPOUT2R_VOL_SHIFT                     0  /* HPOUT2R_VOL - [3:0] */
-#define WM8915_HPOUT2R_VOL_WIDTH                     4  /* HPOUT2R_VOL - [3:0] */
-
-/*
- * R32 (0x20) - MICBIAS (1)
- */
-#define WM8915_MICB1_RATE                       0x0020  /* MICB1_RATE */
-#define WM8915_MICB1_RATE_MASK                  0x0020  /* MICB1_RATE */
-#define WM8915_MICB1_RATE_SHIFT                      5  /* MICB1_RATE */
-#define WM8915_MICB1_RATE_WIDTH                      1  /* MICB1_RATE */
-#define WM8915_MICB1_MODE                       0x0010  /* MICB1_MODE */
-#define WM8915_MICB1_MODE_MASK                  0x0010  /* MICB1_MODE */
-#define WM8915_MICB1_MODE_SHIFT                      4  /* MICB1_MODE */
-#define WM8915_MICB1_MODE_WIDTH                      1  /* MICB1_MODE */
-#define WM8915_MICB1_LVL_MASK                   0x000E  /* MICB1_LVL - [3:1] */
-#define WM8915_MICB1_LVL_SHIFT                       1  /* MICB1_LVL - [3:1] */
-#define WM8915_MICB1_LVL_WIDTH                       3  /* MICB1_LVL - [3:1] */
-#define WM8915_MICB1_DISCH                      0x0001  /* MICB1_DISCH */
-#define WM8915_MICB1_DISCH_MASK                 0x0001  /* MICB1_DISCH */
-#define WM8915_MICB1_DISCH_SHIFT                     0  /* MICB1_DISCH */
-#define WM8915_MICB1_DISCH_WIDTH                     1  /* MICB1_DISCH */
-
-/*
- * R33 (0x21) - MICBIAS (2)
- */
-#define WM8915_MICB2_RATE                       0x0020  /* MICB2_RATE */
-#define WM8915_MICB2_RATE_MASK                  0x0020  /* MICB2_RATE */
-#define WM8915_MICB2_RATE_SHIFT                      5  /* MICB2_RATE */
-#define WM8915_MICB2_RATE_WIDTH                      1  /* MICB2_RATE */
-#define WM8915_MICB2_MODE                       0x0010  /* MICB2_MODE */
-#define WM8915_MICB2_MODE_MASK                  0x0010  /* MICB2_MODE */
-#define WM8915_MICB2_MODE_SHIFT                      4  /* MICB2_MODE */
-#define WM8915_MICB2_MODE_WIDTH                      1  /* MICB2_MODE */
-#define WM8915_MICB2_LVL_MASK                   0x000E  /* MICB2_LVL - [3:1] */
-#define WM8915_MICB2_LVL_SHIFT                       1  /* MICB2_LVL - [3:1] */
-#define WM8915_MICB2_LVL_WIDTH                       3  /* MICB2_LVL - [3:1] */
-#define WM8915_MICB2_DISCH                      0x0001  /* MICB2_DISCH */
-#define WM8915_MICB2_DISCH_MASK                 0x0001  /* MICB2_DISCH */
-#define WM8915_MICB2_DISCH_SHIFT                     0  /* MICB2_DISCH */
-#define WM8915_MICB2_DISCH_WIDTH                     1  /* MICB2_DISCH */
-
-/*
- * R40 (0x28) - LDO 1
- */
-#define WM8915_LDO1_MODE                        0x0020  /* LDO1_MODE */
-#define WM8915_LDO1_MODE_MASK                   0x0020  /* LDO1_MODE */
-#define WM8915_LDO1_MODE_SHIFT                       5  /* LDO1_MODE */
-#define WM8915_LDO1_MODE_WIDTH                       1  /* LDO1_MODE */
-#define WM8915_LDO1_VSEL_MASK                   0x0006  /* LDO1_VSEL - [2:1] */
-#define WM8915_LDO1_VSEL_SHIFT                       1  /* LDO1_VSEL - [2:1] */
-#define WM8915_LDO1_VSEL_WIDTH                       2  /* LDO1_VSEL - [2:1] */
-#define WM8915_LDO1_DISCH                       0x0001  /* LDO1_DISCH */
-#define WM8915_LDO1_DISCH_MASK                  0x0001  /* LDO1_DISCH */
-#define WM8915_LDO1_DISCH_SHIFT                      0  /* LDO1_DISCH */
-#define WM8915_LDO1_DISCH_WIDTH                      1  /* LDO1_DISCH */
-
-/*
- * R41 (0x29) - LDO 2
- */
-#define WM8915_LDO2_MODE                        0x0020  /* LDO2_MODE */
-#define WM8915_LDO2_MODE_MASK                   0x0020  /* LDO2_MODE */
-#define WM8915_LDO2_MODE_SHIFT                       5  /* LDO2_MODE */
-#define WM8915_LDO2_MODE_WIDTH                       1  /* LDO2_MODE */
-#define WM8915_LDO2_VSEL_MASK                   0x001E  /* LDO2_VSEL - [4:1] */
-#define WM8915_LDO2_VSEL_SHIFT                       1  /* LDO2_VSEL - [4:1] */
-#define WM8915_LDO2_VSEL_WIDTH                       4  /* LDO2_VSEL - [4:1] */
-#define WM8915_LDO2_DISCH                       0x0001  /* LDO2_DISCH */
-#define WM8915_LDO2_DISCH_MASK                  0x0001  /* LDO2_DISCH */
-#define WM8915_LDO2_DISCH_SHIFT                      0  /* LDO2_DISCH */
-#define WM8915_LDO2_DISCH_WIDTH                      1  /* LDO2_DISCH */
-
-/*
- * R48 (0x30) - Accessory Detect Mode 1
- */
-#define WM8915_JD_MODE_MASK                     0x0003  /* JD_MODE - [1:0] */
-#define WM8915_JD_MODE_SHIFT                         0  /* JD_MODE - [1:0] */
-#define WM8915_JD_MODE_WIDTH                         2  /* JD_MODE - [1:0] */
-
-/*
- * R49 (0x31) - Accessory Detect Mode 2
- */
-#define WM8915_HPOUT1FB_SRC                     0x0004  /* HPOUT1FB_SRC */
-#define WM8915_HPOUT1FB_SRC_MASK                0x0004  /* HPOUT1FB_SRC */
-#define WM8915_HPOUT1FB_SRC_SHIFT                    2  /* HPOUT1FB_SRC */
-#define WM8915_HPOUT1FB_SRC_WIDTH                    1  /* HPOUT1FB_SRC */
-#define WM8915_MICD_SRC                         0x0002  /* MICD_SRC */
-#define WM8915_MICD_SRC_MASK                    0x0002  /* MICD_SRC */
-#define WM8915_MICD_SRC_SHIFT                        1  /* MICD_SRC */
-#define WM8915_MICD_SRC_WIDTH                        1  /* MICD_SRC */
-#define WM8915_MICD_BIAS_SRC                    0x0001  /* MICD_BIAS_SRC */
-#define WM8915_MICD_BIAS_SRC_MASK               0x0001  /* MICD_BIAS_SRC */
-#define WM8915_MICD_BIAS_SRC_SHIFT                   0  /* MICD_BIAS_SRC */
-#define WM8915_MICD_BIAS_SRC_WIDTH                   1  /* MICD_BIAS_SRC */
-
-/*
- * R52 (0x34) - Headphone Detect 1
- */
-#define WM8915_HP_HOLDTIME_MASK                 0x00E0  /* HP_HOLDTIME - [7:5] */
-#define WM8915_HP_HOLDTIME_SHIFT                     5  /* HP_HOLDTIME - [7:5] */
-#define WM8915_HP_HOLDTIME_WIDTH                     3  /* HP_HOLDTIME - [7:5] */
-#define WM8915_HP_CLK_DIV_MASK                  0x0018  /* HP_CLK_DIV - [4:3] */
-#define WM8915_HP_CLK_DIV_SHIFT                      3  /* HP_CLK_DIV - [4:3] */
-#define WM8915_HP_CLK_DIV_WIDTH                      2  /* HP_CLK_DIV - [4:3] */
-#define WM8915_HP_STEP_SIZE                     0x0002  /* HP_STEP_SIZE */
-#define WM8915_HP_STEP_SIZE_MASK                0x0002  /* HP_STEP_SIZE */
-#define WM8915_HP_STEP_SIZE_SHIFT                    1  /* HP_STEP_SIZE */
-#define WM8915_HP_STEP_SIZE_WIDTH                    1  /* HP_STEP_SIZE */
-#define WM8915_HP_POLL                          0x0001  /* HP_POLL */
-#define WM8915_HP_POLL_MASK                     0x0001  /* HP_POLL */
-#define WM8915_HP_POLL_SHIFT                         0  /* HP_POLL */
-#define WM8915_HP_POLL_WIDTH                         1  /* HP_POLL */
-
-/*
- * R53 (0x35) - Headphone Detect 2
- */
-#define WM8915_HP_DONE                          0x0080  /* HP_DONE */
-#define WM8915_HP_DONE_MASK                     0x0080  /* HP_DONE */
-#define WM8915_HP_DONE_SHIFT                         7  /* HP_DONE */
-#define WM8915_HP_DONE_WIDTH                         1  /* HP_DONE */
-#define WM8915_HP_LVL_MASK                      0x007F  /* HP_LVL - [6:0] */
-#define WM8915_HP_LVL_SHIFT                          0  /* HP_LVL - [6:0] */
-#define WM8915_HP_LVL_WIDTH                          7  /* HP_LVL - [6:0] */
-
-/*
- * R56 (0x38) - Mic Detect 1
- */
-#define WM8915_MICD_BIAS_STARTTIME_MASK         0xF000  /* MICD_BIAS_STARTTIME - [15:12] */
-#define WM8915_MICD_BIAS_STARTTIME_SHIFT            12  /* MICD_BIAS_STARTTIME - [15:12] */
-#define WM8915_MICD_BIAS_STARTTIME_WIDTH             4  /* MICD_BIAS_STARTTIME - [15:12] */
-#define WM8915_MICD_RATE_MASK                   0x0F00  /* MICD_RATE - [11:8] */
-#define WM8915_MICD_RATE_SHIFT                       8  /* MICD_RATE - [11:8] */
-#define WM8915_MICD_RATE_WIDTH                       4  /* MICD_RATE - [11:8] */
-#define WM8915_MICD_DBTIME                      0x0002  /* MICD_DBTIME */
-#define WM8915_MICD_DBTIME_MASK                 0x0002  /* MICD_DBTIME */
-#define WM8915_MICD_DBTIME_SHIFT                     1  /* MICD_DBTIME */
-#define WM8915_MICD_DBTIME_WIDTH                     1  /* MICD_DBTIME */
-#define WM8915_MICD_ENA                         0x0001  /* MICD_ENA */
-#define WM8915_MICD_ENA_MASK                    0x0001  /* MICD_ENA */
-#define WM8915_MICD_ENA_SHIFT                        0  /* MICD_ENA */
-#define WM8915_MICD_ENA_WIDTH                        1  /* MICD_ENA */
-
-/*
- * R57 (0x39) - Mic Detect 2
- */
-#define WM8915_MICD_LVL_SEL_MASK                0x00FF  /* MICD_LVL_SEL - [7:0] */
-#define WM8915_MICD_LVL_SEL_SHIFT                    0  /* MICD_LVL_SEL - [7:0] */
-#define WM8915_MICD_LVL_SEL_WIDTH                    8  /* MICD_LVL_SEL - [7:0] */
-
-/*
- * R58 (0x3A) - Mic Detect 3
- */
-#define WM8915_MICD_LVL_MASK                    0x07FC  /* MICD_LVL - [10:2] */
-#define WM8915_MICD_LVL_SHIFT                        2  /* MICD_LVL - [10:2] */
-#define WM8915_MICD_LVL_WIDTH                        9  /* MICD_LVL - [10:2] */
-#define WM8915_MICD_VALID                       0x0002  /* MICD_VALID */
-#define WM8915_MICD_VALID_MASK                  0x0002  /* MICD_VALID */
-#define WM8915_MICD_VALID_SHIFT                      1  /* MICD_VALID */
-#define WM8915_MICD_VALID_WIDTH                      1  /* MICD_VALID */
-#define WM8915_MICD_STS                         0x0001  /* MICD_STS */
-#define WM8915_MICD_STS_MASK                    0x0001  /* MICD_STS */
-#define WM8915_MICD_STS_SHIFT                        0  /* MICD_STS */
-#define WM8915_MICD_STS_WIDTH                        1  /* MICD_STS */
-
-/*
- * R64 (0x40) - Charge Pump (1)
- */
-#define WM8915_CP_ENA                           0x8000  /* CP_ENA */
-#define WM8915_CP_ENA_MASK                      0x8000  /* CP_ENA */
-#define WM8915_CP_ENA_SHIFT                         15  /* CP_ENA */
-#define WM8915_CP_ENA_WIDTH                          1  /* CP_ENA */
-
-/*
- * R65 (0x41) - Charge Pump (2)
- */
-#define WM8915_CP_DISCH                         0x8000  /* CP_DISCH */
-#define WM8915_CP_DISCH_MASK                    0x8000  /* CP_DISCH */
-#define WM8915_CP_DISCH_SHIFT                       15  /* CP_DISCH */
-#define WM8915_CP_DISCH_WIDTH                        1  /* CP_DISCH */
-
-/*
- * R80 (0x50) - DC Servo (1)
- */
-#define WM8915_DCS_ENA_CHAN_3                   0x0008  /* DCS_ENA_CHAN_3 */
-#define WM8915_DCS_ENA_CHAN_3_MASK              0x0008  /* DCS_ENA_CHAN_3 */
-#define WM8915_DCS_ENA_CHAN_3_SHIFT                  3  /* DCS_ENA_CHAN_3 */
-#define WM8915_DCS_ENA_CHAN_3_WIDTH                  1  /* DCS_ENA_CHAN_3 */
-#define WM8915_DCS_ENA_CHAN_2                   0x0004  /* DCS_ENA_CHAN_2 */
-#define WM8915_DCS_ENA_CHAN_2_MASK              0x0004  /* DCS_ENA_CHAN_2 */
-#define WM8915_DCS_ENA_CHAN_2_SHIFT                  2  /* DCS_ENA_CHAN_2 */
-#define WM8915_DCS_ENA_CHAN_2_WIDTH                  1  /* DCS_ENA_CHAN_2 */
-#define WM8915_DCS_ENA_CHAN_1                   0x0002  /* DCS_ENA_CHAN_1 */
-#define WM8915_DCS_ENA_CHAN_1_MASK              0x0002  /* DCS_ENA_CHAN_1 */
-#define WM8915_DCS_ENA_CHAN_1_SHIFT                  1  /* DCS_ENA_CHAN_1 */
-#define WM8915_DCS_ENA_CHAN_1_WIDTH                  1  /* DCS_ENA_CHAN_1 */
-#define WM8915_DCS_ENA_CHAN_0                   0x0001  /* DCS_ENA_CHAN_0 */
-#define WM8915_DCS_ENA_CHAN_0_MASK              0x0001  /* DCS_ENA_CHAN_0 */
-#define WM8915_DCS_ENA_CHAN_0_SHIFT                  0  /* DCS_ENA_CHAN_0 */
-#define WM8915_DCS_ENA_CHAN_0_WIDTH                  1  /* DCS_ENA_CHAN_0 */
-
-/*
- * R81 (0x51) - DC Servo (2)
- */
-#define WM8915_DCS_TRIG_SINGLE_3                0x8000  /* DCS_TRIG_SINGLE_3 */
-#define WM8915_DCS_TRIG_SINGLE_3_MASK           0x8000  /* DCS_TRIG_SINGLE_3 */
-#define WM8915_DCS_TRIG_SINGLE_3_SHIFT              15  /* DCS_TRIG_SINGLE_3 */
-#define WM8915_DCS_TRIG_SINGLE_3_WIDTH               1  /* DCS_TRIG_SINGLE_3 */
-#define WM8915_DCS_TRIG_SINGLE_2                0x4000  /* DCS_TRIG_SINGLE_2 */
-#define WM8915_DCS_TRIG_SINGLE_2_MASK           0x4000  /* DCS_TRIG_SINGLE_2 */
-#define WM8915_DCS_TRIG_SINGLE_2_SHIFT              14  /* DCS_TRIG_SINGLE_2 */
-#define WM8915_DCS_TRIG_SINGLE_2_WIDTH               1  /* DCS_TRIG_SINGLE_2 */
-#define WM8915_DCS_TRIG_SINGLE_1                0x2000  /* DCS_TRIG_SINGLE_1 */
-#define WM8915_DCS_TRIG_SINGLE_1_MASK           0x2000  /* DCS_TRIG_SINGLE_1 */
-#define WM8915_DCS_TRIG_SINGLE_1_SHIFT              13  /* DCS_TRIG_SINGLE_1 */
-#define WM8915_DCS_TRIG_SINGLE_1_WIDTH               1  /* DCS_TRIG_SINGLE_1 */
-#define WM8915_DCS_TRIG_SINGLE_0                0x1000  /* DCS_TRIG_SINGLE_0 */
-#define WM8915_DCS_TRIG_SINGLE_0_MASK           0x1000  /* DCS_TRIG_SINGLE_0 */
-#define WM8915_DCS_TRIG_SINGLE_0_SHIFT              12  /* DCS_TRIG_SINGLE_0 */
-#define WM8915_DCS_TRIG_SINGLE_0_WIDTH               1  /* DCS_TRIG_SINGLE_0 */
-#define WM8915_DCS_TRIG_SERIES_3                0x0800  /* DCS_TRIG_SERIES_3 */
-#define WM8915_DCS_TRIG_SERIES_3_MASK           0x0800  /* DCS_TRIG_SERIES_3 */
-#define WM8915_DCS_TRIG_SERIES_3_SHIFT              11  /* DCS_TRIG_SERIES_3 */
-#define WM8915_DCS_TRIG_SERIES_3_WIDTH               1  /* DCS_TRIG_SERIES_3 */
-#define WM8915_DCS_TRIG_SERIES_2                0x0400  /* DCS_TRIG_SERIES_2 */
-#define WM8915_DCS_TRIG_SERIES_2_MASK           0x0400  /* DCS_TRIG_SERIES_2 */
-#define WM8915_DCS_TRIG_SERIES_2_SHIFT              10  /* DCS_TRIG_SERIES_2 */
-#define WM8915_DCS_TRIG_SERIES_2_WIDTH               1  /* DCS_TRIG_SERIES_2 */
-#define WM8915_DCS_TRIG_SERIES_1                0x0200  /* DCS_TRIG_SERIES_1 */
-#define WM8915_DCS_TRIG_SERIES_1_MASK           0x0200  /* DCS_TRIG_SERIES_1 */
-#define WM8915_DCS_TRIG_SERIES_1_SHIFT               9  /* DCS_TRIG_SERIES_1 */
-#define WM8915_DCS_TRIG_SERIES_1_WIDTH               1  /* DCS_TRIG_SERIES_1 */
-#define WM8915_DCS_TRIG_SERIES_0                0x0100  /* DCS_TRIG_SERIES_0 */
-#define WM8915_DCS_TRIG_SERIES_0_MASK           0x0100  /* DCS_TRIG_SERIES_0 */
-#define WM8915_DCS_TRIG_SERIES_0_SHIFT               8  /* DCS_TRIG_SERIES_0 */
-#define WM8915_DCS_TRIG_SERIES_0_WIDTH               1  /* DCS_TRIG_SERIES_0 */
-#define WM8915_DCS_TRIG_STARTUP_3               0x0080  /* DCS_TRIG_STARTUP_3 */
-#define WM8915_DCS_TRIG_STARTUP_3_MASK          0x0080  /* DCS_TRIG_STARTUP_3 */
-#define WM8915_DCS_TRIG_STARTUP_3_SHIFT              7  /* DCS_TRIG_STARTUP_3 */
-#define WM8915_DCS_TRIG_STARTUP_3_WIDTH              1  /* DCS_TRIG_STARTUP_3 */
-#define WM8915_DCS_TRIG_STARTUP_2               0x0040  /* DCS_TRIG_STARTUP_2 */
-#define WM8915_DCS_TRIG_STARTUP_2_MASK          0x0040  /* DCS_TRIG_STARTUP_2 */
-#define WM8915_DCS_TRIG_STARTUP_2_SHIFT              6  /* DCS_TRIG_STARTUP_2 */
-#define WM8915_DCS_TRIG_STARTUP_2_WIDTH              1  /* DCS_TRIG_STARTUP_2 */
-#define WM8915_DCS_TRIG_STARTUP_1               0x0020  /* DCS_TRIG_STARTUP_1 */
-#define WM8915_DCS_TRIG_STARTUP_1_MASK          0x0020  /* DCS_TRIG_STARTUP_1 */
-#define WM8915_DCS_TRIG_STARTUP_1_SHIFT              5  /* DCS_TRIG_STARTUP_1 */
-#define WM8915_DCS_TRIG_STARTUP_1_WIDTH              1  /* DCS_TRIG_STARTUP_1 */
-#define WM8915_DCS_TRIG_STARTUP_0               0x0010  /* DCS_TRIG_STARTUP_0 */
-#define WM8915_DCS_TRIG_STARTUP_0_MASK          0x0010  /* DCS_TRIG_STARTUP_0 */
-#define WM8915_DCS_TRIG_STARTUP_0_SHIFT              4  /* DCS_TRIG_STARTUP_0 */
-#define WM8915_DCS_TRIG_STARTUP_0_WIDTH              1  /* DCS_TRIG_STARTUP_0 */
-#define WM8915_DCS_TRIG_DAC_WR_3                0x0008  /* DCS_TRIG_DAC_WR_3 */
-#define WM8915_DCS_TRIG_DAC_WR_3_MASK           0x0008  /* DCS_TRIG_DAC_WR_3 */
-#define WM8915_DCS_TRIG_DAC_WR_3_SHIFT               3  /* DCS_TRIG_DAC_WR_3 */
-#define WM8915_DCS_TRIG_DAC_WR_3_WIDTH               1  /* DCS_TRIG_DAC_WR_3 */
-#define WM8915_DCS_TRIG_DAC_WR_2                0x0004  /* DCS_TRIG_DAC_WR_2 */
-#define WM8915_DCS_TRIG_DAC_WR_2_MASK           0x0004  /* DCS_TRIG_DAC_WR_2 */
-#define WM8915_DCS_TRIG_DAC_WR_2_SHIFT               2  /* DCS_TRIG_DAC_WR_2 */
-#define WM8915_DCS_TRIG_DAC_WR_2_WIDTH               1  /* DCS_TRIG_DAC_WR_2 */
-#define WM8915_DCS_TRIG_DAC_WR_1                0x0002  /* DCS_TRIG_DAC_WR_1 */
-#define WM8915_DCS_TRIG_DAC_WR_1_MASK           0x0002  /* DCS_TRIG_DAC_WR_1 */
-#define WM8915_DCS_TRIG_DAC_WR_1_SHIFT               1  /* DCS_TRIG_DAC_WR_1 */
-#define WM8915_DCS_TRIG_DAC_WR_1_WIDTH               1  /* DCS_TRIG_DAC_WR_1 */
-#define WM8915_DCS_TRIG_DAC_WR_0                0x0001  /* DCS_TRIG_DAC_WR_0 */
-#define WM8915_DCS_TRIG_DAC_WR_0_MASK           0x0001  /* DCS_TRIG_DAC_WR_0 */
-#define WM8915_DCS_TRIG_DAC_WR_0_SHIFT               0  /* DCS_TRIG_DAC_WR_0 */
-#define WM8915_DCS_TRIG_DAC_WR_0_WIDTH               1  /* DCS_TRIG_DAC_WR_0 */
-
-/*
- * R82 (0x52) - DC Servo (3)
- */
-#define WM8915_DCS_TIMER_PERIOD_23_MASK         0x0F00  /* DCS_TIMER_PERIOD_23 - [11:8] */
-#define WM8915_DCS_TIMER_PERIOD_23_SHIFT             8  /* DCS_TIMER_PERIOD_23 - [11:8] */
-#define WM8915_DCS_TIMER_PERIOD_23_WIDTH             4  /* DCS_TIMER_PERIOD_23 - [11:8] */
-#define WM8915_DCS_TIMER_PERIOD_01_MASK         0x000F  /* DCS_TIMER_PERIOD_01 - [3:0] */
-#define WM8915_DCS_TIMER_PERIOD_01_SHIFT             0  /* DCS_TIMER_PERIOD_01 - [3:0] */
-#define WM8915_DCS_TIMER_PERIOD_01_WIDTH             4  /* DCS_TIMER_PERIOD_01 - [3:0] */
-
-/*
- * R84 (0x54) - DC Servo (5)
- */
-#define WM8915_DCS_SERIES_NO_23_MASK            0x7F00  /* DCS_SERIES_NO_23 - [14:8] */
-#define WM8915_DCS_SERIES_NO_23_SHIFT                8  /* DCS_SERIES_NO_23 - [14:8] */
-#define WM8915_DCS_SERIES_NO_23_WIDTH                7  /* DCS_SERIES_NO_23 - [14:8] */
-#define WM8915_DCS_SERIES_NO_01_MASK            0x007F  /* DCS_SERIES_NO_01 - [6:0] */
-#define WM8915_DCS_SERIES_NO_01_SHIFT                0  /* DCS_SERIES_NO_01 - [6:0] */
-#define WM8915_DCS_SERIES_NO_01_WIDTH                7  /* DCS_SERIES_NO_01 - [6:0] */
-
-/*
- * R85 (0x55) - DC Servo (6)
- */
-#define WM8915_DCS_DAC_WR_VAL_3_MASK            0xFF00  /* DCS_DAC_WR_VAL_3 - [15:8] */
-#define WM8915_DCS_DAC_WR_VAL_3_SHIFT                8  /* DCS_DAC_WR_VAL_3 - [15:8] */
-#define WM8915_DCS_DAC_WR_VAL_3_WIDTH                8  /* DCS_DAC_WR_VAL_3 - [15:8] */
-#define WM8915_DCS_DAC_WR_VAL_2_MASK            0x00FF  /* DCS_DAC_WR_VAL_2 - [7:0] */
-#define WM8915_DCS_DAC_WR_VAL_2_SHIFT                0  /* DCS_DAC_WR_VAL_2 - [7:0] */
-#define WM8915_DCS_DAC_WR_VAL_2_WIDTH                8  /* DCS_DAC_WR_VAL_2 - [7:0] */
-
-/*
- * R86 (0x56) - DC Servo (7)
- */
-#define WM8915_DCS_DAC_WR_VAL_1_MASK            0xFF00  /* DCS_DAC_WR_VAL_1 - [15:8] */
-#define WM8915_DCS_DAC_WR_VAL_1_SHIFT                8  /* DCS_DAC_WR_VAL_1 - [15:8] */
-#define WM8915_DCS_DAC_WR_VAL_1_WIDTH                8  /* DCS_DAC_WR_VAL_1 - [15:8] */
-#define WM8915_DCS_DAC_WR_VAL_0_MASK            0x00FF  /* DCS_DAC_WR_VAL_0 - [7:0] */
-#define WM8915_DCS_DAC_WR_VAL_0_SHIFT                0  /* DCS_DAC_WR_VAL_0 - [7:0] */
-#define WM8915_DCS_DAC_WR_VAL_0_WIDTH                8  /* DCS_DAC_WR_VAL_0 - [7:0] */
-
-/*
- * R87 (0x57) - DC Servo Readback 0
- */
-#define WM8915_DCS_CAL_COMPLETE_MASK            0x0F00  /* DCS_CAL_COMPLETE - [11:8] */
-#define WM8915_DCS_CAL_COMPLETE_SHIFT                8  /* DCS_CAL_COMPLETE - [11:8] */
-#define WM8915_DCS_CAL_COMPLETE_WIDTH                4  /* DCS_CAL_COMPLETE - [11:8] */
-#define WM8915_DCS_DAC_WR_COMPLETE_MASK         0x00F0  /* DCS_DAC_WR_COMPLETE - [7:4] */
-#define WM8915_DCS_DAC_WR_COMPLETE_SHIFT             4  /* DCS_DAC_WR_COMPLETE - [7:4] */
-#define WM8915_DCS_DAC_WR_COMPLETE_WIDTH             4  /* DCS_DAC_WR_COMPLETE - [7:4] */
-#define WM8915_DCS_STARTUP_COMPLETE_MASK        0x000F  /* DCS_STARTUP_COMPLETE - [3:0] */
-#define WM8915_DCS_STARTUP_COMPLETE_SHIFT            0  /* DCS_STARTUP_COMPLETE - [3:0] */
-#define WM8915_DCS_STARTUP_COMPLETE_WIDTH            4  /* DCS_STARTUP_COMPLETE - [3:0] */
-
-/*
- * R96 (0x60) - Analogue HP (1)
- */
-#define WM8915_HPOUT1L_RMV_SHORT                0x0080  /* HPOUT1L_RMV_SHORT */
-#define WM8915_HPOUT1L_RMV_SHORT_MASK           0x0080  /* HPOUT1L_RMV_SHORT */
-#define WM8915_HPOUT1L_RMV_SHORT_SHIFT               7  /* HPOUT1L_RMV_SHORT */
-#define WM8915_HPOUT1L_RMV_SHORT_WIDTH               1  /* HPOUT1L_RMV_SHORT */
-#define WM8915_HPOUT1L_OUTP                     0x0040  /* HPOUT1L_OUTP */
-#define WM8915_HPOUT1L_OUTP_MASK                0x0040  /* HPOUT1L_OUTP */
-#define WM8915_HPOUT1L_OUTP_SHIFT                    6  /* HPOUT1L_OUTP */
-#define WM8915_HPOUT1L_OUTP_WIDTH                    1  /* HPOUT1L_OUTP */
-#define WM8915_HPOUT1L_DLY                      0x0020  /* HPOUT1L_DLY */
-#define WM8915_HPOUT1L_DLY_MASK                 0x0020  /* HPOUT1L_DLY */
-#define WM8915_HPOUT1L_DLY_SHIFT                     5  /* HPOUT1L_DLY */
-#define WM8915_HPOUT1L_DLY_WIDTH                     1  /* HPOUT1L_DLY */
-#define WM8915_HPOUT1R_RMV_SHORT                0x0008  /* HPOUT1R_RMV_SHORT */
-#define WM8915_HPOUT1R_RMV_SHORT_MASK           0x0008  /* HPOUT1R_RMV_SHORT */
-#define WM8915_HPOUT1R_RMV_SHORT_SHIFT               3  /* HPOUT1R_RMV_SHORT */
-#define WM8915_HPOUT1R_RMV_SHORT_WIDTH               1  /* HPOUT1R_RMV_SHORT */
-#define WM8915_HPOUT1R_OUTP                     0x0004  /* HPOUT1R_OUTP */
-#define WM8915_HPOUT1R_OUTP_MASK                0x0004  /* HPOUT1R_OUTP */
-#define WM8915_HPOUT1R_OUTP_SHIFT                    2  /* HPOUT1R_OUTP */
-#define WM8915_HPOUT1R_OUTP_WIDTH                    1  /* HPOUT1R_OUTP */
-#define WM8915_HPOUT1R_DLY                      0x0002  /* HPOUT1R_DLY */
-#define WM8915_HPOUT1R_DLY_MASK                 0x0002  /* HPOUT1R_DLY */
-#define WM8915_HPOUT1R_DLY_SHIFT                     1  /* HPOUT1R_DLY */
-#define WM8915_HPOUT1R_DLY_WIDTH                     1  /* HPOUT1R_DLY */
-
-/*
- * R97 (0x61) - Analogue HP (2)
- */
-#define WM8915_HPOUT2L_RMV_SHORT                0x0080  /* HPOUT2L_RMV_SHORT */
-#define WM8915_HPOUT2L_RMV_SHORT_MASK           0x0080  /* HPOUT2L_RMV_SHORT */
-#define WM8915_HPOUT2L_RMV_SHORT_SHIFT               7  /* HPOUT2L_RMV_SHORT */
-#define WM8915_HPOUT2L_RMV_SHORT_WIDTH               1  /* HPOUT2L_RMV_SHORT */
-#define WM8915_HPOUT2L_OUTP                     0x0040  /* HPOUT2L_OUTP */
-#define WM8915_HPOUT2L_OUTP_MASK                0x0040  /* HPOUT2L_OUTP */
-#define WM8915_HPOUT2L_OUTP_SHIFT                    6  /* HPOUT2L_OUTP */
-#define WM8915_HPOUT2L_OUTP_WIDTH                    1  /* HPOUT2L_OUTP */
-#define WM8915_HPOUT2L_DLY                      0x0020  /* HPOUT2L_DLY */
-#define WM8915_HPOUT2L_DLY_MASK                 0x0020  /* HPOUT2L_DLY */
-#define WM8915_HPOUT2L_DLY_SHIFT                     5  /* HPOUT2L_DLY */
-#define WM8915_HPOUT2L_DLY_WIDTH                     1  /* HPOUT2L_DLY */
-#define WM8915_HPOUT2R_RMV_SHORT                0x0008  /* HPOUT2R_RMV_SHORT */
-#define WM8915_HPOUT2R_RMV_SHORT_MASK           0x0008  /* HPOUT2R_RMV_SHORT */
-#define WM8915_HPOUT2R_RMV_SHORT_SHIFT               3  /* HPOUT2R_RMV_SHORT */
-#define WM8915_HPOUT2R_RMV_SHORT_WIDTH               1  /* HPOUT2R_RMV_SHORT */
-#define WM8915_HPOUT2R_OUTP                     0x0004  /* HPOUT2R_OUTP */
-#define WM8915_HPOUT2R_OUTP_MASK                0x0004  /* HPOUT2R_OUTP */
-#define WM8915_HPOUT2R_OUTP_SHIFT                    2  /* HPOUT2R_OUTP */
-#define WM8915_HPOUT2R_OUTP_WIDTH                    1  /* HPOUT2R_OUTP */
-#define WM8915_HPOUT2R_DLY                      0x0002  /* HPOUT2R_DLY */
-#define WM8915_HPOUT2R_DLY_MASK                 0x0002  /* HPOUT2R_DLY */
-#define WM8915_HPOUT2R_DLY_SHIFT                     1  /* HPOUT2R_DLY */
-#define WM8915_HPOUT2R_DLY_WIDTH                     1  /* HPOUT2R_DLY */
-
-/*
- * R256 (0x100) - Chip Revision
- */
-#define WM8915_CHIP_REV_MASK                    0x000F  /* CHIP_REV - [3:0] */
-#define WM8915_CHIP_REV_SHIFT                        0  /* CHIP_REV - [3:0] */
-#define WM8915_CHIP_REV_WIDTH                        4  /* CHIP_REV - [3:0] */
-
-/*
- * R257 (0x101) - Control Interface (1)
- */
-#define WM8915_AUTO_INC                         0x0004  /* AUTO_INC */
-#define WM8915_AUTO_INC_MASK                    0x0004  /* AUTO_INC */
-#define WM8915_AUTO_INC_SHIFT                        2  /* AUTO_INC */
-#define WM8915_AUTO_INC_WIDTH                        1  /* AUTO_INC */
-
-/*
- * R272 (0x110) - Write Sequencer Ctrl (1)
- */
-#define WM8915_WSEQ_ENA                         0x8000  /* WSEQ_ENA */
-#define WM8915_WSEQ_ENA_MASK                    0x8000  /* WSEQ_ENA */
-#define WM8915_WSEQ_ENA_SHIFT                       15  /* WSEQ_ENA */
-#define WM8915_WSEQ_ENA_WIDTH                        1  /* WSEQ_ENA */
-#define WM8915_WSEQ_ABORT                       0x0200  /* WSEQ_ABORT */
-#define WM8915_WSEQ_ABORT_MASK                  0x0200  /* WSEQ_ABORT */
-#define WM8915_WSEQ_ABORT_SHIFT                      9  /* WSEQ_ABORT */
-#define WM8915_WSEQ_ABORT_WIDTH                      1  /* WSEQ_ABORT */
-#define WM8915_WSEQ_START                       0x0100  /* WSEQ_START */
-#define WM8915_WSEQ_START_MASK                  0x0100  /* WSEQ_START */
-#define WM8915_WSEQ_START_SHIFT                      8  /* WSEQ_START */
-#define WM8915_WSEQ_START_WIDTH                      1  /* WSEQ_START */
-#define WM8915_WSEQ_START_INDEX_MASK            0x007F  /* WSEQ_START_INDEX - [6:0] */
-#define WM8915_WSEQ_START_INDEX_SHIFT                0  /* WSEQ_START_INDEX - [6:0] */
-#define WM8915_WSEQ_START_INDEX_WIDTH                7  /* WSEQ_START_INDEX - [6:0] */
-
-/*
- * R273 (0x111) - Write Sequencer Ctrl (2)
- */
-#define WM8915_WSEQ_BUSY                        0x0100  /* WSEQ_BUSY */
-#define WM8915_WSEQ_BUSY_MASK                   0x0100  /* WSEQ_BUSY */
-#define WM8915_WSEQ_BUSY_SHIFT                       8  /* WSEQ_BUSY */
-#define WM8915_WSEQ_BUSY_WIDTH                       1  /* WSEQ_BUSY */
-#define WM8915_WSEQ_CURRENT_INDEX_MASK          0x007F  /* WSEQ_CURRENT_INDEX - [6:0] */
-#define WM8915_WSEQ_CURRENT_INDEX_SHIFT              0  /* WSEQ_CURRENT_INDEX - [6:0] */
-#define WM8915_WSEQ_CURRENT_INDEX_WIDTH              7  /* WSEQ_CURRENT_INDEX - [6:0] */
-
-/*
- * R512 (0x200) - AIF Clocking (1)
- */
-#define WM8915_SYSCLK_SRC_MASK                  0x0018  /* SYSCLK_SRC - [4:3] */
-#define WM8915_SYSCLK_SRC_SHIFT                      3  /* SYSCLK_SRC - [4:3] */
-#define WM8915_SYSCLK_SRC_WIDTH                      2  /* SYSCLK_SRC - [4:3] */
-#define WM8915_SYSCLK_INV                       0x0004  /* SYSCLK_INV */
-#define WM8915_SYSCLK_INV_MASK                  0x0004  /* SYSCLK_INV */
-#define WM8915_SYSCLK_INV_SHIFT                      2  /* SYSCLK_INV */
-#define WM8915_SYSCLK_INV_WIDTH                      1  /* SYSCLK_INV */
-#define WM8915_SYSCLK_DIV                       0x0002  /* SYSCLK_DIV */
-#define WM8915_SYSCLK_DIV_MASK                  0x0002  /* SYSCLK_DIV */
-#define WM8915_SYSCLK_DIV_SHIFT                      1  /* SYSCLK_DIV */
-#define WM8915_SYSCLK_DIV_WIDTH                      1  /* SYSCLK_DIV */
-#define WM8915_SYSCLK_ENA                       0x0001  /* SYSCLK_ENA */
-#define WM8915_SYSCLK_ENA_MASK                  0x0001  /* SYSCLK_ENA */
-#define WM8915_SYSCLK_ENA_SHIFT                      0  /* SYSCLK_ENA */
-#define WM8915_SYSCLK_ENA_WIDTH                      1  /* SYSCLK_ENA */
-
-/*
- * R513 (0x201) - AIF Clocking (2)
- */
-#define WM8915_DSP2_DIV_MASK                    0x0018  /* DSP2_DIV - [4:3] */
-#define WM8915_DSP2_DIV_SHIFT                        3  /* DSP2_DIV - [4:3] */
-#define WM8915_DSP2_DIV_WIDTH                        2  /* DSP2_DIV - [4:3] */
-#define WM8915_DSP1_DIV_MASK                    0x0003  /* DSP1_DIV - [1:0] */
-#define WM8915_DSP1_DIV_SHIFT                        0  /* DSP1_DIV - [1:0] */
-#define WM8915_DSP1_DIV_WIDTH                        2  /* DSP1_DIV - [1:0] */
-
-/*
- * R520 (0x208) - Clocking (1)
- */
-#define WM8915_LFCLK_ENA                        0x0020  /* LFCLK_ENA */
-#define WM8915_LFCLK_ENA_MASK                   0x0020  /* LFCLK_ENA */
-#define WM8915_LFCLK_ENA_SHIFT                       5  /* LFCLK_ENA */
-#define WM8915_LFCLK_ENA_WIDTH                       1  /* LFCLK_ENA */
-#define WM8915_TOCLK_ENA                        0x0010  /* TOCLK_ENA */
-#define WM8915_TOCLK_ENA_MASK                   0x0010  /* TOCLK_ENA */
-#define WM8915_TOCLK_ENA_SHIFT                       4  /* TOCLK_ENA */
-#define WM8915_TOCLK_ENA_WIDTH                       1  /* TOCLK_ENA */
-#define WM8915_AIFCLK_ENA                       0x0004  /* AIFCLK_ENA */
-#define WM8915_AIFCLK_ENA_MASK                  0x0004  /* AIFCLK_ENA */
-#define WM8915_AIFCLK_ENA_SHIFT                      2  /* AIFCLK_ENA */
-#define WM8915_AIFCLK_ENA_WIDTH                      1  /* AIFCLK_ENA */
-#define WM8915_SYSDSPCLK_ENA                    0x0002  /* SYSDSPCLK_ENA */
-#define WM8915_SYSDSPCLK_ENA_MASK               0x0002  /* SYSDSPCLK_ENA */
-#define WM8915_SYSDSPCLK_ENA_SHIFT                   1  /* SYSDSPCLK_ENA */
-#define WM8915_SYSDSPCLK_ENA_WIDTH                   1  /* SYSDSPCLK_ENA */
-
-/*
- * R521 (0x209) - Clocking (2)
- */
-#define WM8915_TOCLK_DIV_MASK                   0x0700  /* TOCLK_DIV - [10:8] */
-#define WM8915_TOCLK_DIV_SHIFT                       8  /* TOCLK_DIV - [10:8] */
-#define WM8915_TOCLK_DIV_WIDTH                       3  /* TOCLK_DIV - [10:8] */
-#define WM8915_DBCLK_DIV_MASK                   0x00F0  /* DBCLK_DIV - [7:4] */
-#define WM8915_DBCLK_DIV_SHIFT                       4  /* DBCLK_DIV - [7:4] */
-#define WM8915_DBCLK_DIV_WIDTH                       4  /* DBCLK_DIV - [7:4] */
-#define WM8915_OPCLK_DIV_MASK                   0x0007  /* OPCLK_DIV - [2:0] */
-#define WM8915_OPCLK_DIV_SHIFT                       0  /* OPCLK_DIV - [2:0] */
-#define WM8915_OPCLK_DIV_WIDTH                       3  /* OPCLK_DIV - [2:0] */
-
-/*
- * R528 (0x210) - AIF Rate
- */
-#define WM8915_SYSCLK_RATE                      0x0001  /* SYSCLK_RATE */
-#define WM8915_SYSCLK_RATE_MASK                 0x0001  /* SYSCLK_RATE */
-#define WM8915_SYSCLK_RATE_SHIFT                     0  /* SYSCLK_RATE */
-#define WM8915_SYSCLK_RATE_WIDTH                     1  /* SYSCLK_RATE */
-
-/*
- * R544 (0x220) - FLL Control (1)
- */
-#define WM8915_FLL_OSC_ENA                      0x0002  /* FLL_OSC_ENA */
-#define WM8915_FLL_OSC_ENA_MASK                 0x0002  /* FLL_OSC_ENA */
-#define WM8915_FLL_OSC_ENA_SHIFT                     1  /* FLL_OSC_ENA */
-#define WM8915_FLL_OSC_ENA_WIDTH                     1  /* FLL_OSC_ENA */
-#define WM8915_FLL_ENA                          0x0001  /* FLL_ENA */
-#define WM8915_FLL_ENA_MASK                     0x0001  /* FLL_ENA */
-#define WM8915_FLL_ENA_SHIFT                         0  /* FLL_ENA */
-#define WM8915_FLL_ENA_WIDTH                         1  /* FLL_ENA */
-
-/*
- * R545 (0x221) - FLL Control (2)
- */
-#define WM8915_FLL_OUTDIV_MASK                  0x3F00  /* FLL_OUTDIV - [13:8] */
-#define WM8915_FLL_OUTDIV_SHIFT                      8  /* FLL_OUTDIV - [13:8] */
-#define WM8915_FLL_OUTDIV_WIDTH                      6  /* FLL_OUTDIV - [13:8] */
-#define WM8915_FLL_FRATIO_MASK                  0x0007  /* FLL_FRATIO - [2:0] */
-#define WM8915_FLL_FRATIO_SHIFT                      0  /* FLL_FRATIO - [2:0] */
-#define WM8915_FLL_FRATIO_WIDTH                      3  /* FLL_FRATIO - [2:0] */
-
-/*
- * R546 (0x222) - FLL Control (3)
- */
-#define WM8915_FLL_THETA_MASK                   0xFFFF  /* FLL_THETA - [15:0] */
-#define WM8915_FLL_THETA_SHIFT                       0  /* FLL_THETA - [15:0] */
-#define WM8915_FLL_THETA_WIDTH                      16  /* FLL_THETA - [15:0] */
-
-/*
- * R547 (0x223) - FLL Control (4)
- */
-#define WM8915_FLL_N_MASK                       0x7FE0  /* FLL_N - [14:5] */
-#define WM8915_FLL_N_SHIFT                           5  /* FLL_N - [14:5] */
-#define WM8915_FLL_N_WIDTH                          10  /* FLL_N - [14:5] */
-#define WM8915_FLL_LOOP_GAIN_MASK               0x000F  /* FLL_LOOP_GAIN - [3:0] */
-#define WM8915_FLL_LOOP_GAIN_SHIFT                   0  /* FLL_LOOP_GAIN - [3:0] */
-#define WM8915_FLL_LOOP_GAIN_WIDTH                   4  /* FLL_LOOP_GAIN - [3:0] */
-
-/*
- * R548 (0x224) - FLL Control (5)
- */
-#define WM8915_FLL_FRC_NCO_VAL_MASK             0x1F80  /* FLL_FRC_NCO_VAL - [12:7] */
-#define WM8915_FLL_FRC_NCO_VAL_SHIFT                 7  /* FLL_FRC_NCO_VAL - [12:7] */
-#define WM8915_FLL_FRC_NCO_VAL_WIDTH                 6  /* FLL_FRC_NCO_VAL - [12:7] */
-#define WM8915_FLL_FRC_NCO                      0x0040  /* FLL_FRC_NCO */
-#define WM8915_FLL_FRC_NCO_MASK                 0x0040  /* FLL_FRC_NCO */
-#define WM8915_FLL_FRC_NCO_SHIFT                     6  /* FLL_FRC_NCO */
-#define WM8915_FLL_FRC_NCO_WIDTH                     1  /* FLL_FRC_NCO */
-#define WM8915_FLL_REFCLK_DIV_MASK              0x0018  /* FLL_REFCLK_DIV - [4:3] */
-#define WM8915_FLL_REFCLK_DIV_SHIFT                  3  /* FLL_REFCLK_DIV - [4:3] */
-#define WM8915_FLL_REFCLK_DIV_WIDTH                  2  /* FLL_REFCLK_DIV - [4:3] */
-#define WM8915_FLL_REF_FREQ                     0x0004  /* FLL_REF_FREQ */
-#define WM8915_FLL_REF_FREQ_MASK                0x0004  /* FLL_REF_FREQ */
-#define WM8915_FLL_REF_FREQ_SHIFT                    2  /* FLL_REF_FREQ */
-#define WM8915_FLL_REF_FREQ_WIDTH                    1  /* FLL_REF_FREQ */
-#define WM8915_FLL_REFCLK_SRC_MASK              0x0003  /* FLL_REFCLK_SRC - [1:0] */
-#define WM8915_FLL_REFCLK_SRC_SHIFT                  0  /* FLL_REFCLK_SRC - [1:0] */
-#define WM8915_FLL_REFCLK_SRC_WIDTH                  2  /* FLL_REFCLK_SRC - [1:0] */
-
-/*
- * R549 (0x225) - FLL Control (6)
- */
-#define WM8915_FLL_REFCLK_SRC_STS_MASK          0x000C  /* FLL_REFCLK_SRC_STS - [3:2] */
-#define WM8915_FLL_REFCLK_SRC_STS_SHIFT              2  /* FLL_REFCLK_SRC_STS - [3:2] */
-#define WM8915_FLL_REFCLK_SRC_STS_WIDTH              2  /* FLL_REFCLK_SRC_STS - [3:2] */
-#define WM8915_FLL_SWITCH_CLK                   0x0001  /* FLL_SWITCH_CLK */
-#define WM8915_FLL_SWITCH_CLK_MASK              0x0001  /* FLL_SWITCH_CLK */
-#define WM8915_FLL_SWITCH_CLK_SHIFT                  0  /* FLL_SWITCH_CLK */
-#define WM8915_FLL_SWITCH_CLK_WIDTH                  1  /* FLL_SWITCH_CLK */
-
-/*
- * R550 (0x226) - FLL EFS 1
- */
-#define WM8915_FLL_LAMBDA_MASK                  0xFFFF  /* FLL_LAMBDA - [15:0] */
-#define WM8915_FLL_LAMBDA_SHIFT                      0  /* FLL_LAMBDA - [15:0] */
-#define WM8915_FLL_LAMBDA_WIDTH                     16  /* FLL_LAMBDA - [15:0] */
-
-/*
- * R551 (0x227) - FLL EFS 2
- */
-#define WM8915_FLL_LFSR_SEL_MASK                0x0006  /* FLL_LFSR_SEL - [2:1] */
-#define WM8915_FLL_LFSR_SEL_SHIFT                    1  /* FLL_LFSR_SEL - [2:1] */
-#define WM8915_FLL_LFSR_SEL_WIDTH                    2  /* FLL_LFSR_SEL - [2:1] */
-#define WM8915_FLL_EFS_ENA                      0x0001  /* FLL_EFS_ENA */
-#define WM8915_FLL_EFS_ENA_MASK                 0x0001  /* FLL_EFS_ENA */
-#define WM8915_FLL_EFS_ENA_SHIFT                     0  /* FLL_EFS_ENA */
-#define WM8915_FLL_EFS_ENA_WIDTH                     1  /* FLL_EFS_ENA */
-
-/*
- * R768 (0x300) - AIF1 Control
- */
-#define WM8915_AIF1_TRI                         0x0004  /* AIF1_TRI */
-#define WM8915_AIF1_TRI_MASK                    0x0004  /* AIF1_TRI */
-#define WM8915_AIF1_TRI_SHIFT                        2  /* AIF1_TRI */
-#define WM8915_AIF1_TRI_WIDTH                        1  /* AIF1_TRI */
-#define WM8915_AIF1_FMT_MASK                    0x0003  /* AIF1_FMT - [1:0] */
-#define WM8915_AIF1_FMT_SHIFT                        0  /* AIF1_FMT - [1:0] */
-#define WM8915_AIF1_FMT_WIDTH                        2  /* AIF1_FMT - [1:0] */
-
-/*
- * R769 (0x301) - AIF1 BCLK
- */
-#define WM8915_AIF1_BCLK_INV                    0x0400  /* AIF1_BCLK_INV */
-#define WM8915_AIF1_BCLK_INV_MASK               0x0400  /* AIF1_BCLK_INV */
-#define WM8915_AIF1_BCLK_INV_SHIFT                  10  /* AIF1_BCLK_INV */
-#define WM8915_AIF1_BCLK_INV_WIDTH                   1  /* AIF1_BCLK_INV */
-#define WM8915_AIF1_BCLK_FRC                    0x0200  /* AIF1_BCLK_FRC */
-#define WM8915_AIF1_BCLK_FRC_MASK               0x0200  /* AIF1_BCLK_FRC */
-#define WM8915_AIF1_BCLK_FRC_SHIFT                   9  /* AIF1_BCLK_FRC */
-#define WM8915_AIF1_BCLK_FRC_WIDTH                   1  /* AIF1_BCLK_FRC */
-#define WM8915_AIF1_BCLK_MSTR                   0x0100  /* AIF1_BCLK_MSTR */
-#define WM8915_AIF1_BCLK_MSTR_MASK              0x0100  /* AIF1_BCLK_MSTR */
-#define WM8915_AIF1_BCLK_MSTR_SHIFT                  8  /* AIF1_BCLK_MSTR */
-#define WM8915_AIF1_BCLK_MSTR_WIDTH                  1  /* AIF1_BCLK_MSTR */
-#define WM8915_AIF1_BCLK_DIV_MASK               0x000F  /* AIF1_BCLK_DIV - [3:0] */
-#define WM8915_AIF1_BCLK_DIV_SHIFT                   0  /* AIF1_BCLK_DIV - [3:0] */
-#define WM8915_AIF1_BCLK_DIV_WIDTH                   4  /* AIF1_BCLK_DIV - [3:0] */
-
-/*
- * R770 (0x302) - AIF1 TX LRCLK(1)
- */
-#define WM8915_AIF1TX_RATE_MASK                 0x07FF  /* AIF1TX_RATE - [10:0] */
-#define WM8915_AIF1TX_RATE_SHIFT                     0  /* AIF1TX_RATE - [10:0] */
-#define WM8915_AIF1TX_RATE_WIDTH                    11  /* AIF1TX_RATE - [10:0] */
-
-/*
- * R771 (0x303) - AIF1 TX LRCLK(2)
- */
-#define WM8915_AIF1TX_LRCLK_MODE                0x0008  /* AIF1TX_LRCLK_MODE */
-#define WM8915_AIF1TX_LRCLK_MODE_MASK           0x0008  /* AIF1TX_LRCLK_MODE */
-#define WM8915_AIF1TX_LRCLK_MODE_SHIFT               3  /* AIF1TX_LRCLK_MODE */
-#define WM8915_AIF1TX_LRCLK_MODE_WIDTH               1  /* AIF1TX_LRCLK_MODE */
-#define WM8915_AIF1TX_LRCLK_INV                 0x0004  /* AIF1TX_LRCLK_INV */
-#define WM8915_AIF1TX_LRCLK_INV_MASK            0x0004  /* AIF1TX_LRCLK_INV */
-#define WM8915_AIF1TX_LRCLK_INV_SHIFT                2  /* AIF1TX_LRCLK_INV */
-#define WM8915_AIF1TX_LRCLK_INV_WIDTH                1  /* AIF1TX_LRCLK_INV */
-#define WM8915_AIF1TX_LRCLK_FRC                 0x0002  /* AIF1TX_LRCLK_FRC */
-#define WM8915_AIF1TX_LRCLK_FRC_MASK            0x0002  /* AIF1TX_LRCLK_FRC */
-#define WM8915_AIF1TX_LRCLK_FRC_SHIFT                1  /* AIF1TX_LRCLK_FRC */
-#define WM8915_AIF1TX_LRCLK_FRC_WIDTH                1  /* AIF1TX_LRCLK_FRC */
-#define WM8915_AIF1TX_LRCLK_MSTR                0x0001  /* AIF1TX_LRCLK_MSTR */
-#define WM8915_AIF1TX_LRCLK_MSTR_MASK           0x0001  /* AIF1TX_LRCLK_MSTR */
-#define WM8915_AIF1TX_LRCLK_MSTR_SHIFT               0  /* AIF1TX_LRCLK_MSTR */
-#define WM8915_AIF1TX_LRCLK_MSTR_WIDTH               1  /* AIF1TX_LRCLK_MSTR */
-
-/*
- * R772 (0x304) - AIF1 RX LRCLK(1)
- */
-#define WM8915_AIF1RX_RATE_MASK                 0x07FF  /* AIF1RX_RATE - [10:0] */
-#define WM8915_AIF1RX_RATE_SHIFT                     0  /* AIF1RX_RATE - [10:0] */
-#define WM8915_AIF1RX_RATE_WIDTH                    11  /* AIF1RX_RATE - [10:0] */
-
-/*
- * R773 (0x305) - AIF1 RX LRCLK(2)
- */
-#define WM8915_AIF1RX_LRCLK_INV                 0x0004  /* AIF1RX_LRCLK_INV */
-#define WM8915_AIF1RX_LRCLK_INV_MASK            0x0004  /* AIF1RX_LRCLK_INV */
-#define WM8915_AIF1RX_LRCLK_INV_SHIFT                2  /* AIF1RX_LRCLK_INV */
-#define WM8915_AIF1RX_LRCLK_INV_WIDTH                1  /* AIF1RX_LRCLK_INV */
-#define WM8915_AIF1RX_LRCLK_FRC                 0x0002  /* AIF1RX_LRCLK_FRC */
-#define WM8915_AIF1RX_LRCLK_FRC_MASK            0x0002  /* AIF1RX_LRCLK_FRC */
-#define WM8915_AIF1RX_LRCLK_FRC_SHIFT                1  /* AIF1RX_LRCLK_FRC */
-#define WM8915_AIF1RX_LRCLK_FRC_WIDTH                1  /* AIF1RX_LRCLK_FRC */
-#define WM8915_AIF1RX_LRCLK_MSTR                0x0001  /* AIF1RX_LRCLK_MSTR */
-#define WM8915_AIF1RX_LRCLK_MSTR_MASK           0x0001  /* AIF1RX_LRCLK_MSTR */
-#define WM8915_AIF1RX_LRCLK_MSTR_SHIFT               0  /* AIF1RX_LRCLK_MSTR */
-#define WM8915_AIF1RX_LRCLK_MSTR_WIDTH               1  /* AIF1RX_LRCLK_MSTR */
-
-/*
- * R774 (0x306) - AIF1TX Data Configuration (1)
- */
-#define WM8915_AIF1TX_WL_MASK                   0xFF00  /* AIF1TX_WL - [15:8] */
-#define WM8915_AIF1TX_WL_SHIFT                       8  /* AIF1TX_WL - [15:8] */
-#define WM8915_AIF1TX_WL_WIDTH                       8  /* AIF1TX_WL - [15:8] */
-#define WM8915_AIF1TX_SLOT_LEN_MASK             0x00FF  /* AIF1TX_SLOT_LEN - [7:0] */
-#define WM8915_AIF1TX_SLOT_LEN_SHIFT                 0  /* AIF1TX_SLOT_LEN - [7:0] */
-#define WM8915_AIF1TX_SLOT_LEN_WIDTH                 8  /* AIF1TX_SLOT_LEN - [7:0] */
-
-/*
- * R775 (0x307) - AIF1TX Data Configuration (2)
- */
-#define WM8915_AIF1TX_DAT_TRI                   0x0001  /* AIF1TX_DAT_TRI */
-#define WM8915_AIF1TX_DAT_TRI_MASK              0x0001  /* AIF1TX_DAT_TRI */
-#define WM8915_AIF1TX_DAT_TRI_SHIFT                  0  /* AIF1TX_DAT_TRI */
-#define WM8915_AIF1TX_DAT_TRI_WIDTH                  1  /* AIF1TX_DAT_TRI */
-
-/*
- * R776 (0x308) - AIF1RX Data Configuration
- */
-#define WM8915_AIF1RX_WL_MASK                   0xFF00  /* AIF1RX_WL - [15:8] */
-#define WM8915_AIF1RX_WL_SHIFT                       8  /* AIF1RX_WL - [15:8] */
-#define WM8915_AIF1RX_WL_WIDTH                       8  /* AIF1RX_WL - [15:8] */
-#define WM8915_AIF1RX_SLOT_LEN_MASK             0x00FF  /* AIF1RX_SLOT_LEN - [7:0] */
-#define WM8915_AIF1RX_SLOT_LEN_SHIFT                 0  /* AIF1RX_SLOT_LEN - [7:0] */
-#define WM8915_AIF1RX_SLOT_LEN_WIDTH                 8  /* AIF1RX_SLOT_LEN - [7:0] */
-
-/*
- * R777 (0x309) - AIF1TX Channel 0 Configuration
- */
-#define WM8915_AIF1TX_CHAN0_DAT_INV             0x8000  /* AIF1TX_CHAN0_DAT_INV */
-#define WM8915_AIF1TX_CHAN0_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN0_DAT_INV */
-#define WM8915_AIF1TX_CHAN0_DAT_INV_SHIFT           15  /* AIF1TX_CHAN0_DAT_INV */
-#define WM8915_AIF1TX_CHAN0_DAT_INV_WIDTH            1  /* AIF1TX_CHAN0_DAT_INV */
-#define WM8915_AIF1TX_CHAN0_SPACING_MASK        0x7E00  /* AIF1TX_CHAN0_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN0_SPACING_SHIFT            9  /* AIF1TX_CHAN0_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN0_SPACING_WIDTH            6  /* AIF1TX_CHAN0_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN0_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN0_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN0_SLOTS_SHIFT              6  /* AIF1TX_CHAN0_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN0_SLOTS_WIDTH              3  /* AIF1TX_CHAN0_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN0_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN0_START_SLOT - [5:0] */
-#define WM8915_AIF1TX_CHAN0_START_SLOT_SHIFT         0  /* AIF1TX_CHAN0_START_SLOT - [5:0] */
-#define WM8915_AIF1TX_CHAN0_START_SLOT_WIDTH         6  /* AIF1TX_CHAN0_START_SLOT - [5:0] */
-
-/*
- * R778 (0x30A) - AIF1TX Channel 1 Configuration
- */
-#define WM8915_AIF1TX_CHAN1_DAT_INV             0x8000  /* AIF1TX_CHAN1_DAT_INV */
-#define WM8915_AIF1TX_CHAN1_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN1_DAT_INV */
-#define WM8915_AIF1TX_CHAN1_DAT_INV_SHIFT           15  /* AIF1TX_CHAN1_DAT_INV */
-#define WM8915_AIF1TX_CHAN1_DAT_INV_WIDTH            1  /* AIF1TX_CHAN1_DAT_INV */
-#define WM8915_AIF1TX_CHAN1_SPACING_MASK        0x7E00  /* AIF1TX_CHAN1_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN1_SPACING_SHIFT            9  /* AIF1TX_CHAN1_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN1_SPACING_WIDTH            6  /* AIF1TX_CHAN1_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN1_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN1_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN1_SLOTS_SHIFT              6  /* AIF1TX_CHAN1_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN1_SLOTS_WIDTH              3  /* AIF1TX_CHAN1_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN1_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN1_START_SLOT - [5:0] */
-#define WM8915_AIF1TX_CHAN1_START_SLOT_SHIFT         0  /* AIF1TX_CHAN1_START_SLOT - [5:0] */
-#define WM8915_AIF1TX_CHAN1_START_SLOT_WIDTH         6  /* AIF1TX_CHAN1_START_SLOT - [5:0] */
-
-/*
- * R779 (0x30B) - AIF1TX Channel 2 Configuration
- */
-#define WM8915_AIF1TX_CHAN2_DAT_INV             0x8000  /* AIF1TX_CHAN2_DAT_INV */
-#define WM8915_AIF1TX_CHAN2_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN2_DAT_INV */
-#define WM8915_AIF1TX_CHAN2_DAT_INV_SHIFT           15  /* AIF1TX_CHAN2_DAT_INV */
-#define WM8915_AIF1TX_CHAN2_DAT_INV_WIDTH            1  /* AIF1TX_CHAN2_DAT_INV */
-#define WM8915_AIF1TX_CHAN2_SPACING_MASK        0x7E00  /* AIF1TX_CHAN2_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN2_SPACING_SHIFT            9  /* AIF1TX_CHAN2_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN2_SPACING_WIDTH            6  /* AIF1TX_CHAN2_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN2_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN2_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN2_SLOTS_SHIFT              6  /* AIF1TX_CHAN2_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN2_SLOTS_WIDTH              3  /* AIF1TX_CHAN2_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN2_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN2_START_SLOT - [5:0] */
-#define WM8915_AIF1TX_CHAN2_START_SLOT_SHIFT         0  /* AIF1TX_CHAN2_START_SLOT - [5:0] */
-#define WM8915_AIF1TX_CHAN2_START_SLOT_WIDTH         6  /* AIF1TX_CHAN2_START_SLOT - [5:0] */
-
-/*
- * R780 (0x30C) - AIF1TX Channel 3 Configuration
- */
-#define WM8915_AIF1TX_CHAN3_DAT_INV             0x8000  /* AIF1TX_CHAN3_DAT_INV */
-#define WM8915_AIF1TX_CHAN3_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN3_DAT_INV */
-#define WM8915_AIF1TX_CHAN3_DAT_INV_SHIFT           15  /* AIF1TX_CHAN3_DAT_INV */
-#define WM8915_AIF1TX_CHAN3_DAT_INV_WIDTH            1  /* AIF1TX_CHAN3_DAT_INV */
-#define WM8915_AIF1TX_CHAN3_SPACING_MASK        0x7E00  /* AIF1TX_CHAN3_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN3_SPACING_SHIFT            9  /* AIF1TX_CHAN3_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN3_SPACING_WIDTH            6  /* AIF1TX_CHAN3_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN3_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN3_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN3_SLOTS_SHIFT              6  /* AIF1TX_CHAN3_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN3_SLOTS_WIDTH              3  /* AIF1TX_CHAN3_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN3_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN3_START_SLOT - [5:0] */
-#define WM8915_AIF1TX_CHAN3_START_SLOT_SHIFT         0  /* AIF1TX_CHAN3_START_SLOT - [5:0] */
-#define WM8915_AIF1TX_CHAN3_START_SLOT_WIDTH         6  /* AIF1TX_CHAN3_START_SLOT - [5:0] */
-
-/*
- * R781 (0x30D) - AIF1TX Channel 4 Configuration
- */
-#define WM8915_AIF1TX_CHAN4_DAT_INV             0x8000  /* AIF1TX_CHAN4_DAT_INV */
-#define WM8915_AIF1TX_CHAN4_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN4_DAT_INV */
-#define WM8915_AIF1TX_CHAN4_DAT_INV_SHIFT           15  /* AIF1TX_CHAN4_DAT_INV */
-#define WM8915_AIF1TX_CHAN4_DAT_INV_WIDTH            1  /* AIF1TX_CHAN4_DAT_INV */
-#define WM8915_AIF1TX_CHAN4_SPACING_MASK        0x7E00  /* AIF1TX_CHAN4_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN4_SPACING_SHIFT            9  /* AIF1TX_CHAN4_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN4_SPACING_WIDTH            6  /* AIF1TX_CHAN4_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN4_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN4_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN4_SLOTS_SHIFT              6  /* AIF1TX_CHAN4_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN4_SLOTS_WIDTH              3  /* AIF1TX_CHAN4_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN4_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN4_START_SLOT - [5:0] */
-#define WM8915_AIF1TX_CHAN4_START_SLOT_SHIFT         0  /* AIF1TX_CHAN4_START_SLOT - [5:0] */
-#define WM8915_AIF1TX_CHAN4_START_SLOT_WIDTH         6  /* AIF1TX_CHAN4_START_SLOT - [5:0] */
-
-/*
- * R782 (0x30E) - AIF1TX Channel 5 Configuration
- */
-#define WM8915_AIF1TX_CHAN5_DAT_INV             0x8000  /* AIF1TX_CHAN5_DAT_INV */
-#define WM8915_AIF1TX_CHAN5_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN5_DAT_INV */
-#define WM8915_AIF1TX_CHAN5_DAT_INV_SHIFT           15  /* AIF1TX_CHAN5_DAT_INV */
-#define WM8915_AIF1TX_CHAN5_DAT_INV_WIDTH            1  /* AIF1TX_CHAN5_DAT_INV */
-#define WM8915_AIF1TX_CHAN5_SPACING_MASK        0x7E00  /* AIF1TX_CHAN5_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN5_SPACING_SHIFT            9  /* AIF1TX_CHAN5_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN5_SPACING_WIDTH            6  /* AIF1TX_CHAN5_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN5_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN5_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN5_SLOTS_SHIFT              6  /* AIF1TX_CHAN5_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN5_SLOTS_WIDTH              3  /* AIF1TX_CHAN5_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN5_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN5_START_SLOT - [5:0] */
-#define WM8915_AIF1TX_CHAN5_START_SLOT_SHIFT         0  /* AIF1TX_CHAN5_START_SLOT - [5:0] */
-#define WM8915_AIF1TX_CHAN5_START_SLOT_WIDTH         6  /* AIF1TX_CHAN5_START_SLOT - [5:0] */
-
-/*
- * R783 (0x30F) - AIF1RX Channel 0 Configuration
- */
-#define WM8915_AIF1RX_CHAN0_DAT_INV             0x8000  /* AIF1RX_CHAN0_DAT_INV */
-#define WM8915_AIF1RX_CHAN0_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN0_DAT_INV */
-#define WM8915_AIF1RX_CHAN0_DAT_INV_SHIFT           15  /* AIF1RX_CHAN0_DAT_INV */
-#define WM8915_AIF1RX_CHAN0_DAT_INV_WIDTH            1  /* AIF1RX_CHAN0_DAT_INV */
-#define WM8915_AIF1RX_CHAN0_SPACING_MASK        0x7E00  /* AIF1RX_CHAN0_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN0_SPACING_SHIFT            9  /* AIF1RX_CHAN0_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN0_SPACING_WIDTH            6  /* AIF1RX_CHAN0_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN0_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN0_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN0_SLOTS_SHIFT              6  /* AIF1RX_CHAN0_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN0_SLOTS_WIDTH              3  /* AIF1RX_CHAN0_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN0_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN0_START_SLOT - [5:0] */
-#define WM8915_AIF1RX_CHAN0_START_SLOT_SHIFT         0  /* AIF1RX_CHAN0_START_SLOT - [5:0] */
-#define WM8915_AIF1RX_CHAN0_START_SLOT_WIDTH         6  /* AIF1RX_CHAN0_START_SLOT - [5:0] */
-
-/*
- * R784 (0x310) - AIF1RX Channel 1 Configuration
- */
-#define WM8915_AIF1RX_CHAN1_DAT_INV             0x8000  /* AIF1RX_CHAN1_DAT_INV */
-#define WM8915_AIF1RX_CHAN1_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN1_DAT_INV */
-#define WM8915_AIF1RX_CHAN1_DAT_INV_SHIFT           15  /* AIF1RX_CHAN1_DAT_INV */
-#define WM8915_AIF1RX_CHAN1_DAT_INV_WIDTH            1  /* AIF1RX_CHAN1_DAT_INV */
-#define WM8915_AIF1RX_CHAN1_SPACING_MASK        0x7E00  /* AIF1RX_CHAN1_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN1_SPACING_SHIFT            9  /* AIF1RX_CHAN1_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN1_SPACING_WIDTH            6  /* AIF1RX_CHAN1_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN1_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN1_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN1_SLOTS_SHIFT              6  /* AIF1RX_CHAN1_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN1_SLOTS_WIDTH              3  /* AIF1RX_CHAN1_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN1_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN1_START_SLOT - [5:0] */
-#define WM8915_AIF1RX_CHAN1_START_SLOT_SHIFT         0  /* AIF1RX_CHAN1_START_SLOT - [5:0] */
-#define WM8915_AIF1RX_CHAN1_START_SLOT_WIDTH         6  /* AIF1RX_CHAN1_START_SLOT - [5:0] */
-
-/*
- * R785 (0x311) - AIF1RX Channel 2 Configuration
- */
-#define WM8915_AIF1RX_CHAN2_DAT_INV             0x8000  /* AIF1RX_CHAN2_DAT_INV */
-#define WM8915_AIF1RX_CHAN2_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN2_DAT_INV */
-#define WM8915_AIF1RX_CHAN2_DAT_INV_SHIFT           15  /* AIF1RX_CHAN2_DAT_INV */
-#define WM8915_AIF1RX_CHAN2_DAT_INV_WIDTH            1  /* AIF1RX_CHAN2_DAT_INV */
-#define WM8915_AIF1RX_CHAN2_SPACING_MASK        0x7E00  /* AIF1RX_CHAN2_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN2_SPACING_SHIFT            9  /* AIF1RX_CHAN2_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN2_SPACING_WIDTH            6  /* AIF1RX_CHAN2_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN2_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN2_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN2_SLOTS_SHIFT              6  /* AIF1RX_CHAN2_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN2_SLOTS_WIDTH              3  /* AIF1RX_CHAN2_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN2_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN2_START_SLOT - [5:0] */
-#define WM8915_AIF1RX_CHAN2_START_SLOT_SHIFT         0  /* AIF1RX_CHAN2_START_SLOT - [5:0] */
-#define WM8915_AIF1RX_CHAN2_START_SLOT_WIDTH         6  /* AIF1RX_CHAN2_START_SLOT - [5:0] */
-
-/*
- * R786 (0x312) - AIF1RX Channel 3 Configuration
- */
-#define WM8915_AIF1RX_CHAN3_DAT_INV             0x8000  /* AIF1RX_CHAN3_DAT_INV */
-#define WM8915_AIF1RX_CHAN3_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN3_DAT_INV */
-#define WM8915_AIF1RX_CHAN3_DAT_INV_SHIFT           15  /* AIF1RX_CHAN3_DAT_INV */
-#define WM8915_AIF1RX_CHAN3_DAT_INV_WIDTH            1  /* AIF1RX_CHAN3_DAT_INV */
-#define WM8915_AIF1RX_CHAN3_SPACING_MASK        0x7E00  /* AIF1RX_CHAN3_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN3_SPACING_SHIFT            9  /* AIF1RX_CHAN3_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN3_SPACING_WIDTH            6  /* AIF1RX_CHAN3_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN3_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN3_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN3_SLOTS_SHIFT              6  /* AIF1RX_CHAN3_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN3_SLOTS_WIDTH              3  /* AIF1RX_CHAN3_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN3_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN3_START_SLOT - [5:0] */
-#define WM8915_AIF1RX_CHAN3_START_SLOT_SHIFT         0  /* AIF1RX_CHAN3_START_SLOT - [5:0] */
-#define WM8915_AIF1RX_CHAN3_START_SLOT_WIDTH         6  /* AIF1RX_CHAN3_START_SLOT - [5:0] */
-
-/*
- * R787 (0x313) - AIF1RX Channel 4 Configuration
- */
-#define WM8915_AIF1RX_CHAN4_DAT_INV             0x8000  /* AIF1RX_CHAN4_DAT_INV */
-#define WM8915_AIF1RX_CHAN4_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN4_DAT_INV */
-#define WM8915_AIF1RX_CHAN4_DAT_INV_SHIFT           15  /* AIF1RX_CHAN4_DAT_INV */
-#define WM8915_AIF1RX_CHAN4_DAT_INV_WIDTH            1  /* AIF1RX_CHAN4_DAT_INV */
-#define WM8915_AIF1RX_CHAN4_SPACING_MASK        0x7E00  /* AIF1RX_CHAN4_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN4_SPACING_SHIFT            9  /* AIF1RX_CHAN4_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN4_SPACING_WIDTH            6  /* AIF1RX_CHAN4_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN4_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN4_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN4_SLOTS_SHIFT              6  /* AIF1RX_CHAN4_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN4_SLOTS_WIDTH              3  /* AIF1RX_CHAN4_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN4_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN4_START_SLOT - [5:0] */
-#define WM8915_AIF1RX_CHAN4_START_SLOT_SHIFT         0  /* AIF1RX_CHAN4_START_SLOT - [5:0] */
-#define WM8915_AIF1RX_CHAN4_START_SLOT_WIDTH         6  /* AIF1RX_CHAN4_START_SLOT - [5:0] */
-
-/*
- * R788 (0x314) - AIF1RX Channel 5 Configuration
- */
-#define WM8915_AIF1RX_CHAN5_DAT_INV             0x8000  /* AIF1RX_CHAN5_DAT_INV */
-#define WM8915_AIF1RX_CHAN5_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN5_DAT_INV */
-#define WM8915_AIF1RX_CHAN5_DAT_INV_SHIFT           15  /* AIF1RX_CHAN5_DAT_INV */
-#define WM8915_AIF1RX_CHAN5_DAT_INV_WIDTH            1  /* AIF1RX_CHAN5_DAT_INV */
-#define WM8915_AIF1RX_CHAN5_SPACING_MASK        0x7E00  /* AIF1RX_CHAN5_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN5_SPACING_SHIFT            9  /* AIF1RX_CHAN5_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN5_SPACING_WIDTH            6  /* AIF1RX_CHAN5_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN5_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN5_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN5_SLOTS_SHIFT              6  /* AIF1RX_CHAN5_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN5_SLOTS_WIDTH              3  /* AIF1RX_CHAN5_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN5_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN5_START_SLOT - [5:0] */
-#define WM8915_AIF1RX_CHAN5_START_SLOT_SHIFT         0  /* AIF1RX_CHAN5_START_SLOT - [5:0] */
-#define WM8915_AIF1RX_CHAN5_START_SLOT_WIDTH         6  /* AIF1RX_CHAN5_START_SLOT - [5:0] */
-
-/*
- * R789 (0x315) - AIF1RX Mono Configuration
- */
-#define WM8915_AIF1RX_CHAN4_MONO_MODE           0x0004  /* AIF1RX_CHAN4_MONO_MODE */
-#define WM8915_AIF1RX_CHAN4_MONO_MODE_MASK      0x0004  /* AIF1RX_CHAN4_MONO_MODE */
-#define WM8915_AIF1RX_CHAN4_MONO_MODE_SHIFT          2  /* AIF1RX_CHAN4_MONO_MODE */
-#define WM8915_AIF1RX_CHAN4_MONO_MODE_WIDTH          1  /* AIF1RX_CHAN4_MONO_MODE */
-#define WM8915_AIF1RX_CHAN2_MONO_MODE           0x0002  /* AIF1RX_CHAN2_MONO_MODE */
-#define WM8915_AIF1RX_CHAN2_MONO_MODE_MASK      0x0002  /* AIF1RX_CHAN2_MONO_MODE */
-#define WM8915_AIF1RX_CHAN2_MONO_MODE_SHIFT          1  /* AIF1RX_CHAN2_MONO_MODE */
-#define WM8915_AIF1RX_CHAN2_MONO_MODE_WIDTH          1  /* AIF1RX_CHAN2_MONO_MODE */
-#define WM8915_AIF1RX_CHAN0_MONO_MODE           0x0001  /* AIF1RX_CHAN0_MONO_MODE */
-#define WM8915_AIF1RX_CHAN0_MONO_MODE_MASK      0x0001  /* AIF1RX_CHAN0_MONO_MODE */
-#define WM8915_AIF1RX_CHAN0_MONO_MODE_SHIFT          0  /* AIF1RX_CHAN0_MONO_MODE */
-#define WM8915_AIF1RX_CHAN0_MONO_MODE_WIDTH          1  /* AIF1RX_CHAN0_MONO_MODE */
-
-/*
- * R794 (0x31A) - AIF1TX Test
- */
-#define WM8915_AIF1TX45_DITHER_ENA              0x0004  /* AIF1TX45_DITHER_ENA */
-#define WM8915_AIF1TX45_DITHER_ENA_MASK         0x0004  /* AIF1TX45_DITHER_ENA */
-#define WM8915_AIF1TX45_DITHER_ENA_SHIFT             2  /* AIF1TX45_DITHER_ENA */
-#define WM8915_AIF1TX45_DITHER_ENA_WIDTH             1  /* AIF1TX45_DITHER_ENA */
-#define WM8915_AIF1TX23_DITHER_ENA              0x0002  /* AIF1TX23_DITHER_ENA */
-#define WM8915_AIF1TX23_DITHER_ENA_MASK         0x0002  /* AIF1TX23_DITHER_ENA */
-#define WM8915_AIF1TX23_DITHER_ENA_SHIFT             1  /* AIF1TX23_DITHER_ENA */
-#define WM8915_AIF1TX23_DITHER_ENA_WIDTH             1  /* AIF1TX23_DITHER_ENA */
-#define WM8915_AIF1TX01_DITHER_ENA              0x0001  /* AIF1TX01_DITHER_ENA */
-#define WM8915_AIF1TX01_DITHER_ENA_MASK         0x0001  /* AIF1TX01_DITHER_ENA */
-#define WM8915_AIF1TX01_DITHER_ENA_SHIFT             0  /* AIF1TX01_DITHER_ENA */
-#define WM8915_AIF1TX01_DITHER_ENA_WIDTH             1  /* AIF1TX01_DITHER_ENA */
-
-/*
- * R800 (0x320) - AIF2 Control
- */
-#define WM8915_AIF2_TRI                         0x0004  /* AIF2_TRI */
-#define WM8915_AIF2_TRI_MASK                    0x0004  /* AIF2_TRI */
-#define WM8915_AIF2_TRI_SHIFT                        2  /* AIF2_TRI */
-#define WM8915_AIF2_TRI_WIDTH                        1  /* AIF2_TRI */
-#define WM8915_AIF2_FMT_MASK                    0x0003  /* AIF2_FMT - [1:0] */
-#define WM8915_AIF2_FMT_SHIFT                        0  /* AIF2_FMT - [1:0] */
-#define WM8915_AIF2_FMT_WIDTH                        2  /* AIF2_FMT - [1:0] */
-
-/*
- * R801 (0x321) - AIF2 BCLK
- */
-#define WM8915_AIF2_BCLK_INV                    0x0400  /* AIF2_BCLK_INV */
-#define WM8915_AIF2_BCLK_INV_MASK               0x0400  /* AIF2_BCLK_INV */
-#define WM8915_AIF2_BCLK_INV_SHIFT                  10  /* AIF2_BCLK_INV */
-#define WM8915_AIF2_BCLK_INV_WIDTH                   1  /* AIF2_BCLK_INV */
-#define WM8915_AIF2_BCLK_FRC                    0x0200  /* AIF2_BCLK_FRC */
-#define WM8915_AIF2_BCLK_FRC_MASK               0x0200  /* AIF2_BCLK_FRC */
-#define WM8915_AIF2_BCLK_FRC_SHIFT                   9  /* AIF2_BCLK_FRC */
-#define WM8915_AIF2_BCLK_FRC_WIDTH                   1  /* AIF2_BCLK_FRC */
-#define WM8915_AIF2_BCLK_MSTR                   0x0100  /* AIF2_BCLK_MSTR */
-#define WM8915_AIF2_BCLK_MSTR_MASK              0x0100  /* AIF2_BCLK_MSTR */
-#define WM8915_AIF2_BCLK_MSTR_SHIFT                  8  /* AIF2_BCLK_MSTR */
-#define WM8915_AIF2_BCLK_MSTR_WIDTH                  1  /* AIF2_BCLK_MSTR */
-#define WM8915_AIF2_BCLK_DIV_MASK               0x000F  /* AIF2_BCLK_DIV - [3:0] */
-#define WM8915_AIF2_BCLK_DIV_SHIFT                   0  /* AIF2_BCLK_DIV - [3:0] */
-#define WM8915_AIF2_BCLK_DIV_WIDTH                   4  /* AIF2_BCLK_DIV - [3:0] */
-
-/*
- * R802 (0x322) - AIF2 TX LRCLK(1)
- */
-#define WM8915_AIF2TX_RATE_MASK                 0x07FF  /* AIF2TX_RATE - [10:0] */
-#define WM8915_AIF2TX_RATE_SHIFT                     0  /* AIF2TX_RATE - [10:0] */
-#define WM8915_AIF2TX_RATE_WIDTH                    11  /* AIF2TX_RATE - [10:0] */
-
-/*
- * R803 (0x323) - AIF2 TX LRCLK(2)
- */
-#define WM8915_AIF2TX_LRCLK_MODE                0x0008  /* AIF2TX_LRCLK_MODE */
-#define WM8915_AIF2TX_LRCLK_MODE_MASK           0x0008  /* AIF2TX_LRCLK_MODE */
-#define WM8915_AIF2TX_LRCLK_MODE_SHIFT               3  /* AIF2TX_LRCLK_MODE */
-#define WM8915_AIF2TX_LRCLK_MODE_WIDTH               1  /* AIF2TX_LRCLK_MODE */
-#define WM8915_AIF2TX_LRCLK_INV                 0x0004  /* AIF2TX_LRCLK_INV */
-#define WM8915_AIF2TX_LRCLK_INV_MASK            0x0004  /* AIF2TX_LRCLK_INV */
-#define WM8915_AIF2TX_LRCLK_INV_SHIFT                2  /* AIF2TX_LRCLK_INV */
-#define WM8915_AIF2TX_LRCLK_INV_WIDTH                1  /* AIF2TX_LRCLK_INV */
-#define WM8915_AIF2TX_LRCLK_FRC                 0x0002  /* AIF2TX_LRCLK_FRC */
-#define WM8915_AIF2TX_LRCLK_FRC_MASK            0x0002  /* AIF2TX_LRCLK_FRC */
-#define WM8915_AIF2TX_LRCLK_FRC_SHIFT                1  /* AIF2TX_LRCLK_FRC */
-#define WM8915_AIF2TX_LRCLK_FRC_WIDTH                1  /* AIF2TX_LRCLK_FRC */
-#define WM8915_AIF2TX_LRCLK_MSTR                0x0001  /* AIF2TX_LRCLK_MSTR */
-#define WM8915_AIF2TX_LRCLK_MSTR_MASK           0x0001  /* AIF2TX_LRCLK_MSTR */
-#define WM8915_AIF2TX_LRCLK_MSTR_SHIFT               0  /* AIF2TX_LRCLK_MSTR */
-#define WM8915_AIF2TX_LRCLK_MSTR_WIDTH               1  /* AIF2TX_LRCLK_MSTR */
-
-/*
- * R804 (0x324) - AIF2 RX LRCLK(1)
- */
-#define WM8915_AIF2RX_RATE_MASK                 0x07FF  /* AIF2RX_RATE - [10:0] */
-#define WM8915_AIF2RX_RATE_SHIFT                     0  /* AIF2RX_RATE - [10:0] */
-#define WM8915_AIF2RX_RATE_WIDTH                    11  /* AIF2RX_RATE - [10:0] */
-
-/*
- * R805 (0x325) - AIF2 RX LRCLK(2)
- */
-#define WM8915_AIF2RX_LRCLK_INV                 0x0004  /* AIF2RX_LRCLK_INV */
-#define WM8915_AIF2RX_LRCLK_INV_MASK            0x0004  /* AIF2RX_LRCLK_INV */
-#define WM8915_AIF2RX_LRCLK_INV_SHIFT                2  /* AIF2RX_LRCLK_INV */
-#define WM8915_AIF2RX_LRCLK_INV_WIDTH                1  /* AIF2RX_LRCLK_INV */
-#define WM8915_AIF2RX_LRCLK_FRC                 0x0002  /* AIF2RX_LRCLK_FRC */
-#define WM8915_AIF2RX_LRCLK_FRC_MASK            0x0002  /* AIF2RX_LRCLK_FRC */
-#define WM8915_AIF2RX_LRCLK_FRC_SHIFT                1  /* AIF2RX_LRCLK_FRC */
-#define WM8915_AIF2RX_LRCLK_FRC_WIDTH                1  /* AIF2RX_LRCLK_FRC */
-#define WM8915_AIF2RX_LRCLK_MSTR                0x0001  /* AIF2RX_LRCLK_MSTR */
-#define WM8915_AIF2RX_LRCLK_MSTR_MASK           0x0001  /* AIF2RX_LRCLK_MSTR */
-#define WM8915_AIF2RX_LRCLK_MSTR_SHIFT               0  /* AIF2RX_LRCLK_MSTR */
-#define WM8915_AIF2RX_LRCLK_MSTR_WIDTH               1  /* AIF2RX_LRCLK_MSTR */
-
-/*
- * R806 (0x326) - AIF2TX Data Configuration (1)
- */
-#define WM8915_AIF2TX_WL_MASK                   0xFF00  /* AIF2TX_WL - [15:8] */
-#define WM8915_AIF2TX_WL_SHIFT                       8  /* AIF2TX_WL - [15:8] */
-#define WM8915_AIF2TX_WL_WIDTH                       8  /* AIF2TX_WL - [15:8] */
-#define WM8915_AIF2TX_SLOT_LEN_MASK             0x00FF  /* AIF2TX_SLOT_LEN - [7:0] */
-#define WM8915_AIF2TX_SLOT_LEN_SHIFT                 0  /* AIF2TX_SLOT_LEN - [7:0] */
-#define WM8915_AIF2TX_SLOT_LEN_WIDTH                 8  /* AIF2TX_SLOT_LEN - [7:0] */
-
-/*
- * R807 (0x327) - AIF2TX Data Configuration (2)
- */
-#define WM8915_AIF2TX_DAT_TRI                   0x0001  /* AIF2TX_DAT_TRI */
-#define WM8915_AIF2TX_DAT_TRI_MASK              0x0001  /* AIF2TX_DAT_TRI */
-#define WM8915_AIF2TX_DAT_TRI_SHIFT                  0  /* AIF2TX_DAT_TRI */
-#define WM8915_AIF2TX_DAT_TRI_WIDTH                  1  /* AIF2TX_DAT_TRI */
-
-/*
- * R808 (0x328) - AIF2RX Data Configuration
- */
-#define WM8915_AIF2RX_WL_MASK                   0xFF00  /* AIF2RX_WL - [15:8] */
-#define WM8915_AIF2RX_WL_SHIFT                       8  /* AIF2RX_WL - [15:8] */
-#define WM8915_AIF2RX_WL_WIDTH                       8  /* AIF2RX_WL - [15:8] */
-#define WM8915_AIF2RX_SLOT_LEN_MASK             0x00FF  /* AIF2RX_SLOT_LEN - [7:0] */
-#define WM8915_AIF2RX_SLOT_LEN_SHIFT                 0  /* AIF2RX_SLOT_LEN - [7:0] */
-#define WM8915_AIF2RX_SLOT_LEN_WIDTH                 8  /* AIF2RX_SLOT_LEN - [7:0] */
-
-/*
- * R809 (0x329) - AIF2TX Channel 0 Configuration
- */
-#define WM8915_AIF2TX_CHAN0_DAT_INV             0x8000  /* AIF2TX_CHAN0_DAT_INV */
-#define WM8915_AIF2TX_CHAN0_DAT_INV_MASK        0x8000  /* AIF2TX_CHAN0_DAT_INV */
-#define WM8915_AIF2TX_CHAN0_DAT_INV_SHIFT           15  /* AIF2TX_CHAN0_DAT_INV */
-#define WM8915_AIF2TX_CHAN0_DAT_INV_WIDTH            1  /* AIF2TX_CHAN0_DAT_INV */
-#define WM8915_AIF2TX_CHAN0_SPACING_MASK        0x7E00  /* AIF2TX_CHAN0_SPACING - [14:9] */
-#define WM8915_AIF2TX_CHAN0_SPACING_SHIFT            9  /* AIF2TX_CHAN0_SPACING - [14:9] */
-#define WM8915_AIF2TX_CHAN0_SPACING_WIDTH            6  /* AIF2TX_CHAN0_SPACING - [14:9] */
-#define WM8915_AIF2TX_CHAN0_SLOTS_MASK          0x01C0  /* AIF2TX_CHAN0_SLOTS - [8:6] */
-#define WM8915_AIF2TX_CHAN0_SLOTS_SHIFT              6  /* AIF2TX_CHAN0_SLOTS - [8:6] */
-#define WM8915_AIF2TX_CHAN0_SLOTS_WIDTH              3  /* AIF2TX_CHAN0_SLOTS - [8:6] */
-#define WM8915_AIF2TX_CHAN0_START_SLOT_MASK     0x003F  /* AIF2TX_CHAN0_START_SLOT - [5:0] */
-#define WM8915_AIF2TX_CHAN0_START_SLOT_SHIFT         0  /* AIF2TX_CHAN0_START_SLOT - [5:0] */
-#define WM8915_AIF2TX_CHAN0_START_SLOT_WIDTH         6  /* AIF2TX_CHAN0_START_SLOT - [5:0] */
-
-/*
- * R810 (0x32A) - AIF2TX Channel 1 Configuration
- */
-#define WM8915_AIF2TX_CHAN1_DAT_INV             0x8000  /* AIF2TX_CHAN1_DAT_INV */
-#define WM8915_AIF2TX_CHAN1_DAT_INV_MASK        0x8000  /* AIF2TX_CHAN1_DAT_INV */
-#define WM8915_AIF2TX_CHAN1_DAT_INV_SHIFT           15  /* AIF2TX_CHAN1_DAT_INV */
-#define WM8915_AIF2TX_CHAN1_DAT_INV_WIDTH            1  /* AIF2TX_CHAN1_DAT_INV */
-#define WM8915_AIF2TX_CHAN1_SPACING_MASK        0x7E00  /* AIF2TX_CHAN1_SPACING - [14:9] */
-#define WM8915_AIF2TX_CHAN1_SPACING_SHIFT            9  /* AIF2TX_CHAN1_SPACING - [14:9] */
-#define WM8915_AIF2TX_CHAN1_SPACING_WIDTH            6  /* AIF2TX_CHAN1_SPACING - [14:9] */
-#define WM8915_AIF2TX_CHAN1_SLOTS_MASK          0x01C0  /* AIF2TX_CHAN1_SLOTS - [8:6] */
-#define WM8915_AIF2TX_CHAN1_SLOTS_SHIFT              6  /* AIF2TX_CHAN1_SLOTS - [8:6] */
-#define WM8915_AIF2TX_CHAN1_SLOTS_WIDTH              3  /* AIF2TX_CHAN1_SLOTS - [8:6] */
-#define WM8915_AIF2TX_CHAN1_START_SLOT_MASK     0x003F  /* AIF2TX_CHAN1_START_SLOT - [5:0] */
-#define WM8915_AIF2TX_CHAN1_START_SLOT_SHIFT         0  /* AIF2TX_CHAN1_START_SLOT - [5:0] */
-#define WM8915_AIF2TX_CHAN1_START_SLOT_WIDTH         6  /* AIF2TX_CHAN1_START_SLOT - [5:0] */
-
-/*
- * R811 (0x32B) - AIF2RX Channel 0 Configuration
- */
-#define WM8915_AIF2RX_CHAN0_DAT_INV             0x8000  /* AIF2RX_CHAN0_DAT_INV */
-#define WM8915_AIF2RX_CHAN0_DAT_INV_MASK        0x8000  /* AIF2RX_CHAN0_DAT_INV */
-#define WM8915_AIF2RX_CHAN0_DAT_INV_SHIFT           15  /* AIF2RX_CHAN0_DAT_INV */
-#define WM8915_AIF2RX_CHAN0_DAT_INV_WIDTH            1  /* AIF2RX_CHAN0_DAT_INV */
-#define WM8915_AIF2RX_CHAN0_SPACING_MASK        0x7E00  /* AIF2RX_CHAN0_SPACING - [14:9] */
-#define WM8915_AIF2RX_CHAN0_SPACING_SHIFT            9  /* AIF2RX_CHAN0_SPACING - [14:9] */
-#define WM8915_AIF2RX_CHAN0_SPACING_WIDTH            6  /* AIF2RX_CHAN0_SPACING - [14:9] */
-#define WM8915_AIF2RX_CHAN0_SLOTS_MASK          0x01C0  /* AIF2RX_CHAN0_SLOTS - [8:6] */
-#define WM8915_AIF2RX_CHAN0_SLOTS_SHIFT              6  /* AIF2RX_CHAN0_SLOTS - [8:6] */
-#define WM8915_AIF2RX_CHAN0_SLOTS_WIDTH              3  /* AIF2RX_CHAN0_SLOTS - [8:6] */
-#define WM8915_AIF2RX_CHAN0_START_SLOT_MASK     0x003F  /* AIF2RX_CHAN0_START_SLOT - [5:0] */
-#define WM8915_AIF2RX_CHAN0_START_SLOT_SHIFT         0  /* AIF2RX_CHAN0_START_SLOT - [5:0] */
-#define WM8915_AIF2RX_CHAN0_START_SLOT_WIDTH         6  /* AIF2RX_CHAN0_START_SLOT - [5:0] */
-
-/*
- * R812 (0x32C) - AIF2RX Channel 1 Configuration
- */
-#define WM8915_AIF2RX_CHAN1_DAT_INV             0x8000  /* AIF2RX_CHAN1_DAT_INV */
-#define WM8915_AIF2RX_CHAN1_DAT_INV_MASK        0x8000  /* AIF2RX_CHAN1_DAT_INV */
-#define WM8915_AIF2RX_CHAN1_DAT_INV_SHIFT           15  /* AIF2RX_CHAN1_DAT_INV */
-#define WM8915_AIF2RX_CHAN1_DAT_INV_WIDTH            1  /* AIF2RX_CHAN1_DAT_INV */
-#define WM8915_AIF2RX_CHAN1_SPACING_MASK        0x7E00  /* AIF2RX_CHAN1_SPACING - [14:9] */
-#define WM8915_AIF2RX_CHAN1_SPACING_SHIFT            9  /* AIF2RX_CHAN1_SPACING - [14:9] */
-#define WM8915_AIF2RX_CHAN1_SPACING_WIDTH            6  /* AIF2RX_CHAN1_SPACING - [14:9] */
-#define WM8915_AIF2RX_CHAN1_SLOTS_MASK          0x01C0  /* AIF2RX_CHAN1_SLOTS - [8:6] */
-#define WM8915_AIF2RX_CHAN1_SLOTS_SHIFT              6  /* AIF2RX_CHAN1_SLOTS - [8:6] */
-#define WM8915_AIF2RX_CHAN1_SLOTS_WIDTH              3  /* AIF2RX_CHAN1_SLOTS - [8:6] */
-#define WM8915_AIF2RX_CHAN1_START_SLOT_MASK     0x003F  /* AIF2RX_CHAN1_START_SLOT - [5:0] */
-#define WM8915_AIF2RX_CHAN1_START_SLOT_SHIFT         0  /* AIF2RX_CHAN1_START_SLOT - [5:0] */
-#define WM8915_AIF2RX_CHAN1_START_SLOT_WIDTH         6  /* AIF2RX_CHAN1_START_SLOT - [5:0] */
-
-/*
- * R813 (0x32D) - AIF2RX Mono Configuration
- */
-#define WM8915_AIF2RX_CHAN0_MONO_MODE           0x0001  /* AIF2RX_CHAN0_MONO_MODE */
-#define WM8915_AIF2RX_CHAN0_MONO_MODE_MASK      0x0001  /* AIF2RX_CHAN0_MONO_MODE */
-#define WM8915_AIF2RX_CHAN0_MONO_MODE_SHIFT          0  /* AIF2RX_CHAN0_MONO_MODE */
-#define WM8915_AIF2RX_CHAN0_MONO_MODE_WIDTH          1  /* AIF2RX_CHAN0_MONO_MODE */
-
-/*
- * R815 (0x32F) - AIF2TX Test
- */
-#define WM8915_AIF2TX_DITHER_ENA                0x0001  /* AIF2TX_DITHER_ENA */
-#define WM8915_AIF2TX_DITHER_ENA_MASK           0x0001  /* AIF2TX_DITHER_ENA */
-#define WM8915_AIF2TX_DITHER_ENA_SHIFT               0  /* AIF2TX_DITHER_ENA */
-#define WM8915_AIF2TX_DITHER_ENA_WIDTH               1  /* AIF2TX_DITHER_ENA */
-
-/*
- * R1024 (0x400) - DSP1 TX Left Volume
- */
-#define WM8915_DSP1TX_VU                        0x0100  /* DSP1TX_VU */
-#define WM8915_DSP1TX_VU_MASK                   0x0100  /* DSP1TX_VU */
-#define WM8915_DSP1TX_VU_SHIFT                       8  /* DSP1TX_VU */
-#define WM8915_DSP1TX_VU_WIDTH                       1  /* DSP1TX_VU */
-#define WM8915_DSP1TXL_VOL_MASK                 0x00FF  /* DSP1TXL_VOL - [7:0] */
-#define WM8915_DSP1TXL_VOL_SHIFT                     0  /* DSP1TXL_VOL - [7:0] */
-#define WM8915_DSP1TXL_VOL_WIDTH                     8  /* DSP1TXL_VOL - [7:0] */
-
-/*
- * R1025 (0x401) - DSP1 TX Right Volume
- */
-#define WM8915_DSP1TX_VU                        0x0100  /* DSP1TX_VU */
-#define WM8915_DSP1TX_VU_MASK                   0x0100  /* DSP1TX_VU */
-#define WM8915_DSP1TX_VU_SHIFT                       8  /* DSP1TX_VU */
-#define WM8915_DSP1TX_VU_WIDTH                       1  /* DSP1TX_VU */
-#define WM8915_DSP1TXR_VOL_MASK                 0x00FF  /* DSP1TXR_VOL - [7:0] */
-#define WM8915_DSP1TXR_VOL_SHIFT                     0  /* DSP1TXR_VOL - [7:0] */
-#define WM8915_DSP1TXR_VOL_WIDTH                     8  /* DSP1TXR_VOL - [7:0] */
-
-/*
- * R1026 (0x402) - DSP1 RX Left Volume
- */
-#define WM8915_DSP1RX_VU                        0x0100  /* DSP1RX_VU */
-#define WM8915_DSP1RX_VU_MASK                   0x0100  /* DSP1RX_VU */
-#define WM8915_DSP1RX_VU_SHIFT                       8  /* DSP1RX_VU */
-#define WM8915_DSP1RX_VU_WIDTH                       1  /* DSP1RX_VU */
-#define WM8915_DSP1RXL_VOL_MASK                 0x00FF  /* DSP1RXL_VOL - [7:0] */
-#define WM8915_DSP1RXL_VOL_SHIFT                     0  /* DSP1RXL_VOL - [7:0] */
-#define WM8915_DSP1RXL_VOL_WIDTH                     8  /* DSP1RXL_VOL - [7:0] */
-
-/*
- * R1027 (0x403) - DSP1 RX Right Volume
- */
-#define WM8915_DSP1RX_VU                        0x0100  /* DSP1RX_VU */
-#define WM8915_DSP1RX_VU_MASK                   0x0100  /* DSP1RX_VU */
-#define WM8915_DSP1RX_VU_SHIFT                       8  /* DSP1RX_VU */
-#define WM8915_DSP1RX_VU_WIDTH                       1  /* DSP1RX_VU */
-#define WM8915_DSP1RXR_VOL_MASK                 0x00FF  /* DSP1RXR_VOL - [7:0] */
-#define WM8915_DSP1RXR_VOL_SHIFT                     0  /* DSP1RXR_VOL - [7:0] */
-#define WM8915_DSP1RXR_VOL_WIDTH                     8  /* DSP1RXR_VOL - [7:0] */
-
-/*
- * R1040 (0x410) - DSP1 TX Filters
- */
-#define WM8915_DSP1TX_NF                        0x2000  /* DSP1TX_NF */
-#define WM8915_DSP1TX_NF_MASK                   0x2000  /* DSP1TX_NF */
-#define WM8915_DSP1TX_NF_SHIFT                      13  /* DSP1TX_NF */
-#define WM8915_DSP1TX_NF_WIDTH                       1  /* DSP1TX_NF */
-#define WM8915_DSP1TXL_HPF                      0x1000  /* DSP1TXL_HPF */
-#define WM8915_DSP1TXL_HPF_MASK                 0x1000  /* DSP1TXL_HPF */
-#define WM8915_DSP1TXL_HPF_SHIFT                    12  /* DSP1TXL_HPF */
-#define WM8915_DSP1TXL_HPF_WIDTH                     1  /* DSP1TXL_HPF */
-#define WM8915_DSP1TXR_HPF                      0x0800  /* DSP1TXR_HPF */
-#define WM8915_DSP1TXR_HPF_MASK                 0x0800  /* DSP1TXR_HPF */
-#define WM8915_DSP1TXR_HPF_SHIFT                    11  /* DSP1TXR_HPF */
-#define WM8915_DSP1TXR_HPF_WIDTH                     1  /* DSP1TXR_HPF */
-#define WM8915_DSP1TX_HPF_MODE_MASK             0x0018  /* DSP1TX_HPF_MODE - [4:3] */
-#define WM8915_DSP1TX_HPF_MODE_SHIFT                 3  /* DSP1TX_HPF_MODE - [4:3] */
-#define WM8915_DSP1TX_HPF_MODE_WIDTH                 2  /* DSP1TX_HPF_MODE - [4:3] */
-#define WM8915_DSP1TX_HPF_CUT_MASK              0x0007  /* DSP1TX_HPF_CUT - [2:0] */
-#define WM8915_DSP1TX_HPF_CUT_SHIFT                  0  /* DSP1TX_HPF_CUT - [2:0] */
-#define WM8915_DSP1TX_HPF_CUT_WIDTH                  3  /* DSP1TX_HPF_CUT - [2:0] */
-
-/*
- * R1056 (0x420) - DSP1 RX Filters (1)
- */
-#define WM8915_DSP1RX_MUTE                      0x0200  /* DSP1RX_MUTE */
-#define WM8915_DSP1RX_MUTE_MASK                 0x0200  /* DSP1RX_MUTE */
-#define WM8915_DSP1RX_MUTE_SHIFT                     9  /* DSP1RX_MUTE */
-#define WM8915_DSP1RX_MUTE_WIDTH                     1  /* DSP1RX_MUTE */
-#define WM8915_DSP1RX_MONO                      0x0080  /* DSP1RX_MONO */
-#define WM8915_DSP1RX_MONO_MASK                 0x0080  /* DSP1RX_MONO */
-#define WM8915_DSP1RX_MONO_SHIFT                     7  /* DSP1RX_MONO */
-#define WM8915_DSP1RX_MONO_WIDTH                     1  /* DSP1RX_MONO */
-#define WM8915_DSP1RX_MUTERATE                  0x0020  /* DSP1RX_MUTERATE */
-#define WM8915_DSP1RX_MUTERATE_MASK             0x0020  /* DSP1RX_MUTERATE */
-#define WM8915_DSP1RX_MUTERATE_SHIFT                 5  /* DSP1RX_MUTERATE */
-#define WM8915_DSP1RX_MUTERATE_WIDTH                 1  /* DSP1RX_MUTERATE */
-#define WM8915_DSP1RX_UNMUTE_RAMP               0x0010  /* DSP1RX_UNMUTE_RAMP */
-#define WM8915_DSP1RX_UNMUTE_RAMP_MASK          0x0010  /* DSP1RX_UNMUTE_RAMP */
-#define WM8915_DSP1RX_UNMUTE_RAMP_SHIFT              4  /* DSP1RX_UNMUTE_RAMP */
-#define WM8915_DSP1RX_UNMUTE_RAMP_WIDTH              1  /* DSP1RX_UNMUTE_RAMP */
-
-/*
- * R1057 (0x421) - DSP1 RX Filters (2)
- */
-#define WM8915_DSP1RX_3D_GAIN_MASK              0x3E00  /* DSP1RX_3D_GAIN - [13:9] */
-#define WM8915_DSP1RX_3D_GAIN_SHIFT                  9  /* DSP1RX_3D_GAIN - [13:9] */
-#define WM8915_DSP1RX_3D_GAIN_WIDTH                  5  /* DSP1RX_3D_GAIN - [13:9] */
-#define WM8915_DSP1RX_3D_ENA                    0x0100  /* DSP1RX_3D_ENA */
-#define WM8915_DSP1RX_3D_ENA_MASK               0x0100  /* DSP1RX_3D_ENA */
-#define WM8915_DSP1RX_3D_ENA_SHIFT                   8  /* DSP1RX_3D_ENA */
-#define WM8915_DSP1RX_3D_ENA_WIDTH                   1  /* DSP1RX_3D_ENA */
-
-/*
- * R1088 (0x440) - DSP1 DRC (1)
- */
-#define WM8915_DSP1DRC_SIG_DET_RMS_MASK         0xF800  /* DSP1DRC_SIG_DET_RMS - [15:11] */
-#define WM8915_DSP1DRC_SIG_DET_RMS_SHIFT            11  /* DSP1DRC_SIG_DET_RMS - [15:11] */
-#define WM8915_DSP1DRC_SIG_DET_RMS_WIDTH             5  /* DSP1DRC_SIG_DET_RMS - [15:11] */
-#define WM8915_DSP1DRC_SIG_DET_PK_MASK          0x0600  /* DSP1DRC_SIG_DET_PK - [10:9] */
-#define WM8915_DSP1DRC_SIG_DET_PK_SHIFT              9  /* DSP1DRC_SIG_DET_PK - [10:9] */
-#define WM8915_DSP1DRC_SIG_DET_PK_WIDTH              2  /* DSP1DRC_SIG_DET_PK - [10:9] */
-#define WM8915_DSP1DRC_NG_ENA                   0x0100  /* DSP1DRC_NG_ENA */
-#define WM8915_DSP1DRC_NG_ENA_MASK              0x0100  /* DSP1DRC_NG_ENA */
-#define WM8915_DSP1DRC_NG_ENA_SHIFT                  8  /* DSP1DRC_NG_ENA */
-#define WM8915_DSP1DRC_NG_ENA_WIDTH                  1  /* DSP1DRC_NG_ENA */
-#define WM8915_DSP1DRC_SIG_DET_MODE             0x0080  /* DSP1DRC_SIG_DET_MODE */
-#define WM8915_DSP1DRC_SIG_DET_MODE_MASK        0x0080  /* DSP1DRC_SIG_DET_MODE */
-#define WM8915_DSP1DRC_SIG_DET_MODE_SHIFT            7  /* DSP1DRC_SIG_DET_MODE */
-#define WM8915_DSP1DRC_SIG_DET_MODE_WIDTH            1  /* DSP1DRC_SIG_DET_MODE */
-#define WM8915_DSP1DRC_SIG_DET                  0x0040  /* DSP1DRC_SIG_DET */
-#define WM8915_DSP1DRC_SIG_DET_MASK             0x0040  /* DSP1DRC_SIG_DET */
-#define WM8915_DSP1DRC_SIG_DET_SHIFT                 6  /* DSP1DRC_SIG_DET */
-#define WM8915_DSP1DRC_SIG_DET_WIDTH                 1  /* DSP1DRC_SIG_DET */
-#define WM8915_DSP1DRC_KNEE2_OP_ENA             0x0020  /* DSP1DRC_KNEE2_OP_ENA */
-#define WM8915_DSP1DRC_KNEE2_OP_ENA_MASK        0x0020  /* DSP1DRC_KNEE2_OP_ENA */
-#define WM8915_DSP1DRC_KNEE2_OP_ENA_SHIFT            5  /* DSP1DRC_KNEE2_OP_ENA */
-#define WM8915_DSP1DRC_KNEE2_OP_ENA_WIDTH            1  /* DSP1DRC_KNEE2_OP_ENA */
-#define WM8915_DSP1DRC_QR                       0x0010  /* DSP1DRC_QR */
-#define WM8915_DSP1DRC_QR_MASK                  0x0010  /* DSP1DRC_QR */
-#define WM8915_DSP1DRC_QR_SHIFT                      4  /* DSP1DRC_QR */
-#define WM8915_DSP1DRC_QR_WIDTH                      1  /* DSP1DRC_QR */
-#define WM8915_DSP1DRC_ANTICLIP                 0x0008  /* DSP1DRC_ANTICLIP */
-#define WM8915_DSP1DRC_ANTICLIP_MASK            0x0008  /* DSP1DRC_ANTICLIP */
-#define WM8915_DSP1DRC_ANTICLIP_SHIFT                3  /* DSP1DRC_ANTICLIP */
-#define WM8915_DSP1DRC_ANTICLIP_WIDTH                1  /* DSP1DRC_ANTICLIP */
-#define WM8915_DSP1RX_DRC_ENA                   0x0004  /* DSP1RX_DRC_ENA */
-#define WM8915_DSP1RX_DRC_ENA_MASK              0x0004  /* DSP1RX_DRC_ENA */
-#define WM8915_DSP1RX_DRC_ENA_SHIFT                  2  /* DSP1RX_DRC_ENA */
-#define WM8915_DSP1RX_DRC_ENA_WIDTH                  1  /* DSP1RX_DRC_ENA */
-#define WM8915_DSP1TXL_DRC_ENA                  0x0002  /* DSP1TXL_DRC_ENA */
-#define WM8915_DSP1TXL_DRC_ENA_MASK             0x0002  /* DSP1TXL_DRC_ENA */
-#define WM8915_DSP1TXL_DRC_ENA_SHIFT                 1  /* DSP1TXL_DRC_ENA */
-#define WM8915_DSP1TXL_DRC_ENA_WIDTH                 1  /* DSP1TXL_DRC_ENA */
-#define WM8915_DSP1TXR_DRC_ENA                  0x0001  /* DSP1TXR_DRC_ENA */
-#define WM8915_DSP1TXR_DRC_ENA_MASK             0x0001  /* DSP1TXR_DRC_ENA */
-#define WM8915_DSP1TXR_DRC_ENA_SHIFT                 0  /* DSP1TXR_DRC_ENA */
-#define WM8915_DSP1TXR_DRC_ENA_WIDTH                 1  /* DSP1TXR_DRC_ENA */
-
-/*
- * R1089 (0x441) - DSP1 DRC (2)
- */
-#define WM8915_DSP1DRC_ATK_MASK                 0x1E00  /* DSP1DRC_ATK - [12:9] */
-#define WM8915_DSP1DRC_ATK_SHIFT                     9  /* DSP1DRC_ATK - [12:9] */
-#define WM8915_DSP1DRC_ATK_WIDTH                     4  /* DSP1DRC_ATK - [12:9] */
-#define WM8915_DSP1DRC_DCY_MASK                 0x01E0  /* DSP1DRC_DCY - [8:5] */
-#define WM8915_DSP1DRC_DCY_SHIFT                     5  /* DSP1DRC_DCY - [8:5] */
-#define WM8915_DSP1DRC_DCY_WIDTH                     4  /* DSP1DRC_DCY - [8:5] */
-#define WM8915_DSP1DRC_MINGAIN_MASK             0x001C  /* DSP1DRC_MINGAIN - [4:2] */
-#define WM8915_DSP1DRC_MINGAIN_SHIFT                 2  /* DSP1DRC_MINGAIN - [4:2] */
-#define WM8915_DSP1DRC_MINGAIN_WIDTH                 3  /* DSP1DRC_MINGAIN - [4:2] */
-#define WM8915_DSP1DRC_MAXGAIN_MASK             0x0003  /* DSP1DRC_MAXGAIN - [1:0] */
-#define WM8915_DSP1DRC_MAXGAIN_SHIFT                 0  /* DSP1DRC_MAXGAIN - [1:0] */
-#define WM8915_DSP1DRC_MAXGAIN_WIDTH                 2  /* DSP1DRC_MAXGAIN - [1:0] */
-
-/*
- * R1090 (0x442) - DSP1 DRC (3)
- */
-#define WM8915_DSP1DRC_NG_MINGAIN_MASK          0xF000  /* DSP1DRC_NG_MINGAIN - [15:12] */
-#define WM8915_DSP1DRC_NG_MINGAIN_SHIFT             12  /* DSP1DRC_NG_MINGAIN - [15:12] */
-#define WM8915_DSP1DRC_NG_MINGAIN_WIDTH              4  /* DSP1DRC_NG_MINGAIN - [15:12] */
-#define WM8915_DSP1DRC_NG_EXP_MASK              0x0C00  /* DSP1DRC_NG_EXP - [11:10] */
-#define WM8915_DSP1DRC_NG_EXP_SHIFT                 10  /* DSP1DRC_NG_EXP - [11:10] */
-#define WM8915_DSP1DRC_NG_EXP_WIDTH                  2  /* DSP1DRC_NG_EXP - [11:10] */
-#define WM8915_DSP1DRC_QR_THR_MASK              0x0300  /* DSP1DRC_QR_THR - [9:8] */
-#define WM8915_DSP1DRC_QR_THR_SHIFT                  8  /* DSP1DRC_QR_THR - [9:8] */
-#define WM8915_DSP1DRC_QR_THR_WIDTH                  2  /* DSP1DRC_QR_THR - [9:8] */
-#define WM8915_DSP1DRC_QR_DCY_MASK              0x00C0  /* DSP1DRC_QR_DCY - [7:6] */
-#define WM8915_DSP1DRC_QR_DCY_SHIFT                  6  /* DSP1DRC_QR_DCY - [7:6] */
-#define WM8915_DSP1DRC_QR_DCY_WIDTH                  2  /* DSP1DRC_QR_DCY - [7:6] */
-#define WM8915_DSP1DRC_HI_COMP_MASK             0x0038  /* DSP1DRC_HI_COMP - [5:3] */
-#define WM8915_DSP1DRC_HI_COMP_SHIFT                 3  /* DSP1DRC_HI_COMP - [5:3] */
-#define WM8915_DSP1DRC_HI_COMP_WIDTH                 3  /* DSP1DRC_HI_COMP - [5:3] */
-#define WM8915_DSP1DRC_LO_COMP_MASK             0x0007  /* DSP1DRC_LO_COMP - [2:0] */
-#define WM8915_DSP1DRC_LO_COMP_SHIFT                 0  /* DSP1DRC_LO_COMP - [2:0] */
-#define WM8915_DSP1DRC_LO_COMP_WIDTH                 3  /* DSP1DRC_LO_COMP - [2:0] */
-
-/*
- * R1091 (0x443) - DSP1 DRC (4)
- */
-#define WM8915_DSP1DRC_KNEE_IP_MASK             0x07E0  /* DSP1DRC_KNEE_IP - [10:5] */
-#define WM8915_DSP1DRC_KNEE_IP_SHIFT                 5  /* DSP1DRC_KNEE_IP - [10:5] */
-#define WM8915_DSP1DRC_KNEE_IP_WIDTH                 6  /* DSP1DRC_KNEE_IP - [10:5] */
-#define WM8915_DSP1DRC_KNEE_OP_MASK             0x001F  /* DSP1DRC_KNEE_OP - [4:0] */
-#define WM8915_DSP1DRC_KNEE_OP_SHIFT                 0  /* DSP1DRC_KNEE_OP - [4:0] */
-#define WM8915_DSP1DRC_KNEE_OP_WIDTH                 5  /* DSP1DRC_KNEE_OP - [4:0] */
-
-/*
- * R1092 (0x444) - DSP1 DRC (5)
- */
-#define WM8915_DSP1DRC_KNEE2_IP_MASK            0x03E0  /* DSP1DRC_KNEE2_IP - [9:5] */
-#define WM8915_DSP1DRC_KNEE2_IP_SHIFT                5  /* DSP1DRC_KNEE2_IP - [9:5] */
-#define WM8915_DSP1DRC_KNEE2_IP_WIDTH                5  /* DSP1DRC_KNEE2_IP - [9:5] */
-#define WM8915_DSP1DRC_KNEE2_OP_MASK            0x001F  /* DSP1DRC_KNEE2_OP - [4:0] */
-#define WM8915_DSP1DRC_KNEE2_OP_SHIFT                0  /* DSP1DRC_KNEE2_OP - [4:0] */
-#define WM8915_DSP1DRC_KNEE2_OP_WIDTH                5  /* DSP1DRC_KNEE2_OP - [4:0] */
-
-/*
- * R1152 (0x480) - DSP1 RX EQ Gains (1)
- */
-#define WM8915_DSP1RX_EQ_B1_GAIN_MASK           0xF800  /* DSP1RX_EQ_B1_GAIN - [15:11] */
-#define WM8915_DSP1RX_EQ_B1_GAIN_SHIFT              11  /* DSP1RX_EQ_B1_GAIN - [15:11] */
-#define WM8915_DSP1RX_EQ_B1_GAIN_WIDTH               5  /* DSP1RX_EQ_B1_GAIN - [15:11] */
-#define WM8915_DSP1RX_EQ_B2_GAIN_MASK           0x07C0  /* DSP1RX_EQ_B2_GAIN - [10:6] */
-#define WM8915_DSP1RX_EQ_B2_GAIN_SHIFT               6  /* DSP1RX_EQ_B2_GAIN - [10:6] */
-#define WM8915_DSP1RX_EQ_B2_GAIN_WIDTH               5  /* DSP1RX_EQ_B2_GAIN - [10:6] */
-#define WM8915_DSP1RX_EQ_B3_GAIN_MASK           0x003E  /* DSP1RX_EQ_B3_GAIN - [5:1] */
-#define WM8915_DSP1RX_EQ_B3_GAIN_SHIFT               1  /* DSP1RX_EQ_B3_GAIN - [5:1] */
-#define WM8915_DSP1RX_EQ_B3_GAIN_WIDTH               5  /* DSP1RX_EQ_B3_GAIN - [5:1] */
-#define WM8915_DSP1RX_EQ_ENA                    0x0001  /* DSP1RX_EQ_ENA */
-#define WM8915_DSP1RX_EQ_ENA_MASK               0x0001  /* DSP1RX_EQ_ENA */
-#define WM8915_DSP1RX_EQ_ENA_SHIFT                   0  /* DSP1RX_EQ_ENA */
-#define WM8915_DSP1RX_EQ_ENA_WIDTH                   1  /* DSP1RX_EQ_ENA */
-
-/*
- * R1153 (0x481) - DSP1 RX EQ Gains (2)
- */
-#define WM8915_DSP1RX_EQ_B4_GAIN_MASK           0xF800  /* DSP1RX_EQ_B4_GAIN - [15:11] */
-#define WM8915_DSP1RX_EQ_B4_GAIN_SHIFT              11  /* DSP1RX_EQ_B4_GAIN - [15:11] */
-#define WM8915_DSP1RX_EQ_B4_GAIN_WIDTH               5  /* DSP1RX_EQ_B4_GAIN - [15:11] */
-#define WM8915_DSP1RX_EQ_B5_GAIN_MASK           0x07C0  /* DSP1RX_EQ_B5_GAIN - [10:6] */
-#define WM8915_DSP1RX_EQ_B5_GAIN_SHIFT               6  /* DSP1RX_EQ_B5_GAIN - [10:6] */
-#define WM8915_DSP1RX_EQ_B5_GAIN_WIDTH               5  /* DSP1RX_EQ_B5_GAIN - [10:6] */
-
-/*
- * R1154 (0x482) - DSP1 RX EQ Band 1 A
- */
-#define WM8915_DSP1RX_EQ_B1_A_MASK              0xFFFF  /* DSP1RX_EQ_B1_A - [15:0] */
-#define WM8915_DSP1RX_EQ_B1_A_SHIFT                  0  /* DSP1RX_EQ_B1_A - [15:0] */
-#define WM8915_DSP1RX_EQ_B1_A_WIDTH                 16  /* DSP1RX_EQ_B1_A - [15:0] */
-
-/*
- * R1155 (0x483) - DSP1 RX EQ Band 1 B
- */
-#define WM8915_DSP1RX_EQ_B1_B_MASK              0xFFFF  /* DSP1RX_EQ_B1_B - [15:0] */
-#define WM8915_DSP1RX_EQ_B1_B_SHIFT                  0  /* DSP1RX_EQ_B1_B - [15:0] */
-#define WM8915_DSP1RX_EQ_B1_B_WIDTH                 16  /* DSP1RX_EQ_B1_B - [15:0] */
-
-/*
- * R1156 (0x484) - DSP1 RX EQ Band 1 PG
- */
-#define WM8915_DSP1RX_EQ_B1_PG_MASK             0xFFFF  /* DSP1RX_EQ_B1_PG - [15:0] */
-#define WM8915_DSP1RX_EQ_B1_PG_SHIFT                 0  /* DSP1RX_EQ_B1_PG - [15:0] */
-#define WM8915_DSP1RX_EQ_B1_PG_WIDTH                16  /* DSP1RX_EQ_B1_PG - [15:0] */
-
-/*
- * R1157 (0x485) - DSP1 RX EQ Band 2 A
- */
-#define WM8915_DSP1RX_EQ_B2_A_MASK              0xFFFF  /* DSP1RX_EQ_B2_A - [15:0] */
-#define WM8915_DSP1RX_EQ_B2_A_SHIFT                  0  /* DSP1RX_EQ_B2_A - [15:0] */
-#define WM8915_DSP1RX_EQ_B2_A_WIDTH                 16  /* DSP1RX_EQ_B2_A - [15:0] */
-
-/*
- * R1158 (0x486) - DSP1 RX EQ Band 2 B
- */
-#define WM8915_DSP1RX_EQ_B2_B_MASK              0xFFFF  /* DSP1RX_EQ_B2_B - [15:0] */
-#define WM8915_DSP1RX_EQ_B2_B_SHIFT                  0  /* DSP1RX_EQ_B2_B - [15:0] */
-#define WM8915_DSP1RX_EQ_B2_B_WIDTH                 16  /* DSP1RX_EQ_B2_B - [15:0] */
-
-/*
- * R1159 (0x487) - DSP1 RX EQ Band 2 C
- */
-#define WM8915_DSP1RX_EQ_B2_C_MASK              0xFFFF  /* DSP1RX_EQ_B2_C - [15:0] */
-#define WM8915_DSP1RX_EQ_B2_C_SHIFT                  0  /* DSP1RX_EQ_B2_C - [15:0] */
-#define WM8915_DSP1RX_EQ_B2_C_WIDTH                 16  /* DSP1RX_EQ_B2_C - [15:0] */
-
-/*
- * R1160 (0x488) - DSP1 RX EQ Band 2 PG
- */
-#define WM8915_DSP1RX_EQ_B2_PG_MASK             0xFFFF  /* DSP1RX_EQ_B2_PG - [15:0] */
-#define WM8915_DSP1RX_EQ_B2_PG_SHIFT                 0  /* DSP1RX_EQ_B2_PG - [15:0] */
-#define WM8915_DSP1RX_EQ_B2_PG_WIDTH                16  /* DSP1RX_EQ_B2_PG - [15:0] */
-
-/*
- * R1161 (0x489) - DSP1 RX EQ Band 3 A
- */
-#define WM8915_DSP1RX_EQ_B3_A_MASK              0xFFFF  /* DSP1RX_EQ_B3_A - [15:0] */
-#define WM8915_DSP1RX_EQ_B3_A_SHIFT                  0  /* DSP1RX_EQ_B3_A - [15:0] */
-#define WM8915_DSP1RX_EQ_B3_A_WIDTH                 16  /* DSP1RX_EQ_B3_A - [15:0] */
-
-/*
- * R1162 (0x48A) - DSP1 RX EQ Band 3 B
- */
-#define WM8915_DSP1RX_EQ_B3_B_MASK              0xFFFF  /* DSP1RX_EQ_B3_B - [15:0] */
-#define WM8915_DSP1RX_EQ_B3_B_SHIFT                  0  /* DSP1RX_EQ_B3_B - [15:0] */
-#define WM8915_DSP1RX_EQ_B3_B_WIDTH                 16  /* DSP1RX_EQ_B3_B - [15:0] */
-
-/*
- * R1163 (0x48B) - DSP1 RX EQ Band 3 C
- */
-#define WM8915_DSP1RX_EQ_B3_C_MASK              0xFFFF  /* DSP1RX_EQ_B3_C - [15:0] */
-#define WM8915_DSP1RX_EQ_B3_C_SHIFT                  0  /* DSP1RX_EQ_B3_C - [15:0] */
-#define WM8915_DSP1RX_EQ_B3_C_WIDTH                 16  /* DSP1RX_EQ_B3_C - [15:0] */
-
-/*
- * R1164 (0x48C) - DSP1 RX EQ Band 3 PG
- */
-#define WM8915_DSP1RX_EQ_B3_PG_MASK             0xFFFF  /* DSP1RX_EQ_B3_PG - [15:0] */
-#define WM8915_DSP1RX_EQ_B3_PG_SHIFT                 0  /* DSP1RX_EQ_B3_PG - [15:0] */
-#define WM8915_DSP1RX_EQ_B3_PG_WIDTH                16  /* DSP1RX_EQ_B3_PG - [15:0] */
-
-/*
- * R1165 (0x48D) - DSP1 RX EQ Band 4 A
- */
-#define WM8915_DSP1RX_EQ_B4_A_MASK              0xFFFF  /* DSP1RX_EQ_B4_A - [15:0] */
-#define WM8915_DSP1RX_EQ_B4_A_SHIFT                  0  /* DSP1RX_EQ_B4_A - [15:0] */
-#define WM8915_DSP1RX_EQ_B4_A_WIDTH                 16  /* DSP1RX_EQ_B4_A - [15:0] */
-
-/*
- * R1166 (0x48E) - DSP1 RX EQ Band 4 B
- */
-#define WM8915_DSP1RX_EQ_B4_B_MASK              0xFFFF  /* DSP1RX_EQ_B4_B - [15:0] */
-#define WM8915_DSP1RX_EQ_B4_B_SHIFT                  0  /* DSP1RX_EQ_B4_B - [15:0] */
-#define WM8915_DSP1RX_EQ_B4_B_WIDTH                 16  /* DSP1RX_EQ_B4_B - [15:0] */
-
-/*
- * R1167 (0x48F) - DSP1 RX EQ Band 4 C
- */
-#define WM8915_DSP1RX_EQ_B4_C_MASK              0xFFFF  /* DSP1RX_EQ_B4_C - [15:0] */
-#define WM8915_DSP1RX_EQ_B4_C_SHIFT                  0  /* DSP1RX_EQ_B4_C - [15:0] */
-#define WM8915_DSP1RX_EQ_B4_C_WIDTH                 16  /* DSP1RX_EQ_B4_C - [15:0] */
-
-/*
- * R1168 (0x490) - DSP1 RX EQ Band 4 PG
- */
-#define WM8915_DSP1RX_EQ_B4_PG_MASK             0xFFFF  /* DSP1RX_EQ_B4_PG - [15:0] */
-#define WM8915_DSP1RX_EQ_B4_PG_SHIFT                 0  /* DSP1RX_EQ_B4_PG - [15:0] */
-#define WM8915_DSP1RX_EQ_B4_PG_WIDTH                16  /* DSP1RX_EQ_B4_PG - [15:0] */
-
-/*
- * R1169 (0x491) - DSP1 RX EQ Band 5 A
- */
-#define WM8915_DSP1RX_EQ_B5_A_MASK              0xFFFF  /* DSP1RX_EQ_B5_A - [15:0] */
-#define WM8915_DSP1RX_EQ_B5_A_SHIFT                  0  /* DSP1RX_EQ_B5_A - [15:0] */
-#define WM8915_DSP1RX_EQ_B5_A_WIDTH                 16  /* DSP1RX_EQ_B5_A - [15:0] */
-
-/*
- * R1170 (0x492) - DSP1 RX EQ Band 5 B
- */
-#define WM8915_DSP1RX_EQ_B5_B_MASK              0xFFFF  /* DSP1RX_EQ_B5_B - [15:0] */
-#define WM8915_DSP1RX_EQ_B5_B_SHIFT                  0  /* DSP1RX_EQ_B5_B - [15:0] */
-#define WM8915_DSP1RX_EQ_B5_B_WIDTH                 16  /* DSP1RX_EQ_B5_B - [15:0] */
-
-/*
- * R1171 (0x493) - DSP1 RX EQ Band 5 PG
- */
-#define WM8915_DSP1RX_EQ_B5_PG_MASK             0xFFFF  /* DSP1RX_EQ_B5_PG - [15:0] */
-#define WM8915_DSP1RX_EQ_B5_PG_SHIFT                 0  /* DSP1RX_EQ_B5_PG - [15:0] */
-#define WM8915_DSP1RX_EQ_B5_PG_WIDTH                16  /* DSP1RX_EQ_B5_PG - [15:0] */
-
-/*
- * R1280 (0x500) - DSP2 TX Left Volume
- */
-#define WM8915_DSP2TX_VU                        0x0100  /* DSP2TX_VU */
-#define WM8915_DSP2TX_VU_MASK                   0x0100  /* DSP2TX_VU */
-#define WM8915_DSP2TX_VU_SHIFT                       8  /* DSP2TX_VU */
-#define WM8915_DSP2TX_VU_WIDTH                       1  /* DSP2TX_VU */
-#define WM8915_DSP2TXL_VOL_MASK                 0x00FF  /* DSP2TXL_VOL - [7:0] */
-#define WM8915_DSP2TXL_VOL_SHIFT                     0  /* DSP2TXL_VOL - [7:0] */
-#define WM8915_DSP2TXL_VOL_WIDTH                     8  /* DSP2TXL_VOL - [7:0] */
-
-/*
- * R1281 (0x501) - DSP2 TX Right Volume
- */
-#define WM8915_DSP2TX_VU                        0x0100  /* DSP2TX_VU */
-#define WM8915_DSP2TX_VU_MASK                   0x0100  /* DSP2TX_VU */
-#define WM8915_DSP2TX_VU_SHIFT                       8  /* DSP2TX_VU */
-#define WM8915_DSP2TX_VU_WIDTH                       1  /* DSP2TX_VU */
-#define WM8915_DSP2TXR_VOL_MASK                 0x00FF  /* DSP2TXR_VOL - [7:0] */
-#define WM8915_DSP2TXR_VOL_SHIFT                     0  /* DSP2TXR_VOL - [7:0] */
-#define WM8915_DSP2TXR_VOL_WIDTH                     8  /* DSP2TXR_VOL - [7:0] */
-
-/*
- * R1282 (0x502) - DSP2 RX Left Volume
- */
-#define WM8915_DSP2RX_VU                        0x0100  /* DSP2RX_VU */
-#define WM8915_DSP2RX_VU_MASK                   0x0100  /* DSP2RX_VU */
-#define WM8915_DSP2RX_VU_SHIFT                       8  /* DSP2RX_VU */
-#define WM8915_DSP2RX_VU_WIDTH                       1  /* DSP2RX_VU */
-#define WM8915_DSP2RXL_VOL_MASK                 0x00FF  /* DSP2RXL_VOL - [7:0] */
-#define WM8915_DSP2RXL_VOL_SHIFT                     0  /* DSP2RXL_VOL - [7:0] */
-#define WM8915_DSP2RXL_VOL_WIDTH                     8  /* DSP2RXL_VOL - [7:0] */
-
-/*
- * R1283 (0x503) - DSP2 RX Right Volume
- */
-#define WM8915_DSP2RX_VU                        0x0100  /* DSP2RX_VU */
-#define WM8915_DSP2RX_VU_MASK                   0x0100  /* DSP2RX_VU */
-#define WM8915_DSP2RX_VU_SHIFT                       8  /* DSP2RX_VU */
-#define WM8915_DSP2RX_VU_WIDTH                       1  /* DSP2RX_VU */
-#define WM8915_DSP2RXR_VOL_MASK                 0x00FF  /* DSP2RXR_VOL - [7:0] */
-#define WM8915_DSP2RXR_VOL_SHIFT                     0  /* DSP2RXR_VOL - [7:0] */
-#define WM8915_DSP2RXR_VOL_WIDTH                     8  /* DSP2RXR_VOL - [7:0] */
-
-/*
- * R1296 (0x510) - DSP2 TX Filters
- */
-#define WM8915_DSP2TX_NF                        0x2000  /* DSP2TX_NF */
-#define WM8915_DSP2TX_NF_MASK                   0x2000  /* DSP2TX_NF */
-#define WM8915_DSP2TX_NF_SHIFT                      13  /* DSP2TX_NF */
-#define WM8915_DSP2TX_NF_WIDTH                       1  /* DSP2TX_NF */
-#define WM8915_DSP2TXL_HPF                      0x1000  /* DSP2TXL_HPF */
-#define WM8915_DSP2TXL_HPF_MASK                 0x1000  /* DSP2TXL_HPF */
-#define WM8915_DSP2TXL_HPF_SHIFT                    12  /* DSP2TXL_HPF */
-#define WM8915_DSP2TXL_HPF_WIDTH                     1  /* DSP2TXL_HPF */
-#define WM8915_DSP2TXR_HPF                      0x0800  /* DSP2TXR_HPF */
-#define WM8915_DSP2TXR_HPF_MASK                 0x0800  /* DSP2TXR_HPF */
-#define WM8915_DSP2TXR_HPF_SHIFT                    11  /* DSP2TXR_HPF */
-#define WM8915_DSP2TXR_HPF_WIDTH                     1  /* DSP2TXR_HPF */
-#define WM8915_DSP2TX_HPF_MODE_MASK             0x0018  /* DSP2TX_HPF_MODE - [4:3] */
-#define WM8915_DSP2TX_HPF_MODE_SHIFT                 3  /* DSP2TX_HPF_MODE - [4:3] */
-#define WM8915_DSP2TX_HPF_MODE_WIDTH                 2  /* DSP2TX_HPF_MODE - [4:3] */
-#define WM8915_DSP2TX_HPF_CUT_MASK              0x0007  /* DSP2TX_HPF_CUT - [2:0] */
-#define WM8915_DSP2TX_HPF_CUT_SHIFT                  0  /* DSP2TX_HPF_CUT - [2:0] */
-#define WM8915_DSP2TX_HPF_CUT_WIDTH                  3  /* DSP2TX_HPF_CUT - [2:0] */
-
-/*
- * R1312 (0x520) - DSP2 RX Filters (1)
- */
-#define WM8915_DSP2RX_MUTE                      0x0200  /* DSP2RX_MUTE */
-#define WM8915_DSP2RX_MUTE_MASK                 0x0200  /* DSP2RX_MUTE */
-#define WM8915_DSP2RX_MUTE_SHIFT                     9  /* DSP2RX_MUTE */
-#define WM8915_DSP2RX_MUTE_WIDTH                     1  /* DSP2RX_MUTE */
-#define WM8915_DSP2RX_MONO                      0x0080  /* DSP2RX_MONO */
-#define WM8915_DSP2RX_MONO_MASK                 0x0080  /* DSP2RX_MONO */
-#define WM8915_DSP2RX_MONO_SHIFT                     7  /* DSP2RX_MONO */
-#define WM8915_DSP2RX_MONO_WIDTH                     1  /* DSP2RX_MONO */
-#define WM8915_DSP2RX_MUTERATE                  0x0020  /* DSP2RX_MUTERATE */
-#define WM8915_DSP2RX_MUTERATE_MASK             0x0020  /* DSP2RX_MUTERATE */
-#define WM8915_DSP2RX_MUTERATE_SHIFT                 5  /* DSP2RX_MUTERATE */
-#define WM8915_DSP2RX_MUTERATE_WIDTH                 1  /* DSP2RX_MUTERATE */
-#define WM8915_DSP2RX_UNMUTE_RAMP               0x0010  /* DSP2RX_UNMUTE_RAMP */
-#define WM8915_DSP2RX_UNMUTE_RAMP_MASK          0x0010  /* DSP2RX_UNMUTE_RAMP */
-#define WM8915_DSP2RX_UNMUTE_RAMP_SHIFT              4  /* DSP2RX_UNMUTE_RAMP */
-#define WM8915_DSP2RX_UNMUTE_RAMP_WIDTH              1  /* DSP2RX_UNMUTE_RAMP */
-
-/*
- * R1313 (0x521) - DSP2 RX Filters (2)
- */
-#define WM8915_DSP2RX_3D_GAIN_MASK              0x3E00  /* DSP2RX_3D_GAIN - [13:9] */
-#define WM8915_DSP2RX_3D_GAIN_SHIFT                  9  /* DSP2RX_3D_GAIN - [13:9] */
-#define WM8915_DSP2RX_3D_GAIN_WIDTH                  5  /* DSP2RX_3D_GAIN - [13:9] */
-#define WM8915_DSP2RX_3D_ENA                    0x0100  /* DSP2RX_3D_ENA */
-#define WM8915_DSP2RX_3D_ENA_MASK               0x0100  /* DSP2RX_3D_ENA */
-#define WM8915_DSP2RX_3D_ENA_SHIFT                   8  /* DSP2RX_3D_ENA */
-#define WM8915_DSP2RX_3D_ENA_WIDTH                   1  /* DSP2RX_3D_ENA */
-
-/*
- * R1344 (0x540) - DSP2 DRC (1)
- */
-#define WM8915_DSP2DRC_SIG_DET_RMS_MASK         0xF800  /* DSP2DRC_SIG_DET_RMS - [15:11] */
-#define WM8915_DSP2DRC_SIG_DET_RMS_SHIFT            11  /* DSP2DRC_SIG_DET_RMS - [15:11] */
-#define WM8915_DSP2DRC_SIG_DET_RMS_WIDTH             5  /* DSP2DRC_SIG_DET_RMS - [15:11] */
-#define WM8915_DSP2DRC_SIG_DET_PK_MASK          0x0600  /* DSP2DRC_SIG_DET_PK - [10:9] */
-#define WM8915_DSP2DRC_SIG_DET_PK_SHIFT              9  /* DSP2DRC_SIG_DET_PK - [10:9] */
-#define WM8915_DSP2DRC_SIG_DET_PK_WIDTH              2  /* DSP2DRC_SIG_DET_PK - [10:9] */
-#define WM8915_DSP2DRC_NG_ENA                   0x0100  /* DSP2DRC_NG_ENA */
-#define WM8915_DSP2DRC_NG_ENA_MASK              0x0100  /* DSP2DRC_NG_ENA */
-#define WM8915_DSP2DRC_NG_ENA_SHIFT                  8  /* DSP2DRC_NG_ENA */
-#define WM8915_DSP2DRC_NG_ENA_WIDTH                  1  /* DSP2DRC_NG_ENA */
-#define WM8915_DSP2DRC_SIG_DET_MODE             0x0080  /* DSP2DRC_SIG_DET_MODE */
-#define WM8915_DSP2DRC_SIG_DET_MODE_MASK        0x0080  /* DSP2DRC_SIG_DET_MODE */
-#define WM8915_DSP2DRC_SIG_DET_MODE_SHIFT            7  /* DSP2DRC_SIG_DET_MODE */
-#define WM8915_DSP2DRC_SIG_DET_MODE_WIDTH            1  /* DSP2DRC_SIG_DET_MODE */
-#define WM8915_DSP2DRC_SIG_DET                  0x0040  /* DSP2DRC_SIG_DET */
-#define WM8915_DSP2DRC_SIG_DET_MASK             0x0040  /* DSP2DRC_SIG_DET */
-#define WM8915_DSP2DRC_SIG_DET_SHIFT                 6  /* DSP2DRC_SIG_DET */
-#define WM8915_DSP2DRC_SIG_DET_WIDTH                 1  /* DSP2DRC_SIG_DET */
-#define WM8915_DSP2DRC_KNEE2_OP_ENA             0x0020  /* DSP2DRC_KNEE2_OP_ENA */
-#define WM8915_DSP2DRC_KNEE2_OP_ENA_MASK        0x0020  /* DSP2DRC_KNEE2_OP_ENA */
-#define WM8915_DSP2DRC_KNEE2_OP_ENA_SHIFT            5  /* DSP2DRC_KNEE2_OP_ENA */
-#define WM8915_DSP2DRC_KNEE2_OP_ENA_WIDTH            1  /* DSP2DRC_KNEE2_OP_ENA */
-#define WM8915_DSP2DRC_QR                       0x0010  /* DSP2DRC_QR */
-#define WM8915_DSP2DRC_QR_MASK                  0x0010  /* DSP2DRC_QR */
-#define WM8915_DSP2DRC_QR_SHIFT                      4  /* DSP2DRC_QR */
-#define WM8915_DSP2DRC_QR_WIDTH                      1  /* DSP2DRC_QR */
-#define WM8915_DSP2DRC_ANTICLIP                 0x0008  /* DSP2DRC_ANTICLIP */
-#define WM8915_DSP2DRC_ANTICLIP_MASK            0x0008  /* DSP2DRC_ANTICLIP */
-#define WM8915_DSP2DRC_ANTICLIP_SHIFT                3  /* DSP2DRC_ANTICLIP */
-#define WM8915_DSP2DRC_ANTICLIP_WIDTH                1  /* DSP2DRC_ANTICLIP */
-#define WM8915_DSP2RX_DRC_ENA                   0x0004  /* DSP2RX_DRC_ENA */
-#define WM8915_DSP2RX_DRC_ENA_MASK              0x0004  /* DSP2RX_DRC_ENA */
-#define WM8915_DSP2RX_DRC_ENA_SHIFT                  2  /* DSP2RX_DRC_ENA */
-#define WM8915_DSP2RX_DRC_ENA_WIDTH                  1  /* DSP2RX_DRC_ENA */
-#define WM8915_DSP2TXL_DRC_ENA                  0x0002  /* DSP2TXL_DRC_ENA */
-#define WM8915_DSP2TXL_DRC_ENA_MASK             0x0002  /* DSP2TXL_DRC_ENA */
-#define WM8915_DSP2TXL_DRC_ENA_SHIFT                 1  /* DSP2TXL_DRC_ENA */
-#define WM8915_DSP2TXL_DRC_ENA_WIDTH                 1  /* DSP2TXL_DRC_ENA */
-#define WM8915_DSP2TXR_DRC_ENA                  0x0001  /* DSP2TXR_DRC_ENA */
-#define WM8915_DSP2TXR_DRC_ENA_MASK             0x0001  /* DSP2TXR_DRC_ENA */
-#define WM8915_DSP2TXR_DRC_ENA_SHIFT                 0  /* DSP2TXR_DRC_ENA */
-#define WM8915_DSP2TXR_DRC_ENA_WIDTH                 1  /* DSP2TXR_DRC_ENA */
-
-/*
- * R1345 (0x541) - DSP2 DRC (2)
- */
-#define WM8915_DSP2DRC_ATK_MASK                 0x1E00  /* DSP2DRC_ATK - [12:9] */
-#define WM8915_DSP2DRC_ATK_SHIFT                     9  /* DSP2DRC_ATK - [12:9] */
-#define WM8915_DSP2DRC_ATK_WIDTH                     4  /* DSP2DRC_ATK - [12:9] */
-#define WM8915_DSP2DRC_DCY_MASK                 0x01E0  /* DSP2DRC_DCY - [8:5] */
-#define WM8915_DSP2DRC_DCY_SHIFT                     5  /* DSP2DRC_DCY - [8:5] */
-#define WM8915_DSP2DRC_DCY_WIDTH                     4  /* DSP2DRC_DCY - [8:5] */
-#define WM8915_DSP2DRC_MINGAIN_MASK             0x001C  /* DSP2DRC_MINGAIN - [4:2] */
-#define WM8915_DSP2DRC_MINGAIN_SHIFT                 2  /* DSP2DRC_MINGAIN - [4:2] */
-#define WM8915_DSP2DRC_MINGAIN_WIDTH                 3  /* DSP2DRC_MINGAIN - [4:2] */
-#define WM8915_DSP2DRC_MAXGAIN_MASK             0x0003  /* DSP2DRC_MAXGAIN - [1:0] */
-#define WM8915_DSP2DRC_MAXGAIN_SHIFT                 0  /* DSP2DRC_MAXGAIN - [1:0] */
-#define WM8915_DSP2DRC_MAXGAIN_WIDTH                 2  /* DSP2DRC_MAXGAIN - [1:0] */
-
-/*
- * R1346 (0x542) - DSP2 DRC (3)
- */
-#define WM8915_DSP2DRC_NG_MINGAIN_MASK          0xF000  /* DSP2DRC_NG_MINGAIN - [15:12] */
-#define WM8915_DSP2DRC_NG_MINGAIN_SHIFT             12  /* DSP2DRC_NG_MINGAIN - [15:12] */
-#define WM8915_DSP2DRC_NG_MINGAIN_WIDTH              4  /* DSP2DRC_NG_MINGAIN - [15:12] */
-#define WM8915_DSP2DRC_NG_EXP_MASK              0x0C00  /* DSP2DRC_NG_EXP - [11:10] */
-#define WM8915_DSP2DRC_NG_EXP_SHIFT                 10  /* DSP2DRC_NG_EXP - [11:10] */
-#define WM8915_DSP2DRC_NG_EXP_WIDTH                  2  /* DSP2DRC_NG_EXP - [11:10] */
-#define WM8915_DSP2DRC_QR_THR_MASK              0x0300  /* DSP2DRC_QR_THR - [9:8] */
-#define WM8915_DSP2DRC_QR_THR_SHIFT                  8  /* DSP2DRC_QR_THR - [9:8] */
-#define WM8915_DSP2DRC_QR_THR_WIDTH                  2  /* DSP2DRC_QR_THR - [9:8] */
-#define WM8915_DSP2DRC_QR_DCY_MASK              0x00C0  /* DSP2DRC_QR_DCY - [7:6] */
-#define WM8915_DSP2DRC_QR_DCY_SHIFT                  6  /* DSP2DRC_QR_DCY - [7:6] */
-#define WM8915_DSP2DRC_QR_DCY_WIDTH                  2  /* DSP2DRC_QR_DCY - [7:6] */
-#define WM8915_DSP2DRC_HI_COMP_MASK             0x0038  /* DSP2DRC_HI_COMP - [5:3] */
-#define WM8915_DSP2DRC_HI_COMP_SHIFT                 3  /* DSP2DRC_HI_COMP - [5:3] */
-#define WM8915_DSP2DRC_HI_COMP_WIDTH                 3  /* DSP2DRC_HI_COMP - [5:3] */
-#define WM8915_DSP2DRC_LO_COMP_MASK             0x0007  /* DSP2DRC_LO_COMP - [2:0] */
-#define WM8915_DSP2DRC_LO_COMP_SHIFT                 0  /* DSP2DRC_LO_COMP - [2:0] */
-#define WM8915_DSP2DRC_LO_COMP_WIDTH                 3  /* DSP2DRC_LO_COMP - [2:0] */
-
-/*
- * R1347 (0x543) - DSP2 DRC (4)
- */
-#define WM8915_DSP2DRC_KNEE_IP_MASK             0x07E0  /* DSP2DRC_KNEE_IP - [10:5] */
-#define WM8915_DSP2DRC_KNEE_IP_SHIFT                 5  /* DSP2DRC_KNEE_IP - [10:5] */
-#define WM8915_DSP2DRC_KNEE_IP_WIDTH                 6  /* DSP2DRC_KNEE_IP - [10:5] */
-#define WM8915_DSP2DRC_KNEE_OP_MASK             0x001F  /* DSP2DRC_KNEE_OP - [4:0] */
-#define WM8915_DSP2DRC_KNEE_OP_SHIFT                 0  /* DSP2DRC_KNEE_OP - [4:0] */
-#define WM8915_DSP2DRC_KNEE_OP_WIDTH                 5  /* DSP2DRC_KNEE_OP - [4:0] */
-
-/*
- * R1348 (0x544) - DSP2 DRC (5)
- */
-#define WM8915_DSP2DRC_KNEE2_IP_MASK            0x03E0  /* DSP2DRC_KNEE2_IP - [9:5] */
-#define WM8915_DSP2DRC_KNEE2_IP_SHIFT                5  /* DSP2DRC_KNEE2_IP - [9:5] */
-#define WM8915_DSP2DRC_KNEE2_IP_WIDTH                5  /* DSP2DRC_KNEE2_IP - [9:5] */
-#define WM8915_DSP2DRC_KNEE2_OP_MASK            0x001F  /* DSP2DRC_KNEE2_OP - [4:0] */
-#define WM8915_DSP2DRC_KNEE2_OP_SHIFT                0  /* DSP2DRC_KNEE2_OP - [4:0] */
-#define WM8915_DSP2DRC_KNEE2_OP_WIDTH                5  /* DSP2DRC_KNEE2_OP - [4:0] */
-
-/*
- * R1408 (0x580) - DSP2 RX EQ Gains (1)
- */
-#define WM8915_DSP2RX_EQ_B1_GAIN_MASK           0xF800  /* DSP2RX_EQ_B1_GAIN - [15:11] */
-#define WM8915_DSP2RX_EQ_B1_GAIN_SHIFT              11  /* DSP2RX_EQ_B1_GAIN - [15:11] */
-#define WM8915_DSP2RX_EQ_B1_GAIN_WIDTH               5  /* DSP2RX_EQ_B1_GAIN - [15:11] */
-#define WM8915_DSP2RX_EQ_B2_GAIN_MASK           0x07C0  /* DSP2RX_EQ_B2_GAIN - [10:6] */
-#define WM8915_DSP2RX_EQ_B2_GAIN_SHIFT               6  /* DSP2RX_EQ_B2_GAIN - [10:6] */
-#define WM8915_DSP2RX_EQ_B2_GAIN_WIDTH               5  /* DSP2RX_EQ_B2_GAIN - [10:6] */
-#define WM8915_DSP2RX_EQ_B3_GAIN_MASK           0x003E  /* DSP2RX_EQ_B3_GAIN - [5:1] */
-#define WM8915_DSP2RX_EQ_B3_GAIN_SHIFT               1  /* DSP2RX_EQ_B3_GAIN - [5:1] */
-#define WM8915_DSP2RX_EQ_B3_GAIN_WIDTH               5  /* DSP2RX_EQ_B3_GAIN - [5:1] */
-#define WM8915_DSP2RX_EQ_ENA                    0x0001  /* DSP2RX_EQ_ENA */
-#define WM8915_DSP2RX_EQ_ENA_MASK               0x0001  /* DSP2RX_EQ_ENA */
-#define WM8915_DSP2RX_EQ_ENA_SHIFT                   0  /* DSP2RX_EQ_ENA */
-#define WM8915_DSP2RX_EQ_ENA_WIDTH                   1  /* DSP2RX_EQ_ENA */
-
-/*
- * R1409 (0x581) - DSP2 RX EQ Gains (2)
- */
-#define WM8915_DSP2RX_EQ_B4_GAIN_MASK           0xF800  /* DSP2RX_EQ_B4_GAIN - [15:11] */
-#define WM8915_DSP2RX_EQ_B4_GAIN_SHIFT              11  /* DSP2RX_EQ_B4_GAIN - [15:11] */
-#define WM8915_DSP2RX_EQ_B4_GAIN_WIDTH               5  /* DSP2RX_EQ_B4_GAIN - [15:11] */
-#define WM8915_DSP2RX_EQ_B5_GAIN_MASK           0x07C0  /* DSP2RX_EQ_B5_GAIN - [10:6] */
-#define WM8915_DSP2RX_EQ_B5_GAIN_SHIFT               6  /* DSP2RX_EQ_B5_GAIN - [10:6] */
-#define WM8915_DSP2RX_EQ_B5_GAIN_WIDTH               5  /* DSP2RX_EQ_B5_GAIN - [10:6] */
-
-/*
- * R1410 (0x582) - DSP2 RX EQ Band 1 A
- */
-#define WM8915_DSP2RX_EQ_B1_A_MASK              0xFFFF  /* DSP2RX_EQ_B1_A - [15:0] */
-#define WM8915_DSP2RX_EQ_B1_A_SHIFT                  0  /* DSP2RX_EQ_B1_A - [15:0] */
-#define WM8915_DSP2RX_EQ_B1_A_WIDTH                 16  /* DSP2RX_EQ_B1_A - [15:0] */
-
-/*
- * R1411 (0x583) - DSP2 RX EQ Band 1 B
- */
-#define WM8915_DSP2RX_EQ_B1_B_MASK              0xFFFF  /* DSP2RX_EQ_B1_B - [15:0] */
-#define WM8915_DSP2RX_EQ_B1_B_SHIFT                  0  /* DSP2RX_EQ_B1_B - [15:0] */
-#define WM8915_DSP2RX_EQ_B1_B_WIDTH                 16  /* DSP2RX_EQ_B1_B - [15:0] */
-
-/*
- * R1412 (0x584) - DSP2 RX EQ Band 1 PG
- */
-#define WM8915_DSP2RX_EQ_B1_PG_MASK             0xFFFF  /* DSP2RX_EQ_B1_PG - [15:0] */
-#define WM8915_DSP2RX_EQ_B1_PG_SHIFT                 0  /* DSP2RX_EQ_B1_PG - [15:0] */
-#define WM8915_DSP2RX_EQ_B1_PG_WIDTH                16  /* DSP2RX_EQ_B1_PG - [15:0] */
-
-/*
- * R1413 (0x585) - DSP2 RX EQ Band 2 A
- */
-#define WM8915_DSP2RX_EQ_B2_A_MASK              0xFFFF  /* DSP2RX_EQ_B2_A - [15:0] */
-#define WM8915_DSP2RX_EQ_B2_A_SHIFT                  0  /* DSP2RX_EQ_B2_A - [15:0] */
-#define WM8915_DSP2RX_EQ_B2_A_WIDTH                 16  /* DSP2RX_EQ_B2_A - [15:0] */
-
-/*
- * R1414 (0x586) - DSP2 RX EQ Band 2 B
- */
-#define WM8915_DSP2RX_EQ_B2_B_MASK              0xFFFF  /* DSP2RX_EQ_B2_B - [15:0] */
-#define WM8915_DSP2RX_EQ_B2_B_SHIFT                  0  /* DSP2RX_EQ_B2_B - [15:0] */
-#define WM8915_DSP2RX_EQ_B2_B_WIDTH                 16  /* DSP2RX_EQ_B2_B - [15:0] */
-
-/*
- * R1415 (0x587) - DSP2 RX EQ Band 2 C
- */
-#define WM8915_DSP2RX_EQ_B2_C_MASK              0xFFFF  /* DSP2RX_EQ_B2_C - [15:0] */
-#define WM8915_DSP2RX_EQ_B2_C_SHIFT                  0  /* DSP2RX_EQ_B2_C - [15:0] */
-#define WM8915_DSP2RX_EQ_B2_C_WIDTH                 16  /* DSP2RX_EQ_B2_C - [15:0] */
-
-/*
- * R1416 (0x588) - DSP2 RX EQ Band 2 PG
- */
-#define WM8915_DSP2RX_EQ_B2_PG_MASK             0xFFFF  /* DSP2RX_EQ_B2_PG - [15:0] */
-#define WM8915_DSP2RX_EQ_B2_PG_SHIFT                 0  /* DSP2RX_EQ_B2_PG - [15:0] */
-#define WM8915_DSP2RX_EQ_B2_PG_WIDTH                16  /* DSP2RX_EQ_B2_PG - [15:0] */
-
-/*
- * R1417 (0x589) - DSP2 RX EQ Band 3 A
- */
-#define WM8915_DSP2RX_EQ_B3_A_MASK              0xFFFF  /* DSP2RX_EQ_B3_A - [15:0] */
-#define WM8915_DSP2RX_EQ_B3_A_SHIFT                  0  /* DSP2RX_EQ_B3_A - [15:0] */
-#define WM8915_DSP2RX_EQ_B3_A_WIDTH                 16  /* DSP2RX_EQ_B3_A - [15:0] */
-
-/*
- * R1418 (0x58A) - DSP2 RX EQ Band 3 B
- */
-#define WM8915_DSP2RX_EQ_B3_B_MASK              0xFFFF  /* DSP2RX_EQ_B3_B - [15:0] */
-#define WM8915_DSP2RX_EQ_B3_B_SHIFT                  0  /* DSP2RX_EQ_B3_B - [15:0] */
-#define WM8915_DSP2RX_EQ_B3_B_WIDTH                 16  /* DSP2RX_EQ_B3_B - [15:0] */
-
-/*
- * R1419 (0x58B) - DSP2 RX EQ Band 3 C
- */
-#define WM8915_DSP2RX_EQ_B3_C_MASK              0xFFFF  /* DSP2RX_EQ_B3_C - [15:0] */
-#define WM8915_DSP2RX_EQ_B3_C_SHIFT                  0  /* DSP2RX_EQ_B3_C - [15:0] */
-#define WM8915_DSP2RX_EQ_B3_C_WIDTH                 16  /* DSP2RX_EQ_B3_C - [15:0] */
-
-/*
- * R1420 (0x58C) - DSP2 RX EQ Band 3 PG
- */
-#define WM8915_DSP2RX_EQ_B3_PG_MASK             0xFFFF  /* DSP2RX_EQ_B3_PG - [15:0] */
-#define WM8915_DSP2RX_EQ_B3_PG_SHIFT                 0  /* DSP2RX_EQ_B3_PG - [15:0] */
-#define WM8915_DSP2RX_EQ_B3_PG_WIDTH                16  /* DSP2RX_EQ_B3_PG - [15:0] */
-
-/*
- * R1421 (0x58D) - DSP2 RX EQ Band 4 A
- */
-#define WM8915_DSP2RX_EQ_B4_A_MASK              0xFFFF  /* DSP2RX_EQ_B4_A - [15:0] */
-#define WM8915_DSP2RX_EQ_B4_A_SHIFT                  0  /* DSP2RX_EQ_B4_A - [15:0] */
-#define WM8915_DSP2RX_EQ_B4_A_WIDTH                 16  /* DSP2RX_EQ_B4_A - [15:0] */
-
-/*
- * R1422 (0x58E) - DSP2 RX EQ Band 4 B
- */
-#define WM8915_DSP2RX_EQ_B4_B_MASK              0xFFFF  /* DSP2RX_EQ_B4_B - [15:0] */
-#define WM8915_DSP2RX_EQ_B4_B_SHIFT                  0  /* DSP2RX_EQ_B4_B - [15:0] */
-#define WM8915_DSP2RX_EQ_B4_B_WIDTH                 16  /* DSP2RX_EQ_B4_B - [15:0] */
-
-/*
- * R1423 (0x58F) - DSP2 RX EQ Band 4 C
- */
-#define WM8915_DSP2RX_EQ_B4_C_MASK              0xFFFF  /* DSP2RX_EQ_B4_C - [15:0] */
-#define WM8915_DSP2RX_EQ_B4_C_SHIFT                  0  /* DSP2RX_EQ_B4_C - [15:0] */
-#define WM8915_DSP2RX_EQ_B4_C_WIDTH                 16  /* DSP2RX_EQ_B4_C - [15:0] */
-
-/*
- * R1424 (0x590) - DSP2 RX EQ Band 4 PG
- */
-#define WM8915_DSP2RX_EQ_B4_PG_MASK             0xFFFF  /* DSP2RX_EQ_B4_PG - [15:0] */
-#define WM8915_DSP2RX_EQ_B4_PG_SHIFT                 0  /* DSP2RX_EQ_B4_PG - [15:0] */
-#define WM8915_DSP2RX_EQ_B4_PG_WIDTH                16  /* DSP2RX_EQ_B4_PG - [15:0] */
-
-/*
- * R1425 (0x591) - DSP2 RX EQ Band 5 A
- */
-#define WM8915_DSP2RX_EQ_B5_A_MASK              0xFFFF  /* DSP2RX_EQ_B5_A - [15:0] */
-#define WM8915_DSP2RX_EQ_B5_A_SHIFT                  0  /* DSP2RX_EQ_B5_A - [15:0] */
-#define WM8915_DSP2RX_EQ_B5_A_WIDTH                 16  /* DSP2RX_EQ_B5_A - [15:0] */
-
-/*
- * R1426 (0x592) - DSP2 RX EQ Band 5 B
- */
-#define WM8915_DSP2RX_EQ_B5_B_MASK              0xFFFF  /* DSP2RX_EQ_B5_B - [15:0] */
-#define WM8915_DSP2RX_EQ_B5_B_SHIFT                  0  /* DSP2RX_EQ_B5_B - [15:0] */
-#define WM8915_DSP2RX_EQ_B5_B_WIDTH                 16  /* DSP2RX_EQ_B5_B - [15:0] */
-
-/*
- * R1427 (0x593) - DSP2 RX EQ Band 5 PG
- */
-#define WM8915_DSP2RX_EQ_B5_PG_MASK             0xFFFF  /* DSP2RX_EQ_B5_PG - [15:0] */
-#define WM8915_DSP2RX_EQ_B5_PG_SHIFT                 0  /* DSP2RX_EQ_B5_PG - [15:0] */
-#define WM8915_DSP2RX_EQ_B5_PG_WIDTH                16  /* DSP2RX_EQ_B5_PG - [15:0] */
-
-/*
- * R1536 (0x600) - DAC1 Mixer Volumes
- */
-#define WM8915_ADCR_DAC1_VOL_MASK               0x03E0  /* ADCR_DAC1_VOL - [9:5] */
-#define WM8915_ADCR_DAC1_VOL_SHIFT                   5  /* ADCR_DAC1_VOL - [9:5] */
-#define WM8915_ADCR_DAC1_VOL_WIDTH                   5  /* ADCR_DAC1_VOL - [9:5] */
-#define WM8915_ADCL_DAC1_VOL_MASK               0x001F  /* ADCL_DAC1_VOL - [4:0] */
-#define WM8915_ADCL_DAC1_VOL_SHIFT                   0  /* ADCL_DAC1_VOL - [4:0] */
-#define WM8915_ADCL_DAC1_VOL_WIDTH                   5  /* ADCL_DAC1_VOL - [4:0] */
-
-/*
- * R1537 (0x601) - DAC1 Left Mixer Routing
- */
-#define WM8915_ADCR_TO_DAC1L                    0x0020  /* ADCR_TO_DAC1L */
-#define WM8915_ADCR_TO_DAC1L_MASK               0x0020  /* ADCR_TO_DAC1L */
-#define WM8915_ADCR_TO_DAC1L_SHIFT                   5  /* ADCR_TO_DAC1L */
-#define WM8915_ADCR_TO_DAC1L_WIDTH                   1  /* ADCR_TO_DAC1L */
-#define WM8915_ADCL_TO_DAC1L                    0x0010  /* ADCL_TO_DAC1L */
-#define WM8915_ADCL_TO_DAC1L_MASK               0x0010  /* ADCL_TO_DAC1L */
-#define WM8915_ADCL_TO_DAC1L_SHIFT                   4  /* ADCL_TO_DAC1L */
-#define WM8915_ADCL_TO_DAC1L_WIDTH                   1  /* ADCL_TO_DAC1L */
-#define WM8915_DSP2RXL_TO_DAC1L                 0x0002  /* DSP2RXL_TO_DAC1L */
-#define WM8915_DSP2RXL_TO_DAC1L_MASK            0x0002  /* DSP2RXL_TO_DAC1L */
-#define WM8915_DSP2RXL_TO_DAC1L_SHIFT                1  /* DSP2RXL_TO_DAC1L */
-#define WM8915_DSP2RXL_TO_DAC1L_WIDTH                1  /* DSP2RXL_TO_DAC1L */
-#define WM8915_DSP1RXL_TO_DAC1L                 0x0001  /* DSP1RXL_TO_DAC1L */
-#define WM8915_DSP1RXL_TO_DAC1L_MASK            0x0001  /* DSP1RXL_TO_DAC1L */
-#define WM8915_DSP1RXL_TO_DAC1L_SHIFT                0  /* DSP1RXL_TO_DAC1L */
-#define WM8915_DSP1RXL_TO_DAC1L_WIDTH                1  /* DSP1RXL_TO_DAC1L */
-
-/*
- * R1538 (0x602) - DAC1 Right Mixer Routing
- */
-#define WM8915_ADCR_TO_DAC1R                    0x0020  /* ADCR_TO_DAC1R */
-#define WM8915_ADCR_TO_DAC1R_MASK               0x0020  /* ADCR_TO_DAC1R */
-#define WM8915_ADCR_TO_DAC1R_SHIFT                   5  /* ADCR_TO_DAC1R */
-#define WM8915_ADCR_TO_DAC1R_WIDTH                   1  /* ADCR_TO_DAC1R */
-#define WM8915_ADCL_TO_DAC1R                    0x0010  /* ADCL_TO_DAC1R */
-#define WM8915_ADCL_TO_DAC1R_MASK               0x0010  /* ADCL_TO_DAC1R */
-#define WM8915_ADCL_TO_DAC1R_SHIFT                   4  /* ADCL_TO_DAC1R */
-#define WM8915_ADCL_TO_DAC1R_WIDTH                   1  /* ADCL_TO_DAC1R */
-#define WM8915_DSP2RXR_TO_DAC1R                 0x0002  /* DSP2RXR_TO_DAC1R */
-#define WM8915_DSP2RXR_TO_DAC1R_MASK            0x0002  /* DSP2RXR_TO_DAC1R */
-#define WM8915_DSP2RXR_TO_DAC1R_SHIFT                1  /* DSP2RXR_TO_DAC1R */
-#define WM8915_DSP2RXR_TO_DAC1R_WIDTH                1  /* DSP2RXR_TO_DAC1R */
-#define WM8915_DSP1RXR_TO_DAC1R                 0x0001  /* DSP1RXR_TO_DAC1R */
-#define WM8915_DSP1RXR_TO_DAC1R_MASK            0x0001  /* DSP1RXR_TO_DAC1R */
-#define WM8915_DSP1RXR_TO_DAC1R_SHIFT                0  /* DSP1RXR_TO_DAC1R */
-#define WM8915_DSP1RXR_TO_DAC1R_WIDTH                1  /* DSP1RXR_TO_DAC1R */
-
-/*
- * R1539 (0x603) - DAC2 Mixer Volumes
- */
-#define WM8915_ADCR_DAC2_VOL_MASK               0x03E0  /* ADCR_DAC2_VOL - [9:5] */
-#define WM8915_ADCR_DAC2_VOL_SHIFT                   5  /* ADCR_DAC2_VOL - [9:5] */
-#define WM8915_ADCR_DAC2_VOL_WIDTH                   5  /* ADCR_DAC2_VOL - [9:5] */
-#define WM8915_ADCL_DAC2_VOL_MASK               0x001F  /* ADCL_DAC2_VOL - [4:0] */
-#define WM8915_ADCL_DAC2_VOL_SHIFT                   0  /* ADCL_DAC2_VOL - [4:0] */
-#define WM8915_ADCL_DAC2_VOL_WIDTH                   5  /* ADCL_DAC2_VOL - [4:0] */
-
-/*
- * R1540 (0x604) - DAC2 Left Mixer Routing
- */
-#define WM8915_ADCR_TO_DAC2L                    0x0020  /* ADCR_TO_DAC2L */
-#define WM8915_ADCR_TO_DAC2L_MASK               0x0020  /* ADCR_TO_DAC2L */
-#define WM8915_ADCR_TO_DAC2L_SHIFT                   5  /* ADCR_TO_DAC2L */
-#define WM8915_ADCR_TO_DAC2L_WIDTH                   1  /* ADCR_TO_DAC2L */
-#define WM8915_ADCL_TO_DAC2L                    0x0010  /* ADCL_TO_DAC2L */
-#define WM8915_ADCL_TO_DAC2L_MASK               0x0010  /* ADCL_TO_DAC2L */
-#define WM8915_ADCL_TO_DAC2L_SHIFT                   4  /* ADCL_TO_DAC2L */
-#define WM8915_ADCL_TO_DAC2L_WIDTH                   1  /* ADCL_TO_DAC2L */
-#define WM8915_DSP2RXL_TO_DAC2L                 0x0002  /* DSP2RXL_TO_DAC2L */
-#define WM8915_DSP2RXL_TO_DAC2L_MASK            0x0002  /* DSP2RXL_TO_DAC2L */
-#define WM8915_DSP2RXL_TO_DAC2L_SHIFT                1  /* DSP2RXL_TO_DAC2L */
-#define WM8915_DSP2RXL_TO_DAC2L_WIDTH                1  /* DSP2RXL_TO_DAC2L */
-#define WM8915_DSP1RXL_TO_DAC2L                 0x0001  /* DSP1RXL_TO_DAC2L */
-#define WM8915_DSP1RXL_TO_DAC2L_MASK            0x0001  /* DSP1RXL_TO_DAC2L */
-#define WM8915_DSP1RXL_TO_DAC2L_SHIFT                0  /* DSP1RXL_TO_DAC2L */
-#define WM8915_DSP1RXL_TO_DAC2L_WIDTH                1  /* DSP1RXL_TO_DAC2L */
-
-/*
- * R1541 (0x605) - DAC2 Right Mixer Routing
- */
-#define WM8915_ADCR_TO_DAC2R                    0x0020  /* ADCR_TO_DAC2R */
-#define WM8915_ADCR_TO_DAC2R_MASK               0x0020  /* ADCR_TO_DAC2R */
-#define WM8915_ADCR_TO_DAC2R_SHIFT                   5  /* ADCR_TO_DAC2R */
-#define WM8915_ADCR_TO_DAC2R_WIDTH                   1  /* ADCR_TO_DAC2R */
-#define WM8915_ADCL_TO_DAC2R                    0x0010  /* ADCL_TO_DAC2R */
-#define WM8915_ADCL_TO_DAC2R_MASK               0x0010  /* ADCL_TO_DAC2R */
-#define WM8915_ADCL_TO_DAC2R_SHIFT                   4  /* ADCL_TO_DAC2R */
-#define WM8915_ADCL_TO_DAC2R_WIDTH                   1  /* ADCL_TO_DAC2R */
-#define WM8915_DSP2RXR_TO_DAC2R                 0x0002  /* DSP2RXR_TO_DAC2R */
-#define WM8915_DSP2RXR_TO_DAC2R_MASK            0x0002  /* DSP2RXR_TO_DAC2R */
-#define WM8915_DSP2RXR_TO_DAC2R_SHIFT                1  /* DSP2RXR_TO_DAC2R */
-#define WM8915_DSP2RXR_TO_DAC2R_WIDTH                1  /* DSP2RXR_TO_DAC2R */
-#define WM8915_DSP1RXR_TO_DAC2R                 0x0001  /* DSP1RXR_TO_DAC2R */
-#define WM8915_DSP1RXR_TO_DAC2R_MASK            0x0001  /* DSP1RXR_TO_DAC2R */
-#define WM8915_DSP1RXR_TO_DAC2R_SHIFT                0  /* DSP1RXR_TO_DAC2R */
-#define WM8915_DSP1RXR_TO_DAC2R_WIDTH                1  /* DSP1RXR_TO_DAC2R */
-
-/*
- * R1542 (0x606) - DSP1 TX Left Mixer Routing
- */
-#define WM8915_ADC1L_TO_DSP1TXL                 0x0002  /* ADC1L_TO_DSP1TXL */
-#define WM8915_ADC1L_TO_DSP1TXL_MASK            0x0002  /* ADC1L_TO_DSP1TXL */
-#define WM8915_ADC1L_TO_DSP1TXL_SHIFT                1  /* ADC1L_TO_DSP1TXL */
-#define WM8915_ADC1L_TO_DSP1TXL_WIDTH                1  /* ADC1L_TO_DSP1TXL */
-#define WM8915_DACL_TO_DSP1TXL                  0x0001  /* DACL_TO_DSP1TXL */
-#define WM8915_DACL_TO_DSP1TXL_MASK             0x0001  /* DACL_TO_DSP1TXL */
-#define WM8915_DACL_TO_DSP1TXL_SHIFT                 0  /* DACL_TO_DSP1TXL */
-#define WM8915_DACL_TO_DSP1TXL_WIDTH                 1  /* DACL_TO_DSP1TXL */
-
-/*
- * R1543 (0x607) - DSP1 TX Right Mixer Routing
- */
-#define WM8915_ADC1R_TO_DSP1TXR                 0x0002  /* ADC1R_TO_DSP1TXR */
-#define WM8915_ADC1R_TO_DSP1TXR_MASK            0x0002  /* ADC1R_TO_DSP1TXR */
-#define WM8915_ADC1R_TO_DSP1TXR_SHIFT                1  /* ADC1R_TO_DSP1TXR */
-#define WM8915_ADC1R_TO_DSP1TXR_WIDTH                1  /* ADC1R_TO_DSP1TXR */
-#define WM8915_DACR_TO_DSP1TXR                  0x0001  /* DACR_TO_DSP1TXR */
-#define WM8915_DACR_TO_DSP1TXR_MASK             0x0001  /* DACR_TO_DSP1TXR */
-#define WM8915_DACR_TO_DSP1TXR_SHIFT                 0  /* DACR_TO_DSP1TXR */
-#define WM8915_DACR_TO_DSP1TXR_WIDTH                 1  /* DACR_TO_DSP1TXR */
-
-/*
- * R1544 (0x608) - DSP2 TX Left Mixer Routing
- */
-#define WM8915_ADC2L_TO_DSP2TXL                 0x0002  /* ADC2L_TO_DSP2TXL */
-#define WM8915_ADC2L_TO_DSP2TXL_MASK            0x0002  /* ADC2L_TO_DSP2TXL */
-#define WM8915_ADC2L_TO_DSP2TXL_SHIFT                1  /* ADC2L_TO_DSP2TXL */
-#define WM8915_ADC2L_TO_DSP2TXL_WIDTH                1  /* ADC2L_TO_DSP2TXL */
-#define WM8915_DACL_TO_DSP2TXL                  0x0001  /* DACL_TO_DSP2TXL */
-#define WM8915_DACL_TO_DSP2TXL_MASK             0x0001  /* DACL_TO_DSP2TXL */
-#define WM8915_DACL_TO_DSP2TXL_SHIFT                 0  /* DACL_TO_DSP2TXL */
-#define WM8915_DACL_TO_DSP2TXL_WIDTH                 1  /* DACL_TO_DSP2TXL */
-
-/*
- * R1545 (0x609) - DSP2 TX Right Mixer Routing
- */
-#define WM8915_ADC2R_TO_DSP2TXR                 0x0002  /* ADC2R_TO_DSP2TXR */
-#define WM8915_ADC2R_TO_DSP2TXR_MASK            0x0002  /* ADC2R_TO_DSP2TXR */
-#define WM8915_ADC2R_TO_DSP2TXR_SHIFT                1  /* ADC2R_TO_DSP2TXR */
-#define WM8915_ADC2R_TO_DSP2TXR_WIDTH                1  /* ADC2R_TO_DSP2TXR */
-#define WM8915_DACR_TO_DSP2TXR                  0x0001  /* DACR_TO_DSP2TXR */
-#define WM8915_DACR_TO_DSP2TXR_MASK             0x0001  /* DACR_TO_DSP2TXR */
-#define WM8915_DACR_TO_DSP2TXR_SHIFT                 0  /* DACR_TO_DSP2TXR */
-#define WM8915_DACR_TO_DSP2TXR_WIDTH                 1  /* DACR_TO_DSP2TXR */
-
-/*
- * R1546 (0x60A) - DSP TX Mixer Select
- */
-#define WM8915_DAC_TO_DSPTX_SRC                 0x0001  /* DAC_TO_DSPTX_SRC */
-#define WM8915_DAC_TO_DSPTX_SRC_MASK            0x0001  /* DAC_TO_DSPTX_SRC */
-#define WM8915_DAC_TO_DSPTX_SRC_SHIFT                0  /* DAC_TO_DSPTX_SRC */
-#define WM8915_DAC_TO_DSPTX_SRC_WIDTH                1  /* DAC_TO_DSPTX_SRC */
-
-/*
- * R1552 (0x610) - DAC Softmute
- */
-#define WM8915_DAC_SOFTMUTEMODE                 0x0002  /* DAC_SOFTMUTEMODE */
-#define WM8915_DAC_SOFTMUTEMODE_MASK            0x0002  /* DAC_SOFTMUTEMODE */
-#define WM8915_DAC_SOFTMUTEMODE_SHIFT                1  /* DAC_SOFTMUTEMODE */
-#define WM8915_DAC_SOFTMUTEMODE_WIDTH                1  /* DAC_SOFTMUTEMODE */
-#define WM8915_DAC_MUTERATE                     0x0001  /* DAC_MUTERATE */
-#define WM8915_DAC_MUTERATE_MASK                0x0001  /* DAC_MUTERATE */
-#define WM8915_DAC_MUTERATE_SHIFT                    0  /* DAC_MUTERATE */
-#define WM8915_DAC_MUTERATE_WIDTH                    1  /* DAC_MUTERATE */
-
-/*
- * R1568 (0x620) - Oversampling
- */
-#define WM8915_SPK_OSR128                       0x0008  /* SPK_OSR128 */
-#define WM8915_SPK_OSR128_MASK                  0x0008  /* SPK_OSR128 */
-#define WM8915_SPK_OSR128_SHIFT                      3  /* SPK_OSR128 */
-#define WM8915_SPK_OSR128_WIDTH                      1  /* SPK_OSR128 */
-#define WM8915_DMIC_OSR64                       0x0004  /* DMIC_OSR64 */
-#define WM8915_DMIC_OSR64_MASK                  0x0004  /* DMIC_OSR64 */
-#define WM8915_DMIC_OSR64_SHIFT                      2  /* DMIC_OSR64 */
-#define WM8915_DMIC_OSR64_WIDTH                      1  /* DMIC_OSR64 */
-#define WM8915_ADC_OSR128                       0x0002  /* ADC_OSR128 */
-#define WM8915_ADC_OSR128_MASK                  0x0002  /* ADC_OSR128 */
-#define WM8915_ADC_OSR128_SHIFT                      1  /* ADC_OSR128 */
-#define WM8915_ADC_OSR128_WIDTH                      1  /* ADC_OSR128 */
-#define WM8915_DAC_OSR128                       0x0001  /* DAC_OSR128 */
-#define WM8915_DAC_OSR128_MASK                  0x0001  /* DAC_OSR128 */
-#define WM8915_DAC_OSR128_SHIFT                      0  /* DAC_OSR128 */
-#define WM8915_DAC_OSR128_WIDTH                      1  /* DAC_OSR128 */
-
-/*
- * R1569 (0x621) - Sidetone
- */
-#define WM8915_ST_LPF                           0x1000  /* ST_LPF */
-#define WM8915_ST_LPF_MASK                      0x1000  /* ST_LPF */
-#define WM8915_ST_LPF_SHIFT                         12  /* ST_LPF */
-#define WM8915_ST_LPF_WIDTH                          1  /* ST_LPF */
-#define WM8915_ST_HPF_CUT_MASK                  0x0380  /* ST_HPF_CUT - [9:7] */
-#define WM8915_ST_HPF_CUT_SHIFT                      7  /* ST_HPF_CUT - [9:7] */
-#define WM8915_ST_HPF_CUT_WIDTH                      3  /* ST_HPF_CUT - [9:7] */
-#define WM8915_ST_HPF                           0x0040  /* ST_HPF */
-#define WM8915_ST_HPF_MASK                      0x0040  /* ST_HPF */
-#define WM8915_ST_HPF_SHIFT                          6  /* ST_HPF */
-#define WM8915_ST_HPF_WIDTH                          1  /* ST_HPF */
-#define WM8915_STR_SEL                          0x0002  /* STR_SEL */
-#define WM8915_STR_SEL_MASK                     0x0002  /* STR_SEL */
-#define WM8915_STR_SEL_SHIFT                         1  /* STR_SEL */
-#define WM8915_STR_SEL_WIDTH                         1  /* STR_SEL */
-#define WM8915_STL_SEL                          0x0001  /* STL_SEL */
-#define WM8915_STL_SEL_MASK                     0x0001  /* STL_SEL */
-#define WM8915_STL_SEL_SHIFT                         0  /* STL_SEL */
-#define WM8915_STL_SEL_WIDTH                         1  /* STL_SEL */
-
-/*
- * R1792 (0x700) - GPIO 1
- */
-#define WM8915_GP1_DIR                          0x8000  /* GP1_DIR */
-#define WM8915_GP1_DIR_MASK                     0x8000  /* GP1_DIR */
-#define WM8915_GP1_DIR_SHIFT                        15  /* GP1_DIR */
-#define WM8915_GP1_DIR_WIDTH                         1  /* GP1_DIR */
-#define WM8915_GP1_PU                           0x4000  /* GP1_PU */
-#define WM8915_GP1_PU_MASK                      0x4000  /* GP1_PU */
-#define WM8915_GP1_PU_SHIFT                         14  /* GP1_PU */
-#define WM8915_GP1_PU_WIDTH                          1  /* GP1_PU */
-#define WM8915_GP1_PD                           0x2000  /* GP1_PD */
-#define WM8915_GP1_PD_MASK                      0x2000  /* GP1_PD */
-#define WM8915_GP1_PD_SHIFT                         13  /* GP1_PD */
-#define WM8915_GP1_PD_WIDTH                          1  /* GP1_PD */
-#define WM8915_GP1_POL                          0x0400  /* GP1_POL */
-#define WM8915_GP1_POL_MASK                     0x0400  /* GP1_POL */
-#define WM8915_GP1_POL_SHIFT                        10  /* GP1_POL */
-#define WM8915_GP1_POL_WIDTH                         1  /* GP1_POL */
-#define WM8915_GP1_OP_CFG                       0x0200  /* GP1_OP_CFG */
-#define WM8915_GP1_OP_CFG_MASK                  0x0200  /* GP1_OP_CFG */
-#define WM8915_GP1_OP_CFG_SHIFT                      9  /* GP1_OP_CFG */
-#define WM8915_GP1_OP_CFG_WIDTH                      1  /* GP1_OP_CFG */
-#define WM8915_GP1_DB                           0x0100  /* GP1_DB */
-#define WM8915_GP1_DB_MASK                      0x0100  /* GP1_DB */
-#define WM8915_GP1_DB_SHIFT                          8  /* GP1_DB */
-#define WM8915_GP1_DB_WIDTH                          1  /* GP1_DB */
-#define WM8915_GP1_LVL                          0x0040  /* GP1_LVL */
-#define WM8915_GP1_LVL_MASK                     0x0040  /* GP1_LVL */
-#define WM8915_GP1_LVL_SHIFT                         6  /* GP1_LVL */
-#define WM8915_GP1_LVL_WIDTH                         1  /* GP1_LVL */
-#define WM8915_GP1_FN_MASK                      0x000F  /* GP1_FN - [3:0] */
-#define WM8915_GP1_FN_SHIFT                          0  /* GP1_FN - [3:0] */
-#define WM8915_GP1_FN_WIDTH                          4  /* GP1_FN - [3:0] */
-
-/*
- * R1793 (0x701) - GPIO 2
- */
-#define WM8915_GP2_DIR                          0x8000  /* GP2_DIR */
-#define WM8915_GP2_DIR_MASK                     0x8000  /* GP2_DIR */
-#define WM8915_GP2_DIR_SHIFT                        15  /* GP2_DIR */
-#define WM8915_GP2_DIR_WIDTH                         1  /* GP2_DIR */
-#define WM8915_GP2_PU                           0x4000  /* GP2_PU */
-#define WM8915_GP2_PU_MASK                      0x4000  /* GP2_PU */
-#define WM8915_GP2_PU_SHIFT                         14  /* GP2_PU */
-#define WM8915_GP2_PU_WIDTH                          1  /* GP2_PU */
-#define WM8915_GP2_PD                           0x2000  /* GP2_PD */
-#define WM8915_GP2_PD_MASK                      0x2000  /* GP2_PD */
-#define WM8915_GP2_PD_SHIFT                         13  /* GP2_PD */
-#define WM8915_GP2_PD_WIDTH                          1  /* GP2_PD */
-#define WM8915_GP2_POL                          0x0400  /* GP2_POL */
-#define WM8915_GP2_POL_MASK                     0x0400  /* GP2_POL */
-#define WM8915_GP2_POL_SHIFT                        10  /* GP2_POL */
-#define WM8915_GP2_POL_WIDTH                         1  /* GP2_POL */
-#define WM8915_GP2_OP_CFG                       0x0200  /* GP2_OP_CFG */
-#define WM8915_GP2_OP_CFG_MASK                  0x0200  /* GP2_OP_CFG */
-#define WM8915_GP2_OP_CFG_SHIFT                      9  /* GP2_OP_CFG */
-#define WM8915_GP2_OP_CFG_WIDTH                      1  /* GP2_OP_CFG */
-#define WM8915_GP2_DB                           0x0100  /* GP2_DB */
-#define WM8915_GP2_DB_MASK                      0x0100  /* GP2_DB */
-#define WM8915_GP2_DB_SHIFT                          8  /* GP2_DB */
-#define WM8915_GP2_DB_WIDTH                          1  /* GP2_DB */
-#define WM8915_GP2_LVL                          0x0040  /* GP2_LVL */
-#define WM8915_GP2_LVL_MASK                     0x0040  /* GP2_LVL */
-#define WM8915_GP2_LVL_SHIFT                         6  /* GP2_LVL */
-#define WM8915_GP2_LVL_WIDTH                         1  /* GP2_LVL */
-#define WM8915_GP2_FN_MASK                      0x000F  /* GP2_FN - [3:0] */
-#define WM8915_GP2_FN_SHIFT                          0  /* GP2_FN - [3:0] */
-#define WM8915_GP2_FN_WIDTH                          4  /* GP2_FN - [3:0] */
-
-/*
- * R1794 (0x702) - GPIO 3
- */
-#define WM8915_GP3_DIR                          0x8000  /* GP3_DIR */
-#define WM8915_GP3_DIR_MASK                     0x8000  /* GP3_DIR */
-#define WM8915_GP3_DIR_SHIFT                        15  /* GP3_DIR */
-#define WM8915_GP3_DIR_WIDTH                         1  /* GP3_DIR */
-#define WM8915_GP3_PU                           0x4000  /* GP3_PU */
-#define WM8915_GP3_PU_MASK                      0x4000  /* GP3_PU */
-#define WM8915_GP3_PU_SHIFT                         14  /* GP3_PU */
-#define WM8915_GP3_PU_WIDTH                          1  /* GP3_PU */
-#define WM8915_GP3_PD                           0x2000  /* GP3_PD */
-#define WM8915_GP3_PD_MASK                      0x2000  /* GP3_PD */
-#define WM8915_GP3_PD_SHIFT                         13  /* GP3_PD */
-#define WM8915_GP3_PD_WIDTH                          1  /* GP3_PD */
-#define WM8915_GP3_POL                          0x0400  /* GP3_POL */
-#define WM8915_GP3_POL_MASK                     0x0400  /* GP3_POL */
-#define WM8915_GP3_POL_SHIFT                        10  /* GP3_POL */
-#define WM8915_GP3_POL_WIDTH                         1  /* GP3_POL */
-#define WM8915_GP3_OP_CFG                       0x0200  /* GP3_OP_CFG */
-#define WM8915_GP3_OP_CFG_MASK                  0x0200  /* GP3_OP_CFG */
-#define WM8915_GP3_OP_CFG_SHIFT                      9  /* GP3_OP_CFG */
-#define WM8915_GP3_OP_CFG_WIDTH                      1  /* GP3_OP_CFG */
-#define WM8915_GP3_DB                           0x0100  /* GP3_DB */
-#define WM8915_GP3_DB_MASK                      0x0100  /* GP3_DB */
-#define WM8915_GP3_DB_SHIFT                          8  /* GP3_DB */
-#define WM8915_GP3_DB_WIDTH                          1  /* GP3_DB */
-#define WM8915_GP3_LVL                          0x0040  /* GP3_LVL */
-#define WM8915_GP3_LVL_MASK                     0x0040  /* GP3_LVL */
-#define WM8915_GP3_LVL_SHIFT                         6  /* GP3_LVL */
-#define WM8915_GP3_LVL_WIDTH                         1  /* GP3_LVL */
-#define WM8915_GP3_FN_MASK                      0x000F  /* GP3_FN - [3:0] */
-#define WM8915_GP3_FN_SHIFT                          0  /* GP3_FN - [3:0] */
-#define WM8915_GP3_FN_WIDTH                          4  /* GP3_FN - [3:0] */
-
-/*
- * R1795 (0x703) - GPIO 4
- */
-#define WM8915_GP4_DIR                          0x8000  /* GP4_DIR */
-#define WM8915_GP4_DIR_MASK                     0x8000  /* GP4_DIR */
-#define WM8915_GP4_DIR_SHIFT                        15  /* GP4_DIR */
-#define WM8915_GP4_DIR_WIDTH                         1  /* GP4_DIR */
-#define WM8915_GP4_PU                           0x4000  /* GP4_PU */
-#define WM8915_GP4_PU_MASK                      0x4000  /* GP4_PU */
-#define WM8915_GP4_PU_SHIFT                         14  /* GP4_PU */
-#define WM8915_GP4_PU_WIDTH                          1  /* GP4_PU */
-#define WM8915_GP4_PD                           0x2000  /* GP4_PD */
-#define WM8915_GP4_PD_MASK                      0x2000  /* GP4_PD */
-#define WM8915_GP4_PD_SHIFT                         13  /* GP4_PD */
-#define WM8915_GP4_PD_WIDTH                          1  /* GP4_PD */
-#define WM8915_GP4_POL                          0x0400  /* GP4_POL */
-#define WM8915_GP4_POL_MASK                     0x0400  /* GP4_POL */
-#define WM8915_GP4_POL_SHIFT                        10  /* GP4_POL */
-#define WM8915_GP4_POL_WIDTH                         1  /* GP4_POL */
-#define WM8915_GP4_OP_CFG                       0x0200  /* GP4_OP_CFG */
-#define WM8915_GP4_OP_CFG_MASK                  0x0200  /* GP4_OP_CFG */
-#define WM8915_GP4_OP_CFG_SHIFT                      9  /* GP4_OP_CFG */
-#define WM8915_GP4_OP_CFG_WIDTH                      1  /* GP4_OP_CFG */
-#define WM8915_GP4_DB                           0x0100  /* GP4_DB */
-#define WM8915_GP4_DB_MASK                      0x0100  /* GP4_DB */
-#define WM8915_GP4_DB_SHIFT                          8  /* GP4_DB */
-#define WM8915_GP4_DB_WIDTH                          1  /* GP4_DB */
-#define WM8915_GP4_LVL                          0x0040  /* GP4_LVL */
-#define WM8915_GP4_LVL_MASK                     0x0040  /* GP4_LVL */
-#define WM8915_GP4_LVL_SHIFT                         6  /* GP4_LVL */
-#define WM8915_GP4_LVL_WIDTH                         1  /* GP4_LVL */
-#define WM8915_GP4_FN_MASK                      0x000F  /* GP4_FN - [3:0] */
-#define WM8915_GP4_FN_SHIFT                          0  /* GP4_FN - [3:0] */
-#define WM8915_GP4_FN_WIDTH                          4  /* GP4_FN - [3:0] */
-
-/*
- * R1796 (0x704) - GPIO 5
- */
-#define WM8915_GP5_DIR                          0x8000  /* GP5_DIR */
-#define WM8915_GP5_DIR_MASK                     0x8000  /* GP5_DIR */
-#define WM8915_GP5_DIR_SHIFT                        15  /* GP5_DIR */
-#define WM8915_GP5_DIR_WIDTH                         1  /* GP5_DIR */
-#define WM8915_GP5_PU                           0x4000  /* GP5_PU */
-#define WM8915_GP5_PU_MASK                      0x4000  /* GP5_PU */
-#define WM8915_GP5_PU_SHIFT                         14  /* GP5_PU */
-#define WM8915_GP5_PU_WIDTH                          1  /* GP5_PU */
-#define WM8915_GP5_PD                           0x2000  /* GP5_PD */
-#define WM8915_GP5_PD_MASK                      0x2000  /* GP5_PD */
-#define WM8915_GP5_PD_SHIFT                         13  /* GP5_PD */
-#define WM8915_GP5_PD_WIDTH                          1  /* GP5_PD */
-#define WM8915_GP5_POL                          0x0400  /* GP5_POL */
-#define WM8915_GP5_POL_MASK                     0x0400  /* GP5_POL */
-#define WM8915_GP5_POL_SHIFT                        10  /* GP5_POL */
-#define WM8915_GP5_POL_WIDTH                         1  /* GP5_POL */
-#define WM8915_GP5_OP_CFG                       0x0200  /* GP5_OP_CFG */
-#define WM8915_GP5_OP_CFG_MASK                  0x0200  /* GP5_OP_CFG */
-#define WM8915_GP5_OP_CFG_SHIFT                      9  /* GP5_OP_CFG */
-#define WM8915_GP5_OP_CFG_WIDTH                      1  /* GP5_OP_CFG */
-#define WM8915_GP5_DB                           0x0100  /* GP5_DB */
-#define WM8915_GP5_DB_MASK                      0x0100  /* GP5_DB */
-#define WM8915_GP5_DB_SHIFT                          8  /* GP5_DB */
-#define WM8915_GP5_DB_WIDTH                          1  /* GP5_DB */
-#define WM8915_GP5_LVL                          0x0040  /* GP5_LVL */
-#define WM8915_GP5_LVL_MASK                     0x0040  /* GP5_LVL */
-#define WM8915_GP5_LVL_SHIFT                         6  /* GP5_LVL */
-#define WM8915_GP5_LVL_WIDTH                         1  /* GP5_LVL */
-#define WM8915_GP5_FN_MASK                      0x000F  /* GP5_FN - [3:0] */
-#define WM8915_GP5_FN_SHIFT                          0  /* GP5_FN - [3:0] */
-#define WM8915_GP5_FN_WIDTH                          4  /* GP5_FN - [3:0] */
-
-/*
- * R1824 (0x720) - Pull Control (1)
- */
-#define WM8915_DMICDAT2_PD                      0x1000  /* DMICDAT2_PD */
-#define WM8915_DMICDAT2_PD_MASK                 0x1000  /* DMICDAT2_PD */
-#define WM8915_DMICDAT2_PD_SHIFT                    12  /* DMICDAT2_PD */
-#define WM8915_DMICDAT2_PD_WIDTH                     1  /* DMICDAT2_PD */
-#define WM8915_DMICDAT1_PD                      0x0400  /* DMICDAT1_PD */
-#define WM8915_DMICDAT1_PD_MASK                 0x0400  /* DMICDAT1_PD */
-#define WM8915_DMICDAT1_PD_SHIFT                    10  /* DMICDAT1_PD */
-#define WM8915_DMICDAT1_PD_WIDTH                     1  /* DMICDAT1_PD */
-#define WM8915_MCLK2_PU                         0x0200  /* MCLK2_PU */
-#define WM8915_MCLK2_PU_MASK                    0x0200  /* MCLK2_PU */
-#define WM8915_MCLK2_PU_SHIFT                        9  /* MCLK2_PU */
-#define WM8915_MCLK2_PU_WIDTH                        1  /* MCLK2_PU */
-#define WM8915_MCLK2_PD                         0x0100  /* MCLK2_PD */
-#define WM8915_MCLK2_PD_MASK                    0x0100  /* MCLK2_PD */
-#define WM8915_MCLK2_PD_SHIFT                        8  /* MCLK2_PD */
-#define WM8915_MCLK2_PD_WIDTH                        1  /* MCLK2_PD */
-#define WM8915_MCLK1_PU                         0x0080  /* MCLK1_PU */
-#define WM8915_MCLK1_PU_MASK                    0x0080  /* MCLK1_PU */
-#define WM8915_MCLK1_PU_SHIFT                        7  /* MCLK1_PU */
-#define WM8915_MCLK1_PU_WIDTH                        1  /* MCLK1_PU */
-#define WM8915_MCLK1_PD                         0x0040  /* MCLK1_PD */
-#define WM8915_MCLK1_PD_MASK                    0x0040  /* MCLK1_PD */
-#define WM8915_MCLK1_PD_SHIFT                        6  /* MCLK1_PD */
-#define WM8915_MCLK1_PD_WIDTH                        1  /* MCLK1_PD */
-#define WM8915_DACDAT1_PU                       0x0020  /* DACDAT1_PU */
-#define WM8915_DACDAT1_PU_MASK                  0x0020  /* DACDAT1_PU */
-#define WM8915_DACDAT1_PU_SHIFT                      5  /* DACDAT1_PU */
-#define WM8915_DACDAT1_PU_WIDTH                      1  /* DACDAT1_PU */
-#define WM8915_DACDAT1_PD                       0x0010  /* DACDAT1_PD */
-#define WM8915_DACDAT1_PD_MASK                  0x0010  /* DACDAT1_PD */
-#define WM8915_DACDAT1_PD_SHIFT                      4  /* DACDAT1_PD */
-#define WM8915_DACDAT1_PD_WIDTH                      1  /* DACDAT1_PD */
-#define WM8915_DACLRCLK1_PU                     0x0008  /* DACLRCLK1_PU */
-#define WM8915_DACLRCLK1_PU_MASK                0x0008  /* DACLRCLK1_PU */
-#define WM8915_DACLRCLK1_PU_SHIFT                    3  /* DACLRCLK1_PU */
-#define WM8915_DACLRCLK1_PU_WIDTH                    1  /* DACLRCLK1_PU */
-#define WM8915_DACLRCLK1_PD                     0x0004  /* DACLRCLK1_PD */
-#define WM8915_DACLRCLK1_PD_MASK                0x0004  /* DACLRCLK1_PD */
-#define WM8915_DACLRCLK1_PD_SHIFT                    2  /* DACLRCLK1_PD */
-#define WM8915_DACLRCLK1_PD_WIDTH                    1  /* DACLRCLK1_PD */
-#define WM8915_BCLK1_PU                         0x0002  /* BCLK1_PU */
-#define WM8915_BCLK1_PU_MASK                    0x0002  /* BCLK1_PU */
-#define WM8915_BCLK1_PU_SHIFT                        1  /* BCLK1_PU */
-#define WM8915_BCLK1_PU_WIDTH                        1  /* BCLK1_PU */
-#define WM8915_BCLK1_PD                         0x0001  /* BCLK1_PD */
-#define WM8915_BCLK1_PD_MASK                    0x0001  /* BCLK1_PD */
-#define WM8915_BCLK1_PD_SHIFT                        0  /* BCLK1_PD */
-#define WM8915_BCLK1_PD_WIDTH                        1  /* BCLK1_PD */
-
-/*
- * R1825 (0x721) - Pull Control (2)
- */
-#define WM8915_LDO1ENA_PD                       0x0100  /* LDO1ENA_PD */
-#define WM8915_LDO1ENA_PD_MASK                  0x0100  /* LDO1ENA_PD */
-#define WM8915_LDO1ENA_PD_SHIFT                      8  /* LDO1ENA_PD */
-#define WM8915_LDO1ENA_PD_WIDTH                      1  /* LDO1ENA_PD */
-#define WM8915_ADDR_PD                          0x0040  /* ADDR_PD */
-#define WM8915_ADDR_PD_MASK                     0x0040  /* ADDR_PD */
-#define WM8915_ADDR_PD_SHIFT                         6  /* ADDR_PD */
-#define WM8915_ADDR_PD_WIDTH                         1  /* ADDR_PD */
-#define WM8915_DACDAT2_PU                       0x0020  /* DACDAT2_PU */
-#define WM8915_DACDAT2_PU_MASK                  0x0020  /* DACDAT2_PU */
-#define WM8915_DACDAT2_PU_SHIFT                      5  /* DACDAT2_PU */
-#define WM8915_DACDAT2_PU_WIDTH                      1  /* DACDAT2_PU */
-#define WM8915_DACDAT2_PD                       0x0010  /* DACDAT2_PD */
-#define WM8915_DACDAT2_PD_MASK                  0x0010  /* DACDAT2_PD */
-#define WM8915_DACDAT2_PD_SHIFT                      4  /* DACDAT2_PD */
-#define WM8915_DACDAT2_PD_WIDTH                      1  /* DACDAT2_PD */
-#define WM8915_DACLRCLK2_PU                     0x0008  /* DACLRCLK2_PU */
-#define WM8915_DACLRCLK2_PU_MASK                0x0008  /* DACLRCLK2_PU */
-#define WM8915_DACLRCLK2_PU_SHIFT                    3  /* DACLRCLK2_PU */
-#define WM8915_DACLRCLK2_PU_WIDTH                    1  /* DACLRCLK2_PU */
-#define WM8915_DACLRCLK2_PD                     0x0004  /* DACLRCLK2_PD */
-#define WM8915_DACLRCLK2_PD_MASK                0x0004  /* DACLRCLK2_PD */
-#define WM8915_DACLRCLK2_PD_SHIFT                    2  /* DACLRCLK2_PD */
-#define WM8915_DACLRCLK2_PD_WIDTH                    1  /* DACLRCLK2_PD */
-#define WM8915_BCLK2_PU                         0x0002  /* BCLK2_PU */
-#define WM8915_BCLK2_PU_MASK                    0x0002  /* BCLK2_PU */
-#define WM8915_BCLK2_PU_SHIFT                        1  /* BCLK2_PU */
-#define WM8915_BCLK2_PU_WIDTH                        1  /* BCLK2_PU */
-#define WM8915_BCLK2_PD                         0x0001  /* BCLK2_PD */
-#define WM8915_BCLK2_PD_MASK                    0x0001  /* BCLK2_PD */
-#define WM8915_BCLK2_PD_SHIFT                        0  /* BCLK2_PD */
-#define WM8915_BCLK2_PD_WIDTH                        1  /* BCLK2_PD */
-
-/*
- * R1840 (0x730) - Interrupt Status 1
- */
-#define WM8915_GP5_EINT                         0x0010  /* GP5_EINT */
-#define WM8915_GP5_EINT_MASK                    0x0010  /* GP5_EINT */
-#define WM8915_GP5_EINT_SHIFT                        4  /* GP5_EINT */
-#define WM8915_GP5_EINT_WIDTH                        1  /* GP5_EINT */
-#define WM8915_GP4_EINT                         0x0008  /* GP4_EINT */
-#define WM8915_GP4_EINT_MASK                    0x0008  /* GP4_EINT */
-#define WM8915_GP4_EINT_SHIFT                        3  /* GP4_EINT */
-#define WM8915_GP4_EINT_WIDTH                        1  /* GP4_EINT */
-#define WM8915_GP3_EINT                         0x0004  /* GP3_EINT */
-#define WM8915_GP3_EINT_MASK                    0x0004  /* GP3_EINT */
-#define WM8915_GP3_EINT_SHIFT                        2  /* GP3_EINT */
-#define WM8915_GP3_EINT_WIDTH                        1  /* GP3_EINT */
-#define WM8915_GP2_EINT                         0x0002  /* GP2_EINT */
-#define WM8915_GP2_EINT_MASK                    0x0002  /* GP2_EINT */
-#define WM8915_GP2_EINT_SHIFT                        1  /* GP2_EINT */
-#define WM8915_GP2_EINT_WIDTH                        1  /* GP2_EINT */
-#define WM8915_GP1_EINT                         0x0001  /* GP1_EINT */
-#define WM8915_GP1_EINT_MASK                    0x0001  /* GP1_EINT */
-#define WM8915_GP1_EINT_SHIFT                        0  /* GP1_EINT */
-#define WM8915_GP1_EINT_WIDTH                        1  /* GP1_EINT */
-
-/*
- * R1841 (0x731) - Interrupt Status 2
- */
-#define WM8915_DCS_DONE_23_EINT                 0x1000  /* DCS_DONE_23_EINT */
-#define WM8915_DCS_DONE_23_EINT_MASK            0x1000  /* DCS_DONE_23_EINT */
-#define WM8915_DCS_DONE_23_EINT_SHIFT               12  /* DCS_DONE_23_EINT */
-#define WM8915_DCS_DONE_23_EINT_WIDTH                1  /* DCS_DONE_23_EINT */
-#define WM8915_DCS_DONE_01_EINT                 0x0800  /* DCS_DONE_01_EINT */
-#define WM8915_DCS_DONE_01_EINT_MASK            0x0800  /* DCS_DONE_01_EINT */
-#define WM8915_DCS_DONE_01_EINT_SHIFT               11  /* DCS_DONE_01_EINT */
-#define WM8915_DCS_DONE_01_EINT_WIDTH                1  /* DCS_DONE_01_EINT */
-#define WM8915_WSEQ_DONE_EINT                   0x0400  /* WSEQ_DONE_EINT */
-#define WM8915_WSEQ_DONE_EINT_MASK              0x0400  /* WSEQ_DONE_EINT */
-#define WM8915_WSEQ_DONE_EINT_SHIFT                 10  /* WSEQ_DONE_EINT */
-#define WM8915_WSEQ_DONE_EINT_WIDTH                  1  /* WSEQ_DONE_EINT */
-#define WM8915_FIFOS_ERR_EINT                   0x0200  /* FIFOS_ERR_EINT */
-#define WM8915_FIFOS_ERR_EINT_MASK              0x0200  /* FIFOS_ERR_EINT */
-#define WM8915_FIFOS_ERR_EINT_SHIFT                  9  /* FIFOS_ERR_EINT */
-#define WM8915_FIFOS_ERR_EINT_WIDTH                  1  /* FIFOS_ERR_EINT */
-#define WM8915_DSP2DRC_SIG_DET_EINT             0x0080  /* DSP2DRC_SIG_DET_EINT */
-#define WM8915_DSP2DRC_SIG_DET_EINT_MASK        0x0080  /* DSP2DRC_SIG_DET_EINT */
-#define WM8915_DSP2DRC_SIG_DET_EINT_SHIFT            7  /* DSP2DRC_SIG_DET_EINT */
-#define WM8915_DSP2DRC_SIG_DET_EINT_WIDTH            1  /* DSP2DRC_SIG_DET_EINT */
-#define WM8915_DSP1DRC_SIG_DET_EINT             0x0040  /* DSP1DRC_SIG_DET_EINT */
-#define WM8915_DSP1DRC_SIG_DET_EINT_MASK        0x0040  /* DSP1DRC_SIG_DET_EINT */
-#define WM8915_DSP1DRC_SIG_DET_EINT_SHIFT            6  /* DSP1DRC_SIG_DET_EINT */
-#define WM8915_DSP1DRC_SIG_DET_EINT_WIDTH            1  /* DSP1DRC_SIG_DET_EINT */
-#define WM8915_FLL_SW_CLK_DONE_EINT             0x0008  /* FLL_SW_CLK_DONE_EINT */
-#define WM8915_FLL_SW_CLK_DONE_EINT_MASK        0x0008  /* FLL_SW_CLK_DONE_EINT */
-#define WM8915_FLL_SW_CLK_DONE_EINT_SHIFT            3  /* FLL_SW_CLK_DONE_EINT */
-#define WM8915_FLL_SW_CLK_DONE_EINT_WIDTH            1  /* FLL_SW_CLK_DONE_EINT */
-#define WM8915_FLL_LOCK_EINT                    0x0004  /* FLL_LOCK_EINT */
-#define WM8915_FLL_LOCK_EINT_MASK               0x0004  /* FLL_LOCK_EINT */
-#define WM8915_FLL_LOCK_EINT_SHIFT                   2  /* FLL_LOCK_EINT */
-#define WM8915_FLL_LOCK_EINT_WIDTH                   1  /* FLL_LOCK_EINT */
-#define WM8915_HP_DONE_EINT                     0x0002  /* HP_DONE_EINT */
-#define WM8915_HP_DONE_EINT_MASK                0x0002  /* HP_DONE_EINT */
-#define WM8915_HP_DONE_EINT_SHIFT                    1  /* HP_DONE_EINT */
-#define WM8915_HP_DONE_EINT_WIDTH                    1  /* HP_DONE_EINT */
-#define WM8915_MICD_EINT                        0x0001  /* MICD_EINT */
-#define WM8915_MICD_EINT_MASK                   0x0001  /* MICD_EINT */
-#define WM8915_MICD_EINT_SHIFT                       0  /* MICD_EINT */
-#define WM8915_MICD_EINT_WIDTH                       1  /* MICD_EINT */
-
-/*
- * R1842 (0x732) - Interrupt Raw Status 2
- */
-#define WM8915_DCS_DONE_23_STS                  0x1000  /* DCS_DONE_23_STS */
-#define WM8915_DCS_DONE_23_STS_MASK             0x1000  /* DCS_DONE_23_STS */
-#define WM8915_DCS_DONE_23_STS_SHIFT                12  /* DCS_DONE_23_STS */
-#define WM8915_DCS_DONE_23_STS_WIDTH                 1  /* DCS_DONE_23_STS */
-#define WM8915_DCS_DONE_01_STS                  0x0800  /* DCS_DONE_01_STS */
-#define WM8915_DCS_DONE_01_STS_MASK             0x0800  /* DCS_DONE_01_STS */
-#define WM8915_DCS_DONE_01_STS_SHIFT                11  /* DCS_DONE_01_STS */
-#define WM8915_DCS_DONE_01_STS_WIDTH                 1  /* DCS_DONE_01_STS */
-#define WM8915_WSEQ_DONE_STS                    0x0400  /* WSEQ_DONE_STS */
-#define WM8915_WSEQ_DONE_STS_MASK               0x0400  /* WSEQ_DONE_STS */
-#define WM8915_WSEQ_DONE_STS_SHIFT                  10  /* WSEQ_DONE_STS */
-#define WM8915_WSEQ_DONE_STS_WIDTH                   1  /* WSEQ_DONE_STS */
-#define WM8915_FIFOS_ERR_STS                    0x0200  /* FIFOS_ERR_STS */
-#define WM8915_FIFOS_ERR_STS_MASK               0x0200  /* FIFOS_ERR_STS */
-#define WM8915_FIFOS_ERR_STS_SHIFT                   9  /* FIFOS_ERR_STS */
-#define WM8915_FIFOS_ERR_STS_WIDTH                   1  /* FIFOS_ERR_STS */
-#define WM8915_DSP2DRC_SIG_DET_STS              0x0080  /* DSP2DRC_SIG_DET_STS */
-#define WM8915_DSP2DRC_SIG_DET_STS_MASK         0x0080  /* DSP2DRC_SIG_DET_STS */
-#define WM8915_DSP2DRC_SIG_DET_STS_SHIFT             7  /* DSP2DRC_SIG_DET_STS */
-#define WM8915_DSP2DRC_SIG_DET_STS_WIDTH             1  /* DSP2DRC_SIG_DET_STS */
-#define WM8915_DSP1DRC_SIG_DET_STS              0x0040  /* DSP1DRC_SIG_DET_STS */
-#define WM8915_DSP1DRC_SIG_DET_STS_MASK         0x0040  /* DSP1DRC_SIG_DET_STS */
-#define WM8915_DSP1DRC_SIG_DET_STS_SHIFT             6  /* DSP1DRC_SIG_DET_STS */
-#define WM8915_DSP1DRC_SIG_DET_STS_WIDTH             1  /* DSP1DRC_SIG_DET_STS */
-#define WM8915_FLL_LOCK_STS                     0x0004  /* FLL_LOCK_STS */
-#define WM8915_FLL_LOCK_STS_MASK                0x0004  /* FLL_LOCK_STS */
-#define WM8915_FLL_LOCK_STS_SHIFT                    2  /* FLL_LOCK_STS */
-#define WM8915_FLL_LOCK_STS_WIDTH                    1  /* FLL_LOCK_STS */
-
-/*
- * R1848 (0x738) - Interrupt Status 1 Mask
- */
-#define WM8915_IM_GP5_EINT                      0x0010  /* IM_GP5_EINT */
-#define WM8915_IM_GP5_EINT_MASK                 0x0010  /* IM_GP5_EINT */
-#define WM8915_IM_GP5_EINT_SHIFT                     4  /* IM_GP5_EINT */
-#define WM8915_IM_GP5_EINT_WIDTH                     1  /* IM_GP5_EINT */
-#define WM8915_IM_GP4_EINT                      0x0008  /* IM_GP4_EINT */
-#define WM8915_IM_GP4_EINT_MASK                 0x0008  /* IM_GP4_EINT */
-#define WM8915_IM_GP4_EINT_SHIFT                     3  /* IM_GP4_EINT */
-#define WM8915_IM_GP4_EINT_WIDTH                     1  /* IM_GP4_EINT */
-#define WM8915_IM_GP3_EINT                      0x0004  /* IM_GP3_EINT */
-#define WM8915_IM_GP3_EINT_MASK                 0x0004  /* IM_GP3_EINT */
-#define WM8915_IM_GP3_EINT_SHIFT                     2  /* IM_GP3_EINT */
-#define WM8915_IM_GP3_EINT_WIDTH                     1  /* IM_GP3_EINT */
-#define WM8915_IM_GP2_EINT                      0x0002  /* IM_GP2_EINT */
-#define WM8915_IM_GP2_EINT_MASK                 0x0002  /* IM_GP2_EINT */
-#define WM8915_IM_GP2_EINT_SHIFT                     1  /* IM_GP2_EINT */
-#define WM8915_IM_GP2_EINT_WIDTH                     1  /* IM_GP2_EINT */
-#define WM8915_IM_GP1_EINT                      0x0001  /* IM_GP1_EINT */
-#define WM8915_IM_GP1_EINT_MASK                 0x0001  /* IM_GP1_EINT */
-#define WM8915_IM_GP1_EINT_SHIFT                     0  /* IM_GP1_EINT */
-#define WM8915_IM_GP1_EINT_WIDTH                     1  /* IM_GP1_EINT */
-
-/*
- * R1849 (0x739) - Interrupt Status 2 Mask
- */
-#define WM8915_IM_DCS_DONE_23_EINT              0x1000  /* IM_DCS_DONE_23_EINT */
-#define WM8915_IM_DCS_DONE_23_EINT_MASK         0x1000  /* IM_DCS_DONE_23_EINT */
-#define WM8915_IM_DCS_DONE_23_EINT_SHIFT            12  /* IM_DCS_DONE_23_EINT */
-#define WM8915_IM_DCS_DONE_23_EINT_WIDTH             1  /* IM_DCS_DONE_23_EINT */
-#define WM8915_IM_DCS_DONE_01_EINT              0x0800  /* IM_DCS_DONE_01_EINT */
-#define WM8915_IM_DCS_DONE_01_EINT_MASK         0x0800  /* IM_DCS_DONE_01_EINT */
-#define WM8915_IM_DCS_DONE_01_EINT_SHIFT            11  /* IM_DCS_DONE_01_EINT */
-#define WM8915_IM_DCS_DONE_01_EINT_WIDTH             1  /* IM_DCS_DONE_01_EINT */
-#define WM8915_IM_WSEQ_DONE_EINT                0x0400  /* IM_WSEQ_DONE_EINT */
-#define WM8915_IM_WSEQ_DONE_EINT_MASK           0x0400  /* IM_WSEQ_DONE_EINT */
-#define WM8915_IM_WSEQ_DONE_EINT_SHIFT              10  /* IM_WSEQ_DONE_EINT */
-#define WM8915_IM_WSEQ_DONE_EINT_WIDTH               1  /* IM_WSEQ_DONE_EINT */
-#define WM8915_IM_FIFOS_ERR_EINT                0x0200  /* IM_FIFOS_ERR_EINT */
-#define WM8915_IM_FIFOS_ERR_EINT_MASK           0x0200  /* IM_FIFOS_ERR_EINT */
-#define WM8915_IM_FIFOS_ERR_EINT_SHIFT               9  /* IM_FIFOS_ERR_EINT */
-#define WM8915_IM_FIFOS_ERR_EINT_WIDTH               1  /* IM_FIFOS_ERR_EINT */
-#define WM8915_IM_DSP2DRC_SIG_DET_EINT          0x0080  /* IM_DSP2DRC_SIG_DET_EINT */
-#define WM8915_IM_DSP2DRC_SIG_DET_EINT_MASK     0x0080  /* IM_DSP2DRC_SIG_DET_EINT */
-#define WM8915_IM_DSP2DRC_SIG_DET_EINT_SHIFT         7  /* IM_DSP2DRC_SIG_DET_EINT */
-#define WM8915_IM_DSP2DRC_SIG_DET_EINT_WIDTH         1  /* IM_DSP2DRC_SIG_DET_EINT */
-#define WM8915_IM_DSP1DRC_SIG_DET_EINT          0x0040  /* IM_DSP1DRC_SIG_DET_EINT */
-#define WM8915_IM_DSP1DRC_SIG_DET_EINT_MASK     0x0040  /* IM_DSP1DRC_SIG_DET_EINT */
-#define WM8915_IM_DSP1DRC_SIG_DET_EINT_SHIFT         6  /* IM_DSP1DRC_SIG_DET_EINT */
-#define WM8915_IM_DSP1DRC_SIG_DET_EINT_WIDTH         1  /* IM_DSP1DRC_SIG_DET_EINT */
-#define WM8915_IM_FLL_SW_CLK_DONE_EINT          0x0008  /* IM_FLL_SW_CLK_DONE_EINT */
-#define WM8915_IM_FLL_SW_CLK_DONE_EINT_MASK     0x0008  /* IM_FLL_SW_CLK_DONE_EINT */
-#define WM8915_IM_FLL_SW_CLK_DONE_EINT_SHIFT         3  /* IM_FLL_SW_CLK_DONE_EINT */
-#define WM8915_IM_FLL_SW_CLK_DONE_EINT_WIDTH         1  /* IM_FLL_SW_CLK_DONE_EINT */
-#define WM8915_IM_FLL_LOCK_EINT                 0x0004  /* IM_FLL_LOCK_EINT */
-#define WM8915_IM_FLL_LOCK_EINT_MASK            0x0004  /* IM_FLL_LOCK_EINT */
-#define WM8915_IM_FLL_LOCK_EINT_SHIFT                2  /* IM_FLL_LOCK_EINT */
-#define WM8915_IM_FLL_LOCK_EINT_WIDTH                1  /* IM_FLL_LOCK_EINT */
-#define WM8915_IM_HP_DONE_EINT                  0x0002  /* IM_HP_DONE_EINT */
-#define WM8915_IM_HP_DONE_EINT_MASK             0x0002  /* IM_HP_DONE_EINT */
-#define WM8915_IM_HP_DONE_EINT_SHIFT                 1  /* IM_HP_DONE_EINT */
-#define WM8915_IM_HP_DONE_EINT_WIDTH                 1  /* IM_HP_DONE_EINT */
-#define WM8915_IM_MICD_EINT                     0x0001  /* IM_MICD_EINT */
-#define WM8915_IM_MICD_EINT_MASK                0x0001  /* IM_MICD_EINT */
-#define WM8915_IM_MICD_EINT_SHIFT                    0  /* IM_MICD_EINT */
-#define WM8915_IM_MICD_EINT_WIDTH                    1  /* IM_MICD_EINT */
-
-/*
- * R1856 (0x740) - Interrupt Control
- */
-#define WM8915_IM_IRQ                           0x0001  /* IM_IRQ */
-#define WM8915_IM_IRQ_MASK                      0x0001  /* IM_IRQ */
-#define WM8915_IM_IRQ_SHIFT                          0  /* IM_IRQ */
-#define WM8915_IM_IRQ_WIDTH                          1  /* IM_IRQ */
-
-/*
- * R2048 (0x800) - Left PDM Speaker
- */
-#define WM8915_SPKL_ENA                         0x0010  /* SPKL_ENA */
-#define WM8915_SPKL_ENA_MASK                    0x0010  /* SPKL_ENA */
-#define WM8915_SPKL_ENA_SHIFT                        4  /* SPKL_ENA */
-#define WM8915_SPKL_ENA_WIDTH                        1  /* SPKL_ENA */
-#define WM8915_SPKL_MUTE                        0x0008  /* SPKL_MUTE */
-#define WM8915_SPKL_MUTE_MASK                   0x0008  /* SPKL_MUTE */
-#define WM8915_SPKL_MUTE_SHIFT                       3  /* SPKL_MUTE */
-#define WM8915_SPKL_MUTE_WIDTH                       1  /* SPKL_MUTE */
-#define WM8915_SPKL_MUTE_ZC                     0x0004  /* SPKL_MUTE_ZC */
-#define WM8915_SPKL_MUTE_ZC_MASK                0x0004  /* SPKL_MUTE_ZC */
-#define WM8915_SPKL_MUTE_ZC_SHIFT                    2  /* SPKL_MUTE_ZC */
-#define WM8915_SPKL_MUTE_ZC_WIDTH                    1  /* SPKL_MUTE_ZC */
-#define WM8915_SPKL_SRC_MASK                    0x0003  /* SPKL_SRC - [1:0] */
-#define WM8915_SPKL_SRC_SHIFT                        0  /* SPKL_SRC - [1:0] */
-#define WM8915_SPKL_SRC_WIDTH                        2  /* SPKL_SRC - [1:0] */
-
-/*
- * R2049 (0x801) - Right PDM Speaker
- */
-#define WM8915_SPKR_ENA                         0x0010  /* SPKR_ENA */
-#define WM8915_SPKR_ENA_MASK                    0x0010  /* SPKR_ENA */
-#define WM8915_SPKR_ENA_SHIFT                        4  /* SPKR_ENA */
-#define WM8915_SPKR_ENA_WIDTH                        1  /* SPKR_ENA */
-#define WM8915_SPKR_MUTE                        0x0008  /* SPKR_MUTE */
-#define WM8915_SPKR_MUTE_MASK                   0x0008  /* SPKR_MUTE */
-#define WM8915_SPKR_MUTE_SHIFT                       3  /* SPKR_MUTE */
-#define WM8915_SPKR_MUTE_WIDTH                       1  /* SPKR_MUTE */
-#define WM8915_SPKR_MUTE_ZC                     0x0004  /* SPKR_MUTE_ZC */
-#define WM8915_SPKR_MUTE_ZC_MASK                0x0004  /* SPKR_MUTE_ZC */
-#define WM8915_SPKR_MUTE_ZC_SHIFT                    2  /* SPKR_MUTE_ZC */
-#define WM8915_SPKR_MUTE_ZC_WIDTH                    1  /* SPKR_MUTE_ZC */
-#define WM8915_SPKR_SRC_MASK                    0x0003  /* SPKR_SRC - [1:0] */
-#define WM8915_SPKR_SRC_SHIFT                        0  /* SPKR_SRC - [1:0] */
-#define WM8915_SPKR_SRC_WIDTH                        2  /* SPKR_SRC - [1:0] */
-
-/*
- * R2050 (0x802) - PDM Speaker Mute Sequence
- */
-#define WM8915_SPK_MUTE_ENDIAN                  0x0100  /* SPK_MUTE_ENDIAN */
-#define WM8915_SPK_MUTE_ENDIAN_MASK             0x0100  /* SPK_MUTE_ENDIAN */
-#define WM8915_SPK_MUTE_ENDIAN_SHIFT                 8  /* SPK_MUTE_ENDIAN */
-#define WM8915_SPK_MUTE_ENDIAN_WIDTH                 1  /* SPK_MUTE_ENDIAN */
-#define WM8915_SPK_MUTE_SEQ1_MASK               0x00FF  /* SPK_MUTE_SEQ1 - [7:0] */
-#define WM8915_SPK_MUTE_SEQ1_SHIFT                   0  /* SPK_MUTE_SEQ1 - [7:0] */
-#define WM8915_SPK_MUTE_SEQ1_WIDTH                   8  /* SPK_MUTE_SEQ1 - [7:0] */
-
-/*
- * R2051 (0x803) - PDM Speaker Volume
- */
-#define WM8915_SPKR_VOL_MASK                    0x00F0  /* SPKR_VOL - [7:4] */
-#define WM8915_SPKR_VOL_SHIFT                        4  /* SPKR_VOL - [7:4] */
-#define WM8915_SPKR_VOL_WIDTH                        4  /* SPKR_VOL - [7:4] */
-#define WM8915_SPKL_VOL_MASK                    0x000F  /* SPKL_VOL - [3:0] */
-#define WM8915_SPKL_VOL_SHIFT                        0  /* SPKL_VOL - [3:0] */
-#define WM8915_SPKL_VOL_WIDTH                        4  /* SPKL_VOL - [3:0] */
-
-#endif
index 09e680a..b393f9f 100644 (file)
@@ -2981,6 +2981,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                        wm8994->hubs.dcs_readback_mode = 1;
                        break;
                }
+               break;
 
        case WM8958:
                wm8994->hubs.dcs_readback_mode = 1;
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
new file mode 100644 (file)
index 0000000..ab8e9d1
--- /dev/null
@@ -0,0 +1,2994 @@
+/*
+ * wm8996.c - WM8996 audio codec interface
+ *
+ * Copyright 2011 Wolfson Microelectronics PLC.
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/gcd.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <trace/events/asoc.h>
+
+#include <sound/wm8996.h>
+#include "wm8996.h"
+
+#define WM8996_AIFS 2
+
+#define HPOUT1L 1
+#define HPOUT1R 2
+#define HPOUT2L 4
+#define HPOUT2R 8
+
+#define WM8996_NUM_SUPPLIES 4
+static const char *wm8996_supply_names[WM8996_NUM_SUPPLIES] = {
+       "DBVDD",
+       "AVDD1",
+       "AVDD2",
+       "CPVDD",
+};
+
+struct wm8996_priv {
+       struct snd_soc_codec *codec;
+
+       int ldo1ena;
+
+       int sysclk;
+       int sysclk_src;
+
+       int fll_src;
+       int fll_fref;
+       int fll_fout;
+
+       struct completion fll_lock;
+
+       u16 dcs_pending;
+       struct completion dcs_done;
+
+       u16 hpout_ena;
+       u16 hpout_pending;
+
+       struct regulator_bulk_data supplies[WM8996_NUM_SUPPLIES];
+       struct notifier_block disable_nb[WM8996_NUM_SUPPLIES];
+
+       struct wm8996_pdata pdata;
+
+       int rx_rate[WM8996_AIFS];
+       int bclk_rate[WM8996_AIFS];
+
+       /* Platform dependant ReTune mobile configuration */
+       int num_retune_mobile_texts;
+       const char **retune_mobile_texts;
+       int retune_mobile_cfg[2];
+       struct soc_enum retune_mobile_enum;
+
+       struct snd_soc_jack *jack;
+       bool detecting;
+       bool jack_mic;
+       wm8996_polarity_fn polarity_cb;
+
+#ifdef CONFIG_GPIOLIB
+       struct gpio_chip gpio_chip;
+#endif
+};
+
+/* We can't use the same notifier block for more than one supply and
+ * there's no way I can see to get from a callback to the caller
+ * except container_of().
+ */
+#define WM8996_REGULATOR_EVENT(n) \
+static int wm8996_regulator_event_##n(struct notifier_block *nb, \
+                                   unsigned long event, void *data)    \
+{ \
+       struct wm8996_priv *wm8996 = container_of(nb, struct wm8996_priv, \
+                                                 disable_nb[n]); \
+       if (event & REGULATOR_EVENT_DISABLE) { \
+               wm8996->codec->cache_sync = 1; \
+       } \
+       return 0; \
+}
+
+WM8996_REGULATOR_EVENT(0)
+WM8996_REGULATOR_EVENT(1)
+WM8996_REGULATOR_EVENT(2)
+WM8996_REGULATOR_EVENT(3)
+
+static const u16 wm8996_reg[WM8996_MAX_REGISTER] = {
+       [WM8996_SOFTWARE_RESET] = 0x8996,
+       [WM8996_POWER_MANAGEMENT_7] = 0x10,
+       [WM8996_DAC1_HPOUT1_VOLUME] = 0x88,
+       [WM8996_DAC2_HPOUT2_VOLUME] = 0x88,
+       [WM8996_DAC1_LEFT_VOLUME] = 0x2c0,
+       [WM8996_DAC1_RIGHT_VOLUME] = 0x2c0,
+       [WM8996_DAC2_LEFT_VOLUME] = 0x2c0,
+       [WM8996_DAC2_RIGHT_VOLUME] = 0x2c0,
+       [WM8996_OUTPUT1_LEFT_VOLUME] = 0x80,
+       [WM8996_OUTPUT1_RIGHT_VOLUME] = 0x80,
+       [WM8996_OUTPUT2_LEFT_VOLUME] = 0x80,
+       [WM8996_OUTPUT2_RIGHT_VOLUME] = 0x80,
+       [WM8996_MICBIAS_1] = 0x39,
+       [WM8996_MICBIAS_2] = 0x39,
+       [WM8996_LDO_1] = 0x3,
+       [WM8996_LDO_2] = 0x13,
+       [WM8996_ACCESSORY_DETECT_MODE_1] = 0x4,
+       [WM8996_HEADPHONE_DETECT_1] = 0x20,
+       [WM8996_MIC_DETECT_1] = 0x7600,
+       [WM8996_MIC_DETECT_2] = 0xbf,
+       [WM8996_CHARGE_PUMP_1] = 0x1f25,
+       [WM8996_CHARGE_PUMP_2] = 0xab19,
+       [WM8996_DC_SERVO_5] = 0x2a2a,
+       [WM8996_CONTROL_INTERFACE_1] = 0x8004,
+       [WM8996_CLOCKING_1] = 0x10,
+       [WM8996_AIF_RATE] = 0x83,
+       [WM8996_FLL_CONTROL_4] = 0x5dc0,
+       [WM8996_FLL_CONTROL_5] = 0xc84,
+       [WM8996_FLL_EFS_2] = 0x2,
+       [WM8996_AIF1_TX_LRCLK_1] = 0x80,
+       [WM8996_AIF1_TX_LRCLK_2] = 0x8,
+       [WM8996_AIF1_RX_LRCLK_1] = 0x80,
+       [WM8996_AIF1TX_DATA_CONFIGURATION_1] = 0x1818,
+       [WM8996_AIF1RX_DATA_CONFIGURATION] = 0x1818,
+       [WM8996_AIF1TX_TEST] = 0x7,
+       [WM8996_AIF2_TX_LRCLK_1] = 0x80,
+       [WM8996_AIF2_TX_LRCLK_2] = 0x8,
+       [WM8996_AIF2_RX_LRCLK_1] = 0x80,
+       [WM8996_AIF2TX_DATA_CONFIGURATION_1] = 0x1818,
+       [WM8996_AIF2RX_DATA_CONFIGURATION] = 0x1818,
+       [WM8996_AIF2TX_TEST] = 0x1,
+       [WM8996_DSP1_TX_LEFT_VOLUME] = 0xc0,
+       [WM8996_DSP1_TX_RIGHT_VOLUME] = 0xc0,
+       [WM8996_DSP1_RX_LEFT_VOLUME] = 0xc0,
+       [WM8996_DSP1_RX_RIGHT_VOLUME] = 0xc0,
+       [WM8996_DSP1_TX_FILTERS] = 0x2000,
+       [WM8996_DSP1_RX_FILTERS_1] = 0x200,
+       [WM8996_DSP1_RX_FILTERS_2] = 0x10,
+       [WM8996_DSP1_DRC_1] = 0x98,
+       [WM8996_DSP1_DRC_2] = 0x845,
+       [WM8996_DSP1_RX_EQ_GAINS_1] = 0x6318,
+       [WM8996_DSP1_RX_EQ_GAINS_2] = 0x6300,
+       [WM8996_DSP1_RX_EQ_BAND_1_A] = 0xfca,
+       [WM8996_DSP1_RX_EQ_BAND_1_B] = 0x400,
+       [WM8996_DSP1_RX_EQ_BAND_1_PG] = 0xd8,
+       [WM8996_DSP1_RX_EQ_BAND_2_A] = 0x1eb5,
+       [WM8996_DSP1_RX_EQ_BAND_2_B] = 0xf145,
+       [WM8996_DSP1_RX_EQ_BAND_2_C] = 0xb75,
+       [WM8996_DSP1_RX_EQ_BAND_2_PG] = 0x1c5,
+       [WM8996_DSP1_RX_EQ_BAND_3_A] = 0x1c58,
+       [WM8996_DSP1_RX_EQ_BAND_3_B] = 0xf373,
+       [WM8996_DSP1_RX_EQ_BAND_3_C] = 0xa54,
+       [WM8996_DSP1_RX_EQ_BAND_3_PG] = 0x558,
+       [WM8996_DSP1_RX_EQ_BAND_4_A] = 0x168e,
+       [WM8996_DSP1_RX_EQ_BAND_4_B] = 0xf829,
+       [WM8996_DSP1_RX_EQ_BAND_4_C] = 0x7ad,
+       [WM8996_DSP1_RX_EQ_BAND_4_PG] = 0x1103,
+       [WM8996_DSP1_RX_EQ_BAND_5_A] = 0x564,
+       [WM8996_DSP1_RX_EQ_BAND_5_B] = 0x559,
+       [WM8996_DSP1_RX_EQ_BAND_5_PG] = 0x4000,
+       [WM8996_DSP2_TX_LEFT_VOLUME] = 0xc0,
+       [WM8996_DSP2_TX_RIGHT_VOLUME] = 0xc0,
+       [WM8996_DSP2_RX_LEFT_VOLUME] = 0xc0,
+       [WM8996_DSP2_RX_RIGHT_VOLUME] = 0xc0,
+       [WM8996_DSP2_TX_FILTERS] = 0x2000,
+       [WM8996_DSP2_RX_FILTERS_1] = 0x200,
+       [WM8996_DSP2_RX_FILTERS_2] = 0x10,
+       [WM8996_DSP2_DRC_1] = 0x98,
+       [WM8996_DSP2_DRC_2] = 0x845,
+       [WM8996_DSP2_RX_EQ_GAINS_1] = 0x6318,
+       [WM8996_DSP2_RX_EQ_GAINS_2] = 0x6300,
+       [WM8996_DSP2_RX_EQ_BAND_1_A] = 0xfca,
+       [WM8996_DSP2_RX_EQ_BAND_1_B] = 0x400,
+       [WM8996_DSP2_RX_EQ_BAND_1_PG] = 0xd8,
+       [WM8996_DSP2_RX_EQ_BAND_2_A] = 0x1eb5,
+       [WM8996_DSP2_RX_EQ_BAND_2_B] = 0xf145,
+       [WM8996_DSP2_RX_EQ_BAND_2_C] = 0xb75,
+       [WM8996_DSP2_RX_EQ_BAND_2_PG] = 0x1c5,
+       [WM8996_DSP2_RX_EQ_BAND_3_A] = 0x1c58,
+       [WM8996_DSP2_RX_EQ_BAND_3_B] = 0xf373,
+       [WM8996_DSP2_RX_EQ_BAND_3_C] = 0xa54,
+       [WM8996_DSP2_RX_EQ_BAND_3_PG] = 0x558,
+       [WM8996_DSP2_RX_EQ_BAND_4_A] = 0x168e,
+       [WM8996_DSP2_RX_EQ_BAND_4_B] = 0xf829,
+       [WM8996_DSP2_RX_EQ_BAND_4_C] = 0x7ad,
+       [WM8996_DSP2_RX_EQ_BAND_4_PG] = 0x1103,
+       [WM8996_DSP2_RX_EQ_BAND_5_A] = 0x564,
+       [WM8996_DSP2_RX_EQ_BAND_5_B] = 0x559,
+       [WM8996_DSP2_RX_EQ_BAND_5_PG] = 0x4000,
+       [WM8996_OVERSAMPLING] = 0xd,
+       [WM8996_SIDETONE] = 0x1040,
+       [WM8996_GPIO_1] = 0xa101,
+       [WM8996_GPIO_2] = 0xa101,
+       [WM8996_GPIO_3] = 0xa101,
+       [WM8996_GPIO_4] = 0xa101,
+       [WM8996_GPIO_5] = 0xa101,
+       [WM8996_PULL_CONTROL_2] = 0x140,
+       [WM8996_INTERRUPT_STATUS_1_MASK] = 0x1f,
+       [WM8996_INTERRUPT_STATUS_2_MASK] = 0x1ecf,
+       [WM8996_RIGHT_PDM_SPEAKER] = 0x1,
+       [WM8996_PDM_SPEAKER_MUTE_SEQUENCE] = 0x69,
+       [WM8996_PDM_SPEAKER_VOLUME] = 0x66,
+       [WM8996_WRITE_SEQUENCER_0] = 0x1,
+       [WM8996_WRITE_SEQUENCER_1] = 0x1,
+       [WM8996_WRITE_SEQUENCER_3] = 0x6,
+       [WM8996_WRITE_SEQUENCER_4] = 0x40,
+       [WM8996_WRITE_SEQUENCER_5] = 0x1,
+       [WM8996_WRITE_SEQUENCER_6] = 0xf,
+       [WM8996_WRITE_SEQUENCER_7] = 0x6,
+       [WM8996_WRITE_SEQUENCER_8] = 0x1,
+       [WM8996_WRITE_SEQUENCER_9] = 0x3,
+       [WM8996_WRITE_SEQUENCER_10] = 0x104,
+       [WM8996_WRITE_SEQUENCER_12] = 0x60,
+       [WM8996_WRITE_SEQUENCER_13] = 0x11,
+       [WM8996_WRITE_SEQUENCER_14] = 0x401,
+       [WM8996_WRITE_SEQUENCER_16] = 0x50,
+       [WM8996_WRITE_SEQUENCER_17] = 0x3,
+       [WM8996_WRITE_SEQUENCER_18] = 0x100,
+       [WM8996_WRITE_SEQUENCER_20] = 0x51,
+       [WM8996_WRITE_SEQUENCER_21] = 0x3,
+       [WM8996_WRITE_SEQUENCER_22] = 0x104,
+       [WM8996_WRITE_SEQUENCER_23] = 0xa,
+       [WM8996_WRITE_SEQUENCER_24] = 0x60,
+       [WM8996_WRITE_SEQUENCER_25] = 0x3b,
+       [WM8996_WRITE_SEQUENCER_26] = 0x502,
+       [WM8996_WRITE_SEQUENCER_27] = 0x100,
+       [WM8996_WRITE_SEQUENCER_28] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_32] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_36] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_40] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_44] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_48] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_52] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_56] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_60] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_64] = 0x1,
+       [WM8996_WRITE_SEQUENCER_65] = 0x1,
+       [WM8996_WRITE_SEQUENCER_67] = 0x6,
+       [WM8996_WRITE_SEQUENCER_68] = 0x40,
+       [WM8996_WRITE_SEQUENCER_69] = 0x1,
+       [WM8996_WRITE_SEQUENCER_70] = 0xf,
+       [WM8996_WRITE_SEQUENCER_71] = 0x6,
+       [WM8996_WRITE_SEQUENCER_72] = 0x1,
+       [WM8996_WRITE_SEQUENCER_73] = 0x3,
+       [WM8996_WRITE_SEQUENCER_74] = 0x104,
+       [WM8996_WRITE_SEQUENCER_76] = 0x60,
+       [WM8996_WRITE_SEQUENCER_77] = 0x11,
+       [WM8996_WRITE_SEQUENCER_78] = 0x401,
+       [WM8996_WRITE_SEQUENCER_80] = 0x50,
+       [WM8996_WRITE_SEQUENCER_81] = 0x3,
+       [WM8996_WRITE_SEQUENCER_82] = 0x100,
+       [WM8996_WRITE_SEQUENCER_84] = 0x60,
+       [WM8996_WRITE_SEQUENCER_85] = 0x3b,
+       [WM8996_WRITE_SEQUENCER_86] = 0x502,
+       [WM8996_WRITE_SEQUENCER_87] = 0x100,
+       [WM8996_WRITE_SEQUENCER_88] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_92] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_96] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_100] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_104] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_108] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_112] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_116] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_120] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_124] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_128] = 0x1,
+       [WM8996_WRITE_SEQUENCER_129] = 0x1,
+       [WM8996_WRITE_SEQUENCER_131] = 0x6,
+       [WM8996_WRITE_SEQUENCER_132] = 0x40,
+       [WM8996_WRITE_SEQUENCER_133] = 0x1,
+       [WM8996_WRITE_SEQUENCER_134] = 0xf,
+       [WM8996_WRITE_SEQUENCER_135] = 0x6,
+       [WM8996_WRITE_SEQUENCER_136] = 0x1,
+       [WM8996_WRITE_SEQUENCER_137] = 0x3,
+       [WM8996_WRITE_SEQUENCER_138] = 0x106,
+       [WM8996_WRITE_SEQUENCER_140] = 0x61,
+       [WM8996_WRITE_SEQUENCER_141] = 0x11,
+       [WM8996_WRITE_SEQUENCER_142] = 0x401,
+       [WM8996_WRITE_SEQUENCER_144] = 0x50,
+       [WM8996_WRITE_SEQUENCER_145] = 0x3,
+       [WM8996_WRITE_SEQUENCER_146] = 0x102,
+       [WM8996_WRITE_SEQUENCER_148] = 0x51,
+       [WM8996_WRITE_SEQUENCER_149] = 0x3,
+       [WM8996_WRITE_SEQUENCER_150] = 0x106,
+       [WM8996_WRITE_SEQUENCER_151] = 0xa,
+       [WM8996_WRITE_SEQUENCER_152] = 0x61,
+       [WM8996_WRITE_SEQUENCER_153] = 0x3b,
+       [WM8996_WRITE_SEQUENCER_154] = 0x502,
+       [WM8996_WRITE_SEQUENCER_155] = 0x100,
+       [WM8996_WRITE_SEQUENCER_156] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_160] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_164] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_168] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_172] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_176] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_180] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_184] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_188] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_192] = 0x1,
+       [WM8996_WRITE_SEQUENCER_193] = 0x1,
+       [WM8996_WRITE_SEQUENCER_195] = 0x6,
+       [WM8996_WRITE_SEQUENCER_196] = 0x40,
+       [WM8996_WRITE_SEQUENCER_197] = 0x1,
+       [WM8996_WRITE_SEQUENCER_198] = 0xf,
+       [WM8996_WRITE_SEQUENCER_199] = 0x6,
+       [WM8996_WRITE_SEQUENCER_200] = 0x1,
+       [WM8996_WRITE_SEQUENCER_201] = 0x3,
+       [WM8996_WRITE_SEQUENCER_202] = 0x106,
+       [WM8996_WRITE_SEQUENCER_204] = 0x61,
+       [WM8996_WRITE_SEQUENCER_205] = 0x11,
+       [WM8996_WRITE_SEQUENCER_206] = 0x401,
+       [WM8996_WRITE_SEQUENCER_208] = 0x50,
+       [WM8996_WRITE_SEQUENCER_209] = 0x3,
+       [WM8996_WRITE_SEQUENCER_210] = 0x102,
+       [WM8996_WRITE_SEQUENCER_212] = 0x61,
+       [WM8996_WRITE_SEQUENCER_213] = 0x3b,
+       [WM8996_WRITE_SEQUENCER_214] = 0x502,
+       [WM8996_WRITE_SEQUENCER_215] = 0x100,
+       [WM8996_WRITE_SEQUENCER_216] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_220] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_224] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_228] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_232] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_236] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_240] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_244] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_248] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_252] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_256] = 0x60,
+       [WM8996_WRITE_SEQUENCER_258] = 0x601,
+       [WM8996_WRITE_SEQUENCER_260] = 0x50,
+       [WM8996_WRITE_SEQUENCER_262] = 0x100,
+       [WM8996_WRITE_SEQUENCER_264] = 0x1,
+       [WM8996_WRITE_SEQUENCER_266] = 0x104,
+       [WM8996_WRITE_SEQUENCER_267] = 0x100,
+       [WM8996_WRITE_SEQUENCER_268] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_272] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_276] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_280] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_284] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_288] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_292] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_296] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_300] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_304] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_308] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_312] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_316] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_320] = 0x61,
+       [WM8996_WRITE_SEQUENCER_322] = 0x601,
+       [WM8996_WRITE_SEQUENCER_324] = 0x50,
+       [WM8996_WRITE_SEQUENCER_326] = 0x102,
+       [WM8996_WRITE_SEQUENCER_328] = 0x1,
+       [WM8996_WRITE_SEQUENCER_330] = 0x106,
+       [WM8996_WRITE_SEQUENCER_331] = 0x100,
+       [WM8996_WRITE_SEQUENCER_332] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_336] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_340] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_344] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_348] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_352] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_356] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_360] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_364] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_368] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_372] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_376] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_380] = 0x2fff,
+       [WM8996_WRITE_SEQUENCER_384] = 0x60,
+       [WM8996_WRITE_SEQUENCER_386] = 0x601,
+       [WM8996_WRITE_SEQUENCER_388] = 0x61,
+       [WM8996_WRITE_SEQUENCER_390] = 0x601,
+       [WM8996_WRITE_SEQUENCER_392] = 0x50,
+       [WM8996_WRITE_SEQUENCER_394] = 0x300,
+       [WM8996_WRITE_SEQUENCER_396] = 0x1,
+       [WM8996_WRITE_SEQUENCER_398] = 0x304,
+       [WM8996_WRITE_SEQUENCER_400] = 0x40,
+       [WM8996_WRITE_SEQUENCER_402] = 0xf,
+       [WM8996_WRITE_SEQUENCER_404] = 0x1,
+       [WM8996_WRITE_SEQUENCER_407] = 0x100,
+};
+
+static const DECLARE_TLV_DB_SCALE(inpga_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 150, 0);
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
+static const DECLARE_TLV_DB_SCALE(out_digital_tlv, -1200, 150, 0);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -900, 75, 0);
+static const DECLARE_TLV_DB_SCALE(spk_tlv, -900, 150, 0);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+
+static const char *sidetone_hpf_text[] = {
+       "2.9kHz", "1.5kHz", "735Hz", "403Hz", "196Hz", "98Hz", "49Hz"
+};
+
+static const struct soc_enum sidetone_hpf =
+       SOC_ENUM_SINGLE(WM8996_SIDETONE, 7, 6, sidetone_hpf_text);
+
+static const char *hpf_mode_text[] = {
+       "HiFi", "Custom", "Voice"
+};
+
+static const struct soc_enum dsp1tx_hpf_mode =
+       SOC_ENUM_SINGLE(WM8996_DSP1_TX_FILTERS, 3, 3, hpf_mode_text);
+
+static const struct soc_enum dsp2tx_hpf_mode =
+       SOC_ENUM_SINGLE(WM8996_DSP2_TX_FILTERS, 3, 3, hpf_mode_text);
+
+static const char *hpf_cutoff_text[] = {
+       "50Hz", "75Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"
+};
+
+static const struct soc_enum dsp1tx_hpf_cutoff =
+       SOC_ENUM_SINGLE(WM8996_DSP1_TX_FILTERS, 0, 7, hpf_cutoff_text);
+
+static const struct soc_enum dsp2tx_hpf_cutoff =
+       SOC_ENUM_SINGLE(WM8996_DSP2_TX_FILTERS, 0, 7, hpf_cutoff_text);
+
+static void wm8996_set_retune_mobile(struct snd_soc_codec *codec, int block)
+{
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       struct wm8996_pdata *pdata = &wm8996->pdata;
+       int base, best, best_val, save, i, cfg, iface;
+
+       if (!wm8996->num_retune_mobile_texts)
+               return;
+
+       switch (block) {
+       case 0:
+               base = WM8996_DSP1_RX_EQ_GAINS_1;
+               if (snd_soc_read(codec, WM8996_POWER_MANAGEMENT_8) &
+                   WM8996_DSP1RX_SRC)
+                       iface = 1;
+               else
+                       iface = 0;
+               break;
+       case 1:
+               base = WM8996_DSP1_RX_EQ_GAINS_2;
+               if (snd_soc_read(codec, WM8996_POWER_MANAGEMENT_8) &
+                   WM8996_DSP2RX_SRC)
+                       iface = 1;
+               else
+                       iface = 0;
+               break;
+       default:
+               return;
+       }
+
+       /* Find the version of the currently selected configuration
+        * with the nearest sample rate. */
+       cfg = wm8996->retune_mobile_cfg[block];
+       best = 0;
+       best_val = INT_MAX;
+       for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
+               if (strcmp(pdata->retune_mobile_cfgs[i].name,
+                          wm8996->retune_mobile_texts[cfg]) == 0 &&
+                   abs(pdata->retune_mobile_cfgs[i].rate
+                       - wm8996->rx_rate[iface]) < best_val) {
+                       best = i;
+                       best_val = abs(pdata->retune_mobile_cfgs[i].rate
+                                      - wm8996->rx_rate[iface]);
+               }
+       }
+
+       dev_dbg(codec->dev, "ReTune Mobile %d %s/%dHz for %dHz sample rate\n",
+               block,
+               pdata->retune_mobile_cfgs[best].name,
+               pdata->retune_mobile_cfgs[best].rate,
+               wm8996->rx_rate[iface]);
+
+       /* The EQ will be disabled while reconfiguring it, remember the
+        * current configuration. 
+        */
+       save = snd_soc_read(codec, base);
+       save &= WM8996_DSP1RX_EQ_ENA;
+
+       for (i = 0; i < ARRAY_SIZE(pdata->retune_mobile_cfgs[best].regs); i++)
+               snd_soc_update_bits(codec, base + i, 0xffff,
+                                   pdata->retune_mobile_cfgs[best].regs[i]);
+
+       snd_soc_update_bits(codec, base, WM8996_DSP1RX_EQ_ENA, save);
+}
+
+/* Icky as hell but saves code duplication */
+static int wm8996_get_retune_mobile_block(const char *name)
+{
+       if (strcmp(name, "DSP1 EQ Mode") == 0)
+               return 0;
+       if (strcmp(name, "DSP2 EQ Mode") == 0)
+               return 1;
+       return -EINVAL;
+}
+
+static int wm8996_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
+                                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       struct wm8996_pdata *pdata = &wm8996->pdata;
+       int block = wm8996_get_retune_mobile_block(kcontrol->id.name);
+       int value = ucontrol->value.integer.value[0];
+
+       if (block < 0)
+               return block;
+
+       if (value >= pdata->num_retune_mobile_cfgs)
+               return -EINVAL;
+
+       wm8996->retune_mobile_cfg[block] = value;
+
+       wm8996_set_retune_mobile(codec, block);
+
+       return 0;
+}
+
+static int wm8996_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
+                                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       int block = wm8996_get_retune_mobile_block(kcontrol->id.name);
+
+       ucontrol->value.enumerated.item[0] = wm8996->retune_mobile_cfg[block];
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new wm8996_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Capture Volume", WM8996_LEFT_LINE_INPUT_VOLUME,
+                WM8996_RIGHT_LINE_INPUT_VOLUME, 0, 31, 0, inpga_tlv),
+SOC_DOUBLE_R("Capture ZC Switch", WM8996_LEFT_LINE_INPUT_VOLUME,
+            WM8996_RIGHT_LINE_INPUT_VOLUME, 5, 1, 0),
+
+SOC_DOUBLE_TLV("DAC1 Sidetone Volume", WM8996_DAC1_MIXER_VOLUMES,
+              0, 5, 24, 0, sidetone_tlv),
+SOC_DOUBLE_TLV("DAC2 Sidetone Volume", WM8996_DAC2_MIXER_VOLUMES,
+              0, 5, 24, 0, sidetone_tlv),
+SOC_SINGLE("Sidetone LPF Switch", WM8996_SIDETONE, 12, 1, 0),
+SOC_ENUM("Sidetone HPF Cut-off", sidetone_hpf),
+SOC_SINGLE("Sidetone HPF Switch", WM8996_SIDETONE, 6, 1, 0),
+
+SOC_DOUBLE_R_TLV("DSP1 Capture Volume", WM8996_DSP1_TX_LEFT_VOLUME,
+                WM8996_DSP1_TX_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("DSP2 Capture Volume", WM8996_DSP2_TX_LEFT_VOLUME,
+                WM8996_DSP2_TX_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
+
+SOC_SINGLE("DSP1 Capture Notch Filter Switch", WM8996_DSP1_TX_FILTERS,
+          13, 1, 0),
+SOC_DOUBLE("DSP1 Capture HPF Switch", WM8996_DSP1_TX_FILTERS, 12, 11, 1, 0),
+SOC_ENUM("DSP1 Capture HPF Mode", dsp1tx_hpf_mode),
+SOC_ENUM("DSP1 Capture HPF Cutoff", dsp1tx_hpf_cutoff),
+
+SOC_SINGLE("DSP2 Capture Notch Filter Switch", WM8996_DSP2_TX_FILTERS,
+          13, 1, 0),
+SOC_DOUBLE("DSP2 Capture HPF Switch", WM8996_DSP2_TX_FILTERS, 12, 11, 1, 0),
+SOC_ENUM("DSP2 Capture HPF Mode", dsp2tx_hpf_mode),
+SOC_ENUM("DSP2 Capture HPF Cutoff", dsp2tx_hpf_cutoff),
+
+SOC_DOUBLE_R_TLV("DSP1 Playback Volume", WM8996_DSP1_RX_LEFT_VOLUME,
+                WM8996_DSP1_RX_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
+SOC_SINGLE("DSP1 Playback Switch", WM8996_DSP1_RX_FILTERS_1, 9, 1, 1),
+
+SOC_DOUBLE_R_TLV("DSP2 Playback Volume", WM8996_DSP2_RX_LEFT_VOLUME,
+                WM8996_DSP2_RX_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
+SOC_SINGLE("DSP2 Playback Switch", WM8996_DSP2_RX_FILTERS_1, 9, 1, 1),
+
+SOC_DOUBLE_R_TLV("DAC1 Volume", WM8996_DAC1_LEFT_VOLUME,
+                WM8996_DAC1_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
+SOC_DOUBLE_R("DAC1 Switch", WM8996_DAC1_LEFT_VOLUME,
+            WM8996_DAC1_RIGHT_VOLUME, 9, 1, 1),
+
+SOC_DOUBLE_R_TLV("DAC2 Volume", WM8996_DAC2_LEFT_VOLUME,
+                WM8996_DAC2_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
+SOC_DOUBLE_R("DAC2 Switch", WM8996_DAC2_LEFT_VOLUME,
+            WM8996_DAC2_RIGHT_VOLUME, 9, 1, 1),
+
+SOC_SINGLE("Speaker High Performance Switch", WM8996_OVERSAMPLING, 3, 1, 0),
+SOC_SINGLE("DMIC High Performance Switch", WM8996_OVERSAMPLING, 2, 1, 0),
+SOC_SINGLE("ADC High Performance Switch", WM8996_OVERSAMPLING, 1, 1, 0),
+SOC_SINGLE("DAC High Performance Switch", WM8996_OVERSAMPLING, 0, 1, 0),
+
+SOC_SINGLE("DAC Soft Mute Switch", WM8996_DAC_SOFTMUTE, 1, 1, 0),
+SOC_SINGLE("DAC Slow Soft Mute Switch", WM8996_DAC_SOFTMUTE, 0, 1, 0),
+
+SOC_DOUBLE_TLV("Digital Output 1 Volume", WM8996_DAC1_HPOUT1_VOLUME, 0, 4,
+              8, 0, out_digital_tlv),
+SOC_DOUBLE_TLV("Digital Output 2 Volume", WM8996_DAC2_HPOUT2_VOLUME, 0, 4,
+              8, 0, out_digital_tlv),
+
+SOC_DOUBLE_R_TLV("Output 1 Volume", WM8996_OUTPUT1_LEFT_VOLUME,
+                WM8996_OUTPUT1_RIGHT_VOLUME, 0, 12, 0, out_tlv),
+SOC_DOUBLE_R("Output 1 ZC Switch",  WM8996_OUTPUT1_LEFT_VOLUME,
+            WM8996_OUTPUT1_RIGHT_VOLUME, 7, 1, 0),
+
+SOC_DOUBLE_R_TLV("Output 2 Volume", WM8996_OUTPUT2_LEFT_VOLUME,
+                WM8996_OUTPUT2_RIGHT_VOLUME, 0, 12, 0, out_tlv),
+SOC_DOUBLE_R("Output 2 ZC Switch",  WM8996_OUTPUT2_LEFT_VOLUME,
+            WM8996_OUTPUT2_RIGHT_VOLUME, 7, 1, 0),
+
+SOC_DOUBLE_TLV("Speaker Volume", WM8996_PDM_SPEAKER_VOLUME, 0, 4, 8, 0,
+              spk_tlv),
+SOC_DOUBLE_R("Speaker Switch", WM8996_LEFT_PDM_SPEAKER,
+            WM8996_RIGHT_PDM_SPEAKER, 3, 1, 1),
+SOC_DOUBLE_R("Speaker ZC Switch", WM8996_LEFT_PDM_SPEAKER,
+            WM8996_RIGHT_PDM_SPEAKER, 2, 1, 0),
+
+SOC_SINGLE("DSP1 EQ Switch", WM8996_DSP1_RX_EQ_GAINS_1, 0, 1, 0),
+SOC_SINGLE("DSP2 EQ Switch", WM8996_DSP2_RX_EQ_GAINS_1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8996_eq_controls[] = {
+SOC_SINGLE_TLV("DSP1 EQ B1 Volume", WM8996_DSP1_RX_EQ_GAINS_1, 11, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("DSP1 EQ B2 Volume", WM8996_DSP1_RX_EQ_GAINS_1, 6, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("DSP1 EQ B3 Volume", WM8996_DSP1_RX_EQ_GAINS_1, 1, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("DSP1 EQ B4 Volume", WM8996_DSP1_RX_EQ_GAINS_2, 11, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("DSP1 EQ B5 Volume", WM8996_DSP1_RX_EQ_GAINS_2, 6, 31, 0,
+              eq_tlv),
+
+SOC_SINGLE_TLV("DSP2 EQ B1 Volume", WM8996_DSP2_RX_EQ_GAINS_1, 11, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("DSP2 EQ B2 Volume", WM8996_DSP2_RX_EQ_GAINS_1, 6, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("DSP2 EQ B3 Volume", WM8996_DSP2_RX_EQ_GAINS_1, 1, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("DSP2 EQ B4 Volume", WM8996_DSP2_RX_EQ_GAINS_2, 11, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("DSP2 EQ B5 Volume", WM8996_DSP2_RX_EQ_GAINS_2, 6, 31, 0,
+              eq_tlv),
+};
+
+static int cp_event(struct snd_soc_dapm_widget *w,
+                   struct snd_kcontrol *kcontrol, int event)
+{
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               msleep(5);
+               break;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int rmv_short_event(struct snd_soc_dapm_widget *w,
+                          struct snd_kcontrol *kcontrol, int event)
+{
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(w->codec);
+
+       /* Record which outputs we enabled */
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMD:
+               wm8996->hpout_pending &= ~w->shift;
+               break;
+       case SND_SOC_DAPM_PRE_PMU:
+               wm8996->hpout_pending |= w->shift;
+               break;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void wait_for_dc_servo(struct snd_soc_codec *codec, u16 mask)
+{
+       struct i2c_client *i2c = to_i2c_client(codec->dev);
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       int i, ret;
+       unsigned long timeout = 200;
+
+       snd_soc_write(codec, WM8996_DC_SERVO_2, mask);
+
+       /* Use the interrupt if possible */
+       do {
+               if (i2c->irq) {
+                       timeout = wait_for_completion_timeout(&wm8996->dcs_done,
+                                                             msecs_to_jiffies(200));
+                       if (timeout == 0)
+                               dev_err(codec->dev, "DC servo timed out\n");
+
+               } else {
+                       msleep(1);
+                       if (--i) {
+                               timeout = 0;
+                               break;
+                       }
+               }
+
+               ret = snd_soc_read(codec, WM8996_DC_SERVO_2);
+               dev_dbg(codec->dev, "DC servo state: %x\n", ret);
+       } while (ret & mask);
+
+       if (timeout == 0)
+               dev_err(codec->dev, "DC servo timed out for %x\n", mask);
+       else
+               dev_dbg(codec->dev, "DC servo complete for %x\n", mask);
+}
+
+static void wm8996_seq_notifier(struct snd_soc_dapm_context *dapm,
+                               enum snd_soc_dapm_type event, int subseq)
+{
+       struct snd_soc_codec *codec = container_of(dapm,
+                                                  struct snd_soc_codec, dapm);
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       u16 val, mask;
+
+       /* Complete any pending DC servo starts */
+       if (wm8996->dcs_pending) {
+               dev_dbg(codec->dev, "Starting DC servo for %x\n",
+                       wm8996->dcs_pending);
+
+               /* Trigger a startup sequence */
+               wait_for_dc_servo(codec, wm8996->dcs_pending
+                                        << WM8996_DCS_TRIG_STARTUP_0_SHIFT);
+
+               wm8996->dcs_pending = 0;
+       }
+
+       if (wm8996->hpout_pending != wm8996->hpout_ena) {
+               dev_dbg(codec->dev, "Applying RMV_SHORTs %x->%x\n",
+                       wm8996->hpout_ena, wm8996->hpout_pending);
+
+               val = 0;
+               mask = 0;
+               if (wm8996->hpout_pending & HPOUT1L) {
+                       val |= WM8996_HPOUT1L_RMV_SHORT;
+                       mask |= WM8996_HPOUT1L_RMV_SHORT;
+               } else {
+                       mask |= WM8996_HPOUT1L_RMV_SHORT |
+                               WM8996_HPOUT1L_OUTP |
+                               WM8996_HPOUT1L_DLY;
+               }
+
+               if (wm8996->hpout_pending & HPOUT1R) {
+                       val |= WM8996_HPOUT1R_RMV_SHORT;
+                       mask |= WM8996_HPOUT1R_RMV_SHORT;
+               } else {
+                       mask |= WM8996_HPOUT1R_RMV_SHORT |
+                               WM8996_HPOUT1R_OUTP |
+                               WM8996_HPOUT1R_DLY;
+               }
+
+               snd_soc_update_bits(codec, WM8996_ANALOGUE_HP_1, mask, val);
+
+               val = 0;
+               mask = 0;
+               if (wm8996->hpout_pending & HPOUT2L) {
+                       val |= WM8996_HPOUT2L_RMV_SHORT;
+                       mask |= WM8996_HPOUT2L_RMV_SHORT;
+               } else {
+                       mask |= WM8996_HPOUT2L_RMV_SHORT |
+                               WM8996_HPOUT2L_OUTP |
+                               WM8996_HPOUT2L_DLY;
+               }
+
+               if (wm8996->hpout_pending & HPOUT2R) {
+                       val |= WM8996_HPOUT2R_RMV_SHORT;
+                       mask |= WM8996_HPOUT2R_RMV_SHORT;
+               } else {
+                       mask |= WM8996_HPOUT2R_RMV_SHORT |
+                               WM8996_HPOUT2R_OUTP |
+                               WM8996_HPOUT2R_DLY;
+               }
+
+               snd_soc_update_bits(codec, WM8996_ANALOGUE_HP_2, mask, val);
+
+               wm8996->hpout_ena = wm8996->hpout_pending;
+       }
+}
+
+static int dcs_start(struct snd_soc_dapm_widget *w,
+                    struct snd_kcontrol *kcontrol, int event)
+{
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(w->codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               wm8996->dcs_pending |= 1 << w->shift;
+               break;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const char *sidetone_text[] = {
+       "IN1", "IN2",
+};
+
+static const struct soc_enum left_sidetone_enum =
+       SOC_ENUM_SINGLE(WM8996_SIDETONE, 0, 2, sidetone_text);
+
+static const struct snd_kcontrol_new left_sidetone =
+       SOC_DAPM_ENUM("Left Sidetone", left_sidetone_enum);
+
+static const struct soc_enum right_sidetone_enum =
+       SOC_ENUM_SINGLE(WM8996_SIDETONE, 1, 2, sidetone_text);
+
+static const struct snd_kcontrol_new right_sidetone =
+       SOC_DAPM_ENUM("Right Sidetone", right_sidetone_enum);
+
+static const char *spk_text[] = {
+       "DAC1L", "DAC1R", "DAC2L", "DAC2R"
+};
+
+static const struct soc_enum spkl_enum =
+       SOC_ENUM_SINGLE(WM8996_LEFT_PDM_SPEAKER, 0, 4, spk_text);
+
+static const struct snd_kcontrol_new spkl_mux =
+       SOC_DAPM_ENUM("SPKL", spkl_enum);
+
+static const struct soc_enum spkr_enum =
+       SOC_ENUM_SINGLE(WM8996_RIGHT_PDM_SPEAKER, 0, 4, spk_text);
+
+static const struct snd_kcontrol_new spkr_mux =
+       SOC_DAPM_ENUM("SPKR", spkr_enum);
+
+static const char *dsp1rx_text[] = {
+       "AIF1", "AIF2"
+};
+
+static const struct soc_enum dsp1rx_enum =
+       SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_8, 0, 2, dsp1rx_text);
+
+static const struct snd_kcontrol_new dsp1rx =
+       SOC_DAPM_ENUM("DSP1RX", dsp1rx_enum);
+
+static const char *dsp2rx_text[] = {
+        "AIF2", "AIF1"
+};
+
+static const struct soc_enum dsp2rx_enum =
+       SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_8, 4, 2, dsp2rx_text);
+
+static const struct snd_kcontrol_new dsp2rx =
+       SOC_DAPM_ENUM("DSP2RX", dsp2rx_enum);
+
+static const char *aif2tx_text[] = {
+       "DSP2", "DSP1", "AIF1"
+};
+
+static const struct soc_enum aif2tx_enum =
+       SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_8, 6, 3, aif2tx_text);
+
+static const struct snd_kcontrol_new aif2tx =
+       SOC_DAPM_ENUM("AIF2TX", aif2tx_enum);
+
+static const char *inmux_text[] = {
+       "ADC", "DMIC1", "DMIC2"
+};
+
+static const struct soc_enum in1_enum =
+       SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_7, 0, 3, inmux_text);
+
+static const struct snd_kcontrol_new in1_mux =
+       SOC_DAPM_ENUM("IN1 Mux", in1_enum);
+
+static const struct soc_enum in2_enum =
+       SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_7, 4, 3, inmux_text);
+
+static const struct snd_kcontrol_new in2_mux =
+       SOC_DAPM_ENUM("IN2 Mux", in2_enum);
+
+static const struct snd_kcontrol_new dac2r_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8996_DAC2_RIGHT_MIXER_ROUTING,
+               5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8996_DAC2_RIGHT_MIXER_ROUTING,
+               4, 1, 0),
+SOC_DAPM_SINGLE("DSP2 Switch", WM8996_DAC2_RIGHT_MIXER_ROUTING, 1, 1, 0),
+SOC_DAPM_SINGLE("DSP1 Switch", WM8996_DAC2_RIGHT_MIXER_ROUTING, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dac2l_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8996_DAC2_LEFT_MIXER_ROUTING,
+               5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8996_DAC2_LEFT_MIXER_ROUTING,
+               4, 1, 0),
+SOC_DAPM_SINGLE("DSP2 Switch", WM8996_DAC2_LEFT_MIXER_ROUTING, 1, 1, 0),
+SOC_DAPM_SINGLE("DSP1 Switch", WM8996_DAC2_LEFT_MIXER_ROUTING, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dac1r_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8996_DAC1_RIGHT_MIXER_ROUTING,
+               5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8996_DAC1_RIGHT_MIXER_ROUTING,
+               4, 1, 0),
+SOC_DAPM_SINGLE("DSP2 Switch", WM8996_DAC1_RIGHT_MIXER_ROUTING, 1, 1, 0),
+SOC_DAPM_SINGLE("DSP1 Switch", WM8996_DAC1_RIGHT_MIXER_ROUTING, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dac1l_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8996_DAC1_LEFT_MIXER_ROUTING,
+               5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8996_DAC1_LEFT_MIXER_ROUTING,
+               4, 1, 0),
+SOC_DAPM_SINGLE("DSP2 Switch", WM8996_DAC1_LEFT_MIXER_ROUTING, 1, 1, 0),
+SOC_DAPM_SINGLE("DSP1 Switch", WM8996_DAC1_LEFT_MIXER_ROUTING, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dsp1txl[] = {
+SOC_DAPM_SINGLE("IN1 Switch", WM8996_DSP1_TX_LEFT_MIXER_ROUTING,
+               1, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8996_DSP1_TX_LEFT_MIXER_ROUTING,
+               0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dsp1txr[] = {
+SOC_DAPM_SINGLE("IN1 Switch", WM8996_DSP1_TX_RIGHT_MIXER_ROUTING,
+               1, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8996_DSP1_TX_RIGHT_MIXER_ROUTING,
+               0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dsp2txl[] = {
+SOC_DAPM_SINGLE("IN1 Switch", WM8996_DSP2_TX_LEFT_MIXER_ROUTING,
+               1, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8996_DSP2_TX_LEFT_MIXER_ROUTING,
+               0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dsp2txr[] = {
+SOC_DAPM_SINGLE("IN1 Switch", WM8996_DSP2_TX_RIGHT_MIXER_ROUTING,
+               1, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8996_DSP2_TX_RIGHT_MIXER_ROUTING,
+               0, 1, 0),
+};
+
+
+static const struct snd_soc_dapm_widget wm8996_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN1LN"),
+SND_SOC_DAPM_INPUT("IN1LP"),
+SND_SOC_DAPM_INPUT("IN1RN"),
+SND_SOC_DAPM_INPUT("IN1RP"),
+
+SND_SOC_DAPM_INPUT("IN2LN"),
+SND_SOC_DAPM_INPUT("IN2LP"),
+SND_SOC_DAPM_INPUT("IN2RN"),
+SND_SOC_DAPM_INPUT("IN2RP"),
+
+SND_SOC_DAPM_INPUT("DMIC1DAT"),
+SND_SOC_DAPM_INPUT("DMIC2DAT"),
+
+SND_SOC_DAPM_SUPPLY_S("SYSCLK", 1, WM8996_AIF_CLOCKING_1, 0, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY_S("SYSDSPCLK", 2, WM8996_CLOCKING_1, 1, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY_S("AIFCLK", 2, WM8996_CLOCKING_1, 2, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY_S("Charge Pump", 2, WM8996_CHARGE_PUMP_1, 15, 0, cp_event,
+                     SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_SUPPLY("LDO2", WM8996_POWER_MANAGEMENT_2, 1, 0, NULL, 0),
+SND_SOC_DAPM_MICBIAS("MICB2", WM8996_POWER_MANAGEMENT_1, 9, 0),
+SND_SOC_DAPM_MICBIAS("MICB1", WM8996_POWER_MANAGEMENT_1, 8, 0),
+
+SND_SOC_DAPM_PGA("IN1L PGA", WM8996_POWER_MANAGEMENT_2, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA("IN1R PGA", WM8996_POWER_MANAGEMENT_2, 4, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("IN1L Mux", SND_SOC_NOPM, 0, 0, &in1_mux),
+SND_SOC_DAPM_MUX("IN1R Mux", SND_SOC_NOPM, 0, 0, &in1_mux),
+SND_SOC_DAPM_MUX("IN2L Mux", SND_SOC_NOPM, 0, 0, &in2_mux),
+SND_SOC_DAPM_MUX("IN2R Mux", SND_SOC_NOPM, 0, 0, &in2_mux),
+
+SND_SOC_DAPM_PGA("IN1L", WM8996_POWER_MANAGEMENT_7, 2, 0, NULL, 0),
+SND_SOC_DAPM_PGA("IN1R", WM8996_POWER_MANAGEMENT_7, 3, 0, NULL, 0),
+SND_SOC_DAPM_PGA("IN2L", WM8996_POWER_MANAGEMENT_7, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA("IN2R", WM8996_POWER_MANAGEMENT_7, 7, 0, NULL, 0),
+
+SND_SOC_DAPM_SUPPLY("DMIC2", WM8996_POWER_MANAGEMENT_7, 9, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("DMIC1", WM8996_POWER_MANAGEMENT_7, 8, 0, NULL, 0),
+
+SND_SOC_DAPM_ADC("DMIC2L", NULL, WM8996_POWER_MANAGEMENT_3, 5, 0),
+SND_SOC_DAPM_ADC("DMIC2R", NULL, WM8996_POWER_MANAGEMENT_3, 4, 0),
+SND_SOC_DAPM_ADC("DMIC1L", NULL, WM8996_POWER_MANAGEMENT_3, 3, 0),
+SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8996_POWER_MANAGEMENT_3, 2, 0),
+
+SND_SOC_DAPM_ADC("ADCL", NULL, WM8996_POWER_MANAGEMENT_3, 1, 0),
+SND_SOC_DAPM_ADC("ADCR", NULL, WM8996_POWER_MANAGEMENT_3, 0, 0),
+
+SND_SOC_DAPM_MUX("Left Sidetone", SND_SOC_NOPM, 0, 0, &left_sidetone),
+SND_SOC_DAPM_MUX("Right Sidetone", SND_SOC_NOPM, 0, 0, &right_sidetone),
+
+SND_SOC_DAPM_AIF_IN("DSP2RXL", NULL, 0, WM8996_POWER_MANAGEMENT_3, 11, 0),
+SND_SOC_DAPM_AIF_IN("DSP2RXR", NULL, 1, WM8996_POWER_MANAGEMENT_3, 10, 0),
+SND_SOC_DAPM_AIF_IN("DSP1RXL", NULL, 0, WM8996_POWER_MANAGEMENT_3, 9, 0),
+SND_SOC_DAPM_AIF_IN("DSP1RXR", NULL, 1, WM8996_POWER_MANAGEMENT_3, 8, 0),
+
+SND_SOC_DAPM_MIXER("DSP2TXL", WM8996_POWER_MANAGEMENT_5, 11, 0,
+                  dsp2txl, ARRAY_SIZE(dsp2txl)),
+SND_SOC_DAPM_MIXER("DSP2TXR", WM8996_POWER_MANAGEMENT_5, 10, 0,
+                  dsp2txr, ARRAY_SIZE(dsp2txr)),
+SND_SOC_DAPM_MIXER("DSP1TXL", WM8996_POWER_MANAGEMENT_5, 9, 0,
+                  dsp1txl, ARRAY_SIZE(dsp1txl)),
+SND_SOC_DAPM_MIXER("DSP1TXR", WM8996_POWER_MANAGEMENT_5, 8, 0,
+                  dsp1txr, ARRAY_SIZE(dsp1txr)),
+
+SND_SOC_DAPM_MIXER("DAC2L Mixer", SND_SOC_NOPM, 0, 0,
+                  dac2l_mix, ARRAY_SIZE(dac2l_mix)),
+SND_SOC_DAPM_MIXER("DAC2R Mixer", SND_SOC_NOPM, 0, 0,
+                  dac2r_mix, ARRAY_SIZE(dac2r_mix)),
+SND_SOC_DAPM_MIXER("DAC1L Mixer", SND_SOC_NOPM, 0, 0,
+                  dac1l_mix, ARRAY_SIZE(dac1l_mix)),
+SND_SOC_DAPM_MIXER("DAC1R Mixer", SND_SOC_NOPM, 0, 0,
+                  dac1r_mix, ARRAY_SIZE(dac1r_mix)),
+
+SND_SOC_DAPM_DAC("DAC2L", NULL, WM8996_POWER_MANAGEMENT_5, 3, 0),
+SND_SOC_DAPM_DAC("DAC2R", NULL, WM8996_POWER_MANAGEMENT_5, 2, 0),
+SND_SOC_DAPM_DAC("DAC1L", NULL, WM8996_POWER_MANAGEMENT_5, 1, 0),
+SND_SOC_DAPM_DAC("DAC1R", NULL, WM8996_POWER_MANAGEMENT_5, 0, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF2RX1", "AIF2 Playback", 1,
+                   WM8996_POWER_MANAGEMENT_4, 9, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX0", "AIF2 Playback", 2,
+                   WM8996_POWER_MANAGEMENT_4, 8, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF2TX1", "AIF2 Capture", 1,
+                   WM8996_POWER_MANAGEMENT_6, 9, 0),
+SND_SOC_DAPM_AIF_IN("AIF2TX0", "AIF2 Capture", 2,
+                   WM8996_POWER_MANAGEMENT_6, 8, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF1RX5", "AIF1 Playback", 5,
+                   WM8996_POWER_MANAGEMENT_4, 5, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX4", "AIF1 Playback", 4,
+                   WM8996_POWER_MANAGEMENT_4, 4, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX3", "AIF1 Playback", 3,
+                   WM8996_POWER_MANAGEMENT_4, 3, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX2", "AIF1 Playback", 2,
+                   WM8996_POWER_MANAGEMENT_4, 2, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX1", "AIF1 Playback", 1,
+                   WM8996_POWER_MANAGEMENT_4, 1, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX0", "AIF1 Playback", 0,
+                   WM8996_POWER_MANAGEMENT_4, 0, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF1TX5", "AIF1 Capture", 5,
+                    WM8996_POWER_MANAGEMENT_6, 5, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX4", "AIF1 Capture", 4,
+                    WM8996_POWER_MANAGEMENT_6, 4, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX3", "AIF1 Capture", 3,
+                    WM8996_POWER_MANAGEMENT_6, 3, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX2", "AIF1 Capture", 2,
+                    WM8996_POWER_MANAGEMENT_6, 2, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX1", "AIF1 Capture", 1,
+                    WM8996_POWER_MANAGEMENT_6, 1, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX0", "AIF1 Capture", 0,
+                    WM8996_POWER_MANAGEMENT_6, 0, 0),
+
+/* We route as stereo pairs so define some dummy widgets to squash
+ * things down for now.  RXA = 0,1, RXB = 2,3 and so on */
+SND_SOC_DAPM_PGA("AIF1RXA", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("AIF1RXB", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("AIF1RXC", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("AIF2RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("DSP2TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("DSP1RX", SND_SOC_NOPM, 0, 0, &dsp1rx),
+SND_SOC_DAPM_MUX("DSP2RX", SND_SOC_NOPM, 0, 0, &dsp2rx),
+SND_SOC_DAPM_MUX("AIF2TX", SND_SOC_NOPM, 0, 0, &aif2tx),
+
+SND_SOC_DAPM_MUX("SPKL", SND_SOC_NOPM, 0, 0, &spkl_mux),
+SND_SOC_DAPM_MUX("SPKR", SND_SOC_NOPM, 0, 0, &spkr_mux),
+SND_SOC_DAPM_PGA("SPKL PGA", WM8996_LEFT_PDM_SPEAKER, 4, 0, NULL, 0),
+SND_SOC_DAPM_PGA("SPKR PGA", WM8996_RIGHT_PDM_SPEAKER, 4, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_S("HPOUT2L PGA", 0, WM8996_POWER_MANAGEMENT_1, 7, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2L_DLY", 1, WM8996_ANALOGUE_HP_2, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2L_DCS", 2, WM8996_DC_SERVO_1, 2, 0, dcs_start,
+                  SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_S("HPOUT2L_OUTP", 3, WM8996_ANALOGUE_HP_2, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2L_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT2L, 0,
+                  rmv_short_event,
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_PGA_S("HPOUT2R PGA", 0, WM8996_POWER_MANAGEMENT_1, 6, 0,NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2R_DLY", 1, WM8996_ANALOGUE_HP_2, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2R_DCS", 2, WM8996_DC_SERVO_1, 3, 0, dcs_start,
+                  SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_S("HPOUT2R_OUTP", 3, WM8996_ANALOGUE_HP_2, 2, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2R_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT2R, 0,
+                  rmv_short_event,
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_PGA_S("HPOUT1L PGA", 0, WM8996_POWER_MANAGEMENT_1, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1L_DLY", 1, WM8996_ANALOGUE_HP_1, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1L_DCS", 2, WM8996_DC_SERVO_1, 0, 0, dcs_start,
+                  SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_S("HPOUT1L_OUTP", 3, WM8996_ANALOGUE_HP_1, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1L_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT1L, 0,
+                  rmv_short_event,
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_PGA_S("HPOUT1R PGA", 0, WM8996_POWER_MANAGEMENT_1, 4, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1R_DLY", 1, WM8996_ANALOGUE_HP_1, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1R_DCS", 2, WM8996_DC_SERVO_1, 1, 0, dcs_start,
+                  SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_S("HPOUT1R_OUTP", 3, WM8996_ANALOGUE_HP_1, 2, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1R_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT1R, 0,
+                  rmv_short_event,
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_OUTPUT("HPOUT1L"),
+SND_SOC_DAPM_OUTPUT("HPOUT1R"),
+SND_SOC_DAPM_OUTPUT("HPOUT2L"),
+SND_SOC_DAPM_OUTPUT("HPOUT2R"),
+SND_SOC_DAPM_OUTPUT("SPKDAT"),
+};
+
+static const struct snd_soc_dapm_route wm8996_dapm_routes[] = {
+       { "AIFCLK", NULL, "SYSCLK" },
+       { "SYSDSPCLK", NULL, "SYSCLK" },
+       { "Charge Pump", NULL, "SYSCLK" },
+
+       { "MICB1", NULL, "LDO2" },
+       { "MICB2", NULL, "LDO2" },
+
+       { "IN1L PGA", NULL, "IN2LN" },
+       { "IN1L PGA", NULL, "IN2LP" },
+       { "IN1L PGA", NULL, "IN1LN" },
+       { "IN1L PGA", NULL, "IN1LP" },
+
+       { "IN1R PGA", NULL, "IN2RN" },
+       { "IN1R PGA", NULL, "IN2RP" },
+       { "IN1R PGA", NULL, "IN1RN" },
+       { "IN1R PGA", NULL, "IN1RP" },
+
+       { "ADCL", NULL, "IN1L PGA" },
+
+       { "ADCR", NULL, "IN1R PGA" },
+
+       { "DMIC1L", NULL, "DMIC1DAT" },
+       { "DMIC1R", NULL, "DMIC1DAT" },
+       { "DMIC2L", NULL, "DMIC2DAT" },
+       { "DMIC2R", NULL, "DMIC2DAT" },
+
+       { "DMIC2L", NULL, "DMIC2" },
+       { "DMIC2R", NULL, "DMIC2" },
+       { "DMIC1L", NULL, "DMIC1" },
+       { "DMIC1R", NULL, "DMIC1" },
+
+       { "IN1L Mux", "ADC", "ADCL" },
+       { "IN1L Mux", "DMIC1", "DMIC1L" },
+       { "IN1L Mux", "DMIC2", "DMIC2L" },
+
+       { "IN1R Mux", "ADC", "ADCR" },
+       { "IN1R Mux", "DMIC1", "DMIC1R" },
+       { "IN1R Mux", "DMIC2", "DMIC2R" },
+
+       { "IN2L Mux", "ADC", "ADCL" },
+       { "IN2L Mux", "DMIC1", "DMIC1L" },
+       { "IN2L Mux", "DMIC2", "DMIC2L" },
+
+       { "IN2R Mux", "ADC", "ADCR" },
+       { "IN2R Mux", "DMIC1", "DMIC1R" },
+       { "IN2R Mux", "DMIC2", "DMIC2R" },
+
+       { "Left Sidetone", "IN1", "IN1L Mux" },
+       { "Left Sidetone", "IN2", "IN2L Mux" },
+
+       { "Right Sidetone", "IN1", "IN1R Mux" },
+       { "Right Sidetone", "IN2", "IN2R Mux" },
+
+       { "DSP1TXL", "IN1 Switch", "IN1L Mux" },
+       { "DSP1TXR", "IN1 Switch", "IN1R Mux" },
+
+       { "DSP2TXL", "IN1 Switch", "IN2L Mux" },
+       { "DSP2TXR", "IN1 Switch", "IN2R Mux" },
+
+       { "AIF1TX0", NULL, "DSP1TXL" },
+       { "AIF1TX1", NULL, "DSP1TXR" },
+       { "AIF1TX2", NULL, "DSP2TXL" },
+       { "AIF1TX3", NULL, "DSP2TXR" },
+       { "AIF1TX4", NULL, "AIF2RX0" },
+       { "AIF1TX5", NULL, "AIF2RX1" },
+
+       { "AIF1RX0", NULL, "AIFCLK" },
+       { "AIF1RX1", NULL, "AIFCLK" },
+       { "AIF1RX2", NULL, "AIFCLK" },
+       { "AIF1RX3", NULL, "AIFCLK" },
+       { "AIF1RX4", NULL, "AIFCLK" },
+       { "AIF1RX5", NULL, "AIFCLK" },
+
+       { "AIF2RX0", NULL, "AIFCLK" },
+       { "AIF2RX1", NULL, "AIFCLK" },
+
+       { "DSP1RXL", NULL, "SYSDSPCLK" },
+       { "DSP1RXR", NULL, "SYSDSPCLK" },
+       { "DSP2RXL", NULL, "SYSDSPCLK" },
+       { "DSP2RXR", NULL, "SYSDSPCLK" },
+       { "DSP1TXL", NULL, "SYSDSPCLK" },
+       { "DSP1TXR", NULL, "SYSDSPCLK" },
+       { "DSP2TXL", NULL, "SYSDSPCLK" },
+       { "DSP2TXR", NULL, "SYSDSPCLK" },
+
+       { "AIF1RXA", NULL, "AIF1RX0" },
+       { "AIF1RXA", NULL, "AIF1RX1" },
+       { "AIF1RXB", NULL, "AIF1RX2" },
+       { "AIF1RXB", NULL, "AIF1RX3" },
+       { "AIF1RXC", NULL, "AIF1RX4" },
+       { "AIF1RXC", NULL, "AIF1RX5" },
+
+       { "AIF2RX", NULL, "AIF2RX0" },
+       { "AIF2RX", NULL, "AIF2RX1" },
+
+       { "AIF2TX", "DSP2", "DSP2TX" },
+       { "AIF2TX", "DSP1", "DSP1RX" },
+       { "AIF2TX", "AIF1", "AIF1RXC" },
+
+       { "DSP1RXL", NULL, "DSP1RX" },
+       { "DSP1RXR", NULL, "DSP1RX" },
+       { "DSP2RXL", NULL, "DSP2RX" },
+       { "DSP2RXR", NULL, "DSP2RX" },
+
+       { "DSP2TX", NULL, "DSP2TXL" },
+       { "DSP2TX", NULL, "DSP2TXR" },
+
+       { "DSP1RX", "AIF1", "AIF1RXA" },
+       { "DSP1RX", "AIF2", "AIF2RX" },
+
+       { "DSP2RX", "AIF1", "AIF1RXB" },
+       { "DSP2RX", "AIF2", "AIF2RX" },
+
+       { "DAC2L Mixer", "DSP2 Switch", "DSP2RXL" },
+       { "DAC2L Mixer", "DSP1 Switch", "DSP1RXL" },
+       { "DAC2L Mixer", "Right Sidetone Switch", "Right Sidetone" },
+       { "DAC2L Mixer", "Left Sidetone Switch", "Left Sidetone" },
+
+       { "DAC2R Mixer", "DSP2 Switch", "DSP2RXR" },
+       { "DAC2R Mixer", "DSP1 Switch", "DSP1RXR" },
+       { "DAC2R Mixer", "Right Sidetone Switch", "Right Sidetone" },
+       { "DAC2R Mixer", "Left Sidetone Switch", "Left Sidetone" },
+
+       { "DAC1L Mixer", "DSP2 Switch", "DSP2RXL" },
+       { "DAC1L Mixer", "DSP1 Switch", "DSP1RXL" },
+       { "DAC1L Mixer", "Right Sidetone Switch", "Right Sidetone" },
+       { "DAC1L Mixer", "Left Sidetone Switch", "Left Sidetone" },
+
+       { "DAC1R Mixer", "DSP2 Switch", "DSP2RXR" },
+       { "DAC1R Mixer", "DSP1 Switch", "DSP1RXR" },
+       { "DAC1R Mixer", "Right Sidetone Switch", "Right Sidetone" },
+       { "DAC1R Mixer", "Left Sidetone Switch", "Left Sidetone" },
+
+       { "DAC1L", NULL, "DAC1L Mixer" },
+       { "DAC1R", NULL, "DAC1R Mixer" },
+       { "DAC2L", NULL, "DAC2L Mixer" },
+       { "DAC2R", NULL, "DAC2R Mixer" },
+
+       { "HPOUT2L PGA", NULL, "Charge Pump" },
+       { "HPOUT2L PGA", NULL, "DAC2L" },
+       { "HPOUT2L_DLY", NULL, "HPOUT2L PGA" },
+       { "HPOUT2L_DCS", NULL, "HPOUT2L_DLY" },
+       { "HPOUT2L_OUTP", NULL, "HPOUT2L_DCS" },
+       { "HPOUT2L_RMV_SHORT", NULL, "HPOUT2L_OUTP" },
+
+       { "HPOUT2R PGA", NULL, "Charge Pump" },
+       { "HPOUT2R PGA", NULL, "DAC2R" },
+       { "HPOUT2R_DLY", NULL, "HPOUT2R PGA" },
+       { "HPOUT2R_DCS", NULL, "HPOUT2R_DLY" },
+       { "HPOUT2R_OUTP", NULL, "HPOUT2R_DCS" },
+       { "HPOUT2R_RMV_SHORT", NULL, "HPOUT2R_OUTP" },
+
+       { "HPOUT1L PGA", NULL, "Charge Pump" },
+       { "HPOUT1L PGA", NULL, "DAC1L" },
+       { "HPOUT1L_DLY", NULL, "HPOUT1L PGA" },
+       { "HPOUT1L_DCS", NULL, "HPOUT1L_DLY" },
+       { "HPOUT1L_OUTP", NULL, "HPOUT1L_DCS" },
+       { "HPOUT1L_RMV_SHORT", NULL, "HPOUT1L_OUTP" },
+
+       { "HPOUT1R PGA", NULL, "Charge Pump" },
+       { "HPOUT1R PGA", NULL, "DAC1R" },
+       { "HPOUT1R_DLY", NULL, "HPOUT1R PGA" },
+       { "HPOUT1R_DCS", NULL, "HPOUT1R_DLY" },
+       { "HPOUT1R_OUTP", NULL, "HPOUT1R_DCS" },
+       { "HPOUT1R_RMV_SHORT", NULL, "HPOUT1R_OUTP" },
+
+       { "HPOUT2L", NULL, "HPOUT2L_RMV_SHORT" },
+       { "HPOUT2R", NULL, "HPOUT2R_RMV_SHORT" },
+       { "HPOUT1L", NULL, "HPOUT1L_RMV_SHORT" },
+       { "HPOUT1R", NULL, "HPOUT1R_RMV_SHORT" },
+
+       { "SPKL", "DAC1L", "DAC1L" },
+       { "SPKL", "DAC1R", "DAC1R" },
+       { "SPKL", "DAC2L", "DAC2L" },
+       { "SPKL", "DAC2R", "DAC2R" },
+
+       { "SPKR", "DAC1L", "DAC1L" },
+       { "SPKR", "DAC1R", "DAC1R" },
+       { "SPKR", "DAC2L", "DAC2L" },
+       { "SPKR", "DAC2R", "DAC2R" },
+
+       { "SPKL PGA", NULL, "SPKL" },
+       { "SPKR PGA", NULL, "SPKR" },
+
+       { "SPKDAT", NULL, "SPKL PGA" },
+       { "SPKDAT", NULL, "SPKR PGA" },
+};
+
+static int wm8996_readable_register(struct snd_soc_codec *codec,
+                                   unsigned int reg)
+{
+       /* Due to the sparseness of the register map the compiler
+        * output from an explicit switch statement ends up being much
+        * more efficient than a table.
+        */
+       switch (reg) {
+       case WM8996_SOFTWARE_RESET:
+       case WM8996_POWER_MANAGEMENT_1:
+       case WM8996_POWER_MANAGEMENT_2:
+       case WM8996_POWER_MANAGEMENT_3:
+       case WM8996_POWER_MANAGEMENT_4:
+       case WM8996_POWER_MANAGEMENT_5:
+       case WM8996_POWER_MANAGEMENT_6:
+       case WM8996_POWER_MANAGEMENT_7:
+       case WM8996_POWER_MANAGEMENT_8:
+       case WM8996_LEFT_LINE_INPUT_VOLUME:
+       case WM8996_RIGHT_LINE_INPUT_VOLUME:
+       case WM8996_LINE_INPUT_CONTROL:
+       case WM8996_DAC1_HPOUT1_VOLUME:
+       case WM8996_DAC2_HPOUT2_VOLUME:
+       case WM8996_DAC1_LEFT_VOLUME:
+       case WM8996_DAC1_RIGHT_VOLUME:
+       case WM8996_DAC2_LEFT_VOLUME:
+       case WM8996_DAC2_RIGHT_VOLUME:
+       case WM8996_OUTPUT1_LEFT_VOLUME:
+       case WM8996_OUTPUT1_RIGHT_VOLUME:
+       case WM8996_OUTPUT2_LEFT_VOLUME:
+       case WM8996_OUTPUT2_RIGHT_VOLUME:
+       case WM8996_MICBIAS_1:
+       case WM8996_MICBIAS_2:
+       case WM8996_LDO_1:
+       case WM8996_LDO_2:
+       case WM8996_ACCESSORY_DETECT_MODE_1:
+       case WM8996_ACCESSORY_DETECT_MODE_2:
+       case WM8996_HEADPHONE_DETECT_1:
+       case WM8996_HEADPHONE_DETECT_2:
+       case WM8996_MIC_DETECT_1:
+       case WM8996_MIC_DETECT_2:
+       case WM8996_MIC_DETECT_3:
+       case WM8996_CHARGE_PUMP_1:
+       case WM8996_CHARGE_PUMP_2:
+       case WM8996_DC_SERVO_1:
+       case WM8996_DC_SERVO_2:
+       case WM8996_DC_SERVO_3:
+       case WM8996_DC_SERVO_5:
+       case WM8996_DC_SERVO_6:
+       case WM8996_DC_SERVO_7:
+       case WM8996_DC_SERVO_READBACK_0:
+       case WM8996_ANALOGUE_HP_1:
+       case WM8996_ANALOGUE_HP_2:
+       case WM8996_CHIP_REVISION:
+       case WM8996_CONTROL_INTERFACE_1:
+       case WM8996_WRITE_SEQUENCER_CTRL_1:
+       case WM8996_WRITE_SEQUENCER_CTRL_2:
+       case WM8996_AIF_CLOCKING_1:
+       case WM8996_AIF_CLOCKING_2:
+       case WM8996_CLOCKING_1:
+       case WM8996_CLOCKING_2:
+       case WM8996_AIF_RATE:
+       case WM8996_FLL_CONTROL_1:
+       case WM8996_FLL_CONTROL_2:
+       case WM8996_FLL_CONTROL_3:
+       case WM8996_FLL_CONTROL_4:
+       case WM8996_FLL_CONTROL_5:
+       case WM8996_FLL_CONTROL_6:
+       case WM8996_FLL_EFS_1:
+       case WM8996_FLL_EFS_2:
+       case WM8996_AIF1_CONTROL:
+       case WM8996_AIF1_BCLK:
+       case WM8996_AIF1_TX_LRCLK_1:
+       case WM8996_AIF1_TX_LRCLK_2:
+       case WM8996_AIF1_RX_LRCLK_1:
+       case WM8996_AIF1_RX_LRCLK_2:
+       case WM8996_AIF1TX_DATA_CONFIGURATION_1:
+       case WM8996_AIF1TX_DATA_CONFIGURATION_2:
+       case WM8996_AIF1RX_DATA_CONFIGURATION:
+       case WM8996_AIF1TX_CHANNEL_0_CONFIGURATION:
+       case WM8996_AIF1TX_CHANNEL_1_CONFIGURATION:
+       case WM8996_AIF1TX_CHANNEL_2_CONFIGURATION:
+       case WM8996_AIF1TX_CHANNEL_3_CONFIGURATION:
+       case WM8996_AIF1TX_CHANNEL_4_CONFIGURATION:
+       case WM8996_AIF1TX_CHANNEL_5_CONFIGURATION:
+       case WM8996_AIF1RX_CHANNEL_0_CONFIGURATION:
+       case WM8996_AIF1RX_CHANNEL_1_CONFIGURATION:
+       case WM8996_AIF1RX_CHANNEL_2_CONFIGURATION:
+       case WM8996_AIF1RX_CHANNEL_3_CONFIGURATION:
+       case WM8996_AIF1RX_CHANNEL_4_CONFIGURATION:
+       case WM8996_AIF1RX_CHANNEL_5_CONFIGURATION:
+       case WM8996_AIF1RX_MONO_CONFIGURATION:
+       case WM8996_AIF1TX_TEST:
+       case WM8996_AIF2_CONTROL:
+       case WM8996_AIF2_BCLK:
+       case WM8996_AIF2_TX_LRCLK_1:
+       case WM8996_AIF2_TX_LRCLK_2:
+       case WM8996_AIF2_RX_LRCLK_1:
+       case WM8996_AIF2_RX_LRCLK_2:
+       case WM8996_AIF2TX_DATA_CONFIGURATION_1:
+       case WM8996_AIF2TX_DATA_CONFIGURATION_2:
+       case WM8996_AIF2RX_DATA_CONFIGURATION:
+       case WM8996_AIF2TX_CHANNEL_0_CONFIGURATION:
+       case WM8996_AIF2TX_CHANNEL_1_CONFIGURATION:
+       case WM8996_AIF2RX_CHANNEL_0_CONFIGURATION:
+       case WM8996_AIF2RX_CHANNEL_1_CONFIGURATION:
+       case WM8996_AIF2RX_MONO_CONFIGURATION:
+       case WM8996_AIF2TX_TEST:
+       case WM8996_DSP1_TX_LEFT_VOLUME:
+       case WM8996_DSP1_TX_RIGHT_VOLUME:
+       case WM8996_DSP1_RX_LEFT_VOLUME:
+       case WM8996_DSP1_RX_RIGHT_VOLUME:
+       case WM8996_DSP1_TX_FILTERS:
+       case WM8996_DSP1_RX_FILTERS_1:
+       case WM8996_DSP1_RX_FILTERS_2:
+       case WM8996_DSP1_DRC_1:
+       case WM8996_DSP1_DRC_2:
+       case WM8996_DSP1_DRC_3:
+       case WM8996_DSP1_DRC_4:
+       case WM8996_DSP1_DRC_5:
+       case WM8996_DSP1_RX_EQ_GAINS_1:
+       case WM8996_DSP1_RX_EQ_GAINS_2:
+       case WM8996_DSP1_RX_EQ_BAND_1_A:
+       case WM8996_DSP1_RX_EQ_BAND_1_B:
+       case WM8996_DSP1_RX_EQ_BAND_1_PG:
+       case WM8996_DSP1_RX_EQ_BAND_2_A:
+       case WM8996_DSP1_RX_EQ_BAND_2_B:
+       case WM8996_DSP1_RX_EQ_BAND_2_C:
+       case WM8996_DSP1_RX_EQ_BAND_2_PG:
+       case WM8996_DSP1_RX_EQ_BAND_3_A:
+       case WM8996_DSP1_RX_EQ_BAND_3_B:
+       case WM8996_DSP1_RX_EQ_BAND_3_C:
+       case WM8996_DSP1_RX_EQ_BAND_3_PG:
+       case WM8996_DSP1_RX_EQ_BAND_4_A:
+       case WM8996_DSP1_RX_EQ_BAND_4_B:
+       case WM8996_DSP1_RX_EQ_BAND_4_C:
+       case WM8996_DSP1_RX_EQ_BAND_4_PG:
+       case WM8996_DSP1_RX_EQ_BAND_5_A:
+       case WM8996_DSP1_RX_EQ_BAND_5_B:
+       case WM8996_DSP1_RX_EQ_BAND_5_PG:
+       case WM8996_DSP2_TX_LEFT_VOLUME:
+       case WM8996_DSP2_TX_RIGHT_VOLUME:
+       case WM8996_DSP2_RX_LEFT_VOLUME:
+       case WM8996_DSP2_RX_RIGHT_VOLUME:
+       case WM8996_DSP2_TX_FILTERS:
+       case WM8996_DSP2_RX_FILTERS_1:
+       case WM8996_DSP2_RX_FILTERS_2:
+       case WM8996_DSP2_DRC_1:
+       case WM8996_DSP2_DRC_2:
+       case WM8996_DSP2_DRC_3:
+       case WM8996_DSP2_DRC_4:
+       case WM8996_DSP2_DRC_5:
+       case WM8996_DSP2_RX_EQ_GAINS_1:
+       case WM8996_DSP2_RX_EQ_GAINS_2:
+       case WM8996_DSP2_RX_EQ_BAND_1_A:
+       case WM8996_DSP2_RX_EQ_BAND_1_B:
+       case WM8996_DSP2_RX_EQ_BAND_1_PG:
+       case WM8996_DSP2_RX_EQ_BAND_2_A:
+       case WM8996_DSP2_RX_EQ_BAND_2_B:
+       case WM8996_DSP2_RX_EQ_BAND_2_C:
+       case WM8996_DSP2_RX_EQ_BAND_2_PG:
+       case WM8996_DSP2_RX_EQ_BAND_3_A:
+       case WM8996_DSP2_RX_EQ_BAND_3_B:
+       case WM8996_DSP2_RX_EQ_BAND_3_C:
+       case WM8996_DSP2_RX_EQ_BAND_3_PG:
+       case WM8996_DSP2_RX_EQ_BAND_4_A:
+       case WM8996_DSP2_RX_EQ_BAND_4_B:
+       case WM8996_DSP2_RX_EQ_BAND_4_C:
+       case WM8996_DSP2_RX_EQ_BAND_4_PG:
+       case WM8996_DSP2_RX_EQ_BAND_5_A:
+       case WM8996_DSP2_RX_EQ_BAND_5_B:
+       case WM8996_DSP2_RX_EQ_BAND_5_PG:
+       case WM8996_DAC1_MIXER_VOLUMES:
+       case WM8996_DAC1_LEFT_MIXER_ROUTING:
+       case WM8996_DAC1_RIGHT_MIXER_ROUTING:
+       case WM8996_DAC2_MIXER_VOLUMES:
+       case WM8996_DAC2_LEFT_MIXER_ROUTING:
+       case WM8996_DAC2_RIGHT_MIXER_ROUTING:
+       case WM8996_DSP1_TX_LEFT_MIXER_ROUTING:
+       case WM8996_DSP1_TX_RIGHT_MIXER_ROUTING:
+       case WM8996_DSP2_TX_LEFT_MIXER_ROUTING:
+       case WM8996_DSP2_TX_RIGHT_MIXER_ROUTING:
+       case WM8996_DSP_TX_MIXER_SELECT:
+       case WM8996_DAC_SOFTMUTE:
+       case WM8996_OVERSAMPLING:
+       case WM8996_SIDETONE:
+       case WM8996_GPIO_1:
+       case WM8996_GPIO_2:
+       case WM8996_GPIO_3:
+       case WM8996_GPIO_4:
+       case WM8996_GPIO_5:
+       case WM8996_PULL_CONTROL_1:
+       case WM8996_PULL_CONTROL_2:
+       case WM8996_INTERRUPT_STATUS_1:
+       case WM8996_INTERRUPT_STATUS_2:
+       case WM8996_INTERRUPT_RAW_STATUS_2:
+       case WM8996_INTERRUPT_STATUS_1_MASK:
+       case WM8996_INTERRUPT_STATUS_2_MASK:
+       case WM8996_INTERRUPT_CONTROL:
+       case WM8996_LEFT_PDM_SPEAKER:
+       case WM8996_RIGHT_PDM_SPEAKER:
+       case WM8996_PDM_SPEAKER_MUTE_SEQUENCE:
+       case WM8996_PDM_SPEAKER_VOLUME:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static int wm8996_volatile_register(struct snd_soc_codec *codec,
+                                   unsigned int reg)
+{
+       switch (reg) {
+       case WM8996_SOFTWARE_RESET:
+       case WM8996_CHIP_REVISION:
+       case WM8996_LDO_1:
+       case WM8996_LDO_2:
+       case WM8996_INTERRUPT_STATUS_1:
+       case WM8996_INTERRUPT_STATUS_2:
+       case WM8996_INTERRUPT_RAW_STATUS_2:
+       case WM8996_DC_SERVO_READBACK_0:
+       case WM8996_DC_SERVO_2:
+       case WM8996_DC_SERVO_6:
+       case WM8996_DC_SERVO_7:
+       case WM8996_FLL_CONTROL_6:
+       case WM8996_MIC_DETECT_3:
+       case WM8996_HEADPHONE_DETECT_1:
+       case WM8996_HEADPHONE_DETECT_2:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static int wm8996_reset(struct snd_soc_codec *codec)
+{
+       return snd_soc_write(codec, WM8996_SOFTWARE_RESET, 0x8915);
+}
+
+static const int bclk_divs[] = {
+       1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96
+};
+
+static void wm8996_update_bclk(struct snd_soc_codec *codec)
+{
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       int aif, best, cur_val, bclk_rate, bclk_reg, i;
+
+       /* Don't bother if we're in a low frequency idle mode that
+        * can't support audio.
+        */
+       if (wm8996->sysclk < 64000)
+               return;
+
+       for (aif = 0; aif < WM8996_AIFS; aif++) {
+               switch (aif) {
+               case 0:
+                       bclk_reg = WM8996_AIF1_BCLK;
+                       break;
+               case 1:
+                       bclk_reg = WM8996_AIF2_BCLK;
+                       break;
+               }
+
+               bclk_rate = wm8996->bclk_rate[aif];
+
+               /* Pick a divisor for BCLK as close as we can get to ideal */
+               best = 0;
+               for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
+                       cur_val = (wm8996->sysclk / bclk_divs[i]) - bclk_rate;
+                       if (cur_val < 0) /* BCLK table is sorted */
+                               break;
+                       best = i;
+               }
+               bclk_rate = wm8996->sysclk / bclk_divs[best];
+               dev_dbg(codec->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n",
+                       bclk_divs[best], bclk_rate);
+
+               snd_soc_update_bits(codec, bclk_reg,
+                                   WM8996_AIF1_BCLK_DIV_MASK, best);
+       }
+}
+
+static int wm8996_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+
+       case SND_SOC_BIAS_PREPARE:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
+                       snd_soc_update_bits(codec, WM8996_POWER_MANAGEMENT_1,
+                                           WM8996_BG_ENA, WM8996_BG_ENA);
+                       msleep(2);
+               }
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+                       ret = regulator_bulk_enable(ARRAY_SIZE(wm8996->supplies),
+                                                   wm8996->supplies);
+                       if (ret != 0) {
+                               dev_err(codec->dev,
+                                       "Failed to enable supplies: %d\n",
+                                       ret);
+                               return ret;
+                       }
+
+                       if (wm8996->pdata.ldo_ena >= 0) {
+                               gpio_set_value_cansleep(wm8996->pdata.ldo_ena,
+                                                       1);
+                               msleep(5);
+                       }
+
+                       codec->cache_only = false;
+                       snd_soc_cache_sync(codec);
+               }
+
+               snd_soc_update_bits(codec, WM8996_POWER_MANAGEMENT_1,
+                                   WM8996_BG_ENA, 0);
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               codec->cache_only = true;
+               if (wm8996->pdata.ldo_ena >= 0)
+                       gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
+               regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies),
+                                      wm8996->supplies);
+               break;
+       }
+
+       codec->dapm.bias_level = level;
+
+       return 0;
+}
+
+static int wm8996_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       int aifctrl = 0;
+       int bclk = 0;
+       int lrclk_tx = 0;
+       int lrclk_rx = 0;
+       int aifctrl_reg, bclk_reg, lrclk_tx_reg, lrclk_rx_reg;
+
+       switch (dai->id) {
+       case 0:
+               aifctrl_reg = WM8996_AIF1_CONTROL;
+               bclk_reg = WM8996_AIF1_BCLK;
+               lrclk_tx_reg = WM8996_AIF1_TX_LRCLK_2;
+               lrclk_rx_reg = WM8996_AIF1_RX_LRCLK_2;
+               break;
+       case 1:
+               aifctrl_reg = WM8996_AIF2_CONTROL;
+               bclk_reg = WM8996_AIF2_BCLK;
+               lrclk_tx_reg = WM8996_AIF2_TX_LRCLK_2;
+               lrclk_rx_reg = WM8996_AIF2_RX_LRCLK_2;
+               break;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               bclk |= WM8996_AIF1_BCLK_INV;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               lrclk_tx |= WM8996_AIF1TX_LRCLK_INV;
+               lrclk_rx |= WM8996_AIF1RX_LRCLK_INV;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               bclk |= WM8996_AIF1_BCLK_INV;
+               lrclk_tx |= WM8996_AIF1TX_LRCLK_INV;
+               lrclk_rx |= WM8996_AIF1RX_LRCLK_INV;
+               break;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+               lrclk_tx |= WM8996_AIF1TX_LRCLK_MSTR;
+               lrclk_rx |= WM8996_AIF1RX_LRCLK_MSTR;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               bclk |= WM8996_AIF1_BCLK_MSTR;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               bclk |= WM8996_AIF1_BCLK_MSTR;
+               lrclk_tx |= WM8996_AIF1TX_LRCLK_MSTR;
+               lrclk_rx |= WM8996_AIF1RX_LRCLK_MSTR;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               aifctrl |= 1;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               aifctrl |= 2;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               aifctrl |= 3;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, aifctrl_reg, WM8996_AIF1_FMT_MASK, aifctrl);
+       snd_soc_update_bits(codec, bclk_reg,
+                           WM8996_AIF1_BCLK_INV | WM8996_AIF1_BCLK_MSTR,
+                           bclk);
+       snd_soc_update_bits(codec, lrclk_tx_reg,
+                           WM8996_AIF1TX_LRCLK_INV |
+                           WM8996_AIF1TX_LRCLK_MSTR,
+                           lrclk_tx);
+       snd_soc_update_bits(codec, lrclk_rx_reg,
+                           WM8996_AIF1RX_LRCLK_INV |
+                           WM8996_AIF1RX_LRCLK_MSTR,
+                           lrclk_rx);
+
+       return 0;
+}
+
+static const int dsp_divs[] = {
+       48000, 32000, 16000, 8000
+};
+
+static int wm8996_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       int bits, i, bclk_rate;
+       int aifdata = 0;
+       int lrclk = 0;
+       int dsp = 0;
+       int aifdata_reg, lrclk_reg, dsp_shift;
+
+       switch (dai->id) {
+       case 0:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+                   (snd_soc_read(codec, WM8996_GPIO_1)) & WM8996_GP1_FN_MASK) {
+                       aifdata_reg = WM8996_AIF1RX_DATA_CONFIGURATION;
+                       lrclk_reg = WM8996_AIF1_RX_LRCLK_1;
+               } else {
+                       aifdata_reg = WM8996_AIF1TX_DATA_CONFIGURATION_1;
+                       lrclk_reg = WM8996_AIF1_TX_LRCLK_1;
+               }
+               dsp_shift = 0;
+               break;
+       case 1:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+                   (snd_soc_read(codec, WM8996_GPIO_2)) & WM8996_GP2_FN_MASK) {
+                       aifdata_reg = WM8996_AIF2RX_DATA_CONFIGURATION;
+                       lrclk_reg = WM8996_AIF2_RX_LRCLK_1;
+               } else {
+                       aifdata_reg = WM8996_AIF2TX_DATA_CONFIGURATION_1;
+                       lrclk_reg = WM8996_AIF2_TX_LRCLK_1;
+               }
+               dsp_shift = WM8996_DSP2_DIV_SHIFT;
+               break;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+
+       bclk_rate = snd_soc_params_to_bclk(params);
+       if (bclk_rate < 0) {
+               dev_err(codec->dev, "Unsupported BCLK rate: %d\n", bclk_rate);
+               return bclk_rate;
+       }
+
+       wm8996->bclk_rate[dai->id] = bclk_rate;
+       wm8996->rx_rate[dai->id] = params_rate(params);
+
+       /* Needs looking at for TDM */
+       bits = snd_pcm_format_width(params_format(params));
+       if (bits < 0)
+               return bits;
+       aifdata |= (bits << WM8996_AIF1TX_WL_SHIFT) | bits;
+
+       for (i = 0; i < ARRAY_SIZE(dsp_divs); i++) {
+               if (dsp_divs[i] == params_rate(params))
+                       break;
+       }
+       if (i == ARRAY_SIZE(dsp_divs)) {
+               dev_err(codec->dev, "Unsupported sample rate %dHz\n",
+                       params_rate(params));
+               return -EINVAL;
+       }
+       dsp |= i << dsp_shift;
+
+       wm8996_update_bclk(codec);
+
+       lrclk = bclk_rate / params_rate(params);
+       dev_dbg(dai->dev, "Using LRCLK rate %d for actual LRCLK %dHz\n",
+               lrclk, bclk_rate / lrclk);
+
+       snd_soc_update_bits(codec, aifdata_reg,
+                           WM8996_AIF1TX_WL_MASK |
+                           WM8996_AIF1TX_SLOT_LEN_MASK,
+                           aifdata);
+       snd_soc_update_bits(codec, lrclk_reg, WM8996_AIF1RX_RATE_MASK,
+                           lrclk);
+       snd_soc_update_bits(codec, WM8996_AIF_CLOCKING_2,
+                           WM8996_DSP1_DIV_SHIFT << dsp_shift, dsp);
+
+       return 0;
+}
+
+static int wm8996_set_sysclk(struct snd_soc_dai *dai,
+               int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       int lfclk = 0;
+       int ratediv = 0;
+       int src;
+       int old;
+
+       if (freq == wm8996->sysclk && clk_id == wm8996->sysclk_src)
+               return 0;
+
+       /* Disable SYSCLK while we reconfigure */
+       old = snd_soc_read(codec, WM8996_AIF_CLOCKING_1) & WM8996_SYSCLK_ENA;
+       snd_soc_update_bits(codec, WM8996_AIF_CLOCKING_1,
+                           WM8996_SYSCLK_ENA, 0);
+
+       switch (clk_id) {
+       case WM8996_SYSCLK_MCLK1:
+               wm8996->sysclk = freq;
+               src = 0;
+               break;
+       case WM8996_SYSCLK_MCLK2:
+               wm8996->sysclk = freq;
+               src = 1;
+               break;
+       case WM8996_SYSCLK_FLL:
+               wm8996->sysclk = freq;
+               src = 2;
+               break;
+       default:
+               dev_err(codec->dev, "Unsupported clock source %d\n", clk_id);
+               return -EINVAL;
+       }
+
+       switch (wm8996->sysclk) {
+       case 6144000:
+               snd_soc_update_bits(codec, WM8996_AIF_RATE,
+                                   WM8996_SYSCLK_RATE, 0);
+               break;
+       case 24576000:
+               ratediv = WM8996_SYSCLK_DIV;
+       case 12288000:
+               snd_soc_update_bits(codec, WM8996_AIF_RATE,
+                                   WM8996_SYSCLK_RATE, WM8996_SYSCLK_RATE);
+               break;
+       case 32000:
+       case 32768:
+               lfclk = WM8996_LFCLK_ENA;
+               break;
+       default:
+               dev_warn(codec->dev, "Unsupported clock rate %dHz\n",
+                        wm8996->sysclk);
+               return -EINVAL;
+       }
+
+       wm8996_update_bclk(codec);
+
+       snd_soc_update_bits(codec, WM8996_AIF_CLOCKING_1,
+                           WM8996_SYSCLK_SRC_MASK | WM8996_SYSCLK_DIV_MASK,
+                           src << WM8996_SYSCLK_SRC_SHIFT | ratediv);
+       snd_soc_update_bits(codec, WM8996_CLOCKING_1, WM8996_LFCLK_ENA, lfclk);
+       snd_soc_update_bits(codec, WM8996_AIF_CLOCKING_1,
+                           WM8996_SYSCLK_ENA, old);
+
+       wm8996->sysclk_src = clk_id;
+
+       return 0;
+}
+
+struct _fll_div {
+       u16 fll_fratio;
+       u16 fll_outdiv;
+       u16 fll_refclk_div;
+       u16 fll_loop_gain;
+       u16 fll_ref_freq;
+       u16 n;
+       u16 theta;
+       u16 lambda;
+};
+
+static struct {
+       unsigned int min;
+       unsigned int max;
+       u16 fll_fratio;
+       int ratio;
+} fll_fratios[] = {
+       {       0,    64000, 4, 16 },
+       {   64000,   128000, 3,  8 },
+       {  128000,   256000, 2,  4 },
+       {  256000,  1000000, 1,  2 },
+       { 1000000, 13500000, 0,  1 },
+};
+
+static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
+                      unsigned int Fout)
+{
+       unsigned int target;
+       unsigned int div;
+       unsigned int fratio, gcd_fll;
+       int i;
+
+       /* Fref must be <=13.5MHz */
+       div = 1;
+       fll_div->fll_refclk_div = 0;
+       while ((Fref / div) > 13500000) {
+               div *= 2;
+               fll_div->fll_refclk_div++;
+
+               if (div > 8) {
+                       pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
+                              Fref);
+                       return -EINVAL;
+               }
+       }
+
+       pr_debug("FLL Fref=%u Fout=%u\n", Fref, Fout);
+
+       /* Apply the division for our remaining calculations */
+       Fref /= div;
+
+       if (Fref >= 3000000)
+               fll_div->fll_loop_gain = 5;
+       else
+               fll_div->fll_loop_gain = 0;
+
+       if (Fref >= 48000)
+               fll_div->fll_ref_freq = 0;
+       else
+               fll_div->fll_ref_freq = 1;
+
+       /* Fvco should be 90-100MHz; don't check the upper bound */
+       div = 2;
+       while (Fout * div < 90000000) {
+               div++;
+               if (div > 64) {
+                       pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
+                              Fout);
+                       return -EINVAL;
+               }
+       }
+       target = Fout * div;
+       fll_div->fll_outdiv = div - 1;
+
+       pr_debug("FLL Fvco=%dHz\n", target);
+
+       /* Find an appropraite FLL_FRATIO and factor it out of the target */
+       for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
+               if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
+                       fll_div->fll_fratio = fll_fratios[i].fll_fratio;
+                       fratio = fll_fratios[i].ratio;
+                       break;
+               }
+       }
+       if (i == ARRAY_SIZE(fll_fratios)) {
+               pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
+               return -EINVAL;
+       }
+
+       fll_div->n = target / (fratio * Fref);
+
+       if (target % Fref == 0) {
+               fll_div->theta = 0;
+               fll_div->lambda = 0;
+       } else {
+               gcd_fll = gcd(target, fratio * Fref);
+
+               fll_div->theta = (target - (fll_div->n * fratio * Fref))
+                       / gcd_fll;
+               fll_div->lambda = (fratio * Fref) / gcd_fll;
+       }
+
+       pr_debug("FLL N=%x THETA=%x LAMBDA=%x\n",
+                fll_div->n, fll_div->theta, fll_div->lambda);
+       pr_debug("FLL_FRATIO=%x FLL_OUTDIV=%x FLL_REFCLK_DIV=%x\n",
+                fll_div->fll_fratio, fll_div->fll_outdiv,
+                fll_div->fll_refclk_div);
+
+       return 0;
+}
+
+static int wm8996_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
+                         unsigned int Fref, unsigned int Fout)
+{
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       struct i2c_client *i2c = to_i2c_client(codec->dev);
+       struct _fll_div fll_div;
+       unsigned long timeout;
+       int ret, reg;
+
+       /* Any change? */
+       if (source == wm8996->fll_src && Fref == wm8996->fll_fref &&
+           Fout == wm8996->fll_fout)
+               return 0;
+
+       if (Fout == 0) {
+               dev_dbg(codec->dev, "FLL disabled\n");
+
+               wm8996->fll_fref = 0;
+               wm8996->fll_fout = 0;
+
+               snd_soc_update_bits(codec, WM8996_FLL_CONTROL_1,
+                                   WM8996_FLL_ENA, 0);
+
+               return 0;
+       }
+
+       ret = fll_factors(&fll_div, Fref, Fout);
+       if (ret != 0)
+               return ret;
+
+       switch (source) {
+       case WM8996_FLL_MCLK1:
+               reg = 0;
+               break;
+       case WM8996_FLL_MCLK2:
+               reg = 1;
+               break;
+       case WM8996_FLL_DACLRCLK1:
+               reg = 2;
+               break;
+       case WM8996_FLL_BCLK1:
+               reg = 3;
+               break;
+       default:
+               dev_err(codec->dev, "Unknown FLL source %d\n", ret);
+               return -EINVAL;
+       }
+
+       reg |= fll_div.fll_refclk_div << WM8996_FLL_REFCLK_DIV_SHIFT;
+       reg |= fll_div.fll_ref_freq << WM8996_FLL_REF_FREQ_SHIFT;
+
+       snd_soc_update_bits(codec, WM8996_FLL_CONTROL_5,
+                           WM8996_FLL_REFCLK_DIV_MASK | WM8996_FLL_REF_FREQ |
+                           WM8996_FLL_REFCLK_SRC_MASK, reg);
+
+       reg = 0;
+       if (fll_div.theta || fll_div.lambda)
+               reg |= WM8996_FLL_EFS_ENA | (3 << WM8996_FLL_LFSR_SEL_SHIFT);
+       else
+               reg |= 1 << WM8996_FLL_LFSR_SEL_SHIFT;
+       snd_soc_write(codec, WM8996_FLL_EFS_2, reg);
+
+       snd_soc_update_bits(codec, WM8996_FLL_CONTROL_2,
+                           WM8996_FLL_OUTDIV_MASK |
+                           WM8996_FLL_FRATIO_MASK,
+                           (fll_div.fll_outdiv << WM8996_FLL_OUTDIV_SHIFT) |
+                           (fll_div.fll_fratio));
+
+       snd_soc_write(codec, WM8996_FLL_CONTROL_3, fll_div.theta);
+
+       snd_soc_update_bits(codec, WM8996_FLL_CONTROL_4,
+                           WM8996_FLL_N_MASK | WM8996_FLL_LOOP_GAIN_MASK,
+                           (fll_div.n << WM8996_FLL_N_SHIFT) |
+                           fll_div.fll_loop_gain);
+
+       snd_soc_write(codec, WM8996_FLL_EFS_1, fll_div.lambda);
+
+       snd_soc_update_bits(codec, WM8996_FLL_CONTROL_1,
+                           WM8996_FLL_ENA, WM8996_FLL_ENA);
+
+       /* The FLL supports live reconfiguration - kick that in case we were
+        * already enabled.
+        */
+       snd_soc_write(codec, WM8996_FLL_CONTROL_6, WM8996_FLL_SWITCH_CLK);
+
+       /* Wait for the FLL to lock, using the interrupt if possible */
+       if (Fref > 1000000)
+               timeout = usecs_to_jiffies(300);
+       else
+               timeout = msecs_to_jiffies(2);
+
+       /* Allow substantially longer if we've actually got the IRQ */
+       if (i2c->irq)
+               timeout *= 1000;
+
+       ret = wait_for_completion_timeout(&wm8996->fll_lock, timeout);
+
+       if (ret == 0 && i2c->irq) {
+               dev_err(codec->dev, "Timed out waiting for FLL\n");
+               ret = -ETIMEDOUT;
+       } else {
+               ret = 0;
+       }
+
+       dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
+
+       wm8996->fll_fref = Fref;
+       wm8996->fll_fout = Fout;
+       wm8996->fll_src = source;
+
+       return ret;
+}
+
+#ifdef CONFIG_GPIOLIB
+static inline struct wm8996_priv *gpio_to_wm8996(struct gpio_chip *chip)
+{
+       return container_of(chip, struct wm8996_priv, gpio_chip);
+}
+
+static void wm8996_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct wm8996_priv *wm8996 = gpio_to_wm8996(chip);
+       struct snd_soc_codec *codec = wm8996->codec;
+
+       snd_soc_update_bits(codec, WM8996_GPIO_1 + offset,
+                           WM8996_GP1_LVL, !!value << WM8996_GP1_LVL_SHIFT);
+}
+
+static int wm8996_gpio_direction_out(struct gpio_chip *chip,
+                                    unsigned offset, int value)
+{
+       struct wm8996_priv *wm8996 = gpio_to_wm8996(chip);
+       struct snd_soc_codec *codec = wm8996->codec;
+       int val;
+
+       val = (1 << WM8996_GP1_FN_SHIFT) | (!!value << WM8996_GP1_LVL_SHIFT);
+
+       return snd_soc_update_bits(codec, WM8996_GPIO_1 + offset,
+                                  WM8996_GP1_FN_MASK | WM8996_GP1_DIR |
+                                  WM8996_GP1_LVL, val);
+}
+
+static int wm8996_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       struct wm8996_priv *wm8996 = gpio_to_wm8996(chip);
+       struct snd_soc_codec *codec = wm8996->codec;
+       int ret;
+
+       ret = snd_soc_read(codec, WM8996_GPIO_1 + offset);
+       if (ret < 0)
+               return ret;
+
+       return (ret & WM8996_GP1_LVL) != 0;
+}
+
+static int wm8996_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+       struct wm8996_priv *wm8996 = gpio_to_wm8996(chip);
+       struct snd_soc_codec *codec = wm8996->codec;
+
+       return snd_soc_update_bits(codec, WM8996_GPIO_1 + offset,
+                                  WM8996_GP1_FN_MASK | WM8996_GP1_DIR,
+                                  (1 << WM8996_GP1_FN_SHIFT) |
+                                  (1 << WM8996_GP1_DIR_SHIFT));
+}
+
+static struct gpio_chip wm8996_template_chip = {
+       .label                  = "wm8996",
+       .owner                  = THIS_MODULE,
+       .direction_output       = wm8996_gpio_direction_out,
+       .set                    = wm8996_gpio_set,
+       .direction_input        = wm8996_gpio_direction_in,
+       .get                    = wm8996_gpio_get,
+       .can_sleep              = 1,
+};
+
+static void wm8996_init_gpio(struct snd_soc_codec *codec)
+{
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       wm8996->gpio_chip = wm8996_template_chip;
+       wm8996->gpio_chip.ngpio = 5;
+       wm8996->gpio_chip.dev = codec->dev;
+
+       if (wm8996->pdata.gpio_base)
+               wm8996->gpio_chip.base = wm8996->pdata.gpio_base;
+       else
+               wm8996->gpio_chip.base = -1;
+
+       ret = gpiochip_add(&wm8996->gpio_chip);
+       if (ret != 0)
+               dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
+}
+
+static void wm8996_free_gpio(struct snd_soc_codec *codec)
+{
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       ret = gpiochip_remove(&wm8996->gpio_chip);
+       if (ret != 0)
+               dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret);
+}
+#else
+static void wm8996_init_gpio(struct snd_soc_codec *codec)
+{
+}
+
+static void wm8996_free_gpio(struct snd_soc_codec *codec)
+{
+}
+#endif
+
+/**
+ * wm8996_detect - Enable default WM8996 jack detection
+ *
+ * The WM8996 has advanced accessory detection support for headsets.
+ * This function provides a default implementation which integrates
+ * the majority of this functionality with minimal user configuration.
+ *
+ * This will detect headset, headphone and short circuit button and
+ * will also detect inverted microphone ground connections and update
+ * the polarity of the connections.
+ */
+int wm8996_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
+                 wm8996_polarity_fn polarity_cb)
+{
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+
+       wm8996->jack = jack;
+       wm8996->detecting = true;
+       wm8996->polarity_cb = polarity_cb;
+
+       if (wm8996->polarity_cb)
+               wm8996->polarity_cb(codec, 0);
+
+       /* Clear discarge to avoid noise during detection */
+       snd_soc_update_bits(codec, WM8996_MICBIAS_1,
+                           WM8996_MICB1_DISCH, 0);
+       snd_soc_update_bits(codec, WM8996_MICBIAS_2,
+                           WM8996_MICB2_DISCH, 0);
+
+       /* LDO2 powers the microphones, SYSCLK clocks detection */
+       snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
+       snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK");
+
+       /* We start off just enabling microphone detection - even a
+        * plain headphone will trigger detection.
+        */
+       snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
+                           WM8996_MICD_ENA, WM8996_MICD_ENA);
+
+       /* Slowest detection rate, gives debounce for initial detection */
+       snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
+                           WM8996_MICD_RATE_MASK,
+                           WM8996_MICD_RATE_MASK);
+
+       /* Enable interrupts and we're off */
+       snd_soc_update_bits(codec, WM8996_INTERRUPT_STATUS_2_MASK,
+                           WM8996_IM_MICD_EINT, 0);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wm8996_detect);
+
+static void wm8996_micd(struct snd_soc_codec *codec)
+{
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       int val, reg;
+
+       val = snd_soc_read(codec, WM8996_MIC_DETECT_3);
+
+       dev_dbg(codec->dev, "Microphone event: %x\n", val);
+
+       if (!(val & WM8996_MICD_VALID)) {
+               dev_warn(codec->dev, "Microphone detection state invalid\n");
+               return;
+       }
+
+       /* No accessory, reset everything and report removal */
+       if (!(val & WM8996_MICD_STS)) {
+               dev_dbg(codec->dev, "Jack removal detected\n");
+               wm8996->jack_mic = false;
+               wm8996->detecting = true;
+               snd_soc_jack_report(wm8996->jack, 0,
+                                   SND_JACK_HEADSET | SND_JACK_BTN_0);
+               snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
+                                   WM8996_MICD_RATE_MASK,
+                                   WM8996_MICD_RATE_MASK);
+               return;
+       }
+
+       /* If the measurement is very high we've got a microphone but
+        * do a little debounce to account for mechanical issues.
+        */
+       if (val & 0x400) {
+               dev_dbg(codec->dev, "Microphone detected\n");
+               snd_soc_jack_report(wm8996->jack, SND_JACK_HEADSET,
+                                   SND_JACK_HEADSET | SND_JACK_BTN_0);
+               wm8996->jack_mic = true;
+               wm8996->detecting = false;
+
+               /* Increase poll rate to give better responsiveness
+                * for buttons */
+               snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
+                                   WM8996_MICD_RATE_MASK,
+                                   5 << WM8996_MICD_RATE_SHIFT);
+       }
+
+       /* If we detected a lower impedence during initial startup
+        * then we probably have the wrong polarity, flip it.  Don't
+        * do this for the lowest impedences to speed up detection of
+        * plain headphones.
+        */
+       if (wm8996->detecting && (val & 0x3f0)) {
+               reg = snd_soc_read(codec, WM8996_ACCESSORY_DETECT_MODE_2);
+               reg ^= WM8996_HPOUT1FB_SRC | WM8996_MICD_SRC |
+                       WM8996_MICD_BIAS_SRC;
+               snd_soc_update_bits(codec, WM8996_ACCESSORY_DETECT_MODE_2,
+                                   WM8996_HPOUT1FB_SRC | WM8996_MICD_SRC |
+                                   WM8996_MICD_BIAS_SRC, reg);
+
+               if (wm8996->polarity_cb)
+                       wm8996->polarity_cb(codec,
+                                           (reg & WM8996_MICD_SRC) != 0);
+
+               dev_dbg(codec->dev, "Set microphone polarity to %d\n",
+                       (reg & WM8996_MICD_SRC) != 0);
+
+               return;
+       }
+
+       /* Don't distinguish between buttons, just report any low
+        * impedence as BTN_0.
+        */
+       if (val & 0x3fc) {
+               if (wm8996->jack_mic) {
+                       dev_dbg(codec->dev, "Mic button detected\n");
+                       snd_soc_jack_report(wm8996->jack,
+                                           SND_JACK_HEADSET | SND_JACK_BTN_0,
+                                           SND_JACK_HEADSET | SND_JACK_BTN_0);
+               } else {
+                       dev_dbg(codec->dev, "Headphone detected\n");
+                       snd_soc_jack_report(wm8996->jack,
+                                           SND_JACK_HEADPHONE,
+                                           SND_JACK_HEADSET |
+                                           SND_JACK_BTN_0);
+
+                       /* Increase the detection rate a bit for
+                        * responsiveness.
+                        */
+                       snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
+                                           WM8996_MICD_RATE_MASK,
+                                           7 << WM8996_MICD_RATE_SHIFT);
+
+                       wm8996->detecting = false;
+               }
+       }
+}
+
+static irqreturn_t wm8996_irq(int irq, void *data)
+{
+       struct snd_soc_codec *codec = data;
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       int irq_val;
+
+       irq_val = snd_soc_read(codec, WM8996_INTERRUPT_STATUS_2);
+       if (irq_val < 0) {
+               dev_err(codec->dev, "Failed to read IRQ status: %d\n",
+                       irq_val);
+               return IRQ_NONE;
+       }
+       irq_val &= ~snd_soc_read(codec, WM8996_INTERRUPT_STATUS_2_MASK);
+
+       snd_soc_write(codec, WM8996_INTERRUPT_STATUS_2, irq_val);
+
+       if (irq_val & (WM8996_DCS_DONE_01_EINT | WM8996_DCS_DONE_23_EINT)) {
+               dev_dbg(codec->dev, "DC servo IRQ\n");
+               complete(&wm8996->dcs_done);
+       }
+
+       if (irq_val & WM8996_FIFOS_ERR_EINT)
+               dev_err(codec->dev, "Digital core FIFO error\n");
+
+       if (irq_val & WM8996_FLL_LOCK_EINT) {
+               dev_dbg(codec->dev, "FLL locked\n");
+               complete(&wm8996->fll_lock);
+       }
+
+       if (irq_val & WM8996_MICD_EINT)
+               wm8996_micd(codec);
+
+       if (irq_val)
+               return IRQ_HANDLED;
+       else
+               return IRQ_NONE;
+}
+
+static irqreturn_t wm8996_edge_irq(int irq, void *data)
+{
+       irqreturn_t ret = IRQ_NONE;
+       irqreturn_t val;
+
+       do {
+               val = wm8996_irq(irq, data);
+               if (val != IRQ_NONE)
+                       ret = val;
+       } while (val != IRQ_NONE);
+
+       return ret;
+}
+
+static void wm8996_retune_mobile_pdata(struct snd_soc_codec *codec)
+{
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       struct wm8996_pdata *pdata = &wm8996->pdata;
+
+       struct snd_kcontrol_new controls[] = {
+               SOC_ENUM_EXT("DSP1 EQ Mode",
+                            wm8996->retune_mobile_enum,
+                            wm8996_get_retune_mobile_enum,
+                            wm8996_put_retune_mobile_enum),
+               SOC_ENUM_EXT("DSP2 EQ Mode",
+                            wm8996->retune_mobile_enum,
+                            wm8996_get_retune_mobile_enum,
+                            wm8996_put_retune_mobile_enum),
+       };
+       int ret, i, j;
+       const char **t;
+
+       /* We need an array of texts for the enum API but the number
+        * of texts is likely to be less than the number of
+        * configurations due to the sample rate dependency of the
+        * configurations. */
+       wm8996->num_retune_mobile_texts = 0;
+       wm8996->retune_mobile_texts = NULL;
+       for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
+               for (j = 0; j < wm8996->num_retune_mobile_texts; j++) {
+                       if (strcmp(pdata->retune_mobile_cfgs[i].name,
+                                  wm8996->retune_mobile_texts[j]) == 0)
+                               break;
+               }
+
+               if (j != wm8996->num_retune_mobile_texts)
+                       continue;
+
+               /* Expand the array... */
+               t = krealloc(wm8996->retune_mobile_texts,
+                            sizeof(char *) * 
+                            (wm8996->num_retune_mobile_texts + 1),
+                            GFP_KERNEL);
+               if (t == NULL)
+                       continue;
+
+               /* ...store the new entry... */
+               t[wm8996->num_retune_mobile_texts] = 
+                       pdata->retune_mobile_cfgs[i].name;
+
+               /* ...and remember the new version. */
+               wm8996->num_retune_mobile_texts++;
+               wm8996->retune_mobile_texts = t;
+       }
+
+       dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n",
+               wm8996->num_retune_mobile_texts);
+
+       wm8996->retune_mobile_enum.max = wm8996->num_retune_mobile_texts;
+       wm8996->retune_mobile_enum.texts = wm8996->retune_mobile_texts;
+
+       ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls));
+       if (ret != 0)
+               dev_err(codec->dev,
+                       "Failed to add ReTune Mobile controls: %d\n", ret);
+}
+
+static int wm8996_probe(struct snd_soc_codec *codec)
+{
+       int ret;
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       struct i2c_client *i2c = to_i2c_client(codec->dev);
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       int i, irq_flags;
+
+       wm8996->codec = codec;
+
+       init_completion(&wm8996->dcs_done);
+       init_completion(&wm8996->fll_lock);
+
+       dapm->idle_bias_off = true;
+       dapm->bias_level = SND_SOC_BIAS_OFF;
+
+       ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_I2C);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               goto err;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++)
+               wm8996->supplies[i].supply = wm8996_supply_names[i];
+
+       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8996->supplies),
+                                wm8996->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               goto err;
+       }
+
+       wm8996->disable_nb[0].notifier_call = wm8996_regulator_event_0;
+       wm8996->disable_nb[1].notifier_call = wm8996_regulator_event_1;
+       wm8996->disable_nb[2].notifier_call = wm8996_regulator_event_2;
+       wm8996->disable_nb[3].notifier_call = wm8996_regulator_event_3;
+
+       /* This should really be moved into the regulator core */
+       for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++) {
+               ret = regulator_register_notifier(wm8996->supplies[i].consumer,
+                                                 &wm8996->disable_nb[i]);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to register regulator notifier: %d\n",
+                               ret);
+               }
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm8996->supplies),
+                                   wm8996->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+               goto err_get;
+       }
+
+       if (wm8996->pdata.ldo_ena >= 0) {
+               gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 1);
+               msleep(5);
+       }
+
+       ret = snd_soc_read(codec, WM8996_SOFTWARE_RESET);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to read ID register: %d\n", ret);
+               goto err_enable;
+       }
+       if (ret != 0x8915) {
+               dev_err(codec->dev, "Device is not a WM8996, ID %x\n", ret);
+               ret = -EINVAL;
+               goto err_enable;
+       }
+
+       ret = snd_soc_read(codec, WM8996_CHIP_REVISION);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to read device revision: %d\n",
+                       ret);
+               goto err_enable;
+       }
+       
+       dev_info(codec->dev, "revision %c\n",
+                (ret & WM8996_CHIP_REV_MASK) + 'A');
+
+       if (wm8996->pdata.ldo_ena >= 0) {
+               gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
+       } else {
+               ret = wm8996_reset(codec);
+               if (ret < 0) {
+                       dev_err(codec->dev, "Failed to issue reset\n");
+                       goto err_enable;
+               }
+       }
+
+       codec->cache_only = true;
+
+       /* Apply platform data settings */
+       snd_soc_update_bits(codec, WM8996_LINE_INPUT_CONTROL,
+                           WM8996_INL_MODE_MASK | WM8996_INR_MODE_MASK,
+                           wm8996->pdata.inl_mode << WM8996_INL_MODE_SHIFT |
+                           wm8996->pdata.inr_mode);
+
+       for (i = 0; i < ARRAY_SIZE(wm8996->pdata.gpio_default); i++) {
+               if (!wm8996->pdata.gpio_default[i])
+                       continue;
+
+               snd_soc_write(codec, WM8996_GPIO_1 + i,
+                             wm8996->pdata.gpio_default[i] & 0xffff);
+       }
+
+       if (wm8996->pdata.spkmute_seq)
+               snd_soc_update_bits(codec, WM8996_PDM_SPEAKER_MUTE_SEQUENCE,
+                                   WM8996_SPK_MUTE_ENDIAN |
+                                   WM8996_SPK_MUTE_SEQ1_MASK,
+                                   wm8996->pdata.spkmute_seq);
+
+       snd_soc_update_bits(codec, WM8996_ACCESSORY_DETECT_MODE_2,
+                           WM8996_MICD_BIAS_SRC | WM8996_HPOUT1FB_SRC |
+                           WM8996_MICD_SRC, wm8996->pdata.micdet_def);
+
+       /* Latch volume update bits */
+       snd_soc_update_bits(codec, WM8996_LEFT_LINE_INPUT_VOLUME,
+                           WM8996_IN1_VU, WM8996_IN1_VU);
+       snd_soc_update_bits(codec, WM8996_RIGHT_LINE_INPUT_VOLUME,
+                           WM8996_IN1_VU, WM8996_IN1_VU);
+
+       snd_soc_update_bits(codec, WM8996_DAC1_LEFT_VOLUME,
+                           WM8996_DAC1_VU, WM8996_DAC1_VU);
+       snd_soc_update_bits(codec, WM8996_DAC1_RIGHT_VOLUME,
+                           WM8996_DAC1_VU, WM8996_DAC1_VU);
+       snd_soc_update_bits(codec, WM8996_DAC2_LEFT_VOLUME,
+                           WM8996_DAC2_VU, WM8996_DAC2_VU);
+       snd_soc_update_bits(codec, WM8996_DAC2_RIGHT_VOLUME,
+                           WM8996_DAC2_VU, WM8996_DAC2_VU);
+
+       snd_soc_update_bits(codec, WM8996_OUTPUT1_LEFT_VOLUME,
+                           WM8996_DAC1_VU, WM8996_DAC1_VU);
+       snd_soc_update_bits(codec, WM8996_OUTPUT1_RIGHT_VOLUME,
+                           WM8996_DAC1_VU, WM8996_DAC1_VU);
+       snd_soc_update_bits(codec, WM8996_OUTPUT2_LEFT_VOLUME,
+                           WM8996_DAC2_VU, WM8996_DAC2_VU);
+       snd_soc_update_bits(codec, WM8996_OUTPUT2_RIGHT_VOLUME,
+                           WM8996_DAC2_VU, WM8996_DAC2_VU);
+
+       snd_soc_update_bits(codec, WM8996_DSP1_TX_LEFT_VOLUME,
+                           WM8996_DSP1TX_VU, WM8996_DSP1TX_VU);
+       snd_soc_update_bits(codec, WM8996_DSP1_TX_RIGHT_VOLUME,
+                           WM8996_DSP1TX_VU, WM8996_DSP1TX_VU);
+       snd_soc_update_bits(codec, WM8996_DSP2_TX_LEFT_VOLUME,
+                           WM8996_DSP2TX_VU, WM8996_DSP2TX_VU);
+       snd_soc_update_bits(codec, WM8996_DSP2_TX_RIGHT_VOLUME,
+                           WM8996_DSP2TX_VU, WM8996_DSP2TX_VU);
+
+       snd_soc_update_bits(codec, WM8996_DSP1_RX_LEFT_VOLUME,
+                           WM8996_DSP1RX_VU, WM8996_DSP1RX_VU);
+       snd_soc_update_bits(codec, WM8996_DSP1_RX_RIGHT_VOLUME,
+                           WM8996_DSP1RX_VU, WM8996_DSP1RX_VU);
+       snd_soc_update_bits(codec, WM8996_DSP2_RX_LEFT_VOLUME,
+                           WM8996_DSP2RX_VU, WM8996_DSP2RX_VU);
+       snd_soc_update_bits(codec, WM8996_DSP2_RX_RIGHT_VOLUME,
+                           WM8996_DSP2RX_VU, WM8996_DSP2RX_VU);
+
+       /* No support currently for the underclocked TDM modes and
+        * pick a default TDM layout with each channel pair working with
+        * slots 0 and 1. */
+       snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_0_CONFIGURATION,
+                           WM8996_AIF1RX_CHAN0_SLOTS_MASK |
+                           WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
+                           1 << WM8996_AIF1RX_CHAN0_SLOTS_SHIFT | 0);
+       snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_1_CONFIGURATION,
+                           WM8996_AIF1RX_CHAN1_SLOTS_MASK |
+                           WM8996_AIF1RX_CHAN1_START_SLOT_MASK,
+                           1 << WM8996_AIF1RX_CHAN1_SLOTS_SHIFT | 1);
+       snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_2_CONFIGURATION,
+                           WM8996_AIF1RX_CHAN2_SLOTS_MASK |
+                           WM8996_AIF1RX_CHAN2_START_SLOT_MASK,
+                           1 << WM8996_AIF1RX_CHAN2_SLOTS_SHIFT | 0);
+       snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_3_CONFIGURATION,
+                           WM8996_AIF1RX_CHAN3_SLOTS_MASK |
+                           WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
+                           1 << WM8996_AIF1RX_CHAN3_SLOTS_SHIFT | 1);
+       snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_4_CONFIGURATION,
+                           WM8996_AIF1RX_CHAN4_SLOTS_MASK |
+                           WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
+                           1 << WM8996_AIF1RX_CHAN4_SLOTS_SHIFT | 0);
+       snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_5_CONFIGURATION,
+                           WM8996_AIF1RX_CHAN5_SLOTS_MASK |
+                           WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
+                           1 << WM8996_AIF1RX_CHAN5_SLOTS_SHIFT | 1);
+
+       snd_soc_update_bits(codec, WM8996_AIF2RX_CHANNEL_0_CONFIGURATION,
+                           WM8996_AIF2RX_CHAN0_SLOTS_MASK |
+                           WM8996_AIF2RX_CHAN0_START_SLOT_MASK,
+                           1 << WM8996_AIF2RX_CHAN0_SLOTS_SHIFT | 0);
+       snd_soc_update_bits(codec, WM8996_AIF2RX_CHANNEL_1_CONFIGURATION,
+                           WM8996_AIF2RX_CHAN1_SLOTS_MASK |
+                           WM8996_AIF2RX_CHAN1_START_SLOT_MASK,
+                           1 << WM8996_AIF2RX_CHAN1_SLOTS_SHIFT | 1);
+
+       snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_0_CONFIGURATION,
+                           WM8996_AIF1TX_CHAN0_SLOTS_MASK |
+                           WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
+                           1 << WM8996_AIF1TX_CHAN0_SLOTS_SHIFT | 0);
+       snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_1_CONFIGURATION,
+                           WM8996_AIF1TX_CHAN1_SLOTS_MASK |
+                           WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
+                           1 << WM8996_AIF1TX_CHAN1_SLOTS_SHIFT | 1);
+       snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_2_CONFIGURATION,
+                           WM8996_AIF1TX_CHAN2_SLOTS_MASK |
+                           WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
+                           1 << WM8996_AIF1TX_CHAN2_SLOTS_SHIFT | 0);
+       snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_3_CONFIGURATION,
+                           WM8996_AIF1TX_CHAN3_SLOTS_MASK |
+                           WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
+                           1 << WM8996_AIF1TX_CHAN3_SLOTS_SHIFT | 1);
+       snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_4_CONFIGURATION,
+                           WM8996_AIF1TX_CHAN4_SLOTS_MASK |
+                           WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
+                           1 << WM8996_AIF1TX_CHAN4_SLOTS_SHIFT | 0);
+       snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_5_CONFIGURATION,
+                           WM8996_AIF1TX_CHAN5_SLOTS_MASK |
+                           WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
+                           1 << WM8996_AIF1TX_CHAN5_SLOTS_SHIFT | 1);
+
+       snd_soc_update_bits(codec, WM8996_AIF2TX_CHANNEL_0_CONFIGURATION,
+                           WM8996_AIF2TX_CHAN0_SLOTS_MASK |
+                           WM8996_AIF2TX_CHAN0_START_SLOT_MASK,
+                           1 << WM8996_AIF2TX_CHAN0_SLOTS_SHIFT | 0);
+       snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_1_CONFIGURATION,
+                           WM8996_AIF2TX_CHAN1_SLOTS_MASK |
+                           WM8996_AIF2TX_CHAN1_START_SLOT_MASK,
+                           1 << WM8996_AIF1TX_CHAN1_SLOTS_SHIFT | 1);
+
+       if (wm8996->pdata.num_retune_mobile_cfgs)
+               wm8996_retune_mobile_pdata(codec);
+       else
+               snd_soc_add_controls(codec, wm8996_eq_controls,
+                                    ARRAY_SIZE(wm8996_eq_controls));
+
+       /* If the TX LRCLK pins are not in LRCLK mode configure the
+        * AIFs to source their clocks from the RX LRCLKs.
+        */
+       if ((snd_soc_read(codec, WM8996_GPIO_1)))
+               snd_soc_update_bits(codec, WM8996_AIF1_TX_LRCLK_2,
+                                   WM8996_AIF1TX_LRCLK_MODE,
+                                   WM8996_AIF1TX_LRCLK_MODE);
+
+       if ((snd_soc_read(codec, WM8996_GPIO_2)))
+               snd_soc_update_bits(codec, WM8996_AIF2_TX_LRCLK_2,
+                                   WM8996_AIF2TX_LRCLK_MODE,
+                                   WM8996_AIF2TX_LRCLK_MODE);
+
+       regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
+
+       wm8996_init_gpio(codec);
+
+       if (i2c->irq) {
+               if (wm8996->pdata.irq_flags)
+                       irq_flags = wm8996->pdata.irq_flags;
+               else
+                       irq_flags = IRQF_TRIGGER_LOW;
+
+               irq_flags |= IRQF_ONESHOT;
+
+               if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
+                       ret = request_threaded_irq(i2c->irq, NULL,
+                                                  wm8996_edge_irq,
+                                                  irq_flags, "wm8996", codec);
+               else
+                       ret = request_threaded_irq(i2c->irq, NULL, wm8996_irq,
+                                                  irq_flags, "wm8996", codec);
+
+               if (ret == 0) {
+                       /* Unmask the interrupt */
+                       snd_soc_update_bits(codec, WM8996_INTERRUPT_CONTROL,
+                                           WM8996_IM_IRQ, 0);
+
+                       /* Enable error reporting and DC servo status */
+                       snd_soc_update_bits(codec,
+                                           WM8996_INTERRUPT_STATUS_2_MASK,
+                                           WM8996_IM_DCS_DONE_23_EINT |
+                                           WM8996_IM_DCS_DONE_01_EINT |
+                                           WM8996_IM_FLL_LOCK_EINT |
+                                           WM8996_IM_FIFOS_ERR_EINT,
+                                           0);
+               } else {
+                       dev_err(codec->dev, "Failed to request IRQ: %d\n",
+                               ret);
+               }
+       }
+
+       return 0;
+
+err_enable:
+       if (wm8996->pdata.ldo_ena >= 0)
+               gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
+
+       regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
+err_get:
+       regulator_bulk_free(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
+err:
+       return ret;
+}
+
+static int wm8996_remove(struct snd_soc_codec *codec)
+{
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       struct i2c_client *i2c = to_i2c_client(codec->dev);
+       int i;
+
+       snd_soc_update_bits(codec, WM8996_INTERRUPT_CONTROL,
+                           WM8996_IM_IRQ, WM8996_IM_IRQ);
+
+       if (i2c->irq)
+               free_irq(i2c->irq, codec);
+
+       wm8996_free_gpio(codec);
+
+       for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++)
+               regulator_unregister_notifier(wm8996->supplies[i].consumer,
+                                             &wm8996->disable_nb[i]);
+       regulator_bulk_free(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
+
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8996 = {
+       .probe =        wm8996_probe,
+       .remove =       wm8996_remove,
+       .set_bias_level = wm8996_set_bias_level,
+       .seq_notifier = wm8996_seq_notifier,
+       .reg_cache_size = WM8996_MAX_REGISTER + 1,
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8996_reg,
+       .volatile_register = wm8996_volatile_register,
+       .readable_register = wm8996_readable_register,
+       .compress_type = SND_SOC_RBTREE_COMPRESSION,
+       .controls = wm8996_snd_controls,
+       .num_controls = ARRAY_SIZE(wm8996_snd_controls),
+       .dapm_widgets = wm8996_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm8996_dapm_widgets),
+       .dapm_routes = wm8996_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(wm8996_dapm_routes),
+       .set_pll = wm8996_set_fll,
+};
+
+#define WM8996_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+                     SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
+#define WM8996_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
+                       SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE |\
+                       SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops wm8996_dai_ops = {
+       .set_fmt = wm8996_set_fmt,
+       .hw_params = wm8996_hw_params,
+       .set_sysclk = wm8996_set_sysclk,
+};
+
+static struct snd_soc_dai_driver wm8996_dai[] = {
+       {
+               .name = "wm8996-aif1",
+               .playback = {
+                       .stream_name = "AIF1 Playback",
+                       .channels_min = 1,
+                       .channels_max = 6,
+                       .rates = WM8996_RATES,
+                       .formats = WM8996_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "AIF1 Capture",
+                        .channels_min = 1,
+                        .channels_max = 6,
+                        .rates = WM8996_RATES,
+                        .formats = WM8996_FORMATS,
+                },
+               .ops = &wm8996_dai_ops,
+       },
+       {
+               .name = "wm8996-aif2",
+               .playback = {
+                       .stream_name = "AIF2 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = WM8996_RATES,
+                       .formats = WM8996_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "AIF2 Capture",
+                        .channels_min = 1,
+                        .channels_max = 2,
+                        .rates = WM8996_RATES,
+                        .formats = WM8996_FORMATS,
+                },
+               .ops = &wm8996_dai_ops,
+       },
+};
+
+static __devinit int wm8996_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       struct wm8996_priv *wm8996;
+       int ret;
+
+       wm8996 = kzalloc(sizeof(struct wm8996_priv), GFP_KERNEL);
+       if (wm8996 == NULL)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, wm8996);
+
+       if (dev_get_platdata(&i2c->dev))
+               memcpy(&wm8996->pdata, dev_get_platdata(&i2c->dev),
+                      sizeof(wm8996->pdata));
+
+       if (wm8996->pdata.ldo_ena > 0) {
+               ret = gpio_request_one(wm8996->pdata.ldo_ena,
+                                      GPIOF_OUT_INIT_LOW, "WM8996 ENA");
+               if (ret < 0) {
+                       dev_err(&i2c->dev, "Failed to request GPIO %d: %d\n",
+                               wm8996->pdata.ldo_ena, ret);
+                       goto err;
+               }
+       }
+
+       ret = snd_soc_register_codec(&i2c->dev,
+                                    &soc_codec_dev_wm8996, wm8996_dai,
+                                    ARRAY_SIZE(wm8996_dai));
+       if (ret < 0)
+               goto err_gpio;
+
+       return ret;
+
+err_gpio:
+       if (wm8996->pdata.ldo_ena > 0)
+               gpio_free(wm8996->pdata.ldo_ena);
+err:
+       kfree(wm8996);
+
+       return ret;
+}
+
+static __devexit int wm8996_i2c_remove(struct i2c_client *client)
+{
+       struct wm8996_priv *wm8996 = i2c_get_clientdata(client);
+
+       snd_soc_unregister_codec(&client->dev);
+       if (wm8996->pdata.ldo_ena > 0)
+               gpio_free(wm8996->pdata.ldo_ena);
+       kfree(i2c_get_clientdata(client));
+       return 0;
+}
+
+static const struct i2c_device_id wm8996_i2c_id[] = {
+       { "wm8996", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8996_i2c_id);
+
+static struct i2c_driver wm8996_i2c_driver = {
+       .driver = {
+               .name = "wm8996",
+               .owner = THIS_MODULE,
+       },
+       .probe =    wm8996_i2c_probe,
+       .remove =   __devexit_p(wm8996_i2c_remove),
+       .id_table = wm8996_i2c_id,
+};
+
+static int __init wm8996_modinit(void)
+{
+       int ret;
+
+       ret = i2c_add_driver(&wm8996_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register WM8996 I2C driver: %d\n",
+                      ret);
+       }
+
+       return ret;
+}
+module_init(wm8996_modinit);
+
+static void __exit wm8996_exit(void)
+{
+       i2c_del_driver(&wm8996_i2c_driver);
+}
+module_exit(wm8996_exit);
+
+MODULE_DESCRIPTION("ASoC WM8996 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8996.h b/sound/soc/codecs/wm8996.h
new file mode 100644 (file)
index 0000000..0fde643
--- /dev/null
@@ -0,0 +1,3717 @@
+/*
+ * wm8996.h - WM8996 audio codec interface
+ *
+ * Copyright 2011 Wolfson Microelectronics PLC.
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.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.
+ */
+
+#ifndef _WM8996_H
+#define _WM8996_H
+
+#define WM8996_SYSCLK_MCLK1 1
+#define WM8996_SYSCLK_MCLK2 2
+#define WM8996_SYSCLK_FLL   3
+
+#define WM8996_FLL_MCLK1      1
+#define WM8996_FLL_MCLK2      2
+#define WM8996_FLL_DACLRCLK1  3
+#define WM8996_FLL_BCLK1      4
+
+typedef void (*wm8996_polarity_fn)(struct snd_soc_codec *codec, int polarity);
+
+int wm8996_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
+                 wm8996_polarity_fn polarity_cb);
+
+/*
+ * Register values.
+ */
+#define WM8996_SOFTWARE_RESET                   0x00
+#define WM8996_POWER_MANAGEMENT_1               0x01
+#define WM8996_POWER_MANAGEMENT_2               0x02
+#define WM8996_POWER_MANAGEMENT_3               0x03
+#define WM8996_POWER_MANAGEMENT_4               0x04
+#define WM8996_POWER_MANAGEMENT_5               0x05
+#define WM8996_POWER_MANAGEMENT_6               0x06
+#define WM8996_POWER_MANAGEMENT_7               0x07
+#define WM8996_POWER_MANAGEMENT_8               0x08
+#define WM8996_LEFT_LINE_INPUT_VOLUME           0x10
+#define WM8996_RIGHT_LINE_INPUT_VOLUME          0x11
+#define WM8996_LINE_INPUT_CONTROL               0x12
+#define WM8996_DAC1_HPOUT1_VOLUME               0x15
+#define WM8996_DAC2_HPOUT2_VOLUME               0x16
+#define WM8996_DAC1_LEFT_VOLUME                 0x18
+#define WM8996_DAC1_RIGHT_VOLUME                0x19
+#define WM8996_DAC2_LEFT_VOLUME                 0x1A
+#define WM8996_DAC2_RIGHT_VOLUME                0x1B
+#define WM8996_OUTPUT1_LEFT_VOLUME              0x1C
+#define WM8996_OUTPUT1_RIGHT_VOLUME             0x1D
+#define WM8996_OUTPUT2_LEFT_VOLUME              0x1E
+#define WM8996_OUTPUT2_RIGHT_VOLUME             0x1F
+#define WM8996_MICBIAS_1                        0x20
+#define WM8996_MICBIAS_2                        0x21
+#define WM8996_LDO_1                            0x28
+#define WM8996_LDO_2                            0x29
+#define WM8996_ACCESSORY_DETECT_MODE_1          0x30
+#define WM8996_ACCESSORY_DETECT_MODE_2          0x31
+#define WM8996_HEADPHONE_DETECT_1               0x34
+#define WM8996_HEADPHONE_DETECT_2               0x35
+#define WM8996_MIC_DETECT_1                     0x38
+#define WM8996_MIC_DETECT_2                     0x39
+#define WM8996_MIC_DETECT_3                     0x3A
+#define WM8996_CHARGE_PUMP_1                    0x40
+#define WM8996_CHARGE_PUMP_2                    0x41
+#define WM8996_DC_SERVO_1                       0x50
+#define WM8996_DC_SERVO_2                       0x51
+#define WM8996_DC_SERVO_3                       0x52
+#define WM8996_DC_SERVO_5                       0x54
+#define WM8996_DC_SERVO_6                       0x55
+#define WM8996_DC_SERVO_7                       0x56
+#define WM8996_DC_SERVO_READBACK_0              0x57
+#define WM8996_ANALOGUE_HP_1                    0x60
+#define WM8996_ANALOGUE_HP_2                    0x61
+#define WM8996_CHIP_REVISION                    0x100
+#define WM8996_CONTROL_INTERFACE_1              0x101
+#define WM8996_WRITE_SEQUENCER_CTRL_1           0x110
+#define WM8996_WRITE_SEQUENCER_CTRL_2           0x111
+#define WM8996_AIF_CLOCKING_1                   0x200
+#define WM8996_AIF_CLOCKING_2                   0x201
+#define WM8996_CLOCKING_1                       0x208
+#define WM8996_CLOCKING_2                       0x209
+#define WM8996_AIF_RATE                         0x210
+#define WM8996_FLL_CONTROL_1                    0x220
+#define WM8996_FLL_CONTROL_2                    0x221
+#define WM8996_FLL_CONTROL_3                    0x222
+#define WM8996_FLL_CONTROL_4                    0x223
+#define WM8996_FLL_CONTROL_5                    0x224
+#define WM8996_FLL_CONTROL_6                    0x225
+#define WM8996_FLL_EFS_1                        0x226
+#define WM8996_FLL_EFS_2                        0x227
+#define WM8996_AIF1_CONTROL                     0x300
+#define WM8996_AIF1_BCLK                        0x301
+#define WM8996_AIF1_TX_LRCLK_1                  0x302
+#define WM8996_AIF1_TX_LRCLK_2                  0x303
+#define WM8996_AIF1_RX_LRCLK_1                  0x304
+#define WM8996_AIF1_RX_LRCLK_2                  0x305
+#define WM8996_AIF1TX_DATA_CONFIGURATION_1      0x306
+#define WM8996_AIF1TX_DATA_CONFIGURATION_2      0x307
+#define WM8996_AIF1RX_DATA_CONFIGURATION        0x308
+#define WM8996_AIF1TX_CHANNEL_0_CONFIGURATION   0x309
+#define WM8996_AIF1TX_CHANNEL_1_CONFIGURATION   0x30A
+#define WM8996_AIF1TX_CHANNEL_2_CONFIGURATION   0x30B
+#define WM8996_AIF1TX_CHANNEL_3_CONFIGURATION   0x30C
+#define WM8996_AIF1TX_CHANNEL_4_CONFIGURATION   0x30D
+#define WM8996_AIF1TX_CHANNEL_5_CONFIGURATION   0x30E
+#define WM8996_AIF1RX_CHANNEL_0_CONFIGURATION   0x30F
+#define WM8996_AIF1RX_CHANNEL_1_CONFIGURATION   0x310
+#define WM8996_AIF1RX_CHANNEL_2_CONFIGURATION   0x311
+#define WM8996_AIF1RX_CHANNEL_3_CONFIGURATION   0x312
+#define WM8996_AIF1RX_CHANNEL_4_CONFIGURATION   0x313
+#define WM8996_AIF1RX_CHANNEL_5_CONFIGURATION   0x314
+#define WM8996_AIF1RX_MONO_CONFIGURATION        0x315
+#define WM8996_AIF1TX_TEST                      0x31A
+#define WM8996_AIF2_CONTROL                     0x320
+#define WM8996_AIF2_BCLK                        0x321
+#define WM8996_AIF2_TX_LRCLK_1                  0x322
+#define WM8996_AIF2_TX_LRCLK_2                  0x323
+#define WM8996_AIF2_RX_LRCLK_1                  0x324
+#define WM8996_AIF2_RX_LRCLK_2                  0x325
+#define WM8996_AIF2TX_DATA_CONFIGURATION_1      0x326
+#define WM8996_AIF2TX_DATA_CONFIGURATION_2      0x327
+#define WM8996_AIF2RX_DATA_CONFIGURATION        0x328
+#define WM8996_AIF2TX_CHANNEL_0_CONFIGURATION   0x329
+#define WM8996_AIF2TX_CHANNEL_1_CONFIGURATION   0x32A
+#define WM8996_AIF2RX_CHANNEL_0_CONFIGURATION   0x32B
+#define WM8996_AIF2RX_CHANNEL_1_CONFIGURATION   0x32C
+#define WM8996_AIF2RX_MONO_CONFIGURATION        0x32D
+#define WM8996_AIF2TX_TEST                      0x32F
+#define WM8996_DSP1_TX_LEFT_VOLUME              0x400
+#define WM8996_DSP1_TX_RIGHT_VOLUME             0x401
+#define WM8996_DSP1_RX_LEFT_VOLUME              0x402
+#define WM8996_DSP1_RX_RIGHT_VOLUME             0x403
+#define WM8996_DSP1_TX_FILTERS                  0x410
+#define WM8996_DSP1_RX_FILTERS_1                0x420
+#define WM8996_DSP1_RX_FILTERS_2                0x421
+#define WM8996_DSP1_DRC_1                       0x440
+#define WM8996_DSP1_DRC_2                       0x441
+#define WM8996_DSP1_DRC_3                       0x442
+#define WM8996_DSP1_DRC_4                       0x443
+#define WM8996_DSP1_DRC_5                       0x444
+#define WM8996_DSP1_RX_EQ_GAINS_1               0x480
+#define WM8996_DSP1_RX_EQ_GAINS_2               0x481
+#define WM8996_DSP1_RX_EQ_BAND_1_A              0x482
+#define WM8996_DSP1_RX_EQ_BAND_1_B              0x483
+#define WM8996_DSP1_RX_EQ_BAND_1_PG             0x484
+#define WM8996_DSP1_RX_EQ_BAND_2_A              0x485
+#define WM8996_DSP1_RX_EQ_BAND_2_B              0x486
+#define WM8996_DSP1_RX_EQ_BAND_2_C              0x487
+#define WM8996_DSP1_RX_EQ_BAND_2_PG             0x488
+#define WM8996_DSP1_RX_EQ_BAND_3_A              0x489
+#define WM8996_DSP1_RX_EQ_BAND_3_B              0x48A
+#define WM8996_DSP1_RX_EQ_BAND_3_C              0x48B
+#define WM8996_DSP1_RX_EQ_BAND_3_PG             0x48C
+#define WM8996_DSP1_RX_EQ_BAND_4_A              0x48D
+#define WM8996_DSP1_RX_EQ_BAND_4_B              0x48E
+#define WM8996_DSP1_RX_EQ_BAND_4_C              0x48F
+#define WM8996_DSP1_RX_EQ_BAND_4_PG             0x490
+#define WM8996_DSP1_RX_EQ_BAND_5_A              0x491
+#define WM8996_DSP1_RX_EQ_BAND_5_B              0x492
+#define WM8996_DSP1_RX_EQ_BAND_5_PG             0x493
+#define WM8996_DSP2_TX_LEFT_VOLUME              0x500
+#define WM8996_DSP2_TX_RIGHT_VOLUME             0x501
+#define WM8996_DSP2_RX_LEFT_VOLUME              0x502
+#define WM8996_DSP2_RX_RIGHT_VOLUME             0x503
+#define WM8996_DSP2_TX_FILTERS                  0x510
+#define WM8996_DSP2_RX_FILTERS_1                0x520
+#define WM8996_DSP2_RX_FILTERS_2                0x521
+#define WM8996_DSP2_DRC_1                       0x540
+#define WM8996_DSP2_DRC_2                       0x541
+#define WM8996_DSP2_DRC_3                       0x542
+#define WM8996_DSP2_DRC_4                       0x543
+#define WM8996_DSP2_DRC_5                       0x544
+#define WM8996_DSP2_RX_EQ_GAINS_1               0x580
+#define WM8996_DSP2_RX_EQ_GAINS_2               0x581
+#define WM8996_DSP2_RX_EQ_BAND_1_A              0x582
+#define WM8996_DSP2_RX_EQ_BAND_1_B              0x583
+#define WM8996_DSP2_RX_EQ_BAND_1_PG             0x584
+#define WM8996_DSP2_RX_EQ_BAND_2_A              0x585
+#define WM8996_DSP2_RX_EQ_BAND_2_B              0x586
+#define WM8996_DSP2_RX_EQ_BAND_2_C              0x587
+#define WM8996_DSP2_RX_EQ_BAND_2_PG             0x588
+#define WM8996_DSP2_RX_EQ_BAND_3_A              0x589
+#define WM8996_DSP2_RX_EQ_BAND_3_B              0x58A
+#define WM8996_DSP2_RX_EQ_BAND_3_C              0x58B
+#define WM8996_DSP2_RX_EQ_BAND_3_PG             0x58C
+#define WM8996_DSP2_RX_EQ_BAND_4_A              0x58D
+#define WM8996_DSP2_RX_EQ_BAND_4_B              0x58E
+#define WM8996_DSP2_RX_EQ_BAND_4_C              0x58F
+#define WM8996_DSP2_RX_EQ_BAND_4_PG             0x590
+#define WM8996_DSP2_RX_EQ_BAND_5_A              0x591
+#define WM8996_DSP2_RX_EQ_BAND_5_B              0x592
+#define WM8996_DSP2_RX_EQ_BAND_5_PG             0x593
+#define WM8996_DAC1_MIXER_VOLUMES               0x600
+#define WM8996_DAC1_LEFT_MIXER_ROUTING          0x601
+#define WM8996_DAC1_RIGHT_MIXER_ROUTING         0x602
+#define WM8996_DAC2_MIXER_VOLUMES               0x603
+#define WM8996_DAC2_LEFT_MIXER_ROUTING          0x604
+#define WM8996_DAC2_RIGHT_MIXER_ROUTING         0x605
+#define WM8996_DSP1_TX_LEFT_MIXER_ROUTING       0x606
+#define WM8996_DSP1_TX_RIGHT_MIXER_ROUTING      0x607
+#define WM8996_DSP2_TX_LEFT_MIXER_ROUTING       0x608
+#define WM8996_DSP2_TX_RIGHT_MIXER_ROUTING      0x609
+#define WM8996_DSP_TX_MIXER_SELECT              0x60A
+#define WM8996_DAC_SOFTMUTE                     0x610
+#define WM8996_OVERSAMPLING                     0x620
+#define WM8996_SIDETONE                         0x621
+#define WM8996_GPIO_1                           0x700
+#define WM8996_GPIO_2                           0x701
+#define WM8996_GPIO_3                           0x702
+#define WM8996_GPIO_4                           0x703
+#define WM8996_GPIO_5                           0x704
+#define WM8996_PULL_CONTROL_1                   0x720
+#define WM8996_PULL_CONTROL_2                   0x721
+#define WM8996_INTERRUPT_STATUS_1               0x730
+#define WM8996_INTERRUPT_STATUS_2               0x731
+#define WM8996_INTERRUPT_RAW_STATUS_2           0x732
+#define WM8996_INTERRUPT_STATUS_1_MASK          0x738
+#define WM8996_INTERRUPT_STATUS_2_MASK          0x739
+#define WM8996_INTERRUPT_CONTROL                0x740
+#define WM8996_LEFT_PDM_SPEAKER                 0x800
+#define WM8996_RIGHT_PDM_SPEAKER                0x801
+#define WM8996_PDM_SPEAKER_MUTE_SEQUENCE        0x802
+#define WM8996_PDM_SPEAKER_VOLUME               0x803
+#define WM8996_WRITE_SEQUENCER_0                0x3000
+#define WM8996_WRITE_SEQUENCER_1                0x3001
+#define WM8996_WRITE_SEQUENCER_2                0x3002
+#define WM8996_WRITE_SEQUENCER_3                0x3003
+#define WM8996_WRITE_SEQUENCER_4                0x3004
+#define WM8996_WRITE_SEQUENCER_5                0x3005
+#define WM8996_WRITE_SEQUENCER_6                0x3006
+#define WM8996_WRITE_SEQUENCER_7                0x3007
+#define WM8996_WRITE_SEQUENCER_8                0x3008
+#define WM8996_WRITE_SEQUENCER_9                0x3009
+#define WM8996_WRITE_SEQUENCER_10               0x300A
+#define WM8996_WRITE_SEQUENCER_11               0x300B
+#define WM8996_WRITE_SEQUENCER_12               0x300C
+#define WM8996_WRITE_SEQUENCER_13               0x300D
+#define WM8996_WRITE_SEQUENCER_14               0x300E
+#define WM8996_WRITE_SEQUENCER_15               0x300F
+#define WM8996_WRITE_SEQUENCER_16               0x3010
+#define WM8996_WRITE_SEQUENCER_17               0x3011
+#define WM8996_WRITE_SEQUENCER_18               0x3012
+#define WM8996_WRITE_SEQUENCER_19               0x3013
+#define WM8996_WRITE_SEQUENCER_20               0x3014
+#define WM8996_WRITE_SEQUENCER_21               0x3015
+#define WM8996_WRITE_SEQUENCER_22               0x3016
+#define WM8996_WRITE_SEQUENCER_23               0x3017
+#define WM8996_WRITE_SEQUENCER_24               0x3018
+#define WM8996_WRITE_SEQUENCER_25               0x3019
+#define WM8996_WRITE_SEQUENCER_26               0x301A
+#define WM8996_WRITE_SEQUENCER_27               0x301B
+#define WM8996_WRITE_SEQUENCER_28               0x301C
+#define WM8996_WRITE_SEQUENCER_29               0x301D
+#define WM8996_WRITE_SEQUENCER_30               0x301E
+#define WM8996_WRITE_SEQUENCER_31               0x301F
+#define WM8996_WRITE_SEQUENCER_32               0x3020
+#define WM8996_WRITE_SEQUENCER_33               0x3021
+#define WM8996_WRITE_SEQUENCER_34               0x3022
+#define WM8996_WRITE_SEQUENCER_35               0x3023
+#define WM8996_WRITE_SEQUENCER_36               0x3024
+#define WM8996_WRITE_SEQUENCER_37               0x3025
+#define WM8996_WRITE_SEQUENCER_38               0x3026
+#define WM8996_WRITE_SEQUENCER_39               0x3027
+#define WM8996_WRITE_SEQUENCER_40               0x3028
+#define WM8996_WRITE_SEQUENCER_41               0x3029
+#define WM8996_WRITE_SEQUENCER_42               0x302A
+#define WM8996_WRITE_SEQUENCER_43               0x302B
+#define WM8996_WRITE_SEQUENCER_44               0x302C
+#define WM8996_WRITE_SEQUENCER_45               0x302D
+#define WM8996_WRITE_SEQUENCER_46               0x302E
+#define WM8996_WRITE_SEQUENCER_47               0x302F
+#define WM8996_WRITE_SEQUENCER_48               0x3030
+#define WM8996_WRITE_SEQUENCER_49               0x3031
+#define WM8996_WRITE_SEQUENCER_50               0x3032
+#define WM8996_WRITE_SEQUENCER_51               0x3033
+#define WM8996_WRITE_SEQUENCER_52               0x3034
+#define WM8996_WRITE_SEQUENCER_53               0x3035
+#define WM8996_WRITE_SEQUENCER_54               0x3036
+#define WM8996_WRITE_SEQUENCER_55               0x3037
+#define WM8996_WRITE_SEQUENCER_56               0x3038
+#define WM8996_WRITE_SEQUENCER_57               0x3039
+#define WM8996_WRITE_SEQUENCER_58               0x303A
+#define WM8996_WRITE_SEQUENCER_59               0x303B
+#define WM8996_WRITE_SEQUENCER_60               0x303C
+#define WM8996_WRITE_SEQUENCER_61               0x303D
+#define WM8996_WRITE_SEQUENCER_62               0x303E
+#define WM8996_WRITE_SEQUENCER_63               0x303F
+#define WM8996_WRITE_SEQUENCER_64               0x3040
+#define WM8996_WRITE_SEQUENCER_65               0x3041
+#define WM8996_WRITE_SEQUENCER_66               0x3042
+#define WM8996_WRITE_SEQUENCER_67               0x3043
+#define WM8996_WRITE_SEQUENCER_68               0x3044
+#define WM8996_WRITE_SEQUENCER_69               0x3045
+#define WM8996_WRITE_SEQUENCER_70               0x3046
+#define WM8996_WRITE_SEQUENCER_71               0x3047
+#define WM8996_WRITE_SEQUENCER_72               0x3048
+#define WM8996_WRITE_SEQUENCER_73               0x3049
+#define WM8996_WRITE_SEQUENCER_74               0x304A
+#define WM8996_WRITE_SEQUENCER_75               0x304B
+#define WM8996_WRITE_SEQUENCER_76               0x304C
+#define WM8996_WRITE_SEQUENCER_77               0x304D
+#define WM8996_WRITE_SEQUENCER_78               0x304E
+#define WM8996_WRITE_SEQUENCER_79               0x304F
+#define WM8996_WRITE_SEQUENCER_80               0x3050
+#define WM8996_WRITE_SEQUENCER_81               0x3051
+#define WM8996_WRITE_SEQUENCER_82               0x3052
+#define WM8996_WRITE_SEQUENCER_83               0x3053
+#define WM8996_WRITE_SEQUENCER_84               0x3054
+#define WM8996_WRITE_SEQUENCER_85               0x3055
+#define WM8996_WRITE_SEQUENCER_86               0x3056
+#define WM8996_WRITE_SEQUENCER_87               0x3057
+#define WM8996_WRITE_SEQUENCER_88               0x3058
+#define WM8996_WRITE_SEQUENCER_89               0x3059
+#define WM8996_WRITE_SEQUENCER_90               0x305A
+#define WM8996_WRITE_SEQUENCER_91               0x305B
+#define WM8996_WRITE_SEQUENCER_92               0x305C
+#define WM8996_WRITE_SEQUENCER_93               0x305D
+#define WM8996_WRITE_SEQUENCER_94               0x305E
+#define WM8996_WRITE_SEQUENCER_95               0x305F
+#define WM8996_WRITE_SEQUENCER_96               0x3060
+#define WM8996_WRITE_SEQUENCER_97               0x3061
+#define WM8996_WRITE_SEQUENCER_98               0x3062
+#define WM8996_WRITE_SEQUENCER_99               0x3063
+#define WM8996_WRITE_SEQUENCER_100              0x3064
+#define WM8996_WRITE_SEQUENCER_101              0x3065
+#define WM8996_WRITE_SEQUENCER_102              0x3066
+#define WM8996_WRITE_SEQUENCER_103              0x3067
+#define WM8996_WRITE_SEQUENCER_104              0x3068
+#define WM8996_WRITE_SEQUENCER_105              0x3069
+#define WM8996_WRITE_SEQUENCER_106              0x306A
+#define WM8996_WRITE_SEQUENCER_107              0x306B
+#define WM8996_WRITE_SEQUENCER_108              0x306C
+#define WM8996_WRITE_SEQUENCER_109              0x306D
+#define WM8996_WRITE_SEQUENCER_110              0x306E
+#define WM8996_WRITE_SEQUENCER_111              0x306F
+#define WM8996_WRITE_SEQUENCER_112              0x3070
+#define WM8996_WRITE_SEQUENCER_113              0x3071
+#define WM8996_WRITE_SEQUENCER_114              0x3072
+#define WM8996_WRITE_SEQUENCER_115              0x3073
+#define WM8996_WRITE_SEQUENCER_116              0x3074
+#define WM8996_WRITE_SEQUENCER_117              0x3075
+#define WM8996_WRITE_SEQUENCER_118              0x3076
+#define WM8996_WRITE_SEQUENCER_119              0x3077
+#define WM8996_WRITE_SEQUENCER_120              0x3078
+#define WM8996_WRITE_SEQUENCER_121              0x3079
+#define WM8996_WRITE_SEQUENCER_122              0x307A
+#define WM8996_WRITE_SEQUENCER_123              0x307B
+#define WM8996_WRITE_SEQUENCER_124              0x307C
+#define WM8996_WRITE_SEQUENCER_125              0x307D
+#define WM8996_WRITE_SEQUENCER_126              0x307E
+#define WM8996_WRITE_SEQUENCER_127              0x307F
+#define WM8996_WRITE_SEQUENCER_128              0x3080
+#define WM8996_WRITE_SEQUENCER_129              0x3081
+#define WM8996_WRITE_SEQUENCER_130              0x3082
+#define WM8996_WRITE_SEQUENCER_131              0x3083
+#define WM8996_WRITE_SEQUENCER_132              0x3084
+#define WM8996_WRITE_SEQUENCER_133              0x3085
+#define WM8996_WRITE_SEQUENCER_134              0x3086
+#define WM8996_WRITE_SEQUENCER_135              0x3087
+#define WM8996_WRITE_SEQUENCER_136              0x3088
+#define WM8996_WRITE_SEQUENCER_137              0x3089
+#define WM8996_WRITE_SEQUENCER_138              0x308A
+#define WM8996_WRITE_SEQUENCER_139              0x308B
+#define WM8996_WRITE_SEQUENCER_140              0x308C
+#define WM8996_WRITE_SEQUENCER_141              0x308D
+#define WM8996_WRITE_SEQUENCER_142              0x308E
+#define WM8996_WRITE_SEQUENCER_143              0x308F
+#define WM8996_WRITE_SEQUENCER_144              0x3090
+#define WM8996_WRITE_SEQUENCER_145              0x3091
+#define WM8996_WRITE_SEQUENCER_146              0x3092
+#define WM8996_WRITE_SEQUENCER_147              0x3093
+#define WM8996_WRITE_SEQUENCER_148              0x3094
+#define WM8996_WRITE_SEQUENCER_149              0x3095
+#define WM8996_WRITE_SEQUENCER_150              0x3096
+#define WM8996_WRITE_SEQUENCER_151              0x3097
+#define WM8996_WRITE_SEQUENCER_152              0x3098
+#define WM8996_WRITE_SEQUENCER_153              0x3099
+#define WM8996_WRITE_SEQUENCER_154              0x309A
+#define WM8996_WRITE_SEQUENCER_155              0x309B
+#define WM8996_WRITE_SEQUENCER_156              0x309C
+#define WM8996_WRITE_SEQUENCER_157              0x309D
+#define WM8996_WRITE_SEQUENCER_158              0x309E
+#define WM8996_WRITE_SEQUENCER_159              0x309F
+#define WM8996_WRITE_SEQUENCER_160              0x30A0
+#define WM8996_WRITE_SEQUENCER_161              0x30A1
+#define WM8996_WRITE_SEQUENCER_162              0x30A2
+#define WM8996_WRITE_SEQUENCER_163              0x30A3
+#define WM8996_WRITE_SEQUENCER_164              0x30A4
+#define WM8996_WRITE_SEQUENCER_165              0x30A5
+#define WM8996_WRITE_SEQUENCER_166              0x30A6
+#define WM8996_WRITE_SEQUENCER_167              0x30A7
+#define WM8996_WRITE_SEQUENCER_168              0x30A8
+#define WM8996_WRITE_SEQUENCER_169              0x30A9
+#define WM8996_WRITE_SEQUENCER_170              0x30AA
+#define WM8996_WRITE_SEQUENCER_171              0x30AB
+#define WM8996_WRITE_SEQUENCER_172              0x30AC
+#define WM8996_WRITE_SEQUENCER_173              0x30AD
+#define WM8996_WRITE_SEQUENCER_174              0x30AE
+#define WM8996_WRITE_SEQUENCER_175              0x30AF
+#define WM8996_WRITE_SEQUENCER_176              0x30B0
+#define WM8996_WRITE_SEQUENCER_177              0x30B1
+#define WM8996_WRITE_SEQUENCER_178              0x30B2
+#define WM8996_WRITE_SEQUENCER_179              0x30B3
+#define WM8996_WRITE_SEQUENCER_180              0x30B4
+#define WM8996_WRITE_SEQUENCER_181              0x30B5
+#define WM8996_WRITE_SEQUENCER_182              0x30B6
+#define WM8996_WRITE_SEQUENCER_183              0x30B7
+#define WM8996_WRITE_SEQUENCER_184              0x30B8
+#define WM8996_WRITE_SEQUENCER_185              0x30B9
+#define WM8996_WRITE_SEQUENCER_186              0x30BA
+#define WM8996_WRITE_SEQUENCER_187              0x30BB
+#define WM8996_WRITE_SEQUENCER_188              0x30BC
+#define WM8996_WRITE_SEQUENCER_189              0x30BD
+#define WM8996_WRITE_SEQUENCER_190              0x30BE
+#define WM8996_WRITE_SEQUENCER_191              0x30BF
+#define WM8996_WRITE_SEQUENCER_192              0x30C0
+#define WM8996_WRITE_SEQUENCER_193              0x30C1
+#define WM8996_WRITE_SEQUENCER_194              0x30C2
+#define WM8996_WRITE_SEQUENCER_195              0x30C3
+#define WM8996_WRITE_SEQUENCER_196              0x30C4
+#define WM8996_WRITE_SEQUENCER_197              0x30C5
+#define WM8996_WRITE_SEQUENCER_198              0x30C6
+#define WM8996_WRITE_SEQUENCER_199              0x30C7
+#define WM8996_WRITE_SEQUENCER_200              0x30C8
+#define WM8996_WRITE_SEQUENCER_201              0x30C9
+#define WM8996_WRITE_SEQUENCER_202              0x30CA
+#define WM8996_WRITE_SEQUENCER_203              0x30CB
+#define WM8996_WRITE_SEQUENCER_204              0x30CC
+#define WM8996_WRITE_SEQUENCER_205              0x30CD
+#define WM8996_WRITE_SEQUENCER_206              0x30CE
+#define WM8996_WRITE_SEQUENCER_207              0x30CF
+#define WM8996_WRITE_SEQUENCER_208              0x30D0
+#define WM8996_WRITE_SEQUENCER_209              0x30D1
+#define WM8996_WRITE_SEQUENCER_210              0x30D2
+#define WM8996_WRITE_SEQUENCER_211              0x30D3
+#define WM8996_WRITE_SEQUENCER_212              0x30D4
+#define WM8996_WRITE_SEQUENCER_213              0x30D5
+#define WM8996_WRITE_SEQUENCER_214              0x30D6
+#define WM8996_WRITE_SEQUENCER_215              0x30D7
+#define WM8996_WRITE_SEQUENCER_216              0x30D8
+#define WM8996_WRITE_SEQUENCER_217              0x30D9
+#define WM8996_WRITE_SEQUENCER_218              0x30DA
+#define WM8996_WRITE_SEQUENCER_219              0x30DB
+#define WM8996_WRITE_SEQUENCER_220              0x30DC
+#define WM8996_WRITE_SEQUENCER_221              0x30DD
+#define WM8996_WRITE_SEQUENCER_222              0x30DE
+#define WM8996_WRITE_SEQUENCER_223              0x30DF
+#define WM8996_WRITE_SEQUENCER_224              0x30E0
+#define WM8996_WRITE_SEQUENCER_225              0x30E1
+#define WM8996_WRITE_SEQUENCER_226              0x30E2
+#define WM8996_WRITE_SEQUENCER_227              0x30E3
+#define WM8996_WRITE_SEQUENCER_228              0x30E4
+#define WM8996_WRITE_SEQUENCER_229              0x30E5
+#define WM8996_WRITE_SEQUENCER_230              0x30E6
+#define WM8996_WRITE_SEQUENCER_231              0x30E7
+#define WM8996_WRITE_SEQUENCER_232              0x30E8
+#define WM8996_WRITE_SEQUENCER_233              0x30E9
+#define WM8996_WRITE_SEQUENCER_234              0x30EA
+#define WM8996_WRITE_SEQUENCER_235              0x30EB
+#define WM8996_WRITE_SEQUENCER_236              0x30EC
+#define WM8996_WRITE_SEQUENCER_237              0x30ED
+#define WM8996_WRITE_SEQUENCER_238              0x30EE
+#define WM8996_WRITE_SEQUENCER_239              0x30EF
+#define WM8996_WRITE_SEQUENCER_240              0x30F0
+#define WM8996_WRITE_SEQUENCER_241              0x30F1
+#define WM8996_WRITE_SEQUENCER_242              0x30F2
+#define WM8996_WRITE_SEQUENCER_243              0x30F3
+#define WM8996_WRITE_SEQUENCER_244              0x30F4
+#define WM8996_WRITE_SEQUENCER_245              0x30F5
+#define WM8996_WRITE_SEQUENCER_246              0x30F6
+#define WM8996_WRITE_SEQUENCER_247              0x30F7
+#define WM8996_WRITE_SEQUENCER_248              0x30F8
+#define WM8996_WRITE_SEQUENCER_249              0x30F9
+#define WM8996_WRITE_SEQUENCER_250              0x30FA
+#define WM8996_WRITE_SEQUENCER_251              0x30FB
+#define WM8996_WRITE_SEQUENCER_252              0x30FC
+#define WM8996_WRITE_SEQUENCER_253              0x30FD
+#define WM8996_WRITE_SEQUENCER_254              0x30FE
+#define WM8996_WRITE_SEQUENCER_255              0x30FF
+#define WM8996_WRITE_SEQUENCER_256              0x3100
+#define WM8996_WRITE_SEQUENCER_257              0x3101
+#define WM8996_WRITE_SEQUENCER_258              0x3102
+#define WM8996_WRITE_SEQUENCER_259              0x3103
+#define WM8996_WRITE_SEQUENCER_260              0x3104
+#define WM8996_WRITE_SEQUENCER_261              0x3105
+#define WM8996_WRITE_SEQUENCER_262              0x3106
+#define WM8996_WRITE_SEQUENCER_263              0x3107
+#define WM8996_WRITE_SEQUENCER_264              0x3108
+#define WM8996_WRITE_SEQUENCER_265              0x3109
+#define WM8996_WRITE_SEQUENCER_266              0x310A
+#define WM8996_WRITE_SEQUENCER_267              0x310B
+#define WM8996_WRITE_SEQUENCER_268              0x310C
+#define WM8996_WRITE_SEQUENCER_269              0x310D
+#define WM8996_WRITE_SEQUENCER_270              0x310E
+#define WM8996_WRITE_SEQUENCER_271              0x310F
+#define WM8996_WRITE_SEQUENCER_272              0x3110
+#define WM8996_WRITE_SEQUENCER_273              0x3111
+#define WM8996_WRITE_SEQUENCER_274              0x3112
+#define WM8996_WRITE_SEQUENCER_275              0x3113
+#define WM8996_WRITE_SEQUENCER_276              0x3114
+#define WM8996_WRITE_SEQUENCER_277              0x3115
+#define WM8996_WRITE_SEQUENCER_278              0x3116
+#define WM8996_WRITE_SEQUENCER_279              0x3117
+#define WM8996_WRITE_SEQUENCER_280              0x3118
+#define WM8996_WRITE_SEQUENCER_281              0x3119
+#define WM8996_WRITE_SEQUENCER_282              0x311A
+#define WM8996_WRITE_SEQUENCER_283              0x311B
+#define WM8996_WRITE_SEQUENCER_284              0x311C
+#define WM8996_WRITE_SEQUENCER_285              0x311D
+#define WM8996_WRITE_SEQUENCER_286              0x311E
+#define WM8996_WRITE_SEQUENCER_287              0x311F
+#define WM8996_WRITE_SEQUENCER_288              0x3120
+#define WM8996_WRITE_SEQUENCER_289              0x3121
+#define WM8996_WRITE_SEQUENCER_290              0x3122
+#define WM8996_WRITE_SEQUENCER_291              0x3123
+#define WM8996_WRITE_SEQUENCER_292              0x3124
+#define WM8996_WRITE_SEQUENCER_293              0x3125
+#define WM8996_WRITE_SEQUENCER_294              0x3126
+#define WM8996_WRITE_SEQUENCER_295              0x3127
+#define WM8996_WRITE_SEQUENCER_296              0x3128
+#define WM8996_WRITE_SEQUENCER_297              0x3129
+#define WM8996_WRITE_SEQUENCER_298              0x312A
+#define WM8996_WRITE_SEQUENCER_299              0x312B
+#define WM8996_WRITE_SEQUENCER_300              0x312C
+#define WM8996_WRITE_SEQUENCER_301              0x312D
+#define WM8996_WRITE_SEQUENCER_302              0x312E
+#define WM8996_WRITE_SEQUENCER_303              0x312F
+#define WM8996_WRITE_SEQUENCER_304              0x3130
+#define WM8996_WRITE_SEQUENCER_305              0x3131
+#define WM8996_WRITE_SEQUENCER_306              0x3132
+#define WM8996_WRITE_SEQUENCER_307              0x3133
+#define WM8996_WRITE_SEQUENCER_308              0x3134
+#define WM8996_WRITE_SEQUENCER_309              0x3135
+#define WM8996_WRITE_SEQUENCER_310              0x3136
+#define WM8996_WRITE_SEQUENCER_311              0x3137
+#define WM8996_WRITE_SEQUENCER_312              0x3138
+#define WM8996_WRITE_SEQUENCER_313              0x3139
+#define WM8996_WRITE_SEQUENCER_314              0x313A
+#define WM8996_WRITE_SEQUENCER_315              0x313B
+#define WM8996_WRITE_SEQUENCER_316              0x313C
+#define WM8996_WRITE_SEQUENCER_317              0x313D
+#define WM8996_WRITE_SEQUENCER_318              0x313E
+#define WM8996_WRITE_SEQUENCER_319              0x313F
+#define WM8996_WRITE_SEQUENCER_320              0x3140
+#define WM8996_WRITE_SEQUENCER_321              0x3141
+#define WM8996_WRITE_SEQUENCER_322              0x3142
+#define WM8996_WRITE_SEQUENCER_323              0x3143
+#define WM8996_WRITE_SEQUENCER_324              0x3144
+#define WM8996_WRITE_SEQUENCER_325              0x3145
+#define WM8996_WRITE_SEQUENCER_326              0x3146
+#define WM8996_WRITE_SEQUENCER_327              0x3147
+#define WM8996_WRITE_SEQUENCER_328              0x3148
+#define WM8996_WRITE_SEQUENCER_329              0x3149
+#define WM8996_WRITE_SEQUENCER_330              0x314A
+#define WM8996_WRITE_SEQUENCER_331              0x314B
+#define WM8996_WRITE_SEQUENCER_332              0x314C
+#define WM8996_WRITE_SEQUENCER_333              0x314D
+#define WM8996_WRITE_SEQUENCER_334              0x314E
+#define WM8996_WRITE_SEQUENCER_335              0x314F
+#define WM8996_WRITE_SEQUENCER_336              0x3150
+#define WM8996_WRITE_SEQUENCER_337              0x3151
+#define WM8996_WRITE_SEQUENCER_338              0x3152
+#define WM8996_WRITE_SEQUENCER_339              0x3153
+#define WM8996_WRITE_SEQUENCER_340              0x3154
+#define WM8996_WRITE_SEQUENCER_341              0x3155
+#define WM8996_WRITE_SEQUENCER_342              0x3156
+#define WM8996_WRITE_SEQUENCER_343              0x3157
+#define WM8996_WRITE_SEQUENCER_344              0x3158
+#define WM8996_WRITE_SEQUENCER_345              0x3159
+#define WM8996_WRITE_SEQUENCER_346              0x315A
+#define WM8996_WRITE_SEQUENCER_347              0x315B
+#define WM8996_WRITE_SEQUENCER_348              0x315C
+#define WM8996_WRITE_SEQUENCER_349              0x315D
+#define WM8996_WRITE_SEQUENCER_350              0x315E
+#define WM8996_WRITE_SEQUENCER_351              0x315F
+#define WM8996_WRITE_SEQUENCER_352              0x3160
+#define WM8996_WRITE_SEQUENCER_353              0x3161
+#define WM8996_WRITE_SEQUENCER_354              0x3162
+#define WM8996_WRITE_SEQUENCER_355              0x3163
+#define WM8996_WRITE_SEQUENCER_356              0x3164
+#define WM8996_WRITE_SEQUENCER_357              0x3165
+#define WM8996_WRITE_SEQUENCER_358              0x3166
+#define WM8996_WRITE_SEQUENCER_359              0x3167
+#define WM8996_WRITE_SEQUENCER_360              0x3168
+#define WM8996_WRITE_SEQUENCER_361              0x3169
+#define WM8996_WRITE_SEQUENCER_362              0x316A
+#define WM8996_WRITE_SEQUENCER_363              0x316B
+#define WM8996_WRITE_SEQUENCER_364              0x316C
+#define WM8996_WRITE_SEQUENCER_365              0x316D
+#define WM8996_WRITE_SEQUENCER_366              0x316E
+#define WM8996_WRITE_SEQUENCER_367              0x316F
+#define WM8996_WRITE_SEQUENCER_368              0x3170
+#define WM8996_WRITE_SEQUENCER_369              0x3171
+#define WM8996_WRITE_SEQUENCER_370              0x3172
+#define WM8996_WRITE_SEQUENCER_371              0x3173
+#define WM8996_WRITE_SEQUENCER_372              0x3174
+#define WM8996_WRITE_SEQUENCER_373              0x3175
+#define WM8996_WRITE_SEQUENCER_374              0x3176
+#define WM8996_WRITE_SEQUENCER_375              0x3177
+#define WM8996_WRITE_SEQUENCER_376              0x3178
+#define WM8996_WRITE_SEQUENCER_377              0x3179
+#define WM8996_WRITE_SEQUENCER_378              0x317A
+#define WM8996_WRITE_SEQUENCER_379              0x317B
+#define WM8996_WRITE_SEQUENCER_380              0x317C
+#define WM8996_WRITE_SEQUENCER_381              0x317D
+#define WM8996_WRITE_SEQUENCER_382              0x317E
+#define WM8996_WRITE_SEQUENCER_383              0x317F
+#define WM8996_WRITE_SEQUENCER_384              0x3180
+#define WM8996_WRITE_SEQUENCER_385              0x3181
+#define WM8996_WRITE_SEQUENCER_386              0x3182
+#define WM8996_WRITE_SEQUENCER_387              0x3183
+#define WM8996_WRITE_SEQUENCER_388              0x3184
+#define WM8996_WRITE_SEQUENCER_389              0x3185
+#define WM8996_WRITE_SEQUENCER_390              0x3186
+#define WM8996_WRITE_SEQUENCER_391              0x3187
+#define WM8996_WRITE_SEQUENCER_392              0x3188
+#define WM8996_WRITE_SEQUENCER_393              0x3189
+#define WM8996_WRITE_SEQUENCER_394              0x318A
+#define WM8996_WRITE_SEQUENCER_395              0x318B
+#define WM8996_WRITE_SEQUENCER_396              0x318C
+#define WM8996_WRITE_SEQUENCER_397              0x318D
+#define WM8996_WRITE_SEQUENCER_398              0x318E
+#define WM8996_WRITE_SEQUENCER_399              0x318F
+#define WM8996_WRITE_SEQUENCER_400              0x3190
+#define WM8996_WRITE_SEQUENCER_401              0x3191
+#define WM8996_WRITE_SEQUENCER_402              0x3192
+#define WM8996_WRITE_SEQUENCER_403              0x3193
+#define WM8996_WRITE_SEQUENCER_404              0x3194
+#define WM8996_WRITE_SEQUENCER_405              0x3195
+#define WM8996_WRITE_SEQUENCER_406              0x3196
+#define WM8996_WRITE_SEQUENCER_407              0x3197
+#define WM8996_WRITE_SEQUENCER_408              0x3198
+#define WM8996_WRITE_SEQUENCER_409              0x3199
+#define WM8996_WRITE_SEQUENCER_410              0x319A
+#define WM8996_WRITE_SEQUENCER_411              0x319B
+#define WM8996_WRITE_SEQUENCER_412              0x319C
+#define WM8996_WRITE_SEQUENCER_413              0x319D
+#define WM8996_WRITE_SEQUENCER_414              0x319E
+#define WM8996_WRITE_SEQUENCER_415              0x319F
+#define WM8996_WRITE_SEQUENCER_416              0x31A0
+#define WM8996_WRITE_SEQUENCER_417              0x31A1
+#define WM8996_WRITE_SEQUENCER_418              0x31A2
+#define WM8996_WRITE_SEQUENCER_419              0x31A3
+#define WM8996_WRITE_SEQUENCER_420              0x31A4
+#define WM8996_WRITE_SEQUENCER_421              0x31A5
+#define WM8996_WRITE_SEQUENCER_422              0x31A6
+#define WM8996_WRITE_SEQUENCER_423              0x31A7
+#define WM8996_WRITE_SEQUENCER_424              0x31A8
+#define WM8996_WRITE_SEQUENCER_425              0x31A9
+#define WM8996_WRITE_SEQUENCER_426              0x31AA
+#define WM8996_WRITE_SEQUENCER_427              0x31AB
+#define WM8996_WRITE_SEQUENCER_428              0x31AC
+#define WM8996_WRITE_SEQUENCER_429              0x31AD
+#define WM8996_WRITE_SEQUENCER_430              0x31AE
+#define WM8996_WRITE_SEQUENCER_431              0x31AF
+#define WM8996_WRITE_SEQUENCER_432              0x31B0
+#define WM8996_WRITE_SEQUENCER_433              0x31B1
+#define WM8996_WRITE_SEQUENCER_434              0x31B2
+#define WM8996_WRITE_SEQUENCER_435              0x31B3
+#define WM8996_WRITE_SEQUENCER_436              0x31B4
+#define WM8996_WRITE_SEQUENCER_437              0x31B5
+#define WM8996_WRITE_SEQUENCER_438              0x31B6
+#define WM8996_WRITE_SEQUENCER_439              0x31B7
+#define WM8996_WRITE_SEQUENCER_440              0x31B8
+#define WM8996_WRITE_SEQUENCER_441              0x31B9
+#define WM8996_WRITE_SEQUENCER_442              0x31BA
+#define WM8996_WRITE_SEQUENCER_443              0x31BB
+#define WM8996_WRITE_SEQUENCER_444              0x31BC
+#define WM8996_WRITE_SEQUENCER_445              0x31BD
+#define WM8996_WRITE_SEQUENCER_446              0x31BE
+#define WM8996_WRITE_SEQUENCER_447              0x31BF
+#define WM8996_WRITE_SEQUENCER_448              0x31C0
+#define WM8996_WRITE_SEQUENCER_449              0x31C1
+#define WM8996_WRITE_SEQUENCER_450              0x31C2
+#define WM8996_WRITE_SEQUENCER_451              0x31C3
+#define WM8996_WRITE_SEQUENCER_452              0x31C4
+#define WM8996_WRITE_SEQUENCER_453              0x31C5
+#define WM8996_WRITE_SEQUENCER_454              0x31C6
+#define WM8996_WRITE_SEQUENCER_455              0x31C7
+#define WM8996_WRITE_SEQUENCER_456              0x31C8
+#define WM8996_WRITE_SEQUENCER_457              0x31C9
+#define WM8996_WRITE_SEQUENCER_458              0x31CA
+#define WM8996_WRITE_SEQUENCER_459              0x31CB
+#define WM8996_WRITE_SEQUENCER_460              0x31CC
+#define WM8996_WRITE_SEQUENCER_461              0x31CD
+#define WM8996_WRITE_SEQUENCER_462              0x31CE
+#define WM8996_WRITE_SEQUENCER_463              0x31CF
+#define WM8996_WRITE_SEQUENCER_464              0x31D0
+#define WM8996_WRITE_SEQUENCER_465              0x31D1
+#define WM8996_WRITE_SEQUENCER_466              0x31D2
+#define WM8996_WRITE_SEQUENCER_467              0x31D3
+#define WM8996_WRITE_SEQUENCER_468              0x31D4
+#define WM8996_WRITE_SEQUENCER_469              0x31D5
+#define WM8996_WRITE_SEQUENCER_470              0x31D6
+#define WM8996_WRITE_SEQUENCER_471              0x31D7
+#define WM8996_WRITE_SEQUENCER_472              0x31D8
+#define WM8996_WRITE_SEQUENCER_473              0x31D9
+#define WM8996_WRITE_SEQUENCER_474              0x31DA
+#define WM8996_WRITE_SEQUENCER_475              0x31DB
+#define WM8996_WRITE_SEQUENCER_476              0x31DC
+#define WM8996_WRITE_SEQUENCER_477              0x31DD
+#define WM8996_WRITE_SEQUENCER_478              0x31DE
+#define WM8996_WRITE_SEQUENCER_479              0x31DF
+#define WM8996_WRITE_SEQUENCER_480              0x31E0
+#define WM8996_WRITE_SEQUENCER_481              0x31E1
+#define WM8996_WRITE_SEQUENCER_482              0x31E2
+#define WM8996_WRITE_SEQUENCER_483              0x31E3
+#define WM8996_WRITE_SEQUENCER_484              0x31E4
+#define WM8996_WRITE_SEQUENCER_485              0x31E5
+#define WM8996_WRITE_SEQUENCER_486              0x31E6
+#define WM8996_WRITE_SEQUENCER_487              0x31E7
+#define WM8996_WRITE_SEQUENCER_488              0x31E8
+#define WM8996_WRITE_SEQUENCER_489              0x31E9
+#define WM8996_WRITE_SEQUENCER_490              0x31EA
+#define WM8996_WRITE_SEQUENCER_491              0x31EB
+#define WM8996_WRITE_SEQUENCER_492              0x31EC
+#define WM8996_WRITE_SEQUENCER_493              0x31ED
+#define WM8996_WRITE_SEQUENCER_494              0x31EE
+#define WM8996_WRITE_SEQUENCER_495              0x31EF
+#define WM8996_WRITE_SEQUENCER_496              0x31F0
+#define WM8996_WRITE_SEQUENCER_497              0x31F1
+#define WM8996_WRITE_SEQUENCER_498              0x31F2
+#define WM8996_WRITE_SEQUENCER_499              0x31F3
+#define WM8996_WRITE_SEQUENCER_500              0x31F4
+#define WM8996_WRITE_SEQUENCER_501              0x31F5
+#define WM8996_WRITE_SEQUENCER_502              0x31F6
+#define WM8996_WRITE_SEQUENCER_503              0x31F7
+#define WM8996_WRITE_SEQUENCER_504              0x31F8
+#define WM8996_WRITE_SEQUENCER_505              0x31F9
+#define WM8996_WRITE_SEQUENCER_506              0x31FA
+#define WM8996_WRITE_SEQUENCER_507              0x31FB
+#define WM8996_WRITE_SEQUENCER_508              0x31FC
+#define WM8996_WRITE_SEQUENCER_509              0x31FD
+#define WM8996_WRITE_SEQUENCER_510              0x31FE
+#define WM8996_WRITE_SEQUENCER_511              0x31FF
+
+#define WM8996_REGISTER_COUNT                   706
+#define WM8996_MAX_REGISTER                     0x31FF
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Software Reset
+ */
+#define WM8996_SW_RESET_MASK                    0xFFFF  /* SW_RESET - [15:0] */
+#define WM8996_SW_RESET_SHIFT                        0  /* SW_RESET - [15:0] */
+#define WM8996_SW_RESET_WIDTH                       16  /* SW_RESET - [15:0] */
+
+/*
+ * R1 (0x01) - Power Management (1)
+ */
+#define WM8996_MICB2_ENA                        0x0200  /* MICB2_ENA */
+#define WM8996_MICB2_ENA_MASK                   0x0200  /* MICB2_ENA */
+#define WM8996_MICB2_ENA_SHIFT                       9  /* MICB2_ENA */
+#define WM8996_MICB2_ENA_WIDTH                       1  /* MICB2_ENA */
+#define WM8996_MICB1_ENA                        0x0100  /* MICB1_ENA */
+#define WM8996_MICB1_ENA_MASK                   0x0100  /* MICB1_ENA */
+#define WM8996_MICB1_ENA_SHIFT                       8  /* MICB1_ENA */
+#define WM8996_MICB1_ENA_WIDTH                       1  /* MICB1_ENA */
+#define WM8996_HPOUT2L_ENA                      0x0080  /* HPOUT2L_ENA */
+#define WM8996_HPOUT2L_ENA_MASK                 0x0080  /* HPOUT2L_ENA */
+#define WM8996_HPOUT2L_ENA_SHIFT                     7  /* HPOUT2L_ENA */
+#define WM8996_HPOUT2L_ENA_WIDTH                     1  /* HPOUT2L_ENA */
+#define WM8996_HPOUT2R_ENA                      0x0040  /* HPOUT2R_ENA */
+#define WM8996_HPOUT2R_ENA_MASK                 0x0040  /* HPOUT2R_ENA */
+#define WM8996_HPOUT2R_ENA_SHIFT                     6  /* HPOUT2R_ENA */
+#define WM8996_HPOUT2R_ENA_WIDTH                     1  /* HPOUT2R_ENA */
+#define WM8996_HPOUT1L_ENA                      0x0020  /* HPOUT1L_ENA */
+#define WM8996_HPOUT1L_ENA_MASK                 0x0020  /* HPOUT1L_ENA */
+#define WM8996_HPOUT1L_ENA_SHIFT                     5  /* HPOUT1L_ENA */
+#define WM8996_HPOUT1L_ENA_WIDTH                     1  /* HPOUT1L_ENA */
+#define WM8996_HPOUT1R_ENA                      0x0010  /* HPOUT1R_ENA */
+#define WM8996_HPOUT1R_ENA_MASK                 0x0010  /* HPOUT1R_ENA */
+#define WM8996_HPOUT1R_ENA_SHIFT                     4  /* HPOUT1R_ENA */
+#define WM8996_HPOUT1R_ENA_WIDTH                     1  /* HPOUT1R_ENA */
+#define WM8996_BG_ENA                           0x0001  /* BG_ENA */
+#define WM8996_BG_ENA_MASK                      0x0001  /* BG_ENA */
+#define WM8996_BG_ENA_SHIFT                          0  /* BG_ENA */
+#define WM8996_BG_ENA_WIDTH                          1  /* BG_ENA */
+
+/*
+ * R2 (0x02) - Power Management (2)
+ */
+#define WM8996_OPCLK_ENA                        0x0800  /* OPCLK_ENA */
+#define WM8996_OPCLK_ENA_MASK                   0x0800  /* OPCLK_ENA */
+#define WM8996_OPCLK_ENA_SHIFT                      11  /* OPCLK_ENA */
+#define WM8996_OPCLK_ENA_WIDTH                       1  /* OPCLK_ENA */
+#define WM8996_INL_ENA                          0x0020  /* INL_ENA */
+#define WM8996_INL_ENA_MASK                     0x0020  /* INL_ENA */
+#define WM8996_INL_ENA_SHIFT                         5  /* INL_ENA */
+#define WM8996_INL_ENA_WIDTH                         1  /* INL_ENA */
+#define WM8996_INR_ENA                          0x0010  /* INR_ENA */
+#define WM8996_INR_ENA_MASK                     0x0010  /* INR_ENA */
+#define WM8996_INR_ENA_SHIFT                         4  /* INR_ENA */
+#define WM8996_INR_ENA_WIDTH                         1  /* INR_ENA */
+#define WM8996_LDO2_ENA                         0x0002  /* LDO2_ENA */
+#define WM8996_LDO2_ENA_MASK                    0x0002  /* LDO2_ENA */
+#define WM8996_LDO2_ENA_SHIFT                        1  /* LDO2_ENA */
+#define WM8996_LDO2_ENA_WIDTH                        1  /* LDO2_ENA */
+
+/*
+ * R3 (0x03) - Power Management (3)
+ */
+#define WM8996_DSP2RXL_ENA                      0x0800  /* DSP2RXL_ENA */
+#define WM8996_DSP2RXL_ENA_MASK                 0x0800  /* DSP2RXL_ENA */
+#define WM8996_DSP2RXL_ENA_SHIFT                    11  /* DSP2RXL_ENA */
+#define WM8996_DSP2RXL_ENA_WIDTH                     1  /* DSP2RXL_ENA */
+#define WM8996_DSP2RXR_ENA                      0x0400  /* DSP2RXR_ENA */
+#define WM8996_DSP2RXR_ENA_MASK                 0x0400  /* DSP2RXR_ENA */
+#define WM8996_DSP2RXR_ENA_SHIFT                    10  /* DSP2RXR_ENA */
+#define WM8996_DSP2RXR_ENA_WIDTH                     1  /* DSP2RXR_ENA */
+#define WM8996_DSP1RXL_ENA                      0x0200  /* DSP1RXL_ENA */
+#define WM8996_DSP1RXL_ENA_MASK                 0x0200  /* DSP1RXL_ENA */
+#define WM8996_DSP1RXL_ENA_SHIFT                     9  /* DSP1RXL_ENA */
+#define WM8996_DSP1RXL_ENA_WIDTH                     1  /* DSP1RXL_ENA */
+#define WM8996_DSP1RXR_ENA                      0x0100  /* DSP1RXR_ENA */
+#define WM8996_DSP1RXR_ENA_MASK                 0x0100  /* DSP1RXR_ENA */
+#define WM8996_DSP1RXR_ENA_SHIFT                     8  /* DSP1RXR_ENA */
+#define WM8996_DSP1RXR_ENA_WIDTH                     1  /* DSP1RXR_ENA */
+#define WM8996_DMIC2L_ENA                       0x0020  /* DMIC2L_ENA */
+#define WM8996_DMIC2L_ENA_MASK                  0x0020  /* DMIC2L_ENA */
+#define WM8996_DMIC2L_ENA_SHIFT                      5  /* DMIC2L_ENA */
+#define WM8996_DMIC2L_ENA_WIDTH                      1  /* DMIC2L_ENA */
+#define WM8996_DMIC2R_ENA                       0x0010  /* DMIC2R_ENA */
+#define WM8996_DMIC2R_ENA_MASK                  0x0010  /* DMIC2R_ENA */
+#define WM8996_DMIC2R_ENA_SHIFT                      4  /* DMIC2R_ENA */
+#define WM8996_DMIC2R_ENA_WIDTH                      1  /* DMIC2R_ENA */
+#define WM8996_DMIC1L_ENA                       0x0008  /* DMIC1L_ENA */
+#define WM8996_DMIC1L_ENA_MASK                  0x0008  /* DMIC1L_ENA */
+#define WM8996_DMIC1L_ENA_SHIFT                      3  /* DMIC1L_ENA */
+#define WM8996_DMIC1L_ENA_WIDTH                      1  /* DMIC1L_ENA */
+#define WM8996_DMIC1R_ENA                       0x0004  /* DMIC1R_ENA */
+#define WM8996_DMIC1R_ENA_MASK                  0x0004  /* DMIC1R_ENA */
+#define WM8996_DMIC1R_ENA_SHIFT                      2  /* DMIC1R_ENA */
+#define WM8996_DMIC1R_ENA_WIDTH                      1  /* DMIC1R_ENA */
+#define WM8996_ADCL_ENA                         0x0002  /* ADCL_ENA */
+#define WM8996_ADCL_ENA_MASK                    0x0002  /* ADCL_ENA */
+#define WM8996_ADCL_ENA_SHIFT                        1  /* ADCL_ENA */
+#define WM8996_ADCL_ENA_WIDTH                        1  /* ADCL_ENA */
+#define WM8996_ADCR_ENA                         0x0001  /* ADCR_ENA */
+#define WM8996_ADCR_ENA_MASK                    0x0001  /* ADCR_ENA */
+#define WM8996_ADCR_ENA_SHIFT                        0  /* ADCR_ENA */
+#define WM8996_ADCR_ENA_WIDTH                        1  /* ADCR_ENA */
+
+/*
+ * R4 (0x04) - Power Management (4)
+ */
+#define WM8996_AIF2RX_CHAN1_ENA                 0x0200  /* AIF2RX_CHAN1_ENA */
+#define WM8996_AIF2RX_CHAN1_ENA_MASK            0x0200  /* AIF2RX_CHAN1_ENA */
+#define WM8996_AIF2RX_CHAN1_ENA_SHIFT                9  /* AIF2RX_CHAN1_ENA */
+#define WM8996_AIF2RX_CHAN1_ENA_WIDTH                1  /* AIF2RX_CHAN1_ENA */
+#define WM8996_AIF2RX_CHAN0_ENA                 0x0100  /* AIF2RX_CHAN0_ENA */
+#define WM8996_AIF2RX_CHAN0_ENA_MASK            0x0100  /* AIF2RX_CHAN0_ENA */
+#define WM8996_AIF2RX_CHAN0_ENA_SHIFT                8  /* AIF2RX_CHAN0_ENA */
+#define WM8996_AIF2RX_CHAN0_ENA_WIDTH                1  /* AIF2RX_CHAN0_ENA */
+#define WM8996_AIF1RX_CHAN5_ENA                 0x0020  /* AIF1RX_CHAN5_ENA */
+#define WM8996_AIF1RX_CHAN5_ENA_MASK            0x0020  /* AIF1RX_CHAN5_ENA */
+#define WM8996_AIF1RX_CHAN5_ENA_SHIFT                5  /* AIF1RX_CHAN5_ENA */
+#define WM8996_AIF1RX_CHAN5_ENA_WIDTH                1  /* AIF1RX_CHAN5_ENA */
+#define WM8996_AIF1RX_CHAN4_ENA                 0x0010  /* AIF1RX_CHAN4_ENA */
+#define WM8996_AIF1RX_CHAN4_ENA_MASK            0x0010  /* AIF1RX_CHAN4_ENA */
+#define WM8996_AIF1RX_CHAN4_ENA_SHIFT                4  /* AIF1RX_CHAN4_ENA */
+#define WM8996_AIF1RX_CHAN4_ENA_WIDTH                1  /* AIF1RX_CHAN4_ENA */
+#define WM8996_AIF1RX_CHAN3_ENA                 0x0008  /* AIF1RX_CHAN3_ENA */
+#define WM8996_AIF1RX_CHAN3_ENA_MASK            0x0008  /* AIF1RX_CHAN3_ENA */
+#define WM8996_AIF1RX_CHAN3_ENA_SHIFT                3  /* AIF1RX_CHAN3_ENA */
+#define WM8996_AIF1RX_CHAN3_ENA_WIDTH                1  /* AIF1RX_CHAN3_ENA */
+#define WM8996_AIF1RX_CHAN2_ENA                 0x0004  /* AIF1RX_CHAN2_ENA */
+#define WM8996_AIF1RX_CHAN2_ENA_MASK            0x0004  /* AIF1RX_CHAN2_ENA */
+#define WM8996_AIF1RX_CHAN2_ENA_SHIFT                2  /* AIF1RX_CHAN2_ENA */
+#define WM8996_AIF1RX_CHAN2_ENA_WIDTH                1  /* AIF1RX_CHAN2_ENA */
+#define WM8996_AIF1RX_CHAN1_ENA                 0x0002  /* AIF1RX_CHAN1_ENA */
+#define WM8996_AIF1RX_CHAN1_ENA_MASK            0x0002  /* AIF1RX_CHAN1_ENA */
+#define WM8996_AIF1RX_CHAN1_ENA_SHIFT                1  /* AIF1RX_CHAN1_ENA */
+#define WM8996_AIF1RX_CHAN1_ENA_WIDTH                1  /* AIF1RX_CHAN1_ENA */
+#define WM8996_AIF1RX_CHAN0_ENA                 0x0001  /* AIF1RX_CHAN0_ENA */
+#define WM8996_AIF1RX_CHAN0_ENA_MASK            0x0001  /* AIF1RX_CHAN0_ENA */
+#define WM8996_AIF1RX_CHAN0_ENA_SHIFT                0  /* AIF1RX_CHAN0_ENA */
+#define WM8996_AIF1RX_CHAN0_ENA_WIDTH                1  /* AIF1RX_CHAN0_ENA */
+
+/*
+ * R5 (0x05) - Power Management (5)
+ */
+#define WM8996_DSP2TXL_ENA                      0x0800  /* DSP2TXL_ENA */
+#define WM8996_DSP2TXL_ENA_MASK                 0x0800  /* DSP2TXL_ENA */
+#define WM8996_DSP2TXL_ENA_SHIFT                    11  /* DSP2TXL_ENA */
+#define WM8996_DSP2TXL_ENA_WIDTH                     1  /* DSP2TXL_ENA */
+#define WM8996_DSP2TXR_ENA                      0x0400  /* DSP2TXR_ENA */
+#define WM8996_DSP2TXR_ENA_MASK                 0x0400  /* DSP2TXR_ENA */
+#define WM8996_DSP2TXR_ENA_SHIFT                    10  /* DSP2TXR_ENA */
+#define WM8996_DSP2TXR_ENA_WIDTH                     1  /* DSP2TXR_ENA */
+#define WM8996_DSP1TXL_ENA                      0x0200  /* DSP1TXL_ENA */
+#define WM8996_DSP1TXL_ENA_MASK                 0x0200  /* DSP1TXL_ENA */
+#define WM8996_DSP1TXL_ENA_SHIFT                     9  /* DSP1TXL_ENA */
+#define WM8996_DSP1TXL_ENA_WIDTH                     1  /* DSP1TXL_ENA */
+#define WM8996_DSP1TXR_ENA                      0x0100  /* DSP1TXR_ENA */
+#define WM8996_DSP1TXR_ENA_MASK                 0x0100  /* DSP1TXR_ENA */
+#define WM8996_DSP1TXR_ENA_SHIFT                     8  /* DSP1TXR_ENA */
+#define WM8996_DSP1TXR_ENA_WIDTH                     1  /* DSP1TXR_ENA */
+#define WM8996_DAC2L_ENA                        0x0008  /* DAC2L_ENA */
+#define WM8996_DAC2L_ENA_MASK                   0x0008  /* DAC2L_ENA */
+#define WM8996_DAC2L_ENA_SHIFT                       3  /* DAC2L_ENA */
+#define WM8996_DAC2L_ENA_WIDTH                       1  /* DAC2L_ENA */
+#define WM8996_DAC2R_ENA                        0x0004  /* DAC2R_ENA */
+#define WM8996_DAC2R_ENA_MASK                   0x0004  /* DAC2R_ENA */
+#define WM8996_DAC2R_ENA_SHIFT                       2  /* DAC2R_ENA */
+#define WM8996_DAC2R_ENA_WIDTH                       1  /* DAC2R_ENA */
+#define WM8996_DAC1L_ENA                        0x0002  /* DAC1L_ENA */
+#define WM8996_DAC1L_ENA_MASK                   0x0002  /* DAC1L_ENA */
+#define WM8996_DAC1L_ENA_SHIFT                       1  /* DAC1L_ENA */
+#define WM8996_DAC1L_ENA_WIDTH                       1  /* DAC1L_ENA */
+#define WM8996_DAC1R_ENA                        0x0001  /* DAC1R_ENA */
+#define WM8996_DAC1R_ENA_MASK                   0x0001  /* DAC1R_ENA */
+#define WM8996_DAC1R_ENA_SHIFT                       0  /* DAC1R_ENA */
+#define WM8996_DAC1R_ENA_WIDTH                       1  /* DAC1R_ENA */
+
+/*
+ * R6 (0x06) - Power Management (6)
+ */
+#define WM8996_AIF2TX_CHAN1_ENA                 0x0200  /* AIF2TX_CHAN1_ENA */
+#define WM8996_AIF2TX_CHAN1_ENA_MASK            0x0200  /* AIF2TX_CHAN1_ENA */
+#define WM8996_AIF2TX_CHAN1_ENA_SHIFT                9  /* AIF2TX_CHAN1_ENA */
+#define WM8996_AIF2TX_CHAN1_ENA_WIDTH                1  /* AIF2TX_CHAN1_ENA */
+#define WM8996_AIF2TX_CHAN0_ENA                 0x0100  /* AIF2TX_CHAN0_ENA */
+#define WM8996_AIF2TX_CHAN0_ENA_MASK            0x0100  /* AIF2TX_CHAN0_ENA */
+#define WM8996_AIF2TX_CHAN0_ENA_SHIFT                8  /* AIF2TX_CHAN0_ENA */
+#define WM8996_AIF2TX_CHAN0_ENA_WIDTH                1  /* AIF2TX_CHAN0_ENA */
+#define WM8996_AIF1TX_CHAN5_ENA                 0x0020  /* AIF1TX_CHAN5_ENA */
+#define WM8996_AIF1TX_CHAN5_ENA_MASK            0x0020  /* AIF1TX_CHAN5_ENA */
+#define WM8996_AIF1TX_CHAN5_ENA_SHIFT                5  /* AIF1TX_CHAN5_ENA */
+#define WM8996_AIF1TX_CHAN5_ENA_WIDTH                1  /* AIF1TX_CHAN5_ENA */
+#define WM8996_AIF1TX_CHAN4_ENA                 0x0010  /* AIF1TX_CHAN4_ENA */
+#define WM8996_AIF1TX_CHAN4_ENA_MASK            0x0010  /* AIF1TX_CHAN4_ENA */
+#define WM8996_AIF1TX_CHAN4_ENA_SHIFT                4  /* AIF1TX_CHAN4_ENA */
+#define WM8996_AIF1TX_CHAN4_ENA_WIDTH                1  /* AIF1TX_CHAN4_ENA */
+#define WM8996_AIF1TX_CHAN3_ENA                 0x0008  /* AIF1TX_CHAN3_ENA */
+#define WM8996_AIF1TX_CHAN3_ENA_MASK            0x0008  /* AIF1TX_CHAN3_ENA */
+#define WM8996_AIF1TX_CHAN3_ENA_SHIFT                3  /* AIF1TX_CHAN3_ENA */
+#define WM8996_AIF1TX_CHAN3_ENA_WIDTH                1  /* AIF1TX_CHAN3_ENA */
+#define WM8996_AIF1TX_CHAN2_ENA                 0x0004  /* AIF1TX_CHAN2_ENA */
+#define WM8996_AIF1TX_CHAN2_ENA_MASK            0x0004  /* AIF1TX_CHAN2_ENA */
+#define WM8996_AIF1TX_CHAN2_ENA_SHIFT                2  /* AIF1TX_CHAN2_ENA */
+#define WM8996_AIF1TX_CHAN2_ENA_WIDTH                1  /* AIF1TX_CHAN2_ENA */
+#define WM8996_AIF1TX_CHAN1_ENA                 0x0002  /* AIF1TX_CHAN1_ENA */
+#define WM8996_AIF1TX_CHAN1_ENA_MASK            0x0002  /* AIF1TX_CHAN1_ENA */
+#define WM8996_AIF1TX_CHAN1_ENA_SHIFT                1  /* AIF1TX_CHAN1_ENA */
+#define WM8996_AIF1TX_CHAN1_ENA_WIDTH                1  /* AIF1TX_CHAN1_ENA */
+#define WM8996_AIF1TX_CHAN0_ENA                 0x0001  /* AIF1TX_CHAN0_ENA */
+#define WM8996_AIF1TX_CHAN0_ENA_MASK            0x0001  /* AIF1TX_CHAN0_ENA */
+#define WM8996_AIF1TX_CHAN0_ENA_SHIFT                0  /* AIF1TX_CHAN0_ENA */
+#define WM8996_AIF1TX_CHAN0_ENA_WIDTH                1  /* AIF1TX_CHAN0_ENA */
+
+/*
+ * R7 (0x07) - Power Management (7)
+ */
+#define WM8996_DMIC2_FN                         0x0200  /* DMIC2_FN */
+#define WM8996_DMIC2_FN_MASK                    0x0200  /* DMIC2_FN */
+#define WM8996_DMIC2_FN_SHIFT                        9  /* DMIC2_FN */
+#define WM8996_DMIC2_FN_WIDTH                        1  /* DMIC2_FN */
+#define WM8996_DMIC1_FN                         0x0100  /* DMIC1_FN */
+#define WM8996_DMIC1_FN_MASK                    0x0100  /* DMIC1_FN */
+#define WM8996_DMIC1_FN_SHIFT                        8  /* DMIC1_FN */
+#define WM8996_DMIC1_FN_WIDTH                        1  /* DMIC1_FN */
+#define WM8996_ADC_DMIC_DSP2R_ENA               0x0080  /* ADC_DMIC_DSP2R_ENA */
+#define WM8996_ADC_DMIC_DSP2R_ENA_MASK          0x0080  /* ADC_DMIC_DSP2R_ENA */
+#define WM8996_ADC_DMIC_DSP2R_ENA_SHIFT              7  /* ADC_DMIC_DSP2R_ENA */
+#define WM8996_ADC_DMIC_DSP2R_ENA_WIDTH              1  /* ADC_DMIC_DSP2R_ENA */
+#define WM8996_ADC_DMIC_DSP2L_ENA               0x0040  /* ADC_DMIC_DSP2L_ENA */
+#define WM8996_ADC_DMIC_DSP2L_ENA_MASK          0x0040  /* ADC_DMIC_DSP2L_ENA */
+#define WM8996_ADC_DMIC_DSP2L_ENA_SHIFT              6  /* ADC_DMIC_DSP2L_ENA */
+#define WM8996_ADC_DMIC_DSP2L_ENA_WIDTH              1  /* ADC_DMIC_DSP2L_ENA */
+#define WM8996_ADC_DMIC_SRC2_MASK               0x0030  /* ADC_DMIC_SRC2 - [5:4] */
+#define WM8996_ADC_DMIC_SRC2_SHIFT                   4  /* ADC_DMIC_SRC2 - [5:4] */
+#define WM8996_ADC_DMIC_SRC2_WIDTH                   2  /* ADC_DMIC_SRC2 - [5:4] */
+#define WM8996_ADC_DMIC_DSP1R_ENA               0x0008  /* ADC_DMIC_DSP1R_ENA */
+#define WM8996_ADC_DMIC_DSP1R_ENA_MASK          0x0008  /* ADC_DMIC_DSP1R_ENA */
+#define WM8996_ADC_DMIC_DSP1R_ENA_SHIFT              3  /* ADC_DMIC_DSP1R_ENA */
+#define WM8996_ADC_DMIC_DSP1R_ENA_WIDTH              1  /* ADC_DMIC_DSP1R_ENA */
+#define WM8996_ADC_DMIC_DSP1L_ENA               0x0004  /* ADC_DMIC_DSP1L_ENA */
+#define WM8996_ADC_DMIC_DSP1L_ENA_MASK          0x0004  /* ADC_DMIC_DSP1L_ENA */
+#define WM8996_ADC_DMIC_DSP1L_ENA_SHIFT              2  /* ADC_DMIC_DSP1L_ENA */
+#define WM8996_ADC_DMIC_DSP1L_ENA_WIDTH              1  /* ADC_DMIC_DSP1L_ENA */
+#define WM8996_ADC_DMIC_SRC1_MASK               0x0003  /* ADC_DMIC_SRC1 - [1:0] */
+#define WM8996_ADC_DMIC_SRC1_SHIFT                   0  /* ADC_DMIC_SRC1 - [1:0] */
+#define WM8996_ADC_DMIC_SRC1_WIDTH                   2  /* ADC_DMIC_SRC1 - [1:0] */
+
+/*
+ * R8 (0x08) - Power Management (8)
+ */
+#define WM8996_AIF2TX_SRC_MASK                  0x00C0  /* AIF2TX_SRC - [7:6] */
+#define WM8996_AIF2TX_SRC_SHIFT                      6  /* AIF2TX_SRC - [7:6] */
+#define WM8996_AIF2TX_SRC_WIDTH                      2  /* AIF2TX_SRC - [7:6] */
+#define WM8996_DSP2RX_SRC                       0x0010  /* DSP2RX_SRC */
+#define WM8996_DSP2RX_SRC_MASK                  0x0010  /* DSP2RX_SRC */
+#define WM8996_DSP2RX_SRC_SHIFT                      4  /* DSP2RX_SRC */
+#define WM8996_DSP2RX_SRC_WIDTH                      1  /* DSP2RX_SRC */
+#define WM8996_DSP1RX_SRC                       0x0001  /* DSP1RX_SRC */
+#define WM8996_DSP1RX_SRC_MASK                  0x0001  /* DSP1RX_SRC */
+#define WM8996_DSP1RX_SRC_SHIFT                      0  /* DSP1RX_SRC */
+#define WM8996_DSP1RX_SRC_WIDTH                      1  /* DSP1RX_SRC */
+
+/*
+ * R16 (0x10) - Left Line Input Volume
+ */
+#define WM8996_IN1_VU                           0x0080  /* IN1_VU */
+#define WM8996_IN1_VU_MASK                      0x0080  /* IN1_VU */
+#define WM8996_IN1_VU_SHIFT                          7  /* IN1_VU */
+#define WM8996_IN1_VU_WIDTH                          1  /* IN1_VU */
+#define WM8996_IN1L_ZC                          0x0020  /* IN1L_ZC */
+#define WM8996_IN1L_ZC_MASK                     0x0020  /* IN1L_ZC */
+#define WM8996_IN1L_ZC_SHIFT                         5  /* IN1L_ZC */
+#define WM8996_IN1L_ZC_WIDTH                         1  /* IN1L_ZC */
+#define WM8996_IN1L_VOL_MASK                    0x001F  /* IN1L_VOL - [4:0] */
+#define WM8996_IN1L_VOL_SHIFT                        0  /* IN1L_VOL - [4:0] */
+#define WM8996_IN1L_VOL_WIDTH                        5  /* IN1L_VOL - [4:0] */
+
+/*
+ * R17 (0x11) - Right Line Input Volume
+ */
+#define WM8996_IN1_VU                           0x0080  /* IN1_VU */
+#define WM8996_IN1_VU_MASK                      0x0080  /* IN1_VU */
+#define WM8996_IN1_VU_SHIFT                          7  /* IN1_VU */
+#define WM8996_IN1_VU_WIDTH                          1  /* IN1_VU */
+#define WM8996_IN1R_ZC                          0x0020  /* IN1R_ZC */
+#define WM8996_IN1R_ZC_MASK                     0x0020  /* IN1R_ZC */
+#define WM8996_IN1R_ZC_SHIFT                         5  /* IN1R_ZC */
+#define WM8996_IN1R_ZC_WIDTH                         1  /* IN1R_ZC */
+#define WM8996_IN1R_VOL_MASK                    0x001F  /* IN1R_VOL - [4:0] */
+#define WM8996_IN1R_VOL_SHIFT                        0  /* IN1R_VOL - [4:0] */
+#define WM8996_IN1R_VOL_WIDTH                        5  /* IN1R_VOL - [4:0] */
+
+/*
+ * R18 (0x12) - Line Input Control
+ */
+#define WM8996_INL_MODE_MASK                    0x000C  /* INL_MODE - [3:2] */
+#define WM8996_INL_MODE_SHIFT                        2  /* INL_MODE - [3:2] */
+#define WM8996_INL_MODE_WIDTH                        2  /* INL_MODE - [3:2] */
+#define WM8996_INR_MODE_MASK                    0x0003  /* INR_MODE - [1:0] */
+#define WM8996_INR_MODE_SHIFT                        0  /* INR_MODE - [1:0] */
+#define WM8996_INR_MODE_WIDTH                        2  /* INR_MODE - [1:0] */
+
+/*
+ * R21 (0x15) - DAC1 HPOUT1 Volume
+ */
+#define WM8996_DAC1R_HPOUT1R_VOL_MASK           0x00F0  /* DAC1R_HPOUT1R_VOL - [7:4] */
+#define WM8996_DAC1R_HPOUT1R_VOL_SHIFT               4  /* DAC1R_HPOUT1R_VOL - [7:4] */
+#define WM8996_DAC1R_HPOUT1R_VOL_WIDTH               4  /* DAC1R_HPOUT1R_VOL - [7:4] */
+#define WM8996_DAC1L_HPOUT1L_VOL_MASK           0x000F  /* DAC1L_HPOUT1L_VOL - [3:0] */
+#define WM8996_DAC1L_HPOUT1L_VOL_SHIFT               0  /* DAC1L_HPOUT1L_VOL - [3:0] */
+#define WM8996_DAC1L_HPOUT1L_VOL_WIDTH               4  /* DAC1L_HPOUT1L_VOL - [3:0] */
+
+/*
+ * R22 (0x16) - DAC2 HPOUT2 Volume
+ */
+#define WM8996_DAC2R_HPOUT2R_VOL_MASK           0x00F0  /* DAC2R_HPOUT2R_VOL - [7:4] */
+#define WM8996_DAC2R_HPOUT2R_VOL_SHIFT               4  /* DAC2R_HPOUT2R_VOL - [7:4] */
+#define WM8996_DAC2R_HPOUT2R_VOL_WIDTH               4  /* DAC2R_HPOUT2R_VOL - [7:4] */
+#define WM8996_DAC2L_HPOUT2L_VOL_MASK           0x000F  /* DAC2L_HPOUT2L_VOL - [3:0] */
+#define WM8996_DAC2L_HPOUT2L_VOL_SHIFT               0  /* DAC2L_HPOUT2L_VOL - [3:0] */
+#define WM8996_DAC2L_HPOUT2L_VOL_WIDTH               4  /* DAC2L_HPOUT2L_VOL - [3:0] */
+
+/*
+ * R24 (0x18) - DAC1 Left Volume
+ */
+#define WM8996_DAC1L_MUTE                       0x0200  /* DAC1L_MUTE */
+#define WM8996_DAC1L_MUTE_MASK                  0x0200  /* DAC1L_MUTE */
+#define WM8996_DAC1L_MUTE_SHIFT                      9  /* DAC1L_MUTE */
+#define WM8996_DAC1L_MUTE_WIDTH                      1  /* DAC1L_MUTE */
+#define WM8996_DAC1_VU                          0x0100  /* DAC1_VU */
+#define WM8996_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
+#define WM8996_DAC1_VU_SHIFT                         8  /* DAC1_VU */
+#define WM8996_DAC1_VU_WIDTH                         1  /* DAC1_VU */
+#define WM8996_DAC1L_VOL_MASK                   0x00FF  /* DAC1L_VOL - [7:0] */
+#define WM8996_DAC1L_VOL_SHIFT                       0  /* DAC1L_VOL - [7:0] */
+#define WM8996_DAC1L_VOL_WIDTH                       8  /* DAC1L_VOL - [7:0] */
+
+/*
+ * R25 (0x19) - DAC1 Right Volume
+ */
+#define WM8996_DAC1R_MUTE                       0x0200  /* DAC1R_MUTE */
+#define WM8996_DAC1R_MUTE_MASK                  0x0200  /* DAC1R_MUTE */
+#define WM8996_DAC1R_MUTE_SHIFT                      9  /* DAC1R_MUTE */
+#define WM8996_DAC1R_MUTE_WIDTH                      1  /* DAC1R_MUTE */
+#define WM8996_DAC1_VU                          0x0100  /* DAC1_VU */
+#define WM8996_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
+#define WM8996_DAC1_VU_SHIFT                         8  /* DAC1_VU */
+#define WM8996_DAC1_VU_WIDTH                         1  /* DAC1_VU */
+#define WM8996_DAC1R_VOL_MASK                   0x00FF  /* DAC1R_VOL - [7:0] */
+#define WM8996_DAC1R_VOL_SHIFT                       0  /* DAC1R_VOL - [7:0] */
+#define WM8996_DAC1R_VOL_WIDTH                       8  /* DAC1R_VOL - [7:0] */
+
+/*
+ * R26 (0x1A) - DAC2 Left Volume
+ */
+#define WM8996_DAC2L_MUTE                       0x0200  /* DAC2L_MUTE */
+#define WM8996_DAC2L_MUTE_MASK                  0x0200  /* DAC2L_MUTE */
+#define WM8996_DAC2L_MUTE_SHIFT                      9  /* DAC2L_MUTE */
+#define WM8996_DAC2L_MUTE_WIDTH                      1  /* DAC2L_MUTE */
+#define WM8996_DAC2_VU                          0x0100  /* DAC2_VU */
+#define WM8996_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
+#define WM8996_DAC2_VU_SHIFT                         8  /* DAC2_VU */
+#define WM8996_DAC2_VU_WIDTH                         1  /* DAC2_VU */
+#define WM8996_DAC2L_VOL_MASK                   0x00FF  /* DAC2L_VOL - [7:0] */
+#define WM8996_DAC2L_VOL_SHIFT                       0  /* DAC2L_VOL - [7:0] */
+#define WM8996_DAC2L_VOL_WIDTH                       8  /* DAC2L_VOL - [7:0] */
+
+/*
+ * R27 (0x1B) - DAC2 Right Volume
+ */
+#define WM8996_DAC2R_MUTE                       0x0200  /* DAC2R_MUTE */
+#define WM8996_DAC2R_MUTE_MASK                  0x0200  /* DAC2R_MUTE */
+#define WM8996_DAC2R_MUTE_SHIFT                      9  /* DAC2R_MUTE */
+#define WM8996_DAC2R_MUTE_WIDTH                      1  /* DAC2R_MUTE */
+#define WM8996_DAC2_VU                          0x0100  /* DAC2_VU */
+#define WM8996_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
+#define WM8996_DAC2_VU_SHIFT                         8  /* DAC2_VU */
+#define WM8996_DAC2_VU_WIDTH                         1  /* DAC2_VU */
+#define WM8996_DAC2R_VOL_MASK                   0x00FF  /* DAC2R_VOL - [7:0] */
+#define WM8996_DAC2R_VOL_SHIFT                       0  /* DAC2R_VOL - [7:0] */
+#define WM8996_DAC2R_VOL_WIDTH                       8  /* DAC2R_VOL - [7:0] */
+
+/*
+ * R28 (0x1C) - Output1 Left Volume
+ */
+#define WM8996_DAC1_VU                          0x0100  /* DAC1_VU */
+#define WM8996_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
+#define WM8996_DAC1_VU_SHIFT                         8  /* DAC1_VU */
+#define WM8996_DAC1_VU_WIDTH                         1  /* DAC1_VU */
+#define WM8996_HPOUT1L_ZC                       0x0080  /* HPOUT1L_ZC */
+#define WM8996_HPOUT1L_ZC_MASK                  0x0080  /* HPOUT1L_ZC */
+#define WM8996_HPOUT1L_ZC_SHIFT                      7  /* HPOUT1L_ZC */
+#define WM8996_HPOUT1L_ZC_WIDTH                      1  /* HPOUT1L_ZC */
+#define WM8996_HPOUT1L_VOL_MASK                 0x000F  /* HPOUT1L_VOL - [3:0] */
+#define WM8996_HPOUT1L_VOL_SHIFT                     0  /* HPOUT1L_VOL - [3:0] */
+#define WM8996_HPOUT1L_VOL_WIDTH                     4  /* HPOUT1L_VOL - [3:0] */
+
+/*
+ * R29 (0x1D) - Output1 Right Volume
+ */
+#define WM8996_DAC1_VU                          0x0100  /* DAC1_VU */
+#define WM8996_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
+#define WM8996_DAC1_VU_SHIFT                         8  /* DAC1_VU */
+#define WM8996_DAC1_VU_WIDTH                         1  /* DAC1_VU */
+#define WM8996_HPOUT1R_ZC                       0x0080  /* HPOUT1R_ZC */
+#define WM8996_HPOUT1R_ZC_MASK                  0x0080  /* HPOUT1R_ZC */
+#define WM8996_HPOUT1R_ZC_SHIFT                      7  /* HPOUT1R_ZC */
+#define WM8996_HPOUT1R_ZC_WIDTH                      1  /* HPOUT1R_ZC */
+#define WM8996_HPOUT1R_VOL_MASK                 0x000F  /* HPOUT1R_VOL - [3:0] */
+#define WM8996_HPOUT1R_VOL_SHIFT                     0  /* HPOUT1R_VOL - [3:0] */
+#define WM8996_HPOUT1R_VOL_WIDTH                     4  /* HPOUT1R_VOL - [3:0] */
+
+/*
+ * R30 (0x1E) - Output2 Left Volume
+ */
+#define WM8996_DAC2_VU                          0x0100  /* DAC2_VU */
+#define WM8996_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
+#define WM8996_DAC2_VU_SHIFT                         8  /* DAC2_VU */
+#define WM8996_DAC2_VU_WIDTH                         1  /* DAC2_VU */
+#define WM8996_HPOUT2L_ZC                       0x0080  /* HPOUT2L_ZC */
+#define WM8996_HPOUT2L_ZC_MASK                  0x0080  /* HPOUT2L_ZC */
+#define WM8996_HPOUT2L_ZC_SHIFT                      7  /* HPOUT2L_ZC */
+#define WM8996_HPOUT2L_ZC_WIDTH                      1  /* HPOUT2L_ZC */
+#define WM8996_HPOUT2L_VOL_MASK                 0x000F  /* HPOUT2L_VOL - [3:0] */
+#define WM8996_HPOUT2L_VOL_SHIFT                     0  /* HPOUT2L_VOL - [3:0] */
+#define WM8996_HPOUT2L_VOL_WIDTH                     4  /* HPOUT2L_VOL - [3:0] */
+
+/*
+ * R31 (0x1F) - Output2 Right Volume
+ */
+#define WM8996_DAC2_VU                          0x0100  /* DAC2_VU */
+#define WM8996_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
+#define WM8996_DAC2_VU_SHIFT                         8  /* DAC2_VU */
+#define WM8996_DAC2_VU_WIDTH                         1  /* DAC2_VU */
+#define WM8996_HPOUT2R_ZC                       0x0080  /* HPOUT2R_ZC */
+#define WM8996_HPOUT2R_ZC_MASK                  0x0080  /* HPOUT2R_ZC */
+#define WM8996_HPOUT2R_ZC_SHIFT                      7  /* HPOUT2R_ZC */
+#define WM8996_HPOUT2R_ZC_WIDTH                      1  /* HPOUT2R_ZC */
+#define WM8996_HPOUT2R_VOL_MASK                 0x000F  /* HPOUT2R_VOL - [3:0] */
+#define WM8996_HPOUT2R_VOL_SHIFT                     0  /* HPOUT2R_VOL - [3:0] */
+#define WM8996_HPOUT2R_VOL_WIDTH                     4  /* HPOUT2R_VOL - [3:0] */
+
+/*
+ * R32 (0x20) - MICBIAS (1)
+ */
+#define WM8996_MICB1_RATE                       0x0020  /* MICB1_RATE */
+#define WM8996_MICB1_RATE_MASK                  0x0020  /* MICB1_RATE */
+#define WM8996_MICB1_RATE_SHIFT                      5  /* MICB1_RATE */
+#define WM8996_MICB1_RATE_WIDTH                      1  /* MICB1_RATE */
+#define WM8996_MICB1_MODE                       0x0010  /* MICB1_MODE */
+#define WM8996_MICB1_MODE_MASK                  0x0010  /* MICB1_MODE */
+#define WM8996_MICB1_MODE_SHIFT                      4  /* MICB1_MODE */
+#define WM8996_MICB1_MODE_WIDTH                      1  /* MICB1_MODE */
+#define WM8996_MICB1_LVL_MASK                   0x000E  /* MICB1_LVL - [3:1] */
+#define WM8996_MICB1_LVL_SHIFT                       1  /* MICB1_LVL - [3:1] */
+#define WM8996_MICB1_LVL_WIDTH                       3  /* MICB1_LVL - [3:1] */
+#define WM8996_MICB1_DISCH                      0x0001  /* MICB1_DISCH */
+#define WM8996_MICB1_DISCH_MASK                 0x0001  /* MICB1_DISCH */
+#define WM8996_MICB1_DISCH_SHIFT                     0  /* MICB1_DISCH */
+#define WM8996_MICB1_DISCH_WIDTH                     1  /* MICB1_DISCH */
+
+/*
+ * R33 (0x21) - MICBIAS (2)
+ */
+#define WM8996_MICB2_RATE                       0x0020  /* MICB2_RATE */
+#define WM8996_MICB2_RATE_MASK                  0x0020  /* MICB2_RATE */
+#define WM8996_MICB2_RATE_SHIFT                      5  /* MICB2_RATE */
+#define WM8996_MICB2_RATE_WIDTH                      1  /* MICB2_RATE */
+#define WM8996_MICB2_MODE                       0x0010  /* MICB2_MODE */
+#define WM8996_MICB2_MODE_MASK                  0x0010  /* MICB2_MODE */
+#define WM8996_MICB2_MODE_SHIFT                      4  /* MICB2_MODE */
+#define WM8996_MICB2_MODE_WIDTH                      1  /* MICB2_MODE */
+#define WM8996_MICB2_LVL_MASK                   0x000E  /* MICB2_LVL - [3:1] */
+#define WM8996_MICB2_LVL_SHIFT                       1  /* MICB2_LVL - [3:1] */
+#define WM8996_MICB2_LVL_WIDTH                       3  /* MICB2_LVL - [3:1] */
+#define WM8996_MICB2_DISCH                      0x0001  /* MICB2_DISCH */
+#define WM8996_MICB2_DISCH_MASK                 0x0001  /* MICB2_DISCH */
+#define WM8996_MICB2_DISCH_SHIFT                     0  /* MICB2_DISCH */
+#define WM8996_MICB2_DISCH_WIDTH                     1  /* MICB2_DISCH */
+
+/*
+ * R40 (0x28) - LDO 1
+ */
+#define WM8996_LDO1_MODE                        0x0020  /* LDO1_MODE */
+#define WM8996_LDO1_MODE_MASK                   0x0020  /* LDO1_MODE */
+#define WM8996_LDO1_MODE_SHIFT                       5  /* LDO1_MODE */
+#define WM8996_LDO1_MODE_WIDTH                       1  /* LDO1_MODE */
+#define WM8996_LDO1_VSEL_MASK                   0x0006  /* LDO1_VSEL - [2:1] */
+#define WM8996_LDO1_VSEL_SHIFT                       1  /* LDO1_VSEL - [2:1] */
+#define WM8996_LDO1_VSEL_WIDTH                       2  /* LDO1_VSEL - [2:1] */
+#define WM8996_LDO1_DISCH                       0x0001  /* LDO1_DISCH */
+#define WM8996_LDO1_DISCH_MASK                  0x0001  /* LDO1_DISCH */
+#define WM8996_LDO1_DISCH_SHIFT                      0  /* LDO1_DISCH */
+#define WM8996_LDO1_DISCH_WIDTH                      1  /* LDO1_DISCH */
+
+/*
+ * R41 (0x29) - LDO 2
+ */
+#define WM8996_LDO2_MODE                        0x0020  /* LDO2_MODE */
+#define WM8996_LDO2_MODE_MASK                   0x0020  /* LDO2_MODE */
+#define WM8996_LDO2_MODE_SHIFT                       5  /* LDO2_MODE */
+#define WM8996_LDO2_MODE_WIDTH                       1  /* LDO2_MODE */
+#define WM8996_LDO2_VSEL_MASK                   0x001E  /* LDO2_VSEL - [4:1] */
+#define WM8996_LDO2_VSEL_SHIFT                       1  /* LDO2_VSEL - [4:1] */
+#define WM8996_LDO2_VSEL_WIDTH                       4  /* LDO2_VSEL - [4:1] */
+#define WM8996_LDO2_DISCH                       0x0001  /* LDO2_DISCH */
+#define WM8996_LDO2_DISCH_MASK                  0x0001  /* LDO2_DISCH */
+#define WM8996_LDO2_DISCH_SHIFT                      0  /* LDO2_DISCH */
+#define WM8996_LDO2_DISCH_WIDTH                      1  /* LDO2_DISCH */
+
+/*
+ * R48 (0x30) - Accessory Detect Mode 1
+ */
+#define WM8996_JD_MODE_MASK                     0x0003  /* JD_MODE - [1:0] */
+#define WM8996_JD_MODE_SHIFT                         0  /* JD_MODE - [1:0] */
+#define WM8996_JD_MODE_WIDTH                         2  /* JD_MODE - [1:0] */
+
+/*
+ * R49 (0x31) - Accessory Detect Mode 2
+ */
+#define WM8996_HPOUT1FB_SRC                     0x0004  /* HPOUT1FB_SRC */
+#define WM8996_HPOUT1FB_SRC_MASK                0x0004  /* HPOUT1FB_SRC */
+#define WM8996_HPOUT1FB_SRC_SHIFT                    2  /* HPOUT1FB_SRC */
+#define WM8996_HPOUT1FB_SRC_WIDTH                    1  /* HPOUT1FB_SRC */
+#define WM8996_MICD_SRC                         0x0002  /* MICD_SRC */
+#define WM8996_MICD_SRC_MASK                    0x0002  /* MICD_SRC */
+#define WM8996_MICD_SRC_SHIFT                        1  /* MICD_SRC */
+#define WM8996_MICD_SRC_WIDTH                        1  /* MICD_SRC */
+#define WM8996_MICD_BIAS_SRC                    0x0001  /* MICD_BIAS_SRC */
+#define WM8996_MICD_BIAS_SRC_MASK               0x0001  /* MICD_BIAS_SRC */
+#define WM8996_MICD_BIAS_SRC_SHIFT                   0  /* MICD_BIAS_SRC */
+#define WM8996_MICD_BIAS_SRC_WIDTH                   1  /* MICD_BIAS_SRC */
+
+/*
+ * R52 (0x34) - Headphone Detect 1
+ */
+#define WM8996_HP_HOLDTIME_MASK                 0x00E0  /* HP_HOLDTIME - [7:5] */
+#define WM8996_HP_HOLDTIME_SHIFT                     5  /* HP_HOLDTIME - [7:5] */
+#define WM8996_HP_HOLDTIME_WIDTH                     3  /* HP_HOLDTIME - [7:5] */
+#define WM8996_HP_CLK_DIV_MASK                  0x0018  /* HP_CLK_DIV - [4:3] */
+#define WM8996_HP_CLK_DIV_SHIFT                      3  /* HP_CLK_DIV - [4:3] */
+#define WM8996_HP_CLK_DIV_WIDTH                      2  /* HP_CLK_DIV - [4:3] */
+#define WM8996_HP_STEP_SIZE                     0x0002  /* HP_STEP_SIZE */
+#define WM8996_HP_STEP_SIZE_MASK                0x0002  /* HP_STEP_SIZE */
+#define WM8996_HP_STEP_SIZE_SHIFT                    1  /* HP_STEP_SIZE */
+#define WM8996_HP_STEP_SIZE_WIDTH                    1  /* HP_STEP_SIZE */
+#define WM8996_HP_POLL                          0x0001  /* HP_POLL */
+#define WM8996_HP_POLL_MASK                     0x0001  /* HP_POLL */
+#define WM8996_HP_POLL_SHIFT                         0  /* HP_POLL */
+#define WM8996_HP_POLL_WIDTH                         1  /* HP_POLL */
+
+/*
+ * R53 (0x35) - Headphone Detect 2
+ */
+#define WM8996_HP_DONE                          0x0080  /* HP_DONE */
+#define WM8996_HP_DONE_MASK                     0x0080  /* HP_DONE */
+#define WM8996_HP_DONE_SHIFT                         7  /* HP_DONE */
+#define WM8996_HP_DONE_WIDTH                         1  /* HP_DONE */
+#define WM8996_HP_LVL_MASK                      0x007F  /* HP_LVL - [6:0] */
+#define WM8996_HP_LVL_SHIFT                          0  /* HP_LVL - [6:0] */
+#define WM8996_HP_LVL_WIDTH                          7  /* HP_LVL - [6:0] */
+
+/*
+ * R56 (0x38) - Mic Detect 1
+ */
+#define WM8996_MICD_BIAS_STARTTIME_MASK         0xF000  /* MICD_BIAS_STARTTIME - [15:12] */
+#define WM8996_MICD_BIAS_STARTTIME_SHIFT            12  /* MICD_BIAS_STARTTIME - [15:12] */
+#define WM8996_MICD_BIAS_STARTTIME_WIDTH             4  /* MICD_BIAS_STARTTIME - [15:12] */
+#define WM8996_MICD_RATE_MASK                   0x0F00  /* MICD_RATE - [11:8] */
+#define WM8996_MICD_RATE_SHIFT                       8  /* MICD_RATE - [11:8] */
+#define WM8996_MICD_RATE_WIDTH                       4  /* MICD_RATE - [11:8] */
+#define WM8996_MICD_DBTIME                      0x0002  /* MICD_DBTIME */
+#define WM8996_MICD_DBTIME_MASK                 0x0002  /* MICD_DBTIME */
+#define WM8996_MICD_DBTIME_SHIFT                     1  /* MICD_DBTIME */
+#define WM8996_MICD_DBTIME_WIDTH                     1  /* MICD_DBTIME */
+#define WM8996_MICD_ENA                         0x0001  /* MICD_ENA */
+#define WM8996_MICD_ENA_MASK                    0x0001  /* MICD_ENA */
+#define WM8996_MICD_ENA_SHIFT                        0  /* MICD_ENA */
+#define WM8996_MICD_ENA_WIDTH                        1  /* MICD_ENA */
+
+/*
+ * R57 (0x39) - Mic Detect 2
+ */
+#define WM8996_MICD_LVL_SEL_MASK                0x00FF  /* MICD_LVL_SEL - [7:0] */
+#define WM8996_MICD_LVL_SEL_SHIFT                    0  /* MICD_LVL_SEL - [7:0] */
+#define WM8996_MICD_LVL_SEL_WIDTH                    8  /* MICD_LVL_SEL - [7:0] */
+
+/*
+ * R58 (0x3A) - Mic Detect 3
+ */
+#define WM8996_MICD_LVL_MASK                    0x07FC  /* MICD_LVL - [10:2] */
+#define WM8996_MICD_LVL_SHIFT                        2  /* MICD_LVL - [10:2] */
+#define WM8996_MICD_LVL_WIDTH                        9  /* MICD_LVL - [10:2] */
+#define WM8996_MICD_VALID                       0x0002  /* MICD_VALID */
+#define WM8996_MICD_VALID_MASK                  0x0002  /* MICD_VALID */
+#define WM8996_MICD_VALID_SHIFT                      1  /* MICD_VALID */
+#define WM8996_MICD_VALID_WIDTH                      1  /* MICD_VALID */
+#define WM8996_MICD_STS                         0x0001  /* MICD_STS */
+#define WM8996_MICD_STS_MASK                    0x0001  /* MICD_STS */
+#define WM8996_MICD_STS_SHIFT                        0  /* MICD_STS */
+#define WM8996_MICD_STS_WIDTH                        1  /* MICD_STS */
+
+/*
+ * R64 (0x40) - Charge Pump (1)
+ */
+#define WM8996_CP_ENA                           0x8000  /* CP_ENA */
+#define WM8996_CP_ENA_MASK                      0x8000  /* CP_ENA */
+#define WM8996_CP_ENA_SHIFT                         15  /* CP_ENA */
+#define WM8996_CP_ENA_WIDTH                          1  /* CP_ENA */
+
+/*
+ * R65 (0x41) - Charge Pump (2)
+ */
+#define WM8996_CP_DISCH                         0x8000  /* CP_DISCH */
+#define WM8996_CP_DISCH_MASK                    0x8000  /* CP_DISCH */
+#define WM8996_CP_DISCH_SHIFT                       15  /* CP_DISCH */
+#define WM8996_CP_DISCH_WIDTH                        1  /* CP_DISCH */
+
+/*
+ * R80 (0x50) - DC Servo (1)
+ */
+#define WM8996_DCS_ENA_CHAN_3                   0x0008  /* DCS_ENA_CHAN_3 */
+#define WM8996_DCS_ENA_CHAN_3_MASK              0x0008  /* DCS_ENA_CHAN_3 */
+#define WM8996_DCS_ENA_CHAN_3_SHIFT                  3  /* DCS_ENA_CHAN_3 */
+#define WM8996_DCS_ENA_CHAN_3_WIDTH                  1  /* DCS_ENA_CHAN_3 */
+#define WM8996_DCS_ENA_CHAN_2                   0x0004  /* DCS_ENA_CHAN_2 */
+#define WM8996_DCS_ENA_CHAN_2_MASK              0x0004  /* DCS_ENA_CHAN_2 */
+#define WM8996_DCS_ENA_CHAN_2_SHIFT                  2  /* DCS_ENA_CHAN_2 */
+#define WM8996_DCS_ENA_CHAN_2_WIDTH                  1  /* DCS_ENA_CHAN_2 */
+#define WM8996_DCS_ENA_CHAN_1                   0x0002  /* DCS_ENA_CHAN_1 */
+#define WM8996_DCS_ENA_CHAN_1_MASK              0x0002  /* DCS_ENA_CHAN_1 */
+#define WM8996_DCS_ENA_CHAN_1_SHIFT                  1  /* DCS_ENA_CHAN_1 */
+#define WM8996_DCS_ENA_CHAN_1_WIDTH                  1  /* DCS_ENA_CHAN_1 */
+#define WM8996_DCS_ENA_CHAN_0                   0x0001  /* DCS_ENA_CHAN_0 */
+#define WM8996_DCS_ENA_CHAN_0_MASK              0x0001  /* DCS_ENA_CHAN_0 */
+#define WM8996_DCS_ENA_CHAN_0_SHIFT                  0  /* DCS_ENA_CHAN_0 */
+#define WM8996_DCS_ENA_CHAN_0_WIDTH                  1  /* DCS_ENA_CHAN_0 */
+
+/*
+ * R81 (0x51) - DC Servo (2)
+ */
+#define WM8996_DCS_TRIG_SINGLE_3                0x8000  /* DCS_TRIG_SINGLE_3 */
+#define WM8996_DCS_TRIG_SINGLE_3_MASK           0x8000  /* DCS_TRIG_SINGLE_3 */
+#define WM8996_DCS_TRIG_SINGLE_3_SHIFT              15  /* DCS_TRIG_SINGLE_3 */
+#define WM8996_DCS_TRIG_SINGLE_3_WIDTH               1  /* DCS_TRIG_SINGLE_3 */
+#define WM8996_DCS_TRIG_SINGLE_2                0x4000  /* DCS_TRIG_SINGLE_2 */
+#define WM8996_DCS_TRIG_SINGLE_2_MASK           0x4000  /* DCS_TRIG_SINGLE_2 */
+#define WM8996_DCS_TRIG_SINGLE_2_SHIFT              14  /* DCS_TRIG_SINGLE_2 */
+#define WM8996_DCS_TRIG_SINGLE_2_WIDTH               1  /* DCS_TRIG_SINGLE_2 */
+#define WM8996_DCS_TRIG_SINGLE_1                0x2000  /* DCS_TRIG_SINGLE_1 */
+#define WM8996_DCS_TRIG_SINGLE_1_MASK           0x2000  /* DCS_TRIG_SINGLE_1 */
+#define WM8996_DCS_TRIG_SINGLE_1_SHIFT              13  /* DCS_TRIG_SINGLE_1 */
+#define WM8996_DCS_TRIG_SINGLE_1_WIDTH               1  /* DCS_TRIG_SINGLE_1 */
+#define WM8996_DCS_TRIG_SINGLE_0                0x1000  /* DCS_TRIG_SINGLE_0 */
+#define WM8996_DCS_TRIG_SINGLE_0_MASK           0x1000  /* DCS_TRIG_SINGLE_0 */
+#define WM8996_DCS_TRIG_SINGLE_0_SHIFT              12  /* DCS_TRIG_SINGLE_0 */
+#define WM8996_DCS_TRIG_SINGLE_0_WIDTH               1  /* DCS_TRIG_SINGLE_0 */
+#define WM8996_DCS_TRIG_SERIES_3                0x0800  /* DCS_TRIG_SERIES_3 */
+#define WM8996_DCS_TRIG_SERIES_3_MASK           0x0800  /* DCS_TRIG_SERIES_3 */
+#define WM8996_DCS_TRIG_SERIES_3_SHIFT              11  /* DCS_TRIG_SERIES_3 */
+#define WM8996_DCS_TRIG_SERIES_3_WIDTH               1  /* DCS_TRIG_SERIES_3 */
+#define WM8996_DCS_TRIG_SERIES_2                0x0400  /* DCS_TRIG_SERIES_2 */
+#define WM8996_DCS_TRIG_SERIES_2_MASK           0x0400  /* DCS_TRIG_SERIES_2 */
+#define WM8996_DCS_TRIG_SERIES_2_SHIFT              10  /* DCS_TRIG_SERIES_2 */
+#define WM8996_DCS_TRIG_SERIES_2_WIDTH               1  /* DCS_TRIG_SERIES_2 */
+#define WM8996_DCS_TRIG_SERIES_1                0x0200  /* DCS_TRIG_SERIES_1 */
+#define WM8996_DCS_TRIG_SERIES_1_MASK           0x0200  /* DCS_TRIG_SERIES_1 */
+#define WM8996_DCS_TRIG_SERIES_1_SHIFT               9  /* DCS_TRIG_SERIES_1 */
+#define WM8996_DCS_TRIG_SERIES_1_WIDTH               1  /* DCS_TRIG_SERIES_1 */
+#define WM8996_DCS_TRIG_SERIES_0                0x0100  /* DCS_TRIG_SERIES_0 */
+#define WM8996_DCS_TRIG_SERIES_0_MASK           0x0100  /* DCS_TRIG_SERIES_0 */
+#define WM8996_DCS_TRIG_SERIES_0_SHIFT               8  /* DCS_TRIG_SERIES_0 */
+#define WM8996_DCS_TRIG_SERIES_0_WIDTH               1  /* DCS_TRIG_SERIES_0 */
+#define WM8996_DCS_TRIG_STARTUP_3               0x0080  /* DCS_TRIG_STARTUP_3 */
+#define WM8996_DCS_TRIG_STARTUP_3_MASK          0x0080  /* DCS_TRIG_STARTUP_3 */
+#define WM8996_DCS_TRIG_STARTUP_3_SHIFT              7  /* DCS_TRIG_STARTUP_3 */
+#define WM8996_DCS_TRIG_STARTUP_3_WIDTH              1  /* DCS_TRIG_STARTUP_3 */
+#define WM8996_DCS_TRIG_STARTUP_2               0x0040  /* DCS_TRIG_STARTUP_2 */
+#define WM8996_DCS_TRIG_STARTUP_2_MASK          0x0040  /* DCS_TRIG_STARTUP_2 */
+#define WM8996_DCS_TRIG_STARTUP_2_SHIFT              6  /* DCS_TRIG_STARTUP_2 */
+#define WM8996_DCS_TRIG_STARTUP_2_WIDTH              1  /* DCS_TRIG_STARTUP_2 */
+#define WM8996_DCS_TRIG_STARTUP_1               0x0020  /* DCS_TRIG_STARTUP_1 */
+#define WM8996_DCS_TRIG_STARTUP_1_MASK          0x0020  /* DCS_TRIG_STARTUP_1 */
+#define WM8996_DCS_TRIG_STARTUP_1_SHIFT              5  /* DCS_TRIG_STARTUP_1 */
+#define WM8996_DCS_TRIG_STARTUP_1_WIDTH              1  /* DCS_TRIG_STARTUP_1 */
+#define WM8996_DCS_TRIG_STARTUP_0               0x0010  /* DCS_TRIG_STARTUP_0 */
+#define WM8996_DCS_TRIG_STARTUP_0_MASK          0x0010  /* DCS_TRIG_STARTUP_0 */
+#define WM8996_DCS_TRIG_STARTUP_0_SHIFT              4  /* DCS_TRIG_STARTUP_0 */
+#define WM8996_DCS_TRIG_STARTUP_0_WIDTH              1  /* DCS_TRIG_STARTUP_0 */
+#define WM8996_DCS_TRIG_DAC_WR_3                0x0008  /* DCS_TRIG_DAC_WR_3 */
+#define WM8996_DCS_TRIG_DAC_WR_3_MASK           0x0008  /* DCS_TRIG_DAC_WR_3 */
+#define WM8996_DCS_TRIG_DAC_WR_3_SHIFT               3  /* DCS_TRIG_DAC_WR_3 */
+#define WM8996_DCS_TRIG_DAC_WR_3_WIDTH               1  /* DCS_TRIG_DAC_WR_3 */
+#define WM8996_DCS_TRIG_DAC_WR_2                0x0004  /* DCS_TRIG_DAC_WR_2 */
+#define WM8996_DCS_TRIG_DAC_WR_2_MASK           0x0004  /* DCS_TRIG_DAC_WR_2 */
+#define WM8996_DCS_TRIG_DAC_WR_2_SHIFT               2  /* DCS_TRIG_DAC_WR_2 */
+#define WM8996_DCS_TRIG_DAC_WR_2_WIDTH               1  /* DCS_TRIG_DAC_WR_2 */
+#define WM8996_DCS_TRIG_DAC_WR_1                0x0002  /* DCS_TRIG_DAC_WR_1 */
+#define WM8996_DCS_TRIG_DAC_WR_1_MASK           0x0002  /* DCS_TRIG_DAC_WR_1 */
+#define WM8996_DCS_TRIG_DAC_WR_1_SHIFT               1  /* DCS_TRIG_DAC_WR_1 */
+#define WM8996_DCS_TRIG_DAC_WR_1_WIDTH               1  /* DCS_TRIG_DAC_WR_1 */
+#define WM8996_DCS_TRIG_DAC_WR_0                0x0001  /* DCS_TRIG_DAC_WR_0 */
+#define WM8996_DCS_TRIG_DAC_WR_0_MASK           0x0001  /* DCS_TRIG_DAC_WR_0 */
+#define WM8996_DCS_TRIG_DAC_WR_0_SHIFT               0  /* DCS_TRIG_DAC_WR_0 */
+#define WM8996_DCS_TRIG_DAC_WR_0_WIDTH               1  /* DCS_TRIG_DAC_WR_0 */
+
+/*
+ * R82 (0x52) - DC Servo (3)
+ */
+#define WM8996_DCS_TIMER_PERIOD_23_MASK         0x0F00  /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8996_DCS_TIMER_PERIOD_23_SHIFT             8  /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8996_DCS_TIMER_PERIOD_23_WIDTH             4  /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8996_DCS_TIMER_PERIOD_01_MASK         0x000F  /* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM8996_DCS_TIMER_PERIOD_01_SHIFT             0  /* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM8996_DCS_TIMER_PERIOD_01_WIDTH             4  /* DCS_TIMER_PERIOD_01 - [3:0] */
+
+/*
+ * R84 (0x54) - DC Servo (5)
+ */
+#define WM8996_DCS_SERIES_NO_23_MASK            0x7F00  /* DCS_SERIES_NO_23 - [14:8] */
+#define WM8996_DCS_SERIES_NO_23_SHIFT                8  /* DCS_SERIES_NO_23 - [14:8] */
+#define WM8996_DCS_SERIES_NO_23_WIDTH                7  /* DCS_SERIES_NO_23 - [14:8] */
+#define WM8996_DCS_SERIES_NO_01_MASK            0x007F  /* DCS_SERIES_NO_01 - [6:0] */
+#define WM8996_DCS_SERIES_NO_01_SHIFT                0  /* DCS_SERIES_NO_01 - [6:0] */
+#define WM8996_DCS_SERIES_NO_01_WIDTH                7  /* DCS_SERIES_NO_01 - [6:0] */
+
+/*
+ * R85 (0x55) - DC Servo (6)
+ */
+#define WM8996_DCS_DAC_WR_VAL_3_MASK            0xFF00  /* DCS_DAC_WR_VAL_3 - [15:8] */
+#define WM8996_DCS_DAC_WR_VAL_3_SHIFT                8  /* DCS_DAC_WR_VAL_3 - [15:8] */
+#define WM8996_DCS_DAC_WR_VAL_3_WIDTH                8  /* DCS_DAC_WR_VAL_3 - [15:8] */
+#define WM8996_DCS_DAC_WR_VAL_2_MASK            0x00FF  /* DCS_DAC_WR_VAL_2 - [7:0] */
+#define WM8996_DCS_DAC_WR_VAL_2_SHIFT                0  /* DCS_DAC_WR_VAL_2 - [7:0] */
+#define WM8996_DCS_DAC_WR_VAL_2_WIDTH                8  /* DCS_DAC_WR_VAL_2 - [7:0] */
+
+/*
+ * R86 (0x56) - DC Servo (7)
+ */
+#define WM8996_DCS_DAC_WR_VAL_1_MASK            0xFF00  /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8996_DCS_DAC_WR_VAL_1_SHIFT                8  /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8996_DCS_DAC_WR_VAL_1_WIDTH                8  /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8996_DCS_DAC_WR_VAL_0_MASK            0x00FF  /* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM8996_DCS_DAC_WR_VAL_0_SHIFT                0  /* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM8996_DCS_DAC_WR_VAL_0_WIDTH                8  /* DCS_DAC_WR_VAL_0 - [7:0] */
+
+/*
+ * R87 (0x57) - DC Servo Readback 0
+ */
+#define WM8996_DCS_CAL_COMPLETE_MASK            0x0F00  /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8996_DCS_CAL_COMPLETE_SHIFT                8  /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8996_DCS_CAL_COMPLETE_WIDTH                4  /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8996_DCS_DAC_WR_COMPLETE_MASK         0x00F0  /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8996_DCS_DAC_WR_COMPLETE_SHIFT             4  /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8996_DCS_DAC_WR_COMPLETE_WIDTH             4  /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8996_DCS_STARTUP_COMPLETE_MASK        0x000F  /* DCS_STARTUP_COMPLETE - [3:0] */
+#define WM8996_DCS_STARTUP_COMPLETE_SHIFT            0  /* DCS_STARTUP_COMPLETE - [3:0] */
+#define WM8996_DCS_STARTUP_COMPLETE_WIDTH            4  /* DCS_STARTUP_COMPLETE - [3:0] */
+
+/*
+ * R96 (0x60) - Analogue HP (1)
+ */
+#define WM8996_HPOUT1L_RMV_SHORT                0x0080  /* HPOUT1L_RMV_SHORT */
+#define WM8996_HPOUT1L_RMV_SHORT_MASK           0x0080  /* HPOUT1L_RMV_SHORT */
+#define WM8996_HPOUT1L_RMV_SHORT_SHIFT               7  /* HPOUT1L_RMV_SHORT */
+#define WM8996_HPOUT1L_RMV_SHORT_WIDTH               1  /* HPOUT1L_RMV_SHORT */
+#define WM8996_HPOUT1L_OUTP                     0x0040  /* HPOUT1L_OUTP */
+#define WM8996_HPOUT1L_OUTP_MASK                0x0040  /* HPOUT1L_OUTP */
+#define WM8996_HPOUT1L_OUTP_SHIFT                    6  /* HPOUT1L_OUTP */
+#define WM8996_HPOUT1L_OUTP_WIDTH                    1  /* HPOUT1L_OUTP */
+#define WM8996_HPOUT1L_DLY                      0x0020  /* HPOUT1L_DLY */
+#define WM8996_HPOUT1L_DLY_MASK                 0x0020  /* HPOUT1L_DLY */
+#define WM8996_HPOUT1L_DLY_SHIFT                     5  /* HPOUT1L_DLY */
+#define WM8996_HPOUT1L_DLY_WIDTH                     1  /* HPOUT1L_DLY */
+#define WM8996_HPOUT1R_RMV_SHORT                0x0008  /* HPOUT1R_RMV_SHORT */
+#define WM8996_HPOUT1R_RMV_SHORT_MASK           0x0008  /* HPOUT1R_RMV_SHORT */
+#define WM8996_HPOUT1R_RMV_SHORT_SHIFT               3  /* HPOUT1R_RMV_SHORT */
+#define WM8996_HPOUT1R_RMV_SHORT_WIDTH               1  /* HPOUT1R_RMV_SHORT */
+#define WM8996_HPOUT1R_OUTP                     0x0004  /* HPOUT1R_OUTP */
+#define WM8996_HPOUT1R_OUTP_MASK                0x0004  /* HPOUT1R_OUTP */
+#define WM8996_HPOUT1R_OUTP_SHIFT                    2  /* HPOUT1R_OUTP */
+#define WM8996_HPOUT1R_OUTP_WIDTH                    1  /* HPOUT1R_OUTP */
+#define WM8996_HPOUT1R_DLY                      0x0002  /* HPOUT1R_DLY */
+#define WM8996_HPOUT1R_DLY_MASK                 0x0002  /* HPOUT1R_DLY */
+#define WM8996_HPOUT1R_DLY_SHIFT                     1  /* HPOUT1R_DLY */
+#define WM8996_HPOUT1R_DLY_WIDTH                     1  /* HPOUT1R_DLY */
+
+/*
+ * R97 (0x61) - Analogue HP (2)
+ */
+#define WM8996_HPOUT2L_RMV_SHORT                0x0080  /* HPOUT2L_RMV_SHORT */
+#define WM8996_HPOUT2L_RMV_SHORT_MASK           0x0080  /* HPOUT2L_RMV_SHORT */
+#define WM8996_HPOUT2L_RMV_SHORT_SHIFT               7  /* HPOUT2L_RMV_SHORT */
+#define WM8996_HPOUT2L_RMV_SHORT_WIDTH               1  /* HPOUT2L_RMV_SHORT */
+#define WM8996_HPOUT2L_OUTP                     0x0040  /* HPOUT2L_OUTP */
+#define WM8996_HPOUT2L_OUTP_MASK                0x0040  /* HPOUT2L_OUTP */
+#define WM8996_HPOUT2L_OUTP_SHIFT                    6  /* HPOUT2L_OUTP */
+#define WM8996_HPOUT2L_OUTP_WIDTH                    1  /* HPOUT2L_OUTP */
+#define WM8996_HPOUT2L_DLY                      0x0020  /* HPOUT2L_DLY */
+#define WM8996_HPOUT2L_DLY_MASK                 0x0020  /* HPOUT2L_DLY */
+#define WM8996_HPOUT2L_DLY_SHIFT                     5  /* HPOUT2L_DLY */
+#define WM8996_HPOUT2L_DLY_WIDTH                     1  /* HPOUT2L_DLY */
+#define WM8996_HPOUT2R_RMV_SHORT                0x0008  /* HPOUT2R_RMV_SHORT */
+#define WM8996_HPOUT2R_RMV_SHORT_MASK           0x0008  /* HPOUT2R_RMV_SHORT */
+#define WM8996_HPOUT2R_RMV_SHORT_SHIFT               3  /* HPOUT2R_RMV_SHORT */
+#define WM8996_HPOUT2R_RMV_SHORT_WIDTH               1  /* HPOUT2R_RMV_SHORT */
+#define WM8996_HPOUT2R_OUTP                     0x0004  /* HPOUT2R_OUTP */
+#define WM8996_HPOUT2R_OUTP_MASK                0x0004  /* HPOUT2R_OUTP */
+#define WM8996_HPOUT2R_OUTP_SHIFT                    2  /* HPOUT2R_OUTP */
+#define WM8996_HPOUT2R_OUTP_WIDTH                    1  /* HPOUT2R_OUTP */
+#define WM8996_HPOUT2R_DLY                      0x0002  /* HPOUT2R_DLY */
+#define WM8996_HPOUT2R_DLY_MASK                 0x0002  /* HPOUT2R_DLY */
+#define WM8996_HPOUT2R_DLY_SHIFT                     1  /* HPOUT2R_DLY */
+#define WM8996_HPOUT2R_DLY_WIDTH                     1  /* HPOUT2R_DLY */
+
+/*
+ * R256 (0x100) - Chip Revision
+ */
+#define WM8996_CHIP_REV_MASK                    0x000F  /* CHIP_REV - [3:0] */
+#define WM8996_CHIP_REV_SHIFT                        0  /* CHIP_REV - [3:0] */
+#define WM8996_CHIP_REV_WIDTH                        4  /* CHIP_REV - [3:0] */
+
+/*
+ * R257 (0x101) - Control Interface (1)
+ */
+#define WM8996_AUTO_INC                         0x0004  /* AUTO_INC */
+#define WM8996_AUTO_INC_MASK                    0x0004  /* AUTO_INC */
+#define WM8996_AUTO_INC_SHIFT                        2  /* AUTO_INC */
+#define WM8996_AUTO_INC_WIDTH                        1  /* AUTO_INC */
+
+/*
+ * R272 (0x110) - Write Sequencer Ctrl (1)
+ */
+#define WM8996_WSEQ_ENA                         0x8000  /* WSEQ_ENA */
+#define WM8996_WSEQ_ENA_MASK                    0x8000  /* WSEQ_ENA */
+#define WM8996_WSEQ_ENA_SHIFT                       15  /* WSEQ_ENA */
+#define WM8996_WSEQ_ENA_WIDTH                        1  /* WSEQ_ENA */
+#define WM8996_WSEQ_ABORT                       0x0200  /* WSEQ_ABORT */
+#define WM8996_WSEQ_ABORT_MASK                  0x0200  /* WSEQ_ABORT */
+#define WM8996_WSEQ_ABORT_SHIFT                      9  /* WSEQ_ABORT */
+#define WM8996_WSEQ_ABORT_WIDTH                      1  /* WSEQ_ABORT */
+#define WM8996_WSEQ_START                       0x0100  /* WSEQ_START */
+#define WM8996_WSEQ_START_MASK                  0x0100  /* WSEQ_START */
+#define WM8996_WSEQ_START_SHIFT                      8  /* WSEQ_START */
+#define WM8996_WSEQ_START_WIDTH                      1  /* WSEQ_START */
+#define WM8996_WSEQ_START_INDEX_MASK            0x007F  /* WSEQ_START_INDEX - [6:0] */
+#define WM8996_WSEQ_START_INDEX_SHIFT                0  /* WSEQ_START_INDEX - [6:0] */
+#define WM8996_WSEQ_START_INDEX_WIDTH                7  /* WSEQ_START_INDEX - [6:0] */
+
+/*
+ * R273 (0x111) - Write Sequencer Ctrl (2)
+ */
+#define WM8996_WSEQ_BUSY                        0x0100  /* WSEQ_BUSY */
+#define WM8996_WSEQ_BUSY_MASK                   0x0100  /* WSEQ_BUSY */
+#define WM8996_WSEQ_BUSY_SHIFT                       8  /* WSEQ_BUSY */
+#define WM8996_WSEQ_BUSY_WIDTH                       1  /* WSEQ_BUSY */
+#define WM8996_WSEQ_CURRENT_INDEX_MASK          0x007F  /* WSEQ_CURRENT_INDEX - [6:0] */
+#define WM8996_WSEQ_CURRENT_INDEX_SHIFT              0  /* WSEQ_CURRENT_INDEX - [6:0] */
+#define WM8996_WSEQ_CURRENT_INDEX_WIDTH              7  /* WSEQ_CURRENT_INDEX - [6:0] */
+
+/*
+ * R512 (0x200) - AIF Clocking (1)
+ */
+#define WM8996_SYSCLK_SRC_MASK                  0x0018  /* SYSCLK_SRC - [4:3] */
+#define WM8996_SYSCLK_SRC_SHIFT                      3  /* SYSCLK_SRC - [4:3] */
+#define WM8996_SYSCLK_SRC_WIDTH                      2  /* SYSCLK_SRC - [4:3] */
+#define WM8996_SYSCLK_INV                       0x0004  /* SYSCLK_INV */
+#define WM8996_SYSCLK_INV_MASK                  0x0004  /* SYSCLK_INV */
+#define WM8996_SYSCLK_INV_SHIFT                      2  /* SYSCLK_INV */
+#define WM8996_SYSCLK_INV_WIDTH                      1  /* SYSCLK_INV */
+#define WM8996_SYSCLK_DIV                       0x0002  /* SYSCLK_DIV */
+#define WM8996_SYSCLK_DIV_MASK                  0x0002  /* SYSCLK_DIV */
+#define WM8996_SYSCLK_DIV_SHIFT                      1  /* SYSCLK_DIV */
+#define WM8996_SYSCLK_DIV_WIDTH                      1  /* SYSCLK_DIV */
+#define WM8996_SYSCLK_ENA                       0x0001  /* SYSCLK_ENA */
+#define WM8996_SYSCLK_ENA_MASK                  0x0001  /* SYSCLK_ENA */
+#define WM8996_SYSCLK_ENA_SHIFT                      0  /* SYSCLK_ENA */
+#define WM8996_SYSCLK_ENA_WIDTH                      1  /* SYSCLK_ENA */
+
+/*
+ * R513 (0x201) - AIF Clocking (2)
+ */
+#define WM8996_DSP2_DIV_MASK                    0x0018  /* DSP2_DIV - [4:3] */
+#define WM8996_DSP2_DIV_SHIFT                        3  /* DSP2_DIV - [4:3] */
+#define WM8996_DSP2_DIV_WIDTH                        2  /* DSP2_DIV - [4:3] */
+#define WM8996_DSP1_DIV_MASK                    0x0003  /* DSP1_DIV - [1:0] */
+#define WM8996_DSP1_DIV_SHIFT                        0  /* DSP1_DIV - [1:0] */
+#define WM8996_DSP1_DIV_WIDTH                        2  /* DSP1_DIV - [1:0] */
+
+/*
+ * R520 (0x208) - Clocking (1)
+ */
+#define WM8996_LFCLK_ENA                        0x0020  /* LFCLK_ENA */
+#define WM8996_LFCLK_ENA_MASK                   0x0020  /* LFCLK_ENA */
+#define WM8996_LFCLK_ENA_SHIFT                       5  /* LFCLK_ENA */
+#define WM8996_LFCLK_ENA_WIDTH                       1  /* LFCLK_ENA */
+#define WM8996_TOCLK_ENA                        0x0010  /* TOCLK_ENA */
+#define WM8996_TOCLK_ENA_MASK                   0x0010  /* TOCLK_ENA */
+#define WM8996_TOCLK_ENA_SHIFT                       4  /* TOCLK_ENA */
+#define WM8996_TOCLK_ENA_WIDTH                       1  /* TOCLK_ENA */
+#define WM8996_AIFCLK_ENA                       0x0004  /* AIFCLK_ENA */
+#define WM8996_AIFCLK_ENA_MASK                  0x0004  /* AIFCLK_ENA */
+#define WM8996_AIFCLK_ENA_SHIFT                      2  /* AIFCLK_ENA */
+#define WM8996_AIFCLK_ENA_WIDTH                      1  /* AIFCLK_ENA */
+#define WM8996_SYSDSPCLK_ENA                    0x0002  /* SYSDSPCLK_ENA */
+#define WM8996_SYSDSPCLK_ENA_MASK               0x0002  /* SYSDSPCLK_ENA */
+#define WM8996_SYSDSPCLK_ENA_SHIFT                   1  /* SYSDSPCLK_ENA */
+#define WM8996_SYSDSPCLK_ENA_WIDTH                   1  /* SYSDSPCLK_ENA */
+
+/*
+ * R521 (0x209) - Clocking (2)
+ */
+#define WM8996_TOCLK_DIV_MASK                   0x0700  /* TOCLK_DIV - [10:8] */
+#define WM8996_TOCLK_DIV_SHIFT                       8  /* TOCLK_DIV - [10:8] */
+#define WM8996_TOCLK_DIV_WIDTH                       3  /* TOCLK_DIV - [10:8] */
+#define WM8996_DBCLK_DIV_MASK                   0x00F0  /* DBCLK_DIV - [7:4] */
+#define WM8996_DBCLK_DIV_SHIFT                       4  /* DBCLK_DIV - [7:4] */
+#define WM8996_DBCLK_DIV_WIDTH                       4  /* DBCLK_DIV - [7:4] */
+#define WM8996_OPCLK_DIV_MASK                   0x0007  /* OPCLK_DIV - [2:0] */
+#define WM8996_OPCLK_DIV_SHIFT                       0  /* OPCLK_DIV - [2:0] */
+#define WM8996_OPCLK_DIV_WIDTH                       3  /* OPCLK_DIV - [2:0] */
+
+/*
+ * R528 (0x210) - AIF Rate
+ */
+#define WM8996_SYSCLK_RATE                      0x0001  /* SYSCLK_RATE */
+#define WM8996_SYSCLK_RATE_MASK                 0x0001  /* SYSCLK_RATE */
+#define WM8996_SYSCLK_RATE_SHIFT                     0  /* SYSCLK_RATE */
+#define WM8996_SYSCLK_RATE_WIDTH                     1  /* SYSCLK_RATE */
+
+/*
+ * R544 (0x220) - FLL Control (1)
+ */
+#define WM8996_FLL_OSC_ENA                      0x0002  /* FLL_OSC_ENA */
+#define WM8996_FLL_OSC_ENA_MASK                 0x0002  /* FLL_OSC_ENA */
+#define WM8996_FLL_OSC_ENA_SHIFT                     1  /* FLL_OSC_ENA */
+#define WM8996_FLL_OSC_ENA_WIDTH                     1  /* FLL_OSC_ENA */
+#define WM8996_FLL_ENA                          0x0001  /* FLL_ENA */
+#define WM8996_FLL_ENA_MASK                     0x0001  /* FLL_ENA */
+#define WM8996_FLL_ENA_SHIFT                         0  /* FLL_ENA */
+#define WM8996_FLL_ENA_WIDTH                         1  /* FLL_ENA */
+
+/*
+ * R545 (0x221) - FLL Control (2)
+ */
+#define WM8996_FLL_OUTDIV_MASK                  0x3F00  /* FLL_OUTDIV - [13:8] */
+#define WM8996_FLL_OUTDIV_SHIFT                      8  /* FLL_OUTDIV - [13:8] */
+#define WM8996_FLL_OUTDIV_WIDTH                      6  /* FLL_OUTDIV - [13:8] */
+#define WM8996_FLL_FRATIO_MASK                  0x0007  /* FLL_FRATIO - [2:0] */
+#define WM8996_FLL_FRATIO_SHIFT                      0  /* FLL_FRATIO - [2:0] */
+#define WM8996_FLL_FRATIO_WIDTH                      3  /* FLL_FRATIO - [2:0] */
+
+/*
+ * R546 (0x222) - FLL Control (3)
+ */
+#define WM8996_FLL_THETA_MASK                   0xFFFF  /* FLL_THETA - [15:0] */
+#define WM8996_FLL_THETA_SHIFT                       0  /* FLL_THETA - [15:0] */
+#define WM8996_FLL_THETA_WIDTH                      16  /* FLL_THETA - [15:0] */
+
+/*
+ * R547 (0x223) - FLL Control (4)
+ */
+#define WM8996_FLL_N_MASK                       0x7FE0  /* FLL_N - [14:5] */
+#define WM8996_FLL_N_SHIFT                           5  /* FLL_N - [14:5] */
+#define WM8996_FLL_N_WIDTH                          10  /* FLL_N - [14:5] */
+#define WM8996_FLL_LOOP_GAIN_MASK               0x000F  /* FLL_LOOP_GAIN - [3:0] */
+#define WM8996_FLL_LOOP_GAIN_SHIFT                   0  /* FLL_LOOP_GAIN - [3:0] */
+#define WM8996_FLL_LOOP_GAIN_WIDTH                   4  /* FLL_LOOP_GAIN - [3:0] */
+
+/*
+ * R548 (0x224) - FLL Control (5)
+ */
+#define WM8996_FLL_FRC_NCO_VAL_MASK             0x1F80  /* FLL_FRC_NCO_VAL - [12:7] */
+#define WM8996_FLL_FRC_NCO_VAL_SHIFT                 7  /* FLL_FRC_NCO_VAL - [12:7] */
+#define WM8996_FLL_FRC_NCO_VAL_WIDTH                 6  /* FLL_FRC_NCO_VAL - [12:7] */
+#define WM8996_FLL_FRC_NCO                      0x0040  /* FLL_FRC_NCO */
+#define WM8996_FLL_FRC_NCO_MASK                 0x0040  /* FLL_FRC_NCO */
+#define WM8996_FLL_FRC_NCO_SHIFT                     6  /* FLL_FRC_NCO */
+#define WM8996_FLL_FRC_NCO_WIDTH                     1  /* FLL_FRC_NCO */
+#define WM8996_FLL_REFCLK_DIV_MASK              0x0018  /* FLL_REFCLK_DIV - [4:3] */
+#define WM8996_FLL_REFCLK_DIV_SHIFT                  3  /* FLL_REFCLK_DIV - [4:3] */
+#define WM8996_FLL_REFCLK_DIV_WIDTH                  2  /* FLL_REFCLK_DIV - [4:3] */
+#define WM8996_FLL_REF_FREQ                     0x0004  /* FLL_REF_FREQ */
+#define WM8996_FLL_REF_FREQ_MASK                0x0004  /* FLL_REF_FREQ */
+#define WM8996_FLL_REF_FREQ_SHIFT                    2  /* FLL_REF_FREQ */
+#define WM8996_FLL_REF_FREQ_WIDTH                    1  /* FLL_REF_FREQ */
+#define WM8996_FLL_REFCLK_SRC_MASK              0x0003  /* FLL_REFCLK_SRC - [1:0] */
+#define WM8996_FLL_REFCLK_SRC_SHIFT                  0  /* FLL_REFCLK_SRC - [1:0] */
+#define WM8996_FLL_REFCLK_SRC_WIDTH                  2  /* FLL_REFCLK_SRC - [1:0] */
+
+/*
+ * R549 (0x225) - FLL Control (6)
+ */
+#define WM8996_FLL_REFCLK_SRC_STS_MASK          0x000C  /* FLL_REFCLK_SRC_STS - [3:2] */
+#define WM8996_FLL_REFCLK_SRC_STS_SHIFT              2  /* FLL_REFCLK_SRC_STS - [3:2] */
+#define WM8996_FLL_REFCLK_SRC_STS_WIDTH              2  /* FLL_REFCLK_SRC_STS - [3:2] */
+#define WM8996_FLL_SWITCH_CLK                   0x0001  /* FLL_SWITCH_CLK */
+#define WM8996_FLL_SWITCH_CLK_MASK              0x0001  /* FLL_SWITCH_CLK */
+#define WM8996_FLL_SWITCH_CLK_SHIFT                  0  /* FLL_SWITCH_CLK */
+#define WM8996_FLL_SWITCH_CLK_WIDTH                  1  /* FLL_SWITCH_CLK */
+
+/*
+ * R550 (0x226) - FLL EFS 1
+ */
+#define WM8996_FLL_LAMBDA_MASK                  0xFFFF  /* FLL_LAMBDA - [15:0] */
+#define WM8996_FLL_LAMBDA_SHIFT                      0  /* FLL_LAMBDA - [15:0] */
+#define WM8996_FLL_LAMBDA_WIDTH                     16  /* FLL_LAMBDA - [15:0] */
+
+/*
+ * R551 (0x227) - FLL EFS 2
+ */
+#define WM8996_FLL_LFSR_SEL_MASK                0x0006  /* FLL_LFSR_SEL - [2:1] */
+#define WM8996_FLL_LFSR_SEL_SHIFT                    1  /* FLL_LFSR_SEL - [2:1] */
+#define WM8996_FLL_LFSR_SEL_WIDTH                    2  /* FLL_LFSR_SEL - [2:1] */
+#define WM8996_FLL_EFS_ENA                      0x0001  /* FLL_EFS_ENA */
+#define WM8996_FLL_EFS_ENA_MASK                 0x0001  /* FLL_EFS_ENA */
+#define WM8996_FLL_EFS_ENA_SHIFT                     0  /* FLL_EFS_ENA */
+#define WM8996_FLL_EFS_ENA_WIDTH                     1  /* FLL_EFS_ENA */
+
+/*
+ * R768 (0x300) - AIF1 Control
+ */
+#define WM8996_AIF1_TRI                         0x0004  /* AIF1_TRI */
+#define WM8996_AIF1_TRI_MASK                    0x0004  /* AIF1_TRI */
+#define WM8996_AIF1_TRI_SHIFT                        2  /* AIF1_TRI */
+#define WM8996_AIF1_TRI_WIDTH                        1  /* AIF1_TRI */
+#define WM8996_AIF1_FMT_MASK                    0x0003  /* AIF1_FMT - [1:0] */
+#define WM8996_AIF1_FMT_SHIFT                        0  /* AIF1_FMT - [1:0] */
+#define WM8996_AIF1_FMT_WIDTH                        2  /* AIF1_FMT - [1:0] */
+
+/*
+ * R769 (0x301) - AIF1 BCLK
+ */
+#define WM8996_AIF1_BCLK_INV                    0x0400  /* AIF1_BCLK_INV */
+#define WM8996_AIF1_BCLK_INV_MASK               0x0400  /* AIF1_BCLK_INV */
+#define WM8996_AIF1_BCLK_INV_SHIFT                  10  /* AIF1_BCLK_INV */
+#define WM8996_AIF1_BCLK_INV_WIDTH                   1  /* AIF1_BCLK_INV */
+#define WM8996_AIF1_BCLK_FRC                    0x0200  /* AIF1_BCLK_FRC */
+#define WM8996_AIF1_BCLK_FRC_MASK               0x0200  /* AIF1_BCLK_FRC */
+#define WM8996_AIF1_BCLK_FRC_SHIFT                   9  /* AIF1_BCLK_FRC */
+#define WM8996_AIF1_BCLK_FRC_WIDTH                   1  /* AIF1_BCLK_FRC */
+#define WM8996_AIF1_BCLK_MSTR                   0x0100  /* AIF1_BCLK_MSTR */
+#define WM8996_AIF1_BCLK_MSTR_MASK              0x0100  /* AIF1_BCLK_MSTR */
+#define WM8996_AIF1_BCLK_MSTR_SHIFT                  8  /* AIF1_BCLK_MSTR */
+#define WM8996_AIF1_BCLK_MSTR_WIDTH                  1  /* AIF1_BCLK_MSTR */
+#define WM8996_AIF1_BCLK_DIV_MASK               0x000F  /* AIF1_BCLK_DIV - [3:0] */
+#define WM8996_AIF1_BCLK_DIV_SHIFT                   0  /* AIF1_BCLK_DIV - [3:0] */
+#define WM8996_AIF1_BCLK_DIV_WIDTH                   4  /* AIF1_BCLK_DIV - [3:0] */
+
+/*
+ * R770 (0x302) - AIF1 TX LRCLK(1)
+ */
+#define WM8996_AIF1TX_RATE_MASK                 0x07FF  /* AIF1TX_RATE - [10:0] */
+#define WM8996_AIF1TX_RATE_SHIFT                     0  /* AIF1TX_RATE - [10:0] */
+#define WM8996_AIF1TX_RATE_WIDTH                    11  /* AIF1TX_RATE - [10:0] */
+
+/*
+ * R771 (0x303) - AIF1 TX LRCLK(2)
+ */
+#define WM8996_AIF1TX_LRCLK_MODE                0x0008  /* AIF1TX_LRCLK_MODE */
+#define WM8996_AIF1TX_LRCLK_MODE_MASK           0x0008  /* AIF1TX_LRCLK_MODE */
+#define WM8996_AIF1TX_LRCLK_MODE_SHIFT               3  /* AIF1TX_LRCLK_MODE */
+#define WM8996_AIF1TX_LRCLK_MODE_WIDTH               1  /* AIF1TX_LRCLK_MODE */
+#define WM8996_AIF1TX_LRCLK_INV                 0x0004  /* AIF1TX_LRCLK_INV */
+#define WM8996_AIF1TX_LRCLK_INV_MASK            0x0004  /* AIF1TX_LRCLK_INV */
+#define WM8996_AIF1TX_LRCLK_INV_SHIFT                2  /* AIF1TX_LRCLK_INV */
+#define WM8996_AIF1TX_LRCLK_INV_WIDTH                1  /* AIF1TX_LRCLK_INV */
+#define WM8996_AIF1TX_LRCLK_FRC                 0x0002  /* AIF1TX_LRCLK_FRC */
+#define WM8996_AIF1TX_LRCLK_FRC_MASK            0x0002  /* AIF1TX_LRCLK_FRC */
+#define WM8996_AIF1TX_LRCLK_FRC_SHIFT                1  /* AIF1TX_LRCLK_FRC */
+#define WM8996_AIF1TX_LRCLK_FRC_WIDTH                1  /* AIF1TX_LRCLK_FRC */
+#define WM8996_AIF1TX_LRCLK_MSTR                0x0001  /* AIF1TX_LRCLK_MSTR */
+#define WM8996_AIF1TX_LRCLK_MSTR_MASK           0x0001  /* AIF1TX_LRCLK_MSTR */
+#define WM8996_AIF1TX_LRCLK_MSTR_SHIFT               0  /* AIF1TX_LRCLK_MSTR */
+#define WM8996_AIF1TX_LRCLK_MSTR_WIDTH               1  /* AIF1TX_LRCLK_MSTR */
+
+/*
+ * R772 (0x304) - AIF1 RX LRCLK(1)
+ */
+#define WM8996_AIF1RX_RATE_MASK                 0x07FF  /* AIF1RX_RATE - [10:0] */
+#define WM8996_AIF1RX_RATE_SHIFT                     0  /* AIF1RX_RATE - [10:0] */
+#define WM8996_AIF1RX_RATE_WIDTH                    11  /* AIF1RX_RATE - [10:0] */
+
+/*
+ * R773 (0x305) - AIF1 RX LRCLK(2)
+ */
+#define WM8996_AIF1RX_LRCLK_INV                 0x0004  /* AIF1RX_LRCLK_INV */
+#define WM8996_AIF1RX_LRCLK_INV_MASK            0x0004  /* AIF1RX_LRCLK_INV */
+#define WM8996_AIF1RX_LRCLK_INV_SHIFT                2  /* AIF1RX_LRCLK_INV */
+#define WM8996_AIF1RX_LRCLK_INV_WIDTH                1  /* AIF1RX_LRCLK_INV */
+#define WM8996_AIF1RX_LRCLK_FRC                 0x0002  /* AIF1RX_LRCLK_FRC */
+#define WM8996_AIF1RX_LRCLK_FRC_MASK            0x0002  /* AIF1RX_LRCLK_FRC */
+#define WM8996_AIF1RX_LRCLK_FRC_SHIFT                1  /* AIF1RX_LRCLK_FRC */
+#define WM8996_AIF1RX_LRCLK_FRC_WIDTH                1  /* AIF1RX_LRCLK_FRC */
+#define WM8996_AIF1RX_LRCLK_MSTR                0x0001  /* AIF1RX_LRCLK_MSTR */
+#define WM8996_AIF1RX_LRCLK_MSTR_MASK           0x0001  /* AIF1RX_LRCLK_MSTR */
+#define WM8996_AIF1RX_LRCLK_MSTR_SHIFT               0  /* AIF1RX_LRCLK_MSTR */
+#define WM8996_AIF1RX_LRCLK_MSTR_WIDTH               1  /* AIF1RX_LRCLK_MSTR */
+
+/*
+ * R774 (0x306) - AIF1TX Data Configuration (1)
+ */
+#define WM8996_AIF1TX_WL_MASK                   0xFF00  /* AIF1TX_WL - [15:8] */
+#define WM8996_AIF1TX_WL_SHIFT                       8  /* AIF1TX_WL - [15:8] */
+#define WM8996_AIF1TX_WL_WIDTH                       8  /* AIF1TX_WL - [15:8] */
+#define WM8996_AIF1TX_SLOT_LEN_MASK             0x00FF  /* AIF1TX_SLOT_LEN - [7:0] */
+#define WM8996_AIF1TX_SLOT_LEN_SHIFT                 0  /* AIF1TX_SLOT_LEN - [7:0] */
+#define WM8996_AIF1TX_SLOT_LEN_WIDTH                 8  /* AIF1TX_SLOT_LEN - [7:0] */
+
+/*
+ * R775 (0x307) - AIF1TX Data Configuration (2)
+ */
+#define WM8996_AIF1TX_DAT_TRI                   0x0001  /* AIF1TX_DAT_TRI */
+#define WM8996_AIF1TX_DAT_TRI_MASK              0x0001  /* AIF1TX_DAT_TRI */
+#define WM8996_AIF1TX_DAT_TRI_SHIFT                  0  /* AIF1TX_DAT_TRI */
+#define WM8996_AIF1TX_DAT_TRI_WIDTH                  1  /* AIF1TX_DAT_TRI */
+
+/*
+ * R776 (0x308) - AIF1RX Data Configuration
+ */
+#define WM8996_AIF1RX_WL_MASK                   0xFF00  /* AIF1RX_WL - [15:8] */
+#define WM8996_AIF1RX_WL_SHIFT                       8  /* AIF1RX_WL - [15:8] */
+#define WM8996_AIF1RX_WL_WIDTH                       8  /* AIF1RX_WL - [15:8] */
+#define WM8996_AIF1RX_SLOT_LEN_MASK             0x00FF  /* AIF1RX_SLOT_LEN - [7:0] */
+#define WM8996_AIF1RX_SLOT_LEN_SHIFT                 0  /* AIF1RX_SLOT_LEN - [7:0] */
+#define WM8996_AIF1RX_SLOT_LEN_WIDTH                 8  /* AIF1RX_SLOT_LEN - [7:0] */
+
+/*
+ * R777 (0x309) - AIF1TX Channel 0 Configuration
+ */
+#define WM8996_AIF1TX_CHAN0_DAT_INV             0x8000  /* AIF1TX_CHAN0_DAT_INV */
+#define WM8996_AIF1TX_CHAN0_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN0_DAT_INV */
+#define WM8996_AIF1TX_CHAN0_DAT_INV_SHIFT           15  /* AIF1TX_CHAN0_DAT_INV */
+#define WM8996_AIF1TX_CHAN0_DAT_INV_WIDTH            1  /* AIF1TX_CHAN0_DAT_INV */
+#define WM8996_AIF1TX_CHAN0_SPACING_MASK        0x7E00  /* AIF1TX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN0_SPACING_SHIFT            9  /* AIF1TX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN0_SPACING_WIDTH            6  /* AIF1TX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN0_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN0_SLOTS_SHIFT              6  /* AIF1TX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN0_SLOTS_WIDTH              3  /* AIF1TX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN0_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN0_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN0_START_SLOT_SHIFT         0  /* AIF1TX_CHAN0_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN0_START_SLOT_WIDTH         6  /* AIF1TX_CHAN0_START_SLOT - [5:0] */
+
+/*
+ * R778 (0x30A) - AIF1TX Channel 1 Configuration
+ */
+#define WM8996_AIF1TX_CHAN1_DAT_INV             0x8000  /* AIF1TX_CHAN1_DAT_INV */
+#define WM8996_AIF1TX_CHAN1_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN1_DAT_INV */
+#define WM8996_AIF1TX_CHAN1_DAT_INV_SHIFT           15  /* AIF1TX_CHAN1_DAT_INV */
+#define WM8996_AIF1TX_CHAN1_DAT_INV_WIDTH            1  /* AIF1TX_CHAN1_DAT_INV */
+#define WM8996_AIF1TX_CHAN1_SPACING_MASK        0x7E00  /* AIF1TX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN1_SPACING_SHIFT            9  /* AIF1TX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN1_SPACING_WIDTH            6  /* AIF1TX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN1_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN1_SLOTS_SHIFT              6  /* AIF1TX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN1_SLOTS_WIDTH              3  /* AIF1TX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN1_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN1_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN1_START_SLOT_SHIFT         0  /* AIF1TX_CHAN1_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN1_START_SLOT_WIDTH         6  /* AIF1TX_CHAN1_START_SLOT - [5:0] */
+
+/*
+ * R779 (0x30B) - AIF1TX Channel 2 Configuration
+ */
+#define WM8996_AIF1TX_CHAN2_DAT_INV             0x8000  /* AIF1TX_CHAN2_DAT_INV */
+#define WM8996_AIF1TX_CHAN2_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN2_DAT_INV */
+#define WM8996_AIF1TX_CHAN2_DAT_INV_SHIFT           15  /* AIF1TX_CHAN2_DAT_INV */
+#define WM8996_AIF1TX_CHAN2_DAT_INV_WIDTH            1  /* AIF1TX_CHAN2_DAT_INV */
+#define WM8996_AIF1TX_CHAN2_SPACING_MASK        0x7E00  /* AIF1TX_CHAN2_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN2_SPACING_SHIFT            9  /* AIF1TX_CHAN2_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN2_SPACING_WIDTH            6  /* AIF1TX_CHAN2_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN2_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN2_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN2_SLOTS_SHIFT              6  /* AIF1TX_CHAN2_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN2_SLOTS_WIDTH              3  /* AIF1TX_CHAN2_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN2_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN2_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN2_START_SLOT_SHIFT         0  /* AIF1TX_CHAN2_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN2_START_SLOT_WIDTH         6  /* AIF1TX_CHAN2_START_SLOT - [5:0] */
+
+/*
+ * R780 (0x30C) - AIF1TX Channel 3 Configuration
+ */
+#define WM8996_AIF1TX_CHAN3_DAT_INV             0x8000  /* AIF1TX_CHAN3_DAT_INV */
+#define WM8996_AIF1TX_CHAN3_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN3_DAT_INV */
+#define WM8996_AIF1TX_CHAN3_DAT_INV_SHIFT           15  /* AIF1TX_CHAN3_DAT_INV */
+#define WM8996_AIF1TX_CHAN3_DAT_INV_WIDTH            1  /* AIF1TX_CHAN3_DAT_INV */
+#define WM8996_AIF1TX_CHAN3_SPACING_MASK        0x7E00  /* AIF1TX_CHAN3_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN3_SPACING_SHIFT            9  /* AIF1TX_CHAN3_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN3_SPACING_WIDTH            6  /* AIF1TX_CHAN3_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN3_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN3_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN3_SLOTS_SHIFT              6  /* AIF1TX_CHAN3_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN3_SLOTS_WIDTH              3  /* AIF1TX_CHAN3_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN3_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN3_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN3_START_SLOT_SHIFT         0  /* AIF1TX_CHAN3_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN3_START_SLOT_WIDTH         6  /* AIF1TX_CHAN3_START_SLOT - [5:0] */
+
+/*
+ * R781 (0x30D) - AIF1TX Channel 4 Configuration
+ */
+#define WM8996_AIF1TX_CHAN4_DAT_INV             0x8000  /* AIF1TX_CHAN4_DAT_INV */
+#define WM8996_AIF1TX_CHAN4_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN4_DAT_INV */
+#define WM8996_AIF1TX_CHAN4_DAT_INV_SHIFT           15  /* AIF1TX_CHAN4_DAT_INV */
+#define WM8996_AIF1TX_CHAN4_DAT_INV_WIDTH            1  /* AIF1TX_CHAN4_DAT_INV */
+#define WM8996_AIF1TX_CHAN4_SPACING_MASK        0x7E00  /* AIF1TX_CHAN4_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN4_SPACING_SHIFT            9  /* AIF1TX_CHAN4_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN4_SPACING_WIDTH            6  /* AIF1TX_CHAN4_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN4_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN4_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN4_SLOTS_SHIFT              6  /* AIF1TX_CHAN4_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN4_SLOTS_WIDTH              3  /* AIF1TX_CHAN4_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN4_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN4_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN4_START_SLOT_SHIFT         0  /* AIF1TX_CHAN4_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN4_START_SLOT_WIDTH         6  /* AIF1TX_CHAN4_START_SLOT - [5:0] */
+
+/*
+ * R782 (0x30E) - AIF1TX Channel 5 Configuration
+ */
+#define WM8996_AIF1TX_CHAN5_DAT_INV             0x8000  /* AIF1TX_CHAN5_DAT_INV */
+#define WM8996_AIF1TX_CHAN5_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN5_DAT_INV */
+#define WM8996_AIF1TX_CHAN5_DAT_INV_SHIFT           15  /* AIF1TX_CHAN5_DAT_INV */
+#define WM8996_AIF1TX_CHAN5_DAT_INV_WIDTH            1  /* AIF1TX_CHAN5_DAT_INV */
+#define WM8996_AIF1TX_CHAN5_SPACING_MASK        0x7E00  /* AIF1TX_CHAN5_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN5_SPACING_SHIFT            9  /* AIF1TX_CHAN5_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN5_SPACING_WIDTH            6  /* AIF1TX_CHAN5_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN5_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN5_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN5_SLOTS_SHIFT              6  /* AIF1TX_CHAN5_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN5_SLOTS_WIDTH              3  /* AIF1TX_CHAN5_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN5_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN5_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN5_START_SLOT_SHIFT         0  /* AIF1TX_CHAN5_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN5_START_SLOT_WIDTH         6  /* AIF1TX_CHAN5_START_SLOT - [5:0] */
+
+/*
+ * R783 (0x30F) - AIF1RX Channel 0 Configuration
+ */
+#define WM8996_AIF1RX_CHAN0_DAT_INV             0x8000  /* AIF1RX_CHAN0_DAT_INV */
+#define WM8996_AIF1RX_CHAN0_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN0_DAT_INV */
+#define WM8996_AIF1RX_CHAN0_DAT_INV_SHIFT           15  /* AIF1RX_CHAN0_DAT_INV */
+#define WM8996_AIF1RX_CHAN0_DAT_INV_WIDTH            1  /* AIF1RX_CHAN0_DAT_INV */
+#define WM8996_AIF1RX_CHAN0_SPACING_MASK        0x7E00  /* AIF1RX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN0_SPACING_SHIFT            9  /* AIF1RX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN0_SPACING_WIDTH            6  /* AIF1RX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN0_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN0_SLOTS_SHIFT              6  /* AIF1RX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN0_SLOTS_WIDTH              3  /* AIF1RX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN0_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN0_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN0_START_SLOT_SHIFT         0  /* AIF1RX_CHAN0_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN0_START_SLOT_WIDTH         6  /* AIF1RX_CHAN0_START_SLOT - [5:0] */
+
+/*
+ * R784 (0x310) - AIF1RX Channel 1 Configuration
+ */
+#define WM8996_AIF1RX_CHAN1_DAT_INV             0x8000  /* AIF1RX_CHAN1_DAT_INV */
+#define WM8996_AIF1RX_CHAN1_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN1_DAT_INV */
+#define WM8996_AIF1RX_CHAN1_DAT_INV_SHIFT           15  /* AIF1RX_CHAN1_DAT_INV */
+#define WM8996_AIF1RX_CHAN1_DAT_INV_WIDTH            1  /* AIF1RX_CHAN1_DAT_INV */
+#define WM8996_AIF1RX_CHAN1_SPACING_MASK        0x7E00  /* AIF1RX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN1_SPACING_SHIFT            9  /* AIF1RX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN1_SPACING_WIDTH            6  /* AIF1RX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN1_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN1_SLOTS_SHIFT              6  /* AIF1RX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN1_SLOTS_WIDTH              3  /* AIF1RX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN1_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN1_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN1_START_SLOT_SHIFT         0  /* AIF1RX_CHAN1_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN1_START_SLOT_WIDTH         6  /* AIF1RX_CHAN1_START_SLOT - [5:0] */
+
+/*
+ * R785 (0x311) - AIF1RX Channel 2 Configuration
+ */
+#define WM8996_AIF1RX_CHAN2_DAT_INV             0x8000  /* AIF1RX_CHAN2_DAT_INV */
+#define WM8996_AIF1RX_CHAN2_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN2_DAT_INV */
+#define WM8996_AIF1RX_CHAN2_DAT_INV_SHIFT           15  /* AIF1RX_CHAN2_DAT_INV */
+#define WM8996_AIF1RX_CHAN2_DAT_INV_WIDTH            1  /* AIF1RX_CHAN2_DAT_INV */
+#define WM8996_AIF1RX_CHAN2_SPACING_MASK        0x7E00  /* AIF1RX_CHAN2_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN2_SPACING_SHIFT            9  /* AIF1RX_CHAN2_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN2_SPACING_WIDTH            6  /* AIF1RX_CHAN2_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN2_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN2_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN2_SLOTS_SHIFT              6  /* AIF1RX_CHAN2_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN2_SLOTS_WIDTH              3  /* AIF1RX_CHAN2_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN2_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN2_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN2_START_SLOT_SHIFT         0  /* AIF1RX_CHAN2_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN2_START_SLOT_WIDTH         6  /* AIF1RX_CHAN2_START_SLOT - [5:0] */
+
+/*
+ * R786 (0x312) - AIF1RX Channel 3 Configuration
+ */
+#define WM8996_AIF1RX_CHAN3_DAT_INV             0x8000  /* AIF1RX_CHAN3_DAT_INV */
+#define WM8996_AIF1RX_CHAN3_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN3_DAT_INV */
+#define WM8996_AIF1RX_CHAN3_DAT_INV_SHIFT           15  /* AIF1RX_CHAN3_DAT_INV */
+#define WM8996_AIF1RX_CHAN3_DAT_INV_WIDTH            1  /* AIF1RX_CHAN3_DAT_INV */
+#define WM8996_AIF1RX_CHAN3_SPACING_MASK        0x7E00  /* AIF1RX_CHAN3_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN3_SPACING_SHIFT            9  /* AIF1RX_CHAN3_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN3_SPACING_WIDTH            6  /* AIF1RX_CHAN3_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN3_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN3_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN3_SLOTS_SHIFT              6  /* AIF1RX_CHAN3_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN3_SLOTS_WIDTH              3  /* AIF1RX_CHAN3_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN3_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN3_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN3_START_SLOT_SHIFT         0  /* AIF1RX_CHAN3_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN3_START_SLOT_WIDTH         6  /* AIF1RX_CHAN3_START_SLOT - [5:0] */
+
+/*
+ * R787 (0x313) - AIF1RX Channel 4 Configuration
+ */
+#define WM8996_AIF1RX_CHAN4_DAT_INV             0x8000  /* AIF1RX_CHAN4_DAT_INV */
+#define WM8996_AIF1RX_CHAN4_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN4_DAT_INV */
+#define WM8996_AIF1RX_CHAN4_DAT_INV_SHIFT           15  /* AIF1RX_CHAN4_DAT_INV */
+#define WM8996_AIF1RX_CHAN4_DAT_INV_WIDTH            1  /* AIF1RX_CHAN4_DAT_INV */
+#define WM8996_AIF1RX_CHAN4_SPACING_MASK        0x7E00  /* AIF1RX_CHAN4_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN4_SPACING_SHIFT            9  /* AIF1RX_CHAN4_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN4_SPACING_WIDTH            6  /* AIF1RX_CHAN4_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN4_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN4_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN4_SLOTS_SHIFT              6  /* AIF1RX_CHAN4_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN4_SLOTS_WIDTH              3  /* AIF1RX_CHAN4_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN4_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN4_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN4_START_SLOT_SHIFT         0  /* AIF1RX_CHAN4_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN4_START_SLOT_WIDTH         6  /* AIF1RX_CHAN4_START_SLOT - [5:0] */
+
+/*
+ * R788 (0x314) - AIF1RX Channel 5 Configuration
+ */
+#define WM8996_AIF1RX_CHAN5_DAT_INV             0x8000  /* AIF1RX_CHAN5_DAT_INV */
+#define WM8996_AIF1RX_CHAN5_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN5_DAT_INV */
+#define WM8996_AIF1RX_CHAN5_DAT_INV_SHIFT           15  /* AIF1RX_CHAN5_DAT_INV */
+#define WM8996_AIF1RX_CHAN5_DAT_INV_WIDTH            1  /* AIF1RX_CHAN5_DAT_INV */
+#define WM8996_AIF1RX_CHAN5_SPACING_MASK        0x7E00  /* AIF1RX_CHAN5_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN5_SPACING_SHIFT            9  /* AIF1RX_CHAN5_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN5_SPACING_WIDTH            6  /* AIF1RX_CHAN5_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN5_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN5_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN5_SLOTS_SHIFT              6  /* AIF1RX_CHAN5_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN5_SLOTS_WIDTH              3  /* AIF1RX_CHAN5_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN5_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN5_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN5_START_SLOT_SHIFT         0  /* AIF1RX_CHAN5_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN5_START_SLOT_WIDTH         6  /* AIF1RX_CHAN5_START_SLOT - [5:0] */
+
+/*
+ * R789 (0x315) - AIF1RX Mono Configuration
+ */
+#define WM8996_AIF1RX_CHAN4_MONO_MODE           0x0004  /* AIF1RX_CHAN4_MONO_MODE */
+#define WM8996_AIF1RX_CHAN4_MONO_MODE_MASK      0x0004  /* AIF1RX_CHAN4_MONO_MODE */
+#define WM8996_AIF1RX_CHAN4_MONO_MODE_SHIFT          2  /* AIF1RX_CHAN4_MONO_MODE */
+#define WM8996_AIF1RX_CHAN4_MONO_MODE_WIDTH          1  /* AIF1RX_CHAN4_MONO_MODE */
+#define WM8996_AIF1RX_CHAN2_MONO_MODE           0x0002  /* AIF1RX_CHAN2_MONO_MODE */
+#define WM8996_AIF1RX_CHAN2_MONO_MODE_MASK      0x0002  /* AIF1RX_CHAN2_MONO_MODE */
+#define WM8996_AIF1RX_CHAN2_MONO_MODE_SHIFT          1  /* AIF1RX_CHAN2_MONO_MODE */
+#define WM8996_AIF1RX_CHAN2_MONO_MODE_WIDTH          1  /* AIF1RX_CHAN2_MONO_MODE */
+#define WM8996_AIF1RX_CHAN0_MONO_MODE           0x0001  /* AIF1RX_CHAN0_MONO_MODE */
+#define WM8996_AIF1RX_CHAN0_MONO_MODE_MASK      0x0001  /* AIF1RX_CHAN0_MONO_MODE */
+#define WM8996_AIF1RX_CHAN0_MONO_MODE_SHIFT          0  /* AIF1RX_CHAN0_MONO_MODE */
+#define WM8996_AIF1RX_CHAN0_MONO_MODE_WIDTH          1  /* AIF1RX_CHAN0_MONO_MODE */
+
+/*
+ * R794 (0x31A) - AIF1TX Test
+ */
+#define WM8996_AIF1TX45_DITHER_ENA              0x0004  /* AIF1TX45_DITHER_ENA */
+#define WM8996_AIF1TX45_DITHER_ENA_MASK         0x0004  /* AIF1TX45_DITHER_ENA */
+#define WM8996_AIF1TX45_DITHER_ENA_SHIFT             2  /* AIF1TX45_DITHER_ENA */
+#define WM8996_AIF1TX45_DITHER_ENA_WIDTH             1  /* AIF1TX45_DITHER_ENA */
+#define WM8996_AIF1TX23_DITHER_ENA              0x0002  /* AIF1TX23_DITHER_ENA */
+#define WM8996_AIF1TX23_DITHER_ENA_MASK         0x0002  /* AIF1TX23_DITHER_ENA */
+#define WM8996_AIF1TX23_DITHER_ENA_SHIFT             1  /* AIF1TX23_DITHER_ENA */
+#define WM8996_AIF1TX23_DITHER_ENA_WIDTH             1  /* AIF1TX23_DITHER_ENA */
+#define WM8996_AIF1TX01_DITHER_ENA              0x0001  /* AIF1TX01_DITHER_ENA */
+#define WM8996_AIF1TX01_DITHER_ENA_MASK         0x0001  /* AIF1TX01_DITHER_ENA */
+#define WM8996_AIF1TX01_DITHER_ENA_SHIFT             0  /* AIF1TX01_DITHER_ENA */
+#define WM8996_AIF1TX01_DITHER_ENA_WIDTH             1  /* AIF1TX01_DITHER_ENA */
+
+/*
+ * R800 (0x320) - AIF2 Control
+ */
+#define WM8996_AIF2_TRI                         0x0004  /* AIF2_TRI */
+#define WM8996_AIF2_TRI_MASK                    0x0004  /* AIF2_TRI */
+#define WM8996_AIF2_TRI_SHIFT                        2  /* AIF2_TRI */
+#define WM8996_AIF2_TRI_WIDTH                        1  /* AIF2_TRI */
+#define WM8996_AIF2_FMT_MASK                    0x0003  /* AIF2_FMT - [1:0] */
+#define WM8996_AIF2_FMT_SHIFT                        0  /* AIF2_FMT - [1:0] */
+#define WM8996_AIF2_FMT_WIDTH                        2  /* AIF2_FMT - [1:0] */
+
+/*
+ * R801 (0x321) - AIF2 BCLK
+ */
+#define WM8996_AIF2_BCLK_INV                    0x0400  /* AIF2_BCLK_INV */
+#define WM8996_AIF2_BCLK_INV_MASK               0x0400  /* AIF2_BCLK_INV */
+#define WM8996_AIF2_BCLK_INV_SHIFT                  10  /* AIF2_BCLK_INV */
+#define WM8996_AIF2_BCLK_INV_WIDTH                   1  /* AIF2_BCLK_INV */
+#define WM8996_AIF2_BCLK_FRC                    0x0200  /* AIF2_BCLK_FRC */
+#define WM8996_AIF2_BCLK_FRC_MASK               0x0200  /* AIF2_BCLK_FRC */
+#define WM8996_AIF2_BCLK_FRC_SHIFT                   9  /* AIF2_BCLK_FRC */
+#define WM8996_AIF2_BCLK_FRC_WIDTH                   1  /* AIF2_BCLK_FRC */
+#define WM8996_AIF2_BCLK_MSTR                   0x0100  /* AIF2_BCLK_MSTR */
+#define WM8996_AIF2_BCLK_MSTR_MASK              0x0100  /* AIF2_BCLK_MSTR */
+#define WM8996_AIF2_BCLK_MSTR_SHIFT                  8  /* AIF2_BCLK_MSTR */
+#define WM8996_AIF2_BCLK_MSTR_WIDTH                  1  /* AIF2_BCLK_MSTR */
+#define WM8996_AIF2_BCLK_DIV_MASK               0x000F  /* AIF2_BCLK_DIV - [3:0] */
+#define WM8996_AIF2_BCLK_DIV_SHIFT                   0  /* AIF2_BCLK_DIV - [3:0] */
+#define WM8996_AIF2_BCLK_DIV_WIDTH                   4  /* AIF2_BCLK_DIV - [3:0] */
+
+/*
+ * R802 (0x322) - AIF2 TX LRCLK(1)
+ */
+#define WM8996_AIF2TX_RATE_MASK                 0x07FF  /* AIF2TX_RATE - [10:0] */
+#define WM8996_AIF2TX_RATE_SHIFT                     0  /* AIF2TX_RATE - [10:0] */
+#define WM8996_AIF2TX_RATE_WIDTH                    11  /* AIF2TX_RATE - [10:0] */
+
+/*
+ * R803 (0x323) - AIF2 TX LRCLK(2)
+ */
+#define WM8996_AIF2TX_LRCLK_MODE                0x0008  /* AIF2TX_LRCLK_MODE */
+#define WM8996_AIF2TX_LRCLK_MODE_MASK           0x0008  /* AIF2TX_LRCLK_MODE */
+#define WM8996_AIF2TX_LRCLK_MODE_SHIFT               3  /* AIF2TX_LRCLK_MODE */
+#define WM8996_AIF2TX_LRCLK_MODE_WIDTH               1  /* AIF2TX_LRCLK_MODE */
+#define WM8996_AIF2TX_LRCLK_INV                 0x0004  /* AIF2TX_LRCLK_INV */
+#define WM8996_AIF2TX_LRCLK_INV_MASK            0x0004  /* AIF2TX_LRCLK_INV */
+#define WM8996_AIF2TX_LRCLK_INV_SHIFT                2  /* AIF2TX_LRCLK_INV */
+#define WM8996_AIF2TX_LRCLK_INV_WIDTH                1  /* AIF2TX_LRCLK_INV */
+#define WM8996_AIF2TX_LRCLK_FRC                 0x0002  /* AIF2TX_LRCLK_FRC */
+#define WM8996_AIF2TX_LRCLK_FRC_MASK            0x0002  /* AIF2TX_LRCLK_FRC */
+#define WM8996_AIF2TX_LRCLK_FRC_SHIFT                1  /* AIF2TX_LRCLK_FRC */
+#define WM8996_AIF2TX_LRCLK_FRC_WIDTH                1  /* AIF2TX_LRCLK_FRC */
+#define WM8996_AIF2TX_LRCLK_MSTR                0x0001  /* AIF2TX_LRCLK_MSTR */
+#define WM8996_AIF2TX_LRCLK_MSTR_MASK           0x0001  /* AIF2TX_LRCLK_MSTR */
+#define WM8996_AIF2TX_LRCLK_MSTR_SHIFT               0  /* AIF2TX_LRCLK_MSTR */
+#define WM8996_AIF2TX_LRCLK_MSTR_WIDTH               1  /* AIF2TX_LRCLK_MSTR */
+
+/*
+ * R804 (0x324) - AIF2 RX LRCLK(1)
+ */
+#define WM8996_AIF2RX_RATE_MASK                 0x07FF  /* AIF2RX_RATE - [10:0] */
+#define WM8996_AIF2RX_RATE_SHIFT                     0  /* AIF2RX_RATE - [10:0] */
+#define WM8996_AIF2RX_RATE_WIDTH                    11  /* AIF2RX_RATE - [10:0] */
+
+/*
+ * R805 (0x325) - AIF2 RX LRCLK(2)
+ */
+#define WM8996_AIF2RX_LRCLK_INV                 0x0004  /* AIF2RX_LRCLK_INV */
+#define WM8996_AIF2RX_LRCLK_INV_MASK            0x0004  /* AIF2RX_LRCLK_INV */
+#define WM8996_AIF2RX_LRCLK_INV_SHIFT                2  /* AIF2RX_LRCLK_INV */
+#define WM8996_AIF2RX_LRCLK_INV_WIDTH                1  /* AIF2RX_LRCLK_INV */
+#define WM8996_AIF2RX_LRCLK_FRC                 0x0002  /* AIF2RX_LRCLK_FRC */
+#define WM8996_AIF2RX_LRCLK_FRC_MASK            0x0002  /* AIF2RX_LRCLK_FRC */
+#define WM8996_AIF2RX_LRCLK_FRC_SHIFT                1  /* AIF2RX_LRCLK_FRC */
+#define WM8996_AIF2RX_LRCLK_FRC_WIDTH                1  /* AIF2RX_LRCLK_FRC */
+#define WM8996_AIF2RX_LRCLK_MSTR                0x0001  /* AIF2RX_LRCLK_MSTR */
+#define WM8996_AIF2RX_LRCLK_MSTR_MASK           0x0001  /* AIF2RX_LRCLK_MSTR */
+#define WM8996_AIF2RX_LRCLK_MSTR_SHIFT               0  /* AIF2RX_LRCLK_MSTR */
+#define WM8996_AIF2RX_LRCLK_MSTR_WIDTH               1  /* AIF2RX_LRCLK_MSTR */
+
+/*
+ * R806 (0x326) - AIF2TX Data Configuration (1)
+ */
+#define WM8996_AIF2TX_WL_MASK                   0xFF00  /* AIF2TX_WL - [15:8] */
+#define WM8996_AIF2TX_WL_SHIFT                       8  /* AIF2TX_WL - [15:8] */
+#define WM8996_AIF2TX_WL_WIDTH                       8  /* AIF2TX_WL - [15:8] */
+#define WM8996_AIF2TX_SLOT_LEN_MASK             0x00FF  /* AIF2TX_SLOT_LEN - [7:0] */
+#define WM8996_AIF2TX_SLOT_LEN_SHIFT                 0  /* AIF2TX_SLOT_LEN - [7:0] */
+#define WM8996_AIF2TX_SLOT_LEN_WIDTH                 8  /* AIF2TX_SLOT_LEN - [7:0] */
+
+/*
+ * R807 (0x327) - AIF2TX Data Configuration (2)
+ */
+#define WM8996_AIF2TX_DAT_TRI                   0x0001  /* AIF2TX_DAT_TRI */
+#define WM8996_AIF2TX_DAT_TRI_MASK              0x0001  /* AIF2TX_DAT_TRI */
+#define WM8996_AIF2TX_DAT_TRI_SHIFT                  0  /* AIF2TX_DAT_TRI */
+#define WM8996_AIF2TX_DAT_TRI_WIDTH                  1  /* AIF2TX_DAT_TRI */
+
+/*
+ * R808 (0x328) - AIF2RX Data Configuration
+ */
+#define WM8996_AIF2RX_WL_MASK                   0xFF00  /* AIF2RX_WL - [15:8] */
+#define WM8996_AIF2RX_WL_SHIFT                       8  /* AIF2RX_WL - [15:8] */
+#define WM8996_AIF2RX_WL_WIDTH                       8  /* AIF2RX_WL - [15:8] */
+#define WM8996_AIF2RX_SLOT_LEN_MASK             0x00FF  /* AIF2RX_SLOT_LEN - [7:0] */
+#define WM8996_AIF2RX_SLOT_LEN_SHIFT                 0  /* AIF2RX_SLOT_LEN - [7:0] */
+#define WM8996_AIF2RX_SLOT_LEN_WIDTH                 8  /* AIF2RX_SLOT_LEN - [7:0] */
+
+/*
+ * R809 (0x329) - AIF2TX Channel 0 Configuration
+ */
+#define WM8996_AIF2TX_CHAN0_DAT_INV             0x8000  /* AIF2TX_CHAN0_DAT_INV */
+#define WM8996_AIF2TX_CHAN0_DAT_INV_MASK        0x8000  /* AIF2TX_CHAN0_DAT_INV */
+#define WM8996_AIF2TX_CHAN0_DAT_INV_SHIFT           15  /* AIF2TX_CHAN0_DAT_INV */
+#define WM8996_AIF2TX_CHAN0_DAT_INV_WIDTH            1  /* AIF2TX_CHAN0_DAT_INV */
+#define WM8996_AIF2TX_CHAN0_SPACING_MASK        0x7E00  /* AIF2TX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF2TX_CHAN0_SPACING_SHIFT            9  /* AIF2TX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF2TX_CHAN0_SPACING_WIDTH            6  /* AIF2TX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF2TX_CHAN0_SLOTS_MASK          0x01C0  /* AIF2TX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF2TX_CHAN0_SLOTS_SHIFT              6  /* AIF2TX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF2TX_CHAN0_SLOTS_WIDTH              3  /* AIF2TX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF2TX_CHAN0_START_SLOT_MASK     0x003F  /* AIF2TX_CHAN0_START_SLOT - [5:0] */
+#define WM8996_AIF2TX_CHAN0_START_SLOT_SHIFT         0  /* AIF2TX_CHAN0_START_SLOT - [5:0] */
+#define WM8996_AIF2TX_CHAN0_START_SLOT_WIDTH         6  /* AIF2TX_CHAN0_START_SLOT - [5:0] */
+
+/*
+ * R810 (0x32A) - AIF2TX Channel 1 Configuration
+ */
+#define WM8996_AIF2TX_CHAN1_DAT_INV             0x8000  /* AIF2TX_CHAN1_DAT_INV */
+#define WM8996_AIF2TX_CHAN1_DAT_INV_MASK        0x8000  /* AIF2TX_CHAN1_DAT_INV */
+#define WM8996_AIF2TX_CHAN1_DAT_INV_SHIFT           15  /* AIF2TX_CHAN1_DAT_INV */
+#define WM8996_AIF2TX_CHAN1_DAT_INV_WIDTH            1  /* AIF2TX_CHAN1_DAT_INV */
+#define WM8996_AIF2TX_CHAN1_SPACING_MASK        0x7E00  /* AIF2TX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF2TX_CHAN1_SPACING_SHIFT            9  /* AIF2TX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF2TX_CHAN1_SPACING_WIDTH            6  /* AIF2TX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF2TX_CHAN1_SLOTS_MASK          0x01C0  /* AIF2TX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF2TX_CHAN1_SLOTS_SHIFT              6  /* AIF2TX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF2TX_CHAN1_SLOTS_WIDTH              3  /* AIF2TX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF2TX_CHAN1_START_SLOT_MASK     0x003F  /* AIF2TX_CHAN1_START_SLOT - [5:0] */
+#define WM8996_AIF2TX_CHAN1_START_SLOT_SHIFT         0  /* AIF2TX_CHAN1_START_SLOT - [5:0] */
+#define WM8996_AIF2TX_CHAN1_START_SLOT_WIDTH         6  /* AIF2TX_CHAN1_START_SLOT - [5:0] */
+
+/*
+ * R811 (0x32B) - AIF2RX Channel 0 Configuration
+ */
+#define WM8996_AIF2RX_CHAN0_DAT_INV             0x8000  /* AIF2RX_CHAN0_DAT_INV */
+#define WM8996_AIF2RX_CHAN0_DAT_INV_MASK        0x8000  /* AIF2RX_CHAN0_DAT_INV */
+#define WM8996_AIF2RX_CHAN0_DAT_INV_SHIFT           15  /* AIF2RX_CHAN0_DAT_INV */
+#define WM8996_AIF2RX_CHAN0_DAT_INV_WIDTH            1  /* AIF2RX_CHAN0_DAT_INV */
+#define WM8996_AIF2RX_CHAN0_SPACING_MASK        0x7E00  /* AIF2RX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF2RX_CHAN0_SPACING_SHIFT            9  /* AIF2RX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF2RX_CHAN0_SPACING_WIDTH            6  /* AIF2RX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF2RX_CHAN0_SLOTS_MASK          0x01C0  /* AIF2RX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF2RX_CHAN0_SLOTS_SHIFT              6  /* AIF2RX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF2RX_CHAN0_SLOTS_WIDTH              3  /* AIF2RX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF2RX_CHAN0_START_SLOT_MASK     0x003F  /* AIF2RX_CHAN0_START_SLOT - [5:0] */
+#define WM8996_AIF2RX_CHAN0_START_SLOT_SHIFT         0  /* AIF2RX_CHAN0_START_SLOT - [5:0] */
+#define WM8996_AIF2RX_CHAN0_START_SLOT_WIDTH         6  /* AIF2RX_CHAN0_START_SLOT - [5:0] */
+
+/*
+ * R812 (0x32C) - AIF2RX Channel 1 Configuration
+ */
+#define WM8996_AIF2RX_CHAN1_DAT_INV             0x8000  /* AIF2RX_CHAN1_DAT_INV */
+#define WM8996_AIF2RX_CHAN1_DAT_INV_MASK        0x8000  /* AIF2RX_CHAN1_DAT_INV */
+#define WM8996_AIF2RX_CHAN1_DAT_INV_SHIFT           15  /* AIF2RX_CHAN1_DAT_INV */
+#define WM8996_AIF2RX_CHAN1_DAT_INV_WIDTH            1  /* AIF2RX_CHAN1_DAT_INV */
+#define WM8996_AIF2RX_CHAN1_SPACING_MASK        0x7E00  /* AIF2RX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF2RX_CHAN1_SPACING_SHIFT            9  /* AIF2RX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF2RX_CHAN1_SPACING_WIDTH            6  /* AIF2RX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF2RX_CHAN1_SLOTS_MASK          0x01C0  /* AIF2RX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF2RX_CHAN1_SLOTS_SHIFT              6  /* AIF2RX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF2RX_CHAN1_SLOTS_WIDTH              3  /* AIF2RX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF2RX_CHAN1_START_SLOT_MASK     0x003F  /* AIF2RX_CHAN1_START_SLOT - [5:0] */
+#define WM8996_AIF2RX_CHAN1_START_SLOT_SHIFT         0  /* AIF2RX_CHAN1_START_SLOT - [5:0] */
+#define WM8996_AIF2RX_CHAN1_START_SLOT_WIDTH         6  /* AIF2RX_CHAN1_START_SLOT - [5:0] */
+
+/*
+ * R813 (0x32D) - AIF2RX Mono Configuration
+ */
+#define WM8996_AIF2RX_CHAN0_MONO_MODE           0x0001  /* AIF2RX_CHAN0_MONO_MODE */
+#define WM8996_AIF2RX_CHAN0_MONO_MODE_MASK      0x0001  /* AIF2RX_CHAN0_MONO_MODE */
+#define WM8996_AIF2RX_CHAN0_MONO_MODE_SHIFT          0  /* AIF2RX_CHAN0_MONO_MODE */
+#define WM8996_AIF2RX_CHAN0_MONO_MODE_WIDTH          1  /* AIF2RX_CHAN0_MONO_MODE */
+
+/*
+ * R815 (0x32F) - AIF2TX Test
+ */
+#define WM8996_AIF2TX_DITHER_ENA                0x0001  /* AIF2TX_DITHER_ENA */
+#define WM8996_AIF2TX_DITHER_ENA_MASK           0x0001  /* AIF2TX_DITHER_ENA */
+#define WM8996_AIF2TX_DITHER_ENA_SHIFT               0  /* AIF2TX_DITHER_ENA */
+#define WM8996_AIF2TX_DITHER_ENA_WIDTH               1  /* AIF2TX_DITHER_ENA */
+
+/*
+ * R1024 (0x400) - DSP1 TX Left Volume
+ */
+#define WM8996_DSP1TX_VU                        0x0100  /* DSP1TX_VU */
+#define WM8996_DSP1TX_VU_MASK                   0x0100  /* DSP1TX_VU */
+#define WM8996_DSP1TX_VU_SHIFT                       8  /* DSP1TX_VU */
+#define WM8996_DSP1TX_VU_WIDTH                       1  /* DSP1TX_VU */
+#define WM8996_DSP1TXL_VOL_MASK                 0x00FF  /* DSP1TXL_VOL - [7:0] */
+#define WM8996_DSP1TXL_VOL_SHIFT                     0  /* DSP1TXL_VOL - [7:0] */
+#define WM8996_DSP1TXL_VOL_WIDTH                     8  /* DSP1TXL_VOL - [7:0] */
+
+/*
+ * R1025 (0x401) - DSP1 TX Right Volume
+ */
+#define WM8996_DSP1TX_VU                        0x0100  /* DSP1TX_VU */
+#define WM8996_DSP1TX_VU_MASK                   0x0100  /* DSP1TX_VU */
+#define WM8996_DSP1TX_VU_SHIFT                       8  /* DSP1TX_VU */
+#define WM8996_DSP1TX_VU_WIDTH                       1  /* DSP1TX_VU */
+#define WM8996_DSP1TXR_VOL_MASK                 0x00FF  /* DSP1TXR_VOL - [7:0] */
+#define WM8996_DSP1TXR_VOL_SHIFT                     0  /* DSP1TXR_VOL - [7:0] */
+#define WM8996_DSP1TXR_VOL_WIDTH                     8  /* DSP1TXR_VOL - [7:0] */
+
+/*
+ * R1026 (0x402) - DSP1 RX Left Volume
+ */
+#define WM8996_DSP1RX_VU                        0x0100  /* DSP1RX_VU */
+#define WM8996_DSP1RX_VU_MASK                   0x0100  /* DSP1RX_VU */
+#define WM8996_DSP1RX_VU_SHIFT                       8  /* DSP1RX_VU */
+#define WM8996_DSP1RX_VU_WIDTH                       1  /* DSP1RX_VU */
+#define WM8996_DSP1RXL_VOL_MASK                 0x00FF  /* DSP1RXL_VOL - [7:0] */
+#define WM8996_DSP1RXL_VOL_SHIFT                     0  /* DSP1RXL_VOL - [7:0] */
+#define WM8996_DSP1RXL_VOL_WIDTH                     8  /* DSP1RXL_VOL - [7:0] */
+
+/*
+ * R1027 (0x403) - DSP1 RX Right Volume
+ */
+#define WM8996_DSP1RX_VU                        0x0100  /* DSP1RX_VU */
+#define WM8996_DSP1RX_VU_MASK                   0x0100  /* DSP1RX_VU */
+#define WM8996_DSP1RX_VU_SHIFT                       8  /* DSP1RX_VU */
+#define WM8996_DSP1RX_VU_WIDTH                       1  /* DSP1RX_VU */
+#define WM8996_DSP1RXR_VOL_MASK                 0x00FF  /* DSP1RXR_VOL - [7:0] */
+#define WM8996_DSP1RXR_VOL_SHIFT                     0  /* DSP1RXR_VOL - [7:0] */
+#define WM8996_DSP1RXR_VOL_WIDTH                     8  /* DSP1RXR_VOL - [7:0] */
+
+/*
+ * R1040 (0x410) - DSP1 TX Filters
+ */
+#define WM8996_DSP1TX_NF                        0x2000  /* DSP1TX_NF */
+#define WM8996_DSP1TX_NF_MASK                   0x2000  /* DSP1TX_NF */
+#define WM8996_DSP1TX_NF_SHIFT                      13  /* DSP1TX_NF */
+#define WM8996_DSP1TX_NF_WIDTH                       1  /* DSP1TX_NF */
+#define WM8996_DSP1TXL_HPF                      0x1000  /* DSP1TXL_HPF */
+#define WM8996_DSP1TXL_HPF_MASK                 0x1000  /* DSP1TXL_HPF */
+#define WM8996_DSP1TXL_HPF_SHIFT                    12  /* DSP1TXL_HPF */
+#define WM8996_DSP1TXL_HPF_WIDTH                     1  /* DSP1TXL_HPF */
+#define WM8996_DSP1TXR_HPF                      0x0800  /* DSP1TXR_HPF */
+#define WM8996_DSP1TXR_HPF_MASK                 0x0800  /* DSP1TXR_HPF */
+#define WM8996_DSP1TXR_HPF_SHIFT                    11  /* DSP1TXR_HPF */
+#define WM8996_DSP1TXR_HPF_WIDTH                     1  /* DSP1TXR_HPF */
+#define WM8996_DSP1TX_HPF_MODE_MASK             0x0018  /* DSP1TX_HPF_MODE - [4:3] */
+#define WM8996_DSP1TX_HPF_MODE_SHIFT                 3  /* DSP1TX_HPF_MODE - [4:3] */
+#define WM8996_DSP1TX_HPF_MODE_WIDTH                 2  /* DSP1TX_HPF_MODE - [4:3] */
+#define WM8996_DSP1TX_HPF_CUT_MASK              0x0007  /* DSP1TX_HPF_CUT - [2:0] */
+#define WM8996_DSP1TX_HPF_CUT_SHIFT                  0  /* DSP1TX_HPF_CUT - [2:0] */
+#define WM8996_DSP1TX_HPF_CUT_WIDTH                  3  /* DSP1TX_HPF_CUT - [2:0] */
+
+/*
+ * R1056 (0x420) - DSP1 RX Filters (1)
+ */
+#define WM8996_DSP1RX_MUTE                      0x0200  /* DSP1RX_MUTE */
+#define WM8996_DSP1RX_MUTE_MASK                 0x0200  /* DSP1RX_MUTE */
+#define WM8996_DSP1RX_MUTE_SHIFT                     9  /* DSP1RX_MUTE */
+#define WM8996_DSP1RX_MUTE_WIDTH                     1  /* DSP1RX_MUTE */
+#define WM8996_DSP1RX_MONO                      0x0080  /* DSP1RX_MONO */
+#define WM8996_DSP1RX_MONO_MASK                 0x0080  /* DSP1RX_MONO */
+#define WM8996_DSP1RX_MONO_SHIFT                     7  /* DSP1RX_MONO */
+#define WM8996_DSP1RX_MONO_WIDTH                     1  /* DSP1RX_MONO */
+#define WM8996_DSP1RX_MUTERATE                  0x0020  /* DSP1RX_MUTERATE */
+#define WM8996_DSP1RX_MUTERATE_MASK             0x0020  /* DSP1RX_MUTERATE */
+#define WM8996_DSP1RX_MUTERATE_SHIFT                 5  /* DSP1RX_MUTERATE */
+#define WM8996_DSP1RX_MUTERATE_WIDTH                 1  /* DSP1RX_MUTERATE */
+#define WM8996_DSP1RX_UNMUTE_RAMP               0x0010  /* DSP1RX_UNMUTE_RAMP */
+#define WM8996_DSP1RX_UNMUTE_RAMP_MASK          0x0010  /* DSP1RX_UNMUTE_RAMP */
+#define WM8996_DSP1RX_UNMUTE_RAMP_SHIFT              4  /* DSP1RX_UNMUTE_RAMP */
+#define WM8996_DSP1RX_UNMUTE_RAMP_WIDTH              1  /* DSP1RX_UNMUTE_RAMP */
+
+/*
+ * R1057 (0x421) - DSP1 RX Filters (2)
+ */
+#define WM8996_DSP1RX_3D_GAIN_MASK              0x3E00  /* DSP1RX_3D_GAIN - [13:9] */
+#define WM8996_DSP1RX_3D_GAIN_SHIFT                  9  /* DSP1RX_3D_GAIN - [13:9] */
+#define WM8996_DSP1RX_3D_GAIN_WIDTH                  5  /* DSP1RX_3D_GAIN - [13:9] */
+#define WM8996_DSP1RX_3D_ENA                    0x0100  /* DSP1RX_3D_ENA */
+#define WM8996_DSP1RX_3D_ENA_MASK               0x0100  /* DSP1RX_3D_ENA */
+#define WM8996_DSP1RX_3D_ENA_SHIFT                   8  /* DSP1RX_3D_ENA */
+#define WM8996_DSP1RX_3D_ENA_WIDTH                   1  /* DSP1RX_3D_ENA */
+
+/*
+ * R1088 (0x440) - DSP1 DRC (1)
+ */
+#define WM8996_DSP1DRC_SIG_DET_RMS_MASK         0xF800  /* DSP1DRC_SIG_DET_RMS - [15:11] */
+#define WM8996_DSP1DRC_SIG_DET_RMS_SHIFT            11  /* DSP1DRC_SIG_DET_RMS - [15:11] */
+#define WM8996_DSP1DRC_SIG_DET_RMS_WIDTH             5  /* DSP1DRC_SIG_DET_RMS - [15:11] */
+#define WM8996_DSP1DRC_SIG_DET_PK_MASK          0x0600  /* DSP1DRC_SIG_DET_PK - [10:9] */
+#define WM8996_DSP1DRC_SIG_DET_PK_SHIFT              9  /* DSP1DRC_SIG_DET_PK - [10:9] */
+#define WM8996_DSP1DRC_SIG_DET_PK_WIDTH              2  /* DSP1DRC_SIG_DET_PK - [10:9] */
+#define WM8996_DSP1DRC_NG_ENA                   0x0100  /* DSP1DRC_NG_ENA */
+#define WM8996_DSP1DRC_NG_ENA_MASK              0x0100  /* DSP1DRC_NG_ENA */
+#define WM8996_DSP1DRC_NG_ENA_SHIFT                  8  /* DSP1DRC_NG_ENA */
+#define WM8996_DSP1DRC_NG_ENA_WIDTH                  1  /* DSP1DRC_NG_ENA */
+#define WM8996_DSP1DRC_SIG_DET_MODE             0x0080  /* DSP1DRC_SIG_DET_MODE */
+#define WM8996_DSP1DRC_SIG_DET_MODE_MASK        0x0080  /* DSP1DRC_SIG_DET_MODE */
+#define WM8996_DSP1DRC_SIG_DET_MODE_SHIFT            7  /* DSP1DRC_SIG_DET_MODE */
+#define WM8996_DSP1DRC_SIG_DET_MODE_WIDTH            1  /* DSP1DRC_SIG_DET_MODE */
+#define WM8996_DSP1DRC_SIG_DET                  0x0040  /* DSP1DRC_SIG_DET */
+#define WM8996_DSP1DRC_SIG_DET_MASK             0x0040  /* DSP1DRC_SIG_DET */
+#define WM8996_DSP1DRC_SIG_DET_SHIFT                 6  /* DSP1DRC_SIG_DET */
+#define WM8996_DSP1DRC_SIG_DET_WIDTH                 1  /* DSP1DRC_SIG_DET */
+#define WM8996_DSP1DRC_KNEE2_OP_ENA             0x0020  /* DSP1DRC_KNEE2_OP_ENA */
+#define WM8996_DSP1DRC_KNEE2_OP_ENA_MASK        0x0020  /* DSP1DRC_KNEE2_OP_ENA */
+#define WM8996_DSP1DRC_KNEE2_OP_ENA_SHIFT            5  /* DSP1DRC_KNEE2_OP_ENA */
+#define WM8996_DSP1DRC_KNEE2_OP_ENA_WIDTH            1  /* DSP1DRC_KNEE2_OP_ENA */
+#define WM8996_DSP1DRC_QR                       0x0010  /* DSP1DRC_QR */
+#define WM8996_DSP1DRC_QR_MASK                  0x0010  /* DSP1DRC_QR */
+#define WM8996_DSP1DRC_QR_SHIFT                      4  /* DSP1DRC_QR */
+#define WM8996_DSP1DRC_QR_WIDTH                      1  /* DSP1DRC_QR */
+#define WM8996_DSP1DRC_ANTICLIP                 0x0008  /* DSP1DRC_ANTICLIP */
+#define WM8996_DSP1DRC_ANTICLIP_MASK            0x0008  /* DSP1DRC_ANTICLIP */
+#define WM8996_DSP1DRC_ANTICLIP_SHIFT                3  /* DSP1DRC_ANTICLIP */
+#define WM8996_DSP1DRC_ANTICLIP_WIDTH                1  /* DSP1DRC_ANTICLIP */
+#define WM8996_DSP1RX_DRC_ENA                   0x0004  /* DSP1RX_DRC_ENA */
+#define WM8996_DSP1RX_DRC_ENA_MASK              0x0004  /* DSP1RX_DRC_ENA */
+#define WM8996_DSP1RX_DRC_ENA_SHIFT                  2  /* DSP1RX_DRC_ENA */
+#define WM8996_DSP1RX_DRC_ENA_WIDTH                  1  /* DSP1RX_DRC_ENA */
+#define WM8996_DSP1TXL_DRC_ENA                  0x0002  /* DSP1TXL_DRC_ENA */
+#define WM8996_DSP1TXL_DRC_ENA_MASK             0x0002  /* DSP1TXL_DRC_ENA */
+#define WM8996_DSP1TXL_DRC_ENA_SHIFT                 1  /* DSP1TXL_DRC_ENA */
+#define WM8996_DSP1TXL_DRC_ENA_WIDTH                 1  /* DSP1TXL_DRC_ENA */
+#define WM8996_DSP1TXR_DRC_ENA                  0x0001  /* DSP1TXR_DRC_ENA */
+#define WM8996_DSP1TXR_DRC_ENA_MASK             0x0001  /* DSP1TXR_DRC_ENA */
+#define WM8996_DSP1TXR_DRC_ENA_SHIFT                 0  /* DSP1TXR_DRC_ENA */
+#define WM8996_DSP1TXR_DRC_ENA_WIDTH                 1  /* DSP1TXR_DRC_ENA */
+
+/*
+ * R1089 (0x441) - DSP1 DRC (2)
+ */
+#define WM8996_DSP1DRC_ATK_MASK                 0x1E00  /* DSP1DRC_ATK - [12:9] */
+#define WM8996_DSP1DRC_ATK_SHIFT                     9  /* DSP1DRC_ATK - [12:9] */
+#define WM8996_DSP1DRC_ATK_WIDTH                     4  /* DSP1DRC_ATK - [12:9] */
+#define WM8996_DSP1DRC_DCY_MASK                 0x01E0  /* DSP1DRC_DCY - [8:5] */
+#define WM8996_DSP1DRC_DCY_SHIFT                     5  /* DSP1DRC_DCY - [8:5] */
+#define WM8996_DSP1DRC_DCY_WIDTH                     4  /* DSP1DRC_DCY - [8:5] */
+#define WM8996_DSP1DRC_MINGAIN_MASK             0x001C  /* DSP1DRC_MINGAIN - [4:2] */
+#define WM8996_DSP1DRC_MINGAIN_SHIFT                 2  /* DSP1DRC_MINGAIN - [4:2] */
+#define WM8996_DSP1DRC_MINGAIN_WIDTH                 3  /* DSP1DRC_MINGAIN - [4:2] */
+#define WM8996_DSP1DRC_MAXGAIN_MASK             0x0003  /* DSP1DRC_MAXGAIN - [1:0] */
+#define WM8996_DSP1DRC_MAXGAIN_SHIFT                 0  /* DSP1DRC_MAXGAIN - [1:0] */
+#define WM8996_DSP1DRC_MAXGAIN_WIDTH                 2  /* DSP1DRC_MAXGAIN - [1:0] */
+
+/*
+ * R1090 (0x442) - DSP1 DRC (3)
+ */
+#define WM8996_DSP1DRC_NG_MINGAIN_MASK          0xF000  /* DSP1DRC_NG_MINGAIN - [15:12] */
+#define WM8996_DSP1DRC_NG_MINGAIN_SHIFT             12  /* DSP1DRC_NG_MINGAIN - [15:12] */
+#define WM8996_DSP1DRC_NG_MINGAIN_WIDTH              4  /* DSP1DRC_NG_MINGAIN - [15:12] */
+#define WM8996_DSP1DRC_NG_EXP_MASK              0x0C00  /* DSP1DRC_NG_EXP - [11:10] */
+#define WM8996_DSP1DRC_NG_EXP_SHIFT                 10  /* DSP1DRC_NG_EXP - [11:10] */
+#define WM8996_DSP1DRC_NG_EXP_WIDTH                  2  /* DSP1DRC_NG_EXP - [11:10] */
+#define WM8996_DSP1DRC_QR_THR_MASK              0x0300  /* DSP1DRC_QR_THR - [9:8] */
+#define WM8996_DSP1DRC_QR_THR_SHIFT                  8  /* DSP1DRC_QR_THR - [9:8] */
+#define WM8996_DSP1DRC_QR_THR_WIDTH                  2  /* DSP1DRC_QR_THR - [9:8] */
+#define WM8996_DSP1DRC_QR_DCY_MASK              0x00C0  /* DSP1DRC_QR_DCY - [7:6] */
+#define WM8996_DSP1DRC_QR_DCY_SHIFT                  6  /* DSP1DRC_QR_DCY - [7:6] */
+#define WM8996_DSP1DRC_QR_DCY_WIDTH                  2  /* DSP1DRC_QR_DCY - [7:6] */
+#define WM8996_DSP1DRC_HI_COMP_MASK             0x0038  /* DSP1DRC_HI_COMP - [5:3] */
+#define WM8996_DSP1DRC_HI_COMP_SHIFT                 3  /* DSP1DRC_HI_COMP - [5:3] */
+#define WM8996_DSP1DRC_HI_COMP_WIDTH                 3  /* DSP1DRC_HI_COMP - [5:3] */
+#define WM8996_DSP1DRC_LO_COMP_MASK             0x0007  /* DSP1DRC_LO_COMP - [2:0] */
+#define WM8996_DSP1DRC_LO_COMP_SHIFT                 0  /* DSP1DRC_LO_COMP - [2:0] */
+#define WM8996_DSP1DRC_LO_COMP_WIDTH                 3  /* DSP1DRC_LO_COMP - [2:0] */
+
+/*
+ * R1091 (0x443) - DSP1 DRC (4)
+ */
+#define WM8996_DSP1DRC_KNEE_IP_MASK             0x07E0  /* DSP1DRC_KNEE_IP - [10:5] */
+#define WM8996_DSP1DRC_KNEE_IP_SHIFT                 5  /* DSP1DRC_KNEE_IP - [10:5] */
+#define WM8996_DSP1DRC_KNEE_IP_WIDTH                 6  /* DSP1DRC_KNEE_IP - [10:5] */
+#define WM8996_DSP1DRC_KNEE_OP_MASK             0x001F  /* DSP1DRC_KNEE_OP - [4:0] */
+#define WM8996_DSP1DRC_KNEE_OP_SHIFT                 0  /* DSP1DRC_KNEE_OP - [4:0] */
+#define WM8996_DSP1DRC_KNEE_OP_WIDTH                 5  /* DSP1DRC_KNEE_OP - [4:0] */
+
+/*
+ * R1092 (0x444) - DSP1 DRC (5)
+ */
+#define WM8996_DSP1DRC_KNEE2_IP_MASK            0x03E0  /* DSP1DRC_KNEE2_IP - [9:5] */
+#define WM8996_DSP1DRC_KNEE2_IP_SHIFT                5  /* DSP1DRC_KNEE2_IP - [9:5] */
+#define WM8996_DSP1DRC_KNEE2_IP_WIDTH                5  /* DSP1DRC_KNEE2_IP - [9:5] */
+#define WM8996_DSP1DRC_KNEE2_OP_MASK            0x001F  /* DSP1DRC_KNEE2_OP - [4:0] */
+#define WM8996_DSP1DRC_KNEE2_OP_SHIFT                0  /* DSP1DRC_KNEE2_OP - [4:0] */
+#define WM8996_DSP1DRC_KNEE2_OP_WIDTH                5  /* DSP1DRC_KNEE2_OP - [4:0] */
+
+/*
+ * R1152 (0x480) - DSP1 RX EQ Gains (1)
+ */
+#define WM8996_DSP1RX_EQ_B1_GAIN_MASK           0xF800  /* DSP1RX_EQ_B1_GAIN - [15:11] */
+#define WM8996_DSP1RX_EQ_B1_GAIN_SHIFT              11  /* DSP1RX_EQ_B1_GAIN - [15:11] */
+#define WM8996_DSP1RX_EQ_B1_GAIN_WIDTH               5  /* DSP1RX_EQ_B1_GAIN - [15:11] */
+#define WM8996_DSP1RX_EQ_B2_GAIN_MASK           0x07C0  /* DSP1RX_EQ_B2_GAIN - [10:6] */
+#define WM8996_DSP1RX_EQ_B2_GAIN_SHIFT               6  /* DSP1RX_EQ_B2_GAIN - [10:6] */
+#define WM8996_DSP1RX_EQ_B2_GAIN_WIDTH               5  /* DSP1RX_EQ_B2_GAIN - [10:6] */
+#define WM8996_DSP1RX_EQ_B3_GAIN_MASK           0x003E  /* DSP1RX_EQ_B3_GAIN - [5:1] */
+#define WM8996_DSP1RX_EQ_B3_GAIN_SHIFT               1  /* DSP1RX_EQ_B3_GAIN - [5:1] */
+#define WM8996_DSP1RX_EQ_B3_GAIN_WIDTH               5  /* DSP1RX_EQ_B3_GAIN - [5:1] */
+#define WM8996_DSP1RX_EQ_ENA                    0x0001  /* DSP1RX_EQ_ENA */
+#define WM8996_DSP1RX_EQ_ENA_MASK               0x0001  /* DSP1RX_EQ_ENA */
+#define WM8996_DSP1RX_EQ_ENA_SHIFT                   0  /* DSP1RX_EQ_ENA */
+#define WM8996_DSP1RX_EQ_ENA_WIDTH                   1  /* DSP1RX_EQ_ENA */
+
+/*
+ * R1153 (0x481) - DSP1 RX EQ Gains (2)
+ */
+#define WM8996_DSP1RX_EQ_B4_GAIN_MASK           0xF800  /* DSP1RX_EQ_B4_GAIN - [15:11] */
+#define WM8996_DSP1RX_EQ_B4_GAIN_SHIFT              11  /* DSP1RX_EQ_B4_GAIN - [15:11] */
+#define WM8996_DSP1RX_EQ_B4_GAIN_WIDTH               5  /* DSP1RX_EQ_B4_GAIN - [15:11] */
+#define WM8996_DSP1RX_EQ_B5_GAIN_MASK           0x07C0  /* DSP1RX_EQ_B5_GAIN - [10:6] */
+#define WM8996_DSP1RX_EQ_B5_GAIN_SHIFT               6  /* DSP1RX_EQ_B5_GAIN - [10:6] */
+#define WM8996_DSP1RX_EQ_B5_GAIN_WIDTH               5  /* DSP1RX_EQ_B5_GAIN - [10:6] */
+
+/*
+ * R1154 (0x482) - DSP1 RX EQ Band 1 A
+ */
+#define WM8996_DSP1RX_EQ_B1_A_MASK              0xFFFF  /* DSP1RX_EQ_B1_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B1_A_SHIFT                  0  /* DSP1RX_EQ_B1_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B1_A_WIDTH                 16  /* DSP1RX_EQ_B1_A - [15:0] */
+
+/*
+ * R1155 (0x483) - DSP1 RX EQ Band 1 B
+ */
+#define WM8996_DSP1RX_EQ_B1_B_MASK              0xFFFF  /* DSP1RX_EQ_B1_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B1_B_SHIFT                  0  /* DSP1RX_EQ_B1_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B1_B_WIDTH                 16  /* DSP1RX_EQ_B1_B - [15:0] */
+
+/*
+ * R1156 (0x484) - DSP1 RX EQ Band 1 PG
+ */
+#define WM8996_DSP1RX_EQ_B1_PG_MASK             0xFFFF  /* DSP1RX_EQ_B1_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B1_PG_SHIFT                 0  /* DSP1RX_EQ_B1_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B1_PG_WIDTH                16  /* DSP1RX_EQ_B1_PG - [15:0] */
+
+/*
+ * R1157 (0x485) - DSP1 RX EQ Band 2 A
+ */
+#define WM8996_DSP1RX_EQ_B2_A_MASK              0xFFFF  /* DSP1RX_EQ_B2_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B2_A_SHIFT                  0  /* DSP1RX_EQ_B2_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B2_A_WIDTH                 16  /* DSP1RX_EQ_B2_A - [15:0] */
+
+/*
+ * R1158 (0x486) - DSP1 RX EQ Band 2 B
+ */
+#define WM8996_DSP1RX_EQ_B2_B_MASK              0xFFFF  /* DSP1RX_EQ_B2_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B2_B_SHIFT                  0  /* DSP1RX_EQ_B2_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B2_B_WIDTH                 16  /* DSP1RX_EQ_B2_B - [15:0] */
+
+/*
+ * R1159 (0x487) - DSP1 RX EQ Band 2 C
+ */
+#define WM8996_DSP1RX_EQ_B2_C_MASK              0xFFFF  /* DSP1RX_EQ_B2_C - [15:0] */
+#define WM8996_DSP1RX_EQ_B2_C_SHIFT                  0  /* DSP1RX_EQ_B2_C - [15:0] */
+#define WM8996_DSP1RX_EQ_B2_C_WIDTH                 16  /* DSP1RX_EQ_B2_C - [15:0] */
+
+/*
+ * R1160 (0x488) - DSP1 RX EQ Band 2 PG
+ */
+#define WM8996_DSP1RX_EQ_B2_PG_MASK             0xFFFF  /* DSP1RX_EQ_B2_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B2_PG_SHIFT                 0  /* DSP1RX_EQ_B2_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B2_PG_WIDTH                16  /* DSP1RX_EQ_B2_PG - [15:0] */
+
+/*
+ * R1161 (0x489) - DSP1 RX EQ Band 3 A
+ */
+#define WM8996_DSP1RX_EQ_B3_A_MASK              0xFFFF  /* DSP1RX_EQ_B3_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B3_A_SHIFT                  0  /* DSP1RX_EQ_B3_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B3_A_WIDTH                 16  /* DSP1RX_EQ_B3_A - [15:0] */
+
+/*
+ * R1162 (0x48A) - DSP1 RX EQ Band 3 B
+ */
+#define WM8996_DSP1RX_EQ_B3_B_MASK              0xFFFF  /* DSP1RX_EQ_B3_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B3_B_SHIFT                  0  /* DSP1RX_EQ_B3_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B3_B_WIDTH                 16  /* DSP1RX_EQ_B3_B - [15:0] */
+
+/*
+ * R1163 (0x48B) - DSP1 RX EQ Band 3 C
+ */
+#define WM8996_DSP1RX_EQ_B3_C_MASK              0xFFFF  /* DSP1RX_EQ_B3_C - [15:0] */
+#define WM8996_DSP1RX_EQ_B3_C_SHIFT                  0  /* DSP1RX_EQ_B3_C - [15:0] */
+#define WM8996_DSP1RX_EQ_B3_C_WIDTH                 16  /* DSP1RX_EQ_B3_C - [15:0] */
+
+/*
+ * R1164 (0x48C) - DSP1 RX EQ Band 3 PG
+ */
+#define WM8996_DSP1RX_EQ_B3_PG_MASK             0xFFFF  /* DSP1RX_EQ_B3_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B3_PG_SHIFT                 0  /* DSP1RX_EQ_B3_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B3_PG_WIDTH                16  /* DSP1RX_EQ_B3_PG - [15:0] */
+
+/*
+ * R1165 (0x48D) - DSP1 RX EQ Band 4 A
+ */
+#define WM8996_DSP1RX_EQ_B4_A_MASK              0xFFFF  /* DSP1RX_EQ_B4_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B4_A_SHIFT                  0  /* DSP1RX_EQ_B4_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B4_A_WIDTH                 16  /* DSP1RX_EQ_B4_A - [15:0] */
+
+/*
+ * R1166 (0x48E) - DSP1 RX EQ Band 4 B
+ */
+#define WM8996_DSP1RX_EQ_B4_B_MASK              0xFFFF  /* DSP1RX_EQ_B4_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B4_B_SHIFT                  0  /* DSP1RX_EQ_B4_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B4_B_WIDTH                 16  /* DSP1RX_EQ_B4_B - [15:0] */
+
+/*
+ * R1167 (0x48F) - DSP1 RX EQ Band 4 C
+ */
+#define WM8996_DSP1RX_EQ_B4_C_MASK              0xFFFF  /* DSP1RX_EQ_B4_C - [15:0] */
+#define WM8996_DSP1RX_EQ_B4_C_SHIFT                  0  /* DSP1RX_EQ_B4_C - [15:0] */
+#define WM8996_DSP1RX_EQ_B4_C_WIDTH                 16  /* DSP1RX_EQ_B4_C - [15:0] */
+
+/*
+ * R1168 (0x490) - DSP1 RX EQ Band 4 PG
+ */
+#define WM8996_DSP1RX_EQ_B4_PG_MASK             0xFFFF  /* DSP1RX_EQ_B4_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B4_PG_SHIFT                 0  /* DSP1RX_EQ_B4_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B4_PG_WIDTH                16  /* DSP1RX_EQ_B4_PG - [15:0] */
+
+/*
+ * R1169 (0x491) - DSP1 RX EQ Band 5 A
+ */
+#define WM8996_DSP1RX_EQ_B5_A_MASK              0xFFFF  /* DSP1RX_EQ_B5_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B5_A_SHIFT                  0  /* DSP1RX_EQ_B5_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B5_A_WIDTH                 16  /* DSP1RX_EQ_B5_A - [15:0] */
+
+/*
+ * R1170 (0x492) - DSP1 RX EQ Band 5 B
+ */
+#define WM8996_DSP1RX_EQ_B5_B_MASK              0xFFFF  /* DSP1RX_EQ_B5_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B5_B_SHIFT                  0  /* DSP1RX_EQ_B5_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B5_B_WIDTH                 16  /* DSP1RX_EQ_B5_B - [15:0] */
+
+/*
+ * R1171 (0x493) - DSP1 RX EQ Band 5 PG
+ */
+#define WM8996_DSP1RX_EQ_B5_PG_MASK             0xFFFF  /* DSP1RX_EQ_B5_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B5_PG_SHIFT                 0  /* DSP1RX_EQ_B5_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B5_PG_WIDTH                16  /* DSP1RX_EQ_B5_PG - [15:0] */
+
+/*
+ * R1280 (0x500) - DSP2 TX Left Volume
+ */
+#define WM8996_DSP2TX_VU                        0x0100  /* DSP2TX_VU */
+#define WM8996_DSP2TX_VU_MASK                   0x0100  /* DSP2TX_VU */
+#define WM8996_DSP2TX_VU_SHIFT                       8  /* DSP2TX_VU */
+#define WM8996_DSP2TX_VU_WIDTH                       1  /* DSP2TX_VU */
+#define WM8996_DSP2TXL_VOL_MASK                 0x00FF  /* DSP2TXL_VOL - [7:0] */
+#define WM8996_DSP2TXL_VOL_SHIFT                     0  /* DSP2TXL_VOL - [7:0] */
+#define WM8996_DSP2TXL_VOL_WIDTH                     8  /* DSP2TXL_VOL - [7:0] */
+
+/*
+ * R1281 (0x501) - DSP2 TX Right Volume
+ */
+#define WM8996_DSP2TX_VU                        0x0100  /* DSP2TX_VU */
+#define WM8996_DSP2TX_VU_MASK                   0x0100  /* DSP2TX_VU */
+#define WM8996_DSP2TX_VU_SHIFT                       8  /* DSP2TX_VU */
+#define WM8996_DSP2TX_VU_WIDTH                       1  /* DSP2TX_VU */
+#define WM8996_DSP2TXR_VOL_MASK                 0x00FF  /* DSP2TXR_VOL - [7:0] */
+#define WM8996_DSP2TXR_VOL_SHIFT                     0  /* DSP2TXR_VOL - [7:0] */
+#define WM8996_DSP2TXR_VOL_WIDTH                     8  /* DSP2TXR_VOL - [7:0] */
+
+/*
+ * R1282 (0x502) - DSP2 RX Left Volume
+ */
+#define WM8996_DSP2RX_VU                        0x0100  /* DSP2RX_VU */
+#define WM8996_DSP2RX_VU_MASK                   0x0100  /* DSP2RX_VU */
+#define WM8996_DSP2RX_VU_SHIFT                       8  /* DSP2RX_VU */
+#define WM8996_DSP2RX_VU_WIDTH                       1  /* DSP2RX_VU */
+#define WM8996_DSP2RXL_VOL_MASK                 0x00FF  /* DSP2RXL_VOL - [7:0] */
+#define WM8996_DSP2RXL_VOL_SHIFT                     0  /* DSP2RXL_VOL - [7:0] */
+#define WM8996_DSP2RXL_VOL_WIDTH                     8  /* DSP2RXL_VOL - [7:0] */
+
+/*
+ * R1283 (0x503) - DSP2 RX Right Volume
+ */
+#define WM8996_DSP2RX_VU                        0x0100  /* DSP2RX_VU */
+#define WM8996_DSP2RX_VU_MASK                   0x0100  /* DSP2RX_VU */
+#define WM8996_DSP2RX_VU_SHIFT                       8  /* DSP2RX_VU */
+#define WM8996_DSP2RX_VU_WIDTH                       1  /* DSP2RX_VU */
+#define WM8996_DSP2RXR_VOL_MASK                 0x00FF  /* DSP2RXR_VOL - [7:0] */
+#define WM8996_DSP2RXR_VOL_SHIFT                     0  /* DSP2RXR_VOL - [7:0] */
+#define WM8996_DSP2RXR_VOL_WIDTH                     8  /* DSP2RXR_VOL - [7:0] */
+
+/*
+ * R1296 (0x510) - DSP2 TX Filters
+ */
+#define WM8996_DSP2TX_NF                        0x2000  /* DSP2TX_NF */
+#define WM8996_DSP2TX_NF_MASK                   0x2000  /* DSP2TX_NF */
+#define WM8996_DSP2TX_NF_SHIFT                      13  /* DSP2TX_NF */
+#define WM8996_DSP2TX_NF_WIDTH                       1  /* DSP2TX_NF */
+#define WM8996_DSP2TXL_HPF                      0x1000  /* DSP2TXL_HPF */
+#define WM8996_DSP2TXL_HPF_MASK                 0x1000  /* DSP2TXL_HPF */
+#define WM8996_DSP2TXL_HPF_SHIFT                    12  /* DSP2TXL_HPF */
+#define WM8996_DSP2TXL_HPF_WIDTH                     1  /* DSP2TXL_HPF */
+#define WM8996_DSP2TXR_HPF                      0x0800  /* DSP2TXR_HPF */
+#define WM8996_DSP2TXR_HPF_MASK                 0x0800  /* DSP2TXR_HPF */
+#define WM8996_DSP2TXR_HPF_SHIFT                    11  /* DSP2TXR_HPF */
+#define WM8996_DSP2TXR_HPF_WIDTH                     1  /* DSP2TXR_HPF */
+#define WM8996_DSP2TX_HPF_MODE_MASK             0x0018  /* DSP2TX_HPF_MODE - [4:3] */
+#define WM8996_DSP2TX_HPF_MODE_SHIFT                 3  /* DSP2TX_HPF_MODE - [4:3] */
+#define WM8996_DSP2TX_HPF_MODE_WIDTH                 2  /* DSP2TX_HPF_MODE - [4:3] */
+#define WM8996_DSP2TX_HPF_CUT_MASK              0x0007  /* DSP2TX_HPF_CUT - [2:0] */
+#define WM8996_DSP2TX_HPF_CUT_SHIFT                  0  /* DSP2TX_HPF_CUT - [2:0] */
+#define WM8996_DSP2TX_HPF_CUT_WIDTH                  3  /* DSP2TX_HPF_CUT - [2:0] */
+
+/*
+ * R1312 (0x520) - DSP2 RX Filters (1)
+ */
+#define WM8996_DSP2RX_MUTE                      0x0200  /* DSP2RX_MUTE */
+#define WM8996_DSP2RX_MUTE_MASK                 0x0200  /* DSP2RX_MUTE */
+#define WM8996_DSP2RX_MUTE_SHIFT                     9  /* DSP2RX_MUTE */
+#define WM8996_DSP2RX_MUTE_WIDTH                     1  /* DSP2RX_MUTE */
+#define WM8996_DSP2RX_MONO                      0x0080  /* DSP2RX_MONO */
+#define WM8996_DSP2RX_MONO_MASK                 0x0080  /* DSP2RX_MONO */
+#define WM8996_DSP2RX_MONO_SHIFT                     7  /* DSP2RX_MONO */
+#define WM8996_DSP2RX_MONO_WIDTH                     1  /* DSP2RX_MONO */
+#define WM8996_DSP2RX_MUTERATE                  0x0020  /* DSP2RX_MUTERATE */
+#define WM8996_DSP2RX_MUTERATE_MASK             0x0020  /* DSP2RX_MUTERATE */
+#define WM8996_DSP2RX_MUTERATE_SHIFT                 5  /* DSP2RX_MUTERATE */
+#define WM8996_DSP2RX_MUTERATE_WIDTH                 1  /* DSP2RX_MUTERATE */
+#define WM8996_DSP2RX_UNMUTE_RAMP               0x0010  /* DSP2RX_UNMUTE_RAMP */
+#define WM8996_DSP2RX_UNMUTE_RAMP_MASK          0x0010  /* DSP2RX_UNMUTE_RAMP */
+#define WM8996_DSP2RX_UNMUTE_RAMP_SHIFT              4  /* DSP2RX_UNMUTE_RAMP */
+#define WM8996_DSP2RX_UNMUTE_RAMP_WIDTH              1  /* DSP2RX_UNMUTE_RAMP */
+
+/*
+ * R1313 (0x521) - DSP2 RX Filters (2)
+ */
+#define WM8996_DSP2RX_3D_GAIN_MASK              0x3E00  /* DSP2RX_3D_GAIN - [13:9] */
+#define WM8996_DSP2RX_3D_GAIN_SHIFT                  9  /* DSP2RX_3D_GAIN - [13:9] */
+#define WM8996_DSP2RX_3D_GAIN_WIDTH                  5  /* DSP2RX_3D_GAIN - [13:9] */
+#define WM8996_DSP2RX_3D_ENA                    0x0100  /* DSP2RX_3D_ENA */
+#define WM8996_DSP2RX_3D_ENA_MASK               0x0100  /* DSP2RX_3D_ENA */
+#define WM8996_DSP2RX_3D_ENA_SHIFT                   8  /* DSP2RX_3D_ENA */
+#define WM8996_DSP2RX_3D_ENA_WIDTH                   1  /* DSP2RX_3D_ENA */
+
+/*
+ * R1344 (0x540) - DSP2 DRC (1)
+ */
+#define WM8996_DSP2DRC_SIG_DET_RMS_MASK         0xF800  /* DSP2DRC_SIG_DET_RMS - [15:11] */
+#define WM8996_DSP2DRC_SIG_DET_RMS_SHIFT            11  /* DSP2DRC_SIG_DET_RMS - [15:11] */
+#define WM8996_DSP2DRC_SIG_DET_RMS_WIDTH             5  /* DSP2DRC_SIG_DET_RMS - [15:11] */
+#define WM8996_DSP2DRC_SIG_DET_PK_MASK          0x0600  /* DSP2DRC_SIG_DET_PK - [10:9] */
+#define WM8996_DSP2DRC_SIG_DET_PK_SHIFT              9  /* DSP2DRC_SIG_DET_PK - [10:9] */
+#define WM8996_DSP2DRC_SIG_DET_PK_WIDTH              2  /* DSP2DRC_SIG_DET_PK - [10:9] */
+#define WM8996_DSP2DRC_NG_ENA                   0x0100  /* DSP2DRC_NG_ENA */
+#define WM8996_DSP2DRC_NG_ENA_MASK              0x0100  /* DSP2DRC_NG_ENA */
+#define WM8996_DSP2DRC_NG_ENA_SHIFT                  8  /* DSP2DRC_NG_ENA */
+#define WM8996_DSP2DRC_NG_ENA_WIDTH                  1  /* DSP2DRC_NG_ENA */
+#define WM8996_DSP2DRC_SIG_DET_MODE             0x0080  /* DSP2DRC_SIG_DET_MODE */
+#define WM8996_DSP2DRC_SIG_DET_MODE_MASK        0x0080  /* DSP2DRC_SIG_DET_MODE */
+#define WM8996_DSP2DRC_SIG_DET_MODE_SHIFT            7  /* DSP2DRC_SIG_DET_MODE */
+#define WM8996_DSP2DRC_SIG_DET_MODE_WIDTH            1  /* DSP2DRC_SIG_DET_MODE */
+#define WM8996_DSP2DRC_SIG_DET                  0x0040  /* DSP2DRC_SIG_DET */
+#define WM8996_DSP2DRC_SIG_DET_MASK             0x0040  /* DSP2DRC_SIG_DET */
+#define WM8996_DSP2DRC_SIG_DET_SHIFT                 6  /* DSP2DRC_SIG_DET */
+#define WM8996_DSP2DRC_SIG_DET_WIDTH                 1  /* DSP2DRC_SIG_DET */
+#define WM8996_DSP2DRC_KNEE2_OP_ENA             0x0020  /* DSP2DRC_KNEE2_OP_ENA */
+#define WM8996_DSP2DRC_KNEE2_OP_ENA_MASK        0x0020  /* DSP2DRC_KNEE2_OP_ENA */
+#define WM8996_DSP2DRC_KNEE2_OP_ENA_SHIFT            5  /* DSP2DRC_KNEE2_OP_ENA */
+#define WM8996_DSP2DRC_KNEE2_OP_ENA_WIDTH            1  /* DSP2DRC_KNEE2_OP_ENA */
+#define WM8996_DSP2DRC_QR                       0x0010  /* DSP2DRC_QR */
+#define WM8996_DSP2DRC_QR_MASK                  0x0010  /* DSP2DRC_QR */
+#define WM8996_DSP2DRC_QR_SHIFT                      4  /* DSP2DRC_QR */
+#define WM8996_DSP2DRC_QR_WIDTH                      1  /* DSP2DRC_QR */
+#define WM8996_DSP2DRC_ANTICLIP                 0x0008  /* DSP2DRC_ANTICLIP */
+#define WM8996_DSP2DRC_ANTICLIP_MASK            0x0008  /* DSP2DRC_ANTICLIP */
+#define WM8996_DSP2DRC_ANTICLIP_SHIFT                3  /* DSP2DRC_ANTICLIP */
+#define WM8996_DSP2DRC_ANTICLIP_WIDTH                1  /* DSP2DRC_ANTICLIP */
+#define WM8996_DSP2RX_DRC_ENA                   0x0004  /* DSP2RX_DRC_ENA */
+#define WM8996_DSP2RX_DRC_ENA_MASK              0x0004  /* DSP2RX_DRC_ENA */
+#define WM8996_DSP2RX_DRC_ENA_SHIFT                  2  /* DSP2RX_DRC_ENA */
+#define WM8996_DSP2RX_DRC_ENA_WIDTH                  1  /* DSP2RX_DRC_ENA */
+#define WM8996_DSP2TXL_DRC_ENA                  0x0002  /* DSP2TXL_DRC_ENA */
+#define WM8996_DSP2TXL_DRC_ENA_MASK             0x0002  /* DSP2TXL_DRC_ENA */
+#define WM8996_DSP2TXL_DRC_ENA_SHIFT                 1  /* DSP2TXL_DRC_ENA */
+#define WM8996_DSP2TXL_DRC_ENA_WIDTH                 1  /* DSP2TXL_DRC_ENA */
+#define WM8996_DSP2TXR_DRC_ENA                  0x0001  /* DSP2TXR_DRC_ENA */
+#define WM8996_DSP2TXR_DRC_ENA_MASK             0x0001  /* DSP2TXR_DRC_ENA */
+#define WM8996_DSP2TXR_DRC_ENA_SHIFT                 0  /* DSP2TXR_DRC_ENA */
+#define WM8996_DSP2TXR_DRC_ENA_WIDTH                 1  /* DSP2TXR_DRC_ENA */
+
+/*
+ * R1345 (0x541) - DSP2 DRC (2)
+ */
+#define WM8996_DSP2DRC_ATK_MASK                 0x1E00  /* DSP2DRC_ATK - [12:9] */
+#define WM8996_DSP2DRC_ATK_SHIFT                     9  /* DSP2DRC_ATK - [12:9] */
+#define WM8996_DSP2DRC_ATK_WIDTH                     4  /* DSP2DRC_ATK - [12:9] */
+#define WM8996_DSP2DRC_DCY_MASK                 0x01E0  /* DSP2DRC_DCY - [8:5] */
+#define WM8996_DSP2DRC_DCY_SHIFT                     5  /* DSP2DRC_DCY - [8:5] */
+#define WM8996_DSP2DRC_DCY_WIDTH                     4  /* DSP2DRC_DCY - [8:5] */
+#define WM8996_DSP2DRC_MINGAIN_MASK             0x001C  /* DSP2DRC_MINGAIN - [4:2] */
+#define WM8996_DSP2DRC_MINGAIN_SHIFT                 2  /* DSP2DRC_MINGAIN - [4:2] */
+#define WM8996_DSP2DRC_MINGAIN_WIDTH                 3  /* DSP2DRC_MINGAIN - [4:2] */
+#define WM8996_DSP2DRC_MAXGAIN_MASK             0x0003  /* DSP2DRC_MAXGAIN - [1:0] */
+#define WM8996_DSP2DRC_MAXGAIN_SHIFT                 0  /* DSP2DRC_MAXGAIN - [1:0] */
+#define WM8996_DSP2DRC_MAXGAIN_WIDTH                 2  /* DSP2DRC_MAXGAIN - [1:0] */
+
+/*
+ * R1346 (0x542) - DSP2 DRC (3)
+ */
+#define WM8996_DSP2DRC_NG_MINGAIN_MASK          0xF000  /* DSP2DRC_NG_MINGAIN - [15:12] */
+#define WM8996_DSP2DRC_NG_MINGAIN_SHIFT             12  /* DSP2DRC_NG_MINGAIN - [15:12] */
+#define WM8996_DSP2DRC_NG_MINGAIN_WIDTH              4  /* DSP2DRC_NG_MINGAIN - [15:12] */
+#define WM8996_DSP2DRC_NG_EXP_MASK              0x0C00  /* DSP2DRC_NG_EXP - [11:10] */
+#define WM8996_DSP2DRC_NG_EXP_SHIFT                 10  /* DSP2DRC_NG_EXP - [11:10] */
+#define WM8996_DSP2DRC_NG_EXP_WIDTH                  2  /* DSP2DRC_NG_EXP - [11:10] */
+#define WM8996_DSP2DRC_QR_THR_MASK              0x0300  /* DSP2DRC_QR_THR - [9:8] */
+#define WM8996_DSP2DRC_QR_THR_SHIFT                  8  /* DSP2DRC_QR_THR - [9:8] */
+#define WM8996_DSP2DRC_QR_THR_WIDTH                  2  /* DSP2DRC_QR_THR - [9:8] */
+#define WM8996_DSP2DRC_QR_DCY_MASK              0x00C0  /* DSP2DRC_QR_DCY - [7:6] */
+#define WM8996_DSP2DRC_QR_DCY_SHIFT                  6  /* DSP2DRC_QR_DCY - [7:6] */
+#define WM8996_DSP2DRC_QR_DCY_WIDTH                  2  /* DSP2DRC_QR_DCY - [7:6] */
+#define WM8996_DSP2DRC_HI_COMP_MASK             0x0038  /* DSP2DRC_HI_COMP - [5:3] */
+#define WM8996_DSP2DRC_HI_COMP_SHIFT                 3  /* DSP2DRC_HI_COMP - [5:3] */
+#define WM8996_DSP2DRC_HI_COMP_WIDTH                 3  /* DSP2DRC_HI_COMP - [5:3] */
+#define WM8996_DSP2DRC_LO_COMP_MASK             0x0007  /* DSP2DRC_LO_COMP - [2:0] */
+#define WM8996_DSP2DRC_LO_COMP_SHIFT                 0  /* DSP2DRC_LO_COMP - [2:0] */
+#define WM8996_DSP2DRC_LO_COMP_WIDTH                 3  /* DSP2DRC_LO_COMP - [2:0] */
+
+/*
+ * R1347 (0x543) - DSP2 DRC (4)
+ */
+#define WM8996_DSP2DRC_KNEE_IP_MASK             0x07E0  /* DSP2DRC_KNEE_IP - [10:5] */
+#define WM8996_DSP2DRC_KNEE_IP_SHIFT                 5  /* DSP2DRC_KNEE_IP - [10:5] */
+#define WM8996_DSP2DRC_KNEE_IP_WIDTH                 6  /* DSP2DRC_KNEE_IP - [10:5] */
+#define WM8996_DSP2DRC_KNEE_OP_MASK             0x001F  /* DSP2DRC_KNEE_OP - [4:0] */
+#define WM8996_DSP2DRC_KNEE_OP_SHIFT                 0  /* DSP2DRC_KNEE_OP - [4:0] */
+#define WM8996_DSP2DRC_KNEE_OP_WIDTH                 5  /* DSP2DRC_KNEE_OP - [4:0] */
+
+/*
+ * R1348 (0x544) - DSP2 DRC (5)
+ */
+#define WM8996_DSP2DRC_KNEE2_IP_MASK            0x03E0  /* DSP2DRC_KNEE2_IP - [9:5] */
+#define WM8996_DSP2DRC_KNEE2_IP_SHIFT                5  /* DSP2DRC_KNEE2_IP - [9:5] */
+#define WM8996_DSP2DRC_KNEE2_IP_WIDTH                5  /* DSP2DRC_KNEE2_IP - [9:5] */
+#define WM8996_DSP2DRC_KNEE2_OP_MASK            0x001F  /* DSP2DRC_KNEE2_OP - [4:0] */
+#define WM8996_DSP2DRC_KNEE2_OP_SHIFT                0  /* DSP2DRC_KNEE2_OP - [4:0] */
+#define WM8996_DSP2DRC_KNEE2_OP_WIDTH                5  /* DSP2DRC_KNEE2_OP - [4:0] */
+
+/*
+ * R1408 (0x580) - DSP2 RX EQ Gains (1)
+ */
+#define WM8996_DSP2RX_EQ_B1_GAIN_MASK           0xF800  /* DSP2RX_EQ_B1_GAIN - [15:11] */
+#define WM8996_DSP2RX_EQ_B1_GAIN_SHIFT              11  /* DSP2RX_EQ_B1_GAIN - [15:11] */
+#define WM8996_DSP2RX_EQ_B1_GAIN_WIDTH               5  /* DSP2RX_EQ_B1_GAIN - [15:11] */
+#define WM8996_DSP2RX_EQ_B2_GAIN_MASK           0x07C0  /* DSP2RX_EQ_B2_GAIN - [10:6] */
+#define WM8996_DSP2RX_EQ_B2_GAIN_SHIFT               6  /* DSP2RX_EQ_B2_GAIN - [10:6] */
+#define WM8996_DSP2RX_EQ_B2_GAIN_WIDTH               5  /* DSP2RX_EQ_B2_GAIN - [10:6] */
+#define WM8996_DSP2RX_EQ_B3_GAIN_MASK           0x003E  /* DSP2RX_EQ_B3_GAIN - [5:1] */
+#define WM8996_DSP2RX_EQ_B3_GAIN_SHIFT               1  /* DSP2RX_EQ_B3_GAIN - [5:1] */
+#define WM8996_DSP2RX_EQ_B3_GAIN_WIDTH               5  /* DSP2RX_EQ_B3_GAIN - [5:1] */
+#define WM8996_DSP2RX_EQ_ENA                    0x0001  /* DSP2RX_EQ_ENA */
+#define WM8996_DSP2RX_EQ_ENA_MASK               0x0001  /* DSP2RX_EQ_ENA */
+#define WM8996_DSP2RX_EQ_ENA_SHIFT                   0  /* DSP2RX_EQ_ENA */
+#define WM8996_DSP2RX_EQ_ENA_WIDTH                   1  /* DSP2RX_EQ_ENA */
+
+/*
+ * R1409 (0x581) - DSP2 RX EQ Gains (2)
+ */
+#define WM8996_DSP2RX_EQ_B4_GAIN_MASK           0xF800  /* DSP2RX_EQ_B4_GAIN - [15:11] */
+#define WM8996_DSP2RX_EQ_B4_GAIN_SHIFT              11  /* DSP2RX_EQ_B4_GAIN - [15:11] */
+#define WM8996_DSP2RX_EQ_B4_GAIN_WIDTH               5  /* DSP2RX_EQ_B4_GAIN - [15:11] */
+#define WM8996_DSP2RX_EQ_B5_GAIN_MASK           0x07C0  /* DSP2RX_EQ_B5_GAIN - [10:6] */
+#define WM8996_DSP2RX_EQ_B5_GAIN_SHIFT               6  /* DSP2RX_EQ_B5_GAIN - [10:6] */
+#define WM8996_DSP2RX_EQ_B5_GAIN_WIDTH               5  /* DSP2RX_EQ_B5_GAIN - [10:6] */
+
+/*
+ * R1410 (0x582) - DSP2 RX EQ Band 1 A
+ */
+#define WM8996_DSP2RX_EQ_B1_A_MASK              0xFFFF  /* DSP2RX_EQ_B1_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B1_A_SHIFT                  0  /* DSP2RX_EQ_B1_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B1_A_WIDTH                 16  /* DSP2RX_EQ_B1_A - [15:0] */
+
+/*
+ * R1411 (0x583) - DSP2 RX EQ Band 1 B
+ */
+#define WM8996_DSP2RX_EQ_B1_B_MASK              0xFFFF  /* DSP2RX_EQ_B1_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B1_B_SHIFT                  0  /* DSP2RX_EQ_B1_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B1_B_WIDTH                 16  /* DSP2RX_EQ_B1_B - [15:0] */
+
+/*
+ * R1412 (0x584) - DSP2 RX EQ Band 1 PG
+ */
+#define WM8996_DSP2RX_EQ_B1_PG_MASK             0xFFFF  /* DSP2RX_EQ_B1_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B1_PG_SHIFT                 0  /* DSP2RX_EQ_B1_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B1_PG_WIDTH                16  /* DSP2RX_EQ_B1_PG - [15:0] */
+
+/*
+ * R1413 (0x585) - DSP2 RX EQ Band 2 A
+ */
+#define WM8996_DSP2RX_EQ_B2_A_MASK              0xFFFF  /* DSP2RX_EQ_B2_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B2_A_SHIFT                  0  /* DSP2RX_EQ_B2_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B2_A_WIDTH                 16  /* DSP2RX_EQ_B2_A - [15:0] */
+
+/*
+ * R1414 (0x586) - DSP2 RX EQ Band 2 B
+ */
+#define WM8996_DSP2RX_EQ_B2_B_MASK              0xFFFF  /* DSP2RX_EQ_B2_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B2_B_SHIFT                  0  /* DSP2RX_EQ_B2_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B2_B_WIDTH                 16  /* DSP2RX_EQ_B2_B - [15:0] */
+
+/*
+ * R1415 (0x587) - DSP2 RX EQ Band 2 C
+ */
+#define WM8996_DSP2RX_EQ_B2_C_MASK              0xFFFF  /* DSP2RX_EQ_B2_C - [15:0] */
+#define WM8996_DSP2RX_EQ_B2_C_SHIFT                  0  /* DSP2RX_EQ_B2_C - [15:0] */
+#define WM8996_DSP2RX_EQ_B2_C_WIDTH                 16  /* DSP2RX_EQ_B2_C - [15:0] */
+
+/*
+ * R1416 (0x588) - DSP2 RX EQ Band 2 PG
+ */
+#define WM8996_DSP2RX_EQ_B2_PG_MASK             0xFFFF  /* DSP2RX_EQ_B2_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B2_PG_SHIFT                 0  /* DSP2RX_EQ_B2_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B2_PG_WIDTH                16  /* DSP2RX_EQ_B2_PG - [15:0] */
+
+/*
+ * R1417 (0x589) - DSP2 RX EQ Band 3 A
+ */
+#define WM8996_DSP2RX_EQ_B3_A_MASK              0xFFFF  /* DSP2RX_EQ_B3_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B3_A_SHIFT                  0  /* DSP2RX_EQ_B3_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B3_A_WIDTH                 16  /* DSP2RX_EQ_B3_A - [15:0] */
+
+/*
+ * R1418 (0x58A) - DSP2 RX EQ Band 3 B
+ */
+#define WM8996_DSP2RX_EQ_B3_B_MASK              0xFFFF  /* DSP2RX_EQ_B3_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B3_B_SHIFT                  0  /* DSP2RX_EQ_B3_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B3_B_WIDTH                 16  /* DSP2RX_EQ_B3_B - [15:0] */
+
+/*
+ * R1419 (0x58B) - DSP2 RX EQ Band 3 C
+ */
+#define WM8996_DSP2RX_EQ_B3_C_MASK              0xFFFF  /* DSP2RX_EQ_B3_C - [15:0] */
+#define WM8996_DSP2RX_EQ_B3_C_SHIFT                  0  /* DSP2RX_EQ_B3_C - [15:0] */
+#define WM8996_DSP2RX_EQ_B3_C_WIDTH                 16  /* DSP2RX_EQ_B3_C - [15:0] */
+
+/*
+ * R1420 (0x58C) - DSP2 RX EQ Band 3 PG
+ */
+#define WM8996_DSP2RX_EQ_B3_PG_MASK             0xFFFF  /* DSP2RX_EQ_B3_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B3_PG_SHIFT                 0  /* DSP2RX_EQ_B3_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B3_PG_WIDTH                16  /* DSP2RX_EQ_B3_PG - [15:0] */
+
+/*
+ * R1421 (0x58D) - DSP2 RX EQ Band 4 A
+ */
+#define WM8996_DSP2RX_EQ_B4_A_MASK              0xFFFF  /* DSP2RX_EQ_B4_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B4_A_SHIFT                  0  /* DSP2RX_EQ_B4_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B4_A_WIDTH                 16  /* DSP2RX_EQ_B4_A - [15:0] */
+
+/*
+ * R1422 (0x58E) - DSP2 RX EQ Band 4 B
+ */
+#define WM8996_DSP2RX_EQ_B4_B_MASK              0xFFFF  /* DSP2RX_EQ_B4_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B4_B_SHIFT                  0  /* DSP2RX_EQ_B4_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B4_B_WIDTH                 16  /* DSP2RX_EQ_B4_B - [15:0] */
+
+/*
+ * R1423 (0x58F) - DSP2 RX EQ Band 4 C
+ */
+#define WM8996_DSP2RX_EQ_B4_C_MASK              0xFFFF  /* DSP2RX_EQ_B4_C - [15:0] */
+#define WM8996_DSP2RX_EQ_B4_C_SHIFT                  0  /* DSP2RX_EQ_B4_C - [15:0] */
+#define WM8996_DSP2RX_EQ_B4_C_WIDTH                 16  /* DSP2RX_EQ_B4_C - [15:0] */
+
+/*
+ * R1424 (0x590) - DSP2 RX EQ Band 4 PG
+ */
+#define WM8996_DSP2RX_EQ_B4_PG_MASK             0xFFFF  /* DSP2RX_EQ_B4_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B4_PG_SHIFT                 0  /* DSP2RX_EQ_B4_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B4_PG_WIDTH                16  /* DSP2RX_EQ_B4_PG - [15:0] */
+
+/*
+ * R1425 (0x591) - DSP2 RX EQ Band 5 A
+ */
+#define WM8996_DSP2RX_EQ_B5_A_MASK              0xFFFF  /* DSP2RX_EQ_B5_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B5_A_SHIFT                  0  /* DSP2RX_EQ_B5_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B5_A_WIDTH                 16  /* DSP2RX_EQ_B5_A - [15:0] */
+
+/*
+ * R1426 (0x592) - DSP2 RX EQ Band 5 B
+ */
+#define WM8996_DSP2RX_EQ_B5_B_MASK              0xFFFF  /* DSP2RX_EQ_B5_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B5_B_SHIFT                  0  /* DSP2RX_EQ_B5_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B5_B_WIDTH                 16  /* DSP2RX_EQ_B5_B - [15:0] */
+
+/*
+ * R1427 (0x593) - DSP2 RX EQ Band 5 PG
+ */
+#define WM8996_DSP2RX_EQ_B5_PG_MASK             0xFFFF  /* DSP2RX_EQ_B5_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B5_PG_SHIFT                 0  /* DSP2RX_EQ_B5_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B5_PG_WIDTH                16  /* DSP2RX_EQ_B5_PG - [15:0] */
+
+/*
+ * R1536 (0x600) - DAC1 Mixer Volumes
+ */
+#define WM8996_ADCR_DAC1_VOL_MASK               0x03E0  /* ADCR_DAC1_VOL - [9:5] */
+#define WM8996_ADCR_DAC1_VOL_SHIFT                   5  /* ADCR_DAC1_VOL - [9:5] */
+#define WM8996_ADCR_DAC1_VOL_WIDTH                   5  /* ADCR_DAC1_VOL - [9:5] */
+#define WM8996_ADCL_DAC1_VOL_MASK               0x001F  /* ADCL_DAC1_VOL - [4:0] */
+#define WM8996_ADCL_DAC1_VOL_SHIFT                   0  /* ADCL_DAC1_VOL - [4:0] */
+#define WM8996_ADCL_DAC1_VOL_WIDTH                   5  /* ADCL_DAC1_VOL - [4:0] */
+
+/*
+ * R1537 (0x601) - DAC1 Left Mixer Routing
+ */
+#define WM8996_ADCR_TO_DAC1L                    0x0020  /* ADCR_TO_DAC1L */
+#define WM8996_ADCR_TO_DAC1L_MASK               0x0020  /* ADCR_TO_DAC1L */
+#define WM8996_ADCR_TO_DAC1L_SHIFT                   5  /* ADCR_TO_DAC1L */
+#define WM8996_ADCR_TO_DAC1L_WIDTH                   1  /* ADCR_TO_DAC1L */
+#define WM8996_ADCL_TO_DAC1L                    0x0010  /* ADCL_TO_DAC1L */
+#define WM8996_ADCL_TO_DAC1L_MASK               0x0010  /* ADCL_TO_DAC1L */
+#define WM8996_ADCL_TO_DAC1L_SHIFT                   4  /* ADCL_TO_DAC1L */
+#define WM8996_ADCL_TO_DAC1L_WIDTH                   1  /* ADCL_TO_DAC1L */
+#define WM8996_DSP2RXL_TO_DAC1L                 0x0002  /* DSP2RXL_TO_DAC1L */
+#define WM8996_DSP2RXL_TO_DAC1L_MASK            0x0002  /* DSP2RXL_TO_DAC1L */
+#define WM8996_DSP2RXL_TO_DAC1L_SHIFT                1  /* DSP2RXL_TO_DAC1L */
+#define WM8996_DSP2RXL_TO_DAC1L_WIDTH                1  /* DSP2RXL_TO_DAC1L */
+#define WM8996_DSP1RXL_TO_DAC1L                 0x0001  /* DSP1RXL_TO_DAC1L */
+#define WM8996_DSP1RXL_TO_DAC1L_MASK            0x0001  /* DSP1RXL_TO_DAC1L */
+#define WM8996_DSP1RXL_TO_DAC1L_SHIFT                0  /* DSP1RXL_TO_DAC1L */
+#define WM8996_DSP1RXL_TO_DAC1L_WIDTH                1  /* DSP1RXL_TO_DAC1L */
+
+/*
+ * R1538 (0x602) - DAC1 Right Mixer Routing
+ */
+#define WM8996_ADCR_TO_DAC1R                    0x0020  /* ADCR_TO_DAC1R */
+#define WM8996_ADCR_TO_DAC1R_MASK               0x0020  /* ADCR_TO_DAC1R */
+#define WM8996_ADCR_TO_DAC1R_SHIFT                   5  /* ADCR_TO_DAC1R */
+#define WM8996_ADCR_TO_DAC1R_WIDTH                   1  /* ADCR_TO_DAC1R */
+#define WM8996_ADCL_TO_DAC1R                    0x0010  /* ADCL_TO_DAC1R */
+#define WM8996_ADCL_TO_DAC1R_MASK               0x0010  /* ADCL_TO_DAC1R */
+#define WM8996_ADCL_TO_DAC1R_SHIFT                   4  /* ADCL_TO_DAC1R */
+#define WM8996_ADCL_TO_DAC1R_WIDTH                   1  /* ADCL_TO_DAC1R */
+#define WM8996_DSP2RXR_TO_DAC1R                 0x0002  /* DSP2RXR_TO_DAC1R */
+#define WM8996_DSP2RXR_TO_DAC1R_MASK            0x0002  /* DSP2RXR_TO_DAC1R */
+#define WM8996_DSP2RXR_TO_DAC1R_SHIFT                1  /* DSP2RXR_TO_DAC1R */
+#define WM8996_DSP2RXR_TO_DAC1R_WIDTH                1  /* DSP2RXR_TO_DAC1R */
+#define WM8996_DSP1RXR_TO_DAC1R                 0x0001  /* DSP1RXR_TO_DAC1R */
+#define WM8996_DSP1RXR_TO_DAC1R_MASK            0x0001  /* DSP1RXR_TO_DAC1R */
+#define WM8996_DSP1RXR_TO_DAC1R_SHIFT                0  /* DSP1RXR_TO_DAC1R */
+#define WM8996_DSP1RXR_TO_DAC1R_WIDTH                1  /* DSP1RXR_TO_DAC1R */
+
+/*
+ * R1539 (0x603) - DAC2 Mixer Volumes
+ */
+#define WM8996_ADCR_DAC2_VOL_MASK               0x03E0  /* ADCR_DAC2_VOL - [9:5] */
+#define WM8996_ADCR_DAC2_VOL_SHIFT                   5  /* ADCR_DAC2_VOL - [9:5] */
+#define WM8996_ADCR_DAC2_VOL_WIDTH                   5  /* ADCR_DAC2_VOL - [9:5] */
+#define WM8996_ADCL_DAC2_VOL_MASK               0x001F  /* ADCL_DAC2_VOL - [4:0] */
+#define WM8996_ADCL_DAC2_VOL_SHIFT                   0  /* ADCL_DAC2_VOL - [4:0] */
+#define WM8996_ADCL_DAC2_VOL_WIDTH                   5  /* ADCL_DAC2_VOL - [4:0] */
+
+/*
+ * R1540 (0x604) - DAC2 Left Mixer Routing
+ */
+#define WM8996_ADCR_TO_DAC2L                    0x0020  /* ADCR_TO_DAC2L */
+#define WM8996_ADCR_TO_DAC2L_MASK               0x0020  /* ADCR_TO_DAC2L */
+#define WM8996_ADCR_TO_DAC2L_SHIFT                   5  /* ADCR_TO_DAC2L */
+#define WM8996_ADCR_TO_DAC2L_WIDTH                   1  /* ADCR_TO_DAC2L */
+#define WM8996_ADCL_TO_DAC2L                    0x0010  /* ADCL_TO_DAC2L */
+#define WM8996_ADCL_TO_DAC2L_MASK               0x0010  /* ADCL_TO_DAC2L */
+#define WM8996_ADCL_TO_DAC2L_SHIFT                   4  /* ADCL_TO_DAC2L */
+#define WM8996_ADCL_TO_DAC2L_WIDTH                   1  /* ADCL_TO_DAC2L */
+#define WM8996_DSP2RXL_TO_DAC2L                 0x0002  /* DSP2RXL_TO_DAC2L */
+#define WM8996_DSP2RXL_TO_DAC2L_MASK            0x0002  /* DSP2RXL_TO_DAC2L */
+#define WM8996_DSP2RXL_TO_DAC2L_SHIFT                1  /* DSP2RXL_TO_DAC2L */
+#define WM8996_DSP2RXL_TO_DAC2L_WIDTH                1  /* DSP2RXL_TO_DAC2L */
+#define WM8996_DSP1RXL_TO_DAC2L                 0x0001  /* DSP1RXL_TO_DAC2L */
+#define WM8996_DSP1RXL_TO_DAC2L_MASK            0x0001  /* DSP1RXL_TO_DAC2L */
+#define WM8996_DSP1RXL_TO_DAC2L_SHIFT                0  /* DSP1RXL_TO_DAC2L */
+#define WM8996_DSP1RXL_TO_DAC2L_WIDTH                1  /* DSP1RXL_TO_DAC2L */
+
+/*
+ * R1541 (0x605) - DAC2 Right Mixer Routing
+ */
+#define WM8996_ADCR_TO_DAC2R                    0x0020  /* ADCR_TO_DAC2R */
+#define WM8996_ADCR_TO_DAC2R_MASK               0x0020  /* ADCR_TO_DAC2R */
+#define WM8996_ADCR_TO_DAC2R_SHIFT                   5  /* ADCR_TO_DAC2R */
+#define WM8996_ADCR_TO_DAC2R_WIDTH                   1  /* ADCR_TO_DAC2R */
+#define WM8996_ADCL_TO_DAC2R                    0x0010  /* ADCL_TO_DAC2R */
+#define WM8996_ADCL_TO_DAC2R_MASK               0x0010  /* ADCL_TO_DAC2R */
+#define WM8996_ADCL_TO_DAC2R_SHIFT                   4  /* ADCL_TO_DAC2R */
+#define WM8996_ADCL_TO_DAC2R_WIDTH                   1  /* ADCL_TO_DAC2R */
+#define WM8996_DSP2RXR_TO_DAC2R                 0x0002  /* DSP2RXR_TO_DAC2R */
+#define WM8996_DSP2RXR_TO_DAC2R_MASK            0x0002  /* DSP2RXR_TO_DAC2R */
+#define WM8996_DSP2RXR_TO_DAC2R_SHIFT                1  /* DSP2RXR_TO_DAC2R */
+#define WM8996_DSP2RXR_TO_DAC2R_WIDTH                1  /* DSP2RXR_TO_DAC2R */
+#define WM8996_DSP1RXR_TO_DAC2R                 0x0001  /* DSP1RXR_TO_DAC2R */
+#define WM8996_DSP1RXR_TO_DAC2R_MASK            0x0001  /* DSP1RXR_TO_DAC2R */
+#define WM8996_DSP1RXR_TO_DAC2R_SHIFT                0  /* DSP1RXR_TO_DAC2R */
+#define WM8996_DSP1RXR_TO_DAC2R_WIDTH                1  /* DSP1RXR_TO_DAC2R */
+
+/*
+ * R1542 (0x606) - DSP1 TX Left Mixer Routing
+ */
+#define WM8996_ADC1L_TO_DSP1TXL                 0x0002  /* ADC1L_TO_DSP1TXL */
+#define WM8996_ADC1L_TO_DSP1TXL_MASK            0x0002  /* ADC1L_TO_DSP1TXL */
+#define WM8996_ADC1L_TO_DSP1TXL_SHIFT                1  /* ADC1L_TO_DSP1TXL */
+#define WM8996_ADC1L_TO_DSP1TXL_WIDTH                1  /* ADC1L_TO_DSP1TXL */
+#define WM8996_DACL_TO_DSP1TXL                  0x0001  /* DACL_TO_DSP1TXL */
+#define WM8996_DACL_TO_DSP1TXL_MASK             0x0001  /* DACL_TO_DSP1TXL */
+#define WM8996_DACL_TO_DSP1TXL_SHIFT                 0  /* DACL_TO_DSP1TXL */
+#define WM8996_DACL_TO_DSP1TXL_WIDTH                 1  /* DACL_TO_DSP1TXL */
+
+/*
+ * R1543 (0x607) - DSP1 TX Right Mixer Routing
+ */
+#define WM8996_ADC1R_TO_DSP1TXR                 0x0002  /* ADC1R_TO_DSP1TXR */
+#define WM8996_ADC1R_TO_DSP1TXR_MASK            0x0002  /* ADC1R_TO_DSP1TXR */
+#define WM8996_ADC1R_TO_DSP1TXR_SHIFT                1  /* ADC1R_TO_DSP1TXR */
+#define WM8996_ADC1R_TO_DSP1TXR_WIDTH                1  /* ADC1R_TO_DSP1TXR */
+#define WM8996_DACR_TO_DSP1TXR                  0x0001  /* DACR_TO_DSP1TXR */
+#define WM8996_DACR_TO_DSP1TXR_MASK             0x0001  /* DACR_TO_DSP1TXR */
+#define WM8996_DACR_TO_DSP1TXR_SHIFT                 0  /* DACR_TO_DSP1TXR */
+#define WM8996_DACR_TO_DSP1TXR_WIDTH                 1  /* DACR_TO_DSP1TXR */
+
+/*
+ * R1544 (0x608) - DSP2 TX Left Mixer Routing
+ */
+#define WM8996_ADC2L_TO_DSP2TXL                 0x0002  /* ADC2L_TO_DSP2TXL */
+#define WM8996_ADC2L_TO_DSP2TXL_MASK            0x0002  /* ADC2L_TO_DSP2TXL */
+#define WM8996_ADC2L_TO_DSP2TXL_SHIFT                1  /* ADC2L_TO_DSP2TXL */
+#define WM8996_ADC2L_TO_DSP2TXL_WIDTH                1  /* ADC2L_TO_DSP2TXL */
+#define WM8996_DACL_TO_DSP2TXL                  0x0001  /* DACL_TO_DSP2TXL */
+#define WM8996_DACL_TO_DSP2TXL_MASK             0x0001  /* DACL_TO_DSP2TXL */
+#define WM8996_DACL_TO_DSP2TXL_SHIFT                 0  /* DACL_TO_DSP2TXL */
+#define WM8996_DACL_TO_DSP2TXL_WIDTH                 1  /* DACL_TO_DSP2TXL */
+
+/*
+ * R1545 (0x609) - DSP2 TX Right Mixer Routing
+ */
+#define WM8996_ADC2R_TO_DSP2TXR                 0x0002  /* ADC2R_TO_DSP2TXR */
+#define WM8996_ADC2R_TO_DSP2TXR_MASK            0x0002  /* ADC2R_TO_DSP2TXR */
+#define WM8996_ADC2R_TO_DSP2TXR_SHIFT                1  /* ADC2R_TO_DSP2TXR */
+#define WM8996_ADC2R_TO_DSP2TXR_WIDTH                1  /* ADC2R_TO_DSP2TXR */
+#define WM8996_DACR_TO_DSP2TXR                  0x0001  /* DACR_TO_DSP2TXR */
+#define WM8996_DACR_TO_DSP2TXR_MASK             0x0001  /* DACR_TO_DSP2TXR */
+#define WM8996_DACR_TO_DSP2TXR_SHIFT                 0  /* DACR_TO_DSP2TXR */
+#define WM8996_DACR_TO_DSP2TXR_WIDTH                 1  /* DACR_TO_DSP2TXR */
+
+/*
+ * R1546 (0x60A) - DSP TX Mixer Select
+ */
+#define WM8996_DAC_TO_DSPTX_SRC                 0x0001  /* DAC_TO_DSPTX_SRC */
+#define WM8996_DAC_TO_DSPTX_SRC_MASK            0x0001  /* DAC_TO_DSPTX_SRC */
+#define WM8996_DAC_TO_DSPTX_SRC_SHIFT                0  /* DAC_TO_DSPTX_SRC */
+#define WM8996_DAC_TO_DSPTX_SRC_WIDTH                1  /* DAC_TO_DSPTX_SRC */
+
+/*
+ * R1552 (0x610) - DAC Softmute
+ */
+#define WM8996_DAC_SOFTMUTEMODE                 0x0002  /* DAC_SOFTMUTEMODE */
+#define WM8996_DAC_SOFTMUTEMODE_MASK            0x0002  /* DAC_SOFTMUTEMODE */
+#define WM8996_DAC_SOFTMUTEMODE_SHIFT                1  /* DAC_SOFTMUTEMODE */
+#define WM8996_DAC_SOFTMUTEMODE_WIDTH                1  /* DAC_SOFTMUTEMODE */
+#define WM8996_DAC_MUTERATE                     0x0001  /* DAC_MUTERATE */
+#define WM8996_DAC_MUTERATE_MASK                0x0001  /* DAC_MUTERATE */
+#define WM8996_DAC_MUTERATE_SHIFT                    0  /* DAC_MUTERATE */
+#define WM8996_DAC_MUTERATE_WIDTH                    1  /* DAC_MUTERATE */
+
+/*
+ * R1568 (0x620) - Oversampling
+ */
+#define WM8996_SPK_OSR128                       0x0008  /* SPK_OSR128 */
+#define WM8996_SPK_OSR128_MASK                  0x0008  /* SPK_OSR128 */
+#define WM8996_SPK_OSR128_SHIFT                      3  /* SPK_OSR128 */
+#define WM8996_SPK_OSR128_WIDTH                      1  /* SPK_OSR128 */
+#define WM8996_DMIC_OSR64                       0x0004  /* DMIC_OSR64 */
+#define WM8996_DMIC_OSR64_MASK                  0x0004  /* DMIC_OSR64 */
+#define WM8996_DMIC_OSR64_SHIFT                      2  /* DMIC_OSR64 */
+#define WM8996_DMIC_OSR64_WIDTH                      1  /* DMIC_OSR64 */
+#define WM8996_ADC_OSR128                       0x0002  /* ADC_OSR128 */
+#define WM8996_ADC_OSR128_MASK                  0x0002  /* ADC_OSR128 */
+#define WM8996_ADC_OSR128_SHIFT                      1  /* ADC_OSR128 */
+#define WM8996_ADC_OSR128_WIDTH                      1  /* ADC_OSR128 */
+#define WM8996_DAC_OSR128                       0x0001  /* DAC_OSR128 */
+#define WM8996_DAC_OSR128_MASK                  0x0001  /* DAC_OSR128 */
+#define WM8996_DAC_OSR128_SHIFT                      0  /* DAC_OSR128 */
+#define WM8996_DAC_OSR128_WIDTH                      1  /* DAC_OSR128 */
+
+/*
+ * R1569 (0x621) - Sidetone
+ */
+#define WM8996_ST_LPF                           0x1000  /* ST_LPF */
+#define WM8996_ST_LPF_MASK                      0x1000  /* ST_LPF */
+#define WM8996_ST_LPF_SHIFT                         12  /* ST_LPF */
+#define WM8996_ST_LPF_WIDTH                          1  /* ST_LPF */
+#define WM8996_ST_HPF_CUT_MASK                  0x0380  /* ST_HPF_CUT - [9:7] */
+#define WM8996_ST_HPF_CUT_SHIFT                      7  /* ST_HPF_CUT - [9:7] */
+#define WM8996_ST_HPF_CUT_WIDTH                      3  /* ST_HPF_CUT - [9:7] */
+#define WM8996_ST_HPF                           0x0040  /* ST_HPF */
+#define WM8996_ST_HPF_MASK                      0x0040  /* ST_HPF */
+#define WM8996_ST_HPF_SHIFT                          6  /* ST_HPF */
+#define WM8996_ST_HPF_WIDTH                          1  /* ST_HPF */
+#define WM8996_STR_SEL                          0x0002  /* STR_SEL */
+#define WM8996_STR_SEL_MASK                     0x0002  /* STR_SEL */
+#define WM8996_STR_SEL_SHIFT                         1  /* STR_SEL */
+#define WM8996_STR_SEL_WIDTH                         1  /* STR_SEL */
+#define WM8996_STL_SEL                          0x0001  /* STL_SEL */
+#define WM8996_STL_SEL_MASK                     0x0001  /* STL_SEL */
+#define WM8996_STL_SEL_SHIFT                         0  /* STL_SEL */
+#define WM8996_STL_SEL_WIDTH                         1  /* STL_SEL */
+
+/*
+ * R1792 (0x700) - GPIO 1
+ */
+#define WM8996_GP1_DIR                          0x8000  /* GP1_DIR */
+#define WM8996_GP1_DIR_MASK                     0x8000  /* GP1_DIR */
+#define WM8996_GP1_DIR_SHIFT                        15  /* GP1_DIR */
+#define WM8996_GP1_DIR_WIDTH                         1  /* GP1_DIR */
+#define WM8996_GP1_PU                           0x4000  /* GP1_PU */
+#define WM8996_GP1_PU_MASK                      0x4000  /* GP1_PU */
+#define WM8996_GP1_PU_SHIFT                         14  /* GP1_PU */
+#define WM8996_GP1_PU_WIDTH                          1  /* GP1_PU */
+#define WM8996_GP1_PD                           0x2000  /* GP1_PD */
+#define WM8996_GP1_PD_MASK                      0x2000  /* GP1_PD */
+#define WM8996_GP1_PD_SHIFT                         13  /* GP1_PD */
+#define WM8996_GP1_PD_WIDTH                          1  /* GP1_PD */
+#define WM8996_GP1_POL                          0x0400  /* GP1_POL */
+#define WM8996_GP1_POL_MASK                     0x0400  /* GP1_POL */
+#define WM8996_GP1_POL_SHIFT                        10  /* GP1_POL */
+#define WM8996_GP1_POL_WIDTH                         1  /* GP1_POL */
+#define WM8996_GP1_OP_CFG                       0x0200  /* GP1_OP_CFG */
+#define WM8996_GP1_OP_CFG_MASK                  0x0200  /* GP1_OP_CFG */
+#define WM8996_GP1_OP_CFG_SHIFT                      9  /* GP1_OP_CFG */
+#define WM8996_GP1_OP_CFG_WIDTH                      1  /* GP1_OP_CFG */
+#define WM8996_GP1_DB                           0x0100  /* GP1_DB */
+#define WM8996_GP1_DB_MASK                      0x0100  /* GP1_DB */
+#define WM8996_GP1_DB_SHIFT                          8  /* GP1_DB */
+#define WM8996_GP1_DB_WIDTH                          1  /* GP1_DB */
+#define WM8996_GP1_LVL                          0x0040  /* GP1_LVL */
+#define WM8996_GP1_LVL_MASK                     0x0040  /* GP1_LVL */
+#define WM8996_GP1_LVL_SHIFT                         6  /* GP1_LVL */
+#define WM8996_GP1_LVL_WIDTH                         1  /* GP1_LVL */
+#define WM8996_GP1_FN_MASK                      0x000F  /* GP1_FN - [3:0] */
+#define WM8996_GP1_FN_SHIFT                          0  /* GP1_FN - [3:0] */
+#define WM8996_GP1_FN_WIDTH                          4  /* GP1_FN - [3:0] */
+
+/*
+ * R1793 (0x701) - GPIO 2
+ */
+#define WM8996_GP2_DIR                          0x8000  /* GP2_DIR */
+#define WM8996_GP2_DIR_MASK                     0x8000  /* GP2_DIR */
+#define WM8996_GP2_DIR_SHIFT                        15  /* GP2_DIR */
+#define WM8996_GP2_DIR_WIDTH                         1  /* GP2_DIR */
+#define WM8996_GP2_PU                           0x4000  /* GP2_PU */
+#define WM8996_GP2_PU_MASK                      0x4000  /* GP2_PU */
+#define WM8996_GP2_PU_SHIFT                         14  /* GP2_PU */
+#define WM8996_GP2_PU_WIDTH                          1  /* GP2_PU */
+#define WM8996_GP2_PD                           0x2000  /* GP2_PD */
+#define WM8996_GP2_PD_MASK                      0x2000  /* GP2_PD */
+#define WM8996_GP2_PD_SHIFT                         13  /* GP2_PD */
+#define WM8996_GP2_PD_WIDTH                          1  /* GP2_PD */
+#define WM8996_GP2_POL                          0x0400  /* GP2_POL */
+#define WM8996_GP2_POL_MASK                     0x0400  /* GP2_POL */
+#define WM8996_GP2_POL_SHIFT                        10  /* GP2_POL */
+#define WM8996_GP2_POL_WIDTH                         1  /* GP2_POL */
+#define WM8996_GP2_OP_CFG                       0x0200  /* GP2_OP_CFG */
+#define WM8996_GP2_OP_CFG_MASK                  0x0200  /* GP2_OP_CFG */
+#define WM8996_GP2_OP_CFG_SHIFT                      9  /* GP2_OP_CFG */
+#define WM8996_GP2_OP_CFG_WIDTH                      1  /* GP2_OP_CFG */
+#define WM8996_GP2_DB                           0x0100  /* GP2_DB */
+#define WM8996_GP2_DB_MASK                      0x0100  /* GP2_DB */
+#define WM8996_GP2_DB_SHIFT                          8  /* GP2_DB */
+#define WM8996_GP2_DB_WIDTH                          1  /* GP2_DB */
+#define WM8996_GP2_LVL                          0x0040  /* GP2_LVL */
+#define WM8996_GP2_LVL_MASK                     0x0040  /* GP2_LVL */
+#define WM8996_GP2_LVL_SHIFT                         6  /* GP2_LVL */
+#define WM8996_GP2_LVL_WIDTH                         1  /* GP2_LVL */
+#define WM8996_GP2_FN_MASK                      0x000F  /* GP2_FN - [3:0] */
+#define WM8996_GP2_FN_SHIFT                          0  /* GP2_FN - [3:0] */
+#define WM8996_GP2_FN_WIDTH                          4  /* GP2_FN - [3:0] */
+
+/*
+ * R1794 (0x702) - GPIO 3
+ */
+#define WM8996_GP3_DIR                          0x8000  /* GP3_DIR */
+#define WM8996_GP3_DIR_MASK                     0x8000  /* GP3_DIR */
+#define WM8996_GP3_DIR_SHIFT                        15  /* GP3_DIR */
+#define WM8996_GP3_DIR_WIDTH                         1  /* GP3_DIR */
+#define WM8996_GP3_PU                           0x4000  /* GP3_PU */
+#define WM8996_GP3_PU_MASK                      0x4000  /* GP3_PU */
+#define WM8996_GP3_PU_SHIFT                         14  /* GP3_PU */
+#define WM8996_GP3_PU_WIDTH                          1  /* GP3_PU */
+#define WM8996_GP3_PD                           0x2000  /* GP3_PD */
+#define WM8996_GP3_PD_MASK                      0x2000  /* GP3_PD */
+#define WM8996_GP3_PD_SHIFT                         13  /* GP3_PD */
+#define WM8996_GP3_PD_WIDTH                          1  /* GP3_PD */
+#define WM8996_GP3_POL                          0x0400  /* GP3_POL */
+#define WM8996_GP3_POL_MASK                     0x0400  /* GP3_POL */
+#define WM8996_GP3_POL_SHIFT                        10  /* GP3_POL */
+#define WM8996_GP3_POL_WIDTH                         1  /* GP3_POL */
+#define WM8996_GP3_OP_CFG                       0x0200  /* GP3_OP_CFG */
+#define WM8996_GP3_OP_CFG_MASK                  0x0200  /* GP3_OP_CFG */
+#define WM8996_GP3_OP_CFG_SHIFT                      9  /* GP3_OP_CFG */
+#define WM8996_GP3_OP_CFG_WIDTH                      1  /* GP3_OP_CFG */
+#define WM8996_GP3_DB                           0x0100  /* GP3_DB */
+#define WM8996_GP3_DB_MASK                      0x0100  /* GP3_DB */
+#define WM8996_GP3_DB_SHIFT                          8  /* GP3_DB */
+#define WM8996_GP3_DB_WIDTH                          1  /* GP3_DB */
+#define WM8996_GP3_LVL                          0x0040  /* GP3_LVL */
+#define WM8996_GP3_LVL_MASK                     0x0040  /* GP3_LVL */
+#define WM8996_GP3_LVL_SHIFT                         6  /* GP3_LVL */
+#define WM8996_GP3_LVL_WIDTH                         1  /* GP3_LVL */
+#define WM8996_GP3_FN_MASK                      0x000F  /* GP3_FN - [3:0] */
+#define WM8996_GP3_FN_SHIFT                          0  /* GP3_FN - [3:0] */
+#define WM8996_GP3_FN_WIDTH                          4  /* GP3_FN - [3:0] */
+
+/*
+ * R1795 (0x703) - GPIO 4
+ */
+#define WM8996_GP4_DIR                          0x8000  /* GP4_DIR */
+#define WM8996_GP4_DIR_MASK                     0x8000  /* GP4_DIR */
+#define WM8996_GP4_DIR_SHIFT                        15  /* GP4_DIR */
+#define WM8996_GP4_DIR_WIDTH                         1  /* GP4_DIR */
+#define WM8996_GP4_PU                           0x4000  /* GP4_PU */
+#define WM8996_GP4_PU_MASK                      0x4000  /* GP4_PU */
+#define WM8996_GP4_PU_SHIFT                         14  /* GP4_PU */
+#define WM8996_GP4_PU_WIDTH                          1  /* GP4_PU */
+#define WM8996_GP4_PD                           0x2000  /* GP4_PD */
+#define WM8996_GP4_PD_MASK                      0x2000  /* GP4_PD */
+#define WM8996_GP4_PD_SHIFT                         13  /* GP4_PD */
+#define WM8996_GP4_PD_WIDTH                          1  /* GP4_PD */
+#define WM8996_GP4_POL                          0x0400  /* GP4_POL */
+#define WM8996_GP4_POL_MASK                     0x0400  /* GP4_POL */
+#define WM8996_GP4_POL_SHIFT                        10  /* GP4_POL */
+#define WM8996_GP4_POL_WIDTH                         1  /* GP4_POL */
+#define WM8996_GP4_OP_CFG                       0x0200  /* GP4_OP_CFG */
+#define WM8996_GP4_OP_CFG_MASK                  0x0200  /* GP4_OP_CFG */
+#define WM8996_GP4_OP_CFG_SHIFT                      9  /* GP4_OP_CFG */
+#define WM8996_GP4_OP_CFG_WIDTH                      1  /* GP4_OP_CFG */
+#define WM8996_GP4_DB                           0x0100  /* GP4_DB */
+#define WM8996_GP4_DB_MASK                      0x0100  /* GP4_DB */
+#define WM8996_GP4_DB_SHIFT                          8  /* GP4_DB */
+#define WM8996_GP4_DB_WIDTH                          1  /* GP4_DB */
+#define WM8996_GP4_LVL                          0x0040  /* GP4_LVL */
+#define WM8996_GP4_LVL_MASK                     0x0040  /* GP4_LVL */
+#define WM8996_GP4_LVL_SHIFT                         6  /* GP4_LVL */
+#define WM8996_GP4_LVL_WIDTH                         1  /* GP4_LVL */
+#define WM8996_GP4_FN_MASK                      0x000F  /* GP4_FN - [3:0] */
+#define WM8996_GP4_FN_SHIFT                          0  /* GP4_FN - [3:0] */
+#define WM8996_GP4_FN_WIDTH                          4  /* GP4_FN - [3:0] */
+
+/*
+ * R1796 (0x704) - GPIO 5
+ */
+#define WM8996_GP5_DIR                          0x8000  /* GP5_DIR */
+#define WM8996_GP5_DIR_MASK                     0x8000  /* GP5_DIR */
+#define WM8996_GP5_DIR_SHIFT                        15  /* GP5_DIR */
+#define WM8996_GP5_DIR_WIDTH                         1  /* GP5_DIR */
+#define WM8996_GP5_PU                           0x4000  /* GP5_PU */
+#define WM8996_GP5_PU_MASK                      0x4000  /* GP5_PU */
+#define WM8996_GP5_PU_SHIFT                         14  /* GP5_PU */
+#define WM8996_GP5_PU_WIDTH                          1  /* GP5_PU */
+#define WM8996_GP5_PD                           0x2000  /* GP5_PD */
+#define WM8996_GP5_PD_MASK                      0x2000  /* GP5_PD */
+#define WM8996_GP5_PD_SHIFT                         13  /* GP5_PD */
+#define WM8996_GP5_PD_WIDTH                          1  /* GP5_PD */
+#define WM8996_GP5_POL                          0x0400  /* GP5_POL */
+#define WM8996_GP5_POL_MASK                     0x0400  /* GP5_POL */
+#define WM8996_GP5_POL_SHIFT                        10  /* GP5_POL */
+#define WM8996_GP5_POL_WIDTH                         1  /* GP5_POL */
+#define WM8996_GP5_OP_CFG                       0x0200  /* GP5_OP_CFG */
+#define WM8996_GP5_OP_CFG_MASK                  0x0200  /* GP5_OP_CFG */
+#define WM8996_GP5_OP_CFG_SHIFT                      9  /* GP5_OP_CFG */
+#define WM8996_GP5_OP_CFG_WIDTH                      1  /* GP5_OP_CFG */
+#define WM8996_GP5_DB                           0x0100  /* GP5_DB */
+#define WM8996_GP5_DB_MASK                      0x0100  /* GP5_DB */
+#define WM8996_GP5_DB_SHIFT                          8  /* GP5_DB */
+#define WM8996_GP5_DB_WIDTH                          1  /* GP5_DB */
+#define WM8996_GP5_LVL                          0x0040  /* GP5_LVL */
+#define WM8996_GP5_LVL_MASK                     0x0040  /* GP5_LVL */
+#define WM8996_GP5_LVL_SHIFT                         6  /* GP5_LVL */
+#define WM8996_GP5_LVL_WIDTH                         1  /* GP5_LVL */
+#define WM8996_GP5_FN_MASK                      0x000F  /* GP5_FN - [3:0] */
+#define WM8996_GP5_FN_SHIFT                          0  /* GP5_FN - [3:0] */
+#define WM8996_GP5_FN_WIDTH                          4  /* GP5_FN - [3:0] */
+
+/*
+ * R1824 (0x720) - Pull Control (1)
+ */
+#define WM8996_DMICDAT2_PD                      0x1000  /* DMICDAT2_PD */
+#define WM8996_DMICDAT2_PD_MASK                 0x1000  /* DMICDAT2_PD */
+#define WM8996_DMICDAT2_PD_SHIFT                    12  /* DMICDAT2_PD */
+#define WM8996_DMICDAT2_PD_WIDTH                     1  /* DMICDAT2_PD */
+#define WM8996_DMICDAT1_PD                      0x0400  /* DMICDAT1_PD */
+#define WM8996_DMICDAT1_PD_MASK                 0x0400  /* DMICDAT1_PD */
+#define WM8996_DMICDAT1_PD_SHIFT                    10  /* DMICDAT1_PD */
+#define WM8996_DMICDAT1_PD_WIDTH                     1  /* DMICDAT1_PD */
+#define WM8996_MCLK2_PU                         0x0200  /* MCLK2_PU */
+#define WM8996_MCLK2_PU_MASK                    0x0200  /* MCLK2_PU */
+#define WM8996_MCLK2_PU_SHIFT                        9  /* MCLK2_PU */
+#define WM8996_MCLK2_PU_WIDTH                        1  /* MCLK2_PU */
+#define WM8996_MCLK2_PD                         0x0100  /* MCLK2_PD */
+#define WM8996_MCLK2_PD_MASK                    0x0100  /* MCLK2_PD */
+#define WM8996_MCLK2_PD_SHIFT                        8  /* MCLK2_PD */
+#define WM8996_MCLK2_PD_WIDTH                        1  /* MCLK2_PD */
+#define WM8996_MCLK1_PU                         0x0080  /* MCLK1_PU */
+#define WM8996_MCLK1_PU_MASK                    0x0080  /* MCLK1_PU */
+#define WM8996_MCLK1_PU_SHIFT                        7  /* MCLK1_PU */
+#define WM8996_MCLK1_PU_WIDTH                        1  /* MCLK1_PU */
+#define WM8996_MCLK1_PD                         0x0040  /* MCLK1_PD */
+#define WM8996_MCLK1_PD_MASK                    0x0040  /* MCLK1_PD */
+#define WM8996_MCLK1_PD_SHIFT                        6  /* MCLK1_PD */
+#define WM8996_MCLK1_PD_WIDTH                        1  /* MCLK1_PD */
+#define WM8996_DACDAT1_PU                       0x0020  /* DACDAT1_PU */
+#define WM8996_DACDAT1_PU_MASK                  0x0020  /* DACDAT1_PU */
+#define WM8996_DACDAT1_PU_SHIFT                      5  /* DACDAT1_PU */
+#define WM8996_DACDAT1_PU_WIDTH                      1  /* DACDAT1_PU */
+#define WM8996_DACDAT1_PD                       0x0010  /* DACDAT1_PD */
+#define WM8996_DACDAT1_PD_MASK                  0x0010  /* DACDAT1_PD */
+#define WM8996_DACDAT1_PD_SHIFT                      4  /* DACDAT1_PD */
+#define WM8996_DACDAT1_PD_WIDTH                      1  /* DACDAT1_PD */
+#define WM8996_DACLRCLK1_PU                     0x0008  /* DACLRCLK1_PU */
+#define WM8996_DACLRCLK1_PU_MASK                0x0008  /* DACLRCLK1_PU */
+#define WM8996_DACLRCLK1_PU_SHIFT                    3  /* DACLRCLK1_PU */
+#define WM8996_DACLRCLK1_PU_WIDTH                    1  /* DACLRCLK1_PU */
+#define WM8996_DACLRCLK1_PD                     0x0004  /* DACLRCLK1_PD */
+#define WM8996_DACLRCLK1_PD_MASK                0x0004  /* DACLRCLK1_PD */
+#define WM8996_DACLRCLK1_PD_SHIFT                    2  /* DACLRCLK1_PD */
+#define WM8996_DACLRCLK1_PD_WIDTH                    1  /* DACLRCLK1_PD */
+#define WM8996_BCLK1_PU                         0x0002  /* BCLK1_PU */
+#define WM8996_BCLK1_PU_MASK                    0x0002  /* BCLK1_PU */
+#define WM8996_BCLK1_PU_SHIFT                        1  /* BCLK1_PU */
+#define WM8996_BCLK1_PU_WIDTH                        1  /* BCLK1_PU */
+#define WM8996_BCLK1_PD                         0x0001  /* BCLK1_PD */
+#define WM8996_BCLK1_PD_MASK                    0x0001  /* BCLK1_PD */
+#define WM8996_BCLK1_PD_SHIFT                        0  /* BCLK1_PD */
+#define WM8996_BCLK1_PD_WIDTH                        1  /* BCLK1_PD */
+
+/*
+ * R1825 (0x721) - Pull Control (2)
+ */
+#define WM8996_LDO1ENA_PD                       0x0100  /* LDO1ENA_PD */
+#define WM8996_LDO1ENA_PD_MASK                  0x0100  /* LDO1ENA_PD */
+#define WM8996_LDO1ENA_PD_SHIFT                      8  /* LDO1ENA_PD */
+#define WM8996_LDO1ENA_PD_WIDTH                      1  /* LDO1ENA_PD */
+#define WM8996_ADDR_PD                          0x0040  /* ADDR_PD */
+#define WM8996_ADDR_PD_MASK                     0x0040  /* ADDR_PD */
+#define WM8996_ADDR_PD_SHIFT                         6  /* ADDR_PD */
+#define WM8996_ADDR_PD_WIDTH                         1  /* ADDR_PD */
+#define WM8996_DACDAT2_PU                       0x0020  /* DACDAT2_PU */
+#define WM8996_DACDAT2_PU_MASK                  0x0020  /* DACDAT2_PU */
+#define WM8996_DACDAT2_PU_SHIFT                      5  /* DACDAT2_PU */
+#define WM8996_DACDAT2_PU_WIDTH                      1  /* DACDAT2_PU */
+#define WM8996_DACDAT2_PD                       0x0010  /* DACDAT2_PD */
+#define WM8996_DACDAT2_PD_MASK                  0x0010  /* DACDAT2_PD */
+#define WM8996_DACDAT2_PD_SHIFT                      4  /* DACDAT2_PD */
+#define WM8996_DACDAT2_PD_WIDTH                      1  /* DACDAT2_PD */
+#define WM8996_DACLRCLK2_PU                     0x0008  /* DACLRCLK2_PU */
+#define WM8996_DACLRCLK2_PU_MASK                0x0008  /* DACLRCLK2_PU */
+#define WM8996_DACLRCLK2_PU_SHIFT                    3  /* DACLRCLK2_PU */
+#define WM8996_DACLRCLK2_PU_WIDTH                    1  /* DACLRCLK2_PU */
+#define WM8996_DACLRCLK2_PD                     0x0004  /* DACLRCLK2_PD */
+#define WM8996_DACLRCLK2_PD_MASK                0x0004  /* DACLRCLK2_PD */
+#define WM8996_DACLRCLK2_PD_SHIFT                    2  /* DACLRCLK2_PD */
+#define WM8996_DACLRCLK2_PD_WIDTH                    1  /* DACLRCLK2_PD */
+#define WM8996_BCLK2_PU                         0x0002  /* BCLK2_PU */
+#define WM8996_BCLK2_PU_MASK                    0x0002  /* BCLK2_PU */
+#define WM8996_BCLK2_PU_SHIFT                        1  /* BCLK2_PU */
+#define WM8996_BCLK2_PU_WIDTH                        1  /* BCLK2_PU */
+#define WM8996_BCLK2_PD                         0x0001  /* BCLK2_PD */
+#define WM8996_BCLK2_PD_MASK                    0x0001  /* BCLK2_PD */
+#define WM8996_BCLK2_PD_SHIFT                        0  /* BCLK2_PD */
+#define WM8996_BCLK2_PD_WIDTH                        1  /* BCLK2_PD */
+
+/*
+ * R1840 (0x730) - Interrupt Status 1
+ */
+#define WM8996_GP5_EINT                         0x0010  /* GP5_EINT */
+#define WM8996_GP5_EINT_MASK                    0x0010  /* GP5_EINT */
+#define WM8996_GP5_EINT_SHIFT                        4  /* GP5_EINT */
+#define WM8996_GP5_EINT_WIDTH                        1  /* GP5_EINT */
+#define WM8996_GP4_EINT                         0x0008  /* GP4_EINT */
+#define WM8996_GP4_EINT_MASK                    0x0008  /* GP4_EINT */
+#define WM8996_GP4_EINT_SHIFT                        3  /* GP4_EINT */
+#define WM8996_GP4_EINT_WIDTH                        1  /* GP4_EINT */
+#define WM8996_GP3_EINT                         0x0004  /* GP3_EINT */
+#define WM8996_GP3_EINT_MASK                    0x0004  /* GP3_EINT */
+#define WM8996_GP3_EINT_SHIFT                        2  /* GP3_EINT */
+#define WM8996_GP3_EINT_WIDTH                        1  /* GP3_EINT */
+#define WM8996_GP2_EINT                         0x0002  /* GP2_EINT */
+#define WM8996_GP2_EINT_MASK                    0x0002  /* GP2_EINT */
+#define WM8996_GP2_EINT_SHIFT                        1  /* GP2_EINT */
+#define WM8996_GP2_EINT_WIDTH                        1  /* GP2_EINT */
+#define WM8996_GP1_EINT                         0x0001  /* GP1_EINT */
+#define WM8996_GP1_EINT_MASK                    0x0001  /* GP1_EINT */
+#define WM8996_GP1_EINT_SHIFT                        0  /* GP1_EINT */
+#define WM8996_GP1_EINT_WIDTH                        1  /* GP1_EINT */
+
+/*
+ * R1841 (0x731) - Interrupt Status 2
+ */
+#define WM8996_DCS_DONE_23_EINT                 0x1000  /* DCS_DONE_23_EINT */
+#define WM8996_DCS_DONE_23_EINT_MASK            0x1000  /* DCS_DONE_23_EINT */
+#define WM8996_DCS_DONE_23_EINT_SHIFT               12  /* DCS_DONE_23_EINT */
+#define WM8996_DCS_DONE_23_EINT_WIDTH                1  /* DCS_DONE_23_EINT */
+#define WM8996_DCS_DONE_01_EINT                 0x0800  /* DCS_DONE_01_EINT */
+#define WM8996_DCS_DONE_01_EINT_MASK            0x0800  /* DCS_DONE_01_EINT */
+#define WM8996_DCS_DONE_01_EINT_SHIFT               11  /* DCS_DONE_01_EINT */
+#define WM8996_DCS_DONE_01_EINT_WIDTH                1  /* DCS_DONE_01_EINT */
+#define WM8996_WSEQ_DONE_EINT                   0x0400  /* WSEQ_DONE_EINT */
+#define WM8996_WSEQ_DONE_EINT_MASK              0x0400  /* WSEQ_DONE_EINT */
+#define WM8996_WSEQ_DONE_EINT_SHIFT                 10  /* WSEQ_DONE_EINT */
+#define WM8996_WSEQ_DONE_EINT_WIDTH                  1  /* WSEQ_DONE_EINT */
+#define WM8996_FIFOS_ERR_EINT                   0x0200  /* FIFOS_ERR_EINT */
+#define WM8996_FIFOS_ERR_EINT_MASK              0x0200  /* FIFOS_ERR_EINT */
+#define WM8996_FIFOS_ERR_EINT_SHIFT                  9  /* FIFOS_ERR_EINT */
+#define WM8996_FIFOS_ERR_EINT_WIDTH                  1  /* FIFOS_ERR_EINT */
+#define WM8996_DSP2DRC_SIG_DET_EINT             0x0080  /* DSP2DRC_SIG_DET_EINT */
+#define WM8996_DSP2DRC_SIG_DET_EINT_MASK        0x0080  /* DSP2DRC_SIG_DET_EINT */
+#define WM8996_DSP2DRC_SIG_DET_EINT_SHIFT            7  /* DSP2DRC_SIG_DET_EINT */
+#define WM8996_DSP2DRC_SIG_DET_EINT_WIDTH            1  /* DSP2DRC_SIG_DET_EINT */
+#define WM8996_DSP1DRC_SIG_DET_EINT             0x0040  /* DSP1DRC_SIG_DET_EINT */
+#define WM8996_DSP1DRC_SIG_DET_EINT_MASK        0x0040  /* DSP1DRC_SIG_DET_EINT */
+#define WM8996_DSP1DRC_SIG_DET_EINT_SHIFT            6  /* DSP1DRC_SIG_DET_EINT */
+#define WM8996_DSP1DRC_SIG_DET_EINT_WIDTH            1  /* DSP1DRC_SIG_DET_EINT */
+#define WM8996_FLL_SW_CLK_DONE_EINT             0x0008  /* FLL_SW_CLK_DONE_EINT */
+#define WM8996_FLL_SW_CLK_DONE_EINT_MASK        0x0008  /* FLL_SW_CLK_DONE_EINT */
+#define WM8996_FLL_SW_CLK_DONE_EINT_SHIFT            3  /* FLL_SW_CLK_DONE_EINT */
+#define WM8996_FLL_SW_CLK_DONE_EINT_WIDTH            1  /* FLL_SW_CLK_DONE_EINT */
+#define WM8996_FLL_LOCK_EINT                    0x0004  /* FLL_LOCK_EINT */
+#define WM8996_FLL_LOCK_EINT_MASK               0x0004  /* FLL_LOCK_EINT */
+#define WM8996_FLL_LOCK_EINT_SHIFT                   2  /* FLL_LOCK_EINT */
+#define WM8996_FLL_LOCK_EINT_WIDTH                   1  /* FLL_LOCK_EINT */
+#define WM8996_HP_DONE_EINT                     0x0002  /* HP_DONE_EINT */
+#define WM8996_HP_DONE_EINT_MASK                0x0002  /* HP_DONE_EINT */
+#define WM8996_HP_DONE_EINT_SHIFT                    1  /* HP_DONE_EINT */
+#define WM8996_HP_DONE_EINT_WIDTH                    1  /* HP_DONE_EINT */
+#define WM8996_MICD_EINT                        0x0001  /* MICD_EINT */
+#define WM8996_MICD_EINT_MASK                   0x0001  /* MICD_EINT */
+#define WM8996_MICD_EINT_SHIFT                       0  /* MICD_EINT */
+#define WM8996_MICD_EINT_WIDTH                       1  /* MICD_EINT */
+
+/*
+ * R1842 (0x732) - Interrupt Raw Status 2
+ */
+#define WM8996_DCS_DONE_23_STS                  0x1000  /* DCS_DONE_23_STS */
+#define WM8996_DCS_DONE_23_STS_MASK             0x1000  /* DCS_DONE_23_STS */
+#define WM8996_DCS_DONE_23_STS_SHIFT                12  /* DCS_DONE_23_STS */
+#define WM8996_DCS_DONE_23_STS_WIDTH                 1  /* DCS_DONE_23_STS */
+#define WM8996_DCS_DONE_01_STS                  0x0800  /* DCS_DONE_01_STS */
+#define WM8996_DCS_DONE_01_STS_MASK             0x0800  /* DCS_DONE_01_STS */
+#define WM8996_DCS_DONE_01_STS_SHIFT                11  /* DCS_DONE_01_STS */
+#define WM8996_DCS_DONE_01_STS_WIDTH                 1  /* DCS_DONE_01_STS */
+#define WM8996_WSEQ_DONE_STS                    0x0400  /* WSEQ_DONE_STS */
+#define WM8996_WSEQ_DONE_STS_MASK               0x0400  /* WSEQ_DONE_STS */
+#define WM8996_WSEQ_DONE_STS_SHIFT                  10  /* WSEQ_DONE_STS */
+#define WM8996_WSEQ_DONE_STS_WIDTH                   1  /* WSEQ_DONE_STS */
+#define WM8996_FIFOS_ERR_STS                    0x0200  /* FIFOS_ERR_STS */
+#define WM8996_FIFOS_ERR_STS_MASK               0x0200  /* FIFOS_ERR_STS */
+#define WM8996_FIFOS_ERR_STS_SHIFT                   9  /* FIFOS_ERR_STS */
+#define WM8996_FIFOS_ERR_STS_WIDTH                   1  /* FIFOS_ERR_STS */
+#define WM8996_DSP2DRC_SIG_DET_STS              0x0080  /* DSP2DRC_SIG_DET_STS */
+#define WM8996_DSP2DRC_SIG_DET_STS_MASK         0x0080  /* DSP2DRC_SIG_DET_STS */
+#define WM8996_DSP2DRC_SIG_DET_STS_SHIFT             7  /* DSP2DRC_SIG_DET_STS */
+#define WM8996_DSP2DRC_SIG_DET_STS_WIDTH             1  /* DSP2DRC_SIG_DET_STS */
+#define WM8996_DSP1DRC_SIG_DET_STS              0x0040  /* DSP1DRC_SIG_DET_STS */
+#define WM8996_DSP1DRC_SIG_DET_STS_MASK         0x0040  /* DSP1DRC_SIG_DET_STS */
+#define WM8996_DSP1DRC_SIG_DET_STS_SHIFT             6  /* DSP1DRC_SIG_DET_STS */
+#define WM8996_DSP1DRC_SIG_DET_STS_WIDTH             1  /* DSP1DRC_SIG_DET_STS */
+#define WM8996_FLL_LOCK_STS                     0x0004  /* FLL_LOCK_STS */
+#define WM8996_FLL_LOCK_STS_MASK                0x0004  /* FLL_LOCK_STS */
+#define WM8996_FLL_LOCK_STS_SHIFT                    2  /* FLL_LOCK_STS */
+#define WM8996_FLL_LOCK_STS_WIDTH                    1  /* FLL_LOCK_STS */
+
+/*
+ * R1848 (0x738) - Interrupt Status 1 Mask
+ */
+#define WM8996_IM_GP5_EINT                      0x0010  /* IM_GP5_EINT */
+#define WM8996_IM_GP5_EINT_MASK                 0x0010  /* IM_GP5_EINT */
+#define WM8996_IM_GP5_EINT_SHIFT                     4  /* IM_GP5_EINT */
+#define WM8996_IM_GP5_EINT_WIDTH                     1  /* IM_GP5_EINT */
+#define WM8996_IM_GP4_EINT                      0x0008  /* IM_GP4_EINT */
+#define WM8996_IM_GP4_EINT_MASK                 0x0008  /* IM_GP4_EINT */
+#define WM8996_IM_GP4_EINT_SHIFT                     3  /* IM_GP4_EINT */
+#define WM8996_IM_GP4_EINT_WIDTH                     1  /* IM_GP4_EINT */
+#define WM8996_IM_GP3_EINT                      0x0004  /* IM_GP3_EINT */
+#define WM8996_IM_GP3_EINT_MASK                 0x0004  /* IM_GP3_EINT */
+#define WM8996_IM_GP3_EINT_SHIFT                     2  /* IM_GP3_EINT */
+#define WM8996_IM_GP3_EINT_WIDTH                     1  /* IM_GP3_EINT */
+#define WM8996_IM_GP2_EINT                      0x0002  /* IM_GP2_EINT */
+#define WM8996_IM_GP2_EINT_MASK                 0x0002  /* IM_GP2_EINT */
+#define WM8996_IM_GP2_EINT_SHIFT                     1  /* IM_GP2_EINT */
+#define WM8996_IM_GP2_EINT_WIDTH                     1  /* IM_GP2_EINT */
+#define WM8996_IM_GP1_EINT                      0x0001  /* IM_GP1_EINT */
+#define WM8996_IM_GP1_EINT_MASK                 0x0001  /* IM_GP1_EINT */
+#define WM8996_IM_GP1_EINT_SHIFT                     0  /* IM_GP1_EINT */
+#define WM8996_IM_GP1_EINT_WIDTH                     1  /* IM_GP1_EINT */
+
+/*
+ * R1849 (0x739) - Interrupt Status 2 Mask
+ */
+#define WM8996_IM_DCS_DONE_23_EINT              0x1000  /* IM_DCS_DONE_23_EINT */
+#define WM8996_IM_DCS_DONE_23_EINT_MASK         0x1000  /* IM_DCS_DONE_23_EINT */
+#define WM8996_IM_DCS_DONE_23_EINT_SHIFT            12  /* IM_DCS_DONE_23_EINT */
+#define WM8996_IM_DCS_DONE_23_EINT_WIDTH             1  /* IM_DCS_DONE_23_EINT */
+#define WM8996_IM_DCS_DONE_01_EINT              0x0800  /* IM_DCS_DONE_01_EINT */
+#define WM8996_IM_DCS_DONE_01_EINT_MASK         0x0800  /* IM_DCS_DONE_01_EINT */
+#define WM8996_IM_DCS_DONE_01_EINT_SHIFT            11  /* IM_DCS_DONE_01_EINT */
+#define WM8996_IM_DCS_DONE_01_EINT_WIDTH             1  /* IM_DCS_DONE_01_EINT */
+#define WM8996_IM_WSEQ_DONE_EINT                0x0400  /* IM_WSEQ_DONE_EINT */
+#define WM8996_IM_WSEQ_DONE_EINT_MASK           0x0400  /* IM_WSEQ_DONE_EINT */
+#define WM8996_IM_WSEQ_DONE_EINT_SHIFT              10  /* IM_WSEQ_DONE_EINT */
+#define WM8996_IM_WSEQ_DONE_EINT_WIDTH               1  /* IM_WSEQ_DONE_EINT */
+#define WM8996_IM_FIFOS_ERR_EINT                0x0200  /* IM_FIFOS_ERR_EINT */
+#define WM8996_IM_FIFOS_ERR_EINT_MASK           0x0200  /* IM_FIFOS_ERR_EINT */
+#define WM8996_IM_FIFOS_ERR_EINT_SHIFT               9  /* IM_FIFOS_ERR_EINT */
+#define WM8996_IM_FIFOS_ERR_EINT_WIDTH               1  /* IM_FIFOS_ERR_EINT */
+#define WM8996_IM_DSP2DRC_SIG_DET_EINT          0x0080  /* IM_DSP2DRC_SIG_DET_EINT */
+#define WM8996_IM_DSP2DRC_SIG_DET_EINT_MASK     0x0080  /* IM_DSP2DRC_SIG_DET_EINT */
+#define WM8996_IM_DSP2DRC_SIG_DET_EINT_SHIFT         7  /* IM_DSP2DRC_SIG_DET_EINT */
+#define WM8996_IM_DSP2DRC_SIG_DET_EINT_WIDTH         1  /* IM_DSP2DRC_SIG_DET_EINT */
+#define WM8996_IM_DSP1DRC_SIG_DET_EINT          0x0040  /* IM_DSP1DRC_SIG_DET_EINT */
+#define WM8996_IM_DSP1DRC_SIG_DET_EINT_MASK     0x0040  /* IM_DSP1DRC_SIG_DET_EINT */
+#define WM8996_IM_DSP1DRC_SIG_DET_EINT_SHIFT         6  /* IM_DSP1DRC_SIG_DET_EINT */
+#define WM8996_IM_DSP1DRC_SIG_DET_EINT_WIDTH         1  /* IM_DSP1DRC_SIG_DET_EINT */
+#define WM8996_IM_FLL_SW_CLK_DONE_EINT          0x0008  /* IM_FLL_SW_CLK_DONE_EINT */
+#define WM8996_IM_FLL_SW_CLK_DONE_EINT_MASK     0x0008  /* IM_FLL_SW_CLK_DONE_EINT */
+#define WM8996_IM_FLL_SW_CLK_DONE_EINT_SHIFT         3  /* IM_FLL_SW_CLK_DONE_EINT */
+#define WM8996_IM_FLL_SW_CLK_DONE_EINT_WIDTH         1  /* IM_FLL_SW_CLK_DONE_EINT */
+#define WM8996_IM_FLL_LOCK_EINT                 0x0004  /* IM_FLL_LOCK_EINT */
+#define WM8996_IM_FLL_LOCK_EINT_MASK            0x0004  /* IM_FLL_LOCK_EINT */
+#define WM8996_IM_FLL_LOCK_EINT_SHIFT                2  /* IM_FLL_LOCK_EINT */
+#define WM8996_IM_FLL_LOCK_EINT_WIDTH                1  /* IM_FLL_LOCK_EINT */
+#define WM8996_IM_HP_DONE_EINT                  0x0002  /* IM_HP_DONE_EINT */
+#define WM8996_IM_HP_DONE_EINT_MASK             0x0002  /* IM_HP_DONE_EINT */
+#define WM8996_IM_HP_DONE_EINT_SHIFT                 1  /* IM_HP_DONE_EINT */
+#define WM8996_IM_HP_DONE_EINT_WIDTH                 1  /* IM_HP_DONE_EINT */
+#define WM8996_IM_MICD_EINT                     0x0001  /* IM_MICD_EINT */
+#define WM8996_IM_MICD_EINT_MASK                0x0001  /* IM_MICD_EINT */
+#define WM8996_IM_MICD_EINT_SHIFT                    0  /* IM_MICD_EINT */
+#define WM8996_IM_MICD_EINT_WIDTH                    1  /* IM_MICD_EINT */
+
+/*
+ * R1856 (0x740) - Interrupt Control
+ */
+#define WM8996_IM_IRQ                           0x0001  /* IM_IRQ */
+#define WM8996_IM_IRQ_MASK                      0x0001  /* IM_IRQ */
+#define WM8996_IM_IRQ_SHIFT                          0  /* IM_IRQ */
+#define WM8996_IM_IRQ_WIDTH                          1  /* IM_IRQ */
+
+/*
+ * R2048 (0x800) - Left PDM Speaker
+ */
+#define WM8996_SPKL_ENA                         0x0010  /* SPKL_ENA */
+#define WM8996_SPKL_ENA_MASK                    0x0010  /* SPKL_ENA */
+#define WM8996_SPKL_ENA_SHIFT                        4  /* SPKL_ENA */
+#define WM8996_SPKL_ENA_WIDTH                        1  /* SPKL_ENA */
+#define WM8996_SPKL_MUTE                        0x0008  /* SPKL_MUTE */
+#define WM8996_SPKL_MUTE_MASK                   0x0008  /* SPKL_MUTE */
+#define WM8996_SPKL_MUTE_SHIFT                       3  /* SPKL_MUTE */
+#define WM8996_SPKL_MUTE_WIDTH                       1  /* SPKL_MUTE */
+#define WM8996_SPKL_MUTE_ZC                     0x0004  /* SPKL_MUTE_ZC */
+#define WM8996_SPKL_MUTE_ZC_MASK                0x0004  /* SPKL_MUTE_ZC */
+#define WM8996_SPKL_MUTE_ZC_SHIFT                    2  /* SPKL_MUTE_ZC */
+#define WM8996_SPKL_MUTE_ZC_WIDTH                    1  /* SPKL_MUTE_ZC */
+#define WM8996_SPKL_SRC_MASK                    0x0003  /* SPKL_SRC - [1:0] */
+#define WM8996_SPKL_SRC_SHIFT                        0  /* SPKL_SRC - [1:0] */
+#define WM8996_SPKL_SRC_WIDTH                        2  /* SPKL_SRC - [1:0] */
+
+/*
+ * R2049 (0x801) - Right PDM Speaker
+ */
+#define WM8996_SPKR_ENA                         0x0010  /* SPKR_ENA */
+#define WM8996_SPKR_ENA_MASK                    0x0010  /* SPKR_ENA */
+#define WM8996_SPKR_ENA_SHIFT                        4  /* SPKR_ENA */
+#define WM8996_SPKR_ENA_WIDTH                        1  /* SPKR_ENA */
+#define WM8996_SPKR_MUTE                        0x0008  /* SPKR_MUTE */
+#define WM8996_SPKR_MUTE_MASK                   0x0008  /* SPKR_MUTE */
+#define WM8996_SPKR_MUTE_SHIFT                       3  /* SPKR_MUTE */
+#define WM8996_SPKR_MUTE_WIDTH                       1  /* SPKR_MUTE */
+#define WM8996_SPKR_MUTE_ZC                     0x0004  /* SPKR_MUTE_ZC */
+#define WM8996_SPKR_MUTE_ZC_MASK                0x0004  /* SPKR_MUTE_ZC */
+#define WM8996_SPKR_MUTE_ZC_SHIFT                    2  /* SPKR_MUTE_ZC */
+#define WM8996_SPKR_MUTE_ZC_WIDTH                    1  /* SPKR_MUTE_ZC */
+#define WM8996_SPKR_SRC_MASK                    0x0003  /* SPKR_SRC - [1:0] */
+#define WM8996_SPKR_SRC_SHIFT                        0  /* SPKR_SRC - [1:0] */
+#define WM8996_SPKR_SRC_WIDTH                        2  /* SPKR_SRC - [1:0] */
+
+/*
+ * R2050 (0x802) - PDM Speaker Mute Sequence
+ */
+#define WM8996_SPK_MUTE_ENDIAN                  0x0100  /* SPK_MUTE_ENDIAN */
+#define WM8996_SPK_MUTE_ENDIAN_MASK             0x0100  /* SPK_MUTE_ENDIAN */
+#define WM8996_SPK_MUTE_ENDIAN_SHIFT                 8  /* SPK_MUTE_ENDIAN */
+#define WM8996_SPK_MUTE_ENDIAN_WIDTH                 1  /* SPK_MUTE_ENDIAN */
+#define WM8996_SPK_MUTE_SEQ1_MASK               0x00FF  /* SPK_MUTE_SEQ1 - [7:0] */
+#define WM8996_SPK_MUTE_SEQ1_SHIFT                   0  /* SPK_MUTE_SEQ1 - [7:0] */
+#define WM8996_SPK_MUTE_SEQ1_WIDTH                   8  /* SPK_MUTE_SEQ1 - [7:0] */
+
+/*
+ * R2051 (0x803) - PDM Speaker Volume
+ */
+#define WM8996_SPKR_VOL_MASK                    0x00F0  /* SPKR_VOL - [7:4] */
+#define WM8996_SPKR_VOL_SHIFT                        4  /* SPKR_VOL - [7:4] */
+#define WM8996_SPKR_VOL_WIDTH                        4  /* SPKR_VOL - [7:4] */
+#define WM8996_SPKL_VOL_MASK                    0x000F  /* SPKL_VOL - [3:0] */
+#define WM8996_SPKL_VOL_SHIFT                        0  /* SPKL_VOL - [3:0] */
+#define WM8996_SPKL_VOL_WIDTH                        4  /* SPKL_VOL - [3:0] */
+
+#endif
index 4cc2d56..e763c54 100644 (file)
@@ -440,9 +440,8 @@ static int hp_event(struct snd_soc_dapm_widget *w,
                reg |= WM8993_HPOUT1L_DLY | WM8993_HPOUT1R_DLY;
                snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg);
 
-               /* Smallest supported update interval */
                snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
-                                   WM8993_DCS_TIMER_PERIOD_01_MASK, 1);
+                                   WM8993_DCS_TIMER_PERIOD_01_MASK, 0);
 
                calibrate_dc_servo(codec);
 
index 83d213b..62e292f 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Jarkko Nikula <jhnikula@gmail.com>
+ * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -402,6 +402,6 @@ static void __exit n810_soc_exit(void)
 module_init(n810_soc_init);
 module_exit(n810_soc_exit);
 
-MODULE_AUTHOR("Jarkko Nikula <jhnikula@gmail.com>");
+MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
 MODULE_DESCRIPTION("ALSA SoC Nokia N810");
 MODULE_LICENSE("GPL");
index 07b7723..ebcc2d4 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Jarkko Nikula <jhnikula@gmail.com>
+ * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
  *          Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * This program is free software; you can redistribute it and/or
@@ -780,6 +780,6 @@ static void __exit snd_omap_mcbsp_exit(void)
 }
 module_exit(snd_omap_mcbsp_exit);
 
-MODULE_AUTHOR("Jarkko Nikula <jhnikula@gmail.com>");
+MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
 MODULE_DESCRIPTION("OMAP I2S SoC Interface");
 MODULE_LICENSE("GPL");
index 9a7dedd..65cde9d 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Jarkko Nikula <jhnikula@gmail.com>
+ * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
  *          Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * This program is free software; you can redistribute it and/or
index b2f5751..9b5c88a 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Jarkko Nikula <jhnikula@gmail.com>
+ * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
  *          Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * This program is free software; you can redistribute it and/or
@@ -436,6 +436,6 @@ static void __exit snd_omap_pcm_exit(void)
 }
 module_exit(snd_omap_pcm_exit);
 
-MODULE_AUTHOR("Jarkko Nikula <jhnikula@gmail.com>");
+MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
 MODULE_DESCRIPTION("OMAP PCM DMA module");
 MODULE_LICENSE("GPL");
index a0ed1db..f95fe30 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Jarkko Nikula <jhnikula@gmail.com>
+ * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
  *          Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * This program is free software; you can redistribute it and/or
index 0aae998..893300a 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Contact: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *          Eduardo Valentin <eduardo.valentin@nokia.com>
- *          Jarkko Nikula <jhnikula@gmail.com>
+ *          Jarkko Nikula <jarkko.nikula@bitmer.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 54b0e4b..b99091f 100644 (file)
@@ -183,7 +183,7 @@ config SND_SOC_SPEYSIDE
        tristate "Audio support for Wolfson Speyside"
        depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
        select SND_SAMSUNG_I2S
-       select SND_SOC_WM8915
+       select SND_SOC_WM8996
        select SND_SOC_WM9081
 
 config SND_SOC_SPEYSIDE_WM8962
index 9eb3b12..8509d3c 100644 (file)
@@ -1,5 +1,6 @@
 # S3c24XX Platform Support
 snd-soc-s3c24xx-objs := dma.o
+snd-soc-idma-objs := idma.o
 snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
 snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o
 snd-soc-ac97-objs := ac97.o
@@ -16,6 +17,7 @@ obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
 obj-$(CONFIG_SND_SAMSUNG_SPDIF) += snd-soc-samsung-spdif.o
 obj-$(CONFIG_SND_SAMSUNG_PCM) += snd-soc-pcm.o
 obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-i2s.o
+obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-idma.o
 
 # S3C24XX Machine Support
 snd-soc-jive-wm8750-objs := jive_wm8750.o
diff --git a/sound/soc/samsung/idma.c b/sound/soc/samsung/idma.c
new file mode 100644 (file)
index 0000000..ebde074
--- /dev/null
@@ -0,0 +1,453 @@
+/*
+ * sound/soc/samsung/idma.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * I2S0's Internal DMA driver
+ *
+ * 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/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "i2s.h"
+#include "idma.h"
+#include "dma.h"
+#include "i2s-regs.h"
+
+#define ST_RUNNING             (1<<0)
+#define ST_OPENED              (1<<1)
+
+static const struct snd_pcm_hardware idma_hardware = {
+       .info = SNDRV_PCM_INFO_INTERLEAVED |
+                   SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                   SNDRV_PCM_INFO_MMAP |
+                   SNDRV_PCM_INFO_MMAP_VALID |
+                   SNDRV_PCM_INFO_PAUSE |
+                   SNDRV_PCM_INFO_RESUME,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE |
+                   SNDRV_PCM_FMTBIT_U16_LE |
+                   SNDRV_PCM_FMTBIT_S24_LE |
+                   SNDRV_PCM_FMTBIT_U24_LE |
+                   SNDRV_PCM_FMTBIT_U8 |
+                   SNDRV_PCM_FMTBIT_S8,
+       .channels_min = 2,
+       .channels_max = 2,
+       .buffer_bytes_max = MAX_IDMA_BUFFER,
+       .period_bytes_min = 128,
+       .period_bytes_max = MAX_IDMA_PERIOD,
+       .periods_min = 1,
+       .periods_max = 2,
+};
+
+struct idma_ctrl {
+       spinlock_t      lock;
+       int             state;
+       dma_addr_t      start;
+       dma_addr_t      pos;
+       dma_addr_t      end;
+       dma_addr_t      period;
+       dma_addr_t      periodsz;
+       void            *token;
+       void            (*cb)(void *dt, int bytes_xfer);
+};
+
+static struct idma_info {
+       spinlock_t      lock;
+       void             __iomem  *regs;
+       dma_addr_t      lp_tx_addr;
+} idma;
+
+static void idma_getpos(dma_addr_t *src)
+{
+       *src = idma.lp_tx_addr +
+               (readl(idma.regs + I2STRNCNT) & 0xffffff) * 4;
+}
+
+static int idma_enqueue(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct idma_ctrl *prtd = substream->runtime->private_data;
+       u32 val;
+
+       spin_lock(&prtd->lock);
+       prtd->token = (void *) substream;
+       spin_unlock(&prtd->lock);
+
+       /* Internal DMA Level0 Interrupt Address */
+       val = idma.lp_tx_addr + prtd->periodsz;
+       writel(val, idma.regs + I2SLVL0ADDR);
+
+       /* Start address0 of I2S internal DMA operation. */
+       val = idma.lp_tx_addr;
+       writel(val, idma.regs + I2SSTR0);
+
+       /*
+        * Transfer block size for I2S internal DMA.
+        * Should decide transfer size before start dma operation
+        */
+       val = readl(idma.regs + I2SSIZE);
+       val &= ~(I2SSIZE_TRNMSK << I2SSIZE_SHIFT);
+       val |= (((runtime->dma_bytes >> 2) &
+                       I2SSIZE_TRNMSK) << I2SSIZE_SHIFT);
+       writel(val, idma.regs + I2SSIZE);
+
+       val = readl(idma.regs + I2SAHB);
+       val |= AHB_INTENLVL0;
+       writel(val, idma.regs + I2SAHB);
+
+       return 0;
+}
+
+static void idma_setcallbk(struct snd_pcm_substream *substream,
+                               void (*cb)(void *, int))
+{
+       struct idma_ctrl *prtd = substream->runtime->private_data;
+
+       spin_lock(&prtd->lock);
+       prtd->cb = cb;
+       spin_unlock(&prtd->lock);
+}
+
+static void idma_control(int op)
+{
+       u32 val = readl(idma.regs + I2SAHB);
+
+       spin_lock(&idma.lock);
+
+       switch (op) {
+       case LPAM_DMA_START:
+               val |= (AHB_INTENLVL0 | AHB_DMAEN);
+               break;
+       case LPAM_DMA_STOP:
+               val &= ~(AHB_INTENLVL0 | AHB_DMAEN);
+               break;
+       default:
+               spin_unlock(&idma.lock);
+               return;
+       }
+
+       writel(val, idma.regs + I2SAHB);
+       spin_unlock(&idma.lock);
+}
+
+static void idma_done(void *id, int bytes_xfer)
+{
+       struct snd_pcm_substream *substream = id;
+       struct idma_ctrl *prtd = substream->runtime->private_data;
+
+       if (prtd && (prtd->state & ST_RUNNING))
+               snd_pcm_period_elapsed(substream);
+}
+
+static int idma_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct idma_ctrl *prtd = substream->runtime->private_data;
+       u32 mod = readl(idma.regs + I2SMOD);
+       u32 ahb = readl(idma.regs + I2SAHB);
+
+       ahb |= (AHB_DMARLD | AHB_INTMASK);
+       mod |= MOD_TXS_IDMA;
+       writel(ahb, idma.regs + I2SAHB);
+       writel(mod, idma.regs + I2SMOD);
+
+       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+       runtime->dma_bytes = params_buffer_bytes(params);
+
+       prtd->start = prtd->pos = runtime->dma_addr;
+       prtd->period = params_periods(params);
+       prtd->periodsz = params_period_bytes(params);
+       prtd->end = runtime->dma_addr + runtime->dma_bytes;
+
+       idma_setcallbk(substream, idma_done);
+
+       return 0;
+}
+
+static int idma_hw_free(struct snd_pcm_substream *substream)
+{
+       snd_pcm_set_runtime_buffer(substream, NULL);
+
+       return 0;
+}
+
+static int idma_prepare(struct snd_pcm_substream *substream)
+{
+       struct idma_ctrl *prtd = substream->runtime->private_data;
+
+       prtd->pos = prtd->start;
+
+       /* flush the DMA channel */
+       idma_control(LPAM_DMA_STOP);
+       idma_enqueue(substream);
+
+       return 0;
+}
+
+static int idma_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct idma_ctrl *prtd = substream->runtime->private_data;
+       int ret = 0;
+
+       spin_lock(&prtd->lock);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               prtd->state |= ST_RUNNING;
+               idma_control(LPAM_DMA_START);
+               break;
+
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               prtd->state &= ~ST_RUNNING;
+               idma_control(LPAM_DMA_STOP);
+               break;
+
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       spin_unlock(&prtd->lock);
+
+       return ret;
+}
+
+static snd_pcm_uframes_t
+       idma_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct idma_ctrl *prtd = runtime->private_data;
+       dma_addr_t src;
+       unsigned long res;
+
+       spin_lock(&prtd->lock);
+
+       idma_getpos(&src);
+       res = src - prtd->start;
+
+       spin_unlock(&prtd->lock);
+
+       return bytes_to_frames(substream->runtime, res);
+}
+
+static int idma_mmap(struct snd_pcm_substream *substream,
+       struct vm_area_struct *vma)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       unsigned long size, offset;
+       int ret;
+
+       /* From snd_pcm_lib_mmap_iomem */
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+       vma->vm_flags |= VM_IO;
+       size = vma->vm_end - vma->vm_start;
+       offset = vma->vm_pgoff << PAGE_SHIFT;
+       ret = io_remap_pfn_range(vma, vma->vm_start,
+                       (runtime->dma_addr + offset) >> PAGE_SHIFT,
+                       size, vma->vm_page_prot);
+
+       return ret;
+}
+
+static irqreturn_t iis_irq(int irqno, void *dev_id)
+{
+       struct idma_ctrl *prtd = (struct idma_ctrl *)dev_id;
+       u32 iiscon, iisahb, val, addr;
+
+       iisahb  = readl(idma.regs + I2SAHB);
+       iiscon  = readl(idma.regs + I2SCON);
+
+       val = (iisahb & AHB_LVL0INT) ? AHB_CLRLVL0INT : 0;
+
+       if (val) {
+               iisahb |= val;
+               writel(iisahb, idma.regs + I2SAHB);
+
+               addr = readl(idma.regs + I2SLVL0ADDR) - idma.lp_tx_addr;
+               addr += prtd->periodsz;
+               addr %= (prtd->end - prtd->start);
+               addr += idma.lp_tx_addr;
+
+               writel(addr, idma.regs + I2SLVL0ADDR);
+
+               if (prtd->cb)
+                       prtd->cb(prtd->token, prtd->period);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int idma_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct idma_ctrl *prtd;
+       int ret;
+
+       snd_soc_set_runtime_hwparams(substream, &idma_hardware);
+
+       prtd = kzalloc(sizeof(struct idma_ctrl), GFP_KERNEL);
+       if (prtd == NULL)
+               return -ENOMEM;
+
+       ret = request_irq(IRQ_I2S0, iis_irq, 0, "i2s", prtd);
+       if (ret < 0) {
+               pr_err("fail to claim i2s irq , ret = %d\n", ret);
+               kfree(prtd);
+               return ret;
+       }
+
+       spin_lock_init(&prtd->lock);
+
+       runtime->private_data = prtd;
+
+       return 0;
+}
+
+static int idma_close(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct idma_ctrl *prtd = runtime->private_data;
+
+       free_irq(IRQ_I2S0, prtd);
+
+       if (!prtd)
+               pr_err("idma_close called with prtd == NULL\n");
+
+       kfree(prtd);
+
+       return 0;
+}
+
+static struct snd_pcm_ops idma_ops = {
+       .open           = idma_open,
+       .close          = idma_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .trigger        = idma_trigger,
+       .pointer        = idma_pointer,
+       .mmap           = idma_mmap,
+       .hw_params      = idma_hw_params,
+       .hw_free        = idma_hw_free,
+       .prepare        = idma_prepare,
+};
+
+static void idma_free(struct snd_pcm *pcm)
+{
+       struct snd_pcm_substream *substream;
+       struct snd_dma_buffer *buf;
+
+       substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+       if (!substream)
+               return;
+
+       buf = &substream->dma_buffer;
+       if (!buf->area)
+               return;
+
+       iounmap(buf->area);
+
+       buf->area = NULL;
+       buf->addr = 0;
+}
+
+static int preallocate_idma_buffer(struct snd_pcm *pcm, int stream)
+{
+       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+       struct snd_dma_buffer *buf = &substream->dma_buffer;
+
+       buf->dev.dev = pcm->card->dev;
+       buf->private_data = NULL;
+
+       /* Assign PCM buffer pointers */
+       buf->dev.type = SNDRV_DMA_TYPE_CONTINUOUS;
+       buf->addr = idma.lp_tx_addr;
+       buf->bytes = idma_hardware.buffer_bytes_max;
+       buf->area = (unsigned char *)ioremap(buf->addr, buf->bytes);
+
+       return 0;
+}
+
+static u64 idma_mask = DMA_BIT_MASK(32);
+
+static int idma_new(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_soc_dai *dai = rtd->cpu_dai;
+       struct snd_pcm *pcm = rtd->pcm;
+       int ret = 0;
+
+       if (!card->dev->dma_mask)
+               card->dev->dma_mask = &idma_mask;
+       if (!card->dev->coherent_dma_mask)
+               card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+       if (dai->driver->playback.channels_min)
+               ret = preallocate_idma_buffer(pcm,
+                               SNDRV_PCM_STREAM_PLAYBACK);
+
+       return ret;
+}
+
+void idma_reg_addr_init(void *regs, dma_addr_t addr)
+{
+       spin_lock_init(&idma.lock);
+       idma.regs = regs;
+       idma.lp_tx_addr = addr;
+}
+
+struct snd_soc_platform_driver asoc_idma_platform = {
+       .ops = &idma_ops,
+       .pcm_new = idma_new,
+       .pcm_free = idma_free,
+};
+
+static int __devinit asoc_idma_platform_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_platform(&pdev->dev, &asoc_idma_platform);
+}
+
+static int __devexit asoc_idma_platform_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver asoc_idma_driver = {
+       .driver = {
+               .name = "samsung-idma",
+               .owner = THIS_MODULE,
+       },
+
+       .probe = asoc_idma_platform_probe,
+       .remove = __devexit_p(asoc_idma_platform_remove),
+};
+
+static int __init asoc_idma_init(void)
+{
+       return platform_driver_register(&asoc_idma_driver);
+}
+module_init(asoc_idma_init);
+
+static void __exit asoc_idma_exit(void)
+{
+       platform_driver_unregister(&asoc_idma_driver);
+}
+module_exit(asoc_idma_exit);
+
+MODULE_AUTHOR("Jaswinder Singh, <jassisinghbrar@gmail.com>");
+MODULE_DESCRIPTION("Samsung ASoC IDMA Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/idma.h b/sound/soc/samsung/idma.h
new file mode 100644 (file)
index 0000000..4827321
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * sound/soc/samsung/idma.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *             http://www.samsung.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.
+ *
+ */
+
+#ifndef __SND_SOC_SAMSUNG_IDMA_H_
+#define __SND_SOC_SAMSUNG_IDMA_H_
+
+extern void idma_reg_addr_init(void *regs, dma_addr_t addr);
+
+/* dma_state */
+#define LPAM_DMA_STOP  0
+#define LPAM_DMA_START 1
+
+#define MAX_IDMA_PERIOD (128 * 1024)
+#define MAX_IDMA_BUFFER (160 * 1024)
+
+#endif /* __SND_SOC_SAMSUNG_IDMA_H_ */
index 3b53ad5..14eb6ea 100644 (file)
@@ -131,7 +131,7 @@ static struct snd_soc_dai_link jive_dai = {
        .cpu_dai_name   = "s3c2412-i2s",
        .codec_dai_name = "wm8750-hifi",
        .platform_name  = "samsung-audio",
-       .codec_name     = "wm8750-codec.0-0x1a",
+       .codec_name     = "wm8750-codec.0-001a",
        .init           = jive_wm8750_init,
        .ops            = &jive_ops,
 };
index d6dee4d..590e927 100644 (file)
 #include <sound/jack.h>
 #include <linux/gpio.h>
 
-#include "../codecs/wm8915.h"
+#include "../codecs/wm8996.h"
 #include "../codecs/wm9081.h"
 
-#define WM8915_HPSEL_GPIO 214
+#define WM8996_HPSEL_GPIO 214
 
 static int speyside_set_bias_level(struct snd_soc_card *card,
                                   struct snd_soc_dapm_context *dapm,
@@ -31,12 +31,12 @@ static int speyside_set_bias_level(struct snd_soc_card *card,
 
        switch (level) {
        case SND_SOC_BIAS_STANDBY:
-               ret = snd_soc_dai_set_sysclk(codec_dai, WM8915_SYSCLK_MCLK2,
+               ret = snd_soc_dai_set_sysclk(codec_dai, WM8996_SYSCLK_MCLK2,
                                             32768, SND_SOC_CLOCK_IN);
                if (ret < 0)
                        return ret;
 
-               ret = snd_soc_dai_set_pll(codec_dai, WM8915_FLL_MCLK2,
+               ret = snd_soc_dai_set_pll(codec_dai, WM8996_FLL_MCLK2,
                                          0, 0, 0);
                if (ret < 0) {
                        pr_err("Failed to stop FLL\n");
@@ -65,7 +65,7 @@ static int speyside_set_bias_level_post(struct snd_soc_card *card,
        case SND_SOC_BIAS_PREPARE:
                if (card->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
                        ret = snd_soc_dai_set_pll(codec_dai, 0,
-                                                 WM8915_FLL_MCLK2,
+                                                 WM8996_FLL_MCLK2,
                                                  32768, 48000 * 256);
                        if (ret < 0) {
                                pr_err("Failed to start FLL\n");
@@ -73,7 +73,7 @@ static int speyside_set_bias_level_post(struct snd_soc_card *card,
                        }
 
                        ret = snd_soc_dai_set_sysclk(codec_dai,
-                                                    WM8915_SYSCLK_FLL,
+                                                    WM8996_SYSCLK_FLL,
                                                     48000 * 256,
                                                     SND_SOC_CLOCK_IN);
                        if (ret < 0)
@@ -149,26 +149,26 @@ static void speyside_set_polarity(struct snd_soc_codec *codec,
                                  int polarity)
 {
        speyside_jack_polarity = !polarity;
-       gpio_direction_output(WM8915_HPSEL_GPIO, speyside_jack_polarity);
+       gpio_direction_output(WM8996_HPSEL_GPIO, speyside_jack_polarity);
 
        /* Re-run DAPM to make sure we're using the correct mic bias */
        snd_soc_dapm_sync(&codec->dapm);
 }
 
-static int speyside_wm8915_init(struct snd_soc_pcm_runtime *rtd)
+static int speyside_wm8996_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_dai *dai = rtd->codec_dai;
        struct snd_soc_codec *codec = rtd->codec;
        int ret;
 
-       ret = snd_soc_dai_set_sysclk(dai, WM8915_SYSCLK_MCLK2, 32768, 0);
+       ret = snd_soc_dai_set_sysclk(dai, WM8996_SYSCLK_MCLK2, 32768, 0);
        if (ret < 0)
                return ret;
 
-       ret = gpio_request(WM8915_HPSEL_GPIO, "HP_SEL");
+       ret = gpio_request(WM8996_HPSEL_GPIO, "HP_SEL");
        if (ret != 0)
                pr_err("Failed to request HP_SEL GPIO: %d\n", ret);
-       gpio_direction_output(WM8915_HPSEL_GPIO, speyside_jack_polarity);
+       gpio_direction_output(WM8996_HPSEL_GPIO, speyside_jack_polarity);
 
        ret = snd_soc_jack_new(codec, "Headset",
                               SND_JACK_HEADSET | SND_JACK_BTN_0,
@@ -182,7 +182,7 @@ static int speyside_wm8915_init(struct snd_soc_pcm_runtime *rtd)
        if (ret)
                return ret;
 
-       wm8915_detect(codec, &speyside_headset, speyside_set_polarity);
+       wm8996_detect(codec, &speyside_headset, speyside_set_polarity);
 
        return 0;
 }
@@ -205,16 +205,16 @@ static struct snd_soc_dai_link speyside_dai[] = {
                .name = "CPU",
                .stream_name = "CPU",
                .cpu_dai_name = "samsung-i2s.0",
-               .codec_dai_name = "wm8915-aif1",
+               .codec_dai_name = "wm8996-aif1",
                .platform_name = "samsung-audio",
-               .codec_name = "wm8915.1-001a",
-               .init = speyside_wm8915_init,
+               .codec_name = "wm8996.1-001a",
+               .init = speyside_wm8996_init,
                .ops = &speyside_ops,
        },
        {
                .name = "Baseband",
                .stream_name = "Baseband",
-               .cpu_dai_name = "wm8915-aif2",
+               .cpu_dai_name = "wm8996-aif2",
                .codec_dai_name = "wm1250-ev1",
                .codec_name = "wm1250-ev1.1-0027",
                .ops = &speyside_ops,
index 8ac42bf..0b9eb5f 100644 (file)
@@ -37,7 +37,7 @@ static int speyside_wm8962_set_bias_level(struct snd_soc_card *card,
                                                     44100 * 256,
                                                     SND_SOC_CLOCK_IN);
                        if (ret < 0) {
-                               pr_err("Failed to set SYSCLK: %d\n");
+                               pr_err("Failed to set SYSCLK: %d\n", ret);
                                return ret;
                        }
                }
index ff86e5e..c7cfd96 100644 (file)
@@ -309,9 +309,14 @@ static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
 
 static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream)
 {
-       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-       struct snd_dma_buffer *buf = &substream->dma_buffer;
+       struct snd_pcm_substream *substream;
+       struct snd_dma_buffer *buf;
+
+       substream = pcm->streams[stream].substream;
+       if (!substream)
+               return;
 
+       buf = &substream->dma_buffer;
        if (!buf->area)
                return;
 
index a42e9ac..661373c 100644 (file)
@@ -56,6 +56,7 @@
 #define GPIO_HP_MUTE    BIT(1)
 #define GPIO_INT_MIC_EN BIT(2)
 #define GPIO_EXT_MIC_EN BIT(3)
+#define GPIO_HP_DET     BIT(4)
 
 struct tegra_wm8903 {
        struct tegra_asoc_utils_data util_data;
@@ -304,6 +305,7 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
                snd_soc_jack_add_gpios(&tegra_wm8903_hp_jack,
                                        1,
                                        &tegra_wm8903_hp_jack_gpio);
+               machine->gpio_requested |= GPIO_HP_DET;
        }
 
        snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE,
@@ -429,10 +431,10 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev)
        struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
        struct tegra_wm8903_platform_data *pdata = machine->pdata;
 
-       snd_soc_unregister_card(card);
-
-       tegra_asoc_utils_fini(&machine->util_data);
-
+       if (machine->gpio_requested & GPIO_HP_DET)
+               snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack,
+                                       1,
+                                       &tegra_wm8903_hp_jack_gpio);
        if (machine->gpio_requested & GPIO_EXT_MIC_EN)
                gpio_free(pdata->gpio_ext_mic_en);
        if (machine->gpio_requested & GPIO_INT_MIC_EN)
@@ -441,6 +443,11 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev)
                gpio_free(pdata->gpio_hp_mute);
        if (machine->gpio_requested & GPIO_SPKR_EN)
                gpio_free(pdata->gpio_spkr_en);
+       machine->gpio_requested = 0;
+
+       snd_soc_unregister_card(card);
+
+       tegra_asoc_utils_fini(&machine->util_data);
 
        kfree(machine);
 
index 34aa972..3de99af 100644 (file)
@@ -290,6 +290,7 @@ static void txx9aclc_pcm_free_dma_buffers(struct snd_pcm *pcm)
 
 static int txx9aclc_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_card *card = rtd->card->snd_card;
        struct snd_soc_dai *dai = rtd->cpu_dai;
        struct snd_pcm *pcm = rtd->pcm;
        struct platform_device *pdev = to_platform_device(dai->platform->dev);
index d0d493c..2cf87f5 100644 (file)
@@ -139,8 +139,12 @@ static void stream_stop(struct snd_usb_caiaqdev *dev)
 
        for (i = 0; i < N_URBS; i++) {
                usb_kill_urb(dev->data_urbs_in[i]);
-               usb_kill_urb(dev->data_urbs_out[i]);
+
+               if (test_bit(i, &dev->outurb_active_mask))
+                       usb_kill_urb(dev->data_urbs_out[i]);
        }
+
+       dev->outurb_active_mask = 0;
 }
 
 static int snd_usb_caiaq_substream_open(struct snd_pcm_substream *substream)
@@ -612,8 +616,9 @@ static void read_completed(struct urb *urb)
 {
        struct snd_usb_caiaq_cb_info *info = urb->context;
        struct snd_usb_caiaqdev *dev;
-       struct urb *out;
-       int frame, len, send_it = 0, outframe = 0;
+       struct urb *out = NULL;
+       int i, frame, len, send_it = 0, outframe = 0;
+       size_t offset = 0;
 
        if (urb->status || !info)
                return;
@@ -623,7 +628,17 @@ static void read_completed(struct urb *urb)
        if (!dev->streaming)
                return;
 
-       out = dev->data_urbs_out[info->index];
+       /* find an unused output urb that is unused */
+       for (i = 0; i < N_URBS; i++)
+               if (test_and_set_bit(i, &dev->outurb_active_mask) == 0) {
+                       out = dev->data_urbs_out[i];
+                       break;
+               }
+
+       if (!out) {
+               log("Unable to find an output urb to use\n");
+               goto requeue;
+       }
 
        /* read the recently received packet and send back one which has
         * the same layout */
@@ -634,7 +649,8 @@ static void read_completed(struct urb *urb)
                len = urb->iso_frame_desc[outframe].actual_length;
                out->iso_frame_desc[outframe].length = len;
                out->iso_frame_desc[outframe].actual_length = 0;
-               out->iso_frame_desc[outframe].offset = BYTES_PER_FRAME * frame;
+               out->iso_frame_desc[outframe].offset = offset;
+               offset += len;
 
                if (len > 0) {
                        spin_lock(&dev->spinlock);
@@ -650,11 +666,15 @@ static void read_completed(struct urb *urb)
        }
 
        if (send_it) {
-               out->number_of_packets = FRAMES_PER_URB;
+               out->number_of_packets = outframe;
                out->transfer_flags = URB_ISO_ASAP;
                usb_submit_urb(out, GFP_ATOMIC);
+       } else {
+               struct snd_usb_caiaq_cb_info *oinfo = out->context;
+               clear_bit(oinfo->index, &dev->outurb_active_mask);
        }
 
+requeue:
        /* re-submit inbound urb */
        for (frame = 0; frame < FRAMES_PER_URB; frame++) {
                urb->iso_frame_desc[frame].offset = BYTES_PER_FRAME * frame;
@@ -676,6 +696,8 @@ static void write_completed(struct urb *urb)
                dev->output_running = 1;
                wake_up(&dev->prepare_wait_queue);
        }
+
+       clear_bit(info->index, &dev->outurb_active_mask);
 }
 
 static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret)
@@ -827,6 +849,9 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev)
        if (!dev->data_cb_info)
                return -ENOMEM;
 
+       dev->outurb_active_mask = 0;
+       BUILD_BUG_ON(N_URBS > (sizeof(dev->outurb_active_mask) * 8));
+
        for (i = 0; i < N_URBS; i++) {
                dev->data_cb_info[i].dev = dev;
                dev->data_cb_info[i].index = i;
index b2b3101..3f9c633 100644 (file)
@@ -96,6 +96,7 @@ struct snd_usb_caiaqdev {
        int input_panic, output_panic, warned;
        char *audio_in_buf, *audio_out_buf;
        unsigned int samplerates, bpp;
+       unsigned long outurb_active_mask;
 
        struct snd_pcm_substream *sub_playback[MAX_STREAMS];
        struct snd_pcm_substream *sub_capture[MAX_STREAMS];
index 4432ef7..a213813 100644 (file)
@@ -30,7 +30,7 @@ static unsigned short keycode_ak1[] =  { KEY_C, KEY_B, KEY_A };
 static unsigned short keycode_rk2[] =  { KEY_1, KEY_2, KEY_3, KEY_4,
                                         KEY_5, KEY_6, KEY_7 };
 static unsigned short keycode_rk3[] =  { KEY_1, KEY_2, KEY_3, KEY_4,
-                                        KEY_5, KEY_6, KEY_7, KEY_5, KEY_6 };
+                                        KEY_5, KEY_6, KEY_7, KEY_8, KEY_9 };
 
 static unsigned short keycode_kore[] = {
        KEY_FN_F1,      /* "menu"               */
index 7c0d21e..7d46e48 100644 (file)
@@ -352,7 +352,7 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                        continue;
                }
                if (((protocol == UAC_VERSION_1) && (fmt->bLength < 8)) ||
-                   ((protocol == UAC_VERSION_2) && (fmt->bLength != 6))) {
+                   ((protocol == UAC_VERSION_2) && (fmt->bLength < 6))) {
                        snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n",
                                   dev->devnum, iface_no, altno);
                        continue;
index c22fa76..cdd19d7 100644 (file)
@@ -152,6 +152,7 @@ static inline void check_mapped_dB(const struct usbmix_name_map *p,
        if (p && p->dB) {
                cval->dBmin = p->dB->min;
                cval->dBmax = p->dB->max;
+               cval->initialized = 1;
        }
 }
 
@@ -1092,7 +1093,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
                                " Switch" : " Volume");
                if (control == UAC_FU_VOLUME) {
                        check_mapped_dB(map, cval);
-                       if (cval->dBmin < cval->dBmax) {
+                       if (cval->dBmin < cval->dBmax || !cval->initialized) {
                                kctl->tlv.c = mixer_vol_tlv;
                                kctl->vd[0].access |= 
                                        SNDRV_CTL_ELEM_ACCESS_TLV_READ |
@@ -1191,6 +1192,11 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void
 
        if (state->mixer->protocol == UAC_VERSION_1) {
                csize = hdr->bControlSize;
+               if (!csize) {
+                       snd_printdd(KERN_ERR "usbaudio: unit %u: "
+                                   "invalid bControlSize == 0\n", unitid);
+                       return -EINVAL;
+               }
                channels = (hdr->bLength - 7) / csize - 1;
                bmaControls = hdr->bmaControls;
        } else {
@@ -1934,15 +1940,13 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
        struct mixer_build state;
        int err;
        const struct usbmix_ctl_map *map;
-       struct usb_host_interface *hostif;
        void *p;
 
-       hostif = mixer->chip->ctrl_intf;
        memset(&state, 0, sizeof(state));
        state.chip = mixer->chip;
        state.mixer = mixer;
-       state.buffer = hostif->extra;
-       state.buflen = hostif->extralen;
+       state.buffer = mixer->hostif->extra;
+       state.buflen = mixer->hostif->extralen;
 
        /* check the mapping table */
        for (map = usbmix_ctl_maps; map->id; map++) {
@@ -1955,7 +1959,8 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
        }
 
        p = NULL;
-       while ((p = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, p, UAC_OUTPUT_TERMINAL)) != NULL) {
+       while ((p = snd_usb_find_csint_desc(mixer->hostif->extra, mixer->hostif->extralen,
+                                           p, UAC_OUTPUT_TERMINAL)) != NULL) {
                if (mixer->protocol == UAC_VERSION_1) {
                        struct uac1_output_terminal_descriptor *desc = p;
 
@@ -2162,17 +2167,15 @@ int snd_usb_mixer_activate(struct usb_mixer_interface *mixer)
 /* create the handler for the optional status interrupt endpoint */
 static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer)
 {
-       struct usb_host_interface *hostif;
        struct usb_endpoint_descriptor *ep;
        void *transfer_buffer;
        int buffer_length;
        unsigned int epnum;
 
-       hostif = mixer->chip->ctrl_intf;
        /* we need one interrupt input endpoint */
-       if (get_iface_desc(hostif)->bNumEndpoints < 1)
+       if (get_iface_desc(mixer->hostif)->bNumEndpoints < 1)
                return 0;
-       ep = get_endpoint(hostif, 0);
+       ep = get_endpoint(mixer->hostif, 0);
        if (!usb_endpoint_dir_in(ep) || !usb_endpoint_xfer_int(ep))
                return 0;
 
@@ -2202,7 +2205,6 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
        };
        struct usb_mixer_interface *mixer;
        struct snd_info_entry *entry;
-       struct usb_host_interface *host_iface;
        int err;
 
        strcpy(chip->card->mixername, "USB Mixer");
@@ -2219,8 +2221,8 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
                return -ENOMEM;
        }
 
-       host_iface = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0];
-       switch (get_iface_desc(host_iface)->bInterfaceProtocol) {
+       mixer->hostif = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0];
+       switch (get_iface_desc(mixer->hostif)->bInterfaceProtocol) {
        case UAC_VERSION_1:
        default:
                mixer->protocol = UAC_VERSION_1;
index ae1a14d..81b2d8a 100644 (file)
@@ -3,6 +3,7 @@
 
 struct usb_mixer_interface {
        struct snd_usb_audio *chip;
+       struct usb_host_interface *hostif;
        struct list_head list;
        unsigned int ignore_ctl_error;
        struct urb *urb;
index dba0b7f..a42e3ef 100644 (file)
@@ -1707,6 +1707,40 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
+{
+       USB_DEVICE(0x0582, 0x0130),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               /* .vendor_name = "BOSS", */
+               /* .product_name = "MICRO BR-80", */
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_IGNORE_INTERFACE
+                       },
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 3,
+                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
+                               .data = & (const struct snd_usb_midi_endpoint_info) {
+                                       .out_cables = 0x0001,
+                                       .in_cables  = 0x0001
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
 
 /* Guillemot devices */
 {
@@ -2417,6 +2451,12 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        .idProduct = 0x1020,
 },
 
+/* KeithMcMillen Stringport */
+{
+       USB_DEVICE(0x1f38, 0x0001),
+       .bInterfaceClass = USB_CLASS_AUDIO,
+},
+
 /* Miditech devices */
 {
        USB_DEVICE(0x4752, 0x0011),
index 77762c9..81e07d8 100644 (file)
@@ -426,7 +426,7 @@ static int snd_usb_cm106_boot_quirk(struct usb_device *dev)
  */
 static int snd_usb_cm6206_boot_quirk(struct usb_device *dev)
 {
-       int err, reg;
+       int err  = 0, reg;
        int val[] = {0x2004, 0x3000, 0xf800, 0x143f, 0x0000, 0x3000};
 
        for (reg = 0; reg < ARRAY_SIZE(val); reg++) {
index 56d62d3..3b8f7b8 100644 (file)
@@ -181,9 +181,9 @@ strip-libs = $(filter-out -l%,$(1))
 
 $(OUTPUT)python/perf.so: $(PYRF_OBJS)
        $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \
-         --quiet build_ext \
-         --build-lib='$(OUTPUT)python' \
-         --build-temp='$(OUTPUT)python/temp'
+         --quiet build_ext; \
+       mkdir -p $(OUTPUT)python && \
+       cp $(PYTHON_EXTBUILD_LIB)perf.so $(OUTPUT)python/
 #
 # No Perl scripts right now:
 #
@@ -509,9 +509,13 @@ else
 
   PYTHON_WORD := $(call shell-wordify,$(PYTHON))
 
-  python-clean := $(PYTHON_WORD) util/setup.py clean \
-    --build-lib='$(OUTPUT)python' \
-    --build-temp='$(OUTPUT)python/temp'
+  # python extension build directories
+  PYTHON_EXTBUILD     := $(OUTPUT)python_ext_build/
+  PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
+  PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/
+  export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
+
+  python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so
 
   ifdef NO_LIBPYTHON
     $(call disable-python)
@@ -868,6 +872,9 @@ install: all
        $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'
        $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
 
+install-python_ext:
+       $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)'
+
 install-doc:
        $(MAKE) -C Documentation install
 
@@ -895,7 +902,7 @@ quick-install-html:
 ### Cleaning rules
 
 clean:
-       $(RM) $(OUTPUT){*.o,*/*.o,*/*/*.o,*/*/*/*.o,$(LIB_FILE),perf-archive}
+       $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS)
        $(RM) $(ALL_PROGRAMS) perf
        $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
        $(MAKE) -C Documentation/ clean
index 9ac05aa..899080a 100644 (file)
@@ -942,10 +942,10 @@ static const char *record_args[] = {
        "-f",
        "-m", "1024",
        "-c", "1",
-       "-e", "lock:lock_acquire:r",
-       "-e", "lock:lock_acquired:r",
-       "-e", "lock:lock_contended:r",
-       "-e", "lock:lock_release:r",
+       "-e", "lock:lock_acquire",
+       "-e", "lock:lock_acquired",
+       "-e", "lock:lock_contended",
+       "-e", "lock:lock_release",
 };
 
 static int __cmd_record(int argc, const char **argv)
index 5f2a5c7..710ae3d 100644 (file)
@@ -134,10 +134,18 @@ static int opt_show_lines(const struct option *opt __used,
 {
        int ret = 0;
 
-       if (str)
-               ret = parse_line_range_desc(str, &params.line_range);
-       INIT_LIST_HEAD(&params.line_range.line_list);
+       if (!str)
+               return 0;
+
+       if (params.show_lines) {
+               pr_warning("Warning: more than one --line options are"
+                          " detected. Only the first one is valid.\n");
+               return 0;
+       }
+
        params.show_lines = true;
+       ret = parse_line_range_desc(str, &params.line_range);
+       INIT_LIST_HEAD(&params.line_range.line_list);
 
        return ret;
 }
index 80dc5b7..6b0519f 100644 (file)
@@ -30,8 +30,6 @@
 #include <sched.h>
 #include <sys/mman.h>
 
-#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
-
 enum write_mode_t {
        WRITE_FORCE,
        WRITE_APPEND
@@ -47,7 +45,7 @@ static int                    freq                            =   1000;
 static int                     output;
 static int                     pipe_output                     =      0;
 static const char              *output_name                    = NULL;
-static int                     group                           =      0;
+static bool                    group                           =  false;
 static int                     realtime_prio                   =      0;
 static bool                    nodelay                         =  false;
 static bool                    raw_samples                     =  false;
@@ -438,7 +436,6 @@ static void mmap_read_all(void)
 
 static int __cmd_record(int argc, const char **argv)
 {
-       int i;
        struct stat st;
        int flags;
        int err;
@@ -682,7 +679,6 @@ static int __cmd_record(int argc, const char **argv)
 
        for (;;) {
                int hits = samples;
-               int thread;
 
                mmap_read_all();
 
@@ -693,19 +689,8 @@ static int __cmd_record(int argc, const char **argv)
                        waking++;
                }
 
-               if (done) {
-                       for (i = 0; i < evsel_list->cpus->nr; i++) {
-                               struct perf_evsel *pos;
-
-                               list_for_each_entry(pos, &evsel_list->entries, node) {
-                                       for (thread = 0;
-                                               thread < evsel_list->threads->nr;
-                                               thread++)
-                                               ioctl(FD(pos, i, thread),
-                                                       PERF_EVENT_IOC_DISABLE);
-                               }
-                       }
-               }
+               if (done)
+                       perf_evlist__disable(evsel_list);
        }
 
        if (quiet || signr == SIGUSR1)
@@ -768,6 +753,8 @@ const struct option record_options[] = {
                    "child tasks do not inherit counters"),
        OPT_UINTEGER('F', "freq", &user_freq, "profile at this frequency"),
        OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"),
+       OPT_BOOLEAN(0, "group", &group,
+                   "put the counters into a counter group"),
        OPT_BOOLEAN('g', "call-graph", &call_graph,
                    "do call-graph (stack chain/backtrace) recording"),
        OPT_INCR('v', "verbose", &verbose,
index f854efd..d7ff277 100644 (file)
@@ -162,23 +162,22 @@ static int perf_session__setup_sample_type(struct perf_session *self)
 {
        if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) {
                if (sort__has_parent) {
-                       fprintf(stderr, "selected --sort parent, but no"
-                                       " callchain data. Did you call"
-                                       " perf record without -g?\n");
+                       ui__warning("Selected --sort parent, but no "
+                                   "callchain data. Did you call "
+                                   "'perf record' without -g?\n");
                        return -EINVAL;
                }
                if (symbol_conf.use_callchain) {
-                       fprintf(stderr, "selected -g but no callchain data."
-                                       " Did you call perf record without"
-                                       " -g?\n");
+                       ui__warning("Selected -g but no callchain data. Did "
+                                   "you call 'perf record' without -g?\n");
                        return -1;
                }
        } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE &&
                   !symbol_conf.use_callchain) {
                        symbol_conf.use_callchain = true;
                        if (callchain_register_param(&callchain_param) < 0) {
-                               fprintf(stderr, "Can't register callchain"
-                                               " params\n");
+                               ui__warning("Can't register callchain "
+                                           "params.\n");
                                return -EINVAL;
                        }
        }
index dcfe887..5177964 100644 (file)
@@ -1637,23 +1637,29 @@ static struct perf_event_ops event_ops = {
        .ordered_samples        = true,
 };
 
-static int read_events(void)
+static void read_events(bool destroy, struct perf_session **psession)
 {
        int err = -EINVAL;
        struct perf_session *session = perf_session__new(input_name, O_RDONLY,
                                                         0, false, &event_ops);
        if (session == NULL)
-               return -ENOMEM;
+               die("No Memory");
 
        if (perf_session__has_traces(session, "record -R")) {
                err = perf_session__process_events(session, &event_ops);
+               if (err)
+                       die("Failed to process events, error %d", err);
+
                nr_events      = session->hists.stats.nr_events[0];
                nr_lost_events = session->hists.stats.total_lost;
                nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST];
        }
 
-       perf_session__delete(session);
-       return err;
+       if (destroy)
+               perf_session__delete(session);
+
+       if (psession)
+               *psession = session;
 }
 
 static void print_bad_events(void)
@@ -1689,9 +1695,10 @@ static void print_bad_events(void)
 static void __cmd_lat(void)
 {
        struct rb_node *next;
+       struct perf_session *session;
 
        setup_pager();
-       read_events();
+       read_events(false, &session);
        sort_lat();
 
        printf("\n ---------------------------------------------------------------------------------------------------------------\n");
@@ -1717,6 +1724,7 @@ static void __cmd_lat(void)
        print_bad_events();
        printf("\n");
 
+       perf_session__delete(session);
 }
 
 static struct trace_sched_handler map_ops  = {
@@ -1731,7 +1739,7 @@ static void __cmd_map(void)
        max_cpu = sysconf(_SC_NPROCESSORS_CONF);
 
        setup_pager();
-       read_events();
+       read_events(true, NULL);
        print_bad_events();
 }
 
@@ -1744,7 +1752,7 @@ static void __cmd_replay(void)
 
        test_calibrations();
 
-       read_events();
+       read_events(true, NULL);
 
        printf("nr_run_events:        %ld\n", nr_run_events);
        printf("nr_sleep_events:      %ld\n", nr_sleep_events);
@@ -1769,7 +1777,7 @@ static void __cmd_replay(void)
 
 
 static const char * const sched_usage[] = {
-       "perf sched [<options>] {record|latency|map|replay|trace}",
+       "perf sched [<options>] {record|latency|map|replay|script}",
        NULL
 };
 
index 1ad04ce..5deb17d 100644 (file)
@@ -193,6 +193,7 @@ static int                  big_num_opt                     =  -1;
 static const char              *cpu_list;
 static const char              *csv_sep                        = NULL;
 static bool                    csv_output                      = false;
+static bool                    group                           = false;
 
 static volatile int done = 0;
 
@@ -280,14 +281,14 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
        attr->inherit = !no_inherit;
 
        if (system_wide)
-               return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, false);
+               return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, group);
 
        if (target_pid == -1 && target_tid == -1) {
                attr->disabled = 1;
                attr->enable_on_exec = 1;
        }
 
-       return perf_evsel__open_per_thread(evsel, evsel_list->threads, false);
+       return perf_evsel__open_per_thread(evsel, evsel_list->threads, group);
 }
 
 /*
@@ -1043,6 +1044,8 @@ static const struct option options[] = {
                    "stat events on existing thread id"),
        OPT_BOOLEAN('a', "all-cpus", &system_wide,
                    "system-wide collection from all CPUs"),
+       OPT_BOOLEAN('g', "group", &group,
+                   "put the counters into a counter group"),
        OPT_BOOLEAN('c', "scale", &scale,
                    "scale/normalize counters"),
        OPT_INCR('v', "verbose", &verbose,
index e02d78c..fe02903 100644 (file)
@@ -399,7 +399,6 @@ static int perf_config_global(void)
 int perf_config(config_fn_t fn, void *data)
 {
        int ret = 0, found = 0;
-       char *repo_config = NULL;
        const char *home = NULL;
 
        /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
@@ -414,19 +413,32 @@ int perf_config(config_fn_t fn, void *data)
        home = getenv("HOME");
        if (perf_config_global() && home) {
                char *user_config = strdup(mkpath("%s/.perfconfig", home));
-               if (!access(user_config, R_OK)) {
-                       ret += perf_config_from_file(fn, user_config, data);
-                       found += 1;
+               struct stat st;
+
+               if (user_config == NULL) {
+                       warning("Not enough memory to process %s/.perfconfig, "
+                               "ignoring it.", home);
+                       goto out;
                }
-               free(user_config);
-       }
 
-       repo_config = perf_pathdup("config");
-       if (!access(repo_config, R_OK)) {
-               ret += perf_config_from_file(fn, repo_config, data);
+               if (stat(user_config, &st) < 0)
+                       goto out_free;
+
+               if (st.st_uid && (st.st_uid != geteuid())) {
+                       warning("File %s not owned by current user or root, "
+                               "ignoring it.", user_config);
+                       goto out_free;
+               }
+
+               if (!st.st_size)
+                       goto out_free;
+
+               ret += perf_config_from_file(fn, user_config, data);
                found += 1;
+out_free:
+               free(user_config);
        }
-       free(repo_config);
+out:
        if (found == 0)
                return -1;
        return ret;
index fddf40f..ee51e9b 100644 (file)
@@ -96,6 +96,39 @@ int cu_find_lineinfo(Dwarf_Die *cu_die, unsigned long addr,
        return *lineno ?: -ENOENT;
 }
 
+static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data);
+
+/**
+ * cu_walk_functions_at - Walk on function DIEs at given address
+ * @cu_die: A CU DIE
+ * @addr: An address
+ * @callback: A callback which called with found DIEs
+ * @data: A user data
+ *
+ * Walk on function DIEs at given @addr in @cu_die. Passed DIEs
+ * should be subprogram or inlined-subroutines.
+ */
+int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr,
+                   int (*callback)(Dwarf_Die *, void *), void *data)
+{
+       Dwarf_Die die_mem;
+       Dwarf_Die *sc_die;
+       int ret = -ENOENT;
+
+       /* Inlined function could be recursive. Trace it until fail */
+       for (sc_die = die_find_realfunc(cu_die, addr, &die_mem);
+            sc_die != NULL;
+            sc_die = die_find_child(sc_die, __die_find_inline_cb, &addr,
+                                    &die_mem)) {
+               ret = callback(sc_die, data);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+
+}
+
 /**
  * die_compare_name - Compare diename and tname
  * @dw_die: a DIE
@@ -198,6 +231,19 @@ static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name,
        return 0;
 }
 
+/* Get attribute and translate it as a sdata */
+static int die_get_attr_sdata(Dwarf_Die *tp_die, unsigned int attr_name,
+                             Dwarf_Sword *result)
+{
+       Dwarf_Attribute attr;
+
+       if (dwarf_attr(tp_die, attr_name, &attr) == NULL ||
+           dwarf_formsdata(&attr, result) != 0)
+               return -ENOENT;
+
+       return 0;
+}
+
 /**
  * die_is_signed_type - Check whether a type DIE is signed or not
  * @tp_die: a DIE of a type
@@ -250,6 +296,50 @@ int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs)
        return 0;
 }
 
+/* Get the call file index number in CU DIE */
+static int die_get_call_fileno(Dwarf_Die *in_die)
+{
+       Dwarf_Sword idx;
+
+       if (die_get_attr_sdata(in_die, DW_AT_call_file, &idx) == 0)
+               return (int)idx;
+       else
+               return -ENOENT;
+}
+
+/* Get the declared file index number in CU DIE */
+static int die_get_decl_fileno(Dwarf_Die *pdie)
+{
+       Dwarf_Sword idx;
+
+       if (die_get_attr_sdata(pdie, DW_AT_decl_file, &idx) == 0)
+               return (int)idx;
+       else
+               return -ENOENT;
+}
+
+/**
+ * die_get_call_file - Get callsite file name of inlined function instance
+ * @in_die: a DIE of an inlined function instance
+ *
+ * Get call-site file name of @in_die. This means from which file the inline
+ * function is called.
+ */
+const char *die_get_call_file(Dwarf_Die *in_die)
+{
+       Dwarf_Die cu_die;
+       Dwarf_Files *files;
+       int idx;
+
+       idx = die_get_call_fileno(in_die);
+       if (idx < 0 || !dwarf_diecu(in_die, &cu_die, NULL, NULL) ||
+           dwarf_getsrcfiles(&cu_die, &files, NULL) != 0)
+               return NULL;
+
+       return dwarf_filesrc(files, idx, NULL, NULL);
+}
+
+
 /**
  * die_find_child - Generic DIE search function in DIE tree
  * @rt_die: a root DIE
@@ -374,9 +464,78 @@ Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
        return die_mem;
 }
 
+struct __instance_walk_param {
+       void    *addr;
+       int     (*callback)(Dwarf_Die *, void *);
+       void    *data;
+       int     retval;
+};
+
+static int __die_walk_instances_cb(Dwarf_Die *inst, void *data)
+{
+       struct __instance_walk_param *iwp = data;
+       Dwarf_Attribute attr_mem;
+       Dwarf_Die origin_mem;
+       Dwarf_Attribute *attr;
+       Dwarf_Die *origin;
+       int tmp;
+
+       attr = dwarf_attr(inst, DW_AT_abstract_origin, &attr_mem);
+       if (attr == NULL)
+               return DIE_FIND_CB_CONTINUE;
+
+       origin = dwarf_formref_die(attr, &origin_mem);
+       if (origin == NULL || origin->addr != iwp->addr)
+               return DIE_FIND_CB_CONTINUE;
+
+       /* Ignore redundant instances */
+       if (dwarf_tag(inst) == DW_TAG_inlined_subroutine) {
+               dwarf_decl_line(origin, &tmp);
+               if (die_get_call_lineno(inst) == tmp) {
+                       tmp = die_get_decl_fileno(origin);
+                       if (die_get_call_fileno(inst) == tmp)
+                               return DIE_FIND_CB_CONTINUE;
+               }
+       }
+
+       iwp->retval = iwp->callback(inst, iwp->data);
+
+       return (iwp->retval) ? DIE_FIND_CB_END : DIE_FIND_CB_CONTINUE;
+}
+
+/**
+ * die_walk_instances - Walk on instances of given DIE
+ * @or_die: an abstract original DIE
+ * @callback: a callback function which is called with instance DIE
+ * @data: user data
+ *
+ * Walk on the instances of give @in_die. @in_die must be an inlined function
+ * declartion. This returns the return value of @callback if it returns
+ * non-zero value, or -ENOENT if there is no instance.
+ */
+int die_walk_instances(Dwarf_Die *or_die, int (*callback)(Dwarf_Die *, void *),
+                      void *data)
+{
+       Dwarf_Die cu_die;
+       Dwarf_Die die_mem;
+       struct __instance_walk_param iwp = {
+               .addr = or_die->addr,
+               .callback = callback,
+               .data = data,
+               .retval = -ENOENT,
+       };
+
+       if (dwarf_diecu(or_die, &cu_die, NULL, NULL) == NULL)
+               return -ENOENT;
+
+       die_find_child(&cu_die, __die_walk_instances_cb, &iwp, &die_mem);
+
+       return iwp.retval;
+}
+
 /* Line walker internal parameters */
 struct __line_walk_param {
-       const char *fname;
+       bool recursive;
        line_walk_callback_t callback;
        void *data;
        int retval;
@@ -385,39 +544,56 @@ struct __line_walk_param {
 static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data)
 {
        struct __line_walk_param *lw = data;
-       Dwarf_Addr addr;
+       Dwarf_Addr addr = 0;
+       const char *fname;
        int lineno;
 
        if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) {
+               fname = die_get_call_file(in_die);
                lineno = die_get_call_lineno(in_die);
-               if (lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) {
-                       lw->retval = lw->callback(lw->fname, lineno, addr,
-                                                 lw->data);
+               if (fname && lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) {
+                       lw->retval = lw->callback(fname, lineno, addr, lw->data);
                        if (lw->retval != 0)
                                return DIE_FIND_CB_END;
                }
        }
-       return DIE_FIND_CB_SIBLING;
+       if (!lw->recursive)
+               /* Don't need to search recursively */
+               return DIE_FIND_CB_SIBLING;
+
+       if (addr) {
+               fname = dwarf_decl_file(in_die);
+               if (fname && dwarf_decl_line(in_die, &lineno) == 0) {
+                       lw->retval = lw->callback(fname, lineno, addr, lw->data);
+                       if (lw->retval != 0)
+                               return DIE_FIND_CB_END;
+               }
+       }
+
+       /* Continue to search nested inlined function call-sites */
+       return DIE_FIND_CB_CONTINUE;
 }
 
 /* Walk on lines of blocks included in given DIE */
-static int __die_walk_funclines(Dwarf_Die *sp_die,
+static int __die_walk_funclines(Dwarf_Die *sp_die, bool recursive,
                                line_walk_callback_t callback, void *data)
 {
        struct __line_walk_param lw = {
+               .recursive = recursive,
                .callback = callback,
                .data = data,
                .retval = 0,
        };
        Dwarf_Die die_mem;
        Dwarf_Addr addr;
+       const char *fname;
        int lineno;
 
        /* Handle function declaration line */
-       lw.fname = dwarf_decl_file(sp_die);
-       if (lw.fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
+       fname = dwarf_decl_file(sp_die);
+       if (fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
            dwarf_entrypc(sp_die, &addr) == 0) {
-               lw.retval = callback(lw.fname, lineno, addr, data);
+               lw.retval = callback(fname, lineno, addr, data);
                if (lw.retval != 0)
                        goto done;
        }
@@ -430,7 +606,7 @@ static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)
 {
        struct __line_walk_param *lw = data;
 
-       lw->retval = __die_walk_funclines(sp_die, lw->callback, lw->data);
+       lw->retval = __die_walk_funclines(sp_die, true, lw->callback, lw->data);
        if (lw->retval != 0)
                return DWARF_CB_ABORT;
 
@@ -439,7 +615,7 @@ static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)
 
 /**
  * die_walk_lines - Walk on lines inside given DIE
- * @rt_die: a root DIE (CU or subprogram)
+ * @rt_die: a root DIE (CU, subprogram or inlined_subroutine)
  * @callback: callback routine
  * @data: user data
  *
@@ -460,12 +636,12 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data)
        size_t nlines, i;
 
        /* Get the CU die */
-       if (dwarf_tag(rt_die) == DW_TAG_subprogram)
+       if (dwarf_tag(rt_die) != DW_TAG_compile_unit)
                cu_die = dwarf_diecu(rt_die, &die_mem, NULL, NULL);
        else
                cu_die = rt_die;
        if (!cu_die) {
-               pr_debug2("Failed to get CU from subprogram\n");
+               pr_debug2("Failed to get CU from given DIE.\n");
                return -EINVAL;
        }
 
@@ -509,7 +685,11 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data)
         * subroutines. We have to check functions list or given function.
         */
        if (rt_die != cu_die)
-               ret = __die_walk_funclines(rt_die, callback, data);
+               /*
+                * Don't need walk functions recursively, because nested
+                * inlined functions don't have lines of the specified DIE.
+                */
+               ret = __die_walk_funclines(rt_die, false, callback, data);
        else {
                struct __line_walk_param param = {
                        .callback = callback,
index bc3b211..6ce1717 100644 (file)
@@ -34,12 +34,19 @@ extern const char *cu_get_comp_dir(Dwarf_Die *cu_die);
 extern int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr,
                            const char **fname, int *lineno);
 
+/* Walk on funcitons at given address */
+extern int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr,
+                       int (*callback)(Dwarf_Die *, void *), void *data);
+
 /* Compare diename and tname */
 extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname);
 
 /* Get callsite line number of inline-function instance */
 extern int die_get_call_lineno(Dwarf_Die *in_die);
 
+/* Get callsite file name of inlined function instance */
+extern const char *die_get_call_file(Dwarf_Die *in_die);
+
 /* Get type die */
 extern Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem);
 
@@ -73,6 +80,10 @@ extern Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr,
 extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
                                      Dwarf_Die *die_mem);
 
+/* Walk on the instances of given DIE */
+extern int die_walk_instances(Dwarf_Die *in_die,
+                             int (*callback)(Dwarf_Die *, void *), void *data);
+
 /* Walker on lines (Note: line number will not be sorted) */
 typedef int (* line_walk_callback_t) (const char *fname, int lineno,
                                      Dwarf_Addr addr, void *data);
index b021ea9..c12bd47 100644 (file)
@@ -85,10 +85,32 @@ int perf_evlist__add_default(struct perf_evlist *evlist)
        struct perf_evsel *evsel = perf_evsel__new(&attr, 0);
 
        if (evsel == NULL)
-               return -ENOMEM;
+               goto error;
+
+       /* use strdup() because free(evsel) assumes name is allocated */
+       evsel->name = strdup("cycles");
+       if (!evsel->name)
+               goto error_free;
 
        perf_evlist__add(evlist, evsel);
        return 0;
+error_free:
+       perf_evsel__delete(evsel);
+error:
+       return -ENOMEM;
+}
+
+void perf_evlist__disable(struct perf_evlist *evlist)
+{
+       int cpu, thread;
+       struct perf_evsel *pos;
+
+       for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
+               list_for_each_entry(pos, &evlist->entries, node) {
+                       for (thread = 0; thread < evlist->threads->nr; thread++)
+                               ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_DISABLE);
+               }
+       }
 }
 
 int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
index b2b8623..ce85ae9 100644 (file)
@@ -53,6 +53,8 @@ int perf_evlist__alloc_mmap(struct perf_evlist *evlist);
 int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite);
 void perf_evlist__munmap(struct perf_evlist *evlist);
 
+void perf_evlist__disable(struct perf_evlist *evlist);
+
 static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
                                         struct cpu_map *cpus,
                                         struct thread_map *threads)
index cb2959a..b6c1ad1 100644 (file)
@@ -189,8 +189,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
                          const char *name, bool is_kallsyms)
 {
        const size_t size = PATH_MAX;
-       char *realname, *filename = malloc(size),
-            *linkname = malloc(size), *targetname;
+       char *realname, *filename = zalloc(size),
+            *linkname = zalloc(size), *targetname;
        int len, err = -1;
 
        if (is_kallsyms) {
@@ -254,8 +254,8 @@ static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
 int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
 {
        const size_t size = PATH_MAX;
-       char *filename = malloc(size),
-            *linkname = malloc(size);
+       char *filename = zalloc(size),
+            *linkname = zalloc(size);
        int err = -1;
 
        if (filename == NULL || linkname == NULL)
@@ -726,7 +726,16 @@ static int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
                        return -1;
 
                bev.header = old_bev.header;
-               bev.pid    = 0;
+
+               /*
+                * As the pid is the missing value, we need to fill
+                * it properly. The header.misc value give us nice hint.
+                */
+               bev.pid = HOST_KERNEL_ID;
+               if (bev.header.misc == PERF_RECORD_MISC_GUEST_USER ||
+                   bev.header.misc == PERF_RECORD_MISC_GUEST_KERNEL)
+                       bev.pid = DEFAULT_GUEST_KERNEL_ID;
+
                memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id));
                __event_process_build_id(&bev, filename, session);
 
index 791f9dd..547628e 100644 (file)
@@ -5,7 +5,9 @@
 #define __always_inline        inline
 #endif
 #define __user
+#ifndef __attribute_const__
 #define __attribute_const__
+#endif
 
 #define __used         __attribute__((__unused__))
 
index 4ea7e19..928918b 100644 (file)
@@ -697,7 +697,11 @@ parse_raw_event(const char **strp, struct perf_event_attr *attr)
                return EVT_FAILED;
        n = hex2u64(str + 1, &config);
        if (n > 0) {
-               *strp = str + n + 1;
+               const char *end = str + n + 1;
+               if (*end != '\0' && *end != ',' && *end != ':')
+                       return EVT_FAILED;
+
+               *strp = end;
                attr->type = PERF_TYPE_RAW;
                attr->config = config;
                return EVT_HANDLED;
@@ -1097,6 +1101,4 @@ void print_events(const char *event_glob)
        printf("\n");
 
        print_tracepoint_events(NULL, NULL);
-
-       exit(129);
 }
index b82d54f..1c7bfa5 100644 (file)
@@ -1820,11 +1820,15 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
                ret = -ENOMEM;
                goto error;
        }
-       tev->point.module = strdup(module);
-       if (tev->point.module == NULL) {
-               ret = -ENOMEM;
-               goto error;
+
+       if (module) {
+               tev->point.module = strdup(module);
+               if (tev->point.module == NULL) {
+                       ret = -ENOMEM;
+                       goto error;
+               }
        }
+
        tev->point.offset = pev->point.offset;
        tev->point.retprobe = pev->point.retprobe;
        tev->nargs = pev->nargs;
index 3e44a3e..555fc38 100644 (file)
@@ -612,12 +612,12 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
        return ret;
 }
 
-/* Find a variable in a subprogram die */
-static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
+/* Find a variable in a scope DIE */
+static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
 {
-       Dwarf_Die vr_die, *scopes;
+       Dwarf_Die vr_die;
        char buf[32], *ptr;
-       int ret, nscopes;
+       int ret = 0;
 
        if (!is_c_varname(pf->pvar->var)) {
                /* Copy raw parameters */
@@ -652,30 +652,16 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
        if (pf->tvar->name == NULL)
                return -ENOMEM;
 
-       pr_debug("Searching '%s' variable in context.\n",
-                pf->pvar->var);
+       pr_debug("Searching '%s' variable in context.\n", pf->pvar->var);
        /* Search child die for local variables and parameters. */
-       if (die_find_variable_at(sp_die, pf->pvar->var, pf->addr, &vr_die))
-               ret = convert_variable(&vr_die, pf);
-       else {
-               /* Search upper class */
-               nscopes = dwarf_getscopes_die(sp_die, &scopes);
-               while (nscopes-- > 1) {
-                       pr_debug("Searching variables in %s\n",
-                                dwarf_diename(&scopes[nscopes]));
-                       /* We should check this scope, so give dummy address */
-                       if (die_find_variable_at(&scopes[nscopes],
-                                                pf->pvar->var, 0,
-                                                &vr_die)) {
-                               ret = convert_variable(&vr_die, pf);
-                               goto found;
-                       }
-               }
-               if (scopes)
-                       free(scopes);
-               ret = -ENOENT;
+       if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) {
+               /* Search again in global variables */
+               if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die))
+                       ret = -ENOENT;
        }
-found:
+       if (ret == 0)
+               ret = convert_variable(&vr_die, pf);
+
        if (ret < 0)
                pr_warning("Failed to find '%s' in this function.\n",
                           pf->pvar->var);
@@ -718,26 +704,30 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,
        return 0;
 }
 
-/* Call probe_finder callback with real subprogram DIE */
-static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
+/* Call probe_finder callback with scope DIE */
+static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
 {
-       Dwarf_Die die_mem;
        Dwarf_Attribute fb_attr;
        size_t nops;
        int ret;
 
-       /* If no real subprogram, find a real one */
-       if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
-               sp_die = die_find_realfunc(&pf->cu_die, pf->addr, &die_mem);
-               if (!sp_die) {
+       if (!sc_die) {
+               pr_err("Caller must pass a scope DIE. Program error.\n");
+               return -EINVAL;
+       }
+
+       /* If not a real subprogram, find a real one */
+       if (dwarf_tag(sc_die) != DW_TAG_subprogram) {
+               if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) {
                        pr_warning("Failed to find probe point in any "
                                   "functions.\n");
                        return -ENOENT;
                }
-       }
+       } else
+               memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die));
 
-       /* Get the frame base attribute/ops */
-       dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
+       /* Get the frame base attribute/ops from subprogram */
+       dwarf_attr(&pf->sp_die, DW_AT_frame_base, &fb_attr);
        ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1);
        if (ret <= 0 || nops == 0) {
                pf->fb_ops = NULL;
@@ -755,7 +745,7 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
        }
 
        /* Call finder's callback handler */
-       ret = pf->callback(sp_die, pf);
+       ret = pf->callback(sc_die, pf);
 
        /* *pf->fb_ops will be cached in libdw. Don't free it. */
        pf->fb_ops = NULL;
@@ -763,17 +753,82 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
        return ret;
 }
 
+struct find_scope_param {
+       const char *function;
+       const char *file;
+       int line;
+       int diff;
+       Dwarf_Die *die_mem;
+       bool found;
+};
+
+static int find_best_scope_cb(Dwarf_Die *fn_die, void *data)
+{
+       struct find_scope_param *fsp = data;
+       const char *file;
+       int lno;
+
+       /* Skip if declared file name does not match */
+       if (fsp->file) {
+               file = dwarf_decl_file(fn_die);
+               if (!file || strcmp(fsp->file, file) != 0)
+                       return 0;
+       }
+       /* If the function name is given, that's what user expects */
+       if (fsp->function) {
+               if (die_compare_name(fn_die, fsp->function)) {
+                       memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die));
+                       fsp->found = true;
+                       return 1;
+               }
+       } else {
+               /* With the line number, find the nearest declared DIE */
+               dwarf_decl_line(fn_die, &lno);
+               if (lno < fsp->line && fsp->diff > fsp->line - lno) {
+                       /* Keep a candidate and continue */
+                       fsp->diff = fsp->line - lno;
+                       memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die));
+                       fsp->found = true;
+               }
+       }
+       return 0;
+}
+
+/* Find an appropriate scope fits to given conditions */
+static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem)
+{
+       struct find_scope_param fsp = {
+               .function = pf->pev->point.function,
+               .file = pf->fname,
+               .line = pf->lno,
+               .diff = INT_MAX,
+               .die_mem = die_mem,
+               .found = false,
+       };
+
+       cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp);
+
+       return fsp.found ? die_mem : NULL;
+}
+
 static int probe_point_line_walker(const char *fname, int lineno,
                                   Dwarf_Addr addr, void *data)
 {
        struct probe_finder *pf = data;
+       Dwarf_Die *sc_die, die_mem;
        int ret;
 
        if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0)
                return 0;
 
        pf->addr = addr;
-       ret = call_probe_finder(NULL, pf);
+       sc_die = find_best_scope(pf, &die_mem);
+       if (!sc_die) {
+               pr_warning("Failed to find scope of probe point.\n");
+               return -ENOENT;
+       }
+
+       ret = call_probe_finder(sc_die, pf);
 
        /* Continue if no error, because the line will be in inline function */
        return ret < 0 ? ret : 0;
@@ -827,6 +882,7 @@ static int probe_point_lazy_walker(const char *fname, int lineno,
                                   Dwarf_Addr addr, void *data)
 {
        struct probe_finder *pf = data;
+       Dwarf_Die *sc_die, die_mem;
        int ret;
 
        if (!line_list__has_line(&pf->lcache, lineno) ||
@@ -836,7 +892,14 @@ static int probe_point_lazy_walker(const char *fname, int lineno,
        pr_debug("Probe line found: line:%d addr:0x%llx\n",
                 lineno, (unsigned long long)addr);
        pf->addr = addr;
-       ret = call_probe_finder(NULL, pf);
+       pf->lno = lineno;
+       sc_die = find_best_scope(pf, &die_mem);
+       if (!sc_die) {
+               pr_warning("Failed to find scope of probe point.\n");
+               return -ENOENT;
+       }
+
+       ret = call_probe_finder(sc_die, pf);
 
        /*
         * Continue if no error, because the lazy pattern will match
@@ -861,42 +924,39 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
        return die_walk_lines(sp_die, probe_point_lazy_walker, pf);
 }
 
-/* Callback parameter with return value */
-struct dwarf_callback_param {
-       void *data;
-       int retval;
-};
-
 static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
 {
-       struct dwarf_callback_param *param = data;
-       struct probe_finder *pf = param->data;
+       struct probe_finder *pf = data;
        struct perf_probe_point *pp = &pf->pev->point;
        Dwarf_Addr addr;
+       int ret;
 
        if (pp->lazy_line)
-               param->retval = find_probe_point_lazy(in_die, pf);
+               ret = find_probe_point_lazy(in_die, pf);
        else {
                /* Get probe address */
                if (dwarf_entrypc(in_die, &addr) != 0) {
                        pr_warning("Failed to get entry address of %s.\n",
                                   dwarf_diename(in_die));
-                       param->retval = -ENOENT;
-                       return DWARF_CB_ABORT;
+                       return -ENOENT;
                }
                pf->addr = addr;
                pf->addr += pp->offset;
                pr_debug("found inline addr: 0x%jx\n",
                         (uintmax_t)pf->addr);
 
-               param->retval = call_probe_finder(in_die, pf);
-               if (param->retval < 0)
-                       return DWARF_CB_ABORT;
+               ret = call_probe_finder(in_die, pf);
        }
 
-       return DWARF_CB_OK;
+       return ret;
 }
 
+/* Callback parameter with return value for libdw */
+struct dwarf_callback_param {
+       void *data;
+       int retval;
+};
+
 /* Search function from function name */
 static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
 {
@@ -933,14 +993,10 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
                        /* TODO: Check the address in this function */
                        param->retval = call_probe_finder(sp_die, pf);
                }
-       } else {
-               struct dwarf_callback_param _param = {.data = (void *)pf,
-                                                     .retval = 0};
+       } else
                /* Inlined function: search instances */
-               dwarf_func_inline_instances(sp_die, probe_point_inline_cb,
-                                           &_param);
-               param->retval = _param.retval;
-       }
+               param->retval = die_walk_instances(sp_die,
+                                       probe_point_inline_cb, (void *)pf);
 
        return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */
 }
@@ -1060,7 +1116,7 @@ found:
 }
 
 /* Add a found probe point into trace event list */
-static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)
+static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
 {
        struct trace_event_finder *tf =
                        container_of(pf, struct trace_event_finder, pf);
@@ -1075,8 +1131,9 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)
        }
        tev = &tf->tevs[tf->ntevs++];
 
-       ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe,
-                                    &tev->point);
+       /* Trace point should be converted from subprogram DIE */
+       ret = convert_to_trace_point(&pf->sp_die, pf->addr,
+                                    pf->pev->point.retprobe, &tev->point);
        if (ret < 0)
                return ret;
 
@@ -1091,7 +1148,8 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)
        for (i = 0; i < pf->pev->nargs; i++) {
                pf->pvar = &pf->pev->args[i];
                pf->tvar = &tev->args[i];
-               ret = find_variable(sp_die, pf);
+               /* Variable should be found from scope DIE */
+               ret = find_variable(sc_die, pf);
                if (ret != 0)
                        return ret;
        }
@@ -1159,13 +1217,13 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
 }
 
 /* Add a found vars into available variables list */
-static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
+static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf)
 {
        struct available_var_finder *af =
                        container_of(pf, struct available_var_finder, pf);
        struct variable_list *vl;
-       Dwarf_Die die_mem, *scopes = NULL;
-       int ret, nscopes;
+       Dwarf_Die die_mem;
+       int ret;
 
        /* Check number of tevs */
        if (af->nvls == af->max_vls) {
@@ -1174,8 +1232,9 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
        }
        vl = &af->vls[af->nvls++];
 
-       ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe,
-                                    &vl->point);
+       /* Trace point should be converted from subprogram DIE */
+       ret = convert_to_trace_point(&pf->sp_die, pf->addr,
+                                    pf->pev->point.retprobe, &vl->point);
        if (ret < 0)
                return ret;
 
@@ -1187,19 +1246,14 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
        if (vl->vars == NULL)
                return -ENOMEM;
        af->child = true;
-       die_find_child(sp_die, collect_variables_cb, (void *)af, &die_mem);
+       die_find_child(sc_die, collect_variables_cb, (void *)af, &die_mem);
 
        /* Find external variables */
        if (!af->externs)
                goto out;
        /* Don't need to search child DIE for externs. */
        af->child = false;
-       nscopes = dwarf_getscopes_die(sp_die, &scopes);
-       while (nscopes-- > 1)
-               die_find_child(&scopes[nscopes], collect_variables_cb,
-                              (void *)af, &die_mem);
-       if (scopes)
-               free(scopes);
+       die_find_child(&pf->cu_die, collect_variables_cb, (void *)af, &die_mem);
 
 out:
        if (strlist__empty(vl->vars)) {
@@ -1391,10 +1445,14 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
 
 static int line_range_inline_cb(Dwarf_Die *in_die, void *data)
 {
-       struct dwarf_callback_param *param = data;
+       find_line_range_by_line(in_die, data);
 
-       param->retval = find_line_range_by_line(in_die, param->data);
-       return DWARF_CB_ABORT;  /* No need to find other instances */
+       /*
+        * We have to check all instances of inlined function, because
+        * some execution paths can be optimized out depends on the
+        * function argument of instances
+        */
+       return 0;
 }
 
 /* Search function from function name */
@@ -1422,15 +1480,10 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
                pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e);
                lr->start = lf->lno_s;
                lr->end = lf->lno_e;
-               if (dwarf_func_inline(sp_die)) {
-                       struct dwarf_callback_param _param;
-                       _param.data = (void *)lf;
-                       _param.retval = 0;
-                       dwarf_func_inline_instances(sp_die,
-                                                   line_range_inline_cb,
-                                                   &_param);
-                       param->retval = _param.retval;
-               } else
+               if (dwarf_func_inline(sp_die))
+                       param->retval = die_walk_instances(sp_die,
+                                               line_range_inline_cb, lf);
+               else
                        param->retval = find_line_range_by_line(sp_die, lf);
                return DWARF_CB_ABORT;
        }
index c478b42..1132c8f 100644 (file)
@@ -57,7 +57,7 @@ struct probe_finder {
        struct perf_probe_event *pev;           /* Target probe event */
 
        /* Callback when a probe point is found */
-       int (*callback)(Dwarf_Die *sp_die, struct probe_finder *pf);
+       int (*callback)(Dwarf_Die *sc_die, struct probe_finder *pf);
 
        /* For function searching */
        int                     lno;            /* Line number */
index 8e0b5a3..cbc8f21 100644 (file)
@@ -187,14 +187,117 @@ static PyTypeObject pyrf_throttle_event__type = {
        .tp_repr        = (reprfunc)pyrf_throttle_event__repr,
 };
 
+static char pyrf_lost_event__doc[] = PyDoc_STR("perf lost event object.");
+
+static PyMemberDef pyrf_lost_event__members[] = {
+       sample_members
+       member_def(lost_event, id, T_ULONGLONG, "event id"),
+       member_def(lost_event, lost, T_ULONGLONG, "number of lost events"),
+       { .name = NULL, },
+};
+
+static PyObject *pyrf_lost_event__repr(struct pyrf_event *pevent)
+{
+       PyObject *ret;
+       char *s;
+
+       if (asprintf(&s, "{ type: lost, id: %#" PRIx64 ", "
+                        "lost: %#" PRIx64 " }",
+                    pevent->event.lost.id, pevent->event.lost.lost) < 0) {
+               ret = PyErr_NoMemory();
+       } else {
+               ret = PyString_FromString(s);
+               free(s);
+       }
+       return ret;
+}
+
+static PyTypeObject pyrf_lost_event__type = {
+       PyVarObject_HEAD_INIT(NULL, 0)
+       .tp_name        = "perf.lost_event",
+       .tp_basicsize   = sizeof(struct pyrf_event),
+       .tp_flags       = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+       .tp_doc         = pyrf_lost_event__doc,
+       .tp_members     = pyrf_lost_event__members,
+       .tp_repr        = (reprfunc)pyrf_lost_event__repr,
+};
+
+static char pyrf_read_event__doc[] = PyDoc_STR("perf read event object.");
+
+static PyMemberDef pyrf_read_event__members[] = {
+       sample_members
+       member_def(read_event, pid, T_UINT, "event pid"),
+       member_def(read_event, tid, T_UINT, "event tid"),
+       { .name = NULL, },
+};
+
+static PyObject *pyrf_read_event__repr(struct pyrf_event *pevent)
+{
+       return PyString_FromFormat("{ type: read, pid: %u, tid: %u }",
+                                  pevent->event.read.pid,
+                                  pevent->event.read.tid);
+       /*
+        * FIXME: return the array of read values,
+        * making this method useful ;-)
+        */
+}
+
+static PyTypeObject pyrf_read_event__type = {
+       PyVarObject_HEAD_INIT(NULL, 0)
+       .tp_name        = "perf.read_event",
+       .tp_basicsize   = sizeof(struct pyrf_event),
+       .tp_flags       = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+       .tp_doc         = pyrf_read_event__doc,
+       .tp_members     = pyrf_read_event__members,
+       .tp_repr        = (reprfunc)pyrf_read_event__repr,
+};
+
+static char pyrf_sample_event__doc[] = PyDoc_STR("perf sample event object.");
+
+static PyMemberDef pyrf_sample_event__members[] = {
+       sample_members
+       member_def(perf_event_header, type, T_UINT, "event type"),
+       { .name = NULL, },
+};
+
+static PyObject *pyrf_sample_event__repr(struct pyrf_event *pevent)
+{
+       PyObject *ret;
+       char *s;
+
+       if (asprintf(&s, "{ type: sample }") < 0) {
+               ret = PyErr_NoMemory();
+       } else {
+               ret = PyString_FromString(s);
+               free(s);
+       }
+       return ret;
+}
+
+static PyTypeObject pyrf_sample_event__type = {
+       PyVarObject_HEAD_INIT(NULL, 0)
+       .tp_name        = "perf.sample_event",
+       .tp_basicsize   = sizeof(struct pyrf_event),
+       .tp_flags       = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+       .tp_doc         = pyrf_sample_event__doc,
+       .tp_members     = pyrf_sample_event__members,
+       .tp_repr        = (reprfunc)pyrf_sample_event__repr,
+};
+
 static int pyrf_event__setup_types(void)
 {
        int err;
        pyrf_mmap_event__type.tp_new =
        pyrf_task_event__type.tp_new =
        pyrf_comm_event__type.tp_new =
+       pyrf_lost_event__type.tp_new =
+       pyrf_read_event__type.tp_new =
+       pyrf_sample_event__type.tp_new =
        pyrf_throttle_event__type.tp_new = PyType_GenericNew;
        err = PyType_Ready(&pyrf_mmap_event__type);
+       if (err < 0)
+               goto out;
+       err = PyType_Ready(&pyrf_lost_event__type);
        if (err < 0)
                goto out;
        err = PyType_Ready(&pyrf_task_event__type);
@@ -206,20 +309,26 @@ static int pyrf_event__setup_types(void)
        err = PyType_Ready(&pyrf_throttle_event__type);
        if (err < 0)
                goto out;
+       err = PyType_Ready(&pyrf_read_event__type);
+       if (err < 0)
+               goto out;
+       err = PyType_Ready(&pyrf_sample_event__type);
+       if (err < 0)
+               goto out;
 out:
        return err;
 }
 
 static PyTypeObject *pyrf_event__type[] = {
        [PERF_RECORD_MMAP]       = &pyrf_mmap_event__type,
-       [PERF_RECORD_LOST]       = &pyrf_mmap_event__type,
+       [PERF_RECORD_LOST]       = &pyrf_lost_event__type,
        [PERF_RECORD_COMM]       = &pyrf_comm_event__type,
        [PERF_RECORD_EXIT]       = &pyrf_task_event__type,
        [PERF_RECORD_THROTTLE]   = &pyrf_throttle_event__type,
        [PERF_RECORD_UNTHROTTLE] = &pyrf_throttle_event__type,
        [PERF_RECORD_FORK]       = &pyrf_task_event__type,
-       [PERF_RECORD_READ]       = &pyrf_mmap_event__type,
-       [PERF_RECORD_SAMPLE]     = &pyrf_mmap_event__type,
+       [PERF_RECORD_READ]       = &pyrf_read_event__type,
+       [PERF_RECORD_SAMPLE]     = &pyrf_sample_event__type,
 };
 
 static PyObject *pyrf_event__new(union perf_event *event)
index bbc982f..95d3700 100644 (file)
@@ -3,9 +3,27 @@
 from distutils.core import setup, Extension
 from os import getenv
 
+from distutils.command.build_ext   import build_ext   as _build_ext
+from distutils.command.install_lib import install_lib as _install_lib
+
+class build_ext(_build_ext):
+    def finalize_options(self):
+        _build_ext.finalize_options(self)
+        self.build_lib  = build_lib
+        self.build_temp = build_tmp
+
+class install_lib(_install_lib):
+    def finalize_options(self):
+        _install_lib.finalize_options(self)
+        self.build_dir = build_lib
+
+
 cflags = ['-fno-strict-aliasing', '-Wno-write-strings']
 cflags += getenv('CFLAGS', '').split()
 
+build_lib = getenv('PYTHON_EXTBUILD_LIB')
+build_tmp = getenv('PYTHON_EXTBUILD_TMP')
+
 perf = Extension('perf',
                  sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c',
                             'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c',
@@ -21,4 +39,5 @@ setup(name='perf',
       author_email='acme@redhat.com',
       license='GPLv2',
       url='http://perf.wiki.kernel.org',
-      ext_modules=[perf])
+      ext_modules=[perf],
+      cmdclass={'build_ext': build_ext, 'install_lib': install_lib})
index eec1963..469c026 100644 (file)
@@ -1504,6 +1504,17 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
        dso->adjust_symbols = 0;
 
        if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
+               struct stat st;
+
+               if (lstat(dso->name, &st) < 0)
+                       return -1;
+
+               if (st.st_uid && (st.st_uid != geteuid())) {
+                       pr_warning("File %s not owned by current user or root, "
+                               "ignoring it.\n", dso->name);
+                       return -1;
+               }
+
                ret = dso__load_perf_map(dso, map, filter);
                dso->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT :
                                              SYMTAB__NOT_FOUND;
@@ -2170,27 +2181,22 @@ size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
        return ret;
 }
 
-struct dso *dso__new_kernel(const char *name)
+static struct dso*
+dso__kernel_findnew(struct machine *machine, const char *name,
+                   const char *short_name, int dso_type)
 {
-       struct dso *dso = dso__new(name ?: "[kernel.kallsyms]");
-
-       if (dso != NULL) {
-               dso__set_short_name(dso, "[kernel]");
-               dso->kernel = DSO_TYPE_KERNEL;
-       }
-
-       return dso;
-}
+       /*
+        * The kernel dso could be created by build_id processing.
+        */
+       struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name);
 
-static struct dso *dso__new_guest_kernel(struct machine *machine,
-                                       const char *name)
-{
-       char bf[PATH_MAX];
-       struct dso *dso = dso__new(name ?: machine__mmap_name(machine, bf,
-                                                             sizeof(bf)));
+       /*
+        * We need to run this in all cases, since during the build_id
+        * processing we had no idea this was the kernel dso.
+        */
        if (dso != NULL) {
-               dso__set_short_name(dso, "[guest.kernel]");
-               dso->kernel = DSO_TYPE_GUEST_KERNEL;
+               dso__set_short_name(dso, short_name);
+               dso->kernel = dso_type;
        }
 
        return dso;
@@ -2208,24 +2214,36 @@ void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine)
                dso->has_build_id = true;
 }
 
-static struct dso *machine__create_kernel(struct machine *machine)
+static struct dso *machine__get_kernel(struct machine *machine)
 {
        const char *vmlinux_name = NULL;
        struct dso *kernel;
 
        if (machine__is_host(machine)) {
                vmlinux_name = symbol_conf.vmlinux_name;
-               kernel = dso__new_kernel(vmlinux_name);
+               if (!vmlinux_name)
+                       vmlinux_name = "[kernel.kallsyms]";
+
+               kernel = dso__kernel_findnew(machine, vmlinux_name,
+                                            "[kernel]",
+                                            DSO_TYPE_KERNEL);
        } else {
+               char bf[PATH_MAX];
+
                if (machine__is_default_guest(machine))
                        vmlinux_name = symbol_conf.default_guest_vmlinux_name;
-               kernel = dso__new_guest_kernel(machine, vmlinux_name);
+               if (!vmlinux_name)
+                       vmlinux_name = machine__mmap_name(machine, bf,
+                                                         sizeof(bf));
+
+               kernel = dso__kernel_findnew(machine, vmlinux_name,
+                                            "[guest.kernel]",
+                                            DSO_TYPE_GUEST_KERNEL);
        }
 
-       if (kernel != NULL) {
+       if (kernel != NULL && (!kernel->has_build_id))
                dso__read_running_kernel_build_id(kernel, machine);
-               dsos__add(&machine->kernel_dsos, kernel);
-       }
+
        return kernel;
 }
 
@@ -2329,7 +2347,7 @@ void machine__destroy_kernel_maps(struct machine *machine)
 
 int machine__create_kernel_maps(struct machine *machine)
 {
-       struct dso *kernel = machine__create_kernel(machine);
+       struct dso *kernel = machine__get_kernel(machine);
 
        if (kernel == NULL ||
            __machine__create_kernel_maps(machine, kernel) < 0)
index 325ee36..4f377d9 100644 (file)
@@ -155,7 +155,6 @@ struct dso {
 };
 
 struct dso *dso__new(const char *name);
-struct dso *dso__new_kernel(const char *name);
 void dso__delete(struct dso *dso);
 
 int dso__name_len(const struct dso *dso);
index 5a06538..88403cf 100644 (file)
@@ -208,6 +208,5 @@ int perf_top__tui_browser(struct perf_top *top)
                },
        };
 
-       ui_helpline__push("Press <- or ESC to exit");
        return perf_top_browser__run(&browser);
 }
diff --git a/tools/power/cpupower/.gitignore b/tools/power/cpupower/.gitignore
new file mode 100644 (file)
index 0000000..8a83dd2
--- /dev/null
@@ -0,0 +1,22 @@
+.libs
+libcpupower.so
+libcpupower.so.0
+libcpupower.so.0.0.0
+build/ccdv
+cpufreq-info
+cpufreq-set
+cpufreq-aperf
+lib/.libs
+lib/cpufreq.lo
+lib/cpufreq.o
+lib/proc.lo
+lib/proc.o
+lib/sysfs.lo
+lib/sysfs.o
+po/cpupowerutils.pot
+po/*.gmo
+utils/cpufreq-info.o
+utils/cpufreq-set.o
+utils/cpufreq-aperf.o
+cpupower
+bench/cpufreq-bench
diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile
new file mode 100644 (file)
index 0000000..94c2cf0
--- /dev/null
@@ -0,0 +1,279 @@
+# Makefile for cpupower
+#
+# Copyright (C) 2005,2006 Dominik Brodowski <linux@dominikbrodowski.net>
+#
+# Based largely on the Makefile for udev by:
+#
+# Copyright (C) 2003,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; 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
+#
+
+# --- CONFIGURATION BEGIN ---
+
+# Set the following to `true' to make a unstripped, unoptimized
+# binary. Leave this set to `false' for production use.
+DEBUG ?=       false
+
+# make the build silent. Set this to something else to make it noisy again.
+V ?=           false
+
+# Internationalization support (output in different languages).
+# Requires gettext.
+NLS ?=         true
+
+# Set the following to 'true' to build/install the
+# cpufreq-bench benchmarking tool
+CPUFRQ_BENCH ?= true
+
+# Prefix to the directories we're installing to
+DESTDIR ?=
+
+# --- CONFIGURATION END ---
+
+
+
+# Package-related definitions. Distributions can modify the version
+# and _should_ modify the PACKAGE_BUGREPORT definition
+
+VERSION=                       $(shell ./utils/version-gen.sh)
+LIB_MAJ=                       0.0.0
+LIB_MIN=                       0
+
+PACKAGE =                      cpupower
+PACKAGE_BUGREPORT =            cpufreq@vger.kernel.org
+LANGUAGES =                    de fr it cs pt
+
+
+# Directory definitions. These are default and most probably
+# do not need to be changed. Please note that DESTDIR is
+# added in front of any of them
+
+bindir ?=      /usr/bin
+sbindir ?=     /usr/sbin
+mandir ?=      /usr/man
+includedir ?=  /usr/include
+libdir ?=      /usr/lib
+localedir ?=   /usr/share/locale
+docdir ?=       /usr/share/doc/packages/cpupower
+confdir ?=      /etc/
+
+# Toolchain: what tools do we use, and what options do they need:
+
+CP = cp -fpR
+INSTALL = /usr/bin/install -c
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_DATA  = ${INSTALL} -m 644
+INSTALL_SCRIPT = ${INSTALL_PROGRAM}
+
+# If you are running a cross compiler, you may want to set this
+# to something more interesting, like "arm-linux-".  If you want
+# to compile vs uClibc, that can be done here as well.
+CROSS = #/usr/i386-linux-uclibc/usr/bin/i386-uclibc-
+CC = $(CROSS)gcc
+LD = $(CROSS)gcc
+AR = $(CROSS)ar
+STRIP = $(CROSS)strip
+RANLIB = $(CROSS)ranlib
+HOSTCC = gcc
+
+
+# Now we set up the build system
+#
+
+# set up PWD so that older versions of make will work with our build.
+PWD = $(shell pwd)
+
+GMO_FILES = ${shell for HLANG in ${LANGUAGES}; do echo po/$$HLANG.gmo; done;}
+
+export CROSS CC AR STRIP RANLIB CFLAGS LDFLAGS LIB_OBJS
+
+# check if compiler option is supported
+cc-supports = ${shell if $(CC) ${1} -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; fi;}
+
+# use '-Os' optimization if available, else use -O2
+OPTIMIZATION := $(call cc-supports,-Os,-O2)
+
+WARNINGS := -Wall -Wchar-subscripts -Wpointer-arith -Wsign-compare
+WARNINGS += $(call cc-supports,-Wno-pointer-sign)
+WARNINGS += $(call cc-supports,-Wdeclaration-after-statement)
+WARNINGS += -Wshadow
+
+CFLAGS += -DVERSION=\"$(VERSION)\" -DPACKAGE=\"$(PACKAGE)\" \
+               -DPACKAGE_BUGREPORT=\"$(PACKAGE_BUGREPORT)\" -D_GNU_SOURCE
+
+UTIL_OBJS =  utils/helpers/amd.o utils/helpers/topology.o utils/helpers/msr.o \
+       utils/helpers/sysfs.o utils/helpers/misc.o utils/helpers/cpuid.o \
+       utils/helpers/pci.o utils/helpers/bitmask.o \
+       utils/idle_monitor/nhm_idle.o utils/idle_monitor/snb_idle.o \
+       utils/idle_monitor/amd_fam14h_idle.o utils/idle_monitor/cpuidle_sysfs.o \
+       utils/idle_monitor/mperf_monitor.o utils/idle_monitor/cpupower-monitor.o \
+       utils/cpupower.o utils/cpufreq-info.o utils/cpufreq-set.o \
+       utils/cpupower-set.o utils/cpupower-info.o utils/cpuidle-info.o
+
+UTIL_HEADERS = utils/helpers/helpers.h utils/idle_monitor/cpupower-monitor.h \
+       utils/helpers/bitmask.h \
+       utils/idle_monitor/idle_monitors.h utils/idle_monitor/idle_monitors.def
+
+UTIL_SRC := $(UTIL_OBJS:.o=.c)
+
+LIB_HEADERS =  lib/cpufreq.h lib/sysfs.h
+LIB_SRC =      lib/cpufreq.c lib/sysfs.c
+LIB_OBJS =     lib/cpufreq.o lib/sysfs.o
+
+CFLAGS +=      -pipe
+
+ifeq ($(strip $(NLS)),true)
+       INSTALL_NLS += install-gmo
+       COMPILE_NLS += create-gmo
+endif
+
+ifeq ($(strip $(CPUFRQ_BENCH)),true)
+       INSTALL_BENCH += install-bench
+       COMPILE_BENCH += compile-bench
+endif
+
+CFLAGS += $(WARNINGS)
+
+ifeq ($(strip $(V)),false)
+       QUIET=@
+       ECHO=@echo
+else
+       QUIET=
+       ECHO=@\#
+endif
+export QUIET ECHO
+
+# if DEBUG is enabled, then we do not strip or optimize
+ifeq ($(strip $(DEBUG)),true)
+       CFLAGS += -O1 -g -DDEBUG
+       STRIPCMD = /bin/true -Since_we_are_debugging
+else
+       CFLAGS += $(OPTIMIZATION) -fomit-frame-pointer
+       STRIPCMD = $(STRIP) -s --remove-section=.note --remove-section=.comment
+endif
+
+
+# the actual make rules
+
+all: libcpupower cpupower $(COMPILE_NLS) $(COMPILE_BENCH)
+
+lib/%.o: $(LIB_SRC) $(LIB_HEADERS)
+       $(ECHO) "  CC      " $@
+       $(QUIET) $(CC) $(CFLAGS) -fPIC -o $@ -c lib/$*.c
+
+libcpupower.so.$(LIB_MAJ): $(LIB_OBJS)
+       $(ECHO) "  LD      " $@
+       $(QUIET) $(CC) -shared $(CFLAGS) $(LDFLAGS) -o $@ \
+               -Wl,-soname,libcpupower.so.$(LIB_MIN) $(LIB_OBJS)
+       @ln -sf $@ libcpupower.so
+       @ln -sf $@ libcpupower.so.$(LIB_MIN)
+
+libcpupower: libcpupower.so.$(LIB_MAJ)
+
+# Let all .o files depend on its .c file and all headers
+# Might be worth to put this into utils/Makefile at some point of time
+$(UTIL_OBJS): $(UTIL_HEADERS)
+
+.c.o:
+       $(ECHO) "  CC      " $@
+       $(QUIET) $(CC) $(CFLAGS) -I./lib -I ./utils -o $@ -c $*.c
+
+cpupower: $(UTIL_OBJS) libcpupower.so.$(LIB_MAJ)
+       $(ECHO) "  CC      " $@
+       $(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) -lcpupower -lrt -lpci -L. -o $@ $(UTIL_OBJS)
+       $(QUIET) $(STRIPCMD) $@
+
+po/$(PACKAGE).pot: $(UTIL_SRC)
+       $(ECHO) "  GETTEXT " $@
+       $(QUIET) xgettext --default-domain=$(PACKAGE) --add-comments \
+               --keyword=_ --keyword=N_ $(UTIL_SRC) && \
+       test -f $(PACKAGE).po && \
+       mv -f $(PACKAGE).po po/$(PACKAGE).pot
+
+po/%.gmo: po/%.po
+       $(ECHO) "  MSGFMT  " $@
+       $(QUIET) msgfmt -o $@ po/$*.po
+
+create-gmo: ${GMO_FILES}
+
+update-po: po/$(PACKAGE).pot
+       $(ECHO) "  MSGMRG  " $@
+       $(QUIET) @for HLANG in $(LANGUAGES); do \
+               echo -n "Updating $$HLANG "; \
+               if msgmerge po/$$HLANG.po po/$(PACKAGE).pot -o \
+                  po/$$HLANG.new.po; then \
+                       mv -f po/$$HLANG.new.po po/$$HLANG.po; \
+               else \
+                       echo "msgmerge for $$HLANG failed!"; \
+                       rm -f po/$$HLANG.new.po; \
+               fi; \
+       done;
+
+compile-bench: libcpupower.so.$(LIB_MAJ)
+       @V=$(V) confdir=$(confdir) $(MAKE) -C bench
+
+clean:
+       -find . \( -not -type d \) -and \( -name '*~' -o -name '*.[oas]' \) -type f -print \
+        | xargs rm -f
+       -rm -f $(UTIL_BINS)
+       -rm -f $(IDLE_OBJS)
+       -rm -f cpupower
+       -rm -f libcpupower.so*
+       -rm -rf po/*.gmo po/*.pot
+       $(MAKE) -C bench clean
+
+
+install-lib:
+       $(INSTALL) -d $(DESTDIR)${libdir}
+       $(CP) libcpupower.so* $(DESTDIR)${libdir}/
+       $(INSTALL) -d $(DESTDIR)${includedir}
+       $(INSTALL_DATA) lib/cpufreq.h $(DESTDIR)${includedir}/cpufreq.h
+
+install-tools:
+       $(INSTALL) -d $(DESTDIR)${bindir}
+       $(INSTALL_PROGRAM) cpupower $(DESTDIR)${bindir}
+
+install-man:
+       $(INSTALL_DATA) -D man/cpupower.1 $(DESTDIR)${mandir}/man1/cpupower.1
+       $(INSTALL_DATA) -D man/cpupower-frequency-set.1 $(DESTDIR)${mandir}/man1/cpupower-frequency-set.1
+       $(INSTALL_DATA) -D man/cpupower-frequency-info.1 $(DESTDIR)${mandir}/man1/cpupower-frequency-info.1
+       $(INSTALL_DATA) -D man/cpupower-set.1 $(DESTDIR)${mandir}/man1/cpupower-set.1
+       $(INSTALL_DATA) -D man/cpupower-info.1 $(DESTDIR)${mandir}/man1/cpupower-info.1
+       $(INSTALL_DATA) -D man/cpupower-monitor.1 $(DESTDIR)${mandir}/man1/cpupower-monitor.1
+
+install-gmo:
+       $(INSTALL) -d $(DESTDIR)${localedir}
+       for HLANG in $(LANGUAGES); do \
+               echo '$(INSTALL_DATA) -D po/$$HLANG.gmo $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo'; \
+               $(INSTALL_DATA) -D po/$$HLANG.gmo $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo; \
+       done;
+
+install-bench:
+       @#DESTDIR must be set from outside to survive
+       @sbindir=$(sbindir) bindir=$(bindir) docdir=$(docdir) confdir=$(confdir) $(MAKE) -C bench install
+
+install: all install-lib install-tools install-man $(INSTALL_NLS) $(INSTALL_BENCH)
+
+uninstall:
+       - rm -f $(DESTDIR)${libdir}/libcpupower.*
+       - rm -f $(DESTDIR)${includedir}/cpufreq.h
+       - rm -f $(DESTDIR)${bindir}/utils/cpupower
+       - rm -f $(DESTDIR)${mandir}/man1/cpufreq-set.1
+       - rm -f $(DESTDIR)${mandir}/man1/cpufreq-info.1
+       - for HLANG in $(LANGUAGES); do \
+               rm -f $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo; \
+         done;
+
+.PHONY: all utils libcpupower update-po create-gmo install-lib install-tools install-man install-gmo install uninstall clean
diff --git a/tools/power/cpupower/README b/tools/power/cpupower/README
new file mode 100644 (file)
index 0000000..fd9d4c0
--- /dev/null
@@ -0,0 +1,49 @@
+The cpufrequtils package (homepage: 
+http://www.kernel.org/pub/linux/utils/kernel/cpufreq/cpufrequtils.html ) 
+consists of the following elements:
+
+requirements
+------------
+
+On x86 pciutils is needed at runtime (-lpci).
+For compilation pciutils-devel (pci/pci.h) and a gcc version
+providing cpuid.h is needed.
+For both it's not explicitly checked for (yet).
+
+
+libcpufreq
+----------
+
+"libcpufreq" is a library which offers a unified access method for userspace
+tools and programs to the cpufreq core and drivers in the Linux kernel. This
+allows for code reduction in userspace tools, a clean implementation of
+the interaction to the cpufreq core, and support for both the sysfs and proc
+interfaces [depending on configuration, see below].
+
+
+compilation and installation
+----------------------------
+
+make
+su
+make install
+
+should suffice on most systems. It builds default libcpufreq,
+cpufreq-set and cpufreq-info files and installs them in /usr/lib and
+/usr/bin, respectively. If you want to set up the paths differently and/or
+want to configure the package to your specific needs, you need to open
+"Makefile" with an editor of your choice and edit the block marked
+CONFIGURATION.
+
+
+THANKS
+------
+Many thanks to Mattia Dongili who wrote the autotoolization and
+libtoolization, the manpages and the italian language file for cpufrequtils;
+to Dave Jones for his feedback and his dump_psb tool; to Bruno Ducrot for his
+powernow-k8-decode and intel_gsic tools as well as the french language file;
+and to various others commenting on the previous (pre-)releases of 
+cpufrequtils.
+
+
+        Dominik Brodowski
diff --git a/tools/power/cpupower/ToDo b/tools/power/cpupower/ToDo
new file mode 100644 (file)
index 0000000..874b78b
--- /dev/null
@@ -0,0 +1,11 @@
+ToDos sorted by priority:
+
+- Use bitmask functions to parse CPU topology more robust
+  (current implementation has issues on AMD)
+- Try to read out boost states and frequencies on Intel
+- Adjust README
+- Somewhere saw the ability to read power consumption of
+  RAM from HW on Intel SandyBridge -> another monitor?
+- Add another c1e debug idle monitor
+  -> Is by design racy with BIOS, but could be added
+     with a --force option and some "be careful" messages
diff --git a/tools/power/cpupower/bench/Makefile b/tools/power/cpupower/bench/Makefile
new file mode 100644 (file)
index 0000000..2b67606
--- /dev/null
@@ -0,0 +1,29 @@
+LIBS = -L../ -lm -lcpupower
+
+OBJS = main.o parse.o system.o benchmark.o
+CFLAGS += -D_GNU_SOURCE -I../lib -DDEFAULT_CONFIG_FILE=\"$(confdir)/cpufreq-bench.conf\"
+
+%.o : %.c
+       $(ECHO) "  CC      " $@
+       $(QUIET) $(CC) -c $(CFLAGS) $< -o $@
+
+cpufreq-bench: $(OBJS)
+       $(ECHO) "  CC      " $@
+       $(QUIET) $(CC) -o $@ $(CFLAGS) $(OBJS) $(LIBS)
+
+all: cpufreq-bench
+
+install:
+       mkdir -p $(DESTDIR)/$(sbindir)
+       mkdir -p $(DESTDIR)/$(bindir)
+       mkdir -p $(DESTDIR)/$(docdir)
+       mkdir -p $(DESTDIR)/$(confdir)
+       install -m 755 cpufreq-bench $(DESTDIR)/$(sbindir)/cpufreq-bench
+       install -m 755 cpufreq-bench_plot.sh $(DESTDIR)/$(bindir)/cpufreq-bench_plot.sh
+       install -m 644 README-BENCH $(DESTDIR)/$(docdir)/README-BENCH
+       install -m 755 cpufreq-bench_script.sh $(DESTDIR)/$(docdir)/cpufreq-bench_script.sh
+       install -m 644 example.cfg $(DESTDIR)/$(confdir)/cpufreq-bench.conf
+
+clean:
+       rm -f *.o
+       rm -f cpufreq-bench
diff --git a/tools/power/cpupower/bench/README-BENCH b/tools/power/cpupower/bench/README-BENCH
new file mode 100644 (file)
index 0000000..8093ec7
--- /dev/null
@@ -0,0 +1,124 @@
+This is cpufreq-bench, a microbenchmark for the cpufreq framework.
+
+Purpose
+=======
+
+What is this benchmark for:
+  - Identify worst case performance loss when doing dynamic frequency
+    scaling using Linux kernel governors
+  - Identify average reaction time of a governor to CPU load changes
+  - (Stress) Testing whether a cpufreq low level driver or governor works
+    as expected
+  - Identify cpufreq related performance regressions between kernels
+  - Possibly Real time priority testing? -> what happens if there are
+    processes with a higher prio than the governor's kernel thread
+  - ...
+
+What this benchmark does *not* cover:
+  - Power saving related regressions (In fact as better the performance
+    throughput is, the worse the power savings will be, but the first should
+    mostly count more...)
+  - Real world (workloads)
+
+
+Description
+===========
+
+cpufreq-bench helps to test the condition of a given cpufreq governor.
+For that purpose, it compares the performance governor to a configured
+powersave module.
+
+
+How it works
+============
+You can specify load (100% CPU load) and sleep (0% CPU load) times in us which
+will be run X time in a row (cycles):
+
+         sleep=25000
+         load=25000
+         cycles=20
+
+This part of the configuration file will create 25ms load/sleep turns,
+repeated 20 times.
+
+Adding this:
+         sleep_step=25000
+         load_step=25000
+         rounds=5
+Will increase load and sleep time by 25ms 5 times.
+Together you get following test:
+25ms  load/sleep time repeated 20 times (cycles).
+50ms  load/sleep time repeated 20 times (cycles).
+..
+100ms load/sleep time repeated 20 times (cycles).
+
+First it is calibrated how long a specific CPU intensive calculation
+takes on this machine and needs to be run in a loop using the performance
+governor.
+Then the above test runs are processed using the performance governor
+and the governor to test. The time the calculation really needed
+with the dynamic freq scaling governor is compared with the time needed
+on full performance and you get the overall performance loss.
+
+
+Example of expected results with ondemand governor:
+
+This shows expected results of the first two test run rounds from
+above config, you there have:
+
+100% CPU load (load) | 0 % CPU load (sleep)  | round
+   25 ms             |    25 ms              |   1
+   50 ms             |    50 ms              |   2
+
+For example if ondemand governor is configured to have a 50ms
+sampling rate you get:
+
+In round 1, ondemand should have rather static 50% load and probably
+won't ever switch up (as long as up_threshold is above).
+
+In round 2, if the ondemand sampling times exactly match the load/sleep
+trigger of the cpufreq-bench, you will see no performance loss (compare with
+below possible ondemand sample kick ins (1)):
+
+But if ondemand always kicks in in the middle of the load sleep cycles, it
+will always see 50% loads and you get worst performance impact never
+switching up (compare with below possible ondemand sample kick ins (2))::
+
+      50     50   50   50ms ->time
+load -----|     |-----|     |-----|     |-----|
+          |     |     |     |     |     |     |
+sleep     |-----|     |-----|     |-----|     |----
+    |-----|-----|-----|-----|-----|-----|-----|----  ondemand sampling (1)
+         100    0    100    0    100    0    100     load seen by ondemand(%)
+       |-----|-----|-----|-----|-----|-----|-----|--   ondemand sampling (2)
+      50     50    50    50    50    50    50        load seen by ondemand(%)
+
+You can easily test all kind of load/sleep times and check whether your
+governor in average behaves as expected.
+
+
+ToDo
+====
+
+Provide a gnuplot utility script for easy generation of plots to present
+the outcome nicely.
+
+
+cpufreq-bench Command Usage
+===========================
+-l, --load=<long int>           initial load time in us
+-s, --sleep=<long int>          initial sleep time in us
+-x, --load-step=<long int>      time to be added to load time, in us
+-y, --sleep-step=<long int>     time to be added to sleep time, in us
+-c, --cpu=<unsigned int>        CPU Number to use, starting at 0
+-p, --prio=<priority>           scheduler priority, HIGH, LOW or DEFAULT
+-g, --governor=<governor>       cpufreq governor to test
+-n, --cycles=<int>              load/sleep cycles to get an avarage value to compare
+-r, --rounds<int>               load/sleep rounds
+-f, --file=<configfile>         config file to use
+-o, --output=<dir>              output dir, must exist
+-v, --verbose                   verbose output on/off
+
+Due to the high priority, the application may not be responsible for some time.
+After the benchmark, the logfile is saved in OUTPUTDIR/benchmark_TIMESTAMP.log
+
diff --git a/tools/power/cpupower/bench/benchmark.c b/tools/power/cpupower/bench/benchmark.c
new file mode 100644 (file)
index 0000000..81b1c48
--- /dev/null
@@ -0,0 +1,194 @@
+/*  cpufreq-bench CPUFreq microbenchmark
+ *
+ *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  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 <stdio.h>
+#include <unistd.h>
+#include <math.h>
+
+#include "config.h"
+#include "system.h"
+#include "benchmark.h"
+
+/* Print out progress if we log into a file */
+#define show_progress(total_time, progress_time)       \
+if (config->output != stdout) {                                \
+       fprintf(stdout, "Progress: %02lu %%\r",         \
+               (progress_time * 100) / total_time);    \
+       fflush(stdout);                                 \
+}
+
+/**
+ * compute how many rounds of calculation we should do
+ * to get the given load time
+ *
+ * @param load aimed load time in µs
+ *
+ * @retval rounds of calculation
+ **/
+
+unsigned int calculate_timespace(long load, struct config *config)
+{
+       int i;
+       long long now, then;
+       unsigned int estimated = GAUGECOUNT;
+       unsigned int rounds = 0;
+       unsigned int timed = 0;
+
+       if (config->verbose)
+               printf("calibrating load of %lius, please wait...\n", load);
+
+       /* get the initial calculation time for a specific number of rounds */
+       now = get_time();
+       ROUNDS(estimated);
+       then = get_time();
+
+       timed = (unsigned int)(then - now);
+
+       /* approximation of the wanted load time by comparing with the
+        * initial calculation time */
+       for (i = 0; i < 4; i++) {
+               rounds = (unsigned int)(load * estimated / timed);
+               dprintf("calibrating with %u rounds\n", rounds);
+               now = get_time();
+               ROUNDS(rounds);
+               then = get_time();
+
+               timed = (unsigned int)(then - now);
+               estimated = rounds;
+       }
+       if (config->verbose)
+               printf("calibration done\n");
+
+       return estimated;
+}
+
+/**
+ * benchmark
+ * generates a specific sleep an load time with the performance
+ * governor and compares the used time for same calculations done
+ * with the configured powersave governor
+ *
+ * @param config config values for the benchmark
+ *
+ **/
+
+void start_benchmark(struct config *config)
+{
+       unsigned int _round, cycle;
+       long long now, then;
+       long sleep_time = 0, load_time = 0;
+       long performance_time = 0, powersave_time = 0;
+       unsigned int calculations;
+       unsigned long total_time = 0, progress_time = 0;
+
+       sleep_time = config->sleep;
+       load_time = config->load;
+
+       /* For the progress bar */
+       for (_round = 1; _round <= config->rounds; _round++)
+               total_time += _round * (config->sleep + config->load);
+       total_time *= 2; /* powersave and performance cycles */
+
+       for (_round = 0; _round < config->rounds; _round++) {
+               performance_time = 0LL;
+               powersave_time = 0LL;
+
+               show_progress(total_time, progress_time);
+
+               /* set the cpufreq governor to "performance" which disables
+                * P-State switching. */
+               if (set_cpufreq_governor("performance", config->cpu) != 0)
+                       return;
+
+               /* calibrate the calculation time. the resulting calculation
+                * _rounds should produce a load which matches the configured
+                * load time */
+               calculations = calculate_timespace(load_time, config);
+
+               if (config->verbose)
+                       printf("_round %i: doing %u cycles with %u calculations"
+                              " for %lius\n", _round + 1, config->cycles,
+                              calculations, load_time);
+
+               fprintf(config->output, "%u %li %li ",
+                       _round, load_time, sleep_time);
+
+               if (config->verbose)
+                       printf("avarage: %lius, rps:%li\n",
+                               load_time / calculations,
+                               1000000 * calculations / load_time);
+
+               /* do some sleep/load cycles with the performance governor */
+               for (cycle = 0; cycle < config->cycles; cycle++) {
+                       now = get_time();
+                       usleep(sleep_time);
+                       ROUNDS(calculations);
+                       then = get_time();
+                       performance_time += then - now - sleep_time;
+                       if (config->verbose)
+                               printf("performance cycle took %lius, "
+                                       "sleep: %lius, "
+                                       "load: %lius, rounds: %u\n",
+                                       (long)(then - now), sleep_time,
+                                       load_time, calculations);
+               }
+               fprintf(config->output, "%li ",
+                       performance_time / config->cycles);
+
+               progress_time += sleep_time + load_time;
+               show_progress(total_time, progress_time);
+
+               /* set the powersave governor which activates P-State switching
+                * again */
+               if (set_cpufreq_governor(config->governor, config->cpu) != 0)
+                       return;
+
+               /* again, do some sleep/load cycles with the
+                * powersave governor */
+               for (cycle = 0; cycle < config->cycles; cycle++) {
+                       now = get_time();
+                       usleep(sleep_time);
+                       ROUNDS(calculations);
+                       then = get_time();
+                       powersave_time += then - now - sleep_time;
+                       if (config->verbose)
+                               printf("powersave cycle took %lius, "
+                                       "sleep: %lius, "
+                                       "load: %lius, rounds: %u\n",
+                                       (long)(then - now), sleep_time,
+                                       load_time, calculations);
+               }
+
+               progress_time += sleep_time + load_time;
+
+               /* compare the avarage sleep/load cycles  */
+               fprintf(config->output, "%li ",
+                       powersave_time / config->cycles);
+               fprintf(config->output, "%.3f\n",
+                       performance_time * 100.0 / powersave_time);
+               fflush(config->output);
+
+               if (config->verbose)
+                       printf("performance is at %.2f%%\n",
+                               performance_time * 100.0 / powersave_time);
+
+               sleep_time += config->sleep_step;
+               load_time += config->load_step;
+       }
+}
diff --git a/tools/power/cpupower/bench/benchmark.h b/tools/power/cpupower/bench/benchmark.h
new file mode 100644 (file)
index 0000000..51d7f50
--- /dev/null
@@ -0,0 +1,29 @@
+/*  cpufreq-bench CPUFreq microbenchmark
+ *
+ *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  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.
+ */
+
+/* load loop, this schould take about 1 to 2ms to complete */
+#define ROUNDS(x) {unsigned int rcnt;                         \
+               for (rcnt = 0; rcnt < x*1000; rcnt++) { \
+                       (void)(((int)(pow(rcnt, rcnt) * \
+                                     sqrt(rcnt*7230970)) ^ 7230716) ^ \
+                                     (int)atan2(rcnt, rcnt));         \
+               } }                                                     \
+
+
+void start_benchmark(struct config *config);
diff --git a/tools/power/cpupower/bench/config.h b/tools/power/cpupower/bench/config.h
new file mode 100644 (file)
index 0000000..ee6f258
--- /dev/null
@@ -0,0 +1,36 @@
+/*  cpufreq-bench CPUFreq microbenchmark
+ *
+ *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  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.
+ */
+
+/* initial loop count for the load calibration */
+#define GAUGECOUNT     1500
+
+/* default scheduling policy SCHED_OTHER */
+#define SCHEDULER      SCHED_OTHER
+
+#define PRIORITY_DEFAULT 0
+#define PRIORITY_HIGH   sched_get_priority_max(SCHEDULER)
+#define PRIORITY_LOW    sched_get_priority_min(SCHEDULER)
+
+/* enable further debug messages */
+#ifdef DEBUG
+#define dprintf printf
+#else
+#define dprintf(...) do { } while (0)
+#endif
+
diff --git a/tools/power/cpupower/bench/cpufreq-bench_plot.sh b/tools/power/cpupower/bench/cpufreq-bench_plot.sh
new file mode 100644 (file)
index 0000000..410021a
--- /dev/null
@@ -0,0 +1,104 @@
+#!/bin/bash
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+# Author/Copyright(c): 2009, Thomas Renninger <trenn@suse.de>, Novell Inc.
+
+# Helper script to easily create nice plots of your cpufreq-bench results
+
+dir=`mktemp -d`
+output_file="cpufreq-bench.png"
+global_title="cpufreq-bench plot"
+picture_type="jpeg"
+file[0]=""
+
+function usage()
+{
+    echo "cpufreq-bench_plot.sh [OPTIONS] logfile [measure_title] [logfile [measure_title]] ...]"
+    echo
+    echo "Options"
+    echo "   -o output_file"
+    echo "   -t global_title"
+    echo "   -p picture_type [jpeg|gif|png|postscript|...]"
+    exit 1
+}
+
+if [ $# -eq 0 ];then
+       echo "No benchmark results file provided"
+       echo
+       usage
+fi
+
+while getopts o:t:p: name ; do
+    case $name in
+       o)
+           output_file="$OPTARG".$picture_type
+           ;;
+       t)
+           global_title="$OPTARG"
+           ;;
+       p)
+           picture_type="$OPTARG"
+           ;;
+        ?)
+           usage
+           ;;
+    esac
+done
+shift $(($OPTIND -1))
+
+plots=0
+while [ "$1" ];do
+    if [ ! -f "$1" ];then
+       echo "File $1 does not exist"
+       usage
+    fi
+    file[$plots]="$1"
+    title[$plots]="$2"
+    # echo "File: ${file[$plots]} - ${title[plots]}"
+    shift;shift
+    plots=$((plots + 1))
+done
+
+echo "set terminal $picture_type"      >> $dir/plot_script.gpl
+echo "set output \"$output_file\""     >> $dir/plot_script.gpl
+echo "set title \"$global_title\""     >> $dir/plot_script.gpl
+echo "set xlabel \"sleep/load time\""  >> $dir/plot_script.gpl
+echo "set ylabel \"Performance (%)\""  >> $dir/plot_script.gpl
+
+for((plot=0;plot<$plots;plot++));do
+
+    # Sanity check
+    ###### I am to dump to get this redirected to stderr/stdout in one awk call... #####
+    cat ${file[$plot]} |grep -v "^#" |awk '{if ($2 != $3) printf("Error in measure %d:Load time %s does not equal sleep time %s, plot will not be correct\n", $1, $2, $3); ERR=1}'
+    ###### I am to dump to get this redirected in one awk call... #####
+
+    # Parse out load time (which must be equal to sleep time for a plot), divide it by 1000
+    # to get ms and parse out the performance in percentage and write it to a temp file for plotting
+    cat ${file[$plot]} |grep -v "^#" |awk '{printf "%lu %.1f\n",$2/1000, $6}' >$dir/data_$plot
+
+    if [ $plot -eq 0 ];then
+       echo -n "plot " >> $dir/plot_script.gpl
+    fi
+    echo -n "\"$dir/data_$plot\" title \"${title[$plot]}\" with lines" >> $dir/plot_script.gpl
+    if [ $(($plot + 1)) -ne $plots ];then
+       echo -n ", " >> $dir/plot_script.gpl
+    fi
+done
+echo >> $dir/plot_script.gpl
+
+gnuplot $dir/plot_script.gpl
+rm -r $dir
\ No newline at end of file
diff --git a/tools/power/cpupower/bench/cpufreq-bench_script.sh b/tools/power/cpupower/bench/cpufreq-bench_script.sh
new file mode 100644 (file)
index 0000000..de20d2a
--- /dev/null
@@ -0,0 +1,101 @@
+#!/bin/bash
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+# Author/Copyright(c): 2009, Thomas Renninger <trenn@suse.de>, Novell Inc.
+
+# Ondemand up_threshold and sampling rate test script for cpufreq-bench
+# mircobenchmark.
+# Modify the general variables at the top or extend or copy out parts
+# if you want to test other things
+#
+
+# Default with latest kernels is 95, before micro account patches
+# it was 80, cmp. with git commit 808009131046b62ac434dbc796
+UP_THRESHOLD="60 80 95"
+# Depending on the kernel and the HW sampling rate could be restricted
+# and cannot be set that low...
+# E.g. before git commit cef9615a853ebc4972084f7 one could only set
+# min sampling rate of 80000 if CONFIG_HZ=250
+SAMPLING_RATE="20000 80000"
+
+function measure()
+{
+    local -i up_threshold_set
+    local -i sampling_rate_set
+
+    for up_threshold in $UP_THRESHOLD;do
+       for sampling_rate in $SAMPLING_RATE;do
+           # Set values in sysfs
+           echo $up_threshold >/sys/devices/system/cpu/cpu0/cpufreq/ondemand/up_threshold
+           echo $sampling_rate >/sys/devices/system/cpu/cpu0/cpufreq/ondemand/sampling_rate
+           up_threshold_set=$(cat /sys/devices/system/cpu/cpu0/cpufreq/ondemand/up_threshold)
+           sampling_rate_set=$(cat /sys/devices/system/cpu/cpu0/cpufreq/ondemand/sampling_rate)
+
+           # Verify set values in sysfs
+           if [ ${up_threshold_set} -eq ${up_threshold} ];then
+               echo "up_threshold: $up_threshold, set in sysfs: ${up_threshold_set}"
+           else
+               echo "WARNING: Tried to set up_threshold: $up_threshold, set in sysfs: ${up_threshold_set}"
+           fi
+           if [ ${sampling_rate_set} -eq ${sampling_rate} ];then
+               echo "sampling_rate: $sampling_rate, set in sysfs: ${sampling_rate_set}"
+           else
+               echo "WARNING: Tried to set sampling_rate: $sampling_rate, set in sysfs: ${sampling_rate_set}"
+           fi
+
+           # Benchmark
+           cpufreq-bench -o /var/log/cpufreq-bench/up_threshold_${up_threshold}_sampling_rate_${sampling_rate}
+       done
+    done
+}
+
+function create_plots()
+{
+    local command
+
+    for up_threshold in $UP_THRESHOLD;do
+       command="cpufreq-bench_plot.sh -o \"sampling_rate_${SAMPLING_RATE}_up_threshold_${up_threshold}\" -t \"Ondemand sampling_rate: ${SAMPLING_RATE} comparison - Up_threshold: $up_threshold %\""
+       for sampling_rate in $SAMPLING_RATE;do
+           command="${command} /var/log/cpufreq-bench/up_threshold_${up_threshold}_sampling_rate_${sampling_rate}/* \"sampling_rate = $sampling_rate\""
+       done
+       echo $command
+       eval "$command"
+       echo
+    done
+
+    for sampling_rate in $SAMPLING_RATE;do
+       command="cpufreq-bench_plot.sh -o \"up_threshold_${UP_THRESHOLD}_sampling_rate_${sampling_rate}\" -t \"Ondemand up_threshold: ${UP_THRESHOLD} % comparison - sampling_rate: $sampling_rate\""
+       for up_threshold in $UP_THRESHOLD;do
+           command="${command} /var/log/cpufreq-bench/up_threshold_${up_threshold}_sampling_rate_${sampling_rate}/* \"up_threshold = $up_threshold\""
+       done
+       echo $command
+       eval "$command"
+       echo
+    done
+
+    command="cpufreq-bench_plot.sh -o \"up_threshold_${UP_THRESHOLD}_sampling_rate_${SAMPLING_RATE}\" -t \"Ondemand up_threshold: ${UP_THRESHOLD} and sampling_rate ${SAMPLING_RATE} comparison\""
+    for sampling_rate in $SAMPLING_RATE;do
+       for up_threshold in $UP_THRESHOLD;do
+           command="${command} /var/log/cpufreq-bench/up_threshold_${up_threshold}_sampling_rate_${sampling_rate}/* \"up_threshold = $up_threshold - sampling_rate = $sampling_rate\""
+       done
+    done
+    echo "$command"
+    eval "$command"
+}
+
+measure
+create_plots
\ No newline at end of file
diff --git a/tools/power/cpupower/bench/example.cfg b/tools/power/cpupower/bench/example.cfg
new file mode 100644 (file)
index 0000000..f91f643
--- /dev/null
@@ -0,0 +1,11 @@
+sleep = 50000
+load = 50000
+cpu = 0
+priority = LOW
+output = /var/log/cpufreq-bench
+sleep_step = 50000
+load_step = 50000
+cycles = 20
+rounds = 40
+verbose = 0
+governor = ondemand
diff --git a/tools/power/cpupower/bench/main.c b/tools/power/cpupower/bench/main.c
new file mode 100644 (file)
index 0000000..2491031
--- /dev/null
@@ -0,0 +1,202 @@
+/*  cpufreq-bench CPUFreq microbenchmark
+ *
+ *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+
+#include "config.h"
+#include "system.h"
+#include "benchmark.h"
+
+static struct option long_options[] = {
+       {"output",      1,      0,      'o'},
+       {"sleep",       1,      0,      's'},
+       {"load",        1,      0,      'l'},
+       {"verbose",     0,      0,      'v'},
+       {"cpu",         1,      0,      'c'},
+       {"governor",    1,      0,      'g'},
+       {"prio",        1,      0,      'p'},
+       {"file",        1,      0,      'f'},
+       {"cycles",      1,      0,      'n'},
+       {"rounds",      1,      0,      'r'},
+       {"load-step",   1,      0,      'x'},
+       {"sleep-step",  1,      0,      'y'},
+       {"help",        0,      0,      'h'},
+       {0, 0, 0, 0}
+};
+
+/*******************************************************************
+ usage
+*******************************************************************/
+
+void usage()
+{
+       printf("usage: ./bench\n");
+       printf("Options:\n");
+       printf(" -l, --load=<long int>\t\tinitial load time in us\n");
+       printf(" -s, --sleep=<long int>\t\tinitial sleep time in us\n");
+       printf(" -x, --load-step=<long int>\ttime to be added to load time, in us\n");
+       printf(" -y, --sleep-step=<long int>\ttime to be added to sleep time, in us\n");
+       printf(" -c, --cpu=<cpu #>\t\t\tCPU Nr. to use, starting at 0\n");
+       printf(" -p, --prio=<priority>\t\t\tscheduler priority, HIGH, LOW or DEFAULT\n");
+       printf(" -g, --governor=<governor>\t\tcpufreq governor to test\n");
+       printf(" -n, --cycles=<int>\t\t\tload/sleep cycles\n");
+       printf(" -r, --rounds<int>\t\t\tload/sleep rounds\n");
+       printf(" -f, --file=<configfile>\t\tconfig file to use\n");
+       printf(" -o, --output=<dir>\t\t\toutput path. Filename will be OUTPUTPATH/benchmark_TIMESTAMP.log\n");
+       printf(" -v, --verbose\t\t\t\tverbose output on/off\n");
+       printf(" -h, --help\t\t\t\tPrint this help screen\n");
+       exit(1);
+}
+
+/*******************************************************************
+ main
+*******************************************************************/
+
+int main(int argc, char **argv)
+{
+       int c;
+       int option_index = 0;
+       struct config *config = NULL;
+
+       config = prepare_default_config();
+
+       if (config == NULL)
+               return EXIT_FAILURE;
+
+       while (1) {
+               c = getopt_long (argc, argv, "hg:o:s:l:vc:p:f:n:r:x:y:",
+                               long_options, &option_index);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'o':
+                       if (config->output != NULL)
+                               fclose(config->output);
+
+                       config->output = prepare_output(optarg);
+
+                       if (config->output == NULL)
+                               return EXIT_FAILURE;
+
+                       dprintf("user output path -> %s\n", optarg);
+                       break;
+               case 's':
+                       sscanf(optarg, "%li", &config->sleep);
+                       dprintf("user sleep time -> %s\n", optarg);
+                       break;
+               case 'l':
+                       sscanf(optarg, "%li", &config->load);
+                       dprintf("user load time -> %s\n", optarg);
+                       break;
+               case 'c':
+                       sscanf(optarg, "%u", &config->cpu);
+                       dprintf("user cpu -> %s\n", optarg);
+                       break;
+               case 'g':
+                       strncpy(config->governor, optarg, 14);
+                       dprintf("user governor -> %s\n", optarg);
+                       break;
+               case 'p':
+                       if (string_to_prio(optarg) != SCHED_ERR) {
+                               config->prio = string_to_prio(optarg);
+                               dprintf("user prio -> %s\n", optarg);
+                       } else {
+                               if (config != NULL) {
+                                       if (config->output != NULL)
+                                               fclose(config->output);
+                                       free(config);
+                               }
+                               usage();
+                       }
+                       break;
+               case 'n':
+                       sscanf(optarg, "%u", &config->cycles);
+                       dprintf("user cycles -> %s\n", optarg);
+                       break;
+               case 'r':
+                       sscanf(optarg, "%u", &config->rounds);
+                       dprintf("user rounds -> %s\n", optarg);
+                       break;
+               case 'x':
+                       sscanf(optarg, "%li", &config->load_step);
+                       dprintf("user load_step -> %s\n", optarg);
+                       break;
+               case 'y':
+                       sscanf(optarg, "%li", &config->sleep_step);
+                       dprintf("user sleep_step -> %s\n", optarg);
+                       break;
+               case 'f':
+                       if (prepare_config(optarg, config))
+                               return EXIT_FAILURE;
+                       break;
+               case 'v':
+                       config->verbose = 1;
+                       dprintf("verbose output enabled\n");
+                       break;
+               case 'h':
+               case '?':
+               default:
+                       if (config != NULL) {
+                               if (config->output != NULL)
+                                       fclose(config->output);
+                               free(config);
+                       }
+                       usage();
+               }
+       }
+
+       if (config->verbose) {
+               printf("starting benchmark with parameters:\n");
+               printf("config:\n\t"
+                      "sleep=%li\n\t"
+                      "load=%li\n\t"
+                      "sleep_step=%li\n\t"
+                      "load_step=%li\n\t"
+                      "cpu=%u\n\t"
+                      "cycles=%u\n\t"
+                      "rounds=%u\n\t"
+                      "governor=%s\n\n",
+                      config->sleep,
+                      config->load,
+                      config->sleep_step,
+                      config->load_step,
+                      config->cpu,
+                      config->cycles,
+                      config->rounds,
+                      config->governor);
+       }
+
+       prepare_user(config);
+       prepare_system(config);
+       start_benchmark(config);
+
+       if (config->output != stdout)
+               fclose(config->output);
+
+       free(config);
+
+       return EXIT_SUCCESS;
+}
+
diff --git a/tools/power/cpupower/bench/parse.c b/tools/power/cpupower/bench/parse.c
new file mode 100644 (file)
index 0000000..543bba1
--- /dev/null
@@ -0,0 +1,225 @@
+/*  cpufreq-bench CPUFreq microbenchmark
+ *
+ *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  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 <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+#include <dirent.h>
+
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "parse.h"
+#include "config.h"
+
+/**
+ * converts priority string to priority
+ *
+ * @param str string that represents a scheduler priority
+ *
+ * @retval priority
+ * @retval SCHED_ERR when the priority doesn't exit
+ **/
+
+enum sched_prio string_to_prio(const char *str)
+{
+       if (strncasecmp("high", str, strlen(str)) == 0)
+               return  SCHED_HIGH;
+       else if (strncasecmp("default", str, strlen(str)) == 0)
+               return SCHED_DEFAULT;
+       else if (strncasecmp("low", str, strlen(str)) == 0)
+               return SCHED_LOW;
+       else
+               return SCHED_ERR;
+}
+
+/**
+ * create and open logfile
+ *
+ * @param dir directory in which the logfile should be created
+ *
+ * @retval logfile on success
+ * @retval NULL when the file can't be created
+ **/
+
+FILE *prepare_output(const char *dirname)
+{
+       FILE *output = NULL;
+       int len;
+       char *filename;
+       struct utsname sysdata;
+       DIR *dir;
+
+       dir = opendir(dirname);
+       if (dir == NULL) {
+               if (mkdir(dirname, 0755)) {
+                       perror("mkdir");
+                       fprintf(stderr, "error: Cannot create dir %s\n",
+                               dirname);
+                       return NULL;
+               }
+       }
+
+       len = strlen(dirname) + 30;
+       filename = malloc(sizeof(char) * len);
+
+       if (uname(&sysdata) == 0) {
+               len += strlen(sysdata.nodename) + strlen(sysdata.release);
+               filename = realloc(filename, sizeof(char) * len);
+
+               if (filename == NULL) {
+                       perror("realloc");
+                       return NULL;
+               }
+
+               snprintf(filename, len - 1, "%s/benchmark_%s_%s_%li.log",
+                       dirname, sysdata.nodename, sysdata.release, time(NULL));
+       } else {
+               snprintf(filename, len - 1, "%s/benchmark_%li.log",
+                       dirname, time(NULL));
+       }
+
+       dprintf("logilename: %s\n", filename);
+
+       output = fopen(filename, "w+");
+       if (output == NULL) {
+               perror("fopen");
+               fprintf(stderr, "error: unable to open logfile\n");
+       }
+
+       fprintf(stdout, "Logfile: %s\n", filename);
+
+       free(filename);
+       fprintf(output, "#round load sleep performance powersave percentage\n");
+       return output;
+}
+
+/**
+ * returns the default config
+ *
+ * @retval default config on success
+ * @retval NULL when the output file can't be created
+ **/
+
+struct config *prepare_default_config()
+{
+       struct config *config = malloc(sizeof(struct config));
+
+       dprintf("loading defaults\n");
+
+       config->sleep = 500000;
+       config->load = 500000;
+       config->sleep_step = 500000;
+       config->load_step = 500000;
+       config->cycles = 5;
+       config->rounds = 50;
+       config->cpu = 0;
+       config->prio = SCHED_HIGH;
+       config->verbose = 0;
+       strncpy(config->governor, "ondemand", 8);
+
+       config->output = stdout;
+
+#ifdef DEFAULT_CONFIG_FILE
+       if (prepare_config(DEFAULT_CONFIG_FILE, config))
+               return NULL;
+#endif
+       return config;
+}
+
+/**
+ * parses config file and returns the config to the caller
+ *
+ * @param path config file name
+ *
+ * @retval 1 on error
+ * @retval 0 on success
+ **/
+
+int prepare_config(const char *path, struct config *config)
+{
+       size_t len = 0;
+       char *opt, *val, *line = NULL;
+       FILE *configfile = fopen(path, "r");
+
+       if (config == NULL) {
+               fprintf(stderr, "error: config is NULL\n");
+               return 1;
+       }
+
+       if (configfile == NULL) {
+               perror("fopen");
+               fprintf(stderr, "error: unable to read configfile\n");
+               free(config);
+               return 1;
+       }
+
+       while (getline(&line, &len, configfile) != -1) {
+               if (line[0] == '#' || line[0] == ' ')
+                       continue;
+
+               sscanf(line, "%as = %as", &opt, &val);
+
+               dprintf("parsing: %s -> %s\n", opt, val);
+
+               if (strncmp("sleep", opt, strlen(opt)) == 0)
+                       sscanf(val, "%li", &config->sleep);
+
+               else if (strncmp("load", opt, strlen(opt)) == 0)
+                       sscanf(val, "%li", &config->load);
+
+               else if (strncmp("load_step", opt, strlen(opt)) == 0)
+                       sscanf(val, "%li", &config->load_step);
+
+               else if (strncmp("sleep_step", opt, strlen(opt)) == 0)
+                       sscanf(val, "%li", &config->sleep_step);
+
+               else if (strncmp("cycles", opt, strlen(opt)) == 0)
+                       sscanf(val, "%u", &config->cycles);
+
+               else if (strncmp("rounds", opt, strlen(opt)) == 0)
+                       sscanf(val, "%u", &config->rounds);
+
+               else if (strncmp("verbose", opt, strlen(opt)) == 0)
+                       sscanf(val, "%u", &config->verbose);
+
+               else if (strncmp("output", opt, strlen(opt)) == 0)
+                       config->output = prepare_output(val); 
+
+               else if (strncmp("cpu", opt, strlen(opt)) == 0)
+                       sscanf(val, "%u", &config->cpu);
+
+               else if (strncmp("governor", opt, 14) == 0)
+                       strncpy(config->governor, val, 14);
+
+               else if (strncmp("priority", opt, strlen(opt)) == 0) {
+                       if (string_to_prio(val) != SCHED_ERR)
+                               config->prio = string_to_prio(val);
+               }
+       }
+
+       free(line);
+       free(opt);
+       free(val);
+
+       return 0;
+}
diff --git a/tools/power/cpupower/bench/parse.h b/tools/power/cpupower/bench/parse.h
new file mode 100644 (file)
index 0000000..a8dc632
--- /dev/null
@@ -0,0 +1,53 @@
+/*  cpufreq-bench CPUFreq microbenchmark
+ *
+ *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  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.
+ */
+
+/* struct that holds the required config parameters */
+struct config
+{
+       long sleep;             /* sleep time in µs */
+       long load;              /* load time in µs */
+       long sleep_step;        /* time value which changes the
+                                * sleep time after every round in µs */
+       long load_step;         /* time value which changes the
+                                * load time after every round in µs */
+       unsigned int cycles;    /* calculation cycles with the same sleep/load time */
+       unsigned int rounds;    /* calculation rounds with iterated sleep/load time */
+       unsigned int cpu;       /* cpu for which the affinity is set */
+       char governor[15];      /* cpufreq governor */
+       enum sched_prio         /* possible scheduler priorities */
+       {
+               SCHED_ERR = -1,
+               SCHED_HIGH,
+               SCHED_DEFAULT,
+               SCHED_LOW
+       } prio;
+
+       unsigned int verbose;   /* verbose output */
+       FILE *output;           /* logfile */
+       char *output_filename;  /* logfile name, must be freed at the end
+                                  if output != NULL and output != stdout*/
+};
+
+enum sched_prio string_to_prio(const char *str);
+
+FILE *prepare_output(const char *dir);
+
+int prepare_config(const char *path, struct config *config);
+struct config *prepare_default_config();
+
diff --git a/tools/power/cpupower/bench/system.c b/tools/power/cpupower/bench/system.c
new file mode 100644 (file)
index 0000000..f01e3f4
--- /dev/null
@@ -0,0 +1,191 @@
+/*  cpufreq-bench CPUFreq microbenchmark
+ *
+ *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  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 <stdio.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <sched.h>
+
+#include <cpufreq.h>
+
+#include "config.h"
+#include "system.h"
+
+/**
+ * returns time since epoch in µs
+ *
+ * @retval time
+ **/
+
+long long int get_time()
+{
+       struct timeval now;
+
+       gettimeofday(&now, NULL);
+
+       return (long long int)(now.tv_sec * 1000000LL + now.tv_usec);
+}
+
+/**
+ * sets the cpufreq governor
+ *
+ * @param governor cpufreq governor name
+ * @param cpu cpu for which the governor should be set
+ *
+ * @retval 0 on success
+ * @retval -1 when failed
+ **/
+
+int set_cpufreq_governor(char *governor, unsigned int cpu)
+{
+
+       dprintf("set %s as cpufreq governor\n", governor);
+
+       if (cpufreq_cpu_exists(cpu) != 0) {
+               perror("cpufreq_cpu_exists");
+               fprintf(stderr, "error: cpu %u does not exist\n", cpu);
+               return -1;
+       }
+
+       if (cpufreq_modify_policy_governor(cpu, governor) != 0) {
+               perror("cpufreq_modify_policy_governor");
+               fprintf(stderr, "error: unable to set %s governor\n", governor);
+               return -1;
+       }
+
+       return 0;
+}
+
+/**
+ * sets cpu affinity for the process
+ *
+ * @param cpu cpu# to which the affinity should be set
+ *
+ * @retval 0 on success
+ * @retval -1 when setting the affinity failed
+ **/
+
+int set_cpu_affinity(unsigned int cpu)
+{
+       cpu_set_t cpuset;
+
+       CPU_ZERO(&cpuset);
+       CPU_SET(cpu, &cpuset);
+
+       dprintf("set affinity to cpu #%u\n", cpu);
+
+       if (sched_setaffinity(getpid(), sizeof(cpu_set_t), &cpuset) < 0) {
+               perror("sched_setaffinity");
+               fprintf(stderr, "warning: unable to set cpu affinity\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+/**
+ * sets the process priority parameter
+ *
+ * @param priority priority value
+ *
+ * @retval 0 on success
+ * @retval -1 when setting the priority failed
+ **/
+
+int set_process_priority(int priority)
+{
+       struct sched_param param;
+
+       dprintf("set scheduler priority to %i\n", priority);
+
+       param.sched_priority = priority;
+
+       if (sched_setscheduler(0, SCHEDULER, &param) < 0) {
+               perror("sched_setscheduler");
+               fprintf(stderr, "warning: unable to set scheduler priority\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+/**
+ * notifies the user that the benchmark may run some time
+ *
+ * @param config benchmark config values
+ *
+ **/
+
+void prepare_user(const struct config *config)
+{
+       unsigned long sleep_time = 0;
+       unsigned long load_time = 0;
+       unsigned int round;
+
+       for (round = 0; round < config->rounds; round++) {
+               sleep_time +=  2 * config->cycles *
+                       (config->sleep + config->sleep_step * round);
+               load_time += 2 * config->cycles *
+                       (config->load + config->load_step * round) +
+                       (config->load + config->load_step * round * 4);
+       }
+
+       if (config->verbose || config->output != stdout)
+               printf("approx. test duration: %im\n",
+                      (int)((sleep_time + load_time) / 60000000));
+}
+
+/**
+ * sets up the cpu affinity and scheduler priority
+ *
+ * @param config benchmark config values
+ *
+ **/
+
+void prepare_system(const struct config *config)
+{
+       if (config->verbose)
+               printf("set cpu affinity to cpu #%u\n", config->cpu);
+
+       set_cpu_affinity(config->cpu);
+
+       switch (config->prio) {
+       case SCHED_HIGH:
+               if (config->verbose)
+                       printf("high priority condition requested\n");
+
+               set_process_priority(PRIORITY_HIGH);
+               break;
+       case SCHED_LOW:
+               if (config->verbose)
+                       printf("low priority condition requested\n");
+
+               set_process_priority(PRIORITY_LOW);
+               break;
+       default:
+               if (config->verbose)
+                       printf("default priority condition requested\n");
+
+               set_process_priority(PRIORITY_DEFAULT);
+       }
+}
+
diff --git a/tools/power/cpupower/bench/system.h b/tools/power/cpupower/bench/system.h
new file mode 100644 (file)
index 0000000..3a8c858
--- /dev/null
@@ -0,0 +1,29 @@
+/*  cpufreq-bench CPUFreq microbenchmark
+ *
+ *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  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 "parse.h"
+
+long long get_time();
+
+int set_cpufreq_governor(char *governor, unsigned int cpu);
+int set_cpu_affinity(unsigned int cpu);
+int set_process_priority(int priority);
+
+void prepare_user(const struct config *config);
+void prepare_system(const struct config *config);
diff --git a/tools/power/cpupower/debug/i386/Makefile b/tools/power/cpupower/debug/i386/Makefile
new file mode 100644 (file)
index 0000000..d08cc1e
--- /dev/null
@@ -0,0 +1,20 @@
+default: all
+
+centrino-decode: centrino-decode.c
+       $(CC) $(CFLAGS) -o centrino-decode centrino-decode.c
+
+dump_psb: dump_psb.c
+       $(CC) $(CFLAGS) -o dump_psb dump_psb.c
+
+intel_gsic: intel_gsic.c
+       $(CC) $(CFLAGS) -o intel_gsic -llrmi intel_gsic.c
+
+powernow-k8-decode: powernow-k8-decode.c
+       $(CC) $(CFLAGS) -o powernow-k8-decode powernow-k8-decode.c
+
+all: centrino-decode dump_psb intel_gsic powernow-k8-decode
+
+clean:
+       rm -rf centrino-decode dump_psb intel_gsic powernow-k8-decode
+
+.PHONY: all default clean
diff --git a/tools/power/cpupower/debug/i386/centrino-decode.c b/tools/power/cpupower/debug/i386/centrino-decode.c
new file mode 100644 (file)
index 0000000..7ef24cc
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ *  (C) 2003 - 2004  Dominik Brodowski <linux@dominikbrodowski.de>
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ * Based on code found in
+ * linux/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
+ * and originally developed by Jeremy Fitzhardinge.
+ *
+ * USAGE: simply run it to decode the current settings on CPU 0,
+ *       or pass the CPU number as argument, or pass the MSR content
+ *       as argument.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define MCPU   32
+
+#define MSR_IA32_PERF_STATUS   0x198
+
+static int rdmsr(unsigned int cpu, unsigned int msr,
+                unsigned int *lo, unsigned int *hi)
+{
+       int fd;
+       char file[20];
+       unsigned long long val;
+       int retval = -1;
+
+       *lo = *hi = 0;
+
+       if (cpu > MCPU)
+               goto err1;
+
+       sprintf(file, "/dev/cpu/%d/msr", cpu);
+       fd = open(file, O_RDONLY);
+
+       if (fd < 0)
+               goto err1;
+
+       if (lseek(fd, msr, SEEK_CUR) == -1)
+               goto err2;
+
+       if (read(fd, &val, 8) != 8)
+               goto err2;
+
+       *lo = (uint32_t )(val & 0xffffffffull);
+       *hi = (uint32_t )(val>>32 & 0xffffffffull);
+
+       retval = 0;
+err2:
+       close(fd);
+err1:
+       return retval;
+}
+
+static void decode (unsigned int msr)
+{
+       unsigned int multiplier;
+       unsigned int mv;
+
+       multiplier = ((msr >> 8) & 0xFF);
+
+       mv = (((msr & 0xFF) * 16) + 700);
+
+       printf("0x%x means multiplier %d @ %d mV\n", msr, multiplier, mv);
+}
+
+static int decode_live(unsigned int cpu)
+{
+       unsigned int lo, hi;
+       int err;
+
+       err = rdmsr(cpu, MSR_IA32_PERF_STATUS, &lo, &hi);
+
+       if (err) {
+               printf("can't get MSR_IA32_PERF_STATUS for cpu %d\n", cpu);
+               printf("Possible trouble: you don't run an Enhanced SpeedStep capable cpu\n");
+               printf("or you are not root, or the msr driver is not present\n");
+               return 1;
+       }
+
+       decode(lo);
+
+       return 0;
+}
+
+int main (int argc, char **argv)
+{
+       unsigned int cpu, mode = 0;
+
+       if (argc < 2)
+               cpu = 0;
+       else {
+               cpu = strtoul(argv[1], NULL, 0);
+               if (cpu >= MCPU)
+                       mode = 1;
+       }
+
+       if (mode)
+               decode(cpu);
+       else
+               decode_live(cpu);
+
+       return 0;
+}
diff --git a/tools/power/cpupower/debug/i386/dump_psb.c b/tools/power/cpupower/debug/i386/dump_psb.c
new file mode 100644 (file)
index 0000000..8d6a475
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * dump_psb. (c) 2004, Dave Jones, Red Hat Inc.
+ * Licensed under the GPL v2.
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define _GNU_SOURCE
+#include <getopt.h>
+
+#include <sys/mman.h>
+
+#define LEN (0x100000 - 0xc0000)
+#define OFFSET (0xc0000)
+
+#ifndef __packed
+#define __packed __attribute((packed))
+#endif
+
+static long relevant;
+
+static const int fid_to_mult[32] = {
+       110, 115, 120, 125, 50, 55, 60, 65,
+       70, 75, 80, 85, 90, 95, 100, 105,
+       30, 190, 40, 200, 130, 135, 140, 210,
+       150, 225, 160, 165, 170, 180, -1, -1,
+};
+
+static const int vid_to_voltage[32] = {
+       2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650,
+       1600, 1550, 1500, 1450, 1400, 1350, 1300, 0,
+       1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100,
+       1075, 1050, 1024, 1000, 975, 950, 925, 0,
+};
+
+struct psb_header {
+       char signature[10];
+       u_char version;
+       u_char flags;
+       u_short settlingtime;
+       u_char res1;
+       u_char numpst;
+} __packed;
+
+struct pst_header {
+       u_int32_t cpuid;
+       u_char fsb;
+       u_char maxfid;
+       u_char startvid;
+       u_char numpstates;
+} __packed;
+
+static u_int fsb;
+static u_int sgtc;
+
+static int
+decode_pst(char *p, int npstates)
+{
+       int i;
+       int freq, fid, vid;
+
+       for (i = 0; i < npstates; ++i) {
+               fid = *p++;
+               vid = *p++;
+               freq = 100 * fid_to_mult[fid] * fsb;
+
+               printf("   %2d %8dkHz  FID %02x (%2d.%01d)  VID %02x (%4dmV)\n",
+                      i,
+                      freq,
+                      fid, fid_to_mult[fid]/10, fid_to_mult[fid]%10,
+                      vid, vid_to_voltage[vid]);
+       }
+
+       return 0;
+}
+
+static
+void decode_psb(char *p, int numpst)
+{
+       int i;
+       struct psb_header *psb;
+       struct pst_header *pst;
+
+       psb = (struct psb_header*) p;
+
+       if (psb->version != 0x12)
+               return;
+
+       printf("PSB version: %hhx flags: %hhx settling time %hhuus res1 %hhx num pst %hhu\n",
+                       psb->version,
+                       psb->flags,
+                       psb->settlingtime,
+                       psb->res1,
+                       psb->numpst);
+       sgtc = psb->settlingtime * 100;
+
+       if (sgtc < 10000)
+               sgtc = 10000;
+
+       p = ((char *) psb) + sizeof(struct psb_header);
+
+       if (numpst < 0)
+               numpst = psb->numpst;
+       else
+               printf("Overriding number of pst :%d\n", numpst);
+
+       for (i = 0; i < numpst; i++) {
+               pst = (struct pst_header*) p;
+
+               if (relevant != 0) {
+                       if (relevant!= pst->cpuid)
+                               goto next_one;
+               }
+
+               printf("  PST %d  cpuid %.3x fsb %hhu mfid %hhx svid %hhx numberstates %hhu\n",
+                               i+1,
+                               pst->cpuid,
+                               pst->fsb,
+                               pst->maxfid,
+                               pst->startvid,
+                               pst->numpstates);
+
+               fsb = pst->fsb;
+               decode_pst(p + sizeof(struct pst_header), pst->numpstates);
+
+next_one:
+               p += sizeof(struct pst_header) + 2*pst->numpstates;
+       }
+
+}
+
+static struct option info_opts[] = {
+       {.name = "numpst",      .has_arg=no_argument,   .flag=NULL, .val='n'},
+};
+
+void print_help(void)
+{
+       printf ("Usage: dump_psb [options]\n");
+       printf ("Options:\n");
+       printf ("  -n, --numpst     Set number of PST tables to scan\n");
+       printf ("  -r, --relevant   Only display PSTs relevant to cpuid N\n");
+}
+
+int
+main(int argc, char *argv[])
+{
+       int fd;
+       int numpst=-1;
+       int ret=0, cont=1;
+       char *mem = NULL;
+       char *p;
+
+       do {
+               ret = getopt_long(argc, argv, "hr:n:", info_opts, NULL);
+               switch (ret){
+               case '?':
+               case 'h':
+                       print_help();
+                       cont = 0;
+                       break;
+               case 'r':
+                       relevant = strtol(optarg, NULL, 16);
+                       break;
+               case 'n':
+                       numpst = strtol(optarg, NULL, 10);
+                       break;
+               case -1:
+                       cont = 0;
+                       break;
+               }
+
+       } while(cont);
+
+       fd = open("/dev/mem", O_RDONLY);
+       if (fd < 0) {
+               printf ("Couldn't open /dev/mem. Are you root?\n");
+               exit(1);
+       }
+
+       mem = mmap(mem, 0x100000 - 0xc0000, PROT_READ, MAP_SHARED, fd, 0xc0000);
+       close(fd);
+
+       for (p = mem; p - mem < LEN; p+=16) {
+               if (memcmp(p, "AMDK7PNOW!", 10) == 0) {
+                       decode_psb(p, numpst);
+                       break;
+               }
+       }
+
+       munmap(mem, LEN);
+       return 0;
+}
diff --git a/tools/power/cpupower/debug/i386/intel_gsic.c b/tools/power/cpupower/debug/i386/intel_gsic.c
new file mode 100644 (file)
index 0000000..53f5293
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ *  (C) 2003  Bruno Ducrot
+ *  (C) 2004  Dominik Brodowski <linux@dominikbrodowski.de>
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ * Based on code found in
+ * linux/include/asm-i386/ist.h and linux/arch/i386/kernel/setup.c
+ * and originally developed by Andy Grover <andrew.grover@intel.com>
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <lrmi.h>
+
+int main (void)
+{
+       struct LRMI_regs        r;
+       int                     retval;
+
+       if (!LRMI_init())
+               return 0;
+
+       memset(&r, 0, sizeof(r));
+
+       r.eax = 0x0000E980;
+       r.edx = 0x47534943;
+
+       retval = LRMI_int(0x15, &r);
+
+       if (!retval) {
+               printf("Failed!\n");
+               return 0;
+       }
+       if (r.eax == 0x47534943) {
+               printf("BIOS supports GSIC call:\n");
+               printf("\tsignature: %c%c%c%c\n",
+                      (r.eax >> 24) & 0xff,
+                      (r.eax >> 16) & 0xff,
+                      (r.eax >> 8) & 0xff,
+                      (r.eax) & 0xff);
+               printf("\tcommand port = 0x%.4x\n",
+                      r.ebx & 0xffff);
+               printf("\tcommand =      0x%.4x\n",
+                      (r.ebx >> 16) & 0xffff);
+               printf("\tevent port =   0x%.8x\n", r.ecx);
+               printf("\tflags =        0x%.8x\n", r.edx);
+               if (((r.ebx >> 16) & 0xffff) != 0x82) {
+                       printf("non-default command value. If speedstep-smi "
+                              "doesn't work out of the box,\nyou may want to "
+                              "try out the default value by passing "
+                              "smi_cmd=0x82 to the module\n ON YOUR OWN "
+                              "RISK.\n");
+               }
+               if ((r.ebx & 0xffff) != 0xb2) {
+                       printf("non-default command port. If speedstep-smi "
+                              "doesn't work out of the box,\nyou may want to "
+                              "try out the default value by passing "
+                              "smi_port=0x82 to the module\n ON YOUR OWN "
+                              "RISK.\n");
+               }
+       } else {
+               printf("BIOS DOES NOT support GSIC call.  Dumping registers anyway:\n");
+               printf("eax = 0x%.8x\n", r.eax);
+               printf("ebx = 0x%.8x\n", r.ebx);
+               printf("ecx = 0x%.8x\n", r.ecx);
+               printf("edx = 0x%.8x\n", r.edx);
+               printf("Note also that some BIOS do not support the initial "
+                      "GSIC call, but the newer\nspeeedstep-smi driver may "
+                      "work.\nFor this, you need to pass some arguments to "
+                      "the speedstep-smi driver:\n");
+               printf("\tsmi_cmd=0x?? smi_port=0x?? smi_sig=1\n");
+               printf("\nUnfortunately, you have to know what exactly are "
+                      "smi_cmd and smi_port, and this\nis system "
+                      "dependant.\n");
+       }
+       return 1;
+}
diff --git a/tools/power/cpupower/debug/i386/powernow-k8-decode.c b/tools/power/cpupower/debug/i386/powernow-k8-decode.c
new file mode 100644 (file)
index 0000000..638a6b3
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ *  (C) 2004 Bruno Ducrot <ducrot@poupinou.org>
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ * Based on code found in
+ * linux/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
+ * and originally developed by Paul Devriendt
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define MCPU 32
+
+#define MSR_FIDVID_STATUS      0xc0010042
+
+#define MSR_S_HI_CURRENT_VID   0x0000001f
+#define MSR_S_LO_CURRENT_FID   0x0000003f
+
+static int get_fidvid(uint32_t cpu, uint32_t *fid, uint32_t *vid)
+{
+       int err = 1;
+       uint64_t msr = 0;
+       int fd;
+       char file[20];
+
+       if (cpu > MCPU)
+               goto out;
+
+       sprintf(file, "/dev/cpu/%d/msr", cpu);
+
+       fd = open(file, O_RDONLY);
+       if (fd < 0)
+               goto out;
+       lseek(fd, MSR_FIDVID_STATUS, SEEK_CUR);
+       if (read(fd, &msr, 8) != 8)
+               goto err1;
+
+       *fid = ((uint32_t )(msr & 0xffffffffull)) & MSR_S_LO_CURRENT_FID;
+       *vid = ((uint32_t )(msr>>32 & 0xffffffffull)) & MSR_S_HI_CURRENT_VID;
+       err = 0;
+err1:
+       close(fd);
+out:
+       return err;
+}
+
+
+/* Return a frequency in MHz, given an input fid */
+static uint32_t find_freq_from_fid(uint32_t fid)
+{
+       return 800 + (fid * 100);
+}
+
+/* Return a voltage in miliVolts, given an input vid */
+static uint32_t find_millivolts_from_vid(uint32_t vid)
+{
+       return 1550-vid*25;
+}
+
+int main (int argc, char *argv[])
+{
+       int err;
+       int cpu;
+       uint32_t fid, vid;
+
+       if (argc < 2)
+               cpu = 0;
+       else
+               cpu = strtoul(argv[1], NULL, 0);
+
+       err = get_fidvid(cpu, &fid, &vid);
+
+       if (err) {
+               printf("can't get fid, vid from MSR\n");
+               printf("Possible trouble: you don't run a powernow-k8 capable cpu\n");
+               printf("or you are not root, or the msr driver is not present\n");
+               exit(1);
+       }
+
+       
+       printf("cpu %d currently at %d MHz and %d mV\n",
+                       cpu,
+                       find_freq_from_fid(fid),
+                       find_millivolts_from_vid(vid));
+       
+       return 0;
+}
diff --git a/tools/power/cpupower/debug/kernel/Makefile b/tools/power/cpupower/debug/kernel/Makefile
new file mode 100644 (file)
index 0000000..96b146f
--- /dev/null
@@ -0,0 +1,23 @@
+obj-m  :=
+
+KDIR   := /lib/modules/$(shell uname -r)/build
+PWD            := $(shell pwd)
+KMISC   := /lib/modules/$(shell uname -r)/cpufrequtils/
+
+ifeq ("$(CONFIG_X86_TSC)", "y")
+  obj-m         += cpufreq-test_tsc.o
+endif
+
+default:
+       $(MAKE) -C $(KDIR) M=$(PWD)
+
+clean:
+       - rm -rf *.o *.ko .tmp-versions .*.cmd .*.mod.* *.mod.c
+       - rm -rf .tmp_versions* Module.symvers modules.order
+
+install: default
+       install -d $(KMISC)
+       install -m 644 -c *.ko $(KMISC)
+       /sbin/depmod -a
+
+all:   default
diff --git a/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c b/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c
new file mode 100644 (file)
index 0000000..66cace6
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * test module to check whether the TSC-based delay routine continues
+ * to work properly after cpufreq transitions. Needs ACPI to work
+ * properly.
+ *
+ * Based partly on the Power Management Timer (PMTMR) code to be found
+ * in arch/i386/kernel/timers/timer_pm.c on recent 2.6. kernels, especially
+ * code written by John Stultz. The read_pmtmr function was copied verbatim
+ * from that file.
+ *
+ * (C) 2004 Dominik Brodowski
+ *
+ * To use:
+ * 1.) pass clock=tsc to the kernel on your bootloader
+ * 2.) modprobe this module (it'll fail)
+ * 3.) change CPU frequency
+ * 4.) modprobe this module again
+ * 5.) if the third value, "diff_pmtmr", changes between 2. and 4., the
+ *     TSC-based delay routine on the Linux kernel does not correctly
+ *     handle the cpufreq transition. Please report this to
+ *     cpufreq@vger.kernel.org
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+static int pm_tmr_ioport = 0;
+
+/*helper function to safely read acpi pm timesource*/
+static u32 read_pmtmr(void)
+{
+       u32 v1=0,v2=0,v3=0;
+       /* It has been reported that because of various broken
+        * chipsets (ICH4, PIIX4 and PIIX4E) where the ACPI PM time
+        * source is not latched, so you must read it multiple
+        * times to insure a safe value is read.
+        */
+       do {
+               v1 = inl(pm_tmr_ioport);
+               v2 = inl(pm_tmr_ioport);
+               v3 = inl(pm_tmr_ioport);
+       } while ((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1)
+                || (v3 > v1 && v3 < v2));
+
+       /* mask the output to 24 bits */
+       return (v2 & 0xFFFFFF);
+}
+
+static int __init cpufreq_test_tsc(void)
+{
+       u32 now, then, diff;
+       u64 now_tsc, then_tsc, diff_tsc;
+       int i;
+
+       /* the following code snipped is copied from arch/x86/kernel/acpi/boot.c
+          of Linux v2.6.25. */
+
+       /* detect the location of the ACPI PM Timer */
+       if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) {
+               /* FADT rev. 2 */
+               if (acpi_gbl_FADT.xpm_timer_block.space_id !=
+                   ACPI_ADR_SPACE_SYSTEM_IO)
+                       return 0;
+
+               pm_tmr_ioport = acpi_gbl_FADT.xpm_timer_block.address;
+               /*
+                * "X" fields are optional extensions to the original V1.0
+                * fields, so we must selectively expand V1.0 fields if the
+                * corresponding X field is zero.
+                */
+               if (!pm_tmr_ioport)
+                       pm_tmr_ioport = acpi_gbl_FADT.pm_timer_block;
+       } else {
+               /* FADT rev. 1 */
+               pm_tmr_ioport = acpi_gbl_FADT.pm_timer_block;
+       }
+
+       printk(KERN_DEBUG "start--> \n");
+       then = read_pmtmr();
+        rdtscll(then_tsc);
+       for (i=0;i<20;i++) {
+               mdelay(100);
+               now = read_pmtmr();
+               rdtscll(now_tsc);
+               diff = (now - then) & 0xFFFFFF;
+               diff_tsc = now_tsc - then_tsc;
+               printk(KERN_DEBUG "t1: %08u t2: %08u diff_pmtmr: %08u diff_tsc: %016llu\n", then, now, diff, diff_tsc);
+               then = now;
+               then_tsc = now_tsc;
+       }
+       printk(KERN_DEBUG "<-- end \n");
+       return -ENODEV;
+}
+
+static void __exit cpufreq_none(void)
+{
+       return;
+}
+
+module_init(cpufreq_test_tsc)
+module_exit(cpufreq_none)
+
+
+MODULE_AUTHOR("Dominik Brodowski");
+MODULE_DESCRIPTION("Verify the TSC cpufreq notifier working correctly -- needs ACPI-enabled system");
+MODULE_LICENSE ("GPL");
diff --git a/tools/power/cpupower/debug/x86_64/Makefile b/tools/power/cpupower/debug/x86_64/Makefile
new file mode 100644 (file)
index 0000000..dbf1399
--- /dev/null
@@ -0,0 +1,14 @@
+default: all
+
+centrino-decode: centrino-decode.c
+       $(CC) $(CFLAGS) -o centrino-decode centrino-decode.c
+
+powernow-k8-decode: powernow-k8-decode.c
+       $(CC) $(CFLAGS) -o powernow-k8-decode powernow-k8-decode.c
+
+all: centrino-decode powernow-k8-decode
+
+clean:
+       rm -rf centrino-decode powernow-k8-decode
+
+.PHONY: all default clean
diff --git a/tools/power/cpupower/debug/x86_64/centrino-decode.c b/tools/power/cpupower/debug/x86_64/centrino-decode.c
new file mode 120000 (symlink)
index 0000000..26fb3f1
--- /dev/null
@@ -0,0 +1 @@
+../i386/centrino-decode.c
\ No newline at end of file
diff --git a/tools/power/cpupower/debug/x86_64/powernow-k8-decode.c b/tools/power/cpupower/debug/x86_64/powernow-k8-decode.c
new file mode 120000 (symlink)
index 0000000..eb30c79
--- /dev/null
@@ -0,0 +1 @@
+../i386/powernow-k8-decode.c
\ No newline at end of file
diff --git a/tools/power/cpupower/lib/cpufreq.c b/tools/power/cpupower/lib/cpufreq.c
new file mode 100644 (file)
index 0000000..d961101
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ */
+
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cpufreq.h"
+#include "sysfs.h"
+
+int cpufreq_cpu_exists(unsigned int cpu)
+{
+       return sysfs_cpu_exists(cpu);
+}
+
+unsigned long cpufreq_get_freq_kernel(unsigned int cpu)
+{
+       return sysfs_get_freq_kernel(cpu);
+}
+
+unsigned long cpufreq_get_freq_hardware(unsigned int cpu)
+{
+       return sysfs_get_freq_hardware(cpu);
+}
+
+unsigned long cpufreq_get_transition_latency(unsigned int cpu)
+{
+       return sysfs_get_freq_transition_latency(cpu);
+}
+
+int cpufreq_get_hardware_limits(unsigned int cpu,
+                               unsigned long *min,
+                               unsigned long *max)
+{
+       if ((!min) || (!max))
+               return -EINVAL;
+       return sysfs_get_freq_hardware_limits(cpu, min, max);
+}
+
+char *cpufreq_get_driver(unsigned int cpu)
+{
+       return sysfs_get_freq_driver(cpu);
+}
+
+void cpufreq_put_driver(char *ptr)
+{
+       if (!ptr)
+               return;
+       free(ptr);
+}
+
+struct cpufreq_policy *cpufreq_get_policy(unsigned int cpu)
+{
+       return sysfs_get_freq_policy(cpu);
+}
+
+void cpufreq_put_policy(struct cpufreq_policy *policy)
+{
+       if ((!policy) || (!policy->governor))
+               return;
+
+       free(policy->governor);
+       policy->governor = NULL;
+       free(policy);
+}
+
+struct cpufreq_available_governors *cpufreq_get_available_governors(unsigned
+                                                               int cpu)
+{
+       return sysfs_get_freq_available_governors(cpu);
+}
+
+void cpufreq_put_available_governors(struct cpufreq_available_governors *any)
+{
+       struct cpufreq_available_governors *tmp, *next;
+
+       if (!any)
+               return;
+
+       tmp = any->first;
+       while (tmp) {
+               next = tmp->next;
+               if (tmp->governor)
+                       free(tmp->governor);
+               free(tmp);
+               tmp = next;
+       }
+}
+
+
+struct cpufreq_available_frequencies
+*cpufreq_get_available_frequencies(unsigned int cpu)
+{
+       return sysfs_get_available_frequencies(cpu);
+}
+
+void cpufreq_put_available_frequencies(struct cpufreq_available_frequencies
+                               *any) {
+       struct cpufreq_available_frequencies *tmp, *next;
+
+       if (!any)
+               return;
+
+       tmp = any->first;
+       while (tmp) {
+               next = tmp->next;
+               free(tmp);
+               tmp = next;
+       }
+}
+
+
+struct cpufreq_affected_cpus *cpufreq_get_affected_cpus(unsigned int cpu)
+{
+       return sysfs_get_freq_affected_cpus(cpu);
+}
+
+void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *any)
+{
+       struct cpufreq_affected_cpus *tmp, *next;
+
+       if (!any)
+               return;
+
+       tmp = any->first;
+       while (tmp) {
+               next = tmp->next;
+               free(tmp);
+               tmp = next;
+       }
+}
+
+
+struct cpufreq_affected_cpus *cpufreq_get_related_cpus(unsigned int cpu)
+{
+       return sysfs_get_freq_related_cpus(cpu);
+}
+
+void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *any)
+{
+       cpufreq_put_affected_cpus(any);
+}
+
+
+int cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy)
+{
+       if (!policy || !(policy->governor))
+               return -EINVAL;
+
+       return sysfs_set_freq_policy(cpu, policy);
+}
+
+
+int cpufreq_modify_policy_min(unsigned int cpu, unsigned long min_freq)
+{
+       return sysfs_modify_freq_policy_min(cpu, min_freq);
+}
+
+
+int cpufreq_modify_policy_max(unsigned int cpu, unsigned long max_freq)
+{
+       return sysfs_modify_freq_policy_max(cpu, max_freq);
+}
+
+
+int cpufreq_modify_policy_governor(unsigned int cpu, char *governor)
+{
+       if ((!governor) || (strlen(governor) > 19))
+               return -EINVAL;
+
+       return sysfs_modify_freq_policy_governor(cpu, governor);
+}
+
+int cpufreq_set_frequency(unsigned int cpu, unsigned long target_frequency)
+{
+       return sysfs_set_frequency(cpu, target_frequency);
+}
+
+struct cpufreq_stats *cpufreq_get_stats(unsigned int cpu,
+                                       unsigned long long *total_time)
+{
+       return sysfs_get_freq_stats(cpu, total_time);
+}
+
+void cpufreq_put_stats(struct cpufreq_stats *any)
+{
+       struct cpufreq_stats *tmp, *next;
+
+       if (!any)
+               return;
+
+       tmp = any->first;
+       while (tmp) {
+               next = tmp->next;
+               free(tmp);
+               tmp = next;
+       }
+}
+
+unsigned long cpufreq_get_transitions(unsigned int cpu)
+{
+       return sysfs_get_freq_transitions(cpu);
+}
diff --git a/tools/power/cpupower/lib/cpufreq.h b/tools/power/cpupower/lib/cpufreq.h
new file mode 100644 (file)
index 0000000..3aae8e7
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ *  cpufreq.h - definitions for libcpufreq
+ *
+ *  Copyright (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _CPUFREQ_H
+#define _CPUFREQ_H 1
+
+struct cpufreq_policy {
+       unsigned long min;
+       unsigned long max;
+       char *governor;
+};
+
+struct cpufreq_available_governors {
+       char *governor;
+       struct cpufreq_available_governors *next;
+       struct cpufreq_available_governors *first;
+};
+
+struct cpufreq_available_frequencies {
+       unsigned long frequency;
+       struct cpufreq_available_frequencies *next;
+       struct cpufreq_available_frequencies *first;
+};
+
+
+struct cpufreq_affected_cpus {
+       unsigned int cpu;
+       struct cpufreq_affected_cpus *next;
+       struct cpufreq_affected_cpus *first;
+};
+
+struct cpufreq_stats {
+       unsigned long frequency;
+       unsigned long long time_in_state;
+       struct cpufreq_stats *next;
+       struct cpufreq_stats *first;
+};
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * returns 0 if the specified CPU is present (it doesn't say
+ * whether it is online!), and an error value if not.
+ */
+
+extern int cpufreq_cpu_exists(unsigned int cpu);
+
+/* determine current CPU frequency
+ * - _kernel variant means kernel's opinion of CPU frequency
+ * - _hardware variant means actual hardware CPU frequency,
+ *    which is only available to root.
+ *
+ * returns 0 on failure, else frequency in kHz.
+ */
+
+extern unsigned long cpufreq_get_freq_kernel(unsigned int cpu);
+
+extern unsigned long cpufreq_get_freq_hardware(unsigned int cpu);
+
+#define cpufreq_get(cpu) cpufreq_get_freq_kernel(cpu);
+
+
+/* determine CPU transition latency
+ *
+ * returns 0 on failure, else transition latency in 10^(-9) s = nanoseconds
+ */
+extern unsigned long cpufreq_get_transition_latency(unsigned int cpu);
+
+
+/* determine hardware CPU frequency limits
+ *
+ * These may be limited further by thermal, energy or other
+ * considerations by cpufreq policy notifiers in the kernel.
+ */
+
+extern int cpufreq_get_hardware_limits(unsigned int cpu,
+                               unsigned long *min,
+                               unsigned long *max);
+
+
+/* determine CPUfreq driver used
+ *
+ * Remember to call cpufreq_put_driver when no longer needed
+ * to avoid memory leakage, please.
+ */
+
+extern char *cpufreq_get_driver(unsigned int cpu);
+
+extern void cpufreq_put_driver(char *ptr);
+
+
+/* determine CPUfreq policy currently used
+ *
+ * Remember to call cpufreq_put_policy when no longer needed
+ * to avoid memory leakage, please.
+ */
+
+
+extern struct cpufreq_policy *cpufreq_get_policy(unsigned int cpu);
+
+extern void cpufreq_put_policy(struct cpufreq_policy *policy);
+
+
+/* determine CPUfreq governors currently available
+ *
+ * may be modified by modprobe'ing or rmmod'ing other governors. Please
+ * free allocated memory by calling cpufreq_put_available_governors
+ * after use.
+ */
+
+
+extern struct cpufreq_available_governors
+*cpufreq_get_available_governors(unsigned int cpu);
+
+extern void cpufreq_put_available_governors(
+       struct cpufreq_available_governors *first);
+
+
+/* determine CPU frequency states available
+ *
+ * Only present on _some_ ->target() cpufreq drivers. For information purposes
+ * only. Please free allocated memory by calling
+ * cpufreq_put_available_frequencies after use.
+ */
+
+extern struct cpufreq_available_frequencies
+*cpufreq_get_available_frequencies(unsigned int cpu);
+
+extern void cpufreq_put_available_frequencies(
+               struct cpufreq_available_frequencies *first);
+
+
+/* determine affected CPUs
+ *
+ * Remember to call cpufreq_put_affected_cpus when no longer needed
+ * to avoid memory leakage, please.
+ */
+
+extern struct cpufreq_affected_cpus *cpufreq_get_affected_cpus(unsigned
+                                                       int cpu);
+
+extern void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *first);
+
+
+/* determine related CPUs
+ *
+ * Remember to call cpufreq_put_related_cpus when no longer needed
+ * to avoid memory leakage, please.
+ */
+
+extern struct cpufreq_affected_cpus *cpufreq_get_related_cpus(unsigned
+                                                       int cpu);
+
+extern void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *first);
+
+
+/* determine stats for cpufreq subsystem
+ *
+ * This is not available in all kernel versions or configurations.
+ */
+
+extern struct cpufreq_stats *cpufreq_get_stats(unsigned int cpu,
+                                       unsigned long long *total_time);
+
+extern void cpufreq_put_stats(struct cpufreq_stats *stats);
+
+extern unsigned long cpufreq_get_transitions(unsigned int cpu);
+
+
+/* set new cpufreq policy
+ *
+ * Tries to set the passed policy as new policy as close as possible,
+ * but results may differ depending e.g. on governors being available.
+ */
+
+extern int cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy);
+
+
+/* modify a policy by only changing min/max freq or governor
+ *
+ * Does not check whether result is what was intended.
+ */
+
+extern int cpufreq_modify_policy_min(unsigned int cpu, unsigned long min_freq);
+extern int cpufreq_modify_policy_max(unsigned int cpu, unsigned long max_freq);
+extern int cpufreq_modify_policy_governor(unsigned int cpu, char *governor);
+
+
+/* set a specific frequency
+ *
+ * Does only work if userspace governor can be used and no external
+ * interference (other calls to this function or to set/modify_policy)
+ * occurs. Also does not work on ->range() cpufreq drivers.
+ */
+
+extern int cpufreq_set_frequency(unsigned int cpu,
+                               unsigned long target_frequency);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CPUFREQ_H */
diff --git a/tools/power/cpupower/lib/sysfs.c b/tools/power/cpupower/lib/sysfs.c
new file mode 100644 (file)
index 0000000..870713a
--- /dev/null
@@ -0,0 +1,672 @@
+/*
+ *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "cpufreq.h"
+
+#define PATH_TO_CPU "/sys/devices/system/cpu/"
+#define MAX_LINE_LEN 4096
+#define SYSFS_PATH_MAX 255
+
+
+static unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen)
+{
+       int fd;
+       ssize_t numread;
+
+       fd = open(path, O_RDONLY);
+       if (fd == -1)
+               return 0;
+
+       numread = read(fd, buf, buflen - 1);
+       if (numread < 1) {
+               close(fd);
+               return 0;
+       }
+
+       buf[numread] = '\0';
+       close(fd);
+
+       return (unsigned int) numread;
+}
+
+
+/* CPUFREQ sysfs access **************************************************/
+
+/* helper function to read file from /sys into given buffer */
+/* fname is a relative path under "cpuX/cpufreq" dir */
+static unsigned int sysfs_cpufreq_read_file(unsigned int cpu, const char *fname,
+                                           char *buf, size_t buflen)
+{
+       char path[SYSFS_PATH_MAX];
+
+       snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s",
+                        cpu, fname);
+       return sysfs_read_file(path, buf, buflen);
+}
+
+/* helper function to write a new value to a /sys file */
+/* fname is a relative path under "cpuX/cpufreq" dir */
+static unsigned int sysfs_cpufreq_write_file(unsigned int cpu,
+                                            const char *fname,
+                                            const char *value, size_t len)
+{
+       char path[SYSFS_PATH_MAX];
+       int fd;
+       ssize_t numwrite;
+
+       snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s",
+                        cpu, fname);
+
+       fd = open(path, O_WRONLY);
+       if (fd == -1)
+               return 0;
+
+       numwrite = write(fd, value, len);
+       if (numwrite < 1) {
+               close(fd);
+               return 0;
+       }
+
+       close(fd);
+
+       return (unsigned int) numwrite;
+}
+
+/* read access to files which contain one numeric value */
+
+enum cpufreq_value {
+       CPUINFO_CUR_FREQ,
+       CPUINFO_MIN_FREQ,
+       CPUINFO_MAX_FREQ,
+       CPUINFO_LATENCY,
+       SCALING_CUR_FREQ,
+       SCALING_MIN_FREQ,
+       SCALING_MAX_FREQ,
+       STATS_NUM_TRANSITIONS,
+       MAX_CPUFREQ_VALUE_READ_FILES
+};
+
+static const char *cpufreq_value_files[MAX_CPUFREQ_VALUE_READ_FILES] = {
+       [CPUINFO_CUR_FREQ] = "cpuinfo_cur_freq",
+       [CPUINFO_MIN_FREQ] = "cpuinfo_min_freq",
+       [CPUINFO_MAX_FREQ] = "cpuinfo_max_freq",
+       [CPUINFO_LATENCY]  = "cpuinfo_transition_latency",
+       [SCALING_CUR_FREQ] = "scaling_cur_freq",
+       [SCALING_MIN_FREQ] = "scaling_min_freq",
+       [SCALING_MAX_FREQ] = "scaling_max_freq",
+       [STATS_NUM_TRANSITIONS] = "stats/total_trans"
+};
+
+
+static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu,
+                                                enum cpufreq_value which)
+{
+       unsigned long value;
+       unsigned int len;
+       char linebuf[MAX_LINE_LEN];
+       char *endp;
+
+       if (which >= MAX_CPUFREQ_VALUE_READ_FILES)
+               return 0;
+
+       len = sysfs_cpufreq_read_file(cpu, cpufreq_value_files[which],
+                               linebuf, sizeof(linebuf));
+
+       if (len == 0)
+               return 0;
+
+       value = strtoul(linebuf, &endp, 0);
+
+       if (endp == linebuf || errno == ERANGE)
+               return 0;
+
+       return value;
+}
+
+/* read access to files which contain one string */
+
+enum cpufreq_string {
+       SCALING_DRIVER,
+       SCALING_GOVERNOR,
+       MAX_CPUFREQ_STRING_FILES
+};
+
+static const char *cpufreq_string_files[MAX_CPUFREQ_STRING_FILES] = {
+       [SCALING_DRIVER] = "scaling_driver",
+       [SCALING_GOVERNOR] = "scaling_governor",
+};
+
+
+static char *sysfs_cpufreq_get_one_string(unsigned int cpu,
+                                          enum cpufreq_string which)
+{
+       char linebuf[MAX_LINE_LEN];
+       char *result;
+       unsigned int len;
+
+       if (which >= MAX_CPUFREQ_STRING_FILES)
+               return NULL;
+
+       len = sysfs_cpufreq_read_file(cpu, cpufreq_string_files[which],
+                               linebuf, sizeof(linebuf));
+       if (len == 0)
+               return NULL;
+
+       result = strdup(linebuf);
+       if (result == NULL)
+               return NULL;
+
+       if (result[strlen(result) - 1] == '\n')
+               result[strlen(result) - 1] = '\0';
+
+       return result;
+}
+
+/* write access */
+
+enum cpufreq_write {
+       WRITE_SCALING_MIN_FREQ,
+       WRITE_SCALING_MAX_FREQ,
+       WRITE_SCALING_GOVERNOR,
+       WRITE_SCALING_SET_SPEED,
+       MAX_CPUFREQ_WRITE_FILES
+};
+
+static const char *cpufreq_write_files[MAX_CPUFREQ_WRITE_FILES] = {
+       [WRITE_SCALING_MIN_FREQ] = "scaling_min_freq",
+       [WRITE_SCALING_MAX_FREQ] = "scaling_max_freq",
+       [WRITE_SCALING_GOVERNOR] = "scaling_governor",
+       [WRITE_SCALING_SET_SPEED] = "scaling_setspeed",
+};
+
+static int sysfs_cpufreq_write_one_value(unsigned int cpu,
+                                        enum cpufreq_write which,
+                                        const char *new_value, size_t len)
+{
+       if (which >= MAX_CPUFREQ_WRITE_FILES)
+               return 0;
+
+       if (sysfs_cpufreq_write_file(cpu, cpufreq_write_files[which],
+                                       new_value, len) != len)
+               return -ENODEV;
+
+       return 0;
+};
+
+unsigned long sysfs_get_freq_kernel(unsigned int cpu)
+{
+       return sysfs_cpufreq_get_one_value(cpu, SCALING_CUR_FREQ);
+}
+
+unsigned long sysfs_get_freq_hardware(unsigned int cpu)
+{
+       return sysfs_cpufreq_get_one_value(cpu, CPUINFO_CUR_FREQ);
+}
+
+unsigned long sysfs_get_freq_transition_latency(unsigned int cpu)
+{
+       return sysfs_cpufreq_get_one_value(cpu, CPUINFO_LATENCY);
+}
+
+int sysfs_get_freq_hardware_limits(unsigned int cpu,
+                             unsigned long *min,
+                             unsigned long *max)
+{
+       if ((!min) || (!max))
+               return -EINVAL;
+
+       *min = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MIN_FREQ);
+       if (!*min)
+               return -ENODEV;
+
+       *max = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MAX_FREQ);
+       if (!*max)
+               return -ENODEV;
+
+       return 0;
+}
+
+char *sysfs_get_freq_driver(unsigned int cpu)
+{
+       return sysfs_cpufreq_get_one_string(cpu, SCALING_DRIVER);
+}
+
+struct cpufreq_policy *sysfs_get_freq_policy(unsigned int cpu)
+{
+       struct cpufreq_policy *policy;
+
+       policy = malloc(sizeof(struct cpufreq_policy));
+       if (!policy)
+               return NULL;
+
+       policy->governor = sysfs_cpufreq_get_one_string(cpu, SCALING_GOVERNOR);
+       if (!policy->governor) {
+               free(policy);
+               return NULL;
+       }
+       policy->min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ);
+       policy->max = sysfs_cpufreq_get_one_value(cpu, SCALING_MAX_FREQ);
+       if ((!policy->min) || (!policy->max)) {
+               free(policy->governor);
+               free(policy);
+               return NULL;
+       }
+
+       return policy;
+}
+
+struct cpufreq_available_governors *
+sysfs_get_freq_available_governors(unsigned int cpu) {
+       struct cpufreq_available_governors *first = NULL;
+       struct cpufreq_available_governors *current = NULL;
+       char linebuf[MAX_LINE_LEN];
+       unsigned int pos, i;
+       unsigned int len;
+
+       len = sysfs_cpufreq_read_file(cpu, "scaling_available_governors",
+                               linebuf, sizeof(linebuf));
+       if (len == 0)
+               return NULL;
+
+       pos = 0;
+       for (i = 0; i < len; i++) {
+               if (linebuf[i] == ' ' || linebuf[i] == '\n') {
+                       if (i - pos < 2)
+                               continue;
+                       if (current) {
+                               current->next = malloc(sizeof(*current));
+                               if (!current->next)
+                                       goto error_out;
+                               current = current->next;
+                       } else {
+                               first = malloc(sizeof(*first));
+                               if (!first)
+                                       goto error_out;
+                               current = first;
+                       }
+                       current->first = first;
+                       current->next = NULL;
+
+                       current->governor = malloc(i - pos + 1);
+                       if (!current->governor)
+                               goto error_out;
+
+                       memcpy(current->governor, linebuf + pos, i - pos);
+                       current->governor[i - pos] = '\0';
+                       pos = i + 1;
+               }
+       }
+
+       return first;
+
+ error_out:
+       while (first) {
+               current = first->next;
+               if (first->governor)
+                       free(first->governor);
+               free(first);
+               first = current;
+       }
+       return NULL;
+}
+
+
+struct cpufreq_available_frequencies *
+sysfs_get_available_frequencies(unsigned int cpu) {
+       struct cpufreq_available_frequencies *first = NULL;
+       struct cpufreq_available_frequencies *current = NULL;
+       char one_value[SYSFS_PATH_MAX];
+       char linebuf[MAX_LINE_LEN];
+       unsigned int pos, i;
+       unsigned int len;
+
+       len = sysfs_cpufreq_read_file(cpu, "scaling_available_frequencies",
+                               linebuf, sizeof(linebuf));
+       if (len == 0)
+               return NULL;
+
+       pos = 0;
+       for (i = 0; i < len; i++) {
+               if (linebuf[i] == ' ' || linebuf[i] == '\n') {
+                       if (i - pos < 2)
+                               continue;
+                       if (i - pos >= SYSFS_PATH_MAX)
+                               goto error_out;
+                       if (current) {
+                               current->next = malloc(sizeof(*current));
+                               if (!current->next)
+                                       goto error_out;
+                               current = current->next;
+                       } else {
+                               first = malloc(sizeof(*first));
+                               if (!first)
+                                       goto error_out;
+                               current = first;
+                       }
+                       current->first = first;
+                       current->next = NULL;
+
+                       memcpy(one_value, linebuf + pos, i - pos);
+                       one_value[i - pos] = '\0';
+                       if (sscanf(one_value, "%lu", &current->frequency) != 1)
+                               goto error_out;
+
+                       pos = i + 1;
+               }
+       }
+
+       return first;
+
+ error_out:
+       while (first) {
+               current = first->next;
+               free(first);
+               first = current;
+       }
+       return NULL;
+}
+
+static struct cpufreq_affected_cpus *sysfs_get_cpu_list(unsigned int cpu,
+                                                       const char *file)
+{
+       struct cpufreq_affected_cpus *first = NULL;
+       struct cpufreq_affected_cpus *current = NULL;
+       char one_value[SYSFS_PATH_MAX];
+       char linebuf[MAX_LINE_LEN];
+       unsigned int pos, i;
+       unsigned int len;
+
+       len = sysfs_cpufreq_read_file(cpu, file, linebuf, sizeof(linebuf));
+       if (len == 0)
+               return NULL;
+
+       pos = 0;
+       for (i = 0; i < len; i++) {
+               if (i == len || linebuf[i] == ' ' || linebuf[i] == '\n') {
+                       if (i - pos  < 1)
+                               continue;
+                       if (i - pos >= SYSFS_PATH_MAX)
+                               goto error_out;
+                       if (current) {
+                               current->next = malloc(sizeof(*current));
+                               if (!current->next)
+                                       goto error_out;
+                               current = current->next;
+                       } else {
+                               first = malloc(sizeof(*first));
+                               if (!first)
+                                       goto error_out;
+                               current = first;
+                       }
+                       current->first = first;
+                       current->next = NULL;
+
+                       memcpy(one_value, linebuf + pos, i - pos);
+                       one_value[i - pos] = '\0';
+
+                       if (sscanf(one_value, "%u", &current->cpu) != 1)
+                               goto error_out;
+
+                       pos = i + 1;
+               }
+       }
+
+       return first;
+
+ error_out:
+       while (first) {
+               current = first->next;
+               free(first);
+               first = current;
+       }
+       return NULL;
+}
+
+struct cpufreq_affected_cpus *sysfs_get_freq_affected_cpus(unsigned int cpu)
+{
+       return sysfs_get_cpu_list(cpu, "affected_cpus");
+}
+
+struct cpufreq_affected_cpus *sysfs_get_freq_related_cpus(unsigned int cpu)
+{
+       return sysfs_get_cpu_list(cpu, "related_cpus");
+}
+
+struct cpufreq_stats *sysfs_get_freq_stats(unsigned int cpu,
+                                       unsigned long long *total_time) {
+       struct cpufreq_stats *first = NULL;
+       struct cpufreq_stats *current = NULL;
+       char one_value[SYSFS_PATH_MAX];
+       char linebuf[MAX_LINE_LEN];
+       unsigned int pos, i;
+       unsigned int len;
+
+       len = sysfs_cpufreq_read_file(cpu, "stats/time_in_state",
+                               linebuf, sizeof(linebuf));
+       if (len == 0)
+               return NULL;
+
+       *total_time = 0;
+       pos = 0;
+       for (i = 0; i < len; i++) {
+               if (i == strlen(linebuf) || linebuf[i] == '\n') {
+                       if (i - pos < 2)
+                               continue;
+                       if ((i - pos) >= SYSFS_PATH_MAX)
+                               goto error_out;
+                       if (current) {
+                               current->next = malloc(sizeof(*current));
+                               if (!current->next)
+                                       goto error_out;
+                               current = current->next;
+                       } else {
+                               first = malloc(sizeof(*first));
+                               if (!first)
+                                       goto error_out;
+                               current = first;
+                       }
+                       current->first = first;
+                       current->next = NULL;
+
+                       memcpy(one_value, linebuf + pos, i - pos);
+                       one_value[i - pos] = '\0';
+                       if (sscanf(one_value, "%lu %llu",
+                                       &current->frequency,
+                                       &current->time_in_state) != 2)
+                               goto error_out;
+
+                       *total_time = *total_time + current->time_in_state;
+                       pos = i + 1;
+               }
+       }
+
+       return first;
+
+ error_out:
+       while (first) {
+               current = first->next;
+               free(first);
+               first = current;
+       }
+       return NULL;
+}
+
+unsigned long sysfs_get_freq_transitions(unsigned int cpu)
+{
+       return sysfs_cpufreq_get_one_value(cpu, STATS_NUM_TRANSITIONS);
+}
+
+static int verify_gov(char *new_gov, char *passed_gov)
+{
+       unsigned int i, j = 0;
+
+       if (!passed_gov || (strlen(passed_gov) > 19))
+               return -EINVAL;
+
+       strncpy(new_gov, passed_gov, 20);
+       for (i = 0; i < 20; i++) {
+               if (j) {
+                       new_gov[i] = '\0';
+                       continue;
+               }
+               if ((new_gov[i] >= 'a') && (new_gov[i] <= 'z'))
+                       continue;
+
+               if ((new_gov[i] >= 'A') && (new_gov[i] <= 'Z'))
+                       continue;
+
+               if (new_gov[i] == '-')
+                       continue;
+
+               if (new_gov[i] == '_')
+                       continue;
+
+               if (new_gov[i] == '\0') {
+                       j = 1;
+                       continue;
+               }
+               return -EINVAL;
+       }
+       new_gov[19] = '\0';
+       return 0;
+}
+
+int sysfs_modify_freq_policy_governor(unsigned int cpu, char *governor)
+{
+       char new_gov[SYSFS_PATH_MAX];
+
+       if (!governor)
+               return -EINVAL;
+
+       if (verify_gov(new_gov, governor))
+               return -EINVAL;
+
+       return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR,
+                                            new_gov, strlen(new_gov));
+};
+
+int sysfs_modify_freq_policy_max(unsigned int cpu, unsigned long max_freq)
+{
+       char value[SYSFS_PATH_MAX];
+
+       snprintf(value, SYSFS_PATH_MAX, "%lu", max_freq);
+
+       return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ,
+                                            value, strlen(value));
+};
+
+
+int sysfs_modify_freq_policy_min(unsigned int cpu, unsigned long min_freq)
+{
+       char value[SYSFS_PATH_MAX];
+
+       snprintf(value, SYSFS_PATH_MAX, "%lu", min_freq);
+
+       return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ,
+                                            value, strlen(value));
+};
+
+
+int sysfs_set_freq_policy(unsigned int cpu, struct cpufreq_policy *policy)
+{
+       char min[SYSFS_PATH_MAX];
+       char max[SYSFS_PATH_MAX];
+       char gov[SYSFS_PATH_MAX];
+       int ret;
+       unsigned long old_min;
+       int write_max_first;
+
+       if (!policy || !(policy->governor))
+               return -EINVAL;
+
+       if (policy->max < policy->min)
+               return -EINVAL;
+
+       if (verify_gov(gov, policy->governor))
+               return -EINVAL;
+
+       snprintf(min, SYSFS_PATH_MAX, "%lu", policy->min);
+       snprintf(max, SYSFS_PATH_MAX, "%lu", policy->max);
+
+       old_min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ);
+       write_max_first = (old_min && (policy->max < old_min) ? 0 : 1);
+
+       if (write_max_first) {
+               ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ,
+                                                   max, strlen(max));
+               if (ret)
+                       return ret;
+       }
+
+       ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ, min,
+                                           strlen(min));
+       if (ret)
+               return ret;
+
+       if (!write_max_first) {
+               ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ,
+                                                   max, strlen(max));
+               if (ret)
+                       return ret;
+       }
+
+       return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR,
+                                            gov, strlen(gov));
+}
+
+int sysfs_set_frequency(unsigned int cpu, unsigned long target_frequency)
+{
+       struct cpufreq_policy *pol = sysfs_get_freq_policy(cpu);
+       char userspace_gov[] = "userspace";
+       char freq[SYSFS_PATH_MAX];
+       int ret;
+
+       if (!pol)
+               return -ENODEV;
+
+       if (strncmp(pol->governor, userspace_gov, 9) != 0) {
+               ret = sysfs_modify_freq_policy_governor(cpu, userspace_gov);
+               if (ret) {
+                       cpufreq_put_policy(pol);
+                       return ret;
+               }
+       }
+
+       cpufreq_put_policy(pol);
+
+       snprintf(freq, SYSFS_PATH_MAX, "%lu", target_frequency);
+
+       return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_SET_SPEED,
+                                            freq, strlen(freq));
+}
+
+/* CPUFREQ sysfs access **************************************************/
+
+/* General sysfs access **************************************************/
+int sysfs_cpu_exists(unsigned int cpu)
+{
+       char file[SYSFS_PATH_MAX];
+       struct stat statbuf;
+
+       snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/", cpu);
+
+       if (stat(file, &statbuf) != 0)
+               return -ENOSYS;
+
+       return S_ISDIR(statbuf.st_mode) ? 0 : -ENOSYS;
+}
+
+/* General sysfs access **************************************************/
diff --git a/tools/power/cpupower/lib/sysfs.h b/tools/power/cpupower/lib/sysfs.h
new file mode 100644 (file)
index 0000000..c76a5e0
--- /dev/null
@@ -0,0 +1,31 @@
+/* General */
+extern unsigned int sysfs_cpu_exists(unsigned int cpu);
+
+/* CPUfreq */
+extern unsigned long sysfs_get_freq_kernel(unsigned int cpu);
+extern unsigned long sysfs_get_freq_hardware(unsigned int cpu);
+extern unsigned long sysfs_get_freq_transition_latency(unsigned int cpu);
+extern int sysfs_get_freq_hardware_limits(unsigned int cpu,
+                                       unsigned long *min, unsigned long *max);
+extern char *sysfs_get_freq_driver(unsigned int cpu);
+extern struct cpufreq_policy *sysfs_get_freq_policy(unsigned int cpu);
+extern struct cpufreq_available_governors *sysfs_get_freq_available_governors(
+       unsigned int cpu);
+extern struct cpufreq_available_frequencies *sysfs_get_available_frequencies(
+       unsigned int cpu);
+extern struct cpufreq_affected_cpus *sysfs_get_freq_affected_cpus(
+       unsigned int cpu);
+extern struct cpufreq_affected_cpus *sysfs_get_freq_related_cpus(
+       unsigned int cpu);
+extern struct cpufreq_stats *sysfs_get_freq_stats(unsigned int cpu,
+                                               unsigned long long *total_time);
+extern unsigned long sysfs_get_freq_transitions(unsigned int cpu);
+extern int sysfs_set_freq_policy(unsigned int cpu,
+                               struct cpufreq_policy *policy);
+extern int sysfs_modify_freq_policy_min(unsigned int cpu,
+                                       unsigned long min_freq);
+extern int sysfs_modify_freq_policy_max(unsigned int cpu,
+                                       unsigned long max_freq);
+extern int sysfs_modify_freq_policy_governor(unsigned int cpu, char *governor);
+extern int sysfs_set_frequency(unsigned int cpu,
+                       unsigned long target_frequency);
diff --git a/tools/power/cpupower/man/cpupower-frequency-info.1 b/tools/power/cpupower/man/cpupower-frequency-info.1
new file mode 100644 (file)
index 0000000..3194811
--- /dev/null
@@ -0,0 +1,76 @@
+.TH "cpufreq-info" "1" "0.1" "Mattia Dongili" ""
+.SH "NAME"
+.LP 
+cpufreq\-info \- Utility to retrieve cpufreq kernel information
+.SH "SYNTAX"
+.LP 
+cpufreq\-info [\fIoptions\fP]
+.SH "DESCRIPTION"
+.LP 
+A small tool which prints out cpufreq information helpful to developers and interested users.
+.SH "OPTIONS"
+.LP 
+.TP  
+\fB\-e\fR \fB\-\-debug\fR
+Prints out debug information.
+.TP  
+\fB\-f\fR \fB\-\-freq\fR
+Get frequency the CPU currently runs at, according to the cpufreq core.
+.TP  
+\fB\-w\fR \fB\-\-hwfreq\fR
+Get frequency the CPU currently runs at, by reading it from hardware (only available to root).
+.TP  
+\fB\-l\fR \fB\-\-hwlimits\fR
+Determine the minimum and maximum CPU frequency allowed.
+.TP  
+\fB\-d\fR \fB\-\-driver\fR
+Determines the used cpufreq kernel driver.
+.TP  
+\fB\-p\fR \fB\-\-policy\fR
+Gets the currently used cpufreq policy.
+.TP  
+\fB\-g\fR \fB\-\-governors\fR
+Determines available cpufreq governors.
+.TP  
+\fB\-a\fR \fB\-\-related\-cpus\fR
+Determines which CPUs run at the same hardware frequency.
+.TP  
+\fB\-a\fR \fB\-\-affected\-cpus\fR
+Determines which CPUs need to have their frequency coordinated by software.
+.TP  
+\fB\-s\fR \fB\-\-stats\fR
+Shows cpufreq statistics if available.
+.TP  
+\fB\-y\fR \fB\-\-latency\fR
+Determines the maximum latency on CPU frequency changes.
+.TP  
+\fB\-o\fR \fB\-\-proc\fR
+Prints out information like provided by the /proc/cpufreq interface in 2.4. and early 2.6. kernels.
+.TP  
+\fB\-m\fR \fB\-\-human\fR
+human\-readable output for the \-f, \-w, \-s and \-y parameters.
+.TP  
+\fB\-h\fR \fB\-\-help\fR
+Prints out the help screen.
+.SH "REMARKS"
+.LP 
+By default only values of core zero are displayed. How to display settings of
+other cores is described in the cpupower(1) manpage in the \-\-cpu option section.
+.LP 
+You can't specify more than one of the output specific options \-o \-e \-a \-g \-p \-d \-l \-w \-f \-y.
+.LP 
+You also can't specify the \-o option combined with the \-c option.
+.SH "FILES"
+.nf 
+\fI/sys/devices/system/cpu/cpu*/cpufreq/\fP  
+\fI/proc/cpufreq\fP (deprecated) 
+\fI/proc/sys/cpu/\fP (deprecated)
+.fi 
+.SH "AUTHORS"
+.nf
+Dominik Brodowski <linux@brodo.de> \- author 
+Mattia Dongili<malattia@gmail.com> \- first autolibtoolization
+.fi
+.SH "SEE ALSO"
+.LP 
+cpupower\-frequency\-set(1), cpupower(1)
diff --git a/tools/power/cpupower/man/cpupower-frequency-set.1 b/tools/power/cpupower/man/cpupower-frequency-set.1
new file mode 100644 (file)
index 0000000..26e3e13
--- /dev/null
@@ -0,0 +1,54 @@
+.TH "cpufreq-set" "1" "0.1" "Mattia Dongili" ""
+.SH "NAME"
+.LP 
+cpufreq\-set \- A small tool which allows to modify cpufreq settings.
+.SH "SYNTAX"
+.LP 
+cpufreq\-set [\fIoptions\fP]
+.SH "DESCRIPTION"
+.LP 
+cpufreq\-set allows you to modify cpufreq settings without having to type e.g. "/sys/devices/system/cpu/cpu0/cpufreq/scaling_set_speed" all the time.
+.SH "OPTIONS"
+.LP 
+.TP 
+\fB\-d\fR \fB\-\-min\fR <FREQ>
+new minimum CPU frequency the governor may select.
+.TP 
+\fB\-u\fR \fB\-\-max\fR <FREQ>
+new maximum CPU frequency the governor may select.
+.TP 
+\fB\-g\fR \fB\-\-governor\fR <GOV>
+new cpufreq governor.
+.TP 
+\fB\-f\fR \fB\-\-freq\fR <FREQ>
+specific frequency to be set. Requires userspace governor to be available and loaded.
+.TP 
+\fB\-r\fR \fB\-\-related\fR
+modify all hardware-related CPUs at the same time
+.TP 
+\fB\-h\fR \fB\-\-help\fR
+Prints out the help screen.
+.SH "REMARKS"
+.LP 
+By default values are applied on all cores. How to modify single core
+configurations is described in the cpupower(1) manpage in the \-\-cpu option section.
+.LP 
+The \-f FREQ, \-\-freq FREQ parameter cannot be combined with any other parameter.
+.LP 
+FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz by postfixing the value with the wanted unit name, without any space (frequency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).
+.LP 
+On Linux kernels up to 2.6.29, the \-r or \-\-related parameter is ignored.
+.SH "FILES" 
+.nf
+\fI/sys/devices/system/cpu/cpu*/cpufreq/\fP  
+\fI/proc/cpufreq\fP (deprecated) 
+\fI/proc/sys/cpu/\fP (deprecated)
+.fi 
+.SH "AUTHORS"
+.nf 
+Dominik Brodowski <linux@brodo.de> \- author 
+Mattia Dongili<malattia@gmail.com> \- first autolibtoolization
+.fi
+.SH "SEE ALSO"
+.LP 
+cpupower\-frequency\-info(1), cpupower(1)
diff --git a/tools/power/cpupower/man/cpupower-info.1 b/tools/power/cpupower/man/cpupower-info.1
new file mode 100644 (file)
index 0000000..58e2119
--- /dev/null
@@ -0,0 +1,19 @@
+.TH CPUPOWER\-INFO "1" "22/02/2011" "" "cpupower Manual"
+.SH NAME
+cpupower\-info \- Shows processor power related kernel or hardware configurations
+.SH SYNOPSIS
+.ft B
+.B cpupower info [ \-b ] [ \-s ] [ \-m ]
+
+.SH DESCRIPTION
+\fBcpupower info \fP shows kernel configurations or processor hardware
+registers affecting processor power saving policies.
+
+Some options are platform wide, some affect single cores. By default values
+of core zero are displayed only. cpupower --cpu all cpuinfo will show the
+settings of all cores, see cpupower(1) how to choose specific cores.
+
+.SH "SEE ALSO"
+Options are described in detail in:
+
+cpupower(1), cpupower-set(1)
diff --git a/tools/power/cpupower/man/cpupower-monitor.1 b/tools/power/cpupower/man/cpupower-monitor.1
new file mode 100644 (file)
index 0000000..d5cfa26
--- /dev/null
@@ -0,0 +1,179 @@
+.TH CPUPOWER\-MONITOR "1" "22/02/2011" "" "cpupower Manual"
+.SH NAME
+cpupower\-monitor \- Report processor frequency and idle statistics
+.SH SYNOPSIS
+.ft B
+.B cpupower monitor
+.RB "\-l"
+
+.B cpupower monitor
+.RB [ "\-m <mon1>," [ "<mon2>,..." ] ]
+.RB [ "\-i seconds" ]
+.br
+.B cpupower monitor
+.RB [ "\-m <mon1>," [ "<mon2>,..." ] ]
+.RB command
+.br
+.SH DESCRIPTION
+\fBcpupower-monitor \fP reports processor topology, frequency and idle power
+state statistics. Either \fBcommand\fP is forked and
+statistics are printed upon its completion, or statistics are printed periodically.
+
+\fBcpupower-monitor \fP implements independent processor sleep state and
+frequency counters. Some are retrieved from kernel statistics, some are
+directly reading out hardware registers. Use \-l to get an overview which are
+supported on your system.
+
+.SH Options
+.PP
+\-l
+.RS 4
+List available monitors on your system. Additional details about each monitor
+are shown:
+.RS 2
+.IP \(bu
+The name in quotation marks which can be passed to the \-m parameter.
+.IP \(bu
+The number of different counters the monitor supports in brackets.
+.IP \(bu
+The amount of time in seconds the counters might overflow, due to
+implementation constraints.
+.IP \(bu
+The name and a description of each counter and its processor hierarchy level
+coverage in square brackets:
+.RS 4
+.IP \(bu
+[T] \-> Thread
+.IP \(bu
+[C] \-> Core
+.IP \(bu
+[P] \-> Processor Package (Socket)
+.IP \(bu
+[M] \-> Machine/Platform wide counter
+.RE
+.RE
+.RE
+.PP
+\-m <mon1>,<mon2>,...
+.RS 4
+Only display specific monitors. Use the monitor string(s) provided by \-l option.
+.RE
+.PP
+\-i seconds
+.RS 4
+Measure intervall.
+.RE
+.PP
+command
+.RS 4
+Measure idle and frequency characteristics of an arbitrary command/workload.
+The executable \fBcommand\fP is forked and upon its exit, statistics gathered since it was
+forked are displayed.
+.RE
+.PP
+\-v
+.RS 4
+Increase verbosity if the binary was compiled with the DEBUG option set.
+.RE
+
+.SH MONITOR DESCRIPTIONS
+.SS "Idle_Stats"
+Shows statistics of the cpuidle kernel subsystem. Values are retrieved from
+/sys/devices/system/cpu/cpu*/cpuidle/state*/.
+The kernel updates these values every time an idle state is entered or
+left. Therefore there can be some inaccuracy when cores are in an idle
+state for some time when the measure starts or ends. In worst case it can happen
+that one core stayed in an idle state for the whole measure time and the idle
+state usage time as exported by the kernel did not get updated. In this case
+a state residency of 0 percent is shown while it was 100.
+
+.SS "Mperf"
+The name comes from the aperf/mperf (average and maximum) MSR registers used
+which are available on recent X86 processors. It shows the average frequency
+(including boost frequencies).
+The fact that on all recent hardware the mperf timer stops ticking in any idle
+state it is also used to show C0 (processor is active) and Cx (processor is in
+any sleep state) times. These counters do not have the inaccuracy restrictions
+the "Idle_Stats" counters may show.
+May work poorly on Linux-2.6.20 through 2.6.29, as the \fBacpi-cpufreq \fP
+kernel frequency driver periodically cleared aperf/mperf registers in those
+kernels.
+
+.SS "Nehalem" "SandyBridge"
+Intel Core and Package sleep state counters.
+Threads (hyperthreaded cores) may not be able to enter deeper core states if
+its sibling is utilized.
+Deepest package sleep states may in reality show up as machine/platform wide
+sleep states and can only be entered if all cores are idle. Look up Intel
+manuals (some are provided in the References section) for further details.
+
+.SS "Ontario" "Liano"
+AMD laptop and desktop processor (family 12h and 14h) sleep state counters.
+The registers are accessed via PCI and therefore can still be read out while
+cores have been offlined.
+
+There is one special counter: NBP1 (North Bridge P1).
+This one always returns 0 or 1, depending on whether the North Bridge P1
+power state got entered at least once during measure time.
+Being able to enter NBP1 state also depends on graphics power management.
+Therefore this counter can be used to verify whether the graphics' driver
+power management is working as expected.
+
+.SH EXAMPLES
+
+cpupower monitor -l" may show:
+.RS 4
+Monitor "Mperf" (3 states) \- Might overflow after 922000000 s
+
+   ...
+
+Monitor "Idle_Stats" (3 states) \- Might overflow after 4294967295 s
+
+   ...
+
+.RE
+cpupower monitor \-m "Idle_Stats,Mperf" scp /tmp/test /nfs/tmp
+
+Monitor the scp command, show both Mperf and Idle_Stats states counter
+statistics, but in exchanged order.
+
+
+
+.RE
+Be careful that the typical command to fully utilize one CPU by doing:
+
+cpupower monitor cat /dev/zero >/dev/null
+
+Does not work as expected, because the measured output is redirected to
+/dev/null. This could get workarounded by putting the line into an own, tiny
+shell script. Hit CTRL\-c to terminate the command and get the measure output
+displayed.
+
+.SH REFERENCES
+"BIOS and Kernel Developer’s Guide (BKDG) for AMD Family 14h Processors"
+http://support.amd.com/us/Processor_TechDocs/43170.pdf
+
+"Intel® Turbo Boost Technology
+in Intel® Core™ Microarchitecture (Nehalem) Based Processors"
+http://download.intel.com/design/processor/applnots/320354.pdf
+
+"Intel® 64 and IA-32 Architectures Software Developer's Manual
+Volume 3B: System Programming Guide"
+http://www.intel.com/products/processor/manuals
+
+.SH FILES
+.ta
+.nf
+/dev/cpu/*/msr
+/sys/devices/system/cpu/cpu*/cpuidle/state*/.
+.fi
+
+.SH "SEE ALSO"
+powertop(8), msr(4), vmstat(8)
+.PP
+.SH AUTHORS
+.nf
+Written by Thomas Renninger <trenn@suse.de>
+
+Nehalem, SandyBridge monitors and command passing
+based on turbostat.8 from Len Brown <len.brown@intel.com>
diff --git a/tools/power/cpupower/man/cpupower-set.1 b/tools/power/cpupower/man/cpupower-set.1
new file mode 100644 (file)
index 0000000..c4954a9
--- /dev/null
@@ -0,0 +1,103 @@
+.TH CPUPOWER\-SET "1" "22/02/2011" "" "cpupower Manual"
+.SH NAME
+cpupower\-set \- Set processor power related kernel or hardware configurations
+.SH SYNOPSIS
+.ft B
+.B cpupower set [ \-b VAL ] [ \-s VAL ] [ \-m VAL ]
+
+
+.SH DESCRIPTION
+\fBcpupower set \fP sets kernel configurations or directly accesses hardware
+registers affecting processor power saving policies.
+
+Some options are platform wide, some affect single cores. By default values
+are applied on all cores. How to modify single core configurations is
+described in the cpupower(1) manpage in the \-\-cpu option section. Whether an
+option affects the whole system or can be applied to individual cores is
+described in the Options sections.
+
+Use \fBcpupower info \fP to read out current settings and whether they are
+supported on the system at all.
+
+.SH Options
+.PP
+\-\-perf-bias, \-b
+.RS 4
+Sets a register on supported Intel processore which allows software to convey
+its policy for the relative importance of performance versus energy savings to
+the  processor.
+
+The range of valid numbers is 0-15, where 0 is maximum
+performance and 15 is maximum energy efficiency.
+
+The processor uses this information in model-specific ways
+when it must select trade-offs between performance and
+energy efficiency.
+
+This policy hint does not supersede Processor Performance states
+(P-states) or CPU Idle power states (C-states), but allows
+software to have influence where it would otherwise be unable
+to express a preference.
+
+For example, this setting may tell the hardware how
+aggressively or conservatively to control frequency
+in the "turbo range" above the explicitly OS-controlled
+P-state frequency range.  It may also tell the hardware
+how aggressively it should enter the OS requested C-states.
+
+This option can be applied to individual cores only via the \-\-cpu option,
+cpupower(1).
+
+Setting the performance bias value on one CPU can modify the setting on
+related CPUs as well (for example all CPUs on one socket), because of
+hardware restrictions.
+Use \fBcpupower -c all info -b\fP to verify.
+
+This options needs the msr kernel driver (CONFIG_X86_MSR) loaded.
+.RE
+.PP
+\-\-sched\-mc,  \-m [ VAL ]
+.RE
+\-\-sched\-smt, \-s [ VAL ]
+.RS 4
+\-\-sched\-mc utilizes cores in one processor package/socket first before
+processes are scheduled to other processor packages/sockets.
+
+\-\-sched\-smt utilizes thread siblings of one processor core first before
+processes are scheduled to other cores.
+
+The impact on power consumption and performance (positiv or negativ) heavily
+depends on processor support for deep sleep states, frequency scaling and
+frequency boost modes and their dependencies between other thread siblings
+and processor cores.
+
+Taken over from kernel documentation:
+
+Adjust the kernel's multi-core scheduler support.
+
+Possible values are:
+.RS 2
+0 - No power saving load balance (default value)
+
+1 - Fill one thread/core/package first for long running threads
+
+2 - Also bias task wakeups to semi-idle cpu package for power
+savings
+.RE
+
+sched_mc_power_savings is dependent upon SCHED_MC, which is
+itself architecture dependent.
+
+sched_smt_power_savings is dependent upon SCHED_SMT, which
+is itself architecture dependent.
+
+The two files are independent of each other. It is possible
+that one file may be present without the other.
+
+.SH "SEE ALSO"
+cpupower-info(1), cpupower-monitor(1), powertop(1)
+.PP
+.SH AUTHORS
+.nf
+\-\-perf\-bias parts written by Len Brown <len.brown@intel.com>
+Thomas Renninger <trenn@suse.de>
diff --git a/tools/power/cpupower/man/cpupower.1 b/tools/power/cpupower/man/cpupower.1
new file mode 100644 (file)
index 0000000..78c20fe
--- /dev/null
@@ -0,0 +1,72 @@
+.TH CPUPOWER "1" "07/03/2011" "" "cpupower Manual"
+.SH NAME
+cpupower \- Shows and sets processor power related values
+.SH SYNOPSIS
+.ft B
+.B cpupower [ \-c cpulist ] subcommand [ARGS]
+
+.B cpupower \-v|\-\-version
+
+.B cpupower \-h|\-\-help
+
+.SH DESCRIPTION
+\fBcpupower \fP is a collection of tools to examine and tune power saving
+related features of your processor.
+
+The manpages of the subcommands (cpupower\-<subcommand>(1)) provide detailed
+descriptions of supported features. Run \fBcpupower help\fP to get an overview
+of supported subcommands.
+
+.SH Options
+.PP
+\-\-help, \-h
+.RS 4
+Shows supported subcommands and general usage.
+.RE
+.PP
+\-\-cpu cpulist,  \-c cpulist
+.RS 4
+Only show or set values for specific cores.
+This option is not supported by all subcommands, details can be found in the
+manpages of the subcommands.
+
+Some subcommands access all cores (typically the *\-set commands), some only
+the first core (typically the *\-info commands) by default.
+
+The syntax for <cpulist> is based on how the kernel exports CPU bitmasks via
+sysfs files. Some examples:
+.RS 4
+.TP 16
+Input
+Equivalent to
+.TP
+all
+all cores
+.TP
+0\-3
+0,1,2,3
+.TP
+0\-7:2
+0,2,4,6
+.TP
+1,3,5-7
+1,3,5,6,7
+.TP
+0\-3:2,8\-15:4
+0,2,8,12       
+.RE
+.RE
+.PP
+\-\-version,  \-v
+.RS 4
+Print the package name and version number.
+
+.SH "SEE ALSO"
+cpupower-set(1), cpupower-info(1), cpupower-idle(1),
+cpupower-frequency-set(1), cpupower-frequency-info(1), cpupower-monitor(1),
+powertop(1)
+.PP
+.SH AUTHORS
+.nf
+\-\-perf\-bias parts written by Len Brown <len.brown@intel.com>
+Thomas Renninger <trenn@suse.de>
diff --git a/tools/power/cpupower/po/cs.po b/tools/power/cpupower/po/cs.po
new file mode 100644 (file)
index 0000000..cb22c45
--- /dev/null
@@ -0,0 +1,944 @@
+# translation of cs.po to Czech
+# Czech translation for cpufrequtils package
+# Czech messages for cpufrequtils.
+# Copyright (C) 2007 kavol
+# This file is distributed under the same license as the cpufrequtils package.
+#
+# Karel Volný <kavol@seznam.cz>, 2007, 2008.
+msgid ""
+msgstr ""
+"Project-Id-Version: cs\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-03-08 17:03+0100\n"
+"PO-Revision-Date: 2008-06-11 16:26+0200\n"
+"Last-Translator: Karel Volný <kavol@seznam.cz>\n"
+"Language-Team: Czech <diskuze@lists.l10n.cz>\n"
+"Language: cs\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms:  nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
+"X-Generator: KBabel 1.11.4\n"
+
+#: utils/idle_monitor/nhm_idle.c:36
+msgid "Processor Core C3"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:43
+msgid "Processor Core C6"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:51
+msgid "Processor Package C3"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:58 utils/idle_monitor/amd_fam14h_idle.c:70
+msgid "Processor Package C6"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:33
+msgid "Processor Core C7"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:40
+msgid "Processor Package C2"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:47
+msgid "Processor Package C7"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:56
+msgid "Package in sleep state (PC1 or deeper)"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:63
+msgid "Processor Package C1"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:77
+msgid "North Bridge P1 boolean counter (returns 0 or 1)"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:35
+msgid "Processor Core not idle"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:42
+msgid "Processor Core in an idle state"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:50
+msgid "Average Frequency (including boost) in MHz"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:66
+#, c-format
+msgid ""
+"cpupower monitor: [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
+"interval_sec | -c command ...]\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:69
+#, c-format
+msgid ""
+"cpupower monitor: [-v] [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
+"interval_sec | -c command ...]\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:71
+#, c-format
+msgid "\t -v: be more verbose\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:73
+#, c-format
+msgid "\t -h: print this help\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:74
+#, c-format
+msgid "\t -i: time intervall to measure for in seconds (default 1)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:75
+#, c-format
+msgid "\t -t: show CPU topology/hierarchy\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:76
+#, c-format
+msgid "\t -l: list available CPU sleep monitors (for use with -m)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:77
+#, c-format
+msgid "\t -m: show specific CPU sleep monitors only (in same order)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:79
+#, c-format
+msgid ""
+"only one of: -t, -l, -m are allowed\n"
+"If none of them is passed,"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:80
+#, c-format
+msgid " all supported monitors are shown\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:197
+#, c-format
+msgid "Monitor %s, Counter %s has no count function. Implementation error\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:207
+#, c-format
+msgid " *is offline\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:236
+#, c-format
+msgid "%s: max monitor name length (%d) exceeded\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:250
+#, c-format
+msgid "No matching monitor found in %s, try -l option\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:266
+#, c-format
+msgid "Monitor \"%s\" (%d states) - Might overflow after %u s\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:319
+#, c-format
+msgid "%s took %.5f seconds and exited with status %d\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:406
+#, c-format
+msgid "Cannot read number of available processors\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:417
+#, c-format
+msgid "Available monitor %s needs root access\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:428
+#, c-format
+msgid "No HW Cstate monitors found\n"
+msgstr ""
+
+#: utils/cpupower.c:78
+#, c-format
+msgid "cpupower [ -c cpulist ] subcommand [ARGS]\n"
+msgstr ""
+
+#: utils/cpupower.c:79
+#, c-format
+msgid "cpupower --version\n"
+msgstr ""
+
+#: utils/cpupower.c:80
+#, c-format
+msgid "Supported subcommands are:\n"
+msgstr ""
+
+#: utils/cpupower.c:83
+#, c-format
+msgid ""
+"\n"
+"Some subcommands can make use of the -c cpulist option.\n"
+msgstr ""
+
+#: utils/cpupower.c:84
+#, c-format
+msgid "Look at the general cpupower manpage how to use it\n"
+msgstr ""
+
+#: utils/cpupower.c:85
+#, c-format
+msgid "and read up the subcommand's manpage whether it is supported.\n"
+msgstr ""
+
+#: utils/cpupower.c:86
+#, c-format
+msgid ""
+"\n"
+"Use cpupower help subcommand for getting help for above subcommands.\n"
+msgstr ""
+
+#: utils/cpupower.c:91
+#, c-format
+msgid "Report errors and bugs to %s, please.\n"
+msgstr ""
+"Chyby v programu prosím hlaste na %s (anglicky).\n"
+"Chyby v překladu prosím hlaste na kavol@seznam.cz (česky ;-)\n"
+
+#: utils/cpupower.c:114
+#, c-format
+msgid "Error parsing cpu list\n"
+msgstr ""
+
+#: utils/cpupower.c:172
+#, c-format
+msgid "Subcommand %s needs root privileges\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:31
+#, c-format
+msgid "Couldn't count the number of CPUs (%s: %s), assuming 1\n"
+msgstr "Nelze zjistit počet CPU (%s: %s), předpokládá se 1.\n"
+
+#: utils/cpufreq-info.c:63
+#, c-format
+msgid ""
+"          minimum CPU frequency  -  maximum CPU frequency  -  governor\n"
+msgstr ""
+"         minimální frekvence CPU - maximální frekvence CPU -  regulátor\n"
+
+#: utils/cpufreq-info.c:151
+#, c-format
+msgid "Error while evaluating Boost Capabilities on CPU %d -- are you root?\n"
+msgstr ""
+
+#. P state changes via MSR are identified via cpuid 80000007
+#. on Intel and AMD, but we assume boost capable machines can do that
+#. if (cpuid_eax(0x80000000) >= 0x80000007
+#. && (cpuid_edx(0x80000007) & (1 << 7)))
+#.
+#: utils/cpufreq-info.c:161
+#, c-format
+msgid "  boost state support: \n"
+msgstr ""
+
+#: utils/cpufreq-info.c:163
+#, c-format
+msgid "    Supported: %s\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164
+msgid "yes"
+msgstr ""
+
+#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164
+msgid "no"
+msgstr ""
+
+#: utils/cpufreq-info.c:164
+#, fuzzy, c-format
+msgid "    Active: %s\n"
+msgstr "  ovladač: %s\n"
+
+#: utils/cpufreq-info.c:177
+#, c-format
+msgid "    Boost States: %d\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:178
+#, c-format
+msgid "    Total States: %d\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:181
+#, c-format
+msgid "    Pstate-Pb%d: %luMHz (boost state)\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:184
+#, c-format
+msgid "    Pstate-P%d:  %luMHz\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:211
+#, c-format
+msgid "  no or unknown cpufreq driver is active on this CPU\n"
+msgstr "  pro tento CPU není aktivní žádný známý ovladač cpufreq\n"
+
+#: utils/cpufreq-info.c:213
+#, c-format
+msgid "  driver: %s\n"
+msgstr "  ovladač: %s\n"
+
+#: utils/cpufreq-info.c:219
+#, fuzzy, c-format
+msgid "  CPUs which run at the same hardware frequency: "
+msgstr "  CPU, které musí měnit frekvenci zároveň: "
+
+#: utils/cpufreq-info.c:230
+#, fuzzy, c-format
+msgid "  CPUs which need to have their frequency coordinated by software: "
+msgstr "  CPU, které musí měnit frekvenci zároveň: "
+
+#: utils/cpufreq-info.c:241
+#, c-format
+msgid "  maximum transition latency: "
+msgstr ""
+
+#: utils/cpufreq-info.c:247
+#, c-format
+msgid "  hardware limits: "
+msgstr "  hardwarové meze: "
+
+#: utils/cpufreq-info.c:256
+#, c-format
+msgid "  available frequency steps: "
+msgstr "  dostupné frekvence: "
+
+#: utils/cpufreq-info.c:269
+#, c-format
+msgid "  available cpufreq governors: "
+msgstr "  dostupné regulátory: "
+
+#: utils/cpufreq-info.c:280
+#, c-format
+msgid "  current policy: frequency should be within "
+msgstr "  současná taktika: frekvence by měla být mezi "
+
+#: utils/cpufreq-info.c:282
+#, c-format
+msgid " and "
+msgstr " a "
+
+#: utils/cpufreq-info.c:286
+#, c-format
+msgid ""
+"The governor \"%s\" may decide which speed to use\n"
+"                  within this range.\n"
+msgstr ""
+"  Regulátor \"%s\" může rozhodnout jakou frekvenci použít\n"
+"                    v těchto mezích.\n"
+
+#: utils/cpufreq-info.c:293
+#, c-format
+msgid "  current CPU frequency is "
+msgstr "  současná frekvence CPU je "
+
+#: utils/cpufreq-info.c:296
+#, c-format
+msgid " (asserted by call to hardware)"
+msgstr "  (zjištěno hardwarovým voláním)"
+
+#: utils/cpufreq-info.c:304
+#, c-format
+msgid "  cpufreq stats: "
+msgstr "  statistika cpufreq: "
+
+#: utils/cpufreq-info.c:472
+#, fuzzy, c-format
+msgid "Usage: cpupower freqinfo [options]\n"
+msgstr "Užití: cpufreq-info [přepínače]\n"
+
+#: utils/cpufreq-info.c:473 utils/cpufreq-set.c:26 utils/cpupower-set.c:23
+#: utils/cpupower-info.c:22 utils/cpuidle-info.c:148
+#, c-format
+msgid "Options:\n"
+msgstr "Přepínače:\n"
+
+#: utils/cpufreq-info.c:474
+#, fuzzy, c-format
+msgid "  -e, --debug          Prints out debug information [default]\n"
+msgstr "  -e, --debug          Vypíše ladicí informace\n"
+
+#: utils/cpufreq-info.c:475
+#, c-format
+msgid ""
+"  -f, --freq           Get frequency the CPU currently runs at, according\n"
+"                       to the cpufreq core *\n"
+msgstr ""
+"  -f, --freq           Zjistí aktuální frekvenci, na které CPU běží\n"
+"                       podle cpufreq *\n"
+
+#: utils/cpufreq-info.c:477
+#, c-format
+msgid ""
+"  -w, --hwfreq         Get frequency the CPU currently runs at, by reading\n"
+"                       it from hardware (only available to root) *\n"
+msgstr ""
+"  -w, --hwfreq         Zjistí aktuální frekvenci, na které CPU běží\n"
+"                       z hardware (dostupné jen uživateli root) *\n"
+
+#: utils/cpufreq-info.c:479
+#, c-format
+msgid ""
+"  -l, --hwlimits       Determine the minimum and maximum CPU frequency "
+"allowed *\n"
+msgstr ""
+"  -l, --hwlimits       Zjistí minimální a maximální dostupnou frekvenci CPU "
+"*\n"
+
+#: utils/cpufreq-info.c:480
+#, c-format
+msgid "  -d, --driver         Determines the used cpufreq kernel driver *\n"
+msgstr "  -d, --driver         Zjistí aktivní ovladač cpufreq *\n"
+
+#: utils/cpufreq-info.c:481
+#, c-format
+msgid "  -p, --policy         Gets the currently used cpufreq policy *\n"
+msgstr "  -p, --policy         Zjistí aktuální taktiku cpufreq *\n"
+
+#: utils/cpufreq-info.c:482
+#, c-format
+msgid "  -g, --governors      Determines available cpufreq governors *\n"
+msgstr "  -g, --governors      Zjistí dostupné regulátory cpufreq *\n"
+
+#: utils/cpufreq-info.c:483
+#, fuzzy, c-format
+msgid ""
+"  -r, --related-cpus   Determines which CPUs run at the same hardware "
+"frequency *\n"
+msgstr ""
+"  -a, --affected-cpus  Zjistí, které CPU musí měnit frekvenci zároveň *\n"
+
+#: utils/cpufreq-info.c:484
+#, fuzzy, c-format
+msgid ""
+"  -a, --affected-cpus  Determines which CPUs need to have their frequency\n"
+"                       coordinated by software *\n"
+msgstr ""
+"  -a, --affected-cpus  Zjistí, které CPU musí měnit frekvenci zároveň *\n"
+
+#: utils/cpufreq-info.c:486
+#, c-format
+msgid "  -s, --stats          Shows cpufreq statistics if available\n"
+msgstr "  -s, --stats          Zobrazí statistiku cpufreq, je-li dostupná\n"
+
+#: utils/cpufreq-info.c:487
+#, fuzzy, c-format
+msgid ""
+"  -y, --latency        Determines the maximum latency on CPU frequency "
+"changes *\n"
+msgstr ""
+"  -l, --hwlimits       Zjistí minimální a maximální dostupnou frekvenci CPU "
+"*\n"
+
+#: utils/cpufreq-info.c:488
+#, c-format
+msgid "  -b, --boost          Checks for turbo or boost modes  *\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:489
+#, c-format
+msgid ""
+"  -o, --proc           Prints out information like provided by the /proc/"
+"cpufreq\n"
+"                       interface in 2.4. and early 2.6. kernels\n"
+msgstr ""
+"  -o, --proc           Vypíše informace ve formátu, jaký používalo rozhraní\n"
+"                       /proc/cpufreq v kernelech řady 2.4 a časné 2.6\n"
+
+#: utils/cpufreq-info.c:491
+#, fuzzy, c-format
+msgid ""
+"  -m, --human          human-readable output for the -f, -w, -s and -y "
+"parameters\n"
+msgstr ""
+"  -m, --human          Výstup parametrů -f, -w a -s v „lidmi čitelném“ "
+"formátu\n"
+
+#: utils/cpufreq-info.c:492 utils/cpuidle-info.c:152
+#, c-format
+msgid "  -h, --help           Prints out this screen\n"
+msgstr "  -h, --help           Vypíše tuto nápovědu\n"
+
+#: utils/cpufreq-info.c:495
+#, c-format
+msgid ""
+"If no argument or only the -c, --cpu parameter is given, debug output about\n"
+"cpufreq is printed which is useful e.g. for reporting bugs.\n"
+msgstr ""
+"Není-li zadán žádný parametr nebo je-li zadán pouze přepínač -c, --cpu, "
+"jsou\n"
+"vypsány ladicí informace, což může být užitečné například při hlášení chyb.\n"
+
+#: utils/cpufreq-info.c:497
+#, c-format
+msgid ""
+"For the arguments marked with *, omitting the -c or --cpu argument is\n"
+"equivalent to setting it to zero\n"
+msgstr ""
+"Není-li při použití přepínačů označených * zadán parametr -c nebo --cpu,\n"
+"předpokládá se jeho hodnota 0.\n"
+
+#: utils/cpufreq-info.c:580
+#, c-format
+msgid ""
+"The argument passed to this tool can't be combined with passing a --cpu "
+"argument\n"
+msgstr "Zadaný parametr nemůže být použit zároveň s přepínačem -c nebo --cpu\n"
+
+#: utils/cpufreq-info.c:596
+#, c-format
+msgid ""
+"You can't specify more than one --cpu parameter and/or\n"
+"more than one output-specific argument\n"
+msgstr ""
+"Nelze zadat více než jeden parametr -c nebo --cpu\n"
+"anebo více než jeden parametr určující výstup\n"
+
+#: utils/cpufreq-info.c:600 utils/cpufreq-set.c:82 utils/cpupower-set.c:42
+#: utils/cpupower-info.c:42 utils/cpuidle-info.c:213
+#, c-format
+msgid "invalid or unknown argument\n"
+msgstr "neplatný nebo neznámý parametr\n"
+
+#: utils/cpufreq-info.c:617
+#, c-format
+msgid "couldn't analyze CPU %d as it doesn't seem to be present\n"
+msgstr "nelze analyzovat CPU %d, vypadá to, že není přítomen\n"
+
+#: utils/cpufreq-info.c:620 utils/cpupower-info.c:142
+#, c-format
+msgid "analyzing CPU %d:\n"
+msgstr "analyzuji CPU %d:\n"
+
+#: utils/cpufreq-set.c:25
+#, fuzzy, c-format
+msgid "Usage: cpupower frequency-set [options]\n"
+msgstr "Užití: cpufreq-set [přepínače]\n"
+
+#: utils/cpufreq-set.c:27
+#, c-format
+msgid ""
+"  -d FREQ, --min FREQ      new minimum CPU frequency the governor may "
+"select\n"
+msgstr ""
+"  -d FREQ, --min FREQ      Nová nejnižší frekvence, kterou může regulátor "
+"vybrat\n"
+
+#: utils/cpufreq-set.c:28
+#, c-format
+msgid ""
+"  -u FREQ, --max FREQ      new maximum CPU frequency the governor may "
+"select\n"
+msgstr ""
+"  -u FREQ, --max FREQ      Nová nejvyšší frekvence, kterou může regulátor "
+"zvolit\n"
+
+#: utils/cpufreq-set.c:29
+#, c-format
+msgid "  -g GOV, --governor GOV   new cpufreq governor\n"
+msgstr "  -g GOV, --governors GOV  Nový regulátor cpufreq\n"
+
+#: utils/cpufreq-set.c:30
+#, c-format
+msgid ""
+"  -f FREQ, --freq FREQ     specific frequency to be set. Requires userspace\n"
+"                           governor to be available and loaded\n"
+msgstr ""
+"  -f FREQ, --freq FREQ     Frekvence, která má být nastavena. Vyžaduje, aby "
+"byl\n"
+"                           v jádře nahrán regulátor ‚userspace‘.\n"
+
+#: utils/cpufreq-set.c:32
+#, c-format
+msgid "  -r, --related            Switches all hardware-related CPUs\n"
+msgstr ""
+
+#: utils/cpufreq-set.c:33 utils/cpupower-set.c:28 utils/cpupower-info.c:27
+#, fuzzy, c-format
+msgid "  -h, --help               Prints out this screen\n"
+msgstr "  -h, --help           Vypíše tuto nápovědu\n"
+
+#: utils/cpufreq-set.c:35
+#, fuzzy, c-format
+msgid ""
+"Notes:\n"
+"1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n"
+msgstr ""
+"Není-li při použití přepínačů označených * zadán parametr -c nebo --cpu,\n"
+"předpokládá se jeho hodnota 0.\n"
+
+#: utils/cpufreq-set.c:37
+#, fuzzy, c-format
+msgid ""
+"2. The -f FREQ, --freq FREQ parameter cannot be combined with any other "
+"parameter\n"
+"   except the -c CPU, --cpu CPU parameter\n"
+"3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n"
+"   by postfixing the value with the wanted unit name, without any space\n"
+"   (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n"
+msgstr ""
+"Poznámky:\n"
+"1. Vynechání parametru -c nebo --cpu je ekvivalentní jeho nastavení na 0\n"
+"2. Přepínač -f nebo --freq nemůže být použit zároveň s žádným jiným vyjma -"
+"c\n"
+"   nebo --cpu\n"
+"3. Frekvence (FREQ) mohou být zadány v Hz, kHz (výchozí), MHz, GHz nebo THz\n"
+"   připojením názvu jednotky bez mezery mezi číslem a jednotkou\n"
+"   (FREQ v kHz =^ Hz * 0,001 = ^ MHz * 1000 =^ GHz * 1000000)\n"
+
+#: utils/cpufreq-set.c:57
+#, c-format
+msgid ""
+"Error setting new values. Common errors:\n"
+"- Do you have proper administration rights? (super-user?)\n"
+"- Is the governor you requested available and modprobed?\n"
+"- Trying to set an invalid policy?\n"
+"- Trying to set a specific frequency, but userspace governor is not "
+"available,\n"
+"   for example because of hardware which cannot be set to a specific "
+"frequency\n"
+"   or because the userspace governor isn't loaded?\n"
+msgstr ""
+"Chyba při nastavování nových hodnot. Obvyklé problémy:\n"
+"- Máte patřičná administrátorská práva? (root?)\n"
+"- Je požadovaný regulátor dostupný v jádře? (modprobe?)\n"
+"- Snažíte se nastavit neplatnou taktiku?\n"
+"- Snažíte se nastavit určitou frekvenci, ale není dostupný\n"
+"  regulátor ‚userspace‘, například protože není nahrán v jádře,\n"
+"  nebo nelze na tomto hardware nastavit určitou frekvenci?\n"
+
+#: utils/cpufreq-set.c:170
+#, c-format
+msgid "wrong, unknown or unhandled CPU?\n"
+msgstr "neznámý nebo nepodporovaný CPU?\n"
+
+#: utils/cpufreq-set.c:302
+#, c-format
+msgid ""
+"the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n"
+"-g/--governor parameters\n"
+msgstr ""
+"přepínač -f/--freq nemůže být použit zároveň\n"
+"s přepínačem -d/--min, -u/--max nebo -g/--governor\n"
+
+#: utils/cpufreq-set.c:308
+#, c-format
+msgid ""
+"At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n"
+"-g/--governor must be passed\n"
+msgstr ""
+"Musí být zadán alespoň jeden přepínač\n"
+"-f/--freq, -d/--min, -u/--max nebo -g/--governor\n"
+
+#: utils/cpufreq-set.c:347
+#, c-format
+msgid "Setting cpu: %d\n"
+msgstr ""
+
+#: utils/cpupower-set.c:22
+#, c-format
+msgid "Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:24
+#, c-format
+msgid ""
+"  -b, --perf-bias [VAL]    Sets CPU's power vs performance policy on some\n"
+"                           Intel models [0-15], see manpage for details\n"
+msgstr ""
+
+#: utils/cpupower-set.c:26
+#, c-format
+msgid ""
+"  -m, --sched-mc  [VAL]    Sets the kernel's multi core scheduler policy.\n"
+msgstr ""
+
+#: utils/cpupower-set.c:27
+#, c-format
+msgid ""
+"  -s, --sched-smt [VAL]    Sets the kernel's thread sibling scheduler "
+"policy.\n"
+msgstr ""
+
+#: utils/cpupower-set.c:80
+#, c-format
+msgid "--perf-bias param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:91
+#, c-format
+msgid "--sched-mc param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:102
+#, c-format
+msgid "--sched-smt param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:121
+#, c-format
+msgid "Error setting sched-mc %s\n"
+msgstr ""
+
+#: utils/cpupower-set.c:127
+#, c-format
+msgid "Error setting sched-smt %s\n"
+msgstr ""
+
+#: utils/cpupower-set.c:146
+#, c-format
+msgid "Error setting perf-bias value on CPU %d\n"
+msgstr ""
+
+#: utils/cpupower-info.c:21
+#, c-format
+msgid "Usage: cpupower info [ -b ] [ -m ] [ -s ]\n"
+msgstr ""
+
+#: utils/cpupower-info.c:23
+#, c-format
+msgid ""
+"  -b, --perf-bias    Gets CPU's power vs performance policy on some\n"
+"                           Intel models [0-15], see manpage for details\n"
+msgstr ""
+
+#: utils/cpupower-info.c:25
+#, fuzzy, c-format
+msgid "  -m, --sched-mc     Gets the kernel's multi core scheduler policy.\n"
+msgstr "  -p, --policy         Zjistí aktuální taktiku cpufreq *\n"
+
+#: utils/cpupower-info.c:26
+#, c-format
+msgid ""
+"  -s, --sched-smt    Gets the kernel's thread sibling scheduler policy.\n"
+msgstr ""
+
+#: utils/cpupower-info.c:28
+#, c-format
+msgid ""
+"\n"
+"Passing no option will show all info, by default only on core 0\n"
+msgstr ""
+
+#: utils/cpupower-info.c:102
+#, c-format
+msgid "System's multi core scheduler setting: "
+msgstr ""
+
+#. if sysfs file is missing it's: errno == ENOENT
+#: utils/cpupower-info.c:105 utils/cpupower-info.c:114
+#, c-format
+msgid "not supported\n"
+msgstr ""
+
+#: utils/cpupower-info.c:111
+#, c-format
+msgid "System's thread sibling scheduler setting: "
+msgstr ""
+
+#: utils/cpupower-info.c:126
+#, c-format
+msgid "Intel's performance bias setting needs root privileges\n"
+msgstr ""
+
+#: utils/cpupower-info.c:128
+#, c-format
+msgid "System does not support Intel's performance bias setting\n"
+msgstr ""
+
+#: utils/cpupower-info.c:147
+#, c-format
+msgid "Could not read perf-bias value\n"
+msgstr ""
+
+#: utils/cpupower-info.c:150
+#, c-format
+msgid "perf-bias: %d\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:28
+#, fuzzy, c-format
+msgid "Analyzing CPU %d:\n"
+msgstr "analyzuji CPU %d:\n"
+
+#: utils/cpuidle-info.c:32
+#, c-format
+msgid "CPU %u: No idle states\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:36
+#, c-format
+msgid "CPU %u: Can't read idle state info\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:41
+#, c-format
+msgid "Could not determine max idle state %u\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:46
+#, c-format
+msgid "Number of idle states: %d\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:48
+#, fuzzy, c-format
+msgid "Available idle states:"
+msgstr "  dostupné frekvence: "
+
+#: utils/cpuidle-info.c:71
+#, c-format
+msgid "Flags/Description: %s\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:74
+#, c-format
+msgid "Latency: %lu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:76
+#, c-format
+msgid "Usage: %lu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:78
+#, c-format
+msgid "Duration: %llu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:90
+#, c-format
+msgid "Could not determine cpuidle driver\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:94
+#, fuzzy, c-format
+msgid "CPUidle driver: %s\n"
+msgstr "  ovladač: %s\n"
+
+#: utils/cpuidle-info.c:99
+#, c-format
+msgid "Could not determine cpuidle governor\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:103
+#, c-format
+msgid "CPUidle governor: %s\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:122
+#, c-format
+msgid "CPU %u: Can't read C-state info\n"
+msgstr ""
+
+#. printf("Cstates: %d\n", cstates);
+#: utils/cpuidle-info.c:127
+#, c-format
+msgid "active state:            C0\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:128
+#, c-format
+msgid "max_cstate:              C%u\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:129
+#, c-format
+msgid "maximum allowed latency: %lu usec\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:130
+#, c-format
+msgid "states:\t\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:132
+#, c-format
+msgid "    C%d:                  type[C%d] "
+msgstr ""
+
+#: utils/cpuidle-info.c:134
+#, c-format
+msgid "promotion[--] demotion[--] "
+msgstr ""
+
+#: utils/cpuidle-info.c:135
+#, c-format
+msgid "latency[%03lu] "
+msgstr ""
+
+#: utils/cpuidle-info.c:137
+#, c-format
+msgid "usage[%08lu] "
+msgstr ""
+
+#: utils/cpuidle-info.c:139
+#, c-format
+msgid "duration[%020Lu] \n"
+msgstr ""
+
+#: utils/cpuidle-info.c:147
+#, fuzzy, c-format
+msgid "Usage: cpupower idleinfo [options]\n"
+msgstr "Užití: cpufreq-info [přepínače]\n"
+
+#: utils/cpuidle-info.c:149
+#, fuzzy, c-format
+msgid "  -s, --silent         Only show general C-state information\n"
+msgstr "  -e, --debug          Vypíše ladicí informace\n"
+
+#: utils/cpuidle-info.c:150
+#, fuzzy, c-format
+msgid ""
+"  -o, --proc           Prints out information like provided by the /proc/"
+"acpi/processor/*/power\n"
+"                       interface in older kernels\n"
+msgstr ""
+"  -o, --proc           Vypíše informace ve formátu, jaký používalo rozhraní\n"
+"                       /proc/cpufreq v kernelech řady 2.4 a časné 2.6\n"
+
+#: utils/cpuidle-info.c:209
+#, fuzzy, c-format
+msgid "You can't specify more than one output-specific argument\n"
+msgstr ""
+"Nelze zadat více než jeden parametr -c nebo --cpu\n"
+"anebo více než jeden parametr určující výstup\n"
+
+#~ msgid ""
+#~ "  -c CPU, --cpu CPU    CPU number which information shall be determined "
+#~ "about\n"
+#~ msgstr ""
+#~ "  -c CPU, --cpu CPU    Číslo CPU, o kterém se mají zjistit informace\n"
+
+#~ msgid ""
+#~ "  -c CPU, --cpu CPU        number of CPU where cpufreq settings shall be "
+#~ "modified\n"
+#~ msgstr ""
+#~ "  -c CPU, --cpu CPU        Číslo CPU pro který se má provést nastavení "
+#~ "cpufreq\n"
diff --git a/tools/power/cpupower/po/de.po b/tools/power/cpupower/po/de.po
new file mode 100644 (file)
index 0000000..78c09e5
--- /dev/null
@@ -0,0 +1,961 @@
+# German translations for cpufrequtils package
+# German messages for cpufrequtils.
+# Copyright (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.net>
+# This file is distributed under the same license as the cpufrequtils package.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: cpufrequtils 006\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-03-08 17:03+0100\n"
+"PO-Revision-Date: 2009-08-08 17:18+0100\n"
+"Last-Translator:  <linux@dominikbrodowski.net>\n"
+"Language-Team: NONE\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: utils/idle_monitor/nhm_idle.c:36
+msgid "Processor Core C3"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:43
+msgid "Processor Core C6"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:51
+msgid "Processor Package C3"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:58 utils/idle_monitor/amd_fam14h_idle.c:70
+msgid "Processor Package C6"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:33
+msgid "Processor Core C7"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:40
+msgid "Processor Package C2"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:47
+msgid "Processor Package C7"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:56
+msgid "Package in sleep state (PC1 or deeper)"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:63
+msgid "Processor Package C1"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:77
+msgid "North Bridge P1 boolean counter (returns 0 or 1)"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:35
+msgid "Processor Core not idle"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:42
+msgid "Processor Core in an idle state"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:50
+msgid "Average Frequency (including boost) in MHz"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:66
+#, c-format
+msgid ""
+"cpupower monitor: [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
+"interval_sec | -c command ...]\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:69
+#, c-format
+msgid ""
+"cpupower monitor: [-v] [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
+"interval_sec | -c command ...]\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:71
+#, c-format
+msgid "\t -v: be more verbose\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:73
+#, c-format
+msgid "\t -h: print this help\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:74
+#, c-format
+msgid "\t -i: time intervall to measure for in seconds (default 1)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:75
+#, c-format
+msgid "\t -t: show CPU topology/hierarchy\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:76
+#, c-format
+msgid "\t -l: list available CPU sleep monitors (for use with -m)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:77
+#, c-format
+msgid "\t -m: show specific CPU sleep monitors only (in same order)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:79
+#, c-format
+msgid ""
+"only one of: -t, -l, -m are allowed\n"
+"If none of them is passed,"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:80
+#, c-format
+msgid " all supported monitors are shown\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:197
+#, c-format
+msgid "Monitor %s, Counter %s has no count function. Implementation error\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:207
+#, c-format
+msgid " *is offline\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:236
+#, c-format
+msgid "%s: max monitor name length (%d) exceeded\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:250
+#, c-format
+msgid "No matching monitor found in %s, try -l option\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:266
+#, c-format
+msgid "Monitor \"%s\" (%d states) - Might overflow after %u s\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:319
+#, c-format
+msgid "%s took %.5f seconds and exited with status %d\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:406
+#, c-format
+msgid "Cannot read number of available processors\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:417
+#, c-format
+msgid "Available monitor %s needs root access\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:428
+#, c-format
+msgid "No HW Cstate monitors found\n"
+msgstr ""
+
+#: utils/cpupower.c:78
+#, c-format
+msgid "cpupower [ -c cpulist ] subcommand [ARGS]\n"
+msgstr ""
+
+#: utils/cpupower.c:79
+#, c-format
+msgid "cpupower --version\n"
+msgstr ""
+
+#: utils/cpupower.c:80
+#, c-format
+msgid "Supported subcommands are:\n"
+msgstr ""
+
+#: utils/cpupower.c:83
+#, c-format
+msgid ""
+"\n"
+"Some subcommands can make use of the -c cpulist option.\n"
+msgstr ""
+
+#: utils/cpupower.c:84
+#, c-format
+msgid "Look at the general cpupower manpage how to use it\n"
+msgstr ""
+
+#: utils/cpupower.c:85
+#, c-format
+msgid "and read up the subcommand's manpage whether it is supported.\n"
+msgstr ""
+
+#: utils/cpupower.c:86
+#, c-format
+msgid ""
+"\n"
+"Use cpupower help subcommand for getting help for above subcommands.\n"
+msgstr ""
+
+#: utils/cpupower.c:91
+#, c-format
+msgid "Report errors and bugs to %s, please.\n"
+msgstr "Bitte melden Sie Fehler an %s.\n"
+
+#: utils/cpupower.c:114
+#, c-format
+msgid "Error parsing cpu list\n"
+msgstr ""
+
+#: utils/cpupower.c:172
+#, c-format
+msgid "Subcommand %s needs root privileges\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:31
+#, c-format
+msgid "Couldn't count the number of CPUs (%s: %s), assuming 1\n"
+msgstr ""
+"Konnte nicht die Anzahl der CPUs herausfinden (%s : %s), nehme daher 1 an.\n"
+
+#: utils/cpufreq-info.c:63
+#, c-format
+msgid ""
+"          minimum CPU frequency  -  maximum CPU frequency  -  governor\n"
+msgstr ""
+"          minimale CPU-Taktfreq. -  maximale CPU-Taktfreq. -  Regler  \n"
+
+#: utils/cpufreq-info.c:151
+#, c-format
+msgid "Error while evaluating Boost Capabilities on CPU %d -- are you root?\n"
+msgstr ""
+
+#. P state changes via MSR are identified via cpuid 80000007
+#. on Intel and AMD, but we assume boost capable machines can do that
+#. if (cpuid_eax(0x80000000) >= 0x80000007
+#. && (cpuid_edx(0x80000007) & (1 << 7)))
+#.
+#: utils/cpufreq-info.c:161
+#, c-format
+msgid "  boost state support: \n"
+msgstr ""
+
+#: utils/cpufreq-info.c:163
+#, c-format
+msgid "    Supported: %s\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164
+msgid "yes"
+msgstr ""
+
+#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164
+msgid "no"
+msgstr ""
+
+#: utils/cpufreq-info.c:164
+#, fuzzy, c-format
+msgid "    Active: %s\n"
+msgstr "  Treiber: %s\n"
+
+#: utils/cpufreq-info.c:177
+#, c-format
+msgid "    Boost States: %d\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:178
+#, c-format
+msgid "    Total States: %d\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:181
+#, c-format
+msgid "    Pstate-Pb%d: %luMHz (boost state)\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:184
+#, c-format
+msgid "    Pstate-P%d:  %luMHz\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:211
+#, c-format
+msgid "  no or unknown cpufreq driver is active on this CPU\n"
+msgstr "  kein oder nicht bestimmbarer cpufreq-Treiber aktiv\n"
+
+#: utils/cpufreq-info.c:213
+#, c-format
+msgid "  driver: %s\n"
+msgstr "  Treiber: %s\n"
+
+#: utils/cpufreq-info.c:219
+#, c-format
+msgid "  CPUs which run at the same hardware frequency: "
+msgstr "  Folgende CPUs laufen mit der gleichen Hardware-Taktfrequenz: "
+
+#: utils/cpufreq-info.c:230
+#, c-format
+msgid "  CPUs which need to have their frequency coordinated by software: "
+msgstr "  Die Taktfrequenz folgender CPUs werden per Software koordiniert: "
+
+#: utils/cpufreq-info.c:241
+#, c-format
+msgid "  maximum transition latency: "
+msgstr "  Maximale Dauer eines Taktfrequenzwechsels: "
+
+#: utils/cpufreq-info.c:247
+#, c-format
+msgid "  hardware limits: "
+msgstr "  Hardwarebedingte Grenzen der Taktfrequenz: "
+
+#: utils/cpufreq-info.c:256
+#, c-format
+msgid "  available frequency steps: "
+msgstr "  mögliche Taktfrequenzen: "
+
+#: utils/cpufreq-info.c:269
+#, c-format
+msgid "  available cpufreq governors: "
+msgstr "  mögliche Regler: "
+
+#: utils/cpufreq-info.c:280
+#, c-format
+msgid "  current policy: frequency should be within "
+msgstr "  momentane Taktik: die Frequenz soll innerhalb "
+
+#: utils/cpufreq-info.c:282
+#, c-format
+msgid " and "
+msgstr " und "
+
+#: utils/cpufreq-info.c:286
+#, c-format
+msgid ""
+"The governor \"%s\" may decide which speed to use\n"
+"                  within this range.\n"
+msgstr ""
+"  liegen. Der Regler \"%s\" kann frei entscheiden,\n"
+"                    welche Taktfrequenz innerhalb dieser Grenze verwendet "
+"wird.\n"
+
+#: utils/cpufreq-info.c:293
+#, c-format
+msgid "  current CPU frequency is "
+msgstr "  momentane Taktfrequenz ist "
+
+#: utils/cpufreq-info.c:296
+#, c-format
+msgid " (asserted by call to hardware)"
+msgstr "  (verifiziert durch Nachfrage bei der Hardware)"
+
+#: utils/cpufreq-info.c:304
+#, c-format
+msgid "  cpufreq stats: "
+msgstr "  Statistik:"
+
+#: utils/cpufreq-info.c:472
+#, fuzzy, c-format
+msgid "Usage: cpupower freqinfo [options]\n"
+msgstr "Aufruf: cpufreq-info [Optionen]\n"
+
+#: utils/cpufreq-info.c:473 utils/cpufreq-set.c:26 utils/cpupower-set.c:23
+#: utils/cpupower-info.c:22 utils/cpuidle-info.c:148
+#, c-format
+msgid "Options:\n"
+msgstr "Optionen:\n"
+
+#: utils/cpufreq-info.c:474
+#, fuzzy, c-format
+msgid "  -e, --debug          Prints out debug information [default]\n"
+msgstr ""
+"  -e, --debug          Erzeugt detaillierte Informationen, hilfreich\n"
+"                       zum Aufspüren von Fehlern\n"
+
+#: utils/cpufreq-info.c:475
+#, c-format
+msgid ""
+"  -f, --freq           Get frequency the CPU currently runs at, according\n"
+"                       to the cpufreq core *\n"
+msgstr ""
+"  -f, --freq           Findet die momentane CPU-Taktfrquenz heraus (nach\n"
+"                       Meinung des Betriebssystems) *\n"
+
+#: utils/cpufreq-info.c:477
+#, c-format
+msgid ""
+"  -w, --hwfreq         Get frequency the CPU currently runs at, by reading\n"
+"                       it from hardware (only available to root) *\n"
+msgstr ""
+"  -w, --hwfreq         Findet die momentane CPU-Taktfrequenz heraus\n"
+"                       (verifiziert durch Nachfrage bei der Hardware)\n"
+"                       [nur der Administrator kann dies tun] *\n"
+
+#: utils/cpufreq-info.c:479
+#, c-format
+msgid ""
+"  -l, --hwlimits       Determine the minimum and maximum CPU frequency "
+"allowed *\n"
+msgstr ""
+"  -l, --hwlimits       Findet die minimale und maximale Taktfrequenz heraus "
+"*\n"
+
+#: utils/cpufreq-info.c:480
+#, c-format
+msgid "  -d, --driver         Determines the used cpufreq kernel driver *\n"
+msgstr "  -d, --driver         Findet den momentanen Treiber heraus *\n"
+
+#: utils/cpufreq-info.c:481
+#, c-format
+msgid "  -p, --policy         Gets the currently used cpufreq policy *\n"
+msgstr "  -p, --policy         Findet die momentane Taktik heraus *\n"
+
+#: utils/cpufreq-info.c:482
+#, c-format
+msgid "  -g, --governors      Determines available cpufreq governors *\n"
+msgstr "  -g, --governors      Erzeugt eine Liste mit verfügbaren Reglern *\n"
+
+#: utils/cpufreq-info.c:483
+#, c-format
+msgid ""
+"  -r, --related-cpus   Determines which CPUs run at the same hardware "
+"frequency *\n"
+msgstr ""
+"  -r, --related-cpus   Findet heraus, welche CPUs mit derselben "
+"physikalischen\n"
+"                       Taktfrequenz laufen *\n"
+
+#: utils/cpufreq-info.c:484
+#, c-format
+msgid ""
+"  -a, --affected-cpus  Determines which CPUs need to have their frequency\n"
+"                       coordinated by software *\n"
+msgstr ""
+"  -a, --affected-cpus  Findet heraus, von welchen CPUs die Taktfrequenz "
+"durch\n"
+"                       Software koordiniert werden muss *\n"
+
+#: utils/cpufreq-info.c:486
+#, c-format
+msgid "  -s, --stats          Shows cpufreq statistics if available\n"
+msgstr ""
+"  -s, --stats          Zeigt, sofern möglich, Statistiken über cpufreq an.\n"
+
+#: utils/cpufreq-info.c:487
+#, c-format
+msgid ""
+"  -y, --latency        Determines the maximum latency on CPU frequency "
+"changes *\n"
+msgstr ""
+"  -y, --latency        Findet die maximale Dauer eines Taktfrequenzwechsels "
+"heraus *\n"
+
+#: utils/cpufreq-info.c:488
+#, c-format
+msgid "  -b, --boost          Checks for turbo or boost modes  *\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:489
+#, c-format
+msgid ""
+"  -o, --proc           Prints out information like provided by the /proc/"
+"cpufreq\n"
+"                       interface in 2.4. and early 2.6. kernels\n"
+msgstr ""
+"  -o, --proc           Erzeugt Informationen in einem ähnlichem Format zu "
+"dem\n"
+"                       der /proc/cpufreq-Datei in 2.4. und frühen 2.6.\n"
+"                       Kernel-Versionen\n"
+
+#: utils/cpufreq-info.c:491
+#, c-format
+msgid ""
+"  -m, --human          human-readable output for the -f, -w, -s and -y "
+"parameters\n"
+msgstr ""
+"  -m, --human          Formatiert Taktfrequenz- und Zeitdauerangaben in "
+"besser\n"
+"                       lesbarer Form (MHz, GHz; us, ms)\n"
+
+#: utils/cpufreq-info.c:492 utils/cpuidle-info.c:152
+#, c-format
+msgid "  -h, --help           Prints out this screen\n"
+msgstr "  -h, --help           Gibt diese Kurzübersicht aus\n"
+
+#: utils/cpufreq-info.c:495
+#, c-format
+msgid ""
+"If no argument or only the -c, --cpu parameter is given, debug output about\n"
+"cpufreq is printed which is useful e.g. for reporting bugs.\n"
+msgstr ""
+"Sofern kein anderer Parameter als '-c, --cpu' angegeben wird, liefert "
+"dieses\n"
+"Programm Informationen, die z.B. zum Berichten von Fehlern nützlich sind.\n"
+
+#: utils/cpufreq-info.c:497
+#, c-format
+msgid ""
+"For the arguments marked with *, omitting the -c or --cpu argument is\n"
+"equivalent to setting it to zero\n"
+msgstr ""
+"Bei den mit * markierten Parametern wird '--cpu 0' angenommen, soweit nicht\n"
+"mittels -c oder --cpu etwas anderes angegeben wird\n"
+
+#: utils/cpufreq-info.c:580
+#, c-format
+msgid ""
+"The argument passed to this tool can't be combined with passing a --cpu "
+"argument\n"
+msgstr "Diese Option kann nicht mit der --cpu-Option kombiniert werden\n"
+
+#: utils/cpufreq-info.c:596
+#, c-format
+msgid ""
+"You can't specify more than one --cpu parameter and/or\n"
+"more than one output-specific argument\n"
+msgstr ""
+"Man kann nicht mehr als einen --cpu-Parameter und/oder mehr als einen\n"
+"informationsspezifischen Parameter gleichzeitig angeben\n"
+
+#: utils/cpufreq-info.c:600 utils/cpufreq-set.c:82 utils/cpupower-set.c:42
+#: utils/cpupower-info.c:42 utils/cpuidle-info.c:213
+#, c-format
+msgid "invalid or unknown argument\n"
+msgstr "unbekannter oder falscher Parameter\n"
+
+#: utils/cpufreq-info.c:617
+#, c-format
+msgid "couldn't analyze CPU %d as it doesn't seem to be present\n"
+msgstr ""
+"Konnte nicht die CPU %d analysieren, da sie (scheinbar?) nicht existiert.\n"
+
+#: utils/cpufreq-info.c:620 utils/cpupower-info.c:142
+#, c-format
+msgid "analyzing CPU %d:\n"
+msgstr "analysiere CPU %d:\n"
+
+#: utils/cpufreq-set.c:25
+#, fuzzy, c-format
+msgid "Usage: cpupower frequency-set [options]\n"
+msgstr "Aufruf: cpufreq-set [Optionen]\n"
+
+#: utils/cpufreq-set.c:27
+#, c-format
+msgid ""
+"  -d FREQ, --min FREQ      new minimum CPU frequency the governor may "
+"select\n"
+msgstr ""
+"  -d FREQ, --min FREQ      neue minimale Taktfrequenz, die der Regler\n"
+"                           auswählen darf\n"
+
+#: utils/cpufreq-set.c:28
+#, c-format
+msgid ""
+"  -u FREQ, --max FREQ      new maximum CPU frequency the governor may "
+"select\n"
+msgstr ""
+"  -u FREQ, --max FREQ      neue maximale Taktfrequenz, die der Regler\n"
+"                           auswählen darf\n"
+
+#: utils/cpufreq-set.c:29
+#, c-format
+msgid "  -g GOV, --governor GOV   new cpufreq governor\n"
+msgstr "  -g GOV, --governors GOV  wechsle zu Regler GOV\n"
+
+#: utils/cpufreq-set.c:30
+#, c-format
+msgid ""
+"  -f FREQ, --freq FREQ     specific frequency to be set. Requires userspace\n"
+"                           governor to be available and loaded\n"
+msgstr ""
+"  -f FREQ, --freq FREQ     setze exakte Taktfrequenz. Benötigt den Regler\n"
+"                           'userspace'.\n"
+
+#: utils/cpufreq-set.c:32
+#, c-format
+msgid "  -r, --related            Switches all hardware-related CPUs\n"
+msgstr ""
+"  -r, --related            Setze Werte für alle CPUs, deren Taktfrequenz\n"
+"                           hardwarebedingt identisch ist.\n"
+
+#: utils/cpufreq-set.c:33 utils/cpupower-set.c:28 utils/cpupower-info.c:27
+#, c-format
+msgid "  -h, --help               Prints out this screen\n"
+msgstr "  -h, --help               Gibt diese Kurzübersicht aus\n"
+
+#: utils/cpufreq-set.c:35
+#, fuzzy, c-format
+msgid ""
+"Notes:\n"
+"1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n"
+msgstr ""
+"Bei den mit * markierten Parametern wird '--cpu 0' angenommen, soweit nicht\n"
+"mittels -c oder --cpu etwas anderes angegeben wird\n"
+
+#: utils/cpufreq-set.c:37
+#, fuzzy, c-format
+msgid ""
+"2. The -f FREQ, --freq FREQ parameter cannot be combined with any other "
+"parameter\n"
+"   except the -c CPU, --cpu CPU parameter\n"
+"3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n"
+"   by postfixing the value with the wanted unit name, without any space\n"
+"   (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n"
+msgstr ""
+"Hinweise:\n"
+"1. Sofern kein -c oder --cpu-Parameter angegeben ist, wird '--cpu 0'\n"
+"   angenommen\n"
+"2. Der Parameter -f bzw. --freq kann mit keinem anderen als dem Parameter\n"
+"   -c bzw. --cpu kombiniert werden\n"
+"3. FREQuenzen können in Hz, kHz (Standard), MHz, GHz oder THz eingegeben\n"
+"   werden, indem der Wert und unmittelbar anschließend (ohne Leerzeichen!)\n"
+"   die Einheit angegeben werden. (Bsp: 1GHz )\n"
+"   (FREQuenz in kHz =^ MHz * 1000 =^ GHz * 1000000).\n"
+
+#: utils/cpufreq-set.c:57
+#, c-format
+msgid ""
+"Error setting new values. Common errors:\n"
+"- Do you have proper administration rights? (super-user?)\n"
+"- Is the governor you requested available and modprobed?\n"
+"- Trying to set an invalid policy?\n"
+"- Trying to set a specific frequency, but userspace governor is not "
+"available,\n"
+"   for example because of hardware which cannot be set to a specific "
+"frequency\n"
+"   or because the userspace governor isn't loaded?\n"
+msgstr ""
+"Beim Einstellen ist ein Fehler aufgetreten. Typische Fehlerquellen sind:\n"
+"- nicht ausreichende Rechte (Administrator)\n"
+"- der Regler ist nicht verfügbar bzw. nicht geladen\n"
+"- die angegebene Taktik ist inkorrekt\n"
+"- eine spezifische Frequenz wurde angegeben, aber der Regler 'userspace'\n"
+"  kann entweder hardwarebedingt nicht genutzt werden oder ist nicht geladen\n"
+
+#: utils/cpufreq-set.c:170
+#, c-format
+msgid "wrong, unknown or unhandled CPU?\n"
+msgstr "unbekannte oder nicht regelbare CPU\n"
+
+#: utils/cpufreq-set.c:302
+#, c-format
+msgid ""
+"the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n"
+"-g/--governor parameters\n"
+msgstr ""
+"Der -f bzw. --freq-Parameter kann nicht mit den Parametern -d/--min, -u/--"
+"max\n"
+"oder -g/--governor kombiniert werden\n"
+
+#: utils/cpufreq-set.c:308
+#, c-format
+msgid ""
+"At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n"
+"-g/--governor must be passed\n"
+msgstr ""
+"Es muss mindestens ein Parameter aus -f/--freq, -d/--min, -u/--max oder\n"
+"-g/--governor angegeben werden.\n"
+
+#: utils/cpufreq-set.c:347
+#, c-format
+msgid "Setting cpu: %d\n"
+msgstr ""
+
+#: utils/cpupower-set.c:22
+#, c-format
+msgid "Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:24
+#, c-format
+msgid ""
+"  -b, --perf-bias [VAL]    Sets CPU's power vs performance policy on some\n"
+"                           Intel models [0-15], see manpage for details\n"
+msgstr ""
+
+#: utils/cpupower-set.c:26
+#, c-format
+msgid ""
+"  -m, --sched-mc  [VAL]    Sets the kernel's multi core scheduler policy.\n"
+msgstr ""
+
+#: utils/cpupower-set.c:27
+#, c-format
+msgid ""
+"  -s, --sched-smt [VAL]    Sets the kernel's thread sibling scheduler "
+"policy.\n"
+msgstr ""
+
+#: utils/cpupower-set.c:80
+#, c-format
+msgid "--perf-bias param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:91
+#, c-format
+msgid "--sched-mc param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:102
+#, c-format
+msgid "--sched-smt param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:121
+#, c-format
+msgid "Error setting sched-mc %s\n"
+msgstr ""
+
+#: utils/cpupower-set.c:127
+#, c-format
+msgid "Error setting sched-smt %s\n"
+msgstr ""
+
+#: utils/cpupower-set.c:146
+#, c-format
+msgid "Error setting perf-bias value on CPU %d\n"
+msgstr ""
+
+#: utils/cpupower-info.c:21
+#, c-format
+msgid "Usage: cpupower info [ -b ] [ -m ] [ -s ]\n"
+msgstr ""
+
+#: utils/cpupower-info.c:23
+#, c-format
+msgid ""
+"  -b, --perf-bias    Gets CPU's power vs performance policy on some\n"
+"                           Intel models [0-15], see manpage for details\n"
+msgstr ""
+
+#: utils/cpupower-info.c:25
+#, fuzzy, c-format
+msgid "  -m, --sched-mc     Gets the kernel's multi core scheduler policy.\n"
+msgstr "  -p, --policy         Findet die momentane Taktik heraus *\n"
+
+#: utils/cpupower-info.c:26
+#, c-format
+msgid ""
+"  -s, --sched-smt    Gets the kernel's thread sibling scheduler policy.\n"
+msgstr ""
+
+#: utils/cpupower-info.c:28
+#, c-format
+msgid ""
+"\n"
+"Passing no option will show all info, by default only on core 0\n"
+msgstr ""
+
+#: utils/cpupower-info.c:102
+#, c-format
+msgid "System's multi core scheduler setting: "
+msgstr ""
+
+#. if sysfs file is missing it's: errno == ENOENT
+#: utils/cpupower-info.c:105 utils/cpupower-info.c:114
+#, c-format
+msgid "not supported\n"
+msgstr ""
+
+#: utils/cpupower-info.c:111
+#, c-format
+msgid "System's thread sibling scheduler setting: "
+msgstr ""
+
+#: utils/cpupower-info.c:126
+#, c-format
+msgid "Intel's performance bias setting needs root privileges\n"
+msgstr ""
+
+#: utils/cpupower-info.c:128
+#, c-format
+msgid "System does not support Intel's performance bias setting\n"
+msgstr ""
+
+#: utils/cpupower-info.c:147
+#, c-format
+msgid "Could not read perf-bias value\n"
+msgstr ""
+
+#: utils/cpupower-info.c:150
+#, c-format
+msgid "perf-bias: %d\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:28
+#, fuzzy, c-format
+msgid "Analyzing CPU %d:\n"
+msgstr "analysiere CPU %d:\n"
+
+#: utils/cpuidle-info.c:32
+#, c-format
+msgid "CPU %u: No idle states\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:36
+#, c-format
+msgid "CPU %u: Can't read idle state info\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:41
+#, c-format
+msgid "Could not determine max idle state %u\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:46
+#, c-format
+msgid "Number of idle states: %d\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:48
+#, fuzzy, c-format
+msgid "Available idle states:"
+msgstr "  mögliche Taktfrequenzen: "
+
+#: utils/cpuidle-info.c:71
+#, c-format
+msgid "Flags/Description: %s\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:74
+#, c-format
+msgid "Latency: %lu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:76
+#, c-format
+msgid "Usage: %lu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:78
+#, c-format
+msgid "Duration: %llu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:90
+#, c-format
+msgid "Could not determine cpuidle driver\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:94
+#, fuzzy, c-format
+msgid "CPUidle driver: %s\n"
+msgstr "  Treiber: %s\n"
+
+#: utils/cpuidle-info.c:99
+#, c-format
+msgid "Could not determine cpuidle governor\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:103
+#, c-format
+msgid "CPUidle governor: %s\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:122
+#, c-format
+msgid "CPU %u: Can't read C-state info\n"
+msgstr ""
+
+#. printf("Cstates: %d\n", cstates);
+#: utils/cpuidle-info.c:127
+#, c-format
+msgid "active state:            C0\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:128
+#, c-format
+msgid "max_cstate:              C%u\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:129
+#, fuzzy, c-format
+msgid "maximum allowed latency: %lu usec\n"
+msgstr "  Maximale Dauer eines Taktfrequenzwechsels: "
+
+#: utils/cpuidle-info.c:130
+#, c-format
+msgid "states:\t\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:132
+#, c-format
+msgid "    C%d:                  type[C%d] "
+msgstr ""
+
+#: utils/cpuidle-info.c:134
+#, c-format
+msgid "promotion[--] demotion[--] "
+msgstr ""
+
+#: utils/cpuidle-info.c:135
+#, c-format
+msgid "latency[%03lu] "
+msgstr ""
+
+#: utils/cpuidle-info.c:137
+#, c-format
+msgid "usage[%08lu] "
+msgstr ""
+
+#: utils/cpuidle-info.c:139
+#, c-format
+msgid "duration[%020Lu] \n"
+msgstr ""
+
+#: utils/cpuidle-info.c:147
+#, fuzzy, c-format
+msgid "Usage: cpupower idleinfo [options]\n"
+msgstr "Aufruf: cpufreq-info [Optionen]\n"
+
+#: utils/cpuidle-info.c:149
+#, fuzzy, c-format
+msgid "  -s, --silent         Only show general C-state information\n"
+msgstr ""
+"  -e, --debug          Erzeugt detaillierte Informationen, hilfreich\n"
+"                       zum Aufspüren von Fehlern\n"
+
+#: utils/cpuidle-info.c:150
+#, fuzzy, c-format
+msgid ""
+"  -o, --proc           Prints out information like provided by the /proc/"
+"acpi/processor/*/power\n"
+"                       interface in older kernels\n"
+msgstr ""
+"  -o, --proc           Erzeugt Informationen in einem ähnlichem Format zu "
+"dem\n"
+"                       der /proc/cpufreq-Datei in 2.4. und frühen 2.6.\n"
+"                       Kernel-Versionen\n"
+
+#: utils/cpuidle-info.c:209
+#, fuzzy, c-format
+msgid "You can't specify more than one output-specific argument\n"
+msgstr ""
+"Man kann nicht mehr als einen --cpu-Parameter und/oder mehr als einen\n"
+"informationsspezifischen Parameter gleichzeitig angeben\n"
+
+#~ msgid ""
+#~ "  -c CPU, --cpu CPU    CPU number which information shall be determined "
+#~ "about\n"
+#~ msgstr ""
+#~ "  -c CPU, --cpu CPU    Nummer der CPU, über die Informationen "
+#~ "herausgefunden werden sollen\n"
+
+#~ msgid ""
+#~ "  -c CPU, --cpu CPU        number of CPU where cpufreq settings shall be "
+#~ "modified\n"
+#~ msgstr ""
+#~ "  -c CPU, --cpu CPU        Nummer der CPU, deren Taktfrequenz-"
+#~ "Einstellung\n"
+#~ "                           werden soll\n"
diff --git a/tools/power/cpupower/po/fr.po b/tools/power/cpupower/po/fr.po
new file mode 100644 (file)
index 0000000..245ad20
--- /dev/null
@@ -0,0 +1,947 @@
+# French translations for cpufrequtils package
+# Copyright (C) 2004 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the cpufrequtils package.
+# Ducrot Bruno <ducrot@poupinou.org>, 2004.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: cpufrequtils 0.1-pre2\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-03-08 17:03+0100\n"
+"PO-Revision-Date: 2004-11-17 15:53+1000\n"
+"Last-Translator: Bruno Ducrot <ducrot@poupinou.org>\n"
+"Language-Team: NONE\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: utils/idle_monitor/nhm_idle.c:36
+msgid "Processor Core C3"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:43
+msgid "Processor Core C6"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:51
+msgid "Processor Package C3"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:58 utils/idle_monitor/amd_fam14h_idle.c:70
+msgid "Processor Package C6"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:33
+msgid "Processor Core C7"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:40
+msgid "Processor Package C2"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:47
+msgid "Processor Package C7"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:56
+msgid "Package in sleep state (PC1 or deeper)"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:63
+msgid "Processor Package C1"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:77
+msgid "North Bridge P1 boolean counter (returns 0 or 1)"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:35
+msgid "Processor Core not idle"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:42
+msgid "Processor Core in an idle state"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:50
+msgid "Average Frequency (including boost) in MHz"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:66
+#, c-format
+msgid ""
+"cpupower monitor: [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
+"interval_sec | -c command ...]\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:69
+#, c-format
+msgid ""
+"cpupower monitor: [-v] [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
+"interval_sec | -c command ...]\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:71
+#, c-format
+msgid "\t -v: be more verbose\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:73
+#, c-format
+msgid "\t -h: print this help\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:74
+#, c-format
+msgid "\t -i: time intervall to measure for in seconds (default 1)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:75
+#, c-format
+msgid "\t -t: show CPU topology/hierarchy\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:76
+#, c-format
+msgid "\t -l: list available CPU sleep monitors (for use with -m)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:77
+#, c-format
+msgid "\t -m: show specific CPU sleep monitors only (in same order)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:79
+#, c-format
+msgid ""
+"only one of: -t, -l, -m are allowed\n"
+"If none of them is passed,"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:80
+#, c-format
+msgid " all supported monitors are shown\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:197
+#, c-format
+msgid "Monitor %s, Counter %s has no count function. Implementation error\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:207
+#, c-format
+msgid " *is offline\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:236
+#, c-format
+msgid "%s: max monitor name length (%d) exceeded\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:250
+#, c-format
+msgid "No matching monitor found in %s, try -l option\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:266
+#, c-format
+msgid "Monitor \"%s\" (%d states) - Might overflow after %u s\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:319
+#, c-format
+msgid "%s took %.5f seconds and exited with status %d\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:406
+#, c-format
+msgid "Cannot read number of available processors\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:417
+#, c-format
+msgid "Available monitor %s needs root access\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:428
+#, c-format
+msgid "No HW Cstate monitors found\n"
+msgstr ""
+
+#: utils/cpupower.c:78
+#, c-format
+msgid "cpupower [ -c cpulist ] subcommand [ARGS]\n"
+msgstr ""
+
+#: utils/cpupower.c:79
+#, c-format
+msgid "cpupower --version\n"
+msgstr ""
+
+#: utils/cpupower.c:80
+#, c-format
+msgid "Supported subcommands are:\n"
+msgstr ""
+
+#: utils/cpupower.c:83
+#, c-format
+msgid ""
+"\n"
+"Some subcommands can make use of the -c cpulist option.\n"
+msgstr ""
+
+#: utils/cpupower.c:84
+#, c-format
+msgid "Look at the general cpupower manpage how to use it\n"
+msgstr ""
+
+#: utils/cpupower.c:85
+#, c-format
+msgid "and read up the subcommand's manpage whether it is supported.\n"
+msgstr ""
+
+#: utils/cpupower.c:86
+#, c-format
+msgid ""
+"\n"
+"Use cpupower help subcommand for getting help for above subcommands.\n"
+msgstr ""
+
+#: utils/cpupower.c:91
+#, c-format
+msgid "Report errors and bugs to %s, please.\n"
+msgstr "Veuillez rapportez les erreurs et les bogues à %s, s'il vous plait.\n"
+
+#: utils/cpupower.c:114
+#, c-format
+msgid "Error parsing cpu list\n"
+msgstr ""
+
+#: utils/cpupower.c:172
+#, c-format
+msgid "Subcommand %s needs root privileges\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:31
+#, c-format
+msgid "Couldn't count the number of CPUs (%s: %s), assuming 1\n"
+msgstr "Détermination du nombre de CPUs (%s : %s) impossible.  Assume 1\n"
+
+#: utils/cpufreq-info.c:63
+#, c-format
+msgid ""
+"          minimum CPU frequency  -  maximum CPU frequency  -  governor\n"
+msgstr ""
+"         Fréquence CPU minimale - Fréquence CPU maximale  - régulateur\n"
+
+#: utils/cpufreq-info.c:151
+#, c-format
+msgid "Error while evaluating Boost Capabilities on CPU %d -- are you root?\n"
+msgstr ""
+
+#. P state changes via MSR are identified via cpuid 80000007
+#. on Intel and AMD, but we assume boost capable machines can do that
+#. if (cpuid_eax(0x80000000) >= 0x80000007
+#. && (cpuid_edx(0x80000007) & (1 << 7)))
+#.
+#: utils/cpufreq-info.c:161
+#, c-format
+msgid "  boost state support: \n"
+msgstr ""
+
+#: utils/cpufreq-info.c:163
+#, c-format
+msgid "    Supported: %s\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164
+msgid "yes"
+msgstr ""
+
+#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164
+msgid "no"
+msgstr ""
+
+#: utils/cpufreq-info.c:164
+#, fuzzy, c-format
+msgid "    Active: %s\n"
+msgstr "  pilote : %s\n"
+
+#: utils/cpufreq-info.c:177
+#, c-format
+msgid "    Boost States: %d\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:178
+#, c-format
+msgid "    Total States: %d\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:181
+#, c-format
+msgid "    Pstate-Pb%d: %luMHz (boost state)\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:184
+#, c-format
+msgid "    Pstate-P%d:  %luMHz\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:211
+#, c-format
+msgid "  no or unknown cpufreq driver is active on this CPU\n"
+msgstr "  pas de pilotes cpufreq reconnu pour ce CPU\n"
+
+#: utils/cpufreq-info.c:213
+#, c-format
+msgid "  driver: %s\n"
+msgstr "  pilote : %s\n"
+
+#: utils/cpufreq-info.c:219
+#, fuzzy, c-format
+msgid "  CPUs which run at the same hardware frequency: "
+msgstr "  CPUs qui doivent changer de fréquences en même temps : "
+
+#: utils/cpufreq-info.c:230
+#, fuzzy, c-format
+msgid "  CPUs which need to have their frequency coordinated by software: "
+msgstr "  CPUs qui doivent changer de fréquences en même temps : "
+
+#: utils/cpufreq-info.c:241
+#, c-format
+msgid "  maximum transition latency: "
+msgstr ""
+
+#: utils/cpufreq-info.c:247
+#, c-format
+msgid "  hardware limits: "
+msgstr "  limitation matérielle : "
+
+#: utils/cpufreq-info.c:256
+#, c-format
+msgid "  available frequency steps: "
+msgstr "  plage de fréquence : "
+
+#: utils/cpufreq-info.c:269
+#, c-format
+msgid "  available cpufreq governors: "
+msgstr "  régulateurs disponibles : "
+
+#: utils/cpufreq-info.c:280
+#, c-format
+msgid "  current policy: frequency should be within "
+msgstr "  tactique actuelle : la fréquence doit être comprise entre "
+
+#: utils/cpufreq-info.c:282
+#, c-format
+msgid " and "
+msgstr " et "
+
+#: utils/cpufreq-info.c:286
+#, c-format
+msgid ""
+"The governor \"%s\" may decide which speed to use\n"
+"                  within this range.\n"
+msgstr ""
+"Le régulateur \"%s\" est libre de choisir la vitesse\n"
+"                  dans cette plage de fréquences.\n"
+
+#: utils/cpufreq-info.c:293
+#, c-format
+msgid "  current CPU frequency is "
+msgstr "  la fréquence actuelle de ce CPU est "
+
+#: utils/cpufreq-info.c:296
+#, c-format
+msgid " (asserted by call to hardware)"
+msgstr " (vérifié par un appel direct du matériel)"
+
+#: utils/cpufreq-info.c:304
+#, c-format
+msgid "  cpufreq stats: "
+msgstr "  des statistique concernant cpufreq:"
+
+#: utils/cpufreq-info.c:472
+#, fuzzy, c-format
+msgid "Usage: cpupower freqinfo [options]\n"
+msgstr "Usage : cpufreq-info [options]\n"
+
+#: utils/cpufreq-info.c:473 utils/cpufreq-set.c:26 utils/cpupower-set.c:23
+#: utils/cpupower-info.c:22 utils/cpuidle-info.c:148
+#, c-format
+msgid "Options:\n"
+msgstr "Options :\n"
+
+#: utils/cpufreq-info.c:474
+#, fuzzy, c-format
+msgid "  -e, --debug          Prints out debug information [default]\n"
+msgstr "  -e, --debug          Afficher les informations de déboguage\n"
+
+#: utils/cpufreq-info.c:475
+#, c-format
+msgid ""
+"  -f, --freq           Get frequency the CPU currently runs at, according\n"
+"                       to the cpufreq core *\n"
+msgstr ""
+"  -f, --freq           Obtenir la fréquence actuelle du CPU selon le point\n"
+"                       de vue du coeur du système de cpufreq *\n"
+
+#: utils/cpufreq-info.c:477
+#, c-format
+msgid ""
+"  -w, --hwfreq         Get frequency the CPU currently runs at, by reading\n"
+"                       it from hardware (only available to root) *\n"
+msgstr ""
+"  -w, --hwfreq         Obtenir la fréquence actuelle du CPU directement par\n"
+"                       le matériel (doit être root) *\n"
+
+#: utils/cpufreq-info.c:479
+#, c-format
+msgid ""
+"  -l, --hwlimits       Determine the minimum and maximum CPU frequency "
+"allowed *\n"
+msgstr ""
+"  -l, --hwlimits       Affiche les fréquences minimales et maximales du CPU "
+"*\n"
+
+#: utils/cpufreq-info.c:480
+#, c-format
+msgid "  -d, --driver         Determines the used cpufreq kernel driver *\n"
+msgstr "  -d, --driver         Affiche le pilote cpufreq utilisé *\n"
+
+#: utils/cpufreq-info.c:481
+#, c-format
+msgid "  -p, --policy         Gets the currently used cpufreq policy *\n"
+msgstr "  -p, --policy         Affiche la tactique actuelle de cpufreq *\n"
+
+#: utils/cpufreq-info.c:482
+#, c-format
+msgid "  -g, --governors      Determines available cpufreq governors *\n"
+msgstr ""
+"  -g, --governors      Affiche les régulateurs disponibles de cpufreq *\n"
+
+#: utils/cpufreq-info.c:483
+#, fuzzy, c-format
+msgid ""
+"  -r, --related-cpus   Determines which CPUs run at the same hardware "
+"frequency *\n"
+msgstr ""
+"  -a, --affected-cpus   Affiche quels sont les CPUs qui doivent changer de\n"
+"                        fréquences en même temps *\n"
+
+#: utils/cpufreq-info.c:484
+#, fuzzy, c-format
+msgid ""
+"  -a, --affected-cpus  Determines which CPUs need to have their frequency\n"
+"                       coordinated by software *\n"
+msgstr ""
+"  -a, --affected-cpus   Affiche quels sont les CPUs qui doivent changer de\n"
+"                        fréquences en même temps *\n"
+
+#: utils/cpufreq-info.c:486
+#, c-format
+msgid "  -s, --stats          Shows cpufreq statistics if available\n"
+msgstr ""
+"  -s, --stats          Indique des statistiques concernant cpufreq, si\n"
+"                       disponibles\n"
+
+#: utils/cpufreq-info.c:487
+#, fuzzy, c-format
+msgid ""
+"  -y, --latency        Determines the maximum latency on CPU frequency "
+"changes *\n"
+msgstr ""
+"  -l, --hwlimits       Affiche les fréquences minimales et maximales du CPU "
+"*\n"
+
+#: utils/cpufreq-info.c:488
+#, c-format
+msgid "  -b, --boost          Checks for turbo or boost modes  *\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:489
+#, c-format
+msgid ""
+"  -o, --proc           Prints out information like provided by the /proc/"
+"cpufreq\n"
+"                       interface in 2.4. and early 2.6. kernels\n"
+msgstr ""
+"  -o, --proc           Affiche les informations en utilisant l'interface\n"
+"                       fournie par /proc/cpufreq, présente dans les "
+"versions\n"
+"                       2.4 et les anciennes versions 2.6 du noyau\n"
+
+#: utils/cpufreq-info.c:491
+#, fuzzy, c-format
+msgid ""
+"  -m, --human          human-readable output for the -f, -w, -s and -y "
+"parameters\n"
+msgstr ""
+"  -m, --human           affiche dans un format lisible pour un humain\n"
+"                        pour les options -f, -w et -s (MHz, GHz)\n"
+
+#: utils/cpufreq-info.c:492 utils/cpuidle-info.c:152
+#, c-format
+msgid "  -h, --help           Prints out this screen\n"
+msgstr "  -h, --help           affiche l'aide-mémoire\n"
+
+#: utils/cpufreq-info.c:495
+#, c-format
+msgid ""
+"If no argument or only the -c, --cpu parameter is given, debug output about\n"
+"cpufreq is printed which is useful e.g. for reporting bugs.\n"
+msgstr ""
+"Par défaut, les informations de déboguage seront affichées si aucun\n"
+"argument, ou bien si seulement l'argument -c (--cpu) est donné, afin de\n"
+"faciliter les rapports de bogues par exemple\n"
+
+#: utils/cpufreq-info.c:497
+#, c-format
+msgid ""
+"For the arguments marked with *, omitting the -c or --cpu argument is\n"
+"equivalent to setting it to zero\n"
+msgstr "Les arguments avec un * utiliseront le CPU 0 si -c (--cpu) est omis\n"
+
+#: utils/cpufreq-info.c:580
+#, c-format
+msgid ""
+"The argument passed to this tool can't be combined with passing a --cpu "
+"argument\n"
+msgstr "Cette option est incompatible avec --cpu\n"
+
+#: utils/cpufreq-info.c:596
+#, c-format
+msgid ""
+"You can't specify more than one --cpu parameter and/or\n"
+"more than one output-specific argument\n"
+msgstr ""
+"On ne peut indiquer plus d'un paramètre --cpu, tout comme l'on ne peut\n"
+"spécifier plus d'un argument de formatage\n"
+
+#: utils/cpufreq-info.c:600 utils/cpufreq-set.c:82 utils/cpupower-set.c:42
+#: utils/cpupower-info.c:42 utils/cpuidle-info.c:213
+#, c-format
+msgid "invalid or unknown argument\n"
+msgstr "option invalide\n"
+
+#: utils/cpufreq-info.c:617
+#, c-format
+msgid "couldn't analyze CPU %d as it doesn't seem to be present\n"
+msgstr "analyse du CPU %d impossible puisqu'il ne semble pas être présent\n"
+
+#: utils/cpufreq-info.c:620 utils/cpupower-info.c:142
+#, c-format
+msgid "analyzing CPU %d:\n"
+msgstr "analyse du CPU %d :\n"
+
+#: utils/cpufreq-set.c:25
+#, fuzzy, c-format
+msgid "Usage: cpupower frequency-set [options]\n"
+msgstr "Usage : cpufreq-set [options]\n"
+
+#: utils/cpufreq-set.c:27
+#, c-format
+msgid ""
+"  -d FREQ, --min FREQ      new minimum CPU frequency the governor may "
+"select\n"
+msgstr ""
+"  -d FREQ, --min FREQ       nouvelle fréquence minimale du CPU à utiliser\n"
+"                            par le régulateur\n"
+
+#: utils/cpufreq-set.c:28
+#, c-format
+msgid ""
+"  -u FREQ, --max FREQ      new maximum CPU frequency the governor may "
+"select\n"
+msgstr ""
+"  -u FREQ, --max FREQ       nouvelle fréquence maximale du CPU à utiliser\n"
+"                            par le régulateur\n"
+
+#: utils/cpufreq-set.c:29
+#, c-format
+msgid "  -g GOV, --governor GOV   new cpufreq governor\n"
+msgstr "  -g GOV, --governor GOV   active le régulateur GOV\n"
+
+#: utils/cpufreq-set.c:30
+#, c-format
+msgid ""
+"  -f FREQ, --freq FREQ     specific frequency to be set. Requires userspace\n"
+"                           governor to be available and loaded\n"
+msgstr ""
+"  -f FREQ, --freq FREQ     fixe la fréquence du processeur à FREQ. Il faut\n"
+"                           que le régulateur « userspace » soit disponible \n"
+"                           et activé.\n"
+
+#: utils/cpufreq-set.c:32
+#, c-format
+msgid "  -r, --related            Switches all hardware-related CPUs\n"
+msgstr ""
+
+#: utils/cpufreq-set.c:33 utils/cpupower-set.c:28 utils/cpupower-info.c:27
+#, fuzzy, c-format
+msgid "  -h, --help               Prints out this screen\n"
+msgstr "  -h, --help           affiche l'aide-mémoire\n"
+
+#: utils/cpufreq-set.c:35
+#, fuzzy, c-format
+msgid ""
+"Notes:\n"
+"1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n"
+msgstr "Les arguments avec un * utiliseront le CPU 0 si -c (--cpu) est omis\n"
+
+#: utils/cpufreq-set.c:37
+#, fuzzy, c-format
+msgid ""
+"2. The -f FREQ, --freq FREQ parameter cannot be combined with any other "
+"parameter\n"
+"   except the -c CPU, --cpu CPU parameter\n"
+"3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n"
+"   by postfixing the value with the wanted unit name, without any space\n"
+"   (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n"
+msgstr ""
+"Remarque :\n"
+"1. Le CPU numéro 0 sera utilisé par défaut si -c (ou --cpu) est omis ;\n"
+"2. l'argument -f FREQ (ou --freq FREQ) ne peut être utilisé qu'avec --cpu ;\n"
+"3. on pourra préciser l'unité des fréquences en postfixant sans aucune "
+"espace\n"
+"   les valeurs par hz, kHz (par défaut), MHz, GHz ou THz\n"
+"   (kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n"
+
+#: utils/cpufreq-set.c:57
+#, c-format
+msgid ""
+"Error setting new values. Common errors:\n"
+"- Do you have proper administration rights? (super-user?)\n"
+"- Is the governor you requested available and modprobed?\n"
+"- Trying to set an invalid policy?\n"
+"- Trying to set a specific frequency, but userspace governor is not "
+"available,\n"
+"   for example because of hardware which cannot be set to a specific "
+"frequency\n"
+"   or because the userspace governor isn't loaded?\n"
+msgstr ""
+"En ajustant les nouveaux paramètres, une erreur est apparue. Les sources\n"
+"d'erreur typique sont :\n"
+"- droit d'administration insuffisant (êtes-vous root ?) ;\n"
+"- le régulateur choisi n'est pas disponible, ou bien n'est pas disponible "
+"en\n"
+"  tant que module noyau ;\n"
+"- la tactique n'est pas disponible ;\n"
+"- vous voulez utiliser l'option -f/--freq, mais le régulateur « userspace »\n"
+"  n'est pas disponible, par exemple parce que le matériel ne le supporte\n"
+"  pas, ou bien n'est tout simplement pas chargé.\n"
+
+#: utils/cpufreq-set.c:170
+#, c-format
+msgid "wrong, unknown or unhandled CPU?\n"
+msgstr "CPU inconnu ou non supporté ?\n"
+
+#: utils/cpufreq-set.c:302
+#, c-format
+msgid ""
+"the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n"
+"-g/--governor parameters\n"
+msgstr ""
+"l'option -f/--freq est incompatible avec les options -d/--min, -u/--max et\n"
+"-g/--governor\n"
+
+#: utils/cpufreq-set.c:308
+#, c-format
+msgid ""
+"At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n"
+"-g/--governor must be passed\n"
+msgstr ""
+"L'un de ces paramètres est obligatoire : -f/--freq, -d/--min, -u/--max et\n"
+"-g/--governor\n"
+
+#: utils/cpufreq-set.c:347
+#, c-format
+msgid "Setting cpu: %d\n"
+msgstr ""
+
+#: utils/cpupower-set.c:22
+#, c-format
+msgid "Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:24
+#, c-format
+msgid ""
+"  -b, --perf-bias [VAL]    Sets CPU's power vs performance policy on some\n"
+"                           Intel models [0-15], see manpage for details\n"
+msgstr ""
+
+#: utils/cpupower-set.c:26
+#, c-format
+msgid ""
+"  -m, --sched-mc  [VAL]    Sets the kernel's multi core scheduler policy.\n"
+msgstr ""
+
+#: utils/cpupower-set.c:27
+#, c-format
+msgid ""
+"  -s, --sched-smt [VAL]    Sets the kernel's thread sibling scheduler "
+"policy.\n"
+msgstr ""
+
+#: utils/cpupower-set.c:80
+#, c-format
+msgid "--perf-bias param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:91
+#, c-format
+msgid "--sched-mc param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:102
+#, c-format
+msgid "--sched-smt param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:121
+#, c-format
+msgid "Error setting sched-mc %s\n"
+msgstr ""
+
+#: utils/cpupower-set.c:127
+#, c-format
+msgid "Error setting sched-smt %s\n"
+msgstr ""
+
+#: utils/cpupower-set.c:146
+#, c-format
+msgid "Error setting perf-bias value on CPU %d\n"
+msgstr ""
+
+#: utils/cpupower-info.c:21
+#, c-format
+msgid "Usage: cpupower info [ -b ] [ -m ] [ -s ]\n"
+msgstr ""
+
+#: utils/cpupower-info.c:23
+#, c-format
+msgid ""
+"  -b, --perf-bias    Gets CPU's power vs performance policy on some\n"
+"                           Intel models [0-15], see manpage for details\n"
+msgstr ""
+
+#: utils/cpupower-info.c:25
+#, fuzzy, c-format
+msgid "  -m, --sched-mc     Gets the kernel's multi core scheduler policy.\n"
+msgstr "  -p, --policy         Affiche la tactique actuelle de cpufreq *\n"
+
+#: utils/cpupower-info.c:26
+#, c-format
+msgid ""
+"  -s, --sched-smt    Gets the kernel's thread sibling scheduler policy.\n"
+msgstr ""
+
+#: utils/cpupower-info.c:28
+#, c-format
+msgid ""
+"\n"
+"Passing no option will show all info, by default only on core 0\n"
+msgstr ""
+
+#: utils/cpupower-info.c:102
+#, c-format
+msgid "System's multi core scheduler setting: "
+msgstr ""
+
+#. if sysfs file is missing it's: errno == ENOENT
+#: utils/cpupower-info.c:105 utils/cpupower-info.c:114
+#, c-format
+msgid "not supported\n"
+msgstr ""
+
+#: utils/cpupower-info.c:111
+#, c-format
+msgid "System's thread sibling scheduler setting: "
+msgstr ""
+
+#: utils/cpupower-info.c:126
+#, c-format
+msgid "Intel's performance bias setting needs root privileges\n"
+msgstr ""
+
+#: utils/cpupower-info.c:128
+#, c-format
+msgid "System does not support Intel's performance bias setting\n"
+msgstr ""
+
+#: utils/cpupower-info.c:147
+#, c-format
+msgid "Could not read perf-bias value\n"
+msgstr ""
+
+#: utils/cpupower-info.c:150
+#, c-format
+msgid "perf-bias: %d\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:28
+#, fuzzy, c-format
+msgid "Analyzing CPU %d:\n"
+msgstr "analyse du CPU %d :\n"
+
+#: utils/cpuidle-info.c:32
+#, c-format
+msgid "CPU %u: No idle states\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:36
+#, c-format
+msgid "CPU %u: Can't read idle state info\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:41
+#, c-format
+msgid "Could not determine max idle state %u\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:46
+#, c-format
+msgid "Number of idle states: %d\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:48
+#, fuzzy, c-format
+msgid "Available idle states:"
+msgstr "  plage de fréquence : "
+
+#: utils/cpuidle-info.c:71
+#, c-format
+msgid "Flags/Description: %s\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:74
+#, c-format
+msgid "Latency: %lu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:76
+#, c-format
+msgid "Usage: %lu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:78
+#, c-format
+msgid "Duration: %llu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:90
+#, c-format
+msgid "Could not determine cpuidle driver\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:94
+#, fuzzy, c-format
+msgid "CPUidle driver: %s\n"
+msgstr "  pilote : %s\n"
+
+#: utils/cpuidle-info.c:99
+#, c-format
+msgid "Could not determine cpuidle governor\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:103
+#, c-format
+msgid "CPUidle governor: %s\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:122
+#, c-format
+msgid "CPU %u: Can't read C-state info\n"
+msgstr ""
+
+#. printf("Cstates: %d\n", cstates);
+#: utils/cpuidle-info.c:127
+#, c-format
+msgid "active state:            C0\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:128
+#, c-format
+msgid "max_cstate:              C%u\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:129
+#, c-format
+msgid "maximum allowed latency: %lu usec\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:130
+#, c-format
+msgid "states:\t\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:132
+#, c-format
+msgid "    C%d:                  type[C%d] "
+msgstr ""
+
+#: utils/cpuidle-info.c:134
+#, c-format
+msgid "promotion[--] demotion[--] "
+msgstr ""
+
+#: utils/cpuidle-info.c:135
+#, c-format
+msgid "latency[%03lu] "
+msgstr ""
+
+#: utils/cpuidle-info.c:137
+#, c-format
+msgid "usage[%08lu] "
+msgstr ""
+
+#: utils/cpuidle-info.c:139
+#, c-format
+msgid "duration[%020Lu] \n"
+msgstr ""
+
+#: utils/cpuidle-info.c:147
+#, fuzzy, c-format
+msgid "Usage: cpupower idleinfo [options]\n"
+msgstr "Usage : cpufreq-info [options]\n"
+
+#: utils/cpuidle-info.c:149
+#, fuzzy, c-format
+msgid "  -s, --silent         Only show general C-state information\n"
+msgstr "  -e, --debug          Afficher les informations de déboguage\n"
+
+#: utils/cpuidle-info.c:150
+#, fuzzy, c-format
+msgid ""
+"  -o, --proc           Prints out information like provided by the /proc/"
+"acpi/processor/*/power\n"
+"                       interface in older kernels\n"
+msgstr ""
+"  -o, --proc           Affiche les informations en utilisant l'interface\n"
+"                       fournie par /proc/cpufreq, présente dans les "
+"versions\n"
+"                       2.4 et les anciennes versions 2.6 du noyau\n"
+
+#: utils/cpuidle-info.c:209
+#, fuzzy, c-format
+msgid "You can't specify more than one output-specific argument\n"
+msgstr ""
+"On ne peut indiquer plus d'un paramètre --cpu, tout comme l'on ne peut\n"
+"spécifier plus d'un argument de formatage\n"
+
+#~ msgid ""
+#~ "  -c CPU, --cpu CPU    CPU number which information shall be determined "
+#~ "about\n"
+#~ msgstr ""
+#~ "  -c CPU, --cpu CPU    Numéro du CPU pour lequel l'information sera "
+#~ "affichée\n"
+
+#~ msgid ""
+#~ "  -c CPU, --cpu CPU        number of CPU where cpufreq settings shall be "
+#~ "modified\n"
+#~ msgstr ""
+#~ "  -c CPU, --cpu CPU        numéro du CPU à prendre en compte pour les\n"
+#~ "                           changements\n"
diff --git a/tools/power/cpupower/po/it.po b/tools/power/cpupower/po/it.po
new file mode 100644 (file)
index 0000000..f80c4dd
--- /dev/null
@@ -0,0 +1,961 @@
+# Italian translations for cpufrequtils package
+# Copyright (C) 2004-2009
+# This file is distributed under the same license as the cpufrequtils package.
+# Mattia Dongili <malattia@gmail.com>.
+#
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: cpufrequtils 0.3\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-03-08 17:03+0100\n"
+"PO-Revision-Date: 2009-08-15 12:00+0900\n"
+"Last-Translator: Mattia Dongili <malattia@gmail.com>\n"
+"Language-Team: NONE\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: utils/idle_monitor/nhm_idle.c:36
+msgid "Processor Core C3"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:43
+msgid "Processor Core C6"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:51
+msgid "Processor Package C3"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:58 utils/idle_monitor/amd_fam14h_idle.c:70
+msgid "Processor Package C6"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:33
+msgid "Processor Core C7"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:40
+msgid "Processor Package C2"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:47
+msgid "Processor Package C7"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:56
+msgid "Package in sleep state (PC1 or deeper)"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:63
+msgid "Processor Package C1"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:77
+msgid "North Bridge P1 boolean counter (returns 0 or 1)"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:35
+msgid "Processor Core not idle"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:42
+msgid "Processor Core in an idle state"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:50
+msgid "Average Frequency (including boost) in MHz"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:66
+#, c-format
+msgid ""
+"cpupower monitor: [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
+"interval_sec | -c command ...]\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:69
+#, c-format
+msgid ""
+"cpupower monitor: [-v] [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
+"interval_sec | -c command ...]\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:71
+#, c-format
+msgid "\t -v: be more verbose\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:73
+#, c-format
+msgid "\t -h: print this help\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:74
+#, c-format
+msgid "\t -i: time intervall to measure for in seconds (default 1)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:75
+#, c-format
+msgid "\t -t: show CPU topology/hierarchy\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:76
+#, c-format
+msgid "\t -l: list available CPU sleep monitors (for use with -m)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:77
+#, c-format
+msgid "\t -m: show specific CPU sleep monitors only (in same order)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:79
+#, c-format
+msgid ""
+"only one of: -t, -l, -m are allowed\n"
+"If none of them is passed,"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:80
+#, c-format
+msgid " all supported monitors are shown\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:197
+#, c-format
+msgid "Monitor %s, Counter %s has no count function. Implementation error\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:207
+#, c-format
+msgid " *is offline\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:236
+#, c-format
+msgid "%s: max monitor name length (%d) exceeded\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:250
+#, c-format
+msgid "No matching monitor found in %s, try -l option\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:266
+#, c-format
+msgid "Monitor \"%s\" (%d states) - Might overflow after %u s\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:319
+#, c-format
+msgid "%s took %.5f seconds and exited with status %d\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:406
+#, c-format
+msgid "Cannot read number of available processors\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:417
+#, c-format
+msgid "Available monitor %s needs root access\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:428
+#, c-format
+msgid "No HW Cstate monitors found\n"
+msgstr ""
+
+#: utils/cpupower.c:78
+#, c-format
+msgid "cpupower [ -c cpulist ] subcommand [ARGS]\n"
+msgstr ""
+
+#: utils/cpupower.c:79
+#, c-format
+msgid "cpupower --version\n"
+msgstr ""
+
+#: utils/cpupower.c:80
+#, c-format
+msgid "Supported subcommands are:\n"
+msgstr ""
+
+#: utils/cpupower.c:83
+#, c-format
+msgid ""
+"\n"
+"Some subcommands can make use of the -c cpulist option.\n"
+msgstr ""
+
+#: utils/cpupower.c:84
+#, c-format
+msgid "Look at the general cpupower manpage how to use it\n"
+msgstr ""
+
+#: utils/cpupower.c:85
+#, c-format
+msgid "and read up the subcommand's manpage whether it is supported.\n"
+msgstr ""
+
+#: utils/cpupower.c:86
+#, c-format
+msgid ""
+"\n"
+"Use cpupower help subcommand for getting help for above subcommands.\n"
+msgstr ""
+
+#: utils/cpupower.c:91
+#, c-format
+msgid "Report errors and bugs to %s, please.\n"
+msgstr "Per favore, comunicare errori e malfunzionamenti a %s.\n"
+
+#: utils/cpupower.c:114
+#, c-format
+msgid "Error parsing cpu list\n"
+msgstr ""
+
+#: utils/cpupower.c:172
+#, c-format
+msgid "Subcommand %s needs root privileges\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:31
+#, c-format
+msgid "Couldn't count the number of CPUs (%s: %s), assuming 1\n"
+msgstr "Impossibile determinare il numero di CPU (%s: %s), assumo sia 1\n"
+
+#: utils/cpufreq-info.c:63
+#, c-format
+msgid ""
+"          minimum CPU frequency  -  maximum CPU frequency  -  governor\n"
+msgstr ""
+"          frequenza minima CPU   -  frequenza massima CPU  -  gestore\n"
+
+#: utils/cpufreq-info.c:151
+#, c-format
+msgid "Error while evaluating Boost Capabilities on CPU %d -- are you root?\n"
+msgstr ""
+
+#. P state changes via MSR are identified via cpuid 80000007
+#. on Intel and AMD, but we assume boost capable machines can do that
+#. if (cpuid_eax(0x80000000) >= 0x80000007
+#. && (cpuid_edx(0x80000007) & (1 << 7)))
+#.
+#: utils/cpufreq-info.c:161
+#, c-format
+msgid "  boost state support: \n"
+msgstr ""
+
+#: utils/cpufreq-info.c:163
+#, c-format
+msgid "    Supported: %s\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164
+msgid "yes"
+msgstr ""
+
+#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164
+msgid "no"
+msgstr ""
+
+#: utils/cpufreq-info.c:164
+#, fuzzy, c-format
+msgid "    Active: %s\n"
+msgstr "  modulo %s\n"
+
+#: utils/cpufreq-info.c:177
+#, c-format
+msgid "    Boost States: %d\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:178
+#, c-format
+msgid "    Total States: %d\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:181
+#, c-format
+msgid "    Pstate-Pb%d: %luMHz (boost state)\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:184
+#, c-format
+msgid "    Pstate-P%d:  %luMHz\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:211
+#, c-format
+msgid "  no or unknown cpufreq driver is active on this CPU\n"
+msgstr "  nessun modulo o modulo cpufreq sconosciuto per questa CPU\n"
+
+#: utils/cpufreq-info.c:213
+#, c-format
+msgid "  driver: %s\n"
+msgstr "  modulo %s\n"
+
+#: utils/cpufreq-info.c:219
+#, c-format
+msgid "  CPUs which run at the same hardware frequency: "
+msgstr "  CPU che operano alla stessa frequenza hardware: "
+
+#: utils/cpufreq-info.c:230
+#, c-format
+msgid "  CPUs which need to have their frequency coordinated by software: "
+msgstr "  CPU che è necessario siano coordinate dal software: "
+
+#: utils/cpufreq-info.c:241
+#, c-format
+msgid "  maximum transition latency: "
+msgstr "  latenza massima durante la transizione: "
+
+#: utils/cpufreq-info.c:247
+#, c-format
+msgid "  hardware limits: "
+msgstr "  limiti hardware: "
+
+#: utils/cpufreq-info.c:256
+#, c-format
+msgid "  available frequency steps: "
+msgstr "  frequenze disponibili: "
+
+#: utils/cpufreq-info.c:269
+#, c-format
+msgid "  available cpufreq governors: "
+msgstr "  gestori disponibili: "
+
+#: utils/cpufreq-info.c:280
+#, c-format
+msgid "  current policy: frequency should be within "
+msgstr "  gestore attuale: la frequenza deve mantenersi tra "
+
+#: utils/cpufreq-info.c:282
+#, c-format
+msgid " and "
+msgstr " e "
+
+#: utils/cpufreq-info.c:286
+#, c-format
+msgid ""
+"The governor \"%s\" may decide which speed to use\n"
+"                  within this range.\n"
+msgstr ""
+" Il gestore \"%s\" può decidere quale velocità usare\n"
+"                  in questo intervallo.\n"
+
+#: utils/cpufreq-info.c:293
+#, c-format
+msgid "  current CPU frequency is "
+msgstr "  la frequenza attuale della CPU è "
+
+#: utils/cpufreq-info.c:296
+#, c-format
+msgid " (asserted by call to hardware)"
+msgstr " (ottenuta da una chiamata diretta all'hardware)"
+
+#: utils/cpufreq-info.c:304
+#, c-format
+msgid "  cpufreq stats: "
+msgstr " statistiche cpufreq:"
+
+#: utils/cpufreq-info.c:472
+#, fuzzy, c-format
+msgid "Usage: cpupower freqinfo [options]\n"
+msgstr "Uso: cpufreq-info [opzioni]\n"
+
+#: utils/cpufreq-info.c:473 utils/cpufreq-set.c:26 utils/cpupower-set.c:23
+#: utils/cpupower-info.c:22 utils/cpuidle-info.c:148
+#, c-format
+msgid "Options:\n"
+msgstr "Opzioni:\n"
+
+#: utils/cpufreq-info.c:474
+#, fuzzy, c-format
+msgid "  -e, --debug          Prints out debug information [default]\n"
+msgstr "  -e, --debug          Mostra informazioni di debug\n"
+
+#: utils/cpufreq-info.c:475
+#, c-format
+msgid ""
+"  -f, --freq           Get frequency the CPU currently runs at, according\n"
+"                       to the cpufreq core *\n"
+msgstr ""
+"  -f, --freq           Mostra la frequenza attuale della CPU secondo\n"
+"                       il modulo cpufreq *\n"
+
+#: utils/cpufreq-info.c:477
+#, c-format
+msgid ""
+"  -w, --hwfreq         Get frequency the CPU currently runs at, by reading\n"
+"                       it from hardware (only available to root) *\n"
+msgstr ""
+"  -w, --hwfreq         Mostra la frequenza attuale della CPU leggendola\n"
+"                       dall'hardware (disponibile solo per l'utente root) *\n"
+
+#: utils/cpufreq-info.c:479
+#, c-format
+msgid ""
+"  -l, --hwlimits       Determine the minimum and maximum CPU frequency "
+"allowed *\n"
+msgstr ""
+"  -l, --hwlimits       Determina le frequenze minima e massima possibili per "
+"la CPU *\n"
+
+#: utils/cpufreq-info.c:480
+#, c-format
+msgid "  -d, --driver         Determines the used cpufreq kernel driver *\n"
+msgstr ""
+"  -d, --driver         Determina il modulo cpufreq del kernel in uso *\n"
+
+#: utils/cpufreq-info.c:481
+#, c-format
+msgid "  -p, --policy         Gets the currently used cpufreq policy *\n"
+msgstr ""
+"  -p, --policy         Mostra il gestore cpufreq attualmente in uso *\n"
+
+#: utils/cpufreq-info.c:482
+#, c-format
+msgid "  -g, --governors      Determines available cpufreq governors *\n"
+msgstr "  -g, --governors      Determina i gestori cpufreq disponibili *\n"
+
+#: utils/cpufreq-info.c:483
+#, c-format
+msgid ""
+"  -r, --related-cpus   Determines which CPUs run at the same hardware "
+"frequency *\n"
+msgstr ""
+"  -r, --related-cpus   Determina quali CPU operano alla stessa frequenza *\n"
+
+#: utils/cpufreq-info.c:484
+#, c-format
+msgid ""
+"  -a, --affected-cpus  Determines which CPUs need to have their frequency\n"
+"                       coordinated by software *\n"
+msgstr ""
+"  -a, --affected-cpus  Determina quali CPU devono avere la frequenza\n"
+"                       coordinata dal software *\n"
+
+#: utils/cpufreq-info.c:486
+#, c-format
+msgid "  -s, --stats          Shows cpufreq statistics if available\n"
+msgstr "  -s, --stats          Mostra le statistiche se disponibili\n"
+
+#: utils/cpufreq-info.c:487
+#, c-format
+msgid ""
+"  -y, --latency        Determines the maximum latency on CPU frequency "
+"changes *\n"
+msgstr ""
+"  -y, --latency        Determina la latenza massima durante i cambi di "
+"frequenza *\n"
+
+#: utils/cpufreq-info.c:488
+#, c-format
+msgid "  -b, --boost          Checks for turbo or boost modes  *\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:489
+#, c-format
+msgid ""
+"  -o, --proc           Prints out information like provided by the /proc/"
+"cpufreq\n"
+"                       interface in 2.4. and early 2.6. kernels\n"
+msgstr ""
+"  -o, --proc           Stampa le informazioni come se provenissero dalla\n"
+"                       interfaccia cpufreq /proc/ presente nei kernel\n"
+"                       2.4 ed i primi 2.6\n"
+
+#: utils/cpufreq-info.c:491
+#, c-format
+msgid ""
+"  -m, --human          human-readable output for the -f, -w, -s and -y "
+"parameters\n"
+msgstr ""
+"  -m, --human          formatta l'output delle opzioni -f, -w, -s e -y in "
+"maniera\n"
+"                       leggibile da un essere umano\n"
+
+#: utils/cpufreq-info.c:492 utils/cpuidle-info.c:152
+#, c-format
+msgid "  -h, --help           Prints out this screen\n"
+msgstr "  -h, --help           Stampa questa schermata\n"
+
+#: utils/cpufreq-info.c:495
+#, c-format
+msgid ""
+"If no argument or only the -c, --cpu parameter is given, debug output about\n"
+"cpufreq is printed which is useful e.g. for reporting bugs.\n"
+msgstr ""
+"Se non viene specificata nessuna opzione o viene specificata solo l'opzione -"
+"c, --cpu,\n"
+"le informazioni di debug per cpufreq saranno utili ad esempio a riportare i "
+"bug.\n"
+
+#: utils/cpufreq-info.c:497
+#, c-format
+msgid ""
+"For the arguments marked with *, omitting the -c or --cpu argument is\n"
+"equivalent to setting it to zero\n"
+msgstr ""
+"Per le opzioni segnalate con *, omettere l'opzione -c o --cpu è come "
+"specificarla\n"
+"con il valore 0\n"
+
+#: utils/cpufreq-info.c:580
+#, c-format
+msgid ""
+"The argument passed to this tool can't be combined with passing a --cpu "
+"argument\n"
+msgstr ""
+"L'opzione specificata a questo programma non può essere combinata con --cpu\n"
+
+#: utils/cpufreq-info.c:596
+#, c-format
+msgid ""
+"You can't specify more than one --cpu parameter and/or\n"
+"more than one output-specific argument\n"
+msgstr ""
+"Non è possibile specificare più di una volta l'opzione --cpu e/o\n"
+"specificare più di un parametro di output specifico\n"
+
+#: utils/cpufreq-info.c:600 utils/cpufreq-set.c:82 utils/cpupower-set.c:42
+#: utils/cpupower-info.c:42 utils/cpuidle-info.c:213
+#, c-format
+msgid "invalid or unknown argument\n"
+msgstr "opzione sconosciuta o non valida\n"
+
+#: utils/cpufreq-info.c:617
+#, c-format
+msgid "couldn't analyze CPU %d as it doesn't seem to be present\n"
+msgstr "impossibile analizzare la CPU %d poiché non sembra essere presente\n"
+
+#: utils/cpufreq-info.c:620 utils/cpupower-info.c:142
+#, c-format
+msgid "analyzing CPU %d:\n"
+msgstr "analisi della CPU %d:\n"
+
+#: utils/cpufreq-set.c:25
+#, fuzzy, c-format
+msgid "Usage: cpupower frequency-set [options]\n"
+msgstr "Uso: cpufreq-set [opzioni]\n"
+
+#: utils/cpufreq-set.c:27
+#, c-format
+msgid ""
+"  -d FREQ, --min FREQ      new minimum CPU frequency the governor may "
+"select\n"
+msgstr ""
+"  -d FREQ, --min FREQ      la nuova frequenza minima che il gestore cpufreq "
+"può scegliere\n"
+
+#: utils/cpufreq-set.c:28
+#, c-format
+msgid ""
+"  -u FREQ, --max FREQ      new maximum CPU frequency the governor may "
+"select\n"
+msgstr ""
+"  -u FREQ, --max FREQ      la nuova frequenza massima che il gestore cpufreq "
+"può scegliere\n"
+
+#: utils/cpufreq-set.c:29
+#, c-format
+msgid "  -g GOV, --governor GOV   new cpufreq governor\n"
+msgstr "  -g GOV, --governor GOV   nuovo gestore cpufreq\n"
+
+#: utils/cpufreq-set.c:30
+#, c-format
+msgid ""
+"  -f FREQ, --freq FREQ     specific frequency to be set. Requires userspace\n"
+"                           governor to be available and loaded\n"
+msgstr ""
+"  -f FREQ, --freq FREQ     specifica la frequenza a cui impostare la CPU.\n"
+"                           È necessario che il gestore userspace sia "
+"disponibile e caricato\n"
+
+#: utils/cpufreq-set.c:32
+#, c-format
+msgid "  -r, --related            Switches all hardware-related CPUs\n"
+msgstr ""
+"  -r, --related            Modifica tutte le CPU coordinate dall'hardware\n"
+
+#: utils/cpufreq-set.c:33 utils/cpupower-set.c:28 utils/cpupower-info.c:27
+#, c-format
+msgid "  -h, --help               Prints out this screen\n"
+msgstr "  -h, --help               Stampa questa schermata\n"
+
+#: utils/cpufreq-set.c:35
+#, fuzzy, c-format
+msgid ""
+"Notes:\n"
+"1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n"
+msgstr ""
+"Per le opzioni segnalate con *, omettere l'opzione -c o --cpu è come "
+"specificarla\n"
+"con il valore 0\n"
+
+#: utils/cpufreq-set.c:37
+#, fuzzy, c-format
+msgid ""
+"2. The -f FREQ, --freq FREQ parameter cannot be combined with any other "
+"parameter\n"
+"   except the -c CPU, --cpu CPU parameter\n"
+"3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n"
+"   by postfixing the value with the wanted unit name, without any space\n"
+"   (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n"
+msgstr ""
+"Note:\n"
+"1. Omettere l'opzione -c o --cpu è equivalente a impostarlo a 0\n"
+"2. l'opzione -f FREQ, --freq FREQ non può essere specificata con altre "
+"opzioni\n"
+"   ad eccezione dell'opzione -c CPU o --cpu CPU\n"
+"3. le FREQuenze possono essere specuficate in  Hz, kHz (default), MHz, GHz, "
+"or THz\n"
+"   postponendo l'unità di misura al valore senza nessuno spazio fra loro\n"
+"   (FREQuenza in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n"
+
+#: utils/cpufreq-set.c:57
+#, c-format
+msgid ""
+"Error setting new values. Common errors:\n"
+"- Do you have proper administration rights? (super-user?)\n"
+"- Is the governor you requested available and modprobed?\n"
+"- Trying to set an invalid policy?\n"
+"- Trying to set a specific frequency, but userspace governor is not "
+"available,\n"
+"   for example because of hardware which cannot be set to a specific "
+"frequency\n"
+"   or because the userspace governor isn't loaded?\n"
+msgstr ""
+"Si sono verificati degli errori impostando i nuovi valori.\n"
+"Alcuni errori comuni possono essere:\n"
+"- Hai i necessari diritti di amministrazione? (super-user?)\n"
+"- Il gestore che hai richiesto è disponibile e caricato?\n"
+"- Stai provando ad impostare una politica di gestione non valida?\n"
+"- Stai provando a impostare una specifica frequenza ma il gestore\n"
+"  userspace non è disponibile, per esempio a causa dell'hardware\n"
+"  che non supporta frequenze fisse o a causa del fatto che\n"
+"  il gestore userspace non è caricato?\n"
+
+#: utils/cpufreq-set.c:170
+#, c-format
+msgid "wrong, unknown or unhandled CPU?\n"
+msgstr "CPU errata, sconosciuta o non gestita?\n"
+
+#: utils/cpufreq-set.c:302
+#, c-format
+msgid ""
+"the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n"
+"-g/--governor parameters\n"
+msgstr ""
+"l'opzione -f/--freq non può venire combinata con i parametri\n"
+" -d/--min, -u/--max o -g/--governor\n"
+
+#: utils/cpufreq-set.c:308
+#, c-format
+msgid ""
+"At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n"
+"-g/--governor must be passed\n"
+msgstr ""
+"Almeno una delle opzioni -f/--freq, -d/--min, -u/--max, e -g/--governor\n"
+"deve essere specificata\n"
+
+#: utils/cpufreq-set.c:347
+#, c-format
+msgid "Setting cpu: %d\n"
+msgstr ""
+
+#: utils/cpupower-set.c:22
+#, c-format
+msgid "Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:24
+#, c-format
+msgid ""
+"  -b, --perf-bias [VAL]    Sets CPU's power vs performance policy on some\n"
+"                           Intel models [0-15], see manpage for details\n"
+msgstr ""
+
+#: utils/cpupower-set.c:26
+#, c-format
+msgid ""
+"  -m, --sched-mc  [VAL]    Sets the kernel's multi core scheduler policy.\n"
+msgstr ""
+
+#: utils/cpupower-set.c:27
+#, c-format
+msgid ""
+"  -s, --sched-smt [VAL]    Sets the kernel's thread sibling scheduler "
+"policy.\n"
+msgstr ""
+
+#: utils/cpupower-set.c:80
+#, c-format
+msgid "--perf-bias param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:91
+#, c-format
+msgid "--sched-mc param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:102
+#, c-format
+msgid "--sched-smt param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:121
+#, c-format
+msgid "Error setting sched-mc %s\n"
+msgstr ""
+
+#: utils/cpupower-set.c:127
+#, c-format
+msgid "Error setting sched-smt %s\n"
+msgstr ""
+
+#: utils/cpupower-set.c:146
+#, c-format
+msgid "Error setting perf-bias value on CPU %d\n"
+msgstr ""
+
+#: utils/cpupower-info.c:21
+#, c-format
+msgid "Usage: cpupower info [ -b ] [ -m ] [ -s ]\n"
+msgstr ""
+
+#: utils/cpupower-info.c:23
+#, c-format
+msgid ""
+"  -b, --perf-bias    Gets CPU's power vs performance policy on some\n"
+"                           Intel models [0-15], see manpage for details\n"
+msgstr ""
+
+#: utils/cpupower-info.c:25
+#, fuzzy, c-format
+msgid "  -m, --sched-mc     Gets the kernel's multi core scheduler policy.\n"
+msgstr ""
+"  -p, --policy         Mostra il gestore cpufreq attualmente in uso *\n"
+
+#: utils/cpupower-info.c:26
+#, c-format
+msgid ""
+"  -s, --sched-smt    Gets the kernel's thread sibling scheduler policy.\n"
+msgstr ""
+
+#: utils/cpupower-info.c:28
+#, c-format
+msgid ""
+"\n"
+"Passing no option will show all info, by default only on core 0\n"
+msgstr ""
+
+#: utils/cpupower-info.c:102
+#, c-format
+msgid "System's multi core scheduler setting: "
+msgstr ""
+
+#. if sysfs file is missing it's: errno == ENOENT
+#: utils/cpupower-info.c:105 utils/cpupower-info.c:114
+#, c-format
+msgid "not supported\n"
+msgstr ""
+
+#: utils/cpupower-info.c:111
+#, c-format
+msgid "System's thread sibling scheduler setting: "
+msgstr ""
+
+#: utils/cpupower-info.c:126
+#, c-format
+msgid "Intel's performance bias setting needs root privileges\n"
+msgstr ""
+
+#: utils/cpupower-info.c:128
+#, c-format
+msgid "System does not support Intel's performance bias setting\n"
+msgstr ""
+
+#: utils/cpupower-info.c:147
+#, c-format
+msgid "Could not read perf-bias value\n"
+msgstr ""
+
+#: utils/cpupower-info.c:150
+#, c-format
+msgid "perf-bias: %d\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:28
+#, fuzzy, c-format
+msgid "Analyzing CPU %d:\n"
+msgstr "analisi della CPU %d:\n"
+
+#: utils/cpuidle-info.c:32
+#, c-format
+msgid "CPU %u: No idle states\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:36
+#, c-format
+msgid "CPU %u: Can't read idle state info\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:41
+#, c-format
+msgid "Could not determine max idle state %u\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:46
+#, c-format
+msgid "Number of idle states: %d\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:48
+#, fuzzy, c-format
+msgid "Available idle states:"
+msgstr "  frequenze disponibili: "
+
+#: utils/cpuidle-info.c:71
+#, c-format
+msgid "Flags/Description: %s\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:74
+#, c-format
+msgid "Latency: %lu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:76
+#, c-format
+msgid "Usage: %lu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:78
+#, c-format
+msgid "Duration: %llu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:90
+#, c-format
+msgid "Could not determine cpuidle driver\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:94
+#, fuzzy, c-format
+msgid "CPUidle driver: %s\n"
+msgstr "  modulo %s\n"
+
+#: utils/cpuidle-info.c:99
+#, c-format
+msgid "Could not determine cpuidle governor\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:103
+#, c-format
+msgid "CPUidle governor: %s\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:122
+#, c-format
+msgid "CPU %u: Can't read C-state info\n"
+msgstr ""
+
+#. printf("Cstates: %d\n", cstates);
+#: utils/cpuidle-info.c:127
+#, c-format
+msgid "active state:            C0\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:128
+#, c-format
+msgid "max_cstate:              C%u\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:129
+#, fuzzy, c-format
+msgid "maximum allowed latency: %lu usec\n"
+msgstr "  latenza massima durante la transizione: "
+
+#: utils/cpuidle-info.c:130
+#, c-format
+msgid "states:\t\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:132
+#, c-format
+msgid "    C%d:                  type[C%d] "
+msgstr ""
+
+#: utils/cpuidle-info.c:134
+#, c-format
+msgid "promotion[--] demotion[--] "
+msgstr ""
+
+#: utils/cpuidle-info.c:135
+#, c-format
+msgid "latency[%03lu] "
+msgstr ""
+
+#: utils/cpuidle-info.c:137
+#, c-format
+msgid "usage[%08lu] "
+msgstr ""
+
+#: utils/cpuidle-info.c:139
+#, c-format
+msgid "duration[%020Lu] \n"
+msgstr ""
+
+#: utils/cpuidle-info.c:147
+#, fuzzy, c-format
+msgid "Usage: cpupower idleinfo [options]\n"
+msgstr "Uso: cpufreq-info [opzioni]\n"
+
+#: utils/cpuidle-info.c:149
+#, fuzzy, c-format
+msgid "  -s, --silent         Only show general C-state information\n"
+msgstr "  -e, --debug          Mostra informazioni di debug\n"
+
+#: utils/cpuidle-info.c:150
+#, fuzzy, c-format
+msgid ""
+"  -o, --proc           Prints out information like provided by the /proc/"
+"acpi/processor/*/power\n"
+"                       interface in older kernels\n"
+msgstr ""
+"  -o, --proc           Stampa le informazioni come se provenissero dalla\n"
+"                       interfaccia cpufreq /proc/ presente nei kernel\n"
+"                       2.4 ed i primi 2.6\n"
+
+#: utils/cpuidle-info.c:209
+#, fuzzy, c-format
+msgid "You can't specify more than one output-specific argument\n"
+msgstr ""
+"Non è possibile specificare più di una volta l'opzione --cpu e/o\n"
+"specificare più di un parametro di output specifico\n"
+
+#~ msgid ""
+#~ "  -c CPU, --cpu CPU    CPU number which information shall be determined "
+#~ "about\n"
+#~ msgstr ""
+#~ "  -c CPU, --cpu CPU    Numero di CPU per la quale ottenere le "
+#~ "informazioni\n"
+
+#~ msgid ""
+#~ "  -c CPU, --cpu CPU        number of CPU where cpufreq settings shall be "
+#~ "modified\n"
+#~ msgstr ""
+#~ "  -c CPU, --cpu CPU        numero di CPU per la quale modificare le "
+#~ "impostazioni\n"
+
+#, fuzzy
+#~ msgid "  CPUs which coordinate software frequency requirements: "
+#~ msgstr ""
+#~ "  CPU per le quali e` necessario cambiare la frequenza "
+#~ "contemporaneamente: "
diff --git a/tools/power/cpupower/po/pt.po b/tools/power/cpupower/po/pt.po
new file mode 100644 (file)
index 0000000..990f526
--- /dev/null
@@ -0,0 +1,957 @@
+# Brazilian Portuguese translations for cpufrequtils package
+# Copyright (C) 2008 THE cpufrequtils'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the cpufrequtils package.
+# Claudio Eduardo <claudioeddy@gmail.com>, 2009.
+#
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: cpufrequtils 004\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-03-08 17:03+0100\n"
+"PO-Revision-Date: 2008-06-14 22:16-0400\n"
+"Last-Translator: Claudio Eduardo <claudioeddy@gmail.com>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: utils/idle_monitor/nhm_idle.c:36
+msgid "Processor Core C3"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:43
+msgid "Processor Core C6"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:51
+msgid "Processor Package C3"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:58 utils/idle_monitor/amd_fam14h_idle.c:70
+msgid "Processor Package C6"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:33
+msgid "Processor Core C7"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:40
+msgid "Processor Package C2"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:47
+msgid "Processor Package C7"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:56
+msgid "Package in sleep state (PC1 or deeper)"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:63
+msgid "Processor Package C1"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:77
+msgid "North Bridge P1 boolean counter (returns 0 or 1)"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:35
+msgid "Processor Core not idle"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:42
+msgid "Processor Core in an idle state"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:50
+msgid "Average Frequency (including boost) in MHz"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:66
+#, c-format
+msgid ""
+"cpupower monitor: [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
+"interval_sec | -c command ...]\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:69
+#, c-format
+msgid ""
+"cpupower monitor: [-v] [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
+"interval_sec | -c command ...]\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:71
+#, c-format
+msgid "\t -v: be more verbose\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:73
+#, c-format
+msgid "\t -h: print this help\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:74
+#, c-format
+msgid "\t -i: time intervall to measure for in seconds (default 1)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:75
+#, c-format
+msgid "\t -t: show CPU topology/hierarchy\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:76
+#, c-format
+msgid "\t -l: list available CPU sleep monitors (for use with -m)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:77
+#, c-format
+msgid "\t -m: show specific CPU sleep monitors only (in same order)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:79
+#, c-format
+msgid ""
+"only one of: -t, -l, -m are allowed\n"
+"If none of them is passed,"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:80
+#, c-format
+msgid " all supported monitors are shown\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:197
+#, c-format
+msgid "Monitor %s, Counter %s has no count function. Implementation error\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:207
+#, c-format
+msgid " *is offline\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:236
+#, c-format
+msgid "%s: max monitor name length (%d) exceeded\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:250
+#, c-format
+msgid "No matching monitor found in %s, try -l option\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:266
+#, c-format
+msgid "Monitor \"%s\" (%d states) - Might overflow after %u s\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:319
+#, c-format
+msgid "%s took %.5f seconds and exited with status %d\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:406
+#, c-format
+msgid "Cannot read number of available processors\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:417
+#, c-format
+msgid "Available monitor %s needs root access\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:428
+#, c-format
+msgid "No HW Cstate monitors found\n"
+msgstr ""
+
+#: utils/cpupower.c:78
+#, c-format
+msgid "cpupower [ -c cpulist ] subcommand [ARGS]\n"
+msgstr ""
+
+#: utils/cpupower.c:79
+#, c-format
+msgid "cpupower --version\n"
+msgstr ""
+
+#: utils/cpupower.c:80
+#, c-format
+msgid "Supported subcommands are:\n"
+msgstr ""
+
+#: utils/cpupower.c:83
+#, c-format
+msgid ""
+"\n"
+"Some subcommands can make use of the -c cpulist option.\n"
+msgstr ""
+
+#: utils/cpupower.c:84
+#, c-format
+msgid "Look at the general cpupower manpage how to use it\n"
+msgstr ""
+
+#: utils/cpupower.c:85
+#, c-format
+msgid "and read up the subcommand's manpage whether it is supported.\n"
+msgstr ""
+
+#: utils/cpupower.c:86
+#, c-format
+msgid ""
+"\n"
+"Use cpupower help subcommand for getting help for above subcommands.\n"
+msgstr ""
+
+#: utils/cpupower.c:91
+#, c-format
+msgid "Report errors and bugs to %s, please.\n"
+msgstr "Reporte erros e bugs para %s, por favor.\n"
+
+#: utils/cpupower.c:114
+#, c-format
+msgid "Error parsing cpu list\n"
+msgstr ""
+
+#: utils/cpupower.c:172
+#, c-format
+msgid "Subcommand %s needs root privileges\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:31
+#, c-format
+msgid "Couldn't count the number of CPUs (%s: %s), assuming 1\n"
+msgstr "Não foi possível contar o número de CPUs (%s: %s), assumindo 1\n"
+
+#: utils/cpufreq-info.c:63
+#, c-format
+msgid ""
+"          minimum CPU frequency  -  maximum CPU frequency  -  governor\n"
+msgstr ""
+"          frequência mínina do CPU  -  frequência máxima do CPU  -  "
+"regulador\n"
+
+#: utils/cpufreq-info.c:151
+#, c-format
+msgid "Error while evaluating Boost Capabilities on CPU %d -- are you root?\n"
+msgstr ""
+
+#. P state changes via MSR are identified via cpuid 80000007
+#. on Intel and AMD, but we assume boost capable machines can do that
+#. if (cpuid_eax(0x80000000) >= 0x80000007
+#. && (cpuid_edx(0x80000007) & (1 << 7)))
+#.
+#: utils/cpufreq-info.c:161
+#, c-format
+msgid "  boost state support: \n"
+msgstr ""
+
+#: utils/cpufreq-info.c:163
+#, c-format
+msgid "    Supported: %s\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164
+msgid "yes"
+msgstr ""
+
+#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164
+msgid "no"
+msgstr ""
+
+#: utils/cpufreq-info.c:164
+#, fuzzy, c-format
+msgid "    Active: %s\n"
+msgstr "  driver: %s\n"
+
+#: utils/cpufreq-info.c:177
+#, c-format
+msgid "    Boost States: %d\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:178
+#, c-format
+msgid "    Total States: %d\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:181
+#, c-format
+msgid "    Pstate-Pb%d: %luMHz (boost state)\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:184
+#, c-format
+msgid "    Pstate-P%d:  %luMHz\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:211
+#, c-format
+msgid "  no or unknown cpufreq driver is active on this CPU\n"
+msgstr "  nenhum ou driver do cpufreq deconhecido está ativo nesse CPU\n"
+
+#: utils/cpufreq-info.c:213
+#, c-format
+msgid "  driver: %s\n"
+msgstr "  driver: %s\n"
+
+#: utils/cpufreq-info.c:219
+#, c-format
+msgid "  CPUs which run at the same hardware frequency: "
+msgstr "  CPUs que rodam na mesma frequência de hardware: "
+
+#: utils/cpufreq-info.c:230
+#, c-format
+msgid "  CPUs which need to have their frequency coordinated by software: "
+msgstr "  CPUs que precisam ter suas frequências coordenadas por software: "
+
+#: utils/cpufreq-info.c:241
+#, c-format
+msgid "  maximum transition latency: "
+msgstr "  maior latência de transição: "
+
+#: utils/cpufreq-info.c:247
+#, c-format
+msgid "  hardware limits: "
+msgstr "  limites do hardware: "
+
+#: utils/cpufreq-info.c:256
+#, c-format
+msgid "  available frequency steps: "
+msgstr "  níveis de frequência disponíveis: "
+
+#: utils/cpufreq-info.c:269
+#, c-format
+msgid "  available cpufreq governors: "
+msgstr "  reguladores do cpufreq disponíveis: "
+
+#: utils/cpufreq-info.c:280
+#, c-format
+msgid "  current policy: frequency should be within "
+msgstr "  política de frequência atual deve estar entre "
+
+#: utils/cpufreq-info.c:282
+#, c-format
+msgid " and "
+msgstr " e "
+
+#: utils/cpufreq-info.c:286
+#, c-format
+msgid ""
+"The governor \"%s\" may decide which speed to use\n"
+"                  within this range.\n"
+msgstr ""
+"O regulador \"%s\" deve decidir qual velocidade usar\n"
+"                  dentro desse limite.\n"
+
+#: utils/cpufreq-info.c:293
+#, c-format
+msgid "  current CPU frequency is "
+msgstr "  frequência atual do CPU é "
+
+#: utils/cpufreq-info.c:296
+#, c-format
+msgid " (asserted by call to hardware)"
+msgstr " (declarado por chamada ao hardware)"
+
+#: utils/cpufreq-info.c:304
+#, c-format
+msgid "  cpufreq stats: "
+msgstr "  status do cpufreq: "
+
+#: utils/cpufreq-info.c:472
+#, fuzzy, c-format
+msgid "Usage: cpupower freqinfo [options]\n"
+msgstr "Uso: cpufreq-info [opções]\n"
+
+#: utils/cpufreq-info.c:473 utils/cpufreq-set.c:26 utils/cpupower-set.c:23
+#: utils/cpupower-info.c:22 utils/cpuidle-info.c:148
+#, c-format
+msgid "Options:\n"
+msgstr "Opções:\n"
+
+#: utils/cpufreq-info.c:474
+#, fuzzy, c-format
+msgid "  -e, --debug          Prints out debug information [default]\n"
+msgstr "  -e, --debug          Mostra informação de debug\n"
+
+#: utils/cpufreq-info.c:475
+#, c-format
+msgid ""
+"  -f, --freq           Get frequency the CPU currently runs at, according\n"
+"                       to the cpufreq core *\n"
+msgstr ""
+"  -f, --freq           Obtem a frequência na qual o CPU roda no momento, de "
+"acordo\n"
+"                       com o núcleo do cpufreq *\n"
+
+#: utils/cpufreq-info.c:477
+#, c-format
+msgid ""
+"  -w, --hwfreq         Get frequency the CPU currently runs at, by reading\n"
+"                       it from hardware (only available to root) *\n"
+msgstr ""
+"  -w, --hwfreq         Obtem a frequência na qual o CPU está operando no "
+"momento,\n"
+"                       através de leitura no hardware (disponível somente "
+"para root) *\n"
+
+#: utils/cpufreq-info.c:479
+#, c-format
+msgid ""
+"  -l, --hwlimits       Determine the minimum and maximum CPU frequency "
+"allowed *\n"
+msgstr ""
+"  -l, --hwlimits       Determina a frequência mínima e máxima do CPU "
+"permitida *\n"
+
+#: utils/cpufreq-info.c:480
+#, c-format
+msgid "  -d, --driver         Determines the used cpufreq kernel driver *\n"
+msgstr ""
+"  -d,  --driver         Determina o driver do kernel do cpufreq usado *\n"
+
+#: utils/cpufreq-info.c:481
+#, c-format
+msgid "  -p, --policy         Gets the currently used cpufreq policy *\n"
+msgstr ""
+"--p, --policy         Obtem a política do cpufreq em uso no momento *\n"
+
+#: utils/cpufreq-info.c:482
+#, c-format
+msgid "  -g, --governors      Determines available cpufreq governors *\n"
+msgstr ""
+"  -g, --governors      Determina reguladores do cpufreq disponíveis *\n"
+
+#: utils/cpufreq-info.c:483
+#, c-format
+msgid ""
+"  -r, --related-cpus   Determines which CPUs run at the same hardware "
+"frequency *\n"
+msgstr ""
+"  -r, --related-cpus   Determina quais CPUs rodam na mesma frequência de "
+"hardware *\n"
+
+#: utils/cpufreq-info.c:484
+#, c-format
+msgid ""
+"  -a, --affected-cpus  Determines which CPUs need to have their frequency\n"
+"                       coordinated by software *\n"
+msgstr ""
+"  -a, --affected-cpus  Determina quais CPUs precisam ter suas frequências\n"
+"                       coordenadas por software *\n"
+
+#: utils/cpufreq-info.c:486
+#, c-format
+msgid "  -s, --stats          Shows cpufreq statistics if available\n"
+msgstr "  -s, --stats          Mostra estatísticas do cpufreq se disponíveis\n"
+
+#: utils/cpufreq-info.c:487
+#, c-format
+msgid ""
+"  -y, --latency        Determines the maximum latency on CPU frequency "
+"changes *\n"
+msgstr ""
+"  -y, --latency        Determina a latência máxima nas trocas de frequência "
+"do CPU *\n"
+
+#: utils/cpufreq-info.c:488
+#, c-format
+msgid "  -b, --boost          Checks for turbo or boost modes  *\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:489
+#, c-format
+msgid ""
+"  -o, --proc           Prints out information like provided by the /proc/"
+"cpufreq\n"
+"                       interface in 2.4. and early 2.6. kernels\n"
+msgstr ""
+"  -o, --proc           Mostra informação do tipo provida pela interface /"
+"proc/cpufreq\n"
+"                       em kernels 2.4. e mais recentes 2.6\n"
+
+#: utils/cpufreq-info.c:491
+#, c-format
+msgid ""
+"  -m, --human          human-readable output for the -f, -w, -s and -y "
+"parameters\n"
+msgstr ""
+"  -m, --human          saída legível para humanos para os parâmetros -f, -w, "
+"-s e -y\n"
+
+#: utils/cpufreq-info.c:492 utils/cpuidle-info.c:152
+#, c-format
+msgid "  -h, --help           Prints out this screen\n"
+msgstr " -h, --help           Imprime essa tela\n"
+
+#: utils/cpufreq-info.c:495
+#, c-format
+msgid ""
+"If no argument or only the -c, --cpu parameter is given, debug output about\n"
+"cpufreq is printed which is useful e.g. for reporting bugs.\n"
+msgstr ""
+"Se nenhum argumento ou somente o parâmetro -c, --cpu é dado, informação de "
+"debug sobre\n"
+"o cpufreq é mostrada, o que é útil por exemplo para reportar bugs.\n"
+
+#: utils/cpufreq-info.c:497
+#, c-format
+msgid ""
+"For the arguments marked with *, omitting the -c or --cpu argument is\n"
+"equivalent to setting it to zero\n"
+msgstr ""
+"Para os argumentos marcados com *, omitir o argumento -c ou --cpu é\n"
+"equivalente a setá-lo como zero\n"
+
+#: utils/cpufreq-info.c:580
+#, c-format
+msgid ""
+"The argument passed to this tool can't be combined with passing a --cpu "
+"argument\n"
+msgstr ""
+"O argumento usado pra essa ferramenta não pode ser combinado com um "
+"argumento --cpu\n"
+
+#: utils/cpufreq-info.c:596
+#, c-format
+msgid ""
+"You can't specify more than one --cpu parameter and/or\n"
+"more than one output-specific argument\n"
+msgstr ""
+"Você não pode especificar mais do que um parâmetro --cpu e/ou\n"
+"mais do que um argumento de saída específico\n"
+
+#: utils/cpufreq-info.c:600 utils/cpufreq-set.c:82 utils/cpupower-set.c:42
+#: utils/cpupower-info.c:42 utils/cpuidle-info.c:213
+#, c-format
+msgid "invalid or unknown argument\n"
+msgstr "argumento inválido ou desconhecido\n"
+
+#: utils/cpufreq-info.c:617
+#, c-format
+msgid "couldn't analyze CPU %d as it doesn't seem to be present\n"
+msgstr ""
+"não foi possível analisar o CPU % já que o mesmo parece não estar presente\n"
+
+#: utils/cpufreq-info.c:620 utils/cpupower-info.c:142
+#, c-format
+msgid "analyzing CPU %d:\n"
+msgstr "analisando o CPU %d:\n"
+
+#: utils/cpufreq-set.c:25
+#, fuzzy, c-format
+msgid "Usage: cpupower frequency-set [options]\n"
+msgstr "Uso: cpufreq-set [opções]\n"
+
+#: utils/cpufreq-set.c:27
+#, c-format
+msgid ""
+"  -d FREQ, --min FREQ      new minimum CPU frequency the governor may "
+"select\n"
+msgstr ""
+"  -d FREQ, --min FREQ      nova frequência mínima do CPU que o regulador "
+"deve selecionar\n"
+
+#: utils/cpufreq-set.c:28
+#, c-format
+msgid ""
+"  -u FREQ, --max FREQ      new maximum CPU frequency the governor may "
+"select\n"
+msgstr ""
+"  -u FREQ, --max FREQ      nova frequência máxima do CPU que o regulador "
+"deve escolher\n"
+
+#: utils/cpufreq-set.c:29
+#, c-format
+msgid "  -g GOV, --governor GOV   new cpufreq governor\n"
+msgstr "  -g GOV, --governor GOV   novo regulador do cpufreq\n"
+
+#: utils/cpufreq-set.c:30
+#, c-format
+msgid ""
+"  -f FREQ, --freq FREQ     specific frequency to be set. Requires userspace\n"
+"                           governor to be available and loaded\n"
+msgstr ""
+"  -f FREQ, --freq FREQ     frequência específica para ser setada. Necessita "
+"que o regulador em\n"
+"                           nível de usuário esteja disponível e carregado\n"
+
+#: utils/cpufreq-set.c:32
+#, c-format
+msgid "  -r, --related            Switches all hardware-related CPUs\n"
+msgstr ""
+"  -r, --related            Modifica todos os CPUs relacionados ao hardware\n"
+
+#: utils/cpufreq-set.c:33 utils/cpupower-set.c:28 utils/cpupower-info.c:27
+#, c-format
+msgid "  -h, --help               Prints out this screen\n"
+msgstr " -h, --help           Mostra essa tela\n"
+
+#: utils/cpufreq-set.c:35
+#, fuzzy, c-format
+msgid ""
+"Notes:\n"
+"1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n"
+msgstr ""
+"Para os argumentos marcados com *, omitir o argumento -c ou --cpu é\n"
+"equivalente a setá-lo como zero\n"
+
+#: utils/cpufreq-set.c:37
+#, fuzzy, c-format
+msgid ""
+"2. The -f FREQ, --freq FREQ parameter cannot be combined with any other "
+"parameter\n"
+"   except the -c CPU, --cpu CPU parameter\n"
+"3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n"
+"   by postfixing the value with the wanted unit name, without any space\n"
+"   (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n"
+msgstr ""
+"Notas:\n"
+"1. Omitir o argumento -c or --cpu é equivalente a setá-lo como zero\n"
+"2. O parâmetro -f FREQ, --freq FREQ não pode ser combinado com qualquer "
+"outro parâmetro\n"
+"   exceto com o parâmetro -c CPU, --cpu CPU\n"
+"3. FREQuências podem ser usadas em Hz, kHz (padrão), MHz, GHz, o THz\n"
+"   colocando o nome desejado da unidade após o valor, sem qualquer espaço\n"
+"   (FREQuência em kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n"
+
+#: utils/cpufreq-set.c:57
+#, c-format
+msgid ""
+"Error setting new values. Common errors:\n"
+"- Do you have proper administration rights? (super-user?)\n"
+"- Is the governor you requested available and modprobed?\n"
+"- Trying to set an invalid policy?\n"
+"- Trying to set a specific frequency, but userspace governor is not "
+"available,\n"
+"   for example because of hardware which cannot be set to a specific "
+"frequency\n"
+"   or because the userspace governor isn't loaded?\n"
+msgstr ""
+"Erro ao setar novos valores. Erros comuns:\n"
+"- Você tem direitos administrativos necessários? (super-usuário?)\n"
+"- O regulador que você requesitou está disponível e foi \"modprobed\"?\n"
+"- Tentando setar uma política inválida?\n"
+"- Tentando setar uma frequência específica, mas o regulador em nível de "
+"usuário não está disponível,\n"
+"   por exemplo devido ao hardware que não pode ser setado pra uma frequência "
+"específica\n"
+"   ou porque o regulador em nível de usuário não foi carregado?\n"
+
+#: utils/cpufreq-set.c:170
+#, c-format
+msgid "wrong, unknown or unhandled CPU?\n"
+msgstr "CPU errado, desconhecido ou inesperado?\n"
+
+#: utils/cpufreq-set.c:302
+#, c-format
+msgid ""
+"the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n"
+"-g/--governor parameters\n"
+msgstr ""
+"o parâmetro -f/--freq não pode ser combinado com os parâmetros -d/--min, -"
+"u/--max ou\n"
+"-g/--governor\n"
+
+#: utils/cpufreq-set.c:308
+#, c-format
+msgid ""
+"At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n"
+"-g/--governor must be passed\n"
+msgstr ""
+"Pelo menos um parâmetro entre -f/--freq, -d/--min, -u/--max, e\n"
+"-g/--governor deve ser usado\n"
+
+#: utils/cpufreq-set.c:347
+#, c-format
+msgid "Setting cpu: %d\n"
+msgstr ""
+
+#: utils/cpupower-set.c:22
+#, c-format
+msgid "Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:24
+#, c-format
+msgid ""
+"  -b, --perf-bias [VAL]    Sets CPU's power vs performance policy on some\n"
+"                           Intel models [0-15], see manpage for details\n"
+msgstr ""
+
+#: utils/cpupower-set.c:26
+#, c-format
+msgid ""
+"  -m, --sched-mc  [VAL]    Sets the kernel's multi core scheduler policy.\n"
+msgstr ""
+
+#: utils/cpupower-set.c:27
+#, c-format
+msgid ""
+"  -s, --sched-smt [VAL]    Sets the kernel's thread sibling scheduler "
+"policy.\n"
+msgstr ""
+
+#: utils/cpupower-set.c:80
+#, c-format
+msgid "--perf-bias param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:91
+#, c-format
+msgid "--sched-mc param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:102
+#, c-format
+msgid "--sched-smt param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:121
+#, c-format
+msgid "Error setting sched-mc %s\n"
+msgstr ""
+
+#: utils/cpupower-set.c:127
+#, c-format
+msgid "Error setting sched-smt %s\n"
+msgstr ""
+
+#: utils/cpupower-set.c:146
+#, c-format
+msgid "Error setting perf-bias value on CPU %d\n"
+msgstr ""
+
+#: utils/cpupower-info.c:21
+#, c-format
+msgid "Usage: cpupower info [ -b ] [ -m ] [ -s ]\n"
+msgstr ""
+
+#: utils/cpupower-info.c:23
+#, c-format
+msgid ""
+"  -b, --perf-bias    Gets CPU's power vs performance policy on some\n"
+"                           Intel models [0-15], see manpage for details\n"
+msgstr ""
+
+#: utils/cpupower-info.c:25
+#, fuzzy, c-format
+msgid "  -m, --sched-mc     Gets the kernel's multi core scheduler policy.\n"
+msgstr ""
+"--p, --policy         Obtem a política do cpufreq em uso no momento *\n"
+
+#: utils/cpupower-info.c:26
+#, c-format
+msgid ""
+"  -s, --sched-smt    Gets the kernel's thread sibling scheduler policy.\n"
+msgstr ""
+
+#: utils/cpupower-info.c:28
+#, c-format
+msgid ""
+"\n"
+"Passing no option will show all info, by default only on core 0\n"
+msgstr ""
+
+#: utils/cpupower-info.c:102
+#, c-format
+msgid "System's multi core scheduler setting: "
+msgstr ""
+
+#. if sysfs file is missing it's: errno == ENOENT
+#: utils/cpupower-info.c:105 utils/cpupower-info.c:114
+#, c-format
+msgid "not supported\n"
+msgstr ""
+
+#: utils/cpupower-info.c:111
+#, c-format
+msgid "System's thread sibling scheduler setting: "
+msgstr ""
+
+#: utils/cpupower-info.c:126
+#, c-format
+msgid "Intel's performance bias setting needs root privileges\n"
+msgstr ""
+
+#: utils/cpupower-info.c:128
+#, c-format
+msgid "System does not support Intel's performance bias setting\n"
+msgstr ""
+
+#: utils/cpupower-info.c:147
+#, c-format
+msgid "Could not read perf-bias value\n"
+msgstr ""
+
+#: utils/cpupower-info.c:150
+#, c-format
+msgid "perf-bias: %d\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:28
+#, fuzzy, c-format
+msgid "Analyzing CPU %d:\n"
+msgstr "analisando o CPU %d:\n"
+
+#: utils/cpuidle-info.c:32
+#, c-format
+msgid "CPU %u: No idle states\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:36
+#, c-format
+msgid "CPU %u: Can't read idle state info\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:41
+#, c-format
+msgid "Could not determine max idle state %u\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:46
+#, c-format
+msgid "Number of idle states: %d\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:48
+#, fuzzy, c-format
+msgid "Available idle states:"
+msgstr "  níveis de frequência disponíveis: "
+
+#: utils/cpuidle-info.c:71
+#, c-format
+msgid "Flags/Description: %s\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:74
+#, c-format
+msgid "Latency: %lu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:76
+#, c-format
+msgid "Usage: %lu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:78
+#, c-format
+msgid "Duration: %llu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:90
+#, c-format
+msgid "Could not determine cpuidle driver\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:94
+#, fuzzy, c-format
+msgid "CPUidle driver: %s\n"
+msgstr "  driver: %s\n"
+
+#: utils/cpuidle-info.c:99
+#, c-format
+msgid "Could not determine cpuidle governor\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:103
+#, c-format
+msgid "CPUidle governor: %s\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:122
+#, c-format
+msgid "CPU %u: Can't read C-state info\n"
+msgstr ""
+
+#. printf("Cstates: %d\n", cstates);
+#: utils/cpuidle-info.c:127
+#, c-format
+msgid "active state:            C0\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:128
+#, c-format
+msgid "max_cstate:              C%u\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:129
+#, fuzzy, c-format
+msgid "maximum allowed latency: %lu usec\n"
+msgstr "  maior latência de transição: "
+
+#: utils/cpuidle-info.c:130
+#, c-format
+msgid "states:\t\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:132
+#, c-format
+msgid "    C%d:                  type[C%d] "
+msgstr ""
+
+#: utils/cpuidle-info.c:134
+#, c-format
+msgid "promotion[--] demotion[--] "
+msgstr ""
+
+#: utils/cpuidle-info.c:135
+#, c-format
+msgid "latency[%03lu] "
+msgstr ""
+
+#: utils/cpuidle-info.c:137
+#, c-format
+msgid "usage[%08lu] "
+msgstr ""
+
+#: utils/cpuidle-info.c:139
+#, c-format
+msgid "duration[%020Lu] \n"
+msgstr ""
+
+#: utils/cpuidle-info.c:147
+#, fuzzy, c-format
+msgid "Usage: cpupower idleinfo [options]\n"
+msgstr "Uso: cpufreq-info [opções]\n"
+
+#: utils/cpuidle-info.c:149
+#, fuzzy, c-format
+msgid "  -s, --silent         Only show general C-state information\n"
+msgstr "  -e, --debug          Mostra informação de debug\n"
+
+#: utils/cpuidle-info.c:150
+#, fuzzy, c-format
+msgid ""
+"  -o, --proc           Prints out information like provided by the /proc/"
+"acpi/processor/*/power\n"
+"                       interface in older kernels\n"
+msgstr ""
+"  -o, --proc           Mostra informação do tipo provida pela interface /"
+"proc/cpufreq\n"
+"                       em kernels 2.4. e mais recentes 2.6\n"
+
+#: utils/cpuidle-info.c:209
+#, fuzzy, c-format
+msgid "You can't specify more than one output-specific argument\n"
+msgstr ""
+"Você não pode especificar mais do que um parâmetro --cpu e/ou\n"
+"mais do que um argumento de saída específico\n"
+
+#~ msgid ""
+#~ "  -c CPU, --cpu CPU    CPU number which information shall be determined "
+#~ "about\n"
+#~ msgstr ""
+#~ "  -c CPU, --cpu CPU    número do CPU sobre o qual as inforções devem ser "
+#~ "determinadas\n"
+
+#~ msgid ""
+#~ "  -c CPU, --cpu CPU        number of CPU where cpufreq settings shall be "
+#~ "modified\n"
+#~ msgstr ""
+#~ "  -c CPU, --cpu CPU        número do CPU onde as configurações do cpufreq "
+#~ "vão ser modificadas\n"
diff --git a/tools/power/cpupower/utils/builtin.h b/tools/power/cpupower/utils/builtin.h
new file mode 100644 (file)
index 0000000..c870ffb
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef BUILTIN_H
+#define BUILTIN_H
+
+extern int cmd_set(int argc, const char **argv);
+extern int cmd_info(int argc, const char **argv);
+extern int cmd_freq_set(int argc, const char **argv);
+extern int cmd_freq_info(int argc, const char **argv);
+extern int cmd_idle_info(int argc, const char **argv);
+extern int cmd_monitor(int argc, const char **argv);
+
+extern void set_help(void);
+extern void info_help(void);
+extern void freq_set_help(void);
+extern void freq_info_help(void);
+extern void idle_info_help(void);
+extern void monitor_help(void);
+
+#endif
diff --git a/tools/power/cpupower/utils/cpufreq-info.c b/tools/power/cpupower/utils/cpufreq-info.c
new file mode 100644 (file)
index 0000000..5a1d25f
--- /dev/null
@@ -0,0 +1,708 @@
+/*
+ *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ */
+
+
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <getopt.h>
+
+#include "cpufreq.h"
+#include "helpers/helpers.h"
+#include "helpers/bitmask.h"
+
+#define LINE_LEN 10
+
+static unsigned int count_cpus(void)
+{
+       FILE *fp;
+       char value[LINE_LEN];
+       unsigned int ret = 0;
+       unsigned int cpunr = 0;
+
+       fp = fopen("/proc/stat", "r");
+       if (!fp) {
+               printf(_("Couldn't count the number of CPUs (%s: %s), assuming 1\n"), "/proc/stat", strerror(errno));
+               return 1;
+       }
+
+       while (!feof(fp)) {
+               if (!fgets(value, LINE_LEN, fp))
+                       continue;
+               value[LINE_LEN - 1] = '\0';
+               if (strlen(value) < (LINE_LEN - 2))
+                       continue;
+               if (strstr(value, "cpu "))
+                       continue;
+               if (sscanf(value, "cpu%d ", &cpunr) != 1)
+                       continue;
+               if (cpunr > ret)
+                       ret = cpunr;
+       }
+       fclose(fp);
+
+       /* cpu count starts from 0, on error return 1 (UP) */
+       return ret + 1;
+}
+
+
+static void proc_cpufreq_output(void)
+{
+       unsigned int cpu, nr_cpus;
+       struct cpufreq_policy *policy;
+       unsigned int min_pctg = 0;
+       unsigned int max_pctg = 0;
+       unsigned long min, max;
+
+       printf(_("          minimum CPU frequency  -  maximum CPU frequency  -  governor\n"));
+
+       nr_cpus = count_cpus();
+       for (cpu = 0; cpu < nr_cpus; cpu++) {
+               policy = cpufreq_get_policy(cpu);
+               if (!policy)
+                       continue;
+
+               if (cpufreq_get_hardware_limits(cpu, &min, &max)) {
+                       max = 0;
+               } else {
+                       min_pctg = (policy->min * 100) / max;
+                       max_pctg = (policy->max * 100) / max;
+               }
+               printf("CPU%3d    %9lu kHz (%3d %%)  -  %9lu kHz (%3d %%)  -  %s\n",
+                       cpu , policy->min, max ? min_pctg : 0, policy->max,
+                       max ? max_pctg : 0, policy->governor);
+
+               cpufreq_put_policy(policy);
+       }
+}
+
+static void print_speed(unsigned long speed)
+{
+       unsigned long tmp;
+
+       if (speed > 1000000) {
+               tmp = speed % 10000;
+               if (tmp >= 5000)
+                       speed += 10000;
+               printf("%u.%02u GHz", ((unsigned int) speed/1000000),
+                       ((unsigned int) (speed%1000000)/10000));
+       } else if (speed > 100000) {
+               tmp = speed % 1000;
+               if (tmp >= 500)
+                       speed += 1000;
+               printf("%u MHz", ((unsigned int) speed / 1000));
+       } else if (speed > 1000) {
+               tmp = speed % 100;
+               if (tmp >= 50)
+                       speed += 100;
+               printf("%u.%01u MHz", ((unsigned int) speed/1000),
+                       ((unsigned int) (speed%1000)/100));
+       } else
+               printf("%lu kHz", speed);
+
+       return;
+}
+
+static void print_duration(unsigned long duration)
+{
+       unsigned long tmp;
+
+       if (duration > 1000000) {
+               tmp = duration % 10000;
+               if (tmp >= 5000)
+                       duration += 10000;
+               printf("%u.%02u ms", ((unsigned int) duration/1000000),
+                       ((unsigned int) (duration%1000000)/10000));
+       } else if (duration > 100000) {
+               tmp = duration % 1000;
+               if (tmp >= 500)
+                       duration += 1000;
+               printf("%u us", ((unsigned int) duration / 1000));
+       } else if (duration > 1000) {
+               tmp = duration % 100;
+               if (tmp >= 50)
+                       duration += 100;
+               printf("%u.%01u us", ((unsigned int) duration/1000),
+                       ((unsigned int) (duration%1000)/100));
+       } else
+               printf("%lu ns", duration);
+
+       return;
+}
+
+/* --boost / -b */
+
+static int get_boost_mode(unsigned int cpu)
+{
+       int support, active, b_states = 0, ret, pstate_no, i;
+       /* ToDo: Make this more global */
+       unsigned long pstates[MAX_HW_PSTATES] = {0,};
+
+       if (cpupower_cpu_info.vendor != X86_VENDOR_AMD &&
+           cpupower_cpu_info.vendor != X86_VENDOR_INTEL)
+               return 0;
+
+       ret = cpufreq_has_boost_support(cpu, &support, &active, &b_states);
+       if (ret) {
+               printf(_("Error while evaluating Boost Capabilities"
+                               " on CPU %d -- are you root?\n"), cpu);
+               return ret;
+       }
+       /* P state changes via MSR are identified via cpuid 80000007
+          on Intel and AMD, but we assume boost capable machines can do that
+          if (cpuid_eax(0x80000000) >= 0x80000007
+          && (cpuid_edx(0x80000007) & (1 << 7)))
+       */
+
+       printf(_("  boost state support:\n"));
+
+       printf(_("    Supported: %s\n"), support ? _("yes") : _("no"));
+       printf(_("    Active: %s\n"), active ? _("yes") : _("no"));
+
+       if (cpupower_cpu_info.vendor == X86_VENDOR_AMD &&
+           cpupower_cpu_info.family >= 0x10) {
+               ret = decode_pstates(cpu, cpupower_cpu_info.family, b_states,
+                                    pstates, &pstate_no);
+               if (ret)
+                       return ret;
+
+               printf(_("    Boost States: %d\n"), b_states);
+               printf(_("    Total States: %d\n"), pstate_no);
+               for (i = 0; i < pstate_no; i++) {
+                       if (i < b_states)
+                               printf(_("    Pstate-Pb%d: %luMHz (boost state)"
+                                        "\n"), i, pstates[i]);
+                       else
+                               printf(_("    Pstate-P%d:  %luMHz\n"),
+                                      i - b_states, pstates[i]);
+               }
+       } else if (cpupower_cpu_info.caps & CPUPOWER_CAP_HAS_TURBO_RATIO) {
+               double bclk;
+               unsigned long long intel_turbo_ratio = 0;
+               unsigned int ratio;
+
+               /* Any way to autodetect this ? */
+               if (cpupower_cpu_info.caps & CPUPOWER_CAP_IS_SNB)
+                       bclk = 100.00;
+               else
+                       bclk = 133.33;
+               intel_turbo_ratio = msr_intel_get_turbo_ratio(cpu);
+               dprint ("    Ratio: 0x%llx - bclk: %f\n",
+                       intel_turbo_ratio, bclk);
+
+               ratio = (intel_turbo_ratio >> 24) & 0xFF;
+               if (ratio)
+                       printf(_("    %.0f MHz max turbo 4 active cores\n"),
+                              ratio * bclk);
+
+               ratio = (intel_turbo_ratio >> 16) & 0xFF;
+               if (ratio)
+                       printf(_("    %.0f MHz max turbo 3 active cores\n"),
+                              ratio * bclk);
+
+               ratio = (intel_turbo_ratio >> 8) & 0xFF;
+               if (ratio)
+                       printf(_("    %.0f MHz max turbo 2 active cores\n"),
+                              ratio * bclk);
+
+               ratio = (intel_turbo_ratio >> 0) & 0xFF;
+               if (ratio)
+                       printf(_("    %.0f MHz max turbo 1 active cores\n"),
+                              ratio * bclk);
+       }
+       return 0;
+}
+
+static void debug_output_one(unsigned int cpu)
+{
+       char *driver;
+       struct cpufreq_affected_cpus *cpus;
+       struct cpufreq_available_frequencies *freqs;
+       unsigned long min, max, freq_kernel, freq_hardware;
+       unsigned long total_trans, latency;
+       unsigned long long total_time;
+       struct cpufreq_policy *policy;
+       struct cpufreq_available_governors *governors;
+       struct cpufreq_stats *stats;
+
+       if (cpufreq_cpu_exists(cpu))
+               return;
+
+       freq_kernel = cpufreq_get_freq_kernel(cpu);
+       freq_hardware = cpufreq_get_freq_hardware(cpu);
+
+       driver = cpufreq_get_driver(cpu);
+       if (!driver) {
+               printf(_("  no or unknown cpufreq driver is active on this CPU\n"));
+       } else {
+               printf(_("  driver: %s\n"), driver);
+               cpufreq_put_driver(driver);
+       }
+
+       cpus = cpufreq_get_related_cpus(cpu);
+       if (cpus) {
+               printf(_("  CPUs which run at the same hardware frequency: "));
+               while (cpus->next) {
+                       printf("%d ", cpus->cpu);
+                       cpus = cpus->next;
+               }
+               printf("%d\n", cpus->cpu);
+               cpufreq_put_related_cpus(cpus);
+       }
+
+       cpus = cpufreq_get_affected_cpus(cpu);
+       if (cpus) {
+               printf(_("  CPUs which need to have their frequency coordinated by software: "));
+               while (cpus->next) {
+                       printf("%d ", cpus->cpu);
+                       cpus = cpus->next;
+               }
+               printf("%d\n", cpus->cpu);
+               cpufreq_put_affected_cpus(cpus);
+       }
+
+       latency = cpufreq_get_transition_latency(cpu);
+       if (latency) {
+               printf(_("  maximum transition latency: "));
+               print_duration(latency);
+               printf(".\n");
+       }
+
+       if (!(cpufreq_get_hardware_limits(cpu, &min, &max))) {
+               printf(_("  hardware limits: "));
+               print_speed(min);
+               printf(" - ");
+               print_speed(max);
+               printf("\n");
+       }
+
+       freqs = cpufreq_get_available_frequencies(cpu);
+       if (freqs) {
+               printf(_("  available frequency steps: "));
+               while (freqs->next) {
+                       print_speed(freqs->frequency);
+                       printf(", ");
+                       freqs = freqs->next;
+               }
+               print_speed(freqs->frequency);
+               printf("\n");
+               cpufreq_put_available_frequencies(freqs);
+       }
+
+       governors = cpufreq_get_available_governors(cpu);
+       if (governors) {
+               printf(_("  available cpufreq governors: "));
+               while (governors->next) {
+                       printf("%s, ", governors->governor);
+                       governors = governors->next;
+               }
+               printf("%s\n", governors->governor);
+               cpufreq_put_available_governors(governors);
+       }
+
+       policy = cpufreq_get_policy(cpu);
+       if (policy) {
+               printf(_("  current policy: frequency should be within "));
+               print_speed(policy->min);
+               printf(_(" and "));
+               print_speed(policy->max);
+
+               printf(".\n                  ");
+               printf(_("The governor \"%s\" may"
+                      " decide which speed to use\n                  within this range.\n"),
+                      policy->governor);
+               cpufreq_put_policy(policy);
+       }
+
+       if (freq_kernel || freq_hardware) {
+               printf(_("  current CPU frequency is "));
+               if (freq_hardware) {
+                       print_speed(freq_hardware);
+                       printf(_(" (asserted by call to hardware)"));
+               } else
+                       print_speed(freq_kernel);
+               printf(".\n");
+       }
+       stats = cpufreq_get_stats(cpu, &total_time);
+       if (stats) {
+               printf(_("  cpufreq stats: "));
+               while (stats) {
+                       print_speed(stats->frequency);
+                       printf(":%.2f%%", (100.0 * stats->time_in_state) / total_time);
+                       stats = stats->next;
+                       if (stats)
+                               printf(", ");
+               }
+               cpufreq_put_stats(stats);
+               total_trans = cpufreq_get_transitions(cpu);
+               if (total_trans)
+                       printf("  (%lu)\n", total_trans);
+               else
+                       printf("\n");
+       }
+       get_boost_mode(cpu);
+
+}
+
+/* --freq / -f */
+
+static int get_freq_kernel(unsigned int cpu, unsigned int human)
+{
+       unsigned long freq = cpufreq_get_freq_kernel(cpu);
+       if (!freq)
+               return -EINVAL;
+       if (human) {
+               print_speed(freq);
+               printf("\n");
+       } else
+               printf("%lu\n", freq);
+       return 0;
+}
+
+
+/* --hwfreq / -w */
+
+static int get_freq_hardware(unsigned int cpu, unsigned int human)
+{
+       unsigned long freq = cpufreq_get_freq_hardware(cpu);
+       if (!freq)
+               return -EINVAL;
+       if (human) {
+               print_speed(freq);
+               printf("\n");
+       } else
+               printf("%lu\n", freq);
+       return 0;
+}
+
+/* --hwlimits / -l */
+
+static int get_hardware_limits(unsigned int cpu)
+{
+       unsigned long min, max;
+       if (cpufreq_get_hardware_limits(cpu, &min, &max))
+               return -EINVAL;
+       printf("%lu %lu\n", min, max);
+       return 0;
+}
+
+/* --driver / -d */
+
+static int get_driver(unsigned int cpu)
+{
+       char *driver = cpufreq_get_driver(cpu);
+       if (!driver)
+               return -EINVAL;
+       printf("%s\n", driver);
+       cpufreq_put_driver(driver);
+       return 0;
+}
+
+/* --policy / -p */
+
+static int get_policy(unsigned int cpu)
+{
+       struct cpufreq_policy *policy = cpufreq_get_policy(cpu);
+       if (!policy)
+               return -EINVAL;
+       printf("%lu %lu %s\n", policy->min, policy->max, policy->governor);
+       cpufreq_put_policy(policy);
+       return 0;
+}
+
+/* --governors / -g */
+
+static int get_available_governors(unsigned int cpu)
+{
+       struct cpufreq_available_governors *governors =
+               cpufreq_get_available_governors(cpu);
+       if (!governors)
+               return -EINVAL;
+
+       while (governors->next) {
+               printf("%s ", governors->governor);
+               governors = governors->next;
+       }
+       printf("%s\n", governors->governor);
+       cpufreq_put_available_governors(governors);
+       return 0;
+}
+
+
+/* --affected-cpus  / -a */
+
+static int get_affected_cpus(unsigned int cpu)
+{
+       struct cpufreq_affected_cpus *cpus = cpufreq_get_affected_cpus(cpu);
+       if (!cpus)
+               return -EINVAL;
+
+       while (cpus->next) {
+               printf("%d ", cpus->cpu);
+               cpus = cpus->next;
+       }
+       printf("%d\n", cpus->cpu);
+       cpufreq_put_affected_cpus(cpus);
+       return 0;
+}
+
+/* --related-cpus  / -r */
+
+static int get_related_cpus(unsigned int cpu)
+{
+       struct cpufreq_affected_cpus *cpus = cpufreq_get_related_cpus(cpu);
+       if (!cpus)
+               return -EINVAL;
+
+       while (cpus->next) {
+               printf("%d ", cpus->cpu);
+               cpus = cpus->next;
+       }
+       printf("%d\n", cpus->cpu);
+       cpufreq_put_related_cpus(cpus);
+       return 0;
+}
+
+/* --stats / -s */
+
+static int get_freq_stats(unsigned int cpu, unsigned int human)
+{
+       unsigned long total_trans = cpufreq_get_transitions(cpu);
+       unsigned long long total_time;
+       struct cpufreq_stats *stats = cpufreq_get_stats(cpu, &total_time);
+       while (stats) {
+               if (human) {
+                       print_speed(stats->frequency);
+                       printf(":%.2f%%",
+                               (100.0 * stats->time_in_state) / total_time);
+               } else
+                       printf("%lu:%llu",
+                               stats->frequency, stats->time_in_state);
+               stats = stats->next;
+               if (stats)
+                       printf(", ");
+       }
+       cpufreq_put_stats(stats);
+       if (total_trans)
+               printf("  (%lu)\n", total_trans);
+       return 0;
+}
+
+/* --latency / -y */
+
+static int get_latency(unsigned int cpu, unsigned int human)
+{
+       unsigned long latency = cpufreq_get_transition_latency(cpu);
+       if (!latency)
+               return -EINVAL;
+
+       if (human) {
+               print_duration(latency);
+               printf("\n");
+       } else
+               printf("%lu\n", latency);
+       return 0;
+}
+
+void freq_info_help(void)
+{
+       printf(_("Usage: cpupower freqinfo [options]\n"));
+       printf(_("Options:\n"));
+       printf(_("  -e, --debug          Prints out debug information [default]\n"));
+       printf(_("  -f, --freq           Get frequency the CPU currently runs at, according\n"
+              "                       to the cpufreq core *\n"));
+       printf(_("  -w, --hwfreq         Get frequency the CPU currently runs at, by reading\n"
+              "                       it from hardware (only available to root) *\n"));
+       printf(_("  -l, --hwlimits       Determine the minimum and maximum CPU frequency allowed *\n"));
+       printf(_("  -d, --driver         Determines the used cpufreq kernel driver *\n"));
+       printf(_("  -p, --policy         Gets the currently used cpufreq policy *\n"));
+       printf(_("  -g, --governors      Determines available cpufreq governors *\n"));
+       printf(_("  -r, --related-cpus   Determines which CPUs run at the same hardware frequency *\n"));
+       printf(_("  -a, --affected-cpus  Determines which CPUs need to have their frequency\n"
+                       "                       coordinated by software *\n"));
+       printf(_("  -s, --stats          Shows cpufreq statistics if available\n"));
+       printf(_("  -y, --latency        Determines the maximum latency on CPU frequency changes *\n"));
+       printf(_("  -b, --boost          Checks for turbo or boost modes  *\n"));
+       printf(_("  -o, --proc           Prints out information like provided by the /proc/cpufreq\n"
+              "                       interface in 2.4. and early 2.6. kernels\n"));
+       printf(_("  -m, --human          human-readable output for the -f, -w, -s and -y parameters\n"));
+       printf(_("  -h, --help           Prints out this screen\n"));
+
+       printf("\n");
+       printf(_("If no argument is given, full output about\n"
+              "cpufreq is printed which is useful e.g. for reporting bugs.\n\n"));
+       printf(_("By default info of CPU 0 is shown which can be overridden\n"
+                "with the cpupower --cpu main command option.\n"));
+}
+
+static struct option info_opts[] = {
+       { .name = "debug",      .has_arg = no_argument,         .flag = NULL,   .val = 'e'},
+       { .name = "boost",      .has_arg = no_argument,         .flag = NULL,   .val = 'b'},
+       { .name = "freq",       .has_arg = no_argument,         .flag = NULL,   .val = 'f'},
+       { .name = "hwfreq",     .has_arg = no_argument,         .flag = NULL,   .val = 'w'},
+       { .name = "hwlimits",   .has_arg = no_argument,         .flag = NULL,   .val = 'l'},
+       { .name = "driver",     .has_arg = no_argument,         .flag = NULL,   .val = 'd'},
+       { .name = "policy",     .has_arg = no_argument,         .flag = NULL,   .val = 'p'},
+       { .name = "governors",  .has_arg = no_argument,         .flag = NULL,   .val = 'g'},
+       { .name = "related-cpus", .has_arg = no_argument,       .flag = NULL,   .val = 'r'},
+       { .name = "affected-cpus",.has_arg = no_argument,       .flag = NULL,   .val = 'a'},
+       { .name = "stats",      .has_arg = no_argument,         .flag = NULL,   .val = 's'},
+       { .name = "latency",    .has_arg = no_argument,         .flag = NULL,   .val = 'y'},
+       { .name = "proc",       .has_arg = no_argument,         .flag = NULL,   .val = 'o'},
+       { .name = "human",      .has_arg = no_argument,         .flag = NULL,   .val = 'm'},
+       { .name = "help",       .has_arg = no_argument,         .flag = NULL,   .val = 'h'},
+       { },
+};
+
+int cmd_freq_info(int argc, char **argv)
+{
+       extern char *optarg;
+       extern int optind, opterr, optopt;
+       int ret = 0, cont = 1;
+       unsigned int cpu = 0;
+       unsigned int human = 0;
+       int output_param = 0;
+
+       do {
+               ret = getopt_long(argc, argv, "hoefwldpgrasmyb", info_opts, NULL);
+               switch (ret) {
+               case '?':
+                       output_param = '?';
+                       cont = 0;
+                       break;
+               case 'h':
+                       output_param = 'h';
+                       cont = 0;
+                       break;
+               case -1:
+                       cont = 0;
+                       break;
+               case 'b':
+               case 'o':
+               case 'a':
+               case 'r':
+               case 'g':
+               case 'p':
+               case 'd':
+               case 'l':
+               case 'w':
+               case 'f':
+               case 'e':
+               case 's':
+               case 'y':
+                       if (output_param) {
+                               output_param = -1;
+                               cont = 0;
+                               break;
+                       }
+                       output_param = ret;
+                       break;
+               case 'm':
+                       if (human) {
+                               output_param = -1;
+                               cont = 0;
+                               break;
+                       }
+                       human = 1;
+                       break;
+               default:
+                       fprintf(stderr, "invalid or unknown argument\n");
+                       return EXIT_FAILURE;
+               }
+       } while (cont);
+
+       switch (output_param) {
+       case 'o':
+               if (!bitmask_isallclear(cpus_chosen)) {
+                       printf(_("The argument passed to this tool can't be "
+                                "combined with passing a --cpu argument\n"));
+                       return -EINVAL;
+               }
+               break;
+       case 0:
+               output_param = 'e';
+       }
+
+       ret = 0;
+
+       /* Default is: show output of CPU 0 only */
+       if (bitmask_isallclear(cpus_chosen))
+               bitmask_setbit(cpus_chosen, 0);
+
+       switch (output_param) {
+       case -1:
+               printf(_("You can't specify more than one --cpu parameter and/or\n"
+                      "more than one output-specific argument\n"));
+               return -EINVAL;
+       case '?':
+               printf(_("invalid or unknown argument\n"));
+               freq_info_help();
+               return -EINVAL;
+       case 'h':
+               freq_info_help();
+               return EXIT_SUCCESS;
+       case 'o':
+               proc_cpufreq_output();
+               return EXIT_SUCCESS;
+       }
+
+       for (cpu = bitmask_first(cpus_chosen);
+            cpu <= bitmask_last(cpus_chosen); cpu++) {
+
+               if (!bitmask_isbitset(cpus_chosen, cpu))
+                       continue;
+               if (cpufreq_cpu_exists(cpu)) {
+                       printf(_("couldn't analyze CPU %d as it doesn't seem to be present\n"), cpu);
+                       continue;
+               }
+               printf(_("analyzing CPU %d:\n"), cpu);
+
+               switch (output_param) {
+               case 'b':
+                       get_boost_mode(cpu);
+                       break;
+               case 'e':
+                       debug_output_one(cpu);
+                       break;
+               case 'a':
+                       ret = get_affected_cpus(cpu);
+                       break;
+               case 'r':
+                       ret = get_related_cpus(cpu);
+                       break;
+               case 'g':
+                       ret = get_available_governors(cpu);
+                       break;
+               case 'p':
+                       ret = get_policy(cpu);
+                       break;
+               case 'd':
+                       ret = get_driver(cpu);
+                       break;
+               case 'l':
+                       ret = get_hardware_limits(cpu);
+                       break;
+               case 'w':
+                       ret = get_freq_hardware(cpu, human);
+                       break;
+               case 'f':
+                       ret = get_freq_kernel(cpu, human);
+                       break;
+               case 's':
+                       ret = get_freq_stats(cpu, human);
+                       break;
+               case 'y':
+                       ret = get_latency(cpu, human);
+                       break;
+               }
+               if (ret)
+                       return ret;
+       }
+       return ret;
+}
diff --git a/tools/power/cpupower/utils/cpufreq-set.c b/tools/power/cpupower/utils/cpufreq-set.c
new file mode 100644 (file)
index 0000000..5f78362
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ */
+
+
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <getopt.h>
+
+#include "cpufreq.h"
+#include "helpers/helpers.h"
+
+#define NORM_FREQ_LEN 32
+
+void freq_set_help(void)
+{
+       printf(_("Usage: cpupower frequency-set [options]\n"));
+       printf(_("Options:\n"));
+       printf(_("  -d FREQ, --min FREQ      new minimum CPU frequency the governor may select\n"));
+       printf(_("  -u FREQ, --max FREQ      new maximum CPU frequency the governor may select\n"));
+       printf(_("  -g GOV, --governor GOV   new cpufreq governor\n"));
+       printf(_("  -f FREQ, --freq FREQ     specific frequency to be set. Requires userspace\n"
+              "                           governor to be available and loaded\n"));
+       printf(_("  -r, --related            Switches all hardware-related CPUs\n"));
+       printf(_("  -h, --help               Prints out this screen\n"));
+       printf("\n");
+       printf(_("Notes:\n"
+              "1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n"));
+       printf(_("2. The -f FREQ, --freq FREQ parameter cannot be combined with any other parameter\n"
+              "   except the -c CPU, --cpu CPU parameter\n"
+              "3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n"
+              "   by postfixing the value with the wanted unit name, without any space\n"
+              "   (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n"));
+
+}
+
+static struct option set_opts[] = {
+       { .name = "min",        .has_arg = required_argument,   .flag = NULL,   .val = 'd'},
+       { .name = "max",        .has_arg = required_argument,   .flag = NULL,   .val = 'u'},
+       { .name = "governor",   .has_arg = required_argument,   .flag = NULL,   .val = 'g'},
+       { .name = "freq",       .has_arg = required_argument,   .flag = NULL,   .val = 'f'},
+       { .name = "help",       .has_arg = no_argument,         .flag = NULL,   .val = 'h'},
+       { .name = "related",    .has_arg = no_argument,         .flag = NULL,   .val='r'},
+       { },
+};
+
+static void print_error(void)
+{
+       printf(_("Error setting new values. Common errors:\n"
+                       "- Do you have proper administration rights? (super-user?)\n"
+                       "- Is the governor you requested available and modprobed?\n"
+                       "- Trying to set an invalid policy?\n"
+                       "- Trying to set a specific frequency, but userspace governor is not available,\n"
+                       "   for example because of hardware which cannot be set to a specific frequency\n"
+                       "   or because the userspace governor isn't loaded?\n"));
+};
+
+struct freq_units {
+       char            *str_unit;
+       int             power_of_ten;
+};
+
+const struct freq_units def_units[] = {
+       {"hz", -3},
+       {"khz", 0}, /* default */
+       {"mhz", 3},
+       {"ghz", 6},
+       {"thz", 9},
+       {NULL, 0}
+};
+
+static void print_unknown_arg(void)
+{
+       printf(_("invalid or unknown argument\n"));
+       freq_set_help();
+}
+
+static unsigned long string_to_frequency(const char *str)
+{
+       char normalized[NORM_FREQ_LEN];
+       const struct freq_units *unit;
+       const char *scan;
+       char *end;
+       unsigned long freq;
+       int power = 0, match_count = 0, i, cp, pad;
+
+       while (*str == '0')
+               str++;
+
+       for (scan = str; isdigit(*scan) || *scan == '.'; scan++) {
+               if (*scan == '.' && match_count == 0)
+                       match_count = 1;
+               else if (*scan == '.' && match_count == 1)
+                       return 0;
+       }
+
+       if (*scan) {
+               match_count = 0;
+               for (unit = def_units; unit->str_unit; unit++) {
+                       for (i = 0;
+                            scan[i] && tolower(scan[i]) == unit->str_unit[i];
+                            ++i)
+                               continue;
+                       if (scan[i])
+                               continue;
+                       match_count++;
+                       power = unit->power_of_ten;
+               }
+               if (match_count != 1)
+                       return 0;
+       }
+
+       /* count the number of digits to be copied */
+       for (cp = 0; isdigit(str[cp]); cp++)
+               continue;
+
+       if (str[cp] == '.') {
+               while (power > -1 && isdigit(str[cp+1]))
+                       cp++, power--;
+       }
+       if (power >= -1)        /* not enough => pad */
+               pad = power + 1;
+       else                    /* to much => strip */
+               pad = 0, cp += power + 1;
+       /* check bounds */
+       if (cp <= 0 || cp + pad > NORM_FREQ_LEN - 1)
+               return 0;
+
+       /* copy digits */
+       for (i = 0; i < cp; i++, str++) {
+               if (*str == '.')
+                       str++;
+               normalized[i] = *str;
+       }
+       /* and pad */
+       for (; i < cp + pad; i++)
+               normalized[i] = '0';
+
+       /* round up, down ? */
+       match_count = (normalized[i-1] >= '5');
+       /* and drop the decimal part */
+       normalized[i-1] = 0; /* cp > 0 && pad >= 0 ==> i > 0 */
+
+       /* final conversion (and applying rounding) */
+       errno = 0;
+       freq = strtoul(normalized, &end, 10);
+       if (errno)
+               return 0;
+       else {
+               if (match_count && freq != ULONG_MAX)
+                       freq++;
+               return freq;
+       }
+}
+
+static int do_new_policy(unsigned int cpu, struct cpufreq_policy *new_pol)
+{
+       struct cpufreq_policy *cur_pol = cpufreq_get_policy(cpu);
+       int ret;
+
+       if (!cur_pol) {
+               printf(_("wrong, unknown or unhandled CPU?\n"));
+               return -EINVAL;
+       }
+
+       if (!new_pol->min)
+               new_pol->min = cur_pol->min;
+
+       if (!new_pol->max)
+               new_pol->max = cur_pol->max;
+
+       if (!new_pol->governor)
+               new_pol->governor = cur_pol->governor;
+
+       ret = cpufreq_set_policy(cpu, new_pol);
+
+       cpufreq_put_policy(cur_pol);
+
+       return ret;
+}
+
+
+static int do_one_cpu(unsigned int cpu, struct cpufreq_policy *new_pol,
+               unsigned long freq, unsigned int pc)
+{
+       switch (pc) {
+       case 0:
+               return cpufreq_set_frequency(cpu, freq);
+
+       case 1:
+               /* if only one value of a policy is to be changed, we can
+                * use a "fast path".
+                */
+               if (new_pol->min)
+                       return cpufreq_modify_policy_min(cpu, new_pol->min);
+               else if (new_pol->max)
+                       return cpufreq_modify_policy_max(cpu, new_pol->max);
+               else if (new_pol->governor)
+                       return cpufreq_modify_policy_governor(cpu,
+                                                       new_pol->governor);
+
+       default:
+               /* slow path */
+               return do_new_policy(cpu, new_pol);
+       }
+}
+
+int cmd_freq_set(int argc, char **argv)
+{
+       extern char *optarg;
+       extern int optind, opterr, optopt;
+       int ret = 0, cont = 1;
+       int double_parm = 0, related = 0, policychange = 0;
+       unsigned long freq = 0;
+       char gov[20];
+       unsigned int cpu;
+
+       struct cpufreq_policy new_pol = {
+               .min = 0,
+               .max = 0,
+               .governor = NULL,
+       };
+
+       /* parameter parsing */
+       do {
+               ret = getopt_long(argc, argv, "d:u:g:f:hr", set_opts, NULL);
+               switch (ret) {
+               case '?':
+                       print_unknown_arg();
+                       return -EINVAL;
+               case 'h':
+                       freq_set_help();
+                       return 0;
+               case -1:
+                       cont = 0;
+                       break;
+               case 'r':
+                       if (related)
+                               double_parm++;
+                       related++;
+                       break;
+               case 'd':
+                       if (new_pol.min)
+                               double_parm++;
+                       policychange++;
+                       new_pol.min = string_to_frequency(optarg);
+                       if (new_pol.min == 0) {
+                               print_unknown_arg();
+                               return -EINVAL;
+                       }
+                       break;
+               case 'u':
+                       if (new_pol.max)
+                               double_parm++;
+                       policychange++;
+                       new_pol.max = string_to_frequency(optarg);
+                       if (new_pol.max == 0) {
+                               print_unknown_arg();
+                               return -EINVAL;
+                       }
+                       break;
+               case 'f':
+                       if (freq)
+                               double_parm++;
+                       freq = string_to_frequency(optarg);
+                       if (freq == 0) {
+                               print_unknown_arg();
+                               return -EINVAL;
+                       }
+                       break;
+               case 'g':
+                       if (new_pol.governor)
+                               double_parm++;
+                       policychange++;
+                       if ((strlen(optarg) < 3) || (strlen(optarg) > 18)) {
+                               print_unknown_arg();
+                               return -EINVAL;
+                       }
+                       if ((sscanf(optarg, "%s", gov)) != 1) {
+                               print_unknown_arg();
+                               return -EINVAL;
+                       }
+                       new_pol.governor = gov;
+                       break;
+               }
+       } while (cont);
+
+       /* parameter checking */
+       if (double_parm) {
+               printf("the same parameter was passed more than once\n");
+               return -EINVAL;
+       }
+
+       if (freq && policychange) {
+               printf(_("the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n"
+                               "-g/--governor parameters\n"));
+               return -EINVAL;
+       }
+
+       if (!freq && !policychange) {
+               printf(_("At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n"
+                               "-g/--governor must be passed\n"));
+               return -EINVAL;
+       }
+
+       /* Default is: set all CPUs */
+       if (bitmask_isallclear(cpus_chosen))
+               bitmask_setall(cpus_chosen);
+
+       /* Also set frequency settings for related CPUs if -r is passed */
+       if (related) {
+               for (cpu = bitmask_first(cpus_chosen);
+                    cpu <= bitmask_last(cpus_chosen); cpu++) {
+                       struct cpufreq_affected_cpus *cpus;
+
+                       if (!bitmask_isbitset(cpus_chosen, cpu) ||
+                           cpufreq_cpu_exists(cpu))
+                               continue;
+
+                       cpus = cpufreq_get_related_cpus(cpu);
+                       if (!cpus)
+                               break;
+                       while (cpus->next) {
+                               bitmask_setbit(cpus_chosen, cpus->cpu);
+                               cpus = cpus->next;
+                       }
+                       cpufreq_put_related_cpus(cpus);
+               }
+       }
+
+
+       /* loop over CPUs */
+       for (cpu = bitmask_first(cpus_chosen);
+            cpu <= bitmask_last(cpus_chosen); cpu++) {
+
+               if (!bitmask_isbitset(cpus_chosen, cpu) ||
+                   cpufreq_cpu_exists(cpu))
+                       continue;
+
+               printf(_("Setting cpu: %d\n"), cpu);
+               ret = do_one_cpu(cpu, &new_pol, freq, policychange);
+               if (ret)
+                       break;
+       }
+
+       if (ret)
+               print_error();
+
+       return ret;
+}
diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c
new file mode 100644 (file)
index 0000000..70da357
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
+ *  (C) 2010       Thomas Renninger <trenn@suse.de>
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ */
+
+
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <cpufreq.h>
+
+#include "helpers/helpers.h"
+#include "helpers/sysfs.h"
+#include "helpers/bitmask.h"
+
+#define LINE_LEN 10
+
+static void cpuidle_cpu_output(unsigned int cpu, int verbose)
+{
+       int idlestates, idlestate;
+       char *tmp;
+
+       printf(_ ("Analyzing CPU %d:\n"), cpu);
+
+       idlestates = sysfs_get_idlestate_count(cpu);
+       if (idlestates == 0) {
+               printf(_("CPU %u: No idle states\n"), cpu);
+               return;
+       } else if (idlestates <= 0) {
+               printf(_("CPU %u: Can't read idle state info\n"), cpu);
+               return;
+       }
+       tmp = sysfs_get_idlestate_name(cpu, idlestates - 1);
+       if (!tmp) {
+               printf(_("Could not determine max idle state %u\n"),
+                      idlestates - 1);
+               return;
+       }
+
+       printf(_("Number of idle states: %d\n"), idlestates);
+
+       printf(_("Available idle states:"));
+       for (idlestate = 1; idlestate < idlestates; idlestate++) {
+               tmp = sysfs_get_idlestate_name(cpu, idlestate);
+               if (!tmp)
+                       continue;
+               printf(" %s", tmp);
+               free(tmp);
+       }
+       printf("\n");
+
+       if (!verbose)
+               return;
+
+       for (idlestate = 1; idlestate < idlestates; idlestate++) {
+               tmp = sysfs_get_idlestate_name(cpu, idlestate);
+               if (!tmp)
+                       continue;
+               printf("%s:\n", tmp);
+               free(tmp);
+
+               tmp = sysfs_get_idlestate_desc(cpu, idlestate);
+               if (!tmp)
+                       continue;
+               printf(_("Flags/Description: %s\n"), tmp);
+               free(tmp);
+
+               printf(_("Latency: %lu\n"),
+                      sysfs_get_idlestate_latency(cpu, idlestate));
+               printf(_("Usage: %lu\n"),
+                      sysfs_get_idlestate_usage(cpu, idlestate));
+               printf(_("Duration: %llu\n"),
+                      sysfs_get_idlestate_time(cpu, idlestate));
+       }
+       printf("\n");
+}
+
+static void cpuidle_general_output(void)
+{
+       char *tmp;
+
+       tmp = sysfs_get_cpuidle_driver();
+       if (!tmp) {
+               printf(_("Could not determine cpuidle driver\n"));
+               return;
+       }
+
+       printf(_("CPUidle driver: %s\n"), tmp);
+       free(tmp);
+
+       tmp = sysfs_get_cpuidle_governor();
+       if (!tmp) {
+               printf(_("Could not determine cpuidle governor\n"));
+               return;
+       }
+
+       printf(_("CPUidle governor: %s\n"), tmp);
+       free(tmp);
+}
+
+static void proc_cpuidle_cpu_output(unsigned int cpu)
+{
+       long max_allowed_cstate = 2000000000;
+       int cstates, cstate;
+
+       cstates = sysfs_get_idlestate_count(cpu);
+       if (cstates == 0) {
+               /*
+                * Go on and print same useless info as you'd see with
+                * cat /proc/acpi/processor/../power
+                *      printf(_("CPU %u: No C-states available\n"), cpu);
+                *      return;
+                */
+       } else if (cstates <= 0) {
+               printf(_("CPU %u: Can't read C-state info\n"), cpu);
+               return;
+       }
+       /* printf("Cstates: %d\n", cstates); */
+
+       printf(_("active state:            C0\n"));
+       printf(_("max_cstate:              C%u\n"), cstates-1);
+       printf(_("maximum allowed latency: %lu usec\n"), max_allowed_cstate);
+       printf(_("states:\t\n"));
+       for (cstate = 1; cstate < cstates; cstate++) {
+               printf(_("    C%d:                  "
+                        "type[C%d] "), cstate, cstate);
+               printf(_("promotion[--] demotion[--] "));
+               printf(_("latency[%03lu] "),
+                      sysfs_get_idlestate_latency(cpu, cstate));
+               printf(_("usage[%08lu] "),
+                      sysfs_get_idlestate_usage(cpu, cstate));
+               printf(_("duration[%020Lu] \n"),
+                      sysfs_get_idlestate_time(cpu, cstate));
+       }
+}
+
+/* --freq / -f */
+
+void idle_info_help(void)
+{
+       printf(_ ("Usage: cpupower idleinfo [options]\n"));
+       printf(_ ("Options:\n"));
+       printf(_ ("  -s, --silent         Only show general C-state information\n"));
+       printf(_ ("  -o, --proc           Prints out information like provided by the /proc/acpi/processor/*/power\n"
+              "                       interface in older kernels\n"));
+       printf(_ ("  -h, --help           Prints out this screen\n"));
+
+       printf("\n");
+}
+
+static struct option info_opts[] = {
+       { .name = "silent",     .has_arg = no_argument, .flag = NULL,   .val = 's'},
+       { .name = "proc",       .has_arg = no_argument, .flag = NULL,   .val = 'o'},
+       { .name = "help",       .has_arg = no_argument, .flag = NULL,   .val = 'h'},
+       { },
+};
+
+static inline void cpuidle_exit(int fail)
+{
+       idle_info_help();
+       exit(EXIT_FAILURE);
+}
+
+int cmd_idle_info(int argc, char **argv)
+{
+       extern char *optarg;
+       extern int optind, opterr, optopt;
+       int ret = 0, cont = 1, output_param = 0, verbose = 1;
+       unsigned int cpu = 0;
+
+       do {
+               ret = getopt_long(argc, argv, "hos", info_opts, NULL);
+               if (ret == -1)
+                       break;
+               switch (ret) {
+               case '?':
+                       output_param = '?';
+                       cont = 0;
+                       break;
+               case 'h':
+                       output_param = 'h';
+                       cont = 0;
+                       break;
+               case 's':
+                       verbose = 0;
+                       break;
+               case -1:
+                       cont = 0;
+                       break;
+               case 'o':
+                       if (output_param) {
+                               output_param = -1;
+                               cont = 0;
+                               break;
+                       }
+                       output_param = ret;
+                       break;
+               }
+       } while (cont);
+
+       switch (output_param) {
+       case -1:
+               printf(_("You can't specify more than one "
+                        "output-specific argument\n"));
+               cpuidle_exit(EXIT_FAILURE);
+       case '?':
+               printf(_("invalid or unknown argument\n"));
+               cpuidle_exit(EXIT_FAILURE);
+       case 'h':
+               cpuidle_exit(EXIT_SUCCESS);
+       }
+
+       /* Default is: show output of CPU 0 only */
+       if (bitmask_isallclear(cpus_chosen))
+               bitmask_setbit(cpus_chosen, 0);
+
+       if (output_param == 0)
+               cpuidle_general_output();
+
+       for (cpu = bitmask_first(cpus_chosen);
+            cpu <= bitmask_last(cpus_chosen); cpu++) {
+
+               if (!bitmask_isbitset(cpus_chosen, cpu) ||
+                   cpufreq_cpu_exists(cpu))
+                       continue;
+
+               switch (output_param) {
+
+               case 'o':
+                       proc_cpuidle_cpu_output(cpu);
+                       break;
+               case 0:
+                       printf("\n");
+                       cpuidle_cpu_output(cpu, verbose);
+                       break;
+               }
+       }
+       return EXIT_SUCCESS;
+}
diff --git a/tools/power/cpupower/utils/cpupower-info.c b/tools/power/cpupower/utils/cpupower-info.c
new file mode 100644 (file)
index 0000000..85253cb
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ *  (C) 2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ */
+
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <getopt.h>
+
+#include <cpufreq.h>
+#include "helpers/helpers.h"
+#include "helpers/sysfs.h"
+
+void info_help(void)
+{
+       printf(_("Usage: cpupower info [ -b ] [ -m ] [ -s ]\n"));
+       printf(_("Options:\n"));
+       printf(_("  -b, --perf-bias    Gets CPU's power vs performance policy on some\n"
+              "                           Intel models [0-15], see manpage for details\n"));
+       printf(_("  -m, --sched-mc     Gets the kernel's multi core scheduler policy.\n"));
+       printf(_("  -s, --sched-smt    Gets the kernel's thread sibling scheduler policy.\n"));
+       printf(_("  -h, --help               Prints out this screen\n"));
+       printf(_("\nPassing no option will show all info, by default only on core 0\n"));
+       printf("\n");
+}
+
+static struct option set_opts[] = {
+       { .name = "perf-bias",  .has_arg = optional_argument,   .flag = NULL,   .val = 'b'},
+       { .name = "sched-mc",   .has_arg = optional_argument,   .flag = NULL,   .val = 'm'},
+       { .name = "sched-smt",  .has_arg = optional_argument,   .flag = NULL,   .val = 's'},
+       { .name = "help",       .has_arg = no_argument,         .flag = NULL,   .val = 'h'},
+       { },
+};
+
+static void print_wrong_arg_exit(void)
+{
+       printf(_("invalid or unknown argument\n"));
+       info_help();
+       exit(EXIT_FAILURE);
+}
+
+int cmd_info(int argc, char **argv)
+{
+       extern char *optarg;
+       extern int optind, opterr, optopt;
+       unsigned int cpu;
+
+       union {
+               struct {
+                       int sched_mc:1;
+                       int sched_smt:1;
+                       int perf_bias:1;
+               };
+               int params;
+       } params = {};
+       int ret = 0;
+
+       setlocale(LC_ALL, "");
+       textdomain(PACKAGE);
+
+       /* parameter parsing */
+       while ((ret = getopt_long(argc, argv, "msbh", set_opts, NULL)) != -1) {
+               switch (ret) {
+               case 'h':
+                       info_help();
+                       return 0;
+               case 'b':
+                       if (params.perf_bias)
+                               print_wrong_arg_exit();
+                       params.perf_bias = 1;
+                       break;
+               case 'm':
+                       if (params.sched_mc)
+                               print_wrong_arg_exit();
+                       params.sched_mc = 1;
+                       break;
+               case 's':
+                       if (params.sched_smt)
+                               print_wrong_arg_exit();
+                       params.sched_smt = 1;
+                       break;
+               default:
+                       print_wrong_arg_exit();
+               }
+       };
+
+       if (!params.params)
+               params.params = 0x7;
+
+       /* Default is: show output of CPU 0 only */
+       if (bitmask_isallclear(cpus_chosen))
+               bitmask_setbit(cpus_chosen, 0);
+
+       if (params.sched_mc) {
+               ret = sysfs_get_sched("mc");
+               printf(_("System's multi core scheduler setting: "));
+               if (ret < 0)
+                       /* if sysfs file is missing it's: errno == ENOENT */
+                       printf(_("not supported\n"));
+               else
+                       printf("%d\n", ret);
+       }
+       if (params.sched_smt) {
+               ret = sysfs_get_sched("smt");
+               printf(_("System's thread sibling scheduler setting: "));
+               if (ret < 0)
+                       /* if sysfs file is missing it's: errno == ENOENT */
+                       printf(_("not supported\n"));
+               else
+                       printf("%d\n", ret);
+       }
+
+       /* Add more per cpu options here */
+       if (!params.perf_bias)
+               return ret;
+
+       if (params.perf_bias) {
+               if (!run_as_root) {
+                       params.perf_bias = 0;
+                       printf(_("Intel's performance bias setting needs root privileges\n"));
+               } else if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_PERF_BIAS)) {
+                       printf(_("System does not support Intel's performance"
+                                " bias setting\n"));
+                       params.perf_bias = 0;
+               }
+       }
+
+       /* loop over CPUs */
+       for (cpu = bitmask_first(cpus_chosen);
+            cpu <= bitmask_last(cpus_chosen); cpu++) {
+
+               if (!bitmask_isbitset(cpus_chosen, cpu) ||
+                   cpufreq_cpu_exists(cpu))
+                       continue;
+
+               printf(_("analyzing CPU %d:\n"), cpu);
+
+               if (params.perf_bias) {
+                       ret = msr_intel_get_perf_bias(cpu);
+                       if (ret < 0) {
+                               printf(_("Could not read perf-bias value\n"));
+                               break;
+                       } else
+                               printf(_("perf-bias: %d\n"), ret);
+               }
+       }
+       return ret;
+}
diff --git a/tools/power/cpupower/utils/cpupower-set.c b/tools/power/cpupower/utils/cpupower-set.c
new file mode 100644 (file)
index 0000000..bc1b391
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ *  (C) 2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ */
+
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <getopt.h>
+
+#include <cpufreq.h>
+#include "helpers/helpers.h"
+#include "helpers/sysfs.h"
+#include "helpers/bitmask.h"
+
+void set_help(void)
+{
+       printf(_("Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n"));
+       printf(_("Options:\n"));
+       printf(_("  -b, --perf-bias [VAL]    Sets CPU's power vs performance policy on some\n"
+              "                           Intel models [0-15], see manpage for details\n"));
+       printf(_("  -m, --sched-mc  [VAL]    Sets the kernel's multi core scheduler policy.\n"));
+       printf(_("  -s, --sched-smt [VAL]    Sets the kernel's thread sibling scheduler policy.\n"));
+       printf(_("  -h, --help               Prints out this screen\n"));
+       printf("\n");
+}
+
+static struct option set_opts[] = {
+       { .name = "perf-bias",  .has_arg = optional_argument,   .flag = NULL,   .val = 'b'},
+       { .name = "sched-mc",   .has_arg = optional_argument,   .flag = NULL,   .val = 'm'},
+       { .name = "sched-smt",  .has_arg = optional_argument,   .flag = NULL,   .val = 's'},
+       { .name = "help",       .has_arg = no_argument,         .flag = NULL,   .val = 'h'},
+       { },
+};
+
+static void print_wrong_arg_exit(void)
+{
+       printf(_("invalid or unknown argument\n"));
+       set_help();
+       exit(EXIT_FAILURE);
+}
+
+int cmd_set(int argc, char **argv)
+{
+       extern char *optarg;
+       extern int optind, opterr, optopt;
+       unsigned int cpu;
+
+       union {
+               struct {
+                       int sched_mc:1;
+                       int sched_smt:1;
+                       int perf_bias:1;
+               };
+               int params;
+       } params;
+       int sched_mc = 0, sched_smt = 0, perf_bias = 0;
+       int ret = 0;
+
+       setlocale(LC_ALL, "");
+       textdomain(PACKAGE);
+
+       params.params = 0;
+       /* parameter parsing */
+       while ((ret = getopt_long(argc, argv, "m:s:b:h",
+                                               set_opts, NULL)) != -1) {
+               switch (ret) {
+               case 'h':
+                       set_help();
+                       return 0;
+               case 'b':
+                       if (params.perf_bias)
+                               print_wrong_arg_exit();
+                       perf_bias = atoi(optarg);
+                       if (perf_bias < 0 || perf_bias > 15) {
+                               printf(_("--perf-bias param out "
+                                        "of range [0-%d]\n"), 15);
+                               print_wrong_arg_exit();
+                       }
+                       params.perf_bias = 1;
+                       break;
+               case 'm':
+                       if (params.sched_mc)
+                               print_wrong_arg_exit();
+                       sched_mc = atoi(optarg);
+                       if (sched_mc < 0 || sched_mc > 2) {
+                               printf(_("--sched-mc param out "
+                                        "of range [0-%d]\n"), 2);
+                               print_wrong_arg_exit();
+                       }
+                       params.sched_mc = 1;
+                       break;
+               case 's':
+                       if (params.sched_smt)
+                               print_wrong_arg_exit();
+                       sched_smt = atoi(optarg);
+                       if (sched_smt < 0 || sched_smt > 2) {
+                               printf(_("--sched-smt param out "
+                                        "of range [0-%d]\n"), 2);
+                               print_wrong_arg_exit();
+                       }
+                       params.sched_smt = 1;
+                       break;
+               default:
+                       print_wrong_arg_exit();
+               }
+       };
+
+       if (!params.params) {
+               set_help();
+               return -EINVAL;
+       }
+
+       if (params.sched_mc) {
+               ret = sysfs_set_sched("mc", sched_mc);
+               if (ret)
+                       fprintf(stderr, _("Error setting sched-mc %s\n"),
+                               (ret == -ENODEV) ? "not supported" : "");
+       }
+       if (params.sched_smt) {
+               ret = sysfs_set_sched("smt", sched_smt);
+               if (ret)
+                       fprintf(stderr, _("Error setting sched-smt %s\n"),
+                               (ret == -ENODEV) ? "not supported" : "");
+       }
+
+       /* Default is: set all CPUs */
+       if (bitmask_isallclear(cpus_chosen))
+               bitmask_setall(cpus_chosen);
+
+       /* loop over CPUs */
+       for (cpu = bitmask_first(cpus_chosen);
+            cpu <= bitmask_last(cpus_chosen); cpu++) {
+
+               if (!bitmask_isbitset(cpus_chosen, cpu) ||
+                   cpufreq_cpu_exists(cpu))
+                       continue;
+
+               if (params.perf_bias) {
+                       ret = msr_intel_set_perf_bias(cpu, perf_bias);
+                       if (ret) {
+                               fprintf(stderr, _("Error setting perf-bias "
+                                                 "value on CPU %d\n"), cpu);
+                               break;
+                       }
+               }
+       }
+       return ret;
+}
diff --git a/tools/power/cpupower/utils/cpupower.c b/tools/power/cpupower/utils/cpupower.c
new file mode 100644 (file)
index 0000000..5844ae0
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ *  Ideas taken over from the perf userspace tool (included in the Linus
+ *  kernel git repo): subcommand builtins and param parsing.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "builtin.h"
+#include "helpers/helpers.h"
+#include "helpers/bitmask.h"
+
+struct cmd_struct {
+       const char *cmd;
+       int (*main)(int, const char **);
+       void (*usage)(void);
+       int needs_root;
+};
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+
+int cmd_help(int argc, const char **argv);
+
+/* Global cpu_info object available for all binaries
+ * Info only retrieved from CPU 0
+ *
+ * Values will be zero/unknown on non X86 archs
+ */
+struct cpupower_cpu_info cpupower_cpu_info;
+int run_as_root;
+/* Affected cpus chosen by -c/--cpu param */
+struct bitmask *cpus_chosen;
+
+#ifdef DEBUG
+int be_verbose;
+#endif
+
+static void print_help(void);
+
+static struct cmd_struct commands[] = {
+       { "frequency-info",     cmd_freq_info,  freq_info_help, 0       },
+       { "frequency-set",      cmd_freq_set,   freq_set_help,  1       },
+       { "idle-info",          cmd_idle_info,  idle_info_help, 0       },
+       { "set",                cmd_set,        set_help,       1       },
+       { "info",               cmd_info,       info_help,      0       },
+       { "monitor",            cmd_monitor,    monitor_help,   0       },
+       { "help",               cmd_help,       print_help,     0       },
+       /*      { "bench",      cmd_bench,      NULL,           1       }, */
+};
+
+int cmd_help(int argc, const char **argv)
+{
+       unsigned int i;
+
+       if (argc > 1) {
+               for (i = 0; i < ARRAY_SIZE(commands); i++) {
+                       struct cmd_struct *p = commands + i;
+                       if (strcmp(p->cmd, argv[1]))
+                               continue;
+                       if (p->usage) {
+                               p->usage();
+                               return EXIT_SUCCESS;
+                       }
+               }
+       }
+       print_help();
+       if (argc == 1)
+               return EXIT_SUCCESS; /* cpupower help */
+       return EXIT_FAILURE;
+}
+
+static void print_help(void)
+{
+       unsigned int i;
+
+#ifdef DEBUG
+       printf(_("cpupower [ -d ][ -c cpulist ] subcommand [ARGS]\n"));
+       printf(_("  -d, --debug      May increase output (stderr) on some subcommands\n"));
+#else
+       printf(_("cpupower [ -c cpulist ] subcommand [ARGS]\n"));
+#endif
+       printf(_("cpupower --version\n"));
+       printf(_("Supported subcommands are:\n"));
+       for (i = 0; i < ARRAY_SIZE(commands); i++)
+               printf("\t%s\n", commands[i].cmd);
+       printf(_("\nSome subcommands can make use of the -c cpulist option.\n"));
+       printf(_("Look at the general cpupower manpage how to use it\n"));
+       printf(_("and read up the subcommand's manpage whether it is supported.\n"));
+       printf(_("\nUse cpupower help subcommand for getting help for above subcommands.\n"));
+}
+
+static void print_version(void)
+{
+       printf(PACKAGE " " VERSION "\n");
+       printf(_("Report errors and bugs to %s, please.\n"), PACKAGE_BUGREPORT);
+}
+
+static void handle_options(int *argc, const char ***argv)
+{
+       int ret, x, new_argc = 0;
+
+       if (*argc < 1)
+               return;
+
+       for (x = 0;  x < *argc && ((*argv)[x])[0] == '-'; x++) {
+               const char *param = (*argv)[x];
+               if (!strcmp(param, "-h") || !strcmp(param, "--help")) {
+                       print_help();
+                       exit(EXIT_SUCCESS);
+               } else if (!strcmp(param, "-c") || !strcmp(param, "--cpu")) {
+                       if (*argc < 2) {
+                               print_help();
+                               exit(EXIT_FAILURE);
+                       }
+                       if (!strcmp((*argv)[x+1], "all"))
+                               bitmask_setall(cpus_chosen);
+                       else {
+                               ret = bitmask_parselist(
+                                               (*argv)[x+1], cpus_chosen);
+                               if (ret < 0) {
+                                       fprintf(stderr, _("Error parsing cpu "
+                                                         "list\n"));
+                                       exit(EXIT_FAILURE);
+                               }
+                       }
+                       x += 1;
+                       /* Cut out param: cpupower -c 1 info -> cpupower info */
+                       new_argc += 2;
+                       continue;
+               } else if (!strcmp(param, "-v") ||
+                       !strcmp(param, "--version")) {
+                       print_version();
+                       exit(EXIT_SUCCESS);
+#ifdef DEBUG
+               } else if (!strcmp(param, "-d") || !strcmp(param, "--debug")) {
+                       be_verbose = 1;
+                       new_argc++;
+                       continue;
+#endif
+               } else {
+                       fprintf(stderr, "Unknown option: %s\n", param);
+                       print_help();
+                       exit(EXIT_FAILURE);
+               }
+       }
+       *argc -= new_argc;
+       *argv += new_argc;
+}
+
+int main(int argc, const char *argv[])
+{
+       const char *cmd;
+       unsigned int i, ret;
+
+       cpus_chosen = bitmask_alloc(sysconf(_SC_NPROCESSORS_CONF));
+
+       argc--;
+       argv += 1;
+
+       handle_options(&argc, &argv);
+
+       cmd = argv[0];
+
+       if (argc < 1) {
+               print_help();
+               return EXIT_FAILURE;
+       }
+
+       setlocale(LC_ALL, "");
+       textdomain(PACKAGE);
+
+       /* Turn "perf cmd --help" into "perf help cmd" */
+       if (argc > 1 && !strcmp(argv[1], "--help")) {
+               argv[1] = argv[0];
+               argv[0] = cmd = "help";
+       }
+
+       get_cpu_info(0, &cpupower_cpu_info);
+       run_as_root = !getuid();
+
+       for (i = 0; i < ARRAY_SIZE(commands); i++) {
+               struct cmd_struct *p = commands + i;
+               if (strcmp(p->cmd, cmd))
+                       continue;
+               if (!run_as_root && p->needs_root) {
+                       fprintf(stderr, _("Subcommand %s needs root "
+                                         "privileges\n"), cmd);
+                       return EXIT_FAILURE;
+               }
+               ret = p->main(argc, argv);
+               if (cpus_chosen)
+                       bitmask_free(cpus_chosen);
+               return ret;
+       }
+       print_help();
+       return EXIT_FAILURE;
+}
diff --git a/tools/power/cpupower/utils/helpers/amd.c b/tools/power/cpupower/utils/helpers/amd.c
new file mode 100644 (file)
index 0000000..87d5605
--- /dev/null
@@ -0,0 +1,137 @@
+#if defined(__i386__) || defined(__x86_64__)
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#include <pci/pci.h>
+
+#include "helpers/helpers.h"
+
+#define MSR_AMD_PSTATE_STATUS  0xc0010063
+#define MSR_AMD_PSTATE         0xc0010064
+#define MSR_AMD_PSTATE_LIMIT   0xc0010061
+
+union msr_pstate {
+       struct {
+               unsigned fid:6;
+               unsigned did:3;
+               unsigned vid:7;
+               unsigned res1:6;
+               unsigned nbdid:1;
+               unsigned res2:2;
+               unsigned nbvid:7;
+               unsigned iddval:8;
+               unsigned idddiv:2;
+               unsigned res3:21;
+               unsigned en:1;
+       } bits;
+       unsigned long long val;
+};
+
+static int get_did(int family, union msr_pstate pstate)
+{
+       int t;
+
+       if (family == 0x12)
+               t = pstate.val & 0xf;
+       else
+               t = pstate.bits.did;
+
+       return t;
+}
+
+static int get_cof(int family, union msr_pstate pstate)
+{
+       int t;
+       int fid, did;
+
+       did = get_did(family, pstate);
+
+       t = 0x10;
+       fid = pstate.bits.fid;
+       if (family == 0x11)
+               t = 0x8;
+
+       return (100 * (fid + t)) >> did;
+}
+
+/* Needs:
+ * cpu          -> the cpu that gets evaluated
+ * cpu_family   -> The cpu's family (0x10, 0x12,...)
+ * boots_states -> how much boost states the machines support
+ *
+ * Fills up:
+ * pstates -> a pointer to an array of size MAX_HW_PSTATES
+ *            must be initialized with zeros.
+ *            All available  HW pstates (including boost states)
+ * no      -> amount of pstates above array got filled up with
+ *
+ * returns zero on success, -1 on failure
+ */
+int decode_pstates(unsigned int cpu, unsigned int cpu_family,
+                  int boost_states, unsigned long *pstates, int *no)
+{
+       int i, psmax, pscur;
+       union msr_pstate pstate;
+       unsigned long long val;
+
+       /* Only read out frequencies from HW when CPU might be boostable
+          to keep the code as short and clean as possible.
+          Otherwise frequencies are exported via ACPI tables.
+       */
+       if (cpu_family < 0x10 || cpu_family == 0x14)
+               return -1;
+
+       if (read_msr(cpu, MSR_AMD_PSTATE_LIMIT, &val))
+               return -1;
+
+       psmax = (val >> 4) & 0x7;
+
+       if (read_msr(cpu, MSR_AMD_PSTATE_STATUS, &val))
+               return -1;
+
+       pscur = val & 0x7;
+
+       pscur += boost_states;
+       psmax += boost_states;
+       for (i = 0; i <= psmax; i++) {
+               if (i >= MAX_HW_PSTATES) {
+                       fprintf(stderr, "HW pstates [%d] exceeding max [%d]\n",
+                               psmax, MAX_HW_PSTATES);
+                       return -1;
+               }
+               if (read_msr(cpu, MSR_AMD_PSTATE + i, &pstate.val))
+                       return -1;
+               pstates[i] = get_cof(cpu_family, pstate);
+       }
+       *no = i;
+       return 0;
+}
+
+int amd_pci_get_num_boost_states(int *active, int *states)
+{
+       struct pci_access *pci_acc;
+       int vendor_id = 0x1022;
+       int boost_dev_ids[4] = {0x1204, 0x1604, 0x1704, 0};
+       struct pci_dev *device;
+       uint8_t val = 0;
+
+       *active = *states = 0;
+
+       device = pci_acc_init(&pci_acc, vendor_id, boost_dev_ids);
+
+       if (device == NULL)
+               return -ENODEV;
+
+       val = pci_read_byte(device, 0x15c);
+       if (val & 3)
+               *active = 1;
+       else
+               *active = 0;
+       *states = (val >> 2) & 7;
+
+       pci_cleanup(pci_acc);
+       return 0;
+}
+#endif /* defined(__i386__) || defined(__x86_64__) */
diff --git a/tools/power/cpupower/utils/helpers/bitmask.c b/tools/power/cpupower/utils/helpers/bitmask.c
new file mode 100644 (file)
index 0000000..5c074c6
--- /dev/null
@@ -0,0 +1,292 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <helpers/bitmask.h>
+
+/* How many bits in an unsigned long */
+#define bitsperlong (8 * sizeof(unsigned long))
+
+/* howmany(a,b) : how many elements of size b needed to hold all of a */
+#define howmany(x, y) (((x)+((y)-1))/(y))
+
+/* How many longs in mask of n bits */
+#define longsperbits(n) howmany(n, bitsperlong)
+
+#define max(a, b) ((a) > (b) ? (a) : (b))
+
+/*
+ * Allocate and free `struct bitmask *`
+ */
+
+/* Allocate a new `struct bitmask` with a size of n bits */
+struct bitmask *bitmask_alloc(unsigned int n)
+{
+       struct bitmask *bmp;
+
+       bmp = malloc(sizeof(*bmp));
+       if (bmp == 0)
+               return 0;
+       bmp->size = n;
+       bmp->maskp = calloc(longsperbits(n), sizeof(unsigned long));
+       if (bmp->maskp == 0) {
+               free(bmp);
+               return 0;
+       }
+       return bmp;
+}
+
+/* Free `struct bitmask` */
+void bitmask_free(struct bitmask *bmp)
+{
+       if (bmp == 0)
+               return;
+       free(bmp->maskp);
+       bmp->maskp = (unsigned long *)0xdeadcdef;  /* double free tripwire */
+       free(bmp);
+}
+
+/*
+ * The routines _getbit() and _setbit() are the only
+ * routines that actually understand the layout of bmp->maskp[].
+ *
+ * On little endian architectures, this could simply be an array of
+ * bytes.  But the kernel layout of bitmasks _is_ visible to userspace
+ * via the sched_(set/get)affinity calls in Linux 2.6, and on big
+ * endian architectures, it is painfully obvious that this is an
+ * array of unsigned longs.
+ */
+
+/* Return the value (0 or 1) of bit n in bitmask bmp */
+static unsigned int _getbit(const struct bitmask *bmp, unsigned int n)
+{
+       if (n < bmp->size)
+               return (bmp->maskp[n/bitsperlong] >> (n % bitsperlong)) & 1;
+       else
+               return 0;
+}
+
+/* Set bit n in bitmask bmp to value v (0 or 1) */
+static void _setbit(struct bitmask *bmp, unsigned int n, unsigned int v)
+{
+       if (n < bmp->size) {
+               if (v)
+                       bmp->maskp[n/bitsperlong] |= 1UL << (n % bitsperlong);
+               else
+                       bmp->maskp[n/bitsperlong] &=
+                               ~(1UL << (n % bitsperlong));
+       }
+}
+
+/*
+ * When parsing bitmask lists, only allow numbers, separated by one
+ * of the allowed next characters.
+ *
+ * The parameter 'sret' is the return from a sscanf "%u%c".  It is
+ * -1 if the sscanf input string was empty.  It is 0 if the first
+ * character in the sscanf input string was not a decimal number.
+ * It is 1 if the unsigned number matching the "%u" was the end of the
+ * input string.  It is 2 if one or more additional characters followed
+ * the matched unsigned number.  If it is 2, then 'nextc' is the first
+ * character following the number.  The parameter 'ok_next_chars'
+ * is the nul-terminated list of allowed next characters.
+ *
+ * The mask term just scanned was ok if and only if either the numbers
+ * matching the %u were all of the input or if the next character in
+ * the input past the numbers was one of the allowed next characters.
+ */
+static int scan_was_ok(int sret, char nextc, const char *ok_next_chars)
+{
+       return sret == 1 ||
+               (sret == 2 && strchr(ok_next_chars, nextc) != NULL);
+}
+
+static const char *nexttoken(const char *q,  int sep)
+{
+       if (q)
+               q = strchr(q, sep);
+       if (q)
+               q++;
+       return q;
+}
+
+/* Set a single bit i in bitmask */
+struct bitmask *bitmask_setbit(struct bitmask *bmp, unsigned int i)
+{
+       _setbit(bmp, i, 1);
+       return bmp;
+}
+
+/* Set all bits in bitmask: bmp = ~0 */
+struct bitmask *bitmask_setall(struct bitmask *bmp)
+{
+       unsigned int i;
+       for (i = 0; i < bmp->size; i++)
+               _setbit(bmp, i, 1);
+       return bmp;
+}
+
+/* Clear all bits in bitmask: bmp = 0 */
+struct bitmask *bitmask_clearall(struct bitmask *bmp)
+{
+       unsigned int i;
+       for (i = 0; i < bmp->size; i++)
+               _setbit(bmp, i, 0);
+       return bmp;
+}
+
+/* True if all bits are clear */
+int bitmask_isallclear(const struct bitmask *bmp)
+{
+       unsigned int i;
+       for (i = 0; i < bmp->size; i++)
+               if (_getbit(bmp, i))
+                       return 0;
+       return 1;
+}
+
+/* True if specified bit i is set */
+int bitmask_isbitset(const struct bitmask *bmp, unsigned int i)
+{
+       return _getbit(bmp, i);
+}
+
+/* Number of lowest set bit (min) */
+unsigned int bitmask_first(const struct bitmask *bmp)
+{
+       return bitmask_next(bmp, 0);
+}
+
+/* Number of highest set bit (max) */
+unsigned int bitmask_last(const struct bitmask *bmp)
+{
+       unsigned int i;
+       unsigned int m = bmp->size;
+       for (i = 0; i < bmp->size; i++)
+               if (_getbit(bmp, i))
+                       m = i;
+       return m;
+}
+
+/* Number of next set bit at or above given bit i */
+unsigned int bitmask_next(const struct bitmask *bmp, unsigned int i)
+{
+       unsigned int n;
+       for (n = i; n < bmp->size; n++)
+               if (_getbit(bmp, n))
+                       break;
+       return n;
+}
+
+/*
+ * Parses a comma-separated list of numbers and ranges of numbers,
+ * with optional ':%u' strides modifying ranges, into provided bitmask.
+ * Some examples of input lists and their equivalent simple list:
+ *     Input           Equivalent to
+ *     0-3             0,1,2,3
+ *     0-7:2           0,2,4,6
+ *     1,3,5-7         1,3,5,6,7
+ *     0-3:2,8-15:4    0,2,8,12
+ */
+int bitmask_parselist(const char *buf, struct bitmask *bmp)
+{
+       const char *p, *q;
+
+       bitmask_clearall(bmp);
+
+       q = buf;
+       while (p = q, q = nexttoken(q, ','), p) {
+               unsigned int a;         /* begin of range */
+               unsigned int b;         /* end of range */
+               unsigned int s;         /* stride */
+               const char *c1, *c2;    /* next tokens after '-' or ',' */
+               char nextc;             /* char after sscanf %u match */
+               int sret;               /* sscanf return (number of matches) */
+
+               sret = sscanf(p, "%u%c", &a, &nextc);
+               if (!scan_was_ok(sret, nextc, ",-"))
+                       goto err;
+               b = a;
+               s = 1;
+               c1 = nexttoken(p, '-');
+               c2 = nexttoken(p, ',');
+               if (c1 != NULL && (c2 == NULL || c1 < c2)) {
+                       sret = sscanf(c1, "%u%c", &b, &nextc);
+                       if (!scan_was_ok(sret, nextc, ",:"))
+                               goto err;
+                       c1 = nexttoken(c1, ':');
+                       if (c1 != NULL && (c2 == NULL || c1 < c2)) {
+                               sret = sscanf(c1, "%u%c", &s, &nextc);
+                               if (!scan_was_ok(sret, nextc, ","))
+                                       goto err;
+                       }
+               }
+               if (!(a <= b))
+                       goto err;
+               if (b >= bmp->size)
+                       goto err;
+               while (a <= b) {
+                       _setbit(bmp, a, 1);
+                       a += s;
+               }
+       }
+       return 0;
+err:
+       bitmask_clearall(bmp);
+       return -1;
+}
+
+/*
+ * emit(buf, buflen, rbot, rtop, len)
+ *
+ * Helper routine for bitmask_displaylist().  Write decimal number
+ * or range to buf+len, suppressing output past buf+buflen, with optional
+ * comma-prefix.  Return len of what would be written to buf, if it
+ * all fit.
+ */
+
+static inline int emit(char *buf, int buflen, int rbot, int rtop, int len)
+{
+       if (len > 0)
+               len += snprintf(buf + len, max(buflen - len, 0), ",");
+       if (rbot == rtop)
+               len += snprintf(buf + len, max(buflen - len, 0), "%d", rbot);
+       else
+               len += snprintf(buf + len, max(buflen - len, 0), "%d-%d",
+                               rbot, rtop);
+       return len;
+}
+
+/*
+ * Write decimal list representation of bmp to buf.
+ *
+ * Output format is a comma-separated list of decimal numbers and
+ * ranges.  Consecutively set bits are shown as two hyphen-separated
+ * decimal numbers, the smallest and largest bit numbers set in
+ * the range.  Output format is compatible with the format
+ * accepted as input by bitmap_parselist().
+ *
+ * The return value is the number of characters which would be
+ * generated for the given input, excluding the trailing '\0', as
+ * per ISO C99.
+ */
+
+int bitmask_displaylist(char *buf, int buflen, const struct bitmask *bmp)
+{
+       int len = 0;
+       /* current bit is 'cur', most recently seen range is [rbot, rtop] */
+       unsigned int cur, rbot, rtop;
+
+       if (buflen > 0)
+               *buf = 0;
+       rbot = cur = bitmask_first(bmp);
+       while (cur < bmp->size) {
+               rtop = cur;
+               cur = bitmask_next(bmp, cur+1);
+               if (cur >= bmp->size || cur > rtop + 1) {
+                       len = emit(buf, buflen, rbot, rtop, len);
+                       rbot = cur;
+               }
+       }
+       return len;
+}
diff --git a/tools/power/cpupower/utils/helpers/bitmask.h b/tools/power/cpupower/utils/helpers/bitmask.h
new file mode 100644 (file)
index 0000000..eb289df
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef __CPUPOWER_BITMASK__
+#define __CPUPOWER_BITMASK__
+
+/* Taken over from libbitmask, a project initiated from sgi:
+ * Url:            http://oss.sgi.com/projects/cpusets/
+ * Unfortunately it's not very widespread, therefore relevant parts are
+ * pasted here.
+ */
+
+struct bitmask {
+       unsigned int size;
+       unsigned long *maskp;
+};
+
+struct bitmask *bitmask_alloc(unsigned int n);
+void bitmask_free(struct bitmask *bmp);
+
+struct bitmask *bitmask_setbit(struct bitmask *bmp, unsigned int i);
+struct bitmask *bitmask_setall(struct bitmask *bmp);
+struct bitmask *bitmask_clearall(struct bitmask *bmp);
+
+unsigned int bitmask_first(const struct bitmask *bmp);
+unsigned int bitmask_next(const struct bitmask *bmp, unsigned int i);
+unsigned int bitmask_last(const struct bitmask *bmp);
+int bitmask_isallclear(const struct bitmask *bmp);
+int bitmask_isbitset(const struct bitmask *bmp, unsigned int i);
+
+int bitmask_parselist(const char *buf, struct bitmask *bmp);
+int bitmask_displaylist(char *buf, int len, const struct bitmask *bmp);
+
+
+
+#endif /*__CPUPOWER_BITMASK__ */
diff --git a/tools/power/cpupower/utils/helpers/cpuid.c b/tools/power/cpupower/utils/helpers/cpuid.c
new file mode 100644 (file)
index 0000000..906895d
--- /dev/null
@@ -0,0 +1,176 @@
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "helpers/helpers.h"
+
+static const char *cpu_vendor_table[X86_VENDOR_MAX] = {
+       "Unknown", "GenuineIntel", "AuthenticAMD",
+};
+
+#if defined(__i386__) || defined(__x86_64__)
+
+/* from gcc */
+#include <cpuid.h>
+
+/*
+ * CPUID functions returning a single datum
+ *
+ * Define unsigned int cpuid_e[abcd]x(unsigned int op)
+ */
+#define cpuid_func(reg)                                        \
+       unsigned int cpuid_##reg(unsigned int op)       \
+       {                                               \
+       unsigned int eax, ebx, ecx, edx;                \
+       __cpuid(op, eax, ebx, ecx, edx);                \
+       return reg;                                     \
+       }
+cpuid_func(eax);
+cpuid_func(ebx);
+cpuid_func(ecx);
+cpuid_func(edx);
+
+#endif /* defined(__i386__) || defined(__x86_64__) */
+
+/* get_cpu_info
+ *
+ * Extract CPU vendor, family, model, stepping info from /proc/cpuinfo
+ *
+ * Returns 0 on success or a negativ error code
+ *
+ * TBD: Should there be a cpuid alternative for this if /proc is not mounted?
+ */
+int get_cpu_info(unsigned int cpu, struct cpupower_cpu_info *cpu_info)
+{
+       FILE *fp;
+       char value[64];
+       unsigned int proc, x;
+       unsigned int unknown = 0xffffff;
+       unsigned int cpuid_level, ext_cpuid_level;
+
+       int ret = -EINVAL;
+
+       cpu_info->vendor                = X86_VENDOR_UNKNOWN;
+       cpu_info->family                = unknown;
+       cpu_info->model                 = unknown;
+       cpu_info->stepping              = unknown;
+       cpu_info->caps                  = 0;
+
+       fp = fopen("/proc/cpuinfo", "r");
+       if (!fp)
+               return -EIO;
+
+       while (!feof(fp)) {
+               if (!fgets(value, 64, fp))
+                       continue;
+               value[63 - 1] = '\0';
+
+               if (!strncmp(value, "processor\t: ", 12))
+                       sscanf(value, "processor\t: %u", &proc);
+
+               if (proc != cpu)
+                       continue;
+
+               /* Get CPU vendor */
+               if (!strncmp(value, "vendor_id", 9)) {
+                       for (x = 1; x < X86_VENDOR_MAX; x++) {
+                               if (strstr(value, cpu_vendor_table[x]))
+                                       cpu_info->vendor = x;
+                       }
+               /* Get CPU family, etc. */
+               } else if (!strncmp(value, "cpu family\t: ", 13)) {
+                       sscanf(value, "cpu family\t: %u",
+                              &cpu_info->family);
+               } else if (!strncmp(value, "model\t\t: ", 9)) {
+                       sscanf(value, "model\t\t: %u",
+                              &cpu_info->model);
+               } else if (!strncmp(value, "stepping\t: ", 10)) {
+                       sscanf(value, "stepping\t: %u",
+                              &cpu_info->stepping);
+
+                       /* Exit -> all values must have been set */
+                       if (cpu_info->vendor == X86_VENDOR_UNKNOWN ||
+                           cpu_info->family == unknown ||
+                           cpu_info->model == unknown ||
+                           cpu_info->stepping == unknown) {
+                               ret = -EINVAL;
+                               goto out;
+                       }
+
+                       ret = 0;
+                       goto out;
+               }
+       }
+       ret = -ENODEV;
+out:
+       fclose(fp);
+       /* Get some useful CPU capabilities from cpuid */
+       if (cpu_info->vendor != X86_VENDOR_AMD &&
+           cpu_info->vendor != X86_VENDOR_INTEL)
+               return ret;
+
+       cpuid_level     = cpuid_eax(0);
+       ext_cpuid_level = cpuid_eax(0x80000000);
+
+       /* Invariant TSC */
+       if (ext_cpuid_level >= 0x80000007 &&
+           (cpuid_edx(0x80000007) & (1 << 8)))
+               cpu_info->caps |= CPUPOWER_CAP_INV_TSC;
+
+       /* Aperf/Mperf registers support */
+       if (cpuid_level >= 6 && (cpuid_ecx(6) & 0x1))
+               cpu_info->caps |= CPUPOWER_CAP_APERF;
+
+       /* AMD Boost state enable/disable register */
+       if (cpu_info->vendor == X86_VENDOR_AMD) {
+               if (ext_cpuid_level >= 0x80000007 &&
+                   (cpuid_edx(0x80000007) & (1 << 9)))
+                       cpu_info->caps |= CPUPOWER_CAP_AMD_CBP;
+       }
+
+       if (cpu_info->vendor == X86_VENDOR_INTEL) {
+               if (cpuid_level >= 6 &&
+                   (cpuid_eax(6) & (1 << 1)))
+                       cpu_info->caps |= CPUPOWER_CAP_INTEL_IDA;
+       }
+
+       if (cpu_info->vendor == X86_VENDOR_INTEL) {
+               /* Intel's perf-bias MSR support */
+               if (cpuid_level >= 6 && (cpuid_ecx(6) & (1 << 3)))
+                       cpu_info->caps |= CPUPOWER_CAP_PERF_BIAS;
+
+               /* Intel's Turbo Ratio Limit support */
+               if (cpu_info->family == 6) {
+                       switch (cpu_info->model) {
+                       case 0x1A:      /* Core i7, Xeon 5500 series
+                                        * Bloomfield, Gainstown NHM-EP
+                                        */
+                       case 0x1E:      /* Core i7 and i5 Processor
+                                        * Clarksfield, Lynnfield, Jasper Forest
+                                        */
+                       case 0x1F:      /* Core i7 and i5 Processor - Nehalem */
+                       case 0x25:      /* Westmere Client
+                                        * Clarkdale, Arrandale
+                                        */
+                       case 0x2C:      /* Westmere EP - Gulftown */
+                               cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
+                       case 0x2A:      /* SNB */
+                       case 0x2D:      /* SNB Xeon */
+                               cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
+                               cpu_info->caps |= CPUPOWER_CAP_IS_SNB;
+                               break;
+                       case 0x2E:      /* Nehalem-EX Xeon - Beckton */
+                       case 0x2F:      /* Westmere-EX Xeon - Eagleton */
+                       default:
+                               break;
+                       }
+               }
+       }
+
+       /*      printf("ID: %u - Extid: 0x%x - Caps: 0x%llx\n",
+               cpuid_level, ext_cpuid_level, cpu_info->caps);
+       */
+       return ret;
+}
diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h
new file mode 100644 (file)
index 0000000..592ee36
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ * Miscellaneous helpers which do not fit or are worth
+ * to put into separate headers
+ */
+
+#ifndef __CPUPOWERUTILS_HELPERS__
+#define __CPUPOWERUTILS_HELPERS__
+
+#include <libintl.h>
+#include <locale.h>
+
+#include "helpers/bitmask.h"
+
+/* Internationalization ****************************/
+#define _(String) gettext(String)
+#ifndef gettext_noop
+#define gettext_noop(String) String
+#endif
+#define N_(String) gettext_noop(String)
+/* Internationalization ****************************/
+
+extern int run_as_root;
+extern struct bitmask *cpus_chosen;
+
+/* Global verbose (-d) stuff *********************************/
+/*
+ * define DEBUG via global Makefile variable
+ * Debug output is sent to stderr, do:
+ * cpupower monitor 2>/tmp/debug
+ * to split debug output away from normal output
+*/
+#ifdef DEBUG
+extern int be_verbose;
+
+#define dprint(fmt, ...) {                                     \
+               if (be_verbose) {                               \
+                       fprintf(stderr, "%s: " fmt,             \
+                               __func__, ##__VA_ARGS__);       \
+               }                                               \
+       }
+#else
+static inline void dprint(const char *fmt, ...) { }
+#endif
+extern int be_verbose;
+/* Global verbose (-v) stuff *********************************/
+
+/* cpuid and cpuinfo helpers  **************************/
+enum cpupower_cpu_vendor {X86_VENDOR_UNKNOWN = 0, X86_VENDOR_INTEL,
+                         X86_VENDOR_AMD, X86_VENDOR_MAX};
+
+#define CPUPOWER_CAP_INV_TSC           0x00000001
+#define CPUPOWER_CAP_APERF             0x00000002
+#define CPUPOWER_CAP_AMD_CBP           0x00000004
+#define CPUPOWER_CAP_PERF_BIAS         0x00000008
+#define CPUPOWER_CAP_HAS_TURBO_RATIO   0x00000010
+#define CPUPOWER_CAP_IS_SNB            0x00000011
+#define CPUPOWER_CAP_INTEL_IDA         0x00000012
+
+#define MAX_HW_PSTATES 10
+
+struct cpupower_cpu_info {
+       enum cpupower_cpu_vendor vendor;
+       unsigned int family;
+       unsigned int model;
+       unsigned int stepping;
+       /* CPU capabilities read out from cpuid */
+       unsigned long long caps;
+};
+
+/* get_cpu_info
+ *
+ * Extract CPU vendor, family, model, stepping info from /proc/cpuinfo
+ *
+ * Returns 0 on success or a negativ error code
+ * Only used on x86, below global's struct values are zero/unknown on
+ * other archs
+ */
+extern int get_cpu_info(unsigned int cpu, struct cpupower_cpu_info *cpu_info);
+extern struct cpupower_cpu_info cpupower_cpu_info;
+/* cpuid and cpuinfo helpers  **************************/
+
+
+/* CPU topology/hierarchy parsing ******************/
+struct cpupower_topology {
+       /* Amount of CPU cores, packages and threads per core in the system */
+       unsigned int cores;
+       unsigned int pkgs;
+       unsigned int threads; /* per core */
+
+       /* Array gets mallocated with cores entries, holding per core info */
+       struct {
+               int pkg;
+               int core;
+               int cpu;
+       } *core_info;
+};
+
+extern int get_cpu_topology(struct cpupower_topology *cpu_top);
+extern void cpu_topology_release(struct cpupower_topology cpu_top);
+/* CPU topology/hierarchy parsing ******************/
+
+/* X86 ONLY ****************************************/
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <pci/pci.h>
+
+/* Read/Write msr ****************************/
+extern int read_msr(int cpu, unsigned int idx, unsigned long long *val);
+extern int write_msr(int cpu, unsigned int idx, unsigned long long val);
+
+extern int msr_intel_set_perf_bias(unsigned int cpu, unsigned int val);
+extern int msr_intel_get_perf_bias(unsigned int cpu);
+extern unsigned long long msr_intel_get_turbo_ratio(unsigned int cpu);
+
+/* Read/Write msr ****************************/
+
+/* PCI stuff ****************************/
+extern int amd_pci_get_num_boost_states(int *active, int *states);
+extern struct pci_dev *pci_acc_init(struct pci_access **pacc, int vendor_id,
+                                   int *dev_ids);
+
+/* PCI stuff ****************************/
+
+/* AMD HW pstate decoding **************************/
+
+extern int decode_pstates(unsigned int cpu, unsigned int cpu_family,
+                         int boost_states, unsigned long *pstates, int *no);
+
+/* AMD HW pstate decoding **************************/
+
+extern int cpufreq_has_boost_support(unsigned int cpu, int *support,
+                                    int *active, int * states);
+/*
+ * CPUID functions returning a single datum
+ */
+unsigned int cpuid_eax(unsigned int op);
+unsigned int cpuid_ebx(unsigned int op);
+unsigned int cpuid_ecx(unsigned int op);
+unsigned int cpuid_edx(unsigned int op);
+
+/* cpuid and cpuinfo helpers  **************************/
+/* X86 ONLY ********************************************/
+#else
+static inline int decode_pstates(unsigned int cpu, unsigned int cpu_family,
+                                int boost_states, unsigned long *pstates,
+                                int *no)
+{ return -1; };
+
+static inline int read_msr(int cpu, unsigned int idx, unsigned long long *val)
+{ return -1; };
+static inline int write_msr(int cpu, unsigned int idx, unsigned long long val)
+{ return -1; };
+static inline int msr_intel_set_perf_bias(unsigned int cpu, unsigned int val)
+{ return -1; };
+static inline int msr_intel_get_perf_bias(unsigned int cpu)
+{ return -1; };
+static inline unsigned long long msr_intel_get_turbo_ratio(unsigned int cpu)
+{ return 0; };
+
+/* Read/Write msr ****************************/
+
+static inline int cpufreq_has_boost_support(unsigned int cpu, int *support,
+                                           int *active, int * states)
+{ return -1; }
+
+/* cpuid and cpuinfo helpers  **************************/
+
+static inline unsigned int cpuid_eax(unsigned int op) { return 0; };
+static inline unsigned int cpuid_ebx(unsigned int op) { return 0; };
+static inline unsigned int cpuid_ecx(unsigned int op) { return 0; };
+static inline unsigned int cpuid_edx(unsigned int op) { return 0; };
+#endif /* defined(__i386__) || defined(__x86_64__) */
+
+#endif /* __CPUPOWERUTILS_HELPERS__ */
diff --git a/tools/power/cpupower/utils/helpers/misc.c b/tools/power/cpupower/utils/helpers/misc.c
new file mode 100644 (file)
index 0000000..1609243
--- /dev/null
@@ -0,0 +1,27 @@
+#if defined(__i386__) || defined(__x86_64__)
+
+#include "helpers/helpers.h"
+
+int cpufreq_has_boost_support(unsigned int cpu, int *support, int *active,
+                       int *states)
+{
+       struct cpupower_cpu_info cpu_info;
+       int ret;
+
+       *support = *active = *states = 0;
+
+       ret = get_cpu_info(0, &cpu_info);
+       if (ret)
+               return ret;
+
+       if (cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_CBP) {
+               *support = 1;
+               amd_pci_get_num_boost_states(active, states);
+               if (ret <= 0)
+                       return ret;
+               *support = 1;
+       } else if (cpupower_cpu_info.caps & CPUPOWER_CAP_INTEL_IDA)
+               *support = *active = 1;
+       return 0;
+}
+#endif /* #if defined(__i386__) || defined(__x86_64__) */
diff --git a/tools/power/cpupower/utils/helpers/msr.c b/tools/power/cpupower/utils/helpers/msr.c
new file mode 100644 (file)
index 0000000..31a4b24
--- /dev/null
@@ -0,0 +1,115 @@
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#include "helpers/helpers.h"
+
+/* Intel specific MSRs */
+#define MSR_IA32_PERF_STATUS           0x198
+#define MSR_IA32_MISC_ENABLES          0x1a0
+#define MSR_IA32_ENERGY_PERF_BIAS      0x1b0
+#define MSR_NEHALEM_TURBO_RATIO_LIMIT  0x1ad
+
+/*
+ * read_msr
+ *
+ * Will return 0 on success and -1 on failure.
+ * Possible errno values could be:
+ * EFAULT -If the read/write did not fully complete
+ * EIO    -If the CPU does not support MSRs
+ * ENXIO  -If the CPU does not exist
+ */
+
+int read_msr(int cpu, unsigned int idx, unsigned long long *val)
+{
+       int fd;
+       char msr_file_name[64];
+
+       sprintf(msr_file_name, "/dev/cpu/%d/msr", cpu);
+       fd = open(msr_file_name, O_RDONLY);
+       if (fd < 0)
+               return -1;
+       if (lseek(fd, idx, SEEK_CUR) == -1)
+               goto err;
+       if (read(fd, val, sizeof *val) != sizeof *val)
+               goto err;
+       close(fd);
+       return 0;
+ err:
+       close(fd);
+       return -1;
+}
+
+/*
+ * write_msr
+ *
+ * Will return 0 on success and -1 on failure.
+ * Possible errno values could be:
+ * EFAULT -If the read/write did not fully complete
+ * EIO    -If the CPU does not support MSRs
+ * ENXIO  -If the CPU does not exist
+ */
+int write_msr(int cpu, unsigned int idx, unsigned long long val)
+{
+       int fd;
+       char msr_file_name[64];
+
+       sprintf(msr_file_name, "/dev/cpu/%d/msr", cpu);
+       fd = open(msr_file_name, O_WRONLY);
+       if (fd < 0)
+               return -1;
+       if (lseek(fd, idx, SEEK_CUR) == -1)
+               goto err;
+       if (write(fd, &val, sizeof val) != sizeof val)
+               goto err;
+       close(fd);
+       return 0;
+ err:
+       close(fd);
+       return -1;
+}
+
+int msr_intel_get_perf_bias(unsigned int cpu)
+{
+       unsigned long long val;
+       int ret;
+
+       if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_PERF_BIAS))
+               return -1;
+
+       ret = read_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, &val);
+       if (ret)
+               return ret;
+       return val;
+}
+
+int msr_intel_set_perf_bias(unsigned int cpu, unsigned int val)
+{
+       int ret;
+
+       if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_PERF_BIAS))
+               return -1;
+
+       ret = write_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, val);
+       if (ret)
+               return ret;
+       return 0;
+}
+
+unsigned long long msr_intel_get_turbo_ratio(unsigned int cpu)
+{
+       unsigned long long val;
+       int ret;
+
+       if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_HAS_TURBO_RATIO))
+               return -1;
+
+       ret = read_msr(cpu, MSR_NEHALEM_TURBO_RATIO_LIMIT, &val);
+       if (ret)
+               return ret;
+       return val;
+}
+#endif
diff --git a/tools/power/cpupower/utils/helpers/pci.c b/tools/power/cpupower/utils/helpers/pci.c
new file mode 100644 (file)
index 0000000..cd2eb6f
--- /dev/null
@@ -0,0 +1,44 @@
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <helpers/helpers.h>
+
+/*
+ * pci_acc_init
+ *
+ * PCI access helper function depending on libpci
+ *
+ * **pacc : if a valid pci_dev is returned
+ *         *pacc must be passed to pci_acc_cleanup to free it
+ *
+ * vendor_id : the pci vendor id matching the pci device to access
+ * dev_ids :   device ids matching the pci device to access
+ *
+ * Returns :
+ * struct pci_dev which can be used with pci_{read,write}_* functions
+ *                to access the PCI config space of matching pci devices
+ */
+struct pci_dev *pci_acc_init(struct pci_access **pacc, int vendor_id,
+                                   int *dev_ids)
+{
+       struct pci_filter filter_nb_link = { -1, -1, -1, -1, vendor_id, 0};
+       struct pci_dev *device;
+       unsigned int i;
+
+       *pacc = pci_alloc();
+       if (*pacc == NULL)
+               return NULL;
+
+       pci_init(*pacc);
+       pci_scan_bus(*pacc);
+
+       for (i = 0; dev_ids[i] != 0; i++) {
+               filter_nb_link.device = dev_ids[i];
+               for (device = (*pacc)->devices; device; device = device->next) {
+                       if (pci_filter_match(&filter_nb_link, device))
+                               return device;
+               }
+       }
+       pci_cleanup(*pacc);
+       return NULL;
+}
+#endif /* defined(__i386__) || defined(__x86_64__) */
diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c
new file mode 100644 (file)
index 0000000..55e2466
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
+ *  (C) 2011       Thomas Renninger <trenn@novell.com> Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "helpers/sysfs.h"
+
+unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen)
+{
+       int fd;
+       ssize_t numread;
+
+       fd = open(path, O_RDONLY);
+       if (fd == -1)
+               return 0;
+
+       numread = read(fd, buf, buflen - 1);
+       if (numread < 1) {
+               close(fd);
+               return 0;
+       }
+
+       buf[numread] = '\0';
+       close(fd);
+
+       return (unsigned int) numread;
+}
+
+static unsigned int sysfs_write_file(const char *path,
+                                    const char *value, size_t len)
+{
+       int fd;
+       ssize_t numwrite;
+
+       fd = open(path, O_WRONLY);
+       if (fd == -1)
+               return 0;
+
+       numwrite = write(fd, value, len);
+       if (numwrite < 1) {
+               close(fd);
+               return 0;
+       }
+       close(fd);
+       return (unsigned int) numwrite;
+}
+
+/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
+
+/*
+ * helper function to read file from /sys into given buffer
+ * fname is a relative path under "cpuX/cpuidle/stateX/" dir
+ * cstates starting with 0, C0 is not counted as cstate.
+ * This means if you want C1 info, pass 0 as idlestate param
+ */
+unsigned int sysfs_idlestate_read_file(unsigned int cpu, unsigned int idlestate,
+                            const char *fname, char *buf, size_t buflen)
+{
+       char path[SYSFS_PATH_MAX];
+       int fd;
+       ssize_t numread;
+
+       snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
+                cpu, idlestate, fname);
+
+       fd = open(path, O_RDONLY);
+       if (fd == -1)
+               return 0;
+
+       numread = read(fd, buf, buflen - 1);
+       if (numread < 1) {
+               close(fd);
+               return 0;
+       }
+
+       buf[numread] = '\0';
+       close(fd);
+
+       return (unsigned int) numread;
+}
+
+/* read access to files which contain one numeric value */
+
+enum idlestate_value {
+       IDLESTATE_USAGE,
+       IDLESTATE_POWER,
+       IDLESTATE_LATENCY,
+       IDLESTATE_TIME,
+       MAX_IDLESTATE_VALUE_FILES
+};
+
+static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = {
+       [IDLESTATE_USAGE] = "usage",
+       [IDLESTATE_POWER] = "power",
+       [IDLESTATE_LATENCY] = "latency",
+       [IDLESTATE_TIME]  = "time",
+};
+
+static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu,
+                                                    unsigned int idlestate,
+                                                    enum idlestate_value which)
+{
+       unsigned long long value;
+       unsigned int len;
+       char linebuf[MAX_LINE_LEN];
+       char *endp;
+
+       if (which >= MAX_IDLESTATE_VALUE_FILES)
+               return 0;
+
+       len = sysfs_idlestate_read_file(cpu, idlestate,
+                                       idlestate_value_files[which],
+                                       linebuf, sizeof(linebuf));
+       if (len == 0)
+               return 0;
+
+       value = strtoull(linebuf, &endp, 0);
+
+       if (endp == linebuf || errno == ERANGE)
+               return 0;
+
+       return value;
+}
+
+/* read access to files which contain one string */
+
+enum idlestate_string {
+       IDLESTATE_DESC,
+       IDLESTATE_NAME,
+       MAX_IDLESTATE_STRING_FILES
+};
+
+static const char *idlestate_string_files[MAX_IDLESTATE_STRING_FILES] = {
+       [IDLESTATE_DESC] = "desc",
+       [IDLESTATE_NAME] = "name",
+};
+
+
+static char *sysfs_idlestate_get_one_string(unsigned int cpu,
+                                       unsigned int idlestate,
+                                       enum idlestate_string which)
+{
+       char linebuf[MAX_LINE_LEN];
+       char *result;
+       unsigned int len;
+
+       if (which >= MAX_IDLESTATE_STRING_FILES)
+               return NULL;
+
+       len = sysfs_idlestate_read_file(cpu, idlestate,
+                                       idlestate_string_files[which],
+                                       linebuf, sizeof(linebuf));
+       if (len == 0)
+               return NULL;
+
+       result = strdup(linebuf);
+       if (result == NULL)
+               return NULL;
+
+       if (result[strlen(result) - 1] == '\n')
+               result[strlen(result) - 1] = '\0';
+
+       return result;
+}
+
+unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
+                                       unsigned int idlestate)
+{
+       return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY);
+}
+
+unsigned long sysfs_get_idlestate_usage(unsigned int cpu,
+                                       unsigned int idlestate)
+{
+       return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_USAGE);
+}
+
+unsigned long long sysfs_get_idlestate_time(unsigned int cpu,
+                                       unsigned int idlestate)
+{
+       return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_TIME);
+}
+
+char *sysfs_get_idlestate_name(unsigned int cpu, unsigned int idlestate)
+{
+       return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_NAME);
+}
+
+char *sysfs_get_idlestate_desc(unsigned int cpu, unsigned int idlestate)
+{
+       return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_DESC);
+}
+
+/*
+ * Returns number of supported C-states of CPU core cpu
+ * Negativ in error case
+ * Zero if cpuidle does not export any C-states
+ */
+int sysfs_get_idlestate_count(unsigned int cpu)
+{
+       char file[SYSFS_PATH_MAX];
+       struct stat statbuf;
+       int idlestates = 1;
+
+
+       snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpuidle");
+       if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
+               return -ENODEV;
+
+       snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/cpuidle/state0", cpu);
+       if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
+               return 0;
+
+       while (stat(file, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) {
+               snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU
+                        "cpu%u/cpuidle/state%d", cpu, idlestates);
+               idlestates++;
+       }
+       idlestates--;
+       return idlestates;
+}
+
+/* CPUidle general /sys/devices/system/cpu/cpuidle/ sysfs access ********/
+
+/*
+ * helper function to read file from /sys into given buffer
+ * fname is a relative path under "cpu/cpuidle/" dir
+ */
+static unsigned int sysfs_cpuidle_read_file(const char *fname, char *buf,
+                                           size_t buflen)
+{
+       char path[SYSFS_PATH_MAX];
+
+       snprintf(path, sizeof(path), PATH_TO_CPU "cpuidle/%s", fname);
+
+       return sysfs_read_file(path, buf, buflen);
+}
+
+
+
+/* read access to files which contain one string */
+
+enum cpuidle_string {
+       CPUIDLE_GOVERNOR,
+       CPUIDLE_GOVERNOR_RO,
+       CPUIDLE_DRIVER,
+       MAX_CPUIDLE_STRING_FILES
+};
+
+static const char *cpuidle_string_files[MAX_CPUIDLE_STRING_FILES] = {
+       [CPUIDLE_GOVERNOR]      = "current_governor",
+       [CPUIDLE_GOVERNOR_RO]   = "current_governor_ro",
+       [CPUIDLE_DRIVER]        = "current_driver",
+};
+
+
+static char *sysfs_cpuidle_get_one_string(enum cpuidle_string which)
+{
+       char linebuf[MAX_LINE_LEN];
+       char *result;
+       unsigned int len;
+
+       if (which >= MAX_CPUIDLE_STRING_FILES)
+               return NULL;
+
+       len = sysfs_cpuidle_read_file(cpuidle_string_files[which],
+                               linebuf, sizeof(linebuf));
+       if (len == 0)
+               return NULL;
+
+       result = strdup(linebuf);
+       if (result == NULL)
+               return NULL;
+
+       if (result[strlen(result) - 1] == '\n')
+               result[strlen(result) - 1] = '\0';
+
+       return result;
+}
+
+char *sysfs_get_cpuidle_governor(void)
+{
+       char *tmp = sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR_RO);
+       if (!tmp)
+               return sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR);
+       else
+               return tmp;
+}
+
+char *sysfs_get_cpuidle_driver(void)
+{
+       return sysfs_cpuidle_get_one_string(CPUIDLE_DRIVER);
+}
+/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
+
+/*
+ * Get sched_mc or sched_smt settings
+ * Pass "mc" or "smt" as argument
+ *
+ * Returns negative value on failure
+ */
+int sysfs_get_sched(const char *smt_mc)
+{
+       unsigned long value;
+       char linebuf[MAX_LINE_LEN];
+       char *endp;
+       char path[SYSFS_PATH_MAX];
+
+       if (strcmp("mc", smt_mc) && strcmp("smt", smt_mc))
+               return -EINVAL;
+
+       snprintf(path, sizeof(path),
+               PATH_TO_CPU "sched_%s_power_savings", smt_mc);
+       if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0)
+               return -1;
+       value = strtoul(linebuf, &endp, 0);
+       if (endp == linebuf || errno == ERANGE)
+               return -1;
+       return value;
+}
+
+/*
+ * Get sched_mc or sched_smt settings
+ * Pass "mc" or "smt" as argument
+ *
+ * Returns negative value on failure
+ */
+int sysfs_set_sched(const char *smt_mc, int val)
+{
+       char linebuf[MAX_LINE_LEN];
+       char path[SYSFS_PATH_MAX];
+       struct stat statbuf;
+
+       if (strcmp("mc", smt_mc) && strcmp("smt", smt_mc))
+               return -EINVAL;
+
+       snprintf(path, sizeof(path),
+               PATH_TO_CPU "sched_%s_power_savings", smt_mc);
+       sprintf(linebuf, "%d", val);
+
+       if (stat(path, &statbuf) != 0)
+               return -ENODEV;
+
+       if (sysfs_write_file(path, linebuf, MAX_LINE_LEN) == 0)
+               return -1;
+       return 0;
+}
diff --git a/tools/power/cpupower/utils/helpers/sysfs.h b/tools/power/cpupower/utils/helpers/sysfs.h
new file mode 100644 (file)
index 0000000..f9373e0
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef __CPUPOWER_HELPERS_SYSFS_H__
+#define __CPUPOWER_HELPERS_SYSFS_H__
+
+#define PATH_TO_CPU "/sys/devices/system/cpu/"
+#define MAX_LINE_LEN 255
+#define SYSFS_PATH_MAX 255
+
+extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen);
+
+extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
+                                               unsigned int idlestate);
+extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu,
+                                       unsigned int idlestate);
+extern unsigned long long sysfs_get_idlestate_time(unsigned int cpu,
+                                               unsigned int idlestate);
+extern char *sysfs_get_idlestate_name(unsigned int cpu,
+                               unsigned int idlestate);
+extern char *sysfs_get_idlestate_desc(unsigned int cpu,
+                               unsigned int idlestate);
+extern int sysfs_get_idlestate_count(unsigned int cpu);
+
+extern char *sysfs_get_cpuidle_governor(void);
+extern char *sysfs_get_cpuidle_driver(void);
+
+extern int sysfs_get_sched(const char *smt_mc);
+extern int sysfs_set_sched(const char *smt_mc, int val);
+
+#endif /* __CPUPOWER_HELPERS_SYSFS_H__ */
diff --git a/tools/power/cpupower/utils/helpers/topology.c b/tools/power/cpupower/utils/helpers/topology.c
new file mode 100644 (file)
index 0000000..385ee5c
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ * ToDo: Needs to be done more properly for AMD/Intel specifics
+ */
+
+/* Helper struct for qsort, must be in sync with cpupower_topology.cpu_info */
+/* Be careful: Need to pass unsigned to the sort, so that offlined cores are
+   in the end, but double check for -1 for offlined cpus at other places */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <helpers/helpers.h>
+#include <helpers/sysfs.h>
+
+/* returns -1 on failure, 0 on success */
+int sysfs_topology_read_file(unsigned int cpu, const char *fname)
+{
+       unsigned long value;
+       char linebuf[MAX_LINE_LEN];
+       char *endp;
+       char path[SYSFS_PATH_MAX];
+
+       snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/topology/%s",
+                        cpu, fname);
+       if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0)
+               return -1;
+       value = strtoul(linebuf, &endp, 0);
+       if (endp == linebuf || errno == ERANGE)
+               return -1;
+       return value;
+}
+
+struct cpuid_core_info {
+       unsigned int pkg;
+       unsigned int thread;
+       unsigned int cpu;
+};
+
+static int __compare(const void *t1, const void *t2)
+{
+       struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1;
+       struct cpuid_core_info *top2 = (struct cpuid_core_info *)t2;
+       if (top1->pkg < top2->pkg)
+               return -1;
+       else if (top1->pkg > top2->pkg)
+               return 1;
+       else if (top1->thread < top2->thread)
+               return -1;
+       else if (top1->thread > top2->thread)
+               return 1;
+       else if (top1->cpu < top2->cpu)
+               return -1;
+       else if (top1->cpu > top2->cpu)
+               return 1;
+       else
+               return 0;
+}
+
+/*
+ * Returns amount of cpus, negative on error, cpu_top must be
+ * passed to cpu_topology_release to free resources
+ *
+ * Array is sorted after ->pkg, ->core, then ->cpu
+ */
+int get_cpu_topology(struct cpupower_topology *cpu_top)
+{
+       int cpu, cpus = sysconf(_SC_NPROCESSORS_CONF);
+
+       cpu_top->core_info = malloc(sizeof(struct cpupower_topology) * cpus);
+       if (cpu_top->core_info == NULL)
+               return -ENOMEM;
+       cpu_top->pkgs = cpu_top->cores = 0;
+       for (cpu = 0; cpu < cpus; cpu++) {
+               cpu_top->core_info[cpu].pkg =
+                       sysfs_topology_read_file(cpu, "physical_package_id");
+               if ((int)cpu_top->core_info[cpu].pkg != -1 &&
+                   cpu_top->core_info[cpu].pkg > cpu_top->pkgs)
+                       cpu_top->pkgs = cpu_top->core_info[cpu].pkg;
+               cpu_top->core_info[cpu].core =
+                       sysfs_topology_read_file(cpu, "core_id");
+               cpu_top->core_info[cpu].cpu = cpu;
+       }
+       cpu_top->pkgs++;
+
+       qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info),
+             __compare);
+
+       /* Intel's cores count is not consecutively numbered, there may
+        * be a core_id of 3, but none of 2. Assume there always is 0
+        * Get amount of cores by counting duplicates in a package
+       for (cpu = 0; cpu_top->core_info[cpu].pkg = 0 && cpu < cpus; cpu++) {
+               if (cpu_top->core_info[cpu].core == 0)
+       cpu_top->cores++;
+       */
+       return cpus;
+}
+
+void cpu_topology_release(struct cpupower_topology cpu_top)
+{
+       free(cpu_top.core_info);
+}
diff --git a/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c b/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c
new file mode 100644 (file)
index 0000000..202e555
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ *  (C) 2010,2011      Thomas Renninger <trenn@suse.de>, Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ *  PCI initialization based on example code from:
+ *  Andreas Herrmann <andreas.herrmann3@amd.com>
+ */
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <time.h>
+#include <string.h>
+
+#include <pci/pci.h>
+
+#include "idle_monitor/cpupower-monitor.h"
+#include "helpers/helpers.h"
+
+/******** PCI parts could go into own file and get shared ***************/
+
+#define PCI_NON_PC0_OFFSET     0xb0
+#define PCI_PC1_OFFSET         0xb4
+#define PCI_PC6_OFFSET         0xb8
+
+#define PCI_MONITOR_ENABLE_REG  0xe0
+
+#define PCI_NON_PC0_ENABLE_BIT 0
+#define PCI_PC1_ENABLE_BIT     1
+#define PCI_PC6_ENABLE_BIT     2
+
+#define PCI_NBP1_STAT_OFFSET   0x98
+#define PCI_NBP1_ACTIVE_BIT    2
+#define PCI_NBP1_ENTERED_BIT   1
+
+#define PCI_NBP1_CAP_OFFSET    0x90
+#define PCI_NBP1_CAPABLE_BIT    31
+
+#define OVERFLOW_MS            343597 /* 32 bit register filled at 12500 HZ
+                                         (1 tick per 80ns) */
+
+enum amd_fam14h_states {NON_PC0 = 0, PC1, PC6, NBP1,
+                       AMD_FAM14H_STATE_NUM};
+
+static int fam14h_get_count_percent(unsigned int self_id, double *percent,
+                                   unsigned int cpu);
+static int fam14h_nbp1_count(unsigned int id, unsigned long long *count,
+                            unsigned int cpu);
+
+static cstate_t amd_fam14h_cstates[AMD_FAM14H_STATE_NUM] = {
+       {
+               .name                   = "!PC0",
+               .desc                   = N_("Package in sleep state (PC1 or deeper)"),
+               .id                     = NON_PC0,
+               .range                  = RANGE_PACKAGE,
+               .get_count_percent      = fam14h_get_count_percent,
+       },
+       {
+               .name                   = "PC1",
+               .desc                   = N_("Processor Package C1"),
+               .id                     = PC1,
+               .range                  = RANGE_PACKAGE,
+               .get_count_percent      = fam14h_get_count_percent,
+       },
+       {
+               .name                   = "PC6",
+               .desc                   = N_("Processor Package C6"),
+               .id                     = PC6,
+               .range                  = RANGE_PACKAGE,
+               .get_count_percent      = fam14h_get_count_percent,
+       },
+       {
+               .name                   = "NBP1",
+               .desc                   = N_("North Bridge P1 boolean counter (returns 0 or 1)"),
+               .id                     = NBP1,
+               .range                  = RANGE_PACKAGE,
+               .get_count              = fam14h_nbp1_count,
+       },
+};
+
+static struct pci_access *pci_acc;
+static int pci_vendor_id = 0x1022;
+static int pci_dev_ids[2] = {0x1716, 0};
+static struct pci_dev *amd_fam14h_pci_dev;
+
+static int nbp1_entered;
+
+struct timespec start_time;
+static unsigned long long timediff;
+
+#ifdef DEBUG
+struct timespec dbg_time;
+long dbg_timediff;
+#endif
+
+static unsigned long long *previous_count[AMD_FAM14H_STATE_NUM];
+static unsigned long long *current_count[AMD_FAM14H_STATE_NUM];
+
+static int amd_fam14h_get_pci_info(struct cstate *state,
+                                  unsigned int *pci_offset,
+                                  unsigned int *enable_bit,
+                                  unsigned int cpu)
+{
+       switch (state->id) {
+       case NON_PC0:
+               *enable_bit = PCI_NON_PC0_ENABLE_BIT;
+               *pci_offset = PCI_NON_PC0_OFFSET;
+               break;
+       case PC1:
+               *enable_bit = PCI_PC1_ENABLE_BIT;
+               *pci_offset = PCI_PC1_OFFSET;
+               break;
+       case PC6:
+               *enable_bit = PCI_PC6_ENABLE_BIT;
+               *pci_offset = PCI_PC6_OFFSET;
+               break;
+       case NBP1:
+               *enable_bit = PCI_NBP1_ENTERED_BIT;
+               *pci_offset = PCI_NBP1_STAT_OFFSET;
+               break;
+       default:
+               return -1;
+       };
+       return 0;
+}
+
+static int amd_fam14h_init(cstate_t *state, unsigned int cpu)
+{
+       int enable_bit, pci_offset, ret;
+       uint32_t val;
+
+       ret = amd_fam14h_get_pci_info(state, &pci_offset, &enable_bit, cpu);
+       if (ret)
+               return ret;
+
+       /* NBP1 needs extra treating -> write 1 to D18F6x98 bit 1 for init */
+       if (state->id == NBP1) {
+               val = pci_read_long(amd_fam14h_pci_dev, pci_offset);
+               val |= 1 << enable_bit;
+               val = pci_write_long(amd_fam14h_pci_dev, pci_offset, val);
+               return ret;
+       }
+
+       /* Enable monitor */
+       val = pci_read_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG);
+       dprint("Init %s: read at offset: 0x%x val: %u\n", state->name,
+              PCI_MONITOR_ENABLE_REG, (unsigned int) val);
+       val |= 1 << enable_bit;
+       pci_write_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG, val);
+
+       dprint("Init %s: offset: 0x%x enable_bit: %d - val: %u (%u)\n",
+              state->name, PCI_MONITOR_ENABLE_REG, enable_bit,
+              (unsigned int) val, cpu);
+
+       /* Set counter to zero */
+       pci_write_long(amd_fam14h_pci_dev, pci_offset, 0);
+       previous_count[state->id][cpu] = 0;
+
+       return 0;
+}
+
+static int amd_fam14h_disable(cstate_t *state, unsigned int cpu)
+{
+       int enable_bit, pci_offset, ret;
+       uint32_t val;
+
+       ret = amd_fam14h_get_pci_info(state, &pci_offset, &enable_bit, cpu);
+       if (ret)
+               return ret;
+
+       val = pci_read_long(amd_fam14h_pci_dev, pci_offset);
+       dprint("%s: offset: 0x%x %u\n", state->name, pci_offset, val);
+       if (state->id == NBP1) {
+               /* was the bit whether NBP1 got entered set? */
+               nbp1_entered = (val & (1 << PCI_NBP1_ACTIVE_BIT)) |
+                       (val & (1 << PCI_NBP1_ENTERED_BIT));
+
+               dprint("NBP1 was %sentered - 0x%x - enable_bit: "
+                      "%d - pci_offset: 0x%x\n",
+                      nbp1_entered ? "" : "not ",
+                      val, enable_bit, pci_offset);
+               return ret;
+       }
+       current_count[state->id][cpu] = val;
+
+       dprint("%s: Current -  %llu (%u)\n", state->name,
+              current_count[state->id][cpu], cpu);
+       dprint("%s: Previous - %llu (%u)\n", state->name,
+              previous_count[state->id][cpu], cpu);
+
+       val = pci_read_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG);
+       val &= ~(1 << enable_bit);
+       pci_write_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG, val);
+
+       return 0;
+}
+
+static int fam14h_nbp1_count(unsigned int id, unsigned long long *count,
+                            unsigned int cpu)
+{
+       if (id == NBP1) {
+               if (nbp1_entered)
+                       *count = 1;
+               else
+                       *count = 0;
+               return 0;
+       }
+       return -1;
+}
+static int fam14h_get_count_percent(unsigned int id, double *percent,
+                                   unsigned int cpu)
+{
+       unsigned long diff;
+
+       if (id >= AMD_FAM14H_STATE_NUM)
+               return -1;
+       /* residency count in 80ns -> divide through 12.5 to get us residency */
+       diff = current_count[id][cpu] - previous_count[id][cpu];
+
+       if (timediff == 0)
+               *percent = 0.0;
+       else
+               *percent = 100.0 * diff / timediff / 12.5;
+
+       dprint("Timediff: %llu - res~: %lu us - percent: %.2f %%\n",
+              timediff, diff * 10 / 125, *percent);
+
+       return 0;
+}
+
+static int amd_fam14h_start(void)
+{
+       int num, cpu;
+       clock_gettime(CLOCK_REALTIME, &start_time);
+       for (num = 0; num < AMD_FAM14H_STATE_NUM; num++) {
+               for (cpu = 0; cpu < cpu_count; cpu++)
+                       amd_fam14h_init(&amd_fam14h_cstates[num], cpu);
+       }
+#ifdef DEBUG
+       clock_gettime(CLOCK_REALTIME, &dbg_time);
+       dbg_timediff = timespec_diff_us(start_time, dbg_time);
+       dprint("Enabling counters took: %lu us\n",
+              dbg_timediff);
+#endif
+       return 0;
+}
+
+static int amd_fam14h_stop(void)
+{
+       int num, cpu;
+       struct timespec end_time;
+
+       clock_gettime(CLOCK_REALTIME, &end_time);
+
+       for (num = 0; num < AMD_FAM14H_STATE_NUM; num++) {
+               for (cpu = 0; cpu < cpu_count; cpu++)
+                       amd_fam14h_disable(&amd_fam14h_cstates[num], cpu);
+       }
+#ifdef DEBUG
+       clock_gettime(CLOCK_REALTIME, &dbg_time);
+       dbg_timediff = timespec_diff_us(end_time, dbg_time);
+       dprint("Disabling counters took: %lu ns\n", dbg_timediff);
+#endif
+       timediff = timespec_diff_us(start_time, end_time);
+       if (timediff / 1000 > OVERFLOW_MS)
+               print_overflow_err((unsigned int)timediff / 1000000,
+                                  OVERFLOW_MS / 1000);
+
+       return 0;
+}
+
+static int is_nbp1_capable(void)
+{
+       uint32_t val;
+       val = pci_read_long(amd_fam14h_pci_dev, PCI_NBP1_CAP_OFFSET);
+       return val & (1 << 31);
+}
+
+struct cpuidle_monitor *amd_fam14h_register(void)
+{
+       int num;
+
+       if (cpupower_cpu_info.vendor != X86_VENDOR_AMD)
+               return NULL;
+
+       if (cpupower_cpu_info.family == 0x14) {
+               if (cpu_count <= 0 || cpu_count > 2) {
+                       fprintf(stderr, "AMD fam14h: Invalid cpu count: %d\n",
+                               cpu_count);
+                       return NULL;
+               }
+       } else
+               return NULL;
+
+       /* We do not alloc for nbp1 machine wide counter */
+       for (num = 0; num < AMD_FAM14H_STATE_NUM - 1; num++) {
+               previous_count[num] = calloc(cpu_count,
+                                             sizeof(unsigned long long));
+               current_count[num]  = calloc(cpu_count,
+                                             sizeof(unsigned long long));
+       }
+
+       amd_fam14h_pci_dev = pci_acc_init(&pci_acc, pci_vendor_id, pci_dev_ids);
+       if (amd_fam14h_pci_dev == NULL || pci_acc == NULL)
+               return NULL;
+
+       if (!is_nbp1_capable())
+               amd_fam14h_monitor.hw_states_num = AMD_FAM14H_STATE_NUM - 1;
+
+       amd_fam14h_monitor.name_len = strlen(amd_fam14h_monitor.name);
+       return &amd_fam14h_monitor;
+}
+
+static void amd_fam14h_unregister(void)
+{
+       int num;
+       for (num = 0; num < AMD_FAM14H_STATE_NUM - 1; num++) {
+               free(previous_count[num]);
+               free(current_count[num]);
+       }
+       pci_cleanup(pci_acc);
+}
+
+struct cpuidle_monitor amd_fam14h_monitor = {
+       .name                   = "Ontario",
+       .hw_states              = amd_fam14h_cstates,
+       .hw_states_num          = AMD_FAM14H_STATE_NUM,
+       .start                  = amd_fam14h_start,
+       .stop                   = amd_fam14h_stop,
+       .do_register            = amd_fam14h_register,
+       .unregister             = amd_fam14h_unregister,
+       .needs_root             = 1,
+       .overflow_s             = OVERFLOW_MS / 1000,
+};
+#endif /* #if defined(__i386__) || defined(__x86_64__) */
diff --git a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c
new file mode 100644 (file)
index 0000000..d048b96
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <limits.h>
+
+#include "helpers/sysfs.h"
+#include "helpers/helpers.h"
+#include "idle_monitor/cpupower-monitor.h"
+
+#define CPUIDLE_STATES_MAX 10
+static cstate_t cpuidle_cstates[CPUIDLE_STATES_MAX];
+struct cpuidle_monitor cpuidle_sysfs_monitor;
+
+static unsigned long long **previous_count;
+static unsigned long long **current_count;
+struct timespec start_time;
+static unsigned long long timediff;
+
+static int cpuidle_get_count_percent(unsigned int id, double *percent,
+                                    unsigned int cpu)
+{
+       unsigned long long statediff = current_count[cpu][id]
+               - previous_count[cpu][id];
+       dprint("%s: - diff: %llu - percent: %f (%u)\n",
+              cpuidle_cstates[id].name, timediff, *percent, cpu);
+
+       if (timediff == 0)
+               *percent = 0.0;
+       else
+               *percent = ((100.0 * statediff) / timediff);
+
+       dprint("%s: - timediff: %llu - statediff: %llu - percent: %f (%u)\n",
+              cpuidle_cstates[id].name, timediff, statediff, *percent, cpu);
+
+       return 0;
+}
+
+static int cpuidle_start(void)
+{
+       int cpu, state;
+       clock_gettime(CLOCK_REALTIME, &start_time);
+       for (cpu = 0; cpu < cpu_count; cpu++) {
+               for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num;
+                    state++) {
+                       previous_count[cpu][state] =
+                               sysfs_get_idlestate_time(cpu, state);
+                       dprint("CPU %d - State: %d - Val: %llu\n",
+                              cpu, state, previous_count[cpu][state]);
+               }
+       };
+       return 0;
+}
+
+static int cpuidle_stop(void)
+{
+       int cpu, state;
+       struct timespec end_time;
+       clock_gettime(CLOCK_REALTIME, &end_time);
+       timediff = timespec_diff_us(start_time, end_time);
+
+       for (cpu = 0; cpu < cpu_count; cpu++) {
+               for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num;
+                    state++) {
+                       current_count[cpu][state] =
+                               sysfs_get_idlestate_time(cpu, state);
+                       dprint("CPU %d - State: %d - Val: %llu\n",
+                              cpu, state, previous_count[cpu][state]);
+               }
+       };
+       return 0;
+}
+
+void fix_up_intel_idle_driver_name(char *tmp, int num)
+{
+       /* fix up cpuidle name for intel idle driver */
+       if (!strncmp(tmp, "NHM-", 4)) {
+               switch (num) {
+               case 1:
+                       strcpy(tmp, "C1");
+                       break;
+               case 2:
+                       strcpy(tmp, "C3");
+                       break;
+               case 3:
+                       strcpy(tmp, "C6");
+                       break;
+               }
+       } else if (!strncmp(tmp, "SNB-", 4)) {
+               switch (num) {
+               case 1:
+                       strcpy(tmp, "C1");
+                       break;
+               case 2:
+                       strcpy(tmp, "C3");
+                       break;
+               case 3:
+                       strcpy(tmp, "C6");
+                       break;
+               case 4:
+                       strcpy(tmp, "C7");
+                       break;
+               }
+       } else if (!strncmp(tmp, "ATM-", 4)) {
+               switch (num) {
+               case 1:
+                       strcpy(tmp, "C1");
+                       break;
+               case 2:
+                       strcpy(tmp, "C2");
+                       break;
+               case 3:
+                       strcpy(tmp, "C4");
+                       break;
+               case 4:
+                       strcpy(tmp, "C6");
+                       break;
+               }
+       }
+}
+
+static struct cpuidle_monitor *cpuidle_register(void)
+{
+       int num;
+       char *tmp;
+
+       /* Assume idle state count is the same for all CPUs */
+       cpuidle_sysfs_monitor.hw_states_num = sysfs_get_idlestate_count(0);
+
+       if (cpuidle_sysfs_monitor.hw_states_num == 0)
+               return NULL;
+
+       for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) {
+               tmp = sysfs_get_idlestate_name(0, num);
+               if (tmp == NULL)
+                       continue;
+
+               fix_up_intel_idle_driver_name(tmp, num);
+               strncpy(cpuidle_cstates[num].name, tmp, CSTATE_NAME_LEN - 1);
+               free(tmp);
+
+               tmp = sysfs_get_idlestate_desc(0, num);
+               if (tmp == NULL)
+                       continue;
+               strncpy(cpuidle_cstates[num].desc, tmp, CSTATE_DESC_LEN - 1);
+               free(tmp);
+
+               cpuidle_cstates[num].range = RANGE_THREAD;
+               cpuidle_cstates[num].id = num;
+               cpuidle_cstates[num].get_count_percent =
+                       cpuidle_get_count_percent;
+       };
+
+       /* Free this at program termination */
+       previous_count = malloc(sizeof(long long *) * cpu_count);
+       current_count = malloc(sizeof(long long *) * cpu_count);
+       for (num = 0; num < cpu_count; num++) {
+               previous_count[num] = malloc(sizeof(long long) *
+                                       cpuidle_sysfs_monitor.hw_states_num);
+               current_count[num] = malloc(sizeof(long long) *
+                                       cpuidle_sysfs_monitor.hw_states_num);
+       }
+
+       cpuidle_sysfs_monitor.name_len = strlen(cpuidle_sysfs_monitor.name);
+       return &cpuidle_sysfs_monitor;
+}
+
+void cpuidle_unregister(void)
+{
+       int num;
+
+       for (num = 0; num < cpu_count; num++) {
+               free(previous_count[num]);
+               free(current_count[num]);
+       }
+       free(previous_count);
+       free(current_count);
+}
+
+struct cpuidle_monitor cpuidle_sysfs_monitor = {
+       .name                   = "Idle_Stats",
+       .hw_states              = cpuidle_cstates,
+       .start                  = cpuidle_start,
+       .stop                   = cpuidle_stop,
+       .do_register            = cpuidle_register,
+       .unregister             = cpuidle_unregister,
+       .needs_root             = 0,
+       .overflow_s             = UINT_MAX,
+};
diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
new file mode 100644 (file)
index 0000000..ba4bf06
--- /dev/null
@@ -0,0 +1,448 @@
+/*
+ *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ *  Output format inspired by Len Brown's <lenb@kernel.org> turbostat tool.
+ *
+ */
+
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <libgen.h>
+
+#include "idle_monitor/cpupower-monitor.h"
+#include "idle_monitor/idle_monitors.h"
+#include "helpers/helpers.h"
+
+/* Define pointers to all monitors.  */
+#define DEF(x) & x ## _monitor ,
+struct cpuidle_monitor *all_monitors[] = {
+#include "idle_monitors.def"
+0
+};
+
+static struct cpuidle_monitor *monitors[MONITORS_MAX];
+static unsigned int avail_monitors;
+
+static char *progname;
+
+enum operation_mode_e { list = 1, show, show_all };
+static int mode;
+static int interval = 1;
+static char *show_monitors_param;
+static struct cpupower_topology cpu_top;
+
+/* ToDo: Document this in the manpage */
+static char range_abbr[RANGE_MAX] = { 'T', 'C', 'P', 'M', };
+
+long long timespec_diff_us(struct timespec start, struct timespec end)
+{
+       struct timespec temp;
+       if ((end.tv_nsec - start.tv_nsec) < 0) {
+               temp.tv_sec = end.tv_sec - start.tv_sec - 1;
+               temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec;
+       } else {
+               temp.tv_sec = end.tv_sec - start.tv_sec;
+               temp.tv_nsec = end.tv_nsec - start.tv_nsec;
+       }
+       return (temp.tv_sec * 1000000) + (temp.tv_nsec / 1000);
+}
+
+void monitor_help(void)
+{
+       printf(_("cpupower monitor: [-m <mon1>,[<mon2>],.. ] command\n"));
+       printf(_("cpupower monitor: [-m <mon1>,[<mon2>],.. ] [ -i interval_sec ]\n"));
+       printf(_("cpupower monitor: -l\n"));
+       printf(_("\t command: pass an arbitrary command to measure specific workload\n"));
+       printf(_("\t -i: time intervall to measure for in seconds (default 1)\n"));
+       printf(_("\t -l: list available CPU sleep monitors (for use with -m)\n"));
+       printf(_("\t -m: show specific CPU sleep monitors only (in same order)\n"));
+       printf(_("\t -h: print this help\n"));
+       printf("\n");
+       printf(_("only one of: -l, -m are allowed\nIf none of them is passed,"));
+       printf(_(" all supported monitors are shown\n"));
+}
+
+void print_n_spaces(int n)
+{
+       int x;
+       for (x = 0; x < n; x++)
+               printf(" ");
+}
+
+/* size of s must be at least n + 1 */
+int fill_string_with_spaces(char *s, int n)
+{
+       int len = strlen(s);
+       if (len > n)
+               return -1;
+       for (; len < n; len++)
+               s[len] = ' ';
+       s[len] = '\0';
+       return 0;
+}
+
+void print_header(int topology_depth)
+{
+       int unsigned mon;
+       int state, need_len, pr_mon_len;
+       cstate_t s;
+       char buf[128] = "";
+       int percent_width = 4;
+
+       fill_string_with_spaces(buf, topology_depth * 5 - 1);
+       printf("%s|", buf);
+
+       for (mon = 0; mon < avail_monitors; mon++) {
+               pr_mon_len = 0;
+               need_len = monitors[mon]->hw_states_num * (percent_width + 3)
+                       - 1;
+               if (mon != 0) {
+                       printf("|| ");
+                       need_len--;
+               }
+               sprintf(buf, "%s", monitors[mon]->name);
+               fill_string_with_spaces(buf, need_len);
+               printf("%s", buf);
+       }
+       printf("\n");
+
+       if (topology_depth > 2)
+               printf("PKG |");
+       if (topology_depth > 1)
+               printf("CORE|");
+       if (topology_depth > 0)
+               printf("CPU |");
+
+       for (mon = 0; mon < avail_monitors; mon++) {
+               if (mon != 0)
+                       printf("|| ");
+               else
+                       printf(" ");
+               for (state = 0; state < monitors[mon]->hw_states_num; state++) {
+                       if (state != 0)
+                               printf(" | ");
+                       s = monitors[mon]->hw_states[state];
+                       sprintf(buf, "%s", s.name);
+                       fill_string_with_spaces(buf, percent_width);
+                       printf("%s", buf);
+               }
+               printf(" ");
+       }
+       printf("\n");
+}
+
+
+void print_results(int topology_depth, int cpu)
+{
+       unsigned int mon;
+       int state, ret;
+       double percent;
+       unsigned long long result;
+       cstate_t s;
+
+       if (topology_depth > 2)
+               printf("%4d|", cpu_top.core_info[cpu].pkg);
+       if (topology_depth > 1)
+               printf("%4d|", cpu_top.core_info[cpu].core);
+       if (topology_depth > 0)
+               printf("%4d|", cpu_top.core_info[cpu].cpu);
+
+       for (mon = 0; mon < avail_monitors; mon++) {
+               if (mon != 0)
+                       printf("||");
+
+               for (state = 0; state < monitors[mon]->hw_states_num; state++) {
+                       if (state != 0)
+                               printf("|");
+
+                       s = monitors[mon]->hw_states[state];
+
+                       if (s.get_count_percent) {
+                               ret = s.get_count_percent(s.id, &percent,
+                                                 cpu_top.core_info[cpu].cpu);
+                               if (ret)
+                                       printf("******");
+                               else if (percent >= 100.0)
+                                       printf("%6.1f", percent);
+                               else
+                                       printf("%6.2f", percent);
+                       } else if (s.get_count) {
+                               ret = s.get_count(s.id, &result,
+                                                 cpu_top.core_info[cpu].cpu);
+                               if (ret)
+                                       printf("******");
+                               else
+                                       printf("%6llu", result);
+                       } else {
+                               printf(_("Monitor %s, Counter %s has no count "
+                                        "function. Implementation error\n"),
+                                      monitors[mon]->name, s.name);
+                               exit(EXIT_FAILURE);
+                       }
+               }
+       }
+       /* cpu offline */
+       if (cpu_top.core_info[cpu].pkg == -1 ||
+           cpu_top.core_info[cpu].core == -1) {
+               printf(_(" *is offline\n"));
+               return;
+       } else
+               printf("\n");
+}
+
+
+/* param: string passed by -m param (The list of monitors to show)
+ *
+ * Monitors must have been registered already, matching monitors
+ * are picked out and available monitors array is overridden
+ * with matching ones
+ *
+ * Monitors get sorted in the same order the user passes them
+*/
+
+static void parse_monitor_param(char *param)
+{
+       unsigned int num;
+       int mon, hits = 0;
+       char *tmp = param, *token;
+       struct cpuidle_monitor *tmp_mons[MONITORS_MAX];
+
+
+       for (mon = 0; mon < MONITORS_MAX; mon++, tmp = NULL) {
+               token = strtok(tmp, ",");
+               if (token == NULL)
+                       break;
+               if (strlen(token) >= MONITOR_NAME_LEN) {
+                       printf(_("%s: max monitor name length"
+                                " (%d) exceeded\n"), token, MONITOR_NAME_LEN);
+                       continue;
+               }
+
+               for (num = 0; num < avail_monitors; num++) {
+                       if (!strcmp(monitors[num]->name, token)) {
+                               dprint("Found requested monitor: %s\n", token);
+                               tmp_mons[hits] = monitors[num];
+                               hits++;
+                       }
+               }
+       }
+       if (hits == 0) {
+               printf(_("No matching monitor found in %s, "
+                        "try -l option\n"), param);
+               monitor_help();
+               exit(EXIT_FAILURE);
+       }
+       /* Override detected/registerd monitors array with requested one */
+       memcpy(monitors, tmp_mons,
+               sizeof(struct cpuidle_monitor *) * MONITORS_MAX);
+       avail_monitors = hits;
+}
+
+void list_monitors(void)
+{
+       unsigned int mon;
+       int state;
+       cstate_t s;
+
+       for (mon = 0; mon < avail_monitors; mon++) {
+               printf(_("Monitor \"%s\" (%d states) - Might overflow after %u "
+                        "s\n"),
+                       monitors[mon]->name, monitors[mon]->hw_states_num,
+                       monitors[mon]->overflow_s);
+
+               for (state = 0; state < monitors[mon]->hw_states_num; state++) {
+                       s = monitors[mon]->hw_states[state];
+                       /*
+                        * ToDo show more state capabilities:
+                        * percent, time (granlarity)
+                        */
+                       printf("%s\t[%c] -> %s\n", s.name, range_abbr[s.range],
+                              gettext(s.desc));
+               }
+       }
+}
+
+int fork_it(char **argv)
+{
+       int status;
+       unsigned int num;
+       unsigned long long timediff;
+       pid_t child_pid;
+       struct timespec start, end;
+
+       child_pid = fork();
+       clock_gettime(CLOCK_REALTIME, &start);
+
+       for (num = 0; num < avail_monitors; num++)
+               monitors[num]->start();
+
+       if (!child_pid) {
+               /* child */
+               execvp(argv[0], argv);
+       } else {
+               /* parent */
+               if (child_pid == -1) {
+                       perror("fork");
+                       exit(1);
+               }
+
+               signal(SIGINT, SIG_IGN);
+               signal(SIGQUIT, SIG_IGN);
+               if (waitpid(child_pid, &status, 0) == -1) {
+                       perror("wait");
+                       exit(1);
+               }
+       }
+       clock_gettime(CLOCK_REALTIME, &end);
+       for (num = 0; num < avail_monitors; num++)
+               monitors[num]->stop();
+
+       timediff = timespec_diff_us(start, end);
+       if (WIFEXITED(status))
+               printf(_("%s took %.5f seconds and exited with status %d\n"),
+                       argv[0], timediff / (1000.0 * 1000),
+                       WEXITSTATUS(status));
+       return 0;
+}
+
+int do_interval_measure(int i)
+{
+       unsigned int num;
+
+       for (num = 0; num < avail_monitors; num++) {
+               dprint("HW C-state residency monitor: %s - States: %d\n",
+                      monitors[num]->name, monitors[num]->hw_states_num);
+               monitors[num]->start();
+       }
+       sleep(i);
+       for (num = 0; num < avail_monitors; num++)
+               monitors[num]->stop();
+
+       return 0;
+}
+
+static void cmdline(int argc, char *argv[])
+{
+       int opt;
+       progname = basename(argv[0]);
+
+       while ((opt = getopt(argc, argv, "+hli:m:")) != -1) {
+               switch (opt) {
+               case 'h':
+                       monitor_help();
+                       exit(EXIT_SUCCESS);
+               case 'l':
+                       if (mode) {
+                               monitor_help();
+                               exit(EXIT_FAILURE);
+                       }
+                       mode = list;
+                       break;
+               case 'i':
+                       /* only allow -i with -m or no option */
+                       if (mode && mode != show) {
+                               monitor_help();
+                               exit(EXIT_FAILURE);
+                       }
+                       interval = atoi(optarg);
+                       break;
+               case 'm':
+                       if (mode) {
+                               monitor_help();
+                               exit(EXIT_FAILURE);
+                       }
+                       mode = show;
+                       show_monitors_param = optarg;
+                       break;
+               default:
+                       monitor_help();
+                       exit(EXIT_FAILURE);
+               }
+       }
+       if (!mode)
+               mode = show_all;
+}
+
+int cmd_monitor(int argc, char **argv)
+{
+       unsigned int num;
+       struct cpuidle_monitor *test_mon;
+       int cpu;
+
+       cmdline(argc, argv);
+       cpu_count = get_cpu_topology(&cpu_top);
+       if (cpu_count < 0) {
+               printf(_("Cannot read number of available processors\n"));
+               return EXIT_FAILURE;
+       }
+
+       dprint("System has up to %d CPU cores\n", cpu_count);
+
+       for (num = 0; all_monitors[num]; num++) {
+               dprint("Try to register: %s\n", all_monitors[num]->name);
+               test_mon = all_monitors[num]->do_register();
+               if (test_mon) {
+                       if (test_mon->needs_root && !run_as_root) {
+                               fprintf(stderr, _("Available monitor %s needs "
+                                         "root access\n"), test_mon->name);
+                               continue;
+                       }
+                       monitors[avail_monitors] = test_mon;
+                       dprint("%s registered\n", all_monitors[num]->name);
+                       avail_monitors++;
+               }
+       }
+
+       if (avail_monitors == 0) {
+               printf(_("No HW Cstate monitors found\n"));
+               return 1;
+       }
+
+       if (mode == list) {
+               list_monitors();
+               exit(EXIT_SUCCESS);
+       }
+
+       if (mode == show)
+               parse_monitor_param(show_monitors_param);
+
+       dprint("Packages: %d - Cores: %d - CPUs: %d\n",
+              cpu_top.pkgs, cpu_top.cores, cpu_count);
+
+       /*
+        * if any params left, it must be a command to fork
+        */
+       if (argc - optind)
+               fork_it(argv + optind);
+       else
+               do_interval_measure(interval);
+
+       /* ToDo: Topology parsing needs fixing first to do
+          this more generically */
+       if (cpu_top.pkgs > 1)
+               print_header(3);
+       else
+               print_header(1);
+
+       for (cpu = 0; cpu < cpu_count; cpu++) {
+               if (cpu_top.pkgs > 1)
+                       print_results(3, cpu);
+               else
+                       print_results(1, cpu);
+       }
+
+       for (num = 0; num < avail_monitors; num++)
+               monitors[num]->unregister();
+
+       cpu_topology_release(cpu_top);
+       return 0;
+}
diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h
new file mode 100644 (file)
index 0000000..9312ee1
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ */
+
+#ifndef __CPUIDLE_INFO_HW__
+#define __CPUIDLE_INFO_HW__
+
+#include <stdarg.h>
+#include <time.h>
+
+#include "idle_monitor/idle_monitors.h"
+
+#define MONITORS_MAX 20
+#define MONITOR_NAME_LEN 20
+#define CSTATE_NAME_LEN 5
+#define CSTATE_DESC_LEN 60
+
+int cpu_count;
+
+/* Hard to define the right names ...: */
+enum power_range_e {
+       RANGE_THREAD,   /* Lowest in topology hierarcy, AMD: core, Intel: thread
+                          kernel sysfs: cpu */
+       RANGE_CORE,     /* AMD: unit, Intel: core, kernel_sysfs: core_id */
+       RANGE_PACKAGE,  /* Package, processor socket */
+       RANGE_MACHINE,  /* Machine, platform wide */
+       RANGE_MAX };
+
+typedef struct cstate {
+       int  id;
+       enum power_range_e range;
+       char name[CSTATE_NAME_LEN];
+       char desc[CSTATE_DESC_LEN];
+
+       /* either provide a percentage or a general count */
+       int (*get_count_percent)(unsigned int self_id, double *percent,
+                                unsigned int cpu);
+       int (*get_count)(unsigned int self_id, unsigned long long *count,
+                        unsigned int cpu);
+} cstate_t;
+
+struct cpuidle_monitor {
+       /* Name must not contain whitespaces */
+       char name[MONITOR_NAME_LEN];
+       int name_len;
+       int hw_states_num;
+       cstate_t *hw_states;
+       int (*start) (void);
+       int (*stop) (void);
+       struct cpuidle_monitor* (*do_register) (void);
+       void (*unregister)(void);
+       unsigned int overflow_s;
+       int needs_root;
+};
+
+extern long long timespec_diff_us(struct timespec start, struct timespec end);
+
+#define print_overflow_err(mes, ov)                                            \
+{                                                                              \
+       fprintf(stderr, gettext("Measure took %u seconds, but registers could " \
+                               "overflow at %u seconds, results "              \
+                               "could be inaccurate\n"), mes, ov);             \
+}
+
+#endif /* __CPUIDLE_INFO_HW__ */
diff --git a/tools/power/cpupower/utils/idle_monitor/idle_monitors.def b/tools/power/cpupower/utils/idle_monitor/idle_monitors.def
new file mode 100644 (file)
index 0000000..e3f8d9b
--- /dev/null
@@ -0,0 +1,7 @@
+#if defined(__i386__) || defined(__x86_64__)
+DEF(amd_fam14h)
+DEF(intel_nhm)
+DEF(intel_snb)
+DEF(mperf)
+#endif
+DEF(cpuidle_sysfs)
diff --git a/tools/power/cpupower/utils/idle_monitor/idle_monitors.h b/tools/power/cpupower/utils/idle_monitor/idle_monitors.h
new file mode 100644 (file)
index 0000000..4fcdeb1
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ *  Based on the idea from Michael Matz <matz@suse.de>
+ *
+ */
+
+#ifndef _CPUIDLE_IDLE_MONITORS_H_
+#define _CPUIDLE_IDLE_MONITORS_H_
+
+#define DEF(x) extern struct cpuidle_monitor x ##_monitor;
+#include "idle_monitors.def"
+#undef DEF
+extern struct cpuidle_monitor *all_monitors[];
+
+#endif /* _CPUIDLE_IDLE_MONITORS_H_ */
diff --git a/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c
new file mode 100644 (file)
index 0000000..63ca87a
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ */
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <cpufreq.h>
+
+#include "helpers/helpers.h"
+#include "idle_monitor/cpupower-monitor.h"
+
+#define MSR_APERF      0xE8
+#define MSR_MPERF      0xE7
+
+#define MSR_TSC        0x10
+
+enum mperf_id { C0 = 0, Cx, AVG_FREQ, MPERF_CSTATE_COUNT };
+
+static int mperf_get_count_percent(unsigned int self_id, double *percent,
+                                  unsigned int cpu);
+static int mperf_get_count_freq(unsigned int id, unsigned long long *count,
+                               unsigned int cpu);
+
+static cstate_t mperf_cstates[MPERF_CSTATE_COUNT] = {
+       {
+               .name                   = "C0",
+               .desc                   = N_("Processor Core not idle"),
+               .id                     = C0,
+               .range                  = RANGE_THREAD,
+               .get_count_percent      = mperf_get_count_percent,
+       },
+       {
+               .name                   = "Cx",
+               .desc                   = N_("Processor Core in an idle state"),
+               .id                     = Cx,
+               .range                  = RANGE_THREAD,
+               .get_count_percent      = mperf_get_count_percent,
+       },
+
+       {
+               .name                   = "Freq",
+               .desc                   = N_("Average Frequency (including boost) in MHz"),
+               .id                     = AVG_FREQ,
+               .range                  = RANGE_THREAD,
+               .get_count              = mperf_get_count_freq,
+       },
+};
+
+static unsigned long long tsc_at_measure_start;
+static unsigned long long tsc_at_measure_end;
+static unsigned long max_frequency;
+static unsigned long long *mperf_previous_count;
+static unsigned long long *aperf_previous_count;
+static unsigned long long *mperf_current_count;
+static unsigned long long *aperf_current_count;
+/* valid flag for all CPUs. If a MSR read failed it will be zero */
+static int *is_valid;
+
+static int mperf_get_tsc(unsigned long long *tsc)
+{
+       return read_msr(0, MSR_TSC, tsc);
+}
+
+static int mperf_init_stats(unsigned int cpu)
+{
+       unsigned long long val;
+       int ret;
+
+       ret = read_msr(cpu, MSR_APERF, &val);
+       aperf_previous_count[cpu] = val;
+       ret |= read_msr(cpu, MSR_MPERF, &val);
+       mperf_previous_count[cpu] = val;
+       is_valid[cpu] = !ret;
+
+       return 0;
+}
+
+static int mperf_measure_stats(unsigned int cpu)
+{
+       unsigned long long val;
+       int ret;
+
+       ret = read_msr(cpu, MSR_APERF, &val);
+       aperf_current_count[cpu] = val;
+       ret |= read_msr(cpu, MSR_MPERF, &val);
+       mperf_current_count[cpu] = val;
+       is_valid[cpu] = !ret;
+
+       return 0;
+}
+
+/*
+ * get_average_perf()
+ *
+ * Returns the average performance (also considers boosted frequencies)
+ *
+ * Input:
+ *   aperf_diff: Difference of the aperf register over a time period
+ *   mperf_diff: Difference of the mperf register over the same time period
+ *   max_freq:   Maximum frequency (P0)
+ *
+ * Returns:
+ *   Average performance over the time period
+ */
+static unsigned long get_average_perf(unsigned long long aperf_diff,
+                                     unsigned long long mperf_diff)
+{
+       unsigned int perf_percent = 0;
+       if (((unsigned long)(-1) / 100) < aperf_diff) {
+               int shift_count = 7;
+               aperf_diff >>= shift_count;
+               mperf_diff >>= shift_count;
+       }
+       perf_percent = (aperf_diff * 100) / mperf_diff;
+       return (max_frequency * perf_percent) / 100;
+}
+
+static int mperf_get_count_percent(unsigned int id, double *percent,
+                                  unsigned int cpu)
+{
+       unsigned long long aperf_diff, mperf_diff, tsc_diff;
+
+       if (!is_valid[cpu])
+               return -1;
+
+       if (id != C0 && id != Cx)
+               return -1;
+
+       mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu];
+       aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu];
+       tsc_diff = tsc_at_measure_end - tsc_at_measure_start;
+
+       *percent = 100.0 * mperf_diff / tsc_diff;
+       dprint("%s: mperf_diff: %llu, tsc_diff: %llu\n",
+              mperf_cstates[id].name, mperf_diff, tsc_diff);
+
+       if (id == Cx)
+               *percent = 100.0 - *percent;
+
+       dprint("%s: previous: %llu - current: %llu - (%u)\n",
+               mperf_cstates[id].name, mperf_diff, aperf_diff, cpu);
+       dprint("%s: %f\n", mperf_cstates[id].name, *percent);
+       return 0;
+}
+
+static int mperf_get_count_freq(unsigned int id, unsigned long long *count,
+                               unsigned int cpu)
+{
+       unsigned long long aperf_diff, mperf_diff;
+
+       if (id != AVG_FREQ)
+               return 1;
+
+       if (!is_valid[cpu])
+               return -1;
+
+       mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu];
+       aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu];
+
+       /* Return MHz for now, might want to return KHz if column width is more
+          generic */
+       *count = get_average_perf(aperf_diff, mperf_diff) / 1000;
+       dprint("%s: %llu\n", mperf_cstates[id].name, *count);
+
+       return 0;
+}
+
+static int mperf_start(void)
+{
+       int cpu;
+       unsigned long long dbg;
+
+       mperf_get_tsc(&tsc_at_measure_start);
+
+       for (cpu = 0; cpu < cpu_count; cpu++)
+               mperf_init_stats(cpu);
+
+       mperf_get_tsc(&dbg);
+       dprint("TSC diff: %llu\n", dbg - tsc_at_measure_start);
+       return 0;
+}
+
+static int mperf_stop(void)
+{
+       unsigned long long dbg;
+       int cpu;
+
+       mperf_get_tsc(&tsc_at_measure_end);
+
+       for (cpu = 0; cpu < cpu_count; cpu++)
+               mperf_measure_stats(cpu);
+
+       mperf_get_tsc(&dbg);
+       dprint("TSC diff: %llu\n", dbg - tsc_at_measure_end);
+
+       return 0;
+}
+
+struct cpuidle_monitor mperf_monitor;
+
+struct cpuidle_monitor *mperf_register(void)
+{
+       unsigned long min;
+
+       if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_APERF))
+               return NULL;
+
+       /* Assume min/max all the same on all cores */
+       if (cpufreq_get_hardware_limits(0, &min, &max_frequency)) {
+               dprint("Cannot retrieve max freq from cpufreq kernel "
+                      "subsystem\n");
+               return NULL;
+       }
+
+       /* Free this at program termination */
+       is_valid = calloc(cpu_count, sizeof(int));
+       mperf_previous_count = calloc(cpu_count, sizeof(unsigned long long));
+       aperf_previous_count = calloc(cpu_count, sizeof(unsigned long long));
+       mperf_current_count = calloc(cpu_count, sizeof(unsigned long long));
+       aperf_current_count = calloc(cpu_count, sizeof(unsigned long long));
+
+       mperf_monitor.name_len = strlen(mperf_monitor.name);
+       return &mperf_monitor;
+}
+
+void mperf_unregister(void)
+{
+       free(mperf_previous_count);
+       free(aperf_previous_count);
+       free(mperf_current_count);
+       free(aperf_current_count);
+       free(is_valid);
+}
+
+struct cpuidle_monitor mperf_monitor = {
+       .name                   = "Mperf",
+       .hw_states_num          = MPERF_CSTATE_COUNT,
+       .hw_states              = mperf_cstates,
+       .start                  = mperf_start,
+       .stop                   = mperf_stop,
+       .do_register            = mperf_register,
+       .unregister             = mperf_unregister,
+       .needs_root             = 1,
+       .overflow_s             = 922000000 /* 922337203 seconds TSC overflow
+                                              at 20GHz */
+};
+#endif /* #if defined(__i386__) || defined(__x86_64__) */
diff --git a/tools/power/cpupower/utils/idle_monitor/nhm_idle.c b/tools/power/cpupower/utils/idle_monitor/nhm_idle.c
new file mode 100644 (file)
index 0000000..d2a91dd
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ *  Based on Len Brown's <lenb@kernel.org> turbostat tool.
+ */
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "helpers/helpers.h"
+#include "idle_monitor/cpupower-monitor.h"
+
+#define MSR_PKG_C3_RESIDENCY   0x3F8
+#define MSR_PKG_C6_RESIDENCY   0x3F9
+#define MSR_CORE_C3_RESIDENCY  0x3FC
+#define MSR_CORE_C6_RESIDENCY  0x3FD
+
+#define MSR_TSC        0x10
+
+#define NHM_CSTATE_COUNT 4
+
+enum intel_nhm_id { C3 = 0, C6, PC3, PC6, TSC = 0xFFFF };
+
+static int nhm_get_count_percent(unsigned int self_id, double *percent,
+                                unsigned int cpu);
+
+static cstate_t nhm_cstates[NHM_CSTATE_COUNT] = {
+       {
+               .name                   = "C3",
+               .desc                   = N_("Processor Core C3"),
+               .id                     = C3,
+               .range                  = RANGE_CORE,
+               .get_count_percent      = nhm_get_count_percent,
+       },
+       {
+               .name                   = "C6",
+               .desc                   = N_("Processor Core C6"),
+               .id                     = C6,
+               .range                  = RANGE_CORE,
+               .get_count_percent      = nhm_get_count_percent,
+       },
+
+       {
+               .name                   = "PC3",
+               .desc                   = N_("Processor Package C3"),
+               .id                     = PC3,
+               .range                  = RANGE_PACKAGE,
+               .get_count_percent      = nhm_get_count_percent,
+       },
+       {
+               .name                   = "PC6",
+               .desc                   = N_("Processor Package C6"),
+               .id                     = PC6,
+               .range                  = RANGE_PACKAGE,
+               .get_count_percent      = nhm_get_count_percent,
+       },
+};
+
+static unsigned long long tsc_at_measure_start;
+static unsigned long long tsc_at_measure_end;
+static unsigned long long *previous_count[NHM_CSTATE_COUNT];
+static unsigned long long *current_count[NHM_CSTATE_COUNT];
+/* valid flag for all CPUs. If a MSR read failed it will be zero */
+static int *is_valid;
+
+static int nhm_get_count(enum intel_nhm_id id, unsigned long long *val,
+                       unsigned int cpu)
+{
+       int msr;
+
+       switch (id) {
+       case C3:
+               msr = MSR_CORE_C3_RESIDENCY;
+               break;
+       case C6:
+               msr = MSR_CORE_C6_RESIDENCY;
+               break;
+       case PC3:
+               msr = MSR_PKG_C3_RESIDENCY;
+               break;
+       case PC6:
+               msr = MSR_PKG_C6_RESIDENCY;
+               break;
+       case TSC:
+               msr = MSR_TSC;
+               break;
+       default:
+               return -1;
+       };
+       if (read_msr(cpu, msr, val))
+               return -1;
+
+       return 0;
+}
+
+static int nhm_get_count_percent(unsigned int id, double *percent,
+                                unsigned int cpu)
+{
+       *percent = 0.0;
+
+       if (!is_valid[cpu])
+               return -1;
+
+       *percent = (100.0 *
+               (current_count[id][cpu] - previous_count[id][cpu])) /
+               (tsc_at_measure_end - tsc_at_measure_start);
+
+       dprint("%s: previous: %llu - current: %llu - (%u)\n",
+               nhm_cstates[id].name, previous_count[id][cpu],
+               current_count[id][cpu], cpu);
+
+       dprint("%s: tsc_diff: %llu - count_diff: %llu - percent: %2.f (%u)\n",
+              nhm_cstates[id].name,
+              (unsigned long long) tsc_at_measure_end - tsc_at_measure_start,
+              current_count[id][cpu] - previous_count[id][cpu],
+              *percent, cpu);
+
+       return 0;
+}
+
+static int nhm_start(void)
+{
+       int num, cpu;
+       unsigned long long dbg, val;
+
+       nhm_get_count(TSC, &tsc_at_measure_start, 0);
+
+       for (num = 0; num < NHM_CSTATE_COUNT; num++) {
+               for (cpu = 0; cpu < cpu_count; cpu++) {
+                       is_valid[cpu] = !nhm_get_count(num, &val, cpu);
+                       previous_count[num][cpu] = val;
+               }
+       }
+       nhm_get_count(TSC, &dbg, 0);
+       dprint("TSC diff: %llu\n", dbg - tsc_at_measure_start);
+       return 0;
+}
+
+static int nhm_stop(void)
+{
+       unsigned long long val;
+       unsigned long long dbg;
+       int num, cpu;
+
+       nhm_get_count(TSC, &tsc_at_measure_end, 0);
+
+       for (num = 0; num < NHM_CSTATE_COUNT; num++) {
+               for (cpu = 0; cpu < cpu_count; cpu++) {
+                       is_valid[cpu] = !nhm_get_count(num, &val, cpu);
+                       current_count[num][cpu] = val;
+               }
+       }
+       nhm_get_count(TSC, &dbg, 0);
+       dprint("TSC diff: %llu\n", dbg - tsc_at_measure_end);
+
+       return 0;
+}
+
+struct cpuidle_monitor intel_nhm_monitor;
+
+struct cpuidle_monitor *intel_nhm_register(void)
+{
+       int num;
+
+       if (cpupower_cpu_info.vendor != X86_VENDOR_INTEL)
+               return NULL;
+
+       if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_INV_TSC))
+               return NULL;
+
+       if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_APERF))
+               return NULL;
+
+       /* Free this at program termination */
+       is_valid = calloc(cpu_count, sizeof(int));
+       for (num = 0; num < NHM_CSTATE_COUNT; num++) {
+               previous_count[num] = calloc(cpu_count,
+                                       sizeof(unsigned long long));
+               current_count[num]  = calloc(cpu_count,
+                                       sizeof(unsigned long long));
+       }
+
+       intel_nhm_monitor.name_len = strlen(intel_nhm_monitor.name);
+       return &intel_nhm_monitor;
+}
+
+void intel_nhm_unregister(void)
+{
+       int num;
+
+       for (num = 0; num < NHM_CSTATE_COUNT; num++) {
+               free(previous_count[num]);
+               free(current_count[num]);
+       }
+       free(is_valid);
+}
+
+struct cpuidle_monitor intel_nhm_monitor = {
+       .name                   = "Nehalem",
+       .hw_states_num          = NHM_CSTATE_COUNT,
+       .hw_states              = nhm_cstates,
+       .start                  = nhm_start,
+       .stop                   = nhm_stop,
+       .do_register            = intel_nhm_register,
+       .unregister             = intel_nhm_unregister,
+       .needs_root             = 1,
+       .overflow_s             = 922000000 /* 922337203 seconds TSC overflow
+                                              at 20GHz */
+};
+#endif
diff --git a/tools/power/cpupower/utils/idle_monitor/snb_idle.c b/tools/power/cpupower/utils/idle_monitor/snb_idle.c
new file mode 100644 (file)
index 0000000..a1bc07c
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ *  Based on Len Brown's <lenb@kernel.org> turbostat tool.
+ */
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "helpers/helpers.h"
+#include "idle_monitor/cpupower-monitor.h"
+
+#define MSR_PKG_C2_RESIDENCY   0x60D
+#define MSR_PKG_C7_RESIDENCY   0x3FA
+#define MSR_CORE_C7_RESIDENCY  0x3FE
+
+#define MSR_TSC        0x10
+
+enum intel_snb_id { C7 = 0, PC2, PC7, SNB_CSTATE_COUNT, TSC = 0xFFFF };
+
+static int snb_get_count_percent(unsigned int self_id, double *percent,
+                                unsigned int cpu);
+
+static cstate_t snb_cstates[SNB_CSTATE_COUNT] = {
+       {
+               .name                   = "C7",
+               .desc                   = N_("Processor Core C7"),
+               .id                     = C7,
+               .range                  = RANGE_CORE,
+               .get_count_percent      = snb_get_count_percent,
+       },
+       {
+               .name                   = "PC2",
+               .desc                   = N_("Processor Package C2"),
+               .id                     = PC2,
+               .range                  = RANGE_PACKAGE,
+               .get_count_percent      = snb_get_count_percent,
+       },
+       {
+               .name                   = "PC7",
+               .desc                   = N_("Processor Package C7"),
+               .id                     = PC7,
+               .range                  = RANGE_PACKAGE,
+               .get_count_percent      = snb_get_count_percent,
+       },
+};
+
+static unsigned long long tsc_at_measure_start;
+static unsigned long long tsc_at_measure_end;
+static unsigned long long *previous_count[SNB_CSTATE_COUNT];
+static unsigned long long *current_count[SNB_CSTATE_COUNT];
+/* valid flag for all CPUs. If a MSR read failed it will be zero */
+static int *is_valid;
+
+static int snb_get_count(enum intel_snb_id id, unsigned long long *val,
+                       unsigned int cpu)
+{
+       int msr;
+
+       switch (id) {
+       case C7:
+               msr = MSR_CORE_C7_RESIDENCY;
+               break;
+       case PC2:
+               msr = MSR_PKG_C2_RESIDENCY;
+               break;
+       case PC7:
+               msr = MSR_PKG_C7_RESIDENCY;
+               break;
+       case TSC:
+               msr = MSR_TSC;
+               break;
+       default:
+               return -1;
+       };
+       if (read_msr(cpu, msr, val))
+               return -1;
+       return 0;
+}
+
+static int snb_get_count_percent(unsigned int id, double *percent,
+                                unsigned int cpu)
+{
+       *percent = 0.0;
+
+       if (!is_valid[cpu])
+               return -1;
+
+       *percent = (100.0 *
+               (current_count[id][cpu] - previous_count[id][cpu])) /
+               (tsc_at_measure_end - tsc_at_measure_start);
+
+       dprint("%s: previous: %llu - current: %llu - (%u)\n",
+               snb_cstates[id].name, previous_count[id][cpu],
+               current_count[id][cpu], cpu);
+
+       dprint("%s: tsc_diff: %llu - count_diff: %llu - percent: %2.f (%u)\n",
+              snb_cstates[id].name,
+              (unsigned long long) tsc_at_measure_end - tsc_at_measure_start,
+              current_count[id][cpu] - previous_count[id][cpu],
+              *percent, cpu);
+
+       return 0;
+}
+
+static int snb_start(void)
+{
+       int num, cpu;
+       unsigned long long val;
+
+       for (num = 0; num < SNB_CSTATE_COUNT; num++) {
+               for (cpu = 0; cpu < cpu_count; cpu++) {
+                       snb_get_count(num, &val, cpu);
+                       previous_count[num][cpu] = val;
+               }
+       }
+       snb_get_count(TSC, &tsc_at_measure_start, 0);
+       return 0;
+}
+
+static int snb_stop(void)
+{
+       unsigned long long val;
+       int num, cpu;
+
+       snb_get_count(TSC, &tsc_at_measure_end, 0);
+
+       for (num = 0; num < SNB_CSTATE_COUNT; num++) {
+               for (cpu = 0; cpu < cpu_count; cpu++) {
+                       is_valid[cpu] = !snb_get_count(num, &val, cpu);
+                       current_count[num][cpu] = val;
+               }
+       }
+       return 0;
+}
+
+struct cpuidle_monitor intel_snb_monitor;
+
+static struct cpuidle_monitor *snb_register(void)
+{
+       int num;
+
+       if (cpupower_cpu_info.vendor != X86_VENDOR_INTEL
+           || cpupower_cpu_info.family != 6)
+               return NULL;
+
+       if (cpupower_cpu_info.model != 0x2A
+           && cpupower_cpu_info.model != 0x2D)
+               return NULL;
+
+       is_valid = calloc(cpu_count, sizeof(int));
+       for (num = 0; num < SNB_CSTATE_COUNT; num++) {
+               previous_count[num] = calloc(cpu_count,
+                                       sizeof(unsigned long long));
+               current_count[num]  = calloc(cpu_count,
+                                       sizeof(unsigned long long));
+       }
+       intel_snb_monitor.name_len = strlen(intel_snb_monitor.name);
+       return &intel_snb_monitor;
+}
+
+void snb_unregister(void)
+{
+       int num;
+       free(is_valid);
+       for (num = 0; num < SNB_CSTATE_COUNT; num++) {
+               free(previous_count[num]);
+               free(current_count[num]);
+       }
+}
+
+struct cpuidle_monitor intel_snb_monitor = {
+       .name                   = "SandyBridge",
+       .hw_states              = snb_cstates,
+       .hw_states_num          = SNB_CSTATE_COUNT,
+       .start                  = snb_start,
+       .stop                   = snb_stop,
+       .do_register            = snb_register,
+       .unregister             = snb_unregister,
+       .needs_root             = 1,
+       .overflow_s             = 922000000 /* 922337203 seconds TSC overflow
+                                              at 20GHz */
+};
+#endif /* defined(__i386__) || defined(__x86_64__) */
diff --git a/tools/power/cpupower/utils/version-gen.sh b/tools/power/cpupower/utils/version-gen.sh
new file mode 100755 (executable)
index 0000000..5ec41c5
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/sh
+#
+# Script which prints out the version to use for building cpupowerutils.
+# Must be called from tools/power/cpupower/
+# 
+# Heavily based on tools/perf/util/PERF-VERSION-GEN .
+
+LF='
+'
+
+# First check if there is a .git to get the version from git describe
+# otherwise try to get the version from the kernel makefile
+if test -d ../../../.git -o -f ../../../.git &&
+       VN=$(git describe --abbrev=4 HEAD 2>/dev/null) &&
+       case "$VN" in
+       *$LF*) (exit 1) ;;
+       v[0-9]*)
+               git update-index -q --refresh
+               test -z "$(git diff-index --name-only HEAD --)" ||
+               VN="$VN-dirty" ;;
+       esac
+then
+       VN=$(echo "$VN" | sed -e 's/-/./g');
+else
+       eval $(grep '^VERSION[[:space:]]*=' ../../../Makefile|tr -d ' ')
+       eval $(grep '^PATCHLEVEL[[:space:]]*=' ../../../Makefile|tr -d ' ')
+       eval $(grep '^SUBLEVEL[[:space:]]*=' ../../../Makefile|tr -d ' ')
+       eval $(grep '^EXTRAVERSION[[:space:]]*=' ../../../Makefile|tr -d ' ')
+
+       VN="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}${EXTRAVERSION}"
+fi
+
+VN=$(expr "$VN" : v*'\(.*\)')
+
+echo $VN
index 6d8ef4a..8b2d37b 100644 (file)
@@ -128,34 +128,34 @@ unsigned long long get_msr(int cpu, off_t offset)
 void print_header(void)
 {
        if (show_pkg)
-               fprintf(stderr, "pk");
+               fprintf(stderr, "pk");
        if (show_core)
-               fprintf(stderr, "core");
+               fprintf(stderr, " cr");
        if (show_cpu)
                fprintf(stderr, " CPU");
        if (do_nhm_cstates)
-               fprintf(stderr, "   %%c0 ");
+               fprintf(stderr, "    %%c0 ");
        if (has_aperf)
-               fprintf(stderr, "  GHz");
+               fprintf(stderr, " GHz");
        fprintf(stderr, "  TSC");
        if (do_nhm_cstates)
-               fprintf(stderr, "   %%c1 ");
+               fprintf(stderr, "    %%c1");
        if (do_nhm_cstates)
-               fprintf(stderr, "   %%c3 ");
+               fprintf(stderr, "    %%c3");
        if (do_nhm_cstates)
-               fprintf(stderr, "   %%c6 ");
+               fprintf(stderr, "    %%c6");
        if (do_snb_cstates)
-               fprintf(stderr, "   %%c7 ");
+               fprintf(stderr, "    %%c7");
        if (do_snb_cstates)
-               fprintf(stderr, "  %%pc2 ");
+               fprintf(stderr, "  %%pc2");
        if (do_nhm_cstates)
-               fprintf(stderr, "  %%pc3 ");
+               fprintf(stderr, "  %%pc3");
        if (do_nhm_cstates)
-               fprintf(stderr, "  %%pc6 ");
+               fprintf(stderr, "  %%pc6");
        if (do_snb_cstates)
-               fprintf(stderr, "  %%pc7 ");
+               fprintf(stderr, "  %%pc7");
        if (extra_msr_offset)
-               fprintf(stderr, "       MSR 0x%x ", extra_msr_offset);
+               fprintf(stderr, "        MSR 0x%x ", extra_msr_offset);
 
        putc('\n', stderr);
 }
@@ -194,14 +194,14 @@ void print_cnt(struct counters *p)
        /* topology columns, print blanks on 1st (average) line */
        if (p == cnt_average) {
                if (show_pkg)
-                       fprintf(stderr, "    ");
+                       fprintf(stderr, " ");
                if (show_core)
                        fprintf(stderr, "    ");
                if (show_cpu)
                        fprintf(stderr, "    ");
        } else {
                if (show_pkg)
-                       fprintf(stderr, "%4d", p->pkg);
+                       fprintf(stderr, "%d", p->pkg);
                if (show_core)
                        fprintf(stderr, "%4d", p->core);
                if (show_cpu)
@@ -241,22 +241,22 @@ void print_cnt(struct counters *p)
                if (!skip_c1)
                        fprintf(stderr, "%7.2f", 100.0 * p->c1/p->tsc);
                else
-                       fprintf(stderr, "   ****");
+                       fprintf(stderr, "  ****");
        }
        if (do_nhm_cstates)
-               fprintf(stderr, "%7.2f", 100.0 * p->c3/p->tsc);
+               fprintf(stderr, " %6.2f", 100.0 * p->c3/p->tsc);
        if (do_nhm_cstates)
-               fprintf(stderr, "%7.2f", 100.0 * p->c6/p->tsc);
+               fprintf(stderr, " %6.2f", 100.0 * p->c6/p->tsc);
        if (do_snb_cstates)
-               fprintf(stderr, "%7.2f", 100.0 * p->c7/p->tsc);
+               fprintf(stderr, " %6.2f", 100.0 * p->c7/p->tsc);
        if (do_snb_cstates)
-               fprintf(stderr, "%7.2f", 100.0 * p->pc2/p->tsc);
+               fprintf(stderr, " %5.2f", 100.0 * p->pc2/p->tsc);
        if (do_nhm_cstates)
-               fprintf(stderr, "%7.2f", 100.0 * p->pc3/p->tsc);
+               fprintf(stderr, " %5.2f", 100.0 * p->pc3/p->tsc);
        if (do_nhm_cstates)
-               fprintf(stderr, "%7.2f", 100.0 * p->pc6/p->tsc);
+               fprintf(stderr, " %5.2f", 100.0 * p->pc6/p->tsc);
        if (do_snb_cstates)
-               fprintf(stderr, "%7.2f", 100.0 * p->pc7/p->tsc);
+               fprintf(stderr, " %5.2f", 100.0 * p->pc7/p->tsc);
        if (extra_msr_offset)
                fprintf(stderr, "  0x%016llx", p->extra_msr);
        putc('\n', stderr);
index 2618ef2..33c5c7e 100644 (file)
@@ -137,7 +137,6 @@ void cmdline(int argc, char **argv)
 void validate_cpuid(void)
 {
        unsigned int eax, ebx, ecx, edx, max_level;
-       char brand[16];
        unsigned int fms, family, model, stepping;
 
        eax = ebx = ecx = edx = 0;
@@ -160,8 +159,8 @@ void validate_cpuid(void)
                model += ((fms >> 16) & 0xf) << 4;
 
        if (verbose > 1)
-               printf("CPUID %s %d levels family:model:stepping "
-                       "0x%x:%x:%x (%d:%d:%d)\n", brand, max_level,
+               printf("CPUID %d levels family:model:stepping "
+                       "0x%x:%x:%x (%d:%d:%d)\n", max_level,
                        family, model, stepping, family, model, stepping);
 
        if (!(edx & (1 << 5))) {
index 516551c..868cc93 100644 (file)
@@ -2,8 +2,9 @@
  * Slabinfo: Tool to get reports about slabs
  *
  * (C) 2007 sgi, Christoph Lameter
+ * (C) 2011 Linux Foundation, Christoph Lameter
  *
- * Compile by:
+ * Compile with:
  *
  * gcc -o slabinfo slabinfo.c
  */
@@ -39,6 +40,8 @@ struct slabinfo {
        unsigned long cpuslab_flush, deactivate_full, deactivate_empty;
        unsigned long deactivate_to_head, deactivate_to_tail;
        unsigned long deactivate_remote_frees, order_fallback;
+       unsigned long cmpxchg_double_cpu_fail, cmpxchg_double_fail;
+       unsigned long alloc_node_mismatch, deactivate_bypass;
        int numa[MAX_NODES];
        int numa_partial[MAX_NODES];
 } slabinfo[MAX_SLABS];
@@ -99,7 +102,7 @@ static void fatal(const char *x, ...)
 
 static void usage(void)
 {
-       printf("slabinfo 5/7/2007. (c) 2007 sgi.\n\n"
+       printf("slabinfo 4/15/2011. (c) 2007 sgi/(c) 2011 Linux Foundation.\n\n"
                "slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n"
                "-a|--aliases           Show aliases\n"
                "-A|--activity          Most active slabs first\n"
@@ -293,7 +296,7 @@ int line = 0;
 static void first_line(void)
 {
        if (show_activity)
-               printf("Name                   Objects      Alloc       Free   %%Fast Fallb O\n");
+               printf("Name                   Objects      Alloc       Free   %%Fast Fallb O CmpX   UL\n");
        else
                printf("Name                   Objects Objsize    Space "
                        "Slabs/Part/Cpu  O/S O %%Fr %%Ef Flg\n");
@@ -379,14 +382,14 @@ static void show_tracking(struct slabinfo *s)
        printf("\n%s: Kernel object allocation\n", s->name);
        printf("-----------------------------------------------------------------------\n");
        if (read_slab_obj(s, "alloc_calls"))
-               printf(buffer);
+               printf("%s", buffer);
        else
                printf("No Data\n");
 
        printf("\n%s: Kernel object freeing\n", s->name);
        printf("------------------------------------------------------------------------\n");
        if (read_slab_obj(s, "free_calls"))
-               printf(buffer);
+               printf("%s", buffer);
        else
                printf("No Data\n");
 
@@ -400,7 +403,7 @@ static void ops(struct slabinfo *s)
        if (read_slab_obj(s, "ops")) {
                printf("\n%s: kmem_cache operations\n", s->name);
                printf("--------------------------------------------\n");
-               printf(buffer);
+               printf("%s", buffer);
        } else
                printf("\n%s has no kmem_cache operations\n", s->name);
 }
@@ -462,19 +465,32 @@ static void slab_stats(struct slabinfo *s)
        if (s->cpuslab_flush)
                printf("Flushes %8lu\n", s->cpuslab_flush);
 
-       if (s->alloc_refill)
-               printf("Refill %8lu\n", s->alloc_refill);
-
        total = s->deactivate_full + s->deactivate_empty +
-                       s->deactivate_to_head + s->deactivate_to_tail;
-
-       if (total)
-               printf("Deactivate Full=%lu(%lu%%) Empty=%lu(%lu%%) "
-                       "ToHead=%lu(%lu%%) ToTail=%lu(%lu%%)\n",
-                       s->deactivate_full, (s->deactivate_full * 100) / total,
-                       s->deactivate_empty, (s->deactivate_empty * 100) / total,
-                       s->deactivate_to_head, (s->deactivate_to_head * 100) / total,
+                       s->deactivate_to_head + s->deactivate_to_tail + s->deactivate_bypass;
+
+       if (total) {
+               printf("\nSlab Deactivation             Ocurrences  %%\n");
+               printf("-------------------------------------------------\n");
+               printf("Slab full                     %7lu  %3lu%%\n",
+                       s->deactivate_full, (s->deactivate_full * 100) / total);
+               printf("Slab empty                    %7lu  %3lu%%\n",
+                       s->deactivate_empty, (s->deactivate_empty * 100) / total);
+               printf("Moved to head of partial list %7lu  %3lu%%\n",
+                       s->deactivate_to_head, (s->deactivate_to_head * 100) / total);
+               printf("Moved to tail of partial list %7lu  %3lu%%\n",
                        s->deactivate_to_tail, (s->deactivate_to_tail * 100) / total);
+               printf("Deactivation bypass           %7lu  %3lu%%\n",
+                       s->deactivate_bypass, (s->deactivate_bypass * 100) / total);
+               printf("Refilled from foreign frees   %7lu  %3lu%%\n",
+                       s->alloc_refill, (s->alloc_refill * 100) / total);
+               printf("Node mismatch                 %7lu  %3lu%%\n",
+                       s->alloc_node_mismatch, (s->alloc_node_mismatch * 100) / total);
+       }
+
+       if (s->cmpxchg_double_fail || s->cmpxchg_double_cpu_fail)
+               printf("\nCmpxchg_double Looping\n------------------------\n");
+               printf("Locked Cmpxchg Double redos   %lu\nUnlocked Cmpxchg Double redos %lu\n",
+                       s->cmpxchg_double_fail, s->cmpxchg_double_cpu_fail);
 }
 
 static void report(struct slabinfo *s)
@@ -573,12 +589,13 @@ static void slabcache(struct slabinfo *s)
                total_alloc = s->alloc_fastpath + s->alloc_slowpath;
                total_free = s->free_fastpath + s->free_slowpath;
 
-               printf("%-21s %8ld %10ld %10ld %3ld %3ld %5ld %1d\n",
+               printf("%-21s %8ld %10ld %10ld %3ld %3ld %5ld %1d %4ld %4ld\n",
                        s->name, s->objects,
                        total_alloc, total_free,
                        total_alloc ? (s->alloc_fastpath * 100 / total_alloc) : 0,
                        total_free ? (s->free_fastpath * 100 / total_free) : 0,
-                       s->order_fallback, s->order);
+                       s->order_fallback, s->order, s->cmpxchg_double_fail,
+                       s->cmpxchg_double_cpu_fail);
        }
        else
                printf("%-21s %8ld %7d %8s %14s %4d %1d %3ld %3ld %s\n",
@@ -1190,6 +1207,10 @@ static void read_slab_dir(void)
                        slab->deactivate_to_tail = get_obj("deactivate_to_tail");
                        slab->deactivate_remote_frees = get_obj("deactivate_remote_frees");
                        slab->order_fallback = get_obj("order_fallback");
+                       slab->cmpxchg_double_cpu_fail = get_obj("cmpxchg_double_cpu_fail");
+                       slab->cmpxchg_double_fail = get_obj("cmpxchg_double_fail");
+                       slab->alloc_node_mismatch = get_obj("alloc_node_mismatch");
+                       slab->deactivate_bypass = get_obj("deactivate_bypass");
                        chdir("..");
                        if (slab->name[0] == ':')
                                alias_targets++;